replaced old numbered script file system with new "modules" system; "Include" is...
[k8-i-v-a-n.git] / src / game / main.cpp
blob5f90f126e86cc289b33ffc4aeda11e7c8acde2de
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #include "ivancommon.h"
14 #include <iostream>
16 #include "game.h"
17 #include "database.h"
18 #include "feio.h"
19 #include "igraph.h"
20 #include "iconf.h"
21 #include "whandler.h"
22 #include "hscore.h"
23 #include "graphics.h"
24 #include "script.h"
25 #include "message.h"
26 #include "proto.h"
29 ////////////////////////////////////////////////////////////////////////////////
30 #define PUSH_BACK(_c) (*ress)[dpos++] = (_c)
31 #define DECODE_TUPLE(tuple,bytes) \
32 for (tmp = bytes; tmp > 0; tmp--, tuple = (tuple & 0x00ffffff)<<8) \
33 PUSH_BACK((char)((tuple >> 24)&0xff))
35 // returns ress length
36 static int ascii85Decode (char **ress, const char *srcs/*, int start, int length*/) {
37 static uint32_t pow85[5] = { 85*85*85*85UL, 85*85*85UL, 85*85UL, 85UL, 1UL };
38 const uint8_t *data = (const uint8_t *)srcs;
39 int len = strlen(srcs);
40 uint32_t tuple = 0;
41 int count = 0, c = 0;
42 int dpos = 0;
43 int start = 0, length = len;
44 int tmp;
46 if (start < 0) start = 0; else { len -= start; data += start; }
47 if (length < 0 || len < length) length = len;
49 if (length > 0) {
50 int xlen = 4*((length+4)/5);
51 kstringReserve(ress, xlen);
55 *ress = (char *)calloc(1, len+1);
56 for (int f = length; f > 0; --f, ++data) {
57 c = *data;
58 if (c <= ' ') continue; // skip blanks
59 switch (c) {
60 case 'z': // zero tuple
61 if (count != 0) {
62 //xdlog("%s: z inside ascii85 5-tuple\n", file);
63 free(*ress);
64 *ress = NULL;
65 return -1;
67 PUSH_BACK('\0');
68 PUSH_BACK('\0');
69 PUSH_BACK('\0');
70 PUSH_BACK('\0');
71 break;
72 case '~': // '~>': end of sequence
73 if (f < 1 || data[1] != '>') { free(*ress); return -2; } // error
74 if (count > 0) { f = -1; break; }
75 default:
76 if (c < '!' || c > 'u') {
77 //xdlog("%s: bad character in ascii85 region: %#o\n", file, c);
78 free(*ress);
79 return -3;
81 tuple += ((uint8_t)(c-'!'))*pow85[count++];
82 if (count == 5) {
83 DECODE_TUPLE(tuple, 4);
84 count = 0;
85 tuple = 0;
87 break;
90 // write last (possibly incomplete) tuple
91 if (count-- > 0) {
92 tuple += pow85[count];
93 DECODE_TUPLE(tuple, count);
95 return dpos;
98 #undef PUSH_BACK
99 #undef DECODE_TUPLE
102 static void decodeBA (char *str, int len) {
103 char pch = 42;
105 for (int f = 0; f < len; ++f, ++str) {
106 char ch = *str;
108 ch = (ch-f-1)^pch;
109 *str = ch;
110 pch = ch;
115 static void printEC (const char *txt) {
116 char *dest;
117 int len;
119 if ((len = ascii85Decode(&dest, txt)) >= 0) {
120 decodeBA(dest, len);
121 fprintf(stderr, "%s\n", dest);
122 free(dest);
127 static int isStr85Equ (const char *txt, const char *str) {
128 char *dest;
129 int len, res = 0;
131 if ((len = ascii85Decode(&dest, txt)) >= 0) {
132 res = (strcmp(dest+1, str) == 0); // +1 to ignore '/'
133 free(dest);
135 return res;
139 static int checkEGG (const char *str) {
140 if (isStr85Equ("06:]JASq", str) || isStr85Equ("0/i", str)) {
141 printEC(
142 "H8lZV&6)1>+AZ>m)Cf8;A1/cP+CnS)0OJ`X.QVcHA4^cc5r3=m1c%0D3&c263d?EV6@4&>"
143 "3DYQo;c-FcO+UJ;MOJ$TAYO@/FI]+B?C.L$>%:oPAmh:4Au)>AAU/H;ZakL2I!*!%J;(AK"
144 "NIR#5TXgZ6c'F1%^kml.JW5W8e;ql0V3fQUNfKpng6ppMf&ip-VOX@=jKl;#q\"DJ-_>jG"
145 "8#L;nm]!q;7c+hR6p;tVY#J8P$aTTK%c-OT?)<00,+q*8f&ff9a/+sbU,:`<H*[fk0o]7k"
146 "^l6nRkngc6Tl2Ngs!!P2I%KHG=7n*an'bsgn>!*8s7TLTC+^\\\"W+<=9^%Ol$1A1eR*Be"
147 "gqjEag:M0OnrC4FBY5@QZ&'HYYZ#EHs8t4$5]!22QoJ3`;-&=\\DteO$d6FBqT0E@:iu?N"
148 "a5ePUf^_uEEcjTDKfMpX/9]DFL8N-Ee;*8C5'WgbGortZuh1\\N0;/rJB6'(MSmYiS\"6+"
149 "<NK)KDV3e+Ad[@).W:%.dd'0h=!QUhghQaNNotIZGrpHr-YfEuUpsKW<^@qlZcdTDA!=?W"
150 "Yd+-^`'G8Or)<0-T&CT.i+:mJp(+/M/nLaVb#5$p2jR2<rl7\"XlngcN`mf,[4oK5JLr\\"
151 "m=X'(ue;'*1ik&/@T4*=j5t=<&/e/Q+2=((h`>>uN(#>&#i>2/ajK+=eib1coVe3'D)*75"
152 "m_h;28^M6p6*D854Jj<C^,Q8Wd\"O<)&L/=C$lUAQNN<=eTD:A6kn-=EItXSss.tAS&!;F"
153 "EsgpJTHIYNNnh'`kmX^[`*ELOHGcWbfPOT`J]A8P`=)AS;rYlR$\"-.RG440lK5:Dg?G'2"
154 "['dE=nEm1:k,,Se_=%-6Z*L^J[)EC"
156 return 1;
158 if (isStr85Equ("04Jj?B)", str)) {
159 printEC(
160 "IPaSa(`c:T,o9Bq3\\)IY++?+!-S9%P0/OkjE&f$l.OmK'Ai2;ZHn[<,6od7^8;)po:HaP"
161 "m<'+&DRS:/1L7)IA7?WI$8WKTUB2tXg>Zb$.?\"@AIAu;)6B;2_PB5M?oBPDC.F)606Z$V"
162 "=ONd6/5P*LoWKTLQ,d@&;+Ru,\\ESY*rg!l1XrhpJ:\"WKWdOg?l;=RHE:uU9C?aotBqj]"
163 "=k8cZ`rp\"ZO=GjkfD#o]Z\\=6^]+Gf&-UFthT*hN"
165 return 1;
167 if (isStr85Equ("04o69A7Tr", str)) {
168 printEC(
169 "Ag7d[&R#Ma9GVV5,S(D;De<T_+W).?,%4n+3cK=%4+0VN@6d\")E].np7l?8gF#cWF7SS_m"
170 "4@V\\nQ;h!WPD2h#@\\RY&G\\LKL=eTP<V-]U)BN^b.DffHkTPnFcCN4B;]8FCqI!p1@H*_"
171 "jHJ<%g']RG*MLqCrbP*XbNL=4D1R[;I(c*<FuesbWmSCF1jTW+rplg;9[S[7eDVl6YsjT"
173 return 1;
175 return 0;
179 int Main (int argc, char *argv[]) {
180 for (int f = 1; f < argc; ++f) {
181 if (checkEGG(argv[f]+1)) exit(1);
184 if (argc > 1 && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-v"))) {
185 std::cout << "Iter Vehemens ad Necem version " << IVAN_VERSION << std::endl;
186 return 0;
189 //femath::SetSeed(time(0));
190 femath::RandSeed();
192 game::LoadModuleList();
194 game::InitGlobalValueMap();
196 // some sanity checks
197 if (game::GetGlobalConst("NONE") != 0) ABORT("`NONE` is not 0");
198 if (game::GetGlobalConst("MIRROR") != 1) ABORT("`MIRROR` is not 1");
199 if (game::GetGlobalConst("FLIP") != 2) ABORT("`FLIP` is not 2");
200 if (game::GetGlobalConst("ROTATE") != 4) ABORT("`ROTATE` is not 4");
202 if (game::GetGlobalConst("GOOD") != 1) ABORT("`GOOD` is not 1");
203 if (game::GetGlobalConst("NEUTRAL") != 2) ABORT("`NEUTRAL` is not 2");
204 if (game::GetGlobalConst("EVIL") != 3) ABORT("`EVIL` is not 3");
206 if (game::GetGlobalConst("RUNED_WHIP") != 1) ABORT("`RUNED_WHIP` is not 1");
207 if (game::GetGlobalConst("CHAIN_WHIP") != 2) ABORT("`CHAIN_WHIP` is not 2");
209 if (game::GetGlobalConst("WAND_OF_POLYMORPH") != 1) ABORT("`WAND_OF_POLYMORPH` is not 1");
210 if (game::GetGlobalConst("WAND_OF_STRIKING") != 2) ABORT("`WAND_OF_STRIKING` is not 2");
212 if (game::GetGlobalConst("KHARAZ_ARAD_SHOP") != 127) ABORT("`KHARAZ_ARAD_SHOP` is not 127");
213 if (game::GetGlobalConst("UNDER_WATER_TUNNEL_EXIT") != 128) ABORT("`UNDER_WATER_TUNNEL_EXIT` is not 128");
215 if (game::GetGlobalConst("ALIEN_VESSEL") != 10) ABORT("`ALIEN_VESSEL` is not 10");
217 scriptsystem::Initialize();
218 databasesystem::Initialize();
219 game::InitLuxTable();
220 ivanconfig::Initialize();
221 igraph::Init();
222 game::CreateBusyAnimationCache();
223 globalwindowhandler::SetQuitMessageHandler(game::HandleQuitMessage);
224 msgsystem::Init();
225 protosystem::Initialize();
226 igraph::LoadMenu();
228 for(;;) {
229 int Select = iosystem::Menu(
230 igraph::GetMenuGraphic(),
231 v2(RES.X / 2, RES.Y / 2 - 20),
232 CONST_S("\r"),
233 CONST_S("Start Game\rContinue Game\rConfiguration\rHighscores\rQuit\r"),
234 LIGHT_GRAY,
235 CONST_S("Released under the GNU\rGeneral Public License\rMore info: see COPYING\r"),
236 CONST_S("IVAN v" IVAN_VERSION "\r"),
237 true);
238 switch (Select) {
239 case -1: return 0; // esc
240 case 0:
241 if (game::Init()) {
242 igraph::UnLoadMenu();
243 game::Run();
244 game::DeInit();
245 igraph::LoadMenu();
247 break;
248 case 1: {
249 festring LoadName = iosystem::ContinueMenu(WHITE, LIGHT_GRAY, game::GetSavePath());
250 if (LoadName.GetSize()) {
251 LoadName.Resize(LoadName.GetSize()-4);
252 if (game::Init(LoadName)) {
253 igraph::UnLoadMenu();
254 game::Run();
255 game::DeInit();
256 igraph::LoadMenu();
259 break; }
260 case 2:
261 ivanconfig::Show();
262 break;
263 case 3: {
264 highscore HScore;
265 HScore.Draw();
266 break; }
267 case 4: return 0;