349 lines
10 KiB
C++
349 lines
10 KiB
C++
/* --------------------------------------------------------------------
|
|
EXTREME TUXRACER
|
|
|
|
Copyright (C) 2010 Extreme Tuxracer Team
|
|
|
|
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.
|
|
---------------------------------------------------------------------*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <etr_config.h>
|
|
#endif
|
|
|
|
#include "game_ctrl.h"
|
|
#include "spx.h"
|
|
#include "course.h"
|
|
#include "env.h"
|
|
#include "audio.h"
|
|
#include "textures.h"
|
|
#include "tux.h"
|
|
#include "physics.h"
|
|
|
|
// --------------------------------------------------------------------
|
|
// administration of events and cups
|
|
// --------------------------------------------------------------------
|
|
|
|
CEvents Events;
|
|
|
|
bool CEvents::LoadEventList() {
|
|
CSPList list(256);
|
|
|
|
if (!list.Load(param.common_course_dir, "events.lst")) {
|
|
Message("could not load events.lst");
|
|
return false;
|
|
}
|
|
|
|
// pass 1: races
|
|
for (size_t i=0; i<list.Count(); i++) {
|
|
const string& line = list.Line(i);
|
|
int type = SPIntN(line, "struct", -1);
|
|
if (type == 0) {
|
|
RaceList.push_back(TRace(
|
|
Course.GetCourse(SPStrN(line, "course")),
|
|
Env.GetLightIdx(SPStrN(line, "light")),
|
|
SPIntN(line, "snow", 0),
|
|
SPIntN(line, "wind", 0),
|
|
SPVector3i(line, "herring"),
|
|
SPVector3d(line, "time"),
|
|
Music.GetThemeIdx(SPStrN(line, "theme", "normal"))));
|
|
}
|
|
}
|
|
list.MakeIndex(RaceIndex, "race");
|
|
|
|
// pass 2: cups
|
|
for (size_t i=0; i<list.Count(); i++) {
|
|
const string& line = list.Line(i);
|
|
int type = SPIntN(line, "struct", -1);
|
|
if (type == 1) {
|
|
CupList.push_back(TCup(
|
|
SPStrN(line, "cup", errorString),
|
|
SPStrN(line, "name", "unknown"),
|
|
SPStrN(line, "desc", "unknown")));
|
|
int num = SPIntN(line, "num", 0);
|
|
CupList.back().races.resize(num);
|
|
for (int ii=0; ii<num; ii++) {
|
|
string race = SPStrN(line, Int_StrN(ii+1));
|
|
CupList.back().races[ii] = &RaceList[GetRaceIdx(race)];
|
|
}
|
|
}
|
|
}
|
|
list.MakeIndex(CupIndex, "cup");
|
|
|
|
// pass 3: events
|
|
for (size_t i=0; i<list.Count(); i++) {
|
|
const string& line = list.Line(i);
|
|
int type = SPIntN(line, "struct", -1);
|
|
if (type == 2) {
|
|
EventList.push_back(TEvent(SPStrN(line, "name", "unknown")));
|
|
int num = SPIntN(line, "num", 0);
|
|
EventList.back().cups.resize(num);
|
|
for (int ii=0; ii<num; ii++) {
|
|
string cup = SPStrN(line, Int_StrN(ii+1));
|
|
EventList.back().cups[ii] = &CupList[GetCupIdx(cup)];
|
|
}
|
|
}
|
|
}
|
|
list.MakeIndex(EventIndex, "event");
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t CEvents::GetRaceIdx(const string& race) const {
|
|
return RaceIndex.at(race);
|
|
}
|
|
|
|
size_t CEvents::GetCupIdx(const string& cup) const {
|
|
return CupIndex.at(cup);
|
|
}
|
|
|
|
size_t CEvents::GetEventIdx(const string& event) const {
|
|
return EventIndex.at(event);
|
|
}
|
|
|
|
const string& CEvents::GetCup(size_t event, size_t cup) const {
|
|
if (event >= EventList.size()) return errorString;
|
|
if (cup >= EventList[event].cups.size()) return errorString;
|
|
return EventList[event].cups[cup]->cup;
|
|
}
|
|
|
|
const string& CEvents::GetCupTrivialName(size_t event, size_t cup) const {
|
|
if (event >= EventList.size()) return errorString;
|
|
if (cup >= EventList[event].cups.size()) return errorString;
|
|
return EventList[event].cups[cup]->name;
|
|
}
|
|
|
|
void CEvents::MakeUnlockList(const string& unlockstr) {
|
|
for (size_t event=0; event<EventList.size(); event++) {
|
|
for (size_t cup=0; cup<EventList[event].cups.size(); cup++) {
|
|
EventList[event].cups[cup]->Unlocked = false;
|
|
}
|
|
}
|
|
for (size_t event=0; event<EventList.size(); event++) {
|
|
for (size_t cup=0; cup<EventList[event].cups.size(); cup++) {
|
|
const string& cp = GetCup(event, cup);
|
|
bool passed = SPosN(unlockstr, cp) != string::npos;
|
|
if (cup < 1) EventList[event].cups[0]->Unlocked = true;
|
|
if (passed) {
|
|
EventList[event].cups[cup]->Unlocked = true;
|
|
if (cup+1 < EventList[event].cups.size())
|
|
EventList[event].cups[cup+1]->Unlocked = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CEvents::IsUnlocked(size_t event, size_t cup) const {
|
|
if (event >= EventList.size()) return false;
|
|
if (cup >= EventList[event].cups.size()) return false;
|
|
return EventList[event].cups[cup]->Unlocked;
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// player administration
|
|
// --------------------------------------------------------------------
|
|
|
|
CPlayers Players;
|
|
|
|
CPlayers::~CPlayers() {
|
|
ResetControls();
|
|
for (size_t i = 0; i < avatars.size(); i++)
|
|
delete avatars[i].texture;
|
|
}
|
|
|
|
void CPlayers::AddPlayer(const string& name, const string& avatar) {
|
|
plyr.push_back(TPlayer(name, FindAvatar(avatar)));
|
|
}
|
|
|
|
void CPlayers::SetDefaultPlayers() {
|
|
plyr.push_back(TPlayer("Racer", FindAvatar("avatar01.png")));
|
|
plyr.push_back(TPlayer("Bunny", FindAvatar("avatar02.png")));
|
|
}
|
|
|
|
bool CPlayers::LoadPlayers() {
|
|
if (FileExists(param.config_dir, "players") == false) {
|
|
SetDefaultPlayers();
|
|
Message("file 'players' does not exist, set default players");
|
|
return false;
|
|
}
|
|
|
|
CSPList list(MAX_PLAYERS);
|
|
if (list.Load(param.config_dir, "players") == false) {
|
|
SetDefaultPlayers();
|
|
Message("could not load players list, set default players");
|
|
return false;
|
|
}
|
|
|
|
g_game.start_player = 0;
|
|
plyr.resize(list.Count());
|
|
for (size_t i=0; i<list.Count(); i++) {
|
|
const string& line = list.Line(i);
|
|
plyr[i].name = SPStrN(line, "name", "unknown");
|
|
plyr[i].funlocked = SPStrN(line, "unlocked");
|
|
plyr[i].avatar = FindAvatar(SPStrN(line, "avatar"));
|
|
plyr[i].ctrl = NULL;
|
|
int active = SPIntN(line, "active", 0);
|
|
if (active > 0) g_game.start_player = plyr.size()-1;
|
|
}
|
|
if (plyr.empty()) {
|
|
SetDefaultPlayers();
|
|
Message("player file doesn't contain a player, set default players");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CPlayers::SavePlayers() const {
|
|
string playerfile = param.config_dir + SEP "players";
|
|
CSPList list(plyr.size());
|
|
for (size_t i=0; i<plyr.size(); i++) {
|
|
string item = "*[name]" + plyr[i].name;
|
|
item +="[avatar]" + plyr[i].avatar->filename;
|
|
item += "[unlocked]" + plyr[i].funlocked;
|
|
if (&plyr[i] == g_game.player) item += "[active]1";
|
|
else item += "[active]0";
|
|
list.Add(item);
|
|
}
|
|
list.Save(playerfile);
|
|
}
|
|
|
|
const TAvatar* CPlayers::FindAvatar(const string& name) {
|
|
for (size_t i = 0; i < avatars.size(); i++)
|
|
if (avatars[i].filename == name)
|
|
return &avatars[i];
|
|
return 0;
|
|
}
|
|
|
|
void CPlayers::AddPassedCup(const string& cup) {
|
|
if (SPIntN(g_game.player->funlocked, cup, -1) > 0) return;
|
|
g_game.player->funlocked += " ";
|
|
g_game.player->funlocked += cup;
|
|
}
|
|
|
|
void CPlayers::ResetControls() {
|
|
for (size_t i=0; i<plyr.size(); i++) {
|
|
delete plyr[i].ctrl;
|
|
plyr[i].ctrl = NULL;
|
|
}
|
|
}
|
|
|
|
// called in module regist.cpp:
|
|
void CPlayers::AllocControl(size_t player) {
|
|
if (player >= plyr.size()) return;
|
|
if (plyr[player].ctrl != NULL) return;
|
|
plyr[player].ctrl = new CControl;
|
|
}
|
|
|
|
// ----------------------- avatars ------------------------------------
|
|
|
|
void CPlayers::LoadAvatars() {
|
|
CSPList list(MAX_AVATARS);
|
|
|
|
if (!list.Load(param.player_dir, "avatars.lst")) {
|
|
Message("could not load avators.lst");
|
|
return;
|
|
}
|
|
|
|
for (size_t i=0; i<list.Count(); i++) {
|
|
const string& line = list.Line(i);
|
|
string filename = SPStrN(line, "file", "unknown");
|
|
TTexture* texture = new TTexture();
|
|
if (texture && texture->Load(param.player_dir, filename)) {
|
|
avatars.push_back(TAvatar(filename, texture));
|
|
} else
|
|
delete texture;
|
|
}
|
|
}
|
|
|
|
TTexture* CPlayers::GetAvatarTexture(size_t avatar) const {
|
|
if (avatar >= avatars.size()) return 0;
|
|
return avatars[avatar].texture;
|
|
}
|
|
|
|
const string& CPlayers::GetDirectAvatarName(size_t avatar) const {
|
|
if (avatar >= avatars.size()) return emptyString;
|
|
return avatars[avatar].filename;
|
|
}
|
|
|
|
// ********************************************************************
|
|
// Character Administration
|
|
// ********************************************************************
|
|
|
|
CKeyframe* TCharacter::GetKeyframe(TFrameType type) {
|
|
if (type < 0 || type >= NUM_FRAME_TYPES) return NULL;
|
|
return &frames[type];
|
|
}
|
|
|
|
|
|
CCharacter Char;
|
|
|
|
static const string char_type_index = "[spheres]0[3d]1";
|
|
|
|
CCharacter::~CCharacter() {
|
|
for (size_t i = 0; i < CharList.size(); i++) {
|
|
delete CharList[i].preview;
|
|
delete CharList[i].shape;
|
|
}
|
|
}
|
|
|
|
void CCharacter::LoadCharacterList() {
|
|
CSPList list(MAX_CHARACTERS);
|
|
|
|
if (!list.Load(param.char_dir, "characters.lst")) {
|
|
Message("could not load characters.lst");
|
|
return;
|
|
}
|
|
|
|
CharList.resize(list.Count());
|
|
for (size_t i=0; i<list.Count(); i++) {
|
|
const string& line = list.Line(i);
|
|
CharList[i].name = SPStrN(line, "name");
|
|
CharList[i].dir = SPStrN(line, "dir");
|
|
string typestr = SPStrN(line, "type", "unknown");
|
|
CharList[i].type = SPIntN(char_type_index, typestr, -1);
|
|
|
|
string charpath = param.char_dir + SEP + CharList[i].dir;
|
|
if (DirExists(charpath.c_str())) {
|
|
string previewfile = charpath + SEP "preview.png";
|
|
|
|
TCharacter* ch = &CharList[i];
|
|
ch->preview = new TTexture();
|
|
if (!ch->preview->LoadMipmap(previewfile, false)) {
|
|
Message("could not load previewfile of character");
|
|
// texid = Tex.TexID (NO_PREVIEW);
|
|
}
|
|
|
|
|
|
ch->shape = new CCharShape;
|
|
if (ch->shape->Load(charpath, "shape.lst", false) == false) {
|
|
delete ch->shape;
|
|
ch->shape = NULL;
|
|
Message("could not load character shape");
|
|
}
|
|
|
|
ch->frames[0].Load(charpath, "start.lst");
|
|
ch->finishframesok = true;
|
|
ch->frames[1].Load(charpath, "finish.lst");
|
|
if (ch->frames[1].loaded == false) ch->finishframesok = false;
|
|
ch->frames[2].Load(charpath, "wonrace.lst");
|
|
if (ch->frames[2].loaded == false) ch->finishframesok = false;
|
|
ch->frames[3].Load(charpath, "lostrace.lst");
|
|
if (ch->frames[3].loaded == false) ch->finishframesok = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CCharacter::FreeCharacterPreviews() {
|
|
for (size_t i=0; i<CharList.size(); i++) {
|
|
delete CharList[i].preview;
|
|
CharList[i].preview = 0;
|
|
}
|
|
}
|