This commit is contained in:
Christoph Oelckers 2014-12-16 17:38:37 +01:00
commit 4f00aa3957
47 changed files with 1770 additions and 1245 deletions

View file

@ -3,6 +3,7 @@ cmake_minimum_required( VERSION 2.4 )
make_release_only()
include( CheckFunctionExists )
include( CheckCXXCompilerFlag )
# DUMB is much slower in a Debug build than a Release build, so we force a Release
# build here, since we're not maintaining DUMB, only using it.
@ -104,5 +105,9 @@ add_library( dumb
target_link_libraries( dumb )
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
CHECK_CXX_COMPILER_FLAG( -msse DUMB_CAN_USE_SSE )
if( DUMB_CAN_USE_SSE )
set_source_files_properties( src/it/filter.cpp PROPERTIES COMPILE_FLAGS -msse )
endif( DUMB_CAN_USE_SSE )
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )

View file

@ -28,7 +28,9 @@ endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON )
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
if( APPLE )
option( OSX_COCOA_BACKEND "Use native Cocoa backend instead of SDL" ON )
endif( APPLE )
if( CMAKE_SIZEOF_VOID_P MATCHES "8" )
set( X64 64 )
@ -590,6 +592,7 @@ set( PLAT_SDL_SYSTEM_SOURCES
sdl/i_cd.cpp
sdl/i_main.cpp
sdl/i_movie.cpp
sdl/i_steam.cpp
sdl/i_system.cpp
sdl/sdlvideo.cpp
sdl/sdlglvideo.cpp

View file

@ -347,6 +347,14 @@ enum
MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag.
MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't.
MF7_CAUSEPAIN = 0x00000400, // Damage sources with this flag can cause similar effects like ALLOWPAIN.
MF7_THRUREFLECT = 0x00000800, // Actors who are reflective cause the missiles to not slow down or change angles.
MF7_MIRRORREFLECT = 0x00001000, // Actor is turned directly 180 degrees around when reflected.
MF7_AIMREFLECT = 0x00002000, // Actor is directly reflected straight back at the one who fired the projectile.
MF7_HITTARGET = 0x00004000, // The actor the projectile dies on is set to target, provided it's targetable anyway.
MF7_HITMASTER = 0x00008000, // Same as HITTARGET, except it's master instead of target.
MF7_HITTRACER = 0x00010000, // Same as HITTARGET, but for tracer.
// --- mobj.renderflags ---
@ -859,7 +867,7 @@ public:
DWORD flags4; // [RH] Even more flags!
DWORD flags5; // OMG! We need another one.
DWORD flags6; // Shit! Where did all the flags go?
DWORD flags7; //
DWORD flags7; // WHO WANTS TO BET ON 8!?
// [BB] If 0, everybody can see the actor, if > 0, only members of team (VisibleToTeam-1) can see it.
DWORD VisibleToTeam;

View file

@ -66,7 +66,7 @@ void DBot::Serialize (FArchive &arc)
arc << savedyaw
<< savedpitch;
}
else if (SaveVersion >= 4516)
else
{
arc << player;
}
@ -105,7 +105,7 @@ void DBot::Tick ()
BotThinkCycles.Clock();
bglobal.m_Thinking = true;
bglobal.Think (player->mo, &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS]);
Think ();
bglobal.m_Thinking = false;
BotThinkCycles.Unclock();
}

View file

@ -89,7 +89,7 @@ public:
void ClearPlayer (int playernum, bool keepTeam);
//(B_Game.c)
//(b_game.cpp)
void Main ();
void Init ();
void End();
@ -99,23 +99,16 @@ public:
bool LoadBots ();
void ForgetBots ();
//(B_Func.c)
bool Check_LOS (AActor *mobj1, AActor *mobj2, angle_t vangle);
//(b_func.cpp)
void StartTravel ();
void FinishTravel ();
bool IsLeader (player_t *player);
void SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum);
fixed_t FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm);
//(B_Think.c)
void Think (AActor *actor, ticcmd_t *cmd);
void WhatToGet (AActor *actor, AActor *item);
//(B_move.c)
void Roam (AActor *actor, ticcmd_t *cmd);
bool Move (AActor *actor, ticcmd_t *cmd);
bool TryWalk (AActor *actor, ticcmd_t *cmd);
void NewChaseDir (AActor *actor, ticcmd_t *cmd);
//(b_move.cpp)
bool CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cmd);
void TurnToAng (AActor *actor);
void Pitch (AActor *actor, AActor *target);
bool IsDangerous (sector_t *sec);
TArray<FString> getspawned; //Array of bots (their names) which should be spawned when starting a game.
@ -132,24 +125,9 @@ public:
bool m_Thinking;
private:
//(B_Game.c)
//(b_game.cpp)
bool DoAddBot (BYTE *info, botskill_t skill);
//(B_Func.c)
bool Reachable (AActor *actor, AActor *target);
void Dofire (AActor *actor, ticcmd_t *cmd);
bool IsLeader (player_t *player);
AActor *Choose_Mate (AActor *bot);
AActor *Find_enemy (AActor *bot);
void SetBodyAt (fixed_t x, fixed_t y, fixed_t z, int hostnum);
fixed_t FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
angle_t FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd);
bool SafeCheckPosition (AActor *actor, fixed_t x, fixed_t y, FCheckPosition &tm);
//(B_Think.c)
void ThinkForMove (AActor *actor, ticcmd_t *cmd);
void Set_enemy (AActor *actor);
protected:
bool ctf;
int loaded_bots;
@ -168,13 +146,17 @@ public:
void Serialize (FArchive &arc);
void Tick ();
//(b_think.cpp)
void WhatToGet (AActor *item);
//(b_func.cpp)
bool Check_LOS (AActor *to, angle_t vangle);
player_t *player;
angle_t angle; // The wanted angle that the bot try to get every tic.
// (used to get a smooth view movement)
TObjPtr<AActor> dest; // Move Destination.
TObjPtr<AActor> prev; // Previous move destination.
TObjPtr<AActor> enemy; // The dead meat.
TObjPtr<AActor> missile; // A threatening missile that needs to be avoided.
TObjPtr<AActor> mate; // Friend (used for grouping in teamplay or coop).
@ -204,6 +186,27 @@ public:
fixed_t oldx;
fixed_t oldy;
private:
//(B_think.cpp)
void Think ();
void ThinkForMove (ticcmd_t *cmd);
void Set_enemy ();
//(B_func.cpp)
bool Reachable (AActor *target);
void Dofire (ticcmd_t *cmd);
AActor *Choose_Mate ();
AActor *Find_enemy ();
angle_t FireRox (AActor *enemy, ticcmd_t *cmd);
//(b_move.cpp)
void Roam (ticcmd_t *cmd);
bool Move (ticcmd_t *cmd);
bool TryWalk (ticcmd_t *cmd);
void NewChaseDir (ticcmd_t *cmd);
void TurnToAng ();
void Pitch (AActor *target);
};
@ -220,7 +223,3 @@ EXTERN_CVAR (Bool, bot_watersplash)
EXTERN_CVAR (Bool, bot_chat)
#endif // __B_BOT_H__

View file

