Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
Reload the module’s config and personality packs in-game or from the server console, without restarting.

- **Event-Based Chatter:**
Player bots now comment on key in-game events such as quest completion, rare loot, deaths, PvP kills, leveling up, duels, learning spells, and achievements. Remarks are context-aware, immersive, and personality-driven, making the world feel much more alive.
Player bots now comment on key in-game events such as quest completion, rare loot, deaths, PvP kills, leveling up, duels, learning spells, and achievements. Remarks are context-aware, immersive, and personality-driven, making the world feel much more alive. Additional opt-in events include entering zones, being slain by creatures, reputation rank-ups, resurrecting, and entering or leaving combat. Each of these new events supports separate player-vs-bot trigger chances (`PlayerEventChance.<Event>` / `BotEventChance.<Event>`) and defaults to off (0) to avoid spam.

- **Party-Only Bot Responses:**
When enabled, bots will only respond to real player messages and events when they are in the same non-raid party. This helps reduce chat spam while maintaining full bot-to-bot communication within parties for immersive group interactions.
Expand Down
31 changes: 31 additions & 0 deletions conf/mod_ollama_chat.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,37 @@ OllamaChat.EventTypeAchievement_Chance = 75
OllamaChat.EventTypeUsedObject = used object
OllamaChat.EventTypeUsedObject_Chance = 10

# --------------------------------------------
# ADDITIONAL EVENT HOOKS — all default 0 (off / opt-in)
# Each event has a type string (the prompt label) and split chances:
# PlayerEventChance.<Event> = chance (0-100) when the actor is a real player
# BotEventChance.<Event> = chance (0-100) when the actor is a bot
# --------------------------------------------

OllamaChat.EventTypeEnteredZone = entered zone
OllamaChat.PlayerEventChance.EnteredZone = 0
OllamaChat.BotEventChance.EnteredZone = 0

OllamaChat.EventTypeKilledByCreature = killed by creature
OllamaChat.PlayerEventChance.KilledByCreature = 0
OllamaChat.BotEventChance.KilledByCreature = 0

OllamaChat.EventTypeReputationRank = reputation rank
OllamaChat.PlayerEventChance.ReputationRank = 0
OllamaChat.BotEventChance.ReputationRank = 0

OllamaChat.EventTypeResurrected = resurrected
OllamaChat.PlayerEventChance.Resurrected = 0
OllamaChat.BotEventChance.Resurrected = 0

OllamaChat.EventTypeEnteredCombat = entered combat
OllamaChat.PlayerEventChance.EnteredCombat = 0
OllamaChat.BotEventChance.EnteredCombat = 0

OllamaChat.EventTypeLeftCombat = left combat
OllamaChat.PlayerEventChance.LeftCombat = 0
OllamaChat.BotEventChance.LeftCombat = 0

# OllamaChat.EventCooldownTime
# Description: The cooldown time (in seconds) for bots to respond to an event.
# Default: 10
Expand Down
42 changes: 42 additions & 0 deletions src/mod-ollama-chat_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,27 @@ std::string g_GuildEventTypeGuildDemotion = "";
std::string g_GuildEventTypeGuildLogin = "";
std::string g_GuildEventTypeGuildAchievement = "";

// additional event-chatter hook type strings and chances
std::string g_EventTypeEnteredZone;
std::string g_EventTypeKilledByCreature;
std::string g_EventTypeReputationRank;
std::string g_EventTypeResurrected;
std::string g_EventTypeEnteredCombat;
std::string g_EventTypeLeftCombat;

