- Joined
- Aug 29, 2011
- Messages
- 512
- Reaction score
- 33
Someone could add to this muserver a custum that has in Zteam that I find very interesting to bonus players in events.
it's the MonsterSpawner.xml
in Red is define an item that when it is dropped will create a Temporary Spot
in Yellow is defined the monster that will spawn and also the quantity and the duration time.
in Green it is defined if the spot created will be private or not (if it is deprived only those who dropped the item can attack the monsters.
in Blue is defined if the party of whom the item drops will be able to attack.
in Orange is set if the guild of who drops the item will be able to attack.
<monsterspawner>
<!-- example, elite yeti -->
<item type="14" index="300">
<spawn monster="20" count="30" duration="60" />
<!-- rules for use this spot (false: any user can attack, true: only owner & by rules) -->
<private active="true">
<party>true</party>
<guild>false</guild>
</private>
</item>
<!-- example, mutant -->
<item type="14" index="301">
<spawn monster="62" count="30" duration="60" />
<!-- rules for use this spot (false: any user can attack, true: only owner & by rules) -->
<private active="true">
<party>true</party>
<guild>false</guild>
</private>
</item>
<!-- example, fire golem -->
<item type="14" index="302">
<spawn monster="291" count="30" duration="60" />
<!-- rules for use this spot (false: any user can attack, true: only owner & by rules) -->
<private active="true">
<party>true</party>
<guild>false</guild>
</private>
</item>
</monsterspawner>
aqui fica os código que eu pegue da source da Zteam
MonsterSpawner.cpp
MonsterSpawner.h
it's the MonsterSpawner.xml
in Red is define an item that when it is dropped will create a Temporary Spot
in Yellow is defined the monster that will spawn and also the quantity and the duration time.
in Green it is defined if the spot created will be private or not (if it is deprived only those who dropped the item can attack the monsters.
in Blue is defined if the party of whom the item drops will be able to attack.
in Orange is set if the guild of who drops the item will be able to attack.
<monsterspawner>
<!-- example, elite yeti -->
<item type="14" index="300">
<spawn monster="20" count="30" duration="60" />
<!-- rules for use this spot (false: any user can attack, true: only owner & by rules) -->
<private active="true">
<party>true</party>
<guild>false</guild>
</private>
</item>
<!-- example, mutant -->
<item type="14" index="301">
<spawn monster="62" count="30" duration="60" />
<!-- rules for use this spot (false: any user can attack, true: only owner & by rules) -->
<private active="true">
<party>true</party>
<guild>false</guild>
</private>
</item>
<!-- example, fire golem -->
<item type="14" index="302">
<spawn monster="291" count="30" duration="60" />
<!-- rules for use this spot (false: any user can attack, true: only owner & by rules) -->
<private active="true">
<party>true</party>
<guild>false</guild>
</private>
</item>
</monsterspawner>
aqui fica os código que eu pegue da source da Zteam
MonsterSpawner.cpp
PHP:
#include "stdafx.h"
#include "MonsterSpawner.h"
#include "GameMain.h"
#include "..\pugixml\pugixml.hpp"
MonsterSpawnerMng* MonsterSpawnerMng::m_Instance = NULL;
MonsterSpawnerMng::MonsterSpawnerMng() {
m_WorkPool.clear();
//m_ItemData.clear();
}
MonsterSpawnerMng::~MonsterSpawnerMng() {
// lifetime instance...
}
void MonsterSpawnerMng::Load() {
m_Loaded = false;
Init();
Read(gDirPath.GetNewPath(FILE_CUSTOM_MONSTERSPAWNER));
}
void MonsterSpawnerMng::Init() {
m_ItemData.clear();
}
void MonsterSpawnerMng::Read(const char *File) {
using namespace pugi;
xml_document Document;
xml_parse_result Result = Document.load_file(File);
if (Result.status != status_ok) {
MsgBox("[MonsterSpawnerMng] File %s not found!", File);
return;
}
xml_node nodeMain = Document.child("monsterspawner");
for (xml_node nodeIt = nodeMain.child("item"); nodeIt; nodeIt = nodeIt.next_sibling()) {
MonsterSpawnerItemInfo newItem = { 0 };
newItem.itemCategory = nodeIt.attribute("type").as_int(-1);
newItem.itemIndex = nodeIt.attribute("index").as_int(-1);
newItem.spawnMonsterId = nodeIt.child("spawn").attribute("monster").as_int(-1);
newItem.spawnMonsterCount = nodeIt.child("spawn").attribute("count").as_int(-1);
newItem.spawnDuration = nodeIt.child("spawn").attribute("duration").as_int(-1);
newItem.isPrivate = nodeIt.child("private").attribute("active").as_bool();
newItem.isPrivateParty = nodeIt.child("private").child("party").text().as_bool();
newItem.isPrivateGuild = nodeIt.child("private").child("guild").text().as_bool();
m_ItemData.push_back(newItem);
}
LogAddTD("[MonsterSpawnerMng] loaded %d node(s)", m_ItemData.size());
m_Loaded = true;
}
void MonsterSpawnerMng::procRun() {
for (size_t i = 0; i < m_WorkPool.size(); i++) {
if (m_WorkPool[i].isEmpty()) {
continue;
}
if (m_WorkPool[i].isExpired()) {
LogAddTD("[MonsterSpawnerMng] [%s] spot duration is expired, slot cleared",
m_WorkPool[i].ownerName.c_str());
m_WorkPool[i].clearSlot();
}
}
}
void MonsterSpawnerMng::procRegen(short MonsterIndex) {
gObj[MonsterIndex].X = gObj[MonsterIndex].StartX;
gObj[MonsterIndex].Y = gObj[MonsterIndex].StartY;
gObj[MonsterIndex].MTX = gObj[MonsterIndex].X;
gObj[MonsterIndex].MTY = gObj[MonsterIndex].Y;
gObj[MonsterIndex].m_ActState.Emotion = 1;
gObj[MonsterIndex].m_ActState.EmotionCount = 1;
}
bool MonsterSpawnerMng::procCreate(short UserIndex, int ItemCode) {
MonsterSpawnerItemInfo* tmpItemInfo = getItemInfo(ItemCode);
if (tmpItemInfo == NULL) {
return false;
}
int tmpSlotIndex = getEmptySlot();
if (tmpSlotIndex == -1) {
MonsterSpawnerWorkNode newNode;
newNode.setSlot(UserIndex, tmpItemInfo);
m_WorkPool.push_back(newNode);
} else {
m_WorkPool[tmpSlotIndex].setSlot(UserIndex, tmpItemInfo);
}
LogAddTD("[MonsterSpawnerMng] [%s][%s] spot has been created (monster: %d, count: %d, duration: %d, map: %d (%d:%d))",
gObj[UserIndex].AccountID, gObj[UserIndex].Name, tmpItemInfo->spawnMonsterId, tmpItemInfo->spawnMonsterCount,
tmpItemInfo->spawnDuration, gObj[UserIndex].MapNumber, gObj[UserIndex].X, gObj[UserIndex].Y);
return true;
}
bool MonsterSpawnerMng::isPrivate(short UserIndex, short MonsterIndex) {
LPOBJ tmpAttacker = &gObj[UserIndex];
LPOBJ tmpMonster = &gObj[MonsterIndex];
LPOBJ tmpOwner = NULL;
MonsterSpawnerWorkNode* tmpNode = NULL;
MonsterSpawnerItemInfo* tmpItem = NULL;
for (size_t i = 0; i < m_WorkPool.size(); i++) { // select node
if (m_WorkPool[i].isMonster(MonsterIndex)) {
tmpNode = &m_WorkPool[i];
break;
}
}
if (tmpNode == NULL) { // node not founded, spot unblocked
return false;
}
if (tmpNode->isOwner(tmpAttacker->Name)) { // owner
return false;
}
tmpItem = getItemInfo(tmpNode->itemCode);
if (tmpItem == NULL) { // rules for node not founded, spot unblocked
return false;
}
if (!tmpItem->isPrivate) { // spot not privated by rules
return false;
}
for (int i = OBJ_STARTUSERINDEX; i < OBJMAX; i++) { // select live owner
if (gObj[i].Connected >= PLAYER_PLAYING) {
if (tmpNode->isOwner(gObj[i].Name)) {
tmpOwner = &gObj[i];
break;
}
}
}
if (tmpOwner == NULL) { // spot have owner, but owner is offline, cant check rules - block by rules
MsgOutput(UserIndex, "Monster is privated by %s", tmpNode->ownerName.c_str());
return true;
}
if (tmpItem->isPrivateParty && tmpOwner->PartyNumber >= 0) { // spot is not privated for party members
if (tmpOwner->PartyNumber == tmpAttacker->PartyNumber) {
return false;
}
}
if (tmpItem->isPrivateGuild && tmpOwner->GuildNumber > 0) { // spot is not privated for guild members
if (tmpOwner->GuildNumber == tmpAttacker->GuildNumber) {
return false;
}
}
MsgOutput(UserIndex, "Monster is privated by %s", tmpNode->ownerName.c_str());
return true;
}
bool MonsterSpawnerMng::isEventMonster(short MonsterIndex) {
for (size_t i = 0; i < m_WorkPool.size(); i++) {
if (m_WorkPool[i].isMonster(MonsterIndex)) {
return true;
}
}
return false;
}
bool MonsterSpawnerMng::isKeyItem(int ItemCode) {
if (getItemInfo(ItemCode) != NULL) {
return true;
}
return false;
}
int MonsterSpawnerMng::getEmptySlot() {
for (size_t i = 0; i < m_WorkPool.size(); i++) {
if (m_WorkPool[i].isEmpty()) {
return i;
}
}
return -1;
}
MonsterSpawnerItemInfo* MonsterSpawnerMng::getItemInfo(int ItemCode) {
if (!m_Loaded) {
return NULL;
}
for (size_t i = 0; i < m_ItemData.size(); i++) {
if (ITEMGET(m_ItemData[i].itemCategory, m_ItemData[i].itemIndex) == ItemCode) {
return &m_ItemData[i];
}
}
return NULL;
}
MonsterSpawner.h
PHP:
#pragma once
// import
#include "user.h"
// data
struct MonsterSpawnerItemInfo {
short itemIndex;
short itemCategory;
short spawnMonsterId;
short spawnMonsterCount;
short spawnDuration;
bool isPrivate;
bool isPrivateParty;
bool isPrivateGuild;
};
struct MonsterSpawnerWorkNode { // maybe better use class & ptr instance...
MonsterSpawnerWorkNode() {
ownerName.reserve(MAX_ACCOUNT_LEN + 1);
monsterPool.clear();
itemCode = -1;
tickEnd = 0;
}
void setSlot(short UserIndex, MonsterSpawnerItemInfo* itemInfo) {
if (UserIndex < 0 || UserIndex > OBJMAX) {
return;
}
LPOBJ tmpUser = &gObj[UserIndex];
if (tmpUser == NULL) {
return;
}
ownerName.assign(tmpUser->Name);
itemCode = ITEMGET(itemInfo->itemCategory, itemInfo->itemIndex);
tickEnd = GetTickCount() + (itemInfo->spawnDuration * 60 * 1000);
setSpot(UserIndex, itemInfo);
}
void clearSlot() {
ownerName.assign("");
itemCode = -1;
tickEnd = 0;
clearSpot();
monsterPool.clear();
}
void setSpot(short UserIndex, MonsterSpawnerItemInfo* itemInfo) {
if (UserIndex < 0 || UserIndex > OBJMAX) {
return;
}
LPOBJ tmpUser = &gObj[UserIndex];
if (tmpUser == NULL) {
return;
}
for (int i = 0; i < itemInfo->spawnMonsterCount; i++) {
int tmpMonsterIndex = gObjAddMonster(tmpUser->MapNumber);
if (tmpMonsterIndex < 0) {
return;
}
gObj[tmpMonsterIndex].m_PosNum = -1;
gObj[tmpMonsterIndex].X = tmpUser->X + rand() % 2;
gObj[tmpMonsterIndex].Y = tmpUser->Y + rand() % 2;
gObj[tmpMonsterIndex].MapNumber = tmpUser->MapNumber;
gObj[tmpMonsterIndex].TX = gObj[tmpMonsterIndex].X;
gObj[tmpMonsterIndex].TY = gObj[tmpMonsterIndex].Y;
gObj[tmpMonsterIndex].m_OldX = gObj[tmpMonsterIndex].X;
gObj[tmpMonsterIndex].m_OldY = gObj[tmpMonsterIndex].Y;
gObj[tmpMonsterIndex].StartX = gObj[tmpMonsterIndex].X;
gObj[tmpMonsterIndex].StartY = gObj[tmpMonsterIndex].Y;
gObj[tmpMonsterIndex].m_ActState.Emotion = 1;
gObj[tmpMonsterIndex].m_ActState.EmotionCount = 15;
gObj[tmpMonsterIndex].Dir = rand() % 8;
gObjSetMonster(tmpMonsterIndex, itemInfo->spawnMonsterId);
monsterPool.push_back(tmpMonsterIndex);
}
}
void clearSpot() {
for (size_t i = 0; i < monsterPool.size(); i++) {
gObjViewportListProtocolDestroy(&gObj[monsterPool[i]]);
gObjViewportClose(&gObj[monsterPool[i]]);
gObjDel(monsterPool[i]);
gObj[monsterPool[i]].Live = 0;
gObj[monsterPool[i]].DieRegen = 1;
}
}
bool isOwner(char* OwnerName) {
if (ownerName.compare(OwnerName) == NULL) {
return true;
}
return false;
}
bool isMonster(short MonsterIndex) {
for (size_t i = 0; i < monsterPool.size(); i++) {
if (monsterPool[i] == MonsterIndex) {
return true;
}
}
return false;
}
bool isEmpty() {
if (isOwner("")) {
return true;
}
return false;
}
bool isExpired() {
if (GetTickCount() >= tickEnd) {
return true;
}
return false;
}
std::string ownerName;
std::vector<short> monsterPool;
int itemCode;
DWORD tickEnd;
};
// monster spawner by item drop impletation
class MonsterSpawnerMng {
public:
MonsterSpawnerMng();
~MonsterSpawnerMng();
void Load();
void Init();
void Read(const char* File);
void procRun();
void procRegen(short MonsterIndex);
bool procCreate(short UserIndex, int ItemCode);
bool isPrivate(short UserIndex, short MonsterIndex);
bool isEventMonster(short MonsterIndex);
bool isKeyItem(int ItemCode);
int getEmptySlot();
MonsterSpawnerItemInfo* getItemInfo(int ItemCode);
// singleton
static MonsterSpawnerMng* getInstance() {
if (m_Instance == NULL) {
m_Instance = new MonsterSpawnerMng();
}
return m_Instance;
}
private:
static MonsterSpawnerMng* m_Instance;
std::vector<MonsterSpawnerWorkNode> m_WorkPool;
std::vector<MonsterSpawnerItemInfo> m_ItemData;
private:
bool m_Loaded;
};