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 "game/Player.h"
48 
49 #include <stddef.h>
50 #include <cstdlib>
51 #include <cstring>
52 #include <algorithm>
53 #include <limits>
54 
55 #include "ai/PathFinderManager.h"
56 #include "ai/Paths.h"
57 
58 #include "core/Application.h"
59 #include "core/Localisation.h"
60 #include "core/GameTime.h"
61 #include "core/Core.h"
62 
63 #include "game/Damage.h"
64 #include "game/EntityManager.h"
65 #include "game/Equipment.h"
66 #include "game/Inventory.h"
67 #include "game/Item.h"
68 #include "game/Missile.h"
69 #include "game/NPC.h"
70 
71 #include "gui/Menu.h"
72 #include "gui/Text.h"
73 #include "gui/Speech.h"
74 #include "gui/Interface.h"
75 #include "gui/MiniMap.h"
76 
77 #include "graphics/BaseGraphicsTypes.h"
78 #include "graphics/Color.h"
79 #include "graphics/Draw.h"
80 #include "graphics/GraphicsModes.h"
81 #include "graphics/GraphicsTypes.h"
82 #include "graphics/Math.h"
83 #include "graphics/Renderer.h"
84 #include "graphics/Vertex.h"
85 #include "graphics/data/TextureContainer.h"
86 #include "graphics/effects/Fog.h"
87 #include "graphics/particle/ParticleManager.h"
88 #include "graphics/particle/ParticleEffects.h"
89 
90 #include "io/resource/ResourcePath.h"
91 #include "io/resource/PakReader.h"
92 #include "io/fs/Filesystem.h"
93 #include "io/log/Logger.h"
94 
95 #include "math/Angle.h"
96 #include "math/Random.h"
97 #include "math/Vector3.h"
98 
99 #include "physics/Collisions.h"
100 #include "physics/Attractors.h"
101 
102 #include "platform/Platform.h"
103 
104 #include "scene/ChangeLevel.h"
105 #include "scene/Scene.h"
106 #include "scene/GameSound.h"
107 #include "scene/Interactive.h"
108 #include "scene/Light.h"
109 #include "scene/Object.h"
110 
111 #include "script/Script.h"
112 
113 using std::vector;
114 
115 extern long		ARX_CONVERSATION;
116 extern long		HERO_SHOW_1ST;
117 extern long		REQUEST_SPEECH_SKIP;
118 extern long		CHANGE_LEVEL_ICON;
119 extern long		DONT_ERASE_PLAYER;
120 extern long		GLOBAL_MAGIC_MODE;
121 extern QUAKE_FX_STRUCT QuakeFx;
122 extern Entity * CURRENT_TORCH;
123 extern Entity * CAMERACONTROLLER;
124 extern ParticleManager * pParticleManager;
125 
126 extern unsigned long LAST_JUMP_ENDTIME;
127 
128 static const float WORLD_GRAVITY = 0.1f;
129 static const float JUMP_GRAVITY = 0.02f;
130 static const float STEP_DISTANCE = 120.f;
131 static const float TARGET_DT = 1000.f / 30.f;
132 
133 extern Vec3f PUSH_PLAYER_FORCE;
134 extern bool bBookHalo;
135 extern bool bGoldHalo;
136 extern float InventoryX;
137 extern float InventoryDir;
138 extern long COLLIDED_CLIMB_POLY;
139 extern long HERO_SHOW_1ST;
140 extern long STARTED_A_GAME;
141 extern bool TRUE_PLAYER_MOUSELOOK_ON;
142 extern unsigned long ulBookHaloTime;
143 extern unsigned long ulGoldHaloTime;
144 extern long cur_rf;
145 
146 static const float ARX_PLAYER_SKILL_STEALTH_MAX = 100.f;
147 
148 ARXCHARACTER player;
149 EERIE_3DOBJ * hero = NULL;
150 float currentdistance = 0.f;
151 float CURRENT_PLAYER_COLOR = 0;
152 float DeadCameraDistance = 0.f;
153 float PLAYER_ROTATION = 0;
154 
155 long USE_PLAYERCOLLISIONS = 1;
156 long BLOCK_PLAYER_CONTROLS = 0;
157 long WILLRETURNTOCOMBATMODE = 0;
158 long DeadTime = 0;
159 static unsigned long LastHungerSample = 0;
160 static unsigned long ROTATE_START = 0;
161 long sp_max = 0;
162 
163 // Player Anims FLAGS/Vars
164 ANIM_HANDLE * herowaitbook = NULL;
165 ANIM_HANDLE * herowait_2h = NULL;
166 
167 ARX_NECKLACE necklace;
168 
169 vector<KEYRING_SLOT> Keyring;
170 Entity * CURRENT_TORCH = NULL;
171 
172 static unsigned long FALLING_TIME = 0;
173 
174 vector<STRUCT_QUEST> PlayerQuest;
175 long FistParticles = 0;
176 void Manage_sp_max();
ARX_PLAYER_IsInFightMode()177 bool ARX_PLAYER_IsInFightMode() {
178 	if (player.Interface & INTER_COMBATMODE) return true;
179 
180 	if(entities.size() > 0 && entities.player()
181 	   && entities.player()->animlayer[1].cur_anim) {
182 
183 		ANIM_USE * ause1 = &entities.player()->animlayer[1];
184 		ANIM_HANDLE ** alist = entities.player()->anims;
185 
186 		if ((ause1->cur_anim	==	alist[ANIM_BARE_READY])
187 		        ||	(ause1->cur_anim	==	alist[ANIM_BARE_UNREADY])
188 		        ||	(ause1->cur_anim	==	alist[ANIM_DAGGER_READY_PART_1])
189 		        ||	(ause1->cur_anim	==	alist[ANIM_DAGGER_READY_PART_2])
190 		        ||	(ause1->cur_anim	==	alist[ANIM_DAGGER_UNREADY_PART_1])
191 		        ||	(ause1->cur_anim	==	alist[ANIM_DAGGER_UNREADY_PART_2])
192 		        ||	(ause1->cur_anim	==	alist[ANIM_1H_READY_PART_1])
193 		        ||	(ause1->cur_anim	==	alist[ANIM_1H_READY_PART_2])
194 		        ||	(ause1->cur_anim	==	alist[ANIM_1H_UNREADY_PART_1])
195 		        ||	(ause1->cur_anim	==	alist[ANIM_1H_UNREADY_PART_2])
196 		        ||	(ause1->cur_anim	==	alist[ANIM_2H_READY_PART_1])
197 		        ||	(ause1->cur_anim	==	alist[ANIM_2H_READY_PART_2])
198 		        ||	(ause1->cur_anim	==	alist[ANIM_2H_UNREADY_PART_1])
199 		        ||	(ause1->cur_anim	==	alist[ANIM_2H_UNREADY_PART_2])
200 		        ||	(ause1->cur_anim	==	alist[ANIM_MISSILE_READY_PART_1])
201 		        ||	(ause1->cur_anim	==	alist[ANIM_MISSILE_READY_PART_2])
202 		        ||	(ause1->cur_anim	==	alist[ANIM_MISSILE_UNREADY_PART_1])
203 		        ||	(ause1->cur_anim	==	alist[ANIM_MISSILE_UNREADY_PART_2])
204 		   )
205 			return true;
206 	}
207 
208 	return false;
209 }
210 //*************************************************************************************
211 //*************************************************************************************
212 // KEYRING FUNCTIONS
213 //-------------------------------------------------------------------------------------
214 
215 //*************************************************************************************
216 // void ARX_KEYRING_Init()
217 //-------------------------------------------------------------------------------------
218 // FUNCTION/RESULT:
219 //   Init/Reset player Keyring structures
220 //*************************************************************************************
ARX_KEYRING_Init()221 void ARX_KEYRING_Init() {
222 	Keyring.clear();
223 }
224 //*************************************************************************************
225 // void ARX_KEYRING_Add(char * key)
226 //-------------------------------------------------------------------------------------
227 // FUNCTION/RESULT:
228 //   Add a key to Keyring
229 //*************************************************************************************
ARX_KEYRING_Add(const std::string & key)230 void ARX_KEYRING_Add(const std::string & key) {
231 	Keyring.resize(Keyring.size() + 1);
232 	memset(&Keyring.back(), 0, sizeof(KEYRING_SLOT));
233 	strcpy(Keyring.back().slot, key.c_str());
234 }
235 
236 //*************************************************************************************
237 // void ARX_KEYRING_Combine(Entity * io)
238 //-------------------------------------------------------------------------------------
239 // FUNCTION/RESULT:
240 //   Sends COMBINE event to "io" for each keyring entry
241 //*************************************************************************************
ARX_KEYRING_Combine(Entity * io)242 void ARX_KEYRING_Combine(Entity * io) {
243 	for(size_t i = 0; i < Keyring.size(); i++) {
244 		if(SendIOScriptEvent(io, SM_COMBINE, Keyring[i].slot) == REFUSE) {
245 			return;
246 		}
247 	}
248 }
249 //-----------------------------------------------------------------------------
250 // KEYRING FUNCTIONS end
251 //******************************************************************************
252 
253 //-----------------------------------------------------------------------------
254 //*************************************************************************************
255 // void ARX_PLAYER_FrontPos(EERIE_3D * pos)
256 //-------------------------------------------------------------------------------------
257 // FUNCTION/RESULT:
258 //   Fills "pos" with player "front pos" for sound purpose
259 //*************************************************************************************
ARX_PLAYER_FrontPos(Vec3f * pos)260 void ARX_PLAYER_FrontPos(Vec3f * pos)
261 {
262 	pos->x = player.pos.x - EEsin(radians(MAKEANGLE(player.angle.b))) * 100.f;
263 	pos->y = player.pos.y + 100.f; //-100.f;
264 	pos->z = player.pos.z + EEcos(radians(MAKEANGLE(player.angle.b))) * 100.f;
265 }
266 
267 // FUNCTION/RESULT:
268 //   Reset all extra-rotation groups of player
ARX_PLAYER_RectifyPosition()269 void ARX_PLAYER_RectifyPosition() {
270 	Entity * io = entities.player();
271 	if(io && io->_npcdata->ex_rotate) {
272 		for(long n = 0; n < MAX_EXTRA_ROTATE; n++) {
273 			io->_npcdata->ex_rotate->group_rotate[n] = Anglef::ZERO;
274 		}
275 		io->_npcdata->ex_rotate->flags = 0;
276 	}
277 }
278 
279 //******************************************************************************
280 // PLAYER TORCH FUNCTIONS
281 //-----------------------------------------------------------------------------
ARX_PLAYER_KillTorch()282 void ARX_PLAYER_KillTorch() {
283 
284 	ARX_SOUND_PlaySFX(SND_TORCH_END);
285 	ARX_SOUND_Stop(SND_TORCH_LOOP);
286 
287 	giveToPlayer(CURRENT_TORCH);
288 
289 	CURRENT_TORCH = NULL;
290 	SHOW_TORCH = 0;
291 	DynLight[0].exist = 0;
292 }
293 
294 //-----------------------------------------------------------------------------
ARX_PLAYER_ClickedOnTorch(Entity * io)295 void ARX_PLAYER_ClickedOnTorch(Entity * io)
296 {
297 	if (io == NULL)
298 	{
299 		return;
300 	}
301 
302 	if (CURRENT_TORCH == NULL)
303 	{
304 		if (io->durability > 0)
305 		{
306 			if (io->ignition > 0)
307 			{
308 				if (ValidDynLight(io->ignit_light))
309 					DynLight[io->ignit_light].exist = 0;
310 
311 				io->ignit_light = -1;
312 
313 				if (io->ignit_sound != audio::INVALID_ID)
314 				{
315 					ARX_SOUND_Stop(io->ignit_sound);
316 					io->ignit_sound = audio::INVALID_ID;
317 				}
318 
319 				io->ignition = 0;
320 			}
321 
322 			SHOW_TORCH = 1;
323 			ARX_SOUND_PlaySFX(SND_TORCH_START);
324 			ARX_SOUND_PlaySFX(SND_TORCH_LOOP, NULL, 1.0F, ARX_SOUND_PLAY_LOOPED);
325 			RemoveFromAllInventories(io);
326 			CURRENT_TORCH = io;
327 			io->show = SHOW_FLAG_ON_PLAYER;
328 
329 			if (DRAGINTER == io)
330 			{
331 				DRAGINTER = NULL;
332 			}
333 		}
334 	}
335 	else if (CURRENT_TORCH == io)
336 	{
337 		ARX_PLAYER_KillTorch();
338 
339 	}
340 	else
341 	{
342 		ARX_PLAYER_KillTorch();
343 
344 		if (io->durability > 0)
345 		{
346 			if (io->ignition > 0)
347 			{
348 				if (io->ignit_light != -1)
349 				{
350 					DynLight[io->ignit_light].exist = 0;
351 					io->ignit_light = -1;
352 				}
353 
354 				if (io->ignit_sound != audio::INVALID_ID)
355 				{
356 					ARX_SOUND_Stop(io->ignit_sound);
357 					io->ignit_sound = audio::INVALID_ID;
358 				}
359 
360 				io->ignition = 0;
361 			}
362 
363 			SHOW_TORCH = 1;
364 			ARX_SOUND_PlaySFX(SND_TORCH_START);
365 			ARX_SOUND_PlaySFX(SND_TORCH_LOOP, NULL, 1.0F, ARX_SOUND_PLAY_LOOPED);
366 			RemoveFromAllInventories(io);
367 			CURRENT_TORCH = io;
368 			io->show = SHOW_FLAG_ON_PLAYER;
369 
370 			if (DRAGINTER == io)
371 			{
372 				DRAGINTER = NULL;
373 			}
374 		}
375 	}
376 }
377 
ARX_PLAYER_ManageTorch()378 static void ARX_PLAYER_ManageTorch() {
379 	if (CURRENT_TORCH)
380 	{
381 		CURRENT_TORCH->ignition = 0;
382 		CURRENT_TORCH->durability -= FrameDiff * ( 1.0f / 10000 );
383 
384 		if (CURRENT_TORCH->durability <= 0)
385 		{
386 
387 			ARX_SPEECH_ReleaseIOSpeech(CURRENT_TORCH);
388 			// Need To Kill timers
389 			ARX_SCRIPT_Timer_Clear_By_IO(CURRENT_TORCH);
390 			CURRENT_TORCH->show = SHOW_FLAG_KILLED;
391 			CURRENT_TORCH->gameFlags &= ~GFLAG_ISINTREATZONE;
392 			RemoveFromAllInventories(CURRENT_TORCH);
393 			ARX_INTERACTIVE_DestroyDynamicInfo(CURRENT_TORCH);
394 			ARX_SOUND_PlaySFX(SND_TORCH_END);
395 			ARX_SOUND_Stop(SND_TORCH_LOOP);
396 			ARX_INTERACTIVE_DestroyIO(CURRENT_TORCH);
397 			CURRENT_TORCH = NULL;
398 			SHOW_TORCH = 0;
399 			DynLight[0].exist = 0;
400 		}
401 	}
402 }
403 //-----------------------------------------------------------------------------
404 // PLAYER TORCH FUNCTIONS end
405 //******************************************************************************
406 
407 
408 //*************************************************************************************
409 // void ARX_PLAYER_Quest_Init()
410 //-------------------------------------------------------------------------------------
411 // FUNCTION/RESULT:
412 //   Init/Reset player Quest structures
413 //*************************************************************************************
ARX_PLAYER_Quest_Init()414 void ARX_PLAYER_Quest_Init() {
415 	PlayerQuest.clear();
416 	gui::updateQuestBook();
417 }
418 
419 //*************************************************************************************
420 // void ARX_Player_Rune_Add(unsigned long _ulRune)
421 //-------------------------------------------------------------------------------------
422 // FUNCTION/RESULT:
423 //   Add _ulRune to player runes
424 //*************************************************************************************
ARX_Player_Rune_Add(RuneFlag _ulRune)425 void ARX_Player_Rune_Add(RuneFlag _ulRune)
426 {
427 	int iNbSpells = 0;
428 	int iNbSpellsAfter = 0;
429 
430 	for (size_t i = 0; i < SPELL_COUNT; i++)
431 	{
432 		if (spellicons[i].bSecret == false)
433 		{
434 			long j = 0;
435 			bool bOk = true;
436 
437 			while ((j < 4) && (spellicons[i].symbols[j] != 255))
438 			{
439 				if (!(player.rune_flags & (RuneFlag)(1 << spellicons[i].symbols[j])))
440 				{
441 					bOk = false;
442 				}
443 
444 				j++;
445 			}
446 
447 			if (bOk)
448 			{
449 				iNbSpells ++;
450 			}
451 		}
452 	}
453 
454 	player.rune_flags |= _ulRune;
455 
456 	for (size_t i = 0; i < SPELL_COUNT; i++)
457 	{
458 		if (spellicons[i].bSecret == false)
459 		{
460 			long j = 0;
461 			bool bOk = true;
462 
463 			while ((j < 4) && (spellicons[i].symbols[j] != 255))
464 			{
465 				if (!(player.rune_flags & (RuneFlag)(1 << spellicons[i].symbols[j])))
466 				{
467 					bOk = false;
468 				}
469 
470 				j++;
471 			}
472 
473 			if (bOk)
474 			{
475 				iNbSpellsAfter ++;
476 			}
477 		}
478 	}
479 
480 	if(iNbSpellsAfter > iNbSpells) {
481 		MakeBookFX(Vec3f(DANAESIZX - INTERFACE_RATIO(35), DANAESIZY - INTERFACE_RATIO(148),
482 		                 0.00001f));
483 		bBookHalo = true;
484 		ulBookHaloTime = 0;
485 	}
486 }
487 
488 //*************************************************************************************
489 // void ARX_Player_Rune_Remove(unsigned long _ulRune
490 //-------------------------------------------------------------------------------------
491 // FUNCTION/RESULT:
492 //   Remove _ulRune from player runes
493 //*************************************************************************************
ARX_Player_Rune_Remove(RuneFlag _ulRune)494 void ARX_Player_Rune_Remove(RuneFlag _ulRune)
495 {
496 	player.rune_flags &= ~_ulRune;
497 }
498 
499 //*************************************************************************************
500 // void ARX_PLAYER_Quest_Add(char * quest)
501 //-------------------------------------------------------------------------------------
502 // FUNCTION/RESULT:
503 //   Add quest "quest" to player Questbook
504 //*************************************************************************************
ARX_PLAYER_Quest_Add(const std::string & quest,bool _bLoad)505 void ARX_PLAYER_Quest_Add(const std::string & quest, bool _bLoad) {
506 
507 	PlayerQuest.push_back(STRUCT_QUEST());
508 	PlayerQuest.back().ident = quest;
509 	bBookHalo = !_bLoad;
510 	ulBookHaloTime = 0;
511 
512 	gui::updateQuestBook();
513 }
514 
515 //*************************************************************************************
516 // void ARX_PLAYER_Remove_Invisibility()
517 //-------------------------------------------------------------------------------------
518 // FUNCTION/RESULT:
519 //   Removes player invisibility by killing Invisibility spells on him
520 //*************************************************************************************
ARX_PLAYER_Remove_Invisibility()521 void ARX_PLAYER_Remove_Invisibility() {
522 	for(size_t i = 0; i < MAX_SPELLS; i++) {
523 		if(spells[i].exist && spells[i].type == SPELL_INVISIBILITY && spells[i].caster == 0) {
524 			spells[i].tolive = 0;
525 		}
526 	}
527 }
528 
529 /* TODO use this table instead of the copied functions below!
530 static const size_t max_skills = 9;
531 static const size_t max_attributes = 4;
532 static const float skill_attribute_factors[max_skills][max_attributes] = {
533 	// Str   Men   Dex   Con
534 	{ 0.0f, 0.0f, 2.0f, 0.0f }, // Stealth
535 	{ 0.0f, 1.0f, 1.0f, 0.0f }, // Technical
536 	{ 0.0f, 2.0f, 0.0f, 0.0f }, // Intuition
537 	{ 0.0f, 2.0f, 0.0f, 0.0f }, // Ethereal link
538 	{ 0.5f, 1.5f, 0.5f, 0.0f }, // Object knowledge
539 	{ 0.0f, 2.0f, 0.0f, 0.0f }, // Casting
540 	{ 2.0f, 0.0f, 1.0f, 0.0f }, // Close combat
541 	{ 1.0f, 0.0f, 2.0f, 0.0f }, // Projectile
542 	{ 0.0f, 0.0f, 0.0f, 1.0f }, // Defense
543 };
544 */
545 
546 //*************************************************************************************
547 // FUNCTION/RESULT:
548 //   Returns player Stealth Skill level (Plain (type==0) or Modified (type==1))
549 //*************************************************************************************
ARX_PLAYER_Get_Skill_Stealth(long type)550 static float ARX_PLAYER_Get_Skill_Stealth(long type) {
551 	if(type == 0) {
552 		return player.Skill_Stealth + player.Attribute_Dexterity * 2.f;
553 	} else {
554 		return player.Skill_Stealth + player.Mod_Skill_Stealth
555 		       + player.Full_Attribute_Dexterity * 2.f;
556 	}
557 }
558 //*************************************************************************************
559 // FUNCTION/RESULT:
560 //   Returns player Mecanism Skill level (Plain (type==0) or Modified (type==1))
561 //*************************************************************************************
ARX_PLAYER_Get_Skill_Mecanism(long type)562 static float ARX_PLAYER_Get_Skill_Mecanism(long type) {
563 	if(type == 0) {
564 		return player.Skill_Mecanism + player.Attribute_Dexterity + player.Attribute_Mind;
565 	} else {
566 		return player.Skill_Mecanism + player.Mod_Skill_Mecanism
567 		       + player.Full_Attribute_Dexterity + player.Full_Attribute_Mind;
568 	}
569 }
570 //*************************************************************************************
571 // FUNCTION/RESULT:
572 //   Returns player Intuition Skill level (Plain (type==0) or Modified (type==1))
573 //*************************************************************************************
ARX_PLAYER_Get_Skill_Intuition(long type)574 static float ARX_PLAYER_Get_Skill_Intuition(long type) {
575 	if(type == 0) {
576 		return player.Skill_Intuition + player.Attribute_Mind * 2.f;
577 	} else {
578 		return player.Skill_Intuition + player.Mod_Skill_Intuition
579 		       + player.Full_Attribute_Mind * 2.f;
580 	}
581 }
582 //*************************************************************************************
583 // FUNCTION/RESULT:
584 //   Returns player Etheral Link Skill level (Plain (type==0) or Modified (type==1))
585 //*************************************************************************************
ARX_PLAYER_Get_Skill_Etheral_Link(long type)586 static float ARX_PLAYER_Get_Skill_Etheral_Link(long type) {
587 	if(type == 0) {
588 		return player.Skill_Etheral_Link + player.Attribute_Mind * 2.f;
589 	} else {
590 		return player.Skill_Etheral_Link + player.Mod_Skill_Etheral_Link
591 		       + player.Full_Attribute_Mind * 2.f;
592 	}
593 }
594 //*************************************************************************************
595 // FUNCTION/RESULT:
596 //   Returns player Object Knowledge Skill level (Plain (type==0) or Modified (type==1))
597 //*************************************************************************************
ARX_PLAYER_Get_Skill_Object_Knowledge(long type)598 static float ARX_PLAYER_Get_Skill_Object_Knowledge(long type) {
599 	if(type == 0) {
600 		return player.Skill_Object_Knowledge + player.Attribute_Mind * 1.5f
601 		       + player.Attribute_Dexterity * 0.5f + player.Attribute_Strength * 0.5f;
602 	} else {
603 		return player.Skill_Object_Knowledge + player.Mod_Skill_Object_Knowledge
604 		       + player.Full_Attribute_Mind * 1.5f + player.Full_Attribute_Dexterity * 0.5f
605 		       + player.Full_Attribute_Strength * 0.5f;
606 	}
607 }
608 //*************************************************************************************
609 // FUNCTION/RESULT:
610 //   Returns player Casting Skill level (Plain (type==0) or Modified (type==1))
611 //*************************************************************************************
ARX_PLAYER_Get_Skill_Casting(long type)612 static float ARX_PLAYER_Get_Skill_Casting(long type) {
613 	if(type == 0) {
614 		return player.Skill_Casting + player.Attribute_Mind * 2.f;
615 	} else {
616 		return player.Skill_Casting + player.Mod_Skill_Casting
617 		       + player.Full_Attribute_Mind * 2.f;
618 	}
619 }
620 //*************************************************************************************
621 // FUNCTION/RESULT:
622 //   Returns player Projectile Skill level (Plain (type==0) or Modified (type==1))
623 //*************************************************************************************
ARX_PLAYER_Get_Skill_Projectile(long type)624 static float ARX_PLAYER_Get_Skill_Projectile(long type) {
625 	if(type == 0) {
626 		return player.Skill_Projectile
627 		       + player.Attribute_Dexterity * 2.f + player.Attribute_Strength;
628 	} else {
629 		return player.Skill_Projectile + player.Mod_Skill_Projectile
630 		       + player.Full_Attribute_Dexterity * 2.f + player.Full_Attribute_Strength;
631 	}
632 }
633 //*************************************************************************************
634 // FUNCTION/RESULT:
635 //   Returns player Close Combat Skill level (Plain (type==0) or Modified (type==1))
636 //*************************************************************************************
ARX_PLAYER_Get_Skill_Close_Combat(long type)637 static float ARX_PLAYER_Get_Skill_Close_Combat(long type) {
638 	if(type == 0) {
639 		return player.Skill_Close_Combat
640 		       + player.Attribute_Dexterity + player.Attribute_Strength * 2.f;
641 	} else {
642 		return player.Skill_Close_Combat + player.Mod_Skill_Close_Combat
643 		       + player.Full_Attribute_Dexterity + player.Full_Attribute_Strength * 2.f;
644 	}
645 }
646 //*************************************************************************************
647 // FUNCTION/RESULT:
648 //   Returns player Defense Skill level (Plain (type==0) or Modified (type==1))
649 //*************************************************************************************
ARX_PLAYER_Get_Skill_Defense(long type)650 static float ARX_PLAYER_Get_Skill_Defense(long type) {
651 	if(type == 0) {
652 		return player.Skill_Defense + player.Attribute_Constitution * 3;
653 	} else {
654 		return player.Skill_Defense + player.Mod_Skill_Defense
655 		       + player.Full_Attribute_Constitution * 3;
656 	}
657 }
658 
659 //*************************************************************************************
660 // void ARX_PLAYER_ComputePlayerStats()
661 //-------------------------------------------------------------------------------------
662 // FUNCTION/RESULT:
663 //   Compute secondary attributes for player
664 //*************************************************************************************
ARX_PLAYER_ComputePlayerStats()665 static void ARX_PLAYER_ComputePlayerStats() {
666 
667 	player.maxlife = (float)player.Attribute_Constitution * (float)(player.level + 2);
668 	player.maxmana = (float)player.Attribute_Mind * (float)(player.level + 1);
669 	float t = ARX_PLAYER_Get_Skill_Defense(0);
670 
671 
672 	float fCalc = t * ( 1.0f / 10 ) - 1 ;
673 	player.armor_class = checked_range_cast<unsigned char>(fCalc);
674 
675 
676 	if (player.armor_class < 1) player.armor_class = 1;
677 
678 	player.resist_magic = (unsigned char)(float)(player.Attribute_Mind * 2.f
679 	                      * (1.f + (ARX_PLAYER_Get_Skill_Casting(0)) * ( 1.0f / 200 )));
680 
681 	fCalc = player.Attribute_Constitution * 2 + ((ARX_PLAYER_Get_Skill_Defense(1) * ( 1.0f / 4 )));
682 	player.resist_poison = checked_range_cast<unsigned char>(fCalc);
683 
684 
685 	player.damages = (player.Attribute_Strength - 10) * ( 1.0f / 2 );
686 
687 	if (player.damages < 1.f) player.damages = 1.f;
688 
689 	player.AimTime = 1500;
690 }
691 extern long cur_mr;
692 extern long SPECIAL_PNUX;
693 //*************************************************************************************
694 // void ARX_PLAYER_ComputePlayerFullStats()
695 //-------------------------------------------------------------------------------------
696 // FUNCTION/RESULT:
697 //   Compute FULL versions of player stats including Equiped Items
698 //   and spells, and any other effect altering them.
699 //*************************************************************************************
ARX_PLAYER_ComputePlayerFullStats()700 void ARX_PLAYER_ComputePlayerFullStats()
701 {
702 	ARX_PLAYER_ComputePlayerStats();
703 	player.Mod_Attribute_Strength = 0;
704 	player.Mod_Attribute_Dexterity = 0;
705 	player.Mod_Attribute_Constitution = 0;
706 	player.Mod_Attribute_Mind = 0;
707 	player.Mod_Skill_Stealth = 0;
708 	player.Mod_Skill_Mecanism = 0;
709 	player.Mod_Skill_Intuition = 0;
710 	player.Mod_Skill_Etheral_Link = 0;
711 	player.Mod_Skill_Object_Knowledge = 0;
712 	player.Mod_Skill_Casting = 0;
713 	player.Mod_Skill_Projectile = 0;
714 	player.Mod_Skill_Close_Combat = 0;
715 	player.Mod_Skill_Defense = 0;
716 	player.Mod_armor_class = 0;
717 	player.Mod_resist_magic = 0;
718 	player.Mod_resist_poison = 0;
719 	player.Mod_Critical_Hit = 0;
720 	player.Mod_damages = 0;
721 
722 	ARX_EQUIPMENT_IdentifyAll();
723 
724 	player.Full_Weapon_Type = ARX_EQUIPMENT_GetPlayerWeaponType();
725 
726 	Entity * io = entities.player();
727 	// Check for Equipment Modificators to Attributes
728 	player.Mod_Attribute_Strength = ARX_EQUIPMENT_Apply(
729 	                                    io, IO_EQUIPITEM_ELEMENT_STRENGTH, player.Attribute_Strength);
730 	player.Mod_Attribute_Dexterity = ARX_EQUIPMENT_Apply(
731 	                                     io, IO_EQUIPITEM_ELEMENT_DEXTERITY, player.Attribute_Dexterity);
732 	player.Mod_Attribute_Constitution = ARX_EQUIPMENT_Apply(
733 	                                        io, IO_EQUIPITEM_ELEMENT_CONSTITUTION, player.Attribute_Constitution);
734 	player.Mod_Attribute_Mind = ARX_EQUIPMENT_Apply(
735 	                                io, IO_EQUIPITEM_ELEMENT_MIND, player.Attribute_Mind);
736 	player.Mod_armor_class = ARX_EQUIPMENT_Apply(
737 	                             io, IO_EQUIPITEM_ELEMENT_Armor_Class, player.armor_class);
738 
739 	// Check for Equipment Modificators to Skills
740 	player.Mod_Skill_Stealth = ARX_EQUIPMENT_Apply(
741 	                               io, IO_EQUIPITEM_ELEMENT_Stealth, ARX_PLAYER_Get_Skill_Stealth(0));
742 	player.Mod_Skill_Mecanism = ARX_EQUIPMENT_Apply(
743 	                                io, IO_EQUIPITEM_ELEMENT_Mecanism, ARX_PLAYER_Get_Skill_Mecanism(0));
744 	player.Mod_Skill_Intuition = ARX_EQUIPMENT_Apply(
745 	                                 io, IO_EQUIPITEM_ELEMENT_Intuition, ARX_PLAYER_Get_Skill_Intuition(0));
746 	player.Mod_Skill_Etheral_Link = ARX_EQUIPMENT_Apply(
747 	                                    io, IO_EQUIPITEM_ELEMENT_Etheral_Link, ARX_PLAYER_Get_Skill_Etheral_Link(0));
748 	player.Mod_Skill_Object_Knowledge = ARX_EQUIPMENT_Apply(
749 	                                        io, IO_EQUIPITEM_ELEMENT_Object_Knowledge, ARX_PLAYER_Get_Skill_Object_Knowledge(0));
750 	player.Mod_Skill_Casting = ARX_EQUIPMENT_Apply(
751 	                               io, IO_EQUIPITEM_ELEMENT_Casting, ARX_PLAYER_Get_Skill_Casting(0));
752 	player.Mod_Skill_Projectile = ARX_EQUIPMENT_Apply(
753 	                                  io, IO_EQUIPITEM_ELEMENT_Projectile, ARX_PLAYER_Get_Skill_Projectile(0));
754 	player.Mod_Skill_Close_Combat = ARX_EQUIPMENT_Apply(
755 	                                    io, IO_EQUIPITEM_ELEMENT_Close_Combat, ARX_PLAYER_Get_Skill_Close_Combat(0));
756 	player.Mod_Skill_Defense = ARX_EQUIPMENT_Apply(
757 	                               io, IO_EQUIPITEM_ELEMENT_Defense, ARX_PLAYER_Get_Skill_Defense(0));
758 
759 	player.Mod_resist_magic = ARX_EQUIPMENT_Apply(
760 	                              io, IO_EQUIPITEM_ELEMENT_Resist_Magic, player.resist_magic);
761 	player.Mod_resist_poison = ARX_EQUIPMENT_Apply(
762 	                               io, IO_EQUIPITEM_ELEMENT_Resist_Poison, player.resist_poison);
763 	player.Mod_Critical_Hit = ARX_EQUIPMENT_Apply(
764 	                              io, IO_EQUIPITEM_ELEMENT_Critical_Hit, player.Critical_Hit);
765 	player.Mod_damages = ARX_EQUIPMENT_Apply(
766 	                         io, IO_EQUIPITEM_ELEMENT_Damages, 0);
767 
768 
769 	//CHECK OVERFLOW
770 	float fFullAimTime	= ARX_EQUIPMENT_Apply(io, IO_EQUIPITEM_ELEMENT_AimTime, 0);
771 	float fCalcHandicap	= (player.Full_Attribute_Dexterity - 10.f) * 20.f;
772 
773 	//CAST
774 	player.Full_AimTime = checked_range_cast<long>(fFullAimTime);
775 
776 	if (player.Full_AimTime <= 0) player.Full_AimTime = player.AimTime;
777 
778 	player.Full_AimTime -= checked_range_cast<long>(fCalcHandicap);
779 
780 
781 	if (player.Full_AimTime <= 1500) player.Full_AimTime = 1500;
782 
783 
784 
785 	/// PERCENTILE.....
786 	player.Mod_Attribute_Strength += ARX_EQUIPMENT_ApplyPercent(
787 	                                     io, IO_EQUIPITEM_ELEMENT_STRENGTH, player.Attribute_Strength + player.Mod_Attribute_Strength);
788 	player.Mod_Attribute_Dexterity += ARX_EQUIPMENT_ApplyPercent(
789 	                                      io, IO_EQUIPITEM_ELEMENT_DEXTERITY, player.Attribute_Dexterity + player.Mod_Attribute_Dexterity);
790 	player.Mod_Attribute_Constitution += ARX_EQUIPMENT_ApplyPercent(
791 	        io, IO_EQUIPITEM_ELEMENT_CONSTITUTION, player.Attribute_Constitution + player.Mod_Attribute_Constitution);
792 	player.Mod_Attribute_Mind += ARX_EQUIPMENT_ApplyPercent(
793 	                                 io, IO_EQUIPITEM_ELEMENT_MIND, player.Attribute_Mind + player.Mod_Attribute_Mind);
794 	player.Mod_armor_class += ARX_EQUIPMENT_ApplyPercent(
795 	                              io, IO_EQUIPITEM_ELEMENT_Armor_Class, player.armor_class + player.Mod_armor_class);
796 
797 	// Check for Equipment Modificators to Skills
798 	player.Mod_Skill_Stealth += ARX_EQUIPMENT_ApplyPercent(
799 	                                io, IO_EQUIPITEM_ELEMENT_Stealth, ARX_PLAYER_Get_Skill_Stealth(1));
800 	player.Mod_Skill_Mecanism += ARX_EQUIPMENT_ApplyPercent(
801 	                                 io, IO_EQUIPITEM_ELEMENT_Mecanism, ARX_PLAYER_Get_Skill_Mecanism(1));
802 	player.Mod_Skill_Intuition += ARX_EQUIPMENT_ApplyPercent(
803 	                                  io, IO_EQUIPITEM_ELEMENT_Intuition, ARX_PLAYER_Get_Skill_Intuition(1));
804 	player.Mod_Skill_Etheral_Link += ARX_EQUIPMENT_ApplyPercent(
805 	                                     io, IO_EQUIPITEM_ELEMENT_Etheral_Link, ARX_PLAYER_Get_Skill_Etheral_Link(1));
806 	player.Mod_Skill_Object_Knowledge += ARX_EQUIPMENT_ApplyPercent(
807 	        io, IO_EQUIPITEM_ELEMENT_Object_Knowledge, ARX_PLAYER_Get_Skill_Object_Knowledge(1));
808 	player.Mod_Skill_Casting += ARX_EQUIPMENT_ApplyPercent(
809 	                                io, IO_EQUIPITEM_ELEMENT_Casting, ARX_PLAYER_Get_Skill_Casting(1));
810 	player.Mod_Skill_Projectile += ARX_EQUIPMENT_ApplyPercent(
811 	                                   io, IO_EQUIPITEM_ELEMENT_Projectile, ARX_PLAYER_Get_Skill_Projectile(1));
812 	player.Mod_Skill_Close_Combat += ARX_EQUIPMENT_ApplyPercent(
813 	                                     io, IO_EQUIPITEM_ELEMENT_Close_Combat, ARX_PLAYER_Get_Skill_Close_Combat(1));
814 	player.Mod_Skill_Defense += ARX_EQUIPMENT_ApplyPercent(
815 	                                io, IO_EQUIPITEM_ELEMENT_Defense, ARX_PLAYER_Get_Skill_Defense(1));
816 
817 	player.Mod_resist_magic += ARX_EQUIPMENT_ApplyPercent(
818 	                               io, IO_EQUIPITEM_ELEMENT_Resist_Magic, player.resist_magic + player.Mod_resist_magic);
819 	player.Mod_resist_poison += ARX_EQUIPMENT_ApplyPercent(
820 	                                io, IO_EQUIPITEM_ELEMENT_Resist_Poison, player.resist_poison + player.Mod_resist_poison);
821 	player.Mod_Critical_Hit += ARX_EQUIPMENT_ApplyPercent(
822 	                               io, IO_EQUIPITEM_ELEMENT_Critical_Hit, player.Critical_Hit + player.Mod_Critical_Hit);
823 	player.Mod_damages += ARX_EQUIPMENT_ApplyPercent(
824 	                          io, IO_EQUIPITEM_ELEMENT_Damages, player.damages);
825 	//player.Full_AimTime=ARX_EQUIPMENT_ApplyPercent(
826 	//	io,IO_EQUIPITEM_ELEMENT_AimTime,0);
827 
828 
829 
830 	// Check for Spell Modificators
831 	if (entities.player())
832 		for (long i = 0; i < entities.player()->nb_spells_on; i++)
833 		{
834 			long n = entities.player()->spells_on[i];
835 
836 			if (spells[n].exist)
837 			{
838 				switch (spells[n].type)
839 				{
840 					case SPELL_ARMOR:
841 						player.Mod_armor_class += spells[n].caster_level;
842 						break;
843 					case SPELL_LOWER_ARMOR:
844 						player.Mod_armor_class -= spells[n].caster_level;
845 						break;
846 					case SPELL_CURSE:
847 						player.Mod_Attribute_Strength -= spells[n].caster_level;
848 						player.Mod_Attribute_Constitution -= spells[n].caster_level;
849 						player.Mod_Attribute_Dexterity -= spells[n].caster_level;
850 						player.Mod_Attribute_Mind -= spells[n].caster_level;
851 						break;
852 					case SPELL_BLESS:
853 						player.Mod_Attribute_Strength += spells[n].caster_level;
854 						player.Mod_Attribute_Dexterity += spells[n].caster_level;
855 						player.Mod_Attribute_Constitution += spells[n].caster_level;
856 						player.Mod_Attribute_Mind += spells[n].caster_level;
857 						break;
858 					default: break;
859 				}
860 			}
861 		}
862 
863 	if (cur_mr == 3)
864 	{
865 		player.Mod_Attribute_Strength += 1;
866 		player.Mod_Attribute_Mind += 10;
867 		player.Mod_Attribute_Constitution += 1;
868 		player.Mod_Attribute_Dexterity += 10;
869 		player.Mod_Skill_Stealth += 5;
870 		player.Mod_Skill_Mecanism += 5;
871 		player.Mod_Skill_Intuition += 100;
872 		player.Mod_Skill_Etheral_Link += 100;
873 		player.Mod_Skill_Object_Knowledge += 100;
874 		player.Mod_Skill_Casting += 5;
875 		player.Mod_Skill_Projectile += 5;
876 		player.Mod_Skill_Close_Combat += 5;
877 		player.Mod_Skill_Defense += 100;
878 		player.Mod_resist_magic += 100;
879 		player.Mod_resist_poison += 100;
880 		player.Mod_Critical_Hit += 5;
881 		player.Mod_damages += 2;
882 		player.Mod_armor_class += 100;
883 		player.Full_AimTime = 100;
884 	}
885 
886 	if (sp_max)
887 	{
888 		player.Mod_Attribute_Strength += 5;
889 		player.Mod_Attribute_Mind += 5;
890 		player.Mod_Attribute_Constitution += 5;
891 		player.Mod_Attribute_Dexterity += 5;
892 		player.Mod_Skill_Stealth += 50;
893 		player.Mod_Skill_Mecanism += 50;
894 		player.Mod_Skill_Intuition += 50;
895 		player.Mod_Skill_Etheral_Link += 50;
896 		player.Mod_Skill_Object_Knowledge += 50;
897 		player.Mod_Skill_Casting += 50;
898 		player.Mod_Skill_Projectile += 50;
899 		player.Mod_Skill_Close_Combat += 50;
900 		player.Mod_Skill_Defense += 50;
901 		player.Mod_resist_magic += 10;
902 		player.Mod_resist_poison += 10;
903 		player.Mod_Critical_Hit += 50;
904 		player.Mod_damages += 10;
905 		player.Mod_armor_class += 20;
906 		player.Full_AimTime = 100;
907 	}
908 
909 	if(SPECIAL_PNUX) {
910 		player.Mod_Attribute_Strength += Random::get(0, 5);
911 		player.Mod_Attribute_Mind += Random::get(0, 5);
912 		player.Mod_Attribute_Constitution += Random::get(0, 5);
913 		player.Mod_Attribute_Dexterity += Random::get(0, 5);
914 		player.Mod_Skill_Stealth += Random::get(0, 20);
915 		player.Mod_Skill_Mecanism += Random::get(0, 20);
916 		player.Mod_Skill_Intuition += Random::get(0, 20);
917 		player.Mod_Skill_Etheral_Link += Random::get(0, 20);
918 		player.Mod_Skill_Object_Knowledge += Random::get(0, 20);
919 		player.Mod_Skill_Casting += Random::get(0, 20);
920 		player.Mod_Skill_Projectile += Random::get(0, 20);
921 		player.Mod_Skill_Close_Combat += Random::get(0, 20);
922 		player.Mod_Skill_Defense += Random::get(0, 30);
923 		player.Mod_resist_magic += Random::get(0, 20);
924 		player.Mod_resist_poison += Random::get(0, 20);
925 		player.Mod_Critical_Hit += Random::get(0, 20);
926 		player.Mod_damages += Random::get(0, 20);
927 		player.Mod_armor_class += Random::get(0, 20);
928 	}
929 
930 	if (cur_rf == 3)
931 	{
932 		player.Mod_Attribute_Mind += 10;
933 		player.Mod_Skill_Casting += 100;
934 		player.Mod_Skill_Etheral_Link += 100;
935 		player.Mod_Skill_Object_Knowledge += 100;
936 		player.Mod_resist_magic += 20;
937 		player.Mod_resist_poison += 20;
938 		player.Mod_damages += 1;
939 		player.Mod_armor_class += 5;
940 	}
941 
942 	player.Full_armor_class = player.armor_class + player.Mod_armor_class;
943 
944 	if (player.Full_armor_class < 0) player.Full_armor_class = 0;
945 
946 	player.Full_Attribute_Strength = player.Attribute_Strength + player.Mod_Attribute_Strength;
947 
948 	if (player.Full_Attribute_Strength < 0) player.Full_Attribute_Strength = 0;
949 
950 	player.Full_Attribute_Mind = player.Attribute_Mind + player.Mod_Attribute_Mind;
951 
952 	if (player.Full_Attribute_Mind < 0) player.Full_Attribute_Mind = 0;
953 
954 	player.Full_Attribute_Constitution = player.Attribute_Constitution + player.Mod_Attribute_Constitution;
955 
956 	if (player.Full_Attribute_Constitution < 0) player.Full_Attribute_Constitution = 0;
957 
958 	player.Full_Attribute_Dexterity = player.Attribute_Dexterity + player.Mod_Attribute_Dexterity;
959 
960 	if (player.Full_Attribute_Dexterity < 0) player.Full_Attribute_Dexterity = 0;
961 
962 	player.Full_Skill_Stealth = ARX_PLAYER_Get_Skill_Stealth(1);
963 	player.Full_Skill_Mecanism = ARX_PLAYER_Get_Skill_Mecanism(1);
964 	player.Full_Skill_Intuition = ARX_PLAYER_Get_Skill_Intuition(1);
965 	player.Full_Skill_Etheral_Link = ARX_PLAYER_Get_Skill_Etheral_Link(1);
966 	player.Full_Skill_Object_Knowledge = ARX_PLAYER_Get_Skill_Object_Knowledge(1);
967 	player.Full_Skill_Casting = ARX_PLAYER_Get_Skill_Casting(1);
968 	player.Full_Skill_Projectile = ARX_PLAYER_Get_Skill_Projectile(1);
969 	player.Full_Skill_Close_Combat = ARX_PLAYER_Get_Skill_Close_Combat(1);
970 	player.Full_Skill_Defense = ARX_PLAYER_Get_Skill_Defense(1);
971 
972 	player.Full_resist_magic = player.resist_magic + player.Mod_resist_magic;
973 
974 	if (player.Full_resist_magic < 0) player.Full_resist_magic = 0;
975 
976 	player.Full_resist_poison = player.resist_poison + player.Mod_resist_poison;
977 
978 	if (player.Full_resist_poison < 0) player.Full_resist_poison = 0;
979 
980 	player.Full_Critical_Hit = player.Critical_Hit + player.Mod_Critical_Hit;
981 
982 	if (player.Full_Critical_Hit < 0) player.Full_Critical_Hit = 0;
983 
984 	player.Full_damages = player.damages + player.Mod_damages
985 	                      + player.Full_Skill_Close_Combat * ( 1.0f / 10 );
986 
987 	if (player.Full_damages < 1) player.Full_damages = 1;
988 
989 	player.Full_life = player.life;
990 	player.Full_maxlife = (float)player.Full_Attribute_Constitution * (float)(player.level + 2);
991 	player.life = std::min(player.life, player.Full_maxlife);
992 	player.Full_maxmana = (float)player.Full_Attribute_Mind * (float)(player.level + 1);
993 	player.mana = std::min(player.mana, player.Full_maxmana);
994 }
995 
996 //*************************************************************************************
997 // void ARX_PLAYER_MakeFreshHero()
998 //-------------------------------------------------------------------------------------
999 // FUNCTION/RESULT:
1000 //   Creates a Fresh hero
1001 //*************************************************************************************
ARX_PLAYER_MakeFreshHero()1002 void ARX_PLAYER_MakeFreshHero()
1003 {
1004 	player.Attribute_Strength = 6;
1005 	player.Attribute_Mind = 6;
1006 	player.Attribute_Dexterity = 6;
1007 	player.Attribute_Constitution = 6;
1008 
1009 	player.Old_Skill_Stealth			=	player.Skill_Stealth			= 0;
1010 	player.Old_Skill_Mecanism			=	player.Skill_Mecanism			= 0;
1011 	player.Old_Skill_Intuition			=	player.Skill_Intuition			= 0;
1012 	player.Old_Skill_Etheral_Link		=	player.Skill_Etheral_Link		= 0;
1013 	player.Old_Skill_Object_Knowledge	=	player.Skill_Object_Knowledge	= 0;
1014 	player.Old_Skill_Casting			=	player.Skill_Casting			= 0;
1015 	player.Old_Skill_Projectile			=	player.Skill_Projectile			= 0;
1016 	player.Old_Skill_Close_Combat		=	player.Skill_Close_Combat		= 0;
1017 	player.Old_Skill_Defense			=	player.Skill_Defense			= 0;
1018 
1019 	player.Attribute_Redistribute = 16;
1020 	player.Skill_Redistribute = 18;
1021 
1022 	player.level = 0;
1023 	player.xp = 0;
1024 	player.poison = 0.f;
1025 	player.hunger = 100.f;
1026 	player.skin = 0;
1027 	player.bag = 1;
1028 
1029 	ARX_PLAYER_ComputePlayerStats();
1030 	player.rune_flags = 0;
1031 
1032 	player.SpellToMemorize.bSpell = false;
1033 }
1034 char SKIN_MOD = 0;
1035 char QUICK_MOD = 0;
1036 
ARX_SPSound()1037 void ARX_SPSound() {
1038 	ARX_SOUND_PlayCinematic("kra_zoha_equip", false);
1039 }
1040 
ARX_PLAYER_MakeSpHero()1041 void ARX_PLAYER_MakeSpHero()
1042 {
1043 	ARX_SPSound();
1044 	player.Attribute_Strength = 12;
1045 	player.Attribute_Mind = 12;
1046 	player.Attribute_Dexterity = 12;
1047 	player.Attribute_Constitution = 12;
1048 
1049 	player.Old_Skill_Stealth			=	player.Skill_Stealth			= 5;
1050 	player.Old_Skill_Mecanism			=	player.Skill_Mecanism			= 5;
1051 	player.Old_Skill_Intuition			=	player.Skill_Intuition			= 5;
1052 	player.Old_Skill_Etheral_Link		=	player.Skill_Etheral_Link		= 5;
1053 	player.Old_Skill_Object_Knowledge	=	player.Skill_Object_Knowledge	= 5;
1054 	player.Old_Skill_Casting			=	player.Skill_Casting			= 5;
1055 	player.Old_Skill_Projectile			=	player.Skill_Projectile			= 5;
1056 	player.Old_Skill_Close_Combat		=	player.Skill_Close_Combat		= 5;
1057 	player.Old_Skill_Defense			=	player.Skill_Defense			= 5;
1058 
1059 	player.Attribute_Redistribute = 6;
1060 	player.Skill_Redistribute = 10;
1061 
1062 	player.level = 1;
1063 	player.xp = 0;
1064 	player.poison = 0.f;
1065 	player.hunger = 100.f;
1066 	player.skin = 4;
1067 
1068 	ARX_PLAYER_ComputePlayerStats();
1069 	player.life = player.maxlife;
1070 	player.mana = player.maxmana;
1071 
1072 	player.rune_flags = RuneFlags::all();
1073 	player.SpellToMemorize.bSpell = false;
1074 
1075 	SKIN_MOD = 0;
1076 	QUICK_MOD = 0;
1077 }
1078 //*************************************************************************************
1079 // void ARX_PLAYER_MakePowerfullHero()
1080 //-------------------------------------------------------------------------------------
1081 // FUNCTION/RESULT:
1082 //   Creates a POWERFULL hero
1083 //*************************************************************************************
ARX_PLAYER_MakePowerfullHero()1084 void ARX_PLAYER_MakePowerfullHero()
1085 {
1086 	player.Attribute_Strength = 18;
1087 	player.Attribute_Mind = 18;
1088 	player.Attribute_Dexterity = 18;
1089 	player.Attribute_Constitution = 18;
1090 
1091 	player.Old_Skill_Stealth			=	player.Skill_Stealth			= 82;
1092 	player.Old_Skill_Mecanism			=	player.Skill_Mecanism			= 82;
1093 	player.Old_Skill_Intuition			=	player.Skill_Intuition			= 82;
1094 	player.Old_Skill_Etheral_Link		=	player.Skill_Etheral_Link		= 82;
1095 	player.Old_Skill_Object_Knowledge	=	player.Skill_Object_Knowledge	= 82;
1096 	player.Old_Skill_Casting			=	player.Skill_Casting			= 82;
1097 	player.Old_Skill_Projectile			=	player.Skill_Projectile			= 82;
1098 	player.Old_Skill_Close_Combat		=	player.Skill_Close_Combat		= 82;
1099 	player.Old_Skill_Defense			=	player.Skill_Defense			= 82;
1100 
1101 	player.Attribute_Redistribute = 0;
1102 	player.Skill_Redistribute = 0;
1103 
1104 	player.level = 10;
1105 	player.xp = 178000;
1106 	player.poison = 0.f;
1107 	player.hunger = 100.f;
1108 	player.skin = 0;
1109 
1110 	ARX_PLAYER_ComputePlayerStats();
1111 	player.life = player.maxlife;
1112 	player.mana = player.maxmana;
1113 
1114 	player.rune_flags = RuneFlags::all();
1115 	player.SpellToMemorize.bSpell = false;
1116 }
1117 
1118 //*************************************************************************************
1119 // void ARX_PLAYER_MakeAverageHero()
1120 //-------------------------------------------------------------------------------------
1121 // FUNCTION/RESULT:
1122 //   Creates an Average hero
1123 //*************************************************************************************
ARX_PLAYER_MakeAverageHero()1124 void ARX_PLAYER_MakeAverageHero()
1125 {
1126 	ARX_PLAYER_MakeFreshHero();
1127 
1128 	player.Attribute_Strength		+= 4;
1129 	player.Attribute_Mind			+= 4;
1130 	player.Attribute_Dexterity		+= 4;
1131 	player.Attribute_Constitution	+= 4;
1132 
1133 	player.Skill_Stealth			+= 2;
1134 	player.Skill_Mecanism			+= 2;
1135 	player.Skill_Intuition			+= 2;
1136 	player.Skill_Etheral_Link		+= 2;
1137 	player.Skill_Object_Knowledge	+= 2;
1138 	player.Skill_Casting			+= 2;
1139 	player.Skill_Projectile			+= 2;
1140 	player.Skill_Close_Combat		+= 2;
1141 	player.Skill_Defense			+= 2;
1142 
1143 	player.Attribute_Redistribute = 0;
1144 	player.Skill_Redistribute = 0;
1145 
1146 	player.level = 0;
1147 	player.xp = 0;
1148 	player.hunger = 100.f;
1149 
1150 	ARX_PLAYER_ComputePlayerStats();
1151 }
1152 
1153 //*************************************************************************************
1154 // void ARX_PLAYER_QuickGeneration()
1155 //-------------------------------------------------------------------------------------
1156 // FUNCTION/RESULT:
1157 //   Quickgenerate a random hero
1158 //*************************************************************************************
ARX_PLAYER_QuickGeneration()1159 void ARX_PLAYER_QuickGeneration() {
1160 
1161 	char old_skin = player.skin;
1162 	ARX_PLAYER_MakeFreshHero();
1163 	player.skin = old_skin;
1164 
1165 	while (player.Attribute_Redistribute)
1166 	{
1167 		float rn = rnd();
1168 
1169 		if ((rn < 0.25f) && (player.Attribute_Strength < 18))
1170 		{
1171 			player.Attribute_Strength++;
1172 			player.Attribute_Redistribute--;
1173 		}
1174 		else if ((rn < 0.5f) && (player.Attribute_Mind < 18))
1175 		{
1176 			player.Attribute_Mind++;
1177 			player.Attribute_Redistribute--;
1178 		}
1179 		else if ((rn < 0.75f) && (player.Attribute_Dexterity < 18))
1180 		{
1181 			player.Attribute_Dexterity++;
1182 			player.Attribute_Redistribute--;
1183 		}
1184 		else if (player.Attribute_Constitution < 18)
1185 		{
1186 			player.Attribute_Constitution++;
1187 			player.Attribute_Redistribute--;
1188 		}
1189 	}
1190 
1191 	while (player.Skill_Redistribute)
1192 	{
1193 		float rn = rnd();
1194 
1195 		if ((rn < 0.1f) && (player.Skill_Stealth < 18))
1196 		{
1197 			player.Skill_Stealth++;
1198 			player.Skill_Redistribute--;
1199 		}
1200 		else if ((rn < 0.2f) && (player.Skill_Mecanism < 18))
1201 		{
1202 			player.Skill_Mecanism++;
1203 			player.Skill_Redistribute--;
1204 		}
1205 		else if ((rn < 0.3f) && (player.Skill_Intuition < 18))
1206 		{
1207 			player.Skill_Intuition++;
1208 			player.Skill_Redistribute--;
1209 		}
1210 		else if ((rn < 0.4f) && (player.Skill_Etheral_Link < 18))
1211 		{
1212 			player.Skill_Etheral_Link++;
1213 			player.Skill_Redistribute--;
1214 		}
1215 		else if ((rn < 0.5f) && (player.Skill_Object_Knowledge < 18))
1216 		{
1217 			player.Skill_Object_Knowledge++;
1218 			player.Skill_Redistribute--;
1219 		}
1220 		else if ((rn < 0.6f) && (player.Skill_Casting < 18))
1221 		{
1222 			player.Skill_Casting++;
1223 			player.Skill_Redistribute--;
1224 		}
1225 		else if ((rn < 0.7f) && (player.Skill_Projectile < 18))
1226 		{
1227 			player.Skill_Projectile++;
1228 			player.Skill_Redistribute--;
1229 		}
1230 		else if ((rn < 0.8f) && (player.Skill_Close_Combat < 18))
1231 		{
1232 			player.Skill_Close_Combat++;
1233 			player.Skill_Redistribute--;
1234 		}
1235 		else if ((rn < 0.9f) && (player.Skill_Defense < 18))
1236 		{
1237 			player.Skill_Defense++;
1238 			player.Skill_Redistribute--;
1239 		}
1240 	}
1241 
1242 	player.level = 0;
1243 	player.xp = 0;
1244 	player.hunger = 100.f;
1245 
1246 	ARX_PLAYER_ComputePlayerStats();
1247 }
1248 
1249 //*************************************************************************************
1250 // long GetXPforLevel(long level)
1251 //-------------------------------------------------------------------------------------
1252 // FUNCTION/RESULT:
1253 //   Returns necessary Experience for a given level
1254 //*************************************************************************************
GetXPforLevel(long level)1255 long GetXPforLevel(long level)
1256 {
1257 	const long XP_FOR_LEVEL[] = {
1258 		0,
1259 		2000,
1260 		4000,
1261 		6000,
1262 		10000,
1263 		16000,
1264 		26000,
1265 		42000,
1266 		68000,
1267 		110000,
1268 		178000,
1269 		300000,
1270 		450000,
1271 		600000,
1272 		750000
1273 	};
1274 
1275 	long xpNeeded;
1276 	if(level < (long)ARRAY_SIZE(XP_FOR_LEVEL))
1277 		xpNeeded = XP_FOR_LEVEL[level];
1278 	else
1279 		xpNeeded = level * 60000;
1280 	return xpNeeded;
1281 }
1282 
1283 //*************************************************************************************
1284 // void ARX_PLAYER_LEVEL_UP()
1285 //-------------------------------------------------------------------------------------
1286 // FUNCTION/RESULT:
1287 //   Manages Player Level Up event
1288 //*************************************************************************************
ARX_PLAYER_LEVEL_UP()1289 void ARX_PLAYER_LEVEL_UP()
1290 {
1291 	ARX_SOUND_PlayInterface(SND_PLAYER_LEVEL_UP);
1292 	player.level++;
1293 	player.Skill_Redistribute += 15;
1294 	player.Attribute_Redistribute++;
1295 	ARX_PLAYER_ComputePlayerStats();
1296 	player.life = player.maxlife;
1297 	player.mana = player.maxmana;
1298 	player.Old_Skill_Stealth			=	player.Skill_Stealth;
1299 	player.Old_Skill_Mecanism			=	player.Skill_Mecanism;
1300 	player.Old_Skill_Intuition			=	player.Skill_Intuition;
1301 	player.Old_Skill_Etheral_Link		=	player.Skill_Etheral_Link;
1302 	player.Old_Skill_Object_Knowledge	=	player.Skill_Object_Knowledge;
1303 	player.Old_Skill_Casting			=	player.Skill_Casting;
1304 	player.Old_Skill_Projectile			=	player.Skill_Projectile;
1305 	player.Old_Skill_Close_Combat		=	player.Skill_Close_Combat;
1306 	player.Old_Skill_Defense			=	player.Skill_Defense;
1307 	SendIOScriptEvent(entities.player(), SM_NULL, "", "level_up");
1308 }
1309 
1310 //*************************************************************************************
1311 // void ARX_PLAYER_Modify_XP(long val)
1312 //-------------------------------------------------------------------------------------
1313 // FUNCTION/RESULT:
1314 //   Modify player XP by adding "val" to it
1315 //*************************************************************************************
ARX_PLAYER_Modify_XP(long val)1316 void ARX_PLAYER_Modify_XP(long val) {
1317 
1318 	player.xp += val;
1319 
1320 	for (long i = player.level + 1; i < 11; i++) {
1321 		if(player.xp >= GetXPforLevel(i)) {
1322 			ARX_PLAYER_LEVEL_UP();
1323 		}
1324 	}
1325 }
1326 
1327 //*************************************************************************************
1328 // void ARX_PLAYER_Poison(float val)
1329 //-------------------------------------------------------------------------------------
1330 // FUNCTION/RESULT:
1331 //   Function to poison player by "val" poison level
1332 //*************************************************************************************
ARX_PLAYER_Poison(float val)1333 void ARX_PLAYER_Poison(float val)
1334 {
1335 	// Make a poison saving throw to see if player is affected
1336 	if (rnd() * 100.f > player.resist_poison)
1337 	{
1338 		player.poison += val;
1339 		ARX_SOUND_PlayInterface(SND_PLAYER_POISONED);
1340 	}
1341 }
1342 long PLAYER_PARALYSED = 0;
1343 
1344 // FUNCTION/RESULT:
1345 //   updates some player stats depending on time:
1346 //		.life/mana recovery
1347 //		.poison evolution
1348 //		.hunger check
1349 //		.invisibility
ARX_PLAYER_FrameCheck(float Framedelay)1350 void ARX_PLAYER_FrameCheck(float Framedelay)
1351 {
1352 	//	ARX_PLAYER_QuickGeneration();
1353 	if (Framedelay > 0)
1354 	{
1355 		UpdateIOInvisibility(entities.player());
1356 		// Natural LIFE recovery
1357 		float inc = 0.00008f * Framedelay * (player.Full_Attribute_Constitution + player.Full_Attribute_Strength * ( 1.0f / 2 ) + player.Full_Skill_Defense) * ( 1.0f / 50 );
1358 
1359 		if (player.life > 0.f)
1360 		{
1361 			float inc_hunger = 0.00008f * Framedelay * (player.Full_Attribute_Constitution + player.Full_Attribute_Strength * ( 1.0f / 2 )) * ( 1.0f / 50 );
1362 
1363 			// Check for player hungry sample playing
1364 			if (((player.hunger > 10.f) && (player.hunger - inc_hunger <= 10.f))
1365 			        || ((player.hunger < 10.f) && (float(arxtime) > LastHungerSample + 180000)))
1366 			{
1367 				LastHungerSample = (unsigned long)(arxtime);
1368 
1369 				if (!BLOCK_PLAYER_CONTROLS)
1370 				{
1371 					bool bOk = true;
1372 
1373 					for(size_t i = 0; i < MAX_ASPEECH; i++) {
1374 						if(aspeech[i].exist && (aspeech[i].io == entities.player())) {
1375 							bOk = false;
1376 						}
1377 					}
1378 
1379 					if (bOk)
1380 						ARX_SPEECH_AddSpeech(entities.player(), "player_off_hungry", ANIM_TALK_NEUTRAL, ARX_SPEECH_FLAG_NOTEXT);
1381 				}
1382 			}
1383 
1384 			player.hunger -= inc_hunger * .5f; //*.7f;
1385 
1386 			if (player.hunger < -10.f) player.hunger = -10.f;
1387 
1388 			if (!BLOCK_PLAYER_CONTROLS)
1389 			{
1390 				if (player.hunger < 0.f) player.life -= inc * ( 1.0f / 2 );
1391 				else player.life += inc;
1392 			}
1393 
1394 			// Natural MANA recovery
1395 			player.mana += 0.00008f * Framedelay * ((player.Full_Attribute_Mind + player.Full_Skill_Etheral_Link) * 10) * ( 1.0f / 100 ); //framedelay*( 1.0f / 1000 );
1396 
1397 			if (player.mana > player.Full_maxmana) player.mana = player.Full_maxmana;
1398 		}
1399 
1400 		//float pmaxlife=(float)player.Full_Attribute_Constitution*(float)(player.level+2);
1401 		if (player.life > player.Full_maxlife) player.life = player.Full_maxlife;
1402 
1403 		// Now Checks Poison Progression
1404 		if (!BLOCK_PLAYER_CONTROLS)
1405 			if (player.poison > 0.f)
1406 			{
1407 				float cp = player.poison;
1408 				cp *= ( 1.0f / 2 ) * Framedelay * ( 1.0f / 1000 ) * ( 1.0f / 2 );
1409 				float faster = 10.f - player.poison;
1410 
1411 				if (faster < 0.f) faster = 0.f;
1412 
1413 				if (rnd() * 100.f > player.resist_poison + faster)
1414 				{
1415 					float dmg = cp * ( 1.0f / 3 );
1416 
1417 					if (player.life - dmg <= 0.f) ARX_DAMAGES_DamagePlayer(dmg, DAMAGE_TYPE_POISON, -1);
1418 					else player.life -= dmg;
1419 
1420 					player.poison -= cp * ( 1.0f / 10 );
1421 				}
1422 				else player.poison -= cp;
1423 			}
1424 
1425 		if (player.poison < 0.1f) player.poison = 0.f;
1426 	}
1427 }
1428 TextureContainer * PLAYER_SKIN_TC = NULL;
1429 
ARX_PLAYER_Restore_Skin()1430 void ARX_PLAYER_Restore_Skin() {
1431 
1432 	res::path tx;
1433 	res::path tx2;
1434 	res::path tx3;
1435 	res::path tx4;
1436 
1437 	switch(player.skin) {
1438 		case 0:
1439 			tx  = "graph/obj3d/textures/npc_human_base_hero_head";
1440 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero_head";
1441 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero_head";
1442 			tx4 = "graph/obj3d/textures/npc_human_leather_hero_head";
1443 			break;
1444 		case 1:
1445 			tx  = "graph/obj3d/textures/npc_human_base_hero2_head";
1446 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero2_head";
1447 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero2_head";
1448 			tx4 = "graph/obj3d/textures/npc_human_leather_hero2_head";
1449 			break;
1450 		case 2:
1451 			tx  = "graph/obj3d/textures/npc_human_base_hero3_head";
1452 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero3_head";
1453 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero3_head";
1454 			tx4 = "graph/obj3d/textures/npc_human_leather_hero3_head";
1455 			break;
1456 		case 3:
1457 			tx  = "graph/obj3d/textures/npc_human_base_hero4_head";
1458 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero4_head";
1459 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero4_head";
1460 			tx4 = "graph/obj3d/textures/npc_human_leather_hero4_head";
1461 			break;
1462 		case 4:
1463 			tx  = "graph/obj3d/textures/npc_human_cm_hero_head";
1464 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero_head";
1465 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero_head";
1466 			tx4 = "graph/obj3d/textures/npc_human_leather_hero_head";
1467 			break;
1468 		case 5:
1469 			tx  = "graph/obj3d/textures/npc_human__base_hero_head";
1470 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero_head";
1471 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero_head";
1472 			tx4 = "graph/obj3d/textures/npc_human_leather_hero_head";
1473 			break;
1474 		case 6: //just in case
1475 			tx  = "graph/obj3d/textures/npc_human__base_hero_head";
1476 			tx2 = "graph/obj3d/textures/npc_human_chainmail_hero_head";
1477 			tx3 = "graph/obj3d/textures/npc_human_chainmail_mithril_hero_head";
1478 			tx4 = "graph/obj3d/textures/npc_human_leather_hero_head";
1479 			break;
1480 	}
1481 
1482 	TextureContainer * tmpTC;
1483 
1484 	// TODO maybe it would be better to replace the textures in the player object instead of replacing the texture data for all objects that use these textures
1485 
1486 	if (PLAYER_SKIN_TC && !tx.empty())
1487 		PLAYER_SKIN_TC->LoadFile(tx);
1488 
1489 	tmpTC = TextureContainer::Find("graph/obj3d/textures/npc_human_chainmail_hero_head");
1490 	if (tmpTC && !tx2.empty())
1491 		tmpTC->LoadFile(tx2);
1492 
1493 	tmpTC = TextureContainer::Find("graph/obj3d/textures/npc_human_chainmail_mithril_hero_head");
1494 	if (tmpTC && !tx3.empty())
1495 		tmpTC->LoadFile(tx3);
1496 
1497 	tmpTC = TextureContainer::Find("graph/obj3d/textures/npc_human_leather_hero_head");
1498 	if (tmpTC && !tx4.empty())
1499 		tmpTC->LoadFile(tx4);
1500 }
1501 
1502 //Load Mesh & anims for hero
ARX_PLAYER_LoadHeroAnimsAndMesh()1503 void ARX_PLAYER_LoadHeroAnimsAndMesh(){
1504 
1505 	const char OBJECT_HUMAN_BASE[] = "graph/obj3d/interactive/npc/human_base/human_base.teo";
1506 	hero = loadObject(OBJECT_HUMAN_BASE, false);
1507 	PLAYER_SKIN_TC = TextureContainer::Load("graph/obj3d/textures/npc_human_base_hero_head");
1508 
1509 	const char ANIM_WAIT_BOOK[] = "graph/obj3d/anims/npc/human_wait_book.tea";
1510 	herowaitbook = EERIE_ANIMMANAGER_Load(ANIM_WAIT_BOOK);
1511 	const char ANIM_WAIT_NORMAL[] = "graph/obj3d/anims/npc/human_normal_wait.tea";
1512 	EERIE_ANIMMANAGER_Load(ANIM_WAIT_NORMAL);
1513 	const char ANIM_WAIT_TWOHANDED[] = "graph/obj3d/anims/npc/human_wait_book_2handed.tea";
1514 	herowait_2h = EERIE_ANIMMANAGER_Load(ANIM_WAIT_TWOHANDED);
1515 
1516 	Entity * io = new Entity("graph/obj3d/interactive/player/player");
1517 	arx_assert_msg(io->index() == 0, "player entity didn't get index 0");
1518 	arx_assert(entities.player() == io);
1519 
1520 	io->obj = hero;
1521 
1522 	player.skin = 0;
1523 	ARX_PLAYER_Restore_Skin();
1524 
1525 	ARX_INTERACTIVE_Show_Hide_1st(entities.player(), 0);
1526 	ARX_INTERACTIVE_HideGore(entities.player(), 1);
1527 	io->ident = -1;
1528 
1529 	//todo free
1530 	io->_npcdata = new IO_NPCDATA;
1531 
1532 	io->ioflags = IO_NPC;
1533 	io->_npcdata->maxlife = io->_npcdata->life = 10.f;
1534 	io->_npcdata->vvpos = -99999.f;
1535 
1536 	//todo free
1537 	io->armormaterial = "leather";
1538 	loadScript(io->script, resources->getFile("graph/obj3d/interactive/player/player.asl"));
1539 
1540 	if ((EERIE_OBJECT_GetGroup(io->obj, "head") != -1)
1541 	        &&	(EERIE_OBJECT_GetGroup(io->obj, "neck") != -1)
1542 	        &&	(EERIE_OBJECT_GetGroup(io->obj, "chest") != -1)
1543 	        &&	(EERIE_OBJECT_GetGroup(io->obj, "belt") != -1))
1544 	{
1545 		io->_npcdata->ex_rotate = (EERIE_EXTRA_ROTATE *)malloc(sizeof(EERIE_EXTRA_ROTATE));
1546 
1547 		if(io->_npcdata->ex_rotate)
1548 		{
1549 			io->_npcdata->ex_rotate->group_number[0] = (short)EERIE_OBJECT_GetGroup(io->obj, "head");
1550 			io->_npcdata->ex_rotate->group_number[1] = (short)EERIE_OBJECT_GetGroup(io->obj, "neck");
1551 			io->_npcdata->ex_rotate->group_number[2] = (short)EERIE_OBJECT_GetGroup(io->obj, "chest");
1552 			io->_npcdata->ex_rotate->group_number[3] = (short)EERIE_OBJECT_GetGroup(io->obj, "belt");
1553 
1554 			for (long n = 0; n < MAX_EXTRA_ROTATE; n++)
1555 			{
1556 				io->_npcdata->ex_rotate->group_rotate[n] = Anglef::ZERO;
1557 			}
1558 
1559 			io->_npcdata->ex_rotate->flags = 0;
1560 		}
1561 	}
1562 
1563 	ARX_INTERACTIVE_RemoveGoreOnIO(entities.player());
1564 }
1565 float Falling_Height = 0;
ARX_PLAYER_StartFall()1566 void ARX_PLAYER_StartFall()
1567 {
1568 	FALLING_TIME = 1;
1569 	Falling_Height = 50.f;
1570 	float yy;
1571 	EERIEPOLY * ep = CheckInPoly(player.pos.x, player.pos.y, player.pos.z, &yy);
1572 
1573 	if (ep)
1574 	{
1575 		Falling_Height = player.pos.y;
1576 	}
1577 }
1578 
1579 //*************************************************************************************
1580 // void ARX_PLAYER_BecomesDead()
1581 //-------------------------------------------------------------------------------------
1582 // FUNCTION/RESULT:
1583 //   Called When player has just died
1584 //*************************************************************************************
ARX_PLAYER_BecomesDead()1585 void ARX_PLAYER_BecomesDead()
1586 {
1587 	STARTED_A_GAME = 0;
1588 	// a mettre au final
1589 	BLOCK_PLAYER_CONTROLS = 1;
1590 
1591 	if (entities.player())
1592 	{
1593 		player.Interface &= ~INTER_COMBATMODE;
1594 		player.Interface = 0;
1595 		DeadCameraDistance = 40.f;
1596 		DeadTime = 0;
1597 	}
1598 
1599 	for(size_t i = 0; i < MAX_SPELLS; i++) {
1600 		if(spells[i].exist && spells[i].caster == 0) {
1601 			spells[i].tolive = 0;
1602 		}
1603 	}
1604 }
1605 
1606 float LASTPLAYERA = 0;
1607 extern long ON_PLATFORM;
1608 long LAST_ON_PLATFORM = 0;
1609 extern long MOVE_PRECEDENCE;
1610 extern long EXTERNALVIEW;
1611 
1612 // Manages Player visual
1613 // Choose the set of animations to use to represent current player
1614 // situation.
ARX_PLAYER_Manage_Visual()1615 void ARX_PLAYER_Manage_Visual() {
1616 
1617 	unsigned long tim = (unsigned long)(arxtime);
1618 
1619 	if(player.Current_Movement & PLAYER_ROTATE) {
1620 		if(ROTATE_START == 0) {
1621 			ROTATE_START = tim;
1622 		}
1623 	} else if (ROTATE_START) {
1624 		float diff = (float)tim - (float)ROTATE_START;
1625 		if(diff > 100) {
1626 			ROTATE_START = 0;
1627 		}
1628 	}
1629 
1630 	static long special[3];
1631 	long light = 0;
1632 
1633 	if(entities.player()) {
1634 
1635 		Entity * io = entities.player();
1636 
1637 		if(!BLOCK_PLAYER_CONTROLS && sp_max) {
1638 			io->halo.color = Color3f::red;
1639 			io->halo.flags |= HALO_ACTIVE | HALO_DYNLIGHT;
1640 			io->halo.radius = 20.f;
1641 			player.life += float(FrameDiff) * 0.1f;
1642 			player.life = std::min(player.life, player.maxlife);
1643 			player.mana += float(FrameDiff) * 0.1f;
1644 			player.mana = std::min(player.mana, player.maxmana);
1645 		}
1646 
1647 		if(cur_mr == 3) {
1648 			player.life += float(FrameDiff) * 0.05f;
1649 			player.life = std::min(player.life, player.maxlife);
1650 			player.mana += float(FrameDiff) * 0.05f;
1651 			player.mana = std::min(player.mana, player.maxmana);
1652 		}
1653 
1654 		io->pos = player.basePosition();
1655 
1656 		if(player.jumpphase == NotJumping && !LAST_ON_PLATFORM) {
1657 			float t;
1658 			EERIEPOLY * ep = CheckInPolyPrecis(player.pos.x, player.pos.y, player.pos.z, &t);
1659 			if(ep && io->pos.y > t - 30.f && io->pos.y < t) {
1660 				player.onfirmground = 1;
1661 			}
1662 		}
1663 
1664 		ComputeVVPos(io);
1665 		io->pos.y = io->_npcdata->vvpos;
1666 
1667 		if(!(player.Current_Movement & PLAYER_CROUCH) && player.physics.cyl.height > -150.f) {
1668 			float old = player.physics.cyl.height;
1669 			player.physics.cyl.height = player.baseHeight();
1670 			player.physics.cyl.origin = player.basePosition();
1671 			float anything = CheckAnythingInCylinder(&player.physics.cyl, entities.player());
1672 			if(anything < 0.f) {
1673 				player.Current_Movement |= PLAYER_CROUCH;
1674 				player.physics.cyl.height = old;
1675 			}
1676 		}
1677 
1678 		if(player.life > 0) {
1679 			io->angle = Anglef(0.f, 180.f - player.angle.b, 0.f);
1680 		}
1681 
1682 		io->gameFlags |= GFLAG_ISINTREATZONE;
1683 
1684 		ANIM_USE * ause0 = &io->animlayer[0];
1685 		ANIM_USE * ause1 = &io->animlayer[1];
1686 		ANIM_USE * ause3 = &io->animlayer[3];
1687 
1688 		ause0->next_anim = NULL;
1689 		entities.player()->animlayer[1].next_anim = NULL;
1690 		entities.player()->animlayer[2].next_anim = NULL;
1691 		entities.player()->animlayer[3].next_anim = NULL;
1692 		ANIM_HANDLE ** alist = io->anims;
1693 
1694 		if(ause0->flags & EA_FORCEPLAY) {
1695 			if(ause0->flags & EA_ANIMEND) {
1696 				ause0->flags &= ~EA_FORCEPLAY;
1697 				ause0->flags |= EA_STATICANIM;
1698 				io->move = io->lastmove = Vec3f::ZERO;
1699 			} else {
1700 				ause0->flags &= ~EA_STATICANIM;
1701 				player.pos = moveto = player.pos + io->move;
1702 				io->pos = player.basePosition();
1703 				goto nochanges;
1704 			}
1705 		}
1706 
1707 		ANIM_HANDLE * ChangeMoveAnim = NULL;
1708 		ANIM_HANDLE * ChangeMoveAnim2 = NULL;
1709 		long ChangeMA_Loop = 1;
1710 		long ChangeMA_Stopend = 0;
1711 
1712 		if(io->ioflags & IO_FREEZESCRIPT) {
1713 			goto nochanges;
1714 		}
1715 
1716 		if(player.life <= 0) {
1717 			HERO_SHOW_1ST = -1;
1718 			io->animlayer[1].cur_anim = NULL;
1719 			ChangeMoveAnim = alist[ANIM_DIE];
1720 			ChangeMA_Loop = 0;
1721 			ChangeMA_Stopend = 1;
1722 			goto makechanges;
1723 		}
1724 
1725 		if(player.Current_Movement == 0 || player.Current_Movement == PLAYER_MOVE_STEALTH
1726 		   || (player.Current_Movement & PLAYER_ROTATE)) {
1727 			if(player.Interface & INTER_COMBATMODE) {
1728 				ChangeMoveAnim = alist[ANIM_FIGHT_WAIT];
1729 			} else if(EXTERNALVIEW) {
1730 				ChangeMoveAnim = alist[ANIM_WAIT];
1731 			} else {
1732 				ChangeMoveAnim = alist[ANIM_WAIT_SHORT];
1733 			}
1734 			ChangeMA_Loop = 1;
1735 		}
1736 
1737 		if(ROTATE_START && player.angle.a > 60.f && player.angle.a < 180.f
1738 		   && LASTPLAYERA > 60.f && LASTPLAYERA < 180.f) {
1739 			if (PLAYER_ROTATION < 0)
1740 			{
1741 				if (player.Interface & INTER_COMBATMODE)
1742 					ChangeMoveAnim = alist[ANIM_U_TURN_LEFT_FIGHT];
1743 				else	ChangeMoveAnim = alist[ANIM_U_TURN_LEFT];
1744 			}
1745 			else
1746 			{
1747 				if (player.Interface & INTER_COMBATMODE)
1748 					ChangeMoveAnim = alist[ANIM_U_TURN_RIGHT_FIGHT];
1749 				else	ChangeMoveAnim = alist[ANIM_U_TURN_RIGHT];
1750 			}
1751 
1752 			ChangeMA_Loop = 1;
1753 
1754 			if ((ause0->cur_anim == alist[ANIM_U_TURN_LEFT])
1755 			        ||	(ause0->cur_anim == alist[ANIM_U_TURN_LEFT_FIGHT]))
1756 			{
1757 				float fv = PLAYER_ROTATION * 5;
1758 				long vv = fv;
1759 				io->frameloss -= fv - (float)vv;
1760 
1761 				if (io->frameloss < 0) io->frameloss = 0;
1762 
1763 				ause0->ctime -= vv;
1764 
1765 				if (ause0->ctime < 0)
1766 					ause0->ctime = 0;
1767 			}
1768 			else if ((ause0->cur_anim == alist[ANIM_U_TURN_RIGHT])
1769 			         ||	(ause0->cur_anim == alist[ANIM_U_TURN_RIGHT_FIGHT]))
1770 			{
1771 				long vv = PLAYER_ROTATION * 5;
1772 				float fv = PLAYER_ROTATION * 5;
1773 				io->frameloss += fv - (float)vv;
1774 
1775 				if (io->frameloss < 0) io->frameloss = 0;
1776 
1777 				ause0->ctime += vv;
1778 
1779 				if (ause0->ctime < 0)
1780 					ause0->ctime = 0;
1781 			}
1782 		}
1783 
1784 		LASTPLAYERA = player.angle.a;
1785 
1786 		{
1787 			long tmove = player.Current_Movement;
1788 
1789 			if (((tmove & PLAYER_MOVE_STRAFE_LEFT)
1790 			        && (tmove & PLAYER_MOVE_STRAFE_RIGHT)))
1791 			{
1792 				tmove &= ~PLAYER_MOVE_STRAFE_LEFT;
1793 				tmove &= ~PLAYER_MOVE_STRAFE_RIGHT;
1794 			}
1795 
1796 			if (MOVE_PRECEDENCE == PLAYER_MOVE_STRAFE_LEFT)
1797 				tmove &= ~PLAYER_MOVE_STRAFE_RIGHT;
1798 
1799 			if (MOVE_PRECEDENCE == PLAYER_MOVE_STRAFE_RIGHT)
1800 				tmove &= ~PLAYER_MOVE_STRAFE_LEFT;
1801 
1802 			if (MOVE_PRECEDENCE == PLAYER_MOVE_WALK_FORWARD)
1803 				tmove &= ~PLAYER_MOVE_WALK_BACKWARD;
1804 
1805 			if (player.Current_Movement & PLAYER_MOVE_WALK_FORWARD)
1806 				tmove = PLAYER_MOVE_WALK_FORWARD;
1807 
1808 			{
1809 				if (tmove & PLAYER_MOVE_STRAFE_LEFT)
1810 				{
1811 					if (player.Interface & INTER_COMBATMODE)
1812 						ChangeMoveAnim = alist[ANIM_FIGHT_STRAFE_LEFT];
1813 					else if (player.Current_Movement & PLAYER_MOVE_STEALTH)
1814 						ChangeMoveAnim = alist[ANIM_STRAFE_LEFT];
1815 					else
1816 						ChangeMoveAnim = alist[ANIM_STRAFE_RUN_LEFT];
1817 				}
1818 
1819 				if (tmove & PLAYER_MOVE_STRAFE_RIGHT)
1820 				{
1821 					if (player.Interface & INTER_COMBATMODE)
1822 						ChangeMoveAnim = alist[ANIM_FIGHT_STRAFE_RIGHT];
1823 					else if (player.Current_Movement & PLAYER_MOVE_STEALTH)
1824 						ChangeMoveAnim = alist[ANIM_STRAFE_RIGHT];
1825 					else
1826 						ChangeMoveAnim = alist[ANIM_STRAFE_RUN_RIGHT];
1827 				}
1828 			}
1829 
1830 			if (tmove & PLAYER_MOVE_WALK_BACKWARD)
1831 			{
1832 				if (player.Interface & INTER_COMBATMODE)
1833 					ChangeMoveAnim = alist[ANIM_FIGHT_WALK_BACKWARD];
1834 				else if (player.Current_Movement & PLAYER_MOVE_STEALTH)
1835 					ChangeMoveAnim = alist[ANIM_WALK_BACKWARD];
1836 				else if (player.Current_Movement & PLAYER_CROUCH)
1837 					ChangeMoveAnim = alist[ANIM_WALK_BACKWARD];
1838 				else
1839 					ChangeMoveAnim = alist[ANIM_RUN_BACKWARD];
1840 			}
1841 
1842 			if (tmove & PLAYER_MOVE_WALK_FORWARD)
1843 			{
1844 
1845 				if (player.Interface & INTER_COMBATMODE)
1846 					ChangeMoveAnim = alist[ANIM_FIGHT_WALK_FORWARD];
1847 				else if (player.Current_Movement & PLAYER_MOVE_STEALTH)
1848 					ChangeMoveAnim = alist[ANIM_WALK];
1849 				else
1850 					ChangeMoveAnim = alist[ANIM_RUN];
1851 			}
1852 
1853 		}
1854 
1855 		if (ChangeMoveAnim == NULL)
1856 		{
1857 			if (EXTERNALVIEW)
1858 				ChangeMoveAnim = alist[ANIM_WAIT];
1859 			else
1860 				ChangeMoveAnim = alist[ANIM_WAIT_SHORT];
1861 
1862 			ChangeMA_Loop = 1;
1863 		}
1864 
1865 		// Finally update anim
1866 		if ((ause1->cur_anim == NULL)
1867 		        &&	((ause0->cur_anim == alist[ANIM_WAIT])
1868 		             ||	(ause0->cur_anim == alist[ANIM_WAIT_SHORT]))
1869 		        &&	(!(player.Current_Movement & PLAYER_CROUCH)))
1870 		{
1871 			if ((player.Current_Movement & PLAYER_LEAN_LEFT)
1872 			        &&	(player.Current_Movement & PLAYER_LEAN_RIGHT))
1873 			{
1874 			}
1875 			else
1876 			{
1877 				if (player.Current_Movement & PLAYER_LEAN_LEFT)
1878 				{
1879 					ChangeMoveAnim2 = alist[ANIM_LEAN_LEFT];
1880 					//ChangeMA_Loop=0;
1881 				}
1882 
1883 				if (player.Current_Movement & PLAYER_LEAN_RIGHT)
1884 				{
1885 					ChangeMoveAnim2 = alist[ANIM_LEAN_RIGHT];
1886 				}
1887 			}
1888 		}
1889 
1890 		if ((ChangeMoveAnim2 == NULL)
1891 		        &&	(ause3->cur_anim)
1892 		        &&	((ause3->cur_anim == alist[ANIM_LEAN_RIGHT])
1893 		             ||	(ause3->cur_anim == alist[ANIM_LEAN_LEFT]))
1894 		   )
1895 		{
1896 			AcquireLastAnim(io);
1897 			ause3->cur_anim = NULL;
1898 		}
1899 
1900 		if ((player.Current_Movement & PLAYER_CROUCH) && !(player.Last_Movement & PLAYER_CROUCH)
1901 		        && !player.levitate)
1902 		{
1903 			ChangeMoveAnim = alist[ANIM_CROUCH_START];
1904 			ChangeMA_Loop = 0;
1905 		}
1906 		else if (!(player.Current_Movement & PLAYER_CROUCH) && (player.Last_Movement & PLAYER_CROUCH))
1907 		{
1908 			ChangeMoveAnim = alist[ANIM_CROUCH_END];
1909 			ChangeMA_Loop = 0;
1910 		}
1911 		else if (player.Current_Movement & PLAYER_CROUCH)
1912 		{
1913 			if (ause0->cur_anim == alist[ANIM_CROUCH_START])
1914 			{
1915 				if (!(ause0->flags & EA_ANIMEND))
1916 				{
1917 					ChangeMoveAnim = alist[ANIM_CROUCH_START];
1918 					ChangeMA_Loop = 0;
1919 				}
1920 				else
1921 				{
1922 					ChangeMoveAnim = alist[ANIM_CROUCH_WAIT];
1923 					ChangeMA_Loop = 1;
1924 					player.physics.cyl.height = player.crouchHeight();
1925 				}
1926 			}
1927 			else
1928 			{
1929 				if ((ChangeMoveAnim == alist[ANIM_STRAFE_LEFT])
1930 				        ||	(ChangeMoveAnim == alist[ANIM_STRAFE_RUN_LEFT])
1931 				        ||	(ChangeMoveAnim == alist[ANIM_FIGHT_STRAFE_LEFT])
1932 				   )
1933 				{
1934 					ChangeMoveAnim = alist[ANIM_CROUCH_STRAFE_LEFT];
1935 					ChangeMA_Loop = 1;
1936 				}
1937 				else if ((ChangeMoveAnim == alist[ANIM_STRAFE_RIGHT])
1938 				         ||	(ChangeMoveAnim == alist[ANIM_STRAFE_RUN_RIGHT])
1939 				         ||	(ChangeMoveAnim == alist[ANIM_FIGHT_STRAFE_RIGHT])
1940 				        )
1941 				{
1942 					ChangeMoveAnim = alist[ANIM_CROUCH_STRAFE_RIGHT];
1943 					ChangeMA_Loop = 1;
1944 				}
1945 				else if ((ChangeMoveAnim == alist[ANIM_WALK])
1946 				         ||	(ChangeMoveAnim == alist[ANIM_RUN])
1947 				         ||	(ChangeMoveAnim == alist[ANIM_FIGHT_WALK_FORWARD])
1948 				        )
1949 				{
1950 					ChangeMoveAnim = alist[ANIM_CROUCH_WALK];
1951 					ChangeMA_Loop = 1;
1952 				}
1953 				else if ((ChangeMoveAnim == alist[ANIM_WALK_BACKWARD])
1954 				         || (ChangeMoveAnim == alist[ANIM_FIGHT_WALK_BACKWARD])
1955 				        )
1956 				{
1957 					ChangeMoveAnim = alist[ANIM_CROUCH_WALK_BACKWARD];
1958 					ChangeMA_Loop = 1;
1959 				}
1960 				else
1961 				{
1962 					ChangeMoveAnim = alist[ANIM_CROUCH_WAIT];
1963 					ChangeMA_Loop = 1;
1964 				}
1965 			}
1966 		}
1967 
1968 		if (ause0->cur_anim == alist[ANIM_CROUCH_END])
1969 		{
1970 			if (!(ause0->flags & EA_ANIMEND))
1971 				goto nochanges;
1972 		}
1973 
1974 	retry:
1975 		;
1976 
1977 		if (ARX_SPELLS_ExistAnyInstance(SPELL_FLYING_EYE))
1978 		{
1979 			FistParticles |= 1;
1980 		}
1981 		else FistParticles &= ~1;
1982 
1983 		if (FistParticles)
1984 		{
1985 			light = 1;
1986 
1987 			if (FistParticles & 1)
1988 			{
1989 				ChangeMoveAnim = alist[ANIM_MEDITATION];
1990 				ChangeMA_Loop = 1;
1991 			}
1992 
1993 			EERIE_3DOBJ * eobj = io->obj;
1994 			long pouet = 2;
1995 
1996 			while (pouet)
1997 			{
1998 				long id;
1999 
2000 				if (pouet == 2)
2001 					id = io->obj->fastaccess.primary_attach;
2002 				else
2003 					id = GetActionPointIdx(io->obj, "left_attach");
2004 
2005 				pouet--;
2006 
2007 				if(id != -1) {
2008 
2009 					if(special[pouet] == -1) {
2010 						special[pouet] = GetFreeDynLight();
2011 					}
2012 					if(special[pouet] != -1) {
2013 						EERIE_LIGHT * el = &DynLight[special[pouet]];
2014 						el->intensity = 1.3f;
2015 						el->exist = 1;
2016 						el->fallend = 180.f;
2017 						el->fallstart = 50.f;
2018 						if(FistParticles & 2) {
2019 							el->rgb = Color3f(1.f, 0.3f, 0.2f);
2020 						} else {
2021 							el->rgb = Color3f(0.7f, 0.3f, 1.f);
2022 						}
2023 						el->pos = eobj->vertexlist3[id].v;
2024 					} else {
2025 						LogWarning << "Maximum number of dynamic lights exceeded.";
2026 					}
2027 
2028 					for(long kk = 0; kk < 2; kk++) {
2029 
2030 						PARTICLE_DEF * pd = createParticle();
2031 						if(!pd) {
2032 							break;
2033 						}
2034 
2035 						pd->ov = eobj->vertexlist3[id].v + randomVec(-1.f, 1.f);
2036 						pd->move = Vec3f(0.1f - 0.2f * rnd(), -2.2f * rnd(), 0.1f - 0.2f * rnd());
2037 						pd->siz = 5.f;
2038 						pd->tolive = Random::get(1500, 3500);
2039 						pd->scale = Vec3f::repeat(0.2f);
2040 						pd->tc = TC_smoke;
2041 						pd->special = FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
2042 						pd->sourceionum = 0;
2043 						pd->source = &eobj->vertexlist3[id].v;
2044 						pd->fparam = 0.0000001f;
2045 						if(FistParticles & 2) {
2046 							pd->move.y *= 2.f;
2047 							pd->rgb = Color3f(1.f - rnd() * .1f, .3f + rnd() * .1f, .2f - rnd() * .1f);
2048 						} else {
2049 							pd->rgb = Color3f(.7f - rnd() * .1f, .3f - rnd() * .1f, 1.f - rnd() * .1f);
2050 						}
2051 					}
2052 				}
2053 			}
2054 
2055 			goto makechanges;
2056 		}
2057 		else if (ARX_SPELLS_GetSpellOn(io, SPELL_LEVITATE) >= 0)
2058 		{
2059 			ChangeMoveAnim = alist[ANIM_LEVITATE];
2060 			ChangeMA_Loop = 1;
2061 			goto makechanges;
2062 
2063 		} else if(player.jumpphase != NotJumping) {
2064 
2065 			switch(player.jumpphase) {
2066 
2067 				case NotJumping: break;
2068 
2069 				case JumpStart: { // Anticipation
2070 					FALLING_TIME = 0;
2071 					player.jumpphase = JumpAscending;
2072 					ChangeMoveAnim = alist[ANIM_JUMP_UP];
2073 					player.jumpstarttime = (unsigned long)(arxtime);
2074 					player.jumplastposition = -1.f;
2075 					break;
2076 				}
2077 
2078 				case JumpAscending: { // Moving up
2079 					ChangeMoveAnim = alist[ANIM_JUMP_UP];
2080 					if(player.jumplastposition >= 1.f) {
2081 						player.jumpphase = JumpDescending;
2082 						ChangeMoveAnim = alist[ANIM_JUMP_CYCLE];
2083 						ARX_PLAYER_StartFall();
2084 					}
2085 					break;
2086 				}
2087 
2088 				case JumpDescending: { // Post-synch
2089 					LAST_JUMP_ENDTIME = (unsigned long)(arxtime);
2090 					if((ause0->cur_anim == alist[ANIM_JUMP_END] && (ause0->flags & EA_ANIMEND))
2091 					   || player.onfirmground) {
2092 						player.jumpphase = JumpEnd;
2093 						ChangeMoveAnim = alist[ANIM_JUMP_END_PART2];
2094 					} else {
2095 						ChangeMoveAnim = alist[ANIM_JUMP_END];
2096 					}
2097 					break;
2098 				}
2099 
2100 				case JumpEnd: { // Post-synch
2101 					LAST_JUMP_ENDTIME = (unsigned long)(arxtime);
2102 					if(ause0->cur_anim == alist[ANIM_JUMP_END_PART2]
2103 					   && (ause0->flags & EA_ANIMEND)) {
2104 						AcquireLastAnim(io);
2105 						player.jumpphase = NotJumping;
2106 						goto retry;
2107 					} else if(ause0->cur_anim == alist[ANIM_JUMP_END_PART2]
2108 					         && EEfabs(player.physics.velocity.x)
2109 					             + EEfabs(player.physics.velocity.z) > (4.f/TARGET_DT)
2110 					         && ause0->ctime > 1) {
2111 						AcquireLastAnim(io);
2112 						player.jumpphase = NotJumping;
2113 						goto retry;
2114 					} else {
2115 						ChangeMoveAnim = alist[ANIM_JUMP_END_PART2];
2116 					}
2117 					break;
2118 				}
2119 
2120 			}
2121 
2122 			if ((ChangeMoveAnim) && (ChangeMoveAnim != ause0->cur_anim))
2123 			{
2124 				AcquireLastAnim(io);
2125 				ResetAnim(ause0);
2126 				ause0->cur_anim = ChangeMoveAnim;
2127 				ause0->flags = EA_STATICANIM;
2128 
2129 				if ((ChangeMoveAnim == alist[ANIM_U_TURN_LEFT])
2130 				        ||	(ChangeMoveAnim == alist[ANIM_U_TURN_RIGHT])
2131 				        ||	(ChangeMoveAnim == alist[ANIM_U_TURN_RIGHT_FIGHT])
2132 				        ||	(ChangeMoveAnim == alist[ANIM_U_TURN_LEFT_FIGHT]))
2133 					ause0->flags |= EA_EXCONTROL;
2134 			}
2135 
2136 			if ((ChangeMoveAnim2) && (ChangeMoveAnim2 != ause3->cur_anim))
2137 			{
2138 				AcquireLastAnim(io);
2139 				ResetAnim(ause3);
2140 				ause3->cur_anim = ChangeMoveAnim2;
2141 				ause3->flags = EA_STATICANIM;
2142 			}
2143 		}
2144 		else
2145 		{
2146 		makechanges:
2147 			;
2148 
2149 			if ((ChangeMoveAnim) && (ChangeMoveAnim != ause0->cur_anim))
2150 			{
2151 				AcquireLastAnim(io);
2152 				ResetAnim(ause0);
2153 				ause0->cur_anim = ChangeMoveAnim;
2154 				ause0->flags = EA_STATICANIM;
2155 
2156 				if (ChangeMA_Loop)		ause0->flags |= EA_LOOP;
2157 
2158 				if (ChangeMA_Stopend)	ause0->flags |= EA_STOPEND;
2159 
2160 				if ((ChangeMoveAnim == alist[ANIM_U_TURN_LEFT])
2161 				        ||	(ChangeMoveAnim == alist[ANIM_U_TURN_RIGHT])
2162 				        ||	(ChangeMoveAnim == alist[ANIM_U_TURN_RIGHT_FIGHT])
2163 				        ||	(ChangeMoveAnim == alist[ANIM_U_TURN_LEFT_FIGHT]))
2164 					ause0->flags |= EA_EXCONTROL;
2165 			}
2166 
2167 			if ((ChangeMoveAnim2) && (ChangeMoveAnim2 != ause3->cur_anim))
2168 			{
2169 				AcquireLastAnim(io);
2170 				ResetAnim(ause3);
2171 				ause3->cur_anim = ChangeMoveAnim2;
2172 				ause3->flags = EA_STATICANIM;
2173 			}
2174 		}
2175 
2176 		memcpy(&io->physics, &player.physics, sizeof(IO_PHYSICS));
2177 	}
2178 
2179 nochanges:
2180 	;
2181 	player.Last_Movement = player.Current_Movement;
2182 
2183 	if (!light)
2184 	{
2185 		if (special[2] != -1)
2186 		{
2187 			DynLight[special[2]].exist = 0;
2188 			special[2] = -1;
2189 		}
2190 
2191 		if (special[1] != -1)
2192 		{
2193 			DynLight[special[1]].exist = 0;
2194 			special[1] = -1;
2195 		}
2196 	}
2197 }
2198 
2199 // Init Local Player Data
ARX_PLAYER_InitPlayer()2200 void ARX_PLAYER_InitPlayer() {
2201 	player.Interface = INTER_MINIBOOK | INTER_MINIBACK | INTER_LIFE_MANA;
2202 	player.physics.cyl.height = player.baseHeight();
2203 	player.physics.cyl.radius = player.baseRadius();
2204 	player.life = player.maxlife = player.Full_maxlife = 100.f;
2205 	player.mana = player.maxmana = player.Full_maxmana = 100.f;
2206 	player.falling = 0;
2207 	player.rightIO = NULL;
2208 	player.leftIO = NULL;
2209 	player.equipsecondaryIO = NULL;
2210 	player.equipshieldIO = NULL;
2211 	player.gold = 0;
2212 	player.bag = 1;
2213 	player.doingmagic = 0;
2214 	ARX_PLAYER_MakeFreshHero();
2215 }
2216 
2217 // Forces player orientation to look at an IO
ForcePlayerLookAtIO(Entity * io)2218 void ForcePlayerLookAtIO(Entity * io) {
2219 
2220 	// Validity Check
2221 	if (!io) return;
2222 
2223 	EERIE_CAMERA tcam;
2224 	Vec3f target;
2225 
2226 	long id = entities.player()->obj->fastaccess.view_attach;
2227 
2228 	if(id != -1) {
2229 		tcam.pos = entities.player()->obj->vertexlist3[id].v;
2230 	} else {
2231 		tcam.pos = player.pos;
2232 	}
2233 
2234 	id = io->obj->fastaccess.view_attach;
2235 
2236 	if(id != -1) {
2237 		target = io->obj->vertexlist3[id].v;
2238 	}
2239 	else
2240 	{
2241 		target = io->pos;
2242 	}
2243 
2244 	// For the case of not already computed Vlist3... !
2245 	if(fartherThan(target, io->pos, 400.f)) {
2246 		target = io->pos;
2247 	}
2248 
2249 	SetTargetCamera(&tcam, target.x, target.y, target.z);
2250 	player.desiredangle.a = player.angle.a = MAKEANGLE(-tcam.angle.a);
2251 	player.desiredangle.b = player.angle.b = MAKEANGLE(tcam.angle.b - 180.f);
2252 	player.angle.g = 0;
2253 }
2254 extern float PLAYER_ARMS_FOCAL;
2255 extern long CURRENT_BASE_FOCAL;
2256 extern long TRAP_DETECT;
2257 extern long TRAP_SECRET;
2258 
2259 
2260 //*************************************************************************************
2261 // void ARX_PLAYER_Frame_Update()
2262 //-------------------------------------------------------------------------------------
2263 // FUNCTION/RESULT:
2264 //   Updates Many player infos each frame...
2265 //*************************************************************************************
ARX_PLAYER_Frame_Update()2266 void ARX_PLAYER_Frame_Update()
2267 {
2268 	if (ARX_SPELLS_GetSpellOn(entities.player(), SPELL_PARALYSE) >= 0)
2269 	{
2270 		PLAYER_PARALYSED = 1;
2271 	}
2272 	else
2273 	{
2274 		entities.player()->ioflags &= ~IO_FREEZESCRIPT;
2275 		PLAYER_PARALYSED = 0;
2276 	}
2277 
2278 	// Reset player moveto info
2279 	moveto = player.pos;
2280 
2281 	// Reset current movement flags
2282 	player.Current_Movement = 0;
2283 
2284 	// Updates player angles to desired angles
2285 	player.angle.a = player.desiredangle.a;
2286 	player.angle.b = player.desiredangle.b;
2287 
2288 	// Updates player Extra-Rotate Informations
2289 	Entity * io;
2290 	io = entities.player();
2291 
2292 	if ((io) && (io->_npcdata->ex_rotate))
2293 	{
2294 		float v = player.angle.a;
2295 
2296 		if (v > 160) v = -(360 - v);
2297 
2298 		if (player.Interface & INTER_COMBATMODE)
2299 		{
2300 			if (ARX_EQUIPMENT_GetPlayerWeaponType() == WEAPON_BOW)
2301 			{
2302 				io->_npcdata->ex_rotate->group_rotate[0].a = 0; //head
2303 				io->_npcdata->ex_rotate->group_rotate[1].a = 0; //neck
2304 				io->_npcdata->ex_rotate->group_rotate[2].a = 0; //chest
2305 				io->_npcdata->ex_rotate->group_rotate[3].a = v; //belt
2306 			}
2307 			else
2308 			{
2309 				v *= ( 1.0f / 10 );
2310 				io->_npcdata->ex_rotate->group_rotate[0].a = v; //head
2311 				io->_npcdata->ex_rotate->group_rotate[1].a = v; //neck
2312 				io->_npcdata->ex_rotate->group_rotate[2].a = v * 4; //chest
2313 				io->_npcdata->ex_rotate->group_rotate[3].a = v * 4; //belt
2314 			}
2315 
2316 		}
2317 		else
2318 		{
2319 			v *= ( 1.0f / 4 );
2320 			io->_npcdata->ex_rotate->group_rotate[0].a = v; //head
2321 			io->_npcdata->ex_rotate->group_rotate[1].a = v; //neck
2322 			io->_npcdata->ex_rotate->group_rotate[2].a = v; //chest
2323 			io->_npcdata->ex_rotate->group_rotate[3].a = v; //belt*/
2324 		}
2325 
2326 		if ((player.Interface & INTER_COMBATMODE) || (player.doingmagic == 2))
2327 			io->_npcdata->ex_rotate->flags &= ~EXTRA_ROTATE_REALISTIC;
2328 	}
2329 
2330 	// Changes player ARMS focal depending on alpha angle.
2331 	if (player.angle.a > 180)
2332 		PLAYER_ARMS_FOCAL = (float)CURRENT_BASE_FOCAL - 80.f;
2333 	else
2334 		PLAYER_ARMS_FOCAL = (float)CURRENT_BASE_FOCAL - 80.f + player.angle.a;
2335 
2336 	PLAYER_ARMS_FOCAL = static_cast<float>(CURRENT_BASE_FOCAL);
2337 
2338 	ARX_PLAYER_ComputePlayerFullStats();
2339 
2340 	TRAP_DETECT = checked_range_cast<long>(player.Full_Skill_Mecanism);
2341 	TRAP_SECRET = checked_range_cast<long>(player.Full_Skill_Intuition);
2342 
2343 	if (ARX_SPELLS_GetSpellOn(entities.player(), SPELL_DETECT_TRAP) >= 0)
2344 		TRAP_DETECT = 100;
2345 
2346 	ModeLight |= MODE_DEPTHCUEING;
2347 
2348 	ARX_PLAYER_ManageTorch();
2349 }
2350 
2351 // Emit player step noise
ARX_PLAYER_MakeStepNoise()2352 static void ARX_PLAYER_MakeStepNoise() {
2353 
2354 	if(ARX_SPELLS_GetSpellOn(entities.player(), SPELL_LEVITATE) >= 0) {
2355 		return;
2356 	}
2357 
2358 	if(USE_PLAYERCOLLISIONS) {
2359 
2360 		float volume = ARX_NPC_AUDIBLE_VOLUME_DEFAULT;
2361 		float factor = ARX_NPC_AUDIBLE_FACTOR_DEFAULT;
2362 
2363 		if(player.Current_Movement & PLAYER_MOVE_STEALTH) {
2364 			float skill_stealth;
2365 			skill_stealth = player.Full_Skill_Stealth / ARX_PLAYER_SKILL_STEALTH_MAX;
2366 			volume -= ARX_NPC_AUDIBLE_VOLUME_RANGE * skill_stealth;
2367 			factor += ARX_NPC_AUDIBLE_FACTOR_RANGE * skill_stealth;
2368 		}
2369 
2370 		Vec3f pos = player.basePosition();
2371 		ARX_NPC_NeedStepSound(entities.player(), &pos, volume, factor);
2372 	}
2373 
2374 	while(currentdistance >= STEP_DISTANCE) {
2375 		currentdistance -= STEP_DISTANCE;
2376 	}
2377 }
2378 
2379 extern bool bGCroucheToggle;
2380 extern float MAX_ALLOWED_PER_SECOND;
2381 
2382 static long LAST_FIRM_GROUND = 1;
2383 static long TRUE_FIRM_GROUND = 1;
2384 float lastposy = -9999999.f;
2385 unsigned long REQUEST_JUMP = 0;
2386 extern float GLOBAL_SLOWDOWN;
2387 extern float Original_framedelay;
2388 
2389 unsigned long LAST_JUMP_ENDTIME = 0;
2390 
Valid_Jump_Pos()2391 bool Valid_Jump_Pos() {
2392 
2393 	if(LAST_ON_PLATFORM || player.climbing) {
2394 		return true;
2395 	}
2396 
2397 	EERIE_CYLINDER tmpp;
2398 	tmpp.height = player.physics.cyl.height;
2399 	tmpp.origin = player.basePosition();
2400 	tmpp.radius = player.physics.cyl.radius * 0.85f;
2401 	float tmp = CheckAnythingInCylinder(&tmpp, entities.player(),
2402 	                                    CFLAG_PLAYER | CFLAG_JUST_TEST);
2403 	if(tmp <= 20.f) {
2404 		return true;
2405 	}
2406 
2407 	long hum = 0;
2408 	for(float vv = 0; vv < 360.f; vv += 20.f) {
2409 		tmpp.origin = player.basePosition();
2410 		tmpp.origin += Vec3f(-EEsin(radians(vv)) * 20.f, 0.f, EEcos(radians(vv)) * 20.f);
2411 		tmpp.radius = player.physics.cyl.radius;
2412 		float anything = CheckAnythingInCylinder(&tmpp, entities.player(), CFLAG_JUST_TEST);
2413 		if(anything > 10) {
2414 			hum = 1;
2415 			break;
2416 		}
2417 	}
2418 	if(!hum) {
2419 		return true;
2420 	}
2421 
2422 	if(COLLIDED_CLIMB_POLY) {
2423 		player.climbing = 1;
2424 		return true;
2425 	}
2426 
2427 	return (tmp <= 50.f);
2428 }
2429 
2430 void PlayerMovementIterate(float DelatTime);
2431 
ARX_PLAYER_Manage_Movement()2432 void ARX_PLAYER_Manage_Movement() {
2433 
2434 	// Is our player able to move ?
2435 	if ((CINEMASCOPE)
2436 	        ||	(BLOCK_PLAYER_CONTROLS)
2437 	        ||	(entities.player() == NULL))
2438 		return;
2439 
2440 	float speedfactor;
2441 	// Compute current player speedfactor
2442 	speedfactor = entities.player()->basespeed + entities.player()->speed_modif;
2443 
2444 	if (speedfactor < 0) speedfactor = 0;
2445 
2446 	if (cur_mr == 3) speedfactor += 0.5f;
2447 
2448 	if (cur_rf == 3) speedfactor += 1.5f;
2449 
2450 	// Compute time things
2451 	const float FIXED_TIMESTEP = 25.f;
2452 	const float MAX_FRAME_TIME = 200.f;
2453 
2454 	static float StoredTime = 0;
2455 
2456 	float DeltaTime = std::min(Original_framedelay, MAX_FRAME_TIME);
2457 	DeltaTime = StoredTime + DeltaTime * speedfactor;
2458 
2459 	if(EDITMODE) {
2460 		DeltaTime = FIXED_TIMESTEP;
2461 	}
2462 
2463 	if(player.jumpphase != NotJumping) {
2464 		while(DeltaTime > FIXED_TIMESTEP) {
2465 			/*
2466 			 * TODO: should be PlayerMovementIterate(FIXED_TIMESTEP);
2467 			 * However, jump forward movement is only applied the the first
2468 			 * iteration, so we need this to not completely break the jump
2469 			 * at lower framerates.
2470 			 * Should only cause minor differences at higher framerates.
2471 			 * Fix this once PlayerMovementIterate has been cleaned up!
2472 			 */
2473 			PlayerMovementIterate(DeltaTime);
2474 			DeltaTime -= FIXED_TIMESTEP;
2475 		}
2476 	} else {
2477 		PlayerMovementIterate(DeltaTime);
2478 		DeltaTime = 0;
2479 	}
2480 
2481 	StoredTime = DeltaTime;
2482 }
2483 
PlayerMovementIterate(float DeltaTime)2484 void PlayerMovementIterate(float DeltaTime) {
2485 
2486 	// A jump is requested so let's go !
2487 	if(REQUEST_JUMP) {
2488 
2489 		if((player.Current_Movement & PLAYER_CROUCH)
2490 		   || player.physics.cyl.height > player.baseHeight()) {
2491 			float old = player.physics.cyl.height;
2492 			player.physics.cyl.height = player.baseHeight();
2493 			player.physics.cyl.origin = player.basePosition();
2494 			float anything = CheckAnythingInCylinder(&player.physics.cyl, entities.player(),
2495 			                                         CFLAG_JUST_TEST);
2496 			if(anything < 0.f) {
2497 				player.Current_Movement |= PLAYER_CROUCH;
2498 				player.physics.cyl.height = old;
2499 				REQUEST_JUMP = 0;
2500 			} else {
2501 				bGCroucheToggle = false;
2502 				player.Current_Movement &= ~PLAYER_CROUCH;
2503 				player.physics.cyl.height = player.baseHeight();
2504 			}
2505 		}
2506 
2507 		if(!Valid_Jump_Pos()) {
2508 			REQUEST_JUMP = 0;
2509 		}
2510 
2511 		if(REQUEST_JUMP) {
2512 			float t = (float)float(arxtime) - (float)REQUEST_JUMP;
2513 			if(t >= 0.f && t <= 350.f) {
2514 				REQUEST_JUMP = 0;
2515 				ARX_NPC_SpawnAudibleSound(&player.pos, entities.player());
2516 				ARX_SPEECH_Launch_No_Unicode_Seek("player_jump", entities.player());
2517 				player.onfirmground = 0;
2518 				player.jumpphase = JumpStart;
2519 			}
2520 		}
2521 
2522 	}
2523 
2524 	if(entities.player()->_npcdata->climb_count != 0.f && FrameDiff > 0) {
2525 		entities.player()->_npcdata->climb_count -= MAX_ALLOWED_PER_SECOND * FrameDiff * 0.1f;
2526 		if(entities.player()->_npcdata->climb_count < 0) {
2527 			entities.player()->_npcdata->climb_count = 0.f;
2528 		}
2529 	}
2530 
2531 	float d = 0;
2532 
2533 	if(!EDITMODE && USE_PLAYERCOLLISIONS) {
2534 
2535 		CollisionFlags levitate = 0;
2536 		if(player.climbing) {
2537 			levitate = CFLAG_LEVITATE;
2538 		}
2539 
2540 		if(player.levitate) {
2541 
2542 			if(player.physics.cyl.height != player.levitateHeight()) {
2543 				float old = player.physics.cyl.height;
2544 				player.physics.cyl.height = player.levitateHeight();
2545 				player.physics.cyl.origin = player.basePosition();
2546 				float anything = CheckAnythingInCylinder(&player.physics.cyl, entities.player());
2547 				if(anything < 0.f) {
2548 					player.physics.cyl.height = old;
2549 					long num = ARX_SPELLS_GetSpellOn(entities.player(), SPELL_LEVITATE);
2550 					if(num != -1) {
2551 						spells[num].tolive = 0;
2552 					}
2553 				}
2554 			}
2555 
2556 			if(player.physics.cyl.height == player.levitateHeight()) {
2557 				levitate = CFLAG_LEVITATE;
2558 				player.climbing = 0;
2559 				bGCroucheToggle = false;
2560 				player.Current_Movement &= ~PLAYER_CROUCH;
2561 			}
2562 
2563 		} else if(player.physics.cyl.height == player.levitateHeight()) {
2564 			player.physics.cyl.height = player.baseHeight();
2565 		}
2566 
2567 		if(player.jumpphase != JumpAscending && !levitate) {
2568 			player.physics.cyl.origin = player.basePosition();
2569 		}
2570 
2571 		if(EEfabs(lastposy - player.pos.y) < DeltaTime * 0.1f) {
2572 			TRUE_FIRM_GROUND = 1;
2573 		} else {
2574 			TRUE_FIRM_GROUND = 0;
2575 		}
2576 
2577 		lastposy = player.pos.y;
2578 		float anything;
2579 		EERIE_CYLINDER testcyl;
2580 		memcpy(&testcyl, &player.physics.cyl, sizeof(EERIE_CYLINDER));
2581 		testcyl.origin.y += 3.f;
2582 		ON_PLATFORM = 0;
2583 		anything = CheckAnythingInCylinder(&testcyl, entities.player(), 0);
2584 		LAST_ON_PLATFORM = ON_PLATFORM;
2585 
2586 		if(player.jumpphase != JumpAscending) {
2587 			if(anything >= 0.f) {
2588 				TRUE_FIRM_GROUND = 0;
2589 			} else {
2590 				TRUE_FIRM_GROUND = 1;
2591 				testcyl.radius -= 30.f;
2592 				testcyl.origin.y -= 10.f;
2593 				anything = CheckAnythingInCylinder(&testcyl, entities.player(), 0);
2594 			}
2595 		} else {
2596 			TRUE_FIRM_GROUND = 0;
2597 			LAST_ON_PLATFORM = 0;
2598 		}
2599 
2600 		EERIE_CYLINDER cyl;
2601 		cyl.origin = player.basePosition() + Vec3f(0.f, 1.f, 0.f);
2602 		cyl.radius = player.physics.cyl.radius;
2603 		cyl.height = player.physics.cyl.height;
2604 		float anything2 = CheckAnythingInCylinder(&cyl, entities.player(), CFLAG_JUST_TEST | CFLAG_PLAYER); //-cyl->origin.y;
2605 
2606 		if(anything2 > -5 && player.physics.velocity.y > (15.f/TARGET_DT) && !LAST_ON_PLATFORM
2607 		  && !TRUE_FIRM_GROUND && player.jumpphase == NotJumping && !player.levitate
2608 		  && anything > 80.f) {
2609 			player.jumpphase = JumpDescending;
2610 			if(!player.falling) {
2611 				player.falling = 1;
2612 				ARX_PLAYER_StartFall();
2613 			}
2614 		} else if(!player.falling) {
2615 			FALLING_TIME = 0;
2616 		}
2617 
2618 		if(player.jumpphase != NotJumping && player.levitate) {
2619 			player.jumpphase = NotJumping;
2620 			player.falling = 0;
2621 			Falling_Height = player.pos.y;
2622 			FALLING_TIME = 0;
2623 		}
2624 
2625 		if(!LAST_FIRM_GROUND && TRUE_FIRM_GROUND) {
2626 			player.jumpphase = NotJumping;
2627 			if(FALLING_TIME > 0 && player.falling) {
2628 				player.physics.velocity.x = 0.f;
2629 				player.physics.velocity.z = 0.f;
2630 				player.physics.forces.x = 0.f;
2631 				player.physics.forces.z = 0.f;
2632 				player.falling = 0;
2633 				float fh = player.pos.y - Falling_Height;
2634 				if(fh > 400.f) {
2635 					float dmg = (fh - 400.f) * (1.0f / 15);
2636 					if(dmg > 0.f) {
2637 						Falling_Height = player.pos.y;
2638 						FALLING_TIME = 0;
2639 						ARX_DAMAGES_DamagePlayer(dmg, 0, -1);
2640 						ARX_DAMAGES_DamagePlayerEquipment(dmg);
2641 					}
2642 				}
2643 			}
2644 		}
2645 
2646 		LAST_FIRM_GROUND = TRUE_FIRM_GROUND;
2647 		player.onfirmground = TRUE_FIRM_GROUND;
2648 		if(player.onfirmground && !player.falling) {
2649 			FALLING_TIME = 0;
2650 		}
2651 
2652 		// Apply player impulse force
2653 
2654 		float jump_mul = 1.f;
2655 		if(float(arxtime) - LAST_JUMP_ENDTIME < 600) {
2656 			jump_mul = 0.5f;
2657 			if(float(arxtime) - LAST_JUMP_ENDTIME >= 300) {
2658 				jump_mul += (float)(LAST_JUMP_ENDTIME + 300 - float(arxtime)) * (1.f / 300);
2659 				if(jump_mul > 1.f) {
2660 					jump_mul = 1.f;
2661 				}
2662 			}
2663 		}
2664 
2665 		Vec3f impulse = moveto - player.pos;
2666 		if(impulse != Vec3f::ZERO) {
2667 
2668 			float scale = 1.25f / 1000;
2669 			if(entities.player()->animlayer[0].cur_anim) {
2670 				if(player.jumpphase != NotJumping) {
2671 					if(player.Current_Movement & PLAYER_MOVE_WALK_BACKWARD) {
2672 						scale = 0.8f / 1000;
2673 					} else if(player.Current_Movement & PLAYER_MOVE_WALK_FORWARD) {
2674 						scale = 7.9f / 1000;
2675 					} else if(player.Current_Movement & PLAYER_MOVE_STRAFE_LEFT) {
2676 						scale = 2.6f / 1000;
2677 					} else if(player.Current_Movement & PLAYER_MOVE_STRAFE_RIGHT) {
2678 						scale = 2.6f / 1000;
2679 					} else {
2680 						scale = 0.2f / 1000;
2681 					}
2682 				} else if(levitate && !player.climbing) {
2683 					scale = 0.875f / 1000;
2684 				} else {
2685 					Vec3f mv;
2686 					short idx = entities.player()->animlayer[0].altidx_cur;
2687 					GetAnimTotalTranslate(entities.player()->animlayer[0].cur_anim, idx, &mv);
2688 					float time = entities.player()->animlayer[0].cur_anim->anims[idx]->anim_time;
2689 					scale = mv.length() / time * 0.0125f;
2690 				}
2691 			}
2692 
2693 			impulse *= scale / impulse.length() * jump_mul;
2694 		}
2695 
2696 		if(player.jumpphase != NotJumping) {
2697 			// No Vertical Interpolation
2698 			entities.player()->_npcdata->vvpos = -99999.f;
2699 			if(player.jumpphase == JumpAscending) {
2700 				moveto.y = player.pos.y;
2701 				player.physics.velocity.y = 0;
2702 			}
2703 		}
2704 
2705 		if(player.climbing) {
2706 			player.physics.velocity.x = 0.f;
2707 			player.physics.velocity.y *= 0.5f;
2708 			player.physics.velocity.z = 0.f;
2709 			if(player.Current_Movement & PLAYER_MOVE_WALK_FORWARD) {
2710 				moveto.x = player.pos.x;
2711 				moveto.z = player.pos.z;
2712 			}
2713 			if(player.Current_Movement & PLAYER_MOVE_WALK_BACKWARD) {
2714 				impulse.x = 0;
2715 				impulse.z = 0;
2716 				moveto.x = player.pos.x;
2717 				moveto.z = player.pos.z;
2718 			}
2719 		}
2720 
2721 		player.physics.forces += impulse;
2722 
2723 		// Apply Gravity force if not LEVITATING or JUMPING
2724 		if(!levitate && player.jumpphase != JumpAscending && !LAST_ON_PLATFORM) {
2725 
2726 			player.physics.forces.y += ((player.falling) ? JUMP_GRAVITY : WORLD_GRAVITY) / TARGET_DT;
2727 
2728 			// Check for LAVA Damage !!!
2729 			float epcentery;
2730 			EERIEPOLY * ep = CheckInPoly(player.pos.x, player.pos.y + 150.f, player.pos.z,
2731 			                             &epcentery);
2732 			if(ep) {
2733 				if((ep->type & POLY_LAVA)
2734 				   && EEfabs(epcentery - (player.pos.y - player.baseHeight())) < 30) {
2735 					float mul = 1.f - (EEfabs(epcentery - (player.pos.y - player.baseHeight()))
2736 					                   * (1.0f / 30));
2737 					const float LAVA_DAMAGE = 10.f;
2738 					float damages = LAVA_DAMAGE * FrameDiff * 0.01f * mul;
2739 					damages = ARX_SPELLS_ApplyFireProtection(entities.player(), damages);
2740 					ARX_DAMAGES_DamagePlayer(damages, DAMAGE_TYPE_FIRE, 0);
2741 					ARX_DAMAGES_DamagePlayerEquipment(damages);
2742 					Vec3f pos = player.basePosition();
2743 					ARX_PARTICLES_Spawn_Lava_Burn(&pos, entities.player());
2744 				}
2745 			}
2746 
2747 		}
2748 
2749 		// Apply velocity damping (natural velocity attenuation, stands for friction)
2750 		float dampen = 1.f - (0.009f * DeltaTime);
2751 		if(dampen < 0.001f) {
2752 			dampen = 0.f;
2753 		}
2754 		player.physics.velocity.x *= dampen;
2755 		player.physics.velocity.z *= dampen;
2756 		if(EEfabs(player.physics.velocity.x) < 0.001f) {
2757 			player.physics.velocity.x = 0;
2758 		}
2759 		if(EEfabs(player.physics.velocity.z) < 0.001f) {
2760 			player.physics.velocity.z = 0;
2761 		}
2762 
2763 		// Apply attraction
2764 		Vec3f attraction;
2765 		ARX_SPECIAL_ATTRACTORS_ComputeForIO(*entities.player(), attraction);
2766 		player.physics.forces += attraction / TARGET_DT;
2767 
2768 		// Apply push player force
2769 		player.physics.forces += PUSH_PLAYER_FORCE / TARGET_DT;
2770 		PUSH_PLAYER_FORCE = Vec3f::ZERO;
2771 
2772 		// Apply forces to velocity
2773 		player.physics.velocity += player.physics.forces * DeltaTime;
2774 
2775 		// Apply climbing velocity
2776 		if(player.climbing) {
2777 			if(player.Current_Movement & PLAYER_MOVE_WALK_FORWARD) {
2778 				player.physics.velocity.y = -0.2f;
2779 			}
2780 			if(player.Current_Movement & PLAYER_MOVE_WALK_BACKWARD) {
2781 				player.physics.velocity.y = 0.2f;
2782 			}
2783 		}
2784 
2785 		// Removes y velocity if on firm ground...
2786 		if(player.onfirmground == 1 && !player.climbing) {
2787 			player.physics.velocity.y = 0.f;
2788 		}
2789 
2790 		float posy;
2791 		EERIEPOLY * ep = CheckInPolyPrecis(player.pos.x, player.pos.y, player.pos.z, &posy);
2792 		if(ep == NULL) {
2793 			player.physics.velocity.y = 0;
2794 		} else if(!player.climbing && player.pos.y >= posy) {
2795 			player.physics.velocity.y = 0;
2796 		}
2797 
2798 		// Reset forces
2799 		player.physics.forces = Vec3f::ZERO;
2800 
2801 		// Check if player is already on firm ground AND not moving
2802 		if(EEfabs(player.physics.velocity.x) < 0.001f
2803 		   && EEfabs(player.physics.velocity.z) < 0.001f
2804 		   && player.onfirmground == 1 && player.jumpphase == NotJumping) {
2805 			moveto = player.pos;
2806 			goto lasuite;
2807 		} else {
2808 
2809 			// Need to apply some physics/collision tests
2810 			player.physics.cyl.origin = player.basePosition();
2811 			player.physics.startpos = player.physics.cyl.origin;
2812 			player.physics.targetpos = player.physics.startpos + player.physics.velocity * DeltaTime;
2813 
2814 			// Jump impulse
2815 			if(player.jumpphase == JumpAscending) {
2816 
2817 				if(player.jumplastposition == -1.f) {
2818 					player.jumplastposition = 0;
2819 					player.jumpstarttime = (unsigned long)(arxtime);
2820 				}
2821 
2822 				const float jump_up_time = 200.f;
2823 				const float jump_up_height = 130.f;
2824 				long timee = (long)arxtime;
2825 				float offset_time = (float)timee - (float)player.jumpstarttime;
2826 				float position = clamp(offset_time / jump_up_time, 0.f, 1.f);
2827 
2828 				float p = (position - player.jumplastposition) * jump_up_height;
2829 				player.physics.targetpos.y -= p;
2830 				player.jumplastposition = position;
2831 				levitate = 0;
2832 			}
2833 
2834 			bool test;
2835 			float PLAYER_CYLINDER_STEP = 40.f;
2836 			if(player.climbing) {
2837 
2838 				test = ARX_COLLISION_Move_Cylinder(&player.physics, entities.player(),
2839 				                                   PLAYER_CYLINDER_STEP,
2840 				                                   CFLAG_EASY_SLIDING | CFLAG_CLIMBING
2841 				                                   | CFLAG_PLAYER);
2842 
2843 				if(!COLLIDED_CLIMB_POLY) {
2844 					player.climbing = 0;
2845 				}
2846 
2847 			} else {
2848 
2849 				test = ARX_COLLISION_Move_Cylinder(&player.physics, entities.player(),
2850 				                                   PLAYER_CYLINDER_STEP,
2851 				                                   levitate | CFLAG_EASY_SLIDING | CFLAG_PLAYER);
2852 
2853 				if(!test && !LAST_FIRM_GROUND && !TRUE_FIRM_GROUND) {
2854 					player.physics.velocity.x = 0.f;
2855 					player.physics.velocity.z = 0.f;
2856 					player.physics.forces.x = 0.f;
2857 					player.physics.forces.z = 0.f;
2858 					if(FALLING_TIME > 0 && player.falling) {
2859 						float fh = player.pos.y - Falling_Height;
2860 						if(fh > 400.f) {
2861 							float dmg = (fh - 400.f) * (1.f / 15);
2862 							if(dmg > 0.f) {
2863 								Falling_Height = (player.pos.y + Falling_Height * 2) * (1.f / 3);
2864 								ARX_DAMAGES_DamagePlayer(dmg, 0, -1);
2865 								ARX_DAMAGES_DamagePlayerEquipment(dmg);
2866 							}
2867 						}
2868 					}
2869 				}
2870 
2871 				if(!test && player.jumpphase != NotJumping) {
2872 					player.physics.startpos.x = player.physics.cyl.origin.x = player.pos.x;
2873 					player.physics.startpos.z = player.physics.cyl.origin.z = player.pos.z;
2874 					player.physics.targetpos.x = player.physics.startpos.x;
2875 					player.physics.targetpos.z = player.physics.startpos.z;
2876 					if(player.physics.targetpos.y != player.physics.startpos.y) {
2877 						test = ARX_COLLISION_Move_Cylinder(&player.physics, entities.player(),
2878 						                                   PLAYER_CYLINDER_STEP,
2879 						                                   levitate | CFLAG_EASY_SLIDING
2880 						                                   | CFLAG_PLAYER);
2881 						entities.player()->_npcdata->vvpos = -99999.f;
2882 					}
2883 				}
2884 			}
2885 
2886 			if(COLLIDED_CLIMB_POLY) {
2887 				player.climbing = 1;
2888 			}
2889 
2890 			if(player.climbing) {
2891 
2892 				if(player.Current_Movement && player.Current_Movement != PLAYER_ROTATE
2893 				   && !(player.Current_Movement & PLAYER_MOVE_WALK_FORWARD)
2894 				   && !(player.Current_Movement & PLAYER_MOVE_WALK_BACKWARD)) {
2895 					player.climbing = 0;
2896 				}
2897 
2898 				if((player.Current_Movement & PLAYER_MOVE_WALK_BACKWARD) && !test) {
2899 					player.climbing = 0;
2900 				}
2901 
2902 				if(player.climbing) {
2903 					player.jumpphase = NotJumping;
2904 					player.falling = 0;
2905 					FALLING_TIME = 0;
2906 					Falling_Height = player.pos.y;
2907 				}
2908 			}
2909 
2910 			if(player.jumpphase == JumpAscending) {
2911 				player.climbing = 0;
2912 			}
2913 
2914 			moveto = player.physics.cyl.origin + player.baseOffset();
2915 			d = dist(player.pos, moveto);
2916 		}
2917 
2918 	} else {
2919 
2920 		if(!EDITMODE) {
2921 			Vec3f vect = moveto - player.pos;
2922 			float divv = vect.length();
2923 			if(divv > 0.f) {
2924 				float mul = (float)FrameDiff * 0.001f * 200.f;
2925 				divv = mul / divv;
2926 				vect *= divv;
2927 				moveto = player.pos + vect;
2928 			}
2929 		}
2930 
2931 		player.onfirmground = 0;
2932 	}
2933 
2934 	if(player.pos == moveto) {
2935 		d = 0.f;
2936 	}
2937 
2938 	// Emit Stepsound
2939 	if(USE_PLAYERCOLLISIONS && !EDITMODE) {
2940 		if(player.Current_Movement & PLAYER_CROUCH) {
2941 			d *= 2.f;
2942 		}
2943 		currentdistance += d;
2944 		if(player.jumpphase == NotJumping && !player.falling
2945 		   && currentdistance >= STEP_DISTANCE) {
2946 			ARX_PLAYER_MakeStepNoise();
2947 		}
2948 	}
2949 
2950 	// Finally update player pos !
2951 	player.pos = moveto;
2952 
2953 lasuite:
2954 	;
2955 
2956 	// Get Player position color
2957 	float grnd_color = GetColorz(player.pos.x, player.pos.y + 90, player.pos.z) - 15.f;
2958 	if(CURRENT_PLAYER_COLOR < grnd_color) {
2959 		CURRENT_PLAYER_COLOR += FrameDiff * (1.0f / 8);
2960 		CURRENT_PLAYER_COLOR = std::min(CURRENT_PLAYER_COLOR, grnd_color);
2961 	}
2962 	if(CURRENT_PLAYER_COLOR > grnd_color) {
2963 		CURRENT_PLAYER_COLOR -= FrameDiff * (1.0f / 4);
2964 		CURRENT_PLAYER_COLOR = std::max(CURRENT_PLAYER_COLOR, grnd_color);
2965 	}
2966 
2967 	if (InventoryDir != 0)
2968 	{
2969 		if ((player.Interface & INTER_COMBATMODE) || (player.doingmagic >= 2) || (InventoryDir == -1))
2970 		{
2971 			if (InventoryX > -160)
2972 				InventoryX -= INTERFACE_RATIO(FrameDiff * ( 1.0f / 3 ));
2973 		}
2974 		else
2975 		{
2976 			if (InventoryX < 0)
2977 				InventoryX += InventoryDir * INTERFACE_RATIO(FrameDiff * ( 1.0f / 3 ));
2978 		}
2979 
2980 		if (InventoryX <= -160)
2981 		{
2982 			InventoryX = -160;
2983 			InventoryDir = 0;
2984 
2985 			if (player.Interface & INTER_STEAL || ioSteal)
2986 			{
2987 				SendIOScriptEvent(ioSteal, SM_STEAL, "off");
2988 				player.Interface &= ~INTER_STEAL;
2989 				ioSteal = NULL;
2990 			}
2991 
2992 			SecondaryInventory = NULL;
2993 			TSecondaryInventory = NULL;
2994 			InventoryDir = 0;
2995 		}
2996 		else if (InventoryX >= 0)
2997 		{
2998 			InventoryX = 0;
2999 			InventoryDir = 0;
3000 		}
3001 	}
3002 }
3003 //******************************************************************************
3004 // Manage Player Death Visual
3005 //******************************************************************************
ARX_PLAYER_Manage_Death()3006 void ARX_PLAYER_Manage_Death()
3007 {
3008 	PLAYER_PARALYSED = 0;
3009 	float ratio = (float)(DeadTime - 2000) * ( 1.0f / 5000 );
3010 
3011 	if (ratio >= 1.f) ratio = 1.f;
3012 
3013 	if (ratio == 1.f)
3014 	{
3015 		ARX_MENU_Launch();
3016 		DeadTime = 0;
3017 	}
3018 
3019 	{
3020 		GRenderer->SetRenderState(Renderer::AlphaBlending, true);
3021 		GRenderer->SetBlendFunc(Renderer::BlendZero, Renderer::BlendInvSrcColor);
3022 		EERIEDrawBitmap( 0.f, 0.f, static_cast<float>(DANAESIZX), static_cast<float>(DANAESIZY), 0.000091f, NULL, Color::gray(ratio));
3023 
3024 	}
3025 }
3026 //******************************************************************************
3027 // Specific for color checks
3028 //******************************************************************************
GetPlayerStealth()3029 float GetPlayerStealth()
3030 {
3031 	return 15 + player.Full_Skill_Stealth * ( 1.0f / 10 );
3032 }
3033 
3034 // Teleport player to any poly...
ARX_PLAYER_GotoAnyPoly()3035 void ARX_PLAYER_GotoAnyPoly() {
3036 	for(long j = 0; j < ACTIVEBKG->Zsize; j++) {
3037 		for(long i = 0; i < ACTIVEBKG->Xsize; i++) {
3038 			EERIE_BKG_INFO * eg = &ACTIVEBKG->Backg[i + j * ACTIVEBKG->Xsize];
3039 			if(eg->nbpoly) {
3040 				player.pos = moveto = eg->polydata[0].center + player.baseOffset();
3041 			}
3042 		}
3043 	}
3044 }
3045 
3046 // Force Player to standard stance... (Need some improvements...)
ARX_PLAYER_PutPlayerInNormalStance(long val)3047 void ARX_PLAYER_PutPlayerInNormalStance(long val) {
3048 
3049 	if(player.Current_Movement & PLAYER_CROUCH) {
3050 		player.Current_Movement &= ~PLAYER_CROUCH;
3051 	}
3052 
3053 	player.Current_Movement = 0;
3054 	ARX_PLAYER_RectifyPosition();
3055 
3056 	if(player.jumpphase != NotJumping || player.falling) {
3057 		player.physics.cyl.origin = player.basePosition();
3058 		IO_PHYSICS phys;
3059 		memcpy(&phys, &player.physics, sizeof(IO_PHYSICS));
3060 		AttemptValidCylinderPos(&phys.cyl, entities.player(), CFLAG_RETURN_HEIGHT);
3061 		player.pos.y = phys.cyl.origin.y + player.baseHeight();
3062 		player.jumpphase = NotJumping;
3063 		player.falling = 0;
3064 	}
3065 
3066 	if(player.Interface & INTER_COMBATMODE) {
3067 		player.Interface &= ~INTER_COMBATMODE;
3068 		ARX_EQUIPMENT_LaunchPlayerUnReadyWeapon();
3069 	}
3070 
3071 	ARX_SOUND_Stop(SND_MAGIC_DRAW);
3072 
3073 	if(!val) {
3074 		for(size_t i = 0; i < MAX_SPELLS; i++) {
3075 			if(spells[i].exist && (spells[i].caster == 0 || spells[i].target == 0)) {
3076 				switch(spells[i].type) {
3077 					case SPELL_MAGIC_SIGHT:
3078 					case SPELL_LEVITATE:
3079 					case SPELL_SPEED:
3080 					case SPELL_FLYING_EYE:
3081 						spells[i].tolive = 0;
3082 						break;
3083 					default: break;
3084 				}
3085 			}
3086 		}
3087 	}
3088 }
3089 
3090 // Add gold to player purse
ARX_PLAYER_AddGold(long _lValue)3091 void ARX_PLAYER_AddGold(long _lValue) {
3092 	player.gold += _lValue;
3093 	bGoldHalo = true;
3094 	ulGoldHaloTime = 0;
3095 }
3096 
ARX_PLAYER_AddGold(Entity * gold)3097 void ARX_PLAYER_AddGold(Entity * gold) {
3098 
3099 	arx_assert(gold->ioflags & IO_GOLD);
3100 
3101 	ARX_PLAYER_AddGold(gold->_itemdata->price * max((short)1, gold->_itemdata->count));
3102 
3103 	ARX_SOUND_PlayInterface(SND_GOLD);
3104 
3105 	gold->gameFlags &= ~GFLAG_ISINTREATZONE;
3106 
3107 	gold->destroy();
3108 }
3109 
ARX_PLAYER_Start_New_Quest()3110 void ARX_PLAYER_Start_New_Quest() {
3111 
3112 	SKIN_MOD = 0;
3113 	QUICK_MOD = 0;
3114 	EERIE_PATHFINDER_Clear();
3115 	EERIE_PATHFINDER_Release();
3116 	ARX_PLAYER_MakeFreshHero();
3117 	CURRENT_TORCH = NULL;
3118 	entities.clear();
3119 	SecondaryInventory = NULL;
3120 	TSecondaryInventory = NULL;
3121 	ARX_EQUIPMENT_UnEquipAllPlayer();
3122 
3123 	ARX_Changelevel_CurGame_Clear();
3124 
3125 	entities.player()->halo.flags = 0;
3126 }
3127 
3128 //-----------------------------------------------------------------------------
ARX_PLAYER_AddBag()3129 void ARX_PLAYER_AddBag()
3130 {
3131 	++player.bag;
3132 
3133 	if (player.bag > 3)
3134 		player.bag = 3;
3135 }
3136 
3137 //-----------------------------------------------------------------------------
ARX_PLAYER_CanStealItem(Entity * _io)3138 bool ARX_PLAYER_CanStealItem(Entity * _io)
3139 {
3140 	if (_io->_itemdata->stealvalue > 0)
3141 		if ((player.Full_Skill_Stealth >= _io->_itemdata->stealvalue)
3142 		        &&	(_io->_itemdata->stealvalue < 100.f))
3143 		{
3144 			return true;
3145 		}
3146 
3147 	return false;
3148 }
ARX_PLAYER_Rune_Add_All()3149 void ARX_PLAYER_Rune_Add_All()
3150 {
3151 	ARX_Player_Rune_Add(FLAG_AAM);
3152 	ARX_Player_Rune_Add(FLAG_CETRIUS);
3153 	ARX_Player_Rune_Add(FLAG_COMUNICATUM);
3154 	ARX_Player_Rune_Add(FLAG_COSUM);
3155 	ARX_Player_Rune_Add(FLAG_FOLGORA);
3156 	ARX_Player_Rune_Add(FLAG_FRIDD);
3157 	ARX_Player_Rune_Add(FLAG_KAOM);
3158 	ARX_Player_Rune_Add(FLAG_MEGA);
3159 	ARX_Player_Rune_Add(FLAG_MORTE);
3160 	ARX_Player_Rune_Add(FLAG_MOVIS);
3161 	ARX_Player_Rune_Add(FLAG_NHI);
3162 	ARX_Player_Rune_Add(FLAG_RHAA);
3163 	ARX_Player_Rune_Add(FLAG_SPACIUM);
3164 	ARX_Player_Rune_Add(FLAG_STREGUM);
3165 	ARX_Player_Rune_Add(FLAG_TAAR);
3166 	ARX_Player_Rune_Add(FLAG_TEMPUS);
3167 	ARX_Player_Rune_Add(FLAG_TERA);
3168 	ARX_Player_Rune_Add(FLAG_VISTA);
3169 	ARX_Player_Rune_Add(FLAG_VITAE);
3170 	ARX_Player_Rune_Add(FLAG_YOK);
3171 }
3172 
3173 extern unsigned long LAST_PRECAST_TIME;
3174 extern long sp_wep;
3175 extern long WILL_QUICKLOAD, WILL_QUICKSAVE;
3176 extern long GLOBAL_Player_Room;
3177 extern long cur_mx, cur_pom;
3178 extern long sp_arm, cur_arm;
3179 extern float sp_max_start;
3180 
ARX_PLAYER_Invulnerability(long flag)3181 void ARX_PLAYER_Invulnerability(long flag)
3182 {
3183 	if (flag)
3184 		player.playerflags |= PLAYERFLAGS_INVULNERABILITY;
3185 	else
3186 		player.playerflags &= ~PLAYERFLAGS_INVULNERABILITY;
3187 }
3188 extern Entity * FlyingOverIO;
3189 extern long cur_sm;
3190 extern void ClearDynLights();
3191 
ARX_GAME_Reset(long type)3192 void ARX_GAME_Reset(long type) {
3193 
3194 	DeadTime = 0;
3195 
3196 	if(entities.player()) {
3197 		entities.player()->speed_modif = 0;
3198 	}
3199 
3200 	LAST_JUMP_ENDTIME = 0;
3201 	FlyingOverIO = NULL;
3202 	g_miniMap.mapMarkerInit();
3203 	ClearDynLights();
3204 
3205 	if(!DONT_ERASE_PLAYER && entities.player()) {
3206 		entities.player()->halo.flags = 0;
3207 	}
3208 
3209 	if(entities.player())entities.player()->gameFlags &= ~GFLAG_INVISIBILITY;
3210 	ARX_PLAYER_Invulnerability(0);
3211 	GLOBAL_Player_Room = -1;
3212 	PLAYER_PARALYSED = 0;
3213 
3214 	ARX_PLAYER_Reset_Fall();
3215 
3216 	player.levitate = 0;
3217 	Project.telekinesis = 0;
3218 	player.onfirmground = 0;
3219 	TRUE_FIRM_GROUND = 0;
3220 	sp_max_start = 0;
3221 	lastposy = -99999999999.f;
3222 
3223 	ioSteal = NULL;
3224 
3225 	WILL_QUICKLOAD = 0;
3226 	WILL_QUICKSAVE = 0;
3227 	GLOBAL_SLOWDOWN = 1.f;
3228 
3229 	PrecalcIOLighting(NULL, 0, 1);
3230 
3231 	sp_arm = 0;
3232 	cur_arm = 0;
3233 	cur_sm = 0;
3234 	sp_wep = 0;
3235 	sp_max = 0;
3236 	cur_mx = 0;
3237 	cur_pom = 0;
3238 	cur_rf = 0;
3239 	cur_mr = 0;
3240 
3241 
3242 	if(entities.player()) {
3243 		entities.player()->spellcast_data.castingspell = SPELL_NONE;
3244 	}
3245 
3246 	LAST_PRECAST_TIME = 0;
3247 
3248 	ARX_INTERFACE_NoteClear();
3249 	player.Interface = INTER_LIFE_MANA | INTER_MINIBACK | INTER_MINIBOOK;
3250 
3251 	// Interactive DynData
3252 	ARX_INTERACTIVE_ClearAllDynData();
3253 
3254 	// PolyBooms
3255 	ARX_BOOMS_ClearAllPolyBooms();
3256 
3257 	// Magical Flares
3258 	ARX_MAGICAL_FLARES_KillAll();
3259 
3260 	// Thrown Objects
3261 	ARX_THROWN_OBJECT_KillAll();
3262 
3263 	// Pathfinder
3264 	EERIE_PATHFINDER_Clear();
3265 
3266 	// Sound
3267 	if (!(type & 1))
3268 	{
3269 		ARX_SOUND_MixerStop(ARX_SOUND_MixerGame);
3270 		ARX_SOUND_MixerPause(ARX_SOUND_MixerGame);
3271 		ARX_SOUND_MixerResume(ARX_SOUND_MixerGame);
3272 	}
3273 
3274 	// Damages
3275 	ARX_DAMAGE_Reset_Blood_Info();
3276 	ARX_DAMAGES_Reset();
3277 
3278 	// Scripts
3279 	ARX_SCRIPT_Timer_ClearAll();
3280 	ARX_SCRIPT_EventStackClear();
3281 	ARX_SCRIPT_ResetAll(0);
3282 
3283 	// Conversations
3284 	ARX_CONVERSATION_Reset();
3285 	ARX_CONVERSATION = 0;
3286 
3287 	// Speech Things
3288 	REQUEST_SPEECH_SKIP = 0;
3289 	ARX_SPEECH_ClearAll();
3290 	ARX_SPEECH_Reset();
3291 
3292 	// Spells
3293 	ARX_SPELLS_Precast_Reset();
3294 	ARX_SPELLS_CancelSpellTarget();
3295 
3296 	ARX_SPELLS_ClearAll();
3297 	ARX_SPELLS_ClearAllSymbolDraw();
3298 	ARX_SPELLS_ResetRecognition();
3299 
3300 	// Particles
3301 	ARX_PARTICLES_ClearAll();
3302 	if(pParticleManager)
3303 		pParticleManager->Clear();
3304 
3305 	// Fogs
3306 	ARX_FOGS_TimeReset();
3307 	ARX_FOGS_Render();
3308 
3309 	// Anchors
3310 	ANCHOR_BLOCK_Clear();
3311 
3312 	// Attractors
3313 	ARX_SPECIAL_ATTRACTORS_Reset();
3314 
3315 	// Cinematics
3316 	DANAE_KillCinematic();
3317 
3318 	// Paths
3319 	ARX_PATH_ClearAllControled();
3320 	ARX_PATH_ClearAllUsePath();
3321 
3322 	// Player Torch
3323 	if (type & 1)
3324 	{
3325 		if (CURRENT_TORCH) ARX_PLAYER_ClickedOnTorch(CURRENT_TORCH);
3326 	}
3327 	else
3328 		CURRENT_TORCH = NULL;
3329 
3330 	// Player Quests
3331 	ARX_PLAYER_Quest_Init();
3332 
3333 	// Player Keyring
3334 	ARX_KEYRING_Init();
3335 
3336 	// Player Init
3337 	if (!DONT_ERASE_PLAYER)
3338 	{
3339 		g_miniMap.mapMarkerInit();
3340 		GLOBAL_MAGIC_MODE = 1;
3341 
3342 		// Linked Objects
3343 		if (!(type & 2))
3344 		{
3345 			UnlinkAllLinkedObjects();
3346 			ARX_EQUIPMENT_UnEquipAllPlayer();
3347 		}
3348 
3349 		ARX_EQUIPMENT_ReleaseAll(entities.player());
3350 
3351 		ARX_PLAYER_InitPlayer();
3352 		ARX_INTERACTIVE_RemoveGoreOnIO(entities.player());
3353 
3354 		// default to mouselook on, inventory closed
3355 		TRUE_PLAYER_MOUSELOOK_ON = true;
3356 
3357 		// Player Inventory
3358 		CleanInventory();
3359 	}
3360 
3361 	// Misc Player Vars.
3362 	ROTATE_START = 0;
3363 	BLOCK_PLAYER_CONTROLS = 0;
3364 	HERO_SHOW_1ST = -1;
3365 	PUSH_PLAYER_FORCE = Vec3f::ZERO;
3366 	player.jumplastposition = 0;
3367 	player.jumpstarttime = 0;
3368 	player.jumpphase = NotJumping;
3369 	player.inzone = NULL;
3370 
3371 	QuakeFx.intensity = 0.f;
3372 	Project.improve = 0;
3373 
3374 	if (eyeball.exist) eyeball.exist = -100;
3375 
3376 	if(entities.size() > 0 && entities.player()) {
3377 		entities.player()->ouch_time = 0;
3378 		entities.player()->invisibility = 0.f;
3379 	}
3380 
3381 	FADEDIR = 0;
3382 	FADEDURATION = 0;
3383 	FADESTART = 0;
3384 	FADECOLOR = Color3f::black;
3385 
3386 	// GLOBALMods
3387 	ARX_GLOBALMODS_Reset();
3388 
3389 	// Missiles
3390 	ARX_MISSILES_ClearAll();
3391 
3392 	// IO PDL
3393 	TOTIOPDL = 0;
3394 
3395 	// Interface
3396 	ARX_INTERFACE_Reset();
3397 	ARX_INTERFACE_NoteClear();
3398 	Set_DragInter(NULL);
3399 	SecondaryInventory = NULL;
3400 	TSecondaryInventory = NULL;
3401 	MasterCamera.exist = 0;
3402 	CHANGE_LEVEL_ICON = -1;
3403 
3404 	CAMERACONTROLLER = NULL;
3405 
3406 	// Kill Script Loaded IO
3407 	CleanScriptLoadedIO();
3408 
3409 	// ARX Timer
3410 	arxtime.init();
3411 
3412 	ClearTileLights();
3413 }
3414 
ARX_PLAYER_Reset_Fall()3415 void ARX_PLAYER_Reset_Fall()
3416 {
3417 	FALLING_TIME = 0;
3418 	Falling_Height = 50.f;
3419 	player.falling = 0;
3420 }
3421 
3422 
3423 
3424 float sp_max_y[64];
3425 Color sp_max_col[64];
3426 char	sp_max_ch[64];
3427 long sp_max_nb;
Manage_sp_max()3428 void Manage_sp_max()
3429 {
3430 	float v = float(arxtime) - sp_max_start;
3431 
3432 	if ((sp_max_start != 0) && (v < 20000))
3433 	{
3434 		float modi = (20000 - v) * ( 1.0f / 2000 ) * ( 1.0f / 10 );
3435 		float sizX = 16;
3436 		float px = (float)DANAECENTERX - (float)sp_max_nb * ( 1.0f / 2 ) * sizX;
3437 		float py = (float)DANAECENTERY;
3438 
3439 		for (long i = 0; i < sp_max_nb; i++)
3440 		{
3441 			float dx = px + sizX * (float)i;
3442 			float dy = py + sp_max_y[i];
3443 			sp_max_y[i] = EEsin(dx + (float)float(arxtime) * ( 1.0f / 100 )) * 30.f * modi;
3444 			std::string tex( 1, sp_max_ch[i] );
3445 
3446 			UNICODE_ARXDrawTextCenter( hFontInBook, dx - 1, dy - 1, tex, Color::none );
3447 			UNICODE_ARXDrawTextCenter( hFontInBook, dx + 1, dy + 1, tex, Color::none );
3448 			UNICODE_ARXDrawTextCenter( hFontInBook, dx, dy, tex, sp_max_col[i] );
3449 
3450 		}
3451 	}
3452 }
3453