Make hooks go through teleporters

This commit is contained in:
def 2013-07-19 00:27:17 +02:00
parent 717219e1c2
commit 54b942fa7e
5 changed files with 156 additions and 11 deletions

View file

@ -1,5 +1,6 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <iostream>
#include <base/system.h>
#include <base/math.h>
#include <base/vmath.h>
@ -192,7 +193,8 @@ int CCollision::IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *p
vec2 Pos = mix(Pos0, Pos1, a);
ix = round(Pos.x);
iy = round(Pos.y);
if(CheckPoint(ix, iy) && !(AllowThrough && IsThrough(ix + dx, iy + dy)))
if((CheckPoint(ix, iy) && !(AllowThrough && IsThrough(ix + dx, iy + dy))))
{
if(pOutCollision)
*pOutCollision = Pos;
@ -200,6 +202,55 @@ int CCollision::IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *p
*pOutBeforeCollision = Last;
return GetCollisionAt(ix, iy);
}
Last = Pos;
}
if(pOutCollision)
*pOutCollision = Pos1;
if(pOutBeforeCollision)
*pOutBeforeCollision = Pos1;
return 0;
}
int CCollision::IntersectLineTele(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, int *pTeleNr, bool AllowThrough)
{
float Distance = distance(Pos0, Pos1);
int End(Distance+1);
vec2 Last = Pos0;
int ix = 0, iy = 0; // Temporary position for checking collision
int dx = 0, dy = 0; // Offset for checking the "through" tile
if (AllowThrough)
{
ThroughOffset(Pos0, Pos1, &dx, &dy);
}
for(int i = 0; i < End; i++)
{
float a = i/Distance;
vec2 Pos = mix(Pos0, Pos1, a);
ix = round(Pos.x);
iy = round(Pos.y);
int Nx = clamp(ix/32, 0, m_Width-1);
int Ny = clamp(iy/32, 0, m_Height-1);
*pTeleNr = IsTeleport(Ny*m_Width+Nx);
if(*pTeleNr)
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
return COLFLAG_TELE;
}
if((CheckPoint(ix, iy) && !(AllowThrough && IsThrough(ix + dx, iy + dy))))
{
if(pOutCollision)
*pOutCollision = Pos;
if(pOutBeforeCollision)
*pOutBeforeCollision = Last;
return GetCollisionAt(ix, iy);
}
Last = Pos;
}
if(pOutCollision)
@ -711,6 +762,51 @@ int CCollision::GetIndex(int Nx, int Ny)
return m_pTiles[Ny*m_Width+Nx].m_Index;
}
int CCollision::GetIndex(vec2 Pos)
{
int nx = clamp((int)Pos.x/32, 0, m_Width-1);
int ny = clamp((int)Pos.y/32, 0, m_Height-1);
return ny*m_Width+nx;
}
int CCollision::GetIndex(vec2 PrevPos, vec2 Pos)
{
float Distance = distance(PrevPos, Pos);
if(!Distance)
{
int Nx = clamp((int)Pos.x/32, 0, m_Width-1);
int Ny = clamp((int)Pos.y/32, 0, m_Height-1);
if ((m_pTele) ||
(m_pSpeedup && m_pSpeedup[Ny*m_Width+Nx].m_Force > 0))
{
return Ny*m_Width+Nx;
}
}
float a = 0.0f;
vec2 Tmp = vec2(0, 0);
int Nx = 0;
int Ny = 0;
for(float f = 0; f < Distance; f++)
{
a = f/Distance;
Tmp = mix(PrevPos, Pos, a);
Nx = clamp((int)Tmp.x/32, 0, m_Width-1);
Ny = clamp((int)Tmp.y/32, 0, m_Height-1);
if ((m_pTele) ||
(m_pSpeedup && m_pSpeedup[Ny*m_Width+Nx].m_Force > 0))
{
return Ny*m_Width+Nx;
}
}
return -1;
}
int CCollision::GetFIndex(int Nx, int Ny)
{
if(!m_pFront) return 0;

View file

@ -25,7 +25,8 @@ public:
COLFLAG_NOHOOK=4,
// DDRace
COLFLAG_NOLASER=8,
COLFLAG_THROUGH=16
COLFLAG_THROUGH=16,
COLFLAG_TELE=32
};
CCollision();
@ -36,6 +37,7 @@ public:
int GetWidth() { return m_Width; };
int GetHeight() { return m_Height; };
int IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, bool AllowThrough);
int IntersectLineTele(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, int *pTeleNr, bool AllowThrough);
void MovePoint(vec2 *pInoutPos, vec2 *pInoutVel, float Elasticity, int *pBounces);
void MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity);
bool TestBox(vec2 Pos, vec2 Size);
@ -54,6 +56,8 @@ public:
int IntersectNoLaserNW(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision);
int IntersectAir(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision);
int GetIndex(int x, int y);
int GetIndex(vec2 Pos);
int GetIndex(vec2 PrevPos, vec2 Pos);
int GetFIndex(int x, int y);
int GetTile(int x, int y);

