1 /*
2  * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3  *
4  * This file is part of Arx Libertatis.
5  *
6  * Arx Libertatis 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, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Arx Libertatis is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Arx Libertatis.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23 
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25 
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28 
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31 
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code.  If not, see
33 <http://www.gnu.org/licenses/>.
34 
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38 
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
46 
47 #include "scene/LoadLevel.h"
48 
49 #include <cstdio>
50 #include <ctime>
51 #include <iomanip>
52 #include <sstream>
53 
54 #include <boost/algorithm/string/case_conv.hpp>
55 
56 #include "ai/PathFinderManager.h"
57 #include "ai/Paths.h"
58 
59 #include "core/Application.h"
60 #include "core/GameTime.h"
61 #include "core/Config.h"
62 #include "core/Core.h"
63 
64 #include "game/EntityManager.h"
65 #include "game/Levels.h"
66 #include "game/Player.h"
67 
68 #include "gui/MiniMap.h"
69 #include "gui/Interface.h"
70 
71 #include "graphics/Math.h"
72 #include "graphics/data/TextureContainer.h"
73 #include "graphics/effects/Fog.h"
74 #include "graphics/particle/ParticleEffects.h"
75 
76 #include "io/fs/FilePath.h"
77 #include "io/fs/FileStream.h"
78 #include "io/fs/Filesystem.h"
79 #include "io/fs/SystemPaths.h"
80 #include "io/resource/ResourcePath.h"
81 #include "io/resource/PakReader.h"
82 #include "io/Blast.h"
83 #include "io/Implode.h"
84 #include "io/log/Logger.h"
85 
86 #include "physics/CollisionShapes.h"
87 
88 #include "scene/Object.h"
89 #include "scene/GameSound.h"
90 #include "scene/Interactive.h"
91 #include "scene/LevelFormat.h"
92 #include "scene/Light.h"
93 
94 #include "util/String.h"
95 
96 using std::max;
97 using std::string;
98 
99 extern float PROGRESS_BAR_COUNT;
100 extern float PROGRESS_BAR_TOTAL;
101 extern long DONT_ERASE_PLAYER;
102 
103 extern QUAKE_FX_STRUCT QuakeFx;
104 extern bool bGToggleCombatModeWithKey;
105 extern bool bGCroucheToggle;
106 
CanPurge(Vec3f * pos)107 bool CanPurge(Vec3f * pos)
108 {
109 	long px, pz;
110 	px = pos->x * ACTIVEBKG->Xmul;
111 
112 	if (px > ACTIVEBKG->Xsize - 3)
113 	{
114 		return true;
115 	}
116 
117 	if (px < 2)
118 	{
119 		return true;
120 	}
121 
122 	pz = pos->z * ACTIVEBKG->Zmul;
123 
124 	if (pz > ACTIVEBKG->Zsize - 3)
125 	{
126 		return true;
127 	}
128 
129 	if (pz < 2)
130 	{
131 		return true;
132 	}
133 
134 	EERIE_BKG_INFO * eg;
135 
136 	for (long j = pz - 1; j <= pz + 1; j++)
137 		for (long i = px - 1; i <= px + 1; i++)
138 		{
139 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
140 
141 			if (eg->nbpoly) return false;
142 		}
143 
144 	return true;
145 }
146 
147 #ifdef BUILD_EDIT_LOADSAVE
148 
LogDirCreation(const fs::path & dir)149 void LogDirCreation(const fs::path & dir) {
150 	if(fs::is_directory(dir)) {
151 		LogDebug("LogDirCreation: " << dir);
152 	}
153 }
154 
DanaeSaveLevel(const fs::path & _fic)155 long DanaeSaveLevel(const fs::path & _fic) {
156 
157 	long nb_inter = GetNumberInterWithOutScriptLoad(); // Without Player
158 	EERIE_BACKGROUND * eb = ACTIVEBKG;
159 
160 	fs::path fic = _fic;
161 	fic.set_ext("dlf");
162 	if(fs::exists(fic)) {
163 		fs::path backupfile = fic;
164 		int i = 0;
165 		do {
166 			std::stringstream s;
167 			s << "dlf_bak_" << i;
168 			backupfile.set_ext(s.str());
169 		} while(fs::exists(backupfile) && (i++, true));
170 
171 		if(!fs::rename(fic, backupfile)) {
172 			LogError << "Unable to rename file " << fic << " to " << backupfile;
173 			return -1;
174 		}
175 	}
176 
177 	fs::path fic2 = fic;
178 	fic2.set_ext("llf");
179 	if(fs::exists(fic2)) {
180 		fs::path backupfile = fic;
181 		int i = 0;
182 		do {
183 			std::stringstream s;
184 			s << "llf_bak_" << i;
185 			backupfile.set_ext(s.str());
186 		} while(fs::exists(backupfile) && (i++, true));
187 
188 		if(!fs::rename(fic2, backupfile)) {
189 			LogError << "Unable to rename file " << fic2 << " to " << backupfile;
190 			return -1;
191 		}
192 	}
193 
194 	DANAE_LS_HEADER dlh;
195 	memset(&dlh, 0, sizeof(DANAE_LS_HEADER));
196 	dlh.nb_nodes = CountNodes();
197 	BOOST_STATIC_ASSERT(SAVED_MAX_LINKS == MAX_LINKS);
198 	dlh.nb_nodeslinks = SAVED_MAX_LINKS;
199 	dlh.nb_lights = 0; // MUST BE 0 !!!!
200 	dlh.nb_fogs = ARX_FOGS_Count();
201 	dlh.nb_bkgpolys = BKG_CountPolys(ACTIVEBKG);
202 	dlh.nb_childpolys = 0;
203 	dlh.nb_ignoredpolys = BKG_CountIgnoredPolys(ACTIVEBKG);
204 	dlh.nb_paths = nbARXpaths;
205 
206 	long bcount = CountBkgVertex();
207 	size_t allocsize = sizeof(DANAE_LS_HEADER) + sizeof(DANAE_LS_HEADER) * 1 + sizeof(DANAE_LS_INTER) * nb_inter + 512
208 					 + sizeof(DANAE_LS_LIGHTINGHEADER) + (bcount + 1) * sizeof(u32)
209 					 + dlh.nb_nodes * (sizeof(DANAE_LS_NODE) + 64 * dlh.nb_nodeslinks)
210 					 + dlh.nb_lights * sizeof(DANAE_LS_LIGHT)
211 
212 					 + 1000000
213 					 + nbARXpaths * sizeof(DANAE_LS_PATH) + nbARXpaths * sizeof(DANAE_LS_PATHWAYS) * 30;
214 	allocsize = max((size_t)dlh.nb_bkgpolys * (sizeof(u32) + 2) + 1000000, allocsize);
215 
216 	char * dat = new char[allocsize];
217 	if(!dat) {
218 		LogError << "Unable to allocate Buffer for save...";
219 		return -1;
220 	}
221 
222 	memset(dat, 0, allocsize);
223 
224 	// Preparing HEADER
225 	dlh.version = DLH_CURRENT_VERSION;
226 
227 	strcpy(dlh.ident, "DANAE_FILE");
228 
229 	dlh.nb_scn = LastLoadedScene.empty() ? 0 : 1;
230 
231 	dlh.nb_inter = nb_inter;
232 	dlh.nb_zones = 0;
233 
234 	dlh.pos_edit = (dlh.nb_scn != 0) ? subj.pos - Mscenepos : subj.pos;
235 
236 	dlh.angle_edit = player.angle;
237 	dlh.lighting = false; // must be false
238 
239 	dlh.time = std::time(NULL);
240 
241 	memset(dlh.lastuser, 0, sizeof(dlh.lastuser));
242 
243 	size_t pos = 0;
244 
245 	memcpy(dat + pos, &dlh, sizeof(DANAE_LS_HEADER));
246 	pos += sizeof(DANAE_LS_HEADER);
247 
248 	// Preparing SCENE DATA
249 	if(dlh.nb_scn > 0) {
250 		DANAE_LS_SCENE dls;
251 		memset(&dls, 0, sizeof(DANAE_LS_SCENE));
252 		strncpy(dls.name, LastLoadedScene.string().c_str(), sizeof(dls.name));
253 		memcpy(dat + pos, &dls, sizeof(DANAE_LS_SCENE));
254 		pos += sizeof(DANAE_LS_SCENE);
255 	}
256 
257 	// preparing INTER DATA, Ignoring Player Data
258 	for(size_t i = 1; i < entities.size(); i++) {
259 		if(entities[i] && !entities[i]->scriptload) {
260 
261 			Entity * io = entities[i];
262 
263 			DANAE_LS_INTER dli;
264 			memset(&dli, 0, sizeof(DANAE_LS_INTER));
265 
266 			if(dlh.nb_scn != 0) {
267 				dli.pos = io->initpos - Mscenepos;
268 			} else {
269 				dli.pos = io->initpos;
270 			}
271 
272 			dli.angle = io->initangle;
273 			strncpy(dli.name, (io->classPath() + ".teo").string().c_str(),
274 			        sizeof(dli.name));
275 
276 			if(io->ident == 0) {
277 				MakeIOIdent(io);
278 			}
279 			dli.ident = io->ident;
280 
281 			if(io->ioflags & IO_FREEZESCRIPT) {
282 				dli.flags = IO_FREEZESCRIPT;
283 			}
284 
285 			memcpy(dat + pos, &dli, sizeof(DANAE_LS_INTER));
286 			pos += sizeof(DANAE_LS_INTER);
287 		}
288 	}
289 
290 	for(size_t i = 0; i < MAX_FOG; i++) {
291 		if(fogs[i].exist) {
292 			DANAE_LS_FOG dlf;
293 			memset(&dlf, 0, sizeof(DANAE_LS_FOG));
294 			dlf.rgb = fogs[i].rgb;
295 			dlf.angle = fogs[i].angle;
296 			dlf.pos = fogs[i].pos - Mscenepos;
297 			dlf.blend = fogs[i].blend;
298 			dlf.frequency = fogs[i].frequency;
299 			dlf.move = fogs[i].move;
300 			dlf.rotatespeed = fogs[i].rotatespeed;
301 			dlf.scale = fogs[i].scale;
302 			dlf.size = fogs[i].size;
303 			dlf.special = fogs[i].special;
304 			dlf.speed = fogs[i].speed;
305 			dlf.tolive = fogs[i].tolive;
306 			memcpy(dat + pos, &dlf, sizeof(DANAE_LS_FOG));
307 			pos += sizeof(DANAE_LS_FOG);
308 		}
309 	}
310 
311 	for(long i = 0; i < nodes.nbmax; i++) {
312 		if(nodes.nodes[i].exist) {
313 
314 			DANAE_LS_NODE dln;
315 			memset(&dln, 0, sizeof(DANAE_LS_NODE));
316 			strcpy(dln.name, nodes.nodes[i].name);
317 			dln.pos = nodes.nodes[i].pos - Mscenepos;
318 			memcpy(dat + pos, &dln, sizeof(DANAE_LS_NODE));
319 			pos += sizeof(DANAE_LS_NODE);
320 
321 			for(size_t j = 0; j < SAVED_MAX_LINKS; j++) {
322 
323 				char name[64];
324 				memset(name, 0, 64);
325 
326 				if(nodes.nodes[i].link[j] != -1 && nodes.nodes[nodes.nodes[i].link[j]].exist) {
327 						strcpy(name, nodes.nodes[nodes.nodes[i].link[j]].name);
328 				}
329 
330 				memcpy(dat + pos, name, 64);
331 				pos += 64;
332 			}
333 		}
334 	}
335 
336 	for(long i = 0; i < nbARXpaths; i++) {
337 
338 		DANAE_LS_PATH dlp;
339 		memset(&dlp, 0, sizeof(DANAE_LS_PATH));
340 		dlp.flags = (short)ARXpaths[i]->flags;
341 		dlp.idx = 0;
342 		dlp.initpos = ARXpaths[i]->initpos - Mscenepos;
343 		dlp.pos = ARXpaths[i]->pos - Mscenepos;
344 		strncpy(dlp.name, ARXpaths[i]->name.c_str(), sizeof(dlp.name));
345 		dlp.nb_pathways = ARXpaths[i]->nb_pathways;
346 		dlp.height = ARXpaths[i]->height;
347 		strncpy(dlp.ambiance, ARXpaths[i]->ambiance.string().c_str(), sizeof(dlp.ambiance));
348 		dlp.amb_max_vol = ARXpaths[i]->amb_max_vol;
349 		dlp.farclip = ARXpaths[i]->farclip;
350 		dlp.reverb = ARXpaths[i]->reverb;
351 		dlp.rgb = ARXpaths[i]->rgb;
352 
353 		memcpy(dat + pos, &dlp, sizeof(DANAE_LS_PATH));
354 		pos += sizeof(DANAE_LS_PATH);
355 
356 		for(long j = 0; j < dlp.nb_pathways; j++) {
357 
358 			DANAE_LS_PATHWAYS dlpw;
359 			memset(&dlpw, 0, sizeof(DANAE_LS_PATHWAYS));
360 			dlpw.flag = ARXpaths[i]->pathways[j].flag;
361 			dlpw.rpos = ARXpaths[i]->pathways[j].rpos;
362 
363 			float fValue = ARXpaths[i]->pathways[j]._time ;
364 			dlpw.time = checked_range_cast<u32>(fValue);
365 
366 			memcpy(dat + pos, &dlpw, sizeof(DANAE_LS_PATHWAYS));
367 			pos += sizeof(DANAE_LS_PATHWAYS);
368 		}
369 	}
370 
371 	//Saving Special Polys
372 	if(pos > allocsize) {
373 		LogError << "Badly Allocated SaveBuffer..." << fic;
374 		delete[] dat;
375 		return -1;
376 	}
377 
378 	// Now Saving Whole Buffer
379 	fs::ofstream ofs(fic, fs::fstream::out | fs::fstream::binary | fs::fstream::trunc);
380 	if(!ofs.is_open()) {
381 		LogError << "Unable to open " << fic << " for write...";
382 		delete[] dat;
383 		return -1;
384 	}
385 
386 	if(ofs.write(dat, sizeof(DANAE_LS_HEADER)).fail()) {
387 		LogError << "Unable to write to " << fic;
388 		delete[] dat;
389 		return -1;
390 	}
391 
392 	size_t cpr_pos = 0;
393 	char * compressed  = implodeAlloc(dat + sizeof(DANAE_LS_HEADER), pos - sizeof(DANAE_LS_HEADER), cpr_pos);
394 
395 	ofs.write(compressed, cpr_pos);
396 
397 	delete[] compressed;
398 
399 	if(ofs.fail()) {
400 		delete[] dat;
401 		return false;
402 	}
403 
404 	ofs.close();
405 
406 	//Now Save Separate LLF Lighting File
407 
408 	pos = 0;
409 
410 	DANAE_LLF_HEADER llh;
411 	memset(&llh, 0, sizeof(DANAE_LLF_HEADER));
412 
413 	// Preparing HEADER
414 	llh.version = DLH_CURRENT_VERSION;
415 	llh.nb_lights = EERIE_LIGHT_Count();
416 	llh.nb_bkgpolys = BKG_CountPolys(ACTIVEBKG);
417 	strcpy(llh.ident, "DANAE_LLH_FILE");
418 
419 	llh.time = std::time(NULL);
420 
421 	memset(llh.lastuser, 0, sizeof(llh.lastuser));
422 
423 	memcpy(dat, &llh, sizeof(DANAE_LLF_HEADER));
424 	pos += sizeof(DANAE_LLF_HEADER);
425 
426 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
427 
428 		EERIE_LIGHT * el = GLight[i];
429 
430 		if(!el || (el->type & TYP_SPECIAL1)) {
431 			continue;
432 		}
433 
434 		DANAE_LS_LIGHT dlight;
435 		memset(&dlight, 0, sizeof(DANAE_LS_LIGHT));
436 		dlight.fallend = el->fallend;
437 		dlight.fallstart = el->fallstart;
438 		dlight.intensity = el->intensity;
439 		dlight.pos = el->pos - Mscenepos;
440 		dlight.rgb = el->rgb;
441 
442 		dlight.extras = el->extras;
443 		dlight.ex_flicker = el->ex_flicker;
444 		dlight.ex_radius = el->ex_radius;
445 		dlight.ex_frequency = el->ex_frequency;
446 		dlight.ex_size = el->ex_size;
447 		dlight.ex_speed = el->ex_speed;
448 		dlight.ex_flaresize = el->ex_flaresize;
449 
450 		memcpy(dat + pos, &dlight, sizeof(DANAE_LS_LIGHT));
451 		pos += sizeof(DANAE_LS_LIGHT);
452 	}
453 
454 	//Saving Special Polys
455 	DANAE_LS_LIGHTINGHEADER dll;
456 	memset(&dll, 0, sizeof(DANAE_LS_LIGHTINGHEADER));
457 	dll.nb_values = bcount;
458 	dll.ModeLight = ModeLight;
459 	dll.ViewMode = ViewMode;
460 	memcpy(dat + pos, &dll, sizeof(DANAE_LS_LIGHTINGHEADER));
461 	pos += sizeof(DANAE_LS_LIGHTINGHEADER);
462 
463 	for(long j = 0; j < eb->Zsize; j++) {
464 		for(long i = 0; i < eb->Xsize; i++) {
465 
466 			EERIE_BKG_INFO * eg = (EERIE_BKG_INFO *)&eb->Backg[i + j*eb->Xsize];
467 			for(long l = 0; l < eg->nbpoly; l++) {
468 
469 				EERIEPOLY * ep = &eg->polydata[l];
470 				if(ep) {
471 					long nbvert = (ep->type & POLY_QUAD) ? 4 : 3;
472 					for(long k = 0; k < nbvert; k++) {
473 						u32 tmp = (u32)ep->v[k].color;
474 						memcpy(dat + pos, &tmp, sizeof(u32));
475 						pos += sizeof(u32);
476 					}
477 				}
478 			}
479 		}
480 	}
481 
482 	if(pos > allocsize) {
483 		LogError << "Badly allocated save buffer..." << fic2;
484 		delete[] dat;
485 		return -1;
486 	}
487 
488 	// Now Saving Whole Buffer
489 	ofs.open(fic2, fs::fstream::out | fs::fstream::binary | fs::fstream::trunc);
490 	if(!ofs.is_open()) {
491 		LogError << "Unable to open " << fic2 << " for write...";
492 		delete[] dat;
493 		return -1;
494 	}
495 
496 	compressed = NULL;
497 	cpr_pos = 0;
498 	compressed = implodeAlloc(dat, pos, cpr_pos);
499 	delete[] dat;
500 
501 	ofs.write(compressed, cpr_pos);
502 
503 	delete[] compressed;
504 
505 	if(ofs.fail()) {
506 		LogError << "Unable to Write to " << fic2;
507 		return -1;
508 	}
509 
510 	ADDED_IO_NOT_SAVED = 0;
511 
512 	return 1;
513 }
514 
WriteIOInfo(Entity * io,const fs::path & dir)515 void WriteIOInfo(Entity * io, const fs::path & dir) {
516 
517 	if(!fs::is_directory(dir)) {
518 		return;
519 	}
520 
521 	fs::path file = (dir / io->short_name()).set_ext("log");
522 
523 	fs::ofstream ofs(file, fs::fstream::out | fs::fstream::trunc);
524 	if(!ofs.is_open()) {
525 		return;
526 	}
527 
528 	ofs << "Object   : " << io->long_name() << std::endl;
529 	ofs << "_______________________________" << std::endl << std::endl;
530 	ofs << "Level    : " << LastLoadedScene << std::endl;
531 	ofs << "Position : x " << (io->initpos.x - Mscenepos.x)
532 	              << " y " << (io->initpos.y - Mscenepos.y)
533 	              << " z " << (io->initpos.z - Mscenepos.z) << " (relative to anchor)" << std::endl;
534 
535 }
536 
SaveIOScript(Entity * io,long fl)537 void SaveIOScript(Entity * io, long fl) {
538 
539 	fs::path file;
540 	EERIE_SCRIPT * script;
541 
542 	switch(fl) {
543 
544 		case 1: { // class script
545 			file = fs::paths.user / io->classPath().string();
546 			script = &io->script;
547 			break;
548 		}
549 
550 		case 2: { // local script
551 			if(io->ident == 0) {
552 				LogError << ("NO IDENT...");
553 				return;
554 			}
555 			file = fs::paths.user / io->full_name().string();
556 			if(!fs::is_directory(file)) {
557 				LogError << "Local DIR don't Exists...";
558 				return;
559 			}
560 			file /= io->short_name();
561 			script = &io->over_script;
562 			break;
563 		}
564 
565 		default: return;
566 	}
567 
568 	file.append(".asl");
569 
570 	fs::ofstream ofs(file, fs::fstream::out | fs::fstream::trunc | fs::fstream::binary);
571 	if(!ofs.is_open()) {
572 		LogError << ("Unable To Save...");
573 		return;
574 	}
575 
576 	ofs.write(script->data, script->size);
577 
578 	ARX_SCRIPT_ComputeShortcuts(*script);
579 }
580 
581 #endif // BUILD_EDIT_LOADSAVE
582 
583 
LoadInter_Ex(const res::path & classPath,EntityInstance instance,const Vec3f & pos,const Anglef & angle,const Vec3f & trans)584 Entity * LoadInter_Ex(const res::path & classPath, EntityInstance instance,
585                       const Vec3f & pos, const Anglef & angle,
586                       const Vec3f & trans) {
587 
588 	std::ostringstream nameident;
589 	nameident << classPath.filename()
590 	          << std::setfill('0') << std::setw(4) << instance;
591 
592 	long t = entities.getById(nameident.str());
593 	if(t >= 0) {
594 		return entities[t];
595 	}
596 
597 	arx_assert(instance != 0);
598 
599 	Entity * io = AddInteractive(classPath, instance, NO_MESH | NO_ON_LOAD);
600 	if(!io) {
601 		return NULL;
602 	}
603 
604 	RestoreInitialIOStatusOfIO(io);
605 	ARX_INTERACTIVE_HideGore(io);
606 
607 	io->lastpos = io->initpos = io->pos = pos + trans;
608 	io->move = Vec3f::ZERO;
609 	io->initangle = io->angle = angle;
610 
611 	res::path tmp = io->full_name(); // Get the directory name to check for
612 	string id = io->short_name();
613 	if(PakDirectory * dir = resources->getDirectory(tmp)) {
614 		if(PakFile * file = dir->getFile(id + ".asl")) {
615 			loadScript(io->over_script, file);
616 			io->over_script.master = (io->script.data != NULL) ? &io->script : NULL;
617 		}
618 	}
619 
620 	if(SendIOScriptEvent(io, SM_LOAD) == ACCEPT && io->obj == NULL) {
621 		bool pbox = (io->ioflags & IO_ITEM) == IO_ITEM;
622 		io->obj = loadObject(io->classPath() + ".teo", pbox);
623 		if(io->ioflags & IO_NPC) {
624 			EERIE_COLLISION_Cylinder_Create(io);
625 		}
626 	}
627 
628 	return io;
629 }
630 
631 static long LastLoadedLightningNb = 0;
632 static u32 * LastLoadedLightning = NULL;
633 Vec3f loddpos;
634 Vec3f MSP;
635 
636 extern long FASTmse;
637 
DanaeLoadLevel(const res::path & file,bool loadEntities)638 long DanaeLoadLevel(const res::path & file, bool loadEntities) {
639 
640 	LogInfo << "Loading Level " << file;
641 
642 	CURRENTLEVEL = GetLevelNumByName(file.string());
643 
644 	res::path lightingFileName = res::path(file).set_ext("llf");
645 
646 	LogDebug("fic2 " << lightingFileName);
647 	LogDebug("fileDlf " << file);
648 
649 	size_t FileSize = 0;
650 	char * dat = resources->readAlloc(file, FileSize);
651 	if(!dat) {
652 		LogError << "Unable to find " << file;
653 		return -1;
654 	}
655 
656 	PakFile * lightingFile = resources->getFile(lightingFileName);
657 
658 	PROGRESS_BAR_COUNT += 1.f;
659 	LoadLevelScreen();
660 
661 	size_t pos = 0;
662 
663 	DANAE_LS_HEADER dlh;
664 	memcpy(&dlh, dat + pos, sizeof(DANAE_LS_HEADER));
665 	pos += sizeof(DANAE_LS_HEADER);
666 
667 	LogDebug("dlh.version " << dlh.version << " header size " << sizeof(DANAE_LS_HEADER));
668 
669 	if(dlh.version > DLH_CURRENT_VERSION) {
670 		LogError << "Unexpected level file version: " << dlh.version << " for " << file;
671 		free(dat);
672 		dat = NULL;
673 		return -1;
674 	}
675 
676 	// using compression
677 	if(dlh.version >= 1.44f) {
678 		char * torelease = dat;
679 		dat = blastMemAlloc(dat + pos, FileSize - pos, FileSize);
680 		free(torelease);
681 		pos = 0;
682 		if(!dat) {
683 			LogError << "STD_Explode did not return anything " << file;
684 			return -1;
685 		}
686 	}
687 
688 	loddpos = subj.pos = dlh.pos_edit;
689 	player.desiredangle = player.angle = subj.angle = dlh.angle_edit;
690 
691 	if(strcmp(dlh.ident, "DANAE_FILE")) {
692 		LogError << "Not a valid file " << file << ": \"" << util::loadString(dlh.ident) << '"';
693 		return -1;
694 	}
695 
696 	LogDebug("Loading Scene");
697 
698 	// Loading Scene
699 	if(dlh.nb_scn > 0) {
700 
701 		const DANAE_LS_SCENE * dls = reinterpret_cast<const DANAE_LS_SCENE *>(dat + pos);
702 		pos += sizeof(DANAE_LS_SCENE);
703 
704 		res::path scene = res::path::load(util::loadString(dls->name));
705 
706 		if(FastSceneLoad(scene)) {
707 			LogDebug("done loading scene");
708 			FASTmse = 1;
709 		} else {
710 #ifdef BUILD_EDIT_LOADSAVE
711 			LogDebug("fast loading scene failed");
712 			ARX_SOUND_PlayCinematic("editor_humiliation", false);
713 			mse = PAK_MultiSceneToEerie(scene);
714 			PROGRESS_BAR_COUNT += 20.f;
715 			LoadLevelScreen();
716 #else
717 			LogError << "Fast loading scene failed";
718 #endif
719 		}
720 
721 		EERIEPOLY_Compute_PolyIn();
722 		LastLoadedScene = scene;
723 	}
724 
725 	Vec3f trans;
726 	if(FASTmse) {
727 		trans = Mscenepos;
728 		player.pos = loddpos + trans;
729 	}
730 #ifdef BUILD_EDIT_LOADSAVE
731 	else if(mse != NULL) {
732 		Mscenepos.x = -mse->cub.xmin - (mse->cub.xmax - mse->cub.xmin) * ( 1.0f / 2 ) + ((float)ACTIVEBKG->Xsize * (float)ACTIVEBKG->Xdiv) * ( 1.0f / 2 );
733 		Mscenepos.z = -mse->cub.zmin - (mse->cub.zmax - mse->cub.zmin) * ( 1.0f / 2 ) + ((float)ACTIVEBKG->Zsize * (float)ACTIVEBKG->Zdiv) * ( 1.0f / 2 );
734 		float t1 = (float)(long)(mse->point0.x / BKG_SIZX);
735 		float t2 = (float)(long)(mse->point0.z / BKG_SIZZ);
736 		t1 = mse->point0.x - t1 * BKG_SIZX;
737 		t2 = mse->point0.z - t2 * BKG_SIZZ;
738 		Mscenepos.x = (float)((long)(Mscenepos.x / BKG_SIZX)) * BKG_SIZX + (float)BKG_SIZX * ( 1.0f / 2 );
739 		Mscenepos.z = (float)((long)(Mscenepos.z / BKG_SIZZ)) * BKG_SIZZ + (float)BKG_SIZZ * ( 1.0f / 2 );
740 		mse->pos.x = Mscenepos.x = Mscenepos.x + BKG_SIZX - t1;
741 		mse->pos.z = Mscenepos.z = Mscenepos.z + BKG_SIZZ - t2;
742 		mse->pos.y = Mscenepos.y = -mse->cub.ymin - 100.f - mse->point0.y;
743 		lastteleport = player.pos = subj.pos = moveto = mse->pos + mse->point0;
744 		mapcam.pos.x = player.pos.x;
745 		mapcam.pos.z = player.pos.z;
746 		lastteleport.y -= 180.f;
747 		player.pos.y = subj.pos.y -= 180.f;
748 		trans = mse->pos;
749 	}
750 #endif // BUILD_EDIT_LOADSAVE
751 	else
752 	{
753 		lastteleport = player.baseOffset();
754 		Mscenepos = trans = Vec3f::ZERO;
755 	}
756 
757 	MSP = trans;
758 
759 	float increment = 0;
760 	if(dlh.nb_inter > 0) {
761 		increment = (60.f / (float)dlh.nb_inter);
762 	} else {
763 		PROGRESS_BAR_COUNT += 60;
764 		LoadLevelScreen();
765 	}
766 
767 	for(long i = 0 ; i < dlh.nb_inter ; i++) {
768 
769 		PROGRESS_BAR_COUNT += increment;
770 		LoadLevelScreen();
771 
772 		const DANAE_LS_INTER * dli = reinterpret_cast<const DANAE_LS_INTER *>(dat + pos);
773 		pos += sizeof(DANAE_LS_INTER);
774 
775 		if(loadEntities) {
776 
777 			string pathstr = boost::to_lower_copy(util::loadString(dli->name));
778 
779 			size_t pos = pathstr.find("graph");
780 			if(pos != std::string::npos) {
781 				pathstr = pathstr.substr(pos);
782 			}
783 
784 			res::path classPath = res::path::load(pathstr).remove_ext();
785 			LoadInter_Ex(classPath, dli->ident, dli->pos, dli->angle, trans);
786 		}
787 	}
788 
789 	if(dlh.lighting) {
790 
791 		const DANAE_LS_LIGHTINGHEADER * dll = reinterpret_cast<const DANAE_LS_LIGHTINGHEADER *>(dat + pos);
792 		pos += sizeof(DANAE_LS_LIGHTINGHEADER);
793 		long bcount = dll->nb_values;
794 
795 		if(!lightingFile) {
796 
797 			LastLoadedLightningNb = bcount;
798 
799 			// DANAE_LS_VLIGHTING
800 			free(LastLoadedLightning);
801 			u32 * ll = LastLoadedLightning = (u32 *)malloc(sizeof(u32) * bcount);
802 
803 			if(dlh.version > 1.001f) {
804 				std::copy((u32*)(dat + pos), (u32*)(dat + pos) + bcount, LastLoadedLightning);
805 				pos += sizeof(u32) * bcount;
806 			} else {
807 				while(bcount) {
808 					const DANAE_LS_VLIGHTING * dlv = reinterpret_cast<const DANAE_LS_VLIGHTING *>(dat + pos);
809 					pos += sizeof(DANAE_LS_VLIGHTING);
810 					*ll = 0xff000000L | ((dlv->r & 255) << 16) | ((dlv->g & 255) << 8) | (dlv->b & 255);
811 					ll++;
812 					bcount--;
813 				}
814 			}
815 
816 		} else {
817 			pos += sizeof(u32) * bcount;
818 		}
819 
820 		ModeLight = LightMode::load(dll->ModeLight); // TODO save/load flags
821 		ViewMode = ViewModeFlags::load(dll->ViewMode); // TODO save/load flags
822 		ViewMode &= ~VIEWMODE_WIRE;
823 	}
824 
825 	PROGRESS_BAR_COUNT += 1;
826 	LoadLevelScreen();
827 
828 	long nb_lights = (dlh.version < 1.003f) ? 0 : dlh.nb_lights;
829 
830 	if(!lightingFile) {
831 
832 		if(nb_lights != 0) {
833 			EERIE_LIGHT_GlobalInit();
834 		}
835 
836 		for(long i = 0; i < nb_lights; i++) {
837 
838 			const DANAE_LS_LIGHT * dlight = reinterpret_cast<const DANAE_LS_LIGHT *>(dat + pos);
839 			pos += sizeof(DANAE_LS_LIGHT);
840 
841 			long j = EERIE_LIGHT_Create();
842 			if(j >= 0) {
843 				EERIE_LIGHT * el = GLight[j];
844 
845 				el->exist = 1;
846 				el->treat = 1;
847 				el->fallend = dlight->fallend;
848 				el->fallstart = dlight->fallstart;
849 				el->falldiff = el->fallend - el->fallstart;
850 				el->falldiffmul = 1.f / el->falldiff;
851 				el->intensity = dlight->intensity;
852 				el->pos = dlight->pos;
853 				el->rgb = dlight->rgb;
854 
855 				el->extras = checked_range_cast<short>(dlight->extras);
856 
857 				el->ex_flicker = dlight->ex_flicker;
858 				el->ex_radius = dlight->ex_radius;
859 				el->ex_frequency = dlight->ex_frequency;
860 				el->ex_size = dlight->ex_size;
861 				el->ex_speed = dlight->ex_speed;
862 				el->tl = -1;
863 				el->sample = audio::INVALID_ID;
864 
865 				if((el->extras & EXTRAS_SPAWNFIRE)) {
866 					el->extras |= EXTRAS_FLARE;
867 					if(el->extras & EXTRAS_FIREPLACE) {
868 						el->ex_flaresize = 95.f;
869 					} else {
870 						el->ex_flaresize = 40.f;
871 					}
872 				}
873 			}
874 		}
875 
876 	} else {
877 		pos += sizeof(DANAE_LS_LIGHT) * nb_lights;
878 	}
879 
880 	LogDebug("Loading FOGS");
881 	ARX_FOGS_Clear();
882 
883 	for(long i = 0; i < dlh.nb_fogs; i++) {
884 
885 		const DANAE_LS_FOG * dlf = reinterpret_cast<const DANAE_LS_FOG *>(dat + pos);
886 		pos += sizeof(DANAE_LS_FOG);
887 
888 		long n = ARX_FOGS_GetFree();
889 		if(n > -1) {
890 
891 			FOG_DEF * fd = &fogs[n];
892 			fd->exist = 1;
893 			fd->rgb = dlf->rgb;
894 			fd->angle = dlf->angle;
895 			fd->pos = Vec3f(dlf->pos) + trans;
896 			fd->blend = dlf->blend;
897 			fd->frequency = dlf->frequency;
898 			fd->rotatespeed = dlf->rotatespeed;
899 			fd->scale = dlf->scale;
900 			fd->size = dlf->size;
901 			fd->special = dlf->special;
902 			fd->speed = dlf->speed;
903 			fd->tolive = dlf->tolive;
904 			fd->move.x = 1.f;
905 			fd->move.y = 0.f;
906 			fd->move.z = 0.f;
907 			Vec3f out;
908 			float ta = radians(MAKEANGLE(fd->angle.b));
909 			YRotatePoint(&fd->move, &out, EEcos(ta), EEsin(ta));
910 			float tb = radians(MAKEANGLE(fd->angle.a));
911 			XRotatePoint(&out, &fd->move, EEcos(tb), EEsin(tb));
912 		}
913 	}
914 
915 	PROGRESS_BAR_COUNT += 2.f;
916 	LoadLevelScreen();
917 
918 	LogDebug("Loading Nodes");
919 	ClearNodes();
920 
921 	long nb_nodes = (dlh.version < 1.001f) ? 0 : dlh.nb_nodes;
922 	for(long i = 0; i < nb_nodes; i++) {
923 
924 		nodes.nodes[i].exist = 1;
925 		nodes.nodes[i].selected = 0;
926 		const DANAE_LS_NODE * dln = reinterpret_cast<const DANAE_LS_NODE *>(dat + pos);
927 		pos += sizeof(DANAE_LS_NODE);
928 
929 		strcpy(nodes.nodes[i].name, boost::to_lower_copy(util::loadString(dln->name)).c_str());
930 		nodes.nodes[i].pos = (Vec3f)dln->pos + trans;
931 
932 		for(long j = 0; j < dlh.nb_nodeslinks; j++) {
933 			if(dat[pos] != '\0') {
934 				strcpy(nodes.nodes[i].lnames[j], boost::to_lower_copy(util::loadString(dat + pos, 64)).c_str());
935 			}
936 			pos += 64;
937 		}
938 	}
939 
940 	RestoreNodeNumbers();
941 
942 	LogDebug("Loading Paths");
943 	ARX_PATH_ReleaseAllPath();
944 
945 	if(dlh.nb_paths) {
946 		ARXpaths = (ARX_PATH **)malloc(sizeof(ARX_PATH *) * dlh.nb_paths);
947 		nbARXpaths = dlh.nb_paths;
948 	}
949 
950 	for(long i = 0; i < dlh.nb_paths; i++) {
951 
952 		const DANAE_LS_PATH * dlp = reinterpret_cast<const DANAE_LS_PATH *>(dat + pos);
953 		pos += sizeof(DANAE_LS_PATH);
954 
955 		Vec3f ppos = Vec3f(dlp->initpos) + trans;
956 		ARX_PATH * ap = ARXpaths[i] = new ARX_PATH(boost::to_lower_copy(util::loadString(dlp->name)), ppos);
957 
958 		ap->flags = PathFlags::load(dlp->flags); // TODO save/load flags
959 		ap->pos = Vec3f(dlp->pos) + trans;
960 		ap->nb_pathways = dlp->nb_pathways;
961 		ap->height = dlp->height;
962 		ap->ambiance = res::path::load(util::loadString(dlp->ambiance));
963 
964 		ap->amb_max_vol = dlp->amb_max_vol;
965 		if(ap->amb_max_vol <= 1.f) {
966 			ap->amb_max_vol = 100.f;
967 		}
968 
969 		ap->farclip = dlp->farclip;
970 		ap->reverb = dlp->reverb;
971 		ap->rgb = dlp->rgb;
972 
973 		ARX_PATHWAY * app = ap->pathways = (ARX_PATHWAY *)malloc(sizeof(ARX_PATHWAY) * dlp->nb_pathways);
974 		memset(app, 0, sizeof(ARX_PATHWAY)*dlp->nb_pathways);
975 
976 		for(long j = 0; j < dlp->nb_pathways; j++) {
977 
978 			const DANAE_LS_PATHWAYS * dlpw = reinterpret_cast<const DANAE_LS_PATHWAYS *>(dat + pos);
979 			pos += sizeof(DANAE_LS_PATHWAYS);
980 
981 			app[j].flag = (PathwayType)dlpw->flag; // save/load enum
982 			app[j].rpos = dlpw->rpos;
983 			app[j]._time = static_cast<float>(dlpw->time);
984 		}
985 	}
986 
987 	ARX_PATH_ComputeAllBoundingBoxes();
988 	PROGRESS_BAR_COUNT += 5.f;
989 	LoadLevelScreen();
990 
991 
992 	//Now LOAD Separate LLF Lighting File
993 
994 	free(dat);
995 	pos = 0;
996 	dat = NULL;
997 
998 	if(lightingFile) {
999 
1000 		LogDebug("Loading LLF Info");
1001 
1002 		// using compression
1003 		if(dlh.version >= 1.44f) {
1004 			char * compressed = lightingFile->readAlloc();
1005 			dat = (char*)blastMemAlloc(compressed, lightingFile->size(), FileSize);
1006 			free(compressed);
1007 		} else {
1008 			dat = lightingFile->readAlloc();
1009 			FileSize = lightingFile->size();
1010 		}
1011 	}
1012 	// TODO size ignored
1013 
1014 	if(!dat) {
1015 		LOADEDD = 1;
1016 		FASTmse = 0;
1017 		USE_PLAYERCOLLISIONS = 1;
1018 		LogInfo << "Done loading level";
1019 		return 1;
1020 	}
1021 
1022 	const DANAE_LLF_HEADER * llh = reinterpret_cast<DANAE_LLF_HEADER *>(dat + pos);
1023 	pos += sizeof(DANAE_LLF_HEADER);
1024 
1025 	PROGRESS_BAR_COUNT += 4.f;
1026 	LoadLevelScreen();
1027 
1028 	if(llh->nb_lights != 0) {
1029 		EERIE_LIGHT_GlobalInit();
1030 	}
1031 
1032 	for(int i = 0; i < llh->nb_lights; i++) {
1033 
1034 		const DANAE_LS_LIGHT * dlight = reinterpret_cast<const DANAE_LS_LIGHT *>(dat + pos);
1035 		pos += sizeof(DANAE_LS_LIGHT);
1036 
1037 		long j = EERIE_LIGHT_Create();
1038 		if(j >= 0) {
1039 			EERIE_LIGHT * el = GLight[j];
1040 
1041 			el->exist = 1;
1042 			el->treat = 1;
1043 			el->fallend = dlight->fallend;
1044 			el->fallstart = dlight->fallstart;
1045 			el->falldiff = el->fallend - el->fallstart;
1046 			el->falldiffmul = 1.f / el->falldiff;
1047 			el->intensity = dlight->intensity;
1048 
1049 			if(FASTmse) {
1050 				el->pos = Vec3f(dlight->pos) + trans;
1051 			} else {
1052 				el->pos = dlight->pos;
1053 			}
1054 
1055 			el->rgb = dlight->rgb;
1056 
1057 			el->extras = checked_range_cast<short>(dlight->extras);
1058 
1059 			el->ex_flicker = dlight->ex_flicker;
1060 			el->ex_radius = dlight->ex_radius;
1061 			el->ex_frequency = dlight->ex_frequency;
1062 			el->ex_size = dlight->ex_size;
1063 			el->ex_speed = dlight->ex_speed;
1064 			el->ex_flaresize = dlight->ex_flaresize;
1065 
1066 			el->status = (el->extras & EXTRAS_STARTEXTINGUISHED) ? 0 : 1;
1067 
1068 			if((el->extras & EXTRAS_SPAWNFIRE) && (!(el->extras & EXTRAS_FLARE))) {
1069 				el->extras |= EXTRAS_FLARE;
1070 				if(el->extras & EXTRAS_FIREPLACE) {
1071 					el->ex_flaresize = 95.f;
1072 				} else {
1073 					el->ex_flaresize = 80.f;
1074 				}
1075 			}
1076 
1077 			el->tl = -1;
1078 			el->sample = audio::INVALID_ID;
1079 		}
1080 	}
1081 
1082 	PROGRESS_BAR_COUNT += 2.f;
1083 	LoadLevelScreen();
1084 
1085 	const DANAE_LS_LIGHTINGHEADER * dll = reinterpret_cast<const DANAE_LS_LIGHTINGHEADER *>(dat + pos);
1086 	pos += sizeof(DANAE_LS_LIGHTINGHEADER);
1087 
1088 	long bcount = dll->nb_values;
1089 	LastLoadedLightningNb = bcount;
1090 
1091 	//DANAE_LS_VLIGHTING
1092 	free(LastLoadedLightning);
1093 	u32 * ll = LastLoadedLightning = (u32 *)malloc(sizeof(u32) * bcount);
1094 	if(dlh.version > 1.001f) {
1095 		std::copy((u32*)(dat + pos), (u32*)(dat + pos) + bcount, LastLoadedLightning);
1096 		pos += sizeof(u32) * bcount;
1097 	} else {
1098 		while(bcount) {
1099 			const DANAE_LS_VLIGHTING * dlv = reinterpret_cast<const DANAE_LS_VLIGHTING *>(dat + pos);
1100 			pos += sizeof(DANAE_LS_VLIGHTING);
1101 			*ll = 0xff000000L | ((dlv->r & 255) << 16) | ((dlv->g & 255) << 8) | (dlv->b & 255);
1102 			ll++;
1103 			bcount--;
1104 		}
1105 	}
1106 
1107 	ARX_UNUSED(pos), ARX_UNUSED(FileSize);
1108 	arx_assert(pos <= FileSize);
1109 
1110 	ModeLight = LightMode::load(dll->ModeLight); // TODO save/load flags
1111 	ViewMode = ViewModeFlags::load(dll->ViewMode); // TODO save/load flags
1112 	ViewMode &= ~VIEWMODE_WIRE;
1113 
1114 	free(dat);
1115 
1116 	PROGRESS_BAR_COUNT += 1.f;
1117 	LoadLevelScreen();
1118 
1119 	LOADEDD = 1;
1120 	FASTmse = 0;
1121 	USE_PLAYERCOLLISIONS = 1;
1122 
1123 	LogInfo << "Done loading level";
1124 
1125 	return 1;
1126 
1127 }
1128 
1129 void MCache_ClearAll();
1130 long FAST_RELEASE = 0;
1131 extern Entity * FlyingOverIO;
1132 extern unsigned long LAST_JUMP_ENDTIME;
1133 
1134 extern EERIE_3DOBJ * stone0;
1135 extern long stone0_count;
1136 extern EERIE_3DOBJ * stone1;
1137 extern long stone1_count;
1138 
1139 extern long JUST_RELOADED;
1140 
DanaeClearLevel(long flag)1141 void DanaeClearLevel(long flag)
1142 {
1143 	JUST_RELOADED = 0;
1144 	g_miniMap.reset();
1145 
1146 	FADEDIR = 0;
1147 	FADEDURATION = 0;
1148 	LAST_JUMP_ENDTIME = 0;
1149 	FAST_RELEASE = 1;
1150 	MCache_ClearAll();
1151 	g_miniMap.purgeTexContainer();
1152 	ARX_GAME_Reset(flag);
1153 	FlyingOverIO = NULL;
1154 
1155 	EERIE_PATHFINDER_Release();
1156 
1157 	InitBkg(ACTIVEBKG, MAX_BKGX, MAX_BKGZ, BKG_SIZX, BKG_SIZZ);
1158 	RemoveAllBackgroundActions();
1159 	ClearNodes();
1160 
1161 #ifdef BUILD_EDIT_LOADSAVE
1162 	if(mse != NULL) {
1163 		ReleaseMultiScene(mse);
1164 		mse = NULL;
1165 	}
1166 #endif
1167 
1168 	EERIE_LIGHT_GlobalInit();
1169 	ARX_FOGS_Clear();
1170 	TOTIOPDL = 0;
1171 
1172 	UnlinkAllLinkedObjects();
1173 
1174 	entities.clear();
1175 
1176 	DANAE_ReleaseAllDatasDynamic();
1177 	delete stone0, stone0 = NULL, stone0_count = 0;
1178 	delete stone1, stone1 = NULL, stone1_count = 0;
1179 
1180 	TextureContainer::DeleteAll(TextureContainer::Level);
1181 	g_miniMap.clearMarkerTexCont();
1182 
1183 	arxtime.init();
1184 
1185 	bGToggleCombatModeWithKey = false;
1186 	bGCroucheToggle = false;
1187 
1188 	for(size_t i = 0; i < MAX_DYNLIGHTS; i++) {
1189 		DynLight[i].exist = 0;
1190 	}
1191 
1192 	TREATZONE_Release();
1193 	TREATZONE_Clear();
1194 
1195 	FAST_RELEASE = 0;
1196 }
1197 
DanaeClearAll()1198 void DanaeClearAll()
1199 {
1200 	DanaeClearLevel();
1201 }
1202 
1203 //*************************************************************************************
1204 //*************************************************************************************
1205 
RestoreLastLoadedLightning()1206 void RestoreLastLoadedLightning()
1207 {
1208 	long pos = 0;
1209 	long bcount = CountBkgVertex();
1210 
1211 	if (LastLoadedLightningNb <= 0) return;
1212 
1213 	if (LastLoadedLightning == NULL) return;
1214 
1215 	if (bcount != LastLoadedLightningNb)
1216 	{
1217 		free(LastLoadedLightning);
1218 		LastLoadedLightning = NULL;
1219 		LastLoadedLightningNb = 0;
1220 		return;
1221 	}
1222 
1223 	EERIE_BKG_INFO * eg;
1224 
1225 	EERIE_BACKGROUND * eb = ACTIVEBKG;
1226 
1227 	bcount = LastLoadedLightningNb;
1228 
1229 	EERIEPOLY * ep;
1230 	long nbvert;
1231 
1232 	for (long j = 0; j < eb->Zsize; j++)
1233 		for (long i = 0; i < eb->Xsize; i++)
1234 		{
1235 			eg = (EERIE_BKG_INFO *)&eb->Backg[i+j*eb->Xsize];
1236 
1237 			for (long l = 0; l < eg->nbpoly; l++)
1238 			{
1239 				ep = &eg->polydata[l];
1240 
1241 				if (ep->type & POLY_QUAD) nbvert = 4;
1242 				else nbvert = 3;
1243 
1244 				for (long k = 0; k < nbvert; k++)
1245 				{
1246 					u32 dc = LastLoadedLightning[pos];
1247 					pos++;
1248 					dc = dc | 0xFF000000;
1249 					ep->tv[k].color = ep->v[k].color = dc;
1250 					ep->tv[k].specular = ep->v[k].specular = 0xFF000000;
1251 					bcount--;
1252 
1253 					if (bcount <= 0) goto plusloin;
1254 				}
1255 			}
1256 		}
1257 
1258 plusloin:
1259 	;
1260 	free(LastLoadedLightning);
1261 	LastLoadedLightning = NULL;
1262 	LastLoadedLightningNb = 0;
1263 
1264 	for (size_t i = 0; i < MAX_ACTIONS; i++)
1265 	{
1266 		if (actions[i].exist)
1267 		{
1268 			long modd = 0;
1269 
1270 			switch (actions[i].type)
1271 			{
1272 				case ACT_FIRE:
1273 					modd = 1;
1274 					break;
1275 				case ACT_FIRE2:
1276 					modd = 1;
1277 					break;
1278 				case ACT_FIREOFF:
1279 				case ACT_FIRE2OFF:
1280 					break;
1281 			}
1282 
1283 			if (modd) RecalcLightZone(actions[i].pos.x, actions[i].pos.z, (long)((float)(DynLight[actions[i].dl].fallend * ACTIVEBKG->Xmul) + 5.f));
1284 		}
1285 	}
1286 }
1287