aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-03 02:08:15 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-03 02:08:15 -0300
commita1e062c8b27fcf2f65d5a21fc85fbcc80abfa86f (patch)
tree12086bd2c8c443632995a467a6bc6f3d666eacd0
parentd2eb32efe2df9e570e491b08d4ecf50da35f1b75 (diff)
downloadgame-a1e062c8b27fcf2f65d5a21fc85fbcc80abfa86f.tar.gz
game-a1e062c8b27fcf2f65d5a21fc85fbcc80abfa86f.zip
more spells
-rw-r--r--reference/game.c538
-rw-r--r--src/magic.cc262
-rw-r--r--src/stubs.hh1
3 files changed, 255 insertions, 546 deletions
diff --git a/reference/game.c b/reference/game.c
index 138c00e..65ac6f5 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -20852,544 +20852,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void MagicRope(void)
-
-{
- bool bVar1;
- undefined4 *puVar2;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- int iVar3;
- undefined4 uVar4;
- int local_58;
- int x;
- int y;
- int z;
- Object local_3c [4];
- Object local_2c [4];
- ulong local_1c;
- Object Obj;
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- error(&DAT_080fb4a0);
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0xffffffff;
- }
- else {
- local_2c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- local_1c = local_2c[0].ObjectID;
- // try { // try from 08082d0e to 08082e18 has its CatchHandler @ 08082e30
- GetObjectCoordinates(local_2c,&local_58,&x,&y);
- uVar4 = 0x32;
- iVar3 = x;
- bVar1 = CoordinateFlag();
- if (bVar1) {
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- local_2c[0].ObjectID = NONE.ObjectID;
- GetMapContainer((int)local_3c,local_58,x + 1);
- z = local_1c;
- Move(0,(Object *)&z,local_3c,-1,false,local_2c);
- GraphicalEffect();
- return;
- }
- puVar2 = (undefined4 *)__cxa_allocate_exception(4,iVar3,y,uVar4);
- *puVar2 = 1;
- }
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void MagicClimbing(void)
-
-{
- bool bVar1;
- int iVar2;
- undefined4 *puVar3;
- int dz;
- int iVar4;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- char *in_stack_00000010;
- char *Text;
- int *x_00;
- int *y_00;
- int *z_00;
- int *local_70;
- int dy;
- int dx;
- int x;
- int y;
- int z;
- Object local_4c [4];
- Object local_3c [4];
- ulong local_2c;
- Object Obj;
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- Text = &DAT_080fb520;
- }
- else {
- if (in_stack_00000010 != (char *)0x0) {
- local_3c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- x_00 = &dx;
- z_00 = &y;
- y_00 = &x;
- local_2c = local_3c[0].ObjectID;
- // try { // try from 08082e99 to 08083153 has its CatchHandler @ 08083174
- GetObjectCoordinates(local_3c,x_00,y_00,z_00);
- iVar4 = y;
- dy = dx;
- local_70 = (int *)x;
- iVar2 = in_stack_00000004->Direction;
- if (iVar2 == 1) {
- dy = dx + 1;
- }
- else if (iVar2 < 2) {
- if (iVar2 == 0) {
- local_70 = (int *)(x + -1);
- }
- }
- else if (iVar2 == 2) {
- local_70 = (int *)(x + 1);
- }
- else if (iVar2 == 3) {
- dy = dx + -1;
- }
- if (y < 1) {
-LAB_08082f00:
- if (y < 0xf) {
- y_00 = (int *)0xffffffff;
- x_00 = (int *)&DAT_080fdfc1;
- iVar2 = stricmp(in_stack_00000010,"down",-1);
- if (iVar2 == 0) {
- z_00 = (int *)0x0;
- x_00 = local_70;
- y_00 = (int *)y;
- bVar1 = CoordinateFlag();
- if (!bVar1) {
- z_00 = (int *)0x20;
- x_00 = local_70;
- y_00 = (int *)y;
- bVar1 = CoordinateFlag();
- if (!bVar1) {
- z_00 = (int *)(y + 1);
- x_00 = (int *)dy;
- y_00 = local_70;
- iVar2 = (*in_stack_00000004->_vptr_TCreature[3])();
- if ((char)iVar2 != '\0') {
- iVar4 = iVar4 + 1;
- goto LAB_08082f09;
- }
- }
- }
- goto LAB_08082fb4;
- }
- }
-LAB_08082f09:
- if (y != iVar4) {
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- local_3c[0].ObjectID = NONE.ObjectID;
- GetMapContainer((int)local_4c,dy,(int)local_70);
- z = local_2c;
- Move(0,(Object *)&z,local_4c,-1,false,local_3c);
- GraphicalEffect();
- return;
- }
- }
- else {
- y_00 = (int *)0xffffffff;
- x_00 = (int *)&DAT_080fdfbe;
- iVar2 = stricmp(in_stack_00000010,"up",-1);
- if (iVar2 != 0) goto LAB_08082f00;
- z_00 = (int *)0x0;
- y_00 = (int *)(y + -1);
- x_00 = (int *)x;
- bVar1 = CoordinateFlag();
- if (!bVar1) {
- z_00 = (int *)0x20;
- y_00 = (int *)(y + -1);
- bVar1 = CoordinateFlag();
- x_00 = (int *)x;
- if (!bVar1) {
- z_00 = (int *)(y + -1);
- x_00 = (int *)dy;
- y_00 = local_70;
- iVar2 = (*in_stack_00000004->_vptr_TCreature[3])();
- if ((char)iVar2 != '\0') {
- iVar4 = iVar4 + -1;
- goto LAB_08082f00;
- }
- }
- }
- }
-LAB_08082fb4:
- puVar3 = (undefined4 *)__cxa_allocate_exception(4,x_00,y_00,z_00);
- *puVar3 = 1;
- goto LAB_08082fc6;
- }
- Text = &DAT_080fb4e0;
- }
- error(Text);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
-LAB_08082fc6:
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
-}
-
-
-
-void MagicClimbing(TCreature *cr,char *Direction)
-
-{
- bool bVar1;
- undefined4 *puVar2;
- char *Text;
-
- if (cr == (TCreature *)0x0) {
- Text = &DAT_080fb520;
- }
- else if (Direction == (char *)0x0) {
- Text = &DAT_080fb4e0;
- }
- else {
- if (cr->Type == PLAYER) {
- // try { // try from 080831cd to 08083233 has its CatchHandler @ 08083246
- bVar1 = CheckRight(cr->ID,LEVITATE);
- if (bVar1) {
- MagicClimbing();
- }
- return;
- }
- Text = "MagicClimbing: Zauberspruch kann nur von Spielern angewendet werden.\n";
- }
- error(Text);
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,&RESULT::typeinfo,0);
-}
-
-
-
-void CreateThing(TCreature *cr,char *Param1,char *Param2)
-
-{
- bool bVar1;
- bool bVar2;
- int iVar3;
- TConnection *Connection;
- undefined4 *puVar4;
- char *pcVar5;
- int local_60;
- int Count;
- Object Con;
- Object local_4c [4];
- ObjectType local_3c [4];
- ObjectType local_2c;
- ObjectType Type;
-
- if (cr == (TCreature *)0x0) {
- pcVar5 = &DAT_080fb720;
-LAB_08083596:
- error(pcVar5);
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar4,&RESULT::typeinfo,0);
- }
- if (Param1 == (char *)0x0) {
- pcVar5 = &DAT_080fb6e0;
- goto LAB_08083596;
- }
- if (cr->Type != PLAYER) {
- pcVar5 = "CreateThing: Zauberspruch kann nur von Spielern angewendet werden.\n";
- goto LAB_08083596;
- }
- // try { // try from 080832a7 to 080835c4 has its CatchHandler @ 080835d7
- bVar1 = CheckRight(cr->ID,CREATE_OBJECTS);
- if (!bVar1) {
- return;
- }
- ObjectType::setTypeID(&local_2c,0);
- local_60 = 1;
- iVar3 = __strtol_internal(Param1,0,10,0);
- if (iVar3 == 0) {
- GetObjectTypeByName((char *)local_4c,SUB41(Param1,0));
- }
- else {
- iVar3 = __strtol_internal(Param1,0,10,0);
- bVar1 = false;
- ObjectType::setTypeID(local_3c,99);
- if ((local_3c[0].TypeID < iVar3) && (bVar2 = ObjectTypeExists(iVar3), bVar2)) {
- bVar1 = true;
- }
- if (bVar1) {
- ObjectType::setTypeID((ObjectType *)&Count,iVar3);
- ObjectType::setTypeID(&local_2c,Count);
- ObjectType::setTypeID((ObjectType *)local_4c,local_2c.TypeID);
- }
- bVar1 = ObjectType::getFlag(&local_2c,UNMOVE);
- if (!bVar1) goto LAB_08083369;
- ObjectType::setTypeID((ObjectType *)local_4c,0);
- }
- ObjectType::setTypeID(&local_2c,local_4c[0].ObjectID);
- ObjectType::setTypeID((ObjectType *)&Count,local_2c.TypeID);
-LAB_08083369:
- ObjectType::setTypeID((ObjectType *)&Count,0);
- if (local_2c.TypeID == Count) {
- Connection = cr->Connection;
- pcVar5 = "There is no such takeable object.";
- }
- else {
- if (Param2 != (char *)0x0) {
- local_60 = __strtol_internal(Param2,0,10,0);
- }
- if (local_60 - 1U < 100) {
- bVar1 = ObjectType::getFlag(&local_2c,TAKE);
- if ((bVar1) || (local_60 == 1)) {
- local_4c[0].ObjectID = (cr->CrObject).ObjectID;
- GetMapContainer((Object *)&Count);
- bVar1 = ObjectType::getFlag(&local_2c,CUMULATIVE);
- if (bVar1) {
- ObjectType::setTypeID(local_3c,local_2c.TypeID);
- CreateAtCreature((ulong)local_4c,(ObjectType *)cr->ID,(ulong)local_3c);
- }
- else {
- iVar3 = 0;
- if (0 < local_60) {
- do {
- ObjectType::setTypeID(local_3c,local_2c.TypeID);
- CreateAtCreature((ulong)local_4c,(ObjectType *)cr->ID,(ulong)local_3c);
- iVar3 = iVar3 + 1;
- } while (iVar3 < local_60);
- }
- }
- local_4c[0].ObjectID = Count;
- GraphicalEffect(local_4c,0xf);
- return;
- }
- Connection = cr->Connection;
- pcVar5 = "You may only create one untakeable object.";
- }
- else {
- Connection = cr->Connection;
- pcVar5 = "You may only create 1 to 100 objects.";
- }
- }
- SendMessage(Connection,0x17,pcVar5);
- return;
-}
-
-
-
-void CreateMoney(TCreature *cr,char *Param)
-
-{
- bool bVar1;
- int iVar2;
- undefined4 *puVar3;
- char *Text;
- Object local_4c [4];
- ulong local_3c [4];
- Object local_2c;
- Object Con;
-
- if (cr == (TCreature *)0x0) {
- Text = &DAT_080fb840;
- }
- else if (Param == (char *)0x0) {
- Text = &DAT_080fb800;
- }
- else {
- if (cr->Type == PLAYER) {
- // try { // try from 08083634 to 08083816 has its CatchHandler @ 08083830
- bVar1 = CheckRight(cr->ID,CREATE_MONEY);
- if (bVar1) {
- iVar2 = __strtol_internal(Param,0,10,0);
- if (iVar2 - 1U < 1000000) {
- local_3c[0] = (cr->CrObject).ObjectID;
- GetMapContainer(&local_2c);
- if (0 < iVar2 / 10000) {
- GetSpecialObject((SPECIALMEANING)local_4c);
- CreateAtCreature((ulong)local_3c,(ObjectType *)cr->ID,(ulong)local_4c);
- }
- if (0 < (iVar2 % 10000) / 100) {
- GetSpecialObject((SPECIALMEANING)local_3c);
- CreateAtCreature((ulong)local_4c,(ObjectType *)cr->ID,(ulong)local_3c);
- }
- if (0 < iVar2 % 100) {
- GetSpecialObject((SPECIALMEANING)local_3c);
- CreateAtCreature((ulong)local_4c,(ObjectType *)cr->ID,(ulong)local_3c);
- }
- local_4c[0].ObjectID = local_2c.ObjectID;
- GraphicalEffect(local_4c,0xf);
- }
- else {
- SendMessage(cr->Connection,0x17,"You may only create 1 to 1,000,000 gold.");
- }
- }
- return;
- }
- Text = "CreateMoney: Zauberspruch kann nur von Spieler angewendet werden.\n";
- }
- error(Text);
- 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 CreateFood(void)
-
-{
- int iVar1;
- int iVar2;
- ObjectType *this;
- undefined4 *puVar3;
- int i;
- int iVar4;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- uchar Number;
- int max;
- ObjectType local_3c [4];
- ObjectType local_2c;
- ObjectType Type;
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- error(&DAT_080fb880);
- puVar3 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar3 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar3,&RESULT::typeinfo,0);
- }
- // try { // try from 08083883 to 08083a64 has its CatchHandler @ 08083a65
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- iVar1 = rand();
- iVar1 = iVar1 % 2 + 1;
- iVar4 = 0;
- if (0 < iVar1) {
- do {
- ObjectType::setTypeID(&local_2c,0);
- iVar2 = rand();
- switch(iVar2 % 7) {
- case 0:
- GetNewObjectType((uchar)&max,0x86);
- ObjectType::setTypeID(&local_2c,max);
- this = local_3c;
- goto LAB_0808392c;
- case 1:
- goto LAB_080839b1;
- case 2:
- Number = 0x88;
- break;
- case 3:
-LAB_080839b1:
- Number = 0x82;
- break;
- case 4:
- goto LAB_08083a09;
- case 5:
-LAB_08083a09:
- Number = 0x83;
- break;
- case 6:
- Number = 0x86;
- break;
- default:
- goto switchD_080838ee_default;
- }
- GetNewObjectType((uchar)local_3c,Number);
- ObjectType::setTypeID(&local_2c,local_3c[0].TypeID);
- this = (ObjectType *)&max;
-LAB_0808392c:
- ObjectType::setTypeID(this,local_2c.TypeID);
-switchD_080838ee_default:
- ObjectType::setTypeID(local_3c,local_2c.TypeID);
- CreateAtCreature((ulong)&max,(ObjectType *)in_stack_00000004->ID,(ulong)local_3c);
- iVar4 = iVar4 + 1;
- } while (iVar4 < iVar1);
- }
- max = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect((Object *)&max,0xf);
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void CreateArrows(void)
-
-{
- undefined4 *puVar1;
- TCreature *in_stack_00000004;
- int in_stack_00000008;
- int in_stack_0000000c;
- undefined4 in_stack_00000010;
- Object *this;
- Object local_4c [4];
- Object local_3c [4];
- ObjectType local_2c;
- ObjectType Type;
-
- if (in_stack_00000004 == (TCreature *)0x0) {
- error(&DAT_080fb900);
-LAB_08083bee:
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = 0xffffffff;
- // WARNING: Subroutine does not return
- __cxa_throw(puVar1,&RESULT::typeinfo,0);
- }
- // try { // try from 08083ab6 to 08083c23 has its CatchHandler @ 08083c26
- CheckMana(in_stack_00000004,in_stack_00000008,in_stack_0000000c,1000);
- ObjectType::setTypeID(&local_2c,0);
- switch(in_stack_00000010) {
- case 0:
- GetNewObjectType((uchar)local_4c,'^');
- ObjectType::setTypeID(&local_2c,local_4c[0].ObjectID);
- this = local_3c;
- goto LAB_08083b18;
- case 1:
- break;
- case 2:
- break;
- case 3:
- break;
- case 4:
- break;
- default:
- error(&DAT_080fb8c0);
- goto LAB_08083bee;
- }
- GetNewObjectType((uchar)local_3c,'^');
- ObjectType::setTypeID(&local_2c,local_3c[0].ObjectID);
- this = local_4c;
-LAB_08083b18:
- ObjectType::setTypeID((ObjectType *)this,local_2c.TypeID);
- ObjectType::setTypeID((ObjectType *)local_3c,local_2c.TypeID);
- CreateAtCreature((ulong)local_4c,(ObjectType *)in_stack_00000004->ID,(ulong)local_3c);
- local_4c[0].ObjectID = (in_stack_00000004->CrObject).ObjectID;
- GraphicalEffect(local_4c,0xd);
- return;
-}
-
-
-
void SummonCreature(TCreature *cr,int Mana,int Race,bool God)
{
diff --git a/src/magic.cc b/src/magic.cc
index 170a8d8..dc91695 100644
--- a/src/magic.cc
+++ b/src/magic.cc
@@ -1356,13 +1356,7 @@ void Teleport(TCreature *Actor, char *Param){
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;
+ uint16 HouseID = HOUSEID_ANY;
int MDGoStrength = Actor->Skills[SKILL_GO_STRENGTH]->MDAct;
if(stricmp(Param, "up") == 0){
@@ -1420,7 +1414,8 @@ void Teleport(TCreature *Actor, char *Param){
DestX = ParamX;
DestY = ParamY;
DestZ = ParamZ;
- // TODO(fusion): Not sure why we do this here.
+ // TODO(fusion): Not sure why we do this here. Maybe `TELEPORT_TO_MARK`
+ // was also assigned to a couple of non GM characters?
HouseID = GetHouseID(DestX, DestY, DestZ);
}else{
SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE, "There is no mark of this name.");
@@ -1547,6 +1542,257 @@ void TeleportPlayerToMe(TCreature *Actor, const char *Name){
GraphicalEffect(DestX, DestY, DestZ, EFFECT_TELEPORT);
}
+void MagicRope(TCreature *Actor, int ManaPoints, int SoulPoints){
+ if(Actor == NULL){
+ error("MagicRope: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ int OrigX = Actor->posx;
+ int OrigY = Actor->posy;
+ int OrigZ = Actor->posz;
+ if(!CoordinateFlag(OrigX, OrigY, OrigZ, ROPESPOT)){
+ throw NOTACCESSIBLE;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ Object Dest = GetMapContainer(OrigX, OrigY + 1, OrigZ - 1);
+ Move(0, Actor->CrObject, Dest, -1, false, NONE);
+ GraphicalEffect(OrigX, OrigY, OrigZ, EFFECT_TELEPORT);
+}
+
+void MagicClimbing(TCreature *Actor, int ManaPoints, int SoulPoints, const char *Param){
+ if(Actor == NULL){
+ error("MagicClimbing: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Param == NULL){
+ error("MagicClimbing: Ungültige Richtung übergeben.\n");
+ throw ERROR;
+ }
+
+ int OrigX = Actor->posx;
+ int OrigY = Actor->posy;
+ int OrigZ = Actor->posz;
+
+ // TODO(fusion): This is probably an inlined function `TCreature::GetForwardPosition`.
+ int DestX = OrigX;
+ int DestY = OrigY;
+ int DestZ = OrigZ;
+ switch(Actor->Direction){
+ case DIRECTION_NORTH: DestY -= 1; break;
+ case DIRECTION_EAST: DestX += 1; break;
+ case DIRECTION_SOUTH: DestY += 1; break;
+ case DIRECTION_WEST: DestX -= 1; break;
+ }
+
+ if(stricmp(Param, "up") == 0){
+ if(OrigZ > 0 && !CoordinateFlag(OrigX, OrigY, OrigZ - 1, BANK)
+ && !CoordinateFlag(OrigX, OrigY, OrigZ - 1, UNPASS)
+ && Actor->MovePossible(DestX, DestY, OrigZ - 1, true, true)){
+ DestZ -= 1;
+ }
+ }else if(stricmp(Param, "down") == 0){
+ if(OrigZ < 15 && !CoordinateFlag(DestX, DestY, OrigZ, BANK)
+ && !CoordinateFlag(DestX, DestY, OrigZ, UNPASS)
+ && Actor->MovePossible(DestX, DestY, OrigZ + 1, true, true)){
+ DestZ += 1;
+ }
+ }
+
+ if(DestZ == OrigZ){
+ throw NOTACCESSIBLE;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ Object Dest = GetMapContainer(DestX, DestY, DestZ);
+ Move(0, Actor->CrObject, Dest, -1, false, NONE);
+ GraphicalEffect(OrigX, OrigY, OrigZ, EFFECT_TELEPORT);
+}
+
+void MagicClimbing(TCreature *Actor, const char *Param){
+ // TODO(fusion): I think this is a version used by GM characters.
+ if(Actor == NULL){
+ error("MagicClimbing: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Param == NULL){
+ error("MagicClimbing: Ungültige Richtung übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("MagicClimbing: Zauberspruch kann nur von Spielern angewendet werden.\n");
+ throw ERROR;
+ }
+
+ if(CheckRight(Actor->ID, LEVITATE)){
+ MagicClimbing(Actor, 0, 0, Param);
+ }
+}
+
+void CreateThing(TCreature *Actor, const char *Param1, const char *Param2){
+ if(Actor == NULL){
+ error("CreateThing: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Param1 == NULL){
+ error("CreateThing: Ungültiger Parameter \"Param1\".\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("CreateThing: Zauberspruch kann nur von Spielern angewendet werden.\n");
+ throw ERROR;
+ }
+
+ if(!CheckRight(Actor->ID, CREATE_OBJECTS)){
+ return;
+ }
+
+ int TypeID = atoi(Param1);
+ if(TypeID != 0){
+ if(TypeID < 100 || !ObjectTypeExists(TypeID)
+ || ObjectType(TypeID).getFlag(UNMOVE)){
+ TypeID = 0;
+ }
+ }else{
+ TypeID = GetObjectTypeByName(Param1, true).TypeID;
+ }
+
+ if(TypeID == 0){
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE,
+ "There is no such takeable object.");
+ return;
+ }
+
+ int Count = (Param2 != NULL ? atoi(Param2) : 1);
+ if(Count < 1 || Count > 100){
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE,
+ "You may only create 1 to 100 objects.");
+ return;
+ }
+
+ ObjectType ObjType(TypeID);
+ if(!ObjType.getFlag(TAKE) && Count > 0){
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE,
+ "You may only create one untakeable object.");
+ return;
+ }
+
+ if(!ObjType.getFlag(CUMULATIVE)){
+ for(int i = 0; i < Count; i += 1){
+ CreateAtCreature(Actor->ID, ObjType, 1);
+ }
+ }else{
+ CreateAtCreature(Actor->ID, ObjType, Count);
+ }
+
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_GREEN);
+}
+
+void CreateMoney(TCreature *Actor, const char *Param){
+ if(Actor == NULL){
+ error("CreateMoney: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ if(Param == NULL){
+ error("CreateMoney: Ungültiger Parameter \"Param1\".\n");
+ throw ERROR;
+ }
+
+ if(Actor->Type != PLAYER){
+ error("CreateMoney: Zauberspruch kann nur von Spieler angewendet werden.\n");
+ throw ERROR;
+ }
+
+ if(!CheckRight(Actor->ID, CREATE_MONEY)){
+ return;
+ }
+
+ int Amount = atoi(Param);
+ if(Amount < 1 || Amount > 1000000){
+ SendMessage(Actor->Connection, TALK_FAILURE_MESSAGE,
+ "You may only create 1 to 1,000,000 gold.");
+ }
+
+ int Crystal = (Amount / 10000);
+ int Platinum = (Amount % 10000) / 100;
+ int Gold = (Amount % 10000) % 100;
+
+ if(Crystal > 0){
+ CreateAtCreature(Actor->ID, GetSpecialObject(MONEY_TENTHOUSAND), Crystal);
+ }
+
+ if(Platinum > 0){
+ CreateAtCreature(Actor->ID, GetSpecialObject(MONEY_HUNDRED), Platinum);
+ }
+
+ if(Gold > 0){
+ CreateAtCreature(Actor->ID, GetSpecialObject(MONEY_ONE), Gold);
+ }
+
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_GREEN);
+}
+
+void CreateFood(TCreature *Actor, int ManaPoints, int SoulPoints){
+ if(Actor == NULL){
+ error("CreateFood: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ int Count = (rand() % 2) + 1;
+ for(int i = 0; i < Count; i += 1){
+ uint8 Group, Number;
+ switch(rand() % 7){
+ case 0: Group = 134; Number = 0; break;
+ case 1: Group = 130; Number = 2; break;
+ case 2: Group = 136; Number = 0; break;
+ case 3: Group = 130; Number = 13; break;
+ 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);
+ }
+
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_GREEN);
+}
+
+void CreateArrows(TCreature *Actor, int ManaPoints, int SoulPoints, int ArrowType, int Count){
+ if(Actor == NULL){
+ error("CreateArrows: Ungültige Kreatur übergeben.\n");
+ throw ERROR;
+ }
+
+ CheckMana(Actor, ManaPoints, SoulPoints, 1000);
+
+ uint8 Number;
+ switch(ArrowType){
+ case 0: Number = 1; break;
+ case 1: Number = 2; break;
+ case 2: Number = 3; break;
+ case 3: Number = 0; break;
+ case 4: Number = 4; break;
+ default:{
+ error("CreateArrows: Ungültiger Pfeiltyp %d.\n", ArrowType);
+ throw ERROR;
+ }
+ }
+
+ CreateAtCreature(Actor->ID, GetNewObjectType(94, Number), Count);
+ GraphicalEffect(Actor->posx, Actor->posy, Actor->posz, EFFECT_MAGIC_BLUE);
+}
+
// Magic Init Functions
// =============================================================================
static void InitCircles(void){
diff --git a/src/stubs.hh b/src/stubs.hh
index 7b10798..4157c61 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -27,6 +27,7 @@ extern void CircleShapeSpell(TCreature *Actor, int DestX, int DestY, int DestZ,
extern void CleanHouseField(int x, int y, int z);
extern int ComputeDamage(TCreature *Creature, int SpellNr, int Damage, int Variation);
extern int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value);
+extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value);
extern void CreateField(int x, int y, int z, int FieldType, uint32 Owner, bool Peaceful);
extern void CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect);
extern void CreatePlayerList(bool Online);