• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • New resources must be posted under Resources tab. A discussion thread will be created automatically, you can't open threads manually anymore.

Advanced PvP Arena (w/ recent bugfix)

Vagabond

New Member
Joined
Oct 5, 2007
Messages
242
Reaction score
0
Note1: this is dependant on my Combat Zoning code! (for ease and efficiency)
Note2: this has a very recent bugfix (about a month old). Those of you who experienced debugs around pvp arenas with the old version of the code (such as that in evolutions) should not experience them with this code.

Now, to the code.


First, in tile.h, before:
class Creature;
class Teleport;
class TrashHolder;
class Mailbox;
class MagicField;
paste:
Code:
#ifdef __PVP_ARENA__
#include "pvparena.h"
class PvPArena;
#endif //__PVP_ARENA__


still in tile.h, after:
#ifdef __COMBAT_ZONES__
, TILESTATE_NOPVP = 256,
TILESTATE_PVP = 512,
TILESTATE_PVP_ENFORCED = 1024,
paste:
Code:
#ifdef __PVP_ARENA__
	TILESTATE_NOSKULLS = 2048,
	#endif //__PVP_ARENA__


still in tile.h, after:
flags = 0;
ground = NULL;
paste:
Code:
#ifdef __PVP_ARENA__
		pvparena = NULL;
		#endif //__PVP_ARENA__


still in tile.h, after:
Item* ground;
ItemVector topItems;
CreatureVector creatures;
ItemVector downItems;
paste:
Code:
#ifdef __PVP_ARENA__
	PvPArena* pvparena;
	#endif //__PVP_ARENA__


