# HG changeset patch # User Medo # Date 1345243689 -7200 # Node ID 3c4b4cb40f402780ffe4122b750ef12b586d81aa # Parent 763d3961400b294e5d6f231f3a5bafbaba2b377a# Parent c7a21fc530de3f2a3fee55f3b22f55033e4c603d Merge diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/gameuiconfig.cpp --- a/QTfrontend/gameuiconfig.cpp Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/gameuiconfig.cpp Sat Aug 18 00:48:09 2012 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include "gameuiconfig.h" #include "hwform.h" @@ -30,6 +31,7 @@ #include "hwconsts.h" #include "fpsedit.h" #include "HWApplication.h" +#include "DataManager.h" GameUIConfig::GameUIConfig(HWForm * FormWidgets, const QString & fileName) : QSettings(fileName, QSettings::IniFormat) @@ -108,6 +110,12 @@ depth = HWApplication::desktop()->depth(); if (depth < 16) depth = 16; else if (depth > 16) depth = 32; + + { // load colors + QStandardItemModel * model = DataManager::instance().colorsModel(); + for(int i = model->rowCount() - 1; i >= 0; --i) + model->item(i)->setData(QColor(value(QString("colors/color%1").arg(i), model->item(i)->data().value()).value())); + } } QStringList GameUIConfig::GetTeamsList() @@ -182,6 +190,13 @@ #ifdef SPARKLE_ENABLED setValue("misc/autoUpdate", isAutoUpdateEnabled()); #endif + + { // save colors + QStandardItemModel * model = DataManager::instance().colorsModel(); + for(int i = model->rowCount() - 1; i >= 0; --i) + setValue(QString("colors/color%1").arg(i), model->item(i)->data()); + } + Form->gameSettings->sync(); } diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/net/newnetclient.cpp --- a/QTfrontend/net/newnetclient.cpp Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/net/newnetclient.cpp Sat Aug 18 00:48:09 2012 +0200 @@ -384,38 +384,6 @@ return; } - if (lst[0] == "ADD_TEAM") - { - if(lst.size() != 24) - { - qWarning("Net: Bad ADDTEAM message"); - return; - } - QStringList tmp = lst; - tmp.removeFirst(); - emit AddNetTeam(tmp); - return; - } - - if (lst[0] == "REMOVE_TEAM") - { - if(lst.size() != 2) - { - qWarning("Net: Bad REMOVETEAM message"); - return; - } - emit RemoveNetTeam(HWTeam(lst[1])); - return; - } - - if(lst[0] == "ROOMABANDONED") - { - netClientState = InLobby; - askRoomsList(); - emit LeftRoom(tr("Room destroyed")); - return; - } - if(lst[0] == "KICKED") { netClientState = InLobby; @@ -424,31 +392,6 @@ return; } - if(lst[0] == "JOINED") - { - if(lst.size() < 2) - { - qWarning("Net: Bad JOINED message"); - return; - } - - for(int i = 1; i < lst.size(); ++i) - { - if (lst[i] == mynick) - { - netClientState = InRoom; - emit EnteredGame(); - emit roomMaster(isChief); - if (isChief) - emit configAsked(); - } - - emit nickAdded(lst[i], isChief && (lst[i] != mynick)); - emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i])); - } - return; - } - if(lst[0] == "LOBBY:JOINED") { if(lst.size() < 2) @@ -472,21 +415,6 @@ return; } - if(lst[0] == "LEFT") - { - if(lst.size() < 2) - { - qWarning("Net: Bad LEFT message"); - return; - } - emit nickRemoved(lst[1]); - if (lst.size() < 3) - emit chatStringFromNet(tr("%1 *** %2 has left").arg('\x03').arg(lst[1])); - else - emit chatStringFromNet(tr("%1 *** %2 has left (%3)").arg('\x03').arg(lst[1], lst[2])); - return; - } - if(lst[0] == "ROOM" && lst.size() == 10 && lst[1] == "ADD") { QStringList tmp = lst; @@ -529,13 +457,6 @@ return; } - if (lst[0] == "RUN_GAME") - { - netClientState = InGame; - emit AskForRunGame(); - return; - } - if (lst[0] == "ASKPASSWORD") { emit AskForPassword(mynick); @@ -563,76 +484,6 @@ return; } - if (lst[0] == "TEAM_ACCEPTED") - { - if (lst.size() != 2) - { - qWarning("Net: Bad TEAM_ACCEPTED message"); - return; - } - emit TeamAccepted(lst[1]); - return; - } - - - if (lst[0] == "CFG") - { - if(lst.size() < 3) - { - qWarning("Net: Bad CFG message"); - return; - } - QStringList tmp = lst; - tmp.removeFirst(); - tmp.removeFirst(); - if (lst[1] == "SCHEME") - emit netSchemeConfig(tmp); - else - emit paramChanged(lst[1], tmp); - return; - } - - if (lst[0] == "HH_NUM") - { - if (lst.size() != 3) - { - qWarning("Net: Bad TEAM_ACCEPTED message"); - return; - } - HWTeam tmptm(lst[1]); - tmptm.setNumHedgehogs(lst[2].toUInt()); - emit hhnumChanged(tmptm); - return; - } - - if (lst[0] == "TEAM_COLOR") - { - if (lst.size() != 3) - { - qWarning("Net: Bad TEAM_COLOR message"); - return; - } - HWTeam tmptm(lst[1]); - tmptm.setColor(lst[2].toInt()); - emit teamColorChanged(tmptm); - return; - } - - if (lst[0] == "EM") - { - if(lst.size() < 2) - { - qWarning("Net: Bad EM message"); - return; - } - for(int i = 1; i < lst.size(); ++i) - { - QByteArray em = QByteArray::fromBase64(lst[i].toAscii()); - emit FromNet(em); - } - return; - } - if (lst[0] == "BYE") { if (lst.size() < 2) @@ -650,26 +501,192 @@ return; } - if (lst[0] == "ADMIN_ACCESS") { emit adminAccess(true); return; } - if (lst[0] == "ROOM_CONTROL_ACCESS") + if(netClientState == InLobby && lst[0] == "JOINED") { - if (lst.size() < 2) + if(lst.size() < 2 || lst[1] != mynick) { - qWarning("Net: Bad ROOM_CONTROL_ACCESS message"); + qWarning("Net: Bad JOINED message"); return; } - isChief = (lst[1] != "0"); - emit roomMaster(isChief); + + for(int i = 1; i < lst.size(); ++i) + { + if (lst[i] == mynick) + { + netClientState = InRoom; + emit EnteredGame(); + emit roomMaster(isChief); + if (isChief) + emit configAsked(); + } + + emit nickAdded(lst[i], isChief && (lst[i] != mynick)); + emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i])); + } return; } - qWarning() << "Net: Unknown message:" << lst; + if(netClientState == InRoom || netClientState == InGame) + { + if (lst[0] == "EM") + { + if(lst.size() < 2) + { + qWarning("Net: Bad EM message"); + return; + } + for(int i = 1; i < lst.size(); ++i) + { + QByteArray em = QByteArray::fromBase64(lst[i].toAscii()); + emit FromNet(em); + } + return; + } + + if (lst[0] == "ADD_TEAM") + { + if(lst.size() != 24) + { + qWarning("Net: Bad ADDTEAM message"); + return; + } + QStringList tmp = lst; + tmp.removeFirst(); + emit AddNetTeam(tmp); + return; + } + + if (lst[0] == "REMOVE_TEAM") + { + if(lst.size() != 2) + { + qWarning("Net: Bad REMOVETEAM message"); + return; + } + emit RemoveNetTeam(HWTeam(lst[1])); + return; + } + + if(lst[0] == "ROOMABANDONED") + { + netClientState = InLobby; + askRoomsList(); + emit LeftRoom(tr("Room destroyed")); + return; + } + + if (lst[0] == "RUN_GAME") + { + netClientState = InGame; + emit AskForRunGame(); + return; + } + + if (lst[0] == "TEAM_ACCEPTED") + { + if (lst.size() != 2) + { + qWarning("Net: Bad TEAM_ACCEPTED message"); + return; + } + emit TeamAccepted(lst[1]); + return; + } + + if (lst[0] == "CFG") + { + if(lst.size() < 3) + { + qWarning("Net: Bad CFG message"); + return; + } + QStringList tmp = lst; + tmp.removeFirst(); + tmp.removeFirst(); + if (lst[1] == "SCHEME") + emit netSchemeConfig(tmp); + else + emit paramChanged(lst[1], tmp); + return; + } + + if (lst[0] == "HH_NUM") + { + if (lst.size() != 3) + { + qWarning("Net: Bad TEAM_ACCEPTED message"); + return; + } + HWTeam tmptm(lst[1]); + tmptm.setNumHedgehogs(lst[2].toUInt()); + emit hhnumChanged(tmptm); + return; + } + + if (lst[0] == "TEAM_COLOR") + { + if (lst.size() != 3) + { + qWarning("Net: Bad TEAM_COLOR message"); + return; + } + HWTeam tmptm(lst[1]); + tmptm.setColor(lst[2].toInt()); + emit teamColorChanged(tmptm); + return; + } + + if(lst[0] == "JOINED") + { + if(lst.size() < 2) + { + qWarning("Net: Bad JOINED message"); + return; + } + + for(int i = 1; i < lst.size(); ++i) + { + emit nickAdded(lst[i], isChief && (lst[i] != mynick)); + emit chatStringFromNet(tr("%1 *** %2 has joined the room").arg('\x03').arg(lst[i])); + } + return; + } + + if(lst[0] == "LEFT") + { + if(lst.size() < 2) + { + qWarning("Net: Bad LEFT message"); + return; + } + emit nickRemoved(lst[1]); + if (lst.size() < 3) + emit chatStringFromNet(tr("%1 *** %2 has left").arg('\x03').arg(lst[1])); + else + emit chatStringFromNet(tr("%1 *** %2 has left (%3)").arg('\x03').arg(lst[1], lst[2])); + return; + } + + if (lst[0] == "ROOM_CONTROL_ACCESS") + { + if (lst.size() < 2) + { + qWarning("Net: Bad ROOM_CONTROL_ACCESS message"); + return; + } + isChief = (lst[1] != "0"); + emit roomMaster(isChief); + return; + } + } + + qWarning() << "Net: Unknown message or wrong state:" << lst; } void HWNewNet::onHedgehogsNumChanged(const HWTeam& team) diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/ui/page/pageeditteam.cpp --- a/QTfrontend/ui/page/pageeditteam.cpp Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/ui/page/pageeditteam.cpp Sat Aug 18 00:48:09 2012 +0200 @@ -289,6 +289,9 @@ int idx = list.indexOf("cpu.png"); if (idx >= 0) list.removeAt(idx); + idx = list.indexOf("cpu_plain.png"); + if (idx >= 0) + list.removeAt(idx); idx = list.indexOf("hedgewars.png"); if (idx >= 0) list.removeAt(idx); diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/ui/page/pageoptions.cpp --- a/QTfrontend/ui/page/pageoptions.cpp Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/ui/page/pageoptions.cpp Sat Aug 18 00:48:09 2012 +0200 @@ -28,368 +28,397 @@ #include #include #include +#include +#include +#include #include "pageoptions.h" #include "hwconsts.h" #include "fpsedit.h" #include "igbox.h" +#include "DataManager.h" // TODO cleanup QLayout * PageOptions::bodyLayoutDefinition() { - QGridLayout * pageLayout = new QGridLayout(); - pageLayout->setColumnStretch(0, 100); - pageLayout->setColumnStretch(1, 100); - pageLayout->setColumnStretch(2, 100); - pageLayout->setRowStretch(0, 0); - //pageLayout->setRowStretch(1, 100); - pageLayout->setRowStretch(2, 0); - pageLayout->setContentsMargins(7, 7, 7, 0); - pageLayout->setSpacing(0); + QVBoxLayout * pageLayout = new QVBoxLayout(); + QTabWidget * tabs = new QTabWidget(this); + pageLayout->addWidget(tabs); + QWidget * page1 = new QWidget(this); + QWidget * page2 = new QWidget(this); + tabs->addTab(page1, tr("General")); + tabs->addTab(page2, tr("Advanced")); + + { // page 1 + QGridLayout * page1Layout = new QGridLayout(page1); + //gbTBLayout->setMargin(0); + page1Layout->setSpacing(0); + page1Layout->setAlignment(Qt::AlignTop | Qt::AlignLeft); - QGroupBox * gbTwoBoxes = new QGroupBox(this); - pageLayout->addWidget(gbTwoBoxes, 0, 0, 1, 3); - QGridLayout * gbTBLayout = new QGridLayout(gbTwoBoxes); - gbTBLayout->setMargin(0); - gbTBLayout->setSpacing(0); - gbTBLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft); - - QPixmap pmNew(":/res/new.png"); - QPixmap pmEdit(":/res/edit.png"); - QPixmap pmDelete(":/res/delete.png"); + QPixmap pmNew(":/res/new.png"); + QPixmap pmEdit(":/res/edit.png"); + QPixmap pmDelete(":/res/delete.png"); - { - teamsBox = new IconedGroupBox(this); - //teamsBox->setContentTopPadding(0); - //teamsBox->setAttribute(Qt::WA_PaintOnScreen, true); - teamsBox->setIcon(QIcon(":/res/teamicon.png")); - teamsBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - teamsBox->setTitle(QGroupBox::tr("Teams")); + { + teamsBox = new IconedGroupBox(this); + //teamsBox->setContentTopPadding(0); + //teamsBox->setAttribute(Qt::WA_PaintOnScreen, true); + teamsBox->setIcon(QIcon(":/res/teamicon.png")); + teamsBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + teamsBox->setTitle(QGroupBox::tr("Teams")); - QGridLayout * GBTlayout = new QGridLayout(teamsBox); + QGridLayout * GBTlayout = new QGridLayout(teamsBox); - CBTeamName = new QComboBox(teamsBox); - GBTlayout->addWidget(CBTeamName, 0, 0); + CBTeamName = new QComboBox(teamsBox); + GBTlayout->addWidget(CBTeamName, 0, 0); - BtnNewTeam = new QPushButton(teamsBox); - BtnNewTeam->setToolTip(tr("New team")); - BtnNewTeam->setIconSize(pmNew.size()); - BtnNewTeam->setIcon(pmNew); - BtnNewTeam->setMaximumWidth(pmNew.width() + 6); - connect(BtnNewTeam, SIGNAL(clicked()), this, SIGNAL(newTeamRequested())); - GBTlayout->addWidget(BtnNewTeam, 0, 1); + BtnNewTeam = new QPushButton(teamsBox); + BtnNewTeam->setToolTip(tr("New team")); + BtnNewTeam->setIconSize(pmNew.size()); + BtnNewTeam->setIcon(pmNew); + BtnNewTeam->setMaximumWidth(pmNew.width() + 6); + connect(BtnNewTeam, SIGNAL(clicked()), this, SIGNAL(newTeamRequested())); + GBTlayout->addWidget(BtnNewTeam, 0, 1); - BtnEditTeam = new QPushButton(teamsBox); - BtnEditTeam->setToolTip(tr("Edit team")); - BtnEditTeam->setIconSize(pmEdit.size()); - BtnEditTeam->setIcon(pmEdit); - BtnEditTeam->setMaximumWidth(pmEdit.width() + 6); - connect(BtnEditTeam, SIGNAL(clicked()), this, SLOT(requestEditSelectedTeam())); - GBTlayout->addWidget(BtnEditTeam, 0, 2); + BtnEditTeam = new QPushButton(teamsBox); + BtnEditTeam->setToolTip(tr("Edit team")); + BtnEditTeam->setIconSize(pmEdit.size()); + BtnEditTeam->setIcon(pmEdit); + BtnEditTeam->setMaximumWidth(pmEdit.width() + 6); + connect(BtnEditTeam, SIGNAL(clicked()), this, SLOT(requestEditSelectedTeam())); + GBTlayout->addWidget(BtnEditTeam, 0, 2); - BtnDeleteTeam = new QPushButton(teamsBox); - BtnDeleteTeam->setToolTip(tr("Delete team")); - BtnDeleteTeam->setIconSize(pmDelete.size()); - BtnDeleteTeam->setIcon(pmDelete); - BtnDeleteTeam->setMaximumWidth(pmDelete.width() + 6); - connect(BtnDeleteTeam, SIGNAL(clicked()), this, SLOT(requestDeleteSelectedTeam())); - GBTlayout->addWidget(BtnDeleteTeam, 0, 3); - - LblNoEditTeam = new QLabel(teamsBox); - LblNoEditTeam->setText(tr("You can't edit teams from team selection. Go back to main menu to add, edit or delete teams.")); - LblNoEditTeam->setWordWrap(true); - LblNoEditTeam->setVisible(false); - GBTlayout->addWidget(LblNoEditTeam, 0, 0); + BtnDeleteTeam = new QPushButton(teamsBox); + BtnDeleteTeam->setToolTip(tr("Delete team")); + BtnDeleteTeam->setIconSize(pmDelete.size()); + BtnDeleteTeam->setIcon(pmDelete); + BtnDeleteTeam->setMaximumWidth(pmDelete.width() + 6); + connect(BtnDeleteTeam, SIGNAL(clicked()), this, SLOT(requestDeleteSelectedTeam())); + GBTlayout->addWidget(BtnDeleteTeam, 0, 3); - gbTBLayout->addWidget(teamsBox, 0, 0); - } - - { - IconedGroupBox* groupWeapons = new IconedGroupBox(this); + LblNoEditTeam = new QLabel(teamsBox); + LblNoEditTeam->setText(tr("You can't edit teams from team selection. Go back to main menu to add, edit or delete teams.")); + LblNoEditTeam->setWordWrap(true); + LblNoEditTeam->setVisible(false); + GBTlayout->addWidget(LblNoEditTeam, 0, 0); - //groupWeapons->setContentTopPadding(0); - //groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - groupWeapons->setIcon(QIcon(":/res/weaponsicon.png")); - groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - groupWeapons->setTitle(QGroupBox::tr("Schemes and Weapons")); - QGridLayout * WeaponsLayout = new QGridLayout(groupWeapons); + page1Layout->addWidget(teamsBox, 0, 0); + } - QLabel* SchemeLabel = new QLabel(groupWeapons); - SchemeLabel->setText(QLabel::tr("Game scheme")); - WeaponsLayout->addWidget(SchemeLabel, 1, 0); + { + IconedGroupBox* groupWeapons = new IconedGroupBox(this); - SchemesName = new QComboBox(groupWeapons); - WeaponsLayout->addWidget(SchemesName, 1, 1); + //groupWeapons->setContentTopPadding(0); + //groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + groupWeapons->setIcon(QIcon(":/res/weaponsicon.png")); + groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + groupWeapons->setTitle(QGroupBox::tr("Schemes and Weapons")); + QGridLayout * WeaponsLayout = new QGridLayout(groupWeapons); - SchemeNew = new QPushButton(groupWeapons); - SchemeNew->setWhatsThis(tr("New scheme")); - SchemeNew->setIconSize(pmNew.size()); - SchemeNew->setIcon(pmNew); - SchemeNew->setMaximumWidth(pmNew.width() + 6); - WeaponsLayout->addWidget(SchemeNew, 1, 2); + QLabel* SchemeLabel = new QLabel(groupWeapons); + SchemeLabel->setText(QLabel::tr("Game scheme")); + WeaponsLayout->addWidget(SchemeLabel, 1, 0); - SchemeEdit = new QPushButton(groupWeapons); - SchemeEdit->setWhatsThis(tr("Edit scheme")); - SchemeEdit->setIconSize(pmEdit.size()); - SchemeEdit->setIcon(pmEdit); - SchemeEdit->setMaximumWidth(pmEdit.width() + 6); - WeaponsLayout->addWidget(SchemeEdit, 1, 3); + SchemesName = new QComboBox(groupWeapons); + WeaponsLayout->addWidget(SchemesName, 1, 1); - SchemeDelete = new QPushButton(groupWeapons); - SchemeDelete->setWhatsThis(tr("Delete scheme")); - SchemeDelete->setIconSize(pmDelete.size()); - SchemeDelete->setIcon(pmDelete); - SchemeDelete->setMaximumWidth(pmDelete.width() + 6); - WeaponsLayout->addWidget(SchemeDelete, 1, 4); + SchemeNew = new QPushButton(groupWeapons); + SchemeNew->setWhatsThis(tr("New scheme")); + SchemeNew->setIconSize(pmNew.size()); + SchemeNew->setIcon(pmNew); + SchemeNew->setMaximumWidth(pmNew.width() + 6); + WeaponsLayout->addWidget(SchemeNew, 1, 2); - QLabel* WeaponLabel = new QLabel(groupWeapons); - WeaponLabel->setText(QLabel::tr("Weapons")); - WeaponsLayout->addWidget(WeaponLabel, 2, 0); - - WeaponsName = new QComboBox(groupWeapons); - WeaponsLayout->addWidget(WeaponsName, 2, 1); - - WeaponNew = new QPushButton(groupWeapons); - WeaponNew->setWhatsThis(tr("New weapon set")); - WeaponNew->setIconSize(pmNew.size()); - WeaponNew->setIcon(pmNew); - WeaponNew->setMaximumWidth(pmNew.width() + 6); - WeaponsLayout->addWidget(WeaponNew, 2, 2); + SchemeEdit = new QPushButton(groupWeapons); + SchemeEdit->setWhatsThis(tr("Edit scheme")); + SchemeEdit->setIconSize(pmEdit.size()); + SchemeEdit->setIcon(pmEdit); + SchemeEdit->setMaximumWidth(pmEdit.width() + 6); + WeaponsLayout->addWidget(SchemeEdit, 1, 3); - WeaponEdit = new QPushButton(groupWeapons); - WeaponEdit->setWhatsThis(tr("Edit weapon set")); - WeaponEdit->setIconSize(pmEdit.size()); - WeaponEdit->setIcon(pmEdit); - WeaponEdit->setMaximumWidth(pmEdit.width() + 6); - WeaponsLayout->addWidget(WeaponEdit, 2, 3); + SchemeDelete = new QPushButton(groupWeapons); + SchemeDelete->setWhatsThis(tr("Delete scheme")); + SchemeDelete->setIconSize(pmDelete.size()); + SchemeDelete->setIcon(pmDelete); + SchemeDelete->setMaximumWidth(pmDelete.width() + 6); + WeaponsLayout->addWidget(SchemeDelete, 1, 4); - WeaponDelete = new QPushButton(groupWeapons); - WeaponDelete->setWhatsThis(tr("Delete weapon set")); - WeaponDelete->setIconSize(pmDelete.size()); - WeaponDelete->setIcon(pmDelete); - WeaponDelete->setMaximumWidth(pmDelete.width() + 6); - WeaponsLayout->addWidget(WeaponDelete, 2, 4); + QLabel* WeaponLabel = new QLabel(groupWeapons); + WeaponLabel->setText(QLabel::tr("Weapons")); + WeaponsLayout->addWidget(WeaponLabel, 2, 0); - WeaponTooltip = new QCheckBox(this); - WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips")); - WeaponsLayout->addWidget(WeaponTooltip, 3, 0, 1, 4); - - gbTBLayout->addWidget(groupWeapons, 1, 0); - } + WeaponsName = new QComboBox(groupWeapons); + WeaponsLayout->addWidget(WeaponsName, 2, 1); - { - IconedGroupBox* groupMisc = new IconedGroupBox(this); - //groupMisc->setContentTopPadding(0); - groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); - groupMisc->setIcon(QIcon(":/res/miscicon.png")); - //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - groupMisc->setTitle(QGroupBox::tr("Misc")); - QGridLayout * MiscLayout = new QGridLayout(groupMisc); + WeaponNew = new QPushButton(groupWeapons); + WeaponNew->setWhatsThis(tr("New weapon set")); + WeaponNew->setIconSize(pmNew.size()); + WeaponNew->setIcon(pmNew); + WeaponNew->setMaximumWidth(pmNew.width() + 6); + WeaponsLayout->addWidget(WeaponNew, 2, 2); - // Label for "Language" - QLabel *labelLanguage = new QLabel(groupMisc); - labelLanguage->setText(QLabel::tr("Locale") + " *"); - MiscLayout->addWidget(labelLanguage, 0, 0); + WeaponEdit = new QPushButton(groupWeapons); + WeaponEdit->setWhatsThis(tr("Edit weapon set")); + WeaponEdit->setIconSize(pmEdit.size()); + WeaponEdit->setIcon(pmEdit); + WeaponEdit->setMaximumWidth(pmEdit.width() + 6); + WeaponsLayout->addWidget(WeaponEdit, 2, 3); - // List of installed languages - CBLanguage = new QComboBox(groupMisc); - QDir tmpdir; - tmpdir.cd(cfgdir->absolutePath()); - tmpdir.cd("Data/Locale"); - tmpdir.setFilter(QDir::Files); - QStringList locs = tmpdir.entryList(QStringList("hedgewars_*.qm")); - CBLanguage->addItem(QComboBox::tr("(System default)"), QString("")); - for(int i = 0; i < locs.count(); i++) - { - QLocale loc(locs[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1")); - CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name()); + WeaponDelete = new QPushButton(groupWeapons); + WeaponDelete->setWhatsThis(tr("Delete weapon set")); + WeaponDelete->setIconSize(pmDelete.size()); + WeaponDelete->setIcon(pmDelete); + 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); } - tmpdir.cd(datadir->absolutePath()); - tmpdir.cd("Locale"); - tmpdir.setFilter(QDir::Files); - QStringList tmplist = tmpdir.entryList(QStringList("hedgewars_*.qm")); - for(int i = 0; i < tmplist.count(); i++) { - if (locs.contains(tmplist[i])) continue; - QLocale loc(tmplist[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1")); - CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name()); + IconedGroupBox* groupMisc = new IconedGroupBox(this); + //groupMisc->setContentTopPadding(0); + groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); + groupMisc->setIcon(QIcon(":/res/miscicon.png")); + //groupMisc->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + groupMisc->setTitle(QGroupBox::tr("Misc")); + QGridLayout * MiscLayout = new QGridLayout(groupMisc); + + // Label for "Language" + QLabel *labelLanguage = new QLabel(groupMisc); + labelLanguage->setText(QLabel::tr("Locale") + " *"); + MiscLayout->addWidget(labelLanguage, 0, 0); + + // List of installed languages + CBLanguage = new QComboBox(groupMisc); + QDir tmpdir; + tmpdir.cd(cfgdir->absolutePath()); + tmpdir.cd("Data/Locale"); + tmpdir.setFilter(QDir::Files); + QStringList locs = tmpdir.entryList(QStringList("hedgewars_*.qm")); + CBLanguage->addItem(QComboBox::tr("(System default)"), QString("")); + for(int i = 0; i < locs.count(); i++) + { + QLocale loc(locs[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1")); + CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name()); + } + + tmpdir.cd(datadir->absolutePath()); + tmpdir.cd("Locale"); + tmpdir.setFilter(QDir::Files); + QStringList tmplist = tmpdir.entryList(QStringList("hedgewars_*.qm")); + for(int i = 0; i < tmplist.count(); i++) + { + if (locs.contains(tmplist[i])) continue; + QLocale loc(tmplist[i].replace(QRegExp("hedgewars_(.*)\\.qm"), "\\1")); + CBLanguage->addItem(QLocale::languageToString(loc.language()) + " (" + QLocale::countryToString(loc.country()) + ")", loc.name()); + } + + MiscLayout->addWidget(CBLanguage, 0, 1); + + // Label and field for net nick + labelNN = new QLabel(groupMisc); + labelNN->setText(QLabel::tr("Nickname")); + MiscLayout->addWidget(labelNN, 1, 0); + + editNetNick = new QLineEdit(groupMisc); + editNetNick->setMaxLength(20); + editNetNick->setText(QLineEdit::tr("anonymous")); + MiscLayout->addWidget(editNetNick, 1, 1); + + // checkbox and field for password + CBSavePassword = new QCheckBox(groupMisc); + CBSavePassword->setText(QCheckBox::tr("Save password")); + MiscLayout->addWidget(CBSavePassword, 2, 0); + + editNetPassword = new QLineEdit(groupMisc); + 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); + CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup")); + MiscLayout->addWidget(CBAutoUpdate, 7, 0, 1, 3); + #endif + #endif + page1Layout->addWidget(groupMisc, 2, 0); } - MiscLayout->addWidget(CBLanguage, 0, 1); + { + AGGroupBox = new IconedGroupBox(this); + //AGGroupBox->setContentTopPadding(0); + AGGroupBox->setIcon(QIcon(":/res/graphicsicon.png")); + //AGGroupBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + AGGroupBox->setTitle(QGroupBox::tr("Audio/Graphic options")); + + QVBoxLayout * GBAlayout = new QVBoxLayout(AGGroupBox); + QHBoxLayout * GBAreslayout = new QHBoxLayout(0); + QHBoxLayout * GBAstereolayout = new QHBoxLayout(0); + QHBoxLayout * GBAqualayout = new QHBoxLayout(0); - // Label and field for net nick - labelNN = new QLabel(groupMisc); - labelNN->setText(QLabel::tr("Nickname")); - MiscLayout->addWidget(labelNN, 1, 0); + CBFrontendFullscreen = new QCheckBox(AGGroupBox); + CBFrontendFullscreen->setText(QCheckBox::tr("Frontend fullscreen")); + GBAlayout->addWidget(CBFrontendFullscreen); + + CBFrontendEffects = new QCheckBox(AGGroupBox); + CBFrontendEffects->setText(QCheckBox::tr("Frontend effects")); + GBAlayout->addWidget(CBFrontendEffects); + + CBEnableFrontendSound = new QCheckBox(AGGroupBox); + CBEnableFrontendSound->setText(QCheckBox::tr("Enable frontend sounds")); + GBAlayout->addWidget(CBEnableFrontendSound); + + CBEnableFrontendMusic = new QCheckBox(AGGroupBox); + CBEnableFrontendMusic->setText(QCheckBox::tr("Enable frontend music")); + GBAlayout->addWidget(CBEnableFrontendMusic); - editNetNick = new QLineEdit(groupMisc); - editNetNick->setMaxLength(20); - editNetNick->setText(QLineEdit::tr("anonymous")); - MiscLayout->addWidget(editNetNick, 1, 1); + QFrame * hr = new QFrame(AGGroupBox); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + GBAlayout->addWidget(hr); + + QLabel * resolution = new QLabel(AGGroupBox); + resolution->setText(QLabel::tr("Resolution")); + GBAreslayout->addWidget(resolution); + + CBResolution = new QComboBox(AGGroupBox); + GBAreslayout->addWidget(CBResolution); + GBAlayout->addLayout(GBAreslayout); - // checkbox and field for password - CBSavePassword = new QCheckBox(groupMisc); - CBSavePassword->setText(QCheckBox::tr("Save password")); - MiscLayout->addWidget(CBSavePassword, 2, 0); + CBFullscreen = new QCheckBox(AGGroupBox); + CBFullscreen->setText(QCheckBox::tr("Fullscreen")); + GBAreslayout->addWidget(CBFullscreen); + + QLabel * quality = new QLabel(AGGroupBox); + quality->setText(QLabel::tr("Quality")); + quality->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + GBAqualayout->addWidget(quality); + + SLQuality = new QSlider(Qt::Horizontal, AGGroupBox); + SLQuality->setTickPosition(QSlider::TicksBelow); + SLQuality->setMaximum(5); + SLQuality->setMinimum(0); + SLQuality->setFixedWidth(150); + GBAqualayout->addWidget(SLQuality); + GBAlayout->addLayout(GBAqualayout); + + QLabel * stereo = new QLabel(AGGroupBox); + stereo->setText(QLabel::tr("Stereo rendering")); + GBAstereolayout->addWidget(stereo); - editNetPassword = new QLineEdit(groupMisc); - editNetPassword->setEchoMode(QLineEdit::Password); - MiscLayout->addWidget(editNetPassword, 2, 1); + CBStereoMode = new QComboBox(AGGroupBox); + CBStereoMode->addItem(QComboBox::tr("Disabled")); + CBStereoMode->addItem(QComboBox::tr("Red/Cyan")); + CBStereoMode->addItem(QComboBox::tr("Cyan/Red")); + CBStereoMode->addItem(QComboBox::tr("Red/Blue")); + CBStereoMode->addItem(QComboBox::tr("Blue/Red")); + CBStereoMode->addItem(QComboBox::tr("Red/Green")); + CBStereoMode->addItem(QComboBox::tr("Green/Red")); + CBStereoMode->addItem(QComboBox::tr("Side-by-side")); + CBStereoMode->addItem(QComboBox::tr("Top-Bottom")); + CBStereoMode->addItem(QComboBox::tr("Wiggle")); + CBStereoMode->addItem(QComboBox::tr("Red/Cyan grayscale")); + CBStereoMode->addItem(QComboBox::tr("Cyan/Red grayscale")); + CBStereoMode->addItem(QComboBox::tr("Red/Blue grayscale")); + CBStereoMode->addItem(QComboBox::tr("Blue/Red grayscale")); + CBStereoMode->addItem(QComboBox::tr("Red/Green grayscale")); + CBStereoMode->addItem(QComboBox::tr("Green/Red grayscale")); - CBNameWithDate = new QCheckBox(groupMisc); - CBNameWithDate->setText(QCheckBox::tr("Append date and time to record file name")); - MiscLayout->addWidget(CBNameWithDate, 5, 0, 1, 2); + 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); - BtnAssociateFiles = new QPushButton(groupMisc); - BtnAssociateFiles->setText(QPushButton::tr("Associate file extensions")); - BtnAssociateFiles->setVisible(!custom_data && !custom_config); - MiscLayout->addWidget(BtnAssociateFiles, 6, 0, 1, 2); + hr = new QFrame(AGGroupBox); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + GBAlayout->addWidget(hr); + + QGridLayout * GBAvollayout = new QGridLayout(); + QLabel * vol = new QLabel(AGGroupBox); + vol->setText(QLabel::tr("Initial sound volume")); + GBAvollayout->addWidget(vol, 0, 0, 1, 2); + GBAlayout->addLayout(GBAvollayout); + volumeBox = new QSpinBox(AGGroupBox); + volumeBox->setRange(0, 100); + volumeBox->setSingleStep(5); + GBAvollayout->addWidget(volumeBox, 0, 2); -#ifdef __APPLE__ -#ifdef SPARKLE_ENABLED - CBAutoUpdate = new QCheckBox(groupMisc); - CBAutoUpdate->setText(QCheckBox::tr("Check for updates at startup")); - MiscLayout->addWidget(CBAutoUpdate, 7, 0, 1, 3); -#endif -#endif - gbTBLayout->addWidget(groupMisc, 2, 0); + CBEnableSound = new QCheckBox(AGGroupBox); + CBEnableSound->setText(QCheckBox::tr("Enable sound")); + GBAvollayout->addWidget(CBEnableSound, 1, 0, 1, 1); + + CBEnableMusic = new QCheckBox(AGGroupBox); + CBEnableMusic->setText(QCheckBox::tr("Enable music")); + GBAvollayout->addWidget(CBEnableMusic, 1, 1, 1, 2); + + GBAvollayout->setSizeConstraint(QLayout::SetMinimumSize); + + hr = new QFrame(AGGroupBox); + hr->setFrameStyle(QFrame::HLine); + hr->setLineWidth(3); + hr->setFixedHeight(10); + GBAlayout->addWidget(hr); + + CBAltDamage = new QCheckBox(AGGroupBox); + CBAltDamage->setText(QCheckBox::tr("Alternative damage show")); + GBAlayout->addWidget(CBAltDamage); + + page1Layout->addWidget(AGGroupBox, 0, 1, 3, 1); + } } - { - AGGroupBox = new IconedGroupBox(this); - //AGGroupBox->setContentTopPadding(0); - AGGroupBox->setIcon(QIcon(":/res/graphicsicon.png")); - //AGGroupBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - AGGroupBox->setTitle(QGroupBox::tr("Audio/Graphic options")); - - QVBoxLayout * GBAlayout = new QVBoxLayout(AGGroupBox); - QHBoxLayout * GBAreslayout = new QHBoxLayout(0); - QHBoxLayout * GBAstereolayout = new QHBoxLayout(0); - QHBoxLayout * GBAqualayout = new QHBoxLayout(0); - - CBFrontendFullscreen = new QCheckBox(AGGroupBox); - CBFrontendFullscreen->setText(QCheckBox::tr("Frontend fullscreen")); - GBAlayout->addWidget(CBFrontendFullscreen); - - CBFrontendEffects = new QCheckBox(AGGroupBox); - CBFrontendEffects->setText(QCheckBox::tr("Frontend effects")); - GBAlayout->addWidget(CBFrontendEffects); - - CBEnableFrontendSound = new QCheckBox(AGGroupBox); - CBEnableFrontendSound->setText(QCheckBox::tr("Enable frontend sounds")); - GBAlayout->addWidget(CBEnableFrontendSound); - - CBEnableFrontendMusic = new QCheckBox(AGGroupBox); - CBEnableFrontendMusic->setText(QCheckBox::tr("Enable frontend music")); - GBAlayout->addWidget(CBEnableFrontendMusic); + { // page 2 + QGridLayout * page2Layout = new QGridLayout(page2); - QFrame * hr = new QFrame(AGGroupBox); - hr->setFrameStyle(QFrame::HLine); - hr->setLineWidth(3); - hr->setFixedHeight(10); - GBAlayout->addWidget(hr); - - QLabel * resolution = new QLabel(AGGroupBox); - resolution->setText(QLabel::tr("Resolution")); - GBAreslayout->addWidget(resolution); - - CBResolution = new QComboBox(AGGroupBox); - GBAreslayout->addWidget(CBResolution); - GBAlayout->addLayout(GBAreslayout); + 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); - CBFullscreen = new QCheckBox(AGGroupBox); - CBFullscreen->setText(QCheckBox::tr("Fullscreen")); - GBAreslayout->addWidget(CBFullscreen); - - QLabel * quality = new QLabel(AGGroupBox); - quality->setText(QLabel::tr("Quality")); - quality->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - GBAqualayout->addWidget(quality); + QSignalMapper * mapper = new QSignalMapper(this); - SLQuality = new QSlider(Qt::Horizontal, AGGroupBox); - SLQuality->setTickPosition(QSlider::TicksBelow); - SLQuality->setMaximum(5); - SLQuality->setMinimum(0); - SLQuality->setFixedWidth(150); - GBAqualayout->addWidget(SLQuality); - GBAlayout->addLayout(GBAqualayout); - - QLabel * stereo = new QLabel(AGGroupBox); - stereo->setText(QLabel::tr("Stereo rendering")); - GBAstereolayout->addWidget(stereo); + QStandardItemModel * model = DataManager::instance().colorsModel(); - CBStereoMode = new QComboBox(AGGroupBox); - CBStereoMode->addItem(QComboBox::tr("Disabled")); - CBStereoMode->addItem(QComboBox::tr("Red/Cyan")); - CBStereoMode->addItem(QComboBox::tr("Cyan/Red")); - CBStereoMode->addItem(QComboBox::tr("Red/Blue")); - CBStereoMode->addItem(QComboBox::tr("Blue/Red")); - CBStereoMode->addItem(QComboBox::tr("Red/Green")); - CBStereoMode->addItem(QComboBox::tr("Green/Red")); - CBStereoMode->addItem(QComboBox::tr("Side-by-side")); - CBStereoMode->addItem(QComboBox::tr("Top-Bottom")); - CBStereoMode->addItem(QComboBox::tr("Wiggle")); - CBStereoMode->addItem(QComboBox::tr("Red/Cyan grayscale")); - CBStereoMode->addItem(QComboBox::tr("Cyan/Red grayscale")); - CBStereoMode->addItem(QComboBox::tr("Red/Blue grayscale")); - CBStereoMode->addItem(QComboBox::tr("Blue/Red grayscale")); - CBStereoMode->addItem(QComboBox::tr("Red/Green grayscale")); - CBStereoMode->addItem(QComboBox::tr("Green/Red grayscale")); - - 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); + connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(onColorModelDataChanged(QModelIndex,QModelIndex))); + for(int i = 0; i < model->rowCount(); ++i) + { + 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); + } - hr = new QFrame(AGGroupBox); - hr->setFrameStyle(QFrame::HLine); - hr->setLineWidth(3); - hr->setFixedHeight(10); - GBAlayout->addWidget(hr); - - QGridLayout * GBAvollayout = new QGridLayout(); - QLabel * vol = new QLabel(AGGroupBox); - vol->setText(QLabel::tr("Initial sound volume")); - GBAvollayout->addWidget(vol, 0, 0, 1, 2); - GBAlayout->addLayout(GBAvollayout); - volumeBox = new QSpinBox(AGGroupBox); - volumeBox->setRange(0, 100); - volumeBox->setSingleStep(5); - GBAvollayout->addWidget(volumeBox, 0, 2); - - CBEnableSound = new QCheckBox(AGGroupBox); - CBEnableSound->setText(QCheckBox::tr("Enable sound")); - GBAvollayout->addWidget(CBEnableSound, 1, 0, 1, 1); - - CBEnableMusic = new QCheckBox(AGGroupBox); - CBEnableMusic->setText(QCheckBox::tr("Enable music")); - GBAvollayout->addWidget(CBEnableMusic, 1, 1, 1, 2); - - GBAvollayout->setSizeConstraint(QLayout::SetMinimumSize); - - hr = new QFrame(AGGroupBox); - hr->setFrameStyle(QFrame::HLine); - hr->setLineWidth(3); - hr->setFixedHeight(10); - GBAlayout->addWidget(hr); - - CBAltDamage = new QCheckBox(AGGroupBox); - CBAltDamage->setText(QCheckBox::tr("Alternative damage show")); - GBAlayout->addWidget(CBAltDamage); - - gbTBLayout->addWidget(AGGroupBox, 0, 1, 3, 1); + connect(mapper, SIGNAL(mapped(int)), this, SLOT(colorButtonClicked(int))); } previousQuality = this->SLQuality->value(); @@ -499,3 +528,25 @@ CBTeamName->setVisible(enabled); LblNoEditTeam->setVisible(!enabled); } + +void PageOptions::colorButtonClicked(int i) +{ + if(i < 0 || i >= m_colorButtons.size()) + return; + + QPalette p = m_colorButtons[i]->palette(); + QColor c = QColorDialog::getColor(p.color(QPalette::Button)); + + if(c.isValid()) + { + DataManager::instance().colorsModel()->item(i)->setData(c); + m_colorButtons[i]->setStyleSheet(QString("background: %1").arg(c.name())); + } +} + +void PageOptions::onColorModelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight) +{ + QStandardItemModel * model = DataManager::instance().colorsModel(); + + m_colorButtons[topLeft.row()]->setStyleSheet(QString("background: %1").arg(model->item(topLeft.row())->data().value().name())); +} diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/ui/page/pageoptions.h --- a/QTfrontend/ui/page/pageoptions.h Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/ui/page/pageoptions.h Sat Aug 18 00:48:09 2012 +0200 @@ -23,6 +23,7 @@ class FPSEdit; class IconedGroupBox; +class QSignalMapper; class PageOptions : public AbstractPage { @@ -91,6 +92,7 @@ QPushButton *BtnNewTeam; QPushButton *BtnEditTeam; QPushButton *BtnDeleteTeam; + QList m_colorButtons; private slots: void forceFullscreen(int index); @@ -101,6 +103,8 @@ void requestEditSelectedTeam(); void requestDeleteSelectedTeam(); void savePwdChanged(int state); + void colorButtonClicked(int i); + void onColorModelDataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight); }; #endif diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/ui/widget/chatwidget.cpp --- a/QTfrontend/ui/widget/chatwidget.cpp Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/ui/widget/chatwidget.cpp Sat Aug 18 00:48:09 2012 +0200 @@ -922,7 +922,7 @@ if(b) { chatNicks->insertAction(0, acKick); -// chatNicks->insertAction(0, acBan); + chatNicks->insertAction(0, acBan); } } diff -r 763d3961400b -r 3c4b4cb40f40 QTfrontend/ui/widget/teamselect.cpp --- a/QTfrontend/ui/widget/teamselect.cpp Sat Aug 18 00:47:51 2012 +0200 +++ b/QTfrontend/ui/widget/teamselect.cpp Sat Aug 18 00:48:09 2012 +0200 @@ -135,6 +135,11 @@ curPlayingTeams.erase(itPlay); break; } + else + { + qWarning() << QString("removeNetTeam: team '%1' was actually a local team!").arg(team.name()); + break; + } } emit setEnabledGameStart(curPlayingTeams.size()>1); } diff -r 763d3961400b -r 3c4b4cb40f40 gameServer/Actions.hs --- a/gameServer/Actions.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/gameServer/Actions.hs Sat Aug 18 00:48:09 2012 +0200 @@ -146,9 +146,14 @@ io $ infoM "Clients" (show ci ++ " quits: " ++ B.unpack msg) - processAction $ AnswerClients [chan] ["BYE", msg] when loggedIn $ processAction $ AnswerClients clientsChans ["LOBBY:LEFT", clNick, msg] + mapM processAction + [ + AnswerClients [chan] ["BYE", msg] + , ModifyClient (\c -> c{logonPassed = False}) -- this will effectively hide client from others while he isn't deleted from list + ] + s <- get put $! s{removedClients = ci `Set.insert` removedClients s} @@ -216,7 +221,7 @@ chans <- othersChans if master then - if gameProgress && playersNum > 1 then + if playersNum > 1 then mapM_ processAction [ChangeMaster, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]] else processAction RemoveRoom @@ -225,7 +230,7 @@ -- when not removing room ready <- client's isReady - when (not master || (gameProgress && playersNum > 1)) . io $ do + when (not master || playersNum > 1) . io $ do modifyRoom rnc (\r -> r{ playersIn = playersIn r - 1, readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r @@ -418,11 +423,22 @@ processAction JoinLobby = do chan <- client's sendChan clientNick <- client's nick - (lobbyNicks, clientsChans) <- liftM (unzip . Prelude.map (nick &&& sendChan) . Prelude.filter logonPassed) $! allClientsS - mapM_ processAction $ - AnswerClients clientsChans ["LOBBY:JOINED", clientNick] - : AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks) - : [ModifyClient (\cl -> cl{logonPassed = True}), SendServerMessage] + isAuthenticated <- liftM (not . B.null) $ client's webPassword + isAdmin <- client's isAdministrator + loggedInClients <- liftM (Prelude.filter logonPassed) $! allClientsS + let (lobbyNicks, clientsChans) = unzip . L.map (nick &&& sendChan) $ loggedInClients + let authenticatedNicks = L.map nick . L.filter (not . B.null . webPassword) $ loggedInClients + let adminsNicks = L.map nick . L.filter isAdministrator $ loggedInClients + let clFlags = B.concat . L.concat $ [["u" | isAuthenticated], ["a" | isAdmin]] + mapM_ processAction . concat $ [ + [AnswerClients clientsChans ["LOBBY:JOINED", clientNick]] + , [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)] + , [AnswerClients [chan] ("CLIENT_FLAGS" : "+u" : authenticatedNicks) | not $ null authenticatedNicks] + , [AnswerClients [chan] ("CLIENT_FLAGS" : "+a" : adminsNicks) | not $ null adminsNicks] + , [AnswerClients (chan : clientsChans) ["CLIENT_FLAGS", B.concat["+" , clFlags], clientNick] | not $ B.null clFlags] + , [ModifyClient (\cl -> cl{logonPassed = True})] + , [SendServerMessage] + ] processAction (KickClient kickId) = do @@ -453,9 +469,9 @@ processAction BanList = do ch <- client's sendChan - bans <- gets (bans . serverInfo) + bans <- gets (B.pack . unlines . map show . bans . serverInfo) processAction $ - AnswerClients [ch] ["BANLIST", B.pack $ show bans] + AnswerClients [ch] ["BANLIST", bans] @@ -522,9 +538,11 @@ where kickTimeouted rnc ci = do pq <- io $ client'sM rnc pingsQueue ci - when (pq > 0) $ + when (pq > 0) $ do withStateT (\as -> as{clientIndex = Just ci}) $ processAction (ByeClient "Ping timeout") + when (pq > 1) $ + processAction $ DeleteClient ci -- smth went wrong with client io threads, issue DeleteClient here processAction StatsAction = do diff -r 763d3961400b -r 3c4b4cb40f40 gameServer/CoreTypes.hs --- a/gameServer/CoreTypes.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/gameServer/CoreTypes.hs Sat Aug 18 00:48:09 2012 +0200 @@ -94,6 +94,7 @@ readyPlayers :: !Int, isRestrictedJoins :: Bool, isRestrictedTeams :: Bool, + roomBansList :: [B.ByteString], mapParams :: Map.Map B.ByteString B.ByteString, params :: Map.Map B.ByteString [B.ByteString] } @@ -111,6 +112,7 @@ 0 False False + [] ( Map.fromList $ Prelude.zipWith (,) ["MAP", "MAPGEN", "MAZE_SIZE", "SEED", "TEMPLATE"] diff -r 763d3961400b -r 3c4b4cb40f40 gameServer/HWProtoInRoomState.hs --- a/gameServer/HWProtoInRoomState.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/gameServer/HWProtoInRoomState.hs Sat Aug 18 00:48:09 2012 +0200 @@ -278,6 +278,14 @@ where engineMsg cl = toEngineMsg $ B.concat ["b", nick cl, "(team): ", msg, "\x20\x20"] +handleCmd_inRoom ["BAN", banNick] = do + (_, rnc) <- ask + maybeClientId <- clientByNick banNick + let banId = fromJust maybeClientId + master <- liftM isMaster thisClient + return [ModifyRoom (\r -> r{roomBansList = (host $ rnc `client` banId) : roomBansList r}) | master && isJust maybeClientId] + + handleCmd_inRoom ["LIST"] = return [] -- for old clients (<= 0.9.17) handleCmd_inRoom (s:_) = return [ProtocolError $ "Incorrect command '" `B.append` s `B.append` "' (state: in room)"] diff -r 763d3961400b -r 3c4b4cb40f40 gameServer/HWProtoLobbyState.hs --- a/gameServer/HWProtoLobbyState.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/gameServer/HWProtoLobbyState.hs Sat Aug 18 00:48:09 2012 +0200 @@ -70,11 +70,14 @@ let jRoomClients = map (client irnc) $ roomClients irnc jRI let nicks = map nick jRoomClients let chans = map sendChan (cl : jRoomClients) + let isBanned = host cl `elem` roomBansList jRoom return $ if isNothing maybeRI || not sameProto then [Warning "No such room"] else if isRestrictedJoins jRoom then [Warning "Joining restricted"] + else if isBanned then + [Warning "You are banned in this room"] else if roomPassword /= password jRoom then [NoticeMessage WrongPassword] else @@ -183,7 +186,7 @@ handleCmd_lobby ["RESTART_SERVER"] = do cl <- thisClient - return [RestartServer] + return [RestartServer | isAdministrator cl] handleCmd_lobby _ = return [ProtocolError "Incorrect command (state: in lobby)"] diff -r 763d3961400b -r 3c4b4cb40f40 gameServer/ServerCore.hs --- a/gameServer/ServerCore.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/gameServer/ServerCore.hs Sat Aug 18 00:48:09 2012 +0200 @@ -43,7 +43,7 @@ ClientMessage (ci, cmd) -> do liftIO $ debugM "Clients" $ show ci ++ ": " ++ show cmd - + removed <- gets removedClients unless (ci `Set.member` removed) $ do modify (\s -> s{clientIndex = Just ci}) @@ -75,8 +75,6 @@ (fromJust $ serverSocket si) (coreChan si) - return () - _ <- forkIO $ timerLoop 0 $ coreChan si startDBConnection si diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/GSHandlers.inc Sat Aug 18 00:48:09 2012 +0200 @@ -610,11 +610,10 @@ // move back to cloud layer if yy > cWaterLine then move:= true - else if ((yy and LAND_HEIGHT_MASK) <> 0) - or (xx > LAND_WIDTH + 512) or (xx < -512) then + else if (xx > snowRight) or (xx < snowLeft) then move:=true // Solid pixel encountered - else if ((xx and LAND_WIDTH_MASK) = 0) and (Land[yy, xx] <> 0) then + else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (Land[yy, xx] <> 0) then begin lf:= Land[yy, xx] and (lfObject or lfBasic or lfIndestructible); // If there's room below keep falling @@ -724,8 +723,8 @@ exit end; Gear^.Pos:= 0; - Gear^.X:= int2hwFloat(GetRandom(LAND_WIDTH+1024)-512); - Gear^.Y:= int2hwFloat(750+(GetRandom(50)-25)); + Gear^.X:= int2hwFloat(GetRandom(snowRight-snowLeft)+snowLeft); + Gear^.Y:= int2hwFloat(LAND_HEIGHT-1300+(GetRandom(50)-25)); Gear^.State:= Gear^.State or gstInvisible; end end; @@ -1817,7 +1816,7 @@ Message := Message and (not gmAttack) end; DeleteGear(Gear); - exit; + exit; end; if CheckGearDrowning(HHGear) then DeleteGear(Gear) end; @@ -3685,10 +3684,6 @@ Gear^.X := HHGear^.X; Gear^.Y := HHGear^.Y; - // For some reason I need to reapply followgear here, something else grabs it otherwise. - // This is probably not needed anymore - if not CurrentTeam^.ExtDriven then - FollowGear := HHGear; if not isUnderWater and hasBorder and ((HHGear^.X < _0) or (hwRound(HHGear^.X) > LAND_WIDTH)) then @@ -4788,7 +4783,7 @@ Gear^.Timer:= Gear^.Tag end; - if (Gear^.Health = 0) or (HHGear^.Damage <> 0) then + if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) then begin DeleteGear(Gear); AfterAttack @@ -4864,7 +4859,7 @@ Gear^.Timer:= Gear^.Tag end; - if (Gear^.Health = 0) or (HHGear^.Damage <> 0) or ((HHGear^.Message and gmAttack) <> 0) then + if (Gear^.Health = 0) or ((HHGear^.State and gstHHDriven) = 0) or ((HHGear^.Message and gmAttack) <> 0) then begin HHGear^.Message:= HHGear^.Message and (not gmAttack); DeleteGear(Gear); diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/SDLh.pas Sat Aug 18 00:48:09 2012 +0200 @@ -410,12 +410,10 @@ PSDL_Color = ^TSDL_Color; TSDL_Color = record - case Byte of - 0: ( r: Byte; - g: Byte; - b: Byte; - unused: Byte; ); - 1: ( value: LongWord; ); + r: Byte; + g: Byte; + b: Byte; + unused: Byte; end; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/hwengine.pas Sat Aug 18 00:48:09 2012 +0200 @@ -57,6 +57,9 @@ gsLandGen: begin GenMap; + uLandTexture.initModule; + UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false); + uAILandMarks.initModule; ParseCommand('sendlanddigest', true); GameState:= gsStart; end; @@ -401,7 +404,6 @@ uAI.initModule; //uAIActions does not need initialization //uAIAmmoTests does not need initialization - uAILandMarks.initModule; uAIMisc.initModule; uAmmos.initModule; uChat.initModule; @@ -413,7 +415,6 @@ //uLandGraphics does not need initialization //uLandObjects does not need initialization //uLandTemplates does not need initialization - uLandTexture.initModule; //uLocale does not need initialization uRandom.initModule; uScript.initModule; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uAI.pas --- a/hedgewars/uAI.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uAI.pas Sat Aug 18 00:48:09 2012 +0200 @@ -178,9 +178,12 @@ begin AddAction(BestActions, aia_attack, aim_push, 350 + random(200), 0, 0); AddAction(BestActions, aia_attack, aim_release, 1, 0, 0); - - AddAction(BestActions, aia_Down, aim_push, 100 + random(150), 0, 0); - AddAction(BestActions, aia_Down, aim_release, 32, 0, 0); + + if abs(ap.Angle) > 32 then + begin + AddAction(BestActions, aia_Down, aim_push, 100 + random(150), 0, 0); + AddAction(BestActions, aia_Down, aim_release, 32, 0, 0); + end; AddAction(BestActions, aia_waitAngle, ap.Angle, 250, 0, 0); AddAction(BestActions, aia_attack, aim_push, 1, 0, 0); @@ -274,7 +277,8 @@ break; if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support - if Push(ticks, Actions, AltMe, Me^.Message) then + // check if we could go backwards and maybe ljump over a gap after this hjump + if Push(ticks, Actions, AltMe, Me^.Message xor 3) then begin with Stack.States[Pred(Stack.Count)] do begin @@ -291,9 +295,8 @@ else AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0); end; - - // check if we could go backwards and maybe ljump over a gap after this hjump - Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message xor 3) + // but first check walking forward + Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message) end; if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support begin diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uAIAmmoTests.pas Sat Aug 18 00:48:09 2012 +0200 @@ -47,6 +47,7 @@ function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; +function TestKamikaze(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; @@ -84,7 +85,7 @@ //(proc: @TestTeleport; flags: amtest_OnTurn), // amTeleport (proc: nil; flags: 0), // amSwitch (proc: @TestMortar; flags: 0), // amMortar - (proc: nil; flags: 0), // amKamikaze + (proc: @TestKamikaze; flags: 0), // amKamikaze (proc: @TestCake; flags: amtest_OnTurn or amtest_NoTarget), // amCake (proc: nil; flags: 0), // amSeduction (proc: @TestWatermelon; flags: 0), // amWatermelon @@ -167,7 +168,7 @@ EX:= trunc(x); EY:= trunc(y); - if Me^.Hedgehog^.BotLevel = 1 then + if Level = 1 then value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand) else value:= RateExplosion(Me, EX, EY, 101); if value = 0 then @@ -330,7 +331,7 @@ EX:= trunc(x); EY:= trunc(y); if t < 50 then - if Me^.Hedgehog^.BotLevel = 1 then + if Level = 1 then Score:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand) else Score:= RateExplosion(Me, EX, EY, 101) else @@ -361,12 +362,12 @@ t: LongInt; begin valueResult:= BadTurn; -TestTime:= 0; +TestTime:= 500; ap.ExplR:= 0; meX:= hwFloat2Float(Me^.X); meY:= hwFloat2Float(Me^.Y); repeat - inc(TestTime, 1000); + inc(TestTime, 900); // Try to overshoot slightly, seems to pay slightly better dividends in terms of hitting cluster if meX 3 then exit(BadTurn); +if Level > 3 then exit(BadTurn); dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; Level:= Level; // avoid compiler hint ap.ExplR:= 0; ap.Time:= 0; ap.Power:= 1; + x:= hwFloat2Float(Me^.X); 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; Vy:= (Targ.Y - y) * t; @@ -650,7 +654,7 @@ d: Longword; fallDmg, valueResult: LongInt; begin -if Me^.Hedgehog^.BotLevel > 3 then exit(BadTurn); +if Level > 3 then exit(BadTurn); dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; Level:= Level; // avoid compiler hint ap.ExplR:= 0; @@ -700,9 +704,9 @@ x, y, trackFall: LongInt; dx, dy: real; begin - if Me^.Hedgehog^.BotLevel < 3 then trackFall:= afTrackFall + if Level < 3 then trackFall:= afTrackFall else trackFall:= 0; - Level:= Level; // avoid compiler hint + ap.ExplR:= 0; ap.Time:= 0; ap.Power:= 1; @@ -749,9 +753,9 @@ var valueResult, v1, v2, i: LongInt; x, y, trackFall: LongInt; begin - if Me^.Hedgehog^.BotLevel = 1 then trackFall:= afTrackFall + if Level = 1 then trackFall:= afTrackFall else trackFall:= 0; - Level:= Level; // avoid compiler hint + ap.ExplR:= 0; ap.Time:= 0; ap.Power:= 1; @@ -805,9 +809,9 @@ var valueResult, v1, v2: LongInt; x, y, trackFall: LongInt; begin - if Me^.Hedgehog^.BotLevel = 1 then trackFall:= afTrackFall + if Level = 1 then trackFall:= afTrackFall else trackFall:= 0; - Level:= Level; // avoid compiler hint + ap.ExplR:= 0; ap.Time:= 0; ap.Power:= 1; @@ -822,7 +826,7 @@ , 30, 30, 25 , -1, -0.8, trackFall or afSetSkip); v1:= v1 + - RateShove(Me, x, y + RateShove(Me, x - 2, y , 30, 30, 25 , -1, -0.8, trackFall); // now try opposite direction @@ -830,7 +834,7 @@ , 30, 30, 25 , 1, -0.8, trackFall or afSetSkip); v2:= v2 + - RateShove(Me, x, y + RateShove(Me, x + 2, y , 30, 30, 25 , 1, -0.8, trackFall); @@ -854,6 +858,90 @@ TestWhip:= valueResult; end; +function TestKamikaze(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; +const step = 8; +var valueResult, i, v, tx: LongInt; + trackFall: LongInt; + t, d, x, y, dx, dy, cx: real; +begin + ap.ExplR:= 0; + ap.Time:= 0; + ap.Power:= 1; + + if Level = 1 then + trackFall:= afTrackFall + else if Level = 2 then + trackFall:= 0 + else + exit(BadTurn); + + valueResult:= 0; + v:= 0; + + x:= hwFloat2Float(Me^.X); + y:= hwFloat2Float(Me^.Y); + d:= sqrt(sqr(Targ.X - x) + sqr(Targ.Y - y)); + if d < 10 then + begin + dx:= 0; + dy:= 8; + ap.Angle:= 2048 + end + else + begin + t:= step / d; + dx:= (Targ.X - x) * t; + dy:= (Targ.Y - y) * t; + + ap.Angle:= DxDy2AttackAnglef(dx, -dy) + end; + + if dx >= 0 then cx:= 0.45 else cx:= -0.45; + + for i:= 0 to 512 div step - 2 do + begin + valueResult:= valueResult + + RateShove(Me, trunc(x), trunc(y) + , 30, 30, 25 + , cx, -0.9, trackFall or afSetSkip); + + x:= x + dx; + y:= y + dy; + end; + if dx = 0 then + begin + x:= hwFloat2Float(Me^.X); + y:= hwFloat2Float(Me^.Y); + tx:= trunc(x); + v:= RateShove(Me, tx, trunc(y) + , 30, 30, 25 + , -cx, -0.9, trackFall); + for i:= 1 to 512 div step - 2 do + begin + y:= y + dy; + v:= v + + RateShove(Me, tx, trunc(y) + , 30, 30, 25 + , -cx, -0.9, trackFall or afSetSkip); + end + end; + if v > valueResult then + begin + ap.Angle:= -2048; + valueResult:= v + end; + + v:= RateShove(Me, trunc(x), trunc(y) + , 30, 30, 25 + , cx, -0.9, trackFall); + valueResult:= valueResult + v - KillScore * friendlyfactor div 100 * 1024; + + if v < 65536 then + inc(valueResult, RateExplosion(Me, trunc(x), trunc(y), 30)); + + TestKamikaze:= valueResult; +end; + function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; var rate: LongInt; begin @@ -1008,7 +1096,8 @@ x, y, trackFall: LongInt; cake: TGear; begin - Level:= Level; // avoid compiler hint + if (Level > 2) then + exit(BadTurn); ap.ExplR:= 0; ap.Time:= 0; ap.Power:= BadTurn; // use it as max score value in checkCakeWalk diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uAILandMarks.pas --- a/hedgewars/uAILandMarks.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uAILandMarks.pas Sat Aug 18 00:48:09 2012 +0200 @@ -1,71 +1,71 @@ -unit uAILandMarks; - -interface -const markWasHere = $01; - -procedure addMark(X, Y: LongInt; mark: byte); -function checkMark(X, Y: LongInt; mark: byte) : boolean; -procedure clearAllMarks; -procedure clearMarks(mark: byte); - -procedure initModule; -procedure freeModule; - -implementation -uses uVariables; - -const gr = 2; - -var marks: array of array of byte; - WIDTH, HEIGHT: Longword; - -procedure addMark(X, Y: LongInt; mark: byte); -begin - if((X and LAND_WIDTH_MASK) = 0) and ((Y and LAND_HEIGHT_MASK) = 0) then - begin - X:= X shr gr; - Y:= Y shr gr; - marks[Y, X]:= marks[Y, X] or mark - end -end; - -function checkMark(X, Y: LongInt; mark: byte) : boolean; -begin - checkMark:= ((X and LAND_WIDTH_MASK) = 0) - and ((Y and LAND_HEIGHT_MASK) = 0) - and ((marks[Y shr gr, X shr gr] and mark) <> 0) -end; - -procedure clearAllMarks; -var - Y, X: Longword; -begin - for Y:= 0 to Pred(HEIGHT) do - for X:= 0 to Pred(WIDTH) do - marks[Y, X]:= 0 -end; - -procedure clearMarks(mark: byte); -var - Y, X: Longword; -begin - for Y:= 0 to Pred(HEIGHT) do - for X:= 0 to Pred(WIDTH) do - marks[Y, X]:= marks[Y, X] and (not mark) -end; - - -procedure initModule; -begin - WIDTH:= LAND_WIDTH shr gr; - HEIGHT:= LAND_HEIGHT shr gr; - - SetLength(marks, HEIGHT, WIDTH); -end; - -procedure freeModule; -begin - SetLength(marks, 0, 0); -end; - -end. +unit uAILandMarks; + +interface +const markWasHere = $01; + +procedure addMark(X, Y: LongInt; mark: byte); +function checkMark(X, Y: LongInt; mark: byte) : boolean; +procedure clearAllMarks; +procedure clearMarks(mark: byte); + +procedure initModule; +procedure freeModule; + +implementation +uses uVariables; + +const gr = 2; + +var marks: array of array of byte; + WIDTH, HEIGHT: Longword; + +procedure addMark(X, Y: LongInt; mark: byte); +begin + if((X and LAND_WIDTH_MASK) = 0) and ((Y and LAND_HEIGHT_MASK) = 0) then + begin + X:= X shr gr; + Y:= Y shr gr; + marks[Y, X]:= marks[Y, X] or mark + end +end; + +function checkMark(X, Y: LongInt; mark: byte) : boolean; +begin + checkMark:= ((X and LAND_WIDTH_MASK) = 0) + and ((Y and LAND_HEIGHT_MASK) = 0) + and ((marks[Y shr gr, X shr gr] and mark) <> 0) +end; + +procedure clearAllMarks; +var + Y, X: Longword; +begin + for Y:= 0 to Pred(HEIGHT) do + for X:= 0 to Pred(WIDTH) do + marks[Y, X]:= 0 +end; + +procedure clearMarks(mark: byte); +var + Y, X: Longword; +begin + for Y:= 0 to Pred(HEIGHT) do + for X:= 0 to Pred(WIDTH) do + marks[Y, X]:= marks[Y, X] and (not mark) +end; + + +procedure initModule; +begin + WIDTH:= LAND_WIDTH shr gr; + HEIGHT:= LAND_HEIGHT shr gr; + + SetLength(marks, HEIGHT, WIDTH); +end; + +procedure freeModule; +begin + SetLength(marks, 0, 0); +end; + +end. diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uAIMisc.pas Sat Aug 18 00:48:09 2012 +0200 @@ -86,12 +86,13 @@ ar: array[0..Pred(MAXBONUS div 8)] of TBonus; // don't use too many end; +const KillScore = 200; +var friendlyfactor: LongInt = 300; + implementation uses uCollisions, uVariables, uUtils, uDebug, uLandTexture; -const KillScore = 200; - -var friendlyfactor: LongInt = 300; +var KnownExplosion: record X, Y, Radius: LongInt end = (X: 0; Y: 0; Radius: 0); diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uCollisions.pas --- a/hedgewars/uCollisions.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uCollisions.pas Sat Aug 18 00:48:09 2012 +0200 @@ -82,7 +82,7 @@ X:= hwRound(Gear^.X); Y:= hwRound(Gear^.Y); Radius:= Gear^.Radius; - ChangeRoundInLand(X, Y, Radius - 1, true, Gear = CurrentHedgehog^.Gear); + ChangeRoundInLand(X, Y, Radius - 1, true, (Gear = CurrentHedgehog^.Gear) or (Gear^.Kind = gtCase)); cGear:= Gear end; Gear^.CollisionIndex:= Count; @@ -103,7 +103,7 @@ if Gear^.CollisionIndex >= 0 then begin with cinfos[Gear^.CollisionIndex] do - ChangeRoundInLand(X, Y, Radius - 1, false, Gear = CurrentHedgehog^.Gear); + ChangeRoundInLand(X, Y, Radius - 1, false, (Gear = CurrentHedgehog^.Gear) or (Gear^.Kind = gtCase)); cinfos[Gear^.CollisionIndex]:= cinfos[Pred(Count)]; cinfos[Gear^.CollisionIndex].cGear^.CollisionIndex:= Gear^.CollisionIndex; Gear^.CollisionIndex:= -1; @@ -138,7 +138,7 @@ var x, y, i: LongInt; begin // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap -if (Gear^.CollisionMask = $FF7F) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and +if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and ((hwRound(Gear^.Hedgehog^.Gear^.X) + Gear^.Hedgehog^.Gear^.Radius + 4 < hwRound(Gear^.X) - Gear^.Radius) or (hwRound(Gear^.Hedgehog^.Gear^.X) - Gear^.Hedgehog^.Gear^.Radius - 4 > hwRound(Gear^.X) + Gear^.Radius)) then Gear^.CollisionMask:= $FFFF; @@ -168,7 +168,7 @@ var x, y, i: LongInt; begin // Special case to emulate the old intersect gear clearing, but with a bit of slop for pixel overlap -if (Gear^.CollisionMask = $FF7F) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and +if (Gear^.CollisionMask = $FF7F) and (Gear^.Kind <> gtHedgehog) and (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.Gear <> nil) and ((hwRound(Gear^.Hedgehog^.Gear^.Y) + Gear^.Hedgehog^.Gear^.Radius + 4 < hwRound(Gear^.Y) - Gear^.Radius) or (hwRound(Gear^.Hedgehog^.Gear^.Y) - Gear^.Hedgehog^.Gear^.Radius - 4 > hwRound(Gear^.Y) + Gear^.Radius)) then Gear^.CollisionMask:= $FFFF; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uCommandHandlers.pas Sat Aug 18 00:48:09 2012 +0200 @@ -614,13 +614,14 @@ if CheckNoTeamOrHH or isPaused then exit; -if FollowGear <> nil then +if autoCameraOn then begin + FollowGear:= nil; AddCaption('Auto Camera Off', $CCCCCC, capgrpVolume); autoCameraOn:= false end - else - begin +else + begin AddCaption('Auto Camera On', $CCCCCC, capgrpVolume); bShowFinger:= true; if not CurrentHedgehog^.Unplaced then diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uConsts.pas Sat Aug 18 00:48:09 2012 +0200 @@ -245,6 +245,7 @@ gmRemoveFromList = $00004000; gmAddToList = $00008000; + gmDelete = $00010000; gmAllStoppable = gmLeft or gmRight or gmUp or gmDown or gmAttack or gmPrecise; cMaxSlotIndex = 9; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uFloat.pas --- a/hedgewars/uFloat.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uFloat.pas Sat Aug 18 00:48:09 2012 +0200 @@ -369,7 +369,7 @@ function hwPow(const t: hwFloat;p: LongWord): hwFloat; begin hwPow:= t; -if p mod 2 = 0 then hwPow.isNegative:= t.isNegative; +if p mod 2 = 0 then hwPow.isNegative:= false; while p > 0 do begin diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uGears.pas Sat Aug 18 00:48:09 2012 +0200 @@ -77,6 +77,7 @@ stAfterDelay, stChWin, stWater, stChWin2, stHealth, stSpawn, stNTurn); upd: Longword; + snowLeft,snowRight: LongInt; //SDMusic: shortstring; // For better maintainability the step handlers of gears are stored in @@ -206,23 +207,28 @@ curHandledGear:= t; t:= curHandledGear^.NextGear; - if curHandledGear^.Message and gmRemoveFromList <> 0 then - begin - RemoveGearFromList(curHandledGear); - // since I can't think of any good reason this would ever be separate from a remove from list, going to keep it inside this block - if curHandledGear^.Message and gmAddToList <> 0 then InsertGearToList(curHandledGear); - curHandledGear^.Message:= curHandledGear^.Message and (not (gmRemoveFromList or gmAddToList)) - end; - if curHandledGear^.Active then + if curHandledGear^.Message and gmDelete <> 0 then + DeleteGear(curHandledGear) + else begin - if curHandledGear^.RenderTimer and (curHandledGear^.Timer > 500) and ((curHandledGear^.Timer mod 1000) = 0) then + if curHandledGear^.Message and gmRemoveFromList <> 0 then + begin + RemoveGearFromList(curHandledGear); + // since I can't think of any good reason this would ever be separate from a remove from list, going to keep it inside this block + if curHandledGear^.Message and gmAddToList <> 0 then InsertGearToList(curHandledGear); + curHandledGear^.Message:= curHandledGear^.Message and (not (gmRemoveFromList or gmAddToList)) + end; + if curHandledGear^.Active then begin - FreeTexture(curHandledGear^.Tex); - curHandledGear^.Tex:= RenderStringTex(inttostr(curHandledGear^.Timer div 1000), cWhiteColor, fntSmall); - end; - curHandledGear^.doStep(curHandledGear); - // might be useful later - //ScriptCall('onGearStep', Gear^.uid); + if curHandledGear^.RenderTimer and (curHandledGear^.Timer > 500) and ((curHandledGear^.Timer mod 1000) = 0) then + begin + FreeTexture(curHandledGear^.Tex); + curHandledGear^.Tex:= RenderStringTex(inttostr(curHandledGear^.Timer div 1000), cWhiteColor, fntSmall); + end; + curHandledGear^.doStep(curHandledGear); + // might be useful later + //ScriptCall('onGearStep', Gear^.uid); + end end end; curHandledGear:= nil; @@ -642,9 +648,12 @@ AddGear(rx, ry, gtGenericFaller, gstInvisible, rdx, rdy, $FFFFFFFF); end; +snowRight:= max(LAND_WIDTH,4096)+512; +snowLeft:= -(snowRight-LAND_WIDTH); + if not hasBorder and ((Theme = 'Snow') or (Theme = 'Christmas')) then - for i:= 0 to Pred(vobCount*2) do - AddGear(GetRandom(LAND_WIDTH+1024)-512, LAND_HEIGHT - GetRandom(LAND_HEIGHT div 2), gtFlake, 0, _0, _0, 0); + for i:= vobCount * max(LAND_WIDTH,4096) div 2048 downto 1 do + AddGear(GetRandom(snowRight-snowLeft)+snowLeft, LAND_HEIGHT-1300+GetRandom(750), gtFlake, 0, _0, _0, 0); end; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uGearsHedgehog.pas --- a/hedgewars/uGearsHedgehog.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uGearsHedgehog.pas Sat Aug 18 00:48:09 2012 +0200 @@ -455,11 +455,13 @@ procedure AfterAttack; var s: shortstring; a: TAmmoType; + HHGear: PGear; begin -with CurrentHedgehog^.Gear^, CurrentHedgehog^ do +with CurrentHedgehog^ do begin + HHGear:= Gear; a:= CurAmmoType; - State:= State and (not gstAttacking); + if HHGear <> nil then HHGear^.State:= HHGear^.State and (not gstAttacking); if (Ammoz[a].Ammo.Propz and ammoprop_Effect) = 0 then begin Inc(MultiShootAttacks); @@ -484,8 +486,8 @@ TagTurnTimeLeft:= TurnTimeLeft; TurnTimeLeft:=(Ammoz[a].TimeAfterTurn * cGetAwayTime) div 100; end; - if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) then - State:= State or gstAttacked; + if ((Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) = 0) and (HHGear <> nil) then + HHGear^.State:= HHGear^.State or gstAttacked; if (Ammoz[a].Ammo.Propz and ammoprop_NoRoundEnd) <> 0 then ApplyAmmoChanges(CurrentHedgehog^) end; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uGearsRender.pas Sat Aug 18 00:48:09 2012 +0200 @@ -376,26 +376,26 @@ hAngle:= 0; i:= -1 end; - if ((Gear^.State and gstWinner) = 0) then - begin - DrawHedgehog(ox, oy, - i, - 1, - 0, - DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + dAngle); - with HH^ do - if (HatTex <> nil) then - begin - DrawTextureRotatedF(HatTex, 1.0, -1.0, -6.0, ox, oy, 0, i, 32, 32, - i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle); - if HatTex^.w > 64 then + if ((Gear^.State and gstWinner) = 0) then + begin + DrawHedgehog(ox, oy, + i, + 1, + 0, + DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + dAngle); + with HH^ do + if (HatTex <> nil) then begin - Tint(HH^.Team^.Clan^.Color shl 8 or $FF); - DrawTextureRotatedF(HatTex, 1.0, -1.0, -6.0, ox, oy, 32, i, 32, 32, + DrawTextureRotatedF(HatTex, 1.0, -1.0, -6.0, ox, oy, 0, i, 32, 32, i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle); - Tint($FF, $FF, $FF, $FF) + if HatTex^.w > 64 then + begin + Tint(HH^.Team^.Clan^.Color shl 8 or $FF); + DrawTextureRotatedF(HatTex, 1.0, -1.0, -6.0, ox, oy, 32, i, 32, 32, + i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle); + Tint($FF, $FF, $FF, $FF) + end end - end end; DrawAltWeapon(Gear, ox, oy); defaultPos:= false diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uGearsUtils.pas diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uLand.pas --- a/hedgewars/uLand.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uLand.pas Sat Aug 18 00:48:09 2012 +0200 @@ -20,7 +20,7 @@ unit uLand; interface -uses SDLh, uLandTemplates, uFloat, uConsts, GLunit, uTypes; +uses SDLh, uLandTemplates, uFloat, uConsts, GLunit, uTypes, uAILandMarks; procedure initModule; procedure freeModule; @@ -35,6 +35,28 @@ var digest: shortstring; +procedure ResizeLand(width, height: LongWord); +var potW, potH: LongWord; +begin +potW:= toPowerOf2(width); +potH:= toPowerOf2(height); +if (potW <> LAND_WIDTH) or (potH <> LAND_HEIGHT) then + begin + LAND_WIDTH:= potW; + LAND_HEIGHT:= potH; + LAND_WIDTH_MASK:= not(LAND_WIDTH-1); + LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1); + cWaterLine:= LAND_HEIGHT; + if (cReducedQuality and rqBlurryLand) = 0 then + SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH) + else + SetLength(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2); + + SetLength(Land, LAND_HEIGHT, LAND_WIDTH); + SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32)); + end; +end; + procedure ColorizeLand(Surface: PSDL_Surface); var tmpsurf: PSDL_Surface; r, rr: TSDL_Rect; @@ -181,6 +203,7 @@ i: Longword; y, x: Longword; begin + ResizeLand(Template.TemplateWidth, Template.TemplateHeight); for y:= 0 to LAND_HEIGHT - 1 do for x:= 0 to LAND_WIDTH - 1 do Land[y, x]:= lfBasic; @@ -237,6 +260,7 @@ procedure GenDrawnMap; begin + ResizeLand(4096, 2048); uLandPainted.Draw; MaxHedgehogs:= 48; @@ -299,7 +323,7 @@ WriteLnToConsole('Generating land...'); case cMapGen of 0: GenBlank(EdgeTemplates[SelectTemplate]); - 1: GenMaze; + 1: begin ResizeLand(4096,2048); GenMaze; end; 2: GenDrawnMap; else OutError('Unknown mapgen', true); @@ -489,7 +513,10 @@ if tmpsurf = nil then tmpsurf:= LoadImage(Pathz[ptMissionMaps] + '/' + mapName + '/map', ifAlpha or ifCritical or ifTransparent or ifIgnoreCaps); end; -TryDo((tmpsurf^.w <= LAND_WIDTH) and (tmpsurf^.h <= LAND_HEIGHT), 'Map dimensions too big!', true); +// (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); + +ResizeLand(tmpsurf^.w, tmpsurf^.h); // unC0Rr - should this be passed from the GUI? I am not sure which layer does what s:= UserPathz[ptMapCurrent] + '/map.cfg'; @@ -676,12 +703,10 @@ LandPixels[y,x]:= w or (LandPixels[y div 2, x div 2] and AMask) end end; - -UpdateLandTexture(0, LAND_WIDTH, 0, LAND_HEIGHT, false); end; procedure GenPreview(out Preview: TPreview); -var x, y, xx, yy, t, bit, cbit, lh, lw: LongInt; +var rh, rw, ox, oy, x, y, xx, yy, t, bit, cbit, lh, lw: LongInt; begin WriteLnToConsole('Generating preview...'); case cMapGen of @@ -692,8 +717,21 @@ OutError('Unknown mapgen', true); end; - lh:= LAND_HEIGHT div 128; - lw:= LAND_WIDTH div 32; + // strict scaling needed here since preview assumes a rectangle + rh:= max(LAND_HEIGHT,2048); + rw:= max(LAND_WIDTH,4096); + ox:= 0; + if rw < rh*2 then + begin + rw:= rh*2; + end; + if rh < rw div 2 then rh:= rw * 2; + + ox:= (rw-LAND_WIDTH) div 2; + oy:= rh-LAND_HEIGHT; + + lh:= rh div 128; + lw:= rw div 32; for y:= 0 to 127 do for x:= 0 to 31 do begin @@ -704,7 +742,8 @@ cbit:= bit * 8; for yy:= y * lh to y * lh + 7 do for xx:= x * lw + cbit to x * lw + cbit + 7 do - if Land[yy, xx] <> 0 then + if ((yy-oy) and LAND_HEIGHT_MASK = 0) and ((xx-ox) and LAND_WIDTH_MASK = 0) + and (Land[yy-oy, xx-ox] <> 0) then inc(t); if t > 8 then Preview[y, x]:= Preview[y, x] or ($80 shr bit); diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uLandGraphics.pas --- a/hedgewars/uLandGraphics.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uLandGraphics.pas Sat Aug 18 00:48:09 2012 +0200 @@ -59,7 +59,7 @@ begin addBgColor:= NewColor; exit - end; + end; // Get colors oRed := (OldColor shr RShift); oGreen := (OldColor shr GShift); @@ -72,7 +72,7 @@ // Mix colors nRed := min(255,((nRed*nAlpha) div 255) + ((oRed*oAlpha*byte(255-nAlpha)) div 65025)); nGreen := min(255,((nGreen*nAlpha) div 255) + ((oGreen*oAlpha*byte(255-nAlpha)) div 65025)); - nBlue := min(255,((nBlue*nAlpha) div 255) + ((oBlue*oAlpha*byte(255-nAlpha)) div 65025)); + nBlue := min(255,((nBlue*nAlpha) div 255) + ((oBlue*oAlpha*byte(255-nAlpha)) div 65025)); nAlpha := min(255, oAlpha + nAlpha); addBgColor := (nAlpha shl AShift) or (nRed shl RShift) or (nGreen shl GShift) or (nBlue shl BShift); @@ -106,25 +106,25 @@ begin if ((y + dy) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do - if isCurrent then + if isCurrent then Land[y + dy, i]:= Land[y + dy, i] and $FF7F else if Land[y + dy, i] and $007F > 0 then Land[y + dy, i]:= (Land[y + dy, i] and $FF80) or ((Land[y + dy, i] and $7F) - 1); if ((y - dy) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do - if isCurrent then + if isCurrent then Land[y - dy, i]:= Land[y - dy, i] and $FF7F else if Land[y - dy, i] and $007F > 0 then Land[y - dy, i]:= (Land[y - dy, i] and $FF80) or ((Land[y - dy, i] and $7F) - 1); if ((y + dx) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do - if isCurrent then + if isCurrent then Land[y + dx, i]:= Land[y + dx, i] and $FF7F else if Land[y + dx, i] and $007F > 0 then Land[y + dx, i]:= (Land[y + dx, i] and $FF80) or ((Land[y + dx, i] and $7F) - 1); if ((y - dx) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do - if isCurrent then + if isCurrent then Land[y - dx, i]:= Land[y - dx, i] and $FF7F else if Land[y - dx, i] and $007F > 0 then Land[y - dx, i]:= (Land[y - dx, i] and $FF80) or ((Land[y - dx, i] and $7F) - 1) @@ -133,27 +133,27 @@ begin if ((y + dy) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do - if isCurrent then + if isCurrent then Land[y + dy, i]:= Land[y + dy, i] or $80 else if Land[y + dy, i] and $007F < 127 then Land[y + dy, i]:= (Land[y + dy, i] and $FF80) or ((Land[y + dy, i] and $7F) + 1); - if ((y - dy) and LAND_HEIGHT_MASK) = 0 then - for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do - if isCurrent then - Land[y - dy, i]:= Land[y - dy, i] or $80 - else if Land[y - dy, i] and $007F < 127 then + if ((y - dy) and LAND_HEIGHT_MASK) = 0 then + for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do + if isCurrent then + Land[y - dy, i]:= Land[y - dy, i] or $80 + else if Land[y - dy, i] and $007F < 127 then Land[y - dy, i]:= (Land[y - dy, i] and $FF80) or ((Land[y - dy, i] and $7F) + 1); - if ((y + dx) and LAND_HEIGHT_MASK) = 0 then - for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do - if isCurrent then - Land[y + dx, i]:= Land[y + dx, i] or $80 - else if Land[y + dx, i] and $007F < 127 then + if ((y + dx) and LAND_HEIGHT_MASK) = 0 then + for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do + if isCurrent then + Land[y + dx, i]:= Land[y + dx, i] or $80 + else if Land[y + dx, i] and $007F < 127 then Land[y + dx, i]:= (Land[y + dx, i] and $FF80) or ((Land[y + dx, i] and $7F) + 1); - if ((y - dx) and LAND_HEIGHT_MASK) = 0 then - for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do - if isCurrent then - Land[y - dx, i]:= Land[y - dx, i] or $80 - else if Land[y - dx, i] and $007F < 127 then + if ((y - dx) and LAND_HEIGHT_MASK) = 0 then + for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do + if isCurrent then + Land[y - dx, i]:= Land[y - dx, i] or $80 + else if Land[y - dx, i] and $007F < 127 then Land[y - dx, i]:= (Land[y - dx, i] and $FF80) or ((Land[y - dx, i] and $7F) + 1) end end; @@ -266,7 +266,7 @@ inc(cnt); LandPixels[by, bx]:= LandBackPixel(i, t) end - else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then + else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then LandPixels[by, bx]:= 0 end; @@ -288,7 +288,7 @@ inc(cnt); LandPixels[by, bx]:= LandBackPixel(i, t) end - else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then + else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then LandPixels[by, bx]:= 0 end; @@ -310,7 +310,7 @@ inc(cnt); LandPixels[by, bx]:= LandBackPixel(i, t) end - else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then + else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then LandPixels[by, bx]:= 0 end; t:= y - dx; @@ -331,7 +331,7 @@ inc(cnt); LandPixels[by, bx]:= LandBackPixel(i, t) end - else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then + else if ((Land[t, i] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then LandPixels[by, bx]:= 0 end; FillLandCircleLinesBG:= cnt; @@ -504,7 +504,7 @@ end; if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then LandPixels[by, bx]:= LandBackPixel(tx, ty) - else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then + else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then LandPixels[by, bx]:= 0 end end; @@ -567,7 +567,7 @@ and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0) or ((Land[ty, tx] and lfObject) <> 0)) then begin - if despeckle then + if despeckle then begin Land[ty, tx]:= Land[ty, tx] or lfDamaged; LandDirty[ty div 32, tx div 32]:= 1 @@ -837,7 +837,7 @@ procedure Smooth(X, Y: LongInt); begin // a bit of AA for explosions -if (Land[Y, X] = 0) and (Y > LongInt(topY) + 1) and +if (Land[Y, X] = 0) and (Y > LongInt(topY) + 1) and (Y < LAND_HEIGHT-2) and (X > LongInt(leftX) + 1) and (X < LongInt(rightX) - 1) then begin if ((((Land[y, x-1] and lfDamaged) <> 0) and (((Land[y+1,x] and lfDamaged) <> 0)) or ((Land[y-1,x] and lfDamaged) <> 0)) diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uLandObjects.pas --- a/hedgewars/uLandObjects.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uLandObjects.pas Sat Aug 18 00:48:09 2012 +0200 @@ -501,7 +501,7 @@ c2.g:= t; c2.b:= t end; - ExplosionBorderColor:= c2.value or AMask; + ExplosionBorderColor:= c2.r shl 24 or c2.g shl 16 or c2.b shl 8 or $FF; end else if key = 'water-top' then begin @@ -554,7 +554,7 @@ SetMusicName(Trim(s)) else if key = 'clouds' then begin - cCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div LAND_WIDTH; + cCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div 4096; cSDCloudsNumber:= cCloudsNumber end else if key = 'object' then @@ -700,7 +700,7 @@ else if key = 'sd-water-opacity' then SDWaterOpacity:= StrToInt(Trim(s)) else if key = 'sd-clouds' then - cSDCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div LAND_WIDTH + cSDCloudsNumber:= Word(StrToInt(Trim(s))) * cScreenSpace div 4096 else if key = 'sd-flakes' then begin i:= Pos(',', s); diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uLandTemplates.pas --- a/hedgewars/uLandTemplates.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uLandTemplates.pas Sat Aug 18 00:48:09 2012 +0200 @@ -1571,9 +1571,191 @@ ( (X: 512; Y: 0) ); +// Many islands +const Template43Points: array[0..173] of TSDL_Rect = + ( + (x: 95; y: 500; w: 1; h: 1), + (x: 100; y: 275; w: 25; h: 100), + (x: 325; y: 275; w: 25; h: 100), + (x: 330; y: 500; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 725; y: 125; w: 1; h: 1), + (x: 725; y: 25; w: 5; h: 25), + (x: 825; y: 35; w: 5; h: 10), + (x: 825; y: 135; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 1150; y: 550; w: 25; h: 50), + (x: 1250; y: 300; w: 25; h: 50), + (x: 1350; y: 300; w: 25; h: 50), + (x: 1400; y: 575; w: 25; h: 50), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 525; y:1050; w: 50; h: 50), + (x: 700; y: 800; w: 100; h: 150), + (x: 950; y: 900; w: 100; h: 150), + (x: 1100; y:1100; w: 50; h: 50), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 175; y:1500; w: 1; h: 1), + (x: 210; y:1400; w: 5; h: 25), + (x: 240; y:1400; w: 5; h: 25), + (x: 275; y:1510; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 450; y:1800; w: 100; h: 100), + (x: 600; y:1750; w: 100; h: 100), + (x: 750; y:1750; w: 100; h: 100), + (x: 950; y:1850; w: 100; h: 100), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 1075; y:1450; w: 1; h: 1), + (x: 1110; y:1300; w: 5; h: 25), + (x: 1140; y:1300; w: 5; h: 25), + (x: 1175; y:1430; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 1600; y:1250; w: 25; h: 100), + (x: 1700; y:1150; w: 25; h: 100), + (x: 1850; y: 500; w: 50; h: 100), + (x: 1950; y: 550; w: 50; h: 150), + (x: 2250; y:1150; w: 25; h: 100), + (x: 2350; y:1250; w: 25; h: 100), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 1750; y:2010; w: 1; h: 1), + (x: 1900; y:1870; w: 50; h: 50), + (x: 2050; y:1870; w: 50; h: 50), + (x: 2175; y:2010; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 2500; y:1700; w: 1; h: 1), + (x: 2575; y:1500; w: 10; h: 50), + (x: 2650; y:1500; w: 10; h: 50), + (x: 2700; y:1690; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 2000; y: 125; w: 1; h: 1), + (x: 2050; y: 50; w: 25; h: 25), + (x: 2100; y: 50; w: 25; h: 25), + (x: 2150; y: 150; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 2600; y: 250; w: 25; h: 100), + (x: 2750; y: 400; w: 50; h: 50), + (x: 2900; y: 525; w: 50; h: 50), + (x: 3150; y: 550; w: 50; h: 100), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 2800; y:1150; w: 1; h: 1), + (x: 2840; y: 950; w: 25; h: 25), + (x: 2880; y: 950; w: 25; h: 25), + (x: 2900; y:1150; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 3075; y:1985; w: 1; h: 1), + (x: 3325; y:1700; w: 50; h: 100), + (x: 3475; y:1700; w: 50; h: 100), + (x: 3625; y:1985; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 3200; y:1450; w: 1; h: 1), + (x: 3240; y:1350; w: 25; h: 25), + (x: 3280; y:1350; w: 25; h: 25), + (x: 3300; y:1450; w: 1; h: 1), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 3500; y:1050; w: 25; h: 50), + (x: 3650; y: 600; w: 50; h: 100), + (x: 3800; y: 600; w: 50; h: 100), + (x: 3900; y:1000; w: 25; h: 50), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 3800; y: 200; w: 25; h: 50), + (x: 3875; y: 100; w: 50; h: 50), + (x: 3925; y: 50; w: 50; h: 25), + (x: 4050; y: 125; w: 25; h: 50), + (x: NTPX; y: 0; w: 1; h: 1), + (x: 95; y:2548; w: 1; h: 1), + (x: 100; y:2323; w: 25; h: 100), + (x: 325; y:2323; w: 25; h: 100), + (x: 330; y:2548; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 725; y:2173; w: 1; h: 1), + (x: 725; y:2073; w: 5; h: 25), + (x: 825; y:2083; w: 5; h: 10), + (x: 825; y:2183; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 1150; y:2598; w: 25; h: 50), + (x: 1250; y:2348; w: 25; h: 50), + (x: 1350; y:2348; w: 25; h: 50), + (x: 1400; y:2623; w: 25; h: 50), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 525; y:3098; w: 50; h: 50), + (x: 700; y:2848; w: 100; h: 150), + (x: 950; y:2948; w: 100; h: 150), + (x: 1100; y:3148; w: 50; h: 50), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 175; y:3548; w: 1; h: 1), + (x: 210; y:3448; w: 5; h: 25), + (x: 240; y:3448; w: 5; h: 25), + (x: 275; y:3558; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 450; y:3848; w: 100; h: 100), + (x: 600; y:3798; w: 100; h: 100), + (x: 750; y:3798; w: 100; h: 100), + (x: 950; y:3898; w: 100; h: 100), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 1075; y:3498; w: 1; h: 1), + (x: 1110; y:3348; w: 5; h: 25), + (x: 1140; y:3348; w: 5; h: 25), + (x: 1175; y:3478; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 1600; y:3298; w: 25; h: 100), + (x: 1700; y:3198; w: 25; h: 100), + (x: 1850; y:2548; w: 50; h: 100), + (x: 1950; y:2598; w: 50; h: 150), + (x: 2250; y:3198; w: 25; h: 100), + (x: 2350; y:3298; w: 25; h: 100), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 1750; y:4058; w: 1; h: 1), + (x: 1900; y:3918; w: 50; h: 50), + (x: 2050; y:3918; w: 50; h: 50), + (x: 2175; y:4058; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 2500; y:3748; w: 1; h: 1), + (x: 2575; y:3548; w: 10; h: 50), + (x: 2650; y:3548; w: 10; h: 50), + (x: 2700; y:3738; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 2000; y:2173; w: 1; h: 1), + (x: 2050; y:2098; w: 25; h: 25), + (x: 2100; y:2098; w: 25; h: 25), + (x: 2150; y:2198; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 2600; y:2298; w: 25; h: 100), + (x: 2750; y:2448; w: 50; h: 50), + (x: 2900; y:2573; w: 50; h: 50), + (x: 3150; y:2598; w: 50; h: 100), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 2800; y:3198; w: 1; h: 1), + (x: 2840; y:2998; w: 25; h: 25), + (x: 2880; y:2998; w: 25; h: 25), + (x: 2900; y:3198; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 3075; y:4033; w: 1; h: 1), + (x: 3325; y:3748; w: 50; h: 100), + (x: 3475; y:3748; w: 50; h: 100), + (x: 3625; y:4033; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 3200; y:3498; w: 1; h: 1), + (x: 3240; y:3398; w: 25; h: 25), + (x: 3280; y:3398; w: 25; h: 25), + (x: 3300; y:3498; w: 1; h: 1), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 3500; y:3098; w: 25; h: 50), + (x: 3650; y:2648; w: 50; h: 100), + (x: 3800; y:2648; w: 50; h: 100), + (x: 3900; y:3048; w: 25; h: 50), + (x: NTPX; y:2048; w: 1; h: 1), + (x: 3800; y:2248; w: 25; h: 50), + (x: 3875; y:2148; w: 50; h: 50), + (x: 3925; y:2098; w: 50; h: 25), + (x: 4050; y:2173; w: 25; h: 50), + (x: NTPX; y:2048; w: 1; h: 1) + ); + Template43FPoints: array[0..0] of TPoint = + ( + (X: 4095; Y: 0) + ); //////////////////////////////////////////////////////////////////////// -var EdgeTemplates: array[0..42] of TEdgeTemplate = +var EdgeTemplates: array[0..43] of TEdgeTemplate = ( (BasePoints: @Template0Points; BasePointsCount: Succ(High(Template0Points)); @@ -2047,19 +2229,30 @@ canMirror: true; canFlip: false; isNegative: false; canInvert: false; hasGirders: false; MaxHedgeHogs: 8; + ), + (BasePoints: @Template43Points; + BasePointsCount: Succ(High(Template43Points)); + FillPoints: @Template43FPoints; + FillPointsCount: Succ(High(Template43FPoints)); + BezierizeCount: 3; + RandPassesCount: 5; + TemplateHeight: 4096; TemplateWidth: 4096; + canMirror: true; canFlip: true; isNegative: false; canInvert: false; + hasGirders: true; + MaxHedgeHogs: 48; ) ); const SmallTemplates: array[0..2] of Longword = ( 39, 40, 42 ); const MediumTemplates: array[0..17] of Longword = ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 ); -const LargeTemplates: array[0..19] of Longword = +const LargeTemplates: array[0..20] of Longword = ( 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 37, 38 + 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 43 ); const CavernTemplates: array[0..4] of Longword = (36, 2, 3, 21, 29); //const WackyTemplates: array[0..4] of Longword = (37, 38, 39, 40, 41); -const WackyTemplates: array[0..2] of Longword = (37, 38, 41); +const WackyTemplates: array[0..3] of Longword = (37, 38, 41, 43); implementation diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uRenderUtils.pas --- a/hedgewars/uRenderUtils.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uRenderUtils.pas Sat Aug 18 00:48:09 2012 +0200 @@ -92,7 +92,7 @@ textRect.y:= Y; textRect.w:= w; textRect.h:= h; - DrawRoundRect(@finalRect, cWhiteColor, endian(cNearBlackColorChannels.value), Surface, true); + DrawRoundRect(@finalRect, cWhiteColor, cNearBlackColor, Surface, true); clr.r:= (Color shr 16) and $FF; clr.g:= (Color shr 8) and $FF; clr.b:= Color and $FF; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uScript.pas --- a/hedgewars/uScript.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uScript.pas Sat Aug 18 00:48:09 2012 +0200 @@ -412,7 +412,7 @@ begin gear:= GearByUID(lua_tointeger(L, 1)); if gear <> nil then - DeleteGear(gear); + gear^.Message:= gear^.Message or gmDelete; end; lc_deletegear:= 0 end; @@ -744,7 +744,7 @@ TryDo(texsurf <> nil, errmsgCreateSurface, true); TryDo(SDL_SetColorKey(texsurf, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true); - DrawRoundRect(@r, cWhiteColor, cNearBlackColorChannels.value, texsurf, true); + DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true); rr:= r; inc(rr.x, 2); dec(rr.w, 4); inc(rr.y, 2); dec(rr.h, 4); DrawRoundRect(@rr, clan^.Color, clan^.Color, texsurf, false); diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uStore.pas --- a/hedgewars/uStore.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uStore.pas Sat Aug 18 00:48:09 2012 +0200 @@ -131,10 +131,11 @@ procedure WriteNames(Font: THWFont); var t: LongInt; - i: LongInt; + i, maxLevel: LongInt; r, rr: TSDL_Rect; drY: LongInt; texsurf, flagsurf, iconsurf: PSDL_Surface; + foundBot: boolean; begin r.x:= 0; r.y:= 0; @@ -151,7 +152,7 @@ TryDo(texsurf <> nil, errmsgCreateSurface, true); TryDo(SDL_SetColorKey(texsurf, SDL_SRCCOLORKEY, 0) = 0, errmsgTransparentSet, true); - DrawRoundRect(@r, cWhiteColor, cNearBlackColorChannels.value, texsurf, true); + DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true); rr:= r; inc(rr.x, 2); dec(rr.w, 4); inc(rr.y, 2); dec(rr.h, 4); DrawRoundRect(@rr, Clan^.Color, Clan^.Color, texsurf, false); @@ -172,11 +173,28 @@ DrawRoundRect(@r, cWhiteColor, cNearBlackColor, texsurf, true); // overwrite flag for cpu teams and keep players from using it - if (Hedgehogs[0].Gear <> nil) and (Hedgehogs[0].BotLevel > 0) then - if Flag = 'hedgewars' then - Flag:= 'cpu' - else if Flag = 'cpu' then - Flag:= 'hedgewars'; + foundBot:= false; + maxLevel:= -1; + for i:= 0 to cMaxHHIndex do + with Hedgehogs[i] do + if (Gear <> nil) and (BotLevel > 0) then + begin + foundBot:= true; + // initially was going to do the highest botlevel of the team, but for now, just apply if entire team has same bot level + if maxLevel = -1 then maxLevel:= BotLevel + else if (maxLevel > 0) and (maxLevel <> BotLevel) then maxLevel:= 0; + //if (maxLevel > 0) and (BotLevel < maxLevel) then maxLevel:= BotLevel + end + else if Gear <> nil then maxLevel:= 0; + + if foundBot then + begin + // disabled the plain flag - I think it looks ok even w/ full bars obscuring CPU + //if (maxLevel > 0) and (maxLevel < 3) then Flag:= 'cpu_plain' else + Flag:= 'cpu' + end + else if (Flag = 'cpu') or (Flag = 'cpu_plain') then + Flag:= 'hedgewars'; flagsurf:= LoadImage(UserPathz[ptFlags] + '/' + Flag, ifNone); if flagsurf = nil then @@ -186,16 +204,27 @@ if flagsurf = nil then flagsurf:= LoadImage(Pathz[ptFlags] + '/hedgewars', ifNone); TryDo(flagsurf <> nil, 'Failed to load flag "' + Flag + '" as well as the default flag', true); + + case maxLevel of + 1: copyToXY(SpritesData[sprBotlevels].Surface, flagsurf, 0, 0); + 2: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 5, 2, 17, 13, 5, 2); + 3: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 9, 5, 13, 10, 9, 5); + 4: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 13, 9, 9, 6, 13, 9); + 5: copyToXYFromRect(SpritesData[sprBotlevels].Surface, flagsurf, 17, 11, 5, 4, 17, 11) + end; + copyToXY(flagsurf, texsurf, 2, 2); SDL_FreeSurface(flagsurf); flagsurf:= nil; + // restore black border pixels inside the flag PLongwordArray(texsurf^.pixels)^[32 * 2 + 2]:= cNearBlackColor; PLongwordArray(texsurf^.pixels)^[32 * 2 + 23]:= cNearBlackColor; PLongwordArray(texsurf^.pixels)^[32 * 16 + 2]:= cNearBlackColor; PLongwordArray(texsurf^.pixels)^[32 * 16 + 23]:= cNearBlackColor; + FlagTex:= Surface2Tex(texsurf, false); SDL_FreeSurface(texsurf); texsurf:= nil; @@ -204,7 +233,7 @@ dec(drY, r.h + 2); DrawHealthY:= drY; - for i:= 0 to 7 do + for i:= 0 to cMaxHHIndex do with Hedgehogs[i] do if Gear <> nil then begin @@ -294,7 +323,6 @@ WriteLnToConsole(msgOK) end; -WriteNames(fnt16); MakeCrossHairs; LoadGraves; if not reload then @@ -391,6 +419,8 @@ Surface:= nil end; +WriteNames(fnt16); + if not reload then AddProgress; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uTypes.pas --- a/hedgewars/uTypes.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uTypes.pas Sat Aug 18 00:48:09 2012 +0200 @@ -86,7 +86,7 @@ sprHandResurrector, sprCross, sprAirDrill, sprNapalmBomb, sprBulletHit, sprSnowball, sprHandSnowball, sprSnow, sprSDFlake, sprSDWater, sprSDCloud, sprSDSplash, sprSDDroplet, sprTardis, - sprSlider + sprSlider, sprBotlevels ); // Gears that interact with other Gears and/or Land diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uUtils.pas --- a/hedgewars/uUtils.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uUtils.pas Sat Aug 18 00:48:09 2012 +0200 @@ -43,7 +43,7 @@ function StrToInt(s: shortstring): LongInt; function FloatToStr(n: hwFloat): shortstring; -function DxDy2Angle(const _dY, _dX: hwFloat): GLfloat; +function DxDy2Angle(const _dY, _dX: hwFloat): GLfloat; inline; function DxDy2Angle32(const _dY, _dX: hwFloat): LongInt; function DxDy2AttackAngle(const _dY, _dX: hwFloat): LongInt; function DxDy2AttackAnglef(const _dY, _dX: extended): LongInt; @@ -182,15 +182,11 @@ end; -function DxDy2Angle(const _dY, _dX: hwFloat): GLfloat; +function DxDy2Angle(const _dY, _dX: hwFloat): GLfloat; inline; var dY, dX: Extended; begin -dY:= _dY.QWordValue / $100000000; -if _dY.isNegative then - dY:= - dY; -dX:= _dX.QWordValue / $100000000; -if _dX.isNegative then - dX:= - dX; +dY:= hwFloat2Float(_dY); +dX:= hwFloat2Float(_dX); DxDy2Angle:= arctan2(dY, dX) * 180 / pi end; @@ -198,12 +194,8 @@ const _16divPI: Extended = 16/pi; var dY, dX: Extended; begin -dY:= _dY.QWordValue / $100000000; -if _dY.isNegative then - dY:= - dY; -dX:= _dX.QWordValue / $100000000; -if _dX.isNegative then - dX:= - dX; +dY:= hwFloat2Float(_dY); +dX:= hwFloat2Float(_dX); DxDy2Angle32:= trunc(arctan2(dY, dX) * _16divPI) and $1f end; @@ -211,12 +203,8 @@ const MaxAngleDivPI: Extended = cMaxAngle/pi; var dY, dX: Extended; begin -dY:= _dY.QWordValue / $100000000; -if _dY.isNegative then - dY:= - dY; -dX:= _dX.QWordValue / $100000000; -if _dX.isNegative then - dX:= - dX; +dY:= hwFloat2Float(_dY); +dX:= hwFloat2Float(_dX); DxDy2AttackAngle:= trunc(arctan2(dY, dX) * MaxAngleDivPI) end; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uVariables.pas Sat Aug 18 00:48:09 2012 +0200 @@ -644,7 +644,9 @@ (FileName: 'TARDIS'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; Width: 48; Height: 79; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprTardis (FileName: 'slider'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 3; Height: 17; imageWidth: 3; imageHeight: 17; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprSlider + Width: 3; Height: 17; imageWidth: 3; imageHeight: 17; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: false), // sprSlider + (FileName: 'botlevels'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; + Width: 22; Height: 15; imageWidth: 22; imageHeight: 15; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: false) // sprBotlevels ); const diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uVisualGears.pas --- a/hedgewars/uVisualGears.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uVisualGears.pas Sat Aug 18 00:48:09 2012 +0200 @@ -958,10 +958,10 @@ exit; if hasBorder or ((Theme <> 'Snow') and (Theme <> 'Christmas')) then - for i:= 0 to Pred(vobCount * cScreenSpace div LAND_WIDTH) do + for i:= 0 to Pred(vobCount * cScreenSpace div 4096) do AddVisualGear(cLeftScreenBorder + random(cScreenSpace), random(1024+200) - 100 + LAND_HEIGHT, vgtFlake) else - for i:= 0 to Pred((vobCount * cScreenSpace div LAND_WIDTH) div 3) do + for i:= 0 to Pred((vobCount * cScreenSpace div 4096) div 3) do AddVisualGear(cLeftScreenBorder + random(cScreenSpace), random(1024+200) - 100 + LAND_HEIGHT, vgtFlake); end; diff -r 763d3961400b -r 3c4b4cb40f40 hedgewars/uWorld.pas --- a/hedgewars/uWorld.pas Sat Aug 18 00:47:51 2012 +0200 +++ b/hedgewars/uWorld.pas Sat Aug 18 00:48:09 2012 +0200 @@ -1614,10 +1614,7 @@ uCursor.updatePosition(); {$ENDIF} z:= round(200/zoom); -if not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) then - if (not autoCameraOn) then - FollowGear:= nil - else +if not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) and autoCameraOn then if ((abs(CursorPoint.X - prevPoint.X) + abs(CursorPoint.Y - prevpoint.Y)) > 4) then begin FollowGear:= nil; diff -r 763d3961400b -r 3c4b4cb40f40 share/hedgewars/Data/Graphics/Flags/cpu_plain.png Binary file share/hedgewars/Data/Graphics/Flags/cpu_plain.png has changed diff -r 763d3961400b -r 3c4b4cb40f40 share/hedgewars/Data/Graphics/botlevels.png Binary file share/hedgewars/Data/Graphics/botlevels.png has changed diff -r 763d3961400b -r 3c4b4cb40f40 share/hedgewars/Data/Locale/en.txt --- a/share/hedgewars/Data/Locale/en.txt Sat Aug 18 00:47:51 2012 +0200 +++ b/share/hedgewars/Data/Locale/en.txt Sat Aug 18 00:48:09 2012 +0200 @@ -492,7 +492,7 @@ 04:36=Well, sometimes you're just too bad in aiming. Get|some assistance using modern day technology.|Attack: Activate 04:37=Don't fear the daylight. It will just last one turn|but will enable you to absorb the damage you do to|other hogs.|Attack: Activate 04:38=The sniper rifle can be the most devastating weapon|in your whole arsenal, however it's very ineffective|at close quarters. The damage dealt increases with|the distance to its target.|Attack: Shoot (twice) -04:39=Fly to other parts of the map using the flying|saucer. This hard to master utility is able to|take you to almost any position on the battlefield.|Attack: Activate|Up/Left/Right: Apply force in one direction|Long Jump: Drop grenades or similar weapons +04:39=Fly to other parts of the map using the flying|saucer. This hard to master utility can|take you to almost any position on the battlefield.|Attack: Activate|Up/Left/Right: Apply force in one direction|Long Jump: Drop grenades or similar weapons 04:40=Set some ground on fire using this bottle filled|with (soon to be) burning liquid.|Attack: Hold to shoot with more power 04:41=The evidence nature might even top the flying|saucer. Birdy can carry your hog around and|drop eggs on your enemies!|Be quick, as using Birdy eats into your turn|time!|Attack: Activate and drop eggs|Up/Left/Right: Flap in one direction 04:42=This portable portal device is capable|of instantly transporting you, your enemies,|or your weaponry between two points on the|terrain.|Use it wisely and your campaign will be a...|HUGE SUCCESS!|Attack: Shoot a portal|Switch: Cycle portal colours @@ -506,7 +506,7 @@ 04:50=Is someone hiding underground?|Dig them out with a drill strike!|Timer controls how far it will dig. 04:51=Get in a free shot by hurling a ball of mud.|Stings a bit, and knocks hogs back. 04:52=UNUSED -04:53=Go on an adventure through time and space,|while leaving your comrades to fight on alone.|Be prepared to return at any time,|or for Sudden Death or if they are all defeated.|Disclaimer. Does not function in Sudden Death,|if you are alone, or if you are a King. +04:53=Take a trip through time and space,|while leaving your comrades to fight on alone.|Be prepared to return at any time,|or for Sudden Death or if they are all defeated.|Disclaimer. Does not function in Sudden Death,|if you are alone, or if you are a King. 04:54=INCOMPLETE 04:55=Spray a stream of sticky flakes.|Build bridges, bury enemies, seal off tunnels.|Be careful you don't get any on you! diff -r 763d3961400b -r 3c4b4cb40f40 share/hedgewars/Data/Locale/hedgewars_zh_CN.ts --- a/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts Sat Aug 18 00:47:51 2012 +0200 +++ b/share/hedgewars/Data/Locale/hedgewars_zh_CN.ts Sat Aug 18 00:48:09 2012 +0200 @@ -2,325 +2,240 @@ - AmmoSchemeModel - - new - 新建 - - - copy of - 副本 - - - - DrawMapWidget - - File error - 文件错误 - - - Cannot open file '%1' for writing - 无法打开文件 '%1' 写入 - 无法打开要写入的文件 '%1' - - - Cannot read file '%1' - 无法读取文件 '%1' - - - FreqSpinBox + Never 从不 + Every %1 turn - 每 %1 个回合 + 每隔 %1 回合 GameCFGWidget + Error 错误 + Illegal ammo scheme 无法使用此弹药设置 + Edit schemes 修改游戏设置 - - Edit weapons - 修改武器 - - - When this option is enabled selecting a game scheme will auto-select a weapon - 使用此项则游戏框架自动选择武器配备 - - - Game Options - 游戏选项 - - HWChatWidget - - %1 *** %2 has been removed from your ignore list - %1 *** %2 已经从您的忽略列表中移除 - - - %1 *** %2 has been added to your ignore list - %1 *** %2 已经添加到您的忽略列表中 - - - %1 *** %2 has been removed from your friends list - %1 *** %2 已经从您的朋友列表中移除 - + GameUIConfig - %1 *** %2 has been added to your friends list - %1 *** %2 已经添加到您的朋友列表中 - - - %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 已从您的好友列表中移除 + + Error + 错误 - %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 + + Cannot create directory %1 + 不能创建路径 - StyleSheet discarded - 已丢弃样式表 - - - StyleSheet saved to %1 - 样式表已保存到 %1 + + Quit + 退出 - Failed to save StyleSheet to %1 - 保存样式表到 %1 失败 - - - %1 is not a valid command! - %1 不是一个有效的命令! - - - Kicking %1 ... - 正在踢出 %1 ... + + Cannot save options to file %1 + 不能把选项保存到 %1 HWForm + Error 错误 + + 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 - - - - Please select record from the list above - 请选择一个记录 - - - DefaultTeam - 默认队伍 - - - Hedgewars Demo File - File Types - 刺猬大作战回放文件 - - - Hedgewars Save File - File Types - 刺猬大作战存档文件 - - - 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 -在Hedgewars.org已注册 -请输入您的密码 -或从游戏配置中选择另一个昵称: - - - No password supplied. - 没有填写密码. - - - Nickname - 昵称 - - - Some one already uses - your nickname %1 -on the server. -Please pick another nickname: - 您的昵称 %1 -以被其他人 -在服务器上使用 -请选择另一个昵称: - - - No nickname supplied. - 没有填写昵称。 + 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 地图 + Themes 主题 + Filter 过滤 + All 全部 + Small 小型 + Medium 中型 + Large 大型 + Cavern 洞穴 + Wacky - 险峻 - - - Type - 类型 + 曲折 + + + HWNet - Small tunnels - 小型隧道 - - - Medium tunnels - 中型隧道 + + Error + 错误 - Large tunnels - 大型隧道 - - - Small floating islands - 小型漂浮岛屿 + + The host was not found. Please check the host name and port settings. + 未发现主机。请检查主机名和端口设置。 - Medium floating islands - 中型漂浮岛屿 + + Connection refused + 连接被拒绝 + + + + HWNetServer + + + Error + 错误 - Large floating islands - 大型漂浮岛屿 - - - Seed - 作种 - - - Set - 设定 + + Unable to start the server: %1. + 无法启动服务端: %1. HWNetServersModel + Title - 名称 + 标题 + IP IP + Port 端口 @@ -328,177 +243,109 @@ HWNewNet - The host was not found. Please check the host name and port settings. - 没找到主机。请检查主机名和端口设置。 + + Error + 错误 + + The host was not found. Please check the host name and port settings. + 错误没找到这个主机。请检查主机名和端口设置。 + + + Connection refused 连接被拒绝 + + *** %1 joined + *** %1 加入 + + + + *** %1 left + *** %1 离开 + + + + *** %1 left (%2) + *** %1 离开 (%2) + + + Quit reason: 退出原因: + Room destroyed 房间损坏 + You got kicked 被踢出 + Password - 密码 - - - Your nickname %1 is -registered on Hedgewars.org -Please provide your password -or pick another nickname: - 您的昵称%1 -在Hedgewars.org已注册 -请输入您的密码 -或选择另一个昵称: - - - %1 *** %2 has joined the room - %1 *** %2 进入这个房间了 - - - %1 *** %2 has joined - %1 *** %2 加入了 + 密码 - %1 *** %2 has left (%3) - %1 *** %2 离开了(%3) - - - %1 *** %2 has left - %1 *** %2 离开了 - - - Your nickname %1 is -registered on Hedgewars.org -Please provide your password below -or pick another nickname in game config: - 您的昵称%1 -在Hedgewars.org已注册 -请输入您的密码 -或从游戏配置中选择另一个昵称: - - - Nickname - 昵称 - - - User quit - 用户退出 + + Enter your password: + 输入你的密码: 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。 + SDL_ttf 返回错误-渲染文字失败,可能有关freetype2的bug。建议升级 freetype。 PageAdmin + Server message: - 服务器信息: - - - Set message - 设定信息 - - - Clear Accounts Cache - 清空账户缓存 - - - Fetch data - 获取数据 + 服务器信息: - Server message for latest version: - 最新版本的服务器信息: - - - Server message for previous versions: - 之前版本的服务器信息: - - - Latest version protocol number: - 最新版本的通讯协议号码: - - - MOTD preview: - MOTD预览: - - - Set data - 设定数据 + + Set message + 设定信息 PageConnecting + Connecting... 连接中... - - Cancel - 取消 - - - - PageDrawMap - - Undo - 取消 - - - Clear - 清除 - - - Load - 读取 - - - Save - 保存 - - - Load drawn map - 读取已经绘制的地图 - - - Drawn Maps (*.hwmap);;All files (*.*) - 绘制的地图 (*.hwmap);;全部文件 (*.*) - - - Save drawn map - 保存绘制的地图 - - - Drawn Maps - 绘制的地图 - - - All files - 全部文件 - PageEditTeam + + Discard + 中止 + + + + Save + 保存 + + + General 常规 + Advanced 进阶 @@ -506,393 +353,87 @@ 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>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>最佳射手是<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. - 最佳射手<b>%1</b>制造了<b>%2</b>点伤害。 - - - The best killer is <b>%1</b> with <b>%2</b> kills in a turn. + + <p>The best killer is <b>%1</b> with <b>%2</b> kills in a turn.</p> - 最佳杀手 <b>%1</b> 完成了单回合<b>%2</b>次击杀。 + <p>最佳杀手<b>%1</b>:却敌<b>%2</b></p> - A total of <b>%1</b> hedgehog(s) were killed during this round. - - 总共 <b>%1</b> 只刺猬在本轮失去生命。 - - - - (%1 kill) + + <p>A total of <b>%1</b> hedgehog(s) were killed during this round.</p> - (%1 击杀) - - - - (%1 kills) - (%1 击杀) - - - <b>%1</b> thought it's good to shoot his own hedgehogs with <b>%2</b> pts. - - <b>%1</b>以为给自己的刺猬造成 <b>%2</b> 点创伤是小意思。 + <p>有<b>%1</b>个刺猬在此局失去生命。</p> - - <b>%1</b> killed <b>%2</b> of his own hedgehogs. - - <b>%1</b> 整垮了 <b>%2</b> 只自己的刺猬。 - - - - <b>%1</b> was scared and skipped turn <b>%2</b> times. - - <b>%1</b> 受惊了,共计 <b>%2</b> 次放弃。 - - - - - PageInGame - - In game... - - 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 - 点击同色作为同一组的友军。控制权不分享,但是共同胜利/失败。 - - - 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 ropse? 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 - 如果您确定好了一个昵称不想让别人使用,那么在 http://www.hedgewars.org/. 注册一个帐号吧。 - - - 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 - 默认情况下游戏记录最后的游戏作为Demo,选择单机游戏——然后Demo——然后点击右下角开始回放或者整理。 - - - 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 - 刺猬大作战是一个开放源代码的免费软件,它充分利用了我们的业余时间。如果您有问题,到论坛来吧,不过7×24小时支持不可能! - - - 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 - 刺猬大作战是一个开放源代码的免费软件,它充分利用了我们的业余时间。与他人分享它吧! - - - From time to time there will be official tournaments. Upcoming events will be announced at http://www.hedgewars.org/ some days in advance. - Tips - 官方的竞赛一直存在。临近时去 http://www.hedgewars.org/ 即可看到。 - - - 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 被翻译成多种语言,中文是刺猬大作战——同样为翻译名。如果您的语言翻译有什么缺失/过时/遗漏或任何问题,来联系我们吧! - - - Hedgewars can be run on lots of different operating systems including Microsoft Windows, Mac OS X and Linux. - Tips - 刺猬大作战可以运行的操作系统包括:GNU/Linux、Mac OS X、MicroSoft Windows。 + + Multiplayer + 多人游戏 - 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 - 您可以建立自己的网络游戏/局域网游戏。不仅限于 "简单游戏" 选项。 - - - Create an account on http://www.hedgewars.org/ to keep others from using your most favourite nickname while playing on the official server. - Tips - 在官方服务器 http://www.hedgewars.org/ 建立自己的帐号——就能一直使用最喜欢的昵称 - - - 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 - 假如你的显卡不能提供OpenGL硬件加速,试着用降低效果的方式运行。 - - - 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 - 特别游戏模式“吸血“、”因果报应“需要全新的战术。现在自定义游戏里试试! + + Single Player + 单人游戏 - The Windows version of Hedgewars supports Xfire. Make sure to add Hedgwars to its game list so your friends can see you playing. - Tips - Windows版本的刺猬大作战支持Xfire。添加它到游戏列表里让您的朋友看到。 - - - 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 - 刺猬大作战适合短时间休息,不需要太多刺猬挤在大地图上。 + + Net game + 网络游戏 - No hedgehogs were harmed in making this game. - Tips - 在制作这款游戏时没有任何刺猬受到伤害。 - - - Connect one or more gamepads before launching the game to be able to assign their controls to your teams. - 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 - 刺猬大作战是开放源代码的免费软件,用我们的闲暇时间创造。如果有人卖给你,那么应该把钱拿回来! - - - Create an account on %1 to keep others from using your most favourite nickname while playing on the official server. - Tips - 在 %1 建立一个帐号阻止其他人使用你喜欢的名称在官方服务器游戏。 - - - There are three different jumps available. Tap [high jump] twice to do a very high/backwards jump. - Tips - 三种跳跃方式。点击[高跳]两次做出跳跃高度极限的后空翻。 + + Saved games + 存档 - 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. It's turn radius depends on it's 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 - 黏着地雷是创造小范围连锁反应的绝佳武器。 + + Demos + Demo - 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 Incinerating Grenade 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 - 想要知道谁是此游戏的幕后人员?点击主菜单的Hedgewars Logo就可以看到贡献者名单。 - - - Like hedgewars? Become a fan on %1 or join our group at %2. You could follow us on %3 as well! - Tips - 喜欢刺猬大作战(hedgewars)?那么加入我们 %1 或者 %2.。你可以在 %3 跟随我们! - - - 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 - 你可以在( 我的文档\Hedgewars)里找到设置文件。可以创建备份,但不要手动修改。 + + Setup + 设置 - 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 - 你可以在家目录找到 .hedgewars。可以创建备份,但不要手动修改。 - - - Connect one or more gamepads before starting the game to be able to assign their controls to your teams. - Tips - 在游戏开始前连接游戏手柄才能用它们操控你的队伍。 - - - If your graphics card isn't able to provide hardware accelerated OpenGL, try to update the associated drivers. - Tips - 加入你的显卡不能使用OpenGL硬件加速,请升级相应驱动。 - - - Like Hedgewars? Become a fan on %1 or join our group at %2. You could follow us on %3 as well! - Tips - 喜欢刺猬大作战(Hedgewars)吗?加入 %2 ,成为 %1 粉丝,也可以在 %3 跟随我们! - - - 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 - 保持显卡驱动最新避免可能的麻烦。 + + About + 关于 - 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 - 你可以关联刺猬大作战的相关文件(比如存档和回放)到本游戏以便在网络或文件浏览器中直接打开这些文件。 - - - 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 - 想要节省绳子?放开绳子之后再次发射,只要你不曾脱离绳子接触接触地面就可以继续使用同一根! - - - Like Hedgewars? Become a fan on %1 or follow us on %2! - Tips - 喜欢刺猬大作战Hedgewars吗?来 %1 或者 %2 追随我们吧! - - - 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 - 在家目录的"Library/Application Support/Hedgewars"找到刺猬的配置文件。备份随你,但是不要手动编辑。 + + Exit + 退出 - 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 - 在家目录的".hedgewars"找到刺猬的配置文件。备份随你,但是不要手动编辑。 - - - The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing. - Tips - Windows版本的刺猬大作战支持Xfire。您可以添加刺猬大作战到它的游戏列表里让您的朋友看到。 + + Local Game (Play a game on a single computer) + 本地游戏(在一台电脑上) - Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms. - Tips - 使用燃烧瓶或火焰喷射器可以短时阻止刺猬通过特定区域(比如隧道或平台). - - - The Homing Bee can be tricky to use. Its turn radius depends on its velocity, so try to not use full power. - Tips - 使用归巢的蜜蜂有些技巧,它的回转半径和发射速度有关,所以最好不要全力发射。 - - - Downloadable Content - 可下载内容 + + Network Game (Play a game across a network) + 网络游戏(通过网络) PageMultiplayer + + Back + 返回 + + + Start 开始 @@ -900,40 +441,43 @@ PageNet + + Local + 本地 + + + + Internet + Internet + + + Error 错误 - Please select server from the list above + + Please, select server from the list above 请选择一个服务器 PageNetGame + Control - 房间管理 - - - Error - 错误 - - - Please enter room name - 请键入房间名 - - - OK - 确定 + Ctrl PageNetType + LAN game 局域网游戏 + Official server 官方服务器 @@ -941,925 +485,681 @@ PageOptions + New team 新队伍 + Edit team 修改队伍设定 - Delete team - 删除队伍 - - - New weapon scheme - 新武器配置 - - - Edit weapon scheme - 修改武器配置 - - - Delete weapon scheme - 删除武器配置 - - - You can't edit teams from team selection. Go back to main menu to add, edit or delete teams. - 您不能在队伍选择界面修改队伍。请返回主页面进行添加、修改、删除队伍等操作。 + + Save + 保存 - New scheme - 新框架 - - - Edit scheme - 修改框架 + + Back + 返回 - Delete scheme - 删除框架 + + Weapons set + 新武器设定 - New weapon set - 新武器配置 - - - Edit weapon set - 修改武器配置 - - - Delete weapon set - 删除武器配置 + + Edit + 修改当前武器设定 PagePlayDemo + Error 错误 + + Please, select record from the list + 请从列表选择记录 + + + OK 确认 + Rename dialog 重命名对话框 + Enter new file name: 输入新的文件名: + Cannot rename to 不能改变名字 + Cannot delete file 不能删除文件 - - Please select record from the list - 请从列表选择记录 - PageRoomsList + Create 建立 + Join 加入 + Refresh 刷新 + Error 错误 + + Please, enter room name + 请键入房间名 + + + OK 确认 - Admin features - 管理员功能 - - - Room Name: - 房间名: - - - 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 是房主,他可以调整设置、开始游戏。 - - - 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 个队伍加入这个房间。 - - - - Please enter room name - 请键入房间名 - - - Please select room from the list + + Please, select room from the list 请从列表选中房间 - Random Maze - 随机迷宫 - - - State: - 游戏状态 - - - Rules: - 规则 - - - Weapons: - 武器 - - - Search: - 搜索 - - - Clear - 清除 - - - Warning - 警告 - - - The game you are trying to join has started. -Do you still want to join the room? - 你要加入的游戏已经开始了。 -还要进入房间吗? - - - %1 players online - - %1 个玩家在线 - + + Admin features + 管理员功能 PageScheme + New - 新模式 - - - Delete - 删除 - - - 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 indestructable border around the terrain - 添加不可毁坏地边界 - - - Lower gravity - 低重力 - - - Assisted aiming with laser sight - 激光瞄准辅助 - - - All hogs have a personal forcefield - 每个刺猬都有一个力场 - - - Enable random mines - 开启随机地雷 - - - Gain 80% of the damage you do back in health - 伤害的80%变成自身力量 - - - Share your opponents pain, share their damage - 分担你的对手的疼痛 - - - Your hogs are unable to move, put your artillery skills to the test - 你的刺猬不能移动,检验你射击技巧的时候到了 - - - Random - 随机 - - - Seconds - 秒钟 + 新游戏 - 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. - AI 死亡再生。 - - - 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. - 每个刺猬都有独立的弹药,而非团队分享。 - - - All (living) hedgehogs are fully restored at the end of turn - 所有活着的刺猬在回合结束时完全恢复健康 - - - You will not have to worry about wind anymore. - 不用担心风的影响了。 - - - Wind will affect almost everything. - 风无所不在。 - - - Copy - 备份 - - - Teams in each clan take successive turns sharing their turn time. - 在同一集团中的队伍在共用的回合时间里使用连续的回合。 - - - Add an indestructible border around the terrain - 添加不可毁坏地边界 - - - Add an indestructible border along the bottom - 在底部添加一个不可毁坏的边界 + + Delete + 删除 PageSelectWeapon + + Back + 返回 + + + Default 默认 + Delete 删除 - New - 新模式 + + Save + 保存 + + + + PageSimpleGame + + + Back + 返回 - Copy - 备份 + + Simple Game + 简单游戏 PageSinglePlayer - Simple Game (a quick game against the computer, settings are chosen for you) - 快速游戏 (使用预设对抗电脑) + + Simple Game + 简单游戏 + + + + Training + 训练 + + + + Multiplayer + 多人游戏 + + Saved games + 游戏存档 + + + + Demos + 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) + Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT - 训练模式 (一系列训练任务)。开发中 + 训练模式 (一系列训练任务)。开发中 + Demos (Watch recorded demos) Demo (观看记录的Demo) + Load (Load a previously saved game) 读取 (读取之前保存的游戏) - - Campaign Mode (...). IN DEVELOPMENT - 战役模式 ——开发中 - - - Campaign Mode (...) - 战役模式 (...) - - - Training Mode (Practice your skills in a range of training missions) - 训练模式(在一系列训练任务中练习你的技能) - - - - PageTraining - - No description available - 没有可用描述 - - - Select a mission! - 选择一个任务! - QAction + Kick - 踢出 + + Start 开始 + Restrict Joins 限制参与 + Restrict Team Additions - 限制增加团队 + 限制团队插件 + Info 信息 + Ban 屏蔽 - - Follow - 跟随 - - - Ignore - 忽略 - - - Add friend - 添加朋友 - - - Unignore - 取消忽略 - - - Remove friend - 移除朋友 - - - Update - 更新 - QCheckBox - Check for updates at startup - 启动时检查程序升级 + + Enable sound + 开启音效 - Enable sound - 开启游戏音效 - - + Fullscreen 游戏全屏幕 + + Forts mode + 城堡模式 + + + Show FPS 显示帧率 (FPS) + Alternative damage show 另一种伤害显示方式 + Enable music - 开启游戏音乐 + 开启音乐 + Frontend fullscreen - 前端界面全屏幕 - - - Append date and time to record file name - 记录名称中包含具体时间和日期 + 界面全屏幕 - Reduced quality - 降低显示效果 - - - Show ammo menu tooltips - 显示武器菜单提示 + + Divide teams + 分组 - Enable frontend sounds - 开启前端界面音效 + + Append date and time to record file name + 记录名称中包含具体时间日期 - Enable frontend music - 开启前端界面音乐 + + Solid land + 固实地面 - Frontend effects - 前端界面效果 + + Reduce Quality + 降低质量 QComboBox + generated map... 生成地图... + Human 玩家 - Level - Lv 级别 - - - (System default) - (系统默认) - - - generated maze... - 生成迷宫... - - - Mission - 任务 - - - Community - 社区 - - - Any - 任意 - - - In lobby - 大厅中 + + Level 5 + Lv 5 - In progress - 进行中 - - - Default - 默认 - - - Pro mode - 高手模式 - - - Shoppa - 绳子党 - - - Basketball - 篮球 - - - Minefield - 雷区 - - - Barrel mayhem - 炼狱场 - - - Tunnel hogs - 刺猬洞 - - - Crazy - 疯狂刺猬 + + Level 4 + Lv 4 - hand drawn map... - 手绘地图... - - - Disabled - 禁用 - - - Red/Cyan - 红/青 - - - Cyan/Red - 青/红 - - - Red/Blue - 红/蓝 - - - Blue/Red - 蓝/红 - - - Red/Green - 红/绿 - - - Green/Red - 绿/红 + + Level 3 + Lv 3 - Side-by-side - 横向排列 - - - Top-Bottom - 自顶向下 - - - Wiggle - - - - Red/Cyan grayscale - 红/青 灰度 + + Level 2 + Lv 2 - Cyan/Red grayscale - 青/红 灰度 - - - Red/Blue grayscale - 红/蓝 灰度 + + Level 1 + Lv 1 - Blue/Red grayscale - 蓝/红 灰度 - - - Red/Green grayscale - 红/绿 灰度 - - - Green/Red grayscale - 绿/红 灰度 + + Level + Lv 级别 QGroupBox + Team Members 成员 + + Team + 队伍 + + + Fort 城堡模式 + Key binds 键位绑定 + Teams 队伍 + Audio/Graphic options 音频/视频选项 + + Net nick + 昵称 + + + + Net options + 网络选项 + + + + Landscape + 地形 + + + + Game scheme + 游戏设置 + + + Playing teams 玩家队伍 + + Team level + 队伍级别 + + + Net game - 局域网络游戏 + 网络游戏 - Weapons - 武器 + + Servers list + 服务器列表 + + Weapons + 武器 + + + + Scheme options + 游戏设定 + + + Game Modifiers 游戏修改 + Basic Settings 基本设置 - - Team Settings - 队伍设定 - - - Misc - 杂项 - - - Schemes and Weapons - 游戏框架和武器配置 - 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> + + + Resolution 分辨率 + FPS limit FPS 上限 + 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 死亡模式倒计时 + + Case Probability + 箱子掉落几率 + + + Scheme Name: 设置名称: + Crate Drops 箱子降落 + Game scheme 游戏设置 - - Mines Time - 布雷时间 - - - Mines - 地雷 - - - % Dud Mines - % 地雷故障 - - - Name - 名称 - - - Type - 类型 - - - Grave - 墓碑 - - - Flag - 旗帜 - - - Voice - 声音 - - - Locale - Locale - - - Restart game to apply - 需要重新启动游戏方可应用 - - - Explosives - 爆炸物 - - - 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! - 当前运行的为开发版本,不同其他版本兼容。功能或许损坏、不完整。请自行承担风险! - - - Quality - 图像质量 - - - Sudden Death Water Rise - 死亡模式水位上涨 - - - Sudden Death Health Decrease - 死亡模式健康降低 - - - % Rope Length - % 绳长 - - - % Health Crates - % 生命箱 - - - Health in Crates - 生命箱的值数 - - - Gameplay - 游戏 - - - Stereo rendering - 立体渲染 - - - Style - 样式 - - - Scheme - 模式 - - - Password - 密码 - - - % Get Away Time - % 脱身时间 - - - This program is distributed under the GNU General Public License v2 - 本程序在GNU通用许可证协议第二版(GNU GPLv2)下发布 - QLineEdit + unnamed 无名 - - hedgehog %1 - 刺猬 %1 - QMainWindow + + -= by unC0Rr =- + -= by unC0Rr =- + + + + Hedgewars + 刺猬大作战 + + + Hedgewars %1 刺猬大作战 %1 @@ -1867,10 +1167,12 @@ QMessageBox + Error 错误 + Failed to open data directory: %1 Please check your installation @@ -1879,233 +1181,292 @@ 请检查 + Network 网络 + Connection to server is lost - 与服务器的连接丢失 + 服务器连接丢失 + Weapons 武器 + Can not delete default weapon set - 不能删除默认武器设定 + 不能删除默认武器设定 + Really delete this weapon set? 真的删除这个武器设定吗? + Can not edit default weapon set - 不能更改默认的武器设定 - - - Can not overwrite default weapon set '%1'! - 不能覆盖默认的武器配置 '%1'! - - - All file associations have been set. - 所有相关文件已经设定。 - - - Teams - 队伍 - - - Really delete this team? - 真的要删除队伍? - - - Schemes - 游戏框架 - - - Can not delete default scheme '%1'! - 无法删除默认游戏框架 '%1'! - - - File association failed. - 文件关联失败。 - - - Really delete this game scheme? - 真的删除此游戏框架? - - - Can not delete default weapon set '%1'! - 无法删除武器配置%1'! + 不能更改默认的武器设定 QObject + Error 错误 + Cannot create directory %1 无法创建路径 %1 - OK - 确认 + + Quit + 退出 - Nickname - 昵称 - - - Please enter your nickname - 请输入您的昵称 + + OK + 确认 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 删除 - Ready - 准备好了 + + Join official server + 加入官方服务器 - Random Team - 随机分配队伍 - - - Associate file extensions - 相关文件扩展 - - - more - 更多 + + Ready + 准备好了 QTableWidget - Room Name - 房间名 + + Room name + 房间名称 - C - 人数限制 - - - T - 时间限制 + + Players number + 玩家数量 - Owner - 创建者 + + Round in progress + 回合数 + + + + QToolBox + + + Actions + 行动 - Map - 地图 - - - Rules - 规则 - - + Weapons 武器 - - - SelWeaponWidget - Weapon set - 武器设置 - - - Probabilities - 空中支援几率 + + Weapon properties + 武器选项 - Ammo in boxes - 弹药箱 - - - Delays - 延迟回合数 - - - new - - - - copy of - 副本 + + Other + 其他 TCPBase + Error 错误 + Unable to start the server: %1. 无法开始服务端: %1. + Unable to run engine: %1 ( 无法运行引擎: %1 ( @@ -2113,678 +1474,362 @@ ToggleButtonWidget + Fort Mode 城堡模式 + Divide Teams 团体行动 + Solid Land 固实地面 + Add Border 添加边界 + Low Gravity 低重力 + Laser Sight 激光瞄准 + Invulnerable 刀枪不入 + Add Mines - 布置地雷 - - - Vampirism - 吸血鬼 - - - Karma - 因果报应 - - - Artillery - 射术 - - - Random Order - 随机顺序 - - - King - 国王模式 - - - Place Hedgehogs - 手动放置刺猬 - - - Clan Shares Ammo - 团队共享弹药 - - - Disable Girders - 禁止梁 - - - Disable Land Objects - 禁止地面物件 - - - AI Survival Mode - AI生存模式 - - - Unlimited Attacks - 无限攻击 - - - Reset Weapons - 重置武器 - - - Per Hedgehog Ammo - 每个刺猬的弹药 - - - Reset Health - 重置生命值 - - - Disable Wind - 禁止风力作用 - - - More Wind - 让风来地更猛烈吧 - - - Tag Team - 为队伍添加标签 - - - Add Bottom Border - 添加底部边界 + 布置地雷 binds + up + left + right + down + + jump + + + + attack 攻击 + put + switch 切换 + slot 1 slot 1 + slot 2 slot 2 + slot 3 slot 3 + slot 4 slot 4 + slot 5 slot 5 + slot 6 slot 6 + slot 7 slot 7 + slot 8 slot 8 + timer 1 sec 定时1秒 + timer 2 sec 定时2秒 + timer 3 sec 定时3秒 + timer 4 sec 定时4秒 + timer 5 sec 定时5秒 + capture - 截取 + 夺取 + quit 退出 + find hedgehog - 寻找刺猬 + 找到 刺猬 + ammo menu 弹药菜单 + volume down 降低音量 + volume up 提高音量 + change mode 改变模式 + pause 暂停 + slot 9 slot 9 + hedgehogs info 刺猬大作战 信息 + chat 聊天 + chat history 聊天记录 + confirmation 确认 + precise aim 练习瞄准 - - zoom in - 放大 - - - zoom out - 缩小 - - - reset zoom - 重置 - - - long jump - 远跳 - - - high jump - 高跳 - - - slot 10 - slot 10 - - - - 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: - 切换刺猬头顶标签的显示方式: - - binds (keys) - - Axis - Axis轴 - + teams - (Up) - (上) - - - (Down) - (下) - - - Hat - 帽子 + + Hedgehogs + 刺猬 - (Left) - (左) - - - (Right) - (右) - - - Button - 按键 - - - Keyboard - 键盘 - - - Mouse: Left button - 鼠标:左键 + + hedgehog 1 + 刺猬 1号 - Mouse: Middle button - 鼠标:中键 - - - Mouse: Right button - 鼠标:右键 - - - Mouse: Wheel up - 鼠标滚轮:向上 - - - Mouse: Wheel down - 鼠标滚轮:向下 + + hedgehog 2 + 刺猬 2号 - Backspace - 退格键 - - - Tab - Tab + + hedgehog 3 + 刺猬 3号 - Clear - Num Lock / Clear + + hedgehog 4 + 刺猬 4号 - Return - 回车 - - - Pause - 暂停键 - - - Escape - ESC键(退出键) + + hedgehog 5 + 刺猬 5号 - Space - 空格键 - - - Delete - Del(删除键) - - - Numpad 0 - 小键盘0 - - - Numpad 1 - 小键盘1 + + hedgehog 6 + 刺猬 6号 - Numpad 2 - 小键盘2 - - - Numpad 3 - 小键盘3 + + hedgehog 7 + 刺猬 7号 - Numpad 4 - 小键盘4 - - - Numpad 5 - 小键盘5 - - - Numpad 6 - 小键盘6 + + hedgehog 8 + 刺猬 8号 - Numpad 7 - 小键盘7 - - - Numpad 8 - 小键盘8 - - - Numpad 9 - 小键盘9 - - - Numpad . - 小键盘. - - - Numpad / - 小键盘/ + + Goddess + 女神 - Numpad * - 小键盘* - - - Numpad - - 小键盘- + + Isis + 艾希丝 - Numpad + - 小键盘+ + + Astarte + 阿斯德尔特 - Enter - 回车键 - - - Equals - 等于 - - - Up - + + Diana + 黛安娜 - Down - - - - Right - - - - Left - - - - Insert - 插入键 + + Aphrodite + 阿弗罗狄特 - Home - Home键 - - - End - End键 - - - Page up - 向上翻页键 - - - Page down - 向下翻页键 - - - Num lock - 小键盘数字锁 + + Hecate + 赫卡特 - Caps lock - 大小写切换键 - - - Scroll lock - Scroll Lock键 - - - Right shift - 右Shift键 - - - Left shift - 左Shift键 + + Demeter + 得墨忒耳 - Right ctrl - 右Ctrl键 - - - Left ctrl - 左Ctrl键 + + Kali + 迦梨 - Right alt - 右Alt键 + + Inanna + 維納斯 - Left alt - 左Alt键 - - - Right meta - 右meta键 - - - Left meta - 左meta键 + + Fruits + 水果 - A button - A 键 - - - B button - B 键 - - - X button - X 键 - - - Y button - Y 键 + + Banana + 香蕉 - LB button - LB 键 - - - RB button - RB 键 + + Apple + 苹果 - Back button - 返回键 - - - Start button - 开始键 - - - Left stick - 左摇杆 - - - Right stick - 右摇杆 + + Orange + 橙子 - Left stick (Right) - 右(左摇杆) - - - Left stick (Left) - 左(左摇杆) + + Lemon + 柠檬 - Left stick (Down) - 下(左摇杆) - - - Left stick (Up) - 上(左摇杆) - - - Left trigger - 左制动 + + Pineapple + 菠萝 - Right trigger - 右制动 - - - Right stick (Down) - 下(右摇杆) + + Mango + 芒果 - Right stick (Up) - 上(右摇杆) + + Peach + 桃子 - Right stick (Right) - 右(右摇杆) - - - Right stick (Left) - 左(右摇杆) - - - DPad - DPad板 + + Plum + 梅子 diff -r 763d3961400b -r 3c4b4cb40f40 share/hedgewars/Data/Locale/zh_CN.txt --- a/share/hedgewars/Data/Locale/zh_CN.txt Sat Aug 18 00:47:51 2012 +0200 +++ b/share/hedgewars/Data/Locale/zh_CN.txt Sat Aug 18 00:48:09 2012 +0200 @@ -1,825 +1,47 @@ ; Simplified Chinese locale 00:00=手榴弹 -00:01=集束炸弹 -00:02=火箭筒 -00:03=归巢的蜜蜂 -00:04=霰弹枪 -00:05=大锤 -00:06=跳过回合 +00:01=子母炸弹 +00:02=火箭炮 +00:03=UFO +00:04=散弹枪 +00:05=气锤 +00:06=掠过 00:07=绳索 00:08=地雷 00:09=沙漠之鹰 00:10=炸药 00:11=球棒 -00:12=Shoryuken +00:12=升龙拳 00:13=秒 00:14=降落伞 00:15=空袭 -00:16=地雷空袭 +00:16=地雷袭击 00:17=喷灯 -00:18=钢梁 +00:18=钢板 00:19=传送 -00:20=切换刺猬 +00:20=切换 00:21=迫击炮 00:22=鞭子 00:23=神风特工队 00:24=蛋糕 -00:25=引诱 +00:25=吸引 00:26=西瓜炸弹 00:27=地狱礼花 -00:28=钻头火箭 +00:28=钻地火箭 00:29=弹珠炮 -00:30=汽油弹空袭 -00:31=遥控轰炸机 +00:30=燃烧弹 +00:31=轰炸机 00:32=低重力 -00:33=增强伤害 -00:34=无敌 +00:33=附加伤害 +00:34=刀枪不入 00:35=加时 00:36=激光瞄准 -00:37=吸血 -00:38=狙击枪 -00:39=UFO -00:40=燃烧瓶 -00:41=鸟儿 -00:42=传送器 -00:43=飞来的钢琴 -00:44=毒奶酪 -00:45=正弦能量炮 -00:46=火焰喷射器 -00:47=固定地雷 -00:48=大锤 -00:49=复苏 -00:50=电钻空袭 -00:51=土块 -01:00=开战! -01:01=平局 -01:02= %1 胜利! +01:00=战斗啦! +01:01=平手 +01:02= %1 胜! 01:03=音量 %1% 01:04=暂停 -01:05=确定要退出? (是Y/否Esc) -01:06=死亡模式! -01:07=%1 剩余 -01:08=燃料 -01:09=同步中... -01:10=使用本工具不会结束回合! -01:11=您还不能用它! -01:12=死亡模式前最后一回合! -01:13=%1 回合倒计时! -01:14=预备上, %1! - -; Event messages -; Hog (%1) died -; 02:00=%1 has kicked the bucket! -02:00=%1 翘辫子了! -; 02:00=%1 has seen the light! -02:00=%1 目睹圣光降临! -; 02:00=%1 never saw that coming! -02:00=%1 无法瞑目! -; 02:00=%1 waves goodbye! -02:00=%1 向大家挥手道别。 -; 02:00=%1 has gone to a better place! -02:00=%1 去了极乐世界! -; 02:00=%1 meets his maker! -02:00=%1 去见造物主了! -; 02:00=%1 can hang on no longer! -02:00=%1 再也受不了了! -; 02:00=%1 has done his duty! -02:00=%1 完成了他的使命! -; 02:00=%1 makes the ultimate sacrifice! -02:00=%1 做了最大的牺牲! -; 02:00=%1 departs this mortal coil! -02:00=%1 摆脱了躯壳的束缚! -; 02:00=%1 makes like a tree and leaves! -02:00=%1 叶落归根。 -; 02:00=%1 has timed out! -02:00=%1 大限已至。 -; 02:00=%1 says peace out! -02:00=%1 悄然离场了。 -; 02:00=%1 will be fondly remembered! -02:00=%1 永远活在我们心中! -; 02:00=%1 has an aneurysm! -02:00=%1 不治而亡。 -; 02:00=%1 leaves behind a wife and child -02:00=%1 留下一家孤儿寡母 -; 02:00=%1 has launched his last bazooka -02:00=%1 发射了最后一发火箭弹 -; 02:00=%1 has tossed his last grenade -02:00=%1 扔出了最后一枚手榴弹 -; 02:00=%1 has baked his last cake -02:00=%1 烘烤了最后一块蛋糕 -; 02:00=%1 has swung on his last rope -02:00=%1 最后一次甩出了绳索 -; 02:00=%1 has called his last airstrike -02:00=%1 最后一次呼叫空袭 -; 02:00=%1 has pumped his last shotgun -02:00=%1 最后一次抽出了霰弹枪 -; 02:00=%1 has thrown his last melon -02:00=%1 最后一次扔出了西瓜炸弹 -; 02:00=%1 has drawn his last deagle -02:00=%1 最后一次拔出了沙漠之鹰 -; 02:00=%1 took one shot too many -02:00=%1 挨了太多枪子了 -; 02:00=%1 could really have used a health crate -02:00=%1 真该用下医疗包的 -; 02:00=%1 has gone to play a better game -02:00=%1 去玩更有意思的游戏去了 -; 02:00=%1 has ragequit life -02:00=%1 拔网线了! -; 02:00=%1 fails -02:00=%1 失败了 -; 02:00=Poor poor %1... -02:00=可怜的 %1... -; 02:00=%1 prefers wormux -02:00=%1 更喜欢 Warmux -; 02:00=%1 has been blocking shots with his face -02:00=%1 勇于面对子弹,结果相当惨烈 -; 02:00=%1 is a hero amongst me...err..hogs -02:00=%1 是位英雄……额……在刺猬当中 -; 02:00=%1 finds his place in Valhalla -02:00=%1 在勇者纪念碑上找到了自己的位置 -; 02:00=%1 has left the building -02:00=%1 离开了这间屋子 -; 02:00=%1 goes the way of the dinosaurs -02:00=%1 步上了恐龙的道路 -; 02:00=%1 brings hedgehogs one step closer to extinction -02:00=%1 让刺猬向物种灭绝更近了一步 -; 02:00=%1 brings a tear to my eye -02:00=%1 带走了我一滴眼泪 -; 02:00=%1 is an ex-hog -02:00=%1 生前是一只刺猬 -; 02:00=%1 is pushing up the daisies -02:00=%1 被菊花簇拥 -; 02:00=%1 has ceased to be -02:00=%1 被删除了 -; 02:00=Say goodbye to %1 -02:00=对 %1 说再见 -; 02:00=No hope left for %1 -02:00=%1 没有希望了 -; 02:00=%1 faces the final curtain -02:00=%1 面容被落下的帷幕遮住了 -; 02:00=Smoke 'em if you got 'em, %1 -02:00=%1 抓紧时间实现你最后的愿望吧 -; 02:00=%1 suffers a Spontaneous Massive Existence Failure -02:00=%1 遭遇了自发性大规模故障 -; 02:00=%1 has passed on -02:00=%1 走了 -; 02:00=%1 is stone dead -02:00=%1 永垂不朽 -; 02:00=%1 is no more -02:00=%1 不在了 -; 02:00=%1 has expired -02:00=%1 已故 -; 02:00=Bereft of life, %1 rests in peace -02:00=%1 安详地躺着 -; 02:00=%1 joins the choir invisible -02:00=%1 加入了隐形唱诗班 -; 02:00=Farewell %1, we hardly knew ye! -02:00=%1, 永别了,我们还没熟悉你呢! -; 02:00=%1 had a low tolerance for being shot -02:00=%1 抗打击能力不足 -; 02:00=%1 could have used an extra life -02:00=%1 本该有第二条命的 -; 02:00=Is there a doctor in the house? -02:00=这里有医生吗? - -; Hog (%1) drowned -; 02:01=%1 plays submarine! -02:01=%1 去玩潜水艇了! -; 02:01=%1 mimics the Titanic! -02:01=%1 学泰坦尼克去了! -; 02:01=%1 swims like a stone! -02:01=%1 石沉大海! -;02:01=%1 checks out the deep end -02:01=%1 说要去检查深水区 -;02:01=%1 goes glug glug glug -02:01=%1 :“咕噜咕噜咕噜……” -;02:01=%1 goes splash -02:01=%1 栽入水花里 -;02:01=%1 forgot his armbands -02:01=%1 忘记了戴臂章 -;02:01=%1 really should have taken swimming lessons -02:01=%1 真的该去学游泳的 -;02:01=%1 left his surfboard at home -02:01=%1 把救生圈忘家了 -;02:01=%1 is washed up -02:01=%1 被冲走了 -;02:01=%1 is one soggy hog -02:01=%1 脑子进水了 -;02:01=%1 forgot to bring his life jacket -02:01=%1 忘记带救生衣了 -;02:01=%1 goes splish splash splish -02:01=%1 实现了水上飘,身后一片水花荡漾 -;02:01=%1 is sleeping with the fishes -02:01=%1 将会和鱼睡在一起 -;02:01=%1 thinks the water physics suck in this game -02:01=%1 认为这游戏关于落水的设定糟糕透了 -;02:01=%1 looks thirsty -02:01=%1 看样子很渴 -;02:01=the sea claims %1 -02:01=大海吞没了 %1 -;02:01=%1 is lost at sea -02:01=%1 在海上迷失了 -;02:01=%1 should have brought his scuba gear -02:01=%1 应该要带潜水工具的 -;02:01=%1 gets a burial at sea -02:01=%1 享受到了海葬待遇 -;02:01=%1 has that sinking feeling -02:01=%1 觉得自己在下沉 -;02:01=%1 is practicing his backstroke -02:01=%1 终于能实践自己的游泳理论了 -;02:01=%1 goes in search of the Titanic -02:01=%1 去泰坦尼克号寻宝了 -;02:01=%1 is not Jesus -02:01=很遗憾 %1 不是耶稣 -;02:01=%1 is finding Nemo -02:01=%1 正在寻找Nemo -;02:01=%1 springs a leak -02:01=%1 钻入了一个水洼 -;02:01=You've gotta wonder how many hogs are down there -02:01=你会知道海底还会有多少同伴的 -;02:01=%1 makes the ocean slightly higher -02:01=%1 让海平面高了那么一点, 就一点 -;02:01=%1 didn't enlist in the Navy -02:01=很明显 %1 没在海军服役过 -;02:01=%1 is doing his impersonation of a dead fish -02:01=%1 其实是在模仿死鱼啦 -;02:01=At least you didn't go down the toilet, %1 -02:01=还好 %1 你不是掉进了厕所 -;02:01=Sonic couldn't swim and neither can %1 -02:01=索尼克不能游泳, %1 也一样 -;02:01=%1 wants to play Ecco the dolphin -02:01=%1 想玩海底漫步 -;02:01=%1 has gone to visit Aquaria -02:01=%1 去水族馆报到了 -;02:01=%1 has found the lost city of Atlantis -02:01=%1 找到了传说中的亚特兰蒂斯城 -;02:01=%1 aims for the lead role in Bioshock 3 -02:01=%1 立志在生化奇兵3中担任头号角色 -;02:01=Your doggy paddle could use a little work, %1 -02:01=你的狗刨式会有点用的, %1 -;02:01=%1 should have brought a jet ski -02:01=%1 竟然没带摩托艇 -;02:01=%1 doesn't like watersports -02:01=%1 不喜欢水上运动 -;02:01=%1 is forever blowing bubbles -02:01=%1 学会了绝技: 神风吹泡泡 -;02:01=%1 is short of a raft -02:01=%1 需要一个救生艇 -;02:01=%1 thinks salt water is good for the skin -02:01=%1 认为盐水对皮肤有好处 -;02:01=%1 gets salt water in his wounds -02:01=%1 的伤口沾上了盐水 -;02:01=%1 has walked the plank -02:01=%1 错过了那块木板 -;02:01=%1 has a bath -02:01=%1 洗澡去了 -;02:01=%1 is wet wet wet -02:01=%1 全身都是水,水,水…… -;02:01=%1 gets his quills wet -02:01=%1 把刺全弄湿了 -;02:01=It's Davy Jones' locker for %1 -02:01=深海阎王正在等待 %1 - -; Round starts -; 02:02=Let's fight! -02:02=开战吧! -; 02:02=Armed and ready! -02:02=武装准备! -;02:02=Let's get ready to rumble! -02:02=准备对轰! -;02:02=Let's get it on! -02:02=为胜利而战吧! -;02:02=Let's get this party started -02:02=让我们开始这个派对吧 -;02:02=Last hog standing wins -02:02=胜利属于最后一个生还者 -;02:02=Let's go! -02:02=出发吧! -;02:02=Let's rock! -02:02=一起摇滚吧! -;02:02=Let's jam! -;02:02=It's beginning... -02:02=开始了... -;02:02=This is the start of something big -02:02=这是一个伟大的开始 -;02:02=Welcome to Hedgewars -02:02=欢迎来到刺猬大作战 -;02:02=Welcome to the front lines -02:02=欢迎来到前线 -;02:02=Crush your enemies! -02:02=目标:粉碎你的敌人! -;02:02=May the best hog win -02:02=祝愿胜利属于最厉害的刺猬! -;02:02=Victory or death -02:02=胜利或死亡 -;02:02=To the victor goes the spoils -02:02=战利品只属于胜利者 -;02:02=Losing is not an option -02:02=字典里面应该没有"输"这个字的 -;02:02=Cry havoc! Let loose the hogs of war! -02:02=放声喊吧! 这是刺猬的战争! -;02:02=Hedgewars, brought to you by Hedgewars.org -02:02=欢迎来到刺猬大作战, Hedgewars.org 为你呈现 -02:02=GL HF -;02:02=Just count yourself lucky you're not up against Tiyuri -02:02=你看你多幸运不是在对战 Tiyuri -;02:02=Just count yourself lucky you're not up against unC0Rr -02:02=你看你多幸运不是在对战 unC0Rr -;02:02=Just count yourself lucky you're not up against Nemo -02:02=你看你多幸运不是在对战 Nemo -;02:02=Just count yourself lucky you're not up against Smaxx -02:02=你看你多幸运不是在对战 Smaxx -;02:02=Just count yourself lucky you're not up against Jessor -02:02=你看你多幸运不是在对战 Jessor -;02:02=Give it your all! -02:02=展现你的一切吧! -;02:02=The losers do the cleaning up! -02:02=输的要罚扫厕所! -;02:02=Let the fight of the millenium begin -02:02=宇宙之战开始了 -;02:02=Let the fight of the century begin -02:02=世纪之战开始了 -;02:02=Let the fight of the decade begin -02:02=正义之战开始了 -;02:02=Let the fight of the year begin -02:02=年度争霸战开始了 -;02:02=Let the fight of the month begin -02:02=本月之星争霸战开始了 -;02:02=Let the fight of the week begin -02:02=每周擂主争霸战开始了 -;02:02=Let the fight of the day begin -02:02=本日最强入围赛开始了 -;02:02=Let the fight of the hour begin -02:02=我们能战一小时! -;02:02=Do your best! -02:02=诸君努力! -;02:02=Destroy the enemy! -02:02=目标: 摧毁敌人 -;02:02=Good luck -02:02=祝你好运 -;02:02=Have fun~ -02:02=开心玩~ -;02:02=Fight the good fight -02:02=漂亮的战斗 -;02:02=Fight dirty -02:02=不择手段 -;02:02=Fight with honour -02:02=满载荣誉而战 -;02:02=Don't give up -02:02=教练告诉你: 别放弃 -;02:02=Never surrender -02:02=永不屈服! -;02:02=Rock 'em and sock 'em! -02:02=蹂虐对手 -;02:02=Let the fragfest begin! -02:02=积分赛开始! -;02:02=I hope you're ready for a tussle! -02:02=你准备好恶战了么? -;02:02=Go Go Go! -02:02=冲冲冲! -;02:02=Hedgehogs advance! -02:02=刺猬向前冲! -;02:02=Bring it to them! -02:02=炸飞他们! -;02:02=Have no fear! -02:02=无所畏惧! -;02:02=Be brave and conquer -02:02=敢于征服! - -; Round ends (win; unused atm) -02:03=回合结束(胜利) - -; Round ends (draw; unused atm) -02:04=回合结束(平局) - -; New health crate -;02:05=Incoming aid! -02:05=医疗包! -;02:05=Medic! -02:05=急救包! -;02:05=First aid from the skies! -02:05=救援物资空运来了! -;02:05=A health pack for you -02:05=你的医疗包到了 -;02:05=Good health.. in box form! -02:05=生命就在那箱子里! -;02:05=The doctor calls -02:05=医生的紧急呼叫 -;02:05=Fresh band-aids! -02:05=新鲜创可贴! -;02:05=This will make you feel better -02:05=吃了这个感觉会好些的... -;02:05=A Hi-Potion! Whoops wrong game -02:05=兴奋剂!呃。。。走错地方了 -;02:05=A pick-me-up! -02:05=万金油! -;02:05=Grab it -02:05=捉住它 -;02:05=A healthy snack -02:05=健康食品 -;02:05=A remedy to pain -02:05=止痛饼来了 -;02:05=Correct Dosage: as many as you can find! -02:05=使用方法: 吃得越多越好 -;02:05=Urgent delivery -02:05=紧急物资 -;02:05=Supplies! -02:05=补给! - -; New ammo crate -; 02:06=More weapons! -02:06=武器! -;02:06=Reinforcements! -02:06=增援! -;02:06=Lock and load! -02:06=准备! -;02:06=I wonder what weapon is in there? -02:06=我要的那个会在的吧... -;02:06=Supplies! -02:06=补给! -;02:06=What could be inside? -02:06=里面会有啥呢? -;02:06=Christmas comes early in Hedgewars -02:06=刺猬大作战每天都是圣诞节 -;02:06=A present! -02:06=礼物送到! -;02:06=Special delivery! -02:06=特快专递! -;02:06=It was a nightmare getting this through customs -02:06=本局的噩梦来了 -;02:06=Destructive toys from the heavens -02:06=玩具从天堂掉下来了 -;02:06=Warning! Contents Volatile -02:06=警告! 内含危险物品 -;02:06=Pick it up or blow it up, choice is yours -02:06=拿走或打爆, 随你 -;02:06=Goodies! -02:06=好玩意儿! -;02:06=Mmmmm Ammo -02:06=弹药!!!! -;02:06=A box of destructive power -02:06=潘朵拉之盒 -;02:06=Airmail! -02:06=天降之物! -;02:06=Whatever's in that box, it ain't pizza -02:06=无论里面是啥, 那肯定不会是软妹子 -;02:06=Get it! -02:06=拿走它! -;02:06=Weapon drop incoming -02:06=武器掉下来了! -;02:06=Don't let the enemy grab that! -02:06=别让敌人拿了! -;02:06=Shiny new toys! -02:06=新玩具! -;02:06=A mysterious box! -02:06=神秘的箱子! - -; New utility crate -; 02:07=Tooltime! -02:07=工具箱! -;02:07=This could come in handy... -02:07=这可能派上用场 -;02:07=Utilities! -02:07=工具! -;02:07=Utilise this box -02:07=工具在这里! -;02:07=Watch out below -02:07=快看这里! -;02:07=More utilities! -02:07=更多选择更多欢笑, 尽在工具包 -;02:07=Tools for you! -02:07=一堆工具, 送给你! -;02:07=This should be good! -02:07=这看见起来蛮好... -;02:07=Use this wisely -02:07=使用这个才是明智的选择 -;02:07=Ooo this box is heavy -02:07=好重...好重... -;02:07=You might need this -02:07=会有用的 - -; Hog (%1) skips his turn -; 02:08=%1 is sooo boring... -02:08=%1 太无聊了... -;02:08=%1 couldn't be bothered -02:08=%1 不想被打扰! -;02:08=%1 is one lazy hog -02:08=%1 太懒了 -;02:08=%1 is thoughtless -02:08=%1 太轻率了 -;02:08=%1 gave up -02:08=%1 放弃了 -;02:08=You snooze you lose, %1 -02:08=不认真你就输了, %1 -;02:08=%1 shamelessly skips -02:08=%1 无耻的跳过了本回合 -;02:08=%1 is really lazy -02:08=%1 真的太懒了 -;02:08=%1 needs a little more motivation -02:08=%1 没有动力了 -;02:08=%1 is a pacifist -02:08=%1 是和平主义者 -;02:08=%1 has a breather -02:08=%1 需要喘息一下 -;02:08=%1 has a rest -02:08=%1 需要休息 -;02:08=%1 chills out -02:08=%1 发冷了 -;02:08=%1 has no faith in his own abilities -02:08=%1 做啥都没信心了 -;02:08=%1 decides to do nothing at all -02:08=%1 决定啥都不做 -;02:08=%1 lets the enemy destroy itself -02:08=%1 认为敌人会自杀的 -;02:08=%1 would be terrible at parties -02:08=%1 将会陷入可怕的事件中 -;02:08=%1 hides out -02:08=%1 说:“你看不到我,你看不到我……” -;02:08=%1 has decided to pass on this opportunity -02:08=%1 已经决定放弃这个机会 -;02:08=%1 decides the best thing he can do is...nothing -02:08=%1 决定他现在最应该做的是......坐着不动 -;02:08=%1 is a big wuss -02:08=%1 大笨蛋! -;02:08=Buck Buck Buck, %1 is a chicken -02:08=%1 是小鸡鸡 -;02:08=%1 is looking a little yellow -02:08=%1 看来有点印堂发黑 -;02:08=%1 is a coward! -02:08=%1 是懦夫! -;02:08=%1 is waiting for sudden death -02:08=%1 在等待突然死亡模式 -;02:08=%1 is not the fighting type -02:08=%1 不是战斗系的 -;02:08=%1 is reconsidering his purpose in life -02:08=%1 正在重新寻找他的人生 -;02:08=%1 was never much of a good shot anyway -02:08=%1 从来没一次打准的 -;02:08=%1 didn't want to join the army in the first place -02:08=%1 不想参军 -;02:08=Stop wasting our time, %1 -02:08=别浪费时间了! %1 -;02:08=I'm dissapointed in you, %1 -02:08=我对你失望了, %1 -;02:08=Come on, you can do better than that %1 -02:08=%1 明明就能做的更好的 -;02:08=%1's will has broken -02:08=%1 会被打飞的 -;02:08=%1 apparently has better things to do -02:08=%1 显然有更好的事情等着做 -;02:08=%1 is scared stiff -02:08=%1 怕刺激 -;02:08=%1 has fallen asleep -02:08=%1 睡着了 - -; Hog (%1) hurts himself only -; 02:09=%1 should practice aiming! -02:09=%1 该练练瞄准了! -; 02:09=%1 seems to hate himself. -02:09=%1 似乎看自己很不爽。 -; 02:09=%1 is standing on the wrong side! -02:09=%1 在表演乌龙! -; 02:09=%1 makes like an emo -02:09=%1 以为自己无敌 -; 02:09=%1 was holding his weapon the wrong way around -02:09=%1 好像把武器拿错方向了 -;02:09=%1 is a little sadistic -02:09=%1 有点施虐狂 -;02:09=%1 is a masochist -02:09=%1 是受虐狂 -;02:09=%1 has no instinct of self-preservation -02:09=%1 根本不会自我保护 -;02:09=%1 messed up -02:09=%1 乱套了 -;02:09=%1 screwed up -02:09=%1 搞砸了 -;02:09=That was a poor shot, %1 -02:09=%1 这一发真渣 -;02:09=%1 is a little too careless with dangerous weapons -02:09=%1 太不小心用那些危险的玩意了 -;02:09=%1 should consider a change of career -02:09=%1 正在考虑转职 -;02:09=Worst. Shot. Ever! -02:09=更差! 最差! 非常差! -;02:09=No no no %1, you shoot at the ENEMY! -02:09=No no no %1, 你要打敌人! -;02:09=%1 should only be destroying the enemy -02:09=%1 应该消灭敌人才对 -;02:09=%1 moves one step closer to suicide -02:09=%1 正在走向自杀 -;02:09=%1 aids the enemy -02:09=%1 帮助敌人 -;02:09=That was stupid %1 -02:09= %1 是笨蛋 -;02:09=%1 lives by the mantra of "no pain, no gain" -02:09=%1 贯彻“不付出,何收获“的原则 -;02:09=%1 is confused -02:09=%1 思维混乱了 -;02:09=%1 hurt itself in its confusion -02:09=%1 在混乱中攻击自己 -;02:09=%1 has a knack for embarrassing himself -02:09=%1 正在为自己尴尬 -;02:09=%1 is a klutz! -02:09=%1 就是一个笨蛋! -;02:09=%1 is clumsy -02:09=%1 笨手笨脚的 -;02:09=%1 shows the enemy what he's capable of -02:09=%1 展示了自己的能力 -;02:09=%1 can't be expected to be perfect all the time -02:09=%1 不能每次都完美 -;02:09=Don't worry %1, pobody's nerfect -02:09=不用担心 %1 , 人都不是完美的 -;02:09=%1 totally did that on purpose -02:09=%1 这么做真的是有目的 -;02:09=I won't tell anyone if you don't, %1 -02:09=我不会把 %1 的事情到处说的 -;02:09=How embarrassing! -02:09=何等的失态! -;02:09=I'm sure nobody saw that %1 -02:09=保证,决没人看到 %1 做什么 -;02:09=%1 needs to review his field manual -02:09=%1 需要复习说明书 -;02:09=%1's weapon clearly malfunctioned -02:09=%1 的武器很明显坏了 - -; Hog shot an home run (using the bat and another hog) -; 02:10=Home Run! -02:10=全垒打! -; 02:10=A bird, a plane, ... -02:10=一只鸟,一架飞机,... -; 02:10=That one is out! -02:10=那一位出界了! - -; Hog (%1) has to leave (team is gone) -02:11=%1 必须上床了 -02:11=%1 玩的过火了,休息一下 -02:11=发射!这位已经被送出去 -02:11=%1 必须走了 - -; Weapon Categories -03:00=定时手雷 -03:01=定时手雷 -03:02=弹道武器 -03:03=制导武器 -03:04=枪 (多发子弹) -03:05=钻孔工具 -03:06=动作 -03:07=移动工具 -03:08=接近式炸弹 -03:09=枪 (多发子弹) -03:10=BOOM! -03:11=咚! -03:12=武术 -03:13=未使用 -03:14=移动工具 -03:15=空投打击 -03:16=空投打击 -03:17=打洞工具 -03:18=工具 -03:19=移动工具 -03:20=动作 -03:21=弹道武器 -03:22=叫我主人! -03:23=武术 (真的!) -03:24=蛋糕不是谎言! -03:25=化妆的诱惑 -03:26=果汁手雷 -03:27=烫手手雷 -03:28=弹道武器 -03:29=弹道武器 -03:30=空投打击 -03:31=遥控飞机(不是玩具!) -03:32=临时效果 -03:33=临时效果 -03:34=临时效果 -03:35=临时效果 -03:36=临时效果 -03:37=临时效果 -03:38=枪 (多发子弹) -03:39=移动工具 -03:40=燃烧弹 -;03:41=Huge fan of Squawks -03:41=粉丝的呼喊 -;03:42=I'm making a note here... -03:42=我将在此做一记录... -; the misspelled "Beethoven" is intentional (-> to beat) -;03:43=Performing Beathoven's deadly sonata -03:43=正在演奏贝揍芬的死亡奏鸣曲 -;03:44=Best before: 1923 -03:44=此日期前最佳:1923 -;03:45=The power of science -03:45=科学的力量 -;03:46=Hot Hot Hot! -03:46=烫烫烫! -;03:47=Stick these somewhere useful! -03:47= 呆在有利的地方! -;03:48=It's Hammer time! -03:48=大锤威武! -;03:49=Does what you guess -03:49=尽情猜想 -;03:50=Moles fan -03:50=地道战 - -; Weapon Descriptions (use | as line breaks) -04:00=使用简单的手榴弹攻击敌人.|定时器倒数到0就会爆炸.|1-5: 设定定时器|攻击键: 按住蓄力. -04:01=使用集束手雷攻击敌人.|定时器倒数到0就会爆炸并裂开成几块.|1-5: 设定定时器|攻击键: 按住蓄力. -04:02=使用弹道导弹攻击敌人.|受风力影响.|攻击键: 按住蓄力. -04:03=发射一个制导导弹攻击所选目标.|如果要精确打击就不要使用全力发射.|光标: 选定目标|攻击键: 按住蓄力. -04:04=霰弹枪有两排子弹.|因为是霰弹枪所以不一定要对准敌人.|攻击键: 开枪 (两发) -04:05=向地底出发! 使用他就能在地面|打个洞, 就能去其他地方.|攻击键: 开始/停止打洞 -04:06=闷了? 没法打? 保存体力? 没问题!|跳过这回合就可以了, 懦夫!|攻击键: 跳过回合 -04:07=用绳索就可以去很远的地方.|还能空降到别的刺猬身上丢手榴弹呢.|攻击键: 发射/收回绳索|长跳键: 发射手榴弹或其他武器 -04:08=你能用地雷阻止敌人靠近.|还能静悄悄的放在敌人脚下.|一定要在爆炸前逃离到安全的地方!|攻击键: 把地雷放在你的脚下 -04:09=自我感觉准头不行? |沙漠之鹰有4颗子弹呢.|攻击键: 开枪 (四发) -04:10=使用强力炸药就是一个明智的选择.|这是最经典的轰炸方式.|攻击键: 把炸药放在你的脚下 -04:11=把敌人打飞, 飞出地图或者飞进水里.|或者把地雷打过去?|攻击键: 敲打你面前的所有东西 -04:12=这就是武术的威力!|致命的气功!|攻击键: 使用升龙拳 -04:13=UNUSED -04:14=有恐高症? 拿降落伞吧.|他能慢慢的安全的把你带到地面.|攻击键: 展开降落伞 -04:15=呼叫一架飞机轰炸你的敌人.|左/右方向键: 决定攻击方向|光标: 选定目标 -04:16=呼叫一架飞机投下大量地雷.|左/右方向键: 决定攻击方向|光标: 选定目标 -04:17=需要个安全的地方? 使用喷灯为你挖掘一条安全的隧道!|攻击键: 开始/停止挖掘 -04:18=喷灯还不够?还要个更安全的地方?|建造若干条大梁挡住吧.|左/右方向键: 选择梁的方向|光标: 建造 -04:19=适当的时候撤退是比所有的攻击|更安全的选择|光标: 选择传送目标 -04:20=可以让你更换当前使用的刺猬.|攻击键: 启动切换功能 -04:21=用炮弹发射器发射一个手榴弹样|的东西. 在爆炸之后会裂开成小块|攻击键: 全力发射 -04:22=这不只是女王才用的东西!|这鞭子能解决很多问题, 比如说那些|喜欢站在悬崖边上的小屁孩.|攻击键: 鞭打你面前的一切东西 -04:23=自杀式炸弹袭击向来好用!|用你的一条命攻击直线上的一切东西并爆炸.|攻击键: 启动自杀性攻击 -04:24=生日快乐! 嗱, 放下这个蛋糕, 他|就会走到敌人身边然后爆炸.| 而且能贴着地形走.|攻击键: 让蛋糕开始/结束走路 -04:25=使用美人计让敌人向着你这个方向跳|(比如跳进海里).|攻击键: 使用本工具诱惑敌人 -04:26=把这个多汁的西瓜扔向敌人!| 一旦定时器倒数完, 就会|炸成几块更强力的炸弹.|攻击键: 按住蓄力. -04:27=让地狱的礼花在敌人头上绽放!|这真的是危险品, 使用时候记得原理|爆炸之后还会燃烧好一阵子|攻击键: 按住蓄力. -04:28=本火箭在发射后将会钻到地里|一旦燃料用完或者打穿地面就会爆炸.|攻击键: 按住蓄力. -04:29=还记得小时候玩的玻璃球么?|不过这个是炸弹版. 发射大量的小玻|璃球然后爆炸|攻击键: 全力发射|上/下方向键: 发射过程中更换方向 -04:30=呼叫一架飞机空投燃烧弹.|用得好的话会造成巨大伤害.|左/右方向键: 决定攻击方向|光标: 选定目标 -04:31=啊哈, 遥控飞机除了能帮你|收集物品之外. 还能空投炸弹.|攻击键: 飞机起飞/投放炸弹|长跳键: 战场之神|上/下方向键: 控制方向 -04:32=低重力装置能影响更多东西!| 除了跳得更远之外还能让|敌人飞得更远.|攻击键: 激活 -04:33=有时候致命打击还是不够过瘾.|攻击键: 激活 -04:34=你打不到我!|攻击键: 激活 -04:35=时间流逝得很快, 你也知道|刺猬腿短.|攻击键: 激活 -04:36=好吧, 你最后还是承认自己眼神不好.|高科技还是能帮你不少的.|攻击键: 激活 -04:37=不用害怕白天.|这只能本回合有效, 可以把造成的伤害变|成自己的血量 .|攻击键: 激活 -04:38=你也知道狙击枪的威力,|能打比较远的地方.|攻击键: 射击 (2发子弹) -04:39=驾驶飞碟可以飞到地图上的任何角落.|不过这个东西连发明者都认为很难用.|攻击键: 激活|上/左/右方向键: 向某方向飞|前跳:攻击敌人 -04:40=把地面填满汽油然后....|攻击键: 按住蓄力. -;04:41=The evidence nature might even top the flying|saucer. Birdy can carry your hog around and|drop eggs on your enemies!|Be quick, as using Birdy eats into your turn|time!|Attack: Activate and drop eggs|Up/Left/Right: Flap in one direction -04:41=自然的力量胜过飞盘的证据。|鸟儿可以携带刺猬并在敌人头上下蛋!|要快!使用鸟儿会消耗回合时间!|攻击键: 激活鸟儿和下蛋|上/左/右方向键: 向某方向飞 -;04:42=This portable portal device is capable|of instantly transporting you, your enemies,|or your weaponry between two points on the|terrain.|Use it wisely and your campaign will be a...|HUGE SUCCESS!|Attack: Shoot a portal|Switch: Cycle portal colours -04:42=移动传送装置|迅速传输自己或者敌人或者|你的武器,直接连接|地表的两个不同位置。|如果用的聪明那你的战斗将是一场……|巨大的胜利!|攻击键: 发射一个传送点|切换键: 改变颜色 -;04:43=Make your musical debut an explosive success!|Drop a piano from the heavens, but beware...|someone needs to play it, and that may cost you|your life!|Cursor: Select target region|F1-F9: Play the piano -04:43=音乐细胞的迸发!|钢琴从天堂降落,带|着演奏者最终回归天堂|光标: 选择目标区域|F1-F9:演奏钢琴 -04:44=这不是奶酪!而是生化武器!|爆炸只有一次,带来的毒害是深远的!|1-5: 设定定时器|攻击键: 按住蓄力 -;04:45=All those physics classes have finally |paid off, launch a devastating Sine |wave at your foes. |Watch out, this weapon packs quite a kick. (This weapon is incomplete)|Attack: Shoot -04:45=全部物理阶级最终|转化为正弦波动|留心,力是相对的|攻击键: 发射 -;04:46=Cover your foes with sizzling liquid flame.|Heartwarming!|Attack: Activate|Up/Down: Continue aiming|Left/Right: Modify spitting power -04:46= 用满腔的火焰虐待你的对手吧。|攻击键: 激活|上/下方向键: 改变攻击方向|左/右方向键: 调整喷射距离 -;04:47=Double the fun with two spiky, sneaky, sticky mines.|Set up a chain reaction or defend yourself (or both!)|Attack: Hold to shoot with more power (twice) -04:47=两次机会双重乐趣,隐蔽且黏着的地雷。|利用脑力造成连锁反应!|攻击键: 按住蓄力(两发) -;04:48=Why should the moles get all the abuse?|Wacking a hog can be just as fun! A good|blow from this hammer will shave off one|third of a hog's health and plunge them|underground.|Attack: Activate -04:48=痛扁刺猬:用力一锤|将使中者镶入地表,削减它健康的1/3.|攻击键: 打 -;04:49=Resurrect your friends!|But beware that this also resurrects your foes.|Attack: Keep attack pressed to resurrect slowly|Up: Accelerate resurrection -04:49=复苏|注意,一视同仁|使用: 按住使用键|上: 提高速率 - -; Game goal strings -;05:01=The following rules apply -05:01= 将应用以下规则 -;05:02=Forts: Defend your fortress; vanquish your enemies! -05:02= 城堡: 守住你的城堡; 削平你的敌人! -;05:03=Low Gravity: Watch your step -05:03= 低重力: 注意脚步 -;05:04=Invulnerability: Hogs are (almost) invulnerable -05:04=无敌: 刺猬不受伤害 -;05:05=Vampirism: Hogs will be healed for the damage dealt -05:05=吸血: 敌人失去的就是我的 -;05:06=Karma: Hogs will be damaged for the damage dealt -05:06=因果效应: 伤害有多少,自己都知道 -;05:07=Protect the King: Don't let your king die!|Place the King: Pick a protected starting point for your King -05:07=保护国王: 国王不能死!|放置国王: 为国王选择安全的起始地点 -;05:08=Place Hedgehogs: Place your hogs before the game starts -05:08=选择起始点: 游戏开始前手动放置刺猬 -;05:09=Artillery: Hogs can't walk to change position -05:09=远程打击: 不许动! -;05:10=Indestructible Terrain: Most weapons won't destroy terrain -05:10=无损地表: 多数武器无法改变地形 -;05:11=Shared Ammo: All teams of the same color share their ammunition -05:11=共享装备: 同色的刺猬共享它们的装备 -;05:12=Mine Timers: Mines will detonate after %1 second(s) -05:12=地雷定时器: %1 秒起爆 -;05:13=Mine Timers: Mines will detonate instantly -05:13=地雷定时器: 立即起爆 -;05:14=Mine Timers: Mines will detonate after 0 - 3 seconds -05:14=地雷定时器: 0-3 秒起爆 -;05:15=Damage Modifier: All weapons will do %1% damage -05:15=伤害修正: 武器伤害使用 %1% 修正值 -;05:16=Health of all hogs is reset on end of turn -05:16=所有活着的刺猬回合结尾时彻底恢复健康 -;05:17=AI hogs respawn on death -05:17=AI刺猬即时复活 -;05:18=Unlimited Attacks -05:18=无限攻击法则 -;05:19=Weapons are reset on end of turn -05:19=武器在回合结束时重置 -;05:20=Weapons are not shared between hogs -05:20=刺猬的武器无法分享 +01:05=退出 (Y/Esc)? +01:06=出现紧急情况! diff -r 763d3961400b -r 3c4b4cb40f40 tools/PascalParser.hs --- a/tools/PascalParser.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/tools/PascalParser.hs Sat Aug 18 00:48:09 2012 +0200 @@ -270,12 +270,12 @@ char ';' comments forward <- liftM isJust $ optionMaybe (try (string "forward;") >> comments) - many functionDecorator + inline <- liftM (any (== "inline;")) $ many functionDecorator b <- if isImpl && (not forward) then liftM Just functionBody else return Nothing - return $ [OperatorDeclaration i rid ret vs b] + return $ [OperatorDeclaration i rid inline ret vs b] funcDecl = do @@ -295,21 +295,24 @@ char ';' comments forward <- liftM isJust $ optionMaybe (try (string "forward;") >> comments) - many functionDecorator + inline <- liftM (any (== "inline;")) $ many functionDecorator b <- if isImpl && (not forward) then liftM Just functionBody else return Nothing - return $ [FunctionDeclaration i ret vs b] + return $ [FunctionDeclaration i inline ret vs b] - functionDecorator = choice [ - try $ string "inline;" - , try $ caseInsensitiveString "cdecl;" - , try $ string "overload;" - , try $ string "export;" - , try $ string "varargs;" - , try (string "external") >> comments >> iD >> optional (string "name" >> comments >> stringLiteral pas)>> string ";" - ] >> comments + functionDecorator = do + d <- choice [ + try $ string "inline;" + , try $ caseInsensitiveString "cdecl;" + , try $ string "overload;" + , try $ string "export;" + , try $ string "varargs;" + , try (string "external") >> comments >> iD >> optional (string "name" >> comments >> stringLiteral pas)>> string ";" + ] + comments + return d program = do diff -r 763d3961400b -r 3c4b4cb40f40 tools/PascalUnitSyntaxTree.hs --- a/tools/PascalUnitSyntaxTree.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/tools/PascalUnitSyntaxTree.hs Sat Aug 18 00:48:09 2012 +0200 @@ -19,8 +19,8 @@ deriving Show data TypeVarDeclaration = TypeDeclaration Identifier TypeDecl | VarDeclaration Bool Bool ([Identifier], TypeDecl) (Maybe InitExpression) - | FunctionDeclaration Identifier TypeDecl [TypeVarDeclaration] (Maybe (TypesAndVars, Phrase)) - | OperatorDeclaration String Identifier TypeDecl [TypeVarDeclaration] (Maybe (TypesAndVars, Phrase)) + | FunctionDeclaration Identifier Bool TypeDecl [TypeVarDeclaration] (Maybe (TypesAndVars, Phrase)) + | OperatorDeclaration String Identifier Bool TypeDecl [TypeVarDeclaration] (Maybe (TypesAndVars, Phrase)) deriving Show data TypeDecl = SimpleType Identifier | RangeType Range diff -r 763d3961400b -r 3c4b4cb40f40 tools/pas2c.hs --- a/tools/pas2c.hs Sat Aug 18 00:47:51 2012 +0200 +++ b/tools/pas2c.hs Sat Aug 18 00:48:09 2012 +0200 @@ -17,24 +17,32 @@ import Data.List (find) import Numeric -import PascalParser +import PascalParser(pascalUnit) import PascalUnitSyntaxTree data InsertOption = IOInsert + | IOInsertWithType Doc | IOLookup | IOLookupLast | IOLookupFunction Int | IODeferred -type Record = (String, BaseType) +data Record = Record + { + lcaseId :: String, + baseType :: BaseType, + typeDecl :: Doc + } + deriving Show type Records = Map.Map String [Record] data RenderState = RenderState { currentScope :: Records, lastIdentifier :: String, lastType :: BaseType, + lastIdTypeDecl :: Doc, stringConsts :: [(String, String)], uniqCounter :: Int, toMangle :: Set.Set String, @@ -43,7 +51,9 @@ namespaces :: Map.Map String Records } -emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty "" "" +rec2Records = map (\(a, b) -> Record a b empty) + +emptyState = RenderState Map.empty "" BTUnknown empty [] 0 Set.empty "" "" getUniq :: State RenderState Int getUniq = do @@ -161,12 +171,12 @@ nss <- gets namespaces withState' (\st -> st{currentScope = fromMaybe Map.empty $ Map.lookup li (namespaces st)}) f -withRecordNamespace :: String -> [(String, BaseType)] -> State RenderState Doc -> State RenderState Doc +withRecordNamespace :: String -> [Record] -> State RenderState Doc -> State RenderState Doc withRecordNamespace _ [] = error "withRecordNamespace: empty record" withRecordNamespace prefix recs = withState' f where f st = st{currentScope = Map.unionWith un records (currentScope st), currentUnit = ""} - records = Map.fromList $ map (\(a, b) -> (map toLower a, [(prefix ++ a, b)])) recs + records = Map.fromList $ map (\(Record a b d) -> (map toLower a, [Record (prefix ++ a) b d])) recs un [a] b = a : b toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO () @@ -200,7 +210,7 @@ pascal2C (Program _ implementation mainFunction) = do impl <- implementation2C implementation - [main] <- tvar2C True False True True (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [VarDeclaration False False ([Identifier "argc" BTInt], SimpleType (Identifier "Integer" BTInt)) Nothing, VarDeclaration False False ([Identifier "argv" BTUnknown], SimpleType (Identifier "PPChar" BTUnknown)) Nothing] (Just (TypesAndVars [], mainFunction))) + [main] <- tvar2C True False True True (FunctionDeclaration (Identifier "main" BTInt) False (SimpleType $ Identifier "int" BTInt) [VarDeclaration False False ([Identifier "argc" BTInt], SimpleType (Identifier "Integer" BTInt)) Nothing, VarDeclaration False False ([Identifier "argv" BTUnknown], SimpleType (Identifier "PPChar" BTUnknown)) Nothing] (Just (TypesAndVars [], mainFunction))) return $ impl $+$ main @@ -231,7 +241,7 @@ where initMap = Map.empty --initMap = Map.fromList [("reset", 2)] - ins (FunctionDeclaration (Identifier i _) _ _ _) m = Map.insertWith (+) (map toLower i) 1 m + ins (FunctionDeclaration (Identifier i _) _ _ _ _) m = Map.insertWith (+) (map toLower i) 1 m ins _ m = m -- the second bool indicates whether declare variable as extern or not @@ -261,8 +271,11 @@ uses2List (Uses ids) = map (\(Identifier i _) -> i) ids +setLastIdValues vv = (\s -> s{lastType = baseType vv, lastIdentifier = lcaseId vv, lastIdTypeDecl = typeDecl vv}) + id2C :: InsertOption -> Identifier -> State RenderState Doc -id2C IOInsert (Identifier i t) = do +id2C IOInsert i = id2C (IOInsertWithType empty) i +id2C (IOInsertWithType d) (Identifier i t) = do ns <- gets currentScope tom <- gets (Set.member n . toMangle) cu <- gets currentUnit @@ -271,7 +284,7 @@ (BTFunction _ _ _, _) -> (cu ++ i, t) (BTVarParam t', _) -> ('(' : '*' : i ++ ")" , t') _ -> (i, t) - modify (\s -> s{currentScope = Map.insertWith (++) n [(i', t')] (currentScope s), lastIdentifier = n}) + modify (\s -> s{currentScope = Map.insertWith (++) n [Record i' t' d] (currentScope s), lastIdentifier = n}) return $ text i' where n = map toLower i @@ -286,9 +299,9 @@ error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v else let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in - modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) + modify (setLastIdValues vv) >> (return . text . lcaseId $ vv) where - checkParam (_, BTFunction _ p _) = p == params + checkParam (Record _ (BTFunction _ p _) _) = p == params checkParam _ = False id2C IODeferred (Identifier i t) = do let i' = map toLower i @@ -296,7 +309,7 @@ if (isNothing v) then modify (\s -> s{lastType = BTUnknown, lastIdentifier = i}) >> return (text i) else - let vv = head $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) + let vv = head $ fromJust v in modify (setLastIdValues vv) >> (return . text . lcaseId $ vv) id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc id2CLookup f (Identifier i t) = do @@ -306,30 +319,34 @@ if isNothing v then error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt else - let vv = f $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) + let vv = f $ fromJust v in modify (setLastIdValues vv) >> (return . text . lcaseId $ vv) id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc -id2CTyped t (Identifier i _) = do +id2CTyped = id2CTyped2 Nothing + +id2CTyped2 :: Maybe Doc -> TypeDecl -> Identifier -> State RenderState Doc +id2CTyped2 md t (Identifier i _) = do tb <- resolveType t case (t, tb) of (_, BTUnknown) -> do error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t (SimpleType {}, BTRecord _ r) -> do ts <- type2C t - id2C IOInsert (Identifier i (BTRecord (render $ ts empty) r)) + id2C (IOInsertWithType $ ts empty) (Identifier i (BTRecord (render $ ts empty) r)) (_, BTRecord _ r) -> do ts <- type2C t - id2C IOInsert (Identifier i (BTRecord i r)) - _ -> id2C IOInsert (Identifier i tb) - + id2C (IOInsertWithType $ ts empty) (Identifier i (BTRecord i r)) + _ -> case md of + Nothing -> id2C IOInsert (Identifier i tb) + Just ts -> id2C (IOInsertWithType ts) (Identifier i tb) resolveType :: TypeDecl -> State RenderState BaseType resolveType st@(SimpleType (Identifier i _)) = do let i' = map toLower i v <- gets $ Map.lookup i' . currentScope - if isJust v then return . snd . head $ fromJust v else return $ f i' + if isJust v then return . baseType . head $ fromJust v else return $ f i' where f "integer" = BTInt f "pointer" = BTPointerTo BTVoid @@ -372,7 +389,7 @@ resolve s (BTUnresolved t) = do v <- gets $ Map.lookup t . currentScope if isJust v then - resolve s . snd . head . fromJust $ v + resolve s . baseType . head . fromJust $ v else error $ "Unknown type " ++ show t ++ "\n" ++ s resolve _ t = return t @@ -412,20 +429,21 @@ ps = zip ['a'..] (toIsVarList params) fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc] -fun2C _ _ (FunctionDeclaration name returnType params Nothing) = do +fun2C _ _ (FunctionDeclaration name inline returnType params Nothing) = do t <- type2C returnType t'<- gets lastType p <- withState' id $ functionParams2C params n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name + let decor = if inline then text "inline" else empty if hasVars then - return [funWithVarsToDefine n params $+$ t empty <+> text (n ++ "__vars") <> parens p] + return [funWithVarsToDefine n params $+$ decor <+> t empty <+> text (n ++ "__vars") <> parens p] else - return [t empty <+> text n <> parens p] + return [decor <+> t empty <+> text n <> parens p] where hasVars = hasPassByReference params -fun2C True rv (FunctionDeclaration name@(Identifier i _) returnType params (Just (tvars, phrase))) = do +fun2C True rv (FunctionDeclaration name@(Identifier i _) inline returnType params (Just (tvars, phrase))) = do let res = docToLower $ text rv <> text "_result" t <- type2C returnType t'<- gets lastType @@ -438,7 +456,7 @@ VoidType -> True _ -> False - (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st + (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [Record (render res) t' empty] $ currentScope st , currentFunctionResult = if isVoid then [] else render res}) $ do p <- functionParams2C params ph <- liftM2 ($+$) (typesAndVars2C False False True tvars) (phrase2C' phrase) @@ -446,11 +464,12 @@ let phrasesBlock = if isVoid then ph else t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi let define = if hasVars then text "#ifndef" <+> text n $+$ funWithVarsToDefine n params $+$ text "#endif" else empty + let decor = if inline then text "inline" else empty return [ define $+$ --(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$ - t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p + decor <+> t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p $+$ text "{" $+$ @@ -463,14 +482,14 @@ un [a] b = a : b hasVars = hasPassByReference params -fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name +fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _ _) = error $ "nested functions not allowed: " ++ name fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv -- the second bool indicates whether declare variable as extern or not -- the third bool indicates whether include types or not -- the fourth bool indicates whether ignore initialization or not (basically for dynamic arrays since we cannot do initialization in function params) tvar2C :: Bool -> Bool -> Bool -> Bool -> TypeVarDeclaration -> State RenderState [Doc] -tvar2C b _ includeType _ f@(FunctionDeclaration (Identifier name _) _ _ _) = do +tvar2C b _ includeType _ f@(FunctionDeclaration (Identifier name _) _ _ _ _) = do t <- fun2C b name f if includeType then return t else return [] tvar2C _ _ includeType _ td@(TypeDeclaration i' t) = do @@ -480,7 +499,7 @@ tvar2C _ _ _ _ (VarDeclaration True _ (ids, t) Nothing) = do t' <- liftM ((empty <+>) . ) $ type2C t - liftM (map(\i -> t' i)) $ mapM (id2CTyped (VarParamType t)) ids + liftM (map(\i -> t' i)) $ mapM (id2CTyped2 (Just $ t' empty) (VarParamType t)) ids tvar2C _ externVar includeType ignoreInit (VarDeclaration _ isConst (ids, t) mInitExpr) = do t' <- liftM (((if isConst then text "static const" else if externVar @@ -515,7 +534,7 @@ (_, _) -> return result - _ -> liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie)) $ mapM (id2CTyped t) ids + _ -> liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie)) $ mapM (id2CTyped2 (Just $ t' empty) t) ids where initExpr Nothing = return $ empty initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e) @@ -528,9 +547,9 @@ ArrayDecl _ _ -> error "Mixed dynamic array and static array are not supported." _ -> 0 -tvar2C f _ _ _ (OperatorDeclaration op (Identifier i _) ret params body) = do +tvar2C f _ _ _ (OperatorDeclaration op (Identifier i _) inline ret params body) = do r <- op2CTyped op (extractTypes params) - fun2C f i (FunctionDeclaration r ret params body) + fun2C f i (FunctionDeclaration r inline ret params body) op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier @@ -780,20 +799,27 @@ r <- ref2C ref t <- gets lastType case t of - (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p + (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") (rec2Records rs) $ phrase2C $ wrapPhrase p a -> do error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb phrase2C (ForCycle i' e1' e2' p up) = do i <- id2C IOLookup i' + iType <- gets lastIdTypeDecl e1 <- expr2C e1' e2 <- expr2C e2' - ph <- phrase2C (wrapPhrase p) - cmp <- return $ if up == True then "<=" else ">=" - inc <- return $ if up == True then "++" else "--" - return $ - text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> parens e1, i <+> text cmp <+> parens e2, text inc <> i]) + let inc = if up then "inc" else "dec" + let add = if up then "+ 1" else "- 1" + let iEnd = i <> text "__end__" + ph <- phrase2C . appendPhrase (BuiltInFunctionCall [Reference $ SimpleReference i'] (SimpleReference (Identifier inc BTUnknown))) $ wrapPhrase p + return . braces $ + i <+> text "=" <+> e1 <> semi $$ - ph + iType <+> iEnd <+> text "=" <+> e2 <> semi + $$ + text "if" <+> (parens $ i <+> text "<=" <+> iEnd) <+> text "do" <+> ph <+> + text "while" <> parens (i <+> text "!=" <+> iEnd <+> text add) <> semi + where + appendPhrase p (Phrases ps) = Phrases $ ps ++ [p] phrase2C (RepeatCycle e' p') = do e <- expr2C e' p <- phrase2C (Phrases p') @@ -992,7 +1018,7 @@ r1 <- ref2C ref1 t <- fromPointer (show ref1) =<< gets lastType r2 <- case t of - BTRecord _ rs -> withRecordNamespace "" rs $ ref2C ref2 + BTRecord _ rs -> withRecordNamespace "" (rec2Records rs) $ ref2C ref2 BTUnit -> error "What??" a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf return $ @@ -1002,7 +1028,7 @@ t <- gets lastType case t of BTRecord _ rs -> do - r2 <- withRecordNamespace "" rs $ ref2C ref2 + r2 <- withRecordNamespace "" (rec2Records rs) $ ref2C ref2 return $ r1 <> text "." <> r2 BTUnit -> withLastIdNamespace $ ref2C ref2 a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf