Skip to content

Commit d14f116

Browse files
committed
Implement doors
1 parent 084391f commit d14f116

File tree

11 files changed

+311
-3
lines changed

11 files changed

+311
-3
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,8 @@ set_glob(GAME_SERVER GLOB_RECURSE src/game/server
903903
infclass/entities/hero-flag.h
904904
infclass/entities/ic-pickup.cpp
905905
infclass/entities/ic-pickup.h
906+
infclass/entities/ic_door.cpp
907+
infclass/entities/ic_door.h
906908
infclass/entities/infc-laser.cpp
907909
infclass/entities/infc-laser.h
908910
infclass/entities/infc-placed-object.cpp

src/game/collision.cpp

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ void CCollision::Init(class CLayers *pLayers)
6363
m_Height = m_pLayers->GameLayer()->m_Height;
6464
m_pTiles = static_cast<CTile *>(m_pLayers->Map()->GetData(m_pLayers->GameLayer()->m_Data));
6565

66+
InitPhysicalLayer();
67+
InitDoorsLayer();
6668
InitTeleports();
6769

6870
if(m_pLayers->SpeedupLayer())
@@ -73,6 +75,41 @@ void CCollision::Init(class CLayers *pLayers)
7375
}
7476
}
7577

78+
constexpr EZonePhysics GetPhysicalTileByTile(int Tile)
79+
{
80+
switch(Tile)
81+
{
82+
case TILE_SOLID:
83+
return EZonePhysics::Solid;
84+
case TILE_NOHOOK:
85+
return EZonePhysics::NoHook;
86+
default:
87+
break;
88+
}
89+
90+
return EZonePhysics::Null;
91+
}
92+
93+
void CCollision::InitPhysicalLayer()
94+
{
95+
mv_Physics.resize(m_Width * m_Height);
96+
for(int Y = 0; Y < m_Height; ++Y)
97+
{
98+
for(int X = 0; X < m_Width; ++X)
99+
{
100+
int Index = Y * m_Width + X;
101+
int Tile = m_pTiles[Index].m_Index;
102+
mv_Physics[Index] = GetPhysicalTileByTile(Tile);
103+
}
104+
}
105+
}
106+
107+
void CCollision::InitDoorsLayer()
108+
{
109+
mv_Doors.clear();
110+
mv_Doors.resize(m_Width * m_Height);
111+
}
112+
76113
void CCollision::InitTeleports()
77114
{
78115
if(!m_pLayers->TeleLayer())
@@ -218,6 +255,76 @@ int CCollision::GetMoveRestrictions(CALLBACK_SWITCHACTIVE pfnSwitchActive, void
218255
return Restrictions;
219256
}
220257

258+
void CCollision::SetDoorCollisionAt(int Index, bool HasDoor)
259+
{
260+
if (HasDoor)
261+
{
262+
mv_Doors[Index]++;
263+
}
264+
else
265+
{
266+
mv_Doors[Index]--;
267+
}
268+
}
269+
270+
void CCollision::SetDoorCollisionAt(vec2 Pos, bool HasDoor)
271+
{
272+
SetDoorCollisionAt(GetPureMapIndex(Pos), HasDoor);
273+
}
274+
275+
int CCollision::GetDoorCollisionAt(vec2 Pos) const
276+
{
277+
int Nx = clamp(static_cast<int>(Pos.x) / 32, 0, m_Width - 1);
278+
int Ny = clamp(static_cast<int>(Pos.y) / 32, 0, m_Height - 1);
279+
int Index = Ny * m_Width + Nx;
280+
281+
return mv_Doors.at(Index);
282+
}
283+
284+
int CCollision::IntersectLineWithDoors(vec2 From, vec2 To, vec2 *pOutCollision, vec2 *pOutBeforeCollision) const
285+
{
286+
vec2 Pos1Pos0 = To - From;
287+
float Distance = length(Pos1Pos0);
288+
int End(Distance + 1);
289+
vec2 Last = From;
290+
291+
for(int i = 0; i < End; i++)
292+
{
293+
float a = i / Distance;
294+
vec2 Pos = From + Pos1Pos0 * a;
295+
if(GetDoorCollisionAt(Pos))
296+
{
297+
if(pOutCollision)
298+
*pOutCollision = Pos;
299+
if(pOutBeforeCollision)
300+
*pOutBeforeCollision = Last;
301+
return GetDoorCollisionAt(Pos);
302+
}
303+
Last = Pos;
304+
}
305+
if(pOutCollision)
306+
*pOutCollision = To;
307+
if(pOutBeforeCollision)
308+
*pOutBeforeCollision = To;
309+
return 0;
310+
}
311+
312+
EZonePhysics CCollision::GetPhysicsTile(int x, int y) const
313+
{
314+
int Nx = clamp(x / 32, 0, m_Width - 1);
315+
int Ny = clamp(y / 32, 0, m_Height - 1);
316+
int Index = Ny * m_Width + Nx;
317+
318+
EZonePhysics Value = mv_Physics.at(Index);
319+
if (Value == EZonePhysics::Null)
320+
{
321+
if(mv_Doors.at(Index))
322+
return EZonePhysics::NoHook;
323+
}
324+
325+
return Value;
326+
}
327+
221328
int CCollision::GetTile(int x, int y) const
222329
{
223330
if(!m_pTiles)
@@ -230,6 +337,10 @@ int CCollision::GetTile(int x, int y) const
230337
int Index = m_pTiles[pos].m_Index;
231338
if(Index >= TILE_SOLID && Index <= TILE_NOLASER)
232339
return Index;
340+
341+
if(mv_Doors.at(pos))
342+
return TILE_NOHOOK;
343+
233344
return 0;
234345
}
235346

@@ -434,8 +545,7 @@ void CCollision::Dest()
434545

435546
bool CCollision::IsSolid(int x, int y) const
436547
{
437-
int index = GetTile(x, y);
438-
return index == TILE_SOLID || index == TILE_NOHOOK;
548+
return GetPhysicsTile(x, y) != EZonePhysics::Null;
439549
}
440550

441551
int CCollision::IsSpeedup(int Index) const

src/game/collision.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ enum
1717
CANTMOVE_DOWN = 1 << 3,
1818
};
1919