now in tile.cpp, after:
ReturnValue Tile::__queryAdd(int32_t index, const Thing* thing, uint32_t count,
uint32_t flags) const
{
paste:
Code:
#ifdef __PVP_ARENA__
	if(pvparena)
	{
	    if(!pvparena->canAdd(thing))
	        return RET_NOTPOSSIBLE;
    }
	#endif //__PVP_ARENA__


still in tile.cpp, after:
void Tile::__addThing(int32_t index, Thing* thing)
{
Creature* creature = thing->getCreature();
if(creature){
paste:
Code:
#ifdef __PVP_ARENA__
        if(pvparena != creature->getParent()->getTile()->pvparena)
		{
		   if(pvparena)
		       pvparena->addCreature(creature);
           if(PvPArena* p = creature->getParent()->getTile()->pvparena)
               p->removeCreature(creature, false);
        }
		#endif //__PVP_ARENA__



now in creature.cpp, in void Creature::die, after:
Tile* tile = getTile();
if(splash){
internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
startDecay(splash);
}
paste:
Code:
#ifdef __PVP_ARENA__
			if(tile->pvparena)
			{
                 tile->pvparena->removeCreature(this, true);
                 if(hasMaster())
                      getMaster()->removeSummon(this);
                 return;
            }
			#endif //__PVP_ARENA__



still in game.cpp, immediately after:
void Game::changeSkull(Player* player, Skulls_t newSkull)
{
paste:
Code:
#ifdef __PVP_ARENA__
    if(player->getTile()->hasFlag(TILESTATE_NOSKULLS))
        return;
    #endif //__PVP_ARENA__

still in game.cpp, after:
//send to client
Player* tmpPlayer = NULL;
for(it = list.begin(); it != list.end(); ++it) {
if((tmpPlayer = (*it)->getPlayer())){
tmpPlayer->sendCreatureAppear(creature, true);
}
}

//event method
for(it = list.begin(); it != list.end(); ++it) {
(*it)->onCreatureAppear(creature, true);
}

int32_t newStackPos = creature->getParent()->__getIndexOfThing(creature);
creature->getParent()->postAddNotification(creature, newStackPos);

creature->addEventThink();
add:
Code:
#ifdef __PVP_ARENA__
	if(PvPArena* pvparena = creature->getTile()->pvparena)
	{
        pvparena->addCreature(creature, true);
    }
	#endif //__PVP_ARENA__


now in player.cpp, replace:
if(!targetPlayer->hasAttacked(this) && targetPlayer->getSkull() == SKULL_NONE){
with:
Code:
if(!targetPlayer->hasAttacked(this) && targetPlayer->getSkull() == SKULL_NONE
            #ifdef __PVP_ARENA__
            && !getTile()->hasFlag(TILESTATE_NOSKULLS)
            #endif //__PVP_ARENA__
            ){


now in otserv.cpp, after:
#ifdef __COMBAT_ZONES__
if(g_game.loadCombatZones())
puts(":: Loaded Combat Zones!");
#endif //__COMBAT_ZONES__
paste:
Code:
#ifdef __PVP_ARENA__
    if(PvPArena::loadArenas())
	    puts(":: Loaded PvP Arenas!");
    #endif //__PVP_ARENA__

now, create two new files in the project, one named pvparena.h, the other names pvparena.cpp.
paste the following into pvparena.h:
Code:
#ifdef __PVP_ARENA__
#ifndef __PVP_ARENA_H__
#define __PVP_ARENA_H__


#include "tile.h"
#include "position.h"
#include <list>

enum PvPArenaFlags_t
{
     ARENA_FLAG_NONE = 0,
     ARENA_FLAG_NOSUMMONS = 2,
     ARENA_FLAG_MULTICOMBAT = 4,
     ARENA_FLAG_NO_FIELDS = 8,
};
     

class PvPArena
{
    public:
       PvPArena();
       ~PvPArena();
       
       int flags;
       
       Position exitPos;
       
       virtual bool canAdd(const Thing*);
       std::list<Creature*> arenaMembers;
       
       static bool loadArenas();
       
       void removeCreature(Creature* cr,  bool death = false);
       void addCreature(Creature* cr, bool isLogin = false);
};

#endif //__PVP_ARENA_H__
#endif //__PVP_ARENA__

and paste the following into pvparena.cpp:
Code:
#ifdef __PVP_ARENA__

#include "pvparena.h"
#include "player.h"
#include "configmanager.h"
extern ConfigManager g_config;

#include "game.h"
extern Game g_game;

#include "tools.h"
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

PvPArena::PvPArena()
{
    exitPos = Position(0, 0, 7);
    flags = 0;
    arenaMembers.clear();
}

PvPArena::~PvPArena()
{
    arenaMembers.clear();
}

bool PvPArena::canAdd(const Thing* thing)
{
    if(!thing)
         return false;
    
    if(const Creature* creature = thing->getCreature())
    {
         if(!creature->isAttackable())
              return true;
         if(flags & ARENA_FLAG_NOSUMMONS && creature->getMonster() != NULL)
              return false;
         else if(!(flags & ARENA_FLAG_MULTICOMBAT) && arenaMembers.size() > 2 && creature->getPlayer())
         {
              std::list<Creature*>::iterator cit = std::find(arenaMembers.begin(), arenaMembers.end(), creature);
              if(cit == arenaMembers.end())
                  return false;
         }
    }
    else if(const Item* item = thing->getItem())
    {
         if(!(flags & ARENA_FLAG_NO_FIELDS) && item->isMagicField())
              return false;
    }
    return true;
}


bool PvPArena::loadArenas()
{
     //system("PAUSE");
     std::string filename = g_config.getString(ConfigManager::DATA_DIRECTORY) + "pvparenas.xml";
     xmlDocPtr doc = xmlParseFile(filename.c_str());
     if(!doc)
         return false;
     
     xmlNodePtr root, arenanode, tilenode;
     root = xmlDocGetRootElement(doc);
	 if(xmlStrcmp(root->name,(const xmlChar*)"pvparenas") != 0){
		xmlFreeDoc(doc);
		return false;
	 }
	 
	 arenanode = root->children;
	 while (arenanode){
         if(xmlStrcmp(arenanode->name,(const xmlChar*)"pvparena") == 0)
         {
             PvPArena* newArena = new PvPArena();
             int x, y, z;
             if(readXMLInteger(arenanode,"exitx",x) && 
                readXMLInteger(arenanode,"exity",y) && 
                readXMLInteger(arenanode,"exitz",z))
              {
                  newArena->exitPos = Position(x, y, z);
              }
              else
              {
                  puts("ERROR: Missing/incomplete exit pos for pvparena! Skipping...");
                  delete newArena;
                  arenanode = arenanode->next;
                  continue;
              }
              std::string strValue;
              int intValue;
              if(readXMLString(arenanode,"allowsummons",strValue) && strValue == "no")
                  newArena->flags |= ARENA_FLAG_NOSUMMONS;
              if(readXMLString(arenanode,"multi-combat",strValue) && strValue == "yes")
                  newArena->flags |= ARENA_FLAG_MULTICOMBAT;
              if(readXMLString(arenanode,"allowfields",strValue) && strValue == "no")
                  newArena->flags |= ARENA_FLAG_NO_FIELDS;
              tilenode = arenanode->children;
              while(tilenode)
              {
                  if(xmlStrcmp(tilenode->name,(const xmlChar*)"tiles") == 0)
                  {
                       int tox, toy, toz;
                       int fromx, fromy, fromz;
                       if(readXMLInteger(tilenode,"tox",tox) &&
                          readXMLInteger(tilenode,"toy",toy) &&
                          readXMLInteger(tilenode,"toz",toz) &&
                          readXMLInteger(tilenode,"fromx",fromx) &&
                          readXMLInteger(tilenode,"fromy",fromy) &&
                          readXMLInteger(tilenode,"fromz",fromz))
                        {
                            if(tox < fromx)
                               std::swap(tox, fromx);
                            if(toy < fromy)
                               std::swap(toy, fromy);
                            if(toz < fromz)
                               std::swap(toz, fromz);
                            for(int dx = fromx; dx <= tox; dx++)
                            {
                               for(int dy = fromy; dy <= toy; dy++)
                               {
                                   for(int dz = fromz; dz <= toz; dz++)
                                   {
                                       if(Tile* t = g_game.getTile(dx, dy, dz))
                                       {
                                            t->pvparena = newArena;
                                            t->setFlag(TILESTATE_PVP);
                                            t->setFlag(TILESTATE_NOSKULLS);
                                       }
                                   }
                               }
                            }
                        }
                        else
                            puts("ERROR: incomplete tile range! Skipping...");
                  }
                  tilenode = tilenode->next;
              }
         }
         arenanode = arenanode->next;
     }
     xmlFreeDoc(doc);
     return true;
	 
}

void PvPArena::removeCreature(Creature* cr, bool death)
{
     if(!cr)
        return;
     if(!cr->isAttackable())
        return;
     
     std::list<Creature*>::iterator cit = std::find(arenaMembers.begin(), arenaMembers.end(), cr);
     if(cit != arenaMembers.end())
         arenaMembers.erase(cit);
     if(death)
     {
         if(Player* pr = cr->getPlayer())
         {
              if(g_game.internalTeleport(cr, exitPos) == RET_NOERROR)
                   g_game.addMagicEffect(exitPos, NM_ME_ENERGY_AREA);
              pr->changeHealth(pr->getMaxHealth());
         }
         else
         {
              g_game.removeCreature(cr);
         }
     }
}

void PvPArena::addCreature(Creature* cr, bool isLogin)
{
     if(!cr)
          return;
     if(!cr->isAttackable())
          return;
     // cant login on a pvp arena
     if(isLogin && cr->getPlayer())
     {
          if(g_game.internalTeleport(cr, cr->getMasterPos()) == RET_NOERROR)
          {
              g_game.addMagicEffect(cr->getMasterPos(), NM_ME_ENERGY_AREA);
              return;
          }
     }
     arenaMembers.push_back(cr);
}


#endif //__PVP_ARENA__



now add -D__PVP_ARENA__ to C++ compiler in project options and rebuild all.



======================================================
Usage
======================================================
1) First, create a new file in your DATA directory named pvparenas.xml. (copy and rename a current xml file if you wish)


2) Open this file and clean its contents (if it has any).


3) paste this:
Code:
<pvparenas>
	<!-- pvp arena tag here -->
</pvparenas>


4a) To create a new arena, create a tag like this:
Code:
<pvparena exitx="x" exity="y" exitz="z" />
Replace x, y, and z with the coordinates where you want players teleported to when they lose.

4b) To disallow summons in this arena, just add
Code:
allowsummons="no"
before the /> in the tag above.

4c) To disallow fielding in this arena, just add
Code:
allowfields="no"
before the /> in the tag above.

4d) To allow more than two combatants in this arena, just add
Code:
multi-combat="yes"
before the /> in the tag above.

4e) To set the arena tiles, create a tag like this:
Code:
<tiles fromx="x1" fromy="y1" fromz="z1" tox="x2" toy="y2" toz="z2" />
Replace x1, y1, and z1 with the coordinates of the northwest-most tile on the lowest floor. Replace x2, y2, and z2 with the coordinates of the southeast-most tile on the highest floor.
 
Last edited:
I think its possible to make it all on creaturescripts. There was already in TFS PvP Arena, but Talaturen removed it becouse of bugs. But its not good idea i think, to add it in sources, when its possible to make in lua. ;)
 
It's possible to make it in scripts.. but it won't function perfectly.
For example, you'll still get skulls on a pvp world, it won't even work on a no-pvp world, and you'll get exp for killing on a pvp-e world.

Besides, that's a flawed concept. It's true that having as much externiality as possible is good, but machine code executes much faster than interpreted bytecode. If you have a sourcecoded alternative and the means to add it, you're better off using it. (Unless the coder sucks)
 
Ok, i think about adding this. But will it work 100% propertly on TFS? Withour errors and crahs? - its very important for me, becouse now i have 0 crashes on my TFS. And Forgotten haven't auto save function, so sometimes when is crash its doesn't save players.
 
