# HG changeset patch # User Medo # Date 1347807291 -7200 # Node ID c73fd8cfa7c0543b4ce6fe57b836b89856056ca6 # Parent ce6ead3327b260dcf6dc7e598f16f145caf3b742# Parent fcdc864cdbeff6d849112659ab8d3dd17b328045 Merge diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/CMakeLists.txt Sun Sep 16 16:54:51 2012 +0200 @@ -28,6 +28,7 @@ # Configure for SDL find_package(SDL REQUIRED) find_package(SDL_mixer REQUIRED) +find_package(FFMPEG) include_directories(.) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/model) @@ -39,6 +40,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/util) include_directories(${SDL_INCLUDE_DIR}) include_directories(${SDLMIXER_INCLUDE_DIR}) +include_directories(${FFMPEG_INCLUDE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/misc/quazip) if(UNIX) # HACK: in freebsd cannot find iconv.h included via SDL.h @@ -71,6 +73,10 @@ file(GLOB_RECURSE UIcpp ui/*.cpp) file(GLOB UtilCpp util/*.cpp) +if((NOT NO_VIDEOREC) AND "${FFMPEG_FOUND}") + add_definitions(-DVIDEOREC) +endif() + set(hwfr_src ${ModelCpp} ${NetCpp} @@ -85,6 +91,7 @@ hwform.cpp main.cpp team.cpp + campaign.cpp ui_hwform.cpp ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp ) @@ -122,6 +129,7 @@ hwform.h team.h util/DataManager.h + util/libav_iteraction.h ) set(hwfr_hdrs @@ -132,6 +140,7 @@ ui_hwform.h hwconsts.h sdlkeys.h + campaign.h ) set(hwfr_rez hedgewars.qrc) @@ -169,6 +178,7 @@ ${QT_LIBRARIES} ${SDL_LIBRARY} ${SDLMIXER_LIBRARY} + ${FFMPEG_LIBRARIES} ${HW_LINK_LIBS} ) diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/binds.cpp --- a/QTfrontend/binds.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/binds.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -65,5 +65,6 @@ {"mute", "8", QT_TRANSLATE_NOOP("binds", "mute audio"), NULL, NULL}, {"fullscr", "f12", QT_TRANSLATE_NOOP("binds", "change mode"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle fullscreen mode:")}, {"capture", "c", QT_TRANSLATE_NOOP("binds", "capture"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Take a screenshot:")}, - {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehogs\ninfo"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")} + {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehogs\ninfo"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")}, + {"record", "r", QT_TRANSLATE_NOOP("binds", "record"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Record video:")} }; diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/binds.h --- a/QTfrontend/binds.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/binds.h Sun Sep 16 16:54:51 2012 +0200 @@ -21,7 +21,7 @@ #include -#define BINDS_NUMBER 45 +#define BINDS_NUMBER 46 struct BindAction { diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/campaign.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/campaign.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,91 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "campaign.h" +#include "gameuiconfig.h" +#include "hwconsts.h" +#include "gamecfgwidget.h" +#include "bgwidget.h" +#include "mouseoverfilter.h" +#include "tcpBase.h" + +#include "DataManager.h" + +extern QString campaign, campaignTeam; + +QStringList getCampMissionList(QString & campaign) +{ + QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0); + campfile.setIniCodec("UTF-8"); + unsigned int mNum = campfile.value("MissionNum", 0).toInt(); + + QStringList missionList; + for (unsigned int i = 0; i < mNum; i++) + { + missionList += campfile.value(QString("Mission %1/Name").arg(i + 1)).toString(); + } + return missionList; +} + +unsigned int getCampProgress(QString & teamName, QString & campName) +{ + QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0); + teamfile.setIniCodec("UTF-8"); + return teamfile.value("Campaign " + campName + "/Progress", 0).toInt(); +} + +QString getCampaignScript(QString campaign, unsigned int mNum) +{ + QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0); + campfile.setIniCodec("UTF-8"); + return campfile.value(QString("Mission %1/Script").arg(mNum)).toString(); +} + + + + + + + diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/campaign.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/campaign.h Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,42 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef CAMPAIGN_H +#define CAMPAIGN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netserver.h" +#include "game.h" +#include "ui_hwform.h" +#include "SDLInteraction.h" +#include "bgwidget.h" + +QStringList getCampMissionList(QString & campaign); +unsigned int getCampProgress(QString & teamName, QString & campName); +QString getCampaignScript(QString campaign, unsigned int mNum); + +#endif diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/game.cpp --- a/QTfrontend/game.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/game.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "game.h" @@ -29,9 +30,12 @@ #include "gamecfgwidget.h" #include "teamselect.h" #include "proto.h" +#include "campaign.h" + +#include #include "ThemeModel.h" -QString training, campaign; // TODO: Cleaner solution? +QString training, campaign, campaignScript, campaignTeam; // TODO: Cleaner solution? HWGame::HWGame(GameUIConfig * config, GameCFGWidget * gamecfg, QString ammo, TeamSelWidget* pTeamSelWidget) : TCPBase(true), @@ -52,20 +56,20 @@ { switch (gameType) { - case gtSave: - if (gameState == gsInterrupted || gameState == gsHalted) - emit HaveRecord(false, demo); - else if (gameState == gsFinished) - emit HaveRecord(true, demo); - break; case gtDemo: + // for video recording we need demo anyway + emit HaveRecord(rtNeither, demo); break; case gtNet: - emit HaveRecord(true, demo); + emit HaveRecord(rtDemo, demo); break; default: - if (gameState == gsInterrupted || gameState == gsHalted) emit HaveRecord(false, demo); - else if (gameState == gsFinished) emit HaveRecord(true, demo); + if (gameState == gsInterrupted || gameState == gsHalted) + emit HaveRecord(rtSave, demo); + else if (gameState == gsFinished) + emit HaveRecord(rtDemo, demo); + else + emit HaveRecord(rtNeither, demo); } SetGameState(gsStopped); } @@ -164,7 +168,7 @@ HWProto::addStringToBuffer(campaigncfg, "TL"); HWProto::addStringToBuffer(campaigncfg, "eseed " + QUuid::createUuid().toString()); - HWProto::addStringToBuffer(campaigncfg, "escript " + campaign); + HWProto::addStringToBuffer(campaigncfg, "escript " + campaignScript); RawSendIPC(campaigncfg); } @@ -261,6 +265,14 @@ emit SendTeamMessage(msgbody); break; } + case 'V': + { + if (msg.at(2) == '?') + sendCampaignVar(msg.right(msg.size() - 3)); + else if (msg.at(2) == '!') + writeCampaignVar(msg.right(msg.size() - 3)); + break; + } default: { if (gameType == gtNet && !netSuspend) @@ -374,10 +386,12 @@ SetGameState(gsStarted); } -void HWGame::StartCampaign(const QString & file) +void HWGame::StartCampaign(const QString & camp, const QString & campScript, const QString & campTeam) { gameType = gtCampaign; - campaign = "Missions/Campaign/" + file + ".lua"; + campaign = camp; + campaignScript = "Missions/Campaign/" + camp + "/" + campScript; + campaignTeam = campTeam; demo.clear(); Start(); SetGameState(gsStarted); @@ -387,6 +401,10 @@ { gameState = state; emit GameStateChanged(state); + if (gameType == gtCampaign) + { + emit CampStateChanged(1); + } } void HWGame::abort() @@ -395,3 +413,29 @@ HWProto::addStringToBuffer(buf, QString("efinish")); RawSendIPC(buf); } + +void HWGame::sendCampaignVar(const QByteArray &varToSend) +{ + QString varToFind(varToSend); + QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + campaignTeam + ".hwt", QSettings::IniFormat, 0); + teamfile.setIniCodec("UTF-8"); + QString varValue = teamfile.value("Campaign " + campaign + "/" + varToFind, "").toString(); + QByteArray command; + HWProto::addStringToBuffer(command, "V." + varValue); + RawSendIPC(command); +} + +void HWGame::writeCampaignVar(const QByteArray & varVal) +{ + int i = varVal.indexOf(" "); + if(i < 0) + return; + + QString varToWrite = QString::fromUtf8(varVal.left(i)); + QString varValue = QString::fromUtf8(varVal.mid(i + 1)); + + QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + campaignTeam + ".hwt", QSettings::IniFormat, 0); + teamfile.setIniCodec("UTF-8"); + teamfile.setValue("Campaign " + campaign + "/" + varToWrite, varValue); +} + diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/game.h --- a/QTfrontend/game.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/game.h Sun Sep 16 16:54:51 2012 +0200 @@ -40,6 +40,13 @@ gsHalted = 6 }; +enum RecordType +{ + rtDemo, + rtSave, + rtNeither, +}; + bool checkForDir(const QString & dir); class HWGame : public TCPBase @@ -54,7 +61,7 @@ void StartQuick(); void StartNet(); void StartTraining(const QString & file); - void StartCampaign(const QString & file); + void StartCampaign(const QString & camp, const QString & campScript, const QString & campTeam); void abort(); GameState gameState; bool netSuspend; @@ -70,8 +77,9 @@ void SendTeamMessage(const QString & msg); void GameStateChanged(GameState gameState); void GameStats(char type, const QString & info); - void HaveRecord(bool isDemo, const QByteArray & record); + void HaveRecord(RecordType type, const QByteArray & record); void ErrorMessage(const QString &); + void CampStateChanged(int); public slots: void FromNet(const QByteArray & msg); @@ -103,6 +111,8 @@ void SendCampaignConfig(); void ParseMessage(const QByteArray & msg); void SetGameState(GameState state); + void sendCampaignVar(const QByteArray & varToSend); + void writeCampaignVar(const QByteArray &varVal); }; #endif diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/gameuiconfig.cpp --- a/QTfrontend/gameuiconfig.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/gameuiconfig.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -27,6 +27,7 @@ #include "gameuiconfig.h" #include "hwform.h" #include "pageoptions.h" +#include "pagevideos.h" #include "pagenetserver.h" #include "hwconsts.h" #include "fpsedit.h" @@ -44,6 +45,7 @@ resizeToConfigValues(); reloadValues(); + reloadVideosValues(); } void GameUIConfig::reloadValues(void) @@ -66,7 +68,7 @@ Form->ui.pageOptions->SLQuality->setValue(value("video/quality", 5).toUInt()); Form->ui.pageOptions->CBStereoMode->setCurrentIndex(value("video/stereo", 0).toUInt()); - Form->ui.pageOptions->CBFrontendEffects->setChecked(frontendEffects); + Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/effects", true).toBool()); Form->ui.pageOptions->CBEnableSound->setChecked(value("audio/sound", true).toBool()); Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/sound", true).toBool()); Form->ui.pageOptions->CBEnableMusic->setChecked(value("audio/music", true).toBool()); @@ -118,6 +120,30 @@ } } +void GameUIConfig::reloadVideosValues(void) +{ + Form->ui.pageVideos->framerateBox->setValue(value("videorec/fps",25).toUInt()); + Form->ui.pageVideos->bitrateBox->setValue(value("videorec/bitrate",400).toUInt()); + bool useGameRes = value("videorec/usegameres",true).toBool(); + if (useGameRes) + { + QRect res = vid_Resolution(); + Form->ui.pageVideos->widthEdit->setText(QString::number(res.width())); + Form->ui.pageVideos->heightEdit->setText(QString::number(res.height())); + } + else + { + Form->ui.pageVideos->widthEdit->setText(value("videorec/width","800").toString()); + Form->ui.pageVideos->heightEdit->setText(value("videorec/height","600").toString()); + } + Form->ui.pageVideos->checkUseGameRes->setChecked(useGameRes); + Form->ui.pageVideos->checkRecordAudio->setChecked(value("videorec/audio",true).toBool()); + if (!Form->ui.pageVideos->tryCodecs(value("videorec/format","no").toString(), + value("videorec/videocodec","no").toString(), + value("videorec/audiocodec","no").toString())) + Form->ui.pageVideos->setDefaultCodecs(); +} + QStringList GameUIConfig::GetTeamsList() { QDir teamdir; @@ -200,6 +226,22 @@ Form->gameSettings->sync(); } +void GameUIConfig::SaveVideosOptions() +{ + QRect res = rec_Resolution(); + setValue("videorec/format", AVFormat()); + setValue("videorec/videocodec", videoCodec()); + setValue("videorec/audiocodec", audioCodec()); + setValue("videorec/fps", rec_Framerate()); + setValue("videorec/bitrate", rec_Bitrate()); + setValue("videorec/width", res.width()); + setValue("videorec/height", res.height()); + setValue("videorec/usegameres", Form->ui.pageVideos->checkUseGameRes->isChecked()); + setValue("videorec/audio", recordAudio()); + + Form->gameSettings->sync(); +} + QString GameUIConfig::language() { return Form->ui.pageOptions->CBLanguage->itemData(Form->ui.pageOptions->CBLanguage->currentIndex()).toString(); @@ -395,3 +437,43 @@ { return Form->ui.pageOptions->volumeBox->value() * 128 / 100; } + +QString GameUIConfig::AVFormat() +{ + return Form->ui.pageVideos->format(); +} + +QString GameUIConfig::videoCodec() +{ + return Form->ui.pageVideos->videoCodec(); +} + +QString GameUIConfig::audioCodec() +{ + return Form->ui.pageVideos->audioCodec(); +} + +QRect GameUIConfig::rec_Resolution() +{ + if (Form->ui.pageVideos->checkUseGameRes->isChecked()) + return vid_Resolution(); + QRect res(0,0,0,0); + res.setWidth(Form->ui.pageVideos->widthEdit->text().toUInt()); + res.setHeight(Form->ui.pageVideos->heightEdit->text().toUInt()); + return res; +} + +int GameUIConfig::rec_Framerate() +{ + return Form->ui.pageVideos->framerateBox->value(); +} + +int GameUIConfig::rec_Bitrate() +{ + return Form->ui.pageVideos->bitrateBox->value(); +} + +bool GameUIConfig::recordAudio() +{ + return Form->ui.pageVideos->checkRecordAudio->isChecked(); +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/gameuiconfig.h --- a/QTfrontend/gameuiconfig.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/gameuiconfig.h Sun Sep 16 16:54:51 2012 +0200 @@ -59,18 +59,28 @@ void resizeToConfigValues(); quint32 stereoMode() const; + QString AVFormat(); + QString videoCodec(); + QString audioCodec(); + QRect rec_Resolution(); + int rec_Framerate(); + int rec_Bitrate(); + bool recordAudio(); + #ifdef __APPLE__ #ifdef SPARKLE_ENABLED bool isAutoUpdateEnabled(); #endif #endif - void reloadValues(void); + void reloadValues(); + void reloadVideosValues(); signals: void frontendFullscreen(bool value); public slots: void SaveOptions(); + void SaveVideosOptions(); void updNetNick(); private: bool netPasswordIsValid(); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/hedgewars.qrc --- a/QTfrontend/hedgewars.qrc Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/hedgewars.qrc Sun Sep 16 16:54:51 2012 +0200 @@ -56,6 +56,7 @@ res/Load.png res/Save.png res/Record.png + res/Videos.png res/weaponsicon.png res/teamicon.png res/panelbg.png diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/hwform.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -51,6 +51,7 @@ #include "hwform.h" #include "game.h" #include "team.h" +#include "campaign.h" #include "teamselect.h" #include "selectWeapon.h" #include "gameuiconfig.h" @@ -76,6 +77,7 @@ #include "pagegamestats.h" #include "pageplayrecord.h" #include "pagedata.h" +#include "pagevideos.h" #include "hwconsts.h" #include "newnetclient.h" #include "gamecfgwidget.h" @@ -90,6 +92,7 @@ #include "drawmapwidget.h" #include "mouseoverfilter.h" #include "roomslistmodel.h" +#include "recorder.h" #include "DataManager.h" @@ -140,6 +143,8 @@ config = new GameUIConfig(this, cfgdir->absolutePath() + "/hedgewars.ini"); + ui.pageVideos->init(config); + #ifdef __APPLE__ panel = new M3Panel; @@ -162,6 +167,7 @@ #endif UpdateTeamsLists(); + InitCampaignPage(); UpdateCampaignPage(0); UpdateWeapons(); @@ -198,6 +204,11 @@ connect(ui.pageNetGame, SIGNAL(DLCClicked()), pageSwitchMapper, SLOT(map())); pageSwitchMapper->setMapping(ui.pageNetGame, ID_PAGE_DATADOWNLOAD); +#ifdef VIDEOREC + connect(ui.pageMain->BtnVideos, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMain->BtnVideos, ID_PAGE_VIDEOS); +#endif + //connect(ui.pageMain->BtnExit, SIGNAL(pressed()), this, SLOT(btnExitPressed())); //connect(ui.pageMain->BtnExit, SIGNAL(clicked()), this, SLOT(btnExitClicked())); @@ -273,6 +284,7 @@ connect(ui.pageCampaign->BtnStartCampaign, SIGNAL(clicked()), this, SLOT(StartCampaign())); connect(ui.pageCampaign->CBTeam, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int))); + connect(ui.pageCampaign->CBCampaign, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int))); connect(ui.pageSelectWeapon->BtnDelete, SIGNAL(clicked()), @@ -288,6 +300,7 @@ connect(ui.pageConnecting, SIGNAL(cancelConnection()), this, SLOT(GoBack())); + connect(ui.pageVideos, SIGNAL(goBack()), config, SLOT(SaveVideosOptions())); ammoSchemeModel = new AmmoSchemeModel(this, cfgdir->absolutePath() + "/schemes.ini"); ui.pageScheme->setModel(ammoSchemeModel); @@ -512,6 +525,11 @@ GoToPage(ID_PAGE_SCHEME); } +void HWForm::GoToVideos() +{ + GoToPage(ID_PAGE_VIDEOS); +} + void HWForm::OnPageShown(quint8 id, quint8 lastid) { #ifdef USE_XFIRE @@ -603,6 +621,11 @@ config->reloadValues(); } + if (id == ID_PAGE_VIDEOS ) + { + config->reloadVideosValues(); + } + // load and save ignore/friends lists if (lastid == ID_PAGE_NETGAME) // leaving a room ui.pageNetGame->pChatWidget->saveLists(ui.pageOptions->editNetNick->text()); @@ -704,6 +727,8 @@ int curid = ui.Pages->currentIndex(); if (curid == ID_PAGE_MAIN) { + if (!ui.pageVideos->tryQuit(this)) + return; stopAnim = true; exit(); } @@ -1354,10 +1379,11 @@ void HWForm::CreateGame(GameCFGWidget * gamecfg, TeamSelWidget* pTeamSelWidget, QString ammo) { game = new HWGame(config, gamecfg, ammo, pTeamSelWidget); + connect(game, SIGNAL(CampStateChanged(int)), this, SLOT(UpdateCampaignPageProgress(int))); connect(game, SIGNAL(GameStateChanged(GameState)), this, SLOT(GameStateChanged(GameState))); connect(game, SIGNAL(GameStats(char, const QString &)), ui.pageGameStats, SLOT(GameStats(char, const QString &))); connect(game, SIGNAL(ErrorMessage(const QString &)), this, SLOT(ShowErrorMessage(const QString &)), Qt::QueuedConnection); - connect(game, SIGNAL(HaveRecord(bool, const QByteArray &)), this, SLOT(GetRecord(bool, const QByteArray &))); + connect(game, SIGNAL(HaveRecord(RecordType, const QByteArray &)), this, SLOT(GetRecord(RecordType, const QByteArray &))); m_lastDemo = QByteArray(); } @@ -1368,43 +1394,47 @@ msg); } -void HWForm::GetRecord(bool isDemo, const QByteArray & record) +void HWForm::GetRecord(RecordType type, const QByteArray & record) { - QString filename; - QByteArray demo = record; - QString recordFileName = - config->appendDateTimeToRecordName() ? - QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm") : - "LastRound"; + if (type != rtNeither) + { + QString filename; + QByteArray demo = record; + QString recordFileName = + config->appendDateTimeToRecordName() ? + QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm") : + "LastRound"; - QStringList versionParts = cVersionString->split('-'); - if ( (versionParts.size() == 2) && (!versionParts[1].isEmpty()) && (versionParts[1].contains(':')) ) - recordFileName = recordFileName + "_" + versionParts[1].replace(':','-'); + QStringList versionParts = cVersionString->split('-'); + if ( (versionParts.size() == 2) && (!versionParts[1].isEmpty()) && (versionParts[1].contains(':')) ) + recordFileName = recordFileName + "_" + versionParts[1].replace(':','-'); - if (isDemo) - { - demo.replace(QByteArray("\x02TL"), QByteArray("\x02TD")); - demo.replace(QByteArray("\x02TN"), QByteArray("\x02TD")); - demo.replace(QByteArray("\x02TS"), QByteArray("\x02TD")); - filename = cfgdir->absolutePath() + "/Demos/" + recordFileName + "." + *cProtoVer + ".hwd"; - m_lastDemo = demo; - } - else - { - demo.replace(QByteArray("\x02TL"), QByteArray("\x02TS")); - demo.replace(QByteArray("\x02TN"), QByteArray("\x02TS")); - filename = cfgdir->absolutePath() + "/Saves/" + recordFileName + "." + *cProtoVer + ".hws"; + if (type == rtDemo) + { + demo.replace(QByteArray("\x02TL"), QByteArray("\x02TD")); + demo.replace(QByteArray("\x02TN"), QByteArray("\x02TD")); + demo.replace(QByteArray("\x02TS"), QByteArray("\x02TD")); + filename = cfgdir->absolutePath() + "/Demos/" + recordFileName + "." + *cProtoVer + ".hwd"; + m_lastDemo = demo; + } + else + { + demo.replace(QByteArray("\x02TL"), QByteArray("\x02TS")); + demo.replace(QByteArray("\x02TN"), QByteArray("\x02TS")); + filename = cfgdir->absolutePath() + "/Saves/" + recordFileName + "." + *cProtoVer + ".hws"; + } + + QFile demofile(filename); + if (!demofile.open(QIODevice::WriteOnly)) + ShowErrorMessage(tr("Cannot save record to file %1").arg(filename)); + else + { + demofile.write(demo); + demofile.close(); + } } - - QFile demofile(filename); - if (!demofile.open(QIODevice::WriteOnly)) - { - ShowErrorMessage(tr("Cannot save record to file %1").arg(filename)); - return ; - } - demofile.write(demo); - demofile.close(); + ui.pageVideos->startEncoding(record); } void HWForm::startTraining(const QString & scriptName) @@ -1418,7 +1448,13 @@ { CreateGame(0, 0, 0); - game->StartCampaign(ui.pageCampaign->CBSelect->itemData(ui.pageCampaign->CBSelect->currentIndex()).toString()); + QComboBox *combo = ui.pageCampaign->CBMission; + QString camp = ui.pageCampaign->CBCampaign->currentText(); + unsigned int mNum = combo->count() - combo->currentIndex(); + QString miss = getCampaignScript(camp, mNum); + QString campTeam = ui.pageCampaign->CBTeam->currentText(); + + game->StartCampaign(camp, miss, campTeam); } void HWForm::CreateNetGame() @@ -1445,6 +1481,7 @@ xfire_free(); #endif config->SaveOptions(); + config->SaveVideosOptions(); event->accept(); } @@ -1544,24 +1581,51 @@ } } +void HWForm::InitCampaignPage() +{ + ui.pageCampaign->CBCampaign->clear(); + HWTeam team(ui.pageCampaign->CBTeam->currentText()); + + QStringList entries = DataManager::instance().entryList( + "Missions/Campaign", + QDir::Dirs, + QStringList("[^\\.]*") + ); + + unsigned int n = entries.count(); + for(unsigned int i = 0; i < n; i++) + { + ui.pageCampaign->CBCampaign->addItem(QString(entries[i]), QString(entries[i])); + } +} + + void HWForm::UpdateCampaignPage(int index) { Q_UNUSED(index); HWTeam team(ui.pageCampaign->CBTeam->currentText()); - ui.pageCampaign->CBSelect->clear(); + ui.pageCampaign->CBMission->clear(); + + QString campaignName = ui.pageCampaign->CBCampaign->currentText(); + QStringList missionEntries = getCampMissionList(campaignName); + QString tName = team.name(); + unsigned int n = missionEntries.count(); + unsigned int m = getCampProgress(tName, campaignName); - QStringList entries = DataManager::instance().entryList( - "Missions/Campaign", - QDir::Files, - QStringList("*#*.lua") - ); + for (unsigned int i = qMin(m + 1, n); i > 0; i--) + { + ui.pageCampaign->CBMission->addItem(QString("Mission %1: ").arg(i) + QString(missionEntries[i-1]), QString(missionEntries[i-1])); + } +} - unsigned int n = entries.count(); - for(unsigned int i = 0; (i < n) && (i <= team.campaignProgress()); i++) - { - ui.pageCampaign->CBSelect->addItem(QString(entries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2").replace("_", " "), QString(entries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1")); - } +void HWForm::UpdateCampaignPageProgress(int index) +{ + Q_UNUSED(index); + + int missionIndex = ui.pageCampaign->CBMission->currentIndex(); + UpdateCampaignPage(0); + ui.pageCampaign->CBMission->setCurrentIndex(missionIndex); } // used for --set-everything [screen width] [screen height] [color dept] [volume] [enable music] [enable sounds] [language file] [full screen] [show FPS] [alternate damage] [timer value] [reduced quality] diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/hwform.h --- a/QTfrontend/hwform.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/hwform.h Sun Sep 16 16:54:51 2012 +0200 @@ -67,6 +67,7 @@ void exit(); void setButtonDescription(QString desc); void backDescription(); + void GoToVideos(); private slots: void GoToSaves(); @@ -114,13 +115,15 @@ void GameStateChanged(GameState gameState); void ForcedDisconnect(const QString & reason); void ShowErrorMessage(const QString &); - void GetRecord(bool isDemo, const QByteArray & record); + void GetRecord(RecordType type, const QByteArray & record); void CreateNetGame(); void UpdateWeapons(); void onFrontendFullscreen(bool value); void onFrontendEffects(bool value); void Music(bool checked); void UpdateCampaignPage(int index); + void UpdateCampaignPageProgress(int index); + void InitCampaignPage(); //Starts the transmission process for the feedback void SendFeedback(); //Make a xml representation of the issue to be created @@ -175,6 +178,7 @@ ID_PAGE_DRAWMAP , ID_PAGE_DATADOWNLOAD , ID_PAGE_FEEDBACK , + ID_PAGE_VIDEOS, MAX_PAGE }; QPointer game; diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/main.cpp --- a/QTfrontend/main.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/main.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -197,6 +197,8 @@ checkForDir(cfgdir->absolutePath() + "/Screenshots"); checkForDir(cfgdir->absolutePath() + "/Teams"); checkForDir(cfgdir->absolutePath() + "/Logs"); + checkForDir(cfgdir->absolutePath() + "/Videos"); + checkForDir(cfgdir->absolutePath() + "/VideoTemp"); } datadir->cd(bindir->absolutePath()); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/net/newnetclient.cpp --- a/QTfrontend/net/newnetclient.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/net/newnetclient.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -357,6 +357,7 @@ QString flags = lst[1]; bool setFlag = flags[0] == '+'; + const QStringList nicks = lst.mid(2); while(flags.size() > 1) { @@ -365,19 +366,51 @@ switch(c) { + // flag indicating if a player is ready to start a game case 'r': - { - for(int i = 2; i < lst.size(); ++i) - { - if (lst[i] == mynick) + foreach (const QString & nick, nicks) + { + if (nick == mynick) + { + if (isChief && !setFlag) ToggleReady(); + else emit setMyReadyStatus(setFlag); + } + emit setReadyStatus(nick, setFlag); + } + break; + + // flag indicating if a player is a registered user + case 'u': + emit setRegisteredStatus(nicks, setFlag); + break; + + // flag indicating if a player is the host/master of the room + case 'h': + foreach (const QString & nick, nicks) { - if (isChief && !setFlag) ToggleReady(); - else emit setMyReadyStatus(setFlag); + if (nick == mynick) + { + isChief = setFlag; + emit roomMaster(isChief); + } + + emit setRoomMasterStatus(nick, setFlag); } + break; - emit setReadyStatus(lst[i], setFlag); - } - } + // flag indicating if a player is admin (if so -> worship them!) + case 'a': + foreach (const QString & nick, nicks) + { + if (nick == mynick) + emit adminAccess(setFlag); + + emit setAdminStatus(nick, setFlag); + } + break; + + default: + qWarning() << "Net: Unknown client-flag: " << c; } } @@ -503,7 +536,7 @@ if (lst[0] == "ADMIN_ACCESS") { - emit adminAccess(true); + // obsolete, see +a client flag return; } @@ -673,6 +706,7 @@ return; } + // obsolete if (lst[0] == "ROOM_CONTROL_ACCESS") { if (lst.size() < 2) @@ -680,8 +714,6 @@ qWarning("Net: Bad ROOM_CONTROL_ACCESS message"); return; } - isChief = (lst[1] != "0"); - emit roomMaster(isChief); return; } } diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/net/newnetclient.h --- a/QTfrontend/net/newnetclient.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/net/newnetclient.h Sun Sep 16 16:54:51 2012 +0200 @@ -118,6 +118,9 @@ void setReadyStatus(const QString & nick, bool isReady); void setMyReadyStatus(bool isReady); + void setAdminStatus(const QString & nick, bool isAdmin); + void setRoomMasterStatus(const QString & nick, bool isAdmin); + void setRegisteredStatus(const QStringList & nicks, bool isRegistered); public slots: void ToggleReady(); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/net/recorder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/net/recorder.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,131 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +//#include + +#include "recorder.h" +#include "gameuiconfig.h" +#include "hwconsts.h" +#include "game.h" +#include "libav_iteraction.h" + +// Encoding is memory expensive process, so we need to limit maximum number +// of simultaneous encoders. +static const int maxRecorders = 3; +static int numRecorders = 0; + +static QList queue; + +HWRecorder::HWRecorder(GameUIConfig * config, const QString &prefix) : + TCPBase(false) +{ + this->config = config; + this->prefix = prefix; + finished = false; + name = prefix + "." + LibavIteraction::instance().getExtension(config->AVFormat()); +} + +HWRecorder::~HWRecorder() +{ + emit encodingFinished(finished); + if (queue.empty()) + numRecorders--; + else + queue.takeFirst()->Start(); +} + +void HWRecorder::onClientDisconnect() +{ +} + +void HWRecorder::onClientRead() +{ + quint8 msglen; + quint32 bufsize; + while (!readbuffer.isEmpty() && ((bufsize = readbuffer.size()) > 0) && + ((msglen = readbuffer.data()[0]) < bufsize)) + { + QByteArray msg = readbuffer.left(msglen + 1); + readbuffer.remove(0, msglen + 1); + switch (msg.at(1)) + { + case '?': + SendIPC("!"); + break; + case 'p': + emit onProgress((quint8(msg.at(2))*256.0 + quint8(msg.at(3)))*0.0001); + break; + case 'v': + finished = true; + break; + } + } +} + +void HWRecorder::EncodeVideo(const QByteArray & record) +{ + toSendBuf = record; + toSendBuf.replace(QByteArray("\x02TD"), QByteArray("\x02TV")); + toSendBuf.replace(QByteArray("\x02TL"), QByteArray("\x02TV")); + toSendBuf.replace(QByteArray("\x02TN"), QByteArray("\x02TV")); + toSendBuf.replace(QByteArray("\x02TS"), QByteArray("\x02TV")); + + if (numRecorders < maxRecorders) + { + numRecorders++; + Start(); // run engine + } + else + queue.push_back(this); +} + +QStringList HWRecorder::getArguments() +{ + QStringList arguments; + QRect resolution = config->rec_Resolution(); + arguments << cfgdir->absolutePath(); + arguments << QString::number(resolution.width()); + arguments << QString::number(resolution.height()); + arguments << "32"; // bpp + arguments << QString("%1").arg(ipc_port); + arguments << "0"; // fullscreen + arguments << "0"; // sound + arguments << "0"; // music + arguments << "0"; // sound volume + arguments << QString::number(config->timerInterval()); + arguments << datadir->absolutePath(); + arguments << (config->isShowFPSEnabled() ? "1" : "0"); + arguments << (config->isAltDamageEnabled() ? "1" : "0"); + arguments << config->netNick().toUtf8().toBase64(); + arguments << QString::number(config->translateQuality()); + arguments << QString::number(config->stereoMode()); + arguments << HWGame::tr("en.txt"); + arguments << QString::number(config->rec_Framerate()); // framerate numerator + arguments << "1"; // framerate denominator + arguments << prefix; + arguments << config->AVFormat(); + arguments << config->videoCodec(); +// Could use a field to use quality instead. maybe quality could override bitrate - or just pass (and set) both. +// The library does support using both at once after all. + arguments << QString::number(config->rec_Bitrate()*1024); + arguments << (config->recordAudio()? config->audioCodec() : "no"); + + return arguments; +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/net/recorder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/net/recorder.h Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,58 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef RECORDER_H +#define RECORDER_H + +#include +#include + +#include "tcpBase.h" + +class GameUIConfig; +class VideoItem; + +class HWRecorder : public TCPBase +{ + Q_OBJECT + public: + HWRecorder(GameUIConfig * config, const QString & prefix); + virtual ~HWRecorder(); + + void EncodeVideo(const QByteArray & record); + + VideoItem * item; // used by pagevideos + QString name; + QString prefix; + + protected: + // virtuals from TCPBase + virtual QStringList getArguments(); + virtual void onClientRead(); + virtual void onClientDisconnect(); + + signals: + void onProgress(float progress); // 0 < progress < 1 + void encodingFinished(bool success); + + private: + bool finished; + GameUIConfig * config; +}; + +#endif // RECORDER_H diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/net/tcpBase.cpp --- a/QTfrontend/net/tcpBase.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/net/tcpBase.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -31,6 +31,8 @@ TCPBase::~TCPBase() { + if (IPCSocket) + IPCSocket->deleteLater(); } TCPBase::TCPBase(bool demoMode) : @@ -65,6 +67,9 @@ connect(IPCSocket, SIGNAL(disconnected()), this, SLOT(ClientDisconnect())); connect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead())); SendToClientFirst(); + + if(srvsList.size()==1) srvsList.pop_front(); + emit isReadyNow(); } void TCPBase::RealStart() @@ -88,9 +93,13 @@ disconnect(IPCSocket, SIGNAL(readyRead()), this, SLOT(ClientRead())); onClientDisconnect(); - if(srvsList.size()==1) srvsList.pop_front(); - emit isReadyNow(); + /* if(srvsList.size()==1) srvsList.pop_front(); + emit isReadyNow();*/ IPCSocket->deleteLater(); + + // make sure this object is not in the server list anymore + srvsList.removeOne(this); + deleteLater(); } diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/net/tcpBase.h diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/res/Videos.png Binary file QTfrontend/res/Videos.png has changed diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/res/css/birthday.css --- a/QTfrontend/res/css/birthday.css Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/res/css/birthday.css Sun Sep 16 16:54:51 2012 +0200 @@ -33,7 +33,7 @@ a { color:#c8c8ff; } QLineEdit, QListWidget, QTableView, QTextBrowser, QSpinBox, QComboBox, -QComboBox QAbstractItemView, QMenu::item { +QComboBox QAbstractItemView, QPlainTextEdit, QMenu::item { background-color: rgba(13, 5, 68, 70%); } @@ -42,7 +42,7 @@ } QPushButton, QListWidget, QTableView, QLineEdit, QHeaderView, -QTextBrowser, QSpinBox, QToolBox, QComboBox, +QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget, QTabWidget::pane, QTabBar::tab { @@ -57,14 +57,14 @@ } QLineEdit, QListWidget,QTableView, QTextBrowser, -QSpinBox, QToolBox { +QSpinBox, QToolBox, QPlainTextEdit { border-radius: 10px; } QLineEdit, QLabel, QHeaderView, QListWidget, QTableView, QSpinBox, QToolBox::tab, QComboBox, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, -SelWeaponWidget, QCheckBox, QRadioButton, QPushButton { +SelWeaponWidget, QCheckBox, QRadioButton, QPushButton, QPlainTextEdit { font: bold 13px; } SelWeaponWidget QTabWidget::pane, SelWeaponWidget QTabBar::tab:selected { diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/res/css/christmas.css --- a/QTfrontend/res/css/christmas.css Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/res/css/christmas.css Sun Sep 16 16:54:51 2012 +0200 @@ -33,7 +33,7 @@ a { color:#c8c8ff; } QLineEdit, QListWidget, QTableView, QTextBrowser, QSpinBox, QComboBox, -QComboBox QAbstractItemView, QMenu::item { +QComboBox QAbstractItemView, QPlainTextEdit, QMenu::item { background-color: rgba(13, 5, 68, 70%); } @@ -42,7 +42,7 @@ } QPushButton, QListWidget, QTableView, QLineEdit, QHeaderView, -QTextBrowser, QSpinBox, QToolBox, QComboBox, +QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget, QTabWidget::pane, QTabBar::tab { @@ -57,14 +57,14 @@ } QLineEdit, QListWidget,QTableView, QTextBrowser, -QSpinBox, QToolBox { +QSpinBox, QToolBox, QPlainTextEdit { border-radius: 10px; } QLineEdit, QLabel, QHeaderView, QListWidget, QTableView, QSpinBox, QToolBox::tab, QComboBox, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, -SelWeaponWidget, QCheckBox, QRadioButton, QPushButton { +SelWeaponWidget, QCheckBox, QRadioButton, QPushButton, QPlainTextEdit { font: bold 13px; } SelWeaponWidget QTabWidget::pane, SelWeaponWidget QTabBar::tab:selected { diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/res/css/easter.css --- a/QTfrontend/res/css/easter.css Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/res/css/easter.css Sun Sep 16 16:54:51 2012 +0200 @@ -33,7 +33,7 @@ a { color:#c8c8ff; } QLineEdit, QListWidget, QTableView, QTextBrowser, QSpinBox, QComboBox, -QComboBox QAbstractItemView, QMenu::item { +QComboBox QAbstractItemView, QPlainTextEdit, QMenu::item { background-color: rgba(13, 5, 68, 70%); } @@ -42,7 +42,7 @@ } QPushButton, QListWidget, QTableView, QLineEdit, QHeaderView, -QTextBrowser, QSpinBox, QToolBox, QComboBox, +QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget, QTabWidget::pane, QTabBar::tab { @@ -57,14 +57,14 @@ } QLineEdit, QListWidget,QTableView, QTextBrowser, -QSpinBox, QToolBox { +QSpinBox, QToolBox, QPlainTextEdit { border-radius: 10px; } QLineEdit, QLabel, QHeaderView, QListWidget, QTableView, QSpinBox, QToolBox::tab, QComboBox, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, -SelWeaponWidget, QCheckBox, QRadioButton, QPushButton { +SelWeaponWidget, QCheckBox, QRadioButton, QPushButton, QPlainTextEdit { font: bold 13px; } SelWeaponWidget QTabWidget::pane, SelWeaponWidget QTabBar::tab:selected { diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/res/css/qt.css --- a/QTfrontend/res/css/qt.css Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/res/css/qt.css Sun Sep 16 16:54:51 2012 +0200 @@ -33,7 +33,7 @@ a { color:#c8c8ff; } QLineEdit, QListWidget, QTableView, QTextBrowser, QSpinBox, QComboBox, -QComboBox QAbstractItemView, QMenu::item { +QComboBox QAbstractItemView, QPlainTextEdit, QMenu::item { background-color: rgba(13, 5, 68, 70%); } @@ -42,7 +42,7 @@ } QPushButton, QListWidget, QTableView, QLineEdit, QHeaderView, -QTextBrowser, QSpinBox, QToolBox, QComboBox, +QTextBrowser, QSpinBox, QToolBox, QComboBox, QPlainTextEdit, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, SelWeaponWidget, QTabWidget::pane, QTabBar::tab { @@ -57,14 +57,14 @@ } QLineEdit, QListWidget,QTableView, QTextBrowser, -QSpinBox, QToolBox { +QSpinBox, QToolBox, QPlainTextEdit { border-radius: 10px; } QLineEdit, QLabel, QHeaderView, QListWidget, QTableView, QSpinBox, QToolBox::tab, QComboBox, QComboBox QAbstractItemView, IconedGroupBox, .QGroupBox, GameCFGWidget, TeamSelWidget, -SelWeaponWidget, QCheckBox, QRadioButton, QPushButton { +SelWeaponWidget, QCheckBox, QRadioButton, QPushButton, QPlainTextEdit { font: bold 13px; } SelWeaponWidget QTabWidget::pane, SelWeaponWidget QTabBar::tab:selected { diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/dialog/ask_quit.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/dialog/ask_quit.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,79 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include + +#include "hwform.h" +#include "ask_quit.h" +#include "pagevideos.h" + +HWAskQuitDialog::HWAskQuitDialog(QWidget* parent, HWForm * form) : QDialog(parent) +{ + this->form = form; + + setWindowTitle(tr("Do yot really want to quit?")); + + QVBoxLayout * layout = new QVBoxLayout(this); + + QLabel * lbLabel = new QLabel(this); + lbLabel->setText(QLabel::tr("There are videos that are currently being processed.\n" + "Exiting now will abort them.\n" + "Do yot really want to quit?")); + layout->addWidget(lbLabel); + + lbList = new QLabel(this); + layout->addWidget(lbList); + updateList(); + + QDialogButtonBox* dbbButtons = new QDialogButtonBox(this); + QPushButton * pbYes = dbbButtons->addButton(QDialogButtonBox::Yes); + QPushButton * pbNo = dbbButtons->addButton(QDialogButtonBox::No); + QPushButton * pbMore = dbbButtons->addButton(QPushButton::tr("More info"), QDialogButtonBox::HelpRole); + layout->addWidget(dbbButtons); + + connect(pbYes, SIGNAL(clicked()), this, SLOT(accept())); + connect(pbNo, SIGNAL(clicked()), this, SLOT(reject())); + connect(pbMore, SIGNAL(clicked()), this, SLOT(goToPageVideos())); + + // update list periodically + QTimer * timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(updateList())); + timer->start(200); +} + +void HWAskQuitDialog::goToPageVideos() +{ + reject(); + form->GoToVideos(); +} + +void HWAskQuitDialog::updateList() +{ + QString text = form->ui.pageVideos->getVideosInProgress(); + if (text.isEmpty()) + { + // automatically exit when everything is finished + accept(); + return; + } + lbList->setText(text); +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/dialog/ask_quit.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/dialog/ask_quit.h Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,45 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef ASK_QUIT_H +#define ASK_QUIT_H + +#include + +class QLabel; +class HWForm; +class PageVideos; + +class HWAskQuitDialog : public QDialog +{ + Q_OBJECT + + public: + HWAskQuitDialog(QWidget* parent, HWForm *form); + + private slots: + void goToPageVideos(); + void updateList(); + + private: + HWForm * form; + QLabel * lbList; +}; + + +#endif // INPUT_PASSWORD_H diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/dialog/upload_video.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/dialog/upload_video.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,297 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "upload_video.h" +#include "hwconsts.h" + +// User-agent string used in http requests. +// Don't make it a global varibale - crash on linux because of cVersionString +#define USER_AGENT ("Hedgewars-QtFrontend/" + *cVersionString).toAscii() + +// This is developer key obtained from http://code.google.com/apis/youtube/dashboard/ +// If you are reusing this code outside Hedgewars, don't use this developer key, +// obtain you own at http://code.google.com/apis/youtube/dashboard/ +static const QByteArray devKey = "AI39si5pKjxR0XgNIlmrEFF-LyYD31rps4g2O5dZTxLgD0fvJ2rHxrMrNFY8FYTZrzeI3VlaFVQLKfFnSBugvdZmy8vFzRDefQ"; + +HWUploadVideoDialog::HWUploadVideoDialog(QWidget* parent, const QString &filename, QNetworkAccessManager* netManager) : QDialog(parent) +{ + this->filename = filename; + this->netManager = netManager; + + setWindowTitle(tr("Upload video")); + + // Google requires us to display this, see https://developers.google.com/youtube/terms + QString GoogleNotice = + "

By clicking 'upload,' you certify that you own all rights to the content or that " + "you are authorized by the owner to make the content publicly available on YouTube, " + "and that it otherwise complies with the YouTube Terms of Service located at " + "http://www.youtube.com/t/terms.

"; + + // youtube doesn't understand this characters, even when they are properly escaped + // (either with CDATA or with < or >) + QRegExp rx("[^<>]*"); + + int row = 0; + + QGridLayout * layout = new QGridLayout(this); + layout->setColumnStretch(0, 1); + layout->setColumnStretch(1, 2); + + QLabel * lbLabel = new QLabel(this); + lbLabel->setWordWrap(true); + lbLabel->setText(QLabel::tr( + "Please provide either the YouTube account name " + "or the email address associated with the Google Account.")); + layout->addWidget(lbLabel, row++, 0, 1, 2); + + lbLabel = new QLabel(this); + lbLabel->setText(QLabel::tr("Account name (or email): ")); + layout->addWidget(lbLabel, row, 0); + + leAccount = new QLineEdit(this); + layout->addWidget(leAccount, row++, 1); + + lbLabel = new QLabel(this); + lbLabel->setText(QLabel::tr("Password: ")); + layout->addWidget(lbLabel, row, 0); + + lePassword = new QLineEdit(this); + lePassword->setEchoMode(QLineEdit::Password); + layout->addWidget(lePassword, row++, 1); + + cbSave = new QCheckBox(this); + cbSave->setText(QCheckBox::tr("Save account name and password")); + layout->addWidget(cbSave, row++, 0, 1, 2); + + QFrame * hr = new QFrame(this); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + layout->addWidget(hr, row++, 0, 1, 2); + + lbLabel = new QLabel(this); + lbLabel->setText(QLabel::tr("Video title: ")); + layout->addWidget(lbLabel, row, 0); + + leTitle = new QLineEdit(this); + leTitle->setText(filename); + leTitle->setValidator(new QRegExpValidator(rx, leTitle)); + layout->addWidget(leTitle, row++, 1); + + lbLabel = new QLabel(this); + lbLabel->setText(QLabel::tr("Video description: ")); + layout->addWidget(lbLabel, row++, 0, 1, 2); + + teDescription = new QPlainTextEdit(this); + layout->addWidget(teDescription, row++, 0, 1, 2); + + lbLabel = new QLabel(this); + lbLabel->setText(QLabel::tr("Tags (comma separated): ")); + layout->addWidget(lbLabel, row, 0); + + leTags = new QLineEdit(this); + leTags->setText("hedgewars"); + leTags->setMaxLength(500); + leTags->setValidator(new QRegExpValidator(rx, leTags)); + layout->addWidget(leTags, row++, 1); + + cbPrivate = new QCheckBox(this); + cbPrivate->setText(QCheckBox::tr("Video is private")); + layout->addWidget(cbPrivate, row++, 0, 1, 2); + + hr = new QFrame(this); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + layout->addWidget(hr, row++, 0, 1, 2); + + lbLabel = new QLabel(this); + lbLabel->setWordWrap(true); + lbLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse); + lbLabel->setTextFormat(Qt::RichText); + lbLabel->setOpenExternalLinks(true); + lbLabel->setText(GoogleNotice); + layout->addWidget(lbLabel, row++, 0, 1, 2); + + QDialogButtonBox* dbbButtons = new QDialogButtonBox(this); + btnUpload = dbbButtons->addButton(tr("Upload"), QDialogButtonBox::ActionRole); + QPushButton * pbCancel = dbbButtons->addButton(QDialogButtonBox::Cancel); + layout->addWidget(dbbButtons, row++, 0, 1, 2); + + /* hr = new QFrame(this); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + layout->addWidget(hr, row++, 0, 1, 2);*/ + + connect(btnUpload, SIGNAL(clicked()), this, SLOT(upload())); + connect(pbCancel, SIGNAL(clicked()), this, SLOT(reject())); +} + +void HWUploadVideoDialog::showEvent(QShowEvent * event) +{ + QDialog::showEvent(event); + + // set width to the same value as height (otherwise dialog has too small width) + QSize s = size(); + QPoint p = pos(); + resize(s.height(), s.height()); + move(p.x() - (s.height() - s.width())/2, p.y()); +} + +void HWUploadVideoDialog::setEditable(bool editable) +{ + leTitle->setEnabled(editable); + leAccount->setEnabled(editable); + lePassword->setEnabled(editable); + btnUpload->setEnabled(editable); +} + +void HWUploadVideoDialog::upload() +{ + setEditable(false); + + // Documentation is at https://developers.google.com/youtube/2.0/developers_guide_protocol_clientlogin#ClientLogin_Authentication + QNetworkRequest request; + request.setUrl(QUrl("https://www.google.com/accounts/ClientLogin")); + request.setRawHeader("User-Agent", USER_AGENT); + request.setRawHeader("Content-Type", "application/x-www-form-urlencoded"); + + QString account(QUrl::toPercentEncoding(leAccount->text())); + QString pass(QUrl::toPercentEncoding(lePassword->text())); + QByteArray data = QString("Email=%1&Passwd=%2&service=youtube&source=Hedgewars").arg(account).arg(pass).toAscii(); + + QNetworkReply *reply = netManager->post(request, data); + connect(reply, SIGNAL(finished()), this, SLOT(authFinished())); +} + +static QString XmlEscape(const QString& str) +{ + QString str2 = str; + // youtube doesn't understand this characters, even when they are properly escaped + // (either with CDATA or with < >) + str2.replace('<', ' ').replace('>', ' '); + return "", "]]]]>") + "]]>"; +} + +void HWUploadVideoDialog::authFinished() +{ + QNetworkReply *reply = (QNetworkReply*)sender(); + reply->deleteLater(); + + int HttpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + QByteArray answer = reply->readAll(); + QString authToken = ""; + QList lines = answer.split('\n'); + foreach (const QByteArray& line, lines) + { + QString str(line); + if (!str.startsWith("Auth=", Qt::CaseInsensitive)) + continue; + str.remove(0, 5); + authToken = str; + break; + } + if (authToken.isEmpty()) + { + QString errorStr = QMessageBox::tr("Error while authenticating at google.com:\n"); + if (HttpCode == 403) + errorStr += QMessageBox::tr("Login or password is incorrect"); + else + errorStr += reply->errorString(); + QMessageBox::warning(this, QMessageBox::tr("Error"), errorStr); + setEditable(true); + return; + } + + QByteArray auth = ("GoogleLogin auth=" + authToken).toAscii(); + + // We have authenticated, now we can send metadata and start upload + // Documentation is here: https://developers.google.com/youtube/2.0/developers_guide_protocol_resumable_uploads#Resumable_uploads + QByteArray body = + "" + "" + "" + // "" + "Games" + "" + "" + + XmlEscape(leTitle->text()).toUtf8() + + "" + "" + + XmlEscape(teDescription->toPlainText()).toUtf8() + + "" + "" + + XmlEscape(leTags->text()).toUtf8() + + "" + + (cbPrivate->isChecked()? "" : "") + + "" + ""; + + QNetworkRequest request; + request.setUrl(QUrl("http://uploads.gdata.youtube.com/resumable/feeds/api/users/default/uploads")); + request.setRawHeader("User-Agent", USER_AGENT); + request.setRawHeader("Authorization", auth); + request.setRawHeader("GData-Version", "2"); + request.setRawHeader("X-GData-Key", "key=" + devKey); + request.setRawHeader("Slug", filename.toUtf8()); + request.setRawHeader("Content-Type", "application/atom+xml; charset=UTF-8"); + + reply = netManager->post(request, body); + connect(reply, SIGNAL(finished()), this, SLOT(startUpload())); +} + +void HWUploadVideoDialog::startUpload() +{ + QNetworkReply *reply = (QNetworkReply*)sender(); + reply->deleteLater(); + + location = QString::fromAscii(reply->rawHeader("Location")); + if (location.isEmpty()) + { + QString errorStr = QMessageBox::tr("Error while sending metadata to youtube.com:\n"); + errorStr += reply->errorString(); + QMessageBox::warning(this, QMessageBox::tr("Error"), errorStr); + setEditable(true); + return; + } + + accept(); +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/dialog/upload_video.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/dialog/upload_video.h Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,65 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef UPLOAD_VIDEO_H +#define UPLOAD_VIDEO_H + +#include + +class QLineEdit; +class QCheckBox; +class QPlainTextEdit; +class QLabel; +class QNetworkAccessManager; + +class HWUploadVideoDialog : public QDialog +{ + Q_OBJECT + public: + HWUploadVideoDialog(QWidget* parent, const QString& filename, QNetworkAccessManager* netManager); + + QLineEdit* leAccount; + QLineEdit* lePassword; + QCheckBox* cbSave; + + QLineEdit* leTitle; + QPlainTextEdit* teDescription; + QLineEdit* leTags; + QCheckBox* cbPrivate; + + QPushButton* btnUpload; + + QString location; + + private: + QNetworkAccessManager* netManager; + QString filename; + + void setEditable(bool editable); + + protected: + // virtual from QWidget + void showEvent(QShowEvent * event); + + private slots: + void upload(); + void authFinished(); + void startUpload(); +}; + +#endif // UPLOAD_VIDEO_H diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagecampaign.cpp --- a/QTfrontend/ui/page/pagecampaign.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pagecampaign.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -31,11 +31,13 @@ pageLayout->setRowStretch(0, 1); pageLayout->setRowStretch(3, 1); - CBSelect = new QComboBox(this); CBTeam = new QComboBox(this); + CBMission = new QComboBox(this); + CBCampaign = new QComboBox(this); pageLayout->addWidget(CBTeam, 1, 1); - pageLayout->addWidget(CBSelect, 2, 1); + pageLayout->addWidget(CBCampaign, 2, 1); + pageLayout->addWidget(CBMission, 3, 1); BtnStartCampaign = new QPushButton(this); BtnStartCampaign->setFont(*font14); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagecampaign.h --- a/QTfrontend/ui/page/pagecampaign.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pagecampaign.h Sun Sep 16 16:54:51 2012 +0200 @@ -29,7 +29,8 @@ PageCampaign(QWidget* parent = 0); QPushButton *BtnStartCampaign; - QComboBox *CBSelect; + QComboBox *CBMission; + QComboBox *CBCampaign; QComboBox *CBTeam; protected: diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagemain.cpp --- a/QTfrontend/ui/page/pagemain.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pagemain.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -85,9 +85,15 @@ bottomLayout->setStretch(0,1); btnBack->setWhatsThis(tr("Exit game")); - - BtnSetup = addButton(":/res/Settings.png", bottomLayout, 1, true); + +#ifdef VIDEOREC + BtnVideos = addButton(":/res/Videos.png", bottomLayout, 1, true); + BtnVideos->setWhatsThis(tr("Manage videos recorded from game")); +#endif + + BtnSetup = addButton(":/res/Settings.png", bottomLayout, 2, true); BtnSetup->setWhatsThis(tr("Edit game preferences")); + return bottomLayout; } diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagemain.h --- a/QTfrontend/ui/page/pagemain.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pagemain.h Sun Sep 16 16:54:51 2012 +0200 @@ -34,6 +34,7 @@ QPushButton * BtnFeedback; QPushButton * BtnInfo; QPushButton * BtnDataDownload; + QPushButton * BtnVideos; QLabel * mainNote; private: diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagenettype.cpp --- a/QTfrontend/ui/page/pagenettype.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pagenettype.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -33,7 +33,7 @@ pageLayout->setColumnStretch(3, 10); BtnLAN = addButton(tr("LAN game"), pageLayout, 1, 2); - BtnLAN->setWhatsThis(tr("Hoin or host your own game server in a Local Area Network.")); + BtnLAN->setWhatsThis(tr("Join or host your own game server in a Local Area Network.")); BtnOfficialServer = addButton(tr("Official server"), pageLayout, 2, 2); BtnOfficialServer->setWhatsThis(tr("Join hundreds of players online!")); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pageoptions.cpp --- a/QTfrontend/ui/page/pageoptions.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pageoptions.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -172,17 +172,13 @@ WeaponDelete->setMaximumWidth(pmDelete.width() + 6); WeaponsLayout->addWidget(WeaponDelete, 2, 4); - WeaponTooltip = new QCheckBox(this); - WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips")); - WeaponsLayout->addWidget(WeaponTooltip, 3, 0, 1, 4); - page1Layout->addWidget(groupWeapons, 1, 0); } { IconedGroupBox* groupMisc = new IconedGroupBox(this); //groupMisc->setContentTopPadding(0); - groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); + //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); groupMisc->setIcon(QIcon(":/res/miscicon.png")); //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); groupMisc->setTitle(QGroupBox::tr("Misc")); @@ -239,15 +235,6 @@ editNetPassword->setEchoMode(QLineEdit::Password); MiscLayout->addWidget(editNetPassword, 2, 1); - CBNameWithDate = new QCheckBox(groupMisc); - CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name")); - MiscLayout->addWidget(CBNameWithDate, 5, 0, 1, 2); - - BtnAssociateFiles = new QPushButton(groupMisc); - BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions")); - BtnAssociateFiles->setVisible(!custom_data && !custom_config); - MiscLayout->addWidget(BtnAssociateFiles, 6, 0, 1, 2); - #ifdef __APPLE__ #ifdef SPARKLE_ENABLED CBAutoUpdate = new QCheckBox(groupMisc); @@ -342,18 +329,6 @@ GBAstereolayout->addWidget(CBStereoMode); GBAlayout->addLayout(GBAstereolayout); - QHBoxLayout * GBAfpslayout = new QHBoxLayout(0); - QLabel * maxfps = new QLabel(AGGroupBox); - maxfps->setText(QLabel::tr("FPS limit")); - GBAfpslayout->addWidget(maxfps); - GBAlayout->addLayout(GBAfpslayout); - fpsedit = new FPSEdit(AGGroupBox); - GBAfpslayout->addWidget(fpsedit); - - CBShowFPS = new QCheckBox(AGGroupBox); - CBShowFPS->setText(QCheckBox::tr("Show FPS")); - GBAfpslayout->addWidget(CBShowFPS); - hr = new QFrame(AGGroupBox); hr->setFrameStyle(QFrame::HLine); hr->setLineWidth(3); @@ -392,33 +367,82 @@ page1Layout->addWidget(AGGroupBox, 0, 1, 3, 1); } + + page1Layout->addWidget(new QWidget(this), 3, 0); + } { // page 2 QGridLayout * page2Layout = new QGridLayout(page2); - IconedGroupBox * gbColors = new IconedGroupBox(this); - //gbColors->setIcon(QIcon(":/res/teamicon.png")); - gbColors->setTitle(QGroupBox::tr("Custom colors")); - page2Layout->addWidget(gbColors, 0, 0, 1, 3); - QVBoxLayout * gbCLayout = new QVBoxLayout(gbColors); + { + IconedGroupBox * gbColors = new IconedGroupBox(this); + gbColors->setIcon(QIcon(":/res/lightbulb_on.png")); + gbColors->setTitle(QGroupBox::tr("Custom colors")); + page2Layout->addWidget(gbColors, 0, 0); + QGridLayout * gbCLayout = new QGridLayout(gbColors); - QSignalMapper * mapper = new QSignalMapper(this); + QSignalMapper * mapper = new QSignalMapper(this); - QStandardItemModel * model = DataManager::instance().colorsModel(); + QStandardItemModel * model = DataManager::instance().colorsModel(); - connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onColorModelDataChanged(QModelIndex,QModelIndex))); - for(int i = 0; i < model->rowCount(); ++i) - { + connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onColorModelDataChanged(QModelIndex,QModelIndex))); + for(int i = 0; i < model->rowCount(); ++i) + { + QPushButton * btn = new QPushButton(this); + btn->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + gbCLayout->addWidget(btn, i / 3, i % 3); + btn->setStyleSheet(QString("background: %1").arg(model->item(i)->data().value().name())); + m_colorButtons.append(btn); + connect(btn, SIGNAL(clicked()), mapper, SLOT(map())); + mapper->setMapping(btn, i); + } + + connect(mapper, SIGNAL(mapped(int)), this, SLOT(colorButtonClicked(int))); + QPushButton * btn = new QPushButton(this); - gbCLayout->addWidget(btn); - btn->setStyleSheet(QString("background: %1").arg(model->item(i)->data().value().name())); - m_colorButtons.append(btn); - connect(btn, SIGNAL(clicked()), mapper, SLOT(map())); - mapper->setMapping(btn, i); + gbCLayout->addWidget(btn, (model->rowCount() - 1) / 3 + 1, 0, 1, 3); + btn->setText(tr("Reset to default colors")); + connect(btn, SIGNAL(clicked()), &DataManager::instance(), SLOT(resetColors())); } - connect(mapper, SIGNAL(mapped(int)), this, SLOT(colorButtonClicked(int))); + { + IconedGroupBox * gbMisc = new IconedGroupBox(this); + gbMisc->setIcon(QIcon(":/res/Settings.png")); + gbMisc->setTitle(QGroupBox::tr("Miscellaneous")); + page2Layout->addWidget(gbMisc, 0, 1); + QVBoxLayout * gbCLayout = new QVBoxLayout(gbMisc); + + QHBoxLayout * GBAfpslayout = new QHBoxLayout(0); + QLabel * maxfps = new QLabel(AGGroupBox); + maxfps->setText(QLabel::tr("FPS limit")); + GBAfpslayout->addWidget(maxfps); + fpsedit = new FPSEdit(AGGroupBox); + GBAfpslayout->addWidget(fpsedit); + + CBShowFPS = new QCheckBox(AGGroupBox); + CBShowFPS->setText(QCheckBox::tr("Show FPS")); + GBAfpslayout->addWidget(CBShowFPS); + + gbCLayout->addLayout(GBAfpslayout); + + + WeaponTooltip = new QCheckBox(this); + WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips")); + gbCLayout->addWidget(WeaponTooltip); + + + CBNameWithDate = new QCheckBox(this); + CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name")); + gbCLayout->addWidget(CBNameWithDate); + + BtnAssociateFiles = new QPushButton(this); + BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions")); + BtnAssociateFiles->setVisible(!custom_data && !custom_config); + gbCLayout->addWidget(BtnAssociateFiles); + } + + page2Layout->addWidget(new QWidget(this), 1, 0); } previousQuality = this->SLQuality->value(); @@ -546,6 +570,8 @@ void PageOptions::onColorModelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight) { + Q_UNUSED(bottomRight); + QStandardItemModel * model = DataManager::instance().colorsModel(); m_colorButtons[topLeft.row()]->setStyleSheet(QString("background: %1").arg(model->item(topLeft.row())->data().value().name())); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagesingleplayer.cpp --- a/QTfrontend/ui/page/pagesingleplayer.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui/page/pagesingleplayer.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -48,7 +48,7 @@ BtnCampaignPage = addButton(":/res/Campaign.png", middleLine, 0, true); BtnCampaignPage->setToolTip(tr("Campaign Mode")); BtnCampaignPage->setWhatsThis(tr("Campaign Mode")); - BtnCampaignPage->setVisible(false); + BtnCampaignPage->setVisible(true); BtnTrainPage = addButton(":/res/Trainings.png", middleLine, 1, true); BtnTrainPage->setToolTip(tr("Training Mode")); diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagevideos.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/page/pagevideos.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,1150 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwconsts.h" +#include "pagevideos.h" +#include "igbox.h" +#include "libav_iteraction.h" +#include "gameuiconfig.h" +#include "recorder.h" +#include "ask_quit.h" +#include "upload_video.h" + +static const QSize ThumbnailSize(350, 350*3/5); + +// columns in table with list of video files +enum VideosColumns +{ + vcName, + vcSize, + vcProgress, // either encoding or uploading + + vcNumColumns, +}; + +// this class is used for items in first column in file-table +class VideoItem : public QTableWidgetItem +{ + // note: QTableWidgetItem is not Q_OBJECT + + public: + VideoItem(const QString& name); + ~VideoItem(); + + QString name; + QString prefix; // original filename without extension + QString desc; // description (duration, resolution, etc...) + QString uploadUrl; // http://youtu.be/??????? + HWRecorder * pRecorder; // non NULL if file is being encoded + QNetworkReply * pUploading; // non NULL if file is being uploaded + bool seen; // used when updating directory + float lastSizeUpdate; + float progress; + + bool ready() + { return !pRecorder; } + + QString path() + { return cfgdir->absoluteFilePath("Videos/" + name); } +}; + +VideoItem::VideoItem(const QString& name) + : QTableWidgetItem(name, UserType) +{ + this->name = name; + pRecorder = NULL; + pUploading = NULL; + lastSizeUpdate = 0; + progress = 0; +} + +VideoItem::~VideoItem() +{} + +QLayout * PageVideos::bodyLayoutDefinition() +{ + QGridLayout * pPageLayout = new QGridLayout(); + pPageLayout->setColumnStretch(0, 1); + pPageLayout->setColumnStretch(1, 2); + pPageLayout->setRowStretch(0, 1); + pPageLayout->setRowStretch(1, 1); + + // options + { + IconedGroupBox* pOptionsGroup = new IconedGroupBox(this); + pOptionsGroup->setIcon(QIcon(":/res/Settings.png")); // FIXME + pOptionsGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + pOptionsGroup->setTitle(QGroupBox::tr("Video recording options")); + QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup); + + // label for format + QLabel *labelFormat = new QLabel(pOptionsGroup); + labelFormat->setText(QLabel::tr("Format")); + pOptLayout->addWidget(labelFormat, 0, 0); + + // list of supported formats + comboAVFormats = new QComboBox(pOptionsGroup); + pOptLayout->addWidget(comboAVFormats, 0, 1, 1, 4); + LibavIteraction::instance().fillFormats(comboAVFormats); + + // separator + QFrame * hr = new QFrame(pOptionsGroup); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + pOptLayout->addWidget(hr, 1, 0, 1, 5); + + // label for audio codec + QLabel *labelACodec = new QLabel(pOptionsGroup); + labelACodec->setText(QLabel::tr("Audio codec")); + pOptLayout->addWidget(labelACodec, 2, 0); + + // list of supported audio codecs + comboAudioCodecs = new QComboBox(pOptionsGroup); + pOptLayout->addWidget(comboAudioCodecs, 2, 1, 1, 3); + + // checkbox 'record audio' + checkRecordAudio = new QCheckBox(pOptionsGroup); + checkRecordAudio->setText(QCheckBox::tr("Record audio")); + pOptLayout->addWidget(checkRecordAudio, 2, 4); + + // separator + hr = new QFrame(pOptionsGroup); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + pOptLayout->addWidget(hr, 3, 0, 1, 5); + + // label for video codec + QLabel *labelVCodec = new QLabel(pOptionsGroup); + labelVCodec->setText(QLabel::tr("Video codec")); + pOptLayout->addWidget(labelVCodec, 4, 0); + + // list of supported video codecs + comboVideoCodecs = new QComboBox(pOptionsGroup); + pOptLayout->addWidget(comboVideoCodecs, 4, 1, 1, 4); + + // label for resolution + QLabel *labelRes = new QLabel(pOptionsGroup); + labelRes->setText(QLabel::tr("Resolution")); + pOptLayout->addWidget(labelRes, 5, 0); + + // width + widthEdit = new QLineEdit(pOptionsGroup); + widthEdit->setValidator(new QIntValidator(this)); + pOptLayout->addWidget(widthEdit, 5, 1); + + // x + QLabel *labelX = new QLabel(pOptionsGroup); + labelX->setText("X"); + pOptLayout->addWidget(labelX, 5, 2); + + // height + heightEdit = new QLineEdit(pOptionsGroup); + heightEdit->setValidator(new QIntValidator(pOptionsGroup)); + pOptLayout->addWidget(heightEdit, 5, 3); + + // checkbox 'use game resolution' + checkUseGameRes = new QCheckBox(pOptionsGroup); + checkUseGameRes->setText(QCheckBox::tr("Use game resolution")); + pOptLayout->addWidget(checkUseGameRes, 5, 4); + + // label for framerate + QLabel *labelFramerate = new QLabel(pOptionsGroup); + labelFramerate->setText(QLabel::tr("Framerate")); + pOptLayout->addWidget(labelFramerate, 6, 0); + + // framerate + framerateBox = new QSpinBox(pOptionsGroup); + framerateBox->setRange(1, 200); + framerateBox->setSingleStep(1); + pOptLayout->addWidget(framerateBox, 6, 1); + + // label for Bitrate + QLabel *labelBitrate = new QLabel(pOptionsGroup); + labelBitrate->setText(QLabel::tr("Bitrate (Kbps)")); + pOptLayout->addWidget(labelBitrate, 6, 2); + + // bitrate + bitrateBox = new QSpinBox(pOptionsGroup); + bitrateBox->setRange(100, 5000); + bitrateBox->setSingleStep(100); + pOptLayout->addWidget(bitrateBox, 6, 3); + + // button 'set default options' + btnDefaults = new QPushButton(pOptionsGroup); + btnDefaults->setText(QPushButton::tr("Set default options")); + pOptLayout->addWidget(btnDefaults, 7, 0, 1, 5); + + pPageLayout->addWidget(pOptionsGroup, 1, 0); + } + + // list of videos + { + IconedGroupBox* pTableGroup = new IconedGroupBox(this); + pTableGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME + pTableGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + pTableGroup->setTitle(QGroupBox::tr("Videos")); + + QStringList columns; + columns << tr("Name"); + columns << tr("Size"); + columns << ""; + + filesTable = new QTableWidget(pTableGroup); + filesTable->setColumnCount(vcNumColumns); + filesTable->setHorizontalHeaderLabels(columns); + filesTable->setSelectionBehavior(QAbstractItemView::SelectRows); + filesTable->setSelectionMode(QAbstractItemView::SingleSelection); + filesTable->setEditTriggers(QAbstractItemView::SelectedClicked); + filesTable->verticalHeader()->hide(); + filesTable->setMinimumWidth(400); + + QHeaderView * header = filesTable->horizontalHeader(); + header->setResizeMode(vcName, QHeaderView::ResizeToContents); + header->setResizeMode(vcSize, QHeaderView::Fixed); + header->resizeSection(vcSize, 100); + header->setStretchLastSection(true); + + btnOpenDir = new QPushButton(QPushButton::tr("Open videos directory"), pTableGroup); + + QVBoxLayout *box = new QVBoxLayout(pTableGroup); + box->addWidget(filesTable); + box->addWidget(btnOpenDir); + + pPageLayout->addWidget(pTableGroup, 0, 1, 2, 1); + } + + // description + { + IconedGroupBox* pDescGroup = new IconedGroupBox(this); + pDescGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME + pDescGroup->setTitle(QGroupBox::tr("Description")); + + QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup); + QHBoxLayout* pTopDescLayout = new QHBoxLayout(0); // picture and text + QHBoxLayout* pBottomDescLayout = new QHBoxLayout(0); // buttons + + // label with thumbnail picture + labelThumbnail = new QLabel(pDescGroup); + labelThumbnail->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + labelThumbnail->setMaximumSize(ThumbnailSize); + labelThumbnail->setStyleSheet( + "QFrame {" + "border: solid;" + "border-width: 3px;" + "border-color: #ffcc00;" + "border-radius: 4px;" + "}" ); + clearThumbnail(); + pTopDescLayout->addWidget(labelThumbnail, 2); + + // label with file description + labelDesc = new QLabel(pDescGroup); + labelDesc->setAlignment(Qt::AlignLeft | Qt::AlignTop); + labelDesc->setTextInteractionFlags(Qt::TextSelectableByMouse | + Qt::TextSelectableByKeyboard | + Qt::LinksAccessibleByMouse | + Qt::LinksAccessibleByKeyboard); + labelDesc->setTextFormat(Qt::RichText); + labelDesc->setOpenExternalLinks(true); + pTopDescLayout->addWidget(labelDesc, 1); + + // buttons: play and delete + btnPlay = new QPushButton(QPushButton::tr("Play"), pDescGroup); + btnPlay->setEnabled(false); + pBottomDescLayout->addWidget(btnPlay); + btnDelete = new QPushButton(QPushButton::tr("Delete"), pDescGroup); + btnDelete->setEnabled(false); + pBottomDescLayout->addWidget(btnDelete); + btnToYouTube = new QPushButton(QPushButton::tr("Upload to YouTube"), pDescGroup); + btnToYouTube->setEnabled(false); + pBottomDescLayout->addWidget(btnToYouTube); + + pDescLayout->addStretch(1); + pDescLayout->addLayout(pTopDescLayout, 0); + pDescLayout->addStretch(1); + pDescLayout->addLayout(pBottomDescLayout, 0); + + pPageLayout->addWidget(pDescGroup, 0, 0); + } + + return pPageLayout; +} + +QLayout * PageVideos::footerLayoutDefinition() +{ + return NULL; +} + +void PageVideos::connectSignals() +{ + connect(checkUseGameRes, SIGNAL(stateChanged(int)), this, SLOT(changeUseGameRes(int))); + connect(checkRecordAudio, SIGNAL(stateChanged(int)), this, SLOT(changeRecordAudio(int))); + connect(comboAVFormats, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAVFormat(int))); + connect(btnDefaults, SIGNAL(clicked()), this, SLOT(setDefaultOptions())); + connect(filesTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(cellDoubleClicked(int, int))); + connect(filesTable, SIGNAL(cellChanged(int,int)), this, SLOT(cellChanged(int, int))); + connect(filesTable, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(currentCellChanged())); + connect(btnPlay, SIGNAL(clicked()), this, SLOT(playSelectedFile())); + connect(btnDelete, SIGNAL(clicked()), this, SLOT(deleteSelectedFiles())); + connect(btnToYouTube, SIGNAL(clicked()), this, SLOT(uploadToYouTube())); + connect(btnOpenDir, SIGNAL(clicked()), this, SLOT(openVideosDirectory())); +} + +PageVideos::PageVideos(QWidget* parent) : AbstractPage(parent), + config(0), netManager(0) +{ + nameChangedFromCode = false; + numRecorders = 0; + numUploads = 0; + initPage(); +} + +void PageVideos::init(GameUIConfig * config) +{ + this->config = config; + + QString path = cfgdir->absolutePath() + "/Videos"; + QFileSystemWatcher * pWatcher = new QFileSystemWatcher(this); + pWatcher->addPath(path); + connect(pWatcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(updateFileList(const QString &))); + updateFileList(path); + + startEncoding(); // this is for videos recorded from demos which were executed directly (without frontend) +} + +// user changed file format, we need to update list of codecs +void PageVideos::changeAVFormat(int index) +{ + // remember selected codecs + QString prevVCodec = videoCodec(); + QString prevACodec = audioCodec(); + + // clear lists of codecs + comboVideoCodecs->clear(); + comboAudioCodecs->clear(); + + // get list of codecs for specified format + LibavIteraction::instance().fillCodecs(comboAVFormats->itemData(index).toString(), comboVideoCodecs, comboAudioCodecs); + + // disable audio if there is no audio codec + if (comboAudioCodecs->count() == 0) + { + checkRecordAudio->setChecked(false); + checkRecordAudio->setEnabled(false); + } + else + checkRecordAudio->setEnabled(true); + + // restore selected codecs if possible + int iVCodec = comboVideoCodecs->findData(prevVCodec); + if (iVCodec != -1) + comboVideoCodecs->setCurrentIndex(iVCodec); + int iACodec = comboAudioCodecs->findData(prevACodec); + if (iACodec != -1) + comboAudioCodecs->setCurrentIndex(iACodec); +} + +// user switched checkbox 'use game resolution' +void PageVideos::changeUseGameRes(int state) +{ + if (state && config) + { + // set resolution to game resolution + QRect resolution = config->vid_Resolution(); + widthEdit->setText(QString::number(resolution.width())); + heightEdit->setText(QString::number(resolution.height())); + } + widthEdit->setEnabled(!state); + heightEdit->setEnabled(!state); +} + +// user switched checkbox 'record audio' +void PageVideos::changeRecordAudio(int state) +{ + comboAudioCodecs->setEnabled(!!state); +} + +void PageVideos::setDefaultCodecs() +{ + if (tryCodecs("mp4", "libx264", "libmp3lame")) + return; + if (tryCodecs("mp4", "libx264", "libfaac")) + return; + if (tryCodecs("mp4", "libx264", "libvo_aacenc")) + return; + if (tryCodecs("mp4", "libx264", "aac")) + return; + if (tryCodecs("mp4", "libx264", "mp2")) + return; + if (tryCodecs("avi", "libxvid", "libmp3lame")) + return; + if (tryCodecs("avi", "libxvid", "ac3_fixed")) + return; + if (tryCodecs("avi", "libxvid", "mp2")) + return; + if (tryCodecs("avi", "mpeg4", "libmp3lame")) + return; + if (tryCodecs("avi", "mpeg4", "ac3_fixed")) + return; + if (tryCodecs("avi", "mpeg4", "mp2")) + return; + + // this shouldn't happen, just in case + if (tryCodecs("ogg", "libtheora", "libvorbis")) + return; + tryCodecs("ogg", "libtheora", "flac"); +} + +void PageVideos::setDefaultOptions() +{ + framerateBox->setValue(25); + bitrateBox->setValue(400); + checkRecordAudio->setChecked(true); + checkUseGameRes->setChecked(true); + setDefaultCodecs(); +} + +bool PageVideos::tryCodecs(const QString & format, const QString & vcodec, const QString & acodec) +{ + // first we should change format + int iFormat = comboAVFormats->findData(format); + if (iFormat == -1) + return false; + comboAVFormats->setCurrentIndex(iFormat); + // format was changed, so lists of codecs were automatically updated to codecs supported by this format + + // try to find video codec + int iVCodec = comboVideoCodecs->findData(vcodec); + if (iVCodec == -1) + return false; + comboVideoCodecs->setCurrentIndex(iVCodec); + + // try to find audio codec + int iACodec = comboAudioCodecs->findData(acodec); + if (iACodec == -1 && checkRecordAudio->isChecked()) + return false; + if (iACodec != -1) + comboAudioCodecs->setCurrentIndex(iACodec); + + return true; +} + +// get file size as string +static QString FileSizeStr(const QString & path) +{ + quint64 size = QFileInfo(path).size(); + + quint64 KiB = 1024; + quint64 MiB = 1024*KiB; + quint64 GiB = 1024*MiB; + QString sizeStr; + if (size >= GiB) + return QString("%1 GiB").arg(QString::number(float(size)/GiB, 'f', 2)); + if (size >= MiB) + return QString("%1 MiB").arg(QString::number(float(size)/MiB, 'f', 2)); + if (size >= KiB) + return QString("%1 KiB").arg(QString::number(float(size)/KiB, 'f', 2)); + return PageVideos::tr("%1 bytes", "", size).arg(QString::number(size)); +} + +// set file size in file list in specified row +void PageVideos::updateSize(int row) +{ + VideoItem * item = nameItem(row); + QString path = item->ready()? item->path() : cfgdir->absoluteFilePath("VideoTemp/" + item->pRecorder->name); + filesTable->item(row, vcSize)->setText(FileSizeStr(path)); +} + +// There is a button 'Open videos dir', so it is possible that user will open +// this dir and rename/delete some files there, so we should handle this. +void PageVideos::updateFileList(const QString & path) +{ + // mark all files as non seen + int numRows = filesTable->rowCount(); + for (int i = 0; i < numRows; i++) + nameItem(i)->seen = false; + + QStringList files = QDir(path).entryList(QDir::Files); + foreach (const QString & name, files) + { + int row = -1; + foreach (QTableWidgetItem * item, filesTable->findItems(name, Qt::MatchExactly)) + { + if (item->type() != QTableWidgetItem::UserType || !((VideoItem*)item)->ready()) + continue; + row = item->row(); + break; + } + if (row == -1) + row = appendRow(name); + VideoItem * item = nameItem(row); + item->seen = true; + item->desc = ""; + updateSize(row); + } + + // remove all non seen files + for (int i = 0; i < filesTable->rowCount();) + { + VideoItem * item = nameItem(i); + if (item->ready() && !item->seen) + filesTable->removeRow(i); + else + i++; + } +} + +void PageVideos::addRecorder(HWRecorder* pRecorder) +{ + int row = appendRow(pRecorder->name); + VideoItem * item = nameItem(row); + item->pRecorder = pRecorder; + pRecorder->item = item; + + // add progress bar + QProgressBar * progressBar = new QProgressBar(filesTable); + progressBar->setMinimum(0); + progressBar->setMaximum(10000); + progressBar->setValue(0); + connect(pRecorder, SIGNAL(onProgress(float)), this, SLOT(updateProgress(float))); + connect(pRecorder, SIGNAL(encodingFinished(bool)), this, SLOT(encodingFinished(bool))); + filesTable->setCellWidget(row, vcProgress, progressBar); + + numRecorders++; +} + +void PageVideos::setProgress(int row, VideoItem* item, float value) +{ + QProgressBar * progressBar = (QProgressBar*)filesTable->cellWidget(row, vcProgress); + progressBar->setValue(value*10000); + progressBar->setFormat(QString("%1%").arg(value*100, 0, 'f', 2)); + item->progress = value; +} + +void PageVideos::updateProgress(float value) +{ + HWRecorder * pRecorder = (HWRecorder*)sender(); + VideoItem * item = pRecorder->item; + int row = filesTable->row(item); + + // update file size every percent + if (value - item->lastSizeUpdate > 0.01) + { + updateSize(row); + item->lastSizeUpdate = value; + } + + setProgress(row, item, value); +} + +void PageVideos::encodingFinished(bool success) +{ + numRecorders--; + + HWRecorder * pRecorder = (HWRecorder*)sender(); + VideoItem * item = (VideoItem*)pRecorder->item; + int row = filesTable->row(item); + + if (success) + { + // move file to destination + success = cfgdir->rename("VideoTemp/" + pRecorder->name, "Videos/" + item->name); + if (!success) + { + // unable to rename for some reason (maybe user entered incorrect name); + // try to use temp name instead. + success = cfgdir->rename("VideoTemp/" + pRecorder->name, "Videos/" + pRecorder->name); + if (success) + setName(item, pRecorder->name); + } + } + + if (!success) + { + filesTable->removeRow(row); + return; + } + + filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar + item->pRecorder = NULL; + updateSize(row); + updateDescription(); +} + +void PageVideos::cellDoubleClicked(int row, int column) +{ + Q_UNUSED(column); + + play(row); +} + +void PageVideos::cellChanged(int row, int column) +{ + // user can only edit name + if (column != vcName || nameChangedFromCode) + return; + + // user has edited filename, so we should rename the file + VideoItem * item = nameItem(row); + QString oldName = item->name; + QString newName = item->text(); + if (!newName.contains('.')) // user forgot an extension + { + // restore old extension + int pt = oldName.lastIndexOf('.'); + if (pt != -1) + { + newName += oldName.right(oldName.length() - pt); + setName(item, newName); + } + } +#ifdef Q_WS_WIN + // there is a bug in qt, QDir::rename() doesn't fail on such names but damages files + if (newName.contains(QRegExp("[\"*:<>?\/|]"))) + { + setName(item, oldName); + return; + } +#endif + if (item->ready() && !cfgdir->rename("Videos/" + oldName, "Videos/" + newName)) + { + // unable to rename for some reason (maybe user entered incorrect name), + // therefore restore old name in cell + setName(item, oldName); + return; + } + item->name = newName; + updateDescription(); +} + +void PageVideos::setName(VideoItem * item, const QString & newName) +{ + nameChangedFromCode = true; + item->setText(newName); + nameChangedFromCode = false; + item->name = newName; +} + +int PageVideos::appendRow(const QString & name) +{ + int row = filesTable->rowCount(); + filesTable->setRowCount(row+1); + + // add 'name' item + QTableWidgetItem * item = new VideoItem(name); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); + nameChangedFromCode = true; + filesTable->setItem(row, vcName, item); + nameChangedFromCode = false; + + // add 'size' item + item = new QTableWidgetItem(); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + item->setTextAlignment(Qt::AlignRight); + filesTable->setItem(row, vcSize, item); + + // add 'progress' item + item = new QTableWidgetItem(); + item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + filesTable->setItem(row, vcProgress, item); + + return row; +} + +VideoItem* PageVideos::nameItem(int row) +{ + return (VideoItem*)filesTable->item(row, vcName); +} + +void PageVideos::clearThumbnail() +{ + // add empty (transparent) image for proper sizing + QPixmap pic(ThumbnailSize); + pic.fill(QColor(0,0,0,0)); + labelThumbnail->setPixmap(pic); +} + +void PageVideos::updateDescription() +{ + VideoItem * item = nameItem(filesTable->currentRow()); + if (!item) + { + // nothing is selected => clear description and return + labelDesc->clear(); + clearThumbnail(); + btnPlay->setEnabled(false); + btnDelete->setEnabled(false); + btnToYouTube->setEnabled(false); + return; + } + + btnPlay->setEnabled(item->ready()); + btnToYouTube->setEnabled(item->ready()); + btnDelete->setEnabled(true); + btnDelete->setText(item->ready()? QPushButton::tr("Delete") : QPushButton::tr("Cancel")); + btnToYouTube->setText(item->pUploading? QPushButton::tr("Cancel uploading") : QPushButton::tr("Upload to YouTube")); + + // construct string with desctiption of this file to display it + QString desc = item->name + "\n\n"; + + if (!item->ready()) + desc += tr("(in progress...)"); + else + { + QString path = item->path(); + desc += tr("Date: ") + QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate) + '\n'; + desc += tr("Size: ") + FileSizeStr(path) + '\n'; + if (item->desc.isEmpty()) + { + // Extract description from file; + // It will contain duration, resolution, etc and also comment added by hwengine. + item->desc = LibavIteraction::instance().getFileInfo(path); + + // extract prefix (original name) from description (it is enclosed in prefix[???]prefix) + int prefixBegin = item->desc.indexOf("prefix["); + int prefixEnd = item->desc.indexOf("]prefix"); + if (prefixBegin != -1 && prefixEnd != -1) + { + item->prefix = item->desc.mid(prefixBegin + 7, prefixEnd - (prefixBegin + 7)); + item->desc.remove(prefixBegin, prefixEnd + 7 - prefixBegin); + } + } + desc += item->desc + '\n'; + } + + if (item->prefix.isEmpty()) + { + // try to extract prefix from file name instead + if (item->ready()) + item->prefix = item->name; + else + item->prefix = item->pRecorder->name; + + // remove extension + int pt = item->prefix.lastIndexOf('.'); + if (pt != -1) + item->prefix.truncate(pt); + } + + if (item->ready() && item->uploadUrl.isEmpty()) + { + // try to load url from file + QFile * file = new QFile(cfgdir->absoluteFilePath("VideoTemp/" + item->prefix + "-url.txt"), this); + if (!file->open(QIODevice::ReadOnly)) + item->uploadUrl = "no"; + else + { + QByteArray data = file->readAll(); + file->close(); + item->uploadUrl = QString::fromUtf8(data.data()); + } + } + if (item->uploadUrl != "no") + desc += QString("%1").arg(item->uploadUrl); + desc.replace("\n", "
"); + + labelDesc->setText(desc); + + if (!item->prefix.isEmpty()) + { + QString thumbName = cfgdir->absoluteFilePath("VideoTemp/" + item->prefix); + QPixmap pic; + if (pic.load(thumbName + ".png") || pic.load(thumbName + ".bmp")) + { + if (pic.height()*ThumbnailSize.width() > pic.width()*ThumbnailSize.height()) + pic = pic.scaledToWidth(ThumbnailSize.width()); + else + pic = pic.scaledToHeight(ThumbnailSize.height()); + labelThumbnail->setPixmap(pic); + } + else + clearThumbnail(); + } +} + +// user selected another cell, so we should change description +void PageVideos::currentCellChanged() +{ + updateDescription(); +} + +// open video file in external media player +void PageVideos::play(int row) +{ + VideoItem * item = nameItem(row); + if (item && item->ready()) + QDesktopServices::openUrl(QUrl("file:///" + QDir::toNativeSeparators(item->path()))); +} + +void PageVideos::playSelectedFile() +{ + int index = filesTable->currentRow(); + if (index != -1) + play(index); +} + +void PageVideos::deleteSelectedFiles() +{ + int index = filesTable->currentRow(); + if (index == -1) + return; + + VideoItem * item = nameItem(index); + if (!item) + return; + + // ask user if (s)he is serious + if (QMessageBox::question(this, + tr("Are you sure?"), + tr("Do you really want do remove %1?").arg(item->name), + QMessageBox::Yes | QMessageBox::No) + != QMessageBox::Yes) + return; + + // remove + if (!item->ready()) + item->pRecorder->deleteLater(); + else + cfgdir->remove("Videos/" + item->name); + +// this code is for removing several files when multiple selection is enabled +#if 0 + QList items = filesTable->selectedItems(); + int num = items.size() / vcNumColumns; + if (num == 0) + return; + + // ask user if (s)he is serious + if (QMessageBox::question(this, + tr("Are you sure?"), + tr("Do you really want do remove %1 file(s)?", "", num).arg(num), + QMessageBox::Yes | QMessageBox::No) + != QMessageBox::Yes) + return; + + // remove + foreach (QTableWidgetItem * witem, items) + { + if (witem->type() != QTableWidgetItem::UserType) + continue; + VideoItem * item = (VideoItem*)witem; + if (!item->ready()) + item->pRecorder->deleteLater(); + else + cfgdir->remove("Videos/" + item->name); + } +#endif +} + +void PageVideos::keyPressEvent(QKeyEvent * pEvent) +{ + if (filesTable->hasFocus()) + { + if (pEvent->key() == Qt::Key_Delete) + { + deleteSelectedFiles(); + return; + } + if (pEvent->key() == Qt::Key_Enter) // doesn't work + { + playSelectedFile(); + return; + } + } + AbstractPage::keyPressEvent(pEvent); +} + +void PageVideos::openVideosDirectory() +{ + QString path = QDir::toNativeSeparators(cfgdir->absolutePath() + "/Videos"); + QDesktopServices::openUrl(QUrl("file:///" + path)); +} + +// clear VideoTemp directory (except for thumbnails and upload links) +void PageVideos::clearTemp() +{ + QDir temp(cfgdir->absolutePath() + "/VideoTemp"); + QStringList files = temp.entryList(QDir::Files); + foreach (const QString& file, files) + { + if (!file.endsWith(".bmp") && !file.endsWith(".png") && !file.endsWith("-url.txt")) + temp.remove(file); + } +} + +bool PageVideos::tryQuit(HWForm * form) +{ + bool quit = true; + if (numRecorders != 0 || numUploads != 0) + { + // ask user what to do - abort or wait + HWAskQuitDialog * askd = new HWAskQuitDialog(this, form); + askd->deleteLater(); + quit = askd->exec(); + } + if (quit) + clearTemp(); + return quit; +} + +// returns multi-line string with list of videos in progress +/* it will look like this: +foo.avi (15.21% - encoding) +bar.avi (18.21% - uploading) +*/ +QString PageVideos::getVideosInProgress() +{ + QString list = ""; + int count = filesTable->rowCount(); + for (int i = 0; i < count; i++) + { + VideoItem * item = nameItem(i); + QString process; + if (!item->ready()) + process = tr("encoding"); + else if (item->pUploading) + process = tr("uploading"); + else + continue; + float progress = 100*item->progress; + if (progress > 99.99) + progress = 99.99; // displaying 100% may be confusing + list += item->name + " (" + QString::number(progress, 'f', 2) + "% - " + process + ")\n"; + } + return list; +} + +void PageVideos::startEncoding(const QByteArray & record) +{ + QDir videoTempDir(cfgdir->absolutePath() + "/VideoTemp/"); + QStringList files = videoTempDir.entryList(QStringList("*.txtout"), QDir::Files); + foreach (const QString & str, files) + { + QString prefix = str; + prefix.chop(7); // remove ".txtout" + videoTempDir.rename(prefix + ".txtout", prefix + ".txtin"); // rename this file to not open it twice + + HWRecorder* pRecorder = new HWRecorder(config, prefix); + + if (!record.isEmpty()) + pRecorder->EncodeVideo(record); + else + { + // this is for videos recorded from demos which were executed directly (without frontend) + QFile demofile(videoTempDir.absoluteFilePath(prefix + ".hwd")); + if (!demofile.open(QIODevice::ReadOnly)) + continue; + QByteArray demo = demofile.readAll(); + if (demo.isEmpty()) + continue; + pRecorder->EncodeVideo(demo); + } + addRecorder(pRecorder); + } +} + +VideoItem * PageVideos::itemFromReply(QNetworkReply* reply, int & row) +{ + VideoItem * item = NULL; + int count = filesTable->rowCount(); + // find corresponding item (maybe there is a better way to implement this?) + for (int i = 0; i < count; i++) + { + item = nameItem(i); + if (item->pUploading == reply) + { + row = i; + break; + } + } + return item; +} + +void PageVideos::uploadProgress(qint64 bytesSent, qint64 bytesTotal) +{ + QNetworkReply* reply = (QNetworkReply*)sender(); + int row; + VideoItem * item = itemFromReply(reply, row); + setProgress(row, item, bytesSent*1.0/bytesTotal); +} + +void PageVideos::uploadFinished() +{ + QNetworkReply* reply = (QNetworkReply*)sender(); + reply->deleteLater(); + + int row; + VideoItem * item = itemFromReply(reply, row); + if (!item) + return; + + item->pUploading = NULL; + + // extract video id from reply + QString videoid; + QXmlStreamReader xml(reply); + while (!xml.atEnd()) + { + xml.readNext(); + if (xml.qualifiedName() == "yt:videoid") + { + videoid = xml.readElementText(); + break; + } + } + + if (!videoid.isEmpty()) + { + item->uploadUrl = "http://youtu.be/" + videoid; + updateDescription(); + + // save url in file + QFile * file = new QFile(cfgdir->absoluteFilePath("VideoTemp/" + item->prefix + "-url.txt"), this); + if (file->open(QIODevice::WriteOnly)) + { + file->write(item->uploadUrl.toUtf8()); + file->close(); + } + } + + filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar + numUploads--; +} + +// this will protect saved youtube password from those who cannot read source code +static QString protectPass(QString str) +{ + QByteArray array = str.toUtf8(); + for (int i = 0; i < array.size(); i++) + array[i] = array[i] ^ 0xC4 ^ i; + array = array.toBase64(); + return QString::fromAscii(array.data()); +} + +static QString unprotectPass(QString str) +{ + QByteArray array = QByteArray::fromBase64(str.toAscii()); + for (int i = 0; i < array.size(); i++) + array[i] = array[i] ^ 0xC4 ^ i; + return QString::fromUtf8(array); +} + +void PageVideos::uploadToYouTube() +{ + int row = filesTable->currentRow(); + VideoItem * item = nameItem(row); + + if (item->pUploading) + { + if (QMessageBox::question(this, + tr("Are you sure?"), + tr("Do you really want do cancel uploading %1?").arg(item->name), + QMessageBox::Yes | QMessageBox::No) + != QMessageBox::Yes) + return; + item->pUploading->deleteLater(); + filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar + numUploads--; + return; + } + + if (!netManager) + netManager = new QNetworkAccessManager(this); + + HWUploadVideoDialog* dlg = new HWUploadVideoDialog(this, item->name, netManager); + dlg->deleteLater(); + if (config->value("youtube/save").toBool()) + { + dlg->cbSave->setChecked(true); + dlg->leAccount->setText(config->value("youtube/name").toString()); + dlg->lePassword->setText(unprotectPass(config->value("youtube/pswd").toString())); + } + + bool result = dlg->exec(); + + if (dlg->cbSave->isChecked()) + { + config->setValue("youtube/save", true); + config->setValue("youtube/name", dlg->leAccount->text()); + config->setValue("youtube/pswd", protectPass(dlg->lePassword->text())); + } + else + { + config->setValue("youtube/save", false); + config->setValue("youtube/name", ""); + config->setValue("youtube/pswd", ""); + } + + if (!result) + return; + + QNetworkRequest request(QUrl(dlg->location)); + request.setRawHeader("Content-Type", "application/octet-stream"); + + QFile * file = new QFile(item->path(), this); + if (!file->open(QIODevice::ReadOnly)) + return; + + // add progress bar + QProgressBar * progressBar = new QProgressBar(filesTable); + progressBar->setMinimum(0); + progressBar->setMaximum(10000); + progressBar->setValue(0); + // make it different from progress-bar used during encoding (use blue color) + progressBar->setStyleSheet("* {color: #00ccff; selection-background-color: #00ccff;}" ); + filesTable->setCellWidget(row, vcProgress, progressBar); + + QNetworkReply* reply = netManager->put(request, file); + file->setParent(reply); // automatically close file when needed + item->pUploading = reply; + connect(reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64))); + connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished())); + numUploads++; + + updateDescription(); +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui/page/pagevideos.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/ui/page/pagevideos.h Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,126 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef PAGE_VIDEOS_H +#define PAGE_VIDEOS_H + +#include "AbstractPage.h" + +class QNetworkAccessManager; +class QNetworkReply; +class GameUIConfig; +class HWRecorder; +class VideoItem; +class HWForm; + +class PageVideos : public AbstractPage +{ + Q_OBJECT + + public: + PageVideos(QWidget* parent = 0); + + QSpinBox *framerateBox; + QSpinBox *bitrateBox; + QLineEdit *widthEdit; + QLineEdit *heightEdit; + QCheckBox *checkUseGameRes; + QCheckBox *checkRecordAudio; + + QString format() + { return comboAVFormats->itemData(comboAVFormats->currentIndex()).toString(); } + + QString videoCodec() + { return comboVideoCodecs->itemData(comboVideoCodecs->currentIndex()).toString(); } + + QString audioCodec() + { return comboAudioCodecs->itemData(comboAudioCodecs->currentIndex()).toString(); } + + void setDefaultCodecs(); + bool tryCodecs(const QString & format, const QString & vcodec, const QString & acodec); + void addRecorder(HWRecorder* pRecorder); + bool tryQuit(HWForm *form); + QString getVideosInProgress(); // get multi-line string with list of videos in progress + void startEncoding(const QByteArray & record = QByteArray()); + void init(GameUIConfig * config); + + private: + // virtuals from AbstractPage + QLayout * bodyLayoutDefinition(); + QLayout * footerLayoutDefinition(); + void connectSignals(); + + // virtual from QWidget + void keyPressEvent(QKeyEvent * pEvent); + + void setName(VideoItem * item, const QString & newName); + void updateSize(int row); + int appendRow(const QString & name); + VideoItem* nameItem(int row); + void play(int row); + void updateDescription(); + void clearTemp(); + void clearThumbnail(); + void setProgress(int row, VideoItem* item, float value); + VideoItem * itemFromReply(QNetworkReply* reply, int & row); + + GameUIConfig * config; + QNetworkAccessManager* netManager; + + // options group + QComboBox *comboAVFormats; + QComboBox *comboVideoCodecs; + QComboBox *comboAudioCodecs; + QPushButton *btnDefaults; + + // file list group + QTableWidget *filesTable; + QPushButton *btnOpenDir; + + // description group + QPushButton *btnPlay, *btnDelete, *btnToYouTube; + QLabel *labelDesc; + QLabel *labelThumbnail; + + // this flag is used to distinguish if cell was changed from code or by user + // (in signal cellChanged) + bool nameChangedFromCode; + + int numRecorders, numUploads; + + private slots: + void changeAVFormat(int index); + void changeUseGameRes(int state); + void changeRecordAudio(int state); + void setDefaultOptions(); + void encodingFinished(bool success); + void updateProgress(float value); + void cellDoubleClicked(int row, int column); + void cellChanged(int row, int column); + void currentCellChanged(); + void playSelectedFile(); + void deleteSelectedFiles(); + void openVideosDirectory(); + void updateFileList(const QString & path); + void uploadToYouTube(); + void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + void uploadFinished(); +}; + +#endif // PAGE_VIDEOS_H diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui_hwform.cpp --- a/QTfrontend/ui_hwform.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui_hwform.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -46,6 +46,7 @@ #include "pagegamestats.h" #include "pageplayrecord.h" #include "pagedata.h" +#include "pagevideos.h" #include "hwconsts.h" void Ui_HWForm::setupUi(HWForm *HWForm) @@ -145,4 +146,7 @@ pageFeedback = new PageFeedback(); Pages->addWidget(pageFeedback); + + pageVideos = new PageVideos(); + Pages->addWidget(pageVideos); } diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/ui_hwform.h --- a/QTfrontend/ui_hwform.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/ui_hwform.h Sun Sep 16 16:54:51 2012 +0200 @@ -43,6 +43,7 @@ class PageAdmin; class PageNetType; class PageDrawMap; +class PageVideos; class QStackedLayout; class QFont; class QWidget; @@ -78,6 +79,7 @@ PageNetType *pageNetType; PageCampaign *pageCampaign; PageDrawMap *pageDrawMap; + PageVideos *pageVideos; QStackedLayout *Pages; QFont *font14; diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/util/DataManager.cpp --- a/QTfrontend/util/DataManager.cpp Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/util/DataManager.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -207,3 +207,11 @@ m_themeModel->loadThemes(); emit updated(); } + +void DataManager::resetColors() +{ + for(int i = colorsModel()->rowCount() - 1; i >= 0; --i) + { + m_colorsModel->item(i)->setData(QColor(colors[i])); + } +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/util/DataManager.h --- a/QTfrontend/util/DataManager.h Mon Aug 27 17:40:16 2012 +0200 +++ b/QTfrontend/util/DataManager.h Sun Sep 16 16:54:51 2012 +0200 @@ -133,6 +133,7 @@ public slots: /// Reloads data from storage. void reload(); + void resetColors(); signals: diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/util/libav_iteraction.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/util/libav_iteraction.cpp Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,358 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "libav_iteraction.h" + +#if VIDEOREC +#define __STDC_CONSTANT_MACROS +extern "C" +{ +#include "libavformat/avformat.h" +} + +#include +#include +#include +#include + +#include "HWApplication.h" + +struct Codec +{ + CodecID id; + bool isAudio; + QString shortName; // used for identification + QString longName; // used for displaying to user + bool isRecomended; +}; + +struct Format +{ + QString shortName; + QString longName; + bool isRecomended; + QString extension; + QVector codecs; +}; + +QList codecs; +QMap formats; + +// test if given format supports given codec +bool FormatQueryCodec(AVOutputFormat *ofmt, enum CodecID codec_id) +{ +#if LIBAVFORMAT_VERSION_MAJOR >= 54 + return avformat_query_codec(ofmt, codec_id, FF_COMPLIANCE_NORMAL) == 1; +#else + if (ofmt->codec_tag) + return !!av_codec_get_tag(ofmt->codec_tag, codec_id); + return codec_id == ofmt->video_codec || codec_id == ofmt->audio_codec; +#endif +} + +LibavIteraction::LibavIteraction() : QObject() +{ + // initialize libav and register all codecs and formats + av_register_all(); + + // get list of all codecs + AVCodec* pCodec = NULL; + while (pCodec = av_codec_next(pCodec)) + { +#if LIBAVCODEC_VERSION_MAJOR >= 54 + if (!av_codec_is_encoder(pCodec)) +#else + if (!pCodec->encode) +#endif + continue; + + if (pCodec->type != AVMEDIA_TYPE_VIDEO && pCodec->type != AVMEDIA_TYPE_AUDIO) + continue; + + // this encoders seems to be buggy + if (strcmp(pCodec->name, "rv10") == 0 || strcmp(pCodec->name, "rv20") == 0) + continue; + + // doesn't support stereo sound + if (strcmp(pCodec->name, "real_144") == 0) + continue; + + if (!pCodec->long_name || strlen(pCodec->long_name) == 0) + continue; + + if (pCodec->type == AVMEDIA_TYPE_VIDEO) + { + if (pCodec->supported_framerates != NULL) + continue; + + // check if codec supports yuv 4:2:0 format + if (!pCodec->pix_fmts) + continue; + bool yuv420Supported = false; + for (const PixelFormat* pfmt = pCodec->pix_fmts; *pfmt != -1; pfmt++) + if (*pfmt == PIX_FMT_YUV420P) + { + yuv420Supported = true; + break; + } + if (!yuv420Supported) + continue; + } + if (pCodec->type == AVMEDIA_TYPE_AUDIO) + { + // check if codec supports signed 16-bit format + if (!pCodec->sample_fmts) + continue; + bool s16Supported = false; + for (const AVSampleFormat* pfmt = pCodec->sample_fmts; *pfmt != -1; pfmt++) + if (*pfmt == AV_SAMPLE_FMT_S16) + { + s16Supported = true; + break; + } + if (!s16Supported) + continue; + } + // add codec to list of codecs + codecs.push_back(Codec()); + Codec & codec = codecs.back(); + codec.id = pCodec->id; + codec.isAudio = pCodec->type == AVMEDIA_TYPE_AUDIO; + codec.shortName = pCodec->name; + codec.longName = pCodec->long_name; + + codec.isRecomended = false; + if (strcmp(pCodec->name, "libx264") == 0) + { + codec.longName = "H.264/MPEG-4 Part 10 AVC (x264)"; + codec.isRecomended = true; + } + else if (strcmp(pCodec->name, "libxvid") == 0) + { + codec.longName = "MPEG-4 Part 2 (Xvid)"; + codec.isRecomended = true; + } + else if (strcmp(pCodec->name, "libmp3lame") == 0) + { + codec.longName = "MP3 (MPEG audio layer 3) (LAME)"; + codec.isRecomended = true; + } + else + codec.longName = pCodec->long_name; + + if (strcmp(pCodec->name, "mpeg4") == 0 || strcmp(pCodec->name, "ac3_fixed") == 0) + codec.isRecomended = true; + + // FIXME: remove next line + //codec.longName += QString(" (%1)").arg(codec.shortName); + } + + // get list of all formats + AVOutputFormat* pFormat = NULL; + while (pFormat = av_oformat_next(pFormat)) + { + if (!pFormat->extensions) + continue; + + // skip some strange formats to not confuse users + if (strstr(pFormat->long_name, "raw")) + continue; + + Format format; + bool hasVideoCodec = false; + for (QList::iterator codec = codecs.begin(); codec != codecs.end(); ++codec) + { + if (!FormatQueryCodec(pFormat, codec->id)) + continue; + format.codecs.push_back(&*codec); + if (!codec->isAudio) + hasVideoCodec = true; + } + if (!hasVideoCodec) + continue; + + QString ext(pFormat->extensions); + ext.truncate(strcspn(pFormat->extensions, ",")); + format.extension = ext; + format.shortName = pFormat->name; + format.longName = QString("%1 (*.%2)").arg(pFormat->long_name).arg(ext); + + // FIXME: remove next line + //format.longName += QString(" (%1)").arg(format.shortName); + + format.isRecomended = strcmp(pFormat->name, "mp4") == 0 || strcmp(pFormat->name, "avi") == 0; + + formats[pFormat->name] = format; + } +} + +void LibavIteraction::fillFormats(QComboBox * pFormats) +{ + // first insert recomended formats + foreach(const Format & format, formats) + if (format.isRecomended) + pFormats->addItem(format.longName, format.shortName); + + // remember where to place separator between recomended and other formats + int sep = pFormats->count(); + + // insert remaining formats + foreach(const Format & format, formats) + if (!format.isRecomended) + pFormats->addItem(format.longName, format.shortName); + + // insert separator if necessary + if (sep != 0 && sep != pFormats->count()) + pFormats->insertSeparator(sep); +} + +void LibavIteraction::fillCodecs(const QString & fmt, QComboBox * pVCodecs, QComboBox * pACodecs) +{ + Format & format = formats[fmt]; + + // first insert recomended codecs + foreach(Codec * codec, format.codecs) + { + if (codec->isRecomended) + { + if (codec->isAudio) + pACodecs->addItem(codec->longName, codec->shortName); + else + pVCodecs->addItem(codec->longName, codec->shortName); + } + } + + // remember where to place separators between recomended and other codecs + int vsep = pVCodecs->count(); + int asep = pACodecs->count(); + + // insert remaining codecs + foreach(Codec * codec, format.codecs) + { + if (!codec->isRecomended) + { + if (codec->isAudio) + pACodecs->addItem(codec->longName, codec->shortName); + else + pVCodecs->addItem(codec->longName, codec->shortName); + } + } + + // insert separators if necessary + if (vsep != 0 && vsep != pVCodecs->count()) + pVCodecs->insertSeparator(vsep); + if (asep != 0 && asep != pACodecs->count()) + pACodecs->insertSeparator(asep); +} + +QString LibavIteraction::getExtension(const QString & format) +{ + return formats[format].extension; +} + +// get information abaout file (duration, resolution etc) in multiline string +QString LibavIteraction::getFileInfo(const QString & filepath) +{ + AVFormatContext* pContext = NULL; + QByteArray utf8path = filepath.toUtf8(); + if (avformat_open_input(&pContext, utf8path.data(), NULL, NULL) < 0) + return ""; +#if LIBAFORMAT_VERSION_MAJOR < 54 + if (av_find_stream_info(pContext) < 0) +#else + if (avformat_find_stream_info(pContext, NULL) < 0) +#endif + return ""; + + int s = float(pContext->duration)/AV_TIME_BASE; + QString desc = QString(tr("Duration: %1m %2s\n")).arg(s/60).arg(s%60); + for (int i = 0; i < (int)pContext->nb_streams; i++) + { + AVStream* pStream = pContext->streams[i]; + if (!pStream) + continue; + AVCodecContext* pCodec = pContext->streams[i]->codec; + if (!pCodec) + continue; + + if (pCodec->codec_type == AVMEDIA_TYPE_VIDEO) + { + desc += QString(tr("Video: %1x%2, ")).arg(pCodec->width).arg(pCodec->height); + if (pStream->avg_frame_rate.den) + { + float fps = float(pStream->avg_frame_rate.num)/pStream->avg_frame_rate.den; + desc += QString(tr("%1 fps, ")).arg(fps, 0, 'f', 2); + } + } + else if (pCodec->codec_type == AVMEDIA_TYPE_AUDIO) + desc += tr("Audio: "); + else + continue; + AVCodec* pDecoder = avcodec_find_decoder(pCodec->codec_id); + desc += pDecoder? pDecoder->name : "unknown"; + desc += "\n"; + } + AVDictionaryEntry* pComment = av_dict_get(pContext->metadata, "comment", NULL, 0); + if (pComment) + desc += QString("\n") + pComment->value; +#if LIBAFORMAT_VERSION_MAJOR < 54 + av_close_input_file(pContext); +#else + avformat_close_input(&pContext); +#endif + return desc; +} + +#else +LibavIteraction::LibavIteraction() : QObject() +{ + +} + +void LibavIteraction::fillFormats(QComboBox * pFormats) +{ + Q_UNUSED(pFormats); +} + +void LibavIteraction::fillCodecs(const QString & format, QComboBox * pVCodecs, QComboBox * pACodecs) +{ + Q_UNUSED(format); + Q_UNUSED(pVCodecs); + Q_UNUSED(pACodecs); +} + +QString LibavIteraction::getExtension(const QString & format) +{ + Q_UNUSED(format); + + return QString(); +} + +QString LibavIteraction::getFileInfo(const QString & filepath) +{ + Q_UNUSED(filepath); + + return QString(); +} +#endif + +LibavIteraction & LibavIteraction::instance() +{ + static LibavIteraction instance; + return instance; +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 QTfrontend/util/libav_iteraction.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/util/libav_iteraction.h Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,51 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef LIBAV_ITERACTION +#define LIBAV_ITERACTION + +#include + +/** + * @brief Class for interacting with ffmpeg/libav libraries + * + * @see singleton pattern + */ +class LibavIteraction : public QObject +{ + Q_OBJECT; + + LibavIteraction(); + +public: + + static LibavIteraction & instance(); + + // fill combo box with known file formats + void fillFormats(QComboBox * pFormats); + + // fill combo boxes with known codecs for given formats + void fillCodecs(const QString & format, QComboBox * pVCodecs, QComboBox * pACodecs); + + QString getExtension(const QString & format); + + // get information about file (duration, resolution etc) in multiline string + QString getFileInfo(const QString & filepath); +}; + +#endif // LIBAV_ITERACTION diff -r ce6ead3327b2 -r c73fd8cfa7c0 cmake_modules/FindFFMPEG.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake_modules/FindFFMPEG.cmake Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,79 @@ +# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil) +# Once done this will define +# +# FFMPEG_FOUND - system has ffmpeg or libav +# FFMPEG_INCLUDE_DIR - the ffmpeg include directory +# FFMPEG_LIBRARIES - Link these to use ffmpeg +# FFMPEG_LIBAVCODEC +# FFMPEG_LIBAVFORMAT +# FFMPEG_LIBAVUTIL +# +# Copyright (c) 2008 Andreas Schneider +# Modified for other libraries by Lasse Kärkkäinen +# Modified for Hedgewars by Stepik777 +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# + +if (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) + # in cache already + set(FFMPEG_FOUND TRUE) +else (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(_FFMPEG_AVCODEC libavcodec) + pkg_check_modules(_FFMPEG_AVFORMAT libavformat) + pkg_check_modules(_FFMPEG_AVUTIL libavutil) + endif (PKG_CONFIG_FOUND) + + find_path(FFMPEG_AVCODEC_INCLUDE_DIR + NAMES libavcodec/avcodec.h + PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS} /usr/include /usr/local/include /opt/local/include /sw/include + PATH_SUFFIXES ffmpeg libav + ) + + find_library(FFMPEG_LIBAVCODEC + NAMES avcodec + PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib + ) + + find_library(FFMPEG_LIBAVFORMAT + NAMES avformat + PATHS ${_FFMPEG_AVFORMAT_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib + ) + + find_library(FFMPEG_LIBAVUTIL + NAMES avutil + PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS} /usr/lib /usr/local/lib /opt/local/lib /sw/lib + ) + + if (FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVFORMAT) + set(FFMPEG_FOUND TRUE) + endif() + + if (FFMPEG_FOUND) + set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR}) + + set(FFMPEG_LIBRARIES + ${FFMPEG_LIBAVCODEC} + ${FFMPEG_LIBAVFORMAT} + ${FFMPEG_LIBAVUTIL} + ) + + endif (FFMPEG_FOUND) + + if (FFMPEG_FOUND) + if (NOT FFMPEG_FIND_QUIETLY) + message(STATUS "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}") + endif (NOT FFMPEG_FIND_QUIETLY) + else (FFMPEG_FOUND) + if (FFMPEG_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libavcodec or libavformat or libavutil") + endif (FFMPEG_FIND_REQUIRED) + endif (FFMPEG_FOUND) + +endif (FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) + diff -r ce6ead3327b2 -r c73fd8cfa7c0 gameServer/Actions.hs --- a/gameServer/Actions.hs Mon Aug 27 17:40:16 2012 +0200 +++ b/gameServer/Actions.hs Sun Sep 16 16:54:51 2012 +0200 @@ -244,11 +244,16 @@ newMasterId <- liftM (head . filter (/= ci)) . io $ roomClientsIndicesM rnc ri newMaster <- io $ client'sM rnc id newMasterId oldRoomName <- io $ room'sM rnc name ri + oldMaster <- client's nick + thisRoomChans <- liftM (map sendChan) $ roomClientsS ri let newRoomName = nick newMaster mapM_ processAction [ - ModifyRoom (\r -> r{masterID = newMasterId, name = newRoomName}), - ModifyClient2 newMasterId (\c -> c{isMaster = True}), - AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"] + ModifyRoom (\r -> r{masterID = newMasterId, name = newRoomName, isRestrictedJoins = False, isRestrictedTeams = False}) + , ModifyClient2 newMasterId (\c -> c{isMaster = True}) + , AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"] + , AnswerClients thisRoomChans ["WARNING", "New room admin is " `B.append` nick newMaster] + , AnswerClients thisRoomChans ["CLIENT_FLAGS", "-h", oldMaster] + , AnswerClients thisRoomChans ["CLIENT_FLAGS", "+h", nick newMaster] ] proto <- client's clientProto @@ -262,6 +267,7 @@ rnc <- gets roomsClients proto <- client's clientProto n <- client's nick + chan <- client's sendChan let rm = newRoom{ masterID = clId, @@ -278,6 +284,7 @@ mapM_ processAction [ AnswerClients chans ("ROOM" : "ADD" : roomInfo n rm) + , AnswerClients [chan] ["CLIENT_FLAGS", "+h", n] , ModifyClient (\cl -> cl{isMaster = True}) ] diff -r ce6ead3327b2 -r c73fd8cfa7c0 gameServer/HWProtoLobbyState.hs --- a/gameServer/HWProtoLobbyState.hs Mon Aug 27 17:40:16 2012 +0200 +++ b/gameServer/HWProtoLobbyState.hs Sun Sep 16 16:54:51 2012 +0200 @@ -6,6 +6,7 @@ import Data.Maybe import Data.List import Control.Monad.Reader +import qualified Data.ByteString.Char8 as B -------------------------------------- import CoreTypes import Actions @@ -69,6 +70,7 @@ let sameProto = clientProto cl == roomProto jRoom let jRoomClients = map (client irnc) $ roomClients irnc jRI let nicks = map nick jRoomClients + let ownerNick = nick . fromJust $ find isMaster jRoomClients let chans = map sendChan (cl : jRoomClients) let isBanned = host cl `elem` roomBansList jRoom return $ @@ -82,9 +84,11 @@ [NoticeMessage WrongPassword] else [ - MoveToRoom jRI, - AnswerClients [sendChan cl] $ "JOINED" : nicks, - AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl] + MoveToRoom jRI + , AnswerClients [sendChan cl] $ "JOINED" : nicks + , AnswerClients chans ["CLIENT_FLAGS", "-r", nick cl] + , AnswerClients [sendChan cl] $ ["WARNING", "Room admin is " `B.append` ownerNick] + , AnswerClients [sendChan cl] $ ["CLIENT_FLAGS", "+h", ownerNick] ] ++ map (readynessMessage cl) jRoomClients ++ answerFullConfig cl (mapParams jRoom) (params jRoom) diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/ArgParsers.inc --- a/hedgewars/ArgParsers.inc Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/ArgParsers.inc Sun Sep 16 16:54:51 2012 +0200 @@ -63,6 +63,21 @@ cLocaleFName:= ParamStr(17); end; +{$IFDEF USE_VIDEO_RECORDING} +procedure internalStartVideoRecordingWithParameters(); +begin + internalStartGameWithParameters(); + GameType:= gmtRecord; + cVideoFramerateNum:= StrToInt(ParamStr(18)); + cVideoFramerateDen:= StrToInt(ParamStr(19)); + RecPrefix:= ParamStr(20); + cAVFormat:= ParamStr(21); + cVideoCodec:= ParamStr(22); + cVideoQuality:= StrToInt(ParamStr(23)); + cAudioCodec:= ParamStr(24); +end; +{$ENDIF} + procedure setVideo(screenWidth: LongInt; screenHeight: LongInt; bitsStr: LongInt); begin cScreenWidth:= screenWidth; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/CMakeLists.txt Sun Sep 16 16:54:51 2012 +0200 @@ -3,6 +3,7 @@ find_package(SDL_net) find_package(SDL_ttf) find_package(SDL_mixer) +find_package(FFMPEG) include(${CMAKE_MODULE_PATH}/FindSDL_Extras.cmake) @@ -62,6 +63,7 @@ uTypes.pas uUtils.pas uVariables.pas + uVideoRec.pas uVisualGears.pas uWorld.pas GSHandlers.inc @@ -185,9 +187,44 @@ message(STATUS "PNG screenshots disabled per user request, using BMP format") endif() + + +#this command is a workaround to some inlining issues present in older +# FreePascal versions and fixed in 2.6, That version is mandatory on OSX, +# hence the command is not needed there +if(NOT APPLE) + add_custom_target(ENGINECLEAN COMMAND ${CMAKE_BUILD_TOOL} "clean" "${PROJECT_BINARY_DIR}" "${hedgewars_SOURCE_DIR}/hedgewars") +endif() + + +if(NOT NO_VIDEOREC) + if(${FFMPEG_FOUND}) + message(STATUS "Compiling with video recording") + include_directories(${FFMPEG_INCLUDE_DIR}) + set(pascal_flags "-dUSE_VIDEO_RECORDING" ${pascal_flags}) + set(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}) + IF (WIN32) + # there are some problems with linking our avwrapper as static lib, so link it as shared + add_library(avwrapper SHARED avwrapper.c) + target_link_libraries(avwrapper ${FFMPEG_LIBRARIES}) + install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_dir}) + ELSE() + add_library(avwrapper STATIC avwrapper.c) + set(pascal_flags "-k${FFMPEG_LIBAVCODEC}" "-k${FFMPEG_LIBAVFORMAT}" "-k${FFMPEG_LIBAVUTIL}" ${pascal_flags}) + # set(pascal_flags "-k${LIBRARY_OUTPUT_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}avwrapper${CMAKE_STATIC_LIBRARY_SUFFIX}" ${pascal_flags}) + ENDIF() + if(NOT APPLE) + add_dependencies(avwrapper ENGINECLEAN) + endif() + else() + message(STATUS "FFMPEG library not found, video recording will be disabled") + endif() +else() + message(STATUS "Video recording disabled by user") +endif() + set(fpc_flags ${noexecstack_flags} ${pascal_flags} ${hwengine_project}) - IF(NOT APPLE) #here is the command for standard executables or for shared library add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}" @@ -224,13 +261,10 @@ add_dependencies(${engine_output_name} lua) endif() -#this command is a workaround to some inlining issues present in older -# FreePascal versions and fixed in 2.6, That version is mandatory on OSX, -# hence the command is not needed there if(NOT APPLE) - add_custom_target(ENGINECLEAN COMMAND ${CMAKE_BUILD_TOOL} "clean" "${PROJECT_BINARY_DIR}" "${hedgewars_SOURCE_DIR}/hedgewars") - add_dependencies(${engine_output_name} ENGINECLEAN) + if(NO_VIDEOREC OR NOT ${FFMPEG_FOUND}) + add_dependencies(${engine_output_name} ENGINECLEAN) + endif() endif() install(PROGRAMS "${EXECUTABLE_OUTPUT_PATH}/${engine_output_name}${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION ${target_dir}) - diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/GSHandlers.inc Sun Sep 16 16:54:51 2012 +0200 @@ -169,11 +169,24 @@ collV, collH: LongInt; land: word; begin - // clip velocity at 1.9 - over 1 per pixel, but really shouldn't cause many actual problems. - if Gear^.dX.QWordValue > 8160437862 then - Gear^.dX.QWordValue:= 8160437862; - if Gear^.dY.QWordValue > 8160437862 then - Gear^.dY.QWordValue:= 8160437862; + // clip velocity at 2 - over 1 per pixel, but really shouldn't cause many actual problems. +{$IFNDEF WEB} + if Gear^.dX.Round > 2 then + Gear^.dX.QWordValue:= 8589934592; + if Gear^.dY.Round > 2 then + Gear^.dY.QWordValue:= 8589934592; +{$ELSE} + if Gear^.dX.Round > 2 then + begin + Gear^.dX.Round:= 2; + Gear^.dX.Frac:= 0 + end; + if Gear^.dY.QWordValue > 2 then + begin + Gear^.dY.Round:= 2; + Gear^.dY.Frac:= 0 + end; +{$ENDIF} Gear^.State := Gear^.State and (not gstCollision); collV := 0; collH := 0; @@ -519,7 +532,7 @@ kick:= hwRound((hwAbs(Gear^.dX)+hwAbs(Gear^.dY)) * _20); Gear^.dY.isNegative:= not Gear^.dY.isNegative; Gear^.dX.isNegative:= not Gear^.dX.isNegative; - AmmoShove(Gear, 1, kick); + AmmoShove(Gear, 0, kick); for i:= 15 + kick div 10 downto 0 do begin particle := AddVisualGear(hwRound(Gear^.X) + Random(25), hwRound(Gear^.Y) + Random(25), vgtDust); @@ -570,13 +583,14 @@ yy:= hwRound(Y); if vobVelocity <> 0 then begin - DirAngle := DirAngle + (Angle / 1250000000); + DirAngle := DirAngle + (Damage / 1000); if DirAngle < 0 then DirAngle := DirAngle + 360 else if 360 < DirAngle then DirAngle := DirAngle - 360; end; - +(* +We aren't using frametick right now, so just a waste of cycles. inc(Health, 8); if longword(Health) > vobFrameTicks then begin @@ -585,6 +599,7 @@ if Timer = vobFramesCount then Timer:= 0 end; +*) // move back to cloud layer if yy > cWaterLine then move:= true @@ -1483,7 +1498,7 @@ or TestCollisionXwithGear(Gear, -2) or (TestCollisionYwithGear(Gear, 2) <> 0) then begin - if (hwAbs(Gear^.dX) > _0) or (hwAbs(Gear^.dY) > _0) then + if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then begin PlaySound(sndRopeAttach); Gear^.dX:= _0; @@ -1756,14 +1771,17 @@ or (TestCollisionYwithGear(Gear, 1) = 0) then begin AllInactive := false; + Gear^.dY := Gear^.dY + cGravity; + + if (Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, -1) <> 0) then + Gear^.dY := _0; + Gear^.Y := Gear^.Y + Gear^.dY; + if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then SetAllHHToActive; - - if (Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, -1) <> 0) then - Gear^.dY := _0; - + if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then begin if (Gear^.dY > _0_2) and (k = gtExplosives) then @@ -2252,14 +2270,13 @@ var HHGear: PGear; begin - Gear^.Hedgehog^.Unplaced := false; HHGear := Gear^.Hedgehog^.Gear; - HHGear^.Y := HHGear^.Y + HHGear^.dY; - HHGear^.X := HHGear^.X + HHGear^.dX; - // hedgehog falling to collect cases - HHGear^.dY := HHGear^.dY + cGravity; - if (TestCollisionYwithGear(HHGear, 1) <> 0) - or CheckGearDrowning(HHGear) then + doStepHedgehogMoving(HHGear); + // if not infattack mode wait for hedgehog finish falling to collect cases + if ((GameFlags and gfInfAttack) <> 0) + or ((HHGear^.State and gstMoving) = 0) + or (Gear^.Hedgehog^.Gear^.Damage > 0) + or ((HHGear^.State and gstDrowning) = 1) then begin DeleteGear(Gear); AfterAttack @@ -2268,6 +2285,11 @@ procedure doStepTeleportAnim(Gear: PGear); begin + if (Gear^.Hedgehog^.Gear^.Damage > 0) then + begin + DeleteGear(Gear); + AfterAttack; + end; inc(Gear^.Timer); if Gear^.Timer = 65 then begin @@ -2311,6 +2333,8 @@ HHGear^.X := int2hwFloat(Gear^.Target.X); HHGear^.Y := int2hwFloat(Gear^.Target.Y); HHGear^.State := HHGear^.State or gstMoving; + Gear^.Hedgehog^.Unplaced := false; + isCursorVisible := false; playSound(sndWarp) end; Gear^.Target.X:= NoPointX @@ -3704,7 +3728,7 @@ // calc gear offset in portal normal vector direction noffs:= (nx * ox + ny * oy); - if isBullet and (hwRound(hwAbs(noffs)) >= Gear^.Radius) then + if isBullet and (noffs.Round >= Gear^.Radius) then continue; // avoid gravity related loops of not really moving gear @@ -3825,6 +3849,7 @@ else begin inc(iterator^.PortalCounter); + iterator^.Active:= true; iterator^.State:= iterator^.State and (not gstHHHJump) end; @@ -5141,3 +5166,84 @@ doStepFallingGear(Gear); end; + +procedure doStepCreeper(Gear: PGear); +var hogs: PGearArrayS; + HHGear: PGear; + tdX: hwFloat; + dir: LongInt; +begin +doStepFallingGear(Gear); +if Gear^.Timer > 0 then dec(Gear^.Timer); +// creeper sleep phase +if (Gear^.Hedgehog = nil) and (Gear^.Timer > 0) then exit; + +if Gear^.Hedgehog <> nil then HHGear:= Gear^.Hedgehog^.Gear +else HHGear:= nil; + +// creeper boom phase +if (Gear^.State and gstTmpFlag <> 0) then + begin + if (Gear^.Timer = 0) then + begin + doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 300, CurrentHedgehog, EXPLAutoSound); + DeleteGear(Gear) + end; + // ssssss he essssscaped + if (Gear^.Timer > 250) and ((HHGear = nil) or + (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > 180) and + (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > _180))) then + begin + Gear^.State:= Gear^.State and (not gstTmpFlag); + Gear^.Timer:= 0 + end; + exit + end; + +// Search out a new target, as target seek time has expired, target is dead, target is out of range, or we didn't have a target +if (HHGear = nil) or (Gear^.Timer = 0) or + (((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) > Gear^.Angle) and + (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) > int2hwFloat(Gear^.Angle))) + then + begin + hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Angle); + if hogs.size > 1 then + Gear^.Hedgehog:= hogs.ar^[GetRandom(hogs.size)]^.Hedgehog + else if hogs.size = 1 then Gear^.Hedgehog:= hogs.ar^[0]^.Hedgehog + else Gear^.Hedgehog:= nil; + if Gear^.Hedgehog <> nil then Gear^.Timer:= 5000; + exit + end; + +// we have a target. move the creeper. +if HHGear <> nil then + begin + // GOTCHA + if ((abs(HHGear^.X.Round-Gear^.X.Round) + abs(HHGear^.Y.Round-Gear^.Y.Round) + 2) < 50) and + (Distance(HHGear^.X-Gear^.X,HHGear^.Y-Gear^.Y) < _50) then + begin + // hisssssssssss + Gear^.State:= Gear^.State or gstTmpFlag; + Gear^.Timer:= 1500; + exit + end; + if (Gear^.State and gstMoving <> 0) then + begin + Gear^.dY:= _0; + Gear^.dX:= _0; + end + else if (GameTicks and $FF = 0) then + begin + tdX:= HHGear^.X-Gear^.X; + dir:= hwSign(tdX); + if not TestCollisionX(Gear, dir) then + Gear^.X:= Gear^.X + signAs(_1,tdX); + if TestCollisionXwithXYShift(Gear, signAs(_10,tdX), 0, dir) then + begin + Gear^.dX:= SignAs(_0_15, tdX); + Gear^.dY:= -_0_3; + Gear^.State:= Gear^.State or gstMoving + end + end; + end; +end; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/SDLh.pas Sun Sep 16 16:54:51 2012 +0200 @@ -827,6 +827,8 @@ TMixMusic = record end; + TPostMix = procedure(udata: pointer; stream: PByte; len: LongInt); cdecl; + {* SDL_net *} TIPAddress = record host: LongWord; @@ -957,6 +959,9 @@ function SDL_GL_SetAttribute(attr: TSDL_GLattr; value: LongInt): LongInt; cdecl; external SDLLibName; procedure SDL_GL_SwapBuffers; cdecl; external SDLLibName; +procedure SDL_LockAudio; cdecl; external SDLLibName; +procedure SDL_UnlockAudio; cdecl; external SDLLibName; + function SDL_NumJoysticks: LongInt; cdecl; external SDLLibName; function SDL_JoystickName(idx: LongInt): PChar; cdecl; external SDLLibName; function SDL_JoystickOpen(idx: LongInt): PSDL_Joystick; cdecl; external SDLLibName; @@ -1008,6 +1013,7 @@ function Mix_OpenAudio(frequency: LongInt; format: Word; channels: LongInt; chunksize: LongInt): LongInt; cdecl; external SDL_MixerLibName; procedure Mix_CloseAudio; cdecl; external SDL_MixerLibName; +function Mix_QuerySpec(frequency: PLongInt; format: PWord; channels: PLongInt): LongInt; cdecl; external SDL_MixerLibName; function Mix_Volume(channel: LongInt; volume: LongInt): LongInt; cdecl; external SDL_MixerLibName; function Mix_SetDistance(channel: LongInt; distance: Byte): LongInt; cdecl; external SDL_MixerLibName; @@ -1035,6 +1041,8 @@ function Mix_FadeInChannelTimed(channel: LongInt; chunk: PMixChunk; loops: LongInt; fadems: LongInt; ticks: LongInt): LongInt; cdecl; external SDL_MixerLibName; function Mix_FadeOutChannel(channel: LongInt; fadems: LongInt): LongInt; cdecl; external SDL_MixerLibName; +procedure Mix_SetPostMix( mix_func: TPostMix; arg: pointer); cdecl; external SDL_MixerLibName; + (* SDL_image *) function IMG_Init(flags: LongInt): LongInt; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName;{$ENDIF} procedure IMG_Quit; {$IFDEF SDL_IMAGE_NEWER}cdecl; external SDL_ImageLibName;{$ENDIF} diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/VGSHandlers.inc --- a/hedgewars/VGSHandlers.inc Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/VGSHandlers.inc Sun Sep 16 16:54:51 2012 +0200 @@ -434,7 +434,7 @@ procedure doStepTeamHealthSorterWork(Gear: PVisualGear; Steps: Longword); var i, t: LongInt; begin -for t:= 1 to Steps do +for t:= 1 to min(Steps, Gear^.Timer) do begin dec(Gear^.Timer); if (Gear^.Timer and 15) = 0 then @@ -442,18 +442,18 @@ with thexchar[i] do begin {$WARNINGS OFF} - team^.DrawHealthY:= ny + dy * LongInt(Gear^.Timer) div 640; + team^.DrawHealthY:= ny + dy * LongInt(Gear^.Timer) div cSorterWorkTime; team^.TeamHealthBarWidth:= team^.NewTeamHealthBarWidth + dw * LongInt(Gear^.Timer) div cSorterWorkTime; {$WARNINGS ON} end; + end; - if (Gear^.Timer = 0) or (currsorter <> Gear) then - begin - if currsorter = Gear then - currsorter:= nil; - DeleteVisualGear(Gear); - exit - end +if (Gear^.Timer = 0) or (currsorter <> Gear) then + begin + if currsorter = Gear then + currsorter:= nil; + DeleteVisualGear(Gear); + exit end end; @@ -463,15 +463,21 @@ t: LongInt; begin Steps:= Steps; // avoid compiler hint + for t:= 0 to Pred(TeamsCount) do with thexchar[t] do begin - dy:= TeamsArray[t]^.DrawHealthY; - dw:= TeamsArray[t]^.TeamHealthBarWidth - TeamsArray[t]^.NewTeamHealthBarWidth; team:= TeamsArray[t]; - SortFactor:= TeamsArray[t]^.Clan^.ClanHealth; - SortFactor:= (SortFactor shl 3) + TeamsArray[t]^.Clan^.ClanIndex; - SortFactor:= (SortFactor shl 30) + TeamsArray[t]^.TeamHealth; + dy:= team^.DrawHealthY; + dw:= team^.TeamHealthBarWidth - team^.NewTeamHealthBarWidth; + if team^.TeamHealth > 0 then + begin + SortFactor:= team^.Clan^.ClanHealth; + SortFactor:= (SortFactor shl 3) + team^.Clan^.ClanIndex; + SortFactor:= (SortFactor shl 30) + team^.TeamHealth; + end + else + SortFactor:= 0; end; if TeamsCount > 1 then @@ -489,12 +495,13 @@ t:= - 4; for i:= 0 to Pred(TeamsCount) do - with thexchar[i] do - begin - dec(t, team^.HealthTex^.h + 2); - ny:= t; - dy:= dy - ny - end; + with thexchar[i] do + if team^.TeamHealth > 0 then + begin + dec(t, team^.HealthTex^.h + 2); + ny:= t; + dy:= dy - ny + end; Gear^.Timer:= cSorterWorkTime; Gear^.doStep:= @doStepTeamHealthSorterWork; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/avwrapper.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/avwrapper.c Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,515 @@ +/* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include "libavformat/avformat.h" + +#ifndef AVIO_FLAG_WRITE +#define AVIO_FLAG_WRITE AVIO_WRONLY +#endif + +static AVFormatContext* g_pContainer; +static AVOutputFormat* g_pFormat; +static AVStream* g_pAStream; +static AVStream* g_pVStream; +static AVFrame* g_pAFrame; +static AVFrame* g_pVFrame; +static AVCodec* g_pACodec; +static AVCodec* g_pVCodec; +static AVCodecContext* g_pAudio; +static AVCodecContext* g_pVideo; + +static int g_Width, g_Height; +static uint32_t g_Frequency, g_Channels; +static int g_VQuality; +static AVRational g_Framerate; + +static FILE* g_pSoundFile; +static int16_t* g_pSamples; +static int g_NumSamples; + +/* +Initially I wrote code for latest ffmpeg, but on Linux (Ubuntu) +only older version is available from repository. That's why you see here +all of this #if LIBAVCODEC_VERSION_MAJOR < 54. +Actually, it may be possible to remove code for newer version +and use only code for older version. +*/ + +#if LIBAVCODEC_VERSION_MAJOR < 54 +#define OUTBUFFER_SIZE 200000 +static uint8_t g_OutBuffer[OUTBUFFER_SIZE]; +#endif + +// pointer to function from hwengine (uUtils.pas) +static void (*AddFileLogRaw)(const char* pString); + +static void FatalError(const char* pFmt, ...) +{ + const char Buffer[1024]; + va_list VaArgs; + + va_start(VaArgs, pFmt); + vsnprintf(Buffer, 1024, pFmt, VaArgs); + va_end(VaArgs); + + AddFileLogRaw("Error in av-wrapper: "); + AddFileLogRaw(Buffer); + AddFileLogRaw("\n"); + exit(1); +} + +// Function to be called from libav for logging. +// Note: libav can call LogCallback from different threads +// (there is mutex in AddFileLogRaw). +static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs) +{ + const char Buffer[1024]; + + vsnprintf(Buffer, 1024, pFmt, VaArgs); + AddFileLogRaw(Buffer); +} + +static void Log(const char* pFmt, ...) +{ + const char Buffer[1024]; + va_list VaArgs; + + va_start(VaArgs, pFmt); + vsnprintf(Buffer, 1024, pFmt, VaArgs); + va_end(VaArgs); + + AddFileLogRaw(Buffer); +} + +static void AddAudioStream() +{ +#if LIBAVFORMAT_VERSION_MAJOR >= 54 + g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); +#else + g_pAStream = av_new_stream(g_pContainer, 1); +#endif + if(!g_pAStream) + { + Log("Could not allocate audio stream\n"); + return; + } + g_pAStream->id = 1; + + g_pAudio = g_pAStream->codec; + + avcodec_get_context_defaults3(g_pAudio, g_pACodec); + g_pAudio->codec_id = g_pACodec->id; + + // put parameters + g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16; + g_pAudio->sample_rate = g_Frequency; + g_pAudio->channels = g_Channels; + + // set quality + g_pAudio->bit_rate = 160000; + + // for codecs that support variable bitrate use it, it should be better + g_pAudio->flags |= CODEC_FLAG_QSCALE; + g_pAudio->global_quality = 1*FF_QP2LAMBDA; + + // some formats want stream headers to be separate + if (g_pFormat->flags & AVFMT_GLOBALHEADER) + g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER; + + // open it +#if LIBAVCODEC_VERSION_MAJOR >= 53 + if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) +#else + if (avcodec_open(g_pAudio, g_pACodec) < 0) +#endif + { + Log("Could not open audio codec %s\n", g_pACodec->long_name); + return; + } + +#if LIBAVCODEC_VERSION_MAJOR >= 54 + if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) +#else + if (g_pAudio->frame_size == 0) +#endif + g_NumSamples = 4096; + else + g_NumSamples = g_pAudio->frame_size; + g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); + g_pAFrame = avcodec_alloc_frame(); + if (!g_pAFrame) + { + Log("Could not allocate frame\n"); + return; + } +} + +// returns non-zero if there is more sound +static int WriteAudioFrame() +{ + if (!g_pAStream) + return 0; + + AVPacket Packet = { 0 }; + av_init_packet(&Packet); + + int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile); + +#if LIBAVCODEC_VERSION_MAJOR >= 54 + AVFrame* pFrame = NULL; + if (NumSamples > 0) + { + g_pAFrame->nb_samples = NumSamples; + avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16, + (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1); + pFrame = g_pAFrame; + } + // when NumSamples == 0 we still need to call encode_audio2 to flush + int got_packet; + if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0) + FatalError("avcodec_encode_audio2 failed"); + if (!got_packet) + return 0; +#else + if (NumSamples == 0) + return 0; + int BufferSize = OUTBUFFER_SIZE; + if (g_pAudio->frame_size == 0) + BufferSize = NumSamples*g_Channels*2; + Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples); + if (Packet.size == 0) + return 1; + if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE) + Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base); + Packet.flags |= AV_PKT_FLAG_KEY; + Packet.data = g_OutBuffer; +#endif + + // Write the compressed frame to the media file. + Packet.stream_index = g_pAStream->index; + if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) + FatalError("Error while writing audio frame"); + return 1; +} + +// add a video output stream +static void AddVideoStream() +{ +#if LIBAVFORMAT_VERSION_MAJOR >= 54 + g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); +#else + g_pVStream = av_new_stream(g_pContainer, 0); +#endif + if (!g_pVStream) + FatalError("Could not allocate video stream"); + + g_pVideo = g_pVStream->codec; + + avcodec_get_context_defaults3(g_pVideo, g_pVCodec); + g_pVideo->codec_id = g_pVCodec->id; + + // put parameters + // resolution must be a multiple of two + g_pVideo->width = g_Width & ~1; // make even (dimensions should be even) + g_pVideo->height = g_Height & ~1; // make even + /* time base: this is the fundamental unit of time (in seconds) in terms + of which frame timestamps are represented. for fixed-fps content, + timebase should be 1/framerate and timestamp increments should be + identically 1. */ + g_pVideo->time_base.den = g_Framerate.num; + g_pVideo->time_base.num = g_Framerate.den; + //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */ + g_pVideo->pix_fmt = PIX_FMT_YUV420P; + + // set quality + if (g_VQuality > 100) + g_pVideo->bit_rate = g_VQuality; + else + { + g_pVideo->flags |= CODEC_FLAG_QSCALE; + g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA; + } + + // some formats want stream headers to be separate + if (g_pFormat->flags & AVFMT_GLOBALHEADER) + g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER; + +#if LIBAVCODEC_VERSION_MAJOR < 54 + // for some versions of ffmpeg x264 options must be set explicitly + if (strcmp(g_pVCodec->name, "libx264") == 0) + { + g_pVideo->coder_type = FF_CODER_TYPE_AC; + g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER; + g_pVideo->crf = 23; + g_pVideo->thread_count = 3; + g_pVideo->me_cmp = FF_CMP_CHROMA; + g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8; + g_pVideo->me_method = ME_HEX; + g_pVideo->me_subpel_quality = 7; + g_pVideo->me_range = 16; + g_pVideo->gop_size = 250; + g_pVideo->keyint_min = 25; + g_pVideo->scenechange_threshold = 40; + g_pVideo->i_quant_factor = 0.71; + g_pVideo->b_frame_strategy = 1; + g_pVideo->qcompress = 0.6; + g_pVideo->qmin = 10; + g_pVideo->qmax = 51; + g_pVideo->max_qdiff = 4; + g_pVideo->max_b_frames = 3; + g_pVideo->refs = 3; + g_pVideo->directpred = 1; + g_pVideo->trellis = 1; + g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP; + g_pVideo->weighted_p_pred = 2; + } +#endif + + // open the codec +#if LIBAVCODEC_VERSION_MAJOR >= 53 + AVDictionary* pDict = NULL; + if (strcmp(g_pVCodec->name, "libx264") == 0) + av_dict_set(&pDict, "preset", "medium", 0); + + if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) +#else + if (avcodec_open(g_pVideo, g_pVCodec) < 0) +#endif + FatalError("Could not open video codec %s", g_pVCodec->long_name); + + g_pVFrame = avcodec_alloc_frame(); + if (!g_pVFrame) + FatalError("Could not allocate frame"); + + g_pVFrame->linesize[0] = g_Width; + g_pVFrame->linesize[1] = g_Width/2; + g_pVFrame->linesize[2] = g_Width/2; + g_pVFrame->linesize[3] = 0; +} + +static int WriteFrame(AVFrame* pFrame) +{ + double AudioTime, VideoTime; + + // write interleaved audio frame + if (g_pAStream) + { + VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den; + do + AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den; + while (AudioTime < VideoTime && WriteAudioFrame()); + } + + if (!g_pVStream) + return 0; + + AVPacket Packet; + av_init_packet(&Packet); + Packet.data = NULL; + Packet.size = 0; + + g_pVFrame->pts++; + if (g_pFormat->flags & AVFMT_RAWPICTURE) + { + /* raw video case. The API will change slightly in the near + future for that. */ + Packet.flags |= AV_PKT_FLAG_KEY; + Packet.stream_index = g_pVStream->index; + Packet.data = (uint8_t*)pFrame; + Packet.size = sizeof(AVPicture); + + if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) + FatalError("Error while writing video frame"); + return 0; + } + else + { +#if LIBAVCODEC_VERSION_MAJOR >= 54 + int got_packet; + if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0) + FatalError("avcodec_encode_video2 failed"); + if (!got_packet) + return 0; + + if (Packet.pts != AV_NOPTS_VALUE) + Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base); + if (Packet.dts != AV_NOPTS_VALUE) + Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base); +#else + Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame); + if (Packet.size < 0) + FatalError("avcodec_encode_video failed"); + if (Packet.size == 0) + return 0; + + if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE) + Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base); + if( g_pVideo->coded_frame->key_frame ) + Packet.flags |= AV_PKT_FLAG_KEY; + Packet.data = g_OutBuffer; +#endif + // write the compressed frame in the media file + Packet.stream_index = g_pVStream->index; + if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) + FatalError("Error while writing video frame"); + + return 1; + } +} + +void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr) +{ + g_pVFrame->data[0] = pY; + g_pVFrame->data[1] = pCb; + g_pVFrame->data[2] = pCr; + WriteFrame(g_pVFrame); +} + +void AVWrapper_Init( + void (*pAddFileLogRaw)(const char*), + const char* pFilename, + const char* pDesc, + const char* pSoundFile, + const char* pFormatName, + const char* pVCodecName, + const char* pACodecName, + int Width, int Height, + int FramerateNum, int FramerateDen, + int VQuality) +{ + AddFileLogRaw = pAddFileLogRaw; + av_log_set_callback( &LogCallback ); + + g_Width = Width; + g_Height = Height; + g_Framerate.num = FramerateNum; + g_Framerate.den = FramerateDen; + g_VQuality = VQuality; + + // initialize libav and register all codecs and formats + av_register_all(); + + // find format + g_pFormat = av_guess_format(pFormatName, NULL, NULL); + if (!g_pFormat) + FatalError("Format \"%s\" was not found", pFormatName); + + // allocate the output media context + g_pContainer = avformat_alloc_context(); + if (!g_pContainer) + FatalError("Could not allocate output context"); + + g_pContainer->oformat = g_pFormat; + + // store description of file + av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0); + + // append extesnion to filename + char ext[16]; + strncpy(ext, g_pFormat->extensions, 16); + ext[15] = 0; + ext[strcspn(ext,",")] = 0; + snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext); + + // find codecs + g_pVCodec = avcodec_find_encoder_by_name(pVCodecName); + g_pACodec = avcodec_find_encoder_by_name(pACodecName); + + // add audio and video stream to container + g_pVStream = NULL; + g_pAStream = NULL; + + if (g_pVCodec) + AddVideoStream(); + else + Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName); + + if (g_pACodec) + { + g_pSoundFile = fopen(pSoundFile, "rb"); + if (g_pSoundFile) + { + fread(&g_Frequency, 4, 1, g_pSoundFile); + fread(&g_Channels, 4, 1, g_pSoundFile); + AddAudioStream(); + } + else + Log("Could not open %s\n", pSoundFile); + } + else + Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); + + if (!g_pAStream && !g_pVStream) + FatalError("No video, no audio, aborting..."); + + // write format info to log + av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); + + // open the output file, if needed + if (!(g_pFormat->flags & AVFMT_NOFILE)) + { + if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0) + FatalError("Could not open output file (%s)", g_pContainer->filename); + } + + // write the stream header, if any + avformat_write_header(g_pContainer, NULL); + + g_pVFrame->pts = -1; +} + +void AVWrapper_Close() +{ + // output buffered frames + if (g_pVCodec->capabilities & CODEC_CAP_DELAY) + while( WriteFrame(NULL) ); + // output any remaining audio + while( WriteAudioFrame() ); + + // write the trailer, if any. + av_write_trailer(g_pContainer); + + // close the output file + if (!(g_pFormat->flags & AVFMT_NOFILE)) + avio_close(g_pContainer->pb); + + // free everything + if (g_pVStream) + { + avcodec_close(g_pVideo); + av_free(g_pVideo); + av_free(g_pVStream); + av_free(g_pVFrame); + } + if (g_pAStream) + { + avcodec_close(g_pAudio); + av_free(g_pAudio); + av_free(g_pAStream); + av_free(g_pAFrame); + av_free(g_pSamples); + fclose(g_pSoundFile); + } + + av_free(g_pContainer); +} diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/hwengine.pas Sun Sep 16 16:54:51 2012 +0200 @@ -32,8 +32,10 @@ uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler, uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uLandTexture, uCollisions, SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted + {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF} {$IFDEF SDL13}, uTouch{$ENDIF}{$IFDEF ANDROID}, GLUnit{$ENDIF}, uAILandMarks; + {$IFDEF HWLIBRARY} procedure initEverything(complete:boolean); procedure freeEverything(complete:boolean); @@ -84,7 +86,7 @@ end; gsConfirm, gsGame: begin - DrawWorld(Lag); // never place between ProcessKbd and DoGameTick - bugs due to /put cmd and isCursorVisible + DrawWorld(Lag); DoGameTick(Lag); ProcessVisualGears(Lag); end; @@ -104,18 +106,27 @@ SwapBuffers; +{$IFDEF USE_VIDEO_RECORDING} + if flagPrerecording then + SaveCameraPosition; +{$ENDIF} + if flagMakeCapture then begin flagMakeCapture:= false; {$IFDEF PAS2C} - s:= 'hw'; + s:= '/Screenshots/hw'; {$ELSE} - s:= 'hw_' + FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks); + s:= '/Screenshots/hw_' + FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks); {$ENDIF} + // flash playSound(sndShutter); - - if MakeScreenshot(s) then + ScreenFade:= sfFromWhite; + ScreenFadeValue:= sfMax; + ScreenFadeSpeed:= 5; + + if MakeScreenshot(s, 1) then WriteLnToConsole('Screenshot saved: ' + s) else begin @@ -264,6 +275,39 @@ end; end; +{$IFDEF USE_VIDEO_RECORDING} +procedure RecorderMainLoop; +var oldGameTicks, oldRealTicks, newGameTicks, newRealTicks: LongInt; +begin + if not BeginVideoRecording() then + exit; + DoTimer(0); // gsLandGen -> gsStart + DoTimer(0); // gsStart -> gsGame + + if not LoadNextCameraPosition(newRealTicks, newGameTicks) then + exit; + fastScrolling:= true; + DoGameTick(newGameTicks); + fastScrolling:= false; + oldRealTicks:= 0; + oldGameTicks:= newGameTicks; + + while LoadNextCameraPosition(newRealTicks, newGameTicks) do + begin + IPCCheckSock(); + DoGameTick(newGameTicks - oldGameTicks); + if GameState = gsExit then + break; + ProcessVisualGears(newRealTicks - oldRealTicks); + DrawWorld(newRealTicks - oldRealTicks); + EncodeFrame(); + oldRealTicks:= newRealTicks; + oldGameTicks:= newGameTicks; + end; + StopVideoRecording(); +end; +{$ENDIF} + /////////////// procedure Game{$IFDEF HWLIBRARY}(gameArgs: PPChar); cdecl; export{$ENDIF}; var p: TPathType; @@ -330,11 +374,18 @@ SDLTry(TTF_Init() <> -1, true); WriteLnToConsole(msgOK); - // show main window - if cFullScreen then - ParseCommand('fullscr 1', true) +{$IFDEF USE_VIDEO_RECORDING} + if GameType = gmtRecord then + InitOffscreenOpenGL() else - ParseCommand('fullscr 0', true); +{$ENDIF} + begin + // show main window + if cFullScreen then + ParseCommand('fullscr 1', true) + else + ParseCommand('fullscr 0', true); + end; ControllerInit(); // has to happen before InitKbdKeyTable to map keys InitKbdKeyTable(); @@ -371,12 +422,22 @@ InitTeams(); AssignStores(); + + if GameType = gmtRecord then + SetSound(false); + InitSound(); isDeveloperMode:= false; TryDo(InitStepsFlags = cifAllInited, 'Some parameters not set (flags = ' + inttostr(InitStepsFlags) + ')', true); ParseCommand('rotmask', true); - MainLoop(); + +{$IFDEF USE_VIDEO_RECORDING} + if GameType = gmtRecord then + RecorderMainLoop() + else +{$ENDIF} + MainLoop(); // clean up all the memory allocated freeEverything(true); @@ -458,6 +519,7 @@ //uAIAmmoTests does not need to be freed //uAIActions does not need to be freed uStore.freeModule; +{$IFDEF USE_VIDEO_RECORDING}uVideoRec.freeModule;{$ENDIF} end; uIO.freeModule; @@ -531,11 +593,14 @@ else if (ParamCount = 3) and ((ParamStr(3) = '--stats-only') or (ParamStr(3) = 'landpreview')) then internalSetGameTypeLandPreviewFromParameters() + else if ParamCount = cDefaultParamNum then + internalStartGameWithParameters() +{$IFDEF USE_VIDEO_RECORDING} + else if ParamCount = cVideorecParamNum then + internalStartVideoRecordingWithParameters() +{$ENDIF} else - if (ParamCount = cDefaultParamNum) then - internalStartGameWithParameters() - else - playReplayFileWithParameters(); + playReplayFileWithParameters(); end; //////////////////////////////////////////////////////////////////////////////// diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/options.inc diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/pas2cSystem.pas --- a/hedgewars/pas2cSystem.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/pas2cSystem.pas Sun Sep 16 16:54:51 2012 +0200 @@ -38,6 +38,7 @@ PPChar = ^Pchar; PByte = ^Byte; + PWord = ^Word; PLongInt = ^LongInt; PLongWord = ^LongWord; PInteger = ^Integer; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uAIActions.pas --- a/hedgewars/uAIActions.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uAIActions.pas Sun Sep 16 16:54:51 2012 +0200 @@ -67,7 +67,7 @@ procedure ProcessAction(var Actions: TActions; Me: PGear); implementation -uses uAIMisc, uAI, uAmmos, uVariables, uCommands, uUtils, uDebug, uIO{$IFDEF TRACEAIACTIONS}, uConsole{$ENDIF}; +uses uAIMisc, uAI, uAmmos, uVariables, uCommands, uUtils, uIO{$IFDEF TRACEAIACTIONS}, uConsole{$ENDIF}; var PrevX: LongInt = 0; timedelta: Longword = 0; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uAIAmmoTests.pas Sun Sep 16 16:54:51 2012 +0200 @@ -123,7 +123,7 @@ const BadTurn = Low(LongInt) div 4; implementation -uses uAIMisc, uVariables, uUtils, uGearsHandlers, uCollisions; +uses uAIMisc, uVariables, uUtils, uGearsHandlers; function Metric(x1, y1, x2, y2: LongInt): LongInt; inline; begin @@ -612,10 +612,7 @@ y:= hwFloat2Float(Me^.Y); if Abs(trunc(x) - Targ.X) + Abs(trunc(y) - Targ.Y) < 40 then - begin - TestDesertEagle:= BadTurn; exit(BadTurn); - end; t:= 2 / sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y)); Vx:= (Targ.X - x) * t; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uAIMisc.pas Sun Sep 16 16:54:51 2012 +0200 @@ -429,7 +429,7 @@ if dmg > 0 then begin - if Flags and afTrackFall <> 0 then + if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then begin dX:= 0.005 * dmg + 0.01; dY:= dX; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uCommandHandlers.pas Sun Sep 16 16:54:51 2012 +0200 @@ -26,7 +26,8 @@ procedure freeModule; implementation -uses uCommands, uTypes, uVariables, uIO, uDebug, uConsts, uScript, uUtils, SDLh, uRandom, uCaptions; +uses uCommands, uTypes, uVariables, uIO, uDebug, uConsts, uScript, uUtils, SDLh, uRandom, uCaptions + {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF}; var prevGState: TGameState = gsConfirm; @@ -412,8 +413,7 @@ end; procedure chNextTurn(var s: shortstring); -var i: Longword; - gi: PGear; +var gi: PGear; begin s:= s; // avoid compiler hint @@ -530,6 +530,17 @@ flagMakeCapture:= true end; +procedure chRecord(var s: shortstring); +begin +s:= s; // avoid compiler hint +{$IFDEF USE_VIDEO_RECORDING} +if flagPrerecording then + StopPreRecording() +else + BeginPreRecording(); +{$ENDIF} +end; + procedure chSetMap(var s: shortstring); begin if isDeveloperMode then @@ -785,6 +796,11 @@ fastUntilLag:= StrToInt(s) <> 0 end; +procedure chCampVar(var s:shortstring); +begin + CampaignVariable := s; +end; + procedure initModule; begin //////// Begin top sorted by freq analysis not including chatmsg @@ -868,6 +884,8 @@ RegisterVariable('-cur_l' , @chCurL_m , true ); RegisterVariable('+cur_r' , @chCurR_p , true ); RegisterVariable('-cur_r' , @chCurR_m , true ); + RegisterVariable('campvar' , @chCampVar , true ); + RegisterVariable('record' , @chRecord , true ); end; procedure freeModule; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uConsts.pas Sun Sep 16 16:54:51 2012 +0200 @@ -28,6 +28,7 @@ const sfMax = 1000; cDefaultParamNum = 17; + cVideorecParamNum = cDefaultParamNum + 7; // message constants errmsgCreateSurface = 'Error creating SDL surface'; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uFloat.pas --- a/hedgewars/uFloat.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uFloat.pas Sun Sep 16 16:54:51 2012 +0200 @@ -115,6 +115,7 @@ _0_0005: hwFloat = (isNegative: false; QWordValue: 2147484); _0_001: hwFloat = (isNegative: false; QWordValue: 4294967); _0_003: hwFloat = (isNegative: false; QWordValue: 12884902); + _0_0032: hwFloat = (isNegative: false; QWordValue: 13743895); _0_004: hwFloat = (isNegative: false; QWordValue: 17179869); _0_005: hwFloat = (isNegative: false; QWordValue: 21474836); _0_008: hwFloat = (isNegative: false; QWordValue: 34359738); @@ -149,12 +150,14 @@ _0_999: hwFloat = (isNegative: false; QWordValue: 4290672328); _0: hwFloat = (isNegative: false; QWordValue: 0); _1: hwFloat = (isNegative: false; QWordValue: 4294967296); + _1_2: hwFloat = (isNegative: false; QWordValue: 1288490189*4); _1_5: hwFloat = (isNegative: false; QWordValue: 4294967296 * 3 div 2); _1_6: hwFloat = (isNegative: false; QWordValue: 4294967296 * 8 div 5); _1_9: hwFloat = (isNegative: false; QWordValue: 8160437862); _2: hwFloat = (isNegative: false; QWordValue: 4294967296 * 2); _2_4: hwFloat = (isNegative: false; QWordValue: 4294967296 * 12 div 5); _3: hwFloat = (isNegative: false; QWordValue: 4294967296 * 3); + _3_2: hwFloat = (isNegative: false; QWordValue: 3435973837*4); _PI: hwFloat = (isNegative: false; QWordValue: 13493037704); _4: hwFloat = (isNegative: false; QWordValue: 4294967296 * 4); _4_5: hwFloat = (isNegative: false; QWordValue: 4294967296 * 9 div 2); @@ -203,20 +206,21 @@ {$IFDEF FPC} -function int2hwFloat (const i: LongInt) : hwFloat; +function int2hwFloat (const i: LongInt) : hwFloat; inline; begin int2hwFloat.isNegative:= i < 0; int2hwFloat.Round:= abs(i); int2hwFloat.Frac:= 0 end; -function hwFloat2Float (const i: hwFloat) : extended; +function hwFloat2Float (const i: hwFloat) : extended; inline; begin -hwFloat2Float:= i.QWordValue / $100000000; +hwFloat2Float:= i.Frac / $100000000 + i.Round; if i.isNegative then hwFloat2Float:= -hwFloat2Float; end; +{$IFNDEF WEB} operator = (const z1, z2: hwFloat) z : boolean; inline; begin z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue); @@ -229,7 +233,7 @@ end; {$ENDIF} -operator + (const z1, z2: hwFloat) z : hwFloat; +operator + (const z1, z2: hwFloat) z : hwFloat; inline; begin if z1.isNegative = z2.isNegative then begin @@ -249,7 +253,7 @@ end end; -operator - (const z1, z2: hwFloat) z : hwFloat; +operator - (const z1, z2: hwFloat) z : hwFloat; inline; begin if z1.isNegative = z2.isNegative then if z1.QWordValue > z2.QWordValue then @@ -269,27 +273,150 @@ end end; -operator - (const z1: hwFloat) z : hwFloat; +function isZero(const z: hwFloat): boolean; inline; +begin +isZero := z.QWordValue = 0; +end; + +operator < (const z1, z2: hwFloat) b : boolean; inline; +begin +if z1.isNegative xor z2.isNegative then + b:= z1.isNegative +else + if z1.QWordValue = z2.QWordValue then + b:= false + else + b:= not((z1.QWordValue = z2.QWordValue) or ((z2.QWordValue < z1.QWordValue) <> z1.isNegative)) +end; + +operator > (const z1, z2: hwFloat) b : boolean; inline; +begin +if z1.isNegative xor z2.isNegative then + b:= z2.isNegative +else + if z1.QWordValue = z2.QWordValue then + b:= false + else + b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative +end; +{$ENDIF} +{$IFDEF WEB} +(* + Mostly to be kind to JS as of 2012-08-27 where there is no int64/uint64. This may change though. +*) +operator = (const z1, z2: hwFloat) z : boolean; inline; +begin + z:= (z1.isNegative = z2.isNegative) and (z1.Frac = z2.Frac) and (z1.Round = z2.Round); +end; + +operator <> (const z1, z2: hwFloat) z : boolean; inline; +begin + z:= (z1.isNegative <> z2.isNegative) or (z1.Frac <> z2.Frac) or (z1.Round <> z2.Round); +end; + +operator + (const z1, z2: hwFloat) z : hwFloat; inline; +begin +if z1.isNegative = z2.isNegative then + begin + z:= z1; + z.Frac:= z.Frac + z2.Frac; + z.Round:= z.Round + z2.Round; + if z.Frac z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac)) then + begin + z.isNegative:= z1.isNegative; + z.Round:= z1.Round - z2.Round; + z.Frac:= z1.Frac - z2.Frac; + if z2.Frac > z1.Frac then dec(z.Round) + end + else + begin + z.isNegative:= z2.isNegative; + z.Round:= z2.Round - z1.Round; + z.Frac:= z2.Frac-z1.Frac; + if z2.Frac < z1.Frac then dec(z.Round) + end +end; + +operator - (const z1, z2: hwFloat) z : hwFloat; inline; +begin +if z1.isNegative = z2.isNegative then + if (z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac)) then + begin + z.isNegative:= z1.isNegative; + z.Round:= z1.Round - z2.Round; + z.Frac:= z1.Frac-z2.Frac; + if z2.Frac > z1.Frac then dec(z.Round) + end + else + begin + z.isNegative:= not z2.isNegative; + z.Round:= z2.Round - z1.Round; + z.Frac:= z2.Frac-z1.Frac; + if z2.Frac < z1.Frac then dec(z.Round) + end +else + begin + z:= z1; + z.Frac:= z.Frac + z2.Frac; + z.Round:= z.Round + z2.Round; + if z.Frac z1.isNegative +end; + +operator > (const z1, z2: hwFloat) b : boolean; inline; +begin +if z1.isNegative xor z2.isNegative then + b:= z2.isNegative +else +(* + if z1.QWordValue = z2.QWordValue then + b:= false + else*) + b:= ((z1.Round > z2.Round) or ((z1.Round = z2.Round) and (z1.Frac > z2.Frac))) <> z1.isNegative +end; + +function isZero(const z: hwFloat): boolean; inline; +begin +isZero := (z.Round = 0) and (z.Frac = 0); +end; +{$ENDIF} + +operator - (const z1: hwFloat) z : hwFloat; inline; begin z:= z1; z.isNegative:= not z.isNegative end; -operator * (const z1, z2: hwFloat) z : hwFloat; +operator * (const z1, z2: hwFloat) z : hwFloat; inline; begin z.isNegative:= z1.isNegative xor z2.isNegative; z.QWordValue:= QWord(z1.Round) * z2.Frac + QWord(z1.Frac) * z2.Round + ((QWord(z1.Frac) * z2.Frac) shr 32); z.Round:= z.Round + QWord(z1.Round) * z2.Round; end; -operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; +operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline; begin z.isNegative:= z1.isNegative xor (z2 < 0); z.QWordValue:= z1.QWordValue * abs(z2) end; -operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; +operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline; var t: hwFloat; begin z.isNegative:= z1.isNegative xor z2.isNegative; @@ -311,34 +438,12 @@ end end; -operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; +operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline; begin z.isNegative:= z1.isNegative xor (z2 < 0); z.QWordValue:= z1.QWordValue div abs(z2) end; -operator < (const z1, z2: hwFloat) b : boolean; -begin -if z1.isNegative xor z2.isNegative then - b:= z1.isNegative -else - if z1.QWordValue = z2.QWordValue then - b:= false - else - b:= (z1.QWordValue < z2.QWordValue) xor z1.isNegative -end; - -operator > (const z1, z2: hwFloat) b : boolean; -begin -if z1.isNegative xor z2.isNegative then - b:= z2.isNegative -else - if z1.QWordValue = z2.QWordValue then - b:= false - else - b:= (z1.QWordValue > z2.QWordValue) xor z2.isNegative -end; - function cstr(const z: hwFloat): shortstring; var tmpstr: shortstring; begin @@ -367,7 +472,7 @@ hwAbs.isNegative:= false end; -function hwSqr(const t: hwFloat): hwFloat; +function hwSqr(const t: hwFloat): hwFloat; inline; begin hwSqr.isNegative:= false; hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32); @@ -468,11 +573,6 @@ else AngleCos.QWordValue:= SinTable[Angle - 1024] end; - -function isZero(const z: hwFloat): boolean; inline; -begin -isZero := z.QWordValue = 0; -end; {$ENDIF} end. diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGame.pas --- a/hedgewars/uGame.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGame.pas Sun Sep 16 16:54:51 2012 +0200 @@ -26,7 +26,9 @@ //////////////////// implementation //////////////////// -uses uInputHandler, uTeams, uIO, uAI, uGears, uSound, uMobile, uVisualGears, uTypes, uVariables{$IFDEF SDL13}, uTouch{$ENDIF}; +uses uInputHandler, uTeams, uIO, uAI, uGears, uSound, uMobile, + uVisualGears, uTypes, uVariables, uCommands, uConsts + {$IFDEF SDL13}, uTouch{$ENDIF}; procedure DoGameTick(Lag: LongInt); var i: LongInt; @@ -39,13 +41,15 @@ isInLag:= false; SendKeepAliveMessage(Lag) end; -if Lag > 100 then - Lag:= 100 -else if (GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) then - Lag:= 2500; +if GameType <> gmtRecord then + begin + if Lag > 100 then + Lag:= 100 + else if (GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) then + Lag:= 2500; -if (GameType = gmtDemo) then - if isSpeed then + if (GameType = gmtDemo) then + if isSpeed then begin i:= RealTicks-SpeedStart; if i < 2000 then Lag:= Lag*5 @@ -54,9 +58,10 @@ else if i < 8000 then Lag:= Lag*40 else Lag:= Lag*80; end - else - if cOnlyStats then - Lag:= High(LongInt); + else + if cOnlyStats then + Lag:= High(LongInt); + end; PlayNextVoice; i:= 1; while (GameState <> gsExit) and (i <= Lag) do @@ -78,14 +83,14 @@ AddVisualGear(0, 0, vgtTeamHealthSorter); break; end; - gmtDemo: begin + gmtDemo, gmtRecord: begin GameState:= gsExit; exit end; gmtSave: begin RestoreTeamsFromSave; SetBinds(CurrentTeam^.Binds); - //CurrentHedgehog^.Gear^.Message:= 0; <- produces bugs with further save restoring and demos + StopMessages(gmLeft or gmRight or gmUp or gmDown); ResetSound; // restore previous sound state PlayMusic; GameType:= gmtLocal; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGears.pas Sun Sep 16 16:54:51 2012 +0200 @@ -284,7 +284,7 @@ end; stChWin: begin - CheckForWin; + CheckForWin(); inc(step) end; stWater: @@ -296,8 +296,8 @@ AddGear(0, 0, gtWaterUp, 0, _0, _0, 0)^.Tag:= cWaterRise; inc(step) end - else - inc(step); + else // since we are not raising the water, a second win-check isn't needed + inc(step,2); stChWin2: begin CheckForWin; @@ -570,7 +570,7 @@ Gear:= GearsList; while Gear <> nil do begin - if Gear^.State and gstInvisible = 0 then + if (Gear^.State and gstInvisible = 0) and (Gear^.Message and gmRemoveFromList = 0) then begin x:= hwRound(Gear^.X) + WorldDx; y:= hwRound(Gear^.Y) + WorldDy; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGearsHandlers.pas --- a/hedgewars/uGearsHandlers.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGearsHandlers.pas Sun Sep 16 16:54:51 2012 +0200 @@ -47,7 +47,6 @@ var xx, yy, xxn, yyn: LongInt; dA: LongInt; - tdx, tdy: hwFloat; begin dA := hwSign(Gear^.dX); xx := dirs[Gear^.Angle].x; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGearsHandlersRope.pas --- a/hedgewars/uGearsHandlersRope.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGearsHandlersRope.pas Sun Sep 16 16:54:51 2012 +0200 @@ -73,165 +73,57 @@ end end; -procedure unstickHog(Gear, HHGear: PGear); -var i: LongInt; - stuck: Boolean; -begin - if (TestCollisionYwithGear(HHGear, 1) <> 0) and (TestCollisionYwithGear(HHGear, -1) = 0) then - begin - i:= 1; - repeat - begin - inc(i); - stuck:= TestCollisionYwithGear(HHGear, 1) <> 0; - if stuck then HHGear^.Y:= HHGear^.Y-_1 - end - until (i = 8) or (not stuck); - HHGear^.Y:= HHGear^.Y+_1; - // experiment in simulating something the shoppa players apparently expect - if Gear^.Message and gmDown <> 0 then - begin - //HHGear^.dY:= HHGear^.dY / 16; - //HHGear^.dY.QWordValue:= 0; - HHGear^.dY:= -_0_1; - HHGear^.dX:= HHGear^.dX * _1_5; - end; - if Gear^.Message and gmRight <> 0 then - HHGear^.dX.isNegative:= false - else if Gear^.Message and gmLeft <> 0 then - HHGear^.dX.isNegative:= true - end - else if (TestCollisionYwithGear(HHGear, -1) <> 0) and (TestCollisionYwithGear(HHGear, 1) = 0) then - begin - i:= 1; - repeat - begin - inc(i); - stuck:= TestCollisionYwithGear(HHGear, -1) <> 0; - if stuck then HHGear^.Y:= HHGear^.Y+_1 - end - until (i = 8) or (not stuck); - HHGear^.Y:= HHGear^.Y-_1; - if Gear^.Message and gmDown <> 0 then - begin - //HHGear^.dY:= HHGear^.dY / 16; - //HHGear^.dY.QWordValue:= 0; - HHGear^.dY:= _0_1; - HHGear^.dX:= HHGear^.dX * _1_5; - end; - if Gear^.Message and gmRight <> 0 then - HHGear^.dX.isNegative:= true - else if Gear^.Message and gmLeft <> 0 then - HHGear^.dX.isNegative:= false - end; - if TestCollisionXwithGear(HHGear, 1) and (not TestCollisionXwithGear(HHGear, -1)) then - begin - i:= 1; - repeat - begin - inc(i); - stuck:= TestCollisionXwithGear(HHGear, 1); - if stuck then HHGear^.X:= HHGear^.X-_1 - end - until (i = 8) or (not stuck); - HHGear^.X:= HHGear^.X+_1; - if Gear^.Message and gmDown <> 0 then - begin - //HHGear^.dX:= HHGear^.dX / 16; - //HHGear^.dX.QWordValue:= 0; - HHGear^.dX:= -_0_1; - HHGear^.dY:= HHGear^.dY * _1_5; - end; - if Gear^.Message and gmRight <> 0 then - HHGear^.dY.isNegative:= true - else if Gear^.Message and gmLeft <> 0 then - HHGear^.dY.isNegative:= false - end - else if TestCollisionXwithGear(HHGear, -1) and (not TestCollisionXwithGear(HHGear, 1)) then - begin - i:= 1; - repeat - begin - inc(i); - stuck:= TestCollisionXwithGear(HHGear, -1); - if stuck then HHGear^.X:= HHGear^.X+_1 - end - until (i = 8) or (not stuck); - HHGear^.X:= HHGear^.X-_1; - if Gear^.Message and gmDown <> 0 then - begin - //HHGear^.dX:= HHGear^.dX / 16; - //HHGear^.dX.QWordValue:= 0; - HHGear^.dX:= _0_1; - HHGear^.dY:= HHGear^.dY * _1_5; - end; - if Gear^.Message and gmRight <> 0 then - HHGear^.dY.isNegative:= false - else if Gear^.Message and gmLeft <> 0 then - HHGear^.dY.isNegative:= true - end -end; - procedure RopeDeleteMe(Gear, HHGear: PGear); begin - PlaySound(sndRopeRelease); - HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue div Gear^.stepFreq; - HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue div Gear^.stepFreq; with HHGear^ do begin Message := Message and (not gmAttack); State := (State or gstMoving) and (not gstWinner); end; - unstickHog(Gear, HHGear); DeleteGear(Gear) end; procedure RopeWaitCollision(Gear, HHGear: PGear); begin - PlaySound(sndRopeRelease); with HHGear^ do begin Message := Message and (not gmAttack); State := State or gstMoving; end; - unstickHog(Gear, HHGear); RopePoints.Count := 0; Gear^.Elasticity := _0; - Gear^.doStep := @doStepRopeAfterAttack; - HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue div Gear^.stepFreq; - HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue div Gear^.stepFreq; - Gear^.stepFreq := 1 + Gear^.doStep := @doStepRopeAfterAttack end; procedure doStepRopeWork(Gear: PGear); var HHGear: PGear; - len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY, t: hwFloat; - lx, ly, cd, i: LongInt; + len, tx, ty, nx, ny, ropeDx, ropeDy, mdX, mdY: hwFloat; + lx, ly, cd: LongInt; haveCollision, haveDivided: boolean; begin - if GameTicks mod 8 <> 0 then exit; + if GameTicks mod 4 <> 0 then exit; HHGear := Gear^.Hedgehog^.Gear; - haveCollision:= false; - if (Gear^.Message and gmLeft <> 0) and (not TestCollisionXwithGear(HHGear, -1)) then - HHGear^.dX := HHGear^.dX - _0_0128 - else haveCollision:= true; - - if (Gear^.Message and gmRight <> 0) and (not TestCollisionXwithGear(HHGear, 1)) then - HHGear^.dX := HHGear^.dX + _0_0128 - else haveCollision:= true; - if ((HHGear^.State and gstHHDriven) = 0) or (CheckGearDrowning(HHGear)) or (Gear^.PortalCounter <> 0) then begin + PlaySound(sndRopeRelease); RopeDeleteMe(Gear, HHGear); exit end; + HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue shl 2; + HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue shl 2; + if (Gear^.Message and gmLeft <> 0) and (not TestCollisionXwithGear(HHGear, -1)) then + HHGear^.dX := HHGear^.dX - _0_0032; + + if (Gear^.Message and gmRight <> 0) and (not TestCollisionXwithGear(HHGear, 1)) then + HHGear^.dX := HHGear^.dX + _0_0032; + // vector between hedgehog and rope attaching point ropeDx := HHGear^.X - Gear^.X; ropeDy := HHGear^.Y - Gear^.Y; @@ -248,37 +140,13 @@ // apply gravity if there is no obstacle if not TestCollisionXwithGear(HHGear, cd) then - HHGear^.dY := HHGear^.dY + cGravity * 64; + HHGear^.dY := HHGear^.dY + cGravity * 16; if (GameFlags and gfMoreWind) <> 0 then // apply wind if there's no obstacle if not TestCollisionXwithGear(HHGear, hwSign(cWindSpeed)) then - HHGear^.dX := HHGear^.dX + cWindSpeed * 64 / HHGear^.Density; - end - else haveCollision:= true; - - if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then - if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx)) - or (TestCollisionYwithGear(HHGear, hwSign(ropeDy)) <> 0)) then - Gear^.Elasticity := Gear^.Elasticity + _2_4 - else haveCollision:= true; - - if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then - if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx)) - or (TestCollisionYwithGear(HHGear, -hwSign(ropeDy)) <> 0)) then - Gear^.Elasticity := Gear^.Elasticity - _2_4 - else haveCollision:= true; - -(* -I am not so sure this is useful. Disabling - if haveCollision then - begin - if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) and not TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then - HHGear^.dX.isNegative:= not HHGear^.dX.isNegative; - if (TestCollisionYwithGear(HHGear, hwSign(HHGear^.dY)) <> 0) and (TestCollisionYwithGear(HHGear, -hwSign(HHGear^.dY)) = 0) then - HHGear^.dY.isNegative:= not HHGear^.dY.isNegative; + HHGear^.dX := HHGear^.dX + cWindSpeed * 16 / HHGear^.Density; end; -*) mdX := ropeDx + HHGear^.dX; mdY := ropeDy + HHGear^.dY; @@ -295,6 +163,16 @@ tx := HHGear^.X; ty := HHGear^.Y; + if ((Gear^.Message and gmDown) <> 0) and (Gear^.Elasticity < Gear^.Friction) then + if not (TestCollisionXwithGear(HHGear, hwSign(ropeDx)) + or (TestCollisionYwithGear(HHGear, hwSign(ropeDy)) <> 0)) then + Gear^.Elasticity := Gear^.Elasticity + _1_2; + + if ((Gear^.Message and gmUp) <> 0) and (Gear^.Elasticity > _30) then + if not (TestCollisionXwithGear(HHGear, -hwSign(ropeDx)) + or (TestCollisionYwithGear(HHGear, -hwSign(ropeDy)) <> 0)) then + Gear^.Elasticity := Gear^.Elasticity - _1_2; + HHGear^.X := Gear^.X + mdX * Gear^.Elasticity; HHGear^.Y := Gear^.Y + mdY * Gear^.Elasticity; @@ -309,8 +187,8 @@ len := Gear^.Elasticity - _5; nx := Gear^.X + mdX * len; ny := Gear^.Y + mdY * len; - tx := mdX * _2_4; // should be the same as increase step - ty := mdY * _2_4; + tx := mdX * _1_2; // should be the same as increase step + ty := mdY * _1_2; while len > _3 do begin @@ -351,8 +229,8 @@ nx := nx - tx; ny := ny - ty; - // len := len - _2_4 // should be the same as increase step - len.QWordValue := len.QWordValue - _2_4.QWordValue; + // len := len - _1_2 // should be the same as increase step + len.QWordValue := len.QWordValue - _1_2.QWordValue; end; if not haveDivided then @@ -394,14 +272,14 @@ if haveCollision and (Gear^.Message and (gmLeft or gmRight) <> 0) and (Gear^.Message and (gmUp or gmDown) <> 0) then begin - HHGear^.dX := SignAs(hwAbs(HHGear^.dX) + _1_6, HHGear^.dX); - HHGear^.dY := SignAs(hwAbs(HHGear^.dY) + _1_6, HHGear^.dY) + HHGear^.dX := SignAs(hwAbs(HHGear^.dX) + _0_8, HHGear^.dX); + HHGear^.dY := SignAs(hwAbs(HHGear^.dY) + _0_8, HHGear^.dY) end; len := hwSqr(HHGear^.dX) + hwSqr(HHGear^.dY); - if len > _49 then + if len > _10 then begin - len := _7 / hwSqrt(len); + len := _3_2 / hwSqrt(len); HHGear^.dX := HHGear^.dX * len; HHGear^.dY := HHGear^.dY * len; end; @@ -443,10 +321,12 @@ if (Gear^.Message and gmAttack) <> 0 then haveCollision:= false; - if not haveCollision then + HHGear^.dX.QWordValue:= HHGear^.dX.QWordValue shr 2; + HHGear^.dY.QWordValue:= HHGear^.dY.QWordValue shr 2; + if (not haveCollision) and ((Gear^.State and gsttmpFlag) <> 0) then begin - if (Gear^.State and gsttmpFlag) <> 0 then begin + PlaySound(sndRopeRelease); if Gear^.Hedgehog^.CurAmmoType <> amParachute then RopeWaitCollision(Gear, HHGear) else @@ -516,12 +396,9 @@ Gear^.Y := Gear^.Y + ty; Gear^.Elasticity := tt; Gear^.doStep := @doStepRopeWork; - Gear^.stepFreq:= 8; PlaySound(sndRopeAttach); with HHGear^ do begin - dX.QWordValue:= dX.QWordValue shl 3; - dY.QWordValue:= dY.QWordValue shl 3; State := State and (not (gstAttacking or gstHHJumping or gstHHHJump)); Message := Message and (not gmAttack) end; @@ -547,12 +424,9 @@ else begin Gear^.doStep := @doStepRopeWork; - Gear^.stepFreq:= 8; PlaySound(sndRopeAttach); with HHGear^ do begin - dX.QWordValue:= dX.QWordValue shl 3; - dY.QWordValue:= dY.QWordValue shl 3; State := State and (not (gstAttacking or gstHHJumping or gstHHHJump)); Message := Message and (not gmAttack) end; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGearsHedgehog.pas --- a/hedgewars/uGearsHedgehog.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGearsHedgehog.pas Sun Sep 16 16:54:51 2012 +0200 @@ -234,8 +234,8 @@ and ((Gear^.Message and gmLJump) <> 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then begin - newDx:= dX / CurAmmoGear^.stepFreq; - newDy:= dY / CurAmmoGear^.stepFreq; + newDx:= dX; + newDy:= dY; altUse:= true end else @@ -357,7 +357,7 @@ amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000); amIceGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtIceGun, 0, _0, _0, 0); end; - if altUse then + if altUse and (newGear <> nil) then begin newGear^.dX:= newDx / newGear^.Density; newGear^.dY:= newDY / newGear^.Density @@ -598,7 +598,6 @@ //////////////////////////////////////////////////////////////////////////////// procedure PickUp(HH, Gear: PGear); var s: shortstring; - a: TAmmoType; i: LongInt; vga: PVisualGear; ag, gi: PGear; @@ -1014,8 +1013,8 @@ if (CurrentHedgehog^.Gear = Gear) then isCursorVisible:= false end; - -if (hwAbs(Gear^.dY) > _0) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then +// IMO this should trigger homerun based on leftX/rightX + someval instead - that is 'knocking it out of the park' +if (not isZero(Gear^.dY)) and (Gear^.FlightTime > 0) and ((GameFlags and gfLowGravity) = 0) then begin inc(Gear^.FlightTime); if Gear^.FlightTime = 3000 then diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGearsList.pas --- a/hedgewars/uGearsList.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGearsList.pas Sun Sep 16 16:54:51 2012 +0200 @@ -105,7 +105,6 @@ // Define ammo association, if any. gear^.AmmoType:= GearKindAmmoTypeMap[Kind]; gear^.CollisionMask:= $FFFF; -gear^.stepFreq:= 1; if CurrentHedgehog <> nil then gear^.Hedgehog:= CurrentHedgehog; @@ -178,16 +177,16 @@ if State and gstTmpFlag = 0 then begin dx.isNegative:= GetRandom(2) = 0; - dx.QWordValue:= GetRandom(100000000); + dx.QWordValue:= $40DA*GetRandom(10000)*8; dy.isNegative:= false; - dy.QWordValue:= GetRandom(70000000); + dy.QWordValue:= $3AD3*GetRandom(7000)*8; if GetRandom(2) = 0 then dx := -dx end; State:= State or gstInvisible; Health:= random(vobFrameTicks); Timer:= random(vobFramesCount); - Angle:= (random(2) * 2 - 1) * (1 + random(10000)) * vobVelocity + Damage:= (random(2) * 2 - 1) * (vobVelocity + random(vobVelocity)) * 8; end end; gtGrave: begin diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGearsRender.pas Sun Sep 16 16:54:51 2012 +0200 @@ -21,7 +21,7 @@ unit uGearsRender; interface -uses uTypes, uConsts, GLunit, uFloat, SDLh, uRandom; +uses uTypes, uConsts, GLunit, uFloat, SDLh; procedure RenderGear(Gear: PGear; x, y: LongInt); diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uGearsUtils.pas Sun Sep 16 16:54:51 2012 +0200 @@ -108,7 +108,7 @@ // Run the calcs only once we know we have a type that will need damage tdX:= Gear^.X-fX; tdY:= Gear^.Y-fY; - if hwRound(hwAbs(tdX)+hwAbs(tdY)) < dmgBase then + if (tdX.Round + tdY.Round + 2) < dmgBase then dmg:= dmgBase - hwRound(Distance(tdX, tdY)); if dmg > 1 then begin @@ -142,7 +142,7 @@ // Run the calcs only once we know we have a type that will need damage tdX:= Gear^.X-fX; tdY:= Gear^.Y-fY; - if hwRound(hwAbs(tdX)+hwAbs(tdY)) < dmgBase then + if (tdX.Round + tdY.Round + 2) < dmgBase then dmg:= dmgBase - hwRound(Distance(tdX, tdY)); if dmg > 1 then begin @@ -241,9 +241,7 @@ end; end else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure - begin Gear^.Hedgehog:= AttackerHog; - end; inc(Gear^.Damage, Damage); ScriptCall('onGearDamage', Gear^.UID, Damage); @@ -321,7 +319,8 @@ var dAngle: real; begin - dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000; +// Frac/Round to be kind to JS as of 2012-08-27 where there is yet no int64/uint64 + dAngle := (Gear^.dX.Round + Gear^.dY.Round) / 2 + (Gear^.dX.Frac+Gear^.dY.Frac) / $80000000; if not Gear^.dX.isNegative then Gear^.DirAngle := Gear^.DirAngle + dAngle else diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uIO.pas --- a/hedgewars/uIO.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uIO.pas Sun Sep 16 16:54:51 2012 +0200 @@ -126,7 +126,12 @@ 'D': GameType:= gmtDemo; 'N': GameType:= gmtNet; 'S': GameType:= gmtSave; + 'V': GameType:= gmtRecord; else OutError(errmsgIncorrectUse + ' IPC "T" :' + s[2], true) end; + 'V': begin + if s[2] = '.' then + ParseCommand('campvar ' + copy(s, 3, length(s) - 2), true); + end else loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]); AddCmd(loTicks, s); diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uInputHandler.pas --- a/hedgewars/uInputHandler.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uInputHandler.pas Sun Sep 16 16:54:51 2012 +0200 @@ -256,6 +256,7 @@ DefaultBinds[KeyNameToCode(_S'9')]:= '+voldown'; DefaultBinds[KeyNameToCode(_S'8')]:= 'mute'; DefaultBinds[KeyNameToCode(_S'c')]:= 'capture'; +DefaultBinds[KeyNameToCode(_S'r')]:= 'record'; DefaultBinds[KeyNameToCode(_S'h')]:= 'findhh'; DefaultBinds[KeyNameToCode(_S'p')]:= 'pause'; DefaultBinds[KeyNameToCode(_S's')]:= '+speedup'; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uLand.pas --- a/hedgewars/uLand.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uLand.pas Sun Sep 16 16:54:51 2012 +0200 @@ -62,8 +62,7 @@ r, rr: TSDL_Rect; x, yd, yu: LongInt; begin - tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/LandTex', ifIgnoreCaps); - if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/LandTex', ifCritical or ifIgnoreCaps); + tmpsurf:= LoadDataImage(ptCurrTheme, 'LandTex', ifCritical or ifIgnoreCaps); r.y:= 0; while r.y < LAND_HEIGHT do begin @@ -78,12 +77,10 @@ SDL_FreeSurface(tmpsurf); // freed in freeModule() below - LandBackSurface:= LoadImage(UserPathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent); - if LandBackSurface = nil then LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent); + LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent); if (LandBackSurface <> nil) and GrayScale then Surface2GrayScale(LandBackSurface); - tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/Border', ifIgnoreCaps or ifTransparent); - if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Border', ifCritical or ifIgnoreCaps or ifTransparent); + tmpsurf:= LoadDataImage(ptCurrTheme, 'Border', ifCritical or ifIgnoreCaps or ifTransparent); for x:= 0 to LAND_WIDTH - 1 do begin yd:= LAND_HEIGHT - 1; @@ -420,15 +417,11 @@ WriteLnToConsole('Generating forts land...'); -tmpsurf:= LoadImage(UserPathz[ptForts] + '/' + ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifTransparent or ifIgnoreCaps); -if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptForts] + '/' + ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); +tmpsurf:= LoadDataImage(ptForts, ClansArray[0]^.Teams[0]^.FortName + 'L', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); BlitImageAndGenerateCollisionInfo(leftX+150, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf); SDL_FreeSurface(tmpsurf); -tmpsurf:= LoadImage(UserPathz[ptForts] + '/' + ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifTransparent or ifIgnoreCaps); -if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptForts] + '/' + ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); +tmpsurf:= LoadDataImage(ptForts, ClansArray[1]^.Teams[0]^.FortName + 'R', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); BlitImageAndGenerateCollisionInfo(rightX - 150 - tmpsurf^.w, LAND_HEIGHT - tmpsurf^.h, tmpsurf^.w, tmpsurf); SDL_FreeSurface(tmpsurf); end; @@ -439,15 +432,11 @@ p: PLongwordArray; x, y, cpX, cpY: Longword; begin -tmpsurf:= LoadImage(UserPathz[ptMapCurrent] + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); -if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); +tmpsurf:= LoadDataImage(ptMapCurrent, 'mask', ifAlpha or ifTransparent or ifIgnoreCaps); if tmpsurf = nil then begin mapName:= ExtractFileName(Pathz[ptMapCurrent]); - tmpsurf:= LoadImage(UserPathz[ptMissionMaps] + '/' + mapName + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptMissionMaps] + '/' + mapName + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); + tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/mask', ifAlpha or ifTransparent or ifIgnoreCaps); end; @@ -490,9 +479,7 @@ if not disableLandBack then begin // freed in freeModule() below - LandBackSurface:= LoadImage(UserPathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent); - if LandBackSurface = nil then - LandBackSurface:= LoadImage(Pathz[ptCurrTheme] + '/LandBackTex', ifIgnoreCaps or ifTransparent); + LandBackSurface:= LoadDataImage(ptCurrTheme, 'LandBackTex', ifIgnoreCaps or ifTransparent); if (LandBackSurface <> nil) and GrayScale then Surface2GrayScale(LandBackSurface) end; @@ -510,15 +497,11 @@ begin WriteLnToConsole('Loading land from file...'); AddProgress; -tmpsurf:= LoadImage(UserPathz[ptMapCurrent] + '/map', ifAlpha or ifTransparent or ifIgnoreCaps); -if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptMapCurrent] + '/map', ifAlpha or ifTransparent or ifIgnoreCaps); +tmpsurf:= LoadDataImage(ptMapCurrent, 'map', ifAlpha or ifTransparent or ifIgnoreCaps); if tmpsurf = nil then begin mapName:= ExtractFileName(Pathz[ptMapCurrent]); - tmpsurf:= LoadImage(UserPathz[ptMissionMaps] + '/' + mapName + '/map', ifAlpha or ifTransparent or ifIgnoreCaps); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptMissionMaps] + '/' + mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); + tmpsurf:= LoadDataImage(ptMissionMaps, mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); end; // (bare) Sanity check. Considering possible LongInt comparisons as well as just how much system memoery it would take TryDo((tmpsurf^.w < $40000000) and (tmpsurf^.h < $40000000) and (tmpsurf^.w * tmpsurf^.h < 6*1024*1024*1024), 'Map dimensions too big!', true); diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uLandObjects.pas --- a/hedgewars/uLandObjects.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uLandObjects.pas Sun Sep 16 16:54:51 2012 +0200 @@ -210,13 +210,7 @@ if x1 > 0 then begin bRes:= true; - tmpsurf:= LoadImage(UserPathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptCurrTheme] + '/Girder', ifTransparent or ifIgnoreCaps); - if tmpsurf = nil then - tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/Girder', ifTransparent or ifIgnoreCaps); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptGraphics] + '/Girder', ifCritical or ifTransparent or ifIgnoreCaps); + tmpsurf:= LoadDataImageAltPath(ptCurrTheme, ptGraphics, 'Girder', ifCritical or ifTransparent or ifIgnoreCaps); rr.x:= x1; while rr.x < x2 do @@ -563,9 +557,7 @@ with ThemeObjects.objs[Pred(ThemeObjects.Count)] do begin i:= Pos(',', s); - Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps); - if Surf = nil then - Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps); + Surf:= LoadDataImage(ptCurrTheme, Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps); Width:= Surf^.w; Height:= Surf^.h; Delete(s, 1, i); @@ -623,9 +615,7 @@ with SprayObjects.objs[Pred(SprayObjects.Count)] do begin i:= Pos(',', s); - Surf:= LoadImage(UserPathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps); - if Surf = nil then - Surf:= LoadImage(Pathz[ptCurrTheme] + '/' + Trim(Copy(s, 1, Pred(i))), ifCritical or ifTransparent or ifIgnoreCaps); + Surf:= LoadDataImage(ptCurrTheme, Trim(Copy(s, 1, Pred(i))), ifTransparent or ifIgnoreCaps); Width:= Surf^.w; Height:= Surf^.h; Delete(s, 1, i); diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uMisc.pas --- a/hedgewars/uMisc.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uMisc.pas Sun Sep 16 16:54:51 2012 +0200 @@ -28,7 +28,7 @@ procedure movecursor(dx, dy: LongInt); function doSurfaceConversion(tmpsurf: PSDL_Surface): PSDL_Surface; -function MakeScreenshot(filename: shortstring): boolean; +function MakeScreenshot(filename: shortstring; k: LongInt): boolean; function GetTeamStatString(p: PTeam): shortstring; {$IFDEF SDL13} function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline; @@ -186,19 +186,48 @@ {$ENDIF} // no PNG_SCREENSHOTS +{$IFDEF USE_VIDEO_RECORDING} +// make image k times smaller (useful for saving thumbnails) +procedure ReduceImage(img: PByte; width, height, k: LongInt); +var i, j, i0, j0, w, h, r, g, b: LongInt; +begin + w:= width div k; + h:= height div k; + + // rescale inplace + if k <> 1 then + begin + for i:= 0 to h-1 do + for j:= 0 to w-1 do + begin + r:= 0; + g:= 0; + b:= 0; + for i0:= 0 to k-1 do + for j0:= 0 to k-1 do + begin + r+= img[4*(width*(i*k+i0) + j*k+j0)+0]; + g+= img[4*(width*(i*k+i0) + j*k+j0)+1]; + b+= img[4*(width*(i*k+i0) + j*k+j0)+2]; + end; + img[4*(w*i + j)+0]:= r div (k*k); + img[4*(w*i + j)+1]:= g div (k*k); + img[4*(w*i + j)+2]:= b div (k*k); + img[4*(w*i + j)+3]:= 255; + end; + end; +end; +{$ENDIF} + // captures and saves the screen. returns true on success. -function MakeScreenshot(filename: shortstring): Boolean; +// saved image will be k times smaller than original (useful for saving thumbnails). +function MakeScreenshot(filename: shortstring; k: LongInt): Boolean; var p: Pointer; size: QWord; image: PScreenshot; format: GLenum; ext: string[4]; begin -// flash -ScreenFade:= sfFromWhite; -ScreenFadeValue:= sfMax; -ScreenFadeSpeed:= 5; - {$IFDEF PNG_SCREENSHOTS} format:= GL_RGBA; ext:= '.png'; @@ -218,14 +247,18 @@ exit; end; -// read pixel from the front buffer +// read pixels from the front buffer glReadPixels(0, 0, cScreenWidth, cScreenHeight, format, GL_UNSIGNED_BYTE, p); +{$IFDEF USE_VIDEO_RECORDING} +ReduceImage(p, cScreenWidth, cScreenHeight, k); +{$ENDIF} + // allocate and fill structure that will be passed to new thread New(image); // will be disposed in SaveScreenshot() -image^.filename:= UserPathPrefix + '/Screenshots/' + filename + ext; -image^.width:= cScreenWidth; -image^.height:= cScreenHeight; +image^.filename:= UserPathPrefix + filename + ext; +image^.width:= cScreenWidth div k; +image^.height:= cScreenHeight div k; image^.size:= size; image^.buffer:= p; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uScript.pas --- a/hedgewars/uScript.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uScript.pas Sun Sep 16 16:54:51 2012 +0200 @@ -80,7 +80,8 @@ uTextures, uLandGraphics, SDLh, - SysUtils; + SysUtils, + uIO; var luaState : Plua_State; ScriptAmmoLoadout : shortstring; @@ -1661,6 +1662,68 @@ lc_getcurammotype := 1; end; +function lc_savecampaignvar(L : Plua_State): LongInt; Cdecl; +begin + if lua_gettop(L) <> 2 then + LuaError('Lua: Wrong number of parameters passed to SaveCampaignVar!') + else begin + SendIPC('V!' + lua_tostring(L, 1) + ' ' + lua_tostring(L, 2) + #0); + end; + lc_savecampaignvar := 0; +end; + +function lc_getcampaignvar(L : Plua_State): LongInt; Cdecl; +begin + if (lua_gettop(L) <> 1) then + LuaError('Lua: Wrong number of parameters passed to GetCampaignVar!') + else + SendIPCAndWaitReply('V?' + lua_tostring(L, 1)); + lua_pushstring(L, str2pchar(CampaignVariable)); + lc_getcampaignvar := 1; +end; + +function lc_hidehog(L: Plua_State): LongInt; Cdecl; +var gear: PGear; +begin + if lua_gettop(L) <> 1 then + LuaError('Lua: Wrong number of parameters passed to HideHog!') + else + begin + gear:= GearByUID(lua_tointeger(L, 1)); + hiddenHedgehogs[hiddenHedgehogsNumber]:=gear^.hedgehog; + inc(hiddenHedgehogsNumber); + HideHog(gear^.hedgehog); + end; + lc_hidehog := 0; +end; + +function lc_restorehog(L: Plua_State): LongInt; Cdecl; +var hog: PHedgehog; + i, j: LongInt; +begin + if lua_gettop(L) <> 1 then + LuaError('Lua: Wrong number of parameters passed to RestoreHog!') + else + begin + i := 0; + while (i < hiddenHedgehogsNumber) do + begin + if hiddenHedgehogs[i]^.gearHidden^.uid = lua_tointeger(L, 1) then + begin + hog := hiddenHedgehogs[i]; + RestoreHog(hog); + dec(hiddenHedgehogsNumber); + for j := i to hiddenHedgehogsNumber - 1 do + hiddenHedgehogs[j] := hiddenHedgehogs[j + 1]; + lc_restorehog := 0; + exit; + end; + inc(i); + end; + end; + lc_restorehog := 0; +end; + // boolean TestRectForObstacle(x1, y1, x2, y2, landOnly) function lc_testrectforobstacle(L : Plua_State) : LongInt; Cdecl; var rtn: Boolean; @@ -1887,9 +1950,14 @@ ScriptSetInteger('RealTime', RealTicks); ScriptSetInteger('TotalRounds', TotalRounds); ScriptSetInteger('WaterLine', cWaterLine); -ScriptSetInteger('LeftX', leftX); -ScriptSetInteger('RightX', rightX); -ScriptSetInteger('TopY', topY); +if GameTicks = 0 then + begin + ScriptSetInteger('LAND_WIDTH', LAND_WIDTH); + ScriptSetInteger('LAND_HEIGHT', LAND_HEIGHT); + ScriptSetInteger('LeftX', leftX); + ScriptSetInteger('RightX', rightX); + ScriptSetInteger('TopY', topY) + end; if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) then ScriptSetInteger('CurrentHedgehog', CurrentHedgehog^.Gear^.UID) else @@ -2086,8 +2154,6 @@ luaopen_table(luaState); // import some variables -ScriptSetInteger('LAND_WIDTH', LAND_WIDTH); -ScriptSetInteger('LAND_HEIGHT', LAND_HEIGHT); ScriptSetString(_S'L', cLocale); // import game flags @@ -2182,6 +2248,10 @@ ScriptSetInteger('gstInvisible' ,$00200000); // register functions +lua_register(luaState, _P'HideHog', @lc_hidehog); +lua_register(luaState, _P'RestoreHog', @lc_restorehog); +lua_register(luaState, _P'SaveCampaignVar', @lc_savecampaignvar); +lua_register(luaState, _P'GetCampaignVar', @lc_getcampaignvar); lua_register(luaState, _P'band', @lc_band); lua_register(luaState, _P'bor', @lc_bor); lua_register(luaState, _P'bnot', @lc_bnot); diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uStore.pas --- a/hedgewars/uStore.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uStore.pas Sun Sep 16 16:54:51 2012 +0200 @@ -21,7 +21,7 @@ unit uStore; interface -uses SysUtils, uConsts, SDLh, GLunit, uTypes, uLandTexture, uCaptions, uChat; +uses {$IFNDEF PAS2C} StrUtils, {$ENDIF}SysUtils, uConsts, SDLh, GLunit, uTypes, uLandTexture, uCaptions, uChat; procedure initModule; procedure freeModule; @@ -32,6 +32,14 @@ procedure AddProgress; procedure FinishProgress; function LoadImage(const filename: shortstring; imageFlags: LongInt): PSDL_Surface; + +// loads an image from the game's data files +function LoadDataImage(const path: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +// like LoadDataImage but uses altPath as fallback-path if file not found/loadable in path +function LoadDataImageAltPath(const path, altPath: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +// like LoadDataImage but uses altFile as fallback-filename if file cannot be loaded +function LoadDataImageAltFile(const path: TPathType; const filename, altFile: shortstring; imageFlags: LongInt): PSDL_Surface; + procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring); procedure SetupOpenGL; procedure SetScale(f: GLfloat); @@ -40,13 +48,17 @@ procedure ShowWeaponTooltip(x, y: LongInt); procedure FreeWeaponTooltip; procedure MakeCrossHairs; +{$IFDEF USE_VIDEO_RECORDING} +procedure InitOffscreenOpenGL; +{$ENDIF} procedure WarpMouse(x, y: Word); inline; procedure SwapBuffers; inline; implementation uses uMisc, uConsole, uMobile, uVariables, uUtils, uTextures, uRender, uRenderUtils, uCommands, - uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF}; + uDebug{$IFDEF USE_CONTEXT_RESTORE}, uWorld{$ENDIF} + {$IF NOT DEFINED(SDL13) AND DEFINED(USE_VIDEO_RECORDING)}, glut {$ENDIF}; //type TGPUVendor = (gvUnknown, gvNVIDIA, gvATI, gvIntel, gvApple); @@ -91,9 +103,7 @@ Color, i: Longword; s: shortstring; begin -s:= UserPathz[ptGraphics] + '/' + cCHFileName; -if not FileExists(s+'.png') then s:= Pathz[ptGraphics] + '/' + cCHFileName; -tmpsurf:= LoadImage(s, ifAlpha or ifCritical); +tmpsurf:= LoadDataImage(ptGraphics, cCHFileName, ifAlpha or ifCritical); for t:= 0 to Pred(TeamsCount) do with TeamsArray[t]^ do @@ -196,13 +206,7 @@ else if (Flag = 'cpu') or (Flag = 'cpu_plain') then Flag:= 'hedgewars'; - flagsurf:= LoadImage(UserPathz[ptFlags] + '/' + Flag, ifNone); - if flagsurf = nil then - flagsurf:= LoadImage(Pathz[ptFlags] + '/' + Flag, ifNone); - if flagsurf = nil then - flagsurf:= LoadImage(UserPathz[ptFlags] + '/hedgewars', ifNone); - if flagsurf = nil then - flagsurf:= LoadImage(Pathz[ptFlags] + '/hedgewars', ifNone); + flagsurf:= LoadDataImageAltFile(ptFlags, Flag, 'hedgewars', ifNone); TryDo(flagsurf <> nil, 'Failed to load flag "' + Flag + '" as well as the default flag', true); case maxLevel of @@ -247,9 +251,7 @@ end end; end; - MissionIcons:= LoadImage(UserPathz[ptGraphics] + '/missions', ifNone); - if MissionIcons = nil then - MissionIcons:= LoadImage(Pathz[ptGraphics] + '/missions', ifCritical); + MissionIcons:= LoadDataImage(ptGraphics, 'missions', ifCritical); iconsurf:= SDL_CreateRGBSurface(SDL_SWSURFACE, 28, 28, 32, RMask, GMask, BMask, AMask); if iconsurf <> nil then begin @@ -287,13 +289,7 @@ begin if GraveName = '' then GraveName:= 'Statue'; - texsurf:= LoadImage(UserPathz[ptGraves] + '/' + GraveName, ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptGraves] + '/' + GraveName, ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(UserPathz[ptGraves] + '/Statue', ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptGraves] + '/Statue', ifCritical or ifTransparent); + texsurf:= LoadDataImageAltFile(ptGraves, GraveName, 'Statue', ifCritical or ifTransparent); GraveTex:= Surface2Tex(texsurf, false); SDL_FreeSurface(texsurf) end @@ -305,7 +301,7 @@ fi: THWFont; ai: TAmmoType; tmpsurf: PSDL_Surface; - i: LongInt; + i, imflags: LongInt; begin AddFileLog('StoreLoad()'); @@ -338,43 +334,18 @@ ((cCloudsNumber > 0) or (ii <> sprCloud)) and ((vobCount > 0) or (ii <> sprFlake)) then begin - if AltPath = ptNone then - if ii in [sprHorizont, sprHorizontL, sprHorizontR, sprSky, sprSkyL, sprSkyR, sprChunk] then // FIXME: hack - begin - if not reload then - begin - tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent) - end - else - tmpsurf:= Surface - end - else - begin - if not reload then - begin - tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent or ifCritical) - end - else - tmpsurf:= Surface - end + if reload then + tmpsurf:= Surface else begin - if not reload then - begin - tmpsurf:= LoadImage(UserPathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[Path] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(UserPathz[AltPath] + '/' + FileName, ifAlpha or ifTransparent); - if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[AltPath] + '/' + FileName, ifAlpha or ifCritical or ifTransparent) - end - else - tmpsurf:= Surface + imflags := (ifAlpha or ifTransparent); + + // these sprites are optional + if not (ii in [sprHorizont, sprHorizontL, sprHorizontR, sprSky, sprSkyL, sprSkyR, sprChunk]) then // FIXME: hack + imflags := (imflags or ifCritical); + + // load the image + tmpsurf := LoadDataImageAltPath(Path, AltPath, FileName, imflags) end; if tmpsurf <> nil then @@ -424,10 +395,8 @@ if not reload then AddProgress; - tmpsurf:= LoadImage(UserPathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifTransparent); -if tmpsurf = nil then - tmpsurf:= LoadImage(Pathz[ptGraphics] + '/' + cHHFileName, ifAlpha or ifCritical or ifTransparent); - +tmpsurf:= LoadDataImage(ptGraphics, cHHFileName, ifAlpha or ifCritical or ifTransparent); + HHTexture:= Surface2Tex(tmpsurf, false); SDL_FreeSurface(tmpsurf); @@ -468,6 +437,31 @@ IMG_Quit(); end; +{$IF NOT DEFINED(S3D_DISABLED) OR DEFINED(USE_VIDEO_RECORDING)} +procedure CreateFramebuffer(var frame, depth, tex: GLuint); +begin + glGenFramebuffersEXT(1, @frame); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame); + glGenRenderbuffersEXT(1, @depth); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth); + glGenTextures(1, @tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex, 0); +end; + +procedure DeleteFramebuffer(var frame, depth, tex: GLuint); +begin + glDeleteTextures(1, @tex); + glDeleteRenderbuffersEXT(1, @depth); + glDeleteFramebuffersEXT(1, @frame); +end; +{$ENDIF} + procedure StoreRelease(reload: boolean); var ii: TSprite; ai: TAmmoType; @@ -541,15 +535,15 @@ end; end; end; +{$IFDEF USE_VIDEO_RECORDING} + if defaultFrame <> 0 then + DeleteFramebuffer(defaultFrame, depthv, texv); +{$ENDIF} {$IFNDEF S3D_DISABLED} if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then begin - glDeleteTextures(1, @texl); - glDeleteRenderbuffersEXT(1, @depthl); - glDeleteFramebuffersEXT(1, @framel); - glDeleteTextures(1, @texr); - glDeleteRenderbuffersEXT(1, @depthr); - glDeleteFramebuffersEXT(1, @framer) + DeleteFramebuffer(framel, depthl, texl); + DeleteFramebuffer(framer, depthr, texr); end {$ENDIF} end; @@ -598,12 +592,59 @@ LoadImage:= tmpsurf //Result end; + +function LoadDataImage(const path: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +var tmpsurf: PSDL_Surface; +begin + // check for file in user dir (never critical) + tmpsurf:= LoadImage(UserPathz[path] + '/' + filename, imageFlags and (not ifCritical)); + + // if unsuccessful check data dir + if (tmpsurf = nil) then + tmpsurf:= LoadImage(Pathz[path] + '/' + filename, imageFlags); + + LoadDataImage:= tmpsurf; +end; + + +function LoadDataImageAltPath(const path, altPath: TPathType; const filename: shortstring; imageFlags: LongInt): PSDL_Surface; +var tmpsurf: PSDL_Surface; +begin + // if there is no alternative path, just forward and return result + if (altPath = ptNone) then + exit(LoadDataImage(path, filename, imageFlags)); + + // since we have a fallback path this search isn't critical yet + tmpsurf:= LoadDataImage(path, filename, imageFlags and (not ifCritical)); + + // if image still not found try alternative path + if (tmpsurf = nil) then + tmpsurf:= LoadDataImage(altPath, filename, imageFlags); + + LoadDataImageAltPath:= tmpsurf; +end; + +function LoadDataImageAltFile(const path: TPathType; const filename, altFile: shortstring; imageFlags: LongInt): PSDL_Surface; +var tmpsurf: PSDL_Surface; +begin + // if there is no alternative filename, just forward and return result + if (altFile = '') then + exit(LoadDataImage(path, filename, imageFlags)); + + // since we have a fallback filename this search isn't critical yet + tmpsurf:= LoadDataImage(path, filename, imageFlags and (not ifCritical)); + + // if image still not found try alternative filename + if (tmpsurf = nil) then + tmpsurf:= LoadDataImage(path, altFile, imageFlags); + + LoadDataImageAltFile:= tmpsurf; +end; + procedure LoadHedgehogHat(HHGear: PGear; newHat: shortstring); var texsurf: PSDL_Surface; begin -texsurf:= LoadImage(UserPathz[ptHats] + '/' + newHat, ifNone); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptHats] + '/' + newHat, ifNone); + texsurf:= LoadDataImage(ptHats, newHat, ifNone); // only do something if the hat could be loaded if texsurf <> nil then @@ -658,6 +699,12 @@ procedure SetupOpenGL; //var vendor: shortstring = ''; var buf: array[byte] of char; +{$IFDEF USE_VIDEO_RECORDING} + AuxBufNum: LongInt; +{$ENDIF} + tmpstr: AnsiString; + tmpint: LongInt; + tmpn: LongInt; begin buf[0]:= char(0); // avoid compiler hint AddFileLog('Setting up OpenGL (using driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf))) + ')'); @@ -709,8 +756,59 @@ AddFileLog(' |----- Vendor: ' + shortstring(pchar(glGetString(GL_VENDOR)))); AddFileLog(' |----- Version: ' + shortstring(pchar(glGetString(GL_VERSION)))); AddFileLog(' |----- Texture Size: ' + inttostr(MaxTextureSize)); - AddFileLog(' \----- Extensions: ' + shortstring(pchar(glGetString(GL_EXTENSIONS)))); - //TODO: don't have the Extensions line trimmed but slipt it into multiple lines +{$IFDEF USE_VIDEO_RECORDING} + glGetIntegerv(GL_AUX_BUFFERS, @AuxBufNum); + AddFileLog(' |----- Number of auxiliary buffers: ' + inttostr(AuxBufNum)); +{$ENDIF} + AddFileLog(' \----- Extensions: '); +{$IFNDEF PAS2C} + // fetch extentions and store them in string + tmpstr := StrPas(PChar(glGetString(GL_EXTENSIONS))); + tmpn := WordCount(tmpstr, [' ']); + tmpint := 1; + + repeat + begin + // print up to 3 extentions per row + // ExtractWord will return empty string if index out of range + AddFileLog(TrimRight( + ExtractWord(tmpint, tmpstr, [' ']) + ' ' + + ExtractWord(tmpint+1, tmpstr, [' ']) + ' ' + + ExtractWord(tmpint+2, tmpstr, [' ']) + )); + tmpint := tmpint + 3; + end; + until (tmpint > tmpn); +{$ELSE} + // doesn't seem to print >256 chars + AddFileLogRaw(PChar(glGetString(GL_EXTENSIONS))); +{$ENDIF} + AddFileLog(''); + + defaultFrame:= 0; +{$IFDEF USE_VIDEO_RECORDING} + if GameType = gmtRecord then + begin + if glLoadExtension('GL_EXT_framebuffer_object') then + begin + CreateFramebuffer(defaultFrame, depthv, texv); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame); + AddFileLog('Using framebuffer for video recording.'); + end + else if AuxBufNum > 0 then + begin + glDrawBuffer(GL_AUX0); + glReadBuffer(GL_AUX0); + AddFileLog('Using auxiliary buffer for video recording.'); + end + else + begin + glDrawBuffer(GL_BACK); + glReadBuffer(GL_BACK); + AddFileLog('Warning: off-screen rendering is not supported; using back buffer but it may not work.'); + end; + end; +{$ENDIF} {$IFNDEF S3D_DISABLED} if (cStereoMode = smHorizontal) or (cStereoMode = smVertical) or (cStereoMode = smAFR) then @@ -718,36 +816,11 @@ // prepare left and right frame buffers and associated textures if glLoadExtension('GL_EXT_framebuffer_object') then begin - // left - glGenFramebuffersEXT(1, @framel); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framel); - glGenRenderbuffersEXT(1, @depthl); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthl); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthl); - glGenTextures(1, @texl); - glBindTexture(GL_TEXTURE_2D, texl); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texl, 0); - - // right - glGenFramebuffersEXT(1, @framer); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framer); - glGenRenderbuffersEXT(1, @depthr); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthr); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, cScreenWidth, cScreenHeight); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthr); - glGenTextures(1, @texr); - glBindTexture(GL_TEXTURE_2D, texr); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cScreenWidth, cScreenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texr, 0); + CreateFramebuffer(framel, depthl, texl); + CreateFramebuffer(framer, depthr, texr); // reset - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame) end else cStereoMode:= smNone; @@ -803,9 +876,7 @@ if Step = 0 then begin WriteToConsole(msgLoading + 'progress sprite: '); - texsurf:= LoadImage(UserPathz[ptGraphics] + '/Progress', ifTransparent); - if texsurf = nil then - texsurf:= LoadImage(Pathz[ptGraphics] + '/Progress', ifCritical or ifTransparent); + texsurf:= LoadDataImage(ptGraphics, 'Progress', ifCritical or ifTransparent); ProgrTex:= Surface2Tex(texsurf, false); @@ -1021,6 +1092,34 @@ WeaponTooltipTex:= nil end; +{$IFDEF USE_VIDEO_RECORDING} +{$IFDEF SDL13} +procedure InitOffscreenOpenGL; +begin + // create hidden window + SDLwindow:= SDL_CreateWindow('hedgewars (you don''t see this)', + SDL_WINDOWPOS_CENTERED_MASK, SDL_WINDOWPOS_CENTERED_MASK, + cScreenWidth, cScreenHeight, + SDL_WINDOW_HIDDEN or SDL_WINDOW_OPENGL); + SDLTry(SDLwindow <> nil, true); + SetupOpenGL(); +end; +{$ELSE} +procedure InitOffscreenOpenGL; +var ArgCount: LongInt; + PrgName: pchar; +begin + ArgCount:= 1; + PrgName:= 'hwengine'; + glutInit(@ArgCount, @PrgName); + glutInitWindowSize(cScreenWidth, cScreenHeight); + glutCreateWindow('hedgewars (you don''t see this)'); // we don't need a window, but if this function is not called then OpenGL will not be initialized + glutHideWindow(); + SetupOpenGL(); +end; +{$ENDIF} // SDL13 +{$ENDIF} // USE_VIDEO_RECORDING + procedure chFullScr(var s: shortstring); var flags: Longword = 0; reinit: boolean = false; @@ -1046,9 +1145,7 @@ WriteLnToConsole(msgOK); // load engine icon {$IFNDEF DARWIN} - ico:= LoadImage(UserPathz[ptGraphics] + '/hwengine', ifIgnoreCaps); - if ico = nil then - ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps); + ico:= LoadDataImage(ptGraphics, 'hwengine', ifIgnoreCaps); if ico <> nil then begin SDL_WM_SetIcon(ico, 0); @@ -1201,6 +1298,8 @@ procedure SwapBuffers; inline; begin + if GameType = gmtRecord then + exit; {$IFDEF SDL13} SDL_GL_SwapWindow(SDLwindow); {$ELSE} diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uTeams.pas --- a/hedgewars/uTeams.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uTeams.pas Sun Sep 16 16:54:51 2012 +0200 @@ -64,6 +64,11 @@ TurnTimeLeft:= 0; ReadyTimeLeft:= 0; + +// if the game ends during a multishot, do last TurnReaction +if (not bBetweenTurns) and isInMultiShoot then + TurnReaction(); + if not GameOver then begin if AliveCount = 0 then @@ -531,7 +536,7 @@ AddTeam(Color); CurrentTeam^.TeamName:= ts; CurrentTeam^.PlayerHash:= s; - if GameType in [gmtDemo, gmtSave] then + if GameType in [gmtDemo, gmtSave, gmtRecord] then CurrentTeam^.ExtDriven:= true; CurrentTeam^.voicepack:= AskForVoicepack('Default') diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uTypes.pas --- a/hedgewars/uTypes.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uTypes.pas Sun Sep 16 16:54:51 2012 +0200 @@ -39,7 +39,7 @@ TGameState = (gsLandGen, gsStart, gsGame, gsChat, gsConfirm, gsExit, gsSuspend); // Game types that help determining what the engine is actually supposed to do - TGameType = (gmtLocal, gmtDemo, gmtNet, gmtSave, gmtLandPreview, gmtSyntax); + TGameType = (gmtLocal, gmtDemo, gmtNet, gmtSave, gmtLandPreview, gmtSyntax, gmtRecord); // Different files are stored in different folders, this enumeration is used to tell which folder to use TPathType = (ptNone, ptData, ptGraphics, ptThemes, ptCurrTheme, ptTeams, ptMaps, @@ -235,7 +235,6 @@ Kind: TGearType; Pos: Longword; doStep: TGearStepProcedure; - stepFreq: Longword; Radius: LongInt; Angle, Power : Longword; DirAngle: real; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uUtils.pas --- a/hedgewars/uUtils.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uUtils.pas Sun Sep 16 16:54:51 2012 +0200 @@ -61,6 +61,7 @@ function CheckCJKFont(s: ansistring; font: THWFont): THWFont; procedure AddFileLog(s: shortstring); +procedure AddFileLogRaw(s: pchar); cdecl; function CheckNoTeamOrHH: boolean; inline; @@ -81,6 +82,9 @@ {$IFDEF DEBUGFILE} var f: textfile; +{$IFDEF USE_VIDEO_RECORDING} + logMutex: TRTLCriticalSection; // mutex for debug file +{$ENDIF} {$ENDIF} var CharArray: array[byte] of Char; @@ -291,11 +295,31 @@ begin s:= s; {$IFDEF DEBUGFILE} +{$IFDEF USE_VIDEO_RECORDING} +EnterCriticalSection(logMutex); +{$ENDIF} writeln(f, inttostr(GameTicks) + ': ' + s); -flush(f) +flush(f); +{$IFDEF USE_VIDEO_RECORDING} +LeaveCriticalSection(logMutex); +{$ENDIF} {$ENDIF} end; +procedure AddFileLogRaw(s: pchar); cdecl; +begin +s:= s; +{$IFDEF DEBUGFILE} +{$IFDEF USE_VIDEO_RECORDING} +EnterCriticalSection(logMutex); +{$ENDIF} +write(f, s); +flush(f); +{$IFDEF USE_VIDEO_RECORDING} +LeaveCriticalSection(logMutex); +{$ENDIF} +{$ENDIF} +end; function CheckCJKFont(s: ansistring; font: THWFont): THWFont; var l, i : LongInt; @@ -385,9 +409,17 @@ begin {$IFDEF DEBUGFILE} if isGame then - logfileBase:= 'game' + begin + if GameType = gmtRecord then + logfileBase:= 'rec' + else + logfileBase:= 'game'; + end else logfileBase:= 'preview'; +{$IFDEF USE_VIDEO_RECORDING} + InitCriticalSection(logMutex); +{$ENDIF} {$I-} {$IFDEF MOBILE} {$IFDEF IPHONEOS} Assign(f,'../Documents/hw-' + logfileBase + '.log'); {$ENDIF} @@ -424,6 +456,9 @@ writeln(f, 'halt at ' + inttostr(GameTicks) + ' ticks. TurnTimeLeft = ' + inttostr(TurnTimeLeft)); flush(f); close(f); +{$IFDEF USE_VIDEO_RECORDING} + DoneCriticalSection(logMutex); +{$ENDIF} {$ENDIF} end; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uVariables.pas Sun Sep 16 16:54:51 2012 +0200 @@ -52,6 +52,15 @@ cReadyDelay : Longword = 5000; cStereoMode : TStereoMode = smNone; cOnlyStats : boolean = False; +{$IFDEF USE_VIDEO_RECORDING} + RecPrefix : shortstring; + cAVFormat : shortstring; + cVideoCodec : shortstring; + cVideoFramerateNum : LongInt; + cVideoFramerateDen : LongInt; + cVideoQuality : LongInt; + cAudioCodec : shortstring; +{$ENDIF} ////////////////////////// cMapName : shortstring = ''; @@ -63,9 +72,11 @@ SpeedStart : LongWord; fastUntilLag : boolean; + fastScrolling : boolean; autoCameraOn : boolean; CheckSum : LongWord; + CampaignVariable: shortstring; GameTicks : LongWord; GameState : TGameState; GameType : TGameType; @@ -182,6 +193,8 @@ hiTicks: Word; LuaGoals : shortstring; + hiddenHedgehogs : array [0..cMaxHHs] of PHedgehog; + hiddenHedgehogsNumber : longint; LuaTemplateNumber : LongWord; @@ -214,7 +227,7 @@ '', // ptData 'Graphics', // ptGraphics 'Themes', // ptThemes - 'Themes/avematan', // ptCurrTheme + 'Themes/Bamboo', // ptCurrTheme 'Teams', // ptTeams 'Maps', // ptMaps '', // ptMapCurrent @@ -2315,7 +2328,7 @@ GearKindAmmoTypeMap : array [TGearType] of TAmmoType = ( (* gtFlame *) amNothing (* gtHedgehog *) , amNothing -(* gtMine *) , amNothing +(* gtMine *) , amMine (* gtCase *) , amNothing (* gtExplosives *) , amNothing (* gtGrenade *) , amGrenade @@ -2449,6 +2462,10 @@ framel, framer, depthl, depthr: GLuint; texl, texr: GLuint; + // video recorder framebuffer and texture + defaultFrame, depthv: GLuint; + texv: GLuint; + VisualGearLayers: array[0..6] of PVisualGear; lastVisualGearByUID: PVisualGear; vobFrameTicks, vobFramesCount, vobCount: Longword; @@ -2574,7 +2591,7 @@ cExplosives := 2; GameState := Low(TGameState); - GameType := gmtLocal; +// GameType := gmtLocal; zoom := cDefaultZoomLevel; ZoomValue := cDefaultZoomLevel; WeaponTooltipTex:= nil; @@ -2591,6 +2608,7 @@ isSpeed := false; SpeedStart := 0; fastUntilLag := false; + fastScrolling := false; autoCameraOn := true; cScriptName := ''; cSeed := ''; @@ -2627,6 +2645,7 @@ LuaGoals:= ''; LuaTemplateNumber:= 0; + hiddenHedgehogsNumber:=0; end; procedure freeModule; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uVideoRec.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uVideoRec.pas Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,369 @@ +(* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + *) + + +{$INCLUDE "options.inc"} + +unit uVideoRec; + +{$IFNDEF USE_VIDEO_RECORDING} +interface +implementation +end. +{$ELSE} + +{$IFNDEF WIN32} + {$LINKLIB ../bin/libavwrapper.a} +{$ENDIF} + +interface + +var flagPrerecording: boolean = false; + +function BeginVideoRecording: Boolean; +function LoadNextCameraPosition(out newRealTicks, newGameTicks: LongInt): Boolean; +procedure EncodeFrame; +procedure StopVideoRecording; + +procedure BeginPreRecording; +procedure StopPreRecording; +procedure SaveCameraPosition; + +procedure freeModule; + +implementation + +uses uVariables, uUtils, GLunit, SDLh, SysUtils, uIO, uMisc, uTypes; + +type TAddFileLogRaw = procedure (s: pchar); cdecl; + +procedure AVWrapper_Init( + AddLog: TAddFileLogRaw; + filename, desc, soundFile, format, vcodec, acodec: PChar; + width, height, framerateNum, framerateDen, vquality: LongInt); cdecl; external {$IFDEF WIN32}'libavwrapper.dll'{$ENDIF}; +procedure AVWrapper_Close; cdecl; external {$IFDEF WIN32}'libavwrapper.dll'{$ENDIF}; +procedure AVWrapper_WriteFrame( pY, pCb, pCr: PByte ); cdecl; external {$IFDEF WIN32}'libavwrapper.dll'{$ENDIF}; + +type TFrame = record + realTicks: LongWord; + gameTicks: LongWord; + CamX, CamY: LongInt; + zoom: single; + end; + +var YCbCr_Planes: array[0..2] of PByte; + RGB_Buffer: PByte; + cameraFile: File of TFrame; + audioFile: File; + numPixels: LongWord; + startTime, numFrames, curTime, progress, maxProgress: LongWord; + soundFilePath: shortstring; + thumbnailSaved : Boolean; + +function BeginVideoRecording: Boolean; +var filename, desc: shortstring; +begin + AddFileLog('BeginVideoRecording'); + +{$IOCHECKS OFF} + // open file with prerecorded camera positions + filename:= UserPathPrefix + '/VideoTemp/' + RecPrefix + '.txtin'; + Assign(cameraFile, filename); + Reset(cameraFile); + maxProgress:= FileSize(cameraFile); + if IOResult <> 0 then + begin + AddFileLog('Error: Could not read from ' + filename); + exit(false); + end; +{$IOCHECKS ON} + + // store some description in output file + desc:= ''; + if UserNick <> '' then + desc+= 'Player: ' + UserNick + #10; + if recordFileName <> '' then + desc+= 'Record: ' + recordFileName + #10; + if cMapName <> '' then + desc+= 'Map: ' + cMapName + #10; + if Theme <> '' then + desc+= 'Theme: ' + Theme + #10; + desc+= 'prefix[' + RecPrefix + ']prefix'; + desc+= #0; + + filename:= UserPathPrefix + '/VideoTemp/' + RecPrefix + #0; + soundFilePath:= UserPathPrefix + '/VideoTemp/' + RecPrefix + '.sw' + #0; + cAVFormat+= #0; + cAudioCodec+= #0; + cVideoCodec+= #0; + AVWrapper_Init(@AddFileLogRaw, @filename[1], @desc[1], @soundFilePath[1], @cAVFormat[1], @cVideoCodec[1], @cAudioCodec[1], + cScreenWidth, cScreenHeight, cVideoFramerateNum, cVideoFramerateDen, cVideoQuality); + + numPixels:= cScreenWidth*cScreenHeight; + YCbCr_Planes[0]:= GetMem(numPixels); + YCbCr_Planes[1]:= GetMem(numPixels div 4); + YCbCr_Planes[2]:= GetMem(numPixels div 4); + + if (YCbCr_Planes[0] = nil) or (YCbCr_Planes[1] = nil) or (YCbCr_Planes[2] = nil) then + begin + AddFileLog('Error: Could not allocate memory for video recording (YCbCr buffer).'); + exit(false); + end; + + RGB_Buffer:= GetMem(4*numPixels); + if RGB_Buffer = nil then + begin + AddFileLog('Error: Could not allocate memory for video recording (RGB buffer).'); + exit(false); + end; + + curTime:= 0; + numFrames:= 0; + progress:= 0; + BeginVideoRecording:= true; +end; + +procedure StopVideoRecording; +begin + AddFileLog('StopVideoRecording'); + FreeMem(YCbCr_Planes[0], numPixels); + FreeMem(YCbCr_Planes[1], numPixels div 4); + FreeMem(YCbCr_Planes[2], numPixels div 4); + FreeMem(RGB_Buffer, 4*numPixels); + Close(cameraFile); + AVWrapper_Close(); + Erase(cameraFile); + DeleteFile(soundFilePath); + SendIPC(_S'v'); // inform frontend that we finished +end; + +function pixel(x, y, color: LongInt): LongInt; +begin + pixel:= RGB_Buffer[(cScreenHeight-y-1)*cScreenWidth*4 + x*4 + color]; +end; + +procedure EncodeFrame; +var x, y, r, g, b: LongInt; + s: shortstring; +begin + // read pixels from OpenGL + glReadPixels(0, 0, cScreenWidth, cScreenHeight, GL_RGBA, GL_UNSIGNED_BYTE, RGB_Buffer); + + // convert to YCbCr 4:2:0 format + // Y + for y := 0 to cScreenHeight-1 do + for x := 0 to cScreenWidth-1 do + YCbCr_Planes[0][y*cScreenWidth + x]:= Byte(16 + ((16828*pixel(x,y,0) + 33038*pixel(x,y,1) + 6416*pixel(x,y,2)) shr 16)); + + // Cb and Cr + for y := 0 to cScreenHeight div 2 - 1 do + for x := 0 to cScreenWidth div 2 - 1 do + begin + r:= pixel(2*x,2*y,0) + pixel(2*x+1,2*y,0) + pixel(2*x,2*y+1,0) + pixel(2*x+1,2*y+1,0); + g:= pixel(2*x,2*y,1) + pixel(2*x+1,2*y,1) + pixel(2*x,2*y+1,1) + pixel(2*x+1,2*y+1,1); + b:= pixel(2*x,2*y,2) + pixel(2*x+1,2*y,2) + pixel(2*x,2*y+1,2) + pixel(2*x+1,2*y+1,2); + YCbCr_Planes[1][y*(cScreenWidth div 2) + x]:= Byte(128 + ((-2428*r - 4768*g + 7196*b) shr 16)); + YCbCr_Planes[2][y*(cScreenWidth div 2) + x]:= Byte(128 + (( 7196*r - 6026*g - 1170*b) shr 16)); + end; + + AVWrapper_WriteFrame(YCbCr_Planes[0], YCbCr_Planes[1], YCbCr_Planes[2]); + + // inform frontend that we have encoded new frame + s[0]:= #3; + s[1]:= 'p'; // p for progress + SDLNet_Write16(progress*10000 div maxProgress, @s[2]); + SendIPC(s); + inc(numFrames); +end; + +function LoadNextCameraPosition(out newRealTicks, newGameTicks: LongInt): Boolean; +var frame: TFrame; +begin + // we need to skip or duplicate frames to match target framerate + while Int64(curTime)*cVideoFramerateNum <= Int64(numFrames)*cVideoFramerateDen*1000 do + begin + {$IOCHECKS OFF} + if eof(cameraFile) then + exit(false); + BlockRead(cameraFile, frame, 1); + {$IOCHECKS ON} + curTime:= frame.realTicks; + WorldDx:= frame.CamX; + WorldDy:= frame.CamY + cScreenHeight div 2; + zoom:= frame.zoom*cScreenWidth; + ZoomValue:= zoom; + inc(progress); + newRealTicks:= frame.realTicks; + newGameTicks:= frame.gameTicks; + end; + LoadNextCameraPosition:= true; +end; + +// Callback which records sound. +// This procedure may be called from different thread. +procedure RecordPostMix(udata: pointer; stream: PByte; len: LongInt); cdecl; +begin + udata:= udata; // avoid warning +{$IOCHECKS OFF} + BlockWrite(audioFile, stream^, len); +{$IOCHECKS ON} +end; + +procedure SaveThumbnail; +var thumbpath: shortstring; + k: LongInt; +begin + thumbpath:= '/VideoTemp/' + RecPrefix; + AddFileLog('Saving thumbnail ' + thumbpath); + k:= max(max(cScreenWidth, cScreenHeight) div 400, 1); // here 400 is minimum size of thumbnail + MakeScreenshot(thumbpath, k); + thumbnailSaved:= true; +end; + +// copy file (free pascal doesn't have copy file function) +procedure CopyFile(src, dest: shortstring); +var inF, outF: file; + buffer: array[0..1023] of byte; + result: LongInt; +begin +{$IOCHECKS OFF} + result:= 0; // avoid compiler hint + + Assign(inF, src); + Reset(inF, 1); + if IOResult <> 0 then + begin + AddFileLog('Error: Could not read from ' + src); + exit; + end; + + Assign(outF, dest); + Rewrite(outF, 1); + if IOResult <> 0 then + begin + AddFileLog('Error: Could not write to ' + dest); + exit; + end; + + repeat + BlockRead(inF, buffer, 1024, result); + BlockWrite(outF, buffer, result); + until result < 1024; +{$IOCHECKS ON} +end; + +procedure BeginPreRecording; +var format: word; + filename: shortstring; + frequency, channels: LongInt; +begin + AddFileLog('BeginPreRecording'); + + thumbnailSaved:= false; + RecPrefix:= 'hw-' + FormatDateTime('YYYY-MM-DD_HH-mm-ss-z', Now()); + + // If this video is recorded from demo executed directly (without frontend) + // then we need to copy demo so that frontend will be able to find it later. + if recordFileName <> '' then + begin + if GameType <> gmtDemo then // this is save and game demo is not recording, abort + exit; + CopyFile(recordFileName, UserPathPrefix + '/VideoTemp/' + RecPrefix + '.hwd'); + end; + + Mix_QuerySpec(@frequency, @format, @channels); + AddFileLog('sound: frequency = ' + IntToStr(frequency) + ', format = ' + IntToStr(format) + ', channels = ' + IntToStr(channels)); + if format <> $8010 then + begin + // TODO: support any audio format + AddFileLog('Error: Unexpected audio format ' + IntToStr(format)); + exit; + end; + +{$IOCHECKS OFF} + // create sound file + filename:= UserPathPrefix + '/VideoTemp/' + RecPrefix + '.sw'; + Assign(audioFile, filename); + Rewrite(audioFile, 1); + if IOResult <> 0 then + begin + AddFileLog('Error: Could not write to ' + filename); + exit; + end; + + // create file with camera positions + filename:= UserPathPrefix + '/VideoTemp/' + RecPrefix + '.txtout'; + Assign(cameraFile, filename); + Rewrite(cameraFile); + if IOResult <> 0 then + begin + AddFileLog('Error: Could not write to ' + filename); + exit; + end; + + // save audio parameters in sound file + BlockWrite(audioFile, frequency, 4); + BlockWrite(audioFile, channels, 4); +{$IOCHECKS ON} + + // register callback for actual audio recording + Mix_SetPostMix(@RecordPostMix, nil); + + startTime:= SDL_GetTicks(); + flagPrerecording:= true; +end; + +procedure StopPreRecording; +begin + AddFileLog('StopPreRecording'); + flagPrerecording:= false; + + // call SDL_LockAudio because RecordPostMix may be executing right now + SDL_LockAudio(); + Close(audioFile); + Close(cameraFile); + Mix_SetPostMix(nil, nil); + SDL_UnlockAudio(); + + if not thumbnailSaved then + SaveThumbnail(); +end; + +procedure SaveCameraPosition; +var frame: TFrame; +begin + if (not thumbnailSaved) and (ScreenFade = sfNone) then + SaveThumbnail(); + + frame.realTicks:= SDL_GetTicks() - startTime; + frame.gameTicks:= GameTicks; + frame.CamX:= WorldDx; + frame.CamY:= WorldDy - cScreenHeight div 2; + frame.zoom:= zoom/cScreenWidth; + BlockWrite(cameraFile, frame, 1); +end; + +procedure freeModule; +begin + if flagPrerecording then + StopPreRecording(); +end; + +end. + +{$ENDIF} // USE_VIDEO_RECORDING diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uVisualGears.pas --- a/hedgewars/uVisualGears.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uVisualGears.pas Sun Sep 16 16:54:51 2012 +0200 @@ -135,7 +135,7 @@ sp: real; begin AddVisualGear:= nil; -if ((GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet))) and // we are scrolling now +if ((GameType = gmtSave) or (fastUntilLag and (GameType = gmtNet)) or fastScrolling) and // we are scrolling now ((Kind <> vgtCloud) and (not Critical)) then exit; diff -r ce6ead3327b2 -r c73fd8cfa7c0 hedgewars/uWorld.pas --- a/hedgewars/uWorld.pas Mon Aug 27 17:40:16 2012 +0200 +++ b/hedgewars/uWorld.pas Sun Sep 16 16:54:51 2012 +0200 @@ -60,7 +60,8 @@ uCaptions, uCursor, uCommands, - uMobile + uMobile, + uVideoRec ; var cWaveWidth, cWaveHeight: LongInt; @@ -80,6 +81,7 @@ stereoDepth: GLfloat; isFirstFrame: boolean; AMAnimType: LongInt; + recTexture: PTexture; const cStereo_Sky = 0.0500; cStereo_Horizon = 0.0250; @@ -377,6 +379,8 @@ timeTexture:= nil; FreeTexture(missionTex); missionTex:= nil; + FreeTexture(recTexture); + recTexture:= nil; end; function GetAmmoMenuTexture(Ammo: PHHAmmo): PTexture; @@ -954,7 +958,7 @@ //glPushMatrix; //glScalef(1.0, 1.0, 1.0); - if not isPaused then + if (not isPaused) and (GameType <> gmtRecord) then MoveCamera; if cStereoMode = smNone then @@ -985,7 +989,7 @@ DrawWorldStereo(0, rmRightEye); // detatch drawing from fbs - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, defaultFrame); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); SetScale(cDefaultZoomLevel); @@ -1303,6 +1307,7 @@ else smallScreenOffset:= 0; for t:= 0 to Pred(TeamsCount) do with TeamsArray[t]^ do + if TeamHealth > 0 then begin h:= 0; highlight:= bShowFinger and (CurrentTeam = TeamsArray[t]) and ((RealTicks mod 1000) < 500); @@ -1325,11 +1330,10 @@ // draw health bars right border inc(r.x, cTeamHealthWidth + 2); - if TeamHealth = 0 then inc(r.x); r.w:= 3; DrawTextureFromRect(TeamHealthBarWidth + 16, cScreenHeight + DrawHealthY + smallScreenOffset, @r, HealthTex); - if not highlight and (not hasGone) and (TeamHealth > 1) then + if not highlight and (not hasGone) then for i:= 0 to cMaxHHIndex do if Hedgehogs[i].Gear <> nil then begin @@ -1581,6 +1585,33 @@ end end; +{$IFDEF USE_VIDEO_RECORDING} +// during video prerecording draw red blinking circle and text 'rec' +if flagPrerecording then + begin + if recTexture = nil then + begin + s:= 'rec'; + tmpSurface:= TTF_RenderUTF8_Blended(Fontz[fntBig].Handle, Str2PChar(s), cWhiteColorChannels); + tmpSurface:= doSurfaceConversion(tmpSurface); + FreeTexture(recTexture); + recTexture:= Surface2Tex(tmpSurface, false); + SDL_FreeSurface(tmpSurface) + end; + DrawTexture( -(cScreenWidth shr 1) + 50, 20, recTexture); + + // 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(); + Tint($FF, $FF, $FF, $FF); + glEnable(GL_TEXTURE_2D); + end; +{$ENDIF} + SetScale(zoom); // Cursor @@ -1761,8 +1792,14 @@ if (not cHasFocus) and (GameState <> gsConfirm) then ParseCommand('quit', true); -if not cHasFocus then DampenAudio() -else UndampenAudio(); +{$IFDEF USE_VIDEO_RECORDING} +// do not change volume during prerecording as it will affect sound in video file +if not flagPrerecording then +{$ENDIF} + begin + if not cHasFocus then DampenAudio() + else UndampenAudio(); + end; end; procedure SetUtilityWidgetState(ammoType: TAmmoType); @@ -1819,6 +1856,7 @@ procedure initModule; begin fpsTexture:= nil; + recTexture:= nil; FollowGear:= nil; WindBarWidth:= 0; bShowAmmoMenu:= false; @@ -1850,7 +1888,9 @@ FreeTexture(timeTexture); timeTexture:= nil; FreeTexture(missionTex); - missionTex:= nil + missionTex:= nil; + FreeTexture(recTexture); + recTexture:= nil; end; end. diff -r ce6ead3327b2 -r c73fd8cfa7c0 project_files/hedgewars.pro --- a/project_files/hedgewars.pro Mon Aug 27 17:40:16 2012 +0200 +++ b/project_files/hedgewars.pro Sun Sep 16 16:54:51 2012 +0200 @@ -104,7 +104,13 @@ ../QTfrontend/ui/dialog/input_password.h \ ../QTfrontend/ui/widget/colorwidget.h \ ../QTfrontend/model/HatModel.h \ - ../QTfrontend/model/GameStyleModel.h + ../QTfrontend/model/GameStyleModel.h \ + ../QTfrontend/util/libav_iteraction.h \ + ../QTfrontend/ui/page/pagevideos.h \ + ../QTfrontend/net/recorder.h \ + ../QTfrontend/ui/dialog/ask_quit.h \ + ../QTfrontend/ui/dialog/upload_video.h \ + ../QTfrontend/campaign.h SOURCES += ../QTfrontend/model/ammoSchemeModel.cpp \ ../QTfrontend/model/MapModel.cpp \ @@ -186,7 +192,14 @@ ../QTfrontend/ui/dialog/input_password.cpp \ ../QTfrontend/ui/widget/colorwidget.cpp \ ../QTfrontend/model/HatModel.cpp \ - ../QTfrontend/model/GameStyleModel.cpp + ../QTfrontend/model/GameStyleModel.cpp \ + ../QTfrontend/util/libav_iteraction.cpp \ + ../QTfrontend/ui/page/pagevideos.cpp \ + ../QTfrontend/net/recorder.cpp \ + ../QTfrontend/ui/dialog/ask_quit.cpp \ + ../QTfrontend/ui/dialog/upload_video.cpp \ + ../QTfrontend/campaign.cpp + win32 { SOURCES += ../QTfrontend/xfire.cpp diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Graphics/Graves/dragonball.png Binary file share/hedgewars/Data/Graphics/Graves/dragonball.png has changed diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Graphics/Graves/dragonball.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Graphics/Graves/dragonball.svg Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,606 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_ar.ts --- a/share/hedgewars/Data/Locale/hedgewars_ar.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_ar.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -70,6 +77,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -131,10 +145,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -190,7 +200,7 @@ Password - كلمة السر + كلمة السر Your nickname %1 is @@ -380,6 +390,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + كلمة السر + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -389,6 +425,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -472,6 +528,10 @@ All files + + Eraser + + PageEditTeam @@ -567,14 +627,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - لعبة محلية + لعبة محلية Network Game (Play a game across a network) - لعبة شبكية (عن طريق شبكة اتصال) + لعبة شبكية (عن طريق شبكة اتصال) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -825,6 +892,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -862,6 +969,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -873,6 +988,14 @@ Official server الخادم الرسمي + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -928,6 +1051,18 @@ Delete weapon set + + General + عام + + + Advanced + متقدم + + + Reset to default colors + + PagePlayDemo @@ -993,39 +1128,39 @@ This game is in lobby. You may join and start playing once the game starts. - هذه غرقة اللعب + هذه غرقة اللعب يمكنك الانضمام و بدء اللعب عند الاتضمام الى غرفة You may join and start playing once the game starts. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - اللعبة قيد اللعب + اللعبة قيد اللعب يمكنك الانضمام و المشاهدة %1 is the host. He may adjust settings and start the game. - %1هو المضيف الذي يبدا و يغيير اعدادات اللعبة + %1هو المضيف الذي يبدا و يغيير اعدادات اللعبة Random Map - خارطة عشوائية + خارطة عشوائية Games may be played on precreated or randomized maps. - اللعبة يمكن ان تكون على خارطة عشوائية او يدوية + اللعبة يمكن ان تكون على خارطة عشوائية او يدوية The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - طراز اللعية يحدد الخيارات مثل وقت الجولة، الموت المفاجئ و مصاص الدماء + طراز اللعية يحدد الخيارات مثل وقت الجولة، الموت المفاجئ و مصاص الدماء The Weapon Scheme defines available weapons and their ammunition count. - طراز الاسلحة يحدد المتوفرة منها و عددها + طراز الاسلحة يحدد المتوفرة منها و عددها There are %1 clients connected to this room. - + يوجد %1 مرتبطون بالغرقة @@ -1033,7 +1168,7 @@ There are %1 teams participating in this room. - + يوجد %1 فريق في الغرفة @@ -1049,7 +1184,7 @@ Random Maze - متاهة عشوائية + متاهة عشوائية Rules: @@ -1238,11 +1373,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - لعية بسيطة ضد الحاسوب + لعية بسيطة ضد الحاسوب Multiplayer (play a hotseat game against your friends, or AI teams) - لعبة متعددة + لعبة متعددة Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1250,18 +1385,54 @@ Demos (Watch recorded demos) - عرض + عرض Load (Load a previously saved game) - تحميل - - - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) + تحميل + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + تحميل + + + Load a previously saved game @@ -1275,6 +1446,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + اسم + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1381,6 +1617,26 @@ Frontend effects تأثيرات المقدمة + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1551,6 +1807,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1604,7 +1880,7 @@ Net nick - اسم اللاعب + اسم اللاعب Resolution @@ -1684,7 +1960,7 @@ Restart game to apply - اعد تشغيل اللعبة لتفعيل التغيير + اعد تشغيل اللعبة لتفعيل التغيير Explosives @@ -1736,7 +2012,7 @@ Password - كلمة السر + كلمة السر % Get Away Time @@ -1746,6 +2022,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + اسم اللاعب + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1757,6 +2095,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1839,6 +2181,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1937,36 +2317,107 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - اسم الغرقة + اسم الغرقة C - C + C T - T + T Owner - المالك + المالك Map - خارطة + خارطة Rules - قوانين + قوانين Weapons - اسلحة + اسلحة + + + + RoomsListModel + + In progress + + + + Room Name + اسم الغرقة + + + C + C + + + T + T + + + Owner + المالك + + + Map + خارطة + + + Rules + قوانين + + + Weapons + اسلحة + + + Random Map + خارطة عشوائية + + + Random Maze + متاهة عشوائية + + + Hand-drawn + @@ -2282,6 +2733,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2368,6 +2827,10 @@ Toggle labels above hedgehogs: تغيير العناوبن فوق اللاعبين + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_bg.ts --- a/share/hedgewars/Data/Locale/hedgewars_bg.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_bg.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -130,10 +144,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -189,7 +199,7 @@ Password - Парола + Парола Your nickname %1 is @@ -382,6 +392,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Парола + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -391,6 +427,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Clear Accounts Cache @@ -470,6 +526,10 @@ All files + + Eraser + + PageEditTeam @@ -555,14 +615,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Локална игра (играйте на един компютър) + Локална игра (играйте на един компютър) Network Game (Play a game across a network) - Мрежова игра (играйте в мрежа) + Мрежова игра (играйте в мрежа) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -813,6 +880,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -850,6 +957,14 @@ OK + + DLC + + + + Downloadable Content + + PageNetType @@ -861,6 +976,14 @@ Official server Официален сървър + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -904,6 +1027,18 @@ Delete weapon set Изтриване на комплекта оръжия + + General + Общи + + + Advanced + За напреднали + + + Reset to default colors + + PagePlayDemo @@ -969,48 +1104,34 @@ This game is in lobby. You may join and start playing once the game starts. - Тази игра е в лоби. + Тази игра е в лоби. След като започне, може да се присъедините и да играете. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Играта тече в момента. + Играта тече в момента. Можете да се присъедините и да гледате, но ще трябва да изчакате да свърши, за да започнете да играете. %1 is the host. He may adjust settings and start the game. - %1 е домакина. Той може да променя настройките и да започне играта. + %1 е домакина. Той може да променя настройките и да започне играта. Random Map - Случайна карта + Случайна карта Games may be played on precreated or randomized maps. - Игрите могат да се играят на предварително създадени или случайно генерирани карти. + Игрите могат да се играят на предварително създадени или случайно генерирани карти. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Игровата схема определя общите настройки и предпочитания, като продължителност на рунда, внезапна смърт или вампиризъм. + Игровата схема определя общите настройки и предпочитания, като продължителност на рунда, внезапна смърт или вампиризъм. The Weapon Scheme defines available weapons and their ammunition count. - Схемата на оръжията определя наличните оръжия и количеството боеприпаси за тях. - - - There are %1 clients connected to this room. - - - - - - - There are %1 teams participating in this room. - - - - + Схемата на оръжията определя наличните оръжия и количеството боеприпаси за тях. Please enter room name @@ -1022,7 +1143,7 @@ Random Maze - Случан лабиринт + Случан лабиринт State: @@ -1208,11 +1329,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Солова игра (бърза игра срещу компютър с готови настройки) + Солова игра (бърза игра срещу компютър с готови настройки) Multiplayer (play a hotseat game against your friends, or AI teams) - Мрежова игра (играйте срещу приятели или ИИ отбори) + Мрежова игра (играйте срещу приятели или ИИ отбори) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1220,22 +1341,58 @@ Demos (Watch recorded demos) - Демо (гледайте записани демота) + Демо (гледайте записани демота) Load (Load a previously saved game) - Зареди (заредете предишно запаметена игра) + Зареди (заредете предишно запаметена игра) Campaign Mode (...). IN DEVELOPMENT Режим кампания (...). В ПРОЦЕС НА РАЗРАБОТКА - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Зареждане + + + Load a previously saved game @@ -1249,6 +1406,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Име + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1351,6 +1573,26 @@ Frontend effects Ефекти + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1521,6 +1763,26 @@ Schemes and Weapons Схеми и оръжия + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1562,7 +1824,7 @@ Net nick - Прякор + Прякор This program is distributed under the GNU General Public License @@ -1654,7 +1916,7 @@ Restart game to apply - Рестартирайте играта за да влезе в сила + Рестартирайте играта за да влезе в сила Explosives @@ -1710,7 +1972,7 @@ Password - Парола + Парола % Get Away Time @@ -1720,6 +1982,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Прякор + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1731,6 +2055,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1813,6 +2141,44 @@ Can not delete default weapon set '%1'! Не моге да се изтрие стандартния комплект с оръжия '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1911,36 +2277,107 @@ more повече + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Име на стаята + Име на стаята C - C + C T - T + T Owner - Притежател + Притежател Map - Карта + Карта Rules - Правила + Правила Weapons - Оръжия + Оръжия + + + + RoomsListModel + + In progress + В прогрес + + + Room Name + Име на стаята + + + C + C + + + T + T + + + Owner + Притежател + + + Map + Карта + + + Rules + Правила + + + Weapons + Оръжия + + + Random Map + Случайна карта + + + Random Maze + Случан лабиринт + + + Hand-drawn + @@ -2252,6 +2689,14 @@ slot 10 Слот 10 + + mute audio + + + + record + + binds (categories) @@ -2338,6 +2783,10 @@ Toggle labels above hedgehogs: Премключване на надписи над таралежите: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_cs.ts --- a/share/hedgewars/Data/Locale/hedgewars_cs.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_cs.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -70,6 +77,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -131,10 +145,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -190,7 +200,7 @@ Password - Heslo + Heslo Your nickname %1 is @@ -383,6 +393,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Heslo + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -392,6 +428,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Clear Accounts Cache @@ -471,6 +527,10 @@ All files + + Eraser + + PageEditTeam @@ -562,14 +622,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Místní hra (Hra na tomto počítači) + Místní hra (Hra na tomto počítači) Network Game (Play a game across a network) - Síťová hra (Hra přes síť) + Síťová hra (Hra přes síť) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -825,6 +892,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -862,6 +969,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -873,6 +988,14 @@ Official server Oficiální server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -916,6 +1039,18 @@ Delete weapon set Smazat sadu zbraní + + General + Obecné + + + Advanced + Rozšířené + + + Reset to default colors + + PagePlayDemo @@ -981,38 +1116,38 @@ This game is in lobby. You may join and start playing once the game starts. - Tato hra je v čekárně. + Tato hra je v čekárně. Můžeš se přidat a začít hrát, jakmile hra začne. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Tato hra právě probíhá. + Tato hra právě probíhá. Můžeš se přidat a pozorovat, ale musíš počkat, než hra skončí, jestli chceš začít hrát. %1 is the host. He may adjust settings and start the game. - %1 je hostitel. On může nastavovat a odstartovat hru. + %1 je hostitel. On může nastavovat a odstartovat hru. Random Map - Náhodná mapa + Náhodná mapa Games may be played on precreated or randomized maps. - Hra může být hrána na předem vytvořené nebo na náhodné mapě. + Hra může být hrána na předem vytvořené nebo na náhodné mapě. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Herní schéma definuje obecné možnosti a nastavení jako třeba počet kol, náhlou smrt nebo vampyrismus. + Herní schéma definuje obecné možnosti a nastavení jako třeba počet kol, náhlou smrt nebo vampyrismus. The Weapon Scheme defines available weapons and their ammunition count. - Zbraňové schéma definuje zbraně, které budou k dispozici a jejich munici. + Zbraňové schéma definuje zbraně, které budou k dispozici a jejich munici. There are %1 clients connected to this room. - + V místnosti je %1 připojený klient. V místnosti jsou %1 připojení klienti. V místnosti je %1 připojených klientů. @@ -1020,7 +1155,7 @@ There are %1 teams participating in this room. - + V místnosti je %1 účastnící se tým. V místnosti jsou %1 účastnící se týmy. V místnosti je %1 účastnících se týmů. @@ -1036,7 +1171,7 @@ Random Maze - Náhodný labyrint + Náhodný labyrint State: @@ -1227,11 +1362,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Prostá hra (rychlá hra proti počítači, nastavení je zvoleno) + Prostá hra (rychlá hra proti počítači, nastavení je zvoleno) Multiplayer (play a hotseat game against your friends, or AI teams) - Hra více hráčů (hrát na jednom počítači proti přátelům nebo počítači) + Hra více hráčů (hrát na jednom počítači proti přátelům nebo počítači) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1239,22 +1374,58 @@ Demos (Watch recorded demos) - Ukázky (Sledování nahraných her) + Ukázky (Sledování nahraných her) Load (Load a previously saved game) - Nahrát (Nahrát uloženou hru) + Nahrát (Nahrát uloženou hru) Campaign Mode (...). IN DEVELOPMENT Mód tažení (...). VE VÝVOJI - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Nahrát + + + Load a previously saved game @@ -1268,6 +1439,73 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Jméno + + + Size + + + + %1 bytes + + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1370,6 +1608,26 @@ Frontend effects Efekty v menu + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1540,6 +1798,26 @@ Schemes and Weapons Schémata a zbraně + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1585,7 +1863,7 @@ Net nick - Síťová přezdívka + Síťová přezdívka Resolution @@ -1673,7 +1951,7 @@ Restart game to apply - Aby se nastavení použilo, restartuj hru + Aby se nastavení použilo, restartuj hru Explosives @@ -1729,7 +2007,7 @@ Password - Heslo + Heslo % Get Away Time @@ -1739,6 +2017,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Přezdívka + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1750,6 +2090,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1832,6 +2176,44 @@ Can not delete default weapon set '%1'! Nemohu smazat výchozí sadu zbraní '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1930,36 +2312,107 @@ more více + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Jméno místnosti + Jméno místnosti C - K + K T - T + T Owner - Vlastník + Vlastník Map - Mapa + Mapa Rules - Pravidla + Pravidla Weapons - Zbraně + Zbraně + + + + RoomsListModel + + In progress + Probíhá + + + Room Name + Jméno místnosti + + + C + K + + + T + T + + + Owner + Vlastník + + + Map + Mapa + + + Rules + Pravidla + + + Weapons + Zbraně + + + Random Map + Náhodná mapa + + + Random Maze + Náhodný labyrint + + + Hand-drawn + @@ -2270,6 +2723,14 @@ slot 10 pozice 10 + + mute audio + + + + record + + binds (categories) @@ -2356,6 +2817,10 @@ Toggle labels above hedgehogs: Přepni popisky nad ježky: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_de.ts --- a/share/hedgewars/Data/Locale/hedgewars_de.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_de.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -132,7 +146,7 @@ Kicking %1 ... - %1 wird rausgeworfen ... + %1 wird rausgeworfen ... @@ -189,7 +203,7 @@ Password - Passwort + Passwort Your nickname %1 is @@ -413,6 +427,32 @@ User quit Benutzer ist gegangen + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Passwort + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -422,6 +462,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -505,6 +565,10 @@ All files Alle Dateien + + Eraser + + PageEditTeam @@ -608,14 +672,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Lokales Spiel + Lokales Spiel Network Game (Play a game across a network) - Netzwerkspiel + Netzwerkspiel Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -891,6 +962,46 @@ Downloadable Content Herunterladbare Inhalte + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -928,6 +1039,14 @@ OK OK + + DLC + + + + Downloadable Content + Herunterladbare Inhalte + PageNetType @@ -939,6 +1058,14 @@ Official server Offizieller Server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -994,6 +1121,18 @@ Delete weapon set Waffenprofil löschen + + General + Allgemein + + + Advanced + Erweitert + + + Reset to default colors + + PagePlayDemo @@ -1059,45 +1198,45 @@ This game is in lobby. You may join and start playing once the game starts. - Dieses Spiel wartet im Augenblick auf Mitspieler. + Dieses Spiel wartet im Augenblick auf Mitspieler. Du kannst beitreten und mitspielen oder zusehen, sobald das Spiel beginnt. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Dieses Spiel läuft gerade. + Dieses Spiel läuft gerade. Du kannst beitreten und zusehen oder du wartest bis die aktuelle Runde zu Ende ist. %1 is the host. He may adjust settings and start the game. - %1 ist der Besitzer dieses Raums und kann die Einstellungen anpassen und die Runde starten. + %1 ist der Besitzer dieses Raums und kann die Einstellungen anpassen und die Runde starten. Random Map - Zufallskarte + Zufallskarte Games may be played on precreated or randomized maps. - Spiele können auf vorgefertigten oder zufälligen Karten stattfinden. + Spiele können auf vorgefertigten oder zufälligen Karten stattfinden. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Spielprofile geben allgemeine Dinge einer Runde vor, etwa die Rundenzeit, Sudden Death oder Vampirismus. + Spielprofile geben allgemeine Dinge einer Runde vor, etwa die Rundenzeit, Sudden Death oder Vampirismus. The Weapon Scheme defines available weapons and their ammunition count. - Waffenzusammenstellungen bestimmen, welche Waffen wann und in welchen Mengen zur Verfügung stehen. + Waffenzusammenstellungen bestimmen, welche Waffen wann und in welchen Mengen zur Verfügung stehen. There are %1 clients connected to this room. - + Es befindet sich %1 Spieler in diesem Raum. Es befinden sich %1 Spieler in diesem Raum. There are %1 teams participating in this room. - + Es nimmt %1 Team in diesem Raum teil. Es nehmen %1 Teams in diesem Raum teil. @@ -1112,7 +1251,7 @@ Random Maze - Zufallslabyrinth + Zufallslabyrinth State: @@ -1302,11 +1441,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Einfaches Spiel (Eine schnelle Runde gegen den PC, Einstellungen werden automatisch gewählt) + Einfaches Spiel (Eine schnelle Runde gegen den PC, Einstellungen werden automatisch gewählt) Multiplayer (play a hotseat game against your friends, or AI teams) - Mehrspieler (Spiele gegen deine Freunde oder Computergegner) + Mehrspieler (Spiele gegen deine Freunde oder Computergegner) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1314,23 +1453,63 @@ Demos (Watch recorded demos) - Demos (Wiedergabe einer gespeicherten Demo) + Demos (Wiedergabe einer gespeicherten Demo) Load (Load a previously saved game) - Laden (eines vorher gespeicherten Spiels) + Laden (eines vorher gespeicherten Spiels) Campaign Mode (...). IN DEVELOPMENT Kampagnenmodus (...) IN ENTWICKLUNG - Campaign Mode (...) + Training Mode (Practice your skills in a range of training missions) + Trainingsmodus (Verbessere deine Fähigkeiten in verschiedenen Trainingsmissionen) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) - Trainingsmodus (Verbessere deine Fähigkeiten in verschiedenen Trainingsmissionen) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Laden + + + Load a previously saved game + @@ -1343,6 +1522,71 @@ Select a mission! Wähle eine Mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Name + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1449,6 +1693,26 @@ Frontend effects Animationen im Frontend + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1619,6 +1883,26 @@ Schemes and Weapons Spielprofile und Waffen + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1664,7 +1948,7 @@ Net nick - Spitzname im Netz + Spitzname im Netz Server name: @@ -1752,7 +2036,7 @@ Restart game to apply - Spiel neu starten, um Änderungen zu übernehmen + Spiel neu starten, um Änderungen zu übernehmen Explosives @@ -1814,7 +2098,7 @@ Password - Passwort + Passwort % Get Away Time @@ -1824,6 +2108,68 @@ This program is distributed under the GNU General Public License v2 Dieses Spiel wird unter den Bedingungen der GNU General Public License v2 verbreitet + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Spitzname + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1835,6 +2181,10 @@ hedgehog %1 Igel %1 + + anonymous + + QMainWindow @@ -1917,6 +2267,44 @@ Can not delete default weapon set '%1'! Standardwaffenprofil '%1' kann nicht gelöscht werden! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2015,36 +2403,107 @@ more mehr + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Raumname + Raumname C - Sp. + Sp. T - T. + T. Owner - Besitzer + Besitzer Map - Karte + Karte Rules - Regeln + Regeln Weapons - Waffen + Waffen + + + + RoomsListModel + + In progress + Im Spiel + + + Room Name + Raumname + + + C + Sp. + + + T + T. + + + Owner + Besitzer + + + Map + Karte + + + Rules + Regeln + + + Weapons + Waffen + + + Random Map + Zufallskarte + + + Random Maze + Zufallslabyrinth + + + Hand-drawn + @@ -2360,6 +2819,14 @@ slot 10 Slot 10 + + mute audio + + + + record + + binds (categories) @@ -2446,6 +2913,10 @@ Toggle labels above hedgehogs: Ändere die Informationen über Igeln: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_en.ts --- a/share/hedgewars/Data/Locale/hedgewars_en.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_en.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -130,10 +144,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -189,7 +199,7 @@ Password - Password + Password Your nickname %1 is @@ -392,6 +402,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Password + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -401,6 +437,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -484,6 +540,10 @@ All files + + Eraser + + PageEditTeam @@ -557,14 +617,12 @@ <b>%1</b> thought it's good to shoot his own hedgehogs with <b>%2</b> pts. - <b>%1</b> killed <b>%2</b> of his own hedgehogs. - @@ -583,14 +641,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Local Game (Play a game on a single computer) + Local Game (Play a game on a single computer) Network Game (Play a game across a network) - Network Game (Play a game across a network) + Network Game (Play a game across a network) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -841,6 +906,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -878,6 +983,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -889,6 +1002,14 @@ Official server Official server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -944,6 +1065,18 @@ Delete weapon set + + General + General + + + Advanced + Advanced + + + Reset to default colors + + PagePlayDemo @@ -1009,45 +1142,45 @@ This game is in lobby. You may join and start playing once the game starts. - This game is in lobby. + This game is in lobby. You may join and start playing once the game starts. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - This game is in progress. + This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. %1 is the host. He may adjust settings and start the game. - %1 is the host. He may adjust settings and start the game. + %1 is the host. He may adjust settings and start the game. Random Map - Random Map + Random Map Games may be played on precreated or randomized maps. - Games may be played on precreated or randomized maps. + Games may be played on precreated or randomized maps. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. + The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. The Weapon Scheme defines available weapons and their ammunition count. - The Weapon Scheme defines available weapons and their ammunition count. + The Weapon Scheme defines available weapons and their ammunition count. There are %1 clients connected to this room. - + There is %1 client connected to this room. There are %1 clients connected to this room. There are %1 teams participating in this room. - + There is %1 team participating in this room. There are %1 teams participating in this room. @@ -1061,10 +1194,6 @@ Please select room from the list - Random Maze - - - Rules: @@ -1094,7 +1223,6 @@ %1 players online - @@ -1252,26 +1380,66 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Simple Game (a quick game against the computer, settings are chosen for you) + Simple Game (a quick game against the computer, settings are chosen for you) Multiplayer (play a hotseat game against your friends, or AI teams) - Multiplayer (play a hotseat game against your friends, or AI teams) + Multiplayer (play a hotseat game against your friends, or AI teams) Training Mode (Practice your skills in a range of training missions) - Training Mode (Practice your skills in a range of training missions) + Training Mode (Practice your skills in a range of training missions) Demos (Watch recorded demos) - Demos (Watch recorded demos) + Demos (Watch recorded demos) Load (Load a previously saved game) - Load (Load a previously saved game) - - - Campaign Mode (...) + Load (Load a previously saved game) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Load + + + Load a previously saved game @@ -1285,6 +1453,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Name + + + Size + + + + %1 bytes + + %1 byte + %1 bytes + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + Do you really want do remove %1 file? + Do you really want do remove %1 files? + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1391,6 +1624,26 @@ Frontend effects Frontend effects + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1561,6 +1814,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1614,7 +1887,7 @@ Net nick - Net nick + Net nick Resolution @@ -1694,7 +1967,7 @@ Restart game to apply - Restart game to apply + Restart game to apply Explosives @@ -1746,7 +2019,7 @@ Password - Password + Password % Get Away Time @@ -1756,6 +2029,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Nickname + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1767,6 +2102,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1849,6 +2188,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1947,36 +2324,107 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Room Name + Room Name C - C + C T - T + T Owner - Owner + Owner Map - Map + Map Rules - Rules + Rules Weapons - Weapons + Weapons + + + + RoomsListModel + + In progress + + + + Room Name + Room Name + + + C + C + + + T + T + + + Owner + Owner + + + Map + Map + + + Rules + Rules + + + Weapons + Weapons + + + Random Map + Random Map + + + Random Maze + + + + Hand-drawn + @@ -2292,6 +2740,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2378,6 +2834,10 @@ Toggle labels above hedgehogs: Toggle labels above hedgehogs: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_es.ts --- a/share/hedgewars/Data/Locale/hedgewars_es.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_es.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -73,6 +80,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -134,10 +148,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -193,7 +203,7 @@ Password - Contraseña + Contraseña Your nickname %1 is @@ -413,6 +423,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Contraseña + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -422,6 +458,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -509,6 +565,10 @@ All files Todos los ficheros + + Eraser + + PageEditTeam @@ -612,14 +672,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Juego local (Jugar en la misma computadora) + Juego local (Jugar en la misma computadora) Network Game (Play a game across a network) - Juego en red (Jugar a través de la red) + Juego en red (Jugar a través de la red) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -895,6 +962,46 @@ Downloadable Content Contenido adicional + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -932,6 +1039,14 @@ OK OK + + DLC + + + + Downloadable Content + Contenido adicional + PageNetType @@ -943,6 +1058,14 @@ Official server Servidor oficial + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -998,6 +1121,18 @@ Delete weapon set Eliminar set de armas + + General + General + + + Advanced + Avanzado + + + Reset to default colors + + PagePlayDemo @@ -1063,45 +1198,45 @@ This game is in lobby. You may join and start playing once the game starts. - Este juego está en espera + Este juego está en espera Puedes entrar y empezar a jugar cuando la partida comience. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Esta partida se encuentra en progreso + Esta partida se encuentra en progreso Puedes unirte como espectador, pero tendrás que esperar a que el juego termine para poder jugar. %1 is the host. He may adjust settings and start the game. - %1 es el anfitrión. Puede ajustar los parámetros del juego e iniciar la partida. + %1 es el anfitrión. Puede ajustar los parámetros del juego e iniciar la partida. Random Map - Terreno aleatorio + Terreno aleatorio Games may be played on precreated or randomized maps. - Las partidas pueden ser jugadas bien en mapas pre-creados o generados aleatoriamente. + Las partidas pueden ser jugadas bien en mapas pre-creados o generados aleatoriamente. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Los modos de juego definen opciones generales y preferencias como el tiempo de las rondas, muerte súbita o vampirismo. + Los modos de juego definen opciones generales y preferencias como el tiempo de las rondas, muerte súbita o vampirismo. The Weapon Scheme defines available weapons and their ammunition count. - El set de armas define las armas y munición disponibles. + El set de armas define las armas y munición disponibles. There are %1 clients connected to this room. - + Hay %1 cliente en esta sala. Hay %1 clientes en esta sala. There are %1 teams participating in this room. - + Hay %1 equipo participando en esta sala. Hay %1 equipos participando en esta sala. @@ -1116,7 +1251,7 @@ Random Maze - Laberinto aleatorio + Laberinto aleatorio State: @@ -1310,11 +1445,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Partida sencilla (Una partida rápida contra la computadora; los ajustes se eligen automáticamente) + Partida sencilla (Una partida rápida contra la computadora; los ajustes se eligen automáticamente) Multiplayer (play a hotseat game against your friends, or AI teams) - Multijugador (Juega compartiendo el ordenador contra tus amigos o la computadora) + Multijugador (Juega compartiendo el ordenador contra tus amigos o la computadora) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1322,22 +1457,58 @@ Demos (Watch recorded demos) - Demos (Visualiza demos previamente grabadas) + Demos (Visualiza demos previamente grabadas) Load (Load a previously saved game) - Cargar (Cargar un juego previamente guardado) + Cargar (Cargar un juego previamente guardado) Campaign Mode (...). IN DEVELOPMENT Campaña (...) EN DESARROLLO - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Cargar + + + Load a previously saved game @@ -1351,6 +1522,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Nombre + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1457,6 +1693,26 @@ Frontend effects Habilitar efectos del interfaz + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1659,6 +1915,26 @@ Schemes and Weapons Modos de juego y sets de armas + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1704,7 +1980,7 @@ Net nick - Apodo + Apodo Server name: @@ -1792,7 +2068,7 @@ Restart game to apply - Requiere reiniciar el juego + Requiere reiniciar el juego This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1865,7 +2141,7 @@ Password - Contraseña + Contraseña % Get Away Time @@ -1875,6 +2151,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Nick + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1886,6 +2224,10 @@ hedgehog %1 erizo %1 + + anonymous + + QMainWindow @@ -1968,6 +2310,44 @@ Can not delete default weapon set '%1'! ¡No se puede eliminar el set de armas predefinido '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2070,36 +2450,107 @@ more más + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Nombre de la sala + Nombre de la sala C - J + J T - E + E Owner - Propietario + Propietario Map - Mapa + Mapa Rules - Reglas + Reglas Weapons - Set de armas + Set de armas + + + + RoomsListModel + + In progress + En progreso + + + Room Name + Nombre de la sala + + + C + J + + + T + E + + + Owner + Propietario + + + Map + Mapa + + + Rules + Reglas + + + Weapons + + + + Random Map + Terreno aleatorio + + + Random Maze + Laberinto aleatorio + + + Hand-drawn + @@ -2415,6 +2866,14 @@ slot 10 posición 10 + + mute audio + + + + record + + binds (categories) @@ -2501,6 +2960,10 @@ Toggle labels above hedgehogs: Cambia las etiquetas sobre los erizos: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_fi.ts --- a/share/hedgewars/Data/Locale/hedgewars_fi.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_fi.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -130,10 +144,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -189,7 +199,7 @@ Password - Salasana + Salasana Your nickname %1 is @@ -392,6 +402,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Salasana + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -401,6 +437,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -484,6 +540,10 @@ All files + + Eraser + + PageEditTeam @@ -587,14 +647,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Paikallinen peli (Pelaa yhdellä tietokoneella) + Paikallinen peli (Pelaa yhdellä tietokoneella) Network Game (Play a game across a network) - Verkkopeli (Pelaa verkon yli) + Verkkopeli (Pelaa verkon yli) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -870,6 +937,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -907,6 +1014,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -918,6 +1033,14 @@ Official server Virallinen palvelin + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -973,6 +1096,18 @@ Delete weapon set + + General + Yleiset + + + Advanced + Lisäasetukset + + + Reset to default colors + + PagePlayDemo @@ -1038,45 +1173,45 @@ This game is in lobby. You may join and start playing once the game starts. - Tämä peli on eteisessä. + Tämä peli on eteisessä. Voit liittyä ja alkaa pelaamaan sitten kun peli alkaa. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Tämä peli on menossa. + Tämä peli on menossa. Voit liittyä ja seurata sitä, mutta sinun on odotettava pelin päättymistä päästäksesi pelaamaan. %1 is the host. He may adjust settings and start the game. - %1 on isäntä. Hän voi säätää asetuksia ja aloittaa pelin. + %1 on isäntä. Hän voi säätää asetuksia ja aloittaa pelin. Random Map - Satunnainen kartta + Satunnainen kartta Games may be played on precreated or randomized maps. - Pelejä voi pelata valmiiksi luoduissa tai satunnaisesti tehdyissä kartoissa. + Pelejä voi pelata valmiiksi luoduissa tai satunnaisesti tehdyissä kartoissa. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Pelikaava määrittelee yleiset asetukset ja säädöt kuten kierrosajan, äkkikuoleman ja vampyrismin. + Pelikaava määrittelee yleiset asetukset ja säädöt kuten kierrosajan, äkkikuoleman ja vampyrismin. The Weapon Scheme defines available weapons and their ammunition count. - Asesuunnitelma määrittelee saatavilla olevat aseet ja niiden panosmäärät. + Asesuunnitelma määrittelee saatavilla olevat aseet ja niiden panosmäärät. There are %1 clients connected to this room. - + Yksi asiakas on liittyneenä tähän huoneeseen %1 asiakasta on liittyneenä tähän huoneeseen There are %1 teams participating in this room. - + Tässä huoneessa on osallistuneena yksi joukkue Tässä huoneessa on osallistuneena %1 joukkuetta @@ -1091,7 +1226,7 @@ Random Maze - Satunnainen sokkelo + Satunnainen sokkelo State: @@ -1285,11 +1420,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Yksinkertainen peli (pikapeli tietokonetta vastaan, asetukset valitaan puolestasi) + Yksinkertainen peli (pikapeli tietokonetta vastaan, asetukset valitaan puolestasi) Multiplayer (play a hotseat game against your friends, or AI teams) - Moninpeli (pelaa samalla koneella kavereitasi tai tekoälyä vastaan) + Moninpeli (pelaa samalla koneella kavereitasi tai tekoälyä vastaan) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1297,22 +1432,58 @@ Demos (Watch recorded demos) - Demot (Katso nauhoitettuja demoja) + Demot (Katso nauhoitettuja demoja) Load (Load a previously saved game) - Lataa (Lataa aikaisemmin tallennettu peli) + Lataa (Lataa aikaisemmin tallennettu peli) Campaign Mode (...). IN DEVELOPMENT Kampanja-tila (...). KEHITYS KESKEN - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Lataa + + + Load a previously saved game @@ -1326,6 +1497,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Nimi + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1432,6 +1668,26 @@ Frontend effects Käyttöliittymän tehosteet + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1630,6 +1886,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1683,7 +1959,7 @@ Net nick - Verkkopeli-nimimerkki + Verkkopeli-nimimerkki Resolution @@ -1763,7 +2039,7 @@ Restart game to apply - Käynnistä peli uudelleen ottaaksesi muutokset käyttöön + Käynnistä peli uudelleen ottaaksesi muutokset käyttöön Explosives @@ -1815,7 +2091,7 @@ Password - Salasana + Salasana % Get Away Time @@ -1825,6 +2101,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Nimimerkki + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1836,6 +2174,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1918,6 +2260,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2016,36 +2396,107 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Huoneen nimi + Huoneen nimi C - A + A T - J + J Owner - Omistaja + Omistaja Map - Kartta + Kartta Rules - Säännöt + Säännöt Weapons - Aseet + Aseet + + + + RoomsListModel + + In progress + Kesken + + + Room Name + Huoneen nimi + + + C + A + + + T + J + + + Owner + Omistaja + + + Map + Kartta + + + Rules + Säännöt + + + Weapons + Aseet + + + Random Map + Satunnainen kartta + + + Random Maze + Satunnainen sokkelo + + + Hand-drawn + @@ -2361,6 +2812,14 @@ slot 10 paikka 10 + + mute audio + + + + record + + binds (categories) @@ -2447,6 +2906,10 @@ Toggle labels above hedgehogs: Vaihda siilien yläpuolella näkyviä "leimoja": + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_fr.ts --- a/share/hedgewars/Data/Locale/hedgewars_fr.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_fr.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -130,10 +144,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -189,7 +199,7 @@ Password - Mot de passe + Mot de passe Your nickname %1 is @@ -392,6 +402,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Mot de passe + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -401,6 +437,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -488,6 +544,10 @@ All files + + Eraser + + PageEditTeam @@ -587,14 +647,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Jeu en local (Jouer une partie sur son propre ordinateur) + Jeu en local (Jouer une partie sur son propre ordinateur) Network Game (Play a game across a network) - Jeu en réseau (Jouer une partie sur le réseau) + Jeu en réseau (Jouer une partie sur le réseau) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -865,6 +932,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -902,6 +1009,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -913,6 +1028,14 @@ Official server Serveur officiel + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -956,6 +1079,18 @@ Delete weapon set Supprimer un ensemble d'armes + + General + Général + + + Advanced + Avancé + + + Reset to default colors + + PagePlayDemo @@ -1021,45 +1156,45 @@ This game is in lobby. You may join and start playing once the game starts. - Ce jeu est dans le lobby. + Ce jeu est dans le lobby. Vous pouvez le rejoindre et commencerez à jouer quand le jeu démarrera. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Ce jeu est en cours. + Ce jeu est en cours. Vous pouvez le rejoindre et y assister maintenant mais vous devrez attendre la fin de la partie pour commencer à jouer. %1 is the host. He may adjust settings and start the game. - %1 est l'hôte. Il peut modifier les options et lancer la partie. + %1 est l'hôte. Il peut modifier les options et lancer la partie. Random Map - Carte Aléatoire + Carte Aléatoire Games may be played on precreated or randomized maps. - Les parties peuvent être jouées sur des cartes aléatoires ou pré-créées. + Les parties peuvent être jouées sur des cartes aléatoires ou pré-créées. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Les paramètres de jeu définissent les options et préférences générales comme la Durée d'un Tour, la Mort Subite ou le Vampirisme. + Les paramètres de jeu définissent les options et préférences générales comme la Durée d'un Tour, la Mort Subite ou le Vampirisme. The Weapon Scheme defines available weapons and their ammunition count. - Les paramètres d'armes définissent les armes disponibles et leur nombre de munitions. + Les paramètres d'armes définissent les armes disponibles et leur nombre de munitions. There are %1 clients connected to this room. - + Il y a %1 client connecté à cette salle. Il y a %1 clients connectés à cette salle. There are %1 teams participating in this room. - + Il y a %1 équipe participant dans cette salle. Il y a %1 équipes participant dans cette salle. @@ -1074,7 +1209,7 @@ Random Maze - Labyrinthe aléatoire + Labyrinthe aléatoire State: @@ -1267,11 +1402,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Jeu en solo (rapide partie contre l'ordinateur, options choisies automatiquement) + Jeu en solo (rapide partie contre l'ordinateur, options choisies automatiquement) Multiplayer (play a hotseat game against your friends, or AI teams) - Jeu à plusieurs (contre vos amis et/ou contre l'ordinateur) + Jeu à plusieurs (contre vos amis et/ou contre l'ordinateur) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1279,22 +1414,58 @@ Demos (Watch recorded demos) - Démonstrations (Visionner les démonstrations enregistrées) + Démonstrations (Visionner les démonstrations enregistrées) Load (Load a previously saved game) - Charger (Charger une partie préalablement sauvegardée) + Charger (Charger une partie préalablement sauvegardée) Campaign Mode (...). IN DEVELOPMENT Mode Campagne (...). EN DÉVELOPPEMENT - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Charger + + + Load a previously saved game @@ -1308,6 +1479,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Nom + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1414,6 +1650,26 @@ Frontend effects Effets du menu principal + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1584,12 +1840,32 @@ Schemes and Weapons Paramètres et Armes + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel Net nick - Pseudo réseau + Pseudo réseau This program is distributed under the GNU General Public License @@ -1717,7 +1993,7 @@ Restart game to apply - Relancez le jeu pour appliquer + Relancez le jeu pour appliquer Explosives @@ -1773,7 +2049,7 @@ Password - Mot de passe + Mot de passe % Get Away Time @@ -1783,6 +2059,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Pseudo + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1794,6 +2132,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1876,6 +2218,44 @@ Can not delete default weapon set '%1'! Impossible d'effacer le set d'armes par défaut. + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1974,36 +2354,107 @@ more plus + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Nom de la salle + Nom de la salle C - C + C T - É + É Owner - Propriétaire + Propriétaire Map - Carte + Carte Rules - Règles + Règles Weapons - Armes + Armes + + + + RoomsListModel + + In progress + En cours + + + Room Name + Nom de la salle + + + C + C + + + T + É + + + Owner + Propriétaire + + + Map + Carte + + + Rules + Règles + + + Weapons + Armes + + + Random Map + Carte Aléatoire + + + Random Maze + Labyrinthe aléatoire + + + Hand-drawn + @@ -2320,6 +2771,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2406,6 +2865,10 @@ Toggle labels above hedgehogs: (Dés)activez les étiquettes au-dessus des hérissons: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_hu.ts --- a/share/hedgewars/Data/Locale/hedgewars_hu.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_hu.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -68,6 +75,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -129,10 +143,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -188,7 +198,7 @@ Password - JElszó + JElszó Your nickname %1 is @@ -378,6 +388,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + JElszó + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -387,6 +423,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -470,6 +526,10 @@ All files + + Eraser + + PageEditTeam @@ -561,14 +621,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Helyi játék (Játssz egyetlen számítógépen) + Helyi játék (Játssz egyetlen számítógépen) Network Game (Play a game across a network) - Hálózati játék (Játék hálózaton keresztül) + Hálózati játék (Játék hálózaton keresztül) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -819,6 +886,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -856,6 +963,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -867,6 +982,14 @@ Official server Hivatalos szerver + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -922,6 +1045,18 @@ Delete weapon set + + General + Általános + + + Advanced + Haladó + + + Reset to default colors + + PagePlayDemo @@ -987,44 +1122,44 @@ This game is in lobby. You may join and start playing once the game starts. - Ez a játék elérhető. + Ez a játék elérhető. Csatlakozz és játssz, amikor a játék elkezdődik. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Ez a játék folyamatban van. + Ez a játék folyamatban van. Csatlakozhatsz mint megfigyelő, de a játszáshoz meg kell várnod a jelenlegi meccs befejeződését. %1 is the host. He may adjust settings and start the game. - %1 a host. Ő kezeli a beállításokat és a játék indítását. + %1 a host. Ő kezeli a beállításokat és a játék indítását. Random Map - Véletlen pálya + Véletlen pálya Games may be played on precreated or randomized maps. - A játékok előkészített vagy véletlen pályákon játszódnak. + A játékok előkészített vagy véletlen pályákon játszódnak. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - A játék sémája az általános beállításokat határozza meg. illetve egyéb dolgokat, mint egy kör ideje, Hirtelen halál vagy Vámpírizmus. + A játék sémája az általános beállításokat határozza meg. illetve egyéb dolgokat, mint egy kör ideje, Hirtelen halál vagy Vámpírizmus. The Weapon Scheme defines available weapons and their ammunition count. - A fegyverséma az elérhető fegyverek és a lőszer mennyiségét határozza meg. + A fegyverséma az elérhető fegyverek és a lőszer mennyiségét határozza meg. There are %1 clients connected to this room. - + Összesen %1 kliens csatlakozott a szobához. There are %1 teams participating in this room. - + Összesen %1 csapat van a szobában. @@ -1038,7 +1173,7 @@ Random Maze - Véletlen labirintus + Véletlen labirintus Rules: @@ -1226,11 +1361,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Egyszerű játék (gyors játék a gép ellen, a beállításokat már kiválasztottuk neked) + Egyszerű játék (gyors játék a gép ellen, a beállításokat már kiválasztottuk neked) Multiplayer (play a hotseat game against your friends, or AI teams) - Többjátékos (hotseat játék a barátaid vagy a gép csapatai ellen) + Többjátékos (hotseat játék a barátaid vagy a gép csapatai ellen) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1238,18 +1373,54 @@ Demos (Watch recorded demos) - Demók (felvett demók megtekintése) + Demók (felvett demók megtekintése) Load (Load a previously saved game) - Betöltés (korábbi mentett állás visszatöltése) - - - Campaign Mode (...) + Betöltés (korábbi mentett állás visszatöltése) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Betöltés + + + Load a previously saved game @@ -1263,6 +1434,69 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Név + + + Size + + + + %1 bytes + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1369,6 +1603,26 @@ Frontend effects Frontend effektusok + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1539,6 +1793,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1592,7 +1866,7 @@ Net nick - Becenév a neten + Becenév a neten Resolution @@ -1672,7 +1946,7 @@ Restart game to apply - Újraindításkor lép érvénybe + Újraindításkor lép érvénybe Explosives @@ -1730,7 +2004,7 @@ Password - JElszó + JElszó % Get Away Time @@ -1740,6 +2014,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Becenév + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1751,6 +2087,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1833,6 +2173,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1931,36 +2309,107 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Szoba neve + Szoba neve C - C + C T - T + T Owner - Tulajdonos + Tulajdonos Map - Pálya + Pálya Rules - Szabályok + Szabályok Weapons - Fegyverek + Fegyverek + + + + RoomsListModel + + In progress + + + + Room Name + Szoba neve + + + C + C + + + T + T + + + Owner + Tulajdonos + + + Map + Pálya + + + Rules + Szabályok + + + Weapons + Fegyverek + + + Random Map + Véletlen pálya + + + Random Maze + Véletlen labirintus + + + Hand-drawn + @@ -2276,6 +2725,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2362,6 +2819,10 @@ Toggle labels above hedgehogs: Sünik feletti címkék beállítása: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_it.ts --- a/share/hedgewars/Data/Locale/hedgewars_it.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_it.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + Indietro + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + Vuoi veramente uscire? + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -132,7 +146,7 @@ Kicking %1 ... - %1 sta per venire buttato fuori... + %1 sta per venire buttato fuori... @@ -189,7 +203,7 @@ Password - Password + Password Your nickname %1 is @@ -379,7 +393,7 @@ %1 *** %2 has left - %1 *** %2 se n'è andato + %1 *** %2 se n'è andato Your nickname %1 is @@ -407,7 +421,33 @@ User quit - Uscita dell'utente + Esci + + + Remote host has closed connection + L'host remoto ha terminato la connessione. + + + The server is too old. Disconnecting now. + Il server è troppo datato. Si verrà immediatamente disconessi. + + + + HWPasswordDialog + + Password + Password + + + + HWUploadVideoDialog + + Upload video + Carica video + + + Upload + Carica @@ -418,6 +458,26 @@ + LibavIteraction + + Duration: %1m %2s + + Durata: %1m %2s + + + Video: %1x%2, + Video: %1x%2, + + + %1 fps, + %1 fps, + + + Audio: + Audio: + + + PageAdmin Server message: @@ -505,6 +565,10 @@ All files Tutti i file + + Eraser + Gomma + PageEditTeam @@ -604,14 +668,21 @@ + PageInfo + + Open the snapshot folder + Apri cartella schermate + + + PageMain Local Game (Play a game on a single computer) - Gioco locale (Gioca una partita su un singolo computer) + Gioco locale (Gioca una partita su un singolo computer) Network Game (Play a game across a network) - Gioco in rete (Gioca una partita attraverso la rete) + Gioco in rete (Gioca una partita attraverso la rete) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -681,7 +752,7 @@ While playing you should give yourself a short break at least once an hour. Tips - Durante il gioco dovresti fare una breve pausa almeno ogni ora. In caso di partite più lunghe, sospendi l'attività per almeno 30 minuti al termine del gioco! + Durante il gioco dovresti fare una breve pausa almeno ogni ora. In caso di partite più lunghe, sospendi l'attività per almeno 30 minuti al termine del gioco! If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance. @@ -766,7 +837,7 @@ The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well. Tips - L'Ultima Sonata è l'attacco aereo più dannoso. Perderai il tuo riccio, eseguendolo, quindi ci sono anche delle grosse controindicazioni. + L'Ultima Sonata è l'attacco aereo più dannoso. Perderai il tuo riccio, eseguendolo, quindi ci sono anche delle grosse controindicazioni. Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water. @@ -867,6 +938,46 @@ Downloadable Content Contenuti Scaricabili + + Local Game + Gioco in locale + + + Play a game on a single computer + Gioca una partita offline + + + Network Game + Gioco in rete + + + Play a game across a network + Gioca una partita attraverso una rete + + + Read about who is behind the Hedgewars Project + Leggi chi c'è dietro allo sviluppo di Hedgewars + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + Lascia un feedback segnalando problemi, suggerendo nuove funzionalità o solamente indicando il tuo livello di gradimento del gioco. + + + Access the user created content downloadable from our website + Accedi al download di contenuti creati dalla comunità dal nostro sito web + + + Exit game + Esci dal gioco + + + Manage videos recorded from game + Organizza i video registrati tramite il gioco + + + Edit game preferences + Modifica preferenze + PageMultiplayer @@ -904,6 +1015,14 @@ OK OK + + DLC + DLC + + + Downloadable Content + Contenuti Scaricabili + PageNetType @@ -915,6 +1034,14 @@ Official server Server ufficiale + + Join hundreds of players online! + Incontra centinaia di giocatori online! + + + Join or host your own game server in a Local Area Network. + Unisciti ad un server o creane uno nuovo per il gioco online in una rete LAN. + PageOptions @@ -970,6 +1097,18 @@ Delete weapon set Elimina set delle armi + + General + Generale + + + Advanced + Avanzate + + + Reset to default colors + Ripristina colori originali + PagePlayDemo @@ -1035,45 +1174,45 @@ This game is in lobby. You may join and start playing once the game starts. - Questa partita è nella lobby. + Questa partita è nella lobby. Puoi entrare e iniziare a giocare non appena inizia la partita. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Questa partita è in corso. + Questa partita è in corso. Puoi entrare come spettatore ma dovrai aspettare la fine della partita per giocare. %1 is the host. He may adjust settings and start the game. - %1 è l'host. Può modificare le impostazioni e avviare il gioco. + %1 è l'host. Può modificare le impostazioni e avviare il gioco. Random Map - Mappa casuale + Mappa casuale Games may be played on precreated or randomized maps. - Le partite possono essere giocate su mappe predefinite, casuali o disegnate. + Le partite possono essere giocate su mappe predefinite, casuali o disegnate. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Lo Schema di Gioco definisce le opzioni generali e le preferenze come il tempo per ogni turno, Sudden Death o Vampirismo. + Lo Schema di Gioco definisce le opzioni generali e le preferenze come il tempo per ogni turno, Sudden Death o Vampirismo. The Weapon Scheme defines available weapons and their ammunition count. - Lo Schema delle Armi definisce le armi disponibili e le munizioni per ognuna di esse. + Lo Schema delle Armi definisce le armi disponibili e le munizioni per ognuna di esse. There are %1 clients connected to this room. - + E' presente %1 utente connesso a questa stanza. Sono presenti %1 utenti connessi a questa stanza. There are %1 teams participating in this room. - + E' presente %1 squadra partecipante in questa stanza. Sono presenti %1 squadre partecipanti in questa stanza. @@ -1088,7 +1227,7 @@ Random Maze - Labirinto Casuale + Labirinto Casuale State: @@ -1282,11 +1421,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Partita singola (una partita veloce contro il computer, con impostazioni standard e squadre casuali) + Partita singola (una partita veloce contro il computer, con impostazioni standard e squadre casuali) Multiplayer (play a hotseat game against your friends, or AI teams) - Multigiocatore (Gioca contro i tuoi amici o contro squadre controllate dal computer con impostazioni e squadre personalizzate) + Multigiocatore (Gioca contro i tuoi amici o contro squadre controllate dal computer con impostazioni e squadre personalizzate) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1294,11 +1433,11 @@ Demos (Watch recorded demos) - Demo (Guarda le partite registrate) + Demo (Guarda le partite registrate) Load (Load a previously saved game) - Carica (Carica una partita precedentemente salvata) + Carica (Carica una partita precedentemente salvata) Campaign Mode (...). IN DEVELOPMENT @@ -1306,11 +1445,55 @@ Campaign Mode (...) - Modalità Campagna. + Modalità Campagna. Training Mode (Practice your skills in a range of training missions) - Modalità allenamento e missioni (metti in pratica le tue abilità in una vasta gamma di missioni speciali) + Modalità allenamento e missioni (metti in pratica le tue abilità in una vasta gamma di missioni speciali) + + + Simple Game + Partita Semplice + + + Play a quick game against the computer with random settings + Gioca una partita rapida contro il computer con impostazioni casuali + + + Multiplayer + Multiplayer + + + Play a hotseat game against your friends, or AI teams + Gioca una partira controlo un amico oppure contro il computer + + + Campaign Mode + Modalità Campagna + + + Training Mode + Modalità allenamento + + + Practice your skills in a range of training missions + Metti alla prova le tue capacità in una vasta gamma di missioni di addestramento + + + Demos + Demo + + + Watch recorded demos + Visualizza demo registrate + + + Load + Carica + + + Load a previously saved game + Carica un gioco salvato in precedenza @@ -1323,6 +1506,71 @@ Select a mission! Seleziona una missione! + + Pick the mission or training to play + Scegli la missione, sfida o addestramento da intraprendere + + + Start fighting + Inizia combattimento + + + + PageVideos + + Name + Nome + + + Size + Dimensione + + + %1 bytes + + %1 bytes + %1 bytes + + + + (in progress...) + (in corso...) + + + Date: + Data: + + + Size: + Dimensione: + + + Are you sure? + Sei sicuro? + + + Do you really want do remove %1? + Vuoi veramente cancellare %1? + + + Do you really want do remove %1 file(s)? + + Vuoi veramente cancellare %1 file(s)? + Vuoi veramente cancellare %1 file(s)? + + + + encoding + encoding + + + uploading + caricamento + + + Do you really want do cancel uploading %1? + Vuoi veramente sospendere il carimento del file %1? + QAction @@ -1429,6 +1677,26 @@ Frontend effects Effetti speciali nel frontend + + Save password + Salva password + + + Save account name and password + Salva nome utente e password + + + Video is private + Il video è privato + + + Record audio + Registra audio + + + Use game resolution + Usa la risoluzione del gioco + QComboBox @@ -1599,6 +1867,26 @@ Schemes and Weapons Schemi di Gioco e Armi + + Custom colors + Colori personalizzati + + + Miscellaneous + Varie + + + Video recording options + Opzioni di registrazione video + + + Videos + Video + + + Description + Descrizione + QLabel @@ -1652,7 +1940,7 @@ Net nick - Nickname di rete + Nickname di rete Server name: @@ -1732,7 +2020,7 @@ Restart game to apply - Riavvia il gioco per applicare le impostazioni + Riavvia il gioco per applicare le impostazioni This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1798,7 +2086,7 @@ Password - Password + Password % Get Away Time @@ -1806,7 +2094,71 @@ This program is distributed under the GNU General Public License v2 - Questo programma è distribuito con licenza GNU General Public License v2 + Questo programma è distribuito con licenza GNU General Public License v2 + + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + Ci sono video che stanno ancora venendo elaborati. +Uscire ora annullerà questo processo e conseguentemente i video non verrano salvati. +Vuoi veramente uscire? + + + Please provide either the YouTube account name or the email address associated with the Google Account. + Inserire il nome utente YouTube o l'indirizzo e-mail associato all'account Google. + + + Account name (or email): + Nome utente (o e-mail): + + + Password: + Password: + + + Video title: + Titolo del video: + + + Video description: + Descrizione del video: + + + Tags (comma separated): + Tag (separate da una virgola): + + + Summary + Riassunto + + + Description + Descrizione + + + Nickname + Nickname + + + Format + Formato + + + Audio codec + Codec audio + + + Video codec + Codec video + + + Framerate + Framerate + + + Bitrate (Kbps) + Bitrate (Kbps) @@ -1819,6 +2171,10 @@ hedgehog %1 Riccio %1 + + anonymous + anonimo + QMainWindow @@ -1901,6 +2257,44 @@ Can not delete default weapon set '%1'! Impossibile elimininare il set delle armi predefinito '%1'! + + Fields required + Campi richiesti + + + Please fill out all fields + E' necessario compilare tutti i campi + + + Success + Avvenuto con successo + + + Successfully posted the issue on code.google.com! + Errore segnalato con successo su code.google.com! + + + Error during authentication with www.google.com + Errore durante l'autenticazione con il server www.google.com + + + Error creating the issue + Errore nella segnalazione dell'errore + + + Error while authenticating at google.com: + + Errore durante l'autenticazione su google.com: + + + Login or password is incorrect + Nome utente e password non riconosciuti + + + Error while sending metadata to youtube.com: + + Errore nell'invio dei dati a youtube.com: + QObject @@ -1999,11 +2393,70 @@ more altro + + More info + Più informazioni + + + Set default options + Imposta opzioni predefinite + + + Open videos directory + Apri cartella video + + + Play + Riproduci + + + Upload to YouTube + Carica su YouTube + + + Cancel uploading + Sospendi caricamento + QTableWidget Room Name + Nome della Stanza + + + C + C + + + T + T + + + Owner + Proprietario + + + Map + Mappa + + + Rules + Regole + + + Weapons + Armi + + + + RoomsListModel + + In progress + In corso + + + Room Name Nome della Stanza @@ -2030,6 +2483,18 @@ Weapons Armi + + Random Map + Mappa casuale + + + Random Maze + Labirinto Casuale + + + Hand-drawn + Disegnata a mano + SelWeaponWidget @@ -2344,6 +2809,14 @@ slot 10 slot 10 + + mute audio + disattiva audio + + + record + registra + binds (categories) @@ -2430,6 +2903,10 @@ Toggle labels above hedgehogs: Cambia le etichette sui ricci: + + Record video: + Registra video: + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_ja.ts --- a/share/hedgewars/Data/Locale/hedgewars_ja.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_ja.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -68,6 +75,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -129,10 +143,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -188,7 +198,7 @@ Password - パスワード + パスワード Your nickname %1 is @@ -379,6 +389,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + パスワード + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -388,6 +424,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Clear Accounts Cache @@ -463,6 +519,10 @@ All files + + Eraser + + PageEditTeam @@ -542,14 +602,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - ロカール ゲーム (一台のパソコンゲーム) + ロカール ゲーム (一台のパソコンゲーム) Network Game (Play a game across a network) - ネットワーク ゲーム + ネットワーク ゲーム Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -800,6 +867,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -837,6 +944,14 @@ OK + + DLC + + + + Downloadable Content + + PageNetType @@ -848,6 +963,14 @@ Official server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -891,6 +1014,18 @@ Delete weapon set + + General + 一般 + + + Advanced + 高級 + + + Reset to default colors + + PagePlayDemo @@ -956,44 +1091,7 @@ This game is in lobby. You may join and start playing once the game starts. - このゲームはロビー中。 - - - This game is in progress. -You may join and spectate now but you'll have to wait for the game to end to start playing. - - - - %1 is the host. He may adjust settings and start the game. - - - - Random Map - - - - Games may be played on precreated or randomized maps. - - - - The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - - - - The Weapon Scheme defines available weapons and their ammunition count. - - - - There are %1 clients connected to this room. - - - - - - There are %1 teams participating in this room. - - - + このゲームはロビー中。 Please enter room name @@ -1004,10 +1102,6 @@ - Random Maze - - - Rules: @@ -1185,11 +1279,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - 簡単ゲーム (パソコンとのゲーム、自動設定) + 簡単ゲーム (パソコンとのゲーム、自動設定) Multiplayer (play a hotseat game against your friends, or AI teams) - マルチプレイヤー (パソコンまたは友達との戦い) + マルチプレイヤー (パソコンまたは友達との戦い) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1197,18 +1291,54 @@ Demos (Watch recorded demos) - デモ (録画されたデモを見る) + デモ (録画されたデモを見る) Load (Load a previously saved game) - ロード (その前保存したゲームをやる) - - - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) + ロード (その前保存したゲームをやる) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + ロード + + + Load a previously saved game @@ -1222,6 +1352,69 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + + + + Size + + + + %1 bytes + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1324,6 +1517,26 @@ Frontend effects + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1494,6 +1707,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1547,7 +1780,7 @@ Net nick - ネット別名 + ネット別名 Resolution @@ -1626,10 +1859,6 @@ - Restart game to apply - - - Explosives @@ -1679,7 +1908,7 @@ Password - パスワード + パスワード % Get Away Time @@ -1689,6 +1918,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1700,6 +1991,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1782,6 +2077,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1880,10 +2213,49 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget + Map + 地図 + + + Weapons + 武器 + + + + RoomsListModel + + In progress + + + Room Name @@ -1911,6 +2283,18 @@ Weapons 武器 + + Random Map + + + + Random Maze + + + + Hand-drawn + + SelWeaponWidget @@ -2221,6 +2605,14 @@ slot 10 スロットX + + mute audio + + + + record + + binds (categories) @@ -2307,6 +2699,10 @@ Toggle labels above hedgehogs: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_ko.ts --- a/share/hedgewars/Data/Locale/hedgewars_ko.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_ko.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -68,6 +75,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 has been removed from your ignore list @@ -113,10 +127,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -167,10 +177,6 @@ - Password - - - Your nickname %1 is registered on Hedgewars.org Please provide your password below @@ -340,6 +346,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -349,6 +381,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Clear Accounts Cache @@ -420,6 +472,10 @@ All files + + Eraser + + PageEditTeam @@ -495,16 +551,15 @@ + PageInfo + + Open the snapshot folder + + + + PageMain - Local Game (Play a game on a single computer) - - - - Network Game (Play a game across a network) - - - Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. Tips @@ -753,6 +808,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -790,6 +885,14 @@ OK + + DLC + + + + Downloadable Content + + PageNetType @@ -801,6 +904,14 @@ Official server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -844,6 +955,18 @@ Delete weapon set + + General + + + + Advanced + + + + Reset to default colors + + PagePlayDemo @@ -907,48 +1030,6 @@ - This game is in lobby. -You may join and start playing once the game starts. - - - - This game is in progress. -You may join and spectate now but you'll have to wait for the game to end to start playing. - - - - %1 is the host. He may adjust settings and start the game. - - - - Random Map - - - - Games may be played on precreated or randomized maps. - - - - The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - - - - The Weapon Scheme defines available weapons and their ammunition count. - - - - There are %1 clients connected to this room. - - - - - - There are %1 teams participating in this room. - - - - - Please enter room name @@ -957,10 +1038,6 @@ - Random Maze - - - Rules: @@ -1137,27 +1214,47 @@ PageSinglePlayer - Simple Game (a quick game against the computer, settings are chosen for you) - - - - Multiplayer (play a hotseat game against your friends, or AI teams) - - - - Demos (Watch recorded demos) - - - - Load (Load a previously saved game) - - - - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + + + + Load a previously saved game @@ -1171,6 +1268,69 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + + + + Size + + + + %1 bytes + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1273,6 +1433,26 @@ Frontend effects + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1435,6 +1615,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1483,10 +1683,6 @@ - Net nick - - - Resolution @@ -1563,10 +1759,6 @@ - Restart game to apply - - - Explosives @@ -1615,10 +1807,6 @@ - Password - - - % Get Away Time @@ -1626,6 +1814,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1637,6 +1887,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1709,6 +1963,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1807,9 +2099,37 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + - QTableWidget + RoomsListModel + + In progress + + Room Name @@ -1838,6 +2158,18 @@ Weapons + + Random Map + + + + Random Maze + + + + Hand-drawn + + SelWeaponWidget @@ -2147,6 +2479,14 @@ slot 10 + + mute audio + + + + record + + binds (categories) @@ -2233,6 +2573,10 @@ Toggle labels above hedgehogs: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_lt.ts --- a/share/hedgewars/Data/Locale/hedgewars_lt.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_lt.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,14 +2,22 @@ + AbstractPage + + + Go back + + + + AmmoSchemeModel - + new - + copy of @@ -17,18 +25,18 @@ DrawMapWidget - - + + File error - + Cannot open file '%1' for writing - + Cannot read file '%1' @@ -53,95 +61,98 @@ GameCFGWidget - + Game Options - + Edit schemes - + Edit weapons - + When this option is enabled selecting a game scheme will auto-select a weapon - + Error - + Illegal ammo scheme + HWAskQuitDialog + + + Do yot really want to quit? + + + + HWChatWidget - - Kicking %1 ... - - - - + %1 has been removed from your ignore list - + %1 has been added to your ignore list - + %1 has been removed from your friends list - + %1 has been added to your friends list - + Stylesheet imported from %1 - + Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! - + Couldn't read %1 - + StyleSheet discarded - + StyleSheet saved to %1 - + Failed to save StyleSheet to %1 - + %1 is not a valid command! @@ -149,39 +160,34 @@ HWForm - - + + DefaultTeam - + Game aborted - - + + Error - + Please select record from the list above - + OK - - Password - - - - + Your nickname %1 is registered on Hedgewars.org Please provide your password below @@ -189,17 +195,17 @@ - + No password supplied. - + Nickname - + Some one already uses your nickname %1 on the server. @@ -207,40 +213,40 @@ - + No nickname supplied. - + Unable to start the server - - + + Cannot save record to file %1 - + Hedgewars Demo File File Types - + Hedgewars Save File File Types - + Demo name - + Demo name: @@ -248,12 +254,13 @@ HWGame - + + en.txt lt.txt - + Cannot open demofile %1 @@ -261,92 +268,92 @@ HWMapContainer - + Map - + Filter - + All - + Small - + Medium - + Large - + Cavern - + Wacky - + Type - + Small tunnels - + Medium tunnels - + Large tunnels - + Small floating islands - + Medium floating islands - + Large floating islands - + Themes - + Seed - + Set @@ -354,17 +361,17 @@ HWNetServersModel - + Title - + IP - + Port @@ -372,59 +379,91 @@ HWNewNet - + User quit - + + Remote host has closed connection + + + + The host was not found. Please check the host name and port settings. - + Connection refused - + + The server is too old. Disconnecting now. + + + + Room destroyed - + You got kicked - + + %1 *** %2 has joined the room - + %1 *** %2 has joined - - + + %1 *** %2 has left - - + + %1 *** %2 has left (%3) - + Quit reason: + HWPasswordDialog + + + Password + + + + + HWUploadVideoDialog + + + Upload video + + + + + Upload + + + + KB @@ -433,6 +472,30 @@ + LibavIteraction + + + Duration: %1m %2s + + + + + + Video: %1x%2, + + + + + %1 fps, + + + + + Audio: + + + + PageAdmin @@ -481,44 +544,49 @@ PageDrawMap - - Undo - - - - Clear - - - - - Load + Eraser + Undo + + + + + Clear + + + + + Load + + + + Save - + Load drawn map - - + + Drawn Maps - - + + All files - + Save drawn map @@ -554,12 +622,12 @@ - + The best shot award was won by <b>%1</b> with <b>%2</b> pts. - + The best killer is <b>%1</b> with <b>%2</b> kills in a turn. @@ -568,7 +636,7 @@ - + A total of <b>%1</b> hedgehog(s) were killed during this round. @@ -577,7 +645,7 @@ - + (%1 kill) @@ -586,7 +654,7 @@ - + <b>%1</b> thought it's good to shoot his own hedgehogs with <b>%2</b> pts. @@ -595,7 +663,7 @@ - + <b>%1</b> killed <b>%2</b> of his own hedgehogs. @@ -604,7 +672,7 @@ - + <b>%1</b> was scared and skipped turn <b>%2</b> times. @@ -622,312 +690,360 @@ + PageInfo + + + Open the snapshot folder + + + + PageMain - Local Game (Play a game on a single computer) - - - - - Network Game (Play a game across a network) - - - - + Local Game + + + + + Play a game on a single computer + + + + + Network Game + + + + + Play a game across a network + + + + + Read about who is behind the Hedgewars Project + + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Downloadable Content - - Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. - Tips - - - - - Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water. - Tips - - - - - If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death! - Tips - - - - - Want to save ropes? Release the rope in mid air and then shoot again. As long as you don't touch the ground you'll reuse your rope without wasting ammo! - Tips - - - - - If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/. - Tips - - - - - You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked. - Tips - - - - - By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them. - Tips - - - - - Hedgewars is Open Source and Freeware we create in our spare time. If you've got problems, ask on our forums but please don't expect 24/7 support! - Tips - - - - - Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work! - Tips - - - - - Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like! - Tips - - - - - Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund! - Tips - - - - - From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance. - Tips - - - - - Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us! - Tips - - - - - Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux. - Tips - - - - - Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option. - Tips - - - - - Connect one or more gamepads before starting the game to be able to assign their controls to your teams. - Tips - - - - - Create an account on %1 to keep others from using your most favourite nickname while playing on the official server. - Tips - - - - - While playing you should give yourself a short break at least once an hour. - Tips - - - - - If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance. - Tips - - - - - If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers. - Tips - - - - - We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know! - Tips - - - - - Especially while playing online be polite and always remember there might be some minors playing with or against you as well! - Tips + + Access the user created content downloadable from our website + + + + + Exit game + + + + + Manage videos recorded from game + + + + + Edit game preferences - Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game! + Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. Tips - The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing. + Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water. Tips - You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead! + If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death! Tips - Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well. + Want to save ropes? Release the rope in mid air and then shoot again. As long as you don't touch the ground you'll reuse your rope without wasting ammo! Tips - No hedgehogs were harmed in making this game. + If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/. Tips - There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump. + You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked. Tips - Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving. + By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them. Tips - Some weapons require special strategies or just lots of training, so don't give up on a particular tool if you miss an enemy once. + Hedgewars is Open Source and Freeware we create in our spare time. If you've got problems, ask on our forums but please don't expect 24/7 support! Tips - Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this. + Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work! Tips - The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once. + Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like! Tips - The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well. + Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund! Tips - The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power. + From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance. Tips - Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water. + Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us! Tips - The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground. + Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux. Tips - If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion. + Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option. Tips - The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early. + Connect one or more gamepads before starting the game to be able to assign their controls to your teams. Tips - The Flame Thrower is a weapon but it can be used for tunnel digging as well. + Create an account on %1 to keep others from using your most favourite nickname while playing on the official server. Tips - Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms. + While playing you should give yourself a short break at least once an hour. Tips - Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits. + If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance. Tips - Like Hedgewars? Become a fan on %1 or follow us on %2! + If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers. Tips - Feel free to draw your own graves, hats, flags or even maps and themes! But note that you'll have to share them somewhere to use them online. + We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know! Tips - Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice! + Especially while playing online be polite and always remember there might be some minors playing with or against you as well! + Tips + + + + + Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game! + Tips + + + + + The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing. + Tips + + + + + You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead! Tips - Keep your video card drivers up to date to avoid issues playing the game. + Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well. Tips - You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser. + No hedgehogs were harmed in making this game. + Tips + + + + + There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump. Tips - You can find your Hedgewars configuration files under "My Documents\Hedgewars". Create backups or take the files with you, but don't edit them by hand. + Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving. + Tips + + + + + Some weapons require special strategies or just lots of training, so don't give up on a particular tool if you miss an enemy once. Tips - You can find your Hedgewars configuration files under "Library/Application Support/Hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand. + Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this. + Tips + + + + + The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once. Tips + The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well. + Tips + + + + + The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power. + Tips + + + + + Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water. + Tips + + + + + The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground. + Tips + + + + + If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion. + Tips + + + + + The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early. + Tips + + + + + The Flame Thrower is a weapon but it can be used for tunnel digging as well. + Tips + + + + + Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms. + Tips + + + + + Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits. + Tips + + + + + Like Hedgewars? Become a fan on %1 or follow us on %2! + Tips + + + + + Feel free to draw your own graves, hats, flags or even maps and themes! But note that you'll have to share them somewhere to use them online. + Tips + + + + + Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice! + Tips + + + + + Keep your video card drivers up to date to avoid issues playing the game. + Tips + + + + + You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser. + Tips + + + + + You can find your Hedgewars configuration files under "My Documents\Hedgewars". Create backups or take the files with you, but don't edit them by hand. + Tips + + + + + You can find your Hedgewars configuration files under "Library/Application Support/Hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand. + Tips + + + + You can find your Hedgewars configuration files under ".hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand. Tips @@ -957,22 +1073,32 @@ PageNetGame - + + DLC + + + + + Downloadable Content + + + + Control - + Error - + Please enter room name - + OK @@ -986,102 +1112,127 @@ + Join or host your own game server in a Local Area Network. + + + + Official server + + + Join hundreds of players online! + + PageOptions - + + General + + + + + Advanced + + + + New team - + Edit team - + Delete team - + You can't edit teams from team selection. Go back to main menu to add, edit or delete teams. - + New scheme - + Edit scheme - + Delete scheme - + New weapon set - + Edit weapon set - + Delete weapon set + + + Reset to default colors + + PagePlayDemo - - - - + + + + Error - - + + Please select record from the list - - + + OK - + Rename dialog - + Enter new file name: - + Cannot rename to - + Cannot delete file @@ -1089,145 +1240,85 @@ PageRoomsList - + Room Name: - + Rules: - + Weapons: - + Search: - + Create - + Join - + Refresh - + Clear - + Admin features - - This game is in lobby. -You may join and start playing once the game starts. - - - - - This game is in progress. -You may join and spectate now but you'll have to wait for the game to end to start playing. - - - - - There are %1 clients connected to this room. - - - - - - - - - There are %1 teams participating in this room. - - - - - - - - - %1 is the host. He may adjust settings and start the game. - - - - - Random Map - - - - - Random Maze - - - - - Games may be played on precreated or randomized maps. - - - - - The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - - - - - The Weapon Scheme defines available weapons and their ammunition count. - - - - - + + Error - + Please enter room name - - + + OK - + Please select room from the list - + Warning - + The game you are trying to join has started. Do you still want to join the room? - + %1 players online @@ -1239,152 +1330,152 @@ PageScheme - + Defend your fort and destroy the opponents, two team colours max! - + Teams will start on opposite sides of the terrain, two team colours max! - + Land can not be destroyed! - - Add an indestructible border around the terrain - - - + Add an indestructible border around the terrain + + + + Lower gravity - + Assisted aiming with laser sight - + All hogs have a personal forcefield - - All (living) hedgehogs are fully restored at the end of turn - - - - - Gain 80% of the damage you do back in health - - - + All (living) hedgehogs are fully restored at the end of turn + + + + + Gain 80% of the damage you do back in health + + + + Share your opponents pain, share their damage - + Your hogs are unable to move, put your artillery skills to the test - - Order of play is random instead of in room order. - - - - - Play with a King. If he dies, your side dies. - - - - - Take turns placing your hedgehogs before the start of play. - - - + Order of play is random instead of in room order. + + + + + Play with a King. If he dies, your side dies. + + + + + Take turns placing your hedgehogs before the start of play. + + + + Ammo is shared between all teams that share a colour. - - Disable girders when generating random maps. - - - - - Disable land objects when generating random maps. - - - - - AI respawns on death. - - - - - Attacking does not end your turn. - - - - Weapons are reset to starting values each turn. - - - - - Each hedgehog has its own ammo. It does not share with the team. - - - - - You will not have to worry about wind anymore. - - - - - Wind will affect almost everything. - - - - - Teams in each clan take successive turns sharing their turn time. + Disable girders when generating random maps. + + + + + Disable land objects when generating random maps. + + + + + AI respawns on death. + + + + + Attacking does not end your turn. + Weapons are reset to starting values each turn. + + + + + Each hedgehog has its own ammo. It does not share with the team. + + + + + You will not have to worry about wind anymore. + + + + + Wind will affect almost everything. + + + + + Teams in each clan take successive turns sharing their turn time. + + + + Add an indestructible border along the bottom - + Random - + Seconds - + Copy - + New - + Delete @@ -1416,109 +1507,218 @@ PageSinglePlayer - Simple Game (a quick game against the computer, settings are chosen for you) - - - - - Multiplayer (play a hotseat game against your friends, or AI teams) - - - - - Campaign Mode (...) - - - - - Training Mode (Practice your skills in a range of training missions) - - - - - Demos (Watch recorded demos) - - - - - Load (Load a previously saved game) + Simple Game + + + + + Play a quick game against the computer with random settings + + + + + Multiplayer + + + + + Play a hotseat game against your friends, or AI teams + + + + + + Campaign Mode + + + + + Training Mode + + + + + Practice your skills in a range of training missions + + + + + Demos + + + + + Watch recorded demos + + + + + Load + + + + + Load a previously saved game PageTraining - + + Pick the mission or training to play + + + + + Start fighting + + + + No description available - + Select a mission! + PageVideos + + + Name + + + + + Size + + + + + %1 bytes + + + + + + + + + (in progress...) + + + + + Date: + + + + + Size: + + + + + + + Are you sure? + + + + + Do you really want do remove %1? + + + + + Do you really want do remove %1 file(s)? + + + + + + + + + encoding + + + + + uploading + + + + + Do you really want do cancel uploading %1? + + + + QAction - + Info - - Kick - - - - - Ban - - - - Follow + Kick - - Ignore + Ban - + Follow + + + + + + Ignore + + + + + Add friend - + Unignore - + Remove friend - + Update - + Restrict Joins - + Restrict Team Additions - + Start @@ -1526,203 +1726,228 @@ QCheckBox - + Show ammo menu tooltips - + Alternative damage show - + Append date and time to record file name - + Check for updates at startup - + Frontend fullscreen - + Frontend effects - + Enable frontend sounds - + Enable frontend music - + Fullscreen - + Enable sound - + Enable music - + Show FPS + + + + Save password + + + + + Save account name and password + + + + + Video is private + + + + + Record audio + + + + + Use game resolution + + QComboBox - - + Mission - + generated map... - + generated maze... - + hand drawn map... - + Human - + Level - + Community - + (System default) + + Disabled + + + + + Red/Cyan + + + + + Cyan/Red + + + + + Red/Blue + + + + + Blue/Red + + + + + Red/Green + + + + + Green/Red + + + + + Side-by-side + + + + + Top-Bottom + + + + + Wiggle + + + + + Red/Cyan grayscale + + + + + Cyan/Red grayscale + + + + + Red/Blue grayscale + + + - Disabled + Blue/Red grayscale - Red/Cyan + Red/Green grayscale - Cyan/Red - - - - - Red/Blue - - - - - Blue/Red - - - - - Red/Green - - - - - Green/Red - - - - - Side-by-side - - - - - Top-Bottom - - - - - Wiggle - - - - - Red/Cyan grayscale - - - - - Cyan/Red grayscale - - - - - Red/Blue grayscale - - - - - Blue/Red grayscale - - - - - Red/Green grayscale - - - - Green/Red grayscale - - - + + + Any - + In lobby - + In progress @@ -1735,17 +1960,17 @@ - + Team Settings - + Fort - + Key binds @@ -1755,26 +1980,36 @@ - + Teams - + Schemes and Weapons - + Misc - + Audio/Graphic options + + Custom colors + + + + + Miscellaneous + + + Game Modifiers @@ -1785,10 +2020,25 @@ - + Playing teams + + + Video recording options + + + + + Videos + + + + + Description + + QLabel @@ -1828,18 +2078,18 @@ - + Style - + Scheme - - + + Weapons @@ -1854,37 +2104,37 @@ - + Name - + Type - + Grave - + Flag - + Voice - + Tip: - + This development build is 'work in progress' and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk! @@ -1899,155 +2149,222 @@ - + Game scheme - - Net nick - - - - - Password - - - - + Locale - + + Nickname + + + + + Resolution + + Quality + + + - Quality - - - - Stereo rendering - + Initial sound volume - + FPS limit - - Restart game to apply - - - - + Damage Modifier - + Turn Time - + Initial Health - + Sudden Death Timeout - + Sudden Death Water Rise - + Sudden Death Health Decrease - + % Rope Length - + Crate Drops - + % Health Crates - + Health in Crates - + Mines Time - + Mines - + % Dud Mines - + Explosives - + % Get Away Time - + Scheme Name: + + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + + Account name (or email): + + + + + Password: + + + + + Video title: + + + + + Video description: + + + + + Tags (comma separated): + + + + + Summary + + + + + Description + + + + + Format + + + + + Audio codec + + + + + Video codec + + + + + Framerate + + + + + Bitrate (Kbps) + + QLineEdit - - + unnamed - - + + hedgehog %1 + + + anonymous + + QMainWindow - + Hedgewars %1 @@ -2055,112 +2372,165 @@ QMessageBox - - + + Teams - - + + Really delete this team? - - + + Schemes - + Can not delete default scheme '%1'! - + + + + Network - + Connection to server is lost - + All file associations have been set. - + File association failed. - + + Fields required + + + + + Please fill out all fields + + + + + Success + + + + + Successfully posted the issue on code.google.com! + + + + + + Error during authentication with www.google.com + + + + + Error creating the issue + + + + + + Error - + Failed to open data directory: %1 Please check your installation - + Really delete this game scheme? - - - + + + Weapons - + Can not overwrite default weapon set '%1'! - + Can not delete default weapon set '%1'! - + Really delete this weapon set? + + + Error while authenticating at google.com: + + + + + + Login or password is incorrect + + + + + Error while sending metadata to youtube.com: + + + QObject - + Error - + Cannot create directory %1 - + OK - + Nickname - + Please enter your nickname @@ -2180,29 +2550,29 @@ + Cancel - + more - - + Go! - + Random Team - + Setup @@ -2227,7 +2597,7 @@ - + Ready @@ -2237,69 +2607,122 @@ - + Associate file extensions - - + + Play demo - + Rename - + + + Delete - + Load + + + More info + + + + + Set default options + + + + + Open videos directory + + + + + Play + + + + + + Upload to YouTube + + + + + Cancel uploading + + - QTableWidget - - + RoomsListModel + + + In progress + + + + Room Name - + C - + T - + Owner - + Map - + Rules - + Weapons + + + Random Map + + + + + Random Maze + + + + + Hand-drawn + + SelWeaponWidget @@ -2324,14 +2747,14 @@ - - + + new - - + + copy of @@ -2339,18 +2762,18 @@ TCPBase - - + + Error - + Unable to start the server: %1. - + Unable to run engine: %1 ( @@ -2363,122 +2786,122 @@ - + Divide Teams - + Solid Land - + Add Border - - Low Gravity - - - + Low Gravity + + + + Laser Sight - + Invulnerable - + Reset Health - - Vampirism - - - - - Karma - - - + Vampirism + + + + + Karma + + + + Artillery - + Random Order - - King - - - - - Place Hedgehogs - - - - - Clan Shares Ammo - - - + King + + + + + Place Hedgehogs + + + + + Clan Shares Ammo + + + + Disable Girders - - Disable Land Objects - - - - - AI Survival Mode - - - - - Unlimited Attacks - - - - - Reset Weapons - - - + Disable Land Objects + + + + + AI Survival Mode + + + + + Unlimited Attacks + + + + + Reset Weapons + + + + Per Hedgehog Ammo - + Disable Wind - + More Wind - + Tag Team - + Add Bottom Border @@ -2676,20 +3099,30 @@ - change mode + mute audio - capture + change mode + capture + + + + hedgehogs info + + + record + + binds (categories) @@ -2782,417 +3215,422 @@ - + Toggle fullscreen mode: - - Take a screenshot: - - - + Take a screenshot: + + + + Toggle labels above hedgehogs: + + + Record video: + + binds (keys) - + Axis - - - (Up) - - - + (Up) + + + + + (Down) - + Hat - - (Left) - - - + (Left) + + + + (Right) - + Button - + Keyboard - - Mouse: Left button - - - - Mouse: Middle button + Mouse: Left button - Mouse: Right button + Mouse: Middle button - Mouse: Wheel up + Mouse: Right button - Mouse: Wheel down + Mouse: Wheel up - Backspace + Mouse: Wheel down - Tab + Backspace - Clear + Tab - Return + Clear - Pause + Return - Escape + Pause + Escape + + + + Space - - Delete - - - - Numpad 0 + Delete - Numpad 1 + Numpad 0 - Numpad 2 + Numpad 1 - Numpad 3 + Numpad 2 - Numpad 4 + Numpad 3 - Numpad 5 + Numpad 4 - Numpad 6 + Numpad 5 - Numpad 7 + Numpad 6 - Numpad 8 + Numpad 7 - Numpad 9 + Numpad 8 - Numpad . + Numpad 9 - Numpad / + Numpad . - Numpad * + Numpad / - Numpad - + Numpad * - Numpad + + Numpad - - Enter + Numpad + - Equals + Enter - Up + Equals - Down + Up - Right + Down - Left + Right - Insert + Left - Home + Insert - End + Home - Page up + End + Page up + + + + Page down - - Num lock - - - - Caps lock + Num lock - Scroll lock + Caps lock - Right shift + Scroll lock - Left shift + Right shift - Right ctrl + Left shift - Left ctrl + Right ctrl - Right alt + Left ctrl - Left alt + Right alt - Right meta + Left alt + Right meta + + + + Left meta - - A button - - - - - B button - - - - X button + A button - Y button + B button - LB button + X button - RB button + Y button - Back button + LB button - Start button + RB button - Left stick + Back button + Start button + + + + + Left stick + + + + Right stick - - Left stick (Right) - - - - - Left stick (Left) - - - - - Left stick (Down) - - - - Left stick (Up) + Left stick (Right) - Left trigger + Left stick (Left) - Right trigger + Left stick (Down) - Right stick (Down) + Left stick (Up) - Right stick (Up) + Left trigger - Right stick (Right) + Right trigger - Right stick (Left) + Right stick (Down) + + + + + Right stick (Up) + Right stick (Right) + + + + + Right stick (Left) + + + + DPad diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_nl.ts --- a/share/hedgewars/Data/Locale/hedgewars_nl.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_nl.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 has been removed from your ignore list @@ -114,10 +128,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -168,10 +178,6 @@ - Password - - - Your nickname %1 is registered on Hedgewars.org Please provide your password below @@ -351,6 +357,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -360,6 +392,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Clear Accounts Cache @@ -431,6 +483,10 @@ All files + + Eraser + + PageEditTeam @@ -512,16 +568,15 @@ + PageInfo + + Open the snapshot folder + + + + PageMain - Local Game (Play a game on a single computer) - - - - Network Game (Play a game across a network) - - - Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. Tips @@ -770,6 +825,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -807,6 +902,14 @@ OK + + DLC + + + + Downloadable Content + + PageNetType @@ -818,6 +921,14 @@ Official server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -861,6 +972,18 @@ Delete weapon set + + General + + + + Advanced + + + + Reset to default colors + + PagePlayDemo @@ -924,50 +1047,6 @@ - This game is in lobby. -You may join and start playing once the game starts. - - - - This game is in progress. -You may join and spectate now but you'll have to wait for the game to end to start playing. - - - - %1 is the host. He may adjust settings and start the game. - - - - Random Map - - - - Games may be played on precreated or randomized maps. - - - - The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - - - - The Weapon Scheme defines available weapons and their ammunition count. - - - - There are %1 clients connected to this room. - - - - - - - There are %1 teams participating in this room. - - - - - - Please enter room name @@ -976,10 +1055,6 @@ - Random Maze - - - Rules: @@ -1157,27 +1232,47 @@ PageSinglePlayer - Simple Game (a quick game against the computer, settings are chosen for you) - - - - Multiplayer (play a hotseat game against your friends, or AI teams) - - - - Demos (Watch recorded demos) - - - - Load (Load a previously saved game) - - - - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + + + + Load a previously saved game @@ -1191,6 +1286,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1293,6 +1453,26 @@ Frontend effects + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1455,6 +1635,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1503,10 +1703,6 @@ - Net nick - - - Resolution @@ -1583,10 +1779,6 @@ - Restart game to apply - - - Explosives @@ -1635,10 +1827,6 @@ - Password - - - % Get Away Time @@ -1646,6 +1834,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1657,6 +1907,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1729,6 +1983,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1827,9 +2119,37 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + - QTableWidget + RoomsListModel + + In progress + + Room Name @@ -1858,6 +2178,18 @@ Weapons + + Random Map + + + + Random Maze + + + + Hand-drawn + + SelWeaponWidget @@ -2167,6 +2499,14 @@ slot 10 + + mute audio + + + + record + + binds (categories) @@ -2253,6 +2593,10 @@ Toggle labels above hedgehogs: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_pl.ts --- a/share/hedgewars/Data/Locale/hedgewars_pl.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_pl.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -74,6 +81,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -137,7 +151,7 @@ Kicking %1 ... - Wyrzucam %1... + Wyrzucam %1... @@ -194,7 +208,7 @@ Password - Hasło + Hasło Your nickname %1 is @@ -414,6 +428,32 @@ User quit Użytkownik wyszedł + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Hasło + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -423,6 +463,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -510,6 +570,10 @@ All files Wszystkie pliki + + Eraser + + PageEditTeam @@ -621,14 +685,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Gra lokalna (graj na jednym komputerze) + Gra lokalna (graj na jednym komputerze) Network Game (Play a game across a network) - Gra sieciowa (graj przez internet lub LAN) + Gra sieciowa (graj przez internet lub LAN) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -919,6 +990,46 @@ Downloadable Content Dodatki + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -956,6 +1067,14 @@ OK OK + + DLC + + + + Downloadable Content + Dodatki + PageNetType @@ -967,6 +1086,14 @@ Official server Oficjalny serwer + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -1022,6 +1149,18 @@ Delete weapon set Usuń zestaw uzbrojenia + + General + Ogólne + + + Advanced + Zaawansowane + + + Reset to default colors + + PagePlayDemo @@ -1087,38 +1226,38 @@ This game is in lobby. You may join and start playing once the game starts. - Ta gra jest w poczekalni. + Ta gra jest w poczekalni. Możesz dołączyć i zacząć grać gdy gra się rozpocznie. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Ta gra jest w toku. + Ta gra jest w toku. Możesz dołączyć i obserwować grę, ale by móc zagrać musisz poczekać aż gra się skończy. %1 is the host. He may adjust settings and start the game. - %1 jest właścicielem. Może on zmienić ustawienia i rozpocząć grę. + %1 jest właścicielem. Może on zmienić ustawienia i rozpocząć grę. Random Map - Losowa mapa + Losowa mapa Games may be played on precreated or randomized maps. - Gry mogą być rozgrywane na losowych lub uprzednio stworzonych mapach. + Gry mogą być rozgrywane na losowych lub uprzednio stworzonych mapach. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Schemat określa ustawienia i preferencje takie jak Czas trwania tury, Nagłą śmierć, Wampiryzm itp. + Schemat określa ustawienia i preferencje takie jak Czas trwania tury, Nagłą śmierć, Wampiryzm itp. The Weapon Scheme defines available weapons and their ammunition count. - Zestaw uzbrojenia określa dostępną broń oraz ilość amunicji. + Zestaw uzbrojenia określa dostępną broń oraz ilość amunicji. There are %1 clients connected to this room. - + Do tego pokoju jest podłączony %1 gracz. Do tego pokoju jest podłączonych %1 graczy. Do tego pokoju jest podłączonych %1 graczy. @@ -1126,7 +1265,7 @@ There are %1 teams participating in this room. - + W tym pokoju gra %1 drużyna. W tym pokoju grają %1 drużyny. W tym pokoju grają %1 drużyny. @@ -1142,7 +1281,7 @@ Random Maze - Losowy labirynt + Losowy labirynt State: @@ -1337,11 +1476,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Szybka gra (szybka gra przeciwko komputerowi, ustawienia są wybierane za ciebie) + Szybka gra (szybka gra przeciwko komputerowi, ustawienia są wybierane za ciebie) Multiplayer (play a hotseat game against your friends, or AI teams) - Gra wieloosobowa (graj z komputerem lub na zmianę ze znajomymi) + Gra wieloosobowa (graj z komputerem lub na zmianę ze znajomymi) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1349,11 +1488,11 @@ Demos (Watch recorded demos) - Dema (zobacz nagrane dema) + Dema (zobacz nagrane dema) Load (Load a previously saved game) - Wczytaj grę (wczytaj poprzednio zapisaną grę) + Wczytaj grę (wczytaj poprzednio zapisaną grę) Campaign Mode (...). IN DEVELOPMENT @@ -1361,11 +1500,55 @@ Campaign Mode (...) - Kampania (...) + Kampania (...) Training Mode (Practice your skills in a range of training missions) - Trening (sprawdź swoje umiejętności podczas misji treningowych) + Trening (sprawdź swoje umiejętności podczas misji treningowych) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Wczytaj + + + Load a previously saved game + @@ -1378,6 +1561,73 @@ Select a mission! Wybierz misję! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Nazwa + + + Size + + + + %1 bytes + + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1484,6 +1734,26 @@ Frontend effects Efekty w menu + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1686,6 +1956,26 @@ Schemes and Weapons Schematy i uzbrojenie + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1731,7 +2021,7 @@ Net nick - Pseudonim sieciowy + Pseudonim sieciowy Server name: @@ -1819,7 +2109,7 @@ Restart game to apply - Zrestartuj grę by wprowadzić zmiany + Zrestartuj grę by wprowadzić zmiany This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1895,7 +2185,7 @@ Password - Hasło + Hasło % Get Away Time @@ -1905,6 +2195,68 @@ This program is distributed under the GNU General Public License v2 Ten program jest rozprowadzany na zasadach GNU GPL v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Nick + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1916,6 +2268,10 @@ hedgehog %1 jeż %1 + + anonymous + + QMainWindow @@ -1998,6 +2354,44 @@ Can not delete default weapon set '%1'! Nie można usunąć domyśłnego zestawu usbrojenia '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2100,36 +2494,107 @@ more Więcej + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Nazwa pokoju + Nazwa pokoju C - Kli + Kli T - Druż + Druż Owner - Właśc + Właśc Map - Mapa + Mapa Rules - Schemat + Schemat Weapons - Uzbrojenie + Uzbrojenie + + + + RoomsListModel + + In progress + W toku + + + Room Name + Nazwa pokoju + + + C + Kli + + + T + Druż + + + Owner + Właśc + + + Map + Mapa + + + Rules + Schemat + + + Weapons + Uzbrojenie + + + Random Map + Losowa mapa + + + Random Maze + Losowy labirynt + + + Hand-drawn + @@ -2444,6 +2909,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2530,6 +3003,10 @@ Toggle labels above hedgehogs: Zmień szczegółowość opisów nad jeżami: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_pt_BR.ts --- a/share/hedgewars/Data/Locale/hedgewars_pt_BR.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_pt_BR.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -130,10 +144,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -189,7 +199,7 @@ Password - Senha + Senha Your nickname %1 is @@ -393,6 +403,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Senha + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -402,6 +438,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Clear Accounts Cache @@ -481,6 +537,10 @@ All files + + Eraser + + PageEditTeam @@ -634,14 +694,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Jogo Local (Jogue uma partida em apenas um computador) + Jogo Local (Jogue uma partida em apenas um computador) Network Game (Play a game across a network) - Jogo em Rede (Jogue uma partida em rede) + Jogo em Rede (Jogue uma partida em rede) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -933,6 +1000,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -970,6 +1077,14 @@ OK OK + + DLC + + + + Downloadable Content + + PageNetType @@ -981,6 +1096,14 @@ Official server Servidor Oficial + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -1036,6 +1159,18 @@ Delete weapon set Apagar esquema de armas + + General + Geral + + + Advanced + Avançado + + + Reset to default colors + + PagePlayDemo @@ -1101,45 +1236,45 @@ This game is in lobby. You may join and start playing once the game starts. - Este jogo está em espera. + Este jogo está em espera. Você pode entrar e começar a jogar quando o jogo iniciar. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Este jogo já está acontecendo. + Este jogo já está acontecendo. Você pode entrar e assitir, mas terá que esperar o jogo terminar para poder jogar. %1 is the host. He may adjust settings and start the game. - %1 é o anfitrião. Ele pode ajustar opções e iniciar o jogo. + %1 é o anfitrião. Ele pode ajustar opções e iniciar o jogo. Random Map - Mapa Aleatório + Mapa Aleatório Games may be played on precreated or randomized maps. - Partidas podem ser jogadas em mapas pré-criados ou aleatórios. + Partidas podem ser jogadas em mapas pré-criados ou aleatórios. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - O Esquema de Jogo define as opções gerais e preferências como Tempo do Round, Morte Súbita ou Vampirismo. + O Esquema de Jogo define as opções gerais e preferências como Tempo do Round, Morte Súbita ou Vampirismo. The Weapon Scheme defines available weapons and their ammunition count. - o Esquema de Armas define as armas disponíveis e as quantidades de munições delas. + o Esquema de Armas define as armas disponíveis e as quantidades de munições delas. There are %1 clients connected to this room. - + Existe %1 cliente conectado a esta sala. Existem %1 clientes conectados a esta sala. There are %1 teams participating in this room. - + Existe %1 equipe participando desta sala. Existem %1 equipes participando desta sala. @@ -1154,7 +1289,7 @@ Random Maze - Labirinto Aleatório + Labirinto Aleatório State: @@ -1348,11 +1483,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Jogo Simples (uma partida rápida contra o computador, opções são escolhidas por você) + Jogo Simples (uma partida rápida contra o computador, opções são escolhidas por você) Multiplayer (play a hotseat game against your friends, or AI teams) - Multiplayer (jogue no mesmo computador contra seus amigos ou contra o computador) + Multiplayer (jogue no mesmo computador contra seus amigos ou contra o computador) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1360,22 +1495,58 @@ Demos (Watch recorded demos) - Demos (Assista a demos gravadas) + Demos (Assista a demos gravadas) Load (Load a previously saved game) - Carregar (Carregue um jogo salvo) + Carregar (Carregue um jogo salvo) Campaign Mode (...). IN DEVELOPMENT Modo Campanha (...) EM DESENVOLVIMENTO - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Carregar + + + Load a previously saved game @@ -1389,6 +1560,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Nome + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1495,6 +1731,26 @@ Frontend effects Efeitos da interface + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1697,6 +1953,26 @@ Schemes and Weapons Esquemas e Armas + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1742,7 +2018,7 @@ Net nick - Apelido de rede + Apelido de rede Server name: @@ -1830,7 +2106,7 @@ Restart game to apply - Reinicie o jogo para aplicar as modificações + Reinicie o jogo para aplicar as modificações This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1896,7 +2172,7 @@ Password - Senha + Senha % Get Away Time @@ -1906,6 +2182,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Apelido + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1917,6 +2255,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -2001,6 +2343,44 @@ Can not delete default weapon set '%1'! Esquema de armas não pode ser apagado '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2104,37 +2484,108 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Nome da Sala + Nome da Sala C - C + C T E de equipe, na tabela de salas. (Equipes conectadas) - E + E Owner - Dono + Dono Map - Mapa + Mapa Rules - Regras + Regras Weapons - Armas + Armas + + + + RoomsListModel + + In progress + Em progresso + + + Room Name + Nome da Sala + + + C + C + + + T + E + + + Owner + Dono + + + Map + Mapa + + + Rules + Regras + + + Weapons + Armas + + + Random Map + Mapa Aleatório + + + Random Maze + Labirinto Aleatório + + + Hand-drawn + @@ -2451,6 +2902,14 @@ slot 10 posição 10 + + mute audio + + + + record + + binds (categories) @@ -2537,6 +2996,10 @@ Toggle labels above hedgehogs: Alterna as informações sobre os ouriços: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_pt_PT.ts --- a/share/hedgewars/Data/Locale/hedgewars_pt_PT.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_pt_PT.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -132,7 +146,7 @@ Kicking %1 ... - A expulsar %1 ... + A expulsar %1 ... @@ -189,7 +203,7 @@ Password - Password + Password Your nickname %1 is @@ -403,6 +417,32 @@ User quit Utilizador saiu + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Password + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -412,6 +452,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -499,6 +559,10 @@ All files Todos os ficheiros + + Eraser + + PageEditTeam @@ -598,14 +662,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Jogo local (Joga Hedgewars apenas com este computador) + Jogo local (Joga Hedgewars apenas com este computador) Network Game (Play a game across a network) - Jogo em rede (Joga em rede ou na internet) + Jogo em rede (Joga em rede ou na internet) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -856,6 +927,46 @@ Downloadable Content Conteúdo Transferível (DLC) + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -893,6 +1004,14 @@ OK OK + + DLC + + + + Downloadable Content + Conteúdo Transferível (DLC) + PageNetType @@ -904,6 +1023,14 @@ Official server Servidor oficial + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -959,6 +1086,18 @@ Delete weapon set Apagar esquema de armas + + General + Geral + + + Advanced + Avançado + + + Reset to default colors + + PagePlayDemo @@ -1024,45 +1163,45 @@ This game is in lobby. You may join and start playing once the game starts. - Este jogo está ainda na entrada. + Este jogo está ainda na entrada. Pode-se juntar e jogar assim que o jogo começe. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Este jogo está em progresso. + Este jogo está em progresso. Pode-se juntar e observar, mas vai ter de esperar que o jogo termine para poder jogar. %1 is the host. He may adjust settings and start the game. - %1 é o anfitrião. Ele pode ajustar as configurações e começar o jogo. + %1 é o anfitrião. Ele pode ajustar as configurações e começar o jogo. Random Map - Mapa Aleatório + Mapa Aleatório Games may be played on precreated or randomized maps. - É possivel jogar em mapas pré-criados ou aleatórios. + É possivel jogar em mapas pré-criados ou aleatórios. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - O Esquema de Jogo define as configurações gerais e preferências como Tempo da Ronda, Morte súbita ou Vampirismo. + O Esquema de Jogo define as configurações gerais e preferências como Tempo da Ronda, Morte súbita ou Vampirismo. The Weapon Scheme defines available weapons and their ammunition count. - O Esquema de Armas define que armas estão disponíveis e a quantidade de munições. + O Esquema de Armas define que armas estão disponíveis e a quantidade de munições. There are %1 clients connected to this room. - + Apenas %1 cliente esta conectado a esta sala. Um total de %1 clientes estão conectados a esta sala. There are %1 teams participating in this room. - + Apenas %1 equipa esta a participar nesta sala. Existem %1 equipas a participar nesta sala. @@ -1077,7 +1216,7 @@ Random Maze - Labirinto Aleatório + Labirinto Aleatório State: @@ -1267,11 +1406,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Jogo simples (jogo rápido contra o computador, as definições serão escolhidas para si) + Jogo simples (jogo rápido contra o computador, as definições serão escolhidas para si) Multiplayer (play a hotseat game against your friends, or AI teams) - Multi Jogador (jogo estratégico contra amigos ou equipas IA) + Multi Jogador (jogo estratégico contra amigos ou equipas IA) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1279,11 +1418,11 @@ Demos (Watch recorded demos) - Demos (ver demos gravados) + Demos (ver demos gravados) Load (Load a previously saved game) - Carregar (carrega um jogo salvo previamente) + Carregar (carrega um jogo salvo previamente) Campaign Mode (...). IN DEVELOPMENT @@ -1291,11 +1430,55 @@ Campaign Mode (...) - Modo Campanha (...) + Modo Campanha (...) Training Mode (Practice your skills in a range of training missions) - Modo Treino (Treina as tuas habilidades numa panóplia de missões de treino) + Modo Treino (Treina as tuas habilidades numa panóplia de missões de treino) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Carregar + + + Load a previously saved game + @@ -1308,6 +1491,71 @@ Select a mission! Selecciona uma missão! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Nome + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1414,6 +1662,26 @@ Frontend effects Efeitos no frontend + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1584,6 +1852,26 @@ Schemes and Weapons Esquemas e Armamento + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1637,7 +1925,7 @@ Net nick - Nick de rede + Nick de rede Resolution @@ -1717,7 +2005,7 @@ Restart game to apply - Reinicie o jogo para aplicar as alterações + Reinicie o jogo para aplicar as alterações Explosives @@ -1773,7 +2061,7 @@ Password - Password + Password % Get Away Time @@ -1783,6 +2071,68 @@ This program is distributed under the GNU General Public License v2 Esta aplicação é distribuída sob a GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Nome de utilizador + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1794,6 +2144,10 @@ hedgehog %1 ouriço %1 + + anonymous + + QMainWindow @@ -1876,6 +2230,44 @@ Can not delete default weapon set '%1'! Não é possível eliminar o esquema de armas por omisão '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1974,36 +2366,107 @@ more mais + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Nome da Sala + Nome da Sala C - C + C T - E + E Owner - Anfitrião + Anfitrião Map - Mapa + Mapa Rules - Regras + Regras Weapons - Armas + Armas + + + + RoomsListModel + + In progress + Em progresso + + + Room Name + Nome da Sala + + + C + C + + + T + E + + + Owner + Anfitrião + + + Map + Mapa + + + Rules + Regras + + + Weapons + Armas + + + Random Map + Mapa Aleatório + + + Random Maze + Labirinto Aleatório + + + Hand-drawn + @@ -2319,6 +2782,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2405,6 +2876,10 @@ Toggle labels above hedgehogs: Alterar as etiquetas acima dos ouriços: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_ru.ts --- a/share/hedgewars/Data/Locale/hedgewars_ru.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_ru.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + Назад + + + AmmoSchemeModel new @@ -70,7 +77,14 @@ Game Options - Настройки игры + Настройки игры + + + + HWAskQuitDialog + + Do yot really want to quit? + Хотите выйти? @@ -93,51 +107,47 @@ %1 has been removed from your ignore list - + %1 был удалён из вашего списка игнорирования %1 has been added to your ignore list - + %1 был добавлен в ваш список игнорирования %1 has been removed from your friends list - + %1 был удалён из вашего списка друзей %1 has been added to your friends list - + %1 был добавлен в ваш список друзей Stylesheet imported from %1 - + Импортирован стиль из %1 Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! - + Введите %1 для использования текущего стиля и в будущем, введите %2 для сброса! Couldn't read %1 - + Не могу прочитать %1 StyleSheet discarded - + Стиль снят StyleSheet saved to %1 - + Стиль сохранён в %1 Failed to save StyleSheet to %1 - + Ошибка при сохранении стиля в %1 %1 is not a valid command! - - - - Kicking %1 ... - + %1 не является корректной командой @@ -182,51 +192,51 @@ Demo name - + Название демки Demo name: - + Название демки: Game aborted - + Игра прекращена Password - Пароль + Пароль Your nickname %1 is registered on Hedgewars.org Please provide your password below or pick another nickname in game config: - Ваше имя пользователя %1 + Ваше имя пользователя %1 зарегистрировано на сайте hedgewars.org Пожалуйста, укажите ваш пароль в поле ввода внизу или выберите иное имя пользователя в настройках игры: No password supplied. - + Пароль не указан. Nickname - Псевдоним + Псевдоним Some one already uses your nickname %1 on the server. Please pick another nickname: - Кто-то на этом сервере + Кто-то на этом сервере уже использует ваш псевдоним %1. Выберите другой псевдоним: No nickname supplied. - + Псевдоним не указан. @@ -408,7 +418,33 @@ User quit - + Пользователь вышел + + + Remote host has closed connection + Удалённый хост закрыл соединение + + + The server is too old. Disconnecting now. + Слишком старый сервер. Отсоединяюсь. + + + + HWPasswordDialog + + Password + Пароль + + + + HWUploadVideoDialog + + Upload video + Залить видео + + + Upload + Залить @@ -419,6 +455,26 @@ + LibavIteraction + + Duration: %1m %2s + + Длительность: %1мин %2сек + + + Video: %1x%2, + Видео: %1x%2, + + + %1 fps, + %1 кадров/сек, + + + Audio: + Аудио: + + + PageAdmin Server message: @@ -500,11 +556,15 @@ Drawn Maps - + Рисованные карты All files - + Все файлы + + + Eraser + Стирательная резинка @@ -609,18 +669,25 @@ PageInGame In game... - + В игре... + + + + PageInfo + + Open the snapshot folder + Открыть папку скриншотов PageMain Local Game (Play a game on a single computer) - Локальная игра (игра на одном компьютере) + Локальная игра (игра на одном компьютере) Network Game (Play a game across a network) - Сетевая игра + Сетевая игра Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -871,6 +938,46 @@ Downloadable Content + + Local Game + Локальная игра + + + Play a game on a single computer + Играть на одном компьютере + + + Network Game + Сетевая игра + + + Play a game across a network + Играть по сети + + + Read about who is behind the Hedgewars Project + Прочитать, кто стоит за проектом Hedgewars + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + Выйти из игры + + + Manage videos recorded from game + Управление видеозаписями игры + + + Edit game preferences + Редактировать настройки игры + PageMultiplayer @@ -908,6 +1015,14 @@ OK ОК + + DLC + + + + Downloadable Content + + PageNetType @@ -919,6 +1034,14 @@ Official server Официальный сервер + + Join hundreds of players online! + Присоединиться к сотням игроков! + + + Join or host your own game server in a Local Area Network. + Присоединиться или создать собственный сервер в локальной сети. + PageOptions @@ -974,6 +1097,18 @@ Delete weapon set Удалить набор оружия + + General + Основные настройки + + + Advanced + Дополнительно + + + Reset to default colors + Сбросить на цвета по умолчанию + PagePlayDemo @@ -1039,38 +1174,38 @@ This game is in lobby. You may join and start playing once the game starts. - В этой комнате игра ещё не запущена. + В этой комнате игра ещё не запущена. Вы можете зайти и присоединиться к игре. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - В этой комнате происходит игра. + В этой комнате происходит игра. Вы можете зайти и наблюдать. Чтобы играть, придётся подождать окончания текущей игры. %1 is the host. He may adjust settings and start the game. - %1 управляет комнатой. Он может изменять настройки и запускать игру. + %1 управляет комнатой. Он может изменять настройки и запускать игру. Random Map - Случайная карта + Случайная карта Games may be played on precreated or randomized maps. - Можно играть на нарисованных или сгенерированных картах. + Можно играть на нарисованных или сгенерированных картах. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Схема игры определяет общие настройки, такие как время хода или вампиризм. + Схема игры определяет общие настройки, такие как время хода или вампиризм. The Weapon Scheme defines available weapons and their ammunition count. - Схема оружия определяет доступное оружие и число снарядов. + Схема оружия определяет доступное оружие и число снарядов. There are %1 clients connected to this room. - + Всего %1 игрок находится в этой комнате. Всего %1 игрока находятся в этой комнате. Всего %1 игроков находятся в этой комнате. @@ -1078,7 +1213,7 @@ There are %1 teams participating in this room. - + Всего %1 команда участвует в игре в этой комнате. Всего %1 команды участвуют в игре в этой комнате. Всего %1 команд участвуют в игре в этой комнате. @@ -1094,7 +1229,7 @@ Random Maze - Случайный лабиринт + Случайный лабиринт State: @@ -1263,7 +1398,7 @@ Add an indestructible border along the bottom - + Добавить неразрушимую границу внизу карты @@ -1289,11 +1424,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Быстрый старт (быстрый запуск игры против компьютера на случайной карте) + Быстрый старт (быстрый запуск игры против компьютера на случайной карте) Multiplayer (play a hotseat game against your friends, or AI teams) - Схватка (игра с друзьями за одним компьютером или против ботов) + Схватка (игра с друзьями за одним компьютером или против ботов) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1301,34 +1436,137 @@ Demos (Watch recorded demos) - Демки (просмотр записанных демок) + Демки (просмотр записанных демок) Load (Load a previously saved game) - Загрузить (загрузить сохранённую игру) + Загрузить (загрузить сохранённую игру) Campaign Mode (...). IN DEVELOPMENT Режим прохождения кампании. В РАЗРАБОТКЕ - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) - + Simple Game + Простая игра + + + Play a quick game against the computer with random settings + Играть против компьютера + + + Multiplayer + Схватка + + + Play a hotseat game against your friends, or AI teams + Играть с друзьями за одним компьютером или против ботов + + + Campaign Mode + Кампания + + + Training Mode + Тренировка + + + Practice your skills in a range of training missions + Тренировка мастерства в тренировочных миссиях + + + Demos + Демки + + + Watch recorded demos + Смотреть записанные демки + + + Load + Загрузить + + + Load a previously saved game + Загрузить сохранённую игру PageTraining No description available - + Описание отсутствует Select a mission! - + Выберите миссию! + + + Pick the mission or training to play + Выберите миссию или тренировку + + + Start fighting + Начать битву + + + + PageVideos + + Name + Название + + + Size + Размер + + + %1 bytes + + %1 байт + %1 байта + %1 байтов + + + + (in progress...) + (в игре...) + + + Date: + Дата: + + + Size: + Размер: + + + Are you sure? + Вы уверены? + + + Do you really want do remove %1? + Удалить %1? + + + Do you really want do remove %1 file(s)? + + Удалить %1 файл? + Удалить %1 файла? + Удалить %1 файлов? + + + + encoding + кодирование + + + uploading + отправка + + + Do you really want do cancel uploading %1? + Отменить отправку %1? @@ -1436,6 +1674,26 @@ Frontend effects Эффекты в меню + + Save password + Сохранить пароль + + + Save account name and password + Сохранить псевдоним и пароль + + + Video is private + Частное видео + + + Record audio + Запись звука + + + Use game resolution + Использовать разрешение игры + QComboBox @@ -1606,6 +1864,26 @@ Schemes and Weapons Схемы игры и наборы оружия + + Custom colors + Свои цвета + + + Miscellaneous + Разное + + + Video recording options + Настройки видео + + + Videos + Видео + + + Description + Описание + QLabel @@ -1619,7 +1897,7 @@ Net nick - Имя игрока + Имя игрока This program is distributed under the GNU General Public License @@ -1739,7 +2017,7 @@ Restart game to apply - Перезапустите игру для применения + Перезапустите игру для применения This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1805,7 +2083,7 @@ Password - Пароль + Пароль % Get Away Time @@ -1815,6 +2093,70 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + Сейчас происходит обработка видео. +Выход отменить обработку. +Всё равно выйти? + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + Пароль: + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + Описание + + + Nickname + Псевдоним + + + Format + + + + Audio codec + Видеокодек + + + Video codec + Аудиокодек + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1824,7 +2166,11 @@ hedgehog %1 - + ёжик %1 + + + anonymous + аноним @@ -1908,6 +2254,44 @@ Can not delete default weapon set '%1'! Не могу удлить встроенный набор оружия '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2006,11 +2390,70 @@ more ещё + + More info + + + + Set default options + Установить настройки по умолчанию + + + Open videos directory + Открыть папку с видеозаписями + + + Play + Проиграть + + + Upload to YouTube + Отправить на YouTube + + + Cancel uploading + Отменить отправку + QTableWidget Room Name + Название + + + C + И + + + T + К + + + Owner + Главный + + + Map + Карта + + + Rules + Правила + + + Weapons + Оружие + + + + RoomsListModel + + In progress + В игре + + + Room Name Название @@ -2037,6 +2480,18 @@ Weapons Оружие + + Random Map + Случайная карта + + + Random Maze + Случайный лабиринт + + + Hand-drawn + Рисованная карта + SelWeaponWidget @@ -2184,7 +2639,7 @@ Add Bottom Border - + Добавить нижнюю границу @@ -2351,6 +2806,14 @@ slot 10 слот 10 + + mute audio + отключить звук + + + record + записать + binds (categories) @@ -2437,6 +2900,10 @@ Toggle labels above hedgehogs: Переключение меток над ежами: + + Record video: + Запись видео: + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_sk.ts --- a/share/hedgewars/Data/Locale/hedgewars_sk.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_sk.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -74,6 +81,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -137,7 +151,7 @@ Kicking %1 ... - Vyhadzujem %1... + Vyhadzujem %1... @@ -194,7 +208,7 @@ Password - Heslo + Heslo Your nickname %1 is @@ -414,6 +428,32 @@ User quit Užívateľ odišiel + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Heslo + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -423,6 +463,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -510,6 +570,10 @@ All files Všetky súbory + + Eraser + + PageEditTeam @@ -621,14 +685,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Miestna hra (Hrať hru proti počítaču) + Miestna hra (Hrať hru proti počítaču) Network Game (Play a game across a network) - Sieťová hra (Hrať hru proti súperom na sieti) + Sieťová hra (Hrať hru proti súperom na sieti) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -914,6 +985,46 @@ Downloadable Content Stiahnuteľný obsah + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -951,6 +1062,14 @@ OK OK + + DLC + + + + Downloadable Content + Stiahnuteľný obsah + PageNetType @@ -962,6 +1081,14 @@ Official server Oficiálny server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -1017,6 +1144,18 @@ Delete weapon set Vymazať sadu zbraní + + General + Všeobecné + + + Advanced + Pokročilé + + + Reset to default colors + + PagePlayDemo @@ -1082,38 +1221,38 @@ This game is in lobby. You may join and start playing once the game starts. - Táto hra je v lobby. + Táto hra je v lobby. Môžete sa pridať a začať hru akonáhle hra skončí. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Táto hra práve prebieha. + Táto hra práve prebieha. Môžete sa pridať a sledovať hru, ale ak chcete hrať budete musieť počkať na koniec hry. %1 is the host. He may adjust settings and start the game. - %1 je hostiteľom. Može meniť nastavenia a spúšťať hru. + %1 je hostiteľom. Može meniť nastavenia a spúšťať hru. Random Map - Náhodná mapa + Náhodná mapa Games may be played on precreated or randomized maps. - Hry môžu byť hrané na predvytvorených alebo náhodných mapách. + Hry môžu byť hrané na predvytvorených alebo náhodných mapách. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Schéma hry určuje všeobecné voľby ako napríklad Dĺžka kola, Režim rýchlej smrti alebo Vampírizmus. + Schéma hry určuje všeobecné voľby ako napríklad Dĺžka kola, Režim rýchlej smrti alebo Vampírizmus. The Weapon Scheme defines available weapons and their ammunition count. - Schémy hry určuje dostupné zbrane a množstvo výzbroje. + Schémy hry určuje dostupné zbrane a množstvo výzbroje. There are %1 clients connected to this room. - + K tejto miestnosti je pripojený jeden klient. K tejto miestnosti sú pripojení %1 klienti. K tejto miestnosti je pripojených %1 klientov. @@ -1121,7 +1260,7 @@ There are %1 teams participating in this room. - + V tejto miestnosti je jeden hrajúci tím. V tejto miestnosti sú %1 hrajúce tímy. V tejto miestnosti je %1 hrajúcich tímov. @@ -1137,7 +1276,7 @@ Random Maze - Náhodné bludisko + Náhodné bludisko State: @@ -1332,11 +1471,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Jednoduchá hra (rýchla hra proti počítaču, s preddefinovanými nastaveniami) + Jednoduchá hra (rýchla hra proti počítaču, s preddefinovanými nastaveniami) Multiplayer (play a hotseat game against your friends, or AI teams) - Multiplayer (hrať hru, pri ktorej sa striedate s hráčmi pri počítači alebo proti počítačovým tímom) + Multiplayer (hrať hru, pri ktorej sa striedate s hráčmi pri počítači alebo proti počítačovým tímom) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1344,11 +1483,11 @@ Demos (Watch recorded demos) - Demá (prehrávanie natočených demonahrávok) + Demá (prehrávanie natočených demonahrávok) Load (Load a previously saved game) - Načítať (načíta v minulosti uloženú hru) + Načítať (načíta v minulosti uloženú hru) Campaign Mode (...). IN DEVELOPMENT @@ -1356,11 +1495,55 @@ Campaign Mode (...) - Režim kampane (...) + Režim kampane (...) Training Mode (Practice your skills in a range of training missions) - Tréningový režim (Vycvičte sa v rade tréningových misií) + Tréningový režim (Vycvičte sa v rade tréningových misií) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Načítať + + + Load a previously saved game + @@ -1373,6 +1556,73 @@ Select a mission! Vyberte misiu! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Meno + + + Size + + + + %1 bytes + + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1479,6 +1729,26 @@ Frontend effects Efekty vo frontende + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1681,6 +1951,26 @@ Schemes and Weapons Schémy a zbrane + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1734,7 +2024,7 @@ Net nick - Sieťový nick + Sieťový nick Server name: @@ -1814,7 +2104,7 @@ Restart game to apply - Vyžaduje reštart hry + Vyžaduje reštart hry This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1885,7 +2175,7 @@ Password - Heslo + Heslo % Get Away Time @@ -1895,6 +2185,68 @@ This program is distributed under the GNU General Public License v2 Tento program je distribuovaný pod licenciou GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Prezývka + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1906,6 +2258,10 @@ hedgehog %1 ježko %1 + + anonymous + + QMainWindow @@ -1988,6 +2344,44 @@ Can not delete default weapon set '%1'! Nie je možné vymazať východziu sadu zbraní '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2090,36 +2484,107 @@ more viac + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Názov miestnosti + Názov miestnosti C - C + C T - T + T Owner - Majiteľ + Majiteľ Map - Mapa + Mapa Rules - Pravidlá + Pravidlá Weapons - Zbrane + Zbrane + + + + RoomsListModel + + In progress + Prebieha + + + Room Name + Názov miestnosti + + + C + C + + + T + T + + + Owner + Majiteľ + + + Map + Mapa + + + Rules + Pravidlá + + + Weapons + + + + Random Map + Náhodná mapa + + + Random Maze + Náhodné bludisko + + + Hand-drawn + @@ -2435,6 +2900,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2521,6 +2994,10 @@ Toggle labels above hedgehogs: Prepnúť nápisy nad ježkami: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_sv.ts --- a/share/hedgewars/Data/Locale/hedgewars_sv.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_sv.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -69,6 +76,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -130,10 +144,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -189,7 +199,7 @@ Password - Lösenord + Lösenord Your nickname %1 is @@ -405,6 +415,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Lösenord + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -414,6 +450,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -501,6 +557,10 @@ All files Alla filer + + Eraser + + PageEditTeam @@ -604,14 +664,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Lokalt spel (Spela en omgång på en enskild dator) + Lokalt spel (Spela en omgång på en enskild dator) Network Game (Play a game across a network) - Nätverkspel (Spela en omgång över ett nätverk) + Nätverkspel (Spela en omgång över ett nätverk) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -887,6 +954,46 @@ Downloadable Content Nedladdningsbart innehåll + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -924,6 +1031,14 @@ OK OK + + DLC + + + + Downloadable Content + Nedladdningsbart innehåll + PageNetType @@ -935,6 +1050,14 @@ Official server Officiell server + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -990,6 +1113,18 @@ Delete weapon set Ta bort vapenset + + General + Allmänt + + + Advanced + Avancerat + + + Reset to default colors + + PagePlayDemo @@ -1055,45 +1190,45 @@ This game is in lobby. You may join and start playing once the game starts. - Detta spel är i lobby. + Detta spel är i lobby. Du kan gå med och börja spela när spelet börjar. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Detta spel pågår. + Detta spel pågår. Du kan gå med och se på men du måste vänta tills spelet är slut för att kunna börja spela. %1 is the host. He may adjust settings and start the game. - %1 är ägaren. Han kan ändra inställningar och starta spelet. + %1 är ägaren. Han kan ändra inställningar och starta spelet. Random Map - Slumpad karta + Slumpad karta Games may be played on precreated or randomized maps. - Spel kan spelas på färdiga eller slumpade kartor. + Spel kan spelas på färdiga eller slumpade kartor. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Spelschemat anger allmäna inställningar som tid per person, Sudden Death eller Vampyrism. + Spelschemat anger allmäna inställningar som tid per person, Sudden Death eller Vampyrism. The Weapon Scheme defines available weapons and their ammunition count. - Vapenschemat anger tillgängliga vapen och deras ammunitionsantal. + Vapenschemat anger tillgängliga vapen och deras ammunitionsantal. There are %1 clients connected to this room. - + Det är %1 klient uppkopplad till detta rum. Det är %1 klienter uppkopplade till detta rum. There are %1 teams participating in this room. - + Det är %1 deltagande lag i detta rum. Det är %1 deltagande lag i detta rum. @@ -1108,7 +1243,7 @@ Random Maze - Slumpad labyrint + Slumpad labyrint State: @@ -1302,11 +1437,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Enkelt spel (en snabbomgång mot datorn, inställningar väljs åt dig) + Enkelt spel (en snabbomgång mot datorn, inställningar väljs åt dig) Multiplayer (play a hotseat game against your friends, or AI teams) - Flera spelare (spela en hotseat-omgång mot dina vänner eller AI-lag) + Flera spelare (spela en hotseat-omgång mot dina vänner eller AI-lag) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1314,22 +1449,58 @@ Demos (Watch recorded demos) - Demos (se inspelade demos) + Demos (se inspelade demos) Load (Load a previously saved game) - Ladda (ladda ett tidigare sparat spel) + Ladda (ladda ett tidigare sparat spel) Campaign Mode (...). IN DEVELOPMENT Kampanjläge (...). UNDER UTVECKLING - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Läs in + + + Load a previously saved game @@ -1343,6 +1514,71 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Namn + + + Size + + + + %1 bytes + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1449,6 +1685,26 @@ Frontend effects Effekter i spelmenyn + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1651,6 +1907,26 @@ Schemes and Weapons Scheman och vapen + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1696,7 +1972,7 @@ Net nick - Internetnamn + Internetnamn Server name: @@ -1784,7 +2060,7 @@ Restart game to apply - Starta om spelet för att verkställa + Starta om spelet för att verkställa This SVN build is 'work in progress' and may not be compatible with other versions of the game. @@ -1850,7 +2126,7 @@ Password - Lösenord + Lösenord % Get Away Time @@ -1860,6 +2136,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + Smeknamn + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1871,6 +2209,10 @@ hedgehog %1 igelkott %1 + + anonymous + + QMainWindow @@ -1953,6 +2295,44 @@ Can not delete default weapon set '%1'! Kan inte ta bort standardvapenset '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -2055,36 +2435,107 @@ more mer + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Rumnamn + Rumnamn C - A + A T - L + L Owner - Ägare + Ägare Map - Karta + Karta Rules - Regler + Regler Weapons - Vapen + Vapen + + + + RoomsListModel + + In progress + Pågår + + + Room Name + Rumnamn + + + C + A + + + T + L + + + Owner + Ägare + + + Map + Karta + + + Rules + Regler + + + Weapons + Vapen + + + Random Map + Slumpad karta + + + Random Maze + Slumpad labyrint + + + Hand-drawn + @@ -2399,6 +2850,14 @@ slot 10 fack 10 + + mute audio + + + + record + + binds (categories) @@ -2485,6 +2944,10 @@ Toggle labels above hedgehogs: Visa etiketter över igelkottar: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_tr_TR.ts --- a/share/hedgewars/Data/Locale/hedgewars_tr_TR.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_tr_TR.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -68,6 +75,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 has been removed from your ignore list @@ -113,10 +127,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -172,7 +182,7 @@ Password - Parola + Parola Your nickname %1 is @@ -348,6 +358,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Parola + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -357,6 +393,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -440,6 +496,10 @@ All files + + Eraser + + PageEditTeam @@ -519,14 +579,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Yerel Oyun (Tek bilgisayarda oyna) + Yerel Oyun (Tek bilgisayarda oyna) Network Game (Play a game across a network) - Ağ Oyunu (Bir bilgisayar ağı üzerinde oyna) + Ağ Oyunu (Bir bilgisayar ağı üzerinde oyna) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -777,6 +844,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -814,6 +921,14 @@ OK Tamam + + DLC + + + + Downloadable Content + + PageNetType @@ -825,6 +940,14 @@ Official server Resmi sunucu + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -868,6 +991,18 @@ Delete weapon set + + General + Genel + + + Advanced + Gelişmiş + + + Reset to default colors + + PagePlayDemo @@ -931,48 +1066,6 @@ - This game is in lobby. -You may join and start playing once the game starts. - - - - This game is in progress. -You may join and spectate now but you'll have to wait for the game to end to start playing. - - - - %1 is the host. He may adjust settings and start the game. - - - - Random Map - - - - Games may be played on precreated or randomized maps. - - - - The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - - - - The Weapon Scheme defines available weapons and their ammunition count. - - - - There are %1 clients connected to this room. - - - - - - There are %1 teams participating in this room. - - - - - Please enter room name Lütfen oda ismini girin @@ -981,10 +1074,6 @@ Lütfen listeden bir oda seçin - Random Maze - - - Rules: @@ -1170,11 +1259,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Basit Oyun (bilgisayara karşı oynayın, ayarlar sizin yerinize seçilir) + Basit Oyun (bilgisayara karşı oynayın, ayarlar sizin yerinize seçilir) Multiplayer (play a hotseat game against your friends, or AI teams) - Çok oyunculu (arkadaşlarınızın veya bilgisayarın takımlarına karşı oynayın) + Çok oyunculu (arkadaşlarınızın veya bilgisayarın takımlarına karşı oynayın) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1182,18 +1271,54 @@ Demos (Watch recorded demos) - Kayıtlı Oyunlar (Kaydedilmiş oyunları izleyin) + Kayıtlı Oyunlar (Kaydedilmiş oyunları izleyin) Load (Load a previously saved game) - Yükle (Kaydedilmiş bir oyunu yükleyin) - - - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) + Yükle (Kaydedilmiş bir oyunu yükleyin) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Yükle + + + Load a previously saved game @@ -1207,6 +1332,69 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + + + + Size + + + + %1 bytes + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1309,6 +1497,26 @@ Frontend effects + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1479,6 +1687,26 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1532,7 +1760,7 @@ Net nick - Takma ad + Takma ad Resolution @@ -1611,10 +1839,6 @@ - Restart game to apply - - - Explosives @@ -1664,7 +1888,7 @@ Password - Parola + Parola % Get Away Time @@ -1674,6 +1898,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1685,6 +1971,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1767,6 +2057,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1865,10 +2193,49 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget + Map + Harita + + + Weapons + Silahlar + + + + RoomsListModel + + In progress + + + Room Name @@ -1896,6 +2263,18 @@ Weapons Silahlar + + Random Map + + + + Random Maze + + + + Hand-drawn + + SelWeaponWidget @@ -2210,6 +2589,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2296,6 +2683,10 @@ Toggle labels above hedgehogs: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_uk.ts --- a/share/hedgewars/Data/Locale/hedgewars_uk.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_uk.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -70,6 +77,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 *** %2 has been removed from your ignore list @@ -131,10 +145,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -190,7 +200,7 @@ Password - Пароль + Пароль Your nickname %1 is @@ -406,6 +416,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + Пароль + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -415,6 +451,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -502,6 +558,10 @@ All files + + Eraser + + PageEditTeam @@ -609,14 +669,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - Локальна Гра (Грати на одному комп'ютері) + Локальна Гра (Грати на одному комп'ютері) Network Game (Play a game across a network) - Мережна Гра (Грати по мережі) + Мережна Гра (Грати по мережі) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -867,6 +934,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -904,6 +1011,14 @@ OK Так + + DLC + + + + Downloadable Content + + PageNetType @@ -915,6 +1030,14 @@ Official server Офіційний сервер + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -970,6 +1093,18 @@ Delete weapon set Видалити набір зброї + + General + Основні + + + Advanced + Розширені + + + Reset to default colors + + PagePlayDemo @@ -1035,38 +1170,38 @@ This game is in lobby. You may join and start playing once the game starts. - Ця гра скоро почнеться. + Ця гра скоро почнеться. Ви можете приєднатися і почати грати після старту. This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - Ця гра вже триває. + Ця гра вже триває. Ви можете приєднатись та спостерігати, але повинні дочекатись поки гра закінчиться, і лише тоді зможете грати. %1 is the host. He may adjust settings and start the game. - %1 - це хост. Він може змінювати налаштування і починати гру. + %1 - це хост. Він може змінювати налаштування і починати гру. Random Map - Випадкова Мапа + Випадкова Мапа Games may be played on precreated or randomized maps. - Грати можна на обраних або випадкових мапах. + Грати можна на обраних або випадкових мапах. The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - Схема Гри визначає загальні налаштування(час гри, час до смерті, вампіризм...) + Схема Гри визначає загальні налаштування(час гри, час до смерті, вампіризм...) The Weapon Scheme defines available weapons and their ammunition count. - Схема зброї визначає наявну зброю та боєприпаси. + Схема зброї визначає наявну зброю та боєприпаси. There are %1 clients connected to this room. - + До кімнати приєднаний %1 клієнт. До кімнати приєднані %1 клієнти. До кімнати приєднані %1 клієнтів. @@ -1074,7 +1209,7 @@ There are %1 teams participating in this room. - + В кімнаті знаходиться %1 команда. В кімнаті знаходяться %1 команди. В кімнаті знаходяться %1 команд. @@ -1090,7 +1225,7 @@ Random Maze - Випадковий лабіринт + Випадковий лабіринт State: @@ -1285,11 +1420,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - Проста Гра (швидка гра проти комп'ютера, налаштування вибираються за вас) + Проста Гра (швидка гра проти комп'ютера, налаштування вибираються за вас) Multiplayer (play a hotseat game against your friends, or AI teams) - Мультиплеєр (гра проти ваших друзів, або проти AI команд) + Мультиплеєр (гра проти ваших друзів, або проти AI команд) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1297,22 +1432,58 @@ Demos (Watch recorded demos) - Демки (дивитись записані демо-відео) + Демки (дивитись записані демо-відео) Load (Load a previously saved game) - Завантаження (Завантажити попередньо збережені ігри) + Завантаження (Завантажити попередньо збережені ігри) Campaign Mode (...). IN DEVELOPMENT Режим Кампанії (...). В РОЗРОБЦІ - Campaign Mode (...) + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode - Training Mode (Practice your skills in a range of training missions) + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + Завантажити + + + Load a previously saved game @@ -1326,6 +1497,73 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + Назва + + + Size + + + + %1 bytes + + + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1432,6 +1670,26 @@ Frontend effects Ефекти меню + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1602,6 +1860,26 @@ Schemes and Weapons Схеми та Зброя + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel @@ -1655,7 +1933,7 @@ Net nick - Ім'я гравця + Ім'я гравця Resolution @@ -1735,7 +2013,7 @@ Restart game to apply - Перезапустіть гру щоб застосувати + Перезапустіть гру щоб застосувати Explosives @@ -1791,7 +2069,7 @@ Password - Пароль + Пароль % Get Away Time @@ -1801,6 +2079,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1812,6 +2152,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1894,6 +2238,44 @@ Can not delete default weapon set '%1'! Не можу видалити стандартний набір зброї '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1992,36 +2374,107 @@ more більше + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name - Назва Кімнати + Назва Кімнати C - Кл + Кл T - Км + Км Owner - Власник + Власник Map - Мапа + Мапа Rules - Правила + Правила Weapons - Зброя + Зброя + + + + RoomsListModel + + In progress + В процесі + + + Room Name + Назва Кімнати + + + C + Кл + + + T + Км + + + Owner + Власник + + + Map + Мапа + + + Rules + Правила + + + Weapons + Зброя + + + Random Map + Випадкова Мапа + + + Random Maze + Випадковий лабіринт + + + Hand-drawn + @@ -2337,6 +2790,14 @@ slot 10 слот 10 + + mute audio + + + + record + + binds (categories) @@ -2423,6 +2884,10 @@ Toggle labels above hedgehogs: Перемикання надписів над їжаками: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_zh_CN.ts --- a/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,14 +2,54 @@ + AbstractPage + + + Go back + + + + + AmmoSchemeModel + + + new + + + + + copy of + + + + + DrawMapWidget + + + + File error + + + + + Cannot open file '%1' for writing + + + + + Cannot read file '%1' + + + + FreqSpinBox - + Never 从不 - + Every %1 turn 每隔 %1 回合 @@ -19,17 +59,32 @@ GameCFGWidget - + + Game Options + + + + + Edit weapons + + + + + When this option is enabled selecting a game scheme will auto-select a weapon + + + + Error 错误 - + Illegal ammo scheme 无法使用此弹药设置 - + Edit schemes 修改游戏设置 @@ -37,156 +92,325 @@ GameUIConfig - Error 错误 - Cannot create directory %1 不能创建路径 - Quit 退出 - Cannot save options to file %1 不能把选项保存到 %1 + HWAskQuitDialog + + + Do yot really want to quit? + + + + + HWChatWidget + + + %1 has been removed from your ignore list + + + + + %1 has been added to your ignore list + + + + + %1 has been removed from your friends list + + + + + %1 has been added to your friends list + + + + + Stylesheet imported from %1 + + + + + Enter %1 if you want to use the current StyleSheet in future, enter %2 to reset! + + + + + Couldn't read %1 + + + + + StyleSheet discarded + + + + + StyleSheet saved to %1 + + + + + Failed to save StyleSheet to %1 + + + + + %1 is not a valid command! + + + + HWForm - + + + DefaultTeam + + + + + Game aborted + + + + + Error 错误 - + + Please select record from the list above + + + + + Your nickname %1 is +registered on Hedgewars.org +Please provide your password below +or pick another nickname in game config: + + + + + No password supplied. + + + + + Nickname + + + + + Some one already uses + your nickname %1 +on the server. +Please pick another nickname: + + + + + No nickname supplied. + + + + + Hedgewars Demo File + File Types + + + + + Hedgewars Save File + File Types + + + + + Demo name + + + + + Demo name: + + + Please, select demo from the list above 请选择一个DEMO - + OK 确认 - Please, select server from the list above 请选择一个服务器 - Please, select record from the list above - 请选择一个记录 - - - + 请选择一个记录 + + + + Cannot save record to file %1 无法录入文件 %1 - + Unable to start the server 开启服务端出现错误 - new - + HWGame - Error 错误 - Unable to start the server: %1. 开启服务端出现错误: %1. - + + en.txt zh_CN.txt - Cannot save demo to file %1 不能把demo保存为 %1 - Quit 退出 - + Cannot open demofile %1 DEMO %1 打不开 - Unable to run engine: %1 ( 引擎无法启动: %1 ( - Error reading training config file - 训练设置文件无法读取 + 训练设置文件无法读取 HWMapContainer - + Map 地图 - + + Type + + + + + Small tunnels + + + + + Medium tunnels + + + + + Large tunnels + + + + + Small floating islands + + + + + Medium floating islands + + + + + Large floating islands + + + + Themes 主题 - + + Seed + + + + + Set + + + + Filter 过滤 - + All 全部 - + Small 小型 - + Medium 中型 - + Large 大型 - + Cavern 洞穴 - + Wacky 曲折 @@ -194,17 +418,14 @@ HWNet - Error 错误 - The host was not found. Please check the host name and port settings. 未发现主机。请检查主机名和端口设置。 - Connection refused 连接被拒绝 @@ -212,12 +433,10 @@ HWNetServer - Error 错误 - Unable to start the server: %1. 无法启动服务端: %1. @@ -225,17 +444,17 @@ HWNetServersModel - + Title 标题 - + IP IP - + Port 端口 @@ -243,109 +462,267 @@ HWNewNet - Error 错误 - + + User quit + + + + + Remote host has closed connection + + + + The host was not found. Please check the host name and port settings. 错误没找到这个主机。请检查主机名和端口设置。 - + Connection refused 连接被拒绝 - + + The server is too old. Disconnecting now. + + + + + %1 *** %2 has joined + + + + + + %1 *** %2 has left + + + + + + %1 *** %2 has left (%3) + + + + + + %1 *** %2 has joined the room + + + *** %1 joined - *** %1 加入 - - - + *** %1 加入 + + *** %1 left - *** %1 离开 - - - + *** %1 离开 + + *** %1 left (%2) - *** %1 离开 (%2) - - - + *** %1 离开 (%2) + + + Quit reason: 退出原因: - + Room destroyed 房间损坏 - + You got kicked 被踢出 - + Password + 密码 + + + Enter your password: + 输入你的密码: + + + + HWPasswordDialog + + Password - 密码 - - - - Enter your password: - 输入你的密码: + 密码 + + + + HWUploadVideoDialog + + + Upload video + + + + + Upload + KB - + SDL_ttf returned error while rendering text, most propably it is related to the bug in freetype2. It's recommended to update your freetype lib. SDL_ttf 返回错误-渲染文字失败,可能有关freetype2的bug。建议升级 freetype。 + LibavIteraction + + + Duration: %1m %2s + + + + + + Video: %1x%2, + + + + + %1 fps, + + + + + Audio: + + + + PageAdmin - Server message: - 服务器信息: - - - + 服务器信息: + + Set message - 设定信息 + 设定信息 + + + + Fetch data + + + + + Server message for latest version: + + + + + Server message for previous versions: + + + + + Latest version protocol number: + + + + + MOTD preview: + + + + + Clear Accounts Cache + + + + + Set data + PageConnecting - + Connecting... 连接中... + PageDrawMap + + + Eraser + + + + + Undo + + + + + Clear + + + + + Load + 读取 + + + + Save + 保存 + + + + Load drawn map + + + + + + Drawn Maps + + + + + + All files + + + + + Save drawn map + + + + PageEditTeam - Discard 中止 - Save 保存 - + General 常规 - + Advanced 进阶 @@ -353,87 +730,500 @@ PageGameStats - <p>The best shot award was won by <b>%1</b> with <b>%2</b> pts.</p> - <p>最佳射手是<b>%1</b>。伤害 <b>%2</b>点。</p> + <p>最佳射手是<b>%1</b>。伤害 <b>%2</b>点。</p> - <p>The best killer is <b>%1</b> with <b>%2</b> kills in a turn.</p> - + <p>最佳杀手<b>%1</b>:却敌<b>%2</b></p> - <p>A total of <b>%1</b> hedgehog(s) were killed during this round.</p> - + <p>有<b>%1</b>个刺猬在此局失去生命。</p> + + + Details + + + + + Health graph + + + + + Ranking + + + + + The best shot award was won by <b>%1</b> with <b>%2</b> pts. + + + + + The best killer is <b>%1</b> with <b>%2</b> kills in a turn. + + + + + + + A total of <b>%1</b> hedgehog(s) were killed during this round. + + + + + + + (%1 kill) + + + + + + + <b>%1</b> thought it's good to shoot his own hedgehogs with <b>%2</b> pts. + + + + + + + <b>%1</b> killed <b>%2</b> of his own hedgehogs. + + + + + + + <b>%1</b> was scared and skipped turn <b>%2</b> times. + + + + + + + PageInGame + + + In game... + + + + + PageInfo + + + Open the snapshot folder + + PageMain - Multiplayer 多人游戏 - Single Player 单人游戏 - Net game 网络游戏 - Saved games 存档 - Demos Demo - Setup 设置 - About 关于 - Exit 退出 - Local Game (Play a game on a single computer) - 本地游戏(在一台电脑上) - - - + 本地游戏(在一台电脑上) + + Network Game (Play a game across a network) - 网络游戏(通过网络) + 网络游戏(通过网络) + + + + Local Game + + + + + Play a game on a single computer + + + + + Network Game + + + + + Play a game across a network + + + + + Read about who is behind the Hedgewars Project + + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + + Downloadable Content + + + + + Access the user created content downloadable from our website + + + + + Exit game + + + + + Manage videos recorded from game + + + + + Edit game preferences + + + + + Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. + Tips + + + + + Some weapons might do only low damage but they can be a lot more devastating in the right situation. Try to use the Desert Eagle to knock multiple hedgehogs into the water. + Tips + + + + + If you're unsure what to do and don't want to waste ammo, skip one round. But don't let too much time pass as there will be Sudden Death! + Tips + + + + + Want to save ropes? Release the rope in mid air and then shoot again. As long as you don't touch the ground you'll reuse your rope without wasting ammo! + Tips + + + + + If you'd like to keep others from using your preferred nickname on the official server, register an account at http://www.hedgewars.org/. + Tips + + + + + You're bored of default gameplay? Try one of the missions - they'll offer different gameplay depending on the one you picked. + Tips + + + + + By default the game will always record the last game played as a demo. Select 'Local Game' and pick the 'Demos' button on the lower right corner to play or manage them. + Tips + + + + + Hedgewars is Open Source and Freeware we create in our spare time. If you've got problems, ask on our forums but please don't expect 24/7 support! + Tips + + + + + Hedgewars is Open Source and Freeware we create in our spare time. If you like it, help us with a small donation or contribute your own work! + Tips + + + + + Hedgewars is Open Source and Freeware we create in our spare time. Share it with your family and friends as you like! + Tips + + + + + Hedgewars is Open Source and Freeware we create in our spare time. If someone sold you the game, you should try get a refund! + Tips + + + + + From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance. + Tips + + + + + Hedgewars is available in many languages. If the translation in your language seems to be missing or outdated, feel free to contact us! + Tips + + + + + Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux. + Tips + + + + + Always remember you're able to set up your own games in local and network/online play. You're not restricted to the 'Simple Game' option. + Tips + + + + + Connect one or more gamepads before starting the game to be able to assign their controls to your teams. + Tips + + + + + Create an account on %1 to keep others from using your most favourite nickname while playing on the official server. + Tips + + + + + While playing you should give yourself a short break at least once an hour. + Tips + + + + + If your graphics card isn't able to provide hardware accelerated OpenGL, try to enable the low quality mode to improve performance. + Tips + + + + + If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers. + Tips + + + + + We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know! + Tips + + + + + Especially while playing online be polite and always remember there might be some minors playing with or against you as well! + Tips + + + + + Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game! + Tips + + + + + The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing. + Tips + + + + + You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead! + Tips + + + + + Hedgewars can be perfect for short games during breaks. Just ensure you don't add too many hedgehogs or use an huge map. Reducing time and health might help as well. + Tips + + + + + No hedgehogs were harmed in making this game. + Tips + + + + + There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump. + Tips + + + + + Afraid of falling off a cliff? Hold down [precise] to turn [left] or [right] without actually moving. + Tips + + + + + Some weapons require special strategies or just lots of training, so don't give up on a particular tool if you miss an enemy once. + Tips + + + + + Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this. + Tips + + + + + The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once. + Tips + + + + + The Piano Strike is the most damaging air strike. You'll lose the hedgehog performing it, so there's a huge downside as well. + Tips + + + + + The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power. + Tips + + + + + Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water. + Tips + + + + + The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground. + Tips + + + + + If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion. + Tips + + + + + The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early. + Tips + + + + + The Flame Thrower is a weapon but it can be used for tunnel digging as well. + Tips + + + + + Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms. + Tips + + + + + Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits. + Tips + + + + + Like Hedgewars? Become a fan on %1 or follow us on %2! + Tips + + + + + Feel free to draw your own graves, hats, flags or even maps and themes! But note that you'll have to share them somewhere to use them online. + Tips + + + + + Really want to wear a specific hat? Donate to us and receive an exclusive hat of your choice! + Tips + + + + + Keep your video card drivers up to date to avoid issues playing the game. + Tips + + + + + You're able to associate Hedgewars related files (savegames and demo recordings) with the game to launch them right from your favorite file or internet browser. + Tips + + + + + You can find your Hedgewars configuration files under "My Documents\Hedgewars". Create backups or take the files with you, but don't edit them by hand. + Tips + + + + + You can find your Hedgewars configuration files under "Library/Application Support/Hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand. + Tips + + + + + You can find your Hedgewars configuration files under ".hedgewars" in your home directory. Create backups or take the files with you, but don't edit them by hand. + Tips + PageMultiplayer - Back 返回 - + Start 开始 @@ -441,114 +1231,211 @@ PageNet - Local 本地 - Internet Internet - + Error 错误 - + + Please select server from the list above + + + Please, select server from the list above - 请选择一个服务器 + 请选择一个服务器 PageNetGame - + + DLC + + + + + Downloadable Content + + + + Control Ctrl + + + Error + 错误 + + + + Please enter room name + + + + + OK + + PageNetType - + LAN game 局域网游戏 - + + Join or host your own game server in a Local Area Network. + + + + Official server 官方服务器 + + + Join hundreds of players online! + + PageOptions - + + General + 常规 + + + + Advanced + 进阶 + + + New team 新队伍 - + Edit team 修改队伍设定 - + + Delete team + + + + + You can't edit teams from team selection. Go back to main menu to add, edit or delete teams. + + + + + New scheme + + + + + Edit scheme + + + + + Delete scheme + + + + + New weapon set + + + + + Edit weapon set + + + + + Delete weapon set + + + + + Reset to default colors + + + Save 保存 - Back 返回 - Weapons set - 新武器设定 - - - + 新武器设定 + + Edit - 修改当前武器设定 + 修改当前武器设定 PagePlayDemo - + + + + Error 错误 - Please, select record from the list - 请从列表选择记录 - - - + 请从列表选择记录 + + + + + Please select record from the list + + + + + OK 确认 - + Rename dialog 重命名对话框 - + Enter new file name: 输入新的文件名: - + Cannot rename to 不能改变名字 - + Cannot delete file 不能删除文件 @@ -556,42 +1443,95 @@ PageRoomsList - + + Room Name: + + + + + Rules: + + + + + Weapons: + + + + + Search: + + + + Create 建立 - + Join 加入 - + Refresh 刷新 - + + Clear + + + + + Error 错误 - + + Please enter room name + + + + + Please select room from the list + + + + + Warning + + + + + The game you are trying to join has started. +Do you still want to join the room? + + + + + %1 players online + + + + + Please, enter room name - 请键入房间名 - - - + 请键入房间名 + + + + OK 确认 - Please, select room from the list - 请从列表选中房间 - - - + 请从列表选中房间 + + + Admin features 管理员功能 @@ -599,12 +1539,152 @@ PageScheme - + + Defend your fort and destroy the opponents, two team colours max! + + + + + Teams will start on opposite sides of the terrain, two team colours max! + + + + + Land can not be destroyed! + + + + + Add an indestructible border around the terrain + + + + + Lower gravity + + + + + Assisted aiming with laser sight + + + + + All hogs have a personal forcefield + + + + + All (living) hedgehogs are fully restored at the end of turn + + + + + Gain 80% of the damage you do back in health + + + + + Share your opponents pain, share their damage + + + + + Your hogs are unable to move, put your artillery skills to the test + + + + + Order of play is random instead of in room order. + + + + + Play with a King. If he dies, your side dies. + + + + + Take turns placing your hedgehogs before the start of play. + + + + + Ammo is shared between all teams that share a colour. + + + + + Disable girders when generating random maps. + + + + + Disable land objects when generating random maps. + + + + + AI respawns on death. + + + + + Attacking does not end your turn. + + + + + Weapons are reset to starting values each turn. + + + + + Each hedgehog has its own ammo. It does not share with the team. + + + + + You will not have to worry about wind anymore. + + + + + Wind will affect almost everything. + + + + + Teams in each clan take successive turns sharing their turn time. + + + + + Add an indestructible border along the bottom + + + + + Random + + + + + Seconds + + + + + Copy + + + + New 新游戏 - + Delete 删除 @@ -612,22 +1692,30 @@ PageSelectWeapon - Back 返回 - + + New + 新游戏 + + + Default 默认 - + + Copy + + + + Delete 删除 - Save 保存 @@ -635,12 +1723,10 @@ PageSimpleGame - Back 返回 - Simple Game 简单游戏 @@ -648,518 +1734,1053 @@ PageSinglePlayer - + Simple Game - 简单游戏 - - - + 简单游戏 + + + + Play a quick game against the computer with random settings + + + + + Play a hotseat game against your friends, or AI teams + + + + + + Campaign Mode + + + + + Training Mode + + + + + Practice your skills in a range of training missions + + + + + Watch recorded demos + + + + + Load + 读取 + + + + Load a previously saved game + + + Training 训练 - + Multiplayer - 多人游戏 - - - + 多人游戏 + + Saved games 游戏存档 - + Demos - Demo - - - + Demo + + Simple Game (a quick game against the computer, settings are chosen for you) - 快速游戏 (对抗电脑,固定设置) - - - + 快速游戏 (对抗电脑,固定设置) + + Multiplayer (play a hotseat game against your friends, or AI teams) - 多人游戏 (热坐对抗朋友或AI) - - - + 多人游戏 (热坐对抗朋友或AI) + + Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT - 训练模式 (一系列训练任务)。开发中 - - - + 训练模式 (一系列训练任务)。开发中 + + Demos (Watch recorded demos) - Demo (观看记录的Demo) - - - + Demo (观看记录的Demo) + + Load (Load a previously saved game) - 读取 (读取之前保存的游戏) + 读取 (读取之前保存的游戏) + + + + PageTraining + + + Pick the mission or training to play + + + + + Start fighting + + + + + No description available + + + + + Select a mission! + + + + + PageVideos + + + Name + + + + + Size + + + + + %1 bytes + + + + + + + (in progress...) + + + + + Date: + + + + + Size: + + + + + + + Are you sure? + + + + + Do you really want do remove %1? + + + + + Do you really want do remove %1 file(s)? + + + + + + + encoding + + + + + uploading + + + + + Do you really want do cancel uploading %1? + QAction - + Kick - + + Update + 更新 + + + Start 开始 - + Restrict Joins 限制参与 - + Restrict Team Additions 限制团队插件 - + Info 信息 - + Ban 屏蔽 + + + Follow + + + + + + Ignore + + + + + + Add friend + + + + + Unignore + + + + + Remove friend + + QCheckBox - + Enable sound 开启音效 - + Fullscreen 游戏全屏幕 - Forts mode 城堡模式 - + Show FPS 显示帧率 (FPS) - + Alternative damage show 另一种伤害显示方式 - + + Check for updates at startup + + + + + Frontend effects + + + + + Enable frontend sounds + + + + + Enable frontend music + + + + Enable music 开启音乐 - + + Show ammo menu tooltips + + + + Frontend fullscreen 界面全屏幕 - Divide teams 分组 - + Append date and time to record file name 记录名称中包含具体时间日期 - Solid land 固实地面 - Reduce Quality - 降低质量 + 降低质量 + + + + + Save password + + + + + Save account name and password + + + + + Video is private + + + + + Record audio + + + + + Use game resolution + QComboBox - + generated map... 生成地图... - + + generated maze... + + + + + hand drawn map... + + + + + Mission + + + + Human 玩家 - + + Community + + + Level 5 Lv 5 - Level 4 Lv 4 - Level 3 Lv 3 - Level 2 Lv 2 - Level 1 Lv 1 - + Level Lv 级别 + + + (System default) + + + + + Disabled + + + + + Red/Cyan + + + + + Cyan/Red + + + + + Red/Blue + + + + + Blue/Red + + + + + Red/Green + + + + + Green/Red + + + + + Side-by-side + + + + + Top-Bottom + + + + + Wiggle + + + + + Red/Cyan grayscale + + + + + Cyan/Red grayscale + + + + + Red/Blue grayscale + + + + + Blue/Red grayscale + + + + + Red/Green grayscale + + + + + Green/Red grayscale + + + + + + + Any + + + + + In lobby + + + + + In progress + + QGroupBox - + Team Members 成员 - Team - 队伍 - - - + 队伍 + + + + Team Settings + + + + Fort 城堡模式 - + Key binds 键位绑定 - + Teams 队伍 - + + Schemes and Weapons + + + + + Misc + + + + Audio/Graphic options 音频/视频选项 - + + Custom colors + + + + + Miscellaneous + + + Net nick 昵称 - Net options 网络选项 - Landscape 地形 - Game scheme 游戏设置 - + Playing teams 玩家队伍 - Team level 队伍级别 - + Net game 网络游戏 - Servers list 服务器列表 - Weapons - 武器 - - - + 武器 + + Scheme options 游戏设定 - + Game Modifiers 游戏修改 - + Basic Settings 基本设置 + + + Video recording options + + + + + Videos + + + + + Description + + QLabel - Net nick - 网络游戏昵称 - - - + 网络游戏昵称 + + Server address 服务器地址 - <div align="center"><h1>Hedgewars</h1><h3>Version 0.8</h3><p><a href="http://www.hedgewars.org/">http://www.hedgewars.org/</a></p><br>This program is distributed under the GNU General Public License</div> <div align="center"><h1>刺猬大作战</h1><h3>0.8</h3><p><a href="http://www.hedgewars.org/">http://www.hedgewars.org/</a></p><br>This program is distributed under the GNU General Public License</div> - <h2>Developers:</h2><p>Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>Igor Ulyanov &lt;<a href="mailto:iulyanov@gmail.com">iulyanov@gmail.com</a>&gt;</p><h2>Translations:</h2>english: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>russian: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt; <h2>Developers:</h2><p>Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>Igor Ulyanov &lt;<a href="mailto:iulyanov@gmail.com">iulyanov@gmail.com</a>&gt;</p><h2>Translations:</h2>english: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt;<br>russian: Andrey Korotaev &lt;<a href="mailto:unC0Rr@gmail.com">unC0Rr@gmail.com</a>&gt; - difficulty: 难度: - <h3>Version 0.8</h3> <h3>版本 0.8</h3> - This program is distributed under the GNU General Public License - This program is distributed under the GNU General Public License - - - + This program is distributed under the GNU General Public License + + <h2>Translations:</h2> <h2>翻译:</h2> - <h2>Developers:</h2> <h2>开发者:</h2> - <h2>Translations:</h2><p> <h2>翻译:</h2><p> - <h2>Special thanks:</h2><p> <h2>特别感谢:</h2><p> - <h3>Version 0.8.1</h3> <h3>版本 0.8.1</h3> - <h2></h2><p></p> <h2></h2><p></p> - Turn time 回合时间 - Initial health 初始生命值 - <p>The best shot award was won by <b>%1</b> with <b>%2</b> pts.</p> <p>射击冠军<b>%1</b> with <b>%2</b> .</p> - <p>A total of <b>%1</b> Hedgehog(s) were killed during this round.</p> <p>阵亡<b>%1</b> </p> - <h3>Version 0.9</h3> <h3>版本0.9</h3> - + + Locale + + + + + Nickname + + + + + Resolution 分辨率 - + + Quality + + + + + Stereo rendering + + + + FPS limit FPS 上限 - + + This program is distributed under the GNU General Public License v2 + + + + Developers: 开发者: - + Art: 艺术: - + Translations: 翻译: - + Special thanks: 特别感谢: - + Server name: 服务器名: - + Server port: 服务器端口: - + Host: 主机: - + Port: 端口: - + + Weapons 武器 - <h3>Version 0.9.2</h3> <h3>版本0.9.2</h3> - + Version 版本 - <p>The best shot award was won by <b>%1</b> with <b>%2</b> kills.</p> <p>最佳射手<b>%1</b>取得的战果 <b>%2</b></p> - + Sounds: 声音: - + Initial sound volume 初始音量 - + Damage Modifier 伤害修改 - + Turn Time 回合时间 - + Initial Health 初始生命值 - + Sudden Death Timeout 死亡模式倒计时 - + + Sudden Death Water Rise + + + + + Sudden Death Health Decrease + + + + + % Rope Length + + + + + % Health Crates + + + + + Health in Crates + + + + + Mines Time + + + + + Mines + + + + + % Dud Mines + + + + + Explosives + + + + + % Get Away Time + + + Case Probability 箱子掉落几率 - + Scheme Name: 设置名称: - + Crate Drops 箱子降落 - + Game scheme 游戏设置 + + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + + Account name (or email): + + + + + Password: + + + + + Video title: + + + + + Video description: + + + + + Tags (comma separated): + + + + + Name + + + + + Type + + + + + Grave + + + + + Flag + + + + + Voice + + + + + Summary + + + + + Description + + + + + Tip: + + + + + This development build is 'work in progress' and may not be compatible with other versions of the game. Some features might be broken or incomplete. Use at your own risk! + + + + + Format + + + + + Audio codec + + + + + Video codec + + + + + Framerate + + + + + Bitrate (Kbps) + + + + + Style + + + + + Scheme + + QLineEdit - + unnamed 无名 + + + + hedgehog %1 + + + + + anonymous + + QMainWindow - -= by unC0Rr =- -= by unC0Rr =- - Hedgewars 刺猬大作战 - + Hedgewars %1 刺猬大作战 %1 @@ -1167,12 +2788,14 @@ QMessageBox - + + + Error 错误 - + Failed to open data directory: %1 Please check your installation @@ -1181,292 +2804,520 @@ 请检查 - + + + Teams + 队伍 + + + + + Really delete this team? + + + + + + Schemes + + + + + Can not delete default scheme '%1'! + + + + + + + Network 网络 - + Connection to server is lost 服务器连接丢失 - + + All file associations have been set. + + + + + File association failed. + + + + + Fields required + + + + + Please fill out all fields + + + + + Success + + + + + Successfully posted the issue on code.google.com! + + + + + + Error during authentication with www.google.com + + + + + Error creating the issue + + + + + + Weapons 武器 - + + Can not overwrite default weapon set '%1'! + + + + + Can not delete default weapon set '%1'! + + + Can not delete default weapon set - 不能删除默认武器设定 - - - + 不能删除默认武器设定 + + + Really delete this weapon set? 真的删除这个武器设定吗? - Can not edit default weapon set - 不能更改默认的武器设定 + 不能更改默认的武器设定 + + + + Error while authenticating at google.com: + + + + + + Login or password is incorrect + + + + + Error while sending metadata to youtube.com: + + + + + + Really delete this game scheme? + QObject - + Error 错误 - + Cannot create directory %1 无法创建路径 %1 - Quit 退出 - + OK 确认 + + + Nickname + + + + + Please enter your nickname + + QPushButton - Single Player 单人游戏 - Multiplayer 多人游戏 - Net game 网络游戏 - Demos Demo - + + Setup 设置 - Exit 退出 - Back 返回 - Simple Game 简单游戏 - Discard 中止 - Save 保存 - + + Play demo 播放 demo - New team 新队伍 - Edit team 编辑队伍 - + Connect 连接 - Disconnect 失去连接 - Join 加入 - Create 创建 - Add Team 添加队伍 - + + Go! 上场! - + Start 开始 - About 关于 - + Start server 开始服务端 - + Update 更新 - Waiting 等待中 - + Load 读取 - Weapons scheme 武器设定 - Training 训练 - + Specify 指定 - + + default 默认 - + Rename 重命名 - + OK 确定 - + + Cancel 取消 - + + + Delete 删除 - Join official server 加入官方服务器 - + Ready 准备好了 + + + More info + + + + + Random Team + + + + + Associate file extensions + + + + + Set default options + + + + + Open videos directory + + + + + Play + + + + + + Upload to YouTube + + + + + Cancel uploading + + + + + more + + QTableWidget - Room name - 房间名称 - - - + 房间名称 + + Players number - 玩家数量 - - - + 玩家数量 + + Round in progress - 回合数 + 回合数 QToolBox - Actions - 行动 - - - + 行动 + + Weapons - 武器 - - - + 武器 + + Weapon properties - 武器选项 - - - + 武器选项 + + Other - 其他 + 其他 + + + + RoomsListModel + + + In progress + + + + + Room Name + + + + + C + + + + + T + + + + + Owner + + + + + Map + 地图 + + + + Rules + + + + + Weapons + 武器 + + + + Random Map + + + + + Random Maze + + + + + Hand-drawn + + + + + SelWeaponWidget + + + Weapon set + + + + + Probabilities + + + + + Ammo in boxes + + + + + Delays + + + + + + new + + + + + + copy of + TCPBase - + + Error 错误 - + Unable to start the server: %1. 无法开始服务端: %1. - + Unable to run engine: %1 ( 无法运行引擎: %1 ( @@ -1474,75 +3325,167 @@ ToggleButtonWidget - + Fort Mode 城堡模式 - + Divide Teams 团体行动 - + Solid Land 固实地面 - + Add Border 添加边界 - + Low Gravity 低重力 - + Laser Sight 激光瞄准 - + Invulnerable 刀枪不入 - + + Reset Health + + + + + Vampirism + + + + + Karma + + + + + Artillery + + + + + Random Order + + + + + King + + + + + Place Hedgehogs + + + + + Clan Shares Ammo + + + + + Disable Girders + + + + + Disable Land Objects + + + + + AI Survival Mode + + + + + Unlimited Attacks + + + + + Reset Weapons + + + + + Per Hedgehog Ammo + + + + + Disable Wind + + + + + More Wind + + + + + Tag Team + + + + + Add Bottom Border + + + Add Mines - 布置地雷 + 布置地雷 binds + up + left + right + down - jump - - - - + + + + attack 攻击 @@ -1557,46 +3500,51 @@ 切换 - + slot 1 slot 1 + + slot 2 + slot 2 + + - slot 2 - slot 2 + slot 3 + slot 3 - slot 3 - slot 3 + slot 4 + slot 4 - slot 4 - slot 4 + slot 5 + slot 5 - slot 5 - slot 5 + slot 6 + slot 6 - slot 6 - slot 6 + slot 7 + slot 7 - slot 7 - slot 7 - - - slot 8 slot 8 + + slot 10 + slot 10 + + timer 1 sec 定时1秒 @@ -1622,214 +3570,733 @@ 定时5秒 + + zoom in + + + + zoom out + + + + + reset zoom + + + + + mute audio + + + + capture 夺取 - + + record + + + + quit 退出 + + find hedgehog + 找到 刺猬 + + - find hedgehog - 找到 刺猬 - - - ammo menu 弹药菜单 - + + long jump + + + + + high jump + + + + volume down 降低音量 - + volume up 提高音量 - + change mode 改变模式 - + pause 暂停 - + slot 9 slot 9 - + hedgehogs info 刺猬大作战 信息 - + chat 聊天 - + chat history 聊天记录 - + confirmation 确认 - + precise aim 练习瞄准 + binds (categories) + + + Basic controls + + + + + Weapon controls + + + + + Camera and cursor controls + + + + + Other + 其他 + + + + binds (descriptions) + + + Move your hogs and aim: + + + + + Traverse gaps and obstacles by jumping: + + + + + Fire your selected weapon or trigger an utility item: + + + + + Pick a weapon or a target location under the cursor: + + + + + Switch your currently active hog (if possible): + + + + + Pick a weapon or utility item: + + + + + Set the timer on bombs and timed weapons: + + + + + Move the camera to the active hog: + + + + + Move the cursor or camera without using the mouse: + + + + + Modify the camera's zoom level: + + + + + Talk to your team or all participants: + + + + + Pause, continue or leave your game: + + + + + Modify the game's volume while playing: + + + + + Toggle fullscreen mode: + + + + + Take a screenshot: + + + + + Toggle labels above hedgehogs: + + + + + Record video: + + + + + binds (keys) + + + Mouse: Left button + + + + + Mouse: Middle button + + + + + Mouse: Right button + + + + + Mouse: Wheel up + + + + + Mouse: Wheel down + + + + + Backspace + + + + + Tab + + + + + Clear + + + + + Return + + + + + Pause + + + + + Escape + + + + + Space + + + + + Delete + 删除 + + + + Numpad 0 + + + + + Numpad 1 + + + + + Numpad 2 + + + + + Numpad 3 + + + + + Numpad 4 + + + + + Numpad 5 + + + + + Numpad 6 + + + + + Numpad 7 + + + + + Numpad 8 + + + + + Numpad 9 + + + + + Numpad . + + + + + Numpad / + + + + + Numpad * + + + + + Numpad - + + + + + Numpad + + + + + + Enter + + + + + Equals + + + + + Up + + + + + Down + + + + + Right + + + + + Left + + + + + Insert + + + + + Home + + + + + End + + + + + Page up + + + + + Page down + + + + + Num lock + + + + + Caps lock + + + + + Scroll lock + + + + + Right shift + + + + + Left shift + + + + + Right ctrl + + + + + Left ctrl + + + + + Right alt + + + + + Left alt + + + + + Right meta + + + + + Left meta + + + + + A button + + + + + B button + + + + + X button + + + + + Y button + + + + + LB button + + + + + RB button + + + + + Back button + + + + + Start button + + + + + Left stick + + + + + Right stick + + + + + Left stick (Right) + + + + + Left stick (Left) + + + + + Left stick (Down) + + + + + Left stick (Up) + + + + + Left trigger + + + + + Right trigger + + + + + Right stick (Down) + + + + + Right stick (Up) + + + + + Right stick (Right) + + + + + Right stick (Left) + + + + + DPad + + + + + Keyboard + + + + + Axis + + + + + + (Up) + + + + + + (Down) + + + + + Hat + + + + + (Left) + + + + + (Right) + + + + + Button + + + + teams - Hedgehogs - 刺猬 - - - + 刺猬 + + hedgehog 1 - 刺猬 1号 - - - + 刺猬 1号 + + hedgehog 2 - 刺猬 2号 - - - + 刺猬 2号 + + hedgehog 3 - 刺猬 3号 - - - + 刺猬 3号 + + hedgehog 4 - 刺猬 4号 - - - + 刺猬 4号 + + hedgehog 5 - 刺猬 5号 - - - + 刺猬 5号 + + hedgehog 6 - 刺猬 6号 - - - + 刺猬 6号 + + hedgehog 7 - 刺猬 7号 - - - + 刺猬 7号 + + hedgehog 8 - 刺猬 8号 - - - + 刺猬 8号 + + Goddess - 女神 - - - + 女神 + + Isis - 艾希丝 - - - + 艾希丝 + + Astarte - 阿斯德尔特 - - - + 阿斯德尔特 + + Diana - 黛安娜 - - - + 黛安娜 + + Aphrodite - 阿弗罗狄特 - - - + 阿弗罗狄特 + + Hecate - 赫卡特 - - - + 赫卡特 + + Demeter - 得墨忒耳 - - - + 得墨忒耳 + + Kali - 迦梨 - - - + 迦梨 + + Inanna - 維納斯 - - - + 維納斯 + + Fruits - 水果 - - - + 水果 + + Banana - 香蕉 - - - + 香蕉 + + Apple - 苹果 - - - + 苹果 + + Orange - 橙子 - - - + 橙子 + + Lemon - 柠檬 - - - + 柠檬 + + Pineapple - 菠萝 - - - + 菠萝 + + Mango - 芒果 - - - + 芒果 + + Peach - 桃子 - - - + 桃子 + + Plum - 梅子 + 梅子 diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/hedgewars_zh_TW.ts --- a/share/hedgewars/Data/Locale/hedgewars_zh_TW.ts Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_zh_TW.ts Sun Sep 16 16:54:51 2012 +0200 @@ -2,6 +2,13 @@ + AbstractPage + + Go back + + + + AmmoSchemeModel new @@ -68,6 +75,13 @@ + HWAskQuitDialog + + Do yot really want to quit? + + + + HWChatWidget %1 has been removed from your ignore list @@ -113,10 +127,6 @@ %1 is not a valid command! - - Kicking %1 ... - - HWForm @@ -172,7 +182,7 @@ Password - 密碼 + 密碼 Your nickname %1 is @@ -362,6 +372,32 @@ User quit + + Remote host has closed connection + + + + The server is too old. Disconnecting now. + + + + + HWPasswordDialog + + Password + 密碼 + + + + HWUploadVideoDialog + + Upload video + + + + Upload + + KB @@ -371,6 +407,26 @@ + LibavIteraction + + Duration: %1m %2s + + + + + Video: %1x%2, + + + + %1 fps, + + + + Audio: + + + + PageAdmin Server message: @@ -454,6 +510,10 @@ All files + + Eraser + + PageEditTeam @@ -545,14 +605,21 @@ + PageInfo + + Open the snapshot folder + + + + PageMain Local Game (Play a game on a single computer) - 本地遊戲(在一台電腦上) + 本地遊戲(在一台電腦上) Network Game (Play a game across a network) - 網路遊戲(通過網路) + 網路遊戲(通過網路) Simply pick the same color as a friend to play together as a team. Each of you will still control his or her own hedgehogs but they'll win or lose together. @@ -803,6 +870,46 @@ Downloadable Content + + Local Game + + + + Play a game on a single computer + + + + Network Game + + + + Play a game across a network + + + + Read about who is behind the Hedgewars Project + + + + Leave a feedback here reporting issues, suggesting features or just saying how you like Hedgewars + + + + Access the user created content downloadable from our website + + + + Exit game + + + + Manage videos recorded from game + + + + Edit game preferences + + PageMultiplayer @@ -840,6 +947,14 @@ OK + + DLC + + + + Downloadable Content + + PageNetType @@ -851,6 +966,14 @@ Official server 官方伺服器 + + Join hundreds of players online! + + + + Join or host your own game server in a Local Area Network. + + PageOptions @@ -894,6 +1017,18 @@ Delete weapon set + + General + 常規 + + + Advanced + 進階 + + + Reset to default colors + + PagePlayDemo @@ -959,44 +1094,44 @@ This game is in lobby. You may join and start playing once the game starts. - 遊戲正在等待中。 + 遊戲正在等待中。 您可以加入等待遊戲開始。 This game is in progress. You may join and spectate now but you'll have to wait for the game to end to start playing. - 遊戲正在進行中。 + 遊戲正在進行中。 您可以加入觀戰但必須等遊戲結束才能參與遊戲。 %1 is the host. He may adjust settings and start the game. - %1是房主,他可以調整設置、開始遊戲。 + %1是房主,他可以調整設置、開始遊戲。 Random Map - 隨機地圖 + 隨機地圖 Games may be played on precreated or randomized maps. - 遊戲可以在預先創建或者隨機產生的地圖上進行。 + 遊戲可以在預先創建或者隨機產生的地圖上進行。 The Game Scheme defines general options and preferences like Round Time, Sudden Death or Vampirism. - 遊戲設置包括一般選項例如回合時間,突然死亡或吸血模式。 + 遊戲設置包括一般選項例如回合時間,突然死亡或吸血模式。 The Weapon Scheme defines available weapons and their ammunition count. - 武器設置包括可以選用的武器和彈藥數量。 + 武器設置包括可以選用的武器和彈藥數量。 There are %1 clients connected to this room. - + 有%1個用戶端連接到這個房間。 There are %1 teams participating in this room. - + 有%1個隊伍加入這個房間。 @@ -1009,10 +1144,6 @@ 請從列表選中房間 - Random Maze - - - Rules: @@ -1198,11 +1329,11 @@ PageSinglePlayer Simple Game (a quick game against the computer, settings are chosen for you) - 快速遊戲 (對抗電腦,固定設置) + 快速遊戲 (對抗電腦,固定設置) Multiplayer (play a hotseat game against your friends, or AI teams) - 多人遊戲 (熱坐對抗朋友或AI) + 多人遊戲 (熱坐對抗朋友或AI) Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT @@ -1210,18 +1341,54 @@ Demos (Watch recorded demos) - Demo (觀看記錄的Demo) + Demo (觀看記錄的Demo) Load (Load a previously saved game) - 讀取 (讀取之前保存的遊戲) - - - Campaign Mode (...) - - - - Training Mode (Practice your skills in a range of training missions) + 讀取 (讀取之前保存的遊戲) + + + Simple Game + + + + Play a quick game against the computer with random settings + + + + Multiplayer + + + + Play a hotseat game against your friends, or AI teams + + + + Campaign Mode + + + + Training Mode + + + + Practice your skills in a range of training missions + + + + Demos + + + + Watch recorded demos + + + + Load + 讀取 + + + Load a previously saved game @@ -1235,6 +1402,69 @@ Select a mission! + + Pick the mission or training to play + + + + Start fighting + + + + + PageVideos + + Name + + + + Size + + + + %1 bytes + + + + + + (in progress...) + + + + Date: + + + + Size: + + + + Are you sure? + + + + Do you really want do remove %1? + + + + Do you really want do remove %1 file(s)? + + + + + + encoding + + + + uploading + + + + Do you really want do cancel uploading %1? + + QAction @@ -1341,6 +1571,26 @@ Frontend effects + + Save password + + + + Save account name and password + + + + Video is private + + + + Record audio + + + + Use game resolution + + QComboBox @@ -1511,12 +1761,32 @@ Schemes and Weapons + + Custom colors + + + + Miscellaneous + + + + Video recording options + + + + Videos + + + + Description + + QLabel Net nick - 網路遊戲昵稱 + 網路遊戲昵稱 This program is distributed under the GNU General Public License @@ -1643,10 +1913,6 @@ - Restart game to apply - - - Explosives @@ -1696,7 +1962,7 @@ Password - 密碼 + 密碼 % Get Away Time @@ -1706,6 +1972,68 @@ This program is distributed under the GNU General Public License v2 + + There are videos that are currently being processed. +Exiting now will abort them. +Do yot really want to quit? + + + + Please provide either the YouTube account name or the email address associated with the Google Account. + + + + Account name (or email): + + + + Password: + + + + Video title: + + + + Video description: + + + + Tags (comma separated): + + + + Summary + + + + Description + + + + Nickname + 匿稱 + + + Format + + + + Audio codec + + + + Video codec + + + + Framerate + + + + Bitrate (Kbps) + + QLineEdit @@ -1717,6 +2045,10 @@ hedgehog %1 + + anonymous + + QMainWindow @@ -1799,6 +2131,44 @@ Can not delete default weapon set '%1'! + + Fields required + + + + Please fill out all fields + + + + Success + + + + Successfully posted the issue on code.google.com! + + + + Error during authentication with www.google.com + + + + Error creating the issue + + + + Error while authenticating at google.com: + + + + + Login or password is incorrect + + + + Error while sending metadata to youtube.com: + + + QObject @@ -1897,11 +2267,70 @@ more + + More info + + + + Set default options + + + + Open videos directory + + + + Play + + + + Upload to YouTube + + + + Cancel uploading + + QTableWidget Room Name + 房間名 + + + C + 人數 + + + T + 隊伍 + + + Owner + 創建者 + + + Map + 地圖 + + + Rules + 規則 + + + Weapons + 武器 + + + + RoomsListModel + + In progress + + + + Room Name 房間名 @@ -1928,6 +2357,18 @@ Weapons 武器 + + Random Map + 隨機地圖 + + + Random Maze + + + + Hand-drawn + + SelWeaponWidget @@ -2242,6 +2683,14 @@ slot 10 slot 10 + + mute audio + + + + record + + binds (categories) @@ -2328,6 +2777,10 @@ Toggle labels above hedgehogs: 切換刺蝟標籤顯示方式: + + Record video: + + binds (keys) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/it.txt --- a/share/hedgewars/Data/Locale/it.txt Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/it.txt Sun Sep 16 16:54:51 2012 +0200 @@ -56,6 +56,7 @@ 00:53=Macchina Spazio-Temporale 00:54=Attrezzi da Costruzione 00:55=Land Spray +00:56=Congelatore 01:00=Combattiamo! 01:01=Round in parità @@ -78,6 +79,7 @@ 01:18=Massimo 01:19=Estremo 01:20=Rimbalzo %1 +01:21=Audio disattivato ; Event messages ; Hog (%1) died @@ -132,12 +134,14 @@ 02:00=%1 è caduto per l'onore della sua squadra! 02:00=%1 non ama questo gioco 02:00=Non c'è speranza per %1 -02:00=%1 è morto eroicamente per la patria. +02:00=%1 è morto eroicamente per la patria 02:00=%1 ti consiglio vivamente il Tetris 02:00=%1 ha giocato la sua prima e ultima partita! -02:00=%1 non è morto invano...(forse) +02:00=%1 non è morto invano... (forse) 02:00=L'inferno ti attende, %1 02:00=%1 vivrà per sempre nei nostri cuori +02:00=%1 è stato accolto dal nero falciatore +02:00=Ade ora ha un nuovo schiavo ; Hog (%1) drowned 02:01=%1 gioca a fare il sottomarino! @@ -182,7 +186,6 @@ 02:01=%1 ha perso il battello 02:01=%1 va a visitare la Fossa delle Marianne 02:01=%1 è cibo per i pesci -02:01=Ooops! %1 non può nuotare senza pinne! 02:01=%1 pare amare l'acqua più di ogni altra cosa 02:01=%1 avrebbe dovuto fare qualche lezione di nuoto 02:01=E' abbastanza salata l'acqua, %1? @@ -191,7 +194,10 @@ 02:01=%1 si trova a 20000 leghe sotto i mari 02:01=%1 è il nuovo amichetto di SpongeBob 02:01=%1 vuole incontrare il capitano Nemo! -02:01=Pazzia...QUESTA E' SPARTAAAAAAAAAAAAAAAAAAAAAAAAA!! +02:01=Pazzia...QUESTA E' SPARTAAAAAAAAAAAAAAAAAAAAAAAAA! +02:01=%1 aveva moooolta sete... +; Reference to the game Chip's Challenge. Please do not translate into italian. +02:01=Ooops! %1 can't swim without flippers! ; Round starts 02:02=Combattiamo! @@ -225,6 +231,7 @@ 02:02=Nessuna paura! 02:02=Che la festa abbia inizio! 02:02=Preparatevi alla gloria! +02:02=Forza e coraggio, che la vita è un passaggio! ; Round ends (win; unused atm) 02:03=... @@ -330,7 +337,7 @@ 02:08=Se ci fosse stato Chuck Norris dietro di te, ti avrebbe preso a calci volanti 02:08=%1 si è appena ricordato che deve ancora fare i compiti! 02:08=%1 desidera lasciare che il nemico lo sconfigga -02:08=%1 Domande, dubbi, perplessità? +02:08=%1, domande, dubbi, perplessità? ; Hog (%1) hurts himself only 02:09=%1 dovrebbe migliorare la sua mira! diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Locale/missions_it.txt --- a/share/hedgewars/Data/Locale/missions_it.txt Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Locale/missions_it.txt Sun Sep 16 16:54:51 2012 +0200 @@ -4,12 +4,18 @@ Basic_Training_-_Grenade.name=Addestramento base sull'utilizzo delle Granate Basic_Training_-_Grenade.desc="Ricorda, toglierai PRIMA la sicura e POI lancerai la granata!" +Basic_Training_-_Cluster_Bomb.name=ddestramento base sull'utilizzo delle Granate a Grappolo +Basic_Training_-_Cluster_Bomb.desc="Qualcuno ha bisogno di una doccia (molto) calda!" + Basic_Training_-_Shotgun.name=Addestramento base sull'utilizzo del Fucile a Pompa Basic_Training_-_Shotgun.desc="Prima spara, poi poniti delle domande!" Basic_Training_-_Sniper_Rifle.name=Addestramento base sull'utilizzo del Fucile di Precisione Basic_Training_-_Sniper_Rifle.desc="Sii preciso come non mai con il fucile di precisione! E attenzione a non sbagliare troppi colpi!" +Basic_Training_-_Rope.name=Addestramento base sull'utilizzo della Corda +Basic_Training_-_Rope.desc="Preparati ad arrivare ovunque grazie alla migliore delle corde esistenti sul mercato!" + User_Mission_-_Dangerous_Ducklings.name=Missione: Anatroccoli Pericolosi User_Mission_-_Dangerous_Ducklings.desc="Sii pronto, recluta! E' tempo di mettere a frutto quanto imparato durante l'addestramento base!" @@ -30,3 +36,12 @@ User_Mission_-_Newton_and_the_Hammock.name=Missione: Newton e l'Amaca User_Mission_-_Newton_and_the_Hammock.desc="Ricordate ricci: la velocità di un corpo rimane costante a meno che non intervenga una forza esterna ad esso!" + +User_Mission_-_The_Great_Escape.name=Missione: La Grande Fuga +User_Mission_-_The_Great_Escape.desc="Pensi ancora di potermi imprigionare!?" + +User_Mission_-_Rope_Knock_Challenge.name=Sfida: A Colpi di Corda +User_Mission_-_Rope_Knock_Challenge.desc="Guarda sempre dietro di te!" + +User_Mission_-_RCPlane_Challenge.name=Sfida: Aereo Radiocomandato +User_Mission_-_RCPlane_Challenge.desc="Ti senti abbastanza sicuro, eh, aviatore?" \ No newline at end of file diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/CMakeLists.txt --- a/share/hedgewars/Data/Missions/CMakeLists.txt Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Missions/CMakeLists.txt Sun Sep 16 16:54:51 2012 +0200 @@ -1,2 +1,2 @@ add_subdirectory(Training) -add_subdirectory(Campaign) \ No newline at end of file +add_subdirectory(Campaign) diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/CMakeLists.txt Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,7 @@ +file(GLOB Config *.ini) +file(GLOB Missions *.lua) + +install(FILES + ${Config} + ${Missions} + DESTINATION "${SHAREPATH}Data/Missions/Campaign/A Classic Fairytale") diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/backstab.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,1098 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Constants--------------------------------- +choiceAccepted = 1 +choiceRefused = 2 +choiceAttacked = 3 + +choiceEliminate = 1 +choiceSpare = 2 + +leaksNum = 1 +denseNum = 2 +waterNum = 3 +buffaloNum = 4 +chiefNum = 5 +girlNum = 6 +wiseNum = 7 + +spyKillStage = 1 +platformStage = 2 +wave3Stage = 3 + +tmpVar = 0 + +nativeNames = {loc("Leaks A Lot"), loc("Dense Cloud"), loc("Fiery Water"), + loc("Raging Buffalo"), loc("Righteous Beard"), loc("Fell From Grace"), + loc("Wise Oak"), loc("Eagle Eye"), loc("Flaming Worm")} + +nativeHats = {"Rambo", "RobinHood", "pirate_jack", "zoo_Bunny", "IndianChief", + "tiara", "AkuAku", "None", "None"} + +nativePos = {{887, 329}, {1050, 288}, {1731, 707}, + {830, 342}, {1001, 290}, {773, 340}, + {953, 305}, {347, 648}, {314, 647}} + +nativeDir = {"Right", "Left", "Left", + "Right", "Left", "Right", + "Left", "Right", "Right"} + +cannibalNames = {loc("Brain Teaser"), loc("Bone Jackson"), loc("Gimme Bones"), + loc("Hedgibal Lecter"), loc("Bloodpie"), loc("Scalp Muncher"), + loc("Back Breaker"), loc("Dahmer"), loc("Meiwes"), + loc("Ear Sniffer"), loc("Regurgitator"), loc("Muriel")} + +cannibalPos = {{3607, 1472}, {3612, 1487}, {3646, 1502}, + {3507, 195}, {3612, 1487}, {840, 1757}, + {3056, 1231}, {2981, 1222}, {2785, 1258}} + +cannibalDir = {"Left", "Left", "Left", + "Left", "Right", "Right", + "Left", "Left", "Left"} + +cyborgPos = {1369, 574} +cyborgPos2 = {1308, 148} + +deployedPos = {2522, 1365} +-----------------------------Variables--------------------------------- +natives = {} +nativeDead = {} +nativeHidden = {} +nativeRevived = {} +nativesNum = 0 + +cannibals = {} +cannibalDead = {} +cannibalHidden = {} + +speakerHog = nil +spyHog = nil +deployedHog = nil +deployedDead = false + +cyborgHidden = false +needToAct = 0 + +m2Choice = 0 +m2DenseDead = 0 +m4DenseDead = 0 +m4BuffaloDead = 0 +m4WaterDead = 0 +m4ChiefDead = 0 +m4LeaksDead = 0 + +needRevival = false +gearr = nil +startElimination = 0 +stage = 0 +choice = 0 +highJumped = false +TurnsLeft = 0 +startNativesNum = 0 + +startAnim = {} +afterChoiceAnim = {} +wave2Anim = {} +wave2DeadAnim = {} +wave3DeadAnim = {} + +vCircs = {} +-----------------------------Animations-------------------------------- +function Wave2Reaction() + local i = 1 + local gearr = nil + while nativeDead[i] == true do + i = i + 1 + end + gearr = natives[i] + if nativeDead[denseNum] ~= true and band(GetState(natives[denseNum]), gstDrowning) == 0 then + AnimInsertStepNext({func = AnimCustomFunction, args = {dense, EmitDenseClouds, {"Left"}}}) + AnimInsertStepNext({func = AnimTurn, args = {dense, "Left"}}) + end + if nativeDead[buffaloNum] ~= true and band(GetState(natives[buffaloNum]), gstDrowning) == 0 then + AnimInsertStepNext({func = AnimSay, args = {natives[buffaloNum], loc("Let them have a taste of my fury!"), SAY_SHOUT, 6000}}) + end + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("There's more of them? When did they become so hungry?"), SAY_SHOUT, 8000}}) +end + +function EmitDenseClouds(dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + AnimInsertStepNext({func = AnimVisualGear, args = {natives[denseNum], GetX(natives[denseNum]) + dif, GetY(natives[denseNum]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[denseNum], GetX(natives[denseNum]) + dif, GetY(natives[denseNum]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[denseNum], GetX(natives[denseNum]) + dif, GetY(natives[denseNum]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {natives[denseNum], 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[denseNum], GetX(natives[denseNum]) + dif, GetY(natives[denseNum]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[denseNum], GetX(natives[denseNum]) + dif, GetY(natives[denseNum]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {natives[denseNum], 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[denseNum], GetX(natives[denseNum]) + dif, GetY(natives[denseNum]) + dif, vgtSteam, 0, true}, swh = false}) +end + +function SaySafe() + local i = 1 + while gearr == nil do + if nativeDead[i] ~= true and nativeHidden[i] ~= true then + gearr = natives[i] + end + i = i + 1 + end + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("We are indeed."), SAY_SAY, 2500}}) + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("I think we are safe here."), SAY_SAY, 4000}}) +end + +function ReviveNatives() + for i = 1, 7 do + if nativeHidden[i] == true and nativeDead[i] ~= true then + RestoreHog(natives[i]) + nativeHidden[i] = false + nativeRevived[i] = true + AnimInsertStepNext({func = AnimOutOfNowhere, args = {natives[i], unpack(nativePos[i])}}) + end + end +end + +function WonderAlive() + if nativeRevived[waterNum] == true then + AnimInsertStepNext({func = AnimSay, args = {natives[waterNum], loc("I'm...alive? How? Why?"), SAY_THINK, 3500}}) + AnimInsertStepNext({func = AnimWait, args = {natives[waterNum], 800}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[waterNum], "Left"}}) + AnimInsertStepNext({func = AnimWait, args = {natives[waterNum], 800}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[waterNum], "Right"}}) + end + if nativeRevived[leaksNum] == true and nativeRevived[denseNum] == true then + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("But why would they help us?"), SAY_SAY, 4000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("It must be the aliens!"), SAY_SAY, 3500}}) + AnimInsertStepNext({func = AnimSay, args = {natives[girlNum], loc("You just appeared out of thin air!"), SAY_SAY, 5000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("But...we died!"), SAY_SAY, 2500}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("This must be the caves!"), SAY_SAY, 3500}}) + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("Dude, where are we?"), SAY_SAY, 3000}}) + AnimInsertStepNext({func = AnimWait, args = {natives[leaksNum], 800}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[leaksNum], "Right"}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[denseNum], "Left"}}) + AnimInsertStepNext({func = AnimWait, args = {natives[leaksNum], 800}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[leaksNum], "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[denseNum], "Right"}}) + AnimInsertStepNext({func = AnimWait, args = {natives[leaksNum], 800}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[leaksNum], "Right"}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[denseNum], "Left"}}) + AnimInsertStepNext({func = AnimWait, args = {natives[leaksNum], 800}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[leaksNum], "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[denseNum], "Right"}}) + AnimInsertStepNext({func = AnimCustomFunction, swh = false, args = {natives[leaksNum], CondNeedToTurn, {natives[leaksNum], natives[girlNum]}}}) + if nativeDead[chiefNum] ~= true then + AnimInsertStepNext({func = AnimTurn, args = {natives[chiefNum], "Right"}}) + end + elseif nativeRevived[leaksNum] == true then + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Why would they do this?"), SAY_SAY, 6000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("It must be the aliens' deed."), SAY_SAY, 5000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("Do not laugh, inexperienced one, for he speaks the truth!"), SAY_SAY, 10000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Yeah, sure! I died. Hillarious!"), SAY_SAY, 6000}}) + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("You're...alive!? But we saw you die!"), SAY_SAY, 6000}}) + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("???"), SAY_SAY, 2000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Wow, what a dream!"), SAY_SAY, 3000}}) + if nativeDead[chiefNum] ~= true then + AnimInsertStepNext({func = AnimTurn, args = {natives[chiefNum], "Right"}}) + end + AnimInsertStepNext({func = AnimCustomFunction, swh = false, args = {natives[leaksNum], CondNeedToTurn, {natives[leaksNum], natives[wiseNum]}}}) + AnimInsertStepNext({func = AnimCustomFunction, swh = false, args = {natives[leaksNum], CondNeedToTurn, {natives[leaksNum], gearr}}}) + elseif nativeRevived[denseNum] == true then + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("Dude, that's so cool!"), SAY_SAY, 3000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("It must be the aliens' deed."), SAY_SAY, 5000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("But that's impossible!"), SAY_SAY, 3000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("It was not a dream, unwise one!"), SAY_SAY, 5000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("Exactly, man! That was my dream."), SAY_SAY, 5000}}) + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("You're...alive!? But we saw you die!"), SAY_SAY, 6000}}) + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("???"), SAY_SAY, 2000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("Dude, wow! I just had the weirdest high!"), SAY_SAY, 6000}}) + if nativeDead[chiefNum] ~= true then + AnimInsertStepNext({func = AnimTurn, args = {natives[chiefNum], "Right"}}) + end + AnimInsertStepNext({func = AnimCustomFunction, swh = false, args = {natives[denseNum], CondNeedToTurn, {natives[denseNum], natives[wiseNum]}}}) + AnimInsertStepNext({func = AnimCustomFunction, swh = false, args = {natives[denseNum], CondNeedToTurn, {natives[denseNum], gearr}}}) + end +end + +function ExplainAlive() + if needRevival == true and m4WaterDead == 1 then + RestoreCyborg() + AnimSetGearPosition(cyborg, unpack(cyborgPos)) + AnimInsertStepNext({func = AnimCustomFunction, args = {water, HideCyborg, {}}}) + AnimInsertStepNext({func = AnimSwitchHog, args = {water}}) + AnimInsertStepNext({func = AnimSay, args = {cyborg, loc("The answer is...entertaintment. You'll see what I mean."), SAY_SAY, 8000}}) + AnimInsertStepNext({func = AnimSay, args = {cyborg, loc("You're probably wondering why I bought you back..."), SAY_SAY, 8000}}) + end +end + +function SpyDebate() + if m2Choice == choiceAccepted then + spyHog = natives[denseNum] + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("What shall we do with the traitor?"), SAY_SAY, 6000}}) + AnimInsertStepNext({func = SetHealth, swh = false, args = {natives[denseNum], 26}}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[wiseNum], GetGearPosition(natives[denseNum]), vgtExplosion, 0, true}}) + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("Here, let me help you!"), SAY_SAY, 3000}}) + if nativeDead[chiefNum] == true then + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("I forgot that she's the daughter of the chief, too..."), SAY_THINK, 7000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[girlNum], loc("You killed my father, you monster!"), SAY_SAY, 5000}}) + end + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("Look, I had no choice!"), SAY_SAY, 3000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("You have been giving us out to the enemy, haven't you!"), SAY_SAY, 7000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("You're a pathetic liar!"), SAY_SAY, 3000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Interesting! Last time you said you killed a cannibal!"), SAY_SAY, 7000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[denseNum], loc("I told you, I just found them."), SAY_SAY, 4500}}) + AnimInsertStepNext({func = AnimCustomFunction, args = {natives[denseNum], EmitDenseClouds, {"Left"}}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Where did you get the weapons in the forest, Dense Cloud?"), SAY_SAY, 8000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Not now, Fiery Water!"), SAY_SAY, 3000}}) + else + spyHog = natives[waterNum] + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("What shall we do with the traitor?"), SAY_SAY, 5000}}) + AnimInsertStepNext({func = SetHealth, swh = false, args = {natives[waterNum], 26}}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[wiseNum], nativePos[denseNum][1] + 50, nativePos[denseNum][2], vgtExplosion, 0, true}}) + AnimInsertStepNext({func = AnimSay, args = {natives[girlNum], loc("I can't believe what I'm hearing!"), SAY_SAY, 5500}}) + AnimInsertStepNext({func = AnimSay, args = {natives[waterNum], loc("You know what? I don't even regret anything!"), SAY_SAY, 7000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[girlNum], loc("In fact, you are the only one that's been acting strangely."), SAY_SAY, 8000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[waterNum], loc("Are you accusing me of something?"), SAY_SAY, 3500}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Seems like every time you take a \"walk\", the enemy find us!"), SAY_SAY, 8000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[waterNum], loc("You know...taking a stroll."), SAY_SAY, 3500}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("Where have you been?!"), SAY_SAY, 3000}}) + end + if nativeRevived[waterNum] == true then + AnimInsertStepNext({func = AnimSay, args = {natives[waterNum], loc("You won't believe what happened to me!"), SAY_SAY, 5500}}) + end + AnimInsertStepNext({func = AnimSay, args = {natives[waterNum], loc("Hey, guys!"), SAY_SAY, 2000}}) + AnimInsertStepNext({func = AnimMove, args = {natives[waterNum], "Left", nativePos[denseNum][1] + 50, nativePos[denseNum][2]}}) + AnimInsertStepNext({func = AnimJump, args = {natives[waterNum], "back"}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[waterNum], "Right"}}) + AnimInsertStepNext({func = AnimMove, args = {natives[waterNum], "Left", 1228, 412}}) + AnimInsertStepNext({func = AnimJump, args = {natives[waterNum], "long"}}) + AnimInsertStepNext({func = AnimJump, args = {natives[waterNum], "long"}}) + AnimInsertStepNext({func = AnimJump, args = {natives[waterNum], "long"}}) + AnimInsertStepNext({func = AnimTurn, args = {natives[waterNum], "Left"}}) + AnimInsertStepNext({func = AnimSay, args = {natives[wiseNum], loc("There must be a spy among us!"), SAY_SAY, 4000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[girlNum], loc("We made sure noone followed us!"), SAY_SAY, 4000}}) + AnimInsertStepNext({func = AnimSay, args = {natives[leaksNum], loc("What? Here? How did they find us?!"), SAY_SAY, 5000}}) +end + +function AnimationSetup() + table.insert(startAnim, {func = AnimWait, swh = false, args = {natives[leaksNum], 3000}}) + table.insert(startAnim, {func = AnimCustomFunction, swh = false, args = {natives[leaksNum], SaySafe, {}}}) + if needRevival == true then + table.insert(startAnim, {func = AnimCustomFunction, swh = false, args = {cyborg, ReviveNatives, {}}}) + table.insert(startAnim, {func = AnimCustomFunction, swh = false, args = {natives[leaksNum], WonderAlive, {}}}) + table.insert(startAnim, {func = AnimCustomFunction, swh = false, args = {cyborg, ExplainAlive, {}}}) + end + table.insert(startAnim, {func = AnimCustomFunction, swh = false, args = {natives[leaksNum], RestoreWave, {1}}}) + table.insert(startAnim, {func = AnimOutOfNowhere, args = {cannibals[1], unpack(cannibalPos[1])}}) + table.insert(startAnim, {func = AnimOutOfNowhere, args = {cannibals[2], unpack(cannibalPos[2])}}) + table.insert(startAnim, {func = AnimOutOfNowhere, args = {cannibals[3], unpack(cannibalPos[3])}}) + table.insert(startAnim, {func = AnimWait, args = {natives[leaksNum], 1000}}) + table.insert(startAnim, {func = AnimCustomFunction, swh = false, args = {natives[leaksNum], SpyDebate, {}}}) + AddSkipFunction(startAnim, SkipStartAnim, {}) +end + +function SetupWave2Anim() + for i = 7, 1, -1 do + if nativeDead[i] ~= true then + speakerHog = natives[i] + end + end + table.insert(wave2Anim, {func = AnimOutOfNowhere, args = {cannibals[4], unpack(cannibalPos[4])}}) + table.insert(wave2Anim, {func = AnimOutOfNowhere, args = {cannibals[5], unpack(cannibalPos[5])}}) + table.insert(wave2Anim, {func = AnimOutOfNowhere, args = {cannibals[6], unpack(cannibalPos[6])}}) + table.insert(wave2Anim, {func = AnimSay, args = {speakerHog, loc("Look out! There's more of them!"), SAY_SHOUT, 5000}}) + AddSkipFunction(wave2Anim, SkipWave2Anim, {}) +end + +function PutCircles() + if circlesPut then + return + end + vCircs[1] = AddVisualGear(0,0,vgtCircle,0,true) + vCircs[2] = AddVisualGear(0,0,vgtCircle,0,true) + vCircs[3] = AddVisualGear(0,0,vgtCircle,0,true) + SetVisualGearValues(vCircs[1], cannibalPos[7][1], cannibalPos[7][2], 100, 255, 1, 10, 0, 120, 3, 0xff00ffff) + SetVisualGearValues(vCircs[2], cannibalPos[8][1], cannibalPos[8][2], 100, 255, 1, 10, 0, 120, 3, 0xff00ffff) + SetVisualGearValues(vCircs[3], cannibalPos[9][1], cannibalPos[9][2], 100, 255, 1, 10, 0, 120, 3, 0xff00ffff) + circlesPut = true +end + +function SetupWave2DeadAnim() + for i = 7, 1, -1 do + if nativeDead[i] ~= true then + deployedHog = natives[i] + end + end + if nativeDead[wiseNum] ~= true and band(GetState(natives[wiseNum]), gstDrowning) == 0 then + if nativesNum > 1 then + table.insert(wave2DeadAnim, {func = AnimWait, args = {natives[wiseNum], 1500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("What a strange feeling!"), SAY_THINK, 3000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("I need to warn the others."), SAY_THINK, 3000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("If only I had a way..."), SAY_THINK, 3000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("Oh, silly me! I forgot that I'm the shaman."), SAY_THINK, 6000}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], TeleportNatives, {}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], TurnNatives, {natives[wiseNum]}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], CondNeedToTurn, {natives[wiseNum], deployedHog}}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("I sense another wave of cannibals heading our way!"), SAY_SAY, 6500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("I feel something...a place! They will arrive near the circles!"), SAY_SAY, 7500}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], PutCircles, {}}}) + table.insert(wave2DeadAnim, {func = AnimFollowGear, swh = false, args = {vCircs[1]}}) + table.insert(wave2DeadAnim, {func = AnimWait, args = {natives[wiseNum], 1500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("We need to prevent their arrival!"), SAY_SAY, 4500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("Go, quick!"), SAY_SAY, 2500}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], DeployHog, {}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], RestoreCyborg, {}}}) + table.insert(wave2DeadAnim, {func = AnimOutOfNowhere, swh = false, args = {cyborg, cyborgPos2[1], cyborgPos2[2]}}) + table.insert(wave2DeadAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, IsolateNatives, {}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, PutCGI, {}}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {cyborg, loc("I want to see how it handles this!"), SAY_SAY, 6000}}) + table.insert(wave2DeadAnim, {func = AnimSwitchHog, args = {deployedHog}}) + table.insert(wave2DeadAnim, {func = AnimDisappear, args = {cyborg, 0, 0}}) +-- table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, DeployHog, {}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, swh = false, args = {cyborg, HideCyborg, {}}}) + else + table.insert(wave2DeadAnim, {func = AnimWait, args = {natives[wiseNum], 1500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("What a strange feeling!"), SAY_THINK, 3000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("I sense another wave of cannibals heading my way!"), SAY_THINK, 6500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("I feel something...a place! They will arrive near the circles!"), SAY_SAY, 7500}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], PutCircles, {}}}) + table.insert(wave2DeadAnim, {func = AnimFollowGear, swh = false, args = {vCircs[1]}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("I need to prevent their arrival!"), SAY_THINK, 4500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("If only I had a way..."), SAY_THINK, 3000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {natives[wiseNum], loc("Oh, silly me! I forgot that I'm the shaman."), SAY_THINK, 6000}}) + end + else + table.insert(wave2DeadAnim, {func = AnimWait, args = {cyborg, 1500}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, swh = false, args = {cyborg, RestoreCyborg, {}}}) + table.insert(wave2DeadAnim, {func = AnimOutOfNowhere, args = {cyborg, cyborgPos2[1], cyborgPos2[2]}}) + table.insert(wave2DeadAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, TeleportNatives, {}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, TurnNatives, {cyborg}}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {cyborg, loc("Oh, my! This is even more entertaining than I've expected!"), SAY_SAY, 7500}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {cyborg, loc("You might want to find a way to instantly kill arriving cannibals!"), SAY_SAY, 8000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {cyborg, loc("I believe there's more of them."), SAY_SAY, 4000}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {cyborg, loc("I marked the place of their arrival. You're welcome!"), SAY_SAY, 6000}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], PutCircles, {}}}) + table.insert(wave2DeadAnim, {func = AnimFollowGear, swh = false, args = {vCircs[1]}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {deployedHog, DeployHog, {}}}) + if nativesNum > 1 then +-- table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {natives[wiseNum], RestoreCyborg, {}}}) +-- table.insert(wave2DeadAnim, {func = AnimOutOfNowhere, swh = false, args = {cyborg, cyborgPos2[1], cyborgPos2[2]}}) +-- table.insert(wave2DeadAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, IsolateNatives, {}}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, args = {cyborg, PutCGI, {}}}) + table.insert(wave2DeadAnim, {func = AnimSay, args = {cyborg, loc("I want to see how it handles this!"), SAY_SAY, 6000}}) + end + table.insert(wave2DeadAnim, {func = AnimSwitchHog, args = {deployedHog}}) + table.insert(wave2DeadAnim, {func = AnimDisappear, swh = false, args = {cyborg, 0, 0}}) + table.insert(wave2DeadAnim, {func = AnimCustomFunction, swh = false, args = {cyborg, HideCyborg, {}}}) + end + AddSkipFunction(wave2DeadAnim, SkipWave2DeadAnim, {}) +end + +function IsolateNatives() + PlaceGirder(710, 299, 6) + PlaceGirder(690, 299, 6) + PlaceGirder(761, 209, 4) + PlaceGirder(921, 209, 4) + PlaceGirder(1081, 209, 4) + PlaceGirder(761, 189, 4) + PlaceGirder(921, 189, 4) + PlaceGirder(1081, 189, 4) + PlaceGirder(761, 169, 4) + PlaceGirder(921, 169, 4) + PlaceGirder(1081, 169, 4) + PlaceGirder(761, 149, 4) + PlaceGirder(921, 149, 4) + PlaceGirder(1081, 149, 4) + PlaceGirder(761, 129, 4) + PlaceGirder(921, 129, 4) + PlaceGirder(1081, 129, 4) + PlaceGirder(1120, 261, 2) + PlaceGirder(1140, 261, 2) + PlaceGirder(1160, 261, 2) + AddAmmo(deployedHog, amDEagle, 0) + AddAmmo(deployedHog, amFirePunch, 0) +end + +function PutCGI() + AddVisualGear(710, 299, vgtExplosion, 0, true) + AddVisualGear(690, 299, vgtExplosion, 0, true) + AddVisualGear(761, 209, vgtExplosion, 0, true) + AddVisualGear(921, 209, vgtExplosion, 0, true) + AddVisualGear(1081, 209, vgtExplosion, 0, true) + AddVisualGear(761, 189, vgtExplosion, 0, true) + AddVisualGear(921, 189, vgtExplosion, 0, true) + AddVisualGear(1081, 189, vgtExplosion, 0, true) + AddVisualGear(761, 169, vgtExplosion, 0, true) + AddVisualGear(921, 169, vgtExplosion, 0, true) + AddVisualGear(1081, 169, vgtExplosion, 0, true) + AddVisualGear(761, 149, vgtExplosion, 0, true) + AddVisualGear(921, 149, vgtExplosion, 0, true) + AddVisualGear(1081, 149, vgtExplosion, 0, true) + AddVisualGear(761, 129, vgtExplosion, 0, true) + AddVisualGear(921, 129, vgtExplosion, 0, true) + AddVisualGear(1081, 129, vgtExplosion, 0, true) + AddVisualGear(1120, 261, vgtExplosion, 0, true) + AddVisualGear(1140, 261, vgtExplosion, 0, true) + AddVisualGear(1160, 261, vgtExplosion, 0, true) +end + +function TeleportNatives() + nativePos[waterNum] = {1100, 288} + for i = 1, 7 do + if nativeDead[i] ~= true then + AnimTeleportGear(natives[i], unpack(nativePos[i])) + end + end +end + +function TurnNatives(hog) + for i = 1, 7 do + if nativeDead[i] == false then + if GetX(natives[i]) < GetX(hog) then + AnimTurn(natives[i], "Right") + else + AnimTurn(natives[i], "Left") + end + end + end +end + +function DeployHog() + AnimSwitchHog(deployedHog) + AnimTeleportGear(deployedHog, unpack(deployedPos)) + if deployedHog ~= natives[wiseNum] then + AnimSay(deployedHog, loc("Why me?!"), SAY_THINK, 2000) + end +end + +function SetupAfterChoiceAnim() + for i = 7, 1, -1 do + if nativeDead[i] ~= true then + if natives[i] ~= spyHog then + speakerHog = natives[i] + end + end + end + if choice == choiceEliminate then + table.insert(afterChoiceAnim, {func = AnimWait, args = {speakerHog, 1500}}) + table.insert(afterChoiceAnim, {func = AnimSay, args = {speakerHog, loc("He won't be selling us out anymore!"), SAY_SAY, 6000}}) + if nativeDead[girlNum] ~= true and m4ChiefDead == 1 then + table.insert(afterChoiceAnim, {func = AnimSay, args = {natives[girlNum], loc("That's for my father!"), SAY_SAY, 3500}}) + end + table.insert(afterChoiceAnim, {func = AnimSay, args = {speakerHog, loc("Let's show those cannibals what we're made of!"), SAY_SAY, 7000}}) + else + table.insert(afterChoiceAnim, {func = AnimCustomFunction, swh = false, args = {natives[leaksNum], CondNeedToTurn, {speakerHog, spyHog}}}) + table.insert(afterChoiceAnim, {func = AnimSay, args = {speakerHog, loc("We'll spare your life for now!"), SAY_SAY, 4500}}) + table.insert(afterChoiceAnim, {func = AnimSay, args = {spyHog, loc("May the spirits aid you in all your quests!"), SAY_SAY, 7000}}) + table.insert(afterChoiceAnim, {func = AnimSay, args = {speakerHog, loc("I just don't want to sink to your level."), SAY_SAY, 6000}}) + table.insert(afterChoiceAnim, {func = AnimSay, args = {speakerHog, loc("Let's show those cannibals what we're made of!"), SAY_SAY, 7000}}) + end + table.insert(afterChoiceAnim, {func = AnimSay, args = {natives[8], loc("Let us help, too!"), SAY_SAY, 3000}}) + table.insert(afterChoiceAnim, {func = AnimTurn, args = {speakerHog, "Left", SAY_SAY, 7000}}) + table.insert(afterChoiceAnim, {func = AnimSay, args = {speakerHog, loc("No. You and the rest of the tribe are safer there!"), SAY_SAY, 7000}}) + AddSkipFunction(afterChoiceAnim, SkipAfterChoiceAnim, {}) +end + +function SetupHogDeadAnim(gear) + hogDeadAnim = {} + if nativesNum == 0 then + return + end + local hogDeadStrings = {loc("They killed " .. gear .."! You bastards!"), + loc(gear .. "! Why?!"), + loc("That was just mean!"), + loc("Oh no, not " .. gear .. "!"), + loc("Why " .. gear .. "? Why?"), + loc("What has " .. gear .. " ever done to you?!")} + table.insert(hogDeadAnim, {func = AnimSay, args = {CurrentHedgehog, hogDeadStrings[7 - nativesNum], SAY_SHOUT, 4000}}) +end + +function AfterHogDeadAnim() + freshDead = nil + TurnTimeLeft = TurnTime +end + +--------------------------Anim skip functions-------------------------- + +function AfterAfterChoiceAnim() + stage = 0 + AddEvent(CheckWaveDead, {1}, DoWaveDead, {1}, 0) + AddAmmo(speakerHog, amSwitch, 100) + SetGearMessage(speakerHog, 0) + SetState(speakerHog, 0) + TurnTimeLeft = -1 + ShowMission(loc("Backstab"), loc("The food bites back"), loc("Defeat the cannibals"), 1, 4000) + SpawnCrates() +end + +function SkipAfterChoiceAnim() + SetGearMessage(CurrentHedgehog, 0) + AnimSwitchHog(speakerHog) +end + +function AfterWave2Anim() + AddEvent(CheckWaveDead, {2}, DoWaveDead, {2}, 0) + SetGearMessage(CurrentHedgehog, 0) + SetState(CurrentHedgehog, 0) + SpawnCrates() + TurnTimeLeft = TurnTime +end + +function SkipWave2DeadAnim() + TeleportNatives() + IsolateNatives() + DeployHog() + HideCyborg() + PutCircles() +end + +function SpawnPlatformCrates() + SpawnAmmoCrate(2494, 1262, amMine) + SpawnAmmoCrate(2574, 1279, amSMine) + SpawnAmmoCrate(2575, 1267, amMine) + SpawnAmmoCrate(2617, 1259, amSMine) + SpawnUtilityCrate(2579, 1254, amMine) + SpawnUtilityCrate(2478, 1243, amMine) +end + +function AfterWave2DeadAnim() + TurnsLeft = 7 + stage = platformStage + SpawnPlatformCrates() + SetGearMessage(CurrentHedgehog, 0) + AddEvent(CheckTurnsOver, {}, DoTurnsOver, {3}, 0) + AddEvent(CheckWaveDead, {3}, DoWaveDead, {3}, 0) + AddEvent(CheckDeployedDead, {}, DoDeployedDead, {}, 0) + TurnTimeLeft = 0 + ShowMission(loc("Backstab"), loc("Drills"), loc("You have 7 turns until the next wave arrives.|Make sure the arriving cannibals are greeted appropriately!|If the hog dies, the cause is lost.|Hint: you might want to use some mines..."), 1, 12000) +end + +function DoTurnsOver() + stage = wave3Stage + RestoreWave(3) +end + +function SkipWave2Anim() + AnimSwitchHog(speakerHog) +end + +function SkipStartAnim() + AnimSetGearPosition(natives[waterNum], nativePos[denseNum][1] + 50, nativePos[denseNum][2]) + RestoreWave(1) + ReviveNatives() + SetGearMessage(CurrentHedgehog, 0) + SetState(CurrentHedgehog, 0) + if m2Choice == choiceAccepted then + spyHog = natives[denseNum] + else + spyHog = natives[waterNum] + end + SetHealth(spyHog, 26) +end + +function AfterStartAnim() + AnimSwitchHog(natives[leaksNum]) + TurnTimeLeft = 0 + stage = spyKillStage + AddEvent(CheckChoice, {}, DoChoice, {}, 0) + AddEvent(CheckKilledOther, {}, DoKilledOther, {}, 0) + AddEvent(CheckChoiceRefuse, {}, DoChoiceRefuse, {}, 0) + ShowMission(loc("Backstab"), loc("Judas"), loc("Kill the traitor...or spare his life!|Kill him or press [Precise]!"), 1, 8000) +end + +-----------------------------Events------------------------------------ +function CheckTurnsOver() + return TurnsLeft == 0 +end + +function CheckDeployedDead() + return deployedDead +end + +function DoDeployedDead() + ShowMission(loc("Backstab"), loc("Brutus"), loc("You have failed to save the tribe!"), 0, 6000) + ParseCommand("teamgone " .. loc("Natives")) + ParseCommand("teamgone " .. loc("Tribe")) + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function CheckChoice() + return choice ~= 0 and tmpVar == 0 +end + +function CheckDeaths() + for i = 1, 7 do + if natives[i] ~= spyHog and band(GetState(natives[i]), gstAttacked) ~= 0 then + return true + end + end + return false +end + +function DoChoice() + RemoveEventFunc(CheckChoiceRefuse) + SetGearMessage(CurrentHedgehog, 0) + SetupAfterChoiceAnim() + AddAnim(afterChoiceAnim) + AddFunction({func = AfterAfterChoiceAnim, args = {}}) +end + +function CheckChoiceRefuse() + return highJumped == true and StoppedGear(CurrentHedgehog) +end + +function DoChoiceRefuse() + choice = choiceSpare +end + +function CheckKilledOther() + if stage ~= spyKillStage then + return false + end + return (nativesNum < startNativesNum and choice ~= choiceEliminate) or + (nativesNum < startNativesNum - 1 and choice == choiceEliminate) +end + +function DoKilledOther() + ShowMission(loc("Backstab"), loc("Brutus"), loc("You have killed an innocent hedgehog!"), 0, 6000) + ParseCommand("teamgone " .. loc("Natives")) + ParseCommand("teamgone " .. loc("Tribe")) + TurnTimeLeft = 0 +end + +function CheckWaveDead(index) + for i = (index - 1) * 3 + 1, index * 3 do + if cannibalDead[i] ~= true or CurrentHedgehog == cannibals[i] then + return false + end + end + return true +end + +function DoWaveDead(index) + TurnTimeLeft = 0 + needToAct = index +end + +function AddWave3DeadAnim() + AnimSwitchHog(deployedHog) + AnimWait(deployedHog, 1) + AddFunction({func = HideNatives, args = {}}) + AddFunction({func = SetupWave3DeadAnim, args = {}}) + AddFunction({func = AddAnim, args = {wave3DeadAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterWave3DeadAnim, args = {}}}}) +end + +function HideNatives() + for i = 1, 9 do + if nativeDead[i] ~= true and natives[i] ~= deployedHog then + if nativeHidden[i] ~= true then + HideHog(natives[i]) + nativeHidden[i] = true + end + end + end +end + +function SetupWave3DeadAnim() + table.insert(wave3DeadAnim, {func = AnimTurn, args = {deployedHog, "Left"}}) + table.insert(wave3DeadAnim, {func = AnimSay, args = {deployedHog, loc("That ought to show them!"), SAY_SAY, 4000}}) + table.insert(wave3DeadAnim, {func = AnimSay, args = {deployedHog, loc("Guys, do you think there's more of them?"), SAY_SHOUT, 7000}}) + table.insert(wave3DeadAnim, {func = AnimVisualGear, args = {deployedHog, unpack(nativePos[wiseNum]), vgtFeather, 0, true, true}}) + table.insert(wave3DeadAnim, {func = AnimWait, args = {deployedHog, 1000}}) + table.insert(wave3DeadAnim, {func = AnimSay, args = {deployedHog, loc("Where are they?!"), SAY_THINK, 3000}}) + table.insert(wave3DeadAnim, {func = AnimCustomFunction, args = {deployedHog, RestoreCyborg, {}}}) + table.insert(wave3DeadAnim, {func = AnimOutOfNowhere, args = {cyborg, 4040, 782}}) + table.insert(wave3DeadAnim, {func = AnimSay, args = {cyborg, loc("These primitive people are so funny!"), SAY_THINK, 6500}}) + table.insert(wave3DeadAnim, {func = AnimMove, args = {cyborg, "Right", 4060, 0}}) + table.insert(wave3DeadAnim, {func = AnimSwitchHog, args = {deployedHog}}) + table.insert(wave3DeadAnim, {func = AnimWait, args = {deployedHog, 1}}) + table.insert(wave3DeadAnim, {func = AnimCustomFunction, args = {deployedHog, HideCyborg, {}}}) + table.insert(wave3DeadAnim, {func = AnimSay, args = {deployedHog, loc("I need to find the others!"), SAY_THINK, 4500}}) + table.insert(wave3DeadAnim, {func = AnimSay, args = {deployedHog, loc("I have to follow that alien."), SAY_THINK, 4500}}) +end + +function SkipWave3DeadAnim() + AnimSwitchHog(deployedHog) +end + +function AfterWave3DeadAnim() + if nativeDead[leaksNum] == true then + SaveCampaignVar("M5LeaksDead", "1") + else + SaveCampaignVar("M5LeaksDead", "0") + end + if nativeDead[denseNum] == true then + SaveCampaignVar("M5DenseDead", "1") + else + SaveCampaignVar("M5DenseDead", "0") + end + if nativeDead[waterNum] == true then + SaveCampaignVar("M5WaterDead", "1") + else + SaveCampaignVar("M5WaterDead", "0") + end + if nativeDead[buffaloNum] == true then + SaveCampaignVar("M5BuffaloDead", "1") + else + SaveCampaignVar("M5BuffaloDead", "0") + end + if nativeDead[girlNum] == true then + SaveCampaignVar("M5GirlDead", "1") + else + SaveCampaignVar("M5GirlDead", "0") + end + if nativeDead[wiseNum] == true then + SaveCampaignVar("M5WiseDead", "1") + else + SaveCampaignVar("M5WiseDead", "0") + end + if nativeDead[chiefNum] == true then + SaveCampaignVar("M5ChiefDead", "1") + else + SaveCampaignVar("M5ChiefDead", "0") + end + SaveCampaignVar("M5Choice", "" .. choice) + SaveCampaignVar("Progress", "5") + + for i = 1, 7 do + if natives[i] == deployedHog then + SaveCampaignVar("M5DeployedNum", "" .. i) + end + end + + ParseCommand("teamgone " .. loc("Tribe")) + ParseCommand("teamgone " .. loc("Assault Team")) + ParseCommand("teamgone " .. loc("Reinforcements")) + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +-----------------------------Misc-------------------------------------- + +function SpawnCrates() + SpawnAmmoCrate(0, 0, amDrill) + SpawnAmmoCrate(0, 0, amGrenade) + SpawnAmmoCrate(0, 0, amBazooka) + SpawnAmmoCrate(0, 0, amDynamite) + SpawnAmmoCrate(0, 0, amGrenade) + SpawnAmmoCrate(0, 0, amMine) + SpawnAmmoCrate(0, 0, amShotgun) + SpawnAmmoCrate(0, 0, amFlamethrower) + SpawnAmmoCrate(0, 0, amMolotov) + SpawnAmmoCrate(0, 0, amSMine) + SpawnAmmoCrate(0, 0, amMortar) + SpawnUtilityCrate(0, 0, amRope) + SpawnUtilityCrate(0, 0, amRope) + SpawnUtilityCrate(0, 0, amParachute) + SpawnUtilityCrate(0, 0, amParachute) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) +end + + +function RestoreWave(index) + for i = (index - 1) * 3 + 1, index * 3 do + if cannibalHidden[i] == true then + RestoreHog(cannibals[i]) + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + FollowGear(cannibals[i]) + cannibalHidden[i] = false + end + end +end + +function GetVariables() + m2DenseDead = tonumber(GetCampaignVar("M2DenseDead")) + m2Choice = tonumber(GetCampaignVar("M2Choice")) + m4DenseDead = tonumber(GetCampaignVar("M4DenseDead")) + m4LeaksDead = tonumber(GetCampaignVar("M4LeaksDead")) + m4ChiefDead = tonumber(GetCampaignVar("M4ChiefDead")) + m4WaterDead = tonumber(GetCampaignVar("M4WaterDead")) + m4BuffaloDead = tonumber(GetCampaignVar("M4BuffaloDead")) +end + +function HideCyborg() + if cyborgHidden == false then + HideHog(cyborg) + cyborgHidden = true + end +end + +function RestoreCyborg() + if cyborgHidden == true then + RestoreHog(cyborg) + cyborgHidden = false + end +end + +function SetupPlace() + startNativesNum = nativesNum + HideHog(cyborg) + cyborgHidden = true + for i = 1, 9 do + HideHog(cannibals[i]) + cannibalHidden[i] = true + end + if m4LeaksDead == 1 then + HideHog(natives[leaksNum]) + nativeHidden[leaksNum] = true + needRevival = true + end + if m4DenseDead == 1 then + if m2Choice ~= choiceAccepted then + DeleteGear(natives[denseNum]) + startNativesNum = startNativesNum - 1 + nativeDead[denseNum] = true + else + HideHog(natives[denseNum]) + nativeHidden[denseNum] = true + needRevival = true + end + end + if m4WaterDead == 1 then + HideHog(natives[waterNum]) + nativeHidden[waterNum] = true + needRevival = true + end + if m4ChiefDead == 1 then + DeleteGear(natives[chiefNum]) + startNativesNum = startNativesNum - 1 + nativeDead[chiefNum] = true + AnimSetGearPosition(natives[girlNum], unpack(nativePos[buffaloNum])) + nativePos[girlNum] = nativePos[buffaloNum] + end + if m4BuffaloDead == 1 then + startNativesNum = startNativesNum - 1 + nativeDead[buffaloNum] = true + DeleteGear(natives[buffaloNum]) + end + PlaceGirder(3568, 1461, 1) + PlaceGirder(440, 523, 5) + PlaceGirder(350, 441, 1) + PlaceGirder(405, 553, 5) + PlaceGirder(316, 468, 1) + PlaceGirder(1319, 168, 0) +end + +function SetupAmmo() + AddAmmo(natives[girlNum], amSwitch, 0) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 1, 7 do + natives[i] = AddHog(nativeNames[i], 0, 100, nativeHats[i]) + end + nativesNum = 7 + + AddTeam(loc("Tribe"), 29438, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 8, 9 do + natives[i] = AddHog(nativeNames[i], 0, 100, nativeHats[i]) + end + + + AddTeam(loc("Assault Team"), 14483456, "Skull", "Island", "Pirate", "cm_vampire") + for i = 1, 6 do + cannibals[i] = AddHog(cannibalNames[i], 1, 50, "vampirichog") + end + + AddTeam(loc("Reinforcements"), 14483456, "Skull", "Island", "Pirate", "cm_vampire") + for i = 7, 9 do + cannibals[i] = AddHog(cannibalNames[i], 1, 50, "vampirichog") + end + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Unit 334a$7%;.*"), 0, 200, "cyborg1") + + for i = 1, 9 do + AnimSetGearPosition(natives[i], unpack(nativePos[i])) + AnimTurn(natives[i], nativeDir[i]) + end + + AnimSetGearPosition(cyborg, 0, 0) + + for i = 1, 9 do + AnimSetGearPosition(cannibals[i], cannibalPos[i][1], cannibalPos[i][2] + 40) + AnimTurn(cannibals[i], cannibalDir[i]) + end +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 2 + GameFlags = gfSolidLand + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + Map = "Cave" + Theme = "Nature" + SuddenDeathTurns = 3000 + + AddHogs() + AnimInit() +end + +function onGameStart() + GetVariables() + SetupAmmo() + SetupPlace() + AnimationSetup() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + for i = 1, 7 do + if gear == natives[i] then + if nativeDead[i] ~= true then + freshDead = nativeNames[i] + end + nativeDead[i] = true + nativesNum = nativesNum - 1 + end + end + + for i = 1, 9 do + if gear == cannibals[i] then + cannibalDead[i] = true + end + end + + if gear == spyHog and stage == spyKillStage then + freshDead = nil + choice = choiceEliminate + tmpVar = 1 + end + + if gear == deployedHog then + deployedDead = true + end +end + +function onAmmoStoreInit() + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amSniperRifle, 4, 0, 0, 0) + SetAmmo(amFirePunch, 9, 0, 0, 0) + SetAmmo(amWhip, 9, 0, 0, 0) + SetAmmo(amBaseballBat, 9, 0, 0, 0) + SetAmmo(amHammer, 9, 0, 0, 0) + SetAmmo(amLandGun, 9, 0, 0, 0) + SetAmmo(amSnowball, 8, 0, 0, 0) + SetAmmo(amGirder, 4, 0, 0, 2) + SetAmmo(amParachute, 4, 0, 0, 2) + SetAmmo(amSwitch, 8, 0, 0, 2) + SetAmmo(amSkip, 8, 0, 0, 0) + SetAmmo(amRope, 5, 0, 0, 3) + SetAmmo(amBlowTorch, 3, 0, 0, 3) + SetAmmo(amPickHammer, 0, 0, 0, 3) + SetAmmo(amLowGravity, 0, 0, 0, 2) + SetAmmo(amDynamite, 0, 0, 0, 3) + SetAmmo(amBazooka, 4, 0, 0, 4) + SetAmmo(amGrenade, 4, 0, 0, 4) + SetAmmo(amMine, 2, 0, 0, 2) + SetAmmo(amSMine, 2, 0, 0, 2) + SetAmmo(amMolotov, 2, 0, 0, 3) + SetAmmo(amFlamethrower, 2, 0, 0, 3) + SetAmmo(amShotgun, 4, 0, 0, 4) + SetAmmo(amTeleport, 0, 0, 0, 2) + SetAmmo(amDrill, 0, 0, 0, 4) + SetAmmo(amMortar, 0, 0, 0, 4) +end + +j = 0 + +function onNewTurn() + tmpVar = 0 + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + + if GetHogTeamName(CurrentHedgehog) == loc("Tribe") then + TurnTimeLeft = 0 + return + end + TurnsLeft = TurnsLeft - 1 + + if stage == platformStage then + AddCaption(TurnsLeft .. " turns until arrival!") + end + + if stage == spyKillStage then + if CurrentHedgehog == spyHog or GetHogTeamName(CurrentHedgehog) ~= loc("Natives") then + TurnTimeLeft = 0 + else + SetGearMessage(CurrentHedgehog, 0) + --AnimSwitchHog(natives[leaksNum]) + TurnTimeLeft = -1 + end + else + if freshDead ~= nil and GetHogTeamName(CurrentHedgehog) == loc("Natives") then + SetupHogDeadAnim(freshDead) + AddAnim(hogDeadAnim) + AddFunction({func = AfterHogDeadAnim, args = {}}) + end + end + if needToAct > 0 then + if needToAct == 1 then + RestoreWave(2) + SetupWave2Anim() + AddAnim(wave2Anim) + AddFunction({func = AfterWave2Anim, args = {}}) + elseif needToAct == 2 then + SetupWave2DeadAnim() + AddAnim(wave2DeadAnim) + AddFunction({func = AfterWave2DeadAnim, args = {}}) + elseif needToAct == 3 then + AnimSwitchHog(deployedHog) + AddFunction({func = AddWave3DeadAnim, args = {}}) + end + needToAct = 0 + end +end + +function onPrecise() + if GameTime > 2500 and AnimInProgress() then + SetAnimSkip(true) + return + end + if stage == spyKillStage then + highJumped = true + end +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/campaign.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/campaign.ini Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,42 @@ +MissionNum=10 +ResetRetry=1 + +[Mission 1] +Name=First Blood +Script=first_blood.lua + +[Mission 2] +Name=The Shadow Falls +Script=shadow.lua + +[Mission 3] +Name=The Journey Back +Script=journey.lua + +[Mission 4] +Name=United We Stand +Script=united.lua + +[Mission 5] +Name=Backstab +Script=backstab.lua + +[Mission 6] +Name=Dragon's Lair +Script=dragon.lua + +[Mission 7] +Name=Family Reunion +Script=family.lua + +[Mission 8] +Name=Long Live The Queen +Script=queen.lua + +[Mission 9] +Name=The Enemy Of My Enemy +Script=enemy.lua + +[Mission 10] +Name=Epilogue +Script=epil.lua diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/dragon.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,648 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Map-------------------------------------- +local map = +{ + "\0\91\4\253\131\0\88\0\46\0\0\91\0\49\131\15\196\0\53\0\15\196\0\53\131\15\196\4\250\0\255\242\7\179\131\1\128\7\214\0", + "\1\113\7\207\131\3\182\7\157\0\3\175\7\143\131\6\58\7\200\0\6\76\7\193\131\6\188\7\129\0\6\188\7\129\131\6\248\6\216\0", + "\6\248\6\216\131\7\52\8\14\0\10\206\8\0\131\11\203\6\65\0\11\203\6\65\131\12\18\7\66\0\12\18\7\69\131\16\0\7\69\0", + "\0\109\1\1\131\2\111\0\49\0\2\111\0\49\131\3\133\1\18\0\3\140\1\18\131\4\162\0\165\0\4\162\0\165\131\5\135\1\29\0", + "\5\145\1\22\131\8\84\0\232\0\8\84\0\232\131\9\26\0\70\0\9\26\0\70\131\10\5\1\4\0\10\48\0\243\131\10\2\1\8\0", + "\10\58\0\243\131\10\118\1\15\0\10\118\1\15\131\10\234\1\173\0\11\10\1\177\131\12\11\1\22\0\12\39\1\40\131\12\243\2\9\0", + "\12\243\2\9\131\13\106\0\165\0\13\131\0\176\131\15\186\1\78\0\1\244\0\81\136\0\120\0\84\0\1\99\0\123\137\0\130\0\215\0", + "\0\158\0\130\143\0\158\0\130\0\2\216\0\88\138\4\165\0\102\0\4\91\0\127\142\3\129\0\197\0\3\69\0\134\142\3\69\0\134\0", + "\4\215\0\120\143\8\88\0\134\0\8\187\0\84\139\8\187\0\84\0\8\239\0\70\135\8\239\0\70\0\8\60\0\187\138\5\99\0\222\0", + "\5\61\0\197\138\5\61\0\197\0\9\99\0\81\137\10\23\0\218\0\9\187\0\77\137\11\31\1\117\0\10\30\0\88\137\15\161\0\109\0", + "\15\126\0\225\144\13\177\0\116\0\15\150\0\144\139\15\157\1\26\0\10\202\0\169\152\12\246\0\169\0\10\72\0\144\145\11\122\1\36\0", + "\11\17\1\121\141\11\17\1\121\0\12\229\1\194\138\12\229\1\194\0\12\208\1\85\150\12\208\1\85\0\12\148\1\15\147\12\148\1\15\0", + "\13\145\0\208\147\13\145\0\208\0\6\238\7\45\135\7\10\7\238\0\6\220\7\150\135\6\206\7\242\0\6\174\7\175\135\6\135\8\7\0", + "\6\118\7\214\135\6\62\7\238\0\6\30\7\245\140\3\217\7\210\0\3\161\7\221\138\255\252\7\231\0\15\242\7\165\148\11\115\7\175\0", + "\11\196\6\164\138\11\10\8\4\0\11\210\7\31\141\11\210\7\31\0\14\216\2\72\166\14\216\2\72\0\14\213\4\4\166\14\213\4\4\0", + "\13\216\1\159\148\13\216\1\159\0\13\159\2\143\148\13\159\2\143\0\13\230\3\69\145\13\230\3\69\0\13\163\4\11\145\13\166\4\11\0", + "\13\237\4\208\145\13\237\4\208\0\14\195\5\61\145\14\195\5\61\0\13\78\1\254\136\13\78\1\254\0\12\239\2\93\136\12\239\2\93\0", + "\12\250\2\227\136\12\250\2\227\0\13\71\3\59\136\13\71\3\59\0\13\1\3\168\136\13\1\3\168\0\12\243\4\32\136\12\246\4\32\0", + "\13\40\4\130\136\13\43\4\134\0\13\92\4\243\136\13\92\4\243\0\13\142\5\135\136\13\142\5\135\0\14\33\5\106\136\14\33\5\106\0", + "\14\111\5\208\136\14\121\5\216\0\15\13\5\237\136\15\13\5\237\0\15\73\5\128\136\15\73\5\128\0\15\84\4\243\136\15\84\4\243\0", + "\14\199\6\33\133\14\199\6\33\0\14\97\6\44\133\14\83\6\44\0\14\9\5\240\133\14\9\5\240\0\13\226\5\163\133\13\226\5\163\0", + "\13\170\5\233\133\13\170\5\233\0\13\71\5\205\133\13\71\5\205\0\13\61\5\117\133\13\61\5\117\0\13\22\5\40\133\13\22\5\40\0", + "\12\253\4\211\133\12\253\4\211\0\12\197\4\169\133\12\197\4\169\0\12\204\4\106\133\12\204\4\106\0\12\162\4\46\133\12\162\4\42\0", + "\12\194\3\200\133\12\194\3\196\0\12\201\3\84\133\12\201\3\84\0\12\253\3\62\133\12\253\3\62\0\12\169\2\241\133\12\169\2\241\0", + "\12\187\2\167\133\12\187\2\167\0\12\158\2\93\133\12\158\2\93\0\12\162\2\9\133\12\162\2\9\0\12\123\1\205\132\12\123\1\205\0", + "\12\84\1\251\132\12\84\1\251\0\12\91\2\55\132\12\95\2\55\0\12\63\2\139\132\12\63\2\139\0\12\120\2\164\132\12\120\2\164\0", + "\12\81\2\206\132\12\81\2\206\0\12\106\3\17\132\12\109\3\20\0\12\137\3\73\132\12\137\3\73\0\12\84\3\122\132\12\84\3\122\0", + "\12\137\3\150\132\12\137\3\150\0\12\95\3\217\132\12\95\3\217\0\12\134\3\231\132\12\134\3\231\0\12\106\4\63\132\12\106\4\63\0", + "\12\137\4\120\132\12\141\4\120\0\12\88\4\179\132\12\88\4\183\0\12\134\4\190\132\12\134\4\190\0\12\158\4\232\132\12\165\4\232\0", + "\12\215\5\15\132\12\215\5\15\0\12\91\4\243\130\12\91\4\243\0\12\144\5\26\130\12\144\5\26\0\12\176\5\54\130\12\176\5\54\0", + "\12\225\5\82\130\12\225\5\82\0\13\4\5\117\130\13\1\5\117\0\12\239\5\166\130\12\239\5\166\0\13\8\5\184\130\13\11\5\184\0", + "\13\8\5\226\130\13\8\5\226\0\13\54\6\12\130\13\57\6\12\0\13\106\6\2\130\13\106\5\254\0\13\138\6\12\130\13\138\6\12\0", + "\13\184\6\30\130\13\187\6\30\0\13\223\5\254\130\13\223\5\254\0\13\149\6\69\130\13\145\6\69\0\13\128\6\33\130\13\128\6\33\0", + "\13\85\6\40\130\13\85\6\40\0\12\232\6\2\130\12\232\6\2\0\12\204\5\205\130\12\204\5\201\0\12\183\5\159\130\12\183\5\156\0", + "\12\211\5\128\130\12\211\5\128\0\12\165\5\103\130\12\165\5\103\0\12\123\5\64\130\12\120\5\64\0\12\81\5\71\130\12\81\5\71\0", + "\12\84\5\18\130\12\84\5\18\0\12\39\4\243\130\12\39\4\243\0\12\35\4\194\130\12\35\4\194\0\12\63\4\127\130\12\63\4\127\0", + "\12\91\4\106\130\12\91\4\106\0\12\53\4\60\130\12\53\4\60\0\12\74\4\25\130\12\84\4\21\0\12\120\4\4\130\12\120\4\4\0", + "\12\42\3\231\130\12\42\3\231\0\12\39\3\189\130\12\42\3\186\0\12\60\3\175\130\12\60\3\175\0\12\39\3\133\130\12\39\3\133\0", + "\12\70\3\73\130\12\70\3\73\0\12\25\3\77\130\12\25\3\77\0\12\42\3\13\130\12\46\3\13\0\12\81\3\31\130\12\81\3\31\0", + "\12\32\2\213\130\12\32\2\213\0\12\14\2\178\130\12\14\2\178\0\12\42\2\181\130\12\46\2\181\0\12\14\2\128\130\12\14\2\128\0", + "\12\39\2\100\130\12\42\2\100\0\12\74\2\104\130\12\77\2\104\0\12\106\2\135\130\12\109\2\135\0\12\39\2\72\130\12\39\2\69\0", + "\12\35\2\37\130\12\35\2\37\0\12\32\2\2\130\12\32\2\2\0\12\28\1\226\130\12\28\1\223\0\12\63\1\208\130\12\63\1\208\0", + "\12\84\1\173\130\12\84\1\170\0\12\63\1\159\130\12\60\1\159\0\12\39\1\113\130\12\39\1\113\0\12\14\1\96\130\12\11\1\96\0", + "\11\228\1\131\130\11\228\1\135\0\12\7\1\149\130\12\7\1\149\0\12\21\1\177\130\12\25\1\177\0\11\242\1\201\130\11\242\1\201\0", + "\13\226\6\58\130\13\226\6\58\0\14\16\6\40\130\14\16\6\40\0\13\208\6\86\130\13\208\6\86\0\13\247\6\111\130\13\247\6\114\0", + "\13\184\6\121\130\13\184\6\121\0\13\198\6\146\130\13\201\6\146\0\13\244\6\139\130\13\244\6\139\0\13\223\6\185\130\13\223\6\185\0", + "\13\173\6\199\130\13\173\6\199\0\13\159\6\171\130\13\159\6\171\0\13\138\6\220\130\13\138\6\220\0\13\184\6\238\130\13\184\6\238\0", + "\13\208\6\223\130\13\208\6\223\0\13\216\7\10\130\13\216\7\10\0\13\184\7\10\130\13\180\7\10\0\13\142\7\38\130\13\142\7\41\0", + "\13\128\7\6\130\13\128\7\6\0\13\85\7\34\130\13\89\7\34\0\13\89\7\3\130\13\89\7\3\0\13\117\6\220\130\13\121\6\220\0", + "\13\75\6\195\130\13\75\6\195\0\13\110\6\164\130\13\110\6\164\0\13\156\6\125\130\13\156\6\125\0\13\106\6\135\130\13\106\6\135\0", + "\13\103\6\100\130\13\103\6\100\0\13\64\6\143\130\13\64\6\143\0\13\47\6\104\130\13\47\6\104\0\13\71\6\79\130\13\71\6\79\0", + "\13\40\6\65\130\13\36\6\65\0\13\8\6\44\130\13\1\6\44\0\13\8\6\76\130\13\8\6\76\0\13\1\6\132\130\13\1\6\132\0", + "\13\33\6\135\130\13\33\6\135\0\13\26\6\178\130\13\22\6\178\0\13\47\6\202\130\13\50\6\202\0\13\54\6\245\130\13\54\6\245\0", + "\13\22\7\3\130\13\22\7\3\0\13\43\7\27\130\13\43\7\27\0\12\253\6\248\130\12\250\6\248\0\12\253\6\220\130\12\253\6\220\0", + "\12\215\6\174\130\12\225\6\174\0\12\253\6\174\130\12\253\6\174\0\12\215\6\121\130\12\215\6\121\0\12\229\6\76\130\12\229\6\76\0", + "\12\201\6\51\130\12\201\6\51\0\12\190\6\19\130\12\190\6\19\0\12\151\5\223\130\12\151\5\223\0\12\148\5\194\130\12\151\5\194\0", + "\12\155\5\159\130\12\155\5\156\0\12\144\5\121\130\12\144\5\121\0\12\95\5\110\130\12\95\5\110\0\12\102\5\156\130\12\102\5\159\0", + "\12\99\5\216\130\12\106\5\219\0\12\148\6\40\130\12\148\6\40\0\12\127\6\19\130\12\127\6\19\0\12\176\6\104\130\12\176\6\104\0", + "\12\141\6\72\130\12\141\6\72\0\12\162\6\139\130\12\162\6\143\0\12\172\6\181\130\12\172\6\181\0\12\204\6\216\130\12\208\6\216\0", + "\12\201\7\3\130\12\201\7\3\0\12\236\7\24\130\12\236\7\24\0\12\120\6\146\130\12\120\6\146\0\12\123\6\104\130\12\123\6\104\0", + "\12\123\6\185\130\12\123\6\185\0\12\162\6\227\130\12\162\6\227\0\12\134\6\241\130\12\134\6\241\0\12\155\7\10\130\12\155\7\10\0", + "\12\190\7\41\130\12\190\7\41\0\11\228\1\96\129\11\228\1\96\0\11\200\1\121\129\11\200\1\121\0\11\193\1\156\129\11\196\1\156\0", + "\11\221\1\170\129\11\221\1\170\0\11\217\1\208\129\11\217\1\208\0\11\245\1\230\129\11\245\1\230\0\11\245\2\16\129\11\245\2\16\0", + "\12\14\2\62\129\12\18\2\62\0\11\242\2\93\129\11\242\2\93\0\11\235\2\178\129\11\235\2\178\0\11\231\2\238\129\11\235\2\238\0", + "\12\4\2\252\129\12\4\2\252\0\11\252\3\34\129\11\252\3\34\0\11\235\3\87\129\11\238\3\87\0\12\11\3\119\129\12\11\3\119\0", + "\12\4\3\168\129\12\4\3\168\0\11\245\3\200\129\11\245\3\200\0\11\252\3\238\129\11\252\3\242\0\12\11\4\7\129\12\11\4\7\0", + "\11\245\4\60\129\11\238\4\60\0\11\224\4\74\129\11\221\4\74\0\11\210\4\137\129\11\210\4\137\0\11\228\4\151\129\11\231\4\151\0", + "\11\242\4\130\129\11\242\4\130\0\12\4\4\113\129\12\7\4\113\0\12\28\4\102\129\12\28\4\102\0\12\11\4\141\129\12\11\4\141\0", + "\11\249\4\162\129\11\249\4\162\0\11\221\4\116\129\11\221\4\116\0\11\214\4\106\129\11\217\4\102\0\12\4\4\211\129\12\4\4\211\0", + "\11\249\5\8\129\11\252\5\8\0\12\39\5\11\129\12\42\5\11\0\12\56\5\50\129\12\60\5\47\0\12\46\5\96\129\12\49\5\96\0", + "\12\70\5\113\129\12\70\5\113\0\12\56\5\166\129\12\63\5\166\0\12\70\5\145\129\12\74\5\145\0\12\70\5\194\129\12\77\5\194\0", + "\12\70\5\237\129\12\74\5\237\0\12\106\5\240\129\12\109\5\240\0\12\99\6\33\129\12\99\6\33\0\12\88\6\72\129\12\88\6\72\0", + "\12\91\6\107\129\12\95\6\107\0\12\77\6\146\129\12\81\6\146\0\12\88\6\181\129\12\91\6\181\0\12\91\6\220\129\12\99\6\220\0", + "\12\113\7\10\129\12\116\7\10\0\8\116\4\18\179\8\116\4\18\0\9\205\3\73\156\9\205\3\73\0\10\83\2\146\144\10\83\2\146\0", + "\10\153\2\44\136\10\153\2\44\0\10\181\1\240\132\10\181\1\240\0\10\199\1\205\131\10\199\1\205\0\10\209\1\184\129\10\209\1\184\0", + "\8\42\2\167\150\8\42\2\167\0\8\53\1\240\141\8\53\1\237\0\8\67\1\135\134\8\67\1\135\0\11\224\5\8\129\11\224\5\8\0", + "\11\200\5\8\129\11\200\5\8\0\11\182\5\8\129\11\182\5\8\0\11\154\5\4\129\11\154\5\4\0\11\129\5\8\129\11\129\5\8\0", + "\11\119\3\84\129\11\119\3\84\0\11\140\3\87\129\11\140\3\87\0\11\165\3\87\129\11\165\3\87\0\11\182\3\87\129\11\182\3\87\0", + "\11\203\3\87\129\11\203\3\87\0\9\33\6\223\132\9\33\8\11\0\9\33\6\188\129\9\33\6\188\0\0\123\1\26\136\0\211\2\223\0", + "\0\211\2\223\136\0\120\3\84\0\0\130\3\101\136\0\211\4\53\0\0\204\4\53\136\0\120\4\151\0\0\130\3\193\136\0\127\4\63\0", + "\0\130\3\31\136\0\130\1\201\0\0\91\4\253\130\0\91\6\76\0\7\94\3\136\138\7\94\3\136\0\7\24\3\77\135\7\24\3\77\0", + "\6\238\3\24\132\6\241\3\24\0\6\223\2\238\131\6\223\2\238\0\6\220\2\209\129\6\220\2\209\0\7\87\4\14\133\7\87\4\14\0", + "\7\38\4\0\131\7\38\4\0\0\7\6\3\242\130\7\6\3\242\0\6\241\3\228\129\6\241\3\228\0\6\227\3\217\128\6\227\3\217\0", + "\0\109\4\197\135\0\162\5\99\0\0\144\5\121\135\0\123\6\9\0\0\127\5\92\135\0\127\5\92\0\0\127\5\54\135\0\127\5\54\0", + "\0\134\6\23\132\0\236\6\97\0\0\236\6\97\132\1\106\6\135\0\1\117\6\135\132\1\177\6\143\0\2\234\7\80\130\3\69\7\80\0", + "\3\69\7\80\130\3\84\7\101\0\3\84\7\101\130\3\87\7\129\0\3\87\7\129\130\3\84\7\150\0\0\183\5\103\130\1\92\5\159\0", + "\1\11\5\138\130\0\253\5\180\0\0\253\5\180\130\0\158\5\166\0\0\239\4\60\131\1\166\4\95\0\2\104\3\133\131\3\84\3\129\0", + "\4\162\2\181\131\4\162\3\147\0\3\115\2\26\131\4\74\2\30\0\2\23\1\54\131\2\230\1\54\0\0\204\2\5\131\1\194\2\5\0", + "\4\74\2\33\131\5\226\1\223\0\0\225\5\121\197\1\135\5\163\0\0\204\5\173\197\1\1\5\173\0\0\179\5\152\131\1\57\5\163\0", + "\1\57\5\159\131\1\106\5\219\0\0\165\5\226\130\0\253\5\230\0\0\253\5\230\130\1\8\5\159\0\1\254\6\86\131\1\254\6\86\0", + "\1\254\6\33\131\1\254\6\33\0\1\254\5\230\131\1\254\5\230\0\1\254\5\170\131\1\254\5\170\0\1\254\5\113\131\1\254\5\113\0", + "\1\251\6\5\129\1\251\6\5\0\1\254\5\201\129\1\254\5\201\0\1\254\5\138\129\1\254\5\138\0\1\254\6\58\129\1\254\6\58\0", + "\1\254\5\78\129\1\254\5\78\0\2\2\5\40\131\2\2\5\40\0\2\2\4\246\131\2\2\4\246\0\1\237\4\204\131\1\237\4\204\0", + "\2\40\4\190\131\2\40\4\190\0\6\160\7\52\223\7\27\7\126\0\1\219\4\172\204\1\219\4\172\0\2\37\4\183\197\2\37\4\183\0", + "\3\98\3\122\131\3\126\3\84\0\3\126\3\84\131\3\126\3\52\0\3\126\3\41\131\3\80\3\24\0\3\80\3\24\131\3\112\2\248\0", + "\3\112\2\248\131\3\98\2\188\0", +} + + +-----------------------------Constants--------------------------------- +choiceAccepted = 1 +choiceRefused = 2 +choiceAttacked = 3 + +choiceEliminate = 1 +choiceSpare = 2 + +leaksNum = 1 +denseNum = 2 +waterNum = 3 +buffaloNum = 4 +chiefNum = 5 +girlNum = 6 +wiseNum = 7 + +nativeNames = {loc("Leaks A Lot"), loc("Dense Cloud"), loc("Fiery Water"), + loc("Raging Buffalo"), loc("Righteous Beard"), loc("Fell From Grace"), + loc("Wise Oak")} + +nativeUnNames = {loc("Zork"), loc("Steve"), loc("Jack"), + loc("Lee"), loc("Elmo"), loc("Rachel"), + loc("Muriel")} + +nativeHats = {"Rambo", "RobinHood", "pirate_jack", "zoo_Bunny", "IndianChief", + "tiara", "AkuAku"} + +nativePos = {257, 1950} + +cyborgNames = {loc("Syntax Errol"), loc("Segmentation Paul"), loc("Unexpected Igor"), loc("Jeremiah")} +cyborgPos = {745, 1847} +cyborgsPos = {{2937, 831}, {2945, 1264}, {2335, 1701}, {448, 484}} +cyborgsDir = {"Left", "Left", "Left", "Right"} + +cratePos = { + {788, 1919, amGirder, 2}, {412, 1615, amGirder, 1}, + {209, 1474, amSniperRifle, 1}, {1178, 637, amDEagle, 1}, + {633, 268, amDEagle, 1}, {3016, 1545, amDEagle, 1}, + {249, 1377, amRope, 3}, {330, 1018, amGirder, 1}, + {888, 647, amRope, 3}, {2116, 337, amRope, 3}, + {1779, 948, amRope, 3}, {3090, 1066, amRope, 3}, + {947, 480, amBazooka, 3}, {1097, 480, amMortar, 3}, + {1139, 451, amSnowball, 3}, {1207, 468, amShotgun, 3}, + {1024, 393, amSniperRifle, 2}, {998, 391, amDynamite, 2}, + {1024, 343, amRope, 2}, {998, 341, amRope, 2} + } +reactions = {loc("Yeah, take that!"), loc("Bullseye"), loc("Die, die, die!")} + +secondPos = {{1010, 510}, {1067, 510}} +-----------------------------Variables--------------------------------- +natives = {} +native = nil + +cyborgs = {} +cyborg = {} +cyborgsLeft = 0 + +gearDead = {} +hedgeHidden = {} + +startAnim = {} +killAnim = {} +killedAnim = {} + +freshDead = nil +crates = {} +cratesNum = 0 +jetCrate = nil +-----------------------------Animations-------------------------------- +function EmitDenseClouds(dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + AnimInsertStepNext({func = AnimVisualGear, args = {native, GetX(native) + dif, GetY(native) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {native, GetX(native) + dif, GetY(native) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {native, GetX(native) + dif, GetY(native) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {native, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {native, GetX(native) + dif, GetY(native) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {native, GetX(native) + dif, GetY(native) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {native, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {native, GetX(native) + dif, GetY(native) + dif, vgtSteam, 0, true}, swh = false}) +end + +function AnimationSetup() + startAnim = {} + local m = m5DeployedNum + table.insert(startAnim, {func = AnimWait, args = {native, 3000}}) + table.insert(startAnim, {func = AnimCaption, args = {native, loc("With the rest of the tribe gone, it was up to ") .. nativeNames[m5DeployedNum] .. loc(" to save the village."), 5000}}) + table.insert(startAnim, {func = AnimCaption, args = {native, loc("But it proved to be no easy task!"), 2000}}) + for i = 1, 4 do + table.insert(startAnim, {func = FollowGear, swh = false, args = {cyborgs[i]}}) + table.insert(startAnim, {func = AnimWait, args = {native, 1000}}) + end + table.insert(startAnim, {func = FollowGear, swh = false, args = {native}}) + if m == leaksNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("What a strange cave!"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("Now how do I get on the other side?!"), SAY_THINK, 5500}}) + elseif m == denseNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("Dude, what's this place?!"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {native, EmitDenseClouds, {"Right"}}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("And where's all the weed?"), SAY_THINK, 4000}}) + elseif m == waterNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("Is this place in my head?"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("I shouldn't have drunk that last pint."), SAY_THINK, 6000}}) + elseif m == buffaloNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("Where did that alien run?"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("When I find it..."), SAY_THINK, 3000}}) + elseif m == girlNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("This is typical!"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("It's always up to women to clear up the mess men created!"), SAY_THINK, 8500}}) + elseif m == chiefNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("What is this place?"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("It doesn't matter. I won't let that alien hurt my daughter!"), SAY_THINK, 8500}}) + elseif m == wiseNum then + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 50, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("Every single time!"), SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimMove, args = {native, "Right", nativePos[1] + 200, 0}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("How come in a village full of warriors, it's up to me to save it?"), SAY_THINK, 8500}}) + end + + table.insert(startAnim, {func = AnimCustomFunction, args = {native, RestoreHedge, {cyborg, unpack(cyborgPos)}}}) + table.insert(startAnim, {func = AnimOutOfNowhere, args = {cyborg, unpack(cyborgPos)}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("Greetings, ") .. nativeUnNames[m] .. "!", SAY_SAY, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("As you can see, there is no way to get on the other side!"), SAY_SAY, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("I wish to help you, ") .. nativeUnNames[m] .. "!", SAY_SAY, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("Beware, though! If you are slow, you die!"), SAY_SAY, 7000}}) + table.insert(startAnim, {func = AnimDisappear, args = {cyborg, unpack(cyborgPos)}}) + table.insert(startAnim, {func = AnimSwitchHog, args = {native}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {native, HideHedge, {cyborg}}}) + table.insert(startAnim, {func = AnimSay, args = {native, loc("Talk about mixed signals..."), SAY_SAY, 4000}}) + AddSkipFunction(startAnim, SkipStartAnim, {}) +end + +function SetupKillAnim() + table.insert(killAnim, {func = AnimSay, args = {native, loc("Well, that was a waste of time."), SAY_THINK, 5000}}) + table.insert(killAnim, {func = AnimCustomFunction, args = {native, RestoreHedge, {cyborg, unpack(cyborgPos)}}}) + table.insert(killAnim, {func = AnimOutOfNowhere, args = {cyborg, unpack(cyborgPos)}}) + table.insert(killAnim, {func = AnimCustomFunction, args = {cyborg, CondNeedToTurn, {cyborg, native}}}) + table.insert(killAnim, {func = AnimSay, args = {cyborg, loc("You bear impressive skills, ") .. nativeUnNames[m5DeployedNum] .. "!", SAY_SHOUT, 4000}}) + table.insert(killAnim, {func = AnimSay, args = {cyborg, loc("However, my mates don't agree with me on letting you go..."), SAY_SHOUT, 7000}}) + table.insert(killAnim, {func = AnimSay, args = {cyborg, loc("I guess you'll have to kill them."), SAY_SHOUT, 4000}}) + table.insert(killAnim, {func = AnimDisappear, args = {cyborg, unpack(cyborgPos)}}) + table.insert(killAnim, {func = AnimSwitchHog, args = {native}}) + table.insert(killAnim, {func = AnimWait, args = {native, 1}}) + table.insert(killAnim, {func = AnimCustomFunction, args = {native, HideHedge, {cyborg}}}) + AddSkipFunction(killAnim, SkipKillAnim, {}) +end + +function SetupKilledAnim() + table.insert(killedAnim, {func = AnimWait, args = {cyborg, 500}}) + table.insert(killedAnim, {func = AnimOutOfNowhere, args = {cyborg, unpack(secondPos[2])}}) + table.insert(killedAnim, {func = AnimOutOfNowhere, args = {native, unpack(secondPos[1])}}) + table.insert(killedAnim, {func = AnimCustomFunction, args = {cyborg, CondNeedToTurn, {cyborg, native}}}) + table.insert(killedAnim, {func = AnimSay, args = {cyborg, loc("Nice work, ") .. nativeUnNames[m5DeployedNum] .. "!", SAY_SHOUT, 4000}}) + table.insert(killedAnim, {func = AnimSay, args = {cyborg, loc("As a reward for your performance, here's some new technology!"), SAY_SHOUT, 8000}}) + table.insert(killedAnim, {func = AnimSay, args = {cyborg, loc("Use it wisely!"), SAY_SHOUT, 3000}}) + table.insert(killedAnim, {func = AnimDisappear, args = {cyborg, unpack(secondPos[2])}}) + table.insert(killedAnim, {func = AnimSwitchHog, args = {native}}) + AddSkipFunction(killedAnim, SkipKilledAnim, {}) +end +--------------------------Anim skip functions-------------------------- +function SkipStartAnim() + AnimSwitchHog(native) + AnimWait(native, 1) + AddFunction({func = HideHedge, args = {cyborg}}) +end + +function AfterStartAnim() + SetGearMessage(native, 0) + cratesNum = 0 + for i = 1, 6 do + crates[i] = SpawnAmmoCrate(unpack(cratePos[i])) + cratesNum = cratesNum + 1 + end + FollowGear(native) + AddNewEvent(CheckGearsDead, {{crates[1], crates[2]}}, PutCrates, {2}, 0) + TurnTimeLeft = TurnTime + ShowMission(loc("Dragon's Lair"), loc("Obstacle course"), loc("In order to get to the other side, you need to collect the crates first.|") .. + loc("As the ammo is sparse, you might want to reuse ropes while mid-air.|") .. + loc("If you wish to restart the course, hold [Precise] while your turn ends (e.g with Skip)!|") .. + loc("The enemy can't move but it might be a good idea to stay out of sight!|") .. + loc("You have ") .. SuddenDeathTurns .. loc(" turns until Sudden Death! Better hurry!"), 1, 0) +end + +function SkipKillAnim() + AnimSwitchHog(native) + AnimWait(native, 1) + AddFunction({func = HideHedge, args = {cyborg}}) +end + +function AfterKillAnim() + PutWeaponCrates() + TurnTimeLeft = TurnTime + AddEvent(CheckCyborgsDead, {}, DoCyborgsDead, {}, 0) + ShowMission(loc("Dragon's Lair"), loc("The Slaughter"), loc("Kill the aliens!"), 1, 2000) +end + +function SkipKilledAnim() + AnimSetGearPosition(native, unpack(secondPos[1])) + AnimSwitchHog(native) + AnimWait(native, 1) +end + +function AfterKilledAnim() + HideHedge(cyborg) + TurnTimeLeft = TurnTime + SetGearMessage(native, 0) + AddAmmo(native, amPortalGun, 100) + SpawnUtilityCrate(2259, 755, amTeleport, 2) + SpawnHealthCrate(secondPos[1][1] + 30, secondPos[1][2]) + ShowMission(loc("Dragon's Lair"), loc("The what?!"), loc("Use the portal gun to get to the next crate, then use the new gun to get to the final destination!|").. + loc("Portal hint: one goes to the destination, and one is the entrance.|").. + loc("Teleport hint: just use the mouse to select the destination!"), 1, 0) +end +-----------------------------Events------------------------------------ + +function CheckCyborgsDead() + return cyborgsLeft == 0 +end + +function NullifyAmmo() + AddAmmo(native, amRope, 0) + AddAmmo(native, amGirder, 0) + AddAmmo(native, amLowGravity, 0) + AddAmmo(native, amBazooka, 0) + AddAmmo(native, amSniperRifle, 0) + AddAmmo(native, amDEagle, 0) + AddAmmo(native, amDynamite, 0) + AddAmmo(native, amFirePunch, 0) + AddAmmo(native, amBaseballBat, 0) + AddAmmo(native, amMortar, 0) + AddAmmo(native, amSnowball, 0) + AddAmmo(native, amShotgun, 0) +end + +function DoCyborgsDead() + NullifyAmmo() + RestoreHedge(cyborg) + SetupKilledAnim() + SetGearMessage(CurrentHedgehog, 0) + AddAnim(killedAnim) + AddFunction({func = AfterKilledAnim, args = {}}) +end + + +function PutWeaponCrates() + for i = 1, 8 do + cratesNum = cratesNum + 1 + crates[cratesNum] = SpawnAmmoCrate(unpack(cratePos[cratesNum])) + end + FollowGear(native) +end + +function DoCratesTaken() + SetupKillAnim() + SetGearMessage(CurrentHedgehog, 0) + AddAnim(killAnim) + AddFunction({func = AfterKillAnim, args = {}}) +end + +function PutCrates(index) + if index <= 7 then + cratesNum = cratesNum + 1 + crates[cratesNum] = SpawnUtilityCrate(unpack(cratePos[cratesNum])) + AddNewEvent(CheckGearDead, {crates[cratesNum]}, PutCrates, {index + 1}, 0) + FollowGear(native) + else + AddEvent(StoppedGear, {native}, DoCratesTaken, {}, 0) + end + if index == 4 then + AnimSay(native, loc("I'm a ninja."), SAY_THINK, 0) + end +end + +function CheckMissionFinished() + return gearDead[jetCrate] == true +end + +function DoMissionFinished() + AddCaption(loc("Salvation was one step closer now...")) + SaveCampaignVar("Progress", "6") + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function CheckGearsDead(gearList) + for i = 1, # gearList do + if gearDead[gearList[i]] ~= true then + return false + end + end + return true +end + + +function CheckGearDead(gear) + return gearDead[gear] +end + +function EndMission() + ParseCommand("teamgone " .. loc("Natives")) + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function CheckFreshDead() + return freshDead ~= nil +end + +function CyborgDeadReact() + freshDead = nil + if cyborgsLeft == 0 then + return + end + AnimSay(native, reactions[cyborgsLeft]) +end +-----------------------------Misc-------------------------------------- +function HideHedge(hedge) + if hedgeHidden[hedge] ~= true then + HideHog(hedge) + hedgeHidden[hedge] = true + end +end + +function RestoreHedge(hedge) + if hedgeHidden[hedge] == true then + RestoreHog(hedge) + hedgeHidden[hedge] = false + end +end + +function GetVariables() + m5DeployedNum = tonumber(GetCampaignVar("M5DeployedNum")) +end + +function SetupPlace() + for i = 1, 7 do + if i ~= m5DeployedNum then + DeleteGear(natives[i]) + else + native = natives[i] + end + end + HideHedge(cyborg) + jetCrate = SpawnUtilityCrate(3915, 1723, amJetpack) + + SetTimer(AddGear(1071, 1913, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1098, 1919, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1136, 1923, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1170, 1930, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1203, 1924, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1228, 1939, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1264, 1931, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1309, 1938, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1352, 1936, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1386, 1939, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1432, 1942, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1483, 1950, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1530, 1954, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1579, 1959, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1000, 1903, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(957, 1903, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(909, 1910, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(889, 1917, gtMine, 0, 0, 0, 0), 5000) + ------ STICKY MINE LIST ------ + tempG = AddGear(1199, 733, gtSMine, 0, 0, 0, 0) + tempG = AddGear(1195, 793, gtSMine, 0, 0, 0, 0) + tempG = AddGear(1201, 861, gtSMine, 0, 0, 0, 0) + tempG = AddGear(682, 878, gtSMine, 0, 0, 0, 0) + tempG = AddGear(789, 876, gtSMine, 0, 0, 0, 0) +end + +function SetupEvents() + AddNewEvent(CheckMissionFinished, {}, DoMissionFinished, {}, 0) + AddNewEvent(CheckGearDead, {native}, EndMission, {}, 0) + AddNewEvent(CheckFreshDead, {}, CyborgDeadReact, {}, 1) +end + +function SetupAmmo() + AddAmmo(cyborgs[1], amBazooka, 100) +-- AddAmmo(cyborgs[1], amSniperRifle, 100) + AddAmmo(cyborgs[1], amShotgun, 100) + AddAmmo(cyborgs[1], amSwitch, 100) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 1, 7 do + natives[i] = AddHog(nativeNames[i], 0, 200, nativeHats[i]) + gearDead[natives[i]] = false + end + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Unit 334a$7%;.*"), 0, 200, "cyborg1") + gearDead[cyborg] = false + + AddTeam(loc("011101000"), 14483455, "ring", "UFO", "Robot", "cm_star") + for i = 1, 4 do + cyborgs[i] = AddHog(cyborgNames[i], 2, 100, "cyborg2") + gearDead[cyborgs[i]] = false + end + cyborgsLeft = 4 + + for i = 1, 7 do + AnimSetGearPosition(natives[i], unpack(nativePos)) + end + + AnimSetGearPosition(cyborg, unpack(cyborgPos)) + + for i = 1, 4 do + AnimSetGearPosition(cyborgs[i], unpack(cyborgsPos[i])) + AnimTurn(cyborgs[i], cyborgsDir[i]) + end + +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 0 + GameFlags = gfSolidLand + gfDisableLandObjects + gfDisableWind + gfDisableGirders + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 20 + MinesTime = 3000 + Explosives = 6 + Delay = 10 + MapGen = 2 + Theme = "City" + SuddenDeathTurns = 25 + + for i = 1, #map do + ParseCommand('draw ' .. map[i]) + end + + AddHogs() + AnimInit() +end + +function onGameStart() + GetVariables() + SetupAmmo() + SetupPlace() + AnimationSetup() + SetupEvents() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) + ShowMission(loc("Dragon's Lair"), loc("Y Chwiliad"), loc("Find your tribe!|Cross the lake!"), 1, 0) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + gearDead[gear] = true + if GetGearType(gear) == gtHedgehog then + if GetHogTeamName(gear) == loc("011101000") then + freshDead = GetHogName(gear) + cyborgsLeft = cyborgsLeft - 1 + end + end +end + +function onAmmoStoreInit() + SetAmmo(amFirePunch, 3, 0, 0, 0) + SetAmmo(amBaseballBat, 2, 0, 0, 0) + SetAmmo(amGirder, 0, 0, 0, 2) + SetAmmo(amLowGravity, 0, 0, 0, 1) + SetAmmo(amSkip, 9, 0, 0, 0) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + if GetHogTeamName(CurrentHedgehog) == loc("011101000") then + SetInputMask(band(0xFFFFFFFF, bnot(gmLeft + gmRight + gmLJump + gmHJump))) + for i = 1, 4 do + if gearDead[CurrentHedgehog] ~= true and gearDead[native] ~= true then + if gearDead[cyborgs[i]] ~= true and GetX(cyborgs[i]) < GetX(native) then + HogTurnLeft(cyborgs[i], false) + else + HogTurnLeft(cyborgs[i], true) + end + end + end + if TotalRounds % 6 == 0 then + AddAmmo(CurrentHedgehog, amSniperRifle, 1) + AddAmmo(CurrentHedgehog, amDEagle, 1) + end + TurnTimeLeft = 30000 + elseif GetHogTeamName(CurrentHedgehog) == loc("011101001") then + TurnTimeLeft = 0 + else + SetInputMask(0xFFFFFFFF) + AddCaption(loc("Turns until Sudden Death: ") .. SuddenDeathTurns - TotalRounds) + end +end + +function onPrecise() + if GameTime > 2500 and AnimInProgress() then + SetAnimSkip(true) + end + if AnimInProgress() == false then + end +end + +function onPreciseUp() +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/enemy.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,663 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + + +--------------------------------------------Constants------------------------------------ +choiceAccepted = 1 +choiceRefused = 2 +choiceAttacked = 3 + +choiceEliminate = 1 +choiceSpare = 2 + +leaksNum = 1 +denseNum = 2 +waterNum = 3 +buffaloNum = 4 +chiefNum = 5 +girlNum = 6 +wiseNum = 7 +ramonNum = 8 +spikyNum = 9 + +denseScene = 1 +princessScene = 2 +waterScene = 3 +cyborgScene = 4 + +nativeNames = {loc("Leaks A Lot"), loc("Dense Cloud"), loc("Fiery Water"), + loc("Raging Buffalo"), loc("Righteous Beard"), loc("Fell From Grace"), + loc("Wise Oak"), loc("Ramon"), loc("Spiky Cheese") + } + +nativeHats = {"Rambo", "RobinHood", "pirate_jack", "zoo_Bunny", "IndianChief", + "tiara", "AkuAku", "rasta", "hair_yellow"} + +nativePos = {{1259, 120}, {2378, 796}, {424, 1299}, {3322, 260}, {1022, 1550}} +nativeDir = {"Right", "Left", "Right", "Left", "Right"} + +cannibalNames = {loc("Honest Lee"), loc("Vegan Jack"), loc("Sirius Lee"), + loc("Brutal Lily")} +cannibalPos = {{162, 266}, {2159, 1517}, {3311, 1621}, {1180, 1560}} +cannibalDir = {"Right", "Left", "Left", "Right"} +cannibalsNum = 4 + +playersDir = {"Right", "Left", "Right", "Left", "Right", "Right", "Left", "Left", "Right"} +playersAntiDir = {"Left", "Right", "Left", "Right", "Left", "Left", "Right", "Right", "Left"} + +cyborgNames = {loc("Smith 0.97"), loc("Smith 0.98"), loc("Smith 0.99a"), + loc("Smith 0.99b"), loc("Smith 0.99f"), loc("Smith 1.0")} +cyborgPos = {{2162, 20}, {2458, 564}, {542, 1133}, {3334, 1427}} +cyborgDir = "Right" +cyborgsNum = 6 +cyborgsPos = {{1490, 330}, {1737, 1005}, {2972, 922}, {1341, 1571}, + {751, 543}, {3889, 907}} +cyborgsDir = {"Right", "Right", "Left", "Right", "Right", "Left"} + +leaderPos = {3474, 151} +leaderDir = "Left" + +-----------------------------Variables--------------------------------- +natives = {} +origNatives = {} + +cyborgs = {} +cyborg = nil + +cannibals = {} +players = {} +leader = nil + +gearDead = {} +hedgeHidden = {} + +startAnim = {} +finalAnim = {} +-----------------------------Animations-------------------------------- +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +function CondNeedToTurn2(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimTurn(hog1, "Left") + AnimTurn(hog2, "Right") + elseif xl < xd then + AnimTurn(hog2, "Left") + AnimTurn(hog1, "Right") + end +end + +function EmitDenseClouds(dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + if dir == nil then + dx, dy = GetGearVelocity(dense) + if dx < 0 then + dif = 10 + else + dif = -10 + end + end + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) +end + +function RestoreNatives(cgi) + for i = 1, playersNum do + RestoreHedge(players[i]) + AnimOutOfNowhere(players[i], GetGearPosition(players[i])) + end +end + +function AnimationSetup() + SetupCyborgStartAnim() + SetupPeopleStartAnim() + SetupEnemyStartAnim() + AddSkipFunction(startAnim, SkipStartAnim, {}) +end + +function SetupCyborgStartAnim() + table.insert(startAnim, {func = AnimWait, args = {cyborg, 3000}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Right"}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimTeleportGear, args = {cyborg, unpack(cyborgPos[2])}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Right"}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimTeleportGear, args = {cyborg, unpack(cyborgPos[3])}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 1800}}) + table.insert(startAnim, {func = AnimTeleportGear, args = {cyborg, unpack(cyborgPos[4])}}) + table.insert(startAnim, {func = AnimWait, args = {cyborg, 800}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("Everything looks OK..."), SAY_THINK, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("This will be fun!"), SAY_THINK, 2500}}) + table.insert(startAnim, {func = AnimJump, args = {cyborg, "high"}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {cyborg, RestoreNatives, {true}}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("HAHA!"), SAY_SHOUT, 2000}}) + table.insert(startAnim, {func = AnimSwitchHog, args = {players[1]}}) + table.insert(startAnim, {func = AnimDisappear, swh = false, args = {cyborg, unpack(cyborgPos[4])}}) + table.insert(startAnim, {func = HideHedge, swh = false, args = {cyborg}}) +end + +function SetupPeopleStartAnim() + for i = 1, playersNum do + table.insert(startAnim, {func = AnimTurn, swh = false, args = {players[i], playersAntiDir[i]}}) + end + table.insert(startAnim, {func = AnimWait, args = {players[1], 800}}) + for i = 1, playersNum do + table.insert(startAnim, {func = AnimTurn, swh = false, args = {players[i], playersDir[i]}}) + end + table.insert(startAnim, {func = AnimWait, args = {players[1], 800}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("What is this place?"), SAY_SHOUT, 2500}}) + if m5LeaksDead == 1 then + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("And how am I alive?!"), SAY_SAY, 3000}}) + end + table.insert(startAnim, {func = AnimCustomFunction, args = {players[1], CondNeedToTurn, {players[1], players[2]}}}) + table.insert(startAnim, {func = AnimSay, args = {players[2], loc("It must be the cyborgs again!"), SAY_SAY, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {players[3], loc("Looks like the whole world is falling apart!"), SAY_SAY, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("Look out! We're surrounded by cannibals!"), SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {players[4], CondNeedToTurn, {players[4], cannibals[1]}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {players[4], CondNeedToTurn, {players[1], cannibals[1]}}}) + table.insert(startAnim, {func = AnimSay, args = {players[4], loc("Cannibals?! You're the cannibals!"), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("WHAT?! You're the ones attacking us!"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {players[4], loc("You have kidnapped our whole tribe!"), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("You've been assaulting us, we have been just defending ourselves!"), SAY_SHOUT, 8000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("I can't believe this!"), SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("Have we ever attacked you first?"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {players[4], loc("Yes!"), SAY_SHOUT, 2000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("When?"), SAY_SHOUT, 2000}}) + table.insert(startAnim, {func = AnimSay, args = {players[4], loc("Uhmm...ok no."), SAY_SHOUT, 2000}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("But you're cannibals. It's what you do."), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("Again with the 'cannibals' thing!"), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("Where do you get that?!"), SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {players[4], loc("Everyone knows this."), SAY_SHOUT, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("I didn't until about a month ago."), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {players[4], loc("Hmmm...actually...I didn't either."), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("About a month ago, a cyborg came and told us that you're the cannibals!"), SAY_SHOUT, 8000}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("A cy-what?"), SAY_SHOUT, 2000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("Cyborg. It's what the aliens call themselves."), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("They told us to wear these clothes. They said that this is the newest trend."), SAY_SHOUT, 8000}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("They've been manipulating us all this time!"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("They must be trying to weaken us!"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("We have to unite and defeat those cylergs!"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {cannibals[1], loc("We can't let them take over our little island!"), SAY_SHOUT, 5000}}) +end + +function RestoreCyborgs(cgi) + if cyborgsRestored == true then + return + end + for i = 1, cyborgsNum do + RestoreHedge(cyborgs[i]) + if cgi == true then + AnimOutOfNowhere(cyborgs[i], unpack(cyborgsPos[i])) + end + end + RestoreHedge(leader) + AnimOutOfNowhere(leader, unpack(leaderPos)) + cyborgsRestored = true +end + +function SetupEnemyStartAnim() + local gear + table.insert(startAnim, {func = AnimCustomFunction, args = {cannibals[1], RestoreCyborgs, {true}}}) + if m8EnemyFled == 1 then + gear = leader + else + gear = cyborgs[2] + end + table.insert(startAnim, {func = AnimCustomFunction, args = {players[1], CondNeedToTurn, {players[4], gear}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {players[1], CondNeedToTurn, {players[1], gear}}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("You have finally figured it out!"), SAY_SHOUT, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("You meatbags are pretty slow, you know!"), SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("Why do you want to take over our island?"), SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("Do you have any idea how valuable grass is?"), SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("This island is the only place left on Earth with grass on it!"), SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("It's worth more than wood!"), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("That makes it almost invaluable!"), SAY_SHOUT, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("We have nowhere else to live!"), SAY_SHOUT, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {gear, loc("That's not our problem!"), SAY_SHOUT, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {players[1], loc("We'll give you a problem then!"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSwitchHog, args = {gear}}) +end + +function SetupFinalAnim() + finalAnim = { + {func = AnimGearWait, args = {cyborg, 1000}}, + {func = AnimSay, args = {cyborg, loc("Nicely done, meatbags!"), SAY_SAY, 3000}}, + {func = AnimSay, args = {cyborg, loc("You have won the game by proving true cooperative skills!"), SAY_SAY, 7000}}, + {func = AnimSay, args = {cyborg, loc("You have proven yourselves worthy!"), SAY_SAY, 4000}}, + {func = AnimSay, args = {players[1], loc("Game? Was this a game to you?!"), SAY_SAY, 4000}}, + {func = AnimSay, args = {cyborg, loc("Well, yes. This was a cyborg television show."), SAY_SAY, 5500}}, + {func = AnimSay, args = {cyborg, loc("It is called 'Hogs of Steel'."), SAY_SAY, 4000}}, + {func = AnimSay, args = {players[1], loc("Are you saying that many of us have died for your entertainment?"), SAY_SAY, 8000}}, + {func = AnimSay, args = {players[1], loc("Our tribe, our beautiful island!"), SAY_SAY, 4000}}, + {func = AnimSay, args = {players[1], loc("All gone...everything!"), SAY_SAY, 3000}}, + {func = AnimSay, args = {cyborg, loc("But the ones alive are stronger in their heart!"), SAY_SAY, 6000}}, + {func = AnimSay, args = {cyborg, loc("Just kidding, none of you have died!"), SAY_SAY, 5000}}, + {func = AnimSay, args = {cyborg, loc("I mean, none of you ceased to live."), SAY_SAY, 5000}}, + {func = AnimSay, args = {cyborg, loc("You'll see what I mean!"), SAY_SAY, 4000}}, + {func = AnimSay, args = {cyborg, loc("They are all waiting back in the village, haha."), SAY_SAY, 7000}}, + {func = AnimSay, args = {players[1], loc("You are playing with our lives here!"), SAY_SAY, 6000}}, + {func = AnimSay, args = {players[1], loc("Do you think you're some kind of god?"), SAY_SAY, 6000}}, + {func = AnimSay, args = {cyborg, loc("Interesting idea, haha!"), SAY_SAY, 2000}}, + {func = AnimSwitchHog, args = {players[1]}}, + {func = AnimWait, args = {players[1], 1}}, + {func = AnimDisappear, swh = false, args = {cyborg, unpack(cyborgPos[4])}}, + {func = HideHedge, swh = false, args = {cyborg}}, + {func = AnimSay, args = {players[1], loc("What a douche!"), SAY_SAY, 2000}}, + } +end +--------------------------Anim skip functions-------------------------- +function SkipStartAnim() + RestoreNatives() + RestoreCyborgs() + SetGearMessage(CurrentHedgehog, 0) + AnimSwitchHog(cyborgs[1]) + AnimWait(cyborg, 1) + AddFunction({func = HideHedge, args = {cyborg}}) +end + +function AfterStartAnim() + ShowMission(loc("The Enemy Of My Enemy"), loc("The Union"), loc("Defeat the cyborgs!"), 1, 0) + PutWeaponCrates() + PutHealthCrates() + TurnTimeLeft = 0 +end + +function PutHealthCrates() + for i = 1, 10 do + SpawnHealthCrate(0, 0) + end +end + +function PutWeaponCrates() + SpawnAmmoCrate(2399, 622, amNapalm, 2) + SpawnAmmoCrate(2199, -18, amBee, 2) + SpawnAmmoCrate(2088, 430, amBee, 2) + SpawnAmmoCrate(237, 20, amMortar, 4) + SpawnAmmoCrate(312, 1107, amMolotov, 3) + SpawnAmmoCrate(531, 1123, amWatermelon, 2) + SpawnAmmoCrate(1253, 1444, amFlamethrower, 5) + SpawnAmmoCrate(994, 1364, amBaseballBat, 3) + SpawnAmmoCrate(1104, 1553, amMine, 6) + SpawnAmmoCrate(2277, 803, amDynamite, 2) + SpawnAmmoCrate(1106, 184, amRCPlane, 3) + SpawnAmmoCrate(1333, 28, amSMine, 4) + SpawnAmmoCrate(90, 279, amAirAttack, 2) + SpawnAmmoCrate(288, 269, amBee, 2) + SpawnAmmoCrate(818, 1633, amBaseballBat, 2) +end +-----------------------------Events------------------------------------ +function CheckNativesDead() + return nativesLeft == 0 +end + +function CheckCannibalsDead() + return cannibalsLeft == 0 +end + +function CheckPlayersDead() + return playersLeft == 0 +end + +function CheckCyborgsDead() + return (cyborgsLeft == 0 and (leader == nil or gearDead[leader] == true)) +end + +function DoNativesDead() + nativesDeadFresh = true + TurnTimeLeft = 0 +end + +function DoCannibalsDead() + cannibalsDeadFresh = true + TurnTimeLeft = 0 +end + +function DoPlayersDead() + RemoveEventFunc(CheckNativesDead) + RemoveEventFunc(CheckCannibalsDead) + RemoveEventFunc(CheckCyborgsDead) + playersDeadFresh = true + TurnTimeLeft = 0 +end + +function DoCyborgsDead() +-- RemoveEventFunc(CheckNativesDead) +-- RemoveEventFunc(CheckCannibalsDead) + cyborgsDeadFresh= true + TurnTimeLeft = 0 +end + +function CheckGearsDead(gearList) + for i = 1, # gearList do + if gearDead[gearList[i]] ~= true then + return false + end + end + return true +end + +function CheckGearDead(gear) + return gearDead[gear] +end + +function FailedMission() + RestoreHedge(cyborg) + AnimOutOfNowhere(cyborg, unpack(cyborgPos[1])) + if CheckCyborgsDead() then + AnimSay(cyborg, loc("Hmmm...it's a draw. How unfortunate!"), SAY_THINK, 6000) + elseif leader ~= nil then + CondNeedToTurn2(cyborg, leader) + AddAnim({{func = AnimSay, args = {leader, loc("Yay, we won!"), SAY_SAY, 2000}}, + {func = AnimSay, args = {cyborg, loc("Nice work!"), SAY_SAY, 2000}}}) + else + CondNeedToTurn2(cyborg, cyborgs[1]) + AddAnim({{func = AnimSay, args = {cyborgs[1], loc("Yay, we won!"), SAY_SAY, 2000}}, + {func = AnimSay, args = {cyborg, loc("Nice work!"), SAY_SAY, 2000}}}) + end + AddFunction({func = LoseMission, args = {}}) +end + +function LoseMission() + ParseCommand("teamgone " .. loc("Natives")) + ParseCommand("teamgone " .. loc("Cannibals")) + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function WonMission() + RestoreHedge(cyborg) + CondNeedToTurn2(cyborg, players[1]) + SetupFinalAnim() + AddAnim(finalAnim) + AddFunction({func = WinMission, args = {}}) +end + +function WinMission() + SaveCampaignVar("Progress", "9") + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end +-----------------------------Misc-------------------------------------- +function HideHedge(hedge) + if hedgeHidden[hedge] ~= true then + HideHog(hedge) + hedgeHidden[hedge] = true + end +end + +function RestoreHedge(hedge) + if hedgeHidden[hedge] == true then + RestoreHog(hedge) + hedgeHidden[hedge] = false + end +end + +function GetVariables() + m5DeployedNum = tonumber(GetCampaignVar("M5DeployedNum")) + m2Choice = tonumber(GetCampaignVar("M2Choice")) + m5Choice = tonumber(GetCampaignVar("M5Choice")) + m2DenseDead = tonumber(GetCampaignVar("M2DenseDead")) + m4DenseDead = tonumber(GetCampaignVar("M4DenseDead")) + m5DenseDead = tonumber(GetCampaignVar("M5DenseDead")) + m4LeaksDead = tonumber(GetCampaignVar("M4LeaksDead")) + m5LeaksDead = tonumber(GetCampaignVar("M5LeaksDead")) + m4ChiefDead = tonumber(GetCampaignVar("M4ChiefDead")) + m5ChiefDead = tonumber(GetCampaignVar("M5ChiefDead")) + m4WaterDead = tonumber(GetCampaignVar("M4WaterDead")) + m5WaterDead = tonumber(GetCampaignVar("M5WaterDead")) + m4BuffaloDead = tonumber(GetCampaignVar("M4BuffaloDead")) + m5BuffaloDead = tonumber(GetCampaignVar("M5BuffaloDead")) + m5WiseDead = tonumber(GetCampaignVar("M5WiseDead")) + m5GirlDead = tonumber(GetCampaignVar("M5GirlDead")) + m8DeployedDead = tonumber(GetCampaignVar("M8DeployedDead")) + m8PrincessDead = tonumber(GetCampaignVar("M8PrincessDead")) + m8RamonDead = tonumber(GetCampaignVar("M8RamonDead")) + m8SpikyDead = tonumber(GetCampaignVar("M8SpikyDead")) + m8DeployedLeader = tonumber(GetCampaignVar("M8DeployedLeader")) + m8PrincessLeader = tonumber(GetCampaignVar("M8PrincessLeader")) + m8EnemyFled = tonumber(GetCampaignVar("M8EnemyFled")) + m8Scene = tonumber(GetCampaignVar("M8Scene")) +end + +function SetupPlace() + for i = 1, playersNum do + HideHedge(players[i]) + end + for i = 1, cyborgsNum do + HideHedge(cyborgs[i]) + end + if leader ~= nil then + HideHedge(leader) + end +end + +function SetupEvents() + AddNewEvent(CheckPlayersDead, {}, DoPlayersDead, {}, 0) + AddNewEvent(CheckNativesDead, {}, DoNativesDead, {}, 0) + AddNewEvent(CheckCannibalsDead, {}, DoCannibalsDead, {}, 0) + AddNewEvent(CheckCyborgsDead, {}, DoCyborgsDead, {}, 0) +end + +function SetupAmmo() + AddAmmo(cyborgs[1], amClusterBomb, 100) + AddAmmo(cyborgs[1], amMortar, 100) + AddAmmo(cyborgs[1], amDynamite, 2) + AddAmmo(cyborgs[1], amAirAttack, 2) + AddAmmo(cyborgs[1], amTeleport, 100) + + if leader ~= nil then + AddAmmo(leader, amClusterBomb, 100) + AddAmmo(leader, amMortar, 100) + AddAmmo(leader, amDynamite, 100) + AddAmmo(leader, amAirAttack, 3) + AddAmmo(leader, amTeleport, 100) + end +end + +function AddHogs() + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Unit 334a$7%;.*"), 0, 200, "cyborg1") + + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + natives[1] = AddHog(nativeNames[leaksNum], 0, 100, nativeHats[leaksNum]) + if m5DeployedNum ~= leaksNum and m8DeployedLeader == 0 then + natives[2] = AddHog(nativeNames[m5DeployedNum], 0, 100, nativeHats[m5DeployedNum]) + end + table.insert(natives, AddHog(nativeNames[ramonNum], 0, 100, nativeHats[ramonNum])) + table.insert(natives, AddHog(nativeNames[spikyNum], 0, 100, nativeHats[spikyNum])) + if m8PrincessLeader == 0 then + table.insert(natives, AddHog(loc("Fell From Heaven"), 0, 100, "tiara")) + end + nativesNum = #natives + nativesLeft = nativesNum + cannibalsLeft = cannibalsNum + for i = 1, nativesNum do + table.insert(players, natives[i]) + end + + AddTeam(loc("Cannibals"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 1, cannibalsNum do + cannibals[i] = AddHog(cannibalNames[i], 0, 100, "Zombi") + table.insert(players, cannibals[i]) + end + playersNum = #players + playersLeft = playersNum + + AddTeam(loc("Hedge-cogs"), 14483455, "ring", "UFO", "Robot", "cm_star") + for i = 1, cyborgsNum do + cyborgs[i] = AddHog(cyborgNames[i], 2, 80, "cyborg2") + end + + if m8EnemyFled == 1 then + AddTeam(loc("Leader"), 14483455, "ring", "UFO", "Robot", "cm_star") + if m8Scene == denseScene then + leader = AddHog(loc("Dense Cloud"), 2, 200, nativeHats[denseNum]) + elseif m8Scene == waterScene then + leader = AddHog(loc("Fiery Water"), 2, 200, nativeHats[waterNum]) + elseif m8Scene == princessScene then + leader = AddHog(loc("Fell From Heaven"), 2, 200, "tiara") + else + leader = AddHog(loc("Nancy Screw"), 2, 200, "cyborg2") + end + end + + cyborgsLeft = cyborgsNum + + for i = 1, nativesNum do + AnimSetGearPosition(natives[i], unpack(nativePos[i])) + AnimTurn(natives[i], nativeDir[i]) + end + for i = 1, cannibalsNum do + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + AnimTurn(cannibals[i], cannibalDir[i]) + end + for i = 1, cyborgsNum do + AnimSetGearPosition(cyborgs[i], unpack(cyborgsPos[i])) + AnimTurn(cyborgs[i], cyborgsDir[i]) + end + AnimSetGearPosition(cyborg, unpack(cyborgPos[1])) + AnimTurn(cyborg, cyborgDir) + if leader ~= nil then + AnimSetGearPosition(leader, unpack(leaderPos)) + AnimTurn(leader, leaderDir[i]) + end +end + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 0 + GameFlags = gfSolidLand + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + Map = "Islands" + Theme = "EarthRise" + SuddenDeathTurns = 20 + + GetVariables() + AnimInit() + AddHogs() +end + +function onGameStart() + SetupAmmo() + SetupPlace() + AnimationSetup() + SetupEvents() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + gearDead[gear] = true + if GetGearType(gear) == gtHedgehog then + if GetHogTeamName(gear) == loc("Natives") then + for i = 1, nativesLeft do + if natives[i] == gear then + table.remove(natives, i) + table.remove(players, i) + nativesLeft = nativesLeft - 1 + playersLeft = playersLeft - 1 + end + end + elseif GetHogTeamName(gear) == loc("Cannibals") then + for i = 1, cannibalsLeft do + if cannibals[i] == gear then + table.remove(cannibals, i) + table.remove(players, nativesLeft + i) + cannibalsLeft = cannibalsLeft - 1 + playersLeft = playersLeft - 1 + end + end + elseif GetHogTeamName(gear) == loc("Hedge-cogs") then + for i = 1, cyborgsLeft do + if cyborgs[i] == gear then + table.remove(cyborgs, i) + end + end + cyborgsLeft = cyborgsLeft - 1 + end + end +end + +function onAmmoStoreInit() + SetAmmo(amSkip, 9, 0, 0, 0) + SetAmmo(amSwitch, 9, 0, 0, 0) + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amSniperRifle, 9, 0, 0, 0) + SetAmmo(amBazooka, 8, 0, 0, 0) + SetAmmo(amGrenade, 7, 0, 0, 0) + SetAmmo(amFirePunch, 9, 0, 0, 0) + SetAmmo(amShotgun, 9, 0, 0, 0) + + SetAmmo(amParachute, 9, 0, 0, 0) + SetAmmo(amRope, 9, 0, 0, 0) + SetAmmo(amPickHammer, 9, 0, 0, 0) + SetAmmo(amBlowTorch, 9, 0, 0, 0) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + if playersDeadFresh then + playersDeadFresh = false + FailedMission() + elseif cyborgsDeadFresh then + cyborgsDeadFresh = false + WonMission() + elseif nativesDeadFresh and GetHogTeamName(CurrentHedgehog) == loc("Cannibals") then + AnimSay(CurrentHedgehog, loc("Your deaths will be avenged, cannibals!"), SAY_SHOUT, 0) + nativesDeadFresh = false + elseif cannibalsDeadFresh and GetHogTeamName(CurrentHedgehog) == loc("Natives") then + AnimSay(CurrentHedgehog, loc("Your deaths will be avenged, cannibals!"), SAY_SHOUT, 0) + cannibalsDeadFresh = false + end +end + +function onPrecise() + if GameTime > 3000 and AnimInProgress() then + SetAnimSkip(true) + end +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/epil.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,433 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Constants--------------------------------- +leaksNum = 1 +denseNum = 2 +waterNum = 3 +buffaloNum = 4 +chiefNum = 5 +girlNum = 6 +wiseNum = 7 +ramonNum = 8 +spikyNum = 9 +princessNum = 10 + +denseScene = 1 +princessScene = 2 +waterScene = 3 +cyborgScene = 4 + +nativeNames = {loc("Leaks A Lot"), loc("Dense Cloud"), loc("Fiery Water"), + loc("Raging Buffalo"), loc("Righteous Beard"), loc("Fell From Grace"), + loc("Wise Oak"), loc("Ramon"), loc("Spiky Cheese"), + loc("Fell From Heaven") + } +nativeHats = {"Rambo", "RobinHood", "pirate_jack", "zoo_Bunny", "IndianChief", + "tiara", "AkuAku", "rasta", "hair_yellow", "tiara"} + +nativePosCyborg = {{1900, 508}, {480, 1321}, {2927, 873}, + {1325, 905}, {3190, 1424}, {1442, 857}, + {1134, 1278}, {2881, 853}, {2974, 897}, + {2033, 511}} +nativeDirCyborg = {"Right", "Right", "Left", "Right", "Right", "Left", "Right", "Right", "Left", "Left"} + +nativePosPrincess = {{1930, 508}, {480, 1321}, {2927, 873}, + {1325, 905}, {3190, 1424}, {2033, 511}, + {1134, 1278}, {2881, 853}, {2974, 897}, + {1900, 508}} +nativeDirPrincess = {"Right", "Right", "Left", "Right", "Right", "Left", "Right", "Right", "Left", "Right"} + +nativePosDense = {{1930, 508}, {2285, 772}, {2927, 873}, + {1325, 905}, {3190, 1424}, {1442, 857}, + {1134, 1278}, {480, 1321}, {2974, 897}, + {2033, 511}} +nativeDirDense = {"Right", "Left", "Left", "Right", "Right", "Left", "Right", "Right", "Left", "Left"} + +nativePosWater = {{1900, 508}, {2033, 511}, {2285, 772}, + {1325, 905}, {3190, 1424}, {1442, 857}, + {1134, 1278}, {480, 1321}, {2974, 897}, + {1980, 511}} +nativeDirWater = {"Right", "Left", "Left", "Right", "Right", "Left", "Right", "Right", "Left", "Left"} + +prisonPos = {2285, 772} + +brainNum = 1 +corpseNum = 2 +brutalNum = 3 +earNum = 4 +hanniNum = 5 + +cannibalNames = {loc("Brainiac"), loc("Corpse Thrower"), loc("Brutal Lily"), loc("Ear Sniffer"), loc("Hannibal")} +cannibalHats = {"Zombi", "AkuAku", "Zombi", "Zombi", "IndianChief"} +cannibalPos = {{533, 1304}, {1184, 1282}, {1386, 883}, {2854, 834}, {3243, 1415}} +cannibalDir = {"Left", "Left", "Left", "Right", "Left"} +-----------------------------Variables--------------------------------- +natives = {} +cannibals = {} +traitor = nil +crate = nil + +startAnim = {} + +gearDead = {} +--------------------------Anim skip functions-------------------------- +function SkipStartAnim() + SetGearMessage(CurrentHedgehog, 0) + AnimSwitchHog(natives[1]) +end + +function AfterStartAnim() + crate = SpawnHealthCrate(0, 0) + SetGearMessage(CurrentHedgehog, 0) + AddNewEvent(CheckCrateTaken, {}, DoCrateTaken, {}, 1) + TurnTimeLeft = 0 + ShowMission("Epilogue", "That's all folks!", "You have successfully finished the campaign!|If you wish to replay, there are other possible endings, too!|You can practice moving around and using utilities in this mission.|However, it will never end!", 1, 0) +end + +---------------------------Events------------------------------------- +function CheckCrateTaken() + return gearDead[crate] +end + +function DoCrateTaken() + crate = SpawnHealthCrate(0, 0) +end +-----------------------------Animations-------------------------------- +function AnimationSetup() + if m8Scene == cyborgScene then + SetupAnimCyborg() + elseif m8Scene == princessScene then + SetupAnimPrincess() + elseif m8Scene == waterScene then + SetupAnimWater() + else + SetupAnimDense() + end + AddSkipFunction(startAnim, SkipStartAnim, {}) +end + +function SetupAnimWater() + startAnim = { + {func = AnimWait, args = {natives[1], 3000}}, + {func = AnimCaption, args = {natives[ramonNum], "Back in the village, the two tribes finally started to live in harmony.", 5000}}, + {func = AnimSay, args = {natives[ramonNum], "You got a killer mask there, amigo!", SAY_SAY, 5500}}, + {func = AnimSay, args = {cannibals[brainNum], "Thanks, man! It really means a lot to me.", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[wiseNum], "So, uhmm, how did you manage to teleport them so far?", SAY_SAY, 8000}}, + {func = AnimSay, args = {cannibals[corpseNum], "It's all about the right carrots, you know.", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[wiseNum], "Of course! It's all obvious now!", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "I can't believe how blind we were...", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "Fighting instead of cultivating a beautiful friendship.", SAY_SAY, 8500}}, + {func = AnimSay, args = {cannibals[hanniNum], "One shall not judge one by one's appearance!", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[chiefNum], "You speak great truth, Hannibal. Here, take a sip!", SAY_SAY, 7500}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimSay, args = {natives[leaksNum], "It's amazing how quickly our lives can change...", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[waterNum], "Aye! Fellow! Let me exit this chamber of doom!", SAY_SAY, 7000}}, + {func = AnimTurn, args = {natives[princessNum], "Right"}}, + {func = AnimSay, args = {natives[princessNum], "It's your fault you're there!", SAY_SAY, 5000}}, + {func = AnimTurn, args = {natives[princessNum], "Left"}}, + {func = AnimSay, args = {natives[leaksNum], "I always suspected him!", SAY_SAY, 3000}}, + {func = AnimSay, args = {natives[leaksNum], "Nobody takes walks every day!", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[princessNum], "I don't know who I can trust anymore.", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[princessNum], "Everywhere I look, I see hogs walking around...", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[princessNum], "...and I think they are up to something. Something bad!", SAY_SAY, 8000}}, + {func = AnimMove, args = {natives[leaksNum], "Right", nativePosWater[princessNum][1] - 30, nativePosWater[princessNum][2]}}, + {func = AnimSay, args = {natives[leaksNum], "You can always trust me! I love you!", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[princessNum], "I know and I'm terribly sorry!", SAY_SAY, 5000}}, + {func = AnimSay, args = {natives[princessNum], "I love Dense Cloud now!", SAY_SAY, 4000}}, + {func = AnimTurn, args = {natives[princessNum], "Right"}}, + {func = AnimMove, args = {natives[denseNum], "Left", nativePosWater[princessNum][1] + 20, nativePosWater[princessNum][2]}}, + {func = AnimSay, args = {natives[denseNum], "Problems, dude? Chillax!", SAY_SAY, 4000}}, + {func = AnimTurn, args = {natives[leaksNum], "Left"}}, + {func = AnimSay, args = {natives[leaksNum], "(T_T)", SAY_SAY, 6000}}, + {func = AnimSwitchHog, args = {natives[leaksNum]}}, + } +end + +function SetupAnimDense() + startAnim = { + {func = AnimWait, args = {natives[1], 3000}}, + {func = AnimCaption, args = {natives[ramonNum], "Back in the village, the two tribes finally started to live in harmony.", 5000}}, + {func = AnimSay, args = {natives[ramonNum], "You got a killer mask there, amigo!", SAY_SAY, 5500}}, + {func = AnimSay, args = {cannibals[brainNum], "Thanks, man! It really means a lot to me.", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[wiseNum], "So, uhmm, how did you manage to teleport them so far?", SAY_SAY, 8000}}, + {func = AnimSay, args = {cannibals[corpseNum], "It's all about the right carrots, you know.", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[wiseNum], "Of course! It's all obvious now!", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "I can't believe how blind we were...", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "Fighting instead of cultivating a beautiful friendship.", SAY_SAY, 8500}}, + {func = AnimSay, args = {cannibals[hanniNum], "One shall not judge one by one's appearance!", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[chiefNum], "You speak great truth, Hannibal. Here, take a sip!", SAY_SAY, 7500}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimSay, args = {natives[waterNum], "...And then I took a stroll...", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[leaksNum], "It's amazing how quickly our lives can change...", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[denseNum], "Dude, let me out!", SAY_SAY, 3000}}, + {func = AnimSay, args = {natives[denseNum], "I already said I'm sorry!", SAY_SAY, 4000}}, + {func = AnimTurn, args = {natives[princessNum], "Right"}}, + {func = AnimSay, args = {natives[princessNum], "Traitors don't get to shout around here!", SAY_SAY, 7000}}, + {func = AnimTurn, args = {natives[princessNum], "Left"}}, + {func = AnimSay, args = {natives[leaksNum], "I still can't believe he sold us out like that.", SAY_SAY, 8000}}, + {func = AnimSay, args = {natives[princessNum], "I don't know who I can trust anymore.", SAY_SAY, 6000}}, + {func = AnimMove, args = {natives[leaksNum], "Right", nativePosDense[princessNum][1] - 30, nativePosDense[princessNum][2]}}, + {func = AnimSay, args = {natives[leaksNum], "You can always trust me!", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[princessNum], "I know, my hero!", SAY_SAY, 3000}}, + {func = AnimSay, args = {natives[princessNum], "...xoxo...", SAY_SAY, 2000}}, + {func = AnimSwitchHog, args = {natives[leaksNum]}}, + } +end + +function SetupAnimCyborg() + startAnim = { + {func = AnimWait, args = {natives[1], 3000}}, + {func = AnimCaption, args = {natives[denseNum], "Back in the village, the two tribes finally started to live in harmony.", 5000}}, + {func = AnimSay, args = {natives[denseNum], "Dude, that outfit is so kool!", SAY_SAY, 4500}}, + {func = AnimSay, args = {cannibals[brainNum], "Thanks, dude! It really means a lot to me.", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[wiseNum], "So, uhmm, how did you manage to teleport them so far?", SAY_SAY, 8000}}, + {func = AnimSay, args = {cannibals[corpseNum], "It's all about the right carrots, you know.", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[wiseNum], "Of course! It's all obvious now!", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "I can't believe how blind we were...", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "Fighting instead of cultivating a beautiful friendship.", SAY_SAY, 8500}}, + {func = AnimSay, args = {cannibals[hanniNum], "One shall not judge one by one's appearance!", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[chiefNum], "You speak great truth, Hannibal. Here, take a sip!", SAY_SAY, 7500}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimSay, args = {natives[waterNum], "...And then I took a stroll...", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[leaksNum], "I'm glad this is over!", SAY_SAY, 4000}}, + {func = AnimMove, args = {natives[princessNum], "Right", nativePosCyborg[princessNum][1] + 30, nativePosCyborg[princessNum][2]}}, + {func = AnimSay, args = {natives[princessNum], "I was so scared.", SAY_SAY, 2500}}, + {func = AnimMove, args = {natives[leaksNum], "Right", nativePosCyborg[princessNum][1], nativePosCyborg[princessNum][2]}}, + {func = AnimSay, args = {natives[leaksNum], "You have nothing to be afraid of now.", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[leaksNum], "I'll protect you!", SAY_SAY, 3000}}, + {func = AnimTurn, args = {natives[princessNum], "Left"}}, + {func = AnimSay, args = {natives[princessNum], "You're so brave...I feel safe with you.", SAY_SAY, 6500}}, + {func = AnimSay, args = {natives[princessNum], "I think I love you!", SAY_SAY, 3500}}, + {func = AnimSay, args = {natives[leaksNum], "I...like being with you too.", SAY_SAY, 4500}}, + } +end + +function SetupAnimPrincess() + startAnim = { + {func = AnimWait, args = {natives[1], 3000}}, + {func = AnimCaption, args = {natives[denseNum], "Back in the village, the two tribes finally started to live in harmony.", 5000}}, + {func = AnimSay, args = {natives[denseNum], "Dude, that outfit is so kool!", SAY_SAY, 4500}}, + {func = AnimSay, args = {cannibals[brainNum], "Thanks, dude! It really means a lot to me.", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[wiseNum], "So, uhmm, how did you manage to teleport them so far?", SAY_SAY, 8000}}, + {func = AnimSay, args = {cannibals[corpseNum], "It's all about the right carrots, you know.", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[wiseNum], "Of course! It's all obvious now!", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "I can't believe how blind we were...", SAY_SAY, 4500}}, + {func = AnimSay, args = {natives[chiefNum], "Fighting instead of cultivating a beautiful friendship.", SAY_SAY, 8500}}, + {func = AnimSay, args = {cannibals[hanniNum], "One shall not judge one by one's appearance!", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[chiefNum], "You speak great truth, Hannibal. Here, take a sip!", SAY_SAY, 7500}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimVisualGear, args = {cannibals[hanniNum], cannibalPos[hanniNum][1], cannibalPos[hanniNum][2], vgtSmoke, 0, true}}, + {func = AnimWait, args = {natives[1], 1000}}, + {func = AnimSay, args = {natives[buffaloNum], "So I shook my fist in the air!", SAY_SAY, 5000}}, + {func = AnimSay, args = {cannibals[brutalNum], "Well that was an unnecessary act of violence.", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[waterNum], "...And then I took a stroll...", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[leaksNum], "I'm glad this is over!", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[girlNum], "I still can't believe you forgave her!", SAY_SAY, 6000}}, + {func = AnimSay, args = {natives[girlNum], "She endangered the whole tribe!", SAY_SAY, 5000}}, + {func = AnimSay, args = {natives[leaksNum], "It wasn't her fault!", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[leaksNum], "We oppressed her, the only woman in the tribe!", SAY_SAY, 7000}}, + {func = AnimSay, args = {natives[girlNum], "The only woman, huh?", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[girlNum], "Then what am I?", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[leaksNum], "Of course, but you're...special.", SAY_SAY, 5000}}, + {func = AnimSay, args = {natives[girlNum], "Sure!", SAY_SAY, 2000}}, + {func = AnimTurn, args = {natives[leaksNum], "Left"}}, + {func = AnimSay, args = {natives[leaksNum], "We're terribly sorry!", SAY_SAY, 4000}}, + {func = AnimSay, args = {natives[princessNum], "I don't know if I can forget what you've done!", SAY_SAY, 7000}}, + {func = AnimTurn, args = {natives[princessNum], "Left"}}, + {func = AnimMove, args = {natives[princessNum], "Left", nativePosPrincess[princessNum][1] - 10, nativePosPrincess[princessNum][2]}}, + {func = AnimSwitchHog, args = {natives[leaksNum]}} + } +end +-----------------------------Misc-------------------------------------- +function GetVariables() + m8Scene = tonumber(GetCampaignVar("M8Scene")) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 1, 5 do + natives[i] = AddHog(nativeNames[i], 0, 100, nativeHats[i]) + end + + AddTeam(loc("More Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 6, 10 do + natives[i] = AddHog(nativeNames[i], 0, 100, nativeHats[i]) + end + + AddTeam(loc("Cannibals"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 1, 5 do + cannibals[i] = AddHog(cannibalNames[i], 0, 100, cannibalHats[i]) + end + + if m8Scene == denseScene or m8Scene == waterScene then + AddTeam(loc("Traitors"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + if m8Scene == denseScene then + DeleteGear(natives[2]) + natives[2] = AddHog(nativeNames[2], 0, 100, nativeHats[2]) + else + DeleteGear(natives[3]) + natives[3] = AddHog(nativeNames[3], 0, 100, nativeHats[3]) + end + end + + SetGearPositions() +end + +function SetGearPositions() + if m8Scene == cyborgScene then + for i = 1, 10 do + AnimSetGearPosition(natives[i], unpack(nativePosCyborg[i])) + AnimTurn(natives[i], nativeDirCyborg[i]) + end + elseif m8Scene == waterScene then + for i = 1, 10 do + AnimSetGearPosition(natives[i], unpack(nativePosWater[i])) + AnimTurn(natives[i], nativeDirWater[i]) + end + elseif m8Scene == denseScene then + for i = 1, 10 do + AnimSetGearPosition(natives[i], unpack(nativePosDense[i])) + AnimTurn(natives[i], nativeDirDense[i]) + end + else + for i = 1, 10 do + AnimSetGearPosition(natives[i], unpack(nativePosPrincess[i])) + AnimTurn(natives[i], nativeDirPrincess[i]) + end + end + + for i = 1, 5 do + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + AnimTurn(cannibals[i], cannibalDir[i]) + end +end + +function SetupPlace() + if m8Scene == denseScene or m8Scene == waterScene then + PlaceGirder(2296, 798, 4) + PlaceGirder(2296, 700, 4) + PlaceGirder(2225, 750, 2) + PlaceGirder(2245, 750, 2) + PlaceGirder(2265, 750, 2) + PlaceGirder(2305, 750, 2) + PlaceGirder(2345, 750, 2) + PlaceGirder(2365, 750, 2) + end + if m8Scene == denseScene then + traitor = natives[denseNum] + elseif m8Scene == waterScene then + traitor = natives[waterNum] + end +end +-----------------------------Main Functions---------------------------- +function onGameInit() + Seed = 1 + GameFlags = gfOneClanMode + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + Map = "Hogville" + Theme = "Nature" + SuddenDeathTurns = 3000 + + GetVariables() + AddHogs() + AnimInit() +end + +function onGameStart() + SetupPlace() + AnimationSetup() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + gearDead[gear] = true +end + +function onAmmoStoreInit() + SetAmmo(amAirStrike, 9, 0, 0, 0) + SetAmmo(amBaseballBat, 9, 0, 0, 0) + SetAmmo(amBazooka, 9, 0, 0, 0) + SetAmmo(amBlowTorch, 9, 0, 0, 0) + SetAmmo(amClusterBomb,9, 0, 0, 0) + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amDrill, 9, 0, 0, 4) + SetAmmo(amDynamite, 9, 0, 0, 3) + SetAmmo(amFirePunch, 9, 0, 0, 0) + SetAmmo(amFlamethrower, 9, 0, 0, 3) + SetAmmo(amGirder, 9, 0, 0, 0) + SetAmmo(amGrenade, 9, 0, 0, 0) + SetAmmo(amHammer, 9, 0, 0, 0) + SetAmmo(amJetpack, 9, 0, 0, 0) + SetAmmo(amLandGun, 9, 0, 0, 0) + SetAmmo(amLowGravity, 9, 0, 0, 2) + SetAmmo(amMine, 9, 0, 0, 2) + SetAmmo(amMolotov, 9, 0, 0, 3) + SetAmmo(amMortar, 9, 0, 0, 4) + SetAmmo(amNapalm, 9, 0, 0, 4) + SetAmmo(amParachute, 9, 0, 0, 0) + SetAmmo(amPickHammer, 9, 0, 0, 0) + SetAmmo(amPortalGun, 9, 0, 0, 0) + SetAmmo(amRope, 9, 0, 0, 0) + SetAmmo(amRCPlane, 9, 0, 0, 0) + SetAmmo(amSkip, 9, 0, 0, 0) + SetAmmo(amShotgun, 9, 0, 0, 0) + SetAmmo(amSMine, 9, 0, 0, 2) + SetAmmo(amSniperRifle, 9, 0, 0, 0) + SetAmmo(amSnowball, 9, 0, 0, 0) + SetAmmo(amSwitch, 9, 0, 0, 0) + SetAmmo(amTeleport, 9, 0, 0, 0) + SetAmmo(amWatermelon, 9, 0, 0, 0) + SetAmmo(amWhip, 9, 0, 0, 0) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + if CurrentHedgehog == traitor then + TurnTimeLeft = 0 + else + TurnTimeLeft = -1 + end +end + +function onPrecise() + if GameTime > 2500 then + SetAnimSkip(true) + end +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/family.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,566 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Map-------------------------------------- +local map = +{ + "\255\242\4\218\132\0\53\4\253\0\0\53\4\253\132\0\102\5\92\0\0\102\5\92\132\0\106\5\205\0\0\106\5\205\132\1\1\6\37\0", + "\1\1\6\37\132\1\124\6\160\0\1\113\6\160\132\2\157\6\111\0\2\164\6\107\132\2\252\6\178\0\2\252\6\178\132\3\224\4\179\0", + "\3\224\4\179\132\3\38\2\209\0\3\38\2\209\132\4\109\3\179\0\4\109\3\179\132\5\124\3\172\0\5\128\3\172\132\6\69\4\239\0", + "\6\69\4\239\132\7\175\4\32\0\7\172\4\46\132\8\116\5\18\0\3\38\2\213\132\3\41\1\244\0\3\41\1\244\132\3\94\2\245\0", + "\8\127\5\8\132\8\127\0\14\0\8\127\0\14\132\8\194\5\29\0\8\194\5\29\132\9\36\5\82\0\9\29\5\75\132\9\180\5\103\0", + "\9\194\5\92\132\10\51\6\5\0\10\51\6\5\132\10\216\5\152\0\10\227\5\145\132\11\189\5\212\0\11\189\5\212\132\12\91\5\131\0", + "\12\91\5\131\132\12\253\5\191\0\12\253\5\191\132\13\149\5\106\0\13\149\5\106\132\16\11\5\106\0\14\19\5\110\132\14\16\4\236\0", + "\14\16\4\236\132\15\66\4\236\0\15\66\4\236\132\15\66\5\110\0\14\79\4\194\132\15\6\4\194\0\14\255\4\176\132\14\255\4\49\0", + "\14\255\4\49\132\14\76\4\53\0\14\76\4\53\132\14\76\4\201\0\14\125\4\74\128\14\128\4\187\0\14\188\4\77\128\14\185\4\179\0", + "\14\111\4\39\129\14\76\3\252\0\14\72\3\249\129\14\72\3\147\0\14\72\3\147\129\14\97\3\235\0\14\97\3\235\129\14\146\4\28\0", + "\14\202\4\28\129\14\248\3\238\0\14\248\3\238\129\15\17\3\133\0\15\17\3\133\129\15\27\3\235\0\15\27\3\235\129\14\230\4\49\0", + "\1\124\6\220\130\1\244\7\13\0\1\244\7\13\130\2\104\6\206\0\2\100\6\206\130\2\30\6\178\0\2\12\6\181\130\1\135\6\213\0", + "\3\172\7\136\130\15\41\7\136\0\15\41\7\136\130\15\41\7\62\0\15\41\7\62\130\3\175\7\52\0\3\175\7\52\130\3\126\6\206\0", + "\3\126\6\206\130\3\122\7\133\0\3\122\7\133\130\3\186\7\136\0\8\123\7\94\136\9\173\7\101\0\8\88\7\66\130\8\88\7\119\0", + "\9\212\7\69\130\9\212\7\126\0\8\155\0\14\133\8\151\5\11\0\8\190\2\160\131\8\194\5\1\0\14\83\3\235\131\14\114\4\21\0", + "\15\10\3\196\131\15\10\3\235\0\15\10\3\235\131\14\220\4\32\0\14\65\5\47\137\15\20\5\36\0\15\41\5\82\132\15\41\5\82\0", + "\3\94\3\17\138\4\137\5\124\0\3\221\3\119\138\5\57\4\250\0\4\102\4\67\160\5\26\4\74\0\4\113\5\36\161\5\142\4\222\0", + "\4\42\5\216\169\9\89\6\26\0\6\100\5\22\145\8\134\5\64\0\6\255\4\197\140\7\161\4\120\0\7\214\4\204\146\7\214\4\204\0", + "\10\55\6\97\147\11\13\5\247\0\11\59\6\26\146\11\224\6\30\0\12\95\6\16\153\14\55\6\90\0\13\173\5\226\153\15\196\5\212\0", + "\15\172\7\91\152\15\165\5\230\0\15\235\7\221\142\255\238\7\207\0\14\248\6\188\152\3\217\6\178\0\3\112\6\83\143\3\31\7\101\0", + "\3\73\7\143\140\3\73\7\143\0\15\62\7\13\140\15\62\7\13\0\15\101\7\157\140\15\101\7\157\0\2\181\6\220\141\1\205\7\108\0", + "\2\86\6\160\137\2\150\6\128\0\2\26\6\153\134\1\96\6\195\0\1\82\6\241\136\1\226\7\59\0\2\157\7\98\155\2\157\7\98\0", + "\1\64\7\80\149\255\249\7\27\0\1\4\6\174\148\0\25\6\86\0\0\211\6\58\139\0\7\5\219\0\0\35\5\159\142\0\4\5\47\0", + "\8\123\0\14\199\8\187\0\11\0\16\14\5\99\199\16\14\7\245\0\255\235\4\218\199\255\238\8\25\0\8\67\2\72\202\8\208\2\72\0", + "\8\141\1\251\202\8\141\0\74\0\8\201\2\143\195\8\204\4\49\0\8\84\2\185\205\8\204\2\188\0\8\99\2\230\205\8\187\2\230\0", + "\8\165\3\41\131\8\144\3\3\0\8\144\3\3\131\8\60\2\248\0\8\60\2\248\131\7\252\3\59\0\7\252\3\59\131\8\137\3\31\0", + "\8\56\3\20\131\8\102\3\20\0\8\60\3\13\194\8\60\3\13\0\8\60\3\3\128\8\60\3\31\0\7\238\3\66\128\7\214\3\84\0", + "\7\217\3\87\128\7\217\3\98\0\7\217\3\87\128\7\200\3\91\0\6\209\4\70\208\8\18\4\95\0\0\11\4\225\131\0\0\8\21\0", + "\15\224\5\99\131\15\245\7\252\0\15\242\5\191\192\15\196\6\33\0\15\196\6\33\192\15\245\6\209\0\15\245\6\209\192\15\193\7\115\0", + "\15\193\7\115\192\15\235\8\18\0\15\249\5\223\196\15\217\6\40\0\15\217\6\40\196\16\4\6\188\0\15\245\6\16\196\16\21\7\77\0", + "\16\0\6\245\196\15\214\7\112\0\15\207\7\129\196\16\0\8\4\0\15\245\7\80\196\16\4\7\207\0\15\221\5\85\196\16\11\5\184\0", +} +--------------------------------------------Constants------------------------------------ +choiceAccepted = 1 +choiceRefused = 2 +choiceAttacked = 3 + +choiceEliminate = 1 +choiceSpare = 2 + +leaksNum = 1 +denseNum = 2 +waterNum = 3 +buffaloNum = 4 +chiefNum = 5 +girlNum = 6 +wiseNum = 7 + +nativeNames = {loc("Leaks A Lot"), loc("Dense Cloud"), loc("Fiery Water"), + loc("Raging Buffalo"), loc("Righteous Beard"), loc("Fell From Grace"), + loc("Wise Oak"), loc("Ramon"), loc("Spiky Cheese") + } + +nativeUnNames = {loc("Zork"), loc("Steve"), loc("Jack"), + loc("Lee"), loc("Elmo"), loc("Rachel"), + loc("Muriel")} + +nativeHats = {"Rambo", "RobinHood", "pirate_jack", "zoo_Bunny", "IndianChief", + "tiara", "AkuAku", "rasta", "hair_yellow"} + +nativePos = {{110, 1310}, {984, 1907}, {1040, 1907}} +nativePos2 = {196, 1499} + +cyborgNames = {loc("Unit 0x0007"), loc("Hogminator"), loc("Carol"), + loc("Blender"), loc("Elderbot"), loc("Fiery Water")} +cyborgsDif = {2, 2, 2, 2, 2, 1} +cyborgsHealth = {45, 45, 45, 40, 40, 20} +cyborgPos = {945, 1216} +cyborgsNum = 6 +cyborgsPos = {{2243, 1043}, {3588, 1227}, {2781, 1388}, + {3749, 1040}, {2475, 1338}, {3853, 881}} +cyborgsDir = {"Left", "Left", "Left", "Left", "Left", "Right"} + +princessPos = {3737, 1181} +crateConsts = {} +reactions = {} + +nativeMidPos = {1991, 841} +cyborgMidPos = {2109, 726} +nativeMidPos2 = {2250, 1071} +-----------------------------Variables--------------------------------- +natives = {} +native = nil + +cyborgs = {} +cyborg = nil + +gearDead = {} +hedgeHidden = {} + +startAnim = {} +midAnim = {} + +freshDead = nil +crates = {} +cratesNum = 0 +-----------------------------Animations-------------------------------- +function EmitDenseClouds(dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + AnimInsertStepNext({func = AnimVisualGear, args = {natives[1], GetX(natives[1]) + dif, GetY(natives[1]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[1], GetX(natives[1]) + dif, GetY(natives[1]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[1], GetX(natives[1]) + dif, GetY(natives[1]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {natives[1], 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[1], GetX(natives[1]) + dif, GetY(natives[1]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[1], GetX(natives[1]) + dif, GetY(natives[1]) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {natives[1], 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {natives[1], GetX(natives[1]) + dif, GetY(natives[1]) + dif, vgtSteam, 0, true}, swh = false}) +end + +function AnimationSetup() + table.insert(startAnim, {func = AnimWait, args = {natives[1], 4000}}) + table.insert(startAnim, {func = AnimMove, args = {natives[1], "Right", unpack(nativePos2)}}) + if m5DeployedNum == leaksNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Those aliens are destroying the island!"), SAY_THINK, 5000}}) + elseif m5DeployedNum == denseNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Dude, all the plants are gone!"), SAY_THINK, 3500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("What am I gonna...eat, yo?"), SAY_THINK, 3500}}) + elseif m5DeployedNum == girlNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Fell From Heaven is the best! Fell From Heaven is the greatest!"), SAY_THINK, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Yuck! I bet they'll keep worshipping her even after I save the village!"), SAY_THINK, 7500}}) + elseif m5DeployedNum == chiefNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("I'm getting old for this!"), SAY_THINK, 4000}}) + elseif m5DeployedNum == waterNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("I'm getting thirsty..."), SAY_THINK, 3000}}) + elseif m5DeployedNum == buffaloNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("I wonder why I'm so angry all the time..."), SAY_THINK, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("It must be a childhood trauma..."), SAY_THINK, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Just wait till I get my hands on that trauma! ARGH!"), SAY_THINK, 6500}}) + elseif m5DeployedNum == wiseNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("I could just teleport myself there..."), SAY_THINK, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("It's a shame, I forgot how to do that!"), SAY_THINK, 4500}}) + end + table.insert(startAnim, {func = AnimCustomFunction, args = {natives[1], RestoreHedge, {cyborg}}}) + table.insert(startAnim, {func = AnimOutOfNowhere, args = {cyborg, unpack(cyborgPos)}}) + table.insert(startAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(startAnim, {func = AnimTurn, args = {natives[2], "Left"}}) + table.insert(startAnim, {func = AnimTurn, args = {natives[3], "Left"}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("Hello again, ") .. nativeUnNames[m5DeployedNum] .. "!", SAY_SAY, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("I just found out that they have captured your princess!"), SAY_SAY, 7000}}) + if m5DeployedNum == girlNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Of course I have to save her. What did I expect?!"), SAY_SAY, 7000}}) + elseif m5DeployedNum == denseNum then + table.insert(startAnim, {func = AnimCustomFunction, args = {natives[1], EmitDenseClouds, {"Right"}}}) + end + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("She's behind that tall thingy."), SAY_SAY, 5000}}) + table.insert(startAnim, {func = FollowGear, swh = false, args = {princess}}) + table.insert(startAnim, {func = AnimWait, swh = false, args = {princess, 1000}}) + table.insert(startAnim, {func = FollowGear, swh = false, args = {cyborg}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("I'm here to help you rescue her."), SAY_SAY, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[2], loc("Yo, dude, we're here, too!"), SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[3], loc("We were trying to save her and we got lost."), SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("That's typical of you!"), SAY_SAY, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], loc("Why are you helping us, uhm...?"), SAY_SAY, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {cyborg, loc("Call me Beep! Well, 'cause I'm such a nice...person!"), SAY_SAY, 2500}}) + table.insert(startAnim, {func = AnimDisappear, args = {cyborg, unpack(cyborgPos)}}) + table.insert(startAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(startAnim, {func = AnimWait, args = {natives[1], 1}}) + AddSkipFunction(startAnim, SkipStartAnim, {}) + + table.insert(midAnim, {func = AnimCustomFunction, args = {natives[1], RestoreHedge, {cyborg}}}) + table.insert(midAnim, {func = AnimOutOfNowhere, args = {cyborg, unpack(cyborgMidPos)}}) + table.insert(midAnim, {func = AnimTurn, args = {cyborg, "Left"}}) + table.insert(midAnim, {func = AnimTeleportGear, args = {natives[1], unpack(nativeMidPos)}}) + table.insert(midAnim, {func = AnimSay, args = {cyborg, loc("Here, let me help you save her!"), SAY_SAY, 5000}}) + table.insert(midAnim, {func = AnimSay, args = {natives[1], loc("Thanks!"), SAY_SAY, 2000}}) + table.insert(midAnim, {func = AnimTeleportGear, args = {natives[1], unpack(nativeMidPos2)}}) + table.insert(midAnim, {func = AnimSay, args = {natives[1], loc("Why can't he just let her go?!"), SAY_THINK, 5000}}) + AddSkipFunction(midAnim, SkipMidAnim, {}) +end + +--------------------------Anim skip functions-------------------------- +function AfterMidAnim() + HideHedge(cyborg) + SetupPlace3() + SetGearMessage(natives[1], 0) + AddNewEvent(CheckPrincessFreed, {}, DoPrincessFreed, {}, 0) + TurnTimeLeft = 0 + ShowMission(loc("Family Reunion"), loc("Salvation"), loc("Get your teammates out of their natural prison and save the princess!|Hint: Drilling holes should solve everything.|Hint: It might be a good idea to place a girder before starting to drill. Just saying.|Hint: All your hedgehogs need to be above the marked height!|Hint: Leaks A Lot needs to get really close to the princess!"), 1, 7000) + vCirc = AddVisualGear(0,0,vgtCircle,0,true) + SetVisualGearValues(vCirc, 2625, 1500, 100, 255, 1, 10, 0, 120, 3, 0xff00ffff) +end + +function SkipMidAnim() + AnimTeleportGear(natives[1], unpack(nativeMidPos2)) + SkipStartAnim() +end + +function SetupPlace3() + SpawnUtilityCrate(2086, 1887, amRope, 1) + SpawnUtilityCrate(2147, 728, amBlowTorch, 2) + SpawnUtilityCrate(2778, 1372, amPickHammer, 3) + SpawnUtilityCrate(2579, 1886, amPickHammer, 3) + SpawnUtilityCrate(2622, 1893, amGirder, 1) + SpawnUtilityCrate(2671, 1883, amPortalGun, 3) + SpawnUtilityCrate(2831, 1384, amGirder, 3) + + SetTimer(AddGear(2725, 1387, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2760, 1351, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2805, 1287, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2831, 1376, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2684, 1409, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2637, 1428, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2278, 1280, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2311, 1160, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2339, 1162, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2362, 1184, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2407, 1117, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2437, 1143, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2472, 1309, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2495, 1331, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2536, 1340, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2569, 1360, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2619, 1379, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2596, 1246, gtMine, 0, 0, 0, 0), 5000) +end + +function SkipStartAnim() + AnimSwitchHog(natives[1]) + AnimWait(natives[1], 1) +end + +function AfterStartAnim() + HideHedge(cyborg) + SetupPlace2() + SetGearMessage(natives[1], 0) + AddNewEvent(CheckGearDead, {natives[1]}, EndMission, {}, 0) + AddNewEvent(CheckGearDead, {natives[2]}, EndMission, {}, 0) + AddNewEvent(CheckGearDead, {natives[3]}, EndMission, {}, 0) + AddNewEvent(CheckGearDead, {princess}, EndMission, {}, 0) + AddNewEvent(CheckCyborgsDead, {}, DoCyborgsDead, {}, 0) + for i = 1, cyborgsNum do + AddNewEvent(CheckGearDead, {cyborgs[i]}, DoCyborgDead, {i}, 0) + end + AddNewEvent(CheckOutOfCluster, {}, DoOutOfCluster, {}, 1) + AddNewEvent(CheckOutOfGrenade, {}, DoOutOfGrenade, {}, 1) +-- AddNewEvent(CheckNeedToHide, {}, DoNeedToHide, {}, 1) + TurnTimeLeft = TurnTime + ShowMission(loc("Family Reunion"), loc("Hostage Situation"), loc("Save the princess! All your hogs must survive!|Hint: Kill the cyborgs first! Use the ammo very carefully!|Hint: You might want to spare a girder for cover!"), 1, 7000) +end + +function SetupPlace2() + PlaceGirder(709, 564, 7) + PlaceGirder(591, 677, 7) + PlaceGirder(473, 794, 7) + PlaceGirder(433, 933, 5) + PlaceGirder(553, 1052, 5) + PlaceGirder(674, 1170, 5) + PlaceGirder(710, 1310, 7) + PlaceGirder(648, 1427, 5) + PlaceGirder(2110, 980, 0) + + SpawnAmmoCrate(814, 407, amBazooka, 4) + clusterCrate = SpawnAmmoCrate(862, 494, amClusterBomb, 4) + SpawnAmmoCrate(855, 486, amBee, 3) + grenadeCrate1 = SpawnAmmoCrate(849, 459, amGrenade, 4) + SpawnAmmoCrate(2077, 847, amWatermelon, 3) + grenadeCrate2 = SpawnAmmoCrate(2122, 847, amGrenade, 3) + + SpawnUtilityCrate(747, 1577, amPickHammer, 1) + SpawnUtilityCrate(496, 1757, amGirder, 2) + SpawnUtilityCrate(1809, 1880, amGirder, 1) + SpawnUtilityCrate(530, 1747, amPortalGun, 1) +end + +-----------------------------Events------------------------------------ +function CheckPrincessFreed() + if GetX(natives[1]) == nil or GetX(natives[2]) == nil or GetX(natives[3]) == nil or GetX(princess) == nil then + return false + end + return math.abs(GetX(natives[1]) - GetX(princess)) <= 15 and math.abs(GetY(natives[1]) - GetY(princess)) <= 15 and StoppedGear(natives[1]) + and GetY(natives[2]) < 1500 and GetY(natives[3]) < 1500 and StoppedGear(natives[2]) and StoppedGear(natives[3]) +end + +function DoPrincessFreed() + AnimSay(princess, loc("Thank you, my hero!"), SAY_SAY, 0) + SaveCampaignVar("Progress", "7") + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function CheckCyborgsDead() + return cyborgsLeft == 0 +end + +function DoCyborgsDead() + SetGearMessage(CurrentHedgehog, 0) + RestoreHedge(princess) +-- RemoveEventFunc(CheckNeedToHide) + AddAnim(midAnim) + AddFunction({func = AfterMidAnim, args = {}}) +end + +function DoCyborgDead(index) + if cyborgsLeft == 0 then + return + end + if index == 1 then + SpawnAmmoCrate(1700, 407, amBazooka, 3) + elseif index == 2 then + SpawnAmmoCrate(1862, 494, amClusterBomb, 3) + elseif index == 3 then + SpawnAmmoCrate(1855, 486, amBee, 1) + elseif index == 4 then + SpawnAmmoCrate(1849, 459, amGrenade, 3) + elseif index == 5 then + SpawnAmmoCrate(2122, 847, amGrenade, 3) + elseif index == 6 then + SpawnAmmoCrate(2077, 847, amWatermelon, 1) + end +end + +function CheckGearsDead(gearList) + for i = 1, # gearList do + if gearDead[gearList[i]] ~= true then + return false + end + end + return true +end + + +function CheckGearDead(gear) + return gearDead[gear] +end + +function EndMission() + RemoveEventFunc(CheckPrincessFreed) + AddCaption("So the princess was never heard of again...") + ParseCommand("teamgone " .. loc("Natives")) + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function CheckOutOfCluster() + return CheckGearDead(clusterCrate) and GetAmmoCount(natives[1], amClusterBomb) == 0 +end + +function CheckOutOfGrenade() + return CheckGearDead(grenadeCrate1) and CheckGearDead(grenadeCrate2) and GetAmmoCount(natives[1], amGrenade) == 0 +end + +function DoOutOfCluster() + if (GetX(natives[1]) == nil) then + return + end + clusterCrate = SpawnAmmoCrate(GetX(natives[1]) - 50, GetY(natives[1]) - 50, amClusterBomb, 3) +end + +function DoOutOfGrenade() + if (GetX(natives[1]) == nil) then + return + end + grenadeCrate2 = SpawnAmmoCrate(GetX(natives[1]) - 50, GetY(natives[1]) - 50, amGrenade, 3) +end + +function CheckNeedToHide() + if gearDead[princess] == true then + return false + end + return TurnTimeLeft == 0 +end + +function DoNeedToHide() + HideHedge(princess) +end +-----------------------------Misc-------------------------------------- +function HideHedge(hedge) + if hedgeHidden[hedge] ~= true then + HideHog(hedge) + hedgeHidden[hedge] = true + end +end + +function RestoreHedge(hedge) + if hedgeHidden[hedge] == true then + RestoreHog(hedge) + hedgeHidden[hedge] = false + end +end + +function GetVariables() + m5DeployedNum = tonumber(GetCampaignVar("M5DeployedNum")) + m2Choice = tonumber(GetCampaignVar("M2Choice")) + m5Choice = tonumber(GetCampaignVar("M5Choice")) +end + +function SetupPlace() + SetHogHat(natives[1], nativeHats[m5DeployedNum]) + SetHogName(natives[1], nativeNames[m5DeployedNum]) + if m2Choice ~= choiceAccepted or m5Choice ~= choiceEliminate then + DeleteGear(cyborgs[cyborgsNum]) + cyborgsNum = cyborgsNum - 1 + end + HideHedge(cyborg) +end + +function SetupAmmo() + AddAmmo(cyborgs[1], amBazooka, 100) + AddAmmo(cyborgs[1], amGrenade, 100) + AddAmmo(cyborgs[1], amClusterBomb, 100) + AddAmmo(cyborgs[1], amSniperRifle, 1) + AddAmmo(cyborgs[1], amDynamite, 100) + AddAmmo(cyborgs[1], amBaseballBat, 100) + AddAmmo(cyborgs[1], amMolotov, 100) + AddAmmo(cyborgs[1], amWatermelon, 1) + AddAmmo(cyborgs[1], amAirStrike, 2) + AddAmmo(cyborgs[1], amDrillStrike, 1) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 7, 9 do + natives[i-6] = AddHog(nativeNames[i], 0, 100, nativeHats[i]) + gearDead[natives[i-6]] = false + end + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Unit 334a$7%;.*"), 0, 200, "cyborg1") + princess = AddHog(loc("Fell From Heaven"), 0, 333, "tiara") + gearDead[cyborg] = false + gearDead[princess] = false + + AddTeam(loc("Biomechanic Team"), 14483456, "ring", "UFO", "Robot", "cm_star") + for i = 1, cyborgsNum do + cyborgs[i] = AddHog(cyborgNames[i], cyborgsDif[i], cyborgsHealth[i], "cyborg2") + gearDead[cyborgs[i]] = false + end + cyborgsLeft = cyborgsNum + + for i = 1, 3 do + AnimSetGearPosition(natives[i], unpack(nativePos[i])) + end + + AnimSetGearPosition(cyborg, unpack(cyborgPos)) + AnimSetGearPosition(princess, unpack(princessPos)) + AnimTurn(princess, "Left") + + for i = 1, cyborgsNum do + AnimSetGearPosition(cyborgs[i], unpack(cyborgsPos[i])) + AnimTurn(cyborgs[i], cyborgsDir[i]) + end +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl == nil or xd == nil then + return + end + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 0 + GameFlags = gfSolidLand + gfDisableLandObjects + gfDisableGirders + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + MapGen = 2 + Theme = "Hell" + SuddenDeathTurns = 35 + + for i = 1, #map do + ParseCommand('draw ' .. map[i]) + end + + AddHogs() + AnimInit() +end + +function onGameStart() + GetVariables() + SetupAmmo() + SetupPlace() + AnimationSetup() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + gearDead[gear] = true + if GetGearType(gear) == gtHedgehog then + if GetHogTeamName(gear) == loc("Biomechanic Team") then + cyborgsLeft = cyborgsLeft - 1 + end + end +end + +function onAmmoStoreInit() + SetAmmo(amSkip, 9, 0, 0, 0) + SetAmmo(amSwitch, 9, 0, 0, 0) + SetAmmo(amBazooka, 0, 0, 0, 8) + SetAmmo(amClusterBomb,0, 0, 0, 8) + SetAmmo(amBee, 0, 0, 0, 3) + SetAmmo(amGrenade, 0, 0, 0, 8) + SetAmmo(amWatermelon, 0, 0, 0, 2) + SetAmmo(amSniperRifle, 0, 0, 0, 3) + SetAmmo(amPickHammer, 0, 0, 0, 1) + SetAmmo(amGirder, 0, 0, 0, 3) + SetAmmo(amPortalGun, 0, 0, 0, 1) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + if GetHogTeamName(CurrentHedgehog) == loc("011101001") then + if CheckCyborgsDead() ~= true then + for i = 1, 3 do + if gearDead[natives[i]] ~= true then + HideHedge(natives[i]) + end + end + end + TurnTimeLeft = 0 + else + for i = 1, 3 do + if gearDead[natives[i]] ~= true then + RestoreHedge(natives[i]) + end + end + end +end + +function onPrecise() + if GameTime > 2500 and AnimInProgress() then + SetAnimSkip(true) + return + end +-- HideHedge(princess) +-- for i = 1, 5 do +-- DeleteGear(cyborgs[i]) +-- end +-- AddAmmo(natives[1], amTeleport, 100) +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/first_blood.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,742 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Variables--------------------------------- +startDialogue = {} +damageAnim = {} +onShroomAnim = {} +onFlowerAnim = {} +tookParaAnim = {} +tookPunchAnim = {} +onMoleHeadAnim = {} +tookRope2Anim = {} +challengeAnim = {} +challengeFailedAnim = {} +challengeCompletedAnim = {} +beforeKillAnim = {} +closeCannim = {} +cannKilledAnim = {} +cannKilledEarlyAnim = {} +princessDamagedAnim = {} +elderDamagedAnim = {} +pastMoleHeadAnim = {} + + +targets = {} +crates = {} +targXdif2 = {2755, 2638, 2921, 2973, 3162, 3067, 3062, 1300} +targYdif2 = {1197, 1537, 1646, 1857, 1804, 1173, 1167, 1183} +targXdif1 = {2749, 2909, 2770, 2836, 1558, 1305} +targYdif1 = {1179, 1313, 1734, 1441, 1152, 1259} +targetPosX = {{821, 866, 789}, {614, 656, 638}, {1238, 1237, 1200}} +targetPosY = {{1342, 1347, 1326}, {1112, 1121, 1061}, {1152, 1111, 1111}} +crateNum = {6, 8} + + +stage = 1 +cratesCollected = 0 +chalTries = 0 +targetsDestroyed = 0 +targsWave = 1 +tTime = -1 +difficulty = 0 + +cannibalVisible = false +cannibalKilles = false +youngdamaged = false +youngKilled = false +elderDamaged = false +princessDamaged = false +elderKilled = false +princessKilled = false +rope1Taken = false +paraTaken = false +rope2Taken = false +punchTaken = false +canKilled = false +desertTaken = false +challengeFailed = false +difficultyChoice = false +princessFace = "Left" +elderFace = "Left" + +goals = { + [startDialogue] = {loc("First Blood"), loc("First Steps"), loc("Press [Left] or [Right] to move around, [Enter] to jump"), 1, 4000}, + [onShroomAnim] = {loc("First Blood"), loc("A leap in a leap"), loc("Go on top of the flower"), 1, 4000}, + [onFlowerAnim] = {loc("First Blood"), loc("Hightime"), loc("Collect the crate on the right.|Hint: Select the rope, [Up] or [Down] to aim, [Space] to fire, directional keys to move.|Ropes can be fired again in the air!"), 1, 7000}, + [tookParaAnim] = {loc("First Blood"), loc("Omnivore"), loc("Get on the head of the mole"), 1, 4000}, + [onMoleHeadAnim] = {loc("First Blood"), loc("The Leap of Faith"), loc("Use the parachute ([Space] while in air) to get the next crate"), 1, 4000}, + [tookRope2Anim] = {loc("First Blood"), loc("The Rising"), loc("Do the deed"), 1, 4000}, + [tookPunchAnim] = {loc("First Blood"), loc("The Slaughter"), loc("Destroy the targets!|Hint: Select the Shoryuken and hit [Space]|P.S. You can use it mid-air."), 1, 5000}, + [challengeAnim] = {loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000}, + [challengeFailedAnim] = {loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000}, + [challengeCompletedAnim] = {loc("First Blood"), loc("The Ultimate Weapon"), loc("Destroy the targets!|Hint: [Up], [Down] to aim, [Space] to shoot"), 1, 5000}, + [beforeKillAnim] = {loc("First Blood"), loc("The First Blood"), loc("Kill the cannibal!"), 1, 5000}, + [closeCannim] = {loc("First Blood"), loc("The First Blood"), loc("KILL IT!"), 1, 5000} +} +-----------------------------Animations-------------------------------- +function Skipanim(anim) + AnimSwitchHog(youngh) + if goals[anim] ~= nil then + ShowMission(unpack(goals[anim])) + end + if anim == startDialogue then + HogTurnLeft(princess, false) + end +end + +function SkipDamageAnim(anim) + SwitchHog(youngh) + SetInputMask(0xFFFFFFFF) +end + +function SkipOnShroom() + Skipanim(onShroomAnim) + AnimSetGearPosition(elderh, 2700, 1278) +end + +function AnimationSetup() + AddSkipFunction(damageAnim, SkipDamageAnim, {damageAnim}) + table.insert(damageAnim, {func = AnimWait, args = {youngh, 500}, skipFunc = Skipanim, skipArgs = damageAnim}) + table.insert(damageAnim, {func = AnimSay, args = {elderh, loc("Watch your steps, young one!"), SAY_SAY, 2000}}) + table.insert(damageAnim, {func = AnimGearWait, args = {youngh, 500}}) + + AddSkipFunction(princessDamagedAnim, SkipDamageAnim, {princessDamagedAnim}) + table.insert(princessDamagedAnim, {func = AnimWait, args = {princess, 500}, skipFunc = Skipanim, skipArgs = princessDamagedAnim}) + table.insert(princessDamagedAnim, {func = AnimSay, args = {princess, loc("Why do men keep hurting me?"), SAY_THINK, 3000}}) + table.insert(princessDamagedAnim, {func = AnimGearWait, args = {youngh, 500}}) + + AddSkipFunction(elderDamagedAnim, SkipDamageAnim, {elderDamagedAnim}) + table.insert(elderDamagedAnim, {func = AnimWait, args = {elderh, 500}, skipFunc = Skipanim, skipArgs = elderDamagedAnim}) + table.insert(elderDamagedAnim, {func = AnimSay, args = {elderh, loc("Violence is not the answer to your problems!"), SAY_SAY, 3000}}) + table.insert(elderDamagedAnim, {func = AnimGearWait, args = {youngh, 500}}) + + AddSkipFunction(startDialogue, Skipanim, {startDialogue}) + table.insert(startDialogue, {func = AnimWait, args = {youngh, 3500}, skipFunc = Skipanim, skipArgs = startDialogue}) + table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("Once upon a time, on an island with great natural resources, lived two tribes in heated conflict..."), 5000}}) + table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("One tribe was peaceful, spending their time hunting and training, enjoying the small pleasures of life..."), 5000}}) + table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("The other one were all cannibals, spending their time eating the organs of fellow hedgehogs..."), 5000}}) + table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("And so it began..."), 1000}}) + table.insert(startDialogue, {func = AnimSay, args = {elderh, loc("What are you doing at a distance so great, young one?"), SAY_SHOUT, 4000}}) + table.insert(startDialogue, {func = AnimSay, args = {elderh, loc("Come closer, so that your training may continue!"), SAY_SHOUT, 6000}}) + table.insert(startDialogue, {func = AnimSay, args = {youngh, loc("This is it! It's time to make Fell From Heaven fall for me..."), SAY_THINK, 6000}}) + table.insert(startDialogue, {func = AnimJump, args = {youngh, "long"}}) + table.insert(startDialogue, {func = AnimTurn, args = {princess, "Right"}}) + table.insert(startDialogue, {func = AnimSwitchHog, args = {youngh}}) + table.insert(startDialogue, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("First Steps"), loc("Press [Left] or [Right] to move around, [Enter] to jump"), 1, 4000}}) + + AddSkipFunction(onShroomAnim, SkipOnShroom, {onShroomAnim}) + table.insert(onShroomAnim, {func = AnimSay, args = {elderh, loc("I can see you have been training diligently."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = onShroomAnim}) + table.insert(onShroomAnim, {func = AnimSay, args = {elderh, loc("The wind whispers that you are ready to become familiar with tools, now..."), SAY_SAY, 4000}}) + table.insert(onShroomAnim, {func = AnimSay, args = {elderh, loc("Open that crate and we will continue!"), SAY_SAY, 5000}}) + table.insert(onShroomAnim, {func = AnimMove, args = {elderh, "Right", 2700, 0}}) + table.insert(onShroomAnim, {func = AnimTurn, args = {elderh, "Left"}}) + table.insert(onShroomAnim, {func = AnimSay, args = {princess, loc("He moves like an eagle in the sky."), SAY_THINK, 4000}}) + table.insert(onShroomAnim, {func = AnimSwitchHog, args = {youngh}}) + table.insert(onShroomAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("A leap in a leap"), loc("Go on top of the flower"), 1, 4000}}) + + AddSkipFunction(onFlowerAnim, Skipanim, {onFlowerAnim}) + table.insert(onFlowerAnim, {func = AnimSay, args = {elderh, loc("See that crate farther on the right?"), SAY_SAY, 4000}}) + table.insert(onFlowerAnim, {func = AnimSay, args = {elderh, loc("Swing, Leaks A Lot, on the wings of the wind!"), SAY_SAY, 6000}}) + table.insert(onFlowerAnim, {func = AnimSay, args = {princess, loc("His arms are so strong!"), SAY_THINK, 4000}}) + table.insert(onFlowerAnim, {func = AnimSwitchHog, args = {youngh}}) + table.insert(onFlowerAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("Hightime"), loc("Collect the crate on the right.|Hint: Select the rope, [Up] or [Down] to aim, [Space] to fire, directional keys to move.|Ropes can be fired again in the air!"), 1, 7000}}) + + AddSkipFunction(tookParaAnim, Skipanim, {tookParaAnim}) + table.insert(tookParaAnim, {func = AnimGearWait, args = {youngh, 1000}, skipFunc = Skipanim, skipArgs = tookParaAnim}) + table.insert(tookParaAnim, {func = AnimSay, args = {elderh, loc("Use the rope to get on the head of the mole, young one!"), SAY_SHOUT, 4000}}) + table.insert(tookParaAnim, {func = AnimSay, args = {elderh, loc("Worry not, for it is a peaceful animal! There is no reason to be afraid..."), SAY_SHOUT, 5000}}) + table.insert(tookParaAnim, {func = AnimSay, args = {elderh, loc("We all know what happens when you get frightened..."), SAY_SAY, 4000}}) + table.insert(tookParaAnim, {func = AnimSay, args = {youngh, loc("So humiliating..."), SAY_SAY, 4000}}) + table.insert(tookParaAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("Omnivore"), loc("Get on the head of the mole"), 1, 4000}}) + table.insert(tookParaAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(onMoleHeadAnim, Skipanim, {onMoleHeadAnim}) + table.insert(onMoleHeadAnim, {func = AnimSay, args = {elderh, loc("Perfect! Now try to get the next crate without hurting yourself!"), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = onMoleHeadAnim}) + table.insert(onMoleHeadAnim, {func = AnimSay, args = {elderh, loc("The giant umbrella from the last crate should help break the fall."), SAY_SAY, 4000}}) + table.insert(onMoleHeadAnim, {func = AnimSay, args = {princess, loc("He's so brave..."), SAY_THINK, 4000}}) + table.insert(onMoleHeadAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Leap of Faith"), loc("Use the parachute ([Space] while in air) to get the next crate"), 1, 4000}}) + table.insert(onMoleHeadAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(pastMoleHeadAnim, Skipanim, {pastMoleHeadAnim}) + table.insert(pastMoleHeadAnim, {func = AnimSay, args = {elderh, loc("I see you have already taken the leap of faith."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = pastMoleHeadAnim}) + table.insert(pastMoleHeadAnim, {func = AnimSay, args = {elderh, loc("Get that crate!"), SAY_SAY, 4000}}) + table.insert(pastMoleHeadAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(tookRope2Anim, Skipanim, {tookRope2Anim}) + table.insert(tookRope2Anim, {func = AnimSay, args = {elderh, loc("Impressive...you are still dry as the corpse of a hawk after a week in the desert..."), SAY_SAY, 5000}, skipFunc = Skipanim, skipArgs = tookRope2Anim}) + table.insert(tookRope2Anim, {func = AnimSay, args = {elderh, loc("You probably know what to do next..."), SAY_SAY, 4000}}) + table.insert(tookRope2Anim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Rising"), loc("Do the deed"), 1, 4000}}) + table.insert(tookRope2Anim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(tookPunchAnim, Skipanim, {tookPunchAnim}) + table.insert(tookPunchAnim, {func = AnimSay, args = {elderh, loc("It is time to practice your fighting skills."), SAY_SAY, 4000}}) + table.insert(tookPunchAnim, {func = AnimSay, args = {elderh, loc("Imagine those targets are the wolves that killed your parents! Take your anger out on them!"), SAY_SAY, 5000}}) + table.insert(tookPunchAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Slaughter"), loc("Destroy the targets!|Hint: Select the Shoryuken and hit [Space]|P.S. You can use it mid-air."), 1, 5000}}) + table.insert(tookPunchAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(challengeAnim, Skipanim, {challengeAnim}) + table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("I hope you are prepared for a small challenge, young one."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = challengeAnim}) + table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("Your movement skills will be evaluated now."), SAY_SAY, 4000}}) + table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("Collect all the crates, but remember, our time in this life is limited!"), SAY_SAY, 4000}}) + table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("How difficult would you like it to be?")}}) + table.insert(challengeAnim, {func = AnimSwitchHog, args = {youngh}}) + table.insert(challengeAnim, {func = AnimWait, args = {youngh, 500}}) + + AddSkipFunction(challengeFailedAnim, Skipanim, {challengeFailedAnim}) + table.insert(challengeFailedAnim, {func = AnimSay, args = {elderh, loc("Hmmm...perhaps a little more time will help."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = challengeFailedAnim}) + table.insert(challengeFailedAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000}}) + table.insert(challengeFailedAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(challengeCompletedAnim, Skipanim, {challengeCompletedAnim}) + table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("The spirits of the ancerstors are surely pleased, Leaks A Lot."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = challengeCompletedAnim}) + table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("You have proven yourself worthy to see our most ancient secret!"), SAY_SAY, 4000}}) + table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("The weapon in that last crate was bestowed upon us by the ancients!"), SAY_SAY, 4000}}) + table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("Use it with precaution!"), SAY_SAY, 4000}}) + table.insert(challengeCompletedAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Ultimate Weapon"), loc("Destroy the targets!|Hint: [Up], [Down] to aim, [Space] to shoot"), 1, 5000}}) + table.insert(challengeCompletedAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(beforeKillAnim, Skipanim, {beforeKillAnim}) + table.insert(beforeKillAnim, {func = AnimSay, args = {elderh, loc("What do my faulty eyes observe? A spy!"), SAY_SHOUT, 4000}, skipFunc = Skipanim, skipArgs = beforeKillAnim}) + table.insert(beforeKillAnim, {func = AnimFollowGear, args = {cannibal}}) + table.insert(beforeKillAnim, {func = AnimWait, args = {cannibal, 1000}}) + table.insert(beforeKillAnim, {func = AnimSay, args = {elderh, loc("Destroy him, Leaks A Lot! He is responsible for the deaths of many of us!"), SAY_SHOUT, 4000}}) + table.insert(beforeKillAnim, {func = AnimSay, args = {cannibal, loc("Oh, my!"), SAY_THINK, 4000}}) + table.insert(beforeKillAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The First Blood"), loc("Kill the cannibal!"), 1, 5000}}) + table.insert(beforeKillAnim, {func = AnimSwitchHog, args = {youngh}}) + + AddSkipFunction(closeCannim, Skipanim, {closeCannim}) + table.insert(closeCannim, {func = AnimSay, args = {elderh, loc("I see you would like his punishment to be more...personal..."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = closeCannim}) + table.insert(closeCannim, {func = AnimSay, args = {cannibal, loc("I'm certain that this is a misunderstanding, fellow hedgehogs!"), SAY_SAY, 4000}}) + table.insert(closeCannim, {func = AnimSay, args = {cannibal, loc("If only I were given a chance to explain my being here..."), SAY_SAY, 4000}}) + table.insert(closeCannim, {func = AnimSay, args = {elderh, loc("Do not let his words fool you, young one! He will stab you in the back as soon as you turn away!"), SAY_SAY, 6000}}) + table.insert(closeCannim, {func = AnimSay, args = {elderh, loc("Here...pick your weapon!"), SAY_SAY, 5000}}) + table.insert(closeCannim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The First Blood"), loc("KILL IT!"), 1, 5000}}) + table.insert(closeCannim, {func = AnimSwitchHog, args = {youngh}}) + + table.insert(cannKilledAnim, {func = AnimSay, args = {elderh, loc("Yes, yeees! You are now ready to enter the real world!"), SAY_SHOUT, 6000}}) + + table.insert(cannKilledEarlyAnim, {func = AnimSay, args = {elderh, loc("What?! A cannibal? Here? There is no time to waste! Come, you are prepared."), SAY_SHOUT, 4000}}) +end +-----------------------------Events------------------------------------ +function CheckNeedToTurn(gear) + if gear == princess then + if princessKilled ~= true then + if (GetX(princess) > GetX(youngh) and princessFace == "Right") + or (GetX(princess) < GetX(youngh) and princessFace == "Left") then + --if (GetX(princess) > GetX(youngh)) + -- or (GetX(princess) < GetX(youngh)) then + return true + end + end + else + if elderKilled ~= true then + if (GetX(elderh) > GetX(youngh) and elderFace == "Right") + or (GetX(elderh) < GetX(youngh) and elderFace == "Left") then + return true + end + end + end + return false +end + +function DoNeedToTurn(gear) + if gear == princess then + if GetX(princess) > GetX(youngh) then + HogTurnLeft(princess, true) + princessFace = "Left" + elseif GetX(princess) < GetX(youngh) then + HogTurnLeft(princess, false) + princessFace = "Right" + end + else + if GetX(elderh) > GetX(youngh) then + HogTurnLeft(elderh, true) + elderFace = "Left" + elseif GetX(elderh) < GetX(youngh) then + HogTurnLeft(elderh, false) + elderFace = "Right" + end + end +end + +function CheckDamage() + return youngdamaged and StoppedGear(youngh) +end + +function DoOnDamage() + AddAnim(damageAnim) + youngdamaged = false + AddFunction({func = ResetTurnTime, args = {}}) +end + +function CheckDeath() + return youngKilled +end + +function DoDeath() + RemoveEventFunc(CheckKilledOthers) + RemoveEventFunc(CheckDamage) + RemoveEventFunc(CheckDamagedOthers) + FinishThem() + ShowMission(loc("First Blood"), loc("The wasted youth"), loc("Leaks A Lot gave his life for his tribe! He should have survived!"), 2, 4000) +end + +function CheckDamagedOthers() + return (princessDamaged and StoppedGear(princess)) or (elderDamaged and StoppedGear(elderh)) +end + +function CheckKilledOthers() + return princessKilled or elderKilled +end + +function DoOnDamagedOthers() + if princessDamaged then + AddAnim(princessDamagedAnim) + end + if elderDamaged then + AddAnim(elderDamagedAnim) + end + elderDamaged = false + princessDamaged = false + AddFunction({func = ResetTurnTime, args = {}}) +end + +function DoKilledOthers() + AddCaption(loc("After Leaks A Lot betrayed his tribe, he joined the cannibals...")) + FinishThem() +end + +function CheckMovedUntilJump() + return GetX(youngh) >= 2343 +end + +function DoMovedUntilJump() + ShowMission(loc("First Blood"), loc("Step By Step"), loc("Hint: Double Jump - Press [Backspace] twice"), -amSkip, 0) + AddEvent(CheckOnShroom, {}, DoOnShroom, {}, 0) +end + +function CheckOnShroom() + return GetX(youngh) >= 2461 and StoppedGear(youngh) +end + +function DoOnShroom() + ropeCrate1 = SpawnUtilityCrate(2751, 1194, amRope) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(onShroomAnim) + AddEvent(CheckOnFlower, {}, DoOnFlower, {}, 0) +end + +function CheckOnFlower() + return rope1Taken and StoppedGear(youngh) +end + +function DoOnFlower() + AddAmmo(youngh, amRope, 100) + paraCrate = SpawnUtilityCrate(3245, 1758, amParachute) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(onFlowerAnim) + AddEvent(CheckTookParaCrate, {}, DoTookParaCrate, {}, 0) +end + +function CheckTookParaCrate() + return paraTaken and StoppedGear(youngh) +end + +function DoTookParaCrate() + AddAmmo(youngh, amParachute, 100) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(tookParaAnim) + AddEvent(CheckOnMoleHead, {}, DoOnMoleHead, {}, 0) + AddEvent(CheckPastMoleHead, {}, DoPastMoleHead, {}, 0) +end + +function CheckOnMoleHead() + x = GetX(youngh) + return x >= 3005 and x <= 3126 and StoppedGear(youngh) +end + +function CheckPastMoleHead() + x = GetX(youngh) + y = GetY(youngh) + return x < 3005 and y > 1500 and StoppedGear(youngh) +end + +function DoPastMoleHead() + RemoveEventFunc(CheckOnMoleHead) + ropeCrate2 = SpawnUtilityCrate(2782, 1720, amRope) + AddAmmo(youngh, amRope, 0) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(pastMoleHeadAnim) + AddEvent(CheckTookRope2, {}, DoTookRope2, {}, 0) +end + +function DoOnMoleHead() + RemoveEventFunc(CheckPastMoleHead) + ropeCrate2 = SpawnUtilityCrate(2782, 1720, amRope) + AddAmmo(youngh, amRope, 0) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(onMoleHeadAnim) + AddEvent(CheckTookRope2, {}, DoTookRope2, {}, 0) +end + +function CheckTookRope2() + return rope2Taken and StoppedGear(youngh) +end + +function DoTookRope2() + AddAmmo(youngh, amRope, 100) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(tookRope2Anim) + punchCrate = SpawnAmmoCrate(2460, 1321, amFirePunch) + AddEvent(CheckTookPunch, {}, DoTookPunch, {}) +end + +function CheckTookPunch() + return punchTaken and StoppedGear(youngh) +end + +function DoTookPunch() + AddAmmo(youngh, amFirePunch, 100) + AddAmmo(youngh, amRope, 0) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(tookPunchAnim) + targets[1] = AddGear(1594, 1185, gtTarget, 0, 0, 0, 0) + targets[2] = AddGear(2188, 1314, gtTarget, 0, 0, 0, 0) + targets[3] = AddGear(1961, 1318, gtTarget, 0, 0, 0, 0) + targets[4] = AddGear(1961, 1200, gtTarget, 0, 0, 0, 0) + targets[5] = AddGear(1800, 900, gtTarget, 0, 0, 0, 0) + AddEvent(CheckTargDestroyed, {}, DoTargDestroyed, {}, 0) +end + +function CheckTargDestroyed() + return targetsDestroyed == 5 and StoppedGear(youngh) +end + +function DoTargDestroyed() + SetGearMessage(CurrentHedgehog, 0) + AddAnim(challengeAnim) + targetsDestroyed = 0 + AddFunction({func = SetChoice, args = {}}) + ropeCrate3 = SpawnAmmoCrate(2000, 1200, amRope) + AddEvent(CheckTookRope3, {}, AddAmmo, {youngh, amRope, 100}, 0) + AddEvent(CheckCratesColled, {}, DoCratesColled, {}, 0) + AddEvent(CheckChallengeWon, {}, DoChallengeWon, {}, 0) + AddEvent(CheckTimesUp, {}, DoTimesUp, {}, 1) +end + +function CheckChoice() + return difficulty ~= 0 +end + +function DoChoice() + difficultyChoice = false + SetInputMask(0xFFFFFFFF) + StartChallenge(120000 + chalTries * 20000) +end + +function CheckCratesColled() + return cratesCollected == crateNum[difficulty] +end + +function DoCratesColled() + RemoveEventFunc(CheckTimesUp) + TurnTimeLeft = -1 + AddCaption(loc("As the challenge was completed, Leaks A Lot set foot on the ground...")) +end + +function CheckChallengeWon() + return cratesCollected == crateNum[difficulty] and StoppedGear(youngh) +end + +function DoChallengeWon() + desertCrate = SpawnAmmoCrate(1240, 1212, amDEagle) + SetGearMessage(CurrentHedgehog, 0) + AddAnim(challengeCompletedAnim) + AddEvent(CheckDesertColled, {}, DoDesertColled, {}, 0) +end + +function CheckTookRope3() + return rope3Taken +end + +function CheckTimesUp() + return TurnTimeLeft == 100 +end + +function DoTimesUp() + challengeFailed = true + DeleteGear(crates[1]) + TurnTimeLeft = -1 + AddCaption(loc("And so happenned that Leaks A Lot failed to complete the challenge! He landed, pressured by shame...")) + AddEvent(CheckChallengeFailed, {}, DoChallengeFailed, {}, 0) +end + +function CheckChallengeFailed() + return challengeFailed and StoppedGear(youngh) +end + +function DoChallengeFailed() + challengeFailed = false + SetGearMessage(CurrentHedgehog, 0) + AddAnim(challengeFailedAnim) + chalTries = chalTries + 1 + difficulty = 0 + AddFunction({func = SetChoice, args = {}}) +end + +function CheckDesertColled() + return desertTaken and StoppedGear(youngh) +end + +function DoDesertColled() + AddAmmo(youngh, amDEagle, 100) + PutTargets(1) + AddEvent(CheckTargetsKilled, {}, DoTargetsKilled, {}, 1) + AddEvent(CheckCannibalKilled, {}, DoCannibalKilledEarly, {}, 0) + ShowMission(loc("First Blood"), loc("The Bull's Eye"), loc("[Up], [Down] to aim, [Space] to shoot!"), 1, 5000) +end + +function CheckTargetsKilled() + return targetsDestroyed == 3 and StoppedGear(youngh) +end + +function DoTargetsKilled() + targetsDestroyed = 0 + targsWave = targsWave + 1 + if targsWave > 3 then + RemoveEventFunc(CheckTargetsKilled) + SetState(cannibal, gstVisible) + cannibalVisible = true + SetGearMessage(CurrentHedgehog, 0) + AddAnim(beforeKillAnim) + AddEvent(CheckCloseToCannibal, {}, DoCloseToCannibal, {}, 0) + AddEvent(CheckCannibalKilled, {}, DoCannibalKilled, {}, 0) + else + PutTargets(targsWave) + end +end + +function CheckCloseToCannibal() + if CheckCannibalKilled() then + return false + end + return math.abs(GetX(cannibal) - GetX(youngh)) <= 400 and StoppedGear(youngh) +end + +function DoCloseToCannibal() + SetGearMessage(CurrentHedgehog, 0) + AddAnim(closeCannim) + AddFunction({func = SpawnAmmoCrate, args = {targetPosX[1][1], targetPosY[1][1], amWhip}}) + AddFunction({func = SpawnAmmoCrate, args = {targetPosX[1][2], targetPosY[1][2], amBaseballBat}}) + AddFunction({func = SpawnAmmoCrate, args = {targetPosX[1][3], targetPosY[1][3], amHammer}}) +end + +function CheckCannibalKilled() + return cannibalKilled and StoppedGear(youngh) +end + +function DoCannibalKilled() + AddAnim(cannKilledAnim) + SaveCampaignVar("Progress", "1") +end + +function DoCannibalKilledEarly() + AddAnim(cannKilledEarlyAnim) + DoCannibalKilled() +end + +-----------------------------Misc-------------------------------------- +function StartChallenge(time) + cratesCollected = 0 + PutCrate(1) + TurnTimeLeft = time + ShowMission(loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000) +end + +function SetChoice() + SetInputMask(band(0xFFFFFFFF, bnot(gmAnimate+gmAttack+gmDown+gmHJump+gmLJump+gmSlot+gmSwitch+gmTimer+gmUp+gmWeapon))) + difficultyChoice = true + ShowMission(loc("First Blood"), loc("The Torment"), loc("Select difficulty: [Left] - easier or [Right] - harder"), 0, 4000) + AddEvent(CheckChoice, {}, DoChoice, {}, 0) +end + +function SetTime(time) + TurnTimeLeft = time +end + +function ResetTurnTime() + TurnTimeLeft = tTime + tTime = -1 +end + +function PutCrate(i) + if i > crateNum[difficulty] then + return + end + if difficulty == 1 then + crates[1] = SpawnAmmoCrate(targXdif1[i], targYdif1[i], amRope) + else + crates[1] = SpawnAmmoCrate(targXdif2[i], targYdif2[i], amRope) + end +end + +function PutTargets(i) + targets[1] = AddGear(targetPosX[i][1], targetPosY[i][1], gtTarget, 0, 0, 0, 0) + targets[2] = AddGear(targetPosX[i][2], targetPosY[i][2], gtTarget, 0, 0, 0, 0) + targets[3] = AddGear(targetPosX[i][3], targetPosY[i][3], gtTarget, 0, 0, 0, 0) +end + +function FinishThem() + SetHealth(elderh, 0) + SetHealth(youngh, 0) + SetHealth(princess, 0) +end +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 69 + GameFlags = gfInfAttack + gfSolidLand + gfDisableWind + TurnTime = 100000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + MapGen = 0 + TemplateFilter = 6 + TemplateNumber = 33 + Theme = "Nature" + + + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + youngh = AddHog(loc("Leaks A Lot"), 0, 100, "Rambo") + elderh = AddHog(loc("Righteous Beard"), 0, 99, "IndianChief") + princess = AddHog(loc("Fell From Heaven"), 0, 300, "tiara") + AnimSetGearPosition(princess, 1911, 1361) + HogTurnLeft(princess, true) + AnimSetGearPosition(elderh, 2667, 1208) + HogTurnLeft(elderh, true) + AnimSetGearPosition(youngh, 1862, 1362) + HogTurnLeft(youngh, false) + + AddTeam(loc("Cannibals"), 14483456, "Skull", "Island", "Pirate","cm_vampire") + cannibal = AddHog(loc("Brainiac"), 0, 5, "Zombi") + AnimSetGearPosition(cannibal, 525, 1256) + HogTurnLeft(cannibal, false) + + AnimInit() + AnimationSetup() +end + +function onGameStart() + TurnTimeLeft = -1 + FollowGear(youngh) + ShowMission(loc("A Classic Fairytale"), loc("First Blood"), loc("Finish your training|Hint: Animations can be skipped with the [Precise] key."), -amSkip, 0) + SetState(cannibal, gstInvisible) + + AddAnim(startDialogue) + princessFace = "Right" + AddEvent(CheckNeedToTurn, {princess}, DoNeedToTurn, {princess}, 1) + AddEvent(CheckNeedToTurn, {elderh}, DoNeedToTurn, {elderh}, 1) + AddEvent(CheckDamage, {}, DoOnDamage, {}, 1) + AddEvent(CheckDeath, {}, DoDeath, {}, 0) + AddEvent(CheckDamagedOthers, {}, DoOnDamagedOthers, {}, 1) + AddEvent(CheckKilledOthers, {}, DoKilledOthers, {}, 0) + AddEvent(CheckMovedUntilJump, {}, DoMovedUntilJump, {}, 0) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + if gear == ropeCrate1 then + rope1Taken = true + elseif gear == paraCrate then + paraTaken = true + elseif gear == ropeCrate2 then + rope2Taken = true + elseif gear == ropeCrate3 then + rope3Taken = true + elseif gear == crates[1] and challengeFailed == false then + crates[1] = nil + cratesCollected = cratesCollected + 1 + PutCrate(cratesCollected + 1) + elseif gear == punchCrate then + punchTaken = true + elseif gear == desertCrate then + desertTaken = true + elseif GetGearType(gear) == gtTarget then + i = 1 + while targets[i] ~= gear do + i = i + 1 + end + targets[i] = nil + targetsDestroyed = targetsDestroyed + 1 + elseif gear == cannibal then + cannibalKilled = true + elseif gear == princess then + princessKilled = true + elseif gear == elderh then + elderKilled = true + elseif gear == youngh then + youngKilled = true + end +end + +function onAmmoStoreInit() + SetAmmo(amWhip, 0, 0, 0, 8) + SetAmmo(amBaseballBat, 0, 0, 0, 8) + SetAmmo(amHammer, 0, 0, 0, 8) +end + +function onNewTurn() + if CurrentHedgehog == cannibal and cannibalVisible == false then + SetState(cannibal, gstInvisible) + end + SwitchHog(youngh) + FollowGear(youngh) + TurnTimeLeft = -1 +end + +function onGearDamage(gear, damage) + if gear == youngh then + youngdamaged = true + tTime = TurnTimeLeft + elseif gear == princess then + princessDamaged = true + tTime = TurnTimeLeft + elseif gear == elderh then + elderDamaged = true + tTime = TurnTimeLeft + elseif gear == cannibal then + cannibalVisible = true + cannibalDamaged = true + SetState(cannibal, 0) + end +end + +function onPrecise() + if GameTime > 2000 then + SetAnimSkip(true) + end +end + +function onLeft() + if difficultyChoice == true then + difficulty = 1 + end +end + +function onRight() + if difficultyChoice == true then + difficulty = 2 + end +end + diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/journey.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,1075 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +--///////////////////////////////CONSTANTS/////////////////////////// + +choiceAccepted = 1 +choiceRefused = 2 +choiceAttacked = 3 + +endStage = 1 + +cannibalNum = 8 +cannibalNames = {loc("John"), loc("Flesh for Brainz"), loc("Eye Chewer"), loc("Torn Muscle"), + loc("Nom-Nom"), loc("Vedgies"), loc("Brain Blower"), loc("Gorkij")} +cannibalPos = {{2471, 1174}, {939, 1019}, {1953, 902}, {3055, 1041}, + {1121, 729}, {1150, 718}, {1149, 680}, {1161, 773}} + +startLeaksPosDuo = {3572, 1426} +startEventXDuo = 3300 +startDensePosDuo = {3454, 1471} +startCyborgPosDuo = {3202, 1307} +midDensePosDuo = {1464, 1410} +midCyborgPosDuo = {1264, 1390} + +--///////////////////////////////VARIABLES/////////////////////////// + +m2Choice = 0 +m2DenseDead = 0 +m2RamonDead = 0 +m2SpikyDead = 0 + +TurnsLeft = 0 +stage = 0 + +--cyborgHidden = false +--princessHidden = false +blowTaken = false +fireTaken = false +gravityTaken = false +sniperTaken = false +girderTaken = false +girder1Taken = false +girder2Taken = false +leaksDead = false +denseDead = false +princessDead = false +cyborgDead = false +cannibalDead = {} +hedgeHidden = {} + +startAnim = {} +startAnimAD = {} +startAnimAL = {} +startAnimRL = {} + +pastFlowerAnimAL = {} +pastFlowerAnimRL = {} +pastFlowerAnim = {} + +outPitAnimAL = {} +outPitAnimRL = {} +outPitAnim = {} + +midAnim = {} +midAnimAD = {} + +failAnim = {} +failAnimAD = {} + +endAnim = {} +endAnimAD = {} +endAnimAL = {} +endAnimRL = {} + +endFailAnim = {} +endFailAnimAD = {} + +winAnim = {} +winAnimAD = {} + +--/////////////////////////Animation Functions/////////////////////// +function AfterMidFailAnim() + ParseCommand("teamgone " .. loc("Natives")) + TurnTimeLeft = 0 +end + +function AfterMidAnimAlone() + SetupCourse() + for i = 5, 8 do + RestoreHedge(cannibals[i]) + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + end + + AddAmmo(cannibals[5], amDEagle, 0) + + AddEvent(CheckGirderTaken, {}, DoGirderTaken, {}, 0) + AddEvent(CheckOnFirstGirder, {}, DoOnFirstGirder, {}, 0) + AddEvent(CheckTookSniper, {}, DoTookSniper, {}, 0) + AddEvent(CheckFailedCourse, {}, DoFailedCourse, {}, 0) + SetGearMessage(leaks, 0) + TurnsLeft = 12 + TurnTimeLeft = TurnTime + ShowMission(loc("The Journey Back"), loc("Collateral Damage"), loc("Save the princess by collecting the crate in under 12 turns!"), 0, 6000) + -----------------------///////////////------------ + --AnimSetGearPosition(leaks, 417, 1800) +end + +function SkipEndAnimAlone() + RestoreHedge(cyborg) + RestoreHedge(princess) + AnimSetGearPosition(cyborg, 437, 1700) + AnimSetGearPosition(princess, 519, 1722) +end + +function SkipEndAnimDuo() + RestoreHedge(cyborg) + RestoreHedge(princess) + if princessHidden then + RestoreHog(princess) + princessHidden = false + end + AnimSetGearPosition(cyborg, 437, 1700) + AnimSetGearPosition(princess, 519, 1722) + AnimSetGearPosition(leaks, 763, 1760) + AnimSetGearPosition(dense, 835, 1519) + HogTurnLeft(leaks, true) + HogTurnLeft(dense, true) +end + +function AfterEndAnimAlone() + stage = endStage + SwitchHog(leaks) + SetGearMessage(leaks, 0) + TurnTimeLeft = -1 + ShowMission(loc("The Journey Back"), loc("Collateral Damage II"), loc("Save Fell From Heaven!"), 1, 4000) + AddEvent(CheckLost, {}, DoLost, {}, 0) + AddEvent(CheckWon, {}, DoWon, {}, 0) + RemoveEventFunc(CheckFailedCourse) +end + +function AfterEndAnimDuo() + stage = endStage + SwitchHog(leaks) + SetGearMessage(leaks, 0) + SetGearMessage(dense, 0) + TurnTimeLeft = -1 + ShowMission(loc("The Journey Back"), loc("Collateral Damage II"), loc("Save Fell From Heaven!"), 1, 4000) + AddEvent(CheckLost, {}, DoLost, {}, 0) + AddEvent(CheckWon, {}, DoWon, {}, 0) +end + +function SkipMidAnimAlone() + AnimSetGearPosition(leaks, 2656, 1842) + AnimSwitchHog(leaks) + SetInputMask(0xFFFFFFFF) + AnimWait(dense, 1) + AddFunction({func = HideHedge, args = {princess}}) + AddFunction({func = HideHedge, args = {cyborg}}) +end + +function AfterStartAnim() + SetGearMessage(leaks, 0) + TurnTimeLeft = TurnTime + local goal = loc("Get the crate on the other side of the island!|") + local hint = loc("Hint: you might want to stay out of sight and take all the crates...|") + local stuck = loc("If you get stuck, use your Desert Eagle or restart the mission!|") + local conds = loc("Leaks A Lot must survive!") + if m2DenseDead == 0 then + conds = loc("Your hogs must survive!") + end + ShowMission(loc("The Journey Back"), loc("Adventurous"), goal .. hint .. stuck .. conds, 0, 7000) +end + +function SkipStartAnim() + AnimSwitchHog(leaks) +end + +function PlaceCratesDuo() + SpawnAmmoCrate(3090, 827, amBaseballBat) + girderCrate1 = SpawnUtilityCrate(2466, 1814, amGirder) + girderCrate2 = SpawnUtilityCrate(2630, 1278, amGirder) + SpawnUtilityCrate(2422, 1810, amParachute) + SpawnUtilityCrate(3157, 1009, amLowGravity) + sniperCrate = SpawnAmmoCrate(784, 1715, amSniperRifle) +end + +function PlaceMinesDuo() + SetTimer(AddGear(2920, 1448, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2985, 1338, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(3005, 1302, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(3030, 1270, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(3046, 1257, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2954, 1400, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2967, 1385, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2849, 1449, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2811, 1436, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2773, 1411, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2732, 1390, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2700, 1362, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2642, 1321, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2172, 1417, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2190, 1363, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2219, 1332, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1201, 1207, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1247, 1205, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1295, 1212, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1356, 1209, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1416, 1201, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1466, 1201, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1678, 1198, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1738, 1198, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1796, 1198, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1637, 1217, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1519, 1213, gtMine, 0, 0, 0, 0), 5000) +end + +function AfterPastFlowerAnim() + PlaceMinesDuo() + AddEvent(CheckDensePit, {}, DoDensePit, {}, 0) + AddEvent(CheckTookGirder1, {}, DoTookGirder1, {}, 0) + AddEvent(CheckTookGirder2, {}, DoTookGirder2, {}, 0) + SetGearMessage(leaks, 0) + SetGearMessage(dense, 0) + TurnTimeLeft = 0 + ShowMission(loc("The Journey Back"), loc("The Savior"), loc("Get Dense Cloud out of the pit!"), 1, 5000) +end + +function SkipPastFlowerAnim() + AnimSetGearPosition(dense, 2656, 1842) + AnimSwitchHog(dense) + AnimWait(dense, 1) + AddFunction({func = HideHedge, args = {cyborg}}) +end + +function AfterOutPitAnim() + SetupCourseDuo() + RestoreHedge(cannibals[5]) + AddAmmo(cannibals[5], amDEagle, 0) + HideHedge(cannibals[5]) + AddEvent(CheckTookFire, {}, DoTookFire, {}, 0) + SetGearMessage(leaks, 0) + SetGearMessage(dense, 0) + TurnTimeLeft = 0 + ShowMission(loc("The Journey Back"), loc("They never learn"), loc("Free Dense Cloud and continue the mission!"), 1, 5000) +end + +function SkipOutPitAnim() + AnimSetGearPosition(dense, unpack(midDensePosDuo)) + AnimSwitchHog(dense) + AnimWait(dense, 1) + AddFunction({func = HideHedge, args = {cyborg}}) +end + +function RestoreCyborg(x, y, xx, yy) + RestoreHedge(cyborg) + RestoreHedge(princess) + AnimOutOfNowhere(cyborg, x, y) + AnimOutOfNowhere(princess, xx, yy) + HogTurnLeft(princess, false) + return true +end + +function RestoreCyborgOnly(x, y) + RestoreHedge(cyborg) + SetState(cyborg, 0) + AnimOutOfNowhere(cyborg, x, y) + return true +end + +function TargetPrincess() + ParseCommand("setweap " .. string.char(amDEagle)) + SetGearMessage(cyborg, gmUp) + return true +end + +function HideCyborg() + HideHedge(cyborg) + HideHedge(princess) +end + +function HideCyborgOnly() + HideHedge(cyborg) +end + +function SetupKillRoom() + PlaceGirder(2342, 1814, 2) + PlaceGirder(2294, 1783, 0) + PlaceGirder(2245, 1814, 2) +end + +function SetupCourseDuo() + PlaceGirder(1083, 1152, 6) + PlaceGirder(1087, 1150, 6) + PlaceGirder(1133, 1155, 0) + PlaceGirder(1135, 1152, 0) + PlaceGirder(1135, 1078, 0) + PlaceGirder(1087, 1016, 2) + PlaceGirder(1018, 921, 5) + PlaceGirder(1016, 921, 5) + PlaceGirder(962, 782, 6) + PlaceGirder(962, 662, 2) + PlaceGirder(962, 661, 2) + PlaceGirder(962, 650, 2) + PlaceGirder(962, 630, 2) + PlaceGirder(1033, 649, 0) + PlaceGirder(952, 650, 0) + + fireCrate = SpawnAmmoCrate(1846, 1100, amFirePunch) + SpawnUtilityCrate(1900, 1100, amPickHammer) + SpawnAmmoCrate(950, 674, amDynamite) + SpawnUtilityCrate(994, 825, amRope) + SpawnUtilityCrate(570, 1357, amLowGravity) +end + +function DumpMines() + SetTimer(AddGear(2261, 1835, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2280, 1831, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2272, 1809, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2290, 1815, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2278, 1815, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2307, 1811, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2286, 1820, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2309, 1813, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2303, 1822, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2317, 1827, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2312, 1816, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2316, 1812, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2307, 1802, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2276, 1818, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2284, 1816, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2292, 1811, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2295, 1814, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2306, 1811, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2292, 1815, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2314, 1815, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2286, 1813, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2275, 1813, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2269, 1814, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2273, 1812, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2300, 1808, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2322, 1812, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2323, 1813, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2311, 1811, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2303, 1809, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2287, 1808, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2282, 1808, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2277, 1809, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2296, 1809, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(2314, 1818, gtMine, 0, 0, 0, 0), 5000) +end + +function SetupAnimRefusedDied() + SetupAnimAcceptedDied() + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("I just wonder where Ramon and Spiky disappeared..."), SAY_THINK, 6000}}) +end + +function SetupAnimAttacked() + SetupAnimAcceptedDied() + startAnim = {} + table.insert(startAnim, {func = AnimWait, args = {leaks, 3000}}) + table.insert(startAnim, {func = AnimTurn, args = {leaks, "Left"}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("I wonder where Dense Cloud is..."), SAY_THINK, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("He must be in the village already."), SAY_THINK, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("I'd better get going myself."), SAY_THINK, 4000}}) + + midAnim = {} + table.insert(midAnim, {func = AnimWait, args = {leaks, 500}}) + table.insert(midAnim, {func = AnimCustomFunction, swh = false, args = {leaks, RestoreCyborg, {1300, 1200, 1390, 1200}}}) + table.insert(midAnim, {func = AnimSwitchHog, args = {cyborg}}) + table.insert(midAnim, {func = AnimCustomFunction, args = {cyborg, TargetPrincess, {}}}) + table.insert(midAnim, {func = AnimSay, args = {cyborg, loc("Welcome, Leaks A Lot!"), SAY_SAY, 3000}}) + table.insert(midAnim, {func = AnimSay, args = {cyborg, loc("I want to play a game..."), SAY_SAY, 3000}}) + table.insert(midAnim, {func = AnimSay, args = {princess, loc("Help me, please!!!"), SAY_SHOUT, 3000}}) + table.insert(midAnim, {func = AnimSay, args = {cyborg, loc("If you can get that crate fast enough, your beloved \"princess\" may go free."), SAY_SAY, 7000}}) + table.insert(midAnim, {func = AnimSay, args = {cyborg, loc("However, if you fail to do so, she dies a most violent death! Muahahaha!"), SAY_SAY, 8000}}) + table.insert(midAnim, {func = AnimSay, args = {cyborg, loc("Good luck...or else!"), SAY_SAY, 4000}}) + table.insert(midAnim, {func = AnimTeleportGear, args = {leaks, 2656, 1842}}) + table.insert(midAnim, {func = AnimCustomFunction, args = {cyborg, HideCyborg, {}}, swh = false}) + table.insert(midAnim, {func = AnimSay, args = {leaks, loc("Hey! This is cheating!"), SAY_SHOUT, 4000}}) + AddSkipFunction(midAnim, SkipMidAnimAlone, {}) +end + +function SetupAnimAcceptedDied() + table.insert(startAnimAD, {func = AnimWait, args = {leaks, 3000}}) + table.insert(startAnimAD, {func = AnimTurn, args = {leaks, "Left"}}) + table.insert(startAnimAD, {func = AnimSay, args = {leaks, loc("I need to get to the other side of this island, fast!"), SAY_THINK, 5000}}) + table.insert(startAnimAD, {func = AnimSay, args = {leaks, loc("With Dense Cloud on the land of shadows, I'm the village's only hope..."), SAY_THINK, 7000}}) + + table.insert(midAnimAD, {func = AnimWait, args = {leaks, 500}}) + table.insert(midAnimAD, {func = AnimCustomFunction, swh = false, args = {leaks, RestoreCyborg, {1300, 1200, 1390, 1200}}}) + table.insert(midAnimAD, {func = AnimSwitchHog, args = {cyborg}}) + table.insert(midAnimAD, {func = AnimCustomFunction, args = {cyborg, TargetPrincess, {}}}) + table.insert(midAnimAD, {func = AnimSay, args = {cyborg, loc("Welcome, Leaks A Lot!"), SAY_SAY, 3000}}) + table.insert(midAnimAD, {func = AnimSay, args = {cyborg, loc("I want to play a game..."), SAY_SAY, 3000}}) + table.insert(midAnimAD, {func = AnimSay, args = {princess, loc("Help me, please!!!"), SAY_SHOUT, 3000}}) + table.insert(midAnimAD, {func = AnimSay, args = {cyborg, loc("If you can get that crate fast enough, your beloved \"princess\" may go free."), SAY_SAY, 7000}}) + table.insert(midAnimAD, {func = AnimSay, args = {cyborg, loc("However, if you fail to do so, she dies a most violent death, just like your friend! Muahahaha!"), SAY_SAY, 8000}}) + table.insert(midAnimAD, {func = AnimSay, args = {cyborg, loc("Good luck...or else!"), SAY_SAY, 4000}}) + table.insert(midAnimAD, {func = AnimTeleportGear, args = {leaks, 2656, 1842}}) + table.insert(midAnimAD, {func = AnimCustomFunction, args = {cyborg, HideCyborg, {}}, swh = false}) + table.insert(midAnimAD, {func = AnimSay, args = {leaks, loc("Hey! This is cheating!"), SAY_SHOUT, 4000}}) + AddSkipFunction(midAnimAD, SkipMidAnimAlone, {}) + + table.insert(failAnimAD, {func = AnimCustomFunction, swh = false, args = {leaks, RestoreCyborg, {2299, 1687, 2294, 1841}}}) + table.insert(failAnimAD, {func = AnimTeleportGear, args = {leaks, 2090, 1841}}) + table.insert(failAnimAD, {func = AnimCustomFunction, swh = false, args = {cyborg, SetupKillRoom, {}}}) + table.insert(failAnimAD, {func = AnimTurn, swh = false, args = {cyborg, "Left"}}) + table.insert(failAnimAD, {func = AnimTurn, swh = false, args = {princess, "Left"}}) + table.insert(failAnimAD, {func = AnimTurn, swh = false, args = {leaks, "Right"}}) + table.insert(failAnimAD, {func = AnimWait, args = {cyborg, 1000}}) + table.insert(failAnimAD, {func = AnimSay, args = {cyborg, loc("You have failed to complete your task, young one!"), SAY_SAY, 6000}}) + table.insert(failAnimAD, {func = AnimSay, args = {cyborg, loc("It's time you learned that your actions have consequences!"), SAY_SAY, 7000}}) + table.insert(failAnimAD, {func = AnimSay, args = {princess, loc("No! Please, help me!"), SAY_SAY, 4000}}) + table.insert(failAnimAD, {func = AnimSwitchHog, args = {cyborg}}) + table.insert(failAnimAD, {func = AnimCustomFunction, args = {cyborg, DumpMines, {}}}) + table.insert(failAnimAD, {func = AnimCustomFunction, args = {cyborg, KillPrincess, {}}}) + table.insert(failAnimAD, {func = AnimWait, args = {cyborg, 12000}}) + table.insert(failAnimAD, {func = AnimSay, args = {leaks, loc("No! What have I done?! What have YOU done?!"), SAY_SHOUT, 6000}}) + + table.insert(endAnimAD, {func = AnimCustomFunction, swh = false, args = {leaks, RestoreCyborg, {437, 1700, 519, 1722}}}) + table.insert(endAnimAD, {func = AnimTurn, swh = false, args = {cyborg, "Right"}}) + table.insert(endAnimAD, {func = AnimTurn, swh = false, args = {princess, "Right"}}) + table.insert(endAnimAD, {func = AnimSay, args = {princess, loc("Help me, Leaks!"), SAY_SHOUT, 3000}}) + table.insert(endAnimAD, {func = AnimSay, args = {leaks, loc("But you said you'd let her go!"), SAY_SHOUT, 5000}}) + table.insert(endAnimAD, {func = AnimSay, args = {cyborg, loc("And you believed me? Oh, god, that's cute!"), SAY_SHOUT, 7000}}) + table.insert(endAnimAD, {func = AnimSay, args = {leaks, loc("I won't let you kill her!"), SAY_SHOUT, 4000}}) + AddSkipFunction(endAnimAD, SkipEndAnimAlone, {}) + + table.insert(endFailAnim, {func = AnimCaption, args = {leaks, loc("Leaks A Lot, depressed for killing his loved one, failed to save the village..."), 3000}}) + + table.insert(winAnimAD, {func = AnimCustomFunction, args = {princess, CondNeedToTurn, {leaks, princess}}}) + table.insert(winAnimAD, {func = AnimSay, args = {princess, loc("Thank you, oh, thank you, Leaks A Lot!"), SAY_SAY, 5000}}) + table.insert(winAnimAD, {func = AnimSay, args = {princess, loc("How can I ever repay you for saving my life?"), SAY_SAY, 6000}}) + table.insert(winAnimAD, {func = AnimSay, args = {leaks, loc("There's nothing more satisfying for me than seeing you share your beauty with the world every morning, my princess!"), SAY_SAY, 10000}}) + table.insert(winAnimAD, {func = AnimSay, args = {leaks, loc("Let's go home!"), SAY_SAY, 3000}}) + table.insert(winAnimAD, {func = AnimCaption, args = {leaks, loc("And so they discovered that cyborgs weren't invulnerable..."), 2000}}) + + startAnim = startAnimAD + midAnim = midAnimAD + failAnim = failAnimAD + endAnim = endAnimAD + endFailAnim = endFailAnimAD + winAnim = winAnimAD +end + +function SetupAnimAcceptedLived() + table.insert(startAnimAL, {func = AnimWait, args = {leaks, 3000}}) + table.insert(startAnimAL, {func = AnimCustomFunction, args = {dense, CondNeedToTurn, {leaks, dense}}}) + table.insert(startAnimAL, {func = AnimSay, args = {leaks, loc("All right, we just need to get to the other side of the island!"), SAY_SAY, 8000}}) + table.insert(startAnimAL, {func = AnimSay, args = {dense, loc("We have no time to waste..."), SAY_SAY, 4000}}) + table.insert(startAnimAL, {func = AnimSwitchHog, args = {leaks}}) + AddSkipFunction(startAnimAL, SkipStartAnim, {}) + + table.insert(pastFlowerAnimAL, {func = AnimCustomFunction, args = {dense, RestoreCyborgOnly, {unpack(startCyborgPosDuo)}}, swh = false}) + table.insert(pastFlowerAnimAL, {func = AnimTurn, args = {cyborg, "Right"}}) + table.insert(pastFlowerAnimAL, {func = AnimSay, args = {cyborg, loc("Well, well! Isn't that the cutest thing you've ever seen?"), SAY_SAY, 7000}}) + table.insert(pastFlowerAnimAL, {func = AnimSay, args = {cyborg, loc("Two little hogs cooperating, getting past obstacles..."), SAY_SAY, 7000}}) + table.insert(pastFlowerAnimAL, {func = AnimSay, args = {cyborg, loc("Let me test your skills a little, will you?"), SAY_SAY, 6000}}) + table.insert(pastFlowerAnimAL, {func = AnimTeleportGear, args = {cyborg, 2456, 1842}}) + table.insert(pastFlowerAnimAL, {func = AnimTeleportGear, args = {dense, 2656, 1842}}) + table.insert(pastFlowerAnimAL, {func = AnimCustomFunction, args = {dense, CondNeedToTurn, {cyborg, dense}}}) + table.insert(pastFlowerAnimAL, {func = AnimSay, args = {dense, loc("Why are you doing this?"), SAY_SAY, 4000}}) + table.insert(pastFlowerAnimAL, {func = AnimSay, args = {cyborg, loc("To help you, of course!"), SAY_SAY, 4000}}) + table.insert(pastFlowerAnimAL, {func = AnimSwitchHog, args = {dense}}) + table.insert(pastFlowerAnimAL, {func = AnimDisappear, swh = false, args = {cyborg, 3781, 1583}}) + table.insert(pastFlowerAnimAL, {func = AnimCustomFunction, swh = false, args = {cyborg, HideCyborgOnly, {}}}) + AddSkipFunction(pastFlowerAnimAL, SkipPastFlowerAnim, {}) + + table.insert(outPitAnimAL, {func = AnimCustomFunction, args = {dense, RestoreCyborgOnly, {unpack(midCyborgPosDuo)}}, swh = false}) + table.insert(outPitAnimAL, {func = AnimTurn, args = {cyborg, "Right"}}) + table.insert(outPitAnimAL, {func = AnimTeleportGear, args = {dense, unpack(midDensePosDuo)}}) + table.insert(outPitAnimAL, {func = AnimTurn, args = {dense, "Left"}}) + table.insert(outPitAnimAL, {func = AnimSay, args = {dense, loc("OH, COME ON!"), SAY_SHOUT, 3000}}) + table.insert(outPitAnimAL, {func = AnimSay, args = {cyborg, loc("Let's see what your comrade does now!"), SAY_SAY, 5000}}) + table.insert(outPitAnimAL, {func = AnimSwitchHog, args = {dense}}) + table.insert(outPitAnimAL, {func = AnimDisappear, swh = false, args = {cyborg, 3781, 1583}}) + table.insert(outPitAnimAL, {func = AnimCustomFunction, swh = false, args = {cyborg, HideCyborgOnly, {}}}) + AddSkipFunction(outPitAnimAL, SkipOutPitAnim, {}) + + table.insert(endAnim, {func = AnimCustomFunction, swh = false, args = {leaks, RestoreCyborg, {437, 1700, 519, 1722}}}) + table.insert(endAnim, {func = AnimTeleportGear, args = {leaks, 763, 1760}}) + table.insert(endAnim, {func = AnimTeleportGear, args = {dense, 835, 1519}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {leaks, "Left"}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {dense, "Left"}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {cyborg, "Right"}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {princess, "Right"}}) + table.insert(endAnim, {func = AnimSay, args = {princess, loc("Help me, please!"), SAY_SHOUT, 3000}}) + table.insert(endAnim, {func = AnimSay, args = {leaks, loc("What are you doing? Let her go!"), SAY_SHOUT, 5000}}) + table.insert(endAnim, {func = AnimSay, args = {cyborg, loc("Yeah? Watcha gonna do? Cry?"), SAY_SHOUT, 5000}}) + table.insert(endAnim, {func = AnimSay, args = {leaks, loc("We won't let you hurt her!"), SAY_SHOUT, 4000}}) + AddSkipFunction(endAnim, SkipEndAnimDuo, {}) + + table.insert(endFailAnim, {func = AnimCaption, args = {leaks, loc("Leaks A Lot, depressed for killing his loved one, failed to save the village..."), 3000}}) + + table.insert(winAnim, {func = AnimCustomFunction, args = {princess, CondNeedToTurn, {leaks, princess}}}) + table.insert(winAnim, {func = AnimSay, args = {princess, loc("Thank you, oh, thank you, my heroes!"), SAY_SAY, 5000}}) + table.insert(winAnim, {func = AnimSay, args = {princess, loc("How can I ever repay you for saving my life?"), SAY_SAY, 6000}}) + table.insert(winAnim, {func = AnimSay, args = {leaks, loc("There's nothing more satisfying to us than seeing you share your beauty..."), SAY_SAY, 7000}}) + table.insert(winAnim, {func = AnimSay, args = {leaks, loc("... share your beauty with the world every morning, my princess!"), SAY_SAY, 7000}}) + table.insert(winAnim, {func = AnimSay, args = {leaks, loc("Let's go home!"), SAY_SAY, 3000}}) + table.insert(winAnim, {func = AnimCaption, args = {leaks, loc("And so they discovered that cyborgs weren't invulnerable..."), 2000}}) + + startAnim = startAnimAL + pastFlowerAnim = pastFlowerAnimAL + outPitAnim = outPitAnimAL +end + +function SetupAnimRefusedLived() + table.insert(startAnimRL, {func = AnimWait, args = {leaks, 3000}}) + table.insert(startAnimRL, {func = AnimCustomFunction, args = {dense, CondNeedToTurn, {leaks, dense}}}) + table.insert(startAnimRL, {func = AnimSay, args = {leaks, loc("All right, we just need to get to the other side of the island!"), SAY_SAY, 7000}}) + table.insert(startAnimRL, {func = AnimSay, args = {dense, loc("Dude, can you see Ramon and Spiky?"), SAY_SAY, 5000}}) + table.insert(startAnimRL, {func = AnimSay, args = {leaks, loc("No...I wonder where they disappeared?!"), SAY_SAY, 5000}}) + AddSkipFunction(startAnimRL, SkipStartAnim, {}) + + table.insert(pastFlowerAnimRL, {func = AnimCustomFunction, args = {dense, RestoreCyborgOnly, {unpack(startCyborgPosDuo)}}, swh = false}) + table.insert(pastFlowerAnimRL, {func = AnimTurn, args = {cyborg, "Right"}}) + table.insert(pastFlowerAnimRL, {func = AnimSay, args = {cyborg, loc("Well, well! Isn't that the cutest thing you've ever seen?"), SAY_SAY, 7000}}) + table.insert(pastFlowerAnimRL, {func = AnimSay, args = {cyborg, loc("Two little hogs cooperating, getting past obstacles..."), SAY_SAY, 7000}}) + table.insert(pastFlowerAnimRL, {func = AnimSay, args = {cyborg, loc("Let me test your skills a little, will you?"), SAY_SAY, 6000}}) + table.insert(pastFlowerAnimRL, {func = AnimTeleportGear, args = {cyborg, 2456, 1842}}) + table.insert(pastFlowerAnimRL, {func = AnimTeleportGear, args = {dense, 2656, 1842}}) + table.insert(pastFlowerAnimRL, {func = AnimCustomFunction, args = {dense, CondNeedToTurn, {cyborg, dense}}}) + table.insert(pastFlowerAnimRL, {func = AnimSay, args = {dense, loc("Why are you doing this?"), SAY_SAY, 4000}}) + table.insert(pastFlowerAnimRL, {func = AnimSay, args = {cyborg, loc("You couldn't possibly believe that after refusing my offer I'd just let you go!"), SAY_SAY, 9000}}) + table.insert(pastFlowerAnimRL, {func = AnimSay, args = {cyborg, loc("You're funny!"), SAY_SAY, 4000}}) + table.insert(pastFlowerAnimRL, {func = AnimSwitchHog, args = {dense}}) + table.insert(pastFlowerAnimRL, {func = AnimDisappear, swh = false, args = {cyborg, 3781, 1583}}) + table.insert(pastFlowerAnimRL, {func = AnimCustomFunction, swh = false, args = {cyborg, HideCyborgOnly, {}}}) + AddSkipFunction(pastFlowerAnimRL, SkipPastFlowerAnim, {}) + + table.insert(outPitAnimRL, {func = AnimCustomFunction, args = {dense, RestoreCyborgOnly, {unpack(midCyborgPosDuo)}}, swh = false}) + table.insert(outPitAnimRL, {func = AnimTurn, args = {cyborg, "Right"}}) + table.insert(outPitAnimRL, {func = AnimTeleportGear, args = {dense, unpack(midDensePosDuo)}}) + table.insert(outPitAnimRL, {func = AnimTurn, args = {dense, "Left"}}) + table.insert(outPitAnimRL, {func = AnimSay, args = {dense, loc("OH, COME ON!"), SAY_SHOUT, 3000}}) + table.insert(outPitAnimRL, {func = AnimSay, args = {cyborg, loc("Let's see what your comrade does now!"), SAY_SAY, 5000}}) + table.insert(outPitAnimRL, {func = AnimSwitchHog, args = {dense}}) + table.insert(outPitAnimRL, {func = AnimDisappear, swh = false, args = {cyborg, 3781, 1583}}) + table.insert(outPitAnimRL, {func = AnimCustomFunction, swh = false, args = {cyborg, HideCyborgOnly, {}}}) + AddSkipFunction(outPitAnimRL, SkipOutPitAnim, {}) + + table.insert(endAnim, {func = AnimCustomFunction, args = {leaks, RestoreCyborg, {437, 1700, 519, 1722}}}) + table.insert(endAnim, {func = AnimTeleportGear, args = {leaks, 763, 1760}}) + table.insert(endAnim, {func = AnimTeleportGear, args = {dense, 835, 1519}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {leaks, "Left"}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {dense, "Left"}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {cyborg, "Right"}}) + table.insert(endAnim, {func = AnimTurn, swh = false, args = {princess, "Right"}}) + table.insert(endAnim, {func = AnimSay, args = {princess, loc("Help me, please!"), SAY_SHOUT, 3000}}) + table.insert(endAnim, {func = AnimSay, args = {leaks, loc("What are you doing? Let her go!"), SAY_SHOUT, 5000}}) + table.insert(endAnim, {func = AnimSay, args = {cyborg, loc("Yeah? Watcha gonna do? Cry?"), SAY_SHOUT, 5000}}) + table.insert(endAnim, {func = AnimSay, args = {leaks, loc("We won't let you hurt her!"), SAY_SHOUT, 4000}}) + AddSkipFunction(endAnim, SkipEndAnimDuo, {}) + + table.insert(endFailAnim, {func = AnimCaption, args = {leaks, loc("Leaks A Lot, depressed for killing his loved one, failed to save the village..."), 3000}}) + + table.insert(winAnim, {func = AnimCustomFunction, args = {princess, CondNeedToTurn, {leaks, princess}}}) + table.insert(winAnim, {func = AnimSay, args = {princess, loc("Thank you, oh, thank you, my heroes!"), SAY_SAY, 5000}}) + table.insert(winAnim, {func = AnimSay, args = {princess, loc("How can I ever repay you for saving my life?"), SAY_SAY, 6000}}) + table.insert(winAnim, {func = AnimSay, args = {leaks, loc("There's nothing more satisfying to us than seeing you share your beauty with the world every morning, my princess!"), SAY_SAY, 10000}}) + table.insert(winAnim, {func = AnimSay, args = {leaks, loc("Let's go home!"), SAY_SAY, 3000}}) + table.insert(winAnim, {func = AnimCaption, args = {leaks, loc("And so they discovered that cyborgs weren't invulnerable..."), 2000}}) + + startAnim = startAnimRL + pastFlowerAnim = pastFlowerAnimRL + outPitAnim = outPitAnimRL +end + +function KillPrincess() + ParseCommand("teamgone " .. loc("Cannibal Sentry")) + TurnTimeLeft = 0 +end +--/////////////////////////////Misc Functions//////////////////////// + +function HideHedge(hedge) + if hedgeHidden[hedge] ~= true then + HideHog(hedge) + hedgeHidden[hedge] = true + end +end + +function RestoreHedge(hedge) + if hedgeHidden[hedge] == true then + RestoreHog(hedge) + hedgeHidden[hedge] = false + end +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +function SetupPlaceAlone() + ------ AMMO CRATE LIST ------ + --SpawnAmmoCrate(3122, 994, amShotgun) + SpawnAmmoCrate(3124, 952, amBaseballBat) + SpawnAmmoCrate(2508, 1110, amFirePunch) + ------ UTILITY CRATE LIST ------ + blowCrate = SpawnUtilityCrate(3675, 1480, amBlowTorch) + gravityCrate = SpawnUtilityCrate(3448, 1349, amLowGravity) + SpawnUtilityCrate(3212, 1256, amGirder) + SpawnUtilityCrate(3113, 911, amParachute) + sniperCrate = SpawnAmmoCrate(784, 1715, amSniperRifle) + ------ MINE LIST ------ + SetTimer(AddGear(3328, 1399, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(3028, 1262, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2994, 1274, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2956, 1277, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2925, 1282, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2838, 1276, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2822, 1278, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2786, 1283, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2766, 1270, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2749, 1231, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2717, 1354, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2167, 1330, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2201, 1321, gtMine, 0, 0, 0, 0), 3000) + SetTimer(AddGear(2239, 1295, gtMine, 0, 0, 0, 0), 3000) + + AnimSetGearPosition(leaks, 3781, 1583) + --AnimSetGearPosition(leaks, 1650, 1583) + AddAmmo(cannibals[1], amShotgun, 100) + AddAmmo(leaks, amSwitch, 0) +end + +function SetupPlaceDuo() + PlaceCratesDuo() + AnimSetGearPosition(leaks, unpack(startLeaksPosDuo)) + AnimSetGearPosition(dense, unpack(startDensePosDuo)) +end + +function SetupEventsDuo() + AddEvent(CheckPastFlower, {}, DoPastFlower, {}, 0) + AddEvent(CheckLeaksDead, {}, DoLeaksDead, {}, 0) + AddEvent(CheckDenseDead, {}, DoDenseDead, {}, 0) + AddEvent(CheckTookSniper2, {}, DoTookSniper2, {}, 0) +end + +function SetupEventsAlone() + AddEvent(CheckLeaksDead, {}, DoLeaksDead, {}, 0) + AddEvent(CheckTookBlowTorch, {}, DoTookBlowTorch, {}, 0) + AddEvent(CheckTookLowGravity, {}, DoTookLowGravity, {}, 0) + AddEvent(CheckOnBridge, {}, DoOnBridge, {}, 0) +end + +function StartMission() + if m2DenseDead == 1 then + DeleteGear(dense) + if m2Choice == choiceAccepted then + SetupAnimAcceptedDied() + elseif m2Choice == choiceRefused then + SetupAnimRefusedDied() + else + SetupAnimAttacked() + end + SetupPlaceAlone() + SetupEventsAlone() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) + else + if m2Choice == choiceAccepted then + SetupAnimAcceptedLived() + else + SetupAnimRefusedLived() + end + SetupPlaceDuo() + SetupEventsDuo() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) + end + HideHedge(cyborg) + HideHedge(princess) + for i = 5, 8 do + HideHedge(cannibals[i]) + end + +end + +function SetupCourse() + + ------ GIRDER LIST ------ + PlaceGirder(1091, 1150, 6) + PlaceGirder(1091, 989, 6) + PlaceGirder(1091, 829, 6) + PlaceGirder(1091, 669, 6) + PlaceGirder(1091, 668, 6) + PlaceGirder(1091, 669, 6) + PlaceGirder(1088, 667, 6) + PlaceGirder(1091, 658, 6) + PlaceGirder(1091, 646, 6) + PlaceGirder(1091, 607, 6) + PlaceGirder(1091, 571, 6) + PlaceGirder(1376, 821, 6) + PlaceGirder(1145, 1192, 1) + PlaceGirder(1169, 1076, 3) + PlaceGirder(1351, 1082, 4) + PlaceGirder(1469, 987, 3) + PlaceGirder(1386, 951, 0) + PlaceGirder(1465, 852, 3) + PlaceGirder(1630, 913, 0) + PlaceGirder(1733, 856, 7) + PlaceGirder(1688, 713, 5) + PlaceGirder(1556, 696, 2) + PlaceGirder(1525, 696, 2) + PlaceGirder(1457, 697, 2) + PlaceGirder(1413, 700, 3) + PlaceGirder(1270, 783, 2) + PlaceGirder(1207, 825, 2) + PlaceGirder(1135, 775, 1) + + ------ UTILITY CRATE LIST ------ + SpawnUtilityCrate(1590, 628, amParachute) + SpawnAmmoCrate(1540, 100, amDynamite) + SpawnUtilityCrate(2175, 1815, amLowGravity) + SpawnUtilityCrate(2210, 1499, amFirePunch) + girderCrate = SpawnUtilityCrate(2300, 1663, amGirder) + SpawnUtilityCrate(610, 1394, amPickHammer) + + ------ BARREL LIST ------ + SetHealth(AddGear(1148, 736, gtExplosives, 0, 0, 0, 0), 20) + +end + +function PlaceCourseMines() + SetTimer(AddGear(1215, 1193, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1259, 1199, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1310, 1198, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1346, 1196, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1383, 1192, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1436, 1196, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1487, 1199, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1651, 1209, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1708, 1209, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1759, 1190, gtMine, 0, 0, 0, 0), 5000) + SetTimer(AddGear(1815, 1184, gtMine, 0, 0, 0, 0), 5000) +end + + +--////////////////////////////Event Functions//////////////////////// +function CheckTookFire() + return fireTaken +end + +function DoTookFire() + AddAmmo(leaks, amFirePunch, 100) +end + +function CheckTookGirder1() + return girder1Taken +end + +function CheckTookGirder2() + return girder2Taken +end + +function DoTookGirder1() + AddAmmo(dense, amGirder, 2) +end + +function DoTookGirder2() + AddAmmo(dense, amGirder, 3) +end + +function CheckDensePit() + return GetY(dense) < 1250 and StoppedGear(dense) +end + +function DoDensePit() + TurnTimeLeft = 0 + RestoreHedge(cyborg) + AnimWait(cyborg, 1) + AddFunction({func = AddAnim, args = {outPitAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterOutPitAnim, args = {}}}}) +end + +function CheckPastFlower() + if denseDead == true or leaksDead == true then + return false + end + return (GetX(dense) < startEventXDuo and StoppedGear(dense)) + or (GetX(leaks) < startEventXDuo and StoppedGear(leaks)) +end + +function DoPastFlower() + TurnTimeLeft = 0 + RestoreHedge(cyborg) + AnimWait(cyborg, 1) + AddFunction({func = AddAnim, args = {pastFlowerAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterPastFlowerAnim, args = {}}}}) +end + + +function CheckLeaksDead() + return leaksDead +end + +function DoLeaksDead() + AddCaption(loc("The village, unprepared, was destroyed by the cyborgs...")) + ParseCommand("teamgone " .. loc("Natives")) +end + +function CheckDenseDead() + return denseDead +end + +function DoDenseDead() + AddCaption(loc("The village, unprepared, was destroyed by the cyborgs...")) + ParseCommand("teamgone " .. loc("Natives")) +end + +function CheckTookBlowTorch() + return blowTaken +end + +function DoTookBlowTorch() + ShowMission(loc("The Journey Back"), loc("The Tunnel Maker"), loc("Hint: Select the BlowTorch, aim and press [Fire]. Press [Fire] again to stop.|Don't blow up the crate."), 0, 6000) +end + +function CheckTookLowGravity() + return gravityTaken +end + +function DoTookLowGravity() + ShowMission(loc("The Journey Back"), loc("The Moonwalk"), loc("Hint: Select the LowGravity and press [Fire]."), 0, 6000) +end + +function CheckOnBridge() + return leaksDead == false and GetX(leaks) < 1651 and StoppedGear(leaks) +end + +function DoOnBridge() + TurnTimeLeft = 0 + RestoreHedge(cyborg) + RestoreHedge(princess) + AnimWait(cyborg, 1) + AddFunction({func = AddAnim, args = {midAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterMidAnimAlone, args = {}}}}) +end + +function CheckGirderTaken() + return girderTaken +end + +function DoGirderTaken() + AddAmmo(leaks, amGirder, 2) +-- AddAmmo(leaks, amGirder, 3) +end + +function CheckOnFirstGirder() + return leaksDead == false and GetX(leaks) < 1160 and StoppedGear(leaks) +end + +function DoOnFirstGirder() + PlaceCourseMines() + ShowMission(loc("The Journey Back"), loc("Slippery"), loc("You'd better watch your steps..."), 0, 4000) +end + +function CheckTookSniper() + return sniperTaken and StoppedGear(leaks) +end + +function DoTookSniper() + TurnTimeLeft = 0 + RestoreHedge(cyborg) + RestoreHedge(princess) + AnimWait(cyborg, 1) + AddFunction({func = AddAnim, args = {endAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterEndAnimAlone, args = {}}}}) +end + +function CheckTookSniper2() + return sniperTaken and StoppedGear(leaks) and StoppedGear(dense) +end + +function DoTookSniper2() + TurnTimeLeft = 0 + RestoreHedge(cyborg) + RestoreHedge(princess) + AnimWait(cyborg, 1) + AddFunction({func = AddAnim, args = {endAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterEndAnimDuo, args = {}}}}) +end + +function CheckLost() + return princessDead +end + +function DoLost() + AddAnim(endFailAnim) + AddFunction({func = ParseCommand, args = {'teamgone ' .. loc('Natives')}}) +end + +function CheckWon() + return cyborgDead and not princessDead +end + +function DoWon() + SaveCampaignVar("Progress", "3") + AddAnim(winAnim) + AddFunction({func = FinishWon, args = {}}) +end + +function FinishWon() + SwitchHog(leaks) + ParseCommand("teamgone " .. loc("Cannibal Sentry")) + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function CheckFailedCourse() + return TurnsLeft == 0 +end + +function DoFailedCourse() + TurnTimeLeft = 0 + RestoreHedge(cyborg) + RestoreHedge(princess) + AnimWait(cyborg, 1) + AddFunction({func = AddAnim, args = {failAnim}}) + AddFunction({func = AddFunction, args = {{func = AfterMidFailAnim, args = {}}}}) +end + +--////////////////////////////Main Functions///////////////////////// + +function onGameInit() + Seed = 0 + GameFlags = gfSolidLand + gfDisableWind + TurnTime = 40000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 5 + MapGen = 0 + TemplateFilter = 6 + TemplateNumber = 27 + Theme = "Nature" + SuddenDeathTurns = 3000 + + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + leaks = AddHog(loc("Leaks A Lot"), 0, 100, "Rambo") + dense = AddHog(loc("Dense Cloud"), 0, 100, "RobinHood") + + AddTeam(loc("Cannibal Sentry"), 14483456, "Skull", "Island", "Pirate","cm_vampire") + cannibals = {} + for i = 1, 4 do + cannibals[i] = AddHog(cannibalNames[i], 3, 40, "Zombi") + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + end + + for i = 5, 8 do + cannibals[i] = AddHog(cannibalNames[i], 3, 40, "Zombi") + AnimSetGearPosition(cannibals[i], 0, 0) + end + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Y3K1337"), 0, 200, "cyborg1") + princess = AddHog(loc("Fell From Heaven"), 0, 200, "tiara") + + AnimSetGearPosition(dense, 0, 0) + AnimSetGearPosition(leaks, 0, 0) + AnimSetGearPosition(cyborg, 0, 0) + AnimSetGearPosition(princess, 0, 0) + + AnimInit() +end + +function onGameStart() + m2Choice = tonumber(GetCampaignVar("M2Choice")) + m2DenseDead = tonumber(GetCampaignVar("M2DenseDead")) + m2RamonDead = tonumber(GetCampaignVar("M2RamonDead")) + m2SpikyDead = tonumber(GetCampaignVar("M2SpikyDead")) + StartMission() +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + if gear == blowCrate then + blowTaken = true + elseif gear == fireCrate then + fireTaken = true + elseif gear == gravityCrate then + gravityTaken = true + elseif gear == leaks then + leaksDead = true + elseif gear == dense then + denseDead = true + elseif gear == cyborg then + cyborgDead = true + elseif gear == princess then + princessDead = true + elseif gear == girderCrate then + girderTaken = true + elseif gear == girderCrate1 then + girder1Taken = true + elseif gear == girderCrate2 then + girder2Taken = true + elseif gear == sniperCrate then + sniperTaken = true + else + for i = 1, 4 do + if gear == cannibals[i] then + cannibalDead[i] = true + end + end + end +end + +function onAmmoStoreInit() + SetAmmo(amBlowTorch, 0, 0, 0, 1) + SetAmmo(amParachute, 0, 0, 0, 1) + SetAmmo(amGirder, 0, 0, 0, 3) + SetAmmo(amLowGravity, 0, 0, 0, 1) + SetAmmo(amBaseballBat, 0, 0, 0, 1) + SetAmmo(amFirePunch, 1, 0, 0, 1) + SetAmmo(amSkip, 9, 0, 0, 0) + SetAmmo(amSwitch, 9, 0, 0, 0) + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amRope, 0, 0, 0, 1) + SetAmmo(amSniperRifle, 0, 0, 0, 1) + SetAmmo(amDynamite, 0, 0, 0, 1) + SetAmmo(amPickHammer, 0, 0, 0, 1) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + elseif stage == endStage and CurrentHedgehog ~= leaks then + AnimSwitchHog(leaks) + SetGearMessage(leaks, 0) + TurnTimeLeft = -1 + elseif GetHogTeamName(CurrentHedgehog) ~= loc("Natives") then + for i = 1, 4 do + if cannibalDead[i] ~= true then + if GetX(cannibals[i]) < GetX(leaks) then + HogTurnLeft(cannibals[i], false) + else + HogTurnLeft(cannibals[i], true) + end + end + end + SetInputMask(band(0xFFFFFFFF, bnot(gmLeft + gmRight + gmLJump + gmHJump))) + TurnTimeLeft = 20000 + else + SetInputMask(0xFFFFFFFF) + TurnsLeft = TurnsLeft - 1 + end +end + +function onPrecise() + if GameTime > 2500 and AnimInProgress() then + SetAnimSkip(true) + return + end +-- AddAmmo(leaks, amRope, 100) +-- RemoveEventFunc(CheckPastFlower) +-- DeleteGear(sniperCrate) +end + diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/queen.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,825 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + + +-----------------------------Map-------------------------------------- +local map = +{ + "\16\7\0\225\132\15\200\1\40\0\15\200\1\40\132\15\105\8\81\0\16\14\1\64\143\15\200\7\249\0\13\50\7\252\132\12\243\7\172\0", + "\12\236\7\168\132\12\127\6\192\0\12\127\6\192\132\11\52\6\223\0\11\52\6\223\132\10\62\8\35\0\8\201\8\4\132\8\63\7\126\0", + "\8\63\7\126\132\8\4\6\58\0\8\0\6\65\132\7\147\6\241\0\7\133\6\195\132\7\20\4\151\0\7\143\6\195\132\7\140\6\234\0", + "\7\17\4\151\132\5\191\4\222\0\5\191\4\222\132\3\136\3\252\0\3\136\3\252\132\2\12\4\151\0\2\12\4\151\132\1\138\5\15\0", + "\1\138\5\15\132\1\54\5\156\0\1\54\5\156\132\0\130\5\64\0\0\130\5\64\132\255\214\5\135\0\8\141\1\85\179\8\141\1\85\0", + "\10\30\2\220\139\10\30\2\220\0\11\77\1\142\131\11\77\1\142\0\10\188\0\113\129\10\188\0\113\0\255\235\0\162\132\0\130\0\225\0", + "\0\130\0\229\0\0\127\0\236\132\255\231\0\250\0\0\28\0\215\136\0\4\0\211\0\0\95\5\212\154\0\95\7\238\0\0\246\6\2\154", + "\1\71\8\0\0\1\205\5\145\154\2\132\4\239\0\3\98\4\141\154\1\135\5\216\0\3\179\4\151\154\6\213\5\247\0\6\223\5\124\151", + "\6\185\5\22\0\6\181\5\29\151\6\37\5\64\0\0\179\5\198\148\0\179\5\198\0\6\216\4\253\148\6\216\4\253\0\1\230\7\147\153", + "\8\32\8\18\0\1\187\6\174\153\7\179\7\108\0\2\199\5\177\179\6\128\6\167\0\7\231\7\10\143\7\231\6\202\0\12\148\8\4\156", + "\10\241\8\11\0\11\112\7\101\156\12\56\7\91\0\1\89\5\223\199\4\11\5\208\0\4\67\5\212\200\4\172\6\58\0\4\172\6\58\200", + "\5\36\5\212\0\5\40\5\194\200\4\169\5\57\0\4\169\5\57\200\4\42\5\205\0\4\130\5\142\200\4\218\5\205\0\4\137\5\194\200", + "\4\179\5\251\0\255\245\1\198\133\0\77\1\198\0\0\77\1\198\133\0\102\1\226\0\0\102\1\230\133\255\221\1\244\0\255\245\0\148\195", + "\255\231\1\11\0\0\32\0\162\195\255\231\0\169\0\0\60\0\158\195\0\32\0\172\0\0\21\0\176\195\255\242\0\222\0\255\245\0\215\195", + "\0\7\0\246\0\255\245\0\243\195\0\11\1\33\0\0\4\1\4\195\0\56\1\36\0\255\245\1\173\195\0\35\1\110\0\255\242\1\180\195", + "\255\224\2\9\0\255\238\1\240\195\0\28\2\30\0\0\21\2\19\195\0\102\2\23\0\16\18\1\1\195\16\35\0\222\0\16\14\1\11\195", + "\16\7\2\9\0\16\0\2\16\195\16\35\3\34\0\16\11\2\252\195\16\11\4\208\0\16\11\4\208\195\16\0\6\55\0\16\0\6\55\195", + "\16\14\8\25\0", +} + +--------------------------------------------Constants------------------------------------ +choiceAccepted = 1 +choiceRefused = 2 +choiceAttacked = 3 + +choiceEliminate = 1 +choiceSpare = 2 + +leaksNum = 1 +denseNum = 2 +waterNum = 3 +buffaloNum = 4 +chiefNum = 5 +girlNum = 6 +wiseNum = 7 + +denseScene = 1 +princessScene = 2 +waterScene = 3 +cyborgScene = 4 + +nativeNames = {loc("Leaks A Lot"), loc("Dense Cloud"), loc("Fiery Water"), + loc("Raging Buffalo"), loc("Righteous Beard"), loc("Fell From Grace"), + loc("Wise Oak"), loc("Ramon"), loc("Spiky Cheese") + } +nativeSaveNames = {"M8DeployedDead", "M8RamonDead", "M8SpikyDead", "M8PrincessDead"} + +nativeUnNames = {loc("Zork"), loc("Steve"), loc("Jack"), + loc("Lee"), loc("Elmo"), loc("Rachel"), + loc("Muriel")} + +nativeHats = {"Rambo", "RobinHood", "pirate_jack", "zoo_Bunny", "IndianChief", + "tiara", "AkuAku", "rasta", "hair_yellow"} + +nativePos = {{1474, 1188}, {923, 986}, {564, 1120}, {128, 1315}} +nativesNum = 4 +nativesLeft = 4 + +cyborgNames = {loc("Artur Detour"), loc("Led Heart"), loc("Orlando Boom!"), loc("Nilarian"), + loc("Steel Eye"), loc("Rusty Joe"), loc("Hatless Jerry"), loc("Gas Gargler")} + +cyborgsDif = {2, 2, 2, 2, 2, 2, 2, 2} +cyborgsHealth = {100, 100, 100, 100, 100, 100, 100, 100} +cyborgPos = {1765, 1145} +cyborgsTeamNum = {4, 3} +cyborgsNum = 7 +cyborgsPos = {{2893, 1717}, {2958, 1701}, {3027, 1696}, {3096, 1698}, + {2584, 655}, {2047, 1534}, {115, 179}, {2162, 1916}} +cyborgsDir = {"Left", "Left", "Left", "Left", "Left", "Left", "Right", "Left"} + +crateConsts = {} +reactions = {} + +enemyPos = {4078, 195} + +-----------------------------Variables--------------------------------- +natives = {} +origNatives = {} + +cyborgs = {} +cyborg = nil + +gearDead = {} +hedgeHidden = {} + +scene = 0 +enemyFled = "0" + +deployedLeader = "0" +princessLeader = "0" + +startAnim = {} +fleeAnim = {} +finalAnim = {} +leaderDeadAnim = {} +-----------------------------Animations-------------------------------- +function EmitDenseClouds(dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + if dir == nil then + dx, dy = GetGearVelocity(dense) + if dx < 0 then + dif = 10 + else + dif = -10 + end + end + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) +end + +function AnimationSetup() + table.insert(startAnim, {func = AnimWait, args = {enemy, 3000}}) + table.insert(startAnim, {func = AnimCaption, swh = false, args = {natives[1], "The team continued their quest of finding the rest of the tribe.", 4000}}) + table.insert(startAnim, {func = AnimCaption, swh = false, args = {natives[1], "They stumbled upon a pile of weapons, they seemed to be getting closer.", 4500}}) + if scene == denseScene then + if m5DeployedNum == denseNum then + deployedLeader = "1" + SetupDenseAnimDeployed() + else + SetupDenseAnim() + end + elseif scene == waterScene then + if m5DeployedNum == waterNum then + deployedLeader = "1" + SetupWaterAnimDeployed() + else + SetupWaterAnim() + end + elseif scene == princessScene then + princessLeader = "1" + SetupPrincessAnim() + else + SetupCyborgAnim() + end + + AddSkipFunction(startAnim, SkipAnim, {startAnim}) + AddSkipFunction(fleeAnim, SkipAnim, {fleeAnim}) + AddSkipFunction(leaderDeadAnim, SkipAnim, {leaderDeadAnim}) +end + +function SetupLeaderDeadAnim() + local gear = nil + if CheckCyborgsDead() then + return + end + for i = nativesLeft, 1, -1 do + if band(GetState(natives[i]), gstDrowning) == 0 then + gear = natives[i] + end + end + if gear == nil then + return + end + table.insert(leaderDeadAnim, {func = AnimFollowGear, args = {gear}}) + table.insert(leaderDeadAnim, {func = AnimSay, args = {gear, "That traitor won't be killing us anymore!", SAY_THINK, 6000}}) +end + +function SetupDenseAnim() + table.insert(startAnim, {func = AnimSay, args = {enemy, "Yo, dude! Get away from our weapons!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Dense Cloud?! What are you doing?!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "What does it look like?", SAY_SHOUT, 3500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Are you helping the aliens?!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Lolz, I love the look on your face!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Did you really think that I'd changed?", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "But why did you betray us?!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Yo, the aliens gave me plants...medicinal plants...lots of it.", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You never give me plants!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Besides, why would I choose certain death?", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Do you have any idea how bad an exploding arrow hurts?", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Dude, it's unbearable!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You're a coward!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You endangered your whole tribe, you bastard!", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Yeah, well, for some dude to be happy, some other dude has to suffer.", SAY_SHOUT, 11000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "That's just the way it works, you know.", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You're some piece of hypocrite junkie!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Why do you always have to call me names?", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, EmitDenseClouds, {}}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Make fun of me when I fart...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "IT'S A SERIOUS MEDICAL CONDITION!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You don't deserve my sacrifice!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "I won't let you kill the tribe!", SAY_SHOUT, 5000}}) + + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Dude, this is boring!", SAY_SAY, 3000}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "I ain't gonna sit around no more!", SAY_SAY, 5000}}) + table.insert(fleeAnim, {func = AnimTurn, args = {enemy, "Right"}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Yo, escort my buttocks!", SAY_SHOUT, 3500}}) + table.insert(fleeAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(fleeAnim, {func = AnimWait, args = {natives[1], 1}}) + table.insert(fleeAnim, {func = AnimDisappear, swh = false, args = {enemy, 0, 0}}) +end + +function SetupDenseAnimDeployed() + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, EmitDenseClouds, {}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[3], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[2], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[1], enemy}}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I'm afraid I can't let you proceed!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "???", SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimSay, args = {natives[2], "???", SAY_THINK, 0}}) + table.insert(startAnim, {func = AnimSay, args = {natives[3], "???", SAY_THINK, 1000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Dude, wow, you're so cute!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Did you really think I'd change?", SAY_SHOUT, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I'm still with the aliens.", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimTeleportGear, args = {enemy, unpack(enemyPos)}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[1], enemy}}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "WHAT?!", SAY_THINK, 1000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[3], "But you saved me!", SAY_THINK, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Haha, that was just a coincidence!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I was heading home, you see!", SAY_SHOUT, 3500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We were your home! Your family...", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "How could you betray us?!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Yo, the aliens gave me plants...medicinal plants...lots of it.", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You never give me plants!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Besides, why would I choose certain death?", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Do you have any idea how bad an exploding arrow hurts?", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Dude, it's unbearable!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You're a coward!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You endangered your whole tribe, you bastard!", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Yeah, well, for some dude to be happy, some other dude has to suffer.", SAY_SHOUT, 11000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "That's just the way it works, you know.", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You're some piece of hypocrite junkie!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Why do you always have to call me names?", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, EmitDenseClouds, {}}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Make fun of me when I fart...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "IT'S A SERIOUS MEDICAL CONDITION!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You don't deserve my sacrifice!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "I won't let you kill the tribe!", SAY_SHOUT, 5000}}) + + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Dude, this is boring!", SAY_SAY, 3000}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "I ain't gonna sit around no more!", SAY_SAY, 5000}}) + table.insert(fleeAnim, {func = AnimTurn, args = {enemy, "Right"}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Yo, escort my buttocks!", SAY_SHOUT, 3500}}) + table.insert(fleeAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(fleeAnim, {func = AnimWait, args = {natives[1], 1}}) + table.insert(fleeAnim, {func = AnimDisappear, swh = false, args = {enemy, 0, 0}}) +end + +function SetupWaterAnim() + table.insert(startAnim, {func = AnimSay, args = {enemy, "Stay there, comrades!", SAY_SHOUT, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Come closer and die...burp!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Fiery Water?! Are you drunk again?", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Drunk with power, perhappss!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "The power of love! No, wait, the power of the aliens!", SAY_SHOUT, 7500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We trusted you, you fool!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Why do you keep betraying us?", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Why, why, why, why!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I grew sick of the oppression! I brock free!", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "What oppression?! You were the most unoppressed member of the tribe!", SAY_SHOUT, 10000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "The opression of the elders, of course!", SAY_SHOUT, 6500}}) + if m5DeployedNum == leaksNum then + table.insert(startAnim, {func = AnimSay, args = {enemy, "You should know this more than anyone, Leaks!", SAY_SHOUT, 7000}}) + elseif m5LeaksDead == 1 then + table.insert(startAnim, {func = AnimSay, args = {enemy, "Just look at Leaks, may he rest in peace!", SAY_SHOUT, 6500}}) + end + table.insert(startAnim, {func = AnimSay, args = {enemy, "We, the youth, have to constantly prove our value...", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "We work and work until we sweat blood...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "We risk our lives going through challenges...", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "All this to please our beloved 'elders'...hick...", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "And what do they do in the meantime? NOTHING!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "All they do is sit around and judge us!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You have never worked a bit in your life!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "All *you* do is take long walks when everyone else works.", SAY_SHOUT, 9000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Anyway, the aliens accept me for who I am.", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We won't accept you destroying our village!", SAY_SHOUT, 7000}}) + + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Argh, the borrdommm!", SAY_SAY, 3000}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "I have more important things to do!", SAY_SAY, 5000}}) + table.insert(fleeAnim, {func = AnimTurn, args = {enemy, "Right"}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Comrades! Sail me away!", SAY_SHOUT, 3500}}) + table.insert(fleeAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(fleeAnim, {func = AnimWait, args = {natives[1], 1}}) + table.insert(fleeAnim, {func = AnimDisappear, swh = false, args = {enemy, 0, 0}}) +end + +function SetupWaterAnimDeployed() + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[3], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[2], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[1], enemy}}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Stop, comrades!", SAY_SHOUT, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I cannot let you go any farther...burp!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Fiery Water?! Are you drunk again?", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Drunk with power, perhappss!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "The power of love! No, wait, the power of the aliens!", SAY_SHOUT, 7500}}) + table.insert(startAnim, {func = AnimTeleportGear, args = {enemy, unpack(enemyPos)}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[3], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[2], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[1], enemy}}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We trusted you, you fool!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Why do you keep betraying us?", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Why, why, why, why!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I grew sick of the oppression! I brock free!", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "What oppression?! You were the most unoppressed member of the tribe!", SAY_SHOUT, 10000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "The opression of the elders, of course!", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Just look at Leaks, may he rest in peace!", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "We, the youth, have to constantly prove our value...", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "We work and work until we sweat blood...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "We risk our lives going through challenges...", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "All this to please our beloved 'elders'...hick...", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "And what do they do in the meantime? NOTHING!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "All they do is sit around and judge us!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "You have never worked a bit in your life!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "All *you* do is take long walks when everyone else works.", SAY_SHOUT, 9000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Anyway, the aliens accept me for who I am.", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We won't accept you destroying our village!", SAY_SHOUT, 7000}}) + + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Argh, the borrdommm!", SAY_SAY, 3000}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "I have more important things to do!", SAY_SAY, 5000}}) + table.insert(fleeAnim, {func = AnimTurn, args = {enemy, "Right"}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Comrades! Sail me away!", SAY_SHOUT, 3500}}) + table.insert(fleeAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(fleeAnim, {func = AnimWait, args = {natives[1], 1}}) + table.insert(fleeAnim, {func = AnimDisappear, swh = false, args = {enemy, 0, 0}}) +end + +function SetupPrincessAnim() + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[3], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[2], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[1], enemy}}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Oh, my! I forgot something!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "We need to go back!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "What could you possibly forget in that cage?", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I don't like your tone! You're hurting me!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "I'm terribly sorry!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "What is it that you forgot?", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Uhmm, it's...uhm...my ring!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "It's precious to me!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We don't have time for that now!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We have to find our folk!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "But I want my sandals!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Sandals?! I thought you left your ring!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "All right, you got me...", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Got you? You're acting weird...", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You just can't let it go, can you!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "All right, I'll admit it!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Admit what?", SAY_SHOUT, 2000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You give me no choice!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I can't let you go further because...", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I'm the spy! I've been giving you out!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimTeleportGear, args = {enemy, unpack(enemyPos)}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[3], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[2], enemy}}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {enemy, CondNeedToTurn, {natives[1], enemy}}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "But...they kidnapped you!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Oh, that. We were just having fun!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "It's an ancient ritual of theirs.", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Why did you do this?", SAY_SHOUT, 4000}}) + if m5ChiefDead == 1 then + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Why did you kill your father?", SAY_SHOUT, 5000}}) + end + table.insert(startAnim, {func = AnimSay, args = {enemy, "Do you have any idea what it's like in the village for a woman?", SAY_SHOUT, 10000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "How would you like being discriminated against?", SAY_SHOUT, 7000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Not being able to fight, hunt...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Gathering fruits all day long...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Doing stuff a monkey could do...", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Always being considered weak and fragile...", SAY_SHOUT, 6000}}) + if m5DeployedNum == girlNum then + table.insert(startAnim, {func = AnimSay, args = {natives[1], "In case you haven't noticed, I'm a woman, too!", SAY_SHOUT, 8000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Yes, but you're...different!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Of course I am...", SAY_SHOUT, 3000}}) + end + table.insert(startAnim, {func = AnimSay, args = {enemy, "The aliens respect me, even worship me!", SAY_SHOUT, 6000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I'm living a dream!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Well, you're about to wake up!", SAY_SHOUT, 5000}}) + + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Hmm...it's going slower than expected.", SAY_SAY, 5000}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "I am going to leave the kids play by themselves.", SAY_SAY, 6000}}) + table.insert(fleeAnim, {func = AnimTurn, args = {enemy, "Right"}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Alien! I wish to be moved!", SAY_SHOUT, 4000}}) + table.insert(fleeAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(fleeAnim, {func = AnimWait, args = {natives[1], 1}}) + table.insert(fleeAnim, {func = AnimDisappear, swh = false, args = {enemy, 0, 0}}) +end + +function SetupCyborgAnim() + table.insert(startAnim, {func = AnimSay, args = {enemy, "Stop right there, puny worms!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Stay away from our weapons!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We come in peace! Just let our friends go!", SAY_SHOUT, 5500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I'm afraid we cannot afford that...", SAY_SHOUT, 4500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You see, hedgehog spikes are very very valuable.", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Very valuable, haha!", SAY_SHOUT, 3500}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Don't you dare harm our tribe!", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "It's a shame, really!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "I regret to end your little odyssey.", SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "It was fun to watch...", SAY_SHOUT, 3500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "The way you handled your little internal conflicts...", SAY_SHOUT, 6500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "Did you really think that we needed the help of one of you?", SAY_SHOUT, 7500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "You should have known that we don't rely on meatbags!", SAY_SHOUT, 7500}}) + table.insert(startAnim, {func = AnimSay, args = {enemy, "It was fun to watch though...", SAY_SHOUT, 3500}}) + if m5Choice == choiceEliminate then + table.insert(startAnim, {func = AnimSay, args = {enemy, "Heck, you even executed one of your own!", SAY_SHOUT, 6000}}) + end + table.insert(startAnim, {func = AnimSay, args = {natives[1], "It was all a trick?!", SAY_SHOUT, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "Some sick game of yours?!", SAY_SHOUT, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {natives[1], "We won't let you hurt any more of us!", SAY_SHOUT, 6000}}) + + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Entered boredom phase! Discrepancies detected...", SAY_SAY, 5000}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Initiate escape wish!", SAY_SAY, 6000}}) + table.insert(fleeAnim, {func = AnimTurn, args = {enemy, "Right"}}) + table.insert(fleeAnim, {func = AnimSay, args = {enemy, "Running displacement algorithm...", SAY_SHOUT, 4000}}) + table.insert(fleeAnim, {func = AnimSwitchHog, args = {natives[1]}}) + table.insert(fleeAnim, {func = AnimWait, args = {natives[1], 1}}) + table.insert(fleeAnim, {func = AnimDisappear, swh = false, args = {enemy, 0, 0}}) +end + +function SetupFinalAnim() + local found = 0 + local gears = {} + for i = nativesLeft, 1, -1 do + if band(GetState(natives[i]), gstDrowning) == 0 then + found = found + 1 + gears[found] = natives[i] + end + end + if found == 0 then + return + else + for i = 1, found do + table.insert(finalAnim, {func = AnimCustomFunction, args = {gears[1], CondNeedToTurn, {cyborg, gears[i]}}}) + end + table.insert(finalAnim, {func = AnimSay, args = {cyborg, "Nice work, meatbags!", SAY_SAY, 3000}}) + table.insert(finalAnim, {func = AnimSay, args = {cyborg, "You're on your way to freeing your tribe!", SAY_SAY, 5500}}) + table.insert(finalAnim, {func = AnimSay, args = {gears[1], "Do you know where they are?", SAY_SAY, 4000}}) + table.insert(finalAnim, {func = AnimSay, args = {gears[found], "We need to hurry!", SAY_SAY, 3000}}) + table.insert(finalAnim, {func = AnimSay, args = {cyborg, "Haha! Come!", SAY_SAY, 2000}}) + table.insert(finalAnim, {func = AnimJump, args = {cyborg, "high"}}) + table.insert(finalAnim, {func = AnimDisappear, args = {cyborg, GetGearPosition(cyborg)}}) + for i = 1, found do + table.insert(finalAnim, {func = HideHedge, swh = false, args = {gears[i]}}) + end + table.insert(finalAnim, {func = SetState, swh = false, args = {cyborg, gstInvisible}}) + end +end + + +--------------------------Anim skip functions-------------------------- +function AfterStartAnim() + SetGearMessage(natives[1], 0) + ShowMission("Long Live The Queen", "Closing in", "Defeat the enemy!|The leader seems scared, he will probably flee.", 1, 0) + SetHealth(SpawnHealthCrate(2207, 44), 25) + SetHealth(SpawnHealthCrate(519, 1519), 25) + SetHealth(SpawnHealthCrate(826, 895), 25) + SpawnUtilityCrate(701, 1046, amGirder, 3) + TurnTimeLeft = TurnTime +end + +function SkipAnim(anim) + if anim == startAnim then + SetGearPosition(enemy, unpack(enemyPos)) + end + if GetHogTeamName(CurrentHedgehog) ~= loc("Natives") then + TurnTimeLeft = 0 + end + AnimWait(enemy, 1) +end + +function AfterFleeAnim() + SetHealth(SpawnHealthCrate(130, 455), 25) + SetHealth(SpawnHealthCrate(2087, 50), 25) + SetHealth(SpawnHealthCrate(2143, 54), 25) + SetHealth(SpawnHealthCrate(70, 1308), 25) + SetGearMessage(CurrentHedgehog, 0) + HideHedge(enemy) + ShowMission("Long Live The Queen", "Coward", "The leader escaped. Defeat the rest of the aliens!", 1, 0) + TurnTimeLeft = TurnTime +end + +function AfterLeaderDeadAnim() + SetHealth(SpawnHealthCrate(130, 455), 25) + SetHealth(SpawnHealthCrate(2087, 50), 25) + SetHealth(SpawnHealthCrate(2143, 54), 25) + SetHealth(SpawnHealthCrate(70, 1308), 25) + ShowMission("Long Live The Queen", "Bullseye", "Good Job! Defeat the rest of the aliens!", 1, 0) + TurnTimeLeft = 0 +end +-----------------------------Events------------------------------------ +function CheckTurnsOver() + return TotalRounds > 6 +end + +function DoTurnsOver() + SetGearMessage(CurrentHedgehog, 0) + enemyFled = "1" + AddAnim(fleeAnim) + AddFunction({func = AfterFleeAnim, args = {}}) + RemoveEventFunc(CheckGearDead, {enemy}) +end + +function CheckNativesDead() + return nativesLeft == 0 +end + +function DoNativesDead() + RemoveEventFunc(CheckTurnsOver) + RemoveEventFunc(CheckGearDead) + RemoveEventFunc(CheckCyborgsDead) + AddCaption("...and the cyborgs took over the island.") + TurnTimeLeft = 0 +end + +function CheckCyborgsDead() + return (cyborgsLeft == 0 and (gearDead[enemy] == true or enemyFled == "1")) +end + +function KillEnemy() + if enemyFled == "1" then + ParseCommand("teamgone " .. loc("Leaderbot")) + end + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end + +function DoCyborgsDead() + SaveCampaignVariables() + RestoreHedge(cyborg) + PlaceGirder(3292, 922, 4) + SetGearPosition(cyborg, 3290, 902) + SetupFinalAnim() + AddAnim(finalAnim) + AddFunction({func = KillEnemy, args = {}}) +end + +function DoLeaderDead() + leaderDead = true + SetGearMessage(CurrentHedgehog, 0) + SetupLeaderDeadAnim() + AddAnim(leaderDeadAnim) + AddFunction({func = AfterLeaderDeadAnim, args = {}}) + RemoveEventFunc(CheckTurnsOver) +end + +function CheckGearsDead(gearList) + for i = 1, # gearList do + if gearDead[gearList[i]] ~= true then + return false + end + end + return true +end + +function CheckGearDead(gear) + return gearDead[gear] +end + +-----------------------------Misc-------------------------------------- +function HideHedge(hedge) + if hedgeHidden[hedge] ~= true then + HideHog(hedge) + hedgeHidden[hedge] = true + end +end + +function RestoreHedge(hedge) + if hedgeHidden[hedge] == true then + RestoreHog(hedge) + hedgeHidden[hedge] = false + end +end + +function GetVariables() + m5DeployedNum = tonumber(GetCampaignVar("M5DeployedNum")) + m2Choice = tonumber(GetCampaignVar("M2Choice")) + m5Choice = tonumber(GetCampaignVar("M5Choice")) + m2DenseDead = tonumber(GetCampaignVar("M2DenseDead")) + m4DenseDead = tonumber(GetCampaignVar("M4DenseDead")) + m5DenseDead = tonumber(GetCampaignVar("M5DenseDead")) + m4LeaksDead = tonumber(GetCampaignVar("M4LeaksDead")) + m5LeaksDead = tonumber(GetCampaignVar("M5LeaksDead")) + m4ChiefDead = tonumber(GetCampaignVar("M4ChiefDead")) + m5ChiefDead = tonumber(GetCampaignVar("M5ChiefDead")) + m4WaterDead = tonumber(GetCampaignVar("M4WaterDead")) + m5WaterDead = tonumber(GetCampaignVar("M5WaterDead")) + m4BuffaloDead = tonumber(GetCampaignVar("M4BuffaloDead")) + m5BuffaloDead = tonumber(GetCampaignVar("M5BuffaloDead")) + m5WiseDead = tonumber(GetCampaignVar("M5WiseDead")) + m5GirlDead = tonumber(GetCampaignVar("M5GirlDead")) +end + +function SaveCampaignVariables() + for i = 1, 4 do + if gearDead[origNatives[i]] ~= true then + SaveCampaignVar(nativeSaveNames[i], "0") + else + SaveCampaignVar(nativeSaveNames[i], "1") + end + end + + SaveCampaignVar("M8DeployedLeader", deployedLeader) + SaveCampaignVar("M8PrincessLeader", princessLeader) + SaveCampaignVar("M8EnemyFled", enemyFled) + SaveCampaignVar("M8Scene", "" .. scene) + SaveCampaignVar("Progress", "8") +end + +function SetupPlace() + HideHedge(cyborg) + SetHogHat(natives[1], nativeHats[m5DeployedNum]) + SetHogName(natives[1], nativeNames[m5DeployedNum]) + + if m5DeployedNum == denseNum then + dense = natives[1] + else + dense = enemy + end + + if m2Choice == choiceAccepted and m5Choice ~= choiceEliminate then + scene = denseScene + SetHogHat(enemy, nativeHats[denseNum]) + SetHogName(enemy, nativeNames[denseNum]) + dense = enemy + elseif m2Choice == choiceAccepted then + scene = cyborgScene + SetHogHat(enemy, "cyborg2") + SetHogName(enemy, loc("Nancy Screw")) + elseif m5Choice == choiceEliminate then + scene = princessScene + SetHogHat(enemy, "tiara") + SetHogName(enemy, loc("Fell From Heaven")) + else + scene = waterScene + SetHogHat(enemy, nativeHats[waterNum]) + SetHogName(enemy, nativeNames[waterNum]) + end + for i = 1, 4 do + if GetHogName(natives[i]) == GetHogName(enemy) then + AnimSetGearPosition(enemy, GetGearPosition(natives[i])) + DeleteGear(natives[i]) + DeleteGear(cyborgs[cyborgsLeft]) + end + end + + SpawnAmmoCrate(34, 395, amBee, 2) + SpawnAmmoCrate(33, 374, amRCPlane, 1) + SpawnAmmoCrate(74, 393, amAirAttack, 3) + SpawnAmmoCrate(1313, 1481, amBazooka, 8) + SpawnAmmoCrate(80, 360, amSniperRifle, 4) + SpawnAmmoCrate(1037, 1494, amShotgun, 7) + SpawnAmmoCrate(1037, 1472, amMolotov, 3) + SpawnAmmoCrate(1146, 1503, amMortar, 8) + + SpawnUtilityCrate(1147, 1431, amPortalGun, 2) + SpawnUtilityCrate(1219, 1542, amRope, 5) + SpawnUtilityCrate(1259, 1501, amJetpack, 2) +end + +function SetupEvents() + AddNewEvent(CheckNativesDead, {}, DoNativesDead, {}, 0) + AddNewEvent(CheckGearDead, {enemy}, DoLeaderDead, {}, 0) + AddNewEvent(CheckTurnsOver, {}, DoTurnsOver, {}, 0) + AddNewEvent(CheckCyborgsDead, {}, DoCyborgsDead, {}, 0) +end + +function SetupAmmo() + AddAmmo(natives[1], amPickHammer, 2) + AddAmmo(natives[1], amBazooka, 0) + AddAmmo(natives[1], amGrenade, 0) + AddAmmo(natives[1], amShotgun, 0) + AddAmmo(natives[1], amAirStrike, 0) + AddAmmo(natives[1], amMolotov, 0) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + for i = 7, 9 do + natives[i-6] = AddHog(nativeNames[i], 0, 100, nativeHats[i]) + origNatives[i-6] = natives[i-6] + end + natives[4] = AddHog(loc("Fell From Heaven"), 0, 133, "tiara") + origNatives[4] = natives[4] + nativesLeft = nativesNum + + AddTeam(loc("Beep Loopers"), 14483456, "ring", "UFO", "Robot", "cm_star") + for i = 1, cyborgsTeamNum[1] do + cyborgs[i] = AddHog(cyborgNames[i], cyborgsDif[i], cyborgsHealth[i], "cyborg2") + end + + AddTeam(loc("Corporationals"), 14483456, "ring", "UFO", "Robot", "cm_star") + for i = cyborgsTeamNum[1] + 1, cyborgsNum do + cyborgs[i] = AddHog(cyborgNames[i], cyborgsDif[i], cyborgsHealth[i], "cyborg2") + end + cyborgsLeft = cyborgsTeamNum[1] + cyborgsTeamNum[2] + + AddTeam(loc("Leaderbot"), 14483456, "ring", "UFO", "Robot", "cm_star") + enemy = AddHog(loc("Name"), 2, 200, "cyborg1") + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Unit 334a$7%;.*"), 0, 200, "cyborg1") + + SetGearPosition(cyborg, 0, 0) + + for i = 1, nativesNum do + AnimSetGearPosition(natives[i], unpack(nativePos[i])) + end + + AnimSetGearPosition(enemy, unpack(enemyPos)) + AnimTurn(enemy, "Left") + + for i = 1, cyborgsNum do + AnimSetGearPosition(cyborgs[i], unpack(cyborgsPos[i])) + AnimTurn(cyborgs[i], cyborgsDir[i]) + end +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 0 + GameFlags = gfDisableGirders + gfDisableLandObjects + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + MapGen = 2 + Theme = "Hell" + SuddenDeathTurns = 20 + + for i = 1, #map do + ParseCommand('draw ' .. map[i]) + end + + GetVariables() + AnimInit() + AddHogs() +end + +function onGameStart() + SetupAmmo() + SetupPlace() + AnimationSetup() + SetupEvents() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + local toRemove = nil + gearDead[gear] = true + if GetGearType(gear) == gtHedgehog then + if GetHogTeamName(gear) == loc("Beep Loopers") or GetHogTeamName(gear) == loc("Corporationals") then + cyborgsLeft = cyborgsLeft - 1 + elseif GetHogTeamName(gear) == loc("Natives") then + for i = 1, nativesLeft do + if natives[i] == gear then + toRemove = i + end + end + table.remove(natives, toRemove) + nativesLeft = nativesLeft - 1 + end + end +end + +function onAmmoStoreInit() + SetAmmo(amBaseballBat, 9, 0, 0, 0) + SetAmmo(amFirePunch, 9, 0, 0, 0) + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amSkip, 9, 0, 0, 0) + SetAmmo(amSwitch, 9, 0, 0, 0) + SetAmmo(amBazooka, 9, 0, 0, 0) + SetAmmo(amGrenade, 9, 0, 0, 0) + SetAmmo(amAirStrike, 1, 0, 0, 0) + SetAmmo(amMolotov, 5, 0, 0, 0) + SetAmmo(amShotgun, 9, 0, 0, 0) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + if GetHogTeamName(CurrentHedgehog) == loc("011101001") then + TurnTimeLeft = 0 + end +end + +function onPrecise() + if GameTime > 2500 and AnimInProgress() then + SetAnimSkip(true) +-- else +-- DeleteGear(cyborgs[1]) +-- table.remove(cyborgs, 1) +-- if cyborgsLeft == 0 then +-- DeleteGear(enemy) +-- end + end +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/shadow.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,964 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Constants--------------------------------- +startStage = 0 +spyStage = 1 +wave1Stage = 2 +wave2Stage = 3 +cyborgStage = 4 +ramonStage = 5 +aloneStage = 6 +duoStage = 7 +interSpyStage = 8 +interWeakStage = 9 +acceptedReturnStage = 10 +refusedReturnStage = 11 +attackedReturnStage = 12 +loseStage = 13 + +ourTeam = 0 +weakTeam = 1 +strongTeam = 2 +cyborgTeam = 3 + +leaksNr = 0 +denseNr = 1 + +choiceAccept = 1 +choiceRefuse = 2 +choiceAttack = 3 + +HogNames = {loc("Brainiac"), loc("Corpsemonger"), loc("Femur Lover"), loc("Glark"), loc("Bonely"), loc("Rot Molester"), loc("Bloodrocutor"), loc("Muscle Dissolver"), loc("Bloodsucker")} + +---POSITIONS--- + +cannibalPos = {{3108, 1127}, + {2559, 1080}, {3598, 1270}, {3293, 1177}, {2623, 1336}, + {3418, 1336}, {3447, 1335}, {3481, 1340}, {3507, 1324}} +densePos = {2776, 1177} +leaksPos = {2941, 1172} +cyborgPos = {1113, 1818} + +---Animations + +startDialogue = {} +weaklingsAnim = {} +stronglingsAnim = {} +acceptedAnim = {} +acceptedSurvivedFinalAnim = {} +acceptedDiedFinalAnim = {} +refusedAnim = {} +refusedFinalAnim = {} +attackedAnim = {} +attackedFinalAnim = {} + +-----------------------------Variables--------------------------------- +lastHogTeam = ourTeam +lastOurHog = leaksNr +lastEnemyHog = 0 +stage = 0 +choice = 0 + +brainiacDead = false +cyborgHidden = false +leaksHidden = false +denseHidden = false +cyborgAttacked = false +retryReturn = false +shotgunTaken = false +grenadeTaken = false +spikyDead = false +ramonDead = false +denseDead = false +leaksDead = false +ramonHidden = false +spikyHidden = false +grenadeUsed = false +shotgunUsed = false + + +hogNr = {} +cannibalDead = {} +isHidden = {} + + +--------------------------Anim skip functions-------------------------- +function AfterRefusedAnim() + SpawnUtilityCrate(2045, 1575, amSwitch) + SpawnUtilityCrate(2365, 1495, amShotgun) + SpawnUtilityCrate(2495, 1519, amGrenade) + SpawnUtilityCrate(2620, 1524, amRope) + ShowMission(loc("The Shadow Falls"), loc("The Showdown"), loc("Save Leaks A Lot!|Hint: The Switch utility might be of help to you."), 1, 6000) + RemoveEventFunc(CheckDenseDead) + AddEvent(CheckStronglingsDead, {}, DoStronglingsDeadRefused, {}, 0) + AddAmmo(cannibals[6], amGrenade, 1) + AddAmmo(cannibals[7], amGrenade, 1) + AddAmmo(cannibals[8], amGrenade, 1) + AddAmmo(cannibals[9], amGrenade, 1) + stage = ramonStage + SwitchHog(cannibals[9]) + FollowGear(ramon) + TurnTimeLeft = 0 + SetGearMessage(ramon, 0) + SetGearMessage(leaks, 0) + AnimWait(ramon, 1) + AddFunction({func = HideHog, args = {cyborg}}) +end + +function SkipRefusedAnim() + RefusedStart() + AnimSetGearPosition(dense, 2645, 1146) + AnimSetGearPosition(ramon, 2218, 1675) + AnimSetGearPosition(spiky, 2400, 1675) +end + +function AfterStartDialogue() + stage = spyStage + ShowMission(loc("The Shadow Falls"), loc("Play with me!"), loc("Defend yourself!|Hint: You can get tips on using weapons by moving your mouse over them in the weapon selection menu"), 1, 6000) + TurnTimeLeft = TurnTime +end + + +function StartSkipFunc() + SetState(cannibals[1], 0) + AnimTurn(leaks, "Right") + AnimSwitchHog(leaks) + SetInputMask(0xFFFFFFFF) +end + +function AfterWeaklingsAnim() + AddAmmo(cannibals[2], amShotgun, 1) + AddAmmo(cannibals[2], amGrenade, 1) + AddAmmo(cannibals[3], amShotgun, 1) + AddAmmo(cannibals[3], amGrenade, 1) + AddAmmo(cannibals[4], amShotgun, 1) + AddAmmo(cannibals[4], amGrenade, 1) + AddAmmo(cannibals[5], amShotgun, 1) + AddAmmo(cannibals[5], amGrenade, 1) + AddAmmo(leaks, amSkip, 4) + AddAmmo(dense, amSkip, 4) + AddEvent(CheckWeaklingsKilled, {}, DoWeaklingsKilled, {}, 0) + SetHealth(SpawnHealthCrate(2757, 1030), 50) + SetHealth(SpawnHealthCrate(2899, 1009), 50) + stage = wave1Stage + SwitchHog(dense) + SetGearMessage(dense, 0) + SetGearMessage(leaks, 0) + TurnTimeLeft = TurnTime + ShowMission(loc("The Shadow Falls"), loc("Why do you not like me?"), loc("Obliterate them!|Hint: You might want to take cover..."), 1, 6000) +end + +function SkipWeaklingsAnim() + for i = 2, 5 do + if isHidden[cannibals[i]] == true then + RestoreHog(cannibals[i]) + isHidden[cannibals[i]] = false + end + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + SetState(cannibals[i], 0) + end + SetInputMask(0xFFFFFFFF) +end + +function AfterStronglingsAnim() + stage = cyborgStage + ShowMission(loc("The Shadow Falls"), loc("The Dilemma"), loc("Choose your side! If you want to join the strange man, walk up to him.|Otherwise, walk away from him. If you decide to att...nevermind..."), 1, 8000) + AddEvent(CheckChoice, {}, DoChoice, {}, 0) + AddEvent(CheckRefuse, {}, DoRefuse, {}, 0) + AddEvent(CheckAccept, {}, DoAccept, {}, 0) + AddEvent(CheckConfront, {}, DoConfront, {}, 0) + AddAmmo(dense, amSwitch, 0) + AddAmmo(dense, amSkip, 0) + AddAmmo(leaks, amSwitch, 0) + AddAmmo(leaks, amSkip, 0) + SetHealth(SpawnHealthCrate(2557, 1030), 50) + SetHealth(SpawnHealthCrate(3599, 1009), 50) + TurnTimeLeft = 0 +end + +function SkipStronglingsAnim() + for i = 6, 9 do + if isHidden[cannibals[i]] == true then + RestoreHog(cannibals[i]) + isHidden[cannibals[i]] = false + end + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + SetState(cannibals[i], 0) + end + if cyborgHidden == true then + RestoreHog(cyborg) + cyborgHidden = false + end + SetState(cyborg, 0) + SetState(dense, 0) + AnimSetGearPosition(dense, 1350, 1315) + FollowGear(dense) + HogTurnLeft(dense, true) + AnimSetGearPosition(cyborg, 1250, 1315) + SwitchHog(dense) + SetInputMask(0xFFFFFFFF) +end + +function RestartReturnAccepted() + retryReturn = false + AnimSetGearPosition(dense, 1350, 1310) + AddAmmo(dense, amGirder, 2) + AddAmmo(dense, amParachute, 2) + ShowMission(loc("The Shadow Falls"), loc("The walk of Fame"), loc("Return to Leaks A Lot! If you get stuck, press [Precise] to try again!"), 1, 6000) + RemoveEventFunc(CheckNeedGirder) + RemoveEventFunc(CheckNeedWeapons) + AddEvent(CheckNeedGirder, {}, DoNeedGirder, {}, 0) + AddEvent(CheckNeedWeapons, {}, DoNeedWeapons, {}, 0) +end + + +function AfterAcceptedAnim() + stage = acceptedReturnStage + SpawnAmmoCrate(1370, 810, amGirder) + SpawnAmmoCrate(1300, 810, amParachute) + ShowMission(loc("The Shadow Falls"), loc("The walk of Fame"), loc("Return to Leaks A Lot! If you get stuck, press [Precise] to try again!"), 1, 6000) + AddEvent(CheckTookWeapons, {}, DoTookWeapons, {}, 0) + AddEvent(CheckNeedGirder, {}, DoNeedGirder, {}, 0) + AddEvent(CheckNeedWeapons, {}, DoNeedWeapons, {}, 0) + AddEvent(CheckRestartReturnAccepted, {}, RestartReturnAccepted, {}, 1) + RemoveEventFunc(CheckDenseDead) + SwitchHog(dense) + AnimWait(dense, 1) + AddFunction({func = HideHog, args = {cyborg}}) +end + +function SkipAcceptedAnim() + AnimSetGearPosition(cyborg, unpack(cyborgPos)) + SetState(cyborg, gstInvisible) + AnimSwitchHog(dense) + SetInputMask(0xFFFFFFFF) +end + +function AfterAttackedAnim() + stage = aloneStage + ShowMission(loc("The Shadow Falls"), loc("The Individualist"), loc("Defeat the cannibals!|Grenade hint: set the timer with [1-5], aim with [Up]/[Down] and hold [Space] to set power"), 1, 8000) + AddAmmo(cannibals[6], amGrenade, 1) + AddAmmo(cannibals[6], amFirePunch, 0) + AddAmmo(cannibals[6], amBaseballBat, 0) + AddAmmo(cannibals[7], amGrenade, 1) + AddAmmo(cannibals[7], amFirePunch, 0) + AddAmmo(cannibals[7], amBaseballBat, 0) + AddAmmo(cannibals[8], amGrenade, 1) + AddAmmo(cannibals[8], amFirePunch, 0) + AddAmmo(cannibals[8], amBaseballBat, 0) + AddAmmo(cannibals[9], amGrenade, 1) + AddAmmo(cannibals[9], amFirePunch, 0) + AddAmmo(cannibals[9], amBaseballBat, 0) + SetGearMessage(leaks, 0) + TurnTimeLeft = TurnTime + AddEvent(CheckStronglingsDead, {}, DoStronglingsDeadAttacked, {}, 0) + SwitchHog(leaks) + AnimWait(dense, 1) + AddFunction({func = HideHog, args = {cyborg}}) +end + +function SkipAttackedAnim() + if denseDead == false then + DeleteGear(dense) + end + SpawnAmmoCrate(2551, 994, amGrenade) + SpawnAmmoCrate(3551, 994, amGrenade) + SpawnAmmoCrate(3392, 1101, amShotgun) + SpawnAmmoCrate(3192, 1101, amShotgun) + AnimSetGearPosition(cyborg, unpack(cyborgPos)) + SetState(cyborg, gstInvisible) + AnimSwitchHog(leaks) + SetInputMask(0xFFFFFFFF) +end + + +-----------------------------Animations-------------------------------- + +function SpawnCrates() + SpawnAmmoCrate(2551, 994, amGrenade) + SpawnAmmoCrate(3551, 994, amGrenade) + SpawnAmmoCrate(3392, 1101, amShotgun) + SpawnAmmoCrate(3192, 1101, amShotgun) + return true +end + +function EmitDenseClouds(anim, dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) +end + +function BlowDenseCloud() + AnimInsertStepNext({func = DeleteGear, args = {dense}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense), GetY(dense), vgtBigExplosion, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 1200}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + 20, GetY(dense), vgtExplosion, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 100}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + 10, GetY(dense), vgtExplosion, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 100}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) - 10, GetY(dense), vgtExplosion, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 100}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) - 20, GetY(dense), vgtExplosion, 0, true}, swh = false}) +end + +function SetupAcceptedSurvivedFinalAnim() + table.insert(acceptedSurvivedFinalAnim, {func = AnimCustomFunction, args = {dense, CondNeedToTurn, {leaks, dense}}}) + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {leaks, loc("Pfew! That was close!"), SAY_SAY, 3000}}) + if grenadeUsed and shotgunUsed then + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {leaks, loc("Where did you get the exploding apples and the magic bow that shoots many arrows?"), SAY_SAY, 9000}}) + elseif grenadeUsed then + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {leaks, loc("Where did you get the exploding apples?"), SAY_SAY, 6000}}) + elseif shotgunUsed then + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {leaks, loc("Where did you get the magic bow that shoots many arrows?"), SAY_SAY, 8000}}) + else + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {leaks, loc("Did you warn the village?"), SAY_SAY, 4000}}) + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {dense, loc("No, I came back to help you out..."), SAY_SAY, 5000}}) + end + if grenadeUsed or shotgunUsed then + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {dense, loc("Uhm...I met one of them and took his weapons."), SAY_SAY, 5000}}) + end + table.insert(acceptedSurvivedFinalAnim, {func = AnimSay, args = {dense, loc("We should head back to the village now."), SAY_SAY, 5000}}) +end + +function AnimationSetup() + table.insert(startDialogue, {func = AnimWait, args = {dense, 4000}}) + table.insert(startDialogue, {func = AnimCaption, args = {leaks, loc("After the shock caused by the enemy spy, Leaks A Lot and Dense Cloud went hunting to relax."), 6000}}) + table.insert(startDialogue, {func = AnimCaption, args = {leaks, loc("Little did they know that this hunt will mark them forever..."), 4000}}) + table.insert(startDialogue, {func = AnimSay, args = {leaks, loc("I have no idea where that mole disappeared...Can you see it?"), SAY_SAY, 9000}}) + table.insert(startDialogue, {func = AnimSay, args = {dense, loc("Nope. It was one fast mole, that's for sure."), SAY_SAY, 5000}}) + table.insert(startDialogue, {func = AnimCustomFunction, args = {dense, EmitDenseClouds, {startDialogue, "Right"}}}) + table.insert(startDialogue, {func = AnimWait, args = {dense, 2000}}) + table.insert(startDialogue, {func = AnimSay, args = {leaks, loc("Please, stop releasing your \"smoke signals\"!"), SAY_SAY, 5000}}) + table.insert(startDialogue, {func = AnimSay, args = {leaks, loc("You're terrorizing the forest...We won't catch anything like this!"), SAY_SAY, 6000}}) + table.insert(startDialogue, {func = AnimSay, args = {leaks, loc("..."), SAY_THINK, 1000}}) + table.insert(startDialogue, {func = AnimGiveState, args = {cannibals[1], 0}, swh = false}) + table.insert(startDialogue, {func = AnimOutOfNowhere, args = {cannibals[1], unpack(cannibalPos[1])}, swh = false}) + table.insert(startDialogue, {func = AnimTurn, args = {leaks, "Right"}}) + table.insert(startDialogue, {func = AnimTurn, args = {cannibals[1], "Right"}}) + table.insert(startDialogue, {func = AnimWait, args = {cannibals[1], 1000}}) + table.insert(startDialogue, {func = AnimTurn, args = {cannibals[1], "Left"}}) + table.insert(startDialogue, {func = AnimWait, args = {cannibals[1], 1000}}) + table.insert(startDialogue, {func = AnimTurn, args = {cannibals[1], "Right"}}) + table.insert(startDialogue, {func = AnimSay, args = {cannibals[1], loc("I can't believe it worked!"), SAY_THINK, 3500}}) + table.insert(startDialogue, {func = AnimSay, args = {cannibals[1], loc("That shaman sure knows what he's doing!"), SAY_THINK, 6000}}) + table.insert(startDialogue, {func = AnimSay, args = {cannibals[1], loc("Yeah...I think it's a 'he', lol."), SAY_THINK, 5000}}) + table.insert(startDialogue, {func = AnimSay, args = {leaks, loc("It wants our brains!"), SAY_SHOUT, 3000}}) + table.insert(startDialogue, {func = AnimTurn, args = {cannibals[1], "Left"}}) + table.insert(startDialogue, {func = AnimSay, args = {cannibals[1], loc("Not you again! My head still hurts from last time!"), SAY_SHOUT, 6000}}) + table.insert(startDialogue, {func = AnimSwitchHog, args = {leaks}}) + AddSkipFunction(startDialogue, StartSkipFunc, {}) + + table.insert(weaklingsAnim, {func = AnimGearWait, args = {leaks, 1000}}) + table.insert(weaklingsAnim, {func = AnimCustomFunction, args = {leaks, CondNeedToTurn, {leaks, dense}}}) + table.insert(weaklingsAnim, {func = AnimSay, args = {leaks, loc("Did you see him coming?"), SAY_SAY, 3500}}) + table.insert(weaklingsAnim, {func = AnimSay, args = {dense, loc("No. Where did he come from?"), SAY_SAY, 3500}}) + table.insert(weaklingsAnim, {func = AnimCustomFunction, args = {leaks, UnHideWeaklings, {}}}) + table.insert(weaklingsAnim, {func = AnimOutOfNowhere, args = {cannibals[2], unpack(cannibalPos[2])}}) + table.insert(weaklingsAnim, {func = AnimGiveState, args = {cannibals[2], 0}}) + table.insert(weaklingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(weaklingsAnim, {func = AnimGiveState, args = {cannibals[3], 0}}) + table.insert(weaklingsAnim, {func = AnimOutOfNowhere, args = {cannibals[3], unpack(cannibalPos[3])}}) + table.insert(weaklingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(weaklingsAnim, {func = AnimGiveState, args = {cannibals[4], 0}}) + table.insert(weaklingsAnim, {func = AnimOutOfNowhere, args = {cannibals[4], unpack(cannibalPos[4])}}) + table.insert(weaklingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(weaklingsAnim, {func = AnimGiveState, args = {cannibals[5], 0}}) + table.insert(weaklingsAnim, {func = AnimOutOfNowhere, args = {cannibals[5], unpack(cannibalPos[5])}}) + table.insert(weaklingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(weaklingsAnim, {func = AnimSay, args = {cannibals[3], loc("Are we there yet?"), SAY_SAY, 4000}}) + table.insert(weaklingsAnim, {func = AnimSay, args = {dense, loc("This must be some kind of sorcery!"), SAY_SHOUT, 3500}}) + table.insert(weaklingsAnim, {func = AnimSwitchHog, args = {leaks}}) + AddSkipFunction(weaklingsAnim, SkipWeaklingsAnim, {}) + + table.insert(stronglingsAnim, {func = AnimGearWait, args = {leaks, 1000}}) + table.insert(stronglingsAnim, {func = AnimCustomFunction, args = {leaks, UnHideStronglings, {}}}) + table.insert(stronglingsAnim, {func = AnimCustomFunction, args = {leaks, CondNeedToTurn, {leaks, dense}}}) + table.insert(stronglingsAnim, {func = AnimGiveState, args = {leaks, 0}}) + table.insert(stronglingsAnim, {func = AnimGiveState, args = {dense, 0}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {leaks, loc("I thought their shaman died when he tried our medicine!"), SAY_SAY, 7000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {dense, loc("I saw it with my own eyes!"), SAY_SAY, 4000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {leaks, loc("Then how do they keep appearing?"), SAY_SAY, 4000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {leaks, loc("It's impossible to communicate with the spirits without a shaman."), SAY_SAY, 7000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {dense, loc("We need to warn the village."), SAY_SAY, 3500}}) + table.insert(stronglingsAnim, {func = AnimGiveState, args = {cannibals[6], 0}}) + table.insert(stronglingsAnim, {func = AnimOutOfNowhere, args = {cannibals[6], unpack(cannibalPos[6])}}) + table.insert(stronglingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(stronglingsAnim, {func = AnimGiveState, args = {cannibals[7], 0}}) + table.insert(stronglingsAnim, {func = AnimOutOfNowhere, args = {cannibals[7], unpack(cannibalPos[7])}}) + table.insert(stronglingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(stronglingsAnim, {func = AnimGiveState, args = {cannibals[8], 0}}) + table.insert(stronglingsAnim, {func = AnimOutOfNowhere, args = {cannibals[8], unpack(cannibalPos[8])}}) + table.insert(stronglingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(stronglingsAnim, {func = AnimGiveState, args = {cannibals[9], 0}}) + table.insert(stronglingsAnim, {func = AnimOutOfNowhere, args = {cannibals[9], unpack(cannibalPos[9])}}) + table.insert(stronglingsAnim, {func = AnimWait, args = {leaks, 400}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cannibals[7], loc("What a ride!"), SAY_SHOUT, 2000}}) + table.insert(stronglingsAnim, {func = AnimTurn, args = {leaks, "Right"}}) + table.insert(stronglingsAnim, {func = AnimWait, args = {leaks, 700}}) + table.insert(stronglingsAnim, {func = AnimTurn, args = {leaks, "Left"}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {leaks, loc("We can't defeat them!"), SAY_THINK, 3000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {leaks, loc("I'll hold them off while you return to the village!"), SAY_SAY, 6000}}) + table.insert(stronglingsAnim, {func = AnimFollowGear, args = {cyborg}, swh = false}) + table.insert(stronglingsAnim, {func = AnimCaption, args = {cyborg, loc("30 minutes later...")}, swh = false}) + table.insert(stronglingsAnim, {func = AnimWait, args = {cyborg, 2000}}) + table.insert(stronglingsAnim, {func = AnimSetGearPosition, args = {dense, 1420, 1315}}) + table.insert(stronglingsAnim, {func = AnimMove, args = {dense, "Left", 1400, 0}}) + table.insert(stronglingsAnim, {func = AnimCustomFunction, args = {dense, EmitDenseClouds, {stronglingsAnim, "Left"}}}) + table.insert(stronglingsAnim, {func = AnimMove, args = {dense, "Left", 1350, 0}}) + table.insert(stronglingsAnim, {func = AnimOutOfNowhere, args = {cyborg, 1250, 1320}}) + table.insert(stronglingsAnim, {func = AnimRemoveState, args = {cyborg, gstInvisible}}) + table.insert(stronglingsAnim, {func = AnimGearWait, args = {cyborg, 2000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("Greetings, cloudy one!"), SAY_SAY, 3000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("I have come to make you an offering..."), SAY_SAY, 6000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("You are given the chance to turn your life around..."), SAY_SAY, 6000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("If you agree to provide the information we need, you will be spared!"), SAY_SAY, 7000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("Have no illusions, your tribe is dead, indifferent of your choice."), SAY_SAY, 7000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("If you decide to help us, though, we will no longer need to find a new governor for the island."), SAY_SAY, 8000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("If you know what I mean..."), SAY_SAY, 3000}}) + table.insert(stronglingsAnim, {func = AnimSay, args = {cyborg, loc("So? What will it be?"), SAY_SAY, 3000}}) + table.insert(stronglingsAnim, {func = AnimSwitchHog, args = {dense}}) + AddSkipFunction(stronglingsAnim, SkipStronglingsAnim, {}) + + table.insert(acceptedAnim, {func = AnimSay, args = {cyborg, loc("Great choice, Steve! Mind if I call you that?"), SAY_SAY, 7000}}) + table.insert(acceptedAnim, {func = AnimSay, args = {dense, loc("Whatever floats your boat..."), SAY_SAY, 4500}}) + table.insert(acceptedAnim, {func = AnimSay, args = {cyborg, loc("Great! You will be contacted soon for assistance."), SAY_SAY, 6000}}) + table.insert(acceptedAnim, {func = AnimSay, args = {cyborg, loc("In the meantime, take these and return to your \"friend\"!"), SAY_SAY, 6000}}) + table.insert(acceptedAnim, {func = AnimGiveState, args = {cyborg, gstInvisible}}) + table.insert(acceptedAnim, {func = AnimDisappear, args = {cyborg, unpack(cyborgPos)}}) + table.insert(acceptedAnim, {func = AnimSwitchHog, args = {dense}}) + AddSkipFunction(acceptedAnim, SkipAcceptedAnim, {}) + + table.insert(acceptedDiedFinalAnim, {func = AnimSay, args = {leaks, loc("Pfew! That was close!"), SAY_THINK, 3000}}) + table.insert(acceptedDiedFinalAnim, {func = AnimSay, args = {leaks, loc("Your death will not be in vain, Dense Cloud!"), SAY_THINK, 5000}}) + table.insert(acceptedDiedFinalAnim, {func = AnimSay, args = {dense, loc("You will be avenged!"), SAY_SAY, 3000}}) + + table.insert(refusedAnim, {func = AnimSay, args = {cyborg, loc("I see..."), SAY_SAY, 2000}}) + table.insert(refusedAnim, {func = AnimSay, args = {cyborg, loc("Remember this, pathetic animal: when the day comes, you will regret your blind loyalty!"), SAY_SAY, 8000}}) + table.insert(refusedAnim, {func = AnimSay, args = {cyborg, loc("You just committed suicide..."), SAY_SAY, 5000}}) + table.insert(refusedAnim, {func = AnimDisappear, args = {cyborg, unpack(cyborgPos)}}) + table.insert(refusedAnim, {func = AnimGiveState, args = {cyborg, gstInvisible}}) + table.insert(refusedAnim, {func = AnimSay, args = {dense, loc("If you say so..."), SAY_THINK, 3000}}) + table.insert(refusedAnim, {func = AnimFollowGear, args = {cyborg}, swh = false}) + table.insert(refusedAnim, {func = AnimWait, args = {cyborg, 700}}) + table.insert(refusedAnim, {func = AnimCustomFunction, args = {dense, RefusedStart, {}}}) + table.insert(refusedAnim, {func = AnimOutOfNowhere, args = {dense, 2645, 1146}}) + table.insert(refusedAnim, {func = AnimOutOfNowhere, args = {ramon, 2218, 1675}}) + table.insert(refusedAnim, {func = AnimOutOfNowhere, args = {spiky, 2400, 1675}}) + table.insert(refusedAnim, {func = AnimTurn, args = {spiky, "Left"}}) + table.insert(refusedAnim, {func = AnimWait, args = {cyborg, 1700}}) + table.insert(refusedAnim, {func = AnimTurn, args = {spiky, "Right"}}) + table.insert(refusedAnim, {func = AnimWait, args = {cyborg, 1700}}) + table.insert(refusedAnim, {func = AnimTurn, args = {spiky, "Left"}}) + table.insert(refusedAnim, {func = AnimSay, args = {spiky, loc("Dude, we really need a new shaman..."), SAY_SAY, 4000}}) + AddSkipFunction(refusedAnim, SkipRefusedAnim, {}) + + table.insert(refusedFinalAnim, {func = AnimSay, args = {leaks, loc("It's over..."), SAY_SAY, 2000}}) + table.insert(refusedFinalAnim, {func = AnimSay, args = {leaks, loc("Let's head back to the village!"), SAY_SAY, 4000}}) + + table.insert(attackedAnim, {func = AnimCustomFunction, args = {dense, CondNeedToTurn, {cyborg, dense}}}) + table.insert(attackedAnim, {func = AnimCustomFunction, args = {cyborg, SetHealth, {cyborg, 200}}}) + table.insert(attackedAnim, {func = AnimWait, args = {cyborg, 2000}}) + table.insert(attackedAnim, {func = AnimSay, args = {cyborg, loc("Really?! You thought you could harm me with your little toys?"), SAY_SAY, 7000}}) + table.insert(attackedAnim, {func = AnimSay, args = {cyborg, loc("You're pathetic! You are not worthy of my attention..."), SAY_SAY, 6000}}) + table.insert(attackedAnim, {func = AnimSay, args = {cyborg, loc("Actually, you aren't worthy of life! Take this..."), SAY_SAY, 5000}}) + table.insert(attackedAnim, {func = AnimCustomFunction, args = {dense, BlowDenseCloud, {}}, swh = false}) + table.insert(attackedAnim, {func = AnimWait, args = {cyborg, 2000}}) + table.insert(attackedAnim, {func = AnimSay, args = {cyborg, loc("Incredible..."), SAY_SAY, 3000}}) + table.insert(attackedAnim, {func = AnimDisappear, args = {cyborg, unpack(cyborgPos)}}) + table.insert(attackedAnim, {func = AnimGiveState, args = {cyborg, gstInvisible}}) + table.insert(attackedAnim, {func = AnimSwitchHog, args = {leaks}}) + table.insert(attackedAnim, {func = AnimSay, args = {leaks, loc("I wonder where Dense Cloud is..."), SAY_THINK, 4000}}) + table.insert(attackedAnim, {func = AnimSay, args = {leaks, loc("I can't wait any more, I have to save myself!"), SAY_THINK, 5000}}) + table.insert(attackedAnim, {func = AnimCustomFunction, args = {leaks, SpawnCrates, {}}}) + table.insert(attackedAnim, {func = AnimWait, args = {leaks, 1500}}) + table.insert(attackedAnim, {func = AnimSay, args = {leaks, loc("Where are all these crates coming from?!"), SAY_THINK, 5500}}) + AddSkipFunction(attackedAnim, SkipAttackedAnim, {}) + + table.insert(attackedFinalAnim, {func = AnimWait, args = {leaks, 2000}}) + table.insert(attackedFinalAnim, {func = AnimSay, args = {leaks, loc("I have to get back to the village!"), SAY_THINK, 5000}}) + table.insert(attackedFinalAnim, {func = AnimSay, args = {leaks, loc("Dense Cloud must have already told them everything..."), SAY_THINK, 7000}}) + +end + + +-----------------------------Misc-------------------------------------- + + +function RefusedStart() + if ramonHidden == true then + RestoreHog(ramon) + ramonHidden = false + end + if spikyHidden == true then + RestoreHog(spiky) + spikyHidden = false + end + SetState(ramon, 0) + SetState(spiky, 0) + SetGearMessage(dense, 0) + SetGearMessage(ramon, 0) + SetGearMessage(spiky, 0) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + ramon = AddHog(loc("Ramon"), 0, 100, "rasta") + leaks = AddHog(loc("Leaks A Lot"), 0, 100, "Rambo") + dense = AddHog(loc("Dense Cloud"), 0, 100, "RobinHood") + spiky = AddHog(loc("Spiky Cheese"), 0, 100, "hair_yellow") + + AddTeam(loc("Weaklings"), 14483456, "Skull", "Island", "Pirate","cm_vampire") + cannibals = {} + cannibals[1] = AddHog(loc("Brainiac"), 5, 20, "Zombi") + + for i = 2, 5 do + cannibals[i] = AddHog(HogNames[i], 1, 20, "Zombi") + hogNr[cannibals[i]] = i - 2 + end + + AddTeam(loc("Stronglings"), 14483456, "Skull", "Island", "Pirate","cm_vampire") + + for i = 6, 9 do + cannibals[i] = AddHog(HogNames[i], 2, 30, "vampirichog") + hogNr[cannibals[i]] = i - 2 + end + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Y3K1337"), 0, 200, "cyborg1") +end + +function PlaceHogs() + HogTurnLeft(leaks, true) + + for i = 2, 9 do + AnimSetGearPosition(cannibals[i], unpack(cyborgPos)) + AnimTurn(cannibals[i], "Left") + cannibalDead[i] = false + end + + AnimSetGearPosition(cannibals[1], cannibalPos[1][1], cannibalPos[1][2]) + AnimTurn(cannibals[1], "Left") + + AnimSetGearPosition(cyborg, cyborgPos[1], cyborgPos[2]) + AnimSetGearPosition(ramon, 2218, 1675) + AnimSetGearPosition(skiky, 2400, 1675) + AnimSetGearPosition(dense, densePos[1], densePos[2]) + AnimSetGearPosition(leaks, leaksPos[1], leaksPos[2]) +end + +function VisiblizeHogs() + for i = 1, 9 do + SetState(cannibals[i], gstInvisible) + end + SetState(cyborg, gstInvisible) + SetState(ramon, gstInvisible) + SetState(spiky, gstInvisible) +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +function HideHogs() + for i = 2, 9 do + HideHog(cannibals[i]) + isHidden[cannibals[i]] = true + end + HideHog(cyborg) + cyborgHidden = true + HideHog(ramon) + HideHog(spiky) + ramonHidden = true + spikyHidden = true +end + +function HideStronglings() + for i = 6, 9 do + HideHog(cannibals[i]) + isHidden[cannibals[i]] = true + end +end + +function UnHideWeaklings() + for i = 2, 5 do + RestoreHog(cannibals[i]) + isHidden[cannibals[i]] = false + SetState(cannibals[i], gstInvisible) + end +end + +function UnHideStronglings() + for i = 6, 9 do + RestoreHog(cannibals[i]) + isHidden[cannibals[i]] = false + SetState(cannibals[i], gstInvisible) + end + RestoreHog(cyborg) + cyborgHidden = false + SetState(cyborg, gstInvisible) +end + +function ChoiceTaken() + SetGearMessage(CurrentHedgehog, 0) + if choice == choiceAccept then + AddAnim(acceptedAnim) + AddFunction({func = AfterAcceptedAnim, args = {}}) + elseif choice == choiceRefuse then + AddAnim(refusedAnim) + AddFunction({func = AfterRefusedAnim, args = {}}) + else + AddAnim(attackedAnim) + AddFunction({func = AfterAttackedAnim, args = {}}) + end +end + +function KillCyborg() + RestoreHog(cyborg) + DeleteGear(cyborg) + TurnTimeLeft = 0 +end +-----------------------------Events------------------------------------ + +function CheckBrainiacDead() + return brainiacDead +end + +function DoBrainiacDead() + TurnTimeLeft = 0 + SetGearMessage(CurrentHedgehog, 0) + AddAnim(weaklingsAnim) + AddFunction({func = AfterWeaklingsAnim, args = {}}) + stage = interSpyStage +end + +function CheckWeaklingsKilled() + for i = 2, 5 do + if cannibalDead[i] == false then + return false + end + end + return true +end + +function DoWeaklingsKilled() + SetGearMessage(CurrentHedgehog, 0) + AddAnim(stronglingsAnim) + AddFunction({func = AfterStronglingsAnim, args = {}}) + stage = interWeakStage + ParseCommand("teamgone " .. loc("Weaklings")) +end + +function CheckRefuse() + return GetX(dense) > 1400 and StoppedGear(dense) +end + +function DoRefuse() + choice = choiceRefuse +end + +function CheckAccept() + return GetX(dense) < 1300 and StoppedGear(dense) +end + +function DoAccept() + choice = choiceAccept +end + +function CheckConfront() + return cyborgAttacked and StoppedGear(dense) +end + +function DoConfront() + choice = choiceAttack +end + +function CheckChoice() + return choice ~= 0 +end + +function DoChoice() + RemoveEventFunc(CheckConfront) + RemoveEventFunc(CheckAccept) + RemoveEventFunc(CheckRefuse) + ChoiceTaken() +end + +function CheckNeedGirder() + return GetX(dense) > 1640 and StoppedGear(dense) +end + +function DoNeedGirder() + ShowMission(loc("The Shadow Falls"), loc("Under Construction"), loc("To place a girder, select it, use [Left] and [Right] to select angle and length, place with [Left Click]"), 1, 6000) +end + +function CheckNeedWeapons() + return GetX(dense) > 2522 and StoppedGear(dense) +end + +function DoNeedWeapons() + grenadeCrate = SpawnAmmoCrate(2550, 800, amGrenade) + shotgunCrate = SpawnAmmoCrate(2610, 850, amShotgun) + AddCaption(loc("A little gift from the cyborgs")) +end + +function CheckTookWeapons() + return shotgunTaken and grenadeTaken +end + +function DoTookWeapons() + ShowMission(loc("The Shadow Falls"), loc("The guardian"), loc("Protect yourselves!|Grenade hint: set the timer with [1-5], aim with [Up]/[Down] and hold [Space] to set power"), 1, 8000) + AddAmmo(dense, amSkip, 100) + AddAmmo(dense, amSwitch, 100) + AddAmmo(leaks, amSkip, 100) + AddAmmo(leaks, amSwitch, 100) + stage = duoStage + RemoveEventFunc(CheckNeedGirder) + RemoveEventFunc(CheckNeedWeapons) + RemoveEventFunc(CheckRestartReturnAccepted) + AddEvent(CheckStronglingsDead, {}, DoStronglingsDead, {}, 0) + AddAmmo(cannibals[6], amGrenade, 2) + AddAmmo(cannibals[6], amShotgun, 2) + AddAmmo(cannibals[7], amGrenade, 2) + AddAmmo(cannibals[7], amShotgun, 2) + AddAmmo(cannibals[8], amGrenade, 2) + AddAmmo(cannibals[8], amShotgun, 2) + AddAmmo(cannibals[9], amGrenade, 2) + AddAmmo(cannibals[9], amShotgun, 2) + SetGearMessage(leaks, 0) + SetGearMessage(dense, 0) + TurnTimeLeft = TurnTime +end + +function DoStronglingsDead() + SetGearMessage(CurrentHedgehog, 0) + if denseDead == true then + AddAnim(acceptedDiedFinalAnim) + SaveCampaignVar("M2DenseDead", "1") + else + SetupAcceptedSurvivedFinalAnim() + AddAnim(acceptedSurvivedFinalAnim) + SaveCampaignVar("M2DenseDead", "0") + end + SaveCampaignVar("M2RamonDead", "0") + SaveCampaignVar("M2SpikyDead", "0") + AddFunction({func = KillCyborg, args = {}}) + SaveCampaignVar("Progress", "2") + SaveCampaignVar("M2Choice", "" .. choice) +end + +function DoStronglingsDeadRefused() + if denseDead == true then + SaveCampaignVar("M2DenseDead", "1") + else + SaveCampaignVar("M2DenseDead", "0") + end + if ramonDead == true then + SaveCampaignVar("M2RamonDead", "1") + else + SaveCampaignVar("M2RamonDead", "0") + end + if spikyDead == true then + SaveCampaignVar("M2SpikyDead", "1") + else + SaveCampaignVar("M2SpikyDead", "0") + end + AddAnim(refusedFinalAnim) + AddFunction({func = KillCyborg, args = {}}) + SaveCampaignVar("Progress", "2") + SaveCampaignVar("M2Choice", "" .. choice) +end + +function DoStronglingsDeadAttacked() + SaveCampaignVar("M2DenseDead", "1") + SaveCampaignVar("M2RamonDead", "0") + SaveCampaignVar("M2SpikyDead", "0") + SaveCampaignVar("Progress", "2") + SaveCampaignVar("M2Choice", "" .. choice) + AddAnim(attackedFinalAnim) + AddFunction({func = KillCyborg, args = {}}) +end + +function CheckStronglingsDead() + if leaksDead == true then + return false + end + for i = 6, 9 do + if cannibalDead[i] == false then + return false + end + end + return true +end + +function CheckLeaksDead() + return leaksDead +end + +function DoDead() + AddCaption(loc("...and so the cyborgs took over the world...")) + stage = loseStage + TurnTimeLeft = 0 + ParseCommand("teamgone " .. loc("Natives")) +end + +function CheckDenseDead() + return denseDead and choice ~= choiceAttack +end + +function CheckRestartReturnAccepted() + return retryReturn +end + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 334 + GameFlags = gfSolidLand + gfDisableWind + gfPerHogAmmo + TurnTime = 50000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 0 + Delay = 10 + MapGen = 0 + TemplateFilter = 6 + TemplateNumber = 22 + Theme = "Nature" + SuddenDeathTurns = 3000 + + AddHogs() + PlaceHogs() + VisiblizeHogs() + + AnimInit() + AnimationSetup() +end + +function onGameStart() + HideHogs() + AddAmmo(leaks, amSwitch, 100) + AddAmmo(dense, amSwitch, 100) + AddEvent(CheckLeaksDead, {}, DoDead, {}, 0) + AddEvent(CheckDenseDead, {}, DoDead, {}, 0) + AddAnim(startDialogue) + AddFunction({func = AfterStartDialogue, args = {}}) + AddEvent(CheckBrainiacDead, {}, DoBrainiacDead, {}, 0) + ShowMission(loc("The Shadow Falls"), loc("The First Encounter"), loc("Survive!|Hint: Cinematics can be skipped with the [Precise] key."), 1, 0) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + if gear == cannibals[1] then + brainiacDead = true + elseif gear == grenadeCrate then + grenadeTaken = true + elseif gear == shotgunCrate then + shotgunTaken = true + elseif gear == dense then + denseDead = true + elseif gear == leaks then + leaksDead = true + elseif gear == ramon then + ramonDead = true + elseif gear == spiky then + spikyDead = true + else + for i = 2, 9 do + if gear == cannibals[i] then + cannibalDead[i] = true + end + end + end +end + +function onGearAdd(gear) + if GetGearType(gear) == gtGrenade and GetHogTeamName(CurrentHedgehog) == loc("Natives") then + grenadeUsed = true + elseif GetGearType(gear) == gtShotgunShot and GetHogTeamName(CurrentHedgehog) == loc("Natives") then + shotgunUsed = true + end +end + +function onAmmoStoreInit() + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amSniperRifle, 6, 0, 0, 0) + SetAmmo(amFirePunch, 3, 0, 0, 0) + SetAmmo(amWhip, 4, 0, 0, 0) + SetAmmo(amBaseballBat, 4, 0, 0, 0) + SetAmmo(amHammer, 2, 0, 0, 0) + SetAmmo(amLandGun, 1, 0, 0, 0) + SetAmmo(amSnowball, 7, 0, 0, 0) + SetAmmo(amGirder, 0, 0, 0, 2) + SetAmmo(amParachute, 0, 0, 0, 2) + SetAmmo(amGrenade, 0, 0, 0, 3) + SetAmmo(amShotgun, 0, 0, 0, 3) + SetAmmo(amSwitch, 0, 0, 0, 8) + SetAmmo(amRope, 0, 0, 0, 6) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 +-- elseif stage == interSpyStage and GetHogTeamName(CurrentHedgehog) ~= loc("Natives") then +-- TurnTimeLeft = 0 +-- SetState(CurrentHedgehog, gstInvisible) + elseif stage == cyborgStage then + if CurrentHedgehog ~= dense then + TurnTimeLeft = 0 + else + TurnTimeLeft = -1 + end + elseif stage == acceptedReturnStage then + SwitchHog(dense) + FollowGear(dense) + TurnTimeLeft = -1 + end +end + +function onGearDamage(gear, damage) + if gear == cyborg and stage == cyborgStage then + cyborgAttacked = true + end +end + +function onPrecise() + if GameTime > 2500 and AnimInProgress() then + SetAnimSkip(true) + return + end + if stage == acceptedReturnStage then + retryReturn = true +-- else +-- for i = 1, 9 do +-- DeleteGear(cannibals[i]) +-- end + end +end + diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Missions/Campaign/A Classic Fairytale/united.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,521 @@ +loadfile(GetDataPath() .. "Scripts/Locale.lua")() +loadfile(GetDataPath() .. "Scripts/Animate.lua")() + +-----------------------------Constants--------------------------------- +choiceAccept = 1 +choiceRefuse = 2 +choiceAttack = 3 + +leaksPos = {2067, 509} +densePos = {1882, 503} +waterPos = {3100, 930} +buffaloPos = {2609, 494} +chiefPos = {2538, 617} +cannibalPos = {{2219, 1339}, {2322, 1357}, {805, 784}, {3876, 1048}, + {1101, 916}, {2854, 1408}, {1974, 486}, {1103, 961}} + +HogNames = {loc("Olive"), loc("Brain Stu"), loc("Brainila"), loc("Salivaslurper"), + loc("Spleenlover"), loc("Thighlicker"), loc("NomNom"), loc("Mindy")} + +natives = {} +-----------------------------Variables--------------------------------- +cannibals = {} +cannibalDead = {} +cannibalHidden = {} +cratesSpawned = {} +healthCratesSpawned = {} + +sdrmv = 0 +denseDead = false +leaksDead = false +waterDead = false +buffaloDead = false +chiefDead = false +nativesDead = {} + +m2Choice = 0 +m2DenseDead = 0 + +startAnim = {} +wave2Anim = {} +finalAnim = {} +--------------------------Anim skip functions-------------------------- +function AfterHogDeadAnim() + freshDead = nil + TurnTimeLeft = TurnTime +end + +function AfterStartAnim() + local goal = loc("Defeat the cannibals!|") + local chiefgoal = loc("Try to protect the chief! You won't lose if he dies, but it is advised that he survives.") + TurnTimeLeft = TurnTime + ShowMission(loc("United We Stand"), loc("Invasion"), goal .. chiefgoal, 1, 6000) +end + +function SkipStartAnim() + AnimSetGearPosition(water, 2467, 754) + if cratesSpawned[1] ~= true then + SpawnCrates(1) + end + if healthCratesSpawned[1] ~= true then + SpawnHealthCrates(1) + end + if cannibalHidden[1] == true then + RestoreWave(1) + end + AnimSwitchHog(leaks) +end + +function SkipWave2Anim() + if cratesSpawned[2] ~= true then + SpawnCrates(2) + end + if healthCratesSpawned[2] ~= true then + SpawnHealthCrates(2) + end + if cannibalHidden[5] == true then + RestoreWave(2) + end + AnimSwitchHog(cannibals[5]) +end + +function AfterWave2Anim() + TurnTimeLeft = 0 +end + +function AfterFinalAnim() + if leaksDead == true then + SaveCampaignVar("M4LeaksDead", "1") + else + SaveCampaignVar("M4LeaksDead", "0") + end + if chiefDead == true then + SaveCampaignVar("M4ChiefDead", "1") + else + SaveCampaignVar("M4ChiefDead", "0") + end + if buffaloDead == true then + SaveCampaignVar("M4BuffaloDead", "1") + else + SaveCampaignVar("M4BuffaloDead", "0") + end + if waterDead == true then + SaveCampaignVar("M4WaterDead", "1") + else + SaveCampaignVar("M4WaterDead", "0") + end + if denseDead == true then + SaveCampaignVar("M4DenseDead", "1") + else + SaveCampaignVar("M4DenseDead", "0") + end + SaveCampaignVar("Progress", "4") + ParseCommand("teamgone " .. loc("011101001")) + TurnTimeLeft = 0 +end +-----------------------------Animations-------------------------------- +function Wave2Reaction() + local i = 1 + local gearr = nil + while nativesDead[i] == true do + i = i + 1 + end + gearr = natives[i] + if denseDead ~= true and band(GetState(dense), gstDrowning) == 0 then + AnimInsertStepNext({func = AnimSay, args = {dense, loc("I'm so scared!"), SAY_SAY, 3000}}) + AnimInsertStepNext({func = AnimCustomFunction, args = {dense, EmitDenseClouds, {"Left"}}}) + AnimInsertStepNext({func = AnimTurn, args = {dense, "Left"}}) + end + AnimInsertStepNext({func = AnimSay, args = {gearr, loc("There's more of them? When did they become so hungry?"), SAY_SHOUT, 8000}}) +end + +function EmitDenseClouds(dir) + local dif + if dir == "Left" then + dif = 10 + else + dif = -10 + end + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) + AnimInsertStepNext({func = AnimWait, args = {dense, 800}}) + AnimInsertStepNext({func = AnimVisualGear, args = {dense, GetX(dense) + dif, GetY(dense) + dif, vgtSteam, 0, true}, swh = false}) +end + +function AnimationSetup() + table.insert(startAnim, {func = AnimWait, args = {leaks, 4000}}) + table.insert(startAnim, {func = AnimCaption, args = {leaks, loc("Back in the village, after telling the villagers about the threat..."), 5000}}) + table.insert(startAnim, {func = AnimCaption, args = {leaks, loc("Their buildings were very primitive back then, even for an uncivilised island."), 7000}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("Young one, you are telling us that they can instantly change location without a shaman?"), SAY_SAY, 8000}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("That is, indeed, very weird..."), SAY_SAY, 3500}}) + table.insert(startAnim, {func = AnimSay, args = {buffalo, loc("If they try coming here, they can have a taste of my delicious knuckles!"), SAY_SHOUT, 8000}}) + table.insert(startAnim, {func = AnimSay, args = {buffalo, loc("Haha!"), SAY_SHOUT, 2000}}) + if denseDead == false then + table.insert(startAnim, {func = AnimSay, args = {dense, loc("I'm not sure about that!"), SAY_SAY, 3400}}) + table.insert(startAnim, {func = AnimSay, args = {dense, loc("They have weapons we've never seen before!"), SAY_SAY, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {dense, loc("Luckily, I've managed to snatch some of them."), SAY_SAY, 5000}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {dense, SpawnCrates, {1}}}) + table.insert(startAnim, {func = AnimSay, args = {dense, loc("Oops...I dropped them."), SAY_SAY, 3000}}) + else + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("I'm not sure about that!"), SAY_SAY, 3400}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("They have weapons we've never seen before!"), SAY_SAY, 5000}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {leaks, SpawnCrates, {1}}}) + table.insert(startAnim, {func = AnimWait, args = {leaks, 1000}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("They keep appearing like this. It's weird!"), SAY_SAY, 5000}}) + end + table.insert(startAnim, {func = AnimSay, args = {chief, loc("Did anyone follow you?"), SAY_SAY, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("No, we made sure of that!"), SAY_SAY, 3500}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {leaks, SpawnHealthCrates, {1}}}) + table.insert(startAnim, {func = AnimWait, args = {leaks, 1000}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("First aid kits?!"), SAY_SAY, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("I've seen this before. They just appear out of thin air."), SAY_SAY, 7000}}) + table.insert(startAnim, {func = AnimMove, args = {water, "Left", 3000, 0}}) + table.insert(startAnim, {func = AnimJump, args = {water, "long"}}) + table.insert(startAnim, {func = AnimMove, args = {water, "Left", 2655, 0}}) + table.insert(startAnim, {func = AnimTurn, args = {water, "Right"}}) + table.insert(startAnim, {func = AnimJump, args = {water, "back"}}) + table.insert(startAnim, {func = AnimJump, args = {water, "back"}}) + table.insert(startAnim, {func = AnimTurn, args = {water, "Left"}}) + table.insert(startAnim, {func = AnimMove, args = {water, "Left", 2467, 754}}) + table.insert(startAnim, {func = AnimSay, args = {water, loc("Hey guys!"), SAY_SAY, 2500}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("..."), SAY_THINK, 1500}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("Where have you been?"), SAY_SAY, 4000}}) + table.insert(startAnim, {func = AnimSay, args = {water, loc("Just on a walk."), SAY_SAY, 3000}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("You have chosen the perfect moment to leave."), SAY_SAY, 6000}}) + table.insert(startAnim, {func = AnimCustomFunction, args = {chief, RestoreWave, {1}}}) + for i = 1, 4 do + table.insert(startAnim, {func = AnimOutOfNowhere, args = {cannibals[i], unpack(cannibalPos[i])}}) + end + table.insert(startAnim, {func = AnimWait, args = {chief, 1500}}) + table.insert(startAnim, {func = AnimSay, args = {leaks, loc("HOW DO THEY KNOW WHERE WE ARE???"), SAY_SHOUT, 5000}}) + table.insert(startAnim, {func = AnimSay, args = {chief, loc("We have to protect the village!"), SAY_SAY, 5000}}) + table.insert(startAnim, {func = AnimSwitchHog, args = {leaks}}) + AddSkipFunction(startAnim, SkipStartAnim, {}) + + table.insert(wave2Anim, {func = AnimCustomFunction, args = {leaks, RestoreWave, {2}}, swh = false}) + for i = 5, 8 do + table.insert(wave2Anim, {func = AnimOutOfNowhere, args = {cannibals[i], unpack(cannibalPos[i])}}) + end + table.insert(wave2Anim, {func = AnimCustomFunction, args = {leaks, Wave2Reaction, {}}, swh = false}) + table.insert(wave2Anim, {func = AnimCustomFunction, args = {leaks, SpawnCrates, {2}}, swh = false}) + table.insert(wave2Anim, {func = AnimCustomFunction, args = {leaks, SpawnHealthCrates, {2}}, swh = false}) + table.insert(wave2Anim, {func = AnimSwitchHog, args = {cannibals[5]}}) + AddSkipFunction(wave2Anim, SkipWave2Anim, {}) +end + +function SetupHogDeadAnim(gear) + hogDeadAnim = {} + if nativesNum == 0 then + return + end + local hogDeadStrings = {"They killed " .. gear .."! You bastards!", + gear .. "! Why?!", + "That was just mean!", + "Oh no, not " .. gear .. "!"} + table.insert(hogDeadAnim, {func = AnimSay, args = {CurrentHedgehog, hogDeadStrings[nativesNum], SAY_SHOUT, 4000}}) +end + +function SetupFinalAnim() + local found = 0 + local hogs = {} + local i = 1 + if nativesNum >= 2 then + while found < 2 do + if nativesDead[i] ~= true then + found = found + 1 + hogs[found] = natives[i] + end + i = i + 1 + end + if chiefDead ~= true then + hogs[2] = chief + end + table.insert(finalAnim, {func = AnimCustomFunction, args = {hogs[1], CondNeedToTurn, {hogs[1], hogs[2]}}}) + table.insert(finalAnim, {func = AnimSay, args = {hogs[1], loc("We can't hold them up much longer!"), SAY_SAY, 5000}}) + table.insert(finalAnim, {func = AnimSay, args = {hogs[1], loc("We need to move!"), SAY_SAY, 3000}}) + table.insert(finalAnim, {func = AnimSay, args = {hogs[2], loc("But where can we go?"), SAY_SAY, 3000}}) + table.insert(finalAnim, {func = AnimSay, args = {hogs[1], loc("To the caves..."), SAY_SAY, 2500}}) + table.insert(finalAnim, {func = AnimSay, args = {hogs[2], loc("Good idea, they'll never find us there!"), SAY_SAY, 5000}}) + else + for i = 1, 5 do + if nativesDead[i] ~= true then + hogs[1] = natives[i] + end + end + table.insert(finalAnim, {func = AnimSay, args = {hogs[1], loc("I need to move the tribe!"), SAY_THINK, 4000}}) + table.insert(finalAnim, {func = AnimSay, args = {hogs[1], loc("The caves are well hidden, they won't find us there!"), SAY_THINK, 7000}}) + end +end +-----------------------------Misc-------------------------------------- +function RestoreWave(index) + for i = (index - 1) * 4 + 1, index * 4 do + RestoreHog(cannibals[i]) + cannibalHidden[i] = false + end +end + +function GetVariables() + m2DenseDead = tonumber(GetCampaignVar("M2DenseDead")) + if m2DenseDead == 1 then + denseDead = true + end + m2Choice = tonumber(GetCampaignVar("M2Choice")) +end + +function SetupPlace() + if m2DenseDead == 1 then + sdrmv = 1 + DeleteGear(dense) + end + for i = 1, 8 do + HideHog(cannibals[i]) + cannibalHidden[i] = true + end + HideHog(cyborg) +end + +function SetupEvents() + AddEvent(CheckWaveDead, {1}, DoWaveDead, {1}, 0) + AddEvent(CheckWaveDead, {2}, DoWaveDead, {2}, 0) +end + +function SetupAmmo() + AddAmmo(cannibals[1], amGrenade, 4) + AddAmmo(cannibals[1], amBazooka, 4) + AddAmmo(cannibals[1], amShotgun, 4) + AddAmmo(cannibals[1], amMine, 2) + AddAmmo(cannibals[5], amGrenade, 4) + AddAmmo(cannibals[5], amBazooka, 4) + AddAmmo(cannibals[5], amShotgun, 4) + AddAmmo(cannibals[5], amMine, 2) + AddAmmo(cannibals[5], amMolotov, 2) + AddAmmo(cannibals[5], amFlamethrower, 3) +end + +function AddHogs() + AddTeam(loc("Natives"), 29439, "Bone", "Island", "HillBilly", "cm_birdy") + leaks = AddHog(loc("Leaks A Lot"), 0, 100, "Rambo") + dense = AddHog(loc("Dense Cloud"), 0, 100, "RobinHood") + water = AddHog(loc("Fiery Water"), 0, 100, "pirate_jack") + buffalo = AddHog(loc("Raging Buffalo"), 0, 100, "zoo_Bunny") + chief = AddHog(loc("Righteous Beard"), 0, 100, "IndianChief") + natives = {leaks, dense, water, buffalo, chief} + nativesNum = 5 + + AddTeam(loc("Light Cannfantry"), 14483456, "Skull", "Island", "Pirate", "cm_vampire") + for i = 1, 4 do + cannibals[i] = AddHog(HogNames[i], 2, 40, "Zombi") + end + + AddTeam(loc("Heavy Cannfantry"), 14483456, "Skull", "Island", "Pirate", "cm_vampire") + for i = 5, 8 do + cannibals[i] = AddHog(HogNames[i], 2, 55, "vampirichog") + end + + AddTeam(loc("011101001"), 14483456, "ring", "UFO", "Robot", "cm_star") + cyborg = AddHog(loc("Unit 334a$7%;.*"), 0, 200, "cyborg1") + + AnimSetGearPosition(leaks, unpack(leaksPos)) + AnimSetGearPosition(dense, unpack(densePos)) + AnimSetGearPosition(water, unpack(waterPos)) + HogTurnLeft(water, true) + AnimSetGearPosition(buffalo, unpack(buffaloPos)) + HogTurnLeft(buffalo, true) + AnimSetGearPosition(chief, unpack(chiefPos)) + HogTurnLeft(chief, true) + AnimSetGearPosition(cyborg, 0, 0) + for i = 1, 8 do + AnimSetGearPosition(cannibals[i], unpack(cannibalPos[i])) + end +end + +function CondNeedToTurn(hog1, hog2) + xl, xd = GetX(hog1), GetX(hog2) + if xl > xd then + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Right"}}) + elseif xl < xd then + AnimInsertStepNext({func = AnimTurn, args = {hog2, "Left"}}) + AnimInsertStepNext({func = AnimTurn, args = {hog1, "Right"}}) + end +end + +function SpawnHealthCrates(index) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) + SetHealth(SpawnHealthCrate(0, 0), 25) + healthCratesSpawned[index] = true +end + +function SpawnCrates(index) + if index == 1 then + SpawnAmmoCrate(1943, 408, amBazooka) + SpawnAmmoCrate(1981, 464, amGrenade) + SpawnAmmoCrate(1957, 459, amShotgun) + SpawnAmmoCrate(1902, 450, amDynamite) + SpawnUtilityCrate(1982, 405, amPickHammer) + SpawnUtilityCrate(2028, 455, amRope) + SpawnUtilityCrate(2025, 464, amTeleport) + else + SpawnUtilityCrate(1982, 405, amBlowTorch) + SpawnAmmoCrate(2171, 428, amMolotov) + SpawnAmmoCrate(2364, 346, amFlamethrower) + SpawnAmmoCrate(2521, 303, amBazooka) + SpawnAmmoCrate(2223, 967, amGrenade) + SpawnAmmoCrate(1437, 371, amShotgun) + end + cratesSpawned[index] = true +end + +-----------------------------Events------------------------------------ + +function CheckWaveDead(index) + for i = (index - 1) * 4 + 1, index * 4 do + if cannibalDead[i] ~= true then + return false + end + end + return true +end + +function DoWaveDead(index) + SetGearMessage(CurrentHedgehog, 0) + SetState(CurrentHedgehog, 0) + if index == 1 then + AddAnim(wave2Anim) + AddFunction({func = AfterWave2Anim, args = {}}) + elseif index == 2 then + SetupFinalAnim() + AddAnim(finalAnim) + AddFunction({func = AfterFinalAnim, args = {}}) + end +end + + +-----------------------------Main Functions---------------------------- + +function onGameInit() + Seed = 1 + GameFlags = 0 + TurnTime = 60000 + CaseFreq = 0 + MinesNum = 0 + MinesTime = 3000 + Explosives = 2 + Delay = 10 + Map = "Hogville" + Theme = "Nature" + SuddenDeathTurns = 3000 + + AddHogs() + AnimInit() +end + +function onGameStart() + GetVariables() + SetupAmmo() + SetupPlace() + AnimationSetup() + SetupEvents() + AddAnim(startAnim) + AddFunction({func = AfterStartAnim, args = {}}) +end + +function onGameTick() + AnimUnWait() + if ShowAnimation() == false then + return + end + ExecuteAfterAnimations() + CheckEvents() +end + +function onGearDelete(gear) + if gear == dense then + denseDead = true + nativesNum = nativesNum - 1 + nativesDead[2] = true + if sdrmv == 1 then + freshDead = nil + else + freshDead = loc("Dense Cloud") + end + elseif gear == leaks then + leaksDead = true + nativesNum = nativesNum - 1 + nativesDead[1] = true + freshDead = loc("Leaks A Lot") + elseif gear == chief then + chiefDead = true + nativesNum = nativesNum - 1 + nativesDead[5] = true + freshDead = loc("Righteous Beard") + elseif gear == water then + waterDead = true + nativesNum = nativesNum - 1 + nativesDead[3] = true + freshDead = loc("Fiery Water") + elseif gear == buffalo then + buffaloDead = true + nativesNum = nativesNum - 1 + nativesDead[4] = true + freshDead = loc("Raging Buffalo") + else + for i = 1, 8 do + if gear == cannibals[i] then + cannibalDead[i] = true + end + end + end +end + +function onAmmoStoreInit() + SetAmmo(amDEagle, 9, 0, 0, 0) + SetAmmo(amSniperRifle, 4, 0, 0, 0) + SetAmmo(amFirePunch, 9, 0, 0, 0) + SetAmmo(amWhip, 9, 0, 0, 0) + SetAmmo(amBaseballBat, 9, 0, 0, 0) + SetAmmo(amHammer, 9, 0, 0, 0) + SetAmmo(amLandGun, 9, 0, 0, 0) + SetAmmo(amSnowball, 8, 0, 0, 0) + SetAmmo(amGirder, 4, 0, 0, 2) + SetAmmo(amParachute, 4, 0, 0, 2) + SetAmmo(amSwitch, 8, 0, 0, 2) + SetAmmo(amSkip, 8, 0, 0, 0) + SetAmmo(amRope, 5, 0, 0, 3) + SetAmmo(amBlowTorch, 3, 0, 0, 3) + SetAmmo(amPickHammer, 0, 0, 0, 3) + SetAmmo(amLowGravity, 0, 0, 0, 2) + SetAmmo(amDynamite, 0, 0, 0, 3) + SetAmmo(amBazooka, 0, 0, 0, 4) + SetAmmo(amGrenade, 0, 0, 0, 5) + SetAmmo(amMine, 0, 0, 0, 2) + SetAmmo(amMolotov, 0, 0, 0, 3) + SetAmmo(amFlamethrower, 0, 0, 0, 3) + SetAmmo(amShotgun, 0, 0, 0, 3) + SetAmmo(amTeleport, 0, 0, 0, 2) + SetAmmo(amFlamethrower, 0, 0, 0, 3) +end + +function onNewTurn() + if AnimInProgress() then + TurnTimeLeft = -1 + return + end + if freshDead ~= nil and GetHogTeamName(CurrentHedgehog) == loc("Natives") then + SetupHogDeadAnim(freshDead) + AddAnim(hogDeadAnim) + AddFunction({func = AfterHogDeadAnim, args = {}}) + end +end + +function onPrecise() + if GameTime > 2500 then + SetAnimSkip(true) + end +end + diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Missions/Campaign/CMakeLists.txt --- a/share/hedgewars/Data/Missions/Campaign/CMakeLists.txt Mon Aug 27 17:40:16 2012 +0200 +++ b/share/hedgewars/Data/Missions/Campaign/CMakeLists.txt Sun Sep 16 16:54:51 2012 +0200 @@ -1,3 +1,5 @@ +add_subdirectory("A Classic Fairytale") + file(GLOB Scripts *.lua) install(FILES diff -r ce6ead3327b2 -r c73fd8cfa7c0 share/hedgewars/Data/Scripts/Animate.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Scripts/Animate.lua Sun Sep 16 16:54:51 2012 +0200 @@ -0,0 +1,394 @@ +local animPos, lastx, lasty, jumpTypes, jumpTimes, moveDirs, jumpStarted +local backJumped, jTimer, awTime, globalWait, stageEvents, seNum, curEvent +local needtoDecrease +local AnimList, AnimListNum +local FunctionList, FunctionListNum +local skipFuncList +local skipping +--------------------------------Animation--------------------------------- +--------------------------(In-game cinematics)---------------------------- + +function AddSkipFunction(anim, func, args) + skipFuncList[anim] = {sfunc = func, sargs = args} +end + +function RemoveSkipFunction(anim) + skipFuncList[anim] = nil +end + +function SetAnimSkip(bool) + skipping = bool +end + +function AnimInProgress() + return AnimListNum ~= 0 +end + +function SkipAnimation(anim) + if skipFuncList[anim] == nil then + return + else + skipFuncList[anim].sfunc(unpack(skipFuncList[anim].sargs)) + end +end + +function AddFunction(element) + table.insert(FunctionList, element) + FunctionListNum = FunctionListNum + 1 +end + +function RemoveFunction() + table.remove(FunctionList, 1) + FunctionListNum = FunctionListNum - 1 +end + +function ExecuteAfterAnimations() + if FunctionListNum == 0 then + return + end + FunctionList[1].func(unpack(FunctionList[1].args)) + RemoveFunction() +end + +function AnimInit() + animPos = 1 + lastx = 0 + lasty = 0 + jumpTypes = {long = gmLJump, high = gmHJump, back = gmHJump} + jumpTimes = {long = 500, high = 500, back = 300, backback = 500} + moveDirs = {Right = gmRight, Left = gmLeft} + jumpStarted = false + backJumped = false + jTimer = 0 + awTime = 0 + globalWait = 0 + stageEvents = {} + seNum = 0 + curEvent = 0 + needToDecrease = 0 + AnimList = {} + AnimListNum = 0 + FunctionList = {} + FunctionListNum = 0 + skipping = false + skipFuncList = {} +end + +function AnimSwitchHog(gear) + --SetGearMessage(gear, 0) + --SetState(gear, 0) + SwitchHog(gear) + FollowGear(gear) + return true +end + +function AnimGiveState(gear, state) + SetState(gear, state) + return true +end + +function AnimRemoveState(gear, state) + SetState(gear, band(GetState(gear), bnot(state))) + return true +end + +function AnimGearWait(gear, time) + AnimWait(gear, time) + return true +end + +function AnimUnWait() + if globalWait > 0 then + globalWait = globalWait - 1 + end +end + +function AnimWait(gear, time) -- gear is for compatibility with Animate + globalWait = globalWait + time + return true +end + +function AnimWaitLeft() + return globalWait +end + +function AnimSay(gear, text, manner, time) + HogSay(gear, text, manner, 2) + if time ~= nil then + AnimWait(gear, time) + end + return true +end + +function AnimSound(gear, sound, time) + PlaySound(sound, gear) + AnimWait(gear, time) + return true +end + +function AnimTurn(gear, dir) + if dir == "Right" then + HogTurnLeft(gear, false) + else + HogTurnLeft(gear, true) + end + return true +end + +function AnimFollowGear(gear) + FollowGear(gear) + return true +end + +function AnimMove(gear, dir, posx, posy) + dirr = moveDirs[dir] + SetGearMessage(gear, dirr) + if GetX(gear) == posx or GetY(gear) == posy then + SetGearMessage(gear, 0) + lastx = GetX(gear) + lasty = GetY(gear) + return true + end + return false +end + +function AnimJump(gear, jumpType) + if jumpStarted == false then + lastx = GetX(gear) + lasty = GetY(gear) + backJumped = false + jumpStarted = true + SetGearMessage(gear, jumpTypes[jumpType]) + AnimGearWait(gear, jumpTimes[jumpType]) + elseif jumpType == "back" and backJumped == false then + backJumped = true + SetGearMessage(gear, jumpTypes[jumpType]) + AnimGearWait(gear, jumpTimes["backback"]) + else + curx = GetX(gear) + cury = GetY(gear) + if curx == lastx and cury == lasty then + jumpStarted = false + backJumped = false + AnimGearWait(gear, 100) + return true + else + lastx = curx + lasty = cury + AnimGearWait(gear, 100) + end + end + return false +end + +function AnimSetGearPosition(gear, destX, destY, fall) + SetGearPosition(gear, destX, destY) + if fall ~= false then + SetGearVelocity(gear, 0, 10) + end + return true +end + +function AnimDisappear(gear, destX, destY) + AddVisualGear(GetX(gear)-5, GetY(gear)-5, vgtSmoke, 0, false) + AddVisualGear(GetX(gear)+5, GetY(gear)+5, vgtSmoke, 0, false) + AddVisualGear(GetX(gear)-5, GetY(gear)+5, vgtSmoke, 0, false) + AddVisualGear(GetX(gear)+5, GetY(gear)-5, vgtSmoke, 0, false) + PlaySound(sndExplosion) + AnimSetGearPosition(gear, destX, destY) + return true +end + +function AnimOutOfNowhere(gear, destX, destY) + AnimSetGearPosition(gear, destX, destY) + AddVisualGear(destX, destY, vgtBigExplosion, 0, false) + PlaySound(sndExplosion) + AnimGearWait(gear, 50) + return true +end + +function AnimTeleportGear(gear, destX, destY) + AddVisualGear(GetX(gear)-5, GetY(gear)-5, vgtSmoke, 0, false) + AddVisualGear(GetX(gear)+5, GetY(gear)+5, vgtSmoke, 0, false) + AddVisualGear(GetX(gear)-5, GetY(gear)+5, vgtSmoke, 0, false) + AddVisualGear(GetX(gear)+5, GetY(gear)-5, vgtSmoke, 0, false) + AnimSetGearPosition(gear, destX, destY) + AddVisualGear(GetX(gear), GetY(gear), vgtBigExplosion, 0, false) + PlaySound(sndExplosion) + FollowGear(gear) + AnimGearWait(gear, 50) + return true +end + +function AnimVisualGear(gear, x, y, vgType, state, critical, follow) + local vgear = AddVisualGear(x, y, vgType, state, critical) + if follow == true then + FollowGear(vgear) + end + return true +end + +function AnimCaption(gear, text, time) + AddCaption(text) + if time == nil then + return true + end + AnimWait(gear, time) + return true +end + +function AnimCustomFunction(gear, func, args) + if args == nil then + args = {} + end + retval = func(unpack(args)) + if retval == false then + return false + else + return true + end +end + +function AnimInsertStepNext(step) + table.insert(AnimList[1], animPos + 1, step) + return true +end + +function AnimShowMission(gear, caption, subcaption, text, icon, time) + ShowMission(caption, subcaption, text, icon, time) + return true +end + +function RemoveAnim() + table.remove(AnimList, 1) + AnimListNum = AnimListNum - 1 +end + +function AddAnim(animation) + table.insert(AnimList, animation) + AnimListNum = AnimListNum + 1 + if AnimListNum == 1 then + skipping = false + end +end + +function ShowAnimation() + if AnimListNum == 0 then + skipping = false + return true + else + TurnTimeLeft = -1 + if Animate(AnimList[1]) == true then + RemoveAnim() + end + end + return false +end + +function Animate(steps) + if skipping == true then + animPos = 1 + SetInputMask(0xFFFFFFFF) + SkipAnimation(steps) + return true + end + + if globalWait ~= 0 then + return false + end + + if steps[animPos] == nil then + animPos = 1 + SetInputMask(0xFFFFFFFF) + return true + end + + if steps[animPos].args[1] ~= CurrentHedgehog and steps[animPos].func ~= AnimWait + and (steps[animPos].swh == nil or steps[animPos].swh == true) then + AnimSwitchHog(steps[animPos].args[1]) + end + + SetInputMask(band(0xFFFFFFFF, bnot(gmAnimate+gmAttack+gmDown+gmHJump+gmLeft+gmLJump+gmRight+gmSlot+gmSwitch+gmTimer+gmUp+gmWeapon))) + retVal = steps[animPos].func(unpack(steps[animPos].args)) + if (retVal ~= false) then + animPos = animPos + 1 + end + + return false +end + +------------------------------Event Handling------------------------------ + +function AddEvent(condFunc, condArgs, doFunc, doArgs, evType) + seNum = seNum + 1 + stageEvents[seNum] = {} + stageEvents[seNum].cFunc = condFunc + stageEvents[seNum].cArgs = condArgs + stageEvents[seNum].dFunc = doFunc + stageEvents[seNum].dArgs = doArgs + stageEvents[seNum].evType = evType +end + +function AddNewEvent(condFunc, condArgs, doFunc, doArgs, evType) + local i + for i = 1, seNum do + if stageEvents[i].cFunc == condFunc and stageEvents[i].cArgs == condArgs and + stageEvents[i].dFunc == doFunc and stageEvents[i].dArgs == doArgs and + stageEvents[seNum].evType == evType then + return + end + end + AddEvent(condFunc, condArgs, doFunc, doArgs, evType) +end + +function RemoveEvent(evNum) + if stageEvents[evNum] ~= nil then + seNum = seNum - 1 + table.remove(stageEvents, evNum) + if evNum < curEvent then + return true + end + end + if evNum < curEvent then + needToDecrease = needToDecrease + 1 + end +end + +function RemoveEventFunc(cFunc, cArgs) + local i = 1 + while i <= seNum do + if stageEvents[i].cFunc == cFunc and (cArgs == nil or cArgs == stageEvents[i].cArgs) then + RemoveEvent(i) + i = i - 1 + end + i = i + 1 + end +end + + +function CheckEvents() + local i = 1 + while i <= seNum do + curEvent = i + if stageEvents[i].cFunc(unpack(stageEvents[i].cArgs)) then + stageEvents[i].dFunc(unpack(stageEvents[i].dArgs)) + if needToDecrease > 0 then + i = i - needToDecrease + needToDecrease = 0 + end + if stageEvents[i].evType ~= 1 then + RemoveEvent(i) + i = i - 1 + end + end + i = i + 1 + end + curEvent = 0 +end + +-------------------------------------Misc--------------------------------- + +function StoppedGear(gear) + dx,dy = GetGearVelocity(gear) + return math.abs(dx) <= 1 and math.abs(dy) <= 1 +end diff -r ce6ead3327b2 -r c73fd8cfa7c0 tools/PascalParser.hs --- a/tools/PascalParser.hs Mon Aug 27 17:40:16 2012 +0200 +++ b/tools/PascalParser.hs Sun Sep 16 16:54:51 2012 +0200 @@ -438,7 +438,7 @@ return o ifBlock = do - try $ string "if" + try $ string "if" >> notFollowedBy (alphaNum <|> char '_') comments e <- expression comments