20+
enum class EZonePhysics : int8_t;
21+
2022
vec2 ClampVel(int MoveRestriction, vec2 Vel);
2123

2224
typedef bool (*CALLBACK_SWITCHACTIVE)(int Number, void *pUser);
@@ -29,6 +31,8 @@ struct ZoneData
2931

3032
class CCollision
3133
{
34+
std::vector<EZonePhysics> mv_Physics;
35+
std::vector<int8_t> mv_Doors;
3236
class CTile *m_pTiles;
3337
int m_Width;
3438
int m_Height;
@@ -39,7 +43,6 @@ class CCollision
3943
array< array<int> > m_Zones;
4044

4145
bool IsSolid(int x, int y) const;
42-
int GetTile(int x, int y) const;
4346

4447
public:
4548
enum
@@ -52,6 +55,8 @@ class CCollision
5255
CCollision();
5356
~CCollision();
5457
void Init(class CLayers *pLayers);
58+
void InitPhysicalLayer();
59+
void InitDoorsLayer();
5560
void InitTeleports();
5661

5762
bool CheckPoint(float x, float y) const { return IsSolid(round_to_int(x), round(y)); }
@@ -74,6 +79,15 @@ class CCollision
7479
return GetMoveRestrictions(0, 0, Pos, Distance);
7580
}
7681

82+
EZonePhysics GetPhysicsTile(int x, int y) const;
83+
int GetTile(int x, int y) const;
84+
int GetFTile(int x, int y) const;
85+
86+
void SetDoorCollisionAt(int Index, bool HasDoor);
87+
void SetDoorCollisionAt(vec2 Pos, bool HasDoor);
88+
int GetDoorCollisionAt(vec2 Pos) const;
89+
int IntersectLineWithDoors(vec2 From, vec2 To, vec2 *pOutCollision = nullptr, vec2 *pOutBeforeCollision = nullptr) const;
90+
7791
void SetTime(double Time) { m_Time = Time; }
7892

7993
//This function return an Handle to access all zone layers with the name "pName"

src/game/mapitems.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#ifndef GAME_MAPITEMS_H
44
#define GAME_MAPITEMS_H
55

6+
#include <cstdint>
7+
68
// layer types
79
enum
810
{
@@ -221,6 +223,13 @@ enum
221223
ZONE_BONUS_BONUS=1,
222224
};
223225

