Itutorial
Legendary OT User
- Joined
- Dec 23, 2014
- Messages
- 2,330
- Solutions
- 68
- Reaction score
- 1,008
This was created using Nekiros 1.5 8.6 downgrade. There shouldn't be any problems in adding it in any 1.5+.
This system will allow you to create monsters and npcs that only specific players can see.
Ex. During a quest a NPC comes and talks to a player that only he can see.
Ex. A quest monster spawns that only the player can see to kill.
You can also make it so all party members can see the monster aswell by just creating a loop to add each player to the seen list and the players id to the creatures seen list.
Inspired by WoW this can be used to create all types of cool things. In the future I plan to update this with a more advanced version that can have specific storage values that allow players to see it aswell.
Ex. A whole area is populated with specific monsters/npcs after any player has completed the correct quest.
You will be able to have completly different content for each unique player. I am surprised this wasn't created earlier.
When you want to create a creature make sure you add it to the players seen list and add the player to the creatures seen list.
This code will automatically remove seen players from player list whenever a creature is removed/killed.
Available Methods
In creature.h
UNDER
ADD
UNDER
ADD
in monster.cpp
FIND
UNDER
assert(creature != this);
ADD
in player.h
FIND
ADD
FIND
ADD
IN player.cpp
FIND
ADD
FIND
UNDER ADD
IN game.cpp
FIND
ADD
IN luascript.h
FIND
ADD
FIND
ADD
IN luascript.cpp
FIND
UNDER WHOLE METHOD ADD
FIND
UNDER WHOLE METHOD ADD
Here is an example talkaction code I created.
If you see anything that can be fixed/changed or named different let me know. I am working on the more advanced system now. Please share anything you think could make this better as it is now. I know it has flaws and will be working on fixing them.
For now the npc/monster must be created outside any players screens then teleported back to them after lists are set. That is the first thing im working on.
This system will allow you to create monsters and npcs that only specific players can see.
Ex. During a quest a NPC comes and talks to a player that only he can see.
Ex. A quest monster spawns that only the player can see to kill.
You can also make it so all party members can see the monster aswell by just creating a loop to add each player to the seen list and the players id to the creatures seen list.
Inspired by WoW this can be used to create all types of cool things. In the future I plan to update this with a more advanced version that can have specific storage values that allow players to see it aswell.
Ex. A whole area is populated with specific monsters/npcs after any player has completed the correct quest.
You will be able to have completly different content for each unique player. I am surprised this wasn't created earlier.
When you want to create a creature make sure you add it to the players seen list and add the player to the creatures seen list.
Lua:
local creature = Game.createMonster(name, pos)
creature:addSeenByPlayer(playerid)
player:addSeenCreature(creatureid)
This code will automatically remove seen players from player list whenever a creature is removed/killed.
Available Methods
Code:
creature:addSeenByPlayer(player or id)
creature:removeSeenByPlayer(player or id)
creature:isSeenByPlayer(player or id)
creature:getSeenByList()
player:addSeenCreature(creature or id)
player:removeSeenCreature(creature or id)
player:getSeenCreatures()
player:hasSeenCreature(creature or id)
In creature.h
UNDER
C++:
void decrementReferenceCounter() {
if (--referenceCounter == 0) {
delete this;
}
}
ADD
C++:
std::list<uint32_t> getSeenByList() {
return seenByList;
}
bool isInSeenList(uint32_t id) {
auto it = std::find(seenByList.begin(), seenByList.end(), id);
if (it != seenByList.end()) {
return true;
}
return false;
}
void addSeenByPlayer(uint32_t id) {
seenByList.push_back(id);
}
void removeSeenByPlayer(uint32_t id) {
seenByList.remove(id);
}
UNDER
C++:
std::list<Creature*> summons;
ADD
C++:
std::list<uint32_t> seenByList;
in monster.cpp
FIND
C++:
void Monster::addTarget(Creature* creature, bool pushFront/* = false*/)
UNDER
assert(creature != this);
ADD
C++:
if (creature && creature->getPlayer()) {
std::list<uint32_t> list = getSeenByList();
if (list.size() != 0) {
if (!isInSeenList(creature->getID())) {
return;
}
}
}
in player.h
FIND
C++:
void switchGhostMode() {
ghostMode = !ghostMode;
}
ADD
C++:
bool hasSeenCreature(uint32_t id) const;
void addSeenCreature(uint32_t id) {
seenCreatures.push_back(id);
}
void removeSeenCreature(uint32_t id) {
seenCreatures.remove(id);
}
std::list<uint32_t> getSeenCreatures() {
return seenCreatures;
}
FIND
C++:
std::list<ShopInfo> shopItemList;
ADD
C++:
std::list<uint32_t> seenCreatures;
IN player.cpp
FIND
C++:
if (!creature->getPlayer() && !canSeeInvisibility() && creature->isInvisible()) {
return false;
}
ADD
C++:
if (creature->getSeenByList().size() != 0 && !hasSeenCreature(creature->getID())) {
return false;
}
FIND
C++:
bool Player::canSeeGhostMode(const Creature*) const
{
return group->access;
}
UNDER ADD
C++:
bool Player::hasSeenCreature(uint32_t id) const
{
auto it = std::find(seenCreatures.begin(), seenCreatures.end(), id);
if (it != seenCreatures.end()) {
return true;
}
return false;
}
IN game.cpp
FIND
C++:
for (Creature* spectator : spectators) {
if (Player* player = spectator->getPlayer()) {
if (player->canSeeCreature(creature)) {
player->sendRemoveTileCreature(creature, tilePosition, oldStackPosVector[i++]);
}
}
}
ADD
C++:
// Remove players seen list
std::list<uint32_t> list = creature->getSeenByList();
if (list.size() != 0) {
for (std::list<uint32_t>::iterator it = list.begin(); it != list.end(); it++) {
Player* tmpPlayer = g_game.getPlayerByID(*it);
if (tmpPlayer) {
tmpPlayer->removeSeenCreature(creature->getID());
}
}
}
IN luascript.h
FIND
C++:
static int luaCreatureCanSeeCreature(lua_State* L);
ADD
C++:
static int luaCreatureAddSeenByPlayer(lua_State* L);
static int luaCreatureRemoveSeenByPlayer(lua_State* L);
static int luaCreatureIsSeenByPlayer(lua_State* L);
static int luaCreatureGetSeenByList(lua_State* L);
FIND
C++:
static int luaPlayerSetStorageValue(lua_State* L);
ADD
C++:
static int luaPlayerAddSeenCreature(lua_State* L);
static int luaPlayerRemoveSeenCreature(lua_State* L);
static int luaPlayerHasSeenCreature(lua_State* L);
static int luaPlayerGetSeenCreatures(lua_State* L);
IN luascript.cpp
FIND
C++:
int LuaScriptInterface::luaCreatureCanSeeCreature(lua_State* L)
UNDER WHOLE METHOD ADD
C++:
int LuaScriptInterface::luaCreatureAddSeenByPlayer(lua_State* L)
{
// creature:addSeenByPlayer(id)
Creature* creature = getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}
Player* player = getUserdata<Player>(L, 2);
if (player && !creature->isInSeenList(player->getID())) {
creature->addSeenByPlayer(player->getID());
pushBoolean(L, true);
return 1;
}
uint32_t id = getNumber<uint32_t>(L, 2);
if (id && !creature->isInSeenList(id)) {
creature->addSeenByPlayer(id);
pushBoolean(L, true);
return 1;
}
pushBoolean(L, false);
return 1;
}
int LuaScriptInterface::luaCreatureRemoveSeenByPlayer(lua_State* L)
{
// creature:removeSeenByPlayer(player or id)
Creature* creature = getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}
Player* player = getUserdata<Player>(L, 2);
if (player && creature->isInSeenList(player->getID())) {
creature->removeSeenByPlayer(player->getID());
pushBoolean(L, true);
return 1;
}
uint32_t id = getNumber<uint32_t>(L, 2);
if (id && creature->isInSeenList(id)) {
creature->removeSeenByPlayer(id);
pushBoolean(L, true);
return 1;
}
pushBoolean(L, false);
return 1;
}
int LuaScriptInterface::luaCreatureIsSeenByPlayer(lua_State* L)
{
// creature:isSeenByPlayer(player or id)
Creature* creature = getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}
uint32_t newID = 0;
Player* player = getUserdata<Player>(L, 2);
if (player) {
newID = player->getID();
}
else {
newID = getNumber<uint32_t>(L, 2);
}
if (newID != 0) {
std::list<uint32_t>::iterator it;
std::list<uint32_t> newList = creature->getSeenByList();
for (it = newList.begin(); it != newList.end(); it++) {
if (newID == *it) {
pushBoolean(L, true);
return 1;
}
}
}
pushBoolean(L, false);
return 1;
}
int LuaScriptInterface::luaCreatureGetSeenByList(lua_State* L)
{
// creature:getSeenByList()
Creature* creature = getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}
std::list<uint32_t> newList = creature->getSeenByList();
lua_createtable(L, newList.size(), 0);
std::list<uint32_t>::iterator it;
int index = 0;
for (it = newList.begin(); it != newList.end(); it++) {
lua_pushnumber(L, *it);
lua_rawseti(L, -2, ++index);
}
return 1;
}
FIND
C++:
int LuaScriptInterface::luaPlayerGetStorageValue(lua_State* L)
UNDER WHOLE METHOD ADD
C++:
int LuaScriptInterface::luaPlayerAddSeenCreature(lua_State* L)
{
// player:addSeenCreature(creature or id)
Player* player = getUserdata<Player>(L, 1);
if (!player) {
lua_pushnil(L);
return 1;
}
const Creature* creature = getUserdata<Creature>(L, 2);
if (creature) {
if (!player->hasSeenCreature(creature->getID())) {
player->addSeenCreature(creature->getID());
pushBoolean(L, true);
return 1;
}
}
uint32_t id = getNumber<uint32_t>(L, 2);
if (id && !player->hasSeenCreature(id)) {
player->addSeenCreature(id);
pushBoolean(L, true);
return 1;
}
pushBoolean(L, false);
return 1;
}
int LuaScriptInterface::luaPlayerRemoveSeenCreature(lua_State* L)
{
// player:removeSeenCreature(creature or id)
Player* player = getUserdata<Player>(L, 1);
if (!player) {
lua_pushnil(L);
return 1;
}
const Creature* creature = getUserdata<Creature>(L, 2);
if (creature) {
if (player->hasSeenCreature(creature->getID())) {
player->removeSeenCreature(creature->getID());
pushBoolean(L, true);
return 1;
}
}
uint32_t id = getNumber<uint32_t>(L, 2);
if (id && player->hasSeenCreature(id)) {
player->removeSeenCreature(id);
pushBoolean(L, true);
return 1;
}
pushBoolean(L, false);
return 1;
}
int LuaScriptInterface::luaPlayerGetSeenCreatures(lua_State* L)
{
// player:getSeenCreatures()
Player* player = getUserdata<Player>(L, 1);
if (!player) {
lua_pushnil(L);
return 1;
}
std::list<uint32_t> newList = player->getSeenCreatures();
if (newList.size() == 0) {
lua_pushnil(L);
return 1;
}
lua_createtable(L, newList.size(), 0);
std::list<uint32_t>::iterator it;
int index = 0;
for (it = newList.begin(); it != newList.end(); it++) {
lua_pushnumber(L, *it);
lua_rawseti(L, -2, ++index);
}
return 1;
}
int LuaScriptInterface::luaPlayerHasSeenCreature(lua_State* L)
{
// player:hasSeenCreature(creature or id)
Player* player = getUserdata<Player>(L, 1);
if (!player) {
lua_pushnil(L);
return 1;
}
const Creature* creature = getUserdata<Creature>(L, 2);
if (creature) {
if (player->hasSeenCreature(creature->getID())) {
pushBoolean(L, true);
return 1;
}
}
uint32_t id = getNumber<uint32_t>(L, 2);
if (id && player->hasSeenCreature(id)) {
pushBoolean(L, true);
return 1;
}
pushBoolean(L, false);
return 1;
}
Post automatically merged:
Here is an example talkaction code I created.
Lua:
local createPos = Position(19981, 19998, 7)
local TalkCreateSpecialNpc = TalkAction("/spec")
function TalkCreateSpecialNpc.onSay(player, words, param)
if not player:getGroup():getAccess() or player:getAccountType() < ACCOUNT_TYPE_GOD then
return false
end
if param == "" then
return false
end
local t = param:split(",")
local name = t[1]
local playerName = t[2]
if not t[1] or not t[2] then return false end
local target = Player(playerName)
if not target then
player:sendCancelMessage("Target player is not online.")
return false
end
local creature = Game.createMonster(name, createPos, 0, 1)
if not creature then
creature = Game.createNpc(name, createPos, 0, 1)
end
if not creature then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_RED, "Failed to create special creature.")
return false
end
creature:addSeenByPlayer(target:getId())
target:addSeenCreature(creature:getId())
local list = creature:getSeenByList()
if list and #list > 0 then
for i = 1, #list do
print(list[i])
end
else
print("FAILED TO GET LIST")
creature:remove();
return false
end
local pPos = target:getPosition()
creature:teleportTo(Position(pPos.x, pPos.y - 1, pPos.z))
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_RED, "Special creature created.")
return false
end
TalkCreateSpecialNpc:separator(" ")
TalkCreateSpecialNpc:register()
If you see anything that can be fixed/changed or named different let me know. I am working on the more advanced system now. Please share anything you think could make this better as it is now. I know it has flaws and will be working on fixing them.
For now the npc/monster must be created outside any players screens then teleported back to them after lists are set. That is the first thing im working on.
Last edited: