//------------------------------------------------------------------------- /* Copyright (C) 1997, 2005 - 3D Realms Entertainment This file is part of Shadow Warrior version 1.2 Shadow Warrior 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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Original Source: 1997 - Frank Maddin and Jim Norwood Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms */ //------------------------------------------------------------------------- #include "ns.h" #include "build.h" #include "osd.h" #include "keys.h" #include "names2.h" #include "panel.h" #include "game.h" #include "tags.h" #include "sector.h" #include "sprite.h" #include "weapon.h" #include "player.h" #include "jsector.h" #include "menus.h" #include "sw_strs.h" #include "pal.h" #include "demo.h" #include "keydef.h" #include "gamecontrol.h" #include "gamedefs.h" #include "config.h" #include "network.h" #include "text.h" #include "version.h" #include "network.h" #include "colormap.h" #include "config.h" BEGIN_SW_NS //#define PLOCK_VERSION TRUE extern SWBOOL ExitLevel, NewGame; short TimeLimitTable[9] = {0,3,5,10,15,20,30,45,60}; SWBOOL MNU_StartNetGame(void) { extern SWBOOL ExitLevel, ShortGameMode, DemoInitOnce, FirstTimeIntoGame; extern short Level, Skill; // CTW REMOVED //extern int gTenActivated; // CTW REMOVED END int pnum; // always assumed that a demo is playing ready2send = 0; // Skill can go negative here Skill = gs.NetMonsters - 1; Level = gs.NetLevel + 1; DemoPlaying = FALSE; ExitLevel = TRUE; NewGame = TRUE; // restart demo for multi-play mode DemoInitOnce = FALSE; // TENSW: return if a joiner if (/* CTW REMOVED gTenActivated && */ !AutoNet && FirstTimeIntoGame) return TRUE; // need to set gNet vars for self // everone else gets a packet to set them gNet.AutoAim = cl_autoaim; gNet.SpawnMarkers = gs.NetSpawnMarkers; gNet.HurtTeammate = gs.NetHurtTeammate; gNet.Nuke = gs.NetNuke; gNet.KillLimit = gs.NetKillLimit * 10; gNet.TimeLimit = TimeLimitTable[gs.NetTimeLimit] * 60 * 120; if (ShortGameMode) { gNet.KillLimit /= 10; gNet.TimeLimit /= 2; } gNet.TimeLimitClock = gNet.TimeLimit; gNet.TeamPlay = gs.NetTeamPlay; gNet.MultiGameType = gs.NetGameType + 1; if (gNet.MultiGameType == MULTI_GAME_COMMBAT_NO_RESPAWN) { gNet.MultiGameType = MULTI_GAME_COMMBAT; gNet.NoRespawn = TRUE; } else { gNet.NoRespawn = FALSE; } if (CommEnabled) { PACKET_NEW_GAME p; p.PacketType = PACKET_TYPE_NEW_GAME; p.Level = Level; p.Skill = Skill; p.GameType = gs.NetGameType; p.AutoAim = cl_autoaim; p.HurtTeammate = gs.NetHurtTeammate; p.TeamPlay = gs.NetTeamPlay; p.SpawnMarkers = gs.NetSpawnMarkers; p.KillLimit = gs.NetKillLimit; p.TimeLimit = gs.NetTimeLimit; p.Nuke = gs.NetNuke; netbroadcastpacket((uint8_t*)(&p), sizeof(p)); // TENSW } return TRUE; } //////////////////////////////////////////////// // Measure the pixel width of a graphic string //////////////////////////////////////////////// static char lg_xlat_num[] = { 0,1,2,3,4,5,6,7,8,9 }; #define FONT_LARGE_ALPHA 3706 #define FONT_LARGE_DIGIT 3732 #define MenuDrawFlags (ROTATE_SPRITE_SCREEN_CLIP) #define MZ 65536 #define MENU_SHADE_DEFAULT 0 #define MENU_SHADE_INACTIVE 20 void MNU_MeasureStringLarge(const char *string, short *w, short *h) { short ndx, width, height; char c; short pic; width = 0; height = *h; for (ndx = 0; (c = string[ndx]) != 0; ndx++) { if (isalpha(c)) { c = toupper(c); pic = FONT_LARGE_ALPHA + (c - 'A'); } else if (isdigit(c)) { pic = FONT_LARGE_DIGIT + lg_xlat_num[(c - '0')]; } else if (c == ' ') { width += 10; // Special case for space char continue; } else { continue; } width += tilesiz[pic].x+1; if (height < tilesiz[pic].y) height = tilesiz[pic].y; } *w = width; *h = height; } //////////////////////////////////////////////// // Draw a string using a graphic font //////////////////////////////////////////////// void MNU_DrawStringLarge(short x, short y, const char *string, int shade) { int ndx, offset; char c; short pic; offset = x; for (ndx = 0; (c = string[ndx]) != 0; ndx++) { if (isalpha(c)) { c = toupper(c); pic = FONT_LARGE_ALPHA + (c - 'A'); } else if (isdigit(c)) { pic = FONT_LARGE_DIGIT + lg_xlat_num[(c - '0')]; } else if (c == ' ') { offset += 10; continue; } else { continue; } rotatesprite(offset << 16, y << 16, MZ, 0, pic, shade, 0, MenuDrawFlags|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1); offset += tilesiz[pic].x + 1; } } //////////////////////////////////////////////// // Measure the pixel width of a graphic string //////////////////////////////////////////////// void MNU_MeasureString(const char *string, short *w, short *h) { short ndx, width, height; char c; short ac; if (string[0] == '^') { MNU_MeasureStringLarge(&string[1], w, h); return; } width = 0; height = *h; for (ndx = 0; (c = string[ndx]) != 0; ndx++) { ac = c - '!' + STARTALPHANUM; if ((ac < STARTALPHANUM || ac > ENDALPHANUM) && c != asc_Space) break; if (c > asc_Space && c < 127) { width += tilesiz[ac].x; if (height < tilesiz[ac].y) height = tilesiz[ac].y; } else if (c == asc_Space) width += 4; // Special case for space char } *w = width; *h = height; } //////////////////////////////////////////////// // Draw a string using a graphic font // // MenuTextShade and MenuDrawFlags //////////////////////////////////////////////// void MNU_DrawString(short x, short y, const char *string, short shade, short pal) { int ndx, offset; char c; short ac; if (string[0] == '^') { MNU_DrawStringLarge(x,y, &string[1]); return; } offset = x; for (ndx = 0; (c = string[ndx]) != 0; ndx++) { ac = c - '!' + STARTALPHANUM; if ((ac < STARTALPHANUM || ac > ENDALPHANUM) && c != asc_Space) break; if (c > asc_Space && c < 127) { rotatesprite(offset<<16,y<<16,MZ,0,ac, shade, pal, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1); offset += tilesiz[ac].x; } else if (c == asc_Space) offset += 4; // Special case for space char } } //////////////////////////////////////////////// // Measure the pixel width of a small font string //////////////////////////////////////////////// void MNU_MeasureSmallString(const char *string, short *w, short *h) { short ndx, width, height; char c; short ac; width = 0; height = *h; for (ndx = 0; (c = string[ndx]) != 0; ndx++) { ac = (c - '!') + 2930; if ((ac < 2930 || ac > 3023) && c != asc_Space) break; if (c > asc_Space && c < 127) { width += tilesiz[ac].x; if (height < tilesiz[ac].y) height = tilesiz[ac].y; } else if (c == asc_Space) width += 4; // Special case for space char } *w = width; *h = height; } //////////////////////////////////////////////// // Draw a string using a small graphic font //////////////////////////////////////////////// void MNU_DrawSmallString(short x, short y, const char *string, short shade, short pal) { int ndx; char c; short ac,offset; offset = x; for (ndx = 0; (c = string[ndx]) != 0; ndx++) { ac = c - '!' + 2930; if ((ac < 2930 || ac > 3023) && c != asc_Space) break; if (c > asc_Space && c < 127) { rotatesprite(offset<<16,y<<16,MZ,0,ac, shade, pal, MenuDrawFlags, 0, 0, xdim - 1, ydim - 1); offset += tilesiz[ac].x; } else if (c == asc_Space) { offset += 4; // Special case for space char } } } ////////////////////////////////////////////////////////////////////////////// #define FADE_DAMAGE_FACTOR 3 // 100 health / 32 shade cycles = 3.125 // Fades from 100% to 62.5% somewhat quickly, // then from 62.5% to 37.5% slowly, // then from 37.5% to 0% quickly. // This seems to capture the pain caused by enemy shots, plus the extreme // fade caused by being blinded or intense pain. // Perhaps the next step would be to apply a gentle smoothing to the // intersections of these lines. static int faderamp[32] = { // y=64-4x 252,240,224,208,192,176, // y=44.8-(16/20)x 160,156,152,152,148, 144,140,136,136,132, 128,124,120,120,116, 112,108,104,104,100, // y=128-4x 96,80,64,48,32,16 }; typedef struct RGB_color_typ { unsigned char red; unsigned char green; unsigned char blue; } RGB_color, * RGB_color_ptr; ////////////////////////////////////////// // Set the amount of redness for damage // the player just took ////////////////////////////////////////// void SetFadeAmt(PLAYERp pp, short damage, unsigned char startcolor) { short fadedamage = 0; RGB_color color; //Printf("SetAmt: fadeamt = %d, startcolor = %d, pp = %d",pp->FadeAmt,startcolor,pp->StartColor); if (abs(pp->FadeAmt) > 0 && startcolor == pp->StartColor) return; // Don't ever over ride flash bomb if (pp->StartColor == 1 && abs(pp->FadeAmt) > 0) return; // Reset the palette if (pp == Player + screenpeek) { videoFadePalette(0, 0, 0, 0); } if (damage < -150 && damage > -1000) fadedamage = 150; else if (damage < -1000) // Underwater fadedamage = abs(damage + 1000); else fadedamage = abs(damage); if (damage >= -5 && damage < 0) fadedamage += 10; // Don't let red to TOO red if (startcolor == COLOR_PAIN && fadedamage > 100) fadedamage = 100; pp->FadeAmt = fadedamage / FADE_DAMAGE_FACTOR; if (pp->FadeAmt <= 0) { pp->FadeAmt = 0; return; } // It's a health item, just do a preset flash amount if (damage > 0) pp->FadeAmt = 3; pp->StartColor = startcolor; pp->FadeTics = 0; color.red = palette[pp->StartColor*3]; color.green = palette[pp->StartColor*3+1]; color.blue = palette[pp->StartColor*3+2]; // Do initial palette set if (pp == Player + screenpeek) { videoFadePalette(color.red, color.green, color.blue, faderamp[min(31, max(0, 32 - abs(pp->FadeAmt)))]); if (damage < -1000) pp->FadeAmt = 1000; // Don't call DoPaletteFlash for underwater stuff } } ////////////////////////////////////////// // Do the screen reddness based on damage ////////////////////////////////////////// #define MAXFADETICS 5 void DoPaletteFlash(PLAYERp pp) { if (pp->FadeAmt <= 1) { pp->FadeAmt = 0; pp->StartColor = 0; if (pp == Player + screenpeek) { videoFadePalette(0, 0, 0, 0); DoPlayerDivePalette(pp); // Check Dive again DoPlayerNightVisionPalette(pp); // Check Night Vision again } return; } pp->FadeTics += synctics; // Add this frame's tic amount to // counter if (pp->FadeTics >= MAXFADETICS) { while (pp->FadeTics >= MAXFADETICS) { pp->FadeTics -= MAXFADETICS; pp->FadeAmt--; // Decrement FadeAmt till it gets to // 0 again. } } else return; // Return if they were not > // MAXFADETICS if (pp->FadeAmt > 32) return; if (pp->FadeAmt <= 1) { pp->FadeAmt = 0; pp->StartColor = 0; if (pp == Player + screenpeek) { videoFadePalette(0, 0, 0, 0); DoPlayerDivePalette(pp); // Check Dive again DoPlayerNightVisionPalette(pp); // Check Night Vision again } return; } else { // Only hard set the palette if this is currently the player's view if (pp == Player + screenpeek) { videoFadePalette( palette[pp->StartColor*3], palette[pp->StartColor*3+1], palette[pp->StartColor*3+2], faderamp[min(31, max(0, 32 - abs(pp->FadeAmt)))] ); } } } SWBOOL MNU_ShareWareMessage() { const char* extra_text; short w, h; if (SW_SHAREWARE) { extra_text = "Be sure to call 800-3DREALMS today"; MNU_MeasureString(extra_text, &w, &h); MNU_DrawString(TEXT_XCENTER(w), 110, extra_text, 1, 16); extra_text = "and order the game."; MNU_MeasureString(extra_text, &w, &h); MNU_DrawString(TEXT_XCENTER(w), 120, extra_text, 1, 16); extra_text = "You are only playing the first "; MNU_MeasureString(extra_text, &w, &h); MNU_DrawString(TEXT_XCENTER(w), 130, extra_text, 1, 16); extra_text = "four levels, and are missing most"; MNU_MeasureString(extra_text, &w, &h); MNU_DrawString(TEXT_XCENTER(w), 140, extra_text, 1, 16); extra_text = "of the game, weapons and monsters."; MNU_MeasureString(extra_text, &w, &h); MNU_DrawString(TEXT_XCENTER(w), 150, extra_text, 1, 16); extra_text = "See the ordering information."; MNU_MeasureString(extra_text, &w, &h); MNU_DrawString(TEXT_XCENTER(w), 160, extra_text, 1, 16); //SET(item->flags, mf_disabled); } return TRUE; } #if 0 #endif END_SW_NS