aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-09 01:19:20 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-09 01:19:20 -0300
commitcd8f3f412c2a5f49ee25aab83079a655b88d6def (patch)
treea7f5381472da0e658c37afb5660329f7bc71ba33
parenteaa3536c027a4f7c1b879b78ab0ecdefcdb4833d (diff)
downloadgame-cd8f3f412c2a5f49ee25aab83079a655b88d6def.tar.gz
game-cd8f3f412c2a5f49ee25aab83079a655b88d6def.zip
finish `cract.cc`
-rw-r--r--TODO.md5
-rw-r--r--reference/game.c710
-rw-r--r--src/cr.hh9
-rw-r--r--src/cract.cc401
-rw-r--r--src/magic.cc2
-rw-r--r--src/stubs.hh10
6 files changed, 419 insertions, 718 deletions
diff --git a/TODO.md b/TODO.md
index 50b2e97..32dcda7 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,9 +1,8 @@
## TODO NEXT
-- CRACT.CC
-- CRPLAYER.CC, CRNONPL.CC
-- HOUSES.CC
- INFO.CC
- OPERATE.CC
+- HOUSES.CC
+- CRPLAYER.CC, CRNONPL.CC
- MOVEUSE.CC
- SENDING.CC
- RECEIVING.CC
diff --git a/reference/game.c b/reference/game.c
index 7e6d16d..d430658 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -43083,716 +43083,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-// DWARF original prototype: void Trade(TCreature * this, Object * Obj, ulong PartnerID)
-
-void __thiscall TCreature::Trade(TCreature *this,Object *Obj,ulong PartnerID)
-
-{
- Object OVar1;
- bool bVar2;
- TPlayer *pTVar3;
- int iVar4;
- undefined4 *puVar5;
- TPlayer *Partner;
- TConnection *Connection;
- char *Name;
- Object local_5c;
- Object Help_1;
- Object local_4c [4];
- Object local_3c [4];
- Object local_2c;
- Object Help;
-
- if (this->Type == PLAYER) {
- // try { // try from 080c0226 to 080c05fa has its CatchHandler @ 080c0612
- bVar2 = Object::exists(Obj);
- if (bVar2) {
- local_2c = (Object)Obj->ObjectID;
- bVar2 = ObjectAccessible(this->ID,&local_2c,1);
- if (bVar2) {
- if (this->ID == PartnerID) {
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 9;
- }
- else {
- pTVar3 = GetPlayer(PartnerID);
- if ((pTVar3 == (TPlayer *)0x0) || ((pTVar3->super_TCreature).Type != PLAYER)) {
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 0x1b;
- }
- else {
- local_2c.ObjectID = ::NONE.ObjectID;
- local_3c[0].ObjectID = ::NONE.ObjectID;
- if (this[1].super_TSkillBase.TimerList[0xb] == (TSkill *)::NONE.ObjectID) {
- local_3c[0] = (Object)Obj->ObjectID;
- iVar4 = CountObjects(local_3c);
- if (iVar4 < 0x65) {
- local_3c[0].ObjectID = (pTVar3->super_TCreature).CrObject.ObjectID;
- local_2c.ObjectID = (this->CrObject).ObjectID;
- iVar4 = ObjectDistance(&local_2c,local_3c);
- if (iVar4 < 3) {
- bVar2 = ThrowPossible(this->posx,this->posy,this->posz,
- (pTVar3->super_TCreature).posx,
- (pTVar3->super_TCreature).posy,
- (pTVar3->super_TCreature).posz,0);
- if (bVar2) {
- bVar2 = false;
- local_3c[0].ObjectID = ::NONE.ObjectID;
- local_2c.ObjectID = ::NONE.ObjectID;
- if (((pTVar3->TradeObject).ObjectID != ::NONE.ObjectID) &&
- (pTVar3->TradePartner != this->ID)) {
- bVar2 = true;
- }
- if (!bVar2) {
- OVar1.ObjectID = (pTVar3->TradeObject).ObjectID;
- if (OVar1.ObjectID != ::NONE.ObjectID) {
- while (local_2c.ObjectID = OVar1.ObjectID,
- Object::getObjectType(local_4c),
- local_4c[0].ObjectID != 0) {
- local_4c[0] = (Object)Obj->ObjectID;
- if (local_2c.ObjectID == local_4c[0].ObjectID)
- goto LAB_080c03c7;
- Object::getContainer(&local_5c);
- local_4c[0].ObjectID = local_5c.ObjectID;
- local_2c.ObjectID = local_5c.ObjectID;
- OVar1.ObjectID = local_2c.ObjectID;
- }
- local_5c = (Object)Obj->ObjectID;
- while (Object::getObjectType(local_4c),
- local_4c[0].ObjectID != 0) {
- local_4c[0].ObjectID = local_5c.ObjectID;
- if ((pTVar3->TradeObject).ObjectID ==
- local_5c.ObjectID) goto LAB_080c03c7;
- Object::getContainer(&local_2c);
- local_4c[0].ObjectID = local_2c.ObjectID;
- local_5c.ObjectID = local_2c.ObjectID;
- }
- }
- local_4c[0] = (Object)Obj->ObjectID;
- this[1].super_TSkillBase.TimerList[0xb] =
- (TSkill *)local_4c[0].ObjectID;
- this[1].super_TSkillBase.TimerList[0xc] =
- (TSkill *)PartnerID;
- *(undefined1 *)
- (this[1].super_TSkillBase.TimerList + 0xd) = 0;
- local_5c.ObjectID = ::NONE.ObjectID;
- bVar2 = (pTVar3->TradeObject).ObjectID !=
- ::NONE.ObjectID;
- if (bVar2) {
- SendTradeOffer((pTVar3->super_TCreature).Connection,
- this->Name,false,local_4c);
- local_4c[0].ObjectID =
- (ulong)this[1].super_TSkillBase.TimerList[0xb];
- SendTradeOffer(this->Connection,this->Name,true,
- local_4c);
- local_4c[0].ObjectID =
- (pTVar3->TradeObject).ObjectID;
- Name = (pTVar3->super_TCreature).Name;
- Connection = this->Connection;
- }
- else {
- Name = this->Name;
- SendMessage((pTVar3->super_TCreature).Connection,
- 0x16,"%s wants to trade with you.",Name)
- ;
- local_4c[0].ObjectID =
- (ulong)this[1].super_TSkillBase.TimerList[0xb];
- Connection = this->Connection;
- }
- SendTradeOffer(Connection,Name,!bVar2,local_4c);
- return;
- }
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 0x36;
- }
- else {
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 7;
- }
- }
- else {
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 5;
- }
- }
- else {
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 0x37;
- }
- }
- else {
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 0x35;
- }
- }
- }
- goto LAB_080c03d9;
- }
- }
-LAB_080c03c7:
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 1;
- }
- else {
- error(&DAT_08106e40);
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = 0xffffffff;
- }
-LAB_080c03d9:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar5,&RESULT::typeinfo,0);
-}
-
-
-
-// DWARF original prototype: void Use(TCreature * this, Object * Obj1, Object * Obj2, uchar Dummy)
-
-void __thiscall TCreature::Use(TCreature *this,Object *Obj1,Object *Obj2,uchar Dummy)
-
-{
- int iVar1;
- bool bVar2;
- undefined4 *puVar3;
- ulong uVar4;
- int *piVar5;
- int Delay;
- bool bVar6;
- int iStack_70;
- uchar Dummy_local;
- int local_6c;
- int local_68;
- int x;
- int y;
- int z;
- Object local_4c [4];
- ulong local_3c;
- Object local_2c [7];
-
- // try { // try from 080c0652 to 080c098c has its CatchHandler @ 080c09a0
- bVar2 = Object::exists(Obj1);
- if (bVar2) {
- bVar2 = false;
- local_2c[0].ObjectID = ::NONE.ObjectID;
- local_3c = ::NONE.ObjectID;
- if ((Obj2->ObjectID != ::NONE.ObjectID) && (bVar6 = Object::exists(Obj2), !bVar6)) {
- bVar2 = true;
- }
- if (!bVar2) {
- bVar2 = false;
- local_3c = ::NONE.ObjectID;
- local_2c[0].ObjectID = ::NONE.ObjectID;
- local_4c[0] = (Object)Obj2->ObjectID;
- if (local_4c[0].ObjectID != ::NONE.ObjectID) {
- Object::getObjectType(local_2c);
- bVar6 = ObjectType::getFlag((ObjectType *)local_2c,DISTUSE);
- if (!bVar6) {
- local_2c[0] = (Object)Obj2->ObjectID;
- bVar6 = ObjectInRange(this->ID,local_2c,1);
- if (!bVar6) {
- bVar2 = true;
- }
- }
- local_4c[0] = (Object)Obj2->ObjectID;
- }
- if (bVar2) {
- GetObjectCoordinates(local_4c,&local_68,&x,&y);
- bVar2 = ToDoClear(this);
- if ((bVar2) && (this->Type == PLAYER)) {
- SendSnapback(this->Connection);
- }
- local_4c[0] = (Object)Obj1->ObjectID;
- uVar4 = GetObjectCreatureID(local_4c);
- if (uVar4 != this->ID) {
- z = Obj1->ObjectID;
- ToDoMove(this,(Object *)&z,0xffff,0,0,'\x01');
- }
- ToDoGo(this,local_68,x,y,false,0x7fffffff);
- z = Obj2->ObjectID;
- local_4c[0] = (Object)Obj1->ObjectID;
- ToDoUse(this,'\x02',local_4c,(Object *)&z);
- if (this->NrToDo != 0) {
- this->LockToDo = true;
- this->ActToDo = 0;
- local_6c = CalculateDelay(this);
- iStack_70 = 1;
- piVar5 = &stack0xffffff90;
- if (0 < local_6c) {
- piVar5 = &local_6c;
- }
- iVar1 = *piVar5;
- priority_queue<>::insert(&ToDoQueue);
- this->NextWakeup = iVar1 + ServerMilliseconds;
- }
- return;
- }
- bVar2 = false;
- z = ::NONE.ObjectID;
- bVar6 = local_4c[0].ObjectID != ::NONE.ObjectID;
- local_4c[0].ObjectID = ::NONE.ObjectID;
- if (bVar6) {
- Object::getObjectType(local_4c);
- bVar6 = ObjectType::getFlag((ObjectType *)local_4c,DISTUSE);
- if (bVar6) {
- local_4c[0] = (Object)Obj2->ObjectID;
- bVar6 = ObjectInRange(this->ID,local_4c,7);
- if (!bVar6) {
- bVar2 = true;
- }
- }
- }
- if (!bVar2) {
- z = Obj2->ObjectID;
- if (z != ::NONE.ObjectID) {
- this->EarliestMultiuseTime = ServerMilliseconds + 1000;
- z = Obj2->ObjectID;
- }
- local_4c[0] = (Object)Obj1->ObjectID;
- ::Use(this->ID,local_4c,(Object *)&z,Dummy);
- return;
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 5;
- goto LAB_080c0733;
- }
- }
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0x1f;
-LAB_080c0733:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-// DWARF original prototype: void Turn(TCreature * this, Object * Obj)
-
-void __thiscall TCreature::Turn(TCreature *this,Object *Obj)
-
-{
- bool bVar1;
- undefined4 *puVar2;
- Object local_1c [5];
-
- // try { // try from 080c09cf to 080c0a25 has its CatchHandler @ 080c0a26
- bVar1 = Object::exists(Obj);
- if (bVar1) {
- local_1c[0] = (Object)Obj->ObjectID;
- ::Turn(this->ID,local_1c);
- return;
- }
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0x1f;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-// DWARF original prototype: void NotifyGo(TCreature * this)
-
-void __thiscall TCreature::NotifyGo(TCreature *this)
-
-{
- int iVar1;
- int iVar2;
- TConnection *Connection;
- bool bVar3;
- bool bVar4;
- bool bVar5;
- int Waypoints;
- int iVar6;
- CreatureType CVar7;
- ulong uVar8;
- int iVar9;
- TPlayer *pTVar10;
- int dx;
- uint uVar11;
- TCreature *Window;
- int dy;
- uint uVar12;
- TCreature *Obj_00;
- TCreature *Con_00;
- TPlayer *Partner;
- bool DiagonalMove;
- int dz;
- int local_68;
- int x;
- int y;
- int z;
- Object Obj;
- Object local_4c [4];
- Object local_3c [4];
- Object local_2c;
- Object Con;
-
- local_2c.ObjectID = (this->CrObject).ObjectID;
- GetObjectCoordinates(&local_2c,&local_68,&x,&y);
- iVar9 = this->posx;
- uVar11 = local_68 - iVar9;
- iVar1 = this->posy;
- uVar12 = x - iVar1;
- iVar2 = this->posz;
- bVar3 = false;
- iVar6 = y - iVar2;
- if (((iVar6 == 0) && (uVar11 != 0)) && (uVar12 != 0)) {
- bVar3 = true;
- }
- MoveChainCreature(this,local_68,x);
- CVar7 = this->Type;
- if ((CVar7 == PLAYER) && (Connection = this->Connection, Connection != (TConnection *)0x0)) {
- if (((iVar6 + 1U < 3) && (uVar11 + 1 < 3)) && (uVar12 + 1 < 3)) {
- if (iVar6 == 1) {
- this->posz = this->posz + 1;
- this->posx = this->posx + -1;
- this->posy = this->posy + -1;
- SendFloors(Connection,false);
- uVar11 = uVar11 + 1;
- uVar12 = uVar12 + 1;
- }
- if (iVar6 == -1) {
- this->posz = this->posz + -1;
- uVar11 = uVar11 - 1;
- this->posx = this->posx + 1;
- uVar12 = uVar12 - 1;
- this->posy = this->posy + 1;
- SendFloors(this->Connection,true);
- }
- for (; 0 < (int)uVar11; uVar11 = uVar11 - 1) {
- this->posx = this->posx + 1;
- SendRow(this->Connection,1);
- }
- for (; (int)uVar11 < 0; uVar11 = uVar11 + 1) {
- this->posx = this->posx + -1;
- SendRow(this->Connection,3);
- }
- for (; 0 < (int)uVar12; uVar12 = uVar12 - 1) {
- this->posy = this->posy + 1;
- SendRow(this->Connection,2);
- }
- for (; (int)uVar12 < 0; uVar12 = uVar12 + 1) {
- this->posy = this->posy + -1;
- SendRow(this->Connection,0);
- }
- }
- else {
- this->posx = this->posx + uVar11;
- this->posy = this->posy + uVar12;
- this->posz = this->posz + iVar6;
- SendFullScreen(Connection);
- }
- CVar7 = this->Type;
- }
- else {
- this->posx = this->posx + uVar11;
- this->posy = this->posy + uVar12;
- this->posz = this->posz + iVar6;
- }
- if (CVar7 != PLAYER) goto LAB_080c0c2d;
- Window = (TCreature *)0x0;
- do {
- Obj_00 = this;
- Con_00 = Window;
- TPlayer::GetOpenContainer((TPlayer *)&local_2c,(int)this);
- local_3c[0].ObjectID = ::NONE.ObjectID;
- if (local_2c.ObjectID != ::NONE.ObjectID) {
- bVar4 = Object::exists(&local_2c);
- if (bVar4) {
- Con_00 = (TCreature *)0x1;
- Obj_00 = (TCreature *)local_3c;
- local_3c[0].ObjectID = local_2c.ObjectID;
- bVar4 = ObjectAccessible(this->ID,(Object *)Obj_00,1);
- if (bVar4) goto LAB_080c0c07;
- local_4c[0] = (Object)::NONE.ObjectID;
- Con_00 = (TCreature *)local_4c;
- }
- else {
- error("TCreature::NotifyGo: OpenContainer existiert nicht. (%s, [%d,%d,%d]->[%d,%d,%d])\n"
- ,this->Name,iVar9,iVar1,iVar2,this->posx,this->posy,this->posz);
- local_3c[0].ObjectID = ::NONE.ObjectID;
- Con_00 = (TCreature *)local_3c;
- }
- TPlayer::SetOpenContainer((TPlayer *)this,(int)Window,(Object *)Con_00);
- Obj_00 = Window;
- SendCloseContainer(this->Connection,(int)Window);
- }
-LAB_080c0c07:
- Window = (TCreature *)((int)&Window->_vptr_TCreature + 1);
- } while ((int)Window < 0x10);
- local_4c[0].ObjectID = ::NONE.ObjectID;
- local_3c[0].ObjectID = ::NONE.ObjectID;
- if (this[1].super_TSkillBase.TimerList[0xb] == (TSkill *)::NONE.ObjectID) goto LAB_080c0c2d;
- pTVar10 = GetPlayer((ulong)this[1].super_TSkillBase.TimerList[0xc]);
- bVar4 = Object::exists((Object *)(this[1].super_TSkillBase.TimerList + 0xb));
- if (!bVar4) {
- error("TCreature::NotifyGo: Handelsobjekt existiert nicht mehr.\n",Obj_00,Con_00);
- error(&DAT_081072f3,this->Name,this->posx,this->posy,this->posz);
- if (pTVar10 != (TPlayer *)0x0) {
- error("# Partner %s an [%d,%d,%d]\n",(pTVar10->super_TCreature).Name,
- (pTVar10->super_TCreature).posx,(pTVar10->super_TCreature).posy,
- (pTVar10->super_TCreature).posz);
- }
- }
- bVar4 = false;
- if (pTVar10 == (TPlayer *)0x0) {
-LAB_080c0dba:
- bVar4 = true;
- }
- else {
- local_3c[0].ObjectID = (ulong)this[1].super_TSkillBase.TimerList[0xb];
- bVar5 = ObjectAccessible(this->ID,local_3c,1);
- if (!bVar5) goto LAB_080c0dba;
- local_2c.ObjectID = (pTVar10->super_TCreature).CrObject.ObjectID;
- z = (this->CrObject).ObjectID;
- iVar9 = ObjectDistance((Object *)&z,&local_2c);
- if ((2 < iVar9) ||
- (bVar5 = ThrowPossible(this->posx,this->posy,this->posz,(pTVar10->super_TCreature).posx,
- (pTVar10->super_TCreature).posy,(pTVar10->super_TCreature).posz,0)
- , !bVar5)) goto LAB_080c0dba;
- }
- if (bVar4) {
- SendCloseTrade(this->Connection);
- SendMessage(this->Connection,0x17,"Trade cancelled.");
- TPlayer::RejectTrade((TPlayer *)this);
- }
-LAB_080c0c2d:
- GetFirstObject();
- while( true ) {
- Object::getObjectType(local_4c);
- bVar4 = ObjectType::getFlag((ObjectType *)local_4c,BANK);
- if (bVar4) break;
- local_4c[0].ObjectID = ::NONE.ObjectID;
- local_3c[0].ObjectID = ::NONE.ObjectID;
- if (z == ::NONE.ObjectID) break;
- Object::getNextObject(local_3c);
- z = local_3c[0].ObjectID;
- local_4c[0].ObjectID = z;
- }
- local_4c[0] = (Object)::NONE.ObjectID;
- if (z == ::NONE.ObjectID) {
- error("TCreature::NotifyGo: Auf Feld [%d,%d,%d] befindet sich kein Bank.\n",this->posx,
- this->posy,this->posz);
- }
- else {
- Object::getObjectType(local_4c);
- uVar8 = ObjectType::getAttribute((ObjectType *)local_4c,WAYPOINTS);
- if (bVar3) {
- uVar8 = uVar8 * 3;
- }
- iVar9 = GetSpeed(this);
- this->EarliestWalkTime =
- ((Beat + -1 + (int)(uVar8 * 1000) / iVar9) / Beat) * Beat + ServerMilliseconds;
- }
- return;
-}
-
-
-
-// DWARF original prototype: void NotifyTurn(TCreature * this, Object * DestCon)
-
-void __thiscall TCreature::NotifyTurn(TCreature *this,Object *DestCon)
-
-{
- int dy;
- int iVar1;
- int local_28;
- int x;
- int y;
- int z;
-
- z = DestCon->ObjectID;
- GetObjectCoordinates((Object *)&z,&local_28,&x,&y);
- local_28 = local_28 - this->posx;
- iVar1 = x - this->posy;
- if (local_28 < 1) {
- if (local_28 < 0) {
- this->Direction = 3;
- }
- else if (iVar1 < 0) {
- this->Direction = 0;
- }
- else if (x != this->posy && -1 < iVar1) {
- this->Direction = 2;
- }
- }
- else {
- this->Direction = 1;
- }
- return;
-}
-
-
-
-// DWARF original prototype: void NotifyDelete(TCreature * this)
-
-void __thiscall TCreature::NotifyDelete(TCreature *this)
-
-{
- CreatureType CVar1;
-
- if (this->Type == PLAYER) {
- CVar1 = PLAYER;
- if (this->Connection != (TConnection *)0x0) {
- TConnection::Logout(this->Connection,0x1e,true);
- CVar1 = this->Type;
- this->LoggingOut = true;
- }
- if (CVar1 == PLAYER) {
- TPlayer::RejectTrade((TPlayer *)this);
- }
- }
- DeleteChainCreature(this);
- return;
-}
-
-
-
-// DWARF original prototype: void NotifyCreate(TCreature * this)
-
-void __thiscall TCreature::NotifyCreate(TCreature *this)
-
-{
- InsertChainCreature(this,0,0);
- return;
-}
-
-
-
-// DWARF original prototype: void NotifyChangeInventory(TCreature * this)
-
-void __thiscall TCreature::NotifyChangeInventory(TCreature *this)
-
-{
- TSkill *pTVar1;
- anon_union_4_2_730cd3ca_for_TOutfit_2 aVar2;
- bool bVar3;
- bool bVar4;
- int i;
- int iVar5;
- int iVar6;
- ulong uVar7;
- ulong uVar8;
- bool SkillsChanged;
- int i_1;
- int b;
- ulong uVar9;
- int SkillNr;
- ulong local_ac;
- int iStack_9c;
- int NewDelta [25];
- ulong local_2c;
- Object Obj;
-
- local_2c = ::NONE.ObjectID;
- if ((this->CrObject).ObjectID != ::NONE.ObjectID) {
- bVar3 = Object::exists(&this->CrObject);
- if (bVar3) {
- TCombat::CheckCombatValues(&this->Combat);
- if (this->Type == PLAYER) {
- iVar5 = 0;
- do {
- NewDelta[iVar5 + -1] = 0;
- iVar5 = iVar5 + 1;
- } while (iVar5 < 0x19);
- uVar9 = 1;
- do {
- bVar3 = false;
- GetBodyObject((ulong)&local_2c,this->ID);
- local_ac = ::NONE.ObjectID;
- if (local_2c == ::NONE.ObjectID) {
-LAB_080c12f2:
- bVar3 = true;
- }
- else {
- Object::getObjectType((Object *)&SkillNr);
- bVar4 = ObjectType::getFlag((ObjectType *)&SkillNr,SKILLBOOST);
- if (!bVar4) goto LAB_080c12f2;
- }
- if (!bVar3) {
- Object::getObjectType((Object *)&SkillNr);
- bVar3 = ObjectType::getFlag((ObjectType *)&SkillNr,CLOTHES);
- if (bVar3) {
- Object::getObjectType((Object *)&SkillNr);
- uVar7 = ObjectType::getAttribute((ObjectType *)&SkillNr,BODYPOSITION);
- if (uVar7 == uVar9) {
- Object::getObjectType((Object *)&SkillNr);
- uVar7 = ObjectType::getAttribute((ObjectType *)&SkillNr,SKILLNUMBER)
- ;
- if ((int)uVar7 < 0x19) {
- Object::getObjectType((Object *)&SkillNr);
- uVar8 = ObjectType::getAttribute
- ((ObjectType *)&SkillNr,SKILLMODIFICATION);
- if (0x7fff < (int)uVar8) {
- uVar8 = uVar8 - 0x10000;
- }
- NewDelta[uVar7 - 1] = NewDelta[uVar7 - 1] + uVar8;
- }
- else {
- Object::getObjectType((Object *)&SkillNr);
- error(&DAT_08107080,SkillNr,uVar7);
- }
- }
- }
- else {
- Object::getObjectType((Object *)&SkillNr);
- error("TCreature::NotifyChangeInventory: Objekt %d hat SKILLBOOST, aber nicht CLOTHES.\n"
- ,SkillNr);
- }
- }
- uVar9 = uVar9 + 1;
- } while ((int)uVar9 < 0xb);
- bVar3 = false;
- iVar5 = 0;
- do {
- pTVar1 = (this->super_TSkillBase).Skills[iVar5];
- if (pTVar1->DAct != NewDelta[iVar5 + -1]) {
- pTVar1->DAct = NewDelta[iVar5 + -1];
- if (iVar5 == 4) {
- AnnounceChangedCreature(this->ID,4);
- }
- if (iVar5 == 0x10) {
- if (NewDelta[0xf] < 1) {
- pTVar1 = (this->super_TSkillBase).Skills[0x10];
- iVar6 = (*pTVar1->_vptr_TSkill[0xd])(pTVar1);
- if (iVar6 == 0) {
- aVar2 = (this->OrgOutfit).field_1;
- (this->Outfit).OutfitID = (this->OrgOutfit).OutfitID;
- (this->Outfit).field_1 = aVar2;
- }
- }
- else {
- bVar3 = false;
- if (((this->Outfit).OutfitID == 0) &&
- ((this->Outfit).field_1.ObjectType == 0)) {
- bVar3 = true;
- }
- if ((!bVar3) &&
- (pTVar1 = (this->super_TSkillBase).Skills[0x10],
- iVar6 = (*pTVar1->_vptr_TSkill[0xd])(pTVar1), iVar6 != 0)) {
- TSkillBase::SetTimer(&this->super_TSkillBase);
- }
- (this->Outfit).OutfitID = 0;
- (this->Outfit).field_1.ObjectType = 0;
- }
- AnnounceChangedCreature(this->ID,3);
- }
- bVar3 = true;
- }
- iVar5 = iVar5 + 1;
- } while (iVar5 < 0x19);
- if (bVar3) {
- SendPlayerSkills(this->Connection);
- TPlayer::CheckState((TPlayer *)this);
- }
- SendPlayerData(this->Connection);
- }
- }
- else {
- error("TCreature::NotifyChangeInventory: Kreatur-Objekt existiert nicht.\n");
- error("# Kreatur: %s, Position: %d/%d/%d.\n",this->Name,this->posx,this->posy,this->posz
- );
- }
- }
- return;
-}
-
// WARNING: Unknown calling convention -- yet parameter storage is locked
void _GLOBAL__I__ZN9TShortwayC2EP9TCreatureii(void)
diff --git a/src/cr.hh b/src/cr.hh
index 2c60163..5ad1676 100644
--- a/src/cr.hh
+++ b/src/cr.hh
@@ -526,6 +526,11 @@ struct TCreature: TSkillBase {
void ToDoAttack(void);
void ToDoTalk(int Mode, const char *Addressee, const char *Text, bool CheckSpamming);
void ToDoChangeState(int NewState);
+ void NotifyGo(void);
+ void NotifyTurn(Object DestCon);
+ void NotifyCreate(void);
+ void NotifyDelete(void);
+ void NotifyChangeInventory(void);
// VIRTUAL FUNCTIONS
// =================
@@ -679,6 +684,7 @@ struct TMonster: TNonplayer {
struct TPlayer: TCreature {
//TPlayer(void);
+ // TODO(fusion): Eventually sort these out when we implement player functions.
uint8 GetRealProfession(void);
uint8 GetEffectiveProfession(void);
uint8 GetActiveProfession(void);
@@ -701,6 +707,9 @@ struct TPlayer: TCreature {
void ClearPlayerkillingMarks(void);
void SaveInventory(void);
+ Object GetOpenContainer(int ContainerNr);
+ void SetOpenContainer(int ContainerNr, Object Con);
+ void RejectTrade(void);
// VIRTUAL FUNCTIONS
// =================
diff --git a/src/cract.cc b/src/cract.cc
index 8306ad5..3d56aa2 100644
--- a/src/cract.cc
+++ b/src/cract.cc
@@ -1,4 +1,5 @@
#include "cr.hh"
+#include "config.hh"
#include "operate.hh"
#include "stubs.hh"
@@ -364,8 +365,8 @@ void TCreature::Go(int DestX, int DestY, int DestZ){
}
if(!this->MovePossible(DestX, DestY, DestZ, true, false)){
- bool Diagonal = (OrigX != DestX && OrigY != DestY);
- if(this->Type == PLAYER && !Diagonal){
+ bool DiagonalMove = (OrigX != DestX && OrigY != DestY);
+ if(this->Type == PLAYER && !DiagonalMove){
// TODO(fusion): These are quite similar to `MagicClimbing`. Perhaps
// there is an inlined function here that checks whether climbing is
// possible.
@@ -454,7 +455,7 @@ void TCreature::Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count){
try{
Object Con = GetBodyContainer(this->ID, Position);
CheckInventoryDestination(Obj, Con, false);
- }catch(...){
+ }catch(RESULT r){
continue;
}
@@ -585,7 +586,7 @@ void TCreature::Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count){
this->ToDoMove(Obj, 0xFFFF, 0, 0, 1);
}
- // NOTE(fusion): Walk to destination then try again.
+ // NOTE(fusion): Walk to destination and try again.
this->ToDoGo(DestX, DestY, DestZ, false, INT_MAX);
this->ToDoMove(Obj, DestX, DestY, DestZ, 1);
this->ToDoStart();
@@ -595,6 +596,132 @@ void TCreature::Move(Object Obj, int DestX, int DestY, int DestZ, uint8 Count){
}
}
+void TCreature::Trade(Object Obj, uint32 PartnerID){
+ if(this->Type != PLAYER){
+ error("TCreature::Trade: Nur Spieler können handeln.\n");
+ throw ERROR;
+ }
+
+ if(!Obj.exists() || !ObjectAccessible(this->ID, Obj, 1)){
+ throw NOTACCESSIBLE;
+ }
+
+ if(this->ID == PartnerID){
+ throw CROSSREFERENCE;
+ }
+
+ TPlayer *Partner = GetPlayer(PartnerID);
+ if(Partner == NULL || Partner->Type != PLAYER){
+ throw PLAYERNOTONLINE;
+ }
+
+ if(((TPlayer*)this)->TradeObject != NONE){
+ throw ALREADYTRADING;
+ }
+
+ if(CountObjects(Obj) > 100){
+ throw TOOMANYOBJECTS;
+ }
+
+ if(ObjectDistance(this->CrObject, Partner->CrObject) > 2){
+ throw OUTOFRANGE;
+ }
+
+ if(!ThrowPossible(this->posx, this->posy, this->posz,
+ Partner->posx, Partner->posy, Partner->posz, 0)){
+ throw CANNOTTHROW;
+ }
+
+ if(Partner->TradeObject != NONE && Partner->TradePartner != this->ID){
+ throw PARTNERTRADING;
+ }
+
+ // NOTE(fusion): Check if one object is contained by the other.
+ if(Partner->TradeObject != NONE){
+ Object Help = Partner->TradeObject;
+ while(Help != NONE && !Help.getObjectType().isMapContainer()){
+ if(Help == Obj){
+ throw NOTACCESSIBLE;
+ }
+ Help = Help.getContainer();
+ }
+
+ Help = Obj;
+ while(Help != NONE && !Help.getObjectType().isMapContainer()){
+ if(Help == Partner->TradeObject){
+ throw NOTACCESSIBLE;
+ }
+ Help = Help.getContainer();
+ }
+ }
+
+ ((TPlayer*)this)->TradeObject = Obj;
+ ((TPlayer*)this)->TradePartner = PartnerID;
+ ((TPlayer*)this)->TradeAccepted = false;
+
+ if(Partner->TradeObject != NONE){
+ SendTradeOffer(Partner->Connection, this->Name, false, Obj);
+ SendTradeOffer(this->Connection, this->Name, true, Obj);
+ SendTradeOffer(this->Connection, Partner->Name, false, Partner->TradeObject);
+ }else{
+ SendMessage(Partner->Connection, TALK_INFO_MESSAGE,
+ "%s wants to trade with you.", this->Name);
+ SendTradeOffer(this->Connection, this->Name, true, Obj);
+ }
+}
+
+void TCreature::Use(Object Obj1, Object Obj2, uint8 Dummy){
+ if(!Obj1.exists()){
+ throw DESTROYED;
+ }
+
+ if(Obj2 != NONE){
+ if(!Obj2.exists()){
+ throw DESTROYED;
+ }
+
+ bool DistUse = Obj1.getObjectType().getFlag(DISTUSE);
+ if(!DistUse && !ObjectInRange(this->ID, Obj2, 1)){
+ int ObjX2, ObjY2, ObjZ2;
+ GetObjectCoordinates(Obj2, &ObjX2, &ObjY2, &ObjZ2);
+
+ if(this->ToDoClear() && this->Type == PLAYER){
+ SendSnapback(this->Connection);
+ }
+
+ // NOTE(fusion): Pick up object 1 if it's not in our inventory.
+ if(GetObjectCreatureID(Obj1) != this->ID){
+ this->ToDoMove(Obj1, 0xFFFF, 0, 0, 1);
+ }
+
+ // NOTE(fusion): Walk to object 2 and try again.
+ this->ToDoGo(ObjX2, ObjY2, ObjZ2, false, INT_MAX);
+ // TODO(fusion): Missing `Dummy` here? Probably not because this
+ // could only be triggered if object 2 exists and Dummy is only
+ // used when opening containers.
+ this->ToDoUse(2, Obj1, Obj2);
+ this->ToDoStart();
+ return;
+ }
+
+ if(DistUse && !ObjectInRange(this->ID, Obj2, 7)){
+ throw OUTOFRANGE;
+ }
+
+ this->EarliestMultiuseTime = ServerMilliseconds + 1000;
+ }
+
+ ::Use(this->ID, Obj1, Obj2, Dummy);
+}
+
+void TCreature::Turn(Object Obj){
+ if(!Obj.exists()){
+ throw DESTROYED;
+ }
+
+ ::Turn(this->ID, Obj);
+}
+
void TCreature::Attack(void){
this->Combat.Attack();
}
@@ -1192,3 +1319,269 @@ void TCreature::ToDoChangeState(int NewState){
TD.ChangeState.NewState = NewState;
this->ToDoAdd(TD);
}
+
+void TCreature::NotifyGo(void){
+ // IMPORTANT(fusion): This and the function that does move `this->CrObject`
+ // should be the only ones where the output of `GetObjectCoordinates` will
+ // differ from `this->posx`, `this->posy`, and `this->posz`.
+
+ int DestX, DestY, DestZ;
+ GetObjectCoordinates(this->CrObject, &DestX, &DestY, &DestZ);
+ MoveChainCreature(this, DestX, DestY);
+
+ int OrigX = this->posx;
+ int OrigY = this->posy;
+ int OrigZ = this->posz;
+ bool DiagonalMove = (DestX != OrigX && DestY != OrigY && DestZ == OrigZ);
+
+ // IMPORTANT(fusion): `SendFloors` and `SendRow` will use the current creature
+ // position to know where to pull fields from, so we need to keep them updated
+ // as we go.
+ if(this->Type == PLAYER && this->Connection != NULL){
+ int DistanceX = std::abs(DestX - OrigX);
+ int DistanceY = std::abs(DestY - OrigY);
+ int DistanceZ = std::abs(DestZ - OrigZ);
+ if(DistanceX <= 1 && DistanceY <= 1 && DistanceZ <= 1){
+ while(this->posz < DestZ){
+ this->posx -= 1;
+ this->posy -= 1;
+ this->posz += 1;
+ SendFloors(this->Connection, false);
+ }
+
+ while(this->posz > DestZ){
+ this->posx += 1;
+ this->posy += 1;
+ this->posz -= 1;
+ SendFloors(this->Connection, true);
+ }
+
+ while(this->posx < DestX){
+ this->posx += 1;
+ SendRow(this->Connection, DIRECTION_EAST);
+ }
+
+ while(this->posx > DestX){
+ this->posx -= 1;
+ SendRow(this->Connection, DIRECTION_WEST);
+ }
+
+ while(this->posy < DestY){
+ this->posy += 1;
+ SendRow(this->Connection, DIRECTION_SOUTH);
+ }
+
+ while(this->posy > DestY){
+ this->posy -= 1;
+ SendRow(this->Connection, DIRECTION_NORTH);
+ }
+ }else{
+ this->posx = DestX;
+ this->posy = DestY;
+ this->posz = DestZ;
+ SendFullScreen(this->Connection);
+ }
+ }else{
+ this->posx = DestX;
+ this->posy = DestY;
+ this->posz = DestZ;
+ }
+
+ if(this->Type == PLAYER){
+ // NOTE(fusion): Check open containers.
+ for(int ContainerNr = 0;
+ ContainerNr < NARRAY(TPlayer::OpenContainer);
+ ContainerNr += 1){
+ Object Con = ((TPlayer*)this)->GetOpenContainer(ContainerNr);
+ if(Con == NONE){
+ continue;
+ }
+
+ if(!Con.exists()){
+ error("TCreature::NotifyGo: OpenContainer existiert nicht. (%s, [%d,%d,%d]->[%d,%d,%d])\n",
+ this->Name, OrigX, OrigY, OrigZ, DestX, DestY, DestZ);
+ continue;
+ }
+
+ if(!ObjectAccessible(this->ID, Con, 1)){
+ ((TPlayer*)this)->SetOpenContainer(ContainerNr, NONE);
+ SendCloseContainer(this->Connection, ContainerNr);
+ }
+ }
+
+ // NOTE(fusion): Check trade.
+ Object TradeObject = ((TPlayer*)this)->TradeObject;
+ if(TradeObject != NONE){
+ TPlayer *Partner = GetPlayer(((TPlayer*)this)->TradePartner);
+ if(!TradeObject.exists()){
+ error("TCreature::NotifyGo: Handelsobjekt existiert nicht mehr.\n");
+ error("# Händler %s an [%d,%d,%d]\n", this->Name, DestX, DestY, DestZ);
+ if(Partner != NULL){
+ error("# Partner %s an [%d,%d,%d]\n", Partner->Name,
+ Partner->posx, Partner->posy, Partner->posz);
+ }
+ }
+
+ if(Partner == NULL || !ObjectAccessible(this->ID, TradeObject, 1)
+ || ObjectDistance(this->CrObject, Partner->CrObject) > 2
+ || !ThrowPossible(this->posx, this->posy, this->posz,
+ Partner->posx, Partner->posy, Partner->posz, 0)){
+ SendCloseTrade(this->Connection);
+ SendMessage(this->Connection, TALK_FAILURE_MESSAGE, "Trade cancelled.");
+ ((TPlayer*)this)->RejectTrade();
+ }
+ }
+ }
+
+ // TODO(fusion): This is probably an inlined function to get the first object
+ // with some specific flag on a field.
+ int Waypoints;
+ Object Bank = GetFirstObject(DestX, DestY, DestZ);
+ while(Bank != NONE){
+ ObjectType BankType = Bank.getObjectType();
+ if(BankType.getFlag(BANK)){
+ Waypoints = BankType.getAttribute(WAYPOINTS);
+ break;
+ }
+ Bank = Bank.getNextObject();
+ }
+
+ if(Bank != NONE){
+ // NOTE(fusion): Diagonal movement has three times the delay of a regular one.
+ if(DiagonalMove){
+ Waypoints *= 3;
+ }
+
+ // NOTE(fusion): Compute the step interval and quantize it to be a multiple
+ // of `Beat`, rounding up.
+ int Delay = (Waypoints * 1000) / this->GetSpeed();
+ int BeatCount = (Delay + Beat - 1) / Beat;
+ this->EarliestWalkTime = ServerMilliseconds + BeatCount * Beat;
+ }else{
+ error("TCreature::NotifyGo: Auf Feld [%d,%d,%d] befindet sich kein Bank.\n",
+ DestX, DestY, DestZ);
+ }
+}
+
+void TCreature::NotifyTurn(Object DestCon){
+ int DestX, DestY, DestZ;
+ GetObjectCoordinates(DestCon, &DestX, &DestY, &DestZ);
+
+ // NOTE(fusion): This is somewhat similar to `TCreature::Rotate`.
+ int OffsetX = DestX - this->posx;
+ int OffsetY = DestY - this->posy;
+ if(OffsetX > 0){
+ this->Direction = DIRECTION_EAST;
+ }else if(OffsetX < 0){
+ this->Direction = DIRECTION_WEST;
+ }else if(OffsetY < 0){
+ this->Direction = DIRECTION_NORTH;
+ }else if(OffsetY > 0){
+ this->Direction = DIRECTION_SOUTH;
+ }
+}
+
+void TCreature::NotifyCreate(void){
+ InsertChainCreature(this, 0, 0);
+}
+
+void TCreature::NotifyDelete(void){
+ if(this->Type == PLAYER){
+ if(this->Connection != NULL){
+ this->Connection->Logout(30, true);
+ this->LoggingOut = true;
+ }
+
+ ((TPlayer*)this)->RejectTrade();
+ }
+
+ DeleteChainCreature(this);
+}
+
+void TCreature::NotifyChangeInventory(void){
+ if(this->CrObject == NONE){
+ return;
+ }
+
+ if(!this->CrObject.exists()){
+ error("TCreature::NotifyChangeInventory: Kreatur-Objekt existiert nicht.\n");
+ error("# Kreatur: %s, Position: %d/%d/%d.\n",
+ this->Name, this->posx, this->posy, this->posz);
+ return;
+ }
+
+ this->Combat.CheckCombatValues();
+ if(this->Type == PLAYER){
+ int NewDelta[NARRAY(this->Skills)];
+ for(int Position = INVENTORY_FIRST;
+ Position <= INVENTORY_LAST;
+ Position += 1){
+ Object Obj = GetBodyObject(this->ID, Position);
+ if(Obj == NONE){
+ continue;
+ }
+
+ ObjectType ObjType = Obj.getObjectType();
+ if(!ObjType.getFlag(SKILLBOOST)){
+ continue;
+ }
+
+ if(!ObjType.getFlag(CLOTHES)){
+ error("TCreature::NotifyChangeInventory: Objekt %d hat SKILLBOOST, aber nicht CLOTHES.\n",
+ ObjType.TypeID);
+ continue;
+ }
+
+ if((int)ObjType.getAttribute(BODYPOSITION) != Position){
+ continue;
+ }
+
+ int SkillNr = (int)ObjType.getAttribute(SKILLNUMBER);
+ if(SkillNr < 0 || SkillNr >= NARRAY(this->Skills)){
+ error("TCreature::NotifyChangeInventory: Objekt %d hat ungültige SKILLNUMBER %d.\n",
+ ObjType.TypeID, SkillNr);
+ continue;
+ }
+
+ // IMPORTANT(fusion): The value for the skill modification is stored
+ // as uint32 but is bitcast from a signed integer on load, meaning that
+ // that bitcasting it back should retrieve the original signed value.
+ // See `LoadObjects`.
+ NewDelta[SkillNr] += (int)ObjType.getAttribute(SKILLMODIFICATION);
+ }
+
+ bool SkillsChanged = false;
+ for(int SkillNr = 0;
+ SkillNr < NARRAY(this->Skills);
+ SkillNr += 1){
+ TSkill *Skill = this->Skills[SkillNr];
+ if(Skill->DAct != NewDelta[SkillNr]){
+ SkillsChanged = true;
+ Skill->DAct = NewDelta[SkillNr];
+ if(SkillNr == SKILL_GO_STRENGTH){
+ AnnounceChangedCreature(this->ID, 4); // CREATURE_GO_STRENGTH_CHANGED ?
+ }else if(SkillNr == SKILL_ILLUSION){
+ if(NewDelta[SKILL_ILLUSION] > 0){
+ if(this->Outfit.OutfitID != 0 || this->Outfit.ObjectType != 0){
+ if(Skill->TimerValue() != 0){
+ this->SetTimer(SKILL_ILLUSION, 0, 0, 0, -1);
+ }
+ this->Outfit.OutfitID = 0;
+ this->Outfit.ObjectType = 0;
+ }
+ }else if(Skill->TimerValue() == 0){
+ this->Outfit = this->OrgOutfit;
+ }
+ AnnounceChangedCreature(this->ID, 3); // CREATURE_OUTFIT_CHANGED ?
+ }
+ }
+ }
+
+ if(SkillsChanged){
+ SendPlayerSkills(this->Connection);
+ ((TPlayer*)this)->CheckState();
+ }
+
+ SendPlayerData(this->Connection);
+ }
+}
diff --git a/src/magic.cc b/src/magic.cc
index a222b3a..46da798 100644
--- a/src/magic.cc
+++ b/src/magic.cc
@@ -3690,7 +3690,7 @@ static void RuneSpell(uint32 CreatureID, int SpellNr){
ObjectType RuneType = GetNewObjectType(RuneGr, RuneNr);
Change(LeftHand, RuneType, Amount);
RuneCreated = true;
- }catch(...){
+ }catch(RESULT r){
if(!RuneCreated){
throw;
}
diff --git a/src/stubs.hh b/src/stubs.hh
index 867d813..c2ca289 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -27,6 +27,7 @@ extern void CleanHouseField(int x, int y, int z);
extern void ConvinceMonster(TCreature *Master, TCreature *Slave);
extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster);
extern int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value);
+extern int CountObjects(Object Obj);
extern int CountObjectsInContainer(Object Con);
extern Object Create(Object Con, ObjectType Type, uint32 Value);
extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value);
@@ -63,6 +64,7 @@ extern void Move(uint32 CreatureID, Object Obj, Object Con, int Count, bool NoMe
extern void NetLoadCheck(void);
extern void NetLoadSummary(void);
extern void NotifyAllCreatures(Object Obj, int Type, Object OldCon);
+extern bool ObjectAccessible(uint32 CreatureID, Object Obj, int Range);
extern int ObjectDistance(Object Obj1, Object Obj2);
extern bool ObjectInRange(uint32 CreatureID, Object Obj, int Range);
extern void ProcessCommunicationControl(void);
@@ -82,7 +84,12 @@ extern bool SearchSummonField(int *x, int *y, int *z, int Distance);
extern void SendAll(void);
extern void SendAmbiente(TConnection *Connection);
extern void SendClearTarget(TConnection *Connection);
+extern void SendCloseContainer(TConnection *Connection, int ContainerNr);
+extern void SendCloseTrade(TConnection *Connection);
extern void SendEditList(TConnection *Connection, uint8 ListType, uint32 ID, const char *Text);
+extern void SendFullScreen(TConnection *Connection);
+extern void SendFloors(TConnection *Connection, bool Up);
+extern void SendRow(TConnection *Connection, int Direction);
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);
@@ -91,6 +98,7 @@ extern void SendPlayerSkills(TConnection *Connection);
extern void SendPlayerState(TConnection *Connection, uint8 State);
extern void SendResult(TConnection *Connection, RESULT r);
extern void SendSnapback(TConnection *Connection);
+extern void SendTradeOffer(TConnection *Connection, const char *Name, bool OwnOffer, Object Obj);
extern void ShowGuestList(uint16 HouseID, TPlayer *Player, char *Buffer);
extern void ShowSubownerList(uint16 HouseID, TPlayer *Player, char *Buffer);
extern void ShowNameDoor(Object Door, TPlayer *Player, char *Buffer);
@@ -98,5 +106,7 @@ extern void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char
extern void TextualEffect(Object Obj, int Color, const char *Text, ...) ATTR_PRINTF(3, 4);
extern bool ThrowPossible(int FromX, int FromY, int FromZ,
int ToX, int ToY, int ToZ, int Power);
+extern void Turn(uint32 CreatureID, Object Obj);
+extern void Use(uint32 CreatureID, Object Obj1, Object Object2, uint8 Info);
#endif //TIBIA_STUBS_HH_