// // Copyright 2020 Electronic Arts Inc. // // TiberianDawn.DLL and RedAlert.dll and corresponding source code 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 3 of the License, or (at your option) any later version. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed // in the hope that it will be useful, but with permitted additional restrictions // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT // distributed with this program. You should have received a copy of the // GNU General Public License along with permitted additional restrictions // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection /* $Header: /CounterStrike/JSHELL.CPP 2 3/13/97 2:05p Steve_tall $ */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project Name : Command & Conquer * * * * File Name : JSHELL.CPP * * * * Programmer : Joe L. Bostic * * * * Start Date : April 2, 1994 * * * * Last Update : May 11, 1995 [JLB] * * * *---------------------------------------------------------------------------------------------* * Functions: * * Build_Translucent_Table -- Creates a translucent control table. * * Conquer_Build_Translucent_Table -- Builds fading table for shadow colors only. * * Fatal -- General purpose fatal error handler. * * Load_Alloc_Data -- Allocates a buffer and loads the file into it. * * Load_Uncompress -- Loads and uncompresses data to a buffer. * * Set_Window -- Sets the window dimensions to that specified. * * Small_Icon -- Create a small icon from a big one. * * Translucent_Table_Size -- Determines the size of a translucent table. * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "function.h" #include "wwfile.h" /*********************************************************************************************** * Small_Icon -- Create a small icon from a big one. * * * * This routine will extract the specified icon from the icon data file and convert that * * icon into a small (3x3) representation. Typical use of this mini-icon is for the radar * * map. * * * * INPUT: iconptr -- Pointer to the icon data file. * * * * iconnum -- The embedded icon number to convert into a small image. * * * * OUTPUT: Returns with a pointer to the small icon imagery. This is exactly 9 bytes long. * * * * WARNINGS: none * * * * HISTORY: * * 05/11/1995 JLB : Created. * *=============================================================================================*/ void * Small_Icon(void const * iconptr, int iconnum) { static unsigned char _icon[9]; IControl_Type const * iptr = (IControl_Type const *)iconptr; unsigned char * data; if (iconptr) { iconnum = ((char *)((char *)iptr + iptr->Map))[iconnum]; data = &((unsigned char *)((unsigned char *)iptr + iptr->Icons))[iconnum*(24*24)]; // data = &iptr->Icons[iconnum*(24*24)]; for (int index = 0; index < 9; index++) { int _offsets[9] = { 4+4*24, 12+4*24, 20+4*24, 4+12*24, 12+12*24, 20+12*24, 4+20*24, 12+20*24, 20+20*24 }; _icon[index] = data[_offsets[index]]; } } return(_icon); } /*********************************************************************************************** * Set_Window -- Sets the window dimensions to that specified. * * * * Use this routine to set the windows dimensions to the coordinates and dimensions * * specified. * * * * INPUT: x -- Window X pixel position. * * * * y -- Window Y pixel position. * * * * w -- Window width in pixels. * * * * h -- Window height in pixels. * * * * OUTPUT: none * * * * WARNINGS: The X and width values are truncated to an even 8 pixel boundary. This is * * the same as stripping off the lower 3 bits. * * * * HISTORY: * * 01/15/1995 JLB : Created. * *=============================================================================================*/ void Set_Window(int window, int x, int y, int w, int h) { WindowList[window][WINDOWWIDTH] = w; WindowList[window][WINDOWHEIGHT] = h; WindowList[window][WINDOWX] = x; WindowList[window][WINDOWY] = y; } /*********************************************************************************************** * Fatal -- General purpose fatal error handler. * * * * This is a very simple general purpose fatal error handler. It goes directly to text * * mode, prints the error, and then aborts with a failure code. * * * * INPUT: message -- The text message to display. * * * * ... -- Any optional parameters that are used in formatting the message. * * * * OUTPUT: none * * * * WARNINGS: This routine never returns. The game exits immediately. * * * * HISTORY: * * 10/17/1994 JLB : Created. * *=============================================================================================*/ void Fatal(char const * message, ...) { va_list va; va_start(va, message); Prog_End(message, true); vfprintf(stderr, message, va); Mono_Printf(message); if (!RunningAsDLL) { //PG Emergency_Exit(EXIT_FAILURE); } } #ifdef NEVER void File_Fatal(char const * message) { //Prog_End(); perror(message); Emergency_Exit(EXIT_FAILURE); } #endif /*********************************************************************************************** * Load_Uncompress -- Loads and uncompresses data to a buffer. * * * * This is the C++ counterpart to the Load_Uncompress function. It will load the file * * specified into the graphic buffer indicated and uncompress it. * * * * INPUT: file -- The file to load and uncompress. * * * * uncomp_buff -- The graphic buffer that initial loading will use. * * * * dest_buff -- The buffer that will hold the uncompressed data. * * * * reserved_data -- This is an optional pointer to a buffer that will hold any * * reserved data the compressed file may contain. This is * * typically a palette. * * * * OUTPUT: Returns with the size of the uncompressed data in the destination buffer. * * * * WARNINGS: none * * * * HISTORY: * * 10/17/1994 JLB : Created. * *=============================================================================================*/ long Load_Uncompress(FileClass &file, BuffType &uncomp_buff, BuffType &dest_buff, void * reserved_data) { unsigned short size; void * sptr = uncomp_buff.Get_Buffer(); void * dptr = dest_buff.Get_Buffer(); int opened = false; CompHeaderType header; /* ** The file must be opened in order to be read from. If the file ** isn't opened, then open it. Record this fact so that it can be ** restored to its closed state at the end. */ if (!file.Is_Open()) { if (!file.Open()) { return(0); } opened = true; } /* ** Read in the size of the file (supposedly). */ file.Read(&size, sizeof(size)); /* ** Read in the header block. This block contains the compression type ** and skip data (among other things). */ file.Read(&header, sizeof(header)); size -= sizeof(header); /* ** If there are skip bytes then they must be processed. Either read ** them into the buffer provided or skip past them. No check is made ** to ensure that the reserved data buffer is big enough (watch out!). */ if (header.Skip) { size -= header.Skip; if (reserved_data) { file.Read(reserved_data, header.Skip); } else { file.Seek(header.Skip, SEEK_CUR); } header.Skip = 0; } /* ** Determine where is the proper place to load the data. If both buffers ** specified are identical, then the data should be loaded at the end of ** the buffer and decompressed at the beginning. */ if (uncomp_buff.Get_Buffer() == dest_buff.Get_Buffer()) { sptr = (char *)sptr + uncomp_buff.Get_Size()-(size+sizeof(header)); } /* ** Read in the bulk of the data. */ Mem_Copy(&header, sptr, sizeof(header)); file.Read((char *)sptr + sizeof(header), size); /* ** Decompress the data. */ size = (unsigned int) Uncompress_Data(sptr, dptr); /* ** Close the file if necessary. */ if (opened) { file.Close(); } return((long)size); } int Load_Picture(char const * filename, BufferClass& scratchbuf, BufferClass& destbuf, unsigned char * palette, PicturePlaneType ) { return(Load_Uncompress(CCFileClass(filename), scratchbuf, destbuf, palette ) / 8000); } /*********************************************************************************************** * Load_Alloc_Data -- Allocates a buffer and loads the file into it. * * * * This is the C++ replacement for the Load_Alloc_Data function. It will allocate the * * memory big enough to hold the file and then read the file into it. * * * * INPUT: file -- The file to read. * * * * mem -- The memory system to use for allocation. * * * * OUTPUT: Returns with a pointer to the allocated and filled memory block. * * * * WARNINGS: none * * * * HISTORY: * * 10/17/1994 JLB : Created. * *=============================================================================================*/ void * Load_Alloc_Data(FileClass &file) { void * ptr = 0; long size = file.Size(); ptr = new char [size]; if (ptr) { file.Read(ptr, size); } return(ptr); } /*********************************************************************************************** * Translucent_Table_Size -- Determines the size of a translucent table. * * * * Use this routine to determine how big the translucent table needs * * to be given the specified number of colors. This value is typically * * used when allocating the buffer for the translucent table. * * * * INPUT: count -- The number of colors that are translucent. * * * * OUTPUT: Returns the size of the translucent table. * * * * WARNINGS: none * * * * HISTORY: * * 04/02/1994 JLB : Created. * *=============================================================================================*/ long Translucent_Table_Size(int count) { return(256L + (256L * count)); } /*********************************************************************************************** * Build_Translucent_Table -- Creates a translucent control table. * * * * The table created by this routine is used by Draw_Shape (GHOST) to * * achieve a translucent affect. The original color of the shape will * * show through. This differs from the fading effect, since that * * affect only alters the background color toward a single destination * * color. * * * * INPUT: palette -- Pointer to the control palette. * * * * control -- Pointer to array of structures that control how * * the translucent table will be built. * * * * count -- The number of entries in the control array. * * * * buffer -- Pointer to buffer to place the translucent table. * * If NULL is passed in, then the buffer will be * * allocated. * * * * OUTPUT: Returns with pointer to the translucent table. * * * * WARNINGS: This routine is exceedingly slow. Use sparingly. * * * * HISTORY: * * 04/02/1994 JLB : Created. * *=============================================================================================*/ void * Build_Translucent_Table(PaletteClass const & palette, TLucentType const * control, int count, void * buffer) { unsigned char const *table; // Remap table pointer. int index; // Working color index. if (count && control/* && palette*/) { // palette can't be NULL... ST - 5/9/2019 if (!buffer) { buffer = new char [Translucent_Table_Size(count)]; } if (buffer) { memset(buffer, -1, 256); table = (unsigned char*)buffer + 256; /* ** Build the individual remap tables for each translucent color. */ for (index = 0; index < count; index++) { ((unsigned char*)buffer)[control[index].SourceColor] = index; Build_Fading_Table(palette.Get_Data(), (void*)table, control[index].DestColor, control[index].Fading); table = (unsigned char*)table + 256; } } } return(buffer); } /*********************************************************************************************** * Conquer_Build_Translucent_Table -- Builds fading table for shadow colors only. * * * * This routine will build a translucent (fading) table to remap colors into the shadow * * color region of the palette. Shadow colors are not affected by this translucent table. * * This means that a shape can be overlapped any number of times and the imagery will * * remain deterministic (and constant). * * * * INPUT: palette -- Pointer to the palette to base the translucent process on. * * * * control -- Pointer to special control structure that specifies the * * target color, and percentage of fade. * * * * count -- The number of colors to be remapped (entries in the control array). * * * * buffer -- Pointer to the staging buffer that will hold the translucent table * * data. If this parameter is NULL, then an appropriate sized table * * will be allocated. * * * * OUTPUT: Returns with a pointer to the translucent table data. * * * * WARNINGS: none * * * * HISTORY: * * 06/27/1994 JLB : Created. * *=============================================================================================*/ void * Conquer_Build_Translucent_Table(PaletteClass const & palette, TLucentType const * control, int count, void * buffer) { unsigned char const *table; // Remap table pointer. if (count && control) { if (!buffer) { buffer = new char [Translucent_Table_Size(count)]; } if (buffer) { memset(buffer, -1, 256); table = (unsigned char*)buffer + 256; /* ** Build the individual remap tables for each translucent color. */ for (int index = 0; index < count; index++) { ((unsigned char*)buffer)[control[index].SourceColor] = index; Conquer_Build_Fading_Table(palette, (void*)table, control[index].DestColor, control[index].Fading); table = (unsigned char*)table + 256; } } } return(buffer); } void * Make_Fading_Table(PaletteClass const & palette, void * dest, int color, int frac) { if (dest) { unsigned char * ptr = (unsigned char *)dest; /* ** Find an appropriate remap color index for every color in the palette. ** There are certain exceptions to this, but they are trapped within the ** loop. */ for (int index = 0; index < PaletteClass::COLOR_COUNT; index++) { /* ** Find the color that, ideally, the working color should be remapped ** to in the special remap range. */ RGBClass trycolor = palette[index]; trycolor.Adjust(frac, palette[color]); // Try to match this color. /* ** Search through the remap range to find the color that should be remapped ** to. This special range is used for shadows or other effects that are ** not compounded if additively applied. */ *ptr++ = palette.Closest_Color(trycolor); } } return(dest); } void * Conquer_Build_Fading_Table(PaletteClass const & palette, void * dest, int color, int frac) { if (dest) { unsigned char * ptr = (unsigned char *)dest; // HSVClass desthsv = palette[color]; /* ** Find an appropriate remap color index for every color in the palette. ** There are certain exceptions to this, but they are trapped within the ** loop. */ for (int index = 0; index < PaletteClass::COLOR_COUNT; index++) { /* ** If this color should not be remapped, then it will be stored as a remap ** to itself. This is effectively no remap. */ if (index > PaletteClass::COLOR_COUNT-16 || index == 0) { *ptr++ = index; } else { /* ** Find the color that, ideally, the working color should be remapped ** to in the special remap range. */ RGBClass trycolor = palette[index]; trycolor.Adjust(frac, palette[color]); // Try to match this color. /* ** Search through the remap range to find the color that should be remapped ** to. This special range is used for shadows or other effects that are ** not compounded if additively applied. */ int best = -1; int bvalue = 0; for (int id = PaletteClass::COLOR_COUNT-16; id < PaletteClass::COLOR_COUNT-1; id++) { int diff = palette[id].Difference(trycolor); if (best == -1 || diff < bvalue) { best = id; bvalue = diff; } } *ptr++ = best; } } } return(dest); } #ifdef OBSOLETE //int Desired_Facing8(int x1, int y1, int x2, int y2) DirType xDesired_Facing8(int x1, int y1, int x2, int y2) { int index = 0; // Facing composite value. /* ** Figure the absolute X difference. This determines ** if the facing is leftward or not. */ int xdiff = x2-x1; if (xdiff < 0) { index |= 0x00C0; xdiff = -xdiff; } /* ** Figure the absolute Y difference. This determines ** if the facing is downward or not. This also clarifies ** exactly which quadrant the facing lies. */ int ydiff = y1-y2; if (ydiff < 0) { index ^= 0x0040; ydiff = -ydiff; } /* ** Determine which of the two direction offsets it bigger. The ** offset direction that is bigger (X or Y) will indicate which ** orthogonal direction the facing is closer to. */ unsigned bigger; unsigned smaller; if (xdiff < ydiff) { smaller = xdiff; bigger = ydiff; } else { smaller = ydiff; bigger = xdiff; } /* ** If on the diagonal, then incorporate this into the facing ** and then bail. The facing is known. */ if (((bigger+1)/2) <= smaller) { index += 0x0020; return(DirType(index)); } /* ** Determine if the facing is closer to the Y axis or ** the X axis. */ int adder = (index & 0x0040); if (xdiff == bigger) { adder ^= 0x0040; } index += adder; return(DirType(index)); } //int Desired_Facing256(int srcx, int srcy, int dstx, int dsty) DirType xDesired_Facing256(int srcx, int srcy, int dstx, int dsty) { int composite=0; // Facing built from intermediate calculations. /* ** Fetch the absolute X difference. This also gives a clue as ** to which hemisphere the direction lies. */ int xdiff = dstx - srcx; if (xdiff < 0) { composite |= 0x00C0; xdiff = -xdiff; } /* ** Fetch the absolute Y difference. This clarifies the exact ** quadrant that the direction lies. */ int ydiff = srcy - dsty; if (ydiff < 0) { composite ^= 0x0040; ydiff = -ydiff; } /* ** Bail early if the coordinates are the same. This check also ** has the added bonus of ensuring that checking for division ** by zero is not needed in the following section. */ if (xdiff == 0 && ydiff == 0) return(DirType(0xFF)); /* ** Determine which of the two direction offsets it bigger. The ** offset direction that is bigger (X or Y) will indicate which ** orthogonal direction the facing is closer to. */ unsigned bigger; unsigned smaller; if (xdiff < ydiff) { smaller = xdiff; bigger = ydiff; } else { smaller = ydiff; bigger = xdiff; } /* ** Now that the quadrant is known, we need to determine how far ** from the orthogonal directions, the facing lies. This value ** is calculated as a ratio from 0 (matches orthogonal) to 31 ** (matches diagonal). */ int frac = (smaller * 32U) / bigger; /* ** Given the quadrant and knowing whether the facing is closer ** to the X or Y axis, we must make an adjustment toward the ** subsequent quadrant if necessary. */ int adder = (composite & 0x0040); if (xdiff > ydiff) { adder ^= 0x0040; } if (adder) { frac = (adder - frac)-1; } /* ** Integrate the fraction value into the quadrant. */ composite += frac; /* ** Return with the final facing value. */ return(DirType(composite & 0x00FF)); } #endif