// C Header File // Created 11/30/2002; 8:19:48 PM #ifdef COMPRESSED_TEXTURES static inline short LoadOneTexture(short texcode) { if (ttarchive_valid(texptr)) { unsigned char* pointer_to_entry = ttarchive_data(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 = 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++) { textures[texcode].strips[i].lightdata = (short*)(decompressed+128*i); textures[texcode].strips[i].darkdata = (short*)(decompressed+512+128*i); textures[texcode].strips[i].maskdata = NULL; textures[texcode].strips[i].mirrored = STRIP_NORMAL; } texptrs[texcode] = decompressed; } else free_special(decompressed); // free allocated memory for decompressed entry again } else { texptrs[texcode] = NULL; return 0; } } else { // this entry is NOT compressed. Do something else with it .... texptrs[texcode] = NULL; return 0; } } else { //not even a TTarchive... texptrs[texcode] = NULL; return 0; } return 1; } short LoadLevelTextures(void) { #include "walls_animated.txt" short a; for(a=0;amap_width*fc->map_height;a++) { char val = fc->map_data[a]; if(val > 0 && val <= TOTAL_TEXCONFIGS_IN_oblvgfx1) { /////////////SEPCIAL TILE COUNTS/////////////////////// if(val>=27 && val <=29) //Monitor monitor_count++; if(val==23 || val==25) panel_count++; /////////////////////////////////////////////////////// if(texptrs[val-1]) continue; if(!LoadOneTexture((short)(val-1))) { quitting = E2Q(OBLIVION_OUT_OF_MEM); return 0; } /*/////////////////////////////////////////////////////////////////// AddWaterToTexture(textures+val-1); ///////////////////////////////////////////////////////////////////////*/ } } for(a=0;a<(signed)(sizeof(animatedwalls)/sizeof(animatedwalls[0]));a++) { short index = animatedwalls[a][0]; if(texptrs[index-1]) { short i; for(i=1;i<=animatedwalls[a][1];i++) { if(texptrs[index+i-1]) continue; if(!LoadOneTexture((short)(index+i-1))) { quitting = E2Q(OBLIVION_OUT_OF_MEM); return 0; } } } } //FORCED TEXTURES: #22/45 (textures[21]) for doors //WARNING: This is linked to door support (if updated, update CreateDoors) if(!texptrs[22-1]) { if(!LoadOneTexture(22-1)) { quitting = E2Q(OBLIVION_OUT_OF_MEM); return 0; } } return 1; } void FreeLevelTextures(void) { short a; for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a] <= spawnEast && fc->map_data[a] >= spawnNorthEast) { short 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; cur_orientation = angle; break; } } if(a==fc->map_width*fc->map_height) quitting = E2Q(OBLIVION_MAP_INCORRECT_ERROR); } void InitButtonPtr(short a) { TEXCONFIG *texptr1 = textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a; TEXCONFIG *texptr2 = textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a+MAX_BUTTONS; short t; for(t=0;t<4;t++) { texptr1->strips[t].lightdata = light_data[a]+64*t; texptr1->strips[t].darkdata = dark_data[a]+64*t; texptr2->strips[t].lightdata = light_data2[a]+64*t; texptr2->strips[t].darkdata = dark_data2[a]+64*t; } } void InitButtonPtrTo(short a,short i) { TEXCONFIG *texptr1 = textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a; TEXCONFIG *texptr2 = textures+TOTAL_TEXCONFIGS_IN_oblvgfx1+a+MAX_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; } } /************************************************************* * use a binary search to find a button's level data **************************************************************/ static inline short GetButtonData(short xtile, short ytile) { unsigned short low, high, mid; low = 0; high = MAX_DOORS-1; while (low <= high) { mid = (low+high)>>1; if (button_data[mid].y==ytile) { if (button_data[mid].x==xtile) { return mid; } if (button_data[mid].x>xtile) high = mid-1; else low = mid+1; } else if (button_data[mid].y>ytile) high = mid-1; else low = mid+1; } return -1; } /* 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 unsigned char InitButtons(void) { short xsize = fc->map_width; char *ptr = fc->map_data; short idx = 0; short before_idx, after_idx; char walls[MAX_BUTTONS]; char walldata=0; short match; short i; #include "walls_nobuttons.txt" //Used to prevent multiple copies and buttons drawn for the same wall texture short WallAlreadyHasButton(short a) { short i; for(i=0;ix==xtile && button[cached_button].info->y==ytile) return cached_button; low = 0; high = button_count-1; while (low <= high) { if (button[low].info->y==ytile) { if (button[low].info->x==xtile) { cached_button = low; return low; }} low++; } return -1; } char GetBaseWallFromButton(char before_after) { unsigned short low,high; low = 0; high = button_count-1; while (low <= high) { if (button[low].beforetile==before_after || button[low].aftertile==before_after) return button[low].basetile; low++; } return -1; } /****************************************************************** * use a search to find a button's index based on a DOOR'S coords *******************************************************************/ short GetButtonIdxOfDoor(unsigned char xtile, unsigned char ytile) { unsigned short low, high; if(!button_count) return -1; low = 0; high = button_count-1; while (low <= high) { if (button[low].info->doory==ytile) { if (button[low].info->doorx==xtile) { cached_button = low; return low; }} low++; } return -1; } static inline void UpdateDoor(FATCONFIG* fc, FATDOOR *door); void DrawVehicle(void) { short x = 96/2-48/2; short y = 96-24; short bytewidth = 48>>3; short height = 24; memset(HUDlight,0x00,576*sizeof(short)); memset(HUDdark,0x00,576*sizeof(short)); memset(HUDmask,0xFF,576*sizeof(short)); SpriteX8_AND_96x96(x,y,height,vehicleAmask,bytewidth,HUDmask); SpriteX8_OR_96x96(x,y,height,vehicleAmask,bytewidth,HUDmask); SpriteX8_AND_96x96(x,y,height,vehicleAlight,bytewidth,HUDlight); SpriteX8_OR_96x96(x,y,height,vehicleAlight,bytewidth,HUDlight); SpriteX8_AND_96x96(x,y,height,vehicleAdark,bytewidth,HUDdark); SpriteX8_OR_96x96(x,y,height,vehicleAdark,bytewidth,HUDdark); } static inline void PressButtonAndOpenDoor(short idx) { short location = button[idx].info->y*fc->map_width + button[idx].info->x; //Update button tile button[idx].status = BUTTON_PRESSED; fc->map_data[location] = button[idx].aftertile; if(KeyCheck(KEY_STRAFE)) { //Show updated button FAT_Render(fc); //Wait about 2/3 a second { unsigned long count = int5_counter; while(int5_counter < count+12) continue; } { short player_x = fc->cam_xpos; short player_y = fc->cam_ypos; short player_orientation = fc->cam_orientation; short mappos; FATDOOR* door = FAT_GetDoor(button[idx].info->doorx,button[idx].info->doory); if(!door) return; if(door->state == DOOR_OPEN) return; //Clear HUD memset(HUDlight,0x00,576*sizeof(short)); memset(HUDdark,0x00,576*sizeof(short)); memset(HUDmask,0xFF,576*sizeof(short)); //Move camera to where door is fc->cam_xpos = (button[idx].info->doorx<<6) + 32; fc->cam_ypos = (button[idx].info->doory<<6) + 32; mappos = (fc->cam_ypos>>6)*fc->map_width+(fc->cam_xpos>>6); if(door->type==DOOR_HORIZONTAL) { fc->cam_ypos -= 64; if(fc->map_data[mappos]==traversedTile|| fc->map_data[mappos]==OPEN_DOOR_TILE) { fc->cam_orientation = ANGLE_SOUTH; fc->cam_ypos -= 32; } else { fc->cam_orientation = ANGLE_NORTH; fc->cam_ypos += 128+31; } } else { fc->cam_xpos += 64; if(fc->map_data[mappos]==traversedTile|| fc->map_data[mappos]==OPEN_DOOR_TILE) { fc->cam_orientation = ANGLE_WEST; fc->cam_xpos += 31; } else { fc->cam_orientation = ANGLE_EAST; fc->cam_xpos -= 128+32; } } /* //Keep updating screen while door opens while(door->state != DOOR_OPEN) { UpdateDoor(fc,door); FAT_Render(fc); }*/ FAT_Render(fc); //Wait about a second { unsigned long count = int5_counter; while(int5_counter < count+19) continue; } //Go back to normal view fc->cam_xpos = player_x; fc->cam_ypos = player_y; fc->cam_orientation = player_orientation; SetupCrosshair(); if(levelstyle==level_vehicle) DrawVehicle(); else DrawWeapon(cur_weapon,W_OFF); } } textEnqueue("You unlocked a door."); } short tileIsOccupied(short x, short y) { short a; short location = y*fc->map_width+x; char spot = fc->map_data[location]; fc->map_data[location]=1; char validmove = ValidMove(fc->cam_xpos,fc->cam_ypos); fc->map_data[location] = spot; if(!validmove) return 1; for(a=0;axpos>>6==x && spr->ypos>>6==y) return 1; } return 0; } void HandleDoors(void) { short a; FATDOOR *curdoor = FAT_GetDoorsArray(); for(a=0;astate==DOOR_OPEN) { if(doortimers[a]!=MAX_DOOR_WAIT) doortimers[a]++; //if(doortimers[a]==MAX_DOOR_WAIT) else { if(!tileIsOccupied(curdoor->xtile,curdoor->ytile)) { doortimers[a] = 0; curdoor->state = DOOR_CLOSING; } } } else UpdateDoor(fc,curdoor); ++curdoor; } } static inline void HandlePressedButtons(void) { short tile_x = ((FAT_Cos16384(fc->cam_orientation) >> 8)+fc->cam_xpos)>>6; short tile_y = ((FAT_Sin16384(fc->cam_orientation) >> 8)+fc->cam_ypos)>>6; //Player is pressing the ChgButton key if(chgbutton_flag) { short idx = GetButtonIdx(tile_x,tile_y); if(idx != -1) { if(button[idx].status == BUTTON_UNPRESSED && !button[idx].shootonly) { PressButtonAndOpenDoor(idx); } } else { FATDOOR *door = FAT_GetDoor(tile_x,tile_y); if(door) { short i = (short)((long)door->clientdata); if(i==-1) { if(door->state==DOOR_CLOSED) door->state = DOOR_OPENING; } else if(button[i].status == BUTTON_PRESSED) { if(door->state==DOOR_CLOSED) door->state = DOOR_OPENING; } else if(door!=olddoor) textEnqueue("Locked!"); olddoor = door; } } } } static inline void HandleShotButtons(short tile_x,short tile_y) { short idx = GetButtonIdx(tile_x,tile_y); if(idx != -1) { if(button[idx].status == BUTTON_UNPRESSED) { PressButtonAndOpenDoor(idx); } } } //============================================================================= // add all doors defined in map //============================================================================= static inline unsigned char CreateDoors(void) { short x, y; short a,idx; char *mapdata,mapdata2; long b; doortimers = calloc(doorcount,sizeof(short));//allocate and initialize to 0 for(a=0;amap_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, &textures[(short)*mapdata-1],&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, &textures[(short)*mapdata-1],&textures[(short)mapdata2-1], (void*)b); } *mapdata = 127; } return doorcount; } //============================================================================= // updates the door in front of the player (or specified by X and Y) // the function uses button[idx]'s coordinates //============================================================================= static inline void UpdateDoor(FATCONFIG* fc, FATDOOR *door) { if (door->state == DOOR_OPENING) { door->position+=4; if (door->position >= 64) { door->position = 64; door->state = DOOR_OPEN; *(fc->map_data + fc->map_width * door->ytile + door->xtile) = OPEN_DOOR_TILE; } } else if (door->state == DOOR_CLOSING) { door->position-=4; if (door->position <= 0) { door->position = 0; door->state = DOOR_CLOSED; } *(fc->map_data + fc->map_width * door->ytile + door->xtile) = CLOSED_DOOR_TILE; } } static inline void AdjustLevelSettings(void) { fc=fc; switch(levelstyle) { case level_findWorkingVehicle: textEnqueue("Find a working vehicle to flee this facility!"); break; case level_vehicle: { DrawVehicle(); textEnqueue("Find the exit... with the help of your vehicle."); vehicle_speed = 0; } break; case level_killAllEnemiesToExit: textEnqueue("You must kill ALL enemies to enable the exit door."); break; case level_killGuardianToContinue: textEnqueue("You must kill the Guardian to continue... its slow projectiles are deadly!"); break; case level_fadeIntoDistance: FAT_SetPredrawCallback(Predraw_FadeIntoDistance); break; } } static inline void HandleEvents(void) { short x = fc->cam_xpos>>6; short y = fc->cam_ypos>>6; char *mapcode = fc->map_data + y*fc->map_width + x; short a; switch(*mapcode) { case exitPoint: quitting = NEW_LEVEL; break; } if(*mapcode!=traversedTile && *mapcode!=OPEN_DOOR_TILE) *mapcode = traversedTile; switch(levelstyle) { case level_killAllEnemiesToExit: { short enemies=FALSE; for(a=0;adesire != ENEMY_NONE) { enemies = TRUE; break; }//end if }//end for if(enemies) break; for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a]==impassibleWall) fc->map_data[a] = exitPoint; } levelstyle = level_normal; //Don't check anymore } break; case level_killGuardianToContinue: { short enemies=FALSE; for(a=0;atype == fatty) { enemies = TRUE; break; }//end if }//end for if(enemies) break; for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a]==impassibleWall) fc->map_data[a] = exitPoint; } levelstyle = level_normal; //Don't check anymore } break; case level_fadeIntoDistance: { for(a=0;acam_xpos-(sprites+a)->xpos),abs(fc->cam_ypos-(sprites+a)->ypos))>200UL) (sprites+a)->drawmode = SPRITEMODE_UNUSED; else (sprites+a)->drawmode = (sprites_extra+a)->drawmode; } } break; case level_destroyAllPanels: if(panel_count) break; for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a]==impassibleWall) fc->map_data[a] = exitPoint; } levelstyle = level_normal; //Don't check anymore break; case level_destroyAllMonitors: if(monitor_count) break; for(a=0;amap_width*fc->map_height;a++) { if(fc->map_data[a]==impassibleWall) fc->map_data[a] = exitPoint; } levelstyle = level_normal; //Don't check anymore break; } }