// C Header File // Created 11/30/2002; 8:19:48 PM #ifdef COMPRESSED_TEXTURES static inline void *GetTexSpace(void); static inline short LoadOneTexture(short texcode); static void LoadLevelTextures(void); #else static void HandleLevelTextures(void); #endif static inline void SetupSpawnPoint(void); static void InitButtonPtr(short a); //static void InitButtonPtrTo(short a,short i); static inline void InitButtons(void); static inline char GetBaseWallFromButton(char before_after); static inline short GetButtonIdxOfDoor(unsigned char xtile, unsigned char ytile); static inline void CreateDoors(void); #ifndef __LEVEL_INIT_H__ #define __LEVEL_INIT_H__ #ifdef COMPRESSED_TEXTURES static inline void *GetTexSpace(void) { register GameGlobals *ggg asm("a4") = gg; short a; for(a=0;aunpackedtex[a]) { ggg->unpackedtex[a] = TRUE; return (void*)(ggg->texspace+1024*a); } } return NULL; } static inline short LoadOneTexture(short texcode) { register GameGlobals *ggg asm("a4") = gg; if (ttarchive_valid(ggg->texptr)) { unsigned char* pointer_to_entry = ttarchive_data(ggg->texptr,texcode); //unsigned short size_of_entry = ttarchive_desc(texptr,texcode)->length; unsigned char* decompressed; //----------------------------------------------------------------------- // Now we have a pointer to the entry and we know how large this entry is // If the entry is compressed we could easily decompress it like this: //----------------------------------------------------------------------- if (ttunpack_valid(pointer_to_entry)) { // this entry is compressed ... if ((decompressed = GetTexSpace()/*malloc_special(ttunpack_size(pointer_to_entry))*/)) { if (ttunpack_decompress(pointer_to_entry,decompressed) == TTUNPACK_OKAY) { //--------------------------------- // entry successfully decompressed. // do something with it. //--------------------------------- short i; for(i=0;i<4;i++) { ggg->textures[texcode].strips[i].lightdata = (short*)(decompressed+128*i); ggg->textures[texcode].strips[i].darkdata = (short*)(decompressed+512+128*i); ggg->textures[texcode].strips[i].maskdata = NULL; ggg->textures[texcode].strips[i].mirrored = STRIP_NORMAL; } /*/////////////////////////////////////////////////////////////////// AddWaterToTexture(textures+texcode); /////////////////////////////////////////////////////////////////////// */ ggg->texptrs[texcode] = decompressed; } else { ggg->texptrs[texcode] = NULL; return 0; //free_special(decompressed); // free allocated memory for decompressed entry again } } else { ggg->texptrs[texcode] = NULL; return 0; } } else { // this entry is NOT compressed. Do something else with it .... ggg->texptrs[texcode] = NULL; return 0; } } else { //not even a TTarchive... ggg->texptrs[texcode] = NULL; return 0; } return 1; } static void LoadLevelTextures(void) { register GameGlobals *ggg asm("a4") = gg; #include "walls_animated.txt" short a=0,i; char backup = fc->map_data[0]; for(i=0;itexptrs[i] = NULL; } for(i=0;imap_width*fc->map_height;i++) { char val = fc->map_data[i]; if(val > 0 && val <= TOTAL_TEXCONFIGS_IN_oblvgfx1) { /////////////SPECIAL TILE COUNTS/////////////////////// if(val>=27 && val <=29) //Monitor ggg->monitor_count++; if(val==23 || val==25) ggg->panel_count++; /////////////////////////////////////////////////////// if(ggg->texptrs[val-1]) continue; if(!LoadOneTexture((short)(val-1))) { ggg->quitting = E2Q(OBLIVION_GFX_FILE_ERROR); return; } fc->map_data[a] = val; #include "walls_hit.txt" if(fc->map_data[a]!=val) { val = fc->map_data[a]; if(ggg->texptrs[val-1]) continue; if(!LoadOneTexture((short)(val-1))) { ggg->quitting = E2Q(OBLIVION_GFX_FILE_ERROR); return; } } } } short max = (signed)(sizeof(animatedwalls)/sizeof(animatedwalls[0])); for(i=0;itexptrs[index-1]) { short j; for(j=1;j<=(short)animatedwalls[i][1];j++) { if(ggg->texptrs[index+j-1]) continue; if(!LoadOneTexture((short)(index+j-1))) { ggg->quitting = E2Q(OBLIVION_GFX_FILE_ERROR); return; } } } } //FORCED TEXTURES: #22/45 (textures[21]) for doors //WARNING: This is linked to door support (if updated, update CreateDoors) if(!ggg->texptrs[22-1]) { if(!LoadOneTexture(22-1)) { ggg->quitting = E2Q(OBLIVION_GFX_FILE_ERROR); return; } } //SPECIAL TEXTURES: 51 and 52 (skulls) if(ggg->texptrs[51-1] && !ggg->texptrs[52-1]) { if(!LoadOneTexture(52-1)) { ggg->quitting = E2Q(OBLIVION_GFX_FILE_ERROR); return; } } fc->map_data[a] = backup; } /*void FreeLevelTextures(void) { register GameGlobals *ggg asm("a4") = gg; short a; for(a=0;amap_width*fc->map_height;i++) { char val = fc->map_data[i]; if(val > 0 && val <= TOTAL_TEXCONFIGS_IN_oblvgfx1) { /////////////SPECIAL TILE COUNTS/////////////////////// if(val>=27 && val <=29) //Monitor ggg->monitor_count++; if(val==23 || val==25) ggg->panel_count++; /////////////////////////////////////////////////////// } } } #endif #define SetUpOldTile() {ggg->old_tile = traversedTile/*fc->map_data[(fc\ ->cam_xpos>>6)+(fc->cam_ypos>>6)*fc->map_width]*/;} static inline void SetupSpawnPoint(void) { register GameGlobals *ggg asm("a4") = gg; short a; short angle; for(a=0;amap_width*fc->map_height;a++) { if(ggg->old_level) { if(fc->map_data[a] == exitPoint) { fc->cam_xpos = (a % fc->map_width)*64 + 32; fc->cam_ypos = (a / fc->map_width)*64 + 32; break; } } else { if(fc->map_data[a] <= spawnEast && fc->map_data[a] >= spawnNorthEast) { angle = fc->map_data[a]; angle = (-angle+spawnEast)*ANGLE_045; fc->cam_xpos = (a % fc->map_width)*64 + 32; fc->cam_ypos = (a / fc->map_width)*64 + 32; fc->cam_orientation = angle; ggg->cur_orientation = angle; break; } } } if(a==fc->map_width*fc->map_height) ggg->quitting = E2Q(OBLIVION_MAP_INCORRECT_ERROR); SetUpOldTile(); } static void InitButtonPtr(short a) { register GameGlobals *ggg asm("a4") = gg; TEXCONFIG *texptr1 = ggg->textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a; TEXCONFIG *texptr2 = ggg->textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a+MAX_UNIQUE_BUTTONS; short t; for(t=0;t<4;t++) { texptr1->strips[t].lightdata = ggg->light_data[a]+64*t; texptr1->strips[t].darkdata = ggg->dark_data[a]+64*t; texptr2->strips[t].lightdata = ggg->light_data2[a]+64*t; texptr2->strips[t].darkdata = ggg->dark_data2[a]+64*t; } } /* static void InitButtonPtrTo(short a,short i) { register GameGlobals *ggg asm("a4") = gg; TEXCONFIG *texptr1 = textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a; TEXCONFIG *texptr2 = textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a+MAX_UNIQUE_BUTTONS; short t; for(t=0;t<4;t++) { texptr1->strips[t].lightdata = light_data[i]+64*t; texptr1->strips[t].darkdata = dark_data[i]+64*t; texptr2->strips[t].lightdata = light_data2[i]+64*t; texptr2->strips[t].darkdata = dark_data2[i]+64*t; } }*/ /* IDEA BEHIND BUTTON DECALS: For each wall that has a button on it, buffers are allocated to copy the wall texture to. Then, the button is drawn on the wall buffer using sprites. The Textures in FATCONFIG are updated to support the additional texture, and the map data at the location is updated as well. The code also checks to make sure the wall hasn't already been done, so that there will not be multiple buffers for the same wall texture (to save resources) */ //Initialize the buttons //Note: Not the simplest code in the world static inline void InitButtons(void) { register GameGlobals *ggg asm("a4") = gg; short xsize = fc->map_width; char *ptr = fc->map_data; short idx = 0; short before_idx, after_idx; char walls[MAX_BUTTONS][2]; char walldata=0; short match; short i; short uniques = -1; #include "walls_nobuttons.txt" //Used to prevent multiple copies and buttons drawn for the same wall texture inline short WallAlreadyHasButton(short a) { short i; for(i=0;ibutton_data[a].y*xsize+gg->button_data[a].x]-1) return 1; } return 0; } inline short WallNeedsButton(short a) { unsigned short i; for(i=0;ibutton_data[a].y*xsize+gg->button_data[a].x]) return i; } return -1; //special TRUE } //If the wall already has been done, find the index inline short MatchButton(short a,char *w, char wd) { short i; for(i=0;ibuttoncount;idx++) { //Keycard handling if(ggg->button_data[idx].x & 0x80) { ggg->button[idx].isKeycard = TRUE; ggg->button_data[idx].x &= (unsigned char)~0x80; } else ggg->button[idx].isKeycard = FALSE; i = WallNeedsButton(idx); if(i == -1) //TRUE { if(!WallAlreadyHasButton(idx)) //wall DOES NOT already have a button { uniques++; //Texture indices //When texture space is first allocated, mem for button textured walls (up to //MAX_UNIQUE_BUTTONS buttons is reserved as well. //0 to TOTAL_TEXCONFIGS - 1: Normal Textures //TOTAL_TEXCONFIGS to TOTAL_TEXCONFIGS // + MAX_UNIQUE_BUTTONS - 1: For unpressed buttons //TOTAL_TEXCONFIGS + MAX_UNIQUE_BUTTONS to TOTAL_TEXCONFIGS // + MAX_UNIQUE_BUTTONS*2 - 1: For pressed buttons before_idx = TOTAL_TEXCONFIGS_IN_oblvgfx1 + uniques; after_idx = TOTAL_TEXCONFIGS_IN_oblvgfx1 + uniques + MAX_UNIQUE_BUTTONS; //Copy the wall textures to the allocated buffers CopyTextures(&ggg->textures[(short)ptr[ggg->button_data[idx].y*xsize +ggg->button_data[idx].x]-1],uniques); //Map data - 1, i.e. the texture index walldata = ptr[ggg->button_data[idx].y*xsize+ggg->button_data[idx].x]-1; //Save in Walls array, for duplicate protection walls[idx][0] = walldata; walls[idx][1] = uniques; InitButtonPtr(uniques); if(ggg->button[idx].isKeycard) { //Draw button sprites to new buffer textures AddKeycardToTexture(&ggg->textures[before_idx],keycard1l,keycard1d); AddKeycardToTexture(&ggg->textures[after_idx],keycard2l,keycard2d); } else { //Draw button sprites to new buffer textures AddButtonToTexture(&ggg->textures[before_idx],button1l,button1d, buttonmask); AddButtonToTexture(&ggg->textures[after_idx],button2l,button2d, buttonmask); } }//end IF else //wall DOES already have a button { //Map data - 1, i.e. the texture index walldata = ptr[ggg->button_data[idx].y*xsize+ggg->button_data[idx].x]-1; //Find the index match = MatchButton(idx,*walls,walldata); //InitButtonPtrTo(idx,match); //Texture indices //When texture space is first allocated, mem for ggg->button textured walls (up to //MAX_UNIQUE_BUTTONS buttons is reserved as well. //0 to TOTAL_TEXCONFIGS - 1: Normal Textures //TOTAL_TEXCONFIGS to TOTAL_TEXCONFIGS // + MAX_UNIQUE_BUTTONS - 1: For unpressed buttons //TOTAL_TEXCONFIGS + MAX_UNIQUE_BUTTONS to TOTAL_TEXCONFIGS // + MAX_UNIQUE_BUTTONS*2 - 1: For pressed buttons before_idx = TOTAL_TEXCONFIGS_IN_oblvgfx1 + match; after_idx = TOTAL_TEXCONFIGS_IN_oblvgfx1 + match + MAX_UNIQUE_BUTTONS; //Save in Walls array, for duplicate protection walls[idx][0] = walldata; walls[idx][1] = uniques; } //end ELSE }//end if wall needs button else { before_idx = walls_nobuttons[i][0] - 1; after_idx = walls_nobuttons[i][1] - 1; walldata = ptr[ggg->button_data[idx].y*xsize+ggg->button_data[idx].x]-1; } //Whether the wall had been done before or not, do the default stuff //Pointer to ggg->button structure //Contains ggg->button and door coordinates ggg->button[idx].status = ggg->old_level?BUTTON_PRESSED:BUTTON_UNPRESSED; ggg->button[idx].basetile = walldata+1; ggg->button[idx].shootonly = i!=-1; if(ggg->button[idx].isKeycard) ggg->button[idx].shootonly=PRESS_ONLY; //+1 to convert from texture indices to map data [indices] ggg->button[idx].beforetile = before_idx+1; ggg->button[idx].aftertile = after_idx+1; //Set the map data to the ggg->button's "before tile" ptr[ggg->button_data[idx].y*xsize+ggg->button_data[idx].x] = ggg->old_level?ggg->button[idx].aftertile:ggg->button[idx].beforetile; } //return buttoncount; } static inline char GetBaseWallFromButton(char before_after) { register GameGlobals *ggg asm("a4") = gg; if(!ggg->buttoncount) return -1; unsigned short low,high; low = 0; high = ggg->buttoncount-1; while (low <= high) { if (ggg->button[low].beforetile==before_after || ggg->button[low].aftertile==before_after) return ggg->button[low].basetile; low++; } return -1; } /****************************************************************** * use a search to find a ggg->button's index based on a DOOR'S coords *******************************************************************/ static inline short GetButtonIdxOfDoor(unsigned char xtile, unsigned char ytile) { register GameGlobals *ggg asm("a4") = gg; if(!ggg->buttoncount) return -1; short j; for(j=0;jbuttoncount;j++) { if (ggg->button_data[j].doory==ytile && ggg->button_data[j].doorx==xtile) return j; //printf("[[%i %i][%i %i]]",ggg->button[j].info.doorx,ggg->button[j].info.doory,xtile,ytile); } return -1; } //============================================================================= // add all doors defined in map //============================================================================= static inline void CreateDoors(void) { register GameGlobals *ggg asm("a4") = gg; short x, y; short a,idx; char *mapdata,mapdata2; long b; memset(ggg->doortimers,0x00,MAX_DOORS*sizeof(short)); for(a=0;adoorcount;a++) { x = ggg->door_data[a].x; y = ggg->door_data[a].y; idx = GetButtonIdxOfDoor(x,y); mapdata = fc->map_data+y*fc->map_width+x; b=(long)idx; char *checkdata = fc->map_data+y*fc->map_width+x; if (*(checkdata-1)>0 && *(checkdata-1)!=CLOSED_DOOR_TILE && *(checkdata+1)>0 && *(checkdata+1)!=CLOSED_DOOR_TILE) { mapdata2 = fc->map_data[y*fc->map_width+(x-1)]; if(mapdata2==127) mapdata2 = fc->map_data[y*fc->map_width+(x+1)]; if(mapdata2>TOTAL_TEXCONFIGS_IN_oblvgfx1) //this is a button wall { mapdata2 = GetBaseWallFromButton(mapdata2); if(mapdata2==-1) mapdata2 = 22; } FAT_AddDoor(x, y, DOOR_HORIZONTAL, DOOR_CLOSED, 0, &ggg->textures[(short)*mapdata-1],&ggg->textures[(short)mapdata2-1], (void*)b); } else { mapdata2 = fc->map_data[(y-1)*fc->map_width+x]; if(mapdata2==127) mapdata2 = fc->map_data[(y+1)*fc->map_width+x]; if(!mapdata2) mapdata2 = 22; if(mapdata2>TOTAL_TEXCONFIGS_IN_oblvgfx1) //this is a button wall { mapdata2 = GetBaseWallFromButton(mapdata2); if(mapdata2==-1) mapdata2 = 22; } FAT_AddDoor(x, y, DOOR_VERTICAL, DOOR_CLOSED, 0, &ggg->textures[(short)*mapdata-1],&ggg->textures[(short)mapdata2-1], (void*)b); } *mapdata = 127; } //return ggg->doorcount; } #endif