@ -24,24 +24,23 @@
static FRandom pr_botdofire ("BotDoFire");
//Checks TRUE reachability from
//one looker to another. First mobj (looker) is looker.
bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
//Checks TRUE reachability from bot to a looker.
bool DBot::Reachable (AActor *rtarget)
{
if (looker == rtarget)
if (player->mo == rtarget)
return false;
if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y))
< looker->height) //Where rtarget is, looker can't be.
< player->mo->height) //Where rtarget is, player->mo can't be.
return false;
sector_t *last_s = looker->Sector;
fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y);
fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y);
sector_t *last_s = player->mo->Sector;
fixed_t last_z = last_s->floorplane.ZatPoint (player->mo->x, player->mo->y);
fixed_t estimated_dist = P_AproxDistance (player->mo->x - rtarget->x, player->mo->y - rtarget->y);
bool reachable = true;
FPathTraverse it(looker->x+looker->velx, looker->y+looker->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
FPathTraverse it(player->mo->x+player->mo->velx, player->mo->y+player->mo->vely, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
intercept_t *in;
while ((in = it.Next()))
{
@ -55,8 +54,8 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
dist = FixedMul (frac, MAX_TRAVERSE_DIST);
hitx = it.Trace().x + FixedMul (looker->velx, frac);
hity = it.Trace().y + FixedMul (looker->vely, frac);
hitx = it.Trace().x + FixedMul (player->mo->velx, frac);
hity = it.Trace().y + FixedMul (player->mo->vely, frac);
if (in->isaline)
{
@ -76,7 +75,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
if (!bglobal.IsDangerous (s) && //Any nukage/lava?
(floorheight <= (last_z+MAXMOVEHEIGHT)
&& ((ceilingheight == floorheight && line->special)
|| (ceilingheight - floorheight) >= looker->height))) //Does it fit?
|| (ceilingheight - floorheight) >= player->mo->height))) //Does it fit?
{
last_z = floorheight;
last_s = s;
@ -95,7 +94,7 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
}
thing = in->d.thing;
if (thing == looker) //Can't reach self in this case.
if (thing == player->mo) //Can't reach self in this case.
continue;
if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
{
@ -115,16 +114,16 @@ bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
//if these conditions are true, the function returns true.
//GOOD TO KNOW is that the player's view angle
//in doom is 90 degrees infront.
bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle)
bool DBot::Check_LOS (AActor *to, angle_t vangle)
{
if (!P_CheckSight (from, to, SF_SEEPASTBLOCKEVERYTHING))
if (!P_CheckSight (player->mo, to, SF_SEEPASTBLOCKEVERYTHING))
return false; // out of sight
if (vangle == ANGLE_MAX)
return true;
if (vangle == 0)
return false; //Looker seems to be blind.
return (angle_t)abs (R_PointToAngle2 (from->x, from->y, to->x, to->y) - from->angle) <= vangle/2;
return (angle_t)abs (R_PointToAngle2 (player->mo->x, player->mo->y, to->x, to->y) - player->mo->angle) <= vangle/2;
}
//-------------------------------------
@ -132,7 +131,7 @@ bool FCajunMaster::Check_LOS (AActor *from, AActor *to, angle_t vangle)
//-------------------------------------
//The bot will check if it's time to fire
//and do so if that is the case.
void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
void DBot::Dofire (ticcmd_t *cmd)
{
bool no_fire; //used to prevent bot from pumping rockets into nearby walls.
int aiming_penalty=0; //For shooting at shading target, if screen is red, MAKEME: When screen red.
@ -140,49 +139,48 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
fixed_t dist;
angle_t an;
int m;
AActor *enemy = actor->player->Bot->enemy;
if (!enemy || !(enemy->flags & MF_SHOOTABLE) || enemy->health <= 0)
return;
if (actor->player->ReadyWeapon == NULL)
if (player->ReadyWeapon == NULL)
return;
if (actor->player->damagecount > actor->player->Bot->skill.isp)
if (player->damagecount > skill.isp)
{
actor->player->Bot->first_shot = true;
first_shot = true;
return;
}
//Reaction skill thing.
if (actor->player->Bot->first_shot &&
!(actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING))
if (first_shot &&
!(player->ReadyWeapon->WeaponFlags & WIF_BOT_REACTION_SKILL_THING))
{
actor->player->Bot->t_react = (100-actor->player->Bot->skill.reaction+1)/((pr_botdofire()%3)+3);
t_react = (100-skill.reaction+1)/((pr_botdofire()%3)+3);
}
actor->player->Bot->first_shot = false;
if (actor->player->Bot->t_react)
first_shot = false;
if (t_react)
return;
//MAKEME: Decrease the rocket suicides even more.
no_fire = true;
//actor->player->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y);
//angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y);
//Distance to enemy.
dist = P_AproxDistance ((actor->x + actor->velx) - (enemy->x + enemy->velx),
(actor->y + actor->vely) - (enemy->y + enemy->vely));
dist = P_AproxDistance ((player->mo->x + player->mo->velx) - (enemy->x + enemy->velx),
(player->mo->y + player->mo->vely) - (enemy->y + enemy->vely));
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
if (actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)
if (player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)
{
if ((actor->player->ReadyWeapon->ProjectileType != NULL))
if ((player->ReadyWeapon->ProjectileType != NULL))
{
if (actor->player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true))
if (player->ReadyWeapon->CheckAmmo (AWeapon::PrimaryFire, false, true))
{
// This weapon can fire a projectile and has enough ammo to do so
goto shootmissile;
}
else if (!(actor->player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL))
else if (!(player->ReadyWeapon->WeaponFlags & WIF_AMMO_OPTIONAL))
{
// Ammo is required, so don't shoot. This is for weapons that shoot
// missiles that die at close range, such as the powered-up Phoneix Rod.
@ -195,51 +193,51 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
no_fire = (dist > (MELEERANGE*4));
}
}
else if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG)
else if (player->ReadyWeapon->WeaponFlags & WIF_BOT_BFG)
{
//MAKEME: This should be smarter.
if ((pr_botdofire()%200)<=actor->player->Bot->skill.reaction)
if(Check_LOS(actor, actor->player->Bot->enemy, SHOOTFOV))
if ((pr_botdofire()%200)<=skill.reaction)
if(Check_LOS(enemy, SHOOTFOV))
no_fire = false;
}
else if (actor->player->ReadyWeapon->ProjectileType != NULL)
else if (player->ReadyWeapon->ProjectileType != NULL)
{
if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
if (player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
{
//Special rules for RL
an = FireRox (actor, enemy, cmd);
an = FireRox (enemy, cmd);
if(an)
{
actor->player->Bot->angle = an;
angle = an;
//have to be somewhat precise. to avoid suicide.
if (abs (actor->player->Bot->angle - actor->angle) < 12*ANGLE_1)
if (abs (angle - player->mo->angle) < 12*ANGLE_1)
{
actor->player->Bot->t_rocket = 9;
t_rocket = 9;
no_fire = false;
}
}
}
// prediction aiming
shootmissile:
dist = P_AproxDistance (actor->x - enemy->x, actor->y - enemy->y);
m = dist / GetDefaultByType (actor->player->ReadyWeapon->ProjectileType)->Speed;
SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1);
actor->player->Bot->angle = R_PointToAngle2 (actor->x, actor->y, body1->x, body1->y);
if (Check_LOS (actor, enemy, SHOOTFOV))
dist = P_AproxDistance (player->mo->x - enemy->x, player->mo->y - enemy->y);
m = dist / GetDefaultByType (player->ReadyWeapon->ProjectileType)->Speed;
bglobal.SetBodyAt (enemy->x + enemy->velx*m*2, enemy->y + enemy->vely*m*2, enemy->z, 1);
angle = R_PointToAngle2 (player->mo->x, player->mo->y, bglobal.body1->x, bglobal.body1->y);
if (Check_LOS (enemy, SHOOTFOV))
no_fire = false;
}
else
{
//Other weapons, mostly instant hit stuff.
actor->player->Bot->angle = R_PointToAngle2 (actor->x, actor->y, enemy->x, enemy->y);
angle = R_PointToAngle2 (player->mo->x, player->mo->y, enemy->x, enemy->y);
aiming_penalty = 0;
if (enemy->flags & MF_SHADOW)
aiming_penalty += (pr_botdofire()%25)+10;
if (enemy->Sector->lightlevel<WHATS_DARK/* && !(actor->player->powers & PW_INFRARED)*/)
if (enemy->Sector->lightlevel<WHATS_DARK/* && !(player->powers & PW_INFRARED)*/)
aiming_penalty += pr_botdofire()%40;//Dark
if (actor->player->damagecount)
aiming_penalty += actor->player->damagecount; //Blood in face makes it hard to aim
aiming_value = actor->player->Bot->skill.aiming - aiming_penalty;
if (player->damagecount)
aiming_penalty += player->damagecount; //Blood in face makes it hard to aim
aiming_value = skill.aiming - aiming_penalty;
if (aiming_value <= 0)
aiming_value = 1;
m = ((SHOOTFOV/2)-(aiming_value*SHOOTFOV/200)); //Higher skill is more accurate
@ -248,18 +246,18 @@ shootmissile:
if (m)
{
if (actor->player->Bot->increase)
actor->player->Bot->angle += m;
if (increase)
angle += m;
else
actor->player->Bot->angle -= m;
angle -= m;
}
if (abs (actor->player->Bot->angle - actor->angle) < 4*ANGLE_1)
if (abs (angle - player->mo->angle) < 4*ANGLE_1)
{
actor->player->Bot->increase = !actor->player->Bot->increase;
increase = !increase;
}
if (Check_LOS (actor, enemy, (SHOOTFOV/2)))
if (Check_LOS (enemy, (SHOOTFOV/2)))
no_fire = false;
}
if (!no_fire) //If going to fire weapon
@ -267,7 +265,7 @@ shootmissile:
cmd->ucmd.buttons |= BT_ATTACK;
}
//Prevents bot from jerking, when firing automatic things with low skill.
//actor->angle = R_PointToAngle2(actor->x, actor->y, actor->player->enemy->x, actor->player->enemy->y);
//player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->enemy->x, player->enemy->y);
}
bool FCajunMaster::IsLeader (player_t *player)
@ -287,7 +285,7 @@ bool FCajunMaster::IsLeader (player_t *player)
//This function is called every
//tick (for each bot) to set
//the mate (teammate coop mate).
AActor *FCajunMaster::Choose_Mate (AActor *bot)
AActor *DBot::Choose_Mate ()
{
int count;
fixed_t closest_dist, test;
@ -295,20 +293,20 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
AActor *observer;
//is mate alive?
if (bot->player->Bot->mate)
if (mate)
{
if (bot->player->Bot->mate->health <= 0)
bot->player->Bot->mate = NULL;
if (mate->health <= 0)
mate = NULL;
else
bot->player->Bot->last_mate = bot->player->Bot->mate;
last_mate = mate;
}
if (bot->player->Bot->mate) //Still is..
return bot->player->Bot->mate;
if (mate) //Still is..
return mate;
//Check old_mates status.
if (bot->player->Bot->last_mate)
if (bot->player->Bot->last_mate->health <= 0)
bot->player->Bot->last_mate = NULL;
if (last_mate)
if (last_mate->health <= 0)
last_mate = NULL;
target = NULL;
closest_dist = FIXED_MAX;
@ -324,17 +322,17 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
if (playeringame[count]
&& client->mo
&& bot != client->mo
&& (bot->IsTeammate (client->mo) || !deathmatch)
&& player->mo != client->mo
&& (player->mo->IsTeammate (client->mo) || !deathmatch)
&& client->mo->health > 0
&& client->mo != observer
&& ((bot->health/2) <= client->mo->health || !deathmatch)
&& !IsLeader(client)) //taken?
&& ((player->mo->health/2) <= client->mo->health || !deathmatch)
&& !bglobal.IsLeader(client)) //taken?
{
if (P_CheckSight (bot, client->mo, SF_IGNOREVISIBILITY))
if (P_CheckSight (player->mo, client->mo, SF_IGNOREVISIBILITY))
{
test = P_AproxDistance (client->mo->x - bot->x,
client->mo->y - bot->y);
test = P_AproxDistance (client->mo->x - player->mo->x,
client->mo->y - player->mo->y);
if (test < closest_dist)
{
@ -347,15 +345,15 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
/*
//Make a introducing to mate.
if(target && target!=bot->player->last_mate)
if(target && target!=last_mate)
{
if((P_Random()%(200*bglobal.botnum))<3)
{
bot->player->chat = c_teamup;
chat = c_teamup;
if(target->bot)
strcpy(bot->player->c_target, botsingame[target->bot_id]);
strcpy(c_target, botsingame[target->bot_id]);
else if(target->player)
strcpy(bot->player->c_target, player_names[target->play_id]);
strcpy(c_target, player_names[target->play_id]);
}
}
*/
@ -365,7 +363,7 @@ AActor *FCajunMaster::Choose_Mate (AActor *bot)
}
//MAKEME: Make this a smart decision
AActor *FCajunMaster::Find_enemy (AActor *bot)
AActor *DBot::Find_enemy ()
{
int count;
fixed_t closest_dist, temp; //To target.
@ -375,15 +373,15 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
if (!deathmatch)
{ // [RH] Take advantage of the Heretic/Hexen code to be a little smarter
return P_RoughMonsterSearch (bot, 20);
return P_RoughMonsterSearch (player->mo, 20);
}
//Note: It's hard to ambush a bot who is not alone
if (bot->player->Bot->allround || bot->player->Bot->mate)
if (allround || mate)
vangle = ANGLE_MAX;
else
vangle = ENEMY_SCAN_FOV;
bot->player->Bot->allround = false;
allround = false;
target = NULL;
closest_dist = FIXED_MAX;
@ -396,21 +394,21 @@ AActor *FCajunMaster::Find_enemy (AActor *bot)
{
player_t *client = &players[count];
if (playeringame[count]
&& !bot->IsTeammate (client->mo)
&& !player->mo->IsTeammate (client->mo)
&& client->mo != observer
&& client->mo->health > 0
&& bot != client->mo)
&& player->mo != client->mo)
{
if (Check_LOS (bot, client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
//if(P_CheckSight(bot, players[count].mo))
if (Check_LOS (client->mo, vangle)) //Here's a strange one, when bot is standing still, the P_CheckSight within Check_LOS almost always returns false. tought it should be the same checksight as below but.. (below works) something must be fuckin wierd screded up.
//if(P_CheckSight(player->mo, players[count].mo))
{
temp = P_AproxDistance (client->mo->x - bot->x,
client->mo->y - bot->y);
temp = P_AproxDistance (client->mo->x - player->mo->x,
client->mo->y - player->mo->y);
//Too dark?
if (temp > DARK_DIST &&
client->mo->Sector->lightlevel < WHATS_DARK /*&&
bot->player->Powers & PW_INFRARED*/)
player->Powers & PW_INFRARED*/)
continue;
if (temp < closest_dist)
@ -494,16 +492,16 @@ fixed_t FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
return dist;
}
angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
angle_t DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
{
fixed_t dist;
angle_t ang;
AActor *actor;
int m;
SetBodyAt (bot->x + FixedMul(bot->velx, 5*FRACUNIT),
bot->y + FixedMul(bot->vely, 5*FRACUNIT),
bot->z + (bot->height / 2), 2);
bglobal.SetBodyAt (player->mo->x + FixedMul(player->mo->velx, 5*FRACUNIT),
player->mo->y + FixedMul(player->mo->vely, 5*FRACUNIT),
player->mo->z + (player->mo->height / 2), 2);
actor = bglobal.body2;
@ -513,16 +511,16 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
//Predict.
m = (((dist+1)/FRACUNIT) / GetDefaultByName("Rocket")->Speed);
SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
bglobal.SetBodyAt (enemy->x + FixedMul(enemy->velx, (m+2*FRACUNIT)),
enemy->y + FixedMul(enemy->vely, (m+2*FRACUNIT)), ONFLOORZ, 1);
dist = P_AproxDistance(actor->x-bglobal.body1->x, actor->y-bglobal.body1->y);
//try the predicted location
if (P_CheckSight (actor, bglobal.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile
{
FCheckPosition tm;
if (SafeCheckPosition (bot, actor->x, actor->y, tm))
if (bglobal.SafeCheckPosition (player->mo, actor->x, actor->y, tm))
{
if (FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST)
if (bglobal.FakeFire (actor, bglobal.body1, cmd) >= SAFE_SELF_MISDIST)
{
ang = R_PointToAngle2 (actor->x, actor->y, bglobal.body1->x, bglobal.body1->y);
return ang;
@ -532,9 +530,9 @@ angle_t FCajunMaster::FireRox (AActor *bot, AActor *enemy, ticcmd_t *cmd)
//Try fire straight.
if (P_CheckSight (actor, enemy, 0))
{
if (FakeFire (bot, enemy, cmd) >= SAFE_SELF_MISDIST)
if (bglobal.FakeFire (player->mo, enemy, cmd) >= SAFE_SELF_MISDIST)
{
ang = R_PointToAngle2(bot->x, bot->y, enemy->x, enemy->y);
ang = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
return ang;
}
}

View file

@ -27,57 +27,57 @@ static FRandom pr_botnewchasedir ("BotNewChaseDir");
extern dirtype_t opposite[9];
extern dirtype_t diags[4];
//Called while the bot moves after its player->dest mobj
//Called while the bot moves after its dest mobj
//which can be a weapon/enemy/item whatever.
void FCajunMaster::Roam (AActor *actor, ticcmd_t *cmd)
void DBot::Roam (ticcmd_t *cmd)
{
int delta;
if (Reachable(actor, actor->player->Bot->dest))
if (Reachable(dest))
{ // Straight towards it.
actor->player->Bot->angle = R_PointToAngle2(actor->x, actor->y, actor->player->Bot->dest->x, actor->player->Bot->dest->y);
angle = R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y);
}
else if (actor->movedir < 8) // turn towards movement direction if not there yet
else if (player->mo->movedir < 8) // turn towards movement direction if not there yet
{
actor->player->Bot->angle &= (angle_t)(7<<29);
delta = actor->player->Bot->angle - (actor->movedir << 29);
angle &= (angle_t)(7<<29);
delta = angle - (player->mo->movedir << 29);
if (delta > 0)
actor->player->Bot->angle -= ANG45;
angle -= ANG45;
else if (delta < 0)
actor->player->Bot->angle += ANG45;
angle += ANG45;
}
// chase towards destination.
if (--actor->movecount < 0 || !Move (actor, cmd))
if (--player->mo->movecount < 0 || !Move (cmd))
{
NewChaseDir (actor, cmd);
NewChaseDir (cmd);
}
}
bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
bool DBot::Move (ticcmd_t *cmd)
{
fixed_t tryx, tryy;
bool try_ok;
int good;
if (actor->movedir == DI_NODIR)
if (player->mo->movedir == DI_NODIR)
return false;
if ((unsigned)actor->movedir >= 8)
if ((unsigned)player->mo->movedir >= 8)
I_Error ("Weird bot movedir!");
tryx = actor->x + 8*xspeed[actor->movedir];
tryy = actor->y + 8*yspeed[actor->movedir];
tryx = player->mo->x + 8*xspeed[player->mo->movedir];
tryy = player->mo->y + 8*yspeed[player->mo->movedir];
try_ok = CleanAhead (actor, tryx, tryy, cmd);
try_ok = bglobal.CleanAhead (player->mo, tryx, tryy, cmd);
if (!try_ok) //Anything blocking that could be opened etc..
{
if (!spechit.Size ())
return false;
actor->movedir = DI_NODIR;
player->mo->movedir = DI_NODIR;
good = 0;
line_t *ld;
@ -86,16 +86,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
{
bool tryit = true;
if (ld->special == Door_LockedRaise && !P_CheckKeys (actor, ld->args[3], false))
if (ld->special == Door_LockedRaise && !P_CheckKeys (player->mo, ld->args[3], false))
tryit = false;
else if (ld->special == Generic_Door && !P_CheckKeys (actor, ld->args[4], false))
else if (ld->special == Generic_Door && !P_CheckKeys (player->mo, ld->args[4], false))
tryit = false;
if (tryit &&
(P_TestActivateLine (ld, actor, 0, SPAC_Use) ||
P_TestActivateLine (ld, actor, 0, SPAC_Push)))
(P_TestActivateLine (ld, player->mo, 0, SPAC_Use) ||
P_TestActivateLine (ld, player->mo, 0, SPAC_Push)))
{
good |= ld == actor->BlockingLine ? 1 : 2;
good |= ld == player->mo->BlockingLine ? 1 : 2;
}
}
if (good && ((pr_botopendoor() >= 203) ^ (good & 1)))
@ -113,16 +113,16 @@ bool FCajunMaster::Move (AActor *actor, ticcmd_t *cmd)
return true;
}
bool FCajunMaster::TryWalk (AActor *actor, ticcmd_t *cmd)
bool DBot::TryWalk (ticcmd_t *cmd)
{
if (!Move (actor, cmd))
if (!Move (cmd))
return false;
actor->movecount = pr_bottrywalk() & 60;
player->mo->movecount = pr_bottrywalk() & 60;
return true;
}
void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
void DBot::NewChaseDir (ticcmd_t *cmd)
{
fixed_t deltax;
fixed_t deltay;
@ -134,7 +134,7 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
dirtype_t turnaround;
if (!actor->player->Bot->dest)
if (!dest)
{
#ifndef BOT_RELEASE_COMPILE
Printf ("Bot tried move without destination\n");
@ -142,11 +142,11 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
return;
}
olddir = (dirtype_t)actor->movedir;
olddir = (dirtype_t)player->mo->movedir;
turnaround = opposite[olddir];
deltax = actor->player->Bot->dest->x - actor->x;
deltay = actor->player->Bot->dest->y - actor->y;
deltax = dest->x - player->mo->x;
deltay = dest->y - player->mo->y;
if (deltax > 10*FRACUNIT)
d[1] = DI_EAST;
@ -165,8 +165,8 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
// try direct route
if (d[1] != DI_NODIR && d[2] != DI_NODIR)
{
actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
if (actor->movedir != turnaround && TryWalk(actor, cmd))
player->mo->movedir = diags[((deltay<0)<<1)+(deltax>0)];
if (player->mo->movedir != turnaround && TryWalk(cmd))
return;
}
@ -186,16 +186,16 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
if (d[1]!=DI_NODIR)
{
actor->movedir = d[1];
if (TryWalk (actor, cmd))
player->mo->movedir = d[1];
if (TryWalk (cmd))
return;
}
if (d[2]!=DI_NODIR)
{
actor->movedir = d[2];
player->mo->movedir = d[2];
if (TryWalk(actor, cmd))
if (TryWalk(cmd))
return;
}
@ -203,9 +203,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
// so pick another direction.
if (olddir!=DI_NODIR)
{
actor->movedir = olddir;
player->mo->movedir = olddir;
if (TryWalk(actor, cmd))
if (TryWalk(cmd))
return;
}
@ -218,9 +218,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
{
if (tdir!=turnaround)
{
actor->movedir = tdir;
player->mo->movedir = tdir;
if (TryWalk(actor, cmd))
if (TryWalk(cmd))
return;
}
}
@ -233,9 +233,9 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
{
if (tdir!=turnaround)
{
actor->movedir = tdir;
player->mo->movedir = tdir;
if (TryWalk(actor, cmd))
if (TryWalk(cmd))
return;
}
}
@ -243,12 +243,12 @@ void FCajunMaster::NewChaseDir (AActor *actor, ticcmd_t *cmd)
if (turnaround != DI_NODIR)
{
actor->movedir = turnaround;
if (TryWalk(actor, cmd))
player->mo->movedir = turnaround;
if (TryWalk(cmd))
return;
}
actor->movedir = DI_NODIR; // can not move
player->mo->movedir = DI_NODIR; // can not move
}
@ -307,48 +307,48 @@ bool FCajunMaster::CleanAhead (AActor *thing, fixed_t x, fixed_t y, ticcmd_t *cm
#define MAXTURN (15*ANGLE_1) //Max degrees turned in one tic. Lower is smother but may cause the bot not getting where it should = crash
#define TURNSENS 3 //Higher is smoother but slower turn.
void FCajunMaster::TurnToAng (AActor *actor)
void DBot::TurnToAng ()
{
int maxturn = MAXTURN;
if (actor->player->ReadyWeapon != NULL)
if (player->ReadyWeapon != NULL)
{
if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
if (player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE)
{
if (actor->player->Bot->t_roam && !actor->player->Bot->missile)
if (t_roam && !missile)
{ //Keep angle that where when shot where decided.
return;
}
}
if(actor->player->Bot->enemy)
if(!actor->player->Bot->dest) //happens when running after item in combat situations, or normal, prevents weak turns
if(actor->player->ReadyWeapon->ProjectileType == NULL && !(actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON))
if(Check_LOS(actor, actor->player->Bot->enemy, SHOOTFOV+5*ANGLE_1))
if(enemy)
if(!dest) //happens when running after item in combat situations, or normal, prevents weak turns
if(player->ReadyWeapon->ProjectileType == NULL && !(player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON))
if(Check_LOS(enemy, SHOOTFOV+5*ANGLE_1))
maxturn = 3;
}
int distance = actor->player->Bot->angle - actor->angle;
int distance = angle - player->mo->angle;
if (abs (distance) < OKAYRANGE && !actor->player->Bot->enemy)
if (abs (distance) < OKAYRANGE && !enemy)
return;
distance /= TURNSENS;
if (abs (distance) > maxturn)
distance = distance < 0 ? -maxturn : maxturn;
actor->angle += distance;
player->mo->angle += distance;
}
void FCajunMaster::Pitch (AActor *actor, AActor *target)
void DBot::Pitch (AActor *target)
{
double aim;
double diff;
diff = target->z - actor->z;
aim = atan (diff / (double)P_AproxDistance (actor->x - target->x, actor->y - target->y));
actor->pitch = -(int)(aim * ANGLE_180/M_PI);
diff = target->z - player->mo->z;
aim = atan (diff / (double)P_AproxDistance (player->mo->x - target->x, player->mo->y - target->y));
player->mo->pitch = -(int)(aim * ANGLE_180/M_PI);
}
//Checks if a sector is dangerous.
@ -371,4 +371,3 @@ bool FCajunMaster::IsDangerous (sector_t *sec)
|| special == Damage_InstantDeath
|| special == sDamage_SuperHellslime;
}

View file

@ -24,47 +24,49 @@ static FRandom pr_botmove ("BotMove");
//This function is called each tic for each bot,
//so this is what the bot does.
void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd)
void DBot::Think ()
{
ticcmd_t *cmd = &netcmds[player - players][((gametic + 1)/ticdup)%BACKUPTICS];
memset (cmd, 0, sizeof(*cmd));
if (actor->player->Bot->enemy && actor->player->Bot->enemy->health <= 0)
actor->player->Bot->enemy = NULL;
if (enemy && enemy->health <= 0)
enemy = NULL;
if (actor->health > 0) //Still alive
if (player->mo->health > 0) //Still alive
{
if (teamplay || !deathmatch)
actor->player->Bot->mate = Choose_Mate (actor);
mate = Choose_Mate ();
angle_t oldyaw = actor->angle;
int oldpitch = actor->pitch;
angle_t oldyaw = player->mo->angle;
int oldpitch = player->mo->pitch;
Set_enemy (actor);
ThinkForMove (actor, cmd);
TurnToAng (actor);
Set_enemy ();
ThinkForMove (cmd);
TurnToAng ();
cmd->ucmd.yaw = (short)((actor->angle - oldyaw) >> 16) / ticdup;
cmd->ucmd.pitch = (short)((oldpitch - actor->pitch) >> 16);
cmd->ucmd.yaw = (short)((player->mo->angle - oldyaw) >> 16) / ticdup;
cmd->ucmd.pitch = (short)((oldpitch - player->mo->pitch) >> 16);
if (cmd->ucmd.pitch == -32768)
cmd->ucmd.pitch = -32767;
cmd->ucmd.pitch /= ticdup;
actor->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
actor->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
player->mo->angle = oldyaw + (cmd->ucmd.yaw << 16) * ticdup;
player->mo->pitch = oldpitch - (cmd->ucmd.pitch << 16) * ticdup;
}
if (actor->player->Bot->t_active) actor->player->Bot->t_active--;
if (actor->player->Bot->t_strafe) actor->player->Bot->t_strafe--;
if (actor->player->Bot->t_react) actor->player->Bot->t_react--;
if (actor->player->Bot->t_fight) actor->player->Bot->t_fight--;
if (actor->player->Bot->t_rocket) actor->player->Bot->t_rocket--;
if (actor->player->Bot->t_roam) actor->player->Bot->t_roam--;
if (t_active) t_active--;
if (t_strafe) t_strafe--;
if (t_react) t_react--;
if (t_fight) t_fight--;
if (t_rocket) t_rocket--;
if (t_roam) t_roam--;
//Respawn ticker
if (actor->player->Bot->t_respawn)
if (t_respawn)
{
actor->player->Bot->t_respawn--;
t_respawn--;
}
else if (actor->health <= 0)
else if (player->mo->health <= 0)
{ // Time to respawn
cmd->ucmd.buttons |= BT_USE;
}
@ -72,62 +74,57 @@ void FCajunMaster::Think (AActor *actor, ticcmd_t *cmd)
//how the bot moves.
//MAIN movement function.
void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
void DBot::ThinkForMove (ticcmd_t *cmd)
{
player_t *b;
fixed_t dist;
bool stuck;
int r;
b = actor->player;
if (b->Bot == NULL)
return;
stuck = false;
dist = b->Bot->dest ? P_AproxDistance(actor->x-b->Bot->dest->x, actor->y-b->Bot->dest->y) : 0;
dist = dest ? P_AproxDistance(player->mo->x-dest->x, player->mo->y-dest->y) : 0;
if (b->Bot->missile &&
((!b->Bot->missile->velx || !b->Bot->missile->vely) || !Check_LOS(actor, b->Bot->missile, SHOOTFOV*3/2)))
if (missile &&
((!missile->velx || !missile->vely) || !Check_LOS(missile, SHOOTFOV*3/2)))
{
b->Bot->sleft = !b->Bot->sleft;
b->Bot->missile = NULL; //Probably ended its travel.
sleft = !sleft;
missile = NULL; //Probably ended its travel.
}
if (actor->pitch > 0)
actor->pitch -= 80;
else if (actor->pitch <= -60)
actor->pitch += 80;
if (player->mo->pitch > 0)
player->mo->pitch -= 80;
else if (player->mo->pitch <= -60)
player->mo->pitch += 80;
//HOW TO MOVE:
if (b->Bot->missile && (P_AproxDistance(actor->x-b->Bot->missile->x, actor->y-b->Bot->missile->y)<AVOID_DIST)) //try avoid missile got from P_Mobj.c thinking part.
if (missile && (P_AproxDistance(player->mo->x-missile->x, player->mo->y-missile->y)<AVOID_DIST)) //try avoid missile got from P_Mobj.c thinking part.
{
Pitch (actor, b->Bot->missile);
actor->player->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->missile->x, b->Bot->missile->y);
cmd->ucmd.sidemove = b->Bot->sleft ? -SIDERUN : SIDERUN;
Pitch (missile);
angle = R_PointToAngle2(player->mo->x, player->mo->y, missile->x, missile->y);
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
cmd->ucmd.forwardmove = -FORWARDRUN; //Back IS best.
if ((P_AproxDistance(actor->x-b->Bot->oldx, actor->y-b->Bot->oldy)<50000)
&& b->Bot->t_strafe<=0)
if ((P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000)
&& t_strafe<=0)
{
b->Bot->t_strafe = 5;
b->Bot->sleft = !b->Bot->sleft;
t_strafe = 5;
sleft = !sleft;
}
//If able to see enemy while avoiding missile, still fire at enemy.
if (b->Bot->enemy && Check_LOS (actor, b->Bot->enemy, SHOOTFOV))
Dofire (actor, cmd); //Order bot to fire current weapon
if (enemy && Check_LOS (enemy, SHOOTFOV))
Dofire (cmd); //Order bot to fire current weapon
}
else if (b->Bot->enemy && P_CheckSight (actor, b->Bot->enemy, 0)) //Fight!
else if (enemy && P_CheckSight (player->mo, enemy, 0)) //Fight!
{
Pitch (actor, b->Bot->enemy);
Pitch (enemy);
//Check if it's more important to get an item than fight.
if (b->Bot->dest && (b->Bot->dest->flags&MF_SPECIAL)) //Must be an item, that is close enough.
if (dest && (dest->flags&MF_SPECIAL)) //Must be an item, that is close enough.
{
#define is(x) b->Bot->dest->IsKindOf (PClass::FindClass (#x))
#define is(x) dest->IsKindOf (PClass::FindClass (#x))
if (
(
(actor->health < b->Bot->skill.isp &&
(player->mo->health < skill.isp &&
(is (Medikit) ||
is (Stimpack) ||
is (Soulsphere) ||
@ -140,78 +137,78 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
is (Megasphere)
) ||
dist < (GETINCOMBAT/4) ||
(b->ReadyWeapon == NULL || b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)
(player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)
)
&& (dist < GETINCOMBAT || (b->ReadyWeapon == NULL || b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
&& Reachable (actor, b->Bot->dest))
&& (dist < GETINCOMBAT || (player->ReadyWeapon == NULL || player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
&& Reachable (dest))
#undef is
{
goto roam; //Pick it up, no matter the situation. All bonuses are nice close up.
}
}
b->Bot->dest = NULL; //To let bot turn right
dest = NULL; //To let bot turn right
if (b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
actor->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
if (player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
player->mo->flags &= ~MF_DROPOFF; //Don't jump off any ledges when fighting.
if (!(b->Bot->enemy->flags3 & MF3_ISMONSTER))
b->Bot->t_fight = AFTERTICS;
if (!(enemy->flags3 & MF3_ISMONSTER))
t_fight = AFTERTICS;
if (b->Bot->t_strafe <= 0 &&
(P_AproxDistance(actor->x-b->Bot->oldx, actor->y-b->Bot->oldy)<50000
if (t_strafe <= 0 &&
(P_AproxDistance(player->mo->x-oldx, player->mo->y-oldy)<50000
|| ((pr_botmove()%30)==10))
)
{
stuck = true;
b->Bot->t_strafe = 5;
b->Bot->sleft = !b->Bot->sleft;
t_strafe = 5;
sleft = !sleft;
}
b->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->enemy->x, b->Bot->enemy->y);
angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
if (b->ReadyWeapon == NULL ||
P_AproxDistance(actor->x-b->Bot->enemy->x, actor->y-b->Bot->enemy->y) >
b->ReadyWeapon->MoveCombatDist)
if (player->ReadyWeapon == NULL ||
P_AproxDistance(player->mo->x-enemy->x, player->mo->y-enemy->y) >
player->ReadyWeapon->MoveCombatDist)
{
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
cmd->ucmd.forwardmove = (b->Bot->enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN;
cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? FORWARDWALK : FORWARDRUN;
}
else if (!stuck) //Too close, so move away.
{
// If a monster, use lower speed (just for cooler apperance while strafing down doomed monster)
cmd->ucmd.forwardmove = (b->Bot->enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN;
cmd->ucmd.forwardmove = (enemy->flags3 & MF3_ISMONSTER) ? -FORWARDWALK : -FORWARDRUN;
}
//Strafing.
if (b->Bot->enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool.
if (enemy->flags3 & MF3_ISMONSTER) //It's just a monster so take it down cool.
{
cmd->ucmd.sidemove = b->Bot->sleft ? -SIDEWALK : SIDEWALK;
cmd->ucmd.sidemove = sleft ? -SIDEWALK : SIDEWALK;
}
else
{
cmd->ucmd.sidemove = b->Bot->sleft ? -SIDERUN : SIDERUN;
cmd->ucmd.sidemove = sleft ? -SIDERUN : SIDERUN;
}
Dofire (actor, cmd); //Order bot to fire current weapon
Dofire (cmd); //Order bot to fire current weapon
}
else if (b->Bot->mate && !b->Bot->enemy && (!b->Bot->dest || b->Bot->dest==b->Bot->mate)) //Follow mate move.
else if (mate && !enemy && (!dest || dest==mate)) //Follow mate move.
{
fixed_t matedist;
Pitch (actor, b->Bot->mate);
Pitch (mate);
if (!Reachable (actor, b->Bot->mate))
if (!Reachable (mate))
{
if (b->Bot->mate == b->Bot->dest && pr_botmove.Random() < 32)
if (mate == dest && pr_botmove.Random() < 32)
{ // [RH] If the mate is the dest, pick a new dest sometimes
b->Bot->dest = NULL;
dest = NULL;
}
goto roam;
}
actor->player->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->mate->x, b->Bot->mate->y);
angle = R_PointToAngle2(player->mo->x, player->mo->y, mate->x, mate->y);
matedist = P_AproxDistance(actor->x - b->Bot->mate->x, actor->y - b->Bot->mate->y);
matedist = P_AproxDistance(player->mo->x - mate->x, player->mo->y - mate->y);
if (matedist > (FRIEND_DIST*2))
cmd->ucmd.forwardmove = FORWARDRUN;
else if (matedist > FRIEND_DIST)
@ -221,42 +218,42 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
}
else //Roam after something.
{
b->Bot->first_shot = true;
first_shot = true;
/////
roam:
/////
if (b->Bot->enemy && Check_LOS (actor, b->Bot->enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it.
Dofire (actor, cmd); //Order bot to fire current weapon
if (enemy && Check_LOS (enemy, SHOOTFOV*3/2)) //If able to see enemy while avoiding missile , still fire at it.
Dofire (cmd); //Order bot to fire current weapon
if (b->Bot->dest && !(b->Bot->dest->flags&MF_SPECIAL) && b->Bot->dest->health < 0)
if (dest && !(dest->flags&MF_SPECIAL) && dest->health < 0)
{ //Roaming after something dead.
b->Bot->dest = NULL;
dest = NULL;
}
if (b->Bot->dest == NULL)
if (dest == NULL)
{
if (b->Bot->t_fight && b->Bot->enemy) //Enemy/bot has jumped around corner. So what to do?
if (t_fight && enemy) //Enemy/bot has jumped around corner. So what to do?
{
if (b->Bot->enemy->player)
if (enemy->player)
{
if (((b->Bot->enemy->player->ReadyWeapon != NULL && b->Bot->enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) ||
(pr_botmove()%100)>b->Bot->skill.isp) && b->ReadyWeapon != NULL && !(b->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
b->Bot->dest = b->Bot->enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
else //hide while b->t_fight, but keep view at enemy.
b->Bot->angle = R_PointToAngle2(actor->x, actor->y, b->Bot->enemy->x, b->Bot->enemy->y);
if (((enemy->player->ReadyWeapon != NULL && enemy->player->ReadyWeapon->WeaponFlags & WIF_BOT_EXPLOSIVE) ||
(pr_botmove()%100)>skill.isp) && player->ReadyWeapon != NULL && !(player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON))
dest = enemy;//Dont let enemy kill the bot by supressive fire. So charge enemy.
else //hide while t_fight, but keep view at enemy.
angle = R_PointToAngle2(player->mo->x, player->mo->y, enemy->x, enemy->y);
} //Just a monster, so kill it.
else
b->Bot->dest = b->Bot->enemy;
dest = enemy;
//VerifFavoritWeapon(actor->player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh.
//VerifFavoritWeapon(player); //Dont know why here.., but it must be here, i know the reason, but not why at this spot, uh.
}
else //Choose a distant target. to get things going.
{
r = pr_botmove();
if (r < 128)
{
TThinkerIterator<AInventory> it (STAT_INVENTORY, firstthing);
TThinkerIterator<AInventory> it (STAT_INVENTORY, bglobal.firstthing);
AInventory *item = it.Next();
if (item != NULL || (item = it.Next()) != NULL)
@ -271,60 +268,53 @@ void FCajunMaster::ThinkForMove (AActor *actor, ticcmd_t *cmd)
{
item = it.Next();
}
firstthing = item;
b->Bot->dest = item;
bglobal.firstthing = item;
dest = item;
}
}
else if (b->Bot->mate && (r < 179 || P_CheckSight(actor, b->Bot->mate)))
else if (mate && (r < 179 || P_CheckSight(player->mo, mate)))
{
b->Bot->dest = b->Bot->mate;
dest = mate;
}
else if ((playeringame[(r&(MAXPLAYERS-1))]) && players[(r&(MAXPLAYERS-1))].mo->health > 0)
{
b->Bot->dest = players[(r&(MAXPLAYERS-1))].mo;
dest = players[(r&(MAXPLAYERS-1))].mo;
}
}
if (b->Bot->dest)
if (dest)
{
b->Bot->t_roam = MAXROAM;
t_roam = MAXROAM;
}
}
if (b->Bot->dest)
if (dest)
{ //Bot has a target so roam after it.
Roam (actor, cmd);
Roam (cmd);
}
} //End of movement main part.
if (!b->Bot->t_roam && b->Bot->dest)
if (!t_roam && dest)
{
b->Bot->prev = b->Bot->dest;
b->Bot->dest = NULL;
prev = dest;
dest = NULL;
}
if (b->Bot->t_fight<(AFTERTICS/2))
actor->flags |= MF_DROPOFF;
if (t_fight<(AFTERTICS/2))
player->mo->flags |= MF_DROPOFF;
b->Bot->oldx = actor->x;
b->Bot->oldy = actor->y;
oldx = player->mo->x;
oldy = player->mo->y;
}
//BOT_WhatToGet
//
//Determines if the bot will roam after an item or not.
void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
void DBot::WhatToGet (AActor *item)
{
player_t *b = actor->player;
if (b == NULL)
{
return;
}
#define typeis(x) item->IsKindOf (PClass::FindClass (#x))
if ((item->renderflags & RF_INVISIBLE) //Under respawn and away.
|| item == b->Bot->prev)
|| item == prev)
{
return;
}
@ -338,7 +328,7 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
// FIXME
AWeapon *heldWeapon;
heldWeapon = static_cast<AWeapon *> (b->mo->FindInventory (item->GetClass()));
heldWeapon = static_cast<AWeapon *> (player->mo->FindInventory (item->GetClass()));
if (heldWeapon != NULL)
{
if (!weapgiveammo)
@ -354,39 +344,38 @@ void FCajunMaster::WhatToGet (AActor *actor, AActor *item)
{
AAmmo *ammo = static_cast<AAmmo *> (item);
const PClass *parent = ammo->GetParentAmmo ();
AInventory *holdingammo = b->mo->FindInventory (parent);
AInventory *holdingammo = player->mo->FindInventory (parent);
if (holdingammo != NULL && holdingammo->Amount >= holdingammo->MaxAmount)
{
return;
}
}
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && actor->health >= deh.MaxSoulsphere)
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
return;
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && actor->health >= deh.MaxHealth /*MAXHEALTH*/)
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= deh.MaxHealth /*MAXHEALTH*/)
return;
if ((b->Bot->dest == NULL ||
!(b->Bot->dest->flags & MF_SPECIAL)/* ||
!Reachable (actor, b->dest)*/)/* &&
Reachable (actor, item)*/) // Calling Reachable slows this down tremendously
if ((dest == NULL ||
!(dest->flags & MF_SPECIAL)/* ||
!Reachable (dest)*/)/* &&
Reachable (item)*/) // Calling Reachable slows this down tremendously
{
b->Bot->prev = b->Bot->dest;
b->Bot->dest = item;
b->Bot->t_roam = MAXROAM;
prev = dest;
dest = item;
t_roam = MAXROAM;
}
}
void FCajunMaster::Set_enemy (AActor *actor)
void DBot::Set_enemy ()
{
AActor *oldenemy;
AActor **enemy = &actor->player->Bot->enemy;
if (*enemy
&& (*enemy)->health > 0
&& P_CheckSight (actor, *enemy))
if (enemy
&& enemy->health > 0
&& P_CheckSight (player->mo, enemy))
{
oldenemy = *enemy;
oldenemy = enemy;
}
else
{
@ -395,15 +384,14 @@ void FCajunMaster::Set_enemy (AActor *actor)
// [RH] Don't even bother looking for a different enemy if this is not deathmatch
// and we already have an existing enemy.
if (deathmatch || !*enemy)
if (deathmatch || !enemy)
{
actor->player->Bot->allround = !!*enemy;
*enemy = NULL;
*enemy = Find_enemy(actor);
if (!*enemy)
*enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone)
allround = !!enemy;
enemy = Find_enemy();
if (!enemy)
enemy = oldenemy; //Try go for last (it will be NULL if there wasn't anyone)
}
//Verify that that enemy is really something alive that bot can kill.
if (*enemy && (((*enemy)->health < 0 || !((*enemy)->flags&MF_SHOOTABLE)) || actor->IsFriend(*enemy)))
*enemy = NULL;
if (enemy && ((enemy->health < 0 || !(enemy->flags&MF_SHOOTABLE)) || player->mo->IsFriend(enemy)))
enemy = NULL;
}

View file

@ -1554,13 +1554,6 @@ void C_MidPrint (FFont *font, const char *msg)
AddToConsole (-1, bar1);
AddToConsole (-1, msg);
AddToConsole (-1, bar3);
if (Logfile)
{
fputs (logbar, Logfile);
fputs (msg, Logfile);
fputs (logbar, Logfile);
fflush (Logfile);
}
StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0,
(EColorRange)PrintColors[PRINTLEVELS], con_midtime), MAKE_ID('C','N','T','R'));
@ -1578,13 +1571,6 @@ void C_MidPrintBold (FFont *font, const char *msg)
AddToConsole (-1, bar2);
AddToConsole (-1, msg);
AddToConsole (-1, bar3);
if (Logfile)
{
fputs (logbar, Logfile);
fputs (msg, Logfile);
fputs (logbar, Logfile);
fflush (Logfile);
}
StatusBar->AttachMessage (new DHUDMessage (font, msg, 1.5f, 0.375f, 0, 0,
(EColorRange)PrintColors[PRINTLEVELS+1], con_midtime), MAKE_ID('C','N','T','R'));

View file

@ -1515,6 +1515,22 @@ void UnlatchCVars (void)
}
}
void DestroyCVarsFlagged (DWORD flags)
{
FBaseCVar *cvar = CVars;
FBaseCVar *next = cvar;
while(cvar)
{
next = cvar->m_Next;
if(cvar->Flags & flags)
delete cvar;
cvar = next;
}
}
void C_SetCVarsToDefaults (void)
{
FBaseCVar *cvar = CVars;

View file

@ -159,6 +159,7 @@ private:
friend FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev);
friend FBaseCVar *FindCVarSub (const char *var_name, int namelen);
friend void UnlatchCVars (void);
friend void DestroyCVarsFlagged (DWORD flags);
friend void C_ArchiveCVars (FConfigFile *f, uint32 filter);
friend void C_SetCVarsToDefaults (void);
friend void FilterCompactCVars (TArray<FBaseCVar *> &cvars, uint32 filter);
@ -190,6 +191,9 @@ FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags);
// Called from G_InitNew()
void UnlatchCVars (void);
// Destroy CVars with the matching flags; called from CCMD(restart)
void DestroyCVarsFlagged (DWORD flags);
// archive cvars to FILE f
void C_ArchiveCVars (FConfigFile *f, uint32 filter);

View file

@ -1619,6 +1619,14 @@ const char* I_GetBackEndName()
}
FString OSX_FindApplicationSupport()
{
NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
if(url == nil)
return FString();
return [[url path] UTF8String];
}
// ---------------------------------------------------------------------------

View file

@ -2247,7 +2247,10 @@ static int PatchStrings (int dummy)
ReplaceSpecialChars (holdstring.LockBuffer());
holdstring.UnlockBuffer();
GStrings.SetString (Line1, holdstring);
// Account for a discrepancy between Boom's and ZDoom's name for the red skull key pickup message
const char *ll = Line1;
if (!stricmp(ll, "GOTREDSKULL")) ll = "GOTREDSKUL";
GStrings.SetString (ll, holdstring);
DPrintf ("%s set to:\n%s\n", Line1, holdstring.GetChars());
}

View file

@ -430,27 +430,11 @@ int FIWadManager::IdentifyVersion (TArray<FString> &wadfiles, const char *iwad,
}
}
}
#ifdef _WIN32
FString steam_path = I_GetSteamPath();
if (steam_path.IsNotEmpty())
TArray<FString> steam_path = I_GetSteamPath();
for (i = 0; i < steam_path.Size(); ++i)
{
static const char *const steam_dirs[] =
{
"doom 2/base",
"final doom/base",
"heretic shadow of the serpent riders/base",
"hexen/base",
"hexen deathkings of the dark citadel/base",
"ultimate doom/base",
"DOOM 3 BFG Edition/base/wads"
};
steam_path += "/SteamApps/common/";
for (i = 0; i < countof(steam_dirs); ++i)
{
CheckIWAD (steam_path + steam_dirs[i], &wads[0]);
}
CheckIWAD (steam_path[i], &wads[0]);
}
#endif
}
if (iwadparm != NULL && !wads[0].Path.IsEmpty())

View file

@ -2578,6 +2578,7 @@ void D_DoomMain (void)
new (&gameinfo) gameinfo_t; // Reset gameinfo
S_Shutdown(); // free all channels and delete playlist
C_ClearAliases(); // CCMDs won't be reinitialized so these need to be deleted here
DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods
GC::FullGC(); // perform one final garbage collection before deleting the class data
PClass::ClearRuntimeData(); // clear all runtime generated class data

View file

@ -116,6 +116,7 @@ CVAR (Bool, chasedemo, false, 0);
CVAR (Bool, storesavepic, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, longsavemessages, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (String, save_dir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CVAR (Bool, cl_waitforsave, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
EXTERN_CVAR (Float, con_midtime);
//==========================================================================
@ -2147,6 +2148,9 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
filename = G_BuildSaveName ("demosave.zds", -1);
}
if (cl_waitforsave)
I_FreezeTime(true);
insave = true;
G_SnapshotLevel ();
@ -2156,6 +2160,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
{
Printf ("Could not create savegame '%s'\n", filename.GetChars());
insave = false;
I_FreezeTime(false);
return;
}
@ -2232,6 +2237,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
}
insave = false;
I_FreezeTime(false);
}
@ -2636,7 +2642,7 @@ void G_DoPlayDemo (void)
{
FixPathSeperator (defdemoname);
DefaultExtension (defdemoname, ".lmp");
M_ReadFile (defdemoname, &demobuffer);
M_ReadFileMalloc (defdemoname, &demobuffer);
}
demo_p = demobuffer;

View file

@ -60,7 +60,8 @@ bool APowerupGiver::Use (bool pickup)
}
if (BlendColor != 0)
{
power->BlendColor = BlendColor;
if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor;
else power->BlendColor = 0;
}
if (Mode != NAME_None)
{

View file

@ -1123,7 +1123,7 @@ void DBaseStatusBar::DrawCrosshair ()
ST_LoadCrosshair();
// Don't draw the crosshair if there is none
if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL)
if (CrosshairImage == NULL || gamestate == GS_TITLELEVEL || camera->health <= 0)
{
return;
}

View file

@ -137,6 +137,32 @@ int M_ReadFile (char const *name, BYTE **buffer)
return length;
}
//
// M_ReadFile (same as above but use malloc instead of new to allocate the buffer.)
//
int M_ReadFileMalloc (char const *name, BYTE **buffer)
{
int handle, count, length;
struct stat fileinfo;
BYTE *buf;
handle = open (name, O_RDONLY | O_BINARY, 0666);
if (handle == -1)
I_Error ("Couldn't read file %s", name);
if (fstat (handle,&fileinfo) == -1)
I_Error ("Couldn't read file %s", name);
length = fileinfo.st_size;
buf = (BYTE*)M_Malloc(length);
count = read (handle, buf, length);
close (handle);
if (count < length)
I_Error ("Couldn't read file %s", name);
*buffer = buf;
return length;
}
//---------------------------------------------------------------------------
//
// PROC M_FindResponseFile

View file

@ -33,6 +33,7 @@ extern FGameConfigFile *GameConfig;
bool M_WriteFile (char const *name, void *source, int length);
int M_ReadFile (char const *name, BYTE **buffer);
int M_ReadFileMalloc (char const *name, BYTE **buffer);
void M_FindResponseFile (void);
// [RH] M_ScreenShot now accepts a filename parameter.

View file

@ -300,6 +300,7 @@ xx(CallACS)
xx(Sqrt)
xx(CheckClass)
xx(IsPointerEqual)
xx(Pick)
// Various actor names which are used internally
xx(MapSpot)

File diff suppressed because it is too large Load diff

View file

@ -23,11 +23,11 @@
Feedback and Rhythm part calculation information.
forums.submarine.org.uk(carbon14, opl3):
Tremolo and phase generator calculation information.
OPLx decapsulated(Matthew Gambrell and Olli Niemitalo):
OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
OPL2 ROMs.
*/
//version 1.4.2
//version 1.5
#include "opl.h"
#include "muslib.h"
@ -41,74 +41,188 @@ typedef SWORD Bit16s;
typedef BYTE Bit8u;
typedef SBYTE Bit8s;
struct channel {
Bit8u con;
Bit8u chtype;
Bit8u alg;
Bit16u offset;
Bit8u feedback;
Bit16u cha, chb, chc, chd;
Bit16s out;
Bit16u f_number;
Bit8u block;
Bit8u ksv;
float panl;
float panr;
// Channel types
enum {
ch_2op = 0,
ch_4op = 1,
ch_4op2 = 2,
ch_drum = 3
};
struct slot {
Bit32u PG_pos;
Bit32u PG_inc;
Bit16s EG_out;
// Envelope key types
enum {
egk_norm = 0x01,
egk_drum = 0x02
};
//
// logsin table
//
static const Bit16u logsinrom[256] = {
0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365,
0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261,
0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd,
0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166,
0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118,
0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db,
0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9,
0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081,
0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060,
0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045,
0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f,
0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e,
0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011,
0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007,
0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002,
0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
};
//
// exp table
//
static const Bit16u exprom[256] = {
0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a,
0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a,
0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b,
0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be,
0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4,
0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c,
0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167,
0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4,
0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4,
0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227,
0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d,
0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5,
0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302,
0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351,
0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4,
0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa
};
//
// freq mult table multiplied by 2
//
// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15
//
static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 };
//
// ksl table
//
static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 };
static const Bit8u kslshift[4] = { 8, 1, 2, 0 };
//
// LFO vibrato
//
static const Bit8u vib_table[8] = { 3, 1, 0, 1, 3, 1, 0, 1 };
static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 };
//
// envelope generator constants
//
static const Bit8u eg_incstep[3][4][8] = {
{ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } },
{ { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } },
{ { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } }
};
static const Bit8u eg_incdesc[16] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2
};
static const Bit8s eg_incsh[16] = {
0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2
};
//
// address decoding
//
static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
struct opl_chip;
struct opl_slot;
struct opl_channel;
struct opl_slot {
opl_channel *channel;
opl_chip *chip;
Bit16s out;
Bit16s fbmod;
Bit16s *mod;
Bit16s prout[2];
Bit16s eg_rout;
Bit16s eg_out;
Bit8u eg_inc;
Bit8u eg_gen;
Bit8u eg_gennext;
Bit16u EG_mout;
Bit8u EG_ksl;
Bit8u EG_ar;
Bit8u EG_dr;
Bit8u EG_sl;
Bit8u EG_rr;
Bit8u EG_state;
Bit8u EG_type;
Bit16s out;
Bit16s *mod;
Bit16s prevout[2];
Bit16s fbmod;
Bit16u offset;
Bit8u mult;
Bit8u vibrato;
Bit8u tremolo;
Bit8u ksr;
Bit8u EG_tl;
Bit8u ksl;
Bit8u eg_rate;
Bit8u eg_ksl;
Bit8u *trem;
Bit8u reg_vib;
Bit8u reg_type;
Bit8u reg_ksr;
Bit8u reg_mult;
Bit8u reg_ksl;
Bit8u reg_tl;
Bit8u reg_ar;
Bit8u reg_dr;
Bit8u reg_sl;
Bit8u reg_rr;
Bit8u reg_wf;
Bit8u key;
Bit8u waveform;
Bit32u pg_phase;
};
struct opl_channel {
opl_slot *slots[2];
opl_channel *pair;
opl_chip *chip;
Bit16s *out[4];
Bit8u chtype;
Bit16u f_num;
Bit8u block;
Bit8u fb;
Bit8u con;
Bit8u alg;
Bit8u ksv;
Bit16u cha, chb;
float fcha, fchb;
};
struct chip {
Bit8u opl_memory[0x200];
struct opl_chip {
opl_channel channel[18];
opl_slot slot[36];
Bit16u timer;
Bit8u newm;
Bit8u nts;
Bit8u rhythm;
Bit8u dvb;
Bit8u dam;
Bit8u rhy;
Bit8u vibpos;
Bit8u tremval;
Bit8u tremtval;
Bit8u tremdir;
Bit32u noise;
Bit16u vib_pos;
Bit16u timer;
Bit8u trem_inc;
Bit8u trem_tval;
Bit8u trem_dir;
Bit8u trem_val;
channel Channels[18];
slot OPs[36];
Bit16s zm;
Bit16s zeromod;
};
class NukedOPL3 : public OPLEmul {
private:
chip opl3;
opl_chip opl3;
bool FullPan;
public:
void Reset();

View file

@ -7725,13 +7725,6 @@ scriptwait:
AddToConsole (-1, consolecolor);
AddToConsole (-1, work);
AddToConsole (-1, bar);
if (Logfile)
{
fputs (logbar, Logfile);
fputs (work, Logfile);
fputs (logbar, Logfile);
fflush (Logfile);
}
}
}
}

View file

@ -1510,7 +1510,7 @@ FUNC(LS_Thing_Raise)
if (arg0==0)
{
ok = P_Thing_Raise (it);
ok = P_Thing_Raise (it,NULL);
}
else
{
@ -1518,7 +1518,7 @@ FUNC(LS_Thing_Raise)
while ( (target = iterator.Next ()) )
{
ok |= P_Thing_Raise(target);
ok |= P_Thing_Raise(target,NULL);
}
}
return ok;

View file

@ -171,7 +171,7 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog);
int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type);
void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob);
void P_RemoveThing(AActor * actor);
bool P_Thing_Raise(AActor *thing);
bool P_Thing_Raise(AActor *thing, AActor *raiser);
bool P_Thing_CanRaise(AActor *thing);
const PClass *P_GetSpawnableType(int spawnnum);

