mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-04-19 17:01:46 +00:00
ZDoom 1.18b.
This commit is contained in:
parent
bf857fb4f4
commit
be1223d0a3
28 changed files with 381 additions and 207 deletions
|
@ -16,7 +16,7 @@ G_game.c (v0.95: Too make demorecording work somewhat)
|
|||
G_input.c (v0.95: added some keycommands)
|
||||
G_input.h (v0.95)
|
||||
P_mobj.c (v0.95: changed much in the P_MobjThinker(), a little in P_SpawnPlayerMissile(), maybee something else )
|
||||
P_mobj.h (v0.95: Removed some uneccisary variables)
|
||||
P_mobj.h (v0.95: Removed some unnecessary variables)
|
||||
P_user.c (v0.95: It's only one change maybee it already was there in 0.71)
|
||||
P_inter.c (v0.95: lot of changes)
|
||||
P_pspr.c (v0.71)
|
||||
|
@ -27,7 +27,7 @@ Info.c (v0.95: maybee same as 0.71)
|
|||
Info.h (v0.95: maybee same as 0.71)
|
||||
M_menu.c (v0.95: an extra menu in the key setup with the new commands)
|
||||
R_main.c (v0.95: Fix for bot's view)
|
||||
wi_stuff.c (v0.97: Too remove bots correct)
|
||||
wi_stuff.c (v0.97: To remove bots correct)
|
||||
|
||||
(v0.85) Removed all my code from: P_enemy.c
|
||||
New file: b_move.c
|
||||
|
@ -38,7 +38,7 @@ What I know has to be done. in near future.
|
|||
- Do some hunting/fleeing functions.
|
||||
- Make the roaming 100% flawfree.
|
||||
- Fix all SIGSEVS (Below is known SIGSEVS)
|
||||
-Nada (but they might bee there)
|
||||
-Nada (but they might be there)
|
||||
******************************************
|
||||
Everything that is changed is marked (maybe commented) with "Added by MC"
|
||||
*/
|
||||
|
@ -389,7 +389,8 @@ void DCajunMaster::RemoveAllBots (bool fromlist)
|
|||
int i;
|
||||
int removed = 0;
|
||||
|
||||
if (players[consoleplayer].camera->player &&
|
||||
if (players[consoleplayer].camera &&
|
||||
players[consoleplayer].camera->player &&
|
||||
(!playeringame[players[consoleplayer].camera->player - players]
|
||||
||players[consoleplayer].camera->player->isbot))
|
||||
{
|
||||
|
@ -407,11 +408,12 @@ void DCajunMaster::RemoveAllBots (bool fromlist)
|
|||
}
|
||||
|
||||
if (fromlist)
|
||||
{
|
||||
wanted_botnum = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
waitingforspawn[i] = false;
|
||||
}
|
||||
botnum = 0;
|
||||
|
||||
if (removed)
|
||||
Printf (PRINT_HIGH, "Removed all bots\n");
|
||||
}
|
||||
|
||||
//Clean the bot part of the player_t
|
||||
|
|
|
@ -39,12 +39,13 @@ void DCajunMaster::Think (AActor *actor, ticcmd_t *cmd)
|
|||
ThinkForMove (actor, cmd);
|
||||
TurnToAng (actor);
|
||||
|
||||
cmd->ucmd.yaw = (short)((actor->angle - oldyaw) >> 16);
|
||||
cmd->ucmd.yaw = (short)((actor->angle - oldyaw) >> 16) / ticdup;
|
||||
cmd->ucmd.pitch = (short)((oldpitch - actor->pitch) >> 16);
|
||||
if (cmd->ucmd.pitch == -37268)
|
||||
cmd->ucmd.pitch = -32767;
|
||||
actor->angle = oldyaw + (cmd->ucmd.yaw << 16);
|
||||
actor->pitch = oldpitch - (cmd->ucmd.pitch << 16);
|
||||
cmd->ucmd.pitch /= ticdup;
|
||||
actor->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
|
||||
actor->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
|
||||
}
|
||||
|
||||
if (actor->player->t_active) actor->player->t_active--;
|
||||
|
@ -291,7 +292,17 @@ void DCajunMaster::Set_enemy (AActor *actor)
|
|||
{
|
||||
AActor *oldenemy;
|
||||
|
||||
oldenemy = actor->player->enemy;
|
||||
if (actor->player->enemy
|
||||
&& actor->player->enemy->health > 0
|
||||
&& P_CheckSight (actor, actor->player->enemy))
|
||||
{
|
||||
oldenemy = actor->player->enemy;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldenemy = NULL;
|
||||
}
|
||||
|
||||
actor->player->allround = !!actor->player->enemy;
|
||||
actor->player->enemy = NULL;
|
||||
actor->player->enemy = Find_enemy(actor);
|
||||
|
|
|
@ -73,7 +73,10 @@ private:
|
|||
|
||||
// Writes all cvars that could effect demo sync to *demo_p. These are
|
||||
// cvars that have either CVAR_SERVERINFO or CVAR_DEMOSAVE set.
|
||||
friend void C_WriteCVars (byte **demo_p, unsigned int filter);
|
||||
friend void C_WriteCVars (byte **demo_p, DWORD filter, bool compact=false);
|
||||
|
||||
// Read all cvars from *demo_p and set them appropriately.
|
||||
friend void C_ReadCVars (byte **demo_p);
|
||||
|
||||
// Backup demo cvars. Called before a demo starts playing to save all
|
||||
// cvars the demo might change.
|
||||
|
@ -102,9 +105,6 @@ inline cvar_t *cvar_set (const char *var_name, const byte *value) { return cvar_
|
|||
inline cvar_t *cvar_forceset (const char *var_name, const byte *value) { return cvar_forceset (var_name, (const char *)value); }
|
||||
|
||||
|
||||
// Read all cvars from *demo_p and set them appropriately.
|
||||
void C_ReadCVars (byte **demo_p);
|
||||
|
||||
|
||||
// Maximum number of cvars that can be saved across a demo. If you need
|
||||
// to save more, bump this up.
|
||||
|
|
|
@ -463,10 +463,13 @@ void D_DoomLoop (void)
|
|||
{
|
||||
int i;
|
||||
|
||||
bglobal.RemoveAllBots (true);
|
||||
|
||||
if (error.GetMessage ())
|
||||
Printf (PRINT_HIGH, "%s\n", error.GetMessage());
|
||||
Printf_Bold ("\n%s\n", error.GetMessage());
|
||||
|
||||
D_QuitNetGame ();
|
||||
G_ClearSnapshots ();
|
||||
netgame = false;
|
||||
netdemo = false;
|
||||
multiplayer = false;
|
||||
|
|
|
@ -96,29 +96,19 @@ BOOL DCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
|
|||
|
||||
actor->movedir = DI_NODIR;
|
||||
|
||||
// if the special is not a door that can be opened, return false
|
||||
//
|
||||
// killough 8/9/98: this is what caused monsters to get stuck in
|
||||
// doortracks, because it thought that the monster freed itself
|
||||
// by opening a door, even if it was moving towards the doortrack,
|
||||
// and not the door itself.
|
||||
//
|
||||
// killough 9/9/98: If a line blocking the monster is activated,
|
||||
// return true 90% of the time. If a line blocking the monster is
|
||||
// not activated, but some other line is, return false 90% of the
|
||||
// time. A bit of randomness is needed to ensure it's free from
|
||||
// lockups, but for most cases, it returns the correct result.
|
||||
//
|
||||
// Do NOT simply return false 1/4th of the time (causes monsters to
|
||||
// back out when they shouldn't, and creates secondary stickiness).
|
||||
|
||||
for (good = 0; numspechit > 0; )
|
||||
{
|
||||
line_t *ld = spechit[--numspechit];
|
||||
bool tryit = true;
|
||||
|
||||
// [RH] let monsters push lines, as well as use them
|
||||
if (P_TestActivateLine (ld, actor, 0, SPAC_USE) ||
|
||||
P_TestActivateLine (ld, actor, 0, SPAC_PUSH))
|
||||
if (ld->special == Door_LockedRaise && !P_CheckKeys (actor->player, (keytype_t)ld->args[3], false))
|
||||
tryit = false;
|
||||
else if (ld->special == Generic_Door && !P_CheckKeys (actor->player, (keytype_t)ld->args[4], false))
|
||||
tryit = false;
|
||||
|
||||
if (tryit &&
|
||||
(P_TestActivateLine (ld, actor, 0, SPAC_USE) ||
|
||||
P_TestActivateLine (ld, actor, 0, SPAC_PUSH)))
|
||||
{
|
||||
good |= ld == BlockingLine ? 1 : 2;
|
||||
}
|
||||
|
@ -340,12 +330,12 @@ void DCajunMaster::TurnToAng (AActor *actor)
|
|||
if(actor->player->enemy)
|
||||
if(!actor->player->dest) //happens when running after item in combat situations, or normal, prevent's weak turns
|
||||
if(actor->player->readyweapon != wp_missile && actor->player->readyweapon != wp_bfg && actor->player->readyweapon != wp_plasma && actor->player->readyweapon != wp_fist && actor->player->readyweapon != wp_chainsaw)
|
||||
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV+5))
|
||||
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV+5*ANGLE_1))
|
||||
maxturn = 3;
|
||||
|
||||
int distance = actor->player->angle - actor->angle;
|
||||
|
||||
if (abs (distance) < OKAYRANGE)
|
||||
if (abs (distance) < OKAYRANGE && !actor->player->enemy)
|
||||
return;
|
||||
|
||||
distance /= TURNSENS;
|
||||
|
|
|
@ -208,17 +208,22 @@ void cvar_t::EnableCallbacks ()
|
|||
}
|
||||
}
|
||||
|
||||
void C_WriteCVars (byte **demo_p, unsigned int filter)
|
||||
void C_WriteCVars (byte **demo_p, DWORD filter, bool compact)
|
||||
{
|
||||
cvar_t *cvar = CVars;
|
||||
byte *ptr = *demo_p;
|
||||
|
||||
if (compact)
|
||||
ptr += sprintf ((char *)ptr, "\\\\%x", filter);
|
||||
|
||||
while (cvar)
|
||||
{
|
||||
if (cvar->flags & filter)
|
||||
{
|
||||
sprintf ((char *)ptr, "\\%s\\%s", cvar->name, cvar->string);
|
||||
ptr += strlen ((char *)ptr);
|
||||
if (compact)
|
||||
ptr += sprintf ((char *)ptr, "\\%s", cvar->string);
|
||||
else
|
||||
ptr += sprintf ((char *)ptr, "\\%s\\%s", cvar->name, cvar->string);
|
||||
}
|
||||
cvar = cvar->m_Next;
|
||||
}
|
||||
|
@ -230,32 +235,66 @@ void C_ReadCVars (byte **demo_p)
|
|||
{
|
||||
char *ptr = *((char **)demo_p);
|
||||
char *breakpt;
|
||||
char *value;
|
||||
|
||||
if (*ptr++ != '\\')
|
||||
return;
|
||||
|
||||
while ( (breakpt = strchr (ptr, '\\')) )
|
||||
{
|
||||
if (*ptr == '\\')
|
||||
{ // compact mode
|
||||
cvar_t *cvar = CVars;
|
||||
DWORD filter;
|
||||
|
||||
ptr++;
|
||||
breakpt = strchr (ptr, '\\');
|
||||
*breakpt = 0;
|
||||
value = breakpt + 1;
|
||||
if ( (breakpt = strchr (value, '\\')) )
|
||||
*breakpt = 0;
|
||||
|
||||
cvar_set (ptr, value);
|
||||
|
||||
*(value - 1) = '\\';
|
||||
if (breakpt)
|
||||
filter = strtoul (ptr, NULL, 16);
|
||||
*breakpt = '\\';
|
||||
ptr = breakpt + 1;
|
||||
|
||||
while (cvar)
|
||||
{
|
||||
*breakpt = '\\';
|
||||
ptr = breakpt + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
if (cvar->flags & filter)
|
||||
{
|
||||
breakpt = strchr (ptr, '\\');
|
||||
if (breakpt)
|
||||
*breakpt = 0;
|
||||
cvar->Set (ptr);
|
||||
if (breakpt)
|
||||
{
|
||||
*breakpt = '\\';
|
||||
ptr = breakpt + 1;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
cvar = cvar->m_Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *value;
|
||||
|
||||
while ( (breakpt = strchr (ptr, '\\')) )
|
||||
{
|
||||
*breakpt = 0;
|
||||
value = breakpt + 1;
|
||||
if ( (breakpt = strchr (value, '\\')) )
|
||||
*breakpt = 0;
|
||||
|
||||
cvar_set (ptr, value);
|
||||
|
||||
*(value - 1) = '\\';
|
||||
if (breakpt)
|
||||
{
|
||||
*breakpt = '\\';
|
||||
ptr = breakpt + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*demo_p += strlen (*((char **)demo_p)) + 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ int GetActionBit (unsigned int key)
|
|||
if (actionbits[min].key == key)
|
||||
return actionbits[mid].index;
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void C_DoCommand (char *cmd)
|
||||
|
@ -128,7 +128,7 @@ void C_DoCommand (char *cmd)
|
|||
char *args, *arg, *realargs;
|
||||
char *data;
|
||||
DConsoleCommand *com;
|
||||
int check = 0;
|
||||
int check = -1;
|
||||
|
||||
data = ParseString (cmd);
|
||||
if (!data)
|
||||
|
@ -138,14 +138,16 @@ void C_DoCommand (char *cmd)
|
|||
if (*com_token == '+')
|
||||
{
|
||||
check = GetActionBit (MakeKey (com_token + 1));
|
||||
if (Actions[check] < 255)
|
||||
Actions[check]++;
|
||||
//if (Actions[check] < 255)
|
||||
// Actions[check]++;
|
||||
Actions[check] = 1;
|
||||
}
|
||||
else if (*com_token == '-')
|
||||
{
|
||||
check = GetActionBit (MakeKey (com_token + 1));
|
||||
if (Actions[check])
|
||||
Actions[check]--;
|
||||
//if (Actions[check])
|
||||
// Actions[check]--;
|
||||
Actions[check] = 0;
|
||||
if (check == ACTION_MLOOK && lookspring.value)
|
||||
{
|
||||
AddCommandString ("centerview");
|
||||
|
@ -153,7 +155,7 @@ void C_DoCommand (char *cmd)
|
|||
}
|
||||
|
||||
// Check if this is a normal command
|
||||
if (check == 0)
|
||||
if (check == -1)
|
||||
{
|
||||
argc = 1;
|
||||
argsize = strlen (com_token) + 1;
|
||||
|
|
|
@ -450,6 +450,7 @@ void GetPackets (void)
|
|||
if (netconsole == Net_Arbitrator)
|
||||
{
|
||||
bglobal.RemoveAllBots (true);
|
||||
Printf (PRINT_HIGH, "Removed all bots\n");
|
||||
|
||||
// Pick a new network arbitrator
|
||||
for (int i = 0; i < MAXPLAYERS; i++)
|
||||
|
@ -612,23 +613,6 @@ void NetUpdate (void)
|
|||
G_BuildTiccmd (&localcmds[block]);
|
||||
//Added by MC: For some of that bot stuff. The main bot function.
|
||||
bglobal.Main (block);
|
||||
if (ticdup > 1)
|
||||
{
|
||||
localcmds[block].ucmd.yaw /= ticdup;
|
||||
if (localcmds[block].ucmd.pitch != -32768)
|
||||
localcmds[block].ucmd.pitch /= ticdup;
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
for (int j = 0; j < MAXPLAYERS; j++)
|
||||
{
|
||||
if (playeringame[j] && players[j].isbot)
|
||||
{
|
||||
netcmds[j][block].ucmd.yaw /= ticdup;
|
||||
netcmds[j][block].ucmd.pitch /= ticdup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
maketic++;
|
||||
Net_NewMakeTic ();
|
||||
}
|
||||
|
@ -729,7 +713,8 @@ BOOL CheckAbort (void)
|
|||
event_t *ev;
|
||||
|
||||
Printf (PRINT_HIGH, ""); // [RH] Give the console a chance to redraw itself
|
||||
I_WaitForTic (I_GetTime () + TICRATE*2/35);
|
||||
// This WaitForTic is to avoid flooding the network with packets on startup.
|
||||
I_WaitForTic (I_GetTime () + TICRATE/4);
|
||||
I_StartTic ();
|
||||
for ( ; eventtail != eventhead
|
||||
; eventtail = (++eventtail)&(MAXEVENTS-1) )
|
||||
|
@ -836,7 +821,7 @@ void D_ArbitrateNetStart (void)
|
|||
netbuffer->starttic = nodesdetected[0];
|
||||
stream = &(netbuffer->cmds[0]);
|
||||
|
||||
D_WriteUserInfoStrings (consoleplayer, &stream);
|
||||
D_WriteUserInfoStrings (consoleplayer, &stream, true);
|
||||
|
||||
HSendPacket (i, NCMD_SETUP|NCMD_KILL, (int)stream - (int)netbuffer);
|
||||
}
|
||||
|
@ -854,7 +839,7 @@ void D_ArbitrateNetStart (void)
|
|||
|
||||
WriteString (startmap, &stream);
|
||||
WriteLong (rngseed, &stream);
|
||||
C_WriteCVars (&stream, CVAR_SERVERINFO);
|
||||
C_WriteCVars (&stream, CVAR_SERVERINFO, true);
|
||||
|
||||
HSendPacket (i, NCMD_SETUP, (int)stream - (int)netbuffer);
|
||||
}
|
||||
|
@ -1241,6 +1226,7 @@ void Net_DoCommand (int type, byte **stream, int player)
|
|||
|
||||
case DEM_KILLBOTS:
|
||||
bglobal.RemoveAllBots (true);
|
||||
Printf (PRINT_HIGH, "Removed all bots\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -33,7 +33,7 @@ void D_UserInfoChanged (cvar_t *info);
|
|||
void D_SendServerInfoChange (const cvar_t *cvar, const char *value);
|
||||
void D_DoServerInfoChange (byte **stream);
|
||||
|
||||
void D_WriteUserInfoStrings (int player, byte **stream);
|
||||
void D_ReadUserInfoStrings (int player, byte **stream, BOOL update);
|
||||
void D_WriteUserInfoStrings (int player, byte **stream, bool compact=false);
|
||||
void D_ReadUserInfoStrings (int player, byte **stream, bool update);
|
||||
|
||||
#endif //__D_CLIENTINFO_H__
|
|
@ -27,6 +27,29 @@ CVAR (team, "", CVAR_USERINFO | CVAR_ARCHIVE)
|
|||
CVAR (gender, "male", CVAR_USERINFO | CVAR_ARCHIVE)
|
||||
CVAR (neverswitchonpickup, "0", CVAR_USERINFO | CVAR_ARCHIVE)
|
||||
|
||||
enum
|
||||
{
|
||||
INFO_Name,
|
||||
INFO_Autoaim,
|
||||
INFO_Color,
|
||||
INFO_Skin,
|
||||
INFO_Team,
|
||||
INFO_Gender,
|
||||
INFO_NeverSwitchOnPickup
|
||||
};
|
||||
|
||||
static const char *UserInfoStrings[] =
|
||||
{
|
||||
"name",
|
||||
"autoaim",
|
||||
"color",
|
||||
"skin",
|
||||
"team",
|
||||
"gender",
|
||||
"neverswitchonpickup",
|
||||
NULL
|
||||
};
|
||||
|
||||
int D_GenderToInt (const char *gender)
|
||||
{
|
||||
if (!stricmp (gender, "female"))
|
||||
|
@ -142,7 +165,7 @@ void D_DoServerInfoChange (byte **stream)
|
|||
*stream += strlen (*((char **)stream)) + 1;
|
||||
}
|
||||
|
||||
void D_WriteUserInfoStrings (int i, byte **stream)
|
||||
void D_WriteUserInfoStrings (int i, byte **stream, bool compact)
|
||||
{
|
||||
if (i >= MAXPLAYERS)
|
||||
{
|
||||
|
@ -152,64 +175,115 @@ void D_WriteUserInfoStrings (int i, byte **stream)
|
|||
{
|
||||
userinfo_t *info = &players[i].userinfo;
|
||||
|
||||
sprintf (*((char **)stream),
|
||||
"\\name\\%s"
|
||||
"\\autoaim\\%g"
|
||||
"\\color\\%x %x %x"
|
||||
"\\skin\\%s"
|
||||
"\\team\\%s"
|
||||
"\\gender\\%s"
|
||||
"\\neverswitchonpickup\\%d",
|
||||
info->netname,
|
||||
(double)info->aimdist / 16384.0,
|
||||
RPART(info->color), GPART(info->color), BPART(info->color),
|
||||
skins[info->skin].name, info->team,
|
||||
info->gender == GENDER_FEMALE ? "female" :
|
||||
if (!compact)
|
||||
{
|
||||
sprintf (*((char **)stream),
|
||||
"\\name\\%s"
|
||||
"\\autoaim\\%g"
|
||||
"\\color\\%x %x %x"
|
||||
"\\skin\\%s"
|
||||
"\\team\\%s"
|
||||
"\\gender\\%s"
|
||||
"\\neverswitchonpickup\\%d",
|
||||
info->netname,
|
||||
(double)info->aimdist / 16384.0,
|
||||
RPART(info->color), GPART(info->color), BPART(info->color),
|
||||
skins[info->skin].name, info->team,
|
||||
info->gender == GENDER_FEMALE ? "female" :
|
||||
info->gender == GENDER_NEUTER ? "cyborg" : "male",
|
||||
info->neverswitch
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (*((char **)stream),
|
||||
"\\"
|
||||
"\\%s" // name
|
||||
"\\%g" // autoaim
|
||||
"\\%x %x %x" // color
|
||||
"\\%s" // skin
|
||||
"\\%s" // team
|
||||
"\\%s" // gender
|
||||
"\\%d" // neverswitchonpickup
|
||||
,
|
||||
info->netname,
|
||||
(double)info->aimdist / 16384.0,
|
||||
RPART(info->color), GPART(info->color), BPART(info->color),
|
||||
skins[info->skin].name,
|
||||
info->team,
|
||||
info->gender == GENDER_FEMALE ? "female" :
|
||||
info->gender == GENDER_NEUTER ? "cyborg" : "male",
|
||||
info->neverswitch
|
||||
);
|
||||
info->neverswitch
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
*stream += strlen (*((char **)stream)) + 1;
|
||||
}
|
||||
|
||||
void D_ReadUserInfoStrings (int i, byte **stream, BOOL update)
|
||||
void D_ReadUserInfoStrings (int i, byte **stream, bool update)
|
||||
{
|
||||
userinfo_t *info = &players[i].userinfo;
|
||||
char *ptr = *((char **)stream);
|
||||
char *breakpt;
|
||||
char *value;
|
||||
bool compact;
|
||||
int infotype = -1;
|
||||
|
||||
if (*ptr++ != '\\')
|
||||
return;
|
||||
|
||||
compact = (*ptr == '\\') ? ptr++, true : false;
|
||||
|
||||
if (i < MAXPLAYERS)
|
||||
{
|
||||
while ( (breakpt = strchr (ptr, '\\')) )
|
||||
{
|
||||
*breakpt = 0;
|
||||
value = breakpt + 1;
|
||||
if ( (breakpt = strchr (value, '\\')) )
|
||||
*breakpt = 0;
|
||||
|
||||
if (!stricmp (ptr, "autoaim"))
|
||||
if (compact)
|
||||
{
|
||||
value = ptr;
|
||||
infotype++;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = breakpt + 1;
|
||||
if ( (breakpt = strchr (value, '\\')) )
|
||||
*breakpt = 0;
|
||||
|
||||
int i = infotype + 1;
|
||||
while (UserInfoStrings[i] && stricmp (UserInfoStrings[i], ptr))
|
||||
i++;
|
||||
if (infotype >= 0)
|
||||
{
|
||||
i = 0;
|
||||
while (UserInfoStrings[i] && stricmp (UserInfoStrings[i], ptr))
|
||||
i++;
|
||||
}
|
||||
infotype = i;
|
||||
}
|
||||
|
||||
switch (infotype)
|
||||
{
|
||||
case INFO_Autoaim:
|
||||
info->aimdist = (fixed_t)(atof (value) * 16384.0);
|
||||
}
|
||||
else if (!stricmp (ptr, "name"))
|
||||
{
|
||||
char oldname[MAXPLAYERNAME+1];
|
||||
break;
|
||||
|
||||
strncpy (oldname, info->netname, MAXPLAYERNAME);
|
||||
oldname[MAXPLAYERNAME] = 0;
|
||||
strncpy (info->netname, value, MAXPLAYERNAME);
|
||||
info->netname[MAXPLAYERNAME] = 0;
|
||||
case INFO_Name:
|
||||
{
|
||||
char oldname[MAXPLAYERNAME+1];
|
||||
|
||||
if (update)
|
||||
Printf (PRINT_HIGH, "%s is now known as %s\n", oldname, info->netname);
|
||||
}
|
||||
else if (!stricmp (ptr, "team"))
|
||||
{
|
||||
strncpy (oldname, info->netname, MAXPLAYERNAME);
|
||||
oldname[MAXPLAYERNAME] = 0;
|
||||
strncpy (info->netname, value, MAXPLAYERNAME);
|
||||
info->netname[MAXPLAYERNAME] = 0;
|
||||
|
||||
if (update)
|
||||
Printf (PRINT_HIGH, "%s is now known as %s\n", oldname, info->netname);
|
||||
}
|
||||
break;
|
||||
|
||||
case INFO_Team:
|
||||
strncpy (info->team, value, MAXPLAYERNAME);
|
||||
info->team[MAXPLAYERNAME] = 0;
|
||||
if (update)
|
||||
|
@ -219,31 +293,36 @@ void D_ReadUserInfoStrings (int i, byte **stream, BOOL update)
|
|||
else
|
||||
Printf (PRINT_HIGH, "%s is not on a team\n", info->netname);
|
||||
}
|
||||
}
|
||||
else if (!stricmp (ptr, "color"))
|
||||
{
|
||||
break;
|
||||
|
||||
case INFO_Color:
|
||||
info->color = V_GetColorFromString (NULL, value);
|
||||
R_BuildPlayerTranslation (i, info->color);
|
||||
st_firsttime = true;
|
||||
}
|
||||
else if (!stricmp (ptr, "skin"))
|
||||
{
|
||||
break;
|
||||
|
||||
case INFO_Skin:
|
||||
info->skin = R_FindSkin (value);
|
||||
if (players[i].mo)
|
||||
players[i].mo->sprite = (spritenum_t)skins[info->skin].sprite;
|
||||
ST_loadGraphics ();
|
||||
st_firsttime = true;
|
||||
}
|
||||
else if (!stricmp (ptr, "gender"))
|
||||
{
|
||||
break;
|
||||
|
||||
case INFO_Gender:
|
||||
info->gender = D_GenderToInt (value);
|
||||
}
|
||||
else if (!stricmp (ptr, "neverswitchonpickup"))
|
||||
{
|
||||
break;
|
||||
|
||||
case INFO_NeverSwitchOnPickup:
|
||||
info->neverswitch = atoi (value) ? true : false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*(value - 1) = '\\';
|
||||
if (!compact)
|
||||
*(value - 1) = '\\';
|
||||
if (breakpt)
|
||||
{
|
||||
*breakpt = '\\';
|
||||
|
|
|
@ -300,17 +300,20 @@ void RunNetSpecs (int player, int buf)
|
|||
byte *stream;
|
||||
int len;
|
||||
|
||||
stream = NetSpecs[player][buf].GetData (&len);
|
||||
if (stream)
|
||||
if (gametic % ticdup == 0)
|
||||
{
|
||||
byte *end = stream + len;
|
||||
while (stream < end)
|
||||
stream = NetSpecs[player][buf].GetData (&len);
|
||||
if (stream)
|
||||
{
|
||||
int type = ReadByte (&stream);
|
||||
Net_DoCommand (type, &stream, player);
|
||||
byte *end = stream + len;
|
||||
while (stream < end)
|
||||
{
|
||||
int type = ReadByte (&stream);
|
||||
Net_DoCommand (type, &stream, player);
|
||||
}
|
||||
if (!demorecording)
|
||||
NetSpecs[player][buf].SetData (NULL, 0);
|
||||
}
|
||||
if (!demorecording)
|
||||
NetSpecs[player][buf].SetData (NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,33 @@
|
|||
September 15, 1999
|
||||
- Fixed a nasty bug when saving big games. FArchive used pointers into the
|
||||
m_ObjectMap array when mapping objects to indices. Now it uses indices
|
||||
all the way through so that they will still remain valid if m_ObjectMap
|
||||
has to grow.
|
||||
- Reduced the rate at which arbitration packets are sent out to 4 times per
|
||||
second. Combined with their reduced size, this will hopefully solve
|
||||
problems I understand some people were having using 1.18 with DoomServ.
|
||||
(Based on the assumption that their problems were caused by the lack of
|
||||
bandwidth offered by modems.)
|
||||
- Reduced the size of netgame arbitration packets by removing the names of
|
||||
the cvars the values represent. When playing with the same copy of the
|
||||
executable, these are implicit in the order in which the values appear in
|
||||
the stream, so storing the name of the key is essentially redundant.
|
||||
- Pulled out the original 1.18a source and fixed loading of savegames before
|
||||
a new game is begun. The problem was in DCajunMaster::RemoveAllBots(),
|
||||
where the consoleplayer's camera is restored to the console player if
|
||||
viewing a bot. Before the game begins, the camera field is NULL. Also
|
||||
changed caught recoverable errors so that bots are removed and level
|
||||
snapshots are deleted.
|
||||
|
||||
September 12, 1999
|
||||
- Made actor movement floating-point based. I had already done the fp time
|
||||
system (to an extent) before I had to pull out the 1.18 source and fix
|
||||
bugs. Gravity seems to be inversely proportional to the ticrate. Can't
|
||||
figure out why.
|
||||
|
||||
Okay, I was stupid. I accidentally erased the version of the log file that
|
||||
contained my changes from 1.18 to 1.18a.
|
||||
|
||||
September 5, 1999
|
||||
- The +moveup and +movedown commands finally do something.
|
||||
- Added a fly cheat.
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
#include "stats.h"
|
||||
#include "p_local.h"
|
||||
|
||||
static cycle_t ThinkCycles, BotSupportCycles;
|
||||
static cycle_t ThinkCycles;
|
||||
extern cycle_t BotSupportCycles;
|
||||
|
||||
// Cap is both the head and tail of the thinker list
|
||||
DThinker DThinker::Cap;
|
||||
|
|
|
@ -387,7 +387,11 @@ void FLZOMemFile::Serialize (FArchive &arc)
|
|||
if (arc.IsStoring ())
|
||||
{
|
||||
if (m_ImplodedBuffer == NULL)
|
||||
I_Error ("FLZOMemFile must be imploded before storing\n");
|
||||
{
|
||||
//I_Error ("FLZOMemFile must be imploded before storing\n");
|
||||
// Q: How do we get here without closing FLZOMemFile first?
|
||||
Close ();
|
||||
}
|
||||
arc.Write (LZOSig, 4);
|
||||
|
||||
DWORD sizes[2];
|
||||
|
@ -460,7 +464,7 @@ FArchive::FArchive (FFile &file)
|
|||
}
|
||||
m_ClassCount = 0;
|
||||
for (i = 0; i < EObjectHashSize; i++)
|
||||
m_ObjectHash[i] = NULL;
|
||||
m_ObjectHash[i] = ~0;
|
||||
}
|
||||
|
||||
FArchive::~FArchive ()
|
||||
|
@ -875,7 +879,7 @@ DWORD FArchive::MapObject (const DObject *obj)
|
|||
m_ObjectMap = (ObjectMap *)Realloc (m_ObjectMap, sizeof(ObjectMap)*m_MaxObjectCount);
|
||||
for (int i = m_ObjectCount; i < m_MaxObjectCount; i++)
|
||||
{
|
||||
m_ObjectMap[i].hashNext = NULL;
|
||||
m_ObjectMap[i].hashNext = ~0;
|
||||
m_ObjectMap[i].object = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -885,7 +889,7 @@ DWORD FArchive::MapObject (const DObject *obj)
|
|||
|
||||
m_ObjectMap[index].object = obj;
|
||||
m_ObjectMap[index].hashNext = m_ObjectHash[hash];
|
||||
m_ObjectHash[hash] = m_ObjectMap + index;
|
||||
m_ObjectHash[hash] = index;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
@ -897,13 +901,10 @@ DWORD FArchive::HashObject (const DObject *obj) const
|
|||
|
||||
DWORD FArchive::FindObjectIndex (const DObject *obj) const
|
||||
{
|
||||
ObjectMap *map = m_ObjectHash[HashObject (obj)];
|
||||
while (map && map->object != obj)
|
||||
size_t index = m_ObjectHash[HashObject (obj)];
|
||||
while (index != ~0 && m_ObjectMap[index].object != obj)
|
||||
{
|
||||
map = map->hashNext;
|
||||
index = m_ObjectMap[index].hashNext;
|
||||
}
|
||||
if (map)
|
||||
return map - m_ObjectMap;
|
||||
else
|
||||
return -1;
|
||||
return index;
|
||||
}
|
||||
|
|
|
@ -188,9 +188,9 @@ protected:
|
|||
struct ObjectMap
|
||||
{
|
||||
const DObject *object;
|
||||
ObjectMap *hashNext;
|
||||
size_t hashNext;
|
||||
} *m_ObjectMap;
|
||||
ObjectMap *m_ObjectHash[EObjectHashSize];
|
||||
size_t m_ObjectHash[EObjectHashSize];
|
||||
|
||||
private:
|
||||
FArchive (const FArchive &src) {}
|
||||
|
|
|
@ -449,7 +449,7 @@ void G_BuildTiccmd (ticcmd_t *cmd)
|
|||
{
|
||||
int val;
|
||||
|
||||
val = (int)((float)(mousey * 16) * m_pitch.value);
|
||||
val = (int)((float)(mousey * 16) * m_pitch.value) / ticdup;
|
||||
if (invertmouse.value)
|
||||
look -= val;
|
||||
else
|
||||
|
@ -476,7 +476,7 @@ void G_BuildTiccmd (ticcmd_t *cmd)
|
|||
if (strafe || lookstrafe.value)
|
||||
side += (int)((float)mousex * m_side.value);
|
||||
else
|
||||
cmd->ucmd.yaw -= (int)((float)(mousex*0x8) * m_yaw.value);
|
||||
cmd->ucmd.yaw -= (int)((float)(mousex*0x8) * m_yaw.value) / ticdup;
|
||||
|
||||
mousex = mousey = 0;
|
||||
|
||||
|
@ -1195,6 +1195,8 @@ void G_DoLoadGame (void)
|
|||
fread (text, 8, 1, stdfile);
|
||||
text[8] = 0;
|
||||
|
||||
bglobal.RemoveAllBots (true);
|
||||
|
||||
FLZOFile savefile (stdfile, FFile::EReading);
|
||||
|
||||
if (!savefile.IsOpen ())
|
||||
|
@ -1304,6 +1306,9 @@ void G_DoSaveGame (void)
|
|||
|
||||
Printf (PRINT_HIGH, "%s\n", GGSAVED);
|
||||
arc.Close ();
|
||||
|
||||
delete level.info->snapshot;
|
||||
level.info->snapshot = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1394,7 +1399,7 @@ void G_WriteDemoTiccmd (ticcmd_t *cmd, int player, int buf)
|
|||
}
|
||||
|
||||
// [RH] Write any special "ticcmds" for this player to the demo
|
||||
if ((specdata = NetSpecs[player][buf].GetData (&speclen)))
|
||||
if ((specdata = NetSpecs[player][buf].GetData (&speclen)) && gametic % ticdup == 0)
|
||||
{
|
||||
memcpy (demo_p, specdata, speclen);
|
||||
demo_p += speclen;
|
||||
|
|
|
@ -391,7 +391,7 @@ static void ParseMapInfoLower (MapInfoHandler *handlers,
|
|||
int map = atoi (sc_String);
|
||||
sprintf (sc_String, "MAP%02d", map);
|
||||
}
|
||||
uppercopy ((char *)(info + handler->data1), sc_String);
|
||||
strncpy ((char *)(info + handler->data1), sc_String, 8);
|
||||
break;
|
||||
|
||||
case MITYPE_LUMPNAME:
|
||||
|
|
|
@ -5768,7 +5768,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = {
|
|||
100, // mass
|
||||
0, // damage
|
||||
NULL, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOSECTOR, // flags
|
||||
MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOGRAVITY, // flags
|
||||
0, // flags2
|
||||
S_NULL, // raisestate
|
||||
0x10000
|
||||
|
|
|
@ -111,7 +111,7 @@ FUNC(LS_Door_Raise)
|
|||
}
|
||||
|
||||
FUNC(LS_Door_LockedRaise)
|
||||
// Door_LocedRaise (tag, speed, delay, lock)
|
||||
// Door_LockedRaise (tag, speed, delay, lock)
|
||||
{
|
||||
return EV_DoDoor (arg2 ? DDoor::doorRaise : DDoor::doorOpen, ln, it,
|
||||
arg0, SPEED(arg1), TICS(arg2), (keytype_t)arg3);
|
||||
|
|
|
@ -420,7 +420,7 @@ void P_XYMovement (AActor *mo)
|
|||
|
||||
player = mo->player;
|
||||
|
||||
int maxmove = mo->waterlevel < 2 ? MAXMOVE : MAXMOVE/4;
|
||||
int maxmove = (mo->waterlevel < 2) || (mo->flags & MF_MISSILE) ? MAXMOVE : MAXMOVE/4;
|
||||
|
||||
if (mo->momx > maxmove)
|
||||
mo->momx = maxmove;
|
||||
|
@ -1132,7 +1132,8 @@ void AActor::RunThink ()
|
|||
}
|
||||
}
|
||||
|
||||
if (bglobal.botnum && consoleplayer == Net_Arbitrator && !demoplayback)
|
||||
if (bglobal.botnum && consoleplayer == Net_Arbitrator && !demoplayback &&
|
||||
flags & (MF_COUNTKILL|MF_SPECIAL|MF_MISSILE))
|
||||
{
|
||||
clock (BotSupportCycles);
|
||||
bglobal.m_Thinking = true;
|
||||
|
@ -1141,17 +1142,23 @@ void AActor::RunThink ()
|
|||
if (!playeringame[i] || !players[i].isbot)
|
||||
continue;
|
||||
|
||||
if (((flags & (MF_COUNTKILL|MF_SHOOTABLE)) == (MF_COUNTKILL|MF_SHOOTABLE))
|
||||
&& !IsTeammate (players[i].mo))
|
||||
if ((flags & MF_COUNTKILL)
|
||||
&& health > 0
|
||||
&& !players[i].enemy
|
||||
&& player ? !IsTeammate (players[i].mo) : true
|
||||
&& P_AproxDistance (players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST
|
||||
&& P_CheckSight (players[i].mo, this))
|
||||
{ //Probably a monster, so go kill it.
|
||||
if(!players[i].enemy || players[i].enemy->health<=0 || (players[i].enemy && !P_CheckSight(players[i].mo, players[i].enemy)))
|
||||
if(P_AproxDistance(players[i].mo->x-x, players[i].mo->y-y) < MAX_MONSTER_TARGET_DIST)
|
||||
if(P_CheckSight(players[i].mo, this))
|
||||
players[i].enemy = this;
|
||||
players[i].enemy = this;
|
||||
}
|
||||
else if (flags & MF_SPECIAL) //Item pickup time
|
||||
else if (flags & MF_SPECIAL)
|
||||
{ //Item pickup time
|
||||
bglobal.WhatToGet (players[i].mo, this);
|
||||
else if ((flags & MF_MISSILE) && type != MT_PLASMA && type != MT_ARACHPLAZ)
|
||||
}
|
||||
else if ((flags & MF_MISSILE)
|
||||
&& !players[i].missile
|
||||
&& type != MT_PLASMA
|
||||
&& type != MT_ARACHPLAZ)
|
||||
{ //warn for incoming missiles.
|
||||
if (target != players[i].mo && bglobal.Check_LOS (players[i].mo, this, ANGLE_90))
|
||||
players[i].missile = this;
|
||||
|
@ -1612,9 +1619,10 @@ void P_SpawnMapThing (mapthing2_t *mthing, int position)
|
|||
if (deathmatch_p == &deathmatchstarts[MaxDeathmatchStarts])
|
||||
{
|
||||
// [RH] Get more deathmatchstarts
|
||||
int offset = MaxDeathmatchStarts;
|
||||
MaxDeathmatchStarts *= 2;
|
||||
deathmatchstarts = (mapthing2_t *)Realloc (deathmatchstarts, MaxDeathmatchStarts * sizeof(mapthing2_t));
|
||||
deathmatch_p = &deathmatchstarts[MaxDeathmatchStarts - 8];
|
||||
deathmatch_p = &deathmatchstarts[offset];
|
||||
}
|
||||
memcpy (deathmatch_p, mthing, sizeof(*mthing));
|
||||
deathmatch_p++;
|
||||
|
|
|
@ -1381,8 +1381,9 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
|
||||
po_NumPolyobjs = 0;
|
||||
|
||||
if (!deathmatchstarts) {
|
||||
MaxDeathmatchStarts = 10; // [RH] Default. Increased as needed.
|
||||
if (!deathmatchstarts)
|
||||
{
|
||||
MaxDeathmatchStarts = 16; // [RH] Default. Increased as needed.
|
||||
deathmatchstarts = (mapthing2_t *)Malloc (MaxDeathmatchStarts * sizeof(mapthing2_t));
|
||||
}
|
||||
deathmatch_p = deathmatchstarts;
|
||||
|
|
|
@ -1194,7 +1194,7 @@ void P_PlayerInSpecialSector (player_t *player)
|
|||
int special = sector->special & ~SECRET_MASK;
|
||||
|
||||
// Falling, not all the way down yet?
|
||||
if (player->mo->z != sector->floorheight)
|
||||
if (player->mo->z != sector->floorheight && !player->mo->waterlevel)
|
||||
return;
|
||||
|
||||
// Has hitten ground.
|
||||
|
|
|
@ -643,7 +643,6 @@ void player_s::Serialize (FArchive &arc)
|
|||
<< xviewshift
|
||||
<< jumpTics
|
||||
<< respawn_time
|
||||
<< camera
|
||||
<< air_finished
|
||||
<< isbot;
|
||||
for (i = 0; i < NUMPOWERS; i++)
|
||||
|
@ -725,7 +724,6 @@ void player_s::Serialize (FArchive &arc)
|
|||
>> xviewshift
|
||||
>> jumpTics
|
||||
>> respawn_time
|
||||
>> camera
|
||||
>> air_finished
|
||||
>> isbot;
|
||||
for (i = 0; i < NUMPOWERS; i++)
|
||||
|
@ -743,31 +741,46 @@ void player_s::Serialize (FArchive &arc)
|
|||
for (i = 0; i < 3; i++)
|
||||
arc >> oldvelocity[i];
|
||||
|
||||
camera = mo;
|
||||
|
||||
if (consoleplayer != this - players)
|
||||
userinfo = dummyuserinfo;
|
||||
|
||||
if (isbot)
|
||||
{
|
||||
arc << angle
|
||||
<< dest
|
||||
<< prev
|
||||
<< enemy
|
||||
<< missile
|
||||
<< mate
|
||||
<< last_mate
|
||||
<< skill
|
||||
<< t_active
|
||||
<< t_respawn
|
||||
<< t_strafe
|
||||
<< t_react
|
||||
<< t_fight
|
||||
<< t_roam
|
||||
<< t_rocket
|
||||
<< first_shot
|
||||
<< sleft
|
||||
<< allround
|
||||
<< redteam
|
||||
<< oldx
|
||||
<< oldy
|
||||
<< chat;
|
||||
arc >> angle
|
||||
>> dest
|
||||
>> prev
|
||||
>> enemy
|
||||
>> missile
|
||||
>> mate
|
||||
>> last_mate
|
||||
>> skill
|
||||
>> t_active
|
||||
>> t_respawn
|
||||
>> t_strafe
|
||||
>> t_react
|
||||
>> t_fight
|
||||
>> t_roam
|
||||
>> t_rocket
|
||||
>> first_shot
|
||||
>> sleft
|
||||
>> allround
|
||||
>> redteam
|
||||
>> oldx
|
||||
>> oldy
|
||||
>> chat;
|
||||
arc.Read (c_target, 256);
|
||||
|
||||
botinfo_t *thebot = bglobal.botinfo;
|
||||
while (thebot && stricmp (userinfo.netname, thebot->name))
|
||||
thebot = thebot->next;
|
||||
if (thebot)
|
||||
{
|
||||
thebot->inuse = true;
|
||||
}
|
||||
bglobal.botnum++;
|
||||
bglobal.botingame[this - players] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,6 +258,7 @@ void R_GenerateComposite (int texnum)
|
|||
static void R_GenerateLookup(int texnum, int *const errors)
|
||||
{
|
||||
const texture_t *texture = textures[texnum];
|
||||
const bool nottall = texture->height < 256;
|
||||
|
||||
// Composited texture not created yet.
|
||||
|
||||
|
@ -293,7 +294,7 @@ static void R_GenerateLookup(int texnum, int *const errors)
|
|||
|
||||
const column_t *col = (column_t*)((byte*)realpatch+LONG(cofs[x]));
|
||||
for (;col->topdelta != 0xff; count[x].posts++)
|
||||
col = (column_t *)((byte *) col + col->length + 4);
|
||||
col = (column_t *)((byte *) col + (col->length || nottall ? col->length : 256) + 4);
|
||||
count[x].patches++;
|
||||
collump[x] = pat;
|
||||
colofs[x] = LONG(cofs[x])+3;
|
||||
|
|
|
@ -668,7 +668,7 @@ void R_DrawPlanes (void)
|
|||
{
|
||||
if ((!warpedflats[useflatnum]
|
||||
&& Z_Malloc (64*64, PU_STATIC, &warpedflats[useflatnum]))
|
||||
|| flatwarpedwhen[useflatnum] < level.time)
|
||||
|| flatwarpedwhen[useflatnum] != level.time)
|
||||
{
|
||||
static byte buffer[64];
|
||||
int timebase = level.time*23;
|
||||
|
|
BIN
code/test.lzo
BIN
code/test.lzo
Binary file not shown.
|
@ -3,10 +3,10 @@
|
|||
|
||||
// Lots of different representations for the version number
|
||||
enum { VERSION = 118 };
|
||||
#define VERSIONSTR "118"
|
||||
#define VERSIONSTR "118b"
|
||||
#define CONFIGVERSIONSTR "118.01"
|
||||
#define DOTVERSIONSTR "1.18"
|
||||
#define DOTVERSIONSTR "1.18b"
|
||||
#define GAMEVER (0x0112)
|
||||
#define SAVESIG "ZDOOMSAVE118rel " // Needs to be exactly 16 chars long
|
||||
#define SAVESIG "ZDOOMSAVE118rel2" // Needs to be exactly 16 chars long
|
||||
|
||||
#endif //__VERSION_H__
|
|
@ -1,5 +1,4 @@
|
|||
This is the source code for ZDoom 1.18 released on 5 September 1999. It is
|
||||
not the same as the source released on 15 August.
|
||||
This is the source code for ZDoom 1.18b released on 15 September 1999.
|
||||
|
||||
It is based on the Linux DOOM sources that were prepared by B. Krenheimer
|
||||
and generously released by John Carmack shortly before Christmas, 1997. If
|
||||
|
|
Loading…
Reference in a new issue