• 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!

remove spawn with player on screen

myllenasz

New Member
Joined
Feb 2, 2011
Messages
20
Reaction score
3
hello everything is fine?


I would like to remove spawn with player on screen

to stay version 8.6 7.72 style

can someone help me?


SPAWN.CPP
Lua:
/**
 * The Forgotten Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2019  Mark Samman <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "otpch.h"

#include "spawn.h"
#include "game.h"
#include "monster.h"
#include "configmanager.h"
#include "scheduler.h"

#include "pugicast.h"
#include "events.h"

extern ConfigManager g_config;
extern Monsters g_monsters;
extern Game g_game;
extern Events* g_events;

static constexpr int32_t MINSPAWN_INTERVAL = 1000;

bool Spawns::loadFromXml(const std::string& filename)
{
    if (loaded) {
        return true;
    }

    pugi::xml_document doc;
    pugi::xml_parse_result result = doc.load_file(filename.c_str());
    if (!result) {
        printXMLError("Error - Spawns::loadFromXml", filename, result);
        return false;
    }

    this->filename = filename;
    loaded = true;

    for (auto spawnNode : doc.child("spawns").children()) {
        Position centerPos(
            pugi::cast<uint16_t>(spawnNode.attribute("centerx").value()),
            pugi::cast<uint16_t>(spawnNode.attribute("centery").value()),
            pugi::cast<uint16_t>(spawnNode.attribute("centerz").value())
        );

        int32_t radius;
        pugi::xml_attribute radiusAttribute = spawnNode.attribute("radius");
        if (radiusAttribute) {
            radius = pugi::cast<int32_t>(radiusAttribute.value());
        } else {
            radius = -1;
        }

        spawnList.emplace_front(centerPos, radius);
        Spawn& spawn = spawnList.front();

        for (auto childNode : spawnNode.children()) {
            if (strcasecmp(childNode.name(), "monster") == 0) {
                pugi::xml_attribute nameAttribute = childNode.attribute("name");
                if (!nameAttribute) {
                    continue;
                }

                Direction dir;

                pugi::xml_attribute directionAttribute = childNode.attribute("direction");
                if (directionAttribute) {
                    dir = static_cast<Direction>(pugi::cast<uint16_t>(directionAttribute.value()));
                } else {
                    dir = DIRECTION_NORTH;
                }

                Position pos(
                    centerPos.x + pugi::cast<uint16_t>(childNode.attribute("x").value()),
                    centerPos.y + pugi::cast<uint16_t>(childNode.attribute("y").value()),
                    centerPos.z
                );
                uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 1000;
                if (interval > MINSPAWN_INTERVAL) {
                    spawn.addMonster(nameAttribute.as_string(), pos, dir, interval);
                } else {
                    std::cout << "[Warning - Spawns::loadFromXml] " << nameAttribute.as_string() << ' ' << pos << " spawntime can not be less than " << MINSPAWN_INTERVAL / 1000 << " seconds." << std::endl;
                }
            } else if (strcasecmp(childNode.name(), "npc") == 0) {
                pugi::xml_attribute nameAttribute = childNode.attribute("name");
                if (!nameAttribute) {
                    continue;
                }

                Npc* npc = Npc::createNpc(nameAttribute.as_string());
                if (!npc) {
                    continue;
                }

                pugi::xml_attribute directionAttribute = childNode.attribute("direction");
                if (directionAttribute) {
                    npc->setDirection(static_cast<Direction>(pugi::cast<uint16_t>(directionAttribute.value())));
                }

                npc->setMasterPos(Position(
                    centerPos.x + pugi::cast<uint16_t>(childNode.attribute("x").value()),
                    centerPos.y + pugi::cast<uint16_t>(childNode.attribute("y").value()),
                    centerPos.z
                ), radius);
                npcList.push_front(npc);
            }
        }
    }
    return true;
}

void Spawns::startup()
{
    if (!loaded || isStarted()) {
        return;
    }

    for (Npc* npc : npcList) {
        g_game.placeCreature(npc, npc->getMasterPos(), false, true);
    }
    npcList.clear();

    for (Spawn& spawn : spawnList) {
        spawn.startup();
    }

    started = true;
}

void Spawns::clear()
{
    for (Spawn& spawn : spawnList) {
        spawn.stopEvent();
    }
    spawnList.clear();

    loaded = false;
    started = false;
    filename.clear();
}

bool Spawns::isInZone(const Position& centerPos, int32_t radius, const Position& pos)
{
    if (radius == -1) {
        return true;
    }

    return ((pos.getX() >= centerPos.getX() - radius) && (pos.getX() <= centerPos.getX() + radius) &&
            (pos.getY() >= centerPos.getY() - radius) && (pos.getY() <= centerPos.getY() + radius));
}

void Spawn::startSpawnCheck()
{
    if (checkSpawnEvent == 0) {
        checkSpawnEvent = g_scheduler.addEvent(createSchedulerTask(getInterval(), std::bind(&Spawn::checkSpawn, this)));
    }
}

Spawn::~Spawn()
{
    for (const auto& it : spawnedMap) {
        Monster* monster = it.second;
        monster->setSpawn(nullptr);
        monster->decrementReferenceCounter();
    }
}

bool Spawn::findPlayer(const Position& pos)
{
    SpectatorVec spectators;
    g_game.map.getSpectators(spectators, pos, false, true);
    for (Creature* spectator : spectators) {
        if (!spectator->getPlayer()->hasFlag(PlayerFlag_IgnoredByMonsters)) {
            return true;
        }
    }
    return false;
}

bool Spawn::isInSpawnZone(const Position& pos)
{
    return Spawns::isInZone(centerPos, radius, pos);
}

bool Spawn::spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, bool startup /*= false*/)
{
    std::unique_ptr<Monster> monster_ptr(new Monster(mType));
    if (!g_events->eventMonsterOnSpawn(monster_ptr.get(), pos, startup, false)) {
        return false;
    }

    if (startup) {
        //No need to send out events to the surrounding since there is no one out there to listen!
        if (!g_game.internalPlaceCreature(monster_ptr.get(), pos, true)) {
            return false;
        }
    } else {
        if (!g_game.placeCreature(monster_ptr.get(), pos, false, true)) {
            return false;
        }
    }

    Monster* monster = monster_ptr.release();
    monster->setDirection(dir);
    monster->setSpawn(this);
    monster->setMasterPos(pos);
    monster->incrementReferenceCounter();

    spawnedMap.insert(spawned_pair(spawnId, monster));
    spawnMap[spawnId].lastSpawn = OTSYS_TIME();
    return true;
}

