aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-02 18:17:10 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-02 18:21:54 -0300
commitd2eb32efe2df9e570e491b08d4ecf50da35f1b75 (patch)
tree6097d7f49e6a294f8b216fb6ea13e8aa6184e83e
parent3f85ce3cfb46adee8caf890a8369cd7cd7814874 (diff)
downloadgame-d2eb32efe2df9e570e491b08d4ecf50da35f1b75.tar.gz
game-d2eb32efe2df9e570e491b08d4ecf50da35f1b75.zip
impl some spells and create `info.cc`
-rw-r--r--Makefile9
-rw-r--r--reference/game.c629
-rw-r--r--src/enums.hh3
-rw-r--r--src/info.cc97
-rw-r--r--src/info.hh13
-rw-r--r--src/magic.cc281
-rw-r--r--src/stubs.hh1
-rw-r--r--tools/makefile.go2
8 files changed, 403 insertions, 632 deletions
diff --git a/Makefile b/Makefile
index cc1feb0..d804d60 100644
--- a/Makefile
+++ b/Makefile
@@ -12,9 +12,10 @@ ifneq ($(DEBUG), 0)
else
CFLAGS += -O2
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)/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)/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
+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 $@ $^
$(BUILDDIR)/config.obj: $(SRCDIR)/config.cc $(HEADERS)
@@ -33,6 +34,10 @@ $(BUILDDIR)/crskill.obj: $(SRCDIR)/crskill.cc $(HEADERS)
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<
+$(BUILDDIR)/info.obj: $(SRCDIR)/info.cc $(HEADERS)
+ @mkdir -p $(@D)
+ $(CC) -c $(CFLAGS) -o $@ $<
+
$(BUILDDIR)/magic.obj: $(SRCDIR)/magic.cc $(HEADERS)
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<
diff --git a/reference/game.c b/reference/game.c
index 2062902..138c00e 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -13686,61 +13686,6 @@ int GetHeight(void)
return iVar3;
}
-
-
-bool JumpPossible(int x,int y,int z,bool AvoidPlayers)
-
-{
- bool bVar1;
- TCreature *pTVar2;
- bool local_4e;
- bool BankThere;
- Object OStack_4c;
- bool AvoidPlayers_local;
- Object local_3c [4];
- ulong local_2c;
- Object Obj;
-
- GetFirstObject();
- local_4e = false;
- if (local_2c != NONE.ObjectID) {
- local_4e = false;
- if (local_2c != NONE.ObjectID) {
- do {
- OStack_4c.ObjectID = NONE.ObjectID;
- local_3c[0].ObjectID = NONE.ObjectID;
- Object::getObjectType(&stack0xffffffb4);
- bVar1 = ObjectType::getFlag((ObjectType *)&stack0xffffffb4,BANK);
- if (bVar1) {
- local_4e = true;
- }
- Object::getObjectType(&stack0xffffffb4);
- bVar1 = ObjectType::getFlag((ObjectType *)&stack0xffffffb4,UNPASS);
- if (bVar1) {
- Object::getObjectType(&stack0xffffffb4);
- bVar1 = ObjectType::getFlag((ObjectType *)&stack0xffffffb4,UNMOVE);
- if (bVar1) {
- return false;
- }
- }
- if ((AvoidPlayers) &&
- (Object::getObjectType(&stack0xffffffb4), OStack_4c.ObjectID == 99)) {
- OStack_4c.ObjectID = local_2c;
- pTVar2 = GetCreature(&stack0xffffffb4);
- if ((pTVar2 != (TCreature *)0x0) && (pTVar2->Type == PLAYER)) {
- return false;
- }
- }
- Object::getNextObject(local_3c);
- local_2c = local_3c[0].ObjectID;
- } while (local_3c[0].ObjectID != NONE.ObjectID);
- }
- }
- return local_4e;
-}
-
-
-
// WARNING: Unknown calling convention -- yet parameter storage is locked
bool FieldPossible(void)
@@ -13803,87 +13748,6 @@ LAB_080701d5:
}
-
-// WARNING: Variable defined which should be unmapped: HouseID_local
-
-bool SearchFreeField(int *x,int *y,int *z,int Distance,ushort HouseID,bool Jump)
-
-{
- bool bVar1;
- bool bVar2;
- ushort uVar3;
- int local_28;
- int dy;
- int dx;
- int Dist;
- int Direction;
- bool Jump_local;
- ushort HouseID_local;
-
- local_28 = 0;
- Dist = 4;
- dx = 0;
- dy = 0;
- do {
- if (Jump) {
- bVar2 = JumpPossible(dy + *x,local_28 + *y,*z,true);
-LAB_08070550:
- if (bVar2 != false) {
-LAB_080703ed:
- if (((HouseID == 0xffff) || (bVar2 = IsHouse(dy + *x,local_28 + *y,*z), !bVar2)) ||
- ((HouseID != 0 &&
- (uVar3 = GetHouseID(dy + *x,local_28 + *y,*z), uVar3 == HouseID)))) {
- *x = *x + dy;
- *y = *y + local_28;
- return true;
- }
- }
- }
- else {
- bVar2 = false;
- bVar1 = CoordinateFlag();
- if (bVar1) {
- bVar2 = CoordinateFlag();
- bVar2 = !bVar2;
- }
- if (bVar2) {
- bVar2 = CoordinateFlag();
- if (bVar2) {
- bVar2 = CoordinateFlag();
- goto LAB_08070550;
- }
- goto LAB_080703ed;
- }
- }
- if (Dist == 2) {
- dy = dy + -1;
- if (dy + dx == 0) {
- Dist = 3;
- }
- }
- else if ((uint)Dist < 3) {
- if ((Dist == 1) && (local_28 = local_28 + -1, local_28 + dx == 0)) {
- Dist = 2;
- }
- }
- else if (Dist == 3) {
- local_28 = local_28 + 1;
- if (local_28 == dx) {
- Dist = 4;
- }
- }
- else if ((Dist == 4) && (dy = dy + 1, dy == dx + 1)) {
- Dist = 1;
- dx = dy;
- }
- if (Distance < dx) {
- return false;
- }
- } while( true );
-}
-
-
-
bool SearchLoginField(int *x,int *y,int *z,int Distance,bool Player)
{
@@ -20990,499 +20854,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
// WARNING: Unknown calling convention -- yet parameter storage is locked
-void CleanupField(void)
-
-{
- bool bVar1;
- uint uVar2;
- ulong uVar3;
- undefined4 *puVar4;
- TCreature *in_stack_00000004;
- Object *in_stack_00000008;
- int in_stack_0000000c;
- int in_stack_00000010;
- char *Text;
- int local_58;
- int x;
- int y;
- int z;
- ulong local_3c;
- Object Help;
- Object local_2c [7];
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fb140;
- }
- else {
- // try { // try from 08081d70 to 08081fa5 has its CatchHandler @ 08081fc3
- bVar1 = Object::exists(in_stack_00000008);
- if (bVar1) {
- local_2c[0].ObjectID = in_stack_00000008->ObjectID;
- GetObjectCoordinates(local_2c,&local_58,&x,&y);
- if (y == in_stack_00000004->posz) {
- uVar2 = local_58 - 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) {
- CheckMana(in_stack_00000004,in_stack_0000000c,in_stack_00000010,1000);
- GetFirstObject();
- in_stack_00000008->ObjectID = local_3c;
- if (local_3c != NONE.ObjectID) {
- do {
- local_2c[0].ObjectID = NONE.ObjectID;
- Object::getNextObject((Object *)&z);
- in_stack_00000008->ObjectID = z;
- local_2c[0].ObjectID = z;
- Object::getObjectType((Object *)&z);
- bVar1 = ObjectType::getFlag((ObjectType *)&z,UNMOVE);
- if ((!bVar1) && (Object::getObjectType((Object *)&z), z != 99)) {
- Object::getObjectType((Object *)&z);
- bVar1 = ObjectType::getFlag((ObjectType *)&z,CORPSE);
- if (bVar1) {
- Object::getObjectType((Object *)&z);
- uVar3 = ObjectType::getAttribute
- ((ObjectType *)&z,CORPSETYPE);
- if (uVar3 == 0) goto LAB_08081e86;
- }
- z = local_3c;
- Delete((Object *)&z,-1);
- }
-LAB_08081e86:
- local_3c = in_stack_00000008->ObjectID;
- } while (local_3c != NONE.ObjectID);
- }
- local_3c = NONE.ObjectID;
- local_2c[0].ObjectID = NONE.ObjectID;
- GraphicalEffect();
- TCreature::BlockLogout(in_stack_00000004,0x3c,true);
- return;
- }
- }
- }
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = 5;
- goto LAB_08081f82;
- }
- Text = &DAT_080fb100;
- }
- error(Text);
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = 0xffffffff;
-LAB_08081f82:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar4,&RESULT::typeinfo,0);
-}
-
-
-
-void CleanupField(TCreature *cr)
-
-{
- bool bVar1;
- int y;
- int iVar2;
- undefined4 *puVar3;
- char *Text;
- undefined1 local_1c [16];
-
- if (cr == (TCreature *)0x0) {
- Text = &DAT_080fb140;
- }
- else {
- if (cr->Type == PLAYER) {
- // try { // try from 08082016 to 08082124 has its CatchHandler @ 08082130
- bVar1 = CheckRight(cr->ID,CLEANUP_FIELDS);
- if (!bVar1) {
- return;
- }
- iVar2 = cr->Direction;
- if (iVar2 == 1) {
- iVar2 = cr->posy;
- y = cr->posx + 1;
- }
- else {
- if (iVar2 < 2) {
- if (iVar2 != 0) {
- return;
- }
- iVar2 = cr->posy + -1;
- }
- else {
- if (iVar2 != 2) {
- if (iVar2 != 3) {
- return;
- }
- iVar2 = cr->posy;
- y = cr->posx + -1;
- goto LAB_08082065;
- }
- iVar2 = cr->posy + 1;
- }
- y = cr->posx;
- }
-LAB_08082065:
- GetMapContainer((int)local_1c,y,iVar2);
- CleanupField();
- return;
- }
- Text = "CleanupField: Zauberspruch kann nur von Spielern angewendet werden.\n";
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-void Teleport(TCreature *cr,char *Param)
-
-{
- bool bVar1;
- ushort HouseID;
- int iVar2;
- undefined4 *puVar3;
- TConnection *Connection;
- Object *Obj_00;
- char *pcVar4;
- int *piVar5;
- Object *Ignore;
- int local_68;
- int x;
- int y;
- int z;
- Object local_4c [4];
- Object local_3c [4];
- ulong local_2c;
- Object Obj;
-
- if (cr == (TCreature *)0x0) {
- pcVar4 = &DAT_080fb260;
- }
- else if (Param == (char *)0x0) {
- pcVar4 = "Teleport: Param ist NULL.\n";
- }
- else {
- if (cr->Type == PLAYER) {
- local_3c[0].ObjectID = (cr->CrObject).ObjectID;
- local_2c = local_3c[0].ObjectID;
- // try { // try from 080821ad to 0808270f has its CatchHandler @ 08082740
- GetObjectCoordinates(local_3c,&local_68,&x,&y);
- iVar2 = stricmp(Param,"up",-1);
- if (iVar2 != 0) {
- iVar2 = stricmp(Param,"down",-1);
- if (iVar2 == 0) {
- bVar1 = CheckRight(cr->ID,TELEPORT_VERTICAL);
- if (!bVar1) {
- return;
- }
- y = y + 1;
- bVar1 = SearchFreeField(&local_68,&x,&y,1,0xffff,true);
- if (!bVar1) goto LAB_080822b7;
- z = NONE.ObjectID;
- GetMapContainer((int)local_4c,local_68,x);
- }
- else {
- iVar2 = stricmp(Param,"fast",-1);
- if (iVar2 == 0) {
- bVar1 = CheckRight(cr->ID,MODIFY_GOSTRENGTH);
- if (!bVar1) {
- return;
- }
- iVar2 = 100;
-LAB_080823f2:
- TSkill::SetMDAct((cr->super_TSkillBase).Skills[4],iVar2);
- AnnounceChangedCreature(cr->ID,4);
- z = local_2c;
- GraphicalEffect((Object *)&z,0xd);
- return;
- }
- iVar2 = stricmp(Param,"fastest",-1);
- if (iVar2 == 0) {
- bVar1 = CheckRight(cr->ID,MODIFY_GOSTRENGTH);
- if (!bVar1) {
- return;
- }
- iVar2 = 200;
- goto LAB_080823f2;
- }
- iVar2 = stricmp(Param,"slow",-1);
- if ((iVar2 == 0) || (iVar2 = stricmp(Param,"normal",-1), iVar2 == 0)) {
- bVar1 = CheckRight(cr->ID,MODIFY_GOSTRENGTH);
- if (!bVar1) {
- return;
- }
- iVar2 = 0;
- goto LAB_080823f2;
- }
- piVar5 = &x;
- iVar2 = sscanf(Param,"%d,%d,%d",&local_68,piVar5,&y);
- if (iVar2 == 3) {
-LAB_08082630:
- bVar1 = CheckRight(cr->ID,TELEPORT_TO_COORDINATE);
- if (!bVar1) {
- return;
- }
- if ((((local_68 < 1) || (x < 1)) || (y < 1)) ||
- (bVar1 = IsOnMap(local_68,x,y), !bVar1)) {
- bVar1 = IsOnMap(local_68 + cr->posx,x + cr->posy,y + cr->posz);
- if (!bVar1) {
- Connection = cr->Connection;
- pcVar4 = "Invalid coordinates.";
-LAB_0808257b:
- SendMessage(Connection,0x17,pcVar4,piVar5);
- return;
- }
- x = x + cr->posy;
- local_68 = local_68 + cr->posx;
- y = y + cr->posz;
- }
- HouseID = 0xffff;
- }
- else {
- piVar5 = &x;
- iVar2 = sscanf(Param,"[%d,%d,%d]",&local_68,piVar5,&y);
- if (iVar2 == 3) goto LAB_08082630;
- bVar1 = CheckRight(cr->ID,TELEPORT_TO_MARK);
- if (!bVar1) {
- return;
- }
- piVar5 = &y;
- bVar1 = GetMarkPosition();
- if (!bVar1) {
- Connection = cr->Connection;
- pcVar4 = "There is no mark of this name.";
- goto LAB_0808257b;
- }
- HouseID = GetHouseID(local_68,x,y);
- }
- bVar1 = SearchFreeField(&local_68,&x,&y,1,HouseID,true);
- if (!bVar1) goto LAB_080822b7;
- z = NONE.ObjectID;
- GetMapContainer((int)local_4c,local_68,x);
- }
- Ignore = (Object *)&z;
- Obj_00 = local_3c;
- local_3c[0].ObjectID = local_2c;
-LAB_08082285:
- Move(0,Obj_00,local_4c,-1,false,Ignore);
- GraphicalEffect();
- return;
- }
- bVar1 = CheckRight(cr->ID,TELEPORT_VERTICAL);
- if (!bVar1) {
- return;
- }
- y = y + -1;
- bVar1 = SearchFreeField(&local_68,&x,&y,1,0xffff,true);
- if (bVar1) {
- local_3c[0].ObjectID = NONE.ObjectID;
- GetMapContainer((int)local_4c,local_68,x);
- Obj_00 = (Object *)&z;
- Ignore = local_3c;
- z = local_2c;
- goto LAB_08082285;
- }
-LAB_080822b7:
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 4;
- goto LAB_080822c9;
- }
- pcVar4 = "Teleport: Zauberspruch kann nur von Spielern angewendet werden.\n";
- }
- error(pcVar4);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_080822c9:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-void TeleportToCreature(TCreature *cr,char *Name)
-
-{
- bool bVar1;
- ushort HouseID;
- int Result;
- int iVar2;
- undefined4 *puVar3;
- char *Text;
- int iVar4;
- int local_6c;
- int x;
- int y;
- int z;
- TPlayer *dest;
- Object local_4c [4];
- Object local_3c [4];
- TPlayer *local_2c;
- Object Obj;
-
- if (cr == (TCreature *)0x0) {
- Text = &DAT_080fb360;
- }
- else if (cr->Type == PLAYER) {
- // try { // try from 0808279f to 080829de has its CatchHandler @ 08082a36
- bVar1 = CheckRight(cr->ID,TELEPORT_TO_CHARACTER);
- if (!bVar1) {
- return;
- }
- if ((Name == (char *)0x0) || (*Name == '\0')) {
- SendMessage(cr->Connection,0x17,"You must enter a name.");
- return;
- }
- local_2c = (TPlayer *)0x0;
- bVar1 = CheckRight(cr->ID,READ_GAMEMASTER_CHANNEL);
- iVar2 = IdentifyPlayer(Name,false,!bVar1,(TPlayer **)&z);
- if (iVar2 == -1) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1b;
- goto LAB_080829a6;
- }
- if (iVar2 < 0) {
- if (iVar2 == -2) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1c;
- goto LAB_080829a6;
- }
- }
- else if (iVar2 == 0) {
- local_4c[0].ObjectID = (cr->CrObject).ObjectID;
- local_3c[0].ObjectID = local_4c[0].ObjectID;
- local_2c = (TPlayer *)local_4c[0].ObjectID;
- if (cr == (TCreature *)z) {
- GraphicalEffect(local_4c,0xb);
- return;
- }
- GraphicalEffect(local_4c,3);
- local_6c = *(int *)(z + 0x270);
- x = *(int *)(z + 0x274);
- y = *(int *)(z + 0x278);
- HouseID = GetHouseID(local_6c,x,y);
- bVar1 = SearchFreeField(&local_6c,&x,&y,1,HouseID,true);
- if ((bVar1) || (iVar2 = x, iVar4 = y, bVar1 = IsProtectionZone(), !bVar1)) {
- local_4c[0].ObjectID = NONE.ObjectID;
- GetMapContainer((int)local_3c,local_6c,x);
- dest = local_2c;
- Move(0,(Object *)&dest,local_3c,-1,false,local_4c);
- GraphicalEffect();
- Log("banish","%s teleportiert sich zu %s.\n",cr->Name,z + 0x214);
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4,iVar2,iVar4);
- *puVar3 = 4;
- goto LAB_080829a6;
- }
- Text = &DAT_080fb2a0;
- }
- else {
- Text = "TeleportToCreature: Zauberspruch kann nur von Spielern angewendet werden.\n";
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_080829a6:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-void TeleportPlayerToMe(TCreature *cr,char *Name)
-
-{
- bool bVar1;
- ushort HouseID;
- int Result;
- int iVar2;
- undefined4 *puVar3;
- char *Text;
- int local_6c;
- int x;
- int y;
- int z;
- TPlayer *dest;
- Object local_4c [4];
- Object local_3c [4];
- TPlayer *local_2c;
- Object Obj;
-
- if (cr == (TCreature *)0x0) {
- Text = &DAT_080fb460;
- }
- else if (cr->Type == PLAYER) {
- // try { // try from 08082a8f to 08082c5e has its CatchHandler @ 08082cb6
- bVar1 = CheckRight(cr->ID,RETRIEVE);
- if (!bVar1) {
- return;
- }
- if ((Name == (char *)0x0) || (*Name == '\0')) {
- SendMessage(cr->Connection,0x17,"You must enter a name.");
- return;
- }
- local_2c = (TPlayer *)0x0;
- bVar1 = CheckRight(cr->ID,READ_GAMEMASTER_CHANNEL);
- iVar2 = IdentifyPlayer(Name,false,!bVar1,(TPlayer **)&z);
- if (iVar2 == -1) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1b;
- goto LAB_08082c3b;
- }
- if (iVar2 < 0) {
- if (iVar2 == -2) {
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1c;
- goto LAB_08082c3b;
- }
- }
- else if (iVar2 == 0) {
- local_4c[0].ObjectID = *(undefined4 *)(z + 0x2d0);
- local_3c[0].ObjectID = local_4c[0].ObjectID;
- local_2c = (TPlayer *)local_4c[0].ObjectID;
- GraphicalEffect(local_4c,3);
- local_6c = cr->posx;
- x = cr->posy;
- y = cr->posz;
- HouseID = GetHouseID(local_6c,x,y);
- bVar1 = SearchFreeField(&local_6c,&x,&y,1,HouseID,false);
- if (bVar1) {
- local_4c[0].ObjectID = NONE.ObjectID;
- GetMapContainer((int)local_3c,local_6c,x);
- dest = local_2c;
- Move(0,(Object *)&dest,local_3c,-1,false,local_4c);
- GraphicalEffect();
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 4;
- goto LAB_08082c3b;
- }
- Text = &DAT_080fb3a0;
- }
- else {
- Text = "TeleportPlayerToMe: Zauberspruch kann nur von Spielern angewendet werden.\n";
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_08082c3b:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
void MagicRope(void)
{
diff --git a/src/enums.hh b/src/enums.hh
index 489f8a6..7b2fc68 100644
--- a/src/enums.hh
+++ b/src/enums.hh
@@ -112,8 +112,11 @@ enum EffectType: int {
EFFECT_BURST_ARROW = 7,
EFFECT_POISON = 9,
EFFECT_BONE_HIT = 10,
+ EFFECT_TELEPORT = 11,
EFFECT_ENERGY_HIT = 12,
+ EFFECT_MAGIC_BLUE = 13,
EFFECT_MAGIC_RED = 14,
+ EFFECT_MAGIC_GREEN = 15,
EFFECT_FIRE_HIT = 16,
EFFECT_POISON_HIT = 17,
};
diff --git a/src/info.cc b/src/info.cc
new file mode 100644
index 0000000..7105535
--- /dev/null
+++ b/src/info.cc
@@ -0,0 +1,97 @@
+#include "info.hh"
+#include "creature.hh"
+
+#include "stubs.hh"
+
+bool JumpPossible(int x, int y, int z, bool AvoidPlayers){
+ bool HasBank = false;
+ Object Obj = GetFirstObject(x, y, z);
+ while(Obj != NONE){
+ ObjectType ObjType = Obj.getObjectType();
+
+ if(ObjType.getFlag(BANK)){
+ HasBank = true;
+ }
+
+ if(ObjType.getFlag(UNPASS) && ObjType.getFlag(UNMOVE)){
+ return false;
+ }
+
+ if(AvoidPlayers && ObjType.isCreatureContainer()){
+ TCreature *Creature = GetCreature(Obj);
+ if(Creature != NULL && Creature->Type == PLAYER){
+ return false;
+ }
+ }
+
+ Obj = Obj.getNextObject();
+ }
+ return HasBank;
+}
+
+bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool Jump){
+ int OffsetX = 0;
+ int OffsetY = 0;
+ int CurrentDistance = 0;
+ int CurrentDirection = DIRECTION_EAST;
+ while(CurrentDistance <= Distance){
+ int FieldX = *x + OffsetX;
+ int FieldY = *y + OffsetY;
+ int FieldZ = *z;
+
+ // TODO(fusion): This is probably some form of the `TCreature::MovePossible`
+ // function inlined.
+ bool MovePossible;
+ if(Jump){
+ MovePossible = JumpPossible(FieldX, FieldY, FieldZ, true);
+ }else{
+ MovePossible = CoordinateFlag(FieldX, FieldY, FieldZ, BANK)
+ && !CoordinateFlag(FieldX, FieldY, FieldZ, UNPASS);
+
+ // TODO(fusion): This one I'm not so sure.
+ if(MovePossible && CoordinateFlag(FieldX, FieldY, FieldZ, AVOID)){
+ MovePossible = CoordinateFlag(FieldX, FieldY, FieldZ, BED);
+ }
+ }
+
+ if(MovePossible){
+ if(HouseID == HOUSEID_ANY || !IsHouse(FieldX, FieldY, FieldZ)
+ || (HouseID != 0 && HouseID == GetHouseID(FieldX, FieldY, FieldZ))){
+ *x = FieldX;
+ *y = FieldY;
+ return true;
+ }
+ }
+
+
+ // NOTE(fusion): We're spiraling out from the initial coordinate.
+ // TODO(fusion): This function used directions different from the ones
+ // used by creatures and defined in `enums.hh` so I made it use them
+ // instead, LOL.
+ if(CurrentDirection == DIRECTION_NORTH){
+ OffsetY -= 1;
+ if(OffsetY <= -CurrentDistance){
+ CurrentDirection = DIRECTION_WEST;
+ }
+ }else if(CurrentDirection == DIRECTION_WEST){
+ OffsetX -= 1;
+ if(OffsetX <= -CurrentDistance){
+ CurrentDirection = DIRECTION_SOUTH;
+ }
+ }else if(CurrentDirection == DIRECTION_SOUTH){
+ OffsetY += 1;
+ if(OffsetY >= CurrentDistance){
+ CurrentDirection = DIRECTION_EAST;
+ }
+ }else{
+ ASSERT(CurrentDirection == DIRECTION_EAST);
+ OffsetX += 1;
+ if(OffsetX > CurrentDistance){
+ CurrentDistance = OffsetX;
+ CurrentDirection = DIRECTION_NORTH;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/src/info.hh b/src/info.hh
new file mode 100644
index 0000000..f94ef0e
--- /dev/null
+++ b/src/info.hh
@@ -0,0 +1,13 @@
+#ifndef TIBIA_INFO_HH_
+#define TIBIA_INFO_HH_ 1
+
+#include "common.hh"
+#include "map.hh"
+
+// TODO(fusion): Probably move to `houses.hh` when we implement it?
+constexpr uint16 HOUSEID_ANY = 0xFFFF;
+
+bool JumpPossible(int x, int y, int z, bool AvoidPlayers);
+bool SearchFreeField(int *x, int *y, int *z, int Distance, uint16 HouseID, bool Jump);
+
+#endif //TIBIA_INFO_HH_
diff --git a/src/magic.cc b/src/magic.cc
index 4c641bb..170a8d8 100644
--- a/src/magic.cc
+++ b/src/magic.cc
@@ -1,6 +1,7 @@
#include "magic.hh"
#include "config.hh"
#include "creature.hh"
+#include "info.hh"
#include "monster.hh"
#include "stubs.hh"
@@ -1021,6 +1022,7 @@ void CreateField(TCreature *Actor, int ManaPoints, int SoulPoints, int FieldType
throw ERROR;
}
+ // TODO(fusion): This is probably an inlined function `TCreature::GetForwardPosition`.
int TargetX = Actor->posx;
int TargetY = Actor->posy;
int TargetZ = Actor->posz;
@@ -1266,6 +1268,285 @@ void DeleteField(TCreature *Actor, Object Target, int ManaPoints, int SoulPoints
GraphicalEffect(TargetX, TargetY, TargetZ, EFFECT_POFF);
}
+void CleanupField(TCreature *Actor, Object Target, int ManaPoints, int SoulPoints){
+ if(Actor == NULL){
+ error("CleanupField: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(!Target.exists()){
+ error("CleanupField: Übergebenes Objekt existiert nicht.\n");
+ throw ERROR;
+ }
+
+ int TargetX, TargetY, TargetZ;
+ GetObjectCoordinates(Target, &TargetX, &TargetY, &TargetZ);
+
+ int Distance = std::min<int>(
+ std::abs(Actor->posx - TargetX),
+ std::abs(Actor->posy - TargetY));
+ if(Distance > 1 || Actor->posz != TargetZ){
+ throw OUTOFRANGE;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+ Object Obj = GetFirstObject(TargetX, TargetY, TargetZ);
+ while(Obj != NONE){
+ Object Next = Obj.getNextObject();
+ ObjectType ObjType = Obj.getObjectType();
+ // TODO(fusion): It seems that corpse type can be either 0 for human
+ // corpses or 1 for other/monster corpses, so we're avoiding deleting
+ // human corpses here.
+ if(!ObjType.getFlag(UNMOVE) && !ObjType.isCreatureContainer()
+ && (!ObjType.getFlag(CORPSE) || ObjType.getAttribute(CORPSETYPE) != 0)){
+ Delete(Obj, -1);
+ }
+ Obj = Next;
+ }
+ GraphicalEffect(TargetX, TargetY, TargetZ, EFFECT_POFF);
+ Actor->BlockLogout(60, true);
+}
+
+void CleanupField(TCreature *Actor){
+ if(Actor == NULL){
+ error("CleanupField: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("CleanupField: Zauberspruch kann nur von Spielern angewendet werden.\n");
+ throw ERROR;
+ }
+
+ if(!CheckRight(Actor->ID, CLEANUP_FIELDS)){
+ return;
+ }
+
+ // TODO(fusion): This is probably an inlined function `TCreature::GetForwardPosition`.
+ int TargetX = Actor->posx;
+ int TargetY = Actor->posy;
+ int TargetZ = Actor->posz;
+ switch(Actor->Direction){
+ case DIRECTION_NORTH: TargetY -= 1; break;
+ case DIRECTION_EAST: TargetX += 1; break;
+ case DIRECTION_SOUTH: TargetY += 1; break;
+ case DIRECTION_WEST: TargetX -= 1; break;
+ }
+
+ Object Target = GetMapContainer(TargetX, TargetY, TargetZ);
+ CleanupField(Actor, Target, 0, 0);
+}
+
+void Teleport(TCreature *Actor, char *Param){
+ if(Actor == NULL){
+ error("Teleport: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Param == NULL){
+ error("Teleport: Param ist NULL.\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("Teleport: Zauberspruch kann nur von Spielern angewendet werden.\n");
+ throw ERROR;
+ }
+
+ int DestX = Actor->posx;
+ int DestY = Actor->posy;
+ int DestZ = Actor->posz;
+ // TODO(fusion): The `HouseID` parameter of `SearchFreeField` can be 0xFFFF
+ // as a wildcard to any house. This is probably only used for these special
+ // commands and we should have a `HOUSEID_ANY` constant defined somewhere.
+ // If it is something else, the function will try to find a free field with
+ // the same house id. I'm not sure why we use it with marks but I think we
+ // should only use 0xFFFF here.
+ uint16 HouseID = 0xFFFF;
+ int MDGoStrength = Actor->Skills[SKILL_GO_STRENGTH]->MDAct;
+
+ if(stricmp(Param, "up") == 0){
+ if(!CheckRight(Actor->ID, TELEPORT_VERTICAL)){
+ return;
+ }
+ DestZ -= 1;
+ }else if(stricmp(Param, "down") == 0){
+ if(!CheckRight(Actor->ID, TELEPORT_VERTICAL)){
+ return;
+ }
+ DestZ += 1;
+ }else if(stricmp(Param, "fast") == 0){
+ if(!CheckRight(Actor->ID, MODIFY_GOSTRENGTH)){
+ return;
+ }
+ MDGoStrength = 100;
+ }else if(stricmp(Param, "fastest") == 0){
+ if(!CheckRight(Actor->ID, MODIFY_GOSTRENGTH)){
+ return;
+ }
+ MDGoStrength = 200;
+ }else if(stricmp(Param, "slow") == 0
+ || stricmp(Param, "normal") == 0){
+ if(!CheckRight(Actor->ID, MODIFY_GOSTRENGTH)){
+ return;
+ }
+ MDGoStrength = 0;
+ }else{
+ int ParamX, ParamY, ParamZ;
+ if(sscanf(Param, "%d,%d,%d", &ParamX, &ParamY, &ParamZ) == 3
+ || sscanf(Param, "[%d,%d,%d]", &ParamX, &ParamY, &ParamZ) == 3){
+ if(!CheckRight(Actor->ID, TELEPORT_TO_COORDINATE)){
+ return;
+ }
+
+ if(IsOnMap(ParamX, ParamY, ParamZ)){
+ DestX = ParamX;
+ DestY = ParamY;
+ DestZ = ParamZ;
+ }else if(IsOnMap(DestX + ParamX, DestY + ParamY, DestZ + ParamZ)){
+ DestX += ParamX;
+ DestY += ParamY;
+ DestZ += ParamZ;
+ }else{
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE, "Invalid coordinates.");
+ return;
+ }
+ }else{
+ if(!CheckRight(Actor->ID, TELEPORT_TO_MARK)){
+ return;
+ }
+
+ if(GetMarkPosition(Param, &ParamX, &ParamY, &ParamZ)){
+ DestX = ParamX;
+ DestY = ParamY;
+ DestZ = ParamZ;
+ // TODO(fusion): Not sure why we do this here.
+ HouseID = GetHouseID(DestX, DestY, DestZ);
+ }else{
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE, "There is no mark of this name.");
+ return;
+ }
+ }
+ }
+
+ if(DestX != Actor->posx || DestY != Actor->posy || DestZ != Actor->posz){
+ if(!SearchFreeField(&DestX, &DestY, &DestZ, 1, HouseID, true)){
+ throw NOROOM;
+ }
+ Object Dest = GetMapContainer(DestX, DestY, DestZ);
+ Move(0, Actor->CrObject, Dest, -1, false, NONE);
+ GraphicalEffect(DestX, DestY, DestZ, EFFECT_TELEPORT);
+ }else if(MDGoStrength != Actor->Skills[SKILL_GO_STRENGTH]->MDAct){
+ Actor->Skills[SKILL_GO_STRENGTH]->SetMDAct(MDGoStrength);
+ AnnounceChangedCreature(Actor->ID, 4); // CREATURE_GO_STRENGTH_CHANGED ?
+ GraphicalEffect(DestX, DestY, DestZ, EFFECT_MAGIC_BLUE);
+ }
+}
+
+void TeleportToCreature(TCreature *Actor, const char *Name){
+ if(Actor == NULL){
+ error("TeleportToCreature: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("TeleportToCreature: Zauberspruch kann nur von Spielern angewendet werden.\n");
+ throw ERROR;
+ }
+
+ if(!CheckRight(Actor->ID, TELEPORT_TO_CHARACTER)){
+ return;
+ }
+
+ if(Name == NULL || Name[0] == 0){
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE, "You must enter a name.");
+ return;
+ }
+
+ TPlayer *Player;
+ bool IgnoreGamemasters = !CheckRight(Actor->ID, READ_GAMEMASTER_CHANNEL);
+ switch(IdentifyPlayer(Name, false, IgnoreGamemasters, &Player)){
+ case 0: break; // PLAYERFOUND ?
+ case -1: throw PLAYERNOTONLINE;
+ case -2: throw NAMEAMBIGUOUS;
+ default:{
+ error("TeleportToCreature: Ungültiger Rückgabewert von IdentifyPlayer.\n");
+ throw ERROR;
+ }
+ }
+
+ if(Actor == Player){
+ GraphicalEffect(Actor->CrObject, EFFECT_TELEPORT);
+ return;
+ }
+
+ GraphicalEffect(Actor->CrObject, EFFECT_POFF);
+
+ // TODO(fusion): I assume `SearchFreeField` won't modify the input position
+ // so we're either teleporting to a nearby free position or to the player's
+ // position if it's not protection zone.
+ int DestX = Player->posx;
+ int DestY = Player->posy;
+ int DestZ = Player->posz;
+ uint16 HouseID = GetHouseID(DestX, DestY, DestZ);
+ if(!SearchFreeField(&DestX, &DestY, &DestZ, 1, HouseID, true)
+ || IsProtectionZone(DestX, DestY, DestZ)){
+ throw NOROOM;
+ }
+
+ Object Dest = GetMapContainer(DestX, DestY, DestZ);
+ Move(0, Actor->CrObject, Dest, -1, false, NONE);
+ GraphicalEffect(DestX, DestY, DestZ, EFFECT_TELEPORT);
+ Log("banish", "%s teleportiert sich zu %s.\n", Actor->Name, Player->Name);
+}
+
+void TeleportPlayerToMe(TCreature *Actor, const char *Name){
+ if(Actor == NULL){
+ error("TeleportPlayerToMe: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("TeleportPlayerToMe: Zauberspruch kann nur von Spielern angewendet werden.\n");
+ throw ERROR;
+ }
+
+ if(!CheckRight(Actor->ID, RETRIEVE)){
+ return;
+ }
+
+ if(Name == NULL || Name[0] == 0){
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE, "You must enter a name.");
+ return;
+ }
+
+ TPlayer *Player;
+ bool IgnoreGamemasters = !CheckRight(Actor->ID, READ_GAMEMASTER_CHANNEL);
+ switch(IdentifyPlayer(Name, false, IgnoreGamemasters, &Player)){
+ case 0: break; // PLAYERFOUND ?
+ case -1: throw PLAYERNOTONLINE;
+ case -2: throw NAMEAMBIGUOUS;
+ default:{
+ error("TeleportPlayerToMe: Ungültiger Rückgabewert von IdentifyPlayer.\n");
+ throw ERROR;
+ }
+ }
+
+ GraphicalEffect(Player->CrObject, EFFECT_POFF);
+
+ int DestX = Actor->posx;
+ int DestY = Actor->posy;
+ int DestZ = Actor->posz;
+ uint16 HouseID = GetHouseID(DestX, DestY, DestZ);
+ if(!SearchFreeField(&DestX, &DestY, &DestZ, 1, HouseID, false)){
+ throw NOROOM;
+ }
+
+ Object Dest = GetMapContainer(DestX, DestY, DestZ);
+ Move(0, Player->CrObject, Dest, -1, false, NONE);
+ GraphicalEffect(DestX, DestY, DestZ, EFFECT_TELEPORT);
+}
+
// Magic Init Functions
// =============================================================================
static void InitCircles(void){
diff --git a/src/stubs.hh b/src/stubs.hh
index 0d7bbd0..7b10798 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -43,6 +43,7 @@ extern bool GetRaceNoParalyze(int Race);
extern int GetRacePoison(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 Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3);
extern void LogoutAllPlayers(void);
diff --git a/tools/makefile.go b/tools/makefile.go
index 968b6d1..1e005d5 100644
--- a/tools/makefile.go
+++ b/tools/makefile.go
@@ -78,7 +78,7 @@ func main() {
fmt.Fprint(&output, "\tCFLAGS += -g -O0\n")
fmt.Fprint(&output, "else\n")
fmt.Fprint(&output, "\tCFLAGS += -O2\n")
- fmt.Fprint(&output, "endif\n")
+ fmt.Fprint(&output, "endif\n\n")
// HEADERS
fmt.Fprint(&output, "HEADERS =")