Initial commit2

This commit is contained in:
Niels 2025-05-30 16:09:44 +02:00
commit e24b1d5c01
42 changed files with 3154 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Use target-compatible line endings as the safe default for cross compilation.
* text=auto eol=lf

20
harbour-tetrafish.desktop Normal file
View File

@ -0,0 +1,20 @@
[Desktop Entry]
Type=Application
X-Nemo-Application-Type=silica-qt5
Icon=harbour-tetrafish
Exec=harbour-tetrafish
Name=harbour-tetrafish
# translation example:
# your app name in German locale (de)
#
# Remember to comment out the following line, if you do not want to use
# a different app name in German locale (de).
Name[de]=harbour-tetrafish
[X-Sailjail]
# Replace with your organization as a reverse domain name
OrganizationName=org.myorg
# ApplicationName does not have to be identical to Name
ApplicationName=tetrafish
# Add the required permissions here
Permissions=

39
harbour-tetrafish.pro Normal file
View File

@ -0,0 +1,39 @@
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = harbour-tetrafish
CONFIG += sailfishapp
SOURCES += src/harbour-tetrafish.cpp
DISTFILES += qml/harbour-tetrafish.qml \
qml/cover/CoverPage.qml \
qml/pages/FirstPage.qml \
qml/pages/SecondPage.qml \
rpm/harbour-tetrafish.changes.in \
rpm/harbour-tetrafish.changes.run.in \
rpm/harbour-tetrafish.spec \
translations/*.ts \
harbour-tetrafish.desktop
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the
# following CONFIG line
CONFIG += sailfishapp_i18n
# German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the
# following TRANSLATIONS line. And also do not forget to
# modify the localized app name in the the .desktop file.
TRANSLATIONS += translations/harbour-tetrafish-de.ts

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

65
qml/cover/CoverPage.qml Normal file
View File

@ -0,0 +1,65 @@
/*
Copyright (C) 2013 Jolla Ltd.
Contact: Thomas Perl <thomas.perl@jollamobile.com>
All rights reserved.
You may use this file under the terms of BSD license as follows:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Jolla Ltd nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
CoverBackground {
Image {
id: tetimg
source: "../data/tetris.png"
fillMode: Image.Stretch
width: parent.width
height: parent.height
opacity: 0.2
}
Column {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Image {
id: tetraimg
anchors.horizontalCenter: parent.horizontalCenter
source: "../data/tetrafish.png"
fillMode: Image.PreserveAspectFit
width: parent.width
height: parent.width
// opacity: 0.1
}
Label {
text: "TetraFish"
anchors.horizontalCenter: parent.horizontalCenter
font.pixelSize: Theme.fontSizeExtraLarge
color: Theme.highlightColor
}
}
}

Binary file not shown.

BIN
qml/data/back2back.wav Normal file

Binary file not shown.

BIN
qml/data/bonus.wav Normal file

Binary file not shown.

BIN
qml/data/dot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

BIN
qml/data/down.wav Normal file

Binary file not shown.

BIN
qml/data/gravity.wav Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
qml/data/harddrop.wav Normal file

Binary file not shown.

BIN
qml/data/levelup.wav Normal file

Binary file not shown.

BIN
qml/data/move.wav Normal file

Binary file not shown.

BIN
qml/data/nobonus.wav Normal file

Binary file not shown.

BIN
qml/data/rotate.wav Normal file

Binary file not shown.

BIN
qml/data/softdrop.wav Normal file

Binary file not shown.

BIN
qml/data/tetrafish.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
qml/data/tetris.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

BIN
qml/data/tetris.wav Normal file

Binary file not shown.

32
qml/game/Dot.qml Normal file
View File

@ -0,0 +1,32 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
GlassItem {
property int active: 0 // 0 = empty; 1 = active; 2 = inactive
property bool ghost: false
property bool glowing: false
id: dot
width: Theme.paddingLarge
height: width
radius: dots === 0 ? 0.3 : 0 // 0 ? 0.2 : 0
falloffRadius: dots === 0 ? 0.40 : 2 // 0 ? 0.25 : 2
color: Theme.highlightColor
Timer {
property bool up
id: glowingTimer
running: glowing
repeat: true
interval: 30
onTriggered: {
if (opacity === 1){
up = false
} else if (opacity < 0.5) {
up = true
}
if (up)
opacity += 0.05
else
opacity -= 0.05
}
}
}

1175
qml/game/Functions.qml Normal file

File diff suppressed because it is too large Load Diff

167
qml/game/HighScoreModel.qml Normal file
View File

@ -0,0 +1,167 @@
/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.0
import QtQuick.LocalStorage 2.0
// Models a high score table.
//
// Use this component like this:
//
// HighScoreModel {
// id: highScores
// game: "MyCoolGame"
// }
//
// Then use either use the top-score properties:
//
// Text { text: "HI: " + highScores.topScore }
//
// or, use the model in a view:
//
// ListView {
// model: highScore
// delegate: Component {
// ... player ... score ...
// }
// }
//
// Add new scores via:
//
// saveScore(newScore)
//
// or:
//
// savePlayerScore(playerName,newScore)
//
// The best maxScore scores added by this method will be retained in an SQL database,
// and presented in the model and in the topScore/topPlayer properties.
//
ListModel {
id: model
property string game: ""
property int topScore: 0
property string topPlayer: ""
property int place: 0
property int maxScores: 10
property bool newScore: false
onGameChanged: fillModel()
function __db()
{
return LocalStorage.openDatabaseSync("HighScoreModel", "1.0", "Generic High Score Functionality for QML", 1000000);
}
function __ensureTables(tx)
{
tx.executeSql('CREATE TABLE IF NOT EXISTS HighScores(game TEXT, score INT, player TEXT)', []);
}
function compareScore(point) {
__db().transaction( function(tx) {
__ensureTables(tx);
var rs = tx.executeSql("SELECT score,player FROM HighScores WHERE game=? ORDER BY score ASC", [game]);
if (rs.rows.length >= 10) {
if (point > rs.rows.item(0).score) newScore = true; else newScore = false;//return true; else return false;
} else newScore = true
var length = rs.rows.length
if (newScore){
var i=0
try {
while (point>rs.rows.item(i).score) i++;
place = (lenght-i)-1
} catch (e) {place = (length-i)+1}
}
})
}
function fillModel() {
__db().transaction(
function(tx) {
__ensureTables(tx);
var rs = tx.executeSql("SELECT score,player FROM HighScores WHERE game=? ORDER BY score DESC", [game]);
model.clear();
if (rs.rows.length > 0) {
topScore = rs.rows.item(0).score
topPlayer = rs.rows.item(0).player
// console.log('ts 0: '+rs.rows.item(0).score)
//console.log('ts 9: '+rs.rows.item(0).score)
for (var i=0; i<rs.rows.length; ++i) {
if (i < maxScores) {
//place = i+1
model.append(rs.rows.item(i))
}
}
if (rs.rows.length > maxScores)
tx.executeSql("DELETE FROM HighScores WHERE game=? AND score <= ?",
[game, rs.rows.item(maxScores).score]);
}
}
)
}
function savePlayerScore(player,score) {
__db().transaction(
function(tx) {
__ensureTables(tx);
tx.executeSql("INSERT INTO HighScores VALUES(?,?,?)", [game,score,player]);
fillModel();
}
)
}
function saveScore(score) {
savePlayerScore("player",score);
}
function clearScores() {
__db().transaction(
function(tx) {
tx.executeSql("DELETE FROM HighScores WHERE game=?", [game]);
fillModel();
}
)
}
Component.onCompleted: { fillModel() }
}

View File

@ -0,0 +1,5 @@
import QtQuick 2.0
Item {
}

33
qml/game/Square.qml Normal file
View File

@ -0,0 +1,33 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
GlassItem {
property int active: 0 // 0 = empty; 1 = active; 2 = inactive
property bool ghost: false
property bool glowing: false
id: square
width: Theme.paddingLarge*2
height: width
radius: dots === 0 ? 0.4 : 0 // 0 ? 0.2 : 0
falloffRadius: dots === 0 ? 0.25 : 2 // 0 ? 0.25 : 2
color: Theme.secondaryColor
opacity: 0.1
Timer {
property bool up
id: glowingTimer
running: glowing
repeat: true
interval: 30
onTriggered: {
if (opacity === 1){
up = false
} else if (opacity < 0.5) {
up = true
}
if (up)
opacity += 0.05
else
opacity -= 0.05
}
}
}

40
qml/harbour-tetrafish.qml Normal file
View File

@ -0,0 +1,40 @@
/*
Copyright (C) 2013 Jolla Ltd.
Contact: Thomas Perl <thomas.perl@jollamobile.com>
All rights reserved.
You may use this file under the terms of BSD license as follows:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Jolla Ltd nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import QtQuick 2.0
import Sailfish.Silica 1.0
import "pages"
ApplicationWindow {
initialPage: Component { GamePage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: defaultAllowedOrientations
}

76
qml/js/settings.js Normal file
View File

@ -0,0 +1,76 @@
var db = undefined;
function settings_db_open() {
if (db == undefined)
db = LocalStorage.openDatabaseSync("harbour-tetrafish", "1.0", "StorageDatabase", 100000);
return db;
}
/// GAME SETTINGS
function getValue(setting,def) {
var db = settings_db_open();
var res=def;
try {
db.transaction(function(tx) {
var rs = tx.executeSql('SELECT value FROM settings WHERE setting=?;', [setting]);
if (rs.rows.length > 0) {
res = rs.rows.item(0).value;
} else {
res = def;
}
})
} catch (err) {
res = def
};
return res
}
function setValue(setting, value) {
var db = settings_db_open();
var res = "";
db.transaction(function(tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS settings(setting TEXT UNIQUE, value TEXT)');
var rs = tx.executeSql('INSERT OR REPLACE INTO settings VALUES (?,?);', [setting,value]);
if (rs.rowsAffected > 0) {
res = "OK";
} else {
res = "Error";
}
}
);
return res;
}
/// LOAD/SAVE GAME
function getSave(setting,def) {
var db = settings_db_open();
var res=def;
try {
db.transaction(function(tx) {
var rs = tx.executeSql('SELECT value FROM savegame WHERE setting=?;', [setting]);
if (rs.rows.length > 0) {
res = rs.rows.item(0).value;
} else {
res = def;
}
})
} catch (err) {
res = def
};
return res
}
function setSave(setting, value) {
var db = settings_db_open();
var res = "";
db.transaction(function(tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS settings(savegame TEXT UNIQUE, value TEXT)');
var rs = tx.executeSql('INSERT OR REPLACE INTO savegame VALUES (?,?);', [setting,value]);
if (rs.rowsAffected > 0) {
res = "OK";
} else {
res = "Error";
}
}
);
return res;
}

97
qml/pages/About.qml Normal file
View File

@ -0,0 +1,97 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
SilicaFlickable {
id: flickable
anchors.fill: page
contentHeight: column.height
Column {
id: column
width: parent.width - Theme.paddingLarge*2
spacing: 20
anchors {
left: parent.left
leftMargin: Theme.paddingLarge
}
PageHeader { title: qsTr("TetraFish") }
Label {
width: parent.width
text: qsTr("A remake of SailTris which is a remake of Tetris\n")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignJustify
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("TetraFish is a remake of the game SailTris by Billy Halley, available on OpenRepos. I wanted to contribute to SailTris with some changes and fixes but Billy Halley had stopped he's development on Sailfish and SailTris and so was TetraFish with the kind approval of Billy Halley born. \n\nTetra fish is a common fish in a lot of aquariums and the original game Tetris got it's name from the greek numerical prefix tetra (4) symbolising the 4 segments making up every block in a Tetris game.")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignJustify
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("Controls")
color: Theme.highlightColor
anchors.right: parent.right
anchors.rightMargin: Theme.paddingLarge
font.pixelSize: Theme.fontSizeLarge
horizontalAlignment: Text.AlignRight
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("TetraFish i controlled by multitouch\n\nUse one finger to swipe left, right and down (tap with second finger to rotate while moving)\n\nUse two fingers to swipe down without the ability to swipe left or right (handy to avoid mistakes :-)...)\n\nSwipe down with three fingers to make an instant down\n\nSwipe up with two fingers to pause the game")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("Scoring")
color: Theme.highlightColor
anchors.right: parent.right
anchors.rightMargin: Theme.paddingLarge
font.pixelSize: Theme.fontSizeLarge
horizontalAlignment: Text.AlignRight
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("Block soft down = 1 x level\nBlock hard down = 2 x level\nBlock instant down = 3 x level\nSingle line clear = 100 x level\ntwo line clear = 300 x level\nthree line clear = 500 x level\nfour line clear (Tetris) = 800 x level\nBack to back Tetris (2 four line clear in a row) = 1200 x level\ncombo bonus = 50 x combo x level\n")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("Credits")
color: Theme.highlightColor
anchors.right: parent.right
anchors.rightMargin: Theme.paddingLarge
font.pixelSize: Theme.fontSizeLarge
horizontalAlignment: Text.AlignRight
wrapMode: Text.WordWrap
}
Label {
width: parent.width
text: qsTr("Music by kraku\n\nSounds from different sources (should be public domain according to the same sources!)\n\nSailTris by Billy Halley\n\nTetris by Alexey Pajitnov\n\nHighscoreModel by Nokia\n\nPut together and modified with added functions by me (nesnomis)\n\nAll copyrights belong to their respective owners\n\n")
color: Theme.primaryColor
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
}
}
VerticalScrollDecorator { flickable: flickable }
}
}

43
qml/pages/FirstPage.qml Normal file
View File

@ -0,0 +1,43 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
// To enable PullDownMenu, place our content in a SilicaFlickable
SilicaFlickable {
anchors.fill: parent
// PullDownMenu and PushUpMenu must be declared in SilicaFlickable, SilicaListView or SilicaGridView
PullDownMenu {
MenuItem {
text: qsTr("Show Page 2")
onClicked: pageStack.animatorPush(Qt.resolvedUrl("SecondPage.qml"))
}
}
// Tell SilicaFlickable the height of its content.
contentHeight: column.height
// Place our content in a Column. The PageHeader is always placed at the top
// of the page, followed by our content.
Column {
id: column
width: page.width
spacing: Theme.paddingLarge
PageHeader {
title: qsTr("UI Template")
}
Label {
x: Theme.horizontalPageMargin
text: qsTr("Hello Sailors")
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeExtraLarge
}
}
}
}

728
qml/pages/GamePage.qml Normal file
View File

@ -0,0 +1,728 @@
/*****************************************************************************
** **
** Created by Antonio Mancini **
** Contact: <ziobilly94@gmail.com> **
** This is a version of classic Tetris game for SailfishOS developed **
** entirely by me, no copyright infringement intended. **
** **
*****************************************************************************/
import QtQuick 2.0
import Sailfish.Silica 1.0
import QtQuick.LocalStorage 2.0
import QtQuick.Particles 2.0
import "../js/settings.js" as Settings
import "../game"
Page {
id: page
HighScoreModel {
id: highScoreModel
game: hsdb
}
Functions {
id: functions
}
property bool onlineEnabled: Settings.getValue("onlineEnabled",0)
property string hsdb: onlineEnabled ? "online" : "local"
property int dots: Settings.getValue("dots",1)
property int ghostEnabled: Settings.getValue("ghostEnabled",1)
property int musicEnabled: Settings.getValue("musicEnabled",1)
property int sfxEnabled: Settings.getValue("sfxEnabled",1)
property string musicScore: "../data/Kraku - Tetris part 1.ogg" //: Settings.getValue("musicScore","")
property int scoreValue
property int speedValue
property int linesValue
property int level: 1
property int linesTotal: 0
property int activeBlock
property int futureBlock: -1
property int combo: 1
property int gravityBreak: 1
property bool pauseVal
property int downSpeed: 2500
property int comboSpeed: 10000
// 0 = l_normal; 1 = l_reverse;
// 2 = s_normal; 3 = s_reverse;
// 4 = t_normal; 5 = square;
// 6 = line
property variant activeColor
property variant futureColor
property real centerX
property real centerY
Timer {
id: gameOverTimer
property int i: 15
property int j: 10
property bool clear: true
property bool done: false
interval: 10
repeat: true
onTriggered : {
if (clear) {
if ( j === 0) {
i--
j = 10
} else {
if ( i === 0) {
clear = false
done = true
j = 10
i = 15
} else {
var index = i*12+j
repeater.itemAt(index).color = Theme.secondaryHighlightColor//"black"//"transparent"//Theme.secondaryColor
repeater.itemAt(index).opacity = 0.5//0.5
j--
}
}
} else {
if ( j === 0) {
i--
j = 10
} else {
if ( i === 0) {
running = false
clear = true
if (highScoreModel.newScore) {
highScoreModel.newScore = false
getName.visible = true ;
} else {
pullDownMenu.enabled = true
splash.visible = true
}
i = 15
j = 10
}
else {
done = false
index = i*12+j
repeater.itemAt(index).opacity = 0.1
j--
}
}
}
}
}
function downSpeedCalc(level) {
if (level>1){
for ( var i = 1; i < level; i++) {
var ds = downSpeed/15
downSpeed -= ds
}
return downSpeed
}
}
function comboSpeedCalc(level) {
for ( var i = 1; i < level; i++) {
comboSpeed = comboSpeed/30
}
return comboSpeed+200
}
Timer {
id: downTimer
interval: downSpeed+150//interval-(interval/20)+150 //difficulty*(1338*Math.pow(Math.E,-0.07*level)+150) //difficulty*(1338*Math.pow(Math.E,-0.26*level)+150)
repeat: true
running: false
onTriggered: {
functions.flow()
speedValue += 1
}
}
SilicaFlickable {
id: root
anchors.fill: page
contentHeight : height
PushUpMenu {
id:pushUpMenu
enabled: false
visible: false
MenuItem {
id: pauseMenuItem
text: qsTr("Resume")
onClicked: functions.pause()
}
}
PullDownMenu {
id: pullDownMenu
MenuItem {
text: qsTr("About")
onClicked: pageStack.push("About.qml")
}
MenuItem {
text: qsTr("Settings")
onClicked: {
var dialog = pageStack.push("SettingsDialog.qml", {"dots": dots, "ghostEnabled": ghostEnabled, "musicEnabled": musicEnabled, "sfxEnabled": sfxEnabled, "musicScore": musicScore, "onlineEnabled": onlineEnabled})
dialog.accepted.connect(function() {
dots = dialog.dots
ghostEnabled = dialog.ghostEnabled
musicEnabled = dialog.musicEnabled
sfxEnabled = dialog.sfxEnabled
onlineEnabled = dialog.onlineEnabled
highScoreModel.place = 0
Settings.setValue("dots",dots)
Settings.setValue("ghostEnabled",ghostEnabled)
Settings.setValue("musicEnabled",musicEnabled)
Settings.setValue("sfxEnabled",sfxEnabled)
Settings.setValue("onlineEnabled",onlineEnabled)
// highScoreModel.game = "local"
})
}
}
MenuItem {
text: functions.garunning ? functions.gapaused ? qsTr("Resume") : qsTr("Pause") : qsTr("New Game")
onClicked: {
if (functions.garunning) {
functions.pause()
} else {
splash.visible = false
highscores.visible = false
functions.newGame()
}
}
}
}
Label {
id: score
text: qsTr("LEVEL ") + "\n" + qsTr("SCORE ") + "\n" + qsTr("LINES ")
color: Theme.secondaryHighlightColor
font.family: Theme.fontFamilyHeading
font.pixelSize: Theme.fontSizeMedium
anchors {
left: parent.left
leftMargin: Theme.paddingMedium
bottom: futureGrid.bottom
}
}
Label {
id: scoreValues
text: level + "\n" + scoreValue + "\n" + linesTotal
color: Theme.highlightColor
font.family: Theme.fontFamilyHeading
font.bold: true
font.pixelSize: Theme.fontSizeMedium
horizontalAlignment: Text.AlignRight
anchors {
right: bonusPanel.left
rightMargin: Theme.paddingLarge
bottom: futureGrid.bottom
}
}
Rectangle {
id: bonusPanel
radius: height / 2
height: futureGrid.height
width: height
color: Theme.highlightDimmerColor
opacity: bonusLabel.opacity > 0 ? 0.8 : 0//bonusLabel.opacity
anchors {
horizontalCenter: parent.horizontalCenter
top: futureGrid.top
}
}
Label {
id: bonusLabel
text: ""///functions.garunning ? "" : "PLAY"
color: Theme.highlightColor
font.pixelSize: functions.garunning ? bonusPanel.height - (Theme.paddingMedium * 2) : Theme.fontSizeLarge
font.bold: true
anchors.verticalCenter: bonusPanel.verticalCenter
anchors.horizontalCenter: bonusPanel.horizontalCenter
opacity: 0//functions.garunning ? 0 : 1//infoTimer.running ? 1 : 0
Behavior on opacity {
FadeAnimator {}
}
}
Grid {
id: futureGrid
y: (parent.height-rect.height-height)/2
anchors {
right: parent.right
rightMargin: Theme.paddingLarge
}
columns: 4
rows: 3
Repeater {
id: futureRepeater
model: 12
delegate: Dot {width: Theme.paddingLarge*5/3 ;color: Theme.highlightBackgroundColor; opacity: 0.1}
}
}
Timer { // EXPERIMENT
id: hssplachTimer
running: splash.visible || highscores.visible && Qt.application.active && !contextMenu.visible? true : false//!functions.garunning && !gameOverTimer.running ? true : false
interval: 8000
repeat: true
onTriggered: if (highscores.visible) {highscores.visible=false;splash.visible = true;} else {highscores.visible=true;splash.visible=false}//highscores.visible ? splash.visible = true : high.visible = false
}
Rectangle {
id: rect
width: grid.width
height: grid.height
anchors {
bottom: parent.bottom
}
border.color: "transparent"
color: "black"
opacity: 0.8//0.8
Grid {
id: grid
columns: 12
rows: 17
Repeater {
id: repeater
model: 204
delegate: Dot {width: page.width/12 ;color: Theme.highlightBackgroundColor; opacity: 0.1}
onItemAdded: { // Bordi "muro"... seriamente, si può fare di meglio, 576 caratteri per una linea è più brutto di questo commento, da aggiungere a newGame() magari
if (index < 12 || index > 191 || index === 0 || index === 12 ||
index === 24 || index === 36 || index === 48 || index === 60 ||
index === 72 || index === 84 || index === 96 || index === 108 ||
index === 120 || index === 132 || index === 144 || index === 156 ||
index === 168 || index === 180 || index === 23 || index === 35 ||
index === 47 || index === 59 || index === 71 || index === 83 ||
index === 95 || index === 107 || index === 119 || index === 131 ||
index === 143 || index === 155 || index === 167 || index === 179 || index === 191)
{
itemAt(index).active = 3
itemAt(index).color = Theme.highlightBackgroundColor
itemAt(index).opacity = 0.5
}
}
}
}
/* ParticleSystem {
id: sys
}
Emitter {
anchors.fill: parent
system: sys
ImageParticle {
anchors.fill: parent
system: sys
source: "../data/dot.png"
clip: true
id: redblip
}
velocity: PointDirection {yVariation: 16; xVariation: 5}
acceleration: PointDirection {y: -16}
lifeSpan: Emitter.InfiniteLife
maximumEmitted: 1000
} */
MultiPointTouchArea {
id: mouseArea
property int offsetX: grid.width/14
property int offsetY: (grid.height/19)
property int blahX: (parent.width - (grid.width-point1.x))/offsetX
property int blahY: (parent.height - (grid.height-point1.y))/offsetY
property int prevX
property int prevY
property int initX
property int initY
property int inter: 85
property int plus: 0
x: 0
y: 0
anchors.fill: grid
anchors.margins: offsetX
mouseEnabled: true
touchPoints: [
TouchPoint { id: point1 },
TouchPoint { id: point2 },
TouchPoint { id: point3 }
]
onTouchUpdated: {
if (functions.maenabled){
if (point1.pressed && point2.pressed && point3.pressed){
if (blahY > prevY+2){
prevY=blahY
functions.instantDown()
}
} else if (point1.pressed && point2.pressed && !point3.pressed){
if (blahY > prevY){
prevY=blahY
functions.down()
}
if (blahY < prevY-2){
prevY=blahY
functions.pause()
}
} else if (point1.pressed && !point2.pressed && !point3.pressed){
//if (blahY==prevY) var plus = 0; else plus = 1;
if (blahY > prevY){
plus = 1;
functions.down()
prevY=blahY
} else {
if (blahX < prevX-plus) {
functions.left()
prevX=blahX
plus = 0
}
if (blahX > prevX+plus){
functions.right()
prevX=blahX
plus = 0
}
}
/* if (blahY > prevY){
prevY=blahY
functions.down()
} */
}
// console.log(blahX + " - " + prevX)
}
}
onReleased: {
if (blahY == initY && blahX == initX && !point1.pressed && !point2.pressed || point1.pressed && !point2.pressed){
functions.rotate()
}
functions.maenabled = true
}
onPressed: {
prevX = blahX
initX = blahX
prevY = blahY
initY = blahY
}
}
Label {
id: gameOverLabel
anchors {
horizontalCenter: rect.horizontalCenter
verticalCenter: rect.verticalCenter
}
style: Text.Outline; styleColor: Theme.secondaryHighlightColor
text: "GAME OVER"
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeHuge
font.bold: true
visible: !functions.garunning && opacity > 0 ? true : false
opacity: gameOverTimer.running ? 1 : 0
Behavior on opacity {
FadeAnimator {}
}
}
Label {
id: pauseLabel
anchors {
horizontalCenter: rect.horizontalCenter
verticalCenter: rect.verticalCenter
}
style: Text.Outline; styleColor: Theme.secondaryHighlightColor
text: "PAUSED"
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeHuge
font.bold: true
visible: false
states: [
State { when: stateVisible;
PropertyChanges { target: myRect; opacity: 1.0 }
},
State { when: !stateVisible;
PropertyChanges { target: myRect; opacity: 0.0 }
}
]
transitions: Transition {
NumberAnimation { property: "opacity"; duration: 300}
}
}
Label {
id: infoLabel
anchors {
verticalCenter: rect.verticalCenter
horizontalCenter: rect.horizontalCenter
}
width: parent.width
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
style: Text.Outline; styleColor: Theme.secondaryHighlightColor;
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeLarge*2
font.bold: true
opacity: infoTimer.running ? 1 : 0
Behavior on opacity {
FadeAnimator {}
}
}
Timer {
id: infoTimer
running: false
repeat: false
interval: 1100
onTriggered: {
infoLabel.opacity = 0
}
}
}
Rectangle {
id: highscores
anchors.verticalCenter: rect.verticalCenter
anchors.horizontalCenter: rect.horizontalCenter
width: rect.width - (rect.width/6)
height: rect.height - (rect.height/8)+Theme.paddingSmall
visible: splash.visible || functions.garunning || getName.visible && opacity === 0 ? false : true //!splash.visible && !getName.visible && !functions.garunning
color: "transparent"//Theme.highlightBackgroundColor
opacity: !visible ? 0 : 0.8
Behavior on opacity {
FadeAnimator {onStopped: console.log("highscores fade animation klar")}
}
Label {
id: hs1
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Theme.paddingLarge
text: "HIGHSCORES ["+highScoreModel.game+"]"
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeLarge
font.bold: true
MouseArea {
anchors.fill: hs1
onClicked: {
!onlineEnabled ? onlineEnabled=true : onlineEnabled=false
console.log("ONLINE: "+highScoreModel.game)
}
}
}
ListView {
width: parent.width; height: parent.height - hs1.height
enabled: true
anchors.top: hs1.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: Theme.paddingLarge
model: highScoreModel
delegate: ListItem {
id: showDelegate
// menu: contextMenu
highlighted: index == highScoreModel.place-1 ? true : false
width: ListView.view.width
height: menuOpen ? contextMenu.height + pn.height + Theme.paddingSmall : pn.height + Theme.paddingSmall//contextMenu.height + contentItem.height + Theme.paddingMedium : contentItem.height + Theme.paddingMedium
contentHeight: pn.height + Theme.paddingSmall
Text {
id: pn
font.pixelSize: Theme.fontSizeLarge
anchors.left: parent.left
anchors.leftMargin: Theme.paddingMedium
color: Theme.highlightColor
text: index+(1)+"."
}
Text {
id: pnm
font.pixelSize: Theme.fontSizeLarge
anchors.left: pn.right
anchors.leftMargin: Theme.paddingMedium
anchors.top: pn.top
color: Theme.highlightColor
text: player
}
Text {
font.pixelSize: Theme.fontSizeLarge
anchors.right: parent.right
anchors.rightMargin: Theme.paddingMedium
anchors.top: pn.top
color: Theme.highlightColor
text: score
}
}
}
}
ContextMenu {
id: contextMenu
width: rect.width - (rect.width/6)
anchors.horizontalCenter: highscores.horizontalCenter
MenuItem {
id:onlineMenu
visible: true
text: qsTr("Share score online")
onClicked: {
var uuid = generateUUID()
console.log("UUID: "+uuid)
/* internal ? ps(source) : model.id == 0 ? ps(source) : cps(model.id)
radioStation = title
if (icon == "0") picon = "../allradio-data/images/allradio.png"
else if (icon.search(".png")>0) picon = icon.toLowerCase(); // The old save in database
else picon = "../allradio-data/images/"+icon+".png";
website = (Qt.resolvedUrl(site)) */
}
}
}
Rectangle {
id: splash
anchors.verticalCenter: rect.verticalCenter
anchors.horizontalCenter: rect.horizontalCenter
width: rect.width - (rect.width/6)
height: rect.height - (rect.height/8) + Theme.paddingSmall
visible: functions.garunning || getName.visible || highscores.visible && opacity === 0 ? false : true//true && !functions.garunning//!functions.garunning && !getName.visible && !highscores.visible//&& !gameOverTimer.done ? true : false //&& gameOverTimer.running ? done :
color: "transparent"//Theme.highlightBackgroundColor
opacity: !visible ? 0 : 0.8
Behavior on opacity {
FadeAnimator {}
}
Column {
spacing: Theme.paddingLarge
anchors {
horizontalCenter: splash.horizontalCenter
verticalCenter: splash.verticalCenter
}
Label {
id: name
anchors.horizontalCenter: parent.horizontalCenter
text: "TetraFish"
color: Theme.highlightColor
font.pixelSize: Theme.fontSizeHuge
font.bold: true
}
Image {
anchors.horizontalCenter: parent.horizontalCenter
id: tetraFish
width: name.width
height: width
source: "../data/tetrafish.png"
}
Label {
id: info1
anchors.horizontalCenter: parent.horizontalCenter
text: "A TETRIS clone"
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeLarge
font.bold: true
}
Label {
id: info2
anchors.horizontalCenter: parent.horizontalCenter
text: "Presented by NESNOMIS"
color: Theme.secondaryHighlightColor
font.pixelSize: Theme.fontSizeSmall
font.bold: true
}
}
}
Rectangle {
id: getName
anchors.fill: rect
anchors.left: rect.left
anchors.top: rect.top
width: rect.width
height: rect.height
visible: false//!functions.garunning && !gameOverTimer.done ? true : false //&& gameOverTimer.running ? done :
color: "black"//Theme.highlightBackgroundColor
opacity: !visible ? 0 : 0.8
Behavior on opacity {
FadeAnimator {}
}
Label {
id: congrat
anchors.horizontalCenter: parent.horizontalCenter
text: "CONGRATULATIONS"//+highScoreModel.place
color: Theme.highlightColor
anchors.bottom: namn.top
font.pixelSize: Theme.fontSizeExtraLarge
font.bold: true
}
Label {
id: namn
anchors.horizontalCenter: parent.horizontalCenter
text: "You placed No. "+highScoreModel.place
color: Theme.primaryColor
anchors.bottom: textField.top
anchors.bottomMargin: Theme.paddingLarge * 3
font.pixelSize: Theme.fontSizeMedium
font.bold: true
}
TextField {
id: textField
enabled: parent.visible
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
width: parent.width
maximumLength: 8
focus: true
placeholderText: "ENTER YOUR NAME"
inputMethodHints: Qt.ImhUppercaseOnly | Qt.ImhPreferUppercase | Qt.ImhNoPredictiveText
horizontalAlignment: TextInput.AlignHCenter
font.bold: true
font.pixelSize: Theme.fontSizeHuge
font.capitalization: Font.AllUppercase
EnterKey.iconSource: "image://theme/icon-m-enter" //"image://theme/icon-m-enter-close"
EnterKey.onClicked: {
getName.visible = false
splash.visible = false
highscores.visible = true
pullDownMenu.enabled = true
root.interactive = true
functions.saveHighscore(text.toUpperCase(),scoreValue)
}
}
}
}
function generateUUID(){
var d = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random()*16)%16 | 0;
d = Math.floor(d/16);
return (c === 'x' ? r : (r&0x3|0x8)).toString(16);
});
return uuid;
}
Component.onCompleted: splash.visible = true
}

30
qml/pages/SecondPage.qml Normal file
View File

@ -0,0 +1,30 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
SilicaListView {
id: listView
model: 20
anchors.fill: parent
header: PageHeader {
title: qsTr("Nested Page")
}
delegate: BackgroundItem {
id: delegate
Label {
x: Theme.horizontalPageMargin
text: qsTr("Item") + " " + index
anchors.verticalCenter: parent.verticalCenter
color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
}
onClicked: console.log("Clicked " + index)
}
VerticalScrollDecorator {}
}
}

View File

@ -0,0 +1,105 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Dialog {
id: page
property int dots
property int ghostEnabled
property int musicEnabled
property int sfxEnabled
property int highscoreValue
property int onlineEnabled
SilicaFlickable {
id: flickable
anchors.fill: parent
contentHeight: column.height
Column {
id: column
width: page.width
spacing: Theme.paddingLarge
DialogHeader {
title: qsTr("Settings")
}
TextSwitch {
id: dotSwitch
automaticCheck: false
checked: dots ? true : false
text: checked ? qsTr("Squares") : qsTr("Dots")
description: qsTr("Changes the shape of the blocks")
onClicked: {
if (dots === 0) {
dots = 1
}
else {
dots = 0
}
}
}
TextSwitch {
id: ghostSwitch
automaticCheck: false
checked: ghostEnabled ? true : false
text: checked ? qsTr("Ghost Enabled") : qsTr("Ghost Disabled")
description: qsTr("Display a hint of where the block will fall")
onClicked: {
if (ghostEnabled === 0) {
ghostEnabled = 1
}
else {
ghostEnabled = 0
}
}
}
TextSwitch {
id: sfxSwitch
automaticCheck: false
checked: sfxEnabled ? true : false
text: checked ? qsTr("SoundFX Enabled") : qsTr("SoundFX Disabled")
description: qsTr("Play sound effects in game")
onClicked: {
if (sfxEnabled === 0) {
sfxEnabled = 1
}
else {
sfxEnabled = 0
}
}
}
TextSwitch {
id: musicSwitch
automaticCheck: false
checked: musicEnabled ? true : false
text: checked ? qsTr("Music Enabled") : qsTr("Music Disabled")
description: qsTr("Play music in game")
enabled: true /// enable if music should be included?!
onClicked: {
if (musicEnabled === 0) {
musicEnabled = 1
}
else {
musicEnabled = 0
}
}
}
/* TextSwitch {
id: onlineSwitch
automaticCheck: false
checked: onlineEnabled ? true : false
text: checked ? qsTr("Online highscores Enabled") : qsTr("Online highscores Disabled")
description: qsTr("Save scores online to compare scores with other players")
enabled: true /// enable if music should be included?!
onClicked: {
if (onlineEnabled === 0) {
onlineEnabled = 1
}
else {
onlineEnabled = 0
}
}
} */
}
}
}

