The first campaign commit with a lot of changes...
authorbelphegorr <szabibibi@gmail.com>
Mon, 25 Jun 2012 10:46:48 +0300
changeset 7201 dc17ffdf0702
parent 7199 f329fbf1ffb4
child 7203 37661b2a7b64
The first campaign commit with a lot of changes... branch 'default' added QTfrontend/campaign.cpp added QTfrontend/campaign.h changed QTfrontend/CMakeLists.txt changed QTfrontend/game.cpp changed QTfrontend/game.h changed QTfrontend/hwform.cpp changed QTfrontend/hwform.h changed QTfrontend/ui/page/pagecampaign.cpp changed QTfrontend/ui/page/pagecampaign.h changed QTfrontend/ui/page/pagesingleplayer.cpp changed hedgewars/uCommandHandlers.pas changed hedgewars/uIO.pas changed hedgewars/uScript.pas changed hedgewars/uVariables.pas
QTfrontend/CMakeLists.txt
QTfrontend/campaign.cpp
QTfrontend/campaign.h
QTfrontend/game.cpp
QTfrontend/game.h
QTfrontend/hwform.cpp
QTfrontend/hwform.h
QTfrontend/ui/page/pagecampaign.cpp
QTfrontend/ui/page/pagecampaign.h
QTfrontend/ui/page/pagesingleplayer.cpp
hedgewars/uCommandHandlers.pas
hedgewars/uIO.pas
hedgewars/uScript.pas
hedgewars/uVariables.pas
--- a/QTfrontend/CMakeLists.txt	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/CMakeLists.txt	Mon Jun 25 10:46:48 2012 +0300
@@ -83,6 +83,7 @@
     hwform.cpp
     main.cpp
     team.cpp
+    campaign.cpp
     ui_hwform.cpp
     ${CMAKE_CURRENT_BINARY_DIR}/hwconsts.cpp
     )
@@ -119,6 +120,7 @@
     HWApplication.h
     hwform.h
     team.h
+    campaign.h
     util/DataManager.h
     )
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/campaign.cpp	Mon Jun 25 10:46:48 2012 +0300
@@ -0,0 +1,91 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <QDir>
+#include <QFile>
+#include <QTextStream>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QListWidget>
+#include <QStackedLayout>
+#include <QLineEdit>
+#include <QLabel>
+#include <QRadioButton>
+#include <QSpinBox>
+#include <QCloseEvent>
+#include <QCheckBox>
+#include <QTextBrowser>
+#include <QAction>
+#include <QTimer>
+#include <QScrollBar>
+#include <QDataWidgetMapper>
+#include <QTableView>
+#include <QCryptographicHash>
+#include <QSignalMapper>
+#include <QShortcut>
+#include <QDesktopServices>
+#include <QInputDialog>
+#include <QPropertyAnimation>
+#include <QSettings>
+
+#include "campaign.h"
+#include "gameuiconfig.h"
+#include "hwconsts.h"
+#include "gamecfgwidget.h"
+#include "bgwidget.h"
+#include "mouseoverfilter.h"
+#include "tcpBase.h"
+
+#include "DataManager.h"
+
+extern QString campaign, campaignTeam;
+
+QStringList getCampMissionList(QString & campaign)
+{
+    QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0);
+    campfile.setIniCodec("UTF-8");
+    unsigned int mNum = campfile.value("MissionNum", 0).toInt();
+    
+    QStringList missionList;
+    for (unsigned int i = 0; i < mNum; i++)
+    {
+      missionList += campfile.value(QString("Mission %1/Name").arg(i + 1)).toString();
+    }
+    return missionList;
+}
+  
+unsigned int getCampProgress(QString & teamName, QString & campName)
+{
+    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + teamName + ".hwt", QSettings::IniFormat, 0);
+    teamfile.setIniCodec("UTF-8");
+    return teamfile.value("Campaign " + campName + "/Progress", 0).toInt();
+}
+
+QString getCampaignScript(QString campaign, unsigned int mNum)
+{
+    QSettings campfile(DataManager::instance().findFileForRead("Missions/Campaign/" + campaign + "/campaign.ini"), QSettings::IniFormat, 0);
+    campfile.setIniCodec("UTF-8");
+    return campfile.value(QString("Mission %1/Script").arg(mNum)).toString();
+}
+
+
+    
+
+
+
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QTfrontend/campaign.h	Mon Jun 25 10:46:48 2012 +0300
@@ -0,0 +1,42 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef CAMPAIGN_H
+#define CAMPAIGN_H
+
+#include <QMainWindow>
+#include <QStack>
+#include <QTime>
+#include <QPointer>
+#include <QPropertyAnimation>
+#include <QUrl>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QNetworkAccessManager>
+
+#include "netserver.h"
+#include "game.h"
+#include "ui_hwform.h"
+#include "SDLInteraction.h"
+#include "bgwidget.h"
+
+QStringList getCampMissionList(QString & campaign);
+unsigned int getCampProgress(QString & teamName, QString & campName);
+QString getCampaignScript(QString campaign, unsigned int mNum);
+
+#endif
--- a/QTfrontend/game.cpp	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/game.cpp	Mon Jun 25 10:46:48 2012 +0300
@@ -21,6 +21,7 @@
 #include <QUuid>
 #include <QColor>
 #include <QStringListModel>