void Spawn::startup()
{
    for (const auto& it : spawnMap) {
        uint32_t spawnId = it.first;
        const spawnBlock_t& sb = it.second;
        spawnMonster(spawnId, sb.mType, sb.pos, sb.direction, true);
    }
}

void Spawn::checkSpawn()
{
    checkSpawnEvent = 0;

    cleanup();

    uint32_t spawnCount = 0;

    for (auto& it : spawnMap) {
        uint32_t spawnId = it.first;
        if (spawnedMap.find(spawnId) != spawnedMap.end()) {
            continue;
        }

        spawnBlock_t& sb = it.second;
        if (OTSYS_TIME() >= sb.lastSpawn + sb.interval) {
            if (findPlayer(sb.pos)) {
                sb.lastSpawn = OTSYS_TIME();
                continue;
            }

            spawnMonster(spawnId, sb.mType, sb.pos, sb.direction);
            if (++spawnCount >= static_cast<uint32_t>(g_config.getNumber(ConfigManager::RATE_SPAWN))) {
                break;
            }
        }
    }

    if (spawnedMap.size() < spawnMap.size()) {
        checkSpawnEvent = g_scheduler.addEvent(createSchedulerTask(getInterval(), std::bind(&Spawn::checkSpawn, this)));
    }
}

void Spawn::cleanup()
{
    auto it = spawnedMap.begin();
    while (it != spawnedMap.end()) {
        uint32_t spawnId = it->first;
        Monster* monster = it->second;
        if (monster->isRemoved()) {
            if (spawnId != 0) {
                spawnMap[spawnId].lastSpawn = OTSYS_TIME();
            }

            monster->decrementReferenceCounter();
            it = spawnedMap.erase(it);
        } else if (!isInSpawnZone(monster->getPosition()) && spawnId != 0) {
            spawnedMap.insert(spawned_pair(0, monster));
            it = spawnedMap.erase(it);
        } else {
            ++it;
        }
    }
}