View file

@ -3,7 +3,7 @@
#include "gamecore.h"
#include <engine/shared/config.h>
#include <engine/server/server.h>
const char *CTuningParams::m_apNames[] =
{
#define MACRO_TUNING_PARAM(Name,ScriptName,Value) #ScriptName,
@ -57,10 +57,11 @@ float VelocityRamp(float Value, float Start, float Range, float Curvature)
return 1.0f/powf(Curvature, (Value-Start)/Range);
}
void CCharacterCore::Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore* pTeams)
void CCharacterCore::Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore* pTeams, std::map<int, std::vector<vec2> > pTeleOuts)
{
m_pWorld = pWorld;
m_pCollision = pCollision;
m_pTeleOuts = pTeleOuts;
m_pTeams = pTeams;
m_Id = -1;
@ -70,6 +71,7 @@ void CCharacterCore::Reset()
{
m_Pos = vec2(0,0);
m_Vel = vec2(0,0);
m_NewHook = false;
m_HookPos = vec2(0,0);
m_HookDir = vec2(0,0);
m_HookTick = 0;
@ -229,7 +231,8 @@ void CCharacterCore::Tick(bool UseInput)
else if(m_HookState == HOOK_FLYING)
{
vec2 NewPos = m_HookPos+m_HookDir*m_pWorld->m_Tuning.m_HookFireSpeed;
if(distance(m_Pos, NewPos) > m_pWorld->m_Tuning.m_HookLength)
if((!m_NewHook && distance(m_Pos, NewPos) > m_pWorld->m_Tuning.m_HookLength)
|| (m_NewHook && distance(m_HookTeleBase, NewPos) > m_pWorld->m_Tuning.m_HookLength))
{
m_HookState = HOOK_RETRACT_START;
NewPos = m_Pos + normalize(NewPos-m_Pos) * m_pWorld->m_Tuning.m_HookLength;
@ -239,11 +242,24 @@ void CCharacterCore::Tick(bool UseInput)
// make sure that the hook doesn't go though the ground
bool GoingToHitGround = false;
bool GoingToRetract = false;
int Hit = m_pCollision->IntersectLine(m_HookPos, NewPos, &NewPos, 0, true);
bool GoingThroughTele = false;
int teleNr = 0;
int Hit;
if (m_NewHook)
Hit = m_pCollision->IntersectLine(m_HookPos, NewPos, &NewPos, 0, true);
else
Hit = m_pCollision->IntersectLineTele(m_HookPos, NewPos, &NewPos, 0, &teleNr, true);
//m_NewHook = false;
if(Hit)
{
if(Hit&CCollision::COLFLAG_NOHOOK)
GoingToRetract = true;
else if (Hit&CCollision::COLFLAG_TELE)
{
GoingThroughTele = true;
}
else
GoingToHitGround = true;
m_pReset = true;
@ -260,7 +276,7 @@ void CCharacterCore::Tick(bool UseInput)
continue;
vec2 ClosestPoint = closest_point_on_line(m_HookPos, NewPos, pCharCore->m_Pos);
if(distance(pCharCore->m_Pos, ClosestPoint) < PhysSize+2.0f)
if(m_HookState != HOOK_RETRACT_START && distance(pCharCore->m_Pos, ClosestPoint) < PhysSize+2.0f)
{
if (m_HookedPlayer == -1 || distance(m_HookPos, pCharCore->m_Pos) < Distance)
{
@ -287,7 +303,21 @@ void CCharacterCore::Tick(bool UseInput)
m_HookState = HOOK_RETRACT_START;
}
m_HookPos = NewPos;
if(GoingThroughTele)
{
m_TriggeredEvents = 0;
m_HookedPlayer = -1;
m_NewHook = true;
int Num = m_pTeleOuts[teleNr-1].size();
m_HookPos = m_pTeleOuts[teleNr-1][(!Num)?Num:rand() % Num]+TargetDirection*PhysSize*1.5f;
m_HookDir = TargetDirection;
m_HookTeleBase = m_HookPos;
}
else
{
m_HookPos = NewPos;
}
}
}
@ -413,6 +443,11 @@ void CCharacterCore::Tick(bool UseInput)
}
}
}
if (m_HookState != HOOK_FLYING)
{
m_NewHook = false;
}
}
// clamp the velocity to something sane