Ok, i think about adding this. But will it work 100% propertly on TFS? Withour errors and crahs? - its very important for me, becouse now i have 0 crashes on my TFS. And Forgotten haven't auto save function, so sometimes when is crash its doesn't save players.

I suggest you try it on another server before using it on your own. :p
 
Yes i will try before :d

But i have next question. Will be work propertly PvP from level (protectionLevel)?
 
It won't work in PZ, no.
And if you have a protection code, it'll probably make this not work. It wasn't made with any protection code in mind. You'll need to edit your protection code appropriately.
 
=\

Impossible to add to Forgotten Server.

I' just waiting now when Talaturen will relase stable version with working PvP Arena, and meybe PvP Zones? ;)
 
Impossible? I was looking at TFS' SVN earlier and didn't like they changed much of the code you need to edit. :s
 
Ok, 2 step:

still in tile.h, after:

Code:
#ifdef __COMBAT_ZONES__
, TILESTATE_NOPVP = 4,
TILESTATE_PVP = 8,
TILESTATE_PVP_ENFORCED = 16,

But i haven't this. ;/
 
You gotta add my pvp zones code first. I even said so at the top of my post.
 
../creature.cpp: In member function `virtual void Creature::eek:nDeath()':
../creature.cpp:468: error: `creature' undeclared (first use this function)
../creature.cpp:468: error: (Each undeclared identifier is reported only once for each function it appears in.)

make.exe: *** [../creature.o] Error 1

any ideas?

this the line thats giving that error
tile->pvparena->removeCreature(creature, true);

and i have the pvp zones already
 
Now why didn't you tell me you released this? Hiding shit from me, you bastard!

I'll add it in, unless you want to :p
 
Now why didn't you tell me you released this? Hiding shit from me, you bastard!

I'll add it in, unless you want to :p

I released this on OTRevolution in like February, and it has been a part of Evolutions since a few days later.

@Nosta: Beats the hell out of Yurez's, eh? :p
 
../creature.cpp: In member function `virtual void Creature::eek:nDeath()':
../creature.cpp:468: error: `creature' undeclared (first use this function)
../creature.cpp:468: error: (Each undeclared identifier is reported only once for each function it appears in.)

make.exe: *** [../creature.o] Error 1

any ideas?

this the line thats giving that error
tile->pvparena->removeCreature(creature, true);

and i have the pvp zones already
I have this same problem. :(
 
../creature.cpp: In member function `virtual void Creature::eek:nDeath()':
../creature.cpp:468: error: `creature' undeclared (first use this function)
../creature.cpp:468: error: (Each undeclared identifier is reported only once for each function it appears in.)

make.exe: *** [../creature.o] Error 1

any ideas?

this the line thats giving that error
tile->pvparena->removeCreature(creature, true);

and i have the pvp zones already

Evolutions, maybe? Try not using a shitty outdated distro. :)
 
Try to declarate this function again ;d
Lol, maybe function name is isn't same?
 
Last edited:
i changed line
Code:
tile->pvparena->removeCreature(creature, true);
to
Code:
tile->pvparena->removeCreature(this);
, i have other problem
Code:
 E:\TFS\Source\game.cpp In member function `void Game::changeSkull(Player*, Skulls_t)': 
3375 E:\TFS\Source\game.cpp 'class Tile' has no member named 'hasFlags' 
 E:\TFS\Projekt\Makefile.win [Build Error]  [../Source/game.o] Error 1
 
Back
Top