View File

@ -0,0 +1,18 @@
# Rename this file as harbour-tetrafish.changes to include changelog
# entries in your RPM file.
#
# Add new changelog entries following the format below.
# Add newest entries to the top of the list.
# Separate entries from eachother with a blank line.
#
# Alternatively, if your changelog is automatically generated (e.g. with
# the git-change-log command provided with Sailfish OS SDK), create a
# harbour-tetrafish.changes.run script to let mb2 run the required commands for you.
# * date Author's Name <author's email> version-release
# - Summary of changes
* Sun Apr 13 2014 Jack Tar <jack.tar@example.com> 0.0.1-1
- Scrubbed the deck
- Hoisted the sails

View File

@ -0,0 +1,24 @@
#!/bin/bash
#
# Rename this file as harbour-tetrafish.changes.run to let sfdk automatically
# generate changelog from well formatted Git commit messages and tag
# annotations. Note that 'sfdk changelog' must be invoked as 'sfdk-changelog' here.
sfdk-changelog
# Here are some basic examples how to change from the default behavior. Run
# 'sfdk --help-maintaining' to learn more.
# Use a subset of tags
#sfdk-changelog --tags refs/tags/my-prefix/*
# Group entries by minor revision, suppress headlines for patch-level revisions
#sfdk-changelog --dense '/[0-9]+.[0-9+$'
# Trim very old changes
#sfdk-changelog --since 2014-04-01
#echo '[ Some changelog entries trimmed for brevity ]'
# Use the subjects (first lines) of tag annotations when no entry would be
# included for a revision otherwise
#sfdk-changelog --auto-add-annotations

View File

@ -0,0 +1,41 @@
Name: harbour-tetrafish
Summary: TetraFish
Version: 0.0.1
Release: 1
License: LICENSE
URL: http://example.org/
Source0: %{name}-%{version}.tar.bz2
Requires: sailfishsilica-qt5 >= 0.10.9
BuildRequires: pkgconfig(sailfishapp) >= 1.0.2
BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Qml)
BuildRequires: pkgconfig(Qt5Quick)
BuildRequires: desktop-file-utils
%description
Tetris clone
%prep
%setup -q -n %{name}-%{version}
%build
%qmake5
%make_build
%install
%qmake5_install
desktop-file-install --delete-original --dir %{buildroot}%{_datadir}/applications %{buildroot}%{_datadir}/applications/*.desktop
%files
%defattr(-,root,root,-)
%{_bindir}/%{name}
%{_datadir}/%{name}
%{_datadir}/applications/%{name}.desktop
%{_datadir}/icons/hicolor/*/apps/%{name}.png

20
src/harbour-tetrafish.cpp Normal file
View File

@ -0,0 +1,20 @@
#ifdef QT_QML_DEBUG
#include <QtQuick>
#endif
#include <sailfishapp.h>
int main(int argc, char *argv[])
{
// SailfishApp::main() will display "qml/harbour-tetrafish.qml", if you need more
// control over initialization, you can use:
//
// - SailfishApp::application(int, char *[]) to get the QGuiApplication *
// - SailfishApp::createView() to get a new QQuickView * instance
// - SailfishApp::pathTo(QString) to get a QUrl to a resource file
// - SailfishApp::pathToMainQml() to get a QUrl to the main QML file
//
// To display the view, call "show()" (will show fullscreen on device).
return SailfishApp::main(argc, argv);
}

