- Merge default
- *cough* sorry, but also in this commit: move *.qml files into qrc, include qmlFrontend into cmake build, also exclude QTfrontend
--- a/CMakeLists.txt Mon Feb 16 22:33:15 2015 +0300
+++ b/CMakeLists.txt Thu Apr 02 21:09:56 2015 +0300
@@ -224,7 +224,7 @@
add_subdirectory(project_files/Android-build)
else(ANDROID)
add_subdirectory(bin)
- add_subdirectory(QTfrontend)
+ add_subdirectory(qmlFrontend)
add_subdirectory(share)
add_subdirectory(tools)
endif(ANDROID)
--- a/QTfrontend/game.cpp Mon Feb 16 22:33:15 2015 +0300
+++ b/QTfrontend/game.cpp Thu Apr 02 21:09:56 2015 +0300
@@ -16,6 +16,9 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <QApplication>
+#include <QClipboard>
+
#include <QString>
#include <QCheckBox>
#include <QByteArray>
@@ -258,6 +261,18 @@
.arg(QString::fromUtf8(msg.mid(2).left(size - 4))));
return;
}
+ case 'y':
+ {
+ // copy string to clipboard
+ QApplication::clipboard()->setText(QString::fromUtf8(msg.mid(2)));
+ break;
+ }
+ case 'Y':
+ {
+ // paste clipboard to game
+ SendIPC(QString("Y").toAscii() + QApplication::clipboard()->text().toUtf8().left(250).replace('\n', ' '));
+ break;
+ }
case 'i':
{
emit GameStats(msg.at(2), QString::fromUtf8(msg.mid(3)));
--- a/QTfrontend/model/ammoSchemeModel.cpp Mon Feb 16 22:33:15 2015 +0300
+++ b/QTfrontend/model/ammoSchemeModel.cpp Thu Apr 02 21:09:56 2015 +0300
@@ -58,14 +58,15 @@
<< QVariant(4) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(2) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
AmmoSchemeModel::AmmoSchemeModel(QObject* parent, const QString & fileName) :
@@ -125,14 +126,15 @@
<< "minesnum" // 32
<< "minedudpct" // 33
<< "explosives" // 34
- << "healthprobability" // 35
- << "healthcaseamount" // 36
- << "waterrise" // 37
- << "healthdecrease" // 38
- << "ropepct" // 39
- << "getawaytime" // 40
- << "worldedge" // 41
- << "scriptparam" // scriptparam 42
+ << "airmines" // 35
+ << "healthprobability" // 36
+ << "healthcaseamount" // 37
+ << "waterrise" // 38
+ << "healthdecrease" // 39
+ << "ropepct" // 40
+ << "getawaytime" // 41
+ << "worldedge" // 42
+ << "scriptparam" // scriptparam 43
;
QList<QVariant> proMode;
@@ -172,14 +174,15 @@
<< QVariant(0) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(2) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> shoppa;
@@ -215,18 +218,19 @@
<< QVariant(100) // init health 28
<< QVariant(50) // sudden death 29
<< QVariant(1) // case prob 30
- << QVariant(3) // mines time 31
+ << QVariant(0) // mines time 31
<< QVariant(0) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(0) // explosives 34
- << QVariant(0) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(8) // air mines 35
+ << QVariant(0) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> cleanslate;
@@ -266,14 +270,15 @@
<< QVariant(4) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(2) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> minefield;
@@ -313,14 +318,15 @@
<< QVariant(200) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(0) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> barrelmayhem;
@@ -360,14 +366,15 @@
<< QVariant(0) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(200) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> tunnelhogs;
@@ -407,14 +414,15 @@
<< QVariant(10) // mines number 32
<< QVariant(10) // mine dud pct 33
<< QVariant(10) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(4) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> forts;
@@ -454,14 +462,15 @@
<< QVariant(0) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(0) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> timeless;
@@ -501,14 +510,15 @@
<< QVariant(5) // mines number 32
<< QVariant(10) // mine dud pct 33
<< QVariant(2) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(30) // health case amt 36
- << QVariant(0) // water rise amt 37
- << QVariant(0) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(30) // health case amt 37
+ << QVariant(0) // water rise amt 38
+ << QVariant(0) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> thinkingportals;
@@ -548,14 +558,15 @@
<< QVariant(5) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(5) // explosives 34
- << QVariant(25) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(4) // air mines 35
+ << QVariant(25) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> kingmode;
@@ -595,14 +606,15 @@
<< QVariant(4) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(2) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
QList<QVariant> construction;
@@ -642,14 +654,15 @@
<< QVariant(0) // mines number 32
<< QVariant(0) // mine dud pct 33
<< QVariant(0) // explosives 34
- << QVariant(35) // health case pct 35
- << QVariant(25) // health case amt 36
- << QVariant(47) // water rise amt 37
- << QVariant(5) // health dec amt 38
- << QVariant(100) // rope modfier 39
- << QVariant(100) // get away time 40
- << QVariant(0) // world edge 41
- << QVariant() // scriptparam 42
+ << QVariant(0) // air mines 35
+ << QVariant(35) // health case pct 36
+ << QVariant(25) // health case amt 37
+ << QVariant(47) // water rise amt 38
+ << QVariant(5) // health dec amt 39
+ << QVariant(100) // rope modfier 40
+ << QVariant(100) // get away time 41
+ << QVariant(0) // world edge 42
+ << QVariant() // scriptparam 43
;
schemes.append(defaultScheme);
@@ -853,7 +866,7 @@
return;
}
- cfg[42] = cfg[42].mid(1);
+ cfg[cfg.size()-1] = cfg[cfg.size()-1].mid(1);
for(int i = 0; i < cfg.size(); ++i)
netScheme[i] = QVariant(cfg[i]);
--- a/QTfrontend/ui/page/pagescheme.cpp Mon Feb 16 22:33:15 2015 +0300
+++ b/QTfrontend/ui/page/pagescheme.cpp Thu Apr 02 21:09:56 2015 +0300
@@ -369,27 +369,41 @@
glBSLayout->addWidget(SB_Explosives,13,2,1,1);
l = new QLabel(gbBasicSettings);
- l->setText(QLabel::tr("% Get Away Time"));
+ l->setText(QLabel::tr("Air Mines"));
l->setWordWrap(true);
glBSLayout->addWidget(l,14,0,1,1);
l = new QLabel(gbBasicSettings);
l->setFixedSize(32,32);
+ l->setPixmap(QPixmap(":/res/iconMine.png")); // TODO: icon
+ glBSLayout->addWidget(l,14,1,1,1);
+ SB_AirMines = new QSpinBox(gbBasicSettings);
+ SB_AirMines->setRange(0, 200);
+ SB_AirMines->setValue(0);
+ SB_AirMines->setSingleStep(5);
+ glBSLayout->addWidget(SB_AirMines,14,2,1,1);
+
+ l = new QLabel(gbBasicSettings);
+ l->setText(QLabel::tr("% Get Away Time"));
+ l->setWordWrap(true);
+ glBSLayout->addWidget(l,15,0,1,1);
+ l = new QLabel(gbBasicSettings);
+ l->setFixedSize(32,32);
l->setPixmap(QPixmap(":/res/iconTime.png"));
- glBSLayout->addWidget(l,14,1,1,1);
+ glBSLayout->addWidget(l,15,1,1,1);
SB_GetAwayTime = new QSpinBox(gbBasicSettings);
SB_GetAwayTime->setRange(0, 999);
SB_GetAwayTime->setValue(100);
SB_GetAwayTime->setSingleStep(25);
- glBSLayout->addWidget(SB_GetAwayTime,14,2,1,1);
+ glBSLayout->addWidget(SB_GetAwayTime,15,2,1,1);
l = new QLabel(gbBasicSettings);
l->setText(QLabel::tr("World Edge"));
l->setWordWrap(true);
- glBSLayout->addWidget(l,15,0,1,1);
+ glBSLayout->addWidget(l,16,0,1,1);
l = new QLabel(gbBasicSettings);
l->setFixedSize(32,32);
l->setPixmap(QPixmap(":/res/iconEarth.png"));
- glBSLayout->addWidget(l,15,1,1,1);
+ glBSLayout->addWidget(l,16,1,1,1);
CB_WorldEdge = new QComboBox(gbBasicSettings);
CB_WorldEdge->insertItem(0, tr("None (Default)"));
@@ -397,21 +411,21 @@
CB_WorldEdge->insertItem(2, tr("Bounce (Edges reflect)"));
CB_WorldEdge->insertItem(3, tr("Sea (Edges connect to sea)"));
/* CB_WorldEdge->insertItem(4, tr("Skybox")); */
- glBSLayout->addWidget(CB_WorldEdge,15,2,1,1);
+ glBSLayout->addWidget(CB_WorldEdge,16,2,1,1);
l = new QLabel(gbBasicSettings);
l->setText(QLabel::tr("Script parameter"));
l->setWordWrap(true);
- glBSLayout->addWidget(l,16,0,1,1);
+ glBSLayout->addWidget(l,17,0,1,1);
l = new QLabel(gbBasicSettings);
l->setFixedSize(32,32);
l->setPixmap(QPixmap(":/res/iconBox.png"));
- glBSLayout->addWidget(l,16,1,1,1);
+ glBSLayout->addWidget(l,17,1,1,1);
LE_ScriptParam = new QLineEdit(gbBasicSettings);
LE_ScriptParam->setMaxLength(240);
- glBSLayout->addWidget(LE_ScriptParam,16,2,1,1);
+ glBSLayout->addWidget(LE_ScriptParam,17,2,1,1);
l = new QLabel(gbBasicSettings);
@@ -497,14 +511,15 @@
mapper->addMapping(SB_Mines, 32);
mapper->addMapping(SB_MineDuds, 33);
mapper->addMapping(SB_Explosives, 34);
- mapper->addMapping(SB_HealthCrates, 35);
- mapper->addMapping(SB_CrateHealth, 36);
- mapper->addMapping(SB_WaterRise, 37);
- mapper->addMapping(SB_HealthDecrease, 38);
- mapper->addMapping(SB_RopeModifier, 39);
- mapper->addMapping(SB_GetAwayTime, 40);
- mapper->addMapping(CB_WorldEdge, 41, "currentIndex");
- mapper->addMapping(LE_ScriptParam, 42);
+ mapper->addMapping(SB_AirMines, 35);
+ mapper->addMapping(SB_HealthCrates, 36);
+ mapper->addMapping(SB_CrateHealth, 37);
+ mapper->addMapping(SB_WaterRise, 38);
+ mapper->addMapping(SB_HealthDecrease, 39);
+ mapper->addMapping(SB_RopeModifier, 40);
+ mapper->addMapping(SB_GetAwayTime, 41);
+ mapper->addMapping(CB_WorldEdge, 42, "currentIndex");
+ mapper->addMapping(LE_ScriptParam, 43);
mapper->toFirst();
}
--- a/QTfrontend/ui/page/pagescheme.h Mon Feb 16 22:33:15 2015 +0300
+++ b/QTfrontend/ui/page/pagescheme.h Thu Apr 02 21:09:56 2015 +0300
@@ -87,6 +87,7 @@
QSpinBox * SB_CrateHealth;
QSpinBox * SB_MinesTime;
QSpinBox * SB_Mines;
+ QSpinBox * SB_AirMines;
QSpinBox * SB_MineDuds;
QSpinBox * SB_Explosives;
QSpinBox * SB_RopeModifier;
--- a/QTfrontend/ui/widget/gamecfgwidget.cpp Mon Feb 16 22:33:15 2015 +0300
+++ b/QTfrontend/ui/widget/gamecfgwidget.cpp Thu Apr 02 21:09:56 2015 +0300
@@ -316,18 +316,19 @@
bcfg << QString("e$minesnum %1").arg(schemeData(32).toInt()).toUtf8();
bcfg << QString("e$minedudpct %1").arg(schemeData(33).toInt()).toUtf8();
bcfg << QString("e$explosives %1").arg(schemeData(34).toInt()).toUtf8();
- bcfg << QString("e$healthprob %1").arg(schemeData(35).toInt()).toUtf8();
- bcfg << QString("e$hcaseamount %1").arg(schemeData(36).toInt()).toUtf8();
- bcfg << QString("e$waterrise %1").arg(schemeData(37).toInt()).toUtf8();
- bcfg << QString("e$healthdec %1").arg(schemeData(38).toInt()).toUtf8();
- bcfg << QString("e$ropepct %1").arg(schemeData(39).toInt()).toUtf8();
- bcfg << QString("e$getawaytime %1").arg(schemeData(40).toInt()).toUtf8();
- bcfg << QString("e$worldedge %1").arg(schemeData(41).toInt()).toUtf8();
+ bcfg << QString("e$airmines %1").arg(schemeData(35).toInt()).toUtf8();
+ bcfg << QString("e$healthprob %1").arg(schemeData(36).toInt()).toUtf8();
+ bcfg << QString("e$hcaseamount %1").arg(schemeData(37).toInt()).toUtf8();
+ bcfg << QString("e$waterrise %1").arg(schemeData(38).toInt()).toUtf8();
+ bcfg << QString("e$healthdec %1").arg(schemeData(39).toInt()).toUtf8();
+ bcfg << QString("e$ropepct %1").arg(schemeData(40).toInt()).toUtf8();
+ bcfg << QString("e$getawaytime %1").arg(schemeData(41).toInt()).toUtf8();
+ bcfg << QString("e$worldedge %1").arg(schemeData(42).toInt()).toUtf8();
bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8();
bcfg << QString("e$feature_size %1").arg(pMapContainer->getFeatureSize()).toUtf8();
bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8();
- if(!schemeData(42).isNull())
- bcfg << QString("e$scriptparam %1").arg(schemeData(42).toString()).toUtf8();
+ if(!schemeData(43).isNull())
+ bcfg << QString("e$scriptparam %1").arg(schemeData(43).toString()).toUtf8();
switch (mapgen)
@@ -527,8 +528,8 @@
int num = GameSchemes->findText(pMapContainer->getCurrentScheme());
if (num != -1)
GameSchemes->setCurrentIndex(num);
- else
- GameSchemes->setCurrentIndex(GameSchemes->findText("Default"));
+ //else
+ // GameSchemes->setCurrentIndex(GameSchemes->findText("Default"));
}
if (pMapContainer->getCurrentWeapons() == "locked")
@@ -542,8 +543,8 @@
int num = WeaponsName->findText(pMapContainer->getCurrentWeapons());
if (num != -1)
WeaponsName->setCurrentIndex(num);
- else
- WeaponsName->setCurrentIndex(WeaponsName->findText("Default"));
+ //else
+ // WeaponsName->setCurrentIndex(WeaponsName->findText("Default"));
}
if (pMapContainer->getCurrentScheme() != "locked" && pMapContainer->getCurrentWeapons() != "locked")
@@ -586,7 +587,7 @@
if (sl.size() >= 42)
{
- sl[42].prepend('!');
+ sl[sl.size()-1].prepend('!');
emit paramChanged("SCHEME", sl); // this is a stupid hack for the fact that SCHEME is being sent once, empty. Still need to find out why.
}
@@ -628,8 +629,8 @@
int num = GameSchemes->findText(scheme);
if (num != -1)
GameSchemes->setCurrentIndex(num);
- else
- GameSchemes->setCurrentIndex(GameSchemes->findText("Default"));
+ //else
+ // GameSchemes->setCurrentIndex(GameSchemes->findText("Default"));
}
if (weapons == "locked")
@@ -643,8 +644,8 @@
int num = WeaponsName->findText(weapons);
if (num != -1)
WeaponsName->setCurrentIndex(num);
- else
- WeaponsName->setCurrentIndex(WeaponsName->findText("Default"));
+ //else
+ // WeaponsName->setCurrentIndex(WeaponsName->findText("Default"));
}
if (scheme != "locked" && weapons != "locked")
--- a/gameServer/CoreTypes.hs Mon Feb 16 22:33:15 2015 +0300
+++ b/gameServer/CoreTypes.hs Thu Apr 02 21:09:56 2015 +0300
@@ -226,6 +226,7 @@
isRegisteredOnly :: Bool,
isSpecial :: Bool,
defaultHedgehogsNumber :: Int,
+ teamsNumberLimit :: Int,
greeting :: B.ByteString,
voting :: Maybe Voting,
roomBansList :: ![B.ByteString],
@@ -250,6 +251,7 @@
False
False
4
+ 8
""
Nothing
[]
--- a/gameServer/HWProtoCore.hs Mon Feb 16 22:33:15 2015 +0300
+++ b/gameServer/HWProtoCore.hs Thu Apr 02 21:09:56 2015 +0300
@@ -71,11 +71,14 @@
h "WATCH" f = return [QueryReplay f]
h "FIX" _ = handleCmd ["FIX"]
h "UNFIX" _ = handleCmd ["UNFIX"]
- h "GREETING" msg = handleCmd ["GREETING", msg]
+ h "GREETING" msg | not $ B.null msg = handleCmd ["GREETING", msg]
h "CALLVOTE" msg | B.null msg = handleCmd ["CALLVOTE"]
| otherwise = let (c, p) = extractParameters msg in
if B.null p then handleCmd ["CALLVOTE", c] else handleCmd ["CALLVOTE", c, p]
- h "VOTE" msg = handleCmd ["VOTE", upperCase msg]
+ h "VOTE" msg | not $ B.null msg = handleCmd ["VOTE", upperCase msg]
+ h "FORCE" msg | not $ B.null msg = handleCmd ["VOTE", upperCase msg, "FORCE"]
+ h "MAXTEAMS" n | not $ B.null n = handleCmd ["MAXTEAMS", n]
+ h "INFO" n | not $ B.null n = handleCmd ["INFO", n]
h c p = return [Warning $ B.concat ["Unknown cmd: /", c, " ", p]]
extractParameters p = let (a, b) = B.break (== ' ') p in (upperCase a, B.dropWhile (== ' ') b)
--- a/gameServer/HWProtoInRoomState.hs Mon Feb 16 22:33:15 2015 +0300
+++ b/gameServer/HWProtoInRoomState.hs Thu Apr 02 21:09:56 2015 +0300
@@ -125,7 +125,7 @@
defaultHedgehogsNumber rm
let newTeam = clNick `seq` TeamInfo clNick tName teamColor grave fort voicepack flag isRegistered dif hhNum (hhsList hhsInfo)
return $
- if not . null . drop (maxTeams rm - 1) $ roomTeams then
+ if not . null . drop (teamsNumberLimit rm - 1) $ roomTeams then
[Warning $ loc "too many teams"]
else if canAddNumber roomTeams <= 0 then
[Warning $ loc "too many hedgehogs"]
@@ -389,6 +389,15 @@
s <- roomClientsChans
return [AnswerClients s ["CHAT", n, B.unwords $ "/rnd" : rs], Random s rs]
+
+handleCmd_inRoom ["MAXTEAMS", n] = roomAdminOnly $ do
+ cl <- thisClient
+ let m = readInt_ n
+ if m < 2 || m > 8 then
+ return [AnswerClients [sendChan cl] ["CHAT", "[server]", loc "/maxteams: specify number from 2 to 8"]]
+ else
+ return [ModifyRoom (\r -> r{teamsNumberLimit = m})]
+
handleCmd_inRoom ["FIX"] = serverAdminOnly $
return [ModifyRoom (\r -> r{isSpecial = True})]
@@ -473,11 +482,11 @@
return [AnswerClients [sendChan cl] ["CHAT", "[server]", loc "callvote hedgehogs: specify number from 1 to 8"]]
-handleCmd_inRoom ["VOTE", m] = do
+handleCmd_inRoom ("VOTE" : m : p) = do
cl <- thisClient
let b = if m == "YES" then Just True else if m == "NO" then Just False else Nothing
if isJust b then
- voted (fromJust b)
+ voted (p == ["FORCE"]) (fromJust b)
else
return [AnswerClients [sendChan cl] ["CHAT", "[server]", "vote: 'yes' or 'no'"]]
--- a/gameServer/Votes.hs Mon Feb 16 22:33:15 2015 +0300
+++ b/gameServer/Votes.hs Thu Apr 02 21:09:56 2015 +0300
@@ -26,6 +26,7 @@
import qualified Data.List as L
import qualified Data.Map as Map
import Data.Maybe
+import Control.Applicative
-------------------
import Utils
import CoreTypes
@@ -33,8 +34,8 @@
import EngineInteraction
-voted :: Bool -> Reader (ClientIndex, IRnC) [Action]
-voted vote = do
+voted :: Bool -> Bool -> Reader (ClientIndex, IRnC) [Action]
+voted forced vote = do
cl <- thisClient
rm <- thisRoom
uid <- liftM clUID thisClient
@@ -43,12 +44,15 @@
Nothing ->
return [AnswerClients [sendChan cl] ["CHAT", "[server]", loc "There's no voting going on"]]
Just voting ->
- if uid `L.notElem` entitledToVote voting then
+ if (not forced) && (uid `L.notElem` entitledToVote voting) then
return []
- else if uid `L.elem` map fst (votes voting) then
+ else if (not forced) && (uid `L.elem` map fst (votes voting)) then
return [AnswerClients [sendChan cl] ["CHAT", "[server]", loc "You already have voted"]]
+ else if forced && (not $ isAdministrator cl) then
+ return []
else
- actOnVoting $ voting{votes = (uid, vote):votes voting}
+ ((:) (AnswerClients [sendChan cl] ["CHAT", "[server]", loc "Your vote counted"]))
+ <$> (actOnVoting $ voting{votes = (uid, vote):votes voting})
where
actOnVoting :: Voting -> Reader (ClientIndex, IRnC) [Action]
@@ -57,9 +61,9 @@
let totalV = length $ entitledToVote vt
let successV = totalV `div` 2 + 1
- if length contra > totalV - successV then
+ if (forced && not vote) || (length contra > totalV - successV) then
closeVoting
- else if length pro >= successV then do
+ else if (forced && vote) || (length pro >= successV) then do
a <- act $ voteType vt
c <- closeVoting
return $ c ++ a
@@ -117,10 +121,11 @@
let answers = concatMap (\t ->
[ModifyRoom $ modifyTeam t{hhnum = h}
, AnswerClients chans ["HH_NUM", teamname t, showB h]]
- )
- $
+ ) $ if length curteams * h > 48 then [] else curteams
+ ;
+ curteams =
if isJust $ gameInfo rm then
- teamsAtStart . fromJust . gameInfo $ rm
+ teamsAtStart . fromJust . gameInfo $ rm
else
teams rm
--- a/hedgewars/SDLh.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/SDLh.pas Thu Apr 02 21:09:56 2015 +0300
@@ -306,8 +306,12 @@
SDLK_BACKSPACE = 8;
SDLK_RETURN = 13;
SDLK_ESCAPE = 27;
+ SDLK_a = 97;
+ SDLK_c = 99;
SDLK_q = 113;
+ SDLK_v = 118;
SDLK_w = 119;
+ SDLK_x = 120;
SDLK_DELETE = 127;
SDLK_KP_ENTER = 271;
SDLK_UP = 273;
--- a/hedgewars/hwengine.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/hwengine.pas Thu Apr 02 21:09:56 2015 +0300
@@ -162,7 +162,7 @@
if GameState = gsChat then
begin
// sdl on iphone supports only ashii keyboards and the unicode field is deprecated in sdl 1.3
- KeyPressChat(SDL_GetKeyFromScancode(event.key.keysym.sym), event.key.keysym.sym); //TODO correct for keymodifiers
+ KeyPressChat(SDL_GetKeyFromScancode(event.key.keysym.sym), event.key.keysym.sym, event.key.keysym.modifier);
end
else
if GameState >= gsGame then ProcessKey(event.key);
@@ -208,7 +208,7 @@
{$ELSE}
SDL_KEYDOWN:
if GameState = gsChat then
- KeyPressChat(event.key.keysym.unicode, event.key.keysym.sym)
+ KeyPressChat(event.key.keysym.unicode, event.key.keysym.sym, event.key.keysym.modifier)
else
if GameState >= gsGame then ProcessKey(event.key);
SDL_KEYUP:
--- a/hedgewars/pas2cRedo.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/pas2cRedo.pas Thu Apr 02 21:09:56 2015 +0300
@@ -66,12 +66,12 @@
Now : function : integer;
- new, dispose, FillChar, Move : procedure;
+ new, dispose, FillChar, Insert, Delete, Move : procedure;
trunc, round : function : integer;
abs, sqr : function : integer;
- StrPas, FormatDateTime, copy, delete, str, PosS, trim, LowerCase : function : shortstring;
+ StrPas, FormatDateTime, copy, str, PosS, trim, LowerCase : function : shortstring;
pos : function : integer;
StrToInt : function : integer;
SetLength, SetLengthA, val, StrDispose, StrCopy : procedure;
--- a/hedgewars/uAmmos.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uAmmos.pas Thu Apr 02 21:09:56 2015 +0300
@@ -400,12 +400,12 @@
AddCaption(s, Team^.Clan^.Color, capgrpAmmoinfo);
if (Propz and ammoprop_NeedTarget) <> 0 then
begin
- if Gear <> nil then Gear^.State:= Gear^.State or gstHHChooseTarget;
+ if Gear <> nil then Gear^.State:= Gear^.State or gstChooseTarget;
isCursorVisible:= true
end
else
begin
- if Gear <> nil then Gear^.State:= Gear^.State and (not gstHHChooseTarget);
+ if Gear <> nil then Gear^.State:= Gear^.State and (not gstChooseTarget);
isCursorVisible:= false
end;
end
--- a/hedgewars/uChat.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uChat.pas Thu Apr 02 21:09:56 2015 +0300
@@ -28,13 +28,15 @@
procedure CleanupInput;
procedure AddChatString(s: shortstring);
procedure DrawChat;
-procedure KeyPressChat(Key, Sym: Longword);
+procedure KeyPressChat(Key, Sym: Longword; Modifier: Word);
procedure SendHogSpeech(s: shortstring);
+procedure CopyToClipboard(var newContent: shortstring);
implementation
uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
const MaxStrIndex = 27;
+ MaxInputStrLen = 240;
type TChatLine = record
Tex: PTexture;
@@ -45,22 +47,33 @@
end;
TChatCmd = (ccQuit, ccPause, ccFinish, ccShowHistory, ccFullScreen);
+type TInputStrL = array[0..260] of byte;
+
var Strs: array[0 .. MaxStrIndex] of TChatLine;
MStrs: array[0 .. MaxStrIndex] of shortstring;
LocalStrs: array[0 .. MaxStrIndex] of shortstring;
+ LocalStrsL: array[0 .. MaxStrIndex] of TInputStrL;
missedCount: LongWord;
lastStr: LongWord;
localLastStr: LongInt;
history: LongInt;
visibleCount: LongWord;
InputStr: TChatLine;
- InputStrL: array[0..260] of char; // for full str + 4-byte utf-8 char
+ InputStrL: TInputStrL; // for full str + 4-byte utf-8 char
ChatReady: boolean;
showAll: boolean;
liveLua: boolean;
ChatHidden: boolean;
+ firstDraw: boolean;
+ InputLinePrefix: TChatLine;
+ // cursor
+ cursorPos, cursorX, selectedPos, selectionDx: LongInt;
+ LastKeyPressTick: LongWord;
+
const
+ InputStrLNoPred: byte = 255;
+
colors: array[#0..#6] of TSDL_Color = (
(r:$FF; g:$FF; b:$FF; a:$FF), // unused, feel free to take it for anything
(r:$FF; g:$FF; b:$FF; a:$FF), // chat message [White]
@@ -85,6 +98,59 @@
const Padding = 2;
ClHeight = 2 * Padding + 16; // font height
+function charIsForHogSpeech(c: char): boolean;
+begin
+exit((c = '"') or (c = '''') or (c = '-'));
+end;
+
+procedure ResetSelection();
+begin
+ selectedPos:= -1;
+end;
+
+procedure UpdateCursorCoords();
+var font: THWFont;
+ str : shortstring;
+ coff, soff: LongInt;
+begin
+ if cursorPos = selectedPos then
+ ResetSelection();
+
+ // calculate cursor offset
+
+ str:= InputStr.s;
+ font:= CheckCJKFont(ansistring(str), fnt16);
+
+ // get only substring before cursor to determine length
+ // SetLength(str, cursorPos); // makes pas2c unhappy
+ str[0]:= char(cursorPos);
+ // get render size of text
+ TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @coff, nil);
+
+ cursorX:= 2 + coff;
+
+ // calculate selection width on screen
+ if selectedPos >= 0 then
+ begin
+ if selectedPos > cursorPos then
+ str:= InputStr.s;
+ // SetLength(str, selectedPos); // makes pas2c unhappy
+ str[0]:= char(selectedPos);
+ TTF_SizeUTF8(Fontz[font].Handle, Str2PChar(str), @soff, nil);
+ selectionDx:= soff - coff;
+ end
+ else
+ selectionDx:= 0;
+end;
+
+
+procedure ResetCursor();
+begin
+ ResetSelection();
+ cursorPos:= 0;
+ UpdateCursorCoords();
+end;
+
procedure RenderChatLineTex(var cl: TChatLine; var str: shortstring);
var strSurface,
resSurface: PSDL_Surface;
@@ -139,12 +205,19 @@
begin
cl.s:= str;
color:= colors[#6];
- str:= UserNick + '> ' + str + '_'
+ str:= str + ' ';
end
else
begin
- color:= colors[str[1]];
- delete(str, 1, 1);
+ if str[1] <= High(colors) then
+ begin
+ color:= colors[str[1]];
+ delete(str, 1, 1);
+ end
+ // fallback if invalid color
+ else
+ color:= colors[Low(colors)];
+
cl.s:= str;
end;
@@ -190,8 +263,28 @@
inc(visibleCount)
end;
+procedure CheckPasteBuffer(); forward;
+
+procedure UpdateInputLinePrefix();
+begin
+if liveLua then
+ begin
+ InputLinePrefix.color:= colors[#1];
+ InputLinePrefix.s:= '[Lua] >';
+ end
+else
+ begin
+ InputLinePrefix.color:= colors[#6];
+ InputLinePrefix.s:= UserNick + '>';
+ end;
+
+FreeAndNilTexture(InputLinePrefix.Tex);
+end;
+
procedure DrawChat;
var i, t, left, top, cnt: LongInt;
+ selRect: TSDL_Rect;
+ c: char;
begin
ChatReady:= true; // maybe move to somewhere else?
@@ -204,8 +297,78 @@
// draw chat input line first and under all other lines
if (GameState = gsChat) and (InputStr.Tex <> nil) then
+ begin
+ CheckPasteBuffer();
+
+ if InputLinePrefix.Tex = nil then
+ RenderChatLineTex(InputLinePrefix, InputLinePrefix.s);
+
+ DrawTexture(left, top, InputLinePrefix.Tex);
+ inc(left, InputLinePrefix.Width);
DrawTexture(left, top, InputStr.Tex);
+ if firstDraw then
+ begin
+ UpdateCursorCoords();
+ firstDraw:= false;
+ end;
+
+ if selectedPos < 0 then
+ begin
+ // draw cursor
+ if ((RealTicks - LastKeyPressTick) and 512) < 256 then
+ DrawLineOnScreen(left + cursorX, top + 2, left + cursorX, top + ClHeight - 2, 2.0, $00, $FF, $FF, $FF);
+ end
+ else // draw selection
+ begin
+ selRect.y:= top + 2;
+ selRect.h:= clHeight - 4;
+ if selectionDx < 0 then
+ begin
+ selRect.x:= left + cursorX + selectionDx;
+ selRect.w:= -selectionDx;
+ end
+ else
+ begin
+ selRect.x:= left + cursorX;
+ selRect.w:= selectionDx;
+ end;
+
+ DrawRect(selRect, $FF, $FF, $FF, $40, true);
+ end;
+
+ dec(left, InputLinePrefix.Width);
+
+
+ if (Length(InputStr.s) > 0) and ((CursorPos = 1) or (CursorPos = 2)) then
+ begin
+ c:= InputStr.s[1];
+ if charIsForHogSpeech(c) then
+ begin
+ SpeechHogNumber:= 0;
+ if Length(InputStr.s) > 1 then
+ begin
+ c:= InputStr.s[2];
+ if (c > '0') and (c < '9') then
+ SpeechHogNumber:= byte(c) - 48;
+ end;
+ // default to current hedgehog (if own) or first hedgehog
+ if SpeechHogNumber = 0 then
+ begin
+ if not CurrentTeam^.ExtDriven then
+ SpeechHogNumber:= CurrentTeam^.CurrHedgehog + 1
+ else
+ SpeechHogNumber:= 1;
+ end;
+ end;
+ end
+ else
+ SpeechHogNumber:= -1;
+ end
+else
+ SpeechHogNumber:= -1;
+
+// draw chat lines
if ((not ChatHidden) or showAll) and (UIDisplay <> uiNone) then
begin
if MissedCount <> 0 then // there are chat strings we missed, so print them now
@@ -264,6 +427,7 @@
// put in input history
localLastStr:= (localLastStr + 1) mod MaxStrIndex;
LocalStrs[localLastStr]:= s;
+ LocalStrsL[localLastStr]:= InputStrL;
end;
t:= LocalTeam;
@@ -365,6 +529,7 @@
AddFileLog('[Lua] chat input string parsing disabled');
AddChatString(#3 + 'Lua parsing: OFF');
end;
+ UpdateInputLinePrefix();
end;
exit
end;
@@ -410,26 +575,308 @@
ResetKbd;
end;
-procedure KeyPressChat(Key, Sym: Longword);
+procedure DelBytesFromInputStrBack(endIdx: integer; count: byte);
+var i, startIdx: integer;
+begin
+ // nothing to do if count is 0
+ if count = 0 then
+ exit;
+
+ // first byte to delete
+ startIdx:= endIdx - (count - 1);
+
+ // delete bytes from string
+ Delete(InputStr.s, startIdx, count);
+
+ // wipe utf8 info for deleted char
+ InputStrL[endIdx]:= InputStrLNoPred;
+
+ // shift utf8 char info to reflect new string
+ for i:= endIdx + 1 to Length(InputStr.s) + count do
+ begin
+ if InputStrL[i] <> InputStrLNoPred then
+ begin
+ InputStrL[i-count]:= InputStrL[i] - count;
+ InputStrL[i]:= InputStrLNoPred;
+ end;
+ end;
+
+ SetLine(InputStr, InputStr.s, true);
+end;
+
+// returns count of removed bytes
+function DelCharFromInputStr(idx: integer): integer;
+var btw: byte;
+begin
+ // note: idx is always at last byte of utf8 chars. cuz relevant for InputStrL
+
+ if (Length(InputStr.s) < 1) or (idx < 1) or (idx > Length(InputStr.s)) then
+ exit(0);
+
+ btw:= byte(idx) - InputStrL[idx];
+
+ DelCharFromInputStr:= btw;
+
+ DelBytesFromInputStrBack(idx, btw);
+end;
+
+// unchecked
+procedure DoCursorStepForward();
+begin
+ // go to end of next utf8-char
+ repeat
+ inc(cursorPos);
+ until InputStrL[cursorPos] <> InputStrLNoPred;
+end;
+
+procedure DeleteSelected();
+begin
+ if (selectedPos >= 0) and (cursorPos <> selectedPos) then
+ begin
+ DelBytesFromInputStrBack(max(cursorPos, selectedPos), abs(selectedPos-cursorPos));
+ cursorPos:= min(cursorPos, selectedPos);
+ ResetSelection();
+ end;
+ UpdateCursorCoords();
+end;
+
+procedure HandleSelection(enabled: boolean);
+begin
+if enabled then
+ begin
+ if selectedPos < 0 then
+ selectedPos:= cursorPos;
+ end
+else
+ ResetSelection();
+end;
+
+type TCharSkip = ( none, wspace, numalpha, special );
+
+function GetInputCharSkipClass(index: LongInt): TCharSkip;
+var c: char;
+begin
+ // multi-byte chars counts as letter
+ if (index > 1) and (InputStrL[index] <> index - 1) then
+ exit(numalpha);
+
+ c:= InputStr.s[index];
+
+ // non-ascii counts as letter
+ if c > #127 then
+ exit(numalpha);
+
+ // low-ascii whitespaces and DEL
+ if (c < #33) or (c = #127) then
+ exit(wspace);
+
+ // low-ascii special chars
+ if c < #48 then
+ exit(special);
+
+ // digits
+ if c < #58 then
+ exit(numalpha);
+
+ // make c upper-case
+ if c > #96 then
+ c:= char(byte(c) - 32);
+
+ // letters
+ if (c > #64) and (c < #90) then
+ exit(numalpha);
+
+ // remaining ascii are special chars
+ exit(special);
+end;
+
+// skip from word to word, similar to Qt
+procedure SkipInputChars(skip: TCharSkip; backwards: boolean);
+begin
+if backwards then
+ begin
+ // skip trailing whitespace, similar to Qt
+ while (skip = wspace) and (cursorPos > 0) do
+ begin
+ skip:= GetInputCharSkipClass(cursorPos);
+ if skip = wspace then
+ cursorPos:= InputStrL[cursorPos];
+ end;
+ // skip same-type chars
+ while (cursorPos > 0) and (GetInputCharSkipClass(cursorPos) = skip) do
+ cursorPos:= InputStrL[cursorPos];
+ end
+else
+ begin
+ // skip same-type chars
+ while cursorPos < Length(InputStr.s) do
+ begin
+ DoCursorStepForward();
+ if (GetInputCharSkipClass(cursorPos) <> skip) then
+ begin
+ // go back 1 char
+ cursorPos:= InputStrL[cursorPos];
+ break;
+ end;
+ end;
+ // skip trailing whitespace, similar to Qt
+ while cursorPos < Length(InputStr.s) do
+ begin
+ DoCursorStepForward();
+ if (GetInputCharSkipClass(cursorPos) <> wspace) then
+ begin
+ // go back 1 char
+ cursorPos:= InputStrL[cursorPos];
+ break;
+ end;
+ end;
+ end;
+end;
+
+procedure CopyToClipboard(var newContent: shortstring);
+begin
+ SendIPC(_S'y' + copy(newContent, 1, 253) + #0);
+end;
+
+procedure CopySelectionToClipboard();
+var selection: shortstring;
+begin
+ if selectedPos >= 0 then
+ begin
+ selection:= copy(InputStr.s, min(CursorPos, selectedPos) + 1, abs(CursorPos - selectedPos));
+ CopyToClipboard(selection);
+ end;
+end;
+
+// TODO: honor utf8, don't break utf8 chars when shifting chars beyond limit
+procedure InsertIntoInputStr(s: shortstring);
+var i, l, il, lastc: integer;
+begin
+ // safe length for string
+ l:= min(MaxInputStrLen-cursorPos, Length(s));
+ s:= copy(s,1,l);
+
+ // if we insert rather than append, shift info in InputStrL accordingly
+ if cursorPos < Length(InputStr.s) then
+ begin
+ for i:= Length(InputStr.s) downto cursorPos + 1 do
+ begin
+ if InputStrL[i] <> InputStrLNoPred then
+ begin
+ il:= i + l;
+ // only shift if not overflowing
+ if il <= MaxInputStrLen then
+ InputStrL[il]:= InputStrL[i] + l;
+ InputStrL[i]:= InputStrLNoPred;
+ end;
+ end;
+ end;
+
+ InputStrL[cursorPos + l]:= cursorPos;
+ // insert string truncated to safe length
+ Insert(s, InputStr.s, cursorPos + 1);
+ if Length(InputStr.s) > MaxInputStrLen then
+ InputStr.s[0]:= char(MaxInputStrLen);
+
+ SetLine(InputStr, InputStr.s, true);
+
+ // move cursor to end of inserted string
+ lastc:= MaxInputStrLen;
+ cursorPos:= min(lastc, cursorPos + l);
+ UpdateCursorCoords();
+end;
+
+procedure PasteFromClipboard();
+begin
+ SendIPC(_S'Y');
+end;
+
+procedure CheckPasteBuffer();
+begin
+ if Length(ChatPasteBuffer) > 0 then
+ begin
+ InsertIntoInputStr(ChatPasteBuffer);
+ ChatPasteBuffer:= '';
+ end;
+end;
+
+procedure KeyPressChat(Key, Sym: Longword; Modifier: Word);
const firstByteMark: array[0..3] of byte = (0, $C0, $E0, $F0);
var i, btw, index: integer;
utf8: shortstring;
- action: boolean;
+ action, selMode, ctrl: boolean;
+ skip: TCharSkip;
begin
+ LastKeyPressTick:= RealTicks;
action:= true;
+
+ CheckPasteBuffer();
+
+ selMode:= (modifier and (KMOD_LSHIFT or KMOD_RSHIFT)) <> 0;
+ ctrl:= (modifier and (KMOD_LCTRL or KMOD_RCTRL)) <> 0;
+ skip:= none;
+
case Sym of
SDLK_BACKSPACE:
begin
- if Length(InputStr.s) > 0 then
+ if selectedPos < 0 then
begin
- InputStr.s[0]:= InputStrL[byte(InputStr.s[0])];
- SetLine(InputStr, InputStr.s, true)
+ if ctrl then
+ skip:= GetInputCharSkipClass(cursorPos);
+
+ // remove char before cursor
+ dec(cursorPos, DelCharFromInputStr(cursorPos));
+
+ // delete more if ctrl is held
+ if ctrl and (selectedPos < 0) then
+ begin
+ HandleSelection(true);
+ SkipInputChars(skip, true);
+ DeleteSelected();
+ end
+ else
+ UpdateCursorCoords();
+
end
+ else
+ DeleteSelected();
+ end;
+ SDLK_DELETE:
+ begin
+ if selectedPos < 0 then
+ begin
+ // remove char after cursor
+ if cursorPos < Length(InputStr.s) then
+ begin
+ DoCursorStepForward();
+ if ctrl then
+ skip:= GetInputCharSkipClass(cursorPos);
+
+ // delete char
+ dec(cursorPos, DelCharFromInputStr(cursorPos));
+
+ // delete more if ctrl is held
+ if ctrl and (cursorPos < Length(InputStr.s)) then
+ begin
+ HandleSelection(true);
+ SkipInputChars(skip, false);
+ DeleteSelected();
+ end;
+ end
+ else
+ UpdateCursorCoords();
+ end
+ else
+ DeleteSelected();
end;
SDLK_ESCAPE:
begin
if Length(InputStr.s) > 0 then
- SetLine(InputStr, '', true)
+ begin
+ SetLine(InputStr, '', true);
+ FillChar(InputStrL, sizeof(InputStrL), InputStrLNoPred);
+ ResetCursor();
+ end
else CleanupInput
end;
SDLK_RETURN, SDLK_KP_ENTER:
@@ -437,7 +884,9 @@
if Length(InputStr.s) > 0 then
begin
AcceptChatString(InputStr.s);
- SetLine(InputStr, '', false)
+ SetLine(InputStr, '', false);
+ FillChar(InputStrL, sizeof(InputStrL), InputStrLNoPred);
+ ResetCursor();
end;
CleanupInput
end;
@@ -447,20 +896,150 @@
if (Sym = SDLK_DOWN) and (history > 0) then dec(history);
index:= localLastStr - history + 1;
if (index > localLastStr) then
- SetLine(InputStr, '', true)
- else SetLine(InputStr, LocalStrs[index], true)
+ begin
+ SetLine(InputStr, '', true);
+ FillChar(InputStrL, sizeof(InputStrL), InputStrLNoPred);
+ end
+ else
+ begin
+ SetLine(InputStr, LocalStrs[index], true);
+ InputStrL:= LocalStrsL[index];
+ end;
+ cursorPos:= Length(InputStr.s);
+ ResetSelection();
+ UpdateCursorCoords();
+ end;
+ SDLK_HOME:
+ begin
+ if cursorPos > 0 then
+ begin
+ HandleSelection(selMode);
+ cursorPos:= 0;
+ end
+ else if (not selMode) then
+ ResetSelection();
+
+ UpdateCursorCoords();
+ end;
+ SDLK_END:
+ begin
+ i:= Length(InputStr.s);
+ if cursorPos < i then
+ begin
+ HandleSelection(selMode);
+ cursorPos:= i;
+ end
+ else if (not selMode) then
+ ResetSelection();
+
+ UpdateCursorCoords();
end;
- SDLK_RIGHT, SDLK_LEFT, SDLK_DELETE,
- SDLK_HOME, SDLK_END,
+ SDLK_LEFT:
+ begin
+ if cursorPos > 0 then
+ begin
+
+ if ctrl then
+ skip:= GetInputCharSkipClass(cursorPos);
+
+ if selMode or (selectedPos < 0) then
+ begin
+ HandleSelection(selMode);
+ // go to end of previous utf8-char
+ cursorPos:= InputStrL[cursorPos];
+ end
+ else // if we're leaving selection mode, jump to its left end
+ begin
+ cursorPos:= min(cursorPos, selectedPos);
+ ResetSelection();
+ end;
+
+ if ctrl then
+ SkipInputChars(skip, true);
+
+ end
+ else if (not selMode) then
+ ResetSelection();
+
+ UpdateCursorCoords();
+ end;
+ SDLK_RIGHT:
+ begin
+ if cursorPos < Length(InputStr.s) then
+ begin
+
+ if selMode or (selectedPos < 0) then
+ begin
+ HandleSelection(selMode);
+ DoCursorStepForward();
+ end
+ else // if we're leaving selection mode, jump to its right end
+ begin
+ cursorPos:= max(cursorPos, selectedPos);
+ ResetSelection();
+ end;
+
+ if ctrl then
+ SkipInputChars(GetInputCharSkipClass(cursorPos), false);
+
+ end
+ else if (not selMode) then
+ ResetSelection();
+
+ UpdateCursorCoords();
+ end;
SDLK_PAGEUP, SDLK_PAGEDOWN:
begin
// ignore me!!!
end;
+ SDLK_a:
+ begin
+ // select all
+ if ctrl then
+ begin
+ ResetSelection();
+ cursorPos:= 0;
+ HandleSelection(true);
+ cursorPos:= Length(InputStr.s);
+ UpdateCursorCoords();
+ end
+ else
+ action:= false;
+ end;
+ SDLK_c:
+ begin
+ // copy
+ if ctrl then
+ CopySelectionToClipboard()
+ else
+ action:= false;
+ end;
+ SDLK_v:
+ begin
+ // paste
+ if ctrl then
+ PasteFromClipboard()
+ else
+ action:= false;
+ end;
+ SDLK_x:
+ begin
+ // cut
+ if ctrl then
+ begin
+ CopySelectionToClipboard();
+ DeleteSelected();
+ end
+ else
+ action:= false;
+ end;
else
action:= false;
end;
if not action and (Key <> 0) then
begin
+ DeleteSelected();
+
if (Key < $80) then
btw:= 1
else if (Key < $800) then
@@ -480,11 +1059,18 @@
utf8:= char(Key or firstByteMark[Pred(btw)]) + utf8;
- if byte(InputStr.s[0]) + btw > 240 then
+ if Length(InputStr.s) + btw > MaxInputStrLen then
exit;
- InputStrL[byte(InputStr.s[0]) + btw]:= InputStr.s[0];
- SetLine(InputStr, InputStr.s + utf8, true)
+ if (Length(InputStr.s) = 0) and (Length(utf8) = 1) and (charIsForHogSpeech(utf8[1])) then
+ begin
+ InsertIntoInputStr(utf8);
+ InsertIntoInputStr(utf8);
+ cursorPos:= 1;
+ UpdateCursorCoords();
+ end
+ else
+ InsertIntoInputStr(utf8);
end
end;
@@ -539,7 +1125,14 @@
if length(s) = 0 then
SetLine(InputStr, '', true)
else
- SetLine(InputStr, '/team ', true)
+ begin
+ SetLine(InputStr, '/team ', true);
+ // update InputStrL and cursor accordingly
+ // this allows cursor-jumping over '/team ' as if it was a single char
+ InputStrL[6]:= 0;
+ cursorPos:= 6;
+ UpdateCursorCoords();
+ end;
end;
procedure initModule;
@@ -560,15 +1153,25 @@
missedCount:= 0;
liveLua:= false;
ChatHidden:= false;
+ firstDraw:= true;
+ InputLinePrefix.Tex:= nil;
+ UpdateInputLinePrefix();
+ inputStr.s:= '';
inputStr.Tex := nil;
for i:= 0 to MaxStrIndex do
Strs[i].Tex := nil;
+
+ FillChar(InputStrL, sizeof(InputStrL), InputStrLNoPred);
+
+ LastKeyPressTick:= 0;
+ ResetCursor();
end;
procedure freeModule;
var i: ShortInt;
begin
+ FreeAndNilTexture(InputLinePrefix.Tex);
FreeAndNilTexture(InputStr.Tex);
for i:= 0 to MaxStrIndex do
FreeAndNilTexture(Strs[i].Tex);
--- a/hedgewars/uCollisions.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uCollisions.pas Thu Apr 02 21:09:56 2015 +0300
@@ -52,7 +52,7 @@
function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline;
function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word;
-function TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
+function TestRectangleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
function CheckCoordInWater(X, Y: LongInt): boolean; inline;
@@ -398,11 +398,11 @@
Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
end;
-function TestRectancleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
+function TestRectangleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean;
var x, y: LongInt;
TestWord: LongWord;
begin
-TestRectancleForObstacle:= true;
+TestRectangleForObstacle:= true;
if landOnly then
TestWord:= 255
@@ -431,7 +431,7 @@
if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > TestWord) then
exit;
-TestRectancleForObstacle:= false
+TestRectangleForObstacle:= false
end;
function CalcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): boolean;
--- a/hedgewars/uCommandHandlers.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uCommandHandlers.pas Thu Apr 02 21:09:56 2015 +0300
@@ -27,6 +27,7 @@
implementation
uses uCommands, uTypes, uVariables, uIO, uDebug, uConsts, uScript, uUtils, SDLh, uWorld, uRandom, uCaptions
+ , uVisualGearsList
{$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF};
var prevGState: TGameState = gsConfirm;
@@ -748,6 +749,11 @@
cLandMines:= StrToInt(s)
end;
+procedure chAirMines(var s: shortstring);
+begin
+cAirMines:= StrToInt(s)
+end;
+
procedure chExplosives(var s: shortstring);
begin
cExplosives:= StrToInt(s)
@@ -771,7 +777,14 @@
procedure chFastUntilLag(var s: shortstring);
begin
-fastUntilLag:= StrToInt(s) <> 0
+ fastUntilLag:= StrToInt(s) <> 0;
+
+ if not fastUntilLag then
+ begin
+ // update health bars and the wind indicator
+ AddVisualGear(0, 0, vgtTeamHealthSorter);
+ AddVisualGear(0, 0, vgtSmoothWindBar)
+ end
end;
procedure chCampVar(var s:shortstring);
@@ -837,6 +850,7 @@
RegisterVariable('getawaytime' , @chGetAwayTime , false);
RegisterVariable('minedudpct',@chMineDudPercent, false);
RegisterVariable('minesnum', @chLandMines , false);
+ RegisterVariable('airmines', @chAirMines , false);
RegisterVariable('explosives',@chExplosives , false);
RegisterVariable('gmflags' , @chGameFlags , false);
RegisterVariable('turntime', @chHedgehogTurnTime, false);
--- a/hedgewars/uConsts.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uConsts.pas Thu Apr 02 21:09:56 2015 +0300
@@ -215,7 +215,7 @@
gstAttacked = $00000008;
gstAttacking = $00000010;
gstCollision = $00000020;
- gstHHChooseTarget = $00000040;
+ gstChooseTarget = $00000040;
gstHHJumping = $00000100;
gsttmpFlag = $00000200;
gstHHThinking = $00000800;
--- a/hedgewars/uGame.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGame.pas Thu Apr 02 21:09:56 2015 +0300
@@ -102,8 +102,9 @@
if isInLag then
case GameType of
gmtNet: begin
- // just update the health bars
+ // update health bars and the wind indicator
AddVisualGear(0, 0, vgtTeamHealthSorter);
+ AddVisualGear(0, 0, vgtSmoothWindBar);
break;
end;
gmtDemo, gmtRecord: begin
--- a/hedgewars/uGears.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGears.pas Thu Apr 02 21:09:56 2015 +0300
@@ -33,7 +33,7 @@
* effects are called "Visual Gears" and defined in the respective unit!
*)
interface
-uses uConsts, uFloat, uTypes, uChat;
+uses uConsts, uFloat, uTypes, uChat, uCollisions;
procedure initModule;
procedure freeModule;
@@ -394,7 +394,7 @@
if (CurrentHedgehog^.Gear^.State and gstAttacked <> 0)
and (Ammoz[CurrentHedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0) then
begin
- CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstHHChooseTarget;
+ CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State or gstChooseTarget;
isCursorVisible := true
end;
CurrentHedgehog^.Gear^.State:= CurrentHedgehog^.Gear^.State and (not gstAttacked);
@@ -551,6 +551,9 @@
end;
Gear:= Gear^.NextGear
end;
+
+if SpeechHogNumber > 0 then
+ DrawHHOrder();
end;
procedure FreeGearsList;
@@ -567,7 +570,7 @@
end;
procedure AddMiscGears;
-var p,i,j, unplaced: Longword;
+var p,i,j,t,h,unplaced: Longword;
rx, ry: LongInt;
rdx, rdy: hwFloat;
Gear: PGear;
@@ -604,6 +607,70 @@
inc(i)
end;
+i:= 0;
+j:= 0;
+p:= 0; // 0 searching, 1 bad position, 2 added.
+unplaced:= 0;
+if cAirMines > 0 then
+ Gear:= AddGear(0, 0, gtAirMine, 0, _0, _0, 0);
+while (i < cAirMines) and (j < 1000*cAirMines) do
+ begin
+ p:= 0;
+ if hasBorder then
+ begin
+ rx:= leftX+GetRandom(rightX-leftX-16)+8;
+ ry:= topY+GetRandom(LAND_HEIGHT-topY-16)+8
+ end
+ else
+ begin
+ rx:= leftX+GetRandom(rightX-leftX+400)-200;
+ ry:= topY+GetRandom(LAND_HEIGHT-topY+400)-200
+ end;
+ Gear^.X:= int2hwFloat(rx);
+ Gear^.Y:= int2hwFloat(ry);
+ if CheckLandValue(rx, ry, $FFFF) and
+ (TestCollisionYwithGear(Gear,-1) = 0) and
+ (TestCollisionXwithGear(Gear, 1) = 0) and
+ (TestCollisionXwithGear(Gear,-1) = 0) and
+ (TestCollisionYwithGear(Gear, 1) = 0) then
+ begin
+ t:= 0;
+ while (t < TeamsCount) and (p = 0) do
+ begin
+ h:= 0;
+ with TeamsArray[t]^ do
+ while (h < cMaxHHIndex) and (p = 0) do
+ begin
+ if (Hedgehogs[h].Gear <> nil) then
+ begin
+ rdx:=Gear^.X-Hedgehogs[h].Gear^.X;
+ rdy:=Gear^.Y-Hedgehogs[h].Gear^.Y;
+ if (Gear^.Angle < $FFFFFFFF) and
+ ((rdx.Round+rdy.Round < Gear^.Angle) and
+ (hwRound(hwSqr(rdx) + hwSqr(rdy)) < sqr(Gear^.Angle))) then
+ begin
+// Debug line. Remove later
+// AddFileLog('Too Close to Hog @ (' + inttostr(rx) + ',' + inttostr(ry) + ')');
+
+ p:= 1
+ end
+ end;
+ inc(h)
+ end;
+ inc(t)
+ end;
+ if p = 0 then
+ begin
+ inc(i);
+ AddFileLog('Placed Air Mine @ (' + inttostr(rx) + ',' + inttostr(ry) + ')');
+ if i < cAirMines then
+ Gear:= AddGear(0, 0, gtAirMine, 0, _0, _0, 0)
+ end
+ end;
+ inc(j)
+ end;
+if p <> 0 then DeleteGear(Gear);
+
if (GameFlags and gfLowGravity) <> 0 then
begin
cGravity:= cMaxWindSpeed;
@@ -930,6 +997,7 @@
@doStepHedgehog,
@doStepMine,
@doStepCase,
+ @doStepAirMine,
@doStepCase,
@doStepBomb,
@doStepShell,
@@ -991,8 +1059,7 @@
@doStepIceGun,
@doStepAddAmmo,
@doStepGenericFaller,
- @doStepKnife,
- @doStepAirMine);
+ @doStepKnife);
begin
doStepHandlers:= handlers;
--- a/hedgewars/uGearsHandlersMess.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGearsHandlersMess.pas Thu Apr 02 21:09:56 2015 +0300
@@ -1382,6 +1382,7 @@
dec(TurnTimeLeft)
else
begin
+ HHGear^.State := HHGear^.State and (not gstNotKickable);
DeleteGear(Gear);
AfterAttack
end;
@@ -1762,11 +1763,16 @@
var i,t,targDist,tmpDist: LongWord;
targ, tmpG: PGear;
trackSpeed, airFriction, tX, tY: hwFloat;
+ isUnderwater: Boolean;
begin
+ isUnderwater:= CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y) + Gear^.Radius);
if Gear^.Pos > 0 then
begin
airFriction:= _1;
- dec(airFriction.QWordValue,Gear^.Pos);
+ if isUnderwater then
+ dec(airFriction.QWordValue,Gear^.Pos*2)
+ else
+ dec(airFriction.QWordValue,Gear^.Pos);
Gear^.dX:= Gear^.dX*airFriction;
Gear^.dY:= Gear^.dY*airFriction
end;
@@ -1799,14 +1805,14 @@
((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or
(Gear^.State and gsttmpFlag = 0) or
(Gear^.Angle = 0) then
- gear^.State:= gear^.State and (not gstHHChooseTarget)
+ gear^.State:= gear^.State and (not gstChooseTarget)
else if
// todo, allow not finding new target, set timeout on target retention
(Gear^.State and gstAttacking = 0) and
((GameTicks and $FF) = 17) and
(GameTicks > Gear^.FlightTime) then // recheck hunted hog
begin
- gear^.State:= gear^.State or gstHHChooseTarget;
+ gear^.State:= gear^.State or gstChooseTarget;
if targ <> nil then
targDist:= Distance(Gear^.X-targ^.X,Gear^.Y-targ^.Y).Round
else targDist:= 0;
@@ -1837,9 +1843,12 @@
if targ <> nil then
begin
trackSpeed:= _0;
- trackSpeed.QWordValue:= Gear^.Power;
+ if isUnderwater then
+ trackSpeed.QWordValue:= Gear^.Power div 2
+ else
+ trackSpeed.QWordValue:= Gear^.Power;
if (Gear^.X < targ^.X) and (Gear^.dX < _0_1) then
- Gear^.dX:= Gear^.dX+trackSpeed
+ Gear^.dX:= Gear^.dX+trackSpeed // please leave as an add. I like the effect
else if (Gear^.X > targ^.X) and (Gear^.dX > -_0_1) then
Gear^.dX:= Gear^.dX-trackSpeed;
if (Gear^.Y < targ^.Y) and (Gear^.dY < _0_1) then
@@ -2747,7 +2756,7 @@
end;
HHGear^.Message := HHGear^.Message and (not gmAttack);
HHGear^.State := HHGear^.State and (not gstAttacking);
- HHGear^.State := HHGear^.State or gstHHChooseTarget;
+ HHGear^.State := HHGear^.State or gstChooseTarget;
isCursorVisible := true;
DeleteGear(Gear)
end
@@ -2832,7 +2841,7 @@
begin
HHGear^.Message := HHGear^.Message and (not gmAttack);
HHGear^.State := HHGear^.State and (not gstAttacking);
- HHGear^.State := HHGear^.State or gstHHChooseTarget;
+ HHGear^.State := HHGear^.State or gstChooseTarget;
isCursorVisible := true;
warn:= AddVisualGear(Gear^.Target.X, oy, vgtNoPlaceWarn, 0, true);
if warn <> nil then
@@ -3131,13 +3140,6 @@
////////////////////////////////////////////////////////////////////////////////
-const cakeh = 27;
-var
- CakePoints: array[0..Pred(cakeh)] of record
- x, y: hwFloat;
- end;
- CakeI: Longword;
-
procedure doStepCakeExpl(Gear: PGear);
begin
AllInactive := false;
@@ -3204,6 +3206,7 @@
procedure doStepCakeWork(Gear: PGear);
var
tdx, tdy: hwFloat;
+ cakeData: PCakeData;
begin
AllInactive := false;
@@ -3222,24 +3225,31 @@
Gear^.RenderTimer := false;
Gear^.doStep := @doStepCakeDown;
exit
- end;
+ end
+ else if Gear^.Timer < 6000 then
+ Gear^.RenderTimer:= true;
if not cakeStep(Gear) then Gear^.doStep:= @doStepCakeFall;
if Gear^.Tag = 0 then
begin
- CakeI := (CakeI + 1) mod cakeh;
- tdx := CakePoints[CakeI].x - Gear^.X;
- tdy := - CakePoints[CakeI].y + Gear^.Y;
- CakePoints[CakeI].x := Gear^.X;
- CakePoints[CakeI].y := Gear^.Y;
- Gear^.DirAngle := DxDy2Angle(tdx, tdy);
+ cakeData:= PCakeData(Gear^.Data);
+ with cakeData^ do
+ begin
+ CakeI := (CakeI + 1) mod cakeh;
+ tdx := CakePoints[CakeI].x - Gear^.X;
+ tdy := - CakePoints[CakeI].y + Gear^.Y;
+ CakePoints[CakeI].x := Gear^.X;
+ CakePoints[CakeI].y := Gear^.Y;
+ Gear^.DirAngle := DxDy2Angle(tdx, tdy);
+ end;
end;
end;
procedure doStepCakeUp(Gear: PGear);
var
i: Longword;
+ cakeData: PCakeData;
begin
AllInactive := false;
@@ -3250,12 +3260,16 @@
if Gear^.Pos = 6 then
begin
- for i:= 0 to Pred(cakeh) do
+ cakeData:= PCakeData(Gear^.Data);
+ with cakeData^ do
begin
- CakePoints[i].x := Gear^.X;
- CakePoints[i].y := Gear^.Y
+ for i:= 0 to Pred(cakeh) do
+ begin
+ CakePoints[i].x := Gear^.X;
+ CakePoints[i].y := Gear^.Y
+ end;
+ CakeI := 0;
end;
- CakeI := 0;
Gear^.doStep := @doStepCakeWork
end
else
@@ -3559,6 +3573,11 @@
AllInactive := false;
dec(Gear^.Timer);
HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ DeleteGear(gear);
+ exit
+ end;
HedgehogChAngle(HHGear);
gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
@@ -3575,6 +3594,7 @@
if (Gear^.Timer = 0) or ((HHGear^.State and gstHHDriven) = 0) then
begin
+ HHGear^.State := HHGear^.State and (not gstNotKickable);
DeleteGear(Gear);
AfterAttack
end
@@ -3631,7 +3651,7 @@
else if Gear^.Angle < 2048 then
inc(Gear^.Angle)
else fChanged := false
- end
+ end
else
begin
if ((Gear^.Message and gmLeft) <> 0) then
@@ -3706,6 +3726,7 @@
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, dY, 0);
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtFlame, 0, dX, -dY, 0);
end;
+ if HHGear <> nil then HHGear^.State := HHGear^.State and (not gstNotKickable);
DeleteGear(Gear)
end;
@@ -4962,6 +4983,11 @@
begin
AllInactive := false;
HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ DeleteGear(gear);
+ exit
+ end;
HedgehogChAngle(HHGear);
gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
@@ -5014,6 +5040,7 @@
if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) then
begin
+ HHGear^.State := HHGear^.State and (not gstNotKickable);
DeleteGear(Gear);
AfterAttack
end
@@ -5049,6 +5076,11 @@
begin
AllInactive := false;
HHGear := Gear^.Hedgehog^.Gear;
+ if HHGear = nil then
+ begin
+ DeleteGear(gear);
+ exit
+ end;
HedgehogChAngle(HHGear);
gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle);
gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle);
@@ -5091,6 +5123,7 @@
if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) or ((HHGear^.Message and gmAttack) <> 0) then
begin
HHGear^.Message:= HHGear^.Message and (not gmAttack);
+ HHGear^.State := HHGear^.State and (not gstNotKickable);
DeleteGear(Gear);
AfterAttack
end
--- a/hedgewars/uGearsHedgehog.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGearsHedgehog.pas Thu Apr 02 21:09:56 2015 +0300
@@ -222,7 +222,7 @@
with Gear^,
Gear^.Hedgehog^ do
begin
- if ((State and gstHHDriven) <> 0) and ((State and (gstAttacked or gstHHChooseTarget)) = 0) and (((State and gstMoving) = 0)
+ if ((State and gstHHDriven) <> 0) and ((State and (gstAttacked or gstChooseTarget)) = 0) and (((State and gstMoving) = 0)
or (Power > 0)
or (CurAmmoType = amTeleport)
or
@@ -1318,7 +1318,7 @@
begin
if Gear^.Timer = 0 then
begin
- Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstHHChooseTarget));
+ Gear^.State:= Gear^.State and (not (gstWait or gstLoser or gstWinner or gstAttacked or gstNotKickable or gstChooseTarget));
if Gear^.Hedgehog^.Effects[heFrozen] = 0 then Gear^.Active:= false;
AddCI(Gear);
exit
--- a/hedgewars/uGearsList.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGearsList.pas Thu Apr 02 21:09:56 2015 +0300
@@ -41,6 +41,7 @@
(* gtHedgehog *) , amNothing
(* gtMine *) , amMine
(* gtCase *) , amNothing
+(* gtAirMine *) , amAirMine
(* gtExplosives *) , amNothing
(* gtGrenade *) , amGrenade
(* gtShell *) , amBazooka
@@ -103,7 +104,6 @@
(* gtAddAmmo *) , amNothing
(* gtGenericFaller *) , amNothing
(* gtKnife *) , amKnife
-(* gtAirMine *) , amAirMine
);
@@ -166,6 +166,7 @@
function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear;
var gear: PGear;
//c: byte;
+ cakeData: PCakeData;
begin
inc(GCounter);
@@ -193,6 +194,7 @@
gear^.AmmoType:= GearKindAmmoTypeMap[Kind];
gear^.CollisionMask:= $FFFF;
gear^.Tint:= $FFFFFFFF;
+gear^.Data:= nil;
if CurrentHedgehog <> nil then
begin
@@ -342,6 +344,8 @@
gear^.Radius:= 3;
gear^.Friction:= _450 * _0_01 * cRopePercent;
RopePoints.Count:= 0;
+ gear^.Tint:= $D8D8D8FF;
+ gear^.Tag:= 0; // normal rope render
end;
gtMine: begin
gear^.ImpactSound:= sndMineImpact;
@@ -364,14 +368,14 @@
gear^.ImpactSound:= sndDenied;
gear^.nImpactSounds:= 1;
gear^.Health:= 30;
- gear^.State:= gear^.State or gstMoving or gstNoGravity;
+ gear^.State:= gear^.State or gstMoving or gstNoGravity or gstSubmersible;
gear^.Radius:= 8;
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_995;
gear^.Density:= _1;
gear^.Angle:= 175; // Radius at which air bombs will start "seeking". $FFFFFFFF = unlimited. check is skipped.
gear^.Power:= cMaxWindSpeed.QWordValue div 2; // hwFloat converted. 1/2 g default. defines the "seek" speed when a gear is in range.
- gear^.Pos:= cMaxWindSpeed.QWordValue; // air friction. slows it down when not hitting stuff
+ gear^.Pos:= cMaxWindSpeed.QWordValue * 3 div 2; // air friction. slows it down when not hitting stuff
gear^.Karma:= 30; // damage
if gear^.Timer = 0 then
begin
@@ -500,12 +504,14 @@
gear^.Health:= 2048;
gear^.Radius:= 7;
gear^.Z:= cOnHHZ;
- gear^.RenderTimer:= true;
+ gear^.RenderTimer:= false;
gear^.DirAngle:= -90 * hwSign(Gear^.dX);
if not dX.isNegative then
gear^.Angle:= 1
else
- gear^.Angle:= 3
+ gear^.Angle:= 3;
+ New(cakeData);
+ gear^.Data:= Pointer(cakeData);
end;
gtHellishBomb: begin
gear^.ImpactSound:= sndHellishImpact1;
@@ -658,6 +664,7 @@
var team: PTeam;
t,i: Longword;
k: boolean;
+ cakeData: PCakeData;
begin
ScriptCall('onGearDelete', gear^.uid);
@@ -673,6 +680,12 @@
if (Gear^.LinkedGear^.LinkedGear = Gear) then
Gear^.LinkedGear^.LinkedGear:= nil;
end
+else if Gear^.Kind = gtCake then
+ begin
+ cakeData:= PCakeData(Gear^.Data);
+ Dispose(cakeData);
+ cakeData:= nil;
+ end
else if Gear^.Kind = gtHedgehog then
(*
This behaviour dates back to revision 4, and I accidentally encountered it with TARDIS. I don't think it must apply to any modern weapon, since if it was actually hit, the best the gear could do would be to destroy itself immediately, and you'd still end up with two graves. I believe it should be removed
--- a/hedgewars/uGearsRender.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGearsRender.pas Thu Apr 02 21:09:56 2015 +0300
@@ -36,6 +36,7 @@
rounded : array[0..MAXROPEPOINTS + 2] of TVertex2f;
end;
procedure RenderGear(Gear: PGear; x, y: LongInt);
+procedure DrawHHOrder();
var RopePoints: record
Count: Longword;
@@ -68,7 +69,8 @@
EnableTexture(false);
//glEnable(GL_LINE_SMOOTH);
- Tint($70, $70, $70, $FF);
+
+ Tint(Gear^.Tint shr 24 div 3, Gear^.Tint shr 16 and $FF div 3, Gear^.Tint shr 8 and $FF div 3, Gear^.Tint and $FF);
n:= RopePoints.Count + 2;
@@ -79,7 +81,7 @@
glLineWidth(3.0 * cScaleFactor);
glDrawArrays(GL_LINE_STRIP, 0, n);
- Tint($D8, $D8, $D8, $FF);
+ Tint(Gear^.Tint);
glLineWidth(2.0 * cScaleFactor);
glDrawArrays(GL_LINE_STRIP, 0, n);
@@ -169,7 +171,7 @@
var roplen, i: LongInt;
begin
if Gear^.Hedgehog^.Gear = nil then exit;
- if (cReducedQuality and rqSimpleRope) <> 0 then
+ if (Gear^.Tag = 1) or ((cReducedQuality and rqSimpleRope) <> 0) then
DrawRopeLinesRQ(Gear)
else
begin
@@ -214,6 +216,51 @@
end;
end;
+procedure DrawHHOrder();
+var HHGear: PGear;
+ hh: PHedgehog;
+ c, i, t, x, y, sprH, sprW, fSprOff: LongInt;
+begin
+t:= LocalTeam;
+
+if not CurrentTeam^.ExtDriven then
+ for i:= 0 to Pred(TeamsCount) do
+ if (TeamsArray[i] = CurrentTeam) then
+ t:= i;
+
+if t < 0 then
+ exit;
+
+if TeamsArray[t] <> nil then
+ begin
+ sprH:= SpritesData[sprBigDigit].Height;
+ sprW:= SpritesData[sprBigDigit].Width;
+ fSprOff:= sprW div 4 + SpritesData[sprFrame].Width div 4 - 1; // - 1 for overlap to avoid artifacts
+ i:= 0;
+ c:= 0;
+ repeat
+ hh:= @TeamsArray[t]^.Hedgehogs[i];
+ inc(i);
+ if (hh <> nil) and (hh^.Gear <> nil) then
+ begin
+ inc(c);
+ HHGear:= hh^.Gear;
+ x:= hwRound(HHGear^.X) + WorldDx;
+ y:= hwRound(HHGear^.Y) + WorldDy - 2;
+ if (SpeechHogNumber <> c) or ((RealTicks and 512) < 256) then
+ begin
+ DrawTextureF(SpritesData[sprFrame].Texture, 0.5, x - fSprOff, y, 0, 1, SpritesData[sprFrame].Width, SpritesData[sprFrame].Height);
+ DrawTextureF(SpritesData[sprFrame].Texture, 0.5, x + fSprOff, y, 1, 1, SpritesData[sprFrame].Width, SpritesData[sprFrame].Height);
+ DrawTextureF(SpritesData[sprBigDigit].Texture, 0.5, x, y, c, 1, sprW, sprH);
+ end
+ else
+ DrawCircle(x, y, 20, 3, 0, $FF, $FF, $80);
+ end;
+ until (i > cMaxHHIndex);
+ end
+
+end;
+
procedure DrawHH(Gear: PGear; ox, oy: LongInt);
var i, t: LongInt;
@@ -1128,7 +1175,7 @@
end
else if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) then // mine is chasing a hog
DrawSprite(sprAirMine, x-16, y-16, (RealTicks div 25) mod 16)
- else if Gear^.State and gstHHChooseTarget <> 0 then // mine is seeking for hogs
+ else if Gear^.State and gstChooseTarget <> 0 then // mine is seeking for hogs
DrawSprite(sprAirMine, x-16, y-16, (RealTicks div 125) mod 16)
else
DrawSprite(sprAirMine, x-16, y-16, 4); // mine is active but not seeking
--- a/hedgewars/uGearsUtils.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uGearsUtils.pas Thu Apr 02 21:09:56 2015 +0300
@@ -82,6 +82,7 @@
vg: PVisualGear;
i, cnt: LongInt;
wrap: boolean;
+ bubble: PVisualGear;
begin
if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');
if Radius > 25 then KickFlakes(Radius, X, Y);
@@ -89,7 +90,17 @@
if ((Mask and EXPLNoGfx) = 0) then
begin
vg:= nil;
- if Radius > 50 then vg:= AddVisualGear(X, Y, vgtBigExplosion)
+ if CheckCoordInWater(X, Y - Radius) then
+ begin
+ cnt:= 2 * Radius;
+ for i:= (Radius * Radius) div 4 downto 0 do
+ begin
+ bubble := AddVisualGear(X - Radius + random(cnt), Y - Radius + random(cnt), vgtBubble);
+ if bubble <> nil then
+ bubble^.dY:= 0.1 + random(20)/10;
+ end
+ end
+ else if Radius > 50 then vg:= AddVisualGear(X, Y, vgtBigExplosion)
else if Radius > 10 then vg:= AddVisualGear(X, Y, vgtExplosion);
if vg <> nil then
vg^.Tint:= Tint;
@@ -703,11 +714,7 @@
ScriptCall('onGearWaterSkip', Gear^.uid);
end
else
- begin
- if (not ((Gear^.Kind = gtJetpack) or (Gear^.Kind = gtBee))) then
- Gear^.State:= (Gear^.State and (not gstSubmersible)); // making it temporary for most gears is more attractive I think
CheckGearDrowning := false
- end
end;
--- a/hedgewars/uIO.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uIO.pas Thu Apr 02 21:09:56 2015 +0300
@@ -143,6 +143,7 @@
ParseChatCommand('chatmsg ' + #4, s, 2)
else
isProcessed:= false;
+ 'Y': ChatPasteBuffer:= copy(s, 2, Length(s) - 1);
else
isProcessed:= false;
end;
@@ -370,7 +371,11 @@
isInLag:= (headcmd = nil) and tmpflag and (not CurrentTeam^.hasGone);
-if isInLag then fastUntilLag:= false
+if isInLag and fastUntilLag then
+begin
+ ParseCommand('spectate 0', true);
+ fastUntilLag:= false
+end;
end;
procedure chFatalError(var s: shortstring);
@@ -398,7 +403,7 @@
with CurrentHedgehog^.Gear^,
CurrentHedgehog^ do
- if (State and gstHHChooseTarget) <> 0 then
+ if (State and gstChooseTarget) <> 0 then
begin
isCursorVisible:= false;
if not CurrentTeam^.ExtDriven then
@@ -421,7 +426,7 @@
TargetPoint.Y:= putY
end;
AddFileLog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y));
- State:= State and (not gstHHChooseTarget);
+ State:= State and (not gstChooseTarget);
if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackingPut) <> 0 then
Message:= Message or (gmAttack and InputMask);
end
--- a/hedgewars/uLandGraphics.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uLandGraphics.pas Thu Apr 02 21:09:56 2015 +0300
@@ -82,7 +82,7 @@
inc(drawPixelBG);
end
else if ((Land[landY, landX] and lfObject) <> 0) or (((LandPixels[pixelY, pixelX] and AMask) shr AShift) < 255) then
- LandPixels[pixelY, pixelX]:= LandPixels[pixelY, pixelX] and (not AMASK)
+ LandPixels[pixelY, pixelX]:= ExplosionBorderColorNoA
end;
end;
@@ -199,7 +199,7 @@
begin
calculatePixelsCoordinates(i, y, px, py);
if ((Land[y, i] and lfIndestructible) = 0) and (not disableLandBack or (Land[y, i] > 255)) then
- LandPixels[py, px]:= LandPixels[py, px] and (not AMASK);
+ LandPixels[py, px]:= ExplosionBorderColorNoA;
end;
icePixel:
for i:= fromPix to toPix do
@@ -920,7 +920,68 @@
Despeckle:= false
end;
+// a bit of AA for explosions
procedure Smooth(X, Y: LongInt);
+var c, r, g, b, a, i: integer;
+ nx, ny: LongInt;
+ pixel: LongWord;
+begin
+
+// only AA inwards
+if (Land[Y, X] and lfDamaged) = 0 then
+ exit;
+
+// check location
+if (Y <= LongInt(topY) + 1) or (Y >= LAND_HEIGHT-2)
+or (X <= LongInt(leftX) + 1) or (X >= LongInt(rightX) - 1) then
+ exit;
+
+// counter for neighbor pixels that are not known to be undamaged
+c:= 8;
+
+// accumalating rgba value of relevant pixels here
+r:= 0;
+g:= 0;
+b:= 0;
+a:= 0;
+
+// iterate over all neighbor pixels (also itself, will be skipped anyway)
+for nx:= X-1 to X+1 do
+ for ny:= Y-1 to Y+1 do
+ // only consider undamaged neighbors (also leads to skipping itself)
+ if (Land[ny, nx] and lfDamaged) = 0 then
+ begin
+ pixel:= LandPixels[ny, nx];
+ inc(r, (pixel and RMask) shr RShift);
+ inc(g, (pixel and GMask) shr GShift);
+ inc(b, (pixel and BMask) shr BShift);
+ inc(a, (pixel and AMask) shr AShift);
+ dec(c);
+ end;
+
+// nothing do to if all neighbors damaged
+if c < 1 then
+ exit;
+
+// use explosion color for damaged pixels
+for i:= 1 to c do
+ begin
+ inc(r, ExplosionBorderColorR);
+ inc(g, ExplosionBorderColorG);
+ inc(b, ExplosionBorderColorB);
+ inc(a, 255);
+ end;
+
+// set resulting color value based on average of all neighbors
+r:= r div 8;
+g:= g div 8;
+b:= b div 8;
+a:= a div 8;
+LandPixels[y,x]:= (r shl RShift) or (g shl GShift) or (b shl BShift) or (a shl AShift);
+
+end;
+
+procedure Smooth_oldImpl(X, Y: LongInt);
begin
// a bit of AA for explosions
if (Land[Y, X] = 0) and (Y > LongInt(topY) + 1) and
@@ -939,12 +1000,14 @@
(((((LandPixels[y,x] and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or
(((((LandPixels[y,x] and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift)
end;
+{
if (Land[y, x-1] = lfObject) then
Land[y,x]:= lfObject
else if (Land[y, x+1] = lfObject) then
Land[y,x]:= lfObject
else
Land[y,x]:= lfBasic;
+}
end
else if ((((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0))
or (((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0))
@@ -965,6 +1028,7 @@
(((((LandPixels[y,x] and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or
(((((LandPixels[y,x] and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift)
end;
+{
if (Land[y, x-1] = lfObject) then
Land[y, x]:= lfObject
else if (Land[y, x+1] = lfObject) then
@@ -974,6 +1038,7 @@
else if (Land[y-1, x] = lfObject) then
Land[y, x]:= lfObject
else Land[y,x]:= lfBasic
+}
end
end
else if ((cReducedQuality and rqBlurryLand) = 0) and ((LandPixels[Y, X] and AMask) = AMask)
@@ -1060,16 +1125,18 @@
end;
end;
-for y:= 0 to LAND_HEIGHT div 32 - 1 do
- for x:= 0 to LAND_WIDTH div 32 - 1 do
- if LandDirty[y, x] <> 0 then
- begin
- ty:= y * 32;
- tx:= x * 32;
- for yy:= ty to ty + 31 do
- for xx:= tx to tx + 31 do
- Smooth(xx,yy)
- end;
+// smooth explosion borders (except if land is blurry)
+if (cReducedQuality and rqBlurryLand) = 0 then
+ for y:= 0 to LAND_HEIGHT div 32 - 1 do
+ for x:= 0 to LAND_WIDTH div 32 - 1 do
+ if LandDirty[y, x] <> 0 then
+ begin
+ ty:= y * 32;
+ tx:= x * 32;
+ for yy:= ty to ty + 31 do
+ for xx:= tx to tx + 31 do
+ Smooth(xx,yy)
+ end;
for y:= 0 to LAND_HEIGHT div 32 - 1 do
for x:= 0 to LAND_WIDTH div 32 - 1 do
--- a/hedgewars/uLandObjects.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uLandObjects.pas Thu Apr 02 21:09:56 2015 +0300
@@ -553,7 +553,12 @@
c2.g:= t;
c2.b:= t
end;
- ExplosionBorderColor:= (c2.r shl RShift) or (c2.g shl GShift) or (c2.b shl BShift) or AMask;
+ ExplosionBorderColorR:= c2.r;
+ ExplosionBorderColorG:= c2.g;
+ ExplosionBorderColorB:= c2.b;
+ ExplosionBorderColorNoA:=
+ (c2.r shl RShift) or (c2.g shl GShift) or (c2.b shl BShift);
+ ExplosionBorderColor:= ExplosionBorderColorNoA or AMask;
end
else if key = 'water-top' then
begin
--- a/hedgewars/uRender.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uRender.pas Thu Apr 02 21:09:56 2015 +0300
@@ -48,6 +48,7 @@
procedure DrawCircle (X, Y, Radius, Width: LongInt);
procedure DrawCircle (X, Y, Radius, Width: LongInt; r, g, b, a: Byte);
+procedure DrawCircleFilled (X, Y, Radius: LongInt; r, g, b, a: Byte);
procedure DrawLine (X0, Y0, X1, Y1, Width: Single; color: LongWord); inline;
procedure DrawLine (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte);
@@ -59,12 +60,16 @@
procedure DrawWaves (Dir, dX, dY, oX: LongInt; tnt: Byte);
procedure RenderClear ();
-procedure RenderSetClearColor (r, g, b, a: real);
+procedure RenderClear (mode: TRenderMode);
+procedure RenderSetClearColor (r, g, b, a: real);
procedure Tint (r, g, b, a: Byte); inline;
procedure Tint (c: Longword); inline;
procedure untint(); inline;
procedure setTintAdd (f: boolean); inline;
+// call this to finish the rendering of current frame
+procedure FinishRender();
+
function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
// 0 => not offscreen, <0 => left/top of screen >0 => right/below of screen
@@ -74,13 +79,14 @@
procedure SetScale(f: GLfloat);
procedure UpdateViewLimits();
-procedure RenderSetup();
+procedure RendererSetup();
+procedure RendererCleanup();
+
+procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
+procedure ResetDepth(rm: TRenderMode);
// TODO everything below this should not need a public interface
-procedure CreateFramebuffer(var frame, depth, tex: GLuint);
-procedure DeleteFramebuffer(var frame, depth, tex: GLuint);
-
procedure EnableTexture(enable:Boolean);
procedure SetTexCoordPointer(p: Pointer;n: Integer); inline;
@@ -89,14 +95,9 @@
procedure UpdateModelviewProjection(); inline;
-procedure openglLoadIdentity (); inline;
-procedure openglTranslProjMatrix(X, Y, Z: GLFloat); inline;
procedure openglPushMatrix (); inline;
procedure openglPopMatrix (); inline;
procedure openglTranslatef (X, Y, Z: GLfloat); inline;
-procedure openglScalef (ScaleX, ScaleY, ScaleZ: GLfloat); inline;
-procedure openglRotatef (RotX, RotY, RotZ: GLfloat; dir: LongInt); inline;
-procedure openglTint (r, g, b, a: Byte); inline;
implementation
@@ -123,6 +124,20 @@
LastColorPointerN, LastTexCoordPointerN, LastVertexPointerN: Integer;
{$ENDIF}
+{$IFDEF USE_S3D_RENDERING}
+ // texture/vertex buffers for left/right/default eye modes
+ texLRDtb, texLvb, texRvb: array [0..3] of TVertex2f;
+{$ENDIF}
+
+procedure openglLoadIdentity (); forward;
+procedure openglTranslProjMatrix(X, Y, Z: GLFloat); forward;
+procedure openglScalef (ScaleX, ScaleY, ScaleZ: GLfloat); forward;
+procedure openglRotatef (RotX, RotY, RotZ: GLfloat; dir: LongInt); forward;
+procedure openglTint (r, g, b, a: Byte); forward;
+
+procedure CreateFramebuffer(var frame, depth, tex: GLuint); forward;
+procedure DeleteFramebuffer(var frame, depth, tex: GLuint); forward;
+
function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline;
begin
isAreaOffscreen:= (isDxAreaOffscreen(X, Width) <> 0) or (isDyAreaOffscreen(Y, Height) <> 0);
@@ -147,11 +162,92 @@
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
end;
+{$IFDEF USE_S3D_RENDERING}
+procedure RenderClear(mode: TRenderMode);
+var frame: GLuint;
+begin
+ if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+ begin
+ case mode of
+ rmLeftEye: frame:= frameL;
+ rmRightEye: frame:= frameR;
+ else
+ frame:= defaultFrame;
+ end;
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame);
+
+ RenderClear();
+ end
+ else
+ begin
+ // draw left eye in red channel only
+ if mode = rmLeftEye then
+ begin
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ RenderClear();
+ if cStereoMode = smGreenRed then
+ glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
+ else if cStereoMode = smBlueRed then
+ glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
+ else if cStereoMode = smCyanRed then
+ glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
+ else
+ glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+ end
+ else
+ begin
+ // draw right eye in selected channel(s) only
+ if cStereoMode = smRedGreen then
+ glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
+ else if cStereoMode = smRedBlue then
+ glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
+ else if cStereoMode = smRedCyan then
+ glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
+ else
+ glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
+ end;
+ end;
+end;
+{$ENDIF}
+
procedure RenderSetClearColor(r, g, b, a: real);
begin
glClearColor(r, g, b, a);
end;
+procedure FinishRender();
+begin
+
+{$IFDEF USE_S3D_RENDERING}
+if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+ begin
+ RenderClear(rmDefault);
+
+ SetScale(cDefaultZoomLevel);
+
+
+ // same for all
+ SetTexCoordPointer(@texLRDtb, Length(texLRDtb));
+
+
+ // draw left frame
+ glBindTexture(GL_TEXTURE_2D, texl);
+ SetVertexPointer(@texLvb, Length(texLvb));
+ //UpdateModelviewProjection;
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Length(texLvb));
+
+ // draw right frame
+ glBindTexture(GL_TEXTURE_2D, texl);
+ SetVertexPointer(@texRvb, Length(texRvb));
+ //UpdateModelviewProjection;
+ glDrawArrays(GL_TRIANGLE_FAN, 0, Length(texRvb));
+
+ SetScale(zoom);
+ end;
+{$ENDIF}
+end;
+
{$IFDEF GL2}
function CompileShader(shaderFile: string; shaderType: GLenum): GLuint;
var
@@ -302,14 +398,42 @@
glDeleteRenderbuffersEXT(1, @depth);
glDeleteFramebuffersEXT(1, @frame);
end;
+{$ENDIF}
+procedure RendererCleanup();
+begin
+{$IFNDEF PAS2C}
+{$IFDEF USE_VIDEO_RECORDING}
+ if defaultFrame <> 0 then
+ DeleteFramebuffer(defaultFrame, depthv, texv);
{$ENDIF}
-procedure RenderSetup();
+{$IFDEF USE_S3D_RENDERING}
+ if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+ begin
+ DeleteFramebuffer(framel, depthl, texl);
+ DeleteFramebuffer(framer, depthr, texr);
+ end
+{$ENDIF}
+{$ENDIF}
+end;
+
+procedure RendererSetup();
var AuxBufNum: LongInt = 0;
tmpstr: ansistring;
tmpint: LongInt;
tmpn: LongInt;
begin
+{$IFDEF MOBILE}
+ // TODO: this function creates an opengles1.1 context
+ // un-comment below and add proper logic to support opengles2.0
+ //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+ //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ if SDLGLcontext = nil then
+ SDLGLcontext:= SDL_GL_CreateContext(SDLwindow);
+ SDLTry(SDLGLcontext <> nil, true);
+ SDL_GL_SetSwapInterval(1);
+{$ENDIF}
+
// suppress hint/warning
AuxBufNum:= AuxBufNum;
@@ -426,12 +550,66 @@
CreateFramebuffer(framel, depthl, texl);
CreateFramebuffer(framer, depthr, texr);
+
+
+
// reset
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame)
end
else
cStereoMode:= smNone;
end;
+
+ // set up vertex/texture buffers for frame textures
+ texLRDtb[0].X:= 0.0;
+ texLRDtb[0].Y:= 0.0;
+ texLRDtb[1].X:= 1.0;
+ texLRDtb[1].Y:= 0.0;
+ texLRDtb[2].X:= 1.0;
+ texLRDtb[2].Y:= 1.0;
+ texLRDtb[3].X:= 0.0;
+ texLRDtb[3].Y:= 1.0;
+
+ if cStereoMode = smHorizontal then
+ begin
+ texLvb[0].X:= cScreenWidth / -2;
+ texLvb[0].Y:= cScreenHeight;
+ texLvb[1].X:= 0;
+ texLvb[1].Y:= cScreenHeight;
+ texLvb[2].X:= 0;
+ texLvb[2].Y:= 0;
+ texLvb[3].X:= cScreenWidth / -2;
+ texLvb[3].Y:= 0;
+
+ texRvb[0].X:= 0;
+ texRvb[0].Y:= cScreenHeight;
+ texRvb[1].X:= cScreenWidth / 2;
+ texRvb[1].Y:= cScreenHeight;
+ texRvb[2].X:= cScreenWidth / 2;
+ texRvb[2].Y:= 0;
+ texRvb[3].X:= 0;
+ texRvb[3].Y:= 0;
+ end
+ else
+ begin
+ texLvb[0].X:= cScreenWidth / -2;
+ texLvb[0].Y:= cScreenHeight / 2;
+ texLvb[1].X:= cScreenWidth / 2;
+ texLvb[1].Y:= cScreenHeight / 2;
+ texLvb[2].X:= cScreenWidth / 2;
+ texLvb[2].Y:= 0;
+ texLvb[3].X:= cScreenWidth / -2;
+ texLvb[3].Y:= 0;
+
+ texRvb[0].X:= cScreenWidth / -2;
+ texRvb[0].Y:= cScreenHeight;
+ texRvb[1].X:= cScreenWidth / 2;
+ texRvb[1].Y:= cScreenHeight;
+ texRvb[2].X:= cScreenWidth / 2;
+ texRvb[2].Y:= cScreenHeight / 2;
+ texRvb[3].X:= cScreenWidth / -2;
+ texRvb[3].Y:= cScreenHeight / 2;
+ end;
{$ENDIF}
// set view port to whole window
@@ -1220,6 +1398,25 @@
glDisable(GL_LINE_SMOOTH);
end;
+procedure DrawCircleFilled(X, Y, Radius: LongInt; r, g, b, a: Byte);
+var
+ i: LongInt;
+begin
+ VertexBuffer[0].X := X;
+ VertexBuffer[0].Y := Y;
+
+ for i := 1 to 19 do begin
+ VertexBuffer[i].X := X + Radius*cos(i*pi/9);
+ VertexBuffer[i].Y := Y + Radius*sin(i*pi/9);
+ end;
+
+ EnableTexture(False);
+ Tint(r, g, b, a);
+ SetVertexPointer(@VertexBuffer[0], 20);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 20);
+ Untint();
+ EnableTexture(True);
+end;
procedure DrawHedgehog(X, Y: LongInt; Dir: LongInt; Pos, Step: LongWord; Angle: real);
const VertexBuffer: array [0..3] of TVertex2f = (
@@ -1387,11 +1584,6 @@
firsti:= -1;
afteri:= 0;
-if GameTicks < 2000 then
- lol:= 2000 - GameTicks
-else
- lol:= 0;
-
if InTopY < 0 then
InTopY:= 0;
@@ -1403,6 +1595,13 @@
end
else
begin
+
+ // animate water walls raise animation at start of game
+ if GameTicks < 2000 then
+ lol:= 2000 - GameTicks
+ else
+ lol:= 0;
+
if InLeftX > ViewLeftX then
begin
VertexBuffer[0].X:= OutLeftX - lol;
@@ -1712,6 +1911,42 @@
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
end;
+procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
+var tmp: LongInt;
+begin
+{$IFNDEF USE_S3D_RENDERING}
+ rm:= rm; d:= d; tmp:= tmp; // avoid hint
+{$ELSE}
+ d:= d / 5;
+ if rm = rmDefault then
+ exit
+ else if rm = rmLeftEye then
+ d:= -d;
+ cStereoDepth:= cStereoDepth + d;
+ openglTranslProjMatrix(d, 0, 0);
+ tmp:= round(d / cScaleFactor * cScreenWidth);
+ ViewLeftX := ViewLeftX - tmp;
+ ViewRightX:= ViewRightX - tmp;
+{$ENDIF}
+end;
+
+procedure ResetDepth(rm: TRenderMode);
+var tmp: LongInt;
+begin
+{$IFNDEF USE_S3D_RENDERING}
+ rm:= rm; tmp:= tmp; // avoid hint
+{$ELSE}
+ if rm = rmDefault then
+ exit;
+ openglTranslProjMatrix(-cStereoDepth, 0, 0);
+ tmp:= round(cStereoDepth / cScaleFactor * cScreenWidth);
+ ViewLeftX := ViewLeftX + tmp;
+ ViewRightX:= ViewRightX + tmp;
+ cStereoDepth:= 0;
+{$ENDIF}
+end;
+
+
procedure initModule;
begin
LastTint:= cWhiteColor + 1;
--- a/hedgewars/uRenderUtils.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uRenderUtils.pas Thu Apr 02 21:09:56 2015 +0300
@@ -171,7 +171,7 @@
r0:= (r0 * (255 - LongInt(a1)) + r1 * LongInt(a1)) div 255;
g0:= (g0 * (255 - LongInt(a1)) + g1 * LongInt(a1)) div 255;
b0:= (b0 * (255 - LongInt(a1)) + b1 * LongInt(a1)) div 255;
- a0:= (a0 * (255 - LongInt(a1)) + a1 * LongInt(a1)) div 255;
+ a0:= a0 + ((255 - LongInt(a0)) * a1 div 255);
destPixels^[i]:= SDL_MapRGBA(dest^.format, r0, g0, b0, a0);
end;
end;
--- a/hedgewars/uScript.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uScript.pas Thu Apr 02 21:09:56 2015 +0300
@@ -2309,7 +2309,7 @@
begin
if CheckLuaParamCount(L, 5, 'TestRectForObstacle', 'x1, y1, x2, y2, landOnly') then
begin
- rtn:= TestRectancleForObstacle(
+ rtn:= TestRectangleForObstacle(
lua_tointeger(L, 1),
lua_tointeger(L, 2),
lua_tointeger(L, 3),
@@ -3027,7 +3027,7 @@
ScriptSetInteger('gstAttacked' , gstAttacked);
ScriptSetInteger('gstAttacking' , gstAttacking);
ScriptSetInteger('gstCollision' , gstCollision);
-ScriptSetInteger('gstHHChooseTarget', gstHHChooseTarget);
+ScriptSetInteger('gstChooseTarget', gstChooseTarget);
ScriptSetInteger('gstHHJumping' , gstHHJumping);
ScriptSetInteger('gsttmpFlag' , gsttmpFlag);
ScriptSetInteger('gstHHThinking' , gstHHThinking);
--- a/hedgewars/uStore.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uStore.pas Thu Apr 02 21:09:56 2015 +0300
@@ -561,19 +561,8 @@
end;
end;
end;
-{$IFNDEF PAS2C}
-{$IFDEF USE_VIDEO_RECORDING}
- if defaultFrame <> 0 then
- DeleteFramebuffer(defaultFrame, depthv, texv);
-{$ENDIF}
-{$IFDEF USE_S3D_RENDERING}
- if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
- begin
- DeleteFramebuffer(framel, depthl, texl);
- DeleteFramebuffer(framer, depthr, texr);
- end
-{$ENDIF}
-{$ENDIF}
+
+RendererCleanup();
end;
@@ -756,18 +745,7 @@
AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))) + ')');
{$ENDIF}
-{$IFDEF MOBILE}
- // TODO: this function creates an opengles1.1 context
- // un-comment below and add proper logic to support opengles2.0
- //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
- //SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
- if SDLGLcontext = nil then
- SDLGLcontext:= SDL_GL_CreateContext(SDLwindow);
- SDLTry(SDLGLcontext <> nil, true);
- SDL_GL_SetSwapInterval(1);
-{$ENDIF}
-
- RenderSetup();
+ RendererSetup();
end;
(*
@@ -1045,7 +1023,7 @@
glutHideWindow();
// we do not need to set this callback, but it is required for GLUT3 compat
glutDisplayFunc(@SwapBuffers);
- RenderSetup();
+ RendererSetup();
end;
{$ENDIF} // SDL2
{$ENDIF} // USE_VIDEO_RECORDING
--- a/hedgewars/uTeams.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uTeams.pas Thu Apr 02 21:09:56 2015 +0300
@@ -549,10 +549,12 @@
Gear: PGear;
begin
s:= '';
-if (not isDeveloperMode) or (CurrentTeam = nil) then
+if (not isDeveloperMode) then
exit;
+TryDo((CurrentTeam <> nil), 'Can''t add hedgehogs yet, add a team first!', true);
with CurrentTeam^ do
begin
+ TryDo(HedgehogsNumber<=cMaxHHIndex, 'Can''t add hedgehog to "' + TeamName + '"! (already ' + intToStr(HedgehogsNumber) + ' hogs)', true);
SplitBySpace(id, s);
SwitchCurrentHedgehog(@Hedgehogs[HedgehogsNumber]);
CurrentHedgehog^.BotLevel:= StrToInt(id);
--- a/hedgewars/uTypes.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uTypes.pas Thu Apr 02 21:09:56 2015 +0300
@@ -92,20 +92,21 @@
);
// Gears that interact with other Gears and/or Land
- TGearType = (gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives, // these gears should be avoided when searching a spawn place
- gtGrenade, gtShell, gtGrave, gtBee, // 8
- gtShotgunShot, gtPickHammer, gtRope, // 11
- gtDEagleShot, gtDynamite, gtClusterBomb, gtCluster, gtShover, // 16
- gtFirePunch, gtATStartGame, // 18
- gtATFinishGame, gtParachute, gtAirAttack, gtAirBomb, gtBlowTorch, // 23
- gtGirder, gtTeleport, gtSwitcher, gtTarget, gtMortar, // 28
- gtWhip, gtKamikaze, gtCake, gtSeduction, gtWatermelon, gtMelonPiece, // 34
- gtHellishBomb, gtWaterUp, gtDrill, gtBallGun, gtBall, gtRCPlane, // 40
- gtSniperRifleShot, gtJetpack, gtMolotov, gtBirdy, // 44
- gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower, // 50
- gtSMine, gtPoisonCloud, gtHammer, gtHammerHit, gtResurrector, // 55
+ // first row of gears (<gtExplosives) should be avoided when searching a spawn place
+ TGearType = (gtFlame, gtHedgehog, gtMine, gtCase, gtAirMine, gtExplosives,
+ gtGrenade, gtShell, gtGrave, gtBee, // 9
+ gtShotgunShot, gtPickHammer, gtRope, // 12
+ gtDEagleShot, gtDynamite, gtClusterBomb, gtCluster, gtShover, // 17
+ gtFirePunch, gtATStartGame, // 19
+ gtATFinishGame, gtParachute, gtAirAttack, gtAirBomb, gtBlowTorch, // 24
+ gtGirder, gtTeleport, gtSwitcher, gtTarget, gtMortar, // 29
+ gtWhip, gtKamikaze, gtCake, gtSeduction, gtWatermelon, gtMelonPiece, // 35
+ gtHellishBomb, gtWaterUp, gtDrill, gtBallGun, gtBall, gtRCPlane, // 41
+ gtSniperRifleShot, gtJetpack, gtMolotov, gtBirdy, // 45
+ gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower, // 51
+ gtSMine, gtPoisonCloud, gtHammer, gtHammerHit, gtResurrector, // 56
gtNapalmBomb, gtSnowball, gtFlake, {gtStructure,} gtLandGun, gtTardis, // 61
- gtIceGun, gtAddAmmo, gtGenericFaller, gtKnife, gtAirMine); // 66
+ gtIceGun, gtAddAmmo, gtGenericFaller, gtKnife); // 65
// Gears that are _only_ of visual nature (e.g. background stuff, visual effects, speechbubbles, etc.)
TVisualGearType = (vgtFlake, vgtCloud, vgtExplPart, vgtExplPart2, vgtFire,
@@ -282,6 +283,7 @@
Tint: LongWord; // Used to colour a texture
LinkedGear: PGear; // Used to track a related gear. Portal pairs for example.
SoundChannel: LongInt; // Used to track a sound the gear started
+ Data: Pointer; // pointer to gear type specific data structure (if any)
end;
TPGearArray = array of PGear;
PGearArrayS = record
@@ -515,6 +517,19 @@
getDimensions, getImageDimensions: boolean;
end;
+ // gear data types
+
+ const cakeh = 27;
+
+ type TCakeData = record
+ CakeI: integer;
+ CakePoints: array[0..Pred(cakeh)] of record
+ x, y: hwFloat;
+ end;
+ end;
+
+ PCakeData = ^TCakeData;
+
implementation
end.
--- a/hedgewars/uVariables.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uVariables.pas Thu Apr 02 21:09:56 2015 +0300
@@ -123,7 +123,11 @@
isAudioMuted : boolean;
// originally typed consts
- ExplosionBorderColor: LongWord;
+ ExplosionBorderColorR,
+ ExplosionBorderColorG,
+ ExplosionBorderColorB,
+ ExplosionBorderColorNoA,
+ ExplosionBorderColor: LongWord;
IceColor : LongWord;
IceEdgeColor : LongWord;
WaterOpacity: byte;
@@ -146,6 +150,7 @@
cCaseFactor : Longword;
cLandMines : Longword;
+ cAirMines : Longword;
cExplosives : Longword;
cScriptName : shortstring;
@@ -213,6 +218,8 @@
WorldDx: LongInt;
WorldDy: LongInt;
+ SpeechHogNumber: LongInt;
+
// for tracking the limits of the visible grid based on cScaleFactor
ViewLeftX, ViewRightX, ViewBottomY, ViewTopY, ViewWidth, ViewHeight: LongInt;
@@ -233,6 +240,8 @@
MaxTextureSize: LongInt;
+ ChatPasteBuffer: shortstring;
+
/////////////////////////////////////
//Buttons
{$IFDEF USE_TOUCH_INTERFACE}
@@ -2532,7 +2541,11 @@
SDWaterOpacity:= $80;
SDTint:= $80;
+ ExplosionBorderColorR:= 80;
+ ExplosionBorderColorG:= 80;
+ ExplosionBorderColorB:= 80;
ExplosionBorderColor:= $FF808080;
+ ExplosionBorderColorNoA:= ExplosionBorderColor and (not AMask);
IceColor:= ($44 shl RShift) or ($97 shl GShift) or ($A9 shl BShift) or ($A0 shl AShift);
IceEdgeColor:= ($8A shl RShift) or ($AF shl GShift) or ($B2 shl BShift) or ($FF shl AShift);
@@ -2602,6 +2615,7 @@
AttackBar := 0; // 0 - none, 1 - just bar at the right-down corner, 2 - from weapon
cCaseFactor := 5; {0..9}
cLandMines := 4;
+ cAirMines := 4;
cExplosives := 2;
GameState := Low(TGameState);
@@ -2666,6 +2680,7 @@
if cFullscreenHeight = 0 then
cFullscreenHeight:= min(cWindowedHeight, 480);
+ SpeechHogNumber:= -1;
LuaGoals:= '';
cMapName:= '';
@@ -2678,6 +2693,8 @@
cStereoDepth:= 0;
cViewLimitsDebug:= false;
AprilOne := false;
+
+ ChatPasteBuffer:= '';
end;
procedure freeModule;
--- a/hedgewars/uVisualGears.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uVisualGears.pas Thu Apr 02 21:09:56 2015 +0300
@@ -288,6 +288,14 @@
i:= 1;
DrawTextureRotatedF(SpritesData[TSprite(Gear^.State)].Texture, Gear^.Scale, 0, 0, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, i, SpritesData[TSprite(Gear^.State)].Width, SpritesData[TSprite(Gear^.State)].Height, Gear^.Angle);
end;
+ vgtFeather: begin
+ if Gear^.FrameTicks < 255 then
+ begin
+ Tint($FF, $FF, $FF, Gear^.FrameTicks);
+ tinted:= true
+ end;
+ DrawSpriteRotatedF(sprFeather, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, 1, Gear^.Angle);
+ end;
end;
if (cReducedQuality and rqAntiBoom) = 0 then
case Gear^.Kind of
@@ -333,14 +341,6 @@
end;
DrawSpriteRotatedF(sprShell, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, 1, Gear^.Angle);
end;
- vgtFeather: begin
- if Gear^.FrameTicks < 255 then
- begin
- Tint($FF, $FF, $FF, Gear^.FrameTicks);
- tinted:= true
- end;
- DrawSpriteRotatedF(sprFeather, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, 1, Gear^.Angle);
- end;
vgtEgg: DrawSpriteRotatedF(sprEgg, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, Gear^.Frame, 1, Gear^.Angle);
vgtBeeTrace: begin
if Gear^.FrameTicks < $FF then
--- a/hedgewars/uVisualGearsHandlers.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uVisualGearsHandlers.pas Thu Apr 02 21:09:56 2015 +0300
@@ -515,7 +515,8 @@
procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword);
var i, t, h: LongInt;
begin
-for t:= 1 to min(Steps, Gear^.Timer) do
+if currsorter = Gear then
+ for t:= 1 to min(Steps, Gear^.Timer) do
begin
dec(Gear^.Timer);
if (Gear^.Timer and 15) = 0 then
@@ -872,31 +873,47 @@
end;
////////////////////////////////////////////////////////////////////////////////
+var
+ currwindbar: PVisualGear = nil;
+
+procedure doStepSmoothWindBarWork(Gear: PVisualGear; Steps: Longword);
+begin
+ if currwindbar = Gear then
+ begin
+ inc(Gear^.Timer, Steps);
+
+ while Gear^.Timer >= 10 do
+ begin
+ dec(Gear^.Timer, 10);
+ if WindBarWidth < Gear^.Tag then
+ inc(WindBarWidth)
+ else if WindBarWidth > Gear^.Tag then
+ dec(WindBarWidth);
+ end;
+ if cWindspeedf > Gear^.dAngle then
+ begin
+ cWindspeedf := cWindspeedf - Gear^.Angle*Steps;
+ if cWindspeedf < Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
+ end
+ else if cWindspeedf < Gear^.dAngle then
+ begin
+ cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
+ if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
+ end;
+ end;
+
+ if ((WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle)) or (currwindbar <> Gear) then
+ begin
+ if currwindbar = Gear then currwindbar:= nil;
+ DeleteVisualGear(Gear)
+ end
+end;
+
procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword);
begin
-inc(Gear^.Timer, Steps);
-
-while Gear^.Timer >= 10 do
- begin
- dec(Gear^.Timer, 10);
- if WindBarWidth < Gear^.Tag then
- inc(WindBarWidth)
- else if WindBarWidth > Gear^.Tag then
- dec(WindBarWidth);
- end;
-if cWindspeedf > Gear^.dAngle then
- begin
- cWindspeedf := cWindspeedf - Gear^.Angle*Steps;
- if cWindspeedf < Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
- end
-else if cWindspeedf < Gear^.dAngle then
- begin
- cWindspeedf := cWindspeedf + Gear^.Angle*Steps;
- if cWindspeedf > Gear^.dAngle then cWindspeedf:= Gear^.dAngle;
- end;
-
-if (WindBarWidth = Gear^.Tag) and (cWindspeedf = Gear^.dAngle) then
- DeleteVisualGear(Gear)
+ currwindbar:= Gear;
+ Gear^.doStep:= @doStepSmoothWindBarWork;
+ doStepSmoothWindBarWork(Gear, Steps)
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword);
--- a/hedgewars/uVisualGearsList.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uVisualGearsList.pas Thu Apr 02 21:09:56 2015 +0300
@@ -78,6 +78,7 @@
vgtSmokeTrace,
vgtEvilTrace,
vgtNote,
+ vgtFeather,
vgtSmoothWindBar])) then
exit;
@@ -399,6 +400,7 @@
vgtSmallDamageTag,
vgtHealthTag,
vgtStraightShot,
+ vgtFeather,
vgtChunk: gear^.Layer:= 3;
// 2: this layer is outside the screen when stereo
@@ -409,7 +411,6 @@
vgtSteam,
vgtAmmo,
vgtShell,
- vgtFeather,
vgtEgg,
vgtBeeTrace,
vgtSmokeRing,
--- a/hedgewars/uWorld.pas Mon Feb 16 22:33:15 2015 +0300
+++ b/hedgewars/uWorld.pas Thu Apr 02 21:09:56 2015 +0300
@@ -17,7 +17,6 @@
*)
{$INCLUDE "options.inc"}
-{$IF GLunit = GL}{$DEFINE GLunit:=GL,GLext}{$ENDIF}
unit uWorld;
interface
@@ -53,7 +52,6 @@
, uVisualGears
, uChat
, uLandTexture
- , GLunit
, uVariables
, uUtils
, uTextures
@@ -857,154 +855,28 @@
else
ZoomValue:= zoom;
- // Sky
- glClear(GL_COLOR_BUFFER_BIT);
- //glPushMatrix;
- //glScalef(1.0, 1.0, 1.0);
-
if (not isPaused) and (not isAFK) and (GameType <> gmtRecord) then
MoveCamera;
if cStereoMode = smNone then
begin
- glClear(GL_COLOR_BUFFER_BIT);
+ RenderClear();
DrawWorldStereo(Lag, rmDefault)
end
{$IFDEF USE_S3D_RENDERING}
- else if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) then
+ else
begin
- // create left fb
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framel);
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+ // draw frame for left eye
+ RenderClear(rmLeftEye);
DrawWorldStereo(Lag, rmLeftEye);
- // create right fb
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framer);
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
+ // draw frame for right eye
+ RenderClear(rmRightEye);
DrawWorldStereo(0, rmRightEye);
-
- // detatch drawing from fbs
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame);
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
- SetScale(cDefaultZoomLevel);
-
- // draw left frame
- glBindTexture(GL_TEXTURE_2D, texl);
- glBegin(GL_QUADS);
- if cStereoMode = smHorizontal then
- begin
- glTexCoord2f(0.0, 0.0);
- glVertex2d(cScreenWidth / -2, cScreenHeight);
- glTexCoord2f(1.0, 0.0);
- glVertex2d(0, cScreenHeight);
- glTexCoord2f(1.0, 1.0);
- glVertex2d(0, 0);
- glTexCoord2f(0.0, 1.0);
- glVertex2d(cScreenWidth / -2, 0);
- end
- else
- begin
- glTexCoord2f(0.0, 0.0);
- glVertex2d(cScreenWidth / -2, cScreenHeight / 2);
- glTexCoord2f(1.0, 0.0);
- glVertex2d(cScreenWidth / 2, cScreenHeight / 2);
- glTexCoord2f(1.0, 1.0);
- glVertex2d(cScreenWidth / 2, 0);
- glTexCoord2f(0.0, 1.0);
- glVertex2d(cScreenWidth / -2, 0);
- end;
- glEnd();
+ end;
+{$ENDIF}
- // draw right frame
- glBindTexture(GL_TEXTURE_2D, texr);
- glBegin(GL_QUADS);
- if cStereoMode = smHorizontal then
- begin
- glTexCoord2f(0.0, 0.0);
- glVertex2d(0, cScreenHeight);
- glTexCoord2f(1.0, 0.0);
- glVertex2d(cScreenWidth / 2, cScreenHeight);
- glTexCoord2f(1.0, 1.0);
- glVertex2d(cScreenWidth / 2, 0);
- glTexCoord2f(0.0, 1.0);
- glVertex2d(0, 0);
- end
- else
- begin
- glTexCoord2f(0.0, 0.0);
- glVertex2d(cScreenWidth / -2, cScreenHeight);
- glTexCoord2f(1.0, 0.0);
- glVertex2d(cScreenWidth / 2, cScreenHeight);
- glTexCoord2f(1.0, 1.0);
- glVertex2d(cScreenWidth / 2, cScreenHeight / 2);
- glTexCoord2f(0.0, 1.0);
- glVertex2d(cScreenWidth / -2, cScreenHeight / 2);
- end;
- glEnd();
- SetScale(zoom);
- end
- else
- begin
- // clear scene
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
- // draw left eye in red channel only
- if cStereoMode = smGreenRed then
- glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
- else if cStereoMode = smBlueRed then
- glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
- else if cStereoMode = smCyanRed then
- glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
- else
- glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
- DrawWorldStereo(Lag, rmLeftEye);
- // draw right eye in selected channel(s) only
- if cStereoMode = smRedGreen then
- glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE)
- else if cStereoMode = smRedBlue then
- glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE)
- else if cStereoMode = smRedCyan then
- glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE)
- else
- glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
- DrawWorldStereo(Lag, rmRightEye);
- end
-{$ENDIF}
-end;
-
-procedure ChangeDepth(rm: TRenderMode; d: GLfloat);
-var tmp: LongInt;
-begin
-{$IFNDEF USE_S3D_RENDERING}
- rm:= rm; d:= d; tmp:= tmp; // avoid hint
-{$ELSE}
- d:= d / 5;
- if rm = rmDefault then
- exit
- else if rm = rmLeftEye then
- d:= -d;
- cStereoDepth:= cStereoDepth + d;
- openglTranslProjMatrix(d, 0, 0);
- tmp:= round(d / cScaleFactor * cScreenWidth);
- ViewLeftX := ViewLeftX - tmp;
- ViewRightX:= ViewRightX - tmp;
-{$ENDIF}
-end;
-
-procedure ResetDepth(rm: TRenderMode);
-var tmp: LongInt;
-begin
-{$IFNDEF USE_S3D_RENDERING}
- rm:= rm; tmp:= tmp; // avoid hint
-{$ELSE}
- if rm = rmDefault then
- exit;
- openglTranslProjMatrix(-cStereoDepth, 0, 0);
- tmp:= round(cStereoDepth / cScaleFactor * cScreenWidth);
- ViewLeftX := ViewLeftX + tmp;
- ViewRightX:= ViewRightX + tmp;
- cStereoDepth:= 0;
-{$ENDIF}
+FinishRender();
end;
procedure RenderWorldEdge;
@@ -1291,8 +1163,8 @@
tdx, tdy: Double;
s: shortstring;
offsetX, offsetY, screenBottom: LongInt;
- VertexBuffer: array [0..3] of TVertex2f;
replicateToLeft, replicateToRight, tmp: boolean;
+ a: Byte;
begin
if WorldEdge <> weWrap then
begin
@@ -1723,27 +1595,16 @@
end;
if ScreenFade <> sfNone then
begin
+ r.x:= ViewLeftX;
+ r.y:= ViewTopY;
+ r.w:= ViewWidth;
+ r.h:= ViewHeight;
+
case ScreenFade of
- sfToBlack, sfFromBlack: Tint(0, 0, 0, ScreenFadeValue * 255 div 1000);
- sfToWhite, sfFromWhite: Tint($FF, $FF, $FF, ScreenFadeValue * 255 div 1000);
+ sfToBlack, sfFromBlack: DrawRect(r, 0, 0, 0, ScreenFadeValue * 255 div 1000, true);
+ sfToWhite, sfFromWhite: DrawRect(r, $FF, $FF, $FF, ScreenFadeValue * 255 div 1000, true);
end;
- VertexBuffer[0].X:= -cScreenWidth;
- VertexBuffer[0].Y:= cScreenHeight;
- VertexBuffer[1].X:= -cScreenWidth;
- VertexBuffer[1].Y:= 0;
- VertexBuffer[2].X:= cScreenWidth;
- VertexBuffer[2].Y:= 0;
- VertexBuffer[3].X:= cScreenWidth;
- VertexBuffer[3].Y:= cScreenHeight;
-
- EnableTexture(false);
-
- SetVertexPointer(@VertexBuffer[0], 4);
- glDrawArrays(GL_TRIANGLE_FAN, 0, High(VertexBuffer) - Low(VertexBuffer) + 1);
-
- EnableTexture(true);
- untint;
if not isFirstFrame and ((ScreenFadeValue = 0) or (ScreenFadeValue = sfMax)) then
ScreenFade:= sfNone
end
@@ -1764,15 +1625,11 @@
end;
DrawTexture( -(cScreenWidth shr 1) + 50, 20, recTexture);
+ //a:= Byte(Round(127*(1 + sin(RealTicks*0.007))));
+ a:= Byte(min(255, abs(-255 + ((RealTicks div 2) and 511))));
+
// draw red circle
- glDisable(GL_TEXTURE_2D);
- Tint($FF, $00, $00, Byte(Round(127*(1 + sin(SDL_GetTicks()*0.007)))));
- glBegin(GL_POLYGON);
- for i:= 0 to 20 do
- glVertex2f(-(cScreenWidth shr 1) + 30 + sin(i*2*Pi/20)*10, 35 + cos(i*2*Pi/20)*10);
- glEnd();
- untint;
- glEnable(GL_TEXTURE_2D);
+ DrawCircleFilled(-(cScreenWidth shr 1) + 30, 35, 10, $FF, $00, $00, a);
end;
{$ENDIF}
@@ -1808,7 +1665,7 @@
begin
if not CurrentTeam^.ExtDriven then TargetCursorPoint:= CursorPoint;
with CurrentHedgehog^ do
- if (Gear <> nil) and ((Gear^.State and gstHHChooseTarget) <> 0) then
+ if (Gear <> nil) and ((Gear^.State and gstChooseTarget) <> 0) then
begin
if (CurAmmoType = amNapalm) or (CurAmmoType = amMineStrike) or (((GameFlags and gfMoreWind) <> 0) and ((CurAmmoType = amDrillStrike) or (CurAmmoType = amAirAttack))) then
DrawLine(-3000, topY-300, 7000, topY-300, 3.0, (Team^.Clan^.Color shr 16), (Team^.Clan^.Color shr 8) and $FF, Team^.Clan^.Color and $FF, $FF);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/OfficialChallenges/racer_#13.hwmap Thu Apr 02 21:09:56 2015 +0300
@@ -0,0 +1,1 @@
+AAAEC3icHZJ9aJZVGIevc859znme930etsRKEyllVlJr2AInGDXBBSWVfdHXlFFiq5CWH39U7gNCHVE6WrnSRIq0j01nW7KxaZEtwvFMSzYCl9MWKKnEYrI5puvZ+9/hwH39rt+5T1TjHybMcJjsjXoHJpKr+Dn2KG7KtOCV2oqZrdqZGmGiLX8uE+lJj7XlXdJjTF2S9C5PJgA32ZafcZP4s25d4rvdGXy5X4A77+/AbXHDuFVuA67GGdxp24lfadvx7XZ0eqIiN0Zwzr6WBL/Zvwi+cI8TPOcO4MfdFXy9vw0/wxfidvvZuCJ3AXvK7cJud0uwa+2v2FV2JXajnMZ+I29gr8pNuHLTjzthWvFl5lt8l+khWGCuEbwjjxF0yfcEg/bOXC7hqLyehP/IMGFinyXcY38hLHd3EUbuXYKDro+gzIf4fr8Iv9o/hLuQPp2r8iXYKT8T25iWtsVuJzLkSpFddghZa9cjyy3IYqlHlsoNyFNmN1Jj7ka6dQ821JXYl/Ut2ONqELdEHcQdUI34Bep9/GfqU4J81UmwWV1MTfU9hCW6jrBWnyXsMOnyhkw34X9yb64C8WG9OYm/1qPEdWYN8TLTS3RZbiXaJquJbpatZPfKR2QXyjYyHVJB5gmZT3jN9BEeMZWEjXqccMt0xoc6Q9ipmgjHVTGZFfxJ5hC7yc5jA9km1hDlUUVUx06i8wwQ368WElerD4j3q+vTLhtzQsR7dHES1+uviFeYPKJ/zfNE1aaWyJm3U5R5lGypniQb6QYyU3oO2blqP9kKtZzsMaWIFvM3UQsjxLPU7cSVqpr4Y3UpR0YWyWAi8+2TmDH7E+aQK8A846rQF90+9Cb3A+q660K95z5BFbgX4YQLoMF+DutsEbwiHVAry6DdDKAwb6EqzH2ok8ajy9Lfro8YwRSaIswOsx5zxiTITClBiqQlZ4DJV8cSPaZL0N/pJvQjuh/Vr4dRL+kfUaF+Ewa0g1Nqe5qh5qGepg/Vw5fopTSj9zGMHlEPTqPacjxMKFcSPWJfRTfb3tQlFVcn3SxUuR1DKdsMvbYUfpbjcFleQD0ggmpJe+gC8we6QUL0uXTTxsvvOR6+0Jcl0SZfhjpKaxLOoJX/Ac8c7Ww=
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/OfficialChallenges/racer_#14.hwmap Thu Apr 02 21:09:56 2015 +0300
@@ -0,0 +1,1 @@
+AAAFlnicHZR3bNdlEMY/771371FLixoxKEKEQAgGwzA1SMJ0D6ZARY1SLTEgKEVGGOKIDGUjEJkBIYKADFFQ2RISLFVcjQXRGnBQLEJECUgUv/398+RyefO+994ztEgLsUt+FdI35JH/itxPwa+2g7yquIUGo9M89Lj0hTKWbKPMW9Ngdw5YkushN0rJNrnRxlJ4XQ6kJNcjdoy1ywtaxFr8F5Uq/1lb4if0PvxHHYYf1Vn4N7oZP6xf4fv1PL7DrsPXWxG+3Abgs20MPtkW4sNtGz7IsnN321m8XcrHb0itcEk9SDXpcdKRNIb0QZpFWpzWkCalT0hPpCOkbukk6eZ0gYQ7Vu2NsD3eClvmRdh4744N9J5YBy/GCv1J9LQ/gx70EegqL0Mn+Ri02Mei7X0cWj+r4m8+mvipjyQu9+HE8T6EOMCfILb3AcQCfwA57V2RQ94BecdbIK95Q6TUFbkr/Ym0SNVISocJNWk7oSKtJGxJ0wmL0kjCpFRMKE2dCQ+l5oTbUyI0sxpCgVXAP/Ye1NgcOGrPQ7n1ht3WFrZaIazVWlih5bBI18FcnQoztBSmaXeYok0ziJdhaqyC1+N2mBnfhPmxDBbHXrAqtoENMR+2Sw18Kp/Bl5JdVS3T4ZwMJYg8SGgotxJay9WELuE8YUCoIowIuwlTw2rCyvAGYWcYRfguPEb4K9yDXBvaI+1CE6RPyEdGcgmZRw2yjWNIJZ8jF9lHbMyHxK5sJD7NauI0lhE3soj4FfOJF5iDNmYW2q0OhjAbfYNMp5tZgH6baVIvshK7iXVYN7ZipezCpnEIe5dK7DAnsVrOkwpCJN0aGpIeCq1Jw0Jn0rTQj7QmDCXtDS+TjobFpPPhfTw/VODNwym8oyjeU5rhJdIFf0Eex1+TifgCWYq/LTvxzXIc3yn/4gdjU/yL2A2vjE/h38cp+E9xLX4ylmfWiGdy/shm0cIfUn3tQKqnA0lBx2MXdVk2qe7BftBqrEL/wz62Jtga64TNzExio+w5rNimYJ1sKdbYNqGXbQ96zD5HP7IqdKGdQEfZKbRX9m29xc6gyX4nnrDfiHvtJ+Iy+444IdtMHGS7iJ1sQ8aCvYVcsVeRkzYMKbe+GVGZOWWFNUJmaEbeBD2KDNePkBJdhDyio5F+2gfppW2QnloP6R1/Rh6O+5FH44rMAXEiUhYHIS/Fjhn78QZkjVxGPpEfka/lAFIr64kubxJbymTiXfIssVQeI06RnsS10oNYLncQ/5Db0GukHVokbdFB0h59UW5HV0pn9IDci/4i/bEkT2MtZTR2ZyZgGywrsImyHVsgR7D18ju2N+ZhX8csFE7E+7BzcSh2Oc4gxbiJlJfpLtWPf+c4yl7LiKqDuqp/uRbVram5Sjl7Mxp9uHQvz1uVKTGvii2VeVU+mAbjcsCWXI+rOqTqygbXB8ul7dm6tD2bf0SWVhTMtS5cOVWPff8D7Vs1fw==
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/OfficialChallenges/racer_#15.hwmap Thu Apr 02 21:09:56 2015 +0300
@@ -0,0 +1,1 @@
+AAACYnicFc9NSJRRFAbgc3/PfP8lqGGLIlpIJVktlHAgXaSRLTLMQIQGwwhJF8UIUs7umHExvCn5CcWgiSFo0SBGUrjJjSAIFZWgQdmiggqjdd9sHs7qfc/rZ2UWwnasg6hS1IMzy7ZBn9BbAEfwEXAu6kBl2FNgGTZbcMpFZSEo5+0F+VLfKMiIbczrMbk2H7RpM8+kXs3zEdlR5BLoa6w77/TqK3nvuuzPh1/lmbxXxarzsCCHYr6i0zEe1Cux14k1RY4nHyRX0CLvx3Jc/IxTa6wpxlL+KQ4n4FsctfLGmLWIVstfiArL38GCVS3wzKppPmJTOXXYukdVifWW9CHr1fAd6+dg0uIyzFj+CmOry3DUph7iPevuxT7r7sc+iPZp3zKr7hjxRlUniE4jf8sfJnVA3zb4Tx4z6peIDS6xdeNe5OkiteB8hxnjZOSkcR/rdJFa8HNi0/hZ1WXCniQvNKLC+DmcMmIR75Ju1OeJN6sBYnk5TJAVVQQd0E+8DK4S32LTxFf5ZRLPYZzkEAyR/CAYiY8yR3BBPSD2Gp8UmQKOqEmcTVDncIpwFy4TliY7cRNHCf+oDCGpbUoNq8/kDKguwlviLekGUUp6B3LknCyyzrrJbU96vXqeJl+J0+ROiD5yG+Qe8rS6Sd4X1UthMy5SsJGkBF1ijsLdRQa5obCH/aXgPSsh/xTLUNCWjInmRCdFpJooWtZjFE7oQfoP92i1IA==
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/OfficialChallenges/racer_#16.hwmap Thu Apr 02 21:09:56 2015 +0300
@@ -0,0 +1,1 @@
+AAAAaXicY3RgdGBgWcB2gIGDAcjiTgCy+A6AxVhlgFwgwcHA9ISBgYGRYb8AkLAXYGBmsGeAEKwgLphgB3GBBCPQvD8g82pA5tWAzKsBmVcDAB2iEO4=
\ No newline at end of file
--- a/project_files/hwc/rtl/system.c Mon Feb 16 22:33:15 2015 +0300
+++ b/project_files/hwc/rtl/system.c Thu Apr 02 21:09:56 2015 +0300
@@ -73,6 +73,46 @@
return result;
}
+void fpcrtl_insert__vars(string255 *src, string255 *dst, SizeInt index) {
+ int num_insert;
+ int num_shift;
+ int num_preshift;
+
+ // nothing to do if empty string is inserted or index invalid
+ if ((src->len == 0) || (index < 1) || (index > 255)) {
+ return;
+ }
+
+ num_insert = src->len;
+ // number of chars from start of destination string to end of insertion
+ num_preshift = index - 1 + num_insert;
+
+ // don't overflow on insert
+ if (num_preshift > 255) {
+ num_insert = 255 - (index - 1);
+ num_shift = 0;
+ }
+ // shift trailing chars
+ else {
+ // number of bytes to be shifted
+ num_shift = dst->len - (index - 1);
+
+ if (num_shift > 0) {
+ // don't overflow when shifting
+ if (num_shift + num_preshift > 255)
+ num_shift = 255 - num_preshift;
+
+ // time to move some bytes!
+ memmove(dst->str + num_preshift, dst->str + index - 1, num_shift);
+ }
+ }
+
+ // actual byte insertion
+ memmove(dst->str + index - 1, src->str, num_insert);
+ // store new length
+ dst->len = num_shift + num_preshift;
+}
+
void __attribute__((overloadable)) fpcrtl_delete__vars(string255 *s, SizeInt index, SizeInt count) {
// number of chars to be move
int num_move;
@@ -298,7 +338,7 @@
LongInt fpcrtl_random(LongInt l) {
// random(0) is undefined in docs but effectively returns 0 in free pascal
if (l == 0) {
- printf("WARNING: random(0) called!");
+ printf("WARNING: random(0) called!\n");
return 0;
}
return (LongInt) (rand() / (double) RAND_MAX * l);
--- a/project_files/hwc/rtl/system.h Mon Feb 16 22:33:15 2015 +0300
+++ b/project_files/hwc/rtl/system.h Thu Apr 02 21:09:56 2015 +0300
@@ -26,6 +26,13 @@
astring fpcrtl_copyA(astring s, Integer Index, Integer Count);
/*
+ * Insert a shortstring in another at a specified index
+ */
+void fpcrtl_insert__vars(string255 *src, string255 *dst, SizeInt index);
+#define fpcrtl_insert(src, dst, index) fpcrtl_insert__vars(&(src), &(dst), index);
+#define fpcrtl_Insert fpcrtl_insert
+
+/*
* Delete removes Count characters from string S, starting at position Index.
* All characters after the deleted characters are shifted Count positions to the left,
* and the length of the string is adjusted.
@@ -33,6 +40,7 @@
#define fpcrtl_delete(s, index, count) fpcrtl_delete__vars(&(s), index, count)
void __attribute__((overloadable)) fpcrtl_delete__vars(string255 *s, SizeInt index, SizeInt count);
void __attribute__((overloadable)) fpcrtl_delete__vars(astring *s, SizeInt index, SizeInt count);
+#define fpcrtl_Delete fpcrtl_delete
string255 fpcrtl_floatToStr(double n);
--- a/qmlFrontend/CMakeLists.txt Mon Feb 16 22:33:15 2015 +0300
+++ b/qmlFrontend/CMakeLists.txt Thu Apr 02 21:09:56 2015 +0300
@@ -9,6 +9,8 @@
find_package(Qt5 COMPONENTS Core Qml Quick Gui)
+qt5_add_resources(qresources qmlFrontend.qrc)
+
add_executable(hedgewars WIN32
main
hwengine
@@ -16,6 +18,7 @@
themeiconprovider
qtquick2applicationviewer/qtquick2applicationviewer
flib.h
+ ${qresources}
)
include_directories(${OPENGL_INCLUDE_DIR})
--- a/qmlFrontend/main.cpp Mon Feb 16 22:33:15 2015 +0300
+++ b/qmlFrontend/main.cpp Thu Apr 02 21:09:56 2015 +0300
@@ -13,12 +13,14 @@
HWEngine::exposeToQML();
+ Q_INIT_RESOURCE(qmlFrontend);
+
QtQuick2ApplicationViewer viewer;
viewer.engine()->addImageProvider(QLatin1String("preview"), new PreviewImageProvider());
viewer.engine()->addImageProvider(QLatin1String("theme"), new ThemeIconProvider());
- viewer.setMainQmlFile(QStringLiteral("qml/qmlFrontend/main.qml"));
+ viewer.setSource(QUrl("qrc:/qml/qmlFrontend/main.qml"));
viewer.showExpanded();
return app.exec();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/qmlFrontend/qmlFrontend.qrc Thu Apr 02 21:09:56 2015 +0300
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/qmlFrontend/First.qml</file>
+ <file>qml/qmlFrontend/GameConfig.qml</file>
+ <file>qml/qmlFrontend/HWButton.qml</file>
+ <file>qml/qmlFrontend/HWComboBox.qml</file>
+ <file>qml/qmlFrontend/LocalGame.qml</file>
+ <file>qml/qmlFrontend/main.qml</file>
+ </qresource>
+</RCC>
--- a/share/hedgewars/Data/Maps/ClimbHome/map.lua Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Maps/ClimbHome/map.lua Thu Apr 02 21:09:56 2015 +0300
@@ -43,6 +43,10 @@
local waterAccel = 0
local delayHeight = 32000
local delayTime = 0
+local airMineX = {}
+local airMineY = {}
+local airMine = {}
+local init = true
function onParameters()
parseParams()
@@ -96,6 +100,8 @@
HH[gear] = 1
totalHedgehogs = totalHedgehogs + 1
teams[GetHogTeamName(gear)] = 1
+ elseif init and GetGearType(gear) == gtAirMine then
+ airMine[gear] = 1
end
end
@@ -144,6 +150,23 @@
end
function onNewTurn()
+ if init then
+ init = false
+ for a,i in pairs(airMine) do
+ x,y = GetGearPosition(a)
+ airMineX[a] = x
+ airMineY[a] = y
+ end
+ else
+ for a,i in pairs(airMine) do
+ local x,y = GetGearPosition(a)
+ if not x or airMineX[a] ~= x or airMineY[a] ~= y then
+ DeleteGear(a)
+ AddGear(airMineX[a],airMineY[a], gtAirMine, gsttmpFlag, 0, 0, 0)
+ end
+ end
+ end
+
ready = false
startTime = GameTime
--disable to preserve highest over multiple turns
@@ -220,7 +243,7 @@
function onGameTick20()
- local x,y;
+ local x,y
if math.random(20) == 1 then AddVisualGear(2012,56,vgtSmoke,0,false) end
if CurrentHedgehog == dummyHog and dummySkip ~= 0 and dummySkip < GameTime then
ParseCommand("/skip")
--- a/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Balanced_Random_Weapon.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
+*
locked
--- a/share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Capture_the_Flag.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/DiagonalMaze.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/DiagonalMaze.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/Gravity.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Gravity.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
+*
Highlander
--- a/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Highlander.lua Thu Apr 02 21:09:56 2015 +0300
@@ -110,7 +110,7 @@
[amRope]=true, [amParachute]=true, [amTeleport]=true, [amJetpack]=true,
[amInvulnerable]=true, [amLaserSight]=true, [amVampiric]=true,
[amLowGravity]=true, [amExtraDamage]=true, [amExtraTime]=true,
- [amLandGun]=true, [amSwitch]=true, [amRubber]=true, [amIceGun]=true,
+ [amLandGun]=true, [amRubber]=true, [amIceGun]=true,
}
local wepArray = {}
--- a/share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Mutant.lua Thu Apr 02 21:09:56 2015 +0300
@@ -21,6 +21,7 @@
HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/Tracker.lua")
+HedgewarsScriptLoad("/Scripts/Params.lua")
--[[
MUTANT SCRIPT
@@ -399,7 +400,7 @@
function setAIHints()
for i = 0, #hhs do
- if mutant == nil or hhs[i] == mutant or CurrentHedgehog == mutant then
+ if mutant == nil or hhs[i] == mutant or CurrentHedgehog == mutant or getGearValue(CurrentHedgehog, "Feeder") then
SetGearAIHints(hhs[i], aihUsual)
else
SetGearAIHints(hhs[i], aihDoesntMatter)
@@ -607,6 +608,11 @@
end
end
+function onParameters()
+ parseParams()
+ winScore = tonumber(params["winscore"]) or winScore
+end
+
--[[
S T A R R I N G
prof - Coding, implementing and evangelism
--- a/share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/No_Jumping.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Racer.lua Thu Apr 02 21:09:56 2015 +0300
@@ -1,772 +1,785 @@
-
-------------------------------------------
--- RACER 0.6
--- map-independant racing script
--- by mikade
------------------------------------------
-
------------------------------------
---0.1: took all the code from crazy racer and scrapped most of it
------------------------------------
-
--- Removed tumbler system
--- Removed extra adds like boosters etc
--- Added experimental waypoint placement system
--- More user feedback
--- Reduced race complexity limit to 5 waypoints
--- stop placement at complexity limit reached and end turn
--- guys dont keep racing after dying
--- invulnerable feasibility
--- reverted time keeping method
--- reduced feedback display time
--- colour-coded addcaptions
--- cleaned up code
--- support for more players properly added
--- tardis fix
--- remove airstrikes
-
--- i think the remainder 0 .456 sec of the tracktime isnt getting reset on newturn
-
--- update feedback
-
--------
--- 0.2
--------
-
--- allow gameflags
--- extend time to 90s
--- remove other air-attack based weps
--- turn off water rise for sd
-
--------
--- 0.3
--------
-
--- prevent WP being placed in land
--- prevent waypoints being placed outside border
-
--------
--- 0.4
--------
-
--- update user feedback
--- add more sounds
-
--------
--- 0.5
--------
-
--- fix ghost disappearing if hog falls in water or somehow dies
--- lengthen ghost tracking interval to improve performance on slower machines
--- increase waypoint limit to 8
--- allow for persistent showmission information
-
--------
--- 0.6
--------
-
--- remove hogs from racing area as per request
-
--------
--- 0.7
--------
-
--- switch to first available weapon if starting race with no weapon selected
-
------------------------------
--- SCRIPT BEGINS
------------------------------
-
-HedgewarsScriptLoad("/Scripts/Locale.lua")
-HedgewarsScriptLoad("/Scripts/OfficialChallenges.lua")
-
-------------------
--- Got Variables?
-------------------
-
-local fMod = 1000000 -- 1
-local roundLimit = 3
-local roundNumber = 0
-local firstClan = 10
-
-local fastX = {}
-local fastY = {}
-local fastCount = 0
-local fastIndex = 0
-local fastColour
-
-local currX = {}
-local currY = {}
-local currCount = 0
-
-local specialPointsX = {}
-local specialPointsY = {}
-local specialPointsCount = 0
-
---------------------------
--- hog and team tracking variales
---------------------------
-
-local numhhs = 0 -- store number of hedgehogs
-local hhs = {} -- store hedgehog gears
-
-local numTeams -- store the number of teams in the game
-local teamNameArr = {} -- store the list of teams
-local teamClan = {}
-local teamSize = {} -- store how many hogs per team
-local teamIndex = {} -- at what point in the hhs{} does each team begin
-
-local teamComment = {}
-local teamScore = {}
-
--------
--- racer vars
---------
-
-local cGear = nil
-
-local bestClan = nil
-local bestTime = nil
-
-local gameBegun = false
-local gameOver = false
-local racerActive = false
-local trackTime = 0
-
-local wpCirc = {}
-local wpX = {}
-local wpY = {}
-local wpCol = {}
-local wpActive = {}
-local wpRad = 450 --75
-local wpCount = 0
-local wpLimit = 8
-
-local usedWeapons = {}
-
-local roundN
-local lastRound
-local RoundHasChanged
-
--------------------
--- general methods
--------------------
-
-function RebuildTeamInfo()
-
-
- -- make a list of individual team names
- for i = 0, (TeamsCount-1) do
- teamNameArr[i] = " " -- = i
- teamSize[i] = 0
- teamIndex[i] = 0
- teamScore[i] = 100000
- end
- numTeams = 0
-
- for i = 0, (numhhs-1) do
-
- z = 0
- unfinished = true
- while(unfinished == true) do
-
- newTeam = true
- tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name
-
- if tempHogTeamName == teamNameArr[z] then
- newTeam = false
- unfinished = false
- end
-
- z = z + 1
-
- if z == TeamsCount then
- unfinished = false
- if newTeam == true then
- teamNameArr[numTeams] = tempHogTeamName
- numTeams = numTeams + 1
- end
- end
-
- end
-
- end
-
- -- find out how many hogs per team, and the index of the first hog in hhs
- for i = 0, (numTeams-1) do
- for z = 0, (numhhs-1) do
- if GetHogTeamName(hhs[z]) == teamNameArr[i] then
- teamClan[i] = GetHogClan(hhs[z])
- if teamSize[i] == 0 then
- teamIndex[i] = z -- should give starting index
- end
- teamSize[i] = teamSize[i] + 1
- --add a pointer so this hog appears at i in hhs
- end
- end
-
- end
-
-end
-
-
------------------
--- RACER METHODS
------------------
-
-function CheckWaypoints()
-
- trackFinished = true
-
- for i = 0, (wpCount-1) do
-
- g1X, g1Y = GetGearPosition(CurrentHedgehog)
- g2X, g2Y = wpX[i], wpY[i]
-
- g1X = g1X - g2X
- g1Y = g1Y - g2Y
- dist = (g1X*g1X) + (g1Y*g1Y)
-
- --if i == 0 then
- -- AddCaption(dist .. "/" .. (wpRad*wpRad) )
- --end
-
- NR = (48/100*wpRad)/2
-
- if dist < (NR*NR) then
- --if dist < (wpRad*wpRad) then
- --AddCaption("howdy")
- wpActive[i] = true
- wpCol[i] = GetClanColor(GetHogClan(CurrentHedgehog)) -- new --GetClanColor(1)
- SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 1, 10, 0, wpRad, 5, wpCol[i])
-
- wpRem = 0
- for k = 0, (wpCount-1) do
- if wpActive[k] == false then
- wpRem = wpRem + 1
- end
- end
-
- AddCaption(loc("Way-Points Remaining") .. ": " .. wpRem,0xffba00ff,capgrpAmmoinfo)
-
- end
-
- if wpActive[i] == false then
- trackFinished = false
- end
-
- end
-
- return(trackFinished)
-
-end
-
-function AdjustScores()
-
- if bestTime == nil then
- bestTime = 100000
- bestClan = 10
- bestTimeComment = "N/A"
- end
-
- newScore = false
-
- -- update this clan's time if the new track is better
- for i = 0, (numTeams-1) do
- if teamClan[i] == GetHogClan(CurrentHedgehog) then
- if trackTime < teamScore[i] then
- teamScore[i] = trackTime
- newScore = true
- else
- newScore = false
- end
- end
- end
-
- --bestTime = 100000
- --bestClan = 10
-
- -- find the best time out of those so far
- for i = 0, (numTeams-1) do
- if teamScore[i] < bestTime then
- bestTime = teamScore[i]
- bestClan = teamClan[i]
- end
- end
-
- if bestTime ~= 100000 then
- bestTimeComment = (bestTime/1000) ..loc("s")
- end
-
- if newScore == true then
- if trackTime == bestTime then -- best time of the race
- ShowMission(loc("RACER"),
- loc("TRACK COMPLETED"),
- loc("NEW RACE RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" ..
- loc("WINNING TIME: ") .. bestTimeComment, 0, 4000)
- PlaySound(sndHomerun)
- else -- best time for the clan
- ShowMission(loc("RACER"),
- loc("TRACK COMPLETED"),
- loc("NEW CLAN RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" ..
- loc("WINNING TIME: ") .. bestTimeComment, 4, 4000)
- end
- else -- not any kind of new score
- ShowMission(loc("RACER"),
- loc("TRACK COMPLETED"),
- loc("TIME: ") .. (trackTime/1000) ..loc("s") .. "|" ..
- loc("WINNING TIME: ") .. bestTimeComment, -amSkip, 4000)
- PlaySound(sndHellish)
- end
-
-
- --------
- --new
- --------
-
- if bestTime == trackTime then
- --AddCaption("wooooooooooooooooooooooooooooo")
-
- fastColour = GetClanColor(GetHogClan(CurrentHedgehog))
-
- for i = 0, (currCount-1) do
- fastX[i] = currX[i]
- fastY[i] = currY[i]
- end
-
- fastCount = currCount
- fastIndex = 0
-
- --currCount = 0 -- is this needed?
-
- else
- currCount = 0
- fastIndex = 0
- end
-
-
-end
-
-function onNewRound()
-
- roundNumber = roundNumber + 1
-
- totalComment = ""
- for i = 0, (TeamsCount-1) do
- if teamNameArr[i] ~= " " then -- teamScore[teamClan[i]]
- teamComment[i] = teamNameArr[i] .. ": " .. (teamScore[i]/1000) .. loc("s|")
- totalComment = totalComment .. teamComment[i]
- elseif teamNameArr[i] == " " then
- teamComment[i] = "|"
- end
- end
-
- ShowMission( loc("RACER"),
- loc("STATUS UPDATE"),
- loc("Rounds Complete: ") .. roundNumber .. "/" .. roundLimit .. "|" .. " " .. "|" ..
- loc("Best Team Times: ") .. "|" .. totalComment, 0, 4000)
-
- -- end game if its at round limit
- if roundNumber >= roundLimit then
- for i = 0, (numhhs-1) do
- if GetHogClan(hhs[i]) ~= bestClan then
- SetEffect(hhs[i], heResurrectable, 0)
- SetHealth(hhs[i],0)
- end
- end
- gameOver = true
- TurnTimeLeft = 1
- end
-
-end
-
-function CheckForNewRound()
-
- -------------
- ------ new
- -------------
-
- --[[turnN = turnN + 1
- if gameBegun == false then
- if turnN == 2 then
- for i = 0, (numhhs-1) do
- if hhs[i] ~= nil then
- SetEffect(hhs[i], heResurrectable, 0)
- SetHealth(hhs[i],0)
- end
- end
- gameOver = true
- TurnTimeLeft = 1
- end
- else
-
-
- end]]
-
- --[[if roundBegun == true then
-
- if RoundHasChanged == true then
- roundN = roundN + 1
- RoundHasChanged = false
- onNewRound()
- end
-
- if lastRound ~= TotalRounds then -- new round, but not really
-
- if RoundHasChanged == false then
- RoundHasChanged = true
- end
-
- end
-
- AddCaption("RoundN:" .. roundN .. "; " .. "TR: " .. TotalRounds)
-
- lastRound = TotalRounds
-
- end]]
-
- ------------
- ----- old
- ------------
-
- if GetHogClan(CurrentHedgehog) == firstClan then
- onNewRound()
- end
-
-end
-
-function DisableTumbler()
- currCount = 0
- fastIndex = 0
- TurnTimeLeft = 0
- racerActive = false -- newadd
-end
-
-function HandleGhost()
-
- -- get the current xy of the racer at this point
- currX[currCount] = GetX(CurrentHedgehog)
- currY[currCount] = GetY(CurrentHedgehog)
- currCount = currCount + 1
-
- -- draw a ping of smoke where the fastest player was at this point
- if (fastCount ~= 0) and (fastIndex < fastCount) then
-
- fastIndex = fastIndex + 1
-
- tempE = AddVisualGear(fastX[fastIndex], fastY[fastIndex], vgtSmoke, 0, false)
- g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
- SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, fastColour )
-
- --AddCaption("fC: " .. fastIndex .. " / " .. fastCount)
-
- else
-
- --AddCaption("excep fC: " .. fastIndex .. " / " .. fastCount)
-
- end
-
-
-
-end
-
-function TryRepositionHogs()
-
- if MapHasBorder() == true then
-
- for i = 0, (numhhs-1) do
- if hhs[i] ~= nil then
- SetGearPosition(hhs[i],GetX(hhs[i]), TopY-10)
- end
- end
-
- end
-
-end
-
-----------------------------------
--- GAME METHODS / EVENT HANDLERS
-----------------------------------
-
-function onGameInit()
- EnableGameFlags(gfInfAttack, gfInvulnerable)
- CaseFreq = 0
- TurnTime = 90000
- WaterRise = 0
-end
-
-
-function onGameStart()
-
- roundN = 0
- lastRound = TotalRounds
- RoundHasChanged = false -- true
-
- for i = 0, (specialPointsCount-1) do
- PlaceWayPoint(specialPointsX[i], specialPointsY[i])
- end
-
- RebuildTeamInfo()
-
- ShowMission (
- loc("RACER"),
- loc("a Hedgewars mini-game"),
-
- loc("Build a track and race.") .. "|" ..
- loc("Round Limit:") .. " " .. roundLimit .. "|" ..
-
- "", 4, 4000
- )
-
- TryRepositionHogs()
-
-end
-
-function PlaceWayPoint(x,y)
- if not racerActive then
- if wpCount == 0 or wpX[wpCount - 1] ~= x or wpY[wpCount - 1] ~= y then
-
- wpX[wpCount] = x
- wpY[wpCount] = y
- wpCol[wpCount] = 0xffffffff
- wpCirc[wpCount] = AddVisualGear(wpX[wpCount],wpY[wpCount],vgtCircle,0,true)
-
- SetVisualGearValues(wpCirc[wpCount], wpX[wpCount], wpY[wpCount], 20, 100, 1, 10, 0, wpRad, 5, wpCol[wpCount])
-
- wpCount = wpCount + 1
-
- AddCaption(loc("Waypoint placed.") .. " " .. loc("Available points remaining: ") .. (wpLimit-wpCount))
- end
- end
-end
-
-function onSpecialPoint(x,y,flag)
- specialPointsX[specialPointsCount] = x
- specialPointsY[specialPointsCount] = y
- specialPointsCount = specialPointsCount + 1
-end
-
-function onNewTurn()
-
- CheckForNewRound()
- TryRepositionHogs()
-
- racerActive = false
-
- trackTime = 0
-
- currCount = 0 -- hopefully this solves problem
- AddAmmo(CurrentHedgehog, amAirAttack, 0)
- gTimer = 0
-
- -- Set the waypoints to unactive on new round
- for i = 0,(wpCount-1) do
- wpActive[i] = false
- wpCol[i] = 0xffffffff
- SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 1, 10, 0, wpRad, 5, wpCol[i])
- end
-
- -- Handle Starting Stage of Game
- if (gameOver == false) and (gameBegun == false) then
- if wpCount >= 3 then
- gameBegun = true
- roundNumber = 0
- firstClan = GetHogClan(CurrentHedgehog)
- ShowMission(loc("RACER"),
- loc("GAME BEGUN!!!"),
- loc("Complete the track as fast as you can!"), 2, 4000)
- else
- ShowMission(loc("RACER"),
- loc("NOT ENOUGH WAYPOINTS"),
- loc("Place more waypoints using the 'Air Attack' weapon."), 2, 4000)
- AddAmmo(CurrentHedgehog, amAirAttack, 4000)
- SetWeapon(amAirAttack)
- end
- end
-
- if gameOver == true then
- gameBegun = false
- racerActive = false -- newadd
- end
-
- AddAmmo(CurrentHedgehog, amTardis, 0)
- AddAmmo(CurrentHedgehog, amDrillStrike, 0)
- AddAmmo(CurrentHedgehog, amMineStrike, 0)
- AddAmmo(CurrentHedgehog, amNapalm, 0)
- AddAmmo(CurrentHedgehog, amPiano, 0)
-
-end
-
-function onGameTick20()
-
- -- airstrike detected, convert this into a potential waypoint spot
- if cGear ~= nil then
- x,y = GetGearPosition(cGear)
- if x > -9000 then
- x,y = GetGearTarget(cGear)
-
-
- if TestRectForObstacle(x-20, y-20, x+20, y+20, true) then
- AddCaption(loc("Please place the way-point in the open, within the map boundaries."))
- PlaySound(sndDenied)
- elseif (y > WaterLine-50) then
- AddCaption(loc("Please place the way-point further from the waterline."))
- PlaySound(sndDenied)
- else
- PlaceWayPoint(x, y)
- if wpCount == wpLimit then
- AddCaption(loc("Race complexity limit reached."))
- DisableTumbler()
- end
- end
- else
- DeleteGear(cGear)
- end
- SetGearPosition(cGear, -10000, 0)
- end
-
-
- -- start the player tumbling with a boom once their turn has actually begun
- if racerActive == false then
-
- if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
-
- -- if the gamehas started put the player in the middle of the first
- --waypoint that was placed
- if gameBegun == true then
- AddCaption(loc("Good to go!"))
- racerActive = true
- trackTime = 0
-
- SetGearPosition(CurrentHedgehog, wpX[0], wpY[0])
- AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
- FollowGear(CurrentHedgehog)
-
- HideMission()
-
- -- don't start empty-handed
- if (GetCurAmmoType() == amNothing) then
- SetNextWeapon()
- end
- else
- -- still in placement mode
- end
-
- end
- end
-
-
- -- has the player started his tumbling spree?
- if (CurrentHedgehog ~= nil) then
-
- --airstrike conversion used to be here
-
- -- if the RACE has started, show tracktimes and keep tabs on waypoints
- if (racerActive == true) and (gameBegun == true) then
-
- --ghost
- if GameTime%40 == 0 then
- HandleGhost()
- end
-
- trackTime = trackTime + 20
-
- if GameTime%100 == 0 then
-
- if trackTime%1000 == 0 then
- AddCaption((trackTime/1000)..'.0',GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
- else
- AddCaption(trackTime/1000,GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
- end
-
- if (CheckWaypoints() == true) then
- AdjustScores()
- DisableTumbler()
- end
-
- end
-
- end
-
- -- if the player has expended his tunbling time, stop him tumbling
- if TurnTimeLeft <= 20 then
- DisableTumbler()
- end
-
- end
-
-end
-
-function onGearResurrect(gear)
-
- AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
-
- if gear == CurrentHedgehog then
- DisableTumbler()
- end
-
-end
-
-function onGearAdd(gear)
-
- if GetGearType(gear) == gtHedgehog then
- hhs[numhhs] = gear
- numhhs = numhhs + 1
- SetEffect(gear, heResurrectable, 1)
- end
-
- if GetGearType(gear) == gtAirAttack then
- cGear = gear
- end
-
-end
-
-function onGearDelete(gear)
-
- if GetGearType(gear) == gtAirAttack then
- cGear = nil
- end
-
-end
-
-function onAttack()
- at = GetCurAmmoType()
-
- usedWeapons[at] = 0
-end
-
-function onAchievementsDeclaration()
- usedWeapons[amSkip] = nil
-
- usedRope = usedWeapons[amRope] ~= nil
- usedPortal = usedWeapons[amPortalGun] ~= nil
- usedSaucer = usedWeapons[amJetpack] ~= nil
-
- usedWeapons[amRope] = nil
- usedWeapons[amPortalGun] = nil
- usedWeapons[amJetpack] = nil
-
- usedOther = next(usedWeapons) ~= nil
-
- if usedOther then -- smth besides skip, rope, portal or saucer used
- raceType = "unknown race"
- elseif usedRope and not usedPortal and not usedSaucer then
- raceType = "rope race"
- elseif not usedRope and usedPortal and not usedSaucer then
- raceType = "portal race"
- elseif not usedRope and not usedPortal and usedSaucer then
- raceType = "saucer race"
- elseif (usedRope or usedPortal or usedSaucer or usedOther) == false then -- no weapons used at all?
- raceType = "no tools race"
- else -- at least two of rope, portal and saucer used
- raceType = "mixed race"
- end
-
- map = detectMap()
-
- for i = 0, (numTeams-1) do
- if teamScore[i] < 100000 then
- DeclareAchievement(raceType, teamNameArr[i], map, teamScore[i])
- end
- end
-end
+
+------------------------------------------
+-- RACER 0.6
+-- map-independant racing script
+-- by mikade
+-----------------------------------------
+
+-----------------------------------
+--0.1: took all the code from crazy racer and scrapped most of it
+-----------------------------------
+
+-- Removed tumbler system
+-- Removed extra adds like boosters etc
+-- Added experimental waypoint placement system
+-- More user feedback
+-- Reduced race complexity limit to 5 waypoints
+-- stop placement at complexity limit reached and end turn
+-- guys dont keep racing after dying
+-- invulnerable feasibility
+-- reverted time keeping method
+-- reduced feedback display time
+-- colour-coded addcaptions
+-- cleaned up code
+-- support for more players properly added
+-- tardis fix
+-- remove airstrikes
+
+-- i think the remainder 0 .456 sec of the tracktime isnt getting reset on newturn
+
+-- update feedback
+
+-------
+-- 0.2
+-------
+
+-- allow gameflags
+-- extend time to 90s
+-- remove other air-attack based weps
+-- turn off water rise for sd
+
+-------
+-- 0.3
+-------
+
+-- prevent WP being placed in land
+-- prevent waypoints being placed outside border
+
+-------
+-- 0.4
+-------
+
+-- update user feedback
+-- add more sounds
+
+-------
+-- 0.5
+-------
+
+-- fix ghost disappearing if hog falls in water or somehow dies
+-- lengthen ghost tracking interval to improve performance on slower machines
+-- increase waypoint limit to 8
+-- allow for persistent showmission information
+
+-------
+-- 0.6
+-------
+
+-- remove hogs from racing area as per request
+
+-------
+-- 0.7
+-------
+
+-- switch to first available weapon if starting race with no weapon selected
+
+-----------------------------
+-- SCRIPT BEGINS
+-----------------------------
+
+HedgewarsScriptLoad("/Scripts/Locale.lua")
+HedgewarsScriptLoad("/Scripts/OfficialChallenges.lua")
+HedgewarsScriptLoad("/Scripts/Params.lua")
+
+------------------
+-- Got Variables?
+------------------
+
+local fMod = 1000000 -- 1
+local roundLimit = 3
+local roundNumber = 0
+local firstClan = 10
+
+local fastX = {}
+local fastY = {}
+local fastCount = 0
+local fastIndex = 0
+local fastColour
+
+local currX = {}
+local currY = {}
+local currCount = 0
+
+local specialPointsX = {}
+local specialPointsY = {}
+local specialPointsCount = 0
+
+local TeamRope = false
+
+--------------------------
+-- hog and team tracking variales
+--------------------------
+
+local numhhs = 0 -- store number of hedgehogs
+local hhs = {} -- store hedgehog gears
+
+local numTeams -- store the number of teams in the game
+local teamNameArr = {} -- store the list of teams
+local teamClan = {}
+local teamSize = {} -- store how many hogs per team
+local teamIndex = {} -- at what point in the hhs{} does each team begin
+
+local teamComment = {}
+local teamScore = {}
+
+-------
+-- racer vars
+--------
+
+local cGear = nil
+
+local bestClan = nil
+local bestTime = nil
+
+local gameBegun = false
+local gameOver = false
+local racerActive = false
+local trackTime = 0
+
+local wpCirc = {}
+local wpX = {}
+local wpY = {}
+local wpCol = {}
+local wpActive = {}
+local wpRad = 450 --75
+local wpCount = 0
+local wpLimit = 8
+
+local usedWeapons = {}
+
+local roundN
+local lastRound
+local RoundHasChanged
+
+-------------------
+-- general methods
+-------------------
+
+function onParameters()
+ parseParams()
+ if params["teamrope"] ~= nil then
+ TeamRope = true
+ end
+end
+
+function RebuildTeamInfo()
+
+
+ -- make a list of individual team names
+ for i = 0, (TeamsCount-1) do
+ teamNameArr[i] = " " -- = i
+ teamSize[i] = 0
+ teamIndex[i] = 0
+ teamScore[i] = 100000
+ end
+ numTeams = 0
+
+ for i = 0, (numhhs-1) do
+
+ z = 0
+ unfinished = true
+ while(unfinished == true) do
+
+ newTeam = true
+ tempHogTeamName = GetHogTeamName(hhs[i]) -- this is the new name
+
+ if tempHogTeamName == teamNameArr[z] then
+ newTeam = false
+ unfinished = false
+ end
+
+ z = z + 1
+
+ if z == TeamsCount then
+ unfinished = false
+ if newTeam == true then
+ teamNameArr[numTeams] = tempHogTeamName
+ numTeams = numTeams + 1
+ end
+ end
+
+ end
+
+ end
+
+ -- find out how many hogs per team, and the index of the first hog in hhs
+ for i = 0, (numTeams-1) do
+ for z = 0, (numhhs-1) do
+ if GetHogTeamName(hhs[z]) == teamNameArr[i] then
+ teamClan[i] = GetHogClan(hhs[z])
+ if teamSize[i] == 0 then
+ teamIndex[i] = z -- should give starting index
+ end
+ teamSize[i] = teamSize[i] + 1
+ --add a pointer so this hog appears at i in hhs
+ end
+ end
+
+ end
+
+end
+
+
+-----------------
+-- RACER METHODS
+-----------------
+
+function CheckWaypoints()
+
+ trackFinished = true
+
+ for i = 0, (wpCount-1) do
+
+ g1X, g1Y = GetGearPosition(CurrentHedgehog)
+ g2X, g2Y = wpX[i], wpY[i]
+
+ g1X = g1X - g2X
+ g1Y = g1Y - g2Y
+ dist = (g1X*g1X) + (g1Y*g1Y)
+
+ --if i == 0 then
+ -- AddCaption(dist .. "/" .. (wpRad*wpRad) )
+ --end
+
+ NR = (48/100*wpRad)/2
+
+ if dist < (NR*NR) then
+ --if dist < (wpRad*wpRad) then
+ --AddCaption("howdy")
+ wpActive[i] = true
+ wpCol[i] = GetClanColor(GetHogClan(CurrentHedgehog)) -- new --GetClanColor(1)
+ SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 1, 10, 0, wpRad, 5, wpCol[i])
+
+ wpRem = 0
+ for k = 0, (wpCount-1) do
+ if wpActive[k] == false then
+ wpRem = wpRem + 1
+ end
+ end
+
+ AddCaption(loc("Way-Points Remaining") .. ": " .. wpRem,0xffba00ff,capgrpAmmoinfo)
+
+ end
+
+ if wpActive[i] == false then
+ trackFinished = false
+ end
+
+ end
+
+ return(trackFinished)
+
+end
+
+function AdjustScores()
+
+ if bestTime == nil then
+ bestTime = 100000
+ bestClan = 10
+ bestTimeComment = "N/A"
+ end
+
+ newScore = false
+
+ -- update this clan's time if the new track is better
+ for i = 0, (numTeams-1) do
+ if teamClan[i] == GetHogClan(CurrentHedgehog) then
+ if trackTime < teamScore[i] then
+ teamScore[i] = trackTime
+ newScore = true
+ else
+ newScore = false
+ end
+ end
+ end
+
+ --bestTime = 100000
+ --bestClan = 10
+
+ -- find the best time out of those so far
+ for i = 0, (numTeams-1) do
+ if teamScore[i] < bestTime then
+ bestTime = teamScore[i]
+ bestClan = teamClan[i]
+ end
+ end
+
+ if bestTime ~= 100000 then
+ bestTimeComment = (bestTime/1000) ..loc("s")
+ end
+
+ if newScore == true then
+ if trackTime == bestTime then -- best time of the race
+ ShowMission(loc("RACER"),
+ loc("TRACK COMPLETED"),
+ loc("NEW RACE RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" ..
+ loc("WINNING TIME: ") .. bestTimeComment, 0, 4000)
+ PlaySound(sndHomerun)
+ else -- best time for the clan
+ ShowMission(loc("RACER"),
+ loc("TRACK COMPLETED"),
+ loc("NEW CLAN RECORD: ") .. (trackTime/1000) ..loc("s") .. "|" ..
+ loc("WINNING TIME: ") .. bestTimeComment, 4, 4000)
+ end
+ else -- not any kind of new score
+ ShowMission(loc("RACER"),
+ loc("TRACK COMPLETED"),
+ loc("TIME: ") .. (trackTime/1000) ..loc("s") .. "|" ..
+ loc("WINNING TIME: ") .. bestTimeComment, -amSkip, 4000)
+ PlaySound(sndHellish)
+ end
+
+
+ --------
+ --new
+ --------
+
+ if bestTime == trackTime then
+ --AddCaption("wooooooooooooooooooooooooooooo")
+
+ fastColour = GetClanColor(GetHogClan(CurrentHedgehog))
+
+ for i = 0, (currCount-1) do
+ fastX[i] = currX[i]
+ fastY[i] = currY[i]
+ end
+
+ fastCount = currCount
+ fastIndex = 0
+
+ --currCount = 0 -- is this needed?
+
+ else
+ currCount = 0
+ fastIndex = 0
+ end
+
+
+end
+
+function onNewRound()
+
+ roundNumber = roundNumber + 1
+
+ totalComment = ""
+ for i = 0, (TeamsCount-1) do
+ if teamNameArr[i] ~= " " then -- teamScore[teamClan[i]]
+ teamComment[i] = teamNameArr[i] .. ": " .. (teamScore[i]/1000) .. loc("s|")
+ totalComment = totalComment .. teamComment[i]
+ elseif teamNameArr[i] == " " then
+ teamComment[i] = "|"
+ end
+ end
+
+ ShowMission( loc("RACER"),
+ loc("STATUS UPDATE"),
+ loc("Rounds Complete: ") .. roundNumber .. "/" .. roundLimit .. "|" .. " " .. "|" ..
+ loc("Best Team Times: ") .. "|" .. totalComment, 0, 4000)
+
+ -- end game if its at round limit
+ if roundNumber >= roundLimit then
+ for i = 0, (numhhs-1) do
+ if GetHogClan(hhs[i]) ~= bestClan then
+ SetEffect(hhs[i], heResurrectable, 0)
+ SetHealth(hhs[i],0)
+ end
+ end
+ gameOver = true
+ TurnTimeLeft = 1
+ end
+
+end
+
+function CheckForNewRound()
+
+ -------------
+ ------ new
+ -------------
+
+ --[[turnN = turnN + 1
+ if gameBegun == false then
+ if turnN == 2 then
+ for i = 0, (numhhs-1) do
+ if hhs[i] ~= nil then
+ SetEffect(hhs[i], heResurrectable, 0)
+ SetHealth(hhs[i],0)
+ end
+ end
+ gameOver = true
+ TurnTimeLeft = 1
+ end
+ else
+
+
+ end]]
+
+ --[[if roundBegun == true then
+
+ if RoundHasChanged == true then
+ roundN = roundN + 1
+ RoundHasChanged = false
+ onNewRound()
+ end
+
+ if lastRound ~= TotalRounds then -- new round, but not really
+
+ if RoundHasChanged == false then
+ RoundHasChanged = true
+ end
+
+ end
+
+ AddCaption("RoundN:" .. roundN .. "; " .. "TR: " .. TotalRounds)
+
+ lastRound = TotalRounds
+
+ end]]
+
+ ------------
+ ----- old
+ ------------
+
+ if GetHogClan(CurrentHedgehog) == firstClan then
+ onNewRound()
+ end
+
+end
+
+function DisableTumbler()
+ currCount = 0
+ fastIndex = 0
+ TurnTimeLeft = 0
+ racerActive = false -- newadd
+end
+
+function HandleGhost()
+
+ -- get the current xy of the racer at this point
+ currX[currCount] = GetX(CurrentHedgehog)
+ currY[currCount] = GetY(CurrentHedgehog)
+ currCount = currCount + 1
+
+ -- draw a ping of smoke where the fastest player was at this point
+ if (fastCount ~= 0) and (fastIndex < fastCount) then
+
+ fastIndex = fastIndex + 1
+
+ tempE = AddVisualGear(fastX[fastIndex], fastY[fastIndex], vgtSmoke, 0, false)
+ g1, g2, g3, g4, g5, g6, g7, g8, g9, g10 = GetVisualGearValues(tempE)
+ SetVisualGearValues(tempE, g1, g2, g3, g4, g5, g6, g7, g8, g9, fastColour )
+
+ --AddCaption("fC: " .. fastIndex .. " / " .. fastCount)
+
+ else
+
+ --AddCaption("excep fC: " .. fastIndex .. " / " .. fastCount)
+
+ end
+
+
+
+end
+
+function TryRepositionHogs()
+
+ if MapHasBorder() == true then
+
+ for i = 0, (numhhs-1) do
+ if hhs[i] ~= nil then
+ SetGearPosition(hhs[i],GetX(hhs[i]), TopY-10)
+ end
+ end
+
+ end
+
+end
+
+----------------------------------
+-- GAME METHODS / EVENT HANDLERS
+----------------------------------
+
+function onGameInit()
+ EnableGameFlags(gfInfAttack, gfInvulnerable)
+ CaseFreq = 0
+ TurnTime = 90000
+ WaterRise = 0
+end
+
+
+function onGameStart()
+
+ roundN = 0
+ lastRound = TotalRounds
+ RoundHasChanged = false -- true
+
+ for i = 0, (specialPointsCount-1) do
+ PlaceWayPoint(specialPointsX[i], specialPointsY[i])
+ end
+
+ RebuildTeamInfo()
+
+ ShowMission (
+ loc("RACER"),
+ loc("a Hedgewars mini-game"),
+
+ loc("Build a track and race.") .. "|" ..
+ loc("Round Limit:") .. " " .. roundLimit .. "|" ..
+
+ "", 4, 4000
+ )
+
+ TryRepositionHogs()
+
+end
+
+function PlaceWayPoint(x,y)
+ if not racerActive then
+ if wpCount == 0 or wpX[wpCount - 1] ~= x or wpY[wpCount - 1] ~= y then
+
+ wpX[wpCount] = x
+ wpY[wpCount] = y
+ wpCol[wpCount] = 0xffffffff
+ wpCirc[wpCount] = AddVisualGear(wpX[wpCount],wpY[wpCount],vgtCircle,0,true)
+
+ SetVisualGearValues(wpCirc[wpCount], wpX[wpCount], wpY[wpCount], 20, 100, 1, 10, 0, wpRad, 5, wpCol[wpCount])
+
+ wpCount = wpCount + 1
+
+ AddCaption(loc("Waypoint placed.") .. " " .. loc("Available points remaining: ") .. (wpLimit-wpCount))
+ end
+ end
+end
+
+function onSpecialPoint(x,y,flag)
+ specialPointsX[specialPointsCount] = x
+ specialPointsY[specialPointsCount] = y
+ specialPointsCount = specialPointsCount + 1
+end
+
+function onNewTurn()
+
+ CheckForNewRound()
+ TryRepositionHogs()
+
+ racerActive = false
+
+ trackTime = 0
+
+ currCount = 0 -- hopefully this solves problem
+ AddAmmo(CurrentHedgehog, amAirAttack, 0)
+ gTimer = 0
+
+ -- Set the waypoints to unactive on new round
+ for i = 0,(wpCount-1) do
+ wpActive[i] = false
+ wpCol[i] = 0xffffffff
+ SetVisualGearValues(wpCirc[i], wpX[i], wpY[i], 20, 100, 1, 10, 0, wpRad, 5, wpCol[i])
+ end
+
+ -- Handle Starting Stage of Game
+ if (gameOver == false) and (gameBegun == false) then
+ if wpCount >= 3 then
+ gameBegun = true
+ roundNumber = 0
+ firstClan = GetHogClan(CurrentHedgehog)
+ ShowMission(loc("RACER"),
+ loc("GAME BEGUN!!!"),
+ loc("Complete the track as fast as you can!"), 2, 4000)
+ else
+ ShowMission(loc("RACER"),
+ loc("NOT ENOUGH WAYPOINTS"),
+ loc("Place more waypoints using the 'Air Attack' weapon."), 2, 4000)
+ AddAmmo(CurrentHedgehog, amAirAttack, 4000)
+ SetWeapon(amAirAttack)
+ end
+ end
+
+ if gameOver == true then
+ gameBegun = false
+ racerActive = false -- newadd
+ end
+
+ AddAmmo(CurrentHedgehog, amTardis, 0)
+ AddAmmo(CurrentHedgehog, amDrillStrike, 0)
+ AddAmmo(CurrentHedgehog, amMineStrike, 0)
+ AddAmmo(CurrentHedgehog, amNapalm, 0)
+ AddAmmo(CurrentHedgehog, amPiano, 0)
+
+end
+
+function onGameTick20()
+
+ -- airstrike detected, convert this into a potential waypoint spot
+ if cGear ~= nil then
+ x,y = GetGearPosition(cGear)
+ if x > -9000 then
+ x,y = GetGearTarget(cGear)
+
+
+ if TestRectForObstacle(x-20, y-20, x+20, y+20, true) then
+ AddCaption(loc("Please place the way-point in the open, within the map boundaries."))
+ PlaySound(sndDenied)
+ elseif (y > WaterLine-50) then
+ AddCaption(loc("Please place the way-point further from the waterline."))
+ PlaySound(sndDenied)
+ else
+ PlaceWayPoint(x, y)
+ if wpCount == wpLimit then
+ AddCaption(loc("Race complexity limit reached."))
+ DisableTumbler()
+ end
+ end
+ else
+ DeleteGear(cGear)
+ end
+ SetGearPosition(cGear, -10000, 0)
+ end
+
+
+ -- start the player tumbling with a boom once their turn has actually begun
+ if racerActive == false then
+
+ if (TurnTimeLeft > 0) and (TurnTimeLeft ~= TurnTime) then
+
+ -- if the gamehas started put the player in the middle of the first
+ --waypoint that was placed
+ if gameBegun == true then
+ AddCaption(loc("Good to go!"))
+ racerActive = true
+ trackTime = 0
+
+ SetGearPosition(CurrentHedgehog, wpX[0], wpY[0])
+ AddGear(GetX(CurrentHedgehog), GetY(CurrentHedgehog), gtGrenade, 0, 0, 0, 1)
+ FollowGear(CurrentHedgehog)
+
+ HideMission()
+
+ -- don't start empty-handed
+ if (GetCurAmmoType() == amNothing) then
+ SetNextWeapon()
+ end
+ else
+ -- still in placement mode
+ end
+
+ end
+ end
+
+
+ -- has the player started his tumbling spree?
+ if (CurrentHedgehog ~= nil) then
+
+ --airstrike conversion used to be here
+
+ -- if the RACE has started, show tracktimes and keep tabs on waypoints
+ if (racerActive == true) and (gameBegun == true) then
+
+ --ghost
+ if GameTime%40 == 0 then
+ HandleGhost()
+ end
+
+ trackTime = trackTime + 20
+
+ if GameTime%100 == 0 then
+
+ if trackTime%1000 == 0 then
+ AddCaption((trackTime/1000)..'.0',GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+ else
+ AddCaption(trackTime/1000,GetClanColor(GetHogClan(CurrentHedgehog)),capgrpMessage2)
+ end
+
+ if (CheckWaypoints() == true) then
+ AdjustScores()
+ DisableTumbler()
+ end
+
+ end
+
+ end
+
+ -- if the player has expended his tunbling time, stop him tumbling
+ if TurnTimeLeft <= 20 then
+ DisableTumbler()
+ end
+
+ end
+
+end
+
+function onGearResurrect(gear)
+
+ AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false)
+
+ if gear == CurrentHedgehog then
+ DisableTumbler()
+ end
+
+end
+
+function onGearAdd(gear)
+
+ if GetGearType(gear) == gtHedgehog then
+ hhs[numhhs] = gear
+ numhhs = numhhs + 1
+ SetEffect(gear, heResurrectable, 1)
+ elseif GetGearType(gear) == gtAirAttack then
+ cGear = gear
+ elseif GetGearType(gear) == gtRope and TeamRope then
+ SetTag(gear,1)
+ SetGearValues(gear,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,GetClanColor(GetHogClan(CurrentHedgehog)))
+ elseif GetGearType(gear) == gtAirMine then
+ DeleteGear(gear)
+ end
+end
+
+function onGearDelete(gear)
+
+ if GetGearType(gear) == gtAirAttack then
+ cGear = nil
+ end
+
+end
+
+function onAttack()
+ at = GetCurAmmoType()
+
+ usedWeapons[at] = 0
+end
+
+function onAchievementsDeclaration()
+ usedWeapons[amSkip] = nil
+
+ usedRope = usedWeapons[amRope] ~= nil
+ usedPortal = usedWeapons[amPortalGun] ~= nil
+ usedSaucer = usedWeapons[amJetpack] ~= nil
+
+ usedWeapons[amNothing] = nil
+ usedWeapons[amRope] = nil
+ usedWeapons[amPortalGun] = nil
+ usedWeapons[amJetpack] = nil
+
+ usedOther = next(usedWeapons) ~= nil
+
+ if usedOther then -- smth besides nothing, skip, rope, portal or saucer used
+ raceType = "unknown race"
+ elseif usedRope and not usedPortal and not usedSaucer then
+ raceType = "rope race"
+ elseif not usedRope and usedPortal and not usedSaucer then
+ raceType = "portal race"
+ elseif not usedRope and not usedPortal and usedSaucer then
+ raceType = "saucer race"
+ elseif (usedRope or usedPortal or usedSaucer or usedOther) == false then -- no weapons used at all?
+ raceType = "no tools race"
+ else -- at least two of rope, portal and saucer used
+ raceType = "mixed race"
+ end
+
+ map = detectMap()
+
+ for i = 0, (numTeams-1) do
+ if teamScore[i] < 100000 then
+ DeclareAchievement(raceType, teamNameArr[i], map, teamScore[i])
+ end
+ end
+end
--- a/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Random_Weapon.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
+*
locked
--- a/share/hedgewars/Data/Scripts/Multiplayer/ShoppaMap.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/ShoppaMap.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Space_Invasion.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/The_Specialists.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+locked
--- a/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Tumbler.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/Multiplayer/Tunnels.cfg Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/Multiplayer/Tunnels.cfg Thu Apr 02 21:09:56 2015 +0300
@@ -1,2 +1,2 @@
-Default
-Default
+*
+*
--- a/share/hedgewars/Data/Scripts/OfficialChallenges.lua Mon Feb 16 22:33:15 2015 +0300
+++ b/share/hedgewars/Data/Scripts/OfficialChallenges.lua Thu Apr 02 21:09:56 2015 +0300
@@ -20,6 +20,12 @@
return("Racer Challenge #11")
elseif LandDigest == "M706743197Scripts/Multiplayer/Racer.lua" then
return("Racer Challenge #12")
+ elseif LandDigest == "M157242054Scripts/Multiplayer/Racer.lua" then
+ return("Racer Challenge #13")
+ elseif LandDigest == "M-1585582638Scripts/Multiplayer/Racer.lua" then
+ return("Racer Challenge #14")
+ elseif LandDigest == "M-528106034Scripts/Multiplayer/Racer.lua" then
+ return("Racer Challenge #16")
end
-- challenges without border
elseif LandDigest == "M-134869715Scripts/Multiplayer/Racer.lua" then
@@ -28,6 +34,8 @@
return("Racer Challenge #5")
elseif LandDigest == "M479034891Scripts/Multiplayer/Racer.lua" then
return("Racer Challenge #6")
+ elseif LandDigest == "M256715557Scripts/Multiplayer/Racer.lua" then
+ return("Racer Challenge #15")
end
end
end
--- a/tools/hwmap.hs Mon Feb 16 22:33:15 2015 +0300
+++ b/tools/hwmap.hs Thu Apr 02 21:09:56 2015 +0300
@@ -52,7 +52,7 @@
mapM_ putWord8 $ BW.unpack $ BL.toStrict $ Z.compress b
mapString :: B.ByteString
-mapString = B.pack . Base64.encode . BW.unpack . BL.toStrict . compressWithLength . BL.drop 8 . encode $ drawnMap04
+mapString = B.pack . Base64.encode . BW.unpack . BL.toStrict . compressWithLength . BL.drop 8 . encode $ drawnMap05
main = B.writeFile "out.hwmap" mapString
@@ -152,3 +152,13 @@
]
l = Line Solid 0
fm = flip' . mirror
+
+drawnMap05 = sp ++ fullFill ++ lW
+ where
+ w = 320
+ sh = 420
+ basePoints = [(w, w), (1024 + w `div` 2, 2048 - w), (2048, w), (3072 - w `div` 2, 2048 - w), (4096 - w, w)]
+ lW = [Line Erasing 60 basePoints]
+ sp = [SpecialPoints $ basePoints ++ [(1024 + w `div` 2, 2048 - w - sh), (3072 - w `div` 2, 2048 - w - sh), (2048, w + sh)]]
+
+fullFill = scale 256 $ [Line Solid 63 [(0, 1), (16, 1), (16, 3), (0, 3), (0, 5), (16, 5), (16, 7), (0, 7)]]