-
Notifications
You must be signed in to change notification settings - Fork 0
/
Level.asc
242 lines (219 loc) · 7.24 KB
/
Level.asc
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
static ObjectPosition *ObjectPosition::Create(int x, int y, ObjectDirection dir) {
ObjectPosition wp = new ObjectPosition;
wp.X = x;
wp.Y = y;
wp.Dir = dir;
return wp;
}
static LevelObject *LevelObject::Create(LevelObjectClass def, int x, int y, ObjectDirection dir) {
return LevelObject.Create2(def, ObjectPosition.Create(x, y, dir));
}
static LevelObject *LevelObject::Create2(LevelObjectClass def, ObjectPosition pos) {
LevelObject obj = new LevelObject;
obj.Def = def;
obj.Pos = pos;
obj.View = def.View;
obj.Loop = def.Loop;
obj.Over = Overlay.CreateRoomGraphical(0, 0, 0);
return obj;
}
static Point *Level::ObjectToMap(ObjectPosition *who, int x, int y) {
// TODO: find out if it's possible / easier to use simple 2D matrix transform
Point *mpt = new Point;
switch (who.Dir) {
case eDirNorth: mpt.x = x; mpt.y = -y; break;
case eDirEast: mpt.x = y; mpt.y = x; break;
case eDirSouth: mpt.x = -x; mpt.y = y; break;
case eDirWest: mpt.x = -y; mpt.y = -x; break;
default: System.Log(eLogDebug, "ObjectToMap: INVALID DIR"); break;
}
mpt.x += who.X;
mpt.y += who.Y;
return mpt;
}
static Point *Level::MapToObject(ObjectPosition *who, int x, int y) {
// TODO: find out if it's possible / easier to use simple 2D matrix transform
Point *rel_pt = new Point;
int dx = x - who.X;
int dy = y - who.Y;
switch (who.Dir) {
case eDirNorth: rel_pt.x = dx; rel_pt.y = -dy; break;
case eDirEast: rel_pt.x = dy; rel_pt.y = dx; break;
case eDirSouth: rel_pt.x = -dx; rel_pt.y = dy; break;
case eDirWest: rel_pt.x = -dy; rel_pt.y = -dx; break;
default: System.Log(eLogDebug, "MapToObject: INVALID DIR"); break;
}
return rel_pt;
}
static Point *Level::ObjectDeltaToMap(ObjectPosition *who, int x, int y) {
// TODO: find out if it's possible / easier to use simple 2D matrix transform
Point *mpt = new Point;
switch (who.Dir) {
case eDirNorth: mpt.x = x; mpt.y = -y; break;
case eDirEast: mpt.x = y; mpt.y = x; break;
case eDirSouth: mpt.x = -x; mpt.y = y; break;
case eDirWest: mpt.x = -y; mpt.y = -x; break;
}
return mpt;
}
// NOTE: yes, it happens to be identical to ObjectDeltaToMap...
static Point *Level::MapDeltaToObject(ObjectPosition *who, int x, int y) {
// TODO: find out if it's possible / easier to use simple 2D matrix transform
Point *rel_pt = new Point;
switch (who.Dir) {
case eDirNorth: rel_pt.x = x; rel_pt.y = -y; break;
case eDirEast: rel_pt.x = y; rel_pt.y = x; break;
case eDirSouth: rel_pt.x = -x; rel_pt.y = y; break;
case eDirWest: rel_pt.x = -y; rel_pt.y = -x; break;
}
return rel_pt;
}
static ObjectDirection Level::MapToObjectDir(ObjectPosition *who, ObjectDirection dir) {
// FIXME: better algo?
int delta_dir = dir - who.Dir;
int rel_dir = eDirNorth + delta_dir;
if (rel_dir < eDirNorth) {
rel_dir = eDirWest + rel_dir;
}
return rel_dir;
}
static Direction Level::DirToAGSLoop(ObjectDirection dir) {
switch (dir) {
case eDirNorth: return eDirectionUp;
case eDirEast: return eDirectionRight;
case eDirSouth: return eDirectionDown;
case eDirWest: return eDirectionLeft;
default: return eDirectionDown;
}
}
static MapTransform *Level::GetObjectToMapTransform(ObjectPosition* who) {
// TODO: find out if it's possible / easier to use simple 2D matrix transform
int row_dx = 0, row_dy = 0, col_dx = 0, col_dy = 0;
switch (who.Dir) {
case eDirNorth: row_dy = -1; col_dx = 1; break;
case eDirEast: row_dx = 1; col_dy = 1; break;
case eDirSouth: row_dy = 1; col_dx = -1; break;
case eDirWest: row_dx = -1; col_dy = -1; break;
}
MapTransform *t = new MapTransform;
t.originX = who.X;
t.originY = who.Y;
t.viewRowAxisX = row_dx;
t.viewRowAxisY = row_dy;
t.viewColAxisX = col_dx;
t.viewColAxisY = col_dy;
return t;
}
int UpdateTexturedTile(TextureType tex_type, int tex_id, int frame) {
TileDefinition tiledef = CLevel.TileDefs[tex_id];
TextureSequence txseq = tiledef.Seq[tex_type];
if (txseq == null || txseq.Type == eTxSeq_Fixed || txseq.Timer > 0) {
return frame;
}
if (txseq.Type == eTxSeq_Normal) {
frame++;
if (frame >= txseq.Color1.Length) {
frame = 0;
}
return frame;
} else {
return Random(txseq.Color1.Length - 1);
}
}
static void Level::AddObject(LevelObject *obj) {
int index = Array_TryAdd(CLevel.LevelObjects, obj);
if (index < 0) {
int old_len = Array_SafeLength(CLevel.LevelObjects);
LevelObject *new_arr[] = new LevelObject[old_len + 10];
Array_Copy(new_arr, CLevel.LevelObjects, old_len);
new_arr[old_len] = obj;
CLevel.LevelObjects = new_arr;
}
}
static LevelObject Level::AddObject2(LevelObjectClass *def, int x, int y, ObjectDirection dir) {
LevelObject obj = LevelObject.Create(def, x, y, dir);
ViewFrame *vf = Game.GetViewFrame(obj.View, obj.Loop, obj.Frame);
obj.Timer = vf.Speed;
CLevel.AddObject(obj);
return obj;
}
static void Level::RemoveObject(LevelObject *obj) {
Array_TryRemove(CLevel.LevelObjects, obj);
}
static void Level::RemoveObject2(int index) {
if (index >= 0 && index < CLevel.LevelObjects.Length) {
CLevel.LevelObjects[index] = null;
}
}
static void Level::Tick() {
// Update all animated cells
for (int i = 0; i < CLevel.CellTiles.Length; ++i) {
CellTile *ct = CLevel.CellTiles[i];
if (ct.Floor.DefID >= 0) {
ct.Floor.Frame = UpdateTexturedTile(eTxType_Floor, ct.Floor.DefID, ct.Floor.Frame);
}
if (ct.Ceil.DefID >= 0) {
ct.Ceil.Frame = UpdateTexturedTile(eTxType_Ceil, ct.Ceil.DefID, ct.Ceil.Frame);
}
}
// Update all texture animations
for (int i = 0; i < CLevel.TileDefs.Length; ++i) {
for (TextureType txtype = 0; txtype < eTxType_Base; ++txtype) {
TextureSequence txseq = CLevel.TileDefs[i].Seq[txtype];
if (txseq != null && txseq.Type != eTxSeq_Fixed) {
txseq.Timer--;
if (txseq.Timer < 0) {
txseq.Timer = txseq.FrameTime;
}
}
}
}
// Update all cell objects
// TODO: think how to pick out Animation struct and use in various structs,
// such as TextureSequence, CellObject, etc
if (CLevel.LevelObjectTypes.Length > 0) {
for (int i = 0; i < CLevel.LevelObjects.Length; ++i) {
LevelObject *obj = CLevel.LevelObjects[i];
if (obj == null) {
continue;
}
obj.Timer--;
if (obj.Timer < 0) {
obj.Frame++;
if (obj.Frame >= Game.GetFrameCountForLoop(obj.View, obj.Loop)) {
// If should animate only once, then stop here
if (obj.Def.AnimateOnceAndRemove) {
CLevel.RemoveObject2(i);
continue;
}
obj.Frame = 0;
}
ViewFrame *vf = Game.GetViewFrame(obj.View, obj.Loop, obj.Frame);
obj.Timer = vf.Speed;
}
}
}
}
static void Level::Trigger(ObjectPosition *who, int row_from, int col_from, CommandTrigger trigger) {
CellCommand *cc = CLevel.CellTriggers[who.Y * CLevel.MapWidth + who.X];
if (cc != null && cc.Trigger == trigger) {
Level.RunCommand(who, cc.Cmd.Type, cc.Cmd.Args[0], cc.Cmd.Args[1],
cc.Cmd.Args[2], cc.Cmd.Args[3], cc.Cmd.Args[4], cc.Cmd.SArg);
}
}
static void Level::RunCommand(ObjectPosition *who, GameCommand type,
int arg1, int arg2, int arg3, int arg4, int arg5, String sarg) {
switch (type) {
case eCmdGotoCell:
who.X = arg1; who.Y = arg2; who.Dir = arg3;
// TODO: implement behavior flags, telling whether to cast teleport fx, etc
if (CLevel.TeleportFx != null) {
CLevel.AddObject2(CLevel.TeleportFx, arg1, arg2, arg3);
}
return;
default:
return;
}
}
Level CLevel;
export CLevel;