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/>.
21 import arsd
.simpledisplay
;
25 import iv
.cmdcon
.keybinds
;
26 import iv
.glbinds
.util
;
27 import iv
.prng
.seeder
;
37 // ////////////////////////////////////////////////////////////////////////// //
38 public __gshared
int Scale
= 3;
45 // ////////////////////////////////////////////////////////////////////////// //
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 {
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 {
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 {
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 {
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");
117 if (!optFixedSpawn
) {
118 spawnprng
.seed(getUlongSeed(), 666);
119 monsprng
.seed(spawnprng
.front
, 69);
124 // ////////////////////////////////////////////////////////////////////////// //
126 auto fl
= VFile("stages.stg");
127 foreach (ref stg
; stages
[]) fl
.rawReadExact(stg
[]);
128 assert(fl
.tell
== fl
.size
);
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
) {
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;
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
);
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
);
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;
227 glColor4f(1, 1, 1, 1);
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);
235 glEnable(GL_TEXTURE_2D
);
236 glBindTexture(GL_TEXTURE_2D
, ai
.tex
);
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
244 glColor4f((ctint
&0xff)/255.0, ((ctint
>>8)&0xff)/255.0, ((ctint
>>16)&0xff)/255.0, 0.5);
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
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();
265 int Random (int limit
) {
266 if (limit
< 2) return 0;
267 int res
= cast(int)(monsprng
.front
&0x7fff_ffff
)%limit
;