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:
still in tile.h, after:
still in tile.h, after:
still in tile.h, after:
now in tile.cpp, after:
still in tile.cpp, after:
now in creature.cpp, in void Creature::die, after:
still in game.cpp, immediately after:
still in game.cpp, after:
now in player.cpp, replace:
now in otserv.cpp, after:
now, create two new files in the project, one named pvparena.h, the other names pvparena.cpp.
paste the following into pvparena.h:
and paste the following into pvparena.cpp:
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:
4a) To create a new arena, create a tag like this:
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
before the /> in the tag above.
4c) To disallow fielding in this arena, just add
before the /> in the tag above.
4d) To allow more than two combatants in this arena, just add
before the /> in the tag above.
4e) To set the arena tiles, create a tag like this:
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.
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:
paste:class Creature;
class Teleport;
class TrashHolder;
class Mailbox;
class MagicField;
Code:
#ifdef __PVP_ARENA__
#include "pvparena.h"
class PvPArena;
#endif //__PVP_ARENA__
still in tile.h, after:
paste:#ifdef __COMBAT_ZONES__
, TILESTATE_NOPVP = 256,
TILESTATE_PVP = 512,
TILESTATE_PVP_ENFORCED = 1024,
Code:
#ifdef __PVP_ARENA__
TILESTATE_NOSKULLS = 2048,
#endif //__PVP_ARENA__
still in tile.h, after:
paste:flags = 0;
ground = NULL;
Code:
#ifdef __PVP_ARENA__
pvparena = NULL;
#endif //__PVP_ARENA__
still in tile.h, after:
paste:Item* ground;
ItemVector topItems;
CreatureVector creatures;
ItemVector downItems;
Code:
#ifdef __PVP_ARENA__
PvPArena* pvparena;
#endif //__PVP_ARENA__
now in tile.cpp, after:
paste:ReturnValue Tile::__queryAdd(int32_t index, const Thing* thing, uint32_t count,
uint32_t flags) const
{
Code:
#ifdef __PVP_ARENA__
if(pvparena)
{
if(!pvparena->canAdd(thing))
return RET_NOTPOSSIBLE;
}
#endif //__PVP_ARENA__
still in tile.cpp, after:
paste:void Tile::__addThing(int32_t index, Thing* thing)
{
Creature* creature = thing->getCreature();
if(creature){
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:
paste:Tile* tile = getTile();
if(splash){
internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
startDecay(splash);
}
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:
paste:void Game::changeSkull(Player* player, Skulls_t newSkull)
{
Code:
#ifdef __PVP_ARENA__
if(player->getTile()->hasFlag(TILESTATE_NOSKULLS))
return;
#endif //__PVP_ARENA__
still in game.cpp, after:
add://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();
Code:
#ifdef __PVP_ARENA__
if(PvPArena* pvparena = creature->getTile()->pvparena)
{
pvparena->addCreature(creature, true);
}
#endif //__PVP_ARENA__
now in player.cpp, replace:
with:if(!targetPlayer->hasAttacked(this) && targetPlayer->getSkull() == SKULL_NONE){
Code:
if(!targetPlayer->hasAttacked(this) && targetPlayer->getSkull() == SKULL_NONE
#ifdef __PVP_ARENA__
&& !getTile()->hasFlag(TILESTATE_NOSKULLS)
#endif //__PVP_ARENA__
){
now in otserv.cpp, after:
paste:#ifdef __COMBAT_ZONES__
if(g_game.loadCombatZones())
puts(":: Loaded Combat Zones!");
#endif //__COMBAT_ZONES__
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" />
4b) To disallow summons in this arena, just add
Code:
allowsummons="no"
4c) To disallow fielding in this arena, just add
Code:
allowfields="no"
4d) To allow more than two combatants in this arena, just add
Code:
multi-combat="yes"
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" />
Last edited: