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-2001 ARKANE Studios SA. All rights reserved
46 
47 #include <cctype>
48 #include <cstdlib>
49 #include <cstring>
50 #include <algorithm>
51 #include <vector>
52 
53 #include <boost/algorithm/string/predicate.hpp>
54 #include <boost/lexical_cast.hpp>
55 
56 #include "game/Damage.h"
57 #include "game/EntityManager.h"
58 #include "game/Equipment.h"
59 #include "game/Inventory.h"
60 #include "game/Item.h"
61 #include "game/NPC.h"
62 #include "game/Player.h"
63 #include "game/Spells.h"
64 
65 #include "gui/Interface.h"
66 
67 #include "graphics/BaseGraphicsTypes.h"
68 #include "graphics/Color.h"
69 #include "graphics/GraphicsTypes.h"
70 #include "graphics/Math.h"
71 #include "graphics/Vertex.h"
72 #include "graphics/data/Mesh.h"
73 #include "graphics/data/MeshManipulation.h"
74 #include "graphics/data/TextureContainer.h"
75 #include "graphics/particle/ParticleEffects.h"
76 
77 #include "io/resource/ResourcePath.h"
78 
79 #include "math/Random.h"
80 #include "math/Vector2.h"
81 #include "math/Vector3.h"
82 
83 #include "physics/Collisions.h"
84 
85 #include "platform/Platform.h"
86 
87 #include "scene/Object.h"
88 #include "scene/LinkedObject.h"
89 #include "scene/GameSound.h"
90 #include "scene/Interactive.h"
91 
92 #include "script/Script.h"
93 
94 using std::min;
95 using std::max;
96 using std::string;
97 
98 struct EQUIP_INFO
99 {
100 	char name[64];
101 };
102 
103 #define SP_SPARKING 1
104 #define SP_BLOODY 2
105 
106 extern Vec3f PUSH_PLAYER_FORCE;
107 extern long HERO_SHOW_1ST;
108 extern long EXTERNALVIEW;
109 
110 extern EERIE_3DOBJ * arrowobj;
111 
112 EQUIP_INFO equipinfo[IO_EQUIPITEM_ELEMENT_Number];
113 
114 //***********************************************************************************************
115 // Returns the object type flag corresponding to a string
116 //-----------------------------------------------------------------------------------------------
117 // VERIFIED (Cyril 2001/10/29)
118 //***********************************************************************************************
ARX_EQUIPMENT_GetObjectTypeFlag(const string & temp)119 ItemType ARX_EQUIPMENT_GetObjectTypeFlag(const string & temp) {
120 
121 	if(temp.empty()) {
122 		return 0;
123 	}
124 
125 	char c = temp[0];
126 
127 	arx_assert(std::tolower(c) == c);
128 
129 	switch(c) {
130 		case 'w':
131 			return OBJECT_TYPE_WEAPON;
132 		case 'd':
133 			return OBJECT_TYPE_DAGGER;
134 		case '1':
135 			return OBJECT_TYPE_1H;
136 		case '2':
137 			return OBJECT_TYPE_2H;
138 		case 'b':
139 			return OBJECT_TYPE_BOW;
140 		case 's':
141 			return OBJECT_TYPE_SHIELD;
142 		case 'f':
143 			return OBJECT_TYPE_FOOD;
144 		case 'g':
145 			return OBJECT_TYPE_GOLD;
146 		case 'r':
147 			return OBJECT_TYPE_RING;
148 		case 'a':
149 			return OBJECT_TYPE_ARMOR;
150 		case 'h':
151 			return OBJECT_TYPE_HELMET;
152 		case 'l':
153 			return OBJECT_TYPE_LEGGINGS;
154 	}
155 
156 	return 0;
157 }
158 //***********************************************************************************************
159 // Releases Equiped Id from player
160 //-----------------------------------------------------------------------------------------------
161 // VERIFIED (Cyril 2001/10/29)
162 //***********************************************************************************************
ARX_EQUIPMENT_Release(long id)163 void ARX_EQUIPMENT_Release(long id)
164 {
165 	if (id)
166 	{
167 		for (long i = 0; i < MAX_EQUIPED; i++)
168 		{
169 			if (player.equiped[i] == id)
170 			{
171 				player.equiped[i] = 0;
172 			}
173 		}
174 	}
175 }
176 
177 // Releases Equipment Structure
ARX_EQUIPMENT_ReleaseAll(Entity * io)178 void ARX_EQUIPMENT_ReleaseAll(Entity * io) {
179 
180 	if(!io || !(io->ioflags & IO_ITEM)) {
181 		return;
182 	}
183 
184 	free(io->_itemdata->equipitem), io->_itemdata->equipitem = NULL;
185 }
186 
187 extern long EXITING;
188 
189 // Recreates player mesh from scratch
applyTweak(EquipmentSlot equip,TweakType tw,const string & selection)190 static void applyTweak(EquipmentSlot equip, TweakType tw, const string & selection) {
191 
192 	if(!player.equiped[equip] || !ValidIONum(player.equiped[equip])) {
193 		return;
194 	}
195 
196 	Entity * io = entities.player();
197 
198 	arx_assert(entities[player.equiped[equip]]->tweakerinfo != NULL);
199 
200 	const IO_TWEAKER_INFO & tweak = *entities[player.equiped[equip]]->tweakerinfo;
201 
202 	if(!tweak.filename.empty()) {
203 		res::path mesh = "graph/obj3d/interactive/npc/human_base/tweaks" / tweak.filename;
204 		EERIE_MESH_TWEAK_Do(io, tw, mesh);
205 	}
206 
207 	if(tweak.skintochange.empty() || tweak.skinchangeto.empty()) {
208 		return;
209 	}
210 
211 	res::path file = "graph/obj3d/textures" / tweak.skinchangeto;
212 	TextureContainer * temp = TextureContainer::Load(file, TextureContainer::Level);
213 
214 	long mapidx = ObjectAddMap(io->obj, temp);
215 
216 	long sel = -1;
217 	for(size_t i = 0; i < io->obj->selections.size(); i++) {
218 		if(io->obj->selections[i].name == selection) {
219 			sel = i;
220 			break;
221 		}
222 	}
223 	if(sel == -1) {
224 		return;
225 	}
226 
227 	long textochange = -1;
228 	for(size_t i = 0; i < io->obj->texturecontainer.size(); i++) {
229 		if(tweak.skintochange == io->obj->texturecontainer[i]->m_texName.filename()) {
230 			textochange = i;
231 		}
232 	}
233 	if(textochange == -1) {
234 		return;
235 	}
236 
237 	for(size_t i = 0; i < io->obj->facelist.size(); i++) {
238 		if(IsInSelection(io->obj, io->obj->facelist[i].vid[0], sel) != -1
239 		   && IsInSelection(io->obj, io->obj->facelist[i].vid[1], sel) != -1
240 		   && IsInSelection(io->obj, io->obj->facelist[i].vid[2], sel) != -1) {
241 			if(io->obj->facelist[i].texid == textochange) {
242 				io->obj->facelist[i].texid = (short)mapidx;
243 			}
244 		}
245 	}
246 
247 }
248 
ARX_EQUIPMENT_RecreatePlayerMesh()249 void ARX_EQUIPMENT_RecreatePlayerMesh() {
250 
251 	if(EXITING) {
252 		return;
253 	}
254 
255 	Entity * io = entities.player();
256 	if(!io) {
257 		return;
258 	}
259 
260 	if(io->obj != hero) {
261 		delete io->obj;
262 	}
263 	io->obj = loadObject("graph/obj3d/interactive/npc/human_base/human_base.teo", false);
264 
265 	applyTweak(EQUIP_SLOT_HELMET, TWEAK_HEAD, "head");
266 	applyTweak(EQUIP_SLOT_ARMOR, TWEAK_TORSO, "chest");
267 	applyTweak(EQUIP_SLOT_LEGGINGS, TWEAK_LEGS, "leggings");
268 
269 	Entity * target = entities.player();
270 	Entity * toequip = NULL;
271 
272 	if (!target) return;
273 
274 	for (long i = 0; i < MAX_EQUIPED; i++)
275 	{
276 		if ((player.equiped[i] != 0)
277 		        &&	ValidIONum(player.equiped[i]))
278 		{
279 			toequip = entities[player.equiped[i]];
280 
281 			if (toequip)
282 			{
283 				if (toequip->type_flags & (OBJECT_TYPE_DAGGER
284 				                           |	OBJECT_TYPE_1H
285 				                           |	OBJECT_TYPE_2H
286 				                           |	OBJECT_TYPE_BOW))
287 				{
288 					if (player.Interface & INTER_COMBATMODE)
289 					{
290 						ARX_EQUIPMENT_AttachPlayerWeaponToHand();
291 					}
292 					else
293 					{
294 						EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "weapon_attach", "primary_attach", toequip); //
295 					}
296 				}
297 				else if (toequip->type_flags & OBJECT_TYPE_SHIELD)
298 				{
299 					if (player.equiped[EQUIP_SLOT_SHIELD] != 0)
300 					{
301 						EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "shield_attach", "shield_attach", toequip);
302 					}
303 
304 				}
305 			}
306 		}
307 	}
308 
309 	ARX_PLAYER_Restore_Skin();
310 	HERO_SHOW_1ST = -1;
311 
312 	if (EXTERNALVIEW)
313 	{
314 		ARX_INTERACTIVE_Show_Hide_1st(entities.player(), 0);
315 	}
316 	else
317 	{
318 		ARX_INTERACTIVE_Show_Hide_1st(entities.player(), 1);
319 	}
320 
321 	ARX_INTERACTIVE_HideGore(entities.player(), 1);
322 	EERIE_Object_Precompute_Fast_Access(hero);
323 	EERIE_Object_Precompute_Fast_Access(entities.player()->obj);
324 
325 	ARX_INTERACTIVE_RemoveGoreOnIO(entities.player());
326 }
327 
ARX_EQUIPMENT_UnEquipAllPlayer()328 void ARX_EQUIPMENT_UnEquipAllPlayer()
329 {
330 	for (long i = 0; i < MAX_EQUIPED; i++)
331 	{
332 		if ((player.equiped[i]) && (ValidIONum(player.equiped[i])))
333 		{
334 			ARX_EQUIPMENT_UnEquip(entities.player(), entities[player.equiped[i]]);
335 		}
336 	}
337 
338 	ARX_PLAYER_ComputePlayerFullStats();
339 }
340 
341 
ARX_EQUIPMENT_IsPlayerEquip(Entity * _pIO)342 bool ARX_EQUIPMENT_IsPlayerEquip(Entity * _pIO)
343 {
344 	Entity * io = entities.player();
345 
346 	if (io == NULL) return false;
347 
348 	if (io != entities.player()) return false;
349 
350 	for (long i = 0; i < MAX_EQUIPED; i++)
351 	{
352 		if ((player.equiped[i] != 0) &&
353 		        ValidIONum(player.equiped[i]))
354 		{
355 			Entity * toequip = entities[player.equiped[i]];
356 
357 			if (toequip == _pIO)
358 			{
359 				return true;
360 			}
361 		}
362 	}
363 
364 	return false;
365 }
366 
367 
368 //***********************************************************************************************
369 // flags & 1 == destroyed !
370 //***********************************************************************************************
ARX_EQUIPMENT_UnEquip(Entity * target,Entity * tounequip,long flags)371 void ARX_EQUIPMENT_UnEquip(Entity * target, Entity * tounequip, long flags)
372 {
373 	if (target == NULL) return;
374 
375 	if (tounequip == NULL) return;
376 
377 	if (target != entities.player()) return;
378 
379 	for (long i = 0; i < MAX_EQUIPED; i++)
380 	{
381 		if ((player.equiped[i] != 0)
382 		        &&	ValidIONum(player.equiped[i])
383 		        &&	(entities[player.equiped[i]] == tounequip))
384 		{
385 			EERIE_LINKEDOBJ_UnLinkObjectFromObject(target->obj, tounequip->obj);
386 			ARX_EQUIPMENT_Release(player.equiped[i]);
387 			target->bbox1.x = 9999;
388 			target->bbox2.x = -9999;
389 
390 			if(!flags & 1) {
391 				if(DRAGINTER == NULL) {
392 					ARX_SOUND_PlayInterface(SND_INVSTD);
393 					Set_DragInter(tounequip);
394 				} else {
395 					giveToPlayer(tounequip);
396 				}
397 			}
398 
399 			EVENT_SENDER = tounequip;
400 			SendIOScriptEvent(entities.player(), SM_EQUIPOUT);
401 			EVENT_SENDER = entities.player();
402 			SendIOScriptEvent(tounequip, SM_EQUIPOUT);
403 		}
404 	}
405 
406 	if ((tounequip->type_flags & OBJECT_TYPE_HELMET)
407 	        ||	(tounequip->type_flags & OBJECT_TYPE_ARMOR)
408 	        ||	(tounequip->type_flags & OBJECT_TYPE_LEGGINGS))
409 		ARX_EQUIPMENT_RecreatePlayerMesh();
410 }
411 //***********************************************************************************************
412 //***********************************************************************************************
ARX_EQUIPMENT_AttachPlayerWeaponToHand()413 void ARX_EQUIPMENT_AttachPlayerWeaponToHand()
414 {
415 	Entity * target = entities.player();
416 	Entity * toequip = NULL;
417 
418 	if (!target) return;
419 
420 	for (long i = 0; i < MAX_EQUIPED; i++)
421 	{
422 		if ((player.equiped[i] != 0)
423 		        &&	ValidIONum(player.equiped[i]))
424 		{
425 			toequip = entities[player.equiped[i]];
426 
427 			if (toequip)
428 			{
429 				if ((toequip->type_flags & OBJECT_TYPE_DAGGER)
430 				        ||	(toequip->type_flags & OBJECT_TYPE_1H)
431 				        ||	(toequip->type_flags & OBJECT_TYPE_2H)
432 				        ||	(toequip->type_flags & OBJECT_TYPE_BOW)
433 				   )
434 				{
435 					EERIE_LINKEDOBJ_UnLinkObjectFromObject(target->obj, toequip->obj);
436 					EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "primary_attach", "primary_attach", toequip); //
437 					return;
438 				}
439 			}
440 		}
441 	}
442 }
443 //***********************************************************************************************
444 //***********************************************************************************************
ARX_EQUIPMENT_AttachPlayerWeaponToBack()445 void ARX_EQUIPMENT_AttachPlayerWeaponToBack()
446 {
447 	Entity * target = entities.player();
448 	Entity * toequip = NULL;
449 
450 	if (!target) return;
451 
452 	for (long i = 0; i < MAX_EQUIPED; i++)
453 	{
454 		if ((player.equiped[i] != 0)
455 		        &&	ValidIONum(player.equiped[i]))
456 		{
457 			toequip = entities[player.equiped[i]];
458 
459 			if (toequip)
460 			{
461 				if ((toequip->type_flags & OBJECT_TYPE_DAGGER)
462 				        ||	(toequip->type_flags & OBJECT_TYPE_1H)
463 				        ||	(toequip->type_flags & OBJECT_TYPE_2H)
464 				        ||	(toequip->type_flags & OBJECT_TYPE_BOW)
465 				   )
466 				{
467 					if (toequip->type_flags & OBJECT_TYPE_BOW)
468 					{
469 						EERIE_LINKEDOBJ_UnLinkObjectFromObject(target->obj, toequip->obj);
470 						EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "weapon_attach", "test", toequip); //
471 						return;
472 					}
473 
474 					EERIE_LINKEDOBJ_UnLinkObjectFromObject(target->obj, toequip->obj);
475 					EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "weapon_attach", "primary_attach", toequip); //
476 					return;
477 				}
478 			}
479 		}
480 	}
481 }
482 //***********************************************************************************************
483 //***********************************************************************************************
ARX_EQUIPMENT_GetPlayerWeaponType()484 long ARX_EQUIPMENT_GetPlayerWeaponType()
485 {
486 	Entity * io = entities.player();
487 
488 	if (!io) return WEAPON_BARE;
489 
490 	if ((player.equiped[EQUIP_SLOT_WEAPON] != 0)
491 	        &&	ValidIONum(player.equiped[EQUIP_SLOT_WEAPON]))
492 	{
493 		Entity * toequip = entities[player.equiped[EQUIP_SLOT_WEAPON]];
494 
495 		if (toequip)
496 		{
497 			if (toequip->type_flags & OBJECT_TYPE_DAGGER)	return WEAPON_DAGGER;
498 
499 			if (toequip->type_flags & OBJECT_TYPE_1H)		return WEAPON_1H;
500 
501 			if (toequip->type_flags & OBJECT_TYPE_2H)		return WEAPON_2H;
502 
503 			if (toequip->type_flags & OBJECT_TYPE_BOW)		return WEAPON_BOW;
504 		}
505 	}
506 
507 	return WEAPON_BARE;
508 }
509 //***********************************************************************************************
510 //***********************************************************************************************
ARX_EQUIPMENT_LaunchPlayerUnReadyWeapon()511 void ARX_EQUIPMENT_LaunchPlayerUnReadyWeapon()
512 {
513 	Entity * io = entities.player();
514 
515 	if (!io) return;
516 
517 	ANIM_HANDLE * anim;
518 	long type = ARX_EQUIPMENT_GetPlayerWeaponType();
519 
520 	switch (type)
521 	{
522 		case WEAPON_DAGGER:
523 			anim = io->anims[ANIM_DAGGER_UNREADY_PART_1];
524 			break;
525 		case WEAPON_1H:
526 			anim = io->anims[ANIM_1H_UNREADY_PART_1];
527 			break;
528 		case WEAPON_2H:
529 			anim = io->anims[ANIM_2H_UNREADY_PART_1];
530 			break;
531 		case WEAPON_BOW:
532 		{
533 			anim = io->anims[ANIM_MISSILE_UNREADY_PART_1];
534 
535 			if (arrowobj)
536 			{
537 				EERIE_LINKEDOBJ_UnLinkObjectFromObject(io->obj, arrowobj);
538 			}
539 		}
540 		break;
541 		default:
542 			anim = io->anims[ANIM_BARE_UNREADY];
543 			break;
544 	}
545 
546 	AcquireLastAnim(io);
547 	ANIM_Set(&io->animlayer[1], anim);
548 }
549 //***********************************************************************************************
550 //***********************************************************************************************
ARX_EQUIPMENT_ComputeDamages(Entity * io_source,Entity * io_target,float ratioaim,Vec3f * position)551 float ARX_EQUIPMENT_ComputeDamages(Entity * io_source, Entity * io_target, float ratioaim, Vec3f * position)
552 {
553 	EVENT_SENDER = io_source;
554 	SendIOScriptEvent(io_target, SM_AGGRESSION);
555 
556 	if ((!io_source)
557 	        ||	(!io_target))
558 		return 0.f;
559 
560 	if (!(io_target->ioflags & IO_NPC))
561 	{
562 		if (io_target->ioflags & IO_FIX)
563 		{
564 			if (io_source == entities.player())
565 				ARX_DAMAGES_DamageFIX(io_target, player.Full_damages, 0, 0);
566 			else if (io_source->ioflags & IO_NPC)
567 				ARX_DAMAGES_DamageFIX(io_target, io_source->_npcdata->damages, io_source->index(), 0);
568 			else
569 				ARX_DAMAGES_DamageFIX(io_target, 1, io_source->index(), 0);
570 		}
571 
572 		return 0.f;
573 	}
574 
575 	float attack, ac, damages;
576 	float backstab = 1.f;
577 
578 	string _wmat = "bare";
579 	const string * wmat = &_wmat;
580 
581 	string _amat = "flesh";
582 	const string * amat = &_amat;
583 
584 	bool critical = false;
585 
586 	if(io_source == entities.player()) {
587 
588 		if(player.equiped[EQUIP_SLOT_WEAPON] != 0 && ValidIONum(player.equiped[EQUIP_SLOT_WEAPON])) {
589 			Entity * io = entities[player.equiped[EQUIP_SLOT_WEAPON]];
590 			if(io && !io->weaponmaterial.empty()) {
591 				wmat = &io->weaponmaterial;
592 			}
593 		}
594 
595 		attack = player.Full_damages;
596 
597 		if (rnd() * 100 <= (float)(player.Full_Attribute_Dexterity - 9) * 2.f + (float)(player.Full_Skill_Close_Combat * ( 1.0f / 5 )))
598 		{
599 			if (SendIOScriptEvent(io_source, SM_CRITICAL) != REFUSE)
600 				critical = true;
601 		}
602 		else critical = false;
603 
604 		damages = attack * ratioaim;
605 
606 		if (io_target->_npcdata->npcflags & NPCFLAG_BACKSTAB)
607 		{
608 			if (rnd() * 100.f <= player.Full_Skill_Stealth * ( 1.0f / 2 ))
609 			{
610 				if (SendIOScriptEvent(io_source, SM_BACKSTAB) != REFUSE)
611 					backstab = 1.5f;
612 			}
613 		}
614 	}
615 	else
616 	{
617 		if (!(io_source->ioflags & IO_NPC)) return 0.f; // no NPC source...
618 
619 		if(!io_source->weaponmaterial.empty()){
620 			wmat = &io_source->weaponmaterial;
621 		}
622 
623 		if(io_source->_npcdata->weapon != NULL) {
624 			Entity * iow = io_source->_npcdata->weapon;
625 			if(!iow->weaponmaterial.empty()) {
626 				wmat = &iow->weaponmaterial;
627 			}
628 		}
629 
630 		attack = io_source->_npcdata->tohit;
631 
632 		damages = io_source->_npcdata->damages * ratioaim * (rnd() * ( 1.0f / 2 ) + 0.5f);
633 
634 		long value = ARX_SPELLS_GetSpellOn(io_source, SPELL_CURSE);
635 
636 		if (value >= 0)
637 		{
638 			damages *= (spells[value].caster_level * 0.05f);
639 		}
640 
641 		if (rnd() * 100 <= io_source->_npcdata->critical)
642 		{
643 			if (SendIOScriptEvent(io_source, SM_CRITICAL) != REFUSE)
644 				critical = true;
645 		}
646 		else critical = false;
647 
648 		if (rnd() * 100.f <= (float)io_source->_npcdata->backstab_skill)
649 		{
650 			if (SendIOScriptEvent(io_source, SM_BACKSTAB) != REFUSE)
651 				backstab = 1.5f;
652 		}
653 	}
654 
655 	float absorb;
656 
657 	if (io_target == entities.player())
658 	{
659 		ac = player.Full_armor_class;
660 		absorb = player.Full_Skill_Defense * ( 1.0f / 2 );
661 	}
662 	else
663 	{
664 		ac = ARX_INTERACTIVE_GetArmorClass(io_target);
665 		absorb = io_target->_npcdata->absorb;
666 		long value = ARX_SPELLS_GetSpellOn(io_target, SPELL_CURSE);
667 
668 		if (value >= 0)
669 		{
670 			float modif = (spells[value].caster_level * 0.05f);
671 			ac *= modif;
672 			absorb *= modif;
673 		}
674 	}
675 
676 	if(!io_target->armormaterial.empty()) {
677 		amat = &io_target->armormaterial;
678 	}
679 
680 	if(io_target == entities.player()) {
681 		if(player.equiped[EQUIP_SLOT_ARMOR] > 0
682 		   && ValidIONum(player.equiped[EQUIP_SLOT_ARMOR])) {
683 			Entity * io = entities[player.equiped[EQUIP_SLOT_ARMOR]];
684 			if(io && !io->armormaterial.empty()) {
685 				amat = &io->armormaterial;
686 			}
687 		}
688 	}
689 
690 	float dmgs = damages * backstab;
691 	dmgs -= dmgs * absorb * 0.01f;
692 
693 	Vec3f pos = io_target->pos;
694 	float power = std::min(1.f, dmgs * 0.05f) * 0.1f + 0.9f;
695 
696 	ARX_SOUND_PlayCollision(*amat, *wmat, power, 1.f, &pos, io_source);
697 
698 	float chance = 100.f - (ac - attack);
699 	if(rnd() * 100.f > chance) {
700 		return 0.f;
701 	}
702 
703 	ARX_SOUND_PlayCollision("flesh", *wmat, power, 1.f, &pos, io_source);
704 
705 	if(dmgs > 0.f) {
706 
707 		if(critical) {
708 			dmgs *= 1.5f;
709 		}
710 
711 		if(io_target == entities.player()) {
712 
713 			// TODO should this be player.pos - player.baseOffset() = player.basePosition()?
714 			Vec3f ppos = io_source->pos - (player.pos + player.baseOffset());
715 			fnormalize(ppos);
716 
717 			// Push the player
718 			PUSH_PLAYER_FORCE += ppos * -dmgs * Vec3f(1.0f / 11, 1.0f / 30, 1.0f / 11);
719 
720 			ppos *= 60.f;
721 			ppos += ACTIVECAM->pos;
722 			ARX_DAMAGES_DamagePlayer(dmgs, 0, io_source->index());
723 			ARX_DAMAGES_DamagePlayerEquipment(dmgs);
724 
725 		} else {
726 
727 			Vec3f ppos = io_source->pos - io_target->pos;
728 			fnormalize(ppos);
729 
730 			// Push the NPC
731 			io_target->forcedmove += ppos * -dmgs;
732 
733 			Vec3f * pos = position ? position : &io_target->pos;
734 			ARX_DAMAGES_DamageNPC(io_target, dmgs, io_source->index(), 0, pos);
735 		}
736 	}
737 
738 	return dmgs;
739 }
740 
ARX_EQUIPMENT_GetSpecialValue(Entity * io,long val)741 static float ARX_EQUIPMENT_GetSpecialValue(Entity * io, long val) {
742 
743 	if ((!io) || !(io->ioflags & IO_ITEM) || !io->_itemdata->equipitem) return -1;
744 
745 	for (long i = IO_EQUIPITEM_ELEMENT_SPECIAL_1; i <= IO_EQUIPITEM_ELEMENT_SPECIAL_4; i++)
746 	{
747 		if (io->_itemdata->equipitem->elements[i].special == val)
748 		{
749 			return (io->_itemdata->equipitem->elements[i].value);
750 		}
751 	}
752 
753 	return -1;
754 }
755 
756 //***********************************************************************************************
757 // flags & 1 = blood spawn only
758 //-----------------------------------------------------------------------------------------------
759 //***********************************************************************************************
ARX_EQUIPMENT_Strike_Check(Entity * io_source,Entity * io_weapon,float ratioaim,long flags,long targ)760 bool ARX_EQUIPMENT_Strike_Check(Entity * io_source, Entity * io_weapon, float ratioaim, long flags, long targ)
761 {
762 
763 	bool ret = false;
764 	long source = (io_source == NULL) ? -1 : io_source->index();
765 	long weapon = io_weapon->index();
766 	EERIE_SPHERE sphere;
767 
768 	Vec3f * v0;
769 	EXCEPTIONS_LIST_Pos = 0;
770 	float rad;
771 
772 	long nbact = io_weapon->obj->actionlist.size();
773 	float drain_life = ARX_EQUIPMENT_GetSpecialValue(io_weapon, IO_SPECIAL_ELEM_DRAIN_LIFE);
774 	float paralyse = ARX_EQUIPMENT_GetSpecialValue(io_weapon, IO_SPECIAL_ELEM_PARALYZE);
775 
776 	for (long j = 0; j < nbact; j++) // TODO iterator
777 	{
778 		if (!ValidIONum(weapon)) return false;
779 
780 		rad = GetHitValue(io_weapon->obj->actionlist[j].name);
781 
782 		if (rad == -1) continue;
783 
784 		v0 = &io_weapon->obj->vertexlist3[io_weapon->obj->actionlist[j].idx].v;
785 		sphere.origin = *v0;
786 
787 		sphere.radius = rad;
788 
789 		if (source != 0) sphere.radius += 15.f;
790 
791 		if (CheckEverythingInSphere(&sphere, source, targ))
792 		{
793 			for (size_t jj = 0; jj < MAX_IN_SPHERE_Pos; jj++)
794 			{
795 				if (ValidIONum(EVERYTHING_IN_SPHERE[jj])
796 				        && (!(entities[EVERYTHING_IN_SPHERE[jj]]->ioflags & IO_BODY_CHUNK)))
797 				{
798 					long HIT_SPARK = 0;
799 					EXCEPTIONS_LIST[EXCEPTIONS_LIST_Pos] = EVERYTHING_IN_SPHERE[jj];
800 					EXCEPTIONS_LIST_Pos++;
801 
802 					if (EXCEPTIONS_LIST_Pos >= MAX_IN_SPHERE) EXCEPTIONS_LIST_Pos--;
803 
804 					Entity * target = entities[EVERYTHING_IN_SPHERE[jj]];
805 
806 					Vec3f	pos;
807 					Color color = Color::white;
808 					long		hitpoint	=	-1;
809 					float		curdist		=	999999.f;
810 
811 					Vec3f vector = (sphere.origin - target->pos) * Vec3f(1.f, 0.5f, 1.f);
812 					vector.normalize();
813 
814 					for (size_t ii = 0; ii < target->obj->facelist.size(); ii++)
815 					{
816 						if (target->obj->facelist[ii].facetype & POLY_HIDE) continue;
817 
818 						float d = dist(sphere.origin, target->obj->vertexlist3[target->obj->facelist[ii].vid[0]].v);
819 
820 						if (d < curdist)
821 						{
822 							hitpoint = target->obj->facelist[ii].vid[0];
823 							curdist = d;
824 						}
825 					}
826 
827 					if(hitpoint >= 0) {
828 						color = (target->ioflags & IO_NPC) ? target->_npcdata->blood_color : Color::white;
829 						pos = target->obj->vertexlist3[hitpoint].v;
830 					}
831 					else ARX_DEAD_CODE();
832 
833 					float dmgs = 0.f;
834 					if (!(flags & 1))
835 					{
836 						Vec3f posi;
837 
838 						if (hitpoint >= 0)
839 						{
840 							posi = target->obj->vertexlist3[hitpoint].v;
841 							dmgs = ARX_EQUIPMENT_ComputeDamages(io_source, target, ratioaim, &posi);
842 
843 						}
844 						else
845 						{
846 							dmgs = ARX_EQUIPMENT_ComputeDamages(io_source, target, ratioaim);
847 
848 						}
849 
850 						if (target->ioflags & IO_NPC)
851 						{
852 							ret = true;
853 							target->spark_n_blood = 0;
854 							target->_npcdata->SPLAT_TOT_NB = 0;
855 
856 							if (drain_life > 0.f)
857 							{
858 								float life_gain = min(dmgs, drain_life);
859 								life_gain = min(life_gain, target->_npcdata->life);
860 								life_gain = max(life_gain, 0.f);
861 								ARX_DAMAGES_HealInter(io_source, life_gain);
862 							}
863 
864 							if (paralyse > 0.f)
865 							{
866 								float ptime = min(dmgs * 1000.f, paralyse);
867 								ARX_SPELLS_Launch(SPELL_PARALYSE, weapon, SPELLCAST_FLAG_NOMANA | SPELLCAST_FLAG_NOCHECKCANCAST
868 								                  , 5, EVERYTHING_IN_SPHERE[jj], (long)(ptime));
869 							}
870 						}
871 
872 						if (io_source == entities.player())
873 						{
874 							ARX_DAMAGES_DurabilityCheck(io_weapon, 0.2f);
875 						}
876 					}
877 
878 					if ((dmgs > 0.f) || ((target->ioflags & IO_NPC) && (target->spark_n_blood == SP_BLOODY)))
879 					{
880 						if (target->ioflags & IO_NPC)
881 						{
882 							target->spark_n_blood = SP_BLOODY;
883 
884 							if (!(flags & 1))
885 							{
886 								ARX_PARTICLES_Spawn_Splat(pos, dmgs, color);
887 
888 								EERIE_SPHERE sp;
889 								float power;
890 								power = (dmgs * ( 1.0f / 40 )) + 0.7f;
891 								Vec3f vect;
892 								vect.x = target->obj->vertexlist3[hitpoint].v.x - io_source->pos.x;
893 								vect.y = 0;
894 								vect.z = target->obj->vertexlist3[hitpoint].v.z - io_source->pos.z;
895 								fnormalize(vect);
896 								sp.origin.x = target->obj->vertexlist3[hitpoint].v.x + vect.x * 30.f;
897 								sp.origin.y = target->obj->vertexlist3[hitpoint].v.y;
898 								sp.origin.z = target->obj->vertexlist3[hitpoint].v.z + vect.z * 30.f;
899 								sp.radius = 3.5f * power * 20;
900 
901 								if(CheckAnythingInSphere(&sp, 0, CAS_NO_NPC_COL)) {
902 									Color3f rgb = color.to<float>();
903 									SpawnGroundSplat(&sp, &rgb, 30, 1);
904 								}
905 							}
906 
907 							ARX_PARTICLES_Spawn_Blood2(pos, dmgs, color, target);
908 
909 							if (!ValidIONum(weapon)) io_weapon = NULL;
910 						}
911 						else
912 						{
913 							if (target->ioflags & IO_ITEM)
914 								ARX_PARTICLES_Spawn_Spark(&pos, rnd() * 3.f, 0);
915 							else
916 								ARX_PARTICLES_Spawn_Spark(&pos, rnd() * 30.f, 0);
917 
918 							ARX_NPC_SpawnAudibleSound(&pos, io_source);
919 
920 							if (io_source == entities.player())
921 								HIT_SPARK = 1;
922 						}
923 					}
924 					else if ((target->ioflags & IO_NPC)
925 					         &&	((dmgs <= 0.f) || (target->spark_n_blood == SP_SPARKING)))
926 					{
927 						long nb;
928 
929 						if (target->spark_n_blood == SP_SPARKING)
930 							nb = Random::get(0, 3);
931 						else
932 							nb = 30;
933 
934 						if (target->ioflags & IO_ITEM)
935 							nb = 1;
936 
937 						ARX_PARTICLES_Spawn_Spark(&pos, (float)nb, 0);
938 						ARX_NPC_SpawnAudibleSound(&pos, io_source);
939 						target->spark_n_blood = SP_SPARKING;
940 
941 						if (!(target->ioflags & IO_NPC))
942 							HIT_SPARK = 1;
943 					}
944 					else if ((dmgs <= 0.f)
945 					         &&	((target->ioflags & IO_FIX) || (target->ioflags & IO_ITEM)))
946 					{
947 						long  nb;
948 
949 						if (target->spark_n_blood == SP_SPARKING)
950 							nb = Random::get(0, 3);
951 						else
952 							nb = 30;
953 
954 						if (target->ioflags & IO_ITEM)
955 							nb = 1;
956 
957 						ARX_PARTICLES_Spawn_Spark(&pos, (float)nb, 0);
958 						ARX_NPC_SpawnAudibleSound(&pos, io_source);
959 						target->spark_n_blood = SP_SPARKING;
960 
961 						if (!(target->ioflags & IO_NPC))
962 							HIT_SPARK = 1;
963 					}
964 
965 					if(HIT_SPARK) {
966 						if(!io_source->isHit) {
967 							ARX_DAMAGES_DurabilityCheck(io_weapon, 1.f);
968 							io_source->isHit = true;
969 
970 							if(!ValidIONum(weapon)) {
971 								io_weapon = NULL;
972 							} else {
973 								string _weapon_material = "metal";
974 								const string * weapon_material = &_weapon_material;
975 
976 								if(io_weapon && !io_weapon->weaponmaterial.empty()) {
977 									weapon_material = &io_weapon->weaponmaterial;
978 								}
979 
980 								char bkg_material[128];
981 
982 								if (ARX_MATERIAL_GetNameById(target->material, bkg_material))
983 									ARX_SOUND_PlayCollision(*weapon_material, bkg_material, 1.f, 1.f, &sphere.origin, NULL);
984 							}
985 						}
986 					}
987 
988 				}
989 			}
990 		}
991 
992 
993 		EERIEPOLY * ep = CheckBackgroundInSphere(&sphere);
994 		if (ep)
995 		{
996 			if (io_source == entities.player())
997 			{
998 				if(!io_source->isHit) {
999 
1000 					ARX_DAMAGES_DurabilityCheck(io_weapon, 1.f);
1001 					io_source->isHit = true;
1002 
1003 					if (!ValidIONum(weapon))
1004 					{
1005 						io_weapon = NULL;
1006 					}
1007 					else
1008 					{
1009 						string _weapon_material = "metal";
1010 						const string * weapon_material = &_weapon_material;
1011 						if(io_weapon && !io_weapon->weaponmaterial.empty()) {
1012 							weapon_material = &io_weapon->weaponmaterial;
1013 						}
1014 
1015 						std::string bkg_material = "earth";
1016 
1017 						if (ep &&  ep->tex && !ep->tex->m_texName.empty())
1018 							bkg_material = GetMaterialString( ep->tex->m_texName );
1019 
1020 						ARX_SOUND_PlayCollision(*weapon_material, bkg_material, 1.f, 1.f, &sphere.origin, io_source);
1021 					}
1022 				}
1023 			}
1024 
1025 			ARX_PARTICLES_Spawn_Spark(&sphere.origin, rnd() * 10.f, 0);
1026 			ARX_NPC_SpawnAudibleSound(&sphere.origin, io_source);
1027 		}
1028 	}
1029 
1030 	return ret;
1031 }
1032 
1033 //***********************************************************************************************
1034 //-----------------------------------------------------------------------------------------------
1035 //***********************************************************************************************
ARX_EQUIPMENT_LaunchPlayerReadyWeapon()1036 void ARX_EQUIPMENT_LaunchPlayerReadyWeapon()
1037 {
1038 	Entity * io = entities.player();
1039 
1040 	if (!io) return;
1041 
1042 	long type = ARX_EQUIPMENT_GetPlayerWeaponType();
1043 	ANIM_HANDLE * anim = NULL;
1044 
1045 	switch (type)
1046 	{
1047 		case WEAPON_DAGGER:
1048 			anim = io->anims[ANIM_DAGGER_READY_PART_1];
1049 			break;
1050 		case WEAPON_1H:
1051 			anim = io->anims[ANIM_1H_READY_PART_1];
1052 			break;
1053 		case WEAPON_2H:
1054 
1055 			if (player.equiped[EQUIP_SLOT_SHIELD] == 0)
1056 				anim = io->anims[ANIM_2H_READY_PART_1];
1057 
1058 			break;
1059 		case WEAPON_BOW:
1060 
1061 			if (player.equiped[EQUIP_SLOT_SHIELD] == 0)
1062 				anim = io->anims[ANIM_MISSILE_READY_PART_1];
1063 
1064 			break;
1065 		default:
1066 			anim = io->anims[ANIM_BARE_READY];
1067 			break;
1068 	}
1069 
1070 	AcquireLastAnim(io);
1071 	ANIM_Set(&io->animlayer[1], anim);
1072 }
1073 
1074 //***********************************************************************************************
1075 //-----------------------------------------------------------------------------------------------
1076 //***********************************************************************************************
1077 
ARX_EQUIPMENT_UnEquipPlayerWeapon()1078 void ARX_EQUIPMENT_UnEquipPlayerWeapon()
1079 {
1080 	if ((player.equiped[EQUIP_SLOT_WEAPON] != 0)
1081 	        &&	ValidIONum(player.equiped[EQUIP_SLOT_WEAPON]))
1082 	{
1083 		Entity * pioOldDragInter;
1084 		pioOldDragInter = DRAGINTER;
1085 		DRAGINTER = entities[player.equiped[EQUIP_SLOT_WEAPON]];
1086 
1087 		if (DRAGINTER)
1088 			ARX_SOUND_PlayInterface(SND_INVSTD);
1089 
1090 		ARX_EQUIPMENT_UnEquip(entities.player(), entities[player.equiped[EQUIP_SLOT_WEAPON]]);
1091 		DRAGINTER = pioOldDragInter;
1092 	}
1093 
1094 	player.equiped[EQUIP_SLOT_WEAPON] = 0;
1095 }
1096 
1097 bool bRing = false;
1098 
1099 //***********************************************************************************************
1100 //-----------------------------------------------------------------------------------------------
1101 //***********************************************************************************************
ARX_EQUIPMENT_Equip(Entity * target,Entity * toequip)1102 void ARX_EQUIPMENT_Equip(Entity * target, Entity * toequip)
1103 {
1104 	if (!target) return;
1105 
1106 	if (!toequip) return;
1107 
1108 	if (target != entities.player()) return;
1109 
1110 	long validid = -1;
1111 
1112 	for(size_t i = 0; i < entities.size(); i++) {
1113 		if(entities[i] == toequip) {
1114 			validid = i;
1115 			break;
1116 		}
1117 	}
1118 
1119 	if (validid == -1) return;
1120 
1121 	RemoveFromAllInventories(toequip);
1122 	toequip->show = SHOW_FLAG_ON_PLAYER; // on player
1123 
1124 	if (toequip == DRAGINTER)
1125 		Set_DragInter(NULL);
1126 
1127 	if ((toequip->type_flags & OBJECT_TYPE_DAGGER)
1128 	        ||	(toequip->type_flags & OBJECT_TYPE_1H)
1129 	        ||	(toequip->type_flags & OBJECT_TYPE_2H)
1130 	        ||	(toequip->type_flags & OBJECT_TYPE_BOW)
1131 	   )
1132 	{
1133 		if ((player.equiped[EQUIP_SLOT_WEAPON] != 0)
1134 		        &&	ValidIONum(player.equiped[EQUIP_SLOT_WEAPON]))
1135 		{
1136 			ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_WEAPON]]);
1137 		}
1138 
1139 		player.equiped[EQUIP_SLOT_WEAPON] = (short)validid;
1140 
1141 		if (toequip->type_flags & OBJECT_TYPE_BOW)
1142 		{
1143 			EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "weapon_attach", "test", toequip); //
1144 		}
1145 		else
1146 		{
1147 			EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "weapon_attach", "primary_attach", toequip); //
1148 		}
1149 
1150 		if ((toequip->type_flags & OBJECT_TYPE_2H) || (toequip->type_flags & OBJECT_TYPE_BOW))
1151 		{
1152 			if (player.equiped[EQUIP_SLOT_SHIELD] != 0)
1153 			{
1154 				ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_SHIELD]]);
1155 			}
1156 		}
1157 	}
1158 	else if (toequip->type_flags & OBJECT_TYPE_SHIELD)
1159 	{
1160 		if ((player.equiped[EQUIP_SLOT_SHIELD] != 0)
1161 		        &&	ValidIONum(player.equiped[EQUIP_SLOT_SHIELD]))
1162 		{
1163 			ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_SHIELD]]);
1164 		}
1165 
1166 		player.equiped[EQUIP_SLOT_SHIELD] = (short)validid;
1167 		EERIE_LINKEDOBJ_LinkObjectToObject(target->obj, toequip->obj, "shield_attach", "shield_attach", toequip);
1168 
1169 		if ((player.equiped[EQUIP_SLOT_WEAPON] != 0)
1170 		        &&	ValidIONum(player.equiped[EQUIP_SLOT_WEAPON]))
1171 		{
1172 			if ((entities[player.equiped[EQUIP_SLOT_WEAPON]]->type_flags & OBJECT_TYPE_2H) ||
1173 			        (entities[player.equiped[EQUIP_SLOT_WEAPON]]->type_flags & OBJECT_TYPE_BOW))
1174 			{
1175 				ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_WEAPON]]);
1176 			}
1177 		}
1178 	}
1179 	else if (toequip->type_flags & OBJECT_TYPE_RING)
1180 	{
1181 		// check first, if not already equiped
1182 		if (!((ValidIONum(player.equiped[EQUIP_SLOT_RING_LEFT]) && (toequip == entities[player.equiped[EQUIP_SLOT_RING_LEFT]]))
1183 		        ||	(ValidIONum(player.equiped[EQUIP_SLOT_RING_RIGHT]) && (toequip == entities[player.equiped[EQUIP_SLOT_RING_RIGHT]]))))
1184 		{
1185 			long willequip = -1;
1186 
1187 			if (player.equiped[EQUIP_SLOT_RING_LEFT] == 0) willequip = EQUIP_SLOT_RING_LEFT;
1188 
1189 			if (player.equiped[EQUIP_SLOT_RING_RIGHT] == 0) willequip = EQUIP_SLOT_RING_RIGHT;
1190 
1191 			if (willequip == -1)
1192 			{
1193 				if (bRing)
1194 				{
1195 					if (ValidIONum(player.equiped[EQUIP_SLOT_RING_RIGHT]))
1196 						ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_RING_RIGHT]]);
1197 
1198 					willequip = EQUIP_SLOT_RING_RIGHT;
1199 				}
1200 				else
1201 				{
1202 					if (ValidIONum(player.equiped[EQUIP_SLOT_RING_LEFT]))
1203 						ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_RING_LEFT]]);
1204 
1205 					willequip = EQUIP_SLOT_RING_LEFT;
1206 				}
1207 
1208 				bRing = !bRing;
1209 			}
1210 
1211 			player.equiped[willequip] = (short)validid;
1212 		}
1213 	}
1214 	else if (toequip->type_flags & OBJECT_TYPE_ARMOR)
1215 	{
1216 		if ((player.equiped[EQUIP_SLOT_ARMOR] != 0)
1217 		        &&	ValidIONum(player.equiped[EQUIP_SLOT_ARMOR]))
1218 		{
1219 			ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_ARMOR]]);
1220 		}
1221 
1222 		player.equiped[EQUIP_SLOT_ARMOR] = (short)validid;
1223 	}
1224 	else if (toequip->type_flags & OBJECT_TYPE_LEGGINGS)
1225 	{
1226 		if ((player.equiped[EQUIP_SLOT_LEGGINGS] != 0)
1227 		        &&	ValidIONum(player.equiped[EQUIP_SLOT_LEGGINGS]))
1228 		{
1229 			ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_LEGGINGS]]);
1230 		}
1231 
1232 		player.equiped[EQUIP_SLOT_LEGGINGS] = (short)validid;
1233 	}
1234 	else if (toequip->type_flags & OBJECT_TYPE_HELMET)
1235 	{
1236 		if ((player.equiped[EQUIP_SLOT_HELMET] != 0)
1237 		        &&	(ValidIONum(player.equiped[EQUIP_SLOT_HELMET])))
1238 		{
1239 			ARX_EQUIPMENT_UnEquip(target, entities[player.equiped[EQUIP_SLOT_HELMET]]);
1240 		}
1241 
1242 		player.equiped[EQUIP_SLOT_HELMET] = (short)validid;
1243 	}
1244 
1245 	if ((toequip->type_flags & OBJECT_TYPE_HELMET)
1246 	        ||	(toequip->type_flags & OBJECT_TYPE_ARMOR)
1247 	        ||	(toequip->type_flags & OBJECT_TYPE_LEGGINGS))
1248 		ARX_EQUIPMENT_RecreatePlayerMesh();
1249 
1250 	ARX_PLAYER_ComputePlayerFullStats();
1251 }
1252 
ARX_EQUIPMENT_SetObjectType(Entity & io,const string & temp,bool set)1253 bool ARX_EQUIPMENT_SetObjectType(Entity & io, const string & temp, bool set) {
1254 
1255 	ItemType flag = ARX_EQUIPMENT_GetObjectTypeFlag(temp);
1256 
1257 	if(set) {
1258 		io.type_flags |= flag;
1259 	} else {
1260 		io.type_flags &= ~flag;
1261 	}
1262 
1263 	return (flag != 0);
1264 }
1265 
1266 //***********************************************************************************************
1267 // Initializes Equipment infos
1268 //-----------------------------------------------------------------------------------------------
1269 // VERIFIED (Cyril 2001/10/29)
1270 //***********************************************************************************************
ARX_EQUIPMENT_Init()1271 void ARX_EQUIPMENT_Init()
1272 {
1273 	// IO_EQUIPITEM_ELEMENT_... are Defined in EERIEPOLY.h
1274 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_STRENGTH].name, "strength");
1275 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_DEXTERITY].name, "dexterity");
1276 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_CONSTITUTION].name, "constitution");
1277 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_MIND].name, "intelligence");
1278 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Stealth].name, "stealth");
1279 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Mecanism].name, "mecanism");
1280 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Intuition].name, "intuition");
1281 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Etheral_Link].name, "etheral_link");
1282 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Object_Knowledge].name, "object_knowledge");
1283 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Casting].name, "casting");
1284 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Projectile].name, "projectile");
1285 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Close_Combat].name, "close_combat");
1286 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Defense].name, "defense");
1287 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Armor_Class].name, "armor_class");
1288 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Resist_Magic].name, "resist_magic");
1289 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Resist_Poison].name, "resist_poison");
1290 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Critical_Hit].name, "critical_hit");
1291 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Damages].name, "damages");
1292 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Duration].name, "duration");
1293 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_AimTime].name, "aim_time");
1294 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Identify_Value].name, "identify_value");
1295 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Life].name, "life");
1296 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_Mana].name, "mana");
1297 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_MaxLife].name, "maxlife");
1298 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_MaxMana].name, "maxmana");
1299 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_SPECIAL_1].name, "special1");
1300 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_SPECIAL_2].name, "special2");
1301 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_SPECIAL_3].name, "special3");
1302 	strcpy(equipinfo[IO_EQUIPITEM_ELEMENT_SPECIAL_4].name, "special4");
1303 }
1304 
1305 //***********************************************************************************************
1306 // Removes All special equipement properties
1307 //-----------------------------------------------------------------------------------------------
1308 // VERIFIED (Cyril 2001/10/29)
1309 //***********************************************************************************************
ARX_EQUIPMENT_Remove_All_Special(Entity * io)1310 void ARX_EQUIPMENT_Remove_All_Special(Entity * io)
1311 {
1312 	if (!io) return;
1313 
1314 	if (!(io->ioflags & IO_ITEM)) return;
1315 
1316 	io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_SPECIAL_1].special = IO_SPECIAL_ELEM_NONE;
1317 	io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_SPECIAL_2].special = IO_SPECIAL_ELEM_NONE;
1318 	io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_SPECIAL_3].special = IO_SPECIAL_ELEM_NONE;
1319 	io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_SPECIAL_4].special = IO_SPECIAL_ELEM_NONE;
1320 }
1321 //***********************************************************************************************
1322 // Sets an equipment property
1323 //-----------------------------------------------------------------------------------------------
1324 //***********************************************************************************************
ARX_EQUIPMENT_Apply(Entity * io,EquipmentModifierType ident,float trueval)1325 float ARX_EQUIPMENT_Apply(Entity * io, EquipmentModifierType ident,
1326                           float trueval) {
1327 
1328 	if (io == NULL) return trueval;
1329 
1330 	if (io != entities.player()) return trueval;
1331 
1332 	float toadd = 0;
1333 
1334 	for (long i = 0; i < MAX_EQUIPED; i++)
1335 	{
1336 		if ((player.equiped[i] != 0)
1337 		        &&	ValidIONum(player.equiped[i]))
1338 		{
1339 			Entity * toequip = entities[player.equiped[i]];
1340 
1341 			if ((toequip) && (toequip->ioflags & IO_ITEM) && (toequip->_itemdata->equipitem))
1342 			{
1343 				IO_EQUIPITEM_ELEMENT * elem = &toequip->_itemdata->equipitem->elements[ident];
1344 
1345 				if (!(elem->flags & IO_ELEMENT_FLAG_PERCENT))
1346 					toadd += elem->value;
1347 			}
1348 		}
1349 	}
1350 
1351 	return toadd;
1352 }
1353 
ARX_EQUIPMENT_ApplyPercent(Entity * io,EquipmentModifierType ident,float trueval)1354 float ARX_EQUIPMENT_ApplyPercent(Entity * io, EquipmentModifierType ident,
1355                                  float trueval) {
1356 
1357 	if (io == NULL) return trueval;
1358 
1359 	if (io != entities.player()) return trueval;
1360 
1361 	float toadd = 0;
1362 
1363 	for (long i = 0; i < MAX_EQUIPED; i++)
1364 	{
1365 		if ((player.equiped[i] != 0)
1366 		        &&	ValidIONum(player.equiped[i]))
1367 		{
1368 			Entity * toequip = entities[player.equiped[i]];
1369 
1370 			if ((toequip) && (toequip->ioflags & IO_ITEM) && (toequip->_itemdata->equipitem))
1371 			{
1372 				IO_EQUIPITEM_ELEMENT * elem = &toequip->_itemdata->equipitem->elements[ident];
1373 
1374 				if (elem->flags & IO_ELEMENT_FLAG_PERCENT) // percentile value...
1375 				{
1376 					toadd += elem->value;
1377 				}
1378 			}
1379 		}
1380 	}
1381 
1382 	return (toadd * trueval * ( 1.0f / 100 ));
1383 }
1384 
ARX_EQUIPMENT_SetEquip(Entity * io,bool special,const std::string & param2,float val,EquipmentModifierFlags flags)1385 void ARX_EQUIPMENT_SetEquip(Entity * io, bool special,
1386                             const std::string & param2, float val,
1387                             EquipmentModifierFlags flags) {
1388 
1389 	if (io == NULL) return;
1390 
1391 	if (!(io->ioflags & IO_ITEM)) return;
1392 
1393 	if (!io->_itemdata->equipitem)
1394 	{
1395 		io->_itemdata->equipitem = (IO_EQUIPITEM *) malloc(sizeof(IO_EQUIPITEM));
1396 
1397 		if (io->_itemdata->equipitem == NULL) return;
1398 
1399 		memset(io->_itemdata->equipitem, 0, sizeof(IO_EQUIPITEM));
1400 		io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Duration].value = 10;
1401 		io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_AimTime].value = 10;
1402 		io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Damages].value = 0;
1403 		io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Identify_Value].value = 0;
1404 	}
1405 
1406 	if(special) {
1407 		for (long i = IO_EQUIPITEM_ELEMENT_SPECIAL_1; i <= IO_EQUIPITEM_ELEMENT_SPECIAL_4; i++)
1408 		{
1409 			if (io->_itemdata->equipitem->elements[i].special == IO_SPECIAL_ELEM_NONE)
1410 			{
1411 				if(param2 == "paralyse") {
1412 					io->_itemdata->equipitem->elements[i].special = IO_SPECIAL_ELEM_PARALYZE;
1413 				} else if(param2 == "drainlife") {
1414 					io->_itemdata->equipitem->elements[i].special = IO_SPECIAL_ELEM_DRAIN_LIFE;
1415 				}
1416 
1417 				io->_itemdata->equipitem->elements[i].value = val;
1418 				io->_itemdata->equipitem->elements[i].flags = flags;
1419 				return;
1420 			}
1421 		}
1422 
1423 		return;
1424 
1425 	} else {
1426 		for(long i = 0; i < IO_EQUIPITEM_ELEMENT_Number; i++) {
1427 			if(param2 == equipinfo[i].name) {
1428 				io->_itemdata->equipitem->elements[i].value = val;
1429 				io->_itemdata->equipitem->elements[i].special = IO_SPECIAL_ELEM_NONE;
1430 				io->_itemdata->equipitem->elements[i].flags = flags;
1431 				return;
1432 			}
1433 		}
1434 	}
1435 }
1436 
1437 //-----------------------------------------------------------------------------
ARX_EQUIPMENT_IdentifyAll()1438 void ARX_EQUIPMENT_IdentifyAll()
1439 {
1440 	Entity * io = entities.player();
1441 
1442 	if (io == NULL) return;
1443 
1444 	if (io != entities.player()) return;
1445 
1446 	for (long i = 0; i < MAX_EQUIPED; i++)
1447 	{
1448 		if ((player.equiped[i] != 0)
1449 		        &&	ValidIONum(player.equiped[i]))
1450 		{
1451 			Entity * toequip = entities[player.equiped[i]];
1452 
1453 			if ((toequip) && (toequip->ioflags & IO_ITEM) && (toequip->_itemdata->equipitem))
1454 			{
1455 				if (player.Full_Skill_Object_Knowledge + player.Full_Attribute_Mind
1456 				        >= toequip->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Identify_Value].value)
1457 				{
1458 					SendIOScriptEvent(toequip, SM_IDENTIFY);
1459 				}
1460 			}
1461 		}
1462 	}
1463 }
1464 
GetHitValue(const std::string & name)1465 float GetHitValue( const std::string & name) {
1466 
1467 	if(boost::starts_with(name, "hit_")) {
1468 		// Get the number after the first 4 characters in the string
1469 		try {
1470 			return float(boost::lexical_cast<long>(name.substr(4)));
1471 		} catch(...) { /* ignore */ }
1472 	}
1473 
1474 	return -1;
1475 }
1476