From 70ef6a1ee9ae21d32b41f5d3671a542ba8234ffd Mon Sep 17 00:00:00 2001 From: Nicholas George Date: Fri, 26 Aug 2022 21:24:57 -0500 Subject: [PATCH] begin project --- CMakeLists.txt | 11 +- main.cpp | 6 - src/bmp.h | 136 +++++++++++++ src/dumbutil.h | 13 ++ src/main.cpp | 239 ++++++++++++++++++++++ test/map00021/map00021.anm | Bin 0 -> 512 bytes test/map00021/map00021.cei.png | Bin 0 -> 2942 bytes test/map00021/map00021.cub | Bin 0 -> 9220 bytes test/map00021/map00021.dor | Bin 0 -> 4 bytes test/map00021/map00021.rom | Bin 0 -> 4 bytes test/map00021/map00021.swt | Bin 0 -> 2804 bytes test/map00021/map00021.tmn | Bin 0 -> 1 bytes test/map00021/map00021.txt | 347 ++++++++++++++++++++++++++++++++ test/map00021/map00021.zon | Bin 0 -> 5204 bytes test/map00021/orig/map00021.anm | Bin 0 -> 512 bytes test/map00021/orig/map00021.cub | Bin 0 -> 9220 bytes test/map00021/orig/map00021.dor | Bin 0 -> 4 bytes test/map00021/orig/map00021.rom | Bin 0 -> 4 bytes test/map00021/orig/map00021.swt | Bin 0 -> 38 bytes test/map00021/orig/map00021.tmn | Bin 0 -> 1 bytes test/map00021/orig/map00021.txt | 347 ++++++++++++++++++++++++++++++++ test/map00021/orig/map00021.zon | Bin 0 -> 5204 bytes 22 files changed, 1090 insertions(+), 9 deletions(-) delete mode 100644 main.cpp create mode 100644 src/bmp.h create mode 100644 src/dumbutil.h create mode 100644 src/main.cpp create mode 100644 test/map00021/map00021.anm create mode 100644 test/map00021/map00021.cei.png create mode 100644 test/map00021/map00021.cub create mode 100644 test/map00021/map00021.dor create mode 100644 test/map00021/map00021.rom create mode 100644 test/map00021/map00021.swt create mode 100644 test/map00021/map00021.tmn create mode 100644 test/map00021/map00021.txt create mode 100644 test/map00021/map00021.zon create mode 100644 test/map00021/orig/map00021.anm create mode 100644 test/map00021/orig/map00021.cub create mode 100644 test/map00021/orig/map00021.dor create mode 100644 test/map00021/orig/map00021.rom create mode 100644 test/map00021/orig/map00021.swt create mode 100644 test/map00021/orig/map00021.tmn create mode 100644 test/map00021/orig/map00021.txt create mode 100644 test/map00021/orig/map00021.zon diff --git a/CMakeLists.txt b/CMakeLists.txt index 78f31dd..614e611 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required(VERSION 3.0) -project(oldkeeperfiler) +project(oldkeeperreader) -add_executable(oldkeeperfiler main.cpp) +add_executable( + oldkeeperreader + src/main.cpp + src/bmp.h + src/dumbutil.h +) -install(TARGETS oldkeeperfiler RUNTIME DESTINATION bin) +install(TARGETS oldkeeperreader RUNTIME DESTINATION bin) diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 8bb47f1..0000000 --- a/main.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char **argv) { - std::cout << "Hello, world!" << std::endl; - return 0; -} diff --git a/src/bmp.h b/src/bmp.h new file mode 100644 index 0000000..07d1af0 --- /dev/null +++ b/src/bmp.h @@ -0,0 +1,136 @@ +#ifndef H_BMP +#define H_BMP +#include +#include +#include + +#pragma pack(push, 1) +struct BMPFileHeader { + uint16_t file_type{0x4D42}; // File type always BM which is 0x4D42 + uint32_t file_size{0}; // Size of the file (in bytes) + uint16_t reserved1{0}; // Reserved, always 0 + uint16_t reserved2{0}; // Reserved, always 0 + uint32_t offset_data{0}; // Start position of pixel data (bytes from the beginning of the file) +}; + +struct BMPInfoHeader { + uint32_t size{ 0 }; // Size of this header (in bytes) + int32_t width{ 0 }; // width of bitmap in pixels + int32_t height{ 0 }; // width of bitmap in pixels + // (if positive, bottom-up, with origin in lower left corner) + // (if negative, top-down, with origin in upper left corner) + uint16_t planes{ 1 }; // No. of planes for the target device, this is always 1 + uint16_t bit_count{ 0 }; // No. of bits per pixel + uint32_t compression{ 0 }; // 0 or 3 - uncompressed. THIS PROGRAM CONSIDERS ONLY UNCOMPRESSED BMP images + uint32_t size_image{ 0 }; // 0 - for uncompressed images + int32_t x_pixels_per_meter{ 0 }; + int32_t y_pixels_per_meter{ 0 }; + uint32_t colors_used{ 0 }; // No. color indexes in the color table. Use 0 for the max number of colors allowed by bit_count + uint32_t colors_important{ 0 }; // No. of colors used for displaying the bitmap. If 0 all colors are required +}; + +struct BMPColorHeader { + uint32_t red_mask{ 0x00ff0000 }; // Bit mask for the red channel + uint32_t green_mask{ 0x0000ff00 }; // Bit mask for the green channel + uint32_t blue_mask{ 0x000000ff }; // Bit mask for the blue channel + uint32_t alpha_mask{ 0xff000000 }; // Bit mask for the alpha channel + uint32_t color_space_type{ 0x73524742 }; // Default "sRGB" (0x73524742) + uint32_t unused[16]{ 0 }; // Unused data for sRGB color space +}; +#pragma pack(pop) + +struct BMP { + BMPFileHeader file_header; + BMPInfoHeader bmp_info_header; + BMPColorHeader bmp_color_header; + std::vector data; + + BMP(int32_t width, int32_t height, bool has_alpha = true) { + if (width <= 0 || height <= 0) { + throw std::runtime_error("The image width and height must be positive numbers."); + } + + bmp_info_header.width = width; + bmp_info_header.height = height; + if (has_alpha) { + bmp_info_header.size = sizeof(BMPInfoHeader) + sizeof(BMPColorHeader); + file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + sizeof(BMPColorHeader); + + bmp_info_header.bit_count = 32; + bmp_info_header.compression = 3; + row_stride = width * 4; + data.resize(row_stride * height); + file_header.file_size = file_header.offset_data + data.size(); + } + else { + bmp_info_header.size = sizeof(BMPInfoHeader); + file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader); + + bmp_info_header.bit_count = 24; + bmp_info_header.compression = 0; + row_stride = width * 3; + data.resize(row_stride * height); + + uint32_t new_stride = make_stride_aligned(4); + file_header.file_size = file_header.offset_data + data.size() + bmp_info_header.height * (new_stride - row_stride); + } + } + + void write(const char *fname) { + std::ofstream of{ fname, std::ios_base::binary }; + if (of) { + if (bmp_info_header.bit_count == 32) { + write_headers_and_data(of); + } + else if (bmp_info_header.bit_count == 24) { + if (bmp_info_header.width % 4 == 0) { + write_headers_and_data(of); + } + else { + uint32_t new_stride = make_stride_aligned(4); + std::vector padding_row(new_stride - row_stride); + + write_headers(of); + + for (int y = 0; y < bmp_info_header.height; ++y) { + of.write((const char*)(data.data() + row_stride * y), row_stride); + of.write((const char*)padding_row.data(), padding_row.size()); + } + } + } + else { + throw std::runtime_error("The program can treat only 24 or 32 bits per pixel BMP files"); + } + } + else { + throw std::runtime_error("Unable to open the output image file."); + } + } + +private: + uint32_t row_stride{ 0 }; + + void write_headers(std::ofstream &of) { + of.write((const char*)&file_header, sizeof(file_header)); + of.write((const char*)&bmp_info_header, sizeof(bmp_info_header)); + if(bmp_info_header.bit_count == 32) { + of.write((const char*)&bmp_color_header, sizeof(bmp_color_header)); + } + } + + void write_headers_and_data(std::ofstream &of) { + write_headers(of); + of.write((const char*)data.data(), data.size()); + } + + // Add 1 to the row_stride until it is divisible with align_stride + uint32_t make_stride_aligned(uint32_t align_stride) { + uint32_t new_stride = row_stride; + while (new_stride % align_stride != 0) { + new_stride++; + } + return new_stride; + } +}; + +#endif diff --git a/src/dumbutil.h b/src/dumbutil.h new file mode 100644 index 0000000..38bb73d --- /dev/null +++ b/src/dumbutil.h @@ -0,0 +1,13 @@ +#ifndef H_DUMBUTIL +#define H_DUMBUTIL +#include + +bool str_ends_with(std::string const &fullString, std::string const &ending) { + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); + } else { + return false; + } +} + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..62d9e41 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,239 @@ +#include +#include + +#include "bmp.h" +#include "dumbutil.h" + +std::string output; + +using namespace std; +int render_flg(char* path) { + streampos size; + char * memblock; + + ifstream file(path, ios::in|ios::binary|ios::ate); + if (file.is_open()) { + size = file.tellg(); + memblock = new char [size]; + file.seekg (0, ios::beg); + file.read (memblock, size); + file.close(); + + BMP bmp(256,256,true); + int channels = bmp.bmp_info_header.bit_count / 8; + + int c = 0; + for (size_t x {0}; x < 256; x++){ + for (size_t y {0}; y < 256; y++){ + int b1 = (int) memblock[c]; + int b2 = (int) memblock[c+1]; + + int color_b {0}; + int color_g {0}; + int color_r {0}; + int color_a {255}; + + if (b1 == -48 || b1 == 0 || b1 == 80) { // Bedrock + // Do nothing for black + } else if (b1 == 96) { // Dirt + color_r = 36; + color_g = 23; + } else if (b1 == 2) { // Path + color_r = 52; + color_g = 36; + color_b = 4; + } else if (b1 == 65) { // Gold + color_r = 96; + color_g = 93; + color_b = 16; + } else if (b1 == -64 || b1 == 84) { // Wall + color_r = 64; + color_g = 48; + color_b = 28; + } else if (b1 == 22) { // Room + color_r = 255; + color_g = 255; + color_b = 255; + } else if (b1 == 64) { // Door + if (b2 == 1) { + color_r = 244; + color_g = 132; + color_b = 92; + } else { + color_r = 144; + color_g = 152; + color_b = 80; + } + } else { + color_a = 0; + cout << "Unknown byte '" << hex << b1 << "'.\n"; + } + + if (b2) { + cout << "Byte of '" << hex << b1 << "' has a secondary byte of '" << hex << b2 << "'.\n"; + } + + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 0] = color_b; // B + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 1] = color_g; // G + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 2] = color_r; // R + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 3] = color_a; // A + + c+=2; + } + } + bmp.bmp_info_header.height *=-1; + bmp.write(output.c_str()); + + delete[] memblock; + } else return 1; + return 0; +} + +int render_ori(char* path) { + streampos size; + char * memblock; + + cout << "Reading File: " << path << "\n"; + ifstream file(path, ios::in|ios::binary|ios::ate); + if (file.is_open()) { + size = file.tellg(); + memblock = new char [size]; + file.seekg (0, ios::beg); + file.read (memblock, size); + file.close(); + + BMP bmp(256,256,true); + int channels = bmp.bmp_info_header.bit_count / 8; + + int c = 0; + for (size_t x {0}; x < 256; x++){ + for (size_t y {0}; y < 256; y++){ + int b1 = (int) memblock[c]; + + int color_b {0}; + int color_g {0}; + int color_r {0}; + int color_a {255}; + + if (b1 == 0) { + color_r = 255; + color_g = 255; + color_b = 255; + } else { + color_a = 0; + cout << "Unknown byte '" << hex << b1 << "'.\n"; + } + + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 0] = color_b; // B + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 1] = color_g; // G + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 2] = color_r; // R + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 3] = color_a; // A + + c++; + } + } + bmp.bmp_info_header.height *=-1; + bmp.write(output.c_str()); + + delete[] memblock; + } else return 1; + return 0; +} + +int render_cei(char* path) { + streampos size; + char * memblock; + + cout << "Reading File: " << path << "\n"; + ifstream file(path, ios::in|ios::binary|ios::ate); + if (file.is_open()) { + size = file.tellg(); + memblock = new char [size]; + file.seekg (0, ios::beg); + file.read (memblock, size); + file.close(); + + BMP bmp(256,256,true); + int channels = bmp.bmp_info_header.bit_count / 8; + + int c = 0; + for (size_t x {0}; x < 256; x++){ + for (size_t y {0}; y < 256; y++){ + int b1 = (int) memblock[c]; + + int lightness = 0; + int alpha {255}; + + if (b1 == 0) { + // Do nothing for black + } else if (b1 == 1) { + lightness = 17; + } else if (b1 == 2) { + lightness = 34; + } else if (b1 == 3) { + lightness = 51; + } else if (b1 == 4) { + lightness = 68; + } else if (b1 == 5) { + lightness = 85; + } else if (b1 == 6) { + lightness = 102; + } else if (b1 == 7) { + lightness = 119; + } else if (b1 == 8) { + lightness = 136; + } else if (b1 == 9) { + lightness = 153; + } else if (b1 == 10) { + lightness = 170; + } else if (b1 == 11) { + lightness = 204; + } else if (b1 == 12) { + lightness = 255; + } else { + alpha = 0; + cout << "Unknown byte '" << hex << b1 << "'.\n"; + } + + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 0] = lightness; // B + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 1] = lightness; // G + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 2] = lightness; // R + bmp.data[channels * (x * bmp.bmp_info_header.width + y) + 3] = alpha; // A + + c++; + } + } + bmp.bmp_info_header.height *=-1; + bmp.write(output.c_str()); + + delete[] memblock; + } else return 1; + return 0; +} + +int main (int argc, char **argv) { + if (argc >= 1) { + for(int i = 1; i < argc; i++) { + std::string arg = std::string(argv[i]); + if (arg == "render") { + output = std::string(argv[i+1]) + ".bmp"; + cout << output << "\n"; + if (str_ends_with(argv[i+1], ".flg")) { + return render_flg(argv[i+1]); + } else if (str_ends_with(argv[i+1], ".ori")) { + return render_ori(argv[i+1]); + } else if (str_ends_with(argv[i+1], ".cei")) { + return render_cei(argv[i+1]); + } else { + cout << "Format not supported.\n"; + return 1; + } + } else { + cout << "Old Keeper Render by Wirlaburla (v0.1)\n"; + cout << "oldkeeperrender render \n"; + } + } + } + + return 0; +} diff --git a/test/map00021/map00021.anm b/test/map00021/map00021.anm new file mode 100644 index 0000000000000000000000000000000000000000..07857a02dcd234e011be4909e816e6fd6a9ee0df GIT binary patch literal 512 zcmd7HMN$I*07KCqifnP0E$;5_&RuEo>(m7b^_DQh3|Am;lT3ygVU#h(nP8GBrkP=u zIp$elktLRG#a3<2)@{Q!ZOgXVv0dA70$P>@J z@X8xui(A^V7O{k7?9-x_w0HZmn5FE)a+bHUAyjV#3RFx^gB2-KwK~qA+6>PtC=6;V_%#g$M} SDc%1HDr7;gzxMO-&+-lSzGX20 literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.cei.png b/test/map00021/map00021.cei.png new file mode 100644 index 0000000000000000000000000000000000000000..7d55bd7f2f6d7df77edf3b484592d1bf7432748a GIT binary patch literal 2942 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 F{tg(P>;?b; literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.cub b/test/map00021/map00021.cub new file mode 100644 index 0000000000000000000000000000000000000000..186fb8b65985b85909976f8ab582395cbc934c30 GIT binary patch literal 9220 zcmeI0`L~r-9mb#Uae&K3a0pGJx`>Dk+FZ9REuoRLOcW7Cj)L<5IN*TS89_x6QA9*R z1XM&sq*keGc`>sQGczkIoBxi!&wb9jpL2NopneLRHCVGuSGAZ!kYu$c&9a|DFVBnX?2oH?7jA#Cn}u;EpOHnajOaBt!aD_WbCSc&@*8&;*xWL!u^JC1n~PyZ`$VF)25az8vZ<`Yiq>W=*5cvBvslsE zJc>v0NYX4Tv!eA5*JC}_C7#8K);rvQ4R|c^-C5DvY{W)9p4hOW^*S7@(35hkLWcXO zka-fq>ukXmJeBxftZ1FtimiA$afTJGGuyBY&m@E8I{+(Mo9)<+XA>J%v^G1i1J5Ns zLsqoD*G}xj^NIJviq^Bf58=!YAm-&fwaU!TwL8s%k{Q+zUgu>P&EoDWWOl*GyaM4T zeHE|b$B7LqTASDK8h(=4u%fm3Da5Yw6hDLDKGl8>;aR_caORf~+_~E8cpbk=Y<5FT ziR$}2$C>lWZ{Q95I`J%4v^Hl2ze3pj4Z=_QcL=ZZ4+xuo zLNv>}{IC2RV|V7?dChLqI)b*B-9w|hF}zW|r+kk&qo){Fv?GeyHB|3HZ=?Eb=?U(C zc#Lek+*-XS=mxQ0F?{CXX-Ab=gG2QoMwgXGhVc3HhVWC22+_>d)%FW9s{B?kIz(So zKk+LwKC0i$_iu>4GV6eb7$4(Xzg=*w0z-{s6*3cILL8QO7Asnti7_z_Pi$Dx+8mYl z{78H#j!3lfNAs0^QcP+Yjx%>;9N97-&)1{l!5T5n55R=P^O${-n?1yQl zzP^X)k8iXYCi>%>#jxVMZ|!0FbN%W`HK#wmT@2@N)(LG!E1lS8xW?2y_QO@%_rpZ{ zepqpy_aoE3AI+)nXKKfOG|&4vDNc&-BwSzT{M`^X9B0mET1<=YB{nCA(K;Mw&Y9^k zJx)n%P7Pthapr8Q%*pAr@{E`frzOs?qP3YBGvoBch83;Nte6#NBsOP;u;Dm!HqB_p zS&7Z;5H=iV&Sp-`iL(=%b3)i~oH?7hVf5_hhLJfhjLi8Vn3TCFE{O}W6PXM1irt3e z%-LL;*B5sfjkaev&YWk>&+E%N%)G4Fo#8lhHdn+Au^>Cq4lmCub{mc}XR|P`uk0{a zWyS6c$Ch&*qz}xb2hhzSX_QO+!mr){_b8JM(2Ech$T59vm}fR|1Ut6mX(*q-Emj;J7Z~U z77hCy#c;gSR2k2@Cwjo%o2#oW4`Fj}2>+jLWi+rNyUl$edh@5Z*5NpF&a`fT`&)^s z1|F!HRWqFQ)7Dg+q3nNn{9?z^y^)7EL zD_3Sy&1|ljCu-)&nt7^bw$#kiHM6ytXToUD+d|OGJR8Dhdx$9|^IQmLcBEmqQN5$h zJRf3bdB1js(cQ;14sNj1%Z!BZ=iv`S_P7?r literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.dor b/test/map00021/map00021.dor new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.rom b/test/map00021/map00021.rom new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.swt b/test/map00021/map00021.swt new file mode 100644 index 0000000000000000000000000000000000000000..5194eaa0652b726fd21fa911a667c7f8a0129dff GIT binary patch literal 2804 ocmYdcU|?VY;!!Xf0;3@?8UmvsFd71*Aut*OqaiRF0>d=~0DeFKX#fBK literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.tmn b/test/map00021/map00021.tmn new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/test/map00021/map00021.txt b/test/map00021/map00021.txt new file mode 100644 index 0000000..3931370 --- /dev/null +++ b/test/map00021/map00021.txt @@ -0,0 +1,347 @@ +REM PLAY Level 34 + +SET_GENERATE_SPEED(700) + +MAX_CREATURES(PLAYER0,25) +MAX_CREATURES(PLAYER1,35) + +START_MONEY(PLAYER0,20000) +START_MONEY(PLAYER1,60000) + +COMPUTER_PLAYER(PLAYER1,6) + + +REM ALL PLAYERS + +ADD_CREATURE_TO_POOL(FLY,20) +ADD_CREATURE_TO_POOL(SPIDER,25) +ADD_CREATURE_TO_POOL(DEMONSPAWN,45) +ADD_CREATURE_TO_POOL(TROLL,30) +ADD_CREATURE_TO_POOL(SORCEROR,17) +ADD_CREATURE_TO_POOL(BILE_DEMON,25) +ADD_CREATURE_TO_POOL(DARK_MISTRESS,20) +ADD_CREATURE_TO_POOL(VAMPIRE,11) +ADD_CREATURE_TO_POOL(DRAGON,11) +ADD_CREATURE_TO_POOL(HELL_HOUND,30) +ADD_CREATURE_TO_POOL(ORC,30) + + + REM Creature_Availability + + CREATURE_AVAILABLE(ALL_PLAYERS,TROLL,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,DEMONSPAWN,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,FLY,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,DARK_MISTRESS,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,SORCEROR,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,SPIDER,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,BILE_DEMON,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,HELL_HOUND,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,DRAGON,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,VAMPIRE,1,1) + CREATURE_AVAILABLE(ALL_PLAYERS,ORC,1,1) + + + REM Room_Availability + + ROOM_AVAILABLE(ALL_PLAYERS,TREASURE,1,1) + ROOM_AVAILABLE(ALL_PLAYERS,LAIR,1,1) + ROOM_AVAILABLE(ALL_PLAYERS,GARDEN,1,1) + ROOM_AVAILABLE(ALL_PLAYERS,TRAINING,1,1) + ROOM_AVAILABLE(ALL_PLAYERS,RESEARCH,1,1) + ROOM_AVAILABLE(ALL_PLAYERS,WORKSHOP,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,BARRACKS,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,GUARD_POST,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,BRIDGE,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,PRISON,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,TORTURE,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,SCAVENGER,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,TEMPLE,1,0) + ROOM_AVAILABLE(ALL_PLAYERS,GRAVEYARD,1,0) + + + REM Spells + + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_HAND,1,1) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_IMP,1,1) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_SLAP,1,1) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_SIGHT,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_CALL_TO_ARMS,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_HEAL_CREATURE,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_SPEED,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_LIGHTNING,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_PROTECT,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_CONCEAL,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_DISEASE,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_CAVE_IN,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_CHICKEN,1,0) + MAGIC_AVAILABLE(ALL_PLAYERS,POWER_HOLD_AUDIENCE,1,0) + + + REM doors & traps + + DOOR_AVAILABLE(ALL_PLAYERS,WOOD,1,0) + TRAP_AVAILABLE(ALL_PLAYERS,ALARM,1,0) + DOOR_AVAILABLE(ALL_PLAYERS,BRACED,1,0) + TRAP_AVAILABLE(ALL_PLAYERS,POISON_GAS,1,0) + DOOR_AVAILABLE(ALL_PLAYERS,STEEL,1,0) + TRAP_AVAILABLE(ALL_PLAYERS,BOULDER,1,0) + DOOR_AVAILABLE(ALL_PLAYERS,MAGIC,1,0) + TRAP_AVAILABLE(ALL_PLAYERS,LIGHTNING,1,0) + TRAP_AVAILABLE(ALL_PLAYERS,WORD_OF_POWER,1,0) + + + REM research order + +rem CREATE_TEXT(0,134"YOUR MISSION HERE IS TO CAPTURE THE AVATAR AND TURN THIS WHOLE WORLD EVIL. A RIVAL KEEPER CHALLENGES YOU FOR THE CROWN OF THE MOST EVIL.") +rem CREATE_TEXT(1,135"WELL DONE,YOU HAVE DESTROYED THE AVATAR'S CASTLE, BUT YOUR RIVAL HAS ALREADY MADE OFF WITH THE CAPTURED AVATAR.ONLY THE MOST EVIL OF DUNGEON KEEPER'S CAN KILL THE AVATAR. PROVE YOUR WORTH, RAMSACK YOUR RIVALS CASTLE AND KILL THE AVATAR") +rem CREATE_TEXT(2,136"THE AVATAR IS DEAD BUT NOT BURIED, HE HAS RESSURECTED HIMSELF IN A HIDDEN HERO STRONGHOLD AND IS ENTHUSING HIS ARMIES TO DESTROY YOUR DUNGEON. THIS NOW IS THE ULTIMATE BATTLE BETWEEN GOOD AND EVIL, THERE CAN ONLY BE ONE SURVIVOR.") + +DISPLAY_OBJECTIVE(134,PLAYER0) + +CREATE_PARTY(ONE) + ADD_TO_PARTY(ONE,ARCHER,2,300,ATTACK_ENEMIES,0) + ADD_TO_PARTY(ONE,ARCHER,2,300,ATTACK_ENEMIES,0) + ADD_TO_PARTY(ONE,ARCHER,2,300,ATTACK_ENEMIES,0) + ADD_TO_PARTY(ONE,ARCHER,2,300,ATTACK_ENEMIES,0) + ADD_TO_PARTY(ONE,ARCHER,2,300,ATTACK_ENEMIES,0) + ADD_TO_PARTY(ONE,ARCHER,2,300,ATTACK_ENEMIES,0) + +CREATE_PARTY(TWO) + ADD_TO_PARTY(TWO,ARCHER,3,500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TWO,BARBARIAN,3,500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TWO,BARBARIAN,3,500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TWO,ARCHER,3,500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TWO,ARCHER,3,500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TWO,ARCHER,3,500,ATTACK_ENEMIES,0) + +CREATE_PARTY(THREE) + ADD_TO_PARTY(THREE,DWARFA,4,550,ATTACK_ENEMIES,0) + ADD_TO_PARTY(THREE,DWARFA,4,550,ATTACK_ENEMIES,0) + ADD_TO_PARTY(THREE,DWARFA,4,550,ATTACK_ENEMIES,0) + ADD_TO_PARTY(THREE,DWARFA,4,550,ATTACK_ENEMIES,0) + ADD_TO_PARTY(THREE,DWARFA,4,550,ATTACK_ENEMIES,0) + ADD_TO_PARTY(THREE,WIZARD,5,650,ATTACK_ENEMIES,0) + + +CREATE_PARTY(FOUR) + ADD_TO_PARTY(FOUR,WIZARD,5,650,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FOUR,WIZARD,5,650,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FOUR,WIZARD,5,650,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FOUR,WIZARD,5,650,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FOUR,DWARFA,5,650,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FOUR,DWARFA,5,650,ATTACK_ENEMIES,0) + + +CREATE_PARTY(FIVE) + ADD_TO_PARTY(FIVE,BARBARIAN,5,750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FIVE,BARBARIAN,5,750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FIVE,BARBARIAN,5,750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FIVE,FAIRY,5,750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FIVE,FAIRY,5,750,ATTACK_ENEMIES,0) + +CREATE_PARTY(THIEVES) + ADD_TO_PARTY(THIEVES,THIEF,8,2000,STEAL_GOLD,0) + ADD_TO_PARTY(THIEVES,THIEF,8,2000,STEAL_GOLD,0) + +CREATE_PARTY(SKELETON) + ADD_TO_PARTY(SKELETON(SKELETON,6,300,ATTACK_ENEMIES,0) + + + +CREATE_PARTY(DWARVEN) + ADD_TO_PARTY(DWARVEN,DWARFA,5,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(DWARVEN,DWARFA,5,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(DWARVEN,DWARFA,5,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(DWARVEN,DWARFA,5,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(DWARVEN,DWARFA,5,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(DWARVEN,DWARFA,5,2000,ATTACK_ENEMIES,0) + + +CREATE_PARTY(TRAINERS) + ADD_TO_PARTY(TRAINERS,BARBARIAN,4,1000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TRAINERS,BARBARIAN,4,1000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TRAINERS,WIZARD,5,1200,STEAL_SPELLS,0) + ADD_TO_PARTY(TRAINERS,WIZARD,3,700,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TRAINERS,ARCHER,3,500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TRAINERS,THIEF,7,3000,STEAL_GOLD,0) + +CREATE_PARTY(SAMURAIII) + ADD_TO_PARTY(SAMURAIII,SAMURAI,6,2500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(SAMURAIII,SAMURAI,6,2500,ATTACK_ENEMIES,0) + +IF_ACTION_POINT(1,PLAYER0) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,ONE,2,1) + SET_FLAG(PLAYER_GOOD,FLAG0,1) + SET_TIMER(PLAYER_GOOD,TIMER0) +ENDIF + + +IF_ACTION_POINT(10,PLAYER0) + SET_FLAG(PLAYER_GOOD,FLAG0,1) +ENDIF + +IF_ACTION_POINT(17,PLAYER0) + SET_FLAG(PLAYER_GOOD,FLAG0,1) +ENDIF + +IF(PLAYER_GOOD,FLAG0 == 1) + IF(PLAYER_GOOD,TIMER0 >= 1500) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,TWO,-4,1) + SET_TIMER(PLAYER_GOOD,TIMER0) + ENDIF +ENDIF + +IF(PLAYER_GOOD,FLAG0 == 1) + IF(PLAYER_GOOD,TIMER0 >= 6000) + NEXT_COMMAND_REUSABLE + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,THREE,-4,1) + next_command_reusable + SET_TIMER(PLAYER_GOOD,TIMER0) + ENDIF +ENDIF + +IF(PLAYER_GOOD,FLAG0 == 1) + IF(PLAYER0,TORTURE >= 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,THIEVES,-4,1) + ENDIF +ENDIF + +IF_ACTION_POINT(3,PLAYER0) + IF(PLAYER_GOOD,FLAG0 == 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SKELETON,4,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SKELETON,5,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SKELETON,6,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SKELETON,7,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SKELETON,8,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SKELETON,9,1) + SET_TIMER(PLAYER_GOOD,TIMER1) + ENDIF +ENDIF + +IF(PLAYER_GOOD,TIMER1 >= 250) + ADD_CREATURE_TO_LEVEL(PLAYER_GOOD,GHOST,6,1,8,0) +ENDIF + +IF(PLAYER_GOOD,TIMER1 >= 290) + ADD_CREATURE_TO_LEVEL(PLAYER_GOOD,GHOST,9,1,8,0) +ENDIF + +IF(PLAYER_good,DUNGEON_DESTROYED == 1) + SET_FLAG(PLAYER_GOOD,FLAG0,2) + DISPLAY_OBJECTIVE(135,PLAYER_GOOD) + ADD_CREATURE_TO_LEVEL(PLAYER1,HORNY,PLAYER1,1,10,0) +ENDIF + +IF_ACTION_POINT(10,PLAYER0) + IF(PLAYER_GOOD,FLAG0 == 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,TRAINERS,11,1) + ENDIF +ENDIF + +IF_ACTION_POINT(12,PLAYER0) + IF(PLAYER_GOOD,FLAG0 == 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,FIVE,-5,1) + ENDIF +ENDIF + +IF_ACTION_POINT(13,PLAYER0) + IF(PLAYER_GOOD,FLAG0 == 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SAMURAIII,14,1) + ENDIF +ENDIF + +IF_ACTION_POINT(13,PLAYER0) + IF(PLAYER_GOOD,FLAG0 == 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,SAMURAIII,15,1) + ENDIF +ENDIF + +IF_ACTION_POINT(16,PLAYER0) + IF(PLAYER_GOOD,FLAG0 == 1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,DWARVEN,-4,1) + ENDIF +ENDIF + + + + + + + + +CREATE_PARTY(TUNNELLER) + ADD_TO_PARTY(TUNNELLER,TUNNELLER,6,200,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TUNNELLER,TUNNELLER,6,200,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TUNNELLER,TUNNELLER,6,200,ATTACK_ENEMIES,0) + ADD_TO_PARTY(TUNNELLER,TUNNELLER,6,200,ATTACK_ENEMIES,0) + +CREATE_PARTY(AVATAR_I) + ADD_TO_PARTY(AVATAR_I,KNIGHT,7,3000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_I,BARBARIAN,5,750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_I,BARBARIAN,5,750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_I,ARCHER,3,550,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_I,ARCHER,3,550,ATTACK_ENEMIES,0) + +CREATE_PARTY(AVATAR_II) + ADD_TO_PARTY(AVATAR_II,KNIGHT,8,3500,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_II,SAMURAI,5,1750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_II,SAMURAI,5,1750,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_II,SAMURAI,5,1750,ATTACK_ENEMIES,0) + +CREATE_PARTY(AVATAR_III) + ADD_TO_PARTY(AVATAR_III,KNIGHT,9,4000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_III,MONK,7,3000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_III,MONK,7,3000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR_III,MONK,7,3000,ATTACK_ENEMIES,0) + +CREATE_PARTY(AVATAR) + ADD_TO_PARTY(AVATAR,KNIGHT,9,4000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR,KNIGHT,9,4000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR,KNIGHT,9,4000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR,KNIGHT,9,4000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(AVATAR,AVATAR,10,20000,ATTACK_ENEMIES,0) + +CREATE_PARTY(FAIRY) + ADD_TO_PARTY(FAIRY,FAIRY,9,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FAIRY,FAIRY,9,2000,ATTACK_ENEMIES,0) + ADD_TO_PARTY(FAIRY,FAIRY,9,2000,ATTACK_ENEMIES,0) + +IF(PLAYER1,DUNGEON_DESTROYED == 1) + SET_FLAG(PLAYER0,FLAG0,3) +ENDIF + + +IF(PLAYER_GOOD,FLAG0 == 3) + IF(PLAYER_GOOD,AVATAR == 0) + DISPLAY_OBJECTIVE(136,PLAYER0) + SET_FLAG(PLAYER0,FLAG0,4) + ENDIF +ENDIF + + + +IF(PLAYER0,FLAG0 == 4) + ADD_TUNNELLER_PARTY_TO_LEVEL(PLAYER_GOOD,TUNNELLER,18,DUNGEON,0,6,200) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,AVATAR_I,-1,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,AVATAR_II,-2,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,AVATAR_III,-3,1) + SET_TIMER(PLAYER_GOOD,TIMER3) + IF(PLAYER_GOOD,TIMER3 >= 300) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,AVATAR,-1,1) + ADD_PARTY_TO_LEVEL(PLAYER_GOOD,FAIRY,-2,1) + IF(PLAYER_GOOD,AVATAR == 0) + WIN_GAME + ENDIF + ENDIF +ENDIF + +IF(PLAYER0,DUNGEON_DESTROYED == 1) + LOSE_GAME +ENDIF + + + + + + + diff --git a/test/map00021/map00021.zon b/test/map00021/map00021.zon new file mode 100644 index 0000000000000000000000000000000000000000..430ef91525a52dc6bfccdf5de7c612684e470d7a GIT binary patch literal 5204 zcmeH@Ee^s!5JtaA#$W)!zu^XGQbBqI1e^jz3c-=;UII-5cUZ|Gu)POu$9xAMRo{x2 z$-ZQE^FGk&vw-=Ko-5yJ3k1zaWbzm8K+t?lCS|w*LAw6KXg;AWc~)+kA9OUIvbm<_ z2YE;H8JW7UBM>y7lX>jE2Owy^AhUnACTPASQx~VI-PY24MP_h0uYn+4Yg7RhPyrQC Y0ToaI6;J^cPyrQC0ToaI73ihF50YpkZ2$lO literal 0 HcmV?d00001 diff --git a/test/map00021/orig/map00021.anm b/test/map00021/orig/map00021.anm new file mode 100644 index 0000000000000000000000000000000000000000..07857a02dcd234e011be4909e816e6fd6a9ee0df GIT binary patch literal 512 zcmd7HMN$I*07KCqifnP0E$;5_&RuEo>(m7b^_DQh3|Am;lT3ygVU#h(nP8GBrkP=u zIp$elktLRG#a3<2)@{Q!ZOgXVv0dA70$P>@J z@X8xui(A^V7O{k7?9-x_w0HZmn5FE)a+bHUAyjV#3RFx^gB2-KwK~qA+6>PtC=6;V_%#g$M} SDc%1HDr7;gzxMO-&+-lSzGX20 literal 0 HcmV?d00001 diff --git a/test/map00021/orig/map00021.cub b/test/map00021/orig/map00021.cub new file mode 100644 index 0000000000000000000000000000000000000000..186fb8b65985b85909976f8ab582395cbc934c30 GIT binary patch literal 9220 zcmeI0`L~r-9mb#Uae&K3a0pGJx`>Dk+FZ9REuoRLOcW7Cj)L<5IN*TS89_x6QA9*R z1XM&sq*keGc`>sQGczkIoBxi!&wb9jpL2NopneLRHCVGuSGAZ!kYu$c&9a|DFVBnX?2oH?7jA#Cn}u;EpOHnajOaBt!aD_WbCSc&@*8&;*xWL!u^JC1n~PyZ`$VF)25az8vZ<`Yiq>W=*5cvBvslsE zJc>v0NYX4Tv!eA5*JC}_C7#8K);rvQ4R|c^-C5DvY{W)9p4hOW^*S7@(35hkLWcXO zka-fq>ukXmJeBxftZ1FtimiA$afTJGGuyBY&m@E8I{+(Mo9)<+XA>J%v^G1i1J5Ns zLsqoD*G}xj^NIJviq^Bf58=!YAm-&fwaU!TwL8s%k{Q+zUgu>P&EoDWWOl*GyaM4T zeHE|b$B7LqTASDK8h(=4u%fm3Da5Yw6hDLDKGl8>;aR_caORf~+_~E8cpbk=Y<5FT ziR$}2$C>lWZ{Q95I`J%4v^Hl2ze3pj4Z=_QcL=ZZ4+xuo zLNv>}{IC2RV|V7?dChLqI)b*B-9w|hF}zW|r+kk&qo){Fv?GeyHB|3HZ=?Eb=?U(C zc#Lek+*-XS=mxQ0F?{CXX-Ab=gG2QoMwgXGhVc3HhVWC22+_>d)%FW9s{B?kIz(So zKk+LwKC0i$_iu>4GV6eb7$4(Xzg=*w0z-{s6*3cILL8QO7Asnti7_z_Pi$Dx+8mYl z{78H#j!3lfNAs0^QcP+Yjx%>;9N97-&)1{l!5T5n55R=P^O${-n?1yQl zzP^X)k8iXYCi>%>#jxVMZ|!0FbN%W`HK#wmT@2@N)(LG!E1lS8xW?2y_QO@%_rpZ{ zepqpy_aoE3AI+)nXKKfOG|&4vDNc&-BwSzT{M`^X9B0mET1<=YB{nCA(K;Mw&Y9^k zJx)n%P7Pthapr8Q%*pAr@{E`frzOs?qP3YBGvoBch83;Nte6#NBsOP;u;Dm!HqB_p zS&7Z;5H=iV&Sp-`iL(=%b3)i~oH?7hVf5_hhLJfhjLi8Vn3TCFE{O}W6PXM1irt3e z%-LL;*B5sfjkaev&YWk>&+E%N%)G4Fo#8lhHdn+Au^>Cq4lmCub{mc}XR|P`uk0{a zWyS6c$Ch&*qz}xb2hhzSX_QO+!mr){_b8JM(2Ech$T59vm}fR|1Ut6mX(*q-Emj;J7Z~U z77hCy#c;gSR2k2@Cwjo%o2#oW4`Fj}2>+jLWi+rNyUl$edh@5Z*5NpF&a`fT`&)^s z1|F!HRWqFQ)7Dg+q3nNn{9?z^y^)7EL zD_3Sy&1|ljCu-)&nt7^bw$#kiHM6ytXToUD+d|OGJR8Dhdx$9|^IQmLcBEmqQN5$h zJRf3bdB1js(cQ;14sNj1%Z!BZ=iv`S_P7?r literal 0 HcmV?d00001 diff --git a/test/map00021/orig/map00021.dor b/test/map00021/orig/map00021.dor new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/test/map00021/orig/map00021.rom b/test/map00021/orig/map00021.rom new file mode 100644 index 0000000000000000000000000000000000000000..593f4708db84ac8fd0f5cc47c634f38c013fe9e4 GIT binary patch literal 4 LcmZQzU|;|M00aO5 literal 0 HcmV?d00001 diff --git a/test/map00021/orig/map00021.swt b/test/map00021/orig/map00021.swt new file mode 100644 index 0000000000000000000000000000000000000000..9da94829423ff5929bd115061714d5e3e05c1ac1 GIT binary patch literal 38 scmWIYb7o{<;QGSAz#wu#p)HAlu}46X@uCZm&%n^ckdVUgY9Wgr0G