aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-03 16:00:35 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-03 16:00:35 -0300
commitdbee845a5cfb6ca419604ac984d1845440f76007 (patch)
treef3a0e626c70867f01805c35ac6ad243e3df04a2f
parenta1e062c8b27fcf2f65d5a21fc85fbcc80abfa86f (diff)
downloadgame-dbee845a5cfb6ca419604ac984d1845440f76007.tar.gz
game-dbee845a5cfb6ca419604ac984d1845440f76007.zip
more spells
-rw-r--r--Makefile2
-rw-r--r--reference/game.c1139
-rw-r--r--src/creature.cc22
-rw-r--r--src/creature.hh1
-rw-r--r--src/magic.cc584
-rw-r--r--src/stubs.hh4
6 files changed, 604 insertions, 1148 deletions
diff --git a/Makefile b/Makefile
index d804d60..99b89aa 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ endif
HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/config.hh $(SRCDIR)/connection.hh $(SRCDIR)/containers.hh $(SRCDIR)/crcombat.hh $(SRCDIR)/creature.hh $(SRCDIR)/crskill.hh $(SRCDIR)/enums.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/monster.hh $(SRCDIR)/objects.hh $(SRCDIR)/player.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/thread.hh
$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/config.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/creature.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/player.obj $(BUILDDIR)/script.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/thread.obj $(BUILDDIR)/time.obj $(BUILDDIR)/util.obj
- $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
+ $(CC) -c $(CFLAGS) $(LFLAGS) -o $@ $^
$(BUILDDIR)/config.obj: $(SRCDIR)/config.cc $(HEADERS)
@mkdir -p $(@D)
diff --git a/reference/game.c b/reference/game.c
index 65ac6f5..b469c0e 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -20852,1145 +20852,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-void SummonCreature(TCreature *cr,int Mana,int Race,bool God)
-
-{
- bool bVar1;
- ulong Father;
- int iVar2;
- undefined4 *puVar3;
- int Delay;
- int iStack_28;
- bool God_local;
- int posx;
- int posy;
- int posz;
-
- if (cr == (TCreature *)0x0) {
- error(&DAT_080fb980);
- }
- else {
- if (Race - 1U < 0x1ff) {
- if (God) {
- bVar1 = CheckRight(cr->ID,CREATE_MONSTERS);
- if (!bVar1) {
- return;
- }
- }
- else {
- if (((cr->Type == PLAYER) && (bVar1 = CheckRight(cr->ID,CREATE_MONSTERS), !bVar1))
- && (bVar1 = GetRaceNoSummon(Race), bVar1)) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 1;
- goto LAB_08083d9d;
- }
- if (((!God) && (cr->Type == PLAYER)) && (1 < cr->SummonedCreatures)) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x38;
- goto LAB_08083d9d;
- }
- }
- iStack_28 = cr->posx;
- posx = cr->posy;
- posy = cr->posz;
- // try { // try from 08083cd8 to 08083e67 has its CatchHandler @ 08083e70
- bVar1 = SearchSummonField(&stack0xffffffd8,&posx,&posy,2);
- if (bVar1) {
- if (!God) {
- iVar2 = GetRaceSummonCost(Race);
- Delay = 1000;
- if (WorldType != PVP_ENFORCED) {
- Delay = 2000;
- }
- CheckMana(cr,iVar2 + Mana,0,Delay);
- }
- Father = 0;
- if (!God) {
- Father = cr->ID;
- }
- CreateMonster(Race,iStack_28,posx,posy,0,Father,true);
- posz = (cr->CrObject).ObjectID;
- GraphicalEffect((Object *)&posz,0xd);
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 4;
- goto LAB_08083d9d;
- }
- error(&DAT_080fb940,Race);
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_08083d9d:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: God_local
-
-void SummonCreature(TCreature *cr,int Mana,char *RaceName,bool God)
-
-{
- char *pcVar1;
- int iVar2;
- undefined4 *puVar3;
- int i;
- int Race_00;
- int Race;
- int Race_01;
- bool God_local;
-
- if (cr == (TCreature *)0x0) {
- pcVar1 = &DAT_080fb980;
- }
- else {
- if (RaceName != (char *)0x0) {
- Race_00 = 1;
- do {
- // try { // try from 08083ec6 to 08083f54 has its CatchHandler @ 08083f72
- pcVar1 = GetRaceName(Race_00);
- iVar2 = stricmp(RaceName,pcVar1,-1);
- Race_01 = Race_00;
- if (iVar2 == 0) break;
- Race_00 = Race_00 + 1;
- Race_01 = 0;
- } while (Race_00 < 0x200);
- if (Race_01 != 0) {
- SummonCreature(cr,Mana,Race_01,God);
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x19;
- goto LAB_08083f2d;
- }
- pcVar1 = &DAT_080fb9c0;
- }
- error(pcVar1);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_08083f2d:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-void StartMonsterraid(TCreature *cr,char *RaidName)
-
-{
- bool bVar1;
- undefined4 *puVar2;
- char *Text;
- Object local_102c [4];
- char local_101c [4];
- char FileName [4096];
-
- if (cr == (TCreature *)0x0) {
- Text = &DAT_080fba40;
- }
- else {
- if (RaidName != (char *)0x0) {
- // try { // try from 08083fc9 to 0808403f has its CatchHandler @ 08084130
- bVar1 = CheckRight(cr->ID,CREATE_MONSTERS);
- if (bVar1) {
- strLower(RaidName);
- snprintf(local_101c,0x1000,"%s/%s.evt",MONSTERPATH,RaidName);
- bVar1 = FileExists(local_101c);
- if (bVar1) {
- // try { // try from 0808406e to 08084094 has its CatchHandler @ 080840d9
- LoadMonsterRaid(local_101c,RoundNr,(bool *)0x0,(int *)0x0,(int *)0x0,(int *)0x0)
- ;
- local_102c[0].ObjectID = (cr->CrObject).ObjectID;
- GraphicalEffect(local_102c,0xd);
- }
- else {
- local_102c[0].ObjectID = (cr->CrObject).ObjectID;
- GraphicalEffect(local_102c,3);
- }
- }
- return;
- }
- Text = &DAT_080fba00;
- }
- // try { // try from 080840a1 to 080840cf has its CatchHandler @ 08084130
- error(Text);
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void RaiseDead(void)
-
-{
- bool bVar1;
- uint uVar2;
- undefined4 *puVar3;
- ulong uVar4;
- int Delay;
- TCreature *in_stack_00000004;
- Object *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- char *Text;
- int *y_00;
- int *z_00;
- int local_48;
- int x;
- int y;
- int z;
- Object local_2c [7];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbac0;
- }
- else {
- // try { // try from 08084160 to 080843fa has its CatchHandler @ 08084420
- bVar1 = Object::exists(in_stack_00000008);
- if (bVar1) {
- local_2c[0].ObjectID = in_stack_00000008->ObjectID;
- GetObjectCoordinates(local_2c,&local_48,&x,&y);
- if (y == in_stack_00000004->posz) {
- uVar2 = local_48 - in_stack_00000004->posx;
- if (0x7fffffff < uVar2) {
- uVar2 = -uVar2;
- }
- if ((int)uVar2 < 2) {
- uVar2 = x - in_stack_00000004->posy;
- if (0x7fffffff < uVar2) {
- uVar2 = -uVar2;
- }
- if ((int)uVar2 < 2) {
- GetFirstObject();
- in_stack_00000008->ObjectID = z;
- local_2c[0].ObjectID = NONE.ObjectID;
- if (z != NONE.ObjectID) {
- do {
- z = NONE.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- Object::getObjectType((Object *)&z);
- bVar1 = ObjectType::getFlag((ObjectType *)&z,CORPSE);
- if (bVar1) {
- Object::getObjectType((Object *)&z);
- uVar4 = ObjectType::getAttribute((ObjectType *)&z,CORPSETYPE);
- if (uVar4 == 1) break;
- }
- Object::getNextObject(local_2c);
- in_stack_00000008->ObjectID = local_2c[0].ObjectID;
- bVar1 = local_2c[0].ObjectID != NONE.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- } while (bVar1);
- }
- z = NONE.ObjectID;
- if (in_stack_00000008->ObjectID == NONE.ObjectID) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1d;
- }
- else {
- z_00 = &y;
- y_00 = &x;
- bVar1 = SearchFreeField(&local_48,y_00,z_00,1,0,false);
- if ((bVar1) &&
- (y_00 = (int *)x, z_00 = (int *)y, bVar1 = IsProtectionZone(), !bVar1
- )) {
- Delay = 1000;
- if (WorldType != PVP_ENFORCED) {
- Delay = 2000;
- }
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,
- Delay);
- z = in_stack_00000008->ObjectID;
- Delete((Object *)&z,-1);
- CreateMonster(0x21,local_48,x,y,0,in_stack_00000004->ID,true);
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4,y_00,z_00);
- *puVar3 = 4;
- }
- goto LAB_08084322;
- }
- }
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 5;
- goto LAB_08084322;
- }
- Text = &DAT_080fba80;
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_08084322:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void MassRaiseDead(void)
-
-{
- bool bVar1;
- ulong uVar2;
- undefined4 *puVar3;
- int zx;
- int iVar4;
- TCreature *in_stack_00000004;
- Object *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- int in_stack_00000014;
- char *Text;
- int dx;
- int *local_88;
- int dy;
- int j;
- int i;
- int sx;
- int sy;
- int sz;
- int x;
- int y;
- int z;
- ulong local_4c;
- Object Help;
- Object local_3c;
- Object Obj;
- Object local_2c [7];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbb40;
- }
- else {
- // try { // try from 08084463 to 08084842 has its CatchHandler @ 08084860
- bVar1 = Object::exists(in_stack_00000008);
- if (bVar1) {
- local_2c[0].ObjectID = in_stack_00000008->ObjectID;
- GetObjectCoordinates(local_2c,&sz,&x,&y);
- bVar1 = ThrowPossible(in_stack_00000004->posx,in_stack_00000004->posy,
- in_stack_00000004->posz,sz,x,y,0);
- if (bVar1) {
- iVar4 = 1000;
- if (WorldType != PVP_ENFORCED) {
- iVar4 = 2000;
- }
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,iVar4);
- if (((in_stack_00000004->posx != sz) || (in_stack_00000004->posy != x)) ||
- (in_stack_00000004->posz != y)) {
- local_2c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GetMapContainer((int)&local_3c,sz,x);
- Missile(local_2c,&local_3c,5);
- }
- j = 0;
- if (-1 < in_stack_00000014) {
- local_88 = &Circle[0].Count;
- dx = 0;
- do {
- dy = 0;
- iVar4 = dx;
- if (0 < *local_88) {
- do {
- zx = Circle[0].x[iVar4 + dy] + sz;
- iVar4 = Circle[0].y[iVar4 + dy] + x;
- bVar1 = ThrowPossible(sz,x,y,zx,iVar4,y,0);
- if (bVar1) {
- GraphicalEffect();
- GetFirstObject();
- local_4c = NONE.ObjectID;
- local_2c[0].ObjectID = local_4c;
- if (local_3c.ObjectID != NONE.ObjectID) {
- do {
- local_4c = local_3c.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- Object::getNextObject((Object *)&z);
- local_3c.ObjectID = z;
- local_2c[0].ObjectID = z;
- Object::getObjectType((Object *)&z);
- bVar1 = ObjectType::getFlag((ObjectType *)&z,CORPSE);
- if (bVar1) {
- Object::getObjectType((Object *)&z);
- uVar2 = ObjectType::getAttribute
- ((ObjectType *)&z,CORPSETYPE);
- if (uVar2 == 1) {
- sy = y;
- i = zx;
- sx = iVar4;
- bVar1 = SearchFreeField(&i,&sx,&sy,1,0,false);
- if ((bVar1) &&
- (bVar1 = IsProtectionZone(), !bVar1)) {
- z = local_4c;
- Delete((Object *)&z,-1);
- CreateMonster(0x21,i,sx,sy,0,
- in_stack_00000004->ID,false);
- }
- }
- }
- local_2c[0].ObjectID = NONE.ObjectID;
- local_4c = NONE.ObjectID;
- } while (local_3c.ObjectID != NONE.ObjectID);
- }
- }
- dy = dy + 1;
- iVar4 = j * 0x41;
- } while (dy < *local_88);
- }
- j = j + 1;
- local_88 = local_88 + 0x41;
- dx = dx + 0x41;
- } while (j <= in_stack_00000014);
- }
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 7;
- goto LAB_0808481f;
- }
- Text = &DAT_080fbb00;
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_0808481f:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void Heal(void)
-
-{
- TSkill *this;
- int iVar1;
- undefined4 *puVar2;
- TSkill *sk;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- char *Text;
- Object local_1c [4];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbbc0;
- }
- else {
- if (WorldType == NON_PVP) {
- iVar1 = (*in_stack_00000004->_vptr_TCreature[4])();
- if ((char)iVar1 == '\0') {
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 1;
- goto LAB_0808496b;
- }
- }
- // try { // try from 080848bd to 0808498a has its CatchHandler @ 080849b0
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- this = (in_stack_00000004->super_TSkillBase).Skills[2];
- if (this != (TSkill *)0x0) {
- iVar1 = TSkill::Get(this);
- if (0 < iVar1) {
- TSkill::Change(this,in_stack_00000010);
- if ((in_stack_00000004->super_TSkillBase).Skills[4]->MDAct < 0) {
- TSkillBase::SetTimer(&in_stack_00000004->super_TSkillBase);
- }
- local_1c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_1c,0xd);
- }
- return;
- }
- Text = "Heal: Skill HITPOINTS existiert nicht.\n";
- }
- error(Text);
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0xffffffff;
-LAB_0808496b:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void MassHeal(void)
-
-{
- TSkill *this;
- bool bVar1;
- TCreature *pTVar2;
- int iVar3;
- undefined4 *puVar4;
- TCreature *in_stack_00000004;
- Object *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- int in_stack_00000014;
- int in_stack_00000018;
- char *Text;
- ulong *puVar5;
- int local_78;
- int *local_74;
- int local_70;
- int j;
- int i;
- int x;
- int y;
- int z;
- ulong local_4c;
- Object Help;
- Object local_3c;
- Object Obj;
- Object local_2c [7];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbc80;
- }
- else {
- // try { // try from 080849f3 to 08084d1a has its CatchHandler @ 08084d73
- bVar1 = Object::exists(in_stack_00000008);
- if (bVar1) {
- local_2c[0].ObjectID = in_stack_00000008->ObjectID;
- GetObjectCoordinates(local_2c,&i,&x,&y);
- bVar1 = ThrowPossible(in_stack_00000004->posx,in_stack_00000004->posy,
- in_stack_00000004->posz,i,x,y,0);
- if (bVar1) {
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,1000);
- if (((in_stack_00000004->posx != i) || (in_stack_00000004->posy != x)) ||
- (in_stack_00000004->posz != y)) {
- local_2c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GetMapContainer((int)&local_3c,i,x);
- Missile(local_2c,&local_3c,5);
- }
- j = 0;
- if (-1 < in_stack_00000018) {
- local_74 = &Circle[0].Count;
- local_78 = 0;
- do {
- local_70 = 0;
- iVar3 = local_78;
- if (0 < *local_74) {
- do {
- bVar1 = ThrowPossible(i,x,y,i + Circle[0].x[iVar3 + local_70],
- x + Circle[0].y[iVar3 + local_70],y,0);
- if (bVar1) {
- GraphicalEffect();
- GetFirstObject();
- local_4c = NONE.ObjectID;
- local_2c[0].ObjectID = local_4c;
- if (local_3c.ObjectID != NONE.ObjectID) {
- do {
- puVar5 = &local_4c;
- local_4c = local_3c.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- Object::getNextObject((Object *)&z);
- local_3c.ObjectID = z;
- local_2c[0].ObjectID = z;
- Object::getObjectType((Object *)&z);
- if (z == 99) {
- z = local_4c;
- pTVar2 = GetCreature((Object *)&z);
- if (pTVar2 == (TCreature *)0x0) {
- error(&DAT_080fe061,puVar5);
- }
- else if ((WorldType != NON_PVP) ||
- (iVar3 = (*pTVar2->_vptr_TCreature[4])
- (pTVar2),
- (char)iVar3 != '\0')) {
- this = (pTVar2->super_TSkillBase).Skills[2];
- if (this == (TSkill *)0x0) {
- Text =
- "MassHeal: Skill HITPOINTS existiert nicht.\n";
- goto LAB_08084ccb;
- }
- iVar3 = TSkill::Get(this);
- if ((0 < iVar3) &&
- (TSkill::Change(this,in_stack_00000014),
- (pTVar2->super_TSkillBase).Skills[4]->MDAct < 0
- )) {
- TSkillBase::SetTimer
- (&pTVar2->super_TSkillBase);
- }
- }
- }
- local_2c[0].ObjectID = NONE.ObjectID;
- local_4c = NONE.ObjectID;
- } while (local_3c.ObjectID != NONE.ObjectID);
- }
- }
- local_70 = local_70 + 1;
- iVar3 = j * 0x41;
- } while (local_70 < *local_74);
- }
- j = j + 1;
- local_74 = local_74 + 0x41;
- local_78 = local_78 + 0x41;
- } while (j <= in_stack_00000018);
- }
- return;
- }
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = 7;
- goto LAB_08084ce2;
- }
- Text = &DAT_080fbc40;
- }
-LAB_08084ccb:
- error(Text);
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = 0xffffffff;
-LAB_08084ce2:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar4,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void HealFriend(void)
-
-{
- TSkill *this;
- int iVar1;
- uint uVar2;
- undefined4 *puVar3;
- TSkill *sk;
- TCreature *in_stack_00000004;
- char *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- int in_stack_00000014;
- char *Text;
- TPlayer *local_20;
- TPlayer *pl;
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbd40;
- }
- else {
- if (in_stack_00000008 != (char *)0x0) {
- // try { // try from 08084dc8 to 08084f34 has its CatchHandler @ 08084f83
- iVar1 = IdentifyPlayer(in_stack_00000008,false,true,&local_20);
- if (iVar1 == -1) {
-LAB_08084eff:
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1b;
- }
- else {
- if (iVar1 == -2) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1c;
- goto LAB_08084f11;
- }
- if (in_stack_00000004->posz == (local_20->super_TCreature).posz) {
- uVar2 = in_stack_00000004->posx - (local_20->super_TCreature).posx;
- if (0x7fffffff < uVar2) {
- uVar2 = -uVar2;
- }
- if ((int)uVar2 < 8) {
- uVar2 = in_stack_00000004->posy - (local_20->super_TCreature).posy;
- if (0x7fffffff < uVar2) {
- uVar2 = -uVar2;
- }
- if ((int)uVar2 < 6) {
- this = (local_20->super_TCreature).super_TSkillBase.Skills[2];
- if (this == (TSkill *)0x0) {
- Text = "HealFriend: Skill HITPOINTS existiert nicht.\n";
- goto LAB_08084f30;
- }
- iVar1 = TSkill::Get(this);
- if (0 < iVar1) {
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,1000
- );
- TSkill::Change(this,in_stack_00000014);
- if ((local_20->super_TCreature).super_TSkillBase.Skills[4]->MDAct <
- 0) {
- TSkillBase::SetTimer
- (&(local_20->super_TCreature).super_TSkillBase);
- }
- pl = (TPlayer *)(in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect((Object *)&pl,0xd);
- pl = (TPlayer *)(local_20->super_TCreature).CrObject.ObjectID;
- GraphicalEffect((Object *)&pl,0xf);
- return;
- }
- goto LAB_08084eff;
- }
- }
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 5;
- }
- goto LAB_08084f11;
- }
- Text = &DAT_080fbd00;
- }
-LAB_08084f30:
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_08084f11:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void RefreshMana(void)
-
-{
- TSkill *this;
- undefined4 *puVar1;
- TSkill *sk;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- char *Text;
- Object local_1c [5];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbdc0;
- }
- else {
- // try { // try from 08084fcd to 08085040 has its CatchHandler @ 08085050
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- this = (in_stack_00000004->super_TSkillBase).Skills[3];
- if (this != (TSkill *)0x0) {
- TSkill::Change(this,in_stack_00000010);
- local_1c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_1c,0xd);
- return;
- }
- Text = "RefreshMana: Skill MANA existiert nicht.\n";
- }
- error(Text);
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar1,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void MagicGoStrength(void)
-
-{
- TSkill *this;
- bool bVar1;
- char cVar2;
- undefined4 *puVar3;
- TSkill *sk;
- int mdact;
- int iVar4;
- TCreature *in_stack_00000004;
- int *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- int in_stack_00000014;
- char *Text;
- Object local_2c [7];
-
- if (in_stack_00000008 == (int *)0x0) {
- Text = &DAT_080fbe40;
- }
- else {
- if (in_stack_00000004 != (TCreature *)0x0) {
- if (-1 < in_stack_00000014) {
-LAB_080850a0:
- // try { // try from 080850b9 to 0808522b has its CatchHandler @ 08085250
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,1000);
- this = (TSkill *)in_stack_00000008[5];
- if (in_stack_00000014 < -100) {
- iVar4 = -0x14 - this->Act;
- }
- else {
- iVar4 = (this->Act * in_stack_00000014) / 100;
- }
- TSkill::SetMDAct(this,iVar4);
- TSkillBase::SetTimer((TSkillBase *)(in_stack_00000008 + 1));
- if (in_stack_00000014 < 0) {
- TCreature::BlockLogout(in_stack_00000004,0x3c,in_stack_00000008[0xa3] == 0);
- }
- local_2c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_2c,0xf);
- local_2c[0].ObjectID = in_stack_00000008[0xb4];
- GraphicalEffect(local_2c,0xe);
- return;
- }
- bVar1 = GetRaceNoParalyze(in_stack_00000008[0xa0]);
- if (!bVar1) {
- if (WorldType == NON_PVP) {
- iVar4 = (*in_stack_00000004->_vptr_TCreature[4])();
- if ((char)iVar4 != '\0') {
- cVar2 = (**(code **)(*in_stack_00000008 + 0x10))();
- if (cVar2 != '\0') {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x2b;
- goto LAB_080851f1;
- }
- }
- }
- goto LAB_080850a0;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 1;
- goto LAB_080851f1;
- }
- Text = &DAT_080fbe00;
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_080851f1:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void Shielding(void)
-
-{
- undefined4 *puVar1;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- Object local_1c [4];
-
- if (in_stack_00000004 != (TCreature *)0x0) {
- // try { // try from 0808529f to 0808532a has its CatchHandler @ 08085330
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- TSkillBase::SetTimer(&in_stack_00000004->super_TSkillBase);
- local_1c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_1c,0xd);
- return;
- }
- error(&DAT_080fbe80);
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar1,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void NegatePoison(void)
-
-{
- undefined4 *puVar1;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- char *Text;
- Object local_1c [5];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fbf00;
- }
- else {
- if (in_stack_00000010 != 0) {
- // try { // try from 08085384 to 08085414 has its CatchHandler @ 08085420
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- TSkillBase::SetTimer((TSkillBase *)(in_stack_00000010 + 4));
- local_1c[0].ObjectID = *(ulong *)(in_stack_00000010 + 0x2d0);
- GraphicalEffect(local_1c,0xd);
- return;
- }
- Text = "NegatePoison: Zielkreatur existiert nicht.\n";
- }
- error(Text);
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar1,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void Enlight(void)
-
-{
- TSkill *pTVar1;
- int iVar2;
- undefined4 *puVar3;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- Object local_1c [4];
-
- if (in_stack_00000004 != (TCreature *)0x0) {
- // try { // try from 08085473 to 08085511 has its CatchHandler @ 08085512
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- pTVar1 = (in_stack_00000004->super_TSkillBase).Skills[0xf];
- iVar2 = (*pTVar1->_vptr_TSkill[0xd])(pTVar1);
- if (iVar2 <= in_stack_00000010) {
- TSkillBase::SetTimer(&in_stack_00000004->super_TSkillBase);
- }
- local_1c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_1c,0xd);
- return;
- }
- error(&DAT_080fbf40);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void Invisibility(void)
-
-{
- undefined4 *puVar1;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- Object local_1c [4];
-
- if (in_stack_00000004 != (TCreature *)0x0) {
- // try { // try from 08085563 to 080855ff has its CatchHandler @ 08085600
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- (in_stack_00000004->Outfit).field_1.ObjectType = 0;
- (in_stack_00000004->Outfit).OutfitID = 0;
- TSkillBase::SetTimer(&in_stack_00000004->super_TSkillBase);
- local_1c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_1c,0xd);
- return;
- }
- error(&DAT_080fbf80);
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar1,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void CancelInvisibility(void)
-
-{
- anon_union_4_2_730cd3ca_for_TOutfit_2 aVar1;
- bool bVar2;
- bool bVar3;
- bool bVar4;
- TCreature *pTVar5;
- int iVar6;
- long lVar7;
- ulong uVar8;
- undefined4 *puVar9;
- TCreature *in_stack_00000004;
- Object *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- int in_stack_00000014;
- char *Text;
- int dx;
- int local_a0;
- int *local_9c;
- ulong local_94;
- int b;
- TCreature *dest;
- bool EffectShown;
- int dy;
- int j;
- int i;
- int x;
- int y;
- int z;
- Object local_5c;
- Object Item;
- _func_int_varargs **local_4c;
- Object Help;
- Object local_3c;
- Object Obj;
- Object local_2c [7];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fc040;
- }
- else {
- // try { // try from 08085643 to 08085bec has its CatchHandler @ 08085c10
- bVar3 = Object::exists(in_stack_00000008);
- if (bVar3) {
- local_2c[0].ObjectID = in_stack_00000008->ObjectID;
- GetObjectCoordinates(local_2c,&i,&x,&y);
- bVar3 = ThrowPossible(in_stack_00000004->posx,in_stack_00000004->posy,
- in_stack_00000004->posz,i,x,y,0);
- if (bVar3) {
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,1000);
- if (((in_stack_00000004->posx != i) || (in_stack_00000004->posy != x)) ||
- (in_stack_00000004->posz != y)) {
- local_2c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GetMapContainer((int)&local_3c,i,x);
- Missile(local_2c,&local_3c,5);
- }
- j = 1;
- if (0 < in_stack_00000014) {
- local_9c = &Circle[1].Count;
- local_a0 = 0x41;
- do {
- dy = 0;
- iVar6 = local_a0;
- if (0 < *local_9c) {
- do {
- bVar3 = ThrowPossible(i,x,y,Circle[0].x[iVar6 + dy] + i,
- Circle[0].y[iVar6 + dy] + x,y,0);
- if ((bVar3) && (bVar3 = IsProtectionZone(), !bVar3)) {
- bVar3 = false;
- GetFirstObject();
- if (local_3c.ObjectID != NONE.ObjectID) {
- do {
- dest = (TCreature *)&local_4c;
- local_4c = (_func_int_varargs **)local_3c.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- Object::getNextObject(&local_5c);
- local_3c.ObjectID = local_5c.ObjectID;
- local_2c[0].ObjectID = local_5c.ObjectID;
- Object::getObjectType(&local_5c);
- if ((_func_int_varargs **)local_5c.ObjectID ==
- (_func_int_varargs **)0x63) {
- local_5c.ObjectID = (ulong)local_4c;
- pTVar5 = GetCreature(&local_5c);
- if (pTVar5 == (TCreature *)0x0) {
- error(&DAT_080fbfc0,dest);
- }
- else {
- bVar2 = false;
- if (((pTVar5->Outfit).OutfitID == 0) &&
- ((pTVar5->Outfit).field_1.ObjectType == 0)) {
- bVar2 = true;
- }
- if ((bVar2) &&
- ((WorldType != NON_PVP ||
- (iVar6 = (*pTVar5->_vptr_TCreature[4])
- (pTVar5),
- (char)iVar6 == '\0')))) {
- TSkillBase::SetTimer
- (&pTVar5->super_TSkillBase);
- iVar6 = TSkill::Get((pTVar5->
- super_TSkillBase).Skills[0x10]);
- if (iVar6 == 0) {
- aVar1 = (pTVar5->OrgOutfit).field_1;
- (pTVar5->Outfit).OutfitID =
- (pTVar5->OrgOutfit).OutfitID;
- (pTVar5->Outfit).field_1 = aVar1;
- AnnounceChangedCreature(pTVar5->ID,3);
- local_5c.ObjectID = NONE.ObjectID;
- local_2c[0].ObjectID =
- (pTVar5->CrObject).ObjectID;
- NotifyAllCreatures(local_2c,2,&local_5c);
- }
- else {
- GraphicalEffect();
- bVar3 = true;
- if (WorldType == PVP_ENFORCED) {
- local_94 = 1;
- do {
- GetBodyObject((ulong)&local_5c,
- pTVar5->ID);
- bVar2 = false;
- local_2c[0].ObjectID = NONE.ObjectID;
- z = NONE.ObjectID;
- if (local_5c.ObjectID != NONE.ObjectID
- ) {
- Object::getObjectType
- ((Object *)&z);
- bVar4 = ObjectType::getFlag((
- ObjectType *)&z,SKILLBOOST);
- if (bVar4) {
- Object::getObjectType((Object *)&z);
- uVar8 = ObjectType::getAttribute
- ((ObjectType *)&z,
- BODYPOSITION);
- if (uVar8 == local_94) {
- Object::getObjectType((Object *)&z);
- uVar8 = ObjectType::getAttribute
- ((ObjectType *)&z,
- SKILLNUMBER);
- if (uVar8 == 0x10) {
- bVar2 = true;
- }
- }
- }
- }
- if (bVar2) {
- lVar7 = random();
- if (lVar7 == 1) {
- z = local_5c.ObjectID;
- Delete((Object *)&z,-1);
- }
- break;
- }
- local_94 = local_94 + 1;
- } while ((int)local_94 < 0xb);
- }
- }
- }
- }
- }
- } while (local_3c.ObjectID != NONE.ObjectID);
- }
- local_4c = (_func_int_varargs **)NONE.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- if (!bVar3) {
- GraphicalEffect();
- }
- }
- dy = dy + 1;
- iVar6 = j * 0x41;
- } while (dy < *local_9c);
- }
- j = j + 1;
- local_9c = local_9c + 0x41;
- local_a0 = local_a0 + 0x41;
- } while (j <= in_stack_00000014);
- }
- return;
- }
- puVar9 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar9 = 7;
- goto LAB_08085bc9;
- }
- Text = &DAT_080fc000;
- }
- error(Text);
- puVar9 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar9 = 0xffffffff;
-LAB_08085bc9:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar9,&RESULT::typeinfo,0);
-}
-
-
-
// WARNING: Unknown calling convention -- yet parameter storage is locked
void CreatureIllusion(void)
diff --git a/src/creature.cc b/src/creature.cc
index 65beee0..d1cb7bf 100644
--- a/src/creature.cc
+++ b/src/creature.cc
@@ -56,14 +56,16 @@ void TCreature::Attack(void){
this->Combat.Attack();
}
-// TODO(fusion): This probably belongs elsewhere but we should come back to
+// Temporary Location
+// =============================================================================
+// =============================================================================
+// TODO(fusion): These probably belong elsewhere but we should come back to
// this when we're wrapping up creature files.
+
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.
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
@@ -80,6 +82,20 @@ void AddKillStatistics(int AttackerRace, int DefenderRace){
}
}
+int GetRaceByName(const char *RaceName){
+ int Result = 0;
+ for(int Race = 1; Race < NARRAY(RaceData); Race += 1){
+ if(stricmp(RaceName, RaceData[Race].Name) == 0){
+ Result = Race;
+ break;
+ }
+ }
+ return Result;
+}
+
+// =============================================================================
+// =============================================================================
+
int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){
if(this->IsDead || this->Type == NPC){
return 0;
diff --git a/src/creature.hh b/src/creature.hh
index 79fee7c..96367ff 100644
--- a/src/creature.hh
+++ b/src/creature.hh
@@ -148,5 +148,6 @@ struct TCreature: TSkillBase {
// this when we're wrapping up creature files.
bool IsCreaturePlayer(uint32 CreatureID);
void AddKillStatistics(int AttackerRace, int DefenderRace);
+int GetRaceByName(const char *RaceName);
#endif //TIBIA_CREATURE_HH_
diff --git a/src/magic.cc b/src/magic.cc
index dc91695..6c890ea 100644
--- a/src/magic.cc
+++ b/src/magic.cc
@@ -927,7 +927,7 @@ void KillAllMonsters(TCreature *Actor, int Effect, int Radius){
}
// TODO(fusion): This is similar to `ExecuteCircleSpell` which makes me think
- // there is perhaps a common denominator?
+ // it got inlined and whatever `TImpact` this is got devirtualized.
if(Radius >= NARRAY(Circle)){
Radius = NARRAY(Circle) - 1;
}
@@ -1076,8 +1076,7 @@ void MassCreateField(TCreature *Actor, Object Target,
Missile(Actor->CrObject, Target, Animation);
}
- // TODO(fusion): Same as `KillAllMonsters`. Perhaps the `ExecuteCircleSpell`
- // function is getting inlined and TFieldImpact devirtualized?
+ // TODO(fusion): Same as `KillAllMonsters`.
if(Radius >= NARRAY(Circle)){
Radius = NARRAY(Circle) - 1;
}
@@ -1282,7 +1281,7 @@ void CleanupField(TCreature *Actor, Object Target, int ManaPoints, int SoulPoint
int TargetX, TargetY, TargetZ;
GetObjectCoordinates(Target, &TargetX, &TargetY, &TargetZ);
- int Distance = std::min<int>(
+ int Distance = std::max<int>(
std::abs(Actor->posx - TargetX),
std::abs(Actor->posy - TargetY));
if(Distance > 1 || Actor->posz != TargetZ){
@@ -1753,6 +1752,7 @@ void CreateFood(TCreature *Actor, int ManaPoints, int SoulPoints){
for(int i = 0; i < Count; i += 1){
uint8 Group, Number;
switch(rand() % 7){
+ default: // NOTE(fusion): To avoid compiler warnings.
case 0: Group = 134; Number = 0; break;
case 1: Group = 130; Number = 2; break;
case 2: Group = 136; Number = 0; break;
@@ -1760,7 +1760,6 @@ void CreateFood(TCreature *Actor, int ManaPoints, int SoulPoints){
case 4: Group = 131; Number = 1; break;
case 5: Group = 131; Number = 9; break;
case 6: Group = 134; Number = 1; break;
- default: ASSERT(!"unreachable"); break;
}
CreateAtCreature(Actor->ID, GetNewObjectType(Group, Number), 1);
}
@@ -1793,6 +1792,581 @@ void CreateArrows(TCreature *Actor, int ManaPoints, int SoulPoints, int ArrowTyp
GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
}
+void SummonCreature(TCreature *Actor, int ManaPoints, int Race, bool God){
+ if(Actor == NULL){
+ error("SummonCreature: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Race < 1 || Race >= NARRAY(RaceData)){
+ error("SummonCreature: Ungültige Rassennummer %d übergeben.\n", Race);
+ throw ERROR;
+ }
+
+ // TODO(fusion): These checks are weird. We should probably just split the
+ // function in two?
+ if(God){
+ // TODO(fusion): What happened to checking if the creature is a player
+ // before using `CheckRight`?
+ if(!CheckRight(Actor->ID, CREATE_MONSTERS)){
+ return;
+ }
+ }else if(Actor->Type == PLAYER){
+ if(!CheckRight(Actor->ID, CREATE_MONSTERS) && GetRaceNoSummon(Race)){
+ throw NOTACCESSIBLE;
+ }
+
+ if(Actor->SummonedCreatures > 1){
+ throw TOOMANYSLAVES;
+ }
+ }
+
+ int SummonX = Actor->posx;
+ int SummonY = Actor->posy;
+ int SummonZ = Actor->posz;
+ if(!SearchSummonField(&SummonX, &SummonY, &SummonZ, 2)){
+ throw NOROOM;
+ }
+
+ uint32 Master = 0;
+ if(!God){
+ int Delay = (WorldType == PVP_ENFORCED) ? 1000 : 2000;
+ ManaPoints += GetRaceSummonCost(Race);
+ CheckMana(Actor, ManaPoints, 0, Delay);
+ Master = Actor->ID;
+ }
+
+ CreateMonster(Race, SummonX, SummonY, SummonZ, 0, Master, true);
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+}
+
+void SummonCreature(TCreature *Actor, int Mana, const char *RaceName, bool God){
+ if(Actor == NULL){
+ error("SummonCreature: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(RaceName == NULL){
+ error("SummonCreature: Ungültiger Rassenname übergeben.\n");
+ throw ERROR;
+ }
+
+ int Race = GetRaceByName(RaceName);
+ if(Race == 0){
+ throw CREATURENOTEXISTING;
+ }
+
+ SummonCreature(Actor, Mana, Race, God);
+}
+
+void StartMonsterraid(TCreature *Actor, const char *RaidName){
+ if(Actor == NULL){
+ error("StartMonsterraid: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(RaidName == NULL){
+ error("StartMonsterraid: Ungültiger Raidname übergeben.\n");
+ throw ERROR;
+ }
+
+ // TODO(fusion): What happened to checking if the creature is a player
+ // before using `CheckRight`?
+ if(!CheckRight(Actor->ID, CREATE_MONSTERS)){
+ return;
+ }
+
+ char RaidNameLower[512];
+ strcpy(RaidNameLower, RaidName);
+ strLower(RaidNameLower);
+
+ char FileName[4096];
+ snprintf(FileName, sizeof(FileName), "%s/%s.evt", MONSTERPATH, RaidNameLower);
+ if(FileExists(FileName)){
+ LoadMonsterRaid(FileName, RoundNr, NULL, NULL, NULL, NULL);
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+ }else{
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_POFF);
+ }
+}
+
+void RaiseDead(TCreature *Actor, Object Target, int ManaPoints, int SoulPoints){
+ if(Actor == NULL){
+ error("RaiseDead: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(!Target.exists()){
+ error("RaiseDead: Übergebenes Objekt existiert nicht.\n");
+ throw ERROR;
+ }
+
+ int TargetX, TargetY, TargetZ;
+ GetObjectCoordinates(Target, &TargetX, &TargetY, &TargetZ);
+
+ // TODO(fusion): Could this be some `CheckRange` function inlined?
+ int Distance = std::max<int>(
+ std::abs(Actor->posx - TargetX),
+ std::abs(Actor->posy - TargetY));
+ if(Distance > 1 || Actor->posz != TargetZ){
+ throw OUTOFRANGE;
+ }
+
+ Object Obj = GetFirstObject(TargetX, TargetY, TargetZ);
+ while(Obj != NONE){
+ ObjectType ObjType = Obj.getObjectType();
+ // TODO(fusion): Same as in `CleanupField` except we're looking for a
+ // non human corpse to summon a skeleton from.
+ if(ObjType.getFlag(CORPSE) && ObjType.getAttribute(CORPSETYPE) == 1){
+ break;
+ }
+ Obj = Obj.getNextObject();
+ }
+
+ if(Obj == NONE){
+ throw NOTUSABLE;
+ }
+
+ if(!SearchFreeField(&TargetX, &TargetY, &TargetZ, 1, 0, false)
+ || IsProtectionZone(TargetX, TargetY, TargetZ)){
+ throw NOROOM;
+ }
+
+ int Delay = (WorldType == PVP_ENFORCED) ? 1000 : 2000;
+ CheckMana(Actor, ManaPoints, SoulPoints, Delay);
+ Delete(Obj, -1);
+
+ // NOTE(fusion): The race of a common skeleton is 33 but it should probably
+ // be a constant somewhere.
+ CreateMonster(33, TargetX, TargetY, TargetZ, 0, Actor->ID, true);
+}
+
+void MassRaiseDead(TCreature *Actor, Object Target, int ManaPoints, int SoulPoints, int Radius){
+ if(Actor == NULL){
+ error("MassRaiseDead: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(!Target.exists()){
+ error("MassRaiseDead: Übergebenes Objekt existiert nicht.\n");
+ throw ERROR;
+ }
+
+ // TODO(fusion): Unless `ThrowPossible` also does some max range check, this
+ // spell doesn't check range or floor.
+ int TargetX, TargetY, TargetZ;
+ GetObjectCoordinates(Target, &TargetX, &TargetY, &TargetZ);
+ if(!ThrowPossible(Actor->posx, Actor->posy, Actor->posz, TargetX, TargetY, TargetZ, 0)){
+ throw CANNOTTHROW;
+ }
+
+ int Delay = (WorldType == PVP_ENFORCED) ? 1000 : 2000;
+ CheckMana(Actor, ManaPoints, SoulPoints, Delay);
+
+ if(Actor->posx != TargetX || Actor->posy != TargetY || Actor->posz != TargetZ){
+ Missile(Actor->CrObject, Target, ANIMATION_ENERGY);
+ }
+
+ // TODO(fusion): Same as `KillAllMonsters`.
+ if(Radius >= NARRAY(Circle)){
+ Radius = NARRAY(Circle) - 1;
+ }
+
+ for(int R = 0; R <= Radius; R += 1){
+ int CirclePoints = Circle[R].Count;
+ for(int Point = 0; Point < CirclePoints; Point += 1){
+ int FieldX = TargetX + Circle[R].x[Point];
+ int FieldY = TargetY + Circle[R].y[Point];
+ int FieldZ = TargetZ;
+
+ if(!ThrowPossible(TargetX, TargetY, TargetZ, FieldX, FieldY, FieldZ, 0)){
+ continue;
+ }
+
+ GraphicalEffect(FieldX, FieldY, FieldZ, EFFECT_MAGIC_BLUE);
+ Object Obj = GetFirstObject(FieldX, FieldY, FieldZ);
+ while(Obj != NONE){
+ Object Next = Obj.getNextObject();
+ ObjectType ObjType = Obj.getObjectType();
+ // NOTE(fusion): Same as `RaiseDead`.
+ if(ObjType.getFlag(CORPSE) && ObjType.getAttribute(CORPSETYPE) == 1){
+ int SummonX = FieldX;
+ int SummonY = FieldY;
+ int SummonZ = FieldZ;
+ if(SearchFreeField(&SummonX, &SummonY, &SummonZ, 1, 0, false)
+ && !IsProtectionZone(SummonX, SummonY, SummonZ)){
+ Delete(Obj, -1);
+ CreateMonster(33, SummonX, SummonY, SummonZ, 0, Actor->ID, false);
+ }
+ }
+ Obj = Next;
+ }
+ }
+ }
+}
+
+void Heal(TCreature *Actor, int ManaPoints, int SoulPoints, int Amount){
+ if(Actor == NULL){
+ error("Heal: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ // TODO(fusion): This looks weird, then you peek at `IsPeaceful` and realize
+ // it actually determines whether the creature is a player's summon, then it
+ // gets weirder.
+ if(WorldType == NON_PVP && !Actor->IsPeaceful()){
+ throw NOTACCESSIBLE;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ TSkill *HitPoints = Actor->Skills[SKILL_HITPOINTS];
+ if(HitPoints == NULL){
+ error("Heal: Skill HITPOINTS existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(HitPoints->Get() > 0){
+ // TODO(fusion): This looks a lot like `THealingImpact::handleCreature`
+ // and I'm starting to think most of these spells use a single `TImpact`
+ // on the stack to execute their effects. We don't see any sign of them
+ // because they either get devirtualized by the optimizer or don't exist.
+ HitPoints->Change(Amount);
+ if(Actor->Skills[SKILL_GO_STRENGTH]->MDAct < 0){
+ Actor->SetTimer(SKILL_GO_STRENGTH, 0, 0, 0, -1);
+ }
+
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+ }
+}
+
+
+void MassHeal(TCreature *Actor, Object Target, int ManaPoints, int SoulPoints, int Amount, int Radius){
+ if(Actor == NULL){
+ error("MassHeal: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(!Target.exists()){
+ error("MassHeal: Übergebenes Ziel existiert nicht.\n");
+ throw ERROR;
+ }
+
+ // TODO(fusion): Same as `MassRaiseDead`.
+ int TargetX, TargetY, TargetZ;
+ GetObjectCoordinates(Target, &TargetX, &TargetY, &TargetZ);
+ if(!ThrowPossible(Actor->posx, Actor->posy, Actor->posz, TargetX, TargetY, TargetZ, 0)){
+ throw CANNOTTHROW;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ if(Actor->posx != TargetX || Actor->posy != TargetY || Actor->posz != TargetZ){
+ Missile(Actor->CrObject, Target, ANIMATION_ENERGY);
+ }
+
+ // TODO(fusion): Same as `KillAllMonsters`.
+ if(Radius >= NARRAY(Circle)){
+ Radius = NARRAY(Circle) - 1;
+ }
+
+ for(int R = 0; R <= Radius; R += 1){
+ int CirclePoints = Circle[R].Count;
+ for(int Point = 0; Point < CirclePoints; Point += 1){
+ int FieldX = TargetX + Circle[R].x[Point];
+ int FieldY = TargetY + Circle[R].y[Point];
+ int FieldZ = TargetZ;
+
+ if(!ThrowPossible(TargetX, TargetY, TargetZ, FieldX, FieldY, FieldZ, 0)){
+ continue;
+ }
+
+ GraphicalEffect(FieldX, FieldY, FieldZ, EFFECT_MAGIC_BLUE);
+ Object Obj = GetFirstObject(FieldX, FieldY, FieldZ);
+ while(Obj != NONE){
+ ObjectType ObjType = Obj.getObjectType();
+ if(ObjType.isCreatureContainer()){
+ TCreature *Victim = GetCreature(Obj);
+ if(Victim == NULL){
+ error("MassHeal: Ungültige Kreatur.\n");
+ }else if(WorldType != NON_PVP || Victim->IsPeaceful()){
+ // TODO(fusion): Do we really want to throw here? If not
+ // having hitpoints is a problem, it should have been
+ // enforced ealier for all creatures.
+ TSkill *HitPoints = Victim->Skills[SKILL_HITPOINTS];
+ if(HitPoints == NULL){
+ error("MassHeal: Skill HITPOINTS existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(HitPoints->Get() > 0){
+ HitPoints->Change(Amount);
+ if(Victim->Skills[SKILL_GO_STRENGTH]->MDAct < 0){
+ Victim->SetTimer(SKILL_GO_STRENGTH, 0, 0, 0, -1);
+ }
+ }
+ }
+ }
+ Obj = Obj.getNextObject();
+ }
+ }
+ }
+}
+
+void HealFriend(TCreature *Actor, char *TargetName, int ManaPoints, int SoulPoints, int Amount){
+ if(Actor == NULL){
+ error("HealFriend: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(TargetName == NULL){
+ error("HealFriend: Ungültigen Namen übergeben.\n");
+ throw ERROR;
+ }
+
+ TPlayer *Target;
+ switch(IdentifyPlayer(TargetName, false, true, &Target)){
+ default:
+ case 0: break; // PLAYERFOUND ?
+ case -1: throw PLAYERNOTONLINE;
+ case -2: throw NAMEAMBIGUOUS;
+ }
+
+ // TODO(fusion): These distances are related to the client's viewport.
+ if(Actor->posz != Target->posz
+ || std::abs(Actor->posx - Target->posx) > 7
+ || std::abs(Actor->posy - Target->posy) > 5){
+ throw OUTOFRANGE;
+ }
+
+ TSkill *HitPoints = Target->Skills[SKILL_HITPOINTS];
+ if(HitPoints == NULL){
+ error("HealFriend: Skill HITPOINTS existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(HitPoints->Get() <= 0){
+ throw PLAYERNOTONLINE;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ HitPoints->Change(Amount);
+ if(Target->Skills[SKILL_GO_STRENGTH]->MDAct < 0){
+ Target->SetTimer(SKILL_GO_STRENGTH, 0, 0, 0, -1);
+ }
+
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+ GraphicalEffect(Target->posx, Target->posy, Target->posz, EFFECT_MAGIC_GREEN);
+}
+
+void RefreshMana(TCreature *Actor, int ManaPoints, int SoulPoints, int Amount){
+ if(Actor == NULL){
+ error("RefreshMana: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ TSkill *Mana = Actor->Skills[SKILL_MANA];
+ if(Mana == NULL){
+ error("RefreshMana: Skill MANA existiert nicht.\n");
+ throw ERROR;
+ }
+
+ Mana->Change(Amount);
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+}
+
+void MagicGoStrength(TCreature *Actor, TCreature *Target, int ManaPoints, int SoulPoints, int Percent, int Duration){
+ if(Actor == NULL){
+ error("MagicGoStrength: Übergebene Kreatur existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(Target == NULL){
+ error("MagicGoStrength: Übergebene Ziel Kreatur existiert nicht.\n");
+ throw ERROR;
+ }
+
+ if(Percent < 0){
+ if(GetRaceNoParalyze(Target->Race)){
+ throw NOTACCESSIBLE;
+ }
+
+ if(WorldType == NON_PVP && Actor->IsPeaceful() && Target->IsPeaceful()){
+ throw ATTACKNOTALLOWED;
+ }
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ TSkill *GoStrength = Target->Skills[SKILL_GO_STRENGTH];
+ if(Percent < -100){
+ GoStrength->SetMDAct(-GoStrength->Act - 20);
+ }else{
+ GoStrength->SetMDAct((GoStrength->Act * Percent) / 100);
+ }
+
+ Target->SetTimer(SKILL_GO_STRENGTH, Duration, 10, 10, -1);
+
+ // TODO(fusion): We should probably check if the actor is different from the
+ // target before blocking the actor's logout or sending the first graphical
+ // effect.
+ if(Percent < 0){
+ Actor->BlockLogout(60, Target->Type == PLAYER);
+ }
+
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_GREEN);
+ GraphicalEffect(Target->posx, Target->posy, Target->posz, EFFECT_MAGIC_RED);
+}
+
+void Shielding(TCreature *Actor, int ManaPoints, int SoulPoints, int Duration){
+ if(Actor == NULL){
+ error("Shielding: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+ Actor->SetTimer(SKILL_MANASHIELD, 1, Duration, Duration, -1);
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+}
+
+void NegatePoison(TCreature *Actor, TCreature *Target, int ManaPoints, int SoulPoints){
+ if(Actor == NULL){
+ error("NegatePoison: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Target == NULL){
+ error("NegatePoison: Zielkreatur existiert nicht.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+ Target->SetTimer(SKILL_POISON, 0, 0, 0, -1);
+ GraphicalEffect(Target->posx, Target->posy, Target->posz, EFFECT_MAGIC_BLUE);
+}
+
+void Enlight(TCreature *Actor, int ManaPoints, int SoulPoints, int Radius, int Duration){
+ if(Actor == NULL){
+ error("Enlight: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+ if(Actor->Skills[SKILL_LIGHT]->TimerValue() <= Radius){
+ Actor->SetTimer(SKILL_LIGHT, Radius, Duration / Radius, Duration / Radius, -1);
+ }
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+}
+
+void Invisibility(TCreature *Actor, int ManaPoints, int SoulPoints, int Duration){
+ if(Actor == NULL){
+ error("Invisibility: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+ Actor->Outfit = TOutfit{};
+ Actor->SetTimer(SKILL_ILLUSION, 1, Duration, Duration, -1);
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+}
+
+void CancelInvisibility(TCreature *Actor, Object Target, int ManaPoints, int SoulPoints, int Radius){
+ if(Actor == NULL){
+ error("CancelInvisibility: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(!Target.exists()){
+ error("CancelInvisibility: Übergebenes Ziel existiert nicht.\n");
+ throw ERROR;
+ }
+
+ int TargetX, TargetY, TargetZ;
+ GetObjectCoordinates(Target, &TargetX, &TargetY, &TargetZ);
+ if(!ThrowPossible(Actor->posx, Actor->posy, Actor->posz, TargetX, TargetY, TargetZ, 0)){
+ throw CANNOTTHROW;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ if(Actor->posx != TargetX || Actor->posy != TargetY || Actor->posz != TargetZ){
+ Missile(Actor->CrObject, Target, ANIMATION_ENERGY);
+ }
+
+ // TODO(fusion): Same as `KillAllMonsters`.
+ if(Radius >= NARRAY(Circle)){
+ Radius = NARRAY(Circle) - 1;
+ }
+
+ for(int R = 0; R <= Radius; R += 1){
+ int CirclePoints = Circle[R].Count;
+ for(int Point = 0; Point < CirclePoints; Point += 1){
+ int FieldX = TargetX + Circle[R].x[Point];
+ int FieldY = TargetY + Circle[R].y[Point];
+ int FieldZ = TargetZ;
+
+ if(IsProtectionZone(FieldX, FieldY, FieldZ)){
+ continue;
+ }
+
+ if(!ThrowPossible(TargetX, TargetY, TargetZ, FieldX, FieldY, FieldZ, 0)){
+ continue;
+ }
+
+ int Effect = EFFECT_MAGIC_BLUE;
+ Object Obj = GetFirstObject(FieldX, FieldY, FieldZ);
+ while(Obj != NONE){
+ ObjectType ObjType = Obj.getObjectType();
+ if(ObjType.isCreatureContainer()){
+ TCreature *Victim = GetCreature(Obj);
+ if(Victim == NULL){
+ error("CancelInvisibility: Ungültige Kreatur.\n");
+ }else if(Victim->Outfit.OutfitID == 0 && Victim->Outfit.ObjectType == 0
+ && (WorldType != NON_PVP || !Victim->IsPeaceful())){
+ Victim->SetTimer(SKILL_ILLUSION, 0, 0, 0, -1);
+ if(Victim->Skills[SKILL_ILLUSION]->Get() == 0){
+ Victim->Outfit = Victim->OrgOutfit;
+ AnnounceChangedCreature(Victim->ID, 3); // CREATURE_OUTFIT_CHANGED ?
+ NotifyAllCreatures(Victim->CrObject, 2, NONE); // CREATURE_APPEAR ?
+ }else{
+ Effect = EFFECT_BLOCK_HIT;
+
+ // NOTE(fusion): If the victim still has an illusion effect up, it
+ // it must come from an item and it seems there is a change to destroy
+ // it on pvp enforced worlds.
+ // TODO(fusion): This is probably an inlined function.
+ if(WorldType == PVP_ENFORCED){
+ for(int Position = 1; Position <= 10; Position += 1){
+ Object Item = GetBodyObject(Victim->ID, Position);
+ if(Item == NONE){
+ continue;
+ }
+
+ ObjectType ItemType = Item.getObjectType();
+ if(ItemType.getFlag(SKILLBOOST)
+ && (int)ItemType.getAttribute(BODYPOSITION) == Position
+ && (int)ItemType.getAttribute(SKILLNUMBER) == SKILL_ILLUSION){
+ if(random(1, 5) == 1){
+ Delete(Item, -1);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ Obj = Obj.getNextObject();
+ }
+
+ GraphicalEffect(FieldX, FieldY, FieldZ, Effect);
+ }
+ }
+}
+
// Magic Init Functions
// =============================================================================
static void InitCircles(void){
diff --git a/src/stubs.hh b/src/stubs.hh
index 4157c61..3e69990 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -41,11 +41,15 @@ extern TConnection *GetFirstConnection(void);
extern TConnection *GetNextConnection(void);
extern TPlayer *GetPlayer(uint32 CreatureID);
extern bool GetRaceNoParalyze(int Race);
+extern bool GetRaceNoSummon(int Race);
extern int GetRacePoison(int Race);
+extern int GetRaceSummonCost(int Race);
extern void GraphicalEffect(int x, int y, int z, int Type);
extern void GraphicalEffect(Object Obj, int Type);
extern int IdentifyPlayer(const char *Name, bool ExactMatch, bool IgnoreGamemasters, TPlayer **Player);
extern void InitLog(const char *ProtocolName);
+extern void LoadMonsterRaid(const char *FileName, int Start,
+ bool *Type, int *Date, int *Interval, int *Duration);
extern void Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3);
extern void LogoutAllPlayers(void);
extern void Missile(Object Start, Object Dest, int Type);