+#include <QMessageBox>
 
 #include "game.h"
 #include "hwconsts.h"
@@ -29,10 +30,11 @@
 #include "teamselect.h"
 #include "KB.h"
 #include "proto.h"
+#include "campaign.h"
 
 #include <QTextStream>
 
-QString training, campaign; // TODO: Cleaner solution?
+QString training, campaign, campaignScript, campaignTeam; // TODO: Cleaner solution?
 
 HWGame::HWGame(GameUIConfig * config, GameCFGWidget * gamecfg, QString ammo, TeamSelWidget* pTeamSelWidget) :
     TCPBase(true),
@@ -165,7 +167,7 @@
     HWProto::addStringToBuffer(campaigncfg, "TL");
     HWProto::addStringToBuffer(campaigncfg, "eseed " + QUuid::createUuid().toString());
 
-    HWProto::addStringToBuffer(campaigncfg, "escript " + campaign);
+    HWProto::addStringToBuffer(campaigncfg, "escript " + campaignScript);
 
     RawSendIPC(campaigncfg);
 }
@@ -277,6 +279,14 @@
             emit SendTeamMessage(msgbody);
             break;
         }
+        case 'V':
+        {
+            if (msg.at(2) == '?')
+                sendCampaignVar(msg.right(msg.size() - 3));
+            else if (msg.at(2) == '!')
+                writeCampaignVar(msg.right(msg.size() - 3));
+            break;
+        }
         default:
         {
             if (gameType == gtNet && !netSuspend)
@@ -391,10 +401,12 @@
     SetGameState(gsStarted);
 }
 
-void HWGame::StartCampaign(const QString & file)
+void HWGame::StartCampaign(const QString & camp, const QString & campScript, const QString & campTeam)
 {
     gameType = gtCampaign;
-    campaign = "Missions/Campaign/" + file + ".lua";
+    campaign = camp;
+    campaignScript = "Missions/Campaign/" + camp + "/" + campScript;
+    campaignTeam = campTeam;
     demo.clear();
     Start();
     SetGameState(gsStarted);
@@ -412,3 +424,37 @@
     HWProto::addStringToBuffer(buf, QString("efinish"));
     RawSendIPC(buf);
 }
+
+void HWGame::sendCampaignVar(QByteArray varToSend)
+{
+    QString varToFind(varToSend);
+    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + campaignTeam + ".hwt", QSettings::IniFormat, 0);
+    teamfile.setIniCodec("UTF-8");
+    QString varValue = teamfile.value("Campaign " + campaign + "/" + varToFind, "").toString();
+    QByteArray command;
+    HWProto::addStringToBuffer(command, "V." + varValue);
+    RawSendIPC(command);
+}
+
+void HWGame::writeCampaignVar(QByteArray varVal)
+{
+    QString varToWrite("");
+    QString varValue("");
+    unsigned int i = 0;
+    while (i < varVal.size() && varVal.at(i) != ' ')
+    {
+      varToWrite.append(varVal.at(i));
+      i++;
+    }
+    i++;
+    while (i < varVal.size() && varVal.at(i) != '\0')
+    {
+      varValue.append(varVal.at(i));
+      i++;
+    }
+
+    QSettings teamfile(cfgdir->absolutePath() + "/Teams/" + campaignTeam + ".hwt", QSettings::IniFormat, 0);
+    teamfile.setIniCodec("UTF-8");
+    teamfile.setValue("Campaign " + campaign + "/" + varToWrite, varValue);
+}
+
--- a/QTfrontend/game.h	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/game.h	Mon Jun 25 10:46:48 2012 +0300
@@ -54,7 +54,7 @@
         void StartQuick();
         void StartNet();
         void StartTraining(const QString & file);
-        void StartCampaign(const QString & file);
+        void StartCampaign(const QString & camp, const QString & campScript, const QString & campTeam);
         void abort();
         GameState gameState;
         bool netSuspend;
@@ -103,6 +103,8 @@
         void SendCampaignConfig();
         void ParseMessage(const QByteArray & msg);
         void SetGameState(GameState state);
+        void sendCampaignVar(QByteArray varToSend);
+        void writeCampaignVar(QByteArray varVal);
 };
 
 #endif
--- a/QTfrontend/hwform.cpp	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/hwform.cpp	Mon Jun 25 10:46:48 2012 +0300
@@ -51,6 +51,7 @@
 #include "hwform.h"
 #include "game.h"
 #include "team.h"
+#include "campaign.h"
 #include "teamselect.h"
 #include "selectWeapon.h"
 #include "gameuiconfig.h"
@@ -162,6 +163,7 @@
 #endif
 
     UpdateTeamsLists();
+    InitCampaignPage();
     UpdateCampaignPage(0);
     UpdateWeapons();
 
@@ -273,6 +275,7 @@
 
     connect(ui.pageCampaign->BtnStartCampaign, SIGNAL(clicked()), this, SLOT(StartCampaign()));
     connect(ui.pageCampaign->CBTeam, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
+    connect(ui.pageCampaign->CBCampaign, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCampaignPage(int)));
 
 
     connect(ui.pageSelectWeapon->BtnDelete, SIGNAL(clicked()),
@@ -1418,7 +1421,13 @@
 {
     CreateGame(0, 0, 0);
 
-    game->StartCampaign(ui.pageCampaign->CBSelect->itemData(ui.pageCampaign->CBSelect->currentIndex()).toString());
+    QComboBox *combo = ui.pageCampaign->CBMission;
+    QString camp = ui.pageCampaign->CBCampaign->currentText();
+    unsigned int mNum = combo->count() - combo->currentIndex();
+    QString miss = getCampaignScript(camp, mNum);
+    QString campTeam = ui.pageCampaign->CBTeam->currentText();
+
+    game->StartCampaign(camp, miss, campTeam);
 }
 
 void HWForm::CreateNetGame()
@@ -1544,23 +1553,41 @@
     }
 }
 
+void HWForm::InitCampaignPage()
+{
+    ui.pageCampaign->CBCampaign->clear();
+    HWTeam team(ui.pageCampaign->CBTeam->currentText());
+
+    QStringList entries = DataManager::instance().entryList(
+                                  "Missions/Campaign",
+                                  QDir::Dirs,
+                                  QStringList("[^\\.]*")
+                              );
+
+    unsigned int n = entries.count();
+    for(unsigned int i = 0; i < n; i++)
+    {
+        ui.pageCampaign->CBCampaign->addItem(QString(entries[i]), QString(entries[i]));
+    }
+}
+
+
 void HWForm::UpdateCampaignPage(int index)
 {
     Q_UNUSED(index);
 
     HWTeam team(ui.pageCampaign->CBTeam->currentText());
-    ui.pageCampaign->CBSelect->clear();
+    ui.pageCampaign->CBMission->clear();
 
-    QStringList entries = DataManager::instance().entryList(
-                              "Missions/Campaign",
-                              QDir::Files,
-                              QStringList("*#*.lua")
-                          );
+    QString campaignName = ui.pageCampaign->CBCampaign->currentText();
+    QStringList missionEntries = getCampMissionList(campaignName);
+    QString tName = team.name();
+    unsigned int n = missionEntries.count();
+    unsigned int m = getCampProgress(tName, campaignName);
 
-    unsigned int n = entries.count();
-    for(unsigned int i = 0; (i < n) && (i <= team.campaignProgress()); i++)
+    for (unsigned int i = min(m + 1, n); i > 0; i--)
     {
-        ui.pageCampaign->CBSelect->addItem(QString(entries[i]).replace(QRegExp("^(\\d+)#(.+)\\.lua"), QComboBox::tr("Mission") + " \\1: \\2").replace("_", " "), QString(entries[i]).replace(QRegExp("^(.*)\\.lua"), "\\1"));
+        ui.pageCampaign->CBMission->addItem(QString("Mission %1: ").arg(i) + QString(missionEntries[i-1]), QString(missionEntries[i-1]));
     }
 }
 
--- a/QTfrontend/hwform.h	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/hwform.h	Mon Jun 25 10:46:48 2012 +0300
@@ -121,6 +121,7 @@
         void onFrontendEffects(bool value);
         void Music(bool checked);
         void UpdateCampaignPage(int index);