uint32_t g_PlayerEventChance_EnteredZone = 0;
uint32_t g_BotEventChance_EnteredZone = 0;
uint32_t g_PlayerEventChance_KilledByCreature = 0;
uint32_t g_BotEventChance_KilledByCreature = 0;
uint32_t g_PlayerEventChance_ReputationRank = 0;
uint32_t g_BotEventChance_ReputationRank = 0;
uint32_t g_PlayerEventChance_Resurrected = 0;
uint32_t g_BotEventChance_Resurrected = 0;
uint32_t g_PlayerEventChance_EnteredCombat = 0;
uint32_t g_BotEventChance_EnteredCombat = 0;
uint32_t g_PlayerEventChance_LeftCombat = 0;
uint32_t g_BotEventChance_LeftCombat = 0;

// --------------------------------------------
// Event Chatter Templates
// --------------------------------------------
Expand Down Expand Up @@ -513,6 +534,27 @@ void LoadOllamaChatConfig()
g_EventTypeAchievement = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeAchievement", "");
g_EventTypeUsedObject = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeUsedObject", "");

// additional event-chatter hook type strings
g_EventTypeEnteredZone = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeEnteredZone", "entered zone");
g_EventTypeKilledByCreature = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeKilledByCreature", "killed by creature");
g_EventTypeReputationRank = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeReputationRank", "reputation rank");
g_EventTypeResurrected = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeResurrected", "resurrected");
g_EventTypeEnteredCombat = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeEnteredCombat", "entered combat");
g_EventTypeLeftCombat = sConfigMgr->GetOption<std::string>("OllamaChat.EventTypeLeftCombat", "left combat");

// per-event player/bot chances (default 0 = off)
g_PlayerEventChance_EnteredZone = sConfigMgr->GetOption<uint32_t>("OllamaChat.PlayerEventChance.EnteredZone", 0);
g_BotEventChance_EnteredZone = sConfigMgr->GetOption<uint32_t>("OllamaChat.BotEventChance.EnteredZone", 0);
g_PlayerEventChance_KilledByCreature = sConfigMgr->GetOption<uint32_t>("OllamaChat.PlayerEventChance.KilledByCreature", 0);
g_BotEventChance_KilledByCreature = sConfigMgr->GetOption<uint32_t>("OllamaChat.BotEventChance.KilledByCreature", 0);
g_PlayerEventChance_ReputationRank = sConfigMgr->GetOption<uint32_t>("OllamaChat.PlayerEventChance.ReputationRank", 0);
g_BotEventChance_ReputationRank = sConfigMgr->GetOption<uint32_t>("OllamaChat.BotEventChance.ReputationRank", 0);
g_PlayerEventChance_Resurrected = sConfigMgr->GetOption<uint32_t>("OllamaChat.PlayerEventChance.Resurrected", 0);
g_BotEventChance_Resurrected = sConfigMgr->GetOption<uint32_t>("OllamaChat.BotEventChance.Resurrected", 0);
g_PlayerEventChance_EnteredCombat = sConfigMgr->GetOption<uint32_t>("OllamaChat.PlayerEventChance.EnteredCombat", 0);
g_BotEventChance_EnteredCombat = sConfigMgr->GetOption<uint32_t>("OllamaChat.BotEventChance.EnteredCombat", 0);
g_PlayerEventChance_LeftCombat = sConfigMgr->GetOption<uint32_t>("OllamaChat.PlayerEventChance.LeftCombat", 0);
g_BotEventChance_LeftCombat = sConfigMgr->GetOption<uint32_t>("OllamaChat.BotEventChance.LeftCombat", 0);

// Load extra blacklist commands from config (comma-separated list)
std::string extraBlacklist = sConfigMgr->GetOption<std::string>("OllamaChat.BlacklistCommands", "");
Expand Down
22 changes: 22 additions & 0 deletions src/mod-ollama-chat_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,28 @@ extern std::string g_GuildEventTypeGuildDemotion;
extern std::string g_GuildEventTypeGuildLogin;
extern std::string g_GuildEventTypeGuildAchievement;

