# HG changeset patch # User koda # Date 1294142026 -3600 # Node ID f924be23ffb4bdf5c8368c968b9a3459d55e0ddc # Parent 0ddb100fea6164a5444030929e5c925f4e306119# Parent 3edc0cdcfe03abf1143ddbdabf92d37258a2605f merge with HEAD after 0.9.15 release, move consts and vars in their proper files diff -r 0ddb100fea61 -r f924be23ffb4 .hgtags --- a/.hgtags Mon Dec 27 23:57:44 2010 +0100 +++ b/.hgtags Tue Jan 04 12:53:46 2011 +0100 @@ -22,3 +22,6 @@ 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 +5ea3d182415e4327e7584b1aa68197931d232ac3 Hedgewars-iOS-1.2.2 diff -r 0ddb100fea61 -r f924be23ffb4 CMakeLists.txt --- a/CMakeLists.txt Mon Dec 27 23:57:44 2010 +0100 +++ b/CMakeLists.txt Tue Jan 04 12:53:46 2011 +0100 @@ -18,13 +18,9 @@ ARGS identify -in ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE version_suffix ) - STRING(REGEX REPLACE "(.*) +(.*)" "\\2:\\1" version_suffix ${version_suffix}) + STRING(REGEX REPLACE "([0-9a-zA-Z]+)(.*) ([0-9]+)(.*)" "\\3:\\1" version_suffix ${version_suffix}) MESSAGE(STATUS "Building revision ${version_suffix}") - set(version_suffix ".${version_suffix}") -# #truncate to numbers only - trying to fix a problem described in http://www.hedgewars.org/node/2019 -# STRING(REGEX REPLACE "^\\.(\\d+)" ".\\1" version_suffix ${version_suffix}) -# # screw whole suffix if there's no number -# STRING(REGEX REPLACE "^\\.([a-z]+.*)" "-dev" version_suffix ${version_suffix}) + set(version_suffix "-${version_suffix}") ENDIF() ENDIF() ELSE() @@ -243,13 +239,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 0ddb100fea61 -r f924be23ffb4 ChangeLog.txt --- a/ChangeLog.txt Mon Dec 27 23:57:44 2010 +0100 +++ b/ChangeLog.txt Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 QTfrontend/CMakeLists.txt --- a/QTfrontend/CMakeLists.txt Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/CMakeLists.txt Tue Jan 04 12:53:46 2011 +0100 @@ -23,137 +23,142 @@ include_directories(${SDL_INCLUDE_DIR}) include_directories(${SDLMIXER_INCLUDE_DIR}) if(UNIX) - # HACK: in freebsd cannot find iconv.h included via SDL.h - include_directories("/usr/local/include") + # HACK: in freebsd cannot find iconv.h included via SDL.h + include_directories("/usr/local/include") endif(UNIX) if(WIN32 AND NOT UNIX) - set(HEDGEWARS_BINDIR ".") - set(HEDGEWARS_DATADIR "../share/") + set(HEDGEWARS_BINDIR ".") + set(HEDGEWARS_DATADIR "../share/") add_definitions(-DUSE_XFIRE) else() - set(HEDGEWARS_BINDIR ${CMAKE_INSTALL_PREFIX}) - if(DEFINED DATA_INSTALL_DIR) - set(HEDGEWARS_DATADIR ${DATA_INSTALL_DIR}) - else() - set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/share/) - endif() + set(HEDGEWARS_BINDIR ${CMAKE_INSTALL_PREFIX}) + if(DEFINED DATA_INSTALL_DIR) + set(HEDGEWARS_DATADIR ${DATA_INSTALL_DIR}) + else() + set(HEDGEWARS_DATADIR ${CMAKE_INSTALL_PREFIX}/share/) + endif() endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hwconsts.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp) -set( hwfr_src - game.cpp - main.cpp - hwform.cpp - team.cpp - namegen.cpp - teamselect.cpp - teamselhelper.cpp - frameTeam.cpp - vertScrollArea.cpp - gameuiconfig.cpp - ui_hwform.cpp - gamecfgwidget.cpp - pages.cpp - SquareLabel.cpp - hats.cpp - hedgehogerWidget.cpp - hwmap.cpp - mapContainer.cpp - tcpBase.cpp - about.cpp - proto.cpp - fpsedit.cpp - netserver.cpp - newnetclient.cpp - netudpserver.cpp - netudpwidget.cpp - netregister.cpp - netserverslist.cpp - chatwidget.cpp - binds.cpp - SDLs.cpp - playrecordpage.cpp - ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp - selectWeapon.cpp - itemNum.cpp - input_ip.cpp - igbox.cpp - weaponItem.cpp - statsPage.cpp - misc.cpp - ammoSchemeModel.cpp - togglebutton.cpp - bgwidget.cpp - achievements.cpp - ) +set(hwfr_src + game.cpp + main.cpp + hwform.cpp + team.cpp + namegen.cpp + teamselect.cpp + teamselhelper.cpp + frameTeam.cpp + vertScrollArea.cpp + gameuiconfig.cpp + ui_hwform.cpp + gamecfgwidget.cpp + pages.cpp + SquareLabel.cpp + hats.cpp + hedgehogerWidget.cpp + hwmap.cpp + mapContainer.cpp + tcpBase.cpp + about.cpp + proto.cpp + fpsedit.cpp + netserver.cpp + newnetclient.cpp + netudpserver.cpp + netudpwidget.cpp + netregister.cpp + netserverslist.cpp + chatwidget.cpp + binds.cpp + SDLs.cpp + playrecordpage.cpp + ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp + selectWeapon.cpp + itemNum.cpp + input_ip.cpp + igbox.cpp + weaponItem.cpp + statsPage.cpp + misc.cpp + ammoSchemeModel.cpp + togglebutton.cpp + bgwidget.cpp + achievements.cpp + qaspectratiolayout.cpp + drawmapwidget.cpp + drawmapscene.cpp + ) #xfire integration if(WIN32) - set(hwfr_src ${hwfr_src} xfire.cpp ../misc/xfire/xfiregameclient.cpp) + set(hwfr_src ${hwfr_src} xfire.cpp ../misc/xfire/xfiregameclient.cpp) endif(WIN32) if(MINGW) - # resource compilation for mingw - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o - COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR} - -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc - -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) - set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) + # resource compilation for mingw + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o + COMMAND windres -I ${CMAKE_CURRENT_SOURCE_DIR} + -i ${CMAKE_CURRENT_SOURCE_DIR}/hedgewars.rc + -o ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) + set(hwfr_src ${hwfr_src} ${CMAKE_CURRENT_BINARY_DIR}/hedgewars_rc.o) else(MINGW) - set(hwfr_src ${hwfr_src} hedgewars.rc) + set(hwfr_src ${hwfr_src} hedgewars.rc) endif(MINGW) -set( hwfr_moc_hdrs - game.h - hats.h - hwform.h - teamselect.h - teamselhelper.h - frameTeam.h - vertScrollArea.h - gameuiconfig.h - gamecfgwidget.h - pages.h - SquareLabel.h - hedgehogerWidget.h - hwmap.h - mapContainer.h - tcpBase.h - about.h - proto.h - fpsedit.h - netserver.h - newnetclient.h - netudpserver.h - netudpwidget.h - netregister.h - netserverslist.h - chatwidget.h - SDLs.h - playrecordpage.h - selectWeapon.h - itemNum.h - input_ip.h - igbox.h - weaponItem.h - statsPage.h - misc.h - ammoSchemeModel.h - togglebutton.h - bgwidget.h - ) +set(hwfr_moc_hdrs + game.h + hats.h + hwform.h + teamselect.h + teamselhelper.h + frameTeam.h + vertScrollArea.h + gameuiconfig.h + gamecfgwidget.h + pages.h + SquareLabel.h + hedgehogerWidget.h + hwmap.h + mapContainer.h + tcpBase.h + about.h + proto.h + fpsedit.h + netserver.h + newnetclient.h + netudpserver.h + netudpwidget.h + netregister.h + netserverslist.h + chatwidget.h + SDLs.h + playrecordpage.h + selectWeapon.h + itemNum.h + input_ip.h + igbox.h + weaponItem.h + statsPage.h + misc.h + ammoSchemeModel.h + togglebutton.h + bgwidget.h + qaspectratiolayout.h + drawmapwidget.h + drawmapscene.h + ) -set( hwfr_hdrs - binds.h - ui_hwform.h - predefteams.h - KB.h - hwconsts.h - ) +set(hwfr_hdrs + binds.h + ui_hwform.h + KB.h + hwconsts.h + ) set(hwfr_rez hedgewars.qrc) @@ -163,45 +168,45 @@ if(APPLE) - set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m) - set(HW_LINK_LIBS IOKit) + set(hwfr_src ${hwfr_src} InstallController.cpp CocoaInitializer.mm M3Panel.mm M3InstallController.m NSWorkspace_RBAdditions.m) + set(HW_LINK_LIBS IOKit) - find_package(Sparkle) - if(SPARKLE_FOUND) + find_package(Sparkle) + if(SPARKLE_FOUND) add_definitions(-DSPARKLE_ENABLED) - set(hwfr_src ${hwfr_src} AutoUpdater.cpp SparkleAutoUpdater.mm) + set(hwfr_src ${hwfr_src} AutoUpdater.cpp SparkleAutoUpdater.mm) set(HW_LINK_LIBS ${SPARKLE_LIBRARY} ${HW_LINK_LIBS}) - endif() + endif() endif() add_executable(hedgewars WIN32 - ${hwfr_src} - ${hwfr_moc_srcs} - ${hwfr_hdrs} - ${hwfr_rez_src} - ) + ${hwfr_src} + ${hwfr_moc_srcs} + ${hwfr_hdrs} + ${hwfr_rez_src} + ) -set( HW_LINK_LIBS - ${QT_LIBRARIES} - ${SDL_LIBRARY} - ${SDLMIXER_LIBRARY} - ${HW_LINK_LIBS} - ) +set(HW_LINK_LIBS + ${QT_LIBRARIES} + ${SDL_LIBRARY} + ${SDLMIXER_LIBRARY} + ${HW_LINK_LIBS} + ) if(WIN32 AND NOT UNIX) - if(NOT SDL_LIBRARY) - set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL) - endif() + if(NOT SDL_LIBRARY) + set(HW_LINK_LIBS ${HW_LINK_LIBS} SDL) + endif() - set( HW_LINK_LIBS - ${HW_LINK_LIBS} - ole32 - oleaut32 - winspool - uuid - ) + set( HW_LINK_LIBS + ${HW_LINK_LIBS} + ole32 + oleaut32 + winspool + uuid + ) endif() diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/SDLs.cpp --- a/QTfrontend/SDLs.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/SDLs.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 QTfrontend/SquareLabel.cpp --- a/QTfrontend/SquareLabel.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/SquareLabel.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -29,6 +29,8 @@ void SquareLabel::paintEvent(QPaintEvent * event) { + Q_UNUSED(event); + QPainter painter(this); int pixsize; if (width() > height()) { diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/about.cpp --- a/QTfrontend/about.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/about.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -119,13 +119,14 @@ "German: Peter Hüwe <PeterHuewe@gmx.de>, Mario Liebisch <mario.liebisch@gmail.com>
" "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>
" "Slovak: Jose Riha
" "Spanish: Carlos Vives <mail@carlosvives.es>
" "Swedish: Niklas Grahn <raewolusjoon@yaoo.com>, Henrik Rostedt <henrik.rostedt@gmail.com>
" - "Ukrainian: Eugene V. Lyubimkin <jackyf.devel@gmail.com>" + "Ukrainian: Eugene V. Lyubimkin <jackyf.devel@gmail.com>, Igor Paliychuk <igor-hkr@mail.ru>, Yevhen Sakara <eresid@gmail.com>" "

") + QLabel::tr("Special thanks:") + "

" diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/ammoSchemeModel.cpp --- a/QTfrontend/ammoSchemeModel.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/ammoSchemeModel.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -60,6 +60,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; AmmoSchemeModel::AmmoSchemeModel(QObject* parent, const QString & fileName) : @@ -120,6 +121,7 @@ << "healthcaseamount" // 34 << "waterrise" // 35 << "healthdecrease" // 36 + << "ropepct" // 37 ; QList proMode; @@ -161,6 +163,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList shoppa; @@ -202,6 +205,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList cleanslate; @@ -243,6 +247,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList minefield; @@ -284,6 +289,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList barrelmayhem; @@ -325,6 +331,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList tunnelhogs; @@ -366,6 +373,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList forts; @@ -407,6 +415,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList timeless; @@ -448,6 +457,7 @@ << QVariant(30) // health case amt 34 << QVariant(0) // water rise amt 35 << QVariant(0) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList thinkingportals; @@ -489,6 +499,7 @@ << QVariant(25) // health case amt 34 << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; QList kingmode; @@ -507,8 +518,8 @@ << QVariant(false) // artillery 11 << QVariant(true) // random order 12 << QVariant(true) // king 13 - << QVariant(true) // place hog 14 - << QVariant(true) // shared ammo 15 + << QVariant(false) // place hog 14 + << QVariant(false) // shared ammo 15 << QVariant(false) // disable girders 16 << QVariant(false) // disable land objects 17 << QVariant(false) // AI survival 18 @@ -523,13 +534,14 @@ << QVariant(15) // sudden death 27 << QVariant(5) // case prob 28 << QVariant(3) // mines time 29 - << QVariant(3) // mines number 30 - << QVariant(20) // mine dud pct 31 - << QVariant(3) // explosives 32 + << QVariant(4) // mines number 30 + << QVariant(0) // mine dud pct 31 + << QVariant(2) // explosives 32 << QVariant(35) // health case pct 33 - << QVariant(30) // health case amt 34 - << QVariant(30) // water rise amt 35 + << QVariant(25) // health case amt 34 + << QVariant(47) // water rise amt 35 << QVariant(5) // health dec amt 36 + << QVariant(100) // rope modfier 37 ; @@ -565,6 +577,10 @@ QVariant AmmoSchemeModel::headerData(int section, Qt::Orientation orientation, int role) const { + Q_UNUSED(section); + Q_UNUSED(orientation); + Q_UNUSED(role); + return QVariant(); } @@ -586,6 +602,8 @@ Qt::ItemFlags AmmoSchemeModel::flags(const QModelIndex & index) const { + Q_UNUSED(index); + return Qt::ItemIsEnabled | Qt::ItemIsSelectable @@ -608,12 +626,22 @@ bool AmmoSchemeModel::insertRows(int row, int count, const QModelIndex & parent) { - beginInsertRows(parent, row, row); + Q_UNUSED(count); + + 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(); @@ -672,6 +700,10 @@ QVariant NetAmmoSchemeModel::headerData(int section, Qt::Orientation orientation, int role) const { + Q_UNUSED(section); + Q_UNUSED(orientation); + Q_UNUSED(role); + return QVariant(); } diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/ammoSchemeModel.h --- a/QTfrontend/ammoSchemeModel.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/ammoSchemeModel.h Tue Jan 04 12:53:46 2011 +0100 @@ -42,6 +42,7 @@ int numberOfDefaultSchemes; QStringList predefSchemesNames; + QStringList spNames; public slots: void Save(); @@ -54,8 +55,6 @@ private: QSettings fileConfig; - - QStringList spNames; }; class NetAmmoSchemeModel : public QAbstractTableModel diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/bgwidget.cpp --- a/QTfrontend/bgwidget.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/bgwidget.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -103,6 +103,8 @@ void BGWidget::paintEvent(QPaintEvent *event) { + Q_UNUSED(event); + QPainter p; p.begin(this); //p.setRenderHint(QPainter::Antialiasing); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/chatwidget.cpp --- a/QTfrontend/chatwidget.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/chatwidget.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -341,6 +341,8 @@ void HWChatWidget::chatNickSelected(int index) { + Q_UNUSED(index); + QListWidgetItem* item = chatNicks->currentItem(); if (!item) return; diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/drawmapscene.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/drawmapscene.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,195 @@ +#include +#include +#include + +#include "drawmapscene.h" + +template T sqr(const T & x) +{ + return x*x; +} + +DrawMapScene::DrawMapScene(QObject *parent) : + QGraphicsScene(parent), + m_pen(Qt::yellow), + m_brush(Qt::yellow) +{ + setSceneRect(0, 0, 4096, 2048); + + QLinearGradient gradient(0, 0, 0, 2048); + gradient.setColorAt(0, QColor(60, 60, 155)); + gradient.setColorAt(1, QColor(155, 155, 60)); + setBackgroundBrush(QBrush(gradient)); + + m_pen.setWidth(67); + m_pen.setJoinStyle(Qt::RoundJoin); + m_pen.setCapStyle(Qt::RoundCap); + m_currPath = 0; +} + +void DrawMapScene::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent) +{ + if(m_currPath && (mouseEvent->buttons() & Qt::LeftButton)) + { + QPainterPath path = m_currPath->path(); + path.lineTo(mouseEvent->scenePos()); + paths.first().append(mouseEvent->scenePos().toPoint()); + m_currPath->setPath(path); + + emit pathChanged(); + } +} + +void DrawMapScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent) +{ + m_currPath = addPath(QPainterPath(), m_pen); + + QPainterPath path = m_currPath->path(); + QPointF p = mouseEvent->scenePos(); + p += QPointF(0.01, 0.01); + path.moveTo(p); + path.lineTo(mouseEvent->scenePos()); + paths.prepend(QList() << mouseEvent->scenePos().toPoint()); + m_currPath->setPath(path); + + emit pathChanged(); +} + +void DrawMapScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent) +{ + Q_UNUSED(mouseEvent); + + simplifyLast(); + + m_currPath = 0; +} + +void DrawMapScene::undo() +{ + if(items().size()) + { + removeItem(items().first()); + paths.removeFirst(); + + emit pathChanged(); + } +} + +void DrawMapScene::clearMap() +{ + clear(); + paths.clear(); + + emit pathChanged(); +} + +QByteArray DrawMapScene::encode() +{ + QByteArray b; + + 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()); + qint16 py = qToBigEndian((qint16)point.y()); + quint8 flags = 2; + if(!cnt) flags |= 0x80; + b.append((const char *)&px, 2); + b.append((const char *)&py, 2); + b.append((const char *)&flags, 1); + + ++cnt; + } + + } + + return b; +} + +void DrawMapScene::decode(QByteArray data) +{ + clear(); + paths.clear(); + + QList points; + + while(data.size() >= 5) + { + qint16 px = qFromBigEndian(*(qint16 *)data.data()); + data.remove(0, 2); + qint16 py = qFromBigEndian(*(qint16 *)data.data()); + data.remove(0, 2); + quint8 flags = *(quint8 *)data.data(); + data.remove(0, 1); + + if((flags & 0x80) && points.size()) + { + addPath(pointsToPath(points), m_pen); + paths.prepend(points); + + points.clear(); + } + + points.append(QPoint(px, py)); + } + + if(points.size()) + { + addPath(pointsToPath(points), m_pen); + paths.prepend(points); + } + + emit pathChanged(); +} + +void DrawMapScene::simplifyLast() +{ + if(!paths.size()) return; + + QList points = paths.at(0); + + QPoint prevPoint = points.first(); + int i = 1; + while(i < points.size()) + { + if( (i != points.size() - 1) + && (sqr(prevPoint.x() - points[i].x()) + sqr(prevPoint.y() - points[i].y()) < 1000) + ) + points.removeAt(i); + else + { + prevPoint = points[i]; + ++i; + } + } + + paths[0] = points; + + + // redraw path + { + QGraphicsPathItem * pathItem = static_cast(items()[0]); + pathItem->setPath(pointsToPath(paths[0])); + } + + emit pathChanged(); +} + +QPainterPath DrawMapScene::pointsToPath(const QList points) +{ + QPainterPath path; + + if(points.size()) + { + QPointF p = points[0] + QPointF(0.01, 0.01); + path.moveTo(p); + + foreach(QPoint p, points) + path.lineTo(p); + } + + return path; +} diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/drawmapscene.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/drawmapscene.h Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,41 @@ +#ifndef DRAWMAPSCENE_H +#define DRAWMAPSCENE_H + +#include +#include + +class QGraphicsPathItem; + +typedef QList > Paths; + +class DrawMapScene : public QGraphicsScene +{ +Q_OBJECT +public: + explicit DrawMapScene(QObject *parent = 0); + + QByteArray encode(); + void decode(QByteArray data); + +signals: + void pathChanged(); + +public slots: + void undo(); + void clearMap(); + void simplifyLast(); + +private: + QPen m_pen; + QBrush m_brush; + QGraphicsPathItem * m_currPath; + Paths paths; + + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent); + virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent); + + QPainterPath pointsToPath(const QList points); +}; + +#endif // DRAWMAPSCENE_H diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/drawmapwidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/drawmapwidget.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,87 @@ +#include +#include + +#include "drawmapwidget.h" + +DrawMapWidget::DrawMapWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::DrawMapWidget) +{ + ui->setupUi(this); + + m_scene = 0; +} + +DrawMapWidget::~DrawMapWidget() +{ + delete ui; +} + +void DrawMapWidget::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void DrawMapWidget::setScene(DrawMapScene * scene) +{ + ui->graphicsView->setScene(scene); + m_scene = scene; +} + +void DrawMapWidget::resizeEvent(QResizeEvent * event) +{ + Q_UNUSED(event); + + if(ui->graphicsView && ui->graphicsView->scene()) + ui->graphicsView->fitInView(ui->graphicsView->scene()->sceneRect(), Qt::KeepAspectRatio); +} + +void DrawMapWidget::showEvent(QShowEvent * event) +{ + Q_UNUSED(event); + + resizeEvent(0); +} + +void DrawMapWidget::undo() +{ + if(m_scene) m_scene->undo(); +} + +void DrawMapWidget::clear() +{ + if(m_scene) m_scene->clearMap(); +} + +void DrawMapWidget::save(const QString & 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) +{ + 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 0ddb100fea61 -r f924be23ffb4 QTfrontend/drawmapwidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/drawmapwidget.h Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,69 @@ +#ifndef DRAWMAPWIDGET_H +#define DRAWMAPWIDGET_H + +#include +#include +#include +#include +#include + +#include "qaspectratiolayout.h" +#include "drawmapscene.h" + +namespace Ui { + class Ui_DrawMapWidget + { + public: + QGraphicsView *graphicsView; + + void setupUi(QWidget *drawMapWidget) + { + QAspectRatioLayout * arLayout = new QAspectRatioLayout(drawMapWidget); + arLayout->setMargin(0); + + graphicsView = new QGraphicsView(drawMapWidget); + arLayout->addWidget(graphicsView); + + retranslateUi(drawMapWidget); + + QMetaObject::connectSlotsByName(drawMapWidget); + } // setupUi + + void retranslateUi(QWidget *drawMapWidget) + { + Q_UNUSED(drawMapWidget); + } // retranslateUi + + }; + + class DrawMapWidget: public Ui_DrawMapWidget {}; +} + +class DrawMapWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DrawMapWidget(QWidget *parent = 0); + ~DrawMapWidget(); + + void setScene(DrawMapScene * scene); + +public slots: + void undo(); + void clear(); + void save(const QString & fileName); + void load(const QString & fileName); + +protected: + void changeEvent(QEvent *e); + virtual void resizeEvent(QResizeEvent * event); + virtual void showEvent(QShowEvent * event); + +private: + Ui::DrawMapWidget *ui; + + DrawMapScene * m_scene; +}; + +#endif // DRAWMAPWIDGET_H diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/game.cpp --- a/QTfrontend/game.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/game.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -40,6 +40,7 @@ this->config = config; this->gamecfg = gamecfg; TeamCount = 0; + netSuspend = false; } HWGame::~HWGame() @@ -77,7 +78,7 @@ } HWProto::addStringToBuffer(buf, gt); - HWProto::addStringListToBuffer(buf, gamecfg->getFullConfig()); + buf += gamecfg->getFullConfig(); if (m_pTeamSelWidget) { @@ -88,7 +89,7 @@ HWProto::addStringToBuffer(buf, QString("eammprob %1").arg(ammostr.mid(cAmmoNumber, cAmmoNumber))); HWProto::addStringToBuffer(buf, QString("eammdelay %1").arg(ammostr.mid(2 * cAmmoNumber, cAmmoNumber))); HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber))); - HWProto::addStringToBuffer(buf, QString("eammstore")); + if(!gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore")); HWProto::addStringListToBuffer(buf, (*it).TeamGameConfig(gamecfg->getInitHealth())); } @@ -245,7 +246,7 @@ break; } default: { - if (gameType == gtNet) + if (gameType == gtNet && !netSuspend) { emit SendNet(msg); } @@ -378,3 +379,15 @@ gameState = state; emit GameStateChanged(state); } + +void HWGame::KillAllTeams() +{ + if (m_pTeamSelWidget) + { + QByteArray buf; + QList teams = m_pTeamSelWidget->getPlayingTeams(); + for(QList::iterator it = teams.begin(); it != teams.end(); ++it) + HWProto::addStringToBuffer(buf, QString("eteamgone %1").arg((*it).TeamName)); + RawSendIPC(buf); + } +} diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/game.h --- a/QTfrontend/game.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/game.h Tue Jan 04 12:53:46 2011 +0100 @@ -53,6 +53,9 @@ void StartNet(); void StartTraining(const QString & file); void StartCampaign(const QString & file); + void KillAllTeams(); + GameState gameState; + bool netSuspend; protected: virtual QStringList setArguments(); @@ -89,7 +92,6 @@ GameCFGWidget * gamecfg; TeamSelWidget* m_pTeamSelWidget; GameType gameType; - GameState gameState; void commonConfig(); void SendConfig(); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/gamecfgwidget.cpp --- a/QTfrontend/gamecfgwidget.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/gamecfgwidget.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -30,8 +30,9 @@ #include "igbox.h" #include "hwconsts.h" #include "ammoSchemeModel.h" +#include "proto.h" -GameCFGWidget::GameCFGWidget(QWidget* parent, bool externalControl) : +GameCFGWidget::GameCFGWidget(QWidget* parent) : QGroupBox(parent), mainLayout(this) { mainLayout.setMargin(0); @@ -42,48 +43,96 @@ IconedGroupBox *GBoxOptions = new IconedGroupBox(this); GBoxOptions->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - mainLayout.addWidget(GBoxOptions); + mainLayout.addWidget(GBoxOptions, 1, 0); QGridLayout *GBoxOptionsLayout = new QGridLayout(GBoxOptions); - GameSchemes = new QComboBox(GBoxOptions); - GBoxOptionsLayout->addWidget(GameSchemes, 0, 1); + GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Gameplay"), GBoxOptions), 0, 0); + + Scripts = new QComboBox(GBoxOptions); + GBoxOptionsLayout->addWidget(Scripts, 0, 1); + + Scripts->addItem("Normal"); + Scripts->insertSeparator(1); + + for (int i = 0; i < scriptList->size(); ++i) { + QString script = (*scriptList)[i].remove(".lua", Qt::CaseInsensitive); + QList scriptInfo; + scriptInfo.push_back(script); + QFile scriptCfgFile(QString("%1/Scripts/Multiplayer/%2.cfg").arg(datadir->absolutePath()).arg(script)); + if (scriptCfgFile.exists() && scriptCfgFile.open(QFile::ReadOnly)) { + QString scheme; + QString weapons; + QTextStream input(&scriptCfgFile); + input >> scheme; + input >> weapons; + if (scheme.isEmpty()) + scheme = "locked"; + scheme.replace("_", " "); + if (weapons.isEmpty()) + weapons = "locked"; + weapons.replace("_", " "); + scriptInfo.push_back(scheme); + scriptInfo.push_back(weapons); + scriptCfgFile.close(); + } + else + { + scriptInfo.push_back("locked"); + scriptInfo.push_back("locked"); + } + Scripts->addItem(script.replace("_", " "), scriptInfo); + } + + connect(Scripts, SIGNAL(currentIndexChanged(int)), this, SLOT(scriptChanged(int))); + + QWidget *SchemeWidget = new QWidget(GBoxOptions); + GBoxOptionsLayout->addWidget(SchemeWidget, 1, 0, 1, 2); + + QGridLayout *SchemeWidgetLayout = new QGridLayout(SchemeWidget); + SchemeWidgetLayout->setMargin(0); + + GameSchemes = new QComboBox(SchemeWidget); + SchemeWidgetLayout->addWidget(GameSchemes, 0, 2); connect(GameSchemes, SIGNAL(currentIndexChanged(int)), this, SLOT(schemeChanged(int))); - GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Game scheme"), GBoxOptions), 0, 0); + SchemeWidgetLayout->addWidget(new QLabel(QLabel::tr("Game scheme"), SchemeWidget), 0, 0); QPixmap pmEdit(":/res/edit.png"); - QPushButton * goToSchemePage = new QPushButton(GBoxOptions); + QPushButton * goToSchemePage = new QPushButton(SchemeWidget); goToSchemePage->setToolTip(tr("Edit schemes")); goToSchemePage->setIconSize(pmEdit.size()); goToSchemePage->setIcon(pmEdit); goToSchemePage->setMaximumWidth(pmEdit.width() + 6); - GBoxOptionsLayout->addWidget(goToSchemePage, 0, 2); - connect(goToSchemePage, SIGNAL(clicked()), this, SIGNAL(goToSchemes())); + SchemeWidgetLayout->addWidget(goToSchemePage, 0, 3); + connect(goToSchemePage, SIGNAL(clicked()), this, SLOT(jumpToSchemes())); - GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Weapons"), GBoxOptions), 1, 0); + SchemeWidgetLayout->addWidget(new QLabel(QLabel::tr("Weapons"), SchemeWidget), 1, 0); - WeaponsName = new QComboBox(GBoxOptions); - GBoxOptionsLayout->addWidget(WeaponsName, 1, 1); + WeaponsName = new QComboBox(SchemeWidget); + SchemeWidgetLayout->addWidget(WeaponsName, 1, 2); connect(WeaponsName, SIGNAL(currentIndexChanged(int)), this, SLOT(ammoChanged(int))); - QPushButton * goToWeaponPage = new QPushButton(GBoxOptions); + QPushButton * goToWeaponPage = new QPushButton(SchemeWidget); goToWeaponPage->setToolTip(tr("Edit weapons")); goToWeaponPage->setIconSize(pmEdit.size()); goToWeaponPage->setIcon(pmEdit); goToWeaponPage->setMaximumWidth(pmEdit.width() + 6); - GBoxOptionsLayout->addWidget(goToWeaponPage, 1, 2); - + SchemeWidgetLayout->addWidget(goToWeaponPage, 1, 3); connect(goToWeaponPage, SIGNAL(clicked()), this, SLOT(jumpToWeapons())); - GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Bind schemes and weapons"), GBoxOptions), 2, 0); + //GBoxOptionsLayout->addWidget(new QLabel(QLabel::tr("Bind schemes with weapons"), GBoxOptions), 2, 0); - bindEntries = new QCheckBox(GBoxOptions); - bindEntries->setToolTip(tr("When this option is enabled selecting a game scheme will auto-select a weapon (and viceversa)")); + bindEntries = new QCheckBox(SchemeWidget); + bindEntries->setToolTip(tr("When this option is enabled selecting a game scheme will auto-select a weapon")); bindEntries->setChecked(true); - GBoxOptionsLayout->addWidget(bindEntries, 2, 2); + bindEntries->setMaximumWidth(42); + bindEntries->setStyleSheet( "QCheckBox::indicator:checked { image: url(\":/res/lock.png\"); }" + "QCheckBox::indicator:unchecked { image: url(\":/res/unlock.png\"); }" ); + SchemeWidgetLayout->addWidget(bindEntries, 0, 1, 0, 1, Qt::AlignVCenter); + //GBoxOptionsLayout->addWidget(bindEntries, 2, 2); connect(pMapContainer, SIGNAL(seedChanged(const QString &)), this, SLOT(seedChanged(const QString &))); connect(pMapContainer, SIGNAL(mapChanged(const QString &)), this, SLOT(mapChanged(const QString &))); @@ -91,11 +140,18 @@ connect(pMapContainer, SIGNAL(maze_sizeChanged(int)), this, SLOT(maze_sizeChanged(int))); connect(pMapContainer, SIGNAL(themeChanged(const QString &)), this, SLOT(themeChanged(const QString &))); connect(pMapContainer, SIGNAL(newTemplateFilter(int)), this, SLOT(templateFilterChanged(int))); + connect(pMapContainer, SIGNAL(drawMapRequested()), this, SIGNAL(goToDrawMap())); + connect(pMapContainer, SIGNAL(drawnMapChanged(const QByteArray &)), this, SLOT(onDrawnMapChanged(const QByteArray &))); +} + +void GameCFGWidget::jumpToSchemes() +{ + emit goToSchemes(GameSchemes->currentIndex()); } void GameCFGWidget::jumpToWeapons() { - emit goToWeapons(WeaponsName->currentText()); + emit goToWeapons(WeaponsName->currentIndex()); } QVariant GameCFGWidget::schemeData(int column) const @@ -162,37 +218,71 @@ return schemeData(26).toInt(); } -QStringList GameCFGWidget::getFullConfig() const +QByteArray GameCFGWidget::getFullConfig() const { - QStringList sl; - sl.append("eseed " + pMapContainer->getCurrentSeed()); - sl.append(QString("e$gmflags %1").arg(getGameFlags())); - sl.append(QString("e$damagepct %1").arg(schemeData(24).toInt())); - sl.append(QString("e$turntime %1").arg(schemeData(25).toInt() * 1000)); - sl.append(QString("e$sd_turns %1").arg(schemeData(27).toInt())); - sl.append(QString("e$casefreq %1").arg(schemeData(28).toInt())); - sl.append(QString("e$minestime %1").arg(schemeData(29).toInt())); - sl.append(QString("e$minesnum %1").arg(schemeData(30).toInt())); - sl.append(QString("e$minedudpct %1").arg(schemeData(31).toInt())); - sl.append(QString("e$explosives %1").arg(schemeData(32).toInt())); - sl.append(QString("e$healthprob %1").arg(schemeData(33).toInt())); - sl.append(QString("e$hcaseamount %1").arg(schemeData(34).toInt())); - sl.append(QString("e$waterrise %1").arg(schemeData(35).toInt())); - sl.append(QString("e$healthdec %1").arg(schemeData(36).toInt())); - sl.append(QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter())); - sl.append(QString("e$mapgen %1").arg(pMapContainer->get_mapgen())); - sl.append(QString("e$maze_size %1").arg(pMapContainer->get_maze_size())); + QList bcfg; + int mapgen = pMapContainer->get_mapgen(); + + bcfg << QString("eseed " + pMapContainer->getCurrentSeed()).toUtf8(); + bcfg << QString("e$gmflags %1").arg(getGameFlags()).toUtf8(); + bcfg << QString("e$damagepct %1").arg(schemeData(24).toInt()).toUtf8(); + bcfg << QString("e$turntime %1").arg(schemeData(25).toInt() * 1000).toUtf8(); + bcfg << QString("e$sd_turns %1").arg(schemeData(27).toInt()).toUtf8(); + bcfg << QString("e$casefreq %1").arg(schemeData(28).toInt()).toUtf8(); + bcfg << QString("e$minestime %1").arg(schemeData(29).toInt() * 1000).toUtf8(); + bcfg << QString("e$minesnum %1").arg(schemeData(30).toInt()).toUtf8(); + bcfg << QString("e$minedudpct %1").arg(schemeData(31).toInt()).toUtf8(); + bcfg << QString("e$explosives %1").arg(schemeData(32).toInt()).toUtf8(); + bcfg << QString("e$healthprob %1").arg(schemeData(33).toInt()).toUtf8(); + bcfg << QString("e$hcaseamount %1").arg(schemeData(34).toInt()).toUtf8(); + bcfg << QString("e$waterrise %1").arg(schemeData(35).toInt()).toUtf8(); + bcfg << QString("e$healthdec %1").arg(schemeData(36).toInt()).toUtf8(); + bcfg << QString("e$ropepct %1").arg(schemeData(37).toInt()).toUtf8(); + bcfg << QString("e$template_filter %1").arg(pMapContainer->getTemplateFilter()).toUtf8(); + bcfg << QString("e$mapgen %1").arg(mapgen).toUtf8(); + + switch (mapgen) + { + case MAPGEN_MAZE: + bcfg << QString("e$maze_size %1").arg(pMapContainer->get_maze_size()).toUtf8(); + break; + + case MAPGEN_DRAWN: + { + QByteArray data = pMapContainer->getDrawnMapData(); + while(data.size() > 0) + { + QByteArray tmp = data; + tmp.truncate(200); + tmp.prepend("edraw "); + bcfg << tmp; + data.remove(0, 200); + } + break; + } + default: ; + } QString currentMap = pMapContainer->getCurrentMap(); if (currentMap.size() > 0) { - sl.append("emap " + currentMap); + bcfg << QString("emap " + currentMap).toUtf8(); if(pMapContainer->getCurrentIsMission()) - sl.append(QString("escript Maps/%1/map.lua") - .arg(currentMap)); + bcfg << QString("escript Maps/%1/map.lua").arg(currentMap).toUtf8(); + } + bcfg << QString("etheme " + pMapContainer->getCurrentTheme()).toUtf8(); + + if (Scripts->currentIndex() > 0) + { + bcfg << QString("escript Scripts/Multiplayer/%1.lua").arg(Scripts->itemData(Scripts->currentIndex()).toList()[0].toString()).toUtf8(); } - sl.append("etheme " + pMapContainer->getCurrentTheme()); - return sl; + + QByteArray result; + + foreach(QByteArray ba, bcfg) + HWProto::addByteArrayToBuffer(result, ba); + + return result; } void GameCFGWidget::setNetAmmo(const QString& name, const QString& ammo) @@ -220,6 +310,7 @@ themeChanged(pMapContainer->getCurrentTheme()); schemeChanged(GameSchemes->currentIndex()); + scriptChanged(Scripts->currentIndex()); mapgenChanged(pMapContainer->get_mapgen()); maze_sizeChanged(pMapContainer->get_maze_size()); @@ -241,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") { @@ -259,6 +353,14 @@ pMapContainer->setMaze_size(value.toUInt()); return; } + if (param == "SCRIPT") { + Scripts->setCurrentIndex(Scripts->findText(value)); + return; + } + if (param == "DRAWNMAP") { + pMapContainer->setDrawnMapData(qUncompress(QByteArray::fromBase64(slValue[0].toLatin1()))); + return; + } } if (slValue.size() == 2) @@ -279,32 +381,54 @@ "AMMO", QStringList() << WeaponsName->itemText(index) << WeaponsName->itemData(index).toString() ); - if (bindEntries->isChecked() == true) { - QString weapName = WeaponsName->itemText(index); - for (int i = 0; i < GameSchemes->count(); i++) { - QString schemeName = GameSchemes->itemText(i); - int res = QString::compare(weapName, schemeName, Qt::CaseSensitive); - if (0 == res) { - GameSchemes->setCurrentIndex(i); - break; - } - } - } } } void GameCFGWidget::mapChanged(const QString & value) { - if(pMapContainer->getCurrentIsMission()) + if(isEnabled() && pMapContainer->getCurrentIsMission()) { - GameSchemes->setEnabled(false); - WeaponsName->setEnabled(false); - bindEntries->setEnabled(false); - GameSchemes->setCurrentIndex(GameSchemes->findText("Default")); - WeaponsName->setCurrentIndex(WeaponsName->findText("Default")); + Scripts->setEnabled(false); + Scripts->setCurrentIndex(0); + + if (pMapContainer->getCurrentScheme() == "locked") + { + GameSchemes->setEnabled(false); + GameSchemes->setCurrentIndex(GameSchemes->findText("Default")); + } + else + { + GameSchemes->setEnabled(true); + int num = GameSchemes->findText(pMapContainer->getCurrentScheme()); + if (num != -1) + GameSchemes->setCurrentIndex(num); + else + GameSchemes->setCurrentIndex(GameSchemes->findText("Default")); + } + + if (pMapContainer->getCurrentWeapons() == "locked") + { + WeaponsName->setEnabled(false); + WeaponsName->setCurrentIndex(WeaponsName->findText("Default")); + } + else + { + WeaponsName->setEnabled(true); + int num = WeaponsName->findText(pMapContainer->getCurrentWeapons()); + if (num != -1) + WeaponsName->setCurrentIndex(num); + else + WeaponsName->setCurrentIndex(WeaponsName->findText("Default")); + } + + if (pMapContainer->getCurrentScheme() != "locked" && pMapContainer->getCurrentWeapons() != "locked") + bindEntries->setEnabled(true); + else + bindEntries->setEnabled(false); } else { + Scripts->setEnabled(true); GameSchemes->setEnabled(true); WeaponsName->setEnabled(true); bindEntries->setEnabled(true); @@ -337,19 +461,71 @@ emit paramChanged("SCHEME", sl); - if (bindEntries->isChecked() == true) { + if (isEnabled() && bindEntries->isEnabled() && bindEntries->isChecked()) { QString schemeName = GameSchemes->itemText(index); for (int i = 0; i < WeaponsName->count(); i++) { QString weapName = WeaponsName->itemText(i); int res = QString::compare(weapName, schemeName, Qt::CaseSensitive); if (0 == res) { WeaponsName->setCurrentIndex(i); + emit ammoChanged(i); break; } } } } +void GameCFGWidget::scriptChanged(int index) +{ + if(isEnabled() && index > 0) + { + QString scheme = Scripts->itemData(Scripts->currentIndex()).toList()[1].toString(); + QString weapons = Scripts->itemData(Scripts->currentIndex()).toList()[2].toString(); + + if (scheme == "locked") + { + GameSchemes->setEnabled(false); + GameSchemes->setCurrentIndex(GameSchemes->findText("Default")); + } + else + { + GameSchemes->setEnabled(true); + int num = GameSchemes->findText(scheme); + if (num != -1) + GameSchemes->setCurrentIndex(num); + else + GameSchemes->setCurrentIndex(GameSchemes->findText("Default")); + } + + if (weapons == "locked") + { + WeaponsName->setEnabled(false); + WeaponsName->setCurrentIndex(WeaponsName->findText("Default")); + } + else + { + WeaponsName->setEnabled(true); + int num = WeaponsName->findText(weapons); + if (num != -1) + WeaponsName->setCurrentIndex(num); + else + WeaponsName->setCurrentIndex(WeaponsName->findText("Default")); + } + + if (scheme != "locked" && weapons != "locked") + bindEntries->setEnabled(true); + else + bindEntries->setEnabled(false); + } + else + { + GameSchemes->setEnabled(true); + WeaponsName->setEnabled(true); + bindEntries->setEnabled(true); + } + emit paramChanged("SCRIPT", QStringList(Scripts->itemText(index))); +} + void GameCFGWidget::mapgenChanged(MapGenerator m) { emit paramChanged("MAPGEN", QStringList(QString::number(m))); @@ -364,3 +540,8 @@ { schemeChanged(GameSchemes->currentIndex()); } + +void GameCFGWidget::onDrawnMapChanged(const QByteArray & data) +{ + emit paramChanged("DRAWNMAP", QStringList(qCompress(data, 9).toBase64())); +} diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/gamecfgwidget.h --- a/QTfrontend/gamecfgwidget.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/gamecfgwidget.h Tue Jan 04 12:53:46 2011 +0100 @@ -36,14 +36,16 @@ Q_OBJECT public: - GameCFGWidget(QWidget* parent, bool externalControl=false); + GameCFGWidget(QWidget* parent); quint32 getGameFlags() const; quint32 getInitHealth() const; - QStringList getFullConfig() const; + QByteArray getFullConfig() const; + QComboBox * Scripts; QComboBox * GameSchemes; QComboBox * WeaponsName; HWMapContainer* pMapContainer; QTableView * tv; + QVariant schemeData(int column) const; public slots: void setParam(const QString & param, const QStringList & value); @@ -52,8 +54,9 @@ signals: void paramChanged(const QString & param, const QStringList & value); - void goToSchemes(); - void goToWeapons(const QString & name); + void goToSchemes(int); + void goToWeapons(int); + void goToDrawMap(); private slots: void ammoChanged(int index); @@ -62,9 +65,12 @@ void seedChanged(const QString &); void themeChanged(const QString &); void schemeChanged(int); + void scriptChanged(int); + void jumpToSchemes(); void jumpToWeapons(); void mapgenChanged(MapGenerator m); void maze_sizeChanged(int s); + void onDrawnMapChanged(const QByteArray & data); private: QGridLayout mainLayout; @@ -74,7 +80,6 @@ void setNetAmmo(const QString& name, const QString& ammo); - QVariant schemeData(int column) const; }; #endif // GAMECONFIGWIDGET_H diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/gameuiconfig.cpp --- a/QTfrontend/gameuiconfig.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/gameuiconfig.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -185,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 @@ -206,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: diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hats.cpp --- a/QTfrontend/hats.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hats.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -77,6 +77,10 @@ QVariant HatsModel::headerData(int section, Qt::Orientation orientation, int role) const { + Q_UNUSED(section); + Q_UNUSED(orientation); + Q_UNUSED(role); + return QVariant(); } diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hedgehogerWidget.cpp --- a/QTfrontend/hedgehogerWidget.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hedgehogerWidget.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -20,8 +20,8 @@ #include "frameTeam.h" -CHedgehogerWidget::CHedgehogerWidget(const QImage& im, QWidget * parent) : - ItemNum(im, parent, 1) +CHedgehogerWidget::CHedgehogerWidget(const QImage& im, const QImage& img, QWidget * parent) : + ItemNum(im, img, parent, 1) { // TODO: maxHedgehogsPerGame doesn't reset properly and won't match map limits for now /*if(parent) { diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hedgehogerWidget.h --- a/QTfrontend/hedgehogerWidget.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hedgehogerWidget.h Tue Jan 04 12:53:46 2011 +0100 @@ -28,7 +28,7 @@ Q_OBJECT public: - CHedgehogerWidget(const QImage& im, QWidget * parent); + CHedgehogerWidget(const QImage& im, const QImage& img, QWidget * parent); virtual ~CHedgehogerWidget(); unsigned char getHedgehogsNum() const; void setHHNum (unsigned int num); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hedgewars.qrc --- a/QTfrontend/hedgewars.qrc Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hedgewars.qrc Tue Jan 04 12:53:46 2011 +0100 @@ -2,8 +2,15 @@ ../share/hedgewars/Data/Graphics/AmmoMenu/Ammos.png res/hh25x25.png + res/hh25x25grey.png res/ammopic.png + res/ammopicgrey.png + res/ammopicbox.png + res/ammopicboxgrey.png + res/ammopicdelay.png + res/ammopicdelaygrey.png res/infinity.png + res/infinitygrey.png res/botlevels/0.png res/botlevels/1.png res/botlevels/2.png @@ -80,6 +87,7 @@ res/iconTime.png res/iconMine.png res/iconDud.png + res/iconRope.png res/dice.png res/Star.png res/file_save.png @@ -93,8 +101,6 @@ res/chat_default_off.png res/chat_ignore_off.png res/chat_friend_off.png - res/ammopicbox.png - res/ammopicdelay.png res/addfriend.png res/remfriend.png res/ignore.png @@ -102,6 +108,8 @@ res/follow.png res/info.png res/kick.png + res/lock.png + res/unlock.png res/StatsMedal1.png res/StatsMedal2.png res/StatsMedal3.png diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hwconsts.cpp.in --- a/QTfrontend/hwconsts.cpp.in Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hwconsts.cpp.in Tue Jan 04 12:53:46 2011 +0100 @@ -29,6 +29,7 @@ QStringList * Themes; QStringList * mapList; +QStringList * scriptList; bool custom_config = false; bool custom_data = false; @@ -36,10 +37,10 @@ int cMaxTeams = 6; QString * cDefaultAmmoStore = new QString( - "93919294221991210322351110012010000002111101010111" - "04050405416006555465544647765766666661555101011154" - "00000000000002055000000400070040000000002000000006" - "13111103121111111231141111111111111112111111011111" + "939192942219912103223511100120100000021111010101112" + "040504054160065554655446477657666666615551010111541" + "000000000000020550000004000700400000000020000000060" + "131111031211111112311411111111111111121111110111112" ); int cAmmoNumber = cDefaultAmmoStore->size() / 4; @@ -48,40 +49,40 @@ << qMakePair(QString("Default"), *cDefaultAmmoStore) << qMakePair(QString("Crazy"), QString( // TODO: Remove Piano's unlimited uses! - "99999999999999999929999999999999992999999999099999" - "11111101111111111111111111111111111111111111011111" - "00000000000000000000000000000000000000000000000000" - "13111103121111111231141111111111111112111101011111" + "999999999999999999299999999999999929999999990999999" + "111111011111111111111111111111111111111111110111111" + "000000000000000000000000000000000000000000000000000" + "131111031211111112311411111111111111121111010111111" )) << qMakePair(QString("Pro Mode"), QString( - "90900090000000000000090000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000002055000000400070040000000002000000000" - "11111111111111111111111111111111111111111001011111" + "909000900000000000000900000000000000000000000000000" + "000000000000000000000000000000000000000000000000000" + "000000000000020550000004000700400000000020000000000" + "111111111111111111111111111111111111111110010111111" )) << qMakePair(QString("Shoppa"), QString( - "00000099000000000000000000000000000000000000000000" - "44444100442444022101121212224220000000020004000100" - "00000000000000000000000000000000000000000000000000" - "11111111111111111111111111111111111111111011011111" + "000000990000000000000000000000000000000000000000000" + "444441004424440221011212122242200000000200040001001" + "000000000000000000000000000000000000000000000000000" + "111111111111111111111111111111111111111110110111111" )) << qMakePair(QString("Clean Slate"),QString( - "10100090000100000110000000000000000000000000000010" - "04050405416006555465544647765766666661555101011154" - "00000000000000000000000000000000000000000000000000" - "13111103121111111231141111111111111112111111011111" + "101000900001000001100000000000000000000000000000100" + "040504054160065554655446477657666666615551010111541" + "000000000000000000000000000000000000000000000000000" + "131111031211111112311411111111111111121111110111111" )) << qMakePair(QString("Minefield"), QString( - "00000099000900000003000000000000000000000000000000" - "00000000000000000000000000000000000000000000000000" - "00000000000002055000000400070040000000002000000006" - "11111111111111111111111111111111111111111111011111" + "000000990009000000030000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000" + "000000000000020550000004000700400000000020000000060" + "111111111111111111111111111111111111111111110111111" )) << qMakePair(QString("Thinking with Portals"), QString( - "90000090020000000021000000000000001100000900000000" - "04050405416006555465544647765766666661555101011154" - "00000000000002055000000400070040000000002000000006" - "13111103121111111231141111111111111112111111011111" + "900000900200000000210000000000000011000009000000000" + "040504054160065554655446477657666666615551010111541" + "000000000000020550000004000700400000000020000000060" + "131111031211111112311411111111111111121111110111111" )); QColor *colors[] = { diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hwconsts.h --- a/QTfrontend/hwconsts.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hwconsts.h Tue Jan 04 12:53:46 2011 +0100 @@ -38,6 +38,7 @@ extern QStringList * Themes; extern QStringList * mapList; +extern QStringList * scriptList; extern QString * cDefaultAmmoStore; extern int cAmmoNumber; diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hwform.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include "hwform.h" #include "game.h" @@ -56,6 +57,7 @@ #include "ammoSchemeModel.h" #include "bgwidget.h" #include "xfire.h" +#include "drawmapwidget.h" #ifdef __APPLE__ #include "CocoaInitializer.h" @@ -77,13 +79,14 @@ #ifdef USE_XFIRE xfire_init(); #endif + game = NULL; gameSettings = new QSettings(cfgdir->absolutePath() + "/hedgewars.ini", QSettings::IniFormat); frontendEffects = gameSettings->value("frontend/effects", true).toBool(); playerHash = QString(QCryptographicHash::hash(gameSettings->value("net/nick","").toString().toLatin1(), QCryptographicHash::Md5).toHex()); ui.setupUi(this); setMinimumSize(760, 580); - setFocusPolicy(Qt::StrongFocus); + //setFocusPolicy(Qt::StrongFocus); CustomizePalettes(); ui.pageOptions->CBResolution->addItems(sdli.getResolutions()); @@ -107,13 +110,23 @@ UpdateCampaignPage(0); UpdateWeapons(); + pageSwitchMapper = new QSignalMapper(this); + connect(pageSwitchMapper, SIGNAL(mapped(int)), this, SLOT(GoToPage(int))); + connect(config, SIGNAL(frontendFullscreen(bool)), this, SLOT(onFrontendFullscreen(bool))); onFrontendFullscreen(config->isFrontendFullscreen()); - connect(ui.pageMain->BtnSinglePlayer, SIGNAL(clicked()), this, SLOT(GoToSinglePlayer())); - connect(ui.pageMain->BtnSetup, SIGNAL(clicked()), this, SLOT(GoToSetup())); - connect(ui.pageMain->BtnNet, SIGNAL(clicked()), this, SLOT(GoToNetType())); - connect(ui.pageMain->BtnInfo, SIGNAL(clicked()), this, SLOT(GoToInfo())); + connect(ui.pageMain->BtnSinglePlayer, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMain->BtnSinglePlayer, ID_PAGE_SINGLEPLAYER); + + connect(ui.pageMain->BtnSetup, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMain->BtnSetup, ID_PAGE_SETUP); + + connect(ui.pageMain->BtnNet, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMain->BtnNet, ID_PAGE_NETTYPE); + connect(ui.pageMain->BtnInfo, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMain->BtnInfo, ID_PAGE_INFO); + connect(ui.pageMain->BtnExit, SIGNAL(pressed()), this, SLOT(btnExitPressed())); connect(ui.pageMain->BtnExit, SIGNAL(clicked()), this, SLOT(btnExitClicked())); @@ -127,9 +140,12 @@ connect(ui.pageMultiplayer->BtnStartMPGame, SIGNAL(clicked()), this, SLOT(StartMPGame())); connect(ui.pageMultiplayer->teamsSelect, SIGNAL(setEnabledGameStart(bool)), ui.pageMultiplayer->BtnStartMPGame, SLOT(setEnabled(bool))); - connect(ui.pageMultiplayer->teamsSelect, SIGNAL(SetupClicked()), this, SLOT(IntermediateSetup())); - connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToSchemes()), this, SLOT(GoToSchemes())); - connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToWeapons(const QString &)), this, SLOT(GoToSelectWeaponSet(const QString &))); + connect(ui.pageMultiplayer, SIGNAL(SetupClicked()), this, SLOT(IntermediateSetup())); + connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToSchemes(int)), this, SLOT(GoToScheme(int))); + connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToWeapons(int)), this, SLOT(GoToSelectWeaponSet(int))); + connect(ui.pageMultiplayer->gameCFG, SIGNAL(goToDrawMap()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageMultiplayer->gameCFG, ID_PAGE_DRAWMAP); + connect(ui.pagePlayDemo->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pagePlayDemo->BtnPlayDemo, SIGNAL(clicked()), this, SLOT(PlayDemo())); @@ -146,12 +162,18 @@ #endif connect(ui.pageOptions->WeaponEdit, SIGNAL(clicked()), this, SLOT(GoToSelectWeapon())); - connect(ui.pageOptions->WeaponsButt, SIGNAL(clicked()), this, SLOT(GoToSelectNewWeapon())); + connect(ui.pageOptions->WeaponNew, SIGNAL(clicked()), this, SLOT(GoToSelectNewWeapon())); + connect(ui.pageOptions->WeaponDelete, SIGNAL(clicked()), this, SLOT(DeleteWeaponSet())); + connect(ui.pageOptions->SchemeEdit, SIGNAL(clicked()), this, SLOT(GoToEditScheme())); + connect(ui.pageOptions->SchemeNew, SIGNAL(clicked()), this, SLOT(GoToNewScheme())); + connect(ui.pageOptions->SchemeDelete, SIGNAL(clicked()), this, SLOT(DeleteScheme())); connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsChanged()), this, SLOT(UpdateWeapons())); connect(ui.pageNet->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pageNet->BtnSpecifyServer, SIGNAL(clicked()), this, SLOT(NetConnect())); - connect(ui.pageNet->BtnNetSvrStart, SIGNAL(clicked()), this, SLOT(GoToNetServer())); + connect(ui.pageNet->BtnNetSvrStart, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageNet->BtnNetSvrStart, ID_PAGE_NETSERVER); + connect(ui.pageNet, SIGNAL(connectClicked(const QString &, quint16)), this, SLOT(NetConnectServer(const QString &, quint16))); connect(ui.pageNetServer->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); @@ -162,21 +184,30 @@ ui.pageNetGame->BtnGo, SLOT(setEnabled(bool))); connect(ui.pageNetGame->pNetTeamsWidget, SIGNAL(setEnabledGameStart(bool)), ui.pageNetGame->BtnStart, SLOT(setEnabled(bool))); - connect(ui.pageNetGame->pNetTeamsWidget, SIGNAL(SetupClicked()), this, SLOT(IntermediateSetup())); - connect(ui.pageNetGame->pGameCFG, SIGNAL(goToSchemes()), this, SLOT(GoToSchemes())); - connect(ui.pageNetGame->pGameCFG, SIGNAL(goToWeapons(const QString &)), this, SLOT(GoToSelectWeaponSet(const QString &))); + connect(ui.pageNetGame, SIGNAL(SetupClicked()), this, SLOT(IntermediateSetup())); + connect(ui.pageNetGame->pGameCFG, SIGNAL(goToSchemes(int)), this, SLOT(GoToScheme(int))); + connect(ui.pageNetGame->pGameCFG, SIGNAL(goToWeapons(int)), this, SLOT(GoToSelectWeaponSet(int))); + connect(ui.pageNetGame->pGameCFG, SIGNAL(goToDrawMap()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageNetGame->pGameCFG, ID_PAGE_DRAWMAP); connect(ui.pageRoomsList->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); - connect(ui.pageRoomsList->BtnAdmin, SIGNAL(clicked()), this, SLOT(GoToAdmin())); + connect(ui.pageRoomsList->BtnAdmin, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageRoomsList->BtnAdmin, ID_PAGE_ADMIN); connect(ui.pageInfo->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pageGameStats->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); connect(ui.pageSinglePlayer->BtnSimpleGamePage, SIGNAL(clicked()), this, SLOT(SimpleGame())); - connect(ui.pageSinglePlayer->BtnTrainPage, SIGNAL(clicked()), this, SLOT(GoToTraining())); - connect(ui.pageSinglePlayer->BtnCampaignPage, SIGNAL(clicked()), this, SLOT(GoToCampaign())); - connect(ui.pageSinglePlayer->BtnMultiplayer, SIGNAL(clicked()), this, SLOT(GoToMultiplayer())); + connect(ui.pageSinglePlayer->BtnTrainPage, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageSinglePlayer->BtnTrainPage, ID_PAGE_TRAINING); + + connect(ui.pageSinglePlayer->BtnCampaignPage, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageSinglePlayer->BtnCampaignPage, ID_PAGE_CAMPAIGN); + + connect(ui.pageSinglePlayer->BtnMultiplayer, SIGNAL(clicked()), pageSwitchMapper, SLOT(map())); + pageSwitchMapper->setMapping(ui.pageSinglePlayer->BtnMultiplayer, ID_PAGE_MULTIPLAYER); + connect(ui.pageSinglePlayer->BtnLoad, SIGNAL(clicked()), this, SLOT(GoToSaves())); connect(ui.pageSinglePlayer->BtnDemos, SIGNAL(clicked()), this, SLOT(GoToDemos())); connect(ui.pageSinglePlayer->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); @@ -194,8 +225,8 @@ ui.pageSelectWeapon->pWeapons, SLOT(deleteWeaponsName())); // executed first connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsDeleted()), this, SLOT(UpdateWeapons())); // executed second - connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsDeleted()), - this, SLOT(GoBack())); // executed third + //connect(ui.pageSelectWeapon->pWeapons, SIGNAL(weaponsDeleted()), + // this, SLOT(GoBack())); // executed third connect(ui.pageScheme->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); @@ -205,10 +236,13 @@ connect(ui.pageNetType->BtnLAN, SIGNAL(clicked()), this, SLOT(GoToNet())); connect(ui.pageNetType->BtnOfficialServer, SIGNAL(clicked()), this, SLOT(NetConnectOfficialServer())); + connect(ui.pageDrawMap->BtnBack, SIGNAL(clicked()), this, SLOT(GoBack())); + ammoSchemeModel = new AmmoSchemeModel(this, cfgdir->absolutePath() + "/schemes.ini"); ui.pageScheme->setModel(ammoSchemeModel); ui.pageMultiplayer->gameCFG->GameSchemes->setModel(ammoSchemeModel); + ui.pageOptions->SchemesName->setModel(ammoSchemeModel); wBackground = NULL; if (config->isFrontendEffects()) { @@ -274,11 +308,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() { @@ -299,6 +335,7 @@ combos.push_back(ui.pageOptions->WeaponsName); combos.push_back(ui.pageMultiplayer->gameCFG->WeaponsName); combos.push_back(ui.pageNetGame->pGameCFG->WeaponsName); + combos.push_back(ui.pageSelectWeapon->selectWeaponSet); QStringList names = ui.pageSelectWeapon->pWeapons->getWeaponNames(); @@ -336,59 +373,24 @@ ui.pageCampaign->CBTeam->addItems(teamslist); } -void HWForm::GoToMain() -{ - GoToPage(ID_PAGE_MAIN); -} - -void HWForm::GoToSinglePlayer() -{ - GoToPage(ID_PAGE_SINGLEPLAYER); -} - -void HWForm::GoToTraining() -{ - GoToPage(ID_PAGE_TRAINING); -} - -void HWForm::GoToCampaign() -{ - GoToPage(ID_PAGE_CAMPAIGN); -} - -void HWForm::GoToSetup() -{ - GoToPage(ID_PAGE_SETUP); -} - void HWForm::GoToSelectNewWeapon() { - ui.pageSelectWeapon->pWeapons->setWeaponsName(tr("new")); + ui.pageSelectWeapon->pWeapons->newWeaponsName(); GoToPage(ID_PAGE_SELECTWEAPON); } void HWForm::GoToSelectWeapon() { - ui.pageSelectWeapon->pWeapons->setWeaponsName(ui.pageOptions->WeaponsName->currentText()); + ui.pageSelectWeapon->selectWeaponSet->setCurrentIndex(ui.pageOptions->WeaponsName->currentIndex()); GoToPage(ID_PAGE_SELECTWEAPON); } -void HWForm::GoToSelectWeaponSet(const QString & name) +void HWForm::GoToSelectWeaponSet(int index) { - ui.pageSelectWeapon->pWeapons->setWeaponsName(name); + ui.pageSelectWeapon->selectWeaponSet->setCurrentIndex(index); GoToPage(ID_PAGE_SELECTWEAPON); } -void HWForm::GoToInfo() -{ - GoToPage(ID_PAGE_INFO); -} - -void HWForm::GoToMultiplayer() -{ - GoToPage(ID_PAGE_MULTIPLAYER); -} - void HWForm::GoToSaves() { ui.pagePlayDemo->FillFromDir(PagePlayDemo::RT_Save); @@ -410,24 +412,22 @@ GoToPage(ID_PAGE_NET); } -void HWForm::GoToNetType() +void HWForm::GoToScheme(int index) { - GoToPage(ID_PAGE_NETTYPE); -} - -void HWForm::GoToNetServer() -{ - GoToPage(ID_PAGE_NETSERVER); -} - -void HWForm::GoToSchemes() -{ + ui.pageScheme->selectScheme->setCurrentIndex(index); GoToPage(ID_PAGE_SCHEME); } -void HWForm::GoToAdmin() +void HWForm::GoToNewScheme() { - GoToPage(ID_PAGE_ADMIN); + ui.pageScheme->newRow(); + GoToPage(ID_PAGE_SCHEME); +} + +void HWForm::GoToEditScheme() +{ + ui.pageScheme->selectScheme->setCurrentIndex(ui.pageOptions->SchemesName->currentIndex()); + GoToPage(ID_PAGE_SCHEME); } void HWForm::OnPageShown(quint8 id, quint8 lastid) @@ -435,6 +435,24 @@ #ifdef USE_XFIRE updateXfire(); #endif + if(id == ID_PAGE_DRAWMAP) + { + DrawMapScene * scene; + if(lastid == ID_PAGE_MULTIPLAYER) + scene = ui.pageMultiplayer->gameCFG->pMapContainer->getDrawMapScene(); + else + scene = ui.pageNetGame->pGameCFG->pMapContainer->getDrawMapScene(); + + ui.pageDrawMap->drawMapWidget->setScene(scene); + } + if(lastid == ID_PAGE_DRAWMAP) + { + if(id == ID_PAGE_MULTIPLAYER) + ui.pageMultiplayer->gameCFG->pMapContainer->mapDrawingFinished(); + else + ui.pageNetGame->pGameCFG->pMapContainer->mapDrawingFinished(); + } + if (id == ID_PAGE_MULTIPLAYER || id == ID_PAGE_NETGAME) { QStringList tmNames = config->GetTeamsList(); TeamSelWidget* curTeamSelWidget; @@ -457,7 +475,7 @@ teamsList.push_back(team); } - if(lastid == ID_PAGE_SETUP) { // _TEAM + if(lastid == ID_PAGE_SETUP || lastid == ID_PAGE_DRAWMAP) { // _TEAM if (editedTeam) { curTeamSelWidget->addTeam(*editedTeam); } @@ -490,13 +508,19 @@ if(id == ID_PAGE_NETGAME) // joining a room ui.pageNetGame->pChatWidget->loadLists(ui.pageOptions->editNetNick->text()); - else if(id == ID_PAGE_ROOMSLIST) // joining the lobby +// joining the lobby + else if(id == ID_PAGE_ROOMSLIST) { + if ( hwnet && game && game->gameState == gsStarted) { // abnormal exit - kick or room destruction - send kills. + game->netSuspend = true; + game->KillAllTeams(); + } ui.pageRoomsList->chatWidget->loadLists(ui.pageOptions->editNetNick->text()); + } } -void HWForm::GoToPage(quint8 id) +void HWForm::GoToPage(int id) { - quint8 lastid = ui.Pages->currentIndex(); + int lastid = ui.Pages->currentIndex(); PagesStack.push(ui.Pages->currentIndex()); OnPageShown(id, lastid); ui.Pages->setCurrentIndex(id); @@ -504,8 +528,8 @@ void HWForm::GoBack() { - quint8 id = PagesStack.isEmpty() ? ID_PAGE_MAIN : PagesStack.pop(); - quint8 curid = ui.Pages->currentIndex(); + int id = PagesStack.isEmpty() ? ID_PAGE_MAIN : PagesStack.pop(); + int curid = ui.Pages->currentIndex(); ui.Pages->setCurrentIndex(id); OnPageShown(id, curid); @@ -521,6 +545,9 @@ GoBack(); if (curid == ID_PAGE_ROOMSLIST) NetDisconnect(); + if (curid == ID_PAGE_NETGAME) 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(); if (curid == ID_PAGE_SCHEME) ammoSchemeModel->Save(); @@ -588,11 +615,15 @@ void HWForm::DeleteTeam() { - editedTeam = new HWTeam(ui.pageOptions->CBTeamName->currentText()); - editedTeam->DeleteFile(); + QMessageBox reallyDelete(QMessageBox::Question, QMessageBox::tr("Teams"), QMessageBox::tr("Really delete this team?"), QMessageBox::Ok | QMessageBox::Cancel); - // Remove from lists - ui.pageOptions->CBTeamName->removeItem(ui.pageOptions->CBTeamName->currentIndex()); + if (reallyDelete.exec() == QMessageBox::Ok) { + editedTeam = new HWTeam(ui.pageOptions->CBTeamName->currentText()); + editedTeam->DeleteFile(); + + // Remove from lists + ui.pageOptions->CBTeamName->removeItem(ui.pageOptions->CBTeamName->currentIndex()); + } } void HWForm::RandomNames() @@ -626,6 +657,23 @@ GoBack(); } +void HWForm::DeleteScheme() +{ + ui.pageScheme->selectScheme->setCurrentIndex(ui.pageOptions->SchemesName->currentIndex()); + if (ui.pageOptions->SchemesName->currentIndex() < ammoSchemeModel->numberOfDefaultSchemes) { + 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(); + } +} + +void HWForm::DeleteWeaponSet() +{ + ui.pageSelectWeapon->selectWeaponSet->setCurrentIndex(ui.pageOptions->WeaponsName->currentIndex()); + ui.pageSelectWeapon->pWeapons->deleteWeaponsName(); +} + void HWForm::SimpleGame() { CreateGame(0, 0, *cDefaultAmmoStore); @@ -678,7 +726,7 @@ connect(hwnet, SIGNAL(EnteredGame()), this, SLOT(NetGameEnter())); connect(hwnet, SIGNAL(LeftRoom()), this, SLOT(NetLeftRoom())); connect(hwnet, SIGNAL(AddNetTeam(const HWTeam&)), this, SLOT(AddNetTeam(const HWTeam&))); - connect(ui.pageNetGame->BtnBack, SIGNAL(clicked()), hwnet, SLOT(partRoom())); + //connect(ui.pageNetGame->BtnBack, SIGNAL(clicked()), hwnet, SLOT(partRoom())); // rooms list page stuff connect(hwnet, SIGNAL(roomsList(const QStringList&)), @@ -830,7 +878,6 @@ void HWForm::NetDisconnect() { - //qDebug("NetDisconnect"); if(hwnet) { hwnet->Disconnect(); delete hwnet; @@ -853,8 +900,9 @@ { if(pnetserver) return; // we have server - let it care of all things if (hwnet) { - hwnet->deleteLater(); + HWNewNet * tmp = hwnet; hwnet = 0; + tmp->deleteLater(); QMessageBox::warning(this, QMessageBox::tr("Network"), QMessageBox::tr("Connection to server is lost")); @@ -892,11 +940,12 @@ void HWForm::GameStateChanged(GameState gameState) { + quint8 id = ui.Pages->currentIndex(); switch(gameState) { case gsStarted: { Music(false); if (wBackground) wBackground->stopAnimation(); - GoToPage(ID_PAGE_INGAME); + if (!hwnet || (!hwnet->isRoomChief() || !hwnet->isInRoom())) GoToPage(ID_PAGE_INGAME); ui.pageGameStats->clear(); if (pRegisterServer) { @@ -910,19 +959,23 @@ case gsFinished: { //setVisible(true); setFocusPolicy(Qt::StrongFocus); - GoBack(); + if (id == ID_PAGE_INGAME) GoBack(); Music(ui.pageOptions->CBEnableFrontendMusic->isChecked()); if (wBackground) wBackground->startAnimation(); GoToPage(ID_PAGE_GAMESTATS); - if (hwnet) hwnet->gameFinished(); + if (hwnet && (!game || !game->netSuspend)) hwnet->gameFinished(); + if (game) game->netSuspend = false; break; } default: { //setVisible(true); setFocusPolicy(Qt::StrongFocus); quint8 id = ui.Pages->currentIndex(); - if (id == ID_PAGE_INGAME) { - GoBack(); + if (id == ID_PAGE_INGAME || +// was room chief and the game was aborted + (hwnet && hwnet->isRoomChief() && hwnet->isInRoom() && + (gameState == gsInterrupted || gameState == gsStopped || gameState == gsDestroyed))) { + if (id == ID_PAGE_INGAME) GoBack(); Music(ui.pageOptions->CBEnableFrontendMusic->isChecked()); if (wBackground) wBackground->startAnimation(); if (hwnet) hwnet->gameFinished(); @@ -1089,7 +1142,7 @@ void HWForm::NetLeftRoom() { - if (ui.Pages->currentIndex() == ID_PAGE_NETGAME) + if (ui.Pages->currentIndex() == ID_PAGE_NETGAME || ui.Pages->currentIndex() == ID_PAGE_INGAME) GoBack(); else qWarning("Left room while not in room"); @@ -1107,6 +1160,8 @@ void HWForm::UpdateCampaignPage(int index) { + Q_UNUSED(index); + HWTeam team(ui.pageCampaign->CBTeam->currentText()); ui.pageCampaign->CBSelect->clear(); @@ -1117,7 +1172,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 0ddb100fea61 -r f924be23ffb4 QTfrontend/hwform.h --- a/QTfrontend/hwform.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hwform.h Tue Jan 04 12:53:46 2011 +0100 @@ -42,6 +42,7 @@ class QCloseEvent; class AmmoSchemeModel; class QSettings; +class QSignalMapper; extern bool frontendEffects; extern QString playerHash; @@ -59,24 +60,16 @@ void updateXfire(); private slots: - void GoToMain(); - void GoToSinglePlayer(); - void GoToSetup(); - void GoToMultiplayer(); void GoToSaves(); void GoToDemos(); void GoToNet(); - void GoToNetType(); - void GoToInfo(); - void GoToTraining(); - void GoToCampaign(); void GoToSelectWeapon(); - void GoToSelectWeaponSet(const QString & name); + void GoToSelectWeaponSet(int index); void GoToSelectNewWeapon(); - void GoToNetServer(); - void GoToSchemes(); - void GoToAdmin(); - void GoToPage(quint8 id); + void GoToScheme(int index); + void GoToEditScheme(); + void GoToNewScheme(); + void GoToPage(int id); void GoBack(); void AssociateFiles(); void btnExitPressed(); @@ -89,6 +82,8 @@ void RandomName(const int &i); void TeamSave(); void TeamDiscard(); + void DeleteScheme(); + void DeleteWeaponSet(); void SimpleGame(); void PlayDemo(); void StartTraining(); @@ -127,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, @@ -149,7 +144,8 @@ ID_PAGE_SCHEME = 16, ID_PAGE_ADMIN = 17, ID_PAGE_NETTYPE = 18, - ID_PAGE_CAMPAIGN = 19 + ID_PAGE_CAMPAIGN = 19, + ID_PAGE_DRAWMAP = 20 }; HWGame * game; HWNetServer* pnetserver; @@ -158,9 +154,10 @@ HWNewNet * hwnet; HWNamegen * namegen; AmmoSchemeModel * ammoSchemeModel; - QStack PagesStack; + QStack PagesStack; QTime eggTimer; BGWidget * wBackground; + QSignalMapper * pageSwitchMapper; #ifdef __APPLE__ InstallController * panel; diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hwmap.cpp --- a/QTfrontend/hwmap.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hwmap.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -27,12 +27,13 @@ { } -void HWMap::getImage(std::string seed, int filter, MapGenerator mapgen, int maze_size) +void HWMap::getImage(const QString & seed, int filter, MapGenerator mapgen, int maze_size, const QByteArray & drawMapData) { m_seed = seed; templateFilter = filter; m_mapgen = mapgen; m_maze_size = maze_size; + if(mapgen == MAPGEN_DRAWN) m_drawMapData = drawMapData; Start(); } @@ -59,9 +60,30 @@ void HWMap::SendToClientFirst() { - SendIPC(QString("eseed %1").arg(m_seed.c_str()).toLatin1()); - SendIPC(QString("e$template_filter %1").arg(templateFilter).toLatin1()); - SendIPC(QString("e$mapgen %1").arg(m_mapgen).toLatin1()); - SendIPC(QString("e$maze_size %1").arg(m_maze_size).toLatin1()); + SendIPC(QString("eseed %1").arg(m_seed).toUtf8()); + SendIPC(QString("e$template_filter %1").arg(templateFilter).toUtf8()); + SendIPC(QString("e$mapgen %1").arg(m_mapgen).toUtf8()); + + switch (m_mapgen) + { + case MAPGEN_MAZE: + SendIPC(QString("e$maze_size %1").arg(m_maze_size).toUtf8()); + break; + + case MAPGEN_DRAWN: + { + QByteArray data = m_drawMapData; + while(data.size() > 0) + { + QByteArray tmp = data; + tmp.truncate(200); + SendIPC("edraw " + tmp); + data.remove(0, 200); + } + break; + } + default: ; + } + SendIPC("!"); } diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/hwmap.h --- a/QTfrontend/hwmap.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/hwmap.h Tue Jan 04 12:53:46 2011 +0100 @@ -25,12 +25,12 @@ #include "tcpBase.h" -#include - enum MapGenerator { MAPGEN_REGULAR, MAPGEN_MAZE, + MAPGEN_DRAWN, + MAPGEN_MAP }; class HWMap : public TCPBase @@ -40,7 +40,7 @@ public: HWMap(); virtual ~HWMap(); - void getImage(std::string seed, int templateFilter, MapGenerator mapgen, int maze_size); + void getImage(const QString & seed, int templateFilter, MapGenerator mapgen, int maze_size, const QByteArray & drawMapData); protected: virtual QStringList setArguments(); @@ -52,10 +52,11 @@ void HHLimitReceived(int hhLimit); private: - std::string m_seed; + QString m_seed; int templateFilter; MapGenerator m_mapgen; int m_maze_size; + QByteArray m_drawMapData; private slots: }; diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/igbox.cpp --- a/QTfrontend/igbox.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/igbox.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -24,6 +24,7 @@ #include "igbox.h" IconedGroupBox::IconedGroupBox(QWidget * parent) + : QGroupBox(parent) { // Has issues with border-radius on children // setAttribute(Qt::WA_PaintOnScreen, true); @@ -56,6 +57,8 @@ void IconedGroupBox::paintEvent(QPaintEvent * event) { + Q_UNUSED(event); + QStylePainter painter(this); QStyleOptionGroupBox option; diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/itemNum.cpp --- a/QTfrontend/itemNum.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/itemNum.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -22,10 +22,11 @@ #include #include -ItemNum::ItemNum(const QImage& im, QWidget * parent, unsigned char min, unsigned char max) : - QFrame(parent), m_im(im), infinityState(false), nonInteractive(false), minItems(min), maxItems(max), +ItemNum::ItemNum(const QImage& im, const QImage& img, QWidget * parent, unsigned char min, unsigned char max) : + QFrame(parent), m_im(im), m_img(img), infinityState(false), nonInteractive(false), minItems(min), maxItems(max), numItems(min+2 >= max ? min : min+2) { + enabled = true; if(frontendEffects) setAttribute(Qt::WA_PaintOnScreen, true); } @@ -36,7 +37,7 @@ void ItemNum::mousePressEvent ( QMouseEvent * event ) { if(nonInteractive) return; - if(event->button()==Qt::LeftButton) { + if(event->button()==Qt::LeftButton && enabled) { event->accept(); if((infinityState && numItems <= maxItems) || (!infinityState && numItems < maxItems)) { incItems(); @@ -45,7 +46,7 @@ // appears there's an emit in there decItems(); } - } else if (event->button()==Qt::RightButton) { + } else if (event->button()==Qt::RightButton && enabled) { event->accept(); if(numItems > minItems) { decItems(); @@ -67,15 +68,25 @@ void ItemNum::paintEvent(QPaintEvent* event) { + Q_UNUSED(event); + QPainter painter(this); if (numItems==maxItems+1) { QRect target(0, 0, 100, 32); - painter.drawImage(target, QImage(":/res/infinity.png")); + if (enabled) { + painter.drawImage(target, QImage(":/res/infinity.png")); + } else { + painter.drawImage(target, QImage(":/res/infinitygrey.png")); + } } else { for(int i=0; iabsolutePath()); + tmpdir.cd("Scripts/Multiplayer"); + tmpdir.setFilter(QDir::Files | QDir::NoDotAndDotDot); + scriptList = new QStringList(tmpdir.entryList(QStringList("*.lua"))); + QTranslator Translator; { diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/mapContainer.cpp --- a/QTfrontend/mapContainer.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/mapContainer.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "hwconsts.h" #include "mapContainer.h" @@ -38,8 +40,7 @@ QWidget(parent), mainLayout(this), pMap(0), - mapgen(MAPGEN_REGULAR), - maze_size(0) + mapgen(MAPGEN_REGULAR) { hhSmall.load(":/res/hh_small.png"); hhLimit = 18; @@ -50,17 +51,23 @@ QApplication::style()->pixelMetric(QStyle::PM_LayoutRightMargin), QApplication::style()->pixelMetric(QStyle::PM_LayoutBottomMargin)); - imageButt = new QPushButton(this); + QWidget* mapWidget = new QWidget(this); + mainLayout.addWidget(mapWidget, 0, 0, Qt::AlignHCenter); + + QGridLayout* mapLayout = new QGridLayout(mapWidget); + mapLayout->setMargin(0); + + imageButt = new QPushButton(mapWidget); imageButt->setObjectName("imageButt"); imageButt->setFixedSize(256 + 6, 128 + 6); imageButt->setFlat(true); imageButt->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);//QSizePolicy::Minimum, QSizePolicy::Minimum); - mainLayout.addWidget(imageButt, 0, 0, 1, 2); + mapLayout->addWidget(imageButt, 0, 0, 1, 2); //connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomSeed())); //connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomTheme())); connect(imageButt, SIGNAL(clicked()), this, SLOT(setRandomMap())); - chooseMap = new QComboBox(this); + chooseMap = new QComboBox(mapWidget); chooseMap->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); chooseMap->addItem( // FIXME - need real icons. Disabling until then @@ -70,6 +77,10 @@ // FIXME - need real icons. Disabling until then //QIcon(":/res/mapMaze.png"), QComboBox::tr("generated maze...")); + + chooseMap->addItem(QComboBox::tr("hand drawn map...")); + chooseMap->insertSeparator(chooseMap->count()); // separator between generators and missions + chooseMap->insertSeparator(chooseMap->count()); // separator between generators and missions int missionindex = chooseMap->count(); @@ -88,10 +99,14 @@ if (mapCfgFile.open(QFile::ReadOnly)) { QString theme; quint32 limit = 0; + QString scheme; + QString weapons; QList mapInfo; QTextStream input(&mapCfgFile); input >> theme; input >> limit; + input >> scheme; + input >> weapons; mapInfo.push_back(map); mapInfo.push_back(theme); if (limit) @@ -99,6 +114,14 @@ else mapInfo.push_back(18); mapInfo.push_back(mapLuaFile.exists()); + if (scheme.isEmpty()) + scheme = "locked"; + scheme.replace("_", " "); + if (weapons.isEmpty()) + weapons = "locked"; + weapons.replace("_", " "); + mapInfo.push_back(scheme); + mapInfo.push_back(weapons); if(mapLuaFile.exists()) { chooseMap->insertItem(missionindex++, @@ -118,29 +141,29 @@ chooseMap->insertSeparator(missionindex); // separator between missions and maps connect(chooseMap, SIGNAL(currentIndexChanged(int)), this, SLOT(mapChanged(int))); - mainLayout.addWidget(chooseMap, 1, 1); + mapLayout->addWidget(chooseMap, 1, 1); - QLabel * lblMap = new QLabel(tr("Map"), this); - mainLayout.addWidget(lblMap, 1, 0); + QLabel * lblMap = new QLabel(tr("Map"), mapWidget); + mapLayout->addWidget(lblMap, 1, 0); - lblFilter = new QLabel(tr("Filter"), this); - mainLayout.addWidget(lblFilter, 2, 0); + lblFilter = new QLabel(tr("Filter"), mapWidget); + mapLayout->addWidget(lblFilter, 2, 0); - CB_TemplateFilter = new QComboBox(this); + CB_TemplateFilter = new QComboBox(mapWidget); CB_TemplateFilter->addItem(tr("All"), 0); CB_TemplateFilter->addItem(tr("Small"), 1); CB_TemplateFilter->addItem(tr("Medium"), 2); CB_TemplateFilter->addItem(tr("Large"), 3); CB_TemplateFilter->addItem(tr("Cavern"), 4); CB_TemplateFilter->addItem(tr("Wacky"), 5); - mainLayout.addWidget(CB_TemplateFilter, 2, 1); + mapLayout->addWidget(CB_TemplateFilter, 2, 1); connect(CB_TemplateFilter, SIGNAL(currentIndexChanged(int)), this, SLOT(templateFilterChanged(int))); - maze_size_label = new QLabel(tr("Type"), this); + maze_size_label = new QLabel(tr("Type"), mapWidget); mainLayout.addWidget(maze_size_label, 2, 0); maze_size_label->hide(); - maze_size_selection = new QComboBox(this); + maze_size_selection = new QComboBox(mapWidget); maze_size_selection->addItem(tr("Small tunnels"), 0); maze_size_selection->addItem(tr("Medium tunnels"), 1); maze_size_selection->addItem(tr("Large tunnels"), 2); @@ -148,23 +171,23 @@ maze_size_selection->addItem(tr("Medium floating islands"), 4); maze_size_selection->addItem(tr("Large floating islands"), 5); maze_size_selection->setCurrentIndex(1); - maze_size = 1; - mainLayout.addWidget(maze_size_selection, 2, 1); + + mapLayout->addWidget(maze_size_selection, 2, 1); maze_size_selection->hide(); connect(maze_size_selection, SIGNAL(currentIndexChanged(int)), this, SLOT(setMaze_size(int))); - gbThemes = new IconedGroupBox(this); - gbThemes->setTitleTextPadding(60); - gbThemes->setContentTopPadding(6); + gbThemes = new IconedGroupBox(mapWidget); + gbThemes->setTitleTextPadding(80); + gbThemes->setContentTopPadding(15); gbThemes->setTitle(tr("Themes")); //gbThemes->setStyleSheet("padding: 0px"); // doesn't work - stylesheet is set with icon - mainLayout.addWidget(gbThemes, 0, 2, 3, 1); + mapLayout->addWidget(gbThemes, 0, 2, 3, 1); QVBoxLayout * gbTLayout = new QVBoxLayout(gbThemes); gbTLayout->setContentsMargins(0, 0, 0 ,0); gbTLayout->setSpacing(0); - lwThemes = new QListWidget(this); + lwThemes = new QListWidget(mapWidget); lwThemes->setMinimumHeight(30); lwThemes->setFixedWidth(140); for (int i = 0; i < Themes->size(); ++i) { @@ -193,7 +216,29 @@ gbTLayout->addWidget(lwThemes); lwThemes->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); - mainLayout.setSizeConstraint(QLayout::SetFixedSize);//SetMinimumSize + mapLayout->setSizeConstraint(QLayout::SetFixedSize); + + QWidget* seedWidget = new QWidget(this); + mainLayout.addWidget(seedWidget, 1, 0); + + QGridLayout* seedLayout = new QGridLayout(seedWidget); + seedLayout->setMargin(0); + + seedLabel = new QLabel(tr("Seed"), seedWidget); + seedLayout->addWidget(seedLabel, 3, 0); + seedEdit = new QLineEdit(seedWidget); + seedEdit->setMaxLength(54); + connect(seedEdit, SIGNAL(returnPressed()), this, SLOT(seedEdited())); + seedLayout->addWidget(seedEdit, 3, 1); + seedLayout->setColumnStretch(1, 5); + seedSet = new QPushButton(seedWidget); + 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(); @@ -216,7 +261,7 @@ p.drawPixmap(QPoint(0, 0), px); addInfoToPreview(pxres); - chooseMap->setCurrentIndex(mapgen); + //chooseMap->setCurrentIndex(mapgen); pMap = 0; } @@ -230,7 +275,7 @@ switch(index) { case MAPGEN_REGULAR: mapgen = MAPGEN_REGULAR; - changeImage(); + updatePreview(); gbThemes->show(); lblFilter->show(); CB_TemplateFilter->show(); @@ -242,7 +287,7 @@ break; case MAPGEN_MAZE: mapgen = MAPGEN_MAZE; - changeImage(); + updatePreview(); gbThemes->show(); lblFilter->hide(); CB_TemplateFilter->hide(); @@ -252,8 +297,20 @@ emit mapgenChanged(mapgen); emit themeChanged(chooseMap->itemData(index).toList()[1].toString()); break; + case MAPGEN_DRAWN: + mapgen = MAPGEN_DRAWN; + updatePreview(); + gbThemes->show(); + lblFilter->hide(); + CB_TemplateFilter->hide(); + maze_size_label->hide(); + maze_size_selection->hide(); + emit mapChanged("+drawn+"); + emit mapgenChanged(mapgen); + emit themeChanged(chooseMap->itemData(index).toList()[1].toString()); + break; default: - loadMap(index); + updatePreview(); gbThemes->hide(); lblFilter->hide(); CB_TemplateFilter->hide(); @@ -263,19 +320,6 @@ } } -void HWMapContainer::loadMap(int index) -{ - QPixmap mapImage; - if(!mapImage.load(datadir->absolutePath() + "/Maps/" + chooseMap->itemData(index).toList()[0].toString() + "/preview.png")) { - changeImage(); - chooseMap->setCurrentIndex(0); - return; - } - - hhLimit = chooseMap->itemData(index).toList()[2].toInt(); - addInfoToPreview(mapImage); -} - // Should this add text to identify map size? void HWMapContainer::addInfoToPreview(QPixmap image) { @@ -296,7 +340,7 @@ imageButt->setIconSize(image.size()); } -void HWMapContainer::changeImage() +void HWMapContainer::askForGeneratedPreview() { if (pMap) { @@ -308,25 +352,28 @@ pMap = new HWMap(); connect(pMap, SIGNAL(ImageReceived(const QImage)), this, SLOT(setImage(const QImage))); connect(pMap, SIGNAL(HHLimitReceived(int)), this, SLOT(setHHLimit(int))); - pMap->getImage(m_seed.toStdString(), getTemplateFilter(), mapgen, maze_size); + pMap->getImage(m_seed, + getTemplateFilter(), + get_mapgen(), + get_maze_size(), + getDrawnMapData() + ); } void HWMapContainer::themeSelected(int currentRow) { QString theme = Themes->at(currentRow); - QList mapInfoRegular; - mapInfoRegular.push_back(QString("+rnd+")); - mapInfoRegular.push_back(theme); - mapInfoRegular.push_back(18); - mapInfoRegular.push_back(false); - chooseMap->setItemData(0, mapInfoRegular); - QList mapInfoMaze; - mapInfoMaze.push_back(QString("+maze+")); - mapInfoMaze.push_back(theme); - mapInfoMaze.push_back(18); - mapInfoMaze.push_back(false); - chooseMap->setItemData(1, mapInfoMaze); - gbThemes->setIcon(QIcon(QString("%1/Themes/%2/icon.png").arg(datadir->absolutePath()).arg(theme))); + QList mapInfo; + mapInfo.push_back(QString("+rnd+")); + mapInfo.push_back(theme); + mapInfo.push_back(18); + mapInfo.push_back(false); + chooseMap->setItemData(0, mapInfo); + mapInfo[0] = QString("+maze+"); + chooseMap->setItemData(1, mapInfo); + mapInfo[0] = QString("+drawn+"); + chooseMap->setItemData(2, mapInfo); + gbThemes->setIcon(QIcon(QString("%1/Themes/%2/icon@2x.png").arg(datadir->absolutePath()).arg(theme))); emit themeChanged(theme); } @@ -337,7 +384,7 @@ QString HWMapContainer::getCurrentMap() const { - if(chooseMap->currentIndex() <= 1) return QString(); + if(chooseMap->currentIndex() < MAPGEN_MAP) return QString(); return chooseMap->itemData(chooseMap->currentIndex()).toList()[0].toString(); } @@ -357,6 +404,16 @@ return hhLimit; } +QString HWMapContainer::getCurrentScheme() const +{ + return chooseMap->itemData(chooseMap->currentIndex()).toList()[4].toString(); +} + +QString HWMapContainer::getCurrentWeapons() const +{ + return chooseMap->itemData(chooseMap->currentIndex()).toList()[5].toString(); +} + quint32 HWMapContainer::getTemplateFilter() const { return CB_TemplateFilter->itemData(CB_TemplateFilter->currentIndex()).toInt(); @@ -364,23 +421,21 @@ void HWMapContainer::resizeEvent ( QResizeEvent * event ) { + Q_UNUSED(event); //imageButt->setIconSize(imageButt->size()); } void HWMapContainer::setSeed(const QString & seed) { m_seed = seed; - changeImage(); + if (seed != seedEdit->text()) + seedEdit->setText(seed); + if (chooseMap->currentIndex() < MAPGEN_MAP) + updatePreview(); } void HWMapContainer::setMap(const QString & map) { - if(map == "+rnd+" || map == "+maze+") - { - changeImage(); - return; - } - int id = 0; for(int i = 0; i < chooseMap->count(); i++) if(!chooseMap->itemData(i).isNull() && chooseMap->itemData(i).toList()[0].toString() == map) @@ -397,7 +452,7 @@ pMap = 0; } chooseMap->setCurrentIndex(id); - loadMap(id); + updatePreview(); } } @@ -407,18 +462,21 @@ if(items.size()) lwThemes->setCurrentItem(items.at(0)); } -#include + void HWMapContainer::setRandomMap() { + setRandomSeed(); switch(chooseMap->currentIndex()) { case MAPGEN_REGULAR: case MAPGEN_MAZE: - setRandomSeed(); setRandomTheme(); break; + case MAPGEN_DRAWN: + emit drawMapRequested(); + break; default: - if(chooseMap->currentIndex() < numMissions + 3) + if(chooseMap->currentIndex() <= numMissions + MAPGEN_MAP + 1) setRandomMission(); else setRandomStatic(); @@ -428,21 +486,26 @@ void HWMapContainer::setRandomStatic() { - chooseMap->setCurrentIndex(4 + numMissions + rand() % (chooseMap->count() - 4 - numMissions)); - m_seed = QUuid::createUuid().toString(); + int i = MAPGEN_MAP + 3 + numMissions + rand() % (chooseMap->count() - MAPGEN_MAP - 3 - numMissions); + chooseMap->setCurrentIndex(i); + setRandomSeed(); } void HWMapContainer::setRandomMission() { - chooseMap->setCurrentIndex(3 + rand() % numMissions); - m_seed = QUuid::createUuid().toString(); + int i = MAPGEN_MAP + 2 + rand() % numMissions; + qDebug() << i << MAPGEN_MAP << numMissions; + chooseMap->setCurrentIndex(i); + setRandomSeed(); } void HWMapContainer::setRandomSeed() { m_seed = QUuid::createUuid().toString(); + seedEdit->setText(m_seed); emit seedChanged(m_seed); - changeImage(); + if (chooseMap->currentIndex() < MAPGEN_MAP) + updatePreview(); } void HWMapContainer::setRandomTheme() @@ -460,7 +523,7 @@ void HWMapContainer::templateFilterChanged(int filter) { emit newTemplateFilter(filter); - changeImage(); + updatePreview(); } MapGenerator HWMapContainer::get_mapgen(void) const @@ -470,20 +533,90 @@ int HWMapContainer::get_maze_size(void) const { - return maze_size; + return maze_size_selection->currentIndex(); } void HWMapContainer::setMaze_size(int size) { - maze_size = size; maze_size_selection->setCurrentIndex(size); emit maze_sizeChanged(size); - changeImage(); + updatePreview(); } void HWMapContainer::setMapgen(MapGenerator m) { mapgen = m; + chooseMap->setCurrentIndex(m); emit mapgenChanged(m); - changeImage(); + updatePreview(); +} + +void HWMapContainer::setDrawnMapData(const QByteArray & ar) +{ + drawMapScene.decode(ar); + updatePreview(); +} + +QByteArray HWMapContainer::getDrawnMapData() +{ + return drawMapScene.encode(); +} + +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 + { + setSeed(seedEdit->text()); + emit seedChanged(seedEdit->text()); + } } + +DrawMapScene * HWMapContainer::getDrawMapScene() +{ + return &drawMapScene; +} + +void HWMapContainer::mapDrawingFinished() +{ + emit drawnMapChanged(getDrawnMapData()); + + updatePreview(); +} + +void HWMapContainer::updatePreview() +{ + int curIndex = chooseMap->currentIndex(); + + switch(curIndex) + { + case MAPGEN_REGULAR: + askForGeneratedPreview(); + break; + case MAPGEN_MAZE: + askForGeneratedPreview(); + break; + case MAPGEN_DRAWN: + askForGeneratedPreview(); + break; + default: + QPixmap mapImage; + qDebug() << "Map data" << curIndex << chooseMap->currentText() << chooseMap->itemData(curIndex); + if(!mapImage.load(datadir->absolutePath() + "/Maps/" + chooseMap->itemData(curIndex).toList()[0].toString() + "/preview.png")) { + imageButt->setIcon(QIcon()); + return; + } + + hhLimit = chooseMap->itemData(curIndex).toList()[2].toInt(); + addInfoToPreview(mapImage); + } +} diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/mapContainer.h --- a/QTfrontend/mapContainer.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/mapContainer.h Tue Jan 04 12:53:46 2011 +0100 @@ -23,8 +23,11 @@ #include #include #include +#include +#include #include "hwmap.h" +#include "drawmapscene.h" class QPushButton; class IconedGroupBox; @@ -44,19 +47,26 @@ QString getCurrentMap() const; QString getCurrentTheme() const; int getCurrentHHLimit() const; + QString getCurrentScheme() const; + QString getCurrentWeapons() const; quint32 getTemplateFilter() const; MapGenerator get_mapgen(void) const; int get_maze_size(void) const; bool getCurrentIsMission() const; + QByteArray getDrawnMapData(); + DrawMapScene * getDrawMapScene(); + void mapDrawingFinished(); + QLineEdit* seedEdit; public slots: - void changeImage(); + void askForGeneratedPreview(); void setSeed(const QString & seed); void setMap(const QString & map); void setTheme(const QString & theme); void setTemplateFilter(int); void setMapgen(MapGenerator m); void setMaze_size(int size); + void setDrawnMapData(const QByteArray & ar); signals: void seedChanged(const QString & seed); @@ -65,6 +75,8 @@ void newTemplateFilter(int filter); void mapgenChanged(MapGenerator m); void maze_sizeChanged(int s); + void drawMapRequested(); + void drawnMapChanged(const QByteArray & data); private slots: void setImage(const QImage newImage); @@ -78,6 +90,7 @@ void themeSelected(int currentRow); void addInfoToPreview(QPixmap image); void templateFilterChanged(int filter); + void seedEdited(); protected: virtual void resizeEvent ( QResizeEvent * event ); @@ -90,6 +103,8 @@ QListWidget* lwThemes; HWMap* pMap; QString m_seed; + QPushButton* seedSet; + QLabel* seedLabel; int hhLimit; int templateFilter; QPixmap hhSmall; @@ -99,9 +114,9 @@ QComboBox *maze_size_selection; MapGenerator mapgen; int numMissions; - int maze_size; + DrawMapScene drawMapScene; - void loadMap(int index); + void updatePreview(); }; #endif // _HWMAP_CONTAINER_INCLUDED diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/netregister.cpp --- a/QTfrontend/netregister.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/netregister.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -21,7 +21,8 @@ HWNetRegisterServer::HWNetRegisterServer(QObject *parent, const QString & descr, quint16 port) : QObject(parent) { - + Q_UNUSED(descr); + Q_UNUSED(port); } void HWNetRegisterServer::unregister() diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/newnetclient.cpp diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/pages.cpp --- a/QTfrontend/pages.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/pages.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -40,6 +40,7 @@ #include #include #include +#include #include "ammoSchemeModel.h" #include "pages.h" @@ -63,6 +64,7 @@ #include "togglebutton.h" #include "hwform.h" #include "SDLs.h" +#include "drawmapwidget.h" PageMain::PageMain(QWidget* parent) : AbstractPage(parent) @@ -440,17 +442,22 @@ { QGridLayout * pageLayout = new QGridLayout(this); - BtnBack = addButton(":/res/Exit.png", pageLayout, 2, 0, true); + BtnBack = addButton(":/res/Exit.png", pageLayout, 3, 0, true); gameCFG = new GameCFGWidget(this); pageLayout->addWidget(gameCFG, 0, 0, 1, 2); - pageLayout->setRowStretch(1, 1); + QPushButton * btnSetup = new QPushButton(this); + btnSetup->setText(QPushButton::tr("Setup")); + connect(btnSetup, SIGNAL(clicked()), this, SIGNAL(SetupClicked())); + pageLayout->addWidget(btnSetup, 1, 0, 1, 2); + + pageLayout->setRowStretch(2, 1); teamsSelect = new TeamSelWidget(this); - pageLayout->addWidget(teamsSelect, 0, 2, 2, 2); + pageLayout->addWidget(teamsSelect, 0, 2, 3, 2); - BtnStartMPGame = addButton(tr("Start"), pageLayout, 2, 3); + BtnStartMPGame = addButton(tr("Start"), pageLayout, 3, 3); } PageOptions::PageOptions(QWidget* parent) : @@ -522,45 +529,74 @@ } { - // TODO: This box should contain controls for all schemes: game modes and weapons - IconedGroupBox* groupWeapons = new IconedGroupBox(this); + //groupWeapons->setContentTopPadding(0); //groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); groupWeapons->setIcon(QIcon(":/res/weaponsicon.png")); groupWeapons->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - groupWeapons->setTitle(QGroupBox::tr("Weapons")); + groupWeapons->setTitle(QGroupBox::tr("Schemes and Weapons")); QGridLayout * WeaponsLayout = new QGridLayout(groupWeapons); + QLabel* SchemeLabel = new QLabel(groupWeapons); + SchemeLabel->setText(QLabel::tr("Game scheme")); + WeaponsLayout->addWidget(SchemeLabel, 1, 0); + + SchemesName = new QComboBox(groupWeapons); + WeaponsLayout->addWidget(SchemesName, 1, 1); + + SchemeNew = new QPushButton(groupWeapons); + SchemeNew->setToolTip(tr("New scheme")); + SchemeNew->setIconSize(pmNew.size()); + SchemeNew->setIcon(pmNew); + SchemeNew->setMaximumWidth(pmNew.width() + 6); + WeaponsLayout->addWidget(SchemeNew, 1, 2); + + SchemeEdit = new QPushButton(groupWeapons); + SchemeEdit->setToolTip(tr("Edit scheme")); + SchemeEdit->setIconSize(pmEdit.size()); + SchemeEdit->setIcon(pmEdit); + SchemeEdit->setMaximumWidth(pmEdit.width() + 6); + WeaponsLayout->addWidget(SchemeEdit, 1, 3); + + SchemeDelete = new QPushButton(groupWeapons); + SchemeDelete->setToolTip(tr("Delete scheme")); + SchemeDelete->setIconSize(pmDelete.size()); + SchemeDelete->setIcon(pmDelete); + SchemeDelete->setMaximumWidth(pmDelete.width() + 6); + WeaponsLayout->addWidget(SchemeDelete, 1, 4); + + QLabel* WeaponLabel = new QLabel(groupWeapons); + WeaponLabel->setText(QLabel::tr("Weapons")); + WeaponsLayout->addWidget(WeaponLabel, 2, 0); + WeaponsName = new QComboBox(groupWeapons); - WeaponsLayout->addWidget(WeaponsName, 0, 0); + WeaponsLayout->addWidget(WeaponsName, 2, 1); - WeaponsButt = new QPushButton(groupWeapons); - WeaponsButt->setToolTip(tr("New weapon scheme")); - WeaponsButt->setIconSize(pmNew.size()); - WeaponsButt->setIcon(pmNew); - WeaponsButt->setMaximumWidth(pmNew.width() + 6); - WeaponsLayout->addWidget(WeaponsButt, 0, 1); + WeaponNew = new QPushButton(groupWeapons); + WeaponNew->setToolTip(tr("New weapon set")); + WeaponNew->setIconSize(pmNew.size()); + WeaponNew->setIcon(pmNew); + WeaponNew->setMaximumWidth(pmNew.width() + 6); + WeaponsLayout->addWidget(WeaponNew, 2, 2); WeaponEdit = new QPushButton(groupWeapons); - WeaponEdit->setToolTip(tr("Edit weapon scheme")); + WeaponEdit->setToolTip(tr("Edit weapon set")); WeaponEdit->setIconSize(pmEdit.size()); WeaponEdit->setIcon(pmEdit); WeaponEdit->setMaximumWidth(pmEdit.width() + 6); - WeaponsLayout->addWidget(WeaponEdit, 0, 2); + WeaponsLayout->addWidget(WeaponEdit, 2, 3); WeaponDelete = new QPushButton(groupWeapons); - WeaponDelete->setToolTip(tr("Delete weapon scheme")); + WeaponDelete->setToolTip(tr("Delete weapon set")); WeaponDelete->setIconSize(pmDelete.size()); WeaponDelete->setIcon(pmDelete); WeaponDelete->setMaximumWidth(pmDelete.width() + 6); - WeaponDelete->setEnabled(false); - WeaponDelete->setVisible(false); // hide for now - WeaponsLayout->addWidget(WeaponDelete, 0, 3); + WeaponsLayout->addWidget(WeaponDelete, 2, 4); WeaponTooltip = new QCheckBox(this); WeaponTooltip->setText(QCheckBox::tr("Show ammo menu tooltips")); - WeaponsLayout->addWidget(WeaponTooltip, 1, 0, 1, 3); + WeaponsLayout->addWidget(WeaponTooltip, 3, 0, 1, 4); gbTBLayout->addWidget(groupWeapons, 1, 0); } @@ -942,19 +978,24 @@ // chatwidget pChatWidget = new HWChatWidget(this, gameSettings, sdli, true); pChatWidget->setShowReady(true); // show status bulbs by default - pageLayout->addWidget(pChatWidget, 1, 0, 1, 2); + pageLayout->addWidget(pChatWidget, 2, 0, 1, 2); pageLayout->setRowStretch(1, 100); pGameCFG = new GameCFGWidget(this); pageLayout->addWidget(pGameCFG, 0, 0); + QPushButton * btnSetup = new QPushButton(this); + btnSetup->setText(QPushButton::tr("Setup")); + connect(btnSetup, SIGNAL(clicked()), this, SIGNAL(SetupClicked())); + pageLayout->addWidget(btnSetup, 1, 0); + pNetTeamsWidget = new TeamSelWidget(this); pNetTeamsWidget->setAcceptOuter(true); - pageLayout->addWidget(pNetTeamsWidget, 0, 1); + pageLayout->addWidget(pNetTeamsWidget, 0, 1, 2, 1); QHBoxLayout * bottomLayout = new QHBoxLayout; - pageLayout->addLayout(bottomLayout, 3, 0, 1, 2); + pageLayout->addLayout(bottomLayout, 4, 0, 1, 2); BtnBack = addButton(":/res/Exit.png", bottomLayout, 0, true); @@ -1035,7 +1076,7 @@ BtnCampaignPage = addButton(":/res/Campaign.png", middleLine, 0, true); BtnCampaignPage->setToolTip(tr("Campaign Mode (...). IN DEVELOPMENT")); - BtnCampaignPage->setVisible(false); + //BtnCampaignPage->setVisible(false); BtnTrainPage = addButton(":/res/Trainings.png", middleLine, 1, true); BtnTrainPage->setToolTip(tr("Training Mode (Practice your skills in a range of training missions). IN DEVELOPMENT")); @@ -1069,7 +1110,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); @@ -1110,18 +1154,26 @@ QGridLayout * pageLayout = new QGridLayout(this); pWeapons = new SelWeaponWidget(cAmmoNumber, this); - pageLayout->addWidget(pWeapons, 0, 0, 1, 4); + pageLayout->addWidget(pWeapons, 0, 0, 1, 5); - BtnBack = addButton(":/res/Exit.png", pageLayout, 1, 0, true); - BtnDefault = addButton(tr("Default"), pageLayout, 1, 1); - BtnDelete = addButton(tr("Delete"), pageLayout, 1, 2); - BtnSave = addButton(":/res/Save.png", pageLayout, 1, 3, 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, 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&))); } PageInGame::PageInGame(QWidget* parent) : @@ -1502,7 +1554,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); @@ -1705,105 +1757,118 @@ glBSLayout->addWidget(SB_HealthDecrease,5,2,1,1); l = new QLabel(gbBasicSettings); - l->setText(QLabel::tr("Crate Drops")); + l->setText(QLabel::tr("% Rope Length")); l->setWordWrap(true); glBSLayout->addWidget(l,6,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); - l->setPixmap(QPixmap(":/res/iconBox.png")); + l->setPixmap(QPixmap(":/res/iconRope.png")); glBSLayout->addWidget(l,6,1,1,1); - SB_CaseProb = new FreqSpinBox(gbBasicSettings); - SB_CaseProb->setRange(0, 9); - SB_CaseProb->setValue(5); - glBSLayout->addWidget(SB_CaseProb,6,2,1,1); + SB_RopeModifier = new QSpinBox(gbBasicSettings); + SB_RopeModifier->setRange(25, 999); + SB_RopeModifier->setValue(100); + SB_RopeModifier->setSingleStep(25); + glBSLayout->addWidget(SB_RopeModifier,6,2,1,1); l = new QLabel(gbBasicSettings); - l->setText(QLabel::tr("% Health Crates")); + l->setText(QLabel::tr("Crate Drops")); l->setWordWrap(true); glBSLayout->addWidget(l,7,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); - l->setPixmap(QPixmap(":/res/iconHealth.png")); // TODO: icon + l->setPixmap(QPixmap(":/res/iconBox.png")); glBSLayout->addWidget(l,7,1,1,1); - SB_HealthCrates = new QSpinBox(gbBasicSettings); - SB_HealthCrates->setRange(0, 100); - SB_HealthCrates->setValue(35); - SB_HealthCrates->setSingleStep(5); - glBSLayout->addWidget(SB_HealthCrates,7,2,1,1); + SB_CaseProb = new FreqSpinBox(gbBasicSettings); + SB_CaseProb->setRange(0, 9); + SB_CaseProb->setValue(5); + glBSLayout->addWidget(SB_CaseProb,7,2,1,1); l = new QLabel(gbBasicSettings); - l->setText(QLabel::tr("Health in Crates")); + l->setText(QLabel::tr("% Health Crates")); l->setWordWrap(true); glBSLayout->addWidget(l,8,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); l->setPixmap(QPixmap(":/res/iconHealth.png")); // TODO: icon glBSLayout->addWidget(l,8,1,1,1); + SB_HealthCrates = new QSpinBox(gbBasicSettings); + SB_HealthCrates->setRange(0, 100); + SB_HealthCrates->setValue(35); + SB_HealthCrates->setSingleStep(5); + glBSLayout->addWidget(SB_HealthCrates,8,2,1,1); + + l = new QLabel(gbBasicSettings); + l->setText(QLabel::tr("Health in Crates")); + l->setWordWrap(true); + glBSLayout->addWidget(l,9,0,1,1); + l = new QLabel(gbBasicSettings); + l->setFixedSize(32,32); + l->setPixmap(QPixmap(":/res/iconHealth.png")); // TODO: icon + glBSLayout->addWidget(l,9,1,1,1); SB_CrateHealth = new QSpinBox(gbBasicSettings); SB_CrateHealth->setRange(0, 200); SB_CrateHealth->setValue(25); SB_CrateHealth->setSingleStep(5); - glBSLayout->addWidget(SB_CrateHealth,8,2,1,1); + glBSLayout->addWidget(SB_CrateHealth,9,2,1,1); l = new QLabel(gbBasicSettings); l->setText(QLabel::tr("Mines Time")); l->setWordWrap(true); - glBSLayout->addWidget(l,9,0,1,1); + glBSLayout->addWidget(l,10,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); l->setPixmap(QPixmap(":/res/iconTime.png")); // TODO: icon - glBSLayout->addWidget(l,9,1,1,1); + glBSLayout->addWidget(l,10,1,1,1); SB_MinesTime = new QSpinBox(gbBasicSettings); SB_MinesTime->setRange(-1, 5); SB_MinesTime->setValue(3); SB_MinesTime->setSingleStep(1); SB_MinesTime->setSpecialValueText(tr("Random")); SB_MinesTime->setSuffix(" "+ tr("Seconds")); - glBSLayout->addWidget(SB_MinesTime,9,2,1,1); + glBSLayout->addWidget(SB_MinesTime,10,2,1,1); l = new QLabel(gbBasicSettings); l->setText(QLabel::tr("Mines")); l->setWordWrap(true); - glBSLayout->addWidget(l,10,0,1,1); + glBSLayout->addWidget(l,11,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); l->setPixmap(QPixmap(":/res/iconMine.png")); // TODO: icon - glBSLayout->addWidget(l,10,1,1,1); + glBSLayout->addWidget(l,11,1,1,1); SB_Mines = new QSpinBox(gbBasicSettings); SB_Mines->setRange(0, 80); SB_Mines->setValue(0); SB_Mines->setSingleStep(5); - glBSLayout->addWidget(SB_Mines,10,2,1,1); + glBSLayout->addWidget(SB_Mines,11,2,1,1); l = new QLabel(gbBasicSettings); l->setText(QLabel::tr("% Dud Mines")); l->setWordWrap(true); - glBSLayout->addWidget(l,11,0,1,1); + glBSLayout->addWidget(l,12,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); l->setPixmap(QPixmap(":/res/iconDud.png")); - glBSLayout->addWidget(l,11,1,1,1); + glBSLayout->addWidget(l,12,1,1,1); SB_MineDuds = new QSpinBox(gbBasicSettings); SB_MineDuds->setRange(0, 100); SB_MineDuds->setValue(0); SB_MineDuds->setSingleStep(5); - glBSLayout->addWidget(SB_MineDuds,11,2,1,1); + glBSLayout->addWidget(SB_MineDuds,12,2,1,1); l = new QLabel(gbBasicSettings); l->setText(QLabel::tr("Explosives")); l->setWordWrap(true); - glBSLayout->addWidget(l,12,0,1,1); + glBSLayout->addWidget(l,13,0,1,1); l = new QLabel(gbBasicSettings); l->setFixedSize(32,32); l->setPixmap(QPixmap(":/res/iconDamage.png")); - glBSLayout->addWidget(l,12,1,1,1); + glBSLayout->addWidget(l,13,1,1,1); SB_Explosives = new QSpinBox(gbBasicSettings); SB_Explosives->setRange(0, 40); SB_Explosives->setValue(0); SB_Explosives->setSingleStep(1); - glBSLayout->addWidget(SB_Explosives,12,2,1,1); - + glBSLayout->addWidget(SB_Explosives,13,2,1,1); l = new QLabel(gbBasicSettings); l->setText(QLabel::tr("Scheme Name:")); @@ -1816,12 +1881,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))); @@ -1870,6 +1937,7 @@ mapper->addMapping(SB_CrateHealth, 34); mapper->addMapping(SB_WaterRise, 35); mapper->addMapping(SB_HealthDecrease, 36); + mapper->addMapping(SB_RopeModifier, 37); mapper->toFirst(); } @@ -1877,14 +1945,25 @@ 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); } void PageScheme::deleteRow() { - QAbstractItemModel * model = mapper->model(); - model->removeRow(selectScheme->currentIndex()); + QMessageBox reallyDelete(QMessageBox::Question, QMessageBox::tr("Schemes"), QMessageBox::tr("Really delete this game scheme?"), QMessageBox::Ok | QMessageBox::Cancel); + + if (reallyDelete.exec() == QMessageBox::Ok) { + QAbstractItemModel * model = mapper->model(); + model->removeRow(selectScheme->currentIndex()); + } } void PageScheme::schemeSelected(int n) @@ -1993,3 +2072,41 @@ BtnBack = addButton(":/res/Exit.png", pageLayout, 4, 0, true); } + +///////////////////////////////////////////////// + +PageDrawMap::PageDrawMap(QWidget* parent) : AbstractPage(parent) +{ + QGridLayout * pageLayout = new QGridLayout(this); + + 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, 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 0ddb100fea61 -r f924be23ffb4 QTfrontend/pages.h --- a/QTfrontend/pages.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/pages.h Tue Jan 04 12:53:46 2011 +0100 @@ -61,6 +61,8 @@ class IconedGroupBox; class FreqSpinBox; +class DrawMapWidget; + class AbstractPage : public QWidget { Q_OBJECT @@ -69,8 +71,10 @@ protected: AbstractPage(QWidget* parent = 0) { + Q_UNUSED(parent); + font14 = new QFont("MS Shell Dlg", 14); - setFocusPolicy(Qt::StrongFocus); + //setFocusPolicy(Qt::StrongFocus); } virtual ~AbstractPage() {}; @@ -196,6 +200,9 @@ GameCFGWidget *gameCFG; TeamSelWidget *teamsSelect; QPushButton *BtnStartMPGame; + +signals: + void SetupClicked(); }; class PageOptions : public AbstractPage @@ -205,11 +212,16 @@ public: PageOptions(QWidget* parent = 0); - QPushButton *WeaponsButt; + QCheckBox *WeaponTooltip; + QPushButton *WeaponNew; QPushButton *WeaponEdit; QPushButton *WeaponDelete; QComboBox *WeaponsName; - QCheckBox *WeaponTooltip; + QPushButton *SchemeNew; + QPushButton *SchemeEdit; + QPushButton *SchemeDelete; + QComboBox *SchemesName; + QComboBox *CBLanguage; QPushButton *BtnBack; @@ -324,6 +336,9 @@ public slots: void setReadyStatus(bool isReady); void setMasterMode(bool isMaster); + +signals: + void SetupClicked(); }; class PageInfo : public AbstractPage @@ -389,8 +404,11 @@ QPushButton *BtnSave; QPushButton *BtnDefault; QPushButton *BtnDelete; + QPushButton *BtnNew; + QPushButton *BtnCopy; QPushButton *BtnBack; SelWeaponWidget* pWeapons; + QComboBox* selectWeaponSet; }; class PageInGame : public AbstractPage @@ -462,12 +480,19 @@ PageScheme(QWidget* parent = 0); QPushButton * BtnBack; + QPushButton * BtnCopy; QPushButton * BtnNew; QPushButton * BtnDelete; QPushButton * BtnSave; + QComboBox * selectScheme; void setModel(QAbstractItemModel * model); +public slots: + void newRow(); + void copyRow(); + void deleteRow(); + private: QDataWidgetMapper * mapper; ToggleButtonWidget * TBW_mode_Forts; @@ -507,16 +532,15 @@ QSpinBox * SB_Mines; QSpinBox * SB_MineDuds; QSpinBox * SB_Explosives; + QSpinBox * SB_RopeModifier; QLineEdit * LE_name; - QComboBox * selectScheme; QGroupBox * gbGameModes; QGroupBox * gbBasicSettings; private slots: - void newRow(); - void deleteRow(); void schemeSelected(int); + }; class PageAdmin : public AbstractPage @@ -565,4 +589,21 @@ QPushButton * BtnOfficialServer; }; + +class PageDrawMap : public AbstractPage +{ + Q_OBJECT + +public: + PageDrawMap(QWidget* parent = 0); + + QPushButton * BtnBack; + + DrawMapWidget * drawMapWidget; + +private slots: + void load(); + void save(); +}; + #endif // PAGES_H diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/predefteams.h --- a/QTfrontend/predefteams.h Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * Hedgewars, a free turn based strategy game - * Copyright (c) 2006-2010 Andrey Korotaev - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#ifndef PREDEFTEAMS_H -#define PREDEFTEAMS_H - -#include - -#define PREDEFTEAMS_COUNT 3 -/* -struct PredefinedTeam -{ - const char * TeamName; - const char * hh0name; - const char * hh1name; - const char * hh2name; - const char * hh3name; - const char * hh4name; - const char * hh5name; - const char * hh6name; - const char * hh7name; - const char * hh0hat; - const char * hh1hat; - const char * hh2hat; - const char * hh3hat; - const char * hh4hat; - const char * hh5hat; - const char * hh6hat; - const char * hh7hat; - QString Grave; - QString Fort; -}; - - -const PredefinedTeam pteams[PREDEFTEAMS_COUNT] = -{ - { - QT_TRANSLATE_NOOP("teams", "Hedgehogs"), - QT_TRANSLATE_NOOP("teams", "hedgehog 1"), - QT_TRANSLATE_NOOP("teams", "hedgehog 2"), - QT_TRANSLATE_NOOP("teams", "hedgehog 3"), - QT_TRANSLATE_NOOP("teams", "hedgehog 4"), - QT_TRANSLATE_NOOP("teams", "hedgehog 5"), - QT_TRANSLATE_NOOP("teams", "hedgehog 6"), - QT_TRANSLATE_NOOP("teams", "hedgehog 7"), - QT_TRANSLATE_NOOP("teams", "hedgehog 8"), - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "Simple", "Island" - }, - { - QT_TRANSLATE_NOOP("teams", "Goddess"), - QT_TRANSLATE_NOOP("teams", "Isis"), - QT_TRANSLATE_NOOP("teams", "Astarte"), - QT_TRANSLATE_NOOP("teams", "Diana"), - QT_TRANSLATE_NOOP("teams", "Aphrodite"), - QT_TRANSLATE_NOOP("teams", "Hecate"), - QT_TRANSLATE_NOOP("teams", "Demeter"), - QT_TRANSLATE_NOOP("teams", "Kali"), - QT_TRANSLATE_NOOP("teams", "Inanna"), - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "Bone", "Island" - }, - { - QT_TRANSLATE_NOOP("teams", "Fruits"), - QT_TRANSLATE_NOOP("teams", "Banana"), - QT_TRANSLATE_NOOP("teams", "Apple"), - QT_TRANSLATE_NOOP("teams", "Orange"), - QT_TRANSLATE_NOOP("teams", "Lemon"), - QT_TRANSLATE_NOOP("teams", "Pineapple"), - QT_TRANSLATE_NOOP("teams", "Mango"), - QT_TRANSLATE_NOOP("teams", "Peach"), - QT_TRANSLATE_NOOP("teams", "Plum"), - "banana", - "apple", - "orange", - "lemon", - "NoHat", - "NoHat", - "NoHat", - "NoHat", - "coffin", "Barrelhouse" - } -}; -*/ -#endif // PREDEFTEAMS_H diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/proto.cpp --- a/QTfrontend/proto.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/proto.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -23,14 +23,19 @@ } +QByteArray & HWProto::addByteArrayToBuffer(QByteArray & buf, const QByteArray & msg) +{ + QByteArray bmsg = msg; + bmsg = bmsg.left(250); + quint8 sz = bmsg.size(); + buf.append(QByteArray((char *)&sz, 1)); + buf.append(bmsg); + return buf; +} + QByteArray & HWProto::addStringToBuffer(QByteArray & buf, const QString & string) { - QByteArray strmsg = string.toUtf8(); - strmsg = strmsg.left(250); - quint8 sz = strmsg.size(); - buf.append(QByteArray((char *)&sz, 1)); - buf.append(strmsg); - return buf; + return addByteArrayToBuffer(buf, string.toUtf8()); } QByteArray & HWProto::addStringListToBuffer(QByteArray & buf, const QStringList & strList) diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/proto.h --- a/QTfrontend/proto.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/proto.h Tue Jan 04 12:53:46 2011 +0100 @@ -31,6 +31,7 @@ public: HWProto(); static QByteArray & addStringToBuffer(QByteArray & buf, const QString & string); + 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); }; diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/qaspectratiolayout.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/qaspectratiolayout.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#include "qaspectratiolayout.h" + +QAspectRatioLayout::QAspectRatioLayout(QWidget* parent, int spacing) : QLayout(parent) { + init(spacing); +} + +QAspectRatioLayout::QAspectRatioLayout(int spacing) { + init(spacing); +} + +QAspectRatioLayout::~QAspectRatioLayout() { + delete item; + delete lastReceivedRect; + delete _geometry; +} + +void QAspectRatioLayout::init(int spacing) { + item = 0; + lastReceivedRect = new QRect(0, 0, 0, 0); + _geometry = new QRect(0, 0, 0, 0); + setSpacing(spacing); +} + + +/* Adds item if place isn't already taken. */ +void QAspectRatioLayout::add(QLayoutItem* item) { + if(!hasItem()) { + replaceItem(item); + } +} + +/* Adds item if place isn't already taken. */ +void QAspectRatioLayout::addItem(QLayoutItem* item) { + if(!hasItem()) { + replaceItem(item); + } +} + +/* Adds widget if place isn't already taken. */ +void QAspectRatioLayout::addWidget(QWidget* widget) { + if(!hasItem()) { + replaceItem(new QWidgetItem(widget)); + } +} + +/* Returns the item pointer and dereferences it here. */ +QLayoutItem* QAspectRatioLayout::take() { + QLayoutItem* item = 0; + if(this->hasItem()) { + item = this->item; + this->item = 0; + } + return item; +} + +/* Returns the item pointer and dereferences it here. */ +QLayoutItem* QAspectRatioLayout::takeAt(int index) { + if(index != 0) { + return 0; + } + return this->take(); +} + +/* Returns the item pointer. */ +QLayoutItem* QAspectRatioLayout::itemAt(int index) const { + if(index != 0) { + return 0; + } + if(hasItem()) { + return this->item; + } + return 0; +} + +/* Checks if we have an item. */ +bool QAspectRatioLayout::hasItem() const { + return this->item != 0; +} + +/* Returns the count of items which can be either 0 or 1. */ +int QAspectRatioLayout::count() const { + int returnValue = 0; + if(hasItem()) { + returnValue = 1; + } + return returnValue; +} + +/* Replaces the item with the new and returns the old. */ +QLayoutItem* QAspectRatioLayout::replaceItem(QLayoutItem* item) { + QLayoutItem* old = 0; + if(this->hasItem()) { + old = this->item; + } + this->item = item; + setGeometry(*this->_geometry); + return old; +} + +/* Tells which way layout expands. */ +Qt::Orientations QAspectRatioLayout::expandingDirections() const { + return Qt::Horizontal | Qt::Vertical; +} + +/* Tells which size is preferred. */ +QSize QAspectRatioLayout::sizeHint() const { + return this->item->minimumSize(); +} + +/* Tells minimum size. */ +QSize QAspectRatioLayout::minimumSize() const { + return this->item->minimumSize(); +} + +/* + * Tells if heightForWidth calculations is handled. + * It isn't since width isn't enough to calculate + * proper size. + */ +bool QAspectRatioLayout::hasHeightForWidth() const { + return false; +} + +/* Replaces lastReceivedRect. */ +void QAspectRatioLayout::setLastReceivedRect(const QRect& rect) { + QRect* oldRect = this->lastReceivedRect; + this->lastReceivedRect = new QRect(rect.topLeft(), rect.size()); + delete oldRect; +} + +/* Returns geometry */ +QRect QAspectRatioLayout::geometry() { + return QRect(*this->_geometry); +} + +/* Sets geometry to given size. */ +void QAspectRatioLayout::setGeometry(const QRect& rect) { + /* + * We check if the item is set and + * if size is the same previously received. + * If either is false nothing is done. + */ + if(!this->hasItem() || + areRectsEqual(*this->lastReceivedRect, rect)) { + return; + } + /* Replace the last received rectangle. */ + setLastReceivedRect(rect); + /* Calculate proper size for the item relative to the received size. */ + QSize properSize = calculateProperSize(rect.size()); + /* Calculate center location in the rect and with item size. */ + QPoint properLocation = calculateCenterLocation(rect.size(), properSize); + /* Set items geometry */ + this->item->setGeometry(QRect(properLocation, properSize)); + QRect* oldRect = this->_geometry; + /* Cache the calculated geometry. */ + this->_geometry = new QRect(properLocation, properSize); + delete oldRect; + /* Super classes setGeometry */ + QLayout::setGeometry(*this->_geometry); +} + +/* Takes the shortest side and creates QSize + * with the shortest side as width and height. */ +QSize QAspectRatioLayout::calculateProperSize(QSize from) const { + QSize properSize; + if(from.height() * 2 < from.width()) { + properSize.setHeight(from.height() - this->margin()); + properSize.setWidth(from.height() * 2 - this->margin()); + } + else { + properSize.setWidth(from.width() - this->margin()); + properSize.setHeight(from.width() / 2 - this->margin()); + } + return properSize; +} + +/* Calculates center location from the given height and width for item size. */ +QPoint QAspectRatioLayout::calculateCenterLocation(QSize from, + QSize itemSize) const { + QPoint centerLocation; + if((from.width() - itemSize.width()) > 0) { + centerLocation.setX((from.width() - itemSize.width())/2); + } + if((from.height() - itemSize.height()) > 0) { + centerLocation.setY((from.height() - itemSize.height())/2); + } + return centerLocation; +} + +/* Compares if two QRects are equal. */ +bool QAspectRatioLayout::areRectsEqual(const QRect& a, + const QRect& b) const { + bool result = false; + if(a.x() == b.x() && + a.y() == b.y() && + a.height() == b.height() && + a.width() == b.width()) { + result = true; + } + return result; +} diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/qaspectratiolayout.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/QTfrontend/qaspectratiolayout.h Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2009 Nokia Corporation. + */ + +#ifndef QASPECTRATIOLAYOUT_H_ +#define QASPECTRATIOLAYOUT_H_ + +#include +#include +#include +#include +#include + + +class QAspectRatioLayout : public QLayout +{ + Q_OBJECT + +public: + QAspectRatioLayout(QWidget* parent, int spacing =-1); + QAspectRatioLayout(int spacing = -1); + ~QAspectRatioLayout(); + + /* Convenience method */ + virtual void add(QLayoutItem* item); + +/* http://doc.trolltech.com/qlayout.html#addItem */ + virtual void addItem(QLayoutItem* item); + /* http://doc.trolltech.com/qlayout.html#addWidget */ + virtual void addWidget(QWidget* widget); + /* http://doc.trolltech.com/qlayout.html#takeAt */ + virtual QLayoutItem* takeAt(int index); + /* http://doc.trolltech.com/qlayout.html#itemAt */ + virtual QLayoutItem* itemAt(int index) const; + /* http://doc.trolltech.com/qlayout.html#count */ + virtual int count() const; + + /* + * These are ours since we do have only one item. + */ + virtual QLayoutItem* replaceItem(QLayoutItem* item); + virtual QLayoutItem* take(); + virtual bool hasItem() const; + +/* http://doc.trolltech.com/qlayout.html#expandingDirections */ + virtual Qt::Orientations expandingDirections() const; + + /* + * This method contains most of the juice of this article. + * http://doc.trolltech.com/qlayoutitem.html#setGeometry + */ + virtual void setGeometry(const QRect& rect); + /* http://doc.trolltech.com/qlayoutitem.html#geometry */ + virtual QRect geometry(); + + /* http://doc.trolltech.com/qlayoutitem.html#sizeHint */ + virtual QSize sizeHint() const; + /* http://doc.trolltech.com/qlayout.html#minimumSize */ + virtual QSize minimumSize() const; + /* http://doc.trolltech.com/qlayoutitem.html#hasHeightForWidth */ + virtual bool hasHeightForWidth() const; + +private: + /* Saves the last received rect. */ + void setLastReceivedRect(const QRect& rect); + /* Used to initialize the object. */ + void init(int spacing); + /* Calculates the maximum size for the item from the assigned size. */ + QSize calculateProperSize(QSize from) const; + /* Calculates the center location from the assigned size and + * the items size. */ + QPoint calculateCenterLocation(QSize from, QSize itemSize) const; + /* Check if two QRects are equal */ + bool areRectsEqual(const QRect& a, const QRect& b) const; + /* Contains item reference */ + QLayoutItem* item; + /* + * Used for caching so we won't do calculations every time + * setGeometry is called. + */ + QRect* lastReceivedRect; + /* Contains geometry */ + QRect* _geometry; + +}; + +#endif /* QASPECTRATIOLAYOUT_H_ */ diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/ammopicboxgrey.png Binary file QTfrontend/res/ammopicboxgrey.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/ammopicdelaygrey.png Binary file QTfrontend/res/ammopicdelaygrey.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/ammopicgrey.png Binary file QTfrontend/res/ammopicgrey.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/btnMoreWind.png Binary file QTfrontend/res/btnMoreWind.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/btnNoWind.png Binary file QTfrontend/res/btnNoWind.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/hh25x25grey.png Binary file QTfrontend/res/hh25x25grey.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/iconRope.png Binary file QTfrontend/res/iconRope.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/infinitygrey.png Binary file QTfrontend/res/infinitygrey.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/lock.png Binary file QTfrontend/res/lock.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/res/unlock.png Binary file QTfrontend/res/unlock.png has changed diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/selectWeapon.cpp --- a/QTfrontend/selectWeapon.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/selectWeapon.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -40,7 +40,7 @@ return ammo.copy(x, y, 32, 32); } -SelWeaponItem::SelWeaponItem(bool allowInfinite, int iconNum, int wNum, QImage image, QWidget* parent) : +SelWeaponItem::SelWeaponItem(bool allowInfinite, int iconNum, int wNum, QImage image, QImage imagegrey, QWidget* parent) : QWidget(parent) { QHBoxLayout* hbLayout = new QHBoxLayout(this); @@ -53,7 +53,7 @@ lbl->setGeometry(0, 0, 30, 30); hbLayout->addWidget(lbl); - item = new WeaponItem(image, this); + item = new WeaponItem(image, imagegrey, this); item->setItemsNum(wNum); item->setInfinityState(allowInfinite); hbLayout->addWidget(item); @@ -74,6 +74,11 @@ return item->getItemsNum(); } +void SelWeaponItem::setEnabled(bool value) +{ + item->setEnabled(value); +} + SelWeaponWidget::SelWeaponWidget(int numItems, QWidget* parent) : QFrame(parent), m_numItems(numItems) @@ -124,19 +129,19 @@ for(; i < m_numItems; ++i) { if (i == 6) continue; if (k % 4 == 0) ++j; - SelWeaponItem * swi = new SelWeaponItem(true, i, currentState[i].digitValue(), QImage(":/res/ammopic.png"), this); + SelWeaponItem * swi = new SelWeaponItem(true, i, currentState[i].digitValue(), QImage(":/res/ammopic.png"), QImage(":/res/ammopicgrey.png"), this); weaponItems[i].append(swi); p1Layout->addWidget(swi, j, k % 4); - SelWeaponItem * pwi = new SelWeaponItem(false, i, currentState[numItems + i].digitValue(), QImage(":/res/ammopicbox.png"), this); + SelWeaponItem * pwi = new SelWeaponItem(false, i, currentState[numItems + i].digitValue(), QImage(":/res/ammopicbox.png"), QImage(":/res/ammopicboxgrey.png"), this); weaponItems[i].append(pwi); p2Layout->addWidget(pwi, j, k % 4); - SelWeaponItem * dwi = new SelWeaponItem(false, i, currentState[numItems*2 + i].digitValue(), QImage(":/res/ammopicdelay.png"), this); + SelWeaponItem * dwi = new SelWeaponItem(false, i, currentState[numItems*2 + i].digitValue(), QImage(":/res/ammopicdelay.png"), QImage(":/res/ammopicdelaygrey.png"), this); weaponItems[i].append(dwi); p3Layout->addWidget(dwi, j, k % 4); - SelWeaponItem * awi = new SelWeaponItem(false, i, currentState[numItems*3 + i].digitValue(), QImage(":/res/ammopic.png"), this); + SelWeaponItem * awi = new SelWeaponItem(false, i, currentState[numItems*3 + i].digitValue(), QImage(":/res/ammopic.png"), QImage(":/res/ammopicgrey.png"), this); weaponItems[i].append(awi); p4Layout->addWidget(awi, j, k % 4); @@ -150,6 +155,11 @@ void SelWeaponWidget::setWeapons(const QString& ammo) { + bool enable = true; + for(int i = 0; i < cDefaultAmmos.size(); i++) + if (!cDefaultAmmos[i].first.compare(m_name->text())) { + enable = false; + } for(int i = 0; i < m_numItems; ++i) { twi::iterator it = weaponItems.find(i); if (it == weaponItems.end()) continue; @@ -157,12 +167,20 @@ it.value()[1]->setItemsNum(ammo[m_numItems + i].digitValue()); it.value()[2]->setItemsNum(ammo[m_numItems*2 + i].digitValue()); it.value()[3]->setItemsNum(ammo[m_numItems*3 + i].digitValue()); + it.value()[0]->setEnabled(enable); + it.value()[1]->setEnabled(enable); + it.value()[2]->setEnabled(enable); + it.value()[3]->setEnabled(enable); } - update(); + m_name->setEnabled(enable); } void SelWeaponWidget::setDefault() { + for(int i = 0; i < cDefaultAmmos.size(); i++) + if (!cDefaultAmmos[i].first.compare(m_name->text())) { + return; + } setWeapons(*cDefaultAmmoStore); } @@ -215,11 +233,11 @@ { if (curWeaponsName == "") return; - if (curWeaponsName == "Default") { - QMessageBox impossible(QMessageBox::Warning, QMessageBox::tr("Weapons"), QMessageBox::tr("Can not delete default weapon set")); - impossible.exec(); - return; - } + for(int i = 0; i < cDefaultAmmos.size(); i++) + if (!cDefaultAmmos[i].first.compare(m_name->text())) { + QMessageBox::warning(0, QMessageBox::tr("Weapons"), QMessageBox::tr("Can not delete default weapon set '%1'!").arg(cDefaultAmmos[i].first)); + return; + } QMessageBox reallyDelete(QMessageBox::Question, QMessageBox::tr("Weapons"), QMessageBox::tr("Really delete this weapon set?"), QMessageBox::Ok | QMessageBox::Cancel); @@ -229,18 +247,32 @@ } } +void SelWeaponWidget::newWeaponsName() +{ + setWeaponsName(tr("new")); +} + void SelWeaponWidget::setWeaponsName(const QString& name) { - if(name != "" && wconf->contains(name)) { - setWeapons(wconf->value(name).toString()); - } + m_name->setText(name); curWeaponsName = name; - m_name->setText(name); + if(name != "" && wconf->contains(name)) { + setWeapons(wconf->value(name).toString()); + } else { + setWeapons(*cDefaultAmmoStore); + } } QStringList SelWeaponWidget::getWeaponNames() const { return wconf->allKeys(); } + +void SelWeaponWidget::copy() +{ + QString ammo = getWeaponsString(curWeaponsName); + setWeaponsName(tr("copy of") + " " + curWeaponsName); + setWeapons(ammo); +} diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/selectWeapon.h --- a/QTfrontend/selectWeapon.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/selectWeapon.h Tue Jan 04 12:53:46 2011 +0100 @@ -33,10 +33,11 @@ Q_OBJECT public: - SelWeaponItem(bool allowInfinite, int iconNum, int wNum, QImage image, QWidget* parent=0); + SelWeaponItem(bool allowInfinite, int iconNum, int wNum, QImage image, QImage imagegrey, QWidget* parent=0); unsigned char getItemsNum() const; void setItemsNum(const unsigned char num); + void setEnabled(bool value); private: WeaponItem* item; @@ -56,7 +57,9 @@ void setWeapons(const QString& ammo); void setWeaponsName(const QString& name); void deleteWeaponsName(); + void newWeaponsName(); void save(); + void copy(); signals: void weaponsChanged(); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/statsPage.cpp --- a/QTfrontend/statsPage.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/statsPage.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -31,6 +31,8 @@ void FitGraphicsView::resizeEvent(QResizeEvent * event) { + Q_UNUSED(event); + fitInView(sceneRect()); } diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/teamselect.cpp --- a/QTfrontend/teamselect.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/teamselect.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -233,10 +233,6 @@ p.setColor(QPalette::Window, QColor(0x00, 0x00, 0x00)); addScrArea(framePlaying, p.color(QPalette::Window).light(105), 250); addScrArea(frameDontPlaying, p.color(QPalette::Window).dark(105), 0); - QPushButton * btnSetup = new QPushButton(this); - btnSetup->setText(QPushButton::tr("Setup")); - connect(btnSetup, SIGNAL(clicked()), this, SIGNAL(SetupClicked())); - mainLayout.addWidget(btnSetup); } void TeamSelWidget::setAcceptOuter(bool acceptOuter) diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/teamselect.h --- a/QTfrontend/teamselect.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/teamselect.h Tue Jan 04 12:53:46 2011 +0100 @@ -56,7 +56,6 @@ signals: void setEnabledGameStart(bool); - void SetupClicked(); void teamWillPlay(HWTeam team); void teamNotPlaying(const HWTeam& team); void hhogsNumChanged(const HWTeam&); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/teamselhelper.cpp --- a/QTfrontend/teamselhelper.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/teamselhelper.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -73,7 +73,7 @@ connect(colorButt, SIGNAL(clicked()), this, SLOT(changeTeamColor())); mainLayout.addWidget(colorButt); - phhoger = new CHedgehogerWidget(QImage(":/res/hh25x25.png"), this); + phhoger = new CHedgehogerWidget(QImage(":/res/hh25x25.png"), QImage(":/res/hh25x25grey.png"), this); connect(phhoger, SIGNAL(hedgehogsNumChanged()), this, SLOT(hhNumChanged())); phhoger->setHHNum(team.numHedgehogs); mainLayout.addWidget(phhoger); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/togglebutton.cpp --- a/QTfrontend/togglebutton.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/togglebutton.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -19,6 +19,7 @@ #include "togglebutton.h" ToggleButtonWidget::ToggleButtonWidget(QWidget * parent, QString img) + : QPushButton(parent) { setCheckable(true); diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/ui_hwform.cpp --- a/QTfrontend/ui_hwform.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/ui_hwform.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -116,4 +116,7 @@ pageCampaign = new PageCampaign(); Pages->addWidget(pageCampaign); + + pageDrawMap = new PageDrawMap(); + Pages->addWidget(pageDrawMap); } diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/ui_hwform.h --- a/QTfrontend/ui_hwform.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/ui_hwform.h Tue Jan 04 12:53:46 2011 +0100 @@ -40,6 +40,7 @@ class PageScheme; class PageAdmin; class PageNetType; +class PageDrawMap; class QStackedLayout; class QFont; class QWidget; @@ -72,6 +73,7 @@ PageAdmin *pageAdmin; PageNetType *pageNetType; PageCampaign *pageCampaign; + PageDrawMap *pageDrawMap; QStackedLayout *Pages; QFont *font14; @@ -79,8 +81,6 @@ void setupUi(HWForm *HWForm); void SetupFonts(); void SetupPages(QWidget *Parent, HWForm *HWForm); - void SetupPageNetChat(QWidget *Parent); - void SetupPageNetGame(QWidget *Parent); }; #endif // UI_HWFORM_H diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/weaponItem.cpp --- a/QTfrontend/weaponItem.cpp Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/weaponItem.cpp Tue Jan 04 12:53:46 2011 +0100 @@ -18,8 +18,8 @@ #include "weaponItem.h" -WeaponItem::WeaponItem(const QImage& im, QWidget * parent) : - ItemNum(im, parent, 0) +WeaponItem::WeaponItem(const QImage& im, const QImage& img, QWidget * parent) : + ItemNum(im, img, parent, 0) { } diff -r 0ddb100fea61 -r f924be23ffb4 QTfrontend/weaponItem.h --- a/QTfrontend/weaponItem.h Mon Dec 27 23:57:44 2010 +0100 +++ b/QTfrontend/weaponItem.h Tue Jan 04 12:53:46 2011 +0100 @@ -26,7 +26,7 @@ Q_OBJECT public: - WeaponItem(const QImage& im, QWidget * parent); + WeaponItem(const QImage& im, const QImage& img, QWidget * parent); virtual ~WeaponItem(); signals: diff -r 0ddb100fea61 -r f924be23ffb4 bin/CMakeLists.txt --- a/bin/CMakeLists.txt Mon Dec 27 23:57:44 2010 +0100 +++ b/bin/CMakeLists.txt Tue Jan 04 12:53:46 2011 +0100 @@ -1,7 +1,9 @@ if(WIN32 AND NOT UNIX) file(GLOB DLLs *.dll) + file(GLOB ICOs *.ico) install(FILES ${DLLs} + ${ICOs} DESTINATION bin) endif(WIN32 AND NOT UNIX) diff -r 0ddb100fea61 -r f924be23ffb4 doc/Release.txt diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/Actions.hs --- a/gameServer/Actions.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/Actions.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,134 +1,171 @@ -{-# LANGUAGE OverloadedStrings #-} module Actions where -import Control.Concurrent +import Control.Concurrent.STM import Control.Concurrent.Chan +import Data.IntMap 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 CoreTypes import Utils -import ClientIO -import ServerState data Action = - AnswerClients ![ClientChan] ![B.ByteString] + AnswerThisClient [String] + | AnswerAll [String] + | AnswerAllOthers [String] + | AnswerThisRoom [String] + | AnswerOthersInRoom [String] + | AnswerSameClan [String] + | AnswerLobby [String] | SendServerMessage | SendServerVars - | MoveToRoom RoomIndex - | MoveToLobby B.ByteString - | RemoveTeam B.ByteString + | RoomAddThisClient Int -- roomID + | RoomRemoveThisClient String + | RemoveTeam String | RemoveRoom | UnreadyRoomClients - | JoinLobby - | ProtocolError B.ByteString - | Warning B.ByteString - | ByeClient B.ByteString - | KickClient ClientIndex - | KickRoomClient ClientIndex - | BanClient B.ByteString -- nick - | RemoveClientTeams ClientIndex + | MoveToLobby + | ProtocolError String + | Warning String + | ByeClient String + | KickClient Int -- clID + | KickRoomClient Int -- clID + | BanClient String -- nick + | RemoveClientTeams Int -- clID | ModifyClient (ClientInfo -> ClientInfo) - | ModifyClient2 ClientIndex (ClientInfo -> ClientInfo) + | ModifyClient2 Int (ClientInfo -> ClientInfo) | ModifyRoom (RoomInfo -> RoomInfo) | ModifyServerInfo (ServerInfo -> ServerInfo) - | AddRoom B.ByteString B.ByteString + | AddRoom String String | CheckRegistered | ClearAccountsCache | ProcessAccountInfo AccountInfo | Dump | AddClient ClientInfo - | DeleteClient ClientIndex | PingAll | StatsAction -type CmdHandler = [B.ByteString] -> Reader (ClientIndex, IRnC) [Action] +type CmdHandler = Int -> Clients -> Rooms -> [String] -> [Action] + +replaceID a (b, c, d, e) = (a, c, d, e) + +processAction :: (Int, ServerInfo, Clients, Rooms) -> Action -> IO (Int, ServerInfo, Clients, Rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerThisClient msg) = do + writeChan (sendChan $ clients ! clID) msg + return (clID, serverInfo, clients, rooms) -processAction :: Action -> StateT ServerState IO () +processAction (clID, serverInfo, clients, rooms) (AnswerAll msg) = do + mapM_ (\cl -> writeChan (sendChan cl) msg) (elems clients) + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerAllOthers msg) = do + mapM_ (\id' -> writeChan (sendChan $ clients ! id') msg) $ + Prelude.filter (\id' -> (id' /= clID) && logonPassed (clients ! id')) (keys clients) + return (clID, serverInfo, clients, rooms) + + +processAction (clID, serverInfo, clients, rooms) (AnswerThisRoom msg) = do + mapM_ (\id' -> writeChan (sendChan $ clients ! id') msg) roomClients + return (clID, serverInfo, clients, rooms) + where + roomClients = IntSet.elems $ playersIDs room + room = rooms ! rID + rID = roomID client + client = clients ! clID -processAction (AnswerClients chans msg) = do - liftIO $ map (flip seq ()) chans `seq` map (flip seq ()) msg `seq` mapM_ (flip writeChan msg) chans +processAction (clID, serverInfo, clients, rooms) (AnswerOthersInRoom msg) = do + mapM_ (\id' -> writeChan (sendChan $ clients ! id') msg) $ Prelude.filter (/= clID) roomClients + return (clID, serverInfo, clients, rooms) + where + roomClients = IntSet.elems $ playersIDs room + room = rooms ! rID + rID = roomID client + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (AnswerLobby msg) = do + mapM_ (\id' -> writeChan (sendChan $ clients ! id') msg) roomClients + return (clID, serverInfo, clients, rooms) + where + roomClients = IntSet.elems $ playersIDs room + room = rooms ! 0 -processAction SendServerMessage = do - chan <- client's sendChan - protonum <- client's clientProto - si <- liftM serverInfo get - let message = if protonum < latestReleaseVersion si then +processAction (clID, serverInfo, clients, rooms) (AnswerSameClan msg) = do + mapM_ (\cl -> writeChan (sendChan cl) msg) sameClanOrSpec + return (clID, serverInfo, clients, rooms) + where + otherRoomClients = Prelude.map ((!) clients) $ IntSet.elems $ clID `IntSet.delete` (playersIDs room) + sameClanOrSpec = if teamsInGame client > 0 then sameClanClients else spectators + spectators = Prelude.filter (\cl -> teamsInGame cl == 0) otherRoomClients + sameClanClients = Prelude.filter (\cl -> teamsInGame cl > 0 && clientClan cl == thisClan) otherRoomClients + thisClan = clientClan client + room = rooms ! rID + rID = roomID client + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) SendServerMessage = do + writeChan (sendChan $ clients ! clID) ["SERVER_MESSAGE", message serverInfo] + return (clID, serverInfo, clients, rooms) + where + client = clients ! clID + message si = if clientProto client < latestReleaseVersion si then serverMessageForOldVersions si else serverMessage si - processAction $ AnswerClients [chan] ["SERVER_MESSAGE", message] -{- -processAction (clID, serverInfo, rnc) SendServerVars = do +processAction (clID, serverInfo, clients, rooms) SendServerVars = do writeChan (sendChan $ clients ! clID) ("SERVER_VARS" : vars) - return (clID, serverInfo, rnc) + return (clID, serverInfo, clients, rooms) where client = clients ! clID vars = [ - "MOTD_NEW", serverMessage serverInfo, - "MOTD_OLD", serverMessageForOldVersions serverInfo, + "MOTD_NEW", serverMessage serverInfo, + "MOTD_OLD", serverMessageForOldVersions serverInfo, "LATEST_PROTO", show $ latestReleaseVersion serverInfo ] --} +processAction (clID, serverInfo, clients, rooms) (ProtocolError msg) = do + writeChan (sendChan $ clients ! clID) ["ERROR", msg] + return (clID, serverInfo, clients, rooms) -processAction (ProtocolError msg) = do - chan <- client's sendChan - processAction $ AnswerClients [chan] ["ERROR", msg] + +processAction (clID, serverInfo, clients, rooms) (Warning msg) = do + writeChan (sendChan $ clients ! clID) ["WARNING", msg] + return (clID, serverInfo, clients, rooms) -processAction (Warning msg) = do - chan <- client's sendChan - processAction $ AnswerClients [chan] ["WARNING", msg] - -processAction (ByeClient msg) = do - (Just ci) <- gets clientIndex - rnc <- gets roomsClients - ri <- clientRoomA - - chan <- client's sendChan - ready <- client's isReady +processAction (clID, serverInfo, clients, rooms) (ByeClient msg) = do + infoM "Clients" (show (clientUID client) ++ " quits: " ++ msg) + (_, _, newClients, newRooms) <- + if roomID client /= 0 then + processAction (clID, serverInfo, clients, rooms) $ RoomRemoveThisClient "quit" + else + return (clID, serverInfo, clients, rooms) - when (ri /= lobbyId) $ do - processAction $ MoveToLobby ("quit: " `B.append` msg) - liftIO $ modifyRoom rnc (\r -> r{ - --playersIDs = IntSet.delete ci (playersIDs r) - playersIn = (playersIn r) - 1, - readyPlayers = if ready then readyPlayers r - 1 else readyPlayers r - }) ri - return () - - liftIO $ do - infoM "Clients" (show ci ++ " quits: " ++ (B.unpack msg)) - - --mapM_ (processAction (ci, serverInfo, rnc)) $ answerOthersQuit ++ answerInformRoom - - processAction $ AnswerClients [chan] ["BYE", msg] - - s <- get - put $! s{removedClients = ci `Set.insert` removedClients s} - -processAction (DeleteClient ci) = do - rnc <- gets roomsClients - liftIO $ removeClient rnc ci - - s <- get - put $! s{removedClients = ci `Set.delete` removedClients s} - -{- + mapM_ (processAction (clID, serverInfo, newClients, newRooms)) $ answerOthersQuit ++ answerInformRoom + writeChan (sendChan $ clients ! clID) ["BYE", msg] + return ( + 0, + serverInfo, + delete clID newClients, + adjust (\r -> r{ + playersIDs = IntSet.delete clID (playersIDs r), + playersIn = (playersIn r) - 1, + readyPlayers = if isReady client then readyPlayers r - 1 else readyPlayers r + }) (roomID $ newClients ! clID) newRooms + ) where client = clients ! clID clientNick = nick client @@ -147,57 +184,46 @@ else [AnswerAll ["LOBBY:LEFT", clientNick]] else - [] --} + [] + + +processAction (clID, serverInfo, clients, rooms) (ModifyClient func) = + return (clID, serverInfo, adjust func clID clients, rooms) + -processAction (ModifyClient f) = do - (Just ci) <- gets clientIndex - rnc <- gets roomsClients - liftIO $ modifyClient rnc f ci - return () +processAction (clID, serverInfo, clients, rooms) (ModifyClient2 cl2ID func) = + return (clID, serverInfo, adjust func cl2ID clients, rooms) + -processAction (ModifyClient2 ci f) = do - rnc <- gets roomsClients - liftIO $ modifyClient rnc f ci - return () +processAction (clID, serverInfo, clients, rooms) (ModifyRoom func) = + return (clID, serverInfo, clients, adjust func rID rooms) + where + rID = roomID $ clients ! clID -processAction (ModifyRoom f) = do - rnc <- gets roomsClients - ri <- clientRoomA - liftIO $ modifyRoom rnc f ri - return () +processAction (clID, serverInfo, clients, rooms) (ModifyServerInfo func) = + return (clID, func serverInfo, clients, rooms) -{- - -processAction (clID, serverInfo, rnc) (ModifyServerInfo func) = - return (clID, func serverInfo, rnc) - --} -processAction (MoveToRoom ri) = do - (Just ci) <- gets clientIndex - rnc <- gets roomsClients - liftIO $ do - modifyClient rnc (\cl -> cl{teamsInGame = 0}) ci - modifyRoom rnc (\r -> r{playersIn = (playersIn r) + 1}) ri - - liftIO $ moveClientToRoom rnc ri ci - - chans <- liftM (map sendChan) $ roomClientsS ri - clNick <- client's nick +processAction (clID, serverInfo, clients, rooms) (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 $ AnswerClients chans ["JOINED", clNick] -processAction (MoveToLobby msg) = do - (Just ci) <- gets clientIndex - --ri <- clientRoomA - rnc <- gets roomsClients - - liftIO $ moveClientToLobby rnc ci - -{- +processAction (clID, serverInfo, clients, rooms) (RoomRemoveThisClient msg) = do (_, _, newClients, newRooms) <- + if roomID client /= 0 then if isMaster client then if (gameinprogress room) && (playersIn room > 1) then (changeMaster >>= (\state -> foldM processAction state @@ -205,15 +231,16 @@ AnswerOthersInRoom ["WARNING", "Admin left the room"], RemoveClientTeams clID])) else -- not in game - processAction (clID, serverInfo, rnc) RemoveRoom + processAction (clID, serverInfo, clients, rooms) RemoveRoom else -- not master foldM processAction - (clID, serverInfo, rnc) + (clID, serverInfo, clients, rooms) [AnswerOthersInRoom ["LEFT", nick client, msg], RemoveClientTeams clID] - - + else -- in lobby + return (clID, serverInfo, clients, rooms) + return ( clID, serverInfo, @@ -232,7 +259,7 @@ } insertClientToRoom r = r{playersIDs = IntSet.insert clID (playersIDs r)} changeMaster = do - processAction (newMasterId, serverInfo, rnc) $ AnswerThisClient ["ROOM_CONTROL_ACCESS", "1"] + processAction (newMasterId, serverInfo, clients, rooms) $ AnswerThisClient ["ROOM_CONTROL_ACCESS", "1"] return ( clID, serverInfo, @@ -243,35 +270,34 @@ otherPlayersSet = IntSet.delete clID (playersIDs room) newMasterId = IntSet.findMin otherPlayersSet newMasterClient = clients ! newMasterId --} + -processAction (AddRoom roomName roomPassword) = do - Just clId <- gets clientIndex - rnc <- gets roomsClients - proto <- liftIO $ client'sM rnc clientProto clId - +processAction (clID, serverInfo, clients, rooms) (AddRoom roomName roomPassword) = do + let newServerInfo = serverInfo {nextRoomID = newID} let room = newRoom{ - masterID = clId, + roomUID = newID, + masterID = clID, name = roomName, password = roomPassword, - roomProto = proto + roomProto = (clientProto client) } - rId <- liftIO $ addRoom rnc room - - processAction $ MoveToRoom rId - - chans <- liftM (map sendChan) $! roomClientsS lobbyId + processAction (clID, serverInfo, clients, rooms) $ AnswerLobby ["ROOM", "ADD", roomName] - mapM_ processAction [ - AnswerClients chans ["ROOM", "ADD", roomName] - , ModifyClient (\cl -> cl{isMaster = True}) - ] + processAction ( + clID, + newServerInfo, + adjust (\cl -> cl{isMaster = True}) clID clients, + insert newID room rooms + ) $ RoomAddThisClient newID + where + newID = (nextRoomID serverInfo) - 1 + client = clients ! clID -{- -processAction (clID, serverInfo, rnc) (RemoveRoom) = do - processAction (clID, serverInfo, rnc) $ AnswerLobby ["ROOM", "DEL", name room] - processAction (clID, serverInfo, rnc) $ AnswerOthersInRoom ["ROOMABANDONED", name room] + +processAction (clID, serverInfo, clients, rooms) (RemoveRoom) = do + processAction (clID, serverInfo, clients, rooms) $ AnswerLobby ["ROOM", "DEL", name room] + processAction (clID, serverInfo, clients, rooms) $ AnswerOthersInRoom ["ROOMABANDONED", name room] return (clID, serverInfo, Data.IntMap.map (\cl -> if roomID cl == rID then cl{roomID = 0, isMaster = False, isReady = False, teamsInGame = undefined} else cl) clients, @@ -282,163 +308,139 @@ rID = roomID client client = clients ! clID --} -processAction (UnreadyRoomClients) = do - rnc <- gets roomsClients - ri <- clientRoomA - roomPlayers <- roomClientsS ri - roomClIDs <- liftIO $ roomClientsIndicesM rnc ri - processAction $ AnswerClients (map sendChan roomPlayers) ("NOT_READY" : map nick roomPlayers) - liftIO $ mapM_ (modifyClient rnc (\cl -> cl{isReady = False})) roomClIDs - processAction $ ModifyRoom (\r -> r{readyPlayers = 0}) + +processAction (clID, serverInfo, clients, rooms) (UnreadyRoomClients) = do + processAction (clID, serverInfo, clients, rooms) $ AnswerThisRoom ("NOT_READY" : roomPlayers) + return (clID, + serverInfo, + Data.IntMap.map (\cl -> if roomID cl == rID then cl{isReady = False} else cl) clients, + adjust (\r -> r{readyPlayers = 0}) rID rooms) + where + room = rooms ! rID + rID = roomID client + client = clients ! clID + roomPlayers = Prelude.map (nick . (clients !)) roomPlayersIDs + roomPlayersIDs = IntSet.elems $ playersIDs room -processAction (RemoveTeam teamName) = do - rnc <- gets roomsClients - cl <- client's id - ri <- clientRoomA - inGame <- liftIO $ room'sM rnc gameinprogress ri - chans <- liftM (map sendChan . filter (/= cl)) $ roomClientsS ri - if inGame then - mapM_ processAction [ - AnswerClients chans ["REMOVE_TEAM", teamName], - ModifyRoom (\r -> r{teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r}) - ] +processAction (clID, serverInfo, clients, rooms) (RemoveTeam teamName) = do + newRooms <- if not $ gameinprogress room then + do + processAction (clID, serverInfo, clients, rooms) $ AnswerOthersInRoom ["REMOVE_TEAM", teamName] + return $ + adjust (\r -> r{teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r}) rID rooms 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 - }) - ] + do + processAction (clID, serverInfo, clients, rooms) $ AnswerOthersInRoom ["EM", rmTeamMsg] + return $ + adjust (\r -> r{ + teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r, + leftTeams = teamName : leftTeams r, + roundMsgs = roundMsgs r Seq.|> rmTeamMsg + }) rID rooms + return (clID, serverInfo, clients, newRooms) where - rmTeamMsg = toEngineMsg $ (B.singleton 'F') `B.append` teamName + room = rooms ! rID + rID = roomID client + client = clients ! clID + rmTeamMsg = toEngineMsg $ 'F' : teamName -processAction CheckRegistered = do - (Just ci) <- gets clientIndex - n <- client's nick - h <- client's host - db <- gets (dbQueries . serverInfo) - liftIO $ writeChan db $ CheckAccount ci n h - return () -{- -processAction (clID, serverInfo, rnc) (ClearAccountsCache) = do - writeChan (dbQueries serverInfo) ClearCache - return (clID, serverInfo, rnc) +processAction (clID, serverInfo, clients, rooms) (CheckRegistered) = do + writeChan (dbQueries serverInfo) $ CheckAccount (clientUID client) (nick client) (host client) + return (clID, serverInfo, clients, rooms) where client = clients ! clID -processAction (clID, serverInfo, rnc) (Dump) = do +processAction (clID, serverInfo, clients, rooms) (ClearAccountsCache) = do + writeChan (dbQueries serverInfo) ClearCache + return (clID, serverInfo, clients, rooms) + where + client = clients ! clID + + +processAction (clID, serverInfo, clients, rooms) (Dump) = do writeChan (sendChan $ clients ! clID) ["DUMP", show serverInfo, showTree clients, showTree rooms] - return (clID, serverInfo, rnc) --} + return (clID, serverInfo, clients, rooms) -processAction (ProcessAccountInfo info) = + +processAction (clID, serverInfo, clients, rooms) (ProcessAccountInfo info) = case info of HasAccount passwd isAdmin -> do - chan <- client's sendChan - processAction $ AnswerClients [chan] ["ASKPASSWORD"] + infoM "Clients" $ show clID ++ " has account" + writeChan (sendChan $ clients ! clID) ["ASKPASSWORD"] + return (clID, serverInfo, adjust (\cl -> cl{webPassword = passwd, isAdministrator = isAdmin}) clID clients, rooms) Guest -> do - processAction JoinLobby + infoM "Clients" $ show clID ++ " is guest" + processAction (clID, serverInfo, adjust (\cl -> cl{logonPassed = True}) clID clients, rooms) MoveToLobby Admin -> do - mapM processAction [ModifyClient (\cl -> cl{isAdministrator = True}), JoinLobby] - chan <- client's sendChan - processAction $ AnswerClients [chan] ["ADMIN_ACCESS"] + infoM "Clients" $ show clID ++ " is admin" + foldM processAction (clID, serverInfo, adjust (\cl -> cl{logonPassed = True, isAdministrator = True}) clID clients, rooms) [MoveToLobby, AnswerThisClient ["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, clients, rooms) (MoveToLobby) = + foldM processAction (clID, serverInfo, clients, rooms) $ + (RoomAddThisClient 0) + : answerLobbyNicks + ++ [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 + -- ++ (answerServerMessage client clients) 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") + lobbyNicks = Prelude.map nick $ Prelude.filter logonPassed $ elems clients + answerLobbyNicks = [AnswerThisClient ("LOBBY:JOINED": lobbyNicks) | not $ Prelude.null lobbyNicks] -processAction (clID, serverInfo, rnc) (BanClient banNick) = - return (clID, serverInfo, rnc) +processAction (clID, serverInfo, clients, rooms) (KickClient kickID) = + liftM2 replaceID (return clID) (processAction (kickID, serverInfo, clients, rooms) $ ByeClient "Kicked") + + +processAction (clID, serverInfo, clients, rooms) (BanClient banNick) = + return (clID, serverInfo, clients, rooms) -processAction (clID, serverInfo, rnc) (KickRoomClient kickID) = do +processAction (clID, serverInfo, clients, rooms) (KickRoomClient kickID) = do writeChan (sendChan $ clients ! kickID) ["KICKED"] - liftM2 replaceID (return clID) (processAction (kickID, serverInfo, rnc) $ RoomRemoveThisClient "kicked") + liftM2 replaceID (return clID) (processAction (kickID, serverInfo, clients, rooms) $ RoomRemoveThisClient "kicked") -processAction (clID, serverInfo, rnc) (RemoveClientTeams teamsClID) = +processAction (clID, serverInfo, clients, rooms) (RemoveClientTeams teamsClID) = liftM2 replaceID (return clID) $ - foldM processAction (teamsClID, serverInfo, rnc) removeTeamsActions + foldM processAction (teamsClID, serverInfo, clients, rooms) removeTeamsActions where client = clients ! teamsClID room = rooms ! (roomID client) teamsToRemove = Prelude.filter (\t -> teamowner t == nick client) $ teams room removeTeamsActions = Prelude.map (RemoveTeam . teamname) teamsToRemove --} + -processAction (AddClient client) = do - rnc <- gets roomsClients - si <- gets serverInfo - liftIO $ do - ci <- addClient rnc client - forkIO $ clientRecvLoop (clientSocket client) (coreChan si) ci - forkIO $ clientSendLoop (clientSocket client) (sendChan client) ci +processAction (clID, serverInfo, clients, rooms) (AddClient client) = do + let updatedClients = insert (clientUID client) client clients + infoM "Clients" (show (clientUID client) ++ ": New client. Time: " ++ show (connectTime client)) + writeChan (sendChan client) ["CONNECTED", "Hedgewars server http://www.hedgewars.org/"] - 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 + 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) --} - + if isJust $ host client `Prelude.lookup` newLogins then + processAction (clID, serverInfo{lastLogins = newLogins}, updatedClients, rooms) $ ByeClient "Reconnected too fast" + else + return (clID, serverInfo{lastLogins = (host client, connectTime client) : newLogins}, updatedClients, rooms) -processAction PingAll = do - rnc <- gets roomsClients - liftIO (allClientsM rnc) >>= mapM_ (kickTimeouted rnc) - cis <- liftIO $ allClientsM rnc - chans <- liftIO $ mapM (client'sM rnc sendChan) cis - liftIO $ mapM_ (modifyClient rnc (\cl -> cl{pingsQueue = pingsQueue cl + 1})) cis - processAction $ AnswerClients chans ["PING"] +processAction (clID, serverInfo, clients, rooms) PingAll = do + (_, _, newClients, newRooms) <- foldM kickTimeouted (clID, serverInfo, clients, rooms) $ elems clients + processAction (clID, + serverInfo, + Data.IntMap.map (\cl -> cl{pingsQueue = pingsQueue cl + 1}) newClients, + newRooms) $ AnswerAll ["PING"] where - kickTimeouted rnc ci = do - pq <- liftIO $ client'sM rnc pingsQueue ci - when (pq > 0) $ - withStateT (\as -> as{clientIndex = Just ci}) $ - processAction (ByeClient "Ping timeout") + kickTimeouted (clID, serverInfo, clients, rooms) client = + if pingsQueue client > 0 then + processAction (clientUID client, serverInfo, clients, rooms) $ ByeClient "Ping timeout" + else + return (clID, serverInfo, clients, rooms) -processAction (StatsAction) = do - rnc <- gets roomsClients - si <- gets serverInfo - (roomsNum, clientsNum) <- liftIO $ withRoomsAndClients rnc stats - liftIO $ writeChan (dbQueries si) $ SendStats clientsNum (roomsNum - 1) - where - stats irnc = (length $ allRooms irnc, length $ allClients irnc) - +processAction (clID, serverInfo, clients, rooms) (StatsAction) = do + writeChan (dbQueries serverInfo) $ SendStats (size clients) (size rooms - 1) + return (clID, serverInfo, clients, rooms) diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/CMakeLists.txt --- a/gameServer/CMakeLists.txt Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/CMakeLists.txt Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/ClientIO.hs --- a/gameServer/ClientIO.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/ClientIO.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,4 +1,4 @@ -{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} module ClientIO where import qualified Control.Exception as Exception @@ -6,71 +6,45 @@ import Control.Concurrent import Control.Monad import System.IO -import Network -import Network.Socket.ByteString -import qualified Data.ByteString.Char8 as B +import qualified Data.ByteString.UTF8 as BUTF8 +import qualified Data.ByteString as B ---------------- import CoreTypes -import RoomsAndClients -import Utils - -pDelim :: B.ByteString -pDelim = B.pack "\n\n" - -bs2Packets :: B.ByteString -> ([[B.ByteString]], B.ByteString) -bs2Packets buf = unfoldrE extractPackets buf - where - extractPackets :: B.ByteString -> Either B.ByteString ([B.ByteString], B.ByteString) - extractPackets buf = - let buf' = until (not . B.isPrefixOf pDelim) (B.drop 2) buf in - let (bsPacket, bufTail) = B.breakSubstring pDelim buf' in - if B.null bufTail then - Left bsPacket - else - if B.null bsPacket then - Left bufTail - else - Right (B.splitWith (== '\n') bsPacket, bufTail) - +listenLoop :: Handle -> Int -> [String] -> Chan CoreMessage -> Int -> IO () +listenLoop handle linesNumber buf chan clientID = do + str <- liftM BUTF8.toString $ B.hGetLine handle + if (linesNumber > 50) || (length str > 20000) then + writeChan chan $ ClientMessage (clientID, ["QUIT", "Protocol violation"]) + else + if str == "" then do + writeChan chan $ ClientMessage (clientID, buf) + yield + listenLoop handle 0 [] chan clientID + else + listenLoop handle (linesNumber + 1) (buf ++ [str]) chan clientID -listenLoop :: Socket -> Chan CoreMessage -> ClientIndex -> IO () -listenLoop sock chan ci = recieveWithBufferLoop B.empty - where - recieveWithBufferLoop recvBuf = do - recvBS <- recv sock 4096 --- putStrLn $ show sock ++ " got smth: " ++ (show $ B.length recvBS) - unless (B.null recvBS) $ do - let (packets, newrecvBuf) = bs2Packets $ B.append recvBuf recvBS - forM_ packets sendPacket - recieveWithBufferLoop newrecvBuf - - sendPacket packet = writeChan chan $ ClientMessage (ci, packet) - +clientRecvLoop :: Handle -> Chan CoreMessage -> Int -> IO () +clientRecvLoop handle chan clientID = + listenLoop handle 0 [] chan clientID + `catch` (\e -> clientOff (show e) >> return ()) + where clientOff msg = writeChan chan $ ClientMessage (clientID, ["QUIT", msg]) -- if the client disconnects, we perform as if it sent QUIT message -clientRecvLoop :: Socket -> Chan CoreMessage -> ClientIndex -> IO () -clientRecvLoop s chan ci = do - msg <- (listenLoop s chan ci >> return "Connection closed") `catch` (return . B.pack . show) - clientOff msg - where - clientOff msg = mapM_ (writeChan chan) [ClientMessage (ci, ["QUIT", msg]), Remove ci] - - +clientSendLoop :: Handle -> Chan CoreMessage -> Chan [String] -> Int -> IO() +clientSendLoop handle coreChan chan clientID = do + answer <- readChan chan + doClose <- Exception.handle + (\(e :: Exception.IOException) -> if isQuit answer then return True else sendQuit e >> return False) $ do + B.hPutStrLn handle $ BUTF8.fromString $ unlines answer + hFlush handle + return $ isQuit answer -clientSendLoop :: Socket -> Chan [B.ByteString] -> ClientIndex -> IO () -clientSendLoop s chan ci = do - answer <- readChan chan - Exception.handle - (\(e :: Exception.IOException) -> when (not $ isQuit answer) $ sendQuit e) $ do - sendAll s $ (B.unlines answer) `B.append` (B.singleton '\n') - - if (isQuit answer) then - Exception.handle (\(_ :: Exception.IOException) -> putStrLn "error on sClose") $ sClose s + if doClose then + Exception.handle (\(_ :: Exception.IOException) -> putStrLn "error on hClose") $ hClose handle else - clientSendLoop s chan ci + clientSendLoop handle coreChan chan clientID where - --sendQuit e = writeChan coreChan $ ClientMessage (ci, ["QUIT", B.pack $ show e]) - sendQuit e = putStrLn $ show e + sendQuit e = writeChan coreChan $ ClientMessage (clientID, ["QUIT", show e]) isQuit ("BYE":xs) = True isQuit _ = False diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/CoreTypes.hs --- a/gameServer/CoreTypes.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/CoreTypes.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,4 +1,3 @@ -{-# LANGUAGE OverloadedStrings #-} module CoreTypes where import System.IO @@ -6,95 +5,102 @@ import Control.Concurrent.STM import Data.Word import qualified Data.Map as Map +import qualified Data.IntMap as IntMap import qualified Data.IntSet as IntSet import Data.Sequence(Seq, empty) import Data.Time import Network import Data.Function -import Data.ByteString.Char8 as B -import RoomsAndClients - -type ClientChan = Chan [B.ByteString] data ClientInfo = ClientInfo { - sendChan :: ClientChan, - clientSocket :: Socket, - host :: B.ByteString, + clientUID :: !Int, + sendChan :: Chan [String], + clientHandle :: Handle, + host :: String, connectTime :: UTCTime, - nick :: B.ByteString, - webPassword :: B.ByteString, + nick :: String, + webPassword :: String, logonPassed :: Bool, clientProto :: !Word16, - roomID :: RoomIndex, + roomID :: !Int, pingsQueue :: !Word, isMaster :: Bool, - isReady :: !Bool, + isReady :: Bool, isAdministrator :: Bool, - clientClan :: B.ByteString, + clientClan :: String, teamsInGame :: Word } instance Show ClientInfo where - show ci = " nick: " ++ (unpack $ nick ci) ++ " host: " ++ (unpack $ host ci) + show ci = show (clientUID ci) + ++ " nick: " ++ (nick ci) + ++ " host: " ++ (host ci) instance Eq ClientInfo where - (==) = (==) `on` clientSocket + (==) = (==) `on` clientHandle data HedgehogInfo = - HedgehogInfo B.ByteString B.ByteString + HedgehogInfo String String data TeamInfo = TeamInfo { - teamownerId :: ClientIndex, - teamowner :: B.ByteString, - teamname :: B.ByteString, - teamcolor :: B.ByteString, - teamgrave :: B.ByteString, - teamfort :: B.ByteString, - teamvoicepack :: B.ByteString, - teamflag :: B.ByteString, + teamownerId :: !Int, + teamowner :: String, + teamname :: String, + teamcolor :: String, + teamgrave :: String, + teamfort :: String, + teamvoicepack :: String, + teamflag :: String, difficulty :: Int, hhnum :: Int, hedgehogs :: [HedgehogInfo] } instance Show TeamInfo where - show ti = "owner: " ++ (unpack $ teamowner ti) - ++ "name: " ++ (unpack $ teamname ti) - ++ "color: " ++ (unpack $ teamcolor ti) + show ti = "owner: " ++ (teamowner ti) + ++ "name: " ++ (teamname ti) + ++ "color: " ++ (teamcolor ti) data RoomInfo = RoomInfo { - masterID :: ClientIndex, - name :: B.ByteString, - password :: B.ByteString, + roomUID :: !Int, + masterID :: !Int, + name :: String, + password :: String, roomProto :: Word16, teams :: [TeamInfo], gameinprogress :: Bool, playersIn :: !Int, readyPlayers :: !Int, + playersIDs :: IntSet.IntSet, isRestrictedJoins :: Bool, isRestrictedTeams :: Bool, - roundMsgs :: Seq B.ByteString, - leftTeams :: [B.ByteString], + roundMsgs :: Seq String, + leftTeams :: [String], teamsAtStart :: [TeamInfo], - params :: Map.Map B.ByteString [B.ByteString] + params :: Map.Map String [String] } instance Show RoomInfo where - show ri = ", players: " ++ show (playersIn ri) + show ri = show (roomUID ri) + ++ ", players ids: " ++ show (IntSet.size $ playersIDs ri) + ++ ", players: " ++ show (playersIn ri) ++ ", ready: " ++ show (readyPlayers ri) ++ ", teams: " ++ show (teams ri) -newRoom :: RoomInfo +instance Eq RoomInfo where + (==) = (==) `on` roomUID + newRoom = ( RoomInfo - undefined + 0 + 0 "" "" 0 @@ -102,6 +108,7 @@ False 0 0 + IntSet.empty False False Data.Sequence.empty @@ -121,30 +128,29 @@ ServerInfo { isDedicated :: Bool, - serverMessage :: B.ByteString, - serverMessageForOldVersions :: B.ByteString, + serverMessage :: String, + serverMessageForOldVersions :: String, latestReleaseVersion :: Word16, listenPort :: PortNumber, nextRoomID :: Int, - dbHost :: B.ByteString, - dbLogin :: B.ByteString, - dbPassword :: B.ByteString, - lastLogins :: [(B.ByteString, UTCTime)], + dbHost :: String, + dbLogin :: String, + dbPassword :: String, + lastLogins :: [(String, UTCTime)], stats :: TMVar StatisticsInfo, coreChan :: Chan CoreMessage, dbQueries :: Chan DBQuery } instance Show ServerInfo where - show _ = "Server Info" + show si = "Server Info" -newServerInfo :: TMVar StatisticsInfo -> Chan CoreMessage -> Chan DBQuery -> ServerInfo newServerInfo = ( ServerInfo True "

http://www.hedgewars.org/

" - "

Hedgewars 0.9.14.1 is out! Please update.

Download page here" - 35 + "

Hedgewars 0.9.15 is out! Please update.

Download page here" + 37 46631 0 "" @@ -154,31 +160,29 @@ ) data AccountInfo = - HasAccount B.ByteString Bool + HasAccount String Bool | Guest | Admin deriving (Show, Read) data DBQuery = - CheckAccount ClientIndex B.ByteString B.ByteString + CheckAccount Int String String | ClearCache | SendStats Int Int deriving (Show, Read) data CoreMessage = Accept ClientInfo - | ClientMessage (ClientIndex, [B.ByteString]) - | ClientAccountInfo (ClientIndex, AccountInfo) + | ClientMessage (Int, [String]) + | ClientAccountInfo (Int, AccountInfo) | TimerAction Int - | Remove ClientIndex + +type Clients = IntMap.IntMap ClientInfo +type Rooms = IntMap.IntMap RoomInfo -instance Show CoreMessage where - show (Accept _) = "Accept" - show (ClientMessage _) = "ClientMessage" - show (ClientAccountInfo _) = "ClientAccountInfo" - show (TimerAction _) = "TimerAction" - show (Remove _) = "Remove" - -type MRnC = MRoomsAndClients RoomInfo ClientInfo -type IRnC = IRoomsAndClients RoomInfo ClientInfo +--type ClientsTransform = [ClientInfo] -> [ClientInfo] +--type RoomsTransform = [RoomInfo] -> [RoomInfo] +--type HandlesSelector = ClientInfo -> [ClientInfo] -> [RoomInfo] -> [ClientInfo] +--type Answer = ServerInfo -> (HandlesSelector, [String]) +type ClientsSelector = Clients -> Rooms -> [Int] diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/HWProtoCore.hs --- a/gameServer/HWProtoCore.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/HWProtoCore.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,10 +1,8 @@ -{-# LANGUAGE OverloadedStrings #-} module HWProtoCore where import qualified Data.IntMap as IntMap import Data.Foldable import Data.Maybe -import Control.Monad.Reader -------------------------------------- import CoreTypes import Actions @@ -12,37 +10,35 @@ import HWProtoNEState import HWProtoLobbyState import HWProtoInRoomState -import HandlerUtils -import RoomsAndClients handleCmd, handleCmd_loggedin :: CmdHandler - -handleCmd ["PING"] = answerClient ["PONG"] +handleCmd clID _ _ ["PING"] = [AnswerThisClient ["PONG"]] - -handleCmd ("QUIT" : xs) = return [ByeClient msg] +handleCmd clID clients rooms ("QUIT" : xs) = + [ByeClient msg] where msg = if not $ null xs then head xs else "" -{- -handleCmd ["PONG"] = + +handleCmd clID clients _ ["PONG"] = if pingsQueue client == 0 then [ProtocolError "Protocol violation"] else [ModifyClient (\cl -> cl{pingsQueue = pingsQueue cl - 1})] where client = clients IntMap.! clID --} + -handleCmd cmd = do - (ci, irnc) <- ask - if logonPassed (irnc `client` ci) then - handleCmd_loggedin cmd - else - handleCmd_NotEntered cmd +handleCmd clID clients rooms cmd = + if not $ logonPassed client then + handleCmd_NotEntered clID clients rooms cmd + else + handleCmd_loggedin clID clients rooms cmd + where + client = clients IntMap.! clID -{- + handleCmd_loggedin clID clients rooms ["INFO", asknick] = if noSuchClient then [] @@ -66,12 +62,11 @@ then if teamsInGame client > 0 then "(playing)" else "(spectating)" else "" --} - -handleCmd_loggedin cmd = do - (ci, rnc) <- ask - if clientRoom rnc ci == lobbyId then - handleCmd_lobby cmd - else - handleCmd_inRoom cmd +handleCmd_loggedin clID clients rooms cmd = + if roomID client == 0 then + handleCmd_lobby clID clients rooms cmd + else + handleCmd_inRoom clID clients rooms cmd + where + client = clients IntMap.! clID diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/HWProtoInRoomState.hs --- a/gameServer/HWProtoInRoomState.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/HWProtoInRoomState.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,240 +1,182 @@ -{-# LANGUAGE OverloadedStrings #-} module HWProtoInRoomState where import qualified Data.Foldable as Foldable +import qualified Data.IntMap as IntMap import qualified Data.Map as Map import Data.Sequence(Seq, (|>), (><), fromList, empty) import Data.List import Data.Maybe -import qualified Data.ByteString.Char8 as B -import Control.Monad -import Control.Monad.Reader -------------------------------------- import CoreTypes import Actions import Utils -import HandlerUtils -import RoomsAndClients + handleCmd_inRoom :: CmdHandler -handleCmd_inRoom ["CHAT", msg] = do - n <- clientNick - s <- roomOthersChans - return [AnswerClients s ["CHAT", n, msg]] +handleCmd_inRoom clID clients _ ["CHAT", msg] = + [AnswerOthersInRoom ["CHAT", clientNick, msg]] + where + clientNick = nick $ clients IntMap.! clID -handleCmd_inRoom ["PART"] = return [MoveToLobby "part"] -handleCmd_inRoom ["PART", msg] = return [MoveToLobby $ "part: " `B.append` msg] +handleCmd_inRoom clID clients rooms ["PART"] = + [RoomRemoveThisClient "part"] + where + client = clients IntMap.! clID -handleCmd_inRoom ("CFG" : paramName : paramStrs) - | null paramStrs = return [ProtocolError "Empty config entry"] - | otherwise = do - chans <- roomOthersChans - cl <- thisClient - if isMaster cl then - return [ - ModifyRoom (\r -> r{params = Map.insert paramName paramStrs (params r)}), - AnswerClients chans ("CFG" : paramName : paramStrs)] - else - return [ProtocolError "Not room master"] +handleCmd_inRoom clID clients rooms ("CFG" : paramName : paramStrs) + | null paramStrs = [ProtocolError "Empty config entry"] + | isMaster client = + [ModifyRoom (\r -> r{params = Map.insert paramName paramStrs (params r)}), + AnswerOthersInRoom ("CFG" : paramName : paramStrs)] + | otherwise = [ProtocolError "Not room master"] + where + client = clients IntMap.! clID -handleCmd_inRoom ("ADD_TEAM" : name : color : grave : fort : voicepack : flag : difStr : hhsInfo) - | length hhsInfo /= 16 = return [ProtocolError "Corrupted hedgehogs info"] - | otherwise = do - (ci, rnc) <- ask - r <- thisRoom - clNick <- clientNick - clChan <- thisClientChans - othersChans <- roomOthersChans - return $ - if not . null . drop 5 $ teams r then - [Warning "too many teams"] - else if canAddNumber r <= 0 then - [Warning "too many hedgehogs"] - else if isJust $ findTeam r then - [Warning "There's already a team with same name in the list"] - else if gameinprogress r then - [Warning "round in progress"] - else if isRestrictedTeams r then - [Warning "restricted"] - else - [ModifyRoom (\r -> r{teams = teams r ++ [newTeam ci clNick r]}), - ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = color}), - AnswerClients clChan ["TEAM_ACCEPTED", name], - AnswerClients othersChans $ teamToNet $ newTeam ci clNick r, - AnswerClients othersChans ["TEAM_COLOR", name, color] - ] - where - canAddNumber r = 48 - (sum . map hhnum $ teams r) - findTeam = find (\t -> name == teamname t) . teams - newTeam ci clNick r = (TeamInfo ci clNick name color grave fort voicepack flag difficulty (newTeamHHNum r) (hhsList hhsInfo)) - difficulty = case B.readInt difStr of - Just (i, t) | B.null t -> fromIntegral i - otherwise -> 0 +handleCmd_inRoom clID clients rooms ("ADD_TEAM" : name : color : grave : fort : voicepack : flag : difStr : hhsInfo) + | length hhsInfo == 15 && clientProto client < 30 = handleCmd_inRoom clID clients rooms ("ADD_TEAM" : name : color : grave : fort : voicepack : " " : flag : difStr : hhsInfo) + | length hhsInfo /= 16 = [ProtocolError "Corrupted hedgehogs info"] + | length (teams room) == 8 = [Warning "too many teams"] + | canAddNumber <= 0 = [Warning "too many hedgehogs"] + | isJust findTeam = [Warning "There's already a team with same name in the list"] + | gameinprogress room = [Warning "round in progress"] + | isRestrictedTeams room = [Warning "restricted"] + | otherwise = + [ModifyRoom (\r -> r{teams = teams r ++ [newTeam]}), + ModifyClient (\c -> c{teamsInGame = teamsInGame c + 1, clientClan = color}), + AnswerThisClient ["TEAM_ACCEPTED", name], + AnswerOthersInRoom $ teamToNet (clientProto client) newTeam, + AnswerOthersInRoom ["TEAM_COLOR", name, color] + ] + where + client = clients IntMap.! clID + room = rooms IntMap.! (roomID client) + canAddNumber = 48 - (sum . map hhnum $ teams room) + findTeam = find (\t -> name == teamname t) $ teams room + newTeam = (TeamInfo clID (nick client) name color grave fort voicepack flag difficulty newTeamHHNum (hhsList hhsInfo)) + difficulty = fromMaybe 0 (maybeRead difStr :: Maybe Int) hhsList [] = [] - hhsList [_] = error "Hedgehogs list with odd elements number" hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs - newTeamHHNum r = min 4 (canAddNumber r) - -handleCmd_inRoom ["REMOVE_TEAM", name] = do - (ci, rnc) <- ask - r <- thisRoom - clNick <- clientNick - - let maybeTeam = findTeam r - let team = fromJust maybeTeam + newTeamHHNum = min 4 canAddNumber - return $ - if isNothing $ findTeam r then - [Warning "REMOVE_TEAM: no such team"] - else if clNick /= teamowner team then - [ProtocolError "Not team owner!"] - else - [RemoveTeam name, - ModifyClient - (\c -> c{ - teamsInGame = teamsInGame c - 1, - clientClan = if teamsInGame c == 1 then undefined else anotherTeamClan ci r - }) - ] +handleCmd_inRoom clID clients rooms ["REMOVE_TEAM", teamName] + | noSuchTeam = [Warning "REMOVE_TEAM: no such team"] + | nick client /= teamowner team = [ProtocolError "Not team owner!"] + | otherwise = + [RemoveTeam teamName, + ModifyClient (\c -> c{teamsInGame = teamsInGame c - 1, clientClan = if teamsInGame client == 1 then undefined else anotherTeamClan}) + ] where - anotherTeamClan ci = teamcolor . fromJust . find (\t -> teamownerId t == ci) . teams - findTeam = find (\t -> name == teamname t) . teams + client = clients IntMap.! clID + room = rooms IntMap.! (roomID client) + noSuchTeam = isNothing findTeam + team = fromJust findTeam + findTeam = find (\t -> teamName == teamname t) $ teams room + anotherTeamClan = teamcolor $ fromJust $ find (\t -> teamownerId t == clID) $ teams room -handleCmd_inRoom ["HH_NUM", teamName, numberStr] = do - cl <- thisClient - others <- roomOthersChans - r <- thisRoom - - let maybeTeam = findTeam r - let team = fromJust maybeTeam - - return $ - if not $ isMaster cl then - [ProtocolError "Not room master"] - else if hhNumber < 1 || hhNumber > 8 || isNothing maybeTeam || hhNumber > (canAddNumber r) + (hhnum team) then - [] - else - [ModifyRoom $ modifyTeam team{hhnum = hhNumber}, - AnswerClients others ["HH_NUM", teamName, B.pack $ show hhNumber]] +handleCmd_inRoom clID clients rooms ["HH_NUM", teamName, numberStr] + | not $ isMaster client = [ProtocolError "Not room master"] + | hhNumber < 1 || hhNumber > 8 || noSuchTeam || hhNumber > (canAddNumber + (hhnum team)) = [] + | otherwise = + [ModifyRoom $ modifyTeam team{hhnum = hhNumber}, + AnswerOthersInRoom ["HH_NUM", teamName, show hhNumber]] where - hhNumber = case B.readInt numberStr of - Just (i, t) | B.null t -> fromIntegral i - otherwise -> 0 - findTeam = find (\t -> teamName == teamname t) . teams - canAddNumber = (-) 48 . sum . map hhnum . teams - + client = clients IntMap.! clID + room = rooms IntMap.! (roomID client) + hhNumber = fromMaybe 0 (maybeRead numberStr :: Maybe Int) + noSuchTeam = isNothing findTeam + team = fromJust findTeam + findTeam = find (\t -> teamName == teamname t) $ teams room + canAddNumber = 48 - (sum . map hhnum $ teams room) -handleCmd_inRoom ["TEAM_COLOR", teamName, newColor] = do - cl <- thisClient - others <- roomOthersChans - r <- thisRoom - - let maybeTeam = findTeam r - let team = fromJust maybeTeam - - return $ - if not $ isMaster cl then - [ProtocolError "Not room master"] - else if isNothing maybeTeam then - [] - else - [ModifyRoom $ modifyTeam team{teamcolor = newColor}, - AnswerClients others ["TEAM_COLOR", teamName, newColor], +handleCmd_inRoom clID clients rooms ["TEAM_COLOR", teamName, newColor] + | not $ isMaster client = [ProtocolError "Not room master"] + | noSuchTeam = [] + | otherwise = [ModifyRoom $ modifyTeam team{teamcolor = newColor}, + AnswerOthersInRoom ["TEAM_COLOR", teamName, newColor], ModifyClient2 (teamownerId team) (\c -> c{clientClan = newColor})] where - findTeam = find (\t -> teamName == teamname t) . teams + noSuchTeam = isNothing findTeam + team = fromJust findTeam + findTeam = find (\t -> teamName == teamname t) $ teams room + client = clients IntMap.! clID + room = rooms IntMap.! (roomID client) -handleCmd_inRoom ["TOGGLE_READY"] = do - cl <- thisClient - chans <- roomClientsChans - return [ - ModifyClient (\c -> c{isReady = not $ isReady cl}), - ModifyRoom (\r -> r{readyPlayers = readyPlayers r + (if isReady cl then -1 else 1)}), - AnswerClients chans [if isReady cl then "NOT_READY" else "READY", nick cl] - ] +handleCmd_inRoom clID clients rooms ["TOGGLE_READY"] = + [ModifyClient (\c -> c{isReady = not $ isReady client}), + ModifyRoom (\r -> r{readyPlayers = readyPlayers r + (if isReady client then -1 else 1)}), + AnswerThisRoom [if isReady client then "NOT_READY" else "READY", nick client]] + where + client = clients IntMap.! clID -handleCmd_inRoom ["START_GAME"] = do - cl <- thisClient - r <- thisRoom - chans <- roomClientsChans - if isMaster cl && (playersIn r == readyPlayers r) && (not $ gameinprogress r) then - if enoughClans r then - return [ - ModifyRoom +handleCmd_inRoom clID clients rooms ["START_GAME"] = + if isMaster client && (playersIn room == readyPlayers room) && (not . gameinprogress) room then + if enoughClans then + [ModifyRoom (\r -> r{ gameinprogress = True, roundMsgs = empty, leftTeams = [], teamsAtStart = teams r} ), - AnswerClients chans ["RUN_GAME"] - ] - else - return [Warning "Less than two clans!"] + AnswerThisRoom ["RUN_GAME"]] else - return [] + [Warning "Less than two clans!"] + else + [] where - enoughClans = not . null . drop 1 . group . map teamcolor . teams + client = clients IntMap.! clID + room = rooms IntMap.! (roomID client) + enoughClans = not $ null $ drop 1 $ group $ map teamcolor $ teams room -handleCmd_inRoom ["EM", msg] = do - cl <- thisClient - r <- thisRoom - chans <- roomOthersChans - - if (teamsInGame cl > 0) && isLegal then - return $ (AnswerClients chans ["EM", msg]) : [ModifyRoom (\r -> r{roundMsgs = roundMsgs r |> msg}) | not isKeepAlive] - else - return [] +handleCmd_inRoom clID clients rooms ["EM", msg] = + if (teamsInGame client > 0) && isLegal then + (AnswerOthersInRoom ["EM", msg]) : [ModifyRoom (\r -> r{roundMsgs = roundMsgs r |> msg}) | not isKeepAlive] + else + [] where + client = clients IntMap.! clID (isLegal, isKeepAlive) = checkNetCmd msg - -handleCmd_inRoom ["ROUNDFINISHED"] = do - cl <- thisClient - r <- thisRoom - chans <- roomClientsChans - - if isMaster cl && (gameinprogress r) then - return $ (ModifyRoom +handleCmd_inRoom clID clients rooms ["ROUNDFINISHED"] = + if isMaster client then + [ModifyRoom (\r -> r{ gameinprogress = False, readyPlayers = 0, roundMsgs = empty, leftTeams = [], teamsAtStart = []} - )) - : UnreadyRoomClients - : answerRemovedTeams chans r - else - return [] + ), + UnreadyRoomClients + ] ++ answerRemovedTeams + else + [] where - answerRemovedTeams chans = map (\t -> AnswerClients chans ["REMOVE_TEAM", t]) . leftTeams - -handleCmd_inRoom ["TOGGLE_RESTRICT_JOINS"] = do - cl <- thisClient - return $ - if not $ isMaster cl then - [ProtocolError "Not room master"] - else - [ModifyRoom (\r -> r{isRestrictedJoins = not $ isRestrictedJoins r})] + client = clients IntMap.! clID + room = rooms IntMap.! (roomID client) + answerRemovedTeams = map (\t -> AnswerThisRoom ["REMOVE_TEAM", t]) $ leftTeams room -handleCmd_inRoom ["TOGGLE_RESTRICT_TEAMS"] = do - cl <- thisClient - return $ - if not $ isMaster cl then - [ProtocolError "Not room master"] - else - [ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})] +handleCmd_inRoom clID clients _ ["TOGGLE_RESTRICT_JOINS"] + | isMaster client = [ModifyRoom (\r -> r{isRestrictedJoins = not $ isRestrictedJoins r})] + | otherwise = [ProtocolError "Not room master"] + where + client = clients IntMap.! clID + -{- +handleCmd_inRoom clID clients _ ["TOGGLE_RESTRICT_TEAMS"] + | isMaster client = [ModifyRoom (\r -> r{isRestrictedTeams = not $ isRestrictedTeams r})] + | otherwise = [ProtocolError "Not room master"] + where + client = clients IntMap.! clID + handleCmd_inRoom clID clients rooms ["KICK", kickNick] = [KickRoomClient kickID | isMaster client && not noSuchClient && (kickID /= clID) && (roomID client == roomID kickClient)] where @@ -250,5 +192,5 @@ where client = clients IntMap.! clID engineMsg = toEngineMsg $ 'b' : ((nick client) ++ "(team): " ++ msg ++ "\x20\x20") --} -handleCmd_inRoom _ = return [ProtocolError "Incorrect command (state: in room)"] + +handleCmd_inRoom clID _ _ _ = [ProtocolError "Incorrect command (state: in room)"] diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/HWProtoLobbyState.hs --- a/gameServer/HWProtoLobbyState.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/HWProtoLobbyState.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,102 +1,73 @@ -{-# LANGUAGE OverloadedStrings #-} module HWProtoLobbyState where import qualified Data.Map as Map +import qualified Data.IntMap as IntMap import qualified Data.IntSet as IntSet import qualified Data.Foldable as Foldable import Data.Maybe import Data.List import Data.Word -import Control.Monad.Reader -import qualified Data.ByteString.Char8 as B -------------------------------------- import CoreTypes import Actions import Utils -import HandlerUtils -import RoomsAndClients -{-answerAllTeams protocol teams = concatMap toAnswer teams +answerAllTeams protocol teams = concatMap toAnswer teams where toAnswer team = [AnswerThisClient $ teamToNet protocol team, AnswerThisClient ["TEAM_COLOR", teamname team, teamcolor team], AnswerThisClient ["HH_NUM", teamname team, show $ hhnum team]] --} + handleCmd_lobby :: CmdHandler - -handleCmd_lobby ["LIST"] = do - (ci, irnc) <- ask - let cl = irnc `client` ci - rooms <- allRoomInfos - let roomsInfoList = concatMap (roomInfo irnc) . filter (\r -> (roomProto r == clientProto cl) && not (isRestrictedJoins r)) - return [AnswerClients [sendChan cl] ("ROOMS" : roomsInfoList rooms)] +handleCmd_lobby clID clients rooms ["LIST"] = + [AnswerThisClient ("ROOMS" : roomsInfoList)] where - roomInfo irnc room = [ - showB $ gameinprogress room, + roomsInfoList = concatMap roomInfo sameProtoRooms + sameProtoRooms = filter (\r -> (roomProto r == protocol) && not (isRestrictedJoins r)) roomsList + roomsList = IntMap.elems rooms + protocol = clientProto client + client = clients IntMap.! clID + roomInfo room + | clientProto client < 28 = [ name room, - showB $ playersIn room, - showB $ length $ teams room, - nick $ irnc `client` masterID room, + show (playersIn room) ++ "(" ++ show (length $ teams room) ++ ")", + show $ gameinprogress room + ] + | otherwise = [ + show $ gameinprogress room, + name room, + show $ playersIn room, + show $ length $ teams room, + nick $ clients IntMap.! (masterID room), head (Map.findWithDefault ["+gen+"] "MAP" (params room)), head (Map.findWithDefault ["Default"] "SCHEME" (params room)), head (Map.findWithDefault ["Default"] "AMMO" (params room)) ] - -handleCmd_lobby ["CHAT", msg] = do - n <- clientNick - s <- roomOthersChans - return [AnswerClients s ["CHAT", n, msg]] - -handleCmd_lobby ["CREATE_ROOM", newRoom, roomPassword] - | illegalName newRoom = return [Warning "Illegal room name"] - | otherwise = do - rs <- allRoomInfos - cl <- thisClient - return $ if isJust $ find (\room -> newRoom == name room) rs then - [Warning "Room exists"] - else - [ - AddRoom newRoom roomPassword, - AnswerClients [sendChan cl] ["NOT_READY", nick cl] - ] - - -handleCmd_lobby ["CREATE_ROOM", newRoom] = - handleCmd_lobby ["CREATE_ROOM", newRoom, ""] +handleCmd_lobby clID clients _ ["CHAT", msg] = + [AnswerOthersInRoom ["CHAT", clientNick, msg]] + where + clientNick = nick $ clients IntMap.! clID -handleCmd_lobby ["JOIN_ROOM", roomName, roomPassword] = do - (ci, irnc) <- ask - let ris = allRooms irnc - cl <- thisClient - let maybeRI = find (\ri -> roomName == name (irnc `room` ri)) ris - let jRI = fromJust maybeRI - let jRoom = irnc `room` jRI - let jRoomClients = map (client irnc) $! roomClients irnc jRI -- no lazyness here! - return $ - if isNothing maybeRI then - [Warning "No such rooms"] - else if isRestrictedJoins jRoom then - [Warning "Joining restricted"] - else if roomPassword /= password jRoom then - [Warning "Wrong password"] - else - [ - MoveToRoom jRI, - AnswerClients (map sendChan $ cl : jRoomClients) ["NOT_READY", nick cl] - ] - ++ [ AnswerClients [sendChan cl] $ "JOINED" : map nick jRoomClients | playersIn jRoom /= 0] - ++ (map (readynessMessage cl) jRoomClients) - +handleCmd_lobby clID clients rooms ["CREATE_ROOM", newRoom, roomPassword] + | haveSameRoom = [Warning "Room exists"] + | illegalName newRoom = [Warning "Illegal room name"] + | otherwise = + [RoomRemoveThisClient "", -- leave lobby + AddRoom newRoom roomPassword, + AnswerThisClient ["NOT_READY", clientNick] + ] where - readynessMessage cl c = AnswerClients [sendChan cl] [if isReady c then "READY" else "NOT_READY", nick c] + clientNick = nick $ clients IntMap.! clID + haveSameRoom = isJust $ find (\room -> newRoom == name room) $ IntMap.elems rooms +handleCmd_lobby clID clients rooms ["CREATE_ROOM", newRoom] = + handleCmd_lobby clID clients rooms ["CREATE_ROOM", newRoom, ""] -{- handleCmd_lobby clID clients rooms ["JOIN_ROOM", roomName, roomPassword] | noSuchRoom = [Warning "No such room"] @@ -112,6 +83,12 @@ ++ answerTeams ++ watchRound where + noSuchRoom = isNothing mbRoom + mbRoom = find (\r -> roomName == name r && roomProto r == clientProto client) $ IntMap.elems rooms + jRoom = fromJust mbRoom + rID = roomUID jRoom + client = clients IntMap.! clID + roomClientsIDs = IntSet.elems $ playersIDs jRoom answerNicks = [AnswerThisClient $ "JOINED" : map (\clID -> nick $ clients IntMap.! clID) roomClientsIDs | playersIn jRoom /= 0] @@ -123,9 +100,9 @@ roomClientsIDs toAnswer (paramName, paramStrs) = AnswerThisClient $ "CFG" : paramName : paramStrs - - answerFullConfig = map toAnswer (leftConfigPart ++ rightConfigPart) - (leftConfigPart, rightConfigPart) = partition (\(p, _) -> p /= "MAP") (Map.toList $ params jRoom) + + answerFullConfig = map toAnswer ((Data.List.reverse . Data.List.sort $ leftConfigPart) ++ rightConfigPart) + (leftConfigPart, rightConfigPart) = partition (\(p, _) -> p == "MAP" || p == "MAPGEN" || p == "SCHEME") (Map.toList $ params jRoom) watchRound = if not $ gameinprogress jRoom then [] @@ -137,12 +114,12 @@ answerAllTeams (clientProto client) (teamsAtStart jRoom) else answerAllTeams (clientProto client) (teams jRoom) --} + -handleCmd_lobby ["JOIN_ROOM", roomName] = - handleCmd_lobby ["JOIN_ROOM", roomName, ""] +handleCmd_lobby clID clients rooms ["JOIN_ROOM", roomName] = + handleCmd_lobby clID clients rooms ["JOIN_ROOM", roomName, ""] + -{- handleCmd_lobby clID clients rooms ["FOLLOW", asknick] = if noSuchClient || roomID followClient == 0 then [] @@ -203,7 +180,6 @@ [ClearAccountsCache | isAdministrator client] where client = clients IntMap.! clID --} -handleCmd_lobby _ = return [ProtocolError "Incorrect command (state: in lobby)"] +handleCmd_lobby clID _ _ _ = [ProtocolError "Incorrect command (state: in lobby)"] diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/HWProtoNEState.hs --- a/gameServer/HWProtoNEState.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/HWProtoNEState.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,66 +1,54 @@ -{-# LANGUAGE OverloadedStrings #-} module HWProtoNEState where import qualified Data.IntMap as IntMap import Data.Maybe import Data.List import Data.Word -import Control.Monad.Reader -import qualified Data.ByteString.Char8 as B -------------------------------------- import CoreTypes import Actions import Utils -import RoomsAndClients handleCmd_NotEntered :: CmdHandler -handleCmd_NotEntered ["NICK", newNick] = do - (ci, irnc) <- ask - let cl = irnc `client` ci - if not . B.null $ nick cl then return [ProtocolError "Nickname already chosen"] - else - if haveSameNick irnc (nick cl) then return [AnswerClients [sendChan cl] ["WARNING", "Nickname already in use"], ByeClient ""] - else - if illegalName newNick then return [ByeClient "Illegal nickname"] - else - return $ - ModifyClient (\c -> c{nick = newNick}) : - AnswerClients [sendChan cl] ["NICK", newNick] : - [CheckRegistered | clientProto cl /= 0] +handleCmd_NotEntered clID clients _ ["NICK", newNick] + | not . null $ nick client = [ProtocolError "Nickname already chosen"] + | haveSameNick = [AnswerThisClient ["WARNING", "Nickname already in use"], ByeClient ""] + | illegalName newNick = [ByeClient "Illegal nickname"] + | otherwise = + ModifyClient (\c -> c{nick = newNick}) : + AnswerThisClient ["NICK", newNick] : + [CheckRegistered | clientProto client /= 0] where - haveSameNick irnc clNick = isJust $ find (\cl -> newNick == clNick) $ map (client irnc) $ allClients irnc - -handleCmd_NotEntered ["PROTO", protoNum] = do - (ci, irnc) <- ask - let cl = irnc `client` ci - if clientProto cl > 0 then return [ProtocolError "Protocol already known"] - else - if parsedProto == 0 then return [ProtocolError "Bad number"] - else - return $ - ModifyClient (\c -> c{clientProto = parsedProto}) : - AnswerClients [sendChan cl] ["PROTO", B.pack $ show parsedProto] : - [CheckRegistered | not . B.null $ nick cl] - where - parsedProto = case B.readInt protoNum of - Just (i, t) | B.null t -> fromIntegral i - otherwise -> 0 + client = clients IntMap.! clID + haveSameNick = isJust $ find (\cl -> newNick == nick cl) $ IntMap.elems clients -handleCmd_NotEntered ["PASSWORD", passwd] = do - (ci, irnc) <- ask - let cl = irnc `client` ci +handleCmd_NotEntered clID clients _ ["PROTO", protoNum] + | clientProto client > 0 = [ProtocolError "Protocol already known"] + | parsedProto == 0 = [ProtocolError "Bad number"] + | otherwise = + ModifyClient (\c -> c{clientProto = parsedProto}) : + AnswerThisClient ["PROTO", show parsedProto] : + [CheckRegistered | (not . null) (nick client)] + where + client = clients IntMap.! clID + parsedProto = fromMaybe 0 (maybeRead protoNum :: Maybe Word16) - if passwd == webPassword cl then - return $ JoinLobby : [AnswerClients [sendChan cl] ["ADMIN_ACCESS"] | isAdministrator cl] - else - return [ByeClient "Authentication failed"] -{- +handleCmd_NotEntered clID clients _ ["PASSWORD", passwd] = + if passwd == webPassword client then + [ModifyClient (\cl -> cl{logonPassed = True}), + MoveToLobby] ++ adminNotice + else + [ByeClient "Authentication failed"] + where + client = clients IntMap.! clID + adminNotice = [AnswerThisClient ["ADMIN_ACCESS"] | isAdministrator client] + handleCmd_NotEntered clID clients _ ["DUMP"] = if isAdministrator (clients IntMap.! clID) then [Dump] else [] --} + -handleCmd_NotEntered _ = return [ProtocolError "Incorrect command (state: not entered)"] +handleCmd_NotEntered clID _ _ _ = [ProtocolError "Incorrect command (state: not entered)"] diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/HandlerUtils.hs --- a/gameServer/HandlerUtils.hs Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -module HandlerUtils where - -import Control.Monad.Reader -import qualified Data.ByteString.Char8 as B - -import RoomsAndClients -import CoreTypes -import Actions - -thisClient :: Reader (ClientIndex, IRnC) ClientInfo -thisClient = do - (ci, rnc) <- ask - return $ rnc `client` ci - -thisRoom :: Reader (ClientIndex, IRnC) RoomInfo -thisRoom = do - (ci, rnc) <- ask - let ri = clientRoom rnc ci - return $ rnc `room` ri - -clientNick :: Reader (ClientIndex, IRnC) B.ByteString -clientNick = liftM nick thisClient - -roomOthersChans :: Reader (ClientIndex, IRnC) [ClientChan] -roomOthersChans = do - (ci, rnc) <- ask - let ri = clientRoom rnc ci - return $ map (sendChan . client rnc) $ filter (/= ci) (roomClients rnc ri) - -roomClientsChans :: Reader (ClientIndex, IRnC) [ClientChan] -roomClientsChans = do - (ci, rnc) <- ask - let ri = clientRoom rnc ci - return $ map (sendChan . client rnc) (roomClients rnc ri) - -thisClientChans :: Reader (ClientIndex, IRnC) [ClientChan] -thisClientChans = do - (ci, rnc) <- ask - return $ [sendChan (rnc `client` ci)] - -answerClient :: [B.ByteString] -> Reader (ClientIndex, IRnC) [Action] -answerClient msg = thisClientChans >>= return . (: []) . flip AnswerClients msg - -allRoomInfos :: Reader (a, IRnC) [RoomInfo] -allRoomInfos = liftM ((\irnc -> map (room irnc) $ allRooms irnc) . snd) ask diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/NetRoutines.hs --- a/gameServer/NetRoutines.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/NetRoutines.hs Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/OfficialServer/DBInteraction.hs --- a/gameServer/OfficialServer/DBInteraction.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/OfficialServer/DBInteraction.hs Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/OfficialServer/extdbinterface.hs --- a/gameServer/OfficialServer/extdbinterface.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/OfficialServer/extdbinterface.hs Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/Opts.hs --- a/gameServer/Opts.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/Opts.hs Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/RoomsAndClients.hs --- a/gameServer/RoomsAndClients.hs Mon Dec 27 23:57:44 2010 +0100 +++ /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 0ddb100fea61 -r f924be23ffb4 gameServer/ServerCore.hs --- a/gameServer/ServerCore.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/ServerCore.hs Tue Jan 04 12:53:46 2011 +0100 @@ -2,75 +2,69 @@ import Network import Control.Concurrent +import Control.Concurrent.STM import Control.Concurrent.Chan import Control.Monad import qualified Data.IntMap as IntMap import System.Log.Logger -import Control.Monad.Reader -import Control.Monad.State.Strict -import Data.Set as Set -import qualified Data.ByteString.Char8 as B -------------------------------------- import CoreTypes import NetRoutines +import Utils import HWProtoCore import Actions import OfficialServer.DBInteraction -import ServerState - - -timerLoop :: Int -> Chan CoreMessage -> IO () -timerLoop tick messagesChan = threadDelay (30 * 10^6) >> writeChan messagesChan (TimerAction tick) >> timerLoop (tick + 1) messagesChan -reactCmd :: [B.ByteString] -> StateT ServerState IO () -reactCmd cmd = do - (Just ci) <- gets clientIndex - rnc <- gets roomsClients - actions <- liftIO $ withRoomsAndClients rnc (\irnc -> runReader (handleCmd cmd) (ci, irnc)) - forM_ actions processAction +timerLoop :: Int -> Chan CoreMessage -> IO() +timerLoop tick messagesChan = threadDelay (30 * 10^6) >> writeChan messagesChan (TimerAction tick) >> timerLoop (tick + 1) messagesChan + +firstAway (_, a, b, c) = (a, b, c) + +reactCmd :: ServerInfo -> Int -> [String] -> Clients -> Rooms -> IO (ServerInfo, Clients, Rooms) +reactCmd serverInfo clID cmd clients rooms = + liftM firstAway $ foldM processAction (clID, serverInfo, clients, rooms) $ handleCmd clID clients rooms cmd -mainLoop :: StateT ServerState IO () -mainLoop = forever $ do - get >>= \s -> put $! s - - si <- gets serverInfo - r <- liftIO $ readChan $ coreChan si - - case r of - Accept ci -> processAction (AddClient ci) - - ClientMessage (ci, cmd) -> do - liftIO $ debugM "Clients" $ (show ci) ++ ": " ++ (show cmd) +mainLoop :: ServerInfo -> Clients -> Rooms -> IO () +mainLoop serverInfo clients rooms = do + r <- readChan $ coreChan serverInfo + + (newServerInfo, mClients, mRooms) <- + case r of + Accept ci -> + liftM firstAway $ processAction + (clientUID ci, serverInfo, clients, rooms) (AddClient ci) - removed <- gets removedClients - when (not $ ci `Set.member` removed) $ do - as <- get - put $! as{clientIndex = Just ci} - reactCmd cmd - - Remove ci -> do - liftIO $ debugM "Clients" $ "DeleteClient: " ++ show ci - processAction (DeleteClient ci) + ClientMessage (clID, cmd) -> do + debugM "Clients" $ (show clID) ++ ": " ++ (show cmd) + if clID `IntMap.member` clients then + reactCmd serverInfo clID cmd clients rooms + else + do + debugM "Clients" "Message from dead client" + return (serverInfo, clients, rooms) - --else - --do - --debugM "Clients" "Message from dead client" - --return (serverInfo, rnc) + ClientAccountInfo (clID, info) -> + if clID `IntMap.member` clients then + liftM firstAway $ processAction + (clID, serverInfo, clients, rooms) + (ProcessAccountInfo info) + else + do + debugM "Clients" "Got info for dead client" + return (serverInfo, clients, rooms) - ClientAccountInfo (ci, info) -> do - rnc <- gets roomsClients - exists <- liftIO $ clientExists rnc ci - when (exists) $ do - as <- get - put $! as{clientIndex = Just ci} - processAction (ProcessAccountInfo info) - return () + TimerAction tick -> + liftM firstAway $ + foldM processAction (0, serverInfo, clients, rooms) $ + PingAll : [StatsAction | even tick] + - TimerAction tick -> - mapM_ processAction $ - PingAll : [StatsAction | even tick] + {- let hadRooms = (not $ null rooms) && (null mrooms) + in unless ((not $ isDedicated serverInfo) && ((null clientsIn) || hadRooms)) $ + mainLoop serverInfo acceptChan messagesChan clientsIn mrooms -} + mainLoop newServerInfo mClients mRooms startServer :: ServerInfo -> Socket -> IO () startServer serverInfo serverSocket = do @@ -80,15 +74,14 @@ acceptLoop serverSocket (coreChan serverInfo) + 0 return () - - --forkIO $ timerLoop 0 $ coreChan serverInfo + + forkIO $ timerLoop 0 $ coreChan serverInfo startDBConnection serverInfo - rnc <- newRoomsAndClients newRoom + forkIO $ mainLoop serverInfo IntMap.empty (IntMap.singleton 0 newRoom) - forkIO $ evalStateT mainLoop (ServerState Nothing serverInfo Set.empty rnc) - - forever $ threadDelay (60 * 60 * 10^6) + forever $ threadDelay (60 * 60 * 10^6) >> putStrLn "***" \ No newline at end of file diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/ServerState.hs --- a/gameServer/ServerState.hs Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -module ServerState - ( - module RoomsAndClients, - clientRoomA, - ServerState(..), - client's, - allClientsS, - roomClientsS - ) where - -import Control.Monad.State.Strict -import Data.Set as Set ----------------------- -import RoomsAndClients -import CoreTypes - -data ServerState = ServerState { - clientIndex :: !(Maybe ClientIndex), - serverInfo :: !ServerInfo, - removedClients :: !(Set.Set ClientIndex), - roomsClients :: !MRnC - } - - -clientRoomA :: StateT ServerState IO RoomIndex -clientRoomA = do - (Just ci) <- gets clientIndex - rnc <- gets roomsClients - liftIO $ clientRoomM rnc ci - -client's :: (ClientInfo -> a) -> StateT ServerState IO a -client's f = do - (Just ci) <- gets clientIndex - rnc <- gets roomsClients - liftIO $ client'sM rnc f ci - -allClientsS :: StateT ServerState IO [ClientInfo] -allClientsS = gets roomsClients >>= liftIO . clientsM - -roomClientsS :: RoomIndex -> StateT ServerState IO [ClientInfo] -roomClientsS ri = do - rnc <- gets roomsClients - liftIO $ roomClientsM rnc ri diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/Store.hs --- a/gameServer/Store.hs Mon Dec 27 23:57:44 2010 +0100 +++ /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 0ddb100fea61 -r f924be23ffb4 gameServer/Utils.hs --- a/gameServer/Utils.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/Utils.hs Tue Jan 04 12:53:46 2011 +0100 @@ -1,4 +1,3 @@ -{-# LANGUAGE OverloadedStrings #-} module Utils where import Control.Concurrent @@ -17,34 +16,37 @@ import Data.Maybe ------------------------------------------------- import qualified Codec.Binary.Base64 as Base64 -import qualified Data.ByteString.Char8 as B -import qualified Data.ByteString as BW +import qualified Data.ByteString.UTF8 as BUTF8 +import qualified Data.ByteString as B import CoreTypes -sockAddr2String :: SockAddr -> IO B.ByteString -sockAddr2String (SockAddrInet _ hostAddr) = liftM B.pack $ inet_ntoa hostAddr +sockAddr2String :: SockAddr -> IO String +sockAddr2String (SockAddrInet _ hostAddr) = inet_ntoa hostAddr sockAddr2String (SockAddrInet6 _ _ (a, b, c, d) _) = - return $ B.pack $ (foldr1 (.) + return $ (foldr1 (.) $ List.intersperse (\a -> ':':a) $ concatMap (\n -> (\(a, b) -> [showHex a, showHex b]) $ divMod n 65536) [a, b, c, d]) [] -toEngineMsg :: B.ByteString -> B.ByteString -toEngineMsg msg = B.pack $ Base64.encode (fromIntegral (BW.length msg) : (BW.unpack msg)) +toEngineMsg :: String -> String +toEngineMsg msg = Base64.encode (fromIntegral (B.length encodedMsg) : (B.unpack encodedMsg)) + where + encodedMsg = BUTF8.fromString msg -fromEngineMsg :: B.ByteString -> Maybe B.ByteString -fromEngineMsg msg = Base64.decode (B.unpack msg) >>= removeLength >>= return . BW.pack +fromEngineMsg :: String -> Maybe String +fromEngineMsg msg = liftM (map w2c) (Base64.decode msg >>= removeLength) where removeLength (x:xs) = if length xs == fromIntegral x then Just xs else Nothing removeLength _ = Nothing -checkNetCmd :: B.ByteString -> (Bool, Bool) -checkNetCmd = check . liftM B.unpack . fromEngineMsg +checkNetCmd :: String -> (Bool, Bool) +checkNetCmd msg = check decoded where + decoded = fromEngineMsg msg check Nothing = (False, False) check (Just (m:ms)) = (m `Set.member` legalMessages, m == '+') check _ = (False, False) - legalMessages = Set.fromList $ "M#+LlRrUuDdZzAaSjJ,sFNpPwtghb12345" ++ slotMessages + legalMessages = Set.fromList $ "M#+LlRrUuDdZzAaSjJ,sFNpPwtghbc12345" ++ slotMessages slotMessages = "\128\129\130\131\132\133\134\135\136\137\138" maybeRead :: Read a => String -> Maybe a @@ -52,17 +54,29 @@ [(x, rest)] | all isSpace rest -> Just x _ -> Nothing -teamToNet :: TeamInfo -> [B.ByteString] -teamToNet team = - "ADD_TEAM" - : teamname team - : teamgrave team - : teamfort team - : teamvoicepack team - : teamflag team - : teamowner team - : (B.pack $ show $ difficulty team) - : hhsInfo +teamToNet :: Word16 -> TeamInfo -> [String] +teamToNet protocol team + | protocol < 30 = [ + "ADD_TEAM", + teamname team, + teamgrave team, + teamfort team, + teamvoicepack team, + teamowner team, + show $ difficulty team + ] + ++ hhsInfo + | otherwise = [ + "ADD_TEAM", + teamname team, + teamgrave team, + teamfort team, + teamvoicepack team, + teamflag team, + teamowner team, + show $ difficulty team + ] + ++ hhsInfo where hhsInfo = concatMap (\(HedgehogInfo name hat) -> [name, hat]) $ hedgehogs team @@ -76,10 +90,10 @@ else t : replaceTeam team teams -illegalName :: B.ByteString -> Bool -illegalName = all isSpace . B.unpack +illegalName :: String -> Bool +illegalName = all isSpace -protoNumber2ver :: Word16 -> B.ByteString +protoNumber2ver :: Word16 -> String protoNumber2ver 17 = "0.9.7-dev" protoNumber2ver 19 = "0.9.7" protoNumber2ver 20 = "0.9.8-dev" @@ -98,20 +112,12 @@ protoNumber2ver 33 = "0.9.14" protoNumber2ver 34 = "0.9.15-dev" protoNumber2ver 35 = "0.9.14.1" -protoNumber2ver _ = "Unknown" +protoNumber2ver 37 = "0.9.15" +protoNumber2ver 38 = "0.9.16-dev" +protoNumber2ver w = show w askFromConsole :: String -> IO String askFromConsole msg = do putStr msg hFlush stdout getLine - - -unfoldrE :: (b -> Either b (a, b)) -> b -> ([a], b) -unfoldrE f b = - case f b of - Right (a, new_b) -> let (a', b') = unfoldrE f new_b in (a : a', b') - Left new_b -> ([], new_b) - -showB :: Show a => a -> B.ByteString -showB = B.pack .show diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/hedgewars-server.cabal --- a/gameServer/hedgewars-server.cabal Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -Name: hedgewars-server -Version: 0.1 -Synopsis: hedgewars server -Description: hedgewars server -Homepage: http://www.hedgewars.org/ -License: GPL-2 -Author: unC0Rr -Maintainer: unC0Rr@hedgewars.org -Category: Game -Build-type: Simple -Cabal-version: >=1.2 - - -Executable hedgewars-server - main-is: hedgewars-server.hs - - Build-depends: - base >= 4, - unix, - containers, - array, - bytestring, - network-bytestring, - network, - time, - stm, - mtl, - dataenc, - hslogger, - process - - ghc-options: -O2 \ No newline at end of file diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/hedgewars-server.hs --- a/gameServer/hedgewars-server.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/hedgewars-server.hs Tue Jan 04 12:53:46 2011 +0100 @@ -2,15 +2,23 @@ module Main where -import Network +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) @@ -18,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; @@ -32,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: " @@ -46,7 +52,14 @@ let serverInfo = serverInfo' #endif + + proto <- getProtocolNumber "tcp" Exception.bracket - (Network.listenOn $ Network.PortNumber $ listenPort serverInfo) + (socket AF_INET Stream proto) sClose - (startServer serverInfo) + (\sock -> do + setSocketOption sock ReuseAddr 1 + bindSocket sock (SockAddrInet (listenPort serverInfo) iNADDR_ANY) + listen sock maxListenQueue + startServer serverInfo sock + ) diff -r 0ddb100fea61 -r f924be23ffb4 gameServer/stresstest.hs --- a/gameServer/stresstest.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/stresstest.hs Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/stresstest2.hs --- a/gameServer/stresstest2.hs Mon Dec 27 23:57:44 2010 +0100 +++ b/gameServer/stresstest2.hs Tue Jan 04 12:53:46 2011 +0100 @@ -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 0ddb100fea61 -r f924be23ffb4 gameServer/stresstest3.hs --- a/gameServer/stresstest3.hs Mon Dec 27 23:57:44 2010 +0100 +++ /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 0ddb100fea61 -r f924be23ffb4 hedgewars/CCHandlers.inc --- a/hedgewars/CCHandlers.inc Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,849 +0,0 @@ -(* -* Hedgewars, a free turn based strategy game -* Copyright (c) 2004-2010 Andrey Korotaev -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; version 2 of the License -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA -*) - -function CheckNoTeamOrHH: boolean; -var bRes: boolean; -begin -bRes:= (CurrentTeam = nil) or (CurrentHedgehog^.Gear = nil); -{$IFDEF DEBUGFILE} -if bRes then -if CurrentTeam = nil then AddFileLog('CONSOLE: CurTeam = nil') - else AddFileLog('CONSOLE: CurTeam <> nil, Gear = nil'); -{$ENDIF} -CheckNoTeamOrHH:= bRes; -end; -//////////////////////////////////////////////////////////////////////////////// -procedure chQuit(var s: shortstring); -const prevGState: TGameState = gsConfirm; -begin -s:= s; // avoid compiler hint -if GameState <> gsConfirm then - begin - prevGState:= GameState; - GameState:= gsConfirm - end else - GameState:= prevGState -end; - -procedure chConfirm(var s: shortstring); -begin -s:= s; // avoid compiler hint -if GameState = gsConfirm then - begin - SendIPC('Q'); - GameState:= gsExit - end -else - begin - GameState:= gsChat; - KeyPressChat(27); - KeyPressChat(47); - KeyPressChat(116); - KeyPressChat(101); - KeyPressChat(97); - KeyPressChat(109); - KeyPressChat(32) - end -end; - -procedure chCheckProto(var s: shortstring); -var i, c: LongInt; -begin -if isDeveloperMode then -begin -val(s, i, c); -if (c <> 0) or (i = 0) then exit; -TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old', true); -TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new', true) -end -end; - -procedure chAddTeam(var s: shortstring); -var Color: Longword; - ts, cs: shortstring; -begin -cs:= ''; -ts:= ''; -if isDeveloperMode then -begin -SplitBySpace(s, cs); -SplitBySpace(cs, ts); -val(cs, Color); -TryDo(Color <> 0, 'Error: black team color', true); - -// color is always little endian so the mask must be constant also in big endian archs -Color:= Color or $FF000000; - -AddTeam(Color); -CurrentTeam^.TeamName:= ts; -CurrentTeam^.PlayerHash:= s; -if GameType in [gmtDemo, gmtSave] then CurrentTeam^.ExtDriven:= true; - -CurrentTeam^.voicepack:= AskForVoicepack('Default') -end -end; - -procedure chTeamLocal(var s: shortstring); -begin -s:= s; // avoid compiler hint -if not isDeveloperMode then exit; -if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/rdriven"', true); -CurrentTeam^.ExtDriven:= true -end; - -procedure chGrave(var s: shortstring); -begin -if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/grave"', true); -if s[1]='"' then Delete(s, 1, 1); -if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); -CurrentTeam^.GraveName:= s -end; - -procedure chFort(var s: shortstring); -begin -if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/fort"', true); -if s[1]='"' then Delete(s, 1, 1); -if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); -CurrentTeam^.FortName:= s -end; - -procedure chVoicepack(var s: shortstring); -begin -if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/voicepack"', true); -if s[1]='"' then Delete(s, 1, 1); -if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); -CurrentTeam^.voicepack:= AskForVoicepack(s) -end; - -procedure chFlag(var s: shortstring); -begin -if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/flag"', true); -if s[1]='"' then Delete(s, 1, 1); -if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); -CurrentTeam^.flag:= s -end; - -procedure chScript(var s: shortstring); -begin -if s[1]='"' then Delete(s, 1, 1); -if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); -ScriptLoad(s) -end; - -procedure chAddHH(var id: shortstring); -var s: shortstring; - Gear: PGear; -begin -s:= ''; -if (not isDeveloperMode) or (CurrentTeam = nil) then exit; -with CurrentTeam^ do - begin - SplitBySpace(id, s); - CurrentHedgehog:= @Hedgehogs[HedgehogsNumber]; - val(id, CurrentHedgehog^.BotLevel); - Gear:= AddGear(0, 0, gtHedgehog, 0, _0, _0, 0); - SplitBySpace(s, id); - val(s, Gear^.Health); - TryDo(Gear^.Health > 0, 'Invalid hedgehog health', true); - PHedgehog(Gear^.Hedgehog)^.Team:= CurrentTeam; - if (GameFlags and gfSharedAmmo) <> 0 then CurrentHedgehog^.AmmoStore:= Clan^.ClanIndex - else if (GameFlags and gfPerHogAmmo) <> 0 then - begin - AddAmmoStore; - CurrentHedgehog^.AmmoStore:= StoreCnt - 1 - end - else CurrentHedgehog^.AmmoStore:= TeamsCount - 1; - CurrentHedgehog^.Gear:= Gear; - CurrentHedgehog^.Name:= id; - CurrentHedgehog^.InitialHealth:= Gear^.Health; - CurrHedgehog:= HedgehogsNumber; - inc(HedgehogsNumber) - end -end; - -procedure chSetHat(var s: shortstring); -begin -if (not isDeveloperMode) or (CurrentTeam = nil) then exit; -with CurrentTeam^ do - begin - if not CurrentHedgehog^.King then - if (s = '') or - (((GameFlags and gfKing) <> 0) and (s = 'crown')) or - ((Length(s) > 39) and (Copy(s,1,8) = 'Reserved') and (Copy(s,9,32) <> PlayerHash)) then - CurrentHedgehog^.Hat:= 'NoHat' - else - CurrentHedgehog^.Hat:= s - end; -end; - -procedure chSetHHCoords(var x: shortstring); -var y: shortstring; - t: Longint; -begin -y:= ''; -if (not isDeveloperMode) or (CurrentHedgehog = nil) or (CurrentHedgehog^.Gear = nil) then exit; -SplitBySpace(x, y); -val(x, t); -CurrentHedgehog^.Gear^.X:= int2hwFloat(t); -val(y, t); -CurrentHedgehog^.Gear^.Y:= int2hwFloat(t) -end; - -procedure chSetAmmoLoadout(var descr: shortstring); -begin -SetAmmoLoadout(descr) -end; - -procedure chSetAmmoDelay(var descr: shortstring); -begin -SetAmmoDelay(descr) -end; - -procedure chSetAmmoProbability(var descr: shortstring); -begin -SetAmmoProbability(descr) -end; - -procedure chSetAmmoReinforcement(var descr: shortstring); -begin -SetAmmoReinforcement(descr) -end; - -procedure chAddAmmoStore(var descr: shortstring); -begin -descr:= ''; // avoid compiler hint -AddAmmoStore -end; - -procedure chBind(var id: shortstring); -var s: shortstring; - b: LongInt; -begin -s:= ''; -if CurrentTeam = nil then exit; -SplitBySpace(id, s); -if s[1]='"' then Delete(s, 1, 1); -if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); -b:= KeyNameToCode(id); -if b = 0 then OutError(errmsgUnknownVariable + ' "' + id + '"', false) - else CurrentTeam^.Binds[b]:= s -end; - -procedure chCurU_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementY:= -1; -end; - -procedure chCurU_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementY:= 0; -end; - -procedure chCurD_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementY:= 1; -end; - -procedure chCurD_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementY:= 0; -end; - -procedure chCurL_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementX:= -1; -end; - -procedure chCurL_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementX:= 0; -end; - -procedure chCurR_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementX:= 1; -end; - -procedure chCurR_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -CursorMovementX:= 0; -end; - -procedure chLeft_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('L'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmLeft -end; - -procedure chLeft_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then exit; -if not CurrentTeam^.ExtDriven then SendIPC('l'); -with CurrentHedgehog^.Gear^ do - Message:= Message and not gmLeft -end; - -procedure chRight_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('R'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmRight -end; - -procedure chRight_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then exit; -if not CurrentTeam^.ExtDriven then SendIPC('r'); -with CurrentHedgehog^.Gear^ do - Message:= Message and not gmRight -end; - -procedure chUp_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('U'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmUp -end; - -procedure chUp_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then exit; -if not CurrentTeam^.ExtDriven then SendIPC('u'); -with CurrentHedgehog^.Gear^ do - Message:= Message and not gmUp -end; - -procedure chDown_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('D'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmDown -end; - -procedure chDown_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then exit; -if not CurrentTeam^.ExtDriven then SendIPC('d'); -with CurrentHedgehog^.Gear^ do - Message:= Message and not gmDown -end; - -procedure chPrecise_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('Z'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmPrecise -end; - -procedure chPrecise_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then exit; -if not CurrentTeam^.ExtDriven then SendIPC('z'); -with CurrentHedgehog^.Gear^ do - Message:= Message and not gmPrecise -end; - -procedure chLJump(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('j'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmLJump -end; - -procedure chHJump(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('J'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmHJump -end; - -procedure chAttack_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - begin - {$IFDEF DEBUGFILE}AddFileLog('/+attack: hedgehog''s Gear^.State = '+inttostr(State));{$ENDIF} - if ((State and gstHHDriven) <> 0) then - begin - FollowGear:= CurrentHedgehog^.Gear; - if not CurrentTeam^.ExtDriven then SendIPC('A'); - Message:= Message or gmAttack - end - end -end; - -procedure chAttack_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then exit; -with CurrentHedgehog^.Gear^ do - begin - if not CurrentTeam^.ExtDriven and - ((Message and gmAttack) <> 0) then SendIPC('a'); - Message:= Message and not gmAttack - end -end; - -procedure chSwitch(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -if not CurrentTeam^.ExtDriven then SendIPC('S'); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - Message:= Message or gmSwitch -end; - -procedure chNextTurn(var s: shortstring); -begin - s:= s; // avoid compiler hint - 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} - perfExt_NewTurnBeginning(); -end; - -procedure chSay(var s: shortstring); -begin -SendIPC('s' + s); - -if copy(s, 1, 4) = '/me ' then - s:= #2'* ' + UserNick + ' ' + copy(s, 5, Length(s) - 4) -else - s:= #1 + UserNick + ': ' + s; - -AddChatString(s) -end; - -procedure chTeamSay(var s: shortstring); -begin -SendIPC('b' + s); - -s:= #4 + '[Team] ' + UserNick + ': ' + s; - -AddChatString(s) -end; - -procedure chTimer(var s: shortstring); -begin -if (s[0] <> #1) or (s[1] < '1') or (s[1] > '5') or CheckNoTeamOrHH then exit; - -if not CurrentTeam^.ExtDriven then SendIPC(s); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - begin - Message:= Message or gmTimer; - MsgParam:= byte(s[1]) - ord('0') - end -end; - -procedure chSlot(var s: shortstring); -var slot: LongWord; -begin -if (s[0] <> #1) or CheckNoTeamOrHH then exit; -slot:= byte(s[1]) - 49; -if slot > cMaxSlotIndex then exit; -if not CurrentTeam^.ExtDriven then SendIPC(char(byte(s[1]) + 79)); -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -with CurrentHedgehog^.Gear^ do - begin - Message:= Message or gmSlot; - MsgParam:= slot - end -end; - -procedure chSetWeapon(var s: shortstring); -begin - if (s[0] <> #1) or CheckNoTeamOrHH then exit; - - if TAmmoType(s[1]) > High(TAmmoType) then exit; - - if not CurrentTeam^.ExtDriven then SendIPC('w' + s); - - with CurrentHedgehog^.Gear^ do - begin - Message:= Message or gmWeapon; - MsgParam:= byte(s[1]); - end; -end; - -procedure chTaunt(var s: shortstring); -begin -if (s[0] <> #1) or CheckNoTeamOrHH then exit; - -if TWave(s[1]) > High(TWave) then exit; - -if not CurrentTeam^.ExtDriven then SendIPC('t' + s); - -with CurrentHedgehog^.Gear^ do - begin - Message:= Message or gmAnimate; - MsgParam:= byte(s[1]) - end -end; - -procedure chHogSay(var s: shortstring); -var Gear: PVisualGear; - text: shortstring; -begin -text:= copy(s, 2, Length(s)-1); -if CheckNoTeamOrHH -or ((CurrentHedgehog^.Gear^.State and gstHHDriven) = 0) then - begin - chSay(text); - exit - end; - -if not CurrentTeam^.ExtDriven then SendIPC('h' + s); - -if byte(s[1]) < 4 then - begin - Gear:= AddVisualGear(0, 0, vgtSpeechBubble); - if Gear <> nil then - begin - Gear^.Hedgehog:= CurrentHedgehog; - Gear^.Text:= text; - Gear^.FrameTicks:= byte(s[1]) - end - end -else - begin - SpeechType:= byte(s[1])-3; - SpeechText:= text - end; - -end; - -procedure doPut(putX, putY: LongInt; fromAI: boolean); -begin -if CheckNoTeamOrHH or isPaused then exit; -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -bShowFinger:= false; -if not CurrentTeam^.ExtDriven and bShowAmmoMenu then - begin - bSelected:= true; - exit - end; - -with CurrentHedgehog^.Gear^, - CurrentHedgehog^ do - if (State and gstHHChooseTarget) <> 0 then - begin - isCursorVisible:= false; - if not CurrentTeam^.ExtDriven then - begin - if fromAI then - begin - TargetPoint.X:= putX; - TargetPoint.Y:= putY - end else - begin - TargetPoint.X:= CursorPoint.X - WorldDx; - TargetPoint.Y:= cScreenHeight - CursorPoint.Y - WorldDy; - end; - SendIPCXY('p', TargetPoint.X, TargetPoint.Y); - end - else - begin - TargetPoint.X:= putX; - TargetPoint.Y:= putY - end; - {$IFDEF DEBUGFILE}AddFilelog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y));{$ENDIF} - State:= State and not gstHHChooseTarget; - if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackingPut) <> 0 then - Message:= Message or gmAttack; - end - else - if CurrentTeam^.ExtDriven then - OutError('got /put while not being in choose target mode', false) -end; - -procedure chPut(var s: shortstring); -begin - s:= s; // avoid compiler hint - doPut(0, 0, false); -end; - -procedure chCapture(var s: shortstring); -begin -s:= s; // avoid compiler hint -flagMakeCapture:= true -end; - -procedure chSkip(var s: shortstring); -begin -s:= s; // avoid compiler hint -if not CurrentTeam^.ExtDriven then SendIPC(','); -uStats.Skipped; -skipFlag:= true -end; - -procedure chSetMap(var s: shortstring); -begin -if isDeveloperMode then -begin -Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s; -InitStepsFlags:= InitStepsFlags or cifMap -end -end; - -procedure chSetTheme(var s: shortstring); -begin -if isDeveloperMode then -begin -Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s; -InitStepsFlags:= InitStepsFlags or cifTheme -end -end; - -procedure chSetSeed(var s: shortstring); -begin -if isDeveloperMode then -begin -SetRandomSeed(s); -cSeed:= s; -InitStepsFlags:= InitStepsFlags or cifRandomize -end -end; - -procedure chAmmoMenu(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH then - bShowAmmoMenu:= true -else - begin - with CurrentTeam^ do - with Hedgehogs[CurrHedgehog] do - begin - bSelected:= false; - - if bShowAmmoMenu then bShowAmmoMenu:= false - else if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or - ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or - ((Gear^.State and gstHHDriven) = 0) then else bShowAmmoMenu:= true - end; - if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1 - end -end; - -procedure chFullScr(var s: shortstring); -var flags: Longword = 0; - ico: PSDL_Surface; -{$IFDEF DEBUGFILE} - buf: array[byte] of char; -{$ENDIF} -begin - s:= s; // avoid compiler hint - if Length(s) = 0 then cFullScreen:= not cFullScreen - else cFullScreen:= s = '1'; - -{$IFDEF DEBUGFILE} - buf[0]:= char(0); // avoid compiler hint - AddFileLog('Prepare to change video parameters...'); -{$ENDIF} - - flags:= SDL_OPENGL;// or SDL_RESIZABLE; - - if cFullScreen then - flags:= flags or SDL_FULLSCREEN; - -{$IFDEF SDL_IMAGE_NEWER} - WriteToConsole('Init SDL_image... '); - SDLTry(IMG_Init(IMG_INIT_PNG) <> 0, true); - WriteLnToConsole(msgOK); -{$ENDIF} - // load engine icon -{$IFDEF DARWIN} - ico:= LoadImage(Pathz[ptGraphics] + '/hwengine_mac', ifIgnoreCaps); -{$ELSE} - ico:= LoadImage(Pathz[ptGraphics] + '/hwengine', ifIgnoreCaps); -{$ENDIF} - if ico <> nil then - begin - SDL_WM_SetIcon(ico, 0); - SDL_FreeSurface(ico) - end; - - // set window caption - SDL_WM_SetCaption('Hedgewars', nil); - - if SDLPrimSurface <> nil then - begin -{$IFDEF DEBUGFILE} - AddFileLog('Freeing old primary surface...'); -{$ENDIF} - SDL_FreeSurface(SDLPrimSurface); - SDLPrimSurface:= nil; - end; - -{$IFDEF SDL13} - if SDLwindow = nil then - begin - SDLwindow:= SDL_CreateWindow('Hedgewars', 0, 0, cScreenWidth, cScreenHeight, - SDL_WINDOW_OPENGL or SDL_WINDOW_SHOWN - {$IFDEF IPHONEOS} or SDL_WINDOW_BORDERLESS{$ENDIF}); - SDL_CreateRenderer(SDLwindow, -1, 0); - end; - - SDL_SetRenderDrawColor(0, 0, 0, 255); - SDL_RenderFill(nil); - SDL_RenderPresent(); -{$ELSE} - SDLPrimSurface:= SDL_SetVideoMode(cScreenWidth, cScreenHeight, cBits, flags); - SDLTry(SDLPrimSurface <> nil, true); - PixelFormat:= SDLPrimSurface^.format; -{$ENDIF} - -{$IFDEF DEBUGFILE} - AddFileLog('Setting up OpenGL...'); - AddFileLog('SDL video driver: ' + shortstring(SDL_VideoDriverName(buf, sizeof(buf)))); -{$ENDIF} - SetupOpenGL(); -end; - -procedure chVol_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -inc(cVolumeDelta, 3) -end; - -procedure chVol_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -dec(cVolumeDelta, 3) -end; - -procedure chFindhh(var s: shortstring); -begin -s:= s; // avoid compiler hint -if CheckNoTeamOrHH or isPaused then exit; -bShowFinger:= true; -FollowGear:= CurrentHedgehog^.Gear -end; - -procedure chPause(var s: shortstring); -begin -s:= s; // avoid compiler hint -if ReadyTimeLeft > 1 then ReadyTimeLeft:= 1; -if gameType <> gmtNet then - isPaused:= not isPaused; -SDL_ShowCursor(ord(isPaused)) -end; - -procedure chRotateMask(var s: shortstring); -begin -s:= s; // avoid compiler hint -if ((GameFlags and gfInvulnerable) = 0) then cTagsMask:= cTagsMasks[cTagsMask] else cTagsMask:= cTagsMasksNoHealth[cTagsMask]; -end; - -procedure chSpeedup_p(var s: shortstring); -begin -s:= s; // avoid compiler hint -isSpeed:= true -end; - -procedure chSpeedup_m(var s: shortstring); -begin -s:= s; // avoid compiler hint -isSpeed:= false -end; - -procedure chZoomIn(var s: shortstring); -begin - s:= s; // avoid compiler hint - if ZoomValue < cMinZoomLevel then - ZoomValue:= ZoomValue + cZoomDelta; -end; - -procedure chZoomOut(var s: shortstring); -begin - s:= s; // avoid compiler hint - if ZoomValue > cMaxZoomLevel then - ZoomValue:= ZoomValue - cZoomDelta; -end; - -procedure chZoomReset(var s: shortstring); -begin - s:= s; // avoid compiler hint - ZoomValue:= cDefaultZoomLevel; -end; - -procedure chChat(var s: shortstring); -begin - s:= s; // avoid compiler hint - GameState:= gsChat; - KeyPressChat(27) -end; - -procedure chHistory(var s: shortstring); -begin - s:= s; // avoid compiler hint - uChat.showAll:= not uChat.showAll -end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/CMakeLists.txt Tue Jan 04 12:53:46 2011 +0100 @@ -11,24 +11,24 @@ #if the headers are not installed, the newer apis won't be activated find_file(sdlmixer_h SDL_mixer.h ${SDLMIXER_INCLUDE_DIR}) if(sdlmixer_h) - file(STRINGS ${sdlmixer_h} sdlmixer_version_tmp REGEX "SDL_MIXER_PATCHLEVEL[\t' ']+[0-9]+") - string(REGEX MATCH ".([0-9]+)" sdlmixer_version "${sdlmixer_version_tmp}") + file(STRINGS ${sdlmixer_h} sdlmixer_version_tmp REGEX "SDL_MIXER_PATCHLEVEL[\t' ']+[0-9]+") + string(REGEX MATCH ".([0-9]+)" sdlmixer_version "${sdlmixer_version_tmp}") - if(sdlmixer_version GREATER 9) - message(STATUS "Enabling enhanced SDL_Mixer calls") - set(pascal_compiler_flags_cmn "-dSDL_MIXER_NEWER" ${pascal_compiler_flags_cmn}) - endif() + if(sdlmixer_version GREATER 9) + message(STATUS "Enabling enhanced SDL_Mixer calls") + set(pascal_compiler_flags_cmn "-dSDL_MIXER_NEWER" ${pascal_compiler_flags_cmn}) + endif() endif() find_file(sdlimage_h SDL_image.h ${SDLIMAGE_INCLUDE_DIR}) if(sdlimage_h) - file(STRINGS ${sdlimage_h} sdlimage_version_tmp REGEX "SDL_IMAGE_PATCHLEVEL[\t' ']+[0-9]+") - string(REGEX MATCH ".([0-9]+)" sdlimage_version "${sdlimage_version_tmp}") + file(STRINGS ${sdlimage_h} sdlimage_version_tmp REGEX "SDL_IMAGE_PATCHLEVEL[\t' ']+[0-9]+") + string(REGEX MATCH ".([0-9]+)" sdlimage_version "${sdlimage_version_tmp}") - if(sdlimage_version GREATER 7) - message(STATUS "Enabling enhanced SDL_Image calls") - set(pascal_compiler_flags_cmn "-dSDL_IMAGE_NEWER" ${pascal_compiler_flags_cmn}) - endif() + if(sdlimage_version GREATER 7) + message(STATUS "Enabling enhanced SDL_Image calls") + set(pascal_compiler_flags_cmn "-dSDL_IMAGE_NEWER" ${pascal_compiler_flags_cmn}) + endif() endif() #SOURCE AND PROGRAMS SECTION @@ -36,86 +36,95 @@ set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwengine.pas) set(engine_sources - ${hwengine_project} - SDLh.pas - uAI.pas - uAIActions.pas - uAIAmmoTests.pas - uAIMisc.pas - uAmmos.pas - uChat.pas - uCollisions.pas - uConsole.pas - uConsts.pas - uFloat.pas - uGame.pas - uGears.pas - uIO.pas - uKeys.pas - uLand.pas - uLandGraphics.pas - uLandObjects.pas - uLandTemplates.pas - uLandTexture.pas - uLocale.pas - uMisc.pas - uMobile.pas - uRandom.pas - uScript.pas - adler32.pas - uSound.pas - uStats.pas - uStore.pas - uTeams.pas - uVisualGears.pas - uWorld.pas - CCHandlers.inc - GSHandlers.inc - VGSHandlers.inc - GearDrawing.inc - HHHandlers.inc - SinTable.inc - ArgParsers.inc - options.inc - ${CMAKE_CURRENT_BINARY_DIR}/config.inc - ) + ${hwengine_project} + SDLh.pas + uAI.pas + uAIActions.pas + uAIAmmoTests.pas + uAIMisc.pas + uAmmos.pas + uCaptions.pas + uChat.pas + uCollisions.pas + uCommands.pas + uCommandHandlers.pas + uConsole.pas + uConsts.pas + uDebug.pas + uFloat.pas + uGame.pas + uGears.pas + uGearsRender.pas + uIO.pas + uKeys.pas + uLand.pas + uLandGraphics.pas + uLandObjects.pas + uLandPainted.pas + uLandTemplates.pas + uLandTexture.pas + uLocale.pas + uMisc.pas + uMobile.pas + uRandom.pas + uRender.pas + uRenderUtils.pas + uScript.pas + uSinTable.pas + uSound.pas + uStats.pas + uStore.pas + uTeams.pas + uTextures.pas + uTypes.pas + uUtils.pas + uVisualGears.pas + uWorld.pas + GSHandlers.inc + VGSHandlers.inc + HHHandlers.inc + ArgParsers.inc + options.inc + adler32.pas + ${CMAKE_CURRENT_BINARY_DIR}/config.inc + ) if(BUILD_ENGINE_LIBRARY) - message(STATUS "Engine will be built as library (experimental)") - set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwLibrary.pas) - set(engine_sources ${hwengine_project} PascalExports.pas ${engine_sources}) - set(pascal_compiler_flags_cmn "-dHWLIBRARY" "-k-no_order_inits" "-fPIC" ${pascal_compiler_flags_cmn}) + message(STATUS "Engine will be built as library (experimental)") + set(hwengine_project ${hedgewars_SOURCE_DIR}/hedgewars/hwLibrary.pas) + set(engine_sources ${hwengine_project} PascalExports.pas ${engine_sources}) + set(pascal_compiler_flags_cmn "-dHWLIBRARY" "-k-no_order_inits" "-fPIC" ${pascal_compiler_flags_cmn}) endif(BUILD_ENGINE_LIBRARY) find_program(fpc_executable ${fpc_tryexe}) if(fpc_executable) - exec_program(${fpc_executable} ARGS "-iV" OUTPUT_VARIABLE fpc_output) + exec_program(${fpc_executable} ARGS "-iV" OUTPUT_VARIABLE fpc_output) endif(fpc_executable) set(noexecstack_flags "-k-z" "-knoexecstack") file(WRITE ${EXECUTABLE_OUTPUT_PATH}/checkstack.pas "begin end.") exec_program(${fpc_executable} ${EXECUTABLE_OUTPUT_PATH} - ARGS ${noexecstack_flags} checkstack.pas - OUTPUT_VARIABLE noout - RETURN_VALUE testnoexecstack - ) + ARGS ${noexecstack_flags} checkstack.pas + OUTPUT_VARIABLE noout + RETURN_VALUE testnoexecstack + ) if(${testnoexecstack}) - set (noexecstack_flags "") + set (noexecstack_flags "") endif(${testnoexecstack}) if(APPLE) - string(REGEX MATCH "[pP][pP][cC]+" powerpc_build "${CMAKE_OSX_ARCHITECTURES}") - string(REGEX MATCH "[iI]386+" i386_build "${CMAKE_OSX_ARCHITECTURES}") - string(REGEX MATCH "[xX]86_64+" x86_64_build "${CMAKE_OSX_ARCHITECTURES}") + string(REGEX MATCH "[pP][pP][cC]+" powerpc_build "${CMAKE_OSX_ARCHITECTURES}") + string(REGEX MATCH "[iI]386+" i386_build "${CMAKE_OSX_ARCHITECTURES}") + string(REGEX MATCH "[xX]86_64+" x86_64_build "${CMAKE_OSX_ARCHITECTURES}") - if(powerpc_build) - set(powerpc_build "powerpc") - endif() + if(powerpc_build) + set(powerpc_build "powerpc") + endif() endif(APPLE) @@ -123,19 +132,19 @@ string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" fpc_version "${fpc_output}") if(fpc_version) - string(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" fpc_vers_major "${fpc_version}") - string(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" fpc_vers_minor "${fpc_version}") - string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" fpc_vers_patch "${fpc_version}") - message(STATUS "Freepascal version detected: ${fpc_vers_major}.${fpc_vers_minor}") - math(EXPR fpc_ver "${fpc_vers_major}*10000 + ${fpc_vers_minor}*100 + ${fpc_vers_patch}") + string(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" fpc_vers_major "${fpc_version}") + string(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" fpc_vers_minor "${fpc_version}") + string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" fpc_vers_patch "${fpc_version}") + message(STATUS "Freepascal version detected: ${fpc_vers_major}.${fpc_vers_minor}") + math(EXPR fpc_ver "${fpc_vers_major}*10000 + ${fpc_vers_minor}*100 + ${fpc_vers_patch}") - if(fpc_ver LESS "020200") - message(FATAL_ERROR "Minimum required version of FreePascal is 2.2.0") - elseif(APPLE AND x86_64_build AND fpc_ver LESS "020400") - message(FATAL_ERROR "Minimum required version of FreePascal is 2.4.0 for building 64 bit applications!") - endif() + if(fpc_ver LESS "020200") + message(FATAL_ERROR "Minimum required version of FreePascal is 2.2.0") + elseif(APPLE AND x86_64_build AND fpc_ver LESS "020400") + message(FATAL_ERROR "Minimum required version of FreePascal is 2.4.0 for building 64 bit applications!") + endif() else() - message(FATAL_ERROR "No Pascal compiler found!") + message(FATAL_ERROR "No Pascal compiler found!") endif() set(pascal_compiler ${fpc_executable}) @@ -144,40 +153,40 @@ #DEPENDECIES AND EXECUTABLES SECTION IF(NOT APPLE OR BUILD_ENGINE_LIBRARY) - #here is the command for standard executables or for shared library - add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine${CMAKE_EXECUTABLE_SUFFIX}" - COMMAND "${pascal_compiler}" - ARGS ${pascal_compiler_flags} - MAIN_DEPENDENCY ${hwengine_project} - DEPENDS ${engine_sources} - ) + #here is the command for standard executables or for shared library + add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine${CMAKE_EXECUTABLE_SUFFIX}" + COMMAND "${pascal_compiler}" + ARGS ${pascal_compiler_flags} + MAIN_DEPENDENCY ${hwengine_project} + DEPENDS ${engine_sources} + ) ELSE() - #let's build sdlmain, which is absent from the framework - find_package(SDL REQUIRED) + #let's build sdlmain, which is absent from the framework + find_package(SDL REQUIRED) - set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) - include_directories(${SDL_INCLUDE_DIR}) + set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) + include_directories(${SDL_INCLUDE_DIR}) - add_library (SDLmain STATIC SDLMain.m) + add_library (SDLmain STATIC SDLMain.m) - #these are the dependencies for building a universal binary on Mac OS X - foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build}) - set(lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" ${lipo_args_list}) - add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" - COMMAND "${pascal_compiler}" - ARGS ${pascal_compiler_flags} -ohwengine.${build_arch} -P${build_arch} - MAIN_DEPENDENCY ${hwengine_project} - DEPENDS ${engine_sources} SDLmain lua - ) - add_custom_target(hwengine.${build_arch} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}") - endforeach() + #these are the dependencies for building a universal binary on Mac OS X + foreach (build_arch ${powerpc_build} ${i386_build} ${x86_64_build}) + set(lipo_args_list "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" ${lipo_args_list}) + add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}" + COMMAND "${pascal_compiler}" + ARGS ${pascal_compiler_flags} -ohwengine.${build_arch} -P${build_arch} + MAIN_DEPENDENCY ${hwengine_project} + DEPENDS ${engine_sources} SDLmain lua + ) + add_custom_target(hwengine.${build_arch} ALL DEPENDS "${EXECUTABLE_OUTPUT_PATH}/hwengine.${build_arch}") + endforeach() - add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine" - COMMAND "lipo" - ARGS ${lipo_args_list} -create -output ${EXECUTABLE_OUTPUT_PATH}/hwengine - DEPENDS ${lipo_args_list} - ) + add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/hwengine" + COMMAND "lipo" + ARGS ${lipo_args_list} -create -output ${EXECUTABLE_OUTPUT_PATH}/hwengine + DEPENDS ${lipo_args_list} + ) ENDIF() diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/GSHandlers.inc Tue Jan 04 12:53:46 2011 +0100 @@ -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, PHedgehog(gi^.Hedgehog)^.Team^.voicepack) + 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, PHedgehog(gi^.Hedgehog)^.Team^.voicepack) + PlaySound(sndNooo, gi^.Hedgehog^.Team^.voicepack) else - PlaySound(sndUhOh, PHedgehog(gi^.Hedgehog)^.Team^.voicepack); + PlaySound(sndUhOh, gi^.Hedgehog^.Team^.voicepack); + end; end; end; + gi := gi^.NextGear end; - gi := gi^.NextGear - end; end; //////////////////////////////////////////////////////////////////////////////// procedure doStepDrowningGear(Gear: PGear); @@ -107,37 +107,38 @@ 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 PHedgehog(Gear^.Hedgehog)^.Effects[heResurrectable] then + if Gear^.Hedgehog^.Effects[heResurrectable] then ResurrectHedgehog(Gear) else begin Gear^.doStep := @doStepDrowningGear; Gear^.State := Gear^.State and (not gstHHDriven); - AddCaption(Format(GetEventString(eidDrowned), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage); + AddCaption(Format(GetEventString(eidDrowned), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage); end end else @@ -152,30 +153,38 @@ 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 CheckGearDrowning := false; end; -procedure CheckCollision(Gear: PGear); +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,24 +197,23 @@ 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; //if _0_6 < Gear^.dY then - // PlaySound(sndOw4, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack) + // PlaySound(sndOw4, Gear^.Hedgehog^.Team^.voicepack) //else - // PlaySound(sndOw1, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); + // PlaySound(sndOw1, Gear^.Hedgehog^.Team^.voicepack); ApplyDamage(Gear, dmg, dsFall); 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; @@ -519,16 +527,169 @@ if (GameFlags and gfMoreWind) = 0 then Gear^.dX := Gear^.dX + cWindSpeed; doStepFallingGear(Gear); if (Gear^.State and gstCollision) <> 0 then - begin + begin doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, EXPLAutoSound); DeleteGear(Gear); exit - end; + 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 $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; + +//////////////////////////////////////////////////////////////////////////////// procedure doStepGrave(Gear: PGear); begin AllInactive := false; @@ -626,8 +787,8 @@ dec(Gear^.Timer); if Gear^.Timer = 0 then begin - PHedgehog(Gear^.Hedgehog)^.Gear^.Message:= PHedgehog(Gear^.Hedgehog)^.Gear^.Message and not gmAttack; - PHedgehog(Gear^.Hedgehog)^.Gear^.State:= PHedgehog(Gear^.Hedgehog)^.Gear^.State and not gstAttacking; + Gear^.Hedgehog^.Gear^.Message:= Gear^.Hedgehog^.Gear^.Message and not gmAttack; + Gear^.Hedgehog^.Gear^.State:= Gear^.Hedgehog^.Gear^.State and not gstAttacking; AttackBar:= 0; Gear^.SoundChannel := LoopSound(sndBee); @@ -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; @@ -806,7 +970,7 @@ shell: PVisualGear; begin cArtillery := true; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.State := HHGear^.State or gstNotKickable; HedgehogChAngle(HHGear); if not cLaserSighting then @@ -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,61 +1062,66 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepPickHammerWork(Gear: PGear); var - i, ei: LongInt; + i, ei, x, y: LongInt; HHGear: PGear; begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; 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, 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; @@ -973,7 +1145,7 @@ HHGear: PGear; begin i := 0; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; y := hwRound(Gear^.Y) - cHHRadius * 2; while y < hwRound(Gear^.Y) do @@ -1005,7 +1177,7 @@ begin AllInactive := false; dec(Gear^.Timer); - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HedgehogChAngle(HHGear); @@ -1087,7 +1259,7 @@ begin BTPrevAngle := High(LongInt); BTSteps := 0; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.Message := 0; HHGear^.State := HHGear^.State or gstNotKickable; Gear^.doStep := @doStepBlowTorchWork @@ -1102,14 +1274,14 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; if ((HHGear^.State and gstHHDriven) = 0) or (CheckGearDrowning(HHGear)) or TestCollisionYwithGear(HHGear, 1) then begin DeleteGear(Gear); isCursorVisible := false; - ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^); + ApplyAmmoChanges(HHGear^.Hedgehog^); exit end; @@ -1121,18 +1293,18 @@ 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 Gear^.X := HHGear^.X; Gear^.Y := HHGear^.Y; - ApplyAngleBounds(PHedgehog(Gear^.Hedgehog)^, amRope); + ApplyAngleBounds(Gear^.Hedgehog^, amRope); Gear^.dX := SignAs(AngleSin(HHGear^.Angle), HHGear^.dX); Gear^.dY := -AngleCos(HHGear^.Angle); - Gear^.Friction := _450; + Gear^.Friction := _450 * _0_01 * cRopePercent; Gear^.Elasticity := _0; Gear^.State := Gear^.State and not gsttmpflag; Gear^.doStep := @doStepRope; @@ -1170,7 +1342,7 @@ end; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; if ((HHGear^.State and gstHHDriven) = 0) or (CheckGearDrowning(HHGear)) then @@ -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; ///// @@ -1240,7 +1412,7 @@ begin lx := hwRound(nx); ly := hwRound(ny); - if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] <> 0) then + if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and ((Land[ly, lx] and $FF00) <> 0) then begin ny := _1 / Distance(ropeDx, ropeDy); // old rope pos @@ -1330,10 +1502,47 @@ HHGear^.dY := HHGear^.dY * len; end; - + 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 + // 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 + 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; + + 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 PHedgehog(Gear^.Hedgehog)^ do + with Gear^.Hedgehog^ do begin PlaySound(sndRopeRelease); if CurAmmoType <> amParachute then @@ -1341,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); @@ -1356,10 +1566,10 @@ begin if (Gear^.State and gstAttacked) = 0 then begin - OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^); + OnUsedAmmo(HHGear^.Hedgehog^); Gear^.State := Gear^.State or gstAttacked end; - ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^) + ApplyAmmoChanges(HHGear^.Hedgehog^) end; begin @@ -1367,7 +1577,7 @@ Gear^.Y := Gear^.Y - Gear^.dY; Gear^.Elasticity := Gear^.Elasticity + _1; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; DeleteCI(HHGear); if (HHGear^.State and gstMoving) <> 0 then @@ -1389,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; @@ -1397,8 +1607,7 @@ ty := _0; while tt > _20 do begin - if TestCollisionXwithXYShift(Gear, tx, hwRound(ty), -hwSign(Gear^.dX)) - or TestCollisionYwithXYShift(Gear, hwRound(tx), hwRound(ty), -hwSign(Gear^.dY)) then + if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] and $FF00) <> 0) then begin Gear^.X := Gear^.X + tx; Gear^.Y := Gear^.Y + ty; @@ -1422,7 +1631,7 @@ end; end; - CheckCollision(Gear); + CheckCollisionWithLand(Gear); if (Gear^.State and gstCollision) <> 0 then if Gear^.Elasticity < _10 then @@ -1447,7 +1656,7 @@ or ((HHGear^.State and gstHHDriven) = 0) or (HHGear^.Damage > 0) then begin - with PHedgehog(Gear^.Hedgehog)^.Gear^ do + with Gear^.Hedgehog^.Gear^ do begin State := State and not gstAttacking; Message := Message and not gmAttack @@ -1763,28 +1972,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; @@ -1808,7 +2001,7 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.State := HHGear^.State or gstNoDamage; DeleteCI(HHGear); @@ -1825,15 +2018,15 @@ HHGear: PGear; i: LongInt; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.State := HHGear^.State or gstNoDamage; 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; @@ -1857,13 +2050,12 @@ if ((GameTicks mod 100) = 0) then begin - vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire); + vgt:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtFire, gstTmpFlag); if vgt <> nil then begin vgt^.dx:= 0; vgt^.dy:= 0; vgt^.FrameTicks:= 1800 div (Gear^.Tag mod 3 + 2); - vgt^.State:= gstTmpFlag; end; end; @@ -1978,7 +2170,7 @@ exit end; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; if hwRound(HHGear^.Y) <= Gear^.Tag - 2 then begin Gear^.Tag := hwRound(HHGear^.Y); @@ -2008,7 +2200,7 @@ HHGear: PGear; begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; DeleteCI(HHGear); HHGear^.X := int2hwFloat(hwRound(HHGear^.X)) - _0_5; HHGear^.dX := SignAs(cLittle, Gear^.dX); @@ -2021,7 +2213,7 @@ Gear^.doStep := @doStepFirePunchWork; DrawTunnel(HHGear^.X - int2hwFloat(cHHRadius), HHGear^.Y + _1, _0_5, _0, cHHRadius * 4, 5); - PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), PHedgehog(HHGear^.Hedgehog)^.Team^. + PlaySound(TSound(ord(sndFirePunch1) + GetRandom(6)), HHGear^.Hedgehog^.Team^. voicepack) end; @@ -2031,7 +2223,7 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; inc(Gear^.Timer); @@ -2049,18 +2241,20 @@ end; DeleteGear(Gear); isCursorVisible := false; - ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^); + ApplyAmmoChanges(HHGear^.Hedgehog^); 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 @@ -2070,7 +2264,7 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; DeleteCI(HHGear); @@ -2133,9 +2327,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; @@ -2167,7 +2365,7 @@ begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; tx := int2hwFloat(TargetPoint.X); ty := int2hwFloat(TargetPoint.Y); x := HHGear^.X; @@ -2202,8 +2400,8 @@ var HHGear: PGear; begin - PHedgehog(Gear^.Hedgehog)^.Unplaced := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + Gear^.Hedgehog^.Unplaced := false; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.Y := HHGear^.Y + HHGear^.dY; // hedgehog falling to collect cases HHGear^.dY := HHGear^.dY + cGravity; @@ -2233,7 +2431,7 @@ begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + 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 @@ -2275,14 +2473,14 @@ if ((Gear^.Message and not gmSwitch) <> 0) or (TurnTimeLeft = 0) then begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; Msg := Gear^.Message and not gmSwitch; DeleteGear(Gear); - OnUsedAmmo(PHedgehog(HHGear^.Hedgehog)^); - ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^); + OnUsedAmmo(HHGear^.Hedgehog^); + ApplyAmmoChanges(HHGear^.Hedgehog^); HHGear := CurrentHedgehog^.Gear; - ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^); + ApplyAmmoChanges(HHGear^.Hedgehog^); HHGear^.Message := Msg; exit end; @@ -2326,7 +2524,7 @@ begin Gear^.doStep := @doStepSwitcherWork; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; with HHGear^ do begin State := State and not gstAttacking; @@ -2377,7 +2575,7 @@ begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.State := HHGear^.State or gstNoDamage; DeleteCI(HHGear); @@ -2437,7 +2635,7 @@ if Gear^.Timer = 0 then begin Gear^.Pos := 1; - PlaySound(sndKamikaze, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); + PlaySound(sndKamikaze, Gear^.Hedgehog^.Team^.voicepack); Gear^.doStep := @doStepKamikazeWork end end; @@ -2448,7 +2646,7 @@ begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.dX := Gear^.dX; HHGear^.dY := Gear^.dY; @@ -2637,7 +2835,7 @@ begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.Message := HHGear^.Message and (not gmAttack); DeleteCI(HHGear); Gear^.IntersectGear:= nil; @@ -2661,7 +2859,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; @@ -2669,13 +2867,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); @@ -2687,7 +2885,7 @@ Gear^.Timer := 0; inc(Gear^.Pos); if Gear^.Pos = 5 then - PlaySound(sndYoohoo, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack) + PlaySound(sndYoohoo, Gear^.Hedgehog^.Team^.voicepack) end; if Gear^.Pos = 14 then @@ -2697,7 +2895,7 @@ procedure doStepSeduction(Gear: PGear); begin AllInactive := false; - DeleteCI(PHedgehog(Gear^.Hedgehog)^.Gear); + DeleteCI(Gear^.Hedgehog^.Gear); Gear^.doStep := @doStepSeductionWear end; @@ -2732,6 +2930,9 @@ end; //////////////////////////////////////////////////////////////////////////////// +procedure doStepDrill(Gear: PGear); +forward; + procedure doStepDrillDrilling(Gear: PGear); var t: PGearArray; @@ -2760,10 +2961,11 @@ 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 @@ -2772,7 +2974,12 @@ doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 50, 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^.doStep := @doStepDrill + end; dec(Gear^.Timer); end; @@ -2836,7 +3043,7 @@ begin AllInactive := false; dec(Gear^.Timer); - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HedgehogChAngle(HHGear); gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle); gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle); @@ -2864,7 +3071,7 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.Message := HHGear^.Message and not (gmUp or gmDown); HHGear^.State := HHGear^.State or gstNotKickable; Gear^.doStep := @doStepBallgunWork @@ -2884,12 +3091,7 @@ 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 := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; FollowGear := Gear; fChanged := false; @@ -2931,71 +3133,42 @@ 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); for i:= 0 to 32 do @@ -3012,10 +3185,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 @@ -3025,7 +3194,7 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.Message := 0; HHGear^.State := HHGear^.State or gstNotKickable; Gear^.Angle := HHGear^.Angle; @@ -3045,7 +3214,7 @@ isUnderwater:= cWaterLine < hwRound(Gear^.Y) + Gear^.Radius; if Gear^.Pos > 0 then dec(Gear^.Pos); AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; //dec(Gear^.Timer); move := _0_2; fuel := 50; @@ -3152,7 +3321,7 @@ end; DeleteGear(Gear); isCursorVisible := false; - ApplyAmmoChanges(PHedgehog(HHGear^.Hedgehog)^); + ApplyAmmoChanges(HHGear^.Hedgehog^); // if Gear^.Tex <> nil then FreeTexture(Gear^.Tex); // Gear^.Tex:= RenderStringTex(trmsg[sidFuel] + ': ' + inttostr(round(Gear^.Health / 20)) + '%', cWhiteColor, fntSmall) @@ -3169,7 +3338,7 @@ Gear^.Pos:= 0; Gear^.doStep := @doStepJetpackWork; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; FollowGear := HHGear; AfterAttack; with HHGear^ do @@ -3376,7 +3545,7 @@ if (Gear^.State and gstCollision) <> 0 then begin - doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 11, EXPLPoisoned, $C0E0FFE0); + doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 10, EXPLPoisoned, $C0E0FFE0); PlaySound(sndEggBreak); AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg); vg := AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtEgg); @@ -3396,8 +3565,7 @@ //////////////////////////////////////////////////////////////////////////////// procedure doPortalColorSwitch(); -var flags: LongWord; - CurWeapon: PAmmo; +var CurWeapon: PAmmo; begin if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) @@ -3408,11 +3576,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; @@ -3427,7 +3594,7 @@ // destroy portal if ground it was attached too is gone if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0) or (Gear^.Timer < 1) - or (PHedgehog(Gear^.Hedgehog) <> CurrentHedgehog) + or (Gear^.Hedgehog <> CurrentHedgehog) or (hwRound(Gear^.Y) > cWaterLine) then begin deleteGear(Gear); @@ -3636,7 +3803,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'); @@ -3681,8 +3848,7 @@ s: hwFloat; procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean); -var - flags: LongWord; +var CurWeapon: PAmmo; begin if CurrentHedgehog <> nil then @@ -3691,18 +3857,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; @@ -3754,7 +3921,7 @@ doPortalColorSwitch(); doStepPerPixel(Gear, @doStepMovingPortal_real, true); if (Gear^.Timer < 1) - or (PHedgehog(Gear^.Hedgehog) <> CurrentHedgehog) then + or (Gear^.Hedgehog <> CurrentHedgehog) then deleteGear(Gear); end; @@ -3787,11 +3954,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 @@ -4047,7 +4211,7 @@ Fire: PGear; begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HedgehogChAngle(HHGear); gX := hwRound(Gear^.X) + GetLaunchX(amBallgun, hwSign(HHGear^.dX), HHGear^.Angle); gY := hwRound(Gear^.Y) + GetLaunchY(amBallgun, HHGear^.Angle); @@ -4111,7 +4275,7 @@ var HHGear: PGear; begin - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; HHGear^.Message := HHGear^.Message and not (gmUp or gmDown or gmLeft or gmRight); HHGear^.State := HHGear^.State or gstNotKickable; Gear^.doStep := @doStepFlamethrowerWork @@ -4140,7 +4304,7 @@ t: PGearArray; i: LongInt; begin -HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear; +HHGear:= Gear^.Hedgehog^.Gear; HHGear^.State:= HHGear^.State or gstNoDamage; DeleteCI(HHGear); @@ -4181,7 +4345,7 @@ HHGear: PGear; begin AllInactive := false; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; dec(Gear^.Timer); if (HHGear = nil) or (Gear^.Timer = 0) or ((Gear^.Message and gmDestroy) <> 0) then begin @@ -4234,7 +4398,7 @@ HHGear: PGear; begin i := 0; - HHGear := PHedgehog(Gear^.Hedgehog)^.Gear; + HHGear := Gear^.Hedgehog^.Gear; y := hwRound(Gear^.Y) - cHHRadius * 2; while y < hwRound(Gear^.Y) do @@ -4265,9 +4429,12 @@ dec(TurnTimeLeft); AllInactive := false; - hh := PHedgehog(Gear^.Hedgehog); - DrawCentered(hwRound(hh^.Gear^.X) + WorldDx, hwRound(hh^.Gear^.Y) + WorldDy - + hh := Gear^.Hedgehog; + + // no, you can't do that here + {DrawCentered(hwRound(hh^.Gear^.X) + WorldDx, hwRound(hh^.Gear^.Y) + WorldDy - cHHRadius - 14 - hh^.HealthTagTex^.h, hh^.HealthTagTex); + } (*DrawCircle(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, 1.5, 0, 0, $FF, $FF);*) @@ -4321,13 +4488,13 @@ resgear^.Health := graves[i]^.Health; PHedgehog(graves[i]^.Hedgehog)^.Gear := resgear; DeleteGear(graves[i]); - RenderHealth(PHedgehog(resgear^.Hedgehog)^); - RecountTeamHealth(Phedgehog(resgear^.Hedgehog)^.Team); - PHedgehog(resgear^.Hedgehog)^.Effects[heResurrected]:= true; - if PHedgehog(resgear^.Hedgehog)^.Hat = 'NoHat' then + RenderHealth(resgear^.Hedgehog^); + RecountTeamHealth(resgear^.Hedgehog^.Team); + resgear^.Hedgehog^.Effects[heResurrected]:= true; + if resgear^.Hedgehog^.Hat = 'NoHat' then begin - FreeTexture(PHedgehog(resgear^.Hedgehog)^.HatTex); - PHedgehog(resgear^.Hedgehog)^.HatTex := Surface2Tex( + FreeTexture(resgear^.Hedgehog^.HatTex); + resgear^.Hedgehog^.HatTex := Surface2Tex( LoadImage(Pathz[ptHats] + '/Reserved/Zombie', ifNone), True) end diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/GearDrawing.inc --- a/hedgewars/GearDrawing.inc Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,854 +0,0 @@ -procedure DrawHH(Gear: PGear; ox, oy: LongInt); -var i, t: LongInt; - amt: TAmmoType; - sign, hx, hy, cx, cy, tx, ty, sx, sy, m: LongInt; // hedgehog, crosshair, temp, sprite, direction - dx, dy, ax, ay, aAngle, dAngle, hAngle, lx, ly: real; // laser, change - defaultPos, HatVisible: boolean; - HH: PHedgehog; - CurWeapon: PAmmo; -begin -HH:= PHedgehog(Gear^.Hedgehog); -if HH^.Unplaced then exit; -m:= 1; -if ((Gear^.State and gstHHHJump) <> 0) and not cArtillery then m:= -1; -sx:= ox + 1; // this offset is very common -sy:= oy - 3; -sign:= hwSign(Gear^.dX); - -if (Gear^.State and gstHHDeath) <> 0 then - begin - DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos); - Tint(HH^.Team^.Clan^.Color); - DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos + 8); - Tint($FF, $FF, $FF, $FF); - exit - end -else if (Gear^.State and gstHHGone) <> 0 then - begin - DrawRotatedF(sprTeleport, sx, sy, Gear^.Pos, sign, 0); - exit - end; - -defaultPos:= true; -HatVisible:= false; - - -if HH^.Effects[hePoisoned] then - begin - Tint($00, $FF, $40, $40); - DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 2, 0, 0, sx, sy, 0, 1, 22, 22, (RealTicks shr 36) mod 360); - Tint($FF, $FF, $FF, $FF) - end; - -if ((Gear^.State and gstWinner) <> 0) and - ((CurAmmoGear = nil) or (CurAmmoGear^.Kind <> gtPickHammer)) then - begin - DrawHedgehog(sx, sy, - sign, - 2, - 0, - 0); - defaultPos:= false - end; -if (Gear^.State and gstDrowning) <> 0 then - begin - DrawHedgehog(sx, sy, - sign, - 1, - 7, - 0); - defaultPos:= false - end else -if (Gear^.State and gstLoser) <> 0 then - begin - DrawHedgehog(sx, sy, - sign, - 2, - 3, - 0); - defaultPos:= false - end else - -if (Gear^.State and gstHHDriven) <> 0 then - begin - if ((Gear^.State and gstHHThinking) = 0) and - (ShowCrosshair or ((CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope))) and - ((Gear^.State and (gstAttacked or gstAnimation)) = 0) then - begin -(* These calculations are a little complex for a few reasons: - 1: I need to draw the laser from weapon origin to nearest land - 2: I need to start the beam outside the hedgie for attractiveness. - 3: I need to extend the beam beyond land. - This routine perhaps should be pushed into uStore or somesuch instead of continuuing the increase in size of this function. -*) - dx:= sign * m * Sin(Gear^.Angle * pi / cMaxAngle); - dy:= -Cos(Gear^.Angle * pi / cMaxAngle); - if cLaserSighting then - begin - lx:= GetLaunchX(HH^.CurAmmoType, sign * m, Gear^.Angle); - ly:= GetLaunchY(HH^.CurAmmoType, Gear^.Angle); - - // ensure we start outside the hedgehog (he's solid after all) - while abs(lx * lx + ly * ly) < (Gear^.radius * Gear^.radius) do - begin - lx:= lx + dx; - ly:= ly + dy - end; - - // add hog's position - lx:= lx + ox - WorldDx; - ly:= ly + oy - WorldDy; - - // decrease number of iterations required - ax:= dx * 4; - ay:= dy * 4; - - tx:= round(lx); - ty:= round(ly); - hx:= tx; - hy:= ty; - while ((ty and LAND_HEIGHT_MASK) = 0) and - ((tx and LAND_WIDTH_MASK) = 0) and - (Land[ty, tx] = 0) do // TODO: check for constant variable instead - begin - lx:= lx + ax; - ly:= ly + ay; - tx:= round(lx); - ty:= round(ly) - end; - // reached edge of land. assume infinite beam. Extend it way out past camera - if ((ty and LAND_HEIGHT_MASK) <> 0) or ((tx and LAND_WIDTH_MASK) <> 0) then - begin - tx:= round(lx + ax * (LAND_WIDTH div 4)); - ty:= round(ly + ay * (LAND_WIDTH div 4)); - end; - - //if (abs(lx-tx)>8) or (abs(ly-ty)>8) then - begin - DrawLine(hx, hy, tx, ty, 1.0, $FF, $00, $00, $C0); - end; - end; - // draw crosshair - cx:= Round(hwRound(Gear^.X) + dx * 80 + GetLaunchX(HH^.CurAmmoType, sign * m, Gear^.Angle)); - cy:= Round(hwRound(Gear^.Y) + dy * 80 + GetLaunchY(HH^.CurAmmoType, Gear^.Angle)); - DrawRotatedTex(HH^.Team^.CrosshairTex, - 12, 12, cx + WorldDx, cy + WorldDy, 0, - sign * (Gear^.Angle * 180.0) / cMaxAngle); - end; - hx:= ox + 8 * sign; - hy:= oy - 2; - aangle:= Gear^.Angle * 180 / cMaxAngle - 90; - if CurAmmoGear <> nil then - begin - case CurAmmoGear^.Kind of - gtShotgunShot: begin - if (CurAmmoGear^.State and gstAnimation <> 0) then - DrawRotated(sprShotgun, hx, hy, sign, aangle) - else - DrawRotated(sprHandShotgun, hx, hy, sign, aangle); - end; - gtDEagleShot: DrawRotated(sprDEagle, hx, hy, sign, aangle); - gtSniperRifleShot: begin - if (CurAmmoGear^.State and gstAnimation <> 0) then - DrawRotatedF(sprSniperRifle, hx, hy, 1, sign, aangle) - else - DrawRotatedF(sprSniperRifle, hx, hy, 0, sign, aangle) - end; - gtBallgun: DrawRotated(sprHandBallgun, hx, hy, sign, aangle); - gtRCPlane: begin - DrawRotated(sprHandPlane, hx, hy, sign, 0); - defaultPos:= false - end; - gtRope: begin - if Gear^.X < CurAmmoGear^.X then - begin - dAngle:= 0; - hAngle:= 180; - i:= 1 - end else - begin - dAngle:= 180; - hAngle:= 0; - i:= -1 - end; - if ((Gear^.State and gstWinner) = 0) then - begin - DrawHedgehog(ox, oy, - i, - 1, - 0, - DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + dAngle); - with HH^ do - if (HatTex <> nil) then - begin - DrawRotatedTextureF(HatTex, 1.0, -1.0, -6.0, ox, oy, 0, i, 32, 32, - i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle); - if HatTex^.w > 64 then - begin - Tint(HH^.Team^.Clan^.Color); - 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) - end - end - end; - DrawAltWeapon(Gear, ox, oy); - defaultPos:= false - end; - gtBlowTorch: begin - DrawRotated(sprBlowTorch, hx, hy, sign, aangle); - DrawHedgehog(sx, sy, - sign, - 3, - HH^.visStepPos div 2, - 0); - with HH^ do - if (HatTex <> nil) then - begin - DrawTextureF(HatTex, - 1, - sx, - sy - 5, - 0, - sign, - 32, - 32); - if HatTex^.w > 64 then - begin - Tint(HH^.Team^.Clan^.Color); - DrawTextureF(HatTex, - 1, - sx, - sy - 5, - 32, - sign, - 32, - 32); - Tint($FF, $FF, $FF, $FF) - end - end; - defaultPos:= false - end; - gtShover: DrawRotated(sprHandBaseball, hx, hy, sign, aangle + 180); - gtFirePunch: begin - DrawHedgehog(sx, sy, - sign, - 1, - 4, - 0); - defaultPos:= false - end; - gtPickHammer: begin - defaultPos:= false; - dec(sy,20); - end; - gtTeleport: defaultPos:= false; - gtWhip: begin - DrawRotatedF(sprWhip, - sx, - sy, - 1, - sign, - 0); - defaultPos:= false - end; - gtHammer: begin - DrawRotatedF(sprHammer, - sx, - sy, - 1, - sign, - 0); - defaultPos:= false - end; - gtResurrector: begin - DrawRotated(sprHandResurrector, sx, sy, 0, 0); - defaultPos:= false - end; - gtKamikaze: begin - if CurAmmoGear^.Pos = 0 then - DrawHedgehog(sx, sy, - sign, - 1, - 6, - 0) - else - DrawRotatedF(sprKamikaze, - ox, oy, - CurAmmoGear^.Pos - 1, - sign, - aangle); - defaultPos:= false - end; - gtSeduction: begin - if CurAmmoGear^.Pos >= 6 then - DrawHedgehog(sx, sy, - sign, - 2, - 2, - 0) - else - begin - DrawRotatedF(sprDress, - ox, oy, - CurAmmoGear^.Pos, - sign, - 0); - DrawSprite(sprCensored, ox - 32, oy - 20, 0) - end; - defaultPos:= false - end; - gtFlamethrower: begin - DrawRotatedF(sprHandFlamethrower, hx, hy, (RealTicks div 125) mod 4, sign, aangle); - if CurAmmoGear^.Tex <> nil then DrawCentered(sx, sy - 40, CurAmmoGear^.Tex) - end; - end; - - case CurAmmoGear^.Kind of - gtShotgunShot, - gtDEagleShot, - gtSniperRifleShot, - gtShover: begin - DrawHedgehog(sx, sy, - sign, - 0, - 4, - 0); - defaultPos:= false; - HatVisible:= true - end - end - end else - - if ((Gear^.State and gstHHJumping) <> 0) then - begin - DrawHedgehog(sx, sy, - sign*m, - 1, - 1, - 0); - HatVisible:= true; - defaultPos:= false - end else - - if (Gear^.Message and (gmLeft or gmRight) <> 0) and (not isCursorVisible) then - begin - DrawHedgehog(sx, sy, - sign, - 0, - HH^.visStepPos div 2, - 0); - defaultPos:= false; - HatVisible:= true - end - else - - if ((Gear^.State and gstAnimation) <> 0) then - begin - if (TWave(Gear^.Tag) < Low(TWave)) or (TWave(Gear^.Tag) > High(TWave)) then - begin - Gear^.State:= Gear^.State and not gstAnimation; - end - else - begin - DrawRotatedF(Wavez[TWave(Gear^.Tag)].Sprite, - sx, - sy, - Gear^.Pos, - sign, - 0.0); - defaultPos:= false - end - end - else - if ((Gear^.State and gstAttacked) = 0) then - begin - if HH^.Timer > 0 then - begin - // There must be a tidier way to do this. Anyone? - if aangle <= 90 then aangle:= aangle+360; - if Gear^.dX > _0 then aangle:= aangle-((aangle-240)*HH^.Timer/10) - else aangle:= aangle+((240-aangle)*HH^.Timer/10); - dec(HH^.Timer) - end; - amt:= CurrentHedgehog^.CurAmmoType; - CurWeapon:= GetAmmoEntry(HH^); - case amt of - amBazooka: DrawRotated(sprHandBazooka, 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); - amDrill: DrawRotated(sprHandDrill, hx, hy, sign, aangle); - amRope: DrawRotated(sprHandRope, hx, hy, sign, aangle); - amShotgun: DrawRotated(sprHandShotgun, hx, hy, sign, aangle); - amDEagle: DrawRotated(sprHandDEagle, hx, hy, sign, aangle); - amSineGun: DrawRotated(sprHandShotgun, hx, hy, sign, aangle); - 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); - amSniperRifle: DrawRotatedF(sprSniperRifle, hx, hy, 0, sign, aangle); - amBlowTorch: DrawRotated(sprHandBlowTorch, hx, hy, sign, aangle); - amCake: DrawRotated(sprHandCake, hx, hy, sign, aangle); - amGrenade: DrawRotated(sprHandGrenade, hx, hy, sign, aangle); - amWatermelon: DrawRotated(sprHandMelon, hx, hy, sign, aangle); - amSkip: DrawRotated(sprHandSkip, hx, hy, sign, aangle); - amClusterBomb: DrawRotated(sprHandCluster, hx, hy, sign, aangle); - amDynamite: DrawRotated(sprHandDynamite, hx, hy, sign, aangle); - amHellishBomb: DrawRotated(sprHandHellish, hx, hy, sign, aangle); - amGasBomb: DrawRotated(sprHandCheese, hx, hy, sign, aangle); - amMine: DrawRotated(sprHandMine, hx, hy, sign, aangle); - amSMine: DrawRotated(sprHandSMine, hx, hy, sign, aangle); - amSeduction: DrawRotated(sprHandSeduction, hx, hy, sign, aangle); - amVampiric: DrawRotatedF(sprHandVamp, hx, hy, (RealTicks div 125) mod 4, sign, aangle); - amRCPlane: begin - DrawRotated(sprHandPlane, hx, hy, sign, 0); - defaultPos:= false - end; - amGirder: begin - DrawRotated(sprHandConstruction, hx, hy, sign, aangle); - DrawSpriteClipped(sprGirder, - ox-256, - oy-256, - LongInt(topY)+WorldDy, - LongInt(rightX)+WorldDx, - cWaterLine+WorldDy, - LongInt(leftX)+WorldDx) - end; - amBee: DrawRotatedF(sprHandBee, hx, hy, (RealTicks div 125) mod 4, sign, aangle); - amFlamethrower: DrawRotatedF(sprHandFlamethrower, hx, hy, (RealTicks div 125) mod 4, sign, aangle); - amResurrector: DrawCircle(ox, oy, 98, 4, $F5, $DB, $35, $AA); // I'd rather not like to hardcode 100 here - end; - - case amt of - amAirAttack, - amMineStrike, - amDrillStrike: DrawRotated(sprHandAirAttack, sx, oy, sign, 0); - amPickHammer: DrawHedgehog(sx, sy, - sign, - 1, - 2, - 0); - amTeleport: DrawRotatedF(sprTeleport, sx, sy, 0, sign, 0); - amKamikaze: DrawHedgehog(sx, sy, - sign, - 1, - 5, - 0); - amWhip: DrawRotatedF(sprWhip, - sx, - sy, - 0, - sign, - 0); - amHammer: DrawRotatedF(sprHammer, - sx, - sy, - 0, - sign, - 0); - else - DrawHedgehog(sx, sy, - sign, - 0, - 4, - 0); - - HatVisible:= true; - (* with HH^ do - if (HatTex <> nil) - and (HatVisibility > 0) then - DrawTextureF(HatTex, - HatVisibility, - sx, - sy - 5, - 0, - sign, - 32, - 32); *) - end; - - case amt of - amBaseballBat: DrawRotated(sprHandBaseball, - sx - 4 * sign, - sy + 9, sign, aangle); - end; - - defaultPos:= false - end; - -end else // not gstHHDriven - begin - if (Gear^.Damage > 0) - and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then - begin - DrawHedgehog(sx, sy, - sign, - 2, - 1, - Gear^.DirAngle); - defaultPos:= false - end else - - if ((Gear^.State and gstHHJumping) <> 0) then - begin - DrawHedgehog(sx, sy, - sign*m, - 1, - 1, - 0); - defaultPos:= false - end; - end; - -with HH^ do - begin - if defaultPos then - begin - DrawRotatedF(sprHHIdle, - sx, - sy, - (RealTicks div 128 + Gear^.Pos) mod 19, - sign, - 0); - HatVisible:= true; - end; - - if HatVisible then - if HatVisibility < 1.0 then - HatVisibility:= HatVisibility + 0.2 - else - else - if HatVisibility > 0.0 then - HatVisibility:= HatVisibility - 0.2; - - if (HatTex <> nil) - and (HatVisibility > 0) then - if DefaultPos then - begin - DrawTextureF(HatTex, - HatVisibility, - sx, - sy - 5, - (RealTicks div 128 + Gear^.Pos) mod 19, - sign, - 32, - 32); - if HatTex^.w > 64 then - begin - Tint(HH^.Team^.Clan^.Color); - DrawTextureF(HatTex, - HatVisibility, - sx, - sy - 5, - (RealTicks div 128 + Gear^.Pos) mod 19 + 32, - sign, - 32, - 32); - Tint($FF, $FF, $FF, $FF) - end - end - else - begin - DrawTextureF(HatTex, - HatVisibility, - sx, - sy - 5, - 0, - sign*m, - 32, - 32); - if HatTex^.w > 64 then - begin - Tint(HH^.Team^.Clan^.Color); - DrawTextureF(HatTex, - HatVisibility, - sx, - sy - 5, - 32, - sign*m, - 32, - 32); - Tint($FF, $FF, $FF, $FF) - end - end - end; -if (Gear^.State and gstHHDriven) <> 0 then - begin -(* if (CurAmmoGear = nil) then - begin - amt:= CurrentHedgehog^.CurAmmoType; - case amt of - amJetpack: DrawSprite(sprJetpack, sx-32, sy-32, 0); - end - end; *) - if CurAmmoGear <> nil then - begin - case CurAmmoGear^.Kind of - gtJetpack: begin - DrawSprite(sprJetpack, sx-32, sy-32, 0); - if cWaterLine > hwRound(Gear^.Y) + Gear^.Radius then - begin - if (CurAmmoGear^.MsgParam and gmUp) <> 0 then DrawSprite(sprJetpack, sx-32, sy-28, 1); - if (CurAmmoGear^.MsgParam and gmLeft) <> 0 then DrawSprite(sprJetpack, sx-28, sy-28, 2); - if (CurAmmoGear^.MsgParam and gmRight) <> 0 then DrawSprite(sprJetpack, sx-36, sy-28, 3) - end; - if CurAmmoGear^.Tex <> nil then DrawCentered(sx, sy - 40, CurAmmoGear^.Tex); - DrawAltWeapon(Gear, sx, sy) - end; - end; - end - end; - -with HH^ do - begin - if ((Gear^.State and not gstWinner) = 0) - or ((Gear^.State = gstWait) and (Gear^.dY.QWordValue = 0)) - or (bShowFinger and ((Gear^.State and gstHHDriven) <> 0)) then - begin - t:= sy - cHHRadius - 9; - if (cTagsMask and htTransparent) <> 0 then - Tint($FF, $FF, $FF, $80); - if ((cTagsMask and htHealth) <> 0) then - begin - dec(t, HealthTagTex^.h + 2); - DrawCentered(ox, t, HealthTagTex) - end; - if (cTagsMask and htName) <> 0 then - begin - dec(t, NameTagTex^.h + 2); - DrawCentered(ox, t, NameTagTex) - end; - if (cTagsMask and htTeamName) <> 0 then - begin - dec(t, Team^.NameTagTex^.h + 2); - DrawCentered(ox, t, Team^.NameTagTex) - end; - if (cTagsMask and htTransparent) <> 0 then - Tint($FF, $FF, $FF, $FF) - end; - if (Gear^.State and gstHHDriven) <> 0 then // Current hedgehog - begin - if bShowFinger and ((Gear^.State and gstHHDriven) <> 0) then - DrawSprite(sprFinger, ox - 16, oy - 64, - GameTicks div 32 mod 16); - - if (Gear^.State and gstDrowning) = 0 then - if (Gear^.State and gstHHThinking) <> 0 then - DrawSprite(sprQuestion, ox - 10, oy - cHHRadius - 34, (RealTicks shr 9) mod 8) - end - end; - -if HH^.Effects[hePoisoned] then - begin - Tint($00, $FF, $40, $80); - DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 1.5, 0, 0, sx, sy, 0, 1, 22, 22, 360 - (RealTicks shr 37) mod 360); - end; -if HH^.Effects[heResurrected] then - begin - Tint($f5, $db, $35, $20); - DrawSprite(sprVampiric, sx - 24, sy - 24, 0); - end; - -if Gear^.Invulnerable then - begin - Tint($FF, $FF, $FF, max($40, floor($FF * abs(1 - ((RealTicks div 2 + Gear^.uid * 491) mod 1500) / 750)))); - DrawSprite(sprInvulnerable, sx - 24, sy - 24, 0); - end; -if cVampiric and - (CurrentHedgehog^.Gear <> nil) and - (CurrentHedgehog^.Gear = Gear) then - begin - Tint($FF, 0, 0, max($40, floor($FF * abs(1 - (RealTicks mod 1500) / 750)))); - DrawSprite(sprVampiric, sx - 24, sy - 24, 0); - end; - Tint($FF, $FF, $FF, $FF) -end; - -procedure DrawGears; -var Gear, HHGear: PGear; - i: Longword; - x, y, startX, endX, startY, endY: LongInt; -begin -Gear:= GearsList; -while Gear<>nil do - begin - x:= hwRound(Gear^.X) + WorldDx; - y:= hwRound(Gear^.Y) + WorldDy; - case Gear^.Kind of - gtBomb: DrawRotated(sprBomb, x, y, 0, Gear^.DirAngle); - gtGasBomb: DrawRotated(sprCheese, x, y, 0, Gear^.DirAngle); - gtMolotov: DrawRotated(sprMolotov, x, y, 0, Gear^.DirAngle); - - gtRCPlane: begin - if (Gear^.Tag = -1) then - 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); - - gtPortal: if ((Gear^.Tag and 1) = 0) // still moving? - or (Gear^.IntersectGear = nil) or (Gear^.IntersectGear^.IntersectGear <> Gear) // not linked&backlinked? - or ((Gear^.IntersectGear^.Tag and 1) = 0) then // linked portal still moving? - DrawRotatedf(sprPortal, x, y, Gear^.Tag, hwSign(Gear^.dX), Gear^.DirAngle) - else DrawRotatedf(sprPortal, x, y, 4 + Gear^.Tag div 2, hwSign(Gear^.dX), Gear^.DirAngle); - - gtDrill: if (Gear^.State and gsttmpFlag) <> 0 then - DrawRotated(sprAirDrill, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)) - else - DrawRotated(sprDrill, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); - - gtHedgehog: DrawHH(Gear, x, y); - - gtShell: DrawRotated(sprBazookaShell, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); - - gtGrave: begin - DrawTextureF(PHedgehog(Gear^.Hedgehog)^.Team^.GraveTex, 1, x, y, (GameTicks shr 7+Gear^.uid) and 7, 1, 32, 32); - if Gear^.Health > 0 then - begin - //Tint($33, $33, $FF, max($40, floor($FF * abs(1 - (GameTicks mod (6000 div Gear^.Health)) / 750)))); - Tint($f5, $db, $35, max($40, floor($FF * abs(1 - (GameTicks mod 1500) / (750 + Gear^.Health))))); - //Tint($FF, $FF, $FF, max($40, floor($FF * abs(1 - (RealTicks mod 1500) / 750)))); - DrawSprite(sprVampiric, x - 24, y - 24, 0); - Tint($FF, $FF, $FF, $FF) - end - end; - gtBee: DrawRotatedF(sprBee, x, y, (GameTicks shr 5) mod 2, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); - gtPickHammer: DrawSprite(sprPHammer, x - 16, y - 50 + LongInt(((GameTicks shr 5) and 1) * 2), 0); - gtRope: DrawRope(Gear); - gtMine: if (((Gear^.State and gstAttacking) = 0)or((Gear^.Timer and $3FF) < 420)) and (Gear^.Health <> 0) then - DrawRotated(sprMineOff, x, y, 0, Gear^.DirAngle) - else if Gear^.Health <> 0 then DrawRotated(sprMineOn, x, y, 0, Gear^.DirAngle) - else DrawRotated(sprMineDead, x, y, 0, Gear^.DirAngle); - gtSMine: if (((Gear^.State and gstAttacking) = 0)or((Gear^.Timer and $3FF) < 420)) and (Gear^.Health <> 0) then - DrawRotated(sprSMineOff, x, y, 0, Gear^.DirAngle) - else if Gear^.Health <> 0 then DrawRotated(sprSMineOn, x, y, 0, Gear^.DirAngle) - else DrawRotated(sprMineDead, x, y, 0, Gear^.DirAngle); - gtCase: case Gear^.Pos of - posCaseAmmo : begin - i:= (GameTicks shr 6) mod 64; - if i > 18 then i:= 0; - DrawSprite(sprCase, x - 24, y - 24, i); - end; - posCaseHealth: begin - i:= ((GameTicks shr 6) + 38) mod 64; - if i > 13 then i:= 0; - DrawSprite(sprFAid, x - 24, y - 24, i); - end; - posCaseUtility: begin - i:= (GameTicks shr 6) mod 70; - if i > 23 then i:= 0; - i:= i mod 12; - DrawSprite(sprUtility, x - 24, y - 24, i); - end; - end; - gtExplosives: begin - if ((Gear^.State and gstDrowning) <> 0) then - DrawSprite(sprExplosivesRoll, x - 24, y - 24, 0) - else if Gear^.State and gstAnimation = 0 then - begin - i:= (GameTicks shr 6 + Gear^.uid*3) mod 64; - if i > 18 then i:= 0; - DrawSprite(sprExplosives, x - 24, y - 24, i) - end - else if Gear^.State and gsttmpFlag = 0 then - DrawRotatedF(sprExplosivesRoll, x, y + 4, 0, 0, Gear^.DirAngle) - else - DrawRotatedF(sprExplosivesRoll, x, y + 4, 1, 0, Gear^.DirAngle); - end; - gtDynamite: DrawSprite2(sprDynamite, x - 16, y - 25, Gear^.Tag and 1, Gear^.Tag shr 1); - gtClusterBomb: DrawRotated(sprClusterBomb, x, y, 0, Gear^.DirAngle); - gtCluster: DrawSprite(sprClusterParticle, x - 8, y - 8, 0); - gtFlame: DrawTextureF(SpritesData[sprFlame].Texture, 2 / (Gear^.Tag mod 3 + 2), x, y, (GameTicks shr 7 + LongWord(Gear^.Tag)) mod 8, 1, 16, 16); - gtParachute: begin - DrawSprite(sprParachute, x - 24, y - 48, 0); - DrawAltWeapon(Gear, x + 1, y - 3) - end; - gtAirAttack: if Gear^.Tag > 0 then DrawSprite(sprAirplane, x - SpritesData[sprAirplane].Width div 2, y - SpritesData[sprAirplane].Height div 2, 0) - else DrawSprite(sprAirplane, x - SpritesData[sprAirplane].Width div 2, y - SpritesData[sprAirplane].Height div 2, 1); - gtAirBomb: DrawRotated(sprAirBomb, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); - gtTeleport: begin - HHGear:= PHedgehog(Gear^.Hedgehog)^.Gear; - if not PHedgehog(Gear^.Hedgehog)^.Unplaced then DrawRotatedF(sprTeleport, x + 1, y - 3, Gear^.Pos, hwSign(Gear^.dX), 0); - DrawRotatedF(sprTeleport, hwRound(HHGear^.X) + 1 + WorldDx, hwRound(HHGear^.Y) - 3 + WorldDy, 11 - Gear^.Pos, hwSign(HHGear^.dX), 0); - end; - gtSwitcher: DrawSprite(sprSwitch, x - 16, y - 56, (GameTicks shr 6) mod 12); - gtTarget: begin - Tint($FF, $FF, $FF, floor($FF * Gear^.Timer / 1000)); - DrawSprite(sprTarget, x - 16, y - 16, 0); - Tint($FF, $FF, $FF, $FF); - end; - gtMortar: DrawRotated(sprMortar, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); - gtCake: if Gear^.Pos = 6 then - DrawRotatedf(sprCakeWalk, x, y, (GameTicks div 40) mod 6, hwSign(Gear^.dX), Gear^.DirAngle * hwSign(Gear^.dX) + 90) - else - DrawRotatedf(sprCakeDown, x, y, 5 - Gear^.Pos, hwSign(Gear^.dX), Gear^.DirAngle * hwSign(Gear^.dX) + 90); - gtSeduction: if Gear^.Pos >= 14 then DrawSprite(sprSeduction, x - 16, y - 16, 0); - gtWatermelon: DrawRotatedf(sprWatermelon, x, y, 0, 0, Gear^.DirAngle); - gtMelonPiece: DrawRotatedf(sprWatermelon, x, y, 1, 0, Gear^.DirAngle); - gtHellishBomb: DrawRotated(sprHellishBomb, x, y, 0, Gear^.DirAngle); - gtBirdy: begin - if Gear^.State and gstAnimation = gstAnimation then - begin - if Gear^.State and gstTmpFlag = 0 then // Appearing - begin - endX:= x - WorldDx; - endY:= y - WorldDy; - if Gear^.Tag < 0 then - startX:= max(LAND_WIDTH + 1024, endX + 2048) - else - startX:= max(-LAND_WIDTH - 1024, endX - 2048); - startY:= endY - 256; - DrawTextureF(SpritesData[sprBirdy].Texture, 1, startX + WorldDx + floor((endX - startX) * (-power(2, -10 * LongInt(Gear^.Timer)/2000) + 1)), startY + WorldDy + floor((endY - startY) * sqrt(1 - power((LongInt(Gear^.Timer)/2000)-1, 2))), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75); - end - else // Disappearing - begin - startX:= x - WorldDx; - startY:= y - WorldDy; - if Gear^.Tag > 0 then - endX:= max(LAND_WIDTH + 1024, startX + 2048) - else - endX:= max(-LAND_WIDTH - 1024, startX - 2048); - endY:= startY + 256; - DrawTextureF(SpritesData[sprBirdy].Texture, 1, startX + WorldDx + floor((endX - startX) * power(2, 10 * (LongInt(Gear^.Timer)/2000 - 1))) + hwRound(Gear^.dX * Gear^.Timer), startY + WorldDy + floor((endY - startY) * cos(LongInt(Gear^.Timer)/2000 * (Pi/2)) - (endY - startY)) + hwRound(Gear^.dY * Gear^.Timer), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75); - end; - end - else - DrawTextureF(SpritesData[sprBirdy].Texture, 1, x, y, ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75); - end; - gtEgg: DrawRotatedTextureF(SpritesData[sprEgg].Texture, 1, 0, 0, x, y, 0, 1, 16, 16, Gear^.DirAngle); - gtPiano: begin - if (Gear^.State and gstDrowning) = 0 then - begin - Tint($FF, $FF, $FF, $10); - for i:= 8 downto 1 do - DrawRotatedTextureF(SpritesData[sprPiano].Texture, 1, 0, 0, x, y - hwRound(Gear^.dY * 4 * i), 0, 1, 128, 128, 0); - Tint($FF, $FF, $FF, $FF) - end; - DrawRotatedTextureF(SpritesData[sprPiano].Texture, 1, 0, 0, x, y, 0, 1, 128, 128, 0); - end; - gtPoisonCloud: begin - if Gear^.Timer < 1020 then - Tint($C0, $C0, $00, Gear^.Timer div 8) - else if Gear^.Timer > 3980 then - Tint($C0, $C0, $00, (5000 - Gear^.Timer) div 8) - else - Tint($C0, $C0, $00, $C0); - DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 3, 0, 0, x, y, 0, 1, 22, 22, (RealTicks shr 36 + Gear^.UID * 100) mod 360); - Tint($FF, $FF, $FF, $FF) - end; - gtResurrector: begin - DrawRotated(sprCross, x, y, 0, 0); - Tint($f5, $db, $35, max($00, floor($C0 * abs(1 - (GameTicks mod 6000) / 3000)))); - DrawTexture(x - 108, y - 108, SpritesData[sprVampiric].Texture, 4.5); - Tint($FF, $FF, $FF, $FF); - end; - gtNapalmBomb: DrawRotated(sprNapalmBomb, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); - end; - if Gear^.RenderTimer and (Gear^.Tex <> nil) then DrawCentered(x + 8, y + 8, Gear^.Tex); - Gear:= Gear^.NextGear - end; -end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/HHHandlers.inc --- a/hedgewars/HHHandlers.inc Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/HHHandlers.inc Tue Jan 04 12:53:46 2011 +0100 @@ -48,7 +48,7 @@ ChangeAmmo:= false; slot:= Gear^.MsgParam; -with PHedgehog(Gear^.Hedgehog)^ do +with Gear^.Hedgehog^ do begin Gear^.Message:= Gear^.Message and not gmSlot; ammoidx:= 0; @@ -60,7 +60,7 @@ 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(PHedgehog(Gear^.Hedgehog)^); + if ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) <> 0) and (MultiShootAttacks > 0) then OnUsedAmmo(Gear^.Hedgehog^); MultiShootAttacks:= 0; Gear^.Message:= Gear^.Message and not (gmLJump or gmHJump); @@ -101,7 +101,7 @@ s: boolean; begin weap:= TAmmoType(Gear^.MsgParam); -Hedgehog:= PHedgehog(Gear^.Hedgehog); +Hedgehog:= Gear^.Hedgehog; if Hedgehog^.Team^.Clan^.TurnNumber <= Ammoz[weap].SkipTurns then exit; // weapon is not activated yet @@ -118,15 +118,15 @@ dec(t) end; -if s then ApplyAmmoChanges(PHedgehog(Gear^.Hedgehog)^) +if s then ApplyAmmoChanges(Gear^.Hedgehog^) end; procedure HHSetTimer(Gear: PGear); var CurWeapon: PAmmo; begin Gear^.Message:= Gear^.Message and not gmTimer; -CurWeapon:= GetAmmoEntry(PHedgehog(Gear^.Hedgehog)^); -with PHedgehog(Gear^.Hedgehog)^ do +CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^); +with Gear^.Hedgehog^ do if (CurWeapon^.Propz and ammoprop_Timerable) <> 0 then begin CurWeapon^.Timer:= 1000 * Gear^.MsgParam; @@ -143,9 +143,9 @@ altUse: boolean; begin bShowFinger:= false; -CurWeapon:= GetAmmoEntry(PHedgehog(Gear^.Hedgehog)^); +CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^); with Gear^, - PHedgehog(Gear^.Hedgehog)^ do + Gear^.Hedgehog^ do begin if ((State and gstHHDriven) <> 0)and ((State and (gstAttacked or gstHHChooseTarget)) = 0) and @@ -207,6 +207,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 +223,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 +280,8 @@ end; amLowGravity: begin PlaySound(sndLowGravity); - cGravity:= cMaxWindSpeed + cGravity:= cMaxWindSpeed; + cGravityf:= 0.00025 end; amExtraDamage:begin PlaySound(sndHellishImpact4); @@ -386,7 +392,7 @@ const frametime = 200; timertime = frametime * 6; begin -if PHedgehog(Gear^.Hedgehog)^.Unplaced then exit; +if Gear^.Hedgehog^.Unplaced then exit; if Gear^.Timer > 1 then begin AllInactive:= false; @@ -406,7 +412,7 @@ Gear^.Z:= cCurrHHZ; RemoveGearFromList(Gear); InsertGearToList(Gear); - PlaySound(sndByeBye, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); + PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack); Gear^.Pos:= 0; Gear^.Timer:= timertime end @@ -417,7 +423,7 @@ const frametime = 65; timertime = frametime * 11; begin -if PHedgehog(Gear^.Hedgehog)^.Unplaced then exit; +if Gear^.Hedgehog^.Unplaced then exit; if Gear^.Timer > 1 then begin AllInactive:= false; @@ -434,7 +440,7 @@ Gear^.Z:= cCurrHHZ; RemoveGearFromList(Gear); InsertGearToList(Gear); - PlaySound(sndByeBye, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); + PlaySound(sndByeBye, Gear^.Hedgehog^.Team^.voicepack); PlaySound(sndWarp); Gear^.Pos:= 0; Gear^.Timer:= timertime @@ -454,16 +460,16 @@ posCaseUtility, posCaseAmmo: begin a:= Gear^.AmmoType; - AddAmmo(PHedgehog(HH^.Hedgehog)^, a); + AddAmmo(HH^.Hedgehog^, a); // Possibly needs to check shared clan ammo game flag once added. // On the other hand, no obvious reason that clan members shouldn't know what ammo another clan member picked up - if (not (PHedgehog(HH^.Hedgehog)^.Team^.ExtDriven - or (PHedgehog(HH^.Hedgehog)^.BotLevel > 0))) - or (PHedgehog(HH^.Hedgehog)^.Team^.Clan^.ClanIndex = LocalClan) + if (not (HH^.Hedgehog^.Team^.ExtDriven + or (HH^.Hedgehog^.BotLevel > 0))) + or (HH^.Hedgehog^.Team^.Clan^.ClanIndex = LocalClan) or (GameType = gmtDemo) then begin s:= trammo[Ammoz[a].NameId] + ' (+' + IntToStr(Ammoz[a].NumberInCase) + ')'; - AddCaption(s, PHedgehog(HH^.Hedgehog)^.Team^.Clan^.Color, capgrpAmmoinfo); + AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo); // show ammo icon vga:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtAmmo); @@ -474,12 +480,12 @@ end; posCaseHealth: begin inc(HH^.Health, Gear^.Health); - PHedgehog(HH^.Hedgehog)^.Effects[hePoisoned] := false; + HH^.Hedgehog^.Effects[hePoisoned] := false; str(Gear^.Health, s); s:= '+' + s; - AddCaption(s, PHedgehog(HH^.Hedgehog)^.Team^.Clan^.Color, capgrpAmmoinfo); - RenderHealth(PHedgehog(HH^.Hedgehog)^); - RecountTeamHealth(PHedgehog(HH^.Hedgehog)^.Team); + AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo); + RenderHealth(HH^.Hedgehog^); + RecountTeamHealth(HH^.Hedgehog^.Team); i:= 0; while i < Gear^.Health do @@ -497,11 +503,11 @@ var PrevdX: LongInt; CurWeapon: PAmmo; begin -CurWeapon:= GetAmmoEntry(PHedgehog(Gear^.Hedgehog)^); +CurWeapon:= GetAmmoEntry(Gear^.Hedgehog^); if ((Gear^.State and (gstAttacking or gstMoving)) = 0) then begin if isCursorVisible then - with PHedgehog(Gear^.Hedgehog)^ do + with Gear^.Hedgehog^ do with CurWeapon^ do begin if (Gear^.Message and gmLeft ) <> 0 then @@ -536,7 +542,7 @@ Gear^.dY:= -_0_15; if not cArtillery then Gear^.dX:= SignAs(_0_15, Gear^.dX); Gear^.State:= Gear^.State or gstMoving or gstHHJumping; - PlaySound(sndJump1, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); + PlaySound(sndJump1, Gear^.Hedgehog^.Team^.voicepack); exit end; end; @@ -549,7 +555,7 @@ Gear^.dY:= -_0_2; SetLittle(Gear^.dX); Gear^.State:= Gear^.State or gstMoving or gstHHJumping; - PlaySound(sndJump3, PHedgehog(Gear^.Hedgehog)^.Team^.voicepack); + PlaySound(sndJump3, Gear^.Hedgehog^.Team^.voicepack); exit end; @@ -570,7 +576,7 @@ end; DeleteCI(Gear); // must be after exit!! (see previous line) - PHedgehog(Gear^.Hedgehog)^.visStepPos:= (PHedgehog(Gear^.Hedgehog)^.visStepPos + 1) and 7; + Gear^.Hedgehog^.visStepPos:= (Gear^.Hedgehog^.visStepPos + 1) and 7; if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then begin if not (TestCollisionXwithXYShift(Gear, _0, -6, hwSign(Gear^.dX)) @@ -630,7 +636,7 @@ procedure HedgehogChAngle(Gear: PGear); var da: LongWord; begin -with PHedgehog(Gear^.Hedgehog)^ do +with Gear^.Hedgehog^ do if (CurAmmoType = amRope) and ((Gear^.State and (gstMoving or gstHHJumping)) = gstMoving) then da:= 2 else da:= 1; @@ -649,7 +655,7 @@ if Gear^.dX.QWordValue > 8160437862 then Gear^.dX.QWordValue:= 8160437862; if Gear^.dY.QWordValue > 8160437862 then Gear^.dY.QWordValue:= 8160437862; -if PHedgehog(Gear^.Hedgehog)^.Unplaced then +if Gear^.Hedgehog^.Unplaced then begin Gear^.dY:= _0; Gear^.dX:= _0; @@ -667,12 +673,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 @@ -773,7 +779,7 @@ wasJumping: boolean; Hedgehog: PHedgehog; begin -Hedgehog:= PHedgehog(Gear^.Hedgehog); +Hedgehog:= Gear^.Hedgehog; if not isInMultiShoot then AllInactive:= false else @@ -919,16 +925,16 @@ PrvInactive:= false; AllInactive:= false; - if not PHedgehog(Gear^.Hedgehog)^.Team^.hasGone then + if not Gear^.Hedgehog^.Team^.hasGone then begin - PHedgehog(Gear^.Hedgehog)^.Effects[hePoisoned] := false; - if PHedgehog(Gear^.Hedgehog)^.Effects[heResurrectable] then begin + Gear^.Hedgehog^.Effects[hePoisoned] := false; + if Gear^.Hedgehog^.Effects[heResurrectable] then begin ResurrectHedgehog(Gear); end else begin Gear^.State:= Gear^.State or gstHHDeath; Gear^.doStep:= @doStepHedgehogDead; // Death message - AddCaption(Format(GetEventString(eidDied), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage); + AddCaption(Format(GetEventString(eidDied), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage); end; end else @@ -936,7 +942,7 @@ Gear^.State:= Gear^.State or gstHHGone; Gear^.doStep:= @doStepHedgehogGone; // Gone message - AddCaption(Format(GetEventString(eidGone), PHedgehog(Gear^.Hedgehog)^.Name), cWhiteColor, capgrpMessage); + AddCaption(Format(GetEventString(eidGone), Gear^.Hedgehog^.Name), cWhiteColor, capgrpMessage); end end; exit @@ -974,7 +980,7 @@ doStepHedgehogFree(Gear) else begin - with PHedgehog(Gear^.Hedgehog)^ do + with Gear^.Hedgehog^ do if Team^.hasGone then TeamGoneEffect(Team^); doStepHedgehogDriven(Gear) end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/PascalExports.pas --- a/hedgewars/PascalExports.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/PascalExports.pas Tue Jan 04 12:53:46 2011 +0100 @@ -21,23 +21,21 @@ unit PascalExports; interface -uses uKeys, GLunit, uWorld, uMisc, uConsole, uTeams, uConsts, uChat, - uGears, uSound, hwengine, uAmmos, uLocale; // don't change the order! +uses uTypes, uConsts, uVariables, GLunit, uKeys, uChat, uSound, uAmmos, uUtils, + uCommands; {$INCLUDE "config.inc"} -var dummy: boolean; // avoid compiler hint - implementation {$IFDEF HWLIBRARY} var cZoomVal: GLfloat; + previousGameState: TGameState; // retrieve protocol information -procedure HW_versionInfo(netProto: PShortInt; versionStr: PPChar); cdecl; export; +procedure HW_versionInfo(netProto: PLongInt; versionStr: PPChar); cdecl; export; begin -// http://bugs.freepascal.org/view.php?id=16156 - if netProto <> nil then netProto^:= cNetProtoVersion; - if versionStr <> nil then versionStr^:= cVersionString; + netProto^:= cNetProtoVersion; + versionStr^:= cVersionString; end; procedure HW_click; cdecl; export; @@ -167,9 +165,31 @@ procedure HW_pause; cdecl; export; begin + if isPaused = false then + pauseAction:= true; +end; + +procedure HW_pauseToggle; cdecl; export; +begin pauseAction:= true; end; +function HW_isPaused: boolean; cdecl; export; +begin + exit( isPaused ); +end; + +procedure HW_suspend; cdecl; export; +begin + previousGameState:= GameState; + GameState:= gsSuspend; +end; + +procedure HW_resume; cdecl; export; +begin + GameState:= previousGameState; +end; + procedure HW_terminate(closeFrontend: boolean); cdecl; export; begin isTerminated:= true; @@ -199,11 +219,6 @@ ((Ammoz[CurAmmoGear^.AmmoType].Ammo.Propz and ammoprop_AltAttack) = 0)) and hideAmmoMenu)) ); end; -function HW_isPaused: boolean; cdecl; export; -begin - exit( isPaused ); -end; - function HW_isWaiting: boolean; cdecl; export; begin exit( ReadyTimeLeft > 0 ); diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/SDLMain.m --- a/hedgewars/SDLMain.m Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/SDLMain.m Tue Jan 04 12:53:46 2011 +0100 @@ -216,9 +216,11 @@ #endif /* SDL_USE_CPS */ /* Set up the menubar */ - [NSApp setMainMenu:[[NSMenu alloc] init]]; + NSMenu *menu = [[NSMenu alloc] init]; + [NSApp setMainMenu:menu]; setApplicationMenu(); setupWindowMenu(); + [menu release]; /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/SDLh.pas Tue Jan 04 12:53:46 2011 +0100 @@ -511,6 +511,17 @@ {$ENDIF} end; + TSDL_UserEvent = record +{$IFDEF SDL13} + type_: LongInt; + windowID: LongInt; +{$ELSE} + type_: Byte; +{$ENDIF} + code: LongInt; + data1, data2: Pointer; + end; + PSDL_Event = ^TSDL_Event; TSDL_Event = record {$IFDEF SDL13} @@ -531,6 +542,7 @@ SDL_JOYBALLMOTION: (jball: TSDL_JoyBallEvent); SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP: (jbutton: TSDL_JoyButtonEvent); + SDL_USEREVENT: (user: TSDL_UserEvent); {$ELSE} case Byte of SDL_NOEVENT: (type_: byte); @@ -774,7 +786,7 @@ function TTF_Init: LongInt; cdecl; external SDL_TTFLibName; procedure TTF_Quit; cdecl; external SDL_TTFLibName; -function TTF_SizeUTF8(font: PTTF_Font; const text: PChar; var w, h: LongInt): LongInt; cdecl; external SDL_TTFLibName; +function TTF_SizeUTF8(font: PTTF_Font; const text: PChar; out w, h: LongInt): LongInt; cdecl; external SDL_TTFLibName; function TTF_RenderUTF8_Solid(font: PTTF_Font; const text: PChar; fg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; function TTF_RenderUTF8_Blended(font: PTTF_Font; const text: PChar; fg: TSDL_Color): PSDL_Surface; cdecl; external SDL_TTFLibName; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/SinTable.inc --- a/hedgewars/SinTable.inc Mon Dec 27 23:57:44 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1045 +0,0 @@ -(* - * Hedgewars, a free turn based strategy game - * Copyright (c) 2007 Andrey Korotaev - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - *) - -const SinTable: array[0..1024] of QWord = ( - $00000000, - $006487EB, - $00C90FC6, - $012D9782, - $01921F10, - $01F6A660, - $025B2D62, - $02BFB407, - $03243A40, - $0388BFFC, - $03ED452D, - $0451C9C3, - $04B64DAF, - $051AD0E0, - $057F5348, - $05E3D4D7, - $0648557E, - $06ACD52C, - $071153D3, - $0775D163, - $07DA4DCC, - $083EC900, - $08A342EE, - $0907BB86, - $096C32BB, - $09D0A87B, - $0A351CB8, - $0A998F62, - $0AFE0069, - $0B626FBF, - $0BC6DD53, - $0C2B4916, - $0C8FB2F9, - $0CF41AEB, - $0D5880DF, - $0DBCE4C3, - $0E214689, - $0E85A622, - $0EEA037D, - $0F4E5E8B, - $0FB2B73D, - $10170D83, - $107B614E, - $10DFB28F, - $11440135, - $11A84D31, - $120C9675, - $1270DCF0, - $12D52093, - $1339614E, - $139D9F13, - $1401D9D1, - $14661179, - $14CA45FC, - $152E774A, - $1592A554, - $15F6D00B, - $165AF75E, - $16BF1B3E, - $17233B9D, - $1787586A, - $17EB7197, - $184F8713, - $18B398CF, - $1917A6BC, - $197BB0CB, - $19DFB6EB, - $1A43B90E, - $1AA7B724, - $1B0BB11E, - $1B6FA6EC, - $1BD3987F, - $1C3785C8, - $1C9B6EB6, - $1CFF533B, - $1D633348, - $1DC70ECC, - $1E2AE5B8, - $1E8EB7FE, - $1EF2858D, - $1F564E57, - $1FBA124B, - $201DD15B, - $20818B77, - $20E5408F, - $2148F095, - $21AC9B79, - $2210412C, - $2273E19E, - $22D77CBF, - $233B1281, - $239EA2D5, - $24022DAA, - $2465B2F1, - $24C9329C, - $252CAC9A, - $259020DD, - $25F38F55, - $2656F7F3, - $26BA5AA7, - $271DB762, - $27810E14, - $27E45EB0, - $2847A924, - $28AAED62, - $290E2B5B, - $297162FF, - $29D4943F, - $2A37BF0B, - $2A9AE355, - $2AFE010D, - $2B611823, - $2BC42889, - $2C27322F, - $2C8A3506, - $2CED30FF, - $2D50260A, - $2DB31418, - $2E15FB1A, - $2E78DB01, - $2EDBB3BD, - $2F3E853F, - $2FA14F78, - $30041258, - $3066CDD1, - $30C981D3, - $312C2E50, - $318ED336, - $31F17079, - $32540608, - $32B693D3, - $331919CD, - $337B97E6, - $33DE0E0E, - $34407C36, - $34A2E250, - $3505404B, - $3567961A, - $35C9E3AC, - $362C28F3, - $368E65DE, - $36F09A61, - $3752C66A, - $37B4E9EB, - $381704D5, - $38791719, - $38DB20A7, - $393D2170, - $399F1966, - $3A010879, - $3A62EE9A, - $3AC4CBBA, - $3B269FCB, - $3B886ABB, - $3BEA2C7E, - $3C4BE503, - $3CAD943C, - $3D0F3A1A, - $3D70D68C, - $3DD26986, - $3E33F2F6, - $3E9572CF, - $3EF6E901, - $3F58557E, - $3FB9B836, - $401B111A, - $407C601B, - $40DDA52A, - $413EE039, - $41A01138, - $42013818, - $426254CA, - $42C3673F, - $43246F69, - $43856D38, - $43E6609E, - $4447498B, - $44A827F0, - $4508FBBF, - $4569C4E9, - $45CA835E, - $462B3710, - $468BDFF0, - $46EC7DEE, - $474D10FD, - $47AD990D, - $480E160F, - $486E87F5, - $48CEEEAF, - $492F4A2F, - $498F9A65, - $49EFDF44, - $4A5018BB, - $4AB046BD, - $4B10693A, - $4B708024, - $4BD08B6C, - $4C308B02, - $4C907ED9, - $4CF066E1, - $4D50430C, - $4DB0134A, - $4E0FD78D, - $4E6F8FC7, - $4ECF3BE8, - $4F2EDBE2, - $4F8E6FA6, - $4FEDF725, - $504D7250, - $50ACE11A, - $510C4372, - $516B994B, - $51CAE295, - $522A1F43, - $52894F44, - $52E8728C, - $5347890A, - $53A692B0, - $54058F70, - $54647F3B, - $54C36203, - $552237B8, - $5581004C, - $55DFBBB0, - $563E69D7, - $569D0AB0, - $56FB9E2E, - $575A2443, - $57B89CDE, - $581707F3, - $58756572, - $58D3B54D, - $5931F775, - $59902BDC, - $59EE5273, - $5A4C6B2B, - $5AAA75F7, - $5B0872C8, - $5B66618E, - $5BC4423C, - $5C2214C4, - $5C7FD916, - $5CDD8F25, - $5D3B36E1, - $5D98D03D, - $5DF65B29, - $5E53D798, - $5EB1457C, - $5F0EA4C4, - $5F6BF565, - $5FC9374E, - $60266A71, - $60838EC1, - $60E0A42F, - $613DAAAC, - $619AA22A, - $61F78A9B, - $625463F0, - $62B12E1B, - $630DE90E, - $636A94BB, - $63C73113, - $6423BE08, - $64803B8B, - $64DCA98F, - $65390805, - $659556DF, - $65F1960E, - $664DC585, - $66A9E535, - $6705F510, - $6761F508, - $67BDE50F, - $6819C516, - $6875950F, - $68D154EC, - $692D049F, - $6988A41B, - $69E4334F, - $6A3FB230, - $6A9B20AE, - $6AF67EBB, - $6B51CC49, - $6BAD094B, - $6C0835B2, - $6C635170, - $6CBE5C77, - $6D1956B9, - $6D744028, - $6DCF18B5, - $6E29E054, - $6E8496F6, - $6EDF3C8C, - $6F39D10A, - $6F945460, - $6FEEC681, - $70492760, - $70A376EE, - $70FDB51D, - $7157E1DF, - $71B1FD26, - $720C06E5, - $7265FF0E, - $72BFE593, - $7319BA65, - $73737D77, - $73CD2EBC, - $7426CE24, - $74805BA4, - $74D9D72C, - $753340AF, - $758C981F, - $75E5DD6E, - $763F108F, - $76983174, - $76F1400F, - $774A3C52, - $77A32630, - $77FBFD9B, - $7854C285, - $78AD74E0, - $7906149F, - $795EA1B5, - $79B71C13, - $7A0F83AC, - $7A67D872, - $7AC01A58, - $7B184950, - $7B70654C, - $7BC86E3F, - $7C20641B, - $7C7846D3, - $7CD01659, - $7D27D2A0, - $7D7F7B99, - $7DD71139, - $7E2E9370, - $7E860232, - $7EDD5D71, - $7F34A51F, - $7F8BD930, - $7FE2F995, - $803A0641, - $8090FF28, - $80E7E43A, - $813EB56C, - $819572AF, - $81EC1BF7, - $8242B135, - $8299325D, - $82EF9F62, - $8345F835, - $839C3CC9, - $83F26D12, - $84488902, - $849E908B, - $84F483A1, - $854A6236, - $85A02C3C, - $85F5E1A8, - $864B826B, - $86A10E78, - $86F685C2, - $874BE83C, - $87A135D9, - $87F66E8C, - $884B9247, - $88A0A0FD, - $88F59AA1, - $894A7F26, - $899F4E7F, - $89F408A0, - $8A48AD7A, - $8A9D3D00, - $8AF1B727, - $8B461BE0, - $8B9A6B1F, - $8BEEA4D7, - $8C42C8FA, - $8C96D77C, - $8CEAD050, - $8D3EB368, - $8D9280B9, - $8DE63834, - $8E39D9CD, - $8E8D6578, - $8EE0DB27, - $8F343ACD, - $8F87845E, - $8FDAB7CC, - $902DD50C, - $9080DC0F, - $90D3CCCA, - $9126A72F, - $91796B31, - $91CC18C5, - $921EAFDD, - $9271306C, - $92C39A66, - $9315EDBE, - $93682A67, - $93BA5055, - $940C5F7A, - $945E57CB, - $94B0393B, - $950203BD, - $9553B744, - $95A553C4, - $95F6D930, - $9648477C, - $96999E9A, - $96EADE80, - $973C071F, - $978D186C, - $97DE125A, - $982EF4DD, - $987FBFE7, - $98D0736D, - $99210F62, - $997193BA, - $99C20068, - $9A125560, - $9A629296, - $9AB2B7FD, - $9B02C588, - $9B52BB2C, - $9BA298DC, - $9BF25E8C, - $9C420C2F, - $9C91A1B9, - $9CE11F1F, - $9D308453, - $9D7FD149, - $9DCF05F6, - $9E1E224C, - $9E6D2640, - $9EBC11C6, - $9F0AE4D1, - $9F599F56, - $9FA84148, - $9FF6CA9A, - $A0453B42, - $A0939332, - $A0E1D25F, - $A12FF8BC, - $A17E063F, - $A1CBFAD9, - $A219D681, - $A2679928, - $A2B542C5, - $A302D349, - $A3504AAB, - $A39DA8DD, - $A3EAEDD3, - $A4381983, - $A4852BDF, - $A4D224DD, - $A51F046F, - $A56BCA8B, - $A5B87724, - $A6050A2F, - $A65183A0, - $A69DE36B, - $A6EA2984, - $A73655DF, - $A7826871, - $A7CE612E, - $A81A400B, - $A86604FB, - $A8B1AFF3, - $A8FD40E7, - $A948B7CB, - $A9941495, - $A9DF5738, - $AA2A7FA9, - $AA758DDB, - $AAC081C5, - $AB0B5B59, - $AB561A8D, - $ABA0BF54, - $ABEB49A4, - $AC35B971, - $AC800EB0, - $ACCA4954, - $AD146953, - $AD5E6EA1, - $ADA85932, - $ADF228FC, - $AE3BDDF3, - $AE85780B, - $AECEF73A, - $AF185B73, - $AF61A4AC, - $AFAAD2D9, - $AFF3E5EF, - $B03CDDE3, - $B085BAA9, - $B0CE7C36, - $B117227F, - $B15FAD79, - $B1A81D19, - $B1F07153, - $B238AA1C, - $B280C769, - $B2C8C930, - $B310AF64, - $B35879FB, - $B3A028E9, - $B3E7BC25, - $B42F33A1, - $B4768F55, - $B4BDCF34, - $B504F334, - $B54BFB49, - $B592E769, - $B5D9B789, - $B6206B9E, - $B667039D, - $B6AD7F7A, - $B6F3DF2C, - $B73A22A7, - $B78049E1, - $B7C654CE, - $B80C4364, - $B8521599, - $B897CB60, - $B8DD64B0, - $B922E17E, - $B96841BF, - $B9AD8569, - $B9F2AC70, - $BA37B6CB, - $BA7CA46D, - $BAC1754E, - $BB062962, - $BB4AC09E, - $BB8F3AF8, - $BBD39866, - $BC17D8DD, - $BC5BFC52, - $BCA002BA, - $BCE3EC0D, - $BD27B83E, - $BD6B6744, - $BDAEF913, - $BDF26DA3, - $BE35C4E7, - $BE78FED6, - $BEBC1B66, - $BEFF1A8C, - $BF41FC3E, - $BF84C071, - $BFC7671B, - $C009F032, - $C04C5BAB, - $C08EA97D, - $C0D0D99E, - $C112EC02, - $C154E0A0, - $C196B76D, - $C1D87060, - $C21A0B6E, - $C25B888D, - $C29CE7B4, - $C2DE28D7, - $C31F4BEE, - $C36050ED, - $C3A137CB, - $C3E2007E, - $C422AAFC, - $C463373A, - $C4A3A530, - $C4E3F4D2, - $C5242618, - $C56438F7, - $C5A42D65, - $C5E40359, - $C623BAC8, - $C66353A9, - $C6A2CDF2, - $C6E22999, - $C7216694, - $C76084DA, - $C79F8461, - $C7DE651F, - $C81D270B, - $C85BCA1B, - $C89A4E44, - $C8D8B37F, - $C916F9C0, - $C95520FE, - $C9932930, - $C9D1124D, - $CA0EDC49, - $CA4C871D, - $CA8A12BF, - $CAC77F24, - $CB04CC45, - $CB41FA16, - $CB7F088F, - $CBBBF7A6, - $CBF8C752, - $CC35778A, - $CC720844, - $CCAE7977, - $CCEACB19, - $CD26FD21, - $CD630F87, - $CD9F0240, - $CDDAD543, - $CE168888, - $CE521C04, - $CE8D8FAF, - $CEC8E380, - $CF04176E, - $CF3F2B6E, - $CF7A1F79, - $CFB4F385, - $CFEFA78A, - $D02A3B7D, - $D064AF56, - $D09F030C, - $D0D93696, - $D11349EB, - $D14D3D02, - $D1870FD2, - $D1C0C253, - $D1FA547A, - $D233C641, - $D26D179C, - $D2A64885, - $D2DF58F1, - $D31848D8, - $D3511832, - $D389C6F5, - $D3C25519, - $D3FAC295, - $D4330F60, - $D46B3B73, - $D4A346C3, - $D4DB3148, - $D512FAFB, - $D54AA3D1, - $D5822BC4, - $D5B992C9, - $D5F0D8D8, - $D627FDEA, - $D65F01F5, - $D695E4F1, - $D6CCA6D6, - $D703479A, - $D739C736, - $D77025A2, - $D7A662D4, - $D7DC7EC5, - $D812796C, - $D84852C1, - $D87E0ABB, - $D8B3A152, - $D8E9167F, - $D91E6A38, - $D9539C76, - $D988AD30, - $D9BD9C5E, - $D9F269F8, - $DA2715F5, - $DA5BA04F, - $DA9008FC, - $DAC44FF5, - $DAF87531, - $DB2C78A8, - $DB605A53, - $DB941A29, - $DBC7B822, - $DBFB3437, - $DC2E8E60, - $DC61C694, - $DC94DCCB, - $DCC7D0FF, - $DCFAA326, - $DD2D533A, - $DD5FE131, - $DD924D06, - $DDC496AF, - $DDF6BE25, - $DE28C360, - $DE5AA658, - $DE8C6707, - $DEBE0563, - $DEEF8167, - $DF20DB09, - $DF521242, - $DF83270B, - $DFB4195C, - $DFE4E92D, - $E0159678, - $E0462134, - $E076895A, - $E0A6CEE2, - $E0D6F1C6, - $E106F1FD, - $E136CF81, - $E1668A4A, - $E1962250, - $E1C5978C, - $E1F4E9F7, - $E224198A, - $E253263D, - $E2821009, - $E2B0D6E7, - $E2DF7AD0, - $E30DFBBC, - $E33C59A4, - $E36A9482, - $E398AC4D, - $E3C6A0FF, - $E3F47291, - $E42220FC, - $E44FAC38, - $E47D143F, - $E4AA590A, - $E4D77A91, - $E50478CE, - $E53153B9, - $E55E0B4D, - $E58A9F81, - $E5B71050, - $E5E35DB2, - $E60F87A0, - $E63B8E14, - $E6677106, - $E6933071, - $E6BECC4C, - $E6EA4493, - $E715993D, - $E740CA44, - $E76BD7A2, - $E796C150, - $E7C18746, - $E7EC2980, - $E816A7F6, - $E84102A1, - $E86B397B, - $E8954C7D, - $E8BF3BA2, - $E8E906E2, - $E912AE37, - $E93C319B, - $E9659107, - $E98ECC75, - $E9B7E3DE, - $E9E0D73D, - $EA09A68A, - $EA3251C0, - $EA5AD8D9, - $EA833BCD, - $EAAB7A97, - $EAD39531, - $EAFB8B94, - $EB235DBB, - $EB4B0B9E, - $EB729539, - $EB99FA84, - $EBC13B7B, - $EBE85816, - $EC0F5050, - $EC362422, - $EC5CD387, - $EC835E7A, - $ECA9C4F3, - $ECD006EC, - $ECF62461, - $ED1C1D4B, - $ED41F1A4, - $ED67A167, - $ED8D2C8E, - $EDB29312, - $EDD7D4EE, - $EDFCF21D, - $EE21EA98, - $EE46BE5A, - $EE6B6D5D, - $EE8FF79C, - $EEB45D11, - $EED89DB6, - $EEFCB986, - $EF20B07B, - $EF448290, - $EF682FBF, - $EF8BB802, - $EFAF1B55, - $EFD259B1, - $EFF57311, - $F0186771, - $F03B36C9, - $F05DE116, - $F0806651, - $F0A2C676, - $F0C5017F, - $F0E71767, - $F1090828, - $F12AD3BD, - $F14C7A22, - $F16DFB50, - $F18F5744, - $F1B08DF6, - $F1D19F64, - $F1F28B86, - $F2135259, - $F233F3D8, - $F2546FFC, - $F274C6C2, - $F294F824, - $F2B5041D, - $F2D4EAA8, - $F2F4ABC1, - $F3144762, - $F333BD87, - $F3530E2B, - $F3723949, - $F3913EDB, - $F3B01EDE, - $F3CED94D, - $F3ED6E23, - $F40BDD5A, - $F42A26F0, - $F4484ADD, - $F466491F, - $F48421B1, - $F4A1D48D, - $F4BF61B0, - $F4DCC915, - $F4FA0AB6, - $F5172691, - $F5341C9F, - $F550ECDE, - $F56D9747, - $F58A1BD8, - $F5A67A8B, - $F5C2B35C, - $F5DEC647, - $F5FAB347, - $F6167A59, - $F6321B77, - $F64D969E, - $F668EBC9, - $F6841AF5, - $F69F241C, - $F6BA073B, - $F6D4C44E, - $F6EF5B50, - $F709CC3E, - $F7241713, - $F73E3BCB, - $F7583A63, - $F77212D5, - $F78BC51F, - $F7A5513C, - $F7BEB729, - $F7D7F6E1, - $F7F11060, - $F80A03A4, - $F822D0A6, - $F83B7765, - $F853F7DD, - $F86C5208, - $F88485E4, - $F89C936D, - $F8B47AA0, - $F8CC3B78, - $F8E3D5F1, - $F8FB4A09, - $F91297BC, - $F929BF05, - $F940BFE2, - $F9579A4F, - $F96E4E48, - $F984DBCA, - $F99B42D2, - $F9B1835B, - $F9C79D63, - $F9DD90E6, - $F9F35DE1, - $FA090450, - $FA1E8430, - $FA33DD7E, - $FA491036, - $FA5E1C55, - $FA7301D8, - $FA87C0BC, - $FA9C58FD, - $FAB0CA99, - $FAC5158C, - $FAD939D2, - $FAED376A, - $FB010E50, - $FB14BE80, - $FB2847F8, - $FB3BAAB4, - $FB4EE6B3, - $FB61FBF0, - $FB74EA69, - $FB87B21A, - $FB9A5302, - $FBACCD1D, - $FBBF2068, - $FBD14CE1, - $FBE35284, - $FBF5314F, - $FC06E93F, - $FC187A52, - $FC29E484, - $FC3B27D4, - $FC4C443D, - $FC5D39BE, - $FC6E0855, - $FC7EAFFD, - $FC8F30B6, - $FC9F8A7C, - $FCAFBD4D, - $FCBFC926, - $FCCFAE05, - $FCDF6BE8, - $FCEF02CB, - $FCFE72AD, - $FD0DBB8C, - $FD1CDD64, - $FD2BD833, - $FD3AABF8, - $FD4958B0, - $FD57DE58, - $FD663CEF, - $FD747472, - $FD8284DF, - $FD906E34, - $FD9E306F, - $FDABCB8D, - $FDB93F8C, - $FDC68C6B, - $FDD3B228, - $FDE0B0BF, - $FDED8830, - $FDFA3878, - $FE06C196, - $FE132387, - $FE1F5E4A, - $FE2B71DC, - $FE375E3C, - $FE432368, - $FE4EC15E, - $FE5A381D, - $FE6587A2, - $FE70AFEB, - $FE7BB0F8, - $FE868AC7, - $FE913D55, - $FE9BC8A1, - $FEA62CAA, - $FEB0696D, - $FEBA7EEA, - $FEC46D1F, - $FECE3409, - $FED7D3A9, - $FEE14BFB, - $FEEA9D00, - $FEF3C6B4, - $FEFCC918, - $FF05A429, - $FF0E57E6, - $FF16E44E, - $FF1F495F, - $FF278719, - $FF2F9D79, - $FF378C80, - $FF3F542A, - $FF46F478, - $FF4E6D68, - $FF55BEF9, - $FF5CE92A, - $FF63EBF9, - $FF6AC766, - $FF717B6F, - $FF780814, - $FF7E6D54, - $FF84AB2C, - $FF8AC19E, - $FF90B0A7, - $FF967847, - $FF9C187C, - $FFA19147, - $FFA6E2A6, - $FFAC0C97, - $FFB10F1C, - $FFB5EA32, - $FFBA9DD9, - $FFBF2A10, - $FFC38ED7, - $FFC7CC2C, - $FFCBE210, - $FFCFD082, - $FFD39780, - $FFD7370B, - $FFDAAF21, - $FFDDFFC3, - $FFE128F0, - $FFE42AA6, - $FFE704E7, - $FFE9B7B1, - $FFEC4304, - $FFEEA6E0, - $FFF0E344, - $FFF2F82F, - $FFF4E5A2, - $FFF6AB9D, - $FFF84A1E, - $FFF9C126, - $FFFB10B5, - $FFFC38CA, - $FFFD3965, - $FFFE1286, - $FFFEC42C, - $FFFF4E59, - $FFFFB10B, - $FFFFEC43, - $100000000 - ); diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/VGSHandlers.inc --- a/hedgewars/VGSHandlers.inc Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/VGSHandlers.inc Tue Jan 04 12:53:46 2011 +0100 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA *) procedure doStepFlake(Gear: PVisualGear; Steps: Longword); -var sign: float; +var sign: real; begin if vobCount = 0 then exit; @@ -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 @@ -59,8 +68,8 @@ begin if round(X) < cLeftScreenBorder then X:= X + cScreenSpace else if round(X) > cRightScreenBorder then X:= X - cScreenSpace; - // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + float(25); // For if flag is set for flakes rising upwards? - if round(Y) - 75 > LAND_HEIGHT then Y:= Y - float(1024 + 150); // TODO - configure in theme (jellies for example could use limited range) + // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + 25.0; // For if flag is set for flakes rising upwards? + if round(Y) - 75 > LAND_HEIGHT then Y:= Y - (1024 + 150); // TODO - configure in theme (jellies for example could use limited range) Timer:= 0; tdX:= 0; tdY:= 0 @@ -81,7 +90,7 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepCloud(Gear: PVisualGear; Steps: Longword); var s: Longword; - t: float; + t: real; begin Gear^.X:= Gear^.X + (cWindSpeedf * 750 * Gear^.dX) * Steps; @@ -444,16 +453,16 @@ begin if Gear^.Timer > Steps then dec(Gear^.Timer, Steps) else Gear^.Timer:= 0; -if (PHedgehog(Gear^.Hedgehog)^.Gear <> nil) then +if (Gear^.Hedgehog^.Gear <> nil) then begin - Gear^.X:= PHedgehog(Gear^.Hedgehog)^.Gear^.X.QWordValue/4294967296 + (Gear^.Tex^.w div 2 - Gear^.FrameTicks); - Gear^.Y:= PHedgehog(Gear^.Hedgehog)^.Gear^.Y.QWordValue/4294967296 - (16 + Gear^.Tex^.h); + Gear^.X:= Gear^.Hedgehog^.Gear^.X.QWordValue/4294967296 + (Gear^.Tex^.w div 2 - Gear^.FrameTicks); + Gear^.Y:= Gear^.Hedgehog^.Gear^.Y.QWordValue/4294967296 - (16 + Gear^.Tex^.h); end; if Gear^.Timer = 0 then begin - if PHedgehog(Gear^.Hedgehog)^.SpeechGear = Gear then - PHedgehog(Gear^.Hedgehog)^.SpeechGear:= nil; + if Gear^.Hedgehog^.SpeechGear = Gear then + Gear^.Hedgehog^.SpeechGear:= nil; DeleteVisualGear(Gear) end; end; @@ -462,10 +471,10 @@ begin Steps:= Steps; // avoid compiler hint -with PHedgehog(Gear^.Hedgehog)^ do +with Gear^.Hedgehog^ do if SpeechGear <> nil then SpeechGear^.Timer:= 0; -PHedgehog(Gear^.Hedgehog)^.SpeechGear:= Gear; +Gear^.Hedgehog^.SpeechGear:= Gear; Gear^.Timer:= max(Length(Gear^.Text) * 150, 3000); @@ -479,7 +488,7 @@ Gear^.doStep:= @doStepSpeechBubbleWork; -Gear^.Y:= Gear^.Y - float(Gear^.Tex^.h) +Gear^.Y:= Gear^.Y - Gear^.Tex^.h end; //////////////////////////////////////////////////////////////////////////////// @@ -512,7 +521,7 @@ str(Gear^.State, s); if Gear^.Hedgehog <> nil then - Gear^.Tex:= RenderStringTex(s, PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.Color, fnt16) + Gear^.Tex:= RenderStringTex(s, Gear^.Hedgehog^.Team^.Clan^.Color, fnt16) else Gear^.Tex:= RenderStringTex(s, cWhiteColor, fnt16); @@ -521,7 +530,7 @@ else Gear^.doStep:= @doStepHealthTagWorkUnderWater; -Gear^.Y:= Gear^.Y - float(Gear^.Tex^.h); +Gear^.Y:= Gear^.Y - Gear^.Tex^.h; if Steps > 1 then Gear^.doStep(Gear, Steps-1); end; @@ -558,11 +567,20 @@ procedure doStepExplosion(Gear: PVisualGear; Steps: Longword); var i: LongWord; -gX,gY: LongInt; + gX,gY: LongInt; + vg: PVisualGear; begin gX:= round(Gear^.X); gY:= round(Gear^.Y); -for i:= 0 to 31 do AddVisualGear(gX, gY, vgtFire); +for i:= 0 to 31 do + begin + vg:= AddVisualGear(gX, gY, vgtFire); + if vg <> nil then + begin + vg^.State:= gstTmpFlag; + inc(vg^.FrameTicks, vg^.FrameTicks) + end + end; for i:= 0 to 8 do AddVisualGear(gX, gY, vgtExplPart); for i:= 0 to 8 do AddVisualGear(gX, gY, vgtExplPart2); Gear^.doStep:= @doStepExplosionWork; @@ -590,12 +608,21 @@ procedure doStepBigExplosion(Gear: PVisualGear; Steps: Longword); var i: LongWord; -gX,gY: LongInt; + gX,gY: LongInt; + vg: PVisualGear; begin gX:= round(Gear^.X); gY:= round(Gear^.Y); AddVisualGear(gX, gY, vgtSmokeRing); -for i:= 0 to 46 do AddVisualGear(gX, gY, vgtFire); +for i:= 0 to 46 do + begin + vg:= AddVisualGear(gX, gY, vgtFire); + if vg <> nil then + begin + vg^.State:= gstTmpFlag; + inc(vg^.FrameTicks, vg^.FrameTicks) + end + end; for i:= 0 to 15 do AddVisualGear(gX, gY, vgtExplPart); for i:= 0 to 15 do AddVisualGear(gX, gY, vgtExplPart2); Gear^.doStep:= @doStepBigExplosionWork; @@ -627,3 +654,27 @@ else dec(Gear^.FrameTicks, Steps); end; + +//////////////////////////////////////////////////////////////////////////////// +procedure doStepCircle(Gear: PVisualGear; Steps: Longword); +var tmp: LongInt; + i: LongWord; +begin +with Gear^ do + if Frame <> 0 then + for i:= 1 to Steps do + begin + inc(FrameTicks); + if (FrameTicks mod Frame) = 0 then + begin + tmp:= Gear^.Tint and $FF; + if tdY >= 0 then inc(tmp) + 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; + Gear^.Tint:= (Gear^.Tint and $FFFFFF00) or tmp + end + end +end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/hwLibrary.pas --- a/hedgewars/hwLibrary.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/hwLibrary.pas Tue Jan 04 12:53:46 2011 +0100 @@ -12,10 +12,9 @@ // 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, hwengine, PascalExports; +uses cmem, uVariables, PascalExports, hwengine; begin // avoid compiler warnings about units not being used isTerminated:= isTerminated; - dummy:= dummy; end. diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/hwengine.pas Tue Jan 04 12:53:46 2011 +0100 @@ -30,10 +30,8 @@ {$ENDIF} uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uKeys, uSound, - uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions, uMobile, sysutils; - -var isTerminated: boolean = false; - alsoShutdownFrontend: boolean = false; + uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions, uMobile, + sysutils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted; {$IFDEF HWLIBRARY} procedure initEverything(complete:boolean); @@ -50,16 +48,19 @@ procedure DoTimer(Lag: LongInt); var s: shortstring; begin - if not isPaused then inc(RealTicks, Lag); + if isPaused = false then + inc(RealTicks, Lag); case GameState of gsLandGen: begin GenMap; + ParseCommand('sendlanddigest', true); GameState:= gsStart; end; gsStart: begin if HasBorder then DisableSomeWeapons; AddClouds; + AddFlakes; AssignHHCoords; AddMiscGears; StoreLoad; @@ -98,6 +99,7 @@ gsExit: begin isTerminated:= true; end; + gsSuspend: exit; end; {$IFDEF SDL13} @@ -105,12 +107,13 @@ {$ELSE} SDL_GL_SwapBuffers(); {$ENDIF} - // not going to make captures on the iPhone + if flagMakeCapture then begin flagMakeCapture:= false; s:= 'hw_' + FormatDateTime('YYYY-MM-DD_HH-mm-ss', Now()) + inttostr(GameTicks); WriteLnToConsole('Saving ' + s + '...'); + playSound(sndShutter); MakeScreenshot(s); //SDL_SaveBMP_RW(SDLPrimSurface, SDL_RWFromFile(Str2PChar(s), 'wb'), 1) end; @@ -123,7 +126,6 @@ FreeActionsList(); StoreRelease(); ControllerClose(); - SendKB(); CloseIPC(); TTF_Quit(); {$IFDEF SDL13} @@ -147,19 +149,16 @@ begin case event.type_ of SDL_KEYDOWN: if GameState = gsChat then -{$IFDEF IPHONEOS} +{$IFDEF SDL13} // sdl on iphone supports only ashii keyboards and the unicode field is deprecated in sdl 1.3 KeyPressChat(event.key.keysym.sym); + SDL_WINDOWEVENT: + if event.wevent.event = SDL_WINDOWEVENT_SHOWN then + 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; -{$ENDIF} -{$IFDEF SDL13} - SDL_WINDOWEVENT: - if event.wevent.event = SDL_WINDOWEVENT_SHOWN then - cHasFocus:= true; -{$ELSE} SDL_ACTIVEEVENT: if (event.active.state and SDL_APPINPUTFOCUS) <> 0 then cHasFocus:= event.active.gain = 1; @@ -169,8 +168,8 @@ SDL_JOYBUTTONDOWN: ControllerButtonEvent(event.jbutton.which, event.jbutton.button, true); SDL_JOYBUTTONUP: ControllerButtonEvent(event.jbutton.which, event.jbutton.button, false); SDL_QUITEV: isTerminated:= true - end; // end case event.type_ - end; // end while SDL_PollEvent(@event) <> 0 + end; //end case event.type_ of + end; //end while SDL_PollEvent(@event) <> 0 do if isTerminated = false then begin @@ -319,10 +318,16 @@ Randomize(); // uConsts does not need initialization as they are all consts + uUtils.initModule; uMisc.initModule; + uVariables.initModule; uConsole.initModule; // MUST happen after uMisc + uCommands.initModule; + uCommandHandlers.initModule; uLand.initModule; + uLandPainted.initModule; + uIO.initModule; if complete then @@ -351,6 +356,7 @@ uTeams.initModule; uVisualGears.initModule; uWorld.initModule; + uCaptions.initModule; end; end; @@ -358,6 +364,7 @@ begin if complete then begin + uCaptions.freeModule; uWorld.freeModule; uVisualGears.freeModule; uTeams.freeModule; @@ -387,7 +394,11 @@ uIO.freeModule; //stub uLand.freeModule; + uCommandHandlers.freeModule; + uCommands.freeModule; uConsole.freeModule; + uVariables.freeModule; + uUtils.freeModule; uMisc.freeModule; // uMisc closes the debug log. end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uAI.pas --- a/hedgewars/uAI.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uAI.pas Tue Jan 04 12:53:46 2011 +0100 @@ -29,8 +29,9 @@ procedure FreeActionsList; implementation -uses uTeams, uConsts, SDLh, uAIMisc, uGears, uAIAmmoTests, uAIActions, uMisc, - uAmmos, uConsole, SysUtils{$IFDEF UNIX}, cthreads{$ENDIF}; +uses uConsts, SDLh, uAIMisc, uAIAmmoTests, uAIActions, + uAmmos, SysUtils{$IFDEF UNIX}, cthreads{$ENDIF}, uTypes, + uVariables, uCommands, uUtils, uDebug; var BestActions: TActions; CanUseAmmo: array [TAmmoType] of boolean; @@ -65,7 +66,7 @@ Score, i: LongInt; a, aa: TAmmoType; begin -BotLevel:= PHedgehog(Me^.Hedgehog)^.BotLevel; +BotLevel:= Me^.Hedgehog^.BotLevel; for i:= 0 to Pred(Targets.Count) do if (Targets.ar[i].Score >= 0) and (not StopThinking) then @@ -194,18 +195,18 @@ Actions.Pos:= 0; Actions.Score:= 0; Stack.Count:= 0; -BotLevel:= PHedgehog(Me^.Hedgehog)^.BotLevel; +BotLevel:= Me^.Hedgehog^.BotLevel; tmp:= random(2) + 1; Push(0, Actions, Me^, tmp); Push(0, Actions, Me^, tmp xor 3); -if (Me^.State and gstAttacked) = 0 then maxticks:= max(0, TurnTimeLeft - 5000 - LongWord(4000 * BotLevel)) +if (Me^.State and gstAttacked) = 0 then maxticks:= Max(0, TurnTimeLeft - 5000 - LongWord(4000 * BotLevel)) else maxticks:= TurnTimeLeft; if (Me^.State and gstAttacked) = 0 then TestAmmos(Actions, Me, false); BestRate:= RatePlace(Me); -BaseRate:= max(BestRate, 0); +BaseRate:= Max(BestRate, 0); while (Stack.Count > 0) and (not StopThinking) and (GameFlags and gfArtillery = 0) do begin @@ -321,7 +322,7 @@ FillBonuses((Me^.State and gstAttacked) <> 0); for a:= Low(TAmmoType) to High(TAmmoType) do - CanUseAmmo[a]:= Assigned(AmmoTests[a].proc) and HHHasAmmo(PHedgehog(Me^.Hedgehog)^, a); + CanUseAmmo[a]:= Assigned(AmmoTests[a].proc) and HHHasAmmo(Me^.Hedgehog^, a); {$IFDEF DEBUGFILE}AddFileLog('Enter Think Thread');{$ENDIF} BeginThread(@Think, Me, ThinkThread) end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uAIActions.pas --- a/hedgewars/uAIActions.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uAIActions.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,7 +20,7 @@ unit uAIActions; interface -uses uGears, uFloat; +uses uFloat, uTypes; const MAXACTIONS = 96; aia_none = 0; @@ -62,7 +62,7 @@ procedure ProcessAction(var Actions: TActions; Me: PGear); implementation -uses uMisc, uConsts, uConsole, uAIMisc, uAI, uAmmos; +uses uAIMisc, uAI, uAmmos, uVariables, uCommands, uUtils, uDebug, uIO; const ActionIdToStr: array[0..6] of string[16] = ( {aia_none} '', @@ -95,8 +95,8 @@ else begin WriteLnToConsole('AI action: '+SpecActionIdToStr[Action.Action]); if (Action.Action = aia_WaitXL) or (Action.Action = aia_WaitXR) then - WriteLnToConsole('AI action Wait X = '+inttostr(Action.Param)+', current X = '+inttostr(hwRound(Me^.X))) - else if (Action.Action = aia_AwareExpl) then WriteLnToConsole('Aware X = ' + inttostr(Action.X) + ', Y = ' + inttostr(Action.Y)); + WriteLnToConsole('AI action Wait X = '+IntToStr(Action.Param)+', current X = '+IntToStr(hwRound(Me^.X))) + else if (Action.Action = aia_AwareExpl) then WriteLnToConsole('Aware X = ' + IntToStr(Action.X) + ', Y = ' + IntToStr(Action.Y)); end end; {$ENDIF} @@ -199,7 +199,7 @@ aim_push: s:= '+' + s; aim_release: s:= '-' + s; end - else if Param <> 0 then s:= s + ' ' + inttostr(Param); + else if Param <> 0 then s:= s + ' ' + IntToStr(Param); ParseCommand(s, true) end end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uAIAmmoTests.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,7 +20,7 @@ unit uAIAmmoTests; interface -uses SDLh, uGears, uConsts, uFloat; +uses SDLh, uConsts, uFloat, uTypes; const amtest_OnTurn = $00000001; type TAttackParams = record @@ -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,13 +103,14 @@ (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 ); const BadTurn = Low(LongInt) div 4; implementation -uses uMisc, uAIMisc, uLand; +uses uAIMisc, uVariables, uUtils; function Metric(x1, y1, x2, y2: LongInt): LongInt; begin @@ -172,6 +174,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; @@ -539,7 +598,7 @@ or (y.Round > LongWord(LAND_HEIGHT)) or (d > 200); -if Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 3 then valueResult:= max(0, (4 - d div 50) * 7 * 1024) +if Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 3 then valueResult:= Max(0, (4 - d div 50) * 7 * 1024) else valueResult:= BadTurn; TestDesertEagle:= valueResult end; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uAIMisc.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,7 +20,7 @@ unit uAIMisc; interface -uses SDLh, uConsts, uGears, uFloat; +uses SDLh, uConsts, uFloat, uTypes; const MAXBONUS = 1024; @@ -68,8 +68,7 @@ end; implementation -uses uTeams, uMisc, uLand, uCollisions; - +uses uCollisions, uVariables, uUtils, uDebug; const KillScore = 200; @@ -131,7 +130,7 @@ begin bonuses.Count:= 0; -MyClan:= PHedgehog(ThinkingHH^.Hedgehog)^.Team^.Clan; +MyClan:= ThinkingHH^.Hedgehog^.Team^.Clan; Gear:= GearsList; while Gear <> nil do begin @@ -150,7 +149,7 @@ AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 60, -25) else if isAfterAttack and (ThinkingHH^.Hedgehog <> Gear^.Hedgehog) then - if (MyClan = PHedgehog(Gear^.Hedgehog)^.Team^.Clan) then + if (MyClan = Gear^.Hedgehog^.Team^.Clan) then AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 150, -3) // hedgehog-friend else AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 100, 3) diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uAmmos.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,7 +20,7 @@ unit uAmmos; interface -uses uConsts, uTeams, uStats; +uses uConsts, uTypes; procedure initModule; procedure freeModule; @@ -47,7 +47,7 @@ var StoreCnt: Longword; implementation -uses uMisc, uGears, uWorld, uLocale, uConsole, uMobile; +uses uLocale, uMobile, uVariables, uCommands, uUtils, uCaptions, uDebug; type TAmmoCounts = array[TAmmoType] of Longword; var StoresList: array[0..Pred(cMaxHHs)] of PHHAmmo; @@ -68,20 +68,7 @@ begin TryDo(mi[Ammoz[a].Slot] <= cMaxSlotAmmoIndex, 'Ammo slot overflow', true); Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]]:= Ammoz[a].Ammo; - with Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]] do - begin - Count:= cnts[a]; - if (TotalRounds < 0) and ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then Count:= AMMO_INFINITE; - end; - inc(mi[Ammoz[a].Slot]) - end - else if (TotalRounds < 0) and ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then - begin - TryDo(mi[Ammoz[a].Slot] <= cMaxSlotAmmoIndex, 'Ammo slot overflow', true); - Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]]:= Ammoz[a].Ammo; - - Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]].Count:= AMMO_INFINITE; - + with Ammo^[Ammoz[a].Slot, mi[Ammoz[a].Slot]] do Count:= cnts[a]; inc(mi[Ammoz[a].Slot]) end end @@ -107,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 @@ -134,10 +120,14 @@ if ((GameFlags and gfPlaceHog) <> 0) and (a <> amTeleport) and (a <> amSkip) and - (Ammoz[a].SkipTurns < 10000) then inc(Ammoz[a].SkipTurns,10000) + (Ammoz[a].SkipTurns < 10000) then inc(Ammoz[a].SkipTurns,10000); + if ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then ammos[a]:= AMMO_INFINITE end else ammos[a]:= AMMO_INFINITE; - InitialCounts[Pred(StoreCnt)][a]:= ammos[a]; + if ((GameFlags and gfPlaceHog) <> 0) and (a = amTeleport) then + InitialCounts[Pred(StoreCnt)][a]:= cnt + else + InitialCounts[Pred(StoreCnt)][a]:= ammos[a]; end; FillAmmoStore(StoresList[Pred(StoreCnt)], ammos) end; @@ -329,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; @@ -427,8 +414,22 @@ if Ammoz[a].SkipTurns >= 10000 then dec(Ammoz[a].SkipTurns,10000) end; + + +procedure chAddAmmoStore(var descr: shortstring); +begin +descr:= ''; // avoid compiler hint +AddAmmoStore +end; + procedure initModule; begin + RegisterVariable('ammloadt', vtCommand, @SetAmmoLoadout, false); + RegisterVariable('ammdelay', vtCommand, @SetAmmoDelay, false); + RegisterVariable('ammprob', vtCommand, @SetAmmoProbability, false); + RegisterVariable('ammreinf', vtCommand, @SetAmmoReinforcement, false); + RegisterVariable('ammstore', vtCommand, @chAddAmmoStore , false); + StoreCnt:= 0; ammoLoadout:= ''; ammoProbability:= ''; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uCaptions.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uCaptions.pas Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,72 @@ +unit uCaptions; + +interface +uses uTypes; + +procedure AddCaption(s: shortstring; Color: Longword; Group: TCapGroup); +procedure DrawCaptions; + +procedure initModule; +procedure freeModule; + +implementation +uses uTextures, uRenderUtils, uVariables, uRender, uConsts; + +type TCaptionStr = record + Tex: PTexture; + EndTime: LongWord; + end; +var + Captions: array[TCapGroup] of TCaptionStr; + +procedure AddCaption(s: shortstring; Color: Longword; Group: TCapGroup); +begin + if Captions[Group].Tex <> nil then + FreeTexture(Captions[Group].Tex); + Captions[Group].Tex:= nil; + + Captions[Group].Tex:= RenderStringTex(s, Color, fntBig); + + case Group of + capgrpGameState: Captions[Group].EndTime:= RealTicks + 2200 + else + Captions[Group].EndTime:= RealTicks + 1400 + LongWord(Captions[Group].Tex^.w) * 3; + end; +end; + +procedure DrawCaptions; +var + grp: TCapGroup; + offset: LongInt; +begin +{$IFDEF IPHONEOS} + offset:= 40; +{$ELSE} + offset:= 8; +{$ENDIF} + + for grp:= Low(TCapGroup) to High(TCapGroup) do + with Captions[grp] do + if Tex <> nil then + begin + DrawCentered(0, offset, Tex); + inc(offset, Tex^.h + 2); + if EndTime <= RealTicks then + begin + FreeTexture(Tex); + Tex:= nil; + EndTime:= 0 + end; + end; +end; + +procedure initModule; +begin + FillChar(Captions, sizeof(Captions), 0) +end; + +procedure freeModule; +begin +end; + +end. diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uChat.pas --- a/hedgewars/uChat.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uChat.pas Tue Jan 04 12:53:46 2011 +0100 @@ -34,7 +34,7 @@ showAll: boolean; implementation -uses uMisc, uStore, uConsts, SDLh, uConsole, uKeys, uTeams; +uses SDLh, uKeys, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO; const MaxStrIndex = 27; @@ -181,44 +181,42 @@ visibleCount:= cnt; end; +procedure SendHogSpeech(s: shortstring); +begin +SendIPC('h' + s); +ParseCommand('/hogsay '+s, true) +end; + procedure AcceptChatString(s: shortstring); var i: TWave; - + c, t: LongInt; + x: byte; begin -// "Make hedgehog say something" -if (s[1] = '"') and (s[Length(s)] = '"') then +t:= LocalTeam; +x:= 0; +if (s[1] = '"') and (s[Length(s)] = '"') then x:= 1 +else if (s[1] = '''') and (s[Length(s)] = '''') then x:= 2 +else if (s[1] = '-') and (s[Length(s)] = '-') then x:= 3; +if not CurrentTeam^.ExtDriven and (x <> 0) then + for c:= 0 to Pred(TeamsCount) do + if (TeamsArray[c] = CurrentTeam) then t:= c; + +if x <> 0 then begin - if CurrentTeam^.ExtDriven then + if t = -1 then ParseCommand('/say ' + copy(s, 2, Length(s)-2), true) else - ParseCommand('/hogsay '#1 + copy(s, 2, Length(s)-2), true); + SendHogSpeech(char(x) + char(t) + copy(s, 2, Length(s)-2)); exit end; -// 'Make hedgehog think something' -if (s[1] = '''') and (s[Length(s)] = '''') then - begin - if CurrentTeam^.ExtDriven then - ParseCommand('/say ' + copy(s, 2, Length(s)-2), true) - else - ParseCommand('/hogsay '#2 + copy(s, 2, Length(s)-2), true); - exit - end; -// -Make hedgehog yell something- -if (s[1] = '-') and (s[Length(s)] = '-') then - begin - if CurrentTeam^.ExtDriven then - ParseCommand('/say ' + copy(s, 2, Length(s)-2), true) - else - ParseCommand('/hogsay '#3 + copy(s, 2, Length(s)-2), true); - exit - end; + // These 3 are same as above, only are to make the hedgehog say it on next attack if (s[1] = '/') and (copy(s, 1, 5) = '/hsa ') then begin if CurrentTeam^.ExtDriven then ParseCommand('/say ' + copy(s, 6, Length(s)-5), true) else - ParseCommand('/hogsay '#4 + copy(s, 6, Length(s)-5), true); + SendHogSpeech(#4 + copy(s, 6, Length(s)-5)); exit end; if (s[1] = '/') and (copy(s, 1, 5) = '/hta ') then @@ -226,7 +224,7 @@ if CurrentTeam^.ExtDriven then ParseCommand('/say ' + copy(s, 6, Length(s)-5), true) else - ParseCommand('/hogsay '#5 + copy(s, 6, Length(s)-5), true); + SendHogSpeech(#5 + copy(s, 6, Length(s)-5)); exit end; if (s[1] = '/') and (copy(s, 1, 5) = '/hya ') then @@ -234,7 +232,7 @@ if CurrentTeam^.ExtDriven then ParseCommand('/say ' + copy(s, 6, Length(s)-5), true) else - ParseCommand('/hogsay '#6 + copy(s, 6, Length(s)-5), true); + SendHogSpeech(#6 + copy(s, 6, Length(s)-5)); exit end; @@ -308,8 +306,64 @@ end end; +procedure chChatMessage(var s: shortstring); +begin + AddChatString(s) +end; + +procedure chSay(var s: shortstring); +begin + SendIPC('s' + s); + + if copy(s, 1, 4) = '/me ' then + s:= #2'* ' + UserNick + ' ' + copy(s, 5, Length(s) - 4) + else + s:= #1 + UserNick + ': ' + s; + + AddChatString(s) +end; + +procedure chTeamSay(var s: shortstring); +begin + SendIPC('b' + s); + + s:= #4 + '[Team] ' + UserNick + ': ' + s; + + AddChatString(s) +end; + +procedure chHistory(var s: shortstring); +begin + s:= s; // avoid compiler hint + uChat.showAll:= not uChat.showAll +end; + +procedure chChat(var s: shortstring); +begin + s:= s; // avoid compiler hint + GameState:= gsChat; + if length(s) = 0 then + KeyPressChat(27) + else + begin + KeyPressChat(27); + KeyPressChat(47); + KeyPressChat(116); + KeyPressChat(101); + KeyPressChat(97); + KeyPressChat(109); + KeyPressChat(32) + end +end; + procedure initModule; begin + RegisterVariable('chatmsg', vtCommand, @chChatMessage, true); + RegisterVariable('say', vtCommand, @chSay, true); + RegisterVariable('team', vtCommand, @chTeamSay, true); + RegisterVariable('history', vtCommand, @chHistory, true ); + RegisterVariable('chat', vtCommand, @chChat, true ); + lastStr:= 0; visibleCount:= 0; showAll:= false; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uCollisions.pas --- a/hedgewars/uCollisions.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uCollisions.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,7 +20,7 @@ unit uCollisions; interface -uses uGears, uFloat; +uses uFloat, uTypes; const cMaxGearArrayInd = 255; @@ -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; @@ -52,7 +53,7 @@ function calcSlopeTangent(Gear: PGear; collisionX, collisionY: LongInt; var outDeltaX, outDeltaY: LongInt; TestWord: LongWord): Boolean; implementation -uses uMisc, uConsts, uLand, uLandGraphics; +uses uConsts, uLandGraphics, uVariables, uDebug; type TCollisionEntry = record X, Y, Radius: LongInt; @@ -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 0ddb100fea61 -r f924be23ffb4 hedgewars/uCommandHandlers.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uCommandHandlers.pas Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,617 @@ +{$INCLUDE "options.inc"} +unit uCommandHandlers; + +interface + +procedure initModule; +procedure freeModule; + +implementation +uses uCommands, uTypes, uVariables, uIO, uDebug, uConsts, uScript, uUtils, SDLh, uRandom; + +procedure chGenCmd(var s: shortstring); +begin +case s[1] of + 'R': if ReadyTimeLeft > 1 then + begin + ReadyTimeLeft:= 1; + if not CurrentTeam^.ExtDriven then SendIPC('c'+s); + end + end +end; + +procedure chQuit(var s: shortstring); +const prevGState: TGameState = gsConfirm; +begin +s:= s; // avoid compiler hint +if GameState <> gsConfirm then + begin + prevGState:= GameState; + GameState:= gsConfirm + end else + GameState:= prevGState +end; + +procedure chConfirm(var s: shortstring); +begin +s:= s; // avoid compiler hint +if GameState = gsConfirm then + begin + SendIPC('Q'); + GameState:= gsExit + end +else + ParseCommand('chat team', true); +end; + +procedure chCheckProto(var s: shortstring); +var i, c: LongInt; +begin +if isDeveloperMode then +begin +val(s, i, c); +if (c <> 0) or (i = 0) then exit; +TryDo(i <= cNetProtoVersion, 'Protocol version mismatch: engine is too old', true); +TryDo(i >= cNetProtoVersion, 'Protocol version mismatch: engine is too new', true) +end +end; + +procedure chTeamLocal(var s: shortstring); +begin +s:= s; // avoid compiler hint +if not isDeveloperMode then exit; +if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/rdriven"', true); +CurrentTeam^.ExtDriven:= true +end; + +procedure chGrave(var s: shortstring); +begin +if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/grave"', true); +if s[1]='"' then Delete(s, 1, 1); +if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); +CurrentTeam^.GraveName:= s +end; + +procedure chFort(var s: shortstring); +begin +if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/fort"', true); +if s[1]='"' then Delete(s, 1, 1); +if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); +CurrentTeam^.FortName:= s +end; + +procedure chFlag(var s: shortstring); +begin +if CurrentTeam = nil then OutError(errmsgIncorrectUse + ' "/flag"', true); +if s[1]='"' then Delete(s, 1, 1); +if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); +CurrentTeam^.flag:= s +end; + +procedure chScript(var s: shortstring); +begin +if s[1]='"' then Delete(s, 1, 1); +if s[byte(s[0])]='"' then Delete(s, byte(s[0]), 1); +ScriptLoad(s) +end; + +procedure chSetHat(var s: shortstring); +begin +if (not isDeveloperMode) or (CurrentTeam = nil) then exit; +with CurrentTeam^ do + begin + if not CurrentHedgehog^.King then + if (s = '') or + (((GameFlags and gfKing) <> 0) and (s = 'crown')) or + ((Length(s) > 39) and (Copy(s,1,8) = 'Reserved') and (Copy(s,9,32) <> PlayerHash)) then + CurrentHedgehog^.Hat:= 'NoHat' + else + CurrentHedgehog^.Hat:= s + end; +end; + +procedure chCurU_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementY:= -1; +end; + +procedure chCurU_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementY:= 0; +end; + +procedure chCurD_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementY:= 1; +end; + +procedure chCurD_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementY:= 0; +end; + +procedure chCurL_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementX:= -1; +end; + +procedure chCurL_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementX:= 0; +end; + +procedure chCurR_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementX:= 1; +end; + +procedure chCurR_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +CursorMovementX:= 0; +end; + +procedure chLeft_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('L'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmLeft and InputMask); + ScriptCall('onLeft'); +end; + +procedure chLeft_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then exit; +if not CurrentTeam^.ExtDriven then SendIPC('l'); +with CurrentHedgehog^.Gear^ do + Message:= Message and not (gmLeft and InputMask); + ScriptCall('onLeftUp'); +end; + +procedure chRight_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('R'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmRight and InputMask); + ScriptCall('onRight'); +end; + +procedure chRight_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then exit; +if not CurrentTeam^.ExtDriven then SendIPC('r'); +with CurrentHedgehog^.Gear^ do + Message:= Message and not (gmRight and InputMask); + ScriptCall('onRightUp'); +end; + +procedure chUp_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('U'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmUp and InputMask); + ScriptCall('onUp'); +end; + +procedure chUp_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then exit; +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); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('D'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmDown and InputMask); + ScriptCall('onDown'); +end; + +procedure chDown_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then exit; +if not CurrentTeam^.ExtDriven then SendIPC('d'); +with CurrentHedgehog^.Gear^ do + Message:= Message and not (gmDown and InputMask); + ScriptCall('onDownUp'); +end; + +procedure chPrecise_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('Z'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmPrecise and InputMask); + ScriptCall('onPrecise'); +end; + +procedure chPrecise_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then exit; +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); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('j'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmLJump and InputMask); + ScriptCall('onLJump'); +end; + +procedure chHJump(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('J'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmHJump and InputMask); + ScriptCall('onHJump'); +end; + +procedure chAttack_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + begin + {$IFDEF DEBUGFILE}AddFileLog('/+attack: hedgehog''s Gear^.State = '+inttostr(State));{$ENDIF} + if ((State and gstHHDriven) <> 0) then + begin + FollowGear:= CurrentHedgehog^.Gear; + if not CurrentTeam^.ExtDriven then SendIPC('A'); + Message:= Message or (gmAttack and InputMask); + ScriptCall('onAttack'); + end + end +end; + +procedure chAttack_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then exit; +with CurrentHedgehog^.Gear^ do + begin + if not CurrentTeam^.ExtDriven and + ((Message and gmAttack) <> 0) then SendIPC('a'); + Message:= Message and not (gmAttack and InputMask); + ScriptCall('onAttackUp'); + end +end; + +procedure chSwitch(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +if not CurrentTeam^.ExtDriven then SendIPC('S'); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + Message:= Message or (gmSwitch and InputMask); + ScriptCall('onSwitch'); +end; + +procedure chNextTurn(var s: shortstring); +begin + s:= s; // avoid compiler hint + 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); +begin +if (s[0] <> #1) or (s[1] < '1') or (s[1] > '5') or CheckNoTeamOrHH then exit; + +if not CurrentTeam^.ExtDriven then SendIPC(s); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + begin + Message:= Message or (gmTimer and InputMask); + MsgParam:= byte(s[1]) - ord('0'); + ScriptCall('onTimer'); + end +end; + +procedure chSlot(var s: shortstring); +var slot: LongWord; +begin +if (s[0] <> #1) or CheckNoTeamOrHH then exit; +slot:= byte(s[1]) - 49; +if slot > cMaxSlotIndex then exit; +if not CurrentTeam^.ExtDriven then SendIPC(char(byte(s[1]) + 79)); +bShowFinger:= false; +with CurrentHedgehog^.Gear^ do + begin + Message:= Message or (gmSlot and InputMask); + MsgParam:= slot; + ScriptCall('onSlot'); + end +end; + +procedure chSetWeapon(var s: shortstring); +begin + if (s[0] <> #1) or CheckNoTeamOrHH then exit; + + if TAmmoType(s[1]) > High(TAmmoType) then exit; + + if not CurrentTeam^.ExtDriven then SendIPC('w' + s); + + with CurrentHedgehog^.Gear^ do + begin + Message:= Message or (gmWeapon and InputMask); + MsgParam:= byte(s[1]); + ScriptCall('onSetWeapon'); + end; +end; + +procedure chTaunt(var s: shortstring); +begin +if (s[0] <> #1) or CheckNoTeamOrHH then exit; + +if TWave(s[1]) > High(TWave) then exit; + +if not CurrentTeam^.ExtDriven then SendIPC('t' + s); + +with CurrentHedgehog^.Gear^ do + begin + Message:= Message or (gmAnimate and InputMask); + MsgParam:= byte(s[1]) ; + ScriptCall('onTaunt'); + end +end; + +procedure chPut(var s: shortstring); +begin + s:= s; // avoid compiler hint + doPut(0, 0, false); +end; + +procedure chCapture(var s: shortstring); +begin +s:= s; // avoid compiler hint +flagMakeCapture:= true +end; + +procedure chSetMap(var s: shortstring); +begin +if isDeveloperMode then +begin +Pathz[ptMapCurrent]:= Pathz[ptMaps] + '/' + s; +InitStepsFlags:= InitStepsFlags or cifMap +end +end; + +procedure chSetTheme(var s: shortstring); +begin +if isDeveloperMode then +begin +Pathz[ptCurrTheme]:= Pathz[ptThemes] + '/' + s; +Theme:= s; +InitStepsFlags:= InitStepsFlags or cifTheme +end +end; + +procedure chSetSeed(var s: shortstring); +begin +if isDeveloperMode then +begin +SetRandomSeed(s); +cSeed:= s; +InitStepsFlags:= InitStepsFlags or cifRandomize +end +end; + +procedure chAmmoMenu(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH then + bShowAmmoMenu:= true +else + begin + with CurrentTeam^ do + with Hedgehogs[CurrHedgehog] do + begin + bSelected:= false; + + if bShowAmmoMenu then bShowAmmoMenu:= false + else if ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or + ((MultiShootAttacks > 0) and ((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_NoRoundEnd) = 0)) or + ((Gear^.State and gstHHDriven) = 0) then else bShowAmmoMenu:= true + end; + end +end; + +procedure chVol_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +inc(cVolumeDelta, 3) +end; + +procedure chVol_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +dec(cVolumeDelta, 3) +end; + +procedure chFindhh(var s: shortstring); +begin +s:= s; // avoid compiler hint +if CheckNoTeamOrHH or isPaused then exit; +bShowFinger:= true; +FollowGear:= CurrentHedgehog^.Gear +end; + +procedure chPause(var s: shortstring); +begin +s:= s; // avoid compiler hint +if gameType <> gmtNet then + isPaused:= not isPaused; +SDL_ShowCursor(ord(isPaused)) +end; + +procedure chRotateMask(var s: shortstring); +begin +s:= s; // avoid compiler hint +if ((GameFlags and gfInvulnerable) = 0) then cTagsMask:= cTagsMasks[cTagsMask] else cTagsMask:= cTagsMasksNoHealth[cTagsMask]; +end; + +procedure chSpeedup_p(var s: shortstring); +begin +s:= s; // avoid compiler hint +isSpeed:= true +end; + +procedure chSpeedup_m(var s: shortstring); +begin +s:= s; // avoid compiler hint +isSpeed:= false +end; + +procedure chZoomIn(var s: shortstring); +begin + s:= s; // avoid compiler hint + if ZoomValue < cMinZoomLevel then + ZoomValue:= ZoomValue + cZoomDelta; +end; + +procedure chZoomOut(var s: shortstring); +begin + s:= s; // avoid compiler hint + if ZoomValue > cMaxZoomLevel then + ZoomValue:= ZoomValue - cZoomDelta; +end; + +procedure chZoomReset(var s: shortstring); +begin + s:= s; // avoid compiler hint + ZoomValue:= cDefaultZoomLevel; +end; + + +procedure initModule; +begin +//////// Begin top sorted by freq analysis not including chatmsg + RegisterVariable('+right' , vtCommand, @chRight_p , false); + RegisterVariable('-right' , vtCommand, @chRight_m , false); + RegisterVariable('+up' , vtCommand, @chUp_p , false); + RegisterVariable('-up' , vtCommand, @chUp_m , false); + RegisterVariable('+left' , vtCommand, @chLeft_p , false); + RegisterVariable('-left' , vtCommand, @chLeft_m , false); + RegisterVariable('+attack' , vtCommand, @chAttack_p , false); + RegisterVariable('+down' , vtCommand, @chDown_p , false); + RegisterVariable('-down' , vtCommand, @chDown_m , false); + RegisterVariable('hjump' , vtCommand, @chHJump , false); + RegisterVariable('ljump' , vtCommand, @chLJump , false); + RegisterVariable('nextturn', vtCommand, @chNextTurn , false); + RegisterVariable('-attack' , vtCommand, @chAttack_m , false); + RegisterVariable('slot' , vtCommand, @chSlot , false); + RegisterVariable('setweap' , vtCommand, @chSetWeapon , false); +//////// End top by freq analysis + RegisterVariable('gencmd' , vtCommand, @chGenCmd , false); + RegisterVariable('flag' , vtCommand, @chFlag , false); + RegisterVariable('script' , vtCommand, @chScript , false); + RegisterVariable('proto' , vtCommand, @chCheckProto , true ); + RegisterVariable('spectate', vtBoolean, @fastUntilLag , false); + RegisterVariable('capture' , vtCommand, @chCapture , true ); + RegisterVariable('rotmask' , vtCommand, @chRotateMask , true ); + RegisterVariable('rdriven' , vtCommand, @chTeamLocal , false); + RegisterVariable('map' , vtCommand, @chSetMap , false); + RegisterVariable('theme' , vtCommand, @chSetTheme , false); + RegisterVariable('seed' , vtCommand, @chSetSeed , false); + RegisterVariable('template_filter', vtLongInt, @cTemplateFilter, false); + RegisterVariable('mapgen' , vtLongInt, @cMapGen , false); + RegisterVariable('maze_size',vtLongInt, @cMazeSize , false); + RegisterVariable('delay' , vtLongInt, @cInactDelay , false); + RegisterVariable('ready' , vtLongInt, @cReadyDelay , false); + RegisterVariable('casefreq', vtLongInt, @cCaseFactor , false); + RegisterVariable('healthprob', vtLongInt, @cHealthCaseProb, false); + RegisterVariable('hcaseamount', vtLongInt, @cHealthCaseAmount, false); + RegisterVariable('sd_turns', vtLongInt, @cSuddenDTurns , false); + RegisterVariable('waterrise', vtLongInt, @cWaterRise , false); + RegisterVariable('healthdec', vtLongInt, @cHealthDecrease, false); + RegisterVariable('damagepct',vtLongInt, @cDamagePercent , false); + RegisterVariable('ropepct' , vtLongInt, @cRopePercent , false); + RegisterVariable('minedudpct',vtLongInt,@cMineDudPercent, false); + RegisterVariable('minesnum', vtLongInt, @cLandMines , false); + RegisterVariable('explosives',vtLongInt,@cExplosives , false); + RegisterVariable('gmflags' , vtLongInt, @GameFlags , 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('confirm' , vtCommand, @chConfirm , true ); + RegisterVariable('+speedup', vtCommand, @chSpeedup_p , true ); + RegisterVariable('-speedup', vtCommand, @chSpeedup_m , true ); + RegisterVariable('zoomin' , vtCommand, @chZoomIn , true ); + RegisterVariable('zoomout' , vtCommand, @chZoomOut , true ); + RegisterVariable('zoomreset',vtCommand, @chZoomReset , true ); + RegisterVariable('ammomenu', vtCommand, @chAmmoMenu , true); + RegisterVariable('+precise', vtCommand, @chPrecise_p , false); + RegisterVariable('-precise', vtCommand, @chPrecise_m , false); + RegisterVariable('switch' , vtCommand, @chSwitch , false); + RegisterVariable('timer' , vtCommand, @chTimer , false); + RegisterVariable('taunt' , vtCommand, @chTaunt , false); + RegisterVariable('put' , vtCommand, @chPut , false); + RegisterVariable('+volup' , vtCommand, @chVol_p , true ); + RegisterVariable('-volup' , vtCommand, @chVol_m , true ); + RegisterVariable('+voldown', vtCommand, @chVol_m , true ); + RegisterVariable('-voldown', vtCommand, @chVol_p , true ); + RegisterVariable('findhh' , vtCommand, @chFindhh , true ); + RegisterVariable('pause' , vtCommand, @chPause , true ); + RegisterVariable('+cur_u' , vtCommand, @chCurU_p , true ); + RegisterVariable('-cur_u' , vtCommand, @chCurU_m , true ); + RegisterVariable('+cur_d' , vtCommand, @chCurD_p , true ); + RegisterVariable('-cur_d' , vtCommand, @chCurD_m , true ); + RegisterVariable('+cur_l' , vtCommand, @chCurL_p , true ); + RegisterVariable('-cur_l' , vtCommand, @chCurL_m , true ); + RegisterVariable('+cur_r' , vtCommand, @chCurR_p , true ); + RegisterVariable('-cur_r' , vtCommand, @chCurR_m , true ); +end; + +procedure freeModule; +begin +end; + +end. diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uCommands.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uCommands.pas Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,135 @@ +{$INCLUDE "options.inc"} + +unit uCommands; + +interface + +var isDeveloperMode: boolean; +type TVariableType = (vtCommand, vtLongInt, vthwFloat, vtBoolean); + TCommandHandler = procedure (var params: shortstring); + +procedure initModule; +procedure freeModule; +procedure RegisterVariable(Name: shortstring; VType: TVariableType; p: pointer; Trusted: boolean); +procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); +procedure StopMessages(Message: Longword); + +implementation +uses Types, uConsts, uVariables, uConsole, uUtils, uDebug; + +type PVariable = ^TVariable; + TVariable = record + Next: PVariable; + Name: string[15]; + VType: TVariableType; + Handler: pointer; + Trusted: boolean; + end; + +var + Variables: PVariable; + +procedure RegisterVariable(Name: shortstring; VType: TVariableType; p: pointer; Trusted: boolean); +var value: PVariable; +begin +New(value); +TryDo(value <> nil, 'RegisterVariable: value = nil', true); +FillChar(value^, sizeof(TVariable), 0); +value^.Name:= Name; +value^.VType:= VType; +value^.Handler:= p; +value^.Trusted:= Trusted; + +if Variables = nil then Variables:= value + else begin + value^.Next:= Variables; + Variables:= value + end; +end; + + +procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); +var ii: LongInt; + s: shortstring; + t: PVariable; + c: char; +begin +//WriteLnToConsole(CmdStr); +if CmdStr[0]=#0 then exit; +c:= CmdStr[1]; +if c in ['/', '$'] then Delete(CmdStr, 1, 1) else c:= '/'; +s:= ''; +SplitBySpace(CmdStr, s); +{$IFDEF DEBUGFILE}AddFileLog('[Cmd] ' + c + CmdStr + ' (' + inttostr(length(s)) + ')');{$ENDIF} +t:= Variables; +while t <> nil do + begin + if t^.Name = CmdStr then + begin + if TrustedSource or t^.Trusted then + case t^.VType of + vtCommand: if c='/' then + begin + TCommandHandler(t^.Handler)(s); + end; + vtLongInt: if c='$' then + if s[0]=#0 then + begin + str(PLongInt(t^.Handler)^, s); + WriteLnToConsole('$' + CmdStr + ' is "' + s + '"'); + end else val(s, PLongInt(t^.Handler)^); + vthwFloat: if c='$' then + if s[0]=#0 then + begin + //str(PhwFloat(t^.Handler)^:4:6, s); + WriteLnToConsole('$' + CmdStr + ' is "' + s + '"'); + end else; //val(s, PhwFloat(t^.Handler)^, i); + vtBoolean: if c='$' then + if s[0]=#0 then + begin + str(ord(boolean(t^.Handler^)), s); + WriteLnToConsole('$' + CmdStr + ' is "' + s + '"'); + end else + begin + val(s, ii); + boolean(t^.Handler^):= not (ii = 0) + end; + end; + exit + end else t:= t^.Next + end; +case c of + '$': WriteLnToConsole(errmsgUnknownVariable + ': "$' + CmdStr + '"') + else WriteLnToConsole(errmsgUnknownCommand + ': "/' + CmdStr + '"') end +end; + + +procedure StopMessages(Message: Longword); +begin +if (Message and gmLeft) <> 0 then ParseCommand('/-left', true) else +if (Message and gmRight) <> 0 then ParseCommand('/-right', true) else +if (Message and gmUp) <> 0 then ParseCommand('/-up', true) else +if (Message and gmDown) <> 0 then ParseCommand('/-down', true) else +if (Message and gmAttack) <> 0 then ParseCommand('/-attack', true) +end; + +procedure initModule; +begin + Variables:= nil; + isDeveloperMode:= true; +end; + +procedure freeModule; +var t, tt: PVariable; +begin + tt:= Variables; + Variables:= nil; + while tt <> nil do + begin + t:= tt; + tt:= tt^.Next; + Dispose(t) + end; +end; + +end. diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uConsole.pas --- a/hedgewars/uConsole.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uConsole.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,44 +20,26 @@ unit uConsole; interface -uses uFloat; - -var isDeveloperMode: boolean; -type TVariableType = (vtCommand, vtLongInt, vthwFloat, vtBoolean); - TCommandHandler = procedure (var params: shortstring); procedure initModule; procedure freeModule; procedure WriteToConsole(s: shortstring); procedure WriteLnToConsole(s: shortstring); -procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); -procedure StopMessages(Message: Longword); function GetLastConsoleLine: shortstring; -procedure doPut(putX, putY: LongInt; fromAI: boolean); - implementation -uses uMisc, uStore, Types, uConsts, uGears, uTeams, uIO, uKeys, uWorld, uMobile, - uRandom, uAmmos, uStats, uChat, SDLh, uSound, uVisualGears, uScript; +uses Types, uVariables, uUtils; const cLineWidth: LongInt = 0; - cLinesCount = 256; + cLinesCount = 8; -type PVariable = ^TVariable; - TVariable = record - Next: PVariable; - Name: string[15]; - VType: TVariableType; - Handler: pointer; - Trusted: boolean; - end; +type TTextLine = record s: shortstring; end; var ConsoleLines: array[byte] of TTextLine; CurrLine: LongInt; - Variables: PVariable; procedure SetLine(var tl: TTextLine; str: shortstring); begin @@ -65,32 +47,12 @@ s:= str; end; -function RegisterVariable(Name: shortstring; VType: TVariableType; p: pointer; Trusted: boolean): PVariable; -var value: PVariable; -begin -New(value); -TryDo(value <> nil, 'RegisterVariable: value = nil', true); -FillChar(value^, sizeof(TVariable), 0); -value^.Name:= Name; -value^.VType:= VType; -value^.Handler:= p; -value^.Trusted:= Trusted; - -if Variables = nil then Variables:= value - else begin - value^.Next:= Variables; - Variables:= value - end; - -RegisterVariable:= value; -end; - procedure WriteToConsole(s: shortstring); var Len: LongInt; done: boolean; begin {$IFNDEF NOCONSOLE} -{$IFDEF DEBUGFILE}AddFileLog('Console write: ' + s);{$ENDIF} +{$IFDEF DEBUGFILE}AddFileLog('[Con] ' + s);{$ENDIF} Write(s); done:= false; @@ -122,60 +84,6 @@ {$ENDIF} end; -procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); -var ii: LongInt; - s: shortstring; - t: PVariable; - c: char; -begin -//WriteLnToConsole(CmdStr); -if CmdStr[0]=#0 then exit; -{$IFDEF DEBUGFILE}AddFileLog('ParseCommand "' + CmdStr + '"');{$ENDIF} -c:= CmdStr[1]; -if c in ['/', '$'] then Delete(CmdStr, 1, 1) else c:= '/'; -s:= ''; -SplitBySpace(CmdStr, s); -t:= Variables; -while t <> nil do - begin - if t^.Name = CmdStr then - begin - if TrustedSource or t^.Trusted then - case t^.VType of - vtCommand: if c='/' then - begin - TCommandHandler(t^.Handler)(s); - end; - vtLongInt: if c='$' then - if s[0]=#0 then - begin - str(PLongInt(t^.Handler)^, s); - WriteLnToConsole('$' + CmdStr + ' is "' + s + '"'); - end else val(s, PLongInt(t^.Handler)^); - vthwFloat: if c='$' then - if s[0]=#0 then - begin - //str(PhwFloat(t^.Handler)^:4:6, s); - WriteLnToConsole('$' + CmdStr + ' is "' + s + '"'); - end else; //val(s, PhwFloat(t^.Handler)^, i); - vtBoolean: if c='$' then - if s[0]=#0 then - begin - str(ord(boolean(t^.Handler^)), s); - WriteLnToConsole('$' + CmdStr + ' is "' + s + '"'); - end else - begin - val(s, ii); - boolean(t^.Handler^):= not (ii = 0) - end; - end; - exit - end else t:= t^.Next - end; -case c of - '$': WriteLnToConsole(errmsgUnknownVariable + ': "$' + CmdStr + '"') - else WriteLnToConsole(errmsgUnknownCommand + ': "/' + CmdStr + '"') end -end; function GetLastConsoleLine: shortstring; var valueStr: shortstring; @@ -192,22 +100,10 @@ GetLastConsoleLine:= valueStr; end; -procedure StopMessages(Message: Longword); -begin -if (Message and gmLeft) <> 0 then ParseCommand('/-left', true) else -if (Message and gmRight) <> 0 then ParseCommand('/-right', true) else -if (Message and gmUp) <> 0 then ParseCommand('/-up', true) else -if (Message and gmDown) <> 0 then ParseCommand('/-down', true) else -if (Message and gmAttack) <> 0 then ParseCommand('/-attack', true) -end; - -{$INCLUDE "CCHandlers.inc"} procedure initModule; var i: LongInt; begin CurrLine:= 0; - Variables:= nil; - isDeveloperMode:= true; // initConsole cLineWidth:= cScreenWidth div 10; @@ -215,113 +111,11 @@ cLineWidth:= 255; for i:= 0 to Pred(cLinesCount) do PByte(@ConsoleLines[i])^:= 0; - - // NOTE: please, keep most frequently used commands on bottom - RegisterVariable('flag' , vtCommand, @chFlag , false); - RegisterVariable('script' , vtCommand, @chScript , false); - RegisterVariable('proto' , vtCommand, @chCheckProto , true ); - RegisterVariable('spectate', vtBoolean, @fastUntilLag , false); - RegisterVariable('capture' , vtCommand, @chCapture , true ); - RegisterVariable('rotmask' , vtCommand, @chRotateMask , true ); - RegisterVariable('addteam' , vtCommand, @chAddTeam , false); - RegisterVariable('rdriven' , vtCommand, @chTeamLocal , false); - RegisterVariable('map' , vtCommand, @chSetMap , false); - RegisterVariable('theme' , vtCommand, @chSetTheme , false); - RegisterVariable('seed' , vtCommand, @chSetSeed , false); - RegisterVariable('template_filter', vtLongInt, @cTemplateFilter, false); - RegisterVariable('mapgen' , vtLongInt, @cMapGen , false); - RegisterVariable('maze_size',vtLongInt, @cMazeSize , false); - RegisterVariable('delay' , vtLongInt, @cInactDelay , false); - RegisterVariable('ready' , vtLongInt, @cReadyDelay , false); - RegisterVariable('casefreq', vtLongInt, @cCaseFactor , false); - RegisterVariable('healthprob', vtLongInt, @cHealthCaseProb, false); - RegisterVariable('hcaseamount', vtLongInt, @cHealthCaseAmount, false); - RegisterVariable('sd_turns', vtLongInt, @cSuddenDTurns , false); - RegisterVariable('waterrise', vtLongInt, @cWaterRise , false); - RegisterVariable('healthdec', vtLongInt, @cHealthDecrease, false); - RegisterVariable('damagepct',vtLongInt, @cDamagePercent , false); - RegisterVariable('minedudpct',vtLongInt,@cMineDudPercent, false); - 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('voicepack',vtCommand, @chVoicepack , false); - RegisterVariable('grave' , vtCommand, @chGrave , false); - RegisterVariable('bind' , vtCommand, @chBind , true ); - RegisterVariable('addhh' , vtCommand, @chAddHH , false); - RegisterVariable('hat' , vtCommand, @chSetHat , false); - RegisterVariable('hhcoords', vtCommand, @chSetHHCoords , false); - RegisterVariable('ammloadt', vtCommand, @chSetAmmoLoadout, false); - RegisterVariable('ammdelay', vtCommand, @chSetAmmoDelay, false); - RegisterVariable('ammprob', vtCommand, @chSetAmmoProbability, false); - RegisterVariable('ammreinf', vtCommand, @chSetAmmoReinforcement, false); - RegisterVariable('ammstore', vtCommand, @chAddAmmoStore , false); - RegisterVariable('quit' , vtCommand, @chQuit , true ); - RegisterVariable('confirm' , vtCommand, @chConfirm , true ); - RegisterVariable('+speedup', vtCommand, @chSpeedup_p , true ); - RegisterVariable('-speedup', vtCommand, @chSpeedup_m , true ); - RegisterVariable('zoomin' , vtCommand, @chZoomIn , true ); - RegisterVariable('zoomout' , vtCommand, @chZoomOut , true ); - RegisterVariable('zoomreset',vtCommand, @chZoomReset , true ); - RegisterVariable('skip' , vtCommand, @chSkip , false); - RegisterVariable('history' , vtCommand, @chHistory , true ); - RegisterVariable('chat' , vtCommand, @chChat , true ); - RegisterVariable('say' , vtCommand, @chSay , true ); - RegisterVariable('hogsay' , vtCommand, @chHogSay , true ); - RegisterVariable('team' , vtCommand, @chTeamSay , true ); - RegisterVariable('ammomenu', vtCommand, @chAmmoMenu , true); - RegisterVariable('+precise', vtCommand, @chPrecise_p , false); - RegisterVariable('-precise', vtCommand, @chPrecise_m , false); - RegisterVariable('+left' , vtCommand, @chLeft_p , false); - RegisterVariable('-left' , vtCommand, @chLeft_m , false); - RegisterVariable('+right' , vtCommand, @chRight_p , false); - RegisterVariable('-right' , vtCommand, @chRight_m , false); - RegisterVariable('+up' , vtCommand, @chUp_p , false); - RegisterVariable('-up' , vtCommand, @chUp_m , false); - RegisterVariable('+down' , vtCommand, @chDown_p , false); - RegisterVariable('-down' , vtCommand, @chDown_m , false); - RegisterVariable('+attack' , vtCommand, @chAttack_p , false); - RegisterVariable('-attack' , vtCommand, @chAttack_m , false); - RegisterVariable('switch' , vtCommand, @chSwitch , false); - RegisterVariable('nextturn', vtCommand, @chNextTurn , false); - RegisterVariable('timer' , vtCommand, @chTimer , false); - RegisterVariable('taunt' , vtCommand, @chTaunt , false); - RegisterVariable('setweap' , vtCommand, @chSetWeapon , false); - RegisterVariable('slot' , vtCommand, @chSlot , false); - RegisterVariable('put' , vtCommand, @chPut , false); - RegisterVariable('ljump' , vtCommand, @chLJump , false); - RegisterVariable('hjump' , vtCommand, @chHJump , false); - RegisterVariable('fullscr' , vtCommand, @chFullScr , true ); - RegisterVariable('+volup' , vtCommand, @chVol_p , true ); - RegisterVariable('-volup' , vtCommand, @chVol_m , true ); - RegisterVariable('+voldown', vtCommand, @chVol_m , true ); - RegisterVariable('-voldown', vtCommand, @chVol_p , true ); - RegisterVariable('findhh' , vtCommand, @chFindhh , true ); - RegisterVariable('pause' , vtCommand, @chPause , true ); - RegisterVariable('+cur_u' , vtCommand, @chCurU_p , true ); - RegisterVariable('-cur_u' , vtCommand, @chCurU_m , true ); - RegisterVariable('+cur_d' , vtCommand, @chCurD_p , true ); - RegisterVariable('-cur_d' , vtCommand, @chCurD_m , true ); - RegisterVariable('+cur_l' , vtCommand, @chCurL_p , true ); - RegisterVariable('-cur_l' , vtCommand, @chCurL_m , true ); - RegisterVariable('+cur_r' , vtCommand, @chCurR_p , true ); - RegisterVariable('-cur_r' , vtCommand, @chCurR_m , true ); end; procedure freeModule; -var t, tt: PVariable; begin - tt:= Variables; - Variables:= nil; - while tt <> nil do - begin - t:= tt; - tt:= tt^.Next; - Dispose(t) - end; + end; end. diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uConsts.pas Tue Jan 04 12:53:46 2011 +0100 @@ -21,181 +21,10 @@ unit uConsts; interface -uses SDLh, uFloat, uLocale, GLunit; - +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 - -type - HwColor4f = record - r, g, b, a: byte - end; - - TGameState = (gsLandGen, gsStart, gsGame, gsChat, gsConfirm, gsExit); - - TGameType = (gmtLocal, gmtDemo, gmtNet, gmtSave, gmtLandPreview, gmtSyntax); - - TPathType = (ptNone, ptData, ptGraphics, ptThemes, ptCurrTheme, ptTeams, ptMaps, - ptMapCurrent, ptDemos, ptSounds, ptGraves, ptFonts, ptForts, - ptLocale, ptAmmoMenu, ptHedgehog, ptVoices, ptHats, ptFlags, ptMissionMaps); - - TSprite = (sprWater, sprCloud, sprBomb, sprBigDigit, sprFrame, - sprLag, sprArrow, sprBazookaShell, sprTargetP, sprBee, - sprSmokeTrace, sprRopeHook, sprExplosion50, sprMineOff, - sprMineOn, sprMineDead, sprCase, sprFAid, sprDynamite, sprPower, - sprClusterBomb, sprClusterParticle, sprFlame, sprHorizont, - sprHorizontL, sprHorizontR, sprSky, sprSkyL, - sprSkyR, sprAMBorderHorizontal, sprAMBorderVertical, sprAMSlot, sprAMAmmos, - sprAMSlotKeys, sprAMCorners, sprFinger, sprAirBomb, - sprAirplane, sprAmAirplane, sprAmGirder, sprHHTelepMask, - sprSwitch, sprParachute, sprTarget, sprRopeNode, - sprQuestion, sprPowerBar, sprWindBar, sprWindL, sprWindR, - sprFlake, sprHandRope, sprHandBazooka, sprHandShotgun, - sprHandDEagle, sprHandAirAttack, sprHandBaseball, sprPHammer, - sprHandBlowTorch, sprBlowTorch, sprTeleport, sprHHDeath, - sprShotgun, sprDEagle, sprHHIdle, sprMortar, sprTurnsLeft, - sprKamikaze, sprWhip, sprKowtow, sprSad, sprWave, - sprHurrah, sprLemonade, sprShrug, sprJuggle, sprExplPart, sprExplPart2, - sprCakeWalk, sprCakeDown, sprAMAmmosBW, sprWatermelon, - sprEvilTrace, sprHellishBomb, sprSeduction, sprDress, - sprCensored, sprDrill, sprHandDrill, sprHandBallgun, sprBalls, - sprPlane, sprHandPlane, sprUtility, sprInvulnerable, sprVampiric, sprGirder, - sprSpeechCorner, sprSpeechEdge, sprSpeechTail, - sprThoughtCorner, sprThoughtEdge, sprThoughtTail, - sprShoutCorner, sprShoutEdge, sprShoutTail, - sprSniperRifle, sprBubbles, sprJetpack, sprHealth, sprHandMolotov, sprMolotov, - sprSmoke, sprSmokeWhite, sprShell, sprDust, sprExplosives, sprExplosivesRoll, - sprAmTeleport, sprSplash, sprDroplet, sprBirdy, sprHandCake, sprHandConstruction, - sprHandGrenade, sprHandMelon, sprHandMortar, sprHandSkip, sprHandCluster, - sprHandDynamite, sprHandHellish, sprHandMine, sprHandSeduction, sprHandVamp, - sprBigExplosion, sprSmokeRing, sprBeeTrace, sprEgg, sprTargetBee, sprHandBee, - sprFeather, sprPiano, sprHandSineGun, sprPortalGun, sprPortal, - sprCheese, sprHandCheese, sprHandFlamethrower, sprChunk, sprNote, - sprSMineOff, sprSMineOn, sprHandSMine, sprHammer, - sprHandResurrector, sprCross, sprAirDrill, sprNapalmBomb, - sprBulletHit - ); - - // Gears that interact with other Gears and/or Land - TGearType = (gtBomb, gtHedgehog, gtShell, gtGrave, gtBee, // 4 - gtShotgunShot, gtPickHammer, gtRope, gtMine, gtCase, // 9 - gtDEagleShot, gtDynamite, gtClusterBomb, gtCluster, gtShover, // 14 - gtFlame, gtFirePunch, gtATStartGame, gtATSmoothWindCh, // 18 - gtATFinishGame, gtParachute, gtAirAttack, gtAirBomb, gtBlowTorch, // 23 - gtGirder, gtTeleport, gtSwitcher, gtTarget, gtMortar, // 28 - gtWhip, gtKamikaze, gtCake, gtSeduction, gtWatermelon, gtMelonPiece, // 34 - gtHellishBomb, gtWaterUp, gtDrill, gtBallGun, gtBall, gtRCPlane, // 40 - gtSniperRifleShot, gtJetpack, gtMolotov, gtExplosives, gtBirdy, // 45 - gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower, // 51 - gtSMine, gtPoisonCloud, gtHammer, gtHammerHit, gtResurrector, // 56 - gtNapalmBomb); // 57 - - // Gears that are _only_ of visual nature (e.g. background stuff, visual effects, speechbubbles, etc.) - TVisualGearType = (vgtFlake, vgtCloud, vgtExplPart, vgtExplPart2, vgtFire, - vgtSmallDamageTag, vgtTeamHealthSorter, vgtSpeechBubble, vgtBubble, - vgtSteam, vgtAmmo, vgtSmoke, vgtSmokeWhite, vgtHealth, vgtShell, - vgtDust, vgtSplash, vgtDroplet, vgtSmokeRing, vgtBeeTrace, vgtEgg, - vgtFeather, vgtHealthTag, vgtSmokeTrace, vgtEvilTrace, vgtExplosion, - vgtBigExplosion, vgtChunk, vgtNote, vgtLineTrail, - vgtBulletHit); - - TGearsType = set of TGearType; - - TDamageSource = (dsUnknown, dsFall, dsBullet, dsExplosion, dsShove, dsPoison); - - TSound = (sndNone, - sndGrenadeImpact, sndExplosion, sndThrowPowerUp, sndThrowRelease, - sndSplash, sndShotgunReload, sndShotgunFire, sndGraveImpact, - sndMineTick, sndPickhammer, sndGun, sndBee, sndJump1, sndJump2, - sndJump3, sndYesSir, sndLaugh, sndIllGetYou, sndIncoming, - sndMissed, sndStupid, sndFirstBlood, sndBoring, sndByeBye, - sndSameTeam, sndNutter, sndReinforce, sndTraitor, sndRegret, - sndEnemyDown, sndCoward, sndHurry, sndWatchIt, sndKamikaze, - sndCake, sndOw1, sndOw2, sndOw3, sndOw4, sndFirePunch1, sndFirePunch2, - sndFirePunch3, sndFirePunch4, sndFirePunch5, sndFirePunch6, - sndMelon, sndHellish, sndYoohoo, sndRCPlane, sndWhipCrack, - sndRideOfTheValkyries, sndDenied, sndPlaced, sndBaseballBat, - sndVaporize, sndWarp, sndSuddenDeath, sndMortar, sndShutter, - sndHomerun, sndMolotov, sndCover, sndUhOh, sndOops, - sndNooo, sndHello, sndRopeShot, sndRopeAttach, sndRopeRelease, - sndSwitchHog, sndVictory, sndSniperReload, sndSteps, sndLowGravity, - sndHellishImpact1, sndHellishImpact2, sndHellishImpact3, sndHellishImpact4, - sndMelonImpact, sndDroplet1, sndDroplet2, sndDroplet3, sndEggBreak, sndDrillRocket, - sndPoisonCough, sndPoisonMoan, sndBirdyLay, sndWhistle, sndBeeWater, - sndPiano0, sndPiano1, sndPiano2, sndPiano3, sndPiano4, sndPiano5, sndPiano6, sndPiano7, sndPiano8, - sndSkip, sndSineGun, sndOoff1, sndOoff2, sndOoff3, sndWhack, - sndComeonthen, sndParachute, sndBump, sndResurrector); - - TAmmoType = (amNothing, amGrenade, amClusterBomb, amBazooka, amBee, amShotgun, amPickHammer, // 6 - amSkip, amRope, amMine, amDEagle, amDynamite, amFirePunch, amWhip, // 13 - amBaseballBat, amParachute, amAirAttack, amMineStrike, amBlowTorch, // 18 - amGirder, amTeleport, amSwitch, amMortar, amKamikaze, amCake, // 24 - amSeduction, amWatermelon, amHellishBomb, amNapalm, amDrill, amBallgun, // 30 - amRCPlane, amLowGravity, amExtraDamage, amInvulnerable, amExtraTime, // 35 - amLaserSight, amVampiric, amSniperRifle, amJetpack, amMolotov, amBirdy, amPortalGun, // 42 - amPiano, amGasBomb, amSineGun, amFlamethrower, amSMine, amHammer, // 48 - amResurrector, amDrillStrike); - - TCrateType = (HealthCrate, AmmoCrate, UtilityCrate); - - THWFont = (fnt16, fntBig, fntSmall {$IFNDEF IPHONEOS}, CJKfnt16, CJKfntBig, CJKfntSmall{$ENDIF}); - - TCapGroup = (capgrpGameState, capgrpAmmoinfo, capgrpVolume, - capgrpMessage, capgrpAmmostate); - - TStatInfoType = (siGameResult, siMaxStepDamage, siMaxStepKills, siKilledHHs, - siClanHealth, siTeamStats, siPlayerKills, siMaxTeamDamage, - siMaxTeamKills, siMaxTurnSkips ); - - TWave = (waveRollup, waveSad, waveWave, waveHurrah, waveLemonade, waveShrug, waveJuggle); - - TRenderMode = (rmDefault, rmLeftEye, rmRightEye); - TStereoMode = (smNone, smRedCyan, smCyanRed, smRedBlue, smBlueRed, smRedGreen, smGreenRed, smHorizontal, smVertical, smAFR); - - THHFont = record - Handle: PTTF_Font; - Height: LongInt; - style: LongInt; - Name: string[21]; - end; - - PAmmo = ^TAmmo; - TAmmo = record - Propz: LongWord; - Count: LongWord; -(* Using for place hedgehogs mode, but for any other situation where the initial count would be needed I guess. -For example, say, a mode where the weaponset is reset each turn, or on sudden death *) - NumPerTurn: LongWord; - Timer: LongWord; - Pos: LongWord; - AmmoType: TAmmoType; - AttackVoice: TSound; - end; - - TVertex2f = record - X, Y: GLfloat; - end; - - TVertex2i = record - X, Y: GLint; - end; - - PTexture = ^TTexture; - TTexture = record - id: GLuint; - w, h, scale: LongInt; - rx, ry: GLfloat; - priority: GLfloat; - vb, tb: array [0..3] of TVertex2f; - PrevTexture, NextTexture: PTexture; - end; - - THogEffect = (heInvulnerable, heResurrectable, hePoisoned, heResurrected); - - TScreenFade = (sfNone, sfInit, sfToBlack, sfFromBlack, sfToWhite, sfFromWhite); const sfMax = 1000; cDefaultParamNum = 17; @@ -236,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 @@ -270,6 +99,7 @@ cPowerDivisor = 1500; MAXNAMELEN = 192; + MAXROPEPOINTS = 3840; // some opengl headers do not have these macros GL_BGR = $80E0; @@ -282,6 +112,7 @@ cCursorEdgesDist : LongInt = 100; cTeamHealthWidth : LongInt = 128; cWaterOpacity : byte = $80; + cSDWaterOpacity : byte = $80; cifRandomize = $00000001; cifTheme = $00000002; @@ -290,7 +121,7 @@ cTransparentColor: Longword = $00000000; - cMaxTeams = 6; + cMaxTeams = 8; cMaxHHIndex = 7; cMaxHHs = 48; cMaxSpawnPoints = 1024; @@ -328,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 @@ -360,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, @@ -445,1847 +268,7 @@ htHealth = $04; htTransparent = $08; - cHHFileName = 'Hedgehog'; - cCHFileName = 'Crosshair'; - cThemeCFGFilename = 'theme.cfg'; - FontBorder = 2; - cPathz: array[TPathType] of shortstring = ( - '', // ptNone - '', // ptData - 'Graphics', // ptGraphics - 'Themes', // ptThemes - 'Themes/avematan', // ptCurrTheme - 'Teams', // ptTeams - 'Maps', // ptMaps - '', // ptMapCurrent - 'Demos', // ptDemos - 'Sounds', // ptSounds - 'Graphics/Graves', // ptGraves - 'Fonts', // ptFonts - 'Forts', // ptForts - 'Locale', // ptLocale - 'Graphics/AmmoMenu', // ptAmmoMenu - 'Graphics/Hedgehog', // ptHedgehog - 'Sounds/voices', // ptVoices - 'Graphics/Hats', // ptHats - 'Graphics/Flags', // ptFlags - 'Missions/Maps' // ptMissionMaps - ); - - cTagsMasks : array[0..15] of byte = (7, 0, 0, 0, 15, 6, 4, 5, 0, 0, 0, 0, 0, 14, 12, 13); - cTagsMasksNoHealth: array[0..15] of byte = (3, 2, 11, 1, 0, 0, 0, 0, 0, 10, 0, 9, 0, 0, 0, 0); - - Fontz: array[THWFont] of THHFont = ( - (Handle: nil; - Height: 12; - style: TTF_STYLE_NORMAL; - Name: 'DejaVuSans-Bold.ttf'), - (Handle: nil; - Height: 24; - style: TTF_STYLE_NORMAL; - Name: 'DejaVuSans-Bold.ttf'), - (Handle: nil; - Height: 10; - style: TTF_STYLE_NORMAL; - Name: 'DejaVuSans-Bold.ttf') - {$IFNDEF IPHONEOS}, // remove chinese fonts for now - (Handle: nil; - Height: 12; - style: TTF_STYLE_NORMAL; - Name: 'wqy-zenhei.ttc'), - (Handle: nil; - Height: 24; - style: TTF_STYLE_NORMAL; - Name: 'wqy-zenhei.ttc'), - (Handle: nil; - Height: 10; - style: TTF_STYLE_NORMAL; - Name: 'wqy-zenhei.ttc') - {$ENDIF} - ); - - SpritesData: array[TSprite] of record - FileName: String[16]; - Path, AltPath: TPathType; - Texture: PTexture; - Surface: PSDL_Surface; - Width, Height, imageWidth, imageHeight: LongInt; - saveSurf: boolean; - priority: GLfloat; - getDimensions, getImageDimensions: boolean; - end = ( - (FileName: 'BlueWater'; Path: ptCurrTheme;AltPath: ptGraphics; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: true; getImageDimensions: true),// sprWater - (FileName: 'Clouds'; Path: ptCurrTheme;AltPath: ptGraphics; Texture: nil; Surface: nil; - Width: 256; Height:128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprCloud - (FileName: 'Bomb'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBomb - (FileName: 'BigDigits'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBigDigit - (FileName: 'Frame'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 4; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprFrame - (FileName: 'Lag'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 65; Height: 65; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprLag - (FileName: 'Arrow'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprCursor - (FileName:'BazookaShell'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBazookaShell - (FileName: 'Targetp'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprTargetP - (FileName: 'Bee'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBee - (FileName: 'SmokeTrace'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprSmokeTrace - (FileName: 'RopeHook'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprRopeHook - (FileName: 'Expl50'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprExplosion50 - (FileName: 'MineOff'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprMineOff - (FileName: 'MineOn'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprMineOn - (FileName: 'MineDead'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprMineDead - (FileName: 'Case'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprCase - (FileName: 'FirstAid'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprFAid - (FileName: 'dynamite'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprDynamite - (FileName: 'Power'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprPower - (FileName: 'ClBomb'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprClusterBomb - (FileName: 'ClParticle'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprClusterParticle - (FileName: 'Flame'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprFlame - (FileName: 'horizont'; Path: ptCurrTheme;AltPath: ptNone; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: true; getImageDimensions: true),// sprHorizont - (FileName: 'horizontL'; Path: ptCurrTheme;AltPath: ptNone; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: true; getImageDimensions: true),// sprHorizont - (FileName: 'horizontR'; Path: ptCurrTheme;AltPath: ptNone; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: true; getImageDimensions: true),// sprHorizont - (FileName: 'Sky'; Path: ptCurrTheme;AltPath: ptNone; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: true; getImageDimensions: true),// sprSky - (FileName: 'SkyL'; Path: ptCurrTheme;AltPath: ptNone; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: true; getImageDimensions: true),// sprSky - (FileName: 'SkyR'; Path: ptCurrTheme;AltPath: ptNone; Texture: nil; Surface: nil; - Width: 0; Height: 0; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: true; getImageDimensions: true),// sprSky - (FileName: 'BorderHorizontal'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 33; Height: 2; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: true),// sprAMBorderHorizontal - (FileName: 'BorderVertical'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 2; Height: 33; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLow; getDimensions: false; getImageDimensions: true),// sprAMBorderVertical - (FileName: 'Slot'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 33; Height: 33; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAMSlot - (FileName: 'Ammos'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAMAmmos - (FileName: 'SlotKeys'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAMSlotKeys - (FileName: 'Corners'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 2; Height: 2; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAMCorners - (FileName: 'Finger'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprFinger - (FileName: 'AirBomb'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAirBomb - (FileName: 'Airplane'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 254; Height: 101; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAirplane - (FileName: 'amAirplane'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAmAirplane - (FileName: 'amGirder'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 160; Height:160; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAmGirder - (FileName: 'hhMask'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHHTelepMask - (FileName: 'Switch'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSwitch - (FileName: 'Parachute'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprParachute - (FileName: 'Target'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprTarget - (FileName: 'RopeNode'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 6; Height: 6; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprRopeNode - (FileName: 'thinking'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprQuestion - (FileName: 'PowerBar'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 256; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprPowerBar - (FileName: 'WindBar'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 151; Height: 17; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWindBar - (FileName: 'WindL'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 80; Height: 13; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWindL - (FileName: 'WindR'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 80; Height: 13; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWindR - (FileName: 'Flake'; Path:ptCurrTheme; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprFlake - (FileName: 'amRope'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandRope - (FileName: 'amBazooka'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandBazooka - (FileName: 'amShotgun'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandShotgun - (FileName: 'amDEagle'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandDEagle - (FileName:'amAirAttack'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandAirAttack - (FileName: 'amBaseball'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandBaseball - (FileName: 'Hammer'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprPHammer - (FileName: 'amBTorch_i'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandBlowTorch - (FileName: 'amBTorch_w'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBlowTorch - (FileName: 'Teleport'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprTeleport - (FileName: 'HHDeath'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprHHDeath - (FileName:'amShotgun_w'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprShotgun - (FileName: 'amDEagle_w'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprDEagle - (FileName: 'Idle'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprHHIdle - (FileName: 'Mortar'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprMortar - (FileName: 'TurnsLeft'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprTurnsLeft - (FileName: 'amKamikaze'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 256; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprKamikaze - (FileName: 'amWhip'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWhip - (FileName: 'Kowtow'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprKowtow - (FileName: 'Sad'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprSad - (FileName: 'Wave'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprWave - (FileName: 'Hurrah'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprHurrah - (FileName:'ILoveLemonade';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprLemonade - (FileName: 'Shrug'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprShrug - (FileName: 'Juggle'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprJuggle - (FileName: 'ExplPart'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprExplPart - (FileName: 'ExplPart2'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprExplPart2 - (FileName: 'Cake_walk'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprCakeWalk - (FileName: 'Cake_down'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprCakeDown - (FileName: 'Ammos_bw'; Path: ptAmmoMenu; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprAMAmmosBW - (FileName: 'Watermelon'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprWatermelon - (FileName: 'EvilTrace'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprEvilTrace - (FileName:'HellishBomb'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHellishBomb - (FileName: 'Seduction'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSeduction - (FileName: 'HHDress'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprDress - (FileName: 'Censored'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprCensored - (FileName: 'Drill'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprDrill - (FileName: 'amDrill'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandDrill - (FileName: 'amBallgun'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandBallgun - (FileName: 'Balls'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 20; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprBalls - (FileName: 'RCPlane'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprPlane - (FileName: 'amRCPlane'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandPlane - (FileName: 'Utility'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprUtility - (FileName:'Invulnerable';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprInvulnerable - (FileName: 'Vampiric'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprVampiric - (FileName: 'amGirder'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 512; Height:512; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprGirder - (FileName:'SpeechCorner';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 12; Height: 9; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprSpeechCorner - (FileName: 'SpeechEdge'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 25; Height: 9; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprSpeechEdge - (FileName: 'SpeechTail'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 25; Height: 26; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprSpeechTail - (FileName:'ThoughtCorner';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 49; Height: 37; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprThoughtCorner - (FileName:'ThoughtEdge'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 23; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprThoughtEdge - (FileName:'ThoughtTail'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 45; Height: 65; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprThoughtTail - (FileName:'ShoutCorner'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 34; Height: 23; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprShoutCorner - (FileName: 'ShoutEdge'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 30; Height: 20; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprShoutEdge - (FileName: 'ShoutTail'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 30; Height: 37; imageWidth: 0; imageHeight: 0; saveSurf: true; priority: tpLowest; getDimensions: false; getImageDimensions: true),// sprShoutTail - (FileName:'amSniperRifle';Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSniperRifle - (FileName: 'Bubbles'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprBubbles - (FileName: 'amJetpack'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprJetpack - (FileName: 'Health'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprHealth - (FileName: 'amMolotov'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),//sprHandMolotov - (FileName: 'Molotov'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprMolotov - (FileName: 'Smoke'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 22; Height: 22; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprSmoke - (FileName: 'SmokeWhite'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 22; Height: 22; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprSmokeWhite - (FileName: 'Shells'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpLow; getDimensions: false; getImageDimensions: true),// sprShell - (FileName: 'Dust'; Path: ptCurrTheme; AltPath: ptGraphics; Texture: nil; Surface: nil; - Width: 22; Height: 22; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprDust - (FileName: 'Explosives'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprExplosives - (FileName: 'ExplosivesRoll'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 48; Height: 48; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprExplosivesRoll - (FileName: 'amTeleport'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprAmTeleport - (FileName: 'Splash'; Path: ptCurrTheme; AltPath: ptGraphics; Texture: nil; Surface: nil; - Width: 80; Height: 50; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSplash - (FileName: 'Droplet'; Path: ptCurrTheme; AltPath: ptGraphics; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprDroplet - (FileName: 'Birdy'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 75; Height: 75; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBirdy - (FileName: 'amCake'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandCake - (FileName: 'amConstruction'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandConstruction - (FileName: 'amGrenade'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandGrenade - (FileName: 'amMelon'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandMelon - (FileName: 'amMortar'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandMortar - (FileName: 'amSkip'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandSkip - (FileName: 'amCluster'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandCluster - (FileName: 'amDynamite'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandDynamite - (FileName: 'amHellish'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandHellish - (FileName: 'amMine'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandMine - (FileName: 'amSeduction'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandSeduction - (FileName: 'amVamp'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandVamp - (FileName: 'BigExplosion'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 385; Height: 385; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprBigExplosion - (FileName: 'SmokeRing'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 200; Height: 200; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSmokeRing - (FileName: 'BeeTrace'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHigh; getDimensions: false; getImageDimensions: true),// sprBeeTrace - (FileName: 'Egg'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprEgg - (FileName: 'TargetBee'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprTargetBee - (FileName: 'amBee'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandBee - (FileName: 'Feather'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 15; Height: 25; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpHighest; getDimensions: false; getImageDimensions: true),// sprFeather - (FileName: 'Piano'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprPiano - (FileName: 'amSineGun'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandSineGun - (FileName: 'amPortalGun'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprPortalGun - (FileName: 'Portal'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprPortal - (FileName: 'cheese'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 16; Height: 16; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprCheese - (FileName: 'amCheese'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandCheese - (FileName: 'amFlamethrower'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 128; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandFlamethrower - (FileName: 'Chunk'; Path: ptCurrTheme; AltPath: ptGraphics; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprChunk - (FileName: 'Note'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 32; Height: 32; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprNote - (FileName: 'SMineOff'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSMineOff - (FileName: 'SMineOn'; Path: ptGraphics; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 8; Height: 8; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprSMineOn - (FileName: 'amSMine'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 64; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true),// sprHandSMine - (FileName: 'amHammer'; Path: ptHedgehog; AltPath: ptNone; Texture: nil; Surface: nil; - Width: 128; Height: 64; imageWidth: 0; imageHeight: 0; saveSurf: false; priority: tpMedium; getDimensions: false; getImageDimensions: true), // sprWhip - (FileName: 'amResurrector'; Path: ptHedgehog; AltPath: ptNone; - Texture: nil; Surface: nil; Width: 32; Height: 32; - imageWidth: 0; imageHeight: 0; saveSurf: false; priority: - tpMedium; getDimensions: false; getImageDimensions: true), - //sprHandResurrector - (FileName: 'Cross'; Path: ptGraphics; altPath: ptNone; - Texture: nil; Surface: nil; Width: 108; Height: 138; - imageWidth: 0; imageHeight: 0; saveSurf: false; priority: - tpMedium; getDimensions: false; getImageDimensions: true), - //sprCross - (FileName: 'AirDrill'; Path: ptGraphics; AltPath: ptNone; - Texture: nil; Surface: nil; Width: 16; Height: 16; - imageWidth: 0; imageHeight: 0; saveSurf: false; priority: - tpMedium; getDimensions: false; getImageDimensions: true), - // sprAirDrill - (FileName: 'NapalmBomb'; Path: ptGraphics; AltPath: ptNone; - Texture: nil; Surface: nil; Width: 16; Height: 16; - imageWidth: 0; imageHeight: 0; saveSurf: false; priority: - tpMedium; getDimensions: false; getImageDimensions: true), - // sprNapalmBomb - (FileName: 'BulletHit'; Path: ptGraphics; AltPath: ptNone; - Texture: nil; Surface: nil; Width: 32; Height: 32; - imageWidth: 0; imageHeight: 0; saveSurf: false; priority: - tpMedium; getDimensions: false; getImageDimensions: true) - // sprNapalmBomb - ); - - - Wavez: array [TWave] of record - Sprite: TSprite; - FramesCount: Longword; - Interval: Longword; - cmd: String[20]; - Voice: TSound; - VoiceDelay: LongWord; - end = ( - (Sprite: sprKowtow; FramesCount: 12; Interval: 125; cmd: '/rollup'; Voice: sndNone; VoiceDelay: 0), - (Sprite: sprSad; FramesCount: 14; Interval: 125; cmd: '/sad'; Voice: sndNone; VoiceDelay: 0), - (Sprite: sprWave; FramesCount: 16; Interval: 125; cmd: '/wave'; Voice: sndHello; VoiceDelay: 5), - (Sprite: sprHurrah; FramesCount: 14; Interval: 125; cmd: '/hurrah'; Voice: sndNone; VoiceDelay: 0), - (Sprite: sprLemonade; FramesCount: 24; Interval: 125; cmd: '/ilovelotsoflemonade'; Voice: sndNone; VoiceDelay: 0), - (Sprite: sprShrug; FramesCount: 24; Interval: 125; cmd: '/shrug'; Voice: sndNone; VoiceDelay: 0), - (Sprite: sprJuggle; FramesCount: 49; Interval: 38; cmd: '/juggle'; Voice: sndNone; VoiceDelay: 0) - ); - - Soundz: array[TSound] of record - FileName: String[25]; - Path : TPathType; - end = ( - (FileName: ''; Path: ptNone ),// sndNone - (FileName: 'grenadeimpact.ogg'; Path: ptSounds),// sndGrenadeImpact - (FileName: 'explosion.ogg'; Path: ptSounds),// sndExplosion - (FileName: 'throwpowerup.ogg'; Path: ptSounds),// sndThrowPowerUp - (FileName: 'throwrelease.ogg'; Path: ptSounds),// sndThrowRelease - (FileName: 'splash.ogg'; Path: ptSounds),// sndSplash - (FileName: 'shotgunreload.ogg'; Path: ptSounds),// sndShotgunReload - (FileName: 'shotgunfire.ogg'; Path: ptSounds),// sndShotgunFire - (FileName: 'graveimpact.ogg'; Path: ptSounds),// sndGraveImpact - (FileName: 'minetick.ogg'; Path: ptSounds),// sndMineTicks - (FileName: 'pickhammer.ogg'; Path: ptSounds),// sndPickhammer - (FileName: 'gun.ogg'; Path: ptSounds),// sndGun - (FileName: 'bee.ogg'; Path: ptSounds),// sndBee - (FileName: 'Jump1.ogg'; Path: ptVoices),// sndJump1 - (FileName: 'Jump2.ogg'; Path: ptVoices),// sndJump2 - (FileName: 'Jump3.ogg'; Path: ptVoices),// sndJump3 - (FileName: 'Yessir.ogg'; Path: ptVoices),// sndYesSir - (FileName: 'Laugh.ogg'; Path: ptVoices),// sndLaugh - (FileName: 'Illgetyou.ogg'; Path: ptVoices),// sndIllGetYou - (FileName: 'Incoming.ogg'; Path: ptVoices),// sndIncoming - (FileName: 'Missed.ogg'; Path: ptVoices),// sndMissed - (FileName: 'Stupid.ogg'; Path: ptVoices),// sndStupid - (FileName: 'Firstblood.ogg'; Path: ptVoices),// sndFirstBlood - (FileName: 'Boring.ogg'; Path: ptVoices),// sndBoring - (FileName: 'Byebye.ogg'; Path: ptVoices),// sndByeBye - (FileName: 'Sameteam.ogg'; Path: ptVoices),// sndSameTeam - (FileName: 'Nutter.ogg'; Path: ptVoices),// sndNutter - (FileName: 'Reinforcements.ogg'; Path: ptVoices),// sndReinforce - (FileName: 'Traitor.ogg'; Path: ptVoices),// sndTraitor - (FileName: 'Youllregretthat.ogg'; Path: ptVoices),// sndRegret - (FileName: 'Enemydown.ogg'; Path: ptVoices),// sndEnemyDown - (FileName: 'Coward.ogg'; Path: ptVoices),// sndCoward - (FileName: 'Hurry.ogg'; Path: ptVoices),// sndHurry - (FileName: 'Watchit.ogg'; Path: ptVoices),// sndWatchIt - (FileName: 'Kamikaze.ogg'; Path: ptVoices),// sndKamikaze - (FileName: 'cake2.ogg'; Path: ptSounds),// sndCake - (FileName: 'Ow1.ogg'; Path: ptVoices),// sndOw1 - (FileName: 'Ow2.ogg'; Path: ptVoices),// sndOw2 - (FileName: 'Ow3.ogg'; Path: ptVoices),// sndOw3 - (FileName: 'Ow4.ogg'; Path: ptVoices),// sndOw4 - (FileName: 'Firepunch1.ogg'; Path: ptVoices),// sndFirepunch1 - (FileName: 'Firepunch2.ogg'; Path: ptVoices),// sndFirepunch2 - (FileName: 'Firepunch3.ogg'; Path: ptVoices),// sndFirepunch3 - (FileName: 'Firepunch4.ogg'; Path: ptVoices),// sndFirepunch4 - (FileName: 'Firepunch5.ogg'; Path: ptVoices),// sndFirepunch5 - (FileName: 'Firepunch6.ogg'; Path: ptVoices),// sndFirepunch6 - (FileName: 'Melon.ogg'; Path: ptVoices),// sndMelon - (FileName: 'Hellish.ogg'; Path: ptSounds),// sndHellish - (FileName: 'Yoohoo.ogg'; Path: ptSounds),// sndYoohoo - (FileName: 'rcplane.ogg'; Path: ptSounds),// sndRCPlane - (FileName: 'whipcrack.ogg'; Path: ptSounds),// sndWhipCrack - (FileName:'ride_of_the_valkyries.ogg'; Path: ptSounds),// sndRideOfTheValkyries - (FileName: 'denied.ogg'; Path: ptSounds),// sndDenied - (FileName: 'placed.ogg'; Path: ptSounds),// sndPlaced - (FileName: 'baseballbat.ogg'; Path: ptSounds),// sndBaseballBat - (FileName: 'steam.ogg'; Path: ptSounds),// sndVaporize - (FileName: 'warp.ogg'; Path: ptSounds),// sndWarp - (FileName: 'suddendeath.ogg'; Path: ptSounds),// sndSuddenDeath - (FileName: 'mortar.ogg'; Path: ptSounds),// sndMortar - (FileName: 'shutterclick.ogg'; Path: ptSounds),// sndShutter - (FileName: 'homerun.ogg'; Path: ptSounds),// sndHomerun - (FileName: 'molotov.ogg'; Path: ptSounds),// sndMolotov - (FileName: 'Takecover.ogg'; Path: ptVoices),// sndCover - (FileName: 'Uh-oh.ogg'; Path: ptVoices),// sndUhOh - (FileName: 'Oops.ogg'; Path: ptVoices),// sndOops - (FileName: 'Nooo.ogg'; Path: ptVoices),// sndNooo - (FileName: 'Hello.ogg'; Path: ptVoices),// sndHello - (FileName: 'ropeshot.ogg'; Path: ptSounds),// sndRopeShot - (FileName: 'ropeattach.ogg'; Path: ptSounds),// sndRopeAttach - (FileName: 'roperelease.ogg'; Path: ptSounds),// sndRopeRelease - (FileName: 'switchhog.ogg'; Path: ptSounds),// sndSwitchHog - (FileName: 'victory.ogg'; Path: ptVoices),// sndVictory - (FileName: 'sniperreload.ogg'; Path: ptSounds),// sndSniperReload - (FileName: 'steps.ogg'; Path: ptSounds),// sndSteps - (FileName: 'lowgravity.ogg'; Path: ptSounds),// sndLowGravity - (FileName: 'hell_growl.ogg'; Path: ptSounds),// sndHellishImpact1 - (FileName: 'hell_ooff.ogg'; Path: ptSounds),// sndHellishImpact2 - (FileName: 'hell_ow.ogg'; Path: ptSounds),// sndHellishImpact3 - (FileName: 'hell_ugh.ogg'; Path: ptSounds),// sndHellishImpact4 - (FileName: 'melonimpact.ogg'; Path: ptSounds),// sndMelonImpact - (FileName: 'Droplet1.ogg'; Path: ptSounds),// sndDroplet1 - (FileName: 'Droplet2.ogg'; Path: ptSounds),// sndDroplet2 - (FileName: 'Droplet3.ogg'; Path: ptSounds),// sndDroplet3 - (FileName: 'egg.ogg'; Path: ptSounds),// sndEggBreak - (FileName: 'drillgun.ogg'; Path: ptSounds),// sndDrillRocket - (FileName: 'PoisonCough.ogg'; Path: ptVoices),// sndPoisonCough - (FileName: 'PoisonMoan.ogg'; Path: ptVoices),// sndPoisonMoan - (FileName: 'BirdyLay.ogg'; Path: ptSounds),// sndBirdyLay - (FileName: 'Whistle.ogg'; Path: ptSounds),// sndWhistle - (FileName: 'beewater.ogg'; Path: ptSounds),// sndBeeWater - (FileName: '1C.ogg'; Path: ptSounds),// sndPiano0 - (FileName: '2D.ogg'; Path: ptSounds),// sndPiano1 - (FileName: '3E.ogg'; Path: ptSounds),// sndPiano2 - (FileName: '4F.ogg'; Path: ptSounds),// sndPiano3 - (FileName: '5G.ogg'; Path: ptSounds),// sndPiano4 - (FileName: '6A.ogg'; Path: ptSounds),// sndPiano5 - (FileName: '7B.ogg'; Path: ptSounds),// sndPiano6 - (FileName: '8C.ogg'; Path: ptSounds),// sndPiano7 - (FileName: '9D.ogg'; Path: ptSounds),// sndPiano8 - (FileName: 'skip.ogg'; Path: ptSounds),// sndSkip - (FileName: 'shotgunfire.ogg'; Path: ptSounds),// sndSineGun - (FileName: 'Ooff1.ogg'; Path: ptVoices),// sndOoff1 - (FileName: 'Ooff2.ogg'; Path: ptVoices),// sndOoff2 - (FileName: 'Ooff3.ogg'; Path: ptVoices),// sndOoff3 - (FileName: 'whipcrack.ogg'; Path: ptSounds),// sndWhack - (FileName: 'Comeonthen.ogg'; Path: ptVoices),// sndComeonthen - (FileName: 'parachute.ogg'; Path: ptSounds),// sndParachute - (FileName: 'bump.ogg'; Path: ptSounds),// sndBump - (FileName: 'hogchant3.ogg'; Path: ptSounds) // sndResurrector - ); - - Ammoz: array [TAmmoType] of record - NameId: TAmmoStrId; - NameTex: PTexture; - Probability, NumberInCase: Longword; - Ammo: TAmmo; - Slot: 0..cMaxSlotIndex; - TimeAfterTurn: Longword; - minAngle, maxAngle: Longword; - isDamaging: boolean; - SkipTurns: Longword; - PosCount: Longword; - PosSprite: TSprite; - ejectX, ejectY: Longint; - end = ( - (NameId: sidNothing; - NameTex: nil; - Probability: 0; - NumberInCase: 0; - Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold or ammoprop_Effect; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amNothing; - AttackVoice: sndNone); - Slot: 0; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 9999; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Grenade - (NameId: sidGrenade; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 3000; - Pos: 0; - AmmoType: amGrenade; - AttackVoice: sndCover); - Slot: 1; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// ClusterBomb - (NameId: sidClusterBomb; - NameTex: nil; - Probability: 100; - NumberInCase: 3; - Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse; - Count: 5; - NumPerTurn: 0; - Timer: 3000; - Pos: 0; - AmmoType: amClusterBomb; - AttackVoice: sndCover); - Slot: 1; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Bazooka - (NameId: sidBazooka; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Power or ammoprop_AltUse; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amBazooka; - AttackVoice: sndNone); - Slot: 0; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //20; - ejectY: -6), - -// Bee - (NameId: sidBee; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Power or ammoprop_NeedTarget or ammoprop_DontHold; - Count: 2; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amBee; - AttackVoice: sndNone); - Slot: 0; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //16; - ejectY: 0), - -// Shotgun - (NameId: sidShotgun; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs; - Count: AMMO_INFINITE; - NumPerTurn: 1; - Timer: 0; - Pos: 0; - AmmoType: amShotgun; - AttackVoice: sndNone); - Slot: 2; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //26; - ejectY: -6), - -// PickHammer - (NameId: sidPickHammer; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_AttackInMove or ammoprop_NoCrosshair or ammoprop_DontHold; - Count: 2; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amPickHammer; - AttackVoice: sndNone); - Slot: 6; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Skip - (NameId: sidSkip; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_DontHold; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amSkip; - AttackVoice: sndNone); - Slot: 9; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Rope - (NameId: sidRope; - NameTex: nil; - Probability: 100; - NumberInCase: 3; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_ForwMsgs or - ammoprop_AttackInMove or - ammoprop_Utility or - ammoprop_AltAttack; - Count: 5; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amRope; - AttackVoice: sndNone); - Slot: 7; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: cMaxAngle div 2; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Mine - (NameId: sidMine; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_AttackInMove or ammoprop_DontHold or ammoprop_AltUse; - Count: 2; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amMine; - AttackVoice: sndLaugh); - Slot: 4; - TimeAfterTurn: 5000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// DEagle - (NameId: sidDEagle; - NameTex: nil; - Probability: 20; - NumberInCase: 2; - Ammo: (Propz: 0; - Count: 3; - NumPerTurn: 3; - Timer: 0; - Pos: 0; - AmmoType: amDEagle; - AttackVoice: sndNone); - Slot: 2; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //23; - ejectY: -6), - -// Dynamite - (NameId: sidDynamite; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_AttackInMove or ammoprop_DontHold or ammoprop_AltUse; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amDynamite; - AttackVoice: sndLaugh); - Slot: 4; - TimeAfterTurn: 5000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// FirePunch - (NameId: sidFirePunch; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or ammoprop_ForwMsgs or ammoprop_AttackInMove; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amFirePunch; - AttackVoice: sndNone); - Slot: 3; - TimeAfterTurn: 3000; - MinAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Whip - (NameId: sidWhip; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amWhip; - AttackVoice: sndNone); - Slot: 3; - TimeAfterTurn: 3000; - MinAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// BaseballBat - (NameId: sidBaseballBat; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_DontHold; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amBaseballBat; - AttackVoice: sndNone); - Slot: 3; - TimeAfterTurn: 5000; - minAngle: 0; - maxAngle: cMaxAngle div 2; - isDamaging: true; - SkipTurns: 2; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Parachute - (NameId: sidParachute; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_ForwMsgs or - ammoprop_AttackInMove or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_Utility or - ammoprop_AltAttack; - Count: 2; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amParachute; - AttackVoice: sndNone); - Slot: 7; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// AirAttack - (NameId: sidAirAttack; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_AttackingPut or - ammoprop_DontHold or - ammoprop_NotBorder; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amAirAttack; - AttackVoice: sndIncoming); - Slot: 5; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 5; - PosCount: 2; - PosSprite: sprAmAirplane; - ejectX: 0; - ejectY: 0), - -// MineStrike - (NameId: sidMineStrike; - NameTex: nil; - Probability: 200; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_AttackingPut or - ammoprop_DontHold or - ammoprop_NotBorder; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amMineStrike; - AttackVoice: sndIncoming); - Slot: 5; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 5; - PosCount: 2; - PosSprite: sprAmAirplane; - ejectX: 0; - ejectY: 0), - -// BlowTorch - (NameId: sidBlowTorch; - NameTex: nil; - Probability: 100; - NumberInCase: 2; - Ammo: (Propz: ammoprop_ForwMsgs; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amBlowTorch; - AttackVoice: sndNone); - Slot: 6; - TimeAfterTurn: 3000; - minAngle: 768; - maxAngle: 1280; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Girder - (NameId: sidGirder; - NameTex: nil; - Probability: 150; - NumberInCase: 3; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_Utility or - ammoprop_AttackingPut; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amGirder; - AttackVoice: sndNone); - Slot: 6; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 8; - PosSprite: sprAmGirder; - ejectX: 0; - ejectY: 0), - -// Teleport - (NameId: sidTeleport; - NameTex: nil; - Probability: 200; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or - ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_AttackingPut or - ammoprop_Utility or - ammoprop_DontHold; - Count: 2; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amTeleport; - AttackVoice: sndNone); - Slot: 7; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 2; - PosSprite: sprAmTeleport; - ejectX: 0; - ejectY: 0), - -// Switch - (NameId: sidSwitch; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_ForwMsgs or - ammoprop_NoCrosshair or - ammoprop_Utility or - ammoprop_DontHold; - Count: 3; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amSwitch; - AttackVoice: sndNone); - Slot: 9; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Mortar - (NameId: sidMortar; - NameTex: nil; - Probability: 100; - NumberInCase: 4; - Ammo: (Propz: 0; - Count: 4; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amMortar; - AttackVoice: sndNone); - Slot: 0; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //20; - ejectY: -6), - -// Kamikaze - (NameId: sidKamikaze; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_DontHold or ammoprop_AttackInMove; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amKamikaze; - AttackVoice: sndNone); - Slot: 3; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Cake - (NameId: sidCake; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_NoCrosshair or ammoprop_DontHold; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amCake; - AttackVoice: sndLaugh); - Slot: 4; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 4; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Seduction - (NameId: sidSeduction; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_DontHold; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amSeduction; - AttackVoice: sndNone); - Slot: 3; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Watermelon - (NameId: sidWatermelon; - NameTex: nil; - Probability: 400; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse; - Count: 0; - NumPerTurn: 0; - Timer: 3000; - Pos: 0; - AmmoType: amWatermelon; - AttackVoice: sndMelon); - Slot: 1; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// HellishBomb ("Hellish Hand-Grenade") - (NameId: sidHellishBomb; - NameTex: nil; - Probability: 400; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Power or ammoprop_AltUse; - Count: 0; - NumPerTurn: 0; - Timer: 5000; - Pos: 0; - AmmoType: amHellishBomb; - AttackVoice: sndNone); - Slot: 1; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Napalm - (NameId: sidNapalm; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_AttackingPut or - ammoprop_DontHold or - ammoprop_NotBorder; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amNapalm; - AttackVoice: sndIncoming); - Slot: 5; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 7; - PosCount: 2; - PosSprite: sprAmAirplane; - ejectX: 0; - ejectY: 0), - -// Drill ("Drill Rocket") - (NameId: sidDrill; - NameTex: nil; - Probability: 300; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Power or ammoprop_AltUse; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amDrill; - AttackVoice: sndNone); - Slot: 0; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprDrill; - ejectX: 0; //20; - ejectY: -6), - -// Ballgun - (NameId: sidBallgun; - NameTex: nil; - Probability: 400; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_DontHold; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 5001; - Pos: 0; - AmmoType: amBallgun; - AttackVoice: sndNone); - Slot: 4; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //20; - ejectY: -3), - -// RC-Plane - (NameId: sidRCPlane; - NameTex: nil; - Probability: 200; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs{ or - ammoprop_DontHold or - ammoprop_AltAttack}; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amRCPlane; - AttackVoice: sndNone); - Slot: 4; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 4; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// LowGravity - (NameId: sidLowGravity; - NameTex: nil; - Probability: 20; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_AltUse or - ammoprop_Utility or - ammoprop_Effect; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amLowGravity; - AttackVoice: sndNone); - Slot: 9; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// ExtraDamage - (NameId: sidExtraDamage; - NameTex: nil; - Probability: 15; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_AltUse or - ammoprop_Utility or - ammoprop_Effect; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amExtraDamage; - AttackVoice: sndNone); - Slot: 9; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Invulnerable - (NameId: sidInvulnerable; - NameTex: nil; - Probability: 20; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_AltUse or - ammoprop_Utility or - ammoprop_Effect; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amInvulnerable; - AttackVoice: sndNone); - Slot: 8; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// ExtraTime - (NameId: sidExtraTime; - NameTex: nil; - Probability: 30; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_AltUse or - ammoprop_Utility or - ammoprop_Effect; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amExtraTime; - AttackVoice: sndNone); - Slot: 9; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// LaserSight - (NameId: sidLaserSight; - NameTex: nil; - Probability: 15; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_AltUse or - ammoprop_Utility or - ammoprop_Effect; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amLaserSight; - AttackVoice: sndNone); - Slot: 8; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Vampiric - (NameId: sidVampiric; - NameTex: nil; - Probability: 15; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_AltUse or - ammoprop_Utility or - ammoprop_Effect; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amVampiric; - AttackVoice: sndNone); - Slot: 8; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// SniperRifle - (NameId: sidSniperRifle; - NameTex: nil; - Probability: 20; - NumberInCase: 2; - Ammo: (Propz: 0; - Count: 2; - NumPerTurn: 1; - Timer: 0; - Pos: 0; - AmmoType: amSniperRifle; - AttackVoice: sndNone); - Slot: 2; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //40; - ejectY: -5), - -// Jetpack ("Flying Saucer") - (NameId: sidJetpack; - NameTex: nil; - Probability: 20; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_ForwMsgs or - ammoprop_AttackInMove or - ammoprop_NoCrosshair or - ammoprop_DontHold or - ammoprop_Utility or - ammoprop_AltAttack; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amJetpack; - AttackVoice: sndNone); - Slot: 7; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Molotov - (NameId: sidMolotov; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Power or ammoprop_AltUse; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 3000; - Pos: 0; - AmmoType: amMolotov; - AttackVoice: sndNone); - Slot: 1; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Birdy - (NameId: sidBirdy; - NameTex: nil; - Probability: 20; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or - ammoprop_NoCrosshair or - ammoprop_DontHold; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amBirdy; - AttackVoice: sndNone); - Slot: 7; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// PortalGun - (NameId: sidPortalGun; - NameTex: nil; - Probability: 20; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoRoundEnd or - ammoprop_AttackInMove or - ammoprop_DontHold or - ammoprop_Utility; - Count: 1; - NumPerTurn: 3; - Timer: 0; - Pos: 0; - AmmoType: amPortalGun; - AttackVoice: sndNone); - Slot: 6; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: false; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: -5; //29; - ejectY: -7), - -// Piano - (NameId: sidPiano; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_AttackingPut or - ammoprop_DontHold or - ammoprop_NotBorder; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amPiano; - AttackVoice: sndIncoming); - Slot: 5; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 7; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// GasBomb - (NameId: sidGasBomb; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Timerable or ammoprop_Power or ammoprop_AltUse; - Count: AMMO_INFINITE; - NumPerTurn: 0; - Timer: 3000; - Pos: 0; - AmmoType: amGasBomb; - AttackVoice: sndCover); - Slot: 1; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// SineGun - (NameId: sidSineGun; - NameTex: nil; - Probability: 20; - NumberInCase: 2; - Ammo: (Propz: ammoprop_AttackInMove; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amSineGun; - AttackVoice: sndNone); - Slot: 2; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Flamethrower - (NameId: sidFlamethrower; - NameTex: nil; - Probability: 20; - NumberInCase: 1; - Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_DontHold; - Count: 1; - NumPerTurn: 0; - Timer: 5001; - Pos: 0; - AmmoType: amFlamethrower; - AttackVoice: sndNone); - Slot: 2; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; //20; - ejectY: -3), - -// Sticky Mine - (NameId: sidSMine; - NameTex: nil; - Probability: 100; - NumberInCase: 1; - Ammo: (Propz: ammoprop_Power; //FIXME: enable multishoot at altuse, until then removed ammoprop_AltUse - Count: 1; - NumPerTurn: 1; - Timer: 0; - Pos: 0; - AmmoType: amSMine; - AttackVoice: sndLaugh); - Slot: 4; - TimeAfterTurn: 5000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Hammer - (NameId: sidHammer; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amHammer; - AttackVoice: sndNone); - Slot: 3; - TimeAfterTurn: 1000; - MinAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// Ressurrector - (NameId: sidResurrector; - NameTex: nil; - Probability: 0; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or - ammoprop_Utility or - ammoprop_NoRoundEnd; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amResurrector; - AttackVoice: sndNone); - Slot: 8; - TimeAfterTurn: 3000; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 0; - PosCount: 1; - PosSprite: sprWater; - ejectX: 0; - ejectY: 0), - -// DrillStrike - (NameId: sidDrillStrike; - NameTex: nil; - Probability: 200; - NumberInCase: 1; - Ammo: (Propz: ammoprop_NoCrosshair or - ammoprop_NeedTarget or - ammoprop_AttackingPut or - ammoprop_DontHold or - ammoprop_NotBorder; - Count: 1; - NumPerTurn: 0; - Timer: 0; - Pos: 0; - AmmoType: amDrillStrike; - AttackVoice: sndIncoming); - Slot: 5; - TimeAfterTurn: 0; - minAngle: 0; - maxAngle: 0; - isDamaging: true; - SkipTurns: 6; - PosCount: 2; - PosSprite: sprAmAirplane; - ejectX: 0; - ejectY: 0) - ); - - - - conversionFormat: TSDL_PixelFormat = ( - palette: nil; - BitsPerPixel : 32; - BytesPerPixel: 4; - Rloss : 0; - Gloss : 0; - Bloss : 0; - Aloss : 0; -{$IFDEF ENDIAN_LITTLE} - Rshift: 0; - Gshift: 8; - Bshift: 16; - Ashift: 24; -{$ELSE} - Rshift: 24; - Gshift: 16; - Bshift: 8; - Ashift: 0; -{$ENDIF} - RMask : RMask; - GMask : GMask; - BMask : BMask; - AMask : AMask; - colorkey: 0; - alpha : 255 - ); implementation diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uDebug.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uDebug.pas Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,35 @@ +{$INCLUDE "options.inc"} + +unit uDebug; + +interface + +procedure OutError(Msg: shortstring; isFatalError: boolean); +procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean); inline; +procedure SDLTry(Assert: boolean; isFatal: boolean); + +implementation +uses SDLh, uConsole, uCommands; + +procedure OutError(Msg: shortstring; isFatalError: boolean); +begin +WriteLnToConsole(Msg); +if isFatalError then + begin + ParseCommand('fatal ' + GetLastConsoleLine, true); + SDL_Quit; + halt(1) + end +end; + +procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean); +begin +if not Assert then OutError(Msg, isFatal) +end; + +procedure SDLTry(Assert: boolean; isFatal: boolean); +begin +if not Assert then OutError(SDL_GetError, isFatal) +end; + +end. \ No newline at end of file diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uFloat.pas --- a/hedgewars/uFloat.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uFloat.pas Tue Jan 04 12:53:46 2011 +0100 @@ -62,6 +62,7 @@ function AngleSin(const Angle: Longword): hwFloat; function AngleCos(const Angle: Longword): hwFloat; function SignAs(const num, signum: hwFloat): hwFloat; inline; +function hwSign(r: hwFloat): LongInt; inline; {$IFDEF FPC} {$J-} @@ -147,7 +148,7 @@ {$ENDIF} implementation -//uses uMisc; +uses uSinTable; {$IFDEF FPC} @@ -342,7 +343,12 @@ SignAs.isNegative:= signum.isNegative end; -{$INCLUDE "SinTable.inc"} +function hwSign(r: hwFloat): LongInt; +begin +// yes, we have negative zero for a reason +if r.isNegative then hwSign:= -1 else hwSign:= 1 +end; + function AngleSin(const Angle: Longword): hwFloat; begin diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uGame.pas --- a/hedgewars/uGame.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uGame.pas Tue Jan 04 12:53:46 2011 +0100 @@ -26,7 +26,7 @@ //////////////////// implementation //////////////////// -uses uMisc, uConsts, uKeys, uTeams, uIO, uAI, uGears, uScript, uSound, uMobile, uVisualGears; +uses uKeys, uTeams, uIO, uAI, uGears, uSound, uMobile, uVisualGears, uTypes, uVariables; procedure DoGameTick(Lag: LongInt); var i: LongInt; @@ -45,7 +45,6 @@ i:= 1; while (GameState <> gsExit) and (i <= Lag) do begin - ScriptCall('onGameTick'); if not CurrentTeam^.ExtDriven then begin if CurrentHedgehog^.BotLevel <> 0 then ProcessBot; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uGears.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,63 +20,7 @@ unit uGears; interface -uses SDLh, uConsts, uFloat, Math; - - -type - PGear = ^TGear; - TGearStepProcedure = procedure (Gear: PGear); - TGear = record - NextGear, PrevGear: PGear; - Active: Boolean; - AdvBounce: Longword; - Invulnerable: Boolean; - RenderTimer: Boolean; - AmmoType : TAmmoType; - State : Longword; - X : hwFloat; - Y : hwFloat; - dX: hwFloat; - dY: hwFloat; - Kind: TGearType; - Pos: Longword; - doStep: TGearStepProcedure; - Radius: LongInt; - Angle, Power : Longword; - DirAngle: real; - Timer : LongWord; - Elasticity: hwFloat; - Friction : hwFloat; - Message, MsgParam : Longword; - Hedgehog: pointer; - Health, Damage, Karma: LongInt; - CollisionIndex: LongInt; - Tag: LongInt; - Tex: PTexture; - Z: Longword; - IntersectGear: PGear; - FlightTime: Longword; - uid: Longword; - ImpactSound: TSound; // first sound, others have to be after it in the sounds def. - nImpactSounds: Word; // count of ImpactSounds - SoundChannel: LongInt; - PortalCounter: LongWord // Hopefully temporary, but avoids infinite portal loops in a guaranteed fashion. - end; - TPGearArray = Array of PGear; - -var AllInactive: boolean; - PrvInactive: boolean; - CurAmmoGear: PGear; - GearsList: PGear; - KilledHHs: Longword; - SuddenDeathDmg: Boolean; - SpeechType: Longword; - SpeechText: shortstring; - TrainingTargetGear: PGear; - skipFlag: boolean; - PlacingHogs: boolean; // a convenience flag to indicate placement of hogs is still in progress - StepSoundTimer: LongInt; - StepSoundChannel: LongInt; +uses SDLh, uConsts, uFloat, uTypes; procedure initModule; procedure freeModule; @@ -96,27 +40,16 @@ procedure InsertGearToList(Gear: PGear); procedure RemoveGearFromList(Gear: PGear); function ModifyDamage(dmg: Longword; Gear: PGear): Longword; -procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); -function GetLaunchX(at: TAmmoType; dir: LongInt; angle: LongInt): LongInt; -function GetLaunchY(at: TAmmoType; angle: LongInt): LongInt; +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean = false); +procedure DeleteGear(Gear: PGear); + implementation -uses uWorld, uMisc, uStore, uConsole, uSound, uTeams, uRandom, uCollisions, uLand, uIO, uLandGraphics, - uAIMisc, uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uMobile; +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, uLandTexture; -const MAXROPEPOINTS = 384; -var RopePoints: record - Count: Longword; - HookAngle: GLfloat; - ar: array[0..MAXROPEPOINTS] of record - X, Y: hwFloat; - dLen: hwFloat; - b: boolean; - end; - rounded: array[0..MAXROPEPOINTS + 2] of TVertex2f; - end; -procedure DeleteGear(Gear: PGear); forward; procedure doMakeExplosion(X, Y, Radius: LongInt; Mask: LongWord); forward; procedure doMakeExplosion(X, Y, Radius: LongInt; Mask, Tint: LongWord); forward; procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward; @@ -133,22 +66,6 @@ procedure HHSetWeapon(Gear: PGear); forward; procedure doStepCase(Gear: PGear); forward; -function GetLaunchX(at: TAmmoType; dir: LongInt; angle: LongInt): LongInt; -begin - if (Ammoz[at].ejectX <> 0) or (Ammoz[at].ejectY <> 0) then - GetLaunchX:= sign(dir) * (8 + hwRound(AngleSin(angle) * Ammoz[at].ejectX) + hwRound(AngleCos(angle) * Ammoz[at].ejectY)) - else - GetLaunchX:= 0 -end; - -function GetLaunchY(at: TAmmoType; angle: LongInt): LongInt; -begin - if (Ammoz[at].ejectX <> 0) or (Ammoz[at].ejectY <> 0) then - GetLaunchY:= hwRound(AngleSin(angle) * Ammoz[at].ejectY) - hwRound(AngleCos(angle) * Ammoz[at].ejectX) - 2 - else - GetLaunchY:= 0 -end; - {$INCLUDE "GSHandlers.inc"} {$INCLUDE "HHHandlers.inc"} @@ -210,7 +127,9 @@ @doStepHammer, @doStepHammerHit, @doStepResurrector, - @doStepNapalmBomb + @doStepNapalmBomb, + @doStepSnowball, + @doStepSnowflake ); procedure InsertGearToList(Gear: PGear); @@ -253,7 +172,7 @@ begin tag:= AddVisualGear(hwRound(HHGear^.X), hwRound(HHGear^.Y), vgtHealthTag, dmg); if (tag <> nil) then - tag^.Hedgehog:= PHedgehog(HHGear^.Hedgehog); // the tag needs the tag to determine the text color + tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color AllInactive:= false; HHGear^.Active:= true; end; @@ -302,6 +221,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; @@ -312,22 +232,49 @@ 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 PHedgehog(gear^.Hedgehog)^.BotLevel > 0 then - PHedgehog(gear^.Hedgehog)^.Effects[heResurrectable] := true; + if gear^.Hedgehog^.BotLevel > 0 then + gear^.Hedgehog^.Effects[heResurrectable] := true; 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; @@ -356,7 +303,7 @@ end; gtRope: begin gear^.Radius:= 3; - gear^.Friction:= _450; + gear^.Friction:= _450 * _0_01 * cRopePercent; RopePoints.Count:= 0; end; gtMine: begin @@ -365,10 +312,11 @@ 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 - gear^.Timer:= cMinesTime*1000; + gear^.Timer:= cMinesTime; end; gtSMine: begin gear^.Health:= 10; @@ -376,6 +324,7 @@ gear^.Radius:= 2; gear^.Elasticity:= _0_55; gear^.Friction:= _0_995; + gear^.Density:= _0_9; gear^.Timer:= 500; end; gtCase: begin @@ -390,6 +339,7 @@ gear^.Radius:= 16; gear^.Elasticity:= _0_4; gear^.Friction:= _0_995; + gear^.Density:= _6; gear^.Health:= cBarrelHealth end; gtDEagleShot: begin @@ -404,10 +354,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; @@ -415,6 +367,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; @@ -427,6 +380,7 @@ end; gtAirBomb: begin gear^.Radius:= 5; + gear^.Density:= _2; end; gtBlowTorch: begin gear^.Radius:= cHHRadius + cBlowTorchC; @@ -445,7 +399,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; @@ -468,12 +423,14 @@ 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 + gear^.Radius:= 4; + gear^.Density:= _1; end; gtBall: begin gear^.ImpactSound:= sndGrenadeImpact; @@ -484,6 +441,7 @@ gear^.Timer:= 5000; gear^.Elasticity:= _0_7; gear^.Friction:= _0_995; + gear^.Density:= _1_5; end; gtBallgun: begin gear^.Timer:= 5001; @@ -499,6 +457,7 @@ end; gtMolotov: begin gear^.Radius:= 6; + gear^.Density:= _2; end; gtBirdy: begin gear^.Radius:= 16; // todo: check @@ -510,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 @@ -517,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; @@ -549,6 +511,7 @@ gtNapalmBomb: begin gear^.Timer:= 1000; gear^.Radius:= 5; + gear^.Density:= _1_5; end; end; @@ -594,17 +557,17 @@ 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) end; - team:= PHedgehog(Gear^.Hedgehog)^.Team; + team:= Gear^.Hedgehog^.Team; if CurrentHedgehog^.Gear = Gear then FreeActionsList; // to avoid ThinkThread on drawned gear - PHedgehog(Gear^.Hedgehog)^.Gear:= nil; - if PHedgehog(Gear^.Hedgehog)^.King then + Gear^.Hedgehog^.Gear:= nil; + if Gear^.Hedgehog^.King then begin // are there any other kings left? Just doing nil check. Presumably a mortally wounded king will get reaped soon enough k:= false; @@ -618,7 +581,14 @@ end end; inc(KilledHHs); - RecountTeamHealth(team) + RecountTeamHealth(team); + if (CurrentHedgehog <> nil) and CurrentHedgehog^.Effects[heResurrectable] and not Gear^.Hedgehog^.Effects[heResurrectable] then + with CurrentHedgehog^ do + begin + inc(Team^.stats.AIKills); + if Team^.AIKillsTex <> nil then FreeTexture(Team^.AIKillsTex); + 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)); @@ -626,6 +596,7 @@ if CurAmmoGear = Gear then CurAmmoGear:= nil; if FollowGear = Gear then FollowGear:= nil; +if lastGearByUID = Gear then lastGearByUID := nil; RemoveGearFromList(Gear); Dispose(Gear) end; @@ -655,17 +626,17 @@ else dec(Gear^.Health, dmg); - if (PHedgehog(Gear^.Hedgehog)^.Team = CurrentTeam) and + if (Gear^.Hedgehog^.Team = CurrentTeam) and (Gear^.Damage <> Gear^.Karma) and - not PHedgehog(Gear^.Hedgehog)^.King and - not PHedgehog(Gear^.Hedgehog)^.Effects[hePoisoned] and + not Gear^.Hedgehog^.King and + not Gear^.Hedgehog^.Effects[hePoisoned] and not SuddenDeathDmg then Gear^.State:= Gear^.State or gstLoser; spawnHealthTagForHH(Gear, dmg); - RenderHealth(PHedgehog(Gear^.Hedgehog)^); - RecountTeamHealth(PHedgehog(Gear^.Hedgehog)^.Team); + RenderHealth(Gear^.Hedgehog^); + RecountTeamHealth(Gear^.Hedgehog^.Team); end; if (not isInMultiShoot) then Gear^.Karma:= 0; @@ -689,20 +660,20 @@ if Gear^.Kind = gtHedgehog then begin tmp:= 0; - if PHedgehog(Gear^.Hedgehog)^.Effects[hePoisoned] then + if Gear^.Hedgehog^.Effects[hePoisoned] then begin inc(tmp, ModifyDamage(5, Gear)); - if (GameFlags and gfResetHealth) <> 0 then dec(PHedgehog(Gear^.Hedgehog)^.InitialHealth) // does not need a minimum check since <= 1 basically disables it + if (GameFlags and gfResetHealth) <> 0 then dec(Gear^.Hedgehog^.InitialHealth) // does not need a minimum check since <= 1 basically disables it end; if (TotalRounds > cSuddenDTurns - 1) then begin inc(tmp, cHealthDecrease); - if (GameFlags and gfResetHealth) <> 0 then dec(PHedgehog(Gear^.Hedgehog)^.InitialHealth, cHealthDecrease) + if (GameFlags and gfResetHealth) <> 0 then dec(Gear^.Hedgehog^.InitialHealth, cHealthDecrease) end; - if PHedgehog(Gear^.Hedgehog)^.King then + if Gear^.Hedgehog^.King then begin flag:= false; - team:= PHedgehog(Gear^.Hedgehog)^.Team; + team:= Gear^.Hedgehog^.Team; for i:= 0 to Pred(team^.HedgehogsNumber) do if (team^.Hedgehogs[i].Gear <> nil) and (not team^.Hedgehogs[i].King) and @@ -711,7 +682,7 @@ if not flag then begin inc(tmp, 5); - if (GameFlags and gfResetHealth) <> 0 then dec(PHedgehog(Gear^.Hedgehog)^.InitialHealth, 5) + if (GameFlags and gfResetHealth) <> 0 then dec(Gear^.Hedgehog^.InitialHealth, 5) end end; if tmp > 0 then @@ -764,7 +735,7 @@ end; Gear^.doStep(Gear); // might be useful later - //ScriptCall('OnGearStep', Gear^.uid); + //ScriptCall('onGearStep', Gear^.uid); end end; @@ -822,11 +793,19 @@ 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; + end; AddCaption(trmsg[sidSuddenDeath], cWhiteColor, capgrpGameState); - playSound(sndSuddenDeath) + playSound(sndSuddenDeath); + MusicFN:= SDMusic; + ChangeMusic end else if (TotalRounds < cSuddenDTurns) and not isInMultiShoot then begin @@ -939,6 +918,7 @@ inc(hiTicks) // we do not recieve a message for this end; +ScriptCall('onGameTick'); inc(GameTicks) end; @@ -951,7 +931,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; @@ -969,11 +952,13 @@ for i:= 0 to cMaxHHIndex do with Hedgehogs[i] do begin +(* if (SpeechGear <> nil) then begin DeleteVisualGear(SpeechGear); // remove to restore persisting beyond end of turn. Tiy says was too much of a gameplay issue SpeechGear:= nil end; +*) if (Gear <> nil) then begin @@ -985,15 +970,15 @@ while t <> nil do begin t^.PortalCounter:= 0; - if ((GameFlags and gfResetHealth) <> 0) and (t^.Kind = gtHedgehog) and (t^.Health < PHedgehog(t^.Hedgehog)^.InitialHealth) then + if ((GameFlags and gfResetHealth) <> 0) and (t^.Kind = gtHedgehog) and (t^.Health < t^.Hedgehog^.InitialHealth) then begin - t^.Health:= PHedgehog(t^.Hedgehog)^.InitialHealth; - RenderHealth(PHedgehog(t^.Hedgehog)^); + t^.Health:= t^.Hedgehog^.InitialHealth; + RenderHealth(t^.Hedgehog^); end; t:= t^.NextGear end; - if (GameFlags and gfResetWeps) <> 0 then + if ((GameFlags and gfResetWeps) <> 0) and not PlacingHogs then ResetWeapons; if (GameFlags and gfResetHealth) <> 0 then @@ -1009,7 +994,7 @@ if (Gear^.Kind = gtHedgehog) and (Damage>=1) then begin HHHurt(Gear^.Hedgehog, Source); - AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, PHedgehog(Gear^.Hedgehog)^.Team^.Clan^.Color); + AddDamageTag(hwRound(Gear^.X), hwRound(Gear^.Y), Damage, Gear^.Hedgehog^.Team^.Clan^.Color); tmpDmg:= min(Damage, max(0,Gear^.Health-Gear^.Damage)); if (Gear <> CurrentHedgehog^.Gear) and (CurrentHedgehog^.Gear <> nil) and (tmpDmg >= 1) then begin @@ -1045,7 +1030,7 @@ end; end; inc(Gear^.Damage, Damage); - ScriptCall('OnGearDamage', Gear^.UID, Damage); + ScriptCall('onGearDamage', Gear^.UID, Damage); end; procedure SetAllToActive; @@ -1072,151 +1057,21 @@ end end; -procedure DrawAltWeapon(Gear: PGear; sx, sy: LongInt); + +procedure DrawGears; +var Gear: PGear; + x, y: LongInt; begin -with PHedgehog(Gear^.Hedgehog)^ do +Gear:= GearsList; +while Gear <> nil do begin - if not (((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and ((Gear^.State and gstAttacked) = 0)) then - exit; - DrawTexture(sx + 16, sy + 16, ropeIconTex); - DrawTextureF(SpritesData[sprAMAmmos].Texture, 0.75, sx + 30, sy + 30, ord(CurAmmoType) - 1, 1, 32, 32); + x:= hwRound(Gear^.X) + WorldDx; + y:= hwRound(Gear^.Y) + WorldDy; + RenderGear(Gear, x, y); + Gear:= Gear^.NextGear end; end; -procedure DrawRopeLinesRQ(Gear: PGear); -begin -with RopePoints do - begin - rounded[Count].X:= hwRound(Gear^.X); - rounded[Count].Y:= hwRound(Gear^.Y); - rounded[Count + 1].X:= hwRound(PHedgehog(Gear^.Hedgehog)^.Gear^.X); - rounded[Count + 1].Y:= hwRound(PHedgehog(Gear^.Hedgehog)^.Gear^.Y); - end; - -if (RopePoints.Count > 0) or (Gear^.Elasticity.QWordValue > 0) then - begin - glDisable(GL_TEXTURE_2D); - //glEnable(GL_LINE_SMOOTH); - - glPushMatrix; - - glTranslatef(WorldDx, WorldDy, 0); - - glLineWidth(4.0); - - Tint($C0, $C0, $C0, $FF); - - glVertexPointer(2, GL_FLOAT, 0, @RopePoints.rounded[0]); - glDrawArrays(GL_LINE_STRIP, 0, RopePoints.Count + 2); - Tint($FF, $FF, $FF, $FF); - - glPopMatrix; - - glEnable(GL_TEXTURE_2D); - //glDisable(GL_LINE_SMOOTH) - end -end; - -procedure DrawRope(Gear: PGear); -var roplen: LongInt; - i: Longword; - - procedure DrawRopeLine(X1, Y1, X2, Y2: LongInt); - var eX, eY, dX, dY: LongInt; - i, sX, sY, x, y, d: LongInt; - b: boolean; - begin - if (X1 = X2) and (Y1 = Y2) then - begin - //OutError('WARNING: zero length rope line!', false); - exit - end; - eX:= 0; - eY:= 0; - dX:= X2 - X1; - dY:= Y2 - Y1; - - if (dX > 0) then sX:= 1 - else - if (dX < 0) then - begin - sX:= -1; - dX:= -dX - end else sX:= dX; - - if (dY > 0) then sY:= 1 - else - if (dY < 0) then - begin - sY:= -1; - dY:= -dY - end else sY:= dY; - - if (dX > dY) then d:= dX - else d:= dY; - - x:= X1; - y:= Y1; - - for i:= 0 to d do - begin - inc(eX, dX); - inc(eY, dY); - b:= false; - if (eX > d) then - begin - dec(eX, d); - inc(x, sX); - b:= true - end; - if (eY > d) then - begin - dec(eY, d); - inc(y, sY); - b:= true - end; - if b then - begin - inc(roplen); - if (roplen mod 4) = 0 then DrawSprite(sprRopeNode, x - 2, y - 2, 0) - end - end - end; -begin - if (cReducedQuality and rqSimpleRope) <> 0 then - DrawRopeLinesRQ(Gear) - else - begin - roplen:= 0; - if RopePoints.Count > 0 then - begin - i:= 0; - while i < Pred(RopePoints.Count) do - begin - DrawRopeLine(hwRound(RopePoints.ar[i].X) + WorldDx, hwRound(RopePoints.ar[i].Y) + WorldDy, - hwRound(RopePoints.ar[Succ(i)].X) + WorldDx, hwRound(RopePoints.ar[Succ(i)].Y) + WorldDy); - inc(i) - end; - DrawRopeLine(hwRound(RopePoints.ar[i].X) + WorldDx, hwRound(RopePoints.ar[i].Y) + WorldDy, - hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy); - DrawRopeLine(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, - hwRound(PHedgehog(Gear^.Hedgehog)^.Gear^.X) + WorldDx, hwRound(PHedgehog(Gear^.Hedgehog)^.Gear^.Y) + WorldDy); - end else - if Gear^.Elasticity.QWordValue > 0 then - DrawRopeLine(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, - hwRound(PHedgehog(Gear^.Hedgehog)^.Gear^.X) + WorldDx, hwRound(PHedgehog(Gear^.Hedgehog)^.Gear^.Y) + WorldDy); - end; - - -if RopePoints.Count > 0 then - DrawRotated(sprRopeHook, hwRound(RopePoints.ar[0].X) + WorldDx, hwRound(RopePoints.ar[0].Y) + WorldDy, 1, RopePoints.HookAngle) - else - if Gear^.Elasticity.QWordValue > 0 then - DrawRotated(sprRopeHook, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); -end; - -{$INCLUDE "GearDrawing.inc"} - procedure FreeGearsList; var t, tt: PGear; begin @@ -1236,12 +1091,6 @@ 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 begin Gear:= AddGear(0, 0, gtMine, 0, _0, _0, 0); @@ -1254,7 +1103,10 @@ end; if (GameFlags and gfLowGravity) <> 0 then + begin cGravity:= cMaxWindSpeed; + cGravityf:= 0.00025 + end; if (GameFlags and gfVampiric) <> 0 then cVampiric:= true; @@ -1271,7 +1123,14 @@ 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); @@ -1349,7 +1208,7 @@ if Gear^.Kind <> gtFlame then FollowGear:= Gear end; if ((Mask and EXPLPoisoned) <> 0) and (Gear^.Kind = gtHedgehog) then - PHedgehog(Gear^.Hedgehog)^.Effects[hePoisoned] := true; + Gear^.Hedgehog^.Effects[hePoisoned] := true; end; end; @@ -1448,13 +1307,10 @@ 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; @@ -1473,7 +1329,7 @@ if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then ApplyDamage(Gear, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch DeleteCI(Gear); - if (Gear^.Kind = gtHedgehog) and PHedgehog(Gear^.Hedgehog)^.King then + if (Gear^.Kind = gtHedgehog) and Gear^.Hedgehog^.King then begin Gear^.dX:= Ammo^.dX * Power * _0_005; Gear^.dY:= Ammo^.dY * Power * _0_005 @@ -1663,17 +1519,20 @@ gear^.State := gstWait; uStats.HedgehogDamaged(gear); gear^.Damage := 0; - gear^.Health := 100; - with CurrentHedgehog^ do begin - inc(Team^.stats.AIKills); - if Team^.AIKillsTex <> nil then FreeTexture(Team^.AIKillsTex); - Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16); - end; - tempTeam := PHedgehog(gear^.Hedgehog)^.Team; + gear^.Health := gear^.Hedgehog^.InitialHealth; + gear^.Hedgehog^.Effects[hePoisoned] := false; + if not CurrentHedgehog^.Effects[heResurrectable] then + with CurrentHedgehog^ do + begin + inc(Team^.stats.AIKills); + if Team^.AIKillsTex <> nil then FreeTexture(Team^.AIKillsTex); + Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16); + end; + tempTeam := gear^.Hedgehog^.Team; DeleteCI(gear); - FindPlace(gear, false, 0, LAND_WIDTH); + FindPlace(gear, false, 0, LAND_WIDTH, true); if gear <> nil then begin - RenderHealth(PHedgehog(gear^.Hedgehog)^); + RenderHealth(gear^.Hedgehog^); ScriptCall('onGearResurrect', gear^.uid); end; RecountTeamHealth(tempTeam); @@ -1801,7 +1660,7 @@ end end; -procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean = false); function CountNonZeroz(x, y, r, c: LongInt): LongInt; var i: LongInt; @@ -1823,57 +1682,66 @@ ar2: array[0..1023] of TPoint; cnt, cnt2: Longword; delta: LongInt; + reallySkip, tryAgain: boolean; begin -delta:= 250; -cnt2:= 0; -repeat - x:= Left + LongInt(GetRandom(Delta)); +reallySkip:= false; // try not skipping proximity at first +tryAgain:= true; +while tryAgain do + begin + delta:= 250; + cnt2:= 0; repeat - inc(x, Delta); - cnt:= 0; - y:= min(1024, topY) - 2 * Gear^.Radius; - while y < cWaterLine do - begin - repeat - inc(y, 2); - until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) = 0); + x:= Left + LongInt(GetRandom(Delta)); + repeat + inc(x, Delta); + cnt:= 0; + y:= min(1024, topY) - 2 * Gear^.Radius; + while y < cWaterLine do + begin + repeat + inc(y, 2); + until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) = 0); - sy:= y; + sy:= y; - repeat - inc(y); - until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) <> 0); + repeat + inc(y); + until (y >= cWaterLine) or (CountNonZeroz(x, y, Gear^.Radius - 1, 1) <> 0); - if (y - sy > Gear^.Radius * 2) and - (((Gear^.Kind = gtExplosives) - and (y < cWaterLine) - and (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 60, 60) = nil) - and (CountNonZeroz(x, y+1, Gear^.Radius - 1, Gear^.Radius+1) > Gear^.Radius)) - or - ((Gear^.Kind <> gtExplosives) - and (y < cWaterLine) - and (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 110, 110) = nil))) then - begin - ar[cnt].X:= x; - if withFall then ar[cnt].Y:= sy + Gear^.Radius - else ar[cnt].Y:= y - Gear^.Radius; - inc(cnt) + if (y - sy > Gear^.Radius * 2) and + (((Gear^.Kind = gtExplosives) + and (y < cWaterLine) + and (reallySkip or (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 60, 60) = nil)) + and (CountNonZeroz(x, y+1, Gear^.Radius - 1, Gear^.Radius+1) > Gear^.Radius)) + or + ((Gear^.Kind <> gtExplosives) + and (y < cWaterLine) + and (reallySkip or (CheckGearsNear(x, y - Gear^.Radius, [gtFlame, gtHedgehog, gtMine, gtCase, gtExplosives], 110, 110) = nil)))) then + begin + ar[cnt].X:= x; + if withFall then ar[cnt].Y:= sy + Gear^.Radius + else ar[cnt].Y:= y - Gear^.Radius; + inc(cnt) + end; + + inc(y, 45) end; - inc(y, 45) - end; + if cnt > 0 then + with ar[GetRandom(cnt)] do + begin + ar2[cnt2].x:= x; + ar2[cnt2].y:= y; + inc(cnt2) + end + until (x + Delta > Right); - if cnt > 0 then - with ar[GetRandom(cnt)] do - begin - ar2[cnt2].x:= x; - ar2[cnt2].y:= y; - inc(cnt2) - end - until (x + Delta > Right); - - dec(Delta, 60) -until (cnt2 > 0) or (Delta < 70); + dec(Delta, 60) + until (cnt2 > 0) or (Delta < 70); + if (cnt2 = 0) and skipProximity and not reallySkip then tryAgain:= true + else tryAgain:= false; + reallySkip:= true; + end; if cnt2 > 0 then with ar2[GetRandom(cnt2)] do @@ -1887,7 +1755,7 @@ else begin OutError('Can''t find place for Gear', false); - if Gear^.Kind = gtHedgehog then PHedgehog(Gear^.Hedgehog)^.Effects[heResurrectable] := false; + if Gear^.Kind = gtHedgehog then Gear^.Hedgehog^.Effects[heResurrectable] := false; DeleteGear(Gear); Gear:= nil end @@ -1902,7 +1770,7 @@ *) i:= _1; if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then i:= _1_5; -if (Gear^.Hedgehog <> nil) and (PHedgehog(Gear^.Hedgehog)^.King) then +if (Gear^.Hedgehog <> nil) and (Gear^.Hedgehog^.King) then ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent * _0_5) else ModifyDamage:= hwRound(_0_01 * cDamageModifier * dmg * i * cDamagePercent) @@ -1912,26 +1780,114 @@ 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 end; + +procedure chSkip(var s: shortstring); +begin +s:= s; // avoid compiler hint +if not CurrentTeam^.ExtDriven then SendIPC(','); +uStats.Skipped; +skipFlag:= true +end; + +procedure chHogSay(var s: shortstring); +var Gear: PVisualGear; + text: shortstring; + hh: PHedgehog; + i, x, t, h: byte; + c, j: LongInt; +begin + hh:= nil; + i:= 0; + t:= 0; + x:= byte(s[1]); // speech type + if x < 4 then + begin + t:= byte(s[2]); // team + if Length(s) > 2 then h:= byte(s[3]) // target hog + end; + // allow targetting a hog by specifying a number as the first portion of the text + if (x < 4) and (h > byte('0')) and (h < byte('9')) then i:= h - 48; + if i <> 0 then text:= copy(s, 4, Length(s) - 1) + else if x < 4 then text:= copy(s, 3, Length(s) - 1) + else text:= copy(s, 2, Length(s) - 1); + + (* + if CheckNoTeamOrHH then + begin + ParseCommand('say ' + text, true); + exit + end; + *) + + if (x < 4) and (TeamsArray[t] <> nil) then + begin + // if team matches current hedgehog team, default to current hedgehog + 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 + j:= 0; + c:= 0; + while (j <= cMaxHHIndex) and (hh = nil) do + begin + if (TeamsArray[t]^.Hedgehogs[j].Gear <> nil) then + begin + inc(c); + if (i=0) or (i=c) then + hh:= @TeamsArray[t]^.Hedgehogs[j] + end; + inc(j) + end + end; + if hh <> nil then + begin + 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) + end + else if (x >= 4) then + begin + SpeechType:= x-3; + SpeechText:= text + end; +end; + procedure initModule; begin + RegisterVariable('skip', vtCommand, @chSkip, false); + RegisterVariable('hogsay', vtCommand, @chHogSay, true ); + CurAmmoGear:= nil; GearsList:= nil; KilledHHs:= 0; + SuddenDeath:= false; SuddenDeathDmg:= false; SpeechType:= 1; - TrainingTargetGear:= nil; skipFlag:= false; AllInactive:= false; diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uGearsRender.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uGearsRender.pas Tue Jan 04 12:53:46 2011 +0100 @@ -0,0 +1,1032 @@ +{$INCLUDE "options.inc"} +unit uGearsRender; + +interface +uses uTypes, uConsts, GLunit, uFloat; + +procedure RenderGear(Gear: PGear; x, y: LongInt); + +var RopePoints: record + Count: Longword; + HookAngle: GLfloat; + ar: array[0..MAXROPEPOINTS] of record + X, Y: hwFloat; + dLen: hwFloat; + b: boolean; + end; + rounded: array[0..MAXROPEPOINTS + 2] of TVertex2f; + end; + +implementation +uses uRender, uUtils, uVariables, uAmmos, Math; + +procedure DrawRopeLinesRQ(Gear: PGear); +begin +with RopePoints do + begin + rounded[Count].X:= hwRound(Gear^.X); + rounded[Count].Y:= hwRound(Gear^.Y); + rounded[Count + 1].X:= hwRound(Gear^.Hedgehog^.Gear^.X); + rounded[Count + 1].Y:= hwRound(Gear^.Hedgehog^.Gear^.Y); + end; + +if (RopePoints.Count > 0) or (Gear^.Elasticity.QWordValue > 0) then + begin + glDisable(GL_TEXTURE_2D); + //glEnable(GL_LINE_SMOOTH); + + glPushMatrix; + + glTranslatef(WorldDx, WorldDy, 0); + + glLineWidth(4.0); + + Tint($C0, $C0, $C0, $FF); + + glVertexPointer(2, GL_FLOAT, 0, @RopePoints.rounded[0]); + glDrawArrays(GL_LINE_STRIP, 0, RopePoints.Count + 2); + Tint($FF, $FF, $FF, $FF); + + glPopMatrix; + + glEnable(GL_TEXTURE_2D); + //glDisable(GL_LINE_SMOOTH) + end +end; + + +procedure DrawRope(Gear: PGear); +var roplen: LongInt; + i: Longword; + + procedure DrawRopeLine(X1, Y1, X2, Y2: LongInt); + var eX, eY, dX, dY: LongInt; + i, sX, sY, x, y, d: LongInt; + b: boolean; + begin + if (X1 = X2) and (Y1 = Y2) then + begin + //OutError('WARNING: zero length rope line!', false); + exit + end; + eX:= 0; + eY:= 0; + dX:= X2 - X1; + dY:= Y2 - Y1; + + if (dX > 0) then sX:= 1 + else + if (dX < 0) then + begin + sX:= -1; + dX:= -dX + end else sX:= dX; + + if (dY > 0) then sY:= 1 + else + if (dY < 0) then + begin + sY:= -1; + dY:= -dY + end else sY:= dY; + + if (dX > dY) then d:= dX + else d:= dY; + + x:= X1; + y:= Y1; + + for i:= 0 to d do + begin + inc(eX, dX); + inc(eY, dY); + b:= false; + if (eX > d) then + begin + dec(eX, d); + inc(x, sX); + b:= true + end; + if (eY > d) then + begin + dec(eY, d); + inc(y, sY); + b:= true + end; + if b then + begin + inc(roplen); + if (roplen mod 4) = 0 then DrawSprite(sprRopeNode, x - 2, y - 2, 0) + end + end + end; +begin + if (cReducedQuality and rqSimpleRope) <> 0 then + DrawRopeLinesRQ(Gear) + else + begin + roplen:= 0; + if RopePoints.Count > 0 then + begin + i:= 0; + while i < Pred(RopePoints.Count) do + begin + DrawRopeLine(hwRound(RopePoints.ar[i].X) + WorldDx, hwRound(RopePoints.ar[i].Y) + WorldDy, + hwRound(RopePoints.ar[Succ(i)].X) + WorldDx, hwRound(RopePoints.ar[Succ(i)].Y) + WorldDy); + inc(i) + end; + DrawRopeLine(hwRound(RopePoints.ar[i].X) + WorldDx, hwRound(RopePoints.ar[i].Y) + WorldDy, + hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy); + DrawRopeLine(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, + hwRound(Gear^.Hedgehog^.Gear^.X) + WorldDx, hwRound(Gear^.Hedgehog^.Gear^.Y) + WorldDy); + end else + if Gear^.Elasticity.QWordValue > 0 then + DrawRopeLine(hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, + hwRound(Gear^.Hedgehog^.Gear^.X) + WorldDx, hwRound(Gear^.Hedgehog^.Gear^.Y) + WorldDy); + end; + + +if RopePoints.Count > 0 then + DrawRotated(sprRopeHook, hwRound(RopePoints.ar[0].X) + WorldDx, hwRound(RopePoints.ar[0].Y) + WorldDy, 1, RopePoints.HookAngle) + else + if Gear^.Elasticity.QWordValue > 0 then + DrawRotated(sprRopeHook, hwRound(Gear^.X) + WorldDx, hwRound(Gear^.Y) + WorldDy, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); +end; + + +procedure DrawAltWeapon(Gear: PGear; sx, sy: LongInt); +begin +with Gear^.Hedgehog^ do + begin + if not (((Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AltUse) <> 0) and ((Gear^.State and gstAttacked) = 0)) then + exit; + DrawTexture(sx + 16, sy + 16, ropeIconTex); + DrawTextureF(SpritesData[sprAMAmmos].Texture, 0.75, sx + 30, sy + 30, ord(CurAmmoType) - 1, 1, 32, 32); + end; +end; + + +procedure DrawHH(Gear: PGear; ox, oy: LongInt); +var i, t: LongInt; + amt: TAmmoType; + sign, hx, hy, cx, cy, tx, ty, sx, sy, m: LongInt; // hedgehog, crosshair, temp, sprite, direction + dx, dy, ax, ay, aAngle, dAngle, hAngle, lx, ly: real; // laser, change + defaultPos, HatVisible: boolean; + HH: PHedgehog; + CurWeapon: PAmmo; +begin + HH:= Gear^.Hedgehog; + if HH^.Unplaced then exit; + m:= 1; + if ((Gear^.State and gstHHHJump) <> 0) and not cArtillery then m:= -1; + sx:= ox + 1; // this offset is very common + sy:= oy - 3; + sign:= hwSign(Gear^.dX); + + if (Gear^.State and gstHHDeath) <> 0 then + begin + DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos); + Tint(HH^.Team^.Clan^.Color shl 8 or $FF); + DrawSprite(sprHHDeath, ox - 16, oy - 26, Gear^.Pos + 8); + Tint($FF, $FF, $FF, $FF); + exit + end + else if (Gear^.State and gstHHGone) <> 0 then + begin + DrawRotatedF(sprTeleport, sx, sy, Gear^.Pos, sign, 0); + exit + end; + + defaultPos:= true; + HatVisible:= false; + + + if HH^.Effects[hePoisoned] then + begin + Tint($00, $FF, $40, $40); + DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 2, 0, 0, sx, sy, 0, 1, 22, 22, (RealTicks shr 36) mod 360); + Tint($FF, $FF, $FF, $FF) + end; + + if ((Gear^.State and gstWinner) <> 0) and + ((CurAmmoGear = nil) or (CurAmmoGear^.Kind <> gtPickHammer)) then + begin + DrawHedgehog(sx, sy, + sign, + 2, + 0, + 0); + defaultPos:= false + end; + if (Gear^.State and gstDrowning) <> 0 then + begin + DrawHedgehog(sx, sy, + sign, + 1, + 7, + 0); + defaultPos:= false + end else + if (Gear^.State and gstLoser) <> 0 then + begin + DrawHedgehog(sx, sy, + sign, + 2, + 3, + 0); + defaultPos:= false + end else + + if (Gear^.State and gstHHDriven) <> 0 then + begin + if ((Gear^.State and gstHHThinking) = 0) and + (ShowCrosshair or ((CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope))) and + ((Gear^.State and (gstAttacked or gstAnimation)) = 0) then + begin + (* These calculations are a little complex for a few reasons: + 1: I need to draw the laser from weapon origin to nearest land + 2: I need to start the beam outside the hedgie for attractiveness. + 3: I need to extend the beam beyond land. + This routine perhaps should be pushed into uStore or somesuch instead of continuuing the increase in size of this function. + *) + dx:= sign * m * Sin(Gear^.Angle * pi / cMaxAngle); + dy:= -Cos(Gear^.Angle * pi / cMaxAngle); + if cLaserSighting then + begin + lx:= GetLaunchX(HH^.CurAmmoType, sign * m, Gear^.Angle); + ly:= GetLaunchY(HH^.CurAmmoType, Gear^.Angle); + + // ensure we start outside the hedgehog (he's solid after all) + while abs(lx * lx + ly * ly) < (Gear^.radius * Gear^.radius) do + begin + lx:= lx + dx; + ly:= ly + dy + end; + + // add hog's position + lx:= lx + ox - WorldDx; + ly:= ly + oy - WorldDy; + + // decrease number of iterations required + ax:= dx * 4; + ay:= dy * 4; + + tx:= round(lx); + ty:= round(ly); + hx:= tx; + hy:= ty; + while ((ty and LAND_HEIGHT_MASK) = 0) and + ((tx and LAND_WIDTH_MASK) = 0) and + (Land[ty, tx] = 0) do // TODO: check for constant variable instead + begin + lx:= lx + ax; + ly:= ly + ay; + tx:= round(lx); + ty:= round(ly) + end; + // reached edge of land. assume infinite beam. Extend it way out past camera + if ((ty and LAND_HEIGHT_MASK) <> 0) or ((tx and LAND_WIDTH_MASK) <> 0) then + begin + tx:= round(lx + ax * (LAND_WIDTH div 4)); + ty:= round(ly + ay * (LAND_WIDTH div 4)); + end; + + //if (abs(lx-tx)>8) or (abs(ly-ty)>8) then + begin + DrawLine(hx, hy, tx, ty, 1.0, $FF, $00, $00, $C0); + end; + end; + // draw crosshair + cx:= Round(hwRound(Gear^.X) + dx * 80 + GetLaunchX(HH^.CurAmmoType, sign * m, Gear^.Angle)); + cy:= Round(hwRound(Gear^.Y) + dy * 80 + GetLaunchY(HH^.CurAmmoType, Gear^.Angle)); + DrawRotatedTex(HH^.Team^.CrosshairTex, + 12, 12, cx + WorldDx, cy + WorldDy, 0, + sign * (Gear^.Angle * 180.0) / cMaxAngle); + end; + hx:= ox + 8 * sign; + hy:= oy - 2; + aangle:= Gear^.Angle * 180 / cMaxAngle - 90; + if CurAmmoGear <> nil then + begin + case CurAmmoGear^.Kind of + gtShotgunShot: begin + if (CurAmmoGear^.State and gstAnimation <> 0) then + DrawRotated(sprShotgun, hx, hy, sign, aangle) + else + DrawRotated(sprHandShotgun, hx, hy, sign, aangle); + end; + gtDEagleShot: DrawRotated(sprDEagle, hx, hy, sign, aangle); + gtSniperRifleShot: begin + if (CurAmmoGear^.State and gstAnimation <> 0) then + DrawRotatedF(sprSniperRifle, hx, hy, 1, sign, aangle) + else + DrawRotatedF(sprSniperRifle, hx, hy, 0, sign, aangle) + end; + gtBallgun: DrawRotated(sprHandBallgun, hx, hy, sign, aangle); + gtRCPlane: begin + DrawRotated(sprHandPlane, hx, hy, sign, 0); + defaultPos:= false + end; + gtRope: begin + if Gear^.X < CurAmmoGear^.X then + begin + dAngle:= 0; + hAngle:= 180; + i:= 1 + end else + begin + dAngle:= 180; + hAngle:= 0; + i:= -1 + end; + if ((Gear^.State and gstWinner) = 0) then + begin + DrawHedgehog(ox, oy, + i, + 1, + 0, + DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + dAngle); + with HH^ do + if (HatTex <> nil) then + begin + DrawRotatedTextureF(HatTex, 1.0, -1.0, -6.0, ox, oy, 0, i, 32, 32, + i*DxDy2Angle(CurAmmoGear^.dY, CurAmmoGear^.dX) + hAngle); + if HatTex^.w > 64 then + begin + 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) + end + end + end; + DrawAltWeapon(Gear, ox, oy); + defaultPos:= false + end; + gtBlowTorch: begin + DrawRotated(sprBlowTorch, hx, hy, sign, aangle); + DrawHedgehog(sx, sy, + sign, + 3, + HH^.visStepPos div 2, + 0); + with HH^ do + if (HatTex <> nil) then + begin + DrawTextureF(HatTex, + 1, + sx, + sy - 5, + 0, + sign, + 32, + 32); + if HatTex^.w > 64 then + begin + Tint(HH^.Team^.Clan^.Color shl 8 or $FF); + DrawTextureF(HatTex, + 1, + sx, + sy - 5, + 32, + sign, + 32, + 32); + Tint($FF, $FF, $FF, $FF) + end + end; + defaultPos:= false + end; + gtShover: DrawRotated(sprHandBaseball, hx, hy, sign, aangle + 180); + gtFirePunch: begin + DrawHedgehog(sx, sy, + sign, + 1, + 4, + 0); + defaultPos:= false + end; + gtPickHammer: begin + defaultPos:= false; + dec(sy,20); + end; + gtTeleport: defaultPos:= false; + gtWhip: begin + DrawRotatedF(sprWhip, + sx, + sy, + 1, + sign, + 0); + defaultPos:= false + end; + gtHammer: begin + DrawRotatedF(sprHammer, + sx, + sy, + 1, + sign, + 0); + defaultPos:= false + end; + gtResurrector: begin + DrawRotated(sprHandResurrector, sx, sy, 0, 0); + defaultPos:= false + end; + gtKamikaze: begin + if CurAmmoGear^.Pos = 0 then + DrawHedgehog(sx, sy, + sign, + 1, + 6, + 0) + else + DrawRotatedF(sprKamikaze, + ox, oy, + CurAmmoGear^.Pos - 1, + sign, + aangle); + defaultPos:= false + end; + gtSeduction: begin + if CurAmmoGear^.Pos >= 6 then + DrawHedgehog(sx, sy, + sign, + 2, + 2, + 0) + else + begin + DrawRotatedF(sprDress, + ox, oy, + CurAmmoGear^.Pos, + sign, + 0); + DrawSprite(sprCensored, ox - 32, oy - 20, 0) + end; + defaultPos:= false + end; + gtFlamethrower: begin + DrawRotatedF(sprHandFlamethrower, hx, hy, (RealTicks div 125) mod 4, sign, aangle); + if CurAmmoGear^.Tex <> nil then DrawCentered(sx, sy - 40, CurAmmoGear^.Tex) + end; + end; + + case CurAmmoGear^.Kind of + gtShotgunShot, + gtDEagleShot, + gtSniperRifleShot, + gtShover: begin + DrawHedgehog(sx, sy, + sign, + 0, + 4, + 0); + defaultPos:= false; + HatVisible:= true + end + end + end else + + if ((Gear^.State and gstHHJumping) <> 0) then + begin + DrawHedgehog(sx, sy, + sign*m, + 1, + 1, + 0); + HatVisible:= true; + defaultPos:= false + end else + + if (Gear^.Message and (gmLeft or gmRight) <> 0) and (not isCursorVisible) then + begin + DrawHedgehog(sx, sy, + sign, + 0, + HH^.visStepPos div 2, + 0); + defaultPos:= false; + HatVisible:= true + end + else + + if ((Gear^.State and gstAnimation) <> 0) then + begin + if (TWave(Gear^.Tag) < Low(TWave)) or (TWave(Gear^.Tag) > High(TWave)) then + begin + Gear^.State:= Gear^.State and not gstAnimation; + end + else + begin + DrawRotatedF(Wavez[TWave(Gear^.Tag)].Sprite, + sx, + sy, + Gear^.Pos, + sign, + 0.0); + defaultPos:= false + end + end + else + if ((Gear^.State and gstAttacked) = 0) then + begin + if HH^.Timer > 0 then + begin + // There must be a tidier way to do this. Anyone? + if aangle <= 90 then aangle:= aangle+360; + if Gear^.dX > _0 then aangle:= aangle-((aangle-240)*HH^.Timer/10) + else aangle:= aangle+((240-aangle)*HH^.Timer/10); + dec(HH^.Timer) + end; + amt:= CurrentHedgehog^.CurAmmoType; + 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); + amDrill: DrawRotated(sprHandDrill, hx, hy, sign, aangle); + amRope: DrawRotated(sprHandRope, hx, hy, sign, aangle); + amShotgun: DrawRotated(sprHandShotgun, hx, hy, sign, aangle); + amDEagle: DrawRotated(sprHandDEagle, hx, hy, sign, aangle); + amSineGun: DrawRotated(sprHandShotgun, hx, hy, sign, aangle); + 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^.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); + amGrenade: DrawRotated(sprHandGrenade, hx, hy, sign, aangle); + amWatermelon: DrawRotated(sprHandMelon, hx, hy, sign, aangle); + amSkip: DrawRotated(sprHandSkip, hx, hy, sign, aangle); + amClusterBomb: DrawRotated(sprHandCluster, hx, hy, sign, aangle); + amDynamite: DrawRotated(sprHandDynamite, hx, hy, sign, aangle); + amHellishBomb: DrawRotated(sprHandHellish, hx, hy, sign, aangle); + amGasBomb: DrawRotated(sprHandCheese, hx, hy, sign, aangle); + amMine: DrawRotated(sprHandMine, hx, hy, sign, aangle); + amSMine: DrawRotated(sprHandSMine, hx, hy, sign, aangle); + amSeduction: DrawRotated(sprHandSeduction, hx, hy, sign, aangle); + amVampiric: DrawRotatedF(sprHandVamp, hx, hy, (RealTicks div 125) mod 4, sign, aangle); + amRCPlane: begin + DrawRotated(sprHandPlane, hx, hy, sign, 0); + defaultPos:= false + end; + amGirder: begin + DrawRotated(sprHandConstruction, hx, hy, sign, aangle); + DrawSpriteClipped(sprGirder, + ox-256, + oy-256, + LongInt(topY)+WorldDy, + LongInt(rightX)+WorldDx, + cWaterLine+WorldDy, + LongInt(leftX)+WorldDx) + end; + amBee: DrawRotatedF(sprHandBee, hx, hy, (RealTicks div 125) mod 4, sign, aangle); + amFlamethrower: DrawRotatedF(sprHandFlamethrower, hx, hy, (RealTicks div 125) mod 4, sign, aangle); + amResurrector: DrawCircle(ox, oy, 98, 4, $F5, $DB, $35, $AA); // I'd rather not like to hardcode 100 here + end; + + case amt of + amAirAttack, + amMineStrike, + amDrillStrike: DrawRotated(sprHandAirAttack, sx, oy, sign, 0); + amPickHammer: DrawHedgehog(sx, sy, + sign, + 1, + 2, + 0); + amTeleport: DrawRotatedF(sprTeleport, sx, sy, 0, sign, 0); + amKamikaze: DrawHedgehog(sx, sy, + sign, + 1, + 5, + 0); + amWhip: DrawRotatedF(sprWhip, + sx, + sy, + 0, + sign, + 0); + amHammer: DrawRotatedF(sprHammer, + sx, + sy, + 0, + sign, + 0); + else + DrawHedgehog(sx, sy, + sign, + 0, + 4, + 0); + + HatVisible:= true; + (* with HH^ do + if (HatTex <> nil) + and (HatVisibility > 0) then + DrawTextureF(HatTex, + HatVisibility, + sx, + sy - 5, + 0, + sign, + 32, + 32); *) + end; + + case amt of + amBaseballBat: DrawRotated(sprHandBaseball, + sx - 4 * sign, + sy + 9, sign, aangle); + end; + + defaultPos:= false + end; + + end else // not gstHHDriven + begin + if (Gear^.Damage > 0) + and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > _0_003) then + begin + DrawHedgehog(sx, sy, + sign, + 2, + 1, + Gear^.DirAngle); + defaultPos:= false + end else + + if ((Gear^.State and gstHHJumping) <> 0) then + begin + DrawHedgehog(sx, sy, + sign*m, + 1, + 1, + 0); + defaultPos:= false + end; + end; + + with HH^ do + begin + if defaultPos then + begin + DrawRotatedF(sprHHIdle, + sx, + sy, + (RealTicks div 128 + Gear^.Pos) mod 19, + sign, + 0); + HatVisible:= true; + end; + + if HatVisible then + if HatVisibility < 1.0 then + HatVisibility:= HatVisibility + 0.2 + else + else + if HatVisibility > 0.0 then + HatVisibility:= HatVisibility - 0.2; + + if (HatTex <> nil) + and (HatVisibility > 0) then + if DefaultPos then + begin + DrawTextureF(HatTex, + HatVisibility, + sx, + sy - 5, + (RealTicks div 128 + Gear^.Pos) mod 19, + sign, + 32, + 32); + if HatTex^.w > 64 then + begin + Tint(HH^.Team^.Clan^.Color shl 8 or $FF); + DrawTextureF(HatTex, + HatVisibility, + sx, + sy - 5, + (RealTicks div 128 + Gear^.Pos) mod 19 + 32, + sign, + 32, + 32); + Tint($FF, $FF, $FF, $FF) + end + end + else + begin + DrawTextureF(HatTex, + HatVisibility, + sx, + sy - 5, + 0, + sign*m, + 32, + 32); + if HatTex^.w > 64 then + begin + Tint(HH^.Team^.Clan^.Color shl 8 or $FF); + DrawTextureF(HatTex, + HatVisibility, + sx, + sy - 5, + 32, + sign*m, + 32, + 32); + Tint($FF, $FF, $FF, $FF) + end + end + end; + if (Gear^.State and gstHHDriven) <> 0 then + begin + (* if (CurAmmoGear = nil) then + begin + amt:= CurrentHedgehog^.CurAmmoType; + case amt of + amJetpack: DrawSprite(sprJetpack, sx-32, sy-32, 0); + end + end; *) + if CurAmmoGear <> nil then + begin + case CurAmmoGear^.Kind of + gtJetpack: begin + DrawSprite(sprJetpack, sx-32, sy-32, 0); + if cWaterLine > hwRound(Gear^.Y) + Gear^.Radius then + begin + if (CurAmmoGear^.MsgParam and gmUp) <> 0 then DrawSprite(sprJetpack, sx-32, sy-28, 1); + if (CurAmmoGear^.MsgParam and gmLeft) <> 0 then DrawSprite(sprJetpack, sx-28, sy-28, 2); + if (CurAmmoGear^.MsgParam and gmRight) <> 0 then DrawSprite(sprJetpack, sx-36, sy-28, 3) + end; + if CurAmmoGear^.Tex <> nil then DrawCentered(sx, sy - 40, CurAmmoGear^.Tex); + DrawAltWeapon(Gear, sx, sy) + end; + end; + end + end; + + with HH^ do + begin + if ((Gear^.State and not gstWinner) = 0) + or ((Gear^.State = gstWait) and (Gear^.dY.QWordValue = 0)) + or (bShowFinger and ((Gear^.State and gstHHDriven) <> 0)) then + begin + t:= sy - cHHRadius - 9; + if (cTagsMask and htTransparent) <> 0 then + Tint($FF, $FF, $FF, $80); + if ((cTagsMask and htHealth) <> 0) then + begin + dec(t, HealthTagTex^.h + 2); + DrawCentered(ox, t, HealthTagTex) + end; + if (cTagsMask and htName) <> 0 then + begin + dec(t, NameTagTex^.h + 2); + DrawCentered(ox, t, NameTagTex) + end; + if (cTagsMask and htTeamName) <> 0 then + begin + dec(t, Team^.NameTagTex^.h + 2); + DrawCentered(ox, t, Team^.NameTagTex) + end; + if (cTagsMask and htTransparent) <> 0 then + Tint($FF, $FF, $FF, $FF) + end; + if (Gear^.State and gstHHDriven) <> 0 then // Current hedgehog + begin + if (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtResurrector) then + DrawCentered(ox, sy - cHHRadius - 7 - HealthTagTex^.h, HealthTagTex); + + if bShowFinger and ((Gear^.State and gstHHDriven) <> 0) then + DrawSprite(sprFinger, ox - 16, oy - 64, + GameTicks div 32 mod 16); + + if (Gear^.State and gstDrowning) = 0 then + if (Gear^.State and gstHHThinking) <> 0 then + DrawSprite(sprQuestion, ox - 10, oy - cHHRadius - 34, (RealTicks shr 9) mod 8) + end + end; + + if HH^.Effects[hePoisoned] then + begin + Tint($00, $FF, $40, $80); + DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 1.5, 0, 0, sx, sy, 0, 1, 22, 22, 360 - (RealTicks shr 37) mod 360); + end; + if HH^.Effects[heResurrected] then + begin + Tint($f5, $db, $35, $20); + DrawSprite(sprVampiric, sx - 24, sy - 24, 0); + end; + + if Gear^.Invulnerable then + begin + Tint($FF, $FF, $FF, max($40, round($FF * abs(1 - ((RealTicks div 2 + Gear^.uid * 491) mod 1500) / 750)))); + DrawSprite(sprInvulnerable, sx - 24, sy - 24, 0); + end; + if cVampiric and + (CurrentHedgehog^.Gear <> nil) and + (CurrentHedgehog^.Gear = Gear) then + begin + Tint($FF, 0, 0, max($40, round($FF * abs(1 - (RealTicks mod 1500) / 750)))); + DrawSprite(sprVampiric, sx - 24, sy - 24, 0); + end; + Tint($FF, $FF, $FF, $FF) +end; + + +procedure RenderGear(Gear: PGear; x, y: LongInt); +var + HHGear: PGear; + i: Longword; + startX, endX, startY, endY: LongInt; +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); + + gtRCPlane: begin + if (Gear^.Tag = -1) then + DrawRotated(sprPlane, x, y, -1, DxDy2Angle(Gear^.dX, Gear^.dY) + 90) + else + DrawRotated(sprPlane, x, y,0,DxDy2Angle(Gear^.dY, Gear^.dX)); + end; + gtBall: DrawRotatedf(sprBalls, x, y, Gear^.Tag,0, Gear^.DirAngle); + + gtPortal: if ((Gear^.Tag and 1) = 0) // still moving? + or (Gear^.IntersectGear = nil) or (Gear^.IntersectGear^.IntersectGear <> Gear) // not linked&backlinked? + or ((Gear^.IntersectGear^.Tag and 1) = 0) then // linked portal still moving? + DrawRotatedf(sprPortal, x, y, Gear^.Tag, hwSign(Gear^.dX), Gear^.DirAngle) + else DrawRotatedf(sprPortal, x, y, 4 + Gear^.Tag div 2, hwSign(Gear^.dX), Gear^.DirAngle); + + gtDrill: if (Gear^.State and gsttmpFlag) <> 0 then + DrawRotated(sprAirDrill, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)) + else + DrawRotated(sprDrill, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); + + gtHedgehog: DrawHH(Gear, x, y); + + gtShell: DrawRotated(sprBazookaShell, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); + + gtGrave: begin + DrawTextureF(Gear^.Hedgehog^.Team^.GraveTex, 1, x, y, (GameTicks shr 7+Gear^.uid) and 7, 1, 32, 32); + if Gear^.Health > 0 then + begin + //Tint($33, $33, $FF, max($40, round($FF * abs(1 - (GameTicks mod (6000 div Gear^.Health)) / 750)))); + Tint($f5, $db, $35, max($40, round($FF * abs(1 - (GameTicks mod 1500) / (750 + Gear^.Health))))); + //Tint($FF, $FF, $FF, max($40, round($FF * abs(1 - (RealTicks mod 1500) / 750)))); + DrawSprite(sprVampiric, x - 24, y - 24, 0); + Tint($FF, $FF, $FF, $FF) + end + end; + gtBee: DrawRotatedF(sprBee, x, y, (GameTicks shr 5) mod 2, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); + gtPickHammer: DrawSprite(sprPHammer, x - 16, y - 50 + LongInt(((GameTicks shr 5) and 1) * 2), 0); + gtRope: DrawRope(Gear); + gtMine: if (((Gear^.State and gstAttacking) = 0)or((Gear^.Timer and $3FF) < 420)) and (Gear^.Health <> 0) then + DrawRotated(sprMineOff, x, y, 0, Gear^.DirAngle) + else if Gear^.Health <> 0 then DrawRotated(sprMineOn, x, y, 0, Gear^.DirAngle) + else DrawRotated(sprMineDead, x, y, 0, Gear^.DirAngle); + gtSMine: if (((Gear^.State and gstAttacking) = 0)or((Gear^.Timer and $3FF) < 420)) and (Gear^.Health <> 0) then + DrawRotated(sprSMineOff, x, y, 0, Gear^.DirAngle) + else if Gear^.Health <> 0 then DrawRotated(sprSMineOn, x, y, 0, Gear^.DirAngle) + else DrawRotated(sprMineDead, x, y, 0, Gear^.DirAngle); + gtCase: case Gear^.Pos of + posCaseAmmo : begin + i:= (GameTicks shr 6) mod 64; + if i > 18 then i:= 0; + DrawSprite(sprCase, x - 24, y - 24, i); + end; + posCaseHealth: begin + i:= ((GameTicks shr 6) + 38) mod 64; + if i > 13 then i:= 0; + DrawSprite(sprFAid, x - 24, y - 24, i); + end; + posCaseUtility: begin + i:= (GameTicks shr 6) mod 70; + if i > 23 then i:= 0; + i:= i mod 12; + DrawSprite(sprUtility, x - 24, y - 24, i); + end; + end; + gtExplosives: begin + if ((Gear^.State and gstDrowning) <> 0) then + DrawSprite(sprExplosivesRoll, x - 24, y - 24, 0) + else if Gear^.State and gstAnimation = 0 then + begin + i:= (GameTicks shr 6 + Gear^.uid*3) mod 64; + if i > 18 then i:= 0; + DrawSprite(sprExplosives, x - 24, y - 24, i) + end + else if Gear^.State and gsttmpFlag = 0 then + DrawRotatedF(sprExplosivesRoll, x, y + 4, 0, 0, Gear^.DirAngle) + else + DrawRotatedF(sprExplosivesRoll, x, y + 4, 1, 0, Gear^.DirAngle); + end; + gtDynamite: DrawSprite2(sprDynamite, x - 16, y - 25, Gear^.Tag and 1, Gear^.Tag shr 1); + gtClusterBomb: DrawRotated(sprClusterBomb, x, y, 0, Gear^.DirAngle); + gtCluster: DrawSprite(sprClusterParticle, x - 8, y - 8, 0); + gtFlame: DrawTextureF(SpritesData[sprFlame].Texture, 2 / (Gear^.Tag mod 3 + 2), x, y, (GameTicks shr 7 + LongWord(Gear^.Tag)) mod 8, 1, 16, 16); + gtParachute: begin + DrawSprite(sprParachute, x - 24, y - 48, 0); + DrawAltWeapon(Gear, x + 1, y - 3) + end; + gtAirAttack: if Gear^.Tag > 0 then DrawSprite(sprAirplane, x - SpritesData[sprAirplane].Width div 2, y - SpritesData[sprAirplane].Height div 2, 0) + else DrawSprite(sprAirplane, x - SpritesData[sprAirplane].Width div 2, y - SpritesData[sprAirplane].Height div 2, 1); + gtAirBomb: DrawRotated(sprAirBomb, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); + gtTeleport: begin + HHGear:= Gear^.Hedgehog^.Gear; + if not Gear^.Hedgehog^.Unplaced then DrawRotatedF(sprTeleport, x + 1, y - 3, Gear^.Pos, hwSign(Gear^.dX), 0); + DrawRotatedF(sprTeleport, hwRound(HHGear^.X) + 1 + WorldDx, hwRound(HHGear^.Y) - 3 + WorldDy, 11 - Gear^.Pos, hwSign(HHGear^.dX), 0); + end; + gtSwitcher: DrawSprite(sprSwitch, x - 16, y - 56, (GameTicks shr 6) mod 12); + gtTarget: begin + Tint($FF, $FF, $FF, round($FF * Gear^.Timer / 1000)); + DrawSprite(sprTarget, x - 16, y - 16, 0); + Tint($FF, $FF, $FF, $FF); + end; + gtMortar: DrawRotated(sprMortar, x, y, 0, DxDy2Angle(Gear^.dY, Gear^.dX)); + gtCake: if Gear^.Pos = 6 then + DrawRotatedf(sprCakeWalk, x, y, (GameTicks div 40) mod 6, hwSign(Gear^.dX), Gear^.DirAngle * hwSign(Gear^.dX) + 90) + else + DrawRotatedf(sprCakeDown, x, y, 5 - Gear^.Pos, hwSign(Gear^.dX), Gear^.DirAngle * hwSign(Gear^.dX) + 90); + gtSeduction: if Gear^.Pos >= 14 then DrawSprite(sprSeduction, x - 16, y - 16, 0); + gtWatermelon: DrawRotatedf(sprWatermelon, x, y, 0, 0, Gear^.DirAngle); + gtMelonPiece: DrawRotatedf(sprWatermelon, x, y, 1, 0, Gear^.DirAngle); + gtHellishBomb: DrawRotated(sprHellishBomb, x, y, 0, Gear^.DirAngle); + gtBirdy: begin + if Gear^.State and gstAnimation = gstAnimation then + begin + if Gear^.State and gstTmpFlag = 0 then // Appearing + begin + endX:= x - WorldDx; + endY:= y - WorldDy; + if Gear^.Tag < 0 then + startX:= max(LAND_WIDTH + 1024, endX + 2048) + else + startX:= max(-LAND_WIDTH - 1024, endX - 2048); + startY:= endY - 256; + DrawTextureF(SpritesData[sprBirdy].Texture, 1, startX + WorldDx + round((endX - startX) * (-power(2, -10 * LongInt(Gear^.Timer)/2000) + 1)), startY + WorldDy + round((endY - startY) * sqrt(1 - power((LongInt(Gear^.Timer)/2000)-1, 2))), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75); + end + else // Disappearing + begin + startX:= x - WorldDx; + startY:= y - WorldDy; + if Gear^.Tag > 0 then + endX:= max(LAND_WIDTH + 1024, startX + 2048) + else + endX:= max(-LAND_WIDTH - 1024, startX - 2048); + endY:= startY + 256; + DrawTextureF(SpritesData[sprBirdy].Texture, 1, startX + WorldDx + round((endX - startX) * power(2, 10 * (LongInt(Gear^.Timer)/2000 - 1))) + hwRound(Gear^.dX * Gear^.Timer), startY + WorldDy + round((endY - startY) * cos(LongInt(Gear^.Timer)/2000 * (Pi/2)) - (endY - startY)) + hwRound(Gear^.dY * Gear^.Timer), ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75); + end; + end + else + DrawTextureF(SpritesData[sprBirdy].Texture, 1, x, y, ((Gear^.Pos shr 6) or (RealTicks shr 8)) mod 2, Gear^.Tag, 75, 75); + end; + gtEgg: DrawRotatedTextureF(SpritesData[sprEgg].Texture, 1, 0, 0, x, y, 0, 1, 16, 16, Gear^.DirAngle); + gtPiano: begin + if (Gear^.State and gstDrowning) = 0 then + begin + Tint($FF, $FF, $FF, $10); + for i:= 8 downto 1 do + DrawRotatedTextureF(SpritesData[sprPiano].Texture, 1, 0, 0, x, y - hwRound(Gear^.dY * 4 * i), 0, 1, 128, 128, 0); + Tint($FF, $FF, $FF, $FF) + end; + DrawRotatedTextureF(SpritesData[sprPiano].Texture, 1, 0, 0, x, y, 0, 1, 128, 128, 0); + end; + gtPoisonCloud: begin + if Gear^.Timer < 1020 then + Tint($C0, $C0, $00, Gear^.Timer div 8) + else if Gear^.Timer > 3980 then + Tint($C0, $C0, $00, (5000 - Gear^.Timer) div 8) + else + Tint($C0, $C0, $00, $C0); + DrawRotatedTextureF(SpritesData[sprSmokeWhite].texture, 3, 0, 0, x, y, 0, 1, 22, 22, (RealTicks shr 36 + Gear^.UID * 100) mod 360); + Tint($FF, $FF, $FF, $FF) + end; + gtResurrector: begin + DrawRotated(sprCross, x, y, 0, 0); + Tint($f5, $db, $35, max($00, round($C0 * abs(1 - (GameTicks mod 6000) / 3000)))); + DrawTexture(x - 108, y - 108, SpritesData[sprVampiric].Texture, 4.5); + 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; + + end; + if Gear^.RenderTimer and (Gear^.Tex <> nil) then DrawCentered(x + 8, y + 8, Gear^.Tex); +end; + +end. diff -r 0ddb100fea61 -r f924be23ffb4 hedgewars/uIO.pas --- a/hedgewars/uIO.pas Mon Dec 27 23:57:44 2010 +0100 +++ b/hedgewars/uIO.pas Tue Jan 04 12:53:46 2011 +0100 @@ -20,7 +20,7 @@ unit uIO; interface -uses SDLh; +uses SDLh, uTypes; var ipcPort: Word = 0; hiTicks: Word; @@ -35,14 +35,16 @@ procedure SendIPCTimeInc; procedure SendKeepAliveMessage(Lag: Longword); procedure LoadRecordFromFile(fileName: shortstring); +procedure SendStat(sit: TStatInfoType; s: shortstring); procedure IPCWaitPongEvent; procedure IPCCheckSock; procedure InitIPC; procedure CloseIPC; procedure NetGetNextCmd; +procedure doPut(putX, putY: LongInt; fromAI: boolean); implementation -uses uConsole, uConsts, uWorld, uMisc, uLand, uChat, uTeams; +uses uConsole, uConsts, uVariables, uCommands, uUtils, uDebug; type PCmd = ^TCmd; TCmd = packed record @@ -64,7 +66,6 @@ SendEmptyPacketTicks: LongWord; - function AddCmd(Time: Word; str: shortstring): PCmd; var command: PCmd; begin @@ -128,7 +129,7 @@ 'e': ParseCommand(copy(s, 2, Length(s) - 1), true); 'E': OutError(copy(s, 2, Length(s) - 1), true); 'W': OutError(copy(s, 2, Length(s) - 1), false); - 'M': CheckLandDigest(s); + 'M': ParseCommand('landcheck ' + s, true); 'T': case s[2] of 'L': GameType:= gmtLocal; 'D': GameType:= gmtDemo; @@ -138,7 +139,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} + {$IFDEF DEBUGFILE}AddFileLog('[IPC in] '+s[1]+' ticks '+IntToStr(lastcmd^.loTime));{$ENDIF} end end; @@ -203,6 +204,15 @@ close(f) end; +procedure SendStat(sit: TStatInfoType; s: shortstring); +const stc: array [TStatInfoType] of char = 'rDkKHTPsSB'; +var buf: shortstring; +begin +buf:= 'i' + stc[sit] + s; +SendIPCRaw(@buf[0], length(buf) + 1) +end; + + procedure SendIPC(s: shortstring); begin if IPCSock <> nil then @@ -210,7 +220,7 @@ SendEmptyPacketTicks:= 0; if s[0]>#251 then s[0]:= #251; SDLNet_Write16(GameTicks, @s[Succ(byte(s[0]))]); - {$IFDEF DEBUGFILE}AddFileLog('IPC send: '+ s[1]);{$ENDIF} + {$IFDEF DEBUGFILE}AddFileLog('[IPC out] '+ s[1]);{$ENDIF} inc(s[0], 2); SDLNet_TCP_Send(IPCSock, @s, Succ(byte(s[0]))) end @@ -237,7 +247,7 @@ procedure SendIPCTimeInc; const timeinc: shortstring = '#'; begin -{$IFDEF DEBUGFILE}AddFileLog('IPC Send #');{$ENDIF} +{$IFDEF DEBUGFILE}AddFileLog('[IPC out]