ACF9: Fix cannibal talking to himself in cut scene if playing with 3 natives instead of 4
/*
* Hedgewars, a free turn based strategy game
* Copyright (c) 2009 Martin Minarik <ttsmj@pokec.sk>
* Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
*
* 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; version 2 of the License
*
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QStringList>
#include <QLineEdit>
#include "hwform.h"
#include "DataManager.h"
#include "namegen.h"
HWNamegen::HWNamegen() {}
QList<QStringList> HWNamegen::TypesTeamnames;
QList<QStringList> HWNamegen::TypesHatnames;
bool HWNamegen::typesAvailable = false;
void HWNamegen::teamRandomTeamName(HWTeam & team)
{
QString newName = getRandomTeamName(-1);
if(!newName.isNull())
team.setName(newName);
}
void HWNamegen::teamRandomFlag(HWTeam & team, bool withDLC)
{
team.setFlag(getRandomFlag(withDLC));
}
void HWNamegen::teamRandomVoice(HWTeam & team, bool withDLC)
{
team.setVoicepack(getRandomVoice(withDLC));
}
void HWNamegen::teamRandomGrave(HWTeam & team, bool withDLC)
{
team.setGrave(getRandomGrave(withDLC));
}
void HWNamegen::teamRandomFort(HWTeam & team, bool withDLC)
{
team.setFort(getRandomFort(withDLC));
}
void HWNamegen::teamRandomEverything(HWTeam & team)
{
// load types if not already loaded
if (!typesAvailable)
if (!loadTypes())
return; // abort if loading failed
// abort if there are no hat types
if (TypesHatnames.size() <= 0)
return;
// the hat will influence which names the hogs get
int kind = (rand()%(TypesHatnames.size()));
team.setGrave(getRandomGrave());
team.setFort(getRandomFort());
team.setFlag(getRandomFlag());
team.setVoicepack(getRandomVoice());
QStringList dicts;
QStringList dict;
// Randomness mode:
// 0: Themed hats (from types.ini)
// 1: Equal hats for all
// 2: Random hat for each hedgehog
int r = rand() % 10;
int randomMode;
if (r <= 4) // 0-4 (50%)
randomMode = 0;
else if (r <= 8) // 5-8 (40%)
randomMode = 1;
else // 9 (10%)
randomMode = 2;
// Generate random hats
for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
{
HWHog hh = team.hedgehog(i);
if (randomMode == 0)
{
hh.Hat = TypesHatnames[kind][rand()%(TypesHatnames[kind].size())];
}
else if (randomMode == 1)
{
if (i == 0)
{
hh.Hat = getRandomHat();
}
else
{
hh.Hat = team.hedgehog(i-1).Hat;
}
}
else if (randomMode == 2)
{
hh.Hat = getRandomHat();
}
team.setHedgehog(i,hh);
// there is a chance that this hog has the same hat as the previous one
// let's reuse the hat-specific dict in this case
if ((i == 0) || (team.hedgehog(i).Hat != team.hedgehog(i-1).Hat))
{
dicts = dictsForHat(team.hedgehog(i).Hat);
dict = dictContents(dicts[rand()%(dicts.size())]);
}
// give each hedgehog a random name
HWNamegen::teamRandomHogName(team,i,dict);
}
// If using themed hats, use themed team name.
// Otherwise, only use “generic” team names from the first team
// in types.txt.
if (randomMode == 0)
team.setName(getRandomTeamName(kind));
else
team.setName(getRandomTeamName(0));
}
// Set random hats for entire team
void HWNamegen::teamRandomHats(HWTeam & team, bool withDLC)
{
// 50% chance that all hogs are set to the same hat.
// 50% chance that each hog gets a random head individually.
bool sameHogs = (rand()%2) == 0;
for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
{
HWHog hh = team.hedgehog(i);
if (sameHogs and i > 0)
hh.Hat = team.hedgehog(i-1).Hat;
else
hh.Hat = getRandomHat(withDLC);
team.setHedgehog(i, hh);
}
}
void HWNamegen::teamRandomHat(HWTeam & team, const int HedgehogNumber, bool withDLC)
{
HWHog hh = team.hedgehog(HedgehogNumber);
hh.Hat = getRandomHat(withDLC);
team.setHedgehog(HedgehogNumber, hh);
}
void HWNamegen::teamRandomHat(HWTeam & team, const int HedgehogNumber, const QStringList & dict)
{
HWHog hh = team.hedgehog(HedgehogNumber);
hh.Name = dict[rand()%(dict.size())];
team.setHedgehog(HedgehogNumber, hh);
}
void HWNamegen::teamRandomHogNames(HWTeam & team)
{
QStringList dicts, dict;
for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
{
// there is a chance that this hog has the same hat as the previous one
// let's reuse the hat-specific dict in this case
if ((i == 0) || (team.hedgehog(i).Hat != team.hedgehog(i-1).Hat))
{
dicts = dictsForHat(team.hedgehog(i).Hat);
dict = dictContents(dicts[rand()%(dicts.size())]);
}
// give each hedgehog a random name
HWNamegen::teamRandomHogName(team,i,dict);
}
}
void HWNamegen::teamRandomHogName(HWTeam & team, const int HedgehogNumber)
{
QStringList dicts = dictsForHat(team.hedgehog(HedgehogNumber).Hat);
QStringList dict = dictContents(dicts[rand()%(dicts.size())]);
teamRandomHogName(team, HedgehogNumber, dict);
}
void HWNamegen::teamRandomHogName(HWTeam & team, const int HedgehogNumber, const QStringList & dict)
{
QStringList namesDict = dict;
for(int i = 0; i < HEDGEHOGS_PER_TEAM; i++)
{
namesDict.removeOne(team.hedgehog(i).Name);
}
// if our dict doesn't have any new names we'll have to use duplicates
if (namesDict.size() < 1)
namesDict = dict;
HWHog hh = team.hedgehog(HedgehogNumber);
hh.Name = namesDict[rand()%(namesDict.size())];
team.setHedgehog(HedgehogNumber, hh);
}
QStringList HWNamegen::dictContents(const QString filename)
{
QStringList list;
// find .txt to load the names from
QFile file(QString("physfs://Names/%1.txt").arg(filename));
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream in(&file);
QString line;
do
{
line = in.readLine();
if(!line.isEmpty())
list.append(line);
} while (!line.isNull());
}
if (list.size() == 0)
list.append(filename);
return list;
}
QStringList HWNamegen::dictsForHat(const QString hatname)
{
QStringList list;
// Find and check .cfg to load the dicts from
QString path = QString("physfs://Names/%1.cfg").arg(hatname);
QFileInfo check_file(path);
// Note: The .cfg file is optional; a fallback mechanism is in place (see below)
// Check if file exists to prevent PhysFS from complaining in console so much
if (check_file.exists() && check_file.isFile())
{
QFile file(path);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream in(&file);
QString line;
do
{
line = in.readLine();
if(!line.isEmpty())
list.append(line);
} while (!line.isNull());
}
}
// Use Data/Names/generic.cfg by default
if (list.size() == 0)
list.append(QString("generic"));
return list;
}
// loades types from ini files. returns true on success.
bool HWNamegen::loadTypes()
{
typesAvailable = false;
// find .ini to load the names from
QFile * file = new QFile(QString("physfs://Names/types.ini"));
if (file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text))
{
int counter = 0; //counter starts with 0 (teamnames mode)
TypesTeamnames.append(QStringList());
TypesHatnames.append(QStringList());
QTextStream in(file);
while (!in.atEnd())
{
QString line = in.readLine();
if (line == QString("#####"))
{
counter++; //toggle mode (teamnames || hats)
if ((counter%2) == 0)
{
TypesTeamnames.append(QStringList());
TypesHatnames.append(QStringList());
}
}
else if ((line == QString("*****")) || (line == QString("*END*")))
{
typesAvailable = true;
return true; // bye bye
}
else
{
if ((counter%2) == 0)
{
// even => teamnames mode
TypesTeamnames[(counter/2)].append(line);
}
else
{
// odd => hats mode
TypesHatnames[((counter-1)/2)].append(line);
}
}
}
typesAvailable = true;
}
// this QFile isn't needed any further
delete file;
return typesAvailable;
}
/* Generates a random team name.
kind: Use to select a team name out of a group (types.ini).
Use a negative value if you don't care.
This function may return a null QString on error(this should never happen). */
QString HWNamegen::getRandomTeamName(int kind)
{
// load types if not already loaded
if (!typesAvailable)
if (!loadTypes())
return QString(); // abort if loading failed
// abort if there are no hat types
if (TypesHatnames.size() <= 0)
return QString();
if(kind < 0)
kind = (rand()%(TypesHatnames.size()));
if (TypesTeamnames[kind].size() > 0)
return TypesTeamnames[kind][rand()%(TypesTeamnames[kind].size())];
else
return QString();
}
QString HWNamegen::getRandomHat(bool withDLC)
{
QStringList Hats;
// list all available hats
Hats.append(DataManager::instance().entryList(
"Graphics/Hats",
QDir::Files,
QStringList("*.png"),
withDLC
).replaceInStrings(QRegExp("\\.png$"), "")
);
if(Hats.size()==0)
{
// TODO do some serious error handling
return "Error";
}
// pick a random hat
return Hats[rand()%(Hats.size())];
}
QString HWNamegen::getRandomGrave(bool withDLC)
{
QStringList Graves;
//list all available Graves
Graves.append(DataManager::instance().entryList(
"Graphics/Graves",
QDir::Files,
QStringList("*.png"),
withDLC
).replaceInStrings(QRegExp("\\.png$"), "")
);
if(Graves.size()==0)
{
// TODO do some serious error handling
return "Error";
}
//pick a random grave
return Graves[rand()%(Graves.size())];
}
QString HWNamegen::getRandomFlag(bool withDLC)
{
QStringList Flags;
//list all available flags
Flags.append(DataManager::instance().entryList(
"Graphics/Flags",
QDir::Files,
QStringList("*.png"),
withDLC
).replaceInStrings(QRegExp("\\.png$"), "")
);
//remove internal flags
Flags.removeAll("cpu");
Flags.removeAll("cpu_plain");
if(Flags.size()==0)
{
// TODO do some serious error handling
return "Error";
}
//pick a random flag
return Flags[rand()%(Flags.size())];
}
QString HWNamegen::getRandomFort(bool withDLC)
{
QStringList Forts;
//list all available Forts
Forts.append(DataManager::instance().entryList(
"Forts",
QDir::Files,
QStringList("*L.png"),
withDLC
).replaceInStrings(QRegExp("L\\.png$"), "")
);
if(Forts.size()==0)
{
// TODO do some serious error handling
return "Error";
}
//pick a random fort
return Forts[rand()%(Forts.size())];
}
QString HWNamegen::getRandomVoice(bool withDLC)
{
QStringList Voices;
//list all available voices
Voices.append(DataManager::instance().entryList(
"Sounds/voices",
QDir::Dirs | QDir::NoDotAndDotDot,
QStringList("*"),
withDLC));
if(Voices.size()==0)
{
// TODO do some serious error handling
return "Error";
}
//pick a random voice
return Voices[rand()%(Voices.size())];
}