1 /*
2 This file is part of "Avanor, the Land of Mystery" roguelike game
3 Home page: http://www.avanor.com/
4 Copyright (C) 2000-2003 Vadim Gaidukevich
5
6 This program 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 2 of the License, or
9 (at your option) any later version.
10
11 This program 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 this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "creature.h"
22 #include "modifer.h"
23 #include "xapi.h"
24
Attack()25 void XCreature::Attack()
26 {
27 assert(isValid());
28 XCreature * target = l->map->GetMonster(nx, ny);
29 assert(target);
30
31 XItem * it1 = GetItem(BP_HAND, 0);
32 XItem * it2 = GetItem(BP_HAND, 1);
33 int flag = 0;
34 int ttm_res = 0;
35
36 if (it1 && it1->im & IM_WEAPON)
37 {
38 ttm_res += MeleeAttack(target, it1);
39 flag++;
40 }
41
42 if (it2 && it2->im & IM_WEAPON && target->isValid())
43 {
44 ttm_res += MeleeAttack(target, it2);
45 flag++;
46 }
47
48 if (flag == 0)
49 {
50 ttm_res += MeleeAttack(target, NULL);
51 }
52 }
53
54 /*
55 int XCreature::AttackCreature(ATTACK_DATA * pData)
56 {
57 XCreature * target = pData->target;
58 XCreature * attacker = pData->attacker;
59
60 //check for visibility both of target and attacker
61 int vis1 = 0;
62 if (attaker)
63 vis1 = isVisible();
64 int vis2 = target->isVisible();
65
66 //check if was an enemy for backstab
67 int wasEnemy = 0;
68 if (attaker)
69 target->xai->isEnemy(this);
70
71 //check for basic of DV, HIT
72 int todv = target->GetDV();
73 int tohit = pData->toHIT;
74
75 if (tohit < 0)
76 {
77 todv -= tohit; // a - (-b) == a + b;
78 tohit = 0;
79 }
80
81 int p = (tohit * 150 + 1) / (tohit + todv + 1) - todv;
82 int v = vRand(100);
83
84 if (v < p || pData->isAbsHit) //if was successful hit (or always hit)
85 {
86 int sb = target->GetShieldDVBonus();
87 if (sb > 0 && vRand(todv) < sb && !pData->isAbsHit) //test for block
88 {
89 if (vis1 || vis2) //The attack was blocked
90 {
91 if (pData->attacker_name)
92 {
93 msgwin.Add(target->GetNameEx(CRN_T1));
94 msgwin.Add(target->GetVerb("deflect"));
95 msgwin.Add(attacker_name);
96 msgwin.Add("with");
97 msgwin.Add(target->GetNameEx(CRN_T4));
98 msgwin.Add("shield.");
99 } else
100 {
101 msgwin.Add(GetNameEx(CRN_T1));
102 msgwin.Add(GetVerb("attack"));
103 msgwin.AddLast(target->GetNameEx(CRN_T1));
104 msgwin.Add(target->GetNameEx(CRN_T1));
105 msgwin.Add(target->GetVerb("block"));
106 msgwin.Add(GetNameEx(CRN_T1));
107 msgwin.Add("with");
108 msgwin.Add(target->GetNameEx(CRN_T4));
109 msgwin.Add("shield.");
110 }
111 }
112 target->wsk->UseSkill(WSK_SHIELD);
113 } else
114 {
115 //get random part of body
116 XBodyPart * txbp = target->GetRNDBodyPart();
117
118 //get initial damage
119 int tdam = pData->baseDAM;
120
121 //get initial pv of armour
122 int xpv = 0;
123 if (txbp && txbp->Item())
124 xpv = txbp->Item()->_PV;
125
126 if (txbp && txbp->bp_uin == BP_CLOAK)
127 {
128 XItem * xtmp = GetItem(BP_BODY);
129 if (xtmp)
130 xpv += xtmp->_PV;
131 }
132
133 //critical hit
134 int crtical_flag = 0;
135 if (attacker)
136 {
137 if (vRand(100) < (2 + sk->GetLevel(SKT_FINDWEAKNESS)))
138 {
139 sk->UseSkill(SKT_FINDWEAKNESS);
140 crtical_flag = 1;
141 tdam *= 3;
142 }
143 } else
144 {
145 if (vRand(100) < 2)
146 {
147 crtical_flag = 1;
148 tdam *= 3;
149 }
150 }
151
152 //backstab
153 int backstab = 0;
154 if (pData->weapon && (!target->isCreatureVisible(this) || !wasEnemy))
155 {
156 if (attacker)
157 {
158 if (vRand(100) < sk->GetLevel(SKT_BACKSTABBING) * 5 + 5)
159 {
160 backstab = 1;
161 tdam *= 3;
162 sk->UseSkill(SKT_BACKSTABBING, 3);
163 }
164 } else
165 {
166 if (vRand(100) < 5)
167 {
168 backstab = 1;
169 tdam *= 3;
170 }
171 }
172 }
173
174 int dam = tdam;
175 int p_flag = 0;
176
177 //ignore armour
178 if (attacker)
179 {
180 if (vRand(100) > (2 + sk->GetLevel(SKT_FINDWEAKNESS)) || xpv == 0)
181 dam = tdam - xpv;
182 else
183 {
184 sk->UseSkill(SKT_FINDWEAKNESS);
185 p_flag = 1;
186 }
187 } else
188 {
189 if (vRand(100) > 2 || xpv == 0)
190 dam = tdam - xpv;
191 else
192 p_flag = 1;
193 }
194
195 if (vis1 || vis2)
196 {
197 if (attacker)
198 msgwin.Add(attacker->GetNameEx(CRN_T1));
199 else
200 msgwin.Add(pData->attacker_name);
201
202 if (weapon)
203 {
204 if (crtical_flag)
205 msgwin.Add("exactly");
206
207 if(backstab)
208 msgwin.Add(GetVerb("stab"));
209 else
210 msgwin.Add(GetVerb("hit"));
211 } else
212 {
213 if (crtical_flag)
214 msgwin.Add("exactly");
215 msgwin.Add(GetVerb(GetMeleeAttackMsg()));
216 }
217
218 if (p_flag)
219 {
220 msgwin.Add(target->GetNameEx(CRN_T1));
221 if (target->isHero()) //last message for hero.
222 msgwin.Add("penetrating a piece of armour.");
223 else
224 msgwin.Add("penetrating a piece of armour");
225 } else
226 if (target->isHero()) //last message for hero
227 msgwin.AddLast(target->GetNameEx(CRN_T1));
228 else
229 msgwin.Add(target->GetNameEx(CRN_T1));
230 }
231
232
233 if (!weapon)
234 {
235 int dmg = dam;
236 for (XQList<MELEE_ATTACK>::iterator tit = melee_attack->begin(); tit != melee_attack->end(); tit++)
237 {
238 if (vRand(100) < (*tit).prob)
239 {
240 dam += target->CauseEffect(this, dmg, (*tit).r_attack);
241 }
242 }
243 AttackCreature(target, dam);
244 } else
245 {
246 dam = target->CauseEffect(dam, weapon->brt);
247 AttackCreature(target, dam);
248 }
249 }
250 } else
251 {
252 if (vis1 || vis2)
253 {
254 msgwin.Add(GetNameEx(CRN_T1));
255 msgwin.Add(GetVerb("attack"));
256 char xxbuf[256];
257 sprintf(xxbuf, "%s, but %s.", target->GetNameEx(CRN_T1), GetVerb("miss"));
258 msgwin.Add(xxbuf);
259 }
260 }
261 }
262 */
263
MeleeAttack(XCreature * target,XItem * weapon)264 int XCreature::MeleeAttack(XCreature * target, XItem * weapon)
265 {
266 assert(isValid());
267
268 //need for backstub.
269 int wasEnemy = target->xai->isEnemy(this);
270
271 //~~~check this in future
272 target->xai->onWasAttacked(this);
273 target->stopAction();
274 //~~~~~
275
276 bool vis1 = isVisible();
277 bool vis2 = target->isVisible();
278
279 int res = 0;
280 int tohit;
281 if (weapon)
282 {
283 res += (wsk->GetUseTime(weapon->wt) * GetSpeed()) / 1000;
284 tohit = GetHIT() + wsk->GetHIT(weapon->wt) + GetHITFHBonus(weapon);
285
286 } else
287 {
288 res += (wsk->GetUseTime(WSK_UNARMED) * GetSpeed()) / 1000;
289 tohit = GetHIT() + wsk->GetHIT(WSK_UNARMED);
290 }
291
292 int todv = target->GetDV();
293
294 if (tohit < 0)
295 {
296 todv -= tohit; // a - (-b) == a + b;
297 tohit = 0;
298 }
299
300 int p = (int)(1000 * ((float)(tohit + 1) / (tohit + todv + 1)));
301 int v = vRand() % 1000;
302
303 if (v < p)
304 {
305 //test for block
306 int sb = target->GetShieldDVBonus();
307 if (sb > 0 && vRand(todv) < sb)
308 {
309 if (vis1 || vis2)
310 {
311 msgwin.Add(GetNameEx(CRN_T1));
312 msgwin.Add(GetVerb("attack"));
313 msgwin.AddLast(target->GetNameEx(CRN_T1));
314 msgwin.Add(target->GetNameEx(CRN_T1));
315 msgwin.Add(target->GetVerb("block"));
316 msgwin.Add(GetNameEx(CRN_T1));
317 msgwin.Add("with");
318 msgwin.Add(target->GetNameEx(CRN_T4));
319 msgwin.Add("shield.");
320 }
321 target->wsk->UseSkill(WSK_SHIELD);
322 } else
323 {
324 //get random part of body
325 XBodyPart * txbp = target->GetRNDBodyPart();
326
327 //get initial damage
328 int tdam;
329 if (weapon)
330 {
331 tdam = weapon->dice.Throw() + wsk->GetDMG(weapon->wt) + GetDMGFHBonus(weapon) + GetDMG();
332 wsk->UseSkill(weapon->wt);
333 }
334 else
335 {
336 tdam = dice.Throw() + GetDMG() + wsk->GetDMG(WSK_UNARMED);
337 wsk->UseSkill(WSK_UNARMED);
338 }
339
340 //get initial pv of armour
341 int xpv = 0;
342 if (txbp && txbp->Item())
343 xpv = txbp->Item()->_PV;
344
345 if (txbp && txbp->bp_uin == BP_CLOAK)
346 {
347 XItem * xtmp = GetItem(BP_BODY);
348 if (xtmp)
349 xpv += xtmp->_PV;
350 }
351
352 //write hiter name
353 if (vis1 || vis2)
354 msgwin.Add(GetNameEx(CRN_T1));
355
356 //critical hit
357 int crtical_flag = 0;
358 if ((vRand() % 100) < (2 + sk->GetLevel(SKT_FINDWEAKNESS)))
359 {
360 sk->UseSkill(SKT_FINDWEAKNESS);
361 crtical_flag = 1;
362 tdam *= 3;
363 }
364
365 //backstab
366 int backstab = 0;
367 if (weapon && (!target->isCreatureVisible(this) || !wasEnemy))
368 {
369 if (vRand(100) < sk->GetLevel(SKT_BACKSTABBING) * 5 + 5)
370 {
371 backstab = 1;
372 tdam *= 3;
373 sk->UseSkill(SKT_BACKSTABBING, 3);
374 }
375 }
376
377 int dam = tdam;
378 int p_flag = 0;
379 if ((vRand() % 100) > (2 + sk->GetLevel(SKT_FINDWEAKNESS)) || xpv == 0)
380 dam = tdam - xpv;
381 else
382 {
383 sk->UseSkill(SKT_FINDWEAKNESS);
384 p_flag = 1;
385 }
386
387 if (vis1 || vis2)
388 {
389 if (weapon)
390 {
391 if (crtical_flag)
392 msgwin.Add("exactly");
393
394 if(backstab)
395 msgwin.Add(GetVerb("stab"));
396 else
397 msgwin.Add(GetVerb("hit"));
398 } else
399 {
400 if (crtical_flag)
401 msgwin.Add("exactly");
402 msgwin.Add(GetVerb(GetMeleeAttackMsg()));
403 }
404
405 if (p_flag)
406 {
407 msgwin.Add(target->GetNameEx(CRN_T1));
408 if (target->isHero())
409 msgwin.Add("penetrating a piece of armour.");
410 else
411 msgwin.Add("penetrating a piece of armour");
412 } else
413 if (target->isHero())
414 msgwin.AddLast(target->GetNameEx(CRN_T1));
415 else
416 msgwin.Add(target->GetNameEx(CRN_T1));
417 }
418
419
420 if (!weapon)
421 {
422 int dmg = dam;
423 for (XQList<MELEE_ATTACK>::iterator tit = melee_attack->begin(); tit != melee_attack->end(); tit++)
424 {
425 if (vRand(100) < (*tit).prob)
426 {
427 if ((*tit).r_attack > 0)
428 dam += target->CauseEffect(this, dmg, (*tit).r_attack);
429 else
430 ;
431 }
432 }
433 AttackCreature(target, dam);
434 } else
435 {
436 dam = target->CauseEffect(dam, weapon->brt);
437 AttackCreature(target, dam);
438 }
439 }
440 } else
441 {
442 if (vis1 || vis2)
443 {
444 msgwin.Add(GetNameEx(CRN_T1));
445 msgwin.Add(GetVerb("attack"));
446 char xxbuf[256];
447 sprintf(xxbuf, "%s, but %s.", target->GetNameEx(CRN_T1), GetVerb("miss"));
448 msgwin.Add(xxbuf);
449 }
450 }
451
452 return res;
453 }
454
455
InflictDamage(DAMAGE_DATA * pData)456 int XCreature::InflictDamage(DAMAGE_DATA * pData)
457 {
458 assert(pData->target->isValid());
459 if (pData->attacker)
460 pData->target->xai->onWasAttacked(pData->attacker);
461 pData->target->stopAction();
462
463 int damage = pData->damage;
464 damage -= pData->target->_PV; // always - monster PV
465
466 if (damage <= 0)
467 {
468 if (pData->target->isHero())
469 {
470 if (pData->attacker_name)
471 msgwin.Add(pData->attacker_name);
472 else
473 msgwin.Add(pData->attacker->GetNameEx(CRN_T1));
474 msgwin.Add("does not manage to harm you.");
475 } else if (pData->target->isVisible())
476 {
477 msgwin.Add("but does not manage to harm");
478 msgwin.AddLast(pData->target->GetNameEx(CRN_T3));
479 }
480 } else
481 {
482 pData->target->_HP -= damage;
483
484 if (pData->target->_HP > 0)
485 {
486 if (pData->target->isVisible() && !pData->target->isHero())
487 {
488 char buf[256];
489 sprintf(buf, "and %s %s.", pData->target->GetWoundMsg(1), pData->target->GetNameEx(CRN_T3));
490 msgwin.Add(buf);
491 }
492 } else
493 { // and kill IT!!!
494 if (pData->target->isVisible() && !pData->target->isHero())
495 {
496 msgwin.Add("and");
497 if(pData->target->creature_class & CR_UNDEAD)
498 {
499 if (pData->attacker_name)
500 msgwin.Add("destroys");
501 else
502 msgwin.Add(pData->attacker->GetVerb("destroys"));
503 }
504 else
505 {
506 if (pData->attacker_name)
507 msgwin.Add("kills");
508 else
509 msgwin.Add(pData->attacker->GetVerb("kills"));
510 }
511 msgwin.AddLast(pData->target->GetNameEx(CRN_T3));
512 }
513 pData->target->Die(pData->attacker);
514 cr_kiled++; //temporary counter special for statistic
515 return 1;
516 }
517 }
518 return 0;
519 }
520
AttackCreature(XCreature * target,int dmg)521 int XCreature::AttackCreature(XCreature * target, int dmg)
522 {
523 assert(isValid());
524 target->xai->onWasAttacked(this);
525 target->stopAction();
526 if (target->onAttacked(this, dmg))
527 {
528 target->Die(this);
529 cr_kiled++; //temporare counter special for statistic
530 return 1;
531 }
532 return 0;
533 }
534
AttackCreature(XCreature * target,int dmg,RESISTANCE tr,const char * magic_name)535 int XCreature::AttackCreature(XCreature * target, int dmg, RESISTANCE tr, const char * magic_name)
536 {
537 assert(isValid());
538 target->xai->onWasAttacked(this);
539 target->stopAction();
540 if (target->onAttackedByMagic(this, dmg, tr, magic_name))
541 {
542 target->Die(this);
543 cr_kiled++; //temporare counter special for statistic
544 return 1;
545 }
546 return 0;
547 }
548
549
onMagicDamage(int dmg,RESISTANCE tr)550 int XCreature::onMagicDamage(int dmg, RESISTANCE tr)
551 {
552 assert(isValid());
553 int damage = dmg - (dmg * GetResistance(tr)) / 100;
554 return damage < 0 ? 0 : damage;
555 }
556
CauseEffect(int dmg,BRAND_TYPE brt)557 int XCreature::CauseEffect(int dmg, BRAND_TYPE brt)
558 {
559 int damage = dmg;
560
561 if (brt > BR_NONE)
562 {
563 if (brt & BR_FIRE)
564 {
565 damage += onMagicDamage(dmg, R_FIRE);
566 }
567 if (brt & BR_COLD)
568 {
569 damage += onMagicDamage(dmg, R_COLD);
570 }
571 if (brt & BR_DEMONSLAYER && creature_class & CR_DEMON)
572 {
573 damage += dmg * 3;
574 }
575 if (brt & BR_ORCSLAYER && creature_class & CR_ORC)
576 {
577 damage += dmg * 3;
578 }
579 }
580 return damage;
581 }
582
CauseEffect(XCreature * attacker,int dmg,RESISTANCE tr)583 int XCreature::CauseEffect(XCreature * attacker, int dmg, RESISTANCE tr)
584 {
585 int damage = dmg - (dmg * GetResistance(tr)) / 100;
586 damage = damage < 0 ? 0 : damage;
587
588 if (damage > 0)
589 {
590 switch (tr)
591 {
592 case R_WHITE:
593 case R_BLACK:
594 case R_FIRE:
595 case R_WATER:
596 case R_AIR:
597 case R_EARTH:
598 case R_ACID:
599 case R_COLD:
600 break;
601 case R_POISON:
602 md->Add(MOD_POISON, damage, this, attacker);
603 break;
604 case R_DISEASE:
605 md->Add(MOD_DISEASE, damage, this, attacker);
606 break;
607 case R_PARALYSE:
608 md->Add(MOD_PARALYSE, damage, this, attacker);
609 break;
610 case R_STUN:
611 md->Add(MOD_STUN, damage, this, attacker);
612 break;
613 case R_CONFUSE:
614 md->Add(MOD_CONFUSE, damage, this, attacker);
615 break;
616 case R_BLIND:
617 // md->Add(MOD_BLIND, damage, this, attacker);
618 break;
619 default:
620 return 0;
621 }
622 }
623 return damage;
624 }
625
onAttacked(XCreature * attacker,int dmg)626 int XCreature::onAttacked(XCreature * attacker, int dmg)
627 {
628 assert(isValid());
629 int damage = dmg;
630 damage -= _PV; // always - monster PV
631
632 if (damage > 0)
633 _HP -= damage;
634
635 if (_HP > 0)
636 {
637 if (l->map->GetVisible(x, y))
638 {
639 char buf[256];
640 if (damage <= 0)
641 {
642 if (isHero())
643 {
644 msgwin.Add(attacker->GetNameEx(CRN_T1));
645 msgwin.Add("does not manage to harm");
646 msgwin.AddLast(GetNameEx(CRN_T3));
647 } else
648 {
649 msgwin.Add("but does not manage to harm");
650 msgwin.AddLast(GetNameEx(CRN_T3));
651 }
652 } else if (!isHero())
653 {
654 sprintf(buf, "and %s %s.", GetWoundMsg(1), GetNameEx(CRN_T3));
655 msgwin.Add(buf);
656 }
657 }
658
659 if (vRand() % 1000 < 300)
660 {
661 md->Add(MOD_WOUND, damage / 4, this, attacker);
662 }
663
664 if (vRand() % 1000 < 250)
665 {
666 md->Add(MOD_STUN, damage / 4, this, attacker);
667 }
668
669 if (vRand() % 1000 < 150)
670 {
671 md->Add(MOD_CONFUSE, damage / 4, this, attacker);
672 }
673
674
675 return 0;
676 } else
677 { // and kill IT!!!
678 if (l->map->GetVisible(x, y) && !isHero())
679 {
680 msgwin.Add("and");
681 if(creature_class & CR_UNDEAD)
682 msgwin.Add(attacker->GetVerb("destroy"));
683 else
684 msgwin.Add(attacker->GetVerb("kill"));
685 msgwin.AddLast(GetNameEx(CRN_T3));
686 }
687 return 1;
688 }
689 }
690
691
onAttackedByMagic(XCreature * attacker,int dmg,RESISTANCE tr,const char * magic_name)692 int XCreature::onAttackedByMagic(XCreature * attacker, int dmg, RESISTANCE tr, const char * magic_name)
693 {
694 char buf[256];
695 int damage = onMagicDamage(dmg, tr) - _PV;
696
697 if (damage > 0)
698 _HP -= damage;
699
700 if (_HP > 0)
701 {
702 if (l->map->GetVisible(x, y))
703 {
704 if (damage <= 0)
705 {
706 if (isHero())
707 {
708 msgwin.Add(magic_name);
709 msgwin.Add("does not manage to harm");
710 msgwin.AddLast(GetNameEx(CRN_T3));
711 } else
712 {
713 msgwin.Add("but does not manage to harm");
714 msgwin.AddLast(GetNameEx(CRN_T3));
715 }
716 } else if (!isHero())
717 {
718 sprintf(buf, "and %s %s.", attacker->GetWoundMsg(1), GetNameEx(CRN_T3));
719 msgwin.Add(buf);
720 }
721 }
722 return 0;
723 } else
724 { // and kill IT!!!
725 if (l->map->GetVisible(x, y))
726 {
727 msgwin.Add("and");
728 if(creature_class & CR_UNDEAD)
729 msgwin.Add(attacker->GetVerb("destroy"));
730 else
731 msgwin.Add(attacker->GetVerb("kill"));
732 msgwin.AddLast(GetNameEx(CRN_T3));
733 }
734 return 1;
735 }
736 }
737
738
MissileFlight(MF_DATA * mfd)739 MF_RESULT XCreature::MissileFlight(MF_DATA * mfd)
740 {
741 XMap * tmap = mfd->l->map;
742 int range = mfd->max_range;
743 float fdx = float(mfd->ex - mfd->sx);
744 float fdy = float(mfd->ey - mfd->sy);
745 float xrng = (float)sqrt(fdx * fdx + fdy * fdy);
746 float cos_alpha = 0, sin_alpha = 0;
747 if (xrng > 0)
748 {
749 cos_alpha = fdx / xrng;
750 sin_alpha = fdy / xrng;
751 }
752
753 float mx = (float)mfd->sx;
754 float my = (float)mfd->sy;
755 int epx;
756 int epy;
757 int fl_range = 0;
758
759 bool self_flag = false;
760 if (fdx == fdy && fdy == 0.0)
761 self_flag = true;
762
763 while ((range > 0 && (fabs(mfd->ex - mx) >= 0.5f || fabs(mfd->ey - my) >= 0.5f)) || self_flag)
764 {
765 self_flag = false;
766 range--;
767 fl_range++;
768 float nmx = mx + cos_alpha;
769 float nmy = my + sin_alpha;
770 epx = vRound(nmx);
771 epy = vRound(nmy);
772
773 if (tmap->GetMovability(epx, epy) >= MO_WALL)
774 {
775 epx = vRound(mx);
776 epy = vRound(my);
777 break;
778 }
779
780 if (tmap->GetVisible(epx, epy) && __animation_flag)
781 {
782 tmap->Put(main_creature);
783 if (mfd->arrow_type == MFT_BALL)
784 tmap->PutChar(epx, epy, '*', mfd->arrow_color);
785 else
786 {
787 int ttx = vRound(nmx - mx);
788 int tty = vRound(nmy - my);
789 if (ttx * tty == 1)
790 tmap->PutChar(epx, epy, '\\', mfd->arrow_color);
791 else if (ttx * tty == -1)
792 tmap->PutChar(epx, epy, '/', mfd->arrow_color);
793 else if (ttx == 0)
794 tmap->PutChar(epx, epy, '|', mfd->arrow_color);
795 else if (tty == 0)
796 tmap->PutChar(epx, epy, '-', mfd->arrow_color);
797 }
798
799 vRefresh();
800 vDelay(__animation_flag);
801 }
802
803 mx = nmx;
804 my = nmy;
805
806 XCreature * tgt = tmap->GetMonster(epx, epy);
807 if (tgt)
808 {
809 int tdv = tgt->GetDV() + fl_range * tgt->GetDV() / 4;
810 int tht = mfd->to_hit > 0 ? mfd->to_hit : 1;
811 if (tdv < 0)
812 {
813 tht -= tdv;
814 tdv = 0;
815 }
816 int p = (100 * tht + 1) / (tht + tdv + 1) - tdv;
817 if (vRand(100) <= p)
818 {
819 mfd->pt.x = epx;
820 mfd->pt.y = epy;
821 //check for shield
822 int sb = tgt->GetShieldDVBonus();
823 sb += fl_range * sb / 4;
824 if (sb > 0 && vRand(tdv) < sb)
825 {
826 tgt->wsk->UseSkill(WSK_SHIELD);
827 return MF_BLOCK;
828 }
829 return MF_HIT;
830 }
831 }
832 }
833
834 mfd->pt.x = epx;
835 mfd->pt.y = epy;
836 return MF_AVOID;
837 }
838
839
840
continueUseItem()841 int XCreature::continueUseItem()
842 {
843 assert(isValid());
844 XItem * tool = (XItem *)action_data.item.get();
845 assert(tool->im & IM_TOOL);
846 RESULT res = tool->onUse(UIS_CONTINUE, this);
847 if (res != CONTINUE)
848 {
849 action_data.action = A_MOVE;
850 action_data.item = NULL;
851 }
852 return 1;
853 }
854
UseItem(XItem * item)855 int XCreature::UseItem(XItem * item)
856 {
857 assert(isValid());
858 RESULT res = item->onUse(UIS_BEGIN, this);
859 if (res)
860 {
861 if (res == CONTINUE)
862 {
863 action_data.action = A_USETOOL;
864 action_data.item = item;
865 return 1;
866 } else
867 return 1;
868 } else
869 return 0;
870
871 return 1;
872 }
873
TargetOp(TARGET_REASON tr,XTREQUEST * rq,XTRESPONSE * rp)874 int XCreature::TargetOp(TARGET_REASON tr, XTREQUEST * rq, XTRESPONSE * rp)
875 {
876 return 0;
877 }
878
Sacrifice(XItem * item)879 void XCreature::Sacrifice(XItem * item)
880 {
881 assert(isValid());
882 religion.SacrificeItem(this, item, D_UNKNOWN);
883 }
884
885
isCreatureVisible(XCreature * cr)886 int XCreature::isCreatureVisible(XCreature * cr)
887 {
888 assert(isValid());
889 if ((cr->GetResistance(R_INVISIBLE) <= GetResistance(R_SEEINVISIBLE)) || cr == this)
890 return 1;
891 else
892 return 0;
893
894 }
895
isVisible()896 bool XCreature::isVisible()
897 {
898 assert(isValid());
899 if (l->map->GetVisible(x, y))
900 {
901 if (XCreature::main_creature->isCreatureVisible(this))
902 return true;
903 else
904 return false;
905 } else
906 return false;
907 }
908
909