// This file contains the key initialization functions for the ACK-3D engine. // The main function AckInitialize() must be called first before any of the // other ACK-3D functions are called. The internal functions defined in this file // perform all of the set up work of loading tables and resource files. #include #include #include #include #include #include #include "ack3d.h" #include "ackeng.h" #include "ackext.h" extern char AckKeyboardSetup; extern char AckTimerSetup; short *LowerTable[2048]; short tmpLowerValue[400]; short LowerLen[2048]; char rsName[128]; long FloorCosTable[VIEW_WIDTH+1]; short AckBuildTables(ACKENG *ae); void AckBuildHeightTables(ACKENG *ae); void AckBuildGrid(ACKENG *ae); void SetupFloors(ACKENG *ae); //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Internal function called by AckInitialize(). This function sets up the // internal variables that are required to support the off-screen buffer //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс void AckSetupWindow(ACKENG *ae) { // Access the center row of the viewport ae->CenterRow = ae->WinStartY + ((ae->WinEndY - ae->WinStartY) / 2); // Access a memory location for the center row ae->CenterOffset = ae->CenterRow * BYTES_PER_ROW; // Access the starting memory location of the viewport ae->WinStartOffset = ae->WinStartY * BYTES_PER_ROW; // Calculate the window length in double words ae->WinLength = ((ae->WinEndY - ae->WinStartY)+1) * DWORDS_PER_ROW; // Calculates the viewport window width and height ae->WinWidth = (ae->WinEndX - ae->WinStartX) + 1; ae->WinHeight = (ae->WinEndY - ae->WinStartY) + 1; } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Initializes the ACK interface structure and reads in the TRIG tables // from either the stand alone file TRIG.DAT or from a resource file that // was opened previous to this call. // This function MUST be called before AckBuildView() and AckDisplayScreen() //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс short AckInitialize(ACKENG *ae) { short i,result = 0; short j; UCHAR topcolor; AckKeyboardSetup = 0; // Indicates keyboard interrupt has not been set up AckTimerSetup = 0; // Indicates timer has not been set up // Check to see if viewport coordinates are set up properly if (!ae->WinEndY || !ae->WinEndX || (ae->WinEndY - ae->WinStartY) < 10 || // Height is less than 10 pixels (ae->WinEndX - ae->WinStartX) < 10) // Width is less than 10 pixels { return(ERR_BADWINDOWSIZE); // Return error code for invalid viewport } result = AckBuildTables(ae); // Read in TRIG.DAT and allocate tables if (result) return(result); AckSetupWindow(ae); // Set up the internal coordinates for the viewport SetupFloors(ae); // Set up the floors AckBuildHeightTables(ae); // Build height and adjustment tables topcolor = ae->TopColor; BackDropRows = 100; for (i = 0; i < 640; i++) { BackArray[i] = (UCHAR*)AckMalloc(BackDropRows+1); if (BackArray[i] == NULL) return(ERR_NOMEMORY); memset(BackArray[i],topcolor,BackDropRows); } return(result); } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Opens a resource file for use by any ACK routine that requires a // filename. Only one resource file can be opened at a time. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс short AckOpenResource(char *fName) { ULONG hLen; if (rsHandle) // Is a resource file currently opened? close(rsHandle); // Close it before opening a new one rsHandle = open(fName,O_RDONLY|O_BINARY); // Open new resource file if (rsHandle < 1) // Check to see if file is opened properly { rsHandle = 0; // Reset file handle return(ERR_BADFILE); // Return error code for faliure } hLen = MAX_RBA * sizeof(long); // Get size of file if (rbaTable == NULL) rbaTable = (ULONG *)AckMalloc(hLen); // Allocate buffer for file if (rbaTable == NULL) // Was memory available? { close(rsHandle); // Close file rsHandle = 0; // Reset file handle return(ERR_NOMEMORY); // Return error code } // Read in the file and check for byte count error if (read(rsHandle,(ULONG *)rbaTable,hLen) != hLen) { close(rsHandle); // Close file rsHandle = 0; // Reset file handle AckFree(rbaTable); // Free up buffer return(ERR_BADFILE); // Return file error code } strcpy(rsName,fName); // Store resource filename return(0); } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Closes a resource file if one is opened. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс void AckCloseResource(void) { if (rsHandle) // Check to make sure resource file is opened close(rsHandle); // Close the resource if (rbaTable != NULL) // Do we need to free the memory for the file buffer? { AckFree(rbaTable); // Free up the file buffer rbaTable = NULL; } rsHandle = 0; // Reset the file handle } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Internal function used to pre-define height tables for the wall // drawing code. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс void BuildWallDstTables(void) { short i,j,dst,row,HiValue; long ldst,value,LowValue,len; short *lp; for (ldst = 10;ldst < 2048; ldst++) { HiValue = value = 0; row = 0; while (HiValue < 64 && row < 100) { HiValue = (value >> 8) & 0xFF; tmpLowerValue[row] = HiValue; row++; value += ldst; } LowerLen[ldst] = row; len = row * 2; j = 1; if (row == LowerLen[ldst-1]) { j = 0; lp = LowerTable[ldst-1]; for (i = 0; i < row; i++) { if (tmpLowerValue[i] != lp[i]) { j = 1; break; } } } if (j) { lp = (short*)AckMalloc(len); if (lp == NULL) { return; } LowerTable[ldst] = lp; for (i = 0; i < row; i++) lp[i] = tmpLowerValue[i]; } else { LowerTable[ldst] = LowerTable[ldst-1]; } } } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Internal function called from AckInitialize() to read in the trig tables // and allocate memory for the various buffers. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс short AckBuildTables(ACKENG *ae) { short handle,len,ca,na; int c,s,ang; long fAng,tu,tv; SLICE *sa,*saNext; BuildWallDstTables(); // Create the distance tables if (!rsHandle) // Check to make sure resource file is not opened { handle = open("trig.dat",O_RDONLY|O_BINARY); // Open trig data file if (handle < 1) return(ERR_BADFILE); // File can't be opened; return error code } else { handle = rsHandle; // Get handle for resource file lseek(handle,rbaTable[0],SEEK_SET); } // Allocate memory for trig and coordinate tables LongTanTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); LongInvTanTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); CosTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); SinTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); LongCosTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); xNextTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); yNextTable = (long *)AckMalloc(sizeof(long) * INT_ANGLE_360); ViewCosTable = (long *)AckMalloc(sizeof(long) * VIEW_WIDTH); // Allocate memory for map grid and object grid Grid = (unsigned short *)AckMalloc((GRID_MAX * 2)+1); ObjGrid = (unsigned short *)AckMalloc((GRID_MAX * 2)+1); // Allocate memory for height adjustment table AdjustTable = (long *)AckMalloc((MAX_DISTANCE+1) * sizeof(long)); // Allocate memory for screen buffers ae->ScreenBuffer = (UCHAR *)AckMalloc(SCREEN_SIZE+640); ae->BkgdBuffer = (UCHAR *)AckMalloc(SCREEN_SIZE+640); if (LongTanTable == NULL || // Make sure memory is allocated for tables LongInvTanTable == NULL || CosTable == NULL || SinTable == NULL || LongCosTable == NULL || xNextTable == NULL || yNextTable == NULL || Grid == NULL || ObjGrid == NULL || AdjustTable == NULL || ae->ScreenBuffer == NULL || ae->BkgdBuffer == NULL || ViewCosTable == NULL) { if (!rsHandle) close(handle); return(ERR_NOMEMORY); // Return memory allocation error code } len = sizeof(long) * INT_ANGLE_360; // Calculate size for each trig table read(handle,SinTable,len); // Read in trig data and place in appropriate tables read(handle,CosTable,len); read(handle,LongTanTable,len); read(handle,LongInvTanTable,len); read(handle,InvCosTable,len); read(handle,InvSinTable,len); read(handle,LongCosTable,len); if (!rsHandle) close(handle); // Done reading, close trig.dat ca = INT_ANGLE_32; na = -1; // Set up viewing tables for 32 to -32 angle sweep for (len = 0; len < VIEW_WIDTH; len++) { ViewCosTable[len] = LongCosTable[ca]; FloorCosTable[len] = InvCosTable[ca] >> 6; ca += na; if (ca <= 0) // Index is less than 0 so switch { ca = -ca; na = -na; } } // Adjust tables for 90, 180, and 270 degree angles LongTanTable[INT_ANGLE_90] = LongTanTable[INT_ANGLE_90+1]; LongInvTanTable[INT_ANGLE_90] = LongInvTanTable[INT_ANGLE_90+1]; LongTanTable[INT_ANGLE_180] = LongTanTable[INT_ANGLE_180+1]; LongInvTanTable[INT_ANGLE_180] = LongInvTanTable[INT_ANGLE_180+1]; LongTanTable[INT_ANGLE_270] = LongTanTable[INT_ANGLE_270+1]; LongInvTanTable[INT_ANGLE_270] = LongInvTanTable[INT_ANGLE_270+1]; for (len = 0; len < INT_ANGLE_360; len++) { yNextTable[len] = (long)BITMAP_WIDTH * LongTanTable[len]; // Calculate y intercept increments xNextTable[len] = (long)BITMAP_WIDTH * LongInvTanTable[len]; // Calculate x intercept increments InvCosTable[len] = InvCosTable[len] >> 4; // Scale inverse tables InvSinTable[len] = InvSinTable[len] >> 6; } // Set up the array od slice structures to represent the full width of the view // Each slice structure is initialized by setting its data fields to 0s // Each slice in the array is also linked to a second slice to reference a slice that // could be visually behind the current slice for (len = 0; len < VIEW_WIDTH; len++) { sa = &Slice[len]; // Initialize array of slice structures memset(sa,0,sizeof(SLICE)); // Set all data to 0 for (ca = 0; ca < 8; ca++) { saNext = (SLICE*)AckMalloc(sizeof(SLICE)); // Create a slice structure to link in if (saNext == NULL) return(ERR_NOMEMORY); // Check for memory allocation memset(saNext,0,sizeof(SLICE)); // Initialize all data to 0 sa->Next = saNext; // Link in slice saNext->Prev = sa; sa = saNext; } } return(0); } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Reads a map file and processes any multi-height walls. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс short AckReadMapFile(ACKENG *ae,char *fName) { short len,handle,rdlen,count,i,pos; int mLen,aLen; UCHAR buf[MAX_MULTI+2]; UCHAR *mPtr; if (!rsHandle) // Check to see if resource file is open already { // No resource file so open new one handle = open(fName,O_RDONLY|O_BINARY); // Open the specified resource if (handle < 1) return(ERR_BADMAPFILE); // File was not opened; return error code } else { handle = rsHandle; // Get handle to open resource lseek(handle,rbaTable[(ULONG)fName],SEEK_SET); // Access opened resource file } aLen = GRID_ARRAY * 2; mLen = GRID_MAX * 2; if (read(handle,Grid,mLen) != mLen) // Read in grid map data { if (!rsHandle) close(handle); return(ERR_READINGMAP); // Return file read error code } if (read(handle,ObjGrid,mLen) != mLen) // Read in object map data { if (!rsHandle) close(handle); return(ERR_READINGMAP); } if (read(handle,ae->xGrid,aLen) != aLen) // Read in x grid data { if (!rsHandle) close(handle); return(ERR_READINGMAP); } if (read(handle,ae->yGrid,aLen) != aLen) // Read in y grid data { if (!rsHandle) close(handle); return(ERR_READINGMAP); } if (read(handle,FloorMap,mLen) != mLen) // Read in floor map data { if (!rsHandle) close(handle); return(ERR_READINGMAP); } if (read(handle,CeilMap,mLen) != mLen) // Read in ceiling map data { if (!rsHandle) close(handle); return(ERR_READINGMAP); } read(handle,&count,2); // Check counter for multi-height walls if (count) { for (i = 0; i < count;i++) // Read in multi-height wall data { read(handle,&pos,2); // Get grid position for this multi-height wall mPtr = (UCHAR *)AckMalloc(MAX_MULTI+1); // Allocate memory for multi-height wall data if (mPtr == NULL) { if (!rsHandle) close(handle); return(ERR_NOMEMORY); } ae->mxGrid[pos] = mPtr; // Store pointer to multi-height wall ae->myGrid[pos] = mPtr; ae->mxGrid[pos+1] = mPtr; ae->myGrid[pos+GRID_WIDTH] = mPtr; read(handle,buf,MAX_MULTI); buf[MAX_MULTI] = '\0'; len = strlen((char*)buf); if (len > MAX_MULTI) len = MAX_MULTI; *mPtr = len; if (len) memmove(&mPtr[1],buf,len); } } if (!rsHandle) // Close handle close(handle); AckBuildGrid(ae); // Build object lists return(0); } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Internal function to create height and distance tables for objects. In // the DistanceTable[] each entry represents the distance from the player // to a wall. The value stored in the array is the hight of the wall at // the corresponding distance. For example, DistanceTable[100] indicates // that the distance to the wall is 100 units. The value stored at this // location is 81--the pixel height f the wall. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс void AckBuildHeightTables(ACKENG *ae) { short i,x; short result; long height; height = BITMAP_WIDTH * 128L; // Calculate distance to height conversion factor DistanceTable[0] = MAX_HEIGHT; // First entry = max. height (960) //************ 64 * 65536 ******** AdjustTable[0] = 4194304L / height; for (i = 1; i < MAX_DISTANCE; i++) // Loop to calculate each entry for the arrays { DistanceTable[i] = height / i; if (height - (DistanceTable[i] * i) > (i / 2)) DistanceTable[i]++; // Add 1 to height value if (DistanceTable[i] < MIN_HEIGHT) // Adjust for min. height (8) DistanceTable[i] = MIN_HEIGHT; if (DistanceTable[i] > MAX_HEIGHT) // Adjust for maax. height (960) DistanceTable[i] = MAX_HEIGHT; AdjustTable[i] = 2097152L / DistanceTable[i]; // Calculate entry for } } //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс // Internal function called by AckReadMapFile() to process the objects // in the map. Moveable vs stationary objects are processed here. //сссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссссс void AckBuildGrid(ACKENG *ae) { short i,j,CurIndex,pos,x1,y1; USHORT MapCode,MapHiCode; // Initialize doors for (i = 0; i < MAX_DOORS; i++) { ae->Door[i].ColOffset = 0; ae->Door[i].mPos = ae->Door[i].mPos1 = -1; } ae->SysFlags |= SYS_NO_WALLS; // Assume no floating walls CurIndex = 1; TotalSpecial = 0; TotalSecret = 0; for (i = 0; i < GRID_HEIGHT; i++) // Loop until entire grid has been checked { for (j = 0; j < GRID_WIDTH; j++) { pos = (i * GRID_WIDTH) + j; MapCode = ObjGrid[pos]; // Check object at current grid position if (MapCode) // Is there an object here? { CurIndex = MapCode & 0xFF; if (CurIndex < MAX_OBJECTS) // Get the index of the object into { if (ae->ObjList[CurIndex] == NULL) // No object allocated yet { // Allocate memory for object ae->ObjList[CurIndex] = (NEWOBJECT *)AckMalloc(sizeof(NEWOBJECT)); if (ae->ObjList[CurIndex] != NULL) memset(ae->ObjList[CurIndex],0,sizeof(NEWOBJECT)); } // If memory has been allocated calculate coordinates for object if (ae->ObjList[CurIndex] != NULL) { x1 = (j * BITMAP_WIDTH) + (BITMAP_WIDTH/2); y1 = (i * BITMAP_WIDTH) + (BITMAP_WIDTH/2); ae->ObjList[CurIndex]->x = x1; // Store x,y position ae->ObjList[CurIndex]->y = y1; ae->ObjList[CurIndex]->mPos = pos; // Store map position ae->ObjList[CurIndex]->Active = 1; // Indicates object is active } } } } } } // **** End of Source ****