View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>About</name>
<message>
<source>TetraFish</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>A remake of SailTris which is a remake of Tetris
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TetraFish is a remake of the game SailTris by Billy Halley, available on OpenRepos. I wanted to contribute to SailTris with some changes and fixes but Billy Halley had stopped he&apos;s development on Sailfish and SailTris and so was TetraFish with the kind approval of Billy Halley born.
Tetra fish is a common fish in a lot of aquariums and the original game Tetris got it&apos;s name from the greek numerical prefix tetra (4) symbolising the 4 segments making up every block in a Tetris game.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Controls</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TetraFish i controlled by multitouch
Use one finger to swipe left, right and down (tap with second finger to rotate while moving)
Use two fingers to swipe down without the ability to swipe left or right (handy to avoid mistakes :-)...)
Swipe down with three fingers to make an instant down
Swipe up with two fingers to pause the game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scoring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Block soft down = 1 x level
Block hard down = 2 x level
Block instant down = 3 x level
Single line clear = 100 x level
two line clear = 300 x level
three line clear = 500 x level
four line clear (Tetris) = 800 x level
Back to back Tetris (2 four line clear in a row) = 1200 x level
combo bonus = 50 x combo x level
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Credits</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Music by kraku
Sounds from different sources (should be public domain according to the same sources!)
SailTris by Billy Halley
Tetris by Alexey Pajitnov
HighscoreModel by Nokia
Put together and modified with added functions by me (nesnomis)
All copyrights belong to their respective owners
</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FirstPage</name>
<message>
<source>Show Page 2</source>
<translation>Zur Seite 2</translation>
</message>
<message>
<source>UI Template</source>
<translation>UI-Vorlage</translation>
</message>
<message>
<source>Hello Sailors</source>
<translation>Hallo Matrosen</translation>
</message>
</context>
<context>
<name>GamePage</name>
<message>
<source>Resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New Game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>LEVEL </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SCORE </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>LINES </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Share score online</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SecondPage</name>
<message>
<source>Nested Page</source>
<translation>Unterseite</translation>
</message>
<message>
<source>Item</source>
<translation>Element</translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Squares</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dots</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Changes the shape of the blocks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ghost Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ghost Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Display a hint of where the block will fall</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SoundFX Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SoundFX Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Play sound effects in game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Music Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Music Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Play music in game</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>About</name>
<message>
<source>TetraFish</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>A remake of SailTris which is a remake of Tetris
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TetraFish is a remake of the game SailTris by Billy Halley, available on OpenRepos. I wanted to contribute to SailTris with some changes and fixes but Billy Halley had stopped he&apos;s development on Sailfish and SailTris and so was TetraFish with the kind approval of Billy Halley born.
Tetra fish is a common fish in a lot of aquariums and the original game Tetris got it&apos;s name from the greek numerical prefix tetra (4) symbolising the 4 segments making up every block in a Tetris game.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Controls</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>TetraFish i controlled by multitouch
Use one finger to swipe left, right and down (tap with second finger to rotate while moving)
Use two fingers to swipe down without the ability to swipe left or right (handy to avoid mistakes :-)...)
Swipe down with three fingers to make an instant down
Swipe up with two fingers to pause the game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Scoring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Block soft down = 1 x level
Block hard down = 2 x level
Block instant down = 3 x level
Single line clear = 100 x level
two line clear = 300 x level
three line clear = 500 x level
four line clear (Tetris) = 800 x level
Back to back Tetris (2 four line clear in a row) = 1200 x level
combo bonus = 50 x combo x level
</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Credits</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Music by kraku
Sounds from different sources (should be public domain according to the same sources!)
SailTris by Billy Halley
Tetris by Alexey Pajitnov
HighscoreModel by Nokia
Put together and modified with added functions by me (nesnomis)
All copyrights belong to their respective owners
</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>FirstPage</name>
<message>
<source>Show Page 2</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>UI Template</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hello Sailors</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GamePage</name>
<message>
<source>Resume</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Pause</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>New Game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>LEVEL </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SCORE </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>LINES </source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Share score online</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SecondPage</name>
<message>
<source>Nested Page</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Item</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Squares</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Dots</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Changes the shape of the blocks</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ghost Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Ghost Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Display a hint of where the block will fall</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SoundFX Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>SoundFX Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Play sound effects in game</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Music Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Music Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Play music in game</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>