+        void InitCampaignPage();
         //Starts the transmission process for the feedback
         void SendFeedback();
         //Make a xml representation of the issue to be created
--- a/QTfrontend/ui/page/pagecampaign.cpp	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/ui/page/pagecampaign.cpp	Mon Jun 25 10:46:48 2012 +0300
@@ -31,11 +31,13 @@
     pageLayout->setRowStretch(0, 1);
     pageLayout->setRowStretch(3, 1);
 
-    CBSelect = new QComboBox(this);
     CBTeam = new QComboBox(this);
+    CBMission = new QComboBox(this);
+    CBCampaign = new QComboBox(this);
 
     pageLayout->addWidget(CBTeam, 1, 1);
-    pageLayout->addWidget(CBSelect, 2, 1);
+    pageLayout->addWidget(CBCampaign, 2, 1);
+    pageLayout->addWidget(CBMission, 3, 1);
 
     BtnStartCampaign = new QPushButton(this);
     BtnStartCampaign->setFont(*font14);
--- a/QTfrontend/ui/page/pagecampaign.h	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/ui/page/pagecampaign.h	Mon Jun 25 10:46:48 2012 +0300
@@ -29,7 +29,8 @@
         PageCampaign(QWidget* parent = 0);
 
         QPushButton *BtnStartCampaign;
-        QComboBox   *CBSelect;
+        QComboBox   *CBMission;
+        QComboBox   *CBCampaign;
         QComboBox   *CBTeam;
 
     protected:
--- a/QTfrontend/ui/page/pagesingleplayer.cpp	Fri Jun 08 19:25:40 2012 +0200
+++ b/QTfrontend/ui/page/pagesingleplayer.cpp	Mon Jun 25 10:46:48 2012 +0300
@@ -48,7 +48,7 @@
     BtnCampaignPage = addButton(":/res/Campaign.png", middleLine, 0, true);
     BtnCampaignPage->setToolTip(tr("Campaign Mode"));
     BtnCampaignPage->setWhatsThis(tr("Campaign Mode"));
-    BtnCampaignPage->setVisible(false);
+    BtnCampaignPage->setVisible(true);
 
     BtnTrainPage = addButton(":/res/Trainings.png", middleLine, 1, true);
     BtnTrainPage->setToolTip(tr("Training Mode"));
--- a/hedgewars/uCommandHandlers.pas	Fri Jun 08 19:25:40 2012 +0200
+++ b/hedgewars/uCommandHandlers.pas	Mon Jun 25 10:46:48 2012 +0300
@@ -781,6 +781,11 @@
 fastUntilLag:= StrToInt(s) <> 0
 end;
 
+procedure chCampVar(var s:shortstring);
+begin
+  CampaignVariable := s;
+end;
+
 procedure initModule;
 begin
 //////// Begin top sorted by freq analysis not including chatmsg
@@ -864,6 +869,7 @@
     RegisterVariable('-cur_l'  , @chCurL_m       , true );
     RegisterVariable('+cur_r'  , @chCurR_p       , true );
     RegisterVariable('-cur_r'  , @chCurR_m       , true );
+    RegisterVariable('campvar' , @chCampVar      , true );
 end;
 
 procedure freeModule;
--- a/hedgewars/uIO.pas	Fri Jun 08 19:25:40 2012 +0200
+++ b/hedgewars/uIO.pas	Mon Jun 25 10:46:48 2012 +0300
@@ -127,6 +127,10 @@
                'N': GameType:= gmtNet;
                'S': GameType:= gmtSave;
                else OutError(errmsgIncorrectUse + ' IPC "T" :' + s[2], true) end;
+     'V': begin
+              if s[2] = '.' then
+                  ParseCommand('campvar ' + copy(s, 3, length(s) - 2), true);
+          end
      else
      loTicks:= SDLNet_Read16(@s[byte(s[0]) - 1]);
      AddCmd(loTicks, s);
--- a/hedgewars/uScript.pas	Fri Jun 08 19:25:40 2012 +0200
+++ b/hedgewars/uScript.pas	Mon Jun 25 10:46:48 2012 +0300
@@ -80,7 +80,8 @@
     uTextures,
     uLandGraphics,
     SDLh,
-    SysUtils; 
+    SysUtils, 
+    uIO;
 
 var luaState : Plua_State;
     ScriptAmmoLoadout : shortstring;
@@ -1649,6 +1650,68 @@
     lc_getcurammotype := 1;
 end;
 
