|
|
|
|
/***************************************************************************
|
|
|
|
|
* Copyright (C) 2003 by Ian Wadham and Marco Kr<EFBFBD>ger *
|
|
|
|
|
* ianw2@optusnet.com.au *
|
|
|
|
|
* *
|
|
|
|
|
* 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. *
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
#ifdef KGR_PORTABLE
|
|
|
|
|
// If compiling for portability, redefine KDE's i18n.
|
|
|
|
|
#define i18n tr
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "kgrconsts.h"
|
|
|
|
|
#include "kgrobject.h"
|
|
|
|
|
#include "kgrfigure.h"
|
|
|
|
|
#include "kgrcanvas.h"
|
|
|
|
|
#include "kgrdialog.h"
|
|
|
|
|
|
|
|
|
|
#include "kgrgame.h"
|
|
|
|
|
|
|
|
|
|
// Obsolete - #include <iostream.h>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
|
#include <kstdguiitem.h>
|
|
|
|
|
|
|
|
|
|
#ifndef KGR_PORTABLE
|
|
|
|
|
#include <tdeglobalsettings.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/*********************** KGOLDRUNNER GAME CLASS *************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
KGrGame::KGrGame (KGrCanvas * theView, TQString theSystemDir, TQString theUserDir)
|
|
|
|
|
{
|
|
|
|
|
view = theView;
|
|
|
|
|
systemDataDir = theSystemDir;
|
|
|
|
|
userDataDir = theUserDir;
|
|
|
|
|
|
|
|
|
|
// Set the game-editor OFF, but available.
|
|
|
|
|
editMode = FALSE;
|
|
|
|
|
paintEditObj = FALSE;
|
|
|
|
|
editObj = BRICK;
|
|
|
|
|
shouldSave = FALSE;
|
|
|
|
|
|
|
|
|
|
enemies.setAutoDelete(TRUE);
|
|
|
|
|
|
|
|
|
|
hero = new KGrHero (view, 0, 0); // The hero is born ... Yay !!!
|
|
|
|
|
hero->setPlayfield (&playfield);
|
|
|
|
|
|
|
|
|
|
setBlankLevel (TRUE); // Fill the playfield with blank walls.
|
|
|
|
|
|
|
|
|
|
enemy = NULL;
|
|
|
|
|
newLevel = TRUE; // Next level will be a new one.
|
|
|
|
|
loading = TRUE; // Stop input until it is loaded.
|
|
|
|
|
|
|
|
|
|
modalFreeze = FALSE;
|
|
|
|
|
messageFreeze = FALSE;
|
|
|
|
|
|
|
|
|
|
connect (hero, TQT_SIGNAL (gotNugget(int)), TQT_SLOT (incScore(int)));
|
|
|
|
|
connect (hero, TQT_SIGNAL (caughtHero()), TQT_SLOT (herosDead()));
|
|
|
|
|
connect (hero, TQT_SIGNAL (haveAllNuggets()), TQT_SLOT (showHiddenLadders()));
|
|
|
|
|
connect (hero, TQT_SIGNAL (leaveLevel()), TQT_SLOT (goUpOneLevel()));
|
|
|
|
|
|
|
|
|
|
dyingTimer = new TQTimer (this);
|
|
|
|
|
connect (dyingTimer, TQT_SIGNAL (timeout()), TQT_SLOT (finalBreath()));
|
|
|
|
|
|
|
|
|
|
// Get the mouse position every 40 msec. It is used to steer the hero.
|
|
|
|
|
mouseSampler = new TQTimer (this);
|
|
|
|
|
connect (mouseSampler, TQT_SIGNAL(timeout()), TQT_SLOT (readMousePos ()));
|
|
|
|
|
mouseSampler->start (40, FALSE);
|
|
|
|
|
|
|
|
|
|
srand(1); // initialisiere Random-Generator
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KGrGame::~KGrGame()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************************* GAME SELECTION PROCEDURES ************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::startLevelOne()
|
|
|
|
|
{
|
|
|
|
|
startLevel (SL_START, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::startAnyLevel()
|
|
|
|
|
{
|
|
|
|
|
startLevel (SL_ANY, level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::startNextLevel()
|
|
|
|
|
{
|
|
|
|
|
startLevel (SL_ANY, level + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::startLevel (int startingAt, int requestedLevel)
|
|
|
|
|
{
|
|
|
|
|
if (! saveOK (FALSE)) { // Check unsaved work.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Use dialog box to select game and level: startingAt = ID_FIRST or ID_ANY.
|
|
|
|
|
int selectedLevel = selectLevel (startingAt, requestedLevel);
|
|
|
|
|
if (selectedLevel > 0) { // If OK, start the selected game and level.
|
|
|
|
|
newGame (selectedLevel, selectedGame);
|
|
|
|
|
} else {
|
|
|
|
|
level = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************************ MAIN GAME EVENT PROCEDURES ************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::incScore (int n)
|
|
|
|
|
{
|
|
|
|
|
score = score + n; // SCORING: trap enemy 75, kill enemy 75,
|
|
|
|
|
emit showScore (score); // collect gold 250, complete the level 1500.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::herosDead()
|
|
|
|
|
{
|
|
|
|
|
if ((level < 1) || (lives <= 0))
|
|
|
|
|
return; // Game over: we are in the "ENDE" screen.
|
|
|
|
|
|
|
|
|
|
// Lose a life.
|
|
|
|
|
if (--lives > 0) {
|
|
|
|
|
// Still some life left, so PAUSE and then re-start the level.
|
|
|
|
|
emit showLives (lives);
|
|
|
|
|
KGrObject::frozen = TRUE; // Freeze the animation and let
|
|
|
|
|
dyingTimer->start (1500, TRUE); // the player see what happened.
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Game over: display the "ENDE" screen.
|
|
|
|
|
emit showLives (lives);
|
|
|
|
|
freeze();
|
|
|
|
|
TQString gameOver = "<NOBR><B>" + i18n("GAME OVER !!!") + "</B></NOBR>";
|
|
|
|
|
KGrMessage::information (view, collection->name, gameOver);
|
|
|
|
|
checkHighScore(); // Check if there is a high score for this game.
|
|
|
|
|
|
|
|
|
|
enemyCount = 0;
|
|
|
|
|
enemies.clear(); // Stop the enemies catching the hero again ...
|
|
|
|
|
view->deleteEnemySprites();
|
|
|
|
|
unfreeze(); // ... NOW we can unfreeze.
|
|
|
|
|
newLevel = TRUE;
|
|
|
|
|
level = 0;
|
|
|
|
|
loadLevel (level); // Display the "ENDE" screen.
|
|
|
|
|
newLevel = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::finalBreath()
|
|
|
|
|
{
|
|
|
|
|
// Fix bug 95202: Avoid re-starting if the player selected
|
|
|
|
|
// edit mode before the 1.5 seconds were up.
|
|
|
|
|
if (! editMode) {
|
|
|
|
|
enemyCount = 0; // Hero is dead: re-start the level.
|
|
|
|
|
loadLevel (level);
|
|
|
|
|
}
|
|
|
|
|
KGrObject::frozen = FALSE; // Unfreeze the game, but don't move yet.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showHiddenLadders()
|
|
|
|
|
{
|
|
|
|
|
int i,j;
|
|
|
|
|
for (i=1;i<21;i++)
|
|
|
|
|
for (j=1;j<29;j++)
|
|
|
|
|
if (playfield[j][i]->whatIam()==HLADDER)
|
|
|
|
|
((KGrHladder *)playfield[j][i])->showLadder();
|
|
|
|
|
view->updateCanvas();
|
|
|
|
|
initSearchMatrix();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::goUpOneLevel()
|
|
|
|
|
{
|
|
|
|
|
lives++; // Level completed: gain another life.
|
|
|
|
|
emit showLives (lives);
|
|
|
|
|
incScore (1500);
|
|
|
|
|
|
|
|
|
|
if (level >= collection->nLevels) {
|
|
|
|
|
freeze();
|
|
|
|
|
KGrMessage::information (view, collection->name,
|
|
|
|
|
i18n("<b>CONGRATULATIONS !!!!</b>"
|
|
|
|
|
"<p>You have conquered the last level in the %1 game !!</p>")
|
|
|
|
|
.arg("<b>\"" + collection->name + "\"</b>"));
|
|
|
|
|
checkHighScore(); // Check if there is a high score for this game.
|
|
|
|
|
|
|
|
|
|
unfreeze();
|
|
|
|
|
level = 0; // Game completed: display the "ENDE" screen.
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
level++; // Go up one level.
|
|
|
|
|
emit showLevel (level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enemyCount = 0;
|
|
|
|
|
enemies.clear();
|
|
|
|
|
view->deleteEnemySprites();
|
|
|
|
|
newLevel = TRUE;
|
|
|
|
|
loadLevel (level);
|
|
|
|
|
newLevel = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::loseNugget()
|
|
|
|
|
{
|
|
|
|
|
hero->loseNugget(); // Enemy trapped/dead and holding a nugget.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KGrHero * KGrGame::getHero()
|
|
|
|
|
{
|
|
|
|
|
return (hero); // Return a pointer to the hero.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int KGrGame::getLevel() // Return the current game-level.
|
|
|
|
|
{
|
|
|
|
|
return (level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::inMouseMode()
|
|
|
|
|
{
|
|
|
|
|
return (mouseMode); // Return TRUE if game is under mouse control.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::inEditMode()
|
|
|
|
|
{
|
|
|
|
|
return (editMode); // Return TRUE if the game-editor is active.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::isLoading()
|
|
|
|
|
{
|
|
|
|
|
return (loading); // Return TRUE if a level is being loaded.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::setMouseMode (bool on_off)
|
|
|
|
|
{
|
|
|
|
|
mouseMode = on_off; // Set Mouse OR keyboard control.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::freeze()
|
|
|
|
|
{
|
|
|
|
|
if ((! modalFreeze) && (! messageFreeze)) {
|
|
|
|
|
emit gameFreeze (TRUE); // Do visual feedback in the GUI.
|
|
|
|
|
}
|
|
|
|
|
KGrObject::frozen = TRUE; // Halt the game, by blocking all timer events.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::unfreeze()
|
|
|
|
|
{
|
|
|
|
|
if ((! modalFreeze) && (! messageFreeze)) {
|
|
|
|
|
emit gameFreeze (FALSE);// Do visual feedback in the GUI.
|
|
|
|
|
}
|
|
|
|
|
KGrObject::frozen = FALSE; // Restart the game. Because frozen == FALSE,
|
|
|
|
|
restart(); // the game goes on running after the next step.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::setMessageFreeze (bool on_off)
|
|
|
|
|
{
|
|
|
|
|
if (on_off) { // Freeze the game action during a message.
|
|
|
|
|
messageFreeze = FALSE;
|
|
|
|
|
if (! KGrObject::frozen) {
|
|
|
|
|
messageFreeze = TRUE;
|
|
|
|
|
freeze();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { // Unfreeze the game action after a message.
|
|
|
|
|
if (messageFreeze) {
|
|
|
|
|
unfreeze();
|
|
|
|
|
messageFreeze = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::setBlankLevel(bool playable)
|
|
|
|
|
{
|
|
|
|
|
for (int j=0;j<20;j++)
|
|
|
|
|
for (int i=0;i<28;i++) {
|
|
|
|
|
if (playable) {
|
|
|
|
|
//playfield[i+1][j+1] = new KGrFree (freebg, nuggetbg, false, view);
|
|
|
|
|
playfield[i+1][j+1] = new KGrFree (FREE,i+1,j+1,view);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
//playfield[i+1][j+1] = new KGrEditable (freebg, view);
|
|
|
|
|
playfield[i+1][j+1] = new KGrEditable (FREE);
|
|
|
|
|
view->paintCell (i+1, j+1, FREE);
|
|
|
|
|
}
|
|
|
|
|
editObjArray[i+1][j+1] = FREE;
|
|
|
|
|
}
|
|
|
|
|
for (int j=0;j<30;j++) {
|
|
|
|
|
//playfield[j][0]=new KGrBeton(TQPixmap ());
|
|
|
|
|
playfield[j][0]=new KGrObject (BETON);
|
|
|
|
|
editObjArray[j][0] = BETON;
|
|
|
|
|
//playfield[j][21]=new KGrBeton(TQPixmap ());
|
|
|
|
|
playfield[j][21]=new KGrObject (BETON);
|
|
|
|
|
editObjArray[j][21] = BETON;
|
|
|
|
|
}
|
|
|
|
|
for (int i=0;i<22;i++) {
|
|
|
|
|
//playfield[0][i]=new KGrBeton(TQPixmap ());
|
|
|
|
|
playfield[0][i]=new KGrObject (BETON);
|
|
|
|
|
editObjArray[0][i] = BETON;
|
|
|
|
|
//playfield[29][i]=new KGrBeton(TQPixmap ());
|
|
|
|
|
playfield[29][i]=new KGrObject (BETON);
|
|
|
|
|
editObjArray[29][i] = BETON;
|
|
|
|
|
}
|
|
|
|
|
//for (int j=0;j<22;j++)
|
|
|
|
|
//for (int i=0;i<30;i++) {
|
|
|
|
|
//playfield[i][j]->move(16+i*16,16+j*16);
|
|
|
|
|
//}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::newGame (const int lev, const int gameIndex)
|
|
|
|
|
{
|
|
|
|
|
// Ignore player input from keyboard or mouse while the screen is set up.
|
|
|
|
|
loading = TRUE; // "loadLevel (level)" will reset it.
|
|
|
|
|
|
|
|
|
|
if (editMode) {
|
|
|
|
|
emit setEditMenu (FALSE); // Disable edit menu items and toolbar.
|
|
|
|
|
|
|
|
|
|
editMode = FALSE;
|
|
|
|
|
paintEditObj = FALSE;
|
|
|
|
|
editObj = BRICK;
|
|
|
|
|
|
|
|
|
|
view->setHeroVisible (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newLevel = TRUE;
|
|
|
|
|
level = lev;
|
|
|
|
|
collnIndex = gameIndex;
|
|
|
|
|
collection = collections.at (collnIndex);
|
|
|
|
|
owner = collection->owner;
|
|
|
|
|
|
|
|
|
|
lives = 5; // Start with 5 lives.
|
|
|
|
|
score = 0;
|
|
|
|
|
startScore = 0;
|
|
|
|
|
|
|
|
|
|
emit showLives (lives);
|
|
|
|
|
emit showScore (score);
|
|
|
|
|
emit showLevel (level);
|
|
|
|
|
|
|
|
|
|
enemyCount = 0;
|
|
|
|
|
enemies.clear();
|
|
|
|
|
view->deleteEnemySprites();
|
|
|
|
|
|
|
|
|
|
newLevel = TRUE;;
|
|
|
|
|
loadLevel (level);
|
|
|
|
|
newLevel = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::startTutorial()
|
|
|
|
|
{
|
|
|
|
|
if (! saveOK (FALSE)) { // Check unsaved work.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int i, index;
|
|
|
|
|
int imax = collections.count();
|
|
|
|
|
bool found = FALSE;
|
|
|
|
|
|
|
|
|
|
index = 0;
|
|
|
|
|
for (i = 0; i < imax; i++) {
|
|
|
|
|
index = i; // Index within owner.
|
|
|
|
|
if (collections.at(i)->prefix == "tute") {
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (found) {
|
|
|
|
|
// Start the tutorial.
|
|
|
|
|
collection = collections.at (index);
|
|
|
|
|
owner = collection->owner;
|
|
|
|
|
emit markRuleType (collection->settings);
|
|
|
|
|
collnIndex = index;
|
|
|
|
|
level = 1;
|
|
|
|
|
newGame (level, collnIndex);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
KGrMessage::information (view, i18n("Start Tutorial"),
|
|
|
|
|
i18n("Cannot find the tutorial game (file-prefix %1) in "
|
|
|
|
|
"the %2 files.")
|
|
|
|
|
.arg("'tute'").arg("'games.dat'"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showHint()
|
|
|
|
|
{
|
|
|
|
|
// Put out a hint for this level.
|
|
|
|
|
TQString caption = i18n("Hint");
|
|
|
|
|
|
|
|
|
|
if (levelHint.length() > 0)
|
|
|
|
|
myMessage (view, caption, levelHint);
|
|
|
|
|
else
|
|
|
|
|
myMessage (view, caption,
|
|
|
|
|
i18n("Sorry, there is no hint for this level."));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int KGrGame::loadLevel (int levelNo)
|
|
|
|
|
{
|
|
|
|
|
int i,j;
|
|
|
|
|
TQFile openlevel;
|
|
|
|
|
|
|
|
|
|
if (! openLevelFile (levelNo, openlevel)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignore player input from keyboard or mouse while the screen is set up.
|
|
|
|
|
loading = TRUE;
|
|
|
|
|
|
|
|
|
|
nuggets = 0;
|
|
|
|
|
enemyCount=0;
|
|
|
|
|
startScore = score; // What we will save, if asked.
|
|
|
|
|
|
|
|
|
|
// lade den Level
|
|
|
|
|
for (j=1;j<21;j++)
|
|
|
|
|
for (i=1;i<29;i++) {
|
|
|
|
|
changeObject(openlevel.getch(),i,j);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Absorb a newline character, then read in the level name and hint (if any).
|
|
|
|
|
int c = openlevel.getch();
|
|
|
|
|
levelName = "";
|
|
|
|
|
levelHint = "";
|
|
|
|
|
TQCString levelNameC = "";
|
|
|
|
|
TQCString levelHintC = "";
|
|
|
|
|
i = 1;
|
|
|
|
|
while ((c = openlevel.getch()) != EOF) {
|
|
|
|
|
switch (i) {
|
|
|
|
|
case 1: if (c == '\n') // Level name is on one line.
|
|
|
|
|
i = 2;
|
|
|
|
|
else
|
|
|
|
|
levelNameC += (char) c;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: levelHintC += (char) c; // Hint is on rest of file.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
openlevel.close();
|
|
|
|
|
|
|
|
|
|
// If there is a name, recode any UTF-8 substrings and translate it right now.
|
|
|
|
|
if (levelNameC.length() > 0)
|
|
|
|
|
levelName = i18n((const char *) levelNameC);
|
|
|
|
|
|
|
|
|
|
// Indicate on the menus whether there is a hint for this level.
|
|
|
|
|
int len = levelHintC.length();
|
|
|
|
|
emit hintAvailable (len > 0);
|
|
|
|
|
|
|
|
|
|
// If there is a hint, remove the final newline and translate it right now.
|
|
|
|
|
if (len > 0)
|
|
|
|
|
levelHint = i18n((const char *) levelHintC.left(len-1));
|
|
|
|
|
|
|
|
|
|
// Disconnect edit-mode slots from signals from "view".
|
|
|
|
|
disconnect (view, TQT_SIGNAL (mouseClick(int)), 0, 0);
|
|
|
|
|
disconnect (view, TQT_SIGNAL (mouseLetGo(int)), 0, 0);
|
|
|
|
|
|
|
|
|
|
if (newLevel) {
|
|
|
|
|
hero->setEnemyList (&enemies);
|
|
|
|
|
for (enemy=enemies.first();enemy != 0; enemy = enemies.next())
|
|
|
|
|
enemy->setEnemyList(&enemies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hero->setNuggets(nuggets);
|
|
|
|
|
setTimings();
|
|
|
|
|
|
|
|
|
|
// Set direction-flags to use during enemy searches.
|
|
|
|
|
initSearchMatrix();
|
|
|
|
|
|
|
|
|
|
// Re-draw the playfield frame, level title and figures.
|
|
|
|
|
view->setTitle (getTitle());
|
|
|
|
|
view->updateCanvas();
|
|
|
|
|
|
|
|
|
|
// Check if this is a tutorial collection and we are not on the "ENDE" screen.
|
|
|
|
|
if ((collection->prefix.left(4) == "tute") && (levelNo != 0)) {
|
|
|
|
|
// At the start of a tutorial, put out an introduction.
|
|
|
|
|
if (levelNo == 1)
|
|
|
|
|
myMessage (view, collection->name,
|
|
|
|
|
i18n((const char *) collection->about.utf8()));
|
|
|
|
|
|
|
|
|
|
// Put out an explanation of this level.
|
|
|
|
|
myMessage (view, getTitle(), levelHint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put the mouse pointer on the hero.
|
|
|
|
|
if (mouseMode)
|
|
|
|
|
view->setMousePos (startI, startJ);
|
|
|
|
|
|
|
|
|
|
// Connect play-mode slot to signal from "view".
|
|
|
|
|
connect (view, TQT_SIGNAL(mouseClick(int)), TQT_SLOT(doDig(int)));
|
|
|
|
|
|
|
|
|
|
// Re-enable player input.
|
|
|
|
|
loading = FALSE;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::openLevelFile (int levelNo, TQFile & openlevel)
|
|
|
|
|
{
|
|
|
|
|
TQString filePath;
|
|
|
|
|
TQString msg;
|
|
|
|
|
|
|
|
|
|
filePath = getFilePath (owner, collection, levelNo);
|
|
|
|
|
|
|
|
|
|
openlevel.setName (filePath);
|
|
|
|
|
|
|
|
|
|
// gucken ob und welcher Level existiert
|
|
|
|
|
|
|
|
|
|
if (! openlevel.exists()) {
|
|
|
|
|
KGrMessage::information (view, i18n("Load Level"),
|
|
|
|
|
i18n("Cannot find file '%1'. Please make sure '%2' has been "
|
|
|
|
|
"run in the '%3' folder.")
|
|
|
|
|
.arg(filePath).arg("tar xf levels.tar").arg(systemDataDir.myStr()));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20>ffne Level zum lesen
|
|
|
|
|
if (! openlevel.open (IO_ReadOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Load Level"),
|
|
|
|
|
i18n("Cannot open file '%1' for read-only.").arg(filePath));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::changeObject (unsigned char kind, int i, int j)
|
|
|
|
|
{
|
|
|
|
|
delete playfield[i][j];
|
|
|
|
|
switch(kind) {
|
|
|
|
|
case FREE: createObject(new KGrFree (FREE,i,j,view),FREE,i,j);break;
|
|
|
|
|
case LADDER: createObject(new KGrObject (LADDER),LADDER,i,j);break;
|
|
|
|
|
case HLADDER: createObject(new KGrHladder (HLADDER,i,j,view),FREE,i,j);break;
|
|
|
|
|
case BRICK: createObject(new KGrBrick (BRICK,i,j,view),BRICK,i,j);break;
|
|
|
|
|
case BETON: createObject(new KGrObject (BETON),BETON,i,j);break;
|
|
|
|
|
case FBRICK: createObject(new KGrObject (FBRICK),BRICK,i,j);break;
|
|
|
|
|
case POLE: createObject(new KGrObject (POLE),POLE,i,j);break;
|
|
|
|
|
case NUGGET: createObject(new KGrFree (NUGGET,i,j,view),NUGGET,i,j);
|
|
|
|
|
nuggets++;break;
|
|
|
|
|
case HERO: createObject(new KGrFree (FREE,i,j,view),FREE,i,j);
|
|
|
|
|
hero->init(i,j);
|
|
|
|
|
startI = i; startJ = j;
|
|
|
|
|
hero->started = FALSE;
|
|
|
|
|
hero->showFigure();
|
|
|
|
|
break;
|
|
|
|
|
case ENEMY: createObject(new KGrFree (FREE,i,j,view),FREE,i,j);
|
|
|
|
|
if (newLevel){
|
|
|
|
|
// Starting a level for the first time.
|
|
|
|
|
enemy = new KGrEnemy (view, i, j);
|
|
|
|
|
enemy->setPlayfield(&playfield);
|
|
|
|
|
enemy->enemyId = enemyCount++;
|
|
|
|
|
enemies.append(enemy);
|
|
|
|
|
connect(enemy, TQT_SIGNAL(lostNugget()), TQT_SLOT(loseNugget()));
|
|
|
|
|
connect(enemy, TQT_SIGNAL(trapped(int)), TQT_SLOT(incScore(int)));
|
|
|
|
|
connect(enemy, TQT_SIGNAL(killed(int)), TQT_SLOT(incScore(int)));
|
|
|
|
|
} else {
|
|
|
|
|
// Starting a level again after losing.
|
|
|
|
|
enemy=enemies.at(enemyCount);
|
|
|
|
|
enemy->enemyId=enemyCount++;
|
|
|
|
|
enemy->setNuggets(0);
|
|
|
|
|
enemy->init(i,j); // Re-initialise the enemy's state information.
|
|
|
|
|
}
|
|
|
|
|
enemy->showFigure();
|
|
|
|
|
break;
|
|
|
|
|
default : createObject(new KGrBrick(BRICK,i,j,view),BRICK,i,j);break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::createObject (KGrObject *o, char picType, int x, int y)
|
|
|
|
|
{
|
|
|
|
|
playfield[x][y] = o;
|
|
|
|
|
view->paintCell (x, y, picType); // Pic maybe not same as object.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::setTimings ()
|
|
|
|
|
{
|
|
|
|
|
Timing * timing;
|
|
|
|
|
int c = -1;
|
|
|
|
|
|
|
|
|
|
if (KGrFigure::variableTiming) {
|
|
|
|
|
c = enemies.count(); // Timing based on enemy count.
|
|
|
|
|
c = (c > 5) ? 5 : c;
|
|
|
|
|
timing = &(KGrFigure::varTiming[c]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
timing = &(KGrFigure::fixedTiming); // Fixed timing.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KGrHero::WALKDELAY = timing->hwalk;
|
|
|
|
|
KGrHero::FALLDELAY = timing->hfall;
|
|
|
|
|
KGrEnemy::WALKDELAY = timing->ewalk;
|
|
|
|
|
KGrEnemy::FALLDELAY = timing->efall;
|
|
|
|
|
KGrEnemy::CAPTIVEDELAY = timing->ecaptive;
|
|
|
|
|
KGrBrick::HOLETIME = timing->hole;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::initSearchMatrix()
|
|
|
|
|
{
|
|
|
|
|
// Called at start of level and also when hidden ladders appear.
|
|
|
|
|
int i,j;
|
|
|
|
|
|
|
|
|
|
for (i=1;i<21;i++){
|
|
|
|
|
for (j=1;j<29;j++)
|
|
|
|
|
{
|
|
|
|
|
// If on ladder, can walk L, R, U or D.
|
|
|
|
|
if (playfield[j][i]->whatIam()==LADDER)
|
|
|
|
|
playfield[j][i]->searchValue = CANWALKLEFT + CANWALKRIGHT +
|
|
|
|
|
CANWALKUP + CANWALKDOWN;
|
|
|
|
|
else
|
|
|
|
|
// If on solid ground, can walk L or R.
|
|
|
|
|
if ((playfield[j][i+1]->whatIam()==BRICK)||
|
|
|
|
|
(playfield[j][i+1]->whatIam()==HOLE)||
|
|
|
|
|
(playfield[j][i+1]->whatIam()==USEDHOLE)||
|
|
|
|
|
(playfield[j][i+1]->whatIam()==BETON))
|
|
|
|
|
playfield[j][i]->searchValue=CANWALKLEFT+CANWALKRIGHT;
|
|
|
|
|
else
|
|
|
|
|
// If on pole or top of ladder, can walk L, R or D.
|
|
|
|
|
if ((playfield[j][i]->whatIam()==POLE)||
|
|
|
|
|
(playfield[j][i+1]->whatIam()==LADDER))
|
|
|
|
|
playfield[j][i]->searchValue=CANWALKLEFT+CANWALKRIGHT+CANWALKDOWN;
|
|
|
|
|
else
|
|
|
|
|
// Otherwise, gravity takes over ...
|
|
|
|
|
playfield[j][i]->searchValue=CANWALKDOWN;
|
|
|
|
|
|
|
|
|
|
// Clear corresponding bits if there are solids to L, R, U or D.
|
|
|
|
|
if(playfield[j][i-1]->blocker)
|
|
|
|
|
playfield[j][i]->searchValue &= ~CANWALKUP;
|
|
|
|
|
if(playfield[j-1][i]->blocker)
|
|
|
|
|
playfield[j][i]->searchValue &= ~CANWALKLEFT;
|
|
|
|
|
if(playfield[j+1][i]->blocker)
|
|
|
|
|
playfield[j][i]->searchValue &= ~CANWALKRIGHT;
|
|
|
|
|
if(playfield[j][i+1]->blocker)
|
|
|
|
|
playfield[j][i]->searchValue &= ~CANWALKDOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::startPlaying () {
|
|
|
|
|
if (! hero->started) {
|
|
|
|
|
// Start the enemies and the hero.
|
|
|
|
|
for (--enemyCount; enemyCount>=0; --enemyCount) {
|
|
|
|
|
enemy=enemies.at(enemyCount);
|
|
|
|
|
enemy->startSearching();
|
|
|
|
|
}
|
|
|
|
|
hero->start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQString KGrGame::getFilePath (Owner o, KGrCollection * colln, int lev)
|
|
|
|
|
{
|
|
|
|
|
TQString filePath;
|
|
|
|
|
|
|
|
|
|
if (lev == 0) {
|
|
|
|
|
// End of game: show the "ENDE" screen.
|
|
|
|
|
o = SYSTEM;
|
|
|
|
|
filePath = "level000.grl";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
filePath.setNum (lev); // Convert INT -> TQString.
|
|
|
|
|
filePath = filePath.rightJustify (3,'0'); // Add 0-2 zeros at left.
|
|
|
|
|
filePath.append (".grl"); // Add KGoldrunner level-suffix.
|
|
|
|
|
filePath.prepend (colln->prefix); // Add collection file-prefix.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
filePath.prepend (((o == SYSTEM)? systemDataDir : userDataDir) + "levels/");
|
|
|
|
|
|
|
|
|
|
return (filePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQString KGrGame::getTitle()
|
|
|
|
|
{
|
|
|
|
|
TQString levelTitle;
|
|
|
|
|
if (level == 0) {
|
|
|
|
|
// Generate a special title: end of game or creating a new level.
|
|
|
|
|
if (! editMode)
|
|
|
|
|
levelTitle = "E N D --- F I N --- E N D E";
|
|
|
|
|
else
|
|
|
|
|
levelTitle = i18n("New Level");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Generate title string "Collection-name - NNN - Level-name".
|
|
|
|
|
levelTitle.setNum (level);
|
|
|
|
|
levelTitle = levelTitle.rightJustify (3,'0');
|
|
|
|
|
levelTitle = collection->name + " - " + levelTitle;
|
|
|
|
|
if (levelName.length() > 0) {
|
|
|
|
|
levelTitle = levelTitle + " - " + levelName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (levelTitle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::readMousePos()
|
|
|
|
|
{
|
|
|
|
|
TQPoint p;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
// If loading a level for play or editing, ignore mouse-position input.
|
|
|
|
|
if (loading) return;
|
|
|
|
|
|
|
|
|
|
// If game control is currently by keyboard, ignore the mouse.
|
|
|
|
|
if ((! mouseMode) && (! editMode)) return;
|
|
|
|
|
|
|
|
|
|
p = view->getMousePos ();
|
|
|
|
|
i = p.x(); j = p.y();
|
|
|
|
|
|
|
|
|
|
if (editMode) {
|
|
|
|
|
// Editing - check if we are in paint mode and have moved the mouse.
|
|
|
|
|
if (paintEditObj && ((i != oldI) || (j != oldJ))) {
|
|
|
|
|
insertEditObj (i, j);
|
|
|
|
|
view->updateCanvas();
|
|
|
|
|
oldI = i;
|
|
|
|
|
oldJ = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Playing - if the level has started, control the hero.
|
|
|
|
|
if (KGrObject::frozen) return; // If game is stopped, do nothing.
|
|
|
|
|
|
|
|
|
|
hero->setDirection (i, j);
|
|
|
|
|
|
|
|
|
|
// Start playing when the mouse moves off the hero.
|
|
|
|
|
if ((! hero->started) && ((i != startI) || (j != startJ))) {
|
|
|
|
|
startPlaying();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::doDig (int button) {
|
|
|
|
|
|
|
|
|
|
// If game control is currently by keyboard, ignore the mouse.
|
|
|
|
|
if (editMode) return;
|
|
|
|
|
if (! mouseMode) return;
|
|
|
|
|
|
|
|
|
|
// If loading a level for play or editing, ignore mouse-button input.
|
|
|
|
|
if ((! loading) && (! KGrObject::frozen)) {
|
|
|
|
|
if (! hero->started) {
|
|
|
|
|
startPlaying(); // If first player-input, start playing.
|
|
|
|
|
}
|
|
|
|
|
switch (button) {
|
|
|
|
|
case Qt::LeftButton: hero->digLeft (); break;
|
|
|
|
|
case Qt::RightButton: hero->digRight (); break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::heroAction (KBAction movement)
|
|
|
|
|
{
|
|
|
|
|
switch (movement) {
|
|
|
|
|
case KB_UP: hero->setKey (UP); break;
|
|
|
|
|
case KB_DOWN: hero->setKey (DOWN); break;
|
|
|
|
|
case KB_LEFT: hero->setKey (LEFT); break;
|
|
|
|
|
case KB_RIGHT: hero->setKey (RIGHT); break;
|
|
|
|
|
case KB_STOP: hero->setKey (STAND); break;
|
|
|
|
|
case KB_DIGLEFT: hero->setKey (STAND); hero->digLeft (); break;
|
|
|
|
|
case KB_DIGRIGHT: hero->setKey (STAND); hero->digRight (); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************************** SAVE AND RE-LOAD GAMES **************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::saveGame() // Save game ID, score and level.
|
|
|
|
|
{
|
|
|
|
|
if (editMode) {myMessage (view, i18n("Save Game"),
|
|
|
|
|
i18n("Sorry, you cannot save your game play while you are editing. "
|
|
|
|
|
"Please try menu item %1.").arg("\"" + i18n("&Save Edits...") + "\""));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (hero->started) {myMessage (view, i18n("Save Game"),
|
|
|
|
|
i18n("Please note: for reasons of simplicity, your saved game "
|
|
|
|
|
"position and score will be as they were at the start of this "
|
|
|
|
|
"level, not as they are now."));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQDate today = TQDate::currentDate();
|
|
|
|
|
TQTime now = TQTime::currentTime();
|
|
|
|
|
TQString saved;
|
|
|
|
|
TQString day;
|
|
|
|
|
#ifdef QT3
|
|
|
|
|
day = today.shortDayName(today.dayOfWeek());
|
|
|
|
|
#else
|
|
|
|
|
day = today.dayName(today.dayOfWeek());
|
|
|
|
|
#endif
|
|
|
|
|
saved = saved.sprintf
|
|
|
|
|
("%-6s %03d %03ld %7ld %s %04d-%02d-%02d %02d:%02d\n",
|
|
|
|
|
collection->prefix.myStr(), level, lives, startScore,
|
|
|
|
|
day.myStr(),
|
|
|
|
|
today.year(), today.month(), today.day(),
|
|
|
|
|
now.hour(), now.minute());
|
|
|
|
|
|
|
|
|
|
TQFile file1 (userDataDir + "savegame.dat");
|
|
|
|
|
TQFile file2 (userDataDir + "savegame.tmp");
|
|
|
|
|
|
|
|
|
|
if (! file2.open (IO_WriteOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game"),
|
|
|
|
|
i18n("Cannot open file '%1' for output.")
|
|
|
|
|
.arg(userDataDir + "savegame.tmp"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
TQTextStream text2 (&file2);
|
|
|
|
|
text2 << saved;
|
|
|
|
|
|
|
|
|
|
if (file1.exists()) {
|
|
|
|
|
if (! file1.open (IO_ReadOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game"),
|
|
|
|
|
i18n("Cannot open file '%1' for read-only.")
|
|
|
|
|
.arg(userDataDir + "savegame.dat"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQTextStream text1 (&file1);
|
|
|
|
|
int n = 30; // Limit the file to the last 30 saves.
|
|
|
|
|
while ((! text1.endData()) && (--n > 0)) {
|
|
|
|
|
saved = text1.readLine() + "\n";
|
|
|
|
|
text2 << saved;
|
|
|
|
|
}
|
|
|
|
|
file1.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file2.close();
|
|
|
|
|
|
|
|
|
|
TQDir dir;
|
|
|
|
|
dir.rename (file2.name(), file1.name(), TRUE);
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game"),
|
|
|
|
|
i18n("Your game has been saved."));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::loadGame() // Re-load game, score and level.
|
|
|
|
|
{
|
|
|
|
|
if (! saveOK (FALSE)) { // Check unsaved work.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQFile savedGames (userDataDir + "savegame.dat");
|
|
|
|
|
if (! savedGames.exists()) {
|
|
|
|
|
// Use myMessage() because it stops the game while the message appears.
|
|
|
|
|
myMessage (view, i18n("Load Game"),
|
|
|
|
|
i18n("Sorry, there are no saved games."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! savedGames.open (IO_ReadOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Load Game"),
|
|
|
|
|
i18n("Cannot open file '%1' for read-only.")
|
|
|
|
|
.arg(userDataDir + "savegame.dat"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Halt the game during the loadGame() dialog.
|
|
|
|
|
modalFreeze = FALSE;
|
|
|
|
|
if (!KGrObject::frozen) {
|
|
|
|
|
modalFreeze = TRUE;
|
|
|
|
|
freeze();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQString s;
|
|
|
|
|
|
|
|
|
|
KGrLGDialog * lg = new KGrLGDialog (&savedGames, collections,
|
|
|
|
|
view, "loadDialog");
|
|
|
|
|
|
|
|
|
|
if (lg->exec() == TQDialog::Accepted) {
|
|
|
|
|
s = lg->getCurrentText();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool found = FALSE;
|
|
|
|
|
TQString pr;
|
|
|
|
|
int lev;
|
|
|
|
|
int i;
|
|
|
|
|
int imax = collections.count();
|
|
|
|
|
|
|
|
|
|
if (! s.isNull()) {
|
|
|
|
|
pr = s.mid (21, 7); // Get the collection prefix.
|
|
|
|
|
pr = pr.left (pr.find (" ", 0, FALSE));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < imax; i++) { // Find the collection.
|
|
|
|
|
if (collections.at(i)->prefix == pr) {
|
|
|
|
|
collection = collections.at(i);
|
|
|
|
|
collnIndex = i;
|
|
|
|
|
owner = collections.at(i)->owner;
|
|
|
|
|
found = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (found) {
|
|
|
|
|
// Set the rules for the selected game.
|
|
|
|
|
emit markRuleType (collection->settings);
|
|
|
|
|
lev = s.mid (28, 3).toInt();
|
|
|
|
|
newGame (lev, collnIndex); // Re-start the selected game.
|
|
|
|
|
lives = s.mid (32, 3).toLong(); // Update the lives.
|
|
|
|
|
emit showLives (lives);
|
|
|
|
|
score = s.mid (36, 7).toLong(); // Update the score.
|
|
|
|
|
emit showScore (score);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
KGrMessage::information (view, i18n("Load Game"),
|
|
|
|
|
i18n("Cannot find the game with prefix '%1'.").arg(pr));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unfreeze the game, but only if it was previously unfrozen.
|
|
|
|
|
if (modalFreeze) {
|
|
|
|
|
unfreeze();
|
|
|
|
|
modalFreeze = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete lg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************************** HIGH-SCORE PROCEDURES ***************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::checkHighScore()
|
|
|
|
|
{
|
|
|
|
|
bool prevHigh = TRUE;
|
|
|
|
|
TQ_INT16 prevLevel = 0;
|
|
|
|
|
TQ_INT32 prevScore = 0;
|
|
|
|
|
TQString thisUser = i18n("Unknown");
|
|
|
|
|
int highCount = 0;
|
|
|
|
|
|
|
|
|
|
// Don't keep high scores for tutorial games.
|
|
|
|
|
if (collection->prefix.left(4) == "tute")
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (score <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Look for user's high-score file or for a released high-score file.
|
|
|
|
|
TQFile high1 (userDataDir + "hi_" + collection->prefix + ".dat");
|
|
|
|
|
TQDataStream s1;
|
|
|
|
|
|
|
|
|
|
if (! high1.exists()) {
|
|
|
|
|
high1.setName (systemDataDir + "hi_" + collection->prefix + ".dat");
|
|
|
|
|
if (! high1.exists()) {
|
|
|
|
|
prevHigh = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If a previous high score file exists, check the current score against it.
|
|
|
|
|
if (prevHigh) {
|
|
|
|
|
if (! high1.open (IO_ReadOnly)) {
|
|
|
|
|
TQString high1_name = high1.name();
|
|
|
|
|
KGrMessage::information (view, i18n("Check for High Score"),
|
|
|
|
|
i18n("Cannot open file '%1' for read-only.").arg(high1_name));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read previous users, levels and scores from the high score file.
|
|
|
|
|
s1.setDevice (&high1);
|
|
|
|
|
bool found = FALSE;
|
|
|
|
|
highCount = 0;
|
|
|
|
|
while (! s1.endData()) {
|
|
|
|
|
char * prevUser;
|
|
|
|
|
char * prevDate;
|
|
|
|
|
s1 >> prevUser;
|
|
|
|
|
s1 >> prevLevel;
|
|
|
|
|
s1 >> prevScore;
|
|
|
|
|
s1 >> prevDate;
|
|
|
|
|
delete prevUser;
|
|
|
|
|
delete prevDate;
|
|
|
|
|
highCount++;
|
|
|
|
|
if (score > prevScore) {
|
|
|
|
|
found = TRUE; // We have a high score.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if higher than one on file or fewer than 10 previous scores.
|
|
|
|
|
if ((! found) && (highCount >= 10)) {
|
|
|
|
|
return; // We did not have a high score.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************* */
|
|
|
|
|
/* If we have come this far, we have a new high score to record. */
|
|
|
|
|
/* ************************************************************* */
|
|
|
|
|
|
|
|
|
|
TQFile high2 (userDataDir + "hi_" + collection->prefix + ".tmp");
|
|
|
|
|
TQDataStream s2;
|
|
|
|
|
|
|
|
|
|
if (! high2.open (IO_WriteOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Check for High Score"),
|
|
|
|
|
i18n("Cannot open file '%1' for output.")
|
|
|
|
|
.arg(userDataDir + "hi_" + collection->prefix + ".tmp"));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dialog to ask the user to enter their name.
|
|
|
|
|
TQDialog * hsn = new TQDialog (view, "hsNameDialog", TRUE,
|
|
|
|
|
WStyle_Customize | WStyle_NormalBorder | WStyle_Title);
|
|
|
|
|
|
|
|
|
|
int margin = 10;
|
|
|
|
|
int spacing = 10;
|
|
|
|
|
TQVBoxLayout * mainLayout = new TQVBoxLayout (hsn, margin, spacing);
|
|
|
|
|
|
|
|
|
|
TQLabel * hsnMessage = new TQLabel (
|
|
|
|
|
i18n("<b>Congratulations !!!</b> "
|
|
|
|
|
"You have achieved a high "
|
|
|
|
|
"score in this game. Please enter your name so that "
|
|
|
|
|
"it may be enshrined in the KGoldrunner Hall of Fame."),
|
|
|
|
|
hsn);
|
|
|
|
|
TQLineEdit * hsnUser = new TQLineEdit (hsn);
|
|
|
|
|
TQPushButton * OK = new KPushButton (KStdGuiItem::ok(), hsn);
|
|
|
|
|
|
|
|
|
|
mainLayout-> addWidget (hsnMessage);
|
|
|
|
|
mainLayout-> addWidget (hsnUser);
|
|
|
|
|
mainLayout-> addWidget (OK);
|
|
|
|
|
|
|
|
|
|
hsn-> setCaption (i18n("Save High Score"));
|
|
|
|
|
|
|
|
|
|
TQPoint p = view->mapToGlobal (TQPoint (0,0));
|
|
|
|
|
hsn-> move (p.x() + 50, p.y() + 50);
|
|
|
|
|
|
|
|
|
|
OK-> setAccel (Key_Return);
|
|
|
|
|
hsnUser-> setFocus(); // Set the keyboard input on.
|
|
|
|
|
|
|
|
|
|
connect (hsnUser, TQT_SIGNAL (returnPressed ()), hsn, TQT_SLOT (accept ()));
|
|
|
|
|
connect (OK, TQT_SIGNAL (clicked ()), hsn, TQT_SLOT (accept ()));
|
|
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
|
hsn->exec();
|
|
|
|
|
thisUser = hsnUser->text();
|
|
|
|
|
if (thisUser.length() > 0)
|
|
|
|
|
break;
|
|
|
|
|
KGrMessage::information (view, i18n("Save High Score"),
|
|
|
|
|
i18n("You must enter something. Please try again."));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete hsn;
|
|
|
|
|
|
|
|
|
|
TQDate today = TQDate::currentDate();
|
|
|
|
|
TQString hsDate;
|
|
|
|
|
#ifdef QT3
|
|
|
|
|
TQString day = today.shortDayName(today.dayOfWeek());
|
|
|
|
|
#else
|
|
|
|
|
TQString day = today.dayName(today.dayOfWeek());
|
|
|
|
|
#endif
|
|
|
|
|
hsDate = hsDate.sprintf
|
|
|
|
|
("%s %04d-%02d-%02d",
|
|
|
|
|
day.myStr(),
|
|
|
|
|
today.year(), today.month(), today.day());
|
|
|
|
|
|
|
|
|
|
s2.setDevice (&high2);
|
|
|
|
|
|
|
|
|
|
if (prevHigh) {
|
|
|
|
|
high1.reset();
|
|
|
|
|
bool scoreRecorded = FALSE;
|
|
|
|
|
highCount = 0;
|
|
|
|
|
while ((! s1.endData()) && (highCount < 10)) {
|
|
|
|
|
char * prevUser;
|
|
|
|
|
char * prevDate;
|
|
|
|
|
s1 >> prevUser;
|
|
|
|
|
s1 >> prevLevel;
|
|
|
|
|
s1 >> prevScore;
|
|
|
|
|
s1 >> prevDate;
|
|
|
|
|
if ((! scoreRecorded) && (score > prevScore)) {
|
|
|
|
|
highCount++;
|
|
|
|
|
// Recode the user's name as UTF-8, in case it contains
|
|
|
|
|
// non-ASCII chars (e.g. "Kr<4B>ger" is encoded as "Krüger").
|
|
|
|
|
s2 << (const char *) thisUser.utf8();
|
|
|
|
|
s2 << (TQ_INT16) level;
|
|
|
|
|
s2 << (TQ_INT32) score;
|
|
|
|
|
s2 << hsDate.myStr();
|
|
|
|
|
scoreRecorded = TRUE;
|
|
|
|
|
}
|
|
|
|
|
if (highCount < 10) {
|
|
|
|
|
highCount++;
|
|
|
|
|
s2 << prevUser;
|
|
|
|
|
s2 << prevLevel;
|
|
|
|
|
s2 << prevScore;
|
|
|
|
|
s2 << prevDate;
|
|
|
|
|
}
|
|
|
|
|
delete prevUser;
|
|
|
|
|
delete prevDate;
|
|
|
|
|
}
|
|
|
|
|
if ((! scoreRecorded) && (highCount < 10)) {
|
|
|
|
|
// Recode the user's name as UTF-8, in case it contains
|
|
|
|
|
// non-ASCII chars (e.g. "Kr<4B>ger" is encoded as "Krüger").
|
|
|
|
|
s2 << (const char *) thisUser.utf8();
|
|
|
|
|
s2 << (TQ_INT16) level;
|
|
|
|
|
s2 << (TQ_INT32) score;
|
|
|
|
|
s2 << hsDate.myStr();
|
|
|
|
|
}
|
|
|
|
|
high1.close();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Recode the user's name as UTF-8, in case it contains
|
|
|
|
|
// non-ASCII chars (e.g. "Kr<4B>ger" is encoded as "Krüger").
|
|
|
|
|
s2 << (const char *) thisUser.utf8();
|
|
|
|
|
s2 << (TQ_INT16) level;
|
|
|
|
|
s2 << (TQ_INT32) score;
|
|
|
|
|
s2 << hsDate.myStr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
high2.close();
|
|
|
|
|
|
|
|
|
|
TQDir dir;
|
|
|
|
|
dir.rename (high2.name(),
|
|
|
|
|
userDataDir + "hi_" + collection->prefix + ".dat", TRUE);
|
|
|
|
|
KGrMessage::information (view, i18n("Save High Score"),
|
|
|
|
|
i18n("Your high score has been saved."));
|
|
|
|
|
|
|
|
|
|
showHighScores();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showHighScores()
|
|
|
|
|
{
|
|
|
|
|
// Don't keep high scores for tutorial games.
|
|
|
|
|
if (collection->prefix.left(4) == "tute") {
|
|
|
|
|
KGrMessage::information (view, i18n("Show High Scores"),
|
|
|
|
|
i18n("Sorry, we do not keep high scores for tutorial games."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQ_INT16 prevLevel = 0;
|
|
|
|
|
TQ_INT32 prevScore = 0;
|
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
// Look for user's high-score file or for a released high-score file.
|
|
|
|
|
TQFile high1 (userDataDir + "hi_" + collection->prefix + ".dat");
|
|
|
|
|
TQDataStream s1;
|
|
|
|
|
|
|
|
|
|
if (! high1.exists()) {
|
|
|
|
|
high1.setName (systemDataDir + "hi_" + collection->prefix + ".dat");
|
|
|
|
|
if (! high1.exists()) {
|
|
|
|
|
KGrMessage::information (view, i18n("Show High Scores"),
|
|
|
|
|
i18n("Sorry, there are no high scores for the %1 game yet.")
|
|
|
|
|
.arg("\"" + collection->name + "\""));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! high1.open (IO_ReadOnly)) {
|
|
|
|
|
TQString high1_name = high1.name();
|
|
|
|
|
KGrMessage::information (view, i18n("Show High Scores"),
|
|
|
|
|
i18n("Cannot open file '%1' for read-only.").arg(high1_name));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQDialog * hs = new TQDialog (view, "hsDialog", TRUE,
|
|
|
|
|
WStyle_Customize | WStyle_NormalBorder | WStyle_Title);
|
|
|
|
|
|
|
|
|
|
int margin = 10;
|
|
|
|
|
int spacing = 10;
|
|
|
|
|
TQVBoxLayout * mainLayout = new TQVBoxLayout (hs, margin, spacing);
|
|
|
|
|
|
|
|
|
|
TQLabel * hsHeader = new TQLabel (i18n (
|
|
|
|
|
"<center><h2>KGoldrunner Hall of Fame</h2></center><br>"
|
|
|
|
|
"<center><h3>\"%1\" Game</h3></center>")
|
|
|
|
|
.arg(collection->name),
|
|
|
|
|
hs);
|
|
|
|
|
TQLabel * hsColHeader = new TQLabel (
|
|
|
|
|
i18n(" Name "
|
|
|
|
|
"Level Score Date"), hs);
|
|
|
|
|
#ifdef KGR_PORTABLE
|
|
|
|
|
TQFont f ("courier", 12);
|
|
|
|
|
#else
|
|
|
|
|
TQFont f = TDEGlobalSettings::fixedFont(); // KDE version.
|
|
|
|
|
#endif
|
|
|
|
|
f. setFixedPitch (TRUE);
|
|
|
|
|
f. setBold (TRUE);
|
|
|
|
|
hsColHeader-> setFont (f);
|
|
|
|
|
|
|
|
|
|
TQLabel * hsLine [10];
|
|
|
|
|
|
|
|
|
|
TQHBox * buttons = new TQHBox (hs);
|
|
|
|
|
buttons-> setSpacing (spacing);
|
|
|
|
|
TQPushButton * OK = new KPushButton (KStdGuiItem::close(), buttons);
|
|
|
|
|
|
|
|
|
|
mainLayout-> addWidget (hsHeader);
|
|
|
|
|
mainLayout-> addWidget (hsColHeader);
|
|
|
|
|
|
|
|
|
|
hs-> setCaption (i18n("High Scores"));
|
|
|
|
|
|
|
|
|
|
OK-> setAccel (Key_Return);
|
|
|
|
|
|
|
|
|
|
// Set up the format for the high-score lines.
|
|
|
|
|
f. setBold (FALSE);
|
|
|
|
|
TQString line;
|
|
|
|
|
const char * hsFormat = "%2d. %-30.30s %3d %7ld %s";
|
|
|
|
|
|
|
|
|
|
// Read and display the users, levels and scores from the high score file.
|
|
|
|
|
s1.setDevice (&high1);
|
|
|
|
|
n = 0;
|
|
|
|
|
while ((! s1.endData()) && (n < 10)) {
|
|
|
|
|
char * prevUser;
|
|
|
|
|
char * prevDate;
|
|
|
|
|
s1 >> prevUser;
|
|
|
|
|
s1 >> prevLevel;
|
|
|
|
|
s1 >> prevScore;
|
|
|
|
|
s1 >> prevDate;
|
|
|
|
|
|
|
|
|
|
// TQString::sprintf expects UTF-8 encoding in its string arguments, so
|
|
|
|
|
// prevUser has been saved on file as UTF-8 to allow non=ASCII chars
|
|
|
|
|
// in the user's name (e.g. "Kr<4B>ger" is encoded as "Krüger" in UTF-8).
|
|
|
|
|
|
|
|
|
|
line = line.sprintf (hsFormat,
|
|
|
|
|
n+1, prevUser, prevLevel, prevScore, prevDate);
|
|
|
|
|
hsLine [n] = new TQLabel (line, hs);
|
|
|
|
|
hsLine [n]->setFont (f);
|
|
|
|
|
mainLayout->addWidget (hsLine [n]);
|
|
|
|
|
|
|
|
|
|
delete prevUser;
|
|
|
|
|
delete prevDate;
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQFrame * separator = new TQFrame (hs);
|
|
|
|
|
separator->setFrameStyle (TQFrame::HLine + TQFrame::Sunken);
|
|
|
|
|
mainLayout->addWidget (separator);
|
|
|
|
|
|
|
|
|
|
OK-> setMaximumWidth (100);
|
|
|
|
|
mainLayout-> addWidget (buttons);
|
|
|
|
|
|
|
|
|
|
TQPoint p = view->mapToGlobal (TQPoint (0,0));
|
|
|
|
|
hs-> move (p.x() + 50, p.y() + 50);
|
|
|
|
|
|
|
|
|
|
// Start up the dialog box.
|
|
|
|
|
connect (OK, TQT_SIGNAL (clicked ()), hs, TQT_SLOT (accept ()));
|
|
|
|
|
hs-> exec();
|
|
|
|
|
|
|
|
|
|
delete hs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************************** AUTHORS' DEBUGGING AIDS **************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::doStep()
|
|
|
|
|
{
|
|
|
|
|
if (KGrObject::frozen) { // The game must have been halted.
|
|
|
|
|
restart(); // Do one step and halt again.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::restart()
|
|
|
|
|
{
|
|
|
|
|
bool temp;
|
|
|
|
|
int i,j;
|
|
|
|
|
|
|
|
|
|
if (editMode) // Can't move figures when in Edit Mode.
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
temp = KGrObject::frozen;
|
|
|
|
|
|
|
|
|
|
KGrObject::frozen = FALSE; // Temporarily restart the game, by re-running
|
|
|
|
|
// any timer events that have been blocked.
|
|
|
|
|
|
|
|
|
|
readMousePos(); // Set hero's direction.
|
|
|
|
|
hero->doStep(); // Move the hero one step.
|
|
|
|
|
|
|
|
|
|
j = enemies.count(); // Move each enemy one step.
|
|
|
|
|
for (i = 0; i < j; i++) {
|
|
|
|
|
enemy = enemies.at(i); // Need to use an index because called methods
|
|
|
|
|
enemy->doStep(); // change the "current()" of the "enemies" list.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i=1; i<=28; i++)
|
|
|
|
|
for (j=1; j<=20; j++) {
|
|
|
|
|
if ((playfield[i][j]->whatIam() == HOLE) ||
|
|
|
|
|
(playfield[i][j]->whatIam() == USEDHOLE) ||
|
|
|
|
|
(playfield[i][j]->whatIam() == BRICK))
|
|
|
|
|
((KGrBrick *)playfield[i][j])->doStep();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KGrObject::frozen = temp; // If frozen was TRUE, halt again, which gives a
|
|
|
|
|
// single-step effect, otherwise go on running.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showFigurePositions()
|
|
|
|
|
{
|
|
|
|
|
if (KGrObject::frozen) {
|
|
|
|
|
hero->showState('p');
|
|
|
|
|
for (enemy=enemies.first();enemy != 0; enemy = enemies.next()) {
|
|
|
|
|
enemy->showState('p');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showHeroState()
|
|
|
|
|
{
|
|
|
|
|
if (KGrObject::frozen) {
|
|
|
|
|
hero->showState('s');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showEnemyState(int enemyId)
|
|
|
|
|
{
|
|
|
|
|
if (KGrObject::frozen) {
|
|
|
|
|
for (enemy=enemies.first();enemy != 0; enemy = enemies.next()) {
|
|
|
|
|
if (enemy->enemyId == enemyId) enemy->showState('s');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showObjectState()
|
|
|
|
|
{
|
|
|
|
|
TQPoint p;
|
|
|
|
|
int i, j;
|
|
|
|
|
KGrObject * myObject;
|
|
|
|
|
|
|
|
|
|
if (KGrObject::frozen) {
|
|
|
|
|
p = view->getMousePos ();
|
|
|
|
|
i = p.x(); j = p.y();
|
|
|
|
|
myObject = playfield[i][j];
|
|
|
|
|
switch (myObject->whatIam()) {
|
|
|
|
|
case BRICK:
|
|
|
|
|
case HOLE:
|
|
|
|
|
case USEDHOLE:
|
|
|
|
|
((KGrBrick *)myObject)->showState(i, j); break;
|
|
|
|
|
default: myObject->showState(i, j); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::bugFix()
|
|
|
|
|
{
|
|
|
|
|
if (KGrObject::frozen) { // Toggle a bug fix on/off dynamically.
|
|
|
|
|
KGrObject::bugFixed = (KGrObject::bugFixed) ? FALSE : TRUE;
|
|
|
|
|
printf ("%s", (KGrObject::bugFixed) ? "\n" : "");
|
|
|
|
|
printf (">>> Bug fix is %s\n", (KGrObject::bugFixed) ? "ON" : "OFF\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::startLogging()
|
|
|
|
|
{
|
|
|
|
|
if (KGrObject::frozen) { // Toggle logging on/off dynamically.
|
|
|
|
|
KGrObject::logging = (KGrObject::logging) ? FALSE : TRUE;
|
|
|
|
|
printf ("%s", (KGrObject::logging) ? "\n" : "");
|
|
|
|
|
printf (">>> Logging is %s\n", (KGrObject::logging) ? "ON" : "OFF\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************ GAME EDITOR FUNCTIONS ACTIVATED BY MENU OR TOOLBAR ************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::setEditObj (char newEditObj)
|
|
|
|
|
{
|
|
|
|
|
editObj = newEditObj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::createLevel()
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (! saveOK (FALSE)) { // Check unsaved work.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! ownerOK (USER)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Create Level"),
|
|
|
|
|
i18n("You cannot create and save a level "
|
|
|
|
|
"until you have created a game to hold "
|
|
|
|
|
"it. Try menu item \"Create Game\"."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignore player input from keyboard or mouse while the screen is set up.
|
|
|
|
|
loading = TRUE;
|
|
|
|
|
|
|
|
|
|
level = 0;
|
|
|
|
|
initEdit();
|
|
|
|
|
levelName = "";
|
|
|
|
|
levelHint = "";
|
|
|
|
|
|
|
|
|
|
// Clear the playfield.
|
|
|
|
|
editObj = FREE;
|
|
|
|
|
for (i = 1; i <= FIELDWIDTH; i++)
|
|
|
|
|
for (j = 1; j <= FIELDHEIGHT; j++) {
|
|
|
|
|
insertEditObj (i, j);
|
|
|
|
|
editObjArray[i][j] = editObj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
editObj = HERO;
|
|
|
|
|
insertEditObj (1, 1);
|
|
|
|
|
editObjArray[1][1] = editObj;
|
|
|
|
|
editObj = BRICK;
|
|
|
|
|
|
|
|
|
|
showEditLevel();
|
|
|
|
|
|
|
|
|
|
for (j = 1; j <= FIELDHEIGHT; j++)
|
|
|
|
|
for (i = 1; i <= FIELDWIDTH; i++) {
|
|
|
|
|
lastSaveArray[i][j] = editObjArray[i][j]; // Copy for "saveOK()".
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Re-enable player input.
|
|
|
|
|
loading = FALSE;
|
|
|
|
|
|
|
|
|
|
view->updateCanvas(); // Show the edit area.
|
|
|
|
|
view->update(); // Show the level name.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::updateLevel()
|
|
|
|
|
{
|
|
|
|
|
if (! saveOK (FALSE)) { // Check unsaved work.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! ownerOK (USER)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Edit Level"),
|
|
|
|
|
i18n("You cannot edit and save a level until you "
|
|
|
|
|
"have created a game and a level. Try menu item \"Create Game\"."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (level < 0) level = 0;
|
|
|
|
|
int lev = selectLevel (SL_UPDATE, level);
|
|
|
|
|
if (lev == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (owner == SYSTEM) {
|
|
|
|
|
KGrMessage::information (view, i18n("Edit Level"),
|
|
|
|
|
i18n("It is OK to edit a system level, but you MUST save "
|
|
|
|
|
"the level in one of your own games. You're not just "
|
|
|
|
|
"taking a peek at the hidden ladders "
|
|
|
|
|
"and fall-through bricks, are you? :-)"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loadEditLevel (lev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::updateNext()
|
|
|
|
|
{
|
|
|
|
|
if (! saveOK (FALSE)) { // Check unsaved work.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
level++;
|
|
|
|
|
updateLevel();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::loadEditLevel (int lev)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
TQFile levelFile;
|
|
|
|
|
|
|
|
|
|
if (! openLevelFile (lev, levelFile))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Ignore player input from keyboard or mouse while the screen is set up.
|
|
|
|
|
loading = TRUE;
|
|
|
|
|
|
|
|
|
|
level = lev;
|
|
|
|
|
initEdit();
|
|
|
|
|
|
|
|
|
|
// Load the level.
|
|
|
|
|
for (j = 1; j <= FIELDHEIGHT; j++)
|
|
|
|
|
for (i = 1; i <= FIELDWIDTH; i++) {
|
|
|
|
|
editObj = levelFile.getch ();
|
|
|
|
|
insertEditObj (i, j);
|
|
|
|
|
editObjArray[i][j] = editObj;
|
|
|
|
|
lastSaveArray[i][j] = editObjArray[i][j]; // Copy for "saveOK()".
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read a newline character, then read in the level name and hint (if any).
|
|
|
|
|
int c = levelFile.getch();
|
|
|
|
|
TQCString levelHintC = "";
|
|
|
|
|
TQCString levelNameC = "";
|
|
|
|
|
levelHint = "";
|
|
|
|
|
levelName = "";
|
|
|
|
|
i = 1;
|
|
|
|
|
while ((c = levelFile.getch()) != EOF) {
|
|
|
|
|
switch (i) {
|
|
|
|
|
case 1: if (c == '\n') // Level name is on one line.
|
|
|
|
|
i = 2;
|
|
|
|
|
else
|
|
|
|
|
levelNameC += (char) c;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: levelHintC += (char) c; // Hint is on rest of file.
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Retain the original language of the name and hint when editing,
|
|
|
|
|
// but remove the final \n and convert non-ASCII, UTF-8 substrings
|
|
|
|
|
// to Unicode (eg. ü to <20>).
|
|
|
|
|
int len = levelHintC.length();
|
|
|
|
|
if (len > 0)
|
|
|
|
|
levelHint = TQString::fromUtf8((const char *) levelHintC.left(len-1));
|
|
|
|
|
|
|
|
|
|
len = levelNameC.length();
|
|
|
|
|
if (len > 0)
|
|
|
|
|
levelName = TQString::fromUtf8((const char *) levelNameC);
|
|
|
|
|
|
|
|
|
|
editObj = BRICK; // Reset default object.
|
|
|
|
|
levelFile.close ();
|
|
|
|
|
|
|
|
|
|
view->setTitle (getTitle()); // Show the level name.
|
|
|
|
|
view->updateCanvas(); // Show the edit area.
|
|
|
|
|
showEditLevel(); // Reconnect signals.
|
|
|
|
|
|
|
|
|
|
// Re-enable player input.
|
|
|
|
|
loading = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::editNameAndHint()
|
|
|
|
|
{
|
|
|
|
|
if (! editMode)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Run a dialog box to create/edit the level name and hint.
|
|
|
|
|
KGrNHDialog * nh = new KGrNHDialog (levelName, levelHint, view, "NHDialog");
|
|
|
|
|
|
|
|
|
|
if (nh->exec() == TQDialog::Accepted) {
|
|
|
|
|
levelName = nh->getName();
|
|
|
|
|
levelHint = nh->getHint();
|
|
|
|
|
shouldSave = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete nh;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::saveLevelFile()
|
|
|
|
|
{
|
|
|
|
|
bool isNew;
|
|
|
|
|
int action;
|
|
|
|
|
int selectedLevel = level;
|
|
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
|
TQString filePath;
|
|
|
|
|
|
|
|
|
|
if (! editMode) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Level"),
|
|
|
|
|
i18n("Inappropriate action: you are not editing a level."));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the current collection index.
|
|
|
|
|
int N = collnIndex;
|
|
|
|
|
|
|
|
|
|
if (selectedLevel == 0) {
|
|
|
|
|
// New level: choose a number.
|
|
|
|
|
action = SL_CREATE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Existing level: confirm the number or choose a new number.
|
|
|
|
|
action = SL_SAVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pop up dialog box, which could change the collection or level or both.
|
|
|
|
|
selectedLevel = selectLevel (action, selectedLevel);
|
|
|
|
|
if (selectedLevel == 0)
|
|
|
|
|
return (FALSE);
|
|
|
|
|
|
|
|
|
|
// Get the new collection (if changed).
|
|
|
|
|
int n = collnIndex;
|
|
|
|
|
|
|
|
|
|
// Set the name of the output file.
|
|
|
|
|
filePath = getFilePath (owner, collection, selectedLevel);
|
|
|
|
|
TQFile levelFile (filePath);
|
|
|
|
|
|
|
|
|
|
if ((action == SL_SAVE) && (n == N) && (selectedLevel == level)) {
|
|
|
|
|
// This is a normal edit: the old file is to be re-written.
|
|
|
|
|
isNew = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
isNew = TRUE;
|
|
|
|
|
// Check if the file is to be inserted in or appended to the collection.
|
|
|
|
|
if (levelFile.exists()) {
|
|
|
|
|
switch (KGrMessage::warning (view, i18n("Save Level"),
|
|
|
|
|
i18n("Do you want to insert a level and "
|
|
|
|
|
"move existing levels up by one?"),
|
|
|
|
|
i18n("&Insert Level"), i18n("&Cancel"))) {
|
|
|
|
|
|
|
|
|
|
case 0: if (! reNumberLevels (n, selectedLevel,
|
|
|
|
|
collections.at(n)->nLevels, +1)) {
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 1: return (FALSE);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open the output file.
|
|
|
|
|
if (! levelFile.open (IO_WriteOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Level"),
|
|
|
|
|
i18n("Cannot open file '%1' for output.").arg(filePath));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the level.
|
|
|
|
|
for (j = 1; j < 21; j++)
|
|
|
|
|
for (i = 1; i < 29; i++) {
|
|
|
|
|
levelFile.putch (editObjArray[i][j]);
|
|
|
|
|
lastSaveArray[i][j] = editObjArray[i][j]; // Copy for "saveOK()".
|
|
|
|
|
}
|
|
|
|
|
levelFile.putch ('\n');
|
|
|
|
|
|
|
|
|
|
// Save the level name, changing non-ASCII chars to UTF-8 (eg. <20> to ü).
|
|
|
|
|
TQCString levelNameC = levelName.utf8();
|
|
|
|
|
int len1 = levelNameC.length();
|
|
|
|
|
if (len1 > 0) {
|
|
|
|
|
for (i = 0; i < len1; i++)
|
|
|
|
|
levelFile.putch (levelNameC[i]);
|
|
|
|
|
levelFile.putch ('\n'); // Add a newline.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the level hint, changing non-ASCII chars to UTF-8 (eg. <20> to ü).
|
|
|
|
|
TQCString levelHintC = levelHint.utf8();
|
|
|
|
|
int len2 = levelHintC.length();
|
|
|
|
|
char ch = '\0';
|
|
|
|
|
|
|
|
|
|
if (len2 > 0) {
|
|
|
|
|
if (len1 <= 0)
|
|
|
|
|
levelFile.putch ('\n'); // Leave blank line for name.
|
|
|
|
|
for (i = 0; i < len2; i++) {
|
|
|
|
|
ch = levelHintC[i];
|
|
|
|
|
levelFile.putch (ch); // Copy the character.
|
|
|
|
|
}
|
|
|
|
|
if (ch != '\n')
|
|
|
|
|
levelFile.putch ('\n'); // Add a newline character.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
levelFile.close ();
|
|
|
|
|
shouldSave = FALSE;
|
|
|
|
|
|
|
|
|
|
if (isNew) {
|
|
|
|
|
collections.at(n)->nLevels++;
|
|
|
|
|
saveCollections (owner);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
level = selectedLevel;
|
|
|
|
|
emit showLevel (level);
|
|
|
|
|
view->setTitle (getTitle()); // Display new title.
|
|
|
|
|
view->updateCanvas(); // Show the edit area.
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::moveLevelFile ()
|
|
|
|
|
{
|
|
|
|
|
if (level <= 0) {
|
|
|
|
|
KGrMessage::information (view, i18n("Move Level"),
|
|
|
|
|
i18n("You must first load a level to be moved. Use "
|
|
|
|
|
"the %1 or %2 menu.")
|
|
|
|
|
.arg("\"" + i18n("Game") + "\"")
|
|
|
|
|
.arg("\"" + i18n("Editor") + "\""));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int action = SL_MOVE;
|
|
|
|
|
|
|
|
|
|
int fromC = collnIndex;
|
|
|
|
|
int fromL = level;
|
|
|
|
|
int toC = fromC;
|
|
|
|
|
int toL = fromL;
|
|
|
|
|
|
|
|
|
|
if (! ownerOK (USER)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Move Level"),
|
|
|
|
|
i18n("You cannot move a level until you "
|
|
|
|
|
"have created a game and at least two levels. Try "
|
|
|
|
|
"menu item \"Create Game\"."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (collections.at(fromC)->owner != USER) {
|
|
|
|
|
KGrMessage::information (view, i18n("Move Level"),
|
|
|
|
|
i18n("Sorry, you cannot move a system level."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pop up dialog box to get the collection and level number to move to.
|
|
|
|
|
while ((toC == fromC) && (toL == fromL)) {
|
|
|
|
|
toL = selectLevel (action, toL);
|
|
|
|
|
if (toL == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
toC = collnIndex;
|
|
|
|
|
|
|
|
|
|
if ((toC == fromC) && (toL == fromL)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Move Level"),
|
|
|
|
|
i18n("You must change the level or the game or both."));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQDir dir;
|
|
|
|
|
TQString filePath1;
|
|
|
|
|
TQString filePath2;
|
|
|
|
|
|
|
|
|
|
// Save the "fromN" file under a temporary name.
|
|
|
|
|
filePath1 = getFilePath (USER, collections.at(fromC), fromL);
|
|
|
|
|
filePath2 = filePath1;
|
|
|
|
|
filePath2 = filePath2.append (".tmp");
|
|
|
|
|
dir.rename (filePath1, filePath2, TRUE);
|
|
|
|
|
|
|
|
|
|
if (toC == fromC) { // Same collection.
|
|
|
|
|
if (toL < fromL) { // Decrease level.
|
|
|
|
|
// Move "toL" to "fromL - 1" up by 1.
|
|
|
|
|
if (! reNumberLevels (toC, toL, fromL-1, +1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { // Increase level.
|
|
|
|
|
// Move "fromL + 1" to "toL" down by 1.
|
|
|
|
|
if (! reNumberLevels (toC, fromL+1, toL, -1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { // Different collection.
|
|
|
|
|
// In "fromC", move "fromL + 1" to "nLevels" down and update "nLevels".
|
|
|
|
|
if (! reNumberLevels (fromC, fromL + 1,
|
|
|
|
|
collections.at(fromC)->nLevels, -1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
collections.at(fromC)->nLevels--;
|
|
|
|
|
|
|
|
|
|
// In "toC", move "toL + 1" to "nLevels" up and update "nLevels".
|
|
|
|
|
if (! reNumberLevels (toC, toL, collections.at(toC)->nLevels, +1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
collections.at(toC)->nLevels++;
|
|
|
|
|
|
|
|
|
|
saveCollections (USER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rename the saved "fromL" file to become "toL".
|
|
|
|
|
filePath1 = getFilePath (USER, collections.at(toC), toL);
|
|
|
|
|
dir.rename (filePath2, filePath1, TRUE);
|
|
|
|
|
|
|
|
|
|
level = toL;
|
|
|
|
|
collection = collections.at(toC);
|
|
|
|
|
view->setTitle (getTitle()); // Re-write title.
|
|
|
|
|
view->updateCanvas(); // Re-display details of level.
|
|
|
|
|
emit showLevel (level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::deleteLevelFile ()
|
|
|
|
|
{
|
|
|
|
|
int action = SL_DELETE;
|
|
|
|
|
int lev = level;
|
|
|
|
|
|
|
|
|
|
if (! ownerOK (USER)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Delete Level"),
|
|
|
|
|
i18n("You cannot delete a level until you "
|
|
|
|
|
"have created a game and a level. Try "
|
|
|
|
|
"menu item \"Create Game\"."));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pop up dialog box to get the collection and level number.
|
|
|
|
|
lev = selectLevel (action, level);
|
|
|
|
|
if (lev == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
TQString filePath;
|
|
|
|
|
|
|
|
|
|
// Set the name of the file to be deleted.
|
|
|
|
|
int n = collnIndex;
|
|
|
|
|
filePath = getFilePath (USER, collections.at(n), lev);
|
|
|
|
|
TQFile levelFile (filePath);
|
|
|
|
|
|
|
|
|
|
// Delete the file for the selected collection and level.
|
|
|
|
|
if (levelFile.exists()) {
|
|
|
|
|
if (lev < collections.at(n)->nLevels) {
|
|
|
|
|
switch (KGrMessage::warning (view, i18n("Delete Level"),
|
|
|
|
|
i18n("Do you want to delete a level and "
|
|
|
|
|
"move higher levels down by one?"),
|
|
|
|
|
i18n("&Delete Level"), i18n("&Cancel"))) {
|
|
|
|
|
case 0: break;
|
|
|
|
|
case 1: return; break;
|
|
|
|
|
}
|
|
|
|
|
levelFile.remove ();
|
|
|
|
|
if (! reNumberLevels (n, lev + 1, collections.at(n)->nLevels, -1)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
levelFile.remove ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
KGrMessage::information (view, i18n("Delete Level"),
|
|
|
|
|
i18n("Cannot find file '%1' to be deleted.").arg(filePath));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
collections.at(n)->nLevels--;
|
|
|
|
|
saveCollections (USER);
|
|
|
|
|
if (lev <= collections.at(n)->nLevels) {
|
|
|
|
|
level = lev;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
level = collections.at(n)->nLevels;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Repaint the screen with the level that now has the selected number.
|
|
|
|
|
if (editMode && (level > 0)) {
|
|
|
|
|
loadEditLevel (level); // Load level in edit mode.
|
|
|
|
|
}
|
|
|
|
|
else if (level > 0) {
|
|
|
|
|
enemyCount = 0; // Load level in play mode.
|
|
|
|
|
enemies.clear();
|
|
|
|
|
view->deleteEnemySprites();
|
|
|
|
|
newLevel = TRUE;;
|
|
|
|
|
loadLevel (level);
|
|
|
|
|
newLevel = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
createLevel(); // No levels left in collection.
|
|
|
|
|
}
|
|
|
|
|
emit showLevel (level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::editCollection (int action)
|
|
|
|
|
{
|
|
|
|
|
int lev = level;
|
|
|
|
|
int n = -1;
|
|
|
|
|
|
|
|
|
|
// If editing, choose a collection.
|
|
|
|
|
if (action == SL_UPD_GAME) {
|
|
|
|
|
lev = selectLevel (SL_UPD_GAME, level);
|
|
|
|
|
if (lev == 0)
|
|
|
|
|
return;
|
|
|
|
|
level = lev;
|
|
|
|
|
n = collnIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KGrECDialog * ec = new KGrECDialog (action, n, collections,
|
|
|
|
|
view, "editGameDialog");
|
|
|
|
|
|
|
|
|
|
while (ec->exec() == TQDialog::Accepted) { // Loop until valid.
|
|
|
|
|
|
|
|
|
|
// Validate the collection details.
|
|
|
|
|
TQString ecName = ec->getName();
|
|
|
|
|
int len = ecName.length();
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("You must enter a name for the game."));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQString ecPrefix = ec->getPrefix();
|
|
|
|
|
if ((action == SL_CR_GAME) || (collections.at(n)->nLevels <= 0)) {
|
|
|
|
|
// The filename prefix could have been entered, so validate it.
|
|
|
|
|
len = ecPrefix.length();
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("You must enter a filename prefix for the game."));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (len > 5) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("The filename prefix should not "
|
|
|
|
|
"be more than 5 characters."));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool allAlpha = TRUE;
|
|
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
|
if (! isalpha(ecPrefix.myChar(i))) {
|
|
|
|
|
allAlpha = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (! allAlpha) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("The filename prefix should be "
|
|
|
|
|
"all alphabetic characters."));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool duplicatePrefix = FALSE;
|
|
|
|
|
KGrCollection * c;
|
|
|
|
|
int imax = collections.count();
|
|
|
|
|
for (int i = 0; i < imax; i++) {
|
|
|
|
|
c = collections.at(i);
|
|
|
|
|
if ((c->prefix == ecPrefix) && (i != n)) {
|
|
|
|
|
duplicatePrefix = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (duplicatePrefix) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("The filename prefix '%1' is already in use.")
|
|
|
|
|
.arg(ecPrefix));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the collection details.
|
|
|
|
|
char settings = 'K';
|
|
|
|
|
if (ec->isTrad()) {
|
|
|
|
|
settings = 'T';
|
|
|
|
|
}
|
|
|
|
|
if (action == SL_CR_GAME) {
|
|
|
|
|
collections.append (new KGrCollection (USER,
|
|
|
|
|
ecName, ecPrefix, settings, 0, ec->getAboutText()));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
collection->name = ecName;
|
|
|
|
|
collection->prefix = ecPrefix;
|
|
|
|
|
collection->settings = settings;
|
|
|
|
|
collection->about = ec->getAboutText();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveCollections (USER);
|
|
|
|
|
break; // All done now.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete ec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/********************* SUPPORTING GAME EDITOR FUNCTIONS *********************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
bool KGrGame::saveOK (bool exiting)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
bool result;
|
|
|
|
|
TQString option2 = i18n("&Go on editing");
|
|
|
|
|
|
|
|
|
|
result = TRUE;
|
|
|
|
|
|
|
|
|
|
if (editMode) {
|
|
|
|
|
if (exiting) { // If window is closing,
|
|
|
|
|
option2 = ""; // can't go on editing.
|
|
|
|
|
}
|
|
|
|
|
for (j = 1; j <= FIELDHEIGHT; j++)
|
|
|
|
|
for (i = 1; i <= FIELDWIDTH; i++) { // Check cell changes.
|
|
|
|
|
if ((shouldSave) || (editObjArray[i][j] != lastSaveArray[i][j])) {
|
|
|
|
|
// If shouldSave == TRUE, level name or hint was edited.
|
|
|
|
|
switch (KGrMessage::warning (view, i18n("Editor"),
|
|
|
|
|
i18n("You have not saved your work. Do "
|
|
|
|
|
"you want to save it now?"),
|
|
|
|
|
i18n("&Save"), i18n("&Don't Save"), option2)) {
|
|
|
|
|
case 0: result = saveLevelFile(); break;// Save and continue.
|
|
|
|
|
case 1: shouldSave = FALSE; break; // Continue: don't save.
|
|
|
|
|
case 2: result = FALSE; break; // Go back to editing.
|
|
|
|
|
}
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::initEdit()
|
|
|
|
|
{
|
|
|
|
|
if (! editMode) {
|
|
|
|
|
|
|
|
|
|
editMode = TRUE;
|
|
|
|
|
emit setEditMenu (TRUE); // Enable edit menu items and toolbar.
|
|
|
|
|
|
|
|
|
|
// We were previously in play mode: stop the hero running or falling.
|
|
|
|
|
hero->init (1, 1);
|
|
|
|
|
view->setHeroVisible (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
paintEditObj = FALSE;
|
|
|
|
|
|
|
|
|
|
// Set the default object and button.
|
|
|
|
|
editObj = BRICK;
|
|
|
|
|
emit defaultEditObj(); // Set default edit-toolbar button.
|
|
|
|
|
|
|
|
|
|
oldI = 0;
|
|
|
|
|
oldJ = 0;
|
|
|
|
|
heroCount = 0;
|
|
|
|
|
enemyCount = 0;
|
|
|
|
|
enemies.clear();
|
|
|
|
|
view->deleteEnemySprites();
|
|
|
|
|
nuggets = 0;
|
|
|
|
|
|
|
|
|
|
emit showLevel (level);
|
|
|
|
|
emit showLives (0);
|
|
|
|
|
emit showScore (0);
|
|
|
|
|
|
|
|
|
|
deleteLevel();
|
|
|
|
|
setBlankLevel(FALSE); // Fill playfield with Editable objects.
|
|
|
|
|
|
|
|
|
|
view->setTitle (getTitle());// Show title of level.
|
|
|
|
|
view->updateCanvas(); // Show the edit area.
|
|
|
|
|
|
|
|
|
|
shouldSave = FALSE; // Used to flag editing of name or hint.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::deleteLevel()
|
|
|
|
|
{
|
|
|
|
|
int i,j;
|
|
|
|
|
for (i = 1; i <= FIELDHEIGHT; i++)
|
|
|
|
|
for (j = 1; j <= FIELDWIDTH; j++)
|
|
|
|
|
delete playfield[j][i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::insertEditObj (int i, int j)
|
|
|
|
|
{
|
|
|
|
|
if ((i < 1) || (j < 1) || (i > FIELDWIDTH) || (j > FIELDHEIGHT))
|
|
|
|
|
return; // Do nothing: mouse pointer is out of playfield.
|
|
|
|
|
|
|
|
|
|
if (editObjArray[i][j] == HERO) {
|
|
|
|
|
// The hero is in this cell: remove him.
|
|
|
|
|
editObjArray[i][j] = FREE;
|
|
|
|
|
heroCount = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (editObj == HERO) {
|
|
|
|
|
if (heroCount != 0) {
|
|
|
|
|
// Can only have one hero: remove him from his previous position.
|
|
|
|
|
for (int m = 1; m <= FIELDWIDTH; m++)
|
|
|
|
|
for (int n = 1; n <= FIELDHEIGHT; n++) {
|
|
|
|
|
if (editObjArray[m][n] == HERO) {
|
|
|
|
|
setEditableCell (m, n, FREE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
heroCount = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setEditableCell (i, j, editObj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::setEditableCell (int i, int j, char type)
|
|
|
|
|
{
|
|
|
|
|
((KGrEditable *) playfield[i][j])->setType (type);
|
|
|
|
|
view->paintCell (i, j, type);
|
|
|
|
|
editObjArray[i][j] = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::showEditLevel()
|
|
|
|
|
{
|
|
|
|
|
// Disconnect play-mode slots from signals from "view".
|
|
|
|
|
disconnect (view, TQT_SIGNAL(mouseClick(int)), 0, 0);
|
|
|
|
|
disconnect (view, TQT_SIGNAL(mouseLetGo(int)), 0, 0);
|
|
|
|
|
|
|
|
|
|
// Connect edit-mode slots to signals from "view".
|
|
|
|
|
connect (view, TQT_SIGNAL(mouseClick(int)), TQT_SLOT(doEdit(int)));
|
|
|
|
|
connect (view, TQT_SIGNAL(mouseLetGo(int)), TQT_SLOT(endEdit(int)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::reNumberLevels (int cIndex, int first, int last, int inc)
|
|
|
|
|
{
|
|
|
|
|
int i, n, step;
|
|
|
|
|
TQDir dir;
|
|
|
|
|
TQString file1, file2;
|
|
|
|
|
|
|
|
|
|
if (inc > 0) {
|
|
|
|
|
i = last;
|
|
|
|
|
n = first - 1;
|
|
|
|
|
step = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
i = first;
|
|
|
|
|
n = last + 1;
|
|
|
|
|
step = +1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (i != n) {
|
|
|
|
|
file1 = getFilePath (USER, collections.at(cIndex), i);
|
|
|
|
|
file2 = getFilePath (USER, collections.at(cIndex), i - step);
|
|
|
|
|
if (! dir.rename (file1, file2, TRUE)) { // Allow absolute paths.
|
|
|
|
|
KGrMessage::information (view, i18n("Save Level"),
|
|
|
|
|
i18n("Cannot rename file '%1' to '%2'.")
|
|
|
|
|
.arg(file1).arg(file2));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
i = i + step;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::setLevel (int lev)
|
|
|
|
|
{
|
|
|
|
|
level = lev;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/********************* EDIT ACTION SLOTS **********************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::doEdit (int button)
|
|
|
|
|
{
|
|
|
|
|
// Mouse button down: start making changes.
|
|
|
|
|
TQPoint p;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
p = view->getMousePos ();
|
|
|
|
|
i = p.x(); j = p.y();
|
|
|
|
|
|
|
|
|
|
switch (button) {
|
|
|
|
|
case Qt::LeftButton:
|
|
|
|
|
case Qt::RightButton:
|
|
|
|
|
paintEditObj = TRUE;
|
|
|
|
|
insertEditObj (i, j);
|
|
|
|
|
view->updateCanvas();
|
|
|
|
|
oldI = i;
|
|
|
|
|
oldJ = j;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::endEdit (int button)
|
|
|
|
|
{
|
|
|
|
|
// Mouse button released: finish making changes.
|
|
|
|
|
TQPoint p;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
p = view->getMousePos ();
|
|
|
|
|
i = p.x(); j = p.y();
|
|
|
|
|
|
|
|
|
|
switch (button) {
|
|
|
|
|
case Qt::LeftButton:
|
|
|
|
|
case Qt::RightButton:
|
|
|
|
|
paintEditObj = FALSE;
|
|
|
|
|
if ((i != oldI) || (j != oldJ)) {
|
|
|
|
|
insertEditObj (i, j);
|
|
|
|
|
view->updateCanvas();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/********************** LEVEL SELECTION DIALOG BOX **********************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
int KGrGame::selectLevel (int action, int requestedLevel)
|
|
|
|
|
{
|
|
|
|
|
int selectedLevel = 0; // 0 = no selection (Cancel) or invalid.
|
|
|
|
|
|
|
|
|
|
// Halt the game during the dialog.
|
|
|
|
|
modalFreeze = FALSE;
|
|
|
|
|
if (! KGrObject::frozen) {
|
|
|
|
|
modalFreeze = TRUE;
|
|
|
|
|
freeze();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create and run a modal dialog box to select a game and level.
|
|
|
|
|
KGrSLDialog * sl = new KGrSLDialog (action, requestedLevel, collnIndex,
|
|
|
|
|
collections, this, view, "levelDialog");
|
|
|
|
|
while (sl->exec() == TQDialog::Accepted) {
|
|
|
|
|
selectedGame = sl->selectedGame();
|
|
|
|
|
selectedLevel = 0; // In case the selection is invalid.
|
|
|
|
|
if (collections.at(selectedGame)->owner == SYSTEM) {
|
|
|
|
|
switch (action) {
|
|
|
|
|
case SL_CREATE: // Can save only in a USER collection.
|
|
|
|
|
case SL_SAVE:
|
|
|
|
|
case SL_MOVE:
|
|
|
|
|
KGrMessage::information (view, i18n("Select Level"),
|
|
|
|
|
i18n("Sorry, you can only save or move "
|
|
|
|
|
"into one of your own games."));
|
|
|
|
|
continue; // Re-run the dialog box.
|
|
|
|
|
break;
|
|
|
|
|
case SL_DELETE: // Can delete only in a USER collection.
|
|
|
|
|
KGrMessage::information (view, i18n("Select Level"),
|
|
|
|
|
i18n("Sorry, you can only delete a level "
|
|
|
|
|
"from one of your own games."));
|
|
|
|
|
continue; // Re-run the dialog box.
|
|
|
|
|
break;
|
|
|
|
|
case SL_UPD_GAME: // Can edit info only in a USER collection.
|
|
|
|
|
KGrMessage::information (view, i18n("Edit Game Info"),
|
|
|
|
|
i18n("Sorry, you can only edit the game "
|
|
|
|
|
"information on your own games."));
|
|
|
|
|
continue; // Re-run the dialog box.
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
selectedLevel = sl->selectedLevel();
|
|
|
|
|
if ((selectedLevel > collections.at (selectedGame)->nLevels) &&
|
|
|
|
|
(action != SL_CREATE) && (action != SL_SAVE) &&
|
|
|
|
|
(action != SL_MOVE) && (action != SL_UPD_GAME)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Select Level"),
|
|
|
|
|
i18n("There is no level %1 in %2, "
|
|
|
|
|
"so you cannot play or edit it.")
|
|
|
|
|
.arg(selectedLevel)
|
|
|
|
|
.arg("\"" + collections.at(selectedGame)->name + "\""));
|
|
|
|
|
selectedLevel = 0; // Set an invalid selection.
|
|
|
|
|
continue; // Re-run the dialog box.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If "OK", set the results.
|
|
|
|
|
collection = collections.at (selectedGame);
|
|
|
|
|
owner = collection->owner;
|
|
|
|
|
collnIndex = selectedGame;
|
|
|
|
|
// Set default rules for selected game.
|
|
|
|
|
emit markRuleType (collection->settings);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unfreeze the game, but only if it was previously unfrozen.
|
|
|
|
|
if (modalFreeze) {
|
|
|
|
|
unfreeze();
|
|
|
|
|
modalFreeze = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete sl;
|
|
|
|
|
return (selectedLevel); // 0 = cancelled or invalid.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::ownerOK (Owner o)
|
|
|
|
|
{
|
|
|
|
|
// Check that this owner has at least one collection.
|
|
|
|
|
KGrCollection * c;
|
|
|
|
|
bool OK = FALSE;
|
|
|
|
|
|
|
|
|
|
for (c = collections.first(); c != 0; c = collections.next()) {
|
|
|
|
|
if (c->owner == o) {
|
|
|
|
|
OK = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/********************** CLASS TO DISPLAY THUMBNAIL ***********************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
KGrThumbNail::KGrThumbNail (TQWidget * parent, const char * name)
|
|
|
|
|
: TQFrame (parent, name)
|
|
|
|
|
{
|
|
|
|
|
// Let the parent do all the work. We need a class here so that
|
|
|
|
|
// TQFrame::drawContents (TQPainter *) can be re-implemented and
|
|
|
|
|
// the thumbnail can be automatically re-painted when required.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQColor KGrThumbNail::backgroundColor = TQColor ("#dddddd");
|
|
|
|
|
TQColor KGrThumbNail::brickColor = TQColor ("#ff0000");
|
|
|
|
|
TQColor KGrThumbNail::ladderColor = TQColor ("#ddcc00");
|
|
|
|
|
TQColor KGrThumbNail::poleColor = TQColor ("#aa7700");
|
|
|
|
|
|
|
|
|
|
void KGrThumbNail::setFilePath (TQString & fp, TQLabel * sln)
|
|
|
|
|
{
|
|
|
|
|
filePath = fp; // Keep safe copies of file
|
|
|
|
|
lName = sln; // path and level name field.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrThumbNail::drawContents (TQPainter * p) // Activated via "paintEvent".
|
|
|
|
|
{
|
|
|
|
|
TQFile openFile;
|
|
|
|
|
TQPen pen = p->pen();
|
|
|
|
|
char obj = FREE;
|
|
|
|
|
int fw = 1; // Set frame width.
|
|
|
|
|
int n = width() / FIELDWIDTH; // Set thumbnail cell-size.
|
|
|
|
|
|
|
|
|
|
pen.setColor (backgroundColor);
|
|
|
|
|
p->setPen (pen);
|
|
|
|
|
|
|
|
|
|
openFile.setName (filePath);
|
|
|
|
|
if ((! openFile.exists()) || (! openFile.open (IO_ReadOnly))) {
|
|
|
|
|
// There is no file, so fill the thumbnail with "FREE" cells.
|
|
|
|
|
p->drawRect (TQRect(fw, fw, FIELDWIDTH*n, FIELDHEIGHT*n));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < FIELDHEIGHT; j++)
|
|
|
|
|
for (int i = 0; i < FIELDWIDTH; i++) {
|
|
|
|
|
|
|
|
|
|
obj = openFile.getch();
|
|
|
|
|
|
|
|
|
|
// Set the colour of each object.
|
|
|
|
|
switch (obj) {
|
|
|
|
|
case BRICK:
|
|
|
|
|
case BETON:
|
|
|
|
|
case FBRICK:
|
|
|
|
|
pen.setColor (brickColor); p->setPen (pen); break;
|
|
|
|
|
case LADDER:
|
|
|
|
|
pen.setColor (ladderColor); p->setPen (pen); break;
|
|
|
|
|
case POLE:
|
|
|
|
|
pen.setColor (poleColor); p->setPen (pen); break;
|
|
|
|
|
case HERO:
|
|
|
|
|
pen.setColor (green); p->setPen (pen); break;
|
|
|
|
|
case ENEMY:
|
|
|
|
|
pen.setColor (blue); p->setPen (pen); break;
|
|
|
|
|
default:
|
|
|
|
|
// Set the background for FREE, HLADDER and NUGGET.
|
|
|
|
|
pen.setColor (backgroundColor); p->setPen (pen); break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw nxn pixels as n lines of length n.
|
|
|
|
|
p->drawLine (i*n+fw, j*n+fw, i*n+(n-1)+fw, j*n+fw);
|
|
|
|
|
if (obj == POLE) {
|
|
|
|
|
// For a pole, only the top line is drawn in white.
|
|
|
|
|
pen.setColor (backgroundColor);
|
|
|
|
|
p->setPen (pen);
|
|
|
|
|
}
|
|
|
|
|
for (int k = 1; k < n; k++) {
|
|
|
|
|
p->drawLine (i*n+fw, j*n+k+fw, i*n+(n-1)+fw, j*n+k+fw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For a nugget, add just a vertical touch of yellow (2-3 pixels).
|
|
|
|
|
if (obj == NUGGET) {
|
|
|
|
|
int k = (n/2)+fw;
|
|
|
|
|
// pen.setColor (TQColor("#ffff00"));
|
|
|
|
|
pen.setColor (ladderColor);
|
|
|
|
|
p->setPen (pen);
|
|
|
|
|
p->drawLine (i*n+k, j*n+k, i*n+k, j*n+(n-1)+fw);
|
|
|
|
|
p->drawLine (i*n+k+1, j*n+k, i*n+k+1, j*n+(n-1)+fw);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Absorb a newline character, then read in the level name (if any).
|
|
|
|
|
int c = openFile.getch();
|
|
|
|
|
TQCString s = "";
|
|
|
|
|
while ((c = openFile.getch()) != EOF) {
|
|
|
|
|
if (c == '\n') // Level name is on one line.
|
|
|
|
|
break;
|
|
|
|
|
s += (char) c;
|
|
|
|
|
}
|
|
|
|
|
if (s.length() > 0) // If there is a name, translate it.
|
|
|
|
|
lName->setText (i18n((const char *) s));
|
|
|
|
|
else
|
|
|
|
|
lName->setText ("");
|
|
|
|
|
|
|
|
|
|
openFile.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/************************* COLLECTIONS HANDLING ***************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
// NOTE: Macros "myStr" and "myChar", defined in "kgrgame.h", are used
|
|
|
|
|
// to smooth out differences between TQt 1 and TQt2 TQString classes.
|
|
|
|
|
|
|
|
|
|
bool KGrGame::initCollections ()
|
|
|
|
|
{
|
|
|
|
|
// Initialise the list of collections of levels (i.e. the list of games).
|
|
|
|
|
collections.setAutoDelete(TRUE);
|
|
|
|
|
owner = SYSTEM; // Use system levels initially.
|
|
|
|
|
if (! loadCollections (SYSTEM)) // Load system collections list.
|
|
|
|
|
return (FALSE); // If no collections, abort.
|
|
|
|
|
loadCollections (USER); // Load user collections list.
|
|
|
|
|
// If none, don't worry.
|
|
|
|
|
|
|
|
|
|
mapCollections(); // Check ".grl" file integrity.
|
|
|
|
|
|
|
|
|
|
// Set the default collection (first one in the SYSTEM "games.dat" file).
|
|
|
|
|
collnIndex = 0;
|
|
|
|
|
collection = collections.at (collnIndex);
|
|
|
|
|
level = 1; // Default start is at level 1.
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KGrGame::mapCollections()
|
|
|
|
|
{
|
|
|
|
|
TQDir d;
|
|
|
|
|
KGrCollection * colln;
|
|
|
|
|
TQString d_path;
|
|
|
|
|
TQString fileName1;
|
|
|
|
|
TQString fileName2;
|
|
|
|
|
|
|
|
|
|
// Find KGoldrunner level files, sorted by name (same as numerical order).
|
|
|
|
|
for (colln = collections.first(); colln != 0; colln = collections.next()) {
|
|
|
|
|
d.setPath ((colln->owner == SYSTEM) ? systemDataDir + "levels/"
|
|
|
|
|
: userDataDir + "levels/");
|
|
|
|
|
d_path = d.path();
|
|
|
|
|
if (! d.exists()) {
|
|
|
|
|
// There is no "levels" sub-directory: OK if game has no levels yet.
|
|
|
|
|
if (colln->nLevels > 0) {
|
|
|
|
|
KGrMessage::information (view, i18n("Check Games & Levels"),
|
|
|
|
|
i18n("There is no folder '%1' to hold levels for"
|
|
|
|
|
" the '%2' game. Please make sure '%3' "
|
|
|
|
|
"has been run in the '%4' folder.")
|
|
|
|
|
.arg(d_path)
|
|
|
|
|
.arg(colln->name)
|
|
|
|
|
.arg("tar xf levels.tar")
|
|
|
|
|
.arg(systemDataDir));
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TQFileInfoList * files = d.entryInfoList
|
|
|
|
|
(colln->prefix + "???.grl", TQDir::Files, TQDir::Name);
|
|
|
|
|
TQFileInfoListIterator i (* files);
|
|
|
|
|
TQFileInfo * file;
|
|
|
|
|
|
|
|
|
|
if ((files->count() <= 0) && (colln->nLevels > 0)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Check Games & Levels"),
|
|
|
|
|
i18n("There are no files '%1/%2???.grl' for the %3 game.")
|
|
|
|
|
.arg(d_path)
|
|
|
|
|
.arg(colln->prefix)
|
|
|
|
|
.arg("\"" + colln->name + "\""));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the prefix is "level", the first file is the "ENDE" screen.
|
|
|
|
|
int lev = (colln->prefix == "level") ? 0 : 1;
|
|
|
|
|
|
|
|
|
|
while ((file = i.current())) {
|
|
|
|
|
// Get the name of the file found on disk.
|
|
|
|
|
fileName1 = file->fileName();
|
|
|
|
|
|
|
|
|
|
while (TRUE) {
|
|
|
|
|
// Work out what the file name should be, based on the level no.
|
|
|
|
|
fileName2.setNum (lev); // Convert to TQString.
|
|
|
|
|
fileName2 = fileName2.rightJustify (3,'0'); // Add zeros.
|
|
|
|
|
fileName2.append (".grl"); // Add level-suffix.
|
|
|
|
|
fileName2.prepend (colln->prefix); // Add colln. prefix.
|
|
|
|
|
|
|
|
|
|
if (lev > colln->nLevels) {
|
|
|
|
|
KGrMessage::information (view,
|
|
|
|
|
i18n("Check Games & Levels"),
|
|
|
|
|
i18n("File '%1' is beyond the highest level for "
|
|
|
|
|
"the %2 game and cannot be played.")
|
|
|
|
|
.arg(fileName1)
|
|
|
|
|
.arg("\"" + colln->name + "\""));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (fileName1 == fileName2) {
|
|
|
|
|
lev++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (fileName1.myStr() < fileName2.myStr()) {
|
|
|
|
|
KGrMessage::information (view,
|
|
|
|
|
i18n("Check Games & Levels"),
|
|
|
|
|
i18n("File '%1' is before the lowest level for "
|
|
|
|
|
"the %2 game and cannot be played.")
|
|
|
|
|
.arg(fileName1)
|
|
|
|
|
.arg("\"" + colln->name + "\""));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
KGrMessage::information (view,
|
|
|
|
|
i18n("Check Games & Levels"),
|
|
|
|
|
i18n("Cannot find file '%1' for the %2 game.")
|
|
|
|
|
.arg(fileName2)
|
|
|
|
|
.arg("\"" + colln->name + "\""));
|
|
|
|
|
lev++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
++i; // Go to next file info entry.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::loadCollections (Owner o)
|
|
|
|
|
{
|
|
|
|
|
TQString filePath;
|
|
|
|
|
|
|
|
|
|
filePath = ((o == SYSTEM)? systemDataDir : userDataDir) + "games.dat";
|
|
|
|
|
|
|
|
|
|
TQFile c (filePath);
|
|
|
|
|
|
|
|
|
|
if (! c.exists()) {
|
|
|
|
|
// If the user has not yet created a collection, don't worry.
|
|
|
|
|
if (o == SYSTEM) {
|
|
|
|
|
KGrMessage::information (view, i18n("Load Game Info"),
|
|
|
|
|
i18n("Cannot find game info file '%1'.")
|
|
|
|
|
.arg(filePath));
|
|
|
|
|
}
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! c.open (IO_ReadOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Load Game Info"),
|
|
|
|
|
i18n("Cannot open file '%1' for read-only.").arg(filePath));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQCString line = "";
|
|
|
|
|
TQCString name = "";
|
|
|
|
|
TQString prefix = "";
|
|
|
|
|
char settings = ' ';
|
|
|
|
|
int nLevels = -1;
|
|
|
|
|
|
|
|
|
|
int ch = 0;
|
|
|
|
|
while (ch >= 0) {
|
|
|
|
|
ch = c.getch();
|
|
|
|
|
if (((char) ch != '\n') && (ch >= 0)) {
|
|
|
|
|
// If not end-of-line and not end-of-file, add to the line.
|
|
|
|
|
if (ch == '\r') {line += '\n';}
|
|
|
|
|
else if (ch == '\\') {ch = c.getch(); line += '\n';}
|
|
|
|
|
else {line += (char) ch;}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// If first character is a digit, we have a new collection.
|
|
|
|
|
if (isdigit(line[0])) {
|
|
|
|
|
if (nLevels >= 0) {
|
|
|
|
|
// If previous collection with no "about" exists, load it.
|
|
|
|
|
collections.append (new KGrCollection
|
|
|
|
|
(o, name, prefix, settings, nLevels, ""));
|
|
|
|
|
name = ""; prefix = ""; settings = ' '; nLevels = -1;
|
|
|
|
|
}
|
|
|
|
|
// Decode the first (maybe the only) line in the new collection.
|
|
|
|
|
line = line.simplifyWhiteSpace();
|
|
|
|
|
int i, j, len;
|
|
|
|
|
len = line.length();
|
|
|
|
|
i = 0; j = line.find(' ',i); nLevels = line.left(j).toInt();
|
|
|
|
|
i = j+1; j = line.find(' ',i); settings = line[i];
|
|
|
|
|
i = j+1; j = line.find(' ',i); prefix = line.mid(i,j-i);
|
|
|
|
|
i = j+1; name = line.right(len-i);
|
|
|
|
|
}
|
|
|
|
|
// If first character is not a digit, the line should be an "about".
|
|
|
|
|
else if (nLevels >= 0) {
|
|
|
|
|
collections.append (new KGrCollection
|
|
|
|
|
(o, i18n((const char *) name), // Translate now.
|
|
|
|
|
prefix, settings, nLevels,
|
|
|
|
|
TQString::fromUtf8((const char *) line)));
|
|
|
|
|
name = ""; prefix = ""; settings = ' '; nLevels = -1;
|
|
|
|
|
}
|
|
|
|
|
else if (ch >= 0) {
|
|
|
|
|
// Not EOF: it's an empty line or out-of-context "about" line.
|
|
|
|
|
KGrMessage::information (view, i18n("Load Game Info"),
|
|
|
|
|
i18n("Format error in game info file '%1'.")
|
|
|
|
|
.arg(filePath));
|
|
|
|
|
c.close();
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
line = "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.close();
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool KGrGame::saveCollections (Owner o)
|
|
|
|
|
{
|
|
|
|
|
TQString filePath;
|
|
|
|
|
|
|
|
|
|
if (o != USER) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("You can only modify user games."));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
filePath = ((o == SYSTEM)? systemDataDir : userDataDir) + "games.dat";
|
|
|
|
|
|
|
|
|
|
TQFile c (filePath);
|
|
|
|
|
|
|
|
|
|
// Open the output file.
|
|
|
|
|
if (! c.open (IO_WriteOnly)) {
|
|
|
|
|
KGrMessage::information (view, i18n("Save Game Info"),
|
|
|
|
|
i18n("Cannot open file '%1' for output.").arg(filePath));
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save the collections.
|
|
|
|
|
KGrCollection * colln;
|
|
|
|
|
TQCString line;
|
|
|
|
|
int i, len;
|
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
|
|
for (colln = collections.first(); colln != 0; colln = collections.next()) {
|
|
|
|
|
if (colln->owner == o) {
|
|
|
|
|
line.sprintf ("%03d %c %s %s\n", colln->nLevels, colln->settings,
|
|
|
|
|
colln->prefix.myStr(),
|
|
|
|
|
(const char *) colln->name.utf8());
|
|
|
|
|
len = line.length();
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
c.putch (line[i]);
|
|
|
|
|
|
|
|
|
|
len = colln->about.length();
|
|
|
|
|
if (len > 0) {
|
|
|
|
|
TQCString aboutC = colln->about.utf8();
|
|
|
|
|
len = aboutC.length(); // Might be longer now.
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
ch = aboutC[i];
|
|
|
|
|
if (ch != '\n') {
|
|
|
|
|
c.putch (ch); // Copy the character.
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
c.putch ('\\'); // Change newline to \ and n.
|
|
|
|
|
c.putch ('n');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
c.putch ('\n'); // Add a real newline.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c.close();
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/********************** WORD-WRAPPED MESSAGE BOX ************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
void KGrGame::myMessage (TQWidget * parent, TQString title, TQString contents)
|
|
|
|
|
{
|
|
|
|
|
// Halt the game while the message is displayed.
|
|
|
|
|
setMessageFreeze (TRUE);
|
|
|
|
|
|
|
|
|
|
KGrMessage::wrapped (parent, title, contents);
|
|
|
|
|
|
|
|
|
|
// Unfreeze the game, but only if it was previously unfrozen.
|
|
|
|
|
setMessageFreeze (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
/*********************** COLLECTION DATA CLASS **************************/
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
|
|
KGrCollection::KGrCollection (Owner o, const TQString & n, const TQString & p,
|
|
|
|
|
const char s, int nl, const TQString & a)
|
|
|
|
|
{
|
|
|
|
|
// Holds information about a collection of KGoldrunner levels (i.e. a game).
|
|
|
|
|
owner = o; name = n; prefix = p; settings = s; nLevels = nl; about = a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "kgrgame.moc"
|