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