git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@300 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
driAn
2006-06-01 22:01:32 +00:00
parent c40015be6c
commit e9159704ba
27 changed files with 2957 additions and 2086 deletions
+23 -24
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
+1 -3
View File
@@ -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
View File
@@ -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);
+4 -3
View File
@@ -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);
+1 -1
View File
@@ -471,7 +471,7 @@ private:
// ==================================================================
// Code of TMutiChoice - Begin
// Code of TMultiChoice - Begin
// ==================================================================
template <class C> class TMultiChoice
-9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+246 -12
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
File diff suppressed because it is too large Load Diff
+9 -1
View File
@@ -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
View File
@@ -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);
};
};
+9
View File
@@ -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
View File
@@ -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;
+19
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
{
+3 -3
View File
@@ -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();