-
Notifications
You must be signed in to change notification settings - Fork 0
/
Level.ash
326 lines (300 loc) · 11.5 KB
/
Level.ash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
///////////////////////////////////////////////////////////////////////////////
//
// The Level module.
//
// This module defines a game Level, that is a 2D map of cells, where player
// and NPCs may walk around and engage in a number of activities.
//
// Besides storing a level cell data, the module provides a number of methods
// for converting between map and local object coordinate systems.
//
// The absolute map coordinate system corresponds to the level's grid of cells.
// The map is a 2D grid which goes (0, 0) -> ((Width-1), (Height-1)).
// The direction on this map is fixed:
// - North -> towards -Y (or Y = 0)
// - East -> towards +X (or X = Width)
// - South -> towards +Y (or Y = Height)
// - West -> towards -X (or X = 0)
//
// The local coordinate system corresponds to the particular object's
// perspective. In this local system the owner object is always a center of
// coordinates (0, 0), Y axis points "forward" from this object, and X axis
// points to the "right" from this object. Hence the direction in this system
// is defined like:
// - Forward -> towards +Y
// - Right -> towards +X
// - Backward -> towards -Y
// - Left -> towards -X
//
// The local coordinate systems are used to find out relative positions of
// objects and cells when building first person's view, or working with
// NPCs AI, for instance.
//
//-----------------------------------------------------------------------------
//
// Example:
//
// The map is (0, 0) -> (9, 9), and a object A is positioned at map coordinates
// (4, 4) facing East (+X). There's another object B at map coordinates (5, 6)
// facing North (-Y), and object C at map coordinates (1, 2) facing West (-Y):
//
// |N|
// - 0 1 2 3 4 5 6 +X
// 0
// 1
// 2 <C
// 3
// 4 A>
// 5
// 6 B^
// +Y
//
// If we look from the object A's perspective, object B would be positioned at
// the local coordinates (+2, +1), that is - 1 step forward and 2 steps to the
// right, facing Left, while object C would be positioned at the local coords
// (-2, -3), that is - 2 steps left and 3 steps back, facing backwards.
//
// |F|
// +4
// +3
// +2
// +1 <B
// -4 -3 -2 -1 A^ +1 +2 +3 +4
// -1
// -2
// -3 vC
// -4
//
///////////////////////////////////////////////////////////////////////////////
// ObjectDirection depicts either an absolute direction of look or move
// on a 2D map, or a relative direction in object's local coordinate space.
// Assuming a 2D grid which goes from 0, 0 -> Width, Height, the absolute
// ObjectDirection points as:
// - North -> towards -Y (or Y = 0)
// - East -> towards +X (or X = Width)
// - South -> towards +Y (or Y = Height)
// - West -> towards -X (or X = 0)
// Relative ObjectDirection points as:
// - Forward -> towards +Y
// - Right -> towards +X
// - Backward -> towards -Y
// - Left -> towards -X
// FIXME: make 0-based, need to adjust few algorithms
enum ObjectDirection {
eDirNorth = 1,
eDirEast = 2,
eDirSouth = 3,
eDirWest = 4,
eDirForward = 1, // matches North
eDirRight = 2, // matches East
eDirBackward = 3, // matches South
eDirLeft = 4, // matches West
};
// Position and direction of an object, in either absolute or
// local (relative) coordinate space.
managed struct ObjectPosition {
int X, Y;
ObjectDirection Dir;
import static ObjectPosition *Create(int x, int y, ObjectDirection dir);
};
// MapTransform helps to calculate absolute map position of something
// located relatively to the object. Contains position (aka "origin" and
// directional axes of an object in the map's coordinate space.
//
// Axes point into direction in which object's POV rows or columns increase
// their index, respectively. Remember that rows go from "back" to "forth",
// and columns go from "left" to "right" in the object's local space.
// For example, if viewRowAxisY = 1 this means that view row increases along
// the map's Y coordinate (object "faces" into positive Y direction).
// If viewRowAxisX = -1 this means that view row increases opposite to map's X
// axis (object "faces" into negative X direction).
//
// These axes could be used to calculate actual map position of a cell relative
// to this object; for example, if you want to find out map coordinates of cell
// located one step forward, one step left from the object.
// Assuming origin is object's absolute pos on map, relative cell position is
// stored in variables cellCol and cellRow, then the conversion formula is:
//
// mapX = origin.X + cellRow * viewRowAxis.X + cellCol * viewColAxis.X;
// mapY = origin.Y + cellRow * viewRowAxis.Y + cellCol * viewColAxis.Y;
//
managed struct MapTransform
{
// Origin is object's absolute pos on map
int originX, originY;
// Tells which map direction the object's POV rows increase towards to.
int viewRowAxisX, viewRowAxisY;
// Tells which map direction the object's POV columns increase towards to.
int viewColAxisX, viewColAxisY;
};
// FIXME: this is ugly, figure out how to share this with CellView... :/
// TODO: separate constants for left and right side walls,
// may be necessary if we support "fences" between passable cells
enum TextureType {
eTxType_Floor = 0,
eTxType_Ceil,
eTxType_Front,
eTxType_Side, // side wall (left or right, depending on cell pos)
eTxType_Base, // whole cell object (an image taking whole cell in view)
eTxTypeNum
};
// Helper enum for combining texture types as bit flags;
// for instance, if you need to tell which types are supported for a tile.
// NOTE: it's possible to convert from TextureType using bitwise shift like:
// flag = (1 << type)
enum TextureTypeFlag {
eTxTypeFlag_Floor = 0x01,
eTxTypeFlag_Ceil = 0x02,
eTxTypeFlag_Front = 0x04,
eTxTypeFlag_Side = 0x08,
eTxTypeFlag_Base = 0x10,
eTxTypeFlag_WallMask = (eTxTypeFlag_Front | eTxTypeFlag_Side),
eTxTypeFlag_WallOrBaseMask = (eTxTypeFlag_WallMask | eTxTypeFlag_Base),
eTxTypeFlag_FlatMask = (eTxTypeFlag_Floor | eTxTypeFlag_Ceil)
};
enum TextureSequenceType {
eTxSeq_Fixed, // stay, can be changed by command
eTxSeq_Normal, // change one by one in time
eTxSeq_Random // change at random in time
};
managed struct TextureSequence {
// TODO: sprites
TextureSequenceType Type;
int Color1[];
int Color2[];
int FrameTime;
int Timer;
};
// A description of the Tile's Type.
// Contains all possible things: colors for generating colored "textures",
// sprites, views, animated sequences, and so on.
// Priority, when drawing a cell:
// - sequence
// - sprite
// - if nothing else, then use colors, if applicable
managed struct TileDefinition {
TextureTypeFlag HasTextures;
// TODO: sprites (views?)
// Simple colors
int Color1[eTxTypeNum];
int Color2[eTxTypeNum];
// Sprites
int Sprite[eTxTypeNum];
// Sequences
TextureSequence Seq[eTxTypeNum];
// FIXME: make behavior flags
bool Directional; // use different loops for 4 facing directions
bool Perspective; // has variants depending on position in player's View
bool Scaled; // auto-scaled in the player's View
int OriginY;
};
// Dynamic tile data
struct TileData {
int DefID; // id of a tile definition
int Frame; // current frame of a sequence (if applicable)
ObjectDirection Dir; // current tile direction (if applicable)
};
managed struct CellTile {
TileData Floor;
TileData Ceil;
TileData Base; // big tile for the whole cell
};
enum CommandTrigger {
eCmdTrigger_Enter, // enter cell or pass wall
};
// Command describes a game command with arguments.
// This is a way to schedule a sequence of actions, triggered upon
// certain event.
struct Command {
GameCommand Type;
int Args[5];
String SArg;
};
managed struct CellCommand {
CommandTrigger Trigger; // trigger type
Command Cmd;
};
// Description of the LevelObject type,
// defines its constant or default properties and behavior.
managed struct LevelObjectClass {
String Name;
int View, Loop; // View and Loop, for a simple continuous animation
// FIXME: make behavior flags
bool Directional; // use different loops for 4 facing directions
bool AnimateOnceAndRemove;
};
// LevelObject describes a dynamic state of a level object
managed struct LevelObject extends ArrayElement {
LevelObjectClass Def;
ObjectPosition Pos;
Overlay *Over; // graphical representation
int View, Loop, Frame; // current animation params
int Timer; // animation timer
import static LevelObject *Create(LevelObjectClass def, int x, int y, ObjectDirection dir);
import static LevelObject *Create2(LevelObjectClass def, ObjectPosition pos);
};
//
// Level struct contains the map data, and provides methods for working with
// the map's and objects' coordinate spaces.
//
struct Level
{
//--------------------------------------------------------
// Resource data
// TODO: should store actual tilemaps for textures.
//--------------------------------------------------------
// Tile definitions, used by the CellTiles
TileDefinition TileDefs[];
// Cell object types description, to be used in this level
// TODO: actually, may move this to some kind of a "game manager"
LevelObjectClass LevelObjectTypes[];
LevelObjectClass TeleportFx; // teleport fx type
//--------------------------------------------------------
// Map data
// FIXME: make most of this writeprotected?
//--------------------------------------------------------
// Map size in cells
int MapWidth;
int MapHeight;
// Map layers, expandable
// each layer must be (MapWidth * MapHeight) size
//
// 8-bit passability mask;
// 0 = unrestricted,
// 1+ = passable only if player has the same bits set
char CellPassable[];
// Cell tiles data
CellTile CellTiles[];
// Command triggered by each cell
CellCommand CellTriggers[];
// Separate level objects, not directly bound to the number of tiles
LevelObject LevelObjects[];
// Converts a position relative to the given object into the absolute map coordinates.
import static Point *ObjectToMap(ObjectPosition *who, int x, int y);
// Converts an absolute map position to a position relative to the given object.
import static Point *MapToObject(ObjectPosition *who, int x, int y);
// Converts a relative offset from object's to map coordinates
import static Point *ObjectDeltaToMap(ObjectPosition *who, int x, int y);
// Converts a relative offset from map to object's coordinates
import static Point *MapDeltaToObject(ObjectPosition *who, int x, int y);
// Converts an absolute direction into the object's relative dir;
// in other words - where the dir is facing when looking from the "who" perspective.
// Here "forward" is North, "left" is West, "right" is East, "back" is South.
import static ObjectDirection MapToObjectDir(ObjectPosition *who, ObjectDirection dir);
// Converts ObjectDirection into the AGS Direction, which also corresponds
// to the directional loop index.
import static Direction DirToAGSLoop(ObjectDirection dir);
// Returns position and directional axes of an object translated to map coordinate space.
// See comment to MapTransform struct for more information.
import static MapTransform *GetObjectToMapTransform(ObjectPosition* who);
import static void AddObject(LevelObject *obj);
import static LevelObject AddObject2(LevelObjectClass *def, int x, int y, ObjectDirection dir);
import static void RemoveObject(LevelObject *obj);
import static void RemoveObject2(int index);
import static void Tick();
import static void Trigger(ObjectPosition *who, int from_x, int from_y, CommandTrigger trigger);
import static void RunCommand(ObjectPosition *who, GameCommand type,
int arg1, int arg2, int arg3, int arg4, int arg5, String sarg);
};
// Current level
import Level CLevel;