View file

@ -74,6 +74,69 @@ TArray<line_t *> spechit;
// Temporary holder for thing_sectorlist threads
msecnode_t* sector_list = NULL; // phares 3/16/98
//==========================================================================
//
// GetCoefficientClosestPointInLine24
//
// Formula: (dotProduct(ldv1 - tm, ld) << 24) / dotProduct(ld, ld)
// with: ldv1 = (ld->v1->x, ld->v1->y), tm = (tm.x, tm.y)
// and ld = (ld->dx, ld->dy)
// Returns truncated to range [0, 1 << 24].
//
//==========================================================================
static fixed_t GetCoefficientClosestPointInLine24(line_t *ld, FCheckPosition &tm)
{
// [EP] Use 64 bit integers in order to keep the exact result of the
// multiplication, because in the case the vertexes have both the
// distance coordinates equal to the map limit (32767 units, which is
// 2147418112 in fixed_t notation), the product result would occupy
// 62 bits and the sum of two products would occupy 63 bits
// in the worst case. If instead the vertexes are very close (1 in
// fixed_t notation, which is 1.52587890625e-05 in float notation), the
// product and the sum can be 1 in the worst case, which is very tiny.
SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) +
(SQWORD(tm.y - ld->v1->y)*ld->dy));
// The denominator is always positive. Use this to avoid useless
// calculations.
SQWORD r_den = (SQWORD(ld->dx)*ld->dx + SQWORD(ld->dy)*ld->dy);
if (r_num <= 0) {
// [EP] The numerator is less or equal to zero, hence the closest
// point on the line is the first vertex. Truncate the result to 0.
return 0;
}
if (r_num >= r_den) {
// [EP] The division is greater or equal to 1, hence the closest
// point on the line is the second vertex. Truncate the result to
// 1 << 24.
return (1 << 24);
}
// [EP] Deal with the limited bits. The original formula is:
// r = (r_num << 24) / r_den,
// but r_num might be big enough to make the shift overflow.
// Since the numerator can't be saved in a 128bit integer,
// the denominator must be right shifted. If the denominator is
// less than (1 << 24), there would be a division by zero.
// Thanks to the fact that in this code path the denominator is greater
// than the numerator, it's possible to avoid this bad situation by
// just checking the last 24 bits of the numerator.
if ((r_num >> (63-24)) != 0) {
// [EP] In fact, if the numerator is greater than
// (1 << (63-24)), the denominator must be greater than
// (1 << (63-24)), hence the denominator won't be zero after
// the right shift by 24 places.
return (fixed_t)(r_num/(r_den >> 24));
}
// [EP] Having the last 24 bits all zero allows left shifting
// the numerator by 24 bits without overflow.
return (fixed_t)((r_num << 24)/r_den);
}
//==========================================================================
//
// PIT_FindFloorCeiling
@ -736,19 +799,8 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
else
{ // Find the point on the line closest to the actor's center, and use
// that to calculate openings
// [EP] Use 64 bit integers in order to keep the exact result of the
// multiplication, because in the worst case, which is by the map limit
// (32767 units, which is 2147418112 in fixed_t notation), the result
// would occupy 62 bits (if I consider also the addition with another
// and possible 62 bit value, it's 63 bits).
// This privilege could not be available if the starting data would be
// 64 bit long.
// With this, the division is exact as the 32 bit float counterpart,
// though I don't know why I had to discard the first 24 bits from the
// divisor.
SQWORD r_num = ((SQWORD(tm.x - ld->v1->x)*ld->dx) + (SQWORD(tm.y - ld->v1->y)*ld->dy));
SQWORD r_den = (SQWORD(ld->dx)*ld->dx + SQWORD(ld->dy)*ld->dy) / (1 << 24);
fixed_t r = (fixed_t)(r_num / r_den);
fixed_t r = GetCoefficientClosestPointInLine24(ld, tm);
/* Printf ("%d:%d: %d (%d %d %d %d) (%d %d %d %d)\n", level.time, ld-lines, r,
ld->frontsector->floorplane.a,
ld->frontsector->floorplane.b,
@ -1231,6 +1283,16 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm)
{
P_GiveBody(thing, -damage);
}
if ((thing->flags7 & MF7_THRUREFLECT) && (thing->flags2 & MF2_REFLECTIVE) && (tm.thing->flags & MF_MISSILE))
{
if (tm.thing->flags2 & MF2_SEEKERMISSILE)
{
tm.thing->tracer = tm.thing->target;
}
tm.thing->target = thing;
return true;
}
return false; // don't traverse any more
}
if (thing->flags2 & MF2_PUSHABLE && !(tm.thing->flags2 & MF2_CANNOTPUSH))
@ -1591,7 +1653,7 @@ bool P_TestMobjZ(AActor *actor, bool quick, AActor **pOnmobj)
{ // Don't clip against self
continue;
}
if ((actor->flags & MF_MISSILE) && thing == actor->target)
if ((actor->flags & MF_MISSILE) && (thing == actor->target))
{ // Don't clip against whoever shot the missile.
continue;
}
@ -2931,18 +2993,20 @@ bool P_BounceWall(AActor *mo)
extern FRandom pr_bounce;
bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop)
{
//Don't go through all of this if the actor is reflective and wants things to pass through them.
if (BlockingMobj && ((BlockingMobj->flags2 & MF2_REFLECTIVE) && (BlockingMobj->flags7 & MF7_THRUREFLECT))) return true;
if (mo && BlockingMobj && ((mo->BounceFlags & BOUNCE_AllActors)
|| ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP) || (BlockingMobj->flags5 & MF5_DONTRIP) || ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE))
|| ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER)))
))
|| ((mo->flags & MF_MISSILE) && (!(mo->flags2 & MF2_RIP)
|| (BlockingMobj->flags5 & MF5_DONTRIP)
|| ((mo->flags6 & MF6_NOBOSSRIP) && (BlockingMobj->flags2 & MF2_BOSS))) && (BlockingMobj->flags2 & MF2_REFLECTIVE))
|| ((BlockingMobj->player == NULL) && (!(BlockingMobj->flags3 & MF3_ISMONSTER)))))
{
if (mo->bouncecount > 0 && --mo->bouncecount == 0) return false;
if (!ontop)
{
fixed_t speed;
angle_t angle = R_PointToAngle2(BlockingMobj->x,
BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8);
angle_t angle = R_PointToAngle2(BlockingMobj->x,BlockingMobj->y, mo->x, mo->y) + ANGLE_1*((pr_bounce() % 16) - 8);
speed = P_AproxDistance(mo->velx, mo->vely);
speed = FixedMul(speed, mo->wallbouncefactor); // [GZ] was 0.75, using wallbouncefactor seems more consistent
mo->angle = angle;
@ -5038,6 +5102,8 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
// is normally for projectiles which would have exploded by now anyway...
if (thing->flags6 & MF6_THRUSPECIES && thing->GetSpecies() == intersect->GetSpecies())
continue;
if ((thing->flags & MF_MISSILE) && (intersect->flags2 & MF2_REFLECTIVE) && (intersect->flags7 & MF7_THRUREFLECT))
continue;
if (!(intersect->flags2 & MF2_PASSMOBJ) ||
(!(intersect->flags3 & MF3_ISMONSTER) && intersect->Mass > mymass) ||
(intersect->flags4 & MF4_ACTLIKEBRIDGE)
@ -5046,7 +5112,8 @@ int P_PushUp(AActor *thing, FChangePosition *cpos)
// Can't push bridges or things more massive than ourself
return 2;
}
fixed_t oldz = intersect->z;
fixed_t oldz;
oldz = intersect->z;
P_AdjustFloorCeil(intersect, cpos);
intersect->z = thing->z + thing->height + 1;
if (P_PushUp(intersect, cpos))

View file

@ -1202,6 +1202,9 @@ void P_ExplodeMissile (AActor *mo, line_t *line, AActor *target)
if (target != NULL && ((target->flags & (MF_SHOOTABLE|MF_CORPSE)) || (target->flags6 & MF6_KILLED)) )
{
if (mo->flags7 & MF7_HITTARGET) mo->target = target;
if (mo->flags7 & MF7_HITMASTER) mo->master = target;
if (mo->flags7 & MF7_HITTRACER) mo->tracer = target;
if (target->flags & MF_NOBLOOD) nextstate = mo->FindState(NAME_Crash);
if (nextstate == NULL) nextstate = mo->FindState(NAME_Death, NAME_Extreme);
}
@ -1660,6 +1663,7 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
int steps, step, totalsteps;
fixed_t startx, starty;
fixed_t oldfloorz = mo->floorz;
fixed_t oldz = mo->z;
fixed_t maxmove = (mo->waterlevel < 1) || (mo->flags & MF_MISSILE) ||
(mo->player && mo->player->crouchoffset<-10*FRACUNIT) ? MAXMOVE : MAXMOVE/4;
@ -1949,20 +1953,53 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
}
if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE))
{
angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y);
// Change angle for deflection/reflection
if (mo->AdjustReflectionAngle (BlockingMobj, angle))
bool seeker = (mo->flags2 & MF2_SEEKERMISSILE) ? true : false;
// Don't change the angle if there's THRUREFLECT on the monster.
if (!(BlockingMobj->flags7 & MF7_THRUREFLECT))
{
goto explode;
}
int dir;
angle_t delta;
// Reflect the missile along angle
mo->angle = angle;
angle >>= ANGLETOFINESHIFT;
mo->velx = FixedMul (mo->Speed>>1, finecosine[angle]);
mo->vely = FixedMul (mo->Speed>>1, finesine[angle]);
mo->velz = -mo->velz/2;
if (BlockingMobj->flags7 & MF7_MIRRORREFLECT)
angle = mo->angle + ANG180;
else
angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y);
// Change angle for deflection/reflection
// AIMREFLECT calls precedence so make sure not to bother with adjusting here if declared.
if (!(BlockingMobj->flags7 & MF7_AIMREFLECT) && (mo->AdjustReflectionAngle(BlockingMobj, angle)))
{
goto explode;
}
// Reflect the missile along angle
if (BlockingMobj->flags7 & MF7_AIMREFLECT)
{
dir = P_FaceMobj(mo, mo->target, &delta);
if (dir)
{ // Turn clockwise
mo->angle += delta;
}
else
{ // Turn counter clockwise
mo->angle -= delta;
}
angle = mo->angle >> ANGLETOFINESHIFT;
mo->velx = FixedMul(mo->Speed, finecosine[angle]);
mo->vely = FixedMul(mo->Speed, finesine[angle]);
mo->velz = -mo->velz;
}
else
{
mo->angle = angle;
angle >>= ANGLETOFINESHIFT;
mo->velx = FixedMul(mo->Speed >> 1, finecosine[angle]);
mo->vely = FixedMul(mo->Speed >> 1, finesine[angle]);
mo->velz = -mo->velz / 2;
}
}
if (mo->flags2 & MF2_SEEKERMISSILE)
{
mo->tracer = mo->target;
@ -2893,6 +2930,7 @@ int AActor::SpecialMissileHit (AActor *victim)
bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle)
{
if (flags2 & MF2_DONTREFLECT) return true;
if (thing->flags7 & MF7_THRUREFLECT) return false;
// Change angle for reflection
if (thing->flags4&MF4_SHIELDREFLECT)
@ -3259,7 +3297,7 @@ void AActor::Tick ()
else if (flags & MF_SPECIAL)
{ //Item pickup time
//clock (BotWTG);
bglobal.WhatToGet (players[i].mo, this);
players[i].Bot->WhatToGet (this);
//unclock (BotWTG);
BotWTG++;
}
@ -3267,7 +3305,7 @@ void AActor::Tick ()
{
if (!players[i].Bot->missile && (flags3 & MF3_WARNBOT))
{ //warn for incoming missiles.
if (target != players[i].mo && bglobal.Check_LOS (players[i].mo, this, ANGLE_90))
if (target != players[i].mo && players[i].Bot->Check_LOS (this, ANGLE_90))
players[i].Bot->missile = this;
}
}
@ -4302,12 +4340,15 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
{
spawn_x = p->mo->x;
spawn_y = p->mo->y;
spawn_z = p->mo->z;
spawn_angle = p->mo->angle;
}
else
{
spawn_x = mthing->x;
spawn_y = mthing->y;
// Allow full angular precision but avoid roundoff errors for multiples of 45 degrees.
if (mthing->angle % 45 != 0)
{
@ -4321,14 +4362,14 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
{
spawn_angle += 1 << ANGLETOFINESHIFT;
}
}
if (GetDefaultByType(p->cls)->flags & MF_SPAWNCEILING)
spawn_z = ONCEILINGZ;
else if (GetDefaultByType(p->cls)->flags2 & MF2_SPAWNFLOAT)
spawn_z = FLOATRANDZ;
else
spawn_z = ONFLOORZ;
if (GetDefaultByType(p->cls)->flags & MF_SPAWNCEILING)
spawn_z = ONCEILINGZ;
else if (GetDefaultByType(p->cls)->flags2 & MF2_SPAWNFLOAT)
spawn_z = FLOATRANDZ;
else
spawn_z = ONFLOORZ;
}
mobj = static_cast<APlayerPawn *>
(Spawn (p->cls, spawn_x, spawn_y, spawn_z, NO_REPLACE));
@ -4445,7 +4486,8 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
{
APowerup *invul = static_cast<APowerup*>(p->mo->GiveInventoryType (RUNTIME_CLASS(APowerInvulnerable)));
invul->EffectTics = 3*TICRATE;
invul->BlendColor = 0; // don't mess with the view
invul->BlendColor = 0; // don't mess with the view
invul->ItemFlags |= IF_UNDROPPABLE; // Don't drop this
p->mo->effects |= FX_RESPAWNINVUL; // [RH] special effect
}

View file

@ -412,7 +412,7 @@ void P_RemoveThing(AActor * actor)
}
bool P_Thing_Raise(AActor *thing)
bool P_Thing_Raise(AActor *thing, AActor *raiser)
{
FState * RaiseState = thing->GetRaiseState();
if (RaiseState == NULL)
@ -445,6 +445,12 @@ bool P_Thing_Raise(AActor *thing)
thing->Revive();
if (raiser != NULL)
{
// Let's copy the friendliness of the one who raised it.
thing->CopyFriendliness(raiser, false);
}
thing->SetState (RaiseState);
return true;
}

View file

@ -95,6 +95,7 @@ extern fixed_t globaluclip, globaldclip;
EXTERN_CVAR (Bool, st_scale)
EXTERN_CVAR(Bool, r_shadercolormaps)
EXTERN_CVAR(Int, r_drawfuzz)
EXTERN_CVAR(Bool, r_deathcamera);
//
// Sprite rotation 0 is facing the viewer,
@ -1410,7 +1411,8 @@ void R_DrawPlayerSprites ()
if (!r_drawplayersprites ||
!camera->player ||
(players[consoleplayer].cheats & CF_CHASECAM))
(players[consoleplayer].cheats & CF_CHASECAM) ||
(r_deathcamera && camera->health <= 0))
return;
if(fixedlightlev < 0 && viewsector->e && viewsector->e->XFloor.lightlist.Size()) {

View file

@ -158,6 +158,7 @@ std2:
'random' { RET(TK_Random); }
'random2' { RET(TK_Random2); }
'frandom' { RET(TK_FRandom); }
'pick' { RET(TK_Pick); }
L (L|D)* { RET(TK_Identifier); }

View file

@ -122,4 +122,5 @@ xx(TK_Array, "'array'")
xx(TK_In, "'in'")
xx(TK_SizeOf, "'sizeof'")
xx(TK_AlignOf, "'alignof'")
xx(TK_Pick, "'pick'")
#undef xx

217
src/sdl/i_steam.cpp Normal file
View file

@ -0,0 +1,217 @@
/*
** i_steam.cpp
**
**---------------------------------------------------------------------------
** Copyright 2013 Braden Obrzut
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
**
*/
#include <sys/stat.h>
#include "doomerrors.h"
#include "d_main.h"
#include "zstring.h"
#include "sc_man.h"
static void PSR_FindEndBlock(FScanner &sc)
{
int depth = 1;
do
{
if(sc.CheckToken('}'))
--depth;
else if(sc.CheckToken('{'))
++depth;
else
sc.MustGetAnyToken();
}
while(depth);
}
static void PSR_SkipBlock(FScanner &sc)
{
sc.MustGetToken('{');
PSR_FindEndBlock(sc);
}
static bool PSR_FindAndEnterBlock(FScanner &sc, const char* keyword)
{
// Finds a block with a given keyword and then enter it (opening brace)
// Should be closed with PSR_FindEndBlock
while(sc.GetToken())
{
if(sc.TokenType == '}')
{
sc.UnGet();
return false;
}
sc.TokenMustBe(TK_StringConst);
if(!sc.Compare(keyword))
{
if(!sc.CheckToken(TK_StringConst))
PSR_SkipBlock(sc);
}
else
{
sc.MustGetToken('{');
return true;
}
}
return false;
}
static TArray<FString> PSR_ReadBaseInstalls(FScanner &sc)
{
TArray<FString> result;
// Get a list of possible install directories.
while(sc.GetToken())
{
if(sc.TokenType == '}')
break;
sc.TokenMustBe(TK_StringConst);
FString key(sc.String);
if(key.Left(18).CompareNoCase("BaseInstallFolder_") == 0)
{
sc.MustGetToken(TK_StringConst);
result.Push(FString(sc.String) + "/steamapps/common");
}
else
{
if(sc.CheckToken('{'))
PSR_FindEndBlock(sc);
else
sc.MustGetToken(TK_StringConst);
}
}
return result;
}
static TArray<FString> ParseSteamRegistry(const char* path)
{
TArray<FString> dirs;
// Read registry data
FScanner sc;
sc.OpenFile(path);
sc.SetCMode(true);
// Find the SteamApps listing
if(PSR_FindAndEnterBlock(sc, "InstallConfigStore"))
{
if(PSR_FindAndEnterBlock(sc, "Software"))
{
if(PSR_FindAndEnterBlock(sc, "Valve"))
{
if(PSR_FindAndEnterBlock(sc, "Steam"))
{
dirs = PSR_ReadBaseInstalls(sc);
}
PSR_FindEndBlock(sc);
}
PSR_FindEndBlock(sc);
}
PSR_FindEndBlock(sc);
}
return dirs;
}
static struct SteamAppInfo
{
const char* const BasePath;
const int AppID;
} AppInfo[] =
{
/*{"doom 2/base", 2300},
{"final doom/base", 2290},
{"heretic shadow of the serpent riders/base", 2390},
{"hexen/base", 2360},
{"hexen deathkings of the dark citadel/base", 2370},
{"ultimate doom/base", 2280},
{"DOOM 3 BFG Edition/base/wads", 208200},*/
{"Strife", 317040}
};
TArray<FString> I_GetSteamPath()
{
TArray<FString> result;
TArray<FString> SteamInstallFolders;
// Linux and OS X actually allow the user to install to any location, so
// we need to figure out on an app-by-app basis where the game is installed.
// To do so, we read the virtual registry.
#ifdef __APPLE__
FString OSX_FindApplicationSupport();
FString regPath = OSX_FindApplicationSupport() + "/Steam/config/config.vdf";
try
{
SteamInstallFolders = ParseSteamRegistry(regPath);
}
catch(class CDoomError &error)
{
// If we can't parse for some reason just pretend we can't find anything.
return result;
}
SteamInstallFolders.Push(OSX_FindApplicationSupport() + "/Steam/SteamApps/common");
#else
char* home = getenv("HOME");
if(home != NULL && *home != '\0')
{
FString regPath;
regPath.Format("%s/.local/share/Steam/config/config.vdf", home);
try
{
SteamInstallFolders = ParseSteamRegistry(regPath);
}
catch(class CDoomError &error)
{
// If we can't parse for some reason just pretend we can't find anything.
return result;
}
regPath.Format("%s/.local/share/Steam/SteamApps/common", home);
SteamInstallFolders.Push(regPath);
}
#endif
for(unsigned int i = 0;i < SteamInstallFolders.Size();++i)
{
for(unsigned int app = 0;app < countof(AppInfo);++app)
{
struct stat st;
FString candidate(SteamInstallFolders[i] + "/" + AppInfo[app].BasePath);
if(stat(candidate, &st) == 0 && S_ISDIR(st.st_mode))
result.Push(candidate);
}
}
return result;
}

View file

@ -120,6 +120,10 @@ void I_SetIWADInfo ();
// Pick from multiple IWADs to use
int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad);
// [RH] Checks the registry for Steam's install path, so we can scan its
// directories for IWADs if the user purchased any through Steam.
TArray<FString> I_GetSteamPath();
// The ini could not be saved at exit
bool I_WriteIniFailed ();

View file

@ -2354,18 +2354,33 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTranslucent)
// Fades the actor in
//
//===========================================================================
enum FadeFlags
{
FTF_REMOVE = 1 << 0,
FTF_CLAMP = 1 << 1,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeIn)
{
ACTION_PARAM_START(1);
ACTION_PARAM_FIXED(reduce, 0);
ACTION_PARAM_INT(flags, 1);
if (reduce == 0)
{
reduce = FRACUNIT/10;
reduce = FRACUNIT / 10;
}
self->RenderStyle.Flags &= ~STYLEF_Alpha1;
self->alpha += reduce;
// Should this clamp alpha to 1.0?
if (self->alpha >= (FRACUNIT * 1))
{
if (flags & FTF_CLAMP)
self->alpha = (FRACUNIT * 1);
if (flags & FTF_REMOVE)
self->Destroy();
}
}
//===========================================================================
@ -2379,7 +2394,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut)
{
ACTION_PARAM_START(2);
ACTION_PARAM_FIXED(reduce, 0);
ACTION_PARAM_BOOL(remove, 1);
ACTION_PARAM_INT(flags, 1);
if (reduce == 0)
{
@ -2387,9 +2402,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeOut)
}
self->RenderStyle.Flags &= ~STYLEF_Alpha1;
self->alpha -= reduce;
if (self->alpha <= 0 && remove)
if (self->alpha <= 0)
{
self->Destroy();
if (flags & FTF_CLAMP)
self->alpha = 0;
if (flags & FTF_REMOVE)
self->Destroy();
}
}
@ -2406,7 +2424,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo)
ACTION_PARAM_START(3);
ACTION_PARAM_FIXED(target, 0);
ACTION_PARAM_FIXED(amount, 1);
ACTION_PARAM_BOOL(remove, 2);
ACTION_PARAM_INT(flags, 2);
self->RenderStyle.Flags &= ~STYLEF_Alpha1;
@ -2428,7 +2446,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FadeTo)
self->alpha = target;
}
}
if (self->alpha == target && remove)
if (flags & FTF_CLAMP)
{
if (self->alpha > (FRACUNIT * 1))
self->alpha = (FRACUNIT * 1);
else if (self->alpha < 0)
self->alpha = 0;
}
if (self->alpha == target && (flags & FTF_REMOVE))
{
self->Destroy();
}
@ -3046,37 +3071,41 @@ DEFINE_ACTION_FUNCTION(AActor, A_ClearTarget)
enum CLOF_flags
{
CLOFF_NOAIM_VERT = 0x1,
CLOFF_NOAIM_HORZ = 0x2,
CLOFF_NOAIM_VERT = 0x00000001,
CLOFF_NOAIM_HORZ = 0x00000002,
CLOFF_JUMPENEMY = 0x4,
CLOFF_JUMPFRIEND = 0x8,
CLOFF_JUMPOBJECT = 0x10,
CLOFF_JUMPNONHOSTILE = 0x20,
CLOFF_JUMPENEMY = 0x00000004,
CLOFF_JUMPFRIEND = 0x00000008,
CLOFF_JUMPOBJECT = 0x00000010,
CLOFF_JUMPNONHOSTILE = 0x00000020,
CLOFF_SKIPENEMY = 0x40,
CLOFF_SKIPFRIEND = 0x80,
CLOFF_SKIPOBJECT = 0x100,
CLOFF_SKIPNONHOSTILE = 0x200,
CLOFF_SKIPENEMY = 0x00000040,
CLOFF_SKIPFRIEND = 0x00000080,
CLOFF_SKIPOBJECT = 0x00000100,
CLOFF_SKIPNONHOSTILE = 0x00000200,
CLOFF_MUSTBESHOOTABLE = 0x400,
CLOFF_MUSTBESHOOTABLE = 0x00000400,
CLOFF_SKIPTARGET = 0x800,
CLOFF_ALLOWNULL = 0x1000,
CLOFF_CHECKPARTIAL = 0x2000,
CLOFF_SKIPTARGET = 0x00000800,
CLOFF_ALLOWNULL = 0x00001000,
CLOFF_CHECKPARTIAL = 0x00002000,
CLOFF_MUSTBEGHOST = 0x4000,
CLOFF_IGNOREGHOST = 0x8000,
CLOFF_MUSTBEGHOST = 0x00004000,
CLOFF_IGNOREGHOST = 0x00008000,
CLOFF_MUSTBESOLID = 0x10000,
CLOFF_BEYONDTARGET = 0x20000,
CLOFF_MUSTBESOLID = 0x00010000,
CLOFF_BEYONDTARGET = 0x00020000,
CLOFF_FROMBASE = 0x40000,
CLOFF_MUL_HEIGHT = 0x80000,
CLOFF_MUL_WIDTH = 0x100000,
CLOFF_FROMBASE = 0x00040000,
CLOFF_MUL_HEIGHT = 0x00080000,
CLOFF_MUL_WIDTH = 0x00100000,
CLOFF_JUMP_ON_MISS = 0x200000,
CLOFF_AIM_VERT_NOOFFSET = 0x400000,
CLOFF_JUMP_ON_MISS = 0x00200000,
CLOFF_AIM_VERT_NOOFFSET = 0x00400000,
CLOFF_SETTARGET = 0x00800000,
CLOFF_SETMASTER = 0x01000000,
CLOFF_SETTRACER = 0x02000000,
};
struct LOFData
@ -3316,6 +3345,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckLOF)
{
return;
}
if ((trace.HitType == TRACE_HitActor) && (trace.Actor != NULL) && !(lof_data.BadActor))
{
if (flags & (CLOFF_SETTARGET)) self->target = trace.Actor;
if (flags & (CLOFF_SETMASTER)) self->master = trace.Actor;
if (flags & (CLOFF_SETTRACER)) self->tracer = trace.Actor;
}
ACTION_JUMP(jump);
}
}
@ -3736,11 +3772,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckFlag)
// A_RaiseMaster
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseMaster)
{
ACTION_PARAM_START(1);
ACTION_PARAM_BOOL(copy, 0);
if (self->master != NULL)
{
P_Thing_Raise(self->master);
if (copy)
P_Thing_Raise(self->master, self);
else
P_Thing_Raise(self->master, NULL);
}
}
@ -3749,8 +3791,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseMaster)
// A_RaiseChildren
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseChildren)
{
ACTION_PARAM_START(1);
ACTION_PARAM_BOOL(copy, 0);
TThinkerIterator<AActor> it;
AActor *mo;
@ -3758,7 +3802,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren)
{
if (mo->master == self)
{
P_Thing_Raise(mo);
if (copy)
P_Thing_Raise(mo, self);
else
P_Thing_Raise(mo, NULL);
}
}
}
@ -3768,8 +3815,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseChildren)
// A_RaiseSiblings
//
//===========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings)
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RaiseSiblings)
{
ACTION_PARAM_START(1);
ACTION_PARAM_BOOL(copy, 0);
TThinkerIterator<AActor> it;
AActor *mo;
@ -3779,7 +3828,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_RaiseSiblings)
{
if (mo->master == self->master && mo != self)
{
P_Thing_Raise(mo);
if (copy)
P_Thing_Raise(mo, self);
else
P_Thing_Raise(mo, NULL);
}
}
}

