# HG changeset patch
# User unc0rr
# Date 1296635318 -10800
# Node ID 0eab727d47176b12cd6b25533eb99b9c45f5d381
# Parent 21dd1def5aaf4716392a6ffc3fd2a2d216a005a6# Parent 8bdc879ee6b2b63212c105fc6304b023211b2762
Merge server refactor into default
diff -r 8bdc879ee6b2 -r 0eab727d4717 .hgignore
--- a/.hgignore Mon Jan 31 21:40:17 2011 +0300
+++ b/.hgignore Wed Feb 02 11:28:38 2011 +0300
@@ -32,5 +32,3 @@
glob:*.orig
glob:*.bak
glob:*.rej
-glob:*.qm
-glob:share/hedgewars/Data/misc/hwengine.desktop
diff -r 8bdc879ee6b2 -r 0eab727d4717 .hgtags
--- a/.hgtags Mon Jan 31 21:40:17 2011 +0300
+++ b/.hgtags Wed Feb 02 11:28:38 2011 +0300
@@ -11,16 +11,11 @@
bb56f0682655b18f229be97085a409e3c76f578e hedgewars-0.8.1
fee68e3a303998fdfcc69f74775dc84a36f587fb 0.9.9
fee68e3a303998fdfcc69f74775dc84a36f587fb 0.9.9.1
-fd6c20cd90e33fa5e4f03e1c1f220b3eb14d169a Hedgewars-iOS-1.0
-fd6c20cd90e33fa5e4f03e1c1f220b3eb14d169a Hedgewars-iOS-1.0
-0000000000000000000000000000000000000000 Hedgewars-iOS-1.0
-0000000000000000000000000000000000000000 Hedgewars-iOS-1.0
81db3c85784b4f35c7ff1ef9a5d64f5bdd383f08 Hedgewars-iOS-1.0
-296ec09490d92a74619aa8595df1bbcfd0dff4e5 Hedgewars-iOS-1.0.1
-296ec09490d92a74619aa8595df1bbcfd0dff4e5 Hedgewars-iOS-1.0.1
-0000000000000000000000000000000000000000 Hedgewars-iOS-1.0.1
-0000000000000000000000000000000000000000 Hedgewars-iOS-1.0.1
3620607258cdc1213dce20cb6ad7872f6b8085e0 Hedgewars-iOS-1.0.1
adffb668f06e265b45d1e4aedc283e6f4e5ba7e8 Hedgewars-iOS-1.1
ede569bb76f389bd5dfbb7ebf68af3087e3e881c Hedgewars-iOS-1.2
a5735e877aae61cd705265e2f8c0c7ad08d45f0e Hedgewars-iOS-1.2.1
+29ab0d49c3e6e72a7633d0bd316ae533db15c65d 0.9.15-release
+5ea3d182415e4327e7584b1aa68197931d232ac3 Hedgewars-iOS-1.2.2
+ae71dff40ecc405a55647b0f52f628674c1ebb51 0.9.14.1-release
diff -r 8bdc879ee6b2 -r 0eab727d4717 CMakeLists.txt
--- a/CMakeLists.txt Mon Jan 31 21:40:17 2011 +0300
+++ b/CMakeLists.txt Wed Feb 02 11:28:38 2011 +0300
@@ -9,6 +9,7 @@
#detect Mercurial revision (if present)
set(version_suffix "-dev") #UNSET THIS VARIABLE AT RELEASE TIME
+set(HGCHANGED "")
IF(version_suffix MATCHES "-dev")
set(HW_DEV true)
IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.hg)
@@ -18,8 +19,13 @@
ARGS identify -in ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE version_suffix
)
+ STRING(REGEX REPLACE "[^+]" "" HGCHANGED ${version_suffix})
STRING(REGEX REPLACE "([0-9a-zA-Z]+)(.*) ([0-9]+)(.*)" "\\3:\\1" version_suffix ${version_suffix})
- MESSAGE(STATUS "Building revision ${version_suffix}")
+ IF (HGCHANGED)
+ MESSAGE(STATUS "Building revision ${version_suffix} (SOURCE CODE MODIFIED)")
+ ELSE()
+ MESSAGE(STATUS "Building revision ${version_suffix}")
+ ENDIF()
set(version_suffix "-${version_suffix}")
ENDIF()
ENDIF()
@@ -31,7 +37,7 @@
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "9")
-set(CPACK_PACKAGE_VERSION_PATCH "15${version_suffix}")
+set(CPACK_PACKAGE_VERSION_PATCH "16${version_suffix}")
#forbid in-tree building
#IF (${CMAKE_SOURCE_DIR} MATCHES ${CMAKE_BINARY_DIR})
@@ -77,7 +83,6 @@
set(CMAKE_OSX_ARCHITECTURES "i386;ppc7400")
-
#create universal binaries only when it's time to bundle the application, also build server
IF(BUNDLE)
set(WITH_SERVER true)
@@ -86,7 +91,11 @@
set(CMAKE_CXX_COMPILER "g++-4.0")
else()
if(current_macosx_version MATCHES "10.6")
- set(CMAKE_OSX_ARCHITECTURES "x86_64")
+ if(MACAPPSTORE)
+ set(CMAKE_OSX_ARCHITECTURES "x86_64;i386")
+ else()
+ set(CMAKE_OSX_ARCHITECTURES "x86_64")
+ endif()
endif()
endif()
ELSE()
@@ -165,7 +174,7 @@
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(HEDGEWARS_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-set(HEDGEWARS_PROTO_VER 34)
+set(HEDGEWARS_PROTO_VER 38)
if(WITH_SERVER)
message(STATUS "Server is going to be built! Make sure you have GHC installed")
@@ -239,13 +248,14 @@
"release$"
"Debug$"
"Release$"
- "proto.inc$"
- "hwconsts.cpp$"
- "playlist.inc$"
+ "proto\\\\.inc$"
+ "hwconsts\\\\.cpp$"
+ "playlist\\\\.inc$"
"CPack"
- "cmake_install.cmake$"
- "config.inc$"
- "hwengine.desktop$"
+ "cmake_install\\\\.cmake$"
+ "config\\\\.inc$"
+ "hwengine\\\\.desktop$"
+ "CMakeCache\\\\.txt$"
# "^${CMAKE_CURRENT_SOURCE_DIR}/misc/libopenalbridge"
"^${CMAKE_CURRENT_SOURCE_DIR}/project_files/HedgewarsMobile/"
"^${CMAKE_CURRENT_SOURCE_DIR}/bin/[a-z]"
diff -r 8bdc879ee6b2 -r 0eab727d4717 ChangeLog.txt
--- a/ChangeLog.txt Mon Jan 31 21:40:17 2011 +0300
+++ b/ChangeLog.txt Wed Feb 02 11:28:38 2011 +0300
@@ -1,6 +1,33 @@
+ features
* bugfixes
+0.9.14 -> 0.9.15:
+ + Ability to create, save and load hand drawn maps
+ + New maps: Capture the Flag (Blizzard) Map
+ + New themes: Christmas
+ + Snowflakes on Christmas/Snow themes accumulates on the ground
+ + New game modifiers: No wind, More wind
+ + New missions: Dangerous ducklings, Diver, Spooky tree, Teamwork
+ + New weapons: Mudball, Drill strike
+ + Many more Lua hooks
+ + Readytimer
+ + Ability to edit seed
+ + Ability to select gameplay scripts
+ + New gameplay scripts: Capture the Flag, No jumping, Random weapon
+ + New Lua unified translation framework
+ + Code refactoring
+ + Max teams upped to 8
+ + Cosmetic enhancements to Napalm strike
+ + Selecting a game scheme selects the corresponding weapon set
+ + Dust when drills dig
+ + New hats: beaver, porkey, sheep
+ + Add density property to Gears
+ + Reworked management of schemes and weapon sets
+ + Will ask before deleting teams, schemes and weapon sets
+ + Explosions detach rope from land
+ + Variable rope length in scheme
+ + Allow hog speech when not your turn
+
0.9.13 -> 0.9.14:
+ New audio tracks
+ New forts: EvilChicken, Tank
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/CMakeLists.txt
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/SDLs.cpp
--- a/QTfrontend/SDLs.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/SDLs.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -166,7 +166,7 @@
SDLMusicInit();
if (music == NULL) {
- music = Mix_LoadMUS((datadir->absolutePath() + "/Music/main theme.ogg").toLocal8Bit().constData());
+ music = Mix_LoadMUS((datadir->absolutePath() + "/Music/main_theme.ogg").toLocal8Bit().constData());
}
Mix_VolumeMusic(MIX_MAX_VOLUME - 28);
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/about.cpp
--- a/QTfrontend/about.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/about.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -117,8 +117,10 @@
"Finnish: Nina Kuisma <ninnnu@gmail.com>
"
"French: Antoine Turmel <geekshadow@gmail.com>
"
"German: Peter Hüwe <PeterHuewe@gmx.de>, Mario Liebisch <mario.liebisch@gmail.com>
"
+ "Greek: <talos_kriti@yahoo.gr>"
"Italian: Luca Bonora <bonora.luca@gmail.com>
"
"Japanese: ADAM Etienne <etienne.adam@gmail.com>
"
+ "Korean: Anthony Bellew <webmaster@anthonybellew.com>
"
"Polish: Maciej Mroziński <mynick2@o2.pl>, Wojciech Latkowski <magik17l@gmail.com>, Piotr Mitana, Maciej Górny
"
"Portuguese: Fábio Canário <inufabie@gmail.com>
"
"Russian: Andrey Korotaev <unC0Rr@gmail.com>
"
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/ammoSchemeModel.cpp
--- a/QTfrontend/ammoSchemeModel.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/ammoSchemeModel.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -188,7 +188,7 @@
<< QVariant(false) // disable land objects 17
<< QVariant(false) // AI survival 18
<< QVariant(false) // inf. attack 19
- << QVariant(false) // reset weps 20
+ << QVariant(true) // reset weps 20
<< QVariant(false) // per hog ammo 21
<< QVariant(false) // no wind 22
<< QVariant(false) // more wind 23
@@ -628,12 +628,20 @@
{
Q_UNUSED(count);
- beginInsertRows(parent, row, row);
+ beginInsertRows(parent, schemes.size(), schemes.size());
- QList newScheme = defaultScheme;
- newScheme[0] = QVariant(tr("new"));
-
- schemes.insert(row, newScheme);
+ if (row == -1)
+ {
+ QList newScheme = defaultScheme;
+ newScheme[0] = QVariant(tr("new"));
+ schemes.insert(schemes.size(), newScheme);
+ }
+ else
+ {
+ QList newScheme = schemes[row];
+ newScheme[0] = QVariant(tr("copy of") + " " + newScheme[0].toString());
+ schemes.insert(schemes.size(), newScheme);
+ }
endInsertRows();
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/chatwidget.cpp
--- a/QTfrontend/chatwidget.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/chatwidget.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#include
#include
#include
#include
@@ -26,12 +27,92 @@
#include
#include
#include
+#include
+#include
+#include
+#include
#include "hwconsts.h"
#include "SDLs.h"
#include "gameuiconfig.h"
#include "chatwidget.h"
+ListWidgetNickItem::ListWidgetNickItem(const QString& nick, bool isFriend, bool isIgnored) : QListWidgetItem(nick)
+{
+ this->aFriend = isFriend;
+ this->isIgnored = isIgnored;
+}
+
+void ListWidgetNickItem::setFriend(bool isFriend)
+{
+ this->aFriend = isFriend;
+}
+
+void ListWidgetNickItem::setIgnored(bool isIgnored)
+{
+ this->isIgnored = isIgnored;
+}
+
+bool ListWidgetNickItem::isFriend()
+{
+ return aFriend;
+}
+
+bool ListWidgetNickItem::ignored()
+{
+ return isIgnored;
+}
+
+bool ListWidgetNickItem::operator< (const QListWidgetItem & other) const
+{
+ // case in-sensitive comparison of the associated strings
+ // chars that are no letters are sorted at the end of the list
+
+ ListWidgetNickItem otherNick = const_cast(dynamic_cast(other));
+
+ // ignored always down
+ if (isIgnored != otherNick.ignored())
+ return !isIgnored;
+
+ // friends always up
+ if (aFriend != otherNick.isFriend())
+ return aFriend;
+
+ QString txt1 = text().toLower();
+ QString txt2 = other.text().toLower();
+
+ bool firstIsShorter = (txt1.size() < txt2.size());
+ int len = firstIsShorter?txt1.size():txt2.size();
+
+ for (int i = 0; i < len; i++)
+ {
+ if (txt1[i] == txt2[i])
+ continue;
+ if (txt1[i].isLetter() != txt2[i].isLetter())
+ return txt1[i].isLetter();
+ return (txt1[i] < txt2[i]);
+ }
+
+ return firstIsShorter;
+}
+
+const char* HWChatWidget::STYLE =
+"\
+a { color:#c8c8ff; }\
+.nick { text-decoration: none; }\
+.UserChat .nick { color:#ffec20; }\
+.FriendChat { color: #08e008; }\
+.FriendChat .nick { color: #20ff20; }\
+.UserJoin { color: #c0c0c0; }\
+.UserJoin .nick { color: #d0d0d0; }\
+.FriendJoin { color: #c0e0c0; }\
+.FriendJoin .nick { color: #d0f0d0; }\
+.UserAction { color: #ff80ff; }\
+.UserAction .nick { color: #ffa0ff; }\
+.FriendAction { color: #ff00ff; }\
+.FriendAction .nick { color: #ff30ff; }\
+";
+
HWChatWidget::HWChatWidget(QWidget* parent, QSettings * gameSettings, SDLInteraction * sdli, bool notify) :
QWidget(parent),
mainLayout(this)
@@ -64,10 +145,13 @@
mainLayout.addWidget(chatEditLine, 1, 0);
chatText = new QTextBrowser(this);
+ chatText->document()->setDefaultStyleSheet(STYLE);
chatText->setMinimumHeight(20);
chatText->setMinimumWidth(10);
chatText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- chatText->setOpenExternalLinks(true);
+ chatText->setOpenLinks(false);
+ connect(chatText, SIGNAL(anchorClicked(const QUrl&)),
+ this, SLOT(linkClicked(const QUrl&)));
mainLayout.addWidget(chatText, 0, 0);
chatNicks = new QListWidget(this);
@@ -102,12 +186,50 @@
acFriend->setIcon(QIcon(":/res/addfriend.png"));
connect(acFriend, SIGNAL(triggered(bool)), this, SLOT(onFriend()));
+ chatNicks->insertAction(0, acFriend);
chatNicks->insertAction(0, acInfo);
- chatNicks->insertAction(0, acFollow);
chatNicks->insertAction(0, acIgnore);
- chatNicks->insertAction(0, acFriend);
showReady = false;
+ setShowFollow(true);
+}
+
+void HWChatWidget::linkClicked(const QUrl & link)
+{
+ if (link.scheme() == "http")
+ QDesktopServices::openUrl(link);
+ if (link.scheme() == "hwnick")
+ {
+ // decode nick
+ const QString& nick = QString::fromUtf8(QByteArray::fromBase64(link.encodedQuery()));
+ QList items = chatNicks->findItems(nick, Qt::MatchExactly);
+ if (items.size() < 1)
+ return;
+ QMenu * popup = new QMenu();
+ // selecting an item will automatically scroll there, so let's save old position
+ QScrollBar * scrollBar = chatNicks->verticalScrollBar();
+ int oldScrollPos = scrollBar->sliderPosition();
+ // select the nick which we want to see the actions for
+ chatNicks->setCurrentItem(items[0], QItemSelectionModel::Clear);
+ // selecting an item will automatically scroll there, so let's save old position
+ scrollBar->setSliderPosition(oldScrollPos);
+ // load actions
+ popup->addActions(chatNicks->actions());
+ // display menu popup at mouse cursor position
+ popup->popup(QCursor::pos());
+ }
+}
+
+void HWChatWidget::setShowFollow(bool enabled)
+{
+ if (enabled) {
+ if (!(chatNicks->actions().contains(acFollow)))
+ chatNicks->insertAction(acFriend, acFollow);
+ }
+ else {
+ if (chatNicks->actions().contains(acFollow))
+ chatNicks->removeAction(acFollow);
+ }
}
void HWChatWidget::loadList(QStringList & list, const QString & file)
@@ -145,16 +267,20 @@
txt.close();
}
-void HWChatWidget::updateIcon(QListWidgetItem *item)
+void HWChatWidget::updateNickItem(QListWidgetItem *nickItem)
{
- QString nick = item->text();
+ QString nick = nickItem->text();
+ ListWidgetNickItem * item = dynamic_cast(nickItem);
- if(ignoreList.contains(nick, Qt::CaseInsensitive))
+ item->setFriend(friendsList.contains(nick, Qt::CaseInsensitive));
+ item->setIgnored(ignoreList.contains(nick, Qt::CaseInsensitive));
+
+ if(item->ignored())
{
item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_ignore_on.png" : ":/res/chat_ignore_off.png") : ":/res/chat_ignore.png"));
item->setForeground(Qt::gray);
}
- else if(friendsList.contains(nick, Qt::CaseInsensitive))
+ else if(item->isFriend())
{
item->setIcon(QIcon(showReady ? (item->data(Qt::UserRole).toBool() ? ":/res/chat_friend_on.png" : ":/res/chat_friend_off.png") : ":/res/chat_friend.png"));
item->setForeground(Qt::green);
@@ -166,17 +292,19 @@
}
}
-void HWChatWidget::updateIcons()
+void HWChatWidget::updateNickItems()
{
for(int i = 0; i < chatNicks->count(); i++)
- updateIcon(chatNicks->item(i));
+ updateNickItem(chatNicks->item(i));
+
+ chatNicks->sortItems();
}
void HWChatWidget::loadLists(const QString & nick)
{
loadList(ignoreList, nick.toLower() + "_ignore.txt");
loadList(friendsList, nick.toLower() + "_friends.txt");
- updateIcons();
+ updateNickItems();
}
void HWChatWidget::saveLists(const QString & nick)
@@ -191,34 +319,54 @@
chatEditLine->clear();
}
+
void HWChatWidget::onChatString(const QString& str)
{
+ onChatString("", str);
+}
+
+const QRegExp HWChatWidget::URLREGEXP = QRegExp("(http://)?(www\\.)?(hedgewars\\.org(/[^ ]*)?)");
+
+void HWChatWidget::onChatString(const QString& nick, const QString& str)
+{
+ bool isFriend = false;
+
+ if (!nick.isEmpty()) {
+ // don't show chat lines that are from ignored nicks
+ if (ignoreList.contains(nick, Qt::CaseInsensitive))
+ return;
+ // friends will get special treatment, of course
+ isFriend = friendsList.contains(nick, Qt::CaseInsensitive);
+ }
+
if (chatStrings.size() > 250)
chatStrings.removeFirst();
QString formattedStr = Qt::escape(str.mid(1));
- QStringList parts = formattedStr.split(QRegExp("\\W+"), QString::SkipEmptyParts);
+ // make hedgewars.org urls actual links
+ formattedStr = formattedStr.replace(URLREGEXP, "\\3");
+
+ // "link" nick, but before that encode it in base64 to make sure it can't intefere with html/url syntax
+ // the nick is put as querystring as putting it as host would convert it to it's lower case variant
+ if(!nick.isEmpty())
+ formattedStr.replace("|nick|",QString("%2").arg(QString(nick.toUtf8().toBase64())).arg(nick));
+
+ QString cssClass("UserChat");
- if (!formattedStr.startsWith(" ***")) // don't ignore status messages
- {
- if (formattedStr.startsWith(" *")) // emote
- parts[0] = parts[1];
- if(parts.size() > 0 && ignoreList.contains(parts[0], Qt::CaseInsensitive))
- return;
+ // check first character for color code and set color properly
+ switch (str[0].toAscii()) {
+ case 3:
+ cssClass = (isFriend ? "FriendJoin" : "UserJoin");
+ break;
+ case 2:
+ cssClass = (isFriend ? "FriendAction" : "UserAction");
+ break;
+ default:
+ if (isFriend)
+ cssClass = "FriendChat";
}
- QString color("");
- bool isFriend = friendsList.contains(parts[0], Qt::CaseInsensitive);
-
- if (str.startsWith("\x03"))
- color = QString("#c0c0c0");
- else if (str.startsWith("\x02"))
- color = QString(isFriend ? "#00ff00" : "#ff00ff");
- else if (isFriend)
- color = QString("#00c000");
-
- if(color.compare("") != 0)
- formattedStr = QString("%1").arg(formattedStr).arg(color);
+ formattedStr = QString("%1").arg(formattedStr).arg(cssClass);
chatStrings.append(formattedStr);
@@ -241,8 +389,8 @@
void HWChatWidget::nickAdded(const QString& nick, bool notifyNick)
{
- QListWidgetItem * item = new QListWidgetItem(nick);
- updateIcon(item);
+ QListWidgetItem * item = new ListWidgetNickItem(nick, friendsList.contains(nick, Qt::CaseInsensitive), ignoreList.contains(nick, Qt::CaseInsensitive));
+ updateNickItem(item);
chatNicks->addItem(item);
if(notifyNick && notify && gameSettings->value("frontend/sound", true).toBool()) {
@@ -307,10 +455,19 @@
}
else // not on list - add
{
+ // don't consider ignored people friends
+ if(friendsList.contains(curritem->text(), Qt::CaseInsensitive))
+ emit onFriend();
+
+ // scroll down on first ignore added so that people see where that nick went to
+ if (ignoreList.isEmpty())
+ chatNicks->scrollToBottom();
+
ignoreList << curritem->text().toLower();
onChatString(HWChatWidget::tr("%1 *** %2 has been added to your ignore list").arg('\x03').arg(curritem->text()));
}
- updateIcon(curritem); // update icon
+ updateNickItem(curritem); // update icon/sort order/etc
+ chatNicks->sortItems();
chatNickSelected(0); // update context menu
}
@@ -327,16 +484,26 @@
}
else // not on list - add
{
+ // don't ignore the new friend
+ if(ignoreList.contains(curritem->text(), Qt::CaseInsensitive))
+ emit onIgnore();
+
+ // scroll up on first friend added so that people see where that nick went to
+ if (friendsList.isEmpty())
+ chatNicks->scrollToTop();
+
friendsList << curritem->text().toLower();
onChatString(HWChatWidget::tr("%1 *** %2 has been added to your friends list").arg('\x03').arg(curritem->text()));
}
- updateIcon(curritem); // update icon
+ updateNickItem(curritem); // update icon/sort order/etc
+ chatNicks->sortItems();
chatNickSelected(0); // update context menu
}
void HWChatWidget::chatNickDoubleClicked(QListWidgetItem * item)
{
- if (item) onFollow();
+ QList actions = chatNicks->actions();
+ actions.first()->activate(QAction::Trigger);
}
void HWChatWidget::chatNickSelected(int index)
@@ -386,7 +553,7 @@
}
items[0]->setData(Qt::UserRole, isReady); // bulb status
- updateIcon(items[0]);
+ updateNickItem(items[0]);
// ensure we're still showing the status bulbs
showReady = true;
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/chatwidget.h
--- a/QTfrontend/chatwidget.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/chatwidget.h Wed Feb 02 11:28:38 2011 +0300
@@ -23,15 +23,33 @@
#include
#include
#include
+#include
#include "SDLs.h"
+class ListWidgetNickItem;
class QTextBrowser;
class QLineEdit;
class QListWidget;
class QSettings;
class SDLInteraction;
+// this class is for custom nick sorting
+class ListWidgetNickItem : public QListWidgetItem
+{
+public:
+ ListWidgetNickItem(const QString& nick, bool isFriend, bool isIgnored);
+ bool operator<(const QListWidgetItem & other) const;
+ void setFriend(bool isFriend);
+ void setIgnored(bool isIgnored);
+ bool isFriend();
+ bool ignored();
+
+private:
+ bool aFriend;
+ bool isIgnored;
+};
+
class HWChatWidget : public QWidget
{
Q_OBJECT
@@ -41,15 +59,19 @@
void loadLists(const QString & nick);
void saveLists(const QString & nick);
void setShowReady(bool s);
+ void setShowFollow(bool enabled);
+ static const char* STYLE;
private:
void loadList(QStringList & list, const QString & file);
void saveList(QStringList & list, const QString & file);
- void updateIcon(QListWidgetItem *item);
- void updateIcons();
+ void updateNickItem(QListWidgetItem *item);
+ void updateNickItems();
+ static const QRegExp URLREGEXP;
public slots:
void onChatString(const QString& str);
+ void onChatString(const QString& nick, const QString& str);
void onServerMessage(const QString& str);
void nickAdded(const QString& nick, bool notifyNick);
void nickRemoved(const QString& nick);
@@ -93,6 +115,7 @@
void onFriend();
void chatNickDoubleClicked(QListWidgetItem * item);
void chatNickSelected(int index);
+ void linkClicked(const QUrl & link);
};
#endif // _CHAT_WIDGET_INCLUDED
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/drawmapscene.cpp
--- a/QTfrontend/drawmapscene.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/drawmapscene.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -87,9 +87,10 @@
{
QByteArray b;
- foreach(QList points, paths)
+ for(int i = paths.size() - 1; i >= 0; --i)
{
int cnt = 0;
+ QList points = paths.at(i);
foreach(QPoint point, points)
{
qint16 px = qToBigEndian((qint16)point.x());
@@ -124,21 +125,23 @@
quint8 flags = *(quint8 *)data.data();
data.remove(0, 1);
- //last chunk or first point
- if((data.size() < 5) || (flags & 0x80))
+ if((flags & 0x80) && points.size())
{
- if(points.size())
- {
- addPath(pointsToPath(points), m_pen);
- paths.prepend(points);
+ addPath(pointsToPath(points), m_pen);
+ paths.prepend(points);
- points.clear();
- }
+ points.clear();
}
points.append(QPoint(px, py));
}
+ if(points.size())
+ {
+ addPath(pointsToPath(points), m_pen);
+ paths.prepend(points);
+ }
+
emit pathChanged();
}
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/drawmapwidget.cpp
--- a/QTfrontend/drawmapwidget.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/drawmapwidget.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -1,4 +1,5 @@
#include
+#include
#include "drawmapwidget.h"
@@ -31,6 +32,7 @@
void DrawMapWidget::setScene(DrawMapScene * scene)
{
ui->graphicsView->setScene(scene);
+ m_scene = scene;
}
void DrawMapWidget::resizeEvent(QResizeEvent * event)
@@ -55,15 +57,31 @@
void DrawMapWidget::clear()
{
- if(m_scene) m_scene->clear();
+ if(m_scene) m_scene->clearMap();
}
void DrawMapWidget::save(const QString & fileName)
{
- Q_UNUSED(fileName);
+ if(m_scene)
+ {
+ QFile file(fileName);
+
+ if(!file.open(QIODevice::WriteOnly))
+ QMessageBox::warning(this, tr("File error"), tr("Cannot open file '%1' for writing").arg(fileName));
+ else
+ file.write(qCompress(m_scene->encode()).toBase64());
+ }
}
void DrawMapWidget::load(const QString & fileName)
{
- Q_UNUSED(fileName);
+ if(m_scene)
+ {
+ QFile f(fileName);
+
+ if(!f.open(QIODevice::ReadOnly))
+ QMessageBox::warning(this, tr("File error"), tr("Cannot read file '%1'").arg(fileName));
+ else
+ m_scene->decode(qUncompress(QByteArray::fromBase64(f.readAll())));
+ }
}
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/game.cpp
--- a/QTfrontend/game.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/game.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -56,7 +56,7 @@
emit HaveRecord(true, demo);
break;
default:
- if (gameState == gsInterrupted) emit HaveRecord(false, demo);
+ if (gameState == gsInterrupted || gameState == gsHalted) emit HaveRecord(false, demo);
else if (gameState == gsFinished) emit HaveRecord(true, demo);
}
SetGameState(gsStopped);
@@ -229,6 +229,10 @@
SetGameState(gsFinished);
break;
}
+ case 'H': {
+ SetGameState(gsHalted);
+ break;
+ }
case 's': {
int size = msg.size();
QString msgbody = QString::fromUtf8(msg.mid(2).left(size - 4));
@@ -250,8 +254,8 @@
{
emit SendNet(msg);
}
- if (msg.at(1) != 's')
- demo.append(msg);
+ if (msg.at(1) != 's')
+ demo.append(msg);
}
}
}
@@ -300,6 +304,7 @@
arguments << (config->isAltDamageEnabled() ? "1" : "0");
arguments << config->netNick().toUtf8().toBase64();
arguments << QString::number(config->translateQuality());
+ arguments << QString::number(config->stereoMode());
arguments << tr("en.txt");
return arguments;
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/game.h
--- a/QTfrontend/game.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/game.h Wed Feb 02 11:28:38 2011 +0300
@@ -35,7 +35,8 @@
gsInterrupted = 2,
gsFinished = 3,
gsStopped = 4,
- gsDestroyed = 5
+ gsDestroyed = 5,
+ gsHalted = 6
};
bool checkForDir(const QString & dir);
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/gamecfgwidget.cpp
--- a/QTfrontend/gamecfgwidget.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/gamecfgwidget.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -52,7 +52,7 @@
Scripts = new QComboBox(GBoxOptions);
GBoxOptionsLayout->addWidget(Scripts, 0, 1);
- Scripts->addItem(QComboBox::tr("Normal"));
+ Scripts->addItem("Normal");
Scripts->insertSeparator(1);
for (int i = 0; i < scriptList->size(); ++i) {
@@ -245,6 +245,7 @@
{
case MAPGEN_MAZE:
bcfg << QString("e$maze_size %1").arg(pMapContainer->get_maze_size()).toUtf8();
+ break;
case MAPGEN_DRAWN:
{
@@ -257,6 +258,7 @@
bcfg << tmp;
data.remove(0, 200);
}
+ break;
}
default: ;
}
@@ -330,6 +332,9 @@
}
if (param == "SEED") {
pMapContainer->setSeed(value);
+ if (!QRegExp("\\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\}").exactMatch(value)) {
+ pMapContainer->seedEdit->setVisible(true);
+ }
return;
}
if (param == "THEME") {
@@ -381,7 +386,7 @@
void GameCFGWidget::mapChanged(const QString & value)
{
- if(pMapContainer->getCurrentIsMission())
+ if(isEnabled() && pMapContainer->getCurrentIsMission())
{
Scripts->setEnabled(false);
Scripts->setCurrentIndex(0);
@@ -456,7 +461,7 @@
emit paramChanged("SCHEME", sl);
- if (bindEntries->isEnabled() && bindEntries->isChecked()) {
+ if (isEnabled() && bindEntries->isEnabled() && bindEntries->isChecked()) {
QString schemeName = GameSchemes->itemText(index);
for (int i = 0; i < WeaponsName->count(); i++) {
QString weapName = WeaponsName->itemText(i);
@@ -472,7 +477,7 @@
void GameCFGWidget::scriptChanged(int index)
{
- if(index > 0)
+ if(isEnabled() && index > 0)
{
QString scheme = Scripts->itemData(Scripts->currentIndex()).toList()[1].toString();
QString weapons = Scripts->itemData(Scripts->currentIndex()).toList()[2].toString();
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/gameuiconfig.cpp
--- a/QTfrontend/gameuiconfig.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/gameuiconfig.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -48,6 +48,7 @@
Form->ui.pageOptions->CBFrontendFullscreen->setChecked(ffscr);
Form->ui.pageOptions->SLQuality->setValue(value("video/quality", 5).toUInt());
+ Form->ui.pageOptions->CBStereoMode->setCurrentIndex(value("video/stereo", 0).toUInt());
Form->ui.pageOptions->CBFrontendEffects->setChecked(frontendEffects);
Form->ui.pageOptions->CBEnableSound->setChecked(value("audio/sound", true).toBool());
Form->ui.pageOptions->CBEnableFrontendSound->setChecked(value("frontend/sound", true).toBool());
@@ -93,7 +94,7 @@
{
QDir teamdir;
teamdir.cd(cfgdir->absolutePath() + "/Teams");
- QStringList teamslist = teamdir.entryList(QStringList("*.hwt"));
+ QStringList teamslist = teamdir.entryList(QStringList("*.hwt"),QDir::Files|QDir::Hidden);
QStringList cleanedList;
for (QStringList::Iterator it = teamslist.begin(); it != teamslist.end(); ++it ) {
QString tmpTeamStr=(*it).replace(QRegExp("^(.*)\\.hwt$"), "\\1");
@@ -113,6 +114,7 @@
setValue("video/fullscreen", vid_Fullscreen());
setValue("video/quality", Form->ui.pageOptions->SLQuality->value());
+ setValue("video/stereo", stereoMode());
setValue("frontend/effects", isFrontendEffects());
@@ -183,7 +185,7 @@
quint32 rqNoBackground = 0x00000004; // don't draw background
quint32 rqSimpleRope = 0x00000008; // avoid drawing rope
quint32 rq2DWater = 0x00000010; // disabe 3D water effect
- quint32 rqFancyBoom = 0x00000020; // no fancy explosion effects
+ quint32 rqAntiBoom = 0x00000020; // no fancy explosion effects
quint32 rqKillFlakes = 0x00000040; // no flakes
quint32 rqSlowMenu = 0x00000080; // ammomenu appears with no animation
quint32 rqPlainSplash = 0x00000100; // no droplets
@@ -204,15 +206,15 @@
break;
case 2:
result |= rqBlurryLand | rqKillFlakes | rqPlainSplash | rq2DWater |
- rqFancyBoom | rqSlowMenu;
+ rqAntiBoom | rqSlowMenu;
break;
case 1:
result |= rqBlurryLand | rqKillFlakes | rqPlainSplash | rq2DWater |
- rqFancyBoom | rqSlowMenu | rqSimpleRope | rqDesyncVBlank;
+ rqAntiBoom | rqSlowMenu | rqSimpleRope | rqDesyncVBlank;
break;
case 0:
result |= rqBlurryLand | rqKillFlakes | rqPlainSplash | rq2DWater |
- rqFancyBoom | rqSlowMenu | rqSimpleRope | rqDesyncVBlank |
+ rqAntiBoom | rqSlowMenu | rqSimpleRope | rqDesyncVBlank |
rqNoBackground | rqClampLess;
break;
default:
@@ -261,6 +263,11 @@
return Form->ui.pageOptions->CBAltDamage->isChecked();
}
+quint32 GameUIConfig::stereoMode() const
+{
+ return Form->ui.pageOptions->CBStereoMode->currentIndex();
+}
+
bool GameUIConfig::appendDateTimeToRecordName()
{
return Form->ui.pageOptions->CBNameWithDate->isChecked();
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/gameuiconfig.h
--- a/QTfrontend/gameuiconfig.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/gameuiconfig.h Wed Feb 02 11:28:38 2011 +0300
@@ -52,6 +52,7 @@
bool isFrontendEffects() const;
bool isFrontendFullscreen() const;
void resizeToConfigValues();
+ quint32 stereoMode() const;
#ifdef __APPLE__
#ifdef SPARKLE_ENABLED
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/hwconsts.cpp.in
--- a/QTfrontend/hwconsts.cpp.in Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/hwconsts.cpp.in Wed Feb 02 11:28:38 2011 +0300
@@ -21,7 +21,7 @@
QString * cProtoVer = new QString("${HEDGEWARS_PROTO_VER}");
QString * cDataDir = new QString("${HEDGEWARS_DATADIR}");
QString * cConfigDir = new QString("");
-QString * cVersionString = new QString("${HEDGEWARS_VERSION}");
+QString * cVersionString = new QString("${HEDGEWARS_VERSION}${HGCHANGED}");
QDir * bindir = new QDir("${HEDGEWARS_BINDIR}");
QDir * cfgdir = new QDir();
@@ -37,10 +37,10 @@
int cMaxTeams = 6;
QString * cDefaultAmmoStore = new QString(
- "93919294221991210322351110012010000002111101010111"
- "04050405416006555465544647765766666661555101011154"
- "00000000000002055000000400070040000000002000000006"
- "13111103121111111231141111111111111112111111011111"
+ "93919294221991210322351110012010000002111101010111299"
+ "04050405416006555465544647765766666661555101011154111"
+ "00000000000002055000000400070040000000002000000006000"
+ "13111103121111111231141111111111111112111111011111211"
);
int cAmmoNumber = cDefaultAmmoStore->size() / 4;
@@ -49,40 +49,40 @@
<< qMakePair(QString("Default"), *cDefaultAmmoStore)
<< qMakePair(QString("Crazy"), QString(
// TODO: Remove Piano's unlimited uses!
- "99999999999999999929999999999999992999999999099999"
- "11111101111111111111111111111111111111111111011111"
- "00000000000000000000000000000000000000000000000000"
- "13111103121111111231141111111111111112111101011111"
+ "99999999999999999929999999999999992999999999099999922"
+ "11111101111111111111111111111111111111111111011111111"
+ "00000000000000000000000000000000000000000000000000000"
+ "13111103121111111231141111111111111112111101011111111"
))
<< qMakePair(QString("Pro Mode"), QString(
- "90900090000000000000090000000000000000000000000000"
- "00000000000000000000000000000000000000000000000000"
- "00000000000002055000000400070040000000002000000000"
- "11111111111111111111111111111111111111111001011111"
+ "90900090000000000000090000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000"
+ "00000000000002055000000400070040000000002000000000000"
+ "11111111111111111111111111111111111111111001011111111"
))
<< qMakePair(QString("Shoppa"), QString(
- "00000099000000000000000000000000000000000000000000"
- "44444100442444022101121212224220000000020004000100"
- "00000000000000000000000000000000000000000000000000"
- "11111111111111111111111111111111111111111011011111"
+ "00000099000000000000000000000000000000000000000000000"
+ "44444100442444022101121212224220000000020004000100111"
+ "00000000000000000000000000000000000000000000000000000"
+ "11111111111111111111111111111111111111111011011111111"
))
<< qMakePair(QString("Clean Slate"),QString(
- "10100090000100000110000000000000000000000000000010"
- "04050405416006555465544647765766666661555101011154"
- "00000000000000000000000000000000000000000000000000"
- "13111103121111111231141111111111111112111111011111"
+ "10100090000100000110000000000000000000000000000010000"
+ "04050405416006555465544647765766666661555101011154111"
+ "00000000000000000000000000000000000000000000000000000"
+ "13111103121111111231141111111111111112111111011111111"
))
<< qMakePair(QString("Minefield"), QString(
- "00000099000900000003000000000000000000000000000000"
- "00000000000000000000000000000000000000000000000000"
- "00000000000002055000000400070040000000002000000006"
- "11111111111111111111111111111111111111111111011111"
+ "00000099000900000003000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000000"
+ "00000000000002055000000400070040000000002000000006000"
+ "11111111111111111111111111111111111111111111011111111"
))
<< qMakePair(QString("Thinking with Portals"), QString(
- "90000090020000000021000000000000001100000900000000"
- "04050405416006555465544647765766666661555101011154"
- "00000000000002055000000400070040000000002000000006"
- "13111103121111111231141111111111111112111111011111"
+ "90000090020000000021000000000000001100000900000000000"
+ "04050405416006555465544647765766666661555101011154111"
+ "00000000000002055000000400070040000000002000000006000"
+ "13111103121111111231141111111111111112111111011111111"
));
QColor *colors[] = {
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/hwform.cpp
--- a/QTfrontend/hwform.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/hwform.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include "hwform.h"
#include "game.h"
@@ -86,7 +87,7 @@
ui.setupUi(this);
setMinimumSize(760, 580);
- setFocusPolicy(Qt::StrongFocus);
+ //setFocusPolicy(Qt::StrongFocus);
CustomizePalettes();
ui.pageOptions->CBResolution->addItems(sdli.getResolutions());
@@ -104,6 +105,10 @@
if (updater && config->isAutoUpdateEnabled())
updater->checkForUpdates();
#endif
+#else
+ // ctrl+q closes frontend for consistency
+ QShortcut *closeFrontend = new QShortcut(QKeySequence("Ctrl+Q"), this);
+ connect (closeFrontend, SIGNAL(activated()), this, SLOT(close()));
#endif
UpdateTeamsLists();
@@ -308,11 +313,13 @@
}
}
+/*
void HWForm::keyReleaseEvent(QKeyEvent *event)
{
- if (event->key() == Qt::Key_Escape /*|| event->key() == Qt::Key_Backspace*/ )
+ if (event->key() == Qt::Key_Escape)
this->GoBack();
}
+*/
void HWForm::CustomizePalettes()
{
@@ -543,7 +550,7 @@
GoBack();
if (curid == ID_PAGE_ROOMSLIST) NetDisconnect();
- if (curid == ID_PAGE_NETGAME) hwnet->partRoom();
+ if (curid == ID_PAGE_NETGAME && hwnet) hwnet->partRoom();
// need to work on this, can cause invalid state for admin quit trying to prevent bad state message on kick
//if (curid == ID_PAGE_NETGAME && (!game || game->gameState != gsStarted)) hwnet->partRoom();
@@ -662,6 +669,7 @@
QMessageBox::warning(0, QMessageBox::tr("Schemes"), QMessageBox::tr("Can not delete default scheme '%1'!").arg(ui.pageOptions->SchemesName->currentText()));
} else {
ui.pageScheme->deleteRow();
+ ammoSchemeModel->Save();
}
}
@@ -694,7 +702,7 @@
void HWForm::NetConnectServer(const QString & host, quint16 port)
{
- _NetConnect(host, port, ui.pageOptions->editNetNick->text());
+ _NetConnect(host, port, ui.pageOptions->editNetNick->text().trimmed());
}
void HWForm::NetConnectOfficialServer()
@@ -789,6 +797,8 @@
hwnet, SLOT(chatLineToLobby(const QString&)));
connect(hwnet, SIGNAL(chatStringLobby(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)));
+ connect(hwnet, SIGNAL(chatStringLobby(const QString&, const QString&)),
+ ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&, const QString&)));
connect(hwnet, SIGNAL(chatStringFromMeLobby(const QString&)),
ui.pageRoomsList->chatWidget, SLOT(onChatString(const QString&)));
@@ -971,12 +981,13 @@
if (id == ID_PAGE_INGAME ||
// was room chief and the game was aborted
(hwnet && hwnet->isRoomChief() && hwnet->isInRoom() &&
- (gameState == gsInterrupted || gameState == gsStopped || gameState == gsDestroyed))) {
+ (gameState == gsInterrupted || gameState == gsStopped || gameState == gsDestroyed || gameState == gsHalted))) {
if (id == ID_PAGE_INGAME) GoBack();
Music(ui.pageOptions->CBEnableFrontendMusic->isChecked());
if (wBackground) wBackground->startAnimation();
if (hwnet) hwnet->gameFinished();
}
+ if (gameState == gsHalted) close();
};
}
}
@@ -1006,6 +1017,10 @@
QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm") :
"LastRound";
+ QStringList versionParts = cVersionString->split('-');
+ if ( (versionParts.size() == 2) && (!versionParts[1].isEmpty()) && (versionParts[1].contains(':')) )
+ recordFileName = recordFileName + "_" + versionParts[1].replace(':','-');
+
if (isDemo)
{
demo.replace(QByteArray("\x02TL"), QByteArray("\x02TD"));
@@ -1169,7 +1184,7 @@
QStringList entries = tmpdir.entryList(QStringList("*#*.lua"));
//entries.sort();
for(int i = 0; (i < entries.count()) && (i <= team.CampaignProgress); i++)
- ui.pageCampaign->CBSelect->addItem(QString(entries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2"), QString(entries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1"));
+ ui.pageCampaign->CBSelect->addItem(QString(entries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2").replace("_", " "), QString(entries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1"));
}
void HWForm::AssociateFiles()
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/hwform.h
--- a/QTfrontend/hwform.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/hwform.h Wed Feb 02 11:28:38 2011 +0300
@@ -122,7 +122,7 @@
void closeEvent(QCloseEvent *event);
void CustomizePalettes();
void resizeEvent(QResizeEvent * event);
- void keyReleaseEvent(QKeyEvent *event);
+ //void keyReleaseEvent(QKeyEvent *event);
enum PageIDs {
ID_PAGE_SETUP_TEAM = 0,
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/hwmap.cpp
--- a/QTfrontend/hwmap.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/hwmap.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -33,7 +33,7 @@
templateFilter = filter;
m_mapgen = mapgen;
m_maze_size = maze_size;
- if(mapgen == MAPGEN_MAZE) m_drawMapData = drawMapData;
+ if(mapgen == MAPGEN_DRAWN) m_drawMapData = drawMapData;
Start();
}
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/main.cpp
--- a/QTfrontend/main.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/main.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -49,6 +49,7 @@
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
+ app.setAttribute(Qt::AA_DontShowIconsInMenus,false);
QStringList arguments = app.arguments();
QMap parsedArgs;
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/mapContainer.cpp
--- a/QTfrontend/mapContainer.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/mapContainer.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -177,8 +177,8 @@
connect(maze_size_selection, SIGNAL(currentIndexChanged(int)), this, SLOT(setMaze_size(int)));
gbThemes = new IconedGroupBox(mapWidget);
- gbThemes->setTitleTextPadding(60);
- gbThemes->setContentTopPadding(6);
+ gbThemes->setTitleTextPadding(80);
+ gbThemes->setContentTopPadding(15);
gbThemes->setTitle(tr("Themes"));
//gbThemes->setStyleSheet("padding: 0px"); // doesn't work - stylesheet is set with icon
@@ -224,7 +224,7 @@
QGridLayout* seedLayout = new QGridLayout(seedWidget);
seedLayout->setMargin(0);
- QLabel* seedLabel = new QLabel(tr("Seed"), seedWidget);
+ seedLabel = new QLabel(tr("Seed"), seedWidget);
seedLayout->addWidget(seedLabel, 3, 0);
seedEdit = new QLineEdit(seedWidget);
seedEdit->setMaxLength(54);
@@ -232,11 +232,14 @@
seedLayout->addWidget(seedEdit, 3, 1);
seedLayout->setColumnStretch(1, 5);
seedSet = new QPushButton(seedWidget);
- seedSet->setText(QPushButton::tr("Set"));
+ seedSet->setText(QPushButton::tr("more"));
connect(seedSet, SIGNAL(clicked()), this, SLOT(seedEdited()));
seedLayout->setColumnStretch(2, 1);
seedLayout->addWidget(seedSet, 3, 2);
+ seedLabel->setVisible(false);
+ seedEdit->setVisible(false);
+
setRandomSeed();
setRandomTheme();
}
@@ -370,7 +373,7 @@
chooseMap->setItemData(1, mapInfo);
mapInfo[0] = QString("+drawn+");
chooseMap->setItemData(2, mapInfo);
- gbThemes->setIcon(QIcon(QString("%1/Themes/%2/icon.png").arg(datadir->absolutePath()).arg(theme)));
+ gbThemes->setIcon(QIcon(QString("%1/Themes/%2/icon@2x.png").arg(datadir->absolutePath()).arg(theme)));
emit themeChanged(theme);
}
@@ -561,6 +564,14 @@
void HWMapContainer::seedEdited()
{
+ if (seedLabel->isVisible() == false )
+ {
+ seedLabel->setVisible(true);
+ seedEdit->setVisible(true);
+ seedSet->setText(tr("Set"));
+ return;
+ }
+
if (seedEdit->text().isEmpty())
seedEdit->setText(m_seed);
else
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/mapContainer.h
--- a/QTfrontend/mapContainer.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/mapContainer.h Wed Feb 02 11:28:38 2011 +0300
@@ -56,6 +56,7 @@
QByteArray getDrawnMapData();
DrawMapScene * getDrawMapScene();
void mapDrawingFinished();
+ QLineEdit* seedEdit;
public slots:
void askForGeneratedPreview();
@@ -102,8 +103,8 @@
QListWidget* lwThemes;
HWMap* pMap;
QString m_seed;
- QLineEdit* seedEdit;
QPushButton* seedSet;
+ QLabel* seedLabel;
int hhLimit;
int templateFilter;
QPixmap hhSmall;
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/newnetclient.cpp
--- a/QTfrontend/newnetclient.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/newnetclient.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -276,7 +276,7 @@
return;
}
if (netClientState == 2)
- emit chatStringLobby(HWProto::formatChatMsg(lst[1], lst[2]));
+ emit chatStringLobby(lst[1], HWProto::formatChatMsgForFrontend(lst[2]));
else
emit chatStringFromNet(HWProto::formatChatMsg(lst[1], lst[2]));
return;
@@ -418,7 +418,7 @@
}
emit nickAddedLobby(lst[i], false);
- emit chatStringLobby(tr("%1 *** %2 has joined").arg('\x03').arg(lst[i]));
+ emit chatStringLobby(lst[i], tr("%1 *** %2 has joined").arg('\x03').arg("|nick|"));
}
return;
}
@@ -489,6 +489,26 @@
return;
}
+ if (lst[0] == "NOTICE") {
+ if(lst.size() < 2)
+ {
+ qWarning("Net: Bad NOTICE message");
+ return;
+ }
+
+ bool ok;
+ int n = lst[1].toInt(&ok);
+ if(!ok)
+ {
+ qWarning("Net: Bad NOTICE message");
+ return;
+ }
+
+ handleNotice(n);
+
+ return;
+ }
+
if (lst[0] == "TEAM_ACCEPTED") {
if (lst.size() != 2)
{
@@ -752,3 +772,28 @@
{
RawSendNet(QString("GET_SERVER_VAR"));
}
+
+void HWNewNet::handleNotice(int n)
+{
+ switch(n)
+ {
+ case 0:
+ {
+ bool ok = false;
+ QString newNick = QInputDialog::getText(0, tr("Nickname"), tr("Some one already uses\n your nickname %1\non the server.\nPlease pick another nickname:").arg(mynick), QLineEdit::Normal, mynick, &ok);
+
+ if (!ok || newNick.isEmpty()) {
+ Disconnect();
+ emit Disconnected();
+ return;
+ }
+
+ config->setValue("net/nick", newNick);
+ mynick = newNick;
+
+ RawSendNet(QString("NICK%1%2").arg(delimeter).arg(newNick));
+
+ break;
+ }
+ }
+}
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/newnetclient.h
--- a/QTfrontend/newnetclient.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/newnetclient.h Wed Feb 02 11:28:38 2011 +0300
@@ -86,6 +86,7 @@
void RawSendNet(const QString & buf);
void RawSendNet(const QByteArray & buf);
void ParseCmd(const QStringList & lst);
+ void handleNotice(int n);
int loginStep;
int netClientState;
@@ -112,6 +113,7 @@
void hhnumChanged(const HWTeam&);
void teamColorChanged(const HWTeam&);
void chatStringLobby(const QString&);
+ void chatStringLobby(const QString&, const QString&);
void chatStringFromNet(const QString&);
void chatStringFromMe(const QString&);
void chatStringFromMeLobby(const QString&);
@@ -161,7 +163,7 @@
void ClientRead();
void OnConnect();
void OnDisconnect();
- void displayError(QAbstractSocket::SocketError socketError);
+ void displayError(QAbstractSocket::SocketError socketError);
};
#endif // _NEW_NETCLIENT_INCLUDED
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/pages.cpp
--- a/QTfrontend/pages.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/pages.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -40,6 +40,7 @@
#include
#include
#include
+#include
#include "ammoSchemeModel.h"
#include "pages.h"
@@ -121,7 +122,7 @@
Tips << tr("We're open to suggestions and constructive feedback. If you don't like something or got a great idea, let us know!", "Tips");
Tips << tr("Especially while playing online be polite and always remember there might be some minors playing with or against you as well!", "Tips");
Tips << tr("Special game modes such as 'Vampirism' or 'Karma' allow you to develop completely new tactics. Try them in a custom game!", "Tips");
- Tips << tr("The Windows version of Hedgewars supports Xfire. Make sure to add Hedgwars to its game list so your friends can see you playing.", "Tips");
+ Tips << tr("The Windows version of Hedgewars supports Xfire. Make sure to add Hedgewars to its game list so your friends can see you playing.", "Tips");
Tips << tr("You should never install Hedgewars on computers you don't own (school, university, work, etc.). Please ask the responsible person instead!", "Tips");
Tips << tr("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");
Tips << tr("No hedgehogs were harmed in making this game.", "Tips");
@@ -131,13 +132,13 @@
Tips << tr("Most weapons won't work once they touch the water. The Homing Bee as well as the Cake are exceptions to this.", "Tips");
Tips << tr("The Old Limbuger only causes a small explosion. However the wind affected smelly cloud can poison lots of hogs at once.", "Tips");
Tips << tr("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");
- Tips << tr("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");
+ Tips << tr("The Homing Bee can be tricky to use. Its turn radius depends on it's velocity, so try to not use full power.", "Tips");
Tips << tr("Sticky Mines are a perfect tool to create small chain reactions knocking enemy hedgehogs into dire situations ... or water.", "Tips");
Tips << tr("The Hammer is most effective when used on bridges or girders. Hit hogs will just break through the ground.", "Tips");
Tips << tr("If you're stuck behind an enemy hedgehog, use the Hammer to free yourself without getting damaged by an explosion.", "Tips");
Tips << tr("The Cake's maximum walking distance depends on the ground it has to pass. Use [attack] to detonate it early.", "Tips");
Tips << tr("The Flame Thrower is a weapon but it can be used for tunnel digging as well.", "Tips");
- Tips << tr("Use the Incinerating Grenade to temporary keep hedgehogs from passing terrain such as tunnels or platforms.", "Tips");
+ Tips << tr("Use the Molotov or Flame Thrower to temporary keep hedgehogs from passing terrain such as tunnels or platforms.", "Tips");
Tips << tr("Want to know who's behind the game? Click on the Hedgewars logo in the main menu to see the credits.", "Tips");
Tips << tr("Like Hedgewars? Become a fan on %1 or follow us on %2!", "Tips").arg("Facebook").arg("Twitter");
Tips << tr("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");
@@ -563,7 +564,6 @@
SchemeDelete->setIconSize(pmDelete.size());
SchemeDelete->setIcon(pmDelete);
SchemeDelete->setMaximumWidth(pmDelete.width() + 6);
- SchemeDelete->setEnabled(false);
WeaponsLayout->addWidget(SchemeDelete, 1, 4);
QLabel* WeaponLabel = new QLabel(groupWeapons);
@@ -617,6 +617,7 @@
editNetNick = new QLineEdit(groupMisc);
editNetNick->setMaxLength(20);
editNetNick->setText(QLineEdit::tr("unnamed"));
+ connect(editNetNick, SIGNAL(editingFinished()), this, SLOT(trimNetNick()));
MiscLayout->addWidget(editNetNick, 0, 1);
QLabel *labelLanguage = new QLabel(groupMisc);
@@ -669,6 +670,7 @@
QVBoxLayout * GBAlayout = new QVBoxLayout(AGGroupBox);
QHBoxLayout * GBAreslayout = new QHBoxLayout(0);
+ QHBoxLayout * GBAstereolayout = new QHBoxLayout(0);
QHBoxLayout * GBAqualayout = new QHBoxLayout(0);
CBFrontendFullscreen = new QCheckBox(AGGroupBox);
@@ -704,6 +706,7 @@
CBFullscreen = new QCheckBox(AGGroupBox);
CBFullscreen->setText(QCheckBox::tr("Fullscreen"));
GBAlayout->addWidget(CBFullscreen);
+ connect(CBFullscreen, SIGNAL(stateChanged(int)), this, SLOT(setFullscreen(void)));
QLabel * quality = new QLabel(AGGroupBox);
quality->setText(QLabel::tr("Quality"));
@@ -717,6 +720,25 @@
SLQuality->setFixedWidth(150);
GBAqualayout->addWidget(SLQuality);
GBAlayout->addLayout(GBAqualayout);
+ QLabel * stereo = new QLabel(AGGroupBox);
+ stereo->setText(QLabel::tr("Stereo rendering"));
+ GBAstereolayout->addWidget(stereo);
+
+ 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"));
+ connect(CBStereoMode, SIGNAL(currentIndexChanged(int)), this, SLOT(forceFullscreen(int)));
+
+ GBAstereolayout->addWidget(CBStereoMode);
+ GBAlayout->addLayout(GBAstereolayout);
hr = new QFrame(AGGroupBox);
hr->setFrameStyle(QFrame::HLine);
@@ -781,8 +803,39 @@
BtnBack->setFixedHeight(BtnSaveOptions->height());
BtnBack->setFixedWidth(BtnBack->width()+2);
BtnBack->setStyleSheet("QPushButton{margin: 22px 0 9px 2px;}");
+}
-// BtnAssociateFiles = addButton("");
+void PageOptions::forceFullscreen(int index)
+{
+ if (index != 0) {
+ previousFullscreenValue = this->CBFullscreen->isChecked();
+ this->CBFullscreen->setChecked(true);
+ this->CBFullscreen->setEnabled(false);
+ previousQuality = this->SLQuality->value();
+ this->SLQuality->setValue(this->SLQuality->maximum());
+ this->SLQuality->setEnabled(false);
+ } else {
+ this->CBFullscreen->setChecked(previousFullscreenValue);
+ this->CBFullscreen->setEnabled(true);
+ this->SLQuality->setValue(previousQuality);
+ this->SLQuality->setEnabled(true);
+ }
+}
+
+void PageOptions::setFullscreen(void)
+{
+ int tmp = this->CBResolution->currentIndex();
+ if (this->CBFullscreen->isChecked())
+ this->CBResolution->setCurrentIndex(0);
+ else
+ this->CBResolution->setCurrentIndex(previousResolutionIndex);
+ previousResolutionIndex = tmp;
+ this->CBResolution->setEnabled(!this->CBFullscreen->isChecked());
+}
+
+void PageOptions::trimNetNick()
+{
+ editNetNick->setText(editNetNick->text().trimmed());
}
PageNet::PageNet(QWidget* parent) : AbstractPage(parent)
@@ -931,6 +984,7 @@
// chatwidget
pChatWidget = new HWChatWidget(this, gameSettings, sdli, true);
pChatWidget->setShowReady(true); // show status bulbs by default
+ pChatWidget->setShowFollow(false); // don't show follow in nicks' context menus
pageLayout->addWidget(pChatWidget, 2, 0, 1, 2);
pageLayout->setRowStretch(1, 100);
@@ -1063,7 +1117,10 @@
tmpdir.setFilter(QDir::Files);
CBSelect->addItems(tmpdir.entryList(QStringList("*.lua")).replaceInStrings(QRegExp("^(.*)\\.lua"), "\\1"));
for(int i = 0; i < CBSelect->count(); i++)
+ {
CBSelect->setItemData(i, CBSelect->itemText(i));
+ CBSelect->setItemText(i, CBSelect->itemText(i).replace("_", " "));
+ }
pageLayout->addWidget(CBSelect, 1, 1);
@@ -1104,23 +1161,25 @@
QGridLayout * pageLayout = new QGridLayout(this);
pWeapons = new SelWeaponWidget(cAmmoNumber, this);
- pageLayout->addWidget(pWeapons, 0, 0, 1, 6);
+ pageLayout->addWidget(pWeapons, 0, 0, 1, 5);
- BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, true);
- BtnDefault = addButton(tr("Default"), pageLayout, 1, 2);
- BtnNew = addButton(tr("New"), pageLayout, 1, 3);
- BtnDelete = addButton(tr("Delete"), pageLayout, 1, 4);
- BtnSave = addButton(":/res/Save.png", pageLayout, 1, 5, true);
+ BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, 2, 1, true);
+ BtnDefault = addButton(tr("Default"), pageLayout, 1, 3);
+ BtnNew = addButton(tr("New"), pageLayout, 1, 2);
+ BtnCopy = addButton(tr("Copy"), pageLayout, 2, 2);
+ BtnDelete = addButton(tr("Delete"), pageLayout, 2, 3);
+ BtnSave = addButton(":/res/Save.png", pageLayout, 1, 4, 2, 1, true);
BtnSave->setStyleSheet("QPushButton{margin: 24px 0px 0px 0px;}");
BtnBack->setFixedHeight(BtnSave->height());
BtnBack->setStyleSheet("QPushButton{margin-top: 31px;}");
selectWeaponSet = new QComboBox(this);
- pageLayout->addWidget(selectWeaponSet, 1, 1);
+ pageLayout->addWidget(selectWeaponSet, 1, 1, 2, 1);
connect(BtnDefault, SIGNAL(clicked()), pWeapons, SLOT(setDefault()));
connect(BtnSave, SIGNAL(clicked()), pWeapons, SLOT(save()));
connect(BtnNew, SIGNAL(clicked()), pWeapons, SLOT(newWeaponsName()));
+ connect(BtnCopy, SIGNAL(clicked()), pWeapons, SLOT(copy()));
connect(selectWeaponSet, SIGNAL(currentIndexChanged(const QString&)), pWeapons, SLOT(setWeaponsName(const QString&)));
}
@@ -1301,6 +1360,8 @@
compString = "Random Map";
} else if (a == 5 && compString == "+maze+") {
compString = "Random Maze";
+ } else if (a == 5 && compString == "+drawn+") {
+ compString = "Drawn Map";
}
if (compString.contains(searchText->text(), Qt::CaseInsensitive)) {
found = true;
@@ -1502,7 +1563,7 @@
sp.setVerticalPolicy(QSizePolicy::MinimumExpanding);
sp.setHorizontalPolicy(QSizePolicy::Expanding);
- pageLayout->addWidget(gb, 1,0,13,4);
+ pageLayout->addWidget(gb, 1,0,13,5);
gbGameModes = new QGroupBox(QGroupBox::tr("Game Modifiers"), gb);
gbBasicSettings = new QGroupBox(QGroupBox::tr("Basic Settings"), gb);
@@ -1829,12 +1890,14 @@
mapper = new QDataWidgetMapper(this);
BtnBack = addButton(":/res/Exit.png", pageLayout, 15, 0, true);
- BtnNew = addButton(tr("New"), pageLayout, 15, 2);
- BtnDelete = addButton(tr("Delete"), pageLayout, 15, 3);
+ BtnCopy = addButton(tr("Copy"), pageLayout, 15, 2);
+ BtnNew = addButton(tr("New"), pageLayout, 15, 3);
+ BtnDelete = addButton(tr("Delete"), pageLayout, 15, 4);
selectScheme = new QComboBox(this);
pageLayout->addWidget(selectScheme, 15, 1);
+ connect(BtnCopy, SIGNAL(clicked()), this, SLOT(copyRow()));
connect(BtnNew, SIGNAL(clicked()), this, SLOT(newRow()));
connect(BtnDelete, SIGNAL(clicked()), this, SLOT(deleteRow()));
connect(selectScheme, SIGNAL(currentIndexChanged(int)), mapper, SLOT(setCurrentIndex(int)));
@@ -1891,7 +1954,14 @@
void PageScheme::newRow()
{
QAbstractItemModel * model = mapper->model();
- model->insertRow(model->rowCount());
+ model->insertRow(-1);
+ selectScheme->setCurrentIndex(model->rowCount() - 1);
+}
+
+void PageScheme::copyRow()
+{
+ QAbstractItemModel * model = mapper->model();
+ model->insertRow(selectScheme->currentIndex());
selectScheme->setCurrentIndex(model->rowCount() - 1);
}
@@ -1954,6 +2024,8 @@
pageLayout->addWidget(lblPreview, 4, 0);
tb = new QTextBrowser(this);
+ tb->setOpenExternalLinks(true);
+ tb->document()->setDefaultStyleSheet(HWChatWidget::STYLE);
pageLayout->addWidget(tb, 4, 1, 1, 2);
connect(leServerMessageNew, SIGNAL(textEdited(const QString &)), tb, SLOT(setHtml(const QString &)));
connect(leServerMessageOld, SIGNAL(textEdited(const QString &)), tb, SLOT(setHtml(const QString &)));
@@ -2018,8 +2090,34 @@
{
QGridLayout * pageLayout = new QGridLayout(this);
- BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, true);
+ QPushButton * pbUndo = addButton(tr("Undo"), pageLayout, 0, 0);
+ QPushButton * pbClear = addButton(tr("Clear"), pageLayout, 1, 0);
+ QPushButton * pbLoad = addButton(tr("Load"), pageLayout, 2, 0);
+ QPushButton * pbSave = addButton(tr("Save"), pageLayout, 3, 0);
+
+ BtnBack = addButton(":/res/Exit.png", pageLayout, 5, 0, true);
drawMapWidget = new DrawMapWidget(this);
- pageLayout->addWidget(drawMapWidget, 0, 0, 1, 2);
+ pageLayout->addWidget(drawMapWidget, 0, 1, 5, 1);
+
+ connect(pbUndo, SIGNAL(clicked()), drawMapWidget, SLOT(undo()));
+ connect(pbClear, SIGNAL(clicked()), drawMapWidget, SLOT(clear()));
+ connect(pbLoad, SIGNAL(clicked()), this, SLOT(load()));
+ connect(pbSave, SIGNAL(clicked()), this, SLOT(save()));
}
+
+void PageDrawMap::load()
+{
+ QString fileName = QFileDialog::getOpenFileName(this, tr("Load drawn map"), ".", tr("Drawn Maps (*.hwmap);;All files (*.*)"));
+
+ if(!fileName.isEmpty())
+ drawMapWidget->load(fileName);
+}
+
+void PageDrawMap::save()
+{
+ QString fileName = QFileDialog::getSaveFileName(this, tr("Save drawn map"), ".", tr("Drawn Maps (*.hwmap);;All files (*.*)"));
+
+ if(!fileName.isEmpty())
+ drawMapWidget->save(fileName);
+}
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/pages.h
--- a/QTfrontend/pages.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/pages.h Wed Feb 02 11:28:38 2011 +0300
@@ -74,7 +74,7 @@
Q_UNUSED(parent);
font14 = new QFont("MS Shell Dlg", 14);
- setFocusPolicy(Qt::StrongFocus);
+ //setFocusPolicy(Qt::StrongFocus);
}
virtual ~AbstractPage() {};
@@ -234,6 +234,7 @@
QComboBox *CBTeamName;
IconedGroupBox *AGGroupBox;
QComboBox *CBResolution;
+ QComboBox *CBStereoMode;
QCheckBox *CBEnableSound;
QCheckBox *CBEnableFrontendSound;
QCheckBox *CBEnableMusic;
@@ -254,6 +255,16 @@
QLineEdit *editNetNick;
QSlider *SLQuality;
QCheckBox *CBFrontendEffects;
+
+private:
+ bool previousFullscreenValue;
+ int previousResolutionIndex;
+ int previousQuality;
+
+private slots:
+ void forceFullscreen(int index);
+ void setFullscreen(void);
+ void trimNetNick();
};
class PageNet : public AbstractPage
@@ -395,6 +406,7 @@
QPushButton *BtnDefault;
QPushButton *BtnDelete;
QPushButton *BtnNew;
+ QPushButton *BtnCopy;
QPushButton *BtnBack;
SelWeaponWidget* pWeapons;
QComboBox* selectWeaponSet;
@@ -469,6 +481,7 @@
PageScheme(QWidget* parent = 0);
QPushButton * BtnBack;
+ QPushButton * BtnCopy;
QPushButton * BtnNew;
QPushButton * BtnDelete;
QPushButton * BtnSave;
@@ -478,6 +491,7 @@
public slots:
void newRow();
+ void copyRow();
void deleteRow();
private:
@@ -587,6 +601,10 @@
QPushButton * BtnBack;
DrawMapWidget * drawMapWidget;
+
+private slots:
+ void load();
+ void save();
};
#endif // PAGES_H
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/proto.cpp
--- a/QTfrontend/proto.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/proto.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -45,6 +45,11 @@
return buf;
}
+QString HWProto::formatChatMsgForFrontend(const QString & msg)
+{
+ return formatChatMsg("|nick|", msg);
+}
+
QString HWProto::formatChatMsg(const QString & nick, const QString & msg)
{
if(msg.left(4) == "/me ")
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/proto.h
--- a/QTfrontend/proto.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/proto.h Wed Feb 02 11:28:38 2011 +0300
@@ -34,6 +34,7 @@
static QByteArray & addByteArrayToBuffer(QByteArray & buf, const QByteArray & msg);
static QByteArray & addStringListToBuffer(QByteArray & buf, const QStringList & strList);
static QString formatChatMsg(const QString & nick, const QString & msg);
+ static QString formatChatMsgForFrontend(const QString & msg);
};
#endif // _PROTO_H
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/res/btnMoreWind.png
Binary file QTfrontend/res/btnMoreWind.png has changed
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/res/btnNoWind.png
Binary file QTfrontend/res/btnNoWind.png has changed
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/selectWeapon.cpp
--- a/QTfrontend/selectWeapon.cpp Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/selectWeapon.cpp Wed Feb 02 11:28:38 2011 +0300
@@ -269,3 +269,10 @@
{
return wconf->allKeys();
}
+
+void SelWeaponWidget::copy()
+{
+ QString ammo = getWeaponsString(curWeaponsName);
+ setWeaponsName(tr("copy of") + " " + curWeaponsName);
+ setWeapons(ammo);
+}
diff -r 8bdc879ee6b2 -r 0eab727d4717 QTfrontend/selectWeapon.h
--- a/QTfrontend/selectWeapon.h Mon Jan 31 21:40:17 2011 +0300
+++ b/QTfrontend/selectWeapon.h Wed Feb 02 11:28:38 2011 +0300
@@ -59,6 +59,7 @@
void deleteWeaponsName();
void newWeaponsName();
void save();
+ void copy();
signals:
void weaponsChanged();
diff -r 8bdc879ee6b2 -r 0eab727d4717 doc/Release.txt
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/Actions.hs
--- a/gameServer/Actions.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/Actions.hs Wed Feb 02 11:28:38 2011 +0300
@@ -1,414 +1,414 @@
-{-# LANGUAGE OverloadedStrings #-}
-module Actions where
-
-import Control.Concurrent
-import Control.Concurrent.Chan
-import qualified Data.IntSet as IntSet
-import qualified Data.Set as Set
-import qualified Data.Sequence as Seq
-import System.Log.Logger
-import Control.Monad
-import Data.Time
-import Data.Maybe
-import Control.Monad.Reader
-import Control.Monad.State.Strict
-import qualified Data.ByteString.Char8 as B
-import Control.DeepSeq
------------------------------
-import CoreTypes
-import Utils
-import ClientIO
-import ServerState
-
-data Action =
- AnswerClients ![ClientChan] ![B.ByteString]
- | SendServerMessage
- | SendServerVars
- | MoveToRoom RoomIndex
- | MoveToLobby B.ByteString
- | RemoveTeam B.ByteString
- | RemoveRoom
- | UnreadyRoomClients
- | JoinLobby
- | ProtocolError B.ByteString
- | Warning B.ByteString
- | NoticeMessage Notice
- | ByeClient B.ByteString
- | KickClient ClientIndex
- | KickRoomClient ClientIndex
- | BanClient B.ByteString
- | ChangeMaster
- | RemoveClientTeams ClientIndex
- | ModifyClient (ClientInfo -> ClientInfo)
- | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
- | ModifyRoom (RoomInfo -> RoomInfo)
- | ModifyServerInfo (ServerInfo -> ServerInfo)
- | AddRoom B.ByteString B.ByteString
- | CheckRegistered
- | ClearAccountsCache
- | ProcessAccountInfo AccountInfo
- | AddClient ClientInfo
- | DeleteClient ClientIndex
- | PingAll
- | StatsAction
-
-type CmdHandler = [B.ByteString] -> Reader (ClientIndex, IRnC) [Action]
-
-instance NFData Action where
- rnf (AnswerClients chans msg) = chans `deepseq` msg `deepseq` ()
- rnf a = a `seq` ()
-
-instance NFData B.ByteString
-instance NFData (Chan a)
-
-othersChans = do
- cl <- client's id
- ri <- clientRoomA
- liftM (map sendChan . filter (/= cl)) $ roomClientsS ri
-
-processAction :: Action -> StateT ServerState IO ()
-
-
-processAction (AnswerClients chans msg) = do
- io $ mapM_ (flip writeChan (msg `deepseq` msg)) (chans `deepseq` chans)
-
-
-processAction SendServerMessage = do
- chan <- client's sendChan
- protonum <- client's clientProto
- si <- liftM serverInfo get
- let message = if protonum < latestReleaseVersion si then
- serverMessageForOldVersions si
- else
- serverMessage si
- processAction $ AnswerClients [chan] ["SERVER_MESSAGE", message]
-
-
-processAction SendServerVars = do
- chan <- client's sendChan
- si <- gets serverInfo
- io $ writeChan chan ("SERVER_VARS" : vars si)
- where
- vars si = [
- "MOTD_NEW", serverMessage si,
- "MOTD_OLD", serverMessageForOldVersions si,
- "LATEST_PROTO", B.pack . show $ latestReleaseVersion si
- ]
-
-
-processAction (ProtocolError msg) = do
- chan <- client's sendChan
- processAction $ AnswerClients [chan] ["ERROR", msg]
-
-
-processAction (Warning msg) = do
- chan <- client's sendChan
- processAction $ AnswerClients [chan] ["WARNING", msg]
-
-processAction (NoticeMessage n) = do
- chan <- client's sendChan
- processAction $ AnswerClients [chan] ["NOTICE", B.pack . show . fromEnum $ n]
-
-processAction (ByeClient msg) = do
- (Just ci) <- gets clientIndex
- rnc <- gets roomsClients
- ri <- clientRoomA
-
- chan <- client's sendChan
- clNick <- client's nick
-
- when (ri /= lobbyId) $ do
- processAction $ MoveToLobby ("quit: " `B.append` msg)
- return ()
-
- clientsChans <- liftM (Prelude.map sendChan . Prelude.filter logonPassed) $! allClientsS
- io $ do
- infoM "Clients" (show ci ++ " quits: " ++ (B.unpack msg))
-
- processAction $ AnswerClients [chan] ["BYE", msg]
- processAction $ AnswerClients clientsChans ["LOBBY:LEFT", clNick, msg]
-
- s <- get
- put $! s{removedClients = ci `Set.insert` removedClients s}
-
-processAction (DeleteClient ci) = do
- rnc <- gets roomsClients
- io $ removeClient rnc ci
-
- s <- get
- put $! s{removedClients = ci `Set.delete` removedClients s}
-
-processAction (ModifyClient f) = do
- (Just ci) <- gets clientIndex
- rnc <- gets roomsClients
- io $ modifyClient rnc f ci
- return ()
-
-processAction (ModifyClient2 ci f) = do
- rnc <- gets roomsClients
- io $ modifyClient rnc f ci
- return ()
-
-
-processAction (ModifyRoom f) = do
- rnc <- gets roomsClients
- ri <- clientRoomA
- io $ modifyRoom rnc f ri
- return ()
-
-
-processAction (ModifyServerInfo f) =
- modify (\s -> s{serverInfo = f $ serverInfo s})
-
-
-processAction (MoveToRoom ri) = do
- (Just ci) <- gets clientIndex
- rnc <- gets roomsClients
-
- io $ do
- modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False}) ci
- modifyRoom rnc (\r -> r{playersIn = (playersIn r) + 1}) ri
- moveClientToRoom rnc ri ci
-
- chans <- liftM (map sendChan) $ roomClientsS ri
- clNick <- client's nick
-
- processAction $ AnswerClients chans ["JOINED", clNick]
-
-
-processAction (MoveToLobby msg) = do
- (Just ci) <- gets clientIndex
- ri <- clientRoomA
- rnc <- gets roomsClients
- (gameProgress, playersNum) <- io $ room'sM rnc (\r -> (gameinprogress r, playersIn r)) ri
- ready <- client's isReady
- master <- client's isMaster
--- client <- client's id
- clNick <- client's nick
- chans <- othersChans
-
- if master then
- if gameProgress && playersNum > 1 then
- mapM_ processAction [ChangeMaster, AnswerClients chans ["LEFT", clNick, msg], NoticeMessage AdminLeft, RemoveClientTeams ci]
- else
- processAction RemoveRoom
- else
- mapM_ processAction [AnswerClients chans ["LEFT", clNick, msg], RemoveClientTeams ci]
-
- io $ do
- modifyRoom rnc (\r -> r{
- playersIn = (playersIn r) - 1,
- readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
- }) ri
- moveClientToLobby rnc ci
-
-processAction ChangeMaster = do
- ri <- clientRoomA
- rnc <- gets roomsClients
- newMasterId <- liftM head . io $ roomClientsIndicesM rnc ri
- newMaster <- io $ client'sM rnc id newMasterId
- let newRoomName = nick newMaster
- mapM_ processAction [
- ModifyRoom (\r -> r{masterID = newMasterId, name = newRoomName}),
- ModifyClient2 newMasterId (\c -> c{isMaster = True}),
- AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
- ]
-
-processAction (AddRoom roomName roomPassword) = do
- Just clId <- gets clientIndex
- rnc <- gets roomsClients
- proto <- io $ client'sM rnc clientProto clId
-
- let room = newRoom{
- masterID = clId,
- name = roomName,
- password = roomPassword,
- roomProto = proto
- }
-
- rId <- io $ addRoom rnc room
-
- processAction $ MoveToRoom rId
-
- chans <- liftM (map sendChan) $! roomClientsS lobbyId
-
- mapM_ processAction [
- AnswerClients chans ["ROOM", "ADD", roomName]
- , ModifyClient (\cl -> cl{isMaster = True})
- ]
-
-
-processAction RemoveRoom = do
- Just clId <- gets clientIndex
- rnc <- gets roomsClients
- ri <- io $ clientRoomM rnc clId
- roomName <- io $ room'sM rnc name ri
- others <- othersChans
- lobbyChans <- liftM (map sendChan) $! roomClientsS lobbyId
-
- mapM_ processAction [
- AnswerClients lobbyChans ["ROOM", "DEL", roomName],
- AnswerClients others ["ROOMABANDONED", roomName]
- ]
-
- io $ removeRoom rnc ri
-
-
-processAction (UnreadyRoomClients) = do
- rnc <- gets roomsClients
- ri <- clientRoomA
- roomPlayers <- roomClientsS ri
- roomClIDs <- io $ roomClientsIndicesM rnc ri
- processAction $ AnswerClients (map sendChan roomPlayers) ("NOT_READY" : map nick roomPlayers)
- io $ mapM_ (modifyClient rnc (\cl -> cl{isReady = False})) roomClIDs
- processAction $ ModifyRoom (\r -> r{readyPlayers = 0})
-
-
-processAction (RemoveTeam teamName) = do
- rnc <- gets roomsClients
- cl <- client's id
- ri <- clientRoomA
- inGame <- io $ room'sM rnc gameinprogress ri
- chans <- othersChans
- if inGame then
- mapM_ processAction [
- AnswerClients chans ["REMOVE_TEAM", teamName],
- ModifyRoom (\r -> r{teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r})
- ]
- else
- mapM_ processAction [
- AnswerClients chans ["EM", rmTeamMsg],
- ModifyRoom (\r -> r{
- teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r,
- leftTeams = teamName : leftTeams r,
- roundMsgs = roundMsgs r Seq.|> rmTeamMsg
- })
- ]
- where
- rmTeamMsg = toEngineMsg $ (B.singleton 'F') `B.append` teamName
-
-
-processAction (RemoveClientTeams clId) = do
- rnc <- gets roomsClients
-
- removeTeamActions <- io $ do
- clNick <- client'sM rnc nick clId
- rId <- clientRoomM rnc clId
- roomTeams <- room'sM rnc teams rId
- return . Prelude.map (RemoveTeam . teamname) . Prelude.filter (\t -> teamowner t == clNick) $ roomTeams
-
- mapM_ processAction removeTeamActions
-
-
-
-processAction CheckRegistered = do
- (Just ci) <- gets clientIndex
- n <- client's nick
- h <- client's host
- db <- gets (dbQueries . serverInfo)
- io $ writeChan db $ CheckAccount ci n h
- return ()
-
-
-processAction ClearAccountsCache = do
- dbq <- gets (dbQueries . serverInfo)
- io $ writeChan dbq ClearCache
- return ()
-
-
-processAction (ProcessAccountInfo info) =
- case info of
- HasAccount passwd isAdmin -> do
- chan <- client's sendChan
- processAction $ AnswerClients [chan] ["ASKPASSWORD"]
- Guest -> do
- processAction JoinLobby
- Admin -> do
- mapM processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
- chan <- client's sendChan
- processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
-
-
-processAction JoinLobby = do
- chan <- client's sendChan
- clientNick <- client's nick
- (lobbyNicks, clientsChans) <- liftM (unzip . Prelude.map (\c -> (nick c, sendChan c)) . Prelude.filter logonPassed) $! allClientsS
- mapM_ processAction $
- (AnswerClients clientsChans ["LOBBY:JOINED", clientNick])
- : [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
- ++ [ModifyClient (\cl -> cl{logonPassed = True}), SendServerMessage]
-
-{-
-processAction (clID, serverInfo, rnc) (RoomAddThisClient rID) =
- processAction (
- clID,
- serverInfo,
- adjust (\cl -> cl{roomID = rID, teamsInGame = if rID == 0 then teamsInGame cl else 0}) clID clients,
- adjust (\r -> r{playersIDs = IntSet.insert clID (playersIDs r), playersIn = (playersIn r) + 1}) rID $
- adjust (\r -> r{playersIDs = IntSet.delete clID (playersIDs r)}) 0 rooms
- ) joinMsg
- where
- client = clients ! clID
- joinMsg = if rID == 0 then
- AnswerAllOthers ["LOBBY:JOINED", nick client]
- else
- AnswerThisRoom ["JOINED", nick client]
-
-processAction (clID, serverInfo, rnc) (KickClient kickID) =
- liftM2 replaceID (return clID) (processAction (kickID, serverInfo, rnc) $ ByeClient "Kicked")
-
-
-processAction (clID, serverInfo, rnc) (BanClient banNick) =
- return (clID, serverInfo, rnc)
-
-
-processAction (clID, serverInfo, rnc) (KickRoomClient kickID) = do
- writeChan (sendChan $ clients ! kickID) ["KICKED"]
- liftM2 replaceID (return clID) (processAction (kickID, serverInfo, rnc) $ RoomRemoveThisClient "kicked")
-
--}
-
-processAction (AddClient client) = do
- rnc <- gets roomsClients
- si <- gets serverInfo
- io $ do
- ci <- addClient rnc client
- t <- forkIO $ clientRecvLoop (clientSocket client) (coreChan si) ci
- forkIO $ clientSendLoop (clientSocket client) t (coreChan si) (sendChan client) ci
-
- infoM "Clients" (show ci ++ ": New client. Time: " ++ show (connectTime client))
-
- processAction $ AnswerClients [sendChan client] ["CONNECTED", "Hedgewars server http://www.hedgewars.org/"]
-{- let newLogins = takeWhile (\(_ , time) -> (connectTime client) `diffUTCTime` time <= 11) $ lastLogins serverInfo
-
- if False && (isJust $ host client `Prelude.lookup` newLogins) then
- processAction (ci, serverInfo{lastLogins = newLogins}, rnc) $ ByeClient "Reconnected too fast"
- else
- return (ci, serverInfo)
--}
-
-
-
-processAction PingAll = do
- rnc <- gets roomsClients
- io (allClientsM rnc) >>= mapM_ (kickTimeouted rnc)
- cis <- io $ allClientsM rnc
- chans <- io $ mapM (client'sM rnc sendChan) cis
- io $ mapM_ (modifyClient rnc (\cl -> cl{pingsQueue = pingsQueue cl + 1})) cis
- processAction $ AnswerClients chans ["PING"]
- where
- kickTimeouted rnc ci = do
- pq <- io $ client'sM rnc pingsQueue ci
- when (pq > 0) $
- withStateT (\as -> as{clientIndex = Just ci}) $
- processAction (ByeClient "Ping timeout")
-
-
-processAction (StatsAction) = do
- rnc <- gets roomsClients
- si <- gets serverInfo
- (roomsNum, clientsNum) <- io $ withRoomsAndClients rnc stats
- io $ writeChan (dbQueries si) $ SendStats clientsNum (roomsNum - 1)
- where
- stats irnc = (length $ allRooms irnc, length $ allClients irnc)
-
+{-# LANGUAGE OverloadedStrings #-}
+module Actions where
+
+import Control.Concurrent
+import Control.Concurrent.Chan
+import qualified Data.IntSet as IntSet
+import qualified Data.Set as Set
+import qualified Data.Sequence as Seq
+import System.Log.Logger
+import Control.Monad
+import Data.Time
+import Data.Maybe
+import Control.Monad.Reader
+import Control.Monad.State.Strict
+import qualified Data.ByteString.Char8 as B
+import Control.DeepSeq
+-----------------------------
+import CoreTypes
+import Utils
+import ClientIO
+import ServerState
+
+data Action =
+ AnswerClients ![ClientChan] ![B.ByteString]
+ | SendServerMessage
+ | SendServerVars
+ | MoveToRoom RoomIndex
+ | MoveToLobby B.ByteString
+ | RemoveTeam B.ByteString
+ | RemoveRoom
+ | UnreadyRoomClients
+ | JoinLobby
+ | ProtocolError B.ByteString
+ | Warning B.ByteString
+ | NoticeMessage Notice
+ | ByeClient B.ByteString
+ | KickClient ClientIndex
+ | KickRoomClient ClientIndex
+ | BanClient B.ByteString
+ | ChangeMaster
+ | RemoveClientTeams ClientIndex
+ | ModifyClient (ClientInfo -> ClientInfo)
+ | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo)
+ | ModifyRoom (RoomInfo -> RoomInfo)
+ | ModifyServerInfo (ServerInfo -> ServerInfo)
+ | AddRoom B.ByteString B.ByteString
+ | CheckRegistered
+ | ClearAccountsCache
+ | ProcessAccountInfo AccountInfo
+ | AddClient ClientInfo
+ | DeleteClient ClientIndex
+ | PingAll
+ | StatsAction
+
+type CmdHandler = [B.ByteString] -> Reader (ClientIndex, IRnC) [Action]
+
+instance NFData Action where
+ rnf (AnswerClients chans msg) = chans `deepseq` msg `deepseq` ()
+ rnf a = a `seq` ()
+
+instance NFData B.ByteString
+instance NFData (Chan a)
+
+othersChans = do
+ cl <- client's id
+ ri <- clientRoomA
+ liftM (map sendChan . filter (/= cl)) $ roomClientsS ri
+
+processAction :: Action -> StateT ServerState IO ()
+
+
+processAction (AnswerClients chans msg) = do
+ io $ mapM_ (flip writeChan (msg `deepseq` msg)) (chans `deepseq` chans)
+
+
+processAction SendServerMessage = do
+ chan <- client's sendChan
+ protonum <- client's clientProto
+ si <- liftM serverInfo get
+ let message = if protonum < latestReleaseVersion si then
+ serverMessageForOldVersions si
+ else
+ serverMessage si
+ processAction $ AnswerClients [chan] ["SERVER_MESSAGE", message]
+
+
+processAction SendServerVars = do
+ chan <- client's sendChan
+ si <- gets serverInfo
+ io $ writeChan chan ("SERVER_VARS" : vars si)
+ where
+ vars si = [
+ "MOTD_NEW", serverMessage si,
+ "MOTD_OLD", serverMessageForOldVersions si,
+ "LATEST_PROTO", B.pack . show $ latestReleaseVersion si
+ ]
+
+
+processAction (ProtocolError msg) = do
+ chan <- client's sendChan
+ processAction $ AnswerClients [chan] ["ERROR", msg]
+
+
+processAction (Warning msg) = do
+ chan <- client's sendChan
+ processAction $ AnswerClients [chan] ["WARNING", msg]
+
+processAction (NoticeMessage n) = do
+ chan <- client's sendChan
+ processAction $ AnswerClients [chan] ["NOTICE", B.pack . show . fromEnum $ n]
+
+processAction (ByeClient msg) = do
+ (Just ci) <- gets clientIndex
+ rnc <- gets roomsClients
+ ri <- clientRoomA
+
+ chan <- client's sendChan
+ clNick <- client's nick
+
+ when (ri /= lobbyId) $ do
+ processAction $ MoveToLobby ("quit: " `B.append` msg)
+ return ()
+
+ clientsChans <- liftM (Prelude.map sendChan . Prelude.filter logonPassed) $! allClientsS
+ io $ do
+ infoM "Clients" (show ci ++ " quits: " ++ (B.unpack msg))
+
+ processAction $ AnswerClients [chan] ["BYE", msg]
+ processAction $ AnswerClients clientsChans ["LOBBY:LEFT", clNick, msg]
+
+ s <- get
+ put $! s{removedClients = ci `Set.insert` removedClients s}
+
+processAction (DeleteClient ci) = do
+ rnc <- gets roomsClients
+ io $ removeClient rnc ci
+
+ s <- get
+ put $! s{removedClients = ci `Set.delete` removedClients s}
+
+processAction (ModifyClient f) = do
+ (Just ci) <- gets clientIndex
+ rnc <- gets roomsClients
+ io $ modifyClient rnc f ci
+ return ()
+
+processAction (ModifyClient2 ci f) = do
+ rnc <- gets roomsClients
+ io $ modifyClient rnc f ci
+ return ()
+
+
+processAction (ModifyRoom f) = do
+ rnc <- gets roomsClients
+ ri <- clientRoomA
+ io $ modifyRoom rnc f ri
+ return ()
+
+
+processAction (ModifyServerInfo f) =
+ modify (\s -> s{serverInfo = f $ serverInfo s})
+
+
+processAction (MoveToRoom ri) = do
+ (Just ci) <- gets clientIndex
+ rnc <- gets roomsClients
+
+ io $ do
+ modifyClient rnc (\cl -> cl{teamsInGame = 0, isReady = False, isMaster = False}) ci
+ modifyRoom rnc (\r -> r{playersIn = (playersIn r) + 1}) ri
+ moveClientToRoom rnc ri ci
+
+ chans <- liftM (map sendChan) $ roomClientsS ri
+ clNick <- client's nick
+
+ processAction $ AnswerClients chans ["JOINED", clNick]
+
+
+processAction (MoveToLobby msg) = do
+ (Just ci) <- gets clientIndex
+ ri <- clientRoomA
+ rnc <- gets roomsClients
+ (gameProgress, playersNum) <- io $ room'sM rnc (\r -> (gameinprogress r, playersIn r)) ri
+ ready <- client's isReady
+ master <- client's isMaster
+-- client <- client's id
+ clNick <- client's nick
+ chans <- othersChans
+
+ if master then
+ if gameProgress && playersNum > 1 then
+ mapM_ processAction [ChangeMaster, AnswerClients chans ["LEFT", clNick, msg], NoticeMessage AdminLeft, RemoveClientTeams ci]
+ else
+ processAction RemoveRoom
+ else
+ mapM_ processAction [AnswerClients chans ["LEFT", clNick, msg], RemoveClientTeams ci]
+
+ io $ do
+ modifyRoom rnc (\r -> r{
+ playersIn = (playersIn r) - 1,
+ readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r
+ }) ri
+ moveClientToLobby rnc ci
+
+processAction ChangeMaster = do
+ ri <- clientRoomA
+ rnc <- gets roomsClients
+ newMasterId <- liftM head . io $ roomClientsIndicesM rnc ri
+ newMaster <- io $ client'sM rnc id newMasterId
+ let newRoomName = nick newMaster
+ mapM_ processAction [
+ ModifyRoom (\r -> r{masterID = newMasterId, name = newRoomName}),
+ ModifyClient2 newMasterId (\c -> c{isMaster = True}),
+ AnswerClients [sendChan newMaster] ["ROOM_CONTROL_ACCESS", "1"]
+ ]
+
+processAction (AddRoom roomName roomPassword) = do
+ Just clId <- gets clientIndex
+ rnc <- gets roomsClients
+ proto <- io $ client'sM rnc clientProto clId
+
+ let room = newRoom{
+ masterID = clId,
+ name = roomName,
+ password = roomPassword,
+ roomProto = proto
+ }
+
+ rId <- io $ addRoom rnc room
+
+ processAction $ MoveToRoom rId
+
+ chans <- liftM (map sendChan) $! roomClientsS lobbyId
+
+ mapM_ processAction [
+ AnswerClients chans ["ROOM", "ADD", roomName]
+ , ModifyClient (\cl -> cl{isMaster = True})
+ ]
+
+
+processAction RemoveRoom = do
+ Just clId <- gets clientIndex
+ rnc <- gets roomsClients
+ ri <- io $ clientRoomM rnc clId
+ roomName <- io $ room'sM rnc name ri
+ others <- othersChans
+ lobbyChans <- liftM (map sendChan) $! roomClientsS lobbyId
+
+ mapM_ processAction [
+ AnswerClients lobbyChans ["ROOM", "DEL", roomName],
+ AnswerClients others ["ROOMABANDONED", roomName]
+ ]
+
+ io $ removeRoom rnc ri
+
+
+processAction (UnreadyRoomClients) = do
+ rnc <- gets roomsClients
+ ri <- clientRoomA
+ roomPlayers <- roomClientsS ri
+ roomClIDs <- io $ roomClientsIndicesM rnc ri
+ processAction $ AnswerClients (map sendChan roomPlayers) ("NOT_READY" : map nick roomPlayers)
+ io $ mapM_ (modifyClient rnc (\cl -> cl{isReady = False})) roomClIDs
+ processAction $ ModifyRoom (\r -> r{readyPlayers = 0})
+
+
+processAction (RemoveTeam teamName) = do
+ rnc <- gets roomsClients
+ cl <- client's id
+ ri <- clientRoomA
+ inGame <- io $ room'sM rnc gameinprogress ri
+ chans <- othersChans
+ if inGame then
+ mapM_ processAction [
+ AnswerClients chans ["REMOVE_TEAM", teamName],
+ ModifyRoom (\r -> r{teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r})
+ ]
+ else
+ mapM_ processAction [
+ AnswerClients chans ["EM", rmTeamMsg],
+ ModifyRoom (\r -> r{
+ teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r,
+ leftTeams = teamName : leftTeams r,
+ roundMsgs = roundMsgs r Seq.|> rmTeamMsg
+ })
+ ]
+ where
+ rmTeamMsg = toEngineMsg $ (B.singleton 'F') `B.append` teamName
+
+
+processAction (RemoveClientTeams clId) = do
+ rnc <- gets roomsClients
+
+ removeTeamActions <- io $ do
+ clNick <- client'sM rnc nick clId
+ rId <- clientRoomM rnc clId
+ roomTeams <- room'sM rnc teams rId
+ return . Prelude.map (RemoveTeam . teamname) . Prelude.filter (\t -> teamowner t == clNick) $ roomTeams
+
+ mapM_ processAction removeTeamActions
+
+
+
+processAction CheckRegistered = do
+ (Just ci) <- gets clientIndex
+ n <- client's nick
+ h <- client's host
+ db <- gets (dbQueries . serverInfo)
+ io $ writeChan db $ CheckAccount ci n h
+ return ()
+
+
+processAction ClearAccountsCache = do
+ dbq <- gets (dbQueries . serverInfo)
+ io $ writeChan dbq ClearCache
+ return ()
+
+
+processAction (ProcessAccountInfo info) =
+ case info of
+ HasAccount passwd isAdmin -> do
+ chan <- client's sendChan
+ processAction $ AnswerClients [chan] ["ASKPASSWORD"]
+ Guest -> do
+ processAction JoinLobby
+ Admin -> do
+ mapM processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby]
+ chan <- client's sendChan
+ processAction $ AnswerClients [chan] ["ADMIN_ACCESS"]
+
+
+processAction JoinLobby = do
+ chan <- client's sendChan
+ clientNick <- client's nick
+ (lobbyNicks, clientsChans) <- liftM (unzip . Prelude.map (\c -> (nick c, sendChan c)) . Prelude.filter logonPassed) $! allClientsS
+ mapM_ processAction $
+ (AnswerClients clientsChans ["LOBBY:JOINED", clientNick])
+ : [AnswerClients [chan] ("LOBBY:JOINED" : clientNick : lobbyNicks)]
+ ++ [ModifyClient (\cl -> cl{logonPassed = True}), SendServerMessage]
+
+{-
+processAction (clID, serverInfo, rnc) (RoomAddThisClient rID) =
+ processAction (
+ clID,
+ serverInfo,
+ adjust (\cl -> cl{roomID = rID, teamsInGame = if rID == 0 then teamsInGame cl else 0}) clID clients,
+ adjust (\r -> r{playersIDs = IntSet.insert clID (playersIDs r), playersIn = (playersIn r) + 1}) rID $
+ adjust (\r -> r{playersIDs = IntSet.delete clID (playersIDs r)}) 0 rooms
+ ) joinMsg
+ where
+ client = clients ! clID
+ joinMsg = if rID == 0 then
+ AnswerAllOthers ["LOBBY:JOINED", nick client]
+ else
+ AnswerThisRoom ["JOINED", nick client]
+
+processAction (clID, serverInfo, rnc) (KickClient kickID) =
+ liftM2 replaceID (return clID) (processAction (kickID, serverInfo, rnc) $ ByeClient "Kicked")
+
+
+processAction (clID, serverInfo, rnc) (BanClient banNick) =
+ return (clID, serverInfo, rnc)
+
+
+processAction (clID, serverInfo, rnc) (KickRoomClient kickID) = do
+ writeChan (sendChan $ clients ! kickID) ["KICKED"]
+ liftM2 replaceID (return clID) (processAction (kickID, serverInfo, rnc) $ RoomRemoveThisClient "kicked")
+
+-}
+
+processAction (AddClient client) = do
+ rnc <- gets roomsClients
+ si <- gets serverInfo
+ io $ do
+ ci <- addClient rnc client
+ t <- forkIO $ clientRecvLoop (clientSocket client) (coreChan si) ci
+ forkIO $ clientSendLoop (clientSocket client) t (coreChan si) (sendChan client) ci
+
+ infoM "Clients" (show ci ++ ": New client. Time: " ++ show (connectTime client))
+
+ processAction $ AnswerClients [sendChan client] ["CONNECTED", "Hedgewars server http://www.hedgewars.org/"]
+{- let newLogins = takeWhile (\(_ , time) -> (connectTime client) `diffUTCTime` time <= 11) $ lastLogins serverInfo
+
+ if False && (isJust $ host client `Prelude.lookup` newLogins) then
+ processAction (ci, serverInfo{lastLogins = newLogins}, rnc) $ ByeClient "Reconnected too fast"
+ else
+ return (ci, serverInfo)
+-}
+
+
+
+processAction PingAll = do
+ rnc <- gets roomsClients
+ io (allClientsM rnc) >>= mapM_ (kickTimeouted rnc)
+ cis <- io $ allClientsM rnc
+ chans <- io $ mapM (client'sM rnc sendChan) cis
+ io $ mapM_ (modifyClient rnc (\cl -> cl{pingsQueue = pingsQueue cl + 1})) cis
+ processAction $ AnswerClients chans ["PING"]
+ where
+ kickTimeouted rnc ci = do
+ pq <- io $ client'sM rnc pingsQueue ci
+ when (pq > 0) $
+ withStateT (\as -> as{clientIndex = Just ci}) $
+ processAction (ByeClient "Ping timeout")
+
+
+processAction (StatsAction) = do
+ rnc <- gets roomsClients
+ si <- gets serverInfo
+ (roomsNum, clientsNum) <- io $ withRoomsAndClients rnc stats
+ io $ writeChan (dbQueries si) $ SendStats clientsNum (roomsNum - 1)
+ where
+ stats irnc = (length $ allRooms irnc, length $ allClients irnc)
+
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/CMakeLists.txt
--- a/gameServer/CMakeLists.txt Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/CMakeLists.txt Wed Feb 02 11:28:38 2011 +0300
@@ -1,48 +1,43 @@
find_program(ghc_executable ghc)
if(NOT ghc_executable)
- message(FATAL_ERROR "Cannot find GHC")
+ message(FATAL_ERROR "Cannot find GHC")
endif(NOT ghc_executable)
set(hwserver_sources
- OfficialServer/DBInteraction.hs
- Actions.hs
- ClientIO.hs
- CoreTypes.hs
- HWProtoCore.hs
- HWProtoInRoomState.hs
- HWProtoLobbyState.hs
- HWProtoNEState.hs
- HandlerUtils.hs
- NetRoutines.hs
- Opts.hs
- RoomsAndClients.hs
- ServerCore.hs
- ServerState.hs
- Store.hs
- Utils.hs
- hedgewars-server.hs
- )
+ OfficialServer/DBInteraction.hs
+ Actions.hs
+ ClientIO.hs
+ CoreTypes.hs
+ HWProtoCore.hs
+ HWProtoInRoomState.hs
+ HWProtoLobbyState.hs
+ HWProtoNEState.hs
+ NetRoutines.hs
+ Opts.hs
+ ServerCore.hs
+ Utils.hs
+ hedgewars-server.hs
+ )
set(hwserv_main ${hedgewars_SOURCE_DIR}/gameServer/hedgewars-server.hs)
set(ghc_flags
- -Wall
- --make ${hwserv_main}
- -i${hedgewars_SOURCE_DIR}/gameServer
- -o ${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}
- -odir ${CMAKE_CURRENT_BINARY_DIR}
- -hidir ${CMAKE_CURRENT_BINARY_DIR})
+ --make ${hwserv_main}
+ -i${hedgewars_SOURCE_DIR}/gameServer
+ -o ${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}
+ -odir ${CMAKE_CURRENT_BINARY_DIR}
+ -hidir ${CMAKE_CURRENT_BINARY_DIR})
set(ghc_flags ${haskell_compiler_flags_cmn} ${ghc_flags})
add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}"
- COMMAND "${ghc_executable}"
- ARGS ${ghc_flags}
- MAIN_DEPENDENCY ${hwserv_main}
- DEPENDS ${hwserver_sources}
- )
+ COMMAND "${ghc_executable}"
+ ARGS ${ghc_flags}
+ MAIN_DEPENDENCY ${hwserv_main}
+ DEPENDS ${hwserver_sources}
+ )
add_custom_target(hedgewars-server ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hedgewars-server${CMAKE_EXECUTABLE_SUFFIX}")
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/ClientIO.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/CoreTypes.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/HWProtoCore.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/HWProtoInRoomState.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/HWProtoLobbyState.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/HWProtoNEState.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/NetRoutines.hs
--- a/gameServer/NetRoutines.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/NetRoutines.hs Wed Feb 02 11:28:38 2011 +0300
@@ -1,41 +1,46 @@
-{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
module NetRoutines where
+import Network
import Network.Socket
import System.IO
+import Control.Concurrent
import Control.Concurrent.Chan
+import Control.Concurrent.STM
import qualified Control.Exception as Exception
import Data.Time
-import Control.Monad
-----------------------------
import CoreTypes
+import ClientIO
import Utils
-import RoomsAndClients
-acceptLoop :: Socket -> Chan CoreMessage -> IO ()
-acceptLoop servSock chan = forever $ do
+acceptLoop :: Socket -> Chan CoreMessage -> Int -> IO ()
+acceptLoop servSock coreChan clientCounter = do
Exception.handle
(\(_ :: Exception.IOException) -> putStrLn "exception on connect") $
do
- (sock, sockAddr) <- Network.Socket.accept servSock
+ (socket, sockAddr) <- Network.Socket.accept servSock
+ cHandle <- socketToHandle socket ReadWriteMode
+ hSetBuffering cHandle LineBuffering
clientHost <- sockAddr2String sockAddr
currentTime <- getCurrentTime
-
- sendChan' <- newChan
+
+ sendChan <- newChan
let newClient =
(ClientInfo
- sendChan'
- sock
+ nextID
+ sendChan
+ cHandle
clientHost
currentTime
""
""
False
0
- lobbyId
+ 0
0
False
False
@@ -44,5 +49,12 @@
undefined
)
- writeChan chan $ Accept newClient
+ writeChan coreChan $ Accept newClient
+
+ forkIO $ clientRecvLoop cHandle coreChan nextID
+ forkIO $ clientSendLoop cHandle coreChan sendChan nextID
return ()
+
+ acceptLoop servSock coreChan nextID
+ where
+ nextID = clientCounter + 1
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/OfficialServer/DBInteraction.hs
--- a/gameServer/OfficialServer/DBInteraction.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/OfficialServer/DBInteraction.hs Wed Feb 02 11:28:38 2011 +0300
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, ScopedTypeVariables, OverloadedStrings #-}
+{-# LANGUAGE CPP, ScopedTypeVariables #-}
module OfficialServer.DBInteraction
(
startDBConnection
@@ -20,7 +20,7 @@
localAddressList = ["127.0.0.1", "0:0:0:0:0:0:0:1", "0:0:0:0:0:ffff:7f00:1"]
-fakeDbConnection serverInfo = forever $ do
+fakeDbConnection serverInfo = do
q <- readChan $ dbQueries serverInfo
case q of
CheckAccount clUid _ clHost -> do
@@ -29,6 +29,8 @@
ClearCache -> return ()
SendStats {} -> return ()
+ fakeDbConnection serverInfo
+
#if defined(OFFICIAL_SERVER)
pipeDbConnectionLoop queries coreChan hIn hOut accountsCache =
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/OfficialServer/extdbinterface.hs
--- a/gameServer/OfficialServer/extdbinterface.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/OfficialServer/extdbinterface.hs Wed Feb 02 11:28:38 2011 +0300
@@ -1,4 +1,4 @@
-{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
module Main where
@@ -26,7 +26,7 @@
case q of
CheckAccount clUid clNick _ -> do
statement <- prepare dbConn dbQueryAccount
- execute statement [SqlByteString $ clNick]
+ execute statement [SqlString $ clNick]
passAndRole <- fetchRow statement
finish statement
let response =
@@ -47,7 +47,7 @@
dbConnectionLoop mySQLConnectionInfo =
- Control.Exception.handle (\(e :: IOException) -> hPutStrLn stderr $ show e) $ handleSqlError $
+ Control.Exception.handle (\(_ :: IOException) -> return ()) $ handleSqlError $
bracket
(connectMySQL mySQLConnectionInfo)
(disconnect)
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/Opts.hs
--- a/gameServer/Opts.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/Opts.hs Wed Feb 02 11:28:38 2011 +0300
@@ -3,12 +3,10 @@
getOpts,
) where
-import System.Environment
+import System.Environment ( getArgs )
import System.Console.GetOpt
import Network
import Data.Maybe ( fromMaybe )
-import qualified Data.ByteString.Char8 as B
-
import CoreTypes
import Utils
@@ -32,9 +30,9 @@
where
readDedicated = fromMaybe True (maybeRead str :: Maybe Bool)
-readDbLogin str opts = opts{dbLogin = B.pack str}
-readDbPassword str opts = opts{dbPassword = B.pack str}
-readDbHost str opts = opts{dbHost = B.pack str}
+readDbLogin str opts = opts{dbLogin = str}
+readDbPassword str opts = opts{dbPassword = str}
+readDbHost str opts = opts{dbHost = str}
getOpts :: ServerInfo -> IO ServerInfo
getOpts opts = do
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/RoomsAndClients.hs
--- a/gameServer/RoomsAndClients.hs Mon Jan 31 21:40:17 2011 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-module RoomsAndClients(
- RoomIndex(),
- ClientIndex(),
- MRoomsAndClients(),
- IRoomsAndClients(),
- newRoomsAndClients,
- addRoom,
- addClient,
- removeRoom,
- removeClient,
- modifyRoom,
- modifyClient,
- lobbyId,
- moveClientToLobby,
- moveClientToRoom,
- clientRoomM,
- clientExists,
- client,
- room,
- client'sM,
- room'sM,
- allClientsM,
- clientsM,
- roomClientsM,
- roomClientsIndicesM,
- withRoomsAndClients,
- allRooms,
- allClients,
- clientRoom,
- showRooms,
- roomClients
- ) where
-
-
-import Store
-import Control.Monad
-
-
-data Room r = Room {
- roomClients' :: [ClientIndex],
- room' :: r
- }
-
-
-data Client c = Client {
- clientRoom' :: RoomIndex,
- client' :: c
- }
-
-
-newtype RoomIndex = RoomIndex ElemIndex
- deriving (Eq)
-newtype ClientIndex = ClientIndex ElemIndex
- deriving (Eq, Show, Read, Ord)
-
-instance Show RoomIndex where
- show (RoomIndex i) = 'r' : show i
-
-unRoomIndex :: RoomIndex -> ElemIndex
-unRoomIndex (RoomIndex r) = r
-
-unClientIndex :: ClientIndex -> ElemIndex
-unClientIndex (ClientIndex c) = c
-
-
-newtype MRoomsAndClients r c = MRoomsAndClients (MStore (Room r), MStore (Client c))
-newtype IRoomsAndClients r c = IRoomsAndClients (IStore (Room r), IStore (Client c))
-
-
-lobbyId :: RoomIndex
-lobbyId = RoomIndex firstIndex
-
-
-newRoomsAndClients :: r -> IO (MRoomsAndClients r c)
-newRoomsAndClients r = do
- rooms <- newStore
- clients <- newStore
- let rnc = MRoomsAndClients (rooms, clients)
- ri <- addRoom rnc r
- when (ri /= lobbyId) $ error "Empty struct inserts not at firstIndex index"
- return rnc
-
-
-roomAddClient :: ClientIndex -> Room r -> Room r
-roomAddClient cl room = let cls = cl : roomClients' room; nr = room{roomClients' = cls} in cls `seq` nr `seq` nr
-
-roomRemoveClient :: ClientIndex -> Room r -> Room r
-roomRemoveClient cl room = let cls = filter (/= cl) $ roomClients' room; nr = room{roomClients' = cls} in cls `seq` nr `seq` nr
-
-
-addRoom :: MRoomsAndClients r c -> r -> IO RoomIndex
-addRoom (MRoomsAndClients (rooms, _)) room = do
- i <- addElem rooms (Room [] room)
- return $ RoomIndex i
-
-
-addClient :: MRoomsAndClients r c -> c -> IO ClientIndex
-addClient (MRoomsAndClients (rooms, clients)) client = do
- i <- addElem clients (Client lobbyId client)
- modifyElem rooms (roomAddClient (ClientIndex i)) (unRoomIndex lobbyId)
- return $ ClientIndex i
-
-removeRoom :: MRoomsAndClients r c -> RoomIndex -> IO ()
-removeRoom rnc@(MRoomsAndClients (rooms, _)) room@(RoomIndex ri)
- | room == lobbyId = error "Cannot delete lobby"
- | otherwise = do
- clIds <- liftM roomClients' $ readElem rooms ri
- forM_ clIds (moveClientToLobby rnc)
- removeElem rooms ri
-
-
-removeClient :: MRoomsAndClients r c -> ClientIndex -> IO ()
-removeClient (MRoomsAndClients (rooms, clients)) cl@(ClientIndex ci) = do
- RoomIndex ri <- liftM clientRoom' $ readElem clients ci
- modifyElem rooms (roomRemoveClient cl) ri
- removeElem clients ci
-
-
-modifyRoom :: MRoomsAndClients r c -> (r -> r) -> RoomIndex -> IO ()
-modifyRoom (MRoomsAndClients (rooms, _)) f (RoomIndex ri) = modifyElem rooms (\r -> r{room' = f $ room' r}) ri
-
-modifyClient :: MRoomsAndClients r c -> (c -> c) -> ClientIndex -> IO ()
-modifyClient (MRoomsAndClients (_, clients)) f (ClientIndex ci) = modifyElem clients (\c -> c{client' = f $ client' c}) ci
-
-moveClientInRooms :: MRoomsAndClients r c -> RoomIndex -> RoomIndex -> ClientIndex -> IO ()
-moveClientInRooms (MRoomsAndClients (rooms, clients)) (RoomIndex riFrom) rt@(RoomIndex riTo) cl@(ClientIndex ci) = do
- modifyElem rooms (roomRemoveClient cl) riFrom
- modifyElem rooms (roomAddClient cl) riTo
- modifyElem clients (\c -> c{clientRoom' = rt}) ci
-
-
-moveClientToLobby :: MRoomsAndClients r c -> ClientIndex -> IO ()
-moveClientToLobby rnc ci = do
- room <- clientRoomM rnc ci
- moveClientInRooms rnc room lobbyId ci
-
-
-moveClientToRoom :: MRoomsAndClients r c -> RoomIndex -> ClientIndex -> IO ()
-moveClientToRoom rnc ri ci = moveClientInRooms rnc lobbyId ri ci
-
-
-clientExists :: MRoomsAndClients r c -> ClientIndex -> IO Bool
-clientExists (MRoomsAndClients (_, clients)) (ClientIndex ci) = elemExists clients ci
-
-clientRoomM :: MRoomsAndClients r c -> ClientIndex -> IO RoomIndex
-clientRoomM (MRoomsAndClients (_, clients)) (ClientIndex ci) = liftM clientRoom' (clients `readElem` ci)
-
-client'sM :: MRoomsAndClients r c -> (c -> a) -> ClientIndex -> IO a
-client'sM (MRoomsAndClients (_, clients)) f (ClientIndex ci) = liftM (f . client') (clients `readElem` ci)
-
-room'sM :: MRoomsAndClients r c -> (r -> a) -> RoomIndex -> IO a
-room'sM (MRoomsAndClients (rooms, _)) f (RoomIndex ri) = liftM (f . room') (rooms `readElem` ri)
-
-allClientsM :: MRoomsAndClients r c -> IO [ClientIndex]
-allClientsM (MRoomsAndClients (_, clients)) = liftM (map ClientIndex) $ indicesM clients
-
-clientsM :: MRoomsAndClients r c -> IO [c]
-clientsM (MRoomsAndClients (_, clients)) = indicesM clients >>= mapM (\ci -> liftM client' $ readElem clients ci)
-
-roomClientsIndicesM :: MRoomsAndClients r c -> RoomIndex -> IO [ClientIndex]
-roomClientsIndicesM (MRoomsAndClients (rooms, clients)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri)
-
-roomClientsM :: MRoomsAndClients r c -> RoomIndex -> IO [c]
-roomClientsM (MRoomsAndClients (rooms, clients)) (RoomIndex ri) = liftM roomClients' (rooms `readElem` ri) >>= mapM (\(ClientIndex ci) -> liftM client' $ readElem clients ci)
-
-withRoomsAndClients :: MRoomsAndClients r c -> (IRoomsAndClients r c -> a) -> IO a
-withRoomsAndClients (MRoomsAndClients (rooms, clients)) f =
- withIStore2 rooms clients (\r c -> f $ IRoomsAndClients (r, c))
-
-----------------------------------------
------------ IRoomsAndClients -----------
-
-showRooms :: (Show r, Show c) => IRoomsAndClients r c -> String
-showRooms rnc@(IRoomsAndClients (rooms, clients)) = concatMap showRoom (allRooms rnc)
- where
- showRoom r = unlines $ ((show r) ++ ": " ++ (show $ room' $ rooms ! (unRoomIndex r))) : (map showClient (roomClients' $ rooms ! (unRoomIndex r)))
- showClient c = " " ++ (show c) ++ ": " ++ (show $ client' $ clients ! (unClientIndex c))
-
-
-allRooms :: IRoomsAndClients r c -> [RoomIndex]
-allRooms (IRoomsAndClients (rooms, _)) = map RoomIndex $ indices rooms
-
-allClients :: IRoomsAndClients r c -> [ClientIndex]
-allClients (IRoomsAndClients (_, clients)) = map ClientIndex $ indices clients
-
-clientRoom :: IRoomsAndClients r c -> ClientIndex -> RoomIndex
-clientRoom (IRoomsAndClients (_, clients)) (ClientIndex ci) = clientRoom' (clients ! ci)
-
-client :: IRoomsAndClients r c -> ClientIndex -> c
-client (IRoomsAndClients (_, clients)) (ClientIndex ci) = client' (clients ! ci)
-
-room :: IRoomsAndClients r c -> RoomIndex -> r
-room (IRoomsAndClients (rooms, _)) (RoomIndex ri) = room' (rooms ! ri)
-
-roomClients :: IRoomsAndClients r c -> RoomIndex -> [ClientIndex]
-roomClients (IRoomsAndClients (rooms, _)) (RoomIndex ri) = roomClients' $ (rooms ! ri)
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/ServerCore.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/Store.hs
--- a/gameServer/Store.hs Mon Jan 31 21:40:17 2011 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-module Store(
- ElemIndex(),
- MStore(),
- IStore(),
- newStore,
- addElem,
- removeElem,
- readElem,
- writeElem,
- modifyElem,
- elemExists,
- firstIndex,
- indicesM,
- withIStore,
- withIStore2,
- (!),
- indices
- ) where
-
-import qualified Data.Array.IArray as IA
-import qualified Data.Array.IO as IOA
-import qualified Data.IntSet as IntSet
-import Data.IORef
-import Control.Monad
-
-
-newtype ElemIndex = ElemIndex Int
- deriving (Eq, Show, Read, Ord)
-newtype MStore e = MStore (IORef (IntSet.IntSet, IntSet.IntSet, IOA.IOArray Int e))
-newtype IStore e = IStore (IntSet.IntSet, IA.Array Int e)
-
-
-firstIndex :: ElemIndex
-firstIndex = ElemIndex 0
-
--- MStore code
-initialSize :: Int
-initialSize = 10
-
-
-growFunc :: Int -> Int
-growFunc a = a * 3 `div` 2
-
-
-newStore :: IO (MStore e)
-newStore = do
- newar <- IOA.newArray_ (0, initialSize - 1)
- new <- newIORef (IntSet.empty, IntSet.fromAscList [0..initialSize - 1], newar)
- return (MStore new)
-
-
-growStore :: MStore e -> IO ()
-growStore (MStore ref) = do
- (busyElems, freeElems, arr) <- readIORef ref
- (_, m') <- IOA.getBounds arr
- let newM' = growFunc (m' + 1) - 1
- newArr <- IOA.newArray_ (0, newM')
- sequence_ [IOA.readArray arr i >>= IOA.writeArray newArr i | i <- [0..m']]
- writeIORef ref (busyElems, freeElems `IntSet.union` (IntSet.fromAscList [m'+1..newM']), newArr)
-
-
-growIfNeeded :: MStore e -> IO ()
-growIfNeeded m@(MStore ref) = do
- (_, freeElems, _) <- readIORef ref
- when (IntSet.null freeElems) $ growStore m
-
-
-addElem :: MStore e -> e -> IO ElemIndex
-addElem m@(MStore ref) element = do
- growIfNeeded m
- (busyElems, freeElems, arr) <- readIORef ref
- let (n, freeElems') = IntSet.deleteFindMin freeElems
- IOA.writeArray arr n element
- writeIORef ref (IntSet.insert n busyElems, freeElems', arr)
- return $ ElemIndex n
-
-
-removeElem :: MStore e -> ElemIndex -> IO ()
-removeElem (MStore ref) (ElemIndex n) = do
- (busyElems, freeElems, arr) <- readIORef ref
- IOA.writeArray arr n (error $ "Store: no element " ++ show n)
- writeIORef ref (IntSet.delete n busyElems, IntSet.insert n freeElems, arr)
-
-
-readElem :: MStore e -> ElemIndex -> IO e
-readElem (MStore ref) (ElemIndex n) = readIORef ref >>= \(_, _, arr) -> IOA.readArray arr n
-
-
-writeElem :: MStore e -> ElemIndex -> e -> IO ()
-writeElem (MStore ref) (ElemIndex n) el = readIORef ref >>= \(_, _, arr) -> IOA.writeArray arr n el
-
-
-modifyElem :: MStore e -> (e -> e) -> ElemIndex -> IO ()
-modifyElem (MStore ref) f (ElemIndex n) = do
- (_, _, arr) <- readIORef ref
- IOA.readArray arr n >>= IOA.writeArray arr n . f
-
-elemExists :: MStore e -> ElemIndex -> IO Bool
-elemExists (MStore ref) (ElemIndex n) = do
- (_, free, _) <- readIORef ref
- return $ n `IntSet.notMember` free
-
-indicesM :: MStore e -> IO [ElemIndex]
-indicesM (MStore ref) = do
- (busy, _, _) <- readIORef ref
- return $ map ElemIndex $ IntSet.toList busy
-
-
--- A way to see MStore elements in pure code via IStore
-m2i :: MStore e -> IO (IStore e)
-m2i (MStore ref) = do
- (a, _, c') <- readIORef ref
- c <- IOA.unsafeFreeze c'
- return $ IStore (a, c)
-
-i2m :: (MStore e) -> IStore e -> IO ()
-i2m (MStore ref) (IStore (_, arr)) = do
- (b, e, _) <- readIORef ref
- a <- IOA.unsafeThaw arr
- writeIORef ref (b, e, a)
-
-withIStore :: MStore e -> (IStore e -> a) -> IO a
-withIStore m f = do
- i <- m2i m
- let res = f i
- res `seq` i2m m i
- return res
-
-
-withIStore2 :: MStore e1 -> MStore e2 -> (IStore e1 -> IStore e2 -> a) -> IO a
-withIStore2 m1 m2 f = do
- i1 <- m2i m1
- i2 <- m2i m2
- let res = f i1 i2
- res `seq` i2m m1 i1
- i2m m2 i2
- return res
-
-
--- IStore code
-(!) :: IStore e -> ElemIndex -> e
-(!) (IStore (_, arr)) (ElemIndex i) = (IA.!) arr i
-
-indices :: IStore e -> [ElemIndex]
-indices (IStore (busy, _)) = map ElemIndex $ IntSet.toList busy
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/Utils.hs
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/hedgewars-server.cabal
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/hedgewars-server.hs
--- a/gameServer/hedgewars-server.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/hedgewars-server.hs Wed Feb 02 11:28:38 2011 +0300
@@ -3,15 +3,22 @@
module Main where
import Network.Socket
+import qualified Network
import Network.BSD
import Control.Concurrent.STM
import Control.Concurrent.Chan
+#if defined(NEW_EXCEPTIONS)
+import qualified Control.OldException as Exception
+#else
import qualified Control.Exception as Exception
+#endif
import System.Log.Logger
-----------------------------------
import Opts
import CoreTypes
+import OfficialServer.DBInteraction
import ServerCore
+import Utils
#if !defined(mingw32_HOST_OS)
@@ -19,12 +26,10 @@
#endif
-setupLoggers :: IO ()
setupLoggers =
updateGlobalLogger "Clients"
(setLevel INFO)
-main :: IO ()
main = withSocketsDo $ do
#if !defined(mingw32_HOST_OS)
installHandler sigPIPE Ignore Nothing;
@@ -33,11 +38,11 @@
setupLoggers
- stats' <- atomically $ newTMVar (StatisticsInfo 0 0)
+ stats <- atomically $ newTMVar (StatisticsInfo 0 0)
dbQueriesChan <- newChan
- coreChan' <- newChan
- serverInfo' <- getOpts $ newServerInfo stats' coreChan' dbQueriesChan
-
+ coreChan <- newChan
+ serverInfo' <- getOpts $ newServerInfo stats coreChan dbQueriesChan
+
#if defined(OFFICIAL_SERVER)
dbHost' <- askFromConsole "DB host: "
dbLogin' <- askFromConsole "login: "
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/stresstest.hs
--- a/gameServer/stresstest.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/stresstest.hs Wed Feb 02 11:28:38 2011 +0300
@@ -6,7 +6,7 @@
import System.IO
import Control.Concurrent
import Network
-import Control.OldException
+import Control.Exception
import Control.Monad
import System.Random
@@ -14,24 +14,24 @@
import System.Posix
#endif
-session1 nick room = ["NICK", nick, "", "PROTO", "32", "", "PING", "", "CHAT", "lobby 1", "", "CREATE_ROOM", room, "", "CHAT", "room 1", "", "QUIT", "creator", ""]
-session2 nick room = ["NICK", nick, "", "PROTO", "32", "", "LIST", "", "JOIN_ROOM", room, "", "CHAT", "room 2", "", "PART", "", "CHAT", "lobby after part", "", "QUIT", "part-quit", ""]
-session3 nick room = ["NICK", nick, "", "PROTO", "32", "", "LIST", "", "JOIN_ROON", room, "", "CHAT", "room 2", "", "QUIT", "quit", ""]
+session1 nick room = ["NICK", nick, "", "PROTO", "24", "", "CHAT", "lobby 1", "", "CREATE", room, "", "CHAT", "room 1", "", "QUIT", "bye-bye", ""]
+session2 nick room = ["NICK", nick, "", "PROTO", "24", "", "LIST", "", "JOIN", room, "", "CHAT", "room 2", "", "PART", "", "CHAT", "lobby after part", "", "QUIT", "bye-bye", ""]
+session3 nick room = ["NICK", nick, "", "PROTO", "24", "", "LIST", "", "JOIN", room, "", "CHAT", "room 2", "", "QUIT", "bye-bye", ""]
emulateSession sock s = do
- mapM_ (\x -> hPutStrLn sock x >> hFlush sock >> randomRIO (30000::Int, 59000) >>= threadDelay) s
+ mapM_ (\x -> hPutStrLn sock x >> hFlush sock >> randomRIO (50000::Int, 90000) >>= threadDelay) s
hFlush sock
threadDelay 225000
-testing = Control.OldException.handle print $ do
+testing = Control.Exception.handle print $ do
putStrLn "Start"
sock <- connectTo "127.0.0.1" (PortNumber 46631)
num1 <- randomRIO (70000::Int, 70100)
num2 <- randomRIO (0::Int, 2)
num3 <- randomRIO (0::Int, 5)
- let nick1 = 'n' : show num1
- let room1 = 'r' : show num2
+ let nick1 = show num1
+ let room1 = show num2
case num2 of
0 -> emulateSession sock $ session1 nick1 room1
1 -> emulateSession sock $ session2 nick1 room1
@@ -40,7 +40,7 @@
putStrLn "Finish"
forks = forever $ do
- delay <- randomRIO (30000::Int, 59000)
+ delay <- randomRIO (10000::Int, 19000)
threadDelay delay
forkIO testing
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/stresstest2.hs
--- a/gameServer/stresstest2.hs Mon Jan 31 21:40:17 2011 +0300
+++ b/gameServer/stresstest2.hs Wed Feb 02 11:28:38 2011 +0300
@@ -6,7 +6,7 @@
import System.IO
import Control.Concurrent
import Network
-import Control.OldException
+import Control.Exception
import Control.Monad
import System.Random
@@ -14,28 +14,22 @@
import System.Posix
#endif
-session1 nick room = ["NICK", nick, "", "PROTO", "32", ""]
-
-
-
-testing = Control.OldException.handle print $ do
- putStrLn "Start"
+testing = Control.Exception.handle print $ do
+ delay <- randomRIO (100::Int, 300)
+ threadDelay delay
sock <- connectTo "127.0.0.1" (PortNumber 46631)
+ hClose sock
- num1 <- randomRIO (70000::Int, 70100)
- num2 <- randomRIO (0::Int, 2)
- num3 <- randomRIO (0::Int, 5)
- let nick1 = 'n' : show num1
- let room1 = 'r' : show num2
- mapM_ (\x -> hPutStrLn sock x >> hFlush sock >> randomRIO (300::Int, 590) >>= threadDelay) $ session1 nick1 room1
- mapM_ (\x -> hPutStrLn sock x >> hFlush sock) $ concatMap (\x -> ["CHAT_MSG", show x, ""]) [1..]
- hClose sock
- putStrLn "Finish"
-
-forks = testing
+forks i = do
+ delay <- randomRIO (50::Int, 190)
+ if i `mod` 10 == 0 then putStr (show i) else putStr "."
+ hFlush stdout
+ threadDelay delay
+ forkIO testing
+ forks (i + 1)
main = withSocketsDo $ do
#if !defined(mingw32_HOST_OS)
installHandler sigPIPE Ignore Nothing;
#endif
- forks
+ forks 1
diff -r 8bdc879ee6b2 -r 0eab727d4717 gameServer/stresstest3.hs
--- a/gameServer/stresstest3.hs Mon Jan 31 21:40:17 2011 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-{-# LANGUAGE CPP #-}
-
-module Main where
-
-import IO
-import System.IO
-import Control.Concurrent
-import Network
-import Control.OldException
-import Control.Monad
-import System.Random
-import Control.Monad.State
-import Data.List
-
-#if !defined(mingw32_HOST_OS)
-import System.Posix
-#endif
-
-type SState = Handle
-io = liftIO
-
-readPacket :: StateT SState IO [String]
-readPacket = do
- h <- get
- p <- io $ hGetPacket h []
- return p
- where
- hGetPacket h buf = do
- l <- hGetLine h
- if (not $ null l) then hGetPacket h (buf ++ [l]) else return buf
-
-waitPacket :: String -> StateT SState IO Bool
-waitPacket s = do
- p <- readPacket
- return $ head p == s
-
-sendPacket :: [String] -> StateT SState IO ()
-sendPacket s = do
- h <- get
- io $ do
- mapM_ (hPutStrLn h) s
- hPutStrLn h ""
- hFlush h
-
-emulateSession :: StateT SState IO ()
-emulateSession = do
- n <- io $ randomRIO (100000::Int, 100100)
- waitPacket "CONNECTED"
- sendPacket ["NICK", "test" ++ (show n)]
- waitPacket "NICK"
- sendPacket ["PROTO", "31"]
- waitPacket "PROTO"
- b <- waitPacket "LOBBY:JOINED"
- --io $ print b
- sendPacket ["QUIT", "BYE"]
- return ()
-
-testing = Control.OldException.handle print $ do
- putStr "+"
- sock <- connectTo "127.0.0.1" (PortNumber 46631)
- evalStateT emulateSession sock
- --hClose sock
- putStr "-"
- hFlush stdout
-
-forks = forM_ [1..100] $ const $ do
- delay <- randomRIO (10000::Int, 30000)
- threadDelay delay
- forkIO testing
-
-main = withSocketsDo $ do
-#if !defined(mingw32_HOST_OS)
- installHandler sigPIPE Ignore Nothing;
-#endif
- forks
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/ArgParsers.inc
--- a/hedgewars/ArgParsers.inc Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/ArgParsers.inc Wed Feb 02 11:28:38 2011 +0300
@@ -8,6 +8,7 @@
end;
procedure internalStartGameWithParameters();
+var tmp: LongInt;
begin
val(ParamStr(2), cScreenWidth);
val(ParamStr(3), cScreenHeight);
@@ -23,7 +24,9 @@
cAltDamage:= ParamStr(13) = '1';
UserNick:= DecodeBase64(ParamStr(14));
val(ParamStr(15), cReducedQuality);
- cLocaleFName:= ParamStr(16)
+ val(ParamStr(16), tmp);
+ cStereoMode:= TStereoMode(max(0, min(ord(high(TStereoMode)), tmp)));
+ cLocaleFName:= ParamStr(17);
end;
procedure setVideo(screenWidth: LongInt; screenHeight: LongInt; bitsStr: LongInt);
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/GSHandlers.inc
--- a/hedgewars/GSHandlers.inc Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/GSHandlers.inc Wed Feb 02 11:28:38 2011 +0300
@@ -28,32 +28,32 @@
// Gear is still on the same Pixel it was before
if steps < 1 then
- begin
+ begin
if onlyCheckIfChanged then
- begin
+ begin
Gear^.X := Gear^.X + dX;
Gear^.Y := Gear^.Y + dY;
EXIT;
- end
+ end
else
steps := 1;
- end;
+ end;
if steps > 1 then
- begin
+ begin
sX:= dX / steps;
sY:= dY / steps;
- end
+ end
else
- begin
+ begin
sX:= dX;
sY:= dY;
- end;
+ end;
caller:= Gear^.doStep;
for i:= 1 to steps do
- begin
+ begin
Gear^.X := Gear^.X + sX;
Gear^.Y := Gear^.Y + sY;
step(Gear);
@@ -61,7 +61,7 @@
or ((Gear^.State and gstCollision) <> 0)
or ((Gear^.State and gstMoving) = 0) then
break;
- end;
+ end;
end;
procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
@@ -71,27 +71,27 @@
begin
gi := GearsList;
while gi <> nil do
- begin
+ begin
if (gi^.Kind = gtHedgehog) then
- begin
+ begin
d := r - hwRound(Distance(gi^.X - x, gi^.Y - y));
if (d > 1) and not gi^.Invulnerable and (GetRandom(2) = 0) then
- begin
+ begin
if (CurrentHedgehog^.Gear = gi) then
PlaySound(sndOops, gi^.Hedgehog^.Team^.voicepack)
else
- begin
+ begin
if (gi^.State and gstMoving) = 0 then
gi^.State := gi^.State or gstLoser;
if d > r div 2 then
PlaySound(sndNooo, gi^.Hedgehog^.Team^.voicepack)
else
PlaySound(sndUhOh, gi^.Hedgehog^.Team^.voicepack);
+ end;
end;
end;
+ gi := gi^.NextGear
end;
- gi := gi^.NextGear
- end;
end;
////////////////////////////////////////////////////////////////////////////////
procedure doStepDrowningGear(Gear: PGear);
@@ -107,28 +107,29 @@
isSubmersible:= (Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amJetpack);
// probably needs tweaking. might need to be in a case statement based upon gear type
if cWaterLine < hwRound(Gear^.Y) + Gear^.Radius then
- begin
+ begin
skipSpeed := _0_25;
skipAngle := _1_9;
skipDecay := _0_87;
// this could perhaps be a tiny bit higher.
if (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed) and
(hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
- begin
+ begin
Gear^.dY.isNegative := true;
Gear^.dY := Gear^.dY * skipDecay;
Gear^.dX := Gear^.dX * skipDecay;
CheckGearDrowning := false;
PlaySound(sndSkip)
- end
+ end
else
- begin
+ begin
if not isSubmersible then
- begin
+ begin
CheckGearDrowning := true;
Gear^.State := gstDrowning;
Gear^.RenderTimer := false;
- if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
+ if (Gear^.Kind <> gtSniperRifleShot) and (Gear^.Kind <> gtShotgunShot) and
+ (Gear^.Kind <> gtDEagleShot) and (Gear^.Kind <> gtSineGunShot) then
if Gear^.Kind = gtHedgehog then
begin
if Gear^.Hedgehog^.Effects[heResurrectable] then
@@ -152,21 +153,21 @@
if ((cReducedQuality and rqPlainSplash) = 0) and
(((not isSubmersible) and (hwRound(Gear^.Y) < cWaterLine + 64 + Gear^.Radius)) or
(isSubmersible and (hwRound(Gear^.Y) < cWaterLine + 2 + Gear^.Radius) and ((CurAmmoGear^.Pos = 0) and (CurAmmoGear^.dY < _0_01)))) then
- begin
+ begin
AddVisualGear(hwRound(Gear^.X), cWaterLine, vgtSplash);
maxDrops := (Gear^.Radius div 2) + hwRound(Gear^.dX * Gear^.Radius * 2) + hwRound(Gear^.
dY * Gear^.Radius * 2);
for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do
- begin
+ begin
particle := AddVisualGear(hwRound(Gear^.X) - 3 + Random(6), cWaterLine, vgtDroplet);
if particle <> nil then
- begin
+ begin
particle^.dX := particle^.dX - (Gear^.dX.QWordValue / 42949672960);
particle^.dY := particle^.dY - (Gear^.dY.QWordValue / 21474836480)
+ end
end
- end
- end;
+ end;
if isSubmersible and (CurAmmoGear^.Pos = 0) then CurAmmoGear^.Pos := 1000
end
else
@@ -175,7 +176,15 @@
procedure CheckCollision(Gear: PGear); inline;
begin
- if TestCollisionXwithGear(Gear, hwSign(Gear^.X)) or TestCollisionYwithGear(Gear, hwSign(Gear^.Y)
+ if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) or TestCollisionYwithGear(Gear, hwSign(Gear^.dY)
+ )
+ then Gear^.State := Gear^.State or gstCollision
+ else Gear^.State := Gear^.State and not gstCollision
+end;
+
+procedure CheckCollisionWithLand(Gear: PGear); inline;
+begin
+ if TestCollisionX(Gear, hwSign(Gear^.dX)) or TestCollisionY(Gear, hwSign(Gear^.dY)
)
then Gear^.State := Gear^.State or gstCollision
else Gear^.State := Gear^.State and not gstCollision
@@ -188,17 +197,16 @@
particle: PVisualGear;
begin
if _0_4 < Gear^.dY then
- begin
+ begin
dmg := ModifyDamage(1 + hwRound((hwAbs(Gear^.dY) - _0_4) * 70), Gear);
PlaySound(sndBump);
if dmg < 1 then exit;
for i:= min(12, (3 + dmg div 10)) downto 0 do
- begin
- particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12,
- vgtDust);
+ begin
+ particle := AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480);
- end;
+ end;
if (Gear^.Invulnerable) then exit;
@@ -207,7 +215,7 @@
//else
// PlaySound(sndOw1, Gear^.Hedgehog^.Team^.voicepack);
- ApplyDamage(Gear, dmg, dsFall);
+ ApplyDamage(Gear, CurrentHedgehog, dmg, dsFall);
end
end;
@@ -233,10 +241,10 @@
AllInactive := false;
Gear^.Y := Gear^.Y + cDrownSpeed;
Gear^.X := Gear^.X + Gear^.dX * cDrownSpeed;
- if (cWaterOpacity > $FE) or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
+ if (not SuddenDeathDmg and (cWaterOpacity > $FE)) or (SuddenDeathDmg and (cSDWaterOpacity > $FE)) or (hwRound(Gear^.Y) > Gear^.Radius + cWaterLine + cVisibleWater) then
DeleteGear(Gear);
// Create some bubbles (0.5% might be better but causes too few bubbles sometimes)
- if (cWaterOpacity < $FF) and ((GameTicks and $1F) = 0) then
+ if ((not SuddenDeathDmg and (cWaterOpacity < $FF)) or (SuddenDeathDmg and (cSDWaterOpacity < $FF))) and ((GameTicks and $1F) = 0) then
if (Gear^.Kind = gtHedgehog) and (Random(4) = 0) then
AddVisualGear(hwRound(Gear^.X) - Gear^.Radius, hwRound(Gear^.Y) - Gear^.Radius,
vgtBubble)
@@ -267,60 +275,60 @@
if (hwRound(Gear^.X) < LAND_WIDTH div -2) or (hwRound(Gear^.X) > LAND_WIDTH * 3 div 2) then Gear^.State := Gear^.State or gstCollision;
if Gear^.dY.isNegative then
- begin
+ begin
isFalling := true;
if TestCollisionYwithGear(Gear, -1) then
- begin
+ begin
collV := -1;
Gear^.dX := Gear^.dX * Gear^.Friction;
Gear^.dY := - Gear^.dY * Gear^.Elasticity;
Gear^.State := Gear^.State or gstCollision
- end
+ end
else if (Gear^.AdvBounce=1) and TestCollisionYwithGear(Gear, 1) then collV := 1;
- end
+ end
else if TestCollisionYwithGear(Gear, 1) then
begin
- collV := 1;
- isFalling := false;
- Gear^.dX := Gear^.dX * Gear^.Friction;
- Gear^.dY := - Gear^.dY * Gear^.Elasticity;
- Gear^.State := Gear^.State or gstCollision
+ collV := 1;
+ isFalling := false;
+ Gear^.dX := Gear^.dX * Gear^.Friction;
+ Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+ Gear^.State := Gear^.State or gstCollision
end
else
- begin
+ begin
isFalling := true;
if (Gear^.AdvBounce=1) and not Gear^.dY.isNegative and TestCollisionYwithGear(Gear, -1) then
collV := -1;
- end;
+ end;
if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
- begin
+ begin
collH := hwSign(Gear^.dX);
Gear^.dX := - Gear^.dX * Gear^.Elasticity;
Gear^.dY := Gear^.dY * Gear^.Elasticity;
Gear^.State := Gear^.State or gstCollision
- end
+ end
else if (Gear^.AdvBounce=1) and TestCollisionXwithGear(Gear, -hwSign(Gear^.dX)) then
collH := -hwSign(Gear^.dX);
//if Gear^.AdvBounce and (collV <>0) and (collH <> 0) and (hwSqr(tdX) + hwSqr(tdY) > _0_08) then
if (Gear^.AdvBounce=1) and (collV <>0) and (collH <> 0) and ((collV=-1) or ((tdX.QWordValue +
tdY.QWordValue) > _0_2.QWordValue)) then
- begin
+ begin
Gear^.dX := tdY*Gear^.Elasticity*Gear^.Friction;
Gear^.dY := tdX*Gear^.Elasticity;
//*Gear^.Friction;
Gear^.dY.isNegative := not tdY.isNegative;
isFalling := false;
Gear^.AdvBounce := 10;
- end;
+ end;
if Gear^.AdvBounce > 1 then dec(Gear^.AdvBounce);
if isFalling then
begin
Gear^.dY := Gear^.dY + cGravity;
- if (GameFlags and gfMoreWind) <> 0 then Gear^.dX := Gear^.dX + cWindSpeed * _16 / max(12,sqr(Gear^.Radius))
+ if (GameFlags and gfMoreWind) <> 0 then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
end;
Gear^.X := Gear^.X + Gear^.dX;
@@ -367,7 +375,7 @@
begin
CheckCollision(Gear);
if (Gear^.State and gstCollision) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLDontDraw or EXPLNoGfx);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx);
end;
if (Gear^.Kind = gtGasBomb) and ((GameTicks mod 200) = 0) then
@@ -380,13 +388,13 @@
if Gear^.Timer = 0 then
begin
case Gear^.Kind of
- gtBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
- gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, EXPLAutoSound);
+ gtBomb: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ gtBall: doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 40, Gear^.Hedgehog, EXPLAutoSound);
gtClusterBomb:
begin
x := hwRound(Gear^.X);
y := hwRound(Gear^.Y);
- doMakeExplosion(x, y, 20, EXPLAutoSound);
+ doMakeExplosion(x, y, 20, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 4 do
begin
dX := rndSign(GetRandom * _0_1) + Gear^.dX / 5;
@@ -398,7 +406,7 @@
begin
x := hwRound(Gear^.X);
y := hwRound(Gear^.Y);
- doMakeExplosion(x, y, 75, EXPLAutoSound);
+ doMakeExplosion(x, y, 75, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 5 do
begin
dX := rndSign(GetRandom * _0_1) + Gear^.dX / 5;
@@ -410,7 +418,7 @@
begin
x := hwRound(Gear^.X);
y := hwRound(Gear^.Y);
- doMakeExplosion(x, y, 90, EXPLAutoSound);
+ doMakeExplosion(x, y, 90, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 127 do
begin
@@ -424,7 +432,7 @@
end;
gtGasBomb:
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 2 do
begin
x:= GetRandom(60);
@@ -501,7 +509,7 @@
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Timer, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
@@ -519,13 +527,166 @@
if (GameFlags and gfMoreWind) = 0 then Gear^.dX := Gear^.dX + cWindSpeed;
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
- begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end;
+ if (GameTicks and $3F) = 0 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
+end;
+
+////////////////////////////////////////////////////////////////////////////////
+procedure doStepSnowball(Gear: PGear);
+var kick, i: LongInt;
+ particle: PVisualGear;
+begin
+ AllInactive := false;
+ if (GameFlags and gfMoreWind) = 0 then Gear^.dX := Gear^.dX + cWindSpeed;
+ doStepFallingGear(Gear);
+ CalcRotationDirAngle(Gear);
+ if (Gear^.State and gstCollision) <> 0 then
+ begin
+ kick:= hwRound((hwAbs(Gear^.dX)+hwAbs(Gear^.dY)) * _20);
+ Gear^.dY.isNegative:= not Gear^.dY.isNegative;
+ Gear^.dX.isNegative:= not Gear^.dX.isNegative;
+ AmmoShove(Gear, 1, kick);
+ for i:= 15 + kick div 10 downto 0 do
+ begin
+ particle := AddVisualGear(hwRound(Gear^.X) + Random(25), hwRound(Gear^.Y) + Random(25), vgtDust);
+ if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
+ end;
DeleteGear(Gear);
exit
- end;
- if (GameTicks and $3F) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
+ end;
+ if ((GameTicks and $1F) = 0) and (Random(3) = 0) then
+ begin
+ particle:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtDust);
+ if particle <> nil then particle^.dX := particle^.dX + (Gear^.dX.QWordValue / 21474836480)
+ end
+end;
+
+procedure doStepSnowflake(Gear: PGear);
+var xx, yy, px, py, i: LongInt;
+ move, allpx: Boolean;
+ s: PSDL_Surface;
+ p: PLongwordArray;
+ oAlpha, nAlpha: byte;
+begin
+if GameTicks and $7 = 0 then
+ begin
+ with Gear^ do
+ begin
+ X:= X + cWindSpeed * 1600 + dX;
+ Y:= Y + dY + cGravity * vobFallSpeed * 8; // using same value as flakes to try and get similar results
+ xx:= hwRound(X);
+ yy:= hwRound(Y);
+ if vobVelocity <> 0 then
+ begin
+ DirAngle := DirAngle + (Angle / 1250000000);
+ if DirAngle < 0 then DirAngle := DirAngle + 360
+ else if 360 < DirAngle then DirAngle := DirAngle - 360;
+ end;
+
+ inc(Health, 8);
+ if Health > vobFrameTicks then
+ begin
+ dec(Health, vobFrameTicks);
+ inc(Timer);
+ if Timer = vobFramesCount then Timer:= 0
+ end;
+
+ move:= false;
+ // move back to cloud layer
+ if yy > cWaterLine then move:= true
+ else if ((yy and LAND_HEIGHT_MASK) <> 0) or ((xx and LAND_WIDTH_MASK) <> 0) then move:=true
+ // Solid pixel encountered
+ else if (Land[yy, xx] <> 0) then
+ begin
+ // If there's room below keep falling
+ if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (Land[yy-1, xx] = 0) then
+ begin
+ X:= X - cWindSpeed * 1600 - dX;
+ end
+ // If there's room below, on the sides, fill the gaps
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx-(1*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx-(1*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X - _0_8 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx-(2*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx-(2*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X - _0_8 * 2 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx+(1*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx+(1*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X + _0_8 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ else if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (((xx+(2*hwSign(cWindSpeed))) and LAND_WIDTH_MASK) = 0) and (Land[yy-1, (xx+(2*hwSign(cWindSpeed)))] = 0) then
+ begin
+ X:= X + _0_8 * 2 * hwSign(cWindSpeed);
+ Y:= Y - dY - cGravity * vobFallSpeed * 8;
+ end
+ // if there's an hog/object below do nothing
+ else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy+1, xx] and $FF) <> 0))
+ then move:=true
+ else
+ begin
+ // we've collided with land. draw some stuff and get back into the clouds
+ move:= true;
+ if (CurAmmoGear = nil) or (CurAmmoGear^.Kind <> gtRope) then
+ begin
+ ////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
+ dec(yy,3);
+ dec(xx,1);
+ s:= SpritesData[sprSnow].Surface;
+ p:= s^.pixels;
+ allpx:= true;
+ for py:= 0 to Pred(s^.h) do
+ begin
+ for px:= 0 to Pred(s^.w) do
+ if ((((yy + py) and LAND_HEIGHT_MASK) = 0) and (((xx + px) and LAND_WIDTH_MASK) = 0)) and ((Land[yy + py, xx + px] and $FF) = 0) then
+ begin
+ Land[yy + py, xx + px]:= Land[yy + py, xx + px] or lfObject;
+ if (cReducedQuality and rqBlurryLand) = 0 then
+ begin
+ LandPixels[yy + py, xx + px]:= addBgColor(LandPixels[yy + py, xx + px], p^[px]);
+ end
+ else
+ begin
+ LandPixels[(yy + py) div 2, (xx + px) div 2]:= addBgColor(LandPixels[(yy + py) div 2, (xx + px) div 2], p^[px]);
+ end;
+ end
+ else allpx:= false;
+ p:= @(p^[s^.pitch shr 2])
+ end;
+
+
+ Land[py, px+1]:= lfBasic;
+
+ if allpx then UpdateLandTexture(xx, Pred(s^.h), yy, Pred(s^.w))
+ else
+ begin
+ UpdateLandTexture(
+ max(0, min(LAND_WIDTH, xx)),
+ min(LAND_WIDTH - xx, Pred(s^.w)),
+ max(0, min(LAND_WIDTH, yy)),
+ min(LAND_HEIGHT - yy, Pred(s^.h))
+ );
+ end;
+ ////////////////////////////////// TODO - ASK UNC0RR FOR A GOOD HOME FOR THIS ////////////////////////////////////
+ end
+ end;
+ end;
+ if move then
+ begin
+ X:= int2hwFloat(GetRandom(LAND_WIDTH+1024)-512);
+ Y:= int2hwFloat(750+(GetRandom(50)-25))
+ end
+ end
+ end
end;
////////////////////////////////////////////////////////////////////////////////
@@ -605,7 +766,7 @@
if ((Gear^.State and gstCollision) <> 0) or (Gear^.Timer = 0) then
begin
StopSound(Gear^.SoundChannel);
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
end;
end;
@@ -619,7 +780,7 @@
CheckCollision(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
@@ -736,7 +897,7 @@
dec(Gear^.Health, Gear^.Damage);
Gear^.Damage := 0
end;
- if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and (cWaterOpacity < $FF) then
+ if ((Gear^.State and gstDrowning) <> 0) and (Gear^.Damage < Gear^.Health) and ((not SuddenDeathDmg and (cWaterOpacity < $FF)) or (SuddenDeathDmg and (cSDWaterOpacity < $FF))) then
begin
for i:=(Gear^.Health - Gear^.Damage) * 4 downto 0 do
begin
@@ -797,6 +958,9 @@
procedure doStepDEagleShot(Gear: PGear);
begin
PlaySound(sndGun);
+ // add an initial step to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
Gear^.doStep := @doStepBulletWork
end;
@@ -830,6 +994,9 @@
Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX) * _0_5;
Gear^.dY := -AngleCos(HHGear^.Angle) * _0_5;
PlaySound(sndGun);
+ // add an initial step to avoid problem with ammoshove related to calculation of radius + 1 radius as gear widths
+ Gear^.X := Gear^.X + Gear^.dX;
+ Gear^.Y := Gear^.Y + Gear^.dY;
Gear^.doStep := @doStepBulletWork;
end
else
@@ -895,7 +1062,7 @@
////////////////////////////////////////////////////////////////////////////////
procedure doStepPickHammerWork(Gear: PGear);
var
- i, ei: LongInt;
+ i, ei, x, y: LongInt;
HHGear: PGear;
begin
AllInactive := false;
@@ -903,53 +1070,58 @@
dec(Gear^.Timer);
if (Gear^.Timer = 0)or((Gear^.Message and gmDestroy) <> 0)or((HHGear^.State and gstHHDriven) =
0) then
- begin
+ begin
StopSound(Gear^.SoundChannel);
DeleteGear(Gear);
AfterAttack;
doStepHedgehogMoving(HHGear); // for gfInfAttack
exit
- end;
-
+ end;
+
+ x:= hwRound(Gear^.X);
+ y:= hwRound(Gear^.Y);
if (Gear^.Timer mod 33) = 0 then
- begin
+ begin
HHGear^.State := HHGear^.State or gstNoDamage;
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y) + 7, 6, EXPLDontDraw);
+ doMakeExplosion(x, y + 7, 6, Gear^.Hedgehog, EXPLDontDraw);
HHGear^.State := HHGear^.State and not gstNoDamage
- end;
+ end;
if (Gear^.Timer mod 47) = 0 then
- begin
- for i:= 0 to 1 do
- AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
- i := hwRound(Gear^.X) - Gear^.Radius - LongInt(GetRandom(2));
- ei := hwRound(Gear^.X) + Gear^.Radius + LongInt(GetRandom(2));
+ begin
+ // ok. this was an attempt to turn off dust if not actually drilling land. I have no idea why it isn't working as expected
+ if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y + 12, x] > 255) then
+ for i:= 0 to 1 do
+ AddVisualGear(x - 5 + Random(10), y + 12, vgtDust);
+
+ i := x - Gear^.Radius - LongInt(GetRandom(2));
+ ei := x + Gear^.Radius + LongInt(GetRandom(2));
while i <= ei do
- begin
- DrawExplosion(i, hwRound(Gear^.Y) + 3, 3);
+ begin
+ DrawExplosion(i, y + 3, 3);
inc(i, 1)
- end;
+ end;
if CheckLandValue(hwRound(Gear^.X + Gear^.dX + SignAs(_6,Gear^.dX)), hwRound(Gear^.Y + _1_9)
, lfIndestructible) then
- begin
+ begin
Gear^.X := Gear^.X + Gear^.dX;
Gear^.Y := Gear^.Y + _1_9;
- end;
+ end;
SetAllHHToActive;
- end;
+ end;
if TestCollisionYwithGear(Gear, 1) then
- begin
+ begin
Gear^.dY := _0;
SetLittle(HHGear^.dX);
HHGear^.dY := _0;
- end
+ end
else
- begin
+ begin
Gear^.dY := Gear^.dY + cGravity;
Gear^.Y := Gear^.Y + Gear^.dY;
if hwRound(Gear^.Y) > cWaterLine then Gear^.Timer := 1
- end;
+ end;
Gear^.X := Gear^.X + HHGear^.dX;
HHGear^.X := Gear^.X;
@@ -1121,7 +1293,7 @@
HHGear^.X := HHGear^.X + HHGear^.dX;
HHGear^.Y := HHGear^.Y + HHGear^.dY;
HHGear^.dY := HHGear^.dY + cGravity;
- if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed * _0_2;
+ if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density;
if (Gear^.Message and gmAttack) <> 0 then
begin
@@ -1187,22 +1359,22 @@
if not TestCollisionYwithGear(HHGear, 1) then
begin
HHGear^.dY := HHGear^.dY + cGravity;
- if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed * _0_2
+ if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density;
end;
+ // vector between hedgehog and rope attaching point
ropeDx := HHGear^.X - Gear^.X;
- // vector between hedgehog and rope attaching point
ropeDy := HHGear^.Y - Gear^.Y;
mdX := ropeDx + HHGear^.dX;
mdY := ropeDy + HHGear^.dY;
len := _1 / Distance(mdX, mdY);
+ // rope vector plus hedgehog direction vector normalized
mdX := mdX * len;
- // rope vector plus hedgehog direction vector normalized
mdY := mdY * len;
+ // for visual purposes only
Gear^.dX := mdX;
- // for visual purposes only
Gear^.dY := mdY;
/////
@@ -1330,35 +1502,45 @@
HHGear^.dY := HHGear^.dY * len;
end;
- haveCollision:= false;
- if RopePoints.Count > 0 then
- begin
- ly:= hwRound(RopePoints.ar[0].Y);
- lx:= hwRound(RopePoints.ar[0].X)
- end
- else if Gear^.Elasticity.QWordValue > 0 then
- begin
- ly:= hwRound(Gear^.Y);
- lx:= hwRound(Gear^.X)
- end;
-(* // just in case it turns out we have rounding problems
- i:= -1;
- while not haveCollision and (i < 2) do
+ haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) <> 0);
+
+ if not haveCollision then
begin
- j:= -1;
- while not haveCollision and (j < 2) do
+ // backup gear location
+ tx:= Gear^.X;
+ ty:= Gear^.Y;
+
+ if RopePoints.Count > 0 then
+ begin
+ // set gear location to the remote end of the rope, the attachment point
+ Gear^.X:= RopePoints.ar[0].X;
+ Gear^.Y:= RopePoints.ar[0].Y;
+ end;
+
+ CheckCollisionWithLand(Gear);
+ // if we haven't found any collision yet then check the otheer side too
+ if (Gear^.State and gstCollision) = 0 then
begin
- haveCollision:= ((((ly + i) and LAND_HEIGHT_MASK) = 0) and
- (((lx + j) and LAND_WIDTH_MASK) = 0) and
- ((Land[ly + i, lx + j] and $FF00) <> 0));
- inc(j)
+ Gear^.dX.isNegative:= not Gear^.dX.isNegative;
+ Gear^.dY.isNegative:= not Gear^.dY.isNegative;
+ CheckCollisionWithLand(Gear);
+ Gear^.dX.isNegative:= not Gear^.dX.isNegative;
+ Gear^.dY.isNegative:= not Gear^.dY.isNegative;
end;
- inc(i)
- end; *)
- if ((Gear^.Message and gmAttack) <> 0) or
- (((ly and LAND_HEIGHT_MASK) = 0) and
- ((lx and LAND_WIDTH_MASK) = 0) and
- ((Land[ly, lx] and $FF00) = 0)) then
+
+ haveCollision:= (Gear^.State and gstCollision) <> 0;
+
+ // restore gear location
+ Gear^.X:= tx;
+ Gear^.Y:= ty;
+ end;
+
+ // if the attack key is pressed, lose rope contact as well
+ if (Gear^.Message and gmAttack) <> 0 then
+ haveCollision:= false;
+
+ if not haveCollision then
+ begin
if (Gear^.State and gsttmpFlag) <> 0 then
with Gear^.Hedgehog^ do
begin
@@ -1368,10 +1550,11 @@
else
DeleteMe
end
- else
+ end
else
if (Gear^.State and gsttmpFlag) = 0 then
Gear^.State := Gear^.State or gsttmpFlag;
+
end;
procedure doStepRopeAttach(Gear: PGear);
@@ -1416,7 +1599,7 @@
HHGear^.Y := HHGear^.Y + HHGear^.dY;
Gear^.Y := Gear^.Y + HHGear^.dY;
HHGear^.dY := HHGear^.dY + cGravity;
- if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed * _0_2
+ if (GameFlags and gfMoreWind) <> 0 then HHGear^.dX := HHGear^.dX + cWindSpeed / HHGear^.Density
end;
tt := Gear^.Elasticity;
@@ -1448,9 +1631,7 @@
end;
end;
- if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) <> 0) then
- Gear^.State:= Gear^.State or gstCollision
- else Gear^.State:= Gear^.State and not gstCollision;
+ CheckCollisionWithLand(Gear);
if (Gear^.State and gstCollision) <> 0 then
if Gear^.Elasticity < _10 then
@@ -1529,7 +1710,7 @@
(cMineDudPercent = 0) or
(getRandom(100) > cMineDudPercent) then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear)
end
else
@@ -1550,41 +1731,45 @@
////////////////////////////////////////////////////////////////////////////////
procedure doStepSMine(Gear: PGear);
begin
- DeleteCI(Gear);
// TODO: do real calculation?
if TestCollisionXwithGear(Gear, 2) or TestCollisionYwithGear(Gear, -2) or TestCollisionXwithGear(Gear, -2) or TestCollisionYwithGear(Gear, 2) then
begin
if (hwAbs(Gear^.dX) > _0) or (hwAbs(Gear^.dY) > _0) then
+ begin
PlaySound(sndRopeAttach);
- Gear^.dX:= _0;
- Gear^.dY:= _0;
+ Gear^.dX:= _0;
+ Gear^.dY:= _0;
+ AddGearCI(Gear);
+ end;
end
else
begin
+ DeleteCI(Gear);
doStepFallingGear(Gear);
AllInactive := false;
CalcRotationDirAngle(Gear);
end;
- AddGearCI(Gear);
if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Health <> 0) then
+ begin
if ((Gear^.State and gstAttacking) = 0) then
begin
if ((GameTicks and $1F) = 0) then
if CheckGearNear(Gear, gtHedgehog, 46, 32) <> nil then Gear^.State := Gear^.State or
gstAttacking
end
- else // gstAttacking <> 0
- begin
- AllInactive := false;
- if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick);
- if Gear^.Timer = 0 then
+ else // gstAttacking <> 0
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
- DeleteGear(Gear);
- exit
- end;
- dec(Gear^.Timer);
+ AllInactive := false;
+ if (Gear^.Timer and $FF) = 0 then PlaySound(sndMineTick);
+ if Gear^.Timer = 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ exit
+ end;
+ dec(Gear^.Timer);
+ end
end
else // gsttmpFlag = 0
if TurnTimeLeft = 0 then Gear^.State := Gear^.State or gsttmpFlag;
@@ -1600,7 +1785,7 @@
makeHogsWorry(Gear^.X, Gear^.Y, 75);
if Gear^.Timer = 0 then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 75, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
exit
end;
@@ -1693,6 +1878,7 @@
k: TGearType;
exBoom: boolean;
dX, dY: HWFloat;
+ hog: PHedgehog;
begin
k := Gear^.Kind;
exBoom := false;
@@ -1729,18 +1915,20 @@
begin
x := hwRound(Gear^.X);
y := hwRound(Gear^.Y);
+ hog:= Gear^.Hedgehog;
+
DeleteGear(Gear);
// <-- delete gear!
if k = gtCase then
begin
- doMakeExplosion(x, y, 25, EXPLAutoSound);
+ doMakeExplosion(x, y, 25, hog, EXPLAutoSound);
for i:= 0 to 63 do
AddGear(x, y, gtFlame, 0, _0, _0, 0);
end
else if k = gtExplosives then
begin
- doMakeExplosion(x, y, 75, EXPLAutoSound);
+ doMakeExplosion(x, y, 75, hog, EXPLAutoSound);
for i:= 0 to 31 do
begin
dX := AngleCos(i * 64) * _0_5 * (getrandom + _1);
@@ -1791,28 +1979,12 @@
if (Gear^.Tag = 0) and (Gear^.Timer < 1000) then
inc(Gear^.Timer)
else if Gear^.Tag = 1 then
- begin
- Gear^.Tag := 2;
- if (TrainingFlags and tfTimeTrial) <> 0 then
- begin
- inc(TurnTimeLeft, TrainingTimeInc);
-
- if TrainingTimeInc > TrainingTimeInM then
- dec(TrainingTimeInc, TrainingTimeInD);
- if TurnTimeLeft > TrainingTimeMax then
- TurnTimeLeft := TrainingTimeMax;
- end;
- end
+ Gear^.Tag := 2
else if Gear^.Tag = 2 then
if Gear^.Timer > 0 then
dec(Gear^.Timer)
else
begin
- if (TrainingFlags and tfTargetRespawn) <> 0 then
- begin
- TrainingTargetGear := AddGear(0, 0, gtTarget, 0, _0, _0, 0);
- FindPlace(TrainingTargetGear, false, 0, LAND_WIDTH);
- end;
DeleteGear(Gear);
exit;
end;
@@ -1858,10 +2030,10 @@
DeleteCI(HHGear);
for i:= 0 to 3 do
- begin
+ begin
AmmoShove(Gear, 30, 25);
Gear^.X := Gear^.X + Gear^.dX * 5
- end;
+ end;
HHGear^.State := (HHGear^.State and (not gstNoDamage)) or gstMoving;
@@ -1941,7 +2113,7 @@
AmmoShove(Gear, 4, 150);
Gear^.Radius := 1;
end
- else if ((GameTicks and $3) = 3) then doMakeExplosion(gX, gY, 6, 0);//, EXPLNoDamage);
+ else if ((GameTicks and $3) = 3) then doMakeExplosion(gX, gY, 6, Gear^.Hedgehog, 0);//, EXPLNoDamage);
//DrawExplosion(gX, gY, 4);
if ((GameTicks and $7) = 0) and (Random(2) = 0) then
for i:= 1 to Random(2)+1 do
@@ -2080,14 +2252,16 @@
exit
end;
- if not TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
- HHGear^.X := HHGear^.X + cWindSpeed * 200;
+ HHGear^.X := HHGear^.X + cWindSpeed * 200;
if (Gear^.Message and gmLeft) <> 0 then HHGear^.X := HHGear^.X - cMaxWindSpeed * 80
else if (Gear^.Message and gmRight) <> 0 then HHGear^.X := HHGear^.X + cMaxWindSpeed * 80;
if (Gear^.Message and gmUp) <> 0 then HHGear^.Y := HHGear^.Y - cGravity * 40
else if (Gear^.Message and gmDown) <> 0 then HHGear^.Y := HHGear^.Y + cGravity * 40;
+ // don't drift into obstacles
+ if TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then
+ HHGear^.X := HHGear^.X - int2hwFloat(hwSign(HHGear^.dX));
HHGear^.Y := HHGear^.Y + cGravity * 100;
Gear^.X := HHGear^.X;
Gear^.Y := HHGear^.Y
@@ -2129,7 +2303,7 @@
2: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtNapalmBomb, 0, cBombsSpeed *
Gear^.Tag, _0, 0);
3: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtDrill, gsttmpFlag, cBombsSpeed *
- Gear^.Tag, _0, 0);
+ Gear^.Tag, _0, Gear^.Timer + 1);
//4: FollowGear := AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtWaterMelon, 0, cBombsSpeed *
// Gear^.Tag, _0, 5000);
end;
@@ -2160,9 +2334,13 @@
Gear^.Y := int2hwFloat(topY-300);
Gear^.dX := int2hwFloat(TargetPoint.X - 5 * Gear^.Tag * 15);
- if (int2hwFloat(TargetPoint.Y) - Gear^.Y > _0) then
- Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(TargetPoint.Y) - Gear^.Y) * 2 /
- cGravity) * Gear^.Tag;
+ // calcs for Napalm Strike, so that it will hit the target (without wind at least :P)
+ if (Gear^.State = 2) then
+ Gear^.dX := Gear^.dX - cBombsSpeed * Gear^.Tag * 1000 // ^.Timer of gtNapalmBomb, make it a constant var if you prefer that :P
+ // calcs for regular falling gears
+ else if (int2hwFloat(TargetPoint.Y) - Gear^.Y > _0) then
+ Gear^.dX := Gear^.dX - cBombsSpeed * hwSqrt((int2hwFloat(TargetPoint.Y) - Gear^.Y) * 2 /
+ cGravity) * Gear^.Tag;
Gear^.Health := 6;
Gear^.doStep := @doStepAirAttackWork;
@@ -2176,7 +2354,7 @@
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
performRumble();
exit
@@ -2203,7 +2381,7 @@
if (Distance(tx - x, ty - y) > _256) or
not TryPlaceOnLand(TargetPoint.X - SpritesData[sprAmGirder].Width div 2,
TargetPoint.Y - SpritesData[sprAmGirder].Height div 2,
- sprAmGirder, Gear^.State, true) then
+ sprAmGirder, Gear^.State, true, false) then
begin
PlaySound(sndDenied);
HHGear^.Message := HHGear^.Message and not gmAttack;
@@ -2232,6 +2410,7 @@
Gear^.Hedgehog^.Unplaced := false;
HHGear := Gear^.Hedgehog^.Gear;
HHGear^.Y := HHGear^.Y + HHGear^.dY;
+ HHGear^.X := HHGear^.X + HHGear^.dX;
// hedgehog falling to collect cases
HHGear^.dY := HHGear^.dY + cGravity;
if TestCollisionYwithGear(HHGear, 1)
@@ -2263,7 +2442,7 @@
HHGear := Gear^.Hedgehog^.Gear;
if not TryPlaceOnLand(TargetPoint.X - SpritesData[sprHHTelepMask].Width div 2,
TargetPoint.Y - SpritesData[sprHHTelepMask].Height div 2,
- sprHHTelepMask, 0, false) then
+ sprHHTelepMask, 0, false, false) then
begin
HHGear^.Message := HHGear^.Message and not gmAttack;
HHGear^.State := HHGear^.State and not gstAttacking;
@@ -2375,7 +2554,7 @@
doStepFallingGear(Gear);
if (Gear^.State and gstCollision) <> 0 then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLAutoSound);
Gear^.dX.isNegative := not dxn;
Gear^.dY.isNegative := not dyn;
@@ -2445,7 +2624,7 @@
if Gear^.Health < Gear^.Damage then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
AfterAttack;
DeleteGear(Gear);
DeleteGear(HHGear);
@@ -2505,7 +2684,7 @@
inc(Gear^.Tag);
if Gear^.Tag < 2250 then exit;
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg, Gear^.Hedgehog, EXPLAutoSound);
AfterAttack;
DeleteGear(Gear)
end;
@@ -2688,7 +2867,7 @@
if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then
if (Land[y, x] <> 0) then
- begin
+ begin
Gear^.dX.isNegative := not Gear^.dX.isNegative;
Gear^.dY.isNegative := not Gear^.dY.isNegative;
Gear^.dX := Gear^.dX * _1_5;
@@ -2696,13 +2875,13 @@
AmmoShove(Gear, 0, 40);
AfterAttack;
DeleteGear(Gear)
- end
+ end
+ else
else
- else
- begin
+ begin
AfterAttack;
DeleteGear(Gear)
- end
+ end
end;
procedure doStepSeductionWear(Gear: PGear);
@@ -2759,6 +2938,9 @@
end;
////////////////////////////////////////////////////////////////////////////////
+procedure doStepDrill(Gear: PGear);
+forward;
+
procedure doStepDrillDrilling(Gear: PGear);
var
t: PGearArray;
@@ -2787,19 +2969,26 @@
if (Gear^.Timer = 0)
or (t^.Count <> 0)
or (not TestCollisionYWithGear(Gear, hwSign(Gear^.dY))
- and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)))
+ and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX))
+ and ((Gear^.State and gsttmpFlag) = 0))
// CheckLandValue returns true if the type isn't matched
or not CheckLandValue(hwRound(Gear^.X), hwRound(Gear^.Y), lfIndestructible) then
- begin
+ begin
//out of time or exited ground
StopSound(Gear^.SoundChannel);
if (Gear^.State and gsttmpFlag) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound)
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
else
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
exit
- end;
+ end
+ else if not TestCollisionYWithGear(Gear, hwSign(Gear^.dY)) and not TestCollisionXWithGear(Gear, hwSign(Gear^.dX)) then
+ begin
+ StopSound(Gear^.SoundChannel);
+ Gear^.Tag := 1;
+ Gear^.doStep := @doStepDrill
+ end;
dec(Gear^.Timer);
end;
@@ -2841,17 +3030,29 @@
begin
//explode right on contact with HH
if (Gear^.State and gsttmpFlag) <> 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound)
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound)
else
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, Gear^.Hedgehog, EXPLAutoSound);
DeleteGear(Gear);
exit;
end;
Gear^.SoundChannel := LoopSound(sndDrillRocket);
Gear^.doStep := @doStepDrillDrilling;
+ if (Gear^.State and gsttmpFlag) <> 0 then
+ gear^.RenderTimer:= true;
dec(Gear^.Timer)
end
+ else if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Tag <> 0) then
+ begin
+ if Gear^.Timer = 0 then
+ begin
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound);
+ DeleteGear(Gear);
+ end
+ else
+ dec(Gear^.Timer);
+ end;
end;
////////////////////////////////////////////////////////////////////////////////
@@ -2911,14 +3112,11 @@
begin
AllInactive := false;
- if ((TrainingFlags and tfRCPlane) = 0) and (Gear^.Timer > 0) then dec(Gear^.Timer);
-
- if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (
- TimeTrialStartTime = 0) then TimeTrialStartTime := RealTicks;
-
HHGear := Gear^.Hedgehog^.Gear;
FollowGear := Gear;
+ if Gear^.Timer > 0 then dec(Gear^.Timer);
+
fChanged := false;
if ((HHGear^.State and gstHHDriven) = 0) or (Gear^.Timer = 0) then
begin
@@ -2958,73 +3156,44 @@
Gear^.X := Gear^.X + Gear^.dX;
Gear^.Y := Gear^.Y + Gear^.dY;
- if (TrainingFlags and tfRCPlane) = 0 then
+ if (GameTicks and $FF) = 0 then
+ if Gear^.Timer < 3500 then
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
+ else
+ AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
+
+ if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
begin
- if (GameTicks and $FF) = 0 then
- if Gear^.Timer < 3500 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEvilTrace)
- else
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
-
- if ((HHGear^.Message and gmAttack) <> 0) and (Gear^.Health <> 0) then
- begin
- HHGear^.Message := HHGear^.Message and not gmAttack;
- AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
- _0_5, 0);
- dec(Gear^.Health)
- end;
-
- if ((HHGear^.Message and gmLJump) <> 0)
- and ((Gear^.State and gsttmpFlag) = 0) then
- begin
- Gear^.State := Gear^.State or gsttmpFlag;
- PauseMusic;
- playSound(sndRideOfTheValkyries);
- end;
-
- // pickup bonuses
- t := CheckGearNear(Gear, gtCase, 36, 36);
- if t <> nil then
- PickUp(HHGear, t);
- end
- else
+ HHGear^.Message := HHGear^.Message and not gmAttack;
+ AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAirBomb, 0, Gear^.dX * _0_5, Gear^.dY *
+ _0_5, 0);
+ dec(Gear^.Health)
+ end;
+
+ if ((HHGear^.Message and gmLJump) <> 0)
+ and ((Gear^.State and gsttmpFlag) = 0) then
begin
- if (GameTicks and $FF) = 0 then
- AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtSmokeTrace);
-
- // pickup targets
- t := CheckGearNear(Gear, gtTarget, 36, 36);
- if t <> nil then
- begin
- if t^.Tag <> 0 then // collect it only once
- exit;
- PlaySound(sndShotgunReload);
- t^.Tag := 1;
- TrainingTargetGear := nil;
- // remove target cursor
- exit;
- end;
-
- if (TurnTimeLeft > 0) then
- dec(TurnTimeLeft)
+ Gear^.State := Gear^.State or gsttmpFlag;
+ PauseMusic;
+ playSound(sndRideOfTheValkyries);
end;
+ // pickup bonuses
+ t := CheckGearNear(Gear, gtCase, 36, 36);
+ if t <> nil then
+ PickUp(HHGear, t);
+
CheckCollision(Gear);
- if ((Gear^.State and gstCollision) <> 0) or (((TrainingFlags and tfRCPlane) <> 0) and (
- TurnTimeLeft = 0))
- or CheckGearDrowning(Gear) then
+ if ((Gear^.State and gstCollision) <> 0) or CheckGearDrowning(Gear) then
begin
- if ((TrainingFlags and tfRCPlane) <> 0) and ((TrainingFlags and tfTimeTrial) <> 0 ) and (
- TimeTrialStopTime = 0) then TimeTrialStopTime := RealTicks;
StopSound(Gear^.SoundChannel);
StopSound(sndRideOfTheValkyries);
ResumeMusic;
- if ((Gear^.State and gstCollision) <> 0) or (((TrainingFlags and tfRCPlane) <> 0) and (
- TurnTimeLeft = 0)) then
+ if ((Gear^.State and gstCollision) <> 0) then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, Gear^.Hedgehog, EXPLAutoSound);
for i:= 0 to 32 do
begin
dX := AngleCos(i * 64) * _0_5 * (GetRandom + _1);
@@ -3039,10 +3208,6 @@
CurAmmoGear := nil;
if (GameFlags and gfInfAttack) = 0 then TurnTimeLeft := 14 * 125;
- if (TrainingFlags and tfRCPlane) <> 0 then
- TurnTimeLeft := 0;
- // HACK: RCPlane training allows unlimited plane starts in last 2 seconds
-
HHGear^.Message := 0;
ParseCommand('/taunt '#1, true)
end
@@ -3403,7 +3568,7 @@
if (Gear^.State and gstCollision) <> 0 then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLPoisoned, $C0E0FFE0);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLPoisoned, $C0E0FFE0);
PlaySound(sndEggBreak);
AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
vg := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg);
@@ -3423,8 +3588,7 @@
////////////////////////////////////////////////////////////////////////////////
procedure doPortalColorSwitch();
-var flags: LongWord;
- CurWeapon: PAmmo;
+var CurWeapon: PAmmo;
begin
if (CurrentHedgehog <> nil)
and (CurrentHedgehog^.Gear <> nil)
@@ -3435,11 +3599,10 @@
CurrentHedgehog^.Gear^.Message := CurrentHedgehog^.Gear^.Message and not gmSwitch;
CurWeapon:= GetAmmoEntry(CurrentHedgehog^);
- flags := CurWeapon^.Timer and not 2;
- if (flags and 1) = 0 then
- CurWeapon^.Timer := flags or 1
+ if CurWeapon^.Pos <> 0 then
+ CurWeapon^.Pos := 0
else
- CurWeapon^.Timer := flags and not 1;
+ CurWeapon^.Pos := 1;
end;
end;
@@ -3663,7 +3826,7 @@
iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
end;
- if not isbullet then
+ if not isbullet and (iterator^.Kind <> gtFlake) then
FollowGear := iterator;
//AddFileLog('portal''d');
@@ -3708,8 +3871,7 @@
s: hwFloat;
procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
-var
- flags: LongWord;
+var
CurWeapon: PAmmo;
begin
if CurrentHedgehog <> nil then
@@ -3718,18 +3880,19 @@
CurWeapon:= GetAmmoEntry(CurrentHedgehog^);
if (CurAmmoType = amPortalGun) then
begin
- flags := CurWeapon^.Timer;
-
- if destroyGear xor ((oldPortal^.Tag and 2) = 0) then
- flags := flags or 1
- else
- flags := flags and not 1;
-
- CurWeapon^.Timer := flags and not 2;
+ if not destroyGear then
+ begin
+ // switch color of ball to opposite of oldPortal
+ if (oldPortal^.Tag and 2) = 0 then
+ CurWeapon^.Pos:= 1
+ else
+ CurWeapon^.Pos:= 0;
+ end;
+
// make the ball visible
+ CurWeapon^.Timer := 0;
end
end;
-
if destroyGear then oldPortal^.Timer:= 0;
end;
@@ -3814,11 +3977,8 @@
newPortal^.Elasticity.isNegative := not newPortal^.Elasticity.isNegative;
// make portal gun look unloaded
- CurWeapon^.Timer := CurWeapon^.Timer or 2;
-
- // set portal to the currently chosen color
- if ((CurWeapon^.Timer and 1) <> 0) then
- newPortal^.Tag := newPortal^.Tag or 2;
+ if (CurWeapon <> nil) and (CurAmmoType = amPortalGun) then
+ CurWeapon^.Timer := CurWeapon^.Timer or 2;
iterator := GearsList;
while iterator <> nil do
@@ -3914,9 +4074,9 @@
begin
r0 := GetRandom(21);
r1 := GetRandom(21);
- doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1, 0);
- doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0, 0);
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X) - 30 - r0, hwRound(Gear^.Y) + 40, 40 + r1, Gear^.Hedgehog, 0);
+ doMakeExplosion(hwRound(Gear^.X) + 30 + r1, hwRound(Gear^.Y) + 40, 40 + r0, Gear^.Hedgehog, 0);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 80 + r0, Gear^.Hedgehog, EXPLAutoSound);
for r0:= 0 to 4 do
AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtNote);
Gear^.dY := odY * -1 + cGravity * 2;
@@ -4157,7 +4317,7 @@
Gear^.dX := Gear^.dX + cWindSpeed / 4;
Gear^.dY := Gear^.dY + cGravity / 100;
if (GameTicks mod 250) = 0 then
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 20, Gear^.Hedgehog, EXPLDontDraw or EXPLNoGfx or EXPLNoDamage or EXPLDoNotTouchAny or EXPLPoisoned);
AllInactive:= false;
end;
@@ -4185,7 +4345,7 @@
if (tmp^.Kind = gtHedgehog) then
begin
//tmp^.State:= tmp^.State or gstFlatened;
- ApplyDamage(tmp, tmp^.Health div 3, dsUnknown);
+ ApplyDamage(tmp, CurrentHedgehog, tmp^.Health div 3, dsUnknown);
//DrawTunnel(tmp^.X, tmp^.Y - _1, _0, _0_5, cHHRadius * 6, cHHRadius * 3);
tmp2:= AddGear(hwRound(tmp^.X), hwRound(tmp^.Y), gtHammerHit, 0, _0, _0, 0);
tmp2^.Hedgehog:= tmp^.Hedgehog;
@@ -4354,13 +4514,9 @@
RenderHealth(resgear^.Hedgehog^);
RecountTeamHealth(resgear^.Hedgehog^.Team);
resgear^.Hedgehog^.Effects[heResurrected]:= true;
+ // only make hat-less hedgehogs look like zombies, preserve existing hats
if resgear^.Hedgehog^.Hat = 'NoHat' then
- begin
- FreeTexture(resgear^.Hedgehog^.HatTex);
- resgear^.Hedgehog^.HatTex := Surface2Tex(
- LoadImage(Pathz[ptHats] + '/Reserved/Zombie', ifNone),
- True)
- end
+ LoadHedgehogHat(resgear, 'Reserved/Zombie');
end;
hh^.Gear^.dY := _0;
@@ -4408,7 +4564,7 @@
doStepFallingGear(Gear);
if (Gear^.Timer > 0) and ((Gear^.State and gstCollision) <> 0) then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
gX := hwRound(Gear^.X);
gY := hwRound(Gear^.Y);
for i:= 0 to 10 do
@@ -4425,7 +4581,7 @@
end;
if (Gear^.Timer = 0) then
begin
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, Gear^.Hedgehog, EXPLAutoSound);
for i:= -19 to 19 do
FollowGear := AddGear(hwRound(Gear^.X) + i div 3, hwRound(Gear^.Y), gtFlame, 0, _0_001 * i, _0, 0);
DeleteGear(Gear);
@@ -4437,4 +4593,116 @@
end;
////////////////////////////////////////////////////////////////////////////////
-
+procedure doStepPlaceStructure(Gear: PGear);
+var
+ HHGear: PGear;
+ x, y, tx, ty: hwFloat;
+begin
+ AllInactive := false;
+
+ HHGear := Gear^.Hedgehog^.Gear;
+ tx := int2hwFloat(TargetPoint.X);
+ ty := int2hwFloat(TargetPoint.Y);
+ x := HHGear^.X;
+ y := HHGear^.Y;
+
+ if (Distance(tx - x, ty - y) > _256) or
+ not TryPlaceOnLand(TargetPoint.X - SpritesData[sprAmGirder].Width div 2,
+ TargetPoint.Y - SpritesData[sprAmGirder].Height div 2,
+ sprAmGirder, Gear^.State, true, false) then
+ begin
+ PlaySound(sndDenied);
+ HHGear^.Message := HHGear^.Message and not gmAttack;
+ HHGear^.State := HHGear^.State and not gstAttacking;
+ HHGear^.State := HHGear^.State or gstHHChooseTarget;
+ isCursorVisible := true;
+ DeleteGear(Gear)
+ end
+ else
+ begin
+ PlaySound(sndPlaced);
+ DeleteGear(Gear);
+ AfterAttack;
+ end;
+
+ HHGear^.State := HHGear^.State and not (gstAttacking or gstAttacked);
+ HHGear^.Message := HHGear^.Message and not gmAttack;
+ TargetPoint.X := NoPointX
+end;
+
+procedure doStepStructure(Gear: PGear);
+var
+ i, x, y: LongInt;
+ dX, dY: HWFloat;
+ hog: PHedgehog;
+begin
+ if Gear^.Hedgehog <> nil then
+ if Gear^.Tag = 0 then
+ begin
+ hog:= Gear^.Hedgehog;
+ hog^.GearHidden:= hog^.Gear;
+ RemoveGearFromList(hog^.Gear);
+ hog^.Gear:= nil;
+ Gear^.Tag:= TotalRounds + 3;
+ end
+ else if Gear^.Tag = TotalRounds then
+ begin
+ hog:= Gear^.Hedgehog;
+ hog^.Gear:= hog^.GearHidden;
+ hog^.Gear^.X:= Gear^.X;
+ hog^.Gear^.Y:= Gear^.Y - Int2hwFloat(Gear^.Radius);
+ hog^.Gear^.Active:= false;
+ hog^.Gear^.State:= hog^.Gear^.State And not gstHHdriven;
+ InsertGearToList(hog^.Gear);
+ hog^.GearHidden:= nil;
+ Gear^.Hedgehog:= nil;
+ end;
+
+ if (Gear^.dY.QWordValue <> 0) or (not TestCollisionYwithGear(Gear, 1)) then
+ begin
+ AllInactive := false;
+ Gear^.dY := Gear^.dY + cGravity;
+ Gear^.Y := Gear^.Y + Gear^.dY;
+ if (not Gear^.dY.isNegative) and (Gear^.dY > _0_001) then SetAllHHToActive;
+ if (Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, -1) then Gear^.dY := _0;
+ if (not Gear^.dY.isNegative) and TestCollisionYwithGear(Gear, 1) then
+ begin
+ if Gear^.dY > _0_2 then
+ for i:= min(12, hwRound(Gear^.dY*_10)) downto 0 do
+ AddVisualGear(hwRound(Gear^.X) - 5 + Random(10), hwRound(Gear^.Y) + 12, vgtDust);
+ Gear^.dY := - Gear^.dY * Gear^.Elasticity;
+ if Gear^.dY > - _0_001 then Gear^.dY := _0
+ else if Gear^.dY < - _0_03 then
+ PlaySound(Gear^.ImpactSound);
+ end;
+ CheckGearDrowning(Gear);
+ end;
+
+ if (Gear^.dY.QWordValue = 0) then AddGearCI(Gear)
+ else if (Gear^.dY.QWordValue <> 0) then DeleteCI(Gear);
+
+ dec(Gear^.Health, Gear^.Damage);
+ Gear^.Damage := 0;
+
+ if Gear^.Health <= 0 then
+ begin
+ if Gear^.Hedgehog <> nil then
+ begin
+ hog:= Gear^.Hedgehog;
+ hog^.Gear:= hog^.GearHidden;
+ hog^.Gear^.X:= Gear^.X;
+ hog^.Gear^.Y:= Gear^.Y;
+ InsertGearToList(hog^.Gear);
+ hog^.GearHidden:= nil;
+ Gear^.Hedgehog:= nil;
+ end;
+
+ x := hwRound(Gear^.X);
+ y := hwRound(Gear^.Y);
+
+ DeleteGear(Gear);
+
+ doMakeExplosion(x, y, 50, CurrentHedgehog, EXPLAutoSound);
+ end;
+end;
+
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/HHHandlers.inc
--- a/hedgewars/HHHandlers.inc Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/HHHandlers.inc Wed Feb 02 11:28:38 2011 +0300
@@ -41,29 +41,29 @@
end;
// Shouldn't more of this ammo switching stuff be moved to uAmmos ?
-function ChangeAmmo(Gear: PGear): boolean;
+function ChangeAmmo(HHGear: PGear): boolean;
var slot, i: Longword;
ammoidx: LongInt;
begin
ChangeAmmo:= false;
-slot:= Gear^.MsgParam;
+slot:= HHGear^.MsgParam;
-with Gear^.Hedgehog^ do
+with HHGear^.Hedgehog^ do
begin
- Gear^.Message:= Gear^.Message and not gmSlot;
+ HHGear^.Message:= HHGear^.Message and not gmSlot;
ammoidx:= 0;
- if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or
+ if ((HHGear^.State and (gstAttacking or gstAttacked)) <> 0) or
(TargetPoint.X <> NoPointX) or
((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or
- ((Gear^.State and gstHHDriven) = 0) then exit;
+ ((HHGear^.State and gstHHDriven) = 0) then exit;
ChangeAmmo:= true;
while (ammoidx < cMaxSlotAmmoIndex) and (Ammo^[slot, ammoidx].AmmoType <> CurAmmoType) do inc(ammoidx);
- if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(Gear^.Hedgehog^);
+ if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(HHGear^.Hedgehog^);
MultiShootAttacks:= 0;
- Gear^.Message:= Gear^.Message and not (gmLJump or gmHJump);
+ HHGear^.Message:= HHGear^.Message and not (gmLJump or gmHJump);
if Ammoz[CurAmmoType].Slot = slot then
begin
@@ -94,31 +94,33 @@
end
end;
-procedure HHSetWeapon(Gear: PGear);
+procedure HHSetWeapon(HHGear: PGear);
var t: LongInt;
weap: TAmmoType;
Hedgehog: PHedgehog;
s: boolean;
begin
-weap:= TAmmoType(Gear^.MsgParam);
-Hedgehog:= Gear^.Hedgehog;
+s:= false;
+
+weap:= TAmmoType(HHGear^.MsgParam);
+Hedgehog:= HHGear^.Hedgehog;
if Hedgehog^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet
-Gear^.MsgParam:= Ammoz[weap].Slot;
+HHGear^.MsgParam:= Ammoz[weap].Slot;
t:= cMaxSlotAmmoIndex;
-Gear^.Message:= Gear^.Message and not gmWeapon;
+HHGear^.Message:= HHGear^.Message and not gmWeapon;
with Hedgehog^ do
while (CurAmmoType <> weap) and (t >= 0) do
begin
- s:= ChangeAmmo(Gear);
+ s:= ChangeAmmo(HHGear);
dec(t)
end;
-if s then ApplyAmmoChanges(Gear^.Hedgehog^)
+if s then ApplyAmmoChanges(HHGear^.Hedgehog^)
end;
procedure HHSetTimer(Gear: PGear);
@@ -207,6 +209,7 @@
amClusterBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtClusterBomb, 0, newDx, newDy, CurWeapon^.Timer);
amGasBomb: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtGasBomb, 0, newDx, newDy, CurWeapon^.Timer);
amBazooka: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtShell, 0, newDx, newDy, 0);
+ amSnowball: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtSnowball, 0, newDx, newDy, 0);
amBee: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtBee, 0, newDx, newDy, 0);
amShotgun: begin
PlaySound(sndShotgunReload);
@@ -222,7 +225,11 @@
amSMine: FollowGear:= AddGear(hwRound(lx), hwRound(ly), gtSMine, 0, xx*Power/cPowerDivisor, yy*Power/cPowerDivisor, 0);
amDEagle: CurAmmoGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtDEagleShot, 0, xx * _0_5, yy * _0_5, 0);
amSineGun: CurAmmoGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSineGunShot, 0, xx * _0_5, yy * _0_5, 0);
- amPortalGun: AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtPortal, 0, xx * _0_6, yy * _0_6, 0);
+ amPortalGun: begin
+ AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtPortal, 0, xx * _0_6, yy * _0_6,
+ // set selected color
+ CurWeapon^.Pos);
+ end;
amSniperRifle: begin
PlaySound(sndSniperReload);
CurAmmoGear:= AddGear(hwRound(lx + xx * cHHRadius), hwRound(ly + yy * cHHRadius), gtSniperRifleShot, 0, xx * _0_5, yy * _0_5, 0);
@@ -275,7 +282,8 @@
end;
amLowGravity: begin
PlaySound(sndLowGravity);
- cGravity:= cMaxWindSpeed
+ cGravity:= cMaxWindSpeed;
+ cGravityf:= 0.00025
end;
amExtraDamage:begin
PlaySound(sndHellishImpact4);
@@ -305,8 +313,12 @@
gtResurrector, 0, _0, _0, 0);
CurAmmoGear^.SoundChannel := LoopSound(sndResurrector);
end;
- amDrillStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 3, _0, _0, 0);
+ amDrillStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 3, _0, _0, CurWeapon^.Timer);
//amMelonStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 4, _0, _0, 0);
+ amStructure: begin
+ FollowGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, 0, SignAs(_0_03, dX), _0, 0);
+ FollowGear^.Hedgehog:= Gear^.Hedgehog;
+ end;
end;
uStats.AmmoUsed(CurAmmoType);
@@ -396,7 +408,7 @@
if Gear^.Timer = 1 then
begin
Gear^.State:= Gear^.State or gstNoDamage;
- doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, EXPLAutoSound);
+ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, CurrentHedgehog, EXPLAutoSound);
AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtGrave, 0, _0, _0, 0)^.Hedgehog:= Gear^.Hedgehog;
DeleteGear(Gear);
SetAllToActive
@@ -627,17 +639,17 @@
end
end;
-procedure HedgehogChAngle(Gear: PGear);
+procedure HedgehogChAngle(HHGear: PGear);
var da: LongWord;
begin
-with Gear^.Hedgehog^ do
+with HHGear^.Hedgehog^ do
if (CurAmmoType = amRope)
- and ((Gear^.State and (gstMoving or gstHHJumping)) = gstMoving) then da:= 2 else da:= 1;
+ and ((HHGear^.State and (gstMoving or gstHHJumping)) = gstMoving) then da:= 2 else da:= 1;
-if (((Gear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
- if ((Gear^.Message and gmUp) <> 0) and (Gear^.Angle >= CurMinAngle + da) then dec(Gear^.Angle, da)
+if (((HHGear^.Message and gmPrecise) = 0) or ((GameTicks mod 5) = 1)) then
+ if ((HHGear^.Message and gmUp) <> 0) and (HHGear^.Angle >= CurMinAngle + da) then dec(HHGear^.Angle, da)
else
- if ((Gear^.Message and gmDown) <> 0) and (Gear^.Angle + da <= CurMaxAngle) then inc(Gear^.Angle, da)
+ if ((HHGear^.Message and gmDown) <> 0) and (HHGear^.Angle + da <= CurMaxAngle) then inc(HHGear^.Angle, da)
end;
procedure doStepHedgehog(Gear: PGear); forward;
@@ -667,12 +679,12 @@
Gear^.dY:= Gear^.dY + cGravity;
// this set of circumstances could be less complex if jumping was more clearly identified
if ((GameFlags and gfMoreWind) <> 0) and
- (Gear^.Damage <> 0) or
+ (((Gear^.Damage <> 0) or
((CurAmmoGear <> nil) and
((CurAmmoGear^.AmmoType = amJetpack) or
(CurAmmoGear^.AmmoType = amBirdy))) or
- ((Gear^.dY.QWordValue + Gear^.dX.QWordValue) > _0_55.QWordValue)
- then Gear^.dX := Gear^.dX + cWindSpeed * _0_2
+ ((Gear^.dY.QWordValue + Gear^.dX.QWordValue) > _0_55.QWordValue)))
+ then Gear^.dX := Gear^.dX + cWindSpeed / Gear^.Density
end
end
else
@@ -768,118 +780,118 @@
end;
-procedure doStepHedgehogDriven(Gear: PGear);
+procedure doStepHedgehogDriven(HHGear: PGear);
var t: PGear;
wasJumping: boolean;
Hedgehog: PHedgehog;
begin
-Hedgehog:= Gear^.Hedgehog;
+Hedgehog:= HHGear^.Hedgehog;
if not isInMultiShoot then
AllInactive:= false
else
- Gear^.Message:= 0;
+ HHGear^.Message:= 0;
-if (TurnTimeLeft = 0) or (Gear^.Damage > 0) then
+if (TurnTimeLeft = 0) or (HHGear^.Damage > 0) then
begin
TurnTimeLeft:= 0;
isCursorVisible:= false;
- Gear^.State:= Gear^.State and not (gstHHDriven or gstAnimation or gstAttacking);
+ HHGear^.State:= HHGear^.State and not (gstHHDriven or gstAnimation or gstAttacking);
AttackBar:= 0;
- if Gear^.Damage > 0 then
- Gear^.State:= Gear^.State and not (gstHHJumping or gstHHHJump);
+ if HHGear^.Damage > 0 then
+ HHGear^.State:= HHGear^.State and not (gstHHJumping or gstHHHJump);
exit
end;
-if (Gear^.State and gstAnimation) <> 0 then
+if (HHGear^.State and gstAnimation) <> 0 then
begin
- Gear^.Message:= 0;
- if (Gear^.Pos = Wavez[TWave(Gear^.Tag)].VoiceDelay) and (Gear^.Timer = 0) then PlaySound(Wavez[TWave(Gear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
- inc(Gear^.Timer);
- if Gear^.Timer = Wavez[TWave(Gear^.Tag)].Interval then
+ HHGear^.Message:= 0;
+ if (HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].VoiceDelay) and (HHGear^.Timer = 0) then PlaySound(Wavez[TWave(HHGear^.Tag)].Voice, Hedgehog^.Team^.voicepack);
+ inc(HHGear^.Timer);
+ if HHGear^.Timer = Wavez[TWave(HHGear^.Tag)].Interval then
begin
- Gear^.Timer:= 0;
- inc(Gear^.Pos);
- if Gear^.Pos = Wavez[TWave(Gear^.Tag)].FramesCount then
- Gear^.State:= Gear^.State and not gstAnimation
+ HHGear^.Timer:= 0;
+ inc(HHGear^.Pos);
+ if HHGear^.Pos = Wavez[TWave(HHGear^.Tag)].FramesCount then
+ HHGear^.State:= HHGear^.State and not gstAnimation
end;
exit
end;
-if ((Gear^.State and gstMoving) <> 0)
+if ((HHGear^.State and gstMoving) <> 0)
or (StepTicks = cHHStepTicks)
or (CurAmmoGear <> nil) then // we are moving
begin
with Hedgehog^ do
if (CurAmmoGear = nil)
- and (Gear^.dY > _0_39)
- and (CurAmmoType = amParachute) then Gear^.Message:= Gear^.Message or gmAttack;
+ and (HHGear^.dY > _0_39)
+ and (CurAmmoType = amParachute) then HHGear^.Message:= HHGear^.Message or gmAttack;
// check for case with ammo
- t:= CheckGearNear(Gear, gtCase, 36, 36);
+ t:= CheckGearNear(HHGear, gtCase, 36, 36);
if t <> nil then
- PickUp(Gear, t)
+ PickUp(HHGear, t)
end;
if (CurAmmoGear = nil) then
- if (((Gear^.Message and gmAttack) <> 0)
- or ((Gear^.State and gstAttacking) <> 0)) then
- Attack(Gear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
+ if (((HHGear^.Message and gmAttack) <> 0)
+ or ((HHGear^.State and gstAttacking) <> 0)) then
+ Attack(HHGear) // should be before others to avoid desync with '/put' msg and changing weapon msgs
else
else
with Hedgehog^ do
if ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
- and ((Gear^.Message and gmLJump) <> 0)
+ and ((HHGear^.Message and gmLJump) <> 0)
and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) then
begin
- Attack(Gear);
- Gear^.Message:= Gear^.Message and not gmLJump
+ Attack(HHGear);
+ HHGear^.Message:= HHGear^.Message and not gmLJump
end;
if (CurAmmoGear = nil)
or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) <> 0)
or ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) then
begin
- if ((Gear^.Message and gmSlot) <> 0) then
- if ChangeAmmo(Gear) then ApplyAmmoChanges(Hedgehog^);
+ if ((HHGear^.Message and gmSlot) <> 0) then
+ if ChangeAmmo(HHGear) then ApplyAmmoChanges(Hedgehog^);
- if ((Gear^.Message and gmWeapon) <> 0) then HHSetWeapon(Gear);
+ if ((HHGear^.Message and gmWeapon) <> 0) then HHSetWeapon(HHGear);
- if ((Gear^.Message and gmTimer) <> 0) then HHSetTimer(Gear);
+ if ((HHGear^.Message and gmTimer) <> 0) then HHSetTimer(HHGear);
end;
if CurAmmoGear <> nil then
begin
- CurAmmoGear^.Message:= Gear^.Message;
+ CurAmmoGear^.Message:= HHGear^.Message;
exit
end;
if not isInMultiShoot then
- HedgehogChAngle(Gear);
+ HedgehogChAngle(HHGear);
-if (Gear^.State and gstMoving) <> 0 then
+if (HHGear^.State and gstMoving) <> 0 then
begin
- wasJumping:= ((Gear^.State and gstHHJumping) <> 0);
+ wasJumping:= ((HHGear^.State and gstHHJumping) <> 0);
- if ((Gear^.Message and gmHJump) <> 0) and
+ if ((HHGear^.Message and gmHJump) <> 0) and
wasJumping and
- ((Gear^.State and gstHHHJump) = 0) then
- if (not (hwAbs(Gear^.dX) > cLittle)) and (Gear^.dY < -_0_02) then
+ ((HHGear^.State and gstHHHJump) = 0) then
+ if (not (hwAbs(HHGear^.dX) > cLittle)) and (HHGear^.dY < -_0_02) then
begin
- Gear^.State:= Gear^.State or gstHHHJump;
- Gear^.dY:= -_0_25;
- if not cArtillery then Gear^.dX:= -SignAs(_0_02, Gear^.dX);
+ HHGear^.State:= HHGear^.State or gstHHHJump;
+ HHGear^.dY:= -_0_25;
+ if not cArtillery then HHGear^.dX:= -SignAs(_0_02, HHGear^.dX);
PlaySound(sndJump2, Hedgehog^.Team^.voicepack)
end;
- Gear^.Message:= Gear^.Message and not (gmLJump or gmHJump);
+ HHGear^.Message:= HHGear^.Message and not (gmLJump or gmHJump);
if (not cArtillery) and wasJumping and
- TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then SetLittle(Gear^.dX);
+ TestCollisionXwithGear(HHGear, hwSign(HHGear^.dX)) then SetLittle(HHGear^.dX);
- doStepHedgehogMoving(Gear);
+ if Hedgehog^.Gear <> nil then doStepHedgehogMoving(HHGear);
- if ((Gear^.State and (gstMoving or gstDrowning)) = 0) then
+ if ((HHGear^.State and (gstMoving or gstDrowning)) = 0) then
begin
- AddGearCI(Gear);
+ AddGearCI(HHGear);
if wasJumping then
StepTicks:= 410
else
@@ -888,10 +900,10 @@
exit
end;
- if not isInMultiShoot then
+ if not isInMultiShoot and (Hedgehog^.Gear <> nil) then
begin
if StepTicks > 0 then dec(StepTicks);
- if (StepTicks = 0) then HedgehogStep(Gear)
+ if (StepTicks = 0) then HedgehogStep(HHGear)
end
end;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/PascalExports.pas
--- a/hedgewars/PascalExports.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/PascalExports.pas Wed Feb 02 11:28:38 2011 +0300
@@ -22,10 +22,9 @@
interface
uses uTypes, uConsts, uVariables, GLunit, uKeys, uChat, uSound, uAmmos, uUtils,
- uCommands;
+ uCommands, uMobile;
{$INCLUDE "config.inc"}
-var dummy: boolean; // avoid compiler hint
implementation
{$IFDEF HWLIBRARY}
@@ -33,12 +32,13 @@
previousGameState: TGameState;
// retrieve protocol information
-procedure HW_versionInfo(netProto: PShortInt; versionStr: PPChar); cdecl; export;
+procedure HW_versionInfo(netProto: PLongInt; versionStr: PPChar); cdecl; export;
begin
netProto^:= cNetProtoVersion;
versionStr^:= cVersionString;
end;
+// emulate mouse/keyboard input
procedure HW_click; cdecl; export;
begin
leftClick:= true;
@@ -191,12 +191,15 @@
GameState:= previousGameState;
end;
+// equivalent to esc+y; when closeFrontend = true the game exits after memory cleanup
procedure HW_terminate(closeFrontend: boolean); cdecl; export;
begin
- isTerminated:= true;
- if closeFrontend then alsoShutdownFrontend:= true;
+ {$IFDEF IPHONEOS}setGameRunning(false);{$ENDIF}
+ alsoShutdownFrontend:= closeFrontend;
+ ParseCommand('forcequit', true);
end;
+// cursor handling
procedure HW_setCursor(x,y: LongInt); cdecl; export;
begin
CursorPoint.X:= x;
@@ -209,9 +212,10 @@
y^:= CursorPoint.Y;
end;
+// ammo menu related functions
function HW_isAmmoMenuOpen: boolean; cdecl; export;
begin
- exit(bShowAmmoMenu);
+ exit( bShowAmmoMenu );
end;
function HW_isAmmoMenuNotAllowed: boolean; cdecl; export;
@@ -220,11 +224,6 @@
((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) = 0)) and hideAmmoMenu)) );
end;
-function HW_isWaiting: boolean; cdecl; export;
-begin
- exit( ReadyTimeLeft > 0 );
-end;
-
function HW_isWeaponRequiringClick: boolean; cdecl; export;
begin
if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.BotLevel = 0) then
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/VGSHandlers.inc
--- a/hedgewars/VGSHandlers.inc Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/VGSHandlers.inc Wed Feb 02 11:28:38 2011 +0300
@@ -24,14 +24,23 @@
with Gear^ do
begin
inc(FrameTicks, Steps);
- if FrameTicks > vobFrameTicks then
+ if not SuddenDeathDmg and (FrameTicks > vobFrameTicks) then
begin
dec(FrameTicks, vobFrameTicks);
inc(Frame);
if Frame = vobFramesCount then Frame:= 0
+ end
+ else if SuddenDeathDmg and (FrameTicks > vobSDFrameTicks) then
+ begin
+ dec(FrameTicks, vobSDFrameTicks);
+ inc(Frame);
+ if Frame = vobSDFramesCount then Frame:= 0
end;
X:= X + (cWindSpeedf * 200 + dX + tdX) * Steps;
- Y:= Y + (dY + tdY + cGravityf * vobFallSpeed) * Steps;
+ if SuddenDeathDmg then
+ Y:= Y + (dY + tdY + cGravityf * vobSDFallSpeed) * Steps
+ else
+ Y:= Y + (dY + tdY + cGravityf * vobFallSpeed) * Steps;
Angle:= Angle + dAngle * Steps;
if Angle > 360 then
Angle:= Angle - 360
@@ -663,8 +672,8 @@
else dec(tmp);
if tmp < round(dX) then tdY:= 1;
if tmp > round(dY) then tdY:= -1;
- if tmp > 255 then tmp := 255;
- if tmp < 0 then tmp := 0;
+ if tmp > 255 then tmp := 255;
+ if tmp < 0 then tmp := 0;
Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or tmp
end
end
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/hwLibrary.pas
--- a/hedgewars/hwLibrary.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/hwLibrary.pas Wed Feb 02 11:28:38 2011 +0300
@@ -12,10 +12,8 @@
// these procedures/functions to the PascalImports.h file (also in the "Pascal Sources" group)
// to make these functions available in the C/C++/Objective-C source files
// (add "#include PascalImports.h" near the top of these files if it's not there yet)
-uses cmem, uVariables, PascalExports, hwengine;
+uses PascalExports, hwengine;
begin
- // avoid compiler warnings about units not being used
- isTerminated:= isTerminated;
- dummy:= dummy;
+
end.
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/hwengine.pas
--- a/hedgewars/hwengine.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/hwengine.pas Wed Feb 02 11:28:38 2011 +0300
@@ -60,6 +60,7 @@
gsStart: begin
if HasBorder then DisableSomeWeapons;
AddClouds;
+ AddFlakes;
AssignHHCoords;
AddMiscGears;
StoreLoad;
@@ -156,8 +157,8 @@
cHasFocus:= true;
{$ELSE}
KeyPressChat(event.key.keysym.unicode);
- SDL_MOUSEBUTTONDOWN: if event.button.button = SDL_BUTTON_WHEELDOWN then uKeys.wheelDown:= true;
- SDL_MOUSEBUTTONUP: if event.button.button = SDL_BUTTON_WHEELUP then uKeys.wheelUp:= true;
+ SDL_MOUSEBUTTONDOWN: if event.button.button = SDL_BUTTON_WHEELDOWN then wheelDown:= true;
+ SDL_MOUSEBUTTONUP: if event.button.button = SDL_BUTTON_WHEELUP then wheelUp:= true;
SDL_ACTIVEEVENT:
if (event.active.state and SDL_APPINPUTFOCUS) <> 0 then
cHasFocus:= event.active.gain = 1;
@@ -200,9 +201,7 @@
{$ENDIF}
var p: TPathType;
s: shortstring;
-{$IFDEF DEBUGFILE}
i: LongInt;
-{$ENDIF}
begin
{$IFDEF HWLIBRARY}
cBits:= 32;
@@ -225,22 +224,22 @@
cAltDamage:= gameArgs[8] = '1';
val(gameArgs[9], rotationQt);
recordFileName:= gameArgs[10];
+ cStereoMode:= smNone;
{$ENDIF}
cLogfileBase:= 'game';
initEverything(true);
+
WriteLnToConsole('Hedgewars ' + cVersionString + ' engine (network protocol: ' + inttostr(cNetProtoVersion) + ')');
-{$IFDEF DEBUGFILE}
AddFileLog('Prefix: "' + PathPrefix +'"');
for i:= 0 to ParamCount do
AddFileLog(inttostr(i) + ': ' + ParamStr(i));
-{$ENDIF}
for p:= Succ(Low(TPathType)) to High(TPathType) do
if p <> ptMapCurrent then Pathz[p]:= PathPrefix + '/' + Pathz[p];
WriteToConsole('Init SDL... ');
- SDLTry(SDL_Init(SDL_INIT_VIDEO) >= 0, true);
+ SDLTry(SDL_Init(SDL_INIT_VIDEO or SDL_INIT_NOPARACHUTE) >= 0, true);
WriteLnToConsole(msgOK);
SDL_EnableUNICODE(1);
@@ -380,7 +379,7 @@
//uGame does not need to be freed
//uFloat does not need to be freed
uCollisions.freeModule; //stub
- uChat.freeModule; //stub
+ uChat.freeModule;
uAmmos.freeModule;
uAIMisc.freeModule; //stub
//uAIAmmoTests does not need to be freed
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/options.inc
--- a/hedgewars/options.inc Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/options.inc Wed Feb 02 11:28:38 2011 +0300
@@ -25,13 +25,12 @@
{$MODE OBJFPC}
{$MACRO ON}
-{$DEFINE GLunit:=GL,GLext}
+{$DEFINE GLunit:=GL}
{$IFDEF IPHONEOS}
{$DEFINE SDL13}
- {$DEFINE SDL_MIXER_NEWER}
- {$DEFINE SDL_IMAGE_NEWER}
{$DEFINE HWLIBRARY}
+ {$DEFINE S3D_DISABLED}
{$DEFINE GLunit:=gles11}
{$ENDIF}
@@ -41,3 +40,5 @@
{ $DEFINE TRACEAIACTIONS}
{ $DEFINE COUNTTICKS}
{$ENDIF}
+
+//also available LUA_DISABLED
\ No newline at end of file
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uAI.pas
--- a/hedgewars/uAI.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uAI.pas Wed Feb 02 11:28:38 2011 +0300
@@ -41,10 +41,10 @@
procedure FreeActionsList;
begin
-{$IFDEF DEBUGFILE}AddFileLog('FreeActionsList called');{$ENDIF}
+AddFileLog('FreeActionsList called');
if hasThread <> 0 then
begin
- {$IFDEF DEBUGFILE}AddFileLog('Waiting AI thread to finish');{$ENDIF}
+ AddFileLog('Waiting AI thread to finish');
StopThinking:= true;
repeat
SDL_Delay(10)
@@ -323,7 +323,7 @@
FillBonuses((Me^.State and gstAttacked) <> 0);
for a:= Low(TAmmoType) to High(TAmmoType) do
CanUseAmmo[a]:= Assigned(AmmoTests[a].proc) and HHHasAmmo(Me^.Hedgehog^, a);
-{$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF}
+AddFileLog('Enter Think Thread');
BeginThread(@Think, Me, ThinkThread)
end;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uAIAmmoTests.pas
--- a/hedgewars/uAIAmmoTests.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uAIAmmoTests.pas Wed Feb 02 11:28:38 2011 +0300
@@ -31,6 +31,7 @@
end;
function TestBazooka(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
@@ -102,7 +103,10 @@
(proc: @TestGrenade; flags: 0), // amSMine
(proc: @TestFirePunch; flags: 0), // amHammer
(proc: nil; flags: 0), // amResurrector
- (proc: nil; flags: 0) // amDrillStrike
+ (proc: nil; flags: 0), // amDrillStrike
+ (proc: @TestSnowball; flags: 0), // amSnowball
+ (proc: nil; flags: 0), // amTardis
+ (proc: nil; flags: 0) // amStructure
);
const BadTurn = Low(LongInt) div 4;
@@ -172,6 +176,63 @@
TestBazooka:= valueResult
end;
+function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+var Vx, Vy, r: hwFloat;
+ rTime: LongInt;
+ Score, EX, EY: LongInt;
+ valueResult: LongInt;
+
+ function CheckTrace: LongInt;
+ var x, y, dX, dY: hwFloat;
+ t: LongInt;
+ value: LongInt;
+ begin
+ x:= Me^.X;
+ y:= Me^.Y;
+ dX:= Vx;
+ dY:= -Vy;
+ t:= rTime;
+ repeat
+ x:= x + dX;
+ y:= y + dY;
+ dX:= dX + cWindSpeed;
+ dY:= dY + cGravity;
+ dec(t)
+ until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 5) or (t <= 0);
+ EX:= hwRound(x);
+ EY:= hwRound(y);
+ value:= RateExplosion(Me, EX, EY, 5);
+ if value = 0 then value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+ CheckTrace:= value;
+ end;
+
+begin
+ap.Time:= 0;
+rTime:= 350;
+ap.ExplR:= 0;
+valueResult:= BadTurn;
+repeat
+ rTime:= rTime + 300 + Level * 50 + random(300);
+ Vx:= - cWindSpeed * rTime * _0_5 + (int2hwFloat(Targ.X + AIrndSign(2)) - Me^.X) / int2hwFloat(rTime);
+ Vy:= cGravity * rTime * _0_5 - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(rTime);
+ r:= Distance(Vx, Vy);
+ if not (r > _1) then
+ begin
+ Score:= CheckTrace;
+ if valueResult <= Score then
+ begin
+ ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
+ ap.Power:= hwRound(r * cMaxPower) - random((Level - 1) * 17 + 1);
+ ap.ExplR:= 100;
+ ap.ExplX:= EX;
+ ap.ExplY:= EY;
+ valueResult:= Score
+ end;
+ end
+until (rTime > 4250);
+TestSnowball:= valueResult
+end;
+
function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
var Vx, Vy, r: hwFloat;
Score, EX, EY, valueResult: LongInt;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uAmmos.pas
--- a/hedgewars/uAmmos.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uAmmos.pas Wed Feb 02 11:28:38 2011 +0300
@@ -94,7 +94,6 @@
Ammoz[a].Probability:= probability[byte(ammoProbability[ord(a)]) - byte('0')];
Ammoz[a].SkipTurns:= (byte(ammoDelay[ord(a)]) - byte('0'));
Ammoz[a].NumberInCase:= (byte(ammoReinforcement[ord(a)]) - byte('0'));
- if (TrainingFlags and tfIgnoreDelays) <> 0 then Ammoz[a].SkipTurns:= 0;
cnt:= byte(ammoLoadout[ord(a)]) - byte('0');
// avoid things we already have infinite number
if cnt = 9 then
@@ -320,15 +319,12 @@
with CurWeapon^ do
begin
- if AmmoType <> amNothing then
- begin
- s:= trammo[Ammoz[AmmoType].NameId];
- if (Count <> AMMO_INFINITE) and not (Hedgehog.Team^.ExtDriven or (Hedgehog.BotLevel > 0)) then
- s:= s + ' (' + IntToStr(Count) + ')';
- if (Propz and ammoprop_Timerable) <> 0 then
- s:= s + ', ' + IntToStr(Timer div 1000) + ' ' + trammo[sidSeconds];
- AddCaption(s, Team^.Clan^.Color, capgrpAmmoinfo);
- end;
+ s:= trammo[Ammoz[AmmoType].NameId];
+ if (Count <> AMMO_INFINITE) and not (Hedgehog.Team^.ExtDriven or (Hedgehog.BotLevel > 0)) then
+ s:= s + ' (' + IntToStr(Count) + ')';
+ if (Propz and ammoprop_Timerable) <> 0 then
+ s:= s + ', ' + IntToStr(Timer div 1000) + ' ' + trammo[sidSeconds];
+ AddCaption(s, Team^.Clan^.Color, capgrpAmmoinfo);
if (Propz and ammoprop_NeedTarget) <> 0
then begin
Gear^.State:= Gear^.State or gstHHChooseTarget;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uCaptions.pas
--- a/hedgewars/uCaptions.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uCaptions.pas Wed Feb 02 11:28:38 2011 +0300
@@ -10,7 +10,7 @@
procedure freeModule;
implementation
-uses uTextures, uRenderUtils, uVariables, uRender, uConsts;
+uses uTextures, uRenderUtils, uVariables, uRender;
type TCaptionStr = record
Tex: PTexture;
@@ -39,14 +39,11 @@
grp: TCapGroup;
offset: LongInt;
begin
- {$IFDEF IPHONEOS}
+{$IFDEF IPHONEOS}
offset:= 40;
- {$ELSE}
- if ((TrainingFlags and tfTimeTrial) <> 0) and (TimeTrialStartTime > 0) then
- offset:= 48
- else
- offset:= 8;
- {$ENDIF}
+{$ELSE}
+ offset:= 8;
+{$ENDIF}
for grp:= Low(TCapGroup) to High(TCapGroup) do
with Captions[grp] do
@@ -69,7 +66,13 @@
end;
procedure freeModule;
+var
+ group: TCapGroup;
begin
+ for group:= Low(TCapGroup) to High(TCapGroup) do
+ begin
+ FreeTexture(Captions[group].Tex);
+ end;
end;
end.
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uChat.pas
--- a/hedgewars/uChat.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uChat.pas Wed Feb 02 11:28:38 2011 +0300
@@ -29,10 +29,6 @@
procedure DrawChat;
procedure KeyPressChat(Key: Longword);
-var UserNick: shortstring = '';
- ChatReady: boolean;
- showAll: boolean;
-
implementation
uses SDLh, uKeys, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO;
@@ -52,6 +48,8 @@
visibleCount: LongWord;
InputStr: TChatLine;
InputStrL: array[0..260] of char; // for full str + 4-byte utf-8 char
+ ChatReady: boolean;
+ showAll: boolean;
const colors: array[#1..#5] of TSDL_Color = (
(r:$FF; g:$FF; b:$FF; unused:$FF), // chat message [White]
@@ -372,8 +370,13 @@
end;
procedure freeModule;
+var i: ShortInt;
begin
- UserNick:= '';
+ FreeTexture(InputStr.Tex);
+ for i:= 0 to MaxStrIndex do
+ begin
+ FreeTexture(Strs[i].Tex);
+ end;
end;
end.
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uCollisions.pas
--- a/hedgewars/uCollisions.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uCollisions.pas Wed Feb 02 11:28:38 2011 +0300
@@ -44,6 +44,7 @@
function TestCollisionXKick(Gear: PGear; Dir: LongInt): boolean;
function TestCollisionYKick(Gear: PGear; Dir: LongInt): boolean;
+function TestCollisionX(Gear: PGear; Dir: LongInt): boolean;
function TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): boolean;
@@ -289,6 +290,24 @@
Gear^.X:= Gear^.X - ShiftX;
Gear^.Y:= Gear^.Y - int2hwFloat(ShiftY)
end;
+function TestCollisionX(Gear: PGear; Dir: LongInt): boolean;
+var x, y, i: LongInt;
+begin
+x:= hwRound(Gear^.X);
+if Dir < 0 then x:= x - Gear^.Radius
+ else x:= x + Gear^.Radius;
+if (x and LAND_WIDTH_MASK) = 0 then
+ begin
+ y:= hwRound(Gear^.Y) - Gear^.Radius + 1;
+ i:= y + Gear^.Radius * 2 - 2;
+ repeat
+ if (y and LAND_HEIGHT_MASK) = 0 then
+ if Land[y, x] > 255 then exit(true);
+ inc(y)
+ until (y > i);
+ end;
+TestCollisionX:= false
+end;
function TestCollisionY(Gear: PGear; Dir: LongInt): boolean;
var x, y, i: LongInt;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uCommandHandlers.pas
--- a/hedgewars/uCommandHandlers.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uCommandHandlers.pas Wed Feb 02 11:28:38 2011 +0300
@@ -23,27 +23,41 @@
procedure chQuit(var s: shortstring);
const prevGState: TGameState = gsConfirm;
begin
-s:= s; // avoid compiler hint
-if GameState <> gsConfirm then
- begin
+ s:= s; // avoid compiler hint
+ if GameState <> gsConfirm then
+ begin
prevGState:= GameState;
GameState:= gsConfirm
- end else
- GameState:= prevGState
+ end else
+ GameState:= prevGState
+end;
+
+procedure chForceQuit(var s: shortstring);
+begin
+ s:= s; // avoid compiler hint
+ GameState:= gsConfirm;
+ ParseCommand('confirm', true);
end;
procedure chConfirm(var s: shortstring);
begin
-s:= s; // avoid compiler hint
-if GameState = gsConfirm then
+ s:= s; // avoid compiler hint
+ if GameState = gsConfirm then
begin
- SendIPC('Q');
- GameState:= gsExit
+ SendIPC('Q');
+ GameState:= gsExit
end
else
ParseCommand('chat team', true);
end;
+procedure chHalt (var s: shortstring);
+begin
+ s:= s; // avoid compiler hint
+ SendIPC('H');
+ GameState:= gsExit
+end;
+
procedure chCheckProto(var s: shortstring);
var i, c: LongInt;
begin
@@ -165,7 +179,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('L');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmLeft and InputMask)
+ Message:= Message or (gmLeft and InputMask);
+ ScriptCall('onLeft');
end;
procedure chLeft_m(var s: shortstring);
@@ -174,7 +189,8 @@
if CheckNoTeamOrHH then exit;
if not CurrentTeam^.ExtDriven then SendIPC('l');
with CurrentHedgehog^.Gear^ do
- Message:= Message and not (gmLeft and InputMask)
+ Message:= Message and not (gmLeft and InputMask);
+ ScriptCall('onLeftUp');
end;
procedure chRight_p(var s: shortstring);
@@ -184,7 +200,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('R');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmRight and InputMask)
+ Message:= Message or (gmRight and InputMask);
+ ScriptCall('onRight');
end;
procedure chRight_m(var s: shortstring);
@@ -193,7 +210,8 @@
if CheckNoTeamOrHH then exit;
if not CurrentTeam^.ExtDriven then SendIPC('r');
with CurrentHedgehog^.Gear^ do
- Message:= Message and not (gmRight and InputMask)
+ Message:= Message and not (gmRight and InputMask);
+ ScriptCall('onRightUp');
end;
procedure chUp_p(var s: shortstring);
@@ -203,7 +221,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('U');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmUp and InputMask)
+ Message:= Message or (gmUp and InputMask);
+ ScriptCall('onUp');
end;
procedure chUp_m(var s: shortstring);
@@ -213,6 +232,7 @@
if not CurrentTeam^.ExtDriven then SendIPC('u');
with CurrentHedgehog^.Gear^ do
Message:= Message and not (gmUp and InputMask);
+ ScriptCall('onUpUp');
end;
procedure chDown_p(var s: shortstring);
@@ -222,7 +242,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('D');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmDown and InputMask)
+ Message:= Message or (gmDown and InputMask);
+ ScriptCall('onDown');
end;
procedure chDown_m(var s: shortstring);
@@ -231,7 +252,8 @@
if CheckNoTeamOrHH then exit;
if not CurrentTeam^.ExtDriven then SendIPC('d');
with CurrentHedgehog^.Gear^ do
- Message:= Message and not (gmDown and InputMask)
+ Message:= Message and not (gmDown and InputMask);
+ ScriptCall('onDownUp');
end;
procedure chPrecise_p(var s: shortstring);
@@ -242,6 +264,7 @@
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
Message:= Message or (gmPrecise and InputMask);
+ ScriptCall('onPrecise');
end;
procedure chPrecise_m(var s: shortstring);
@@ -251,6 +274,7 @@
if not CurrentTeam^.ExtDriven then SendIPC('z');
with CurrentHedgehog^.Gear^ do
Message:= Message and not (gmPrecise and InputMask);
+ ScriptCall('onPreciseUp');
end;
procedure chLJump(var s: shortstring);
@@ -260,7 +284,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('j');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmLJump and InputMask)
+ Message:= Message or (gmLJump and InputMask);
+ ScriptCall('onLJump');
end;
procedure chHJump(var s: shortstring);
@@ -270,7 +295,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('J');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmHJump and InputMask)
+ Message:= Message or (gmHJump and InputMask);
+ ScriptCall('onHJump');
end;
procedure chAttack_p(var s: shortstring);
@@ -280,12 +306,13 @@
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
begin
- {$IFDEF DEBUGFILE}AddFileLog('/+attack: hedgehog''s Gear^.State = '+inttostr(State));{$ENDIF}
+ AddFileLog('/+attack: hedgehog''s Gear^.State = '+inttostr(State));
if ((State and gstHHDriven) <> 0) then
begin
FollowGear:= CurrentHedgehog^.Gear;
if not CurrentTeam^.ExtDriven then SendIPC('A');
- Message:= Message or (gmAttack and InputMask)
+ Message:= Message or (gmAttack and InputMask);
+ ScriptCall('onAttack');
end
end
end;
@@ -298,7 +325,8 @@
begin
if not CurrentTeam^.ExtDriven and
((Message and gmAttack) <> 0) then SendIPC('a');
- Message:= Message and not (gmAttack and InputMask)
+ Message:= Message and not (gmAttack and InputMask);
+ ScriptCall('onAttackUp');
end
end;
@@ -309,7 +337,8 @@
if not CurrentTeam^.ExtDriven then SendIPC('S');
bShowFinger:= false;
with CurrentHedgehog^.Gear^ do
- Message:= Message or (gmSwitch and InputMask)
+ Message:= Message or (gmSwitch and InputMask);
+ ScriptCall('onSwitch');
end;
procedure chNextTurn(var s: shortstring);
@@ -318,9 +347,7 @@
TryDo(AllInactive, '/nextturn called when not all gears are inactive', true);
if not CurrentTeam^.ExtDriven then SendIPC('N');
-{$IFDEF DEBUGFILE}
AddFileLog('Doing SwitchHedgehog: time '+inttostr(GameTicks));
-{$ENDIF}
end;
procedure chTimer(var s: shortstring);
@@ -332,7 +359,8 @@
with CurrentHedgehog^.Gear^ do
begin
Message:= Message or (gmTimer and InputMask);
- MsgParam:= byte(s[1]) - ord('0')
+ MsgParam:= byte(s[1]) - ord('0');
+ ScriptCall('onTimer');
end
end;
@@ -347,7 +375,8 @@
with CurrentHedgehog^.Gear^ do
begin
Message:= Message or (gmSlot and InputMask);
- MsgParam:= slot
+ MsgParam:= slot;
+ ScriptCall('onSlot');
end
end;
@@ -363,6 +392,7 @@
begin
Message:= Message or (gmWeapon and InputMask);
MsgParam:= byte(s[1]);
+ ScriptCall('onSetWeapon');
end;
end;
@@ -377,7 +407,8 @@
with CurrentHedgehog^.Gear^ do
begin
Message:= Message or (gmAnimate and InputMask);
- MsgParam:= byte(s[1])
+ MsgParam:= byte(s[1]) ;
+ ScriptCall('onTaunt');
end
end;
@@ -407,6 +438,7 @@
if isDeveloperMode then
begin
Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s;
+Theme:= s;
InitStepsFlags:= InitStepsFlags or cifTheme
end
end;
@@ -555,14 +587,15 @@
RegisterVariable('minesnum', vtLongInt, @cLandMines , false);
RegisterVariable('explosives',vtLongInt,@cExplosives , false);
RegisterVariable('gmflags' , vtLongInt, @GameFlags , false);
- RegisterVariable('trflags' , vtLongInt, @TrainingFlags , false);
RegisterVariable('turntime', vtLongInt, @cHedgehogTurnTime, false);
RegisterVariable('minestime',vtLongInt, @cMinesTime , false);
RegisterVariable('fort' , vtCommand, @chFort , false);
RegisterVariable('grave' , vtCommand, @chGrave , false);
RegisterVariable('hat' , vtCommand, @chSetHat , false);
RegisterVariable('quit' , vtCommand, @chQuit , true );
+ RegisterVariable('forcequit', vtCommand, @chForceQuit , true );
RegisterVariable('confirm' , vtCommand, @chConfirm , true );
+ RegisterVariable('halt', vtCommand, @chHalt , true );
RegisterVariable('+speedup', vtCommand, @chSpeedup_p , true );
RegisterVariable('-speedup', vtCommand, @chSpeedup_m , true );
RegisterVariable('zoomin' , vtCommand, @chZoomIn , true );
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uCommands.pas
--- a/hedgewars/uCommands.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uCommands.pas Wed Feb 02 11:28:38 2011 +0300
@@ -60,7 +60,7 @@
if c in ['/', '$'] then Delete(CmdStr, 1, 1) else c:= '/';
s:= '';
SplitBySpace(CmdStr, s);
-{$IFDEF DEBUGFILE}AddFileLog('[Cmd] ' + c + CmdStr + ' (' + inttostr(length(CmdStr)) + ')');{$ENDIF}
+AddFileLog('[Cmd] ' + c + CmdStr + ' (' + inttostr(length(s)) + ')');
t:= Variables;
while t <> nil do
begin
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uConsole.pas
--- a/hedgewars/uConsole.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uConsole.pas Wed Feb 02 11:28:38 2011 +0300
@@ -52,7 +52,7 @@
done: boolean;
begin
{$IFNDEF NOCONSOLE}
-{$IFDEF DEBUGFILE}AddFileLog('[Con] ' + s);{$ENDIF}
+AddFileLog('[Con] ' + s);
Write(s);
done:= false;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uConsts.pas
--- a/hedgewars/uConsts.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uConsts.pas Wed Feb 02 11:28:38 2011 +0300
@@ -23,15 +23,11 @@
uses SDLh, uFloat, GLunit;
-
{$INCLUDE "config.inc"}
-// typed const is a variable despite const qualifier
-// in freepascal you may actually use var for the same purpose
-
const
sfMax = 1000;
- cDefaultParamNum = 16;
+ cDefaultParamNum = 17;
// message constants
errmsgCreateSurface = 'Error creating SDL surface';
@@ -69,7 +65,7 @@
rqNoBackground= $00000004; // don't draw background
rqSimpleRope = $00000008; // draw rope using lines only
rq2DWater = $00000010; // disable 3D water effect
- rqFancyBoom = $00000020; // no fancy explosion effects
+ rqAntiBoom = $00000020; // no fancy explosion effects
rqKillFlakes = $00000040; // no flakes
rqSlowMenu = $00000080; // ammomenu appears with no animation
rqPlainSplash = $00000100; // no droplets
@@ -116,6 +112,7 @@
cCursorEdgesDist : LongInt = 100;
cTeamHealthWidth : LongInt = 128;
cWaterOpacity : byte = $80;
+ cSDWaterOpacity : byte = $80;
cifRandomize = $00000001;
cifTheme = $00000002;
@@ -162,14 +159,6 @@
cSendEmptyPacketTime = 1000;
trigTurns = $80000001;
- // Training Flags
- tfNone = $00000000;
- tfTimeTrial = $00000001;
- tfRCPlane = $00000002;
- tfSpawnTargets = $00000004;
- tfIgnoreDelays = $00000008;
- tfTargetRespawn = $00000010;
-
gfAny = $FFFFFFFF;
gfOneClanMode = $00000001; // used in trainings
gfMultiWeapon = $00000002; // used in trainings
@@ -194,7 +183,7 @@
gfInfAttack = $00100000;
gfResetWeps = $00200000;
gfPerHogAmmo = $00400000;
- gfDisableWind = $00800000; // only lua for now
+ gfDisableWind = $00800000;
gfMoreWind = $01000000;
// NOTE: When adding new game flags, ask yourself
// if a "game start notice" would be useful. If so,
@@ -252,7 +241,7 @@
ammoprop_NotBorder = $00000800;
ammoprop_Utility = $00001000;
ammoprop_Effect = $00002000;
- ammoprop_NoRoundEnd=$10000000;
+ ammoprop_NoRoundEnd = $10000000;
AMMO_INFINITE = 100;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uDebug.pas
--- a/hedgewars/uDebug.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uDebug.pas Wed Feb 02 11:28:38 2011 +0300
@@ -32,4 +32,4 @@
if not Assert then OutError(SDL_GetError, isFatal)
end;
-end.
\ No newline at end of file
+end.
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uFloat.pas
--- a/hedgewars/uFloat.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uFloat.pas Wed Feb 02 11:28:38 2011 +0300
@@ -352,9 +352,7 @@
function AngleSin(const Angle: Longword): hwFloat;
begin
-{$IFDEF DEBUGFILE}
//TryDo((Angle >= 0) and (Angle <= 2048), 'Sin param exceeds limits', true);
-{$ENDIF}
AngleSin.isNegative:= false;
if Angle < 1024 then AngleSin.QWordValue:= SinTable[Angle]
else AngleSin.QWordValue:= SinTable[2048 - Angle]
@@ -362,9 +360,7 @@
function AngleCos(const Angle: Longword): hwFloat;
begin
-{$IFDEF DEBUGFILE}
//TryDo((Angle >= 0) and (Angle <= 2048), 'Cos param exceeds limits', true);
-{$ENDIF}
AngleCos.isNegative:= Angle > 1024;
if Angle < 1024 then AngleCos.QWordValue:= SinTable[1024 - Angle]
else AngleCos.QWordValue:= SinTable[Angle - 1024]
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uGears.pas
--- a/hedgewars/uGears.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uGears.pas Wed Feb 02 11:28:38 2011 +0300
@@ -29,7 +29,7 @@
procedure ResurrectHedgehog(gear: PGear);
procedure ProcessGears;
procedure EndTurnCleanup;
-procedure ApplyDamage(Gear: PGear; Damage: Longword; Source: TDamageSource);
+procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
procedure SetAllToActive;
procedure SetAllHHToActive;
procedure DrawGears;
@@ -47,11 +47,10 @@
implementation
uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics,
uAIMisc, uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uMobile, uVariables,
- uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug;
+ uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture;
-procedure doMakeExplosion(X, Y, Radius: LongInt; Mask: LongWord); forward;
-procedure doMakeExplosion(X, Y, Radius: LongInt; Mask, Tint: LongWord); forward;
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord = $FFFFFFFF); forward;
procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward;
//procedure AmmoFlameWork(Ammo: PGear); forward;
function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): TPGearArray; forward;
@@ -60,10 +59,10 @@
procedure AfterAttack; forward;
procedure HedgehogStep(Gear: PGear); forward;
procedure doStepHedgehogMoving(Gear: PGear); forward;
-procedure HedgehogChAngle(Gear: PGear); forward;
+procedure HedgehogChAngle(HHGear: PGear); forward;
procedure ShotgunShot(Gear: PGear); forward;
procedure PickUp(HH, Gear: PGear); forward;
-procedure HHSetWeapon(Gear: PGear); forward;
+procedure HHSetWeapon(HHGear: PGear); forward;
procedure doStepCase(Gear: PGear); forward;
{$INCLUDE "GSHandlers.inc"}
@@ -127,7 +126,10 @@
@doStepHammer,
@doStepHammerHit,
@doStepResurrector,
- @doStepNapalmBomb
+ @doStepNapalmBomb,
+ @doStepSnowball,
+ @doStepSnowflake,
+ @doStepStructure
);
procedure InsertGearToList(Gear: PGear);
@@ -180,9 +182,7 @@
var gear: PGear;
begin
inc(Counter);
-{$IFDEF DEBUGFILE}
AddFileLog('AddGear: #' + inttostr(Counter) + ' (' + inttostr(x) + ',' + inttostr(y) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
-{$ENDIF}
New(gear);
FillChar(gear^, sizeof(TGear), 0);
@@ -203,7 +203,7 @@
gear^.ImpactSound:= sndNone;
gear^.nImpactSounds:= 0;
-if CurrentTeam <> nil then
+if CurrentHedgehog <> nil then
begin
gear^.Hedgehog:= CurrentHedgehog;
gear^.IntersectGear:= CurrentHedgehog^.Gear
@@ -219,6 +219,7 @@
gear^.Radius:= 5;
gear^.Elasticity:= _0_8;
gear^.Friction:= _0_8;
+ gear^.Density:= _1_5;
gear^.RenderTimer:= true;
if gear^.Timer = 0 then gear^.Timer:= 3000
end;
@@ -229,15 +230,20 @@
gear^.Radius:= 6;
gear^.Elasticity:= _0_8;
gear^.Friction:= _0_995;
+ gear^.Density:= _2;
gear^.RenderTimer:= true;
if gear^.Timer = 0 then gear^.Timer:= 3000
end;
+ gtMelonPiece: begin
+ gear^.Density:= _2;
+ end;
gtHedgehog: begin
gear^.AdvBounce:= 1;
gear^.Radius:= cHHRadius;
gear^.Elasticity:= _0_35;
gear^.Friction:= _0_999;
gear^.Angle:= cMaxAngle div 2;
+ gear^.Density:= _3;
gear^.Z:= cHHZ;
if (GameFlags and gfAISurvival) <> 0 then
if gear^.Hedgehog^.BotLevel > 0 then
@@ -245,6 +251,28 @@
end;
gtShell: begin
gear^.Radius:= 4;
+ gear^.Density:= _1;
+ end;
+ gtSnowball: begin
+ gear^.Radius:= 4;
+ gear^.Elasticity:= _1;
+ gear^.Friction:= _1;
+ gear^.Density:= _0_5;
+ end;
+
+ gtFlake: begin
+ with Gear^ do
+ begin
+ DirAngle:= random * 360;
+ dx.isNegative:= GetRandom(2) = 0;
+ dx.QWordValue:= GetRandom(100000000);
+ dy.isNegative:= false;
+ dy.QWordValue:= GetRandom(70000000);
+ if GetRandom(2) = 0 then dx := -dx;
+ Health:= random(vobFrameTicks);
+ Timer:= random(vobFramesCount);
+ Angle:= (random(2) * 2 - 1) * (1 + random(10000)) * vobVelocity
+ end
end;
gtGrave: begin
gear^.ImpactSound:= sndGraveImpact;
@@ -282,6 +310,7 @@
gear^.Radius:= 2;
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_995;
+ gear^.Density:= _0_9;
if cMinesTime < 0 then
gear^.Timer:= getrandom(51)*100
else
@@ -293,6 +322,7 @@
gear^.Radius:= 2;
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_995;
+ gear^.Density:= _0_9;
gear^.Timer:= 500;
end;
gtCase: begin
@@ -307,6 +337,7 @@
gear^.Radius:= 16;
gear^.Elasticity:= _0_4;
gear^.Friction:= _0_995;
+ gear^.Density:= _6;
gear^.Health:= cBarrelHealth
end;
gtDEagleShot: begin
@@ -321,10 +352,12 @@
gear^.Radius:= 3;
gear^.Elasticity:= _0_55;
gear^.Friction:= _0_03;
+ gear^.Density:= _2;
gear^.Timer:= 5000;
end;
gtCluster: begin
gear^.Radius:= 2;
+ gear^.Density:= _1_5;
gear^.RenderTimer:= true
end;
gtShover: gear^.Radius:= 20;
@@ -332,6 +365,7 @@
gear^.Tag:= GetRandom(32);
gear^.Radius:= 1;
gear^.Health:= 5;
+ gear^.Density:= _1;
if (gear^.dY.QWordValue = 0) and (gear^.dX.QWordValue = 0) then
begin
gear^.dY:= (getrandom - _0_8) * _0_03;
@@ -344,6 +378,7 @@
end;
gtAirBomb: begin
gear^.Radius:= 5;
+ gear^.Density:= _2;
end;
gtBlowTorch: begin
gear^.Radius:= cHHRadius + cBlowTorchC;
@@ -362,7 +397,8 @@
gtMortar: begin
gear^.Radius:= 4;
gear^.Elasticity:= _0_2;
- gear^.Friction:= _0_08
+ gear^.Friction:= _0_08;
+ gear^.Density:= _1;
end;
gtWhip: gear^.Radius:= 20;
gtHammer: gear^.Radius:= 20;
@@ -385,12 +421,16 @@
gear^.Radius:= 4;
gear^.Elasticity:= _0_5;
gear^.Friction:= _0_96;
+ gear^.Density:= _1_5;
gear^.RenderTimer:= true;
gear^.Timer:= 5000
end;
gtDrill: begin
- gear^.Timer:= 5000;
- gear^.Radius:= 4
+ if gear^.Timer = 0 then gear^.Timer:= 5000;
+ // Tag for drill strike. if 1 then first impact occured already
+ gear^.Tag := 0;
+ gear^.Radius:= 4;
+ gear^.Density:= _1;
end;
gtBall: begin
gear^.ImpactSound:= sndGrenadeImpact;
@@ -401,6 +441,7 @@
gear^.Timer:= 5000;
gear^.Elasticity:= _0_7;
gear^.Friction:= _0_995;
+ gear^.Density:= _1_5;
end;
gtBallgun: begin
gear^.Timer:= 5001;
@@ -416,6 +457,7 @@
end;
gtMolotov: begin
gear^.Radius:= 6;
+ gear^.Density:= _2;
end;
gtBirdy: begin
gear^.Radius:= 16; // todo: check
@@ -427,6 +469,7 @@
gear^.Radius:= 4;
gear^.Elasticity:= _0_6;
gear^.Friction:= _0_96;
+ gear^.Density:= _1;
if gear^.Timer = 0 then gear^.Timer:= 3000
end;
gtPortal: begin
@@ -434,13 +477,15 @@
gear^.nImpactSounds:= 1;
gear^.AdvBounce:= 0;
gear^.Radius:= 16;
- gear^.Tag:= 0;
+ // set color
+ gear^.Tag:= 2 * gear^.Timer;
gear^.Timer:= 15000;
gear^.RenderTimer:= false;
gear^.Health:= 100;
end;
gtPiano: begin
- gear^.Radius:= 32
+ gear^.Radius:= 32;
+ gear^.Density:= _50;
end;
gtSineGunShot: begin
gear^.Radius:= 5;
@@ -466,6 +511,14 @@
gtNapalmBomb: begin
gear^.Timer:= 1000;
gear^.Radius:= 5;
+ gear^.Density:= _1_5;
+ end;
+ gtStructure: begin
+ gear^.ImpactSound:= sndGrenadeImpact;
+ gear^.nImpactSounds:= 1;
+ gear^.Radius:= 13;
+ gear^.Elasticity:= _0_3;
+ gear^.Health:= 50;
end;
end;
@@ -511,9 +564,12 @@
begin
t:= max(Gear^.Damage, Gear^.Health);
Gear^.Damage:= t;
- if (cWaterOpacity < $FF) and (hwRound(Gear^.Y) < cWaterLine + 256) then
+ if ((not SuddenDeathDmg and (cWaterOpacity < $FF)) or (SuddenDeathDmg and (cWaterOpacity < $FF))) and (hwRound(Gear^.Y) < cWaterLine + 256) then
spawnHealthTagForHH(Gear, t);
- uStats.HedgehogDamaged(Gear)
+
+ // should be not CurrentHedgehog, but hedgehog of the last gear which caused damage to this hog
+ // same stand for CheckHHDamage
+ uStats.HedgehogDamaged(Gear, CurrentHedgehog)
end;
team:= Gear^.Hedgehog^.Team;
@@ -544,12 +600,12 @@
Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
end
end;
-{$IFDEF DEBUGFILE}
-with Gear^ do AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
-{$ENDIF}
+with Gear^ do
+ AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind));
if CurAmmoGear = Gear then CurAmmoGear:= nil;
if FollowGear = Gear then FollowGear:= nil;
+if lastGearByUID = Gear then lastGearByUID := nil;
RemoveGearFromList(Gear);
Dispose(Gear)
end;
@@ -569,7 +625,7 @@
(not Gear^.Invulnerable) then
begin
CheckNoDamage:= false;
- uStats.HedgehogDamaged(Gear);
+
dmg:= Gear^.Damage;
if Gear^.Health < dmg then
begin
@@ -746,11 +802,20 @@
stHealth: begin
if (cWaterRise <> 0) or (cHealthDecrease <> 0) then
begin
- if (TotalRounds = cSuddenDTurns) and not SuddenDeathDmg and not isInMultiShoot then
+ if (TotalRounds = cSuddenDTurns) and not SuddenDeath and not isInMultiShoot then
begin
- SuddenDeathDmg:= true;
+ SuddenDeath:= true;
+ if cHealthDecrease <> 0 then
+ begin
+ SuddenDeathDmg:= true;
+ ChangeToSDClouds;
+ ChangeToSDFlakes;
+ glClearColor(SDSkyColor.r / 255, SDSkyColor.g / 255, SDSkyColor.b / 255, 0.99);
+ end;
AddCaption(trmsg[sidSuddenDeath], cWhiteColor, capgrpGameState);
- playSound(sndSuddenDeath)
+ playSound(sndSuddenDeath);
+ MusicFN:= SDMusic;
+ ChangeMusic
end
else if (TotalRounds < cSuddenDTurns) and not isInMultiShoot then
begin
@@ -876,7 +941,10 @@
SpeechText:= ''; // in case it has not been consumed
if (GameFlags and gfLowGravity) = 0 then
+ begin
cGravity:= cMaxWindSpeed * 2;
+ cGravityf:= 0.00025 * 2
+ end;
if (GameFlags and gfVampiric) = 0 then
cVampiric:= false;
@@ -928,13 +996,16 @@
RecountTeamHealth(TeamsArray[i])
end;
-procedure ApplyDamage(Gear: PGear; Damage: Longword; Source: TDamageSource);
+procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
var s: shortstring;
vampDmg, tmpDmg, i: Longword;
vg: PVisualGear;
begin
- if (Gear^.Kind = gtHedgehog) and (Damage>=1) then
+ if Damage = 0 then exit; // nothing to apply
+
+ if (Gear^.Kind = gtHedgehog) then
begin
+ uStats.HedgehogDamaged(Gear, AttackerHog);
HHHurt(Gear^.Hedgehog, Source);
AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color);
tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage));
@@ -970,7 +1041,11 @@
spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg);
end;
end;
- end;
+ end else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
+ begin
+ AddFileLog('Assigning hedgehog ' + inttostr(LongInt(AttackerHog)) + ' to gear ' + inttostr(Gear^.uid));
+ Gear^.Hedgehog:= AttackerHog;
+ end;
inc(Gear^.Damage, Damage);
ScriptCall('onGearDamage', Gear^.UID, Damage);
end;
@@ -994,7 +1069,7 @@
t:= GearsList;
while t <> nil do
begin
- if t^.Kind = gtHedgehog then t^.Active:= true;
+ if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then t^.Active:= true;
t:= t^.NextGear
end
end;
@@ -1033,25 +1108,29 @@
begin
AddGear(0, 0, gtATStartGame, 0, _0, _0, 2000);
-if (TrainingFlags and tfSpawnTargets) <> 0 then
- begin
- TrainingTargetGear:= AddGear(0, 0, gtTarget, 0, _0, _0, 0);
- FindPlace(TrainingTargetGear, false, 0, LAND_WIDTH);
- end;
-
-for i:= 0 to Pred(cLandMines) do
+i:= 0;
+Gear:= PGear(1);
+while (i < cLandMines) {and (Gear <> nil)} do // disable this check until better solution found
begin
Gear:= AddGear(0, 0, gtMine, 0, _0, _0, 0);
FindPlace(Gear, false, 0, LAND_WIDTH);
+ inc(i)
end;
-for i:= 0 to Pred(cExplosives) do
+
+i:= 0;
+Gear:= PGear(1);
+while (i < cExplosives){ and (Gear <> nil)} do
begin
Gear:= AddGear(0, 0, gtExplosives, 0, _0, _0, 0);
FindPlace(Gear, false, 0, LAND_WIDTH);
+ inc(i)
end;
if (GameFlags and gfLowGravity) <> 0 then
+ begin
cGravity:= cMaxWindSpeed;
+ cGravityf:= 0.00025
+ end;
if (GameFlags and gfVampiric) <> 0 then
cVampiric:= true;
@@ -1068,15 +1147,17 @@
cLaserSighting:= true;
if (GameFlags and gfArtillery) <> 0 then
- cArtillery:= true
+ cArtillery:= true;
+
+if not hasBorder and ((Theme = 'Snow') or (Theme = 'Christmas')) and ((cReducedQuality and rqLowRes) = 0) then
+ begin
+ 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);
+ disableLandBack:= true
+ end
end;
-procedure doMakeExplosion(X, Y, Radius: LongInt; Mask: LongWord);
-begin
-doMakeExplosion(X, Y, Radius, Mask, $FFFFFFFF);
-end;
-
-procedure doMakeExplosion(X, Y, Radius: LongInt; Mask, Tint: LongWord);
+procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord);
var Gear: PGear;
dmg, dmgRadius, dmgBase: LongInt;
fX, fY: hwFloat;
@@ -1084,7 +1165,7 @@
i, cnt: LongInt;
begin
TargetPoint.X:= NoPointX;
-{$IFDEF DEBUGFILE}if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');{$ENDIF}
+if Radius > 4 then AddFileLog('Explosion: at (' + inttostr(x) + ',' + inttostr(y) + ')');
if Radius > 25 then KickFlakes(Radius, X, Y);
if ((Mask and EXPLNoGfx) = 0) then
@@ -1119,18 +1200,19 @@
gtCase,
gtTarget,
gtFlame,
- gtExplosives: begin
+ gtExplosives,
+ gtStructure: begin
// Run the calcs only once we know we have a type that will need damage
if hwRound(hwAbs(Gear^.X-fX)+hwAbs(Gear^.Y-fY)) < dmgBase then
dmg:= dmgBase - hwRound(Distance(Gear^.X - fX, Gear^.Y - fY));
if dmg > 1 then
begin
dmg:= ModifyDamage(min(dmg div 2, Radius), Gear);
- //{$IFDEF DEBUGFILE}AddFileLog('Damage: ' + inttostr(dmg));{$ENDIF}
+ //AddFileLog('Damage: ' + inttostr(dmg));
if (Mask and EXPLNoDamage) = 0 then
begin
if not Gear^.Invulnerable then
- ApplyDamage(Gear, dmg, dsExplosion)
+ ApplyDamage(Gear, AttackingHog, dmg, dsExplosion)
else
Gear^.State:= Gear^.State or gstWinner;
end;
@@ -1194,9 +1276,10 @@
gtSMine,
gtCase,
gtTarget,
- gtExplosives: begin
+ gtExplosives,
+ gtStructure: begin
if (not t^.Invulnerable) then
- ApplyDamage(t, dmg, dsBullet)
+ ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet)
else
Gear^.State:= Gear^.State or gstWinner;
@@ -1243,16 +1326,13 @@
tmpDmg:= ModifyDamage(Damage, Gear);
if (Gear^.State and gstNoDamage) = 0 then
begin
-
+
if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then
- begin
+ begin
VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
- if VGear <> nil then
- begin
- VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
+ if VGear <> nil then VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
end;
- end;
-
+
if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then Gear^.FlightTime:= 1;
case Gear^.Kind of
@@ -1261,13 +1341,14 @@
gtSMine,
gtTarget,
gtCase,
- gtExplosives: begin
+ gtExplosives,
+ gtStructure: begin
if (Ammo^.Kind = gtDrill) then begin Ammo^.Timer:= 0; exit; end;
if (not Gear^.Invulnerable) then
- ApplyDamage(Gear, tmpDmg, dsShove)
+ ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
else
Gear^.State:= Gear^.State or gstWinner;
- if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then ApplyDamage(Gear, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
+ if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
DeleteCI(Gear);
if (Gear^.Kind = gtHedgehog) and Gear^.Hedgehog^.King then
@@ -1369,12 +1450,13 @@
var
t: PGear;
begin
+ r:= r*r;
GearsNear := nil;
t := GearsList;
while t <> nil do begin
if (t^.Kind = Kind) then begin
if (X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) <
- int2hwFloat(r)*int2hwFloat(r) then
+ int2hwFloat(r) then
begin
SetLength(GearsNear, Length(GearsNear)+1);
GearsNear[High(GearsNear)] := t;
@@ -1458,7 +1540,6 @@
gear^.dX := _0;
gear^.dY := _0;
gear^.State := gstWait;
- uStats.HedgehogDamaged(gear);
gear^.Damage := 0;
gear^.Health := gear^.Hedgehog^.InitialHealth;
gear^.Hedgehog^.Effects[hePoisoned] := false;
@@ -1689,9 +1770,7 @@
begin
Gear^.X:= int2hwFloat(x);
Gear^.Y:= int2hwFloat(y);
- {$IFDEF DEBUGFILE}
AddFileLog('Assigned Gear coordinates (' + inttostr(x) + ',' + inttostr(y) + ')');
- {$ENDIF}
end
else
begin
@@ -1721,13 +1800,20 @@
var gear: PGear;
begin
GearByUID:= nil;
+if uid = 0 then exit;
+if (lastGearByUID <> nil) and (lastGearByUID^.uid = uid) then
+ begin
+ GearByUID:= lastGearByUID;
+ exit
+ end;
gear:= GearsList;
while gear <> nil do
begin
if gear^.uid = uid then
begin
- GearByUID:= gear;
- exit
+ lastGearByUID:= gear;
+ GearByUID:= gear;
+ exit
end;
gear:= gear^.NextGear
end
@@ -1775,7 +1861,7 @@
if (x < 4) and (TeamsArray[t] <> nil) then
begin
// if team matches current hedgehog team, default to current hedgehog
- if (i = 0) and (CurrentHedgehog^.Team = TeamsArray[t]) then hh:= CurrentHedgehog
+ if (i = 0) and (CurrentHedgehog <> nil) and (CurrentHedgehog^.Team = TeamsArray[t]) then hh:= CurrentHedgehog
else
begin
// otherwise use the first living hog or the hog amongs the remaining ones indicated by i
@@ -1792,14 +1878,17 @@
inc(j)
end
end;
- if hh <> nil then Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
- if Gear <> nil then
+ if hh <> nil then
begin
- Gear^.Hedgehog:= hh;
- Gear^.Text:= text;
- Gear^.FrameTicks:= x
+ Gear:= AddVisualGear(0, 0, vgtSpeechBubble);
+ if Gear <> nil then
+ begin
+ Gear^.Hedgehog:= hh;
+ Gear^.Text:= text;
+ Gear^.FrameTicks:= x
+ end
end
- else ParseCommand('say ' + text, true)
+ //else ParseCommand('say ' + text, true)
end
else if (x >= 4) then
begin
@@ -1816,9 +1905,9 @@
CurAmmoGear:= nil;
GearsList:= nil;
KilledHHs:= 0;
+ SuddenDeath:= false;
SuddenDeathDmg:= false;
SpeechType:= 1;
- TrainingTargetGear:= nil;
skipFlag:= false;
AllInactive:= false;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uGearsRender.pas
--- a/hedgewars/uGearsRender.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uGearsRender.pas Wed Feb 02 11:28:38 2011 +0300
@@ -186,7 +186,7 @@
if (Gear^.State and gstHHDeath) <> 0 then
begin
DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos);
- Tint(HH^.Team^.Clan^.Color);
+ Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos + 8);
Tint($FF, $FF, $FF, $FF);
exit
@@ -353,7 +353,7 @@
i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle);
if HatTex^.w > 64 then
begin
- Tint(HH^.Team^.Clan^.Color);
+ Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawRotatedTextureF(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)
@@ -383,7 +383,7 @@
32);
if HatTex^.w > 64 then
begin
- Tint(HH^.Team^.Clan^.Color);
+ Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawTextureF(HatTex,
1,
sx,
@@ -543,6 +543,7 @@
CurWeapon:= GetAmmoEntry(HH^);
case amt of
amBazooka: DrawRotated(sprHandBazooka, hx, hy, sign, aangle);
+ amSnowball: DrawRotated(sprHandSnowball, hx, hy, sign, aangle);
amMortar: DrawRotated(sprHandMortar, hx, hy, sign, aangle);
amMolotov: DrawRotated(sprHandMolotov, hx, hy, sign, aangle);
amBallgun: DrawRotated(sprHandBallgun, hx, hy, sign, aangle);
@@ -554,7 +555,7 @@
amPortalGun: if (CurWeapon^.Timer and 2) <> 0 then // Add a new Hedgehog value instead of abusing timer?
DrawRotatedF(sprPortalGun, hx, hy, 0, sign, aangle)
else
- DrawRotatedF(sprPortalGun, hx, hy, 1+(CurWeapon^.Timer and 1), sign, aangle);
+ DrawRotatedF(sprPortalGun, hx, hy, 1+CurWeapon^.Pos, sign, aangle);
amSniperRifle: DrawRotatedF(sprSniperRifle, hx, hy, 0, sign, aangle);
amBlowTorch: DrawRotated(sprHandBlowTorch, hx, hy, sign, aangle);
amCake: DrawRotated(sprHandCake, hx, hy, sign, aangle);
@@ -704,7 +705,7 @@
32);
if HatTex^.w > 64 then
begin
- Tint(HH^.Team^.Clan^.Color);
+ Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawTextureF(HatTex,
HatVisibility,
sx,
@@ -728,7 +729,7 @@
32);
if HatTex^.w > 64 then
begin
- Tint(HH^.Team^.Clan^.Color);
+ Tint(HH^.Team^.Clan^.Color shl 8 or $FF);
DrawTextureF(HatTex,
HatVisibility,
sx,
@@ -845,6 +846,7 @@
begin
case Gear^.Kind of
gtBomb: DrawRotated(sprBomb, x, y, 0, Gear^.DirAngle);
+ gtSnowball: DrawRotated(sprSnowball, x, y, 0, Gear^.DirAngle);
gtGasBomb: DrawRotated(sprCheese, x, y, 0, Gear^.DirAngle);
gtMolotov: DrawRotated(sprMolotov, x, y, 0, Gear^.DirAngle);
@@ -853,8 +855,6 @@
DrawRotated(sprPlane, x, y, -1, DxDy2Angle(Gear^.dX, Gear^.dY) + 90)
else
DrawRotated(sprPlane, x, y,0,DxDy2Angle(Gear^.dY, Gear^.dX));
- if ((TrainingFlags and tfRCPlane) <> 0) and (TrainingTargetGear <> nil) and ((Gear^.State and gstDrowning) = 0) then
- DrawRotatedf(sprFinger, x, y, GameTicks div 32 mod 16, 0, DxDy2Angle(Gear^.X - TrainingTargetGear^.X, TrainingTargetGear^.Y - Gear^.Y));
end;
gtBall: DrawRotatedf(sprBalls, x, y, Gear^.Tag,0, Gear^.DirAngle);
@@ -1015,6 +1015,17 @@
Tint($FF, $FF, $FF, $FF);
end;
gtNapalmBomb: DrawRotated(sprNapalmBomb, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX));
+ gtFlake: if not isInLag then
+ begin
+ if vobVelocity = 0 then
+ //DrawSprite(sprFlake, x-SpritesData[sprFlake].Width div 2, y-SpritesData[sprFlake].Height div 2, Gear^.Timer)
+ DrawSprite(sprFlake, x, y, Gear^.Timer)
+ else
+ //DrawRotatedF(sprFlake, x-SpritesData[sprFlake].Width div 2, y-SpritesData[sprFlake].Height div 2, Gear^.Timer, 1, Gear^.DirAngle);
+ DrawRotatedF(sprFlake, x, y, Gear^.Timer, 1, Gear^.DirAngle)
+ end;
+ gtStructure: DrawSprite(sprTarget, x - 16, y - 16, 0);
+
end;
if Gear^.RenderTimer and (Gear^.Tex <> nil) then DrawCentered(x + 8, y + 8, Gear^.Tex);
end;
diff -r 8bdc879ee6b2 -r 0eab727d4717 hedgewars/uIO.pas
--- a/hedgewars/uIO.pas Mon Jan 31 21:40:17 2011 +0300
+++ b/hedgewars/uIO.pas Wed Feb 02 11:28:38 2011 +0300
@@ -22,9 +22,6 @@
interface
uses SDLh, uTypes;
-var ipcPort: Word = 0;
- hiTicks: Word;
-
procedure initModule;
procedure freeModule;
@@ -99,18 +96,18 @@
procedure InitIPC;
var ipaddr: TIPAddress;
begin
-WriteToConsole('Init SDL_Net... ');
-SDLTry(SDLNet_Init = 0, true);
-fds:= SDLNet_AllocSocketSet(1);
-SDLTry(fds <> nil, true);
-WriteLnToConsole(msgOK);
-WriteToConsole('Establishing IPC connection... ');
-{$HINTS OFF}
-SDLTry(SDLNet_ResolveHost(ipaddr, '127.0.0.1', ipcPort) = 0, true);
-{$HINTS ON}
-IPCSock:= SDLNet_TCP_Open(ipaddr);
-SDLTry(IPCSock <> nil, true);
-WriteLnToConsole(msgOK)
+ WriteToConsole('Init SDL_Net... ');
+ SDLTry(SDLNet_Init = 0, true);
+ fds:= SDLNet_AllocSocketSet(1);
+ SDLTry(fds <> nil, true);
+ WriteLnToConsole(msgOK);
+ WriteToConsole('Establishing IPC connection to tcp 127.0.0.1:' + IntToStr(ipcPort) + ' ');
+ {$HINTS OFF}
+ SDLTry(SDLNet_ResolveHost(ipaddr, '127.0.0.1', ipcPort) = 0, true);
+ {$HINTS ON}
+ IPCSock:= SDLNet_TCP_Open(ipaddr);
+ SDLTry(IPCSock <> nil, true);
+ WriteLnToConsole(msgOK)
end;
procedure CloseIPC;
@@ -124,7 +121,7 @@
var loTicks: Word;
begin
case s[1] of
- '!': begin {$IFDEF DEBUGFILE}AddFileLog('Ping? Pong!');{$ENDIF}isPonged:= true; end;
+ '!': begin AddFileLog('Ping? Pong!'); isPonged:= true; end;
'?': SendIPC('!');
'e': ParseCommand(copy(s, 2, Length(s) - 1), true);
'E': OutError(copy(s, 2, Length(s) - 1), true);
@@ -139,7 +136,7 @@
else
loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]);
AddCmd(loTicks, s);
- {$IFDEF DEBUGFILE}AddFileLog('[IPC in] '+s[1]+' ticks '+IntToStr(lastcmd^.loTime));{$ENDIF}
+ AddFileLog('[IPC in] '+s[1]+' ticks '+IntToStr(lastcmd^.loTime));
end
end;
@@ -220,7 +217,7 @@
SendEmptyPacketTicks:= 0;
if s[0]>#251 then s[0]:= #251;
SDLNet_Write16(GameTicks, @s[Succ(byte(s[0]))]);
- {$IFDEF DEBUGFILE}AddFileLog('[IPC out] '+ s[1]);{$ENDIF}
+ AddFileLog('[IPC out] '+ s[1]);
inc(s[0], 2);
SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0])))
end
@@ -247,7 +244,7 @@
procedure SendIPCTimeInc;
const timeinc: shortstring = '#';
begin
-{$IFDEF DEBUGFILE}AddFileLog('[IPC out]