bots
git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@300 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
+23
-24
@@ -27,10 +27,12 @@ void CACBot::Spawn()
|
||||
m_pMyEnt->eyeheight = 4.25f;
|
||||
m_pMyEnt->aboveeye = 0.7f;
|
||||
m_pMyEnt->radius = 1.1f;
|
||||
m_pMyEnt->primary = m_pMyEnt->nextprimary = rnd(3)+GUN_PISTOL;
|
||||
|
||||
spawnplayer(m_pMyEnt);
|
||||
|
||||
m_pMyEnt->targetyaw = m_pMyEnt->yaw = m_pMyEnt->targetpitch = m_pMyEnt->pitch = 0.0f;
|
||||
m_pMyEnt->primary = m_pMyEnt->nextprimary = GUN_ASSULT;
|
||||
m_pMyEnt->move = 0;
|
||||
m_pMyEnt->enemy = NULL;
|
||||
m_pMyEnt->maxspeed = 16.0f;
|
||||
@@ -40,8 +42,9 @@ void CACBot::Spawn()
|
||||
m_pMyEnt->roll = 0;
|
||||
m_pMyEnt->state = CS_ALIVE;
|
||||
m_pMyEnt->anger = 0;
|
||||
m_pMyEnt->pBot = this;
|
||||
loopi(NUMGUNS) m_pMyEnt->ammo[i] = 0;
|
||||
m_pMyEnt->pBot = this;
|
||||
// loopi(NUMGUNS) m_pMyEnt->ammo[i] = m_pMyEnt->mag[i] = 0;
|
||||
|
||||
/* UNDONE
|
||||
m_pMyEnt->ammo[GUN_FIST] = 1;
|
||||
if(m_noitems)
|
||||
@@ -92,9 +95,9 @@ void CACBot::Spawn()
|
||||
}*/
|
||||
|
||||
m_pMyEnt->ammo[GUN_KNIFE] = 1;
|
||||
m_pMyEnt->ammo[GUN_SEMIPISTOL] = 5;
|
||||
m_pMyEnt->mag[GUN_SEMIPISTOL] = 5;
|
||||
SelectGun(GUN_SEMIPISTOL);
|
||||
m_pMyEnt->ammo[GUN_PISTOL] = 5;
|
||||
m_pMyEnt->mag[GUN_PISTOL] = 5;
|
||||
SelectGun(m_pMyEnt->primary);
|
||||
|
||||
m_eCurrentBotState = STATE_NORMAL;
|
||||
m_iShootDelay = m_iChangeWeaponDelay = 0;
|
||||
@@ -137,7 +140,8 @@ void CACBot::Spawn()
|
||||
void CACBot::BotPain(int damage, dynent *d)
|
||||
{
|
||||
if(m_pMyEnt->state!=CS_ALIVE || editmode || intermission) return;
|
||||
int ad = damage*(m_pMyEnt->armourtype+1)*20/100; // let armour absorb when possible
|
||||
//fixmebot
|
||||
int ad = damage/**(m_pMyEnt->armourtype+1)*20/100*/; // let armour absorb when possible
|
||||
if(ad>m_pMyEnt->armour) ad = m_pMyEnt->armour;
|
||||
m_pMyEnt->armour -= ad;
|
||||
damage -= ad;
|
||||
@@ -242,17 +246,11 @@ void CACBot::PickUp(int n)
|
||||
int ammo = np*2;
|
||||
switch(ents[n].type)
|
||||
{
|
||||
case I_SEMIPISTOL: AddItem(n, m_pMyEnt->ammo[1], ammo); break;
|
||||
case I_AUTOPISTOL: AddItem(n, m_pMyEnt->ammo[2], ammo); break;
|
||||
case I_SHOTGUN: AddItem(n, m_pMyEnt->ammo[3], ammo); break;
|
||||
case I_SNIPER: AddItem(n, m_pMyEnt->ammo[4], ammo); break;
|
||||
case I_SUBGUN: AddItem(n, m_pMyEnt->ammo[5], ammo); break;
|
||||
case I_CARBINE: AddItem(n, m_pMyEnt->ammo[6], ammo); break;
|
||||
case I_SEMIRIFLE: AddItem(n, m_pMyEnt->ammo[7], ammo); break;
|
||||
case I_AUTORIFLE: AddItem(n, m_pMyEnt->ammo[8], ammo); break;
|
||||
case I_GRENADE: AddItem(n, m_pMyEnt->ammo[9], ammo); break;
|
||||
case I_CLIPS: AddItem(n, m_pMyEnt->ammo[GUN_PISTOL], ammo); break;
|
||||
case I_AMMO: AddItem(n, m_pMyEnt->ammo[m_pMyEnt->primary], ammo); break;
|
||||
case I_GRENADE: AddItem(n, m_pMyEnt->ammo[GUN_GRENADE], ammo); break;
|
||||
|
||||
case I_HELMET:
|
||||
/* case I_HELMET:
|
||||
// (100h/100g only absorbs 166 damage)
|
||||
if(m_pMyEnt->armourtype==A_YELLOW && m_pMyEnt->armour>66) break;
|
||||
AddItem(n, m_pMyEnt->armour, 20);
|
||||
@@ -264,9 +262,9 @@ void CACBot::PickUp(int n)
|
||||
|
||||
case OBJ_ITEM:
|
||||
AddItem(n, m_pMyEnt->quadmillis, 60);
|
||||
break;
|
||||
break;*/
|
||||
|
||||
case TRIGGER:
|
||||
/* case TRIGGER:
|
||||
ents[n].spawned = false;
|
||||
triggertime = lastmillis;
|
||||
trigger(ents[n].attr1, ents[n].attr2, false); // needs to go over server for multiplayer
|
||||
@@ -280,8 +278,8 @@ void CACBot::PickUp(int n)
|
||||
m_iCheckEntsDelay = lastmillis + RandomLong(5000, 10000);
|
||||
}
|
||||
|
||||
BotManager.PickNextTrigger();
|
||||
break;
|
||||
BotManager.PickNextTrigger();
|
||||
break;*/
|
||||
};
|
||||
};
|
||||
|
||||
@@ -290,10 +288,11 @@ void CACBot::AddItem(int i, int &v, int spawnsec)
|
||||
if((i>=sents.length()) || (!sents[i].spawned))
|
||||
return;
|
||||
|
||||
if(v>=itemstats[ents[i].type-I_SEMIPISTOL].max) // don't pick up if not needed
|
||||
//fixmebot
|
||||
if(v>=itemstats[ents[i].type-1].max) // don't pick up if not needed
|
||||
return;
|
||||
|
||||
itemstat &is = itemstats[ents[i].type-I_SEMIPISTOL];
|
||||
itemstat &is = itemstats[ents[i].type-1];
|
||||
ents[i].spawned = false;
|
||||
v += is.add;
|
||||
if(v>is.max) v = is.max;
|
||||
@@ -301,7 +300,7 @@ void CACBot::AddItem(int i, int &v, int spawnsec)
|
||||
sents[i].spawned = false;
|
||||
sents[i].spawnsecs = spawnsec;
|
||||
|
||||
addmsg(1, 4, SV_ITEMPICKUP, i, m_classicsp ? 100000 : spawnsec, false);
|
||||
addmsg(1, 3, SV_BOTITEMPICKUP, i, m_classicsp ? 100000 : spawnsec);
|
||||
|
||||
// HACK: Reset ent goal if bot was looking for for this ent
|
||||
if (m_pTargetEnt == &ents[i])
|
||||
@@ -310,7 +309,7 @@ void CACBot::AddItem(int i, int &v, int spawnsec)
|
||||
m_vGoal = g_vecZero;
|
||||
ResetWaypointVars();
|
||||
m_iCheckEntsDelay = lastmillis + RandomLong(5000, 10000);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// AC Bot class end
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
|
||||
// AI Functions
|
||||
virtual bool ChoosePreferredWeapon(void);
|
||||
void Reload(int Gun);
|
||||
virtual entity *SearchForEnts(bool bUseWPs, float flRange=9999.0f,
|
||||
float flMaxHeight=JUMP_HEIGHT);
|
||||
virtual bool HeadToTargetEnt(void);
|
||||
|
||||
+104
-68
@@ -21,39 +21,105 @@ weaponinfo_s WeaponInfoTable[MAX_WEAPONS] =
|
||||
{
|
||||
// KNIFE
|
||||
{ TYPE_MELEE, 0.0f, 3.5f, 0.0f, 5.0f, 1 },
|
||||
// SEMI PISTOL
|
||||
{ TYPE_NORMAL, 5.0f, 12.0f, 0.0f, 50.0f, 4 },
|
||||
// AUTO PISTOL
|
||||
{ TYPE_AUTO, 10.0f, 20.0f, 0.0f, 100.0f, 10 },
|
||||
// PISTOL
|
||||
{ TYPE_NORMAL, 5.0f, 12.0f, 0.0f, 50.0f, 6 },
|
||||
// SHOTGUN
|
||||
{ TYPE_SHOTGUN, 15.0f, 25.0f, 10.0f, 70.0f, 3 },
|
||||
// SNIPER
|
||||
{ TYPE_SNIPER, 12.0f, 25.0f, 0.0f, 100.0f, 4 },
|
||||
{ TYPE_SHOTGUN, 0.0f, 20.0f, 0.0f, 70.0f, 4 },
|
||||
// SUBGUN
|
||||
{ TYPE_AUTO, 12.0f, 25.0f, 0.0f, 100.0f, 4 },
|
||||
|
||||
/* EDIT: Adrian Henke - those are not used yet
|
||||
// CARBINE
|
||||
{ TYPE_AUTO, 12.0f, 25.0f, 0.0f, 100.0f, 4 },
|
||||
// SEMI RIFLE
|
||||
{ TYPE_SNIPER, 12.0f, 25.0f, 0.0f, 100.0f, 4 },
|
||||
// AUTO RIFLE
|
||||
{ TYPE_AUTO, 12.0f, 25.0f, 0.0f, 100.0f, 4 },
|
||||
*/
|
||||
|
||||
{ TYPE_AUTO, 12.0f, 25.0f, 0.0f, 100.0f, 15 },
|
||||
// SNIPER
|
||||
{ TYPE_SNIPER, 15.0f, 25.0f, 0.0f, 100.0f, 3 },
|
||||
// ASSAULT
|
||||
{ TYPE_AUTO, 12.0f, 25.0f, 0.0f, 100.0f, 10 },
|
||||
// GRENADE
|
||||
{ TYPE_GRENADE, 12.0f, 25.0f, 0.0f, 100.0f, 4 }
|
||||
{ TYPE_GRENADE, 12.0f, 25.0f, 0.0f, 50.0f, 1 }
|
||||
};
|
||||
|
||||
// Code of CACBot - Start
|
||||
|
||||
bool CACBot::ChoosePreferredWeapon()
|
||||
{
|
||||
if (CBot::ChoosePreferredWeapon())
|
||||
return true;
|
||||
else
|
||||
return SelectGun(GUN_KNIFE);
|
||||
}
|
||||
printf("chose weapon\n");
|
||||
TMultiChoice<int> WeaponChoices;
|
||||
short sWeaponScore;
|
||||
float flDist = GetDistance(m_pMyEnt->enemy->o);
|
||||
|
||||
if ((m_iChangeWeaponDelay > lastmillis) && (m_pMyEnt->ammo[m_pMyEnt->gunselect]))
|
||||
{
|
||||
if ((WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType != TYPE_MELEE) || (flDist <= 3.5f))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Choose a weapon
|
||||
for(int i=0;i<MAX_WEAPONS;i++)
|
||||
{
|
||||
// If no ammo for this weapon, skip it
|
||||
if (m_pMyEnt->ammo[i] == 0) continue;
|
||||
|
||||
sWeaponScore = 5; // Minimal score for a weapon
|
||||
|
||||
if ((flDist >= WeaponInfoTable[i].flMinDesiredDistance) &&
|
||||
(flDist <= WeaponInfoTable[i].flMaxDesiredDistance))
|
||||
{
|
||||
// In desired range for this weapon
|
||||
sWeaponScore += 5; // Increase score much
|
||||
}
|
||||
else if ((flDist < WeaponInfoTable[i].flMinFireDistance) ||
|
||||
(flDist > WeaponInfoTable[i].flMaxFireDistance))
|
||||
continue; // Wrong distance for this weapon
|
||||
|
||||
// The ideal distance would be between the Min and Max desired distance.
|
||||
// Score on the difference of the avarage of the Min and Max desired distance.
|
||||
float flAvarage = (WeaponInfoTable[i].flMinDesiredDistance +
|
||||
WeaponInfoTable[i].flMaxDesiredDistance) / 2.0f;
|
||||
float flIdealDiff = fabs(flDist - flAvarage);
|
||||
|
||||
if (flIdealDiff < 0.5f) // Close to ideal distance
|
||||
sWeaponScore += 4;
|
||||
else if (flIdealDiff <= 1.0f)
|
||||
sWeaponScore += 2;
|
||||
|
||||
// Now rate the weapon on available ammo...
|
||||
if (WeaponInfoTable[i].sMinDesiredAmmo > 0)
|
||||
{
|
||||
// Calculate how much percent of the min desired ammo the bot has
|
||||
float flDesiredPercent = (float(m_pMyEnt->mag[i]) /
|
||||
float(WeaponInfoTable[i].sMinDesiredAmmo)) *
|
||||
100.0f;
|
||||
|
||||
if(flDesiredPercent >= 175.0f)
|
||||
sWeaponScore += 4;
|
||||
else if(flDesiredPercent >= 100.0f)
|
||||
sWeaponScore += 3;
|
||||
}
|
||||
|
||||
WeaponChoices.Insert(i, sWeaponScore);
|
||||
}
|
||||
|
||||
int WeaponSelect;
|
||||
if (WeaponChoices.GetSelection(WeaponSelect))
|
||||
{
|
||||
m_iChangeWeaponDelay = lastmillis + RandomLong(2000, 8000);
|
||||
m_bShootAtFeet = ((WeaponInfoTable[WeaponSelect].eWeaponType==TYPE_ROCKET) &&
|
||||
(RandomLong(1, 100) <=
|
||||
m_pBotSkill->sShootAtFeetWithRLPercent));
|
||||
if(SelectGun(WeaponSelect))
|
||||
{
|
||||
if(m_pMyEnt->mag[WeaponSelect]==0) reload(m_pMyEnt); // fixme, more intelligent reload
|
||||
printf("gun selected %i\n", WeaponSelect);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
};
|
||||
|
||||
void CACBot::Reload(int Gun)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
entity *CACBot::SearchForEnts(bool bUseWPs, float flRange, float flMaxHeight)
|
||||
{
|
||||
@@ -86,56 +152,26 @@ entity *CACBot::SearchForEnts(bool bUseWPs, float flRange, float flMaxHeight)
|
||||
if (OUTBORD(e.x, e.y)) continue;
|
||||
|
||||
bool bInteresting = false;
|
||||
short sAmmo = 0, sMaxAmmo = itemstats[e.type-I_SEMIPISTOL].max;
|
||||
|
||||
short sAmmo = 0, sMaxAmmo = 0;
|
||||
//fixmebot
|
||||
switch(e.type)
|
||||
{
|
||||
case I_SEMIPISTOL:
|
||||
bInteresting = (m_pMyEnt->ammo[1]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[1];
|
||||
case I_CLIPS:
|
||||
sMaxAmmo = itemstats[GUN_PISTOL-1].max;
|
||||
bInteresting = (m_pMyEnt->ammo[GUN_PISTOL]<sMaxAmmo);
|
||||
sAmmo = m_pMyEnt->ammo[GUN_PISTOL];
|
||||
break;
|
||||
case I_AUTOPISTOL:
|
||||
bInteresting = (m_pMyEnt->ammo[2]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[2];
|
||||
case I_AMMO:
|
||||
sMaxAmmo = itemstats[m_pMyEnt->primary-1].max;
|
||||
bInteresting = (m_pMyEnt->ammo[m_pMyEnt->primary]<sMaxAmmo);
|
||||
sAmmo = m_pMyEnt->ammo[m_pMyEnt->primary];
|
||||
break;
|
||||
case I_SHOTGUN:
|
||||
bInteresting = (m_pMyEnt->ammo[3]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[3];
|
||||
break;
|
||||
case I_SNIPER:
|
||||
bInteresting = (m_pMyEnt->ammo[4]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[4];
|
||||
break;
|
||||
case I_SUBGUN:
|
||||
bInteresting = (m_pMyEnt->ammo[5]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[4];
|
||||
break;
|
||||
case I_CARBINE:
|
||||
bInteresting = (m_pMyEnt->ammo[6]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[4];
|
||||
break;
|
||||
case I_SEMIRIFLE:
|
||||
bInteresting = (m_pMyEnt->ammo[7]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[4];
|
||||
break;
|
||||
case I_AUTORIFLE:
|
||||
bInteresting = (m_pMyEnt->ammo[8]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[4];
|
||||
break;
|
||||
case I_GRENADE:
|
||||
bInteresting = (m_pMyEnt->ammo[9]<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->ammo[4];
|
||||
break;
|
||||
case I_HELMET:
|
||||
bInteresting = ((m_pMyEnt->armour<itemstats[e.type-I_SEMIPISTOL].max) &&
|
||||
(m_pMyEnt->armourtype!=A_YELLOW || m_pMyEnt->armour<=66));
|
||||
sAmmo = m_pMyEnt->armour;
|
||||
sMaxAmmo = itemstats[GUN_GRENADE-1].max;
|
||||
bInteresting = (m_pMyEnt->ammo[GUN_GRENADE]<sMaxAmmo);
|
||||
sAmmo = m_pMyEnt->ammo[GUN_GRENADE];
|
||||
break;
|
||||
case I_ARMOUR:
|
||||
bInteresting = (m_pMyEnt->armour<itemstats[e.type-I_SEMIPISTOL].max);
|
||||
sAmmo = m_pMyEnt->armour;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (!bInteresting)
|
||||
continue; // Not an interesting item, skip
|
||||
|
||||
@@ -376,9 +376,7 @@ bool CBot::SelectGun(int Gun)
|
||||
if (m_pMyEnt->ammo[Gun])
|
||||
{
|
||||
//temporary doc out argh
|
||||
//if (m_pMyEnt->gunselect != Gun)
|
||||
// botplaysound(S_WEAPLOAD, m_pMyEnt);
|
||||
|
||||
/* if (m_pMyEnt->gunselect != Gun) botplaysound(S_WEAPLOAD, m_pMyEnt); */
|
||||
m_pMyEnt->gunselect = Gun;
|
||||
return true;
|
||||
}
|
||||
|
||||
+11
-7
@@ -86,6 +86,10 @@ inline void debugbeam(vec &s, vec &e) { /*if (!dedserv) particle_trail(1, 500, s
|
||||
#define DOWN (1<<6)
|
||||
#define DIR_NONE 0
|
||||
|
||||
//fixmebot
|
||||
#define m_sp 1000
|
||||
#define m_classicsp 1000
|
||||
|
||||
enum EBotCommands // For voting of bot commands
|
||||
{
|
||||
COMMAND_ADDBOT=0,
|
||||
@@ -146,7 +150,7 @@ enum ECurrentBotState
|
||||
STATE_HUNT, // Bot is hunting an enemy
|
||||
STATE_ENT, // Bot is heading to an entity
|
||||
STATE_SP, // Bot is doing sp specific stuff
|
||||
STATE_NORMAL // Bot is doing normal navaigation
|
||||
STATE_NORMAL // Bot is doing normal navigation
|
||||
};
|
||||
|
||||
struct unreachable_ent_s
|
||||
@@ -233,10 +237,10 @@ public:
|
||||
void AimToIdeal(void);
|
||||
float ChangeAngle(float speed, float ideal, float current);
|
||||
bool SelectGun(int Gun);
|
||||
virtual void CheckItemPickup(void) = NULL;
|
||||
virtual void PickUp(int n) = NULL;
|
||||
virtual void AddItem(int i, int &v, int spawnsec) = NULL;
|
||||
virtual void BotPain(int damage, dynent *d) = NULL;
|
||||
virtual void CheckItemPickup(void) = 0;
|
||||
virtual void PickUp(int n) = 0;
|
||||
virtual void AddItem(int i, int &v, int spawnsec) = 0;
|
||||
virtual void BotPain(int damage, dynent *d) = 0;
|
||||
void SendBotInfo(void);
|
||||
float GetDistance(const vec &o);
|
||||
float GetDistance(const vec &v1, const vec &v2);
|
||||
@@ -275,10 +279,10 @@ public:
|
||||
virtual bool ChoosePreferredWeapon(void);
|
||||
virtual entity *SearchForEnts(bool bUseWPs, float flRange=9999.0f,
|
||||
float flMaxHeight=JUMP_HEIGHT) = NULL;
|
||||
virtual bool HeadToTargetEnt(void) = NULL;
|
||||
virtual bool HeadToTargetEnt(void) = 0;
|
||||
bool CheckItems(void);
|
||||
bool InUnreachableList(entity *e);
|
||||
virtual bool DoSPStuff(void) = NULL;
|
||||
virtual bool DoSPStuff(void) = 0;
|
||||
vec GetEnemyPos(dynent *d);
|
||||
bool AStar(void);
|
||||
float AStarCost(waypoint_s *pWP1, waypoint_s *pWP2);
|
||||
|
||||
@@ -919,7 +919,7 @@ void CBot::ShootEnemy()
|
||||
// Add shoot delay
|
||||
m_iShootDelay = lastmillis + GetShootDelay();
|
||||
}
|
||||
ChoosePreferredWeapon();
|
||||
ChoosePreferredWeapon();
|
||||
}
|
||||
#ifndef RELEASE_BUILD
|
||||
else
|
||||
@@ -2190,9 +2190,10 @@ void CBot::HearSound(int n, vec *o)
|
||||
if (m_pMyEnt->enemy) return;
|
||||
|
||||
// Is the sound not interesting?
|
||||
if ((n==S_DIE1) || (n==S_DIE2) || (n==S_DEATHR) || (n==S_DEATHE) || (n==S_DEATHS) ||
|
||||
//fixmebot
|
||||
/* if ((n==S_DIE1) || (n==S_DIE2) || (n==S_DEATHR) || (n==S_DEATHE) || (n==S_DEATHS) ||
|
||||
(n==S_DEATHB) || (n==S_DEATHH) || (n==S_DEATHD) || (n==S_PIGGR2))
|
||||
return;
|
||||
return;*/
|
||||
|
||||
int soundvol = m_pBotSkill->iMaxHearVolume -
|
||||
(int)(GetDistance(*o)*3*m_pBotSkill->iMaxHearVolume/255);
|
||||
|
||||
@@ -471,7 +471,7 @@ private:
|
||||
|
||||
|
||||
// ==================================================================
|
||||
// Code of TMutiChoice - Begin
|
||||
// Code of TMultiChoice - Begin
|
||||
// ==================================================================
|
||||
|
||||
template <class C> class TMultiChoice
|
||||
|
||||
@@ -970,15 +970,6 @@ dynent *CBotManager::CreateBot(const char *team, const char *skill, const char *
|
||||
|
||||
m->pBot->Spawn();
|
||||
|
||||
// edit: driAn
|
||||
loopi(3)
|
||||
{
|
||||
m->mdl[i] = i;
|
||||
m->animstate[i].frm = 0;
|
||||
m->animstate[i].anim = 0;
|
||||
m->animstate[i].lastTime = 0;
|
||||
};
|
||||
|
||||
bots.add(m);
|
||||
|
||||
return m;
|
||||
|
||||
+21
-27
@@ -41,27 +41,27 @@ void throttle()
|
||||
};
|
||||
|
||||
void ctf_team(char *name)
|
||||
{
|
||||
bool isvalidteam = strcmp(name, "RVSF") == 0 || strcmp(name, "CLA") == 0;
|
||||
if(strcmp(name, player1->team) == 0 && isvalidteam) return;
|
||||
c2sinit = false;
|
||||
ctf_death();
|
||||
if(isvalidteam) strcpy(player1->team, name);
|
||||
else strcpy(player1->team, rb_team_string(rnd(2)));
|
||||
player1->lastaction = lastmillis;
|
||||
{
|
||||
bool isvalidteam = strcmp(name, "RVSF") == 0 || strcmp(name, "CLA") == 0;
|
||||
if(strcmp(name, player1->team) == 0 && isvalidteam) return;
|
||||
c2sinit = false;
|
||||
ctf_death();
|
||||
if(isvalidteam) strcpy(player1->team, name);
|
||||
else strcpy(player1->team, rb_team_string(rnd(2)));
|
||||
player1->lastaction = lastmillis;
|
||||
player1->state = CS_DEAD;
|
||||
};
|
||||
|
||||
void newname(char *name) { c2sinit = false; strn0cpy(player1->name, name, 16); };
|
||||
void newskin(int skin) { c2sinit=false; player1->nextskin = max(0, min(skin, (rb_team_int(player1->team)==TEAM_CLA ? 3 : 5))); };
|
||||
void newteam(char *name)
|
||||
{
|
||||
if(m_teammode) ctf_team(name);
|
||||
else { strn0cpy(player1->team, name, 5); c2sinit=false; };
|
||||
void newname(char *name) { c2sinit = false; strn0cpy(player1->name, name, 16); };
|
||||
void newskin(int skin) { player1->nextskin = max(0, min(skin, (rb_team_int(player1->team)==TEAM_CLA ? 3 : 5))); };
|
||||
void newteam(char *name)
|
||||
{
|
||||
if(m_teammode) ctf_team(name);
|
||||
else { strn0cpy(player1->team, name, 5); c2sinit=false; };
|
||||
};
|
||||
|
||||
COMMANDN(team, newteam, ARG_1STR);
|
||||
COMMANDN(name, newname, ARG_1STR);
|
||||
COMMANDN(name, newname, ARG_1STR);
|
||||
COMMANDN(skin, newskin, ARG_1INT);
|
||||
|
||||
void connects(char *servername)
|
||||
@@ -262,7 +262,7 @@ void c2sinfo(dynent *d) // send update to the server
|
||||
c2sinit = true;
|
||||
putint(p, SV_INITC2S);
|
||||
sendstring(player1->name, p);
|
||||
sendstring(player1->team, p);
|
||||
sendstring(player1->team, p);
|
||||
putint(p, player1->skin);
|
||||
putint(p, player1->lifesequence);
|
||||
};
|
||||
@@ -326,14 +326,8 @@ void gets2c() // get updates from the server
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
void lsinfo()
|
||||
{
|
||||
printf("lifesequences:\nyou\t%i\n", player1->lifesequence);
|
||||
loopv(players)
|
||||
{
|
||||
dynent *d = players[i];
|
||||
if(!d) continue;
|
||||
printf("%s\t%i\n", d->name, d->lifesequence);
|
||||
}
|
||||
}; COMMAND(lsinfo, ARG_NONE);
|
||||
|
||||
void lsinfo()
|
||||
{
|
||||
printf("%i %i\n", player1->ammo[player1->gunselect], player1->mag[player1->gunselect]);
|
||||
}; COMMAND(lsinfo, ARG_NONE);
|
||||
|
||||
+14
-10
@@ -45,13 +45,13 @@ void renderclient(dynent *d, bool team, char *mdlname, bool vwep, float scale)
|
||||
rendermodel(mdlname, frame[n], range[n], 0, 1.5f, d->o.x, mz, d->o.y, d->yaw+90, d->pitch/2, team, scale, speed, 0, basetime);
|
||||
};
|
||||
|
||||
extern int democlientnum;
|
||||
|
||||
void renderplayer(dynent *d)
|
||||
{
|
||||
if(!d) return;
|
||||
|
||||
int team = rb_team_int(d->team);
|
||||
extern int democlientnum;
|
||||
|
||||
void renderplayer(dynent *d)
|
||||
{
|
||||
if(!d) return;
|
||||
|
||||
int team = rb_team_int(d->team);
|
||||
sprintf_sd(mdl)("playermodels/%s/0%i", team==TEAM_CLA ? "terrorist" : "counterterrorist", 1 + max(0, min(d->skin, (team==TEAM_CLA ? 3 : 5))));
|
||||
renderclient(d, isteam(player1->team, d->team), mdl, false, 1.6f);
|
||||
|
||||
@@ -59,7 +59,7 @@ void renderplayer(dynent *d)
|
||||
{
|
||||
sprintf_sd(vwep)("weapons/%s/world", hudgunnames[d->gunselect]);
|
||||
renderclient(d, isteam(player1->team, d->team), vwep, true, 1.6f);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
void renderclients()
|
||||
@@ -73,9 +73,9 @@ void renderclients()
|
||||
d->gunselect = player1->gunselect;
|
||||
d->moving = true;
|
||||
d->health != 1 ? d->state=CS_ALIVE : d->state=CS_DEAD;
|
||||
};
|
||||
};
|
||||
renderplayer(d);
|
||||
};
|
||||
};
|
||||
|
||||
if(player1->state==CS_DEAD) renderplayer(player1);
|
||||
};
|
||||
@@ -144,6 +144,10 @@ void renderscores()
|
||||
scorelines.setsize(0);
|
||||
if(!demoplayback) renderscore(player1);
|
||||
loopv(players) if(players[i]) renderscore(players[i]);
|
||||
|
||||
// Added by Rick: Render Score for bots
|
||||
BotManager.RenderBotScore();
|
||||
|
||||
sortmenu(menu, 0, scorelines.length());
|
||||
if(m_teammode)
|
||||
{
|
||||
|
||||
+679
-626
File diff suppressed because it is too large
Load Diff
+246
-12
@@ -24,6 +24,29 @@ void changemap(char *name) // request map change, server ma
|
||||
strcpy_s(toservermap, name);
|
||||
};
|
||||
|
||||
// Added by Rick
|
||||
void botcommand(uchar *&p, char *text)
|
||||
{
|
||||
int type = getint(p);
|
||||
switch(EBotCommands(type))
|
||||
{
|
||||
case COMMAND_ADDBOT:
|
||||
getint(p);
|
||||
getint(p);
|
||||
sgetstr();
|
||||
sgetstr();
|
||||
break;
|
||||
case COMMAND_KICKBOT:
|
||||
if (getint(p)==1) // Kick a specific bot
|
||||
sgetstr();
|
||||
break;
|
||||
case COMMAND_BOTSKILL:
|
||||
getint(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// End add
|
||||
|
||||
// update the position of other clients in the game in our world
|
||||
// don't care if he's in the scenery or other players,
|
||||
// just don't overlap with our client
|
||||
@@ -60,6 +83,7 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
int cn = -1, type;
|
||||
dynent *d = NULL;
|
||||
bool mapchanged = false;
|
||||
bool c2si = false, killedbybot=false;
|
||||
|
||||
while(p<end) switch(type = getint(p))
|
||||
{
|
||||
@@ -95,6 +119,7 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
cn = getint(p);
|
||||
d = getclient(cn);
|
||||
if(!d) return;
|
||||
c2si = false;
|
||||
d->o.x = getint(p)/DMF;
|
||||
d->o.y = getint(p)/DMF;
|
||||
d->o.z = getint(p)/DMF;
|
||||
@@ -161,13 +186,19 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
c2sinit = false; // send new players my info again
|
||||
conoutf("connected: %s", (int)&text);
|
||||
gun_changed = true;
|
||||
// Added by Rick: If we are the host("the bot owner"), tell the bots
|
||||
// to update their stats
|
||||
if (ishost())
|
||||
BotManager.LetBotsUpdateStats();
|
||||
// End add by Rick
|
||||
};
|
||||
strcpy_s(d->name, text);
|
||||
sgetstr();
|
||||
strcpy_s(d->team, text);
|
||||
strcpy_s(d->team, text);
|
||||
d->skin = getint(p);
|
||||
d->lifesequence = getint(p);
|
||||
printf("SV_INIT2C\tskin:%i\tlifes:%i\n", d->skin, d->lifesequence);
|
||||
d->lifesequence = getint(p);
|
||||
c2si = true;
|
||||
printf("SV_INITC2S\n");
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -203,16 +234,36 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
if(target==clientnum) { if(ls==player1->lifesequence) selfdamage(damage, cn, d); else printf("wrong lifesequence\n"); }
|
||||
else playsound(S_PAIN1+rnd(5), &getclient(target)->o);
|
||||
break;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
case SV_BOT2CLIENTDMG:
|
||||
{
|
||||
|
||||
int target = getint(p);
|
||||
int damage = getint(p);
|
||||
int ls = getint(p);
|
||||
int damager = getint(p);
|
||||
|
||||
if(target==clientnum)
|
||||
{
|
||||
dynent *a = getbot(damager);
|
||||
if(ls==player1->lifesequence)
|
||||
selfdamage(damage, cn, a);
|
||||
}
|
||||
else playsound(S_PAIN1+rnd(5), &getclient(target)->o);
|
||||
break;
|
||||
}
|
||||
|
||||
case SV_DIEDBYBOT:
|
||||
killedbybot = true;
|
||||
case SV_DIED:
|
||||
{
|
||||
int actor = getint(p);
|
||||
if(actor==cn)
|
||||
if(actor==cn && !killedbybot)
|
||||
{
|
||||
conoutf("%s suicided", (int)d->name);
|
||||
}
|
||||
else if(actor==clientnum)
|
||||
else if(actor==clientnum && !killedbybot)
|
||||
{
|
||||
int frags;
|
||||
if(isteam(player1->team, d->team))
|
||||
@@ -229,7 +280,7 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
}
|
||||
else
|
||||
{
|
||||
dynent *a = getclient(actor);
|
||||
dynent *a = killedbybot ? getbot(actor) : getclient(actor);
|
||||
if(a)
|
||||
{
|
||||
if(isteam(a->team, d->name))
|
||||
@@ -243,15 +294,19 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
};
|
||||
};
|
||||
playsound(S_DIE1+rnd(2), &d->o);
|
||||
d->lifesequence++; printf("SV_DIED\n");
|
||||
if(!c2si) d->lifesequence++;
|
||||
killedbybot = false;
|
||||
break;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
case SV_FRAGS:
|
||||
players[cn]->frags = getint(p);
|
||||
break;
|
||||
|
||||
case SV_ITEMPICKUP:
|
||||
case SV_ITEMPICKUP:
|
||||
case SV_BOTITEMPICKUP:
|
||||
setspawn(getint(p), false);
|
||||
getint(p);
|
||||
break;
|
||||
@@ -430,7 +485,186 @@ void localservertoclient(uchar *buf, int len) // processes any updates from th
|
||||
for(int n = getint(p); n; n--) getint(p);
|
||||
break;
|
||||
};
|
||||
*/
|
||||
*/
|
||||
// Added by Rick: Bot specific messages
|
||||
case SV_BOTSOUND:
|
||||
{
|
||||
int Sound = getint(p);
|
||||
dynent *pBot = getbot(getint(p));
|
||||
|
||||
if (pBot)
|
||||
playsound(Sound, &pBot->o);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SV_ADDBOT: // Bot joined the game
|
||||
{
|
||||
dynent *b = getbot(getint(p));
|
||||
if (!b) break;
|
||||
|
||||
sgetstr();
|
||||
if(b->name[0]) // already connected
|
||||
{
|
||||
if(strcmp(b->name, text))
|
||||
conoutf("%s is now known as %s", (int)b->name, (int)&text);
|
||||
}
|
||||
else // new client
|
||||
{
|
||||
//c2sinit = false; // send new players my info again
|
||||
conoutf("connected: %s", (int)&text);
|
||||
};
|
||||
strcpy_s(b->name, text);
|
||||
sgetstr();
|
||||
strcpy_s(b->team, text);
|
||||
b->lifesequence = getint(p);
|
||||
b->bIsBot = true;
|
||||
b->pBot = NULL;
|
||||
break;
|
||||
};
|
||||
|
||||
case SV_BOTDIS:
|
||||
{
|
||||
int n = getint(p);
|
||||
dynent *b = getbot(n);
|
||||
|
||||
if (!b)
|
||||
break;
|
||||
|
||||
conoutf("bot %s disconnected", (int)(b->name[0] ? b->name : "[incompatible client]"));
|
||||
delete b->pBot;
|
||||
zapdynent(bots[n]);
|
||||
bots.remove(n);
|
||||
break;
|
||||
}
|
||||
|
||||
case SV_CLIENT2BOTDMG:
|
||||
case SV_BOT2BOTDMG:
|
||||
{
|
||||
int target = getint(p);
|
||||
int damage = getint(p);
|
||||
int damager = getint(p);
|
||||
dynent *b = getbot(target);
|
||||
|
||||
dynent *a;
|
||||
if (damager == -1)
|
||||
{
|
||||
// HACK! if the local client who sended the message is the damager, its -1
|
||||
a = d;
|
||||
}
|
||||
else if (type == SV_CLIENT2BOTDMG)
|
||||
{
|
||||
if (damager == clientnum) a = player1;
|
||||
else a = getclient(damager);
|
||||
}
|
||||
else
|
||||
a = getbot(damager);
|
||||
|
||||
if (b && a)
|
||||
{
|
||||
// Do we know the bot info? if so we are the host...
|
||||
if (b->pBot) b->pBot->BotPain(damage, a);
|
||||
playsound(S_PAIN1+rnd(5), &b->o);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SV_BOTDIED:
|
||||
{
|
||||
int b = getint(p);
|
||||
int killer = getint(p);
|
||||
bool KilledByABot = getint(p);
|
||||
dynent *bot = getbot(b);
|
||||
|
||||
if((b==killer) && KilledByABot)
|
||||
{
|
||||
conoutf("%s suicided", (int)bot->name);
|
||||
}
|
||||
else if((killer==clientnum) && !KilledByABot)
|
||||
{
|
||||
int frags;
|
||||
if(isteam(player1->team, bot->team))
|
||||
{
|
||||
frags = -1;
|
||||
conoutf("you fragged a teammate (%s)", (int)bot->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
frags = 1;
|
||||
conoutf("you fragged %s", (int)bot->name);
|
||||
};
|
||||
addmsg(1, 2, SV_FRAGS, player1->frags += frags);
|
||||
}
|
||||
else
|
||||
{
|
||||
dynent *k;
|
||||
if (KilledByABot)
|
||||
k = getbot(killer);
|
||||
else if (killer == -1)
|
||||
// if killer = -1, 'a player1' sended the message(hack)
|
||||
k = d;
|
||||
else
|
||||
k = getclient(killer);
|
||||
|
||||
if(bot && k)
|
||||
{
|
||||
if(isteam(bot->team, k->name))
|
||||
{
|
||||
conoutf("%s fragged his teammate (%s)", (int)bot->name, (int)k->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
conoutf("%s fragged %s", (int)bot->name, (int)k->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playsound(S_DIE1+rnd(2), &bot->o);
|
||||
bot->lifesequence++;
|
||||
break;
|
||||
};
|
||||
|
||||
case SV_BOTFRAGS:
|
||||
{
|
||||
dynent *b = getbot(getint(p));
|
||||
if (b) b->frags = getint(p);
|
||||
break;
|
||||
}
|
||||
|
||||
case SV_BOTUPDATE:
|
||||
{
|
||||
int n = getint(p);
|
||||
dynent *b = getbot(n);
|
||||
if(!b) return;
|
||||
b->o.x = getint(p)/DMF;
|
||||
b->o.y = getint(p)/DMF;
|
||||
b->o.z = getint(p)/DMF;
|
||||
b->yaw = getint(p)/DAF;
|
||||
b->pitch = getint(p)/DAF;
|
||||
b->roll = getint(p)/DAF;
|
||||
b->vel.x = getint(p)/DVF;
|
||||
b->vel.y = getint(p)/DVF;
|
||||
b->vel.z = getint(p)/DVF;
|
||||
int f = getint(p);
|
||||
b->strafe = (f&3)==3 ? -1 : f&3;
|
||||
f >>= 2;
|
||||
b->move = (f&3)==3 ? -1 : f&3;
|
||||
b->onfloor = (f>>2)&1;
|
||||
int state = f>>3;
|
||||
if(state==CS_DEAD && b->state!=CS_DEAD) b->lastaction = lastmillis;
|
||||
b->state = state;
|
||||
|
||||
if (!b->bIsBot)
|
||||
b->bIsBot = true;
|
||||
|
||||
if(!demoplayback) updatepos(b);
|
||||
break;
|
||||
}
|
||||
case SV_BOTCOMMAND:
|
||||
botcommand(p, text);
|
||||
break;
|
||||
|
||||
// End add
|
||||
|
||||
default:
|
||||
neterr("type");
|
||||
|
||||
+81
-8
@@ -91,8 +91,44 @@ struct vec { float x, y, z; };
|
||||
struct block { int x, y, xs, ys; };
|
||||
struct mapmodelinfo { int rad, h, zoff, snap; char *name; };
|
||||
|
||||
enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSULT, GUN_GRENADE, NUMGUNS };
|
||||
enum { G_PRIMARY=0, G_SECONDARY, G_MELEE, G_GRENADE, G_NUM };
|
||||
enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSULT, GUN_GRENADE, NUMGUNS };
|
||||
enum { G_PRIMARY=0, G_SECONDARY, G_MELEE, G_GRENADE, G_NUM };
|
||||
|
||||
|
||||
|
||||
// Added by Rick
|
||||
class CBot;
|
||||
|
||||
#define MAX_STORED_LOCATIONS 7
|
||||
|
||||
extern int lastmillis; // last time (Moved up by Rick)
|
||||
|
||||
class CPrevLocation
|
||||
{
|
||||
int nextupdate;
|
||||
|
||||
public:
|
||||
vec prevloc[MAX_STORED_LOCATIONS];
|
||||
|
||||
CPrevLocation(void) : nextupdate(0) { Reset(); };
|
||||
void Reset(void) { loopi(MAX_STORED_LOCATIONS) prevloc[i].x=prevloc[i].y=prevloc[i].z=0.0f; };
|
||||
void Update(const vec &o)
|
||||
{
|
||||
extern float GetDistance(vec v1, vec v2);
|
||||
|
||||
if (nextupdate > lastmillis) return;
|
||||
if (GetDistance(o, prevloc[0]) >= 4.0f)
|
||||
{
|
||||
for(int i=(MAX_STORED_LOCATIONS-1);i>=1;i--)
|
||||
prevloc[i] = prevloc[i-1];
|
||||
prevloc[0] = o;
|
||||
}
|
||||
nextupdate = lastmillis + 100;
|
||||
};
|
||||
};
|
||||
|
||||
struct itemstat { int add, start, max, sound; };
|
||||
// End add
|
||||
|
||||
struct md3state
|
||||
{
|
||||
@@ -147,7 +183,7 @@ struct dynent // players & monsters
|
||||
int lifesequence; // sequence id for each respawn, used in damage test
|
||||
int state; // one of CS_* below
|
||||
int frags;
|
||||
int health, armour; //armourtype, quadmillis;
|
||||
int health, armour; //armourtype, quadmillis;
|
||||
int akimbomillis;
|
||||
int gunselect, gunwait;
|
||||
int lastaction, lastattackgun, lastmove;
|
||||
@@ -157,6 +193,9 @@ struct dynent // players & monsters
|
||||
int monsterstate; // one of M_* below, M_NONE means human
|
||||
int mtype; // see monster.cpp
|
||||
dynent *enemy; // monster wants to kill this entity
|
||||
// Added by Rick: targetpitch
|
||||
float targetpitch; // monster wants to look in this direction
|
||||
// End add
|
||||
float targetyaw; // monster wants to look in this direction
|
||||
bool blocked, moving; // used by physics to signal ai
|
||||
int trigger; // millis at which transition to another monsterstate takes place
|
||||
@@ -168,7 +207,7 @@ struct dynent // players & monsters
|
||||
int shots; //keeps track of shots from auto weapons
|
||||
bool reloading, hasarmour;
|
||||
int primary; //primary gun
|
||||
int nextprimary;
|
||||
int nextprimary;
|
||||
int skin, nextskin;
|
||||
md3state animstate[3];
|
||||
|
||||
@@ -177,7 +216,20 @@ struct dynent // players & monsters
|
||||
bool isphysent; // hack
|
||||
int thrownademillis;
|
||||
int akimbo;
|
||||
// Added by Rick
|
||||
CBot *pBot; // Only used if this is a bot, points to the bot class if we are the host,
|
||||
// for other clients its NULL
|
||||
bool bIsBot; // Is this dynent a bot?
|
||||
CPrevLocation PrevLocations; // Previous stored locations of this player
|
||||
// End add by Rick
|
||||
};
|
||||
// Moved from server.cpp by Rick
|
||||
struct server_entity // server side version of "entity" type
|
||||
{
|
||||
bool spawned;
|
||||
int spawnsecs;
|
||||
};
|
||||
// End move
|
||||
|
||||
// EDIT: AH
|
||||
enum { CTFF_INBASE = 0, CTFF_STOLEN, CTFF_DROPPED };
|
||||
@@ -223,6 +275,11 @@ enum
|
||||
SV_SENDMAP, SV_RECVMAP, SV_SERVMSG, SV_ITEMLIST, SV_WEAPCHANGE,
|
||||
SV_MODELSKIN,
|
||||
SV_FLAGPICKUP, SV_FLAGDROP, SV_FLAGRETURN, SV_FLAGSCORE, SV_FLAGINFO, SV_FLAGS, //EDIT: AH
|
||||
// Added by Rick: Bot specific messages
|
||||
SV_BOTSOUND, SV_BOTDIS, SV_BOTDIED, SV_CLIENT2BOTDMG, SV_BOT2BOTDMG,
|
||||
SV_BOTFRAGS, SV_ADDBOT, SV_BOTUPDATE, SV_BOTCOMMAND,
|
||||
// End add
|
||||
SV_BOTITEMPICKUP, SV_BOT2CLIENTDMG, SV_DIEDBYBOT,
|
||||
SV_EXT,
|
||||
};
|
||||
|
||||
@@ -247,9 +304,9 @@ enum
|
||||
S_FALL1, S_FALL2, //31
|
||||
S_FLAUNCH, S_FEXPLODE, //33
|
||||
S_SPLASH1, S_SPLASH2,
|
||||
S_GRUNT1, S_GRUNT2, S_RUMBLE,
|
||||
S_FLAGDROP, S_FLAGPICKUP, S_FLAGRETURN, S_FLAGSCORE,
|
||||
S_GRENADEPULL, S_GRENADETHROW,
|
||||
S_GRUNT1, S_GRUNT2, S_RUMBLE,
|
||||
S_FLAGDROP, S_FLAGPICKUP, S_FLAGRETURN, S_FLAGSCORE,
|
||||
S_GRENADEPULL, S_GRENADETHROW,
|
||||
S_RAKIMBO,
|
||||
S_NULL
|
||||
};
|
||||
@@ -303,7 +360,9 @@ extern bool demoplayback;
|
||||
#define vdistsquared(d,v,e,s) vec v = s; vsub(v,e); float d = (dotprod(v,v));
|
||||
#define vreject(v,u,max) ((v).x>(u).x+(max) || (v).x<(u).x-(max) || (v).y>(u).y+(max) || (v).y<(u).y-(max))
|
||||
#define vlinterp(v,f,u,g) { (v).x = (v).x*f+(u).x*g; (v).y = (v).y*f+(u).y*g; (v).z = (v).z*f+(u).z*g; }
|
||||
|
||||
// Added by Rick (compares 2 vectors)
|
||||
#define vis(v1,v2) ((v1.x==v2.x) && (v1.y==v2.y) && (v1.z==v2.z))
|
||||
// End add by Rick
|
||||
#define sgetstr() { char *t = text; int tlen=0; do { *t = getint(p); } while(*t++ && ++tlen<MAXTRANS); text[MAXTRANS-1]=0; } // used by networking
|
||||
|
||||
/* Gamemodes
|
||||
@@ -380,5 +439,19 @@ enum // function signatures for script functions, see command.cpp
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
// Added by Rick
|
||||
extern ENetHost *clienthost;
|
||||
inline bool ishost(void) { return !clienthost; };
|
||||
|
||||
void splaysound(int n, vec *loc=0);
|
||||
void addteamscore(dynent *d);
|
||||
void renderscore(dynent *d);
|
||||
extern void conoutf(const char *s, int a = 0, int b = 0, int c = 0); // Moved from protos.h
|
||||
extern void particle_trail(int type, int fade, vec &from, vec &to); // Moved from protos.h
|
||||
extern bool listenserv;
|
||||
extern bool intermission;
|
||||
#include "bot/bot.h"
|
||||
// End add by Rick
|
||||
|
||||
#include "protos.h" // external function decls
|
||||
|
||||
|
||||
+78
-49
@@ -76,7 +76,7 @@ void renderentities()
|
||||
};
|
||||
};
|
||||
|
||||
struct itemstat { int add, start, max, sound; } itemstats[] =
|
||||
itemstat itemstats[] =
|
||||
{
|
||||
16, 8, 72, S_ITEMAMMO, //pistol
|
||||
14, 7, 21, S_ITEMAMMO, //shotgun
|
||||
@@ -90,6 +90,9 @@ struct itemstat { int add, start, max, sound; } itemstats[] =
|
||||
};
|
||||
|
||||
void baseammo(int gun) { player1->ammo[gun] = itemstats[gun-1].add*2; };
|
||||
// Added by Rick: baseammo for bots
|
||||
void botbaseammo(int gun, dynent *d) { d->ammo[gun] = itemstats[gun-1].add*2; };
|
||||
// End add
|
||||
|
||||
// these two functions are called when the server acknowledges that you really
|
||||
// picked up the item (in multiplayer someone may grab it before you).
|
||||
@@ -112,42 +115,37 @@ void radditem(int i, int &v, int t)
|
||||
v += is.add;
|
||||
if(v>is.max) v = is.max;
|
||||
playsoundc(is.sound);
|
||||
};
|
||||
|
||||
extern void weapon(int gun);
|
||||
};
|
||||
|
||||
extern void weapon(int gun);
|
||||
|
||||
void realpickup(int n, dynent *d)
|
||||
{
|
||||
switch(ents[n].type)
|
||||
{
|
||||
//case I_PISTOL: radditem(n, d->ammo[1]); break;
|
||||
//case I_SHOTGUN: radditem(n, d->ammo[2]); break;
|
||||
//case I_SUBGUN: radditem(n, d->ammo[3]); break;
|
||||
//case I_SNIPER: radditem(n, d->ammo[4]); break;
|
||||
//case I_ASSULT: radditem(n, d->ammo[5]); break;
|
||||
case I_CLIPS:
|
||||
|
||||
radditem(n, d->ammo[1], 1);
|
||||
break;
|
||||
|
||||
case I_AMMO:
|
||||
radditem(n, d->ammo[d->primary], d->primary);
|
||||
break;
|
||||
case I_GRENADE: radditem(n, d->mag[6], 6); break;
|
||||
case I_HEALTH: radditem(n, d->health, 7); break;
|
||||
|
||||
case I_ARMOUR:
|
||||
case I_CLIPS:
|
||||
radditem(n, d->ammo[1], 1);
|
||||
break;
|
||||
case I_AMMO:
|
||||
radditem(n, d->ammo[d->primary], d->primary);
|
||||
break;
|
||||
case I_GRENADE:
|
||||
radditem(n, d->mag[6], 6);
|
||||
break;
|
||||
case I_HEALTH:
|
||||
radditem(n, d->health, 7);
|
||||
break;
|
||||
case I_ARMOUR:
|
||||
radditem(n, d->armour, 8);
|
||||
//d->hasarmour = true;
|
||||
break;
|
||||
|
||||
case I_AKIMBO:
|
||||
d->akimbo = true;
|
||||
d->akimbo = true;
|
||||
d->akimbomillis = 30000;
|
||||
d->mag[GUN_PISTOL] = 16;
|
||||
radditem(n, d->ammo[1], 9);
|
||||
radditem(n, d->ammo[1], 9);
|
||||
weapon(G_SECONDARY);
|
||||
conoutf("a lesser man would use a single pistol");
|
||||
if(d==player1) conoutf("a lesser man would use a single pistol");
|
||||
break;
|
||||
};
|
||||
};
|
||||
@@ -183,18 +181,13 @@ void pickup(int n, dynent *d)
|
||||
int ammo = np*2;
|
||||
switch(ents[n].type)
|
||||
{
|
||||
//case I_PISTOL: additem(n, d->ammo[1], ammo); break;
|
||||
//case I_SHOTGUN: additem(n, d->ammo[2], ammo); break;
|
||||
//case I_SUBGUN: additem(n, d->ammo[3], ammo); break;
|
||||
//case I_SNIPER: additem(n, d->ammo[4], ammo); break;
|
||||
//case I_ASSULT: additem(n, d->ammo[5], ammo); break;
|
||||
case I_CLIPS:
|
||||
additem(n, d->ammo[1], ammo, 1);
|
||||
break;
|
||||
case I_AMMO:
|
||||
additem(n, d->ammo[d->primary], ammo, d->primary);
|
||||
break;
|
||||
case I_GRENADE: additem(n, d->mag[6], ammo, 6); break;
|
||||
additem(n, d->ammo[1], ammo, 1);
|
||||
break;
|
||||
case I_AMMO:
|
||||
additem(n, d->ammo[d->primary], ammo, d->primary);
|
||||
break;
|
||||
case I_GRENADE: additem(n, d->mag[6], ammo, 6); break;
|
||||
case I_HEALTH: additem(n, d->health, np*5, 7); break;
|
||||
|
||||
case I_ARMOUR:
|
||||
@@ -287,27 +280,21 @@ void radd(dynent *d)
|
||||
d->mag[GUN_KNIFE] = 1;
|
||||
|
||||
d->mag[GUN_PISTOL] = 8;
|
||||
d->ammo[GUN_PISTOL] = 24;
|
||||
d->ammo[GUN_PISTOL] = 24;
|
||||
d->mag[GUN_GRENADE] = d->ammo[GUN_GRENADE] = 0;
|
||||
|
||||
if (m_pistol || d->primary==GUN_PISTOL) // || pistol only mode!
|
||||
{
|
||||
d->primary = GUN_PISTOL;
|
||||
d->ammo[d->primary] = 72;
|
||||
d->primary = GUN_PISTOL;
|
||||
d->ammo[d->primary] = 72;
|
||||
}
|
||||
else if (d->primary>GUN_PISTOL && d->primary<GUN_GRENADE)
|
||||
{
|
||||
d->ammo[d->primary] = itemstats[d->primary-1].max;
|
||||
d->mag[d->primary] = itemstats[d->primary-1].start;
|
||||
printf("player is you: %i\n", d==player1?1:0);
|
||||
};
|
||||
|
||||
d->mag[d->primary] = itemstats[d->primary-1].start;
|
||||
}
|
||||
|
||||
/*
|
||||
if (d->primary==GUN_GRENADE)
|
||||
{
|
||||
//conoutf("you don't have to worry about blowing your hand off just yet...");
|
||||
}
|
||||
*/
|
||||
if (d->hasarmour)
|
||||
{
|
||||
if(gamemode==m_arena)
|
||||
@@ -331,6 +318,48 @@ COMMAND(item,ARG_1INT);
|
||||
void akimbo()
|
||||
{
|
||||
conoutf("akimbo=%d",player1->akimbo);
|
||||
};
|
||||
};
|
||||
|
||||
COMMAND(akimbo, ARG_NONE);
|
||||
|
||||
// Added by Rick
|
||||
bool intersect(entity *e, vec &from, vec &to, vec *end) // if lineseg hits entity bounding box(entity version)
|
||||
{
|
||||
mapmodelinfo &mmi = getmminfo(e->attr2);
|
||||
if(!&mmi || !mmi.h) return false;
|
||||
|
||||
float lo = (float)(S(e->x, e->y)->floor+mmi.zoff+e->attr3);
|
||||
float hi = lo+mmi.h;
|
||||
vec v = to, w = { e->x, e->y, lo + (fabs(hi-lo)/2.0f) }, *p;
|
||||
vsub(v, from);
|
||||
vsub(w, from);
|
||||
float c1 = dotprod(w, v);
|
||||
|
||||
if(c1<=0) p = &from;
|
||||
else
|
||||
{
|
||||
float c2 = dotprod(v, v);
|
||||
if(c2<=c1) p = &to;
|
||||
else
|
||||
{
|
||||
float f = c1/c2;
|
||||
vmul(v, f);
|
||||
vadd(v, from);
|
||||
p = &v;
|
||||
};
|
||||
};
|
||||
|
||||
if (p->x <= e->x+mmi.rad
|
||||
&& p->x >= e->x-mmi.rad
|
||||
&& p->y <= e->y+mmi.rad
|
||||
&& p->y >= e->y-mmi.rad
|
||||
&& p->z <= hi
|
||||
&& p->z >= lo)
|
||||
{
|
||||
if (end) *end = *p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
// End add by Ricks
|
||||
|
||||
|
||||
+223
-223
@@ -1,223 +1,223 @@
|
||||
// menus.cpp: ingame menu system (also used for scores and serverlist)
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
#define FIRSTMENU 120
|
||||
|
||||
struct mitem { char *text, *action, *hoveraction; };
|
||||
|
||||
struct gmenu
|
||||
{
|
||||
char *name;
|
||||
vector<mitem> items;
|
||||
int mwidth;
|
||||
int menusel;
|
||||
int tex; // (optional) bg tex
|
||||
char *mdl; // (optional) md2 mdl
|
||||
int frame, range, rotspeed, scale;
|
||||
};
|
||||
|
||||
vector<gmenu> menus;
|
||||
|
||||
int vmenu = -1;
|
||||
|
||||
ivector menustack;
|
||||
|
||||
void menuset(int menu) // EDIT: AH
|
||||
{
|
||||
if((vmenu = menu)>=1 && menu != 2) resetmovement(player1);
|
||||
if(vmenu==1) menus[1].menusel = 0;
|
||||
};
|
||||
|
||||
void showmenu(char *name)
|
||||
{
|
||||
loopv(menus) if(i>1 && strcmp(menus[i].name, name)==0)
|
||||
{
|
||||
menuset(i);
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
int menucompare(mitem *a, mitem *b)
|
||||
{
|
||||
int x = atoi(a->text);
|
||||
int y = atoi(b->text);
|
||||
if(x>y) return -1;
|
||||
if(x<y) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
void sortmenu(int m, int start, int num)
|
||||
{
|
||||
qsort(&menus[m].items[start], num, sizeof(mitem), (int (__cdecl *)(const void *,const void *))menucompare);
|
||||
};
|
||||
|
||||
void refreshservers();
|
||||
|
||||
bool rendermenu()
|
||||
{
|
||||
if(vmenu<0) { menustack.setsize(0); return false; };
|
||||
if(vmenu==1) refreshservers();
|
||||
gmenu &m = menus[vmenu];
|
||||
sprintf_sd(title)(vmenu>0 && vmenu!=2 ? "[ %s menu ]" : "%s", m.name); // EDIT: AH
|
||||
int mdisp = m.items.length();
|
||||
int w = 0;
|
||||
loopi(mdisp)
|
||||
{
|
||||
int x = text_width(m.items[i].text);
|
||||
if(x>w) w = x;
|
||||
};
|
||||
int tw = text_width(title);
|
||||
if(tw>w) w = tw;
|
||||
int step = FONTH/4*5;
|
||||
int h = (mdisp+2)*step;
|
||||
int y = (VIRTH-h)/2;
|
||||
int x = (VIRTW-w)/2;
|
||||
blendbox(x-FONTH/2*3, y-FONTH, x+w+FONTH/2*3, y+h+FONTH, true, m.tex >= 0 ? FIRSTMENU + m.tex : -1);
|
||||
draw_text(title, x, y,2);
|
||||
y += FONTH*2;
|
||||
if(vmenu && vmenu!=2)
|
||||
{
|
||||
int bh = y+m.menusel*step;
|
||||
blendbox(x-FONTH, bh-10, x+w+FONTH, bh+FONTH+10, false);
|
||||
};
|
||||
loopj(mdisp)
|
||||
{
|
||||
draw_text(m.items[j].text, x, y, 2);
|
||||
y += step;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
void rendermenumdl()
|
||||
{
|
||||
if(vmenu<0) { menustack.setsize(0); return; };
|
||||
if(vmenu==1) refreshservers();
|
||||
gmenu &m = menus[vmenu];
|
||||
if(!m.mdl) return;
|
||||
|
||||
glPushMatrix ();
|
||||
|
||||
glTranslatef(player1->o.x, player1->o.z, player1->o.y);
|
||||
glRotatef(player1->yaw+90+180, 0, -1, 0);
|
||||
glRotatef(player1->pitch, 0, 0, 1);
|
||||
|
||||
if(strstr(m.mdl, "playermodel")==NULL) glTranslatef(2.0f, 1.7f, 0.0f);
|
||||
else glTranslatef(2.0f, 1.0f, 1.5f);
|
||||
if(m.rotspeed) glRotatef(lastmillis/5.0f/100.0f*m.rotspeed, 0, 1, 0);
|
||||
|
||||
rendermodel(m.mdl, m.frame, m.range, 0.0f, 0.0f, 0.0f, 0, 0, 0, 0, false, (float)(m.scale ? m.scale/25.0f : 1), 100, 0, 0, false);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void newmenu(char *name)
|
||||
{
|
||||
gmenu &menu = menus.add();
|
||||
menu.name = newstring(name);
|
||||
menu.menusel = 0;
|
||||
menu.tex = -1;
|
||||
menu.mdl = NULL;
|
||||
};
|
||||
|
||||
void menumanual(int m, int n, char *text)
|
||||
{
|
||||
if(!n) menus[m].items.setsize(0);
|
||||
mitem &mitem = menus[m].items.add();
|
||||
mitem.text = text;
|
||||
mitem.action = "";
|
||||
}
|
||||
|
||||
void menuitem(char *text, char *action, char *hoveraction)
|
||||
{
|
||||
gmenu &menu = menus.last();
|
||||
mitem &mi = menu.items.add();
|
||||
mi.text = newstring(text);
|
||||
mi.action = action[0] ? newstring(action) : mi.text;
|
||||
if(hoveraction) mi.hoveraction = newstring(hoveraction);
|
||||
else mi.hoveraction = NULL;
|
||||
};
|
||||
|
||||
void menubg(char *tex)
|
||||
{
|
||||
gmenu &menu = menus.last();
|
||||
int curmtex = 0;
|
||||
loopv(menus) curmtex = max(curmtex, menus[i].tex);
|
||||
if(curmtex>=100) return;
|
||||
sprintf_sd(path)("packages/%s", tex);
|
||||
int xs, ys;
|
||||
if(installtex(FIRSTMENU + curmtex, path, xs, ys, false, true))
|
||||
menu.tex = curmtex;
|
||||
};
|
||||
|
||||
void menumdl(char *mdl, char *frame, char *range, char *rotspeed, char *scale)
|
||||
{
|
||||
if(!mdl || !frame || !range) return;
|
||||
gmenu &menu = menus.last();
|
||||
menu.mdl = newstring(mdl, _MAXDEFSTR);
|
||||
menu.frame = max(0, atoi(frame));
|
||||
menu.range = max(1, atoi(range));
|
||||
menu.rotspeed = max(0, min(atoi(rotspeed), 100));
|
||||
menu.scale = max(0, min(atoi(scale), 100));
|
||||
};
|
||||
|
||||
void chmenumdl(char *menu, char *mdl, char *frame, char *range, char *rotspeed, char *scale)
|
||||
{
|
||||
if(!menu || !mdl) return;
|
||||
loopv(menus)
|
||||
{
|
||||
gmenu &m = menus[i];
|
||||
if(strcmp(m.name, menu) == 0)
|
||||
{
|
||||
if(m.mdl) strcpy_s(m.mdl, mdl);
|
||||
else m.mdl = newstring(mdl, _MAXDEFSTR);
|
||||
m.frame = atoi(frame);
|
||||
m.range = atoi(range);
|
||||
m.rotspeed = max(0, min(atoi(rotspeed), 100));
|
||||
m.scale = max(0, min(atoi(scale), 100));
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
COMMAND(menuitem, ARG_3STR);
|
||||
COMMAND(showmenu, ARG_1STR);
|
||||
COMMAND(newmenu, ARG_1STR);
|
||||
COMMAND(menubg, ARG_1STR);
|
||||
COMMAND(menumdl, ARG_5STR);
|
||||
COMMAND(chmenumdl, ARG_6STR);
|
||||
|
||||
bool menukey(int code, bool isdown)
|
||||
{
|
||||
if(vmenu<=0 || vmenu == 2) return false; // EDIT: AH
|
||||
int menusel = menus[vmenu].menusel;
|
||||
if(isdown)
|
||||
{
|
||||
int oldmenusel = menusel;
|
||||
if(code==SDLK_ESCAPE)
|
||||
{
|
||||
menuset(-1);
|
||||
if(!menustack.empty()) menuset(menustack.pop());
|
||||
return true;
|
||||
}
|
||||
else if(code==SDLK_UP || code==-4) menusel--;
|
||||
else if(code==SDLK_DOWN || code==-5) menusel++;
|
||||
int n = menus[vmenu].items.length();
|
||||
if(menusel<0) menusel = n-1;
|
||||
else if(menusel>=n) menusel = 0;
|
||||
menus[vmenu].menusel = menusel;
|
||||
if(menusel != oldmenusel)execute(menus[vmenu].items[menusel].hoveraction, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(code==SDLK_RETURN || code==-2)
|
||||
{
|
||||
char *action = menus[vmenu].items[menusel].action;
|
||||
if(vmenu==1) connects(getservername(menusel));
|
||||
menustack.add(vmenu);
|
||||
menuset(-1);
|
||||
execute(action, true);
|
||||
};
|
||||
};
|
||||
return true;
|
||||
};
|
||||
// menus.cpp: ingame menu system (also used for scores and serverlist)
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
#define FIRSTMENU 120
|
||||
|
||||
struct mitem { char *text, *action, *hoveraction; };
|
||||
|
||||
struct gmenu
|
||||
{
|
||||
char *name;
|
||||
vector<mitem> items;
|
||||
int mwidth;
|
||||
int menusel;
|
||||
int tex; // (optional) bg tex
|
||||
char *mdl; // (optional) md2 mdl
|
||||
int frame, range, rotspeed, scale;
|
||||
};
|
||||
|
||||
vector<gmenu> menus;
|
||||
|
||||
int vmenu = -1;
|
||||
|
||||
ivector menustack;
|
||||
|
||||
void menuset(int menu) // EDIT: AH
|
||||
{
|
||||
if((vmenu = menu)>=1 && menu != 2) resetmovement(player1);
|
||||
if(vmenu==1) menus[1].menusel = 0;
|
||||
};
|
||||
|
||||
void showmenu(char *name)
|
||||
{
|
||||
loopv(menus) if(i>1 && strcmp(menus[i].name, name)==0)
|
||||
{
|
||||
menuset(i);
|
||||
return;
|
||||
};
|
||||
};
|
||||
|
||||
int menucompare(mitem *a, mitem *b)
|
||||
{
|
||||
int x = atoi(a->text);
|
||||
int y = atoi(b->text);
|
||||
if(x>y) return -1;
|
||||
if(x<y) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
void sortmenu(int m, int start, int num)
|
||||
{
|
||||
qsort(&menus[m].items[start], num, sizeof(mitem), (int (__cdecl *)(const void *,const void *))menucompare);
|
||||
};
|
||||
|
||||
void refreshservers();
|
||||
|
||||
bool rendermenu()
|
||||
{
|
||||
if(vmenu<0) { menustack.setsize(0); return false; };
|
||||
if(vmenu==1) refreshservers();
|
||||
gmenu &m = menus[vmenu];
|
||||
sprintf_sd(title)(vmenu>0 && vmenu!=2 ? "[ %s menu ]" : "%s", m.name); // EDIT: AH
|
||||
int mdisp = m.items.length();
|
||||
int w = 0;
|
||||
loopi(mdisp)
|
||||
{
|
||||
int x = text_width(m.items[i].text);
|
||||
if(x>w) w = x;
|
||||
};
|
||||
int tw = text_width(title);
|
||||
if(tw>w) w = tw;
|
||||
int step = FONTH/4*5;
|
||||
int h = (mdisp+2)*step;
|
||||
int y = (VIRTH-h)/2;
|
||||
int x = (VIRTW-w)/2;
|
||||
blendbox(x-FONTH/2*3, y-FONTH, x+w+FONTH/2*3, y+h+FONTH, true, m.tex >= 0 ? FIRSTMENU + m.tex : -1);
|
||||
draw_text(title, x, y,2);
|
||||
y += FONTH*2;
|
||||
if(vmenu && vmenu!=2)
|
||||
{
|
||||
int bh = y+m.menusel*step;
|
||||
blendbox(x-FONTH, bh-10, x+w+FONTH, bh+FONTH+10, false);
|
||||
};
|
||||
loopj(mdisp)
|
||||
{
|
||||
draw_text(m.items[j].text, x, y, 2);
|
||||
y += step;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
void rendermenumdl()
|
||||
{
|
||||
if(vmenu<0) { menustack.setsize(0); return; };
|
||||
if(vmenu==1) refreshservers();
|
||||
gmenu &m = menus[vmenu];
|
||||
if(!m.mdl) return;
|
||||
|
||||
glPushMatrix ();
|
||||
|
||||
glTranslatef(player1->o.x, player1->o.z, player1->o.y);
|
||||
glRotatef(player1->yaw+90+180, 0, -1, 0);
|
||||
glRotatef(player1->pitch, 0, 0, 1);
|
||||
|
||||
if(strstr(m.mdl, "playermodel")==NULL) glTranslatef(2.0f, 1.7f, 0.0f);
|
||||
else glTranslatef(2.0f, 1.0f, 1.5f);
|
||||
if(m.rotspeed) glRotatef(lastmillis/5.0f/100.0f*m.rotspeed, 0, 1, 0);
|
||||
|
||||
rendermodel(m.mdl, m.frame, m.range, 0.0f, 0.0f, 0.0f, 0, 0, 0, 0, false, (float)(m.scale ? m.scale/25.0f : 1), 100, 0, 0, false);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void newmenu(char *name)
|
||||
{
|
||||
gmenu &menu = menus.add();
|
||||
menu.name = newstring(name);
|
||||
menu.menusel = 0;
|
||||
menu.tex = -1;
|
||||
menu.mdl = NULL;
|
||||
};
|
||||
|
||||
void menumanual(int m, int n, char *text)
|
||||
{
|
||||
if(!n) menus[m].items.setsize(0);
|
||||
mitem &mitem = menus[m].items.add();
|
||||
mitem.text = text;
|
||||
mitem.action = "";
|
||||
}
|
||||
|
||||
void menuitem(char *text, char *action, char *hoveraction)
|
||||
{
|
||||
gmenu &menu = menus.last();
|
||||
mitem &mi = menu.items.add();
|
||||
mi.text = newstring(text);
|
||||
mi.action = action[0] ? newstring(action) : mi.text;
|
||||
if(hoveraction) mi.hoveraction = newstring(hoveraction);
|
||||
else mi.hoveraction = NULL;
|
||||
};
|
||||
|
||||
void menubg(char *tex)
|
||||
{
|
||||
gmenu &menu = menus.last();
|
||||
int curmtex = 0;
|
||||
loopv(menus) curmtex = max(curmtex, menus[i].tex);
|
||||
if(curmtex>=100) return;
|
||||
sprintf_sd(path)("packages/%s", tex);
|
||||
int xs, ys;
|
||||
if(installtex(FIRSTMENU + curmtex, path, xs, ys, false, true))
|
||||
menu.tex = curmtex;
|
||||
};
|
||||
|
||||
void menumdl(char *mdl, char *frame, char *range, char *rotspeed, char *scale)
|
||||
{
|
||||
if(!mdl || !frame || !range) return;
|
||||
gmenu &menu = menus.last();
|
||||
menu.mdl = newstring(mdl, _MAXDEFSTR);
|
||||
menu.frame = max(0, atoi(frame));
|
||||
menu.range = max(1, atoi(range));
|
||||
menu.rotspeed = max(0, min(atoi(rotspeed), 100));
|
||||
menu.scale = max(0, min(atoi(scale), 100));
|
||||
};
|
||||
|
||||
void chmenumdl(char *menu, char *mdl, char *frame, char *range, char *rotspeed, char *scale)
|
||||
{
|
||||
if(!menu || !mdl) return;
|
||||
loopv(menus)
|
||||
{
|
||||
gmenu &m = menus[i];
|
||||
if(strcmp(m.name, menu) == 0)
|
||||
{
|
||||
if(m.mdl) strcpy_s(m.mdl, mdl);
|
||||
else m.mdl = newstring(mdl, _MAXDEFSTR);
|
||||
m.frame = atoi(frame);
|
||||
m.range = atoi(range);
|
||||
m.rotspeed = max(0, min(atoi(rotspeed), 100));
|
||||
m.scale = max(0, min(atoi(scale), 100));
|
||||
return;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
COMMAND(menuitem, ARG_3STR);
|
||||
COMMAND(showmenu, ARG_1STR);
|
||||
COMMAND(newmenu, ARG_1STR);
|
||||
COMMAND(menubg, ARG_1STR);
|
||||
COMMAND(menumdl, ARG_5STR);
|
||||
COMMAND(chmenumdl, ARG_6STR);
|
||||
|
||||
bool menukey(int code, bool isdown)
|
||||
{
|
||||
if(vmenu<=0 || vmenu == 2) return false; // EDIT: AH
|
||||
int menusel = menus[vmenu].menusel;
|
||||
if(isdown)
|
||||
{
|
||||
int oldmenusel = menusel;
|
||||
if(code==SDLK_ESCAPE)
|
||||
{
|
||||
menuset(-1);
|
||||
if(!menustack.empty()) menuset(menustack.pop());
|
||||
return true;
|
||||
}
|
||||
else if(code==SDLK_UP || code==-4) menusel--;
|
||||
else if(code==SDLK_DOWN || code==-5) menusel++;
|
||||
int n = menus[vmenu].items.length();
|
||||
if(menusel<0) menusel = n-1;
|
||||
else if(menusel>=n) menusel = 0;
|
||||
menus[vmenu].menusel = menusel;
|
||||
if(menusel != oldmenusel)execute(menus[vmenu].items[menusel].hoveraction, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(code==SDLK_RETURN || code==-2)
|
||||
{
|
||||
char *action = menus[vmenu].items[menusel].action;
|
||||
if(vmenu==1) connects(getservername(menusel));
|
||||
menustack.add(vmenu);
|
||||
menuset(-1);
|
||||
execute(action, true);
|
||||
};
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
+41
-3
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
/* Modified by Rick: Fix, so we can jump on players aswell
|
||||
bool plcollide(dynent *d, dynent *o, float &headspace) // collide with player or monster
|
||||
{
|
||||
if(o->state!=CS_ALIVE) return true;
|
||||
@@ -18,6 +19,24 @@ bool plcollide(dynent *d, dynent *o, float &headspace) // collide with
|
||||
};
|
||||
return true;
|
||||
};
|
||||
*/
|
||||
|
||||
bool plcollide(dynent *d, dynent *o, float &headspace, float &hi, float &lo) // collide with player or monster
|
||||
{
|
||||
if(o->state!=CS_ALIVE) return true;
|
||||
const float r = o->radius+d->radius;
|
||||
if(fabs(o->o.x-d->o.x)<r && fabs(o->o.y-d->o.y)<r)
|
||||
{
|
||||
if(d->o.z-d->eyeheight<o->o.z-o->eyeheight) { if(o->o.z-o->eyeheight<hi) hi = o->o.z-o->eyeheight-1; }
|
||||
else if(o->o.z+o->aboveeye>lo) lo = o->o.z+o->aboveeye+1;
|
||||
|
||||
if(fabs(o->o.z-d->o.z)<o->aboveeye+d->eyeheight) return false;
|
||||
//if(d->monsterstate) return false; // hack
|
||||
headspace = d->o.z-o->o.z-o->aboveeye-d->eyeheight;
|
||||
if(headspace<0) headspace = 10;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
bool cornertest(int mip, int x, int y, int dx, int dy, int &bx, int &by, int &bs) // recursively collide with a mipmapped corner cube
|
||||
{
|
||||
@@ -109,14 +128,28 @@ bool collide(dynent *d, bool spawn, float drop, float rise)
|
||||
|
||||
if(hi-lo < d->eyeheight+d->aboveeye) return false;
|
||||
|
||||
// Modified by Rick: plcollide now takes hi and lo in account aswell, that way we can jump/walk on players
|
||||
|
||||
float headspace = 10;
|
||||
loopv(players) // collide with other players
|
||||
{
|
||||
dynent *o = players[i];
|
||||
if(!o || o==d) continue;
|
||||
if(!plcollide(d, o, headspace)) return false;
|
||||
if(!plcollide(d, o, headspace, hi, lo)) return false;
|
||||
};
|
||||
if(d!=player1 && d->mtype!=M_NADE) if(!plcollide(d, player1, headspace)) return false;
|
||||
loopv(bots) // Added by Rick: collide with other bots
|
||||
{
|
||||
dynent *o = bots[i];
|
||||
if(!o || o==d) continue;
|
||||
if(!plcollide(d, o, headspace, hi, lo)) return false;
|
||||
};
|
||||
|
||||
if(d!=player1 && d->mtype!=M_NADE) if(!plcollide(d, player1, headspace, hi, lo)) return false;
|
||||
//dvector &v = getmonsters();
|
||||
// this loop can be a performance bottleneck with many monster on a slow cpu,
|
||||
// should replace with a blockmap but seems mostly fast enough
|
||||
// Modified by Rick: Added v[i] pointer check
|
||||
//loopv(v) if(v[i] && !vreject(d->o, v[i]->o, 7.0f) && d!=v[i] && !plcollide(d, v[i], headspace, hi, lo)) return false;
|
||||
headspace -= 0.01f;
|
||||
|
||||
mmcollide(d, hi, lo); // collide with map models
|
||||
@@ -274,11 +307,13 @@ void moveplayer(dynent *pl, int moveres, bool local, int curtime)
|
||||
if(water) { pl->vel.x /= 8; pl->vel.y /= 8; }; // dampen velocity change even harder, gives correct water feel
|
||||
if(local) playsoundc(S_JUMP);
|
||||
else if(pl->monsterstate) playsound(S_JUMP, &pl->o);
|
||||
else if(pl->bIsBot) botplaysound(S_JUMP, pl); // Added by Rick
|
||||
}
|
||||
/*else if(pl->timeinair>800) // if we land after long time must have been a high jump, make thud sound
|
||||
{
|
||||
if(local) playsoundc(S_LAND);
|
||||
else if(pl->monsterstate) playsound(S_LAND, &pl->o);
|
||||
else if(pl->bIsBot) botplaysound(S_LAND, pl); // Added by Rick
|
||||
};*/
|
||||
pl->timeinair = 0;
|
||||
if(pl->isphysent) pl->vel.z *= 0.7f;
|
||||
@@ -369,9 +404,12 @@ void moveplayer(dynent *pl, int moveres, bool local, int curtime)
|
||||
if(!pl->inwater && water) { playsound(S_SPLASH2, &pl->o); pl->vel.z = 0; }
|
||||
else if(pl->inwater && !water) playsound(S_SPLASH1, &pl->o);
|
||||
pl->inwater = water;
|
||||
// Added by Rick: Easy hack to store previous locations of all players/monsters/bots
|
||||
pl->PrevLocations.Update(pl->o);
|
||||
// End add
|
||||
};
|
||||
|
||||
void moveplayer(dynent *pl, int moveres, bool local)
|
||||
{
|
||||
loopi(physicsrepeat) moveplayer(pl, moveres, local, i ? curtime/physicsrepeat : curtime-curtime/physicsrepeat*(physicsrepeat-1));
|
||||
};
|
||||
};
|
||||
|
||||
+18
-6
@@ -18,7 +18,7 @@ extern void writecfg();
|
||||
// console
|
||||
extern void keypress(int code, bool isdown, int cooked);
|
||||
extern void renderconsole();
|
||||
extern void conoutf(const char *s, int a = 0, int b = 0, int c = 0);
|
||||
// extern void conoutf(const char *s, int a = 0, int b = 0, int c = 0); Moved to cube.h by Rick
|
||||
extern char *getcurcommand();
|
||||
|
||||
// menus
|
||||
@@ -89,6 +89,7 @@ extern char *getclientmap();
|
||||
extern const char *modestr(int n);
|
||||
extern void zapdynent(dynent *&d);
|
||||
extern dynent *getclient(int cn);
|
||||
extern dynent *getbot(int cn); // Added by Rick
|
||||
extern void timeupdate(int timeremain);
|
||||
extern void resetmovement(dynent *d);
|
||||
extern void fixplayer1range();
|
||||
@@ -169,13 +170,14 @@ extern void damageblend(int n);
|
||||
extern void addshotline(dynent *d, vec &from, vec &to);
|
||||
extern void rendershotlines();
|
||||
extern void shotlinereset();
|
||||
extern void renderphysents();
|
||||
extern void renderphysents();
|
||||
extern bool scoped;
|
||||
|
||||
// renderparticles
|
||||
extern void setorient(vec &r, vec &u);
|
||||
extern void particle_splash(int type, int num, int fade, vec &p);
|
||||
extern void particle_trail(int type, int fade, vec &from, vec &to);
|
||||
//extern void particle_splash(int num, int fade, vec &p);
|
||||
// extern void particle_trail(int type, int fade, vec &from, vec &to); Moved to cube.h by Rick
|
||||
extern void render_particles(int time);
|
||||
|
||||
// worldio
|
||||
@@ -204,6 +206,7 @@ extern void playsound(int n, vec *loc = 0);
|
||||
extern void playsoundc(int n);
|
||||
extern void initsound();
|
||||
extern void cleansound();
|
||||
extern void botplaysound(int n, dynent *b); // Added by Rick
|
||||
|
||||
// rendermd2
|
||||
extern void rendermodel(char *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap = 0, int basetime = 0, bool oculling=true);
|
||||
@@ -240,14 +243,19 @@ extern void createrays(vec &from, vec &to);
|
||||
extern void moveprojectiles(float time);
|
||||
extern void projreset();
|
||||
extern dynent *playerincrosshair();
|
||||
extern int reloadtime(int gun);
|
||||
extern int reloadtime(int gun);
|
||||
extern void reload(dynent *d);
|
||||
extern int attackdelay(int gun);
|
||||
extern int magsize(int gun);
|
||||
extern int kick_rot(int gun);
|
||||
extern int kick_back(int gun);
|
||||
extern bool gun_changed;
|
||||
extern bool akimboside;
|
||||
extern bool gun_changed;
|
||||
extern bool akimboside;
|
||||
extern int akimbolastaction[2];
|
||||
// Added by Rick
|
||||
extern char *botincrosshair();
|
||||
extern bool intersect(dynent *d, vec &from, vec &to, vec *end = NULL);
|
||||
// End add by Rick
|
||||
|
||||
// entities
|
||||
extern void renderents();
|
||||
@@ -260,6 +268,10 @@ extern void setspawn(int i, bool on);
|
||||
extern void baseammo(int gun);
|
||||
extern void checkitems();
|
||||
extern void radd(dynent *d);
|
||||
// Added by Rick
|
||||
extern void botbaseammo(int gun, dynent *d);
|
||||
extern bool intersect(entity *e, vec &from, vec &to, vec *end=NULL);
|
||||
// End add by Rick
|
||||
|
||||
// rndmap
|
||||
extern void perlinarea(block &b, int scale, int seed, int psize);
|
||||
|
||||
+567
-566
File diff suppressed because it is too large
Load Diff
@@ -283,7 +283,7 @@ void drawhudmodel(int start, int end, float speed, int base)
|
||||
{
|
||||
sprintf_sd(mdl)("hudguns/%s", hudgunnames[player1->gunselect]);
|
||||
rendermodel(mdl, start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw+90, player1->pitch, false, 1.0f, speed, 0, base);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
void drawhudgun(int w, int h, float aspect, int farplane)
|
||||
@@ -377,6 +377,8 @@ void gl_drawframe(int w, int h, float changelod, float curfps)
|
||||
xtraverts = 0;
|
||||
|
||||
renderclients();
|
||||
//monsterrender();
|
||||
BotManager.RenderBots(); // Added by Rick
|
||||
|
||||
renderentities();
|
||||
|
||||
@@ -389,6 +391,12 @@ void gl_drawframe(int w, int h, float changelod, float curfps)
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
// Added by Rick: Need todo here because of drawing the waypoints
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
WaypointClass.Think();
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
// end add
|
||||
|
||||
drawhudgun(w, h, aspect, farplane);
|
||||
|
||||
overbright(1);
|
||||
|
||||
+107
-107
@@ -79,9 +79,9 @@ struct md3model
|
||||
md3tag *tags;
|
||||
int numframes, numtags;
|
||||
bool loaded;
|
||||
vec scale;
|
||||
vec scale;
|
||||
bool mirrored;
|
||||
void setanim(int anim);
|
||||
void setanim(int anim);
|
||||
void setanimstate(md3state &as);
|
||||
bool link(md3model *link, char *tag);
|
||||
bool load(char *path, bool mirror);
|
||||
@@ -92,12 +92,12 @@ struct md3model
|
||||
};
|
||||
|
||||
md3model::md3model()
|
||||
{
|
||||
{
|
||||
mirrored = false;
|
||||
loaded = false;
|
||||
scale.x = scale.y = scale.z = MD3_DEFAULT_SCALE;
|
||||
// animstate = NULL;
|
||||
animstate = new md3state();
|
||||
// animstate = NULL;
|
||||
animstate = new md3state();
|
||||
animstate->lastTime = lastmillis;
|
||||
};
|
||||
|
||||
@@ -111,13 +111,13 @@ md3model::~md3model()
|
||||
if(links) free(links);
|
||||
if(tags) delete [] tags;
|
||||
};
|
||||
|
||||
void md3model::setanimstate(md3state &as)
|
||||
{
|
||||
animstate->anim = as.anim;
|
||||
animstate->frm = as.frm;
|
||||
animstate->lastTime = as.lastTime;
|
||||
};
|
||||
|
||||
void md3model::setanimstate(md3state &as)
|
||||
{
|
||||
animstate->anim = as.anim;
|
||||
animstate->frm = as.frm;
|
||||
animstate->lastTime = as.lastTime;
|
||||
};
|
||||
|
||||
void md3model::setanim(int anim)
|
||||
{
|
||||
@@ -137,7 +137,7 @@ bool md3model::link(md3model *link, char *tag)
|
||||
};
|
||||
|
||||
bool md3model::load(char *path, bool mirror=false)
|
||||
{
|
||||
{
|
||||
mirrored = mirror;
|
||||
if(!path) return false;
|
||||
FILE *f = fopen(path, "rb");
|
||||
@@ -268,7 +268,7 @@ void md3model::render()
|
||||
|
||||
if(animdebug) printf("interp. from frame %i to %i, %f percent done\n", a->frm, nextfrm, t*100.0f);
|
||||
|
||||
#define interpolate(p1,p2) ((p1) + t * ((p2) - (p1)))
|
||||
#define interpolate(p1,p2) ((p1) + t * ((p2) - (p1)))
|
||||
|
||||
loopv(meshes)
|
||||
{
|
||||
@@ -295,7 +295,7 @@ void md3model::render()
|
||||
};
|
||||
glEnd();
|
||||
};
|
||||
|
||||
|
||||
|
||||
loopi(numtags) // render the linked models - interpolate rotation and position of the 'link-tags'
|
||||
{
|
||||
@@ -329,11 +329,11 @@ void md3model::draw(float x, float y, float z, float yaw, float pitch, float rad
|
||||
glRotatef(-90, 1, 0, 0);
|
||||
|
||||
glScalef( scale.x, scale.y, scale.z);
|
||||
|
||||
if(mirrored) glCullFace(GL_BACK);
|
||||
|
||||
render();
|
||||
|
||||
if(mirrored) glCullFace(GL_BACK);
|
||||
|
||||
render();
|
||||
|
||||
if(mirrored) glCullFace(GL_FRONT);
|
||||
|
||||
glPopMatrix();
|
||||
@@ -396,7 +396,7 @@ void loadweapons()
|
||||
{
|
||||
firstweapon = models.length();
|
||||
loopi(NUMGUNS+1)
|
||||
{
|
||||
{
|
||||
bool akimbo = i==NUMGUNS;
|
||||
sprintf(basedir, "packages/models/weapons/%s", akimbo ? hudgunnames[GUN_PISTOL] : hudgunnames[i]);
|
||||
md3model *mdl = new md3model();
|
||||
@@ -420,71 +420,71 @@ VAR(swayupmovediv, 1, 200, 1000);
|
||||
|
||||
VAR(x, 0, 0, 1000);
|
||||
VAR(y, 0, 0, 1000);
|
||||
VAR(z, 0, 0, 1000);
|
||||
|
||||
struct weaponmove
|
||||
{
|
||||
float k_rot, kick;
|
||||
vec pos;
|
||||
int anim;
|
||||
|
||||
weaponmove(vec base, int basetime)
|
||||
{
|
||||
bool akimbo = player1->akimbo && player1->gunselect==GUN_PISTOL;
|
||||
bool throwingnade = player1->gunselect==GUN_GRENADE && player1->thrownademillis;
|
||||
int timediff = throwingnade ? (lastmillis-player1->thrownademillis) : lastmillis-basetime;
|
||||
int animtime = attackdelay(player1->gunselect);
|
||||
int rtime = reloadtime(player1->gunselect);
|
||||
kick = k_rot = 0.0f;
|
||||
pos = player1->o;
|
||||
anim = MDL_GUN_IDLE;
|
||||
bool attacking = player1->lastaction && player1->lastattackgun==player1->gunselect /*&& lastmillis-player1->lastaction<rtime*/;
|
||||
|
||||
if(akimbo && basetime>lastmillis) // akimbo gun queued for reloading
|
||||
{
|
||||
|
||||
}
|
||||
else if(player1->reloading)
|
||||
{
|
||||
anim = MDL_GUN_RELOAD;
|
||||
VAR(z, 0, 0, 1000);
|
||||
|
||||
struct weaponmove
|
||||
{
|
||||
float k_rot, kick;
|
||||
vec pos;
|
||||
int anim;
|
||||
|
||||
weaponmove(vec base, int basetime)
|
||||
{
|
||||
bool akimbo = player1->akimbo && player1->gunselect==GUN_PISTOL;
|
||||
bool throwingnade = player1->gunselect==GUN_GRENADE && player1->thrownademillis;
|
||||
int timediff = throwingnade ? (lastmillis-player1->thrownademillis) : lastmillis-basetime;
|
||||
int animtime = attackdelay(player1->gunselect);
|
||||
int rtime = reloadtime(player1->gunselect);
|
||||
kick = k_rot = 0.0f;
|
||||
pos = player1->o;
|
||||
anim = MDL_GUN_IDLE;
|
||||
bool attacking = player1->lastaction && player1->lastattackgun==player1->gunselect /*&& lastmillis-player1->lastaction<rtime*/;
|
||||
|
||||
if(akimbo && basetime>lastmillis) // akimbo gun queued for reloading
|
||||
{
|
||||
|
||||
}
|
||||
else if(player1->reloading)
|
||||
{
|
||||
anim = MDL_GUN_RELOAD;
|
||||
float percent_done = (float)(timediff)*100.0f/rtime;
|
||||
if(percent_done >= 100) percent_done = 100;
|
||||
k_rot = -(sin((float)(percent_done*2/100.0f*90.0f)*PI/180.0f)*90);
|
||||
}
|
||||
else if(throwingnade && timediff>animtime-rtime/2 && timediff<animtime && attacking)
|
||||
{
|
||||
anim = MDL_GUN_IDLE;
|
||||
float percent_done = (float)50.0f+(timediff-(animtime-rtime/2))*100.0f/rtime;
|
||||
k_rot = -(sin((float)(percent_done*2/100.0f*90.0f)*PI/180.0f)*90);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec sway = base;
|
||||
float percent_done = 0.0f;
|
||||
float k_back = 0.0f;
|
||||
|
||||
if(player1->gunselect==player1->lastattackgun)
|
||||
{
|
||||
if(percent_done >= 100) percent_done = 100;
|
||||
k_rot = -(sin((float)(percent_done*2/100.0f*90.0f)*PI/180.0f)*90);
|
||||
}
|
||||
else if(throwingnade && timediff>animtime-rtime/2 && timediff<animtime && attacking)
|
||||
{
|
||||
anim = MDL_GUN_IDLE;
|
||||
float percent_done = (float)50.0f+(timediff-(animtime-rtime/2))*100.0f/rtime;
|
||||
k_rot = -(sin((float)(percent_done*2/100.0f*90.0f)*PI/180.0f)*90);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec sway = base;
|
||||
float percent_done = 0.0f;
|
||||
float k_back = 0.0f;
|
||||
|
||||
if(player1->gunselect==player1->lastattackgun)
|
||||
{
|
||||
percent_done = timediff*100.0f/(float)animtime;
|
||||
if(percent_done > 100.0f) percent_done = 100.0f;
|
||||
// f(x) = -sin(x-1.5)^3
|
||||
kick = -sin(pow((1.5f/100.0f*percent_done)-1.5f,3));
|
||||
};
|
||||
|
||||
if(attacking && timediff<animtime)
|
||||
{
|
||||
if(throwingnade)
|
||||
{
|
||||
anim = MDL_GUN_ATTACK2;
|
||||
}
|
||||
else anim = MDL_GUN_ATTACK;
|
||||
};
|
||||
|
||||
if(player1->gunselect!=GUN_GRENADE && player1->gunselect!=GUN_KNIFE)
|
||||
{
|
||||
kick = -sin(pow((1.5f/100.0f*percent_done)-1.5f,3));
|
||||
};
|
||||
|
||||
if(attacking && timediff<animtime)
|
||||
{
|
||||
if(throwingnade)
|
||||
{
|
||||
anim = MDL_GUN_ATTACK2;
|
||||
}
|
||||
else anim = MDL_GUN_ATTACK;
|
||||
};
|
||||
|
||||
if(player1->gunselect!=GUN_GRENADE && player1->gunselect!=GUN_KNIFE)
|
||||
{
|
||||
k_rot = kick_rot(player1->gunselect)*kick;
|
||||
k_back = kick_back(player1->gunselect)*kick/10;
|
||||
};
|
||||
k_back = kick_back(player1->gunselect)*kick/10;
|
||||
};
|
||||
|
||||
int swayt = (lastmillis+1)/10 % 100;
|
||||
float swayspeed = (float) (sin((float)lastmillis/swayspeeddiv))/(swaymovediv/10.0f);
|
||||
@@ -505,14 +505,14 @@ struct weaponmove
|
||||
|
||||
sway.x *= swayspeed;
|
||||
sway.y *= swayspeed;
|
||||
sway.z *= swayupspeed;
|
||||
|
||||
pos.x = player1->o.x-base.x*k_back+sway.x;
|
||||
pos.y = player1->o.y-base.y*k_back+sway.y;
|
||||
pos.z = player1->o.z-base.z*k_back+sway.z;
|
||||
};
|
||||
};
|
||||
};
|
||||
sway.z *= swayupspeed;
|
||||
|
||||
pos.x = player1->o.x-base.x*k_back+sway.x;
|
||||
pos.y = player1->o.y-base.y*k_back+sway.y;
|
||||
pos.z = player1->o.z-base.z*k_back+sway.z;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
void rendermd3gun()
|
||||
{
|
||||
@@ -533,25 +533,25 @@ void rendermd3gun()
|
||||
};
|
||||
|
||||
vdist(dist, unitv, player1->o, worldpos);
|
||||
vdiv(unitv, dist);
|
||||
|
||||
md3model *weapon = models[firstweapon + player1->gunselect];
|
||||
md3model *akimbo = player1->akimbo && player1->gunselect==GUN_PISTOL ? models[firstweapon+NUMGUNS] : NULL;
|
||||
|
||||
weaponmove *w1, *w2;
|
||||
|
||||
if(akimbo)
|
||||
{
|
||||
w1 = new weaponmove(unitv, akimbolastaction[0]);
|
||||
w2 = new weaponmove(unitv, akimbolastaction[1]);
|
||||
akimbo->setanim(w2->anim);
|
||||
}
|
||||
else w1 = new weaponmove(unitv, player1->lastaction);
|
||||
|
||||
if(!w1) return;
|
||||
weapon->setanim(w1->anim);
|
||||
weapon->draw( w1->pos.x, w1->pos.z, w1->pos.y, player1->yaw + 90, player1->pitch+w1->k_rot, 1.0f, light);
|
||||
|
||||
vdiv(unitv, dist);
|
||||
|
||||
md3model *weapon = models[firstweapon + player1->gunselect];
|
||||
md3model *akimbo = player1->akimbo && player1->gunselect==GUN_PISTOL ? models[firstweapon+NUMGUNS] : NULL;
|
||||
|
||||
weaponmove *w1, *w2;
|
||||
|
||||
if(akimbo)
|
||||
{
|
||||
w1 = new weaponmove(unitv, akimbolastaction[0]);
|
||||
w2 = new weaponmove(unitv, akimbolastaction[1]);
|
||||
akimbo->setanim(w2->anim);
|
||||
}
|
||||
else w1 = new weaponmove(unitv, player1->lastaction);
|
||||
|
||||
if(!w1) return;
|
||||
weapon->setanim(w1->anim);
|
||||
weapon->draw( w1->pos.x, w1->pos.z, w1->pos.y, player1->yaw + 90, player1->pitch+w1->k_rot, 1.0f, light);
|
||||
|
||||
if(akimbo && w2) akimbo->draw( w2->pos.x, w2->pos.z, w2->pos.y, player1->yaw + 90, player1->pitch+w2->k_rot, 1.0f, light);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,6 +35,15 @@ void stop()
|
||||
demoloading = false;
|
||||
loopv(playerhistory) zapdynent(playerhistory[i]);
|
||||
playerhistory.setsize(0);
|
||||
// Added by Rick: Remove bots
|
||||
loopv(bots)
|
||||
{
|
||||
if (!bots[i]) continue;
|
||||
delete bots[i]->pBot;
|
||||
bots[i]->pBot = NULL;
|
||||
zapdynent(bots[i]);
|
||||
}
|
||||
bots.setsize(0);
|
||||
};
|
||||
|
||||
void stopifrecording() { if(demorecording) stop(); };
|
||||
|
||||
+237
-6
@@ -15,6 +15,13 @@ struct client // server side version of "dynent" type
|
||||
string mapvote;
|
||||
string name;
|
||||
int modevote;
|
||||
// Added by Rick: For bot voting
|
||||
bool addbot, kickbot, changebotskill;
|
||||
short botcount;
|
||||
string botteam, botname;
|
||||
short botskill;
|
||||
bool kickallbots;
|
||||
// End add
|
||||
};
|
||||
|
||||
vector<client> clients;
|
||||
@@ -29,17 +36,18 @@ int numclients()
|
||||
return num;
|
||||
};
|
||||
|
||||
struct server_entity // server side version of "entity" type
|
||||
{
|
||||
bool spawned;
|
||||
int spawnsecs;
|
||||
};
|
||||
|
||||
vector<server_entity> sents;
|
||||
|
||||
bool notgotitems = true; // true when map has changed and waiting for clients to send item
|
||||
int mode = 0;
|
||||
|
||||
// Added by Rick
|
||||
#ifndef STANDALONE
|
||||
extern void kickbot(const char *szName);
|
||||
extern void kickallbots(void);
|
||||
#endif
|
||||
// End add
|
||||
|
||||
void restoreserverstate(vector<entity> &ents) // hack: called from savegame code, only works in SP
|
||||
{
|
||||
loopv(sents)
|
||||
@@ -286,6 +294,207 @@ bool vote(char *map, int reqmode, int sender)
|
||||
return true;
|
||||
};
|
||||
|
||||
// Added by Rick: Vote for bot commands
|
||||
|
||||
void resetbotvotes()
|
||||
{
|
||||
loopv(clients)
|
||||
{
|
||||
clients[i].addbot = false;
|
||||
clients[i].kickbot = false;
|
||||
clients[i].changebotskill = false;
|
||||
clients[i].kickallbots = false;
|
||||
clients[i].botcount = 0;
|
||||
clients[i].botteam[0] = 0;
|
||||
clients[i].botname[0] = 0;
|
||||
clients[i].botskill = -1;
|
||||
}
|
||||
};
|
||||
|
||||
bool addbotvote(int count, char *team, int skill, char *name, int sender)
|
||||
{
|
||||
#ifndef STANDALONE
|
||||
clients[sender].addbot = true;
|
||||
clients[sender].kickbot = false;
|
||||
clients[sender].changebotskill = false;
|
||||
clients[sender].botcount = (count>=0) ? count : 0;
|
||||
if (team && team[0]) strcpy_s(clients[sender].botteam, team);
|
||||
else clients[sender].botteam[0] = 0;
|
||||
clients[sender].botskill = skill;
|
||||
if (name && name[0]) strcpy_s(clients[sender].botname, name);
|
||||
else clients[sender].botname[0] = 0;
|
||||
int yes = 0, no = 0;
|
||||
loopv(clients) if(clients[i].type!=ST_EMPTY)
|
||||
{
|
||||
if (clients[i].addbot)
|
||||
{
|
||||
if (!strcmp(clients[i].botteam, team) && !strcmp(clients[i].botname, name) &&
|
||||
(clients[i].botskill == skill) &&
|
||||
(clients[i].botcount == clients[sender].botcount))
|
||||
yes++;
|
||||
else
|
||||
no++;
|
||||
}
|
||||
else no++;
|
||||
}
|
||||
if(yes==1 && no==0) return true; // single player
|
||||
sprintf_sd(msg)("%s suggests to add a bot", clients[sender].name);
|
||||
if (team && team[0])
|
||||
{
|
||||
strcat(msg, " on team ");
|
||||
strcat(msg, team);
|
||||
}
|
||||
|
||||
if (skill!=-1)
|
||||
{
|
||||
strcat(msg, ", with skill ");
|
||||
strcat(msg, SkillNrToSkillName(skill));
|
||||
}
|
||||
|
||||
if (name && name[0])
|
||||
{
|
||||
strcat(msg, " named ");
|
||||
strcat(msg, name);
|
||||
}
|
||||
|
||||
sendservmsg(msg);
|
||||
if(yes/(float)(yes+no) <= 0.5f) return false;
|
||||
sendservmsg("vote passed");
|
||||
resetbotvotes();
|
||||
#endif
|
||||
return true;
|
||||
};
|
||||
|
||||
bool kickbotvote(int specific, char *name, int sender)
|
||||
{
|
||||
clients[sender].addbot = false;
|
||||
clients[sender].kickbot = true;
|
||||
clients[sender].changebotskill = false;
|
||||
clients[sender].kickallbots = !specific;
|
||||
if (name && name[0]) strcpy_s(clients[sender].botname, name);
|
||||
else clients[sender].botname[0] = 0;
|
||||
int yes = 0, no = 0;
|
||||
loopv(clients) if(clients[i].type!=ST_EMPTY)
|
||||
{
|
||||
if (clients[i].kickbot)
|
||||
{
|
||||
if (clients[sender].kickallbots)
|
||||
{
|
||||
if (clients[i].kickallbots) yes++;
|
||||
else no++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!clients[i].kickallbots && !strcmp(clients[i].botname, name))
|
||||
yes++;
|
||||
else
|
||||
no++;
|
||||
}
|
||||
}
|
||||
else no++;
|
||||
}
|
||||
if(yes==1 && no==0) return true; // single player
|
||||
|
||||
char msg[256];
|
||||
if (clients[sender].kickallbots)
|
||||
sprintf(msg, "%s suggests to kick all bots", clients[sender].name);
|
||||
else
|
||||
sprintf(msg, "%s suggests to kick bot %s", clients[sender].name,
|
||||
clients[sender].botname);
|
||||
|
||||
sendservmsg(msg);
|
||||
if(yes/(float)(yes+no) <= 0.5f) return false;
|
||||
sendservmsg("vote passed");
|
||||
resetbotvotes();
|
||||
return true;
|
||||
};
|
||||
|
||||
bool botskillvote(int skill, int sender)
|
||||
{
|
||||
#ifndef STANDALONE
|
||||
clients[sender].addbot = false;
|
||||
clients[sender].kickbot = false;
|
||||
clients[sender].changebotskill = true;
|
||||
clients[sender].botskill = skill;
|
||||
int yes = 0, no = 0;
|
||||
loopv(clients) if(clients[i].type!=ST_EMPTY)
|
||||
{
|
||||
if (clients[i].changebotskill)
|
||||
{
|
||||
if (clients[sender].botskill == clients[i].botskill) yes++;
|
||||
else no++;
|
||||
}
|
||||
else no++;
|
||||
}
|
||||
if(yes==1 && no==0) return true; // single player
|
||||
|
||||
sprintf_sd(msg)("%s suggests to change the skill of all bots to: %s", clients[sender].name,
|
||||
SkillNrToSkillName(clients[sender].botskill));
|
||||
sendservmsg(msg);
|
||||
if(yes/(float)(yes+no) <= 0.5f) return false;
|
||||
sendservmsg("vote passed");
|
||||
resetbotvotes();
|
||||
#endif
|
||||
return true;
|
||||
};
|
||||
|
||||
void botcommand(uchar *&p, char *text, int sender)
|
||||
{
|
||||
int type = getint(p);
|
||||
switch(EBotCommands(type))
|
||||
{
|
||||
case COMMAND_ADDBOT:
|
||||
{
|
||||
string name, team;
|
||||
int count = getint(p);
|
||||
int skill = getint(p);
|
||||
sgetstr();
|
||||
strcpy(team, text);
|
||||
sgetstr();
|
||||
strcpy(name, text);
|
||||
#ifndef STANDALONE
|
||||
if (addbotvote(count, team, skill, name, sender))
|
||||
{
|
||||
while(count>0)
|
||||
{
|
||||
BotManager.CreateBot(team, SkillNrToSkillName(skill), name);
|
||||
count--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case COMMAND_KICKBOT:
|
||||
{
|
||||
int specific = getint(p);
|
||||
|
||||
if (specific)
|
||||
sgetstr();
|
||||
#ifndef STANDALONE
|
||||
if (kickbotvote(specific, text, sender))
|
||||
{
|
||||
if (specific)
|
||||
kickbot(text);
|
||||
else
|
||||
kickallbots();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
case COMMAND_BOTSKILL:
|
||||
{
|
||||
int skill = getint(p);
|
||||
#ifndef STANDALONE
|
||||
if (botskillvote(skill, sender))
|
||||
{
|
||||
BotManager.ChangeBotSkill(skill, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End add
|
||||
|
||||
// force map change, EDIT: AH
|
||||
void changemap()
|
||||
{
|
||||
@@ -378,6 +587,12 @@ void process(ENetPacket * packet, int sender) // sender may be -1
|
||||
int n = getint(p);
|
||||
pickup(n, getint(p), sender);
|
||||
break;
|
||||
};
|
||||
|
||||
case SV_BOTITEMPICKUP:
|
||||
{
|
||||
loopi(2) getint(p);
|
||||
break;
|
||||
};
|
||||
|
||||
case SV_PING:
|
||||
@@ -411,6 +626,21 @@ void process(ENetPacket * packet, int sender) // sender may be -1
|
||||
send(sender, recvmap(sender));
|
||||
return;
|
||||
|
||||
// Added by Rick: Bot specifc messages
|
||||
case SV_ADDBOT:
|
||||
getint(p);
|
||||
sgetstr();
|
||||
//strcpy_s(clients[cn].name, text);
|
||||
sgetstr();
|
||||
getint(p);
|
||||
break;
|
||||
case SV_BOTCOMMAND: // Client asked server for a bot command
|
||||
{
|
||||
botcommand(p, text, sender);
|
||||
break;
|
||||
}
|
||||
// End add by Rick
|
||||
|
||||
// EDIT: AH
|
||||
case SV_FLAGPICKUP:
|
||||
{
|
||||
@@ -559,6 +789,7 @@ void resetserverifempty()
|
||||
clients.setsize(0);
|
||||
smapname[0] = 0;
|
||||
resetvotes();
|
||||
resetbotvotes(); // Added by Rick
|
||||
resetitems();
|
||||
mode = 0;
|
||||
mapreload = false;
|
||||
|
||||
@@ -35,6 +35,20 @@ const char *modenames[] =
|
||||
//const char *modestr(int n) { return (n>=-2 && n<12) ? modenames[n+2] : "unknown"; };
|
||||
const char *modestr(int n) { return (n>=0 && n<6) ? modenames[n] : "unknown"; };
|
||||
|
||||
/* Modified by Rick: New messages and different sizes for existing ones
|
||||
char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes
|
||||
{
|
||||
SV_INITS2C, 4, SV_INITC2S, 0, SV_POS, 12, SV_TEXT, 0, SV_SOUND, 2, SV_CDIS, 2,
|
||||
SV_DIED, 2, SV_DAMAGE, 4, SV_SHOsT, 8, SV_FRAGS, 2,
|
||||
SV_TIMEUP, 2, SV_EDITENT, 10, SV_MAPRELOAD, 2, SV_ITEMACC, 2,
|
||||
SV_MAPCHANGE, 0, SV_ITEMSPAWN, 2, SV_ITEMPICKUP, 3, SV_DENIED, 2,
|
||||
SV_PING, 2, SV_PONG, 2, SV_CLIENTPING, 2, SV_GAMEMODE, 2,
|
||||
SV_EDITH, 7, SV_EDITT, 7, SV_EDITS, 6, SV_EDITD, 6, SV_EDITE, 6,
|
||||
SV_SENDMAP, 0, SV_RECVMAP, 1, SV_SERVMSG, 0, SV_ITEMLIST, 0,
|
||||
SV_EXT, 0,
|
||||
-1
|
||||
};
|
||||
*/
|
||||
|
||||
char msgsizesl[] = // size inclusive message token, 0 for variable or not-checked sizes
|
||||
{
|
||||
@@ -47,6 +61,11 @@ char msgsizesl[] = // size inclusive message token, 0 for variable
|
||||
SV_SENDMAP, 0, SV_RECVMAP, 1, SV_SERVMSG, 0, SV_ITEMLIST, 0, SV_WEAPCHANGE, 2,
|
||||
SV_MODELSKIN, 2,
|
||||
SV_FLAGPICKUP, 2, SV_FLAGDROP, 2, SV_FLAGRETURN, 2, SV_FLAGSCORE, 2, SV_FLAGINFO, 0, SV_FLAGS, 2, // EDIT: AH
|
||||
// Added by Rick: Bot specific messages
|
||||
SV_BOTSOUND, 3, SV_BOTDIS, 2, SV_BOTDIED, 4, SV_CLIENT2BOTDMG, 4, SV_BOT2BOTDMG, 2,
|
||||
SV_BOTFRAGS, 3, SV_ADDBOT, 5, SV_BOTUPDATE, 12, SV_BOTCOMMAND, 0,
|
||||
// End add
|
||||
SV_BOTITEMPICKUP, 3, SV_BOT2CLIENTDMG, 5, SV_DIEDBYBOT, 2,
|
||||
SV_EXT, 0,
|
||||
-1
|
||||
};
|
||||
|
||||
+234
-227
@@ -1,227 +1,234 @@
|
||||
// sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform)
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
//#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback
|
||||
#define USE_MIXER
|
||||
//#endif
|
||||
|
||||
VARP(soundvol, 0, 255, 255);
|
||||
VARP(musicvol, 0, 128, 255);
|
||||
bool nosound = false;
|
||||
|
||||
#define MAXCHAN 32
|
||||
#define SOUNDFREQ 22050
|
||||
|
||||
struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN];
|
||||
|
||||
#ifdef USE_MIXER
|
||||
#include "SDL_mixer.h"
|
||||
#define MAXVOL MIX_MAX_VOLUME
|
||||
Mix_Music *mod = NULL;
|
||||
void *stream = NULL;
|
||||
#else
|
||||
#include "fmod.h"
|
||||
#define MAXVOL 255
|
||||
FMUSIC_MODULE *mod = NULL;
|
||||
FSOUND_STREAM *stream = NULL;
|
||||
#endif
|
||||
|
||||
void stopsound()
|
||||
{
|
||||
if(nosound) return;
|
||||
if(mod)
|
||||
{
|
||||
#ifdef USE_MIXER
|
||||
Mix_HaltMusic();
|
||||
Mix_FreeMusic(mod);
|
||||
#else
|
||||
FMUSIC_FreeSong(mod);
|
||||
#endif
|
||||
mod = NULL;
|
||||
};
|
||||
if(stream)
|
||||
{
|
||||
#ifndef USE_MIXER
|
||||
FSOUND_Stream_Close(stream);
|
||||
#endif
|
||||
stream = NULL;
|
||||
};
|
||||
};
|
||||
|
||||
VAR(soundbufferlen, 128, 1024, 4096);
|
||||
|
||||
void initsound()
|
||||
{
|
||||
memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN);
|
||||
#ifdef USE_MIXER
|
||||
if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0)
|
||||
{
|
||||
conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError());
|
||||
nosound = true;
|
||||
};
|
||||
Mix_AllocateChannels(MAXCHAN);
|
||||
#else
|
||||
if(FSOUND_GetVersion()<FMOD_VERSION) fatal("old FMOD dll");
|
||||
if(!FSOUND_Init(SOUNDFREQ, MAXCHAN, FSOUND_INIT_GLOBALFOCUS))
|
||||
{
|
||||
conoutf("sound init failed (FMOD): %d", FSOUND_GetError());
|
||||
nosound = true;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
void music(char *name)
|
||||
{
|
||||
if(nosound) return;
|
||||
stopsound();
|
||||
if(soundvol && musicvol)
|
||||
{
|
||||
string sn;
|
||||
strcpy_s(sn, "packages/");
|
||||
strcat_s(sn, name);
|
||||
#ifdef USE_MIXER
|
||||
if(mod = Mix_LoadMUS(path(sn)))
|
||||
{
|
||||
Mix_PlayMusic(mod, -1);
|
||||
Mix_VolumeMusic((musicvol*MAXVOL)/255);
|
||||
};
|
||||
#else
|
||||
if(mod = FMUSIC_LoadSong(path(sn)))
|
||||
{
|
||||
FMUSIC_PlaySong(mod);
|
||||
FMUSIC_SetMasterVolume(mod, musicvol);
|
||||
}
|
||||
else if(stream = FSOUND_Stream_Open(path(sn), FSOUND_LOOP_NORMAL, 0, 0))
|
||||
{
|
||||
int chan = FSOUND_Stream_Play(FSOUND_FREE, stream);
|
||||
if(chan>=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); };
|
||||
}
|
||||
else
|
||||
{
|
||||
conoutf("could not play music: %s", sn);
|
||||
};
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
COMMAND(music, ARG_1STR);
|
||||
|
||||
#ifdef USE_MIXER
|
||||
vector<Mix_Chunk *> samples;
|
||||
#else
|
||||
vector<FSOUND_SAMPLE *> samples;
|
||||
#endif
|
||||
|
||||
cvector snames;
|
||||
|
||||
int registersound(char *name)
|
||||
{
|
||||
loopv(snames) if(strcmp(snames[i], name)==0) return i;
|
||||
snames.add(newstring(name));
|
||||
samples.add(NULL);
|
||||
return samples.length()-1;
|
||||
};
|
||||
|
||||
COMMAND(registersound, ARG_1EST);
|
||||
|
||||
void cleansound()
|
||||
{
|
||||
if(nosound) return;
|
||||
stopsound();
|
||||
#ifdef USE_MIXER
|
||||
Mix_CloseAudio();
|
||||
#else
|
||||
FSOUND_Close();
|
||||
#endif
|
||||
};
|
||||
|
||||
VAR(stereo, 0, 1, 1);
|
||||
|
||||
void updatechanvol(int chan, vec *loc)
|
||||
{
|
||||
int vol = soundvol, pan = 255/2;
|
||||
if(loc)
|
||||
{
|
||||
vdist(dist, v, *loc, player1->o);
|
||||
vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation
|
||||
if(vol<0) vol = 0;
|
||||
if(stereo && (v.x != 0 || v.y != 0))
|
||||
{
|
||||
float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis
|
||||
pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right)
|
||||
};
|
||||
};
|
||||
vol = (vol*MAXVOL)/255;
|
||||
#ifdef USE_MIXER
|
||||
Mix_Volume(chan, vol);
|
||||
Mix_SetPanning(chan, 255-pan, pan);
|
||||
#else
|
||||
FSOUND_SetVolume(chan, vol);
|
||||
FSOUND_SetPan(chan, pan);
|
||||
#endif
|
||||
};
|
||||
|
||||
void newsoundloc(int chan, vec *loc)
|
||||
{
|
||||
assert(chan>=0 && chan<MAXCHAN);
|
||||
soundlocs[chan].loc = *loc;
|
||||
soundlocs[chan].inuse = true;
|
||||
};
|
||||
|
||||
void updatevol()
|
||||
{
|
||||
if(nosound) return;
|
||||
loopi(MAXCHAN) if(soundlocs[i].inuse)
|
||||
{
|
||||
#ifdef USE_MIXER
|
||||
if(Mix_Playing(i))
|
||||
#else
|
||||
if(FSOUND_IsPlaying(i))
|
||||
#endif
|
||||
updatechanvol(i, &soundlocs[i].loc);
|
||||
else soundlocs[i].inuse = false;
|
||||
};
|
||||
};
|
||||
|
||||
void playsoundc(int n) { addmsg(0, 2, SV_SOUND, n); playsound(n); };
|
||||
|
||||
int soundsatonce = 0, lastsoundmillis = 0;
|
||||
|
||||
void playsound(int n, vec *loc)
|
||||
{
|
||||
if(nosound) return;
|
||||
if(!soundvol) return;
|
||||
if(lastmillis==lastsoundmillis) soundsatonce++; else soundsatonce = 1;
|
||||
lastsoundmillis = lastmillis;
|
||||
if(soundsatonce>5) return; // avoid bursts of sounds with heavy packetloss and in sp
|
||||
if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; };
|
||||
|
||||
if(!samples[n])
|
||||
{
|
||||
sprintf_sd(buf)("packages/audio/sounds/%s.wav", snames[n]);
|
||||
|
||||
#ifdef USE_MIXER
|
||||
samples[n] = Mix_LoadWAV(path(buf));
|
||||
#else
|
||||
samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0);
|
||||
#endif
|
||||
|
||||
if(!samples[n]) { conoutf("failed to load sample: %s", (int)buf); return; };
|
||||
};
|
||||
|
||||
#ifdef USE_MIXER
|
||||
int chan = Mix_PlayChannel(-1, samples[n], 0);
|
||||
#else
|
||||
int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true);
|
||||
#endif
|
||||
if(chan<0) return;
|
||||
if(loc) newsoundloc(chan, loc);
|
||||
updatechanvol(chan, loc);
|
||||
#ifndef USE_MIXER
|
||||
FSOUND_SetPaused(chan, false);
|
||||
#endif
|
||||
};
|
||||
|
||||
void sound(int n) { playsound(n, NULL); };
|
||||
COMMAND(sound, ARG_1INT);
|
||||
// sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform)
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
//#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback
|
||||
#define USE_MIXER
|
||||
//#endif
|
||||
|
||||
VARP(soundvol, 0, 255, 255);
|
||||
VARP(musicvol, 0, 128, 255);
|
||||
bool nosound = false;
|
||||
|
||||
#define MAXCHAN 32
|
||||
#define SOUNDFREQ 22050
|
||||
|
||||
struct soundloc { vec loc; bool inuse; } soundlocs[MAXCHAN];
|
||||
|
||||
#ifdef USE_MIXER
|
||||
#include "SDL_mixer.h"
|
||||
#define MAXVOL MIX_MAX_VOLUME
|
||||
Mix_Music *mod = NULL;
|
||||
void *stream = NULL;
|
||||
#else
|
||||
#include "fmod.h"
|
||||
#define MAXVOL 255
|
||||
FMUSIC_MODULE *mod = NULL;
|
||||
FSOUND_STREAM *stream = NULL;
|
||||
#endif
|
||||
|
||||
void stopsound()
|
||||
{
|
||||
if(nosound) return;
|
||||
if(mod)
|
||||
{
|
||||
#ifdef USE_MIXER
|
||||
Mix_HaltMusic();
|
||||
Mix_FreeMusic(mod);
|
||||
#else
|
||||
FMUSIC_FreeSong(mod);
|
||||
#endif
|
||||
mod = NULL;
|
||||
};
|
||||
if(stream)
|
||||
{
|
||||
#ifndef USE_MIXER
|
||||
FSOUND_Stream_Close(stream);
|
||||
#endif
|
||||
stream = NULL;
|
||||
};
|
||||
};
|
||||
|
||||
VAR(soundbufferlen, 128, 1024, 4096);
|
||||
|
||||
void initsound()
|
||||
{
|
||||
memset(soundlocs, 0, sizeof(soundloc)*MAXCHAN);
|
||||
#ifdef USE_MIXER
|
||||
if(Mix_OpenAudio(SOUNDFREQ, MIX_DEFAULT_FORMAT, 2, soundbufferlen)<0)
|
||||
{
|
||||
conoutf("sound init failed (SDL_mixer): %s", (size_t)Mix_GetError());
|
||||
nosound = true;
|
||||
};
|
||||
Mix_AllocateChannels(MAXCHAN);
|
||||
#else
|
||||
if(FSOUND_GetVersion()<FMOD_VERSION) fatal("old FMOD dll");
|
||||
if(!FSOUND_Init(SOUNDFREQ, MAXCHAN, FSOUND_INIT_GLOBALFOCUS))
|
||||
{
|
||||
conoutf("sound init failed (FMOD): %d", FSOUND_GetError());
|
||||
nosound = true;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
void music(char *name)
|
||||
{
|
||||
if(nosound) return;
|
||||
stopsound();
|
||||
if(soundvol && musicvol)
|
||||
{
|
||||
string sn;
|
||||
strcpy_s(sn, "packages/");
|
||||
strcat_s(sn, name);
|
||||
#ifdef USE_MIXER
|
||||
if(mod = Mix_LoadMUS(path(sn)))
|
||||
{
|
||||
Mix_PlayMusic(mod, -1);
|
||||
Mix_VolumeMusic((musicvol*MAXVOL)/255);
|
||||
};
|
||||
#else
|
||||
if(mod = FMUSIC_LoadSong(path(sn)))
|
||||
{
|
||||
FMUSIC_PlaySong(mod);
|
||||
FMUSIC_SetMasterVolume(mod, musicvol);
|
||||
}
|
||||
else if(stream = FSOUND_Stream_Open(path(sn), FSOUND_LOOP_NORMAL, 0, 0))
|
||||
{
|
||||
int chan = FSOUND_Stream_Play(FSOUND_FREE, stream);
|
||||
if(chan>=0) { FSOUND_SetVolume(chan, (musicvol*MAXVOL)/255); FSOUND_SetPaused(chan, false); };
|
||||
}
|
||||
else
|
||||
{
|
||||
conoutf("could not play music: %s", sn);
|
||||
};
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
COMMAND(music, ARG_1STR);
|
||||
|
||||
#ifdef USE_MIXER
|
||||
vector<Mix_Chunk *> samples;
|
||||
#else
|
||||
vector<FSOUND_SAMPLE *> samples;
|
||||
#endif
|
||||
|
||||
cvector snames;
|
||||
|
||||
int registersound(char *name)
|
||||
{
|
||||
loopv(snames) if(strcmp(snames[i], name)==0) return i;
|
||||
snames.add(newstring(name));
|
||||
samples.add(NULL);
|
||||
return samples.length()-1;
|
||||
};
|
||||
|
||||
COMMAND(registersound, ARG_1EST);
|
||||
|
||||
void cleansound()
|
||||
{
|
||||
if(nosound) return;
|
||||
stopsound();
|
||||
#ifdef USE_MIXER
|
||||
Mix_CloseAudio();
|
||||
#else
|
||||
FSOUND_Close();
|
||||
#endif
|
||||
};
|
||||
|
||||
VAR(stereo, 0, 1, 1);
|
||||
|
||||
void updatechanvol(int chan, vec *loc)
|
||||
{
|
||||
int vol = soundvol, pan = 255/2;
|
||||
if(loc)
|
||||
{
|
||||
vdist(dist, v, *loc, player1->o);
|
||||
vol -= (int)(dist*3*soundvol/255); // simple mono distance attenuation
|
||||
if(vol<0) vol = 0;
|
||||
if(stereo && (v.x != 0 || v.y != 0))
|
||||
{
|
||||
float yaw = -atan2(v.x, v.y) - player1->yaw*(PI / 180.0f); // relative angle of sound along X-Y axis
|
||||
pan = int(255.9f*(0.5*sin(yaw)+0.5f)); // range is from 0 (left) to 255 (right)
|
||||
};
|
||||
};
|
||||
vol = (vol*MAXVOL)/255;
|
||||
#ifdef USE_MIXER
|
||||
Mix_Volume(chan, vol);
|
||||
Mix_SetPanning(chan, 255-pan, pan);
|
||||
#else
|
||||
FSOUND_SetVolume(chan, vol);
|
||||
FSOUND_SetPan(chan, pan);
|
||||
#endif
|
||||
};
|
||||
|
||||
void newsoundloc(int chan, vec *loc)
|
||||
{
|
||||
assert(chan>=0 && chan<MAXCHAN);
|
||||
soundlocs[chan].loc = *loc;
|
||||
soundlocs[chan].inuse = true;
|
||||
};
|
||||
|
||||
void updatevol()
|
||||
{
|
||||
if(nosound) return;
|
||||
loopi(MAXCHAN) if(soundlocs[i].inuse)
|
||||
{
|
||||
#ifdef USE_MIXER
|
||||
if(Mix_Playing(i))
|
||||
#else
|
||||
if(FSOUND_IsPlaying(i))
|
||||
#endif
|
||||
updatechanvol(i, &soundlocs[i].loc);
|
||||
else soundlocs[i].inuse = false;
|
||||
};
|
||||
};
|
||||
|
||||
void playsoundc(int n) { addmsg(0, 2, SV_SOUND, n); playsound(n); };
|
||||
|
||||
// Added by Rick: For bots
|
||||
void botplaysound(int n, dynent *b)
|
||||
{
|
||||
addmsg(0, 3, SV_BOTSOUND, n, BotManager.GetBotIndex(b)); playsound(n, &b->o);
|
||||
}
|
||||
// End add by Rick
|
||||
|
||||
int soundsatonce = 0, lastsoundmillis = 0;
|
||||
|
||||
void playsound(int n, vec *loc)
|
||||
{
|
||||
if(nosound) return;
|
||||
if(!soundvol) return;
|
||||
if(lastmillis==lastsoundmillis) soundsatonce++; else soundsatonce = 1;
|
||||
lastsoundmillis = lastmillis;
|
||||
if(soundsatonce>5) return; // avoid bursts of sounds with heavy packetloss and in sp
|
||||
if(n<0 || n>=samples.length()) { conoutf("unregistered sound: %d", n); return; };
|
||||
|
||||
if(!samples[n])
|
||||
{
|
||||
sprintf_sd(buf)("packages/audio/sounds/%s.wav", snames[n]);
|
||||
|
||||
#ifdef USE_MIXER
|
||||
samples[n] = Mix_LoadWAV(path(buf));
|
||||
#else
|
||||
samples[n] = FSOUND_Sample_Load(n, path(buf), FSOUND_LOOP_OFF, 0, 0);
|
||||
#endif
|
||||
|
||||
if(!samples[n]) { conoutf("failed to load sample: %s", (int)buf); return; };
|
||||
};
|
||||
|
||||
#ifdef USE_MIXER
|
||||
int chan = Mix_PlayChannel(-1, samples[n], 0);
|
||||
#else
|
||||
int chan = FSOUND_PlaySoundEx(FSOUND_FREE, samples[n], NULL, true);
|
||||
#endif
|
||||
if(chan<0) return;
|
||||
if(loc) newsoundloc(chan, loc);
|
||||
updatechanvol(chan, loc);
|
||||
#ifndef USE_MIXER
|
||||
FSOUND_SetPaused(chan, false);
|
||||
#endif
|
||||
};
|
||||
|
||||
void sound(int n) { playsound(n, NULL); };
|
||||
COMMAND(sound, ARG_1INT);
|
||||
|
||||
+216
-96
@@ -11,92 +11,95 @@ vec sg[SGRAYS];
|
||||
//change the particales
|
||||
guninfo guns[NUMGUNS] =
|
||||
{
|
||||
{ S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, "knife" },
|
||||
{ S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, "knife" },
|
||||
{ S_PISTOL, S_RPISTOL, 1400, 170, 20, 0, 0, 80, 10, 8, 6, 5, "pistol" }, // *SGRAYS
|
||||
{ S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 6, 0, 0, 1, 35, 7, 9, 9, "shotgun" }, //reload time is for 1 shell from 7 too powerful to 6
|
||||
{ S_SUBGUN, S_RSUBGUN, 1650, 80, 17, 0, 0, 70, 15, 30, 1, 2, "subgun" },
|
||||
{ S_SNIPER, S_RSNIPER, 1950, 1500, 72, 0, 0, 60, 50, 5, 4, 4, "sniper" },
|
||||
{ S_ASSULT, S_RASSULT, 2000, 130, 20, 0, 0, 20, 40, 20, 0, 2, "assult" }, //recoil was 44
|
||||
{ S_GRENADE, S_NULL, 1000, 2500, 150, 20, 6, 1, 1, 1, 3, 1, "grenade" },
|
||||
{ S_GRENADE, S_NULL, 1000, 2500, 150, 20, 6, 1, 1, 1, 3, 1, "grenade" },
|
||||
};
|
||||
|
||||
|
||||
bool gun_changed = false;
|
||||
|
||||
void weapon(int gun)
|
||||
{
|
||||
if(gun>=0) gun %= G_NUM;
|
||||
else gun = G_NUM-(gun % G_NUM);
|
||||
gun_changed = true;
|
||||
switch(gun)
|
||||
{
|
||||
case G_PRIMARY: player1->gunselect=player1->primary; break;
|
||||
case G_SECONDARY: player1->gunselect=GUN_PISTOL; break;
|
||||
case G_MELEE: player1->gunselect=GUN_KNIFE; break;
|
||||
case G_GRENADE: player1->gunselect=GUN_GRENADE; break;
|
||||
};
|
||||
};
|
||||
|
||||
void shiftweapon(int i)
|
||||
{
|
||||
int gun;
|
||||
switch(player1->gunselect)
|
||||
{
|
||||
case GUN_KNIFE: gun=G_MELEE; break;
|
||||
case GUN_PISTOL: gun=G_SECONDARY; break;
|
||||
case GUN_GRENADE: gun=G_GRENADE; break;
|
||||
default: gun=G_PRIMARY; break;
|
||||
};
|
||||
gun += i;
|
||||
weapon(gun);
|
||||
bool gun_changed = false;
|
||||
|
||||
void weapon(int gun)
|
||||
{
|
||||
if(gun>=0) gun %= G_NUM;
|
||||
else gun = G_NUM-(gun % G_NUM);
|
||||
gun_changed = true;
|
||||
switch(gun)
|
||||
{
|
||||
case G_PRIMARY: player1->gunselect=player1->primary; break;
|
||||
case G_SECONDARY: player1->gunselect=GUN_PISTOL; break;
|
||||
case G_MELEE: player1->gunselect=GUN_KNIFE; break;
|
||||
case G_GRENADE: player1->gunselect=GUN_GRENADE; break;
|
||||
};
|
||||
};
|
||||
|
||||
void shiftweapon(int i)
|
||||
{
|
||||
int gun;
|
||||
switch(player1->gunselect)
|
||||
{
|
||||
case GUN_KNIFE: gun=G_MELEE; break;
|
||||
case GUN_PISTOL: gun=G_SECONDARY; break;
|
||||
case GUN_GRENADE: gun=G_GRENADE; break;
|
||||
default: gun=G_PRIMARY; break;
|
||||
};
|
||||
gun += i;
|
||||
weapon(gun);
|
||||
}
|
||||
|
||||
COMMAND(weapon, ARG_1INT);
|
||||
COMMAND(weapon, ARG_1INT);
|
||||
COMMAND(shiftweapon, ARG_1INT);
|
||||
|
||||
void reload()
|
||||
void reload(dynent *d)
|
||||
{
|
||||
bool akimbo = player1->gunselect==GUN_PISTOL && player1->akimbo!=0;
|
||||
if(!d) return;
|
||||
|
||||
if(player1->gunselect==GUN_KNIFE || player1->gunselect==GUN_GRENADE) return;
|
||||
if(akimbo && player1->mag[player1->gunselect]>=(guns[player1->gunselect].magsize * 2)) return;
|
||||
else if(player1->mag[player1->gunselect]>=guns[player1->gunselect].magsize && player1->akimbo==0) return;
|
||||
if(player1->ammo[player1->gunselect]<=0) return;
|
||||
if(player1->reloading) return;
|
||||
bool akimbo = d->gunselect==GUN_PISTOL && d->akimbo!=0;
|
||||
|
||||
if(d->gunselect==GUN_KNIFE || d->gunselect==GUN_GRENADE) return;
|
||||
if(akimbo && d->mag[d->gunselect]>=(guns[d->gunselect].magsize * 2)) return;
|
||||
else if(d->mag[d->gunselect]>=guns[d->gunselect].magsize && d->akimbo==0) return;
|
||||
if(d->ammo[d->gunselect]<=0) return;
|
||||
if(d->reloading) return;
|
||||
|
||||
player1->reloading = true;
|
||||
player1->lastaction = lastmillis;
|
||||
|
||||
if(akimbo)
|
||||
{
|
||||
akimbolastaction[akimboside?1:0] = lastmillis;
|
||||
akimbolastaction[akimboside?0:1] = lastmillis;// + (reloadtime(GUN_PISTOL)/2);
|
||||
d->reloading = true;
|
||||
d->lastaction = lastmillis;
|
||||
|
||||
if(akimbo)
|
||||
{
|
||||
akimbolastaction[akimboside?1:0] = lastmillis;
|
||||
akimbolastaction[akimboside?0:1] = lastmillis;// + (reloadtime(GUN_PISTOL)/2);
|
||||
};
|
||||
|
||||
player1->gunwait = guns[player1->gunselect].reloadtime;
|
||||
d->gunwait = guns[d->gunselect].reloadtime;
|
||||
|
||||
//temp hack in drawhudgun() so no guns drawn while reloading, needs fixed
|
||||
|
||||
int a = guns[player1->gunselect].magsize - player1->mag[player1->gunselect];
|
||||
if(player1->gunselect==GUN_PISTOL && player1->akimbo!=0)
|
||||
a = guns[player1->gunselect].magsize * 2 - player1->mag[player1->gunselect];
|
||||
int a = guns[d->gunselect].magsize - d->mag[d->gunselect];
|
||||
if(d->gunselect==GUN_PISTOL && d->akimbo!=0)
|
||||
a = guns[d->gunselect].magsize * 2 - d->mag[d->gunselect];
|
||||
|
||||
if (a >= player1->ammo[player1->gunselect])
|
||||
if (a >= d->ammo[d->gunselect])
|
||||
{
|
||||
player1->mag[player1->gunselect] += player1->ammo[player1->gunselect];
|
||||
player1->ammo[player1->gunselect] = 0;
|
||||
d->mag[d->gunselect] += d->ammo[d->gunselect];
|
||||
d->ammo[d->gunselect] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
player1->mag[player1->gunselect] += a;
|
||||
player1->ammo[player1->gunselect] -= a;
|
||||
d->mag[d->gunselect] += a;
|
||||
d->ammo[d->gunselect] -= a;
|
||||
}
|
||||
|
||||
if(akimbo) playsoundc(S_RAKIMBO);
|
||||
else playsoundc(guns[player1->gunselect].reload);
|
||||
if(akimbo) playsoundc(S_RAKIMBO);
|
||||
else playsoundc(guns[d->gunselect].reload);
|
||||
};
|
||||
|
||||
COMMAND(reload,ARG_NONE);
|
||||
|
||||
void selfreload() { reload(player1); };
|
||||
COMMANDN(reload, selfreload, ARG_NONE);
|
||||
|
||||
int reloadtime(int gun) { return guns[gun].reloadtime; };
|
||||
int attackdelay(int gun) { return guns[gun].attackdelay; };
|
||||
@@ -118,7 +121,8 @@ void createrays(vec &from, vec &to) // create random spread of rays
|
||||
};
|
||||
};
|
||||
|
||||
bool intersect(dynent *d, vec &from, vec &to) // if lineseg hits entity bounding box
|
||||
//bool intersect(dynent *d, vec &from, vec &to) // if lineseg hits entity bounding box
|
||||
bool intersect(dynent *d, vec &from, vec &to, vec *end) // if lineseg hits entity bounding box
|
||||
{
|
||||
vec v = to, w = d->o, *p;
|
||||
vsub(v, from);
|
||||
@@ -158,6 +162,19 @@ dynent *playerincrosshair()
|
||||
};
|
||||
return NULL;
|
||||
};
|
||||
// Added by Rick
|
||||
char *botincrosshair()
|
||||
{
|
||||
if(demoplayback) return NULL;
|
||||
loopv(bots)
|
||||
{
|
||||
dynent *o = bots[i];
|
||||
if(!o) continue;
|
||||
if(intersect(o, player1->o, worldpos)) return o->name;
|
||||
};
|
||||
return NULL;
|
||||
};
|
||||
// End add by Rick
|
||||
|
||||
const int MAXPROJ = 100;
|
||||
struct projectile { vec o, to; float speed; dynent *owner; int gun; bool inuse, local; };
|
||||
@@ -185,7 +202,58 @@ void newprojectile(vec &from, vec &to, float speed, bool local, dynent *owner, i
|
||||
void hit(int target, int damage, dynent *d, dynent *at)
|
||||
{
|
||||
if(d==player1) selfdamage(damage, at==player1 ? -1 : -2, at);
|
||||
else { addmsg(1, 4, SV_DAMAGE, target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); };
|
||||
//else if(d->monsterstate) monsterpain(d, damage, at);
|
||||
// Added by Rick: Let bots take damage
|
||||
else if (d->pBot) d->pBot->BotPain(damage, at);
|
||||
else if (d->bIsBot)
|
||||
{
|
||||
int PlayerIndex = -1;
|
||||
if (at->bIsBot) PlayerIndex = BotManager.GetBotIndex(at);
|
||||
else
|
||||
{
|
||||
loopv(players)
|
||||
{
|
||||
if (!players[i]) continue;
|
||||
|
||||
if (players[i] == at)
|
||||
{
|
||||
PlayerIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int msgtype = (at->bIsBot) ? SV_BOT2BOTDMG : SV_CLIENT2BOTDMG;
|
||||
addmsg(1, 4, msgtype, BotManager.GetBotIndex(d), damage, PlayerIndex);
|
||||
playsound(S_PAIN1+rnd(5), &d->o);
|
||||
}
|
||||
// End add by Rick
|
||||
//else { addmsg(1, 4, SV_DAMAGE, target, damage, d->lifesequence); playsound(S_PAIN1+rnd(5), &d->o); }; Modified by Rick: Added IsBot and PlayerIndex to message
|
||||
else
|
||||
{
|
||||
// Modified by Rick: Added IsBot and PlayerIndex to message
|
||||
int PlayerIndex = -1;
|
||||
if (at->bIsBot)
|
||||
PlayerIndex = BotManager.GetBotIndex(at);
|
||||
else
|
||||
{
|
||||
loopv(players)
|
||||
{
|
||||
if (!players[i])
|
||||
continue;
|
||||
|
||||
if (players[i] == at)
|
||||
{
|
||||
PlayerIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(at->bIsBot) addmsg(1, 5, SV_BOT2CLIENTDMG, target, damage, d->lifesequence, PlayerIndex);
|
||||
else addmsg(1, 4, SV_DAMAGE, target, damage, d->lifesequence);
|
||||
playsound(S_PAIN1+rnd(5), &d->o);
|
||||
};
|
||||
|
||||
particle_splash(3, damage, 1000, d->o);
|
||||
demodamage(damage, d->o);
|
||||
};
|
||||
@@ -208,7 +276,8 @@ void radialeffect(dynent *o, vec &v, int cn, int qdam, dynent *at)
|
||||
};
|
||||
};
|
||||
|
||||
void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int notthismonster, int qdam)
|
||||
// Modified by Rick: Added notthisbot
|
||||
void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int notthismonster, int notthisbot, int qdam)
|
||||
{
|
||||
particle_splash(0, 50, 300, v);
|
||||
p->inuse = false;
|
||||
@@ -231,15 +300,29 @@ void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int notthismons
|
||||
if(!o) continue;
|
||||
radialeffect(o, v, i, qdam, p->owner);
|
||||
};
|
||||
};
|
||||
// Added by Rick
|
||||
loopv(bots)
|
||||
{
|
||||
if(i==notthisbot) continue;
|
||||
dynent *o = bots[i];
|
||||
if(!o) continue;
|
||||
radialeffect(o, v, i, qdam, p->owner);
|
||||
}
|
||||
// End add by Rick
|
||||
//dvector &mv = getmonsters();
|
||||
//loopv(mv) if(i!=notthismonster) radialeffect(mv[i], v, i, qdam, p->owner);
|
||||
};
|
||||
};
|
||||
|
||||
inline void projdamage(dynent *o, projectile *p, vec &v, int i, int im, int qdam)
|
||||
// Modified by Rick
|
||||
// inline void projdamage(dynent *o, projectile *p, vec &v, int i, int im, int qdam)
|
||||
inline void projdamage(dynent *o, projectile *p, vec &v, int i, int im, int ib, int qdam)
|
||||
{
|
||||
if(o->state!=CS_ALIVE) return;
|
||||
if(intersect(o, p->o, v))
|
||||
{
|
||||
splash(p, v, p->o, i, im, qdam);
|
||||
// splash(p, v, p->o, i, im, qdam); Modified by Rick
|
||||
splash(p, v, p->o, i, im, ib, qdam);
|
||||
hit(i, qdam, o, p->owner);
|
||||
};
|
||||
};
|
||||
@@ -263,17 +346,36 @@ void moveprojectiles(float time)
|
||||
{
|
||||
dynent *o = players[i];
|
||||
if(!o) continue;
|
||||
projdamage(o, p, v, i, -1, qdam);
|
||||
// projdamage(o, p, v, i, -1, qdam); Modified by Rick
|
||||
projdamage(o, p, v, i, -1, -1, qdam);
|
||||
};
|
||||
if(p->owner!=player1) projdamage(player1, p, v, -1, -1, qdam);
|
||||
// Added by Rick: Damage bots aswell
|
||||
loopv(bots)
|
||||
{
|
||||
dynent *o = bots[i];
|
||||
if(!o || (o == p->owner)) continue;
|
||||
projdamage(o, p, v, -1, -1, i, qdam);
|
||||
};
|
||||
// End add by Rick
|
||||
// if(p->owner!=player1) projdamage(player1, p, v, -1, -1, qdam); Modified by Rick
|
||||
if(p->owner!=player1) projdamage(player1, p, v, -1, -1, -1, qdam);
|
||||
//dvector &mv = getmonsters();
|
||||
//loopv(mv) if(!vreject(mv[i]->o, v, 10.0f) && mv[i]!=p->owner) projdamage(mv[i], p, v, -1, i, qdam); Modified by Rick
|
||||
//loopv(mv) if(!vreject(mv[i]->o, v, 10.0f) && mv[i]!=p->owner) projdamage(mv[i], p, v, -1, i, -1, qdam);
|
||||
};
|
||||
if(p->inuse)
|
||||
{
|
||||
if(time==dtime) splash(p, v, p->o, -1, -1, qdam);
|
||||
// if(time==dtime) splash(p, v, p->o, -1, -1, qdam); Modified by Rick
|
||||
if(time==dtime) splash(p, v, p->o, -1, -1, -1, qdam);
|
||||
else
|
||||
{
|
||||
if(p->gun==GUN_GRENADE) { dodynlight(p->o, v, 0, 255, p->owner); particle_splash(5, 2, 200, v); }
|
||||
else { particle_splash(1, 1, 200, v); particle_splash(guns[p->gun].part, 1, 1, v); };
|
||||
// Added by Rick
|
||||
traceresult_s tr;
|
||||
TraceLine(p->o, v, p->owner, true, &tr);
|
||||
if (tr.collided) splash(p, v, p->o, -1, -1, -1, qdam);
|
||||
// End add
|
||||
};
|
||||
};
|
||||
p->o = v;
|
||||
@@ -288,7 +390,7 @@ void throw_nade(dynent *d, vec &to, physent *p)
|
||||
{
|
||||
if(!p || !d) return;
|
||||
printf("thrownade\n");
|
||||
playsound(S_GRENADETHROW, &d->o);
|
||||
playsound(S_GRENADETHROW, &d->o);
|
||||
|
||||
p->isphysent = true;
|
||||
p->gravity = 20;
|
||||
@@ -378,7 +480,7 @@ physent *new_nade(dynent *d, int millis = 0)
|
||||
{
|
||||
curnade = p;
|
||||
d->thrownademillis = 0;
|
||||
};
|
||||
};
|
||||
playsound(S_GRENADEPULL, &d->o);
|
||||
return p;
|
||||
};
|
||||
@@ -394,7 +496,7 @@ void explode_nade(physent *i)
|
||||
vec dist = { 0.1f, 0.1f, 0.1f };
|
||||
vadd(o, dist);
|
||||
throw_nade(i->owner, o, i);
|
||||
};
|
||||
};
|
||||
playsound(S_FEXPLODE, &i->o);
|
||||
newprojectile(i->o, i->o, 1, i->owner==player1, i->owner, GUN_GRENADE);
|
||||
};
|
||||
@@ -422,7 +524,7 @@ void shootv(int gun, vec &from, vec &to, dynent *d, bool local, int nademillis)
|
||||
//particle_trail(1, 10, from, to);
|
||||
break;
|
||||
|
||||
case GUN_GRENADE:
|
||||
case GUN_GRENADE:
|
||||
{
|
||||
if(d!=player1)
|
||||
{
|
||||
@@ -460,7 +562,7 @@ void raydamage(dynent *o, vec &from, vec &to, dynent *d, int i)
|
||||
if(damage) hitpush(i, damage, o, d, from, to);
|
||||
}
|
||||
else if(intersect(o, from, to)) hitpush(i, qdam, o, d, from, to);
|
||||
};
|
||||
};
|
||||
|
||||
void spreadandrecoil(vec & from, vec & to, dynent * d)
|
||||
{
|
||||
@@ -503,13 +605,13 @@ void spreadandrecoil(vec & from, vec & to, dynent * d)
|
||||
|
||||
if(d->pitch<80.0f) d->pitch += guns[d->gunselect].recoil*0.05f;
|
||||
};
|
||||
|
||||
//VAR(grenadepulltime, 0, 100, 10000);
|
||||
const int grenadepulltime = 650;
|
||||
|
||||
bool akimboside = false;
|
||||
int akimbolastaction[2] = {0,0};
|
||||
|
||||
|
||||
//VAR(grenadepulltime, 0, 100, 10000);
|
||||
const int grenadepulltime = 650;
|
||||
|
||||
bool akimboside = false;
|
||||
int akimbolastaction[2] = {0,0};
|
||||
|
||||
|
||||
void shoot(dynent *d, vec &targ)
|
||||
{
|
||||
@@ -517,10 +619,10 @@ void shoot(dynent *d, vec &targ)
|
||||
|
||||
if(!d->attacking && d->gunselect==GUN_GRENADE && curnade) // throw
|
||||
{
|
||||
if(attacktime>grenadepulltime)
|
||||
{
|
||||
d->thrownademillis = lastmillis;
|
||||
throw_nade(d, targ, curnade);
|
||||
if(attacktime>grenadepulltime)
|
||||
{
|
||||
d->thrownademillis = lastmillis;
|
||||
throw_nade(d, targ, curnade);
|
||||
}
|
||||
return;
|
||||
};
|
||||
@@ -538,17 +640,26 @@ void shoot(dynent *d, vec &targ)
|
||||
if(d->gunselect!=GUN_SUBGUN && d->gunselect!=GUN_ASSULT && d->gunselect!=GUN_GRENADE) d->attacking = false; //makes sub/assult autos
|
||||
else d->shots++;
|
||||
|
||||
if(d->gunselect==GUN_PISTOL && d->akimbo!=0)
|
||||
{
|
||||
d->attacking = true; //make akimbo auto
|
||||
akimbolastaction[akimboside?1:0] = lastmillis;
|
||||
akimboside = !akimboside;
|
||||
}
|
||||
if(d->gunselect==GUN_PISTOL && d->akimbo)
|
||||
{
|
||||
d->attacking = true; //make akimbo auto
|
||||
akimbolastaction[akimboside?1:0] = lastmillis;
|
||||
akimboside = !akimboside;
|
||||
}
|
||||
|
||||
d->lastaction = lastmillis;
|
||||
d->lastattackgun = d->gunselect;
|
||||
if(!d->mag[d->gunselect]) { playsoundc(S_NOAMMO); d->gunwait = 250; d->lastattackgun = -1; return; };
|
||||
|
||||
//if(!d->mag[d->gunselect]) { playsoundc(S_NOAMMO); d->gunwait = 250; d->lastattackgun = -1; return; };
|
||||
if(!d->mag[d->gunselect])
|
||||
{
|
||||
if (d->bIsBot) botplaysound(S_NOAMMO, d);
|
||||
else playsoundc(S_NOAMMO);
|
||||
d->gunwait = 250;
|
||||
d->lastattackgun = -1;
|
||||
return;
|
||||
};
|
||||
// End mod
|
||||
|
||||
if(d->gunselect) d->mag[d->gunselect]--;
|
||||
|
||||
vec from = d->o;
|
||||
@@ -567,18 +678,17 @@ void shoot(dynent *d, vec &targ)
|
||||
vadd(to, unitv);
|
||||
};
|
||||
if(d->gunselect==GUN_SHOTGUN) createrays(from, to);
|
||||
|
||||
//if(d->quadmillis && attacktime>200) playsoundc(S_ITEMPUP);
|
||||
|
||||
if(d->gunselect==GUN_PISTOL && d->akimbo) d->gunwait = guns[d->gunselect].attackdelay / 2; //make akimbo pistols shoot twice as fast as normal pistol
|
||||
else d->gunwait = guns[d->gunselect].attackdelay;
|
||||
|
||||
if(d->gunselect==GUN_GRENADE) // activate
|
||||
{
|
||||
if(!curnade) new_nade(player1);
|
||||
if(!curnade) new_nade(d);
|
||||
return;
|
||||
}
|
||||
|
||||
//fixmebot
|
||||
shootv(d->gunselect, from, to, d, 0);
|
||||
addmsg(1, 9, SV_SHOT, d->gunselect, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), 0 );
|
||||
|
||||
@@ -589,6 +699,16 @@ void shoot(dynent *d, vec &targ)
|
||||
dynent *o = players[i];
|
||||
if(!o) continue;
|
||||
raydamage(o, from, to, d, i);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// Added by Rick: raydamage on bots too
|
||||
loopv(bots)
|
||||
{
|
||||
dynent *o = bots[i];
|
||||
if(!o || (o == d)) continue;
|
||||
raydamage(o, from, to, d, i);
|
||||
};
|
||||
// End add by Rick
|
||||
|
||||
if(d->bIsBot) raydamage(player1, from, to, d, -1);
|
||||
};
|
||||
|
||||
+10
-1
@@ -37,7 +37,16 @@ void settag(int tag, int type) // set all cubes with "tag" to space, if
|
||||
};
|
||||
|
||||
void resettagareas() { settag(0, 0); }; // reset for editing or map saving
|
||||
void settagareas() { settag(0, 1); loopv(ents) if(ents[i].type==CARROT) setspawn(i, true); }; // set for playing
|
||||
// Modified by Rick
|
||||
//void settagareas() { settag(0, 1); loopv(ents) if(ents[i].type==TRIGGER) setspawn(i, true); }; // set for playing
|
||||
|
||||
void settagareas() // set for playing
|
||||
{
|
||||
settag(0, 1);
|
||||
loopv(ents) if(ents[i].type==CARROT) setspawn(i, true);
|
||||
if(ishost()) BotManager.PickNextTrigger();
|
||||
};
|
||||
// End mod
|
||||
|
||||
void trigger(int tag, int type, bool savegame)
|
||||
{
|
||||
|
||||
@@ -205,11 +205,11 @@ void save_world(char *mname)
|
||||
conoutf("wrote map file %s", (int)cgzname);
|
||||
settagareas();
|
||||
};
|
||||
|
||||
extern void preparectf(bool cleanonly = false);
|
||||
|
||||
extern void preparectf(bool cleanonly = false);
|
||||
|
||||
void load_world(char *mname) // still supports all map formats that have existed since the earliest cube betas!
|
||||
{
|
||||
{
|
||||
preparectf(true);
|
||||
stopifrecording();
|
||||
cleardlights();
|
||||
|
||||
Reference in New Issue
Block a user