View file

@ -247,6 +247,12 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7),
DEFINE_FLAG(MF7, ALLOWPAIN, AActor, flags7),
DEFINE_FLAG(MF7, CAUSEPAIN, AActor, flags7),
DEFINE_FLAG(MF7, THRUREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, MIRRORREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, AIMREFLECT, AActor, flags7),
DEFINE_FLAG(MF7, HITTARGET, AActor, flags7),
DEFINE_FLAG(MF7, HITMASTER, AActor, flags7),
DEFINE_FLAG(MF7, HITTRACER, AActor, flags7),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),

View file

@ -371,6 +371,37 @@ static FxExpression *ParseExpression0 (FScanner &sc, const PClass *cls)
return new FxRandom(rng, min, max, sc);
}
else if (sc.CheckToken(TK_Pick))
{
FRandom *rng;
TArray<FxExpression*> list;
list.Clear();
int index = 0;
if (sc.CheckToken('['))
{
sc.MustGetToken(TK_Identifier);
rng = FRandom::StaticFindRNG(sc.String);
sc.MustGetToken(']');
}
else
{
rng = &pr_exrandom;
}
sc.MustGetToken('(');
while (!(sc.CheckToken(')')))
{
FxExpression *min = ParseExpressionM(sc, cls);
list.Push(min);
if (sc.CheckToken(')'))
break;
else
sc.MustGetToken(',');
}
return new FxPick(rng, list, sc);
}
else if (sc.CheckToken(TK_FRandom))
{
FRandom *rng;

View file

@ -559,6 +559,27 @@ public:
//
//==========================================================================
class FxPick : public FxExpression
{
protected:
FRandom * rng;
TDeletingArray<FxExpression*> min;
public:
FxPick(FRandom *, TArray<FxExpression*> mi, const FScriptPosition &pos);
~FxPick();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression(AActor *self);
};
//==========================================================================
//
//
//
//==========================================================================
class FxFRandom : public FxRandom
{
public:

View file

@ -1691,6 +1691,73 @@ ExpVal FxRandom::EvalExpression (AActor *self)
return val;
}
//==========================================================================
//
//
//
//==========================================================================
FxPick::FxPick(FRandom * r, TArray<FxExpression*> mi, const FScriptPosition &pos)
: FxExpression(pos)
{
for (unsigned int index = 0; index < mi.Size(); index++)
{
min.Push(new FxIntCast(mi[index]));
}
rng = r;
ValueType = VAL_Int;
}
//==========================================================================
//
//
//
//==========================================================================
FxPick::~FxPick()
{
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxPick::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
for (unsigned int index = 0; index < min.Size(); index++)
{
RESOLVE(min[index], ctx);
ABORT(min[index]);
}
return this;
};
//==========================================================================
//
//
//
//==========================================================================
ExpVal FxPick::EvalExpression(AActor *self)
{
ExpVal val;
val.Type = VAL_Int;
int max = min.Size();
if (max > 0)
{
int select = (*rng)(max);
val.Int = min[select]->EvalExpression(self).GetInt();
}
else
{
val.Int = (*rng)();
}
return val;
}
//==========================================================================
//
//

View file

@ -2050,6 +2050,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
*pBlendColor = MakeSpecialColormap(v);
return;
}
else if (!stricmp(name, "none") && info->Class->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
{
*pBlendColor = MakeSpecialColormap(65535);
return;
}
color = V_GetColor(NULL, name);
}

