switched to GPLv3 ONLY, because i don't trust FSF anymore
[knightmare.git] / levelmap.d
blob3c1ec9fefdb987e90cef1e4745d24a6cc021f045
1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * Based on the DOS Knightmare source code by Andrew Zabolotny
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, version 3 of the License ONLY.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module levelmap;
20 import arsd.color;
21 import arsd.simpledisplay;
23 import iv.cmdcon;
24 import iv.cmdcon.gl;
25 import iv.cmdcon.keybinds;
26 import iv.glbinds.util;
27 import iv.prng.seeder;
28 import iv.prng.pcg32;
29 import iv.strex;
30 import iv.vfs.io;
32 import music;
33 import tatlas;
34 import zmythspr;
37 // ////////////////////////////////////////////////////////////////////////// //
38 public __gshared int Scale = 3;
39 enum StageCount = 8;
40 enum MapWidth = 20;
41 enum MapHeight = 136;
42 enum ScrTilesH = 12;
45 // ////////////////////////////////////////////////////////////////////////// //
46 struct MonsterSpawn {
47 int type;
48 int delayNext;
49 int power;
50 // for bats
51 int groupid;
52 int groupcount;
56 // ////////////////////////////////////////////////////////////////////////// //
57 __gshared ubyte[MapWidth*MapHeight][StageCount] stages;
58 __gshared MonsterSpawn[][StageCount] monsters;
60 __gshared ubyte[MapWidth*MapHeight] stage, stagec; // c: tile hitcounter
61 __gshared MonsterSpawn[] mons;
64 int stageAt (int y, int x) nothrow @trusted @nogc {
65 pragma(inline, true);
66 return (x >= 0 && y >= 0 && x < MapWidth && y < MapHeight ? stage.ptr[y*MapWidth+x] : 0);
69 void stagePutAt (int y, int x, int b) nothrow @trusted @nogc {
70 pragma(inline, true);
71 if (x >= 0 && y >= 0 && x < MapWidth && y < MapHeight) stage.ptr[y*MapWidth+x] = b&0xff;
74 int stageHCAt (int y, int x) nothrow @trusted @nogc {
75 pragma(inline, true);
76 return (x >= 0 && y >= 0 && x < MapWidth && y < MapHeight ? stagec.ptr[y*MapWidth+x] : 0);
79 void stageHCPutAt (int y, int x, int b) nothrow @trusted @nogc {
80 pragma(inline, true);
81 if (x >= 0 && y >= 0 && x < MapWidth && y < MapHeight) stagec.ptr[y*MapWidth+x] = b&0xff;
85 __gshared PCG32 monsprng, spawnprng;
87 __gshared bool paused = false;
89 __gshared bool cheatGod = false;
90 __gshared bool cheatInvul = false;
91 __gshared bool cheatGhost = false;
92 __gshared bool cheatToDevil = false;
93 __gshared bool cheatSpawnGun = false;
94 __gshared bool cheatSpawnPup = false;
95 __gshared bool cheatDevilDead = false;
96 __gshared int cheatSpawnType = 0;
97 __gshared int cheatSpawnPower = 0;
98 __gshared int cheatSetStage = 0;
99 __gshared bool cheatKonamiCode = false;
101 __gshared bool optFixedSpawn = false;
104 shared static this () {
105 conRegVar!cheatGod("god", "toggle god mode");
106 conRegVar!cheatInvul("invul", "toggle invulnerability mode");
107 conRegVar!cheatGhost("ghost", "toggle ghost mode");
108 conRegVar!cheatSetStage("stage", "set current stage");
109 conRegFunc!(() { cheatToDevil = true; })("todevil", "teleport to devil");
110 conRegFunc!(() { cheatSpawnGun = true; })("sp_gun", "spawn weapon powerup");
111 conRegFunc!(() { cheatSpawnPup = true; })("sp_pup", "spawn protection powerup");
112 conRegFunc!(() { cheatDevilDead = true; })("kill_devil", "immediately kill the devil");
116 void seedPRNGs () {
117 if (!optFixedSpawn) {
118 spawnprng.seed(getUlongSeed(), 666);
119 monsprng.seed(spawnprng.front, 69);
124 // ////////////////////////////////////////////////////////////////////////// //
125 void loadStages () {
126 auto fl = VFile("stages.stg");
127 foreach (ref stg; stages[]) fl.rawReadExact(stg[]);
128 assert(fl.tell == fl.size);
129 // visible prizes:
130 // 16: bridge
131 // 17: rook
132 // 18: wall
133 // 19: knight
134 // 20: queen
135 // invisible prizes:
136 // 21: king
137 // 22: exit
138 // 23: bridge (fast)
139 //stages[0][(MapHeight-12)*MapWidth+10] = 22;
141 stages[0][(MapHeight-12)*MapWidth+11] = 17;
142 stages[0][(MapHeight-12)*MapWidth+12] = 18;
143 stages[0][(MapHeight-12)*MapWidth+13] = 19;
144 stages[0][(MapHeight-12)*MapWidth+14] = 20;
145 stages[0][(MapHeight-12)*MapWidth+15] = 21;
146 stages[0][(MapHeight-12)*MapWidth+16] = 22;
147 stages[0][(MapHeight-12)*MapWidth+17] = 23;
152 void loadMonsters () {
153 auto fl = VFile("monsters.stg");
154 foreach (ref mm; monsters[]) {
155 ushort count = fl.readVarUNum!ushort;
156 //conwriteln(count, " monsters...");
157 foreach (immutable _; 0..count) {
158 MonsterSpawn m;
159 m.type = fl.readNum!ubyte;
160 //if (m.type < 1 || m.type > MonsType.max) assert(0, "invalid monster type");
161 m.delayNext = fl.readVarUNum!ushort;
162 //if (m.delayNext == 0) assert(0, "invalid monster delay");
163 m.power = fl.readVarUNum!ushort;
164 mm ~= m;
167 assert(fl.tell == fl.size);
171 // ////////////////////////////////////////////////////////////////////////// //
172 // returns next stidx
173 int loadSpriteGfx (string prefix, string fname, int stidx) {
174 conwriteln("loading '", fname, "'...");
175 bool masked = fname.endsWithCI(".SPR");
176 auto fl = VFile(fname);
177 uint[] img;
178 scope(exit) delete img;
179 while (fl.tell < fl.size) {
180 auto spr = new MythSprite(fl, masked);
181 scope(exit) delete spr;
182 if (img.length < spr.width*spr.height) img.length = spr.width*spr.height;
183 foreach (immutable dy; 0..spr.height) {
184 foreach (immutable dx; 0..spr.width) {
185 img[dy*spr.width+dx] = spr.getpix(dx, dy).asUint;
188 atlasAdd(prefix, stidx++, img[], spr.width, spr.height);
190 return stidx;
194 // ////////////////////////////////////////////////////////////////////////// //
195 void resetStagePRNGs (int stidx) {
196 monsprng.seed(stidx, 666);
197 spawnprng.seed(stidx, 42);
201 void loadStageData (int stidx) {
202 if (stidx < 1) stidx = 1; else if (stidx > StageCount) stidx = StageCount;
203 stage[] = stages[stidx-1][];
204 mons = monsters[stidx-1];
208 // ////////////////////////////////////////////////////////////////////////// //
209 void Sound (int idx, int xpos) {
210 static immutable int[36] prio = [2,2,3,2,3,4,2,2,3,3,3,2,3,4,3,3,2,1,10,10,3,3,3,2,3,5,4,3,2,2,4,3,3,3,1,1];
211 if (idx < 0 || idx > 35) return;
212 //conwriteln("sound #", idx, "; prio=", prio[idx]);
213 int realidx = idx-(idx == 29 ? 1 : 0);
214 //realidx = 19; // i'll be back
215 soundPlay(realidx, xpos, prio[idx]);
219 // ////////////////////////////////////////////////////////////////////////// //
220 void putSprite (const(char)[] prefix, uint idx, int x, int y, int ctint=-1) {
221 auto ai = atlasGet(prefix, idx);
222 if (ai is null) return;
223 alias glx = x;
224 alias gly = y;
226 if (ctint == -1) {
227 glColor4f(1, 1, 1, 1);
228 } else {
229 glColor4f((ctint&0xff)/255.0, ((ctint>>8)&0xff)/255.0, ((ctint>>16)&0xff)/255.0, 1);
232 glColor4f(1, 1, 1, 1);
233 //static if (alpha) glEnable(GL_BLEND); else glDisable(GL_BLEND);
234 glEnable(GL_BLEND);
235 glEnable(GL_TEXTURE_2D);
236 glBindTexture(GL_TEXTURE_2D, ai.tex);
237 glBegin(GL_QUADS);
238 glTexCoord2f(ai.frc.x0, ai.frc.y0); glVertex2i(glx, gly); // top-left
239 glTexCoord2f(ai.frc.x1, ai.frc.y0); glVertex2i(glx+ai.rc.w, gly); // top-right
240 glTexCoord2f(ai.frc.x1, ai.frc.y1); glVertex2i(glx+ai.rc.w, gly+ai.rc.h); // bottom-right
241 glTexCoord2f(ai.frc.x0, ai.frc.y1); glVertex2i(glx, gly+ai.rc.h); // bottom-left
242 glEnd();
243 if (ctint != -1) {
244 glColor4f((ctint&0xff)/255.0, ((ctint>>8)&0xff)/255.0, ((ctint>>16)&0xff)/255.0, 0.5);
245 glBegin(GL_QUADS);
246 glTexCoord2f(ai.frc.x0, ai.frc.y0); glVertex2i(glx, gly); // top-left
247 glTexCoord2f(ai.frc.x1, ai.frc.y0); glVertex2i(glx+ai.rc.w, gly); // top-right
248 glTexCoord2f(ai.frc.x1, ai.frc.y1); glVertex2i(glx+ai.rc.w, gly+ai.rc.h); // bottom-right
249 glTexCoord2f(ai.frc.x0, ai.frc.y1); glVertex2i(glx, gly+ai.rc.h); // bottom-left
250 glEnd();
252 glDisable(GL_BLEND);
256 // ////////////////////////////////////////////////////////////////////////// //
257 int SpawnRandom (int limit) {
258 if (limit < 2) return 0;
259 int res = cast(int)(spawnprng.front&0x7fff_ffff)%limit;
260 spawnprng.popFront();
261 return res;
265 int Random (int limit) {
266 if (limit < 2) return 0;
267 int res = cast(int)(monsprng.front&0x7fff_ffff)%limit;
268 monsprng.popFront();
269 return res;