impl TCreature::Damage + overall improvements
This commit is contained in:
parent
d7c11b2716
commit
c4b06256d9
3
TODO.md
3
TODO.md
@ -1,4 +1,7 @@
|
||||
## TODO NEXT
|
||||
- TCreature::Damage
|
||||
- MAP.CC FileNumber: uint32 -> uintptr
|
||||
- MAGIC.CC
|
||||
- TCreature
|
||||
- TPlayer
|
||||
- TNonPlayer
|
||||
|
||||
628
reference/game.c
628
reference/game.c
@ -38167,16 +38167,6 @@ TCreature * GetCreature(Object *Obj)
|
||||
return pTVar1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool IsCreaturePlayer(ulong CreatureID)
|
||||
|
||||
{
|
||||
return CreatureID < 0x40000000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WARNING: Unknown calling convention -- yet parameter storage is locked
|
||||
|
||||
void ProcessSkills(void)
|
||||
@ -38969,49 +38959,6 @@ void WriteKillStatistics(void)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AddKillStatistics(int AttackerRace,int DefenderRace)
|
||||
|
||||
{
|
||||
int iVar1;
|
||||
TRaceData *pTVar2;
|
||||
char *pcVar3;
|
||||
bool bVar4;
|
||||
|
||||
bVar4 = AttackerRace * 0x150 == 0;
|
||||
iVar1 = 6;
|
||||
pTVar2 = RaceData + AttackerRace;
|
||||
pcVar3 = "human";
|
||||
do {
|
||||
if (iVar1 == 0) break;
|
||||
iVar1 = iVar1 + -1;
|
||||
bVar4 = pTVar2->Name[0] == *pcVar3;
|
||||
pTVar2 = (TRaceData *)(pTVar2->Name + 1);
|
||||
pcVar3 = pcVar3 + 1;
|
||||
} while (bVar4);
|
||||
if (bVar4) {
|
||||
KilledCreatures[DefenderRace] = KilledCreatures[DefenderRace] + 1;
|
||||
}
|
||||
iVar1 = 6;
|
||||
bVar4 = DefenderRace * 0x150 == 0;
|
||||
pTVar2 = RaceData + DefenderRace;
|
||||
pcVar3 = "human";
|
||||
do {
|
||||
if (iVar1 == 0) break;
|
||||
iVar1 = iVar1 + -1;
|
||||
bVar4 = pTVar2->Name[0] == *pcVar3;
|
||||
pTVar2 = (TRaceData *)(pTVar2->Name + 1);
|
||||
pcVar3 = pcVar3 + 1;
|
||||
} while (bVar4);
|
||||
if (bVar4) {
|
||||
KilledPlayers[AttackerRace] = KilledPlayers[AttackerRace] + 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WARNING: Unknown calling convention -- yet parameter storage is locked
|
||||
|
||||
void ExitKillStatistics(void)
|
||||
@ -39950,581 +39897,6 @@ void __thiscall TCreature::Death(TCreature *this)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// DWARF original prototype: int Damage(TCreature * this, TCreature * atk, int Damage, int
|
||||
// DamageType)
|
||||
|
||||
int __thiscall TCreature::Damage(TCreature *this,TCreature *atk,int Damage,int DamageType)
|
||||
|
||||
{
|
||||
TConnection *pTVar1;
|
||||
bool bVar2;
|
||||
bool bVar3;
|
||||
ushort uVar4;
|
||||
int iVar5;
|
||||
int iVar6;
|
||||
int iVar7;
|
||||
ulong uVar8;
|
||||
TPlayer *this_00;
|
||||
int iVar9;
|
||||
_func_int_varargs **pp_Var10;
|
||||
TSkill *pTVar11;
|
||||
CreatureType CVar12;
|
||||
TSkill *sk_1;
|
||||
char *pcVar13;
|
||||
Object *pOVar14;
|
||||
char *pcVar15;
|
||||
undefined4 uVar16;
|
||||
TPlayer *pl;
|
||||
int Unjustified;
|
||||
int i;
|
||||
uint local_88;
|
||||
ulong MurdererID;
|
||||
int OldLevel;
|
||||
int b;
|
||||
TSkill *sk;
|
||||
int b_1;
|
||||
ulong atkID;
|
||||
TCreature *Responsible;
|
||||
char Remark [30];
|
||||
Object Obj;
|
||||
Object local_3c [4];
|
||||
Object local_2c;
|
||||
Object Obj_1;
|
||||
|
||||
if (this->IsDead != false) {
|
||||
return 0;
|
||||
}
|
||||
if (this->Type == NPC) {
|
||||
return 0;
|
||||
}
|
||||
if (this->Type == PLAYER) {
|
||||
CVar12 = PLAYER;
|
||||
if ((this->Connection != (TConnection *)0x0) && (atk != (TCreature *)0x0)) {
|
||||
SendMarkCreature((TConnection *)atk->ID,0,(int)this->Connection);
|
||||
CVar12 = this->Type;
|
||||
}
|
||||
if ((((CVar12 == PLAYER) && (atk != (TCreature *)0x0)) && (atk->Type == PLAYER)) &&
|
||||
(((DamageType != 0x20 && (DamageType != 0x40)) && (DamageType != 0x80)))) {
|
||||
Damage = (Damage + 1) / 2;
|
||||
}
|
||||
}
|
||||
atkID = (ulong)atk;
|
||||
if (atk == (TCreature *)0x0) {
|
||||
b_1 = 0;
|
||||
}
|
||||
else {
|
||||
iVar5 = (*atk->_vptr_TCreature[5])(atk);
|
||||
if (iVar5 != 0) {
|
||||
uVar8 = (*atk->_vptr_TCreature[5])(atk);
|
||||
atkID = (ulong)GetCreature(uVar8);
|
||||
}
|
||||
b_1 = atk->ID;
|
||||
}
|
||||
if (atk != (TCreature *)0x0) {
|
||||
BlockLogout(atk,0x3c,this->Type == PLAYER);
|
||||
}
|
||||
if (((atkID != 0) &&
|
||||
(BlockLogout((TCreature *)atkID,0x3c,this->Type == PLAYER), *(int *)(atkID + 0x28c) == 0))
|
||||
&& (this->Type == PLAYER)) {
|
||||
TPlayer::RecordAttack((TPlayer *)atkID,this->ID);
|
||||
}
|
||||
if (Damage < 1) {
|
||||
LAB_080a1ca4:
|
||||
local_2c.ObjectID = (this->CrObject).ObjectID;
|
||||
pOVar14 = &local_2c;
|
||||
}
|
||||
else {
|
||||
if (this->Type == PLAYER) {
|
||||
bVar2 = CheckRight(this->ID,INVULNERABLE);
|
||||
if (bVar2) goto LAB_080a1ca4;
|
||||
if (this->Type == PLAYER) {
|
||||
sk = (TSkill *)0x1;
|
||||
do {
|
||||
if (Damage < 1) goto LAB_080a1c71;
|
||||
bVar2 = false;
|
||||
GetBodyObject((ulong)&local_2c,this->ID);
|
||||
local_3c[0].ObjectID = ::NONE.ObjectID;
|
||||
if (local_2c.ObjectID == ::NONE.ObjectID) {
|
||||
LAB_080a1d02:
|
||||
bVar2 = true;
|
||||
}
|
||||
else {
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
bVar3 = ObjectType::getFlag((ObjectType *)(Remark + 0x1c),PROTECTION);
|
||||
if (!bVar3) goto LAB_080a1d02;
|
||||
}
|
||||
if (!bVar2) {
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
bVar2 = ObjectType::getFlag((ObjectType *)(Remark + 0x1c),CLOTHES);
|
||||
if (bVar2) {
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
pTVar11 = (TSkill *)
|
||||
ObjectType::getAttribute
|
||||
((ObjectType *)(Remark + 0x1c),BODYPOSITION);
|
||||
if (pTVar11 == sk) {
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
uVar8 = ObjectType::getAttribute
|
||||
((ObjectType *)(Remark + 0x1c),
|
||||
PROTECTIONDAMAGETYPES);
|
||||
if ((DamageType & uVar8) != 0) {
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
uVar8 = ObjectType::getAttribute
|
||||
((ObjectType *)(Remark + 0x1c),DAMAGEREDUCTION
|
||||
);
|
||||
Damage = (Damage * (100 - uVar8)) / 100;
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
bVar2 = ObjectType::getFlag((ObjectType *)(Remark + 0x1c),
|
||||
WEAROUT);
|
||||
if (bVar2) {
|
||||
uVar8 = Object::getAttribute(&local_2c,REMAININGUSES);
|
||||
if (uVar8 < 2) {
|
||||
// try { // try from 080a1e9f to 080a1ee8 has its CatchHandler @ 080a1f63
|
||||
Object::getObjectType(local_3c);
|
||||
uVar8 = ObjectType::getAttribute
|
||||
((ObjectType *)local_3c,WEAROUTTARGET)
|
||||
;
|
||||
ObjectType::setTypeID
|
||||
((ObjectType *)(Remark + 0x1c),uVar8);
|
||||
local_3c[0].ObjectID = local_2c.ObjectID;
|
||||
Change(local_3c,(ObjectType *)(Remark + 0x1c),0);
|
||||
}
|
||||
else {
|
||||
stack0xffffffb4 = local_2c.ObjectID;
|
||||
uVar8 = Object::getAttribute(&local_2c,REMAININGUSES);
|
||||
Change((Object *)(Remark + 0x1c),REMAININGUSES,uVar8 - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Object::getObjectType((Object *)(Remark + 0x1c));
|
||||
error("TCreature::Damage: Objekt %d hat PROTECTION, aber nicht CLOTHES.\n"
|
||||
,stack0xffffffb4);
|
||||
}
|
||||
}
|
||||
sk = (TSkill *)((int)&sk->_vptr_TSkill + 1);
|
||||
} while ((int)sk < 0xb);
|
||||
}
|
||||
}
|
||||
if (0 < Damage) {
|
||||
if (DamageType == 0x20) {
|
||||
if (RaceData[this->Race].NoPoison != false) {
|
||||
return 0;
|
||||
}
|
||||
pTVar11 = (this->super_TSkillBase).Skills[0x11];
|
||||
iVar5 = (*pTVar11->_vptr_TSkill[0xd])(pTVar11);
|
||||
if (iVar5 < Damage) {
|
||||
this->PoisonDamageOrigin = b_1;
|
||||
TSkillBase::SetTimer(&this->super_TSkillBase);
|
||||
}
|
||||
pp_Var10 = this->_vptr_TCreature;
|
||||
uVar16 = 0x20;
|
||||
LAB_080a1b71:
|
||||
(*pp_Var10[7])(this,b_1,Damage,uVar16);
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
if (DamageType == 0x40) {
|
||||
if (RaceData[this->Race].NoBurning != false) {
|
||||
return 0;
|
||||
}
|
||||
this->FireDamageOrigin = b_1;
|
||||
TSkillBase::SetTimer(&this->super_TSkillBase);
|
||||
pp_Var10 = this->_vptr_TCreature;
|
||||
uVar16 = 0x40;
|
||||
goto LAB_080a1b71;
|
||||
}
|
||||
if (DamageType == 0x80) {
|
||||
if (RaceData[this->Race].NoEnergy != false) {
|
||||
return 0;
|
||||
}
|
||||
this->EnergyDamageOrigin = b_1;
|
||||
TSkillBase::SetTimer(&this->super_TSkillBase);
|
||||
pp_Var10 = this->_vptr_TCreature;
|
||||
uVar16 = 0x80;
|
||||
goto LAB_080a1b71;
|
||||
}
|
||||
if (DamageType == 1) {
|
||||
uVar4 = TCombat::GetArmorStrength(&this->Combat);
|
||||
Damage = Damage - (uint)uVar4;
|
||||
if (0 < Damage) goto LAB_080a0dd2;
|
||||
}
|
||||
else {
|
||||
LAB_080a0dd2:
|
||||
if ((((DamageType != 2) || (RaceData[this->Race].NoPoison == false)) &&
|
||||
(((DamageType != 4 || (RaceData[this->Race].NoBurning == false)) &&
|
||||
((DamageType != 8 || (RaceData[this->Race].NoEnergy == false)))))) &&
|
||||
(((DamageType != 1 || (RaceData[this->Race].NoHit == false)) &&
|
||||
((DamageType != 0x100 || (RaceData[this->Race].NoLifeDrain == false)))))) {
|
||||
pOVar14 = (Object *)Damage;
|
||||
iVar5 = DamageType;
|
||||
(*this->_vptr_TCreature[7])(this,b_1,Damage,DamageType);
|
||||
bVar2 = false;
|
||||
if (((this->Outfit).OutfitID == 0) && ((this->Outfit).field_1.ObjectType == 0))
|
||||
{
|
||||
bVar2 = true;
|
||||
}
|
||||
if ((bVar2) && (this->Type != PLAYER)) {
|
||||
iVar5 = 0;
|
||||
TSkillBase::SetTimer(&this->super_TSkillBase);
|
||||
iVar9 = (this->OrgOutfit).OutfitID;
|
||||
(this->Outfit).field_1 = (this->OrgOutfit).field_1;
|
||||
(this->Outfit).OutfitID = iVar9;
|
||||
AnnounceChangedCreature(this->ID,3);
|
||||
pOVar14 = (Object *)(Remark + 0x1c);
|
||||
stack0xffffffb4 = ::NONE.ObjectID;
|
||||
local_3c[0].ObjectID = (this->CrObject).ObjectID;
|
||||
b_1 = 2;
|
||||
NotifyAllCreatures(local_3c,2,pOVar14);
|
||||
}
|
||||
if (DamageType == 0x200) {
|
||||
pTVar11 = (this->super_TSkillBase).Skills[3];
|
||||
iVar5 = TSkill::Get(pTVar11);
|
||||
if (iVar5 < Damage) {
|
||||
Damage = TSkill::Get(pTVar11);
|
||||
}
|
||||
if ((Object *)Damage != (Object *)0x0) {
|
||||
TSkill::Change(pTVar11,-Damage);
|
||||
if ((this->Type == PLAYER) && (this->Connection != (TConnection *)0x0))
|
||||
{
|
||||
SendMessage(this->Connection,0x15,"You lose %d mana.",Damage);
|
||||
}
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),0xe);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
TextualEffect();
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
pTVar11 = (this->super_TSkillBase).Skills[0x15];
|
||||
iVar5 = (*pTVar11->_vptr_TSkill[0xd])(pTVar11,b_1,pOVar14,iVar5);
|
||||
if ((0 < iVar5) ||
|
||||
(iVar5 = TSkill::Get((this->super_TSkillBase).Skills[0x15]), 0 < iVar5)) {
|
||||
pTVar11 = (this->super_TSkillBase).Skills[3];
|
||||
iVar5 = TSkill::Get(pTVar11);
|
||||
if (Damage <= iVar5) {
|
||||
TSkill::Change(pTVar11,-Damage);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),2);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
TextualEffect();
|
||||
if (this->Type != PLAYER) {
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
pTVar1 = this->Connection;
|
||||
if (pTVar1 != (TConnection *)0x0) {
|
||||
if (atk == (TCreature *)0x0) {
|
||||
SendMessage(pTVar1,0x15,"You lose %d mana.",Damage);
|
||||
}
|
||||
else {
|
||||
SendMessage(pTVar1,0x15,
|
||||
"You lose %d mana blocking an attack by %s.",Damage,
|
||||
atk->Name);
|
||||
}
|
||||
SendPlayerData(this->Connection);
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
iVar5 = TSkill::Get(pTVar11);
|
||||
Damage = Damage - iVar5;
|
||||
(*pTVar11->_vptr_TSkill[2])(pTVar11,0);
|
||||
}
|
||||
pTVar11 = (this->super_TSkillBase).Skills[2];
|
||||
iVar5 = TSkill::Get(pTVar11);
|
||||
if (iVar5 < Damage) {
|
||||
Damage = TSkill::Get(pTVar11);
|
||||
}
|
||||
TSkill::Change(pTVar11,-Damage);
|
||||
if ((TCreature *)atkID == atk) {
|
||||
pOVar14 = (Object *)Damage;
|
||||
if (atk != (TCreature *)0x0) goto LAB_080a0fec;
|
||||
}
|
||||
else {
|
||||
if (atkID != 0) {
|
||||
TCombat::AddDamageToCombatList
|
||||
(&this->Combat,*(ulong *)(atkID + 0x208),(ushort)(Damage / 2))
|
||||
;
|
||||
}
|
||||
if (atk != (TCreature *)0x0) {
|
||||
pOVar14 = (Object *)(Damage / 2);
|
||||
LAB_080a0fec:
|
||||
TCombat::AddDamageToCombatList(&this->Combat,atk->ID,(ushort)pOVar14);
|
||||
}
|
||||
}
|
||||
if (DamageType == 4) {
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
iVar5 = 0x10;
|
||||
LAB_080a17a3:
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),iVar5);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)0xc6;
|
||||
LAB_080a1080:
|
||||
pcVar15 = "%d";
|
||||
TextualEffect();
|
||||
}
|
||||
else {
|
||||
if (4 < DamageType) {
|
||||
if (DamageType == 8) {
|
||||
switchD_080a1623_caseD_4:
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),0xc);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)0x23;
|
||||
}
|
||||
else {
|
||||
if (DamageType != 0x100) goto LAB_080a102f;
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),0xe);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)0xb4;
|
||||
}
|
||||
goto LAB_080a1080;
|
||||
}
|
||||
if (DamageType != 1) {
|
||||
if (DamageType != 2) {
|
||||
LAB_080a102f:
|
||||
error(&DAT_08101f00,DamageType);
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),9);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)0x1e;
|
||||
goto LAB_080a1080;
|
||||
}
|
||||
pcVar15 = (char *)this->Race;
|
||||
switch(RaceData[(int)pcVar15].Blood) {
|
||||
case BT_BLOOD:
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),1);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
TextualEffect();
|
||||
local_3c[0].ObjectID = (this->CrObject).ObjectID;
|
||||
// try { // try from 080a1684 to 080a16b8 has its CatchHandler @ 080a1fb1
|
||||
GetMapContainer((Object *)(Remark + 0x1c));
|
||||
pOVar14 = &local_2c;
|
||||
GetSpecialObject((SPECIALMEANING)pOVar14);
|
||||
pcVar15 = (char *)0x5;
|
||||
CreatePool();
|
||||
break;
|
||||
case BT_SLIME:
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),0x11);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
TextualEffect();
|
||||
local_3c[0].ObjectID = (this->CrObject).ObjectID;
|
||||
// try { // try from 080a171a to 080a174e has its CatchHandler @ 080a1fb1
|
||||
GetMapContainer((Object *)(Remark + 0x1c));
|
||||
pOVar14 = &local_2c;
|
||||
GetSpecialObject((SPECIALMEANING)pOVar14);
|
||||
pcVar15 = (char *)0x6;
|
||||
CreatePool();
|
||||
break;
|
||||
case BT_BONES:
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
GraphicalEffect((Object *)(Remark + 0x1c),10);
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)0x81;
|
||||
goto LAB_080a1080;
|
||||
case BT_FIRE:
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
iVar5 = 1;
|
||||
goto LAB_080a17a3;
|
||||
case BT_ENERGY:
|
||||
goto switchD_080a1623_caseD_4;
|
||||
default:
|
||||
pOVar14 = (Object *)RaceData[(int)pcVar15].Blood;
|
||||
error(&DAT_08101fe0,pOVar14,pcVar15);
|
||||
}
|
||||
}
|
||||
if ((this->Type == PLAYER) &&
|
||||
(pTVar1 = this->Connection, pTVar1 != (TConnection *)0x0)) {
|
||||
if (atk == (TCreature *)0x0) {
|
||||
pcVar15 = "You lose %d hitpoint%s.";
|
||||
pcVar13 = "";
|
||||
if ((Object *)Damage != (Object *)0x1) {
|
||||
pcVar13 = "s";
|
||||
}
|
||||
pOVar14 = (Object *)0x15;
|
||||
SendMessage(pTVar1,0x15,"You lose %d hitpoint%s.",Damage,pcVar13);
|
||||
}
|
||||
else {
|
||||
pcVar13 = "";
|
||||
pcVar15 = "You lose %d hitpoint%s due to an attack by %s.";
|
||||
pOVar14 = (Object *)0x15;
|
||||
if ((Object *)Damage != (Object *)0x1) {
|
||||
pcVar13 = "s";
|
||||
}
|
||||
SendMessage(pTVar1,0x15,"You lose %d hitpoint%s due to an attack by %s."
|
||||
,Damage,pcVar13,atk->Name);
|
||||
}
|
||||
SendPlayerData(this->Connection);
|
||||
}
|
||||
iVar5 = TSkill::Get(pTVar11);
|
||||
if (0 < iVar5) goto LAB_080a1103;
|
||||
if (this->Type == PLAYER) {
|
||||
OldLevel = 1;
|
||||
do {
|
||||
pOVar14 = (Object *)this->ID;
|
||||
pcVar15 = (char *)OldLevel;
|
||||
GetBodyObject((ulong)(Remark + 0x1c),(int)pOVar14);
|
||||
local_3c[0].ObjectID = ::NONE.ObjectID;
|
||||
if (stack0xffffffb4 != ::NONE.ObjectID) {
|
||||
Object::getObjectType(local_3c);
|
||||
pOVar14 = (Object *)0x2e;
|
||||
bVar2 = ObjectType::getFlag((ObjectType *)local_3c,CLOTHES);
|
||||
if (bVar2) {
|
||||
Object::getObjectType(local_3c);
|
||||
pOVar14 = (Object *)0x16;
|
||||
uVar8 = ObjectType::getAttribute
|
||||
((ObjectType *)local_3c,BODYPOSITION);
|
||||
if (uVar8 == OldLevel) {
|
||||
Object::getObjectType(local_3c);
|
||||
pcVar15 = (char *)0xc;
|
||||
pOVar14 = (Object *)0x4d;
|
||||
GetNewObjectType((uchar)&local_2c,'M');
|
||||
if (local_3c[0].ObjectID == local_2c.ObjectID) {
|
||||
pcVar15 = this->Name;
|
||||
Log("game","%s stirbt mit Amulett of Loss.\n",pcVar15);
|
||||
this->LoseInventory = 0;
|
||||
pOVar14 = (Object *)0xffffffff;
|
||||
local_3c[0].ObjectID = stack0xffffffb4;
|
||||
// try { // try from 080a159b to 080a159f has its CatchHandler @ 080a1fc8
|
||||
Delete(local_3c,-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OldLevel = OldLevel + 1;
|
||||
} while (OldLevel < 0xb);
|
||||
}
|
||||
iVar5 = TSkill::Get((this->super_TSkillBase).Skills[0]);
|
||||
(*this->_vptr_TCreature[2])(this,pOVar14,pcVar15);
|
||||
if ((atk != (TCreature *)0x0) && (this->Type == PLAYER)) {
|
||||
BlockLogout(atk,900,true);
|
||||
}
|
||||
if ((atkID != 0) && (this->Type == PLAYER)) {
|
||||
BlockLogout((TCreature *)atkID,900,true);
|
||||
}
|
||||
Responsible = (TCreature *)((uint)Responsible & 0xffffff00);
|
||||
local_88 = 0;
|
||||
if (atk == (TCreature *)0x0) {
|
||||
iVar9 = this->Race;
|
||||
iVar7 = strcmp(RaceData[0].Name,"human");
|
||||
if (iVar7 == 0) {
|
||||
KilledCreatures[iVar9] = KilledCreatures[iVar9] + 1;
|
||||
}
|
||||
uVar16 = 6;
|
||||
iVar9 = strcmp(RaceData[iVar9].Name,"human");
|
||||
if (iVar9 == 0) {
|
||||
KilledPlayers[0] = KilledPlayers[0] + 1;
|
||||
}
|
||||
if (DamageType == 2) {
|
||||
Responsible = (TCreature *)0x73696f70;
|
||||
Remark[0] = 'o';
|
||||
Remark[1] = 'n';
|
||||
LAB_080a1479:
|
||||
Remark[2] = '\0';
|
||||
}
|
||||
else if (DamageType < 3) {
|
||||
if (DamageType == 1) {
|
||||
Responsible = (TCreature *)0x69682061;
|
||||
Remark[0] = 't';
|
||||
Remark[1] = '\0';
|
||||
}
|
||||
else {
|
||||
LAB_080a1436:
|
||||
error(&DAT_08101f80,DamageType,uVar16);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (DamageType != 4) {
|
||||
if (DamageType == 8) {
|
||||
Responsible = (TCreature *)0x72656e65;
|
||||
Remark[0] = 'g';
|
||||
Remark[1] = 'y';
|
||||
goto LAB_080a1479;
|
||||
}
|
||||
goto LAB_080a1436;
|
||||
}
|
||||
Responsible = (TCreature *)0x65726966;
|
||||
Remark._0_2_ = Remark._0_2_ & 0xff00;
|
||||
}
|
||||
}
|
||||
else {
|
||||
iVar9 = atk->Race;
|
||||
iVar7 = this->Race;
|
||||
iVar6 = strcmp(RaceData[iVar9].Name,"human");
|
||||
if (iVar6 == 0) {
|
||||
KilledCreatures[iVar7] = KilledCreatures[iVar7] + 1;
|
||||
}
|
||||
iVar7 = strcmp(RaceData[iVar7].Name,"human");
|
||||
if (iVar7 == 0) {
|
||||
KilledPlayers[iVar9] = KilledPlayers[iVar9] + 1;
|
||||
}
|
||||
strcpy(this->Murderer,atk->Name);
|
||||
if ((atkID != 0) && (*(int *)(atkID + 0x28c) == 0)) {
|
||||
local_88 = *(uint *)(atkID + 0x208);
|
||||
}
|
||||
if (atk->Type != PLAYER) {
|
||||
strcpy((char *)&Responsible,atk->Name);
|
||||
}
|
||||
}
|
||||
if (this->Type == PLAYER) {
|
||||
Unjustified = 1;
|
||||
do {
|
||||
uVar8 = local_88;
|
||||
if (Unjustified != 1) {
|
||||
uVar8 = TCombat::GetMostDangerousAttacker(&this->Combat);
|
||||
}
|
||||
if ((Unjustified != 2) ||
|
||||
(((uVar8 != 0 && (uVar8 != local_88)) && (uVar8 < 0x40000000)))) {
|
||||
bVar2 = false;
|
||||
if (uVar8 - 1 < 0x3fffffff) {
|
||||
this_00 = GetPlayer(uVar8);
|
||||
if (this_00 == (TPlayer *)0x0) goto LAB_080a1376;
|
||||
bVar2 = TPlayer::IsAttackJustified(this_00,this->ID);
|
||||
bVar2 = !bVar2;
|
||||
TPlayer::RecordMurder(this_00,this->ID);
|
||||
}
|
||||
bVar3 = false;
|
||||
if (this->ID != uVar8) {
|
||||
bVar3 = bVar2;
|
||||
}
|
||||
CharacterDeathOrder(this,iVar5,uVar8,(char *)&Responsible,bVar3);
|
||||
Responsible = (TCreature *)((uint)Responsible & 0xffffff00);
|
||||
}
|
||||
LAB_080a1376:
|
||||
Unjustified = Unjustified + 1;
|
||||
} while (Unjustified < 3);
|
||||
}
|
||||
LAB_080a1103:
|
||||
AnnounceChangedCreature(this->ID,1);
|
||||
return (int)(Object *)Damage;
|
||||
}
|
||||
}
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)(Remark + 0x1c);
|
||||
iVar5 = 4;
|
||||
goto LAB_080a1a50;
|
||||
}
|
||||
LAB_080a1c71:
|
||||
unique0x00009680 = (this->CrObject).ObjectID;
|
||||
pOVar14 = (Object *)(Remark + 0x1c);
|
||||
}
|
||||
iVar5 = 3;
|
||||
LAB_080a1a50:
|
||||
GraphicalEffect(pOVar14,iVar5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WARNING: Variable defined which should be unmapped: Execute_local
|
||||
// DWARF original prototype: bool MovePossible(TCreature * this, int x, int y, int z, bool Execute,
|
||||
// bool Jump)
|
||||
|
||||
@ -839,10 +839,17 @@ void TCombat::DistanceAttack(TCreature *Target){
|
||||
ANIMATION_NONE, 2, &Impact, EFFECT_BURST_ARROW);
|
||||
}
|
||||
|
||||
if(random(0, 99) < Fragility){
|
||||
Delete(this->Ammo, 1);
|
||||
}else{
|
||||
Move(0, this->Ammo, DropCon, 1, false, NONE);
|
||||
try{
|
||||
if(random(0, 99) < Fragility){
|
||||
Delete(this->Ammo, 1);
|
||||
}else{
|
||||
Move(0, this->Ammo, DropCon, 1, false, NONE);
|
||||
}
|
||||
}catch(RESULT err){
|
||||
if(err != DESTROYED){
|
||||
error("TCombat::RangeAttack: Konnte Ammo nicht verschieben/löschen"
|
||||
" (Exception %d, [%d,%d,%d].\n", err, DropX, DropY, DropZ);
|
||||
}
|
||||
}
|
||||
|
||||
if(!Hit){
|
||||
@ -918,11 +925,12 @@ void TCombat::DistributeExperiencePoints(uint32 Exp){
|
||||
int MasterLevel = Master->Skills[SKILL_LEVEL]->Get();
|
||||
int AttackerLevel = Attacker->Skills[SKILL_LEVEL]->Get();
|
||||
int MaxLevel = (MasterLevel * 11) / 10;
|
||||
if(AttackerLevel < MaxLevel){
|
||||
Amount = ((MaxLevel - AttackerLevel) * Amount) / MasterLevel;
|
||||
}else{
|
||||
Amount = 0;
|
||||
}
|
||||
if(AttackerLevel <= MaxLevel){
|
||||
continue;
|
||||
}
|
||||
|
||||
Amount = ((MaxLevel - AttackerLevel) * Amount) / MasterLevel;
|
||||
print(3, "%s erhält %d EXP.\n", Attacker->Name, Amount);
|
||||
}
|
||||
|
||||
if(Amount > 0){
|
||||
@ -944,8 +952,8 @@ void TCombat::DistributeExperiencePoints(uint32 Exp){
|
||||
}
|
||||
}
|
||||
|
||||
Attacker->Skills[0]->Increase(Amount);
|
||||
TextualEffect(Attacker->CrObject, 0xD7, "%d", Amount);
|
||||
Attacker->Skills[SKILL_LEVEL]->Increase(Amount);
|
||||
TextualEffect(Attacker->CrObject, COLOR_WHITE, "%d", Amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
416
src/creature.cc
416
src/creature.cc
@ -1,4 +1,5 @@
|
||||
#include "creature.hh"
|
||||
#include "monster.hh"
|
||||
#include "enums.hh"
|
||||
|
||||
#include "stubs.hh"
|
||||
@ -54,3 +55,418 @@ TCreature::TCreature(void) :
|
||||
void TCreature::Attack(void){
|
||||
this->Combat.Attack();
|
||||
}
|
||||
|
||||
// TODO(fusion): This probably belongs elsewhere but we should come back to
|
||||
// this when we're wrapping up creature files.
|
||||
static bool IsCreaturePlayer(uint32 CreatureID){
|
||||
return CreatureID < 0x40000000;
|
||||
}
|
||||
|
||||
// TODO(fusion): This probably belongs elsewhere but we should come back to
|
||||
// this when we're wrapping up creature files.
|
||||
static void AddKillStatistics(int AttackerRace, int DefenderRace){
|
||||
// NOTE(fusion): I think the race name can be "human" only for players,
|
||||
// which means we're probably tracking how many creatures are killed by
|
||||
// players with `KilledCreatures`, and how many players are killed by
|
||||
// creatures with `KilledPlayers`.
|
||||
|
||||
if(strcmp(RaceData[AttackerRace].Name, "human") == 0){
|
||||
KilledCreatures[DefenderRace] += 1;
|
||||
}
|
||||
|
||||
// NOTE(fusion): This seems to track how many players are killed by
|
||||
if(strcmp(RaceData[DefenderRace].Name, "human") == 0){
|
||||
KilledPlayers[AttackerRace] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){
|
||||
if(this->IsDead || this->Type == NPC){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(this->Type == PLAYER){
|
||||
if(this->Connection != NULL && Attacker != NULL){
|
||||
SendMarkCreature(this->Connection, Attacker->ID, COLOR_BLACK);
|
||||
}
|
||||
|
||||
if(Attacker != NULL && Attacker->Type == PLAYER
|
||||
&& DamageType != DAMAGE_POISON_PERIODIC
|
||||
&& DamageType != DAMAGE_FIRE_PERIODIC
|
||||
&& DamageType != DAMAGE_ENERGY_PERIODIC){
|
||||
Damage = (Damage + 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(fusion): `Responsible` is either the attacker or its master. It is
|
||||
// always valid if `Attacker` is not NULL.
|
||||
TCreature *Responsible = Attacker;
|
||||
if(Attacker != NULL){
|
||||
uint32 MasterID = Attacker->GetMaster();
|
||||
if(MasterID != 0){
|
||||
Responsible = GetCreature(MasterID);
|
||||
}
|
||||
|
||||
Attacker->BlockLogout(60, this->Type == PLAYER);
|
||||
if(Responsible != Attacker){
|
||||
Responsible->BlockLogout(60, this->Type == PLAYER);
|
||||
}
|
||||
|
||||
if(this->Type == PLAYER && Responsible->Type == PLAYER){
|
||||
((TPlayer*)Responsible)->RecordAttack(this->ID);
|
||||
}
|
||||
}
|
||||
|
||||
if(this->Type == PLAYER){
|
||||
if(CheckRight(this->ID, INVULNERABLE)){
|
||||
Damage = 0;
|
||||
}
|
||||
|
||||
// NOTE(fusion): We're iterating over the victim's inventory to apply
|
||||
// damage reductions, while the damage is greater than zero.
|
||||
for(int Position = 1;
|
||||
Position <= 10 && Damage > 0;
|
||||
Position += 1){
|
||||
Object Obj = GetBodyObject(this->ID, Position);
|
||||
if(Obj == NONE){
|
||||
continue;
|
||||
}
|
||||
|
||||
ObjectType ObjType = Obj.getObjectType();
|
||||
if(ObjType.getFlag(PROTECTION) && ObjType.getFlag(CLOTHES)
|
||||
&& (int)ObjType.getAttribute(BODYPOSITION) == Position
|
||||
&& (ObjType.getAttribute(PROTECTIONDAMAGETYPES) & DamageType) != 0){
|
||||
int DamageReduction = ObjType.getAttribute(DAMAGEREDUCTION);
|
||||
Damage = (Damage * (100 - DamageReduction)) / 100;
|
||||
if(ObjType.getFlag(WEAROUT)){
|
||||
// TODO(fusion): Ugh... The try..catch block might be used only
|
||||
// when changing the object's type.
|
||||
try{
|
||||
uint32 RemainingUses = Obj.getAttribute(REMAININGUSES);
|
||||
if(RemainingUses > 1){
|
||||
Change(Obj, REMAININGUSES, RemainingUses - 1);
|
||||
}else{
|
||||
ObjectType WearOutType = ObjType.getAttribute(WEAROUTTARGET);
|
||||
Change(Obj, WearOutType, 0);
|
||||
}
|
||||
}catch(RESULT err){
|
||||
error("TCreature::Damage: Exception %d beim Abnutzen von Objekt %d.\n",
|
||||
err, ObjType.TypeID);
|
||||
}
|
||||
}
|
||||
}else if(ObjType.getFlag(PROTECTION) && !ObjType.getFlag(CLOTHES)){
|
||||
error("TCreature::Damage: Objekt %d hat PROTECTION, aber nicht CLOTHES.\n",
|
||||
ObjType.TypeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Damage <= 0){
|
||||
GraphicalEffect(this->CrObject, EFFECT_POFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(DamageType == DAMAGE_POISON_PERIODIC){
|
||||
if(RaceData[this->Race].NoPoison){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Damage > this->Skills[SKILL_POISON]->TimerValue()){
|
||||
this->PoisonDamageOrigin = Attacker->ID;
|
||||
this->SetTimer(SKILL_POISON, Damage, 3, 3, -1);
|
||||
}
|
||||
|
||||
this->DamageStimulus(Attacker->ID, Damage, DamageType);
|
||||
return Damage;
|
||||
}else if(DamageType == DAMAGE_FIRE_PERIODIC){
|
||||
if(RaceData[this->Race].NoBurning){
|
||||
return 0;
|
||||
}
|
||||
|
||||
this->FireDamageOrigin = Attacker->ID;
|
||||
this->SetTimer(SKILL_BURNING, Damage / 10, 8, 8, -1);
|
||||
this->DamageStimulus(Attacker->ID, Damage, DamageType);
|
||||
return Damage;
|
||||
}else if(DamageType == DAMAGE_ENERGY_PERIODIC){
|
||||
if(RaceData[this->Race].NoEnergy){
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(fusion): Shouldn't we use `Damage / 25` here?
|
||||
this->EnergyDamageOrigin = Attacker->ID;
|
||||
this->SetTimer(SKILL_ENERGY, Damage / 20, 10, 10, -1);
|
||||
this->DamageStimulus(Attacker->ID, Damage, DamageType);
|
||||
return Damage;
|
||||
}
|
||||
|
||||
if((DamageType == DAMAGE_PHYSICAL && RaceData[this->Race].NoHit)
|
||||
|| (DamageType == DAMAGE_POISON && RaceData[this->Race].NoPoison)
|
||||
|| (DamageType == DAMAGE_FIRE && RaceData[this->Race].NoBurning)
|
||||
|| (DamageType == DAMAGE_ENERGY && RaceData[this->Race].NoEnergy)
|
||||
|| (DamageType == DAMAGE_LIFEDRAIN && RaceData[this->Race].NoLifeDrain)){
|
||||
GraphicalEffect(this->CrObject, EFFECT_BLOCK_HIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(DamageType == DAMAGE_PHYSICAL){
|
||||
Damage -= this->Combat.GetArmorStrength();
|
||||
if(Damage <= 0){
|
||||
GraphicalEffect(this->CrObject, EFFECT_BLOCK_HIT);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
this->DamageStimulus(Attacker->ID, Damage, DamageType);
|
||||
|
||||
// NOTE(fusion): Remove non-player illusion. Might as well be an inlined
|
||||
// function.
|
||||
if(this->Type != PLAYER
|
||||
&& this->Outfit.OutfitID == 0
|
||||
&& this->Outfit.ObjectType == 0){
|
||||
this->SetTimer(SKILL_ILLUSION, 0, 0, 0, -1);
|
||||
this->Outfit = this->OrgOutfit;
|
||||
AnnounceChangedCreature(this->ID, 3); // CREATURE_OUTFIT_CHANGED ?
|
||||
NotifyAllCreatures(this->CrObject, 2, NONE); // CREATURE_APPEAR ?
|
||||
}
|
||||
|
||||
if(DamageType == DAMAGE_MANADRAIN){
|
||||
int ManaPoints = this->Skills[SKILL_MANA]->Get();
|
||||
if(Damage > ManaPoints){
|
||||
Damage = ManaPoints;
|
||||
}
|
||||
|
||||
if(Damage > 0){
|
||||
this->Skills[SKILL_MANA]->Change(-Damage);
|
||||
if(this->Type == PLAYER && this->Connection != NULL){
|
||||
SendMessage(this->Connection, TALK_STATUS_MESSAGE,
|
||||
"You lose %d mana.", Damage);
|
||||
}
|
||||
GraphicalEffect(this->CrObject, EFFECT_MAGIC_RED);
|
||||
TextualEffect(this->CrObject, COLOR_BLUE, "%d", Damage);
|
||||
}
|
||||
|
||||
return Damage;
|
||||
}
|
||||
|
||||
if(this->Skills[SKILL_MANASHIELD]->TimerValue() > 0
|
||||
|| this->Skills[SKILL_MANASHIELD]->Get() > 0){
|
||||
// NOTE(fusion): We only send these if the attack was fully absorbed,
|
||||
// else it'd be overwritten by whatever effect and messages we send
|
||||
// next, when the victim's hitpoints are actually touched.
|
||||
int ManaPoints = this->Skills[SKILL_MANA]->Get();
|
||||
if(Damage <= ManaPoints){
|
||||
this->Skills[SKILL_MANA]->Change(-Damage);
|
||||
GraphicalEffect(this->CrObject, EFFECT_MANA_HIT);
|
||||
TextualEffect(this->CrObject, COLOR_BLUE, "%d", Damage);
|
||||
if(this->Type == PLAYER && this->Connection != NULL){
|
||||
if(Attacker != NULL){
|
||||
SendMessage(this->Connection, TALK_STATUS_MESSAGE,
|
||||
"You lose %d mana blocking an attack by %s.",
|
||||
Damage, Attacker->Name);
|
||||
}else{
|
||||
SendMessage(this->Connection, TALK_STATUS_MESSAGE,
|
||||
"You lose %d mana.", Damage);
|
||||
}
|
||||
SendPlayerData(this->Connection);
|
||||
}
|
||||
return Damage;
|
||||
}
|
||||
|
||||
this->Skills[SKILL_MANA]->Set(0);
|
||||
Damage -= ManaPoints;
|
||||
}
|
||||
|
||||
int HitPoints = this->Skills[SKILL_HITPOINTS]->Get();
|
||||
if(Damage > HitPoints){
|
||||
Damage = HitPoints;
|
||||
}
|
||||
|
||||
this->Skills[SKILL_HITPOINTS]->Change(-Damage);
|
||||
if(Responsible != NULL){
|
||||
ASSERT(Attacker != NULL);
|
||||
if(Responsible == Attacker){
|
||||
this->Combat.AddDamageToCombatList(Attacker->ID, Damage);
|
||||
}else{
|
||||
this->Combat.AddDamageToCombatList(Attacker->ID, Damage / 2);
|
||||
this->Combat.AddDamageToCombatList(Responsible->ID, Damage / 2);
|
||||
}
|
||||
}
|
||||
|
||||
int HitEffect = EFFECT_NONE;
|
||||
int TextColor = COLOR_BLACK;
|
||||
int SplashLiquid = LIQUID_NONE;
|
||||
if(DamageType == DAMAGE_PHYSICAL){
|
||||
switch(RaceData[this->Race].Blood){
|
||||
case BT_BLOOD:{
|
||||
HitEffect = EFFECT_BLOOD_HIT;
|
||||
TextColor = COLOR_RED;
|
||||
SplashLiquid = LIQUID_BLOOD;
|
||||
break;
|
||||
}
|
||||
case BT_SLIME:{
|
||||
HitEffect = EFFECT_POISON_HIT;
|
||||
TextColor = COLOR_LIGHTGREEN;
|
||||
SplashLiquid = LIQUID_SLIME;
|
||||
break;
|
||||
}
|
||||
case BT_BONES:{
|
||||
HitEffect = EFFECT_BONE_HIT;
|
||||
TextColor = COLOR_LIGHTGRAY;
|
||||
break;
|
||||
}
|
||||
case BT_FIRE:{
|
||||
HitEffect = EFFECT_FIRE_HIT;
|
||||
TextColor = COLOR_ORANGE;
|
||||
break;
|
||||
}
|
||||
case BT_ENERGY:{
|
||||
HitEffect = EFFECT_ENERGY_HIT;
|
||||
TextColor = COLOR_LIGHTBLUE;
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
error("TCreature::Damage: Ungültiger Bluttyp %d für Rasse %d.\n",
|
||||
RaceData[this->Race].Blood, this->Race);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(Damage == DAMAGE_POISON){
|
||||
HitEffect = EFFECT_POISON;
|
||||
TextColor = COLOR_LIGHTGREEN;
|
||||
}else if(DamageType == DAMAGE_FIRE){
|
||||
HitEffect = EFFECT_FIRE_HIT;
|
||||
TextColor = COLOR_ORANGE;
|
||||
}else if(DamageType == DAMAGE_ENERGY){
|
||||
HitEffect = EFFECT_ENERGY_HIT;
|
||||
TextColor = COLOR_LIGHTBLUE;
|
||||
}else if(DamageType == DAMAGE_LIFEDRAIN){
|
||||
HitEffect = EFFECT_MAGIC_RED;
|
||||
TextColor = COLOR_RED;
|
||||
}else{
|
||||
// TODO(fusion): The original decompiled function would return here but
|
||||
// I don't think it's a good idea because it would skip death handling.
|
||||
error("TCreature::Damage: Ungültiger Schadenstyp %d.\n", DamageType);
|
||||
//return Damage;
|
||||
}
|
||||
|
||||
if(HitEffect != EFFECT_NONE){
|
||||
GraphicalEffect(this->CrObject, HitEffect);
|
||||
TextualEffect(this->CrObject, TextColor, "%d", Damage);
|
||||
if(SplashLiquid != LIQUID_NONE){
|
||||
CreatePool(GetMapContainer(this->CrObject),
|
||||
GetSpecialObject(BLOOD_SPLASH),
|
||||
SplashLiquid);
|
||||
}
|
||||
}
|
||||
|
||||
if(this->Type == PLAYER && this->Connection != NULL){
|
||||
if(Attacker != NULL){
|
||||
SendMessage(this->Connection, TALK_STATUS_MESSAGE,
|
||||
"You lose %d hitpoint%s due to an attack by %s.",
|
||||
Damage, (Damage == 1 ? "" : "s"), Attacker->Name);
|
||||
}else{
|
||||
SendMessage(this->Connection, TALK_STATUS_MESSAGE,
|
||||
"You lose %d hitpoint%s.",
|
||||
Damage, (Damage == 1 ? "" : "s"));
|
||||
}
|
||||
SendPlayerData(this->Connection);
|
||||
}
|
||||
|
||||
if(Damage == HitPoints){
|
||||
if(this->Type == PLAYER){
|
||||
for(int Position = 1; Position <= 10; Position += 1){
|
||||
Object Obj = GetBodyObject(this->ID, Position);
|
||||
if(Obj == NONE){
|
||||
continue;
|
||||
}
|
||||
|
||||
ObjectType ObjType = Obj.getObjectType();
|
||||
if(ObjType.getFlag(CLOTHES) && (int)ObjType.getAttribute(BODYPOSITION) == Position){
|
||||
ObjectType AmuletOfLossType = GetNewObjectType(77, 12);
|
||||
if(ObjType == AmuletOfLossType){
|
||||
Log("game", "%s stirbt mit Amulett of Loss.\n", this->Name);
|
||||
this->LoseInventory = 0;
|
||||
Delete(Obj, -1);
|
||||
// TODO(fusion): Shouldn't we break here? We could also
|
||||
// just check if there is an amulet of loss in the necklace
|
||||
// container instead of iterating over all of them.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int OldLevel = this->Skills[SKILL_LEVEL]->Get();
|
||||
this->Death();
|
||||
if(Attacker != NULL && this->Type == PLAYER){
|
||||
Attacker->BlockLogout(900, true);
|
||||
if(Responsible != Attacker){
|
||||
Responsible->BlockLogout(900, true);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 MurdererID = 0;
|
||||
char Remark[30] = {};
|
||||
if(Attacker == NULL){
|
||||
AddKillStatistics(0, this->Race);
|
||||
if(DamageType == DAMAGE_PHYSICAL){
|
||||
strcpy(Remark, "a hit");
|
||||
}else if(DamageType == DAMAGE_POISON){
|
||||
strcpy(Remark, "poison");
|
||||
}else if(DamageType == DAMAGE_FIRE){
|
||||
strcpy(Remark, "fire");
|
||||
}else if(DamageType == DAMAGE_ENERGY){
|
||||
strcpy(Remark, "energy");
|
||||
}else{
|
||||
// NOTE(fusion): We probably don't expect any other damage type
|
||||
// as the cause of death when there is no attacker.
|
||||
error("TCreature::Damage: Ungültiger Schadenstyp %d als Todesursache.\n", DamageType);
|
||||
}
|
||||
}else{
|
||||
AddKillStatistics(Attacker->Race, this->Race);
|
||||
strcpy(this->Murderer, Attacker->Name);
|
||||
|
||||
if(Responsible->Type == PLAYER){
|
||||
MurdererID = Responsible->ID;
|
||||
}
|
||||
|
||||
if(Attacker->Type != PLAYER){
|
||||
strcpy(Remark, Attacker->Name);
|
||||
}
|
||||
}
|
||||
|
||||
if(this->Type == PLAYER){
|
||||
if(MurdererID != 0 && MurdererID != this->ID){
|
||||
bool Justified = true;
|
||||
if(IsCreaturePlayer(MurdererID)){
|
||||
TPlayer *Murderer = GetPlayer(MurdererID);
|
||||
if(Murderer != NULL){
|
||||
Justified = Murderer->IsAttackJustified(this->ID);
|
||||
Murderer->RecordMurder(this->ID);
|
||||
}
|
||||
}
|
||||
CharacterDeathOrder(this, OldLevel, MurdererID, Remark, !Justified);
|
||||
}
|
||||
|
||||
uint32 MostDangerousID = this->Combat.GetMostDangerousAttacker();
|
||||
if(MostDangerousID != 0
|
||||
&& MostDangerousID != MurdererID
|
||||
&& MostDangerousID != this->ID
|
||||
&& IsCreaturePlayer(MostDangerousID)){
|
||||
bool Justified = true;
|
||||
TPlayer *MostDangerous = GetPlayer(MostDangerousID);
|
||||
if(MostDangerous != NULL){
|
||||
Justified = MostDangerous->IsAttackJustified(this->ID);
|
||||
MostDangerous->RecordMurder(this->ID);
|
||||
}
|
||||
|
||||
// TODO(fusion): The original function is confusing at this point
|
||||
// but it seems correct that the remark is included only with the
|
||||
// murderer.
|
||||
CharacterDeathOrder(this, OldLevel, MostDangerousID, "", !Justified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnnounceChangedCreature(this->ID, 1); // CREATURE_HITPOINTS_CHANGED ?
|
||||
return Damage;
|
||||
}
|
||||
|
||||
33
src/enums.hh
33
src/enums.hh
@ -45,10 +45,16 @@ enum ChaseMode: uint8 {
|
||||
CHASE_MODE_RANGE = 2,
|
||||
};
|
||||
|
||||
enum CreatureType: int {
|
||||
PLAYER = 0,
|
||||
MONSTER = 1,
|
||||
NPC = 2,
|
||||
// NOTE(fusion): Not in debug symbols.
|
||||
enum Color: int {
|
||||
COLOR_BLACK = 0,
|
||||
COLOR_BLUE = 5,
|
||||
COLOR_LIGHTGREEN = 30,
|
||||
COLOR_LIGHTBLUE = 35,
|
||||
COLOR_LIGHTGRAY = 129,
|
||||
COLOR_RED = 180,
|
||||
COLOR_ORANGE = 198,
|
||||
COLOR_WHITE = 215,
|
||||
};
|
||||
|
||||
enum CONNECTIONSTATE: int {
|
||||
@ -62,6 +68,12 @@ enum CONNECTIONSTATE: int {
|
||||
CONNECTION_DISCONNECTED = 7,
|
||||
};
|
||||
|
||||
enum CreatureType: int {
|
||||
PLAYER = 0,
|
||||
MONSTER = 1,
|
||||
NPC = 2,
|
||||
};
|
||||
|
||||
// NOTE(fusion): Not in debug symbols.
|
||||
enum DamageType: int {
|
||||
DAMAGE_NONE = 0x0000,
|
||||
@ -77,9 +89,20 @@ enum DamageType: int {
|
||||
DAMAGE_MANADRAIN = 0x0200,
|
||||
};
|
||||
|
||||
// TODO(fusion): Review these names.
|
||||
enum EffectType: int {
|
||||
EFFECT_NONE = 0,
|
||||
EFFECT_BLOOD_HIT = 1,
|
||||
EFFECT_MANA_HIT = 2,
|
||||
EFFECT_POFF = 3,
|
||||
EFFECT_BURST_ARROW = 7, // Review
|
||||
EFFECT_BLOCK_HIT = 4,
|
||||
EFFECT_BURST_ARROW = 7,
|
||||
EFFECT_POISON = 9,
|
||||
EFFECT_BONE_HIT = 10,
|
||||
EFFECT_ENERGY_HIT = 12,
|
||||
EFFECT_MAGIC_RED = 14,
|
||||
EFFECT_FIRE_HIT = 16,
|
||||
EFFECT_POISON_HIT = 17,
|
||||
};
|
||||
|
||||
enum FLAG: int {
|
||||
|
||||
@ -85,6 +85,9 @@ struct TMonster: TNonplayer {
|
||||
};
|
||||
#endif
|
||||
|
||||
//#define MAX_RACES 512
|
||||
extern TRaceData RaceData[512];
|
||||
extern int KilledCreatures[512];
|
||||
extern int KilledPlayers[512];
|
||||
|
||||
#endif //TIBIA_MONSTER_HH_
|
||||
|
||||
@ -77,6 +77,7 @@ struct TPlayer: TCreature {
|
||||
|
||||
bool IsAttackJustified(uint32 Victim);
|
||||
void RecordAttack(uint32 Victim);
|
||||
void RecordMurder(uint32 Victim);
|
||||
|
||||
void CheckState(void);
|
||||
|
||||
|
||||
@ -19,17 +19,21 @@ extern void AbortWriter(void);
|
||||
extern void AnnounceChangedCreature(uint32 CreatureID, int Type);
|
||||
extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3);
|
||||
extern void Change(Object Obj, ObjectType NewType, uint32 Value);
|
||||
extern void CharacterDeathOrder(TCreature *Creature, int OldLevel,
|
||||
uint32 Offender, const char *Remark, bool Unjustified);
|
||||
extern bool CheckRight(uint32 CreatureID, RIGHT Right);
|
||||
extern void CircleShapeSpell(TCreature *Actor, int DestX, int DestY, int DestZ,
|
||||
int Range, int Animation, int Radius, TImpact *Impact, int Effect);
|
||||
extern void CleanHouseField(int x, int y, int z);
|
||||
extern int ComputeDamage(TCreature *Creature, int SpellNr, int Damage, int Variation);
|
||||
extern void CreatePlayerList(bool Online);
|
||||
extern void CreatePool(Object Con, ObjectType Type, uint32 Value);
|
||||
extern void Delete(Object Obj, int Count);
|
||||
extern Object GetBodyObject(uint32 CreatureID, int Position);
|
||||
extern TCreature *GetCreature(uint32 CreatureID);
|
||||
extern TConnection *GetFirstConnection(void);
|
||||
extern TConnection *GetNextConnection(void);
|
||||
extern TPlayer *GetPlayer(uint32 CreatureID);
|
||||
extern int GetRacePoison(int Race);
|
||||
extern void GraphicalEffect(int x, int y, int z, int Type);
|
||||
extern void GraphicalEffect(Object Obj, int Type);
|
||||
@ -61,6 +65,7 @@ extern void SendAll(void);
|
||||
extern void SendAmbiente(TConnection *Connection);
|
||||
extern void SendClearTarget(TConnection *Connection);
|
||||
extern void SendMails(TPlayerData *PlayerData);
|
||||
extern void SendMarkCreature(TConnection *Connection, uint32 CreatureID, int Color);
|
||||
extern void SendMessage(TConnection *Connection, int Mode, const char *Text, ...) ATTR_PRINTF(3, 4);
|
||||
extern void SendPlayerData(TConnection *Connection);
|
||||
extern void SendPlayerSkills(TConnection *Connection);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user