View file

@ -1524,20 +1524,36 @@ static bool QueryPathKey(HKEY key, const char *keypath, const char *valname, FSt
//
//==========================================================================
FString I_GetSteamPath()
TArray<FString> I_GetSteamPath()
{
TArray<FString> result;
static const char *const steam_dirs[] =
{
"doom 2/base",
"final doom/base",
"heretic shadow of the serpent riders/base",
"hexen/base",
"hexen deathkings of the dark citadel/base",
"ultimate doom/base",
"DOOM 3 BFG Edition/base/wads",
"Strife"
};
FString path;
if (QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path))
if (!QueryPathKey(HKEY_CURRENT_USER, "Software\\Valve\\Steam", "SteamPath", path))
{
return path;
if (!QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path))
return result;
}
if (QueryPathKey(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", "InstallPath", path))
path += "/SteamApps/common/";
for(unsigned int i = 0; i < countof(steam_dirs); ++i)
{
return path;
result.Push(path + steam_dirs[i]);
}
path = "";
return path;
return result;
}
//==========================================================================

View file

@ -142,7 +142,7 @@ void I_SetWndProc();
// [RH] Checks the registry for Steam's install path, so we can scan its
// directories for IWADs if the user purchased any through Steam.
FString I_GetSteamPath();
TArray<FString> I_GetSteamPath();
// Damn Microsoft for doing Get/SetWindowLongPtr half-assed. Instead of
// giving them proper prototypes under Win32, they are just macros for

View file

@ -222,9 +222,9 @@ ACTOR Actor native //: Thinker
action native A_Log(string whattoprint);
action native A_LogInt(int whattoprint);
action native A_SetTranslucent(float alpha, int style = 0);
action native A_FadeIn(float reduce = 0.1);
action native A_FadeOut(float reduce = 0.1, bool remove = true);
action native A_FadeTo(float target, float amount = 0.1, bool remove = false);
action native A_FadeIn(float reduce = 0.1, int flags = 0);
action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true
action native A_FadeTo(float target, float amount = 0.1, int flags = 0);
action native A_SetScale(float scalex, float scaley = 0);
action native A_SetMass(int mass);
action native A_SpawnDebris(class<Actor> spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1);
@ -241,9 +241,9 @@ ACTOR Actor native //: Thinker
action native A_KillMaster(name damagetype = "none", int flags = 0);
action native A_KillChildren(name damagetype = "none", int flags = 0);
action native A_KillSiblings(name damagetype = "none", int flags = 0);
action native A_RaiseMaster();
action native A_RaiseChildren();
action native A_RaiseSiblings();
action native A_RaiseMaster(bool copy = 0);
action native A_RaiseChildren(bool copy = 0);
action native A_RaiseSiblings(bool copy = 0);
action native A_CheckFloor(state label);
action native A_CheckCeiling(state label);
action native A_PlayerSkinCheck(state label);

View file

@ -372,6 +372,10 @@ enum
CLOFF_JUMP_ON_MISS = 0x200000,
CLOFF_AIM_VERT_NOOFFSET = 0x400000,
CLOFF_SETTARGET = 0x800000,
CLOFF_SETMASTER = 0x1000000,
CLOFF_SETTRACER = 0x2000000,
CLOFF_SKIPOBSTACLES = CLOFF_SKIPENEMY|CLOFF_SKIPFRIEND|CLOFF_SKIPOBJECT|CLOFF_SKIPNONHOSTILE,
CLOFF_NOAIM = CLOFF_NOAIM_VERT|CLOFF_NOAIM_HORZ
};
@ -405,6 +409,13 @@ enum
RMVF_EVERYTHING = 1 << 3,
};
// Flags for A_Fade*
enum
{
FTF_REMOVE = 1 << 0,
FTF_CLAMP = 1 << 1,
};
// This is only here to provide one global variable for testing.
native int testglobalvar;

View file

@ -99,7 +99,7 @@ ACTOR CrusaderMissile
Loop
Death:
SMIS A 0 Bright A_SetTranslucent(1,1)
SMIS A 5 Bright A_StopSoundEx("Voice")
SMIS A 5 Bright
SMIS B 5 Bright
SMIS C 4 Bright
SMIS DEFG 2 Bright

View file

@ -85,7 +85,7 @@ ACTOR BishopMissile
Loop
Death:
SMIS A 0 Bright A_SetTranslucent(1,1)
SMIS A 0 Bright A_StopSoundEx("Voice")
SMIS A 0 Bright // State left for savegame compatibility
SMIS A 5 Bright A_Explode(64,64,1,1)
SMIS B 5 Bright
SMIS C 4 Bright

View file

@ -390,7 +390,7 @@ ACTOR MiniMissile
Loop
Death:
SMIS A 0 Bright A_SetTranslucent(1,1)
SMIS A 0 Bright A_StopSoundEx("Voice")
SMIS A 0 Bright // State left for savegame compatibility
SMIS A 5 Bright A_Explode(64,64,1,1)
SMIS B 5 Bright
SMIS C 4 Bright