226+
enum class EZonePhysics : int8_t
227+
{
228+
Null,
229+
Solid = TILE_SOLID,
230+
NoHook = TILE_NOHOOK,
231+
};
232+
224233
enum class EZoneTele
225234
{
226235
Null,

src/game/server/gameworld.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class CGameWorld
4242
ENTTYPE_LASER_TELEPORT,
4343
ENTTYPE_TURRET,
4444
ENTTYPE_PLASMA,
45+
46+
ENTTYPE_DOOR,
4547

4648
NUM_ENTTYPES
4749
};
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#include "ic_door.h"
2+
3+
#include <engine/shared/config.h>
4+
#include <game/server/gamecontext.h>
5+
6+
CDoor::CDoor(CGameContext *pGameContext, vec2 Pos, vec2 PosTo) :
7+
CPlacedObject(pGameContext, CGameWorld::ENTTYPE_DOOR),
8+
m_Open{true}
9+
{
10+
m_Pos = Pos;
11+
m_Pos2 = PosTo;
12+
13+
m_InfClassObjectFlags = INFCLASS_OBJECT_FLAG_HAS_SECOND_POSITION;
14+
15+
SetOpen(false);
16+
GameWorld()->InsertEntity(this);
17+
}
18+
19+
void CDoor::Destroy()
20+
{
21+
SetOpen(true);
22+
23+
CPlacedObject::Destroy();
24+
}
25+
26+
void CDoor::SetCollisions(bool Set)
27+
{
28+
const vec2 DoorVector = m_Pos2 - m_Pos;
29+
const float Distance = length(DoorVector);
30+
31+
int PrevIndex = -1;
32+
auto SetOncePerTile = [&](vec2 Pos)
33+
{
34+
int Index = GameServer()->Collision()->GetPureMapIndex(Pos);
35+
if (Index == PrevIndex)
36+
return;
37+
38+
PrevIndex = Index;
39+
GameServer()->Collision()->SetDoorCollisionAt(Index, Set);
40+
};
41+
42+
SetOncePerTile(m_Pos);
43+
if(Distance > TileSizeF)
44+
{
45+
float Step = TileSize / 2;
46+
vec2 NormalizedDoor = DoorVector / Distance;
47+
float ProcessedDistance = Step;
48+
while(ProcessedDistance < Distance)
49+
{
50+
SetOncePerTile(m_Pos + NormalizedDoor * ProcessedDistance);
51+
ProcessedDistance += Step;
52+
}
53+
}
54+
SetOncePerTile(m_Pos2);
55+
}
56+
57+
void CDoor::Reset()
58+
{
59+
MarkForDestroy();
60+
}
61+
62+
void CDoor::Snap(int SnappingClientId)
63+
{
64+
const std::optional<CViewParams> ViewParams = GetViewParams(GameServer(), SnappingClientId);
65+
66+
int SnappingClientVersion = GameServer()->GetClientVersion(SnappingClientId);
67+
68+
vec2 To = m_Pos;
69+
vec2 From = IsOpen() ? m_Pos : m_Pos2;
70+
int StartTick = 0;
71+
72+
if(SnappingClientVersion < VERSION_DDNET_ENTITY_NETOBJS)
73+
{
74+
StartTick = Server()->Tick();
75+
}
76+
77+
const bool ForcedShowOpen = Config()->m_SvShowOpenDoors && IsOpen();
78+
if(ForcedShowOpen)
79+
{
80+
From = m_Pos2;
81+
}
82+
int MaxY = Collision()->GetHeight() * TileSize;
83+
if((From != To) && ViewParams.has_value())
84+
{
85+
if(m_Pos.x == m_Pos2.x)
86+
{
87+
const bool AutoextendTop = ((m_Pos.y < 32) || (m_Pos2.y < 32));
88+
const bool AutoextendBottom = ((m_Pos.y >= MaxY) || (m_Pos2.y >= MaxY));
89+
90+
if(AutoextendTop)
91+
{
92+
const auto TopY = ViewParams->ViewPos.y - ViewParams->ShowDistance.y - 1000;
93+
if(To.y < 32)
94+
{
95+
To.y = TopY;
96+
}
97+
else
98+
{
99+
From.y = TopY;
100+
}
101+
}
102+
if(AutoextendBottom)
103+
{
104+
const auto BottomY = ViewParams->ViewPos.y + ViewParams->ShowDistance.y + 1000;
105+
if(To.y >= MaxY)
106+
{
107+
To.y = BottomY;
108+
}
109+
else
110+
{
111+
From.y = BottomY;
112+
}
113+
}
114+
}
115+
}
116+
117+
GameServer()->SnapLaserObject(CSnapContext(SnappingClientVersion), GetId(), To, From, StartTick, -1, ForcedShowOpen ? LASERTYPE_FREEZE : LASERTYPE_DOOR);
118+
// TODO: CGameContext::SnapSwitchers()
119+
}
120+
121+
void CDoor::SetOpen(bool Open)
122+
{
123+
if (m_Open == Open)
124+
return;
125+
126+
m_Open = Open;
127+
SetCollisions(!Open);
128+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */
2+
#ifndef GAME_SERVER_ENTITIES_DOOR_H
3+
#define GAME_SERVER_ENTITIES_DOOR_H
4+
5+
#include <game/server/infclass/entities/infc-placed-object.h>
6+
7+
class CGameWorld;
8+
9+
class CDoor : public CPlacedObject
10+
{
11+
public:
12+
CDoor(CGameContext *pGameContext, vec2 Pos, vec2 PosTo);
13+
14+
void Destroy() override;
15+
16+
void Reset() override;
17+
void Snap(int SnappingClientId) override;
18+
19+
bool IsOpen() const { return m_Open; }
20+
void SetOpen(bool Open);
21+
22+
protected:
23+
void SetCollisions(bool Set);
24+
bool m_Open = false;
25+
};
26+
27+
#endif // GAME_SERVER_ENTITIES_DOOR_H

0 commit comments

Comments
 (0)