SparrowBot/app/rpgmodule.cpp
2016-03-18 12:16:09 +01:00

507 lines
16 KiB
C++

#include "rpgmodule.h"
#include <QString>
#include <QStringList>
#include <QFileInfo>
#include <QTextStream>
#include "message.h"
#include "user.h"
QString RPGCharacter::toString()
{
QString str;
str.append(pseudo).append(" ");
str.append(password).append(" ");
str.append(QString::number(level)).append(" ");
str.append(QString::number(xp)).append(" ");
str.append(QString::number(x)).append(" ");
str.append(QString::number(y));
return str;
}
void RPGModule::initVillages()
{
Village v;
Event eventBlacksmith;
eventBlacksmith.name = "blacksmith";
eventBlacksmith.description = "you approach the strong bearded blacksmith, and asks him to show his goods.";
eventBlacksmith.type = Event::TRADER;
Trade t;
t.goldPrice = 100;
t.item = "rusty sword";
Trader *blacksmithTrader = new Trader();
blacksmithTrader->push_back(t);
eventBlacksmith.trader = blacksmithTrader;
Event eventInn;
eventInn.name = "inn";
eventInn.description = "you enter the inn, there are plenty of townsfolk drinking and eating loudly.";
eventInn.type = Event::TRADER;
t.goldPrice = 20;
t.item = "night of rest";
Trader *innkeeperTrader = new Trader();
innkeeperTrader->push_back(t);
eventInn.trader = innkeeperTrader;
v.x = 7;
v.y = 4;
v.name = "Dornwich";
v.events.push_back(eventInn);
v.events.push_back(eventBlacksmith);
villages.push_back(v);
v.x = 1;
v.y = 11;
v.name = "Dawsbury";
v.events.push_back(eventInn);
villages.push_back(v);
v.x = 17;
v.y = 8;
v.name = "Willowdale";
v.events.push_back(eventInn);
v.events.push_back(eventBlacksmith);
villages.push_back(v);
v.x = 19;
v.y = 22;
v.name = "Myrefall";
v.events.push_back(eventInn);
villages.push_back(v);
v.x = 12;
v.y = 15;
v.name = "Calmarnock";
v.events.push_back(eventInn);
villages.push_back(v);
v.x = 3;
v.y = 18;
v.name = "Waeldestone";
v.events.push_back(eventInn);
v.events.push_back(eventBlacksmith);
villages.push_back(v);
}
bool RPGCharacter::fromString(QString str)
{
QStringList list = str.split(QChar(' '));
if(list.size() == 6)
{
bool ok;
pseudo = list[0];
password = list[1];
level = list[2].toInt(&ok);
if(!ok)
return false;
xp = list[3].toInt(&ok);
if(!ok)
return false;
x = list[4].toInt(&ok);
if(!ok)
return false;
y = list[5].toInt(&ok);
if(!ok)
return false;
return true;
}
else
return false;
}
RPGModule::RPGModule()
{
initVillages();
QFile f("../../res/rpg.save");
if(!f.open(QFile::ReadOnly | QFile::Text))
{
fprintf(stderr, "can't load save file.\n");
return;
}
QTextStream in(&f);
QString line = "plop (line init)";
do
{
line = in.readLine();
RPGCharacter *c = new RPGCharacter(line);
if(c->pseudo.compare("trash") != 0)
charList.add(c);
}
while(!line.isNull());
f.close();
}
void RPGModule::saveCharacters()
{
QFile f("../../res/rpg.save");
if(!f.open(QFile::WriteOnly | QFile::Text))
{
fprintf(stderr, "can't load save file.\n");
return;
}
QTextStream out(&f);
for(const std::string &name : charList.names)
{
if(name != "trash")
out << charList.get(name)->toString() << "\n";
}
f.close();
}
void RPGModule::playerJoin(User *user, RPGCharacter *c)
{
c->user = user;
charOnline[user] = c;
}
void RPGModule::playerLeave(User *user)
{
if(charOnline.count(user) > 0)
{
charOnline[user]->user = NULL;
charOnline.erase(user);
}
}
QString RPGModule::getTerrainName(int type)
{
switch(type)
{
case FOREST :
return QString("the forest");
case MOUNTAINS :
return QString("the mountains");
case PLAINS :
return QString("the plains");
case ROAD :
return QString("a road");
case VILLAGE :
return QString("a village");
default :
return QString("Hell");
}
}
Village* RPGModule::getVillage(RPGCharacter *c)
{
for(Village &v : villages)
{
if(v.x == c->x && v.y == c->y)
return &v;
}
return NULL;
}
QString RPGModule::lookAt(RPGCharacter *c, QString target)
{
if(target.compare("around") == 0)
{
int terrain = WORLDMAP[c->y][c->x];
if(terrain == VILLAGE)
{
Village *v = getVillage(c);
if(v == NULL)
return QString("%1 is in an unknown village").arg(c->pseudo);
QString str = QString("%1 is in %2").arg(c->pseudo).arg(v->name);
QString evStr;
bool first = true;
for(Event &e : v->events)
{
if(first)
first = false;
else
evStr += ", ";
evStr += e.name;
}
if(!first)
str += ", you can see " + evStr;
return str;
}
else
return QString("%1 is in %2").arg(c->pseudo).arg(getTerrainName(terrain));
}
else if(target.compare("north") == 0 || target.compare("n") == 0)
return QString("%1 looks north and sees %2").arg(c->pseudo).arg(getTerrainName(WORLDMAP[c->y-1][c->x]));
else if(target.compare("south") == 0 || target.compare("s") == 0)
return QString("%1 looks south and sees %2").arg(c->pseudo).arg(getTerrainName(WORLDMAP[c->y+1][c->x]));
else if(target.compare("west") == 0 || target.compare("w") == 0)
return QString("%1 looks west and sees %2").arg(c->pseudo).arg(getTerrainName(WORLDMAP[c->y][c->x-1]));
else if(target.compare("east") == 0 || target.compare("e") == 0)
return QString("%1 looks east and sees %2").arg(c->pseudo).arg(getTerrainName(WORLDMAP[c->y][c->x+1]));
else
return QString("%1 is not a valid target").arg(target);
}
QString RPGModule::eventInteract(RPGCharacter *c, QString target)
{
Village *v = getVillage(c);
if(v != NULL)
{
for(Event &e : v->events)
{
if(e.name.compare(target) == 0)
{
return e.description;
}
}
}
return QString("%1 is not a valid target").arg(target);
}
QString RPGModule::playerTravel(RPGCharacter *c, QString dir, bool repeat)
{
char terrainType = WORLDMAP[c->y][c->x];
QString direction;
QString currentArea = getTerrainName(terrainType);
bool blocked = false;
int dist = 0;
do
{
if(dir.compare("north") == 0 || dir.compare("n") == 0)
{
bool isDiff = repeat && terrainType != WORLDMAP[c->y-1][c->x];
if(c->y == 0 || (isDiff && dist != 0))
blocked = true;
else
{
if(isDiff)
blocked = true;
c->y -= 1;
++dist;
}
direction = "north";
}
else if(dir.compare("south") == 0 || dir.compare("s") == 0)
{
bool isDiff = repeat && terrainType != WORLDMAP[c->y+1][c->x];
if(c->y == 24 || (isDiff && dist != 0))
blocked = true;
else
{
if(isDiff)
blocked = true;
c->y += 1;
++dist;
}
direction = "south";
}
else if(dir.compare("west") == 0 || dir.compare("w") == 0)
{
bool isDiff = repeat && terrainType != WORLDMAP[c->y][c->x-1];
if(c->x == 0 || (isDiff && dist != 0))
blocked = true;
else
{
if(isDiff)
blocked = true;
c->x -= 1;
++dist;
}
direction = "west";
}
else if(dir.compare("east") == 0 || dir.compare("e") == 0)
{
bool isDiff = repeat && terrainType != WORLDMAP[c->y][c->x+1];
if(c->x == 24 || (isDiff && dist != 0))
blocked = true;
else
{
if(isDiff)
blocked = true;
c->x += 1;
++dist;
}
direction = "east";
}
else
return QString("%1 is not a valid direction, use : north, south, west, east").arg(dir);
}
while(!blocked && repeat);
if(blocked)
{
if(repeat)
{
if(dist > 1)
return QString("%1 travels %2 during %3 hours through %4")
.arg(c->pseudo).arg(direction).arg(dist).arg(currentArea);
else {}
}
else
return QString("%1 cannot go %2, a hill is blocking his way").arg(c->pseudo).arg(direction);
}
char newTerrainType = WORLDMAP[c->y][c->x];
if(terrainType == newTerrainType)
return QString("%1 is traveling %2 and is still in %3").arg(c->pseudo).arg(direction).arg(currentArea);
else
return QString("%1 is traveling %2, leaving %3 and entering %4")
.arg(c->pseudo).arg(direction).arg(currentArea).arg(getTerrainName(WORLDMAP[c->y][c->x]));
}
bool RPGModule::messageHandler(Message msg)
{
User* src = getUsers()->getFromNick(msg.nick);
if(msg.command.compare(QString("PRIVMSG"), Qt::CaseInsensitive) == 0)
{
if(msg.args.startsWith("!rpg register") && !msg.target.contains(getChan()))
{
QStringList paramList = msg.args.split(' ');
if(paramList.size() != 4)
answer = privateSay("usage : !rpg register [name of character] [password]", msg.nick);
else
{
if(charList.get(paramList[2].toStdString()) != NULL)
answer = privateSay(QString("ERROR : Character name \"%1\" already exists").arg(paramList[2]), msg.nick);
else
{
answer = privateSay(QString("successfully created the character \"%1\"").arg(paramList[2]), msg.nick);
charList.add(new RPGCharacter(paramList[2], paramList[3]));
}
}
return true;
}
else if(msg.args.startsWith("!rpg join") && !msg.target.contains(getChan()))
{
QStringList paramList = msg.args.split(' ');
if(paramList.size() != 4)
answer = privateSay("usage : !rpg join [name of character] [password]", msg.nick);
else
{
RPGCharacter *c = charList.get(paramList[2].toStdString());
if(c != NULL)
{
if(c->password.compare(paramList[3]) == 0)
{
playerJoin(getUsers()->getFromNick(msg.nick), c);
answer = say(QString("%1 joins the RPG as %2").arg(msg.nick).arg(paramList[2]));
}
else
answer = privateSay(QString("ERROR : Wrong password"), msg.nick);
}
else
answer = privateSay(QString("ERROR : Character name \"%1\" does not exists").arg(paramList[2]), msg.nick);
}
return true;
}
else if(msg.args.startsWith("!rpg delete") && !msg.target.contains(getChan()))
{
QStringList paramList = msg.args.split(' ');
if(paramList.size() != 4)
answer = privateSay("usage : !rpg delete [name of character] [password]", msg.nick);
else
{
RPGCharacter *c = charList.get(paramList[2].toStdString());
if(c != NULL)
{
if(c->password.compare(paramList[3]) == 0)
{
charOnline.erase(c->user);
charList.erase(paramList[2].toStdString());
answer = say(QString("Character %2 has been deleted").arg(paramList[2]));
}
else
answer = privateSay(QString("ERROR : Wrong password"), msg.nick);
}
else
answer = privateSay(QString("ERROR : Character name \"%1\" does not exists").arg(paramList[2]), msg.nick);
}
return true;
}
else if(msg.args.compare("!rpg leave") == 0)
{
if(charOnline.count(src) > 0)
{
answer = say(QString("%1 (%2) left the RPG").arg(charOnline[src]->pseudo).arg(src->getNick()));
playerLeave(src);
return true;
}
}
else if(msg.args.compare("!rpg list") == 0)
{
answer = QString("");
bool hasPeople = false;
for(auto it : charOnline)
{
hasPeople = true;
RPGCharacter *c = it.second;
answer += say(QString("%1 [lvl %2] (%3)").arg(c->pseudo).arg(c->level).arg(c->user->getNick()));
}
return hasPeople;
}
else if(msg.args.compare("!rpg stats") == 0)
{
if(charOnline.count(src) > 0)
{
RPGCharacter *c = charOnline[src];
answer = say(QString("%1 is level %2 (%3 xp)").arg(c->pseudo).arg(c->level).arg(c->xp));
return true;
}
}
else if(msg.args.compare("!rpg reset") == 0 && src->isOp())
{
charList.data.clear();
charList.names.clear();
answer = say("cleared character database");
return true;
}
else if(msg.args.compare("!rpg save") == 0)
{
saveCharacters();
answer = say("saved RPG characters");
return true;
}
else if(msg.args.startsWith("go "))
{
QStringList paramList = msg.args.split(' ');
if(charOnline.count(src) > 0)
{
if(paramList.size() == 2)
{
answer = say(playerTravel(charOnline[src], paramList[1], false));
return true;
}
else if(paramList.size() == 3 && paramList[1].compare("to") == 0)
{
answer = say(eventInteract(charOnline[src], paramList[2]));
return true;
}
}
}
else if(msg.args.startsWith("travel "))
{
QStringList paramList = msg.args.split(' ');
if(charOnline.count(src) > 0 && paramList.size() == 2)
{
answer = say(playerTravel(charOnline[src], paramList[1], true));
return true;
}
}
else if(msg.args.startsWith("look "))
{
QStringList paramList = msg.args.split(' ');
if(charOnline.count(src) > 0 && paramList.size() == 2)
{
answer = say(lookAt(charOnline[src], paramList[1]));
return true;
}
}
else if(msg.args.compare("!rpg help") == 0)
{
answer = privateSay("Commands : register, join, delete, leave, save, stats, list", msg.nick);
answer += privateSay("Create new character (works only in private message) : !rpg register [name of character] [password]", msg.nick);
answer += privateSay("Join game with character (works only in private message) : !rpg join [name of character] [password]", msg.nick);
answer += privateSay("Delete character (works only in private message) : !rpg delete [name of character] [password]", msg.nick);
answer += privateSay("leave the game : !rpg leave", msg.nick);
answer += privateSay("show your stats : !rpg stats", msg.nick);
answer += privateSay("show all in-game players : !rpg list", msg.nick);
return true;
}
}
else if(msg.command.compare("QUIT", Qt::CaseInsensitive) == 0)
playerLeave(src);
else if(msg.command.compare("PART", Qt::CaseInsensitive) == 0)
playerLeave(src);
else if(msg.command.compare("KICK", Qt::CaseInsensitive) == 0)
playerLeave(getUsers()->getFromNick(msg.target2));
return false;
}