// additional event-chatter hook type strings
extern std::string g_EventTypeEnteredZone;
extern std::string g_EventTypeKilledByCreature;
extern std::string g_EventTypeReputationRank;
extern std::string g_EventTypeResurrected;
extern std::string g_EventTypeEnteredCombat;
extern std::string g_EventTypeLeftCombat;

// per-event player/bot chances (0-100); all default 0 (opt-in)
extern uint32_t g_PlayerEventChance_EnteredZone;
extern uint32_t g_BotEventChance_EnteredZone;
extern uint32_t g_PlayerEventChance_KilledByCreature;
extern uint32_t g_BotEventChance_KilledByCreature;
extern uint32_t g_PlayerEventChance_ReputationRank;
extern uint32_t g_BotEventChance_ReputationRank;
extern uint32_t g_PlayerEventChance_Resurrected;
extern uint32_t g_BotEventChance_Resurrected;
extern uint32_t g_PlayerEventChance_EnteredCombat;
extern uint32_t g_BotEventChance_EnteredCombat;
extern uint32_t g_PlayerEventChance_LeftCombat;
extern uint32_t g_BotEventChance_LeftCombat;

// Chance variables for normal events
extern int g_EventTypeDefeated_Chance;
extern int g_EventTypeDefeatedPlayer_Chance;
Expand Down
99 changes: 99 additions & 0 deletions src/mod-ollama-chat_events.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
#include "SpellMgr.h"
#include "AchievementMgr.h"
#include "GameObject.h"
#include "Creature.h"
#include "DBCStores.h"
#include "World.h"
#include "SharedDefines.h"
#include <vector>
#include <thread>
#include <random>
Expand Down Expand Up @@ -198,6 +202,30 @@ void OllamaBotEventChatter::DispatchGameEvent(Player* source, std::string type,
} else if (type == g_EventTypeUsedObject) {
eventChance = g_EventTypeUsedObject_Chance;
}
else if (type == g_EventTypeEnteredZone)
{
eventChance = isSourceBot ? g_BotEventChance_EnteredZone : g_PlayerEventChance_EnteredZone;
}
else if (type == g_EventTypeKilledByCreature)
{
eventChance = isSourceBot ? g_BotEventChance_KilledByCreature : g_PlayerEventChance_KilledByCreature;
}
else if (type == g_EventTypeReputationRank)
{
eventChance = isSourceBot ? g_BotEventChance_ReputationRank : g_PlayerEventChance_ReputationRank;
}
else if (type == g_EventTypeResurrected)
{
eventChance = isSourceBot ? g_BotEventChance_Resurrected : g_PlayerEventChance_Resurrected;
}
else if (type == g_EventTypeEnteredCombat)
{
eventChance = isSourceBot ? g_BotEventChance_EnteredCombat : g_PlayerEventChance_EnteredCombat;
}
else if (type == g_EventTypeLeftCombat)
{
eventChance = isSourceBot ? g_BotEventChance_LeftCombat : g_PlayerEventChance_LeftCombat;
}

// Add chance checks for all GuildEventType entries
if (type == g_GuildEventTypeEpicGear) {
Expand Down Expand Up @@ -663,6 +691,77 @@ void ChatOnGameObjectUse::OnGameObjectUse(Player* player, GameObject* go)
eventChatter.DispatchGameEvent(player, g_EventTypeUsedObject, go->GetGOInfo()->name);
}

// additional event-chatter hooks

ChatOnZone::ChatOnZone() : PlayerScript("ChatOnZone") {}

void ChatOnZone::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 /*newArea*/)
{
if (!player)
return;
std::string zoneName;
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone))
{
zoneName = zone->area_name[sWorld->GetDefaultDbcLocale()];
if (zoneName.empty())
zoneName = zone->area_name[LOCALE_enUS];
}
eventChatter.DispatchGameEvent(player, g_EventTypeEnteredZone, zoneName);
}

ChatOnKilledByCreature::ChatOnKilledByCreature() : PlayerScript("ChatOnKilledByCreature") {}