bool Spawn::addMonster(const std::string& name, const Position& pos, Direction dir, uint32_t interval)
{
    MonsterType* mType = g_monsters.getMonsterType(name);
    if (!mType) {
        std::cout << "[Spawn::addMonster] Can not find " << name << std::endl;
        return false;
    }

    this->interval = std::min(this->interval, interval);

    spawnBlock_t sb;
    sb.mType = mType;
    sb.pos = pos;
    sb.direction = dir;
    sb.interval = interval;
    sb.lastSpawn = 0;

    uint32_t spawnId = spawnMap.size() + 1;
    spawnMap[spawnId] = sb;
    return true;
}

void Spawn::removeMonster(Monster* monster)
{
    for (auto it = spawnedMap.begin(), end = spawnedMap.end(); it != end; ++it) {
        if (it->second == monster) {
            monster->decrementReferenceCounter();
            spawnedMap.erase(it);
            break;
        }
    }
}

void Spawn::stopEvent()
{
    if (checkSpawnEvent != 0) {
        g_scheduler.stopEvent(checkSpawnEvent);
        checkSpawnEvent = 0;
    }
}

spawn.h

Code:
/**
 * The Forgotten Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2019  Mark Samman <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef FS_SPAWN_H_1A86089E080846A9AE53ED12E7AE863B
#define FS_SPAWN_H_1A86089E080846A9AE53ED12E7AE863B

#include "tile.h"
#include "position.h"

class Monster;
class MonsterType;
class Npc;

struct spawnBlock_t {
    Position pos;
    MonsterType* mType;
    int64_t lastSpawn;
    uint32_t interval;
    Direction direction;
};

class Spawn
{
    public:
        Spawn(Position pos, int32_t radius) : centerPos(std::move(pos)), radius(radius) {}
        ~Spawn();

        // non-copyable
        Spawn(const Spawn&) = delete;
        Spawn& operator=(const Spawn&) = delete;

        bool addMonster(const std::string& name, const Position& pos, Direction dir, uint32_t interval);
        void removeMonster(Monster* monster);

        uint32_t getInterval() const {
            return interval;
        }
        void startup();

        void startSpawnCheck();
        void stopEvent();

        bool isInSpawnZone(const Position& pos);
        void cleanup();

    private:
        //map of the spawned creatures
        using SpawnedMap = std::multimap<uint32_t, Monster*>;
        using spawned_pair = SpawnedMap::value_type;
        SpawnedMap spawnedMap;

        //map of creatures in the spawn
        std::map<uint32_t, spawnBlock_t> spawnMap;

        Position centerPos;
        int32_t radius;

        uint32_t interval = 60000;
        uint32_t checkSpawnEvent = 0;

        static bool findPlayer(const Position& pos);
        bool spawnMonster(uint32_t spawnId, MonsterType* mType, const Position& pos, Direction dir, bool startup = false);
        void checkSpawn();
};

class Spawns
{
    public:
        static bool isInZone(const Position& centerPos, int32_t radius, const Position& pos);

        bool loadFromXml(const std::string& filename);
        void startup();
        void clear();

        bool isStarted() const {
            return started;
        }

    private:
        std::forward_list<Npc*> npcList;
        std::forward_list<Spawn> spawnList;
        std::string filename;
        bool loaded = false;
        bool started = false;
};

#endif


please can someone help me thanks
 
If there is at least one player in the spawn position, the monster will not be spawned. The findPlayer function is used to check if there is any player in the spawn position, and if found, the checkSpawn function will not spawn any monster at that moment and will wait until the next interval to try again.

spawn.cpp
C++:
if (findPlayer(sb.pos)) {
    sb.lastSpawn = OTSYS_TIME();
    continue;
}
 
If there is at least one player in the spawn position, the monster will not be spawned. The findPlayer function is used to check if there is any player in the spawn position, and if found, the checkSpawn function will not spawn any monster at that moment and will wait until the next interval to try again.

spawn.cpp
C++:
if (findPlayer(sb.pos)) {
    sb.lastSpawn = OTSYS_TIME();
    continue;
}
THANKZ FIX
 
Last edited:
Back
Top