ddnet/src/game/server/entities/character.cpp

1534 lines
58 KiB
C++
Raw Normal View History

#include <new>
#include <stdio.h>
#include <string.h>
2010-05-29 07:25:38 +00:00
#include <engine/shared/config.h>
#include <engine/server/server.h>
2010-05-29 07:25:38 +00:00
#include <game/server/gamecontext.h>
#include <game/mapitems.h>
#include <game/server/gamemodes/DDRace.h>
#include <game/server/score.h>
2010-05-29 07:25:38 +00:00
#include "character.h"
#include "laser.h"
#include "light.h"
2010-05-29 07:25:38 +00:00
#include "projectile.h"
2010-05-29 07:25:38 +00:00
//input count
struct CInputCount
{
2010-05-29 07:25:38 +00:00
int m_Presses;
int m_Releases;
};
2010-05-29 07:25:38 +00:00
CInputCount CountInput(int Prev, int Cur)
{
2010-05-29 07:25:38 +00:00
CInputCount c = {0, 0};
Prev &= INPUT_STATE_MASK;
Cur &= INPUT_STATE_MASK;
int i = Prev;
2010-05-29 07:25:38 +00:00
while(i != Cur)
{
i = (i+1)&INPUT_STATE_MASK;
if(i&1)
2010-05-29 07:25:38 +00:00
c.m_Presses++;
else
2010-05-29 07:25:38 +00:00
c.m_Releases++;
}
return c;
}
2010-05-29 07:25:38 +00:00
MACRO_ALLOC_POOL_ID_IMPL(CCharacter, MAX_CLIENTS)
// Character, "physical" m_pPlayer's part
2010-05-29 07:25:38 +00:00
CCharacter::CCharacter(CGameWorld *pWorld)
: CEntity(pWorld, NETOBJTYPE_CHARACTER)
2008-09-23 07:43:41 +00:00
{
2010-06-03 15:39:42 +00:00
m_ProximityRadius = ms_PhysSize;
2010-05-29 07:25:38 +00:00
m_Health = 0;
m_Armor = 0;
2008-09-23 07:43:41 +00:00
}
2010-05-29 07:25:38 +00:00
void CCharacter::Reset()
{
2010-05-29 07:25:38 +00:00
Destroy();
}
2010-05-29 07:25:38 +00:00
bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
{
2010-05-29 07:25:38 +00:00
m_PlayerState = PLAYERSTATE_UNKNOWN;
m_EmoteStop = -1;
m_LastAction = -1;
m_ActiveWeapon = WEAPON_GUN;
m_LastWeapon = WEAPON_HAMMER;
m_QueuedWeapon = -1;
m_pPlayer = pPlayer;
m_Pos = Pos;
m_OlderPos = Pos;
m_OldPos = Pos;
2010-10-29 21:28:15 +00:00
m_DDRaceState = DDRACE_NONE;
m_PrevPos = Pos;
2010-05-29 07:25:38 +00:00
m_Core.Reset();
m_BroadTime = true;
m_BroadCast = true;
m_EyeEmote = true;
m_Fly = true;
2010-11-04 19:06:47 +00:00
m_TimerReseted = false;
m_TeamBeforeSuper = 0;
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
m_Core.Init(&GameServer()->m_World.m_Core, GameServer()->Collision(), &Controller->m_Teams.m_Core);
2010-05-29 07:25:38 +00:00
m_Core.m_Pos = m_Pos;
2010-09-11 09:31:36 +00:00
m_Core.m_Id = GetPlayer()->GetCID();
2010-05-29 07:25:38 +00:00
GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = &m_Core;
2010-05-29 07:25:38 +00:00
m_ReckoningTick = 0;
mem_zero(&m_SendCore, sizeof(m_SendCore));
mem_zero(&m_ReckoningCore, sizeof(m_ReckoningCore));
2010-05-29 07:25:38 +00:00
GameServer()->m_World.InsertEntity(this);
m_Alive = true;
if(m_pPlayer->m_RconFreeze) Freeze(-1);
2010-05-29 07:25:38 +00:00
GameServer()->m_pController->OnCharacterSpawn(this);
2008-08-27 20:04:07 +00:00
return true;
}
2010-05-29 07:25:38 +00:00
void CCharacter::Destroy()
{
2010-05-29 07:25:38 +00:00
GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = 0;
m_Alive = false;
}
2010-05-29 07:25:38 +00:00
void CCharacter::SetWeapon(int W)
{
2010-05-29 07:25:38 +00:00
if(W == m_ActiveWeapon)
return;
2010-05-29 07:25:38 +00:00
m_LastWeapon = m_ActiveWeapon;
m_QueuedWeapon = -1;
m_ActiveWeapon = W;
GameServer()->CreateSound(m_Pos, SOUND_WEAPON_SWITCH);
2010-05-29 07:25:38 +00:00
if(m_ActiveWeapon < 0 || m_ActiveWeapon >= NUM_WEAPONS)
m_ActiveWeapon = 0;
}
bool CCharacter::CanCollide(int Cid) {
return Teams()->m_Core.CanCollide(GetPlayer()->GetCID(), Cid);
}
bool CCharacter::SameTeam(int Cid) {
return Teams()->m_Core.SameTeam(GetPlayer()->GetCID(), Cid);
}
2010-05-29 07:25:38 +00:00
bool CCharacter::IsGrounded()
{
if(GameServer()->Collision()->CheckPoint(m_Pos.x+m_ProximityRadius/2, m_Pos.y+m_ProximityRadius/2+5))
return true;
if(GameServer()->Collision()->CheckPoint(m_Pos.x-m_ProximityRadius/2, m_Pos.y+m_ProximityRadius/2+5))
return true;
return false;
}
2010-05-29 07:25:38 +00:00
void CCharacter::HandleNinja()
{
2010-05-29 07:25:38 +00:00
if(m_ActiveWeapon != WEAPON_NINJA)
return;
2010-05-29 07:25:38 +00:00
vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY));
2010-05-29 07:25:38 +00:00
if ((Server()->Tick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000))
{
// time's up, return
2010-05-29 07:25:38 +00:00
m_aWeapons[WEAPON_NINJA].m_Got = false;
m_ActiveWeapon = m_LastWeapon;
if(m_ActiveWeapon == WEAPON_NINJA)
m_ActiveWeapon = WEAPON_GUN;
Direction= normalize(vec2(0,0)) ;
2010-05-29 07:25:38 +00:00
SetWeapon(m_ActiveWeapon);
return;
}
2010-05-29 07:25:38 +00:00
// force ninja Weapon
SetWeapon(WEAPON_NINJA);
2010-05-29 07:25:38 +00:00
m_Ninja.m_CurrentMoveTime--;
2010-05-29 07:25:38 +00:00
if (m_Ninja.m_CurrentMoveTime == 0)
{
2010-05-29 07:25:38 +00:00
// reset velocity
m_Core.m_Vel *= 0.2f;
}
2010-05-29 07:25:38 +00:00
if (m_Ninja.m_CurrentMoveTime > 0)
{
2010-05-29 07:25:38 +00:00
// Set velocity
m_Core.m_Vel = m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity;
vec2 OldPos = m_Pos;
2010-06-03 15:39:42 +00:00
GameServer()->Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(m_ProximityRadius, m_ProximityRadius), 0.f);
// reset velocity so the client doesn't predict stuff
2010-05-29 07:25:38 +00:00
m_Core.m_Vel = vec2(0.f, 0.f);
2010-05-29 07:25:38 +00:00
// check if we Hit anything along the way
{
2010-05-29 07:25:38 +00:00
CCharacter *aEnts[64];
vec2 Dir = m_Pos - OldPos;
2010-06-03 15:39:42 +00:00
float Radius = m_ProximityRadius * 2.0f;
2010-05-29 07:25:38 +00:00
vec2 Center = OldPos + Dir * 0.5f;
int Num = GameServer()->m_World.FindEntities(Center, Radius, (CEntity**)aEnts, 64, NETOBJTYPE_CHARACTER);
2010-05-29 07:25:38 +00:00
for (int i = 0; i < Num; ++i)
{
2010-05-29 07:25:38 +00:00
if (aEnts[i] == this)
continue;
2010-05-29 07:25:38 +00:00
// make sure we haven't Hit this object before
bool bAlreadyHit = false;
for (int j = 0; j < m_NumObjectsHit; j++)
{
2010-05-29 07:25:38 +00:00
if (m_apHitObjects[j] == aEnts[i])
bAlreadyHit = true;
}
2010-05-29 07:25:38 +00:00
if (bAlreadyHit)
continue;
// check so we are sufficiently close
2010-06-03 15:39:42 +00:00
if (distance(aEnts[i]->m_Pos, m_Pos) > (m_ProximityRadius * 2.0f))
continue;
// Hit a m_pPlayer, give him damage and stuffs...
2010-05-29 07:25:38 +00:00
GameServer()->CreateSound(aEnts[i]->m_Pos, SOUND_NINJA_HIT);
// set his velocity to fast upward (for now)
2010-05-29 07:25:38 +00:00
if(m_NumObjectsHit < 10)
m_apHitObjects[m_NumObjectsHit++] = aEnts[i];
2010-05-29 07:25:38 +00:00
aEnts[i]->TakeDamage(vec2(0, 10.0f), g_pData->m_Weapons.m_Ninja.m_pBase->m_Damage, m_pPlayer->GetCID(), WEAPON_NINJA);
}
}
2010-05-29 07:25:38 +00:00
return;
}
2010-05-29 07:25:38 +00:00
return;
}
2010-05-29 07:25:38 +00:00
void CCharacter::DoWeaponSwitch()
{
2010-05-29 07:25:38 +00:00
// make sure we can switch
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_aWeapons[WEAPON_NINJA].m_Got)
return;
2010-05-29 07:25:38 +00:00
// switch Weapon
SetWeapon(m_QueuedWeapon);
}
2010-05-29 07:25:38 +00:00
void CCharacter::HandleWeaponSwitch()
{
2010-05-29 07:25:38 +00:00
int WantedWeapon = m_ActiveWeapon;
if(m_QueuedWeapon != -1)
WantedWeapon = m_QueuedWeapon;
2010-05-29 07:25:38 +00:00
// select Weapon
int Next = CountInput(m_LatestPrevInput.m_NextWeapon, m_LatestInput.m_NextWeapon).m_Presses;
int Prev = CountInput(m_LatestPrevInput.m_PrevWeapon, m_LatestInput.m_PrevWeapon).m_Presses;
2010-05-29 07:25:38 +00:00
if(Next < 128) // make sure we only try sane stuff
{
2010-05-29 07:25:38 +00:00
while(Next) // Next Weapon selection
{
2010-05-29 07:25:38 +00:00
WantedWeapon = (WantedWeapon+1)%NUM_WEAPONS;
if(m_aWeapons[WantedWeapon].m_Got)
Next--;
}
}
2010-05-29 07:25:38 +00:00
if(Prev < 128) // make sure we only try sane stuff
{
2010-05-29 07:25:38 +00:00
while(Prev) // Prev Weapon selection
{
2010-05-29 07:25:38 +00:00
WantedWeapon = (WantedWeapon-1)<0?NUM_WEAPONS-1:WantedWeapon-1;
if(m_aWeapons[WantedWeapon].m_Got)
Prev--;
}
}
2010-05-29 07:25:38 +00:00
// Direct Weapon selection
if(m_LatestInput.m_WantedWeapon)
WantedWeapon = m_Input.m_WantedWeapon-1;
// check for insane values
2010-05-29 07:25:38 +00:00
if(WantedWeapon >= 0 && WantedWeapon < NUM_WEAPONS && WantedWeapon != m_ActiveWeapon && m_aWeapons[WantedWeapon].m_Got)
m_QueuedWeapon = WantedWeapon;
2010-05-29 07:25:38 +00:00
DoWeaponSwitch();
}
2010-05-29 07:25:38 +00:00
void CCharacter::FireWeapon()
{
if(m_ReloadTimer != 0 /*|| m_FreezeTime > 0*/)
return;
2010-05-29 07:25:38 +00:00
DoWeaponSwitch();
vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY));
2010-05-29 07:25:38 +00:00
bool FullAuto = false;
if(m_ActiveWeapon == WEAPON_GRENADE || m_ActiveWeapon == WEAPON_SHOTGUN || m_ActiveWeapon == WEAPON_RIFLE)
FullAuto = true;
// check if we gonna fire
2010-05-29 07:25:38 +00:00
bool WillFire = false;
if(CountInput(m_LatestPrevInput.m_Fire, m_LatestInput.m_Fire).m_Presses)
WillFire = true;
if((FullAuto || m_Super) && (m_LatestInput.m_Fire&1) && m_aWeapons[m_ActiveWeapon].m_Ammo)
2010-05-29 07:25:38 +00:00
WillFire = true;
2010-05-29 07:25:38 +00:00
if(!WillFire)
return;
// check for ammo
2010-05-29 07:25:38 +00:00
if(!m_aWeapons[m_ActiveWeapon].m_Ammo)
{
/* // 125ms is a magical limit of how fast a human can click
m_ReloadTimer = 1 * Server()->TickSpeed();
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG);*/
// Timerstuff to avoid shrieking orchestra caused by unfreeze-plasma
if(m_PainSoundTimer<=0)
{
m_PainSoundTimer = 1 * Server()->TickSpeed();
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG);
}
return;
}
2010-06-03 15:39:42 +00:00
vec2 ProjStartPos = m_Pos+Direction*m_ProximityRadius*0.75f;
2010-05-29 07:25:38 +00:00
switch(m_ActiveWeapon)
{
case WEAPON_HAMMER:
{
2010-05-29 07:25:38 +00:00
// reset objects Hit
m_NumObjectsHit = 0;
2010-10-23 12:15:29 +00:00
GameServer()->CreateSound(m_Pos, SOUND_HAMMER_FIRE, Teams()->TeamMask(Team()));
2010-08-29 12:28:21 +00:00
if (!g_Config.m_SvHit) break;
2010-05-29 07:25:38 +00:00
CCharacter *aEnts[64];
int Hits = 0;
int Num = GameServer()->m_World.FindEntities(ProjStartPos, m_ProximityRadius*0.5f, (CEntity**)aEnts,
2010-05-29 07:25:38 +00:00
64, NETOBJTYPE_CHARACTER);
2010-05-29 07:25:38 +00:00
for (int i = 0; i < Num; ++i)
{
2010-05-29 07:25:38 +00:00
CCharacter *Target = aEnts[i];
//for DDRace mod or any other mod, which needs hammer hits through the wall remove second condition
2010-09-24 17:10:18 +00:00
if ((Target == this || !CanCollide(Target->GetPlayer()->GetCID())) /*|| GameServer()->Collision()->IntersectLine(ProjStartPos, Target->m_Pos, NULL, NULL)*/)
continue;
// set his velocity to fast upward (for now)
GameServer()->CreateHammerHit(m_Pos, Teams()->TeamMask(Team()));
2010-05-29 07:25:38 +00:00
aEnts[i]->TakeDamage(vec2(0.f, -1.f), g_pData->m_Weapons.m_Hammer.m_pBase->m_Damage, m_pPlayer->GetCID(), m_ActiveWeapon);
2010-05-29 07:25:38 +00:00
vec2 Dir;
if (length(Target->m_Pos - m_Pos) > 0.0f)
Dir = normalize(Target->m_Pos - m_Pos);
else
2010-05-29 07:25:38 +00:00
Dir = vec2(0.f, -1.f);
vec2 Temp = Target->m_Core.m_Vel + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f * (m_HammerType + 1);
if(Temp.x > 0 && ((Target->m_TileIndex == TILE_STOP && Target->m_TileFlags == ROTATION_270) || (Target->m_TileIndexL == TILE_STOP && Target->m_TileFlagsL == ROTATION_270) || (Target->m_TileIndexL == TILE_STOPS && (Target->m_TileFlagsL == ROTATION_90 || Target->m_TileFlagsL ==ROTATION_270)) || (Target->m_TileIndexL == TILE_STOPA) || (Target->m_TileFIndex == TILE_STOP && Target->m_TileFFlags == ROTATION_270) || (Target->m_TileFIndexL == TILE_STOP && Target->m_TileFFlagsL == ROTATION_270) || (Target->m_TileFIndexL == TILE_STOPS && (Target->m_TileFFlagsL == ROTATION_90 || Target->m_TileFFlagsL == ROTATION_270)) || (Target->m_TileFIndexL == TILE_STOPA) || (Target->m_TileSIndex == TILE_STOP && Target->m_TileSFlags == ROTATION_270) || (Target->m_TileSIndexL == TILE_STOP && Target->m_TileSFlagsL == ROTATION_270) || (Target->m_TileSIndexL == TILE_STOPS && (Target->m_TileSFlagsL == ROTATION_90 || Target->m_TileSFlagsL == ROTATION_270)) || (Target->m_TileSIndexL == TILE_STOPA)))
Temp.x = 0;
if(Temp.x < 0 && ((Target->m_TileIndex == TILE_STOP && Target->m_TileFlags == ROTATION_90) || (Target->m_TileIndexR == TILE_STOP && Target->m_TileFlagsR == ROTATION_90) || (Target->m_TileIndexR == TILE_STOPS && (Target->m_TileFlagsR == ROTATION_90 || Target->m_TileFlagsR == ROTATION_270)) || (Target->m_TileIndexR == TILE_STOPA) || (Target->m_TileFIndex == TILE_STOP && Target->m_TileFFlags == ROTATION_90) || (Target->m_TileFIndexR == TILE_STOP && Target->m_TileFFlagsR == ROTATION_90) || (Target->m_TileFIndexR == TILE_STOPS && (Target->m_TileFFlagsR == ROTATION_90 || Target->m_TileFFlagsR == ROTATION_270)) || (Target->m_TileFIndexR == TILE_STOPA) || (Target->m_TileSIndex == TILE_STOP && Target->m_TileSFlags == ROTATION_90) || (Target->m_TileSIndexR == TILE_STOP && Target->m_TileSFlagsR == ROTATION_90) || (Target->m_TileSIndexR == TILE_STOPS && (Target->m_TileSFlagsR == ROTATION_90 || Target->m_TileSFlagsR == ROTATION_270)) || (Target->m_TileSIndexR == TILE_STOPA)))
Temp.x = 0;
if(Temp.y < 0 && ((Target->m_TileIndex == TILE_STOP && Target->m_TileFlags == ROTATION_180) || (Target->m_TileIndexB == TILE_STOP && Target->m_TileFlagsB == ROTATION_180) || (Target->m_TileIndexB == TILE_STOPS && (Target->m_TileFlagsB == ROTATION_0 || Target->m_TileFlagsB == ROTATION_180)) || (Target->m_TileIndexB == TILE_STOPA) || (Target->m_TileFIndex == TILE_STOP && Target->m_TileFFlags == ROTATION_180) || (Target->m_TileFIndexB == TILE_STOP && Target->m_TileFFlagsB == ROTATION_180) || (Target->m_TileFIndexB == TILE_STOPS && (Target->m_TileFFlagsB == ROTATION_0 || Target->m_TileFFlagsB == ROTATION_180)) || (Target->m_TileFIndexB == TILE_STOPA) || (Target->m_TileSIndex == TILE_STOP && Target->m_TileSFlags == ROTATION_180) || (Target->m_TileSIndexB == TILE_STOP && Target->m_TileSFlagsB == ROTATION_180) || (Target->m_TileSIndexB == TILE_STOPS && (Target->m_TileSFlagsB == ROTATION_0 || Target->m_TileSFlagsB == ROTATION_180)) || (Target->m_TileSIndexB == TILE_STOPA)))
Temp.y = 0;
if(Temp.y > 0 && ((Target->m_TileIndex == TILE_STOP && Target->m_TileFlags == ROTATION_0) || (Target->m_TileIndexT == TILE_STOP && Target->m_TileFlagsT == ROTATION_0) || (Target->m_TileIndexT == TILE_STOPS && (Target->m_TileFlagsT == ROTATION_0 || Target->m_TileFlagsT == ROTATION_180)) || (Target->m_TileIndexT == TILE_STOPA) || (Target->m_TileFIndex == TILE_STOP && Target->m_TileFFlags == ROTATION_0) || (Target->m_TileFIndexT == TILE_STOP && Target->m_TileFFlagsT == ROTATION_0) || (Target->m_TileFIndexT == TILE_STOPS && (Target->m_TileFFlagsT == ROTATION_0 || Target->m_TileFFlagsT == ROTATION_180)) || (Target->m_TileFIndexT == TILE_STOPA) || (Target->m_TileSIndex == TILE_STOP && Target->m_TileSFlags == ROTATION_0) || (Target->m_TileSIndexT == TILE_STOP && Target->m_TileSFlagsT == ROTATION_0) || (Target->m_TileSIndexT == TILE_STOPS && (Target->m_TileSFlagsT == ROTATION_0 || Target->m_TileSFlagsT == ROTATION_180)) || (Target->m_TileSIndexT == TILE_STOPA)))
Temp.y = 0;
Target->m_Core.m_Vel = Temp;
Target->UnFreeze();
2010-05-29 07:25:38 +00:00
Hits++;
}
2010-05-29 07:25:38 +00:00
// if we Hit anything, we have to wait for the reload
if(Hits)
m_ReloadTimer = Server()->TickSpeed()/3;
} break;
case WEAPON_GUN:
{
CProjectile *Proj = new CProjectile
(
GameWorld(),
WEAPON_GUN,//Type
m_pPlayer->GetCID(),//Owner
ProjStartPos,//Pos
Direction,//Dir
(int)(Server()->TickSpeed()*GameServer()->Tuning()->m_GunLifetime),//Span
0,//Freeze
0,//Explosive
0,//Force
-1,//SoundImpact
WEAPON_GUN//Weapon
);
2010-05-29 07:25:38 +00:00
// pack the Projectile and send it to the client Directly
CNetObj_Projectile p;
Proj->FillInfo(&p);
2010-05-29 07:25:38 +00:00
CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE);
Msg.AddInt(1);
for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++)
Msg.AddInt(((int *)&p)[i]);
2010-05-29 07:25:38 +00:00
Server()->SendMsg(&Msg, 0, m_pPlayer->GetCID());
2010-10-23 12:15:29 +00:00
GameServer()->CreateSound(m_Pos, SOUND_GUN_FIRE, Teams()->TeamMask(Team()));
} break;
case WEAPON_SHOTGUN:
{
new CLaser(&GameServer()->m_World, m_Pos, Direction, GameServer()->Tuning()->m_LaserReach, m_pPlayer->GetCID(), 1);
GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE);
/*int ShotSpread = 2;
2010-05-29 07:25:38 +00:00
CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE);
Msg.AddInt(ShotSpread*2+1);
2010-05-29 07:25:38 +00:00
for(int i = -ShotSpread; i <= ShotSpread; ++i)
{
2010-05-29 07:25:38 +00:00
float Spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f};
float a = GetAngle(Direction);
a += Spreading[i+2];
float v = 1-(absolute(i)/(float)ShotSpread);
float Speed = mix((float)GameServer()->Tuning()->m_ShotgunSpeeddiff, 1.0f, v);
CProjectile *Proj = new CProjectile(GameWorld(), WEAPON_SHOTGUN,
m_pPlayer->GetCID(),
ProjStartPos,
vec2(cosf(a), sinf(a))*Speed,
(int)(Server()->TickSpeed()*GameServer()->Tuning()->m_Shotm_GunLifetime),
1, 0, 0, -1, WEAPON_SHOTGUN);
2010-05-29 07:25:38 +00:00
// pack the Projectile and send it to the client Directly
CNetObj_Projectile p;
Proj->FillInfo(&p);
2010-05-29 07:25:38 +00:00
for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++)
Msg.AddInt(((int *)&p)[i]);
}
Server()->SendMsg(&Msg, 0,m_pPlayer->GetCID());
GameServer()->CreateSound(m_Pos, SOUND_SHOTGUN_FIRE);*/
} break;
case WEAPON_GRENADE:
{
CProjectile *Proj = new CProjectile
(
GameWorld(),
WEAPON_GRENADE,//Type
m_pPlayer->GetCID(),//Owner
ProjStartPos,//Pos
Direction,//Dir
(int)(Server()->TickSpeed()*GameServer()->Tuning()->m_GrenadeLifetime),//Span
0,//Freeze
true,//Explosive
0,//Force
SOUND_GRENADE_EXPLODE,//SoundImpact
WEAPON_GRENADE//Weapon
);//SoundImpact
2010-05-29 07:25:38 +00:00
// pack the Projectile and send it to the client Directly
CNetObj_Projectile p;
Proj->FillInfo(&p);
CMsgPacker Msg(NETMSGTYPE_SV_EXTRAPROJECTILE);
Msg.AddInt(1);
for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++)
Msg.AddInt(((int *)&p)[i]);
Server()->SendMsg(&Msg, 0, m_pPlayer->GetCID());
2010-10-23 12:15:29 +00:00
GameServer()->CreateSound(m_Pos, SOUND_GRENADE_FIRE, Teams()->TeamMask(Team()));
} break;
case WEAPON_RIFLE:
{
new CLaser(GameWorld(), m_Pos, Direction, GameServer()->Tuning()->m_LaserReach, m_pPlayer->GetCID(), 0);
2010-10-18 19:10:21 +00:00
GameServer()->CreateSound(m_Pos, SOUND_RIFLE_FIRE, Teams()->TeamMask(Team()));
} break;
case WEAPON_NINJA:
{
// reset Hit objects
m_NumObjectsHit = 0;
m_AttackTick = Server()->Tick();
m_Ninja.m_ActivationDir = Direction;
//m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
m_Ninja.m_CurrentMoveTime = 10;
2010-10-18 19:10:21 +00:00
GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE, Teams()->TeamMask(Team()));
} break;
}
2010-05-29 07:25:38 +00:00
m_AttackTick = Server()->Tick();
/*
2010-05-29 07:25:38 +00:00
if(m_aWeapons[m_ActiveWeapon].m_Ammo > 0) // -1 == unlimited
m_aWeapons[m_ActiveWeapon].m_Ammo--;
*/
2010-05-29 07:25:38 +00:00
if(!m_ReloadTimer)
m_ReloadTimer = g_pData->m_Weapons.m_aId[m_ActiveWeapon].m_Firedelay * Server()->TickSpeed() / 1000;
}
2010-05-29 07:25:38 +00:00
void CCharacter::HandleWeapons()
{
2010-05-29 07:25:38 +00:00
//ninja
HandleNinja();
2010-05-29 07:25:38 +00:00
vec2 Direction = normalize(vec2(m_LatestInput.m_TargetX, m_LatestInput.m_TargetY));
// check PainSoundTimer - Hmm, maybe sometimes shrieking can be a weapon too? ;)
if(m_PainSoundTimer>0)
m_PainSoundTimer--;
// check reload timer
2010-05-29 07:25:38 +00:00
if(m_ReloadTimer)
{
2010-05-29 07:25:38 +00:00
m_ReloadTimer--;
return;
}
2010-05-29 07:25:38 +00:00
// fire Weapon, if wanted
FireWeapon();
/*
// ammo regen
2010-05-29 07:25:38 +00:00
int AmmoRegenTime = g_pData->m_Weapons.m_aId[m_ActiveWeapon].m_Ammoregentime;
if(AmmoRegenTime)
{
// If equipped and not active, regen ammo?
2010-05-29 07:25:38 +00:00
if (m_ReloadTimer <= 0)
{
2010-05-29 07:25:38 +00:00
if (m_aWeapons[m_ActiveWeapon].m_AmmoRegenStart < 0)
m_aWeapons[m_ActiveWeapon].m_AmmoRegenStart = Server()->Tick();
2010-05-29 07:25:38 +00:00
if ((Server()->Tick() - m_aWeapons[m_ActiveWeapon].m_AmmoRegenStart) >= AmmoRegenTime * Server()->TickSpeed() / 1000)
{
// Add some ammo
2010-05-29 07:25:38 +00:00
m_aWeapons[m_ActiveWeapon].m_Ammo = min(m_aWeapons[m_ActiveWeapon].m_Ammo + 1, 10);
m_aWeapons[m_ActiveWeapon].m_AmmoRegenStart = -1;
}
}
else
{
2010-05-29 07:25:38 +00:00
m_aWeapons[m_ActiveWeapon].m_AmmoRegenStart = -1;
}
}
*/
2010-05-29 07:25:38 +00:00
return;
}
bool CCharacter::GiveWeapon(int Weapon, int Ammo)
{
if(m_aWeapons[Weapon].m_Ammo < g_pData->m_Weapons.m_aId[Weapon].m_Maxammo || !m_aWeapons[Weapon].m_Got)
{
2010-05-29 07:25:38 +00:00
m_aWeapons[Weapon].m_Got = true;
if(!m_FreezeTime) m_aWeapons[Weapon].m_Ammo = min(g_pData->m_Weapons.m_aId[Weapon].m_Maxammo, Ammo);
2010-05-29 07:25:38 +00:00
return true;
}
return false;
}
void CCharacter::GiveNinja()
{
if(!m_aWeapons[WEAPON_NINJA].m_Got)
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_NINJA);
2010-05-29 07:25:38 +00:00
m_Ninja.m_ActivationTick = Server()->Tick();
m_aWeapons[WEAPON_NINJA].m_Got = true;
if (!m_FreezeTime) m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
2010-05-29 07:25:38 +00:00
m_LastWeapon = m_ActiveWeapon;
m_ActiveWeapon = WEAPON_NINJA;
}
2010-05-29 07:25:38 +00:00
void CCharacter::SetEmote(int Emote, int Tick)
{
m_EmoteType = Emote;
m_EmoteStop = Tick;
}
void CCharacter::OnPredictedInput(CNetObj_PlayerInput *pNewInput)
{
// check for changes
2010-05-29 07:25:38 +00:00
if(mem_comp(&m_Input, pNewInput, sizeof(CNetObj_PlayerInput)) != 0)
m_LastAction = Server()->Tick();
// copy new input
2010-05-29 07:25:38 +00:00
mem_copy(&m_Input, pNewInput, sizeof(m_Input));
m_NumInputs++;
// or are not allowed to aim in the center
2010-05-29 07:25:38 +00:00
if(m_Input.m_TargetX == 0 && m_Input.m_TargetY == 0)
m_Input.m_TargetY = -1;
}
2010-05-29 07:25:38 +00:00
void CCharacter::OnDirectInput(CNetObj_PlayerInput *pNewInput)
{
2010-05-29 07:25:38 +00:00
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
mem_copy(&m_LatestInput, pNewInput, sizeof(m_LatestInput));
2010-05-29 07:25:38 +00:00
if(m_NumInputs > 2 && m_pPlayer->GetTeam() != -1)
{
2010-05-29 07:25:38 +00:00
HandleWeaponSwitch();
FireWeapon();
}
if(pNewInput->m_Jump&1 && m_Super && m_Fly)
HandleFly();
2010-05-29 07:25:38 +00:00
mem_copy(&m_LatestPrevInput, &m_LatestInput, sizeof(m_LatestInput));
}
void CCharacter::OnFinish()
{
//TODO: this ugly
float time = (float)(Server()->Tick() - m_StartTime) / ((float)Server()->TickSpeed());
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
char aBuf[128];
m_CpActive=-2;
str_format(aBuf, sizeof(aBuf), "%s finished in: %d minute(s) %5.2f second(s)", Server()->ClientName(m_pPlayer->GetCID()), (int)time/60, time-((int)time/60*60));
if(g_Config.m_SvHideScore)
GameServer()->SendChatTarget(m_pPlayer->GetCID(), aBuf);
else
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
if(time - pData->m_BestTime < 0)
{
// new record \o/
2010-11-04 18:20:45 +00:00
str_format(aBuf, sizeof(aBuf), "New record: %5.2f second(s) better.", fabs(time - pData->m_BestTime));
if(g_Config.m_SvHideScore)
GameServer()->SendChatTarget(m_pPlayer->GetCID(), aBuf);
else
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
}
else if(pData->m_BestTime != 0) // tee has already finished?
2010-11-04 18:20:45 +00:00
{
if(fabs(time - pData->m_BestTime) <= 0.005)
{
GameServer()->SendChatTarget(m_pPlayer->GetCID(), "You finished with your best time.");
}
else
{
str_format(aBuf, sizeof(aBuf), "%5.2f second(s) worse, better luck next time.", fabs(pData->m_BestTime - time));
2010-11-04 18:20:45 +00:00
GameServer()->SendChatTarget(m_pPlayer->GetCID(), aBuf);//this is private, sent only to the tee
}
2010-11-04 18:20:45 +00:00
}
if(!pData->m_BestTime || time < pData->m_BestTime)
{
// update the score
pData->Set(time, m_CpCurrent);
if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0)
GameServer()->Score()->SaveScore(m_pPlayer->GetCID(), time, this);
}
bool NeedToSendNewRecord = false;
// update server best time
if(GameServer()->m_pController->m_CurrentRecord == 0 || time < GameServer()->m_pController->m_CurrentRecord)
{
// check for nameless
if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0) {
GameServer()->m_pController->m_CurrentRecord = time;
//dbg_msg("character", "Finish");
NeedToSendNewRecord = true;
}
}
2010-10-29 21:28:15 +00:00
m_DDRaceState = DDRACE_NONE;
// set player score
if(!GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime || GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime > time)
{
GameServer()->Score()->PlayerData(m_pPlayer->GetCID())->m_CurrentTime = time;
NeedToSendNewRecord = true;
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_IsUsingDDRaceClient)
{
if(!g_Config.m_SvHideScore || i == m_pPlayer->GetCID())
{
CNetMsg_Sv_PlayerTime Msg;
char aBuf[16];
str_format(aBuf, sizeof(aBuf), "%.0f", time*100.0f); // damn ugly but the only way i know to do it
int TimeToSend;
sscanf(aBuf, "%d", &TimeToSend);
Msg.m_Time = TimeToSend;
Msg.m_Cid = m_pPlayer->GetCID();
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, i);
}
}
}
}
if(NeedToSendNewRecord && GetPlayer()->m_IsUsingDDRaceClient) {
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(GameServer()->m_apPlayers[i] && GameServer()->m_apPlayers[i]->m_IsUsingDDRaceClient)
{
GameServer()->SendRecord(i);
}
}
}
if(GetPlayer()->m_IsUsingDDRaceClient) {
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)(time * 100.0f);
Msg.m_Check = 0;
Msg.m_Finish = 1;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID());
}
int TTime = 0-(int)time;
if(m_pPlayer->m_Score < TTime)
m_pPlayer->m_Score = TTime;
}
int CCharacter::Team()
{
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
return Controller->m_Teams.m_Core.Team(m_pPlayer->GetCID());
}
CGameTeams* CCharacter::Teams()
{
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
return &Controller->m_Teams;
}
void CCharacter::HandleFly()
{
m_Core.HandleFly();
}
2010-05-29 07:25:38 +00:00
void CCharacter::Tick()
{
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
std::list < int > Indices = GameServer()->Collision()->GetMapIndices(m_PrevPos, m_Pos);
//dbg_msg("Indices","%d",Indices.size());
2010-10-11 19:27:35 +00:00
/*if(m_pPlayer->m_ForceBalanced)
2010-10-08 13:33:42 +00:00
{
char Buf[128];
str_format(Buf, sizeof(Buf), "You were moved to %s due to team balancing", Controller->GetTeamName(m_pPlayer->GetTeam()));
GameServer()->SendBroadcast(Buf, m_pPlayer->GetCID());
2010-10-08 13:33:42 +00:00
m_pPlayer->m_ForceBalanced = false;
2010-10-11 19:27:35 +00:00
}*/
2010-10-08 13:33:42 +00:00
m_Armor=(m_FreezeTime != -1)?10-(m_FreezeTime/15):0;
if(m_Input.m_Direction != 0 || m_Input.m_Jump != 0)
m_LastMove = Server()->Tick();
2010-10-08 13:33:42 +00:00
if(m_FreezeTime > 0 || m_FreezeTime == -1)
{
if (m_FreezeTime % Server()->TickSpeed() == 0 || m_FreezeTime == -1)
{
GameServer()->CreateDamageInd(m_Pos, 0, m_FreezeTime / Server()->TickSpeed());
}
if(m_FreezeTime != -1)
m_FreezeTime--;
else
m_Ninja.m_ActivationTick = Server()->Tick();
m_Input.m_Direction = 0;
m_Input.m_Jump = 0;
m_Input.m_Hook = 0;
//m_Input.m_Fire = 0;
if (m_FreezeTime == 1) {
UnFreeze();
}
}
m_Core.m_Input = m_Input;
m_Core.Tick(true);
m_Core.m_Id = GetPlayer()->GetCID();
2010-10-08 13:33:42 +00:00
m_DoSplash = false;
if (g_Config.m_SvEndlessDrag)
m_Core.m_HookTick = 0;
if (m_Super && m_Core.m_Jumped > 1)
m_Core.m_Jumped = 1;
if (m_Super && g_Config.m_SvEndlessSuperHook)
m_Core.m_HookTick = 0;
/*dbg_msg("character","m_TileIndex=%d , m_TileFIndex=%d",m_TileIndex,m_TileFIndex); //REMOVE*/
//DDRace
char aBuftime[128];
m_Time = (float)(Server()->Tick() - m_StartTime) / ((float)Server()->TickSpeed());
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
2010-11-04 19:06:47 +00:00
if(!m_TimerReseted && m_DDRaceState == DDRACE_CHEAT) {
m_TimerReseted = true;
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = 0;
Msg.m_Check = 0;
Msg.m_Finish = 0;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID());
}
2010-10-08 13:33:42 +00:00
if(Server()->Tick() - m_RefreshTime >= Server()->TickSpeed())
{
2010-10-29 21:28:15 +00:00
if (m_DDRaceState == DDRACE_STARTED) {
2010-10-08 13:33:42 +00:00
int IntTime = (int)m_Time;
if(m_pPlayer->m_IsUsingDDRaceClient) {
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = IntTime;
Msg.m_Check = 0;
Msg.m_Finish = 0;
if(m_CpActive != -1 && m_CpTick > Server()->Tick())
{
if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0)
{
float Diff = (m_CpCurrent[m_CpActive] - pData->m_aBestCpTime[m_CpActive])*100;
Msg.m_Check = (int)Diff;
}
}
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, m_pPlayer->GetCID());
} else {
if(m_BroadTime)
str_format(aBuftime, sizeof(aBuftime), "%s%d:%s%d", ((IntTime/60) > 9)?"":"0", IntTime/60, ((IntTime%60) > 9)?"":"0", IntTime%60);
else
str_format(aBuftime, sizeof(aBuftime), "");
if(m_CpActive != -1 && m_CpTick > Server()->Tick())
{
if(pData->m_BestTime && pData->m_aBestCpTime[m_CpActive] != 0)
{
char aTmp[128];
float Diff = m_CpCurrent[m_CpActive] - pData->m_aBestCpTime[m_CpActive];
str_format(aTmp, sizeof(aTmp), "\nCheckpoint | Diff : %+5.2f", Diff);
strcat(aBuftime, aTmp);
}
}
if( g_Config.m_SvBroadcast[0] != 0 && m_BroadCast)
{
2010-10-08 13:33:42 +00:00
char aTmp[128];
str_format(aTmp, sizeof(aTmp), "\n%s\n", g_Config.m_SvBroadcast);
2010-10-08 13:33:42 +00:00
strcat(aBuftime, aTmp);
}
if(Server()->Tick() >= (m_LastBroadcast + Server()->TickSpeed()))
{
GameServer()->SendBroadcast(aBuftime, m_pPlayer->GetCID());
m_LastBroadcast = Server()->Tick();
}
2010-09-26 02:25:05 +00:00
}
2010-10-08 13:33:42 +00:00
2010-10-31 21:17:36 +00:00
} else {
if(!m_pPlayer->m_IsUsingDDRaceClient)
{
2010-10-08 13:33:42 +00:00
2010-10-31 21:17:36 +00:00
if( g_Config.m_SvBroadcast[0] != 0 && (Server()->Tick() > (m_LastBroadcast + (Server()->TickSpeed() * 9)))) {
char aTmp[128], aYourBest[64],aServerBest[64];
str_format(aYourBest, sizeof(aYourBest), "Your Best:'%s%d:%s%d'", ((pData->m_BestTime / 60) < 10)?"0":"", (int)(pData->m_BestTime / 60), (((int)pData->m_BestTime % 60) < 10)?"0":"", (int)pData->m_BestTime % 60);
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCID());
str_format(aServerBest, sizeof(aServerBest), "Server Best:'%s%d:%s%d'", ((GameServer()->m_pController->m_CurrentRecord / 60) < 10)?"0":"", (int)(GameServer()->m_pController->m_CurrentRecord / 60), (((int)GameServer()->m_pController->m_CurrentRecord % 60) < 10)?"0":"", (int)GameServer()->m_pController->m_CurrentRecord % 60);
str_format(aTmp, sizeof(aTmp), "%s\n%s %s", g_Config.m_SvBroadcast, (GameServer()->m_pController->m_CurrentRecord)?aServerBest:"", (pData->m_BestTime)?aYourBest:"");
GameServer()->SendBroadcast(aTmp, m_pPlayer->GetCID());
m_LastBroadcast = Server()->Tick();
}
} else {
//make there smthing with broadcast
2010-09-26 02:25:05 +00:00
}
2010-10-08 13:33:42 +00:00
}
m_RefreshTime = Server()->Tick();
}
2010-10-08 13:33:42 +00:00
//int num =0;
if(!Indices.empty())
for(std::list < int >::iterator i = Indices.begin(); i != Indices.end(); i++)
HandleTiles(*i);
else
HandleTiles(-1);
2010-10-10 23:46:13 +00:00
// kill player when leaving gamelayer
if((int)m_Pos.x/32 < -200 || (int)m_Pos.x/32 > GameServer()->Collision()->GetWidth()+200 ||
(int)m_Pos.y/32 < -200 || (int)m_Pos.y/32 > GameServer()->Collision()->GetHeight()+200)
{
Die(m_pPlayer->GetCID(), WEAPON_WORLD);
}
2010-05-29 07:25:38 +00:00
// handle Weapons
HandleWeapons();
2010-05-29 07:25:38 +00:00
m_PlayerState = m_Input.m_PlayerState;
// Previnput
2010-05-29 07:25:38 +00:00
m_PrevInput = m_Input;
if (!m_Doored)
{
m_OlderPos = m_OldPos;
m_OldPos = m_Core.m_Pos;
}
m_PrevPos = m_Core.m_Pos;
return;
}
2010-10-08 13:33:42 +00:00
void CCharacter::HandleTiles(int Index)
{//dbg_msg("num","%d",++num);
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
int MapIndex = Index;
2010-11-01 21:52:59 +00:00
float Offset = 4;
int MapIndexL = GameServer()->Collision()->GetPureMapIndex(vec2(m_Pos.x + (m_ProximityRadius/2)+Offset,m_Pos.y));
int MapIndexR = GameServer()->Collision()->GetPureMapIndex(vec2(m_Pos.x - (m_ProximityRadius/2)-Offset,m_Pos.y));
int MapIndexT = GameServer()->Collision()->GetPureMapIndex(vec2(m_Pos.x,m_Pos.y + (m_ProximityRadius/2)+Offset));
int MapIndexB = GameServer()->Collision()->GetPureMapIndex(vec2(m_Pos.x,m_Pos.y - (m_ProximityRadius/2)-Offset));
2010-10-08 13:33:42 +00:00
//dbg_msg("","N%d L%d R%d B%d T%d",MapIndex,MapIndexL,MapIndexR,MapIndexB,MapIndexT);
m_TileIndex = GameServer()->Collision()->GetTileIndex(MapIndex);
2010-11-01 01:51:17 +00:00
m_TileFlags = GameServer()->Collision()->GetTileFlags(MapIndex);
2010-10-08 13:33:42 +00:00
m_TileIndexL = GameServer()->Collision()->GetTileIndex(MapIndexL);
2010-11-01 01:51:17 +00:00
m_TileFlagsL = GameServer()->Collision()->GetTileFlags(MapIndexL);
2010-10-08 13:33:42 +00:00
m_TileIndexR = GameServer()->Collision()->GetTileIndex(MapIndexR);
2010-11-01 01:51:17 +00:00
m_TileFlagsR = GameServer()->Collision()->GetTileFlags(MapIndexR);
2010-10-08 13:33:42 +00:00
m_TileIndexB = GameServer()->Collision()->GetTileIndex(MapIndexB);
2010-11-01 01:51:17 +00:00
m_TileFlagsB = GameServer()->Collision()->GetTileFlags(MapIndexB);
2010-10-08 13:33:42 +00:00
m_TileIndexT = GameServer()->Collision()->GetTileIndex(MapIndexT);
2010-11-01 01:51:17 +00:00
m_TileFlagsT = GameServer()->Collision()->GetTileFlags(MapIndexT);
2010-10-08 13:33:42 +00:00
m_TileFIndex = GameServer()->Collision()->GetFTileIndex(MapIndex);
2010-11-01 01:51:17 +00:00
m_TileFFlags = GameServer()->Collision()->GetFTileFlags(MapIndex);
2010-10-08 13:33:42 +00:00
m_TileFIndexL = GameServer()->Collision()->GetFTileIndex(MapIndexL);
2010-11-01 01:51:17 +00:00
m_TileFFlagsL = GameServer()->Collision()->GetFTileFlags(MapIndexL);
2010-10-08 13:33:42 +00:00
m_TileFIndexR = GameServer()->Collision()->GetFTileIndex(MapIndexR);
2010-11-01 01:51:17 +00:00
m_TileFFlagsR = GameServer()->Collision()->GetFTileFlags(MapIndexR);
2010-10-08 13:33:42 +00:00
m_TileFIndexB = GameServer()->Collision()->GetFTileIndex(MapIndexB);
2010-11-01 01:51:17 +00:00
m_TileFFlagsB = GameServer()->Collision()->GetFTileFlags(MapIndexB);
2010-10-08 13:33:42 +00:00
m_TileFIndexT = GameServer()->Collision()->GetFTileIndex(MapIndexT);
2010-11-01 01:51:17 +00:00
m_TileFFlagsT = GameServer()->Collision()->GetFTileFlags(MapIndexT);
2010-10-08 13:33:42 +00:00
m_TileSIndex = GameServer()->Collision()->GetDTileIndex(MapIndex, Team());
2010-11-01 01:51:17 +00:00
m_TileSFlags = GameServer()->Collision()->GetDTileFlags(MapIndex, Team());
2010-10-08 13:33:42 +00:00
m_TileSIndexL = GameServer()->Collision()->GetDTileIndex(MapIndexL, Team());
2010-11-01 01:51:17 +00:00
m_TileSFlagsL = GameServer()->Collision()->GetDTileFlags(MapIndexL, Team());
2010-10-08 13:33:42 +00:00
m_TileSIndexR = GameServer()->Collision()->GetDTileIndex(MapIndexR, Team());
2010-11-01 01:51:17 +00:00
m_TileSFlagsR = GameServer()->Collision()->GetDTileFlags(MapIndexR, Team());
2010-10-08 13:33:42 +00:00
m_TileSIndexB = GameServer()->Collision()->GetDTileIndex(MapIndexB, Team());
2010-11-01 01:51:17 +00:00
m_TileSFlagsB = GameServer()->Collision()->GetDTileFlags(MapIndexB, Team());
2010-10-08 13:33:42 +00:00
m_TileSIndexT = GameServer()->Collision()->GetDTileIndex(MapIndexT, Team());
2010-11-01 01:51:17 +00:00
m_TileSFlagsT = GameServer()->Collision()->GetDTileFlags(MapIndexT, Team());
2010-10-08 13:33:42 +00:00
//dbg_msg("","N%d L%d R%d B%d T%d",m_TileIndex,m_TileIndexL,m_TileIndexR,m_TileIndexB,m_TileIndexT);
//dbg_msg("","N%d L%d R%d B%d T%d",m_TileFIndex,m_TileFIndexL,m_TileFIndexR,m_TileFIndexB,m_TileFIndexT);
int cp = GameServer()->Collision()->IsCheckpoint(MapIndex);
2010-10-29 21:28:15 +00:00
if(cp != -1 && m_DDRaceState == DDRACE_STARTED && cp > m_CpActive)
2010-10-08 13:33:42 +00:00
{
m_CpActive = cp;
m_CpCurrent[cp] = m_Time;
m_CpTick = Server()->Tick() + Server()->TickSpeed()*2;
}
2010-10-30 18:48:30 +00:00
int cpf = GameServer()->Collision()->IsFCheckpoint(MapIndex);
if(cpf != -1 && m_DDRaceState == DDRACE_STARTED && cpf > m_CpActive)
{
m_CpActive = cpf;
m_CpCurrent[cpf] = m_Time;
m_CpTick = Server()->Tick() + Server()->TickSpeed()*2;
}
2010-10-29 21:28:15 +00:00
if(((m_TileIndex == TILE_BEGIN) || (m_TileFIndex == TILE_BEGIN)) && (m_DDRaceState == DDRACE_NONE || (m_DDRaceState == DDRACE_STARTED && !Team())))
2010-10-08 13:33:42 +00:00
{
Controller->m_Teams.OnCharacterStart(m_pPlayer->GetCID());
m_CpActive = -2;
}
2010-10-29 21:28:15 +00:00
if(((m_TileIndex == TILE_END) || (m_TileFIndex == TILE_END)) && m_DDRaceState == DDRACE_STARTED)
2010-10-08 13:33:42 +00:00
{
Controller->m_Teams.OnCharacterFinish(m_pPlayer->GetCID());
}
if(((m_TileIndex == TILE_FREEZE) || (m_TileFIndex == TILE_FREEZE)) && !m_Super)
{
Freeze(Server()->TickSpeed()*3);
}
else if((m_TileIndex == TILE_UNFREEZE) || (m_TileFIndex == TILE_UNFREEZE))
{
UnFreeze();
}
2010-11-01 01:51:17 +00:00
if(((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_270) || (m_TileIndexL == TILE_STOP && m_TileFlagsL == ROTATION_270) || (m_TileIndexL == TILE_STOPS && (m_TileFlagsL == ROTATION_90 || m_TileFlagsL ==ROTATION_270)) || (m_TileIndexL == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_270) || (m_TileFIndexL == TILE_STOP && m_TileFFlagsL == ROTATION_270) || (m_TileFIndexL == TILE_STOPS && (m_TileFFlagsL == ROTATION_90 || m_TileFFlagsL == ROTATION_270)) || (m_TileFIndexL == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_270) || (m_TileSIndexL == TILE_STOP && m_TileSFlagsL == ROTATION_270) || (m_TileSIndexL == TILE_STOPS && (m_TileSFlagsL == ROTATION_90 || m_TileSFlagsL == ROTATION_270)) || (m_TileSIndexL == TILE_STOPA)) && m_Core.m_Vel.x > 0)
2010-10-08 13:33:42 +00:00
{
if((int)GameServer()->Collision()->GetPos(MapIndexL).x)
if((int)GameServer()->Collision()->GetPos(MapIndexL).x < (int)m_Core.m_Pos.x)
m_Core.m_Pos = m_PrevPos;
m_Core.m_Vel.x = 0;
}
2010-11-01 01:51:17 +00:00
if(((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_90) || (m_TileIndexR == TILE_STOP && m_TileFlagsR == ROTATION_90) || (m_TileIndexR == TILE_STOPS && (m_TileFlagsR == ROTATION_90 || m_TileFlagsR == ROTATION_270)) || (m_TileIndexR == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_90) || (m_TileFIndexR == TILE_STOP && m_TileFFlagsR == ROTATION_90) || (m_TileFIndexR == TILE_STOPS && (m_TileFFlagsR == ROTATION_90 || m_TileFFlagsR == ROTATION_270)) || (m_TileFIndexR == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_90) || (m_TileSIndexR == TILE_STOP && m_TileSFlagsR == ROTATION_90) || (m_TileSIndexR == TILE_STOPS && (m_TileSFlagsR == ROTATION_90 || m_TileSFlagsR == ROTATION_270)) || (m_TileSIndexR == TILE_STOPA)) && m_Core.m_Vel.x < 0)
2010-10-08 13:33:42 +00:00
{
if((int)GameServer()->Collision()->GetPos(MapIndexR).x)
if((int)GameServer()->Collision()->GetPos(MapIndexR).x > (int)m_Core.m_Pos.x)
m_Core.m_Pos = m_PrevPos;
m_Core.m_Vel.x = 0;
}
2010-11-01 01:51:17 +00:00
if(((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_180) || (m_TileIndexB == TILE_STOP && m_TileFlagsB == ROTATION_180) || (m_TileIndexB == TILE_STOPS && (m_TileFlagsB == ROTATION_0 || m_TileFlagsB == ROTATION_180)) || (m_TileIndexB == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_180) || (m_TileFIndexB == TILE_STOP && m_TileFFlagsB == ROTATION_180) || (m_TileFIndexB == TILE_STOPS && (m_TileFFlagsB == ROTATION_0 || m_TileFFlagsB == ROTATION_180)) || (m_TileFIndexB == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_180) || (m_TileSIndexB == TILE_STOP && m_TileSFlagsB == ROTATION_180) || (m_TileSIndexB == TILE_STOPS && (m_TileSFlagsB == ROTATION_0 || m_TileSFlagsB == ROTATION_180)) || (m_TileSIndexB == TILE_STOPA)) && m_Core.m_Vel.y < 0)
2010-10-08 13:33:42 +00:00
{
if((int)GameServer()->Collision()->GetPos(MapIndexB).y)
if((int)GameServer()->Collision()->GetPos(MapIndexB).y > (int)m_Core.m_Pos.y)
m_Core.m_Pos = m_PrevPos;
m_Core.m_Vel.y = 0;
}
2010-11-01 01:51:17 +00:00
if(((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_0) || (m_TileIndexT == TILE_STOP && m_TileFlagsT == ROTATION_0) || (m_TileIndexT == TILE_STOPS && (m_TileFlagsT == ROTATION_0 || m_TileFlagsT == ROTATION_180)) || (m_TileIndexT == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_0) || (m_TileFIndexT == TILE_STOP && m_TileFFlagsT == ROTATION_0) || (m_TileFIndexT == TILE_STOPS && (m_TileFFlagsT == ROTATION_0 || m_TileFFlagsT == ROTATION_180)) || (m_TileFIndexT == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_0) || (m_TileSIndexT == TILE_STOP && m_TileSFlagsT == ROTATION_0) || (m_TileSIndexT == TILE_STOPS && (m_TileSFlagsT == ROTATION_0 || m_TileSFlagsT == ROTATION_180)) || (m_TileSIndexT == TILE_STOPA)) && m_Core.m_Vel.y > 0)
2010-10-08 13:33:42 +00:00
{
//dbg_msg("","%f %f",GameServer()->Collision()->GetPos(MapIndex).y,m_Core.m_Pos.y);
if((int)GameServer()->Collision()->GetPos(MapIndexT).y)
if((int)GameServer()->Collision()->GetPos(MapIndexT).y < (int)m_Core.m_Pos.y)
m_Core.m_Pos = m_PrevPos;
m_Core.m_Vel.y = 0;
m_Core.m_Jumped = 0;
}
// handle speedup tiles
if(GameServer()->Collision()->IsSpeedup(MapIndex) == TILE_BOOST)
{
vec2 Direction, MaxVel, TempVel = m_Core.m_Vel;
int Force, MaxSpeed = 0;
2010-10-31 15:36:04 +00:00
float TeeAngle, SpeederAngle, DiffAngle, SpeedLeft, TeeSpeed;
const float Zero=0;
2010-10-08 13:33:42 +00:00
GameServer()->Collision()->GetSpeedup(MapIndex, &Direction, &Force, &MaxSpeed);
if(Force == 255 && MaxSpeed)
2010-10-31 15:36:04 +00:00
{
m_Core.m_Vel = Direction * (MaxSpeed/5);
}
else
{
if(MaxSpeed > 0 && MaxSpeed < 5) MaxSpeed = 5;
//dbg_msg("speedup tile start","Direction %f %f, Force %d, Max Speed %d", (Direction).x,(Direction).y, Force, MaxSpeed);
if(
((Direction.x < 0) && ((int)GameServer()->Collision()->GetPos(MapIndexL).x) && ((int)GameServer()->Collision()->GetPos(MapIndexL).x < (int)m_Core.m_Pos.x)) ||
((Direction.x > 0) && ((int)GameServer()->Collision()->GetPos(MapIndexR).x) && ((int)GameServer()->Collision()->GetPos(MapIndexR).x > (int)m_Core.m_Pos.x)) ||
((Direction.y > 0) && ((int)GameServer()->Collision()->GetPos(MapIndexB).y) && ((int)GameServer()->Collision()->GetPos(MapIndexB).y > (int)m_Core.m_Pos.y)) ||
((Direction.y < 0) && ((int)GameServer()->Collision()->GetPos(MapIndexT).y) && ((int)GameServer()->Collision()->GetPos(MapIndexT).y < (int)m_Core.m_Pos.y))
)
m_Core.m_Pos = m_PrevPos;
2010-10-31 15:36:04 +00:00
if(MaxSpeed > 0)
{
if(Direction.x > 0.0000001f)
SpeederAngle = -atan(Direction.y / Direction.x);
else if(Direction.x < 0.0000001f)
SpeederAngle = atan(Direction.y / Direction.x) + 2.0f * asin(1.0f);
else if(Direction.y > 0.0000001f)
SpeederAngle = asin(1.0f);
else
SpeederAngle = asin(-1.0f);
2010-10-31 16:42:37 +00:00
if(SpeederAngle < 0)
SpeederAngle = 4.0f * asin(1.0f) + SpeederAngle;
if(TempVel.x > 0.0000001f)
TeeAngle = -atan(TempVel.y / TempVel.x);
else if(TempVel.x < 0.0000001f)
TeeAngle = atan(TempVel.y / TempVel.x) + 2.0f * asin(1.0f);
else if(TempVel.y > 0.0000001f)
TeeAngle = asin(1.0f);
else
TeeAngle = asin(-1.0f);
if(TeeAngle < 0)
TeeAngle = 4.0f * asin(1.0f) + TeeAngle;
TeeSpeed = sqrt(pow(TempVel.x, 2) + pow(TempVel.y, 2));
DiffAngle = SpeederAngle - TeeAngle;
SpeedLeft = MaxSpeed / 5.0f - cos(DiffAngle) * TeeSpeed;
//dbg_msg("speedup tile debug","MaxSpeed %i, TeeSpeed %f, SpeedLeft %f, SpeederAngle %f, TeeAngle %f", MaxSpeed, TeeSpeed, SpeedLeft, SpeederAngle, TeeAngle);
if(abs(SpeedLeft) > Force && SpeedLeft > 0.0000001f)
TempVel += Direction * Force;
else if(abs(SpeedLeft) > Force)
TempVel += Direction * -Force;
else
TempVel += Direction * SpeedLeft;
}
2010-10-31 15:36:04 +00:00
else
TempVel += Direction * Force;
if(TempVel.x > 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_270) || (m_TileIndexL == TILE_STOP && m_TileFlagsL == ROTATION_270) || (m_TileIndexL == TILE_STOPS && (m_TileFlagsL == ROTATION_90 || m_TileFlagsL ==ROTATION_270)) || (m_TileIndexL == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_270) || (m_TileFIndexL == TILE_STOP && m_TileFFlagsL == ROTATION_270) || (m_TileFIndexL == TILE_STOPS && (m_TileFFlagsL == ROTATION_90 || m_TileFFlagsL == ROTATION_270)) || (m_TileFIndexL == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_270) || (m_TileSIndexL == TILE_STOP && m_TileSFlagsL == ROTATION_270) || (m_TileSIndexL == TILE_STOPS && (m_TileSFlagsL == ROTATION_90 || m_TileSFlagsL == ROTATION_270)) || (m_TileSIndexL == TILE_STOPA)))
TempVel.x = 0;
if(TempVel.x < 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_90) || (m_TileIndexR == TILE_STOP && m_TileFlagsR == ROTATION_90) || (m_TileIndexR == TILE_STOPS && (m_TileFlagsR == ROTATION_90 || m_TileFlagsR == ROTATION_270)) || (m_TileIndexR == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_90) || (m_TileFIndexR == TILE_STOP && m_TileFFlagsR == ROTATION_90) || (m_TileFIndexR == TILE_STOPS && (m_TileFFlagsR == ROTATION_90 || m_TileFFlagsR == ROTATION_270)) || (m_TileFIndexR == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_90) || (m_TileSIndexR == TILE_STOP && m_TileSFlagsR == ROTATION_90) || (m_TileSIndexR == TILE_STOPS && (m_TileSFlagsR == ROTATION_90 || m_TileSFlagsR == ROTATION_270)) || (m_TileSIndexR == TILE_STOPA)))
TempVel.x = 0;
if(TempVel.y < 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_180) || (m_TileIndexB == TILE_STOP && m_TileFlagsB == ROTATION_180) || (m_TileIndexB == TILE_STOPS && (m_TileFlagsB == ROTATION_0 || m_TileFlagsB == ROTATION_180)) || (m_TileIndexB == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_180) || (m_TileFIndexB == TILE_STOP && m_TileFFlagsB == ROTATION_180) || (m_TileFIndexB == TILE_STOPS && (m_TileFFlagsB == ROTATION_0 || m_TileFFlagsB == ROTATION_180)) || (m_TileFIndexB == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_180) || (m_TileSIndexB == TILE_STOP && m_TileSFlagsB == ROTATION_180) || (m_TileSIndexB == TILE_STOPS && (m_TileSFlagsB == ROTATION_0 || m_TileSFlagsB == ROTATION_180)) || (m_TileSIndexB == TILE_STOPA)))
TempVel.y = 0;
if(TempVel.y > 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_0) || (m_TileIndexT == TILE_STOP && m_TileFlagsT == ROTATION_0) || (m_TileIndexT == TILE_STOPS && (m_TileFlagsT == ROTATION_0 || m_TileFlagsT == ROTATION_180)) || (m_TileIndexT == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_0) || (m_TileFIndexT == TILE_STOP && m_TileFFlagsT == ROTATION_0) || (m_TileFIndexT == TILE_STOPS && (m_TileFFlagsT == ROTATION_0 || m_TileFFlagsT == ROTATION_180)) || (m_TileFIndexT == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_0) || (m_TileSIndexT == TILE_STOP && m_TileSFlagsT == ROTATION_0) || (m_TileSIndexT == TILE_STOPS && (m_TileSFlagsT == ROTATION_0 || m_TileSFlagsT == ROTATION_180)) || (m_TileSIndexT == TILE_STOPA)))
TempVel.y = 0;
m_Core.m_Vel = TempVel;
//dbg_msg("speedup tile end","(Direction*Force) %f %f m_Core.m_Vel%f %f",(Direction*Force).x,(Direction*Force).y,m_Core.m_Vel.x,m_Core.m_Vel.y);
//dbg_msg("speedup tile end","Direction %f %f, Force %d, Max Speed %d", (Direction).x,(Direction).y, Force, MaxSpeed);
2010-10-31 15:36:04 +00:00
}
2010-11-04 09:19:07 +00:00
}
2010-10-08 13:33:42 +00:00
m_LastBooster = MapIndex;
int z = GameServer()->Collision()->IsTeleport(MapIndex);
if(z && ((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts[z-1].size())
2010-10-08 13:33:42 +00:00
{
m_Core.m_HookedPlayer = -1;
m_Core.m_HookState = HOOK_RETRACTED;
m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
m_Core.m_HookState = HOOK_RETRACTED;
int Num = (((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts[z-1].size());
m_Core.m_Pos = ((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts[z-1][(!Num)?Num:rand() % Num];
m_Core.m_HookPos = m_Core.m_Pos;
2010-10-10 23:46:13 +00:00
return;
2010-10-08 13:33:42 +00:00
}
int evilz = GameServer()->Collision()->IsEvilTeleport(MapIndex);
if(evilz && !m_Super && ((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts[evilz-1].size())
2010-10-08 13:33:42 +00:00
{
m_Core.m_HookedPlayer = -1;
m_Core.m_HookState = HOOK_RETRACTED;
m_Core.m_TriggeredEvents |= COREEVENT_HOOK_RETRACT;
m_Core.m_HookState = HOOK_RETRACTED;
GameWorld()->ReleaseHooked(GetPlayer()->GetCID());
int Num = (((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts[evilz-1].size());
m_Core.m_Pos = ((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts[evilz-1][(!Num)?Num:rand() % Num];
m_Core.m_HookPos = m_Core.m_Pos;
m_Core.m_Vel = vec2(0,0);
2010-10-10 23:46:13 +00:00
return;
2010-10-08 13:33:42 +00:00
}
2010-10-10 23:46:13 +00:00
// handle death-tiles
if((GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetFCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetFCollisionAt(m_Pos.x+m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetFCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y-m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH ||
GameServer()->Collision()->GetFCollisionAt(m_Pos.x-m_ProximityRadius/3.f, m_Pos.y+m_ProximityRadius/3.f)&CCollision::COLFLAG_DEATH)&&
!m_Super)
{
Die(m_pPlayer->GetCID(), WEAPON_WORLD);
return;
}
2010-10-08 13:33:42 +00:00
}
float point_distance(vec2 point, vec2 line_start, vec2 line_end)
{
float res = -1.0f;
vec2 dir = normalize(line_end-line_start);
for(int i = 0; i < length(line_end-line_start); i++)
{
vec2 step = dir;
step.x *= i;
step.y *= i;
float dist = distance(step+line_start, point);
if(res < 0 || dist < res)
res = dist;
}
return res;
}
void CCharacter::ResetPos()
{
m_Core.m_Pos = m_OlderPos;
//core.pos-=core.vel;
m_Core.m_Vel = vec2(0,0);
if(m_Core.m_Jumped >= 2)
m_Core.m_Jumped = 1;
}
2010-05-29 07:25:38 +00:00
void CCharacter::TickDefered()
{
2008-09-23 07:43:41 +00:00
// advance the dummy
{
2010-05-29 07:25:38 +00:00
CWorldCore TempWorld;
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
m_ReckoningCore.Init(&TempWorld, GameServer()->Collision(), &Controller->m_Teams.m_Core);
2010-05-29 07:25:38 +00:00
m_ReckoningCore.Tick(false);
m_ReckoningCore.Move();
m_ReckoningCore.Quantize();
2008-09-23 07:43:41 +00:00
}
2010-05-29 07:25:38 +00:00
//lastsentcore
vec2 StartPos = m_Core.m_Pos;
vec2 StartVel = m_Core.m_Vel;
bool StuckBefore = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f));
2010-05-29 07:25:38 +00:00
m_Core.Move();
if(m_Doored)
{
ResetPos();
m_Doored = false;
}
/*if((m_Stopped&STOPPED_LEFT && m_Core.m_Vel.x > 0)||(m_Stopped&STOPPED_RIGHT && m_Core.m_Vel.x < 0))
m_Core.m_Vel.x=0;
if((m_Stopped&STOPPED_BOTTOM && m_Core.m_Vel.y < 0)||(m_Stopped&STOPPED_TOP && m_Core.m_Vel.y > 0))
m_Core.m_Vel.y=0;*/
2010-05-29 07:25:38 +00:00
bool StuckAfterMove = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f));
m_Core.Quantize();
bool StuckAfterQuant = GameServer()->Collision()->TestBox(m_Core.m_Pos, vec2(28.0f, 28.0f));
m_Pos = m_Core.m_Pos;
2010-05-29 07:25:38 +00:00
if(!StuckBefore && (StuckAfterMove || StuckAfterQuant))
{
// Hackish solution to get rid of strict-aliasing warning
union
{
float f;
unsigned u;
}StartPosX, StartPosY, StartVelX, StartVelY;
StartPosX.f = StartPos.x;
StartPosY.f = StartPos.y;
StartVelX.f = StartVel.x;
StartVelY.f = StartVel.y;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x",
2010-05-29 07:25:38 +00:00
StuckBefore,
StuckAfterMove,
StuckAfterQuant,
StartPos.x, StartPos.y,
StartVel.x, StartVel.y,
StartPosX.u, StartPosY.u,
StartVelX.u, StartVelY.u);
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
2010-05-29 07:25:38 +00:00
}
2010-05-29 07:25:38 +00:00
int Events = m_Core.m_TriggeredEvents;
int Mask = CmaskAllExceptOne(m_pPlayer->GetCID());
2010-05-29 07:25:38 +00:00
if(Events&COREEVENT_GROUND_JUMP) GameServer()->CreateSound(m_Pos, SOUND_PLAYER_JUMP, Mask);
2010-05-29 07:25:38 +00:00
if(Events&COREEVENT_HOOK_ATTACH_PLAYER) GameServer()->CreateSound(m_Pos, SOUND_HOOK_ATTACH_PLAYER, CmaskAll());
if(Events&COREEVENT_HOOK_ATTACH_GROUND) GameServer()->CreateSound(m_Pos, SOUND_HOOK_ATTACH_GROUND, Mask);
if(Events&COREEVENT_HOOK_HIT_NOHOOK) GameServer()->CreateSound(m_Pos, SOUND_HOOK_NOATTACH, Mask);
2010-05-29 07:25:38 +00:00
if(m_pPlayer->GetTeam() == -1)
{
2010-05-29 07:25:38 +00:00
m_Pos.x = m_Input.m_TargetX;
m_Pos.y = m_Input.m_TargetY;
}
2010-05-29 07:25:38 +00:00
// update the m_SendCore if needed
2008-09-23 07:43:41 +00:00
{
2010-05-29 07:25:38 +00:00
CNetObj_Character Predicted;
CNetObj_Character Current;
mem_zero(&Predicted, sizeof(Predicted));
mem_zero(&Current, sizeof(Current));
m_ReckoningCore.Write(&Predicted);
m_Core.Write(&Current);
// only allow dead reackoning for a top of 3 seconds
if(m_Core.m_pReset || m_ReckoningTick+Server()->TickSpeed()*3 < Server()->Tick() || mem_comp(&Predicted, &Current, sizeof(CNetObj_Character)) != 0)
2008-09-23 07:43:41 +00:00
{
2010-05-29 07:25:38 +00:00
m_ReckoningTick = Server()->Tick();
m_SendCore = m_Core;
m_ReckoningCore = m_Core;
m_Core.m_pReset = false;
2008-09-23 07:43:41 +00:00
}
}
}
bool CCharacter::Freeze(int Time)
{
if ((Time <= 1 || m_Super || m_FreezeTime == -1) && Time != -1)
return false;
if (m_FreezeTick < Server()->Tick() - Server()->TickSpeed())
{
for(int i=0;i<NUM_WEAPONS;i++)
if(m_aWeapons[i].m_Got)
{
m_aWeapons[i].m_Ammo = 0;
}
m_Armor=0;
m_FreezeTime=Time;
m_FreezeTick=Server()->Tick();
return true;
}
return false;
}
bool CCharacter::Freeze()
{
int Time = Server()->TickSpeed()*3;
if (Time <= 1 || m_Super || m_FreezeTime == -1)
return false;
if (m_FreezeTick < Server()->Tick() - Server()->TickSpeed())
{
for(int i=0;i<NUM_WEAPONS;i++)
if(m_aWeapons[i].m_Got)
{
m_aWeapons[i].m_Ammo = 0;
}
m_Armor=0;
m_Ninja.m_ActivationTick = Server()->Tick();
m_FreezeTime=Time;
m_FreezeTick=Server()->Tick();
return true;
}
return false;
}
bool CCharacter::UnFreeze()
{
if (m_FreezeTime>0)
{
m_Armor=10;
for(int i=0;i<NUM_WEAPONS;i++)
if(m_aWeapons[i].m_Got)
{
m_aWeapons[i].m_Ammo = -1;
}
if(!m_aWeapons[m_ActiveWeapon].m_Got)
m_ActiveWeapon = WEAPON_GUN;
m_FreezeTime = 0;
m_FreezeTick = 0;
m_ReloadTimer = 0;
return true;
}
return false;
}
void CCharacter::GiveAllWeapons()
{
for(int i=1;i<NUM_WEAPONS-1;i++)
{
m_aWeapons[i].m_Got = true;
if(!m_FreezeTime) m_aWeapons[i].m_Ammo = -1;
}
return;
}
2010-05-29 07:25:38 +00:00
bool CCharacter::IncreaseHealth(int Amount)
{
2010-05-29 07:25:38 +00:00
if(m_Health >= 10)
return false;
2010-05-29 07:25:38 +00:00
m_Health = clamp(m_Health+Amount, 0, 10);
return true;
}
2010-05-29 07:25:38 +00:00
bool CCharacter::IncreaseArmor(int Amount)
{
2010-05-29 07:25:38 +00:00
if(m_Armor >= 10)
return false;
2010-05-29 07:25:38 +00:00
m_Armor = clamp(m_Armor+Amount, 0, 10);
return true;
}
2010-05-29 07:25:38 +00:00
void CCharacter::Die(int Killer, int Weapon)
{
2010-05-29 07:25:38 +00:00
int ModeSpecial = GameServer()->m_pController->OnCharacterDeath(this, GameServer()->m_apPlayers[Killer], Weapon);
CGameControllerDDRace* Controller = (CGameControllerDDRace*)GameServer()->m_pController;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d",
2010-05-29 07:25:38 +00:00
Killer, Server()->ClientName(Killer),
m_pPlayer->GetCID(), Server()->ClientName(m_pPlayer->GetCID()), Weapon, ModeSpecial);
GameServer()->Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
2010-09-22 10:43:59 +00:00
Controller->m_Teams.SetForceCharacterTeam(m_pPlayer->GetCID(), 0);
// send the kill message
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_KillMsg Msg;
Msg.m_Killer = Killer;
Msg.m_Victim = m_pPlayer->GetCID();
Msg.m_Weapon = Weapon;
Msg.m_ModeSpecial = ModeSpecial;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, -1);
// a nice sound
2010-05-29 07:25:38 +00:00
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_DIE);
2008-11-16 14:28:44 +00:00
// this is for auto respawn after 3 secs
2010-05-29 07:25:38 +00:00
m_pPlayer->m_DieTick = Server()->Tick();
2010-05-29 07:25:38 +00:00
m_Alive = false;
GameServer()->m_World.RemoveEntity(this);
GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = 0;
GameServer()->CreateDeath(m_Pos, m_pPlayer->GetCID());
2008-11-16 14:28:44 +00:00
// we got to wait 0.5 secs before respawning
2010-05-29 07:25:38 +00:00
m_pPlayer->m_RespawnTick = Server()->Tick()+Server()->TickSpeed()/2;
}
2010-05-29 07:25:38 +00:00
bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon)
{
2010-11-01 12:12:59 +00:00
vec2 Temp = m_Core.m_Vel + Force;
if(Temp.x > 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_270) || (m_TileIndexL == TILE_STOP && m_TileFlagsL == ROTATION_270) || (m_TileIndexL == TILE_STOPS && (m_TileFlagsL == ROTATION_90 || m_TileFlagsL ==ROTATION_270)) || (m_TileIndexL == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_270) || (m_TileFIndexL == TILE_STOP && m_TileFFlagsL == ROTATION_270) || (m_TileFIndexL == TILE_STOPS && (m_TileFFlagsL == ROTATION_90 || m_TileFFlagsL == ROTATION_270)) || (m_TileFIndexL == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_270) || (m_TileSIndexL == TILE_STOP && m_TileSFlagsL == ROTATION_270) || (m_TileSIndexL == TILE_STOPS && (m_TileSFlagsL == ROTATION_90 || m_TileSFlagsL == ROTATION_270)) || (m_TileSIndexL == TILE_STOPA)))
Temp.x = 0;
if(Temp.x < 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_90) || (m_TileIndexR == TILE_STOP && m_TileFlagsR == ROTATION_90) || (m_TileIndexR == TILE_STOPS && (m_TileFlagsR == ROTATION_90 || m_TileFlagsR == ROTATION_270)) || (m_TileIndexR == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_90) || (m_TileFIndexR == TILE_STOP && m_TileFFlagsR == ROTATION_90) || (m_TileFIndexR == TILE_STOPS && (m_TileFFlagsR == ROTATION_90 || m_TileFFlagsR == ROTATION_270)) || (m_TileFIndexR == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_90) || (m_TileSIndexR == TILE_STOP && m_TileSFlagsR == ROTATION_90) || (m_TileSIndexR == TILE_STOPS && (m_TileSFlagsR == ROTATION_90 || m_TileSFlagsR == ROTATION_270)) || (m_TileSIndexR == TILE_STOPA)))
Temp.x = 0;
if(Temp.y < 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_180) || (m_TileIndexB == TILE_STOP && m_TileFlagsB == ROTATION_180) || (m_TileIndexB == TILE_STOPS && (m_TileFlagsB == ROTATION_0 || m_TileFlagsB == ROTATION_180)) || (m_TileIndexB == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_180) || (m_TileFIndexB == TILE_STOP && m_TileFFlagsB == ROTATION_180) || (m_TileFIndexB == TILE_STOPS && (m_TileFFlagsB == ROTATION_0 || m_TileFFlagsB == ROTATION_180)) || (m_TileFIndexB == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_180) || (m_TileSIndexB == TILE_STOP && m_TileSFlagsB == ROTATION_180) || (m_TileSIndexB == TILE_STOPS && (m_TileSFlagsB == ROTATION_0 || m_TileSFlagsB == ROTATION_180)) || (m_TileSIndexB == TILE_STOPA)))
Temp.y = 0;
if(Temp.y > 0 && ((m_TileIndex == TILE_STOP && m_TileFlags == ROTATION_0) || (m_TileIndexT == TILE_STOP && m_TileFlagsT == ROTATION_0) || (m_TileIndexT == TILE_STOPS && (m_TileFlagsT == ROTATION_0 || m_TileFlagsT == ROTATION_180)) || (m_TileIndexT == TILE_STOPA) || (m_TileFIndex == TILE_STOP && m_TileFFlags == ROTATION_0) || (m_TileFIndexT == TILE_STOP && m_TileFFlagsT == ROTATION_0) || (m_TileFIndexT == TILE_STOPS && (m_TileFFlagsT == ROTATION_0 || m_TileFFlagsT == ROTATION_180)) || (m_TileFIndexT == TILE_STOPA) || (m_TileSIndex == TILE_STOP && m_TileSFlags == ROTATION_0) || (m_TileSIndexT == TILE_STOP && m_TileSFlagsT == ROTATION_0) || (m_TileSIndexT == TILE_STOPS && (m_TileSFlagsT == ROTATION_0 || m_TileSFlagsT == ROTATION_180)) || (m_TileSIndexT == TILE_STOPA)))
Temp.y = 0;
m_Core.m_Vel = Temp;
/*
2010-05-29 07:25:38 +00:00
if(GameServer()->m_pController->IsFriendlyFire(m_pPlayer->GetCID(), From) && !g_Config.m_SvTeamdamage)
return false;
2010-05-29 07:25:38 +00:00
// m_pPlayer only inflicts half damage on self
if(From == m_pPlayer->GetCID())
Dmg = max(1, Dmg/2);
2010-05-29 07:25:38 +00:00
m_DamageTaken++;
// create healthmod indicator
2010-05-29 07:25:38 +00:00
if(Server()->Tick() < m_DamageTakenTick+25)
{
// make sure that the damage indicators doesn't group together
2010-05-29 07:25:38 +00:00
GameServer()->CreateDamageInd(m_Pos, m_DamageTaken*0.25f, Dmg);
}
else
{
2010-05-29 07:25:38 +00:00
m_DamageTaken = 0;
GameServer()->CreateDamageInd(m_Pos, 0, Dmg);
}
2010-05-29 07:25:38 +00:00
if(Dmg)
{
2010-05-29 07:25:38 +00:00
if(m_Armor)
{
2010-05-29 07:25:38 +00:00
if(Dmg > 1)
{
2010-05-29 07:25:38 +00:00
m_Health--;
Dmg--;
}
2010-05-29 07:25:38 +00:00
if(Dmg > m_Armor)
{
2010-05-29 07:25:38 +00:00
Dmg -= m_Armor;
m_Armor = 0;
}
else
{
2010-05-29 07:25:38 +00:00
m_Armor -= Dmg;
Dmg = 0;
}
}
2010-05-29 07:25:38 +00:00
m_Health -= Dmg;
}
2010-05-29 07:25:38 +00:00
m_DamageTakenTick = Server()->Tick();
2010-05-29 07:25:38 +00:00
// do damage Hit sound
if(From >= 0 && From != m_pPlayer->GetCID() && GameServer()->m_apPlayers[From])
GameServer()->CreateSound(GameServer()->m_apPlayers[From]->m_ViewPos, SOUND_HIT, CmaskOne(From));
// check for death
2010-05-29 07:25:38 +00:00
if(m_Health <= 0)
{
2010-05-29 07:25:38 +00:00
Die(From, Weapon);
return false;
}
2010-05-29 07:25:38 +00:00
if (Dmg > 2)
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_LONG);
else
2010-05-29 07:25:38 +00:00
GameServer()->CreateSound(m_Pos, SOUND_PLAYER_PAIN_SHORT);
*/
// set attacker's face to happy (taunt!)
/*if(g_Config.m_SvEmotionalTees)
{
if (From >= 0 && From != m_pPlayer->GetCID() && GameServer()->m_apPlayers[From])
{
CCharacter *pChr = GameServer()->m_apPlayers[From]->GetCharacter();
if (pChr)
{
pChr->m_EmoteType = EMOTE_HAPPY;
pChr->m_EmoteStop = Server()->Tick() + Server()->TickSpeed();
}
}*///Removed you can set your emote via /emoteEMOTENAME
//set the attacked face to pain
2010-05-29 07:25:38 +00:00
m_EmoteType = EMOTE_PAIN;
m_EmoteStop = Server()->Tick() + 500 * Server()->TickSpeed() / 1000;
return true;
}
2010-05-29 07:25:38 +00:00
void CCharacter::Snap(int SnappingClient)
{
2010-05-29 07:25:38 +00:00
if(NetworkClipped(SnappingClient))
return;
CCharacter* SnapChar = GameServer()->GetPlayerChar(SnappingClient);
if(SnapChar && !SnapChar->m_Super &&
GameServer()->m_apPlayers[SnappingClient]->GetTeam() != -1 &&
2010-10-29 21:28:15 +00:00
!CanCollide(SnappingClient) && !GameServer()->m_apPlayers[SnappingClient]->m_IsUsingDDRaceClient) return;
if(GetPlayer()->m_Invisible &&
GetPlayer()->GetCID() != SnappingClient &&
GameServer()->m_apPlayers[SnappingClient]->m_Authed < GetPlayer()->m_Authed
)
return;
2010-05-29 07:25:38 +00:00
CNetObj_Character *Character = static_cast<CNetObj_Character *>(Server()->SnapNewItem(NETOBJTYPE_CHARACTER, m_pPlayer->GetCID(), sizeof(CNetObj_Character)));
2010-05-29 07:25:38 +00:00
// write down the m_Core
2010-08-08 16:56:54 +00:00
if(!m_ReckoningTick || GameServer()->m_World.m_Paused)
{
// no dead reckoning when paused because the client doesn't know
// how far to perform the reckoning
2010-05-29 07:25:38 +00:00
Character->m_Tick = 0;
m_Core.Write(Character);
}
else
{
2010-05-29 07:25:38 +00:00
Character->m_Tick = m_ReckoningTick;
m_SendCore.Write(Character);
}
if(m_DoSplash)
{
Character->m_Jumped = 3;
}
2008-09-23 07:43:41 +00:00
// set emote
2010-05-29 07:25:38 +00:00
if (m_EmoteStop < Server()->Tick())
{
2010-05-29 07:25:38 +00:00
m_EmoteType = EMOTE_NORMAL;
m_EmoteStop = -1;
}
2010-05-29 07:25:38 +00:00
Character->m_Emote = m_EmoteType;
2010-05-29 07:25:38 +00:00
Character->m_AmmoCount = 0;
Character->m_Health = 0;
Character->m_Armor = 0;
if (m_FreezeTime > 0 || m_FreezeTime == -1)
{
Character->m_Emote = EMOTE_BLINK;
Character->m_Weapon = WEAPON_NINJA;
Character->m_AmmoCount = 0;
}
else
Character->m_Weapon = m_ActiveWeapon;
2010-05-29 07:25:38 +00:00
Character->m_AttackTick = m_AttackTick;
2010-05-29 07:25:38 +00:00
Character->m_Direction = m_Input.m_Direction;
2010-05-29 07:25:38 +00:00
if(m_pPlayer->GetCID() == SnappingClient)
{
2010-05-29 07:25:38 +00:00
Character->m_Health = m_Health;
Character->m_Armor = m_Armor;
if(m_aWeapons[m_ActiveWeapon].m_Ammo > 0)
Character->m_AmmoCount = (!m_FreezeTime)?m_aWeapons[m_ActiveWeapon].m_Ammo:0;
}
2010-05-29 07:25:38 +00:00
if (Character->m_Emote == EMOTE_NORMAL)
{
2010-05-29 07:25:38 +00:00
if(250 - ((Server()->Tick() - m_LastAction)%(250)) < 5)
Character->m_Emote = EMOTE_BLINK;
}
2010-05-29 07:25:38 +00:00
Character->m_PlayerState = m_PlayerState;
2010-09-11 09:31:36 +00:00
}