View file

@ -6,6 +6,9 @@
#include <base/system.h>
#include <base/math.h>
#include <map>
#include <vector>
#include <math.h>
#include "collision.h"
#include <engine/shared/protocol.h>
@ -161,6 +164,7 @@ enum
COREEVENT_HOOK_ATTACH_GROUND=0x10,
COREEVENT_HOOK_HIT_NOHOOK=0x20,
COREEVENT_HOOK_RETRACT=0x40,
//COREEVENT_HOOK_TELE=0x80,
};
class CWorldCore
@ -179,16 +183,22 @@ class CCharacterCore
{
CWorldCore *m_pWorld;
CCollision *m_pCollision;
std::map<int, std::vector<vec2> > m_pTeleOuts;
public:
vec2 m_Pos;
vec2 m_Vel;
vec2 m_HookPos;
vec2 m_HookDir;
vec2 m_HookTeleBase;
int m_HookTick;
int m_HookState;
int m_HookedPlayer;
bool m_NewHook;
vec2 m_NewHookPos;
vec2 m_NewHookDir;
int m_Jumped;
int m_Direction;
@ -197,7 +207,7 @@ public:
int m_TriggeredEvents;
void Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore* pTeams);
void Init(CWorldCore *pWorld, CCollision *pCollision, CTeamsCore* pTeams, std::map<int, std::vector<vec2> > pTeleOuts);
void Reset();
void Tick(bool UseInput);
void Move();

View file

@ -71,7 +71,7 @@ bool CCharacter::Spawn(CPlayer *pPlayer, vec2 Pos)
m_Pos = Pos;
m_Core.Reset();
m_Core.Init(&GameServer()->m_World.m_Core, GameServer()->Collision(), &((CGameControllerDDRace*)GameServer()->m_pController)->m_Teams.m_Core);
m_Core.Init(&GameServer()->m_World.m_Core, GameServer()->Collision(), &((CGameControllerDDRace*)GameServer()->m_pController)->m_Teams.m_Core, ((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts);
m_Core.m_Pos = m_Pos;
GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = &m_Core;
@ -651,7 +651,7 @@ void CCharacter::TickDefered()
// advance the dummy
{
CWorldCore TempWorld;
m_ReckoningCore.Init(&TempWorld, GameServer()->Collision(), &((CGameControllerDDRace*)GameServer()->m_pController)->m_Teams.m_Core);
m_ReckoningCore.Init(&TempWorld, GameServer()->Collision(), &((CGameControllerDDRace*)GameServer()->m_pController)->m_Teams.m_Core, ((CGameControllerDDRace*)GameServer()->m_pController)->m_TeleOuts);
m_ReckoningCore.m_Id = m_pPlayer->GetCID();
m_ReckoningCore.Tick(false);
m_ReckoningCore.Move();