+function lc_savecampaignvar(L : Plua_State): LongInt; Cdecl;
+begin
+    if lua_gettop(L) <> 2 then
+        LuaError('Lua: Wrong number of parameters passed to SaveCampaignVar!')
+    else begin
+        SendIPC('V!' + lua_tostring(L, 1) + ' ' + lua_tostring(L, 2) + #0);
+    end;
+    lc_savecampaignvar := 0;
+end;
+
+function lc_getcampaignvar(L : Plua_State): LongInt; Cdecl;
+begin
+    if (lua_gettop(L) <> 1) then
+        LuaError('Lua: Wrong number of parameters passed to GetCampaignVar!')
+    else
+        SendIPCAndWaitReply('V?' + lua_tostring(L, 1));
+    lua_pushstring(L, str2pchar(CampaignVariable));
+    lc_getcampaignvar := 1;
+end;
+
+function lc_hidehog(L: Plua_State): LongInt; Cdecl;
+var gear: PGear;
+begin
+    if lua_gettop(L) <> 1 then
+        LuaError('Lua: Wrong number of parameters passed to HideHog!')
+    else
+        begin
+        gear:= GearByUID(lua_tointeger(L, 1));
+        hiddenHedgehogs[hiddenHedgehogsNumber]:=gear^.hedgehog;
+        inc(hiddenHedgehogsNumber);
+        HideHog(gear^.hedgehog);
+        end;
+    lc_hidehog := 0;
+end;
+
+function lc_restorehog(L: Plua_State): LongInt; Cdecl;
+var hog: PHedgehog;
+    i, j: LongInt;
+begin
+    if lua_gettop(L) <> 1 then
+        LuaError('Lua: Wrong number of parameters passed to RestoreHog!')
+    else
+        begin
+          i := 0;
+          while (i < hiddenHedgehogsNumber) do
+            begin
+            if hiddenHedgehogs[i]^.gearHidden^.uid = lua_tointeger(L, 1) then
+              begin
+                hog := hiddenHedgehogs[i];
+                RestoreHog(hog);
+                dec(hiddenHedgehogsNumber);
+                for j := i to hiddenHedgehogsNumber - 1 do
+                  hiddenHedgehogs[j] := hiddenHedgehogs[j + 1];
+                lc_restorehog := 0;
+                exit;
+              end;
+            inc(i);
+            end;
+        end;
+    lc_restorehog := 0;
+end;
+
 // boolean TestRectForObstacle(x1, y1, x2, y2, landOnly)
 function lc_testrectforobstacle(L : Plua_State) : LongInt; Cdecl;
 var rtn: Boolean;
@@ -2168,6 +2231,10 @@
 ScriptSetInteger('gstInvisible'      ,$00200000);
 
 // register functions
+lua_register(luaState, _P'HideHog', @lc_hidehog);
+lua_register(luaState, _P'RestoreHog', @lc_restorehog);
+lua_register(luaState, _P'SaveCampaignVar', @lc_savecampaignvar);
+lua_register(luaState, _P'GetCampaignVar', @lc_getcampaignvar);
 lua_register(luaState, _P'band', @lc_band);
 lua_register(luaState, _P'bor', @lc_bor);
 lua_register(luaState, _P'bnot', @lc_bnot);
--- a/hedgewars/uVariables.pas	Fri Jun 08 19:25:40 2012 +0200
+++ b/hedgewars/uVariables.pas	Mon Jun 25 10:46:48 2012 +0300
@@ -64,6 +64,7 @@
     fastUntilLag    : boolean;
     autoCameraOn    : boolean;
 
+    CampaignVariable: shortstring;
     GameTicks       : LongWord;
     GameState       : TGameState;
     GameType        : TGameType;
@@ -179,6 +180,8 @@
     hiTicks: Word;
 
     LuaGoals        : shortstring;
+    hiddenHedgehogs : array [0..cMaxHHs] of PHedgehog;
+    hiddenHedgehogsNumber : longint;
 
     VoiceList : array[0..7] of TVoice =  (
                     ( snd: sndNone; voicepack: nil),
@@ -209,7 +212,7 @@
         '',                              // ptData
         'Graphics',                      // ptGraphics
         'Themes',                        // ptThemes
-        'Themes/avematan',               // ptCurrTheme
+        'Themes/Bamboo',                 // ptCurrTheme
         'Teams',                         // ptTeams
         'Maps',                          // ptMaps
         '',                              // ptMapCurrent
@@ -2614,6 +2617,7 @@
     GrayScale:= false;
 
     LuaGoals:= '';
+    hiddenHedgehogsNumber:=0;
 end;
 
 procedure freeModule;