void ChatOnKilledByCreature::OnPlayerKilledByCreature(Creature* killer, Player* killed)
{
if (!killer || !killed)
return;
eventChatter.DispatchGameEvent(killed, g_EventTypeKilledByCreature, killer->GetName());
}

ChatOnReputationRank::ChatOnReputationRank() : PlayerScript("ChatOnReputationRank") {}

void ChatOnReputationRank::OnPlayerReputationRankChange(Player* player, uint32 factionID,
ReputationRank /*newRank*/,
ReputationRank /*oldRank*/, bool increased)
{
if (!player || !increased) // only celebrate rank-ups, not losses
return;
std::string factionName;
if (FactionEntry const* faction = sFactionStore.LookupEntry(factionID))
{
factionName = faction->name[sWorld->GetDefaultDbcLocale()];
if (factionName.empty())
factionName = faction->name[LOCALE_enUS];
}
eventChatter.DispatchGameEvent(player, g_EventTypeReputationRank, factionName);
}

ChatOnResurrect::ChatOnResurrect() : PlayerScript("ChatOnResurrect") {}

void ChatOnResurrect::OnPlayerResurrect(Player* player, float /*restorePercent*/, bool& /*applySickness*/)
{
if (!player)
return;
eventChatter.DispatchGameEvent(player, g_EventTypeResurrected, "");
}

ChatOnCombat::ChatOnCombat() : PlayerScript("ChatOnCombat") {}

void ChatOnCombat::OnPlayerEnterCombat(Player* player, Unit* enemy)
{
if (!player)
return;
std::string enemyName = enemy ? enemy->GetName() : "";
eventChatter.DispatchGameEvent(player, g_EventTypeEnteredCombat, enemyName);
}

void ChatOnCombat::OnPlayerLeaveCombat(Player* player)
{
if (!player)
return;
eventChatter.DispatchGameEvent(player, g_EventTypeLeftCombat, "");
}

ChatOnGuildMemberChange::ChatOnGuildMemberChange() : PlayerScript("ChatOnGuildMemberChange") {}

void ChatOnGuildMemberChange::OnGuildMemberJoin(Player* player, Guild* /*guild*/)
Expand Down
38 changes: 38 additions & 0 deletions src/mod-ollama-chat_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,44 @@ class ChatOnGameObjectUse : public PlayerScript
void OnGameObjectUse(Player* player, GameObject* go);
};

// additional event-chatter hooks
class ChatOnZone : public PlayerScript
{
public:
ChatOnZone();
void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea) override;
};

class ChatOnKilledByCreature : public PlayerScript
{
public:
ChatOnKilledByCreature();
void OnPlayerKilledByCreature(Creature* killer, Player* killed) override;
};

class ChatOnReputationRank : public PlayerScript
{
public:
ChatOnReputationRank();
void OnPlayerReputationRankChange(Player* player, uint32 factionID, ReputationRank /*newRank*/,
ReputationRank /*oldRank*/, bool increased) override;
};

class ChatOnResurrect : public PlayerScript
{
public:
ChatOnResurrect();
void OnPlayerResurrect(Player* player, float restorePercent, bool& applySickness) override;
};

class ChatOnCombat : public PlayerScript
{
public:
ChatOnCombat();
void OnPlayerEnterCombat(Player* player, Unit* enemy) override;
void OnPlayerLeaveCombat(Player* player) override;
};

class ChatOnGuildMemberChange : public PlayerScript
{
public:
Expand Down
5 changes: 5 additions & 0 deletions src/mod-ollama-chat_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,10 @@ void Addmod_ollama_chatScripts()
new ChatOnLevelUp();
new ChatOnAchievement();
new ChatOnGameObjectUse();
new ChatOnZone();
new ChatOnKilledByCreature();
new ChatOnReputationRank();
new ChatOnResurrect();
new ChatOnCombat();
new OllamaChatConfigCommand();
}