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 "ai/Paths.h"
48 
49 #include <cstdlib>
50 #include <cstring>
51 #include <algorithm>
52 
53 #include <boost/foreach.hpp>
54 
55 #include "animation/Animation.h"
56 
57 #include "core/GameTime.h"
58 #include "core/Core.h"
59 
60 #include "game/Spells.h"
61 #include "game/NPC.h"
62 #include "game/Player.h"
63 #include "game/Damage.h"
64 #include "game/EntityManager.h"
65 #include "game/Equipment.h"
66 #include "game/Inventory.h"
67 
68 #include "graphics/GraphicsModes.h"
69 #include "graphics/GraphicsTypes.h"
70 #include "graphics/Math.h"
71 #include "graphics/Renderer.h"
72 #include "graphics/effects/SpellEffects.h"
73 #include "graphics/particle/ParticleEffects.h"
74 #include "graphics/data/Mesh.h"
75 #include "graphics/data/TextureContainer.h"
76 
77 #include "io/resource/ResourcePath.h"
78 
79 #include "math/Random.h"
80 
81 #include "platform/Platform.h"
82 
83 #include "physics/Box.h"
84 #include "physics/Collisions.h"
85 
86 #include "scene/GameSound.h"
87 #include "scene/Interactive.h"
88 #include "scene/Light.h"
89 
90 #include "script/Script.h"
91 
92 using std::min;
93 using std::max;
94 using std::string;
95 
96 extern long CHANGE_LEVEL_ICON;
97 extern float FrameDiff;
98 static bool IsPointInField(Vec3f * pos);
99 ARX_PATH ** ARXpaths = NULL;
100 ARX_USE_PATH USE_CINEMATICS_PATH;
101 MASTER_CAMERA_STRUCT MasterCamera;
102 long nbARXpaths = 0;
103 long USE_CINEMATICS_CAMERA = 0;
104 
ARX_PATH_ComputeBB(ARX_PATH * ap)105 void ARX_PATH_ComputeBB(ARX_PATH * ap) {
106 
107 	ap->bbmin = Vec3f::repeat(9999999999.f);
108 	ap->bbmax = Vec3f::repeat(-9999999999.f);
109 
110 	for(long i = 0; i < ap->nb_pathways; i++) {
111 		ap->bbmin.x = std::min(ap->bbmin.x, ap->pos.x + ap->pathways[i].rpos.x);
112 		ap->bbmax.x = std::max(ap->bbmax.x, ap->pos.x + ap->pathways[i].rpos.x);
113 		ap->bbmin.z = std::min(ap->bbmin.z, ap->pos.z + ap->pathways[i].rpos.z);
114 		ap->bbmax.z = std::max(ap->bbmax.z, ap->pos.z + ap->pathways[i].rpos.z);
115 	}
116 
117 	if(ap->height > 0) {
118 		ap->bbmin.y = ap->pos.y - ap->height;
119 		ap->bbmax.y = ap->pos.y;
120 	} else {
121 		ap->bbmin.y = -99999999.f;
122 		ap->bbmax.y = 99999999.f;
123 	}
124 }
125 
ARX_PATH_ComputeAllBoundingBoxes()126 void ARX_PATH_ComputeAllBoundingBoxes()
127 {
128 	for (long i = 0; i < nbARXpaths; i++)
129 	{
130 		if (ARXpaths[i])
131 		{
132 			ARX_PATH_ComputeBB(ARXpaths[i]);
133 		}
134 	}
135 }
ARX_PATH_IsPosInZone(ARX_PATH * ap,float x,float y,float z)136 long ARX_PATH_IsPosInZone(ARX_PATH * ap, float x, float y, float z)
137 {
138 	if (x < ap->bbmin.x) return 0;
139 
140 	if (x > ap->bbmax.x) return 0;
141 
142 	if (z < ap->bbmin.z) return 0;
143 
144 	if (z > ap->bbmax.z) return 0;
145 
146 	if (y < ap->bbmin.y) return 0;
147 
148 	if (y > ap->bbmax.y) return 0;
149 
150 	int i, j, c = 0;
151 
152 	x -= ap->pos.x;
153 	z -= ap->pos.z;
154 
155 	ARX_PATHWAY * app = ap->pathways;
156 
157 	for (i = 0, j = ap->nb_pathways - 1; i < ap->nb_pathways; j = i++)
158 	{
159 		Vec3f * pi = &app[i].rpos;
160 		Vec3f * pj = &app[j].rpos;
161 
162 		if ((((pi->z <= z) && (z < pj->z)) ||
163 		        ((pj->z <= z) && (z < pi->z))) &&
164 		        (x < (pj->x - pi->x) *(z - pi->z) / (pj->z - pi->z) + pi->x))
165 			c = !c;
166 	}
167 
168 	return c;
169 }
ARX_PATH_CheckInZone(Entity * io)170 ARX_PATH * ARX_PATH_CheckInZone(Entity * io)
171 {
172 	if (ARXpaths)
173 	{
174 		Vec3f curpos;
175 		GetItemWorldPosition(io, &curpos);
176 
177 		for (long i = 0; i < nbARXpaths; i++)
178 		{
179 			if ((ARXpaths[i]) && (ARXpaths[i]->height != 0))
180 			{
181 				if (ARX_PATH_IsPosInZone(ARXpaths[i], curpos.x, curpos.y, curpos.z))
182 					return ARXpaths[i];
183 			}
184 		}
185 	}
186 
187 	return NULL;
188 }
ARX_PATH_CheckPlayerInZone()189 ARX_PATH * ARX_PATH_CheckPlayerInZone()
190 {
191 	if (ARXpaths)
192 		for (long i = 0; i < nbARXpaths; i++)
193 		{
194 			if ((ARXpaths[i]) && (ARXpaths[i]->height != 0))
195 			{
196 				if (ARX_PATH_IsPosInZone(ARXpaths[i], player.pos.x, player.pos.y + 160.f, player.pos.z))
197 					return ARXpaths[i];
198 			}
199 		}
200 
201 	return NULL;
202 }
203 long JUST_RELOADED = 0;
204 
ARX_PATH_UpdateAllZoneInOutInside()205 void ARX_PATH_UpdateAllZoneInOutInside() {
206 
207 	if(EDITMODE) {
208 		return;
209 	}
210 
211 	static size_t count = 1;
212 
213 	long f = clamp(static_cast<long>(FrameDiff), 10, 50);
214 
215 	if(count >= entities.size()) {
216 		count = 1;
217 	}
218 
219 	if (entities.size() > 1)
220 		for (long tt = 0; tt < f; tt++)
221 		{
222 			long i = count;
223 			Entity * io = entities[i];
224 
225 			if ((count < entities.size()) && (io)
226 			        && (io->ioflags & (IO_NPC | IO_ITEM))
227 			        && (io->show != SHOW_FLAG_MEGAHIDE)
228 			        && (io->show != SHOW_FLAG_DESTROYED)
229 
230 			   )
231 			{
232 				ARX_PATH * p = ARX_PATH_CheckInZone(io);
233 				ARX_PATH * op = io->inzone;
234 
235 				if ((op == NULL) && (p == NULL)) goto next; // Not in a zone
236 
237 				if(op == p) { // Stayed inside Zone OP
238 					if (io->show != io->inzone_show)
239 					{
240 						io->inzone_show = io->show;
241 						goto entering;
242 					}
243 				}
244 				else if ((op != NULL) && (p == NULL)) // Leaving Zone OP
245 				{
246 					SendIOScriptEvent(io, SM_LEAVEZONE, op->name);
247 
248 					if (!op->controled.empty())
249 					{
250 						long t = entities.getById(op->controled);
251 
252 						if (t >= 0)
253 						{
254 							string str = io->long_name() + ' ' + op->name;
255 							SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_LEAVE, str);
256 						}
257 					}
258 				}
259 				else if ((op == NULL) && (p != NULL)) // Entering Zone P
260 				{
261 					io->inzone_show = io->show;
262 				entering:
263 
264 					if(JUST_RELOADED && (p->name == "ingot_maker" || p->name == "mauld_user")) {
265 						ARX_DEAD_CODE(); // TODO remove JUST_RELOADED global
266 					} else {
267 						SendIOScriptEvent(io, SM_ENTERZONE, p->name);
268 
269 						if (!p->controled.empty())
270 						{
271 							long t = entities.getById(p->controled);
272 
273 							if (t >= 0)
274 							{
275 								string params = io->long_name() + ' ' + p->name;
276 								SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_ENTER, params);
277 							}
278 						}
279 					}
280 				}
281 				else
282 				{
283 					SendIOScriptEvent(io, SM_LEAVEZONE, op->name);
284 
285 					if (!op->controled.empty())
286 					{
287 						long t = entities.getById(op->controled);
288 
289 						if (t >= 0)
290 						{
291 							string str = io->long_name() + ' ' + op->name;
292 							SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_LEAVE, str);
293 						}
294 					}
295 
296 					io->inzone_show = io->show;
297 					SendIOScriptEvent(io, SM_ENTERZONE, p->name);
298 
299 					if (!p->controled.empty())
300 					{
301 						long t = entities.getById(p->controled);
302 
303 						if (t >= 0)
304 						{
305 							string str = io->long_name() + ' ' + p->name;
306 							SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_ENTER, str);
307 						}
308 					}
309 				}
310 
311 				io->inzone = p;
312 			}
313 
314 		next:
315 			count++;
316 
317 			if (count >= entities.size()) count = 1;
318 		}
319 
320 	// player check*************************************************
321 	if (entities.player())
322 	{
323 		ARX_PATH * p = ARX_PATH_CheckPlayerInZone();
324 		ARX_PATH * op = (ARX_PATH *)player.inzone;
325 
326 		if ((op == NULL) && (p == NULL)) goto suite; // Not in a zone
327 
328 		if (op == p) // Stayed inside Zone OP
329 		{
330 
331 		}
332 		else if ((op != NULL) && (p == NULL)) // Leaving Zone OP
333 		{
334 			SendIOScriptEvent(entities.player(), SM_LEAVEZONE, op->name);
335 			CHANGE_LEVEL_ICON = -1;
336 
337 			if (!op->controled.empty())
338 			{
339 				long t = entities.getById(op->controled);
340 
341 				if (t >= 0)
342 				{
343 					SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_LEAVE, "player " + op->name);
344 				}
345 			}
346 		}
347 		else if ((op == NULL) && (p != NULL)) // Entering Zone P
348 		{
349 			SendIOScriptEvent(entities.player(), SM_ENTERZONE, p->name);
350 
351 			if (p->flags & PATH_AMBIANCE && !p->ambiance.empty())
352 				ARX_SOUND_PlayZoneAmbiance(p->ambiance, ARX_SOUND_PLAY_LOOPED, p->amb_max_vol * ( 1.0f / 100 ));
353 
354 			if (p->flags & PATH_FARCLIP)
355 			{
356 				desired.flags |= GMOD_ZCLIP;
357 				desired.zclip = p->farclip;
358 			}
359 
360 			if (p->flags & PATH_REVERB)
361 			{
362 			}
363 
364 			if (p->flags & PATH_RGB)
365 			{
366 				desired.flags |= GMOD_DCOLOR;
367 				desired.depthcolor = p->rgb;
368 			}
369 
370 			if (!p->controled.empty())
371 			{
372 				long t = entities.getById(p->controled);
373 
374 				if (t >= 0)
375 				{
376 					SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_ENTER, "player " + p->name);
377 				}
378 			}
379 		}
380 		else
381 		{
382 
383 			if (!op->controled.empty())
384 			{
385 				long t = entities.getById(op->controled);
386 
387 				if (t >= 0)
388 				{
389 					SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_LEAVE, "player " + p->name);
390 				}
391 			}
392 
393 			if (!op->controled.empty())
394 			{
395 				long t = entities.getById(p->controled);
396 
397 				if (t >= 0)
398 				{
399 					SendIOScriptEvent(entities[t], SM_CONTROLLEDZONE_ENTER, "player " + p->name);
400 				}
401 			}
402 		}
403 
404 		player.inzone = p;
405 	}
406 
407 
408 suite:
409 	JUST_RELOADED = 0;
410 }
411 
ARX_PATH(const std::string & _name,const Vec3f & _pos)412 ARX_PATH::ARX_PATH(const std::string & _name, const Vec3f & _pos)
413 	: name(_name), initpos(_pos), pos(_pos) {
414 
415 	flags = 0;
416 	nb_pathways = 0;
417 	pathways = NULL;
418 	height = 0; // 0 NOT A ZONE
419 
420 	rgb = Color3f::black;
421 	farclip = 0.f;
422 	reverb = 0.f;
423 	amb_max_vol = 0.f;
424 	bbmin = Vec3f::ZERO;
425 	bbmax = Vec3f::ZERO;
426 
427 }
428 
ARX_PATH_ClearAllUsePath()429 void ARX_PATH_ClearAllUsePath() {
430 	BOOST_FOREACH(Entity * e, entities) {
431 		if(e && e->usepath) {
432 			free(e->usepath), e->usepath = NULL;
433 		}
434 	}
435 }
436 
ARX_PATH_ClearAllControled()437 void ARX_PATH_ClearAllControled() {
438 	for(long i = 0; i < nbARXpaths; i++) {
439 		if(ARXpaths[i]) {
440 			ARXpaths[i]->controled.clear();
441 		}
442 	}
443 }
444 
ARX_PATH_GetAddressByName(const string & name)445 ARX_PATH * ARX_PATH_GetAddressByName(const string & name) {
446 
447 	// TODO this is almost the same as ARX_PATHS_ExistName()
448 
449 	if(name.empty() || !ARXpaths) {
450 		return NULL;
451 	}
452 
453 	for(long i = 0; i < nbARXpaths; i++) {
454 		if(ARXpaths[i] && ARXpaths[i]->name == name) {
455 			return ARXpaths[i];
456 		}
457 	}
458 
459 	return NULL;
460 }
461 
ARX_PATH_ReleaseAllPath()462 void ARX_PATH_ReleaseAllPath() {
463 
464 	ARX_PATH_ClearAllUsePath();
465 
466 	for(long i = 0; i < nbARXpaths; i++) {
467 		if(ARXpaths[i]) {
468 			free(ARXpaths[i]->pathways), ARXpaths[i]->pathways = NULL;
469 			delete ARXpaths[i], ARXpaths[i] = NULL;
470 		}
471 	}
472 
473 	free(ARXpaths), ARXpaths = NULL;
474 	nbARXpaths = 0;
475 }
476 
ARX_PATHS_ExistName(const string & name)477 ARX_PATH * ARX_PATHS_ExistName(const string & name) {
478 
479 	if(!ARXpaths) {
480 		return NULL;
481 	}
482 
483 	for(long i = 0; i < nbARXpaths; i++) {
484 		if(ARXpaths[i]->name == name) {
485 			return ARXpaths[i];
486 		}
487 	}
488 
489 	return NULL;
490 }
491 
ARX_PATHS_Interpolate(ARX_USE_PATH * aup,Vec3f * pos)492 long ARX_PATHS_Interpolate(ARX_USE_PATH * aup, Vec3f * pos) {
493 
494 	ARX_PATH * ap = aup->path;
495 
496 	// compute Delta Time
497 	float tim = aup->_curtime - aup->_starttime;
498 
499 	if(tim < 0) {
500 		return -1;
501 	}
502 
503 	// set pos to startpos
504 	*pos = Vec3f::ZERO;
505 
506 	if(tim == 0) {
507 		return 0;
508 	}
509 
510 	// we start at reference waypoint 0  (time & rpos = 0 for this waypoint).
511 	long targetwaypoint = 1;
512 	aup->aupflags &= ~ARX_USEPATH_FLAG_FINISHED;
513 
514 	if(ap->pathways) {
515 		ap->pathways[0]._time = 0;
516 		ap->pathways[0].rpos = Vec3f::ZERO;
517 	} else {
518 		return -1;
519 	}
520 
521 	// While we have time left, iterate
522 	while(tim > 0) {
523 
524 		// Path Ended
525 		if(targetwaypoint > ap->nb_pathways - 1) {
526 			*pos += ap->pos;
527 			aup->aupflags |= ARX_USEPATH_FLAG_FINISHED;
528 			return -2;
529 		}
530 
531 		// Manages a Bezier block
532 		if(ap->pathways[targetwaypoint - 1].flag == PATHWAY_BEZIER) {
533 
534 			targetwaypoint += 1;
535 			float delta = tim - ap->pathways[targetwaypoint]._time;
536 
537 			if(delta >= 0) {
538 
539 				tim = delta;
540 
541 				if(targetwaypoint < ap->nb_pathways) {
542 					*pos = ap->pathways[targetwaypoint].rpos;
543 				}
544 
545 				targetwaypoint += 1;
546 
547 			} else {
548 
549 				if(targetwaypoint < ap->nb_pathways) {
550 
551 					if(ap->pathways[targetwaypoint]._time == 0) {
552 						return targetwaypoint - 1;
553 					}
554 
555 					float rel = tim / ap->pathways[targetwaypoint]._time;
556 					float mull = square(rel);
557 
558 					*pos = ap->pos + ap->pathways[targetwaypoint].rpos * mull;
559 					*pos += ap->pathways[targetwaypoint - 1].rpos * (rel - mull);
560 					*pos += ap->pathways[targetwaypoint - 2].rpos * (1 - rel);
561 				}
562 
563 				return targetwaypoint - 1;
564 			}
565 
566 		} else {
567 
568 			// Manages a non-Bezier block
569 			float delta = tim - ap->pathways[targetwaypoint]._time;
570 
571 			if(delta >= 0) {
572 
573 				tim = delta;
574 
575 				if(targetwaypoint < ap->nb_pathways) {
576 					*pos = ap->pathways[targetwaypoint].rpos;
577 				}
578 
579 				targetwaypoint++;
580 
581 			} else {
582 
583 				if(targetwaypoint < ap->nb_pathways) {
584 
585 					if(ap->pathways[targetwaypoint]._time == 0) {
586 						return targetwaypoint - 1;
587 					}
588 
589 					float rel = tim / ap->pathways[targetwaypoint]._time;
590 
591 					*pos += (ap->pathways[targetwaypoint].rpos - *pos) * rel;
592 				}
593 
594 				*pos += ap->pos;
595 
596 				return targetwaypoint - 1;
597 			}
598 		}
599 	}
600 
601 	*pos += ap->pos;
602 
603 	return targetwaypoint;
604 }
605 
606 // THROWN OBJECTS MANAGEMENT
607 
608 ARX_THROWN_OBJECT Thrown[MAX_THROWN_OBJECTS];
609 long Thrown_Count = 0;
ARX_THROWN_OBJECT_Kill(long num)610 void ARX_THROWN_OBJECT_Kill(long num) {
611 	if(num >= 0 && size_t(num) < MAX_THROWN_OBJECTS) {
612 		Thrown[num].flags = 0;
613 		Thrown_Count--;
614 		delete Thrown[num].pRuban, Thrown[num].pRuban = NULL;
615 	}
616 }
617 
ARX_THROWN_OBJECT_KillAll()618 void ARX_THROWN_OBJECT_KillAll()
619 {
620 	for (size_t i = 0; i < MAX_THROWN_OBJECTS; i++)
621 	{
622 		ARX_THROWN_OBJECT_Kill(i);
623 	}
624 
625 	Thrown_Count = 0;
626 }
627 
ARX_THROWN_OBJECT_GetFree()628 long ARX_THROWN_OBJECT_GetFree()
629 {
630 	unsigned long latest_time = (unsigned long)(arxtime);
631 	long latest_obj = -1;
632 
633 	for (size_t i = 0; i < MAX_THROWN_OBJECTS; i++)
634 	{
635 		if (Thrown[i].flags & ATO_EXIST)
636 		{
637 			if (Thrown[i].creation_time < latest_time)
638 			{
639 				latest_obj = i;
640 				latest_time = Thrown[i].creation_time;
641 			}
642 		}
643 		else
644 		{
645 			return i;
646 		}
647 	}
648 
649 	if (latest_obj >= 0)
650 	{
651 		ARX_THROWN_OBJECT_Kill(latest_obj);
652 		return latest_obj;
653 	}
654 
655 	return -1;
656 }
657 
658 extern EERIE_3DOBJ * arrowobj;
659 
ARX_THROWN_OBJECT_Throw(long source,Vec3f * position,Vec3f * vect,Vec3f * upvect,EERIE_QUAT * quat,float velocity,float damages,float poison)660 long ARX_THROWN_OBJECT_Throw(long source, Vec3f * position, Vec3f * vect, Vec3f * upvect,
661                              EERIE_QUAT * quat, float velocity, float damages, float poison) {
662 
663 	long num = ARX_THROWN_OBJECT_GetFree();
664 
665 	if (num >= 0)
666 	{
667 
668 		Thrown[num].damages = damages;
669 		Thrown[num].position = *position;
670 		Thrown[num].initial_position = *position;
671 		Thrown[num].vector = *vect;
672 		Thrown[num].upvect = *upvect;
673 		Quat_Copy(&Thrown[num].quat, quat);
674 		Thrown[num].source = source;
675 		Thrown[num].obj = NULL;
676 		Thrown[num].velocity = velocity;
677 		Thrown[num].poisonous = poison;
678 		Thrown[num].pRuban = new CRuban();
679 		Thrown[num].pRuban->Create(num, 2000);
680 
681 		Thrown[num].obj = arrowobj;
682 
683 		if (Thrown[num].obj)
684 		{
685 			Thrown[num].creation_time = (unsigned long)(arxtime);
686 			Thrown[num].flags |= ATO_EXIST | ATO_MOVING;
687 			Thrown_Count++;
688 		}
689 
690 		if ((source == 0)
691 		        && (player.equiped[EQUIP_SLOT_WEAPON] != 0)
692 		        && (ValidIONum(player.equiped[EQUIP_SLOT_WEAPON])))
693 		{
694 			Entity * tio = entities[player.equiped[EQUIP_SLOT_WEAPON]];
695 
696 			if (tio->ioflags & IO_FIERY)
697 				Thrown[num].flags |= ATO_FIERY;
698 		}
699 
700 	}
701 
702 	return num;
703 }
704 
ARX_THROWN_ComputeDamages(long thrownum,long source,long target)705 float ARX_THROWN_ComputeDamages(long thrownum, long source, long target)
706 {
707 	float distance_limit = 1000.f;
708 	Entity * io_target = entities[target];
709 	Entity * io_source = entities[source];
710 
711 	SendIOScriptEvent(io_target, SM_AGGRESSION);
712 
713 	float distance = fdist(Thrown[thrownum].position, Thrown[thrownum].initial_position);
714 	float distance_modifier = 1.f;
715 
716 	if (distance < distance_limit * 2.f)
717 	{
718 		distance_modifier = distance / distance_limit;
719 
720 		if (distance_modifier < 0.5f)
721 			distance_modifier = 0.5f;
722 	}
723 	else distance_modifier = 2.f;
724 
725 	float attack, dmgs, backstab, critical, ac;
726 
727 	backstab = 1.f;
728 	critical = false;
729 
730 	if (source == 0)
731 	{
732 		attack = Thrown[thrownum].damages;
733 
734 		if(rnd() * 100 <= float(player.Full_Attribute_Dexterity - 9) * 2.f
735 		                   + float(player.Full_Skill_Projectile * 0.2f)) {
736 			if (SendIOScriptEvent(io_source, SM_CRITICAL, "bow") != REFUSE)
737 				critical = true;
738 		}
739 
740 		dmgs = attack;
741 
742 		if (io_target->_npcdata->npcflags & NPCFLAG_BACKSTAB)
743 		{
744 			if (rnd() * 100.f <= player.Full_Skill_Stealth)
745 			{
746 				if (SendIOScriptEvent(io_source, SM_BACKSTAB, "bow") != REFUSE)
747 					backstab = 1.5f;
748 			}
749 		}
750 	}
751 	else
752 	{
753 		// TODO treat NPC !!!
754 
755 		ARX_DEAD_CODE();
756 		attack = 0;
757 		dmgs = 0;
758 
759 	}
760 
761 	float absorb;
762 
763 	if (target == 0)
764 	{
765 		ac = player.Full_armor_class;
766 		absorb = player.Full_Skill_Defense * .5f;
767 	}
768 	else
769 	{
770 		ac = ARX_INTERACTIVE_GetArmorClass(io_target);
771 		absorb = io_target->_npcdata->absorb;
772 	}
773 
774 	char wmat[64];
775 
776 	string _amat = "flesh";
777 	const string * amat = &_amat;
778 
779 	strcpy(wmat, "dagger");
780 
781 	if(!io_target->armormaterial.empty()) {
782 		amat = &io_target->armormaterial;
783 	}
784 
785 	if(io_target == entities.player()) {
786 		if(player.equiped[EQUIP_SLOT_ARMOR] > 0) {
787 			Entity * io = entities[player.equiped[EQUIP_SLOT_ARMOR]];
788 			if(io && !io->armormaterial.empty()) {
789 				amat = &io->armormaterial;
790 			}
791 		}
792 	}
793 
794 	float power;
795 	power = dmgs * ( 1.0f / 20 );
796 
797 	if (power > 1.f) power = 1.f;
798 
799 	power = power * 0.15f + 0.85f;
800 
801 	ARX_SOUND_PlayCollision(*amat, wmat, power, 1.f, &Thrown[thrownum].position, io_source);
802 
803 	dmgs *= backstab;
804 	dmgs -= dmgs * (absorb * ( 1.0f / 100 ));
805 
806 	float chance = 100.f - (ac - attack);
807 	float dice = rnd() * 100.f;
808 
809 	if(dice <= chance) {
810 		if (dmgs > 0.f)
811 		{
812 			if (critical)
813 				dmgs *= 1.5f;
814 
815 			dmgs *= distance_modifier;
816 			return dmgs;
817 		}
818 	}
819 
820 	return 0.f;
821 }
822 
CheckArrowPolyCollision(Vec3f * start,Vec3f * end)823 EERIEPOLY * CheckArrowPolyCollision(Vec3f * start, Vec3f * end) {
824 
825 	EERIE_TRI pol;
826 	pol.v[0] = *start;
827 	pol.v[2] = *end - Vec3f(2.f, 15.f, 2.f);
828 	pol.v[1] = *end;
829 
830 	long px = end->x * ACTIVEBKG->Xmul;
831 	long pz = end->z * ACTIVEBKG->Zmul;
832 
833 	long ix = std::max(px - 2, 0L);
834 	long ax = std::min(px + 2, ACTIVEBKG->Xsize - 1L);
835 	long iz = std::max(pz - 2, 0L);
836 	long az = std::min(pz + 2, ACTIVEBKG->Zsize - 1L);
837 
838 	for(long zz = iz; zz <= az; zz++) for(long xx = ix; xx <= ax; xx++) {
839 
840 		FAST_BKG_DATA * feg = &ACTIVEBKG->fastdata[xx][zz];
841 
842 		for(long k = 0; k < feg->nbpolyin; k++) {
843 
844 			EERIEPOLY * ep = feg->polyin[k];
845 
846 			if(ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)) {
847 				continue;
848 			}
849 
850 			EERIE_TRI pol2;
851 			pol2.v[0] = ep->v[0].p;
852 			pol2.v[1] = ep->v[1].p;
853 			pol2.v[2] = ep->v[2].p;
854 
855 			if(Triangles_Intersect(&pol2, &pol)) {
856 				return ep;
857 			}
858 
859 			if(ep->type & POLY_QUAD) {
860 				pol2.v[0] = ep->v[1].p;
861 				pol2.v[1] = ep->v[3].p;
862 				pol2.v[2] = ep->v[2].p;
863 				if(Triangles_Intersect(&pol2, &pol)) {
864 					return ep;
865 				}
866 			}
867 
868 		}
869 	}
870 
871 	return NULL;
872 }
873 
CheckExp(long i)874 void CheckExp(long i) {
875 
876 	if((Thrown[i].flags & ATO_FIERY) && !(Thrown[i].flags & ATO_UNDERWATER)) {
877 
878 		ARX_BOOMS_Add(&Thrown[i].position);
879 		LaunchFireballBoom(&Thrown[i].position, 10);
880 		DoSphericDamage(&Thrown[i].position, 4.f * 2, 50.f,
881 		                DAMAGE_AREA, DAMAGE_TYPE_FIRE | DAMAGE_TYPE_MAGICAL, 0);
882 		ARX_SOUND_PlaySFX(SND_SPELL_FIRE_HIT, &Thrown[i].position);
883 		ARX_NPC_SpawnAudibleSound(&Thrown[i].position, entities.player());
884 		long id = GetFreeDynLight();
885 
886 		if(id != -1 && FrameDiff > 0) {
887 			DynLight[id].exist = 1;
888 			DynLight[id].intensity = 3.9f;
889 			DynLight[id].fallstart = 400.f;
890 			DynLight[id].fallend   = 440.f;
891 			DynLight[id].rgb = Color3f(1.f - rnd() * .2f, .8f - rnd() * .2f, .6f - rnd() * .2f);
892 			DynLight[id].pos = Thrown[i].position;
893 			DynLight[id].ex_flaresize = 40.f;
894 			DynLight[id].duration = 1500;
895 		}
896 	}
897 }
898 
899 extern long FRAME_COUNT;
900 
ARX_THROWN_OBJECT_Manage(unsigned long time_offset)901 void ARX_THROWN_OBJECT_Manage(unsigned long time_offset)
902 {
903 	if (Thrown_Count <= 0) return;
904 
905 	GRenderer->SetRenderState(Renderer::DepthWrite, true);
906 	GRenderer->SetRenderState(Renderer::DepthTest, true);
907 
908 	for (size_t i = 0; i < MAX_THROWN_OBJECTS; i++)
909 	{
910 		if (Thrown[i].flags & ATO_EXIST)
911 		{
912 			// Is Object Visible & Near ?
913 			if(fartherThan(ACTIVECAM->pos, Thrown[i].position, ACTIVECAM->cdepth * fZFogEnd + 50.f)) {
914 				continue;
915 			}
916 
917 			long xx, yy;
918 			xx = (Thrown[i].position.x)*ACTIVEBKG->Xmul;
919 			yy = (Thrown[i].position.z)*ACTIVEBKG->Zmul;
920 
921 			if (xx < 0)
922 				continue;
923 
924 			if (xx >= ACTIVEBKG->Xsize)
925 				continue;
926 
927 			if (yy < 0)
928 				continue;
929 
930 			if (yy >= ACTIVEBKG->Zsize)
931 				continue;
932 
933 			FAST_BKG_DATA * feg = (FAST_BKG_DATA *)&ACTIVEBKG->fastdata[xx][yy];
934 
935 			if (!feg->treat)
936 				continue;
937 
938 			// Now render object !
939 			if (!Thrown[i].obj)
940 				continue;
941 
942 			EERIEMATRIX mat;
943 			MatrixFromQuat(&mat, &Thrown[i].quat);
944 			long ccount = FRAME_COUNT;
945 			FRAME_COUNT = 0;
946 			DrawEERIEInterMatrix(Thrown[i].obj, &mat, &Thrown[i].position, NULL);
947 
948 			if((Thrown[i].flags & ATO_FIERY) && (Thrown[i].flags & ATO_MOVING)
949 			   && !(Thrown[i].flags & ATO_UNDERWATER)) {
950 
951 				long id = GetFreeDynLight();
952 				if(id != -1 && FrameDiff > 0) {
953 					DynLight[id].exist = 1;
954 					DynLight[id].intensity = 1.f;
955 					DynLight[id].fallstart = 100.f;
956 					DynLight[id].fallend   = 240.f;
957 					DynLight[id].rgb = Color3f(1.f - rnd() * .2f, .8f - rnd() * .2f, .6f - rnd() * .2f);
958 					DynLight[id].pos = Thrown[i].position;
959 					DynLight[id].ex_flaresize = 40.f;
960 					DynLight[id].extras |= EXTRAS_FLARE;
961 					DynLight[id].duration = static_cast<long>(FrameDiff * 0.5f);
962 				}
963 
964 				float p = 3.f;
965 
966 				while (p > 0.f)
967 				{
968 					p -= 0.5f;
969 
970 					if (Thrown[i].obj)
971 					{
972 						Vec3f pos;
973 						long notok = 10;
974 						std::vector<EERIE_FACE>::iterator it;
975 
976 						while (notok-- > 0)
977 						{
978 							it = Random::getIterator(Thrown[i].obj->facelist);
979 							arx_assert(it != Thrown[i].obj->facelist.end());
980 
981 							if (it->facetype & POLY_HIDE) continue;
982 
983 							notok = -1;
984 						}
985 
986 						if (notok < 0)
987 						{
988 							pos = Thrown[i].obj->vertexlist3[it->vid[0]].v;
989 
990 							for(long nn = 0; nn < 2; nn++) {
991 
992 								if(rnd() >= 0.4f) {
993 									continue;
994 								}
995 
996 								PARTICLE_DEF * pd = createParticle();
997 								if(!pd) {
998 									break;
999 								}
1000 
1001 								pd->ov = pos;
1002 								pd->move = Vec3f(2.f - 4.f * rnd(), 2.f - 22.f * rnd(),
1003 								                 2.f - 4.f * rnd());
1004 								pd->siz = 7.f;
1005 								pd->tolive = Random::get(500, 1500);
1006 								pd->special = FIRE_TO_SMOKE | ROTATING | MODULATE_ROTATION;
1007 								pd->tc = fire2;
1008 								pd->fparam = 0.1f - rnd() * 0.2f;
1009 								pd->scale = Vec3f::repeat(-8.f);
1010 								pd->rgb = Color3f(0.71f, 0.43f, 0.29f);
1011 								pd->delay = nn * 180;
1012 							}
1013 
1014 						}
1015 
1016 					}
1017 				}
1018 			}
1019 
1020 			if (Thrown[i].pRuban)
1021 			{
1022 
1023 				Thrown[i].pRuban->Update();
1024 
1025 				Thrown[i].pRuban->Render();
1026 			}
1027 
1028 			FRAME_COUNT = ccount;
1029 			Vec3f original_pos;
1030 
1031 			if (Thrown[i].flags & ATO_MOVING)
1032 			{
1033 				long need_kill = 0;
1034 				float mod = (float)time_offset * Thrown[i].velocity;
1035 				original_pos = Thrown[i].position;
1036 				Thrown[i].position.x += Thrown[i].vector.x * mod;
1037 				float gmod = 1.f - Thrown[i].velocity;
1038 
1039 				if (gmod > 1.f) gmod = 1.f;
1040 				else if (gmod < 0.f) gmod = 0.f;
1041 
1042 				Thrown[i].position.y += Thrown[i].vector.y * mod + (time_offset * gmod);
1043 				Thrown[i].position.z += Thrown[i].vector.z * mod;
1044 
1045 				CheckForIgnition(&original_pos, 10.f, 0, 2);
1046 
1047 				Vec3f wpos = Thrown[i].position;
1048 				wpos.y += 20.f;
1049 				EERIEPOLY * ep = EEIsUnderWater(&wpos);
1050 
1051 				if (Thrown[i].flags & ATO_UNDERWATER)
1052 				{
1053 					if (ep == NULL)
1054 					{
1055 						Thrown[i].flags &= ~ATO_UNDERWATER;
1056 						ARX_SOUND_PlaySFX(SND_PLOUF, &Thrown[i].position);
1057 					}
1058 				}
1059 				else if (ep != NULL)
1060 				{
1061 					Thrown[i].flags |= ATO_UNDERWATER;
1062 					ARX_SOUND_PlaySFX(SND_PLOUF, &Thrown[i].position);
1063 				}
1064 
1065 				// Check for collision MUST be done after DRAWING !!!!
1066 				long nbact = Thrown[i].obj->actionlist.size();
1067 
1068 				for (long j = 0; j < nbact; j++)
1069 				{ // TODO iterator
1070 					float rad = -1;
1071 					rad = GetHitValue(Thrown[i].obj->actionlist[j].name);
1072 					rad *= .5f;
1073 
1074 					if (rad == -1) continue;
1075 
1076 					Vec3f * v0 = &Thrown[i].obj->vertexlist3[Thrown[i].obj->actionlist[j].idx].v;
1077 					Vec3f dest = original_pos + Thrown[i].vector * 95.f;
1078 					Vec3f orgn = original_pos - Thrown[i].vector * 25.f;
1079 					EERIEPOLY * ep = CheckArrowPolyCollision(&orgn, &dest);
1080 
1081 					if (ep)
1082 					{
1083 						ARX_PARTICLES_Spawn_Spark(v0, 14, 0);
1084 						CheckExp(i);
1085 
1086 						if (ValidIONum(Thrown[i].source))
1087 							ARX_NPC_SpawnAudibleSound(v0, entities[Thrown[i].source]);
1088 
1089 						Thrown[i].flags &= ~ATO_MOVING;
1090 						Thrown[i].velocity = 0.f;
1091 						char weapon_material[64] = "dagger";
1092 						string bkg_material = "earth";
1093 
1094 						if (ep &&  ep->tex && !ep->tex->m_texName.empty())
1095 							bkg_material = GetMaterialString(ep->tex->m_texName);
1096 
1097 						if (ValidIONum(Thrown[i].source))
1098 							ARX_SOUND_PlayCollision(weapon_material, bkg_material, 1.f, 1.f, v0,
1099 							                        entities[Thrown[i].source]);
1100 
1101 						Thrown[i].position = original_pos;
1102 						j = 200;
1103 
1104 					}
1105 					else if (IsPointInField(v0))
1106 					{
1107 						ARX_PARTICLES_Spawn_Spark(v0, 24, 0);
1108 						CheckExp(i);
1109 
1110 						if (ValidIONum(Thrown[i].source))
1111 							ARX_NPC_SpawnAudibleSound(v0, entities[Thrown[i].source]);
1112 
1113 						Thrown[i].flags &= ~ATO_MOVING;
1114 						Thrown[i].velocity = 0.f;
1115 						char weapon_material[64] = "dagger";
1116 						char bkg_material[64] = "earth";
1117 
1118 						if (ValidIONum(Thrown[i].source))
1119 							ARX_SOUND_PlayCollision(weapon_material, bkg_material, 1.f, 1.f, v0,
1120 							                        entities[Thrown[i].source]);
1121 
1122 						Thrown[i].position = original_pos;
1123 						j = 200;
1124 						need_kill = 1;
1125 					}
1126 					else
1127 						for (float precision = 0.5f; precision <= 6.f; precision += 0.5f)
1128 						{
1129 							EERIE_SPHERE sphere;
1130 							sphere.origin = *v0 + Thrown[i].vector * precision * 4.5f;
1131 							sphere.radius = rad + 3.f;
1132 
1133 							if (CheckEverythingInSphere(&sphere, Thrown[i].source, -1))
1134 							{
1135 								for (size_t jj = 0; jj < MAX_IN_SPHERE_Pos; jj++)
1136 								{
1137 
1138 									if ((ValidIONum(EVERYTHING_IN_SPHERE[jj])
1139 									        && (EVERYTHING_IN_SPHERE[jj] != Thrown[i].source)))
1140 									{
1141 
1142 										Entity * target = entities[EVERYTHING_IN_SPHERE[jj]];
1143 
1144 										if (target->ioflags & IO_NPC)
1145 										{
1146 											Vec3f pos;
1147 											Color color = Color::none;
1148 											long hitpoint = -1;
1149 											float curdist = 999999.f;
1150 
1151 											for (size_t ii = 0 ; ii < target->obj->facelist.size() ; ii++)
1152 											{
1153 												if (target->obj->facelist[ii].facetype & POLY_HIDE) continue;
1154 
1155 												short vid = target->obj->facelist[ii].vid[0];
1156 												float d = dist(sphere.origin, target->obj->vertexlist3[vid].v);
1157 
1158 												if (d < curdist)
1159 												{
1160 													hitpoint = target->obj->facelist[ii].vid[0];
1161 													curdist = d;
1162 												}
1163 											}
1164 
1165 											if (hitpoint >= 0)
1166 											{
1167 												color = target->_npcdata->blood_color;
1168 												pos = target->obj->vertexlist3[hitpoint].v;
1169 											}
1170 
1171 											if (Thrown[i].source == 0)
1172 											{
1173 												float damages = ARX_THROWN_ComputeDamages(i, Thrown[i].source,
1174 												                                          EVERYTHING_IN_SPHERE[jj]);
1175 
1176 												if (damages > 0.f)
1177 												{
1178 													arx_assert(hitpoint >= 0);
1179 
1180 													if (target->ioflags & IO_NPC)
1181 													{
1182 														target->_npcdata->SPLAT_TOT_NB = 0;
1183 														ARX_PARTICLES_Spawn_Blood2(original_pos, damages, color, target);
1184 													}
1185 
1186 													ARX_PARTICLES_Spawn_Blood2(pos, damages, color, target);
1187 													ARX_DAMAGES_DamageNPC(target, damages, Thrown[i].source, 0, &pos);
1188 
1189 													if (rnd() * 100.f > target->_npcdata->resist_poison)
1190 													{
1191 														target->_npcdata->poisonned += Thrown[i].poisonous;
1192 													}
1193 
1194 													CheckExp(i);
1195 												}
1196 												else
1197 												{
1198 													ARX_PARTICLES_Spawn_Spark(v0, 14, 0);
1199 													ARX_NPC_SpawnAudibleSound(v0, entities[Thrown[i].source]);
1200 												}
1201 											}
1202 										}
1203 										else // not NPC
1204 										{
1205 											if (target->ioflags & IO_FIX)
1206 											{
1207 												if (ValidIONum(Thrown[i].source))
1208 													ARX_DAMAGES_DamageFIX(target, 0.1f, Thrown[i].source, 0);
1209 											}
1210 
1211 											ARX_PARTICLES_Spawn_Spark(v0, 14, 0);
1212 
1213 											if (ValidIONum(Thrown[i].source))
1214 												ARX_NPC_SpawnAudibleSound(v0, entities[Thrown[i].source]);
1215 
1216 											CheckExp(i);
1217 										}
1218 
1219 										// Need to deal damages !
1220 										Thrown[i].flags &= ~ATO_MOVING;
1221 										Thrown[i].velocity = 0.f;
1222 										need_kill = 1;
1223 										precision = 500.f;
1224 										j = 200;
1225 									}
1226 								}
1227 							}
1228 						}
1229 				}
1230 
1231 				if (need_kill) ARX_THROWN_OBJECT_Kill(i);
1232 			}
1233 		}
1234 	}
1235 }
1236 
1237 // RUBAN
Create(int _iNumThrow,int _iDuration)1238 void CRuban::Create(int _iNumThrow, int _iDuration)
1239 {
1240 	iNumThrow = _iNumThrow;
1241 
1242 	key = 1;
1243 	duration = _iDuration;
1244 	currduration = 0;
1245 
1246 	nbrubandef = 0;
1247 
1248 	int nb = 2048;
1249 
1250 	while (nb--)
1251 	{
1252 		truban[nb].actif = 0;
1253 	}
1254 
1255 	float col = 0.1f + (rnd() * 0.1f);
1256 	float size = 2.f + (2.f * rnd());
1257 	int taille = Random::get(8, 16);
1258 	AddRubanDef(0, size, taille, col, col, col, 0.f, 0.f, 0.f);
1259 
1260 }
1261 
AddRubanDef(int origin,float size,int dec,float r,float g,float b,float r2,float g2,float b2)1262 void CRuban::AddRubanDef(int origin, float size, int dec, float r, float g, float b,
1263                          float r2, float g2, float b2) {
1264 
1265 	if (nbrubandef > 255) return;
1266 
1267 	trubandef[nbrubandef].first = -1;
1268 	trubandef[nbrubandef].origin = origin;
1269 	trubandef[nbrubandef].size = size;
1270 	trubandef[nbrubandef].dec = dec;
1271 	trubandef[nbrubandef].r = r;
1272 	trubandef[nbrubandef].g = g;
1273 	trubandef[nbrubandef].b = b;
1274 	trubandef[nbrubandef].r2 = r2;
1275 	trubandef[nbrubandef].g2 = g2;
1276 	trubandef[nbrubandef].b2 = b2;
1277 	nbrubandef++;
1278 }
1279 
GetFreeRuban()1280 int CRuban::GetFreeRuban()
1281 {
1282 	int nb = 2048;
1283 
1284 	while (nb--)
1285 	{
1286 		if (!truban[nb].actif) return nb;
1287 	}
1288 
1289 	return -1;
1290 }
1291 
AddRuban(int * f,int dec)1292 void CRuban::AddRuban(int * f, int dec) {
1293 
1294 	int num = GetFreeRuban();
1295 
1296 	if (num >= 0)
1297 	{
1298 		truban[num].actif = 1;
1299 
1300 		truban[num].pos = Thrown[iNumThrow].position;
1301 
1302 		if (*f < 0)
1303 		{
1304 			*f = num;
1305 			truban[num].next = -1;
1306 		}
1307 		else
1308 		{
1309 			truban[num].next = *f;
1310 			*f = num;
1311 		}
1312 
1313 		int nb = 0, oldnum = 0;
1314 
1315 		while (num != -1)
1316 		{
1317 			nb++;
1318 			oldnum = num;
1319 			num = truban[num].next;
1320 		}
1321 
1322 		if (nb > dec)
1323 		{
1324 
1325 			truban[oldnum].actif = 0;
1326 			num = *f;
1327 			nb -= 2;
1328 
1329 			while (nb--)
1330 			{
1331 				num = truban[num].next;
1332 			}
1333 
1334 			truban[num].next = -1;
1335 		}
1336 	}
1337 }
1338 
Update()1339 void CRuban::Update() {
1340 
1341 	int nb, num;
1342 
1343 	if (arxtime.is_paused()) return;
1344 
1345 	num = 0;
1346 	nb = nbrubandef;
1347 
1348 	while (nb--)
1349 	{
1350 		AddRuban(&trubandef[num].first, trubandef[num].dec);
1351 		num++;
1352 	}
1353 }
1354 
DrawRuban(int num,float size,int dec,float r,float g,float b,float r2,float g2,float b2)1355 void CRuban::DrawRuban(int num, float size, int dec, float r, float g, float b,
1356                        float r2, float g2, float b2) {
1357 
1358 	int numsuiv;
1359 
1360 	float dsize = size / (float)(dec + 1);
1361 	int r1 = ((int)(r * 255.f)) << 16;
1362 	int g1 = ((int)(g * 255.f)) << 16;
1363 	int b1 = ((int)(b * 255.f)) << 16;
1364 	int rr2 = ((int)(r2 * 255.f)) << 16;
1365 	int gg2 = ((int)(g2 * 255.f)) << 16;
1366 	int bb2 = ((int)(b2 * 255.f)) << 16;
1367 	int dr = (rr2 - r1) / dec;
1368 	int dg = (gg2 - g1) / dec;
1369 	int db = (bb2 - b1) / dec;
1370 
1371 	for (;;)
1372 	{
1373 		numsuiv = truban[num].next;
1374 
1375 		if ((num >= 0) && (numsuiv >= 0))
1376 		{
1377 			Draw3DLineTex2(truban[num].pos, truban[numsuiv].pos, size,
1378 			               Color(r1 >> 16, g1 >> 16, b1 >> 16, 0),
1379 			               Color((r1 + dr) >> 16, (g1 + dg) >> 16, (b1 + db) >> 16, 0));
1380 			r1 += dr;
1381 			g1 += dg;
1382 			b1 += db;
1383 			size -= dsize;
1384 		}
1385 		else
1386 		{
1387 			break;
1388 		}
1389 
1390 		num = numsuiv;
1391 	}
1392 }
1393 
Render()1394 float CRuban::Render()
1395 {
1396 	GRenderer->SetCulling(Renderer::CullNone);
1397 	GRenderer->SetRenderState(Renderer::AlphaBlending, true);
1398 	GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
1399 	GRenderer->ResetTexture(0);
1400 
1401 	for (int i = 0; i < nbrubandef; i++)
1402 	{
1403 		this->DrawRuban(trubandef[i].first,
1404 		                trubandef[i].size,
1405 		                trubandef[i].dec,
1406 		                trubandef[i].r, trubandef[i].g, trubandef[i].b,
1407 		                trubandef[i].r2, trubandef[i].g2, trubandef[i].b2);
1408 	}
1409 
1410 	GRenderer->SetRenderState(Renderer::AlphaBlending, false);
1411 	GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendZero);
1412 
1413 	return 0;
1414 }
1415 
1416 extern bool IsValidPos3(Vec3f * pos);
1417 
1418 static EERIEPOLY * LAST_COLLISION_POLY = NULL;
1419 extern long CUR_COLLISION_MATERIAL;
1420 
1421 float VELOCITY_THRESHOLD = 850.f;
1422 
ARX_ApplySpring(PHYSVERT * phys,long k,long l,float PHYSICS_constant,float PHYSICS_Damp)1423 void ARX_ApplySpring(PHYSVERT * phys, long k, long l, float PHYSICS_constant,
1424                      float PHYSICS_Damp) {
1425 
1426 	Vec3f deltaP, deltaV, springforce;
1427 	PHYSVERT * pv_k = &phys[k];
1428 	PHYSVERT * pv_l = &phys[l];
1429 	float Dterm, Hterm;
1430 
1431 	float restlength = dist(pv_k->initpos, pv_l->initpos);
1432 	// Computes Spring Magnitude
1433 	deltaP = pv_k->pos - pv_l->pos;
1434 	float dist = deltaP.length(); // Magnitude of delta
1435 	dist = std::max(dist, 0.000001f); //TODO workaround for division by zero
1436 	float divdist = 1.f / dist;
1437 	Hterm = (dist - restlength) * PHYSICS_constant;
1438 
1439 	deltaV = pv_k->velocity - pv_l->velocity; // Delta Velocity Vector
1440 	Dterm = dot(deltaV, deltaP) * PHYSICS_Damp * divdist; // Damping Term
1441 	Dterm = (-(Hterm + Dterm));
1442 	divdist *= Dterm;
1443 	springforce = deltaP * divdist; // Normalize Distance Vector & Calc Force
1444 
1445 	pv_k->force += springforce; // + force on particle 1
1446 
1447 	pv_l->force -= springforce; // - force on particle 2
1448 }
1449 
ComputeForces(PHYSVERT * phys,long nb)1450 void ComputeForces(PHYSVERT * phys, long nb) {
1451 
1452 	const Vec3f PHYSICS_Gravity(0.f, 65.f, 0.f);
1453 	const float PHYSICS_Damping = 0.5f;
1454 
1455 	float lastmass = 1.f;
1456 	float div = 1.f;
1457 
1458 	for(long k = 0; k < nb; k++) {
1459 
1460 		PHYSVERT * pv = &phys[k];
1461 
1462 		// Reset Force
1463 		pv->force = pv->inertia;
1464 
1465 		// Apply Gravity
1466 		if(pv->mass > 0.f) {
1467 
1468 			// need to be precomputed...
1469 			if(lastmass != pv->mass) {
1470 				div = 1.f / pv->mass;
1471 				lastmass = pv->mass;
1472 			}
1473 
1474 			pv->force += (PHYSICS_Gravity * div);
1475 		}
1476 
1477 		// Apply Damping
1478 		pv->force += pv->velocity * -PHYSICS_Damping;
1479 	}
1480 
1481 	for(int k = 0; k < nb; k++) {
1482 		// Now Resolves Spring System
1483 		for(long l = 0; l < nb; l++) {
1484 			if(l != k) {
1485 				ARX_ApplySpring(phys, l, k, 15.f, 0.99f);
1486 			}
1487 		}
1488 	}
1489 }
1490 
1491 bool ARX_INTERACTIVE_CheckFULLCollision(EERIE_3DOBJ * obj, long source);
1492 
1493 //! Calculate new Positions and Velocities given a deltatime
1494 //! @param DeltaTime that has passed since last iteration
RK4Integrate(EERIE_3DOBJ * obj,float DeltaTime)1495 void RK4Integrate(EERIE_3DOBJ * obj, float DeltaTime) {
1496 
1497 	PHYSVERT * source, * target, * accum1, * accum2, * accum3, * accum4;
1498 	float halfDeltaT, sixthDeltaT;
1499 	halfDeltaT = DeltaTime * .5f; // some time values i will need
1500 	sixthDeltaT = ( 1.0f / 6 );
1501 
1502 	PHYSVERT m_TempSys[5][32];
1503 
1504 	for(long jj = 0; jj < 4; jj++) {
1505 
1506 		arx_assert(size_t(obj->pbox->nb_physvert) <= ARRAY_SIZE(m_TempSys[jj + 1]));
1507 		memcpy(m_TempSys[jj + 1], obj->pbox->vert, sizeof(PHYSVERT) * obj->pbox->nb_physvert);
1508 
1509 		if(jj == 3) {
1510 			halfDeltaT = DeltaTime;
1511 		}
1512 
1513 		for(long kk = 0; kk < obj->pbox->nb_physvert; kk++) {
1514 
1515 			source = &obj->pbox->vert[kk];
1516 			accum1 = &m_TempSys[jj + 1][kk];
1517 			target = &m_TempSys[0][kk];
1518 
1519 			accum1->force = source->force * (source->mass * halfDeltaT);
1520 			accum1->velocity = source->velocity * halfDeltaT;
1521 
1522 			// determine the new velocity for the particle over 1/2 time
1523 			target->velocity = source->velocity + accum1->force;
1524 			target->mass = source->mass;
1525 
1526 			// set the new position
1527 			target->pos = source->pos + accum1->velocity;
1528 		}
1529 
1530 		ComputeForces(m_TempSys[0], obj->pbox->nb_physvert); // compute the new forces
1531 	}
1532 
1533 	for(long kk = 0; kk < obj->pbox->nb_physvert; kk++) {
1534 
1535 		source = &obj->pbox->vert[kk]; // current state of particle
1536 		target = &obj->pbox->vert[kk];
1537 		accum1 = &m_TempSys[1][kk];
1538 		accum2 = &m_TempSys[2][kk];
1539 		accum3 = &m_TempSys[3][kk];
1540 		accum4 = &m_TempSys[4][kk];
1541 
1542 		// determine the new velocity for the particle using rk4 formula
1543 		Vec3f dv = accum1->force + ((accum2->force + accum3->force) * 2.f) + accum4->force;
1544 		target->velocity = source->velocity + (dv * sixthDeltaT);
1545 		// determine the new position for the particle using rk4 formula
1546 		Vec3f dp = accum1->velocity + ((accum2->velocity + accum3->velocity) * 2.f)
1547 		           + accum4->velocity;
1548 		target->pos = source->pos + (dp * sixthDeltaT * 1.2f);
1549 	}
1550 
1551 }
1552 
IsPointInField(Vec3f * pos)1553 static bool IsPointInField(Vec3f * pos) {
1554 
1555 	for(size_t i = 0; i < MAX_SPELLS; i++) {
1556 
1557 		if(spells[i].exist && spells[i].type == SPELL_CREATE_FIELD) {
1558 
1559 			if(ValidIONum(spells[i].longinfo)) {
1560 
1561 				Entity * pfrm = entities[spells[i].longinfo];
1562 				EERIE_CYLINDER cyl;
1563 				cyl.height = -35.f;
1564 				cyl.radius = 35.f;
1565 				cyl.origin = *pos + Vec3f(0.f, 17.5f, 0.f);
1566 
1567 				if(CylinderPlatformCollide(&cyl, pfrm) != 0.f) {
1568 					return true;
1569 				}
1570 			}
1571 		}
1572 	}
1573 
1574 	return false;
1575 }
1576 
IsObjectInField(EERIE_3DOBJ * obj)1577 static bool IsObjectInField(EERIE_3DOBJ * obj) {
1578 
1579 	for(size_t i = 0; i < MAX_SPELLS; i++) {
1580 
1581 		if(spells[i].exist && spells[i].type == SPELL_CREATE_FIELD) {
1582 
1583 			if(ValidIONum(spells[i].longinfo)) {
1584 
1585 				Entity * pfrm = entities[spells[i].longinfo];
1586 				EERIE_CYLINDER cyl;
1587 				cyl.height = -35.f;
1588 				cyl.radius = 35.f;
1589 
1590 				for(long k = 0; k < obj->pbox->nb_physvert; k++) {
1591 					PHYSVERT * pv = &obj->pbox->vert[k];
1592 					cyl.origin = pv->pos + Vec3f(0.f, 17.5f, 0.f);
1593 					if(CylinderPlatformCollide(&cyl, pfrm) != 0.f) {
1594 						return true;
1595 					}
1596 				}
1597 			}
1598 		}
1599 	}
1600 
1601 	return false;
1602 }
1603 
IsObjectVertexCollidingPoly(EERIE_3DOBJ * obj,EERIEPOLY * ep,long k,long * validd)1604 static bool IsObjectVertexCollidingPoly(EERIE_3DOBJ * obj, EERIEPOLY * ep,
1605                                         long k, long * validd) {
1606 
1607 	Vec3f pol[3];
1608 	pol[0] = ep->v[0].p;
1609 	pol[1] = ep->v[1].p;
1610 	pol[2] = ep->v[2].p;
1611 
1612 	if(ep->type & POLY_QUAD) {
1613 
1614 		if(IsObjectVertexCollidingTriangle(obj, pol, k, validd)) {
1615 			return true;
1616 		}
1617 
1618 		pol[1] = ep->v[2].p;
1619 		pol[2] = ep->v[3].p;
1620 
1621 		if(IsObjectVertexCollidingTriangle(obj, pol, k, validd)) {
1622 			return true;
1623 		}
1624 
1625 		return false;
1626 	}
1627 
1628 	if(IsObjectVertexCollidingTriangle(obj, pol, k, validd)) {
1629 		return true;
1630 	}
1631 
1632 	return false;
1633 }
1634 
IsFULLObjectVertexInValidPosition(EERIE_3DOBJ * obj)1635 static bool IsFULLObjectVertexInValidPosition(EERIE_3DOBJ * obj) {
1636 
1637 	bool ret = true;
1638 	long px, pz;
1639 	float x = obj->pbox->vert[0].pos.x;
1640 	px = x * ACTIVEBKG->Xmul;
1641 	float z = obj->pbox->vert[0].pos.z;
1642 	pz = z * ACTIVEBKG->Zmul;
1643 	long ix, iz, ax, az;
1644 	long n;
1645 	n = obj->pbox->radius * ( 1.0f / 100 );
1646 	n = min(1L, n + 1);
1647 	ix = max(px - n, 0L);
1648 	ax = min(px + n, ACTIVEBKG->Xsize - 1L);
1649 	iz = max(pz - n, 0L);
1650 	az = min(pz + n, ACTIVEBKG->Zsize - 1L);
1651 	LAST_COLLISION_POLY = NULL;
1652 	EERIEPOLY * ep;
1653 	EERIE_BKG_INFO * eg;
1654 
1655 	float rad = obj->pbox->radius;
1656 
1657 	for (pz = iz; pz <= az; pz++)
1658 		for (px = ix; px <= ax; px++)
1659 		{
1660 			eg = &ACTIVEBKG->Backg[px+pz*ACTIVEBKG->Xsize];
1661 
1662 			for (long k = 0; k < eg->nbpoly; k++)
1663 			{
1664 
1665 				ep = &eg->polydata[k];
1666 
1667 				if ( (ep->area > 190.f)
1668 				    && (!(ep->type & (POLY_WATER)))
1669 				    && (!(ep->type & (POLY_TRANS)))
1670 				    && (!(ep->type & (POLY_NOCOL)))
1671 				)
1672 				{
1673 					if (fartherThan(ep->center, obj->pbox->vert[0].pos, rad + 75.f))
1674 						continue;
1675 
1676 					for (long kk = 0; kk < obj->pbox->nb_physvert; kk++)
1677 					{
1678 						float radd = 4.f;
1679 
1680 						if(!fartherThan(obj->pbox->vert[kk].pos, ep->center, radd)
1681 						   || !fartherThan(obj->pbox->vert[kk].pos, ep->v[0].p, radd)
1682 						   || !fartherThan(obj->pbox->vert[kk].pos, ep->v[1].p, radd)
1683 						   || !fartherThan(obj->pbox->vert[kk].pos, ep->v[2].p, radd)
1684 						   || !fartherThan(obj->pbox->vert[kk].pos, (ep->v[0].p + ep->v[1].p) * .5f, radd)
1685 						   || !fartherThan(obj->pbox->vert[kk].pos, (ep->v[2].p + ep->v[1].p) * .5f, radd)
1686 						   || !fartherThan(obj->pbox->vert[kk].pos, (ep->v[0].p + ep->v[2].p) * .5f, radd)) {
1687 
1688 							LAST_COLLISION_POLY = ep;
1689 
1690 							if (ep->type & POLY_METAL) CUR_COLLISION_MATERIAL = MATERIAL_METAL;
1691 							else if (ep->type & POLY_WOOD) CUR_COLLISION_MATERIAL = MATERIAL_WOOD;
1692 							else if (ep->type & POLY_STONE) CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1693 							else if (ep->type & POLY_GRAVEL) CUR_COLLISION_MATERIAL = MATERIAL_GRAVEL;
1694 							else if (ep->type & POLY_WATER) CUR_COLLISION_MATERIAL = MATERIAL_WATER;
1695 							else if (ep->type & POLY_EARTH) CUR_COLLISION_MATERIAL = MATERIAL_EARTH;
1696 							else CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1697 
1698 							return false;
1699 						}
1700 
1701 						// Last addon
1702 						for (long kl = 1; kl < obj->pbox->nb_physvert; kl++)
1703 						{
1704 							if (kl != kk)
1705 							{
1706 								Vec3f pos = (obj->pbox->vert[kk].pos + obj->pbox->vert[kl].pos) * .5f;
1707 
1708 								if(!fartherThan(pos, ep->center, radd)
1709 								   || !fartherThan(pos, ep->v[0].p, radd)
1710 								   || !fartherThan(pos, ep->v[1].p, radd)
1711 								   || !fartherThan(pos, ep->v[2].p, radd)
1712 								   || !fartherThan(pos, (ep->v[0].p + ep->v[1].p) * .5f, radd)
1713 								   || !fartherThan(pos, (ep->v[2].p + ep->v[1].p) * .5f, radd)
1714 								   || !fartherThan(pos, (ep->v[0].p + ep->v[2].p) * .5f, radd)) {
1715 
1716 									LAST_COLLISION_POLY = ep;
1717 
1718 									if (ep->type & POLY_METAL) CUR_COLLISION_MATERIAL = MATERIAL_METAL;
1719 									else if (ep->type & POLY_WOOD) CUR_COLLISION_MATERIAL = MATERIAL_WOOD;
1720 									else if (ep->type & POLY_STONE) CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1721 									else if (ep->type & POLY_GRAVEL) CUR_COLLISION_MATERIAL = MATERIAL_GRAVEL;
1722 									else if (ep->type & POLY_WATER) CUR_COLLISION_MATERIAL = MATERIAL_WATER;
1723 									else if (ep->type & POLY_EARTH) CUR_COLLISION_MATERIAL = MATERIAL_EARTH;
1724 									else CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1725 
1726 									return false;
1727 								}
1728 							}
1729 						}
1730 					}
1731 
1732 
1733 					if (IsObjectVertexCollidingPoly(obj, ep, -1, NULL))
1734 					{
1735 
1736 						LAST_COLLISION_POLY = ep;
1737 
1738 						if (ep->type & POLY_METAL) CUR_COLLISION_MATERIAL = MATERIAL_METAL;
1739 						else if (ep->type & POLY_WOOD) CUR_COLLISION_MATERIAL = MATERIAL_WOOD;
1740 						else if (ep->type & POLY_STONE) CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1741 						else if (ep->type & POLY_GRAVEL) CUR_COLLISION_MATERIAL = MATERIAL_GRAVEL;
1742 						else if (ep->type & POLY_WATER) CUR_COLLISION_MATERIAL = MATERIAL_WATER;
1743 						else if (ep->type & POLY_EARTH) CUR_COLLISION_MATERIAL = MATERIAL_EARTH;
1744 						else CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1745 
1746 						return false;
1747 					}
1748 				}
1749 			}
1750 		}
1751 
1752 	return ret;
1753 }
1754 
ARX_EERIE_PHYSICS_BOX_Compute(EERIE_3DOBJ * obj,float framediff,long source)1755 static bool ARX_EERIE_PHYSICS_BOX_Compute(EERIE_3DOBJ * obj, float framediff, long source) {
1756 
1757 	PHYSVERT * pv;
1758 	Vec3f oldpos[32];
1759 	long COUNT = 0;
1760 	COUNT++;
1761 
1762 	for (long kk = 0; kk < obj->pbox->nb_physvert; kk++)
1763 	{
1764 		pv = &obj->pbox->vert[kk];
1765 		oldpos[kk] = pv->pos;
1766 		pv->inertia = Vec3f::ZERO;
1767 
1768 		if (pv->velocity.x > VELOCITY_THRESHOLD) pv->velocity.x = VELOCITY_THRESHOLD;
1769 		else if (pv->velocity.x < -VELOCITY_THRESHOLD) pv->velocity.x = -VELOCITY_THRESHOLD;
1770 
1771 		if (pv->velocity.y > VELOCITY_THRESHOLD) pv->velocity.y = VELOCITY_THRESHOLD;
1772 		else if (pv->velocity.y < -VELOCITY_THRESHOLD) pv->velocity.y = -VELOCITY_THRESHOLD;
1773 
1774 		if (pv->velocity.z > VELOCITY_THRESHOLD) pv->velocity.z = VELOCITY_THRESHOLD;
1775 		else if (pv->velocity.z < -VELOCITY_THRESHOLD) pv->velocity.z = -VELOCITY_THRESHOLD;
1776 	}
1777 
1778 	CUR_COLLISION_MATERIAL = MATERIAL_STONE;
1779 
1780 	RK4Integrate(obj, framediff);
1781 
1782 	EERIE_SPHERE sphere;
1783 	pv = &obj->pbox->vert[0];
1784 	sphere.origin = pv->pos;
1785 	sphere.radius = obj->pbox->radius;
1786 	long colidd = 0;
1787 
1788 	for (int kk = 0; kk < obj->pbox->nb_physvert; kk += 2)
1789 	{
1790 		pv = &obj->pbox->vert[kk];
1791 
1792 		if (!IsValidPos3(&pv->pos))
1793 		{
1794 			colidd = 1;
1795 			break;
1796 		}
1797 	}
1798 
1799 	if ((!IsFULLObjectVertexInValidPosition(obj))
1800 	    || ARX_INTERACTIVE_CheckFULLCollision(obj, source)
1801 	    || colidd
1802 	    || (IsObjectInField(obj))
1803 	)
1804 	{
1805 		colidd = 1;
1806 		float power = (EEfabs(obj->pbox->vert[0].velocity.x)
1807 		               + EEfabs(obj->pbox->vert[0].velocity.y)
1808 		               + EEfabs(obj->pbox->vert[0].velocity.z)) * .01f;
1809 
1810 
1811 		if (ValidIONum(source) && (entities[source]->ioflags & IO_BODY_CHUNK))
1812 		{
1813 		}
1814 		else
1815 			ARX_TEMPORARY_TrySound(0.4f + power);
1816 
1817 
1818 		if(!LAST_COLLISION_POLY) {
1819 
1820 			for(long k = 0; k < obj->pbox->nb_physvert; k++) {
1821 				pv = &obj->pbox->vert[k];
1822 
1823 				{
1824 					pv->velocity.x *= -0.3f;
1825 					pv->velocity.z *= -0.3f;
1826 					pv->velocity.y *= -0.4f;
1827 				}
1828 
1829 				pv->pos = oldpos[k];
1830 			}
1831 
1832 		} else {
1833 
1834 			for(long k = 0; k < obj->pbox->nb_physvert; k++) {
1835 
1836 				pv = &obj->pbox->vert[k];
1837 
1838 				float t = dot(LAST_COLLISION_POLY->norm, pv->velocity);
1839 				pv->velocity -= LAST_COLLISION_POLY->norm * (2.f * t);
1840 
1841 				pv->velocity.x *= 0.3f;
1842 				pv->velocity.z *= 0.3f;
1843 				pv->velocity.y *= 0.4f;
1844 
1845 				pv->pos = oldpos[k];
1846 			}
1847 		}
1848 	}
1849 
1850 	if (colidd)
1851 	{
1852 		obj->pbox->stopcount += 1;
1853 	}
1854 	else
1855 	{
1856 		obj->pbox->stopcount -= 2;
1857 
1858 		if (obj->pbox->stopcount < 0)
1859 			obj->pbox->stopcount = 0;
1860 	}
1861 
1862 	return true;
1863 }
1864 
ARX_PHYSICS_BOX_ApplyModel(EERIE_3DOBJ * obj,float framediff,float rubber,long source)1865 long ARX_PHYSICS_BOX_ApplyModel(EERIE_3DOBJ * obj, float framediff, float rubber, long source) {
1866 
1867 	VELOCITY_THRESHOLD = 400.f;
1868 	long ret = 0;
1869 
1870 	if ((!obj) || (!obj->pbox)) return ret;
1871 
1872 	if (obj->pbox->active == 2) return ret;
1873 
1874 	if (framediff == 0.f) return ret;
1875 
1876 	PHYSVERT * pv;
1877 
1878 	// Memorizes initpos
1879 	for(long k = 0; k < obj->pbox->nb_physvert; k++) {
1880 		pv = &obj->pbox->vert[k];
1881 		pv->temp = pv->pos;
1882 	}
1883 
1884 	float timing = obj->pbox->storedtiming + framediff * rubber * 0.0055f;
1885 	float t_threshold = 0.18f;
1886 
1887 	if (timing < t_threshold)
1888 	{
1889 		obj->pbox->storedtiming = timing;
1890 		return 1;
1891 	}
1892 	else
1893 	{
1894 
1895 		while(timing >= t_threshold) {
1896 
1897 			ComputeForces(obj->pbox->vert, obj->pbox->nb_physvert);
1898 
1899 			if (!ARX_EERIE_PHYSICS_BOX_Compute(obj, std::min(0.11f, timing * 10), source))
1900 				ret = 1;
1901 
1902 			timing -= t_threshold;
1903 		}
1904 
1905 		obj->pbox->storedtiming = timing;
1906 	}
1907 
1908 
1909 	if (obj->pbox->stopcount < 16) return ret;
1910 
1911 	obj->pbox->active = 2;
1912 	obj->pbox->stopcount = 0;
1913 
1914 	if (ValidIONum(source))
1915 	{
1916 		entities[source]->soundcount = 0;
1917 		entities[source]->soundtime = (unsigned long)(arxtime) + 2000;
1918 	}
1919 
1920 	return ret;
1921 }
1922 
ARX_PrepareBackgroundNRMLs()1923 void ARX_PrepareBackgroundNRMLs()
1924 {
1925 	long i, j, k, mai, maj, mii, mij;
1926 	long i2, j2, k2;
1927 	EERIE_BKG_INFO * eg;
1928 	EERIE_BKG_INFO * eg2;
1929 	EERIEPOLY * ep;
1930 	EERIEPOLY * ep2;
1931 	Vec3f nrml;
1932 	Vec3f cur_nrml;
1933 	float count;
1934 	long nbvert;
1935 	long nbvert2;
1936 
1937 	for (j = 0; j < ACTIVEBKG->Zsize; j++)
1938 		for (i = 0; i < ACTIVEBKG->Xsize; i++)
1939 		{
1940 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
1941 
1942 			for (long l = 0; l < eg->nbpoly; l++)
1943 			{
1944 				ep = &eg->polydata[l];
1945 
1946 				if (ep->type & POLY_QUAD) nbvert = 4;
1947 				else nbvert = 3;
1948 
1949 				for (k = 0; k < nbvert; k++)
1950 				{
1951 					float ttt = 1.f;
1952 
1953 					if(k == 3) {
1954 						nrml = ep->norm2;
1955 						count = 1.f;
1956 					} else if(k > 0 && nbvert > 3) {
1957 						nrml = (ep->norm + ep->norm2);
1958 						count = 2.f;
1959 						ttt = .5f;
1960 					} else {
1961 						nrml = ep->norm;
1962 						count = 1.f;
1963 					}
1964 
1965 					cur_nrml = nrml * ttt;
1966 
1967 					mai = i + 4;
1968 					maj = j + 4;
1969 					mii = i - 4;
1970 					mij = j - 4;
1971 
1972 					if (mij < 0) mij = 0;
1973 
1974 					if (mii < 0) mii = 0;
1975 
1976 					if (maj >= ACTIVEBKG->Zsize) maj = ACTIVEBKG->Zsize - 1;
1977 
1978 					if (mai >= ACTIVEBKG->Xsize) mai = ACTIVEBKG->Xsize - 1;
1979 
1980 					for (j2 = mij; j2 < maj; j2++)
1981 						for (i2 = mii; i2 < mai; i2++)
1982 						{
1983 							eg2 = &ACTIVEBKG->Backg[i2+j2*ACTIVEBKG->Xsize];
1984 
1985 							for (long kr = 0; kr < eg2->nbpoly; kr++)
1986 							{
1987 								ep2 = &eg2->polydata[kr];
1988 
1989 								if (ep2->type & POLY_QUAD) nbvert2 = 4;
1990 								else nbvert2 = 3;
1991 
1992 								if (ep != ep2)
1993 
1994 									for (k2 = 0; k2 < nbvert2; k2++)
1995 									{
1996 										if ((EEfabs(ep2->v[k2].p.x - ep->v[k].p.x) < 2.f)
1997 										        && (EEfabs(ep2->v[k2].p.y - ep->v[k].p.y) < 2.f)
1998 										        && (EEfabs(ep2->v[k2].p.z - ep->v[k].p.z) < 2.f))
1999 										{
2000 											if(k2 == 3) {
2001 
2002 												if(LittleAngularDiff(&cur_nrml, &ep2->norm2)) {
2003 													nrml += ep2->norm2;
2004 													count += 1.f;
2005 													nrml += cur_nrml;
2006 													count += 1.f;
2007 												}
2008 
2009 											} else if(k2 > 0 && nbvert2 > 3) {
2010 
2011 												Vec3f tnrml = (ep2->norm + ep2->norm2) * .5f;
2012 												if(LittleAngularDiff(&cur_nrml, &tnrml)) {
2013 													nrml += tnrml * 2.f;
2014 													count += 2.f;
2015 												}
2016 
2017 											} else {
2018 
2019 												if(LittleAngularDiff(&cur_nrml, &ep2->norm)) {
2020 													nrml += ep2->norm;
2021 													count += 1.f;
2022 												}
2023 											}
2024 										}
2025 									}
2026 							}
2027 						}
2028 
2029 					count = 1.f / count;
2030 					ep->tv[k].p = nrml * count;
2031 
2032 				}
2033 			}
2034 		}
2035 
2036 	for (j = 0; j < ACTIVEBKG->Zsize; j++)
2037 		for (i = 0; i < ACTIVEBKG->Xsize; i++)
2038 		{
2039 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
2040 
2041 			for (long l = 0; l < eg->nbpoly; l++)
2042 			{
2043 				ep = &eg->polydata[l];
2044 
2045 				if (ep->type & POLY_QUAD) nbvert = 4;
2046 				else nbvert = 3;
2047 
2048 				for(k = 0; k < nbvert; k++) {
2049 					ep->nrml[k] = ep->tv[k].p;
2050 				}
2051 
2052 				float d = 0.f;
2053 
2054 				for(long ii = 0; ii < nbvert; ii++) {
2055 					d = max(d, dist(ep->center, ep->v[ii].p));
2056 				}
2057 
2058 				ep->v[0].rhw = d;
2059 			}
2060 		}
2061 
2062 }
2063 
EERIE_PHYSICS_BOX_Launch_NOCOL(Entity * io,EERIE_3DOBJ * obj,Vec3f * pos,Vec3f * vect,long flags,Anglef * angle)2064 void EERIE_PHYSICS_BOX_Launch_NOCOL(Entity * io, EERIE_3DOBJ * obj, Vec3f * pos,
2065                                     Vec3f * vect, long flags, Anglef * angle) {
2066 	io->gameFlags |= GFLAG_NO_PHYS_IO_COL;
2067 	EERIE_PHYSICS_BOX_Launch(obj, pos, vect, flags, angle);
2068 }
2069