mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-23 20:43:15 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
4f00aa3957
47 changed files with 1770 additions and 1245 deletions
|
@ -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 )
|
||||
|
|
|
@ -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
|
||||
|
|
10
src/actor.h
10
src/actor.h
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
71
src/b_bot.h
71
src/b_bot.h
|
@ -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__
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
200
src/b_func.cpp
200
src/b_func.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
123
src/b_move.cpp
123
src/b_move.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
284
src/b_think.cpp
284
src/b_think.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
107
src/p_map.cpp
107
src/p_map.cpp
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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
217
src/sdl/i_steam.cpp
Normal 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;
|
||||
}
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue