summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorerihel <erihel@gmail.com>2012-08-09 20:20:47 +0200
committererihel <erihel@gmail.com>2012-08-09 20:20:47 +0200
commit611680a72e0f04e080c3b7ed59bd23d5b8b709f1 (patch)
treee27ba7ba84de26777d275969993d46d904eb37e7 /src
parentd56db5f4e4a8e0d572bf3d682619bb25aebe4120 (diff)
parentbc24b9f9e516e657fcc0034808e010287fc2e393 (diff)
downloadcolobot-611680a72e0f04e080c3b7ed59bd23d5b8b709f1.tar.gz
colobot-611680a72e0f04e080c3b7ed59bd23d5b8b709f1.tar.bz2
colobot-611680a72e0f04e080c3b7ed59bd23d5b8b709f1.zip
Merge branch 'dev' of https://github.com/adiblol/colobot into dev
Conflicts: src/sound/sound.h
Diffstat (limited to 'src')
-rw-r--r--src/CBot/CBot.apsbin44112 -> 0 bytes
-rw-r--r--src/CBot/CBot.cpp8036
-rw-r--r--src/CBot/CBot.h3365
-rw-r--r--src/CBot/CBot.rc279
-rw-r--r--src/CBot/CBotAddExpr.cpp286
-rw-r--r--src/CBot/CBotClass.cpp1763
-rw-r--r--src/CBot/CBotCompExpr.cpp264
-rw-r--r--src/CBot/CBotDll.h2317
-rw-r--r--src/CBot/CBotFunction.cpp3295
-rw-r--r--src/CBot/CBotIf.cpp320
-rw-r--r--src/CBot/CBotProgram.cpp2229
-rw-r--r--src/CBot/CBotStack.cpp2946
-rw-r--r--src/CBot/CBotString.cpp1295
-rw-r--r--src/CBot/CBotToken.cpp1116
-rw-r--r--src/CBot/CBotToken.h75
-rw-r--r--src/CBot/CBotTwoOpExpr.cpp1134
-rw-r--r--src/CBot/CBotVar.cpp4493
-rw-r--r--src/CBot/CBotWhile.cpp2860
-rw-r--r--src/CBot/CMakeLists.txt1
-rw-r--r--src/CBot/ClassFILE.cpp854
-rw-r--r--src/CBot/StringFunctions.cpp870
-rw-r--r--src/CBot/_Copy.bat2
-rw-r--r--src/CBot/colobot.ini49
-rw-r--r--src/CBot/idees.txt54
-rw-r--r--src/CBot/old15
-rw-r--r--src/CBot/resource.h357
-rw-r--r--src/CBot/tests/TestCBot/CBotConsoleDlg.cpp (renamed from src/CBot/TestCBot/CBotConsoleDlg.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/CBotConsoleDlg.h (renamed from src/CBot/TestCBot/CBotConsoleDlg.h)0
-rw-r--r--src/CBot/tests/TestCBot/ChildFrm.cpp (renamed from src/CBot/TestCBot/ChildFrm.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/ChildFrm.h (renamed from src/CBot/TestCBot/ChildFrm.h)0
-rw-r--r--src/CBot/tests/TestCBot/MainFrm.cpp (renamed from src/CBot/TestCBot/MainFrm.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/MainFrm.h (renamed from src/CBot/TestCBot/MainFrm.h)0
-rw-r--r--src/CBot/tests/TestCBot/PerformDlg.cpp (renamed from src/CBot/TestCBot/PerformDlg.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/PerformDlg.h (renamed from src/CBot/TestCBot/PerformDlg.h)0
-rw-r--r--src/CBot/tests/TestCBot/Routines.cpp (renamed from src/CBot/TestCBot/Routines.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/StdAfx.cpp (renamed from src/CBot/TestCBot/StdAfx.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/StdAfx.h (renamed from src/CBot/TestCBot/StdAfx.h)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBot.clw (renamed from src/CBot/TestCBot/TestCBot.clw)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBot.cpp (renamed from src/CBot/TestCBot/TestCBot.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBot.dsp (renamed from src/CBot/TestCBot/TestCBot.dsp)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBot.h (renamed from src/CBot/TestCBot/TestCBot.h)4
-rw-r--r--src/CBot/tests/TestCBot/TestCBot.rc (renamed from src/CBot/TestCBot/TestCBot.rc)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBotDoc.cpp (renamed from src/CBot/TestCBot/TestCBotDoc.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBotDoc.h (renamed from src/CBot/TestCBot/TestCBotDoc.h)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBotView.cpp (renamed from src/CBot/TestCBot/TestCBotView.cpp)0
-rw-r--r--src/CBot/tests/TestCBot/TestCBotView.h (renamed from src/CBot/TestCBot/TestCBotView.h)0
-rw-r--r--src/CBot/tests/TestCBot/a§1.txt~ (renamed from src/CBot/TestCBot/a§1.txt)0
-rw-r--r--src/CBot/tests/TestCBot/res/TestCBot.ico (renamed from src/CBot/TestCBot/res/TestCBot.ico)bin1078 -> 1078 bytes
-rw-r--r--src/CBot/tests/TestCBot/res/TestCBot.rc2 (renamed from src/CBot/TestCBot/res/TestCBot.rc2)0
-rw-r--r--src/CBot/tests/TestCBot/res/TestCBotDoc.ico (renamed from src/CBot/TestCBot/res/TestCBotDoc.ico)bin1078 -> 1078 bytes
-rw-r--r--src/CBot/tests/TestCBot/res/Toolbar.bmp (renamed from src/CBot/TestCBot/res/Toolbar.bmp)bin1198 -> 1198 bytes
-rw-r--r--src/CBot/tests/TestCBot/resource.h (renamed from src/CBot/TestCBot/resource.h)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/B.txt (renamed from src/CBot/TestCBot/B.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/BUG2.txt (renamed from src/CBot/TestCBot/BUG2.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/Deleted.txt (renamed from src/CBot/TestCBot/Deleted.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/MaClass.txt (renamed from src/CBot/TestCBot/MaClass.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/Mc2.txt (renamed from src/CBot/TestCBot/Mc2.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/Mon fichier.txt (renamed from src/CBot/TestCBot/Mon fichier.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/Nop.txt (renamed from src/CBot/TestCBot/Nop.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/POS.txt (renamed from src/CBot/TestCBot/POS.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/T.txt (renamed from src/CBot/TestCBot/T.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TESTALL.txt (renamed from src/CBot/TestCBot/TESTALL.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestCB1.txt (renamed from src/CBot/TestCBot/TestCB1.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestCBot1.txt (renamed from src/CBot/TestCBot/TestCBot1.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestCBot3.txt (renamed from src/CBot/TestCBot/TestCBot3.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestNull.txt (renamed from src/CBot/TestCBot/TestNull.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestRestoreState.txt (renamed from src/CBot/TestCBot/TestRestoreState.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestStatic.txt (renamed from src/CBot/TestCBot/TestStatic.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/TestStr.txt (renamed from src/CBot/TestCBot/TestStr.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/Z.txt (renamed from src/CBot/TestCBot/Z.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/a1.txt (renamed from src/CBot/TestCBot/až1.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/array.txt (renamed from src/CBot/TestCBot/array.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/až1.txt96
-rw-r--r--src/CBot/tests/TestCBot/scenarios/a§1.txt96
-rw-r--r--src/CBot/tests/TestCBot/scenarios/bug.txt (renamed from src/CBot/TestCBot/bug.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/bugmw.txt (renamed from src/CBot/TestCBot/bugmw.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/ccc.txt (renamed from src/CBot/TestCBot/ccc.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/enum.txt (renamed from src/CBot/TestCBot/enum.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/fibo.txt (renamed from src/CBot/TestCBot/fibo.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/file.txt (renamed from src/CBot/TestCBot/file.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/h.txt (renamed from src/CBot/TestCBot/h.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/include.txt (renamed from src/CBot/TestCBot/include.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/intrinsic.txt (renamed from src/CBot/TestCBot/intrinsic.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/methode1.txt (renamed from src/CBot/TestCBot/methode1.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/methode2.txt (renamed from src/CBot/TestCBot/methode2.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/mp1.txt (renamed from src/CBot/TestCBot/mp1.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/mp2.txt (renamed from src/CBot/TestCBot/mp2.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/mw.txt (renamed from src/CBot/TestCBot/mw.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/null.txt (renamed from src/CBot/TestCBot/null.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/opnew.txt (renamed from src/CBot/TestCBot/opnew.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/plante.txt (renamed from src/CBot/TestCBot/plante.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/pointer.txt (renamed from src/CBot/TestCBot/pointer.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/postinc.txt (renamed from src/CBot/TestCBot/postinc.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/radar.txt (renamed from src/CBot/TestCBot/radar.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/solution.txt (renamed from src/CBot/TestCBot/solution.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/test.txt (renamed from src/CBot/TestCBot/test.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/test23.txt (renamed from src/CBot/TestCBot/test23.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/testmw.txt (renamed from src/CBot/TestCBot/testmw.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/this.txt (renamed from src/CBot/TestCBot/this.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/tt.txt (renamed from src/CBot/TestCBot/tt.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/tt2.txt (renamed from src/CBot/TestCBot/tt2.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/vide.txt (renamed from src/CBot/TestCBot/vide.txt)0
-rw-r--r--src/CBot/tests/TestCBot/scenarios/zz.txt (renamed from src/CBot/TestCBot/zz.txt)0
-rw-r--r--src/CBot/tests/TestCBot/xTestCBot.clw (renamed from src/CBot/TestCBot/xTestCBot.clw)0
-rw-r--r--src/CBot/tests/old TstCBot/BotConsoleDlg.cpp (renamed from src/CBot/old TstCBot/BotConsoleDlg.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/BotConsoleDlg.h (renamed from src/CBot/old TstCBot/BotConsoleDlg.h)0
-rw-r--r--src/CBot/tests/old TstCBot/BotErrorDlg.cpp (renamed from src/CBot/old TstCBot/BotErrorDlg.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/BotErrorDlg.h (renamed from src/CBot/old TstCBot/BotErrorDlg.h)0
-rw-r--r--src/CBot/tests/old TstCBot/CBotTest.txt (renamed from src/CBot/old TstCBot/CBotTest.txt)0
-rw-r--r--src/CBot/tests/old TstCBot/CMyThread.cpp (renamed from src/CBot/old TstCBot/CMyThread.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/CMyThread.h (renamed from src/CBot/old TstCBot/CMyThread.h)0
-rw-r--r--src/CBot/tests/old TstCBot/MainFrm.cpp (renamed from src/CBot/old TstCBot/MainFrm.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/MainFrm.h (renamed from src/CBot/old TstCBot/MainFrm.h)0
-rw-r--r--src/CBot/tests/old TstCBot/ReadMe.txt (renamed from src/CBot/old TstCBot/ReadMe.txt)0
-rw-r--r--src/CBot/tests/old TstCBot/Resource.h (renamed from src/CBot/old TstCBot/Resource.h)0
-rw-r--r--src/CBot/tests/old TstCBot/StdAfx.cpp (renamed from src/CBot/old TstCBot/StdAfx.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/StdAfx.h (renamed from src/CBot/old TstCBot/StdAfx.h)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBot.clw (renamed from src/CBot/old TstCBot/TstCBot.clw)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBot.cpp (renamed from src/CBot/old TstCBot/TstCBot.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBot.dsp (renamed from src/CBot/old TstCBot/TstCBot.dsp)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBot.h (renamed from src/CBot/old TstCBot/TstCBot.h)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBot.rc (renamed from src/CBot/old TstCBot/TstCBot.rc)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBotDoc.cpp (renamed from src/CBot/old TstCBot/TstCBotDoc.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBotDoc.h (renamed from src/CBot/old TstCBot/TstCBotDoc.h)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBotView.cpp (renamed from src/CBot/old TstCBot/TstCBotView.cpp)0
-rw-r--r--src/CBot/tests/old TstCBot/TstCBotView.h (renamed from src/CBot/old TstCBot/TstCBotView.h)0
-rw-r--r--src/CBot/tests/old TstCBot/res/TstCBot.ico (renamed from src/CBot/old TstCBot/res/TstCBot.ico)bin1078 -> 1078 bytes
-rw-r--r--src/CBot/tests/old TstCBot/res/TstCBot.rc2 (renamed from src/CBot/old TstCBot/res/TstCBot.rc2)0
-rw-r--r--src/CBot/tests/old TstCBot/res/TstCBotDoc.ico (renamed from src/CBot/old TstCBot/res/TstCBotDoc.ico)bin1078 -> 1078 bytes
-rw-r--r--src/CBot/tests/old TstCBot/test complet 1.txt (renamed from src/CBot/old TstCBot/test complet 1.txt)0
-rw-r--r--src/CBot/tests/old TstCBot/x.txt (renamed from src/CBot/old TstCBot/x.txt)0
-rw-r--r--src/CMakeLists.txt73
-rw-r--r--src/app/app.cpp858
-rw-r--r--src/app/app.h238
-rw-r--r--src/app/main.cpp47
-rw-r--r--src/app/system.cpp270
-rw-r--r--src/app/system.h46
-rw-r--r--src/app/system_linux.h101
-rw-r--r--src/app/system_other.h146
-rw-r--r--src/app/system_windows.h122
-rw-r--r--src/common/config.h.cmake18
-rw-r--r--src/common/event.cpp54
-rw-r--r--src/common/event.h290
-rw-r--r--src/common/image.cpp221
-rw-r--r--src/common/image.h84
-rw-r--r--src/common/iman.cpp2
-rw-r--r--src/common/ioutils.h85
-rw-r--r--src/common/key.h (renamed from src/graphics/common/device.h)40
-rw-r--r--src/common/logger.cpp4
-rw-r--r--src/common/logger.h2
-rw-r--r--src/common/misc.h2
-rw-r--r--src/common/modfile.cpp695
-rw-r--r--src/common/modfile.h115
-rw-r--r--src/common/singleton.h12
-rw-r--r--src/common/stringutils.cpp149
-rw-r--r--src/common/stringutils.h77
-rw-r--r--src/common/test/CMakeLists.txt6
-rw-r--r--src/common/test/image_test.cpp34
-rw-r--r--src/graphics/common/README.txt5
-rw-r--r--src/graphics/common/camera.cpp23
-rw-r--r--src/graphics/common/camera.h273
-rw-r--r--src/graphics/common/color.cpp150
-rw-r--r--src/graphics/common/color.h50
-rw-r--r--src/graphics/common/device.cpp14
-rw-r--r--src/graphics/common/engine.cpp73
-rw-r--r--src/graphics/common/engine.h715
-rw-r--r--src/graphics/common/light.cpp22
-rw-r--r--src/graphics/common/light.h115
-rw-r--r--src/graphics/common/model.cpp23
-rw-r--r--src/graphics/common/model.h141
-rw-r--r--src/graphics/common/modfile.cpp23
-rw-r--r--src/graphics/common/modfile.h114
-rw-r--r--src/graphics/common/vertex.h68
-rw-r--r--src/graphics/core/README.txt6
-rw-r--r--src/graphics/core/color.cpp103
-rw-r--r--src/graphics/core/color.h98
-rw-r--r--src/graphics/core/device.h412
-rw-r--r--src/graphics/core/light.h91
-rw-r--r--src/graphics/core/material.h (renamed from src/graphics/common/material.h)3
-rw-r--r--src/graphics/core/texture.h237
-rw-r--r--src/graphics/core/vertex.h141
-rw-r--r--src/graphics/engine/README.txt8
-rw-r--r--src/graphics/engine/camera.cpp1664
-rw-r--r--src/graphics/engine/camera.h386
-rw-r--r--src/graphics/engine/cloud.cpp (renamed from src/graphics/common/cloud.cpp)2
-rw-r--r--src/graphics/engine/cloud.h (renamed from src/graphics/common/cloud.h)2
-rw-r--r--src/graphics/engine/engine.cpp743
-rw-r--r--src/graphics/engine/engine.h1002
-rw-r--r--src/graphics/engine/lightman.cpp416
-rw-r--r--src/graphics/engine/lightman.h181
-rw-r--r--src/graphics/engine/lightning.cpp (renamed from src/graphics/common/lightning.cpp)2
-rw-r--r--src/graphics/engine/lightning.h (renamed from src/graphics/common/lightning.h)0
-rw-r--r--src/graphics/engine/modelfile.cpp841
-rw-r--r--src/graphics/engine/modelfile.h120
-rw-r--r--src/graphics/engine/particle.cpp (renamed from src/graphics/common/particle.cpp)2
-rw-r--r--src/graphics/engine/particle.h (renamed from src/graphics/common/particle.h)109
-rw-r--r--src/graphics/engine/planet.cpp (renamed from src/graphics/common/planet.cpp)2
-rw-r--r--src/graphics/engine/planet.h (renamed from src/graphics/common/planet.h)0
-rw-r--r--src/graphics/engine/pyro.cpp (renamed from src/graphics/common/pyro.cpp)2
-rw-r--r--src/graphics/engine/pyro.h (renamed from src/graphics/common/pyro.h)2
-rw-r--r--src/graphics/engine/terrain.cpp (renamed from src/graphics/common/terrain.cpp)2
-rw-r--r--src/graphics/engine/terrain.h (renamed from src/graphics/common/terrain.h)2
-rw-r--r--src/graphics/engine/test/CMakeLists.txt7
-rw-r--r--src/graphics/engine/test/modelfile_test.cpp48
-rw-r--r--src/graphics/engine/text.cpp (renamed from src/graphics/common/text.cpp)2
-rw-r--r--src/graphics/engine/text.h (renamed from src/graphics/common/text.h)8
-rw-r--r--src/graphics/engine/water.cpp (renamed from src/graphics/common/water.cpp)2
-rw-r--r--src/graphics/engine/water.h (renamed from src/graphics/common/water.h)8
-rw-r--r--src/graphics/opengl/README.txt4
-rw-r--r--src/graphics/opengl/gldevice.cpp1192
-rw-r--r--src/graphics/opengl/gldevice.h176
-rw-r--r--src/graphics/opengl/glengine.cpp21
-rw-r--r--src/graphics/opengl/glengine.h32
-rw-r--r--src/graphics/opengl/test/CMakeLists.txt87
-rw-r--r--src/graphics/opengl/test/README.txt9
-rw-r--r--src/graphics/opengl/test/light_test.cpp437
-rw-r--r--src/graphics/opengl/test/model_test.cpp377
-rw-r--r--src/graphics/opengl/test/tex1.pngbin0 -> 151263 bytes
-rw-r--r--src/graphics/opengl/test/tex2.pngbin0 -> 57503 bytes
-rw-r--r--src/graphics/opengl/test/texture_test.cpp193
-rw-r--r--src/graphics/opengl/test/transform_test.cpp339
-rw-r--r--src/math/func.h38
-rw-r--r--src/math/geometry.h141
-rw-r--r--src/math/intsize.h61
-rw-r--r--src/math/matrix.h20
-rw-r--r--src/math/point.h22
-rw-r--r--src/math/size.h66
-rw-r--r--src/math/vector.h35
-rw-r--r--src/sound/sound.h637
229 files changed, 31492 insertions, 23120 deletions
diff --git a/src/CBot/CBot.aps b/src/CBot/CBot.aps
deleted file mode 100644
index cd294ec..0000000
--- a/src/CBot/CBot.aps
+++ /dev/null
Binary files differ
diff --git a/src/CBot/CBot.cpp b/src/CBot/CBot.cpp
index e2b01a9..62d9fb7 100644
--- a/src/CBot/CBot.cpp
+++ b/src/CBot/CBot.cpp
@@ -1,4072 +1,3964 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// compilation des diverses instructions
-// toutes les routines Compile sont statiques
-// et retournent un object selon ce qui a été trouvé comme instruction
-
-// principe de compilation:
-// les routines Compile retournent un objet de la classe correspondant à l'opération trouvée
-// il s'agit toujours d'une classe fille de CBotInstr.
-// ( les objets CBotInstr ne sont jamais utilisés directement )
-
-// si la routine Compile retourne NULL, c'est que l'instruction est fausse
-// ou incomprise.
-// L'erreur se trouve alors sur la pile CBotCStack::IsOk() est FALSE
-
-
-#include "CBot.h"
-
-
-
-
-// les divers constructeurs / destructeurs
-// pour libérer tout selon l'arbre établi
-CBotInstr::CBotInstr()
-{
- name = "CBotInstr";
- m_next = NULL;
- m_next2b = NULL;
- m_next3 = NULL;
- m_next3b = NULL;
-}
-
-CBotInstr::~CBotInstr()
-{
- delete m_next;
- delete m_next2b;
- delete m_next3;
- delete m_next3b;
-}
-
-// compteur de boucles imbriquées,
-// pour détermniner les break et continue valides
-// et liste des labels utilisables
-
-int CBotInstr::m_LoopLvl = 0;
-CBotStringArray
- CBotInstr::m_labelLvl = CBotStringArray();
-
-// ajoute un niveau avec un label
-void CBotInstr::IncLvl(CBotString& label)
-{
- m_labelLvl.SetSize(m_LoopLvl+1);
- m_labelLvl[m_LoopLvl] = label;
- m_LoopLvl++;
-}
-
-// ajoute un niveau (instruction switch)
-void CBotInstr::IncLvl()
-{
- m_labelLvl.SetSize(m_LoopLvl+1);
- m_labelLvl[m_LoopLvl] = "#SWITCH";
- m_LoopLvl++;
-}
-
-// libère un niveau
-void CBotInstr::DecLvl()
-{
- m_LoopLvl--;
- m_labelLvl[m_LoopLvl].Empty();
-}
-
-// controle la validité d'un break ou continu
-BOOL CBotInstr::ChkLvl(const CBotString& label, int type)
-{
- int i = m_LoopLvl;
- while (--i>=0)
- {
- if ( type == ID_CONTINUE && m_labelLvl[i] == "#SWITCH") continue;
- if ( label.IsEmpty() ) return TRUE;
- if ( m_labelLvl[i] == label ) return TRUE;
- }
- return FALSE;
-}
-
-BOOL CBotInstr::IsOfClass(CBotString n)
-{
- return name == n;
-}
-
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de base de la classe CBotInstr
-
-// définie le token correspondant à l'instruction
-
-void CBotInstr::SetToken(CBotToken* p)
-{
- m_token = *p;
-}
-
-void CBotInstr::SetToken(CBotString* name, int start, int end)
-{
- SetToken( &CBotToken( *name, CBotString(), start, end));
-}
-
-
-// rend le type du token associé à l'instruction
-
-int CBotInstr::GivTokenType()
-{
- return m_token.GivType();
-}
-
-// rend le token associé
-
-CBotToken* CBotInstr::GivToken()
-{
- return &m_token;
-}
-
-// ajoute une instruction à la suite des autres
-
-void CBotInstr::AddNext(CBotInstr* n)
-{
- CBotInstr* p = this;
- while ( p->m_next != NULL ) p = p->m_next;
- p->m_next = n;
-}
-
-void CBotInstr::AddNext3(CBotInstr* n)
-{
- CBotInstr* p = this;
- while ( p->m_next3 != NULL ) p = p->m_next3;
- p->m_next3 = n;
-}
-
-void CBotInstr::AddNext3b(CBotInstr* n)
-{
- CBotInstr* p = this;
- while ( p->m_next3b != NULL ) p = p->m_next3b;
- p->m_next3b = n;
-}
-
-// donne l'instruction suivante
-
-CBotInstr* CBotInstr::GivNext()
-{
- return m_next;
-}
-
-CBotInstr* CBotInstr::GivNext3()
-{
- return m_next3;
-}
-
-CBotInstr* CBotInstr::GivNext3b()
-{
- return m_next3b;
-}
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction, qui peut être
-// while, do, try, throw, if, for, switch, break, continu, return
-// int, float, boolean, string,
-// déclaration d'une instance d'une classe
-// expression quelconque
-
-CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- if ( p == NULL ) return NULL;
-
- int type = p->GivType(); // quel est le prochaine token ?
-
- // y a-t-il un label ?
- if ( IsOfType( pp, TokenTypVar ) &&
- IsOfType( pp, ID_DOTS ) )
- {
- type = pp->GivType();
- // seules ces instructions acceptent un label
- if (!IsOfTypeList( pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0 ))
- {
- pStack->SetError(TX_LABEL, pp->GivStart());
- return NULL;
- }
- }
-
- // appel la routine de compilation correspondant au token trouvé
- switch (type)
- {
- case ID_WHILE:
- return CBotWhile::Compile(p, pStack);
-
- case ID_FOR:
- return CBotFor::Compile(p, pStack);
-
- case ID_DO:
- return CBotDo::Compile(p, pStack);
-
- case ID_REPEAT:
- return CBotRepeat::Compile(p, pStack);
-
- case ID_BREAK:
- case ID_CONTINUE:
- return CBotBreak::Compile(p, pStack);
-
- case ID_SWITCH:
- return CBotSwitch::Compile(p, pStack);
-
- case ID_TRY:
- return CBotTry::Compile(p, pStack);
-
- case ID_THROW:
- return CBotThrow::Compile(p, pStack);
-
- case ID_DEBUGDD:
- return CBotStartDebugDD::Compile(p, pStack);
-
- case ID_INT:
- return CBotInt::Compile(p, pStack);
-
- case ID_FLOAT:
- return CBotFloat::Compile(p, pStack);
-
- case ID_STRING:
- return CBotIString::Compile(p, pStack);
-
- case ID_BOOLEAN:
- case ID_BOOL:
- return CBotBoolean::Compile(p, pStack);
-
- case ID_IF:
- return CBotIf::Compile(p, pStack);
-
- case ID_RETURN:
- return CBotReturn::Compile(p, pStack);
-
- case ID_ELSE:
- pStack->SetStartError(p->GivStart());
- pStack->SetError(TX_ELSEWITHOUTIF, p->GivEnd());
- return NULL;
-
- case ID_CASE:
- pStack->SetStartError(p->GivStart());
- pStack->SetError(TX_OUTCASE, p->GivEnd());
- return NULL;
- }
-
- pStack->SetStartError(p->GivStart());
-
- // ne doit pas être un mot réservé par DefineNum
- if ( p->GivType() == TokenTypDef )
- {
- pStack->SetError(TX_RESERVED, p);
- return NULL;
- }
-
- // ce peut être une définition d'instance de class
- CBotToken* ppp = p;
- if ( IsOfType( ppp, TokenTypVar ) /* && IsOfType( ppp, TokenTypVar )*/ )
- {
- if ( CBotClass::Find(p) != NULL )
- {
- // oui, compile la déclaration de l'instance
- return CBotClassInst::Compile(p, pStack);
- }
- }
-
- // ce peut être une instruction arithmétique
- CBotInstr* inst = CBotExpression::Compile(p, pStack);
- if (IsOfType(p, ID_SEP))
- {
- return inst;
- }
- pStack->SetError(TX_ENDOF, p->GivStart());
- delete inst;
- return NULL;
-}
-
-BOOL CBotInstr::Execute(CBotStack* &pj)
-{
- CBotString ClassManquante = name;
- ASM_TRAP(); // ne doit jamais passer par cette routine
- // mais utiliser les routines des classes filles
- return FALSE;
-}
-
-BOOL CBotInstr::Execute(CBotStack* &pj, CBotVar* pVar)
-{
- if ( !Execute(pj) ) return FALSE;
- pVar->SetVal( pj->GivVar() );
- return TRUE;
-}
-
-void CBotInstr::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotString ClassManquante = name;
- ASM_TRAP(); // ne doit jamais passer par cette routine
- // mais utiliser les routines des classes filles
-}
-
-
-BOOL CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- ASM_TRAP(); // papa sait pas faire, voir les filles
- return FALSE;
-}
-
-BOOL CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend)
-{
- ASM_TRAP(); // papa sait pas faire, voir les filles
- return FALSE;
-}
-
-void CBotInstr::RestoreStateVar(CBotStack* &pile, BOOL bMain)
-{
- ASM_TRAP(); // papa sait pas faire, voir les filles
-}
-
-// cette routine n'est définie que pour la classe fille CBotCase
-// cela permet de faire l'appel CompCase sur toutes les instructions
-// pour savoir s'il s'agit d'un case pour la valeur désirée.
-
-BOOL CBotInstr::CompCase(CBotStack* &pj, int val)
-{
- return FALSE;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un bloc d'instruction " { i ; i ; } "
-
-// cette classe n'a pas de constructeur, car il n'y a jamais d'instance de cette classe
-// l'objet retourné par Compile est généralement de type CBotListInstr
-
-
-CBotInstr* CBotBlock::Compile(CBotToken* &p, CBotCStack* pStack, BOOL bLocal)
-{
- pStack->SetStartError(p->GivStart());
-
- if (IsOfType(p, ID_OPBLK))
- {
- CBotInstr* inst = CBotListInstr::Compile( p, pStack, bLocal );
-
- if (IsOfType(p, ID_CLBLK))
- {
- return inst;
- }
-
- pStack->SetError(TX_CLOSEBLK, p->GivStart()); // manque la parenthèse
- delete inst;
- return NULL;
- }
-
- pStack->SetError(TX_OPENBLK, p->GivStart());
- return NULL;
-}
-
-CBotInstr* CBotBlock::CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, BOOL bLocal)
-{
- // est-ce un nouveau bloc ?
- if ( p->GivType() == ID_OPBLK ) return CBotBlock::Compile(p, pStack);
-
- // sinon, cherche une instruction unique à la place
-
- // pour gérer les cas avec définition local à l'instructin (*)
- CBotCStack* pStk = pStack->TokenStack(p, bLocal);
-
- return pStack->Return( CBotInstr::Compile(p, pStk), // une instruction unique
- pStk);
-}
-
-// (*) c'est le cas dans l'instruction suivante
-// if ( 1 == 1 ) int x = 0;
-// où la variable x n'est connue que dans le bloc qui suit le if.
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une liste d'instruction, séparés par des points-virgules
-
-CBotListInstr::CBotListInstr()
-{
- m_Instr = NULL;
- name = "CBotListInstr";
-}
-
-CBotListInstr::~CBotListInstr()
-{
- delete m_Instr;
-}
-
-CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, BOOL bLocal)
-{
- CBotCStack* pStk = pStack->TokenStack(p, bLocal); // les variables sont locales
-
- CBotListInstr* inst = new CBotListInstr();
-
- while (TRUE)
- {
- if ( p == NULL ) break;
-
- if (IsOfType(p, ID_SEP)) continue; // instruction vide ignorée
- if ( p->GivType() == ID_CLBLK ) break; // déja plus d'instruction
-
- if (IsOfType(p, 0))
- {
- pStack->SetError(TX_CLOSEBLK, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk ); // compile la suivante
-
- if (!pStk->IsOk())
- {
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- if ( inst->m_Instr == NULL ) inst->m_Instr = i;
- else inst->m_Instr->AddNext(i); // ajoute à la suite
- }
- return pStack->Return(inst, pStk);
-}
-
-// exécute une liste d'instructions
-
-BOOL CBotListInstr::Execute(CBotStack* &pj)
-{
-
- CBotStack* pile = pj->AddStack(this, TRUE);//indispensable pour SetState()
- if ( pile->StackOver() ) return pj->Return( pile );
-
-
- CBotInstr* p = m_Instr; // la première expression
-
- int state = pile->GivState();
- while (state-->0) p = p->GivNext(); // revient sur l'opération interrompue
-
- if ( p != NULL ) while (TRUE)
- {
-// DEBUG( "CBotListInstr", pile->GivState(), pile );
-
- if ( !p->Execute(pile) ) return FALSE;
- p = p->GivNext();
- if ( p == NULL ) break;
- if (!pile->IncState()) ;//return FALSE; // prêt pour la suivante
- }
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-void CBotListInstr::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotInstr* p = m_Instr; // la première expression
-
- int state = pile->GivState();
- while ( p != NULL && state-- > 0)
- {
- p->RestoreState(pile, FALSE);
- p = p->GivNext(); // revient sur l'opération interrompue
- }
-
- if ( p != NULL ) p->RestoreState(pile, TRUE);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compilation d'un élément se trouvant à gauche d'une assignation
-
-CBotLeftExprVar::CBotLeftExprVar()
-{
- name = "CBotLeftExprVar";
- m_typevar = -1;
- m_nIdent = 0;
-}
-
-CBotLeftExprVar::~CBotLeftExprVar()
-{
-}
-
-CBotInstr* CBotLeftExprVar::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- // vérifie que le token est un nom de variable
- if (p->GivType() != TokenTypVar)
- {
- pStack->SetError( TX_NOVAR, p->GivStart());
- return NULL;
- }
-
- CBotLeftExprVar* inst = new CBotLeftExprVar();
- inst->SetToken(p);
- p = p->GivNext();
-
- return inst;
-}
-
-// crée une variable et lui assigne le résultat de la pile
-BOOL CBotLeftExprVar::Execute(CBotStack* &pj)
-{
- CBotVar* var1;
- CBotVar* var2;
-
- var1 = CBotVar::Create(m_token.GivString(), m_typevar);
- var1->SetUniqNum(m_nIdent); // avec cet identificateur unique
- pj->AddVar(var1); // la place sur la pile
-
- var2 = pj->GivVar(); // resultat sur la pile
- if ( var2 ) var1->SetVal(var2); // fait l'assignation
-
- return TRUE; // opération faite
-}
-
-void CBotLeftExprVar::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotVar* var1;
-
- var1 = pj->FindVar(m_token.GivString());
- if ( var1 == NULL ) ASM_TRAP();
-
- var1->SetUniqNum(m_nIdent); // avec cet identificateur unique
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// définition d'un tableau de n'importe quel type
-// int a[12];
-// point x[];
-
-CBotInstArray::CBotInstArray()
-{
- m_var = NULL;
- m_listass = NULL;
- name = "CBotInstArray";
-}
-
-CBotInstArray::~CBotInstArray()
-{
- delete m_var;
- delete m_listass;
-}
-
-
-CBotInstr* CBotInstArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
-{
- CBotCStack* pStk = pStack->TokenStack(p);
-
- CBotInstArray* inst = new CBotInstArray(); // crée l'objet
-
- CBotToken* vartoken = p;
- inst->SetToken(vartoken);
-
- // détermine l'expression valable pour l'élément gauche
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable ?
- {
- pStk->SetError(TX_REDEFVAR, vartoken);
- goto error;
- }
-
- CBotInstr* i;
- while (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- if ( p->GivType() != ID_CLBRK )
- i = CBotExpression::Compile( p, pStk ); // expression pour la valeur
- else
- i = new CBotEmpty(); // spécial si pas de formule
-
- inst->AddNext3b(i); // construit une liste
- type = CBotTypResult(CBotTypArrayPointer, type);
-
- if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ) )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- }
-
- CBotVar* var = CBotVar::Create(vartoken, type); // crée avec une instance
- inst->m_typevar = type;
-
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-
- if ( IsOfType(p, ID_ASS) ) // avec une assignation
- {
- inst->m_listass = CBotListArray::Compile( p, pStk, type.GivTypElem() );
- }
-
- if ( pStk->IsOk() ) return pStack->Return(inst, pStk);
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-
-// exécute la définition d'un tableau
-
-BOOL CBotInstArray::Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this);
-// if ( pile1 == EOX ) return TRUE;
-
- CBotStack* pile = pile1;
-
- if ( pile1->GivState() == 0 )
- {
- // cherche les dimensions max du tableau
- CBotInstr* p = GivNext3b(); // les différentes formules
- int nb = 0;
-
- while (p != NULL)
- {
- pile = pile->AddStack(); // petite place pour travailler
- nb++;
- if ( pile->GivState() == 0 )
- {
- if ( !p->Execute(pile) ) return FALSE; // calcul de la taille // interrompu?
- pile->IncState();
- }
- p = p->GivNext3b();
- }
-
- p = GivNext3b();
- pile = pile1; // revient sur la pile
- int n = 0;
- int max[100];
-
- while (p != NULL)
- {
- pile = pile->AddStack(); // récupère la même petite place
- CBotVar* v = pile->GivVar(); // résultat
- max[n] = v->GivValInt(); // valeur
- if (max[n]>MAXARRAYSIZE)
- {
- pile->SetError(TX_OUTARRAY, &m_token);
- return pj->Return ( pile );
- }
- n++;
- p = p->GivNext3b();
- }
- while (n<100) max[n++] = 0;
-
- m_typevar.SetArray( max ); // mémorise les limitations
-
- // crée simplement un pointeur null
- CBotVar* var = CBotVar::Create(m_var->GivToken(), m_typevar);
- var->SetPointer(NULL);
- var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent);
- pj->AddVar(var); // inscrit le tableau de base sur la pile
-
-#if STACKMEM
- pile1->AddStack()->Delete();
-#else
- delete pile1->AddStack(); // plus besoin des indices
-#endif
- pile1->IncState();
- }
-
- if ( pile1->GivState() == 1 )
- {
- if ( m_listass != NULL ) // il y a des assignation pour ce tableau
- {
- CBotVar* pVar = pj->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if ( !m_listass->Execute(pile1, pVar) ) return FALSE;
- }
- pile1->IncState();
- }
-
- if ( pile1->IfStep() ) return FALSE; // montre ce pas ?
-
- if ( m_next2b &&
- !m_next2b->Execute( pile1 ) ) return FALSE;
-
- return pj->Return( pile1 ); // transmet en dessous
-}
-
-void CBotInstArray::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotStack* pile1 = pj;
-
- CBotVar* var = pj->FindVar(m_var->GivToken()->GivString());
- if ( var != NULL ) var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if ( bMain )
- {
- pile1 = pj->RestoreStack(this);
- CBotStack* pile = pile1;
- if ( pile == NULL ) return;
-
- if ( pile1->GivState() == 0 )
- {
- // cherche les dimensions max du tableau
- CBotInstr* p = GivNext3b(); // les différentes formules
-
- while (p != NULL)
- {
- pile = pile->RestoreStack(); // petite place pour travailler
- if ( pile == NULL ) return;
- if ( pile->GivState() == 0 )
- {
- p->RestoreState(pile, bMain); // calcul de la taille // interrompu!
- return;
- }
- p = p->GivNext3b();
- }
- }
- if ( pile1->GivState() == 1 && m_listass != NULL )
- {
- m_listass->RestoreState(pile1, bMain);
- }
-
- }
-
-
- if ( m_next2b ) m_next2b->RestoreState( pile1, bMain );
-}
-
-// cas particulier pour les indices vides
-BOOL CBotEmpty :: Execute(CBotStack* &pj)
-{
- CBotVar* pVar = CBotVar::Create("", CBotTypInt);
- pVar->SetValInt(-1); // met la valeur -1 sur la pile
- pj->SetVar(pVar);
- return TRUE;
-}
-
-void CBotEmpty :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// définition d'une liste d'initialisation pour un tableau
-// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ;
-
-
-CBotListArray::CBotListArray()
-{
- m_expr = NULL;
- name = "CBotListArray";
-}
-
-CBotListArray::~CBotListArray()
-{
- delete m_expr;
-}
-
-
-CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
-{
- CBotCStack* pStk = pStack->TokenStack(p);
-
- CBotToken* pp = p;
-
- if ( IsOfType( p, ID_NULL ) )
- {
- CBotInstr* inst = new CBotExprNull ();
- inst->SetToken( pp );
-// CBotVar* var = CBotVar::Create("", CBotTypNullPointer);
-// pStk->SetVar(var);
- return pStack->Return(inst, pStk); // ok avec élément vide
- }
-
- CBotListArray* inst = new CBotListArray(); // crée l'objet
-
- if ( IsOfType( p, ID_OPENPAR ) )
- {
- // prend chaque élément l'un après l'autre
- if ( type.Eq( CBotTypArrayPointer ) )
- {
- type = type.GivTypElem();
-
- pStk->SetStartError(p->GivStart());
- if ( NULL == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) ) )
- {
- goto error;
- }
-
- while ( IsOfType( p, ID_COMMA ) ) // d'autres éléments ?
- {
- pStk->SetStartError(p->GivStart());
-
- CBotInstr* i = CBotListArray::Compile( p, pStk, type );
- if ( NULL == i )
- {
- goto error;
- }
-
- inst->m_expr->AddNext3(i);
- }
- }
- else
- {
- pStk->SetStartError(p->GivStart());
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- CBotVar* pv = pStk->GivVar(); // le résultat de l'expression
-
- if ( pv == NULL || !TypesCompatibles( type, pv->GivTypResult() )) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
-
- while ( IsOfType( p, ID_COMMA ) ) // d'autres éléments ?
- {
- pStk->SetStartError(p->GivStart());
-
- CBotInstr* i = CBotTwoOpExpr::Compile( p, pStk ) ;
- if ( NULL == i )
- {
- goto error;
- }
-
- CBotVar* pv = pStk->GivVar(); // le résultat de l'expression
-
- if ( pv == NULL || !TypesCompatibles( type, pv->GivTypResult() )) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- inst->m_expr->AddNext3(i);
- }
- }
-
- if (!IsOfType(p, ID_CLOSEPAR) )
- {
- pStk->SetError(TX_CLOSEPAR, p->GivStart());
- goto error;
- }
-
- return pStack->Return(inst, pStk);
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-
-// exécute la définition d'un tableau
-
-BOOL CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar)
-{
- CBotStack* pile1 = pj->AddStack();
-// if ( pile1 == EOX ) return TRUE;
- CBotVar* pVar2;
-
- CBotInstr* p = m_expr;
-
- int n = 0;
-
- for ( ; p != NULL ; n++, p = p->GivNext3() )
- {
- if ( pile1->GivState() > n ) continue;
-
- pVar2 = pVar->GivItem(n, TRUE);
-
- if ( !p->Execute(pile1, pVar2) ) return FALSE; // évalue l'expression
-
- pile1->IncState();
- }
-
- return pj->Return( pile1 ); // transmet en dessous
-}
-
-void CBotListArray::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain )
- {
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotInstr* p = m_expr;
-
- int state = pile->GivState();
-
- while( state-- > 0 ) p = p->GivNext3() ;
-
- p->RestoreState(pile, bMain); // calcul de la taille // interrompu!
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// définition d'une variable entière
-// int a, b = 12;
-
-CBotInt::CBotInt()
-{
- m_next = NULL; // pour les définitions multiples
- m_var =
- m_expr = NULL;
- name = "CBotInt";
-}
-
-CBotInt::~CBotInt()
-{
- delete m_var;
- delete m_expr;
-// delete m_next; // fait par le destructeur de la classe de base ~CBotInstr()
-}
-
-CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, BOOL first)
-{
- if ( IsOfType(p, ID_OPBRK) )
- {
- if ( !IsOfType(p, ID_CLBRK) )
- {
- pStack->SetError(TX_CLBRK, p->GivStart());
- return NULL;
- }
-
- CBotInstr* inst = CompileArray(p, pStack, CBotTypResult( CBotTypArrayPointer, type ), FALSE);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
- }
-
- // compile une déclaration de tableau
- if (first) return NULL ;
-
- CBotInstr* inst = CBotInstArray::Compile( p, pStack, type );
- if ( inst == NULL ) return NULL;
-
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next2b = CBotInstArray::CompileArray(p, pStack, type, FALSE) )) // compile la suivante
- {
- return inst;
- }
- delete inst;
- return NULL;
- }
-
- if (IsOfType(p, ID_SEP)) // instruction terminée
- {
- return inst;
- }
-
- delete inst;
- pStack->SetError(TX_ENDOF, p->GivStart());
- return NULL;
-}
-
-CBotInstr* CBotInt::Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont, BOOL noskip)
-{
- CBotToken* pp = cont ? NULL : p; // pas de répétition du token "int"
-
- if (!cont && !IsOfType(p, ID_INT)) return NULL;
-
- CBotInt* inst = (CBotInt*)CompileArray(p, pStack, CBotTypInt);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotInt(); // crée l'objet
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- inst->SetToken( vartoken );
-
- // détermine l'expression valable pour l'élément gauche
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypInt;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetError(TX_REDEFVAR, vartoken);
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- delete inst; // n'est pas de type CBotInt
- p = vartoken; // revient sur le nom de la variable
-
- // compile une déclaration de tableau
-
- CBotInstr* inst2 = CBotInstArray::Compile( p, pStk, CBotTypInt );
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
-
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst2->m_next2b = CBotInt::Compile(p, pStk, TRUE, noskip) )) // compile la suivante
- {
- return pStack->Return(inst2, pStk);
- }
- }
- inst = (CBotInt*)inst2;
- goto suite; // pas d'assignation, variable déjà créée
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- if ( pStk->GivType() >= CBotTypBoolean ) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- }
-
- {
- CBotVar* var = CBotVar::Create(vartoken, CBotTypInt);// crée la variable (après l'assignation évaluée)
- var->SetInit(inst->m_expr != NULL); // la marque initialisée si avec assignation
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
- }
-
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next2b = CBotInt::Compile(p, pStk, TRUE, noskip) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-suite:
- if (noskip || IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute la définition de la variable entière
-
-BOOL CBotInt::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); //indispensable pour SetState()
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return FALSE; // valeur initiale // interrompu?
- m_var->Execute( pile ); // crée et fait l'assigation du résultat
-
- if (!pile->SetState(1)) return FALSE;
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return FALSE; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-void CBotInt::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotStack* pile = pj;
- if ( bMain )
- {
- pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain); // valeur initiale // interrompu!
- return;
- }
- }
-
- m_var->RestoreState(pile, bMain);
-
- if ( m_next2b ) m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// définition d'une variable booléen
-// int a, b = false;
-
-CBotBoolean::CBotBoolean()
-{
- m_var =
- m_expr = NULL;
- name = "CBotBoolean";
-}
-
-CBotBoolean::~CBotBoolean()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotBoolean::Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont, BOOL noskip)
-{
- CBotToken* pp = cont ? NULL : p;
-
- if (!cont && !IsOfType(p, ID_BOOLEAN, ID_BOOL)) return NULL;
-
- CBotBoolean* inst = (CBotBoolean*)CompileArray(p, pStack, CBotTypBoolean);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotBoolean();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- inst->SetToken( vartoken );
- CBotVar* var = NULL;
-
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypBoolean;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetError(TX_REDEFVAR, vartoken);
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- delete inst; // n'est pas de type CBotInt
- p = vartoken; // revient sur le nom de la variable
-
- // compile une déclaration de tableau
-
- inst = (CBotBoolean*)CBotInstArray::Compile( p, pStk, CBotTypBoolean );
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // pas d'assignation, variable déjà créée
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- if ( !pStk->GivTypResult().Eq(CBotTypBoolean) ) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- }
-
- var = CBotVar::Create(vartoken, CBotTypBoolean);// crée la variable (après l'assignation évaluée)
- var->SetInit(inst->m_expr != NULL); // la marque initialisée si avec assignation
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-suite:
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next2b = CBotBoolean::Compile(p, pStk, TRUE, noskip) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (noskip || IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute une définition de variable booléenne
-
-BOOL CBotBoolean::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);//indispensable pour SetState()
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return FALSE; // valeur initiale // interrompu?
- m_var->Execute( pile ); // crée et fait l'assigation du résultat
-
- if (!pile->SetState(1)) return FALSE;
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return FALSE; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-void CBotBoolean::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotStack* pile = pj;
- if ( bMain )
- {
- pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain); // valeur initiale interrompu?
- return;
- }
- }
-
- m_var->RestoreState( pile, bMain ); //
-
- if ( m_next2b )
- m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// définition d'une variable réelle
-// int a, b = 12.4;
-
-CBotFloat::CBotFloat()
-{
- m_var =
- m_expr = NULL;
- name = "CBotFloat";
-}
-
-CBotFloat::~CBotFloat()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotFloat::Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont, BOOL noskip)
-{
- CBotToken* pp = cont ? NULL : p;
-
- if (!cont && !IsOfType(p, ID_FLOAT)) return NULL;
-
- CBotFloat* inst = (CBotFloat*)CompileArray(p, pStack, CBotTypFloat);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotFloat();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- CBotVar* var = NULL;
- inst->SetToken(vartoken);
-
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypFloat;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- delete inst; // n'est pas de type CBotInt
- p = vartoken; // revient sur le nom de la variable
-
- // compile une déclaration de tableau
-
- inst = (CBotFloat*)CBotInstArray::Compile( p, pStk, CBotTypFloat );
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // pas d'assignation, variable déjà créée
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- if ( pStk->GivType() >= CBotTypBoolean ) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
- }
-
- var = CBotVar::Create(vartoken, CBotTypFloat); // crée la variable (après l'assignation évaluée)
- var->SetInit(inst->m_expr != NULL); // la marque initialisée si avec assignation
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-suite:
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next2b = CBotFloat::Compile(p, pStk, TRUE, noskip) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (noskip || IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute la défintion de la variable réelle
-
-BOOL CBotFloat::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);//indispensable pour SetState()
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return FALSE; // valeur initiale // interrompu?
- m_var->Execute( pile ); // crée et fait l'assigation du résultat
-
- if (!pile->SetState(1)) return FALSE;
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return FALSE; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-void CBotFloat::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotStack* pile = pj;
- if ( bMain )
- {
- pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain); // valeur initiale interrompu?
- return;
- }
- }
-
- m_var->RestoreState( pile, bMain ); //
-
- if ( m_next2b )
- m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// définition d'une variable chaîne de caractères
-// int a, b = "salut";
-
-CBotIString::CBotIString()
-{
- m_var =
- m_expr = NULL;
- name = "CBotIString";
-}
-
-CBotIString::~CBotIString()
-{
- delete m_var;
- delete m_expr;
-}
-
-CBotInstr* CBotIString::Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont, BOOL noskip)
-{
- CBotToken* pp = cont ? NULL : p;
-
- if (!cont && !IsOfType(p, ID_STRING)) return NULL;
-
- CBotIString* inst = (CBotIString*)CompileArray(p, pStack, CBotTypString);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- inst = new CBotIString();
-
- inst->m_expr = NULL;
-
- CBotToken* vartoken = p;
- inst->SetToken( vartoken );
-
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypString;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
-/* if ( !pStk->GivTypResult().Eq(CBotTypString) ) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }*/
- }
-
- CBotVar* var = CBotVar::Create(vartoken, CBotTypString); // crée la variable (après l'assignation évaluée)
- var->SetInit(inst->m_expr != NULL); // la marque initialisée si avec assignation
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next2b = CBotIString::Compile(p, pStk, TRUE, noskip) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (noskip || IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute la définition de la variable string
-
-BOOL CBotIString::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);//indispensable pour SetState()
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState()==0)
- {
- if (m_expr && !m_expr->Execute(pile)) return FALSE; // valeur initiale // interrompu?
- m_var->Execute( pile ); // crée et fait l'assigation du résultat
-
- if (!pile->SetState(1)) return FALSE;
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- if ( m_next2b &&
- !m_next2b->Execute(pile)) return FALSE; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-void CBotIString::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotStack* pile = pj;
-
- if ( bMain )
- {
- pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState()==0)
- {
- if (m_expr) m_expr->RestoreState(pile, bMain); // valeur initiale interrompu?
- return;
- }
- }
-
- m_var->RestoreState( pile, bMain ); //
-
- if ( m_next2b )
- m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une instruction de type " x = 123 " ou " z * 5 + 4 "
-// avec ou sans assignation donc
-
-CBotExpression::CBotExpression()
-{
- m_leftop = NULL;
- m_rightop = NULL;
- name = "CBotExpression";
-}
-
-CBotExpression::~CBotExpression()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- CBotExpression* inst = new CBotExpression();
-
- inst->m_leftop = CBotLeftExpr::Compile(p, pStack);
-
- inst->SetToken(p);
- int OpType = p->GivType();
-
- if ( pStack->IsOk() &&
- IsOfTypeList(p, ID_ASS, ID_ASSADD, ID_ASSSUB, ID_ASSMUL, ID_ASSDIV, ID_ASSMODULO,
- ID_ASSAND, ID_ASSXOR, ID_ASSOR,
- ID_ASSSL , ID_ASSSR, ID_ASSASR, 0 ))
- {
- if ( inst->m_leftop == NULL )
- {
- pStack->SetError(TX_BADLEFT, p->GivEnd());
- delete inst;
- return NULL;
- }
-
- inst->m_rightop = CBotExpression::Compile(p, pStack);
- if (inst->m_rightop == NULL)
- {
- delete inst;
- return NULL;
- }
-
- CBotTypResult type1 = pStack->GivTypResult();
-
- // récupère la variable pour la marquer assignée
- CBotVar* var = NULL;
- inst->m_leftop->ExecuteVar(var, pStack);
- if ( var == NULL )
- {
- delete inst;
- return NULL;
- }
-
- if (OpType != ID_ASS && var->GivInit() != IS_DEF)
- {
- pStack->SetError(TX_NOTINIT, pp);
- delete inst;
- return NULL;
- }
-
- CBotTypResult type2 = var->GivTypResult();
-
- // quels sont les types acceptables ?
- switch (OpType)
- {
- case ID_ASS:
- // if (type2 == CBotTypClass) type2 = -1; // pas de classe
- if ( (type1.Eq(CBotTypPointer) && type2.Eq(CBotTypPointer) ) ||
- (type1.Eq(CBotTypClass) && type2.Eq(CBotTypClass) ) )
- {
-/* CBotClass* c1 = type1.GivClass();
- CBotClass* c2 = type2.GivClass();
- if ( !c1->IsChildOf(c2) ) type2.SetType(-1); // pas la même classe
-//- if ( !type1.Eq(CBotTypClass) ) var->SetPointer(pStack->GivVar()->GivPointer());*/
- var->SetInit(2);
- }
- else
- var->SetInit(TRUE);
-
- break;
- case ID_ASSADD:
- if (type2.Eq(CBotTypBoolean) ||
- type2.Eq(CBotTypPointer) ) type2 = -1; // nombres et chaines
- break;
- case ID_ASSSUB:
- case ID_ASSMUL:
- case ID_ASSDIV:
- case ID_ASSMODULO:
- if (type2.GivType() >= CBotTypBoolean) type2 = -1; // nombres uniquement
- break;
- }
-
- if (!TypeCompatible( type1, type2, OpType ))
- {
- pStack->SetError(TX_BADTYPE, &inst->m_token);
- delete inst;
- return NULL;
- }
-
- return inst; // types compatibles ?
- }
-
- delete inst;
-// p = p->GivNext();
- int start, end, error = pStack->GivError(start, end);
-
- p = pp; // revient au début
- pStack->SetError(0,0); // oublie l'erreur
-
-// return CBotTwoOpExpr::Compile(p, pStack); // essaie sans assignation
- CBotInstr* i = CBotTwoOpExpr::Compile(p, pStack); // essaie sans assignation
- if ( i != NULL && error == TX_PRIVATE && p->GivType() == ID_ASS )
- pStack->ResetError( error, start, end );
- return i;
-}
-
-// exécute une expression avec assignation
-
-BOOL CBotExpression::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- CBotToken* pToken = m_leftop->GivToken();
- CBotVar* pVar = NULL;
-
- CBotStack* pile1 = pile;
-
- BOOL IsInit = TRUE;
- CBotVar* result = NULL;
-
- // doit être fait avant pour les indices éventuels (pile peut être changée)
- if ( !m_leftop->ExecuteVar(pVar, pile, NULL, FALSE) ) return FALSE; // variable avant évaluation de la valeur droite
-
-// DEBUG( "CBotExpression::Execute", -1, pj);
- if ( pile1->GivState()==0)
- {
- pile1->SetCopyVar(pVar); // garde une copie sur la pile (si interrompu)
- pile1->IncState();
- }
-
- CBotStack* pile2 = pile->AddStack(); // attention pile et surtout pas pile1
-
- if ( pile2->GivState()==0)
- {
-// DEBUG( "CBotExpression::Execute", -2, pj);
- if (m_rightop && !m_rightop->Execute(pile2)) return FALSE; // valeur initiale // interrompu?
- pile2->IncState();
- }
-
- if ( pile1->GivState() == 1 )
- {
-// DEBUG( "CBotExpression::Execute", -3, pj);
- if ( m_token.GivType() != ID_ASS )
- {
- pVar = pile1->GivVar(); // récupére si interrompu
- IsInit = pVar->GivInit();
- if ( IsInit == IS_NAN )
- {
- pile2->SetError(TX_OPNAN, m_leftop->GivToken());
- return pj->Return(pile2);
- }
- result = CBotVar::Create("", pVar->GivTypResult(2));
- }
-
- switch ( m_token.GivType() )
- {
- case ID_ASS:
- break;
- case ID_ASSADD:
- result->Add(pile1->GivVar(), pile2->GivVar()); // additionne
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSSUB:
- result->Sub(pile1->GivVar(), pile2->GivVar()); // soustrait
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSMUL:
- result->Mul(pile1->GivVar(), pile2->GivVar()); // multiplie
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSDIV:
- if (IsInit &&
- result->Div(pile1->GivVar(), pile2->GivVar())) // divise
- pile2->SetError(TX_DIVZERO, &m_token);
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSMODULO:
- if (IsInit &&
- result->Modulo(pile1->GivVar(), pile2->GivVar())) // reste de la division
- pile2->SetError(TX_DIVZERO, &m_token);
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSAND:
- result->And(pile1->GivVar(), pile2->GivVar()); // multiplie
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSXOR:
- result->XOr(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSOR:
- result->Or(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSSL:
- result->SL(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSSR:
- result->SR(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result); // re-place le résultat
- break;
- case ID_ASSASR:
- result->ASR(pile1->GivVar(), pile2->GivVar());
- pile2->SetVar(result); // re-place le résultat
- break;
- default:
- ASM_TRAP();
- }
- if (!IsInit)
- pile2->SetError(TX_NOTINIT, m_leftop->GivToken());
-
- pile1->IncState();
- }
-
-// DEBUG( "CBotExpression::Execute", -4, pj);
- if ( !m_leftop->Execute( pile2, pile1 ) )
- return FALSE; // crée et fait l'assigation du résultat
-
- return pj->Return( pile2 ); // transmet en dessous
-}
-
-
-void CBotExpression::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain )
- {
- CBotToken* pToken = m_leftop->GivToken();
- CBotVar* pVar = NULL;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotStack* pile1 = pile;
-
-
- if ( pile1->GivState()==0)
- {
- m_leftop->RestoreStateVar(pile, TRUE); // variable avant évaluation de la valeur droite
- return;
- }
-
- m_leftop->RestoreStateVar(pile, FALSE); // variable avant évaluation de la valeur droite
-
- CBotStack* pile2 = pile->RestoreStack(); // attention pile et surtout pas pile1
- if ( pile2 == NULL ) return;
-
- if ( pile2->GivState()==0)
- {
- if (m_rightop) m_rightop->RestoreState(pile2, bMain); // valeur initiale // interrompu?
- return;
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une instruction de type " ( condition ) "
-// la condition doit être de type booléen
-
-// cette classe n'a pas de constructeur, car il n'y a jamais d'instance de cette classe
-// l'objet retourné par Compile est généralement de type CBotExpression
-
-CBotInstr* CBotCondition::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
- if ( IsOfType(p, ID_OPENPAR ))
- {
- CBotInstr* inst = CBotBoolExpr::Compile( p, pStack );
- if ( NULL != inst )
- {
- if ( IsOfType(p, ID_CLOSEPAR ))
- {
- return inst;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart()); // manque la parenthèse
- }
- delete inst;
- }
-
- pStack->SetError(TX_OPENPAR, p->GivStart()); // manque la parenthèse
-
- return NULL;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une instruction de type " condition "
-// la condition doit être de type booléen
-
-// cette classe n'a pas de constructeur, car il n'y a jamais d'instance de cette classe
-// l'objet retourné par Compile est généralement de type CBotExpression
-
-CBotInstr* CBotBoolExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
-
- CBotInstr* inst = CBotTwoOpExpr::Compile( p, pStack );
-
- if ( NULL != inst )
- {
- if ( pStack->GivTypResult().Eq(CBotTypBoolean) )
- {
- return inst;
- }
- pStack->SetError(TX_NOTBOOL, p->GivStart()); // n'est pas un booléan
- }
-
- delete inst;
- return NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile soit :
-// une instruction entre parenthèses (...)
-// une expression unaire (négatif, not)
-// nom de variable
-// les variables prè et post incrémentées ou décrémentées
-// un nombre donné par DefineNum
-// une constante
-// un appel de procédure
-// l'instruction new
-
-// cette classe n'a pas de constructeur, car il n'y a jamais d'instance de cette classe
-// l'objet retourné par Compile est de la classe correspondant à l'instruction
-
-CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(p->GivStart());
-
- // est-ce une expression entre parenthèse ?
- if (IsOfType(p, ID_OPENPAR))
- {
- CBotInstr* inst = CBotExpression::Compile( p, pStk );
-
- if ( NULL != inst )
- {
- if (IsOfType(p, ID_CLOSEPAR))
- {
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_CLOSEPAR, p->GivStart());
- }
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- // est-ce une opération unaire ?
- CBotInstr* inst = CBotExprUnaire::Compile(p, pStk);
- if (inst != NULL || !pStk->IsOk())
- return pStack->Return(inst, pStk);
-
- // est-ce un nom de variable ?
- if (p->GivType() == TokenTypVar)
- {
- // c'est peut-être un appel de méthode sans le "this." devant
- inst = CBotExprVar::CompileMethode(p, pStk);
- if ( inst != NULL ) return pStack->Return(inst, pStk);
-
-
- // est-ce un appel de procédure ?
- inst = CBotInstrCall::Compile(p, pStk);
- if ( inst != NULL || !pStk->IsOk() )
- return pStack->Return(inst, pStk);
-
-
- CBotToken* pvar = p;
- // non, c'est une variable "ordinaire"
- inst = CBotExprVar::Compile(p, pStk);
-
- CBotToken* pp = p;
- // post incrémenté ou décrémenté ?
- if (IsOfType(p, ID_INC, ID_DEC))
- {
- if ( pStk->GivType() >= CBotTypBoolean )
- {
- pStk->SetError(TX_BADTYPE, pp);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- // recompile la variable pour read-only
- delete inst;
- p = pvar;
- inst = CBotExprVar::Compile(p, pStk, PR_READ);
- p = p->GivNext();
-
- CBotPostIncExpr* i = new CBotPostIncExpr();
- i->SetToken(pp);
- i->m_Instr = inst; // instruction associée
- return pStack->Return(i, pStk);
- }
- return pStack->Return(inst, pStk);
- }
-
- // est-ce une variable préincrémentée ou prédécrémentée ?
- CBotToken* pp = p;
- if (IsOfType(p, ID_INC, ID_DEC))
- {
- CBotPreIncExpr* i = new CBotPreIncExpr();
- i->SetToken(pp);
-
- if (p->GivType() == TokenTypVar)
- {
- if (NULL != (i->m_Instr = CBotExprVar::Compile(p, pStk, PR_READ)))
- {
- if ( pStk->GivType() >= CBotTypBoolean )
- {
- pStk->SetError(TX_BADTYPE, pp);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- return pStack->Return(i, pStk);
- }
- delete i;
- return pStack->Return(NULL, pStk);
- }
- }
-
- // est-ce un nombre ou un DefineNum ?
- if (p->GivType() == TokenTypNum ||
- p->GivType() == TokenTypDef )
- {
- CBotInstr* inst = CBotExprNum::Compile( p, pStk );
- return pStack->Return(inst, pStk);
- }
-
- // est-ce une chaine ?
- if (p->GivType() == TokenTypString)
- {
- CBotInstr* inst = CBotExprAlpha::Compile(p, pStk);
- return pStack->Return(inst, pStk);
- }
-
- // est un élément "true" ou "false"
- if (p->GivType() == ID_TRUE ||
- p->GivType() == ID_FALSE )
- {
- CBotInstr* inst = CBotExprBool::Compile( p, pStk );
- return pStack->Return(inst, pStk);
- }
-
- // est un objet à créer avec new
- if (p->GivType() == ID_NEW)
- {
- CBotInstr* inst = CBotNew::Compile( p, pStk );
- return pStack->Return(inst, pStk);
- }
-
- // est un pointeur nul
- if (IsOfType( p, ID_NULL ))
- {
- CBotInstr* inst = new CBotExprNull ();
- inst->SetToken( pp );
- CBotVar* var = CBotVar::Create("", CBotTypNullPointer);
- pStk->SetVar(var);
- return pStack->Return(inst, pStk);
- }
-
- // est un nombre nan
- if (IsOfType( p, ID_NAN ))
- {
- CBotInstr* inst = new CBotExprNan ();
- inst->SetToken( pp );
- CBotVar* var = CBotVar::Create("", CBotTypInt);
- var->SetInit(IS_NAN);
- pStk->SetVar(var);
- return pStack->Return(inst, pStk);
- }
-
-
- return pStack->Return(NULL, pStk);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// gestion du post et pré- incrément/décrément
-
-// il n'y a pas de routine Compile, l'objet est créé directement
-// dans CBotParExpr::Compile
-
-CBotPostIncExpr::CBotPostIncExpr()
-{
- m_Instr = NULL;
- name = "CBotPostIncExpr";
-}
-
-CBotPostIncExpr::~CBotPostIncExpr()
-{
- delete m_Instr;
-}
-
-CBotPreIncExpr::CBotPreIncExpr()
-{
- m_Instr = NULL;
- name = "CBotPreIncExpr";
-}
-
-CBotPreIncExpr::~CBotPreIncExpr()
-{
- delete m_Instr;
-}
-
-BOOL CBotPostIncExpr::Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this);
- CBotStack* pile2 = pile1;
-
- CBotVar* var1 = NULL;
-
- if ( !((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, TRUE) ) return FALSE; // récupère la variable selon champs et index
-
- pile1->SetState(1);
- pile1->SetCopyVar(var1); // place le résultat (avant incrémentation);
-
- CBotStack* pile3 = pile2->AddStack(this);
- if ( pile3->IfStep() ) return FALSE;
-
- if ( var1->GivInit() == IS_NAN )
- {
- pile1->SetError( TX_OPNAN, &m_token );
- }
-
- if ( var1->GivInit() != IS_DEF )
- {
- pile1->SetError( TX_NOTINIT, &m_token );
- }
-
- if (GivTokenType() == ID_INC) var1->Inc();
- else var1->Dec();
-
- return pj->Return(pile1); // opération faite, résultat sur pile2
-}
-
-void CBotPostIncExpr::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile1 = pj->RestoreStack(this);
- if ( pile1 == NULL ) return;
-
- ((CBotExprVar*)m_Instr)->RestoreStateVar(pile1, bMain);
-
- if ( pile1 != NULL ) pile1->RestoreStack(this);
-}
-
-BOOL CBotPreIncExpr::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- CBotVar* var1;
-
- if ( pile->GivState() == 0 )
- {
- CBotStack* pile2 = pile;
- if ( !((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, TRUE) ) return FALSE; // récupère la variable selon champs et index
- // pile2 est modifié en retour
-
- if ( var1->GivInit() == IS_NAN )
- {
- pile->SetError( TX_OPNAN, &m_token );
- return pj->Return(pile); // opération faite
- }
-
- if ( var1->GivInit() != IS_DEF )
- {
- pile->SetError( TX_NOTINIT, &m_token );
- return pj->Return(pile); // opération faite
- }
-
- if (GivTokenType() == ID_INC) var1->Inc();
- else var1->Dec(); // ((CBotVarInt*)var1)->m_val
-
- pile->IncState();
- }
-
- if ( !m_Instr->Execute(pile) ) return FALSE;
- return pj->Return(pile); // opération faite
-}
-
-
-void CBotPreIncExpr::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- return;
- }
-
- m_Instr->RestoreState(pile, bMain);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une expression unaire
-// +
-// -
-// not
-// !
-// ~
-
-CBotExprUnaire::CBotExprUnaire()
-{
- m_Expr = NULL;
- name = "CBotExprUnaire";
-}
-
-CBotExprUnaire::~CBotExprUnaire()
-{
- delete m_Expr;
-}
-
-CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- int op = p->GivType();
- CBotToken* pp = p;
- if ( !IsOfTypeList( p, ID_ADD, ID_SUB, ID_LOG_NOT, ID_TXT_NOT, ID_NOT, 0 ) ) return NULL;
-
- CBotCStack* pStk = pStack->TokenStack(pp);
-
- CBotExprUnaire* inst = new CBotExprUnaire();
- inst->SetToken(pp);
-
- if ( NULL != (inst->m_Expr = CBotParExpr::Compile( p, pStk )) )
- {
- if ( op == ID_ADD && pStk->GivType() < CBotTypBoolean ) // seulement avec des nombre
- return pStack->Return(inst, pStk);
- if ( op == ID_SUB && pStk->GivType() < CBotTypBoolean ) // seulement avec des nombre
- return pStack->Return(inst, pStk);
- if ( op == ID_NOT && pStk->GivType() < CBotTypFloat ) // seulement avec des entiers
- return pStack->Return(inst, pStk);
- if ( op == ID_LOG_NOT && pStk->GivTypResult().Eq(CBotTypBoolean) )// seulement avec des booléens
- return pStack->Return(inst, pStk);
- if ( op == ID_TXT_NOT && pStk->GivTypResult().Eq(CBotTypBoolean) )// seulement avec des booléens
- return pStack->Return(inst, pStk);
-
- pStk->SetError(TX_BADTYPE, &inst->m_token);
- }
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute l'expresson unaire
-
-BOOL CBotExprUnaire::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState() == 0 )
- {
- if (!m_Expr->Execute( pile )) return FALSE; // interrompu ?
- pile->IncState();
- }
-
- CBotStack* pile2 = pile->AddStack();
- if ( pile2->IfStep() ) return FALSE;
-
- CBotVar* var = pile->GivVar(); // récupère le résultat sur la pile
-
- switch (GivTokenType())
- {
- case ID_ADD:
- break; // ne fait donc rien
- case ID_SUB:
- var->Neg(); // change le signe
- break;
- case ID_NOT:
- case ID_LOG_NOT:
- case ID_TXT_NOT:
- var->Not();
- break;
- }
- return pj->Return(pile); // transmet en dessous
-}
-
-void CBotExprUnaire::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL) return;
-
- if ( pile->GivState() == 0 )
- {
- m_Expr->RestoreState( pile, bMain ); // interrompu ici !
- return;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// gestion des index pour les tableaux
-// array [ expression ]
-
-
-CBotIndexExpr::CBotIndexExpr()
-{
- m_expr = NULL;
- name = "CBotIndexExpr";
-}
-
-CBotIndexExpr::~CBotIndexExpr()
-{
- delete m_expr;
-}
-
-// trouve un champ à partir de l'instance à la compilation
-
-BOOL CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- if ( pVar->GivType(1) != CBotTypArrayPointer )
- ASM_TRAP();
-
- pVar = ((CBotVarArray*)pVar)->GivItem(0, FALSE); // à la compilation rend l'élément [0]
- if ( pVar == NULL )
- {
- pile->SetError(TX_OUTARRAY, m_token.GivEnd());
- return FALSE;
- }
- if ( m_next3 != NULL ) return m_next3->ExecuteVar(pVar, pile);
- return TRUE;
-}
-
-// idem à l'exécution
-// attention, modifie le pointeur à la pile volontairement
-// place les index calculés sur la pile supplémentaire
-
-BOOL CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend)
-{
- CBotStack* pj = pile;
-// DEBUG( "CBotIndexExpr::ExecuteVar", -1 , pj);
-
- if ( pVar->GivType(1) != CBotTypArrayPointer )
- ASM_TRAP();
-
- pile = pile->AddStack();
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_expr->Execute(pile) ) return FALSE;
- pile->IncState();
- }
- // traite les tableaux
-
- CBotVar* p = pile->GivVar(); // résultat sur la pile
-
- if ( p == NULL || p->GivType() > CBotTypDouble )
- {
- pile->SetError(TX_BADINDEX, prevToken);
- return pj->Return(pile);
- }
-
- int n = p->GivValInt(); // position dans le tableau
-// DEBUG( "CBotIndexExpr::ExecuteVar", n , pj);
-
- pVar = ((CBotVarArray*)pVar)->GivItem(n, bExtend);
- if ( pVar == NULL )
- {
- pile->SetError(TX_OUTARRAY, prevToken);
- return pj->Return(pile);
- }
-
-// DEBUG( "CBotIndexExpr::ExecuteVar", -2 , pj);
- //if ( bUpdate )
- pVar->Maj(pile->GivPUser(), TRUE);
-
-// DEBUG( "CBotIndexExpr::ExecuteVar", -3 , pj);
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile, prevToken, bStep, bExtend) ) return FALSE;
-
-// DEBUG( "CBotIndexExpr::ExecuteVar", -4 , pj);
- return TRUE; // ne libère pas la pile
- // pour éviter de recalculer les index deux fois le cas échéant
-}
-
-void CBotIndexExpr::RestoreStateVar(CBotStack* &pile, BOOL bMain)
-{
- pile = pile->RestoreStack();
- if ( pile == NULL ) return;
-
- if ( bMain && pile->GivState() == 0 )
- {
- m_expr->RestoreState(pile, TRUE);
- return;
- }
-
- if ( m_next3 )
- m_next3->RestoreStateVar(pile, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// gestion des champs dans une instance (opérateur point)
-// toto.x
-
-
-CBotFieldExpr::CBotFieldExpr()
-{
- name = "CBotFieldExpr";
- m_nIdent = 0;
-}
-
-CBotFieldExpr::~CBotFieldExpr()
-{
-}
-
-void CBotFieldExpr::SetUniqNum(int num)
-{
- m_nIdent = num;
-}
-
-
-// trouve un champ à partir de l'instance à la compilation
-
-BOOL CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- if ( pVar->GivType(1) != CBotTypPointer )
- ASM_TRAP();
-
-// pVar = pVar->GivItem(m_token.GivString());
- pVar = pVar->GivItemRef(m_nIdent);
- if ( pVar == NULL )
- {
- pile->SetError(TX_NOITEM, &m_token);
- return FALSE;
- }
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile) ) return FALSE;
-
- return TRUE;
-}
-
-// idem à l'exécution
-
-BOOL CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend)
-{
- CBotStack* pj = pile;
- pile = pile->AddStack(this); // modifie pile en sortie
- if ( pile == EOX ) return TRUE;
-
-// DEBUG( "CBotFieldExpre::ExecuteVar "+m_token.GivString(), 0, pj );
-
- if ( pVar->GivType(1) != CBotTypPointer )
- ASM_TRAP();
-
- CBotVarClass* pItem = pVar->GivPointer();
- if ( pItem == NULL )
- {
- pile->SetError(TX_NULLPT, prevToken);
- return pj->Return( pile );
- }
- if ( pItem->GivUserPtr() == OBJECTDELETED )
- {
- pile->SetError(TX_DELETEDPT, prevToken);
- return pj->Return( pile );
- }
-
- if ( bStep && pile->IfStep() ) return FALSE;
-
-// pVar = pVar->GivItem(m_token.GivString());
- pVar = pVar->GivItemRef(m_nIdent);
- if ( pVar == NULL )
- {
- pile->SetError(TX_NOITEM, &m_token);
- return pj->Return( pile );
- }
-
- if ( pVar->IsStatic() )
- {
-// DEBUG( "IsStatic", 0, pj) ;
- // pour une variable statique, la prend dans la classe elle-même
- CBotClass* pClass = pItem->GivClass();
- pVar = pClass->GivItem(m_token.GivString());
-// DEBUG( "done "+pVar->GivName(), 0, pj) ;
- }
-
- // demande la mise à jour de l'élément, s'il y a lieu
- pVar->Maj(pile->GivPUser(), TRUE);
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, bExtend) ) return FALSE;
-
- return TRUE; // ne libère pas la pile
- // pour conserver l'état SetState() correspondant à l'étape
-}
-
-void CBotFieldExpr::RestoreStateVar(CBotStack* &pj, BOOL bMain)
-{
- pj = pj->RestoreStack(this); // modifie pj en sortie
- if ( pj == NULL ) return;
-
- if ( m_next3 != NULL )
- m_next3->RestoreStateVar(pj, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un opérande gauche pour une assignation
-
-CBotLeftExpr::CBotLeftExpr()
-{
- name = "CBotLeftExpr";
- m_nIdent = 0;
-}
-
-CBotLeftExpr::~CBotLeftExpr()
-{
-}
-
-// compile une expression pour un left-opérande ( à gauche d'une assignation)
-// cela peut être
-// toto
-// toto[ 3 ]
-// toto.x
-// toto.pos.x
-// toto[2].pos.x
-// toto[1].pos[2].x
-// toto[1][2][3]
-
-CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(p->GivStart());
-
- // est-ce un nom de variable ?
- if (p->GivType() == TokenTypVar)
- {
- CBotLeftExpr* inst = new CBotLeftExpr(); // crée l'objet
-
- inst->SetToken(p);
-
- CBotVar* var;
-
- if ( NULL != (var = pStk->FindVar(p)) ) // cherche si variable connue
- {
- inst->m_nIdent = var->GivUniqNum();
- if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
- {
- if ( var->IsPrivate(PR_READ) &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError( TX_PRIVATE, p );
- goto err;
- }
- // il s'agit d'un élement de la classe courante
- // ajoute l'équivalent d'un this. devant
- CBotToken pthis("this");
- inst->SetToken(&pthis);
- inst->m_nIdent = -2; // ident pour this
-
- CBotFieldExpr* i = new CBotFieldExpr(); // nouvel élément
- i->SetToken( p ); // garde le nom du token
- inst->AddNext3(i); // ajoute à la suite
-
- var = pStk->FindVar(pthis);
- var = var->GivItem(p->GivString());
- i->SetUniqNum(var->GivUniqNum());
- }
- p = p->GivNext(); // token suivant
-
- while (TRUE)
- {
- if ( var->GivType() == CBotTypArrayPointer ) // s'il sagit d'un tableau
- {
- if ( IsOfType( p, ID_OPBRK ) ) // regarde s'il y a un index
- {
- CBotIndexExpr* i = new CBotIndexExpr();
- i->m_expr = CBotExpression::Compile(p, pStk); // compile la formule
- inst->AddNext3(i); // ajoute à la chaine
-
- var = ((CBotVarArray*)var)->GivItem(0,TRUE); // donne le composant [0]
-
- if ( i->m_expr == NULL )
- {
- pStk->SetError( TX_BADINDEX, p->GivStart() );
- goto err;
- }
-
- if ( !pStk->IsOk() || !IsOfType( p, ID_CLBRK ) )
- {
- pStk->SetError( TX_CLBRK, p->GivStart() );
- goto err;
- }
- continue;
- }
- }
-
- if ( var->GivType(1) == CBotTypPointer ) // pour les classes
- {
- if ( IsOfType(p, ID_DOT) )
- {
- CBotToken* pp = p;
-
- CBotFieldExpr* i = new CBotFieldExpr(); // nouvel élément
- i->SetToken( pp ); // garde le nom du token
- inst->AddNext3(i); // ajoute à la suite
-
- if ( p->GivType() == TokenTypVar ) // doit être un nom
- {
- var = var->GivItem(p->GivString()); // récupère l'item correpondant
- if ( var != NULL )
- {
- if ( var->IsPrivate(PR_READ) &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError( TX_PRIVATE, pp );
- goto err;
- }
-
- i->SetUniqNum(var->GivUniqNum());
- p = p->GivNext(); // saute le nom
- continue;
- }
- pStk->SetError( TX_NOITEM, p );
- }
- pStk->SetError( TX_DOT, p->GivStart() );
- goto err;
- }
- }
- break;
- }
-
-
- if ( pStk->IsOk() ) return (CBotLeftExpr*) pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_UNDEFVAR, p);
-err:
- delete inst;
- return (CBotLeftExpr*) pStack->Return(NULL, pStk);
- }
-
- return (CBotLeftExpr*) pStack->Return(NULL, pStk);
-}
-
-// exécute, trouve une variable et lui assigne le résultat de la pile
-
-BOOL CBotLeftExpr::Execute(CBotStack* &pj, CBotStack* array)
-{
- CBotStack* pile = pj->AddStack();
-// if ( pile == EOX ) return TRUE;
-
-// if ( pile->IfStep() ) return FALSE;
-
- CBotVar* var1 = NULL;
- CBotVar* var2 = NULL;
-
-// var1 = pile->FindVar(m_token, FALSE, TRUE);
- if (!ExecuteVar( var1, array, NULL, FALSE )) return FALSE;
- // retrouve la variable (et pas la copie)
- if (pile->IfStep()) return FALSE;
-
- if ( var1 )
- {
- var2 = pj->GivVar(); // resultat sur la pile d'entrée
- if ( var2 )
- {
- CBotTypResult t1 = var1->GivTypResult();
- CBotTypResult t2 = var2->GivTypResult();
- if ( t2.Eq(CBotTypPointer) )
- {
- CBotClass* c1 = t1.GivClass();
- CBotClass* c2 = t2.GivClass();
- if ( !c2->IsChildOf(c1))
- {
- CBotToken* pt = &m_token;
- pile->SetError(TX_BADTYPE, pt);
- return pj->Return(pile); // opération faite
- }
- }
- var1->SetVal(var2); // fait l'assignation
- }
- pile->SetCopyVar( var1 ); // remplace sur la pile par une copie de la variable elle-même
- // (pour avoir le nom)
- }
-
- return pj->Return(pile); // opération faite
-}
-
-// retrouve une variable pendant la compilation
-
-BOOL CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
-{
- pVar = pile->FindVar(m_token);
- if ( pVar == NULL ) return FALSE;
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile) ) return FALSE;
-
- return TRUE;
-}
-
-// retrouve une variable à l'exécution
-
-BOOL CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep)
-{
- pile = pile->AddStack( this ); // déplace la pile
-
- pVar = pile->FindVar(m_nIdent);
- if ( pVar == NULL )
- {
-#ifdef _DEBUG
- ASM_TRAP();
-#endif
- pile->SetError(2, &m_token);
- return FALSE;
- }
-
- if ( bStep && m_next3 == NULL && pile->IfStep() ) return FALSE;
-
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, TRUE) ) return FALSE;
-
- return TRUE;
-}
-
-void CBotLeftExpr::RestoreStateVar(CBotStack* &pile, BOOL bMain)
-{
- pile = pile->RestoreStack( this ); // déplace la pile
- if ( pile == NULL ) return;
-
- if ( m_next3 != NULL )
- m_next3->RestoreStateVar(pile, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// transforme une chaîne en nombre entier
-// peut être de la forme 0xabc123
-
-long GivNumInt( const char* p )
-{
- long num = 0;
- while (*p >= '0' && *p <= '9')
- {
- num = num * 10 + *p - '0';
- p++;
- }
- if ( *p == 'x' || *p == 'X' )
- {
- while (*++p != 0)
- {
- if ( *p >= '0' && *p <= '9' )
- {
- num = num * 16 + *p - '0';
- continue;
- }
- if ( *p >= 'A' && *p <= 'F' )
- {
- num = num * 16 + *p - 'A' + 10;
- continue;
- }
- if ( *p >= 'a' && *p <= 'f' )
- {
- num = num * 16 + *p - 'a' + 10;
- continue;
- }
- break;
- }
- }
- return num;
-}
-
-// transforme une chaîne en un nombre réel
-
-extern float GivNumFloat( const char* p )
-{
- double num = 0;
- double div = 10;
- BOOL bNeg = FALSE;
-
- if (*p == '-')
- {
- bNeg = TRUE;
- p++;
- }
- while (*p >= '0' && *p <= '9')
- {
- num = num * 10. + (*p - '0');
- p++;
- }
-
- if ( *p == '.' )
- {
- p++;
- while (*p >= '0' && *p <= '9')
- {
- num = num + (*p - '0') / div;
- div = div * 10;
- p++;
- }
- }
-
- int exp = 0;
- if ( *p == 'e' || *p == 'E' )
- {
- char neg = 0;
- p++;
- if ( *p == '-' || *p == '+' ) neg = *p++;
-
- while (*p >= '0' && *p <= '9')
- {
- exp = exp * 10 + (*p - '0');
- p++;
- }
- if ( neg == '-' ) exp = -exp;
- }
-
- while ( exp > 0 )
- {
- num *= 10.0;
- exp--;
- }
-
- while ( exp < 0 )
- {
- num /= 10.0;
- exp++;
- }
-
- if ( bNeg ) num = -num;
- return (float)num;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un token représentant un nombre
-
-CBotExprNum::CBotExprNum()
-{
- name = "CBotExprNum";
-}
-
-CBotExprNum::~CBotExprNum()
-{
-}
-
-CBotInstr* CBotExprNum::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- CBotExprNum* inst = new CBotExprNum();
-
- inst->SetToken(p);
- CBotString s = p->GivString();
-
- inst->m_numtype = CBotTypInt;
- if ( p->GivType() == TokenTypDef )
- {
- inst->m_valint = p->GivIdKey();
- }
- else
- {
- if ( s.Find('.') >= 0 || ( s.Find('x') < 0 && ( s.Find('e') >= 0 || s.Find('E') >= 0 ) ) )
- {
- inst->m_numtype = CBotTypFloat;
- inst->m_valfloat = GivNumFloat(s);
- }
- else
- {
- inst->m_valint = GivNumInt(s);
- }
- }
-
- if (pStk->NextToken(p))
- {
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, inst->m_numtype);
- pStk->SetVar(var);
-
- return pStack->Return(inst, pStk);
- }
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute, retourne le nombre correspondant
-
-BOOL CBotExprNum::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, m_numtype);
-
- CBotString nombre ;
- if ( m_token.GivType() == TokenTypDef )
- {
- nombre = m_token.GivString();
- }
-
- switch (m_numtype)
- {
- case CBotTypShort:
- case CBotTypInt:
- var->SetValInt( m_valint, nombre ); // valeur du nombre
- break;
- case CBotTypFloat:
- var->SetValFloat( m_valfloat ); // valeur du nombre
- break;
- }
- pile->SetVar( var ); // mis sur la pile
-
- return pj->Return(pile); // c'est ok
-}
-
-void CBotExprNum::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un token représentant une chaine de caractères
-
-CBotExprAlpha::CBotExprAlpha()
-{
- name = "CBotExprAlpha";
-}
-
-CBotExprAlpha::~CBotExprAlpha()
-{
-}
-
-CBotInstr* CBotExprAlpha::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
-
- CBotExprAlpha* inst = new CBotExprAlpha();
-
- inst->SetToken(p);
- p = p->GivNext();
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString);
- pStk->SetVar(var);
-
- return pStack->Return(inst, pStk);
-}
-
-// exécute, retourne la chaîne correspondante
-
-BOOL CBotExprAlpha::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString);
-
- CBotString chaine = m_token.GivString();
- chaine = chaine.Mid(1, chaine.GivLength()-2); // enlève les guillemets
-
- var->SetValString( chaine ); // valeur du nombre
-
- pile->SetVar( var ); // mis sur la pile
-
- return pj->Return(pile);
-}
-
-void CBotExprAlpha::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un token représentant true ou false
-
-CBotExprBool::CBotExprBool()
-{
- name = "CBotExprBool";
-}
-
-CBotExprBool::~CBotExprBool()
-{
-}
-
-CBotInstr* CBotExprBool::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->TokenStack();
- CBotExprBool* inst = NULL;
-
- if ( p->GivType() == ID_TRUE ||
- p->GivType() == ID_FALSE )
- {
- inst = new CBotExprBool();
- inst->SetToken(p); // mémorise l'opération false ou true
- p = p->GivNext();
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
- pStk->SetVar(var);
- }
-
- return pStack->Return(inst, pStk);
-}
-
-// exécute, retourne true ou false
-
-BOOL CBotExprBool::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
-
- if (GivTokenType() == ID_TRUE) var->SetValInt(1);
- else var->SetValInt(0);
-
- pile->SetVar( var ); // mis sur la pile
- return pj->Return(pile); // transmet en dessous
-}
-
-void CBotExprBool::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// gestion de l'opérande "null"
-
-CBotExprNull::CBotExprNull()
-{
- name = "CBotExprNull";
-}
-
-CBotExprNull::~CBotExprNull()
-{
-}
-
-// exécute, retourne un pointeur vide
-
-BOOL CBotExprNull::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypNullPointer);
-
- var->SetInit(TRUE); // pointeur null valide
- pile->SetVar( var ); // mis sur la pile
- return pj->Return(pile); // transmet en dessous
-}
-
-void CBotExprNull::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// gestion de l'opérande "nan"
-
-CBotExprNan::CBotExprNan()
-{
- name = "CBotExprNan";
-}
-
-CBotExprNan::~CBotExprNan()
-{
-}
-
-// exécute, retourne un pointeur vide
-
-BOOL CBotExprNan::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypInt);
-
- var->SetInit(IS_NAN); // nombre nan
- pile->SetVar( var ); // mis sur la pile
- return pj->Return(pile); // transmet en dessous
-}
-
-void CBotExprNan::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un nom de variable
-// vérifie qu'elle est connue sur la pile
-// et qu'elle a été initialisée
-
-CBotExprVar::CBotExprVar()
-{
- name = "CBotExprVar";
- m_nIdent = 0;
-}
-
-CBotExprVar::~CBotExprVar()
-{
-}
-
-CBotInstr* CBotExprVar::Compile(CBotToken* &p, CBotCStack* pStack, int privat)
-{
- CBotToken* pDebut = p;
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(p->GivStart());
-
- // est-ce un nom de variable ?
- if (p->GivType() == TokenTypVar)
- {
- CBotInstr* inst = new CBotExprVar(); // crée l'objet
-
- inst->SetToken(p);
-
- CBotVar* var;
-
- if ( NULL != (var = pStk->FindVar(p)) ) // cherche si variable connue
- {
- int ident = var->GivUniqNum();
- ((CBotExprVar*)inst)->m_nIdent = ident; // l'identifie par son numéro
-
- if (ident > 0 && ident < 9000)
- {
- if ( var->IsPrivate(privat) &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError( TX_PRIVATE, p );
- goto err;
- }
-
- // il s'agit d'un élement de la classe courante
- // ajoute l'équivalent d'un this. devant
- inst->SetToken(&CBotToken("this"));
- ((CBotExprVar*)inst)->m_nIdent = -2; // ident pour this
-
- CBotFieldExpr* i = new CBotFieldExpr(); // nouvel élément
- i->SetToken( p ); // garde le nom du token
- i->SetUniqNum(ident);
- inst->AddNext3(i); // ajoute à la suite
- }
-
- p = p->GivNext(); // token suivant
-
- while (TRUE)
- {
- if ( var->GivType() == CBotTypArrayPointer ) // s'il sagit d'un tableau
- {
- if ( IsOfType( p, ID_OPBRK ) ) // regarde s'il y a un index
- {
- CBotIndexExpr* i = new CBotIndexExpr();
- i->m_expr = CBotExpression::Compile(p, pStk); // compile la formule
- inst->AddNext3(i); // ajoute à la chaine
-
- var = ((CBotVarArray*)var)->GivItem(0,TRUE); // donne le composant [0]
-
- if ( i->m_expr == NULL )
- {
- pStk->SetError( TX_BADINDEX, p->GivStart() );
- goto err;
- }
- if ( !pStk->IsOk() || !IsOfType( p, ID_CLBRK ) )
- {
- pStk->SetError( TX_CLBRK, p->GivStart() );
- goto err;
- }
- continue;
- }
- //// pStk->SetError( TX_OPBRK, p->GivStart() );
- }
- if ( var->GivType(1) == CBotTypPointer ) // pour les classes
- {
- if ( IsOfType(p, ID_DOT) )
- {
- CBotToken* pp = p;
-
- if ( p->GivType() == TokenTypVar ) // doit être un nom
- {
- if ( p->GivNext()->GivType() == ID_OPENPAR )// un appel de méthode ?
- {
- CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
- if ( !pStk->IsOk() ) goto err;
- inst->AddNext3(i); // ajoute à la suite
- return pStack->Return(inst, pStk);
- }
- else
- {
- CBotFieldExpr* i = new CBotFieldExpr(); // nouvel élément
- i->SetToken( pp ); // garde le nom du token
- inst->AddNext3(i); // ajoute à la suite
- var = var->GivItem(p->GivString()); // récupère l'item correpondant
- if ( var != NULL )
- {
- i->SetUniqNum(var->GivUniqNum());
- if ( var->IsPrivate() &&
- !pStk->GivBotCall()->m_bCompileClass)
- {
- pStk->SetError( TX_PRIVATE, pp );
- goto err;
- }
- }
- }
-
-
- if ( var != NULL )
- {
- p = p->GivNext(); // saute le nom
- continue;
- }
- pStk->SetError( TX_NOITEM, p );
- goto err;
- }
- pStk->SetError( TX_DOT, p->GivStart() );
- goto err;
- }
- }
-
- break;
- }
-
- pStk->SetCopyVar(var); // place une copie de la variable sur la pile (pour le type)
- if ( pStk->IsOk() ) return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_UNDEFVAR, p);
-err:
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- return pStack->Return(NULL, pStk);
-}
-
-CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
- CBotCStack* pStk = pStack->TokenStack();
-
- pStk->SetStartError(pp->GivStart());
-
- // est-ce un nom de variable ?
- if (pp->GivType() == TokenTypVar)
- {
- CBotToken pthis("this");
- CBotVar* var = pStk->FindVar(pthis);
- if ( var == 0 ) return pStack->Return(NULL, pStk);
-
- CBotInstr* inst = new CBotExprVar(); // crée l'objet
-
- // il s'agit d'un élement de la classe courante
- // ajoute l'équivalent d'un this. devant
- inst->SetToken(&pthis);
- ((CBotExprVar*)inst)->m_nIdent = -2; // ident pour this
-
- CBotToken* pp = p;
-
- if ( pp->GivType() == TokenTypVar ) // doit être un nom
- {
- if ( pp->GivNext()->GivType() == ID_OPENPAR ) // un appel de méthode ?
- {
- CBotInstr* i = CBotInstrMethode::Compile(pp, pStk, var);
- if ( pStk->IsOk() )
- {
- inst->AddNext3(i); // ajoute à la suite
- p = pp; // instructions passées
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(0,0); // l'erreur n'est pas traitée ici
- }
- }
- delete inst;
- }
- return pStack->Return(NULL, pStk);
-}
-
-
-// exécute, rend la valeur d'une variable
-
-BOOL CBotExprVar::Execute(CBotStack* &pj)
-{
- CBotVar* pVar = NULL;
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
-// if ( pile->IfStep() ) return FALSE;
-
- CBotStack* pile1 = pile;
-
- if ( pile1->GivState() == 0 )
- {
- if ( !ExecuteVar(pVar, pile, NULL, TRUE) ) return FALSE; // récupère la variable selon champs et index
-// DEBUG("CBotExprVar::Execute", 1 , pj);
-
- if ( pVar ) pile1->SetCopyVar(pVar); // la place une copie sur la pile
- else
- {
-//-- pile1->SetVar(NULL); // la pile contient déjà le resultat (méthode)
- return pj->Return(pile1);
- }
- pile1->IncState();
- }
-
- pVar = pile1->GivVar(); // récupère si interrompu
-
- if ( pVar == NULL )
- {
-// pile1->SetError(TX_NULLPT, &m_token);
- return pj->Return(pile1);
- }
-
- if ( pVar->GivInit() == IS_UNDEF )
- {
- CBotToken* pt = &m_token;
- while ( pt->GivNext() != NULL ) pt = pt->GivNext();
- pile1->SetError(TX_NOTINIT, pt);
- return pj->Return(pile1);
- }
- return pj->Return(pile1); // opération faite
-}
-
-void CBotExprVar::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotStack* pile1 = pile;
-
- if ( pile1->GivState() == 0 )
- {
- RestoreStateVar(pile, bMain); // récupère la variable selon champs et index
- return;
- }
-}
-
-// retrouve une variable à l'exécution
-
-BOOL CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, BOOL bStep)
-{
- CBotStack* pile = pj;
- pj = pj->AddStack( this );
-
- if ( bStep && m_nIdent>0 && pj->IfStep() ) return FALSE;
-
- pVar = pj->FindVar(m_nIdent, TRUE); // cherche la variable avec mise à jour si nécessaire
- if ( pVar == NULL )
- {
-#ifdef _DEBUG
- ASM_TRAP();
-#endif
- pj->SetError(1, &m_token);
- return FALSE;
- }
- if ( m_next3 != NULL &&
- !m_next3->ExecuteVar(pVar, pj, &m_token, bStep, FALSE) )
- return FALSE; // Champs d'une instance, tableau, méthode ?
-
- return pile->ReturnKeep( pj ); // ne rend pas la pile mais récupère le résultat si une méthode a été appelée
-}
-
-
-// retrouve une variable à l'exécution
-
-void CBotExprVar::RestoreStateVar(CBotStack* &pj, BOOL bMain)
-{
- pj = pj->RestoreStack( this );
- if ( pj == NULL ) return;
-
- if ( m_next3 != NULL )
- m_next3->RestoreStateVar(pj, bMain);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-// compile une liste de paramètres
-
-CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
-{
- BOOL first = TRUE;
- CBotInstr* ret = NULL; // pour la liste à retourner
-
-// pStack->SetStartError(p->GivStart());
- CBotCStack* pile = pStack;
- int i = 0;
-
- if ( IsOfType(p, ID_OPENPAR) )
- {
- int start, end;
- if (!IsOfType(p, ID_CLOSEPAR)) while (TRUE)
- {
- start = p->GivStart();
- pile = pile->TokenStack(); // garde les résultats sur la pile
-
- if ( first ) pStack->SetStartError(start);
- first = FALSE;
-
- CBotInstr* param = CBotExpression::Compile(p, pile);
- end = p->GivStart();
-
- if ( !pile->IsOk() )
- {
- return pStack->Return(NULL, pile);
- }
-
- if ( ret == NULL ) ret = param;
- else ret->AddNext(param); // construit la liste
-
- if ( param != NULL )
- {
- if ( pile->GivTypResult().Eq(99) )
- {
- delete pStack->TokenStack();
- pStack->SetError(TX_VOID, p->GivStart());
- return NULL;
- }
- ppVars[i] = pile->GivVar();
- ppVars[i]->GivToken()->SetPos(start, end);
- i++;
-
- if (IsOfType(p, ID_COMMA)) continue; // saute la virgule
- if (IsOfType(p, ID_CLOSEPAR)) break;
- }
-
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- delete pStack->TokenStack();
- return NULL;
- }
- }
- ppVars[i] = NULL;
- return ret;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile un appel d'une méthode
-
-CBotInstrMethode::CBotInstrMethode()
-{
- m_Parameters = NULL;
- m_MethodeIdent = 0;
-// m_nThisIdent = 0;
- name = "CBotInstrMethode";
-}
-
-CBotInstrMethode::~CBotInstrMethode()
-{
- delete m_Parameters;
-}
-
-CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var)
-{
- CBotInstrMethode* inst = new CBotInstrMethode();
- inst->SetToken(p); // token correspondant
-
-// inst->m_nThisIdent = CBotVar::NextUniqNum();
-
- if ( NULL != var )
- {
- CBotToken* pp = p;
- p = p->GivNext();
-
- if ( p->GivType() == ID_OPENPAR )
- {
- inst->m_NomMethod = pp->GivString();
-
- // compile la liste des paramètres
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStack, ppVars);
-
- if ( pStack->IsOk() )
- {
- CBotClass* pClass = var->GivClass(); // pointeur à la classe
- inst->m_ClassName = pClass->GivName(); // le nom de la classe
- CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars,
- pStack, inst->m_MethodeIdent);
- delete pStack->TokenStack(); // libères les paramètres encore sur la pile
- inst->m_typRes = r;
-
- if (inst->m_typRes.GivType() > 20)
- {
- pStack->SetError(inst->m_typRes.GivType(), pp);
- delete inst;
- return NULL;
- }
- // met un résultat sur la pile pour avoir quelque chose
- if (inst->m_typRes.GivType() > 0)
- {
- CBotVar* pResult = CBotVar::Create("", inst->m_typRes);
- if (inst->m_typRes.Eq(CBotTypClass))
- {
-// CBotClass* pClass = CBotClass::Find(inst->m_RetClassName);
- pResult->SetClass(inst->m_typRes.GivClass());
- }
- pStack->SetVar(pResult);
- }
- return inst;
- }
- delete inst;
- return NULL;
- }
- }
- pStack->SetError( 1234, p );
- delete inst;
- return NULL;
-}
-
-// exécute l'appel de méthode
-
-BOOL CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, BOOL bStep, BOOL bExtend)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile1 = pj->AddStack(this, TRUE); // une place pour la copie de This
-// if ( pile1 == EOX ) return TRUE;
-
-// DEBUG( "CBotInstrMethode::ExecuteVar", 0, pj );
-
- if ( pVar->GivPointer() == NULL )
- {
- pj->SetError( TX_NULLPT, prevToken );
- }
-
- if ( pile1->IfStep() ) return FALSE;
-
- CBotStack* pile2 = pile1->AddStack(); // et pour les paramètres à venir
-
- if ( pile1->GivState() == 0)
- {
- CBotVar* pThis = CBotVar::Create(pVar);
- pThis->Copy(pVar);
- // la valeur de This doit être prise avant l'évaluation des paramètres
- // Test.Action( Test = Autre );
- // Action doit agir sur la valeur avant Test = Autre !!
- pThis->SetName("this");
-// pThis->SetUniqNum(m_nThisIdent);
- pThis->SetUniqNum(-2);
- pile1->AddVar(pThis);
- pile1->IncState();
- }
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( TRUE )
- {
- if ( pile2->GivState() == 0 )
- {
- if (!p->Execute(pile2)) return FALSE; // interrompu ici ?
- if (!pile2->SetState(1)) return FALSE; // marque spéciale pour reconnaîre les paramètres
- }
- ppVars[i++] = pile2->GivVar(); // construit la liste des pointeurs
- pile2 = pile2->AddStack(); // de la place sur la pile pour les résultats
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotClass* pClass = CBotClass::Find(m_ClassName);
- CBotVar* pThis = pile1->FindVar(-2);
- CBotVar* pResult = NULL;
- if (m_typRes.GivType() > 0) pResult = CBotVar::Create("", m_typRes);
- if (m_typRes.Eq(CBotTypClass))
- {
-// CBotClass* pClass = CBotClass::Find(m_RetClassName);
- pResult->SetClass(m_typRes.GivClass());
- }
- CBotVar* pRes = pResult;
-
- if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
- pThis, ppVars,
- pResult, pile2, GivToken())) return FALSE; // interrompu
- if (pRes != pResult) delete pRes;
-
- pVar = NULL; // ne retourne pas une valeur par cela
- return pj->Return(pile2); // libère toute la pile
-}
-
-void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotVar* ppVars[1000];
- CBotStack* pile1 = pile->RestoreStack(this); // une place pour la copie de This
- if ( pile1 == NULL ) return;
-
- CBotStack* pile2 = pile1->RestoreStack(); // et pour les paramètres à venir
- if ( pile2 == NULL ) return;
-
- CBotVar* pThis = pile1->FindVar("this");
-// pThis->SetUniqNum(m_nThisIdent);
- pThis->SetUniqNum(-2);
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( TRUE )
- {
- if ( pile2->GivState() == 0 )
- {
- p->RestoreState(pile2, TRUE); // interrompu ici !
- return;
- }
- ppVars[i++] = pile2->GivVar(); // construit la liste des pointeurs
- pile2 = pile2->RestoreStack();
- if ( pile2 == NULL ) return;
-
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotClass* pClass = CBotClass::Find(m_ClassName);
- CBotVar* pResult = NULL;
-
- CBotVar* pRes = pResult;
-
- pClass->RestoreMethode(m_MethodeIdent, m_NomMethod,
- pThis, ppVars, pile2);
-}
-
-
-BOOL CBotInstrMethode::Execute(CBotStack* &pj)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile1 = pj->AddStack(this, TRUE); // une place pour la copie de This
-// if ( pile1 == EOX ) return TRUE;
-
- if ( pile1->IfStep() ) return FALSE;
-
- CBotStack* pile2 = pile1->AddStack(); // et pour les paramètres à venir
-
- if ( pile1->GivState() == 0)
- {
- CBotVar* pThis = pile1->CopyVar(m_token);
- // la valeur de This doit être prise avant l'évaluation des paramètres
- // Test.Action( Test = Autre );
- // Action doit agir sur la valeur avant Test = Autre !!
- pThis->SetName("this");
- pile1->AddVar(pThis);
- pile1->IncState();
- }
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( TRUE )
- {
- if ( pile2->GivState() == 0 )
- {
- if (!p->Execute(pile2)) return FALSE; // interrompu ici ?
- if (!pile2->SetState(1)) return FALSE; // marque spéciale pour reconnaîre les paramètres
- }
- ppVars[i++] = pile2->GivVar(); // construit la liste des pointeurs
- pile2 = pile2->AddStack(); // de la place sur la pile pour les résultats
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotClass* pClass = CBotClass::Find(m_ClassName);
- CBotVar* pThis = pile1->FindVar("this");
- CBotVar* pResult = NULL;
- if (m_typRes.GivType()>0) pResult = CBotVar::Create("", m_typRes);
- if (m_typRes.Eq(CBotTypClass))
- {
-// CBotClass* pClass = CBotClass::Find(m_RetClassName);
- pResult->SetClass(m_typRes.GivClass());
- }
- CBotVar* pRes = pResult;
-
- if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
- pThis, ppVars,
- pResult, pile2, GivToken())) return FALSE; // interrompu
-
- // met la nouvelle valeur de this à la place de l'ancienne variable
- CBotVar* old = pile1->FindVar(m_token);
- old->Copy(pThis, FALSE);
-
- if (pRes != pResult) delete pRes;
-
- return pj->Return(pile2); // libère toute la pile
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "new"
-
-CBotNew::CBotNew()
-{
- name = "CBotNew";
- m_Parameters = NULL;
- m_nMethodeIdent = 0;
-// m_nThisIdent = 0;
-}
-
-CBotNew::~CBotNew()
-{
-}
-
-CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
- if ( !IsOfType(p, ID_NEW) ) return NULL;
-
- // vérifie que le token est un nom de classe
- if (p->GivType() != TokenTypVar) return NULL;
-
- CBotClass* pClass = CBotClass::Find(p);
- if (pClass == NULL)
- {
- pStack->SetError(TX_BADNEW, p);
- return NULL;
- }
-/* if ( !pClass->m_IsDef )
- {
- pStack->SetError(TX_BADNEW, p);
- return NULL;
- }*/
-
- CBotNew* inst = new CBotNew();
- inst->SetToken(pp);
-
- inst->m_vartoken = p;
- p = p->GivNext();
-
- // crée l'objet sur le "tas"
- // avec un pointeur sur cet objet
- CBotVar* pVar = CBotVar::Create("", pClass);
-// inst->m_nThisIdent = CBotVar::NextUniqNum();
-
- // fait l'appel du créateur
- CBotCStack* pStk = pStack->TokenStack();
- {
- // regarde s'il y a des paramètres
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStk, ppVars);
- if ( !pStk->IsOk() ) goto error;
-
- // le constructeur existe-il ?
-// CBotString noname;
- CBotTypResult r = pClass->CompileMethode(pClass->GivName(), pVar, ppVars, pStk, inst->m_nMethodeIdent);
- delete pStk->TokenStack(); // libère le supplément de pile
- int typ = r.GivType();
-
- // s'il n'y a pas de constructeur, et pas de paramètres non plus, c'est ok
- if ( typ == TX_UNDEFCALL && inst->m_Parameters == NULL ) typ = 0;
- pVar->SetInit(TRUE); // marque l'instance comme init
-
- if (typ>20)
- {
- pStk->SetError(typ, inst->m_vartoken.GivEnd());
- goto error;
- }
-
- // si le constructeur n'existe pas, mais qu'il y a des paramètres
- if (typ<0 && inst->m_Parameters != NULL)
- {
- pStk->SetError(TX_NOCONST, &inst->m_vartoken);
- goto error;
- }
-
- // rend le pointeur à l'objet sur la pile
- pStk->SetVar(pVar);
- return pStack->Return(inst, pStk);
- }
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// exécute une instruction "new"
-
-BOOL CBotNew::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); //pile principale
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- CBotStack* pile1 = pj->AddStack2(); //pile secondaire
-
- CBotVar* pThis = NULL;
-
- CBotToken* pt = &m_vartoken;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // crée la variable "this" de type pointeur à l'objet
-
- if ( pile->GivState()==0)
- {
- // crée une instance de la classe demandée
- // et initialise le pointeur à cet objet
-
- pThis = CBotVar::Create("this", pClass);
-// pThis->SetUniqNum( m_nThisIdent ) ;
- pThis->SetUniqNum( -2 ) ;
-
- pile1->SetVar(pThis); // la place sur la pile1
- pile->IncState();
- }
-
- // retrouve le pointeur this si on a été interrompu
- if ( pThis == NULL)
- {
- pThis = pile1->GivVar(); // retrouve le pointeur
- }
-
- // y a-t-il une assignation ou des paramètres (constructeur)
- if ( pile->GivState()==1)
- {
- // évalue le constructeur de l'instance
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( TRUE )
- {
- pile2 = pile2->AddStack(); // de la place sur la pile pour les résultats
- if ( pile2->GivState() == 0 )
- {
- if (!p->Execute(pile2)) return FALSE; // interrompu ici ?
- pile2->SetState(1);
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
- pThis, ppVars,
- pResult, pile2, GivToken())) return FALSE; // interrompu
-
- pThis->ConstructorSet(); // signale que le constructeur a été appelé
-// pile->Return(pile2); // libère un bout de pile
-
-// pile->IncState();
- }
-
- return pj->Return( pile1 ); // transmet en dessous
-}
-
-void CBotNew::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); //pile principale
- if ( pile == NULL ) return;
-
- CBotStack* pile1 = pj->AddStack2(); //pile secondaire
-
- CBotToken* pt = &m_vartoken;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // crée la variable "this" de type pointeur à l'objet
-
- if ( pile->GivState()==0)
- {
- return;
- }
-
- CBotVar* pThis = pile1->GivVar(); // retrouve le pointeur
-// pThis->SetUniqNum( m_nThisIdent );
- pThis->SetUniqNum( -2 );
-
- // y a-t-il une assignation ou des paramètres (constructeur)
- if ( pile->GivState()==1)
- {
- // évalue le constructeur de l'instance
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( TRUE )
- {
- pile2 = pile2->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile2 == NULL ) return;
-
- if ( pile2->GivState() == 0 )
- {
- p->RestoreState(pile2, bMain); // interrompu ici !
- return;
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GivString(), pThis,
- ppVars, pile2) ; // interrompu ici !
- }
-}
-
-/////////////////////////////////////////////////////////////
-// regarde si deux résultats sont compatibles pour faire une opération
-
-BOOL TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op )
-{
- int t1 = type1.GivType();
- int t2 = type2.GivType();
-
- int max = (t1 > t2) ? t1 : t2;
-
- if ( max == 99 ) return FALSE; // un résultat est void ?
-
- // cas particulier pour les concaténation de chaînes
- if (op == ID_ADD && max >= CBotTypString) return TRUE;
- if (op == ID_ASSADD && max >= CBotTypString) return TRUE;
- if (op == ID_ASS && t1 == CBotTypString) return TRUE;
-
- if ( max >= CBotTypBoolean )
- {
- if ( (op == ID_EQ || op == ID_NE) &&
- (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return TRUE;
- if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) &&
- (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return TRUE;
- if ( (op == ID_EQ || op == ID_NE) &&
- (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return TRUE;
- if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) &&
- (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return TRUE;
- if (t2 != t1) return FALSE;
- if (t1 == CBotTypArrayPointer) return type1.Compare(type2);
- if (t1 == CBotTypPointer ||
- t1 == CBotTypClass ||
- t1 == CBotTypIntrinsic )
- {
- CBotClass* c1 = type1.GivClass();
- CBotClass* c2 = type2.GivClass();
-
- return c1->IsChildOf(c2) || c2->IsChildOf(c1);
- // accepte le caste à l'envers,
- // l'opération sera refusée à l'exécution si le pointeur n'est pas compatible
- }
-
- return TRUE;
- }
-
- type1.SetType(max);
- type2.SetType(max);
- return TRUE;
-}
-
-// regarde si deux variables sont compatible pour un passage de paramètre
-
-BOOL TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 )
-{
- int t1 = type1.GivType();
- int t2 = type2.GivType();
-
- if ( t1 == CBotTypIntrinsic ) t1 = CBotTypClass;
- if ( t2 == CBotTypIntrinsic ) t2 = CBotTypClass;
-
- int max = (t1 > t2) ? t1 : t2;
-
- if ( max == 99 ) return FALSE; // un résultat est void ?
-
- if ( max >= CBotTypBoolean )
- {
- if ( t2 != t1 ) return FALSE;
-
- if ( max == CBotTypArrayPointer )
- return TypesCompatibles(type1.GivTypElem(), type2.GivTypElem());
-
- if ( max == CBotTypClass || max == CBotTypPointer )
- return type1.GivClass() == type2.GivClass() ;
-
- return TRUE ;
- }
- return TRUE;
-}
-
-
-/////////////////////////////////////////////////////////////////////////////////////
-// Gestion des fichiers
-
-// nécessaire car il n'est pas possible de faire le fopen dans le programme principal
-// et les fwrite ou fread dans une dll en utilisant le FILE* rendu.
-
-FILE* fOpen(const char* name, const char* mode)
-{
- return fopen(name, mode);
-}
-
-int fClose(FILE* filehandle)
-{
- return fclose(filehandle);
-}
-
-size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle)
-{
- return fwrite(buffer, elemsize, length, filehandle);
-}
-
-size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle)
-{
- return fread(buffer, elemsize, length, filehandle);
-}
-
-size_t fWrite(const void *buffer, size_t length, FILE* filehandle)
-{
- return fwrite(buffer, 1, length, filehandle);
-}
-
-size_t fRead(void *buffer, size_t length, FILE* filehandle)
-{
- return fread(buffer, 1, length, filehandle);
-}
-
-
-////////////////////////////////////////
-
-
-#if FALSE
-
-CBotString num(int n)
-{
- CBotString s;
- if ( n<0 ) {n = -n; s += "-";}
- if ( n > 9 )
- {
- s += num(n/10);
- }
- s += '0' + n%10;
- return s;
-}
-
-extern void DEBUG( const char* text, int val, CBotStack* pile )
-{
- CBotProgram* p = pile->GivBotCall(TRUE);
- if ( !p->m_bDebugDD ) return;
-
- FILE* pf = fopen("CbotDebug.txt", "a");
-
- fputs( text, pf );
-
- CBotString v = " " + num(val) + "\n";
- fputs( v, pf );
-
- fclose( pf);
-}
-
-#endif
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+///////////////////////////////////////////////////////////////////////
+
+// compilation of various instructions
+// compile all routines as static
+// and return an object according to what was found as instruction
+
+// compiler principle:
+// compile the routines return an object of the class corresponding to the operation found
+// this is always a subclass of CBotInstr.
+// (CBotInstr objects are never used directly)
+
+
+// compiles if the routine returns NULL is that the statement is false
+// or misunderstood.
+// the error is then on the stack CBotCStack :: Isok () is false
+
+
+
+#include "CBot.h"
+
+CBotInstr::CBotInstr()
+{
+ name = "CBotInstr";
+ m_next = NULL;
+ m_next2b = NULL;
+ m_next3 = NULL;
+ m_next3b = NULL;
+}
+
+CBotInstr::~CBotInstr()
+{
+ delete m_next;
+ delete m_next2b;
+ delete m_next3;
+ delete m_next3b;
+}
+
+// counter of nested loops,
+// to determine the break and continue valid
+// list of labels used
+
+
+int CBotInstr::m_LoopLvl = 0;
+CBotStringArray CBotInstr::m_labelLvl = CBotStringArray();
+
+// adds a level with a label
+void CBotInstr::IncLvl(CBotString& label)
+{
+ m_labelLvl.SetSize(m_LoopLvl+1);
+ m_labelLvl[m_LoopLvl] = label;
+ m_LoopLvl++;
+}
+
+// adds a level (switch statement)
+void CBotInstr::IncLvl()
+{
+ m_labelLvl.SetSize(m_LoopLvl+1);
+ m_labelLvl[m_LoopLvl] = "#SWITCH";
+ m_LoopLvl++;
+}
+
+// free a level
+void CBotInstr::DecLvl()
+{
+ m_LoopLvl--;
+ m_labelLvl[m_LoopLvl].Empty();
+}
+
+// control validity of break and continue
+bool CBotInstr::ChkLvl(const CBotString& label, int type)
+{
+ int i = m_LoopLvl;
+ while (--i>=0)
+ {
+ if ( type == ID_CONTINUE && m_labelLvl[i] == "#SWITCH") continue;
+ if (label.IsEmpty()) return true;
+ if (m_labelLvl[i] == label) return true;
+ }
+ return false;
+}
+
+bool CBotInstr::IsOfClass(CBotString n)
+{
+ return name == n;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+// database management class CBotInstr
+
+// set the token corresponding to the instruction
+
+void CBotInstr::SetToken(CBotToken* p)
+{
+ m_token = *p;
+}
+
+// return the type of the token assicated with the instruction
+
+int CBotInstr::GivTokenType()
+{
+ return m_token.GivType();
+}
+
+// return associated token
+
+CBotToken* CBotInstr::GivToken()
+{
+ return &m_token;
+}
+
+// adds the statement following the other
+
+void CBotInstr::AddNext(CBotInstr* n)
+{
+ CBotInstr* p = this;
+ while (p->m_next != NULL) p = p->m_next;
+ p->m_next = n;
+}
+
+void CBotInstr::AddNext3(CBotInstr* n)
+{
+ CBotInstr* p = this;
+ while (p->m_next3 != NULL) p = p->m_next3;
+ p->m_next3 = n;
+}
+
+void CBotInstr::AddNext3b(CBotInstr* n)
+{
+ CBotInstr* p = this;
+ while (p->m_next3b != NULL) p = p->m_next3b;
+ p->m_next3b = n;
+}
+
+// returns next statement
+
+CBotInstr* CBotInstr::GivNext()
+{
+ return m_next;
+}
+
+CBotInstr* CBotInstr::GivNext3()
+{
+ return m_next3;
+}
+
+CBotInstr* CBotInstr::GivNext3b()
+{
+ return m_next3b;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// compile an instruction which can be
+// while, do, try, throw, if, for, switch, break, continue, return
+// int, float, boolean, string,
+// declaration of an instance of a class
+// arbitrary expression
+
+
+CBotInstr* CBotInstr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p;
+
+ if (p == NULL) return NULL;
+
+ int type = p->GivType(); // what is the next token
+
+ // is it a lable?
+ if (IsOfType(pp, TokenTypVar) &&
+ IsOfType(pp, ID_DOTS))
+ {
+ type = pp->GivType();
+ // these instructions accept only lable
+ if (!IsOfTypeList(pp, ID_WHILE, ID_FOR, ID_DO, ID_REPEAT, 0))
+ {
+ pStack->SetError(TX_LABEL, pp->GivStart());
+ return NULL;
+ }
+ }
+
+ // call routine corresponding to the compilation token found
+ switch (type)
+ {
+ case ID_WHILE:
+ return CBotWhile::Compile(p, pStack);
+
+ case ID_FOR:
+ return CBotFor::Compile(p, pStack);
+
+ case ID_DO:
+ return CBotDo::Compile(p, pStack);
+
+ case ID_REPEAT:
+ return CBotRepeat::Compile(p, pStack);
+
+ case ID_BREAK:
+ case ID_CONTINUE:
+ return CBotBreak::Compile(p, pStack);
+
+ case ID_SWITCH:
+ return CBotSwitch::Compile(p, pStack);
+
+ case ID_TRY:
+ return CBotTry::Compile(p, pStack);
+
+ case ID_THROW:
+ return CBotThrow::Compile(p, pStack);
+
+ case ID_DEBUGDD:
+ return CBotStartDebugDD::Compile(p, pStack);
+
+ case ID_INT:
+ return CBotInt::Compile(p, pStack);
+
+ case ID_FLOAT:
+ return CBotFloat::Compile(p, pStack);
+
+ case ID_STRING:
+ return CBotIString::Compile(p, pStack);
+
+ case ID_BOOLEAN:
+ case ID_BOOL:
+ return CBotBoolean::Compile(p, pStack);
+
+ case ID_IF:
+ return CBotIf::Compile(p, pStack);
+
+ case ID_RETURN:
+ return CBotReturn::Compile(p, pStack);
+
+ case ID_ELSE:
+ pStack->SetStartError(p->GivStart());
+ pStack->SetError(TX_ELSEWITHOUTIF, p->GivEnd());
+ return NULL;
+
+ case ID_CASE:
+ pStack->SetStartError(p->GivStart());
+ pStack->SetError(TX_OUTCASE, p->GivEnd());
+ return NULL;
+ }
+
+ pStack->SetStartError(p->GivStart());
+
+ // should not be a reserved word DefineNum
+ if (p->GivType() == TokenTypDef)
+ {
+ pStack->SetError(TX_RESERVED, p);
+ return NULL;
+ }
+
+ // this might be an instance of class definnition
+ CBotToken* ppp = p;
+ if (IsOfType(ppp, TokenTypVar))
+ {
+ if (CBotClass::Find(p) != NULL)
+ {
+ // yes, compiles the declaration of the instance
+ return CBotClassInst::Compile(p, pStack);
+ }
+ }
+
+ // this can be an arythmetic instruction
+ CBotInstr* inst = CBotExpression::Compile(p, pStack);
+ if (IsOfType(p, ID_SEP))
+ {
+ return inst;
+ }
+ pStack->SetError(TX_ENDOF, p->GivStart());
+ delete inst;
+ return NULL;
+}
+
+bool CBotInstr::Execute(CBotStack* &pj)
+{
+ CBotString ClassManquante = name;
+ ASM_TRAP(); // should never go through this routine
+ // but use the routines of the subclasses
+ return false;
+}
+
+bool CBotInstr::Execute(CBotStack* &pj, CBotVar* pVar)
+{
+ if (!Execute(pj)) return false;
+ pVar->SetVal(pj->GivVar());
+ return true;
+}
+
+void CBotInstr::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotString ClassManquante = name;
+ ASM_TRAP(); // should never go through this routine
+ // but use the routines of the subclasses
+}
+
+
+bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
+{
+ ASM_TRAP(); // dad do not know, see the girls
+ return false;
+}
+
+bool CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend)
+{
+ ASM_TRAP(); // dad do not know, see the girls
+ return false;
+}
+
+void CBotInstr::RestoreStateVar(CBotStack* &pile, bool bMain)
+{
+ ASM_TRAP(); // dad do not know, see the girls
+}
+
+// this routine is defined only for the subclass CBotCase
+// this allows to make the call on all instructions CompCase
+// to see if it's a case to the desired value.
+
+bool CBotInstr::CompCase(CBotStack* &pj, int val)
+{
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compiles a statement block " { i ; i ; } "
+
+// this class have no constructor because there is never an instance of this
+// class (TODO what about default constructor?)
+// the object returned by Compile is usually of type CBotListInstr
+
+
+CBotInstr* CBotBlock::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal)
+{
+ pStack->SetStartError(p->GivStart());
+
+ if (IsOfType(p, ID_OPBLK))
+ {
+ CBotInstr* inst = CBotListInstr::Compile(p, pStack, bLocal);
+
+ if (IsOfType(p, ID_CLBLK))
+ {
+ return inst;
+ }
+
+ pStack->SetError(TX_CLOSEBLK, p->GivStart()); // missing parenthesis
+ delete inst;
+ return NULL;
+ }
+
+ pStack->SetError(TX_OPENBLK, p->GivStart());
+ return NULL;
+}
+
+CBotInstr* CBotBlock::CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal)
+{
+ // is this a new block
+ if (p->GivType() == ID_OPBLK) return CBotBlock::Compile(p, pStack);
+
+ // otherwise, look for a single statement instead
+
+ // to handle the case with local definition instruction (*)
+ CBotCStack* pStk = pStack->TokenStack(p, bLocal);
+
+ return pStack->Return( CBotInstr::Compile(p, pStk), // a single instruction
+ pStk);
+}
+
+// (*) is the case in the following statement
+// if (1 == 1) int x = 0;
+// where the variable x is known only in the block following the if
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compiles a list of instructions separated by semicolons
+
+CBotListInstr::CBotListInstr()
+{
+ m_Instr = NULL;
+ name = "CBotListInstr";
+}
+
+CBotListInstr::~CBotListInstr()
+{
+ delete m_Instr;
+}
+
+CBotInstr* CBotListInstr::Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal)
+{
+ CBotCStack* pStk = pStack->TokenStack(p, bLocal); // variables are local
+
+ CBotListInstr* inst = new CBotListInstr();
+
+ while (true)
+ {
+ if (p == NULL) break;
+
+ if (IsOfType(p, ID_SEP)) continue; // empty statement ignored
+ if (p->GivType() == ID_CLBLK) break;
+
+ if (IsOfType(p, 0))
+ {
+ pStack->SetError(TX_CLOSEBLK, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ CBotInstr* i = CBotBlock::CompileBlkOrInst(p, pStk); // compiles next
+
+ if (!pStk->IsOk())
+ {
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ if (inst->m_Instr == NULL) inst->m_Instr = i;
+ else inst->m_Instr->AddNext(i); // added a result
+ }
+ return pStack->Return(inst, pStk);
+}
+
+// executes a set of instructions
+
+bool CBotListInstr::Execute(CBotStack* &pj)
+{
+
+ CBotStack* pile = pj->AddStack(this, true); //needed for SetState()
+ if (pile->StackOver() ) return pj->Return( pile);
+
+
+ CBotInstr* p = m_Instr; // the first expression
+
+ int state = pile->GivState();
+ while (state-->0) p = p->GivNext(); // returns to the interrupted operation
+
+ if (p != NULL) while (true)
+ {
+ if (!p->Execute(pile)) return false;
+ p = p->GivNext();
+ if (p == NULL) break;
+ if (!pile->IncState()) ;//return false; // ready for next
+ }
+
+ return pj->Return(pile);
+}
+
+void CBotListInstr::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ CBotInstr* p = m_Instr; // the first expression
+
+ int state = pile->GivState();
+ while ( p != NULL && state-- > 0)
+ {
+ p->RestoreState(pile, false);
+ p = p->GivNext(); // returns to the interrupted operation
+ }
+
+ if (p != NULL) p->RestoreState(pile, true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compilation of an element to the left of an assignment
+
+CBotLeftExprVar::CBotLeftExprVar()
+{
+ name = "CBotLeftExprVar";
+ m_typevar = -1;
+ m_nIdent = 0;
+}
+
+CBotLeftExprVar::~CBotLeftExprVar()
+{
+}
+
+CBotInstr* CBotLeftExprVar::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ // verifies that the token is a variable name
+ if (p->GivType() != TokenTypVar)
+ {
+ pStack->SetError( TX_NOVAR, p->GivStart());
+ return NULL;
+ }
+
+ CBotLeftExprVar* inst = new CBotLeftExprVar();
+ inst->SetToken(p);
+ p = p->GivNext();
+
+ return inst;
+}
+
+// creates a variable and assigns the result to the stack
+bool CBotLeftExprVar::Execute(CBotStack* &pj)
+{
+ CBotVar* var1;
+ CBotVar* var2;
+
+ var1 = CBotVar::Create(m_token.GivString(), m_typevar);
+ var1->SetUniqNum(m_nIdent); // with the unique identifier
+ pj->AddVar(var1); // place it on the stack
+
+ var2 = pj->GivVar(); // result on the stack
+ if (var2) var1->SetVal(var2); // do the assignment
+
+ return true;
+}
+
+void CBotLeftExprVar::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotVar* var1;
+
+ var1 = pj->FindVar(m_token.GivString());
+ if (var1 == NULL) ASM_TRAP();
+
+ var1->SetUniqNum(m_nIdent); // with the unique identifier
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// defining an array of any type
+// int a[12];
+// point x[];
+
+CBotInstArray::CBotInstArray()
+{
+ m_var = NULL;
+ m_listass = NULL;
+ name = "CBotInstArray";
+}
+
+CBotInstArray::~CBotInstArray()
+{
+ delete m_var;
+ delete m_listass;
+}
+
+
+CBotInstr* CBotInstArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
+{
+ CBotCStack* pStk = pStack->TokenStack(p);
+
+ CBotInstArray* inst = new CBotInstArray();
+
+ CBotToken* vartoken = p;
+ inst->SetToken(vartoken);
+
+ // determinse the expression is valid for the item on the left side
+ if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
+ {
+ if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable?
+ {
+ pStk->SetError(TX_REDEFVAR, vartoken);
+ goto error;
+ }
+
+ CBotInstr* i;
+ while (IsOfType(p, ID_OPBRK))
+ {
+ if (p->GivType() != ID_CLBRK)
+ i = CBotExpression::Compile(p, pStk); // expression for the value
+ else
+ i = new CBotEmpty(); // if no special formula
+
+ inst->AddNext3b(i); // construct a list
+ type = CBotTypResult(CBotTypArrayPointer, type);
+
+ if (!pStk->IsOk() || !IsOfType(p, ID_CLBRK ))
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto error;
+ }
+ }
+
+ CBotVar* var = CBotVar::Create(vartoken, type); // create an instance
+ inst->m_typevar = type;
+
+ var->SetUniqNum(
+ ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
+ pStack->AddVar(var); // place it on the stack
+
+ if (IsOfType(p, ID_ASS)) // with an assignment
+ {
+ inst->m_listass = CBotListArray::Compile(p, pStk, type.GivTypElem());
+ }
+
+ if (pStk->IsOk()) return pStack->Return(inst, pStk);
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+
+// executes the definition of an array
+
+bool CBotInstArray::Execute(CBotStack* &pj)
+{
+ CBotStack* pile1 = pj->AddStack(this);
+
+ CBotStack* pile = pile1;
+
+ if (pile1->GivState() == 0)
+ {
+ // seek the maximum dimension of the table
+ CBotInstr* p = GivNext3b(); // the different formulas
+ int nb = 0;
+
+ while (p != NULL)
+ {
+ pile = pile->AddStack(); // little room to work
+ nb++;
+ if (pile->GivState() == 0)
+ {
+ if (!p->Execute(pile)) return false; // size calculation //interrupted?
+ pile->IncState();
+ }
+ p = p->GivNext3b();
+ }
+
+ p = GivNext3b();
+ pile = pile1; // returns to the stack
+ int n = 0;
+ int max[100];
+
+ while (p != NULL)
+ {
+ pile = pile->AddStack();
+ CBotVar* v = pile->GivVar(); // result
+ max[n] = v->GivValInt(); // value
+ if (max[n]>MAXARRAYSIZE)
+ {
+ pile->SetError(TX_OUTARRAY, &m_token);
+ return pj->Return (pile);
+ }
+ n++;
+ p = p->GivNext3b();
+ }
+ while (n<100) max[n++] = 0;
+
+ m_typevar.SetArray(max); // store the limitations
+
+ // create simply a NULL pointer
+ CBotVar* var = CBotVar::Create(m_var->GivToken(), m_typevar);
+ var->SetPointer(NULL);
+ var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent);
+ pj->AddVar(var);
+
+#if STACKMEM
+ pile1->AddStack()->Delete();
+#else
+ delete pile1->AddStack(); // need more indices
+#endif
+ pile1->IncState();
+ }
+
+ if (pile1->GivState() == 1)
+ {
+ if (m_listass != NULL) // there is the assignment for this table
+ {
+ CBotVar* pVar = pj->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
+
+ if (!m_listass->Execute(pile1, pVar)) return false;
+ }
+ pile1->IncState();
+ }
+
+ if (pile1->IfStep()) return false;
+
+ if ( m_next2b &&
+ !m_next2b->Execute(pile1 )) return false;
+
+ return pj->Return(pile1);
+}
+
+void CBotInstArray::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile1 = pj;
+
+ CBotVar* var = pj->FindVar(m_var->GivToken()->GivString());
+ if (var != NULL) var->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent);
+
+ if (bMain)
+ {
+ pile1 = pj->RestoreStack(this);
+ CBotStack* pile = pile1;
+ if (pile == NULL) return;
+
+ if (pile1->GivState() == 0)
+ {
+ // seek the maximum dimension of the table
+ CBotInstr* p = GivNext3b();
+
+ while (p != NULL)
+ {
+ pile = pile->RestoreStack();
+ if (pile == NULL) return;
+ if (pile->GivState() == 0)
+ {
+ p->RestoreState(pile, bMain);
+ return;
+ }
+ p = p->GivNext3b();
+ }
+ }
+ if (pile1->GivState() == 1 && m_listass != NULL)
+ {
+ m_listass->RestoreState(pile1, bMain);
+ }
+
+ }
+
+ if (m_next2b ) m_next2b->RestoreState( pile1, bMain);
+}
+
+// special case for empty indexes
+bool CBotEmpty :: Execute(CBotStack* &pj)
+{
+ CBotVar* pVar = CBotVar::Create("", CBotTypInt);
+ pVar->SetValInt(-1);
+ pj->SetVar(pVar);
+ return true;
+}
+
+void CBotEmpty :: RestoreState(CBotStack* &pj, bool bMain)
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// defining a list table initialization
+// int [ ] a [ ] = (( 1, 2, 3 ) , ( 3, 2, 1 )) ;
+
+
+CBotListArray::CBotListArray()
+{
+ m_expr = NULL;
+ name = "CBotListArray";
+}
+
+CBotListArray::~CBotListArray()
+{
+ delete m_expr;
+}
+
+
+CBotInstr* CBotListArray::Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type)
+{
+ CBotCStack* pStk = pStack->TokenStack(p);
+
+ CBotToken* pp = p;
+
+ if (IsOfType( p, ID_NULL ))
+ {
+ CBotInstr* inst = new CBotExprNull ();
+ inst->SetToken(pp);
+ return pStack->Return(inst, pStk); // ok with empty element
+ }
+
+ CBotListArray* inst = new CBotListArray();
+
+ if (IsOfType( p, ID_OPENPAR ))
+ {
+ // each element takes the one after the other
+ if (type.Eq( CBotTypArrayPointer ))
+ {
+ type = type.GivTypElem();
+
+ pStk->SetStartError(p->GivStart());
+ if (NULL == ( inst->m_expr = CBotListArray::Compile( p, pStk, type ) ))
+ {
+ goto error;
+ }
+
+ while (IsOfType( p, ID_COMMA )) // other elements?
+ {
+ pStk->SetStartError(p->GivStart());
+
+ CBotInstr* i = CBotListArray::Compile(p, pStk, type);
+ if (NULL == i)
+ {
+ goto error;
+ }
+
+ inst->m_expr->AddNext3(i);
+ }
+ }
+ else
+ {
+ pStk->SetStartError(p->GivStart());
+ if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
+ {
+ goto error;
+ }
+ CBotVar* pv = pStk->GivVar(); // result of the expression
+
+ if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type?
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }
+
+ while (IsOfType( p, ID_COMMA )) // other elements?
+ {
+ pStk->SetStartError(p->GivStart());
+
+ CBotInstr* i = CBotTwoOpExpr::Compile(p, pStk) ;
+ if (NULL == i)
+ {
+ goto error;
+ }
+
+ CBotVar* pv = pStk->GivVar(); // result of the expression
+
+ if (pv == NULL || !TypesCompatibles( type, pv->GivTypResult())) // compatible type?
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }
+ inst->m_expr->AddNext3(i);
+ }
+ }
+
+ if (!IsOfType(p, ID_CLOSEPAR) )
+ {
+ pStk->SetError(TX_CLOSEPAR, p->GivStart());
+ goto error;
+ }
+
+ return pStack->Return(inst, pStk);
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+
+// executes the definition of an array
+
+bool CBotListArray::Execute(CBotStack* &pj, CBotVar* pVar)
+{
+ CBotStack* pile1 = pj->AddStack();
+ CBotVar* pVar2;
+
+ CBotInstr* p = m_expr;
+
+ int n = 0;
+
+ for (; p != NULL ; n++, p = p->GivNext3())
+ {
+ if (pile1->GivState() > n) continue;
+
+ pVar2 = pVar->GivItem(n, true);
+
+ if (!p->Execute(pile1, pVar2)) return false; // evaluate expression
+
+ pile1->IncState();
+ }
+
+ return pj->Return(pile1);
+}
+
+void CBotListArray::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain)
+ {
+ CBotStack* pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ CBotInstr* p = m_expr;
+
+ int state = pile->GivState();
+
+ while(state-- > 0) p = p->GivNext3() ;
+
+ p->RestoreState(pile, bMain); // size calculation //interrupted!
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// definition of an integer variable
+// int a, b = 12;
+
+CBotInt::CBotInt()
+{
+ m_next = NULL; // for multiple definitions
+ m_var =
+ m_expr = NULL;
+ name = "CBotInt";
+}
+
+CBotInt::~CBotInt()
+{
+ delete m_var;
+ delete m_expr;
+}
+
+CBotInstr* CBotInstr::CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first)
+{
+ if (IsOfType(p, ID_OPBRK))
+ {
+ if (!IsOfType(p, ID_CLBRK))
+ {
+ pStack->SetError(TX_CLBRK, p->GivStart());
+ return NULL;
+ }
+
+ CBotInstr* inst = CompileArray(p, pStack, CBotTypResult(CBotTypArrayPointer, type), false);
+ if (inst != NULL || !pStack->IsOk()) return inst;
+ }
+
+ // compiles an array declaration
+ if (first) return NULL ;
+
+ CBotInstr* inst = CBotInstArray::Compile(p, pStack, type);
+ if (inst == NULL) return NULL;
+
+ if (IsOfType(p, ID_COMMA)) // several definitions
+ {
+ if (NULL != ( inst->m_next2b = CBotInstArray::CompileArray(p, pStack, type, false))) // compiles next one
+ {
+ return inst;
+ }
+ delete inst;
+ return NULL;
+ }
+
+ if (IsOfType(p, ID_SEP)) // end of instruction
+ {
+ return inst;
+ }
+
+ delete inst;
+ pStack->SetError(TX_ENDOF, p->GivStart());
+ return NULL;
+}
+
+CBotInstr* CBotInt::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
+{
+ CBotToken* pp = cont ? NULL : p; // no repetition of the token "int"
+
+ if (!cont && !IsOfType(p, ID_INT)) return NULL;
+
+ CBotInt* inst = (CBotInt*)CompileArray(p, pStack, CBotTypInt);
+ if (inst != NULL || !pStack->IsOk()) return inst;
+
+ CBotCStack* pStk = pStack->TokenStack(pp);
+
+ inst = new CBotInt();
+
+ inst->m_expr = NULL;
+
+ CBotToken* vartoken = p;
+ inst->SetToken(vartoken);
+
+ // determines the expression is valid for the item on the left side
+ if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
+ {
+ ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypInt;
+ if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
+ {
+ pStk->SetError(TX_REDEFVAR, vartoken);
+ goto error;
+ }
+
+ if (IsOfType(p, ID_OPBRK))
+ {
+ delete inst; // type is not CBotInt
+ p = vartoken; // returns the variable name
+
+ // compiles an array declaration
+
+ CBotInstr* inst2 = CBotInstArray::Compile(p, pStk, CBotTypInt);
+
+ if (!pStk->IsOk() )
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto error;
+ }
+
+ if (IsOfType(p, ID_COMMA)) // several definition chained
+ {
+ if (NULL != ( inst2->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile the next one
+ {
+ return pStack->Return(inst2, pStk);
+ }
+ }
+ inst = (CBotInt*)inst2;
+ goto suite; // no assignment, variable already created
+ }
+
+ if (IsOfType(p, ID_ASS)) // with an assignment?
+ {
+ if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
+ {
+ goto error;
+ }
+ if (pStk->GivType() >= CBotTypBoolean) // compatible type ?
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }
+ }
+
+ {
+ CBotVar* var = CBotVar::Create(vartoken, CBotTypInt);// create the variable (evaluated after the assignment)
+ var->SetInit(inst->m_expr != NULL); // if initialized with assignment
+ var->SetUniqNum( //set it with a unique number
+ ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
+ pStack->AddVar(var); // place it on the stack
+ }
+
+ if (IsOfType(p, ID_COMMA)) // chained several definitions
+ {
+ if (NULL != ( inst->m_next2b = CBotInt::Compile(p, pStk, true, noskip))) // compile next one
+ {
+ return pStack->Return(inst, pStk);
+ }
+ }
+suite:
+ if (noskip || IsOfType(p, ID_SEP)) // instruction is completed
+ {
+ return pStack->Return(inst, pStk);
+ }
+
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// execute the definition of the integer variable
+
+bool CBotInt::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // essential for SetState()
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr && !m_expr->Execute(pile)) return false; // initial value // interrupted?
+ m_var->Execute(pile); // creates and assign the result
+
+ if (!pile->SetState(1)) return false;
+ }
+
+ if (pile->IfStep()) return false;
+
+ if ( m_next2b &&
+ !m_next2b->Execute(pile)) return false; // other(s) definition(s)
+
+ return pj->Return(pile); // forward below
+}
+
+void CBotInt::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile = pj;
+ if (bMain)
+ {
+ pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr) m_expr->RestoreState(pile, bMain); // initial value // interrupted?
+ return;
+ }
+ }
+
+ m_var->RestoreState(pile, bMain);
+
+ if (m_next2b) m_next2b->RestoreState(pile, bMain); // other(s) definition(s)
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// defining a boolean variable
+// int a, b = false;
+
+CBotBoolean::CBotBoolean()
+{
+ m_var =
+ m_expr = NULL;
+ name = "CBotBoolean";
+}
+
+CBotBoolean::~CBotBoolean()
+{
+ delete m_var;
+ delete m_expr;
+}
+
+CBotInstr* CBotBoolean::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
+{
+ CBotToken* pp = cont ? NULL : p;
+
+ if (!cont && !IsOfType(p, ID_BOOLEAN, ID_BOOL)) return NULL;
+
+ CBotBoolean* inst = (CBotBoolean*)CompileArray(p, pStack, CBotTypBoolean);
+ if (inst != NULL || !pStack->IsOk()) return inst;
+
+ CBotCStack* pStk = pStack->TokenStack(pp);
+
+ inst = new CBotBoolean();
+
+ inst->m_expr = NULL;
+
+ CBotToken* vartoken = p;
+ inst->SetToken(vartoken);
+ CBotVar* var = NULL;
+
+ if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
+ {
+ ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypBoolean;
+ if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
+ {
+ pStk->SetError(TX_REDEFVAR, vartoken);
+ goto error;
+ }
+
+ if (IsOfType(p, ID_OPBRK))
+ {
+ delete inst; // type is not CBotInt
+ p = vartoken; // resutns to the variable name
+
+ // compiles an array declaration
+
+ inst = (CBotBoolean*)CBotInstArray::Compile(p, pStk, CBotTypBoolean);
+
+ if (!pStk->IsOk() )
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto error;
+ }
+ goto suite; // no assignment, variable already created
+ }
+
+ if (IsOfType(p, ID_ASS))
+ {
+ if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
+ {
+ goto error;
+ }
+ if (!pStk->GivTypResult().Eq(CBotTypBoolean))
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }
+ }
+
+ var = CBotVar::Create(vartoken, CBotTypBoolean);// create the variable (evaluated after the assignment)
+ var->SetInit(inst->m_expr != NULL);
+ var->SetUniqNum(
+ ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
+ pStack->AddVar(var);
+suite:
+ if (IsOfType(p, ID_COMMA))
+ {
+ if (NULL != ( inst->m_next2b = CBotBoolean::Compile(p, pStk, true, noskip)))
+ {
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ if (noskip || IsOfType(p, ID_SEP))
+ {
+ return pStack->Return(inst, pStk);
+ }
+
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// executes a boolean variable definition
+
+bool CBotBoolean::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);//essential for SetState()
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr && !m_expr->Execute(pile)) return false;
+ m_var->Execute(pile);
+
+ if (!pile->SetState(1)) return false;
+ }
+
+ if (pile->IfStep()) return false;
+
+ if ( m_next2b &&
+ !m_next2b->Execute(pile)) return false;
+
+ return pj->Return(pile);
+}
+
+void CBotBoolean::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile = pj;
+ if (bMain)
+ {
+ pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr) m_expr->RestoreState(pile, bMain); // initial value interrupted?
+ return;
+ }
+ }
+
+ m_var->RestoreState(pile, bMain);
+
+ if (m_next2b)
+ m_next2b->RestoreState(pile, bMain); // other(s) definition(s)
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// definition of a real/float variable
+// int a, b = 12.4;
+
+CBotFloat::CBotFloat()
+{
+ m_var =
+ m_expr = NULL;
+ name = "CBotFloat";
+}
+
+CBotFloat::~CBotFloat()
+{
+ delete m_var;
+ delete m_expr;
+}
+
+CBotInstr* CBotFloat::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
+{
+ CBotToken* pp = cont ? NULL : p;
+
+ if (!cont && !IsOfType(p, ID_FLOAT)) return NULL;
+
+ CBotFloat* inst = (CBotFloat*)CompileArray(p, pStack, CBotTypFloat);
+ if (inst != NULL || !pStack->IsOk()) return inst;
+
+ CBotCStack* pStk = pStack->TokenStack(pp);
+
+ inst = new CBotFloat();
+
+ inst->m_expr = NULL;
+
+ CBotToken* vartoken = p;
+ CBotVar* var = NULL;
+ inst->SetToken(vartoken);
+
+ if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
+ {
+ ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypFloat;
+ if (pStk->CheckVarLocal(vartoken)) // redefinition of a variable
+ {
+ pStk->SetStartError(vartoken->GivStart());
+ pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
+ goto error;
+ }
+
+ if (IsOfType(p, ID_OPBRK))
+ {
+ delete inst;
+ p = vartoken;
+ inst = (CBotFloat*)CBotInstArray::Compile(p, pStk, CBotTypFloat);
+
+ if (!pStk->IsOk() )
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto error;
+ }
+ goto suite; // no assignment, variable already created
+ }
+
+ if (IsOfType(p, ID_ASS))
+ {
+ if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
+ {
+ goto error;
+ }
+ if (pStk->GivType() >= CBotTypBoolean)
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }
+ }
+
+ var = CBotVar::Create(vartoken, CBotTypFloat);
+ var->SetInit(inst->m_expr != NULL);
+ var->SetUniqNum(
+ ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
+ pStack->AddVar(var);
+suite:
+ if (IsOfType(p, ID_COMMA))
+ {
+ if (NULL != ( inst->m_next2b = CBotFloat::Compile(p, pStk, true, noskip)))
+ {
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ if (noskip || IsOfType(p, ID_SEP))
+ {
+ return pStack->Return(inst, pStk);
+ }
+
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// executes the definition of a real variable
+
+bool CBotFloat::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr && !m_expr->Execute(pile)) return false;
+ m_var->Execute(pile);
+
+ if (!pile->SetState(1)) return false;
+ }
+
+ if (pile->IfStep()) return false;
+
+ if ( m_next2b &&
+ !m_next2b->Execute(pile)) return false;
+
+ return pj->Return(pile);
+}
+
+void CBotFloat::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile = pj;
+ if (bMain)
+ {
+ pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr) m_expr->RestoreState(pile, bMain);
+ return;
+ }
+ }
+
+ m_var->RestoreState(pile, bMain);
+
+ if (m_next2b)
+ m_next2b->RestoreState(pile, bMain);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// define a string variable
+// int a, b = "salut";
+
+CBotIString::CBotIString()
+{
+ m_var =
+ m_expr = NULL;
+ name = "CBotIString";
+}
+
+CBotIString::~CBotIString()
+{
+ delete m_var;
+ delete m_expr;
+}
+
+CBotInstr* CBotIString::Compile(CBotToken* &p, CBotCStack* pStack, bool cont, bool noskip)
+{
+ CBotToken* pp = cont ? NULL : p;
+
+ if (!cont && !IsOfType(p, ID_STRING)) return NULL;
+
+ CBotIString* inst = (CBotIString*)CompileArray(p, pStack, CBotTypString);
+ if (inst != NULL || !pStack->IsOk()) return inst;
+
+ CBotCStack* pStk = pStack->TokenStack(pp);
+
+ inst = new CBotIString();
+
+ inst->m_expr = NULL;
+
+ CBotToken* vartoken = p;
+ inst->SetToken(vartoken);
+
+ if (NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )))
+ {
+ ((CBotLeftExprVar*)inst->m_var)->m_typevar = CBotTypString;
+ if (pStk->CheckVarLocal(vartoken))
+ {
+ pStk->SetStartError(vartoken->GivStart());
+ pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
+ goto error;
+ }
+
+ if (IsOfType(p, ID_ASS))
+ {
+ if (NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )))
+ {
+ goto error;
+ }
+/* if (!pStk->GivTypResult().Eq(CBotTypString)) // type compatible ?
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }*/
+ }
+
+ CBotVar* var = CBotVar::Create(vartoken, CBotTypString);
+ var->SetInit(inst->m_expr != NULL);
+ var->SetUniqNum(
+ ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
+ pStack->AddVar(var);
+
+ if (IsOfType(p, ID_COMMA))
+ {
+ if (NULL != ( inst->m_next2b = CBotIString::Compile(p, pStk, true, noskip)))
+ {
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ if (noskip || IsOfType(p, ID_SEP))
+ {
+ return pStack->Return(inst, pStk);
+ }
+
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// executes the definition of the string variable
+
+bool CBotIString::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr && !m_expr->Execute(pile)) return false;
+ m_var->Execute(pile);
+
+ if (!pile->SetState(1)) return false;
+ }
+
+ if (pile->IfStep()) return false;
+
+ if ( m_next2b &&
+ !m_next2b->Execute(pile)) return false;
+
+ return pj->Return(pile);
+}
+
+void CBotIString::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile = pj;
+
+ if (bMain)
+ {
+ pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ if ( pile->GivState()==0)
+ {
+ if (m_expr) m_expr->RestoreState(pile, bMain);
+ return;
+ }
+ }
+
+ m_var->RestoreState(pile, bMain);
+
+ if (m_next2b)
+ m_next2b->RestoreState(pile, bMain);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compiles a statement such as " x = 123 " ou " z * 5 + 4 "
+// with or without assignment
+
+CBotExpression::CBotExpression()
+{
+ m_leftop = NULL;
+ m_rightop = NULL;
+ name = "CBotExpression";
+}
+
+CBotExpression::~CBotExpression()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+CBotInstr* CBotExpression::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p;
+
+ CBotExpression* inst = new CBotExpression();
+
+ inst->m_leftop = CBotLeftExpr::Compile(p, pStack);
+
+ inst->SetToken(p);
+ int OpType = p->GivType();
+
+ if ( pStack->IsOk() &&
+ IsOfTypeList(p, ID_ASS, ID_ASSADD, ID_ASSSUB, ID_ASSMUL, ID_ASSDIV, ID_ASSMODULO,
+ ID_ASSAND, ID_ASSXOR, ID_ASSOR,
+ ID_ASSSL , ID_ASSSR, ID_ASSASR, 0 ))
+ {
+ if (inst->m_leftop == NULL)
+ {
+ pStack->SetError(TX_BADLEFT, p->GivEnd());
+ delete inst;
+ return NULL;
+ }
+
+ inst->m_rightop = CBotExpression::Compile(p, pStack);
+ if (inst->m_rightop == NULL)
+ {
+ delete inst;
+ return NULL;
+ }
+
+ CBotTypResult type1 = pStack->GivTypResult();
+
+ // get the variable assigned to mark
+ CBotVar* var = NULL;
+ inst->m_leftop->ExecuteVar(var, pStack);
+ if (var == NULL)
+ {
+ delete inst;
+ return NULL;
+ }
+
+ if (OpType != ID_ASS && var->GivInit() != IS_DEF)
+ {
+ pStack->SetError(TX_NOTINIT, pp);
+ delete inst;
+ return NULL;
+ }
+
+ CBotTypResult type2 = var->GivTypResult();
+
+ // what types are acceptable?
+ switch (OpType)
+ {
+ case ID_ASS:
+ // if (type2 == CBotTypClass) type2 = -1;
+ if ((type1.Eq(CBotTypPointer) && type2.Eq(CBotTypPointer)) ||
+ (type1.Eq(CBotTypClass) && type2.Eq(CBotTypClass) ) )
+ {
+/* CBotClass* c1 = type1.GivClass();
+ CBotClass* c2 = type2.GivClass();
+ if (!c1->IsChildOf(c2)) type2.SetType(-1);
+//- if (!type1.Eq(CBotTypClass)) var->SetPointer(pStack->GivVar()->GivPointer());*/
+ var->SetInit(2);
+ }
+ else
+ var->SetInit(true);
+
+ break;
+ case ID_ASSADD:
+ if (type2.Eq(CBotTypBoolean) ||
+ type2.Eq(CBotTypPointer) ) type2 = -1; // numbers and strings
+ break;
+ case ID_ASSSUB:
+ case ID_ASSMUL:
+ case ID_ASSDIV:
+ case ID_ASSMODULO:
+ if (type2.GivType() >= CBotTypBoolean) type2 = -1; // numbers only
+ break;
+ }
+
+ if (!TypeCompatible(type1, type2, OpType))
+ {
+ pStack->SetError(TX_BADTYPE, &inst->m_token);
+ delete inst;
+ return NULL;
+ }
+
+ return inst; // compatible type?
+ }
+
+ delete inst;
+ int start, end, error = pStack->GivError(start, end);
+
+ p = pp; // returns to the top
+ pStack->SetError(0,0); // forget the error
+
+ CBotInstr* i = CBotTwoOpExpr::Compile(p, pStack); // tries without assignment
+ if (i != NULL && error == TX_PRIVATE && p->GivType() == ID_ASS)
+ pStack->ResetError(error, start, end);
+ return i;
+}
+
+// executes an expression with assignment
+
+bool CBotExpression::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ CBotToken* pToken = m_leftop->GivToken();
+ CBotVar* pVar = NULL;
+
+ CBotStack* pile1 = pile;
+
+ bool IsInit = true;
+ CBotVar* result = NULL;
+
+ // must be done before any indexes (stack can be changed)
+ if (!m_leftop->ExecuteVar(pVar, pile, NULL, false)) return false; // variable before accessing the value on the right
+
+ if ( pile1->GivState()==0)
+ {
+ pile1->SetCopyVar(pVar); // keeps the copy on the stack (if interrupted)
+ pile1->IncState();
+ }
+
+ CBotStack* pile2 = pile->AddStack();
+
+ if ( pile2->GivState()==0)
+ {
+ if (m_rightop && !m_rightop->Execute(pile2)) return false; // initial value // interrupted?
+ pile2->IncState();
+ }
+
+ if (pile1->GivState() == 1)
+ {
+ if (m_token.GivType() != ID_ASS)
+ {
+ pVar = pile1->GivVar(); // recovers if interrupted
+ IsInit = pVar->GivInit();
+ if (IsInit == IS_NAN)
+ {
+ pile2->SetError(TX_OPNAN, m_leftop->GivToken());
+ return pj->Return(pile2);
+ }
+ result = CBotVar::Create("", pVar->GivTypResult(2));
+ }
+
+ switch (m_token.GivType())
+ {
+ case ID_ASS:
+ break;
+ case ID_ASSADD:
+ result->Add(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSSUB:
+ result->Sub(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSMUL:
+ result->Mul(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSDIV:
+ if (IsInit &&
+ result->Div(pile1->GivVar(), pile2->GivVar()))
+ pile2->SetError(TX_DIVZERO, &m_token);
+ pile2->SetVar(result);
+ break;
+ case ID_ASSMODULO:
+ if (IsInit &&
+ result->Modulo(pile1->GivVar(), pile2->GivVar()))
+ pile2->SetError(TX_DIVZERO, &m_token);
+ pile2->SetVar(result);
+ break;
+ case ID_ASSAND:
+ result->And(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSXOR:
+ result->XOr(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSOR:
+ result->Or(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSSL:
+ result->SL(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSSR:
+ result->SR(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ case ID_ASSASR:
+ result->ASR(pile1->GivVar(), pile2->GivVar());
+ pile2->SetVar(result);
+ break;
+ default:
+ ASM_TRAP();
+ }
+ if (!IsInit)
+ pile2->SetError(TX_NOTINIT, m_leftop->GivToken());
+
+ pile1->IncState();
+ }
+
+ if (!m_leftop->Execute( pile2, pile1 ))
+ return false;
+
+ return pj->Return(pile2);
+}
+
+
+void CBotExpression::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain)
+ {
+ CBotToken* pToken = m_leftop->GivToken();
+ CBotVar* pVar = NULL;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ CBotStack* pile1 = pile;
+
+ if ( pile1->GivState()==0)
+ {
+ m_leftop->RestoreStateVar(pile, true);
+ return;
+ }
+
+ m_leftop->RestoreStateVar(pile, false);
+
+ CBotStack* pile2 = pile->RestoreStack();
+ if (pile2 == NULL) return;
+
+ if ( pile2->GivState()==0)
+ {
+ if (m_rightop) m_rightop->RestoreState(pile2, bMain);
+ return;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a statement such as "(condition)"
+// the condition must be Boolean
+
+// this class has no constructor, because there is never an instance of this class
+// the object returned by Compile is usually type CBotExpression
+
+
+CBotInstr* CBotCondition::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ pStack->SetStartError(p->GivStart());
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ CBotInstr* inst = CBotBoolExpr::Compile(p, pStack);
+ if (NULL != inst)
+ {
+ if (IsOfType(p, ID_CLOSEPAR))
+ {
+ return inst;
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart()); // missing parenthesis
+ }
+ delete inst;
+ }
+
+ pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis
+
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a statement such as "(condition)"
+// the condition must be Boolean
+//
+// this class has no constructor, because there is never an instance of this
+// class
+// the object returned by Compile is usually type CBotExpression
+//
+
+CBotInstr* CBotBoolExpr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ pStack->SetStartError(p->GivStart());
+
+ CBotInstr* inst = CBotTwoOpExpr::Compile(p, pStack);
+
+ if (NULL != inst)
+ {
+ if (pStack->GivTypResult().Eq(CBotTypBoolean))
+ {
+ return inst;
+ }
+ pStack->SetError(TX_NOTBOOL, p->GivStart()); // is not a boolean
+ }
+
+ delete inst;
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile either:
+// instruction in parentheses (...)
+// a unary expression (negative, not)
+// variable name
+// variables pre and post-incremented or decremented
+// a given number DefineNum
+// a constant
+// procedure call
+// new statement
+//
+// this class has no constructor, because there is never an instance of this class
+// the object returned by Compile is the class corresponding to the instruction
+
+
+CBotInstr* CBotParExpr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->TokenStack();
+
+ pStk->SetStartError(p->GivStart());
+
+ // is it an expression in parentheses?
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ CBotInstr* inst = CBotExpression::Compile(p, pStk);
+
+ if (NULL != inst)
+ {
+ if (IsOfType(p, ID_CLOSEPAR))
+ {
+ return pStack->Return(inst, pStk);
+ }
+ pStk->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ // is this a unary operation?
+ CBotInstr* inst = CBotExprUnaire::Compile(p, pStk);
+ if (inst != NULL || !pStk->IsOk())
+ return pStack->Return(inst, pStk);
+
+ // is it a variable name?
+ if (p->GivType() == TokenTypVar)
+ {
+ // this may be a method call without the "this." before
+ inst = CBotExprVar::CompileMethode(p, pStk);
+ if (inst != NULL) return pStack->Return(inst, pStk);
+
+
+ // is it a procedure call?
+ inst = CBotInstrCall::Compile(p, pStk);
+ if (inst != NULL || !pStk->IsOk())
+ return pStack->Return(inst, pStk);
+
+
+ CBotToken* pvar = p;
+ // no, it an "ordinaty" variable
+ inst = CBotExprVar::Compile(p, pStk);
+
+ CBotToken* pp = p;
+ // post incremented or decremented?
+ if (IsOfType(p, ID_INC, ID_DEC))
+ {
+ if (pStk->GivType() >= CBotTypBoolean)
+ {
+ pStk->SetError(TX_BADTYPE, pp);
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ // recompile the variable for read-only
+ delete inst;
+ p = pvar;
+ inst = CBotExprVar::Compile(p, pStk, PR_READ);
+ p = p->GivNext();
+
+ CBotPostIncExpr* i = new CBotPostIncExpr();
+ i->SetToken(pp);
+ i->m_Instr = inst; // associated statement
+ return pStack->Return(i, pStk);
+ }
+ return pStack->Return(inst, pStk);
+ }
+
+ // pre increpemted or pre decremented?
+ CBotToken* pp = p;
+ if (IsOfType(p, ID_INC, ID_DEC))
+ {
+ CBotPreIncExpr* i = new CBotPreIncExpr();
+ i->SetToken(pp);
+
+ if (p->GivType() == TokenTypVar)
+ {
+ if (NULL != (i->m_Instr = CBotExprVar::Compile(p, pStk, PR_READ)))
+ {
+ if (pStk->GivType() >= CBotTypBoolean)
+ {
+ pStk->SetError(TX_BADTYPE, pp);
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ return pStack->Return(i, pStk);
+ }
+ delete i;
+ return pStack->Return(NULL, pStk);
+ }
+ }
+
+ // is it a number or DefineNum?
+ if (p->GivType() == TokenTypNum ||
+ p->GivType() == TokenTypDef )
+ {
+ CBotInstr* inst = CBotExprNum::Compile(p, pStk);
+ return pStack->Return(inst, pStk);
+ }
+
+ // is this a chaine?
+ if (p->GivType() == TokenTypString)
+ {
+ CBotInstr* inst = CBotExprAlpha::Compile(p, pStk);
+ return pStack->Return(inst, pStk);
+ }
+
+ // is a "true" or "false"
+ if (p->GivType() == ID_TRUE ||
+ p->GivType() == ID_FALSE )
+ {
+ CBotInstr* inst = CBotExprBool::Compile(p, pStk);
+ return pStack->Return(inst, pStk);
+ }
+
+ // is an object to be created with new
+ if (p->GivType() == ID_NEW)
+ {
+ CBotInstr* inst = CBotNew::Compile(p, pStk);
+ return pStack->Return(inst, pStk);
+ }
+
+ // is a null pointer
+ if (IsOfType(p, ID_NULL))
+ {
+ CBotInstr* inst = new CBotExprNull ();
+ inst->SetToken(pp);
+ CBotVar* var = CBotVar::Create("", CBotTypNullPointer);
+ pStk->SetVar(var);
+ return pStack->Return(inst, pStk);
+ }
+
+ // is a number nan
+ if (IsOfType(p, ID_NAN))
+ {
+ CBotInstr* inst = new CBotExprNan ();
+ inst->SetToken(pp);
+ CBotVar* var = CBotVar::Create("", CBotTypInt);
+ var->SetInit(IS_NAN);
+ pStk->SetVar(var);
+ return pStack->Return(inst, pStk);
+ }
+
+
+ return pStack->Return(NULL, pStk);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// Management of pre-and post increment / decrement
+// There is no routine Compiles, the object is created directly
+// Compiles in CBotParExpr ::
+
+
+CBotPostIncExpr::CBotPostIncExpr()
+{
+ m_Instr = NULL;
+ name = "CBotPostIncExpr";
+}
+
+CBotPostIncExpr::~CBotPostIncExpr()
+{
+ delete m_Instr;
+}
+
+CBotPreIncExpr::CBotPreIncExpr()
+{
+ m_Instr = NULL;
+ name = "CBotPreIncExpr";
+}
+
+CBotPreIncExpr::~CBotPreIncExpr()
+{
+ delete m_Instr;
+}
+
+bool CBotPostIncExpr::Execute(CBotStack* &pj)
+{
+ CBotStack* pile1 = pj->AddStack(this);
+ CBotStack* pile2 = pile1;
+
+ CBotVar* var1 = NULL;
+
+ // retrieves the variable fields and indexes according
+ if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false;
+
+ pile1->SetState(1);
+ pile1->SetCopyVar(var1); // places the result (before incrementation);
+
+ CBotStack* pile3 = pile2->AddStack(this);
+ if (pile3->IfStep()) return false;
+
+ if (var1->GivInit() == IS_NAN)
+ {
+ pile1->SetError(TX_OPNAN, &m_token);
+ }
+
+ if (var1->GivInit() != IS_DEF)
+ {
+ pile1->SetError(TX_NOTINIT, &m_token);
+ }
+
+ if (GivTokenType() == ID_INC) var1->Inc();
+ else var1->Dec();
+
+ return pj->Return(pile1); // operation done, result on pile2
+}
+
+void CBotPostIncExpr::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotStack* pile1 = pj->RestoreStack(this);
+ if (pile1 == NULL) return;
+
+ ((CBotExprVar*)m_Instr)->RestoreStateVar(pile1, bMain);
+
+ if (pile1 != NULL) pile1->RestoreStack(this);
+}
+
+bool CBotPreIncExpr::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->IfStep()) return false;
+
+ CBotVar* var1;
+
+ if (pile->GivState() == 0)
+ {
+ CBotStack* pile2 = pile;
+ // retrieves the variable fields and indexes according
+ // pile2 is modified on return
+ if (!((CBotExprVar*)m_Instr)->ExecuteVar(var1, pile2, NULL, true)) return false;
+
+ if (var1->GivInit() == IS_NAN)
+ {
+ pile->SetError(TX_OPNAN, &m_token);
+ return pj->Return(pile); // operation performed
+ }
+
+ if (var1->GivInit() != IS_DEF)
+ {
+ pile->SetError(TX_NOTINIT, &m_token);
+ return pj->Return(pile); // operation performed
+ }
+
+ if (GivTokenType() == ID_INC) var1->Inc();
+ else var1->Dec(); // ((CBotVarInt*)var1)->m_val
+
+ pile->IncState();
+ }
+
+ if (!m_Instr->Execute(pile)) return false;
+ return pj->Return(pile); // operation performed
+}
+
+
+void CBotPreIncExpr::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ if (pile->GivState() == 0)
+ {
+ return;
+ }
+
+ m_Instr->RestoreState(pile, bMain);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile an unary expression
+// +
+// -
+// not
+// !
+// ~
+
+CBotExprUnaire::CBotExprUnaire()
+{
+ m_Expr = NULL;
+ name = "CBotExprUnaire";
+}
+
+CBotExprUnaire::~CBotExprUnaire()
+{
+ delete m_Expr;
+}
+
+CBotInstr* CBotExprUnaire::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ int op = p->GivType();
+ CBotToken* pp = p;
+ if (!IsOfTypeList( p, ID_ADD, ID_SUB, ID_LOG_NOT, ID_TXT_NOT, ID_NOT, 0 )) return NULL;
+
+ CBotCStack* pStk = pStack->TokenStack(pp);
+
+ CBotExprUnaire* inst = new CBotExprUnaire();
+ inst->SetToken(pp);
+
+ if (NULL != (inst->m_Expr = CBotParExpr::Compile( p, pStk )))
+ {
+ if (op == ID_ADD && pStk->GivType() < CBotTypBoolean) // only with the number
+ return pStack->Return(inst, pStk);
+ if (op == ID_SUB && pStk->GivType() < CBotTypBoolean) // only with the numer
+ return pStack->Return(inst, pStk);
+ if (op == ID_NOT && pStk->GivType() < CBotTypFloat) // only with an integer
+ return pStack->Return(inst, pStk);
+ if (op == ID_LOG_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean
+ return pStack->Return(inst, pStk);
+ if (op == ID_TXT_NOT && pStk->GivTypResult().Eq(CBotTypBoolean))// only with boolean
+ return pStack->Return(inst, pStk);
+
+ pStk->SetError(TX_BADTYPE, &inst->m_token);
+ }
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// executes unary expression
+
+bool CBotExprUnaire::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->GivState() == 0)
+ {
+ if (!m_Expr->Execute(pile)) return false; // interrupted ?
+ pile->IncState();
+ }
+
+ CBotStack* pile2 = pile->AddStack();
+ if (pile2->IfStep()) return false;
+
+ CBotVar* var = pile->GivVar(); // get the result on the stack
+
+ switch (GivTokenType())
+ {
+ case ID_ADD:
+ break;
+ case ID_SUB:
+ var->Neg(); // change the sign
+ break;
+ case ID_NOT:
+ case ID_LOG_NOT:
+ case ID_TXT_NOT:
+ var->Not();
+ break;
+ }
+ return pj->Return(pile); // forwards below
+}
+
+void CBotExprUnaire::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL) return;
+
+ if (pile->GivState() == 0)
+ {
+ m_Expr->RestoreState(pile, bMain); // interrupted here!
+ return;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// index management for arrays
+// array [ expression ]
+
+
+CBotIndexExpr::CBotIndexExpr()
+{
+ m_expr = NULL;
+ name = "CBotIndexExpr";
+}
+
+CBotIndexExpr::~CBotIndexExpr()
+{
+ delete m_expr;
+}
+
+// finds a field from the instance at compile time
+
+bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
+{
+ if (pVar->GivType(1) != CBotTypArrayPointer)
+ ASM_TRAP();
+
+ pVar = ((CBotVarArray*)pVar)->GivItem(0, false); // at compile time makes the element [0]
+ if (pVar == NULL)
+ {
+ pile->SetError(TX_OUTARRAY, m_token.GivEnd());
+ return false;
+ }
+ if (m_next3 != NULL) return m_next3->ExecuteVar(pVar, pile);
+ return true;
+}
+
+// attention, changes the pointer to the stack intentionally
+// place the index calculated on the additional stack
+
+
+bool CBotIndexExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend)
+{
+ CBotStack* pj = pile;
+
+ if (pVar->GivType(1) != CBotTypArrayPointer)
+ ASM_TRAP();
+
+ pile = pile->AddStack();
+
+ if (pile->GivState() == 0)
+ {
+ if (!m_expr->Execute(pile)) return false;
+ pile->IncState();
+ }
+ // handles array
+
+ CBotVar* p = pile->GivVar(); // result on the stack
+
+ if (p == NULL || p->GivType() > CBotTypDouble)
+ {
+ pile->SetError(TX_BADINDEX, prevToken);
+ return pj->Return(pile);
+ }
+
+ int n = p->GivValInt(); // position in the table
+
+ pVar = ((CBotVarArray*)pVar)->GivItem(n, bExtend);
+ if (pVar == NULL)
+ {
+ pile->SetError(TX_OUTARRAY, prevToken);
+ return pj->Return(pile);
+ }
+
+ pVar->Maj(pile->GivPUser(), true);
+
+ if ( m_next3 != NULL &&
+ !m_next3->ExecuteVar(pVar, pile, prevToken, bStep, bExtend) ) return false;
+
+ // does not release the stack
+ // to avoid recalculation of the index twice where appropriate
+ return true;
+}
+
+void CBotIndexExpr::RestoreStateVar(CBotStack* &pile, bool bMain)
+{
+ pile = pile->RestoreStack();
+ if (pile == NULL) return;
+
+ if (bMain && pile->GivState() == 0)
+ {
+ m_expr->RestoreState(pile, true);
+ return;
+ }
+
+ if (m_next3)
+ m_next3->RestoreStateVar(pile, bMain);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// field management in an instance (dot operator)
+// toto.x
+
+
+CBotFieldExpr::CBotFieldExpr()
+{
+ name = "CBotFieldExpr";
+ m_nIdent = 0;
+}
+
+CBotFieldExpr::~CBotFieldExpr()
+{
+}
+
+void CBotFieldExpr::SetUniqNum(int num)
+{
+ m_nIdent = num;
+}
+
+
+// find a field from the instance at compile
+
+bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
+{
+ if (pVar->GivType(1) != CBotTypPointer)
+ ASM_TRAP();
+
+ pVar = pVar->GivItemRef(m_nIdent);
+ if (pVar == NULL)
+ {
+ pile->SetError(TX_NOITEM, &m_token);
+ return false;
+ }
+
+ if ( m_next3 != NULL &&
+ !m_next3->ExecuteVar(pVar, pile) ) return false;
+
+ return true;
+}
+
+bool CBotFieldExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend)
+{
+ CBotStack* pj = pile;
+ pile = pile->AddStack(this); // changes in output stack
+ if (pile == EOX) return true;
+
+
+ if (pVar->GivType(1) != CBotTypPointer)
+ ASM_TRAP();
+
+ CBotVarClass* pItem = pVar->GivPointer();
+ if (pItem == NULL)
+ {
+ pile->SetError(TX_NULLPT, prevToken);
+ return pj->Return(pile);
+ }
+ if (pItem->GivUserPtr() == OBJECTDELETED)
+ {
+ pile->SetError(TX_DELETEDPT, prevToken);
+ return pj->Return(pile);
+ }
+
+ if (bStep && pile->IfStep()) return false;
+
+ pVar = pVar->GivItemRef(m_nIdent);
+ if (pVar == NULL)
+ {
+ pile->SetError(TX_NOITEM, &m_token);
+ return pj->Return(pile);
+ }
+
+ if (pVar->IsStatic())
+ {
+ // for a static variable, takes it in the class itself
+ CBotClass* pClass = pItem->GivClass();
+ pVar = pClass->GivItem(m_token.GivString());
+ }
+
+ // request the update of the element, if applicable
+ pVar->Maj(pile->GivPUser(), true);
+
+ if ( m_next3 != NULL &&
+ !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, bExtend) ) return false;
+
+ // does not release the stack
+ // to maintain the state SetState () corresponding to step
+
+ return true;
+}
+
+void CBotFieldExpr::RestoreStateVar(CBotStack* &pj, bool bMain)
+{
+ pj = pj->RestoreStack(this);
+ if (pj == NULL) return;
+
+ if (m_next3 != NULL)
+ m_next3->RestoreStateVar(pj, bMain);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a left operand for an assignment
+CBotLeftExpr::CBotLeftExpr()
+{
+ name = "CBotLeftExpr";
+ m_nIdent = 0;
+}
+
+CBotLeftExpr::~CBotLeftExpr()
+{
+}
+
+// compiles an expression for a left-operand (left of an assignment)
+// this can be
+// toto
+// toto[ 3 ]
+// toto.x
+// toto.pos.x
+// toto[2].pos.x
+// toto[1].pos[2].x
+// toto[1][2][3]
+
+CBotLeftExpr* CBotLeftExpr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->TokenStack();
+
+ pStk->SetStartError(p->GivStart());
+
+ // is it a variable name?
+ if (p->GivType() == TokenTypVar)
+ {
+ CBotLeftExpr* inst = new CBotLeftExpr(); // creates the object
+
+ inst->SetToken(p);
+
+ CBotVar* var;
+
+ if (NULL != (var = pStk->FindVar(p))) // seek if known variable
+ {
+ inst->m_nIdent = var->GivUniqNum();
+ if (inst->m_nIdent > 0 && inst->m_nIdent < 9000)
+ {
+ if ( var->IsPrivate(PR_READ) &&
+ !pStk->GivBotCall()->m_bCompileClass)
+ {
+ pStk->SetError(TX_PRIVATE, p);
+ goto err;
+ }
+ // this is an element of the current class
+ // adds the equivalent of this. before
+ CBotToken pthis("this");
+ inst->SetToken(&pthis);
+ inst->m_nIdent = -2; // indent for this
+
+ CBotFieldExpr* i = new CBotFieldExpr(); // new element
+ i->SetToken(p); // keeps the name of the token
+ inst->AddNext3(i); // add after
+
+ var = pStk->FindVar(pthis);
+ var = var->GivItem(p->GivString());
+ i->SetUniqNum(var->GivUniqNum());
+ }
+ p = p->GivNext(); // next token
+
+ while (true)
+ {
+ if (var->GivType() == CBotTypArrayPointer)
+ {
+ if (IsOfType( p, ID_OPBRK ))
+ {
+ CBotIndexExpr* i = new CBotIndexExpr();
+ i->m_expr = CBotExpression::Compile(p, pStk);
+ inst->AddNext3(i); // add to the chain
+
+ var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0]
+
+ if (i->m_expr == NULL)
+ {
+ pStk->SetError(TX_BADINDEX, p->GivStart());
+ goto err;
+ }
+
+ if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ))
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto err;
+ }
+ continue;
+ }
+ }
+
+ if (var->GivType(1) == CBotTypPointer) // for classes
+ {
+ if (IsOfType(p, ID_DOT))
+ {
+ CBotToken* pp = p;
+
+ CBotFieldExpr* i = new CBotFieldExpr(); // new element
+ i->SetToken(pp); // keeps the name of the token
+ inst->AddNext3(i); // adds after
+
+ if (p->GivType() == TokenTypVar) // must be a name
+ {
+ var = var->GivItem(p->GivString()); // get item correspondent
+ if (var != NULL)
+ {
+ if ( var->IsPrivate(PR_READ) &&
+ !pStk->GivBotCall()->m_bCompileClass)
+ {
+ pStk->SetError(TX_PRIVATE, pp);
+ goto err;
+ }
+
+ i->SetUniqNum(var->GivUniqNum());
+ p = p->GivNext(); // skips the name
+ continue;
+ }
+ pStk->SetError(TX_NOITEM, p);
+ }
+ pStk->SetError(TX_DOT, p->GivStart());
+ goto err;
+ }
+ }
+ break;
+ }
+
+
+ if (pStk->IsOk()) return (CBotLeftExpr*) pStack->Return(inst, pStk);
+ }
+ pStk->SetError(TX_UNDEFVAR, p);
+err:
+ delete inst;
+ return (CBotLeftExpr*) pStack->Return(NULL, pStk);
+ }
+
+ return (CBotLeftExpr*) pStack->Return(NULL, pStk);
+}
+
+// runs, is a variable and assigns the result to the stack
+bool CBotLeftExpr::Execute(CBotStack* &pj, CBotStack* array)
+{
+ CBotStack* pile = pj->AddStack();
+
+ CBotVar* var1 = NULL;
+ CBotVar* var2 = NULL;
+ // fetch a variable (not copy)
+ if (!ExecuteVar(var1, array, NULL, false)) return false;
+
+ if (pile->IfStep()) return false;
+
+ if (var1)
+ {
+ var2 = pj->GivVar(); // result on the input stack
+ if (var2)
+ {
+ CBotTypResult t1 = var1->GivTypResult();
+ CBotTypResult t2 = var2->GivTypResult();
+ if (t2.Eq(CBotTypPointer))
+ {
+ CBotClass* c1 = t1.GivClass();
+ CBotClass* c2 = t2.GivClass();
+ if ( !c2->IsChildOf(c1))
+ {
+ CBotToken* pt = &m_token;
+ pile->SetError(TX_BADTYPE, pt);
+ return pj->Return(pile); // operation performed
+ }
+ }
+ var1->SetVal(var2); // do assignment
+ }
+ pile->SetCopyVar(var1); // replace the stack with the copy of the variable
+ // (for name)
+ }
+
+ return pj->Return(pile); // operation performed
+}
+
+// fetch a variable during compilation
+
+bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
+{
+ pVar = pile->FindVar(m_token);
+ if (pVar == NULL) return false;
+
+ if ( m_next3 != NULL &&
+ !m_next3->ExecuteVar(pVar, pile) ) return false;
+
+ return true;
+}
+
+// fetch the variable at runtume
+
+bool CBotLeftExpr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep)
+{
+ pile = pile->AddStack(this);
+
+ pVar = pile->FindVar(m_nIdent);
+ if (pVar == NULL)
+ {
+#ifdef _DEBUG
+ ASM_TRAP();
+#endif
+ pile->SetError(2, &m_token);
+ return false;
+ }
+
+ if (bStep && m_next3 == NULL && pile->IfStep()) return false;
+
+ if ( m_next3 != NULL &&
+ !m_next3->ExecuteVar(pVar, pile, &m_token, bStep, true) ) return false;
+
+ return true;
+}
+
+void CBotLeftExpr::RestoreStateVar(CBotStack* &pile, bool bMain)
+{
+ pile = pile->RestoreStack(this);
+ if (pile == NULL) return;
+
+ if (m_next3 != NULL)
+ m_next3->RestoreStateVar(pile, bMain);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// converts a string into integer
+// may be of the form 0xabc123
+
+long GivNumInt(const char* p)
+{
+ long num = 0;
+ while (*p >= '0' && *p <= '9')
+ {
+ num = num * 10 + *p - '0';
+ p++;
+ }
+ if (*p == 'x' || *p == 'X')
+ {
+ while (*++p != 0)
+ {
+ if (*p >= '0' && *p <= '9')
+ {
+ num = num * 16 + *p - '0';
+ continue;
+ }
+ if (*p >= 'A' && *p <= 'F')
+ {
+ num = num * 16 + *p - 'A' + 10;
+ continue;
+ }
+ if (*p >= 'a' && *p <= 'f')
+ {
+ num = num * 16 + *p - 'a' + 10;
+ continue;
+ }
+ break;
+ }
+ }
+ return num;
+}
+
+// converts a string into a float number
+extern float GivNumFloat(const char* p)
+{
+ double num = 0;
+ double div = 10;
+ bool bNeg = false;
+
+ if (*p == '-')
+ {
+ bNeg = true;
+ p++;
+ }
+ while (*p >= '0' && *p <= '9')
+ {
+ num = num * 10. + (*p - '0');
+ p++;
+ }
+
+ if (*p == '.')
+ {
+ p++;
+ while (*p >= '0' && *p <= '9')
+ {
+ num = num + (*p - '0') / div;
+ div = div * 10;
+ p++;
+ }
+ }
+
+ int exp = 0;
+ if (*p == 'e' || *p == 'E')
+ {
+ char neg = 0;
+ p++;
+ if (*p == '-' || *p == '+') neg = *p++;
+
+ while (*p >= '0' && *p <= '9')
+ {
+ exp = exp * 10 + (*p - '0');
+ p++;
+ }
+ if (neg == '-') exp = -exp;
+ }
+
+ while (exp > 0)
+ {
+ num *= 10.0;
+ exp--;
+ }
+
+ while (exp < 0)
+ {
+ num /= 10.0;
+ exp++;
+ }
+
+ if (bNeg) num = -num;
+ return (float)num;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compiles a token representing a number
+CBotExprNum::CBotExprNum()
+{
+ name = "CBotExprNum";
+}
+
+CBotExprNum::~CBotExprNum()
+{
+}
+
+CBotInstr* CBotExprNum::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->TokenStack();
+
+ CBotExprNum* inst = new CBotExprNum();
+
+ inst->SetToken(p);
+ CBotString s = p->GivString();
+
+ inst->m_numtype = CBotTypInt;
+ if (p->GivType() == TokenTypDef)
+ {
+ inst->m_valint = p->GivIdKey();
+ }
+ else
+ {
+ if (s.Find('.') >= 0 || ( s.Find('x') < 0 && ( s.Find('e') >= 0 || s.Find('E') >= 0 ) ))
+ {
+ inst->m_numtype = CBotTypFloat;
+ inst->m_valfloat = GivNumFloat(s);
+ }
+ else
+ {
+ inst->m_valint = GivNumInt(s);
+ }
+ }
+
+ if (pStk->NextToken(p))
+ {
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, inst->m_numtype);
+ pStk->SetVar(var);
+
+ return pStack->Return(inst, pStk);
+ }
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// execute, returns the corresponding number
+
+bool CBotExprNum::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->IfStep()) return false;
+
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, m_numtype);
+
+ CBotString nombre ;
+ if (m_token.GivType() == TokenTypDef)
+ {
+ nombre = m_token.GivString();
+ }
+
+ switch (m_numtype)
+ {
+ case CBotTypShort:
+ case CBotTypInt:
+ var->SetValInt(m_valint, nombre);
+ break;
+ case CBotTypFloat:
+ var->SetValFloat(m_valfloat);
+ break;
+ }
+ pile->SetVar(var); // place on the stack
+
+ return pj->Return(pile); // it's ok
+}
+
+void CBotExprNum::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain) pj->RestoreStack(this);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a token representing a string
+
+CBotExprAlpha::CBotExprAlpha()
+{
+ name = "CBotExprAlpha";
+}
+
+CBotExprAlpha::~CBotExprAlpha()
+{
+}
+
+CBotInstr* CBotExprAlpha::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->TokenStack();
+
+ CBotExprAlpha* inst = new CBotExprAlpha();
+
+ inst->SetToken(p);
+ p = p->GivNext();
+
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString);
+ pStk->SetVar(var);
+
+ return pStack->Return(inst, pStk);
+}
+
+// execute, returns the corresponding string
+
+bool CBotExprAlpha::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->IfStep()) return false;
+
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypString);
+
+ CBotString chaine = m_token.GivString();
+ chaine = chaine.Mid(1, chaine.GivLength()-2); // removes the quotes
+
+ var->SetValString(chaine); // value of the number
+
+ pile->SetVar(var); // put on the stack
+
+ return pj->Return(pile);
+}
+
+void CBotExprAlpha::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain) pj->RestoreStack(this);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a token representing true or false
+
+CBotExprBool::CBotExprBool()
+{
+ name = "CBotExprBool";
+}
+
+CBotExprBool::~CBotExprBool()
+{
+}
+
+CBotInstr* CBotExprBool::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->TokenStack();
+ CBotExprBool* inst = NULL;
+
+ if ( p->GivType() == ID_TRUE ||
+ p->GivType() == ID_FALSE )
+ {
+ inst = new CBotExprBool();
+ inst->SetToken(p); // stores the operation false or true
+ p = p->GivNext();
+
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
+ pStk->SetVar(var);
+ }
+
+ return pStack->Return(inst, pStk);
+}
+
+// executes, returns true or false
+
+bool CBotExprBool::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->IfStep()) return false;
+
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
+
+ if (GivTokenType() == ID_TRUE) var->SetValInt(1);
+ else var->SetValInt(0);
+
+ pile->SetVar(var); // put on the stack
+ return pj->Return(pile); // forwards below
+}
+
+void CBotExprBool::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain) pj->RestoreStack(this);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// management of the operand "null"
+
+CBotExprNull::CBotExprNull()
+{
+ name = "CBotExprNull";
+}
+
+CBotExprNull::~CBotExprNull()
+{
+}
+
+// executes, returns an empty pointer
+
+bool CBotExprNull::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->IfStep()) return false;
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypNullPointer);
+
+ var->SetInit(true); // null pointer valid
+ pile->SetVar(var); // place on the stack
+ return pj->Return(pile); // forwards below
+}
+
+void CBotExprNull::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain) pj->RestoreStack(this);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// management of the operand "nan"
+
+CBotExprNan::CBotExprNan()
+{
+ name = "CBotExprNan";
+}
+
+CBotExprNan::~CBotExprNan()
+{
+}
+
+// executes, returns null pointer
+
+bool CBotExprNan::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+
+ if (pile->IfStep()) return false;
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypInt);
+
+ var->SetInit(IS_NAN); // nan
+ pile->SetVar(var); // put on the stack
+ return pj->Return(pile); // forward below
+}
+
+void CBotExprNan::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (bMain) pj->RestoreStack(this);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a variable name
+// check that it is known on the stack
+// and it has been initialized
+
+CBotExprVar::CBotExprVar()
+{
+ name = "CBotExprVar";
+ m_nIdent = 0;
+}
+
+CBotExprVar::~CBotExprVar()
+{
+}
+
+CBotInstr* CBotExprVar::Compile(CBotToken* &p, CBotCStack* pStack, int privat)
+{
+ CBotToken* pDebut = p;
+ CBotCStack* pStk = pStack->TokenStack();
+
+ pStk->SetStartError(p->GivStart());
+
+ // is it a variable?
+ if (p->GivType() == TokenTypVar)
+ {
+ CBotInstr* inst = new CBotExprVar(); // create the object
+
+ inst->SetToken(p);
+
+ CBotVar* var;
+
+ if (NULL != (var = pStk->FindVar(p))) // seek if known variable
+ {
+ int ident = var->GivUniqNum();
+ ((CBotExprVar*)inst)->m_nIdent = ident; // identifies variable by its number
+
+ if (ident > 0 && ident < 9000)
+ {
+ if ( var->IsPrivate(privat) &&
+ !pStk->GivBotCall()->m_bCompileClass)
+ {
+ pStk->SetError(TX_PRIVATE, p);
+ goto err;
+ }
+
+ // This is an element of the current class
+ // ads the equivalent of this. before
+ /// \TODO need to be fixed revised and fixed after adding unit
+ ///tests
+ CBotToken token("this");
+ inst->SetToken(&token);
+ ((CBotExprVar*)inst)->m_nIdent = -2; // identificator for this
+
+ CBotFieldExpr* i = new CBotFieldExpr(); // new element
+ i->SetToken(p); // keeps the name of the token
+ i->SetUniqNum(ident);
+ inst->AddNext3(i); // added after
+ }
+
+ p = p->GivNext(); // next token
+
+ while (true)
+ {
+ if (var->GivType() == CBotTypArrayPointer)
+ {
+ if (IsOfType( p, ID_OPBRK )) // check if there is an aindex
+ {
+ CBotIndexExpr* i = new CBotIndexExpr();
+ i->m_expr = CBotExpression::Compile(p, pStk); // compile the formula
+ inst->AddNext3(i); // add to the chain
+
+ var = ((CBotVarArray*)var)->GivItem(0,true); // gets the component [0]
+
+ if (i->m_expr == NULL)
+ {
+ pStk->SetError(TX_BADINDEX, p->GivStart());
+ goto err;
+ }
+ if (!pStk->IsOk() || !IsOfType( p, ID_CLBRK ))
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto err;
+ }
+ continue;
+ }
+ }
+ if (var->GivType(1) == CBotTypPointer) // for classes
+ {
+ if (IsOfType(p, ID_DOT))
+ {
+ CBotToken* pp = p;
+
+ if (p->GivType() == TokenTypVar) // must be a name
+ {
+ if (p->GivNext()->GivType() == ID_OPENPAR) // a method call?
+ {
+ CBotInstr* i = CBotInstrMethode::Compile(p, pStk, var);
+ if (!pStk->IsOk()) goto err;
+ inst->AddNext3(i); // added after
+ return pStack->Return(inst, pStk);
+ }
+ else
+ {
+ CBotFieldExpr* i = new CBotFieldExpr(); // new element
+ i->SetToken(pp); // keeps the name of the token
+ inst->AddNext3(i); // add after
+ var = var->GivItem(p->GivString()); // get item correspondent
+ if (var != NULL)
+ {
+ i->SetUniqNum(var->GivUniqNum());
+ if ( var->IsPrivate() &&
+ !pStk->GivBotCall()->m_bCompileClass)
+ {
+ pStk->SetError(TX_PRIVATE, pp);
+ goto err;
+ }
+ }
+ }
+
+
+ if (var != NULL)
+ {
+ p = p->GivNext(); // skips the name
+ continue;
+ }
+ pStk->SetError(TX_NOITEM, p);
+ goto err;
+ }
+ pStk->SetError(TX_DOT, p->GivStart());
+ goto err;
+ }
+ }
+
+ break;
+ }
+
+ pStk->SetCopyVar(var); // place the copy of the variable on the stack (for type)
+ if (pStk->IsOk()) return pStack->Return(inst, pStk);
+ }
+ pStk->SetError(TX_UNDEFVAR, p);
+err:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ return pStack->Return(NULL, pStk);
+}
+
+CBotInstr* CBotExprVar::CompileMethode(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p;
+ CBotCStack* pStk = pStack->TokenStack();
+
+ pStk->SetStartError(pp->GivStart());
+
+ // is it a variable ?
+ if (pp->GivType() == TokenTypVar)
+ {
+ CBotToken pthis("this");
+ CBotVar* var = pStk->FindVar(pthis);
+ if (var == 0) return pStack->Return(NULL, pStk);
+
+ CBotInstr* inst = new CBotExprVar();
+
+ // this is an element of the current class
+ // adds the equivalent of this. before
+
+ inst->SetToken(&pthis);
+ ((CBotExprVar*)inst)->m_nIdent = -2; // ident for this
+
+ CBotToken* pp = p;
+
+ if (pp->GivType() == TokenTypVar)
+ {
+ if (pp->GivNext()->GivType() == ID_OPENPAR) // a method call?
+ {
+ CBotInstr* i = CBotInstrMethode::Compile(pp, pStk, var);
+ if (pStk->IsOk())
+ {
+ inst->AddNext3(i); // add after
+ p = pp; // previous instruction
+ return pStack->Return(inst, pStk);
+ }
+ pStk->SetError(0,0); // the error is not adressed here
+ }
+ }
+ delete inst;
+ }
+ return pStack->Return(NULL, pStk);
+}
+
+
+// execute, making the value of a variable
+
+bool CBotExprVar::Execute(CBotStack* &pj)
+{
+ CBotVar* pVar = NULL;
+ CBotStack* pile = pj->AddStack(this);
+
+ CBotStack* pile1 = pile;
+
+ if (pile1->GivState() == 0)
+ {
+ if (!ExecuteVar(pVar, pile, NULL, true)) return false; // Get the variable fields and indexes according
+
+ if (pVar) pile1->SetCopyVar(pVar); // place a copy on the stack
+ else
+ {
+ return pj->Return(pile1);
+ }
+ pile1->IncState();
+ }
+
+ pVar = pile1->GivVar();
+
+ if (pVar == NULL)
+ {
+ return pj->Return(pile1);
+ }
+
+ if (pVar->GivInit() == IS_UNDEF)
+ {
+ CBotToken* pt = &m_token;
+ while (pt->GivNext() != NULL) pt = pt->GivNext();
+ pile1->SetError(TX_NOTINIT, pt);
+ return pj->Return(pile1);
+ }
+ return pj->Return(pile1); // operation completed
+}
+
+void CBotExprVar::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if (pile == NULL) return;
+
+ CBotStack* pile1 = pile;
+
+ if (pile1->GivState() == 0)
+ {
+ RestoreStateVar(pile, bMain); // retrieves the variable fields and indexes according
+ return;
+ }
+}
+
+// fetch a variable at runtime
+
+bool CBotExprVar::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep)
+{
+ CBotStack* pile = pj;
+ pj = pj->AddStack(this);
+
+ if (bStep && m_nIdent>0 && pj->IfStep()) return false;
+
+ pVar = pj->FindVar(m_nIdent, true); // tries with the variable update if necessary
+ if (pVar == NULL)
+ {
+#ifdef _DEBUG
+ ASM_TRAP();
+#endif
+ pj->SetError(1, &m_token);
+ return false;
+ }
+ if ( m_next3 != NULL &&
+ !m_next3->ExecuteVar(pVar, pj, &m_token, bStep, false) )
+ return false; // field of an instance, table, methode
+
+ return pile->ReturnKeep(pj); // does not put on stack but get the result if a method was called
+}
+
+
+// fetch variable at runtime
+
+void CBotExprVar::RestoreStateVar(CBotStack* &pj, bool bMain)
+{
+ pj = pj->RestoreStack(this);
+ if (pj == NULL) return;
+
+ if (m_next3 != NULL)
+ m_next3->RestoreStateVar(pj, bMain);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// compile a list of parameters
+
+CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars)
+{
+ bool first = true;
+ CBotInstr* ret = NULL; // to return to the list
+
+ CBotCStack* pile = pStack;
+ int i = 0;
+
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ int start, end;
+ if (!IsOfType(p, ID_CLOSEPAR)) while (true)
+ {
+ start = p->GivStart();
+ pile = pile->TokenStack(); // keeps the result on the stack
+
+ if (first) pStack->SetStartError(start);
+ first = false;
+
+ CBotInstr* param = CBotExpression::Compile(p, pile);
+ end = p->GivStart();
+
+ if (!pile->IsOk())
+ {
+ return pStack->Return(NULL, pile);
+ }
+
+ if (ret == NULL) ret = param;
+ else ret->AddNext(param); // construct the list
+
+ if (param != NULL)
+ {
+ if (pile->GivTypResult().Eq(99))
+ {
+ delete pStack->TokenStack();
+ pStack->SetError(TX_VOID, p->GivStart());
+ return NULL;
+ }
+ ppVars[i] = pile->GivVar();
+ ppVars[i]->GivToken()->SetPos(start, end);
+ i++;
+
+ if (IsOfType(p, ID_COMMA)) continue; // skips the comma
+ if (IsOfType(p, ID_CLOSEPAR)) break;
+ }
+
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ delete pStack->TokenStack();
+ return NULL;
+ }
+ }
+ ppVars[i] = NULL;
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compile a method call
+
+CBotInstrMethode::CBotInstrMethode()
+{
+ m_Parameters = NULL;
+ m_MethodeIdent = 0;
+ name = "CBotInstrMethode";
+}
+
+CBotInstrMethode::~CBotInstrMethode()
+{
+ delete m_Parameters;
+}
+
+CBotInstr* CBotInstrMethode::Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* var)
+{
+ CBotInstrMethode* inst = new CBotInstrMethode();
+ inst->SetToken(p); // corresponding token
+
+ if (NULL != var)
+ {
+ CBotToken* pp = p;
+ p = p->GivNext();
+
+ if (p->GivType() == ID_OPENPAR)
+ {
+ inst->m_NomMethod = pp->GivString();
+
+ // compiles the list of parameters
+ CBotVar* ppVars[1000];
+ inst->m_Parameters = CompileParams(p, pStack, ppVars);
+
+ if (pStack->IsOk())
+ {
+ CBotClass* pClass = var->GivClass(); // pointer to the class
+ inst->m_ClassName = pClass->GivName(); // name of the class
+ CBotTypResult r = pClass->CompileMethode(inst->m_NomMethod, var, ppVars,
+ pStack, inst->m_MethodeIdent);
+ delete pStack->TokenStack(); // release parameters on the stack
+ inst->m_typRes = r;
+
+ if (inst->m_typRes.GivType() > 20)
+ {
+ pStack->SetError(inst->m_typRes.GivType(), pp);
+ delete inst;
+ return NULL;
+ }
+ // put the result on the stack to have something
+ if (inst->m_typRes.GivType() > 0)
+ {
+ CBotVar* pResult = CBotVar::Create("", inst->m_typRes);
+ if (inst->m_typRes.Eq(CBotTypClass))
+ {
+ pResult->SetClass(inst->m_typRes.GivClass());
+ }
+ pStack->SetVar(pResult);
+ }
+ return inst;
+ }
+ delete inst;
+ return NULL;
+ }
+ }
+ pStack->SetError(1234, p);
+ delete inst;
+ return NULL;
+}
+
+// execute the method call
+
+bool CBotInstrMethode::ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend)
+{
+ CBotVar* ppVars[1000];
+ CBotStack* pile1 = pj->AddStack(this, true); // a place for the copy of This
+
+ if (pVar->GivPointer() == NULL)
+ {
+ pj->SetError(TX_NULLPT, prevToken);
+ }
+
+ if (pile1->IfStep()) return false;
+
+ CBotStack* pile2 = pile1->AddStack(); // for the next parameters
+
+ if ( pile1->GivState() == 0)
+ {
+ CBotVar* pThis = CBotVar::Create(pVar);
+ pThis->Copy(pVar);
+ // this value should be taken before the evaluation parameters
+ // Test.Action (Test = Other);
+ // action must act on the value before test = Other!
+
+ pThis->SetName("this");
+ pThis->SetUniqNum(-2);
+ pile1->AddVar(pThis);
+ pile1->IncState();
+ }
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluate the parameters
+ // and places the values on the stack
+ // to be interrupted at any time
+
+ if (p != NULL) while ( true)
+ {
+ if (pile2->GivState() == 0)
+ {
+ if (!p->Execute(pile2)) return false; // interrupted here?
+ if (!pile2->SetState(1)) return false; // special mark to recognize parameters
+ }
+ ppVars[i++] = pile2->GivVar(); // construct the list of pointers
+ pile2 = pile2->AddStack(); // space on the stack for the result
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotClass* pClass = CBotClass::Find(m_ClassName);
+ CBotVar* pThis = pile1->FindVar(-2);
+ CBotVar* pResult = NULL;
+ if (m_typRes.GivType() > 0) pResult = CBotVar::Create("", m_typRes);
+ if (m_typRes.Eq(CBotTypClass))
+ {
+ pResult->SetClass(m_typRes.GivClass());
+ }
+ CBotVar* pRes = pResult;
+
+ if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
+ pThis, ppVars,
+ pResult, pile2, GivToken())) return false;
+ if (pRes != pResult) delete pRes;
+
+ pVar = NULL; // does not return value for this
+ return pj->Return(pile2); // release the entire stack
+}
+
+void CBotInstrMethode::RestoreStateVar(CBotStack* &pile, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotVar* ppVars[1000];
+ CBotStack* pile1 = pile->RestoreStack(this); // place for the copy of This
+ if (pile1 == NULL) return;
+
+ CBotStack* pile2 = pile1->RestoreStack(); // and for the parameters coming
+ if (pile2 == NULL) return;
+
+ CBotVar* pThis = pile1->FindVar("this");
+ pThis->SetUniqNum(-2);
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluate the parameters
+ // and places the values on the stack
+ // to be interrupted at any time
+
+ if (p != NULL) while ( true)
+ {
+ if (pile2->GivState() == 0)
+ {
+ p->RestoreState(pile2, true); // interrupted here!
+ return;
+ }
+ ppVars[i++] = pile2->GivVar(); // construct the list of pointers
+ pile2 = pile2->RestoreStack();
+ if (pile2 == NULL) return;
+
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotClass* pClass = CBotClass::Find(m_ClassName);
+ CBotVar* pResult = NULL;
+
+ CBotVar* pRes = pResult;
+
+ pClass->RestoreMethode(m_MethodeIdent, m_NomMethod,
+ pThis, ppVars, pile2);
+}
+
+
+bool CBotInstrMethode::Execute(CBotStack* &pj)
+{
+ CBotVar* ppVars[1000];
+ CBotStack* pile1 = pj->AddStack(this, true); // place for the copy of This
+
+ if (pile1->IfStep()) return false;
+
+ CBotStack* pile2 = pile1->AddStack(); // and for the parameters coming
+
+ if ( pile1->GivState() == 0)
+ {
+ CBotVar* pThis = pile1->CopyVar(m_token);
+ // this value should be taken before the evaluation parameters
+ // Test.Action (Test = Other);
+ // Action must act on the value before test = Other!
+ pThis->SetName("this");
+ pile1->AddVar(pThis);
+ pile1->IncState();
+ }
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluate the parameters
+ // and places the values on the stack
+ // to be interrupted at any time
+ if (p != NULL) while ( true)
+ {
+ if (pile2->GivState() == 0)
+ {
+ if (!p->Execute(pile2)) return false; // interrupted here?
+ if (!pile2->SetState(1)) return false; // special mark to recognize parameters
+ }
+ ppVars[i++] = pile2->GivVar(); // construct the list of pointers
+ pile2 = pile2->AddStack(); // space on the stack for the results
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotClass* pClass = CBotClass::Find(m_ClassName);
+ CBotVar* pThis = pile1->FindVar("this");
+ CBotVar* pResult = NULL;
+ if (m_typRes.GivType()>0) pResult = CBotVar::Create("", m_typRes);
+ if (m_typRes.Eq(CBotTypClass))
+ {
+ pResult->SetClass(m_typRes.GivClass());
+ }
+ CBotVar* pRes = pResult;
+
+ if ( !pClass->ExecuteMethode(m_MethodeIdent, m_NomMethod,
+ pThis, ppVars,
+ pResult, pile2, GivToken())) return false; // interupted
+
+ // set the new value of this in place of the old variable
+ CBotVar* old = pile1->FindVar(m_token);
+ old->Copy(pThis, false);
+
+ if (pRes != pResult) delete pRes;
+
+ return pj->Return(pile2); // release the entire stack
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compile an instruction "new"
+
+CBotNew::CBotNew()
+{
+ name = "CBotNew";
+ m_Parameters = NULL;
+ m_nMethodeIdent = 0;
+}
+
+CBotNew::~CBotNew()
+{
+}
+
+CBotInstr* CBotNew::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p;
+ if (!IsOfType(p, ID_NEW)) return NULL;
+
+ // verifies that the token is a class name
+ if (p->GivType() != TokenTypVar) return NULL;
+
+ CBotClass* pClass = CBotClass::Find(p);
+ if (pClass == NULL)
+ {
+ pStack->SetError(TX_BADNEW, p);
+ return NULL;
+ }
+
+ CBotNew* inst = new CBotNew();
+ inst->SetToken(pp);
+
+ inst->m_vartoken = p;
+ p = p->GivNext();
+
+ // creates the object on the "job"
+ // with a pointer to the object
+ CBotVar* pVar = CBotVar::Create("", pClass);
+
+ // do the call of the creator
+ CBotCStack* pStk = pStack->TokenStack();
+ {
+ // check if there are parameters
+ CBotVar* ppVars[1000];
+ inst->m_Parameters = CompileParams(p, pStk, ppVars);
+ if (!pStk->IsOk()) goto error;
+
+ // constructor exist?
+ CBotTypResult r = pClass->CompileMethode(pClass->GivName(), pVar, ppVars, pStk, inst->m_nMethodeIdent);
+ delete pStk->TokenStack(); // release extra stack
+ int typ = r.GivType();
+
+ // if there is no constructor, and no parameters either, it's ok
+ if (typ == TX_UNDEFCALL && inst->m_Parameters == NULL) typ = 0;
+ pVar->SetInit(true); // mark the instance as init
+
+ if (typ>20)
+ {
+ pStk->SetError(typ, inst->m_vartoken.GivEnd());
+ goto error;
+ }
+
+ // if the constructor does not exist, but there are parameters
+ if (typ<0 && inst->m_Parameters != NULL)
+ {
+ pStk->SetError(TX_NOCONST, &inst->m_vartoken);
+ goto error;
+ }
+
+ // makes pointer to the object on the stack
+ pStk->SetVar(pVar);
+ return pStack->Return(inst, pStk);
+ }
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// executes instruction "new"
+
+bool CBotNew::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); //main stack
+
+ if (pile->IfStep()) return false;
+
+ CBotStack* pile1 = pj->AddStack2(); //secondary stack
+
+ CBotVar* pThis = NULL;
+
+ CBotToken* pt = &m_vartoken;
+ CBotClass* pClass = CBotClass::Find(pt);
+
+ // create the variable "this" pointer type to the stack
+
+ if ( pile->GivState()==0)
+ {
+ // create an instance of the requested class
+ // and initialize the pointer to that object
+
+
+ pThis = CBotVar::Create("this", pClass);
+ pThis->SetUniqNum(-2) ;
+
+ pile1->SetVar(pThis); // place on stack1
+ pile->IncState();
+ }
+
+ // fetch the this pointer if it was interrupted
+ if ( pThis == NULL)
+ {
+ pThis = pile1->GivVar(); // find the pointer
+ }
+
+ // is there an assignment or parameters (constructor)
+ if ( pile->GivState()==1)
+ {
+ // evaluates the constructor of the instance
+
+ CBotVar* ppVars[1000];
+ CBotStack* pile2 = pile;
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluate the parameters
+ // and places the values on the stack
+ // to be interrupted at any time
+
+ if (p != NULL) while ( true)
+ {
+ pile2 = pile2->AddStack(); // space on the stack for the result
+ if (pile2->GivState() == 0)
+ {
+ if (!p->Execute(pile2)) return false; // interrupted here?
+ pile2->SetState(1);
+ }
+ ppVars[i++] = pile2->GivVar();
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ // create a variable for the result
+ CBotVar* pResult = NULL; // constructos still void
+
+ if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
+ pThis, ppVars,
+ pResult, pile2, GivToken())) return false; // interrupt
+
+ pThis->ConstructorSet(); // indicates that the constructor has been called
+ }
+
+ return pj->Return(pile1); // passes below
+}
+
+void CBotNew::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if (!bMain) return;
+
+ CBotStack* pile = pj->RestoreStack(this); //primary stack
+ if (pile == NULL) return;
+
+ CBotStack* pile1 = pj->AddStack2(); //secondary stack
+
+ CBotToken* pt = &m_vartoken;
+ CBotClass* pClass = CBotClass::Find(pt);
+
+ // create the variable "this" pointer type to the object
+
+ if ( pile->GivState()==0)
+ {
+ return;
+ }
+
+ CBotVar* pThis = pile1->GivVar(); // find the pointer
+ pThis->SetUniqNum(-2);
+
+ // is ther an assignment or parameters (constructor)
+ if ( pile->GivState()==1)
+ {
+ // evaluates the constructor of the instance
+
+ CBotVar* ppVars[1000];
+ CBotStack* pile2 = pile;
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluate the parameters
+ // and places the values on the stack
+ // to be interrupted at any time
+
+ if (p != NULL) while ( true)
+ {
+ pile2 = pile2->RestoreStack(); // space on the stack for the result
+ if (pile2 == NULL) return;
+
+ if (pile2->GivState() == 0)
+ {
+ p->RestoreState(pile2, bMain); // interrupt here!
+ return;
+ }
+ ppVars[i++] = pile2->GivVar();
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ pClass->RestoreMethode(m_nMethodeIdent, m_vartoken.GivString(), pThis,
+ ppVars, pile2) ; // interrupt here!
+ }
+}
+
+/////////////////////////////////////////////////////////////
+// check if two results are consistent to make an operation
+
+bool TypeCompatible(CBotTypResult& type1, CBotTypResult& type2, int op)
+{
+ int t1 = type1.GivType();
+ int t2 = type2.GivType();
+
+ int max = (t1 > t2) ? t1 : t2;
+
+ if (max == 99) return false; // result is void?
+
+ // special case for strin concatenation
+ if (op == ID_ADD && max >= CBotTypString) return true;
+ if (op == ID_ASSADD && max >= CBotTypString) return true;
+ if (op == ID_ASS && t1 == CBotTypString) return true;
+
+ if (max >= CBotTypBoolean)
+ {
+ if ( (op == ID_EQ || op == ID_NE) &&
+ (t1 == CBotTypPointer && t2 == CBotTypNullPointer)) return true;
+ if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) &&
+ (t2 == CBotTypPointer && t1 == CBotTypNullPointer)) return true;
+ if ( (op == ID_EQ || op == ID_NE) &&
+ (t1 == CBotTypArrayPointer && t2 == CBotTypNullPointer)) return true;
+ if ( (op == ID_EQ || op == ID_NE || op == ID_ASS) &&
+ (t2 == CBotTypArrayPointer && t1 == CBotTypNullPointer)) return true;
+ if (t2 != t1) return false;
+ if (t1 == CBotTypArrayPointer) return type1.Compare(type2);
+ if (t1 == CBotTypPointer ||
+ t1 == CBotTypClass ||
+ t1 == CBotTypIntrinsic )
+ {
+ CBotClass* c1 = type1.GivClass();
+ CBotClass* c2 = type2.GivClass();
+
+ return c1->IsChildOf(c2) || c2->IsChildOf(c1);
+ // accept the case in reverse
+ // the transaction will be denied at runtime if the pointer is not
+ // compatible
+ }
+
+ return true;
+ }
+
+ type1.SetType(max);
+ type2.SetType(max);
+ return true;
+}
+
+// check if two variables are compatible for parameter passing
+
+bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2)
+{
+ int t1 = type1.GivType();
+ int t2 = type2.GivType();
+
+ if (t1 == CBotTypIntrinsic) t1 = CBotTypClass;
+ if (t2 == CBotTypIntrinsic) t2 = CBotTypClass;
+
+ int max = (t1 > t2) ? t1 : t2;
+
+ if (max == 99) return false; // result is void?
+
+ if (max >= CBotTypBoolean)
+ {
+ if (t2 != t1) return false;
+
+ if (max == CBotTypArrayPointer)
+ return TypesCompatibles(type1.GivTypElem(), type2.GivTypElem());
+
+ if (max == CBotTypClass || max == CBotTypPointer)
+ return type1.GivClass() == type2.GivClass() ;
+
+ return true ;
+ }
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// file management
+
+// necessary because it is not possible to do the fopen in the main program
+// fwrite and fread in a dll or using the FILE * returned.
+
+
+FILE* fOpen(const char* name, const char* mode)
+{
+ return fopen(name, mode);
+}
+
+int fClose(FILE* filehandle)
+{
+ return fclose(filehandle);
+}
+
+size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle)
+{
+ return fwrite(buffer, elemsize, length, filehandle);
+}
+
+size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle)
+{
+ return fread(buffer, elemsize, length, filehandle);
+}
+
+size_t fWrite(const void *buffer, size_t length, FILE* filehandle)
+{
+ return fwrite(buffer, 1, length, filehandle);
+}
+
+size_t fRead(void *buffer, size_t length, FILE* filehandle)
+{
+ return fread(buffer, 1, length, filehandle);
+}
+
+
+////////////////////////////////////////
+
diff --git a/src/CBot/CBot.h b/src/CBot/CBot.h
index e28bbee..ebc8e52 100644
--- a/src/CBot/CBot.h
+++ b/src/CBot/CBot.h
@@ -1,1633 +1,1732 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.////////////////////////////////////////////////////////////////////
-// interpréteur pour le language CBot du jeu COLOBOT
-
-// dernière révision : 03/10/2002 DD
-
-#define EXTENDS TRUE
-
-
-#include "resource.h"
-#include "CBotDll.h" // définitions publiques
-#include "CBotToken.h" // gestion des tokens
-
-#define STACKRUN TRUE // reprise de l'exécution direct sur une routine suspendue
-#define STACKMEM TRUE // préréserve la mémoire pour la pile d'exécution
-#define MAXSTACK 990 // taille du stack réservé
-
-#define EOX (CBotStack*)-1 // marqueur condition spéciale
-
-
-// fix for MSVC instruction __asm int 3 (setting a trap)
-#ifdef __MINGW32__
-#define ASM_TRAP() asm("int $3");
-#else
-#define ASM_TRAP() __asm int 3;
-#endif
-
-/////////////////////////////////////////////////////////////////////
-// résumé des classes utilisées, définies ci-après
-
-class CBotCompExpr; // une expression telle que
- // () <= ()
-class CBotAddExpr; // une expression telle que
- // () + ()
-class CBotParExpr; // un élément de base ou entre parenthèse
- // Toto.truc
- // 12.5
- // "chaine"
- // ( expression )
-class CBotExprVar; // un nom de variable tel que
- // Toto
- // chose.truc.machin
-class CBotWhile; // while (...) {...};
-class CBotIf; // if (...) {...} else {...}
-class CBotDefParam; // liste de paramètres d'une fonction
-class CBotRepeat; // repeat (nb) {...}
-
-
-
-////////////////////////////////////////////////////////////////////////
-// Gestion de la pile d'exécution
-////////////////////////////////////////////////////////////////////////
-
-// en fait, en externe, la seule chose qu'il est possible de faire
-// c'est de créer une instance d'une pile
-// pour l'utiliser pour la routine CBotProgram::Execute(CBotStack)
-
-class CBotStack
-{
-private:
- CBotStack* m_next;
- CBotStack* m_next2;
- CBotStack* m_prev;
- friend class CBotInstArray;
-
-#ifdef _DEBUG
- int m_index;
-#endif
- int m_state;
- int m_step;
- static int m_error;
- static int m_start;
- static int m_end;
- static
- CBotVar* m_retvar; // résultat d'un return
-
- CBotVar* m_var; // résultat des opérations
- CBotVar* m_listVar; // les variables déclarées à ce niveau
-
- BOOL m_bBlock; // fait partie d'un bloc (variables sont locales à ce bloc)
- BOOL m_bOver; // limites de la pile ?
-// BOOL m_bDontDelete; // spécial, ne pas détruire les variables au delete
- CBotProgram* m_prog; // les fonctions définies par user
-
- static
- int m_initimer;
- static
- int m_timer;
- static
- CBotString m_labelBreak;
- static
- void* m_pUser;
-
- CBotInstr* m_instr; // l'instruction correspondante
- BOOL m_bFunc; // une entrée d'une fonction ?
- CBotCall* m_call; // point de reprise dans un call extern
- friend class CBotTry;
-
-public:
-#if STACKMEM
- static
- CBotStack* FirstStack();
- void Delete();
-#endif
- CBotStack(CBotStack* ppapa);
- ~CBotStack();
- BOOL StackOver();
-
- int GivError(int& start, int& end);
- int GivError(); // rend le numéro d'erreur retourné
-
- void Reset(void* pUser); // plus d'erreur, timer au début
- void SetType(CBotTypResult& type); // détermine le type
- int GivType(int mode = 0); // donne le type de valeur sur le stack
- CBotTypResult GivTypResult(int mode = 0); // donne le type complet de valeur sur le stack
-
-// void AddVar(CBotVar* p, BOOL bDontDelete=FALSE); // ajoute une variable locale
- void AddVar(CBotVar* p); // ajoute une variable locale
-// void RestoreVar(CBotVar* pVar);
-
- CBotVar* FindVar(CBotToken* &p, BOOL bUpdate = FALSE,
- BOOL bModif = FALSE); // trouve une variable
- CBotVar* FindVar(CBotToken& Token, BOOL bUpdate = FALSE,
- BOOL bModif = FALSE);
- CBotVar* FindVar(const char* name);
- CBotVar* FindVar(long ident, BOOL bUpdate = FALSE,
- BOOL bModif = FALSE);
-
- CBotVar* CopyVar(CBotToken& Token, BOOL bUpdate = FALSE); // trouve et rend une copie
-
-
- CBotStack* AddStack(CBotInstr* instr = NULL, BOOL bBlock = FALSE); // étend le stack
- CBotStack* AddStackEOX(CBotCall* instr = NULL, BOOL bBlock = FALSE); // étend le stack
- CBotStack* RestoreStack(CBotInstr* instr = NULL);
- CBotStack* RestoreStackEOX(CBotCall* instr = NULL);
-
- CBotStack* AddStack2(BOOL bBlock = FALSE); // étend le stack
- BOOL Return(CBotStack* pFils); // transmet le résultat au dessus
- BOOL ReturnKeep(CBotStack* pFils); // transmet le résultat sans réduire la pile
- BOOL BreakReturn(CBotStack* pfils, const char* name = NULL);
- // en cas de break éventuel
- BOOL IfContinue(int state, const char* name);
- // ou de "continue"
-
- BOOL IsOk();
-
- BOOL SetState(int n, int lim = -10); // sélectionne un état
- int GivState(); // dans quel état j'ère ?
- BOOL IncState(int lim = -10); // passe à l'état suivant
- BOOL IfStep(); // faire du pas à pas ?
- BOOL Execute();
-
- void SetVar( CBotVar* var );
- void SetCopyVar( CBotVar* var );
- CBotVar* GivVar();
- CBotVar* GivCopyVar();
- CBotVar* GivPtVar();
- BOOL GivRetVar(BOOL bRet);
- long GivVal();
-
- void SetStartError(int pos);
- void SetError(int n, CBotToken* token = NULL);
- void SetPosError(CBotToken* token);
- void ResetError(int n, int start, int end);
- void SetBreak(int val, const char* name);
-
- void SetBotCall(CBotProgram* p);
- CBotProgram* GivBotCall(BOOL bFirst = FALSE);
- void* GivPUser();
- BOOL GivBlock();
-
-
-// BOOL ExecuteCall(CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype);
- BOOL ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype);
- void RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar);
-
- BOOL SaveState(FILE* pf);
- BOOL RestoreState(FILE* pf, CBotStack* &pStack);
-
- static
- void SetTimer(int n);
-
- void GetRunPos(const char* &FunctionName, int &start, int &end);
- CBotVar* GivStackVars(const char* &FunctionName, int level);
-
- int m_temp;
-};
-
-// les routines inline doivent être déclarées dans le fichier .h
-
-inline BOOL CBotStack::IsOk()
-{
- return (m_error == 0);
-}
-
-inline int CBotStack::GivState()
-{
- return m_state;
-}
-
-inline int CBotStack::GivError()
-{
- return m_error;
-}
-
-////////////////////////////////////////////////////////////////////////
-// Gestion de la pile de compilation
-////////////////////////////////////////////////////////////////////////
-
-
-class CBotCStack
-{
-private:
- CBotCStack* m_next;
- CBotCStack* m_prev;
-
- static
- int m_error;
- static
- int m_end;
- int m_start;
-
- CBotVar* m_var; // résultat des opérations
-
- BOOL m_bBlock; // fait partie d'un bloc (variables sont locales à ce bloc)
- CBotVar* m_listVar;
-
- static
- CBotProgram* m_prog; // liste des fonctions compilées
- static
- CBotTypResult m_retTyp;
-// static
-// CBotToken* m_retClass;
-
-public:
- CBotCStack(CBotCStack* ppapa);
- ~CBotCStack();
-
- BOOL IsOk();
- int GivError();
- int GivError(int& start, int& end);
- // rend le numéro d'erreur retourné
-
- void SetType(CBotTypResult& type);// détermine le type
- CBotTypResult GivTypResult(int mode = 0); // donne le type de valeur sur le stack
- int GivType(int mode = 0); // donne le type de valeur sur le stack
- CBotClass* GivClass(); // donne la classe de la valeur sur le stack
-
- void AddVar(CBotVar* p); // ajoute une variable locale
- CBotVar* FindVar(CBotToken* &p); // trouve une variable
- CBotVar* FindVar(CBotToken& Token);
- BOOL CheckVarLocal(CBotToken* &pToken);
- CBotVar* CopyVar(CBotToken& Token); // trouve et rend une copie
-
- CBotCStack* TokenStack(CBotToken* pToken = NULL, BOOL bBlock = FALSE);
- CBotInstr* Return(CBotInstr* p, CBotCStack* pParent); // transmet le résultat au dessus
- CBotFunction* ReturnFunc(CBotFunction* p, CBotCStack* pParent); // transmet le résultat au dessus
-
- void SetVar( CBotVar* var );
- void SetCopyVar( CBotVar* var );
- CBotVar* GivVar();
-
- void SetStartError(int pos);
- void SetError(int n, int pos);
- void SetError(int n, CBotToken* p);
- void ResetError(int n, int start, int end);
-
- void SetRetType(CBotTypResult& type);
- CBotTypResult GivRetType();
-
-// void SetBotCall(CBotFunction* &pFunc);
- void SetBotCall(CBotProgram* p);
- CBotProgram* GivBotCall();
- CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent);
- BOOL CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
-
- BOOL NextToken(CBotToken* &p);
-};
-
-
-extern BOOL SaveVar(FILE* pf, CBotVar* pVar);
-
-
-/////////////////////////////////////////////////////////////////////
-// classes définissant une instruction
-class CBotInstr
-{
-private:
- static
- CBotStringArray
- m_labelLvl;
-protected:
- CBotToken m_token; // conserve le token
- CBotString name; // debug
- CBotInstr* m_next; // instructions chaînées
- CBotInstr* m_next2b; // seconde liste pour définition en chaîne
- CBotInstr* m_next3; // troisième liste pour les indices et champs
- CBotInstr* m_next3b; // nécessaire pour la déclaration des tableaux
-/*
- par exemple, le programme suivant
- int x[]; x[1] = 4;
- int y[x[1]][10], z;
- va généré
- CBotInstrArray
- m_next3b-> CBotEmpty
- m_next->
- CBotExpression ....
- m_next->
- CBotInstrArray
- m_next3b-> CBotExpression ('x') ( m_next3-> CBotIndexExpr ('1') )
- m_next3b-> CBotExpression ('10')
- m_next2-> 'z'
- m_next->...
-
-*/
-
- static
- int m_LoopLvl;
- friend class CBotClassInst;
- friend class CBotInt;
- friend class CBotListArray;
-
-public:
- CBotInstr();
- virtual
- ~CBotInstr();
-
- DllExport//debug
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- static
- CBotInstr* CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, BOOL first = TRUE);
-
- virtual
- BOOL Execute(CBotStack* &pj);
- virtual
- BOOL Execute(CBotStack* &pj, CBotVar* pVar);
- virtual
- void RestoreState(CBotStack* &pj, BOOL bMain);
-
- virtual
- BOOL ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- virtual
- BOOL ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend);
- virtual
- void RestoreStateVar(CBotStack* &pile, BOOL bMain);
-
- virtual
- BOOL CompCase(CBotStack* &pj, int val);
-
- void SetToken(CBotToken* p);
- void SetToken(CBotString* name, int start=0, int end=0);
- int GivTokenType();
- CBotToken* GivToken();
-
- void AddNext(CBotInstr* n);
- CBotInstr* GivNext();
- void AddNext3(CBotInstr* n);
- CBotInstr* GivNext3();
- void AddNext3b(CBotInstr* n);
- CBotInstr* GivNext3b();
-
- static
- void IncLvl(CBotString& label);
- static
- void IncLvl();
- static
- void DecLvl();
- static
- BOOL ChkLvl(const CBotString& label, int type);
-
- BOOL IsOfClass(CBotString name);
-};
-
-class CBotWhile : public CBotInstr
-{
-private:
- CBotInstr* m_Condition; // la condition
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotWhile();
- ~CBotWhile();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotRepeat : public CBotInstr
-{
-private:
- CBotInstr* m_NbIter; // le nombre d'itération
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotRepeat();
- ~CBotRepeat();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotDo : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_Condition; // la condition
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotDo();
- ~CBotDo();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotFor : public CBotInstr
-{
-private:
- CBotInstr* m_Init; // intruction initiale
- CBotInstr* m_Test; // la condition de test
- CBotInstr* m_Incr; // instruction pour l'incrément
- CBotInstr* m_Block; // les instructions
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotFor();
- ~CBotFor();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotBreak : public CBotInstr
-{
-private:
- CBotString m_label; // une étiquette s'il y a
-
-public:
- CBotBreak();
- ~CBotBreak();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotReturn : public CBotInstr
-{
-private:
- CBotInstr* m_Instr; // le paramètre à retourner
-
-public:
- CBotReturn();
- ~CBotReturn();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotSwitch : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // value à chercher
- CBotInstr* m_Block; // les instructions
-
-public:
- CBotSwitch();
- ~CBotSwitch();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotCase : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // valeur à comparer
-
-public:
- CBotCase();
- ~CBotCase();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
- BOOL CompCase(CBotStack* &pj, int val);
-};
-
-class CBotCatch : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_Cond; // la condition
- CBotCatch* m_next; // le catch suivant
- friend class CBotTry;
-
-public:
- CBotCatch();
- ~CBotCatch();
- static
- CBotCatch* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL TestCatch(CBotStack* &pj, int val);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
- void RestoreCondState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotTry : public CBotInstr
-{
-private:
- CBotInstr* m_Block; // les instructions
- CBotCatch* m_ListCatch; // les catches
- CBotInstr* m_FinalInst; // instruction finale
-
-public:
- CBotTry();
- ~CBotTry();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotThrow : public CBotInstr
-{
-private:
- CBotInstr* m_Value; // la valeur à envoyer
-
-public:
- CBotThrow();
- ~CBotThrow();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotStartDebugDD : public CBotInstr
-{
-private:
-
-public:
- CBotStartDebugDD();
- ~CBotStartDebugDD();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
-};
-
-
-class CBotIf : public CBotInstr
-{
-private:
- CBotInstr* m_Condition; // la condition
- CBotInstr* m_Block; // les instructions
- CBotInstr* m_BlockElse; // les instructions
-
-public:
- CBotIf();
- ~CBotIf();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-// définition d'un nombre entier
-
-class CBotInt : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-/// CBotInstr* m_next; // plusieurs définitions enchaînées
-
-public:
- CBotInt();
- ~CBotInt();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont = FALSE, BOOL noskip = FALSE);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// définition d'un tableau
-
-class CBotInstArray : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_listass; // liste d'assignations pour le tableau
- CBotTypResult
- m_typevar; // type d'éléments
-// CBotString m_ClassName;
-
-public:
- CBotInstArray();
- ~CBotInstArray();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-// définition d'une liste d'assignation pour un tableau
-// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ;
-
-class CBotListArray : public CBotInstr
-{
-private:
- CBotInstr* m_expr; // expression pour un élément
- // les autres sont chaînés avec CBotInstr::m_next3;
-public:
- CBotListArray();
- ~CBotListArray();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
- BOOL Execute(CBotStack* &pj, CBotVar* pVar);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotEmpty : public CBotInstr
-{
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// définition d'un booléen
-
-class CBotBoolean : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotBoolean();
- ~CBotBoolean();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont = FALSE, BOOL noskip=FALSE);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-// définition d'un nombre réel
-
-class CBotFloat : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotFloat();
- ~CBotFloat();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont = FALSE, BOOL noskip=FALSE);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// définition d'un elément string
-
-class CBotIString : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
-
-public:
- CBotIString();
- ~CBotIString();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, BOOL cont = FALSE, BOOL noskip=FALSE);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// définition d'un elément dans une classe quelconque
-
-class CBotClassInst : public CBotInstr
-{
-private:
- CBotInstr* m_var; // la variable à initialiser
- CBotClass* m_pClass; // référence à la classe
- CBotInstr* m_Parameters; // les paramètres à évaluer pour le constructeur
- CBotInstr* m_expr; // la valeur à mettre, s'il y a
- BOOL m_hasParams; // il y a des paramètres ?
- long m_nMethodeIdent;
-
-public:
- CBotClassInst();
- ~CBotClassInst();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass = NULL);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotCondition : public CBotInstr
-{
-private:
-
-public:
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-
-// left opérande
-// n'accepte que les expressions pouvant être à gauche d'une assignation
-
-class CBotLeftExpr : public CBotInstr
-{
-private:
- long m_nIdent;
-
-public:
- CBotLeftExpr();
- ~CBotLeftExpr();
- static
- CBotLeftExpr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pStack, CBotStack* array);
-
- BOOL ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- BOOL ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep);
- void RestoreStateVar(CBotStack* &pile, BOOL bMain);
-};
-
-
-// gestion des champs d'une instance
-
-class CBotFieldExpr : public CBotInstr
-{
-private:
- friend class CBotExpression;
- int m_nIdent;
-
-public:
- CBotFieldExpr();
- ~CBotFieldExpr();
- void SetUniqNum(int num);
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- BOOL ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend);
- void RestoreStateVar(CBotStack* &pj, BOOL bMain);
-};
-
-// gestion des index dans les tableaux
-
-class CBotIndexExpr : public CBotInstr
-{
-private:
- CBotInstr* m_expr; // expression pour le calcul de l'index
- friend class CBotLeftExpr;
- friend class CBotExprVar;
-
-public:
- CBotIndexExpr();
- ~CBotIndexExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
- BOOL ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend);
- void RestoreStateVar(CBotStack* &pj, BOOL bMain);
-};
-
-// une expression du genre
-// x = a;
-// x * y + 3;
-
-class CBotExpression : public CBotInstr
-{
-private:
- CBotLeftExpr* m_leftop; // élément de gauche
- CBotInstr* m_rightop; // élément de droite
-
-public:
- CBotExpression();
- ~CBotExpression();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotListExpression : public CBotInstr
-{
-private:
- CBotInstr* m_Expr; // la 1ère expression à évaluer
-
-public:
- CBotListExpression();
- ~CBotListExpression();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotLogicExpr : public CBotInstr
-{
-private:
- CBotInstr* m_condition; // test à évaluer
- CBotInstr* m_op1; // élément de gauche
- CBotInstr* m_op2; // élément de droite
- friend class CBotTwoOpExpr;
-
-public:
- CBotLogicExpr();
- ~CBotLogicExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-
-class CBotBoolExpr : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-
-
-// une expression éventuellement entre parenthèses ( ... )
-// il n'y a jamais d'instance de cette classe
-// l'objet retourné étant le contenu de la parenthése
-class CBotParExpr : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
-};
-
-// expression unaire
-class CBotExprUnaire : public CBotInstr
-{
-private:
- CBotInstr* m_Expr; // l'expression à évaluer
-public:
- CBotExprUnaire();
- ~CBotExprUnaire();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// toutes les opérations à 2 opérandes
-
-class CBotTwoOpExpr : public CBotInstr
-{
-private:
- CBotInstr* m_leftop; // élément de gauche
- CBotInstr* m_rightop; // élément de droite
-public:
- CBotTwoOpExpr();
- ~CBotTwoOpExpr();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = NULL);
- BOOL Execute(CBotStack* &pStack);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-
-
-// un bloc d'instructions { .... }
-class CBotBlock : public CBotInstr
-{
-private:
-
-public:
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, BOOL bLocal = TRUE);
- static
- CBotInstr* CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, BOOL bLocal = FALSE);
-};
-
-
-// le contenu d'un bloc d'instructions ... ; ... ; ... ; ... ;
-class CBotListInstr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr; // les instructions à faire
-
-public:
- CBotListInstr();
- ~CBotListInstr();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, BOOL bLocal = TRUE);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotInstrCall : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
-// int m_typeRes; // type du résultat
-// CBotString m_RetClassName; // class du résultat
- CBotTypResult
- m_typRes; // type complet du résultat
- long m_nFuncIdent; // id de la fonction
-
-public:
- CBotInstrCall();
- ~CBotInstrCall();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// un appel d'une méthode
-
-class CBotInstrMethode : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
-// int m_typeRes; // type du résultat
-// CBotString m_RetClassName; // class du résultat
- CBotTypResult
- m_typRes; // type complet du résultat
-
- CBotString m_NomMethod; // nom de la méthode
- long m_MethodeIdent; // identificateur de la méthode
-// long m_nThisIdent; // identificateur pour "this"
- CBotString m_ClassName; // nom de la classe
-
-public:
- CBotInstrMethode();
- ~CBotInstrMethode();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar);
- BOOL Execute(CBotStack* &pj);
- BOOL ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, BOOL bStep, BOOL bExtend);
- void RestoreStateVar(CBotStack* &pj, BOOL bMain);
-};
-
-// expression donnant un nom de variable
-
-class CBotExprVar : public CBotInstr
-{
-private:
- long m_nIdent;
- friend class CBotPostIncExpr;
- friend class CBotPreIncExpr;
-
-public:
- CBotExprVar();
- ~CBotExprVar();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int privat=PR_PROTECT);
- static
- CBotInstr* CompileMethode(CBotToken* &p, CBotCStack* pStack);
-
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
- BOOL ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep);
- BOOL Execute2Var(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, BOOL bStep);
- void RestoreStateVar(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotPostIncExpr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr;
- friend class CBotParExpr;
-
-public:
- CBotPostIncExpr();
- ~CBotPostIncExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotPreIncExpr : public CBotInstr
-{
-private:
- CBotInstr* m_Instr;
- friend class CBotParExpr;
-
-public:
- CBotPreIncExpr();
- ~CBotPreIncExpr();
-// static
-// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotLeftExprVar : public CBotInstr
-{
-private:
-public:
- CBotTypResult
- m_typevar; // type de variable déclarée
- long m_nIdent; // identificateur unique pour cette variable
-
-public:
- CBotLeftExprVar();
- ~CBotLeftExprVar();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotExprBool : public CBotInstr
-{
-private:
-
-public:
- CBotExprBool();
- ~CBotExprBool();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-class CBotExprNull : public CBotInstr
-{
-private:
-
-public:
- CBotExprNull();
- ~CBotExprNull();
-
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotExprNan : public CBotInstr
-{
-private:
-
-public:
- CBotExprNan();
- ~CBotExprNan();
-
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-class CBotNew : public CBotInstr
-{
-private:
- CBotInstr* m_Parameters; // les paramètres à évaluer
- long m_nMethodeIdent;
-// long m_nThisIdent;
- CBotToken m_vartoken;
-
-public:
- CBotNew();
- ~CBotNew();
-
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-// expression représentant un nombre
-
-class CBotExprNum : public CBotInstr
-{
-private:
- int m_numtype; // et le type de nombre
- long m_valint; // valeur pour un int
- float m_valfloat; // valeur pour un float
-
-public:
- CBotExprNum();
- ~CBotExprNum();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-
-// expression représentant une chaine de caractères
-
-class CBotExprAlpha : public CBotInstr
-{
-private:
-
-public:
- CBotExprAlpha();
- ~CBotExprAlpha();
- static
- CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-};
-
-
-#define MAX(a,b) ((a>b) ? a : b)
-
-
-// classe pour la gestion des nombres entier (int)
-class CBotVarInt : public CBotVar
-{
-private:
- int m_val; // la valeur
- CBotString m_defnum; // le nom si donné par DefineNum
- friend class CBotVar;
-
-public:
- CBotVarInt( const CBotToken* name );
-// ~CBotVarInt();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
-
-
- void Add(CBotVar* left, CBotVar* right); // addition
- void Sub(CBotVar* left, CBotVar* right); // soustraction
- void Mul(CBotVar* left, CBotVar* right); // multiplication
- int Div(CBotVar* left, CBotVar* right); // division
- int Modulo(CBotVar* left, CBotVar* right); // reste de division
- void Power(CBotVar* left, CBotVar* right); // puissance
-
- BOOL Lo(CBotVar* left, CBotVar* right);
- BOOL Hi(CBotVar* left, CBotVar* right);
- BOOL Ls(CBotVar* left, CBotVar* right);
- BOOL Hs(CBotVar* left, CBotVar* right);
- BOOL Eq(CBotVar* left, CBotVar* right);
- BOOL Ne(CBotVar* left, CBotVar* right);
-
- void XOr(CBotVar* left, CBotVar* right);
- void Or(CBotVar* left, CBotVar* right);
- void And(CBotVar* left, CBotVar* right);
-
- void SL(CBotVar* left, CBotVar* right);
- void SR(CBotVar* left, CBotVar* right);
- void ASR(CBotVar* left, CBotVar* right);
-
- void Neg();
- void Not();
- void Inc();
- void Dec();
-
- BOOL Save0State(FILE* pf);
- BOOL Save1State(FILE* pf);
-
-};
-
-// classe pour la gestion des nombres réels (float)
-class CBotVarFloat : public CBotVar
-{
-private:
- float m_val; // la valeur
-
-public:
- CBotVarFloat( const CBotToken* name );
-// ~CBotVarFloat();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
-
-
- void Add(CBotVar* left, CBotVar* right); // addition
- void Sub(CBotVar* left, CBotVar* right); // soustraction
- void Mul(CBotVar* left, CBotVar* right); // multiplication
- int Div(CBotVar* left, CBotVar* right); // division
- int Modulo(CBotVar* left, CBotVar* right); // reste de division
- void Power(CBotVar* left, CBotVar* right); // puissance
-
- BOOL Lo(CBotVar* left, CBotVar* right);
- BOOL Hi(CBotVar* left, CBotVar* right);
- BOOL Ls(CBotVar* left, CBotVar* right);
- BOOL Hs(CBotVar* left, CBotVar* right);
- BOOL Eq(CBotVar* left, CBotVar* right);
- BOOL Ne(CBotVar* left, CBotVar* right);
-
- void Neg();
- void Inc();
- void Dec();
-
- BOOL Save1State(FILE* pf);
-};
-
-
-// classe pour la gestion des chaînes (String)
-class CBotVarString : public CBotVar
-{
-private:
- CBotString m_val; // la valeur
-
-public:
- CBotVarString( const CBotToken* name );
-// ~CBotVarString();
-
- void SetValString(const char* p);
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
-
- void Add(CBotVar* left, CBotVar* right); // addition
-
- BOOL Lo(CBotVar* left, CBotVar* right);
- BOOL Hi(CBotVar* left, CBotVar* right);
- BOOL Ls(CBotVar* left, CBotVar* right);
- BOOL Hs(CBotVar* left, CBotVar* right);
- BOOL Eq(CBotVar* left, CBotVar* right);
- BOOL Ne(CBotVar* left, CBotVar* right);
-
- BOOL Save1State(FILE* pf);
-};
-
-// classe pour la gestion des boolean
-class CBotVarBoolean : public CBotVar
-{
-private:
- BOOL m_val; // la valeur
-
-public:
- CBotVarBoolean( const CBotToken* name );
-// ~CBotVarBoolean();
-
- void SetValInt(int val, const char* s = NULL);
- void SetValFloat(float val);
- int GivValInt();
- float GivValFloat();
- CBotString GivValString();
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
-
- void And(CBotVar* left, CBotVar* right);
- void Or(CBotVar* left, CBotVar* right);
- void XOr(CBotVar* left, CBotVar* right);
- void Not();
- BOOL Eq(CBotVar* left, CBotVar* right);
- BOOL Ne(CBotVar* left, CBotVar* right);
-
- BOOL Save1State(FILE* pf);
-};
-
-
-// classe pour la gestion des instances de classe
-class CBotVarClass : public CBotVar
-{
-private:
- static
- CBotVarClass* m_ExClass; // liste des instances existantes à un moment donné
- CBotVarClass* m_ExNext; // pour cette liste générale
- CBotVarClass* m_ExPrev; // pour cette liste générale
-
-private:
- CBotClass* m_pClass; // la définition de la classe
- CBotVarClass* m_pParent; // l'instance dans la classe parent
- CBotVar* m_pVar; // contenu
- friend class CBotVar; // mon papa est un copain
- friend class CBotVarPointer; // et le pointeur aussi
- int m_CptUse; // compteur d'utilisation
- long m_ItemIdent; // identificateur (unique) de l'instance
- BOOL m_bConstructor; // set si un constructeur a été appelé
-
-public:
- CBotVarClass( const CBotToken* name, const CBotTypResult& type );
-// CBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
- ~CBotVarClass();
-// void InitCBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
- void SetClass(CBotClass* pClass); //, int &nIdent);
- CBotClass* GivClass();
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- CBotVar* GivItemRef(int nIdent);
-
- CBotVar* GivItem(int n, BOOL bExtend);
- CBotVar* GivItemList();
-
- CBotString GivValString();
-
- BOOL Save1State(FILE* pf);
- void Maj(void* pUser, BOOL bContinue);
-
- void IncrementUse(); // une référence en plus
- void DecrementUse(); // une référence en moins
-
- CBotVarClass*
- GivPointer();
- void SetItemList(CBotVar* pVar);
-
- void SetIdent(long n);
-
- static
- CBotVarClass*
- CBotVarClass::Find(long id);
-
-
-// CBotVar* GivMyThis();
-
- BOOL Eq(CBotVar* left, CBotVar* right);
- BOOL Ne(CBotVar* left, CBotVar* right);
-
- void ConstructorSet();
-};
-
-
-// classe pour la gestion des pointeurs à une instances de classe
-class CBotVarPointer : public CBotVar
-{
-private:
- CBotVarClass*
- m_pVarClass; // contenu
- CBotClass* m_pClass; // la classe prévue pour ce pointeur
- friend class CBotVar; // mon papa est un copain
-
-public:
- CBotVarPointer( const CBotToken* name, CBotTypResult& type );
- ~CBotVarPointer();
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
- void SetClass(CBotClass* pClass);
- CBotClass* GivClass();
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- CBotVar* GivItemRef(int nIdent);
- CBotVar* GivItemList();
-
- CBotString GivValString();
- void SetPointer(CBotVar* p);
- CBotVarClass*
- GivPointer();
-
- void SetIdent(long n); // associe un numéro d'identification (unique)
- long GivIdent(); // donne le numéro d'identification associé
- void ConstructorSet();
-
- BOOL Save1State(FILE* pf);
- void Maj(void* pUser, BOOL bContinue);
-
- BOOL Eq(CBotVar* left, CBotVar* right);
- BOOL Ne(CBotVar* left, CBotVar* right);
-};
-
-
-// classe pour les tableaux
-
-#define MAXARRAYSIZE 9999
-
-class CBotVarArray : public CBotVar
-{
-private:
- CBotVarClass*
- m_pInstance; // instance gérant le tableau
-
- friend class CBotVar; // papa est un copain
-
-public:
- CBotVarArray( const CBotToken* name, CBotTypResult& type );
- ~CBotVarArray();
-
- void SetPointer(CBotVar* p);
- CBotVarClass*
- GivPointer();
-
- void Copy(CBotVar* pSrc, BOOL bName=TRUE);
- CBotVar* GivItem(int n, BOOL bGrow=FALSE); // rend un élément selon son index numérique
- // agrandi le tableau si nécessaire si bExtend
-// CBotVar* GivItem(const char* name); // rend un élément selon son index litéral
- CBotVar* GivItemList(); // donne le premier élément de la liste
-
- CBotString GivValString(); // donne le contenu du tableau dans une chaîne
-
- BOOL Save1State(FILE* pf);
-};
-
-
-extern CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars);
-
-extern BOOL TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op = 0 );
-extern BOOL TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 );
-
-extern BOOL WriteWord(FILE* pf, WORD w);
-extern BOOL ReadWord(FILE* pf, WORD& w);
-extern BOOL ReadLong(FILE* pf, long& w);
-extern BOOL WriteFloat(FILE* pf, float w);
-extern BOOL WriteLong(FILE* pf, long w);
-extern BOOL ReadFloat(FILE* pf, float& w);
-extern BOOL WriteString(FILE* pf, CBotString s);
-extern BOOL ReadString(FILE* pf, CBotString& s);
-extern BOOL WriteType(FILE* pf, CBotTypResult type);
-extern BOOL ReadType(FILE* pf, CBotTypResult& type);
-
-extern float GivNumFloat( const char* p );
-
-#if FALSE
-extern void DEBUG( const char* text, int val, CBotStack* pile );
-#endif
-
-///////////////////////////////////////////
-// classe pour les appels de routines (externes)
-
-class CBotCall
-{
-private:
- static
- CBotCall* m_ListCalls;
- static
- void* m_pUser;
- long m_nFuncIdent;
-
-private:
- CBotString m_name;
- BOOL (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser) ;
- CBotTypResult
- (*m_rComp) (CBotVar* &pVar, void* pUser) ;
- CBotCall* m_next;
-
-public:
- CBotCall(const char* name,
- BOOL rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
- ~CBotCall();
-
- static
- BOOL AddFunction(const char* name,
- BOOL rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
-
- static
- CBotTypResult
- CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent);
- static
- BOOL CheckCall(const char* name);
-
-// static
-// int DoCall(CBotToken* &p, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
- static
- int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
-#if STACKRUN
- BOOL Run(CBotStack* pStack);
- static
- BOOL RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack);
-#endif
-
- CBotString GivName();
- CBotCall* Next();
-
- static void SetPUser(void* pUser);
- static void Free();
-};
-
-// classe gérant les méthodes déclarées par AddFunction sur une classe
-
-class CBotCallMethode
-{
-private:
- CBotString m_name;
- BOOL (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception);
- CBotTypResult
- (*m_rComp) (CBotVar* pThis, CBotVar* &pVar);
- CBotCallMethode* m_next;
- friend class CBotClass;
- long m_nFuncIdent;
-
-public:
- CBotCallMethode(const char* name,
- BOOL rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
- ~CBotCallMethode();
-
- CBotTypResult
- CompileCall(const char* name, CBotVar* pThis,
- CBotVar** ppVars, CBotCStack* pStack,
- long& nIdent);
-
- int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pFunc);
-
- CBotString GivName();
- CBotCallMethode* Next();
- void AddNext(CBotCallMethode* p);
-
-};
-
-// une liste de paramètres
-
-class CBotDefParam
-{
-private:
- CBotToken m_token; // nom du paramètre
- CBotString m_typename; // nom du type
- CBotTypResult m_type; // type de paramètre
- CBotDefParam* m_next; // paramètre suivant
- long m_nIdent;
-
-public:
- CBotDefParam();
- ~CBotDefParam();
- static
- CBotDefParam* Compile(CBotToken* &p, CBotCStack* pStack);
- BOOL Execute(CBotVar** ppVars, CBotStack* &pj);
- void RestoreState(CBotStack* &pj, BOOL bMain);
-
- void AddNext(CBotDefParam* p);
- int GivType();
- CBotTypResult GivTypResult();
- CBotDefParam* GivNext();
-
- CBotString GivParamString();
-};
-
-
-// une déclaration de fonction
-
-class CBotFunction : CBotInstr
-{
-private:
- // gestion d'une liste (static) de fonctions publiques
- static
- CBotFunction* m_listPublic;
- CBotFunction* m_nextpublic;
- CBotFunction* m_prevpublic;
- friend class CBotCStack;
-// long m_nThisIdent;
- long m_nFuncIdent;
- BOOL m_bSynchro; // méthode synchronisée ?
-
-private:
- CBotDefParam* m_Param; // liste des paramètres
- CBotInstr* m_Block; // le bloc d'instructions
- CBotFunction* m_next;
- CBotToken m_retToken; // si retourne un CBotTypClass
- CBotTypResult m_retTyp; // type complet du résultat
-
- BOOL m_bPublic; // fonction publique
- BOOL m_bExtern; // fonction extern
- CBotString m_MasterClass; // nom de la classe qu'on dérive
- CBotProgram* m_pProg;
- friend class CBotProgram;
- friend class CBotClass;
-
- CBotToken m_extern; // pour la position du mot "extern"
- CBotToken m_openpar;
- CBotToken m_closepar;
- CBotToken m_openblk;
- CBotToken m_closeblk;
-public:
- CBotFunction::CBotFunction();
- CBotFunction::~CBotFunction();
- static
- CBotFunction* Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* pFunc, BOOL bLocal = TRUE);
- static
- CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass);
- BOOL Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
- void RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
-
- void AddNext(CBotFunction* p);
- CBotTypResult CompileCall(const char* name, CBotVar** ppVars, long& nIdent);
- CBotFunction* FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, BOOL bPublic = TRUE);
-
- int DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
- void RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack);
- int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
- void RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
- BOOL CheckParam(CBotDefParam* pParam);
-
- static
- void AddPublic(CBotFunction* pfunc);
-
- CBotString GivName();
- CBotString GivParams();
- BOOL IsPublic();
- BOOL IsExtern();
- CBotFunction* Next();
-
- BOOL GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop);
-};
-
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+////////////////////////////////////////////////////////////////////
+/**
+ * \file CBot.h
+ * \brief Interpreter of the language CBot for COLOBOT game
+ */
+
+#pragma once
+
+#include "resource.h"
+#include "CBotDll.h" // public definitions
+#include "CBotToken.h" // token management
+
+#define STACKRUN true /// \def return execution directly on a suspended routine
+#define STACKMEM true /// \def preserve memory for the execution stack
+#define MAXSTACK 990 /// \def stack size reserved
+
+#define EOX (CBotStack*)-1 /// \def tag special condition
+
+
+// fix for MSVC instruction __asm int 3 (setting a trap)
+#if defined(__MINGW32__) || defined(__GNUC__)
+#define ASM_TRAP() asm("int $3");
+#else
+#define ASM_TRAP() __asm int 3;
+#endif
+
+/////////////////////////////////////////////////////////////////////
+// forward declaration
+
+class CBotCompExpr; // an expression like
+ // () <= ()
+class CBotAddExpr; // an expression like
+ // () + ()
+class CBotParExpr; // basic type or instruction in parenthesis
+ // Toto.truc
+ // 12.5
+ // "string"
+ // ( expression )
+class CBotExprVar; // a variable name as
+ // Toto
+ // chose.truc.machin
+class CBotWhile; // while (...) {...};
+class CBotIf; // if (...) {...} else {...}
+class CBotDefParam; // paramerer list of a function
+class CBotRepeat; // repeat (nb) {...}
+
+
+
+////////////////////////////////////////////////////////////////////////
+// Management of the execution stack
+////////////////////////////////////////////////////////////////////////
+
+// actually, externally, the only thing it can do
+// is to create an instance of a stack
+// to use for routine CBotProgram :: Execute (CBotStack)
+
+
+/**\class CBotStack
+ * \brief Management of the execution stack.
+ * \brief Actually the only thing it can do is to create an instance of a stack
+ * \brief to use for routine CBotProgram :: Execute(CBotStack)*/
+class CBotStack
+{
+public:
+#if STACKMEM
+ /**
+ * \brief FirstStack Allocate first stack
+ * \return pointer to created stack
+ */
+ static CBotStack * FirstStack();
+
+ /** \brief Delete Remove current stack */
+ void Delete();
+#endif
+
+ /**
+ * \brief CBotStack Constructor of the stack
+ * \param ppapa Not used.
+ */
+ CBotStack(CBotStack* ppapa);
+
+
+ /** \brief ~CBotStack Destructor */
+ ~CBotStack();
+
+ /**
+ * \brief StackOver Check if end of stack is reached
+ * \return true if end of stack
+ */
+ bool StackOver();
+
+ /**
+ * \brief GivError Get error number of the stack
+ * \param [out] start beginning of the stack
+ * \param [out] end end of stack
+ * \return error number
+ */
+ int GivError(int& start, int& end);
+
+ /**
+ * \brief GivError Get error number
+ * \return eror number
+ */
+ int GivError();// rend le numéro d'erreur retourné
+
+ /**
+ * \brief Reset Reset error at and set user
+ * \param [in] pUser User of stack
+ */
+ void Reset(void* pUser);
+
+ /**
+ * \brief SetType Determines the type.
+ * \param type Type of instruction on the stack.
+ */
+ void SetType(CBotTypResult& type);
+
+ /**
+ * \brief GivType Get the type of value on the stack.
+ * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic).
+ * \return Type number.
+ */
+ int GivType(int mode = 0);
+
+ /**
+ * \brief Gives the type of complete value on the stack.
+ * \param [in] mode Used when getting class type (1 gives pointer, 2 gives intrinsic).
+ * \return Type of an element.
+ */
+ CBotTypResult GivTypResult(int mode = 0);
+
+ /**
+ * \brief Adds a local variable.
+ * \param [in] p Variable to be added.
+ */
+ void AddVar(CBotVar* p);
+
+ /**
+ * \brief Fetch a variable by its token.
+ * \brief This may be a composite variable
+ * \param [in] pToken Token upon which search is performed
+ * \param [in] bUpdate Not used. Probably need to be removed
+ * \param [in] bModif Not used. Probably need to be removed
+ * \return Found variable
+ */
+ CBotVar* FindVar(CBotToken* &pToken, bool bUpdate = false,
+ bool bModif = false);
+
+ /**
+ * \brief Fetch a variable by its token.
+ * \brief This may be a composite variable
+ * \param [in] pToken Token upon which search is performed
+ * \param [in] bUpdate Not used. Probably need to be removed
+ * \param [in] bModif Not used. Probably need to be removed
+ * \return Found variable
+ */
+ CBotVar* FindVar(CBotToken& Token, bool bUpdate = false,
+ bool bModif = false);
+
+ /**
+ * \brief Fetch variable by its name
+ * \param [in] name Name of variable to find
+ * \return Found variable
+ */
+ CBotVar* FindVar(const char* name);
+
+ /**
+ * \brief Fetch a variable on the stack according to its identification number
+ * \brief This is faster than comparing names
+ * \param [in] ident Identifier of a variable
+ * \param [in] bUpdate Not used. Probably need to be removed
+ * \param [in] bModif Not used. Probably need to be removed
+ * \return Found variable
+ */
+ CBotVar* FindVar(long ident, bool bUpdate = false,
+ bool bModif = false);
+
+ /**
+ * \brief Find variable by its token and returns a copy of it.
+ * \param Token Token upon which search is performed
+ * \param bUpdate Not used.
+ * \return Found variable, NULL if not found
+ */
+ CBotVar* CopyVar(CBotToken& Token, bool bUpdate = false);
+
+
+ CBotStack* AddStack(CBotInstr* instr = NULL, bool bBlock = false); // extends the stack
+ CBotStack* AddStackEOX(CBotCall* instr = NULL, bool bBlock = false); // extends the stack
+ CBotStack* RestoreStack(CBotInstr* instr = NULL);
+ CBotStack* RestoreStackEOX(CBotCall* instr = NULL);
+
+ CBotStack* AddStack2(bool bBlock = false); // extends the stack
+ bool Return(CBotStack* pFils); // transmits the result over
+ bool ReturnKeep(CBotStack* pFils); // transmits the result without reducing the stack
+ bool BreakReturn(CBotStack* pfils, const char* name = NULL);
+ // in case of eventual break
+ bool IfContinue(int state, const char* name);
+ // or "continue"
+
+ bool IsOk();
+
+ bool SetState(int n, int lim = -10); // select a state
+ int GivState(); // in what state am I?
+ bool IncState(int lim = -10); // passes to the next state
+ bool IfStep(); // do step by step
+ bool Execute();
+
+ void SetVar( CBotVar* var );
+ void SetCopyVar( CBotVar* var );
+ CBotVar* GivVar();
+ CBotVar* GivCopyVar();
+ CBotVar* GivPtVar();
+ bool GivRetVar(bool bRet);
+ long GivVal();
+
+ void SetStartError(int pos);
+ void SetError(int n, CBotToken* token = NULL);
+ void SetPosError(CBotToken* token);
+ void ResetError(int n, int start, int end);
+ void SetBreak(int val, const char* name);
+
+ void SetBotCall(CBotProgram* p);
+ CBotProgram* GivBotCall(bool bFirst = false);
+ void* GivPUser();
+ bool GivBlock();
+
+
+ bool ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype);
+ void RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar);
+
+ bool SaveState(FILE* pf);
+ bool RestoreState(FILE* pf, CBotStack* &pStack);
+
+ static
+ void SetTimer(int n);
+
+ void GetRunPos(const char* &FunctionName, int &start, int &end);
+ CBotVar* GivStackVars(const char* &FunctionName, int level);
+
+ int m_temp;
+
+private:
+ CBotStack* m_next;
+ CBotStack* m_next2;
+ CBotStack* m_prev;
+ friend class CBotInstArray;
+
+#ifdef _DEBUG
+ int m_index;
+#endif
+ int m_state;
+ int m_step;
+ static int m_error;
+ static int m_start;
+ static int m_end;
+ static
+ CBotVar* m_retvar; // result of a return
+
+ CBotVar* m_var; // result of the operations
+ CBotVar* m_listVar; // variables declared at this level
+
+ bool m_bBlock; // is part of a block (variables are local to this block)
+ bool m_bOver; // stack limits?
+// bool m_bDontDelete; // special, not to destroy the variable during delete
+ CBotProgram* m_prog; // user-defined functions
+
+ static
+ int m_initimer;
+ static
+ int m_timer;
+ static
+ CBotString m_labelBreak;
+ static
+ void* m_pUser;
+
+ CBotInstr* m_instr; // the corresponding instruction
+ bool m_bFunc; // an input of a function?
+ CBotCall* m_call; // recovery point in a extern call
+ friend class CBotTry;
+};
+
+// inline routinees must be declared in file.h
+
+inline bool CBotStack::IsOk()
+{
+ return (m_error == 0);
+}
+
+inline int CBotStack::GivState()
+{
+ return m_state;
+}
+
+inline int CBotStack::GivError()
+{
+ return m_error;
+}
+
+////////////////////////////////////////////////////////////////////////
+// Management of the stack of compilation
+////////////////////////////////////////////////////////////////////////
+
+
+class CBotCStack
+{
+private:
+ CBotCStack* m_next;
+ CBotCStack* m_prev;
+
+ static int m_error;
+ static int m_end;
+ int m_start;
+
+ CBotVar* m_var; // result of the operations
+
+ bool m_bBlock; // is part of a block (variables are local to this block)
+ CBotVar* m_listVar;
+
+ static
+ CBotProgram* m_prog; // list of compiled functions
+ static
+ CBotTypResult m_retTyp;
+// static
+// CBotToken* m_retClass;
+
+public:
+ CBotCStack(CBotCStack* ppapa);
+ ~CBotCStack();
+
+ bool IsOk();
+ int GivError();
+ int GivError(int& start, int& end);
+ // gives error number
+
+ void SetType(CBotTypResult& type);// determines the type
+ CBotTypResult GivTypResult(int mode = 0); // gives the type of value on the stack
+ int GivType(int mode = 0); // gives the type of value on the stack
+ CBotClass* GivClass(); // gives the class of the value on the stack
+
+ void AddVar(CBotVar* p); // adds a local variable
+ CBotVar* FindVar(CBotToken* &p); // finds a variable
+ CBotVar* FindVar(CBotToken& Token);
+ bool CheckVarLocal(CBotToken* &pToken);
+ CBotVar* CopyVar(CBotToken& Token); // finds and makes a copy
+
+ CBotCStack* TokenStack(CBotToken* pToken = NULL, bool bBlock = false);
+ CBotInstr* Return(CBotInstr* p, CBotCStack* pParent); // transmits the result upper
+ CBotFunction* ReturnFunc(CBotFunction* p, CBotCStack* pParent); // transmits the result upper
+
+ void SetVar( CBotVar* var );
+ void SetCopyVar( CBotVar* var );
+ CBotVar* GivVar();
+
+ void SetStartError(int pos);
+ void SetError(int n, int pos);
+ void SetError(int n, CBotToken* p);
+ void ResetError(int n, int start, int end);
+
+ void SetRetType(CBotTypResult& type);
+ CBotTypResult GivRetType();
+
+// void SetBotCall(CBotFunction* &pFunc);
+ void SetBotCall(CBotProgram* p);
+ CBotProgram* GivBotCall();
+ CBotTypResult CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent);
+ bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
+
+ bool NextToken(CBotToken* &p);
+};
+
+
+extern bool SaveVar(FILE* pf, CBotVar* pVar);
+
+
+/////////////////////////////////////////////////////////////////////
+// class defining an instruction
+class CBotInstr
+{
+private:
+ static
+ CBotStringArray
+ m_labelLvl;
+protected:
+ CBotToken m_token; // keeps the token
+ CBotString name; // debug
+ CBotInstr* m_next; // linked command
+ CBotInstr* m_next2b; // second list definition chain
+ CBotInstr* m_next3; // third list for indices and fields
+ CBotInstr* m_next3b; // necessary for reporting tables
+/*
+ for example, the following program
+ int x[]; x[1] = 4;
+ int y[x[1]][10], z;
+ is generated
+ CBotInstrArray
+ m_next3b-> CBotEmpty
+ m_next->
+ CBotExpression ....
+ m_next->
+ CBotInstrArray
+ m_next3b-> CBotExpression ('x') ( m_next3-> CBotIndexExpr ('1') )
+ m_next3b-> CBotExpression ('10')
+ m_next2-> 'z'
+ m_next->...
+
+*/
+
+ static
+ int m_LoopLvl;
+ friend class CBotClassInst;
+ friend class CBotInt;
+ friend class CBotListArray;
+
+public:
+ CBotInstr();
+ virtual
+ ~CBotInstr();
+
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ static
+ CBotInstr* CompileArray(CBotToken* &p, CBotCStack* pStack, CBotTypResult type, bool first = true);
+
+ virtual
+ bool Execute(CBotStack* &pj);
+ virtual
+ bool Execute(CBotStack* &pj, CBotVar* pVar);
+ virtual
+ void RestoreState(CBotStack* &pj, bool bMain);
+
+ virtual
+ bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
+ virtual
+ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
+ virtual
+ void RestoreStateVar(CBotStack* &pile, bool bMain);
+
+ virtual
+ bool CompCase(CBotStack* &pj, int val);
+
+ void SetToken(CBotToken* p);
+ int GivTokenType();
+ CBotToken* GivToken();
+
+ void AddNext(CBotInstr* n);
+ CBotInstr* GivNext();
+ void AddNext3(CBotInstr* n);
+ CBotInstr* GivNext3();
+ void AddNext3b(CBotInstr* n);
+ CBotInstr* GivNext3b();
+
+ static
+ void IncLvl(CBotString& label);
+ static
+ void IncLvl();
+ static
+ void DecLvl();
+ static
+ bool ChkLvl(const CBotString& label, int type);
+
+ bool IsOfClass(CBotString name);
+};
+
+class CBotWhile : public CBotInstr
+{
+private:
+ CBotInstr* m_Condition; // condition
+ CBotInstr* m_Block; // instructions
+ CBotString m_label; // a label if there is
+
+public:
+ CBotWhile();
+ ~CBotWhile();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotRepeat : public CBotInstr
+{
+private:
+ /// Number of iterations
+ CBotInstr* m_NbIter;
+
+ /// Instructions
+ CBotInstr* m_Block;
+
+ /// Label
+ CBotString m_label; // a label if there is
+
+public:
+ CBotRepeat();
+ ~CBotRepeat();
+
+ /// Static method used for compilation
+ static CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+
+ /// Execute
+ bool Execute(CBotStack* &pj);
+
+ /// Restore state
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotDo : public CBotInstr
+{
+private:
+ CBotInstr* m_Block; // instruction
+ CBotInstr* m_Condition; // conditions
+ CBotString m_label; // a label if there is
+
+public:
+ CBotDo();
+ ~CBotDo();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotFor : public CBotInstr
+{
+private:
+ CBotInstr* m_Init; // initial intruction
+ CBotInstr* m_Test; // test condition
+ CBotInstr* m_Incr; // instruction for increment
+ CBotInstr* m_Block; // instructions
+ CBotString m_label; // a label if there is
+
+public:
+ CBotFor();
+ ~CBotFor();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotBreak : public CBotInstr
+{
+private:
+ CBotString m_label; // a label if there is
+
+public:
+ CBotBreak();
+ ~CBotBreak();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotReturn : public CBotInstr
+{
+private:
+ CBotInstr* m_Instr; // paramter of return
+
+public:
+ CBotReturn();
+ ~CBotReturn();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotSwitch : public CBotInstr
+{
+private:
+ CBotInstr* m_Value; // value to seek
+ CBotInstr* m_Block; // instructions
+
+public:
+ CBotSwitch();
+ ~CBotSwitch();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotCase : public CBotInstr
+{
+private:
+ CBotInstr* m_Value; // value to compare
+
+public:
+ CBotCase();
+ ~CBotCase();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+ bool CompCase(CBotStack* &pj, int val);
+};
+
+class CBotCatch : public CBotInstr
+{
+private:
+ CBotInstr* m_Block; // instructions
+ CBotInstr* m_Cond; //condition
+ CBotCatch* m_next; //following catch
+ friend class CBotTry;
+
+public:
+ CBotCatch();
+ ~CBotCatch();
+ static
+ CBotCatch* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool TestCatch(CBotStack* &pj, int val);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+ void RestoreCondState(CBotStack* &pj, bool bMain);
+};
+
+class CBotTry : public CBotInstr
+{
+private:
+ CBotInstr* m_Block; // instructions
+ CBotCatch* m_ListCatch; // catches
+ CBotInstr* m_FinalInst; // final instruction
+
+public:
+ CBotTry();
+ ~CBotTry();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotThrow : public CBotInstr
+{
+private:
+ CBotInstr* m_Value; // the value to send
+
+public:
+ CBotThrow();
+ ~CBotThrow();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotStartDebugDD : public CBotInstr
+{
+private:
+
+public:
+ CBotStartDebugDD();
+ ~CBotStartDebugDD();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+};
+
+
+class CBotIf : public CBotInstr
+{
+private:
+ CBotInstr* m_Condition; // condition
+ CBotInstr* m_Block; // instructions
+ CBotInstr* m_BlockElse; // instructions
+
+public:
+ CBotIf();
+ ~CBotIf();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+// definition of an integer
+
+class CBotInt : public CBotInstr
+{
+private:
+ CBotInstr* m_var; // the variable to initialize
+ CBotInstr* m_expr; // a value to put, if there is
+/// CBotInstr* m_next; // several definitions chained
+
+public:
+ CBotInt();
+ ~CBotInt();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip = false);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// definition of an array
+
+class CBotInstArray : public CBotInstr
+{
+private:
+ CBotInstr* m_var; // the variables to initialize
+ CBotInstr* m_listass; // list of assignments for array
+ CBotTypResult
+ m_typevar; // type of elements
+// CBotString m_ClassName;
+
+public:
+ CBotInstArray();
+ ~CBotInstArray();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+// definition of a assignment list for a table
+// int [ ] a [ ] = ( ( 1, 2, 3 ) , ( 3, 2, 1 ) ) ;
+
+class CBotListArray : public CBotInstr
+{
+private:
+ CBotInstr* m_expr; // an expression for an element
+ // others are linked with CBotInstr :: m_next3;
+public:
+ CBotListArray();
+ ~CBotListArray();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotTypResult type);
+ bool Execute(CBotStack* &pj, CBotVar* pVar);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotEmpty : public CBotInstr
+{
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// defininition of a boolean
+
+class CBotBoolean : public CBotInstr
+{
+private:
+ CBotInstr* m_var; // variable to initialise
+ CBotInstr* m_expr; // a value to put, if there is
+
+public:
+ CBotBoolean();
+ ~CBotBoolean();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+// definition of a real number
+
+class CBotFloat : public CBotInstr
+{
+private:
+ CBotInstr* m_var; // variable to initialise
+ CBotInstr* m_expr; // a value to put, if there is
+
+public:
+ CBotFloat();
+ ~CBotFloat();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// definition of an element string
+
+class CBotIString : public CBotInstr
+{
+private:
+ CBotInstr* m_var; // variable to initialise
+ CBotInstr* m_expr; // a value to put, if there is
+
+public:
+ CBotIString();
+ ~CBotIString();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool cont = false, bool noskip=false);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// definition of an element of any class
+
+class CBotClassInst : public CBotInstr
+{
+private:
+ CBotInstr* m_var; // variable to initialise
+ CBotClass* m_pClass; // reference to the class
+ CBotInstr* m_Parameters; // parameters to be evaluated for the contructor
+ CBotInstr* m_expr; // a value to put, if there is
+ bool m_hasParams; // has it parameters?
+ long m_nMethodeIdent;
+
+public:
+ CBotClassInst();
+ ~CBotClassInst();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass = NULL);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotCondition : public CBotInstr
+{
+private:
+
+public:
+
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+};
+
+
+// left operand
+// accept the expressions that be to the left of assignment
+
+class CBotLeftExpr : public CBotInstr
+{
+private:
+ long m_nIdent;
+
+public:
+ CBotLeftExpr();
+ ~CBotLeftExpr();
+ static
+ CBotLeftExpr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pStack, CBotStack* array);
+
+ bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
+ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
+ void RestoreStateVar(CBotStack* &pile, bool bMain);
+};
+
+
+// management of the fields of an instance
+
+class CBotFieldExpr : public CBotInstr
+{
+private:
+ friend class CBotExpression;
+ int m_nIdent;
+
+public:
+ CBotFieldExpr();
+ ~CBotFieldExpr();
+ void SetUniqNum(int num);
+// static
+// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
+ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
+ void RestoreStateVar(CBotStack* &pj, bool bMain);
+};
+
+// management of indices of the tables
+
+class CBotIndexExpr : public CBotInstr
+{
+private:
+ CBotInstr* m_expr; // expression for calculating the index
+ friend class CBotLeftExpr;
+ friend class CBotExprVar;
+
+public:
+ CBotIndexExpr();
+ ~CBotIndexExpr();
+// static
+// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool ExecuteVar(CBotVar* &pVar, CBotCStack* &pile);
+ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep, bool bExtend);
+ void RestoreStateVar(CBotStack* &pj, bool bMain);
+};
+
+// expressions like
+// x = a;
+// x * y + 3;
+
+class CBotExpression : public CBotInstr
+{
+private:
+ CBotLeftExpr* m_leftop; // left operand
+ CBotInstr* m_rightop; // right operant
+
+public:
+ CBotExpression();
+ ~CBotExpression();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pStack);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotListExpression : public CBotInstr
+{
+private:
+ CBotInstr* m_Expr; // the first expression to be evaluated
+
+public:
+ CBotListExpression();
+ ~CBotListExpression();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pStack);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotLogicExpr : public CBotInstr
+{
+private:
+ CBotInstr* m_condition; // test to evaluate
+ CBotInstr* m_op1; // left element
+ CBotInstr* m_op2; // right element
+ friend class CBotTwoOpExpr;
+
+public:
+ CBotLogicExpr();
+ ~CBotLogicExpr();
+// static
+// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pStack);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+
+class CBotBoolExpr : public CBotInstr
+{
+private:
+
+public:
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+};
+
+
+
+// possibly an expression in parentheses ( ... )
+// there is never an instance of this class
+// being the object returned inside the parenthesis
+class CBotParExpr : public CBotInstr
+{
+private:
+
+public:
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+};
+
+// unary expression
+class CBotExprUnaire : public CBotInstr
+{
+private:
+ CBotInstr* m_Expr; // expression to be evaluated
+public:
+ CBotExprUnaire();
+ ~CBotExprUnaire();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pStack);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// all operations with two operands
+
+class CBotTwoOpExpr : public CBotInstr
+{
+private:
+ CBotInstr* m_leftop; // left element
+ CBotInstr* m_rightop; // right element
+public:
+ CBotTwoOpExpr();
+ ~CBotTwoOpExpr();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations = NULL);
+ bool Execute(CBotStack* &pStack);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+
+
+// an instruction block { .... }
+class CBotBlock : public CBotInstr
+{
+private:
+
+public:
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true);
+ static
+ CBotInstr* CompileBlkOrInst(CBotToken* &p, CBotCStack* pStack, bool bLocal = false);
+};
+
+
+// the content of a block of instructions ... ; ... ; ... ; ... ;
+class CBotListInstr : public CBotInstr
+{
+private:
+ CBotInstr* m_Instr; // instructions to do
+
+public:
+ CBotListInstr();
+ ~CBotListInstr();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, bool bLocal = true);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotInstrCall : public CBotInstr
+{
+private:
+ CBotInstr* m_Parameters; // the parameters to be evaluated
+// int m_typeRes; // type of the result
+// CBotString m_RetClassName; // class of the result
+ CBotTypResult
+ m_typRes; // complete type of the result
+ long m_nFuncIdent; // id of a function
+
+public:
+ CBotInstrCall();
+ ~CBotInstrCall();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// a call of method
+
+class CBotInstrMethode : public CBotInstr
+{
+private:
+ CBotInstr* m_Parameters; // the parameters to be evaluated
+// int m_typeRes; // type of the result
+// CBotString m_RetClassName; // class of the result
+ CBotTypResult
+ m_typRes; // complete type of the result
+
+ CBotString m_NomMethod; // name of the method
+ long m_MethodeIdent; // identifier of the method
+// long m_nThisIdent; // identifier for "this"
+ CBotString m_ClassName; // name of the class
+
+public:
+ CBotInstrMethode();
+ ~CBotInstrMethode();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, CBotVar* pVar);
+ bool Execute(CBotStack* &pj);
+ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep, bool bExtend);
+ void RestoreStateVar(CBotStack* &pj, bool bMain);
+};
+
+// expression for the variable name
+
+class CBotExprVar : public CBotInstr
+{
+private:
+ long m_nIdent;
+ friend class CBotPostIncExpr;
+ friend class CBotPreIncExpr;
+
+public:
+ CBotExprVar();
+ ~CBotExprVar();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack, int privat=PR_PROTECT);
+ static
+ CBotInstr* CompileMethode(CBotToken* &p, CBotCStack* pStack);
+
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+ bool ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, bool bStep);
+ bool Execute2Var(CBotVar* &pVar, CBotStack* &pj, CBotToken* prevToken, bool bStep);
+ void RestoreStateVar(CBotStack* &pj, bool bMain);
+};
+
+class CBotPostIncExpr : public CBotInstr
+{
+private:
+ CBotInstr* m_Instr;
+ friend class CBotParExpr;
+
+public:
+ CBotPostIncExpr();
+ ~CBotPostIncExpr();
+// static
+// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotPreIncExpr : public CBotInstr
+{
+private:
+ CBotInstr* m_Instr;
+ friend class CBotParExpr;
+
+public:
+ CBotPreIncExpr();
+ ~CBotPreIncExpr();
+// static
+// CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotLeftExprVar : public CBotInstr
+{
+private:
+public:
+ CBotTypResult
+ m_typevar; // type of variable declared
+ long m_nIdent; // unique identifier for that variable
+
+public:
+ CBotLeftExprVar();
+ ~CBotLeftExprVar();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotExprBool : public CBotInstr
+{
+private:
+
+public:
+ CBotExprBool();
+ ~CBotExprBool();
+
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+class CBotExprNull : public CBotInstr
+{
+private:
+
+public:
+ CBotExprNull();
+ ~CBotExprNull();
+
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotExprNan : public CBotInstr
+{
+private:
+
+public:
+ CBotExprNan();
+ ~CBotExprNan();
+
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+class CBotNew : public CBotInstr
+{
+private:
+ CBotInstr* m_Parameters; // the parameters to be evaluated
+ long m_nMethodeIdent;
+// long m_nThisIdent;
+ CBotToken m_vartoken;
+
+public:
+ CBotNew();
+ ~CBotNew();
+
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+// expression representing a number
+
+class CBotExprNum : public CBotInstr
+{
+private:
+ int m_numtype; // et the type of number
+ long m_valint; // value for an int
+ float m_valfloat; // value for a float
+
+public:
+ CBotExprNum();
+ ~CBotExprNum();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+
+// expression representing a string
+
+class CBotExprAlpha : public CBotInstr
+{
+private:
+
+public:
+ CBotExprAlpha();
+ ~CBotExprAlpha();
+ static
+ CBotInstr* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+};
+
+
+#define MAX(a,b) ((a>b) ? a : b)
+
+
+// class for the management of integer numbers (int)
+class CBotVarInt : public CBotVar
+{
+private:
+ int m_val; // the value
+ CBotString m_defnum; // the name if given by DefineNum
+ friend class CBotVar;
+
+public:
+ CBotVarInt( const CBotToken* name );
+// ~CBotVarInt();
+
+ void SetValInt(int val, const char* s = NULL);
+ void SetValFloat(float val);
+ int GivValInt();
+ float GivValFloat();
+ CBotString GivValString();
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+
+
+ void Add(CBotVar* left, CBotVar* right); // addition
+ void Sub(CBotVar* left, CBotVar* right); // substraction
+ void Mul(CBotVar* left, CBotVar* right); // multiplication
+ int Div(CBotVar* left, CBotVar* right); // division
+ int Modulo(CBotVar* left, CBotVar* right); // remainder of division
+ void Power(CBotVar* left, CBotVar* right); // power
+
+ bool Lo(CBotVar* left, CBotVar* right);
+ bool Hi(CBotVar* left, CBotVar* right);
+ bool Ls(CBotVar* left, CBotVar* right);
+ bool Hs(CBotVar* left, CBotVar* right);
+ bool Eq(CBotVar* left, CBotVar* right);
+ bool Ne(CBotVar* left, CBotVar* right);
+
+ void XOr(CBotVar* left, CBotVar* right);
+ void Or(CBotVar* left, CBotVar* right);
+ void And(CBotVar* left, CBotVar* right);
+
+ void SL(CBotVar* left, CBotVar* right);
+ void SR(CBotVar* left, CBotVar* right);
+ void ASR(CBotVar* left, CBotVar* right);
+
+ void Neg();
+ void Not();
+ void Inc();
+ void Dec();
+
+ bool Save0State(FILE* pf);
+ bool Save1State(FILE* pf);
+
+};
+
+// Class for managing real numbers (float)
+class CBotVarFloat : public CBotVar
+{
+private:
+ float m_val; // the value
+
+public:
+ CBotVarFloat( const CBotToken* name );
+// ~CBotVarFloat();
+
+ void SetValInt(int val, const char* s = NULL);
+ void SetValFloat(float val);
+ int GivValInt();
+ float GivValFloat();
+ CBotString GivValString();
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+
+
+ void Add(CBotVar* left, CBotVar* right); // addition
+ void Sub(CBotVar* left, CBotVar* right); // substraction
+ void Mul(CBotVar* left, CBotVar* right); // multiplication
+ int Div(CBotVar* left, CBotVar* right); // division
+ int Modulo(CBotVar* left, CBotVar* right); // remainder of division
+ void Power(CBotVar* left, CBotVar* right); // power
+
+ bool Lo(CBotVar* left, CBotVar* right);
+ bool Hi(CBotVar* left, CBotVar* right);
+ bool Ls(CBotVar* left, CBotVar* right);
+ bool Hs(CBotVar* left, CBotVar* right);
+ bool Eq(CBotVar* left, CBotVar* right);
+ bool Ne(CBotVar* left, CBotVar* right);
+
+ void Neg();
+ void Inc();
+ void Dec();
+
+ bool Save1State(FILE* pf);
+};
+
+
+// class for management of strings (String)
+class CBotVarString : public CBotVar
+{
+private:
+ CBotString m_val; // the value
+
+public:
+ CBotVarString( const CBotToken* name );
+// ~CBotVarString();
+
+ void SetValString(const char* p);
+ CBotString GivValString();
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+
+ void Add(CBotVar* left, CBotVar* right); // addition
+
+ bool Lo(CBotVar* left, CBotVar* right);
+ bool Hi(CBotVar* left, CBotVar* right);
+ bool Ls(CBotVar* left, CBotVar* right);
+ bool Hs(CBotVar* left, CBotVar* right);
+ bool Eq(CBotVar* left, CBotVar* right);
+ bool Ne(CBotVar* left, CBotVar* right);
+
+ bool Save1State(FILE* pf);
+};
+
+// class for the management of boolean
+class CBotVarBoolean : public CBotVar
+{
+private:
+ bool m_val; // the value
+
+public:
+ CBotVarBoolean( const CBotToken* name );
+// ~CBotVarBoolean();
+
+ void SetValInt(int val, const char* s = NULL);
+ void SetValFloat(float val);
+ int GivValInt();
+ float GivValFloat();
+ CBotString GivValString();
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+
+ void And(CBotVar* left, CBotVar* right);
+ void Or(CBotVar* left, CBotVar* right);
+ void XOr(CBotVar* left, CBotVar* right);
+ void Not();
+ bool Eq(CBotVar* left, CBotVar* right);
+ bool Ne(CBotVar* left, CBotVar* right);
+
+ bool Save1State(FILE* pf);
+};
+
+
+// class management class instances
+class CBotVarClass : public CBotVar
+{
+private:
+ static
+ CBotVarClass* m_ExClass; // list of existing instances at some point
+ CBotVarClass* m_ExNext; // for this general list
+ CBotVarClass* m_ExPrev; // for this general list
+
+private:
+ CBotClass* m_pClass; // the class definition
+ CBotVarClass* m_pParent; // the instance of a parent class
+ CBotVar* m_pVar; // contents
+ friend class CBotVar; // my daddy is a buddy WHAT? :D(\TODO mon papa est un copain )
+ friend class CBotVarPointer; // and also the pointer
+ int m_CptUse; // counter usage
+ long m_ItemIdent; // identifier (unique) of an instance
+ bool m_bConstructor; // set if a constructor has been called
+
+public:
+ CBotVarClass( const CBotToken* name, const CBotTypResult& type );
+// CBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
+ ~CBotVarClass();
+// void InitCBotVarClass( const CBotToken* name, CBotTypResult& type, int &nIdent );
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+ void SetClass(CBotClass* pClass); //, int &nIdent);
+ CBotClass* GivClass();
+ CBotVar* GivItem(const char* name); // return an element of a class according to its name (*)
+ CBotVar* GivItemRef(int nIdent);
+
+ CBotVar* GivItem(int n, bool bExtend);
+ CBotVar* GivItemList();
+
+ CBotString GivValString();
+
+ bool Save1State(FILE* pf);
+ void Maj(void* pUser, bool bContinue);
+
+ void IncrementUse(); // a reference to incrementation
+ void DecrementUse(); // a reference to decrementation
+
+ CBotVarClass*
+ GivPointer();
+ void SetItemList(CBotVar* pVar);
+
+ void SetIdent(long n);
+
+ static CBotVarClass* Find(long id);
+
+
+// CBotVar* GivMyThis();
+
+ bool Eq(CBotVar* left, CBotVar* right);
+ bool Ne(CBotVar* left, CBotVar* right);
+
+ void ConstructorSet();
+};
+
+
+// class for the management of pointers to a class instances
+class CBotVarPointer : public CBotVar
+{
+private:
+ CBotVarClass*
+ m_pVarClass; // contents
+ CBotClass* m_pClass; // class provided for this pointer
+ friend class CBotVar; // my daddy is a buddy
+
+public:
+ CBotVarPointer( const CBotToken* name, CBotTypResult& type );
+ ~CBotVarPointer();
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+ void SetClass(CBotClass* pClass);
+ CBotClass* GivClass();
+ CBotVar* GivItem(const char* name); // return an element of a class according to its name (*)
+ CBotVar* GivItemRef(int nIdent);
+ CBotVar* GivItemList();
+
+ CBotString GivValString();
+ void SetPointer(CBotVar* p);
+ CBotVarClass*
+ GivPointer();
+
+ void SetIdent(long n); // associates an identification number (unique)
+ long GivIdent(); // gives the identification number associated with
+ void ConstructorSet();
+
+ bool Save1State(FILE* pf);
+ void Maj(void* pUser, bool bContinue);
+
+ bool Eq(CBotVar* left, CBotVar* right);
+ bool Ne(CBotVar* left, CBotVar* right);
+};
+
+
+// classe pour les tableaux
+
+#define MAXARRAYSIZE 9999
+
+class CBotVarArray : public CBotVar
+{
+private:
+ CBotVarClass*
+ m_pInstance; // instance manager of table
+
+ friend class CBotVar; // my daddy is a buddy
+
+public:
+ CBotVarArray( const CBotToken* name, CBotTypResult& type );
+ ~CBotVarArray();
+
+ void SetPointer(CBotVar* p);
+ CBotVarClass*
+ GivPointer();
+
+ void Copy(CBotVar* pSrc, bool bName=true);
+ CBotVar* GivItem(int n, bool bGrow=false); // makes an element according to its numeric index
+ // enlarged the table if necessary if bExtend
+// CBotVar* GivItem(const char* name); // makes a element by literal index
+ CBotVar* GivItemList(); // gives the first item in the list
+
+ CBotString GivValString(); // gets the contents of the array into a string
+
+ bool Save1State(FILE* pf);
+};
+
+
+extern CBotInstr* CompileParams(CBotToken* &p, CBotCStack* pStack, CBotVar** ppVars);
+
+extern bool TypeCompatible( CBotTypResult& type1, CBotTypResult& type2, int op = 0 );
+extern bool TypesCompatibles( const CBotTypResult& type1, const CBotTypResult& type2 );
+
+extern bool WriteWord(FILE* pf, unsigned short w);
+extern bool ReadWord(FILE* pf, unsigned short& w);
+extern bool ReadLong(FILE* pf, long& w);
+extern bool WriteFloat(FILE* pf, float w);
+extern bool WriteLong(FILE* pf, long w);
+extern bool ReadFloat(FILE* pf, float& w);
+extern bool WriteString(FILE* pf, CBotString s);
+extern bool ReadString(FILE* pf, CBotString& s);
+extern bool WriteType(FILE* pf, CBotTypResult type);
+extern bool ReadType(FILE* pf, CBotTypResult& type);
+
+extern float GivNumFloat( const char* p );
+
+#if false
+extern void DEBUG( const char* text, int val, CBotStack* pile );
+#endif
+
+///////////////////////////////////////////
+// class for routine calls (external)
+
+class CBotCall
+{
+private:
+ static
+ CBotCall* m_ListCalls;
+ static
+ void* m_pUser;
+ long m_nFuncIdent;
+
+private:
+ CBotString m_name;
+ bool (*m_rExec) (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser) ;
+ CBotTypResult
+ (*m_rComp) (CBotVar* &pVar, void* pUser) ;
+ CBotCall* m_next;
+
+public:
+ CBotCall(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
+ ~CBotCall();
+
+ static
+ bool AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
+
+ static
+ CBotTypResult
+ CompileCall(CBotToken* &p, CBotVar** ppVars, CBotCStack* pStack, long& nIdent);
+ static
+ bool CheckCall(const char* name);
+
+// static
+// int DoCall(CBotToken* &p, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
+ static
+ int DoCall(long& nIdent, CBotToken* token, CBotVar** ppVars, CBotStack* pStack, CBotTypResult& rettype);
+#if STACKRUN
+ bool Run(CBotStack* pStack);
+ static
+ bool RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack);
+#endif
+
+ CBotString GivName();
+ CBotCall* Next();
+
+ static void SetPUser(void* pUser);
+ static void Free();
+};
+
+// class managing the methods declared by AddFunction on a class
+
+class CBotCallMethode
+{
+private:
+ CBotString m_name;
+ bool (*m_rExec) (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception);
+ CBotTypResult
+ (*m_rComp) (CBotVar* pThis, CBotVar* &pVar);
+ CBotCallMethode* m_next;
+ friend class CBotClass;
+ long m_nFuncIdent;
+
+public:
+ CBotCallMethode(const char* name,
+ bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
+ CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
+ ~CBotCallMethode();
+
+ CBotTypResult
+ CompileCall(const char* name, CBotVar* pThis,
+ CBotVar** ppVars, CBotCStack* pStack,
+ long& nIdent);
+
+ int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pFunc);
+
+ CBotString GivName();
+ CBotCallMethode* Next();
+ void AddNext(CBotCallMethode* p);
+
+};
+
+// a list of parameters
+
+class CBotDefParam
+{
+private:
+ CBotToken m_token; // name of the parameter
+ CBotString m_typename; // type name
+ CBotTypResult m_type; // type of paramteter
+ CBotDefParam* m_next; // next parameter
+ long m_nIdent;
+
+public:
+ CBotDefParam();
+ ~CBotDefParam();
+ static
+ CBotDefParam* Compile(CBotToken* &p, CBotCStack* pStack);
+ bool Execute(CBotVar** ppVars, CBotStack* &pj);
+ void RestoreState(CBotStack* &pj, bool bMain);
+
+ void AddNext(CBotDefParam* p);
+ int GivType();
+ CBotTypResult GivTypResult();
+ CBotDefParam* GivNext();
+
+ CBotString GivParamString();
+};
+
+
+// a function declaration
+
+class CBotFunction : CBotInstr
+{
+private:
+ // management of list of (static) public functions
+ static
+ CBotFunction* m_listPublic;
+ CBotFunction* m_nextpublic;
+ CBotFunction* m_prevpublic;
+ friend class CBotCStack;
+// long m_nThisIdent;
+ long m_nFuncIdent;
+ bool m_bSynchro; // synchronized method?
+
+private:
+ CBotDefParam* m_Param; // parameter list
+ CBotInstr* m_Block; // the instruction block
+ CBotFunction* m_next;
+ CBotToken m_retToken; // if returns CBotTypClass
+ CBotTypResult m_retTyp; // complete type of the result
+
+ bool m_bPublic; // public function
+ bool m_bExtern; // extern function
+ CBotString m_MasterClass; // name of the class we derive
+ CBotProgram* m_pProg;
+ friend class CBotProgram;
+ friend class CBotClass;
+
+ CBotToken m_extern; // for the position of the word "extern"
+ CBotToken m_openpar;
+ CBotToken m_closepar;
+ CBotToken m_openblk;
+ CBotToken m_closeblk;
+public:
+ CBotFunction();
+ ~CBotFunction();
+ static
+ CBotFunction* Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* pFunc, bool bLocal = true);
+ static
+ CBotFunction* Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass);
+ bool Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
+ void RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance = NULL);
+
+ void AddNext(CBotFunction* p);
+ CBotTypResult CompileCall(const char* name, CBotVar** ppVars, long& nIdent);
+ CBotFunction* FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic = true);
+
+ int DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken);
+ void RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack);
+ int DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass);
+ void RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass);
+ bool CheckParam(CBotDefParam* pParam);
+
+ static
+ void AddPublic(CBotFunction* pfunc);
+
+ CBotString GivName();
+ CBotString GivParams();
+ bool IsPublic();
+ bool IsExtern();
+ CBotFunction* Next();
+
+ bool GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop);
+};
+
+
diff --git a/src/CBot/CBot.rc b/src/CBot/CBot.rc
deleted file mode 100644
index d8b5b74..0000000
--- a/src/CBot/CBot.rc
+++ /dev/null
@@ -1,279 +0,0 @@
-//Microsoft Developer Studio generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// French (France) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
-#ifdef _WIN32
-LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE DISCARDABLE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_IF "if"
- ID_ELSE "else"
- ID_WHILE "while"
- ID_DO "do"
- ID_FOR "for"
- ID_BREAK "break"
- ID_CONTINUE "continue"
- ID_SWITCH "switch"
- ID_CASE "case"
- ID_DEFAULT "default"
- ID_TRY "try"
- ID_THROW "throw"
- ID_CATCH "catch"
- ID_FINALLY "finally"
- ID_TXT_AND "and"
- ID_TXT_OR "or"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_DEBUGDD "STARTDEBUGDD"
- ID_INT "int"
- ID_FLOAT "float"
- ID_BOOLEAN "boolean"
- ID_STRING "string"
- ID_VOID "void"
- ID_BOOL "bool"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_TXT_NOT "not"
- ID_RETURN "return"
- ID_CLASS "class"
- ID_EXTENDS "extends"
- ID_SYNCHO "synchronized"
- ID_NEW "new"
- ID_PUBLIC "public"
- ID_EXTERN "extern"
- ID_FINAL "final"
- ID_STATIC "static"
- ID_PROTECTED "protected"
- ID_PRIVATE "private"
- ID_REPEAT "repeat"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- TX_OPENPAR "Il manque une parenthèse ouvrante."
- TX_CLOSEPAR "Il manque une parenthèse fermante."
- TX_NOTBOOL "L'expression doit être un boolean."
- TX_UNDEFVAR "Variable non déclarée."
- TX_BADLEFT "Assignation impossible."
- TX_ENDOF "Terminateur point-virgule non trouvé."
- TX_OUTCASE "Instruction ""case"" hors d'un bloc ""switch""."
- TX_NOTERM "Instructions après la fin."
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- TX_CLOSEBLK "Il manque la fin du bloc."
- TX_ELSEWITHOUTIF "Instruction ""else"" sans ""if"" correspondant."
- TX_OPENBLK "Début d'un bloc attendu."
- TX_BADTYPE "Mauvais type de résultat pour l'assignation."
- TX_REDEFVAR "Redéfinition d'une variable."
- TX_BAD2TYPE "Les deux opérandes ne sont pas de types compatibles."
- TX_UNDEFCALL "Routine inconnue."
- TX_MISDOTS "Séparateur "" : "" attendu."
- TX_WHILE "Manque le mot ""while""."
- TX_BREAK "Instruction ""break"" en dehors d'une boucle."
- TX_LABEL "Un label ne peut se placer que devant un ""for"", un ""while"" ou un ""do""."
- TX_NOLABEL "Cette étiquette n'existe pas"
- TX_NOCASE "Manque une instruction ""case""."
- TX_BADNUM "Un nombre est attendu."
- TX_VOID "Paramètre void."
- TX_NOTYP "Déclaration de type attendu."
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- TX_DIVZERO "Division par zéro."
- TX_NOTINIT "Variable non initialisée."
- TX_BADTHROW "Valeur négative refusée pour ""throw""."
- TX_NORETVAL "La fonction n'a pas retourné de résultat"
- TX_NORUN "Pas de fonction en exécution"
- TX_NOCALL "Appel d'une fonction inexistante"
- TX_NOCLASS "Cette classe n'existe pas"
- TX_NULLPT "Pointeur nul."
- TX_OPNAN "Opération sur un ""nan"""
- TX_OUTARRAY "Accès hors du tableau"
- TX_STACKOVER "Dépassement de la pile"
- TX_DELETEDPT "Pointeur à un objet détruit"
- TX_FILEOPEN "Ouverture du fichier impossible"
- TX_NOTOPEN "Fichier pas ouvert"
- TX_ERRREAD "Erreur de lecture"
- TX_ERRWRITE "Erreur d'écriture"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- TX_NOVAR "Nom d'une variable attendu."
- TX_NOFONC "Nom de la fonction attendu."
- TX_OVERPARAM "Trop de paramètres."
- TX_REDEF "Cette fonction existe déjà."
- TX_LOWPARAM "Pas assez de paramètres."
- TX_BADPARAM "Aucune fonction de ce nom n'accepte ce(s) type(s) de paramètre(s)."
- TX_NUMPARAM "Aucune fonction de ce nom n'accepte ce nombre de paramètres."
- TX_NOITEM "Cet élément n'existe pas dans cette classe."
- TX_DOT "L'objet n'est pas une instance d'une classe."
- TX_NOCONST "Il n'y a pas de constructeur approprié."
- TX_REDEFCLASS "Cette classe existe déjà."
- TX_CLBRK """ ] "" attendu."
- TX_RESERVED "Ce mot est réservé."
- TX_BADNEW "Mauvais argument pour ""new""."
- TX_OPBRK """ [ "" attendu."
- TX_BADSTRING "Une chaîne de caractère est attendue."
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- TX_BADINDEX "Mauvais type d'index"
- TX_PRIVATE "Membre privé de la classe"
- TX_NOPUBLIC """public"" manque"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_OPENPAR "("
- ID_CLOSEPAR ")"
- ID_OPBLK "{"
- ID_CLBLK "}"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_SEP ";"
- ID_COMMA ","
- ID_DOTS ":"
- ID_DOT "."
- ID_OPBRK "["
- ID_CLBRK "]"
- ID_DBLDOTS "::"
- ID_LOGIC "?"
- ID_ADD "+"
- ID_SUB "-"
- ID_MUL "*"
- ID_DIV "/"
- ID_ASS "="
- ID_ASSADD "+="
- ID_ASSSUB "-="
- ID_ASSMUL "*="
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_TRUE "true"
- ID_FALSE "false"
- ID_NULL "null"
- ID_NAN "nan"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_ASSDIV "/="
- ID_ASSOR "|="
- ID_ASSAND "&="
- ID_ASSXOR "^="
- ID_ASSSL "<<="
- ID_ASSSR ">>>="
- ID_ASSASR ">>="
- ID_SL "<<"
- ID_SR ">>>"
- ID_ASR ">>"
- ID_INC "++"
- ID_DEC "--"
- ID_LO "<"
- ID_HI ">"
- ID_LS "<="
- ID_HS ">="
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_EQ "=="
- ID_NE "!="
- ID_AND "&"
- ID_XOR "^"
- ID_OR "|"
- ID_LOG_AND "&&"
- ID_LOG_OR "||"
- ID_LOG_NOT "!"
- ID_NOT "~"
- ID_MODULO "%"
- ID_POWER "**"
- ID_ASSMODULO "%="
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- TX_UNDEF "undefined"
- TX_NAN "not a number"
-END
-
-STRINGTABLE DISCARDABLE
-BEGIN
- ID_SUPER "super"
-END
-
-#endif // French (France) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
diff --git a/src/CBot/CBotAddExpr.cpp b/src/CBot/CBotAddExpr.cpp
index ad87880..231f008 100644
--- a/src/CBot/CBotAddExpr.cpp
+++ b/src/CBot/CBotAddExpr.cpp
@@ -1,142 +1,144 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////
-// expression du genre Opérande1 + Opérande2
-// Opérande1 - Opérande2
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotAddExpr::CBotAddExpr()
-{
- m_leftop =
- m_rightop = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotAddExpr"; // debug
-}
-
-CBotAddExpr::~CBotAddExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-
-// compile une instruction de type A + B
-
-CBotInstr* CBotAddExpr::Compile(CBotToken* &p, CBotStack* pStack)
-{
- CBotStack* pStk = pStack->TokenStack(); // un bout de pile svp
-
- // cherche des instructions qui peuvent convenir à gauche de l'opération + ou -
-
- CBotInstr* left = CBotMulExpr::Compile( p, pStk ); // expression A * B à gauche
- if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
-
- // est-ce qu'on a le token + ou - ensuite ?
-
- if ( p->GetType() == ID_ADD ||
- p->GetType() == ID_SUB) // plus ou moins
- {
- CBotAddExpr* inst = new CBotAddExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
- int type1, type2;
- type1 = pStack->GetType(); // de quel type le premier opérande ?
-
- p = p->Next(); // saute le token de l'opération
-
- // cherche des instructions qui peuvent convenir à droite
-
- if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression (...) à droite
- {
- // il y a un second opérande acceptable
-
- type2 = pStack->GetType(); // de quel type le résultat ?
-
- if ( type1 == type2 ) // les résultats sont-ils compatibles
- {
- // si ok, enregistre l'opérande dans l'objet
- inst->m_leftop = left;
- // et rend l'object à qui l'a demandé
- return pStack->Return(inst, pStk);
- }
- }
-
- // en cas d'erreur, libère les éléments
- delete left;
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile
- return pStack->Return(NULL, pStk);
- }
-
- // si on n'a pas affaire à une opération + ou -
- // rend à qui l'a demandé, l'opérande (de gauche) trouvé
- // à la place de l'objet "addition"
- return pStack->Return(left, pStk);
-}
-
-
-
-
-// fait l'opération d'addition ou de soustraction
-
-BOOL CBotAddExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pSk1 == EOX ) return TRUE;
-
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GetState() == 0 && // 1er état, évalue l'opérande de gauche
- !m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- // passe à l'étape suivante
- pStk1->SetState(1); // prêt pour la suite
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- // qui se trouve sur la pile, justement.
-
- CBotStack* pStk2 = pStk1->AddStack(); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-
- // 2e état, évalue l'opérande de droite
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
-
- int type1 = pStk1->GetType(); // de quels types les résultats ?
- int type2 = pStk2->GetType();
-
- // crée une variable temporaire pour y mettre le résultat
- CBotVar* result = new CBotVar( NULL, MAX(type1, type2));
-
- // fait l'opération selon la demande
- switch (GetTokenType())
- {
- case ID_ADD:
- result->Add(pStk1->GetVar(), pStk2->GetVar()); // additionne
- break;
- case ID_SUB:
- result->Sub(pStk1->GetVar(), pStk2->GetVar()); // soustrait
- break;
- }
- pStk2->SetVar(result); // met le résultat sur la pile
-
- pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk1); // transmet le résultat
-}
-
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+///////////////////////////////////////////////////
+// expressions of type Operand1 + Operand2
+// Operand1 - Operand2
+
+#include "CBot.h"
+
+// various constructors
+
+CBotAddExpr::CBotAddExpr()
+{
+ m_leftop =
+ m_rightop = NULL; // NULL to be able to delete without further
+ name = "CBotAddExpr"; // debug
+}
+
+CBotAddExpr::~CBotAddExpr()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+
+// compile une instruction de type A + B
+
+CBotInstr* CBotAddExpr::Compile(CBotToken* &p, CBotStack* pStack)
+{
+ CBotStack* pStk = pStack->TokenStack(); // one end of stack please
+
+ // looking statements that may be suitable to the left of the operation + or -
+
+ CBotInstr* left = CBotMulExpr::Compile( p, pStk ); // expression A * B left
+ if (left == NULL) return pStack->Return(NULL, pStk); // if error, transmit
+
+ // do we have the token + or - next?
+
+ if ( p->GetType() == ID_ADD ||
+ p->GetType() == ID_SUB) // more or less
+ {
+ CBotAddExpr* inst = new CBotAddExpr(); // element for operation
+ inst->SetToken(p); // stores the operation
+
+ int type1, type2;
+ type1 = pStack->GetType(); // what kind of the first operand?
+
+ p = p->Next(); // skip the token of the operation
+
+ // looking statements that may be suitable for right
+
+ if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression (...) rigth
+ {
+ // there is an acceptable second operand
+
+ type2 = pStack->GetType(); // what kind of results?
+
+ if ( type1 == type2 ) // are the results consistent ?
+ {
+ // ok so, saves the operand in the object
+ inst->m_leftop = left;
+ // and makes the object on demand
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ // in case of error, free the elements
+ delete left;
+ delete inst;
+ // and transmits the error that is on the stack
+ return pStack->Return(NULL, pStk);
+ }
+
+ // if we are not dealing with an operation + or -
+ // goes to that requested, the operand (left) found
+ // place the object "addition"
+ return pStack->Return(left, pStk);
+}
+
+
+
+
+// operation is addition or subtraction
+
+bool CBotAddExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack
+ // or is found in case of recovery
+// if ( pSk1 == EOX ) return TRUE;
+
+
+ // according to recovery, it may be in one of two states
+
+ if ( pStk1->GetState() == 0 && // first state, evaluates the left operand
+ !m_leftop->Execute(pStk1) ) return FALSE; // interrupted here?
+
+ // passes to the next step
+ pStk1->SetState(1); // ready for further
+
+ // requires a little more stack to not touch the result of the left
+ // which is on the stack, precisely.
+
+ CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
+ // or is found in case of recovery
+
+ // Second state, evaluates the right operand
+ if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrupted here?
+
+ int type1 = pStk1->GetType(); // what kind of results?
+ int type2 = pStk2->GetType();
+
+ // creates a temporary variable to put the result
+ CBotVar* result = new CBotVar( NULL, MAX(type1, type2));
+
+ // is the operation as requested
+ switch (GetTokenType())
+ {
+ case ID_ADD:
+ result->Add(pStk1->GetVar(), pStk2->GetVar()); // addition
+ break;
+ case ID_SUB:
+ result->Sub(pStk1->GetVar(), pStk2->GetVar()); // subtraction
+ break;
+ }
+ pStk2->SetVar(result); // puts the result on the stack
+
+ pStk1->Return(pStk2); // frees the stack
+ return pStack->Return(pStk1); // transmits the result
+}
+
+
diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp
index 7c097af..a524a8e 100644
--- a/src/CBot/CBotClass.cpp
+++ b/src/CBot/CBotClass.cpp
@@ -1,881 +1,882 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// Gestion des variables de type classe
-//
-
-#include "CBot.h"
-
-
-CBotClass* CBotClass::m_ExClass = NULL;
-
-CBotClass::CBotClass(const char* name, CBotClass* pPapa, BOOL bIntrinsic)
-{
- m_pParent = pPapa;
- m_name = name;
- m_pVar = NULL;
- m_next = NULL;
- m_pCalls = NULL;
- m_pMethod = NULL;
- m_rMaj = NULL;
- m_IsDef = TRUE;
- m_bIntrinsic= bIntrinsic;
- m_cptLock = 0;
- m_cptOne = 0;
- m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
-
- for ( int j= 0; j< 5 ; j++ )
- {
- m_ProgInLock[j] = NULL;
- }
-
-
- // se place tout seul dans la liste
- if (m_ExClass) m_ExClass->m_ExPrev = this;
- m_ExNext = m_ExClass;
- m_ExPrev = NULL;
- m_ExClass = this;
-
-}
-
-CBotClass::~CBotClass()
-{
- // retire la classe de la liste
- if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
- else m_ExClass = m_ExNext;
-
- if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
- m_ExPrev = NULL;
- m_ExNext = NULL;
-
- delete m_pVar;
- delete m_pCalls;
- delete m_pMethod;
-
- delete m_next; // libère toutes celle de ce niveau
-}
-
-
-void CBotClass::Free()
-{
- while ( m_ExClass != NULL )
- {
- delete m_ExClass;
- }
-}
-
-void CBotClass::Purge()
-{
- if ( this == NULL ) return;
-
- delete m_pVar;
- m_pVar = NULL;
- delete m_pCalls;
- m_pCalls = NULL;
- delete m_pMethod;
- m_pMethod = NULL;
- m_IsDef = FALSE;
-
- m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
-
- m_next->Purge();
- m_next = NULL; // n'appartient plus à cette chaîne
-}
-
-BOOL CBotClass::Lock(CBotProgram* p)
-{
- int i = m_cptLock++;
-
- if ( i == 0 )
- {
- m_cptOne = 1;
- m_ProgInLock[0] = p;
- return TRUE;
- }
- if ( p == m_ProgInLock[0] )
- {
- m_cptOne++;
- m_cptLock--; // a déjà été compté
- return TRUE;
- }
-
- for ( int j = 1 ; j <= i ; j++)
- {
- if ( p == m_ProgInLock[j] )
- {
- m_cptLock--;
- return FALSE; // déjà en attente
- }
- }
-
- if ( i < 5 ) // maxi 5 en attente
- {
- m_ProgInLock[i] = p; // se place dans la queue
- }
- else
- m_cptLock--;
-
- return FALSE;
-}
-
-void CBotClass::Unlock()
-{
- if ( --m_cptOne > 0 ) return ;
-
- int i = --m_cptLock;
- if ( i<0 )
- {
- m_cptLock = 0;
- return;
- }
-
- for ( int j= 0; j< i ; j++ )
- {
- m_ProgInLock[j] = m_ProgInLock[j+1];
- }
- m_ProgInLock[i] = 0;
-}
-
-void CBotClass::FreeLock(CBotProgram* p)
-{
- CBotClass* pClass = m_ExClass;
-
- while ( pClass != NULL )
- {
- if ( p == pClass->m_ProgInLock[0] )
- {
- pClass->m_cptLock -= pClass->m_cptOne;
- pClass->m_cptOne = 0;
- }
-
- for ( int j = 1; j < 5 ; j++ )
- if ( p == pClass->m_ProgInLock[j] )
- pClass->m_cptLock--;
-
- pClass = pClass->m_ExNext;
- }
-}
-
-
-
-BOOL CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate)
-{
- CBotToken token(name, CBotString());
- CBotClass* pClass = type.GivClass();
-
- CBotVar* pVar = CBotVar::Create( name, type );
-/// pVar->SetUniqNum(CBotVar::NextUniqNum());
- pVar->SetPrivate( mPrivate );
-
- if ( pClass != NULL )
- {
-// pVar->SetClass(pClass);
- if ( type.Eq(CBotTypClass) )
- {
- // ajoute une instruction new pour initialiser l'object
- pVar->m_InitExpr = new CBotNew() ;
- CBotToken nom( pClass->GivName() );
- pVar->m_InitExpr->SetToken(&nom);
- }
- }
- return AddItem( pVar );
-}
-
-
-BOOL CBotClass::AddItem(CBotVar* pVar)
-{
- pVar->SetUniqNum(++m_nbVar);
-
- if ( m_pVar == NULL ) m_pVar = pVar;
- else m_pVar->AddNext(pVar);
-
- return TRUE;
-}
-
-void CBotClass::AddNext(CBotClass* pClass)
-{
- CBotClass* p = this;
- while (p->m_next != NULL) p = p->m_next;
-
- p->m_next = pClass;
-}
-
-CBotString CBotClass::GivName()
-{
- return m_name;
-}
-
-CBotClass* CBotClass::GivParent()
-{
- if ( this == NULL ) return NULL;
- return m_pParent;
-}
-
-BOOL CBotClass::IsChildOf(CBotClass* pClass)
-{
- CBotClass* p = this;
- while ( p != NULL )
- {
- if ( p == pClass ) return TRUE;
- p = p->m_pParent;
- }
- return FALSE;
-}
-
-
-CBotVar* CBotClass::GivVar()
-{
- return m_pVar;
-}
-
-CBotVar* CBotClass::GivItem(const char* name)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->GivNext();
- }
- if ( m_pParent != NULL ) return m_pParent->GivItem(name);
- return NULL;
-}
-
-CBotVar* CBotClass::GivItemRef(int nIdent)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivUniqNum() == nIdent ) return p;
- p = p->GivNext();
- }
- if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
- return NULL;
-}
-
-BOOL CBotClass::IsIntrinsic()
-{
- return m_bIntrinsic;
-}
-
-CBotClass* CBotClass::Find(CBotToken* &pToken)
-{
- return Find(pToken->GivString());
-}
-
-CBotClass* CBotClass::Find(const char* name)
-{
- CBotClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->m_ExNext;
- }
-
- return NULL;
-}
-
-BOOL CBotClass::AddFunction(const char* name,
- BOOL rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
-{
- // mémorise les pointeurs aux deux fonctions
- CBotCallMethode* p = m_pCalls;
- CBotCallMethode* pp = NULL;
-
- while ( p != NULL )
- {
- if ( name == p->GivName() )
- {
- if ( pp == NULL ) m_pCalls = p->m_next;
- else pp->m_next = p->m_next;
- delete p;
- break;
- }
- pp = p;
- p = p->m_next;
- }
-
- p = new CBotCallMethode(name, rExec, rCompile);
-
- if (m_pCalls == NULL) m_pCalls = p;
- else m_pCalls->AddNext(p); // ajoute à la liste
-
- return TRUE;
-}
-
-BOOL CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) )
-{
- m_rMaj = rMaj;
- return TRUE;
-}
-
-// compile une méthode associée à une instance de classe
-// la méthode peut être déclarée par AddFunction ou par l'utilisateur
-
-CBotTypResult CBotClass::CompileMethode(const char* name,
- CBotVar* pThis, CBotVar** ppParams,
- CBotCStack* pStack, long& nIdent)
-{
- nIdent = 0; // oublie le précédent s'il y a lieu
-
- // recherche dans les méthodes déclarées par AddFunction
-
- CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent);
- if ( r.GivType() >= 0) return r;
-
- // recherche dans les méthodes déclarées par l'utilisateur
-
- r = m_pMethod->CompileCall(name, ppParams, nIdent);
- if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL )
- return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent);
- return r;
-}
-
-// exécute une méthode
-
-BOOL CBotClass::ExecuteMethode(long& nIdent, const char* name,
- CBotVar* pThis, CBotVar** ppParams,
- CBotVar* &pResult, CBotStack* &pStack,
- CBotToken* pToken)
-{
- int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
- if (ret>=0) return ret;
-
- ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this);
- return ret;
-}
-
-// rétabli la pile d'exécution
-
-void CBotClass::RestoreMethode(long& nIdent, const char* name, CBotVar* pThis,
- CBotVar** ppParams, CBotStack* &pStack)
-{
- m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this);
-}
-
-
-
-
-BOOL CBotClass::SaveStaticState(FILE* pf)
-{
- if (!WriteWord( pf, CBOTVERSION*2)) return FALSE;
-
- // sauve l'état des variables statiques dans les classes
- CBotClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if (!WriteWord( pf, 1)) return FALSE;
- // enregistre le nom de la classe
- if (!WriteString( pf, p->GivName() )) return FALSE;
-
- CBotVar* pv = p->GivVar();
- while( pv != NULL )
- {
- if ( pv->IsStatic() )
- {
- if (!WriteWord( pf, 1)) return FALSE;
- if (!WriteString( pf, pv->GivName() )) return FALSE;
-
- if ( !pv->Save0State(pf)) return FALSE; // entête commune
- if ( !pv->Save1State(pf) ) return FALSE; // sauve selon la classe fille
- if ( !WriteWord( pf, 0)) return FALSE;
- }
- pv = pv->GivNext();
- }
-
- if (!WriteWord( pf, 0)) return FALSE;
- p = p->m_ExNext;
- }
-
- if (!WriteWord( pf, 0)) return FALSE;
- return TRUE;
-}
-
-BOOL CBotClass::RestoreStaticState(FILE* pf)
-{
- CBotString ClassName, VarName;
- CBotClass* pClass;
- WORD w;
-
- if (!ReadWord( pf, w )) return FALSE;
- if ( w != CBOTVERSION*2 ) return FALSE;
-
- while (TRUE)
- {
- if (!ReadWord( pf, w )) return FALSE;
- if ( w == 0 ) return TRUE;
-
- if (!ReadString( pf, ClassName )) return FALSE;
- pClass = Find(ClassName);
-
- while (TRUE)
- {
- if (!ReadWord( pf, w )) return FALSE;
- if ( w == 0 ) break;
-
- CBotVar* pVar = NULL;
- CBotVar* pv = NULL;
-
- if (!ReadString( pf, VarName )) return FALSE;
- if ( pClass != NULL ) pVar = pClass->GivItem(VarName);
-
- if (!CBotVar::RestoreState(pf, pv)) return FALSE; // la variable temp
-
- if ( pVar != NULL ) pVar->Copy(pv);
- delete pv;
- }
- }
- return TRUE;
-}
-
-
-/////////////////////////////////////////////////////////////////////
-
-CBotClassInst::CBotClassInst()
-{
- m_next = NULL;
- m_var = NULL;
- m_Parameters = NULL;
- m_expr = NULL;
- m_hasParams = FALSE;
- m_nMethodeIdent = 0;
- name = "CBotClassInst";
-}
-
-CBotClassInst::~CBotClassInst()
-{
- delete m_var;
-// delete m_next; // fait par le destructeur de la classe de base ~CBotInstr()
-}
-
-// définition de pointeur(s) à un objet
-// du style
-// CPoint A, B ;
-
-CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
-{
- // cherche la classe correspondante
- if ( pClass == NULL )
- {
- pStack->SetStartError(p->GivStart());
- pClass = CBotClass::Find(p);
- if ( pClass == NULL )
- {
- // pas trouvé ? c'est bizare
- pStack->SetError(TX_NOCLASS, p);
- return NULL;
- }
- p = p->GivNext();
- }
-
- BOOL bIntrinsic = pClass->IsIntrinsic();
- CBotTypResult
- type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer,
- pClass );
- CBotClassInst* inst = (CBotClassInst*)CompileArray(p, pStack, type);
- if ( inst != NULL || !pStack->IsOk() ) return inst;
-
- CBotCStack* pStk = pStack->TokenStack();
-
- inst = new CBotClassInst();
-
- inst->SetToken(&pClass->GivName(), p->GivStart(), p->GivEnd());
- CBotToken* vartoken = p;
-
- if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
- {
- ((CBotLeftExprVar*)inst->m_var)->m_typevar = type;
- if (pStk->CheckVarLocal(vartoken)) // redéfinition de la variable
- {
- pStk->SetStartError(vartoken->GivStart());
- pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
- goto error;
- }
-
- if (IsOfType(p, ID_OPBRK)) // avec des indices ?
- {
- delete inst; // n'est pas de type CBotInt
- p = vartoken; // revient sur le nom de la variable
-
- // compile une déclaration de tableau
-
- inst = (CBotClassInst*)CBotInstArray::Compile( p, pStk, type );
-
- if (!pStk->IsOk() )
- {
- pStk->SetError(TX_CLBRK, p->GivStart());
- goto error;
- }
- goto suite; // pas d'assignation, variable déjà créée
- }
-
-
- CBotVar* var;
- var = CBotVar::Create(vartoken->GivString(), type); // crée l'instance
-// var->SetClass(pClass);
- var->SetUniqNum(
- ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
- // lui attribut un numéro unique
- pStack->AddVar(var); // la place sur la pile
-
- // regarde s'il y a des paramètres
- inst->m_hasParams = (p->GivType() == ID_OPENPAR);
-
- CBotVar* ppVars[1000];
- inst->m_Parameters = CompileParams(p, pStk, ppVars);
- if ( !pStk->IsOk() ) goto error;
-
- // s'il y a des paramètres, fait l'équivalent de l'instruction new
- // CPoint A ( 0, 0 ) est équivalent à
- // CPoint A = new CPoint( 0, 0 )
-
-// if ( NULL != inst->m_Parameters )
- if ( inst->m_hasParams )
- {
- // le constructeur existe-il ?
-// CBotString noname;
- CBotTypResult r = pClass->CompileMethode(pClass->GivName(), var, ppVars, pStk, inst->m_nMethodeIdent);
- delete pStk->TokenStack(); // libère le supplément de pile
- int typ = r.GivType();
-
- if (typ == TX_UNDEFCALL)
- {
- // si le constructeur n'existe pas
- if (inst->m_Parameters != NULL) // avec des paramètres
- {
- pStk->SetError(TX_NOCONST, vartoken);
- goto error;
- }
- typ = 0;
- }
-
- if (typ>20)
- {
- pStk->SetError(typ, vartoken->GivEnd());
- goto error;
- }
-
- }
-
- if (IsOfType(p, ID_ASS)) // avec une assignation ?
- {
- if (inst->m_hasParams)
- {
- pStk->SetError(TX_ENDOF, p->GivStart());
- goto error;
- }
-
- if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
- {
- goto error;
- }
- CBotClass* result = pStk->GivClass();
- if ( !pStk->GivTypResult(1).Eq(CBotTypNullPointer) &&
- ( !pStk->GivTypResult(1).Eq(CBotTypPointer) ||
- ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ?
- {
- pStk->SetError(TX_BADTYPE, p->GivStart());
- goto error;
- }
-// if ( !bIntrinsic ) var->SetPointer(pStk->GivVar()->GivPointer());
- if ( !bIntrinsic )
- {
- // n'utilise pas le résultat sur la pile, pour imposer la classe
- CBotVar* pvar = CBotVar::Create("", pClass);
- var->SetPointer( pvar ); // var déjà déclarée pointe l'instance
- delete pvar; // supprime le second pointeur
- }
- var->SetInit(TRUE); // marque le pointeur comme init
- }
- else if (inst->m_hasParams)
- {
- // crée l'objet sur le "tas"
- // avec un pointeur sur cet objet
- if ( !bIntrinsic )
- {
- CBotVar* pvar = CBotVar::Create("", pClass);
- var->SetPointer( pvar ); // var déjà déclarée pointe l'instance
- delete pvar; // supprime le second pointeur
- }
- var->SetInit(2); // marque le pointeur comme init
- }
-suite:
- if (IsOfType(p, ID_COMMA)) // plusieurs définitions enchaînées
- {
- if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compile la suivante
- {
- return pStack->Return(inst, pStk);
- }
- }
-
- if (IsOfType(p, ID_SEP)) // instruction terminée
- {
- return pStack->Return(inst, pStk);
- }
-
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
-
-error:
- delete inst;
- return pStack->Return(NULL, pStk);
-}
-
-// déclaration de l'instance d'une classe, par exemple:
-// CPoint A, B;
-
-BOOL CBotClassInst::Execute(CBotStack* &pj)
-{
- CBotVar* pThis = NULL;
-
- CBotStack* pile = pj->AddStack(this);//indispensable pour SetState()
-// if ( pile == EOX ) return TRUE;
-
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
-
- BOOL bIntrincic = pClass->IsIntrinsic();
-
- // crée la variable de type pointeur à l'objet
-
- if ( pile->GivState()==0)
- {
- CBotString name = m_var->m_token.GivString();
- if ( bIntrincic )
- {
- pThis = CBotVar::Create(name, CBotTypResult( CBotTypIntrinsic, pClass ));
- }
- else
- {
- pThis = CBotVar::Create(name, CBotTypResult( CBotTypPointer, pClass ));
- }
-
- pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // lui attribut un numéro unique
- pile->AddVar(pThis); // la place sur la pile
- pile->IncState();
- }
-
- if ( pThis == NULL ) pThis = pile->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
-
- if ( pile->GivState()<3)
- {
- // y a-t-il une assignation ou des paramètres (constructeur)
-
-// CBotVarClass* pInstance = NULL;
-
- if ( m_expr != NULL )
- {
- // évalue l'expression pour l'assignation
- if (!m_expr->Execute(pile)) return FALSE;
-
- if ( bIntrincic )
- {
- CBotVar* pv = pile->GivVar();
- if ( pv == NULL || pv->GivPointer() == NULL )
- {
- pile->SetError(TX_NULLPT, &m_token);
- return pj->Return(pile);
- }
- pThis->Copy(pile->GivVar(), FALSE);
- }
- else
- {
- CBotVarClass* pInstance;
- pInstance = ((CBotVarPointer*)pile->GivVar())->GivPointer(); // valeur pour l'assignation
- pThis->SetPointer(pInstance);
- }
- pThis->SetInit(TRUE);
- }
-
- else if ( m_hasParams )
- {
- // évalue le constructeur d'une instance
-
- if ( !bIntrincic && pile->GivState() == 1)
- {
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
-
- // crée une instance de la classe demandée
-
- CBotVarClass* pInstance;
- pInstance = (CBotVarClass*)CBotVar::Create("", pClass);
- pThis->SetPointer(pInstance);
- delete pInstance;
-
- pile->IncState();
- }
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( TRUE )
- {
- pile2 = pile2->AddStack(); // de la place sur la pile pour les résultats
- if ( pile2->GivState() == 0 )
- {
- if (!p->Execute(pile2)) return FALSE; // interrompu ici ?
- pile2->SetState(1);
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
- pThis, ppVars,
- pResult, pile2, GivToken())) return FALSE; // interrompu
-
- pThis->SetInit(TRUE);
- pThis->ConstructorSet(); // signale que le constructeur a été appelé
- pile->Return(pile2); // libère un bout de pile
-
-// pInstance = pThis->GivPointer();
-
- }
-
-// if ( !bIntrincic ) pThis->SetPointer(pInstance); // le fait pointer l'instance
-
- pile->SetState(3); // fini cette partie
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- if ( m_next2b != NULL &&
- !m_next2b->Execute(pile)) return FALSE; // autre(s) définition(s)
-
- return pj->Return( pile ); // transmet en dessous
-}
-
-
-
-void CBotClassInst::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotVar* pThis = NULL;
-
- CBotStack* pile = pj;
- if ( bMain ) pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- // crée la variable de type pointeur à l'objet
- {
- CBotString name = m_var->m_token.GivString();
- pThis = pile->FindVar(name);
- pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // lui attribut un numéro unique
- }
-
- CBotToken* pt = &m_token;
- CBotClass* pClass = CBotClass::Find(pt);
- BOOL bIntrincic = pClass->IsIntrinsic();
-
- if ( bMain && pile->GivState()<3)
- {
- // y a-t-il une assignation ou des paramètres (constructeur)
-
-// CBotVarClass* pInstance = NULL;
-
- if ( m_expr != NULL )
- {
- // évalue l'expression pour l'assignation
- m_expr->RestoreState(pile, bMain);
- return;
- }
-
- else if ( m_hasParams )
- {
- // évalue le constructeur d'une instance
-
- if ( !bIntrincic && pile->GivState() == 1)
- {
- return;
- }
-
- CBotVar* ppVars[1000];
- CBotStack* pile2 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
-
- if ( p != NULL) while ( TRUE )
- {
- pile2 = pile2->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile2 == NULL ) return;
-
- if ( pile2->GivState() == 0 )
- {
- p->RestoreState(pile2, bMain); // interrompu ici ?
- return;
- }
- ppVars[i++] = pile2->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- // crée une variable pour le résultat
- CBotVar* pResult = NULL; // constructeurs toujours void
-
- pClass->RestoreMethode(m_nMethodeIdent, pClass->GivName(), pThis, ppVars, pile2);
- return;
- }
- }
-
- if ( m_next2b != NULL )
- m_next2b->RestoreState(pile, bMain); // autre(s) définition(s)
-}
-
-
-// test si un nom de procédure est déjà défini quelque part
-
-BOOL CBotClass::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
-{
- CBotString name = pToken->GivString();
-
- if ( CBotCall::CheckCall(name) ) return TRUE;
-
- CBotFunction* pp = m_pMethod;
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return TRUE;
- }
- pp = pp->Next();
- }
-
- return FALSE;
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.//
+
+/////////////////////////////////////////////////////////////////////
+// Management of variables of class type
+//
+
+#include "CBot.h"
+
+
+CBotClass* CBotClass::m_ExClass = NULL;
+
+CBotClass::CBotClass(const char* name, CBotClass* pPapa, bool bIntrinsic)
+{
+ m_pParent = pPapa;
+ m_name = name;
+ m_pVar = NULL;
+ m_next = NULL;
+ m_pCalls = NULL;
+ m_pMethod = NULL;
+ m_rMaj = NULL;
+ m_IsDef = true;
+ m_bIntrinsic= bIntrinsic;
+ m_cptLock = 0;
+ m_cptOne = 0;
+ m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
+
+ for ( int j= 0; j< 5 ; j++ )
+ {
+ m_ProgInLock[j] = NULL;
+ }
+
+
+ // is located alone in the list
+ if (m_ExClass) m_ExClass->m_ExPrev = this;
+ m_ExNext = m_ExClass;
+ m_ExPrev = NULL;
+ m_ExClass = this;
+
+}
+
+CBotClass::~CBotClass()
+{
+ // removes the list of class
+ if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
+ else m_ExClass = m_ExNext;
+
+ if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
+ m_ExPrev = NULL;
+ m_ExNext = NULL;
+
+ delete m_pVar;
+ delete m_pCalls;
+ delete m_pMethod;
+
+ delete m_next; // releases all of them on this level
+}
+
+
+void CBotClass::Free()
+{
+ while ( m_ExClass != NULL )
+ {
+ delete m_ExClass;
+ }
+}
+
+void CBotClass::Purge()
+{
+ if ( this == NULL ) return;
+
+ delete m_pVar;
+ m_pVar = NULL;
+ delete m_pCalls;
+ m_pCalls = NULL;
+ delete m_pMethod;
+ m_pMethod = NULL;
+ m_IsDef = false;
+
+ m_nbVar = m_pParent == NULL ? 0 : m_pParent->m_nbVar;
+
+ m_next->Purge();
+ m_next = NULL; // no longer belongs to this chain
+}
+
+bool CBotClass::Lock(CBotProgram* p)
+{
+ int i = m_cptLock++;
+
+ if ( i == 0 )
+ {
+ m_cptOne = 1;
+ m_ProgInLock[0] = p;
+ return true;
+ }
+ if ( p == m_ProgInLock[0] )
+ {
+ m_cptOne++;
+ m_cptLock--; // has already been counted
+ return true;
+ }
+
+ for ( int j = 1 ; j <= i ; j++)
+ {
+ if ( p == m_ProgInLock[j] )
+ {
+ m_cptLock--;
+ return false; // already pending
+ }
+ }
+
+ if ( i < 5 ) // max 5 in query
+ {
+ m_ProgInLock[i] = p; // located in a queue
+ }
+ else
+ m_cptLock--;
+
+ return false;
+}
+
+void CBotClass::Unlock()
+{
+ if ( --m_cptOne > 0 ) return ;
+
+ int i = --m_cptLock;
+ if ( i<0 )
+ {
+ m_cptLock = 0;
+ return;
+ }
+
+ for ( int j= 0; j< i ; j++ )
+ {
+ m_ProgInLock[j] = m_ProgInLock[j+1];
+ }
+ m_ProgInLock[i] = 0;
+}
+
+void CBotClass::FreeLock(CBotProgram* p)
+{
+ CBotClass* pClass = m_ExClass;
+
+ while ( pClass != NULL )
+ {
+ if ( p == pClass->m_ProgInLock[0] )
+ {
+ pClass->m_cptLock -= pClass->m_cptOne;
+ pClass->m_cptOne = 0;
+ }
+
+ for ( int j = 1; j < 5 ; j++ )
+ if ( p == pClass->m_ProgInLock[j] )
+ pClass->m_cptLock--;
+
+ pClass = pClass->m_ExNext;
+ }
+}
+
+
+
+bool CBotClass::AddItem(CBotString name, CBotTypResult type, int mPrivate)
+{
+ CBotToken token(name, CBotString());
+ CBotClass* pClass = type.GivClass();
+
+ CBotVar* pVar = CBotVar::Create( name, type );
+/// pVar->SetUniqNum(CBotVar::NextUniqNum());
+ pVar->SetPrivate( mPrivate );
+
+ if ( pClass != NULL )
+ {
+// pVar->SetClass(pClass);
+ if ( type.Eq(CBotTypClass) )
+ {
+ // adds a new statement for the object initialization
+ pVar->m_InitExpr = new CBotNew() ;
+ CBotToken nom( pClass->GivName() );
+ pVar->m_InitExpr->SetToken(&nom);
+ }
+ }
+ return AddItem( pVar );
+}
+
+
+bool CBotClass::AddItem(CBotVar* pVar)
+{
+ pVar->SetUniqNum(++m_nbVar);
+
+ if ( m_pVar == NULL ) m_pVar = pVar;
+ else m_pVar->AddNext(pVar);
+
+ return true;
+}
+
+void CBotClass::AddNext(CBotClass* pClass)
+{
+ CBotClass* p = this;
+ while (p->m_next != NULL) p = p->m_next;
+
+ p->m_next = pClass;
+}
+
+CBotString CBotClass::GivName()
+{
+ return m_name;
+}
+
+CBotClass* CBotClass::GivParent()
+{
+ if ( this == NULL ) return NULL;
+ return m_pParent;
+}
+
+bool CBotClass::IsChildOf(CBotClass* pClass)
+{
+ CBotClass* p = this;
+ while ( p != NULL )
+ {
+ if ( p == pClass ) return true;
+ p = p->m_pParent;
+ }
+ return false;
+}
+
+
+CBotVar* CBotClass::GivVar()
+{
+ return m_pVar;
+}
+
+CBotVar* CBotClass::GivItem(const char* name)
+{
+ CBotVar* p = m_pVar;
+
+ while ( p != NULL )
+ {
+ if ( p->GivName() == name ) return p;
+ p = p->GivNext();
+ }
+ if ( m_pParent != NULL ) return m_pParent->GivItem(name);
+ return NULL;
+}
+
+CBotVar* CBotClass::GivItemRef(int nIdent)
+{
+ CBotVar* p = m_pVar;
+
+ while ( p != NULL )
+ {
+ if ( p->GivUniqNum() == nIdent ) return p;
+ p = p->GivNext();
+ }
+ if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
+ return NULL;
+}
+
+bool CBotClass::IsIntrinsic()
+{
+ return m_bIntrinsic;
+}
+
+CBotClass* CBotClass::Find(CBotToken* &pToken)
+{
+ return Find(pToken->GivString());
+}
+
+CBotClass* CBotClass::Find(const char* name)
+{
+ CBotClass* p = m_ExClass;
+
+ while ( p != NULL )
+ {
+ if ( p->GivName() == name ) return p;
+ p = p->m_ExNext;
+ }
+
+ return NULL;
+}
+
+bool CBotClass::AddFunction(const char* name,
+ bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
+ CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
+{
+ // stores pointers to the two functions
+ CBotCallMethode* p = m_pCalls;
+ CBotCallMethode* pp = NULL;
+
+ while ( p != NULL )
+ {
+ if ( name == p->GivName() )
+ {
+ if ( pp == NULL ) m_pCalls = p->m_next;
+ else pp->m_next = p->m_next;
+ delete p;
+ break;
+ }
+ pp = p;
+ p = p->m_next;
+ }
+
+ p = new CBotCallMethode(name, rExec, rCompile);
+
+ if (m_pCalls == NULL) m_pCalls = p;
+ else m_pCalls->AddNext(p); // added to the list
+
+ return true;
+}
+
+bool CBotClass::AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) )
+{
+ m_rMaj = rMaj;
+ return true;
+}
+
+// compiles a method associated with an instance of class
+// the method can be declared by the user or AddFunction
+
+CBotTypResult CBotClass::CompileMethode(const char* name,
+ CBotVar* pThis, CBotVar** ppParams,
+ CBotCStack* pStack, long& nIdent)
+{
+ nIdent = 0; // forget the previous one if necessary
+
+ // find the methods declared by AddFunction
+
+ CBotTypResult r = m_pCalls->CompileCall(name, pThis, ppParams, pStack, nIdent);
+ if ( r.GivType() >= 0) return r;
+
+ // find the methods declared by user
+
+ r = m_pMethod->CompileCall(name, ppParams, nIdent);
+ if ( r.Eq(TX_UNDEFCALL) && m_pParent != NULL )
+ return m_pParent->m_pMethod->CompileCall(name, ppParams, nIdent);
+ return r;
+}
+
+// executes a method
+
+bool CBotClass::ExecuteMethode(long& nIdent, const char* name,
+ CBotVar* pThis, CBotVar** ppParams,
+ CBotVar* &pResult, CBotStack* &pStack,
+ CBotToken* pToken)
+{
+ int ret = m_pCalls->DoCall(nIdent, name, pThis, ppParams, pResult, pStack, pToken);
+ if (ret>=0) return ret;
+
+ ret = m_pMethod->DoCall(nIdent, name, pThis, ppParams, pStack, pToken, this);
+ return ret;
+}
+
+// restored the execution stack
+
+void CBotClass::RestoreMethode(long& nIdent, const char* name, CBotVar* pThis,
+ CBotVar** ppParams, CBotStack* &pStack)
+{
+ m_pMethod->RestoreCall(nIdent, name, pThis, ppParams, pStack, this);
+}
+
+
+
+
+bool CBotClass::SaveStaticState(FILE* pf)
+{
+ if (!WriteWord( pf, CBOTVERSION*2)) return false;
+
+ // saves the state of static variables in classes
+ CBotClass* p = m_ExClass;
+
+ while ( p != NULL )
+ {
+ if (!WriteWord( pf, 1)) return false;
+ // save the name of the class
+ if (!WriteString( pf, p->GivName() )) return false;
+
+ CBotVar* pv = p->GivVar();
+ while( pv != NULL )
+ {
+ if ( pv->IsStatic() )
+ {
+ if (!WriteWord( pf, 1)) return false;
+ if (!WriteString( pf, pv->GivName() )) return false;
+
+ if ( !pv->Save0State(pf)) return false; // common header
+ if ( !pv->Save1State(pf) ) return false; // saves as the child class
+ if ( !WriteWord( pf, 0)) return false;
+ }
+ pv = pv->GivNext();
+ }
+
+ if (!WriteWord( pf, 0)) return false;
+ p = p->m_ExNext;
+ }
+
+ if (!WriteWord( pf, 0)) return false;
+ return true;
+}
+
+bool CBotClass::RestoreStaticState(FILE* pf)
+{
+ CBotString ClassName, VarName;
+ CBotClass* pClass;
+ unsigned short w;
+
+ if (!ReadWord( pf, w )) return false;
+ if ( w != CBOTVERSION*2 ) return false;
+
+ while (true)
+ {
+ if (!ReadWord( pf, w )) return false;
+ if ( w == 0 ) return true;
+
+ if (!ReadString( pf, ClassName )) return false;
+ pClass = Find(ClassName);
+
+ while (true)
+ {
+ if (!ReadWord( pf, w )) return false;
+ if ( w == 0 ) break;
+
+ CBotVar* pVar = NULL;
+ CBotVar* pv = NULL;
+
+ if (!ReadString( pf, VarName )) return false;
+ if ( pClass != NULL ) pVar = pClass->GivItem(VarName);
+
+ if (!CBotVar::RestoreState(pf, pv)) return false; // the temp variable
+
+ if ( pVar != NULL ) pVar->Copy(pv);
+ delete pv;
+ }
+ }
+ return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////
+
+CBotClassInst::CBotClassInst()
+{
+ m_next = NULL;
+ m_var = NULL;
+ m_Parameters = NULL;
+ m_expr = NULL;
+ m_hasParams = false;
+ m_nMethodeIdent = 0;
+ name = "CBotClassInst";
+}
+
+CBotClassInst::~CBotClassInst()
+{
+ delete m_var;
+// delete m_next; // done by the destructor of the base class ~CBotInstr()
+}
+
+// definition of pointer (s) to an object
+// style
+// CPoint A, B ;
+
+CBotInstr* CBotClassInst::Compile(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
+{
+ // seeks the corresponding classes
+ if ( pClass == NULL )
+ {
+ pStack->SetStartError(p->GivStart());
+ pClass = CBotClass::Find(p);
+ if ( pClass == NULL )
+ {
+ // not found? is bizare
+ pStack->SetError(TX_NOCLASS, p);
+ return NULL;
+ }
+ p = p->GivNext();
+ }
+
+ bool bIntrinsic = pClass->IsIntrinsic();
+ CBotTypResult type = CBotTypResult( bIntrinsic ? CBotTypIntrinsic : CBotTypPointer, pClass );
+ CBotClassInst* inst = (CBotClassInst*)CompileArray(p, pStack, type);
+ if ( inst != NULL || !pStack->IsOk() ) return inst;
+
+ CBotCStack* pStk = pStack->TokenStack();
+
+ inst = new CBotClassInst();
+ /// \TODO Need to be revised and fixed after adding unit tests
+ CBotToken token(pClass->GivName(), CBotString(), p->GivStart(), p->GivEnd());
+ inst->SetToken(&token);
+ CBotToken* vartoken = p;
+
+ if ( NULL != (inst->m_var = CBotLeftExprVar::Compile( p, pStk )) )
+ {
+ ((CBotLeftExprVar*)inst->m_var)->m_typevar = type;
+ if (pStk->CheckVarLocal(vartoken)) // redefinition of the variable
+ {
+ pStk->SetStartError(vartoken->GivStart());
+ pStk->SetError(TX_REDEFVAR, vartoken->GivEnd());
+ goto error;
+ }
+
+ if (IsOfType(p, ID_OPBRK)) // with any clues?
+ {
+ delete inst; // is not type CBotInt
+ p = vartoken; // returns to the variable name
+
+ // compiles declaration an array
+
+ inst = (CBotClassInst*)CBotInstArray::Compile( p, pStk, type );
+
+ if (!pStk->IsOk() )
+ {
+ pStk->SetError(TX_CLBRK, p->GivStart());
+ goto error;
+ }
+ goto suite; // no assignment, variable already created
+ }
+
+
+ CBotVar* var;
+ var = CBotVar::Create(vartoken->GivString(), type); // creates the instance
+// var->SetClass(pClass);
+ var->SetUniqNum(
+ ((CBotLeftExprVar*)inst->m_var)->m_nIdent = CBotVar::NextUniqNum());
+ // its attribute a unique number
+ pStack->AddVar(var); // placed on the stack
+
+ // look if there are parameters
+ inst->m_hasParams = (p->GivType() == ID_OPENPAR);
+
+ CBotVar* ppVars[1000];
+ inst->m_Parameters = CompileParams(p, pStk, ppVars);
+ if ( !pStk->IsOk() ) goto error;
+
+ // if there are parameters, is the equivalent to the stament "new"
+ // CPoint A ( 0, 0 ) is equivalent to
+ // CPoint A = new CPoint( 0, 0 )
+
+// if ( NULL != inst->m_Parameters )
+ if ( inst->m_hasParams )
+ {
+ // the constructor is there?
+// CBotString noname;
+ CBotTypResult r = pClass->CompileMethode(pClass->GivName(), var, ppVars, pStk, inst->m_nMethodeIdent);
+ delete pStk->TokenStack(); // releases the supplement stack
+ int typ = r.GivType();
+
+ if (typ == TX_UNDEFCALL)
+ {
+ // si le constructeur n'existe pas
+ if (inst->m_Parameters != NULL) // with parameters
+ {
+ pStk->SetError(TX_NOCONST, vartoken);
+ goto error;
+ }
+ typ = 0;
+ }
+
+ if (typ>20)
+ {
+ pStk->SetError(typ, vartoken->GivEnd());
+ goto error;
+ }
+
+ }
+
+ if (IsOfType(p, ID_ASS)) // with a assignment?
+ {
+ if (inst->m_hasParams)
+ {
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ goto error;
+ }
+
+ if ( NULL == ( inst->m_expr = CBotTwoOpExpr::Compile( p, pStk )) )
+ {
+ goto error;
+ }
+ CBotClass* result = pStk->GivClass();
+ if ( !pStk->GivTypResult(1).Eq(CBotTypNullPointer) &&
+ ( !pStk->GivTypResult(1).Eq(CBotTypPointer) ||
+ ( result != NULL && !pClass->IsChildOf(result) ))) // type compatible ?
+ {
+ pStk->SetError(TX_BADTYPE, p->GivStart());
+ goto error;
+ }
+// if ( !bIntrinsic ) var->SetPointer(pStk->GivVar()->GivPointer());
+ if ( !bIntrinsic )
+ {
+ // does not use the result on the stack, to impose the class
+ CBotVar* pvar = CBotVar::Create("", pClass);
+ var->SetPointer( pvar ); // variable already declared instance pointer
+ delete pvar; // removes the second pointer
+ }
+ var->SetInit(true); // marks the pointer as init
+ }
+ else if (inst->m_hasParams)
+ {
+ // creates the object on the "job" (\TODO "tas")
+ // with a pointer to the object
+ if ( !bIntrinsic )
+ {
+ CBotVar* pvar = CBotVar::Create("", pClass);
+ var->SetPointer( pvar ); // variable already declared instance pointer
+ delete pvar; // removes the second pointer
+ }
+ var->SetInit(2); // marks the pointer as init
+ }
+suite:
+ if (IsOfType(p, ID_COMMA)) // several chained definitions
+ {
+ if ( NULL != ( inst->m_next = CBotClassInst::Compile(p, pStk, pClass) )) // compiles the following
+ {
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ if (IsOfType(p, ID_SEP)) // complete instruction
+ {
+ return pStack->Return(inst, pStk);
+ }
+
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+
+error:
+ delete inst;
+ return pStack->Return(NULL, pStk);
+}
+
+// declaration of the instance of a class, for example:
+// CPoint A, B;
+
+bool CBotClassInst::Execute(CBotStack* &pj)
+{
+ CBotVar* pThis = NULL;
+
+ CBotStack* pile = pj->AddStack(this);//essential for SetState()
+// if ( pile == EOX ) return true;
+
+ CBotToken* pt = &m_token;
+ CBotClass* pClass = CBotClass::Find(pt);
+
+ bool bIntrincic = pClass->IsIntrinsic();
+
+ // creates the variable of type pointer to the object
+
+ if ( pile->GivState()==0)
+ {
+ CBotString name = m_var->m_token.GivString();
+ if ( bIntrincic )
+ {
+ pThis = CBotVar::Create(name, CBotTypResult( CBotTypIntrinsic, pClass ));
+ }
+ else
+ {
+ pThis = CBotVar::Create(name, CBotTypResult( CBotTypPointer, pClass ));
+ }
+
+ pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // its attribute as unique number
+ pile->AddVar(pThis); // place on the stack
+ pile->IncState();
+ }
+
+ if ( pThis == NULL ) pThis = pile->FindVar(((CBotLeftExprVar*)m_var)->m_nIdent);
+
+ if ( pile->GivState()<3)
+ {
+ // ss there an assignment or parameters (contructor)
+
+// CBotVarClass* pInstance = NULL;
+
+ if ( m_expr != NULL )
+ {
+ // evaluates the expression for the assignment
+ if (!m_expr->Execute(pile)) return false;
+
+ if ( bIntrincic )
+ {
+ CBotVar* pv = pile->GivVar();
+ if ( pv == NULL || pv->GivPointer() == NULL )
+ {
+ pile->SetError(TX_NULLPT, &m_token);
+ return pj->Return(pile);
+ }
+ pThis->Copy(pile->GivVar(), false);
+ }
+ else
+ {
+ CBotVarClass* pInstance;
+ pInstance = ((CBotVarPointer*)pile->GivVar())->GivPointer(); // value for the assignment
+ pThis->SetPointer(pInstance);
+ }
+ pThis->SetInit(true);
+ }
+
+ else if ( m_hasParams )
+ {
+ // evaluates the constructor of an instance
+
+ if ( !bIntrincic && pile->GivState() == 1)
+ {
+ CBotToken* pt = &m_token;
+ CBotClass* pClass = CBotClass::Find(pt);
+
+ // creates an instance of the requested class
+
+ CBotVarClass* pInstance;
+ pInstance = (CBotVarClass*)CBotVar::Create("", pClass);
+ pThis->SetPointer(pInstance);
+ delete pInstance;
+
+ pile->IncState();
+ }
+
+ CBotVar* ppVars[1000];
+ CBotStack* pile2 = pile;
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluates the parameters
+ // and places the values ​​on the stack
+ // to (can) be interrupted (broken) at any time
+
+ if ( p != NULL) while ( true )
+ {
+ pile2 = pile2->AddStack(); // place on the stack for the results
+ if ( pile2->GivState() == 0 )
+ {
+ if (!p->Execute(pile2)) return false; // interrupted here?
+ pile2->SetState(1);
+ }
+ ppVars[i++] = pile2->GivVar();
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ // creates a variable for the result
+ CBotVar* pResult = NULL; // constructor still void
+
+ if ( !pClass->ExecuteMethode(m_nMethodeIdent, pClass->GivName(),
+ pThis, ppVars,
+ pResult, pile2, GivToken())) return false; // interrupt
+
+ pThis->SetInit(true);
+ pThis->ConstructorSet(); // indicates that the constructor has been called
+ pile->Return(pile2); // releases a piece of stack
+
+// pInstance = pThis->GivPointer();
+
+ }
+
+// if ( !bIntrincic ) pThis->SetPointer(pInstance); // a pointer to the instance
+
+ pile->SetState(3); // finished this part
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ if ( m_next2b != NULL &&
+ !m_next2b->Execute(pile)) return false; // other (s) definition (s)
+
+ return pj->Return( pile ); // transmits below (further)
+}
+
+
+
+void CBotClassInst::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotVar* pThis = NULL;
+
+ CBotStack* pile = pj;
+ if ( bMain ) pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ // creates the variable of type pointer to the object
+ {
+ CBotString name = m_var->m_token.GivString();
+ pThis = pile->FindVar(name);
+ pThis->SetUniqNum(((CBotLeftExprVar*)m_var)->m_nIdent); // its attribute a unique number
+ }
+
+ CBotToken* pt = &m_token;
+ CBotClass* pClass = CBotClass::Find(pt);
+ bool bIntrincic = pClass->IsIntrinsic();
+
+ if ( bMain && pile->GivState()<3)
+ {
+ // is there an assignment or parameters (constructor)
+
+// CBotVarClass* pInstance = NULL;
+
+ if ( m_expr != NULL )
+ {
+ // evaluates the expression for the assignment
+ m_expr->RestoreState(pile, bMain);
+ return;
+ }
+
+ else if ( m_hasParams )
+ {
+ // evaluates the constructor of an instance
+
+ if ( !bIntrincic && pile->GivState() == 1)
+ {
+ return;
+ }
+
+ CBotVar* ppVars[1000];
+ CBotStack* pile2 = pile;
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluates the parameters
+ // and the values an the stack
+ // for the ability to be interrupted at any time (\TODO pour pouvoir être interrompu n'importe quand)
+
+ if ( p != NULL) while ( true )
+ {
+ pile2 = pile2->RestoreStack(); // place on the stack for the results
+ if ( pile2 == NULL ) return;
+
+ if ( pile2->GivState() == 0 )
+ {
+ p->RestoreState(pile2, bMain); // interrupted here?
+ return;
+ }
+ ppVars[i++] = pile2->GivVar();
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ // creates a variable for the result
+ CBotVar* pResult = NULL; // constructor still void
+
+ pClass->RestoreMethode(m_nMethodeIdent, pClass->GivName(), pThis, ppVars, pile2);
+ return;
+ }
+ }
+
+ if ( m_next2b != NULL )
+ m_next2b->RestoreState(pile, bMain); // other(s) definition(s)
+}
+
+
+// test if a procedure name is already defined somewhere
+
+bool CBotClass::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
+{
+ CBotString name = pToken->GivString();
+
+ if ( CBotCall::CheckCall(name) ) return true;
+
+ CBotFunction* pp = m_pMethod;
+ while ( pp != NULL )
+ {
+ if ( pToken->GivString() == pp->GivName() )
+ {
+ // are their parameters exactly the same?
+ if ( pp->CheckParam( pParam ) )
+ return true;
+ }
+ pp = pp->Next();
+ }
+
+ return false;
+}
+
diff --git a/src/CBot/CBotCompExpr.cpp b/src/CBot/CBotCompExpr.cpp
index 41e7e05..2daf53f 100644
--- a/src/CBot/CBotCompExpr.cpp
+++ b/src/CBot/CBotCompExpr.cpp
@@ -1,131 +1,133 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////
-// expression du genre Opérande1 > Opérande2
-// Opérande1 != Opérande2
-// etc.
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotCompExpr::CBotCompExpr()
-{
- m_leftop =
- m_rightop = NULL;
- name = "CBotCompExpr";
-}
-
-CBotCompExpr::~CBotCompExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-fichier plus utilise;
-
-// compile une instruction de type A < B
-
-CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCStack* pStk = pStack->AddStack();
-
- CBotInstr* left = CBotAddExpr::Compile( p, pStk ); // expression A + B à gauche
- if (left == NULL) return pStack->Return(NULL, pStk); // erreur
-
- if ( p->GetType() == ID_HI ||
- p->GetType() == ID_LO ||
- p->GetType() == ID_HS ||
- p->GetType() == ID_LS ||
- p->GetType() == ID_EQ ||
- p->GetType() == ID_NE) // les diverses comparaisons
- {
- CBotCompExpr* inst = new CBotCompExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
- int type1, type2;
- type1 = pStack->GetType();
-
- p = p->Next();
- if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B à droite
- {
- type2 = pStack->GetType();
- // les résultats sont-ils compatibles
- if ( type1 == type2 )
- {
- inst->m_leftop = left;
- pStk->SetVar(new CBotVar(NULL, CBotTypBoolean));
- // le résultat est un boolean
- return pStack->Return(inst, pStk);
- }
- }
-
- delete left;
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- return pStack->Return(left, pStk);
-}
-
-
-// fait l'opération
-
-BOOL CBotCompExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this);
-// if ( pStk1 == EOX ) return TRUE;
-
- if ( pStk1->GetState() == 0 && !m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- pStk1->SetState(1); // opération terminée
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- CBotStack* pStk2 = pStk1->AddStack();
-
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
-
- int type1 = pStk1->GetType();
- int type2 = pStk2->GetType();
-
- CBotVar* result = new CBotVar( NULL, CBotTypBoolean );
-
- switch (GetTokenType())
- {
- case ID_LO:
- result->Lo(pStk1->GetVar(), pStk2->GetVar()); // inférieur
- break;
- case ID_HI:
- result->Hi(pStk1->GetVar(), pStk2->GetVar()); // supérieur
- break;
- case ID_LS:
- result->Ls(pStk1->GetVar(), pStk2->GetVar()); // inférieur ou égal
- break;
- case ID_HS:
- result->Hs(pStk1->GetVar(), pStk2->GetVar()); // supérieur ou égal
- break;
- case ID_EQ:
- result->Eq(pStk1->GetVar(), pStk2->GetVar()); // égal
- break;
- case ID_NE:
- result->Ne(pStk1->GetVar(), pStk2->GetVar()); // différent
- break;
- }
- pStk2->SetVar(result); // met le résultat sur la pile
-
- pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk1); // transmet le résultat
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+///////////////////////////////////////////////////
+// expression of type Opérande1 > Opérande2
+// Opérande1 != Opérande2
+// etc.
+
+#include "CBot.h"
+
+// various constructeurs
+
+CBotCompExpr::CBotCompExpr()
+{
+ m_leftop =
+ m_rightop = NULL;
+ name = "CBotCompExpr";
+}
+
+CBotCompExpr::~CBotCompExpr()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+fichier plus utilise;
+
+// compile instruction of type A < B
+
+CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->AddStack();
+
+ CBotInstr* left = CBotAddExpr::Compile( p, pStk ); // expression A + B left
+ if (left == NULL) return pStack->Return(NULL, pStk); // error
+
+ if ( p->GetType() == ID_HI ||
+ p->GetType() == ID_LO ||
+ p->GetType() == ID_HS ||
+ p->GetType() == ID_LS ||
+ p->GetType() == ID_EQ ||
+ p->GetType() == ID_NE) // the various comparisons
+ {
+ CBotCompExpr* inst = new CBotCompExpr(); // element for operation
+ inst->SetToken(p); // stores the operation
+
+ int type1, type2;
+ type1 = pStack->GetType();
+
+ p = p->Next();
+ if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B right
+ {
+ type2 = pStack->GetType();
+ // are the results compatible
+ if ( type1 == type2 )
+ {
+ inst->m_leftop = left;
+ pStk->SetVar(new CBotVar(NULL, CBotTypBoolean));
+ // the result is a boolean
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ delete left;
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ return pStack->Return(left, pStk);
+}
+
+
+// perform the operation
+
+bool CBotCompExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this);
+// if ( pStk1 == EOX ) return TRUE;
+
+ if ( pStk1->GetState() == 0 && !m_leftop->Execute(pStk1) ) return FALSE; // interrupted here ?
+
+ pStk1->SetState(1); // finished
+
+ // requires a little more stack to not touch the result of the left
+ CBotStack* pStk2 = pStk1->AddStack();
+
+ if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrupted here ?
+
+ int type1 = pStk1->GetType();
+ int type2 = pStk2->GetType();
+
+ CBotVar* result = new CBotVar( NULL, CBotTypBoolean );
+
+ switch (GetTokenType())
+ {
+ case ID_LO:
+ result->Lo(pStk1->GetVar(), pStk2->GetVar()); // lower
+ break;
+ case ID_HI:
+ result->Hi(pStk1->GetVar(), pStk2->GetVar()); // higher
+ break;
+ case ID_LS:
+ result->Ls(pStk1->GetVar(), pStk2->GetVar()); // lower or equal
+ break;
+ case ID_HS:
+ result->Hs(pStk1->GetVar(), pStk2->GetVar()); // higher of equal
+ break;
+ case ID_EQ:
+ result->Eq(pStk1->GetVar(), pStk2->GetVar()); // equal
+ break;
+ case ID_NE:
+ result->Ne(pStk1->GetVar(), pStk2->GetVar()); // not equal
+ break;
+ }
+ pStk2->SetVar(result); // puts the result on the stack
+
+ pStk1->Return(pStk2); // frees the stack
+ return pStack->Return(pStk1); // transmit the result
+}
+
diff --git a/src/CBot/CBotDll.h b/src/CBot/CBotDll.h
index 7fa9472..269ef94 100644
--- a/src/CBot/CBotDll.h
+++ b/src/CBot/CBotDll.h
@@ -1,1200 +1,1117 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.////////////////////////////////////////////////////////////////////////
-// Librairie pour l'interprétation du language CBOT
-// pour le jeu COLOBOT
-//
-
-//#include "stdafx.h"
-
-#include <windows.h>
-#include <stdio.h>
-
-#define DllExport __declspec( dllexport )
-
-#define CBOTVERSION 104
-
-////////////////////////////////////////////////////////////////////////
-// quelques classes définies par ailleurs
-
-class CBotToken; // programme transformé en "jetons"
-class CBotStack; // pile pour l'exécution
-class CBotClass; // classe d'object
-class CBotInstr; // instruction à exécuter
-class CBotFunction; // les fonctions user
-class CBotVar; // les variables
-class CBotVarClass; // une instance de classe
-class CBotVarPointer; // pointeur à une instance de classe
-class CBotCall; // les fonctions
-class CBotCallMethode; // les méthodes
-class CBotDefParam; // liste de paramètres
-class CBotCStack;
-
-
-////////////////////////////////////////////////////////////////////////
-// Gestion des variables
-////////////////////////////////////////////////////////////////////////
-
-// ces types sont calqués sur les types Java
-// ne pas changer l'ordre de ces types
-
-enum CBotType
-{
- CBotTypVoid = 0, // fonction retournant void
- CBotTypByte = 1, //n // nombre entier ( 8 bits)
- CBotTypShort = 2, //n // nombre entier (16 bits)
- CBotTypChar = 3, //n // caractère "unicode" (16 bits)
- CBotTypInt = 4, // nombre entier (32 bits)
- CBotTypLong = 5, //n // nombre entier (64 bits)
- CBotTypFloat = 6, // nombre décimal (32 bits)
- CBotTypDouble = 7, //n // nombre décimal (64 bits)
- CBotTypBoolean = 8, // true ou false exclusivement
- CBotTypString = 9, // chaine de caractère
-
- CBotTypArrayPointer = 10, // un tableau de variables
- CBotTypArrayBody = 11, // idem mais crée l'instance
-
- CBotTypPointer = 12, // pointeur à une instance
- CBotTypNullPointer = 13, // pointeur null est spécial
-
- CBotTypClass = 15, // instance d'une classe
- CBotTypIntrinsic = 16 // instance d'une classe intrinsèque
-};
- //n = non encore implémenté
-
-// pour SetUserPtr lors de la suppression d'un objet
-#define OBJECTDELETED ((void*)-1)
-// valeur mise avant initialisation
-#define OBJECTCREATED ((void*)-2)
-
-
-// classe permettant de définir le type complet d'un résultat
-class CBotTypResult
-{
-private:
- int m_type;
- CBotTypResult* m_pNext; // pour les types de types
- CBotClass* m_pClass; // pour les dérivés de classe
- int m_limite; // limitation des tableaux
- friend class CBotVarClass;
- friend class CBotVarPointer;
-
-public:
- // divers constructeurs selon les besoins
- DllExport
- CBotTypResult(int type);
- // pour les types simples (CBotTypInt à CBotTypString)
- DllExport
- CBotTypResult(int type, const char* name);
- // pour les types pointeur et classe intrinsic
- DllExport
- CBotTypResult(int type, CBotClass* pClass);
- // idem à partir de l'instance d'une classe
- DllExport
- CBotTypResult(int type, CBotTypResult elem);
- // pour les tableaux de variables
-
- DllExport
- CBotTypResult(const CBotTypResult& typ);
- // pour les assignations
- DllExport
- CBotTypResult();
- // pour par défaut
- DllExport
- ~CBotTypResult();
-
- DllExport
- int GivType(int mode = 0) const;
- // rend le type CBotTyp* du résultat
-
- void SetType(int n);
- // modifie le type
-
- DllExport
- CBotClass* GivClass() const;
- // rend le pointeur à la classe (pour les CBotTypClass, CBotTypPointer)
-
- DllExport
- int GivLimite() const;
- // rend la taille limite du tableau (CBotTypArray)
-
- DllExport
- void SetLimite(int n);
- // fixe une limite au tableau
-
- void SetArray(int* max );
- // idem avec une liste de dimension (tableaux de tableaux)
-
- DllExport
- CBotTypResult& GivTypElem() const;
- // rend le type des éléments du tableau (CBotTypArray)
-
- DllExport
- BOOL Compare(const CBotTypResult& typ) const;
- // compare si les types sont compatibles
- DllExport
- BOOL Eq(int type) const;
- // compare le type
-
- DllExport
- CBotTypResult&
- operator=(const CBotTypResult& src);
- // copie un type complet dans un autre
-};
-
-/*
-// pour définir un résultat en sortie, utiliser par exemple
-
- // pour rendre un simple Float
- return CBotTypResult( CBotTypFloat );
-
-
- // pour rendre un tableau de string
- return CBotTypResult( CBotTypArray, CBotTypResult( CBotTypString ) );
-
- // pour rendre un tableau de tableau de "point"
- CBotTypResult typPoint( CBotTypIntrinsic, "point" );
- CBotTypResult arrPoint( CBotTypArray, typPoint );
- return CBotTypResult( CBotTypArray, arrPoint );
-*/
-
-
-////////////////////////////////////////////////////////////////////////
-// Gestion des erreurs compilation et exécution
-////////////////////////////////////////////////////////////////////////
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour la compilation
-
-#define CBotErrOpenPar 5000 // manque la parenthèse ouvrante
-#define CBotErrClosePar 5001 // manque la parenthèse fermante
-#define CBotErrNotBoolean 5002 // l'expression doit être un boolean
-#define CBotErrUndefVar 5003 // variable non déclarée
-#define CBotErrBadLeft 5004 // assignation impossible ( 5 = ... )
-#define CBotErrNoTerminator 5005 // point-virgule attendu
-#define CBotErrCaseOut 5006 // case en dehors d'un switch
-// CBotErrNoTerm 5007, plus utile
-#define CBotErrCloseBlock 5008 // manque " } "
-#define CBotErrElseWhitoutIf 5009 // else sans if correspondant
-#define CBotErrOpenBlock 5010 // manque " { "
-#define CBotErrBadType1 5011 // mauvais type pour l'assignation
-#define CBotErrRedefVar 5012 // redéfinition de la variable
-#define CBotErrBadType2 5013 // 2 opérandes de type incompatibles
-#define CBotErrUndefCall 5014 // routine inconnue
-#define CBotErrNoDoubleDots 5015 // " : " attendu
-// CBotErrWhile 5016, plus utile
-#define CBotErrBreakOutside 5017 // break en dehors d'une boucle
-#define CBotErrUndefLabel 5019 // label inconnu
-#define CBotErrLabel 5018 // label ne peut se mettre ici
-#define CBotErrNoCase 5020 // manque " case "
-#define CBotErrBadNum 5021 // nombre attendu
-#define CBotErrVoid 5022 // " void " pas possible ici
-#define CBotErrNoType 5023 // déclaration de type attendue
-#define CBotErrNoVar 5024 // nom de variable attendu
-#define CBotErrNoFunc 5025 // nom de fonction attendu
-#define CBotErrOverParam 5026 // trop de paramètres
-#define CBotErrRedefFunc 5027 // cette fonction existe déjà
-#define CBotErrLowParam 5028 // pas assez de paramètres
-#define CBotErrBadParam 5029 // mauvais types de paramètres
-#define CBotErrNbParam 5030 // mauvais nombre de paramètres
-#define CBotErrUndefItem 5031 // élément n'existe pas dans la classe
-#define CBotErrUndefClass 5032 // variable n'est pas une classe
-#define CBotErrNoConstruct 5033 // pas de constructeur approprié
-#define CBotErrRedefClass 5034 // classe existe déjà
-#define CBotErrCloseIndex 5035 // " ] " attendu
-#define CBotErrReserved 5036 // mot réservé (par un DefineNum)
-#define CBotErrBadNew 5037 // mauvais paramètre pour new
-#define CBotErrOpenIndex 5038 // " [ " attendu
-#define CBotErrBadString 5039 // chaîne de caractère attendue
-#define CBotErrBadIndex 5040 // mauvais type d'index "[ false ]"
-#define CBotErrPrivate 5041 // élément protégé
-#define CBotErrNoPublic 5042 // manque le mot "public"
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour l'exécution
-
-#define CBotErrZeroDiv 6000 // division par zéro
-#define CBotErrNotInit 6001 // variable non initialisée
-#define CBotErrBadThrow 6002 // throw d'une valeur négative
-#define CBotErrNoRetVal 6003 // fonction n'a pas retourné de résultat
-#define CBotErrNoRun 6004 // Run() sans fonction active
-#define CBotErrUndefFunc 6005 // appel d'une fonction qui n'existe plus
-#define CBotErrNotClass 6006 // cette classe n'existe pas
-#define CBotErrNull 6007 // pointeur null
-#define CBotErrNan 6008 // calcul avec un NAN
-#define CBotErrOutArray 6009 // index hors du tableau
-#define CBotErrStackOver 6010 // dépassement de la pile
-#define CBotErrDeletedPtr 6011 // pointeur à un objet détruit
-
-#define CBotErrFileOpen 6012 // ouverture du fichier impossible
-#define CBotErrNotOpen 6013 // canal pas ouvert
-#define CBotErrRead 6014 // erreur à la lecture
-#define CBotErrWrite 6015 // erreur à l'écriture
-
-// d'autres valeurs peuvent être rendues
-// par exemple les exceptions rendues par les routines externes
-// et les " throw " avec un nombre quelconque.
-
-
-////////////////////////////////////////////////////////////////////////
-// définie une classe pour l'utilisation des strings
-// car CString fait partie de MFC pas utilisé ici.
-//
-// ( toutes les fonctions ne sont pas encore implémentées )
-
-class CBotString
-{
-private:
- char* m_ptr; // pointeur à la chaine
- int m_lg; // longueur de la chaine
- static
- HINSTANCE m_hInstance;
-
-public:
- DllExport
- CBotString();
- DllExport
- CBotString(const char* p);
- DllExport
- CBotString(const CBotString& p);
- DllExport
- ~CBotString();
-
- DllExport
- void Empty();
- DllExport
- BOOL IsEmpty() const;
- DllExport
- int GivLength();
- DllExport
- int Find(const char c);
- DllExport
- int Find(LPCTSTR lpsz);
- DllExport
- int ReverseFind(const char c);
- DllExport
- int ReverseFind(LPCTSTR lpsz);
- DllExport
- BOOL LoadString(UINT id);
- DllExport
- CBotString Mid(int nFirst, int nCount) const;
- DllExport
- CBotString Mid(int nFirst) const;
- DllExport
- CBotString Left(int nCount) const;
- DllExport
- CBotString Right(int nCount) const;
-
- DllExport
- const CBotString&
- operator=(const CBotString& stringSrc);
- DllExport
- const CBotString&
- operator=(const char ch);
- DllExport
- const CBotString&
- operator=(const char* pString);
- DllExport
- const CBotString&
- operator+(const CBotString& str);
- DllExport
- friend CBotString
- operator+(const CBotString& string, LPCTSTR lpsz);
-
- DllExport
- const CBotString&
- operator+=(const char ch);
- DllExport
- const CBotString&
- operator+=(const CBotString& str);
- DllExport
- BOOL operator==(const CBotString& str);
- DllExport
- BOOL operator==(const char* p);
- DllExport
- BOOL operator!=(const CBotString& str);
- DllExport
- BOOL operator!=(const char* p);
- DllExport
- BOOL operator>(const CBotString& str);
- DllExport
- BOOL operator>(const char* p);
- DllExport
- BOOL operator>=(const CBotString& str);
- DllExport
- BOOL operator>=(const char* p);
- DllExport
- BOOL operator<(const CBotString& str);
- DllExport
- BOOL operator<(const char* p);
- DllExport
- BOOL operator<=(const CBotString& str);
- DllExport
- BOOL operator<=(const char* p);
-
- DllExport
- operator LPCTSTR() const; // as a C string
-
- int Compare(LPCTSTR lpsz) const;
-
- DllExport
- CBotString Mid(int start, int lg=-1);
-
- DllExport
- void MakeUpper();
- DllExport
- void MakeLower();
-};
-
-
-// idem avec la gestion en tableau
-
-class CBotStringArray : public CBotString
-{
-private:
- int m_nSize; // nombre d'éléments
- int m_nMaxSize; // taille réservée
- CBotString* m_pData; // ^aux données
-
-public:
- DllExport
- CBotStringArray();
- DllExport
- ~CBotStringArray();
- DllExport
- void SetSize(int nb);
- DllExport
- int GivSize();
- DllExport
- void Add(const CBotString& str);
- DllExport
- CBotString& operator[](int nIndex);
-
- DllExport
- CBotString& ElementAt(int nIndex);
-};
-
-// différents mode pour GetPosition
-enum CBotGet
-{
- GetPosExtern = 1,
- GetPosNom = 2,
- GetPosParam = 3,
- GetPosBloc = 4
-};
-
-////////////////////////////////////////////////////////////////////
-// classe principale gérant un programme CBot
-//
-
-class CBotProgram
-{
-private:
- CBotFunction* m_Prog; // les fonctions définies par l'utilisateur
- CBotFunction* m_pRun; // la fonction de base pour l'exécution
- CBotClass* m_pClass; // les classes définies dans cette partie
- CBotStack* m_pStack; // la pile d'exécution
- CBotVar* m_pInstance; // instance de la classe parent
- friend class CBotFunction;
-
- int m_ErrorCode;
- int m_ErrorStart;
- int m_ErrorEnd;
-
- long m_Ident; // identificateur associé
-
-public:
- static
- CBotString m_DebugVarStr; // a fin de debug
- BOOL m_bDebugDD; // idem déclanchable par robot
-
- BOOL m_bCompileClass;
-
-public:
- DllExport
- static
- void Init();
- // initialise le module (défini les mots clefs pour les erreurs)
- // doit être fait une fois (et une seule) au tout début
- DllExport
- static
- void Free();
- // libère les zones mémoires statiques
-
- DllExport
- static
- int GivVersion();
- // donne la version de la librairie CBOT
-
-
- DllExport
- CBotProgram();
- DllExport
- CBotProgram(CBotVar* pInstance);
- DllExport
- ~CBotProgram();
-
- DllExport
- BOOL Compile( const char* program, CBotStringArray& ListFonctions, void* pUser = NULL);
- // compile le programme donné en texte
- // retourne FALSE s'il y a une erreur à la compilation
- // voir GetCompileError() pour récupérer l'erreur
- // ListFonctions retourne le nom des fonctions déclarées extern
- // pUser permet de passer un pointeur pour les routines définies par AddFunction
-
- DllExport
- void SetIdent(long n);
- // associe un identificateur avec l'instance CBotProgram
-
- DllExport
- long GivIdent();
- // redonne l'identificateur
-
- DllExport
- int GivError();
- DllExport
- BOOL GetError(int& code, int& start, int& end);
- DllExport
- BOOL GetError(int& code, int& start, int& end, CBotProgram* &pProg);
- // si TRUE
- // donne l'erreur trouvée à la compilation
- // ou à l'exécution
- // start et end délimite le bloc où se trouve l'erreur
- // pProg permet de savoir dans quel "module" s'est produite l'erreur d'exécution
- DllExport
- static
- CBotString GivErrorText(int code);
-
-
- DllExport
- BOOL Start(const char* name);
- // définie quelle fonction doit être exécutée
- // retourne FALSE si la fontion name n'est pas trouvée
- // le programme ne fait rien, il faut appeller Run() pour cela
-
- DllExport
- BOOL Run(void* pUser = NULL, int timer = -1);
- // exécute le programme
- // retourne FALSE si le programme a été suspendu
- // retourne TRUE si le programme s'est terminé avec ou sans erreur
- // timer = 0 permet de faire une avance pas à pas
-
- DllExport
- BOOL GetRunPos(const char* &FunctionName, int &start, int &end);
- // donne la position dans le programme en exécution
- // retourne FALSE si on n'est pas en exécution (programme terminé)
- // FunctionName est un pointeur rendu sur le nom de la fonction
- // start et end la position dans le texte du token en traitement
-
- DllExport
- CBotVar* GivStackVars(const char* &FunctionName, int level);
- // permet d'obtenir le pointeur aux variables sur la pile d'exécution
- // level est un paramètre d'entrée, 0 pour le dernier niveau, -1, -2, etc pour les autres niveau
- // la valeur retournée (CBotVar*) est une liste de variable (ou NULL)
- // qui peut être traité que la liste des paramètres reçu par une routine
- // FunctionName donne le nom de la fonction où se trouvent ces variables
- // FunctionName == NULL signifiant qu'on est plus dans le programme (selon level)
-
- DllExport
- void Stop();
- // arrête l'exécution du programme
- // quitte donc le mode "suspendu"
-
- DllExport
- static
- void SetTimer(int n);
- // défini le nombre de pas (parties d'instructions) à faire
- // dans Run() avant de rendre la main "FALSE"
-
- DllExport
- static
- BOOL AddFunction(const char* name,
- BOOL rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
- // cet appel permet d'ajouter de manière externe (**)
- // une nouvelle fonction utilisable par le programme CBot
-
- DllExport
- static
- BOOL DefineNum(const char* name, long val);
-
- DllExport
- BOOL SaveState(FILE* pf);
- // sauvegarde l'état d'exécution dans le fichier
- // le fichier doit avoir été ouvert avec l'appel fopen de cette dll
- // sinon le système plante
- DllExport
- BOOL RestoreState(FILE* pf);
- // rétablie l'état de l'exécution depuis le fichier
- // le programme compilé doit évidemment être identique
-
- DllExport
- BOOL GetPosition(const char* name, int& start, int& stop,
- CBotGet modestart = GetPosExtern,
- CBotGet modestop = GetPosBloc);
- // donne la position d'une routine dans le texte d'origine
- // le mode permet de choisir l'élément à trouver pour le début et la fin
- // voir les modes ci-dessus dans CBotGet
-
-
- CBotFunction* GivFunctions();
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// routines pour la gestion d'un fichier (FILE*)
- DllExport
- FILE* fOpen(const char* name, const char* mode);
- DllExport
- int fClose(FILE* filehandle);
- DllExport
- size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle);
- DllExport
- size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle);
-
-
-#if 0
-/*
-(**) Note:
- Pour définir une fonction externe, il faut procéder ainsi:
-
- a) définir une routine pour la compilation
- cette routine reçois la liste des paramètres (sans valeurs)
- et retourne soit un type de résultat (CBotTyp... ou 0 = void)
- soit un numéro d'erreur
- b) définir une routine pour l'exécution
- cette rourine reCoit la liste des paramètres (avec valeurs),
- une variable pour stocker le résultat (selon le type donné à la compilation)
-
- Par exemple, une routine qui calcule la moyenne d'une liste de paramètres */
-
-int cMoyenne(CBotVar* &pVar, CBotString& ClassName)
-{
- if ( pVar == NULL ) return 6001; // il n'y a aucun paramètre !
-
- while ( pVar != NULL )
- {
- if ( pVar->GivType() > CBotTypDouble ) return 6002; // ce n'est pas un nombre
- pVar = pVar -> GivNext();
- }
-
- return CBotTypFloat; // le type du résultat pourrait dépendre des paramètres !
-}
-
-
-BOOL rMoyenne(CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- float total = 0;
- int nb = 0;
- while (pVar != NULL)
- {
- total += pVar->GivValFloat();
- pVar = pVar->GivNext();
- nb++;
- }
- pResult->SetValFloat(total/nb); // retourne la valeur moyenne
-
- return TRUE; // opération totalement terminée
-}
-
-#endif
-
-/////////////////////////////////////////////////////////////////////////////////
-// Classe pour la gestion des variables
-
-// les méthodes marquées DllExport
-// peuvent être utile à l'exterieur du module
-// ( il n'est pour l'instant pas prévu de pouvoir créer ces objets en externe )
-
-// résultats pour GivInit()
-#define IS_UNDEF 0 // variable indéfinie
-#define IS_DEF 1 // variable définie
-#define IS_NAN 999 // variable définie comme étant not a number
-
-// type de variable SetPrivate / IsPrivate
-#define PR_PUBLIC 0 // variable publique
-#define PR_READ 1 // read only
-#define PR_PROTECT 2 // protected (héritage)
-#define PR_PRIVATE 3 // strictement privée
-
-class CBotVar
-{
-protected:
- CBotToken* m_token; // le token correspondant
-
- CBotVar* m_next; // liste de variables
- friend class CBotStack;
- friend class CBotCStack;
- friend class CBotInstrCall;
- friend class CBotProgram;
-
- CBotTypResult m_type; // type de valeur
-
- int m_binit; // pas initialisée ?
- CBotVarClass* m_pMyThis; // ^élément this correspondant
- void* m_pUserPtr; // ^données user s'il y a lieu
- BOOL m_bStatic; // élément static (dans une classe)
- int m_mPrivate; // élément public, protected ou private ?
-
- CBotInstr* m_InitExpr; // expression pour le contenu initial
- CBotInstr* m_LimExpr; // liste des limites pour un tableau
- friend class CBotClass;
- friend class CBotVarClass;
- friend class CBotVarPointer;
- friend class CBotVarArray;
-
- long m_ident; // identificateur unique
- static long m_identcpt; // compteur
-
-public:
- CBotVar();
-virtual ~CBotVar( ); // destructeur
-
-
-/* DllExport
- static
- CBotVar* Create( const char* name, int type, const char* ClassName = NULL);
- // crée une variable selon son type,*/
-
- DllExport
- static
- CBotVar* Create( const char* name, CBotTypResult type);
- // idem à partir du type complet
-
- DllExport
- static
- CBotVar* Create( const char* name, CBotClass* pClass);
- // idem pour une instance d'une classe connue
-
- static
- CBotVar* Create( const CBotToken* name, int type );
- static
- CBotVar* Create( const CBotToken* name, CBotTypResult type );
-
- static
- CBotVar* Create( const char* name, int type, CBotClass* pClass);
-
- static
- CBotVar* Create( CBotVar* pVar );
-
-
- DllExport
- void SetUserPtr(void* pUser);
- // associe un pointeur utilisateur à une instance
-
- DllExport
- virtual void SetIdent(long UniqId);
- // associe un identificateur unique à une instance
- // ( c'est à l'utilisateur de s'assurer que l'id est unique)
-
- DllExport
- void* GivUserPtr();
- // rend le pointeur associé à la variable
-
- DllExport
- CBotString GivName(); // le nom de la variable, s'il est connu
- ////////////////////////////////////////////////////////////////////////////////////
- void SetName(const char* name); // change le nom de la variable
-
- DllExport
- int GivType(int mode = 0); // rend le type de base (int) de la variable
- ////////////////////////////////////////////////////////////////////////////////////////
-
- DllExport
- CBotTypResult GivTypResult(int mode = 0); // rend le type complet de la variable
-
-
- CBotToken* GivToken();
- void SetType(CBotTypResult& type);
-
- DllExport
- void SetInit(int bInit); // met la variable dans l'état IS_UNDEF, IS_DEF, IS_NAN
-
- DllExport
- int GivInit(); // donne l'état de la variable
-
- DllExport
- void SetStatic(BOOL bStatic);
- DllExport
- BOOL IsStatic();
-
- DllExport
- void SetPrivate(int mPrivate);
- DllExport
- BOOL IsPrivate(int mode = PR_PROTECT);
- DllExport
- int GivPrivate();
-
- virtual
- void ConstructorSet();
-
- void SetVal(CBotVar* var); // remprend une valeur
-
- DllExport
- virtual
- CBotVar* GivItem(const char* name); // rend un élément d'une classe selon son nom (*)
- virtual
- CBotVar* GivItemRef(int nIdent); // idem à partir du n° ref
-
- DllExport
- virtual
- CBotVar* GivItem(int row, BOOL bGrow = FALSE);
-
- DllExport
- virtual
- CBotVar* GivItemList(); // donne la liste des éléments
-
- DllExport
- CBotVar* GivStaticVar(); // rend le pointeur à la variable si elle est statique
-
- DllExport
- BOOL IsElemOfClass(const char* name);
- // dit si l'élément appartient à la classe "name"
- // rend TRUE si l'objet est d'une classe fille
-
- DllExport
- CBotVar* GivNext(); // prochaine variable dans la liste (paramètres)
- ////////////////////////////////////////////////////////////////////////////////////////////
-
- void AddNext(CBotVar* pVar); // ajoute dans une liste
-
- virtual
- void Copy(CBotVar* pSrc, BOOL bName = TRUE); // fait une copie de la variable
-
- DllExport
- virtual void SetValInt(int val, const char* name = NULL);
- // initialise avec une valeur entière (#)
- /////////////////////////////////////////////////////////////////////////////////
-
- DllExport
- virtual void SetValFloat(float val); // initialise avec une valeur réelle (#)
- ////////////////////////////////////////////////////////////////////////////////
-
- DllExport
- virtual void SetValString(const char* p);// initialise avec une valeur chaîne (#)
- ////////////////////////////////////////////////////////////////////////////////
-
- DllExport
- virtual int GivValInt(); // demande la valeur entière (#)
- ////////////////////////////////////////////////////////////////////////
-
- DllExport
- virtual float GivValFloat(); // demande la valeur réelle (#)
- ///////////////////////////////////////////////////////////////////////
-
- virtual
- CBotString GivValString(); // demande la valeur chaîne (#)
- ///////////////////////////////////////////////////////////////////////
-
- virtual void SetClass(CBotClass* pClass);
- virtual
- CBotClass* GivClass();
-
- virtual void SetPointer(CBotVar* p);
- virtual
- CBotVarClass* GivPointer();
-// virtual void SetIndirection(CBotVar* pVar);
-
- virtual void Add(CBotVar* left, CBotVar* right); // addition
- virtual void Sub(CBotVar* left, CBotVar* right); // soustraction
- virtual void Mul(CBotVar* left, CBotVar* right); // multiplication
- virtual int Div(CBotVar* left, CBotVar* right); // division
- virtual int Modulo(CBotVar* left, CBotVar* right); // reste de division
- virtual void Power(CBotVar* left, CBotVar* right); // puissance
-
- virtual BOOL Lo(CBotVar* left, CBotVar* right);
- virtual BOOL Hi(CBotVar* left, CBotVar* right);
- virtual BOOL Ls(CBotVar* left, CBotVar* right);
- virtual BOOL Hs(CBotVar* left, CBotVar* right);
- virtual BOOL Eq(CBotVar* left, CBotVar* right);
- virtual BOOL Ne(CBotVar* left, CBotVar* right);
-
- virtual void And(CBotVar* left, CBotVar* right);
- virtual void Or(CBotVar* left, CBotVar* right);
- virtual void XOr(CBotVar* left, CBotVar* right);
- virtual void ASR(CBotVar* left, CBotVar* right);
- virtual void SR(CBotVar* left, CBotVar* right);
- virtual void SL(CBotVar* left, CBotVar* right);
-
- virtual void Neg();
- virtual void Not();
- virtual void Inc();
- virtual void Dec();
-
-
- virtual BOOL Save0State(FILE* pf);
- virtual BOOL Save1State(FILE* pf);
- static BOOL RestoreState(FILE* pf, CBotVar* &pVar);
-
- DllExport
- void debug();
-
-// virtual
-// CBotVar* GivMyThis();
-
- DllExport
- virtual
- void Maj(void* pUser = NULL, BOOL bContinue = TRUE);
-
- void SetUniqNum(long n);
- long GivUniqNum();
- static long NextUniqNum();
-};
-
-/* NOTE (#)
- les méthodes SetValInt() SetValFloat() et SetValString()
- ne peuvent êtes appellées qu'avec des objets respectivement entier, réelle ou chaîne
- toujours s'assurer du type de la variable avant d'appeller ces méthodes
-
- if ( pVar->GivType() == CBotInt() ) pVar->SetValFloat( 3.3 ); // plante !!
-
- les méthodes GivValInt(), GivValFloat() et GivValString()
- font des conversions de valeur,
- GivValString() fonctionne sur des nombres (rend la chaîne correspondante)
- par contre il ne faut pas faire de GivValInt() avec une variable de type chaîne !
-*/
-
-
-
-////////////////////////////////////////////////////////////////////////
-// Gestion des classes
-////////////////////////////////////////////////////////////////////////
-
-// classe pour définir de nouvelle classes dans le language CBOT
-// par exemple pour définir la classe CPoint (x,y)
-
-class CBotClass
-{
-private:
- static
- CBotClass* m_ExClass; // liste des classes existante à un moment donné
- CBotClass* m_ExNext; // pour cette liste générale
- CBotClass* m_ExPrev; // pour cette liste générale
-
-private:
- CBotClass* m_pParent; // classe parent
- CBotString m_name; // nom de cette classe-ci
- int m_nbVar; // nombre de variables dans la chaîne
- CBotVar* m_pVar; // contenu de la classe
- BOOL m_bIntrinsic; // classe intrinsèque
- CBotClass* m_next; // chaine les classe
- CBotCallMethode* m_pCalls; // liste des méthodes définie en externe
- CBotFunction* m_pMethod; // liste des méthodes compilées
- void (*m_rMaj) ( CBotVar* pThis, void* pUser );
- friend class CBotVarClass;
- int m_cptLock; // pour Lock / UnLock
- int m_cptOne; // pour réentrance Lock
- CBotProgram* m_ProgInLock[5];// processus en attente pour synchro
-
-public:
- BOOL m_IsDef; // marque si est définie ou pas encore
-
- DllExport
- CBotClass( const char* name,
- CBotClass* pParent, BOOL bIntrinsic = FALSE ); // constructeur
- // Dès qu'une classe est créée, elle est connue
- // partout dans CBot
- // le mode intrinsic donne une classe qui n'est pas gérée par des pointeurs
-
- DllExport
- ~CBotClass( ); // destructeur
-
- DllExport
- BOOL AddFunction(const char* name,
- BOOL rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
- // cet appel permet d'ajouter de manière externe (**)
- // une nouvelle méthode utilisable par les objets de cette classe
-
- DllExport
- BOOL AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) );
- // défini la routine qui sera appellée pour mettre à jour les élements de la classe
-
- DllExport
- BOOL AddItem(CBotString name, CBotTypResult type, int mPrivate = PR_PUBLIC);
- // ajoute un élément à la classe
-// DllExport
-// BOOL AddItem(CBotString name, CBotClass* pClass);
- // idem pour des éléments appartenant à pClass
- DllExport
- BOOL AddItem(CBotVar* pVar);
- // idem en passant le pointeur à une instance d'une variable
- // l'objet est pris tel quel, il ne faut donc pas le détruire
-
-
-
- // idem en donnant un élément de type CBotVar
- void AddNext(CBotClass* pClass);
-
- DllExport
- CBotString GivName(); // rend le nom de la classe
- DllExport
- CBotClass* GivParent(); // donne la classe père (ou NULL)
-
- // dit si une classe est dérivée (Extends) d'une autre
- // rend TRUE aussi si les classes sont identiques
- DllExport
- BOOL IsChildOf(CBotClass* pClass);
-
- static
- CBotClass* Find(CBotToken* &pToken); // trouve une classe d'après son nom
-
- DllExport
- static
- CBotClass* Find(const char* name);
-
- CBotVar* GivVar(); // rend la liste des variables
- CBotVar* GivItem(const char* name); // l'une des variables selon son nom
- CBotVar* GivItemRef(int nIdent);
-
- CBotTypResult CompileMethode(const char* name, CBotVar* pThis, CBotVar** ppParams,
- CBotCStack* pStack, long& nIdent);
-
- BOOL ExecuteMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotVar* &pResult, CBotStack* &pStack, CBotToken* pToken);
- void RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotStack* &pStack);
-
- // compile une classe déclarée par l'utilisateur
- static
- CBotClass* Compile(CBotToken* &p, CBotCStack* pStack);
- static
- CBotClass* Compile1(CBotToken* &p, CBotCStack* pStack);
-
- BOOL CompileDefItem(CBotToken* &p, CBotCStack* pStack, BOOL bSecond);
-
- BOOL IsIntrinsic();
- void Purge();
- static
- void Free();
-
- DllExport
- static
- BOOL SaveStaticState(FILE* pf);
-
- DllExport
- static
- BOOL RestoreStaticState(FILE* pf);
-
- BOOL Lock(CBotProgram* p);
- void Unlock();
- static
- void FreeLock(CBotProgram* p);
-
- BOOL CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
-
-};
-
-#define MAXDEFNUM 1000 // nombre limite des DefineNum
-
-/////////////////////////////////////////////////////////////////////////////////////
-// gestion des jetons (tokens)
-
-#define TokenTypKeyWord 1 // un mot clef du language (voir TokenKeyWord)
-#define TokenTypNum 2 // un nombre
-#define TokenTypString 3 // une chaine
-#define TokenTypVar 4 // un nom de variable
-#define TokenTypDef 5 // une valeur selon DefineNum
-
-#define TokenKeyWord 2000 // les mots clefs du langage
-#define TokenKeyDeclare 2100 // mots clefs pour déclarations (int, float,..)
-#define TokenKeyVal 2200 // les mots représentant une "valeur" (true, false, null, nan)
-#define TokenKeyOp 2300 // les opérateurs
-
-
-class CBotToken
-{
-private:
- static
- CBotStringArray m_ListKeyWords; // liste des mots clefs du language
- static
- int m_ListIdKeyWords[200]; // les codes correspondants
-
- static
- CBotStringArray m_ListKeyDefine; // les noms définis par un DefineNum
- static
- long m_ListKeyNums[MAXDEFNUM]; // les valeurs associées
-
-private:
- CBotToken* m_next; // suivant dans la liste
- CBotToken* m_prev;
- int m_type; // type de Token
- long m_IdKeyWord; // numéro du mot clef si c'en est un
- // ou valeur du "define"
-
- CBotString m_Text; // mot trouvé comme token
- CBotString m_Sep; // séparateurs qui suivent
-
- int m_start; // position dans le texte d'origine (programme)
- int m_end; // itou pour la fin du token
-
- static
- int GivKeyWords(const char* w); // est-ce un mot clef ?
- static
- BOOL GivKeyDefNum(const char* w, CBotToken* &token);
-
- static
- void LoadKeyWords(); // fait la liste des mots clefs
-
-public:
- CBotToken();
- CBotToken(const CBotToken* pSrc);
- CBotToken(const CBotString& mot, const CBotString& sep, int start=0, int end=0);
- CBotToken(const char* mot, const char* sep = NULL);
- // constructeur
- ~CBotToken(); // destructeur
-
- DllExport
- int GivType(); // rend le type du token
-
- DllExport
- CBotString& GivString(); // rend la chaine correspondant à ce token
-
- DllExport
- CBotString& GivSep(); // rend le séparateur suivant le token
-
- DllExport
- int GivStart(); // position du début dans le texte
- DllExport
- int GivEnd(); // position de fin dans le texte
-
- DllExport
- CBotToken* GivNext(); // rend le suivant dans la liste
- DllExport
- CBotToken* GivPrev(); // rend le Précédent dans la liste
-
- DllExport
- static
- CBotToken* CompileTokens(const char* p, int& error);
- // transforme tout le programme
- DllExport
- static
- void Delete(CBotToken* pToken); // libère la liste
-
-
- // fonctions non utiles en export
- static
- BOOL DefineNum(const char* name, long val);
- void SetString(const char* name);
-
- void SetPos(int start, int end);
- long GivIdKey();
- void AddNext(CBotToken* p); // ajoute un token (une copie)
-
- static
- CBotToken* NextToken(char* &program, int& error, BOOL first = FALSE);
- // trouve le prochain token
- const CBotToken&
- operator=(const CBotToken& src);
-
- static
- void Free();
-};
-
-
-
-#if 0
-////////////////////////////////////////////////////////////////////////
-// Exemples d'utilisation
-// Définition de classes et de fonctions
-
-
-// définie la classe globale CPoint
-// --------------------------------
- m_pClassPoint = new CBotClass("CPoint", NULL);
- // ajoute le composant ".x"
- m_pClassPoint->AddItem("x", CBotTypResult(CBotTypFloat));
- // ajoute le composant ".y"
- m_pClassPoint->AddItem("y", CBotTypResult(CBotTypFloat));
- // le joueur peut alors utiliser les instructions
- // CPoint position; position.x = 12; position.y = -13.6
-
-// définie la classe CColobotObject
-// --------------------------------
-// cette classe gère tous les objets dans le monde de COLOBOT
-// le programme utilisateur "main" appartient à cette classe
- m_pClassObject = new CBotClass("CColobotObject", m_pClassBase);
- // ajoute le composant ".position"
- m_pClassObject->AddItem("position", m_pClassPoint);
- // ajoute le composant ".type"
- m_pClassObject->AddItem("type", CBotTypResult(CBotTypShort));
- // ajoute une définition de constante
- m_pClassObject->AddConst("ROBOT", CBotTypShort, 1); // ROBOT équivalent à la valeur 1
- // ajoute la routine FIND
- m_pClassObject->AddFunction( rCompFind, rDoFind );
- // le joueur peut maintenant utiliser les instructions
- // CColobotObject chose; chose = FIND( ROBOT )
-
-
-
-// définie la classe CColobotRobot dérivée de CColobotObject
-// ---------------------------------------------------------
-// les programmes "main" associés aux robots font partie de cette classe
- m_pClassRobot = new CBotClass("CColobotRobot", m_pClassObject);
- // ajoute la routine GOTO
- m_pClassRobot->AddFunction( rCompGoto, rDoGoto );
- // le joueur peut maintenant faire
- // GOTO( FIND ( ROBOT ) );
-
-
-// crée une instance de la classe Robot
-// ------------------------------------
-// par exemple un nouveau robot qui vient d'être fabriqué
- CBotVar* m_pMonRobot = new CBotVar("MonRobot", m_pClassRobot);
-
-// compile le programme main pour ce robot-là
-// ------------------------------------------
- CString LeProgramme( "void main() {GOTO(0, 0); return 0;}" );
- if ( !m_pMonRobot->Compile( LeProgramme ) ) {gestion d'erreur...};
-
-// construit une pile pour l'interpréteur
-// --------------------------------------
- CBotStack* pStack = new CBotStack(NULL);
-
-// exécute le programme main
-// -------------------------
- while( FALSE = m_pMonRobot->Execute( "main", pStack ))
- {
- // programme suspendu
- // on pourrait passer la main à un autre (en sauvegardant pStack pour ce robot-là)
- };
- // programme "main" terminé !
-
-
-
-
-// routine implémentant l'instruction GOTO( CPoint pos )
-BOOL rDoGoto( CBotVar* pVar, CBotVar* pResult, int& exception )
-{
- if (pVar->GivType() != CBotTypeClass ||
- pVar->IsElemOfClas("CPoint") ) { exception = 6522; return FALSE; )
- // le paramètre n'est pas de la bonne classe ?
- // NB en fait ce contrôle est déjà fait par la routine pour la compilation
-
- m_PosToGo.Copy( pVar ); // garde la position à atteindre (object type CBotVar)
-
- // ou alors
- CBotVar* temp;
- temp = pVar->GivItem("x"); // trouve forcément pour un object de type "CPoint"
- ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
- m_PosToGo.x = temp->GivValFloat();
-
- temp = pVar->GivItem("y"); // trouve forcément pour un object de type "CPoint"
- ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
- m_PosToGo.y = temp->GivValFloat();
-
- return (m_CurentPos == m_PosToGo); // rend TRUE si la position est atteinte
- // rend FALSE s'il faut patienter encore
-}
-
-#endif \ No newline at end of file
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+////////////////////////////////////////////////////////////////////////
+
+#pragma once
+#ifndef _CBOTDLL_H_
+#define _CBOTDLL_H_
+/**
+ * \file CBotDll.h
+ * \brief Library for interpretation of CBOT language
+ */
+
+#include <stdio.h>
+#include "resource.h"
+#include <map>
+#include <cstring>
+
+
+#define CBOTVERSION 104
+
+////////////////////////////////////////////////////////////////////////
+// forward declaration of needed classes
+
+class CBotToken; // program turned into "tokens
+class CBotStack; // for the execution stack
+class CBotClass; // class of object
+class CBotInstr; // instruction to be executed
+class CBotFunction; // user functions
+class CBotVar; // variables
+class CBotVarClass; // instance of class
+class CBotVarPointer; // pointer to an instance of class
+class CBotCall; // functions
+class CBotCallMethode; // methods
+class CBotDefParam; // parameter list
+class CBotCStack; // stack
+
+
+////////////////////////////////////////////////////////////////////////
+// Variables management
+////////////////////////////////////////////////////////////////////////
+
+/** \brief CBotType Defines known types. This types are modeled on Java types. Do not change the order of elements */
+enum CBotType
+{
+ CBotTypVoid = 0,
+ CBotTypByte = 1, //n
+ CBotTypShort = 2, //n
+ CBotTypChar = 3, //n
+ CBotTypInt = 4,
+ CBotTypLong = 5, //n
+ CBotTypFloat = 6,
+ CBotTypDouble = 7, //n
+ CBotTypBoolean = 8,
+ CBotTypString = 9,
+
+ CBotTypArrayPointer = 10, // array of variables
+ CBotTypArrayBody = 11, // same but creates an instance
+
+ CBotTypPointer = 12, // pointer to an instance
+ CBotTypNullPointer = 13, // null pointer is special
+ CBotTypClass = 15,
+ CBotTypIntrinsic = 16 // instance of a class intrinsic
+};
+//n = not implemented yet
+
+// for SetUserPtr when deleting an object
+#define OBJECTDELETED ((void*)-1)
+// value set before initialization
+#define OBJECTCREATED ((void*)-2)
+
+
+/** \brief CBotTypResult class to define the complete type of a result*/
+class CBotTypResult
+{
+public:
+ /**
+ * \brief CBotTypResult constructor for simple types (CBotTypInt to CBotTypString)
+ * \param type type of created result, see CBotType
+ */
+ CBotTypResult(int type);
+ // for simple types (CBotTypInt à CBotTypString)
+
+
+ CBotTypResult(int type, const char* name);
+ // for pointer types and intrinsic classes
+
+ CBotTypResult(int type, CBotClass* pClass);
+ // for the instance of a class
+
+ CBotTypResult(int type, CBotTypResult elem);
+ // for arrays of variables
+
+ CBotTypResult(const CBotTypResult& typ);
+ // for assignments
+
+ CBotTypResult();
+ // for default
+
+ ~CBotTypResult();
+
+ int GivType(int mode = 0) const;
+ // returns type CBotType* as a result
+
+ void SetType(int n);
+ // modifies a type
+
+ CBotClass* GivClass() const;
+ // makes the pointer to the class (for CBotTypClass, CBotTypPointer)
+
+ int GivLimite() const;
+ // returns limit size of table (CBotTypArray)
+
+ void SetLimite(int n);
+ // set limit to the table
+
+ void SetArray(int* max );
+ // set limits for a list of dimensions (arrays of arrays)
+
+ CBotTypResult& GivTypElem() const;
+ // returns type of array elements (CBotTypArray)
+ // rend le type des éléments du tableau (CBotTypArray)
+
+ bool Compare(const CBotTypResult& typ) const;
+ // compares whether the types are compatible
+ bool Eq(int type) const;
+ // compare type
+
+ CBotTypResult& operator=(const CBotTypResult& src);
+ // copy a complete type in another
+
+private:
+ int m_type;
+ CBotTypResult* m_pNext; // for the types of type
+ CBotClass* m_pClass; // for the derivatives of class
+ int m_limite; // limits of tables
+ friend class CBotVarClass;
+ friend class CBotVarPointer;
+};
+
+/*
+// to define a result as output, using for example
+
+ // to return a simple Float
+ return CBotTypResult( CBotTypFloat );
+
+
+ // to return a string array
+ return CBotTypResult( CBotTypArray, CBotTypResult( CBotTypString ) );
+
+ // to return un array of array of "point" class
+ CBotTypResult typPoint( CBotTypIntrinsic, "point" );
+ CBotTypResult arrPoint( CBotTypArray, typPoint );
+ return CBotTypResult( CBotTypArray, arrPoint );
+*/
+
+
+////////////////////////////////////////////////////////////////////////
+// Error Handling of compilation and execution
+////////////////////////////////////////////////////////////////////////
+
+// Here are the list of errors that can be returned by the module
+// for compilation
+
+#define CBotErrOpenPar 5000 // missing the opening parenthesis
+#define CBotErrClosePar 5001 // missing the closing parenthesis
+#define CBotErrNotBoolean 5002 // expression must be a boolean
+#define CBotErrUndefVar 5003 // undeclared variable
+#define CBotErrBadLeft 5004 // assignment impossible ( 5 = ... )
+#define CBotErrNoTerminator 5005 // semicolon expected
+#define CBotErrCaseOut 5006 // case outside a switch
+// CBotErrNoTerm 5007, plus utile
+#define CBotErrCloseBlock 5008 // missing " } "
+#define CBotErrElseWhitoutIf 5009 // else without matching if
+#define CBotErrOpenBlock 5010 // missing " { "
+#define CBotErrBadType1 5011 // wrong type for the assignment
+#define CBotErrRedefVar 5012 // redefinition of the variable
+#define CBotErrBadType2 5013 // Two operands are incompatible
+#define CBotErrUndefCall 5014 // routine undefined
+#define CBotErrNoDoubleDots 5015 // " : " expected
+// CBotErrWhile 5016, plus utile
+#define CBotErrBreakOutside 5017 // break outside of a loop
+#define CBotErrUndefLabel 5019 // label udnefined
+#define CBotErrLabel 5018 // label ne peut se mettre ici (label can not get here)
+#define CBotErrNoCase 5020 // missing " case "
+#define CBotErrBadNum 5021 // expected number
+#define CBotErrVoid 5022 // " void " not possible here
+#define CBotErrNoType 5023 // type declaration expected
+#define CBotErrNoVar 5024 // variable name expected
+#define CBotErrNoFunc 5025 // expected function name
+#define CBotErrOverParam 5026 // too many parameters
+#define CBotErrRedefFunc 5027 // this function already exists
+#define CBotErrLowParam 5028 // not enough parameters
+#define CBotErrBadParam 5029 // wrong types of parameters
+#define CBotErrNbParam 5030 // wrong number of parameters
+#define CBotErrUndefItem 5031 // element does not exist in the class
+#define CBotErrUndefClass 5032 // variable is not a class
+#define CBotErrNoConstruct 5033 // no appropriate constructor
+#define CBotErrRedefClass 5034 // class already exists
+#define CBotErrCloseIndex 5035 // " ] " expected
+#define CBotErrReserved 5036 // reserved word (for a DefineNum)
+#define CBotErrBadNew 5037 // wrong setting for new
+#define CBotErrOpenIndex 5038 // " [ " expected
+#define CBotErrBadString 5039 // expected string
+#define CBotErrBadIndex 5040 // wrong index type "[ false ]"
+#define CBotErrPrivate 5041 // protected item
+#define CBotErrNoPublic 5042 // missing word "public"
+
+// here is the list of errors that can be returned by the module
+// for the execution
+
+#define CBotErrZeroDiv 6000 // division by zero
+#define CBotErrNotInit 6001 // uninitialized variable
+#define CBotErrBadThrow 6002 // throw a negative value
+#define CBotErrNoRetVal 6003 // function did not return results
+#define CBotErrNoRun 6004 // Run() without active function
+#define CBotErrUndefFunc 6005 // calling a function that no longer exists
+#define CBotErrNotClass 6006 // this class does not exist
+#define CBotErrNull 6007 // null pointer
+#define CBotErrNan 6008 // calculation with a NAN
+#define CBotErrOutArray 6009 // index out of array
+#define CBotErrStackOver 6010 // stack overflow
+#define CBotErrDeletedPtr 6011 // pointer to an object destroyed
+
+#define CBotErrFileOpen 6012 // cannot open the file
+#define CBotErrNotOpen 6013 // channel not open
+#define CBotErrRead 6014 // error while reading
+#define CBotErrWrite 6015 // writing error
+
+
+// other values ​​may be returned
+// for example exceptions returned by external routines
+// and " throw " with any number.
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// as part of MFC CString not used here.
+//
+// ( all functions are not implemented yet )
+
+/** \brief CBotString Class used to work on strings */
+class CBotString
+{
+public:
+ CBotString();
+ CBotString(const char* p);
+ CBotString(const CBotString& p);
+ ~CBotString();
+
+ void Empty();
+ bool IsEmpty() const;
+ int GivLength();
+ int Find(const char c);
+ int Find(const char* lpsz);
+ int ReverseFind(const char c);
+ int ReverseFind(const char* lpsz);
+ bool LoadString(unsigned int id);
+ CBotString Mid(int nFirst, int nCount) const;
+ CBotString Mid(int nFirst) const;
+ CBotString Mid(int start, int lg=-1);
+ CBotString Left(int nCount) const;
+ CBotString Right(int nCount) const;
+ int Compare(const char* lpsz) const;
+ void MakeUpper();
+ void MakeLower();
+
+
+ /**
+ * \brief Overloaded oprators to work on CBotString classes
+ */
+ const CBotString& operator=(const CBotString& stringSrc);
+ const CBotString& operator=(const char ch);
+ const CBotString& operator=(const char* pString);
+ const CBotString& operator+(const CBotString& str);
+ friend CBotString operator+(const CBotString& string, const char* lpsz);
+
+ const CBotString& operator+=(const char ch);
+ const CBotString& operator+=(const CBotString& str);
+ bool operator==(const CBotString& str);
+ bool operator==(const char* p);
+ bool operator!=(const CBotString& str);
+ bool operator!=(const char* p);
+ bool operator>(const CBotString& str);
+ bool operator>(const char* p);
+ bool operator>=(const CBotString& str);
+ bool operator>=(const char* p);
+ bool operator<(const CBotString& str);
+ bool operator<(const char* p);
+ bool operator<=(const CBotString& str);
+ bool operator<=(const char* p);
+
+ operator const char*() const; // as a C string
+
+
+private:
+
+ /** \brief Pointer to string */
+ char* m_ptr;
+
+ /** \brief Length of the string */
+ int m_lg;
+
+ /** \brief Keeps the string corresponding to keyword ID */
+ static const std::map<EID, char *> s_keywordString;
+
+ /**
+ * \brief MapIdToString maps given ID to its string equivalent
+ * \param id Provided identifier
+ * \return string if found, else NullString
+ */
+ static const char * MapIdToString(EID id);
+};
+
+
+// Class used to array management
+
+class CBotStringArray : public CBotString
+{
+private:
+ int m_nSize; // number of elements
+ int m_nMaxSize; // reserved size
+ CBotString* m_pData; // ^data
+
+public:
+ CBotStringArray();
+ ~CBotStringArray();
+ void SetSize(int nb);
+ int GivSize();
+ void Add(const CBotString& str);
+ CBotString& operator[](int nIndex);
+
+ CBotString& ElementAt(int nIndex);
+};
+
+// different modes for GetPosition
+enum CBotGet
+{
+ GetPosExtern = 1,
+ GetPosNom = 2,
+ GetPosParam = 3,
+ GetPosBloc = 4
+};
+
+////////////////////////////////////////////////////////////////////
+// main class managing CBot program
+//
+
+class CBotProgram
+{
+private:
+ CBotFunction* m_Prog; // the user-defined functions
+ CBotFunction* m_pRun; // the basic function for the execution
+ CBotClass* m_pClass; // classes defined in this part
+ CBotStack* m_pStack; // execution stack
+ CBotVar* m_pInstance; // instance of the parent class
+ friend class CBotFunction;
+
+ int m_ErrorCode;
+ int m_ErrorStart;
+ int m_ErrorEnd;
+
+ long m_Ident; // associated identifier
+
+public:
+ static CBotString m_DebugVarStr; // end of a debug
+ bool m_bDebugDD; // idem déclanchable par robot \TODO ???
+ bool m_bCompileClass;
+
+public:
+ static void Init();
+ // initializes the module (defined keywords for errors)
+ // should be done once (and only one) at the beginning
+ static
+ void Free();
+ // frees the static memory areas
+
+ static
+ int GivVersion();
+ // gives the version of the library CBOT
+
+
+ CBotProgram();
+ CBotProgram(CBotVar* pInstance);
+ ~CBotProgram();
+
+ bool Compile( const char* program, CBotStringArray& ListFonctions, void* pUser = NULL);
+ // compiles the program given in text
+ // returns false if an error at compile
+ // see GetCompileError () to retrieve the error
+ // ListFonctions returns the names of functions declared as extern
+ // pUser can pass a pointer to routines defined by AddFunction
+
+ void SetIdent(long n);
+ // associates an identifier with the instance CBotProgram
+
+ long GivIdent();
+ // gives the identifier
+
+ int GivError();
+ bool GetError(int& code, int& start, int& end);
+ bool GetError(int& code, int& start, int& end, CBotProgram* &pProg);
+ // if true
+ // gives the error found in the compilation
+ // or execution
+ // delimits the start and end block where the error
+ // pProg lets you know what "module" has produced runtime error
+ static CBotString GivErrorText(int code);
+
+
+ bool Start(const char* name);
+ // defines what function should be executed
+ // returns false if the funtion name is not found
+ // the program does nothing, we must call Run () for this
+
+ bool Run(void* pUser = NULL, int timer = -1);
+ // executes the program
+ // returns false if the program was suspended
+ // returns true if the program ended with or without error
+ // timer = 0 allows to advance step by step
+
+ bool GetRunPos(const char* &FunctionName, int &start, int &end);
+ // gives the position in the executing program
+ // returns false if it is not running (program completion)
+ // FunctionName is a pointer made to the name of the function
+ // start and end position in the text of the token processing
+
+ CBotVar* GivStackVars(const char* &FunctionName, int level);
+ // provides the pointer to the variables on the execution stack
+ // level is an input parameter, 0 for the last level, -1, -2, etc. for the other levels
+ // the return value (CBotVar *) is a variable list (or NULL)
+ // that can be processed as the list of parameters received by a routine
+ // FunctionName gives the name of the function where are these variables
+ // FunctionName == NULL means that is more in a program (depending on level)
+
+ void Stop();
+ // stops execution of the program
+ // therefore quits "suspend" mode
+
+ static
+ void SetTimer(int n);
+ // defines the number of steps (parts of instructions) to done
+ // in Run() before rendering hand "false" \TODO avant de rendre la main "false"
+
+ static
+ bool AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser));
+ // call this to add externally (**)
+ // a new function used by the program CBoT
+
+ static
+ bool DefineNum(const char* name, long val);
+
+ bool SaveState(FILE* pf);
+ // backup the execution status in the file
+ // the file must have been opened with the fopen call this dll (\TODO this library??)
+ // if the system crashes
+ bool RestoreState(FILE* pf);
+ // restores the state of execution from file
+ // the compiled program must obviously be the same
+
+ bool GetPosition(const char* name, int& start, int& stop,
+ CBotGet modestart = GetPosExtern,
+ CBotGet modestop = GetPosBloc);
+ // gives the position of a routine in the original text
+ // the user can select the item to find from the beginning to the end
+ // see the above modes in CBotGet
+
+
+ CBotFunction* GivFunctions();
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// routines for file management (* FILE)
+ FILE* fOpen(const char* name, const char* mode);
+ int fClose(FILE* filehandle);
+ size_t fWrite(const void *buffer, size_t elemsize, size_t length, FILE* filehandle);
+ size_t fRead(void *buffer, size_t elemsize, size_t length, FILE* filehandle);
+
+
+#if 0
+/*
+(**) Note:
+ To define an external function, proceed as follows:
+
+ a) define a routine for compilation
+ this routine receive list of parameters (no values)
+ and either returns a result type (CBotTyp... or 0 = void)
+ or an error number
+ b) define a routine for the execution
+ this routine receive list of parameters (with valeurs),
+ a variable to store the result (according to the given type at compile time)
+
+ For example, a routine which calculates the mean of a parameter list */
+
+int cMean(CBotVar* &pVar, CBotString& ClassName)
+{
+ if ( pVar == NULL ) return 6001; // there is no parameter!
+
+ while ( pVar != NULL )
+ {
+ if ( pVar->GivType() > CBotTypDouble ) return 6002; // this is not a number
+ pVar = pVar -> GivNext();
+ }
+
+ return CBotTypFloat; // the type of the result may depend on the parameters!
+}
+
+
+bool rMean(CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ float total = 0;
+ int nb = 0;
+ while (pVar != NULL)
+ {
+ total += pVar->GivValFloat();
+ pVar = pVar->GivNext();
+ nb++;
+ }
+ pResult->SetValFloat(total/nb); // returns the mean value
+
+ return true; // operation fully completed
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////
+// Class for managing variables
+
+// may be useful to the outside of the module
+// ( it is currently not expected to be able to create these objects in outer )
+
+// results of GivInit()
+#define IS_UNDEF 0 // undefined variable
+#define IS_DEF 1 // variable defined
+#define IS_NAN 999 // variable defined as not a number
+
+// variable type SetPrivate / IsPrivate
+#define PR_PUBLIC 0 // public variable
+#define PR_READ 1 // read only
+#define PR_PROTECT 2 // protected (inheritance)
+#define PR_PRIVATE 3 // strictly private
+
+class CBotVar
+{
+protected:
+ CBotToken* m_token; // the corresponding token
+
+ CBotVar* m_next; // list of variables
+ friend class CBotStack;
+ friend class CBotCStack;
+ friend class CBotInstrCall;
+ friend class CBotProgram;
+
+ CBotTypResult m_type; // type of value
+
+ int m_binit; // not initialized?
+ CBotVarClass* m_pMyThis; // ^ corresponding this element
+ void* m_pUserPtr; // ^user data if necessary
+ bool m_bStatic; // static element (in class)
+ int m_mPrivate; // element public, protected or private?
+
+ CBotInstr* m_InitExpr; // expression for the original content
+ CBotInstr* m_LimExpr; // list of limits for a table
+ friend class CBotClass;
+ friend class CBotVarClass;
+ friend class CBotVarPointer;
+ friend class CBotVarArray;
+
+ long m_ident; // unique identifier
+ static long m_identcpt; // counter
+
+public:
+ CBotVar();
+virtual ~CBotVar( ); // destructor
+
+ static
+ CBotVar* Create( const char* name, CBotTypResult type);
+ // creates from a complete type
+
+ static
+ CBotVar* Create( const char* name, CBotClass* pClass);
+ // creates from one instance of a known class
+
+ static
+ CBotVar* Create( const CBotToken* name, int type );
+ static
+ CBotVar* Create( const CBotToken* name, CBotTypResult type );
+
+ static
+ CBotVar* Create( const char* name, int type, CBotClass* pClass);
+
+ static
+ CBotVar* Create( CBotVar* pVar );
+
+
+ void SetUserPtr(void* pUser);
+ // associate a user pointer to an instance
+
+ virtual void SetIdent(long UniqId);
+ // associates a unique identifier to an instance
+ // ( it is used to ensure that the id is unique)
+
+ void* GivUserPtr();
+ // makes the pointer associated with the variable
+
+ CBotString GivName(); // the name of the variable, if known
+ ////////////////////////////////////////////////////////////////////////////////////
+ void SetName(const char* name); // changes the name of the variable
+
+ int GivType(int mode = 0); // returns the base type (int) of the variable
+ // TODO check it
+ ////////////////////////////////////////////////////////////////////////////////////////
+
+ CBotTypResult GivTypResult(int mode = 0); // returns the complete type of the variable
+
+
+ CBotToken* GivToken();
+ void SetType(CBotTypResult& type);
+
+ void SetInit(int bInit); // is the variable in the state IS_UNDEF, IS_DEF, IS_NAN
+
+ int GivInit(); // gives the state of the variable
+
+ void SetStatic(bool bStatic);
+ bool IsStatic();
+
+ void SetPrivate(int mPrivate);
+ bool IsPrivate(int mode = PR_PROTECT);
+ int GivPrivate();
+
+ virtual
+ void ConstructorSet();
+
+ void SetVal(CBotVar* var); // remprend une valeur
+ // TODO remprend value
+ virtual
+ CBotVar* GivItem(const char* name); // returns an element of a class according to its name (*)
+ virtual
+ CBotVar* GivItemRef(int nIdent); // idem à partir du n° ref
+ // TODO ditto from ref no.
+ virtual
+ CBotVar* GivItem(int row, bool bGrow = false);
+
+ virtual
+ CBotVar* GivItemList(); // lists the elements
+
+ CBotVar* GivStaticVar(); // makes the pointer to the variable if it is static
+
+ bool IsElemOfClass(const char* name);
+ // said if the element belongs to the class "name"
+ // makes true if the object is a subclass
+
+ CBotVar* GivNext(); // next variable in the list (parameters)
+ ////////////////////////////////////////////////////////////////////////////////////////////
+
+ void AddNext(CBotVar* pVar); // added to a list
+
+ virtual
+ void Copy(CBotVar* pSrc, bool bName = true); // makes a copy of the variable
+
+ virtual void SetValInt(int val, const char* name = NULL);
+ // initialized with an integer value (#)
+ /////////////////////////////////////////////////////////////////////////////////
+
+ virtual void SetValFloat(float val); // initialized with a real value (#)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ virtual void SetValString(const char* p);// initialized with a string value (#)
+ ////////////////////////////////////////////////////////////////////////////////
+
+ virtual int GivValInt(); // request the full value (#)
+ ////////////////////////////////////////////////////////////////////////
+
+ virtual float GivValFloat(); // gets real value (#)
+ ///////////////////////////////////////////////////////////////////////
+
+ virtual
+ CBotString GivValString(); // request the string value (#)
+ ///////////////////////////////////////////////////////////////////////
+
+ virtual void SetClass(CBotClass* pClass);
+ virtual
+ CBotClass* GivClass();
+
+ virtual void SetPointer(CBotVar* p);
+ virtual
+ CBotVarClass* GivPointer();
+// virtual void SetIndirection(CBotVar* pVar);
+
+ virtual void Add(CBotVar* left, CBotVar* right); // addition
+ virtual void Sub(CBotVar* left, CBotVar* right); // subtraction
+ virtual void Mul(CBotVar* left, CBotVar* right); // multiplication
+ virtual int Div(CBotVar* left, CBotVar* right); // division
+ virtual int Modulo(CBotVar* left, CBotVar* right); // remainder of division
+ virtual void Power(CBotVar* left, CBotVar* right); // power
+
+ virtual bool Lo(CBotVar* left, CBotVar* right);
+ virtual bool Hi(CBotVar* left, CBotVar* right);
+ virtual bool Ls(CBotVar* left, CBotVar* right);
+ virtual bool Hs(CBotVar* left, CBotVar* right);
+ virtual bool Eq(CBotVar* left, CBotVar* right);
+ virtual bool Ne(CBotVar* left, CBotVar* right);
+
+ virtual void And(CBotVar* left, CBotVar* right);
+ virtual void Or(CBotVar* left, CBotVar* right);
+ virtual void XOr(CBotVar* left, CBotVar* right);
+ virtual void ASR(CBotVar* left, CBotVar* right);
+ virtual void SR(CBotVar* left, CBotVar* right);
+ virtual void SL(CBotVar* left, CBotVar* right);
+
+ virtual void Neg();
+ virtual void Not();
+ virtual void Inc();
+ virtual void Dec();
+
+
+ virtual bool Save0State(FILE* pf);
+ virtual bool Save1State(FILE* pf);
+ static bool RestoreState(FILE* pf, CBotVar* &pVar);
+
+ void debug();
+
+// virtual
+// CBotVar* GivMyThis();
+
+ virtual
+ void Maj(void* pUser = NULL, bool bContinue = true);
+
+ void SetUniqNum(long n);
+ long GivUniqNum();
+ static long NextUniqNum();
+};
+
+/* NOTE (#)
+ methods SetValInt() SetValFloat() et SetValString()
+ can be called with objects which are respectively integer, real or string
+ Always be sure of the type of the variable before calling these methods
+
+ if ( pVar->GivType() == CBotInt() ) pVar->SetValFloat( 3.3 ); // plante !!
+
+ methods GivValInt(), GivValFloat() et GivValString()
+ use value conversions,
+ GivValString() works on numbers (makes the corresponding string)
+ but do not make GivValInt () with a string variable!
+*/
+
+
+
+////////////////////////////////////////////////////////////////////////
+// management of classes
+////////////////////////////////////////////////////////////////////////
+
+// class to define new classes in the language CBOT
+// for example to define the class CPoint (x, y)
+
+class CBotClass
+{
+private:
+ static
+ CBotClass* m_ExClass; // list of classes existing at a given time
+ CBotClass* m_ExNext; // for this general list
+ CBotClass* m_ExPrev; // for this general list
+
+private:
+ CBotClass* m_pParent; // parent class
+ CBotString m_name; // name of this class
+ int m_nbVar; // number of variables in the chain
+ CBotVar* m_pVar; // content of the class
+ bool m_bIntrinsic; // intrinsic class
+ CBotClass* m_next; // the string class
+ CBotCallMethode* m_pCalls; // list of methods defined in external
+ CBotFunction* m_pMethod; // compiled list of methods
+ void (*m_rMaj) ( CBotVar* pThis, void* pUser );
+ friend class CBotVarClass;
+ int m_cptLock; // for Lock / UnLock
+ int m_cptOne; // Lock for reentrancy
+ CBotProgram* m_ProgInLock[5];// processes waiting for sync
+
+public:
+ bool m_IsDef; // mark if is set or not
+
+ CBotClass( const char* name,
+ CBotClass* pParent, bool bIntrinsic = false ); // constructor
+ // Once a class is created, it is known
+ // around CBoT
+ // intrinsic mode gives a class that is not managed by pointers
+
+ ~CBotClass( ); // destructor
+
+ bool AddFunction(const char* name,
+ bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
+ CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar));
+ // this call allows to add as external (**)
+ // new method used by the objects of this class
+
+ bool AddUpdateFunc( void rMaj ( CBotVar* pThis, void* pUser ) );
+ // defines routine to be called to update the elements of the class
+
+ bool AddItem(CBotString name, CBotTypResult type, int mPrivate = PR_PUBLIC);
+ // adds an element to the class
+// bool AddItem(CBotString name, CBotClass* pClass);
+ // the same for elements belonging to pClass
+ bool AddItem(CBotVar* pVar);
+ // adds an item by passing the pointer to an instance of a variable
+ // the object is taken as is, so do not destroyed
+
+
+
+ // adds an element by giving an element of type CBotVar
+ void AddNext(CBotClass* pClass);
+
+ CBotString GivName(); // gives the name of the class
+ CBotClass* GivParent(); // gives the parent class (or NULL)
+
+ // true if a class is derived (Extends) of another
+ // return true also if the classes are identical
+ bool IsChildOf(CBotClass* pClass);
+
+ static
+ CBotClass* Find(CBotToken* &pToken); // trouve une classe d'après son nom
+ // return a class by it's its name
+ static
+ CBotClass* Find(const char* name);
+
+ CBotVar* GivVar(); // return the list of variables
+ CBotVar* GivItem(const char* name); // one of the variables according to its name
+ CBotVar* GivItemRef(int nIdent);
+
+ CBotTypResult CompileMethode(const char* name, CBotVar* pThis, CBotVar** ppParams,
+ CBotCStack* pStack, long& nIdent);
+
+ bool ExecuteMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotVar* &pResult, CBotStack* &pStack, CBotToken* pToken);
+ void RestoreMethode(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppParams, CBotStack* &pStack);
+
+ // compiles a class declared by the user
+ static
+ CBotClass* Compile(CBotToken* &p, CBotCStack* pStack);
+ static
+ CBotClass* Compile1(CBotToken* &p, CBotCStack* pStack);
+
+ bool CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond);
+
+ bool IsIntrinsic();
+ void Purge();
+ static
+ void Free();
+
+ static
+ bool SaveStaticState(FILE* pf);
+
+ static
+ bool RestoreStaticState(FILE* pf);
+
+ bool Lock(CBotProgram* p);
+ void Unlock();
+ static
+ void FreeLock(CBotProgram* p);
+
+ bool CheckCall(CBotToken* &pToken, CBotDefParam* pParam);
+
+};
+
+#define MAXDEFNUM 1000 // limited number of DefineNum
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Token management (tokens)
+
+#define TokenTypKeyWord 1 // a keyword of the language (see TokenKeyWord)
+#define TokenTypNum 2 // number
+#define TokenTypString 3 // string
+#define TokenTypVar 4 // a variable name
+#define TokenTypDef 5 // value according DefineNum
+
+#define TokenKeyWord 2000 // keywords of the language
+#define TokenKeyDeclare 2100 // keywords of declarations (int, float,..)
+#define TokenKeyVal 2200 // keywords representing the value (true, false, null, nan)
+#define TokenKeyOp 2300 // operators
+
+/** \class Responsible for token management */
+class CBotToken
+{
+private:
+ static
+ CBotStringArray m_ListKeyWords; // list of keywords of language
+ static
+ int m_ListIdKeyWords[200]; // the corresponding codes
+
+ static
+ CBotStringArray m_ListKeyDefine; // names defined by a DefineNum
+ static
+ long m_ListKeyNums[MAXDEFNUM]; // the ​​associated values
+
+private:
+ CBotToken* m_next; // following in the list
+ CBotToken* m_prev;
+ int m_type; // type of Token
+ long m_IdKeyWord; // number of the keyword if it is a
+ // or value of the "define"
+
+ CBotString m_Text; // word found as token
+ CBotString m_Sep; // following separators
+
+ int m_start; // position in the original text (program)
+ int m_end; // the same for the end of the token
+
+ /**
+ * \brief Check whether given parameter is a keyword
+ */
+ static
+ int GivKeyWords(const char* w); // is it a keyword?
+ static
+ bool GivKeyDefNum(const char* w, CBotToken* &token);
+
+ /**
+ * \brief Loads the list of keywords
+ */
+ static
+ void LoadKeyWords();
+
+public:
+ /**
+ * \brief Constructors
+ */
+ CBotToken();
+ CBotToken(const CBotToken* pSrc);
+ CBotToken(const CBotString& mot, const CBotString& sep, int start=0, int end=0);
+ CBotToken(const char* mot, const char* sep = NULL);
+
+ /**
+ * \brief Destructor
+ */
+ ~CBotToken();
+ /**
+ * \brief Returns the type of token
+ */
+ int GivType();
+
+ /**
+ * \brief makes the string corresponding to this token
+ */
+ CBotString& GivString();
+
+ /**
+ * \brief makes the following separator token
+ */
+ CBotString& GivSep();
+
+ /**
+ * \brief position of the beginning in the text
+ */
+ int GivStart();
+ /**
+ * \brief end position in the text
+ */
+ int GivEnd();
+
+ /**
+ * \brief gives the next token in the list
+ */
+ CBotToken* GivNext();
+ /**
+ * \brief gives the previous token in a list
+ */
+ CBotToken* GivPrev();
+
+ /**
+ * \brief transforms the entire program
+ */
+ static
+ CBotToken* CompileTokens(const char* p, int& error);
+
+ /**
+ * \brief releases the list
+ */
+ static
+ void Delete(CBotToken* pToken); // libère la liste
+
+
+ // fonctions non utiles en export
+ static
+ bool DefineNum(const char* name, long val);
+ void SetString(const char* name);
+
+ void SetPos(int start, int end);
+ long GivIdKey();
+ /**
+ * \brief adds a token (a copy)
+ */
+ void AddNext(CBotToken* p);
+
+ /**
+ * finds the next token
+ */
+ static
+ CBotToken* NextToken(char* &program, int& error, bool first = false);
+
+ const CBotToken&
+ operator=(const CBotToken& src);
+
+ static
+ void Free();
+};
+
+
+
+#if 0
+////////////////////////////////////////////////////////////////////////
+// Examples of use
+// Definition classes and functions
+
+
+// define the global class CPoint
+// --------------------------------
+ m_pClassPoint = new CBotClass("CPoint", NULL);
+ // adds the component ".x"
+ m_pClassPoint->AddItem("x", CBotTypResult(CBotTypFloat));
+ // adds the component ".y"
+ m_pClassPoint->AddItem("y", CBotTypResult(CBotTypFloat));
+ // the player can then use the instructions
+ // CPoint position; position.x = 12; position.y = -13.6
+
+// define class CColobotObject
+// --------------------------------
+// This class manages all the objects in the world of COLOBOT
+// the "main" user program belongs to this class
+ m_pClassObject = new CBotClass("CColobotObject", m_pClassBase);
+ // adds the component ".position"
+ m_pClassObject->AddItem("position", m_pClassPoint);
+ // adds the component ".type"
+ m_pClassObject->AddItem("type", CBotTypResult(CBotTypShort));
+ // adds a definition of constant
+ m_pClassObject->AddConst("ROBOT", CBotTypShort, 1); // ROBOT equivalent to the value 1
+ // adds the FIND routine
+ m_pClassObject->AddFunction( rCompFind, rDoFind );
+ // the player can now use the instructions
+ // CColobotObject chose; chose = FIND( ROBOT )
+
+
+
+// define class CColobotRobot derived from CColobotObject
+// ---------------------------------------------------------
+// programs "main" associated with robots as a part of this class
+ m_pClassRobot = new CBotClass("CColobotRobot", m_pClassObject);
+ // add routine GOTO
+ m_pClassRobot->AddFunction( rCompGoto, rDoGoto );
+ // the player can now use
+ // GOTO( FIND ( ROBOT ) );
+
+
+// creates an instance of the class Robot
+// ------------------------------------
+// for example a new robot which has just been manufactured
+ CBotVar* m_pMonRobot = new CBotVar("MonRobot", m_pClassRobot);
+
+// compiles the program by hand for this robot
+// ------------------------------------------
+ CString LeProgramme( "void main() {GOTO(0, 0); return 0;}" );
+ if ( !m_pMonRobot->Compile( LeProgramme ) ) {error handling ...};
+
+// build a stack for interpreter
+// --------------------------------------
+ CBotStack* pStack = new CBotStack(NULL);
+
+// executes the main program
+// -------------------------
+ while( false = m_pMonRobot->Execute( "main", pStack ))
+ {
+ // program suspended
+ // could be pass a handle to another (safeguarding pstack for the robot one)
+ };
+ // programme "main" finished !
+
+
+
+
+// routine that implements the GOTO (CPoint pos)
+bool rDoGoto( CBotVar* pVar, CBotVar* pResult, int& exception )
+{
+ if (pVar->GivType() != CBotTypeClass ||
+ pVar->IsElemOfClas("CPoint") ) { exception = 6522; return false; )
+ // the parameter is not the right class?
+ // in fact the control is done to the routine of compilation
+
+ m_PosToGo.Copy( pVar ); // keeps the target position (object type CBotVar)
+
+ // or so
+ CBotVar* temp;
+ temp = pVar->GivItem("x"); // is necessary for the object of type CPoint
+ ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
+ m_PosToGo.x = temp->GivValFloat();
+
+ temp = pVar->GivItem("y"); // is necessary for the object of type CPoint
+ ASSERT (temp != NULL && temp->GivType() == CBotTypFloat);
+ m_PosToGo.y = temp->GivValFloat();
+
+ return (m_CurentPos == m_PosToGo); // makes true if the position is reached
+ // returns false if one had wait yet
+}
+
+#endif
+#endif //_CBOTDLL_H_
+
diff --git a/src/CBot/CBotFunction.cpp b/src/CBot/CBotFunction.cpp
index 488061c..1c94c1b 100644
--- a/src/CBot/CBotFunction.cpp
+++ b/src/CBot/CBotFunction.cpp
@@ -1,1648 +1,1647 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// compilation des diverses fonctions déclarées par l'utilisateur
-//
-
-#include "CBot.h"
-
-// les divers constructeurs / destructeurs
-// pour libérer tout selon l'arbre établi
-CBotFunction::CBotFunction()
-{
- m_Param = NULL; // liste des paramètres vide
- m_Block = NULL; // le bloc d'instructions
- m_next = NULL; // les fonctions peuvent être chaînées
- m_bPublic = FALSE; // fonction non publique
- m_bExtern = FALSE; // fonction non externe
- m_nextpublic = NULL;
- m_prevpublic = NULL;
- m_pProg = NULL;
-// m_nThisIdent = 0;
- m_nFuncIdent = 0;
- m_bSynchro = FALSE;
-}
-
-CBotFunction* CBotFunction::m_listPublic = NULL;
-
-CBotFunction::~CBotFunction()
-{
- delete m_Param; // liste des paramètres vide
- delete m_Block; // le bloc d'instructions
- delete m_next;
-
- // enlève de la liste publique s'il y a lieu
- if ( m_bPublic )
- {
- if ( m_nextpublic != NULL )
- {
- m_nextpublic->m_prevpublic = m_prevpublic;
- }
- if ( m_prevpublic != NULL)
- {
- m_prevpublic->m_nextpublic = m_nextpublic;
- }
- else
- {
- // si prev = next = null peut ne pas être dans la liste !
- if ( m_listPublic == this ) m_listPublic = m_nextpublic;
- }
- }
-}
-
-BOOL CBotFunction::IsPublic()
-{
- return m_bPublic;
-}
-
-BOOL CBotFunction::IsExtern()
-{
- return m_bExtern;
-}
-
-BOOL CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
-{
- start = m_extern.GivStart();
- stop = m_closeblk.GivEnd();
-
- if (modestart == GetPosExtern)
- {
- start = m_extern.GivStart();
- }
- if (modestop == GetPosExtern)
- {
- stop = m_extern.GivEnd();
- }
- if (modestart == GetPosNom)
- {
- start = m_token.GivStart();
- }
- if (modestop == GetPosNom)
- {
- stop = m_token.GivEnd();
- }
- if (modestart == GetPosParam)
- {
- start = m_openpar.GivStart();
- }
- if (modestop == GetPosParam)
- {
- stop = m_closepar.GivEnd();
- }
- if (modestart == GetPosBloc)
- {
- start = m_openblk.GivStart();
- }
- if (modestop == GetPosBloc)
- {
- stop = m_closeblk.GivEnd();
- }
-
- return TRUE;
-}
-
-
-CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
-{
- while ( IsOfType( p, ID_OPBRK ) )
- {
- if ( !IsOfType( p, ID_CLBRK ) )
- {
- pile->SetError(TX_CLBRK, p->GivStart());
- return CBotTypResult( -1 );
- }
- type = CBotTypResult( CBotTypArrayPointer, type );
- }
- return type;
-}
-
-CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
-{
- CBotClass* pClass = NULL;
-
- switch (p->GivType())
- {
- case ID_INT:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
- case ID_FLOAT:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
- case ID_BOOLEAN:
- case ID_BOOL:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
- case ID_STRING:
- p = p->GivNext();
- return ArrayType(p, pile, CBotTypResult( CBotTypString ));
- case ID_VOID:
- p = p->GivNext();
- return CBotTypResult( 0 );
-
- case TokenTypVar:
- pClass = CBotClass::Find(p);
- if ( pClass != NULL)
- {
- p = p->GivNext();
- return ArrayType(p, pile,
- pClass->IsIntrinsic() ?
- CBotTypResult( CBotTypIntrinsic, pClass ) :
- CBotTypResult( CBotTypPointer, pClass ) );
- }
- }
- return CBotTypResult( -1 );
-}
-
-// compile une nouvelle fonction
-// bLocal permet de mettre la déclaration des paramètres au même niveau
-// que le éléments appartenant à la classe pour les méthodes
-CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, BOOL bLocal)
-{
- CBotToken* pp;
- CBotFunction* func = finput;
- if ( func == NULL ) func = new CBotFunction();
-
- CBotCStack* pStk = pStack->TokenStack(p, bLocal);
-
-// func->m_nFuncIdent = CBotVar::NextUniqNum();
-
- while (TRUE)
- {
- if ( IsOfType(p, ID_PUBLIC) )
- {
- func->m_bPublic = TRUE;
- continue;
- }
- pp = p;
- if ( IsOfType(p, ID_EXTERN) )
- {
- func->m_extern = pp; // pour la position du mot "extern"
- func->m_bExtern = TRUE;
-// func->m_bPublic = TRUE; // donc aussi publique!
- continue;
- }
- break;
- }
-
- func->m_retToken = *p;
-// CBotClass* pClass;
- func->m_retTyp = TypeParam(p, pStk); // type du résultat
-
- if (func->m_retTyp.GivType() >= 0)
- {
- CBotToken* pp = p;
- func->m_token = *p;
-
- if ( IsOfType(p, ID_NOT) )
- {
- CBotToken d("~" + p->GivString());
- func->m_token = d;
- }
-
- // un nom de fonction est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe
- {
- func->m_MasterClass = pp->GivString();
- CBotClass* pClass = CBotClass::Find(pp);
- if ( pClass == NULL ) goto bad;
-
-// pp = p;
- func->m_token = *p;
- if (!IsOfType(p, TokenTypVar)) goto bad;
-
- }
- func->m_openpar = p;
- func->m_Param = CBotDefParam::Compile( p, pStk );
- func->m_closepar = p->GivPrev();
- if (pStk->IsOk())
- {
- pStk->SetRetType(func->m_retTyp); // pour savoir de quel type les return
-
- if (!func->m_MasterClass.IsEmpty())
- {
- // rend "this" connu
- CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass ));
- pThis->SetInit(2);
-// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() va pas
- pThis->SetUniqNum(-2);
- pStk->AddVar(pThis);
-
- // initialise les variables selon This
- // n'enregistre que le pointeur à la première,
- // le reste est chainé
- CBotVar* pv = pThis->GivItemList();
-// int num = 1;
- while (pv != NULL)
- {
- CBotVar* pcopy = CBotVar::Create(pv);
-// pcopy->SetInit(2);
- pcopy->Copy(pv);
- pcopy->SetPrivate(pv->GivPrivate());
-// pcopy->SetUniqNum(pv->GivUniqNum()); //num++);
- pStk->AddVar(pcopy);
- pv = pv->GivNext();
- }
- }
-
- // et compile le bloc d'instruction qui suit
- func->m_openblk = p;
- func->m_Block = CBotBlock::Compile(p, pStk, FALSE);
- func->m_closeblk = p->GivPrev();
- if ( pStk->IsOk() )
- {
- if ( func->m_bPublic ) // fonction publique, la rend connue pour tous
- {
- CBotFunction::AddPublic(func);
- }
- return pStack->ReturnFunc(func, pStk);
- }
- }
- }
-bad:
- pStk->SetError(TX_NOFONC, p);
- }
- pStk->SetError(TX_NOTYP, p);
- if ( finput == NULL ) delete func;
- return pStack->ReturnFunc(NULL, pStk);
-}
-
-// pré-compile une nouvelle fonction
-CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
-{
- CBotFunction* func = new CBotFunction();
- func->m_nFuncIdent = CBotVar::NextUniqNum();
-
- CBotCStack* pStk = pStack->TokenStack(p, TRUE);
-
- while (TRUE)
- {
- if ( IsOfType(p, ID_PUBLIC) )
- {
- // func->m_bPublic = TRUE; // sera fait en passe 2
- continue;
- }
- if ( IsOfType(p, ID_EXTERN) )
- {
- func->m_bExtern = TRUE;
- continue;
- }
- break;
- }
-
- func->m_retToken = *p;
- func->m_retTyp = TypeParam(p, pStack); // type du résultat
-
- if (func->m_retTyp.GivType() >= 0)
- {
- CBotToken* pp = p;
- func->m_token = *p;
- // un nom de fonction est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- if ( IsOfType( p, ID_DBLDOTS ) ) // méthode pour une classe
- {
- func->m_MasterClass = pp->GivString();
- CBotClass* pClass = CBotClass::Find(pp);
- if ( pClass == NULL )
- {
- pStk->SetError(TX_NOCLASS, pp);
- goto bad;
- }
-
- pp = p;
- func->m_token = *p;
- if (!IsOfType(p, TokenTypVar)) goto bad;
-
- }
- func->m_Param = CBotDefParam::Compile( p, pStk );
- if (pStk->IsOk())
- {
- // regarde si la fonction existe ailleurs
- if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) &&
- ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) )
- {
- if (IsOfType(p, ID_OPBLK))
- {
- int level = 1;
- // et saute le bloc d'instructions qui suit
- do
- {
- int type = p->GivType();
- p = p->GivNext();
- if (type == ID_OPBLK) level++;
- if (type == ID_CLBLK) level--;
- }
- while (level > 0 && p != NULL);
-
- return pStack->ReturnFunc(func, pStk);
- }
- pStk->SetError(TX_OPENBLK, p);
- }
- }
- pStk->SetError(TX_REDEF, pp);
- }
-bad:
- pStk->SetError(TX_NOFONC, p);
- }
- pStk->SetError(TX_NOTYP, p);
- delete func;
- return pStack->ReturnFunc(NULL, pStk);
-}
-
-#ifdef _DEBUG
-static int xx = 0;
-#endif
-
-BOOL CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
-{
- CBotStack* pile = pj->AddStack(this, 2); // un bout de pile local à cette fonction
-// if ( pile == EOX ) return TRUE;
-
- pile->SetBotCall(m_pProg); // bases pour les routines
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_Param->Execute(ppVars, pile) ) return FALSE; // défini les paramètres
- pile->IncState();
- }
-
- if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() )
- {
- // rend "this" connu
- CBotVar* pThis ;
- if ( pInstance == NULL )
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass ));
- pThis->SetInit(2);
- }
- else
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass ));
- pThis->SetPointer(pInstance);
- pThis->SetInit(2);
- }
-
-// pThis->SetUniqNum(m_nThisIdent);
- pThis->SetUniqNum(-2);
- pile->AddVar(pThis);
-
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- if ( !m_Block->Execute(pile) )
- {
- if ( pile->GivError() < 0 )
- pile->SetError( 0 );
- else
- return FALSE;
- }
-
- return pj->Return(pile);
-}
-
-
-void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
-{
- CBotStack* pile = pj->RestoreStack(this); // un bout de pile local à cette fonction
- if ( pile == NULL ) return;
- CBotStack* pile2 = pile;
-
- pile->SetBotCall(m_pProg); // bases pour les routines
-
- if ( pile->GivBlock() < 2 )
- {
- CBotStack* pile2 = pile->RestoreStack(NULL); // un bout de pile local à cette fonction
- if ( pile2 == NULL ) return;
- pile->SetState(pile->GivState() + pile2->GivState());
- pile2->Delete();
- }
-
- m_Param->RestoreState(pile2, TRUE); // les paramètres
-
- if ( !m_MasterClass.IsEmpty() )
- {
- CBotVar* pThis = pile->FindVar("this");
- pThis->SetInit(2);
- pThis->SetUniqNum(-2);
- }
-
- m_Block->RestoreState(pile2, TRUE);
-}
-
-void CBotFunction::AddNext(CBotFunction* p)
-{
- CBotFunction* pp = this;
- while (pp->m_next != NULL) pp = pp->m_next;
-
- pp->m_next = p;
-}
-
-
-CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
-{
- nIdent = 0;
- CBotTypResult type;
-
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
- return type;
-}
-
-
-// trouve une fonction selon son identificateur unique
-// si l'identificateur n'est pas trouvé, cherche selon le nom et les paramètres
-
-CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, BOOL bPublic)
-{
- TypeOrError.SetType(TX_UNDEFCALL); // pas de routine de ce nom
- CBotFunction* pt;
-
- if ( nIdent )
- {
- if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- TypeOrError = pt->m_retTyp;
- return pt;
- }
- }
-
- // recherche dans la liste des fonctions publiques
-
- for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- TypeOrError = pt->m_retTyp;
- return pt;
- }
- }
- }
-
- if ( name == NULL ) return NULL;
-
- int delta = 99999; // cherche la signature la plus faible
- CBotFunction* pFunc = NULL; // la meilleure fonction trouvée
-
- if ( this != NULL )
- {
- for ( pt = this ; pt != NULL ; pt = pt->m_next )
- {
- if ( pt->m_token.GivString() == name )
- {
- int i = 0;
- int alpha = 0; // signature des paramètres
- // les paramètres sont-ils compatibles ?
- CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus
- CBotVar* pw = ppVars[i++]; // liste des paramètres fournis
- while ( pv != NULL && pw != NULL)
- {
- if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
- {
- if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
- break;
- }
- int d = pv->GivType() - pw->GivType(2);
- alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !!
-
- pv = pv->GivNext();
- pw = ppVars[i++];
- }
- if ( pw != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
- continue; // trop de paramètres
- }
- if ( pv != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
- continue; // pas assez de paramètres
- }
-
- if (alpha == 0) // signature parfaite
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // une meilleur signature ?
- {
- pFunc = pt;
- delta = alpha;
- }
- }
- }
- }
-
- if ( bPublic )
- {
- for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
- {
- if ( pt->m_token.GivString() == name )
- {
- int i = 0;
- int alpha = 0; // signature des paramètres
- // les paramètres sont-ils compatibles ?
- CBotDefParam* pv = pt->m_Param; // liste des paramètres attendus
- CBotVar* pw = ppVars[i++]; // liste des paramètres fournis
- while ( pv != NULL && pw != NULL)
- {
- if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
- {
- if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
- break;
- }
- int d = pv->GivType() - pw->GivType(2);
- alpha += d>0 ? d : -10*d; // perte de qualité, 10 fois plus cher !!
-
- pv = pv->GivNext();
- pw = ppVars[i++];
- }
- if ( pw != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
- continue; // trop de paramètres
- }
- if ( pv != NULL )
- {
- if ( pFunc != NULL ) continue;
- if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
- if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
- continue; // pas assez de paramètres
- }
-
- if (alpha == 0) // signature parfaite
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // une meilleur signature ?
- {
- pFunc = pt;
- delta = alpha;
- }
- }
- }
- }
-
- if ( pFunc != NULL )
- {
- nIdent = pFunc->m_nFuncIdent;
- TypeOrError = pFunc->m_retTyp;
- return pFunc;
- }
- return NULL;
-}
-
-
-// fait un appel à une fonction
-
-int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
-{
- CBotTypResult type;
- CBotFunction* pt = NULL;
-
- pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- CBotStack* pStk1 = pStack->AddStack(pt, 2); // pour mettre "this"
-// if ( pStk1 == EOX ) return TRUE;
-
- pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- if ( pStk1->IfStep() ) return FALSE;
-
- CBotStack* pStk3 = pStk1->AddStack(NULL, TRUE); // paramètres
-
- // prépare les paramètres sur la pile
-
- if ( pStk1->GivState() == 0 )
- {
- if ( !pt->m_MasterClass.IsEmpty() )
- {
- CBotVar* pInstance = m_pProg->m_pInstance;
- // rend "this" connu
- CBotVar* pThis ;
- if ( pInstance == NULL )
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass ));
- pThis->SetInit(2);
- }
- else
- {
- pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass ));
- pThis->SetPointer(pInstance);
- pThis->SetInit(2);
- }
-
- pThis->SetUniqNum(-2);
- pStk1->AddVar(pThis);
-
- }
-
- // initialise les variables selon paramètres
- pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu
-
- pStk1->IncState();
- }
-
- // finalement exécute la fonction trouvée
-
- if ( !pStk3->GivRetVar( // remet le résultat sur la pile
- pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu
- {
- if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
- {
-#ifdef _DEBUG
- if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return FALSE;
-#endif
- pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure
- }
- return FALSE; // interrompu !
- }
-
- return pStack->Return( pStk3 );
- }
- return -1;
-}
-
-void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
-{
- CBotTypResult type;
- CBotFunction* pt = NULL;
- CBotStack* pStk1;
- CBotStack* pStk3;
-
- // recherche la fonction pour remettre l'identificateur ok
-
- pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- pStk1 = pStack->RestoreStack(pt);
- if ( pStk1 == NULL ) return;
-
- pStk1->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- if ( pStk1->GivBlock() < 2 )
- {
- CBotStack* pStk2 = pStk1->RestoreStack(NULL); // plus utilisé
- if ( pStk2 == NULL ) return;
- pStk3 = pStk2->RestoreStack(NULL);
- if ( pStk3 == NULL ) return;
- }
- else
- {
- pStk3 = pStk1->RestoreStack(NULL);
- if ( pStk3 == NULL ) return;
- }
-
- // prépare les paramètres sur la pile
-
- {
- if ( !pt->m_MasterClass.IsEmpty() )
- {
- CBotVar* pInstance = m_pProg->m_pInstance;
- // rend "this" connu
- CBotVar* pThis = pStk1->FindVar("this");
- pThis->SetInit(2);
- pThis->SetUniqNum(-2);
- }
- }
-
- if ( pStk1->GivState() == 0 )
- {
- pt->m_Param->RestoreState(pStk3, TRUE);
- return;
- }
-
- // initialise les variables selon paramètres
- pt->m_Param->RestoreState(pStk3, FALSE);
- pt->m_Block->RestoreState(pStk3, TRUE);
- }
-}
-
-
-
-// fait un appel d'une méthode
-// note : this est déjà sur la pile, le pointeur pThis est juste là pour simplifier
-
-int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
-{
- CBotTypResult type;
- CBotProgram* pProgCurrent = pStack->GivBotCall();
-
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, FALSE);
-
- if ( pt != NULL )
- {
-// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack);
-
- CBotStack* pStk = pStack->AddStack(pt, 2);
-// if ( pStk == EOX ) return TRUE;
-
- pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module
- CBotStack* pStk3 = pStk->AddStack(NULL, TRUE); // pour mettre les paramètres passés
-
- // prépare les paramètres sur la pile
-
- if ( pStk->GivState() == 0 )
- {
- // met la variable "this" sur la pile
- CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
- pthis->Copy(pThis, FALSE);
- pthis->SetUniqNum(-2); // valeur spéciale
- pStk->AddVar(pthis);
-
- CBotClass* pClass = pThis->GivClass()->GivParent();
- if ( pClass )
- {
- // met la variable "super" sur la pile
- CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer);
- psuper->Copy(pThis, FALSE); // en fait identique à "this"
- psuper->SetUniqNum(-3); // valeur spéciale
- pStk->AddVar(psuper);
- }
- // initialise les variables selon paramètres
- pt->m_Param->Execute(ppVars, pStk3); // ne peut pas être interrompu
- pStk->IncState();
- }
-
- if ( pStk->GivState() == 1 )
- {
- if ( pt->m_bSynchro )
- {
- CBotProgram* pProgBase = pStk->GivBotCall(TRUE);
- if ( !pClass->Lock(pProgBase) ) return FALSE; // attend de pouvoir
- }
- pStk->IncState();
- }
- // finalement appelle la fonction trouvée
-
- if ( !pStk3->GivRetVar( // remet le résultat sur la pile
- pt->m_Block->Execute(pStk3) )) // GivRetVar dit si c'est interrompu
- {
- if ( !pStk3->IsOk() )
- {
- if ( pt->m_bSynchro )
- {
- pClass->Unlock(); // libère la fonction
- }
-
- if ( pt->m_pProg != pProgCurrent )
- {
- pStk3->SetPosError(pToken); // indique l'erreur sur l'appel de procédure
- }
- }
- return FALSE; // interrompu !
- }
-
- if ( pt->m_bSynchro )
- {
- pClass->Unlock(); // libère la fonction
- }
-
- return pStack->Return( pStk3 );
- }
- return -1;
-}
-
-void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
-{
- CBotTypResult type;
- CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
-
- if ( pt != NULL )
- {
- CBotStack* pStk = pStack->RestoreStack(pt);
- if ( pStk == NULL ) return;
- pStk->SetBotCall(pt->m_pProg); // on a peut-être changé de module
-
- CBotVar* pthis = pStk->FindVar("this");
- pthis->SetUniqNum(-2);
-
- CBotStack* pStk3 = pStk->RestoreStack(NULL); // pour mettre les paramètres passés
- if ( pStk3 == NULL ) return;
-
- pt->m_Param->RestoreState(pStk3, TRUE); // les paramètres
-
- if ( pStk->GivState() > 1 && // vérouillage est effectif ?
- pt->m_bSynchro )
- {
- CBotProgram* pProgBase = pStk->GivBotCall(TRUE);
- pClass->Lock(pProgBase); // vérouille la classe
- }
-
- // finalement appelle la fonction trouvée
-
- pt->m_Block->RestoreState(pStk3, TRUE); // interrompu !
- }
-}
-
-// regarde si la "signature" des paramètres est identique
-BOOL CBotFunction::CheckParam(CBotDefParam* pParam)
-{
- CBotDefParam* pp = m_Param;
- while ( pp != NULL && pParam != NULL )
- {
- CBotTypResult type1 = pp->GivType();
- CBotTypResult type2 = pParam->GivType();
- if ( !type1.Compare(type2) ) return FALSE;
- pp = pp->GivNext();
- pParam = pParam->GivNext();
- }
- return ( pp == NULL && pParam == NULL );
-}
-
-CBotString CBotFunction::GivName()
-{
- return m_token.GivString();
-}
-
-CBotString CBotFunction::GivParams()
-{
- if ( m_Param == NULL ) return CBotString("()");
-
- CBotString params = "( ";
- CBotDefParam* p = m_Param; // liste des paramètres
-
- while (p != NULL)
- {
- params += p->GivParamString();
- p = p->GivNext();
- if ( p != NULL ) params += ", ";
- }
-
- params += " )";
- return params;
-}
-
-CBotFunction* CBotFunction::Next()
-{
- return m_next;
-}
-
-void CBotFunction::AddPublic(CBotFunction* func)
-{
- if ( m_listPublic != NULL )
- {
- func->m_nextpublic = m_listPublic;
- m_listPublic->m_prevpublic = func;
- }
- m_listPublic = func;
-}
-
-
-
-/////////////////////////////////////////////////////////////////////////
-// gestion des paramètres
-
-
-CBotDefParam::CBotDefParam()
-{
- m_next = NULL;
- m_nIdent = 0;
-}
-
-CBotDefParam::~CBotDefParam()
-{
- delete m_next;
-}
-
-
-// compile une liste de paramètres
-CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- // surtout pas de pStack->TokenStack ici
- // les variables déclarées doivent rester visibles par la suite
-
- pStack->SetStartError(p->GivStart());
-
- if (IsOfType(p, ID_OPENPAR))
- {
- CBotDefParam* list = NULL;
-
- while (!IsOfType(p, ID_CLOSEPAR))
- {
- CBotDefParam* param = new CBotDefParam();
- if (list == NULL) list = param;
- else list->AddNext(param); // ajoute à la liste
-
- CBotClass* pClass = NULL;//= CBotClass::Find(p);
- param->m_typename = p->GivString();
- CBotTypResult type = param->m_type = TypeParam(p, pStack);
-// if ( type == CBotTypPointer ) type = CBotTypClass; // il faut créer un nouvel objet
-
- if (param->m_type.GivType() > 0)
- {
- CBotToken* pp = p;
- param->m_token = *p;
- if (pStack->IsOk() && IsOfType(p, TokenTypVar) )
- {
-
- // variable déjà déclarée ?
- if (pStack->CheckVarLocal(pp))
- {
- pStack->SetError(TX_REDEFVAR, pp);
- break;
- }
-
- if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
- CBotVar* var = CBotVar::Create(pp->GivString(), type); // crée la variable
-// if ( pClass ) var->SetClass(pClass);
- var->SetInit(2); // la marque initialisée
- param->m_nIdent = CBotVar::NextUniqNum();
- var->SetUniqNum(param->m_nIdent);
- pStack->AddVar(var); // la place sur la pile
-
- if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR)
- continue;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStack->SetError(TX_NOTYP, p);
- delete list;
- return NULL;
- }
- return list;
- }
- pStack->SetError(TX_OPENPAR, p->GivStart());
- return NULL;
-}
-
-void CBotDefParam::AddNext(CBotDefParam* p)
-{
- CBotDefParam* pp = this;
- while (pp->m_next != NULL) pp = pp->m_next;
-
- pp->m_next = p;
-}
-
-
-BOOL CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
-{
- int i = 0;
- CBotDefParam* p = this;
-
- while ( p != NULL )
- {
- // crée une variable locale sur la pile
- CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type);
-
- // procède ainsi pour faire la transformation des types :
- if ( ppVars != NULL && ppVars[i] != NULL )
- {
- switch (p->m_type.GivType())
- {
- case CBotTypInt:
- newvar->SetValInt(ppVars[i]->GivValInt());
- break;
- case CBotTypFloat:
- newvar->SetValFloat(ppVars[i]->GivValFloat());
- break;
- case CBotTypString:
- newvar->SetValString(ppVars[i]->GivValString());
- break;
- case CBotTypBoolean:
- newvar->SetValInt(ppVars[i]->GivValInt());
- break;
- case CBotTypIntrinsic:
- ((CBotVarClass*)newvar)->Copy(ppVars[i], FALSE);
- break;
- case CBotTypPointer:
- case CBotTypArrayPointer:
- {
- newvar->SetPointer(ppVars[i]->GivPointer());
- }
- break;
- default:
- ASM_TRAP();
- }
- }
- newvar->SetUniqNum(p->m_nIdent);
- pj->AddVar(newvar); // place la variable
- p = p->m_next;
- i++;
- }
-
- return TRUE;
-}
-
-void CBotDefParam::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- int i = 0;
- CBotDefParam* p = this;
-
- while ( p != NULL )
- {
- // crée une variable locale sur la pile
- CBotVar* var = pj->FindVar(p->m_token.GivString());
- var->SetUniqNum(p->m_nIdent);
- p = p->m_next;
- }
-}
-
-int CBotDefParam::GivType()
-{
- return m_type.GivType();
-}
-
-CBotTypResult CBotDefParam::GivTypResult()
-{
- return m_type;
-}
-
-CBotDefParam* CBotDefParam::GivNext()
-{
- return m_next;
-}
-
-CBotString CBotDefParam::GivParamString()
-{
- CBotString param;
-
- param = m_typename;
- param += ' ';
-
- param += m_token.GivString();
- return param;
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////
-// retour des paramètres
-
-CBotReturn::CBotReturn()
-{
- m_Instr = NULL;
- name = "CBotReturn"; // debug
-}
-
-CBotReturn::~CBotReturn()
-{
- delete m_Instr;
-}
-
-CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p;
-
- if (!IsOfType(p, ID_RETURN)) return NULL; // ne devrait jamais arriver
-
- CBotReturn* inst = new CBotReturn(); // crée l'objet
- inst->SetToken( pp );
-
- CBotTypResult type = pStack->GivRetType();
-
- if ( type.GivType() == 0 ) // retourne void ?
- {
- if ( IsOfType( p, ID_SEP ) ) return inst;
- pStack->SetError( TX_BADTYPE, pp );
- return NULL;
- }
-
- inst->m_Instr = CBotExpression::Compile(p, pStack);
- if ( pStack->IsOk() )
- {
- CBotTypResult retType = pStack->GivTypResult(2);
- if (TypeCompatible(retType, type, ID_ASS))
- {
- if ( IsOfType( p, ID_SEP ) )
- return inst;
-
- pStack->SetError(TX_ENDOF, p->GivStart());
- }
- pStack->SetError(TX_BADTYPE, p->GivStart());
- }
-
- delete inst;
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-BOOL CBotReturn::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState() == 0 )
- {
- if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return FALSE; // évalue le résultat
- // le résultat est sur la pile
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- pile->SetBreak(3, CBotString());
- return pj->Return(pile);
-}
-
-void CBotReturn::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // évalue le résultat
- return;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Les appels à ces fonctions
-
-CBotInstrCall::CBotInstrCall()
-{
- m_Parameters = NULL;
- m_nFuncIdent = 0;
- name = "CBotInstrCall";
-}
-
-CBotInstrCall::~CBotInstrCall()
-{
- delete m_Parameters;
-}
-
-CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotVar* ppVars[1000];
-
- int i = 0;
-
- CBotToken* pp = p;
- p = p->GivNext();
-
- pStack->SetStartError(p->GivStart());
- CBotCStack* pile = pStack;
-
- if ( IsOfType(p, ID_OPENPAR) )
- {
- int start, end;
- CBotInstrCall* inst = new CBotInstrCall();
- inst->SetToken(pp);
-
- // compile la liste des paramètres
- if (!IsOfType(p, ID_CLOSEPAR)) while (TRUE)
- {
- start = p->GivStart();
- pile = pile->TokenStack(); // garde les résultats sur la pile
-
- CBotInstr* param = CBotExpression::Compile(p, pile);
- end = p->GivStart();
- if ( inst->m_Parameters == NULL ) inst->m_Parameters = param;
- else inst->m_Parameters->AddNext(param); // construit la liste
-
- if ( !pile->IsOk() )
- {
- delete inst;
- return pStack->Return(NULL, pile);
- }
-
- if ( param != NULL )
- {
- if ( pile->GivTypResult().Eq(99) )
- {
- delete pStack->TokenStack();
- pStack->SetError(TX_VOID, p->GivStart());
- delete inst;
- return NULL;
- }
- ppVars[i] = pile->GivVar();
- ppVars[i]->GivToken()->SetPos(start, end);
- i++;
-
- if (IsOfType(p, ID_COMMA)) continue; // saute la virgule
- if (IsOfType(p, ID_CLOSEPAR)) break;
- }
-
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- delete pStack->TokenStack();
- delete inst;
- return NULL;
- }
- ppVars[i] = NULL;
-
- // la routine est-elle connue ?
-// CBotClass* pClass = NULL;
- inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent);
- if ( inst->m_typRes.GivType() >= 20 )
- {
-// if (pVar2!=NULL) pp = pVar2->RetToken();
- pStack->SetError( inst->m_typRes.GivType(), pp );
- delete pStack->TokenStack();
- delete inst;
- return NULL;
- }
-
- delete pStack->TokenStack();
- if ( inst->m_typRes.GivType() > 0 )
- {
- CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
- pStack->SetVar(pRes); // pour connaître le type du résultat
- }
- else pStack->SetVar(NULL); // routine retourne void
-
- return inst;
- }
- p = pp;
- delete pStack->TokenStack();
- return NULL;
-}
-
-BOOL CBotInstrCall::Execute(CBotStack* &pj)
-{
- CBotVar* ppVars[1000];
- CBotStack* pile = pj->AddStack(this);
- if ( pile->StackOver() ) return pj->Return( pile );
-
- CBotStack* pile1 = pile;
-
- int i = 0;
-
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( TRUE )
- {
- pile = pile->AddStack(); // de la place sur la pile pour les résultats
- if ( pile->GivState() == 0 )
- {
- if (!p->Execute(pile)) return FALSE; // interrompu ici ?
- pile->SetState(1); // marque spéciale pour reconnaîre les paramètres
- }
- ppVars[i++] = pile->GivVar();
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotStack* pile2 = pile->AddStack();
- if ( pile2->IfStep() ) return FALSE;
-
- if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return FALSE; // interrompu
-
- return pj->Return(pile2); // libère toute la pile
-}
-
-void CBotInstrCall::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- CBotStack* pile1 = pile;
-
- int i = 0;
- CBotVar* ppVars[1000];
- CBotInstr* p = m_Parameters;
- // évalue les paramètres
- // et place les valeurs sur la pile
- // pour pouvoir être interrompu n'importe quand
- if ( p != NULL) while ( TRUE )
- {
- pile = pile->RestoreStack(); // de la place sur la pile pour les résultats
- if ( pile == NULL ) return;
- if ( pile->GivState() == 0 )
- {
- p->RestoreState(pile, bMain); // interrompu ici !
- return;
- }
- ppVars[i++] = pile->GivVar(); // construit la liste des paramètres
- p = p->GivNext();
- if ( p == NULL) break;
- }
- ppVars[i] = NULL;
-
- CBotStack* pile2 = pile->RestoreStack();
- if ( pile2 == NULL ) return;
-
- pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// déclaration des classes par l'utilisateur
-
-// pré-compile une nouvelle class
-// l'analyse est complète à l'execption du corps des routines
-
-CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
-{
- if ( !IsOfType(p, ID_PUBLIC) )
- {
- pStack->SetError(TX_NOPUBLIC, p);
- return NULL;
- }
-
- if ( !IsOfType(p, ID_CLASS) ) return NULL;
-
- CBotString name = p->GivString();
-
- CBotClass* pOld = CBotClass::Find(name);
- if ( pOld != NULL && pOld->m_IsDef )
- {
- pStack->SetError( TX_REDEFCLASS, p );
- return NULL;
- }
-
- // un nom pour la classe est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- CBotClass* pPapa = NULL;
-#if EXTENDS
- if ( IsOfType( p, ID_EXTENDS ) )
- {
- CBotString name = p->GivString();
- pPapa = CBotClass::Find(name);
-
- if (!IsOfType(p, TokenTypVar) || pPapa == NULL )
- {
- pStack->SetError( TX_NOCLASS, p );
- return NULL;
- }
- }
-#endif
- CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld;
- classe->Purge(); // vide les anciennes définitions
- classe->m_IsDef = FALSE; // définition en cours
-
- if ( !IsOfType( p, ID_OPBLK) )
- {
- pStack->SetError(TX_OPENBLK, p);
- return NULL;
- }
-
- while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
- {
- classe->CompileDefItem(p, pStack, FALSE);
- }
-
- if (pStack->IsOk()) return classe;
- }
- pStack->SetError(TX_ENDOF, p);
- return NULL;
-}
-
-BOOL CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, BOOL bSecond)
-{
- BOOL bStatic = FALSE;
- int mProtect = PR_PUBLIC;
- BOOL bSynchro = FALSE;
-
- while (IsOfType(p, ID_SEP)) ;
-
- CBotTypResult type( -1 );
-
- if ( IsOfType(p, ID_SYNCHO) ) bSynchro = TRUE;
- CBotToken* pBase = p;
-
- if ( IsOfType(p, ID_STATIC) ) bStatic = TRUE;
- if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC;
- if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE;
- if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT;
- if ( IsOfType(p, ID_STATIC) ) bStatic = TRUE;
-
-// CBotClass* pClass = NULL;
- type = TypeParam(p, pStack); // type du résultat
-
- if ( type.Eq(-1) )
- {
- pStack->SetError(TX_NOTYP, p);
- return FALSE;
- }
-
- while (pStack->IsOk())
- {
- CBotToken* pp = p;
- IsOfType(p, ID_NOT); // saute le ~ éventuel (destructeur)
-
- if (IsOfType(p, TokenTypVar))
- {
- CBotInstr* limites = NULL;
- while ( IsOfType( p, ID_OPBRK ) ) // un tableau ?
- {
- CBotInstr* i = NULL;
-
- if ( p->GivType() != ID_CLBRK )
- i = CBotExpression::Compile( p, pStack ); // expression pour la valeur
- else
- i = new CBotEmpty(); // spécial si pas de formule
-
- type = CBotTypResult(CBotTypArrayPointer, type);
-
- if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
- {
- pStack->SetError(TX_CLBRK, p->GivStart());
- return FALSE;
- }
-
-/* CBotVar* pv = pStack->GivVar();
- if ( pv->GivType()>= CBotTypBoolean )
- {
- pStack->SetError(TX_BADTYPE, p->GivStart());
- return FALSE;
- }*/
-
- if (limites == NULL) limites = i;
- else limites->AddNext3(i);
- }
-
- if ( p->GivType() == ID_OPENPAR )
- {
- if ( !bSecond )
- {
- p = pBase;
- CBotFunction* f =
- CBotFunction::Compile1(p, pStack, this);
-
- if ( f == NULL ) return FALSE;
-
- if (m_pMethod == NULL) m_pMethod = f;
- else m_pMethod->AddNext(f);
- }
- else
- {
- // retrouve la méthode précompilée en passe 1
- CBotFunction* pf = m_pMethod;
- CBotFunction* prev = NULL;
- while ( pf != NULL )
- {
- if (pf->GivName() == pp->GivString()) break;
- prev = pf;
- pf = pf->Next();
- }
-
- BOOL bConstructor = (pp->GivString() == GivName());
- CBotCStack* pile = pStack->TokenStack(NULL, TRUE);
-
- // rend "this" connu
- CBotToken TokenThis(CBotString("this"), CBotString());
- CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) );
- pThis->SetUniqNum(-2);
- pile->AddVar(pThis);
-
- if ( m_pParent )
- {
- // rend "super" connu
- CBotToken TokenSuper(CBotString("super"), CBotString());
- CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) );
- pThis->SetUniqNum(-3);
- pile->AddVar(pThis);
- }
-
-// int num = 1;
- CBotClass* my = this;
- while (my != NULL)
- {
- // place une copie des varibles de la classe (this) sur la pile
- CBotVar* pv = my->m_pVar;
- while (pv != NULL)
- {
- CBotVar* pcopy = CBotVar::Create(pv);
- pcopy->SetInit(!bConstructor || pv->IsStatic());
- pcopy->SetUniqNum(pv->GivUniqNum());
- pile->AddVar(pcopy);
- pv = pv->GivNext();
- }
- my = my->m_pParent;
- }
-
- // compile une méthode
- p = pBase;
- CBotFunction* f =
- CBotFunction::Compile(p, pile, NULL/*, FALSE*/);
-
- if ( f != NULL )
- {
- f->m_pProg = pStack->GivBotCall();
- f->m_bSynchro = bSynchro;
- // remplace l'élément dans la chaîne
- f->m_next = pf->m_next;
- pf->m_next = NULL;
- delete pf;
- if (prev == NULL) m_pMethod = f;
- else prev->m_next = f;
- }
- pStack->Return(NULL, pile);
- }
-
- return pStack->IsOk();
- }
-
- // définition d'un élément
- if (type.Eq(0))
- {
- pStack->SetError(TX_ENDOF, p);
- return FALSE;
- }
-
- CBotInstr* i = NULL;
- if ( IsOfType(p, ID_ASS ) )
- {
- if ( type.Eq(CBotTypArrayPointer) )
- {
- i = CBotListArray::Compile(p, pStack, type.GivTypElem());
- }
- else
- {
- // il y a une assignation à calculer
- i = CBotTwoOpExpr::Compile(p, pStack);
- }
- if ( !pStack->IsOk() ) return FALSE;
- }
-
-
- if ( !bSecond )
- {
- CBotVar* pv = CBotVar::Create(pp->GivString(), type);
- pv -> SetStatic( bStatic );
- pv -> SetPrivate( mProtect );
-
- AddItem( pv );
-
- pv->m_InitExpr = i;
- pv->m_LimExpr = limites;
-
-
- if ( pv->IsStatic() && pv->m_InitExpr != NULL )
- {
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
- while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // évalue l'expression sans timer
- pv->SetVal( pile->GivVar() ) ;
- pile->Delete();
- }
- }
- else
- delete i;
-
- if ( IsOfType(p, ID_COMMA) ) continue;
- if ( IsOfType(p, ID_SEP) ) break;
- }
- pStack->SetError(TX_ENDOF, p);
- }
- return pStack->IsOk();
-}
-
-
-CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- if ( !IsOfType(p, ID_PUBLIC) ) return NULL;
- if ( !IsOfType(p, ID_CLASS) ) return NULL;
-
- CBotString name = p->GivString();
-
- // un nom pour la classe est-il là ?
- if (IsOfType(p, TokenTypVar))
- {
- // la classe à été créée par Compile1
- CBotClass* pOld = CBotClass::Find(name);
-
-#if EXTENDS
- if ( IsOfType( p, ID_EXTENDS ) )
- {
- IsOfType(p, TokenTypVar); // forcément
- }
-#endif
- IsOfType( p, ID_OPBLK); // forcément
-
- while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
- {
- pOld->CompileDefItem(p, pStack, TRUE);
- }
-
- pOld->m_IsDef = TRUE; // définition terminée
- if (pStack->IsOk()) return pOld;
- }
- pStack->SetError(TX_ENDOF, p);
- return NULL;
-}
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+///////////////////////////////////////////////////////////////////////
+// compilation of various functions declared by the user
+//
+
+#include "CBot.h"
+
+// various constructors / destructors
+// \TODO translation:to liberate all according to esteblished tree
+// pour libérer tout selon l'arbre établi
+CBotFunction::CBotFunction()
+{
+ m_Param = NULL; // empty parameter list
+ m_Block = NULL; // the instruction block
+ m_next = NULL; // functions can be chained
+ m_bPublic = false; // function not public
+ m_bExtern = false; // function not extern
+ m_nextpublic = NULL;
+ m_prevpublic = NULL;
+ m_pProg = NULL;
+// m_nThisIdent = 0;
+ m_nFuncIdent = 0;
+ m_bSynchro = false;
+}
+
+CBotFunction* CBotFunction::m_listPublic = NULL;
+
+CBotFunction::~CBotFunction()
+{
+ delete m_Param; // empty parameter list
+ delete m_Block; // the instruction block
+ delete m_next;
+
+ // remove public list if there is
+ if ( m_bPublic )
+ {
+ if ( m_nextpublic != NULL )
+ {
+ m_nextpublic->m_prevpublic = m_prevpublic;
+ }
+ if ( m_prevpublic != NULL)
+ {
+ m_prevpublic->m_nextpublic = m_nextpublic;
+ }
+ else
+ {
+ // if prev = next = null may not be in the list!
+ if ( m_listPublic == this ) m_listPublic = m_nextpublic;
+ }
+ }
+}
+
+bool CBotFunction::IsPublic()
+{
+ return m_bPublic;
+}
+
+bool CBotFunction::IsExtern()
+{
+ return m_bExtern;
+}
+
+bool CBotFunction::GetPosition(int& start, int& stop, CBotGet modestart, CBotGet modestop)
+{
+ start = m_extern.GivStart();
+ stop = m_closeblk.GivEnd();
+
+ if (modestart == GetPosExtern)
+ {
+ start = m_extern.GivStart();
+ }
+ if (modestop == GetPosExtern)
+ {
+ stop = m_extern.GivEnd();
+ }
+ if (modestart == GetPosNom)
+ {
+ start = m_token.GivStart();
+ }
+ if (modestop == GetPosNom)
+ {
+ stop = m_token.GivEnd();
+ }
+ if (modestart == GetPosParam)
+ {
+ start = m_openpar.GivStart();
+ }
+ if (modestop == GetPosParam)
+ {
+ stop = m_closepar.GivEnd();
+ }
+ if (modestart == GetPosBloc)
+ {
+ start = m_openblk.GivStart();
+ }
+ if (modestop == GetPosBloc)
+ {
+ stop = m_closeblk.GivEnd();
+ }
+
+ return true;
+}
+
+
+CBotTypResult ArrayType(CBotToken* &p, CBotCStack* pile, CBotTypResult type)
+{
+ while ( IsOfType( p, ID_OPBRK ) )
+ {
+ if ( !IsOfType( p, ID_CLBRK ) )
+ {
+ pile->SetError(TX_CLBRK, p->GivStart());
+ return CBotTypResult( -1 );
+ }
+ type = CBotTypResult( CBotTypArrayPointer, type );
+ }
+ return type;
+}
+
+CBotTypResult TypeParam(CBotToken* &p, CBotCStack* pile)
+{
+ CBotClass* pClass = NULL;
+
+ switch (p->GivType())
+ {
+ case ID_INT:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypInt ));
+ case ID_FLOAT:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypFloat ));
+ case ID_BOOLEAN:
+ case ID_BOOL:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypBoolean ));
+ case ID_STRING:
+ p = p->GivNext();
+ return ArrayType(p, pile, CBotTypResult( CBotTypString ));
+ case ID_VOID:
+ p = p->GivNext();
+ return CBotTypResult( 0 );
+
+ case TokenTypVar:
+ pClass = CBotClass::Find(p);
+ if ( pClass != NULL)
+ {
+ p = p->GivNext();
+ return ArrayType(p, pile,
+ pClass->IsIntrinsic() ?
+ CBotTypResult( CBotTypIntrinsic, pClass ) :
+ CBotTypResult( CBotTypPointer, pClass ) );
+ }
+ }
+ return CBotTypResult( -1 );
+}
+
+// compiles a new function
+// bLocal allows of the declaration of parameters on the same level
+// as the elements belonging to the class for methods
+CBotFunction* CBotFunction::Compile(CBotToken* &p, CBotCStack* pStack, CBotFunction* finput, bool bLocal)
+{
+ CBotToken* pp;
+ CBotFunction* func = finput;
+ if ( func == NULL ) func = new CBotFunction();
+
+ CBotCStack* pStk = pStack->TokenStack(p, bLocal);
+
+// func->m_nFuncIdent = CBotVar::NextUniqNum();
+
+ while (true)
+ {
+ if ( IsOfType(p, ID_PUBLIC) )
+ {
+ func->m_bPublic = true;
+ continue;
+ }
+ pp = p;
+ if ( IsOfType(p, ID_EXTERN) )
+ {
+ func->m_extern = pp; // for the position of the word "extern"
+ func->m_bExtern = true;
+// func->m_bPublic = true; // therefore also public!
+ continue;
+ }
+ break;
+ }
+
+ func->m_retToken = *p;
+// CBotClass* pClass;
+ func->m_retTyp = TypeParam(p, pStk); // type of the result
+
+ if (func->m_retTyp.GivType() >= 0)
+ {
+ CBotToken* pp = p;
+ func->m_token = *p;
+
+ if ( IsOfType(p, ID_NOT) )
+ {
+ CBotToken d("~" + p->GivString());
+ func->m_token = d;
+ }
+
+ // un nom de fonction est-il là ?
+ if (IsOfType(p, TokenTypVar))
+ {
+ if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
+ {
+ func->m_MasterClass = pp->GivString();
+ CBotClass* pClass = CBotClass::Find(pp);
+ if ( pClass == NULL ) goto bad;
+
+// pp = p;
+ func->m_token = *p;
+ if (!IsOfType(p, TokenTypVar)) goto bad;
+
+ }
+ func->m_openpar = p;
+ func->m_Param = CBotDefParam::Compile( p, pStk );
+ func->m_closepar = p->GivPrev();
+ if (pStk->IsOk())
+ {
+ pStk->SetRetType(func->m_retTyp); // for knowledge what type returns
+
+ if (!func->m_MasterClass.IsEmpty())
+ {
+ // return "this" known
+ CBotVar* pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, func->m_MasterClass ));
+ pThis->SetInit(2);
+// pThis->SetUniqNum(func->m_nThisIdent = -2); //CBotVar::NextUniqNum() will not
+ pThis->SetUniqNum(-2);
+ pStk->AddVar(pThis);
+
+ // initialize variables acording to This
+ // only saves the pointer to the first,
+ // the rest is chained
+ CBotVar* pv = pThis->GivItemList();
+// int num = 1;
+ while (pv != NULL)
+ {
+ CBotVar* pcopy = CBotVar::Create(pv);
+// pcopy->SetInit(2);
+ pcopy->Copy(pv);
+ pcopy->SetPrivate(pv->GivPrivate());
+// pcopy->SetUniqNum(pv->GivUniqNum()); //num++);
+ pStk->AddVar(pcopy);
+ pv = pv->GivNext();
+ }
+ }
+
+ // and compiles the following instruction block
+ func->m_openblk = p;
+ func->m_Block = CBotBlock::Compile(p, pStk, false);
+ func->m_closeblk = p->GivPrev();
+ if ( pStk->IsOk() )
+ {
+ if ( func->m_bPublic ) // public function, return known for all
+ {
+ CBotFunction::AddPublic(func);
+ }
+ return pStack->ReturnFunc(func, pStk);
+ }
+ }
+ }
+bad:
+ pStk->SetError(TX_NOFONC, p);
+ }
+ pStk->SetError(TX_NOTYP, p);
+ if ( finput == NULL ) delete func;
+ return pStack->ReturnFunc(NULL, pStk);
+}
+
+// pre-compile a new function
+CBotFunction* CBotFunction::Compile1(CBotToken* &p, CBotCStack* pStack, CBotClass* pClass)
+{
+ CBotFunction* func = new CBotFunction();
+ func->m_nFuncIdent = CBotVar::NextUniqNum();
+
+ CBotCStack* pStk = pStack->TokenStack(p, true);
+
+ while (true)
+ {
+ if ( IsOfType(p, ID_PUBLIC) )
+ {
+ // func->m_bPublic = true; // will be done in two passes
+ continue;
+ }
+ if ( IsOfType(p, ID_EXTERN) )
+ {
+ func->m_bExtern = true;
+ continue;
+ }
+ break;
+ }
+
+ func->m_retToken = *p;
+ func->m_retTyp = TypeParam(p, pStack); // type of the result
+
+ if (func->m_retTyp.GivType() >= 0)
+ {
+ CBotToken* pp = p;
+ func->m_token = *p;
+ // un nom de fonction est-il là ?
+ if (IsOfType(p, TokenTypVar))
+ {
+ if ( IsOfType( p, ID_DBLDOTS ) ) // method for a class
+ {
+ func->m_MasterClass = pp->GivString();
+ CBotClass* pClass = CBotClass::Find(pp);
+ if ( pClass == NULL )
+ {
+ pStk->SetError(TX_NOCLASS, pp);
+ goto bad;
+ }
+
+ pp = p;
+ func->m_token = *p;
+ if (!IsOfType(p, TokenTypVar)) goto bad;
+
+ }
+ func->m_Param = CBotDefParam::Compile( p, pStk );
+ if (pStk->IsOk())
+ {
+ // looks if the function exists elsewhere
+ if (( pClass != NULL || !pStack->CheckCall(pp, func->m_Param)) &&
+ ( pClass == NULL || !pClass->CheckCall(pp, func->m_Param)) )
+ {
+ if (IsOfType(p, ID_OPBLK))
+ {
+ int level = 1;
+ // and skips the following instruction block
+ do
+ {
+ int type = p->GivType();
+ p = p->GivNext();
+ if (type == ID_OPBLK) level++;
+ if (type == ID_CLBLK) level--;
+ }
+ while (level > 0 && p != NULL);
+
+ return pStack->ReturnFunc(func, pStk);
+ }
+ pStk->SetError(TX_OPENBLK, p);
+ }
+ }
+ pStk->SetError(TX_REDEF, pp);
+ }
+bad:
+ pStk->SetError(TX_NOFONC, p);
+ }
+ pStk->SetError(TX_NOTYP, p);
+ delete func;
+ return pStack->ReturnFunc(NULL, pStk);
+}
+
+#ifdef _DEBUG
+static int xx = 0;
+#endif
+
+bool CBotFunction::Execute(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
+{
+ CBotStack* pile = pj->AddStack(this, 2); // one end of stack local to this function
+// if ( pile == EOX ) return true;
+
+ pile->SetBotCall(m_pProg); // bases for routines
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( !m_Param->Execute(ppVars, pile) ) return false; // define parameters
+ pile->IncState();
+ }
+
+ if ( pile->GivState() == 1 && !m_MasterClass.IsEmpty() )
+ {
+ // makes "this" known
+ CBotVar* pThis ;
+ if ( pInstance == NULL )
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, m_MasterClass ));
+ pThis->SetInit(2);
+ }
+ else
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, m_MasterClass ));
+ pThis->SetPointer(pInstance);
+ pThis->SetInit(2);
+ }
+
+// pThis->SetUniqNum(m_nThisIdent);
+ pThis->SetUniqNum(-2);
+ pile->AddVar(pThis);
+
+ pile->IncState();
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ if ( !m_Block->Execute(pile) )
+ {
+ if ( pile->GivError() < 0 )
+ pile->SetError( 0 );
+ else
+ return false;
+ }
+
+ return pj->Return(pile);
+}
+
+
+void CBotFunction::RestoreState(CBotVar** ppVars, CBotStack* &pj, CBotVar* pInstance)
+{
+ CBotStack* pile = pj->RestoreStack(this); // one end of stack local to this function
+ if ( pile == NULL ) return;
+ CBotStack* pile2 = pile;
+
+ pile->SetBotCall(m_pProg); // bases for routines
+
+ if ( pile->GivBlock() < 2 )
+ {
+ CBotStack* pile2 = pile->RestoreStack(NULL); // one end of stack local to this function
+ if ( pile2 == NULL ) return;
+ pile->SetState(pile->GivState() + pile2->GivState());
+ pile2->Delete();
+ }
+
+ m_Param->RestoreState(pile2, true); // parameters
+
+ if ( !m_MasterClass.IsEmpty() )
+ {
+ CBotVar* pThis = pile->FindVar("this");
+ pThis->SetInit(2);
+ pThis->SetUniqNum(-2);
+ }
+
+ m_Block->RestoreState(pile2, true);
+}
+
+void CBotFunction::AddNext(CBotFunction* p)
+{
+ CBotFunction* pp = this;
+ while (pp->m_next != NULL) pp = pp->m_next;
+
+ pp->m_next = p;
+}
+
+
+CBotTypResult CBotFunction::CompileCall(const char* name, CBotVar** ppVars, long& nIdent)
+{
+ nIdent = 0;
+ CBotTypResult type;
+
+ CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+ return type;
+}
+
+
+// is a function according to its unique identifier
+// if the identifier is not found, looking by name and parameters
+
+CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const char* name, CBotVar** ppVars, CBotTypResult& TypeOrError, bool bPublic)
+{
+ TypeOrError.SetType(TX_UNDEFCALL); // no routine of the name
+ CBotFunction* pt;
+
+ if ( nIdent )
+ {
+ if ( this != NULL ) for ( pt = this ; pt != NULL ; pt = pt->m_next )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+ }
+
+ // search the list of public functions
+
+ for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+ }
+ }
+
+ if ( name == NULL ) return NULL;
+
+ int delta = 99999; // seeks the lowest signature
+ CBotFunction* pFunc = NULL; // the best function found
+
+ if ( this != NULL )
+ {
+ for ( pt = this ; pt != NULL ; pt = pt->m_next )
+ {
+ if ( pt->m_token.GivString() == name )
+ {
+ int i = 0;
+ int alpha = 0; // signature of parameters
+ // parameters are compatible?
+ CBotDefParam* pv = pt->m_Param; // expected list of parameters
+ CBotVar* pw = ppVars[i++]; // provided list parameter
+ while ( pv != NULL && pw != NULL)
+ {
+ if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
+ {
+ if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
+ break;
+ }
+ int d = pv->GivType() - pw->GivType(2);
+ alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+
+ pv = pv->GivNext();
+ pw = ppVars[i++];
+ }
+ if ( pw != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
+ continue; // too many parameters
+ }
+ if ( pv != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
+ continue; // not enough parameters
+ }
+
+ if (alpha == 0) // perfect signature
+ {
+ nIdent = pt->m_nFuncIdent;
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+
+ if ( alpha < delta ) // a better signature?
+ {
+ pFunc = pt;
+ delta = alpha;
+ }
+ }
+ }
+ }
+
+ if ( bPublic )
+ {
+ for ( pt = m_listPublic ; pt != NULL ; pt = pt->m_nextpublic )
+ {
+ if ( pt->m_token.GivString() == name )
+ {
+ int i = 0;
+ int alpha = 0; // signature of parameters
+ // parameters sont-ils compatibles ?
+ CBotDefParam* pv = pt->m_Param; // list of expected parameters
+ CBotVar* pw = ppVars[i++]; // list of provided parameters
+ while ( pv != NULL && pw != NULL)
+ {
+ if (!TypesCompatibles(pv->GivTypResult(), pw->GivTypResult()))
+ {
+ if ( pFunc == NULL ) TypeOrError = TX_BADPARAM;
+ break;
+ }
+ int d = pv->GivType() - pw->GivType(2);
+ alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+
+ pv = pv->GivNext();
+ pw = ppVars[i++];
+ }
+ if ( pw != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_LOWPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL)) TypeOrError.SetType(TX_OVERPARAM);
+ continue; // to many parameters
+ }
+ if ( pv != NULL )
+ {
+ if ( pFunc != NULL ) continue;
+ if ( TypeOrError.Eq(TX_OVERPARAM) ) TypeOrError.SetType(TX_NUMPARAM);
+ if ( TypeOrError.Eq(TX_UNDEFCALL) ) TypeOrError.SetType(TX_LOWPARAM);
+ continue; // not enough parameters
+ }
+
+ if (alpha == 0) // perfect signature
+ {
+ nIdent = pt->m_nFuncIdent;
+ TypeOrError = pt->m_retTyp;
+ return pt;
+ }
+
+ if ( alpha < delta ) // a better signature?
+ {
+ pFunc = pt;
+ delta = alpha;
+ }
+ }
+ }
+ }
+
+ if ( pFunc != NULL )
+ {
+ nIdent = pFunc->m_nFuncIdent;
+ TypeOrError = pFunc->m_retTyp;
+ return pFunc;
+ }
+ return NULL;
+}
+
+
+// fait un appel à une fonction
+
+int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken)
+{
+ CBotTypResult type;
+ CBotFunction* pt = NULL;
+
+ pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+
+ if ( pt != NULL )
+ {
+ CBotStack* pStk1 = pStack->AddStack(pt, 2); // to put "this"
+// if ( pStk1 == EOX ) return true;
+
+ pStk1->SetBotCall(pt->m_pProg); // it may have changed module
+
+ if ( pStk1->IfStep() ) return false;
+
+ CBotStack* pStk3 = pStk1->AddStack(NULL, true); // parameters
+
+ // preparing parameters on the stack
+
+ if ( pStk1->GivState() == 0 )
+ {
+ if ( !pt->m_MasterClass.IsEmpty() )
+ {
+ CBotVar* pInstance = m_pProg->m_pInstance;
+ // make "this" known
+ CBotVar* pThis ;
+ if ( pInstance == NULL )
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypClass, pt->m_MasterClass ));
+ pThis->SetInit(2);
+ }
+ else
+ {
+ pThis = CBotVar::Create("this", CBotTypResult( CBotTypPointer, pt->m_MasterClass ));
+ pThis->SetPointer(pInstance);
+ pThis->SetInit(2);
+ }
+
+ pThis->SetUniqNum(-2);
+ pStk1->AddVar(pThis);
+
+ }
+
+ // initializes the variables as parameters
+ pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted
+
+ pStk1->IncState();
+ }
+
+ // finally execution of the found function
+
+ if ( !pStk3->GivRetVar( // puts the result on the stack
+ pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted
+ {
+ if ( !pStk3->IsOk() && pt->m_pProg != m_pProg )
+ {
+#ifdef _DEBUG
+ if ( m_pProg->GivFunctions()->GivName() == "LaCommande" ) return false;
+#endif
+ pStk3->SetPosError(pToken); // indicates the error on the procedure call
+ }
+ return false; // interrupt !
+ }
+
+ return pStack->Return( pStk3 );
+ }
+ return -1;
+}
+
+void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar** ppVars, CBotStack* pStack)
+{
+ CBotTypResult type;
+ CBotFunction* pt = NULL;
+ CBotStack* pStk1;
+ CBotStack* pStk3;
+
+ // search function to return the ok identifier
+
+ pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+
+ if ( pt != NULL )
+ {
+ pStk1 = pStack->RestoreStack(pt);
+ if ( pStk1 == NULL ) return;
+
+ pStk1->SetBotCall(pt->m_pProg); // it may have changed module
+
+ if ( pStk1->GivBlock() < 2 )
+ {
+ CBotStack* pStk2 = pStk1->RestoreStack(NULL); // used more
+ if ( pStk2 == NULL ) return;
+ pStk3 = pStk2->RestoreStack(NULL);
+ if ( pStk3 == NULL ) return;
+ }
+ else
+ {
+ pStk3 = pStk1->RestoreStack(NULL);
+ if ( pStk3 == NULL ) return;
+ }
+
+ // preparing parameters on the stack
+
+ {
+ if ( !pt->m_MasterClass.IsEmpty() )
+ {
+ CBotVar* pInstance = m_pProg->m_pInstance;
+ // make "this" known
+ CBotVar* pThis = pStk1->FindVar("this");
+ pThis->SetInit(2);
+ pThis->SetUniqNum(-2);
+ }
+ }
+
+ if ( pStk1->GivState() == 0 )
+ {
+ pt->m_Param->RestoreState(pStk3, true);
+ return;
+ }
+
+ // initializes the variables as parameters
+ pt->m_Param->RestoreState(pStk3, false);
+ pt->m_Block->RestoreState(pStk3, true);
+ }
+}
+
+
+
+// makes call of a method
+// note: this is already on the stack, the pointer pThis is just to simplify
+
+int CBotFunction::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotToken* pToken, CBotClass* pClass)
+{
+ CBotTypResult type;
+ CBotProgram* pProgCurrent = pStack->GivBotCall();
+
+ CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type, false);
+
+ if ( pt != NULL )
+ {
+// DEBUG( "CBotFunction::DoCall" + pt->GivName(), 0, pStack);
+
+ CBotStack* pStk = pStack->AddStack(pt, 2);
+// if ( pStk == EOX ) return true;
+
+ pStk->SetBotCall(pt->m_pProg); // it may have changed module
+ CBotStack* pStk3 = pStk->AddStack(NULL, true); // to set parameters passed
+
+ // preparing parameters on the stack
+
+ if ( pStk->GivState() == 0 )
+ {
+ // sets the variable "this" on the stack
+ CBotVar* pthis = CBotVar::Create("this", CBotTypNullPointer);
+ pthis->Copy(pThis, false);
+ pthis->SetUniqNum(-2); // special value
+ pStk->AddVar(pthis);
+
+ CBotClass* pClass = pThis->GivClass()->GivParent();
+ if ( pClass )
+ {
+ // sets the variable "super" on the stack
+ CBotVar* psuper = CBotVar::Create("super", CBotTypNullPointer);
+ psuper->Copy(pThis, false); // in fact identical to "this"
+ psuper->SetUniqNum(-3); // special value
+ pStk->AddVar(psuper);
+ }
+ // initializes the variables as parameters
+ pt->m_Param->Execute(ppVars, pStk3); // cannot be interrupted
+ pStk->IncState();
+ }
+
+ if ( pStk->GivState() == 1 )
+ {
+ if ( pt->m_bSynchro )
+ {
+ CBotProgram* pProgBase = pStk->GivBotCall(true);
+ if ( !pClass->Lock(pProgBase) ) return false; // expected to power \TODO attend de pouvoir
+ }
+ pStk->IncState();
+ }
+ // finally calls the found function
+
+ if ( !pStk3->GivRetVar( // puts the result on the stack
+ pt->m_Block->Execute(pStk3) )) // GivRetVar said if it is interrupted
+ {
+ if ( !pStk3->IsOk() )
+ {
+ if ( pt->m_bSynchro )
+ {
+ pClass->Unlock(); // release function
+ }
+
+ if ( pt->m_pProg != pProgCurrent )
+ {
+ pStk3->SetPosError(pToken); // indicates the error on the procedure call
+ }
+ }
+ return false; // interrupt !
+ }
+
+ if ( pt->m_bSynchro )
+ {
+ pClass->Unlock(); // release function
+ }
+
+ return pStack->Return( pStk3 );
+ }
+ return -1;
+}
+
+void CBotFunction::RestoreCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotStack* pStack, CBotClass* pClass)
+{
+ CBotTypResult type;
+ CBotFunction* pt = FindLocalOrPublic(nIdent, name, ppVars, type);
+
+ if ( pt != NULL )
+ {
+ CBotStack* pStk = pStack->RestoreStack(pt);
+ if ( pStk == NULL ) return;
+ pStk->SetBotCall(pt->m_pProg); // it may have changed module
+
+ CBotVar* pthis = pStk->FindVar("this");
+ pthis->SetUniqNum(-2);
+
+ CBotStack* pStk3 = pStk->RestoreStack(NULL); // to set parameters passed
+ if ( pStk3 == NULL ) return;
+
+ pt->m_Param->RestoreState(pStk3, true); // parameters
+
+ if ( pStk->GivState() > 1 && // latching is effective?
+ pt->m_bSynchro )
+ {
+ CBotProgram* pProgBase = pStk->GivBotCall(true);
+ pClass->Lock(pProgBase); // locks the class
+ }
+
+ // finally calls the found function
+
+ pt->m_Block->RestoreState(pStk3, true); // interrupt !
+ }
+}
+
+// see if the "signature" of parameters is identical
+bool CBotFunction::CheckParam(CBotDefParam* pParam)
+{
+ CBotDefParam* pp = m_Param;
+ while ( pp != NULL && pParam != NULL )
+ {
+ CBotTypResult type1 = pp->GivType();
+ CBotTypResult type2 = pParam->GivType();
+ if ( !type1.Compare(type2) ) return false;
+ pp = pp->GivNext();
+ pParam = pParam->GivNext();
+ }
+ return ( pp == NULL && pParam == NULL );
+}
+
+CBotString CBotFunction::GivName()
+{
+ return m_token.GivString();
+}
+
+CBotString CBotFunction::GivParams()
+{
+ if ( m_Param == NULL ) return CBotString("()");
+
+ CBotString params = "( ";
+ CBotDefParam* p = m_Param; // list of parameters
+
+ while (p != NULL)
+ {
+ params += p->GivParamString();
+ p = p->GivNext();
+ if ( p != NULL ) params += ", ";
+ }
+
+ params += " )";
+ return params;
+}
+
+CBotFunction* CBotFunction::Next()
+{
+ return m_next;
+}
+
+void CBotFunction::AddPublic(CBotFunction* func)
+{
+ if ( m_listPublic != NULL )
+ {
+ func->m_nextpublic = m_listPublic;
+ m_listPublic->m_prevpublic = func;
+ }
+ m_listPublic = func;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////
+// management of parameters
+
+
+CBotDefParam::CBotDefParam()
+{
+ m_next = NULL;
+ m_nIdent = 0;
+}
+
+CBotDefParam::~CBotDefParam()
+{
+ delete m_next;
+}
+
+
+// compiles a list of parameters
+CBotDefParam* CBotDefParam::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ // mainly not pStack->TokenStack here
+ // declared variables must remain visible thereafter
+
+ pStack->SetStartError(p->GivStart());
+
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ CBotDefParam* list = NULL;
+
+ while (!IsOfType(p, ID_CLOSEPAR))
+ {
+ CBotDefParam* param = new CBotDefParam();
+ if (list == NULL) list = param;
+ else list->AddNext(param); // added to the list
+
+ CBotClass* pClass = NULL;//= CBotClass::Find(p);
+ param->m_typename = p->GivString();
+ CBotTypResult type = param->m_type = TypeParam(p, pStack);
+// if ( type == CBotTypPointer ) type = CBotTypClass; // we must create a new object
+
+ if (param->m_type.GivType() > 0)
+ {
+ CBotToken* pp = p;
+ param->m_token = *p;
+ if (pStack->IsOk() && IsOfType(p, TokenTypVar) )
+ {
+
+ // variable already declared?
+ if (pStack->CheckVarLocal(pp))
+ {
+ pStack->SetError(TX_REDEFVAR, pp);
+ break;
+ }
+
+ if ( type.Eq(CBotTypArrayPointer) ) type.SetType(CBotTypArrayBody);
+ CBotVar* var = CBotVar::Create(pp->GivString(), type); // creates the variable
+// if ( pClass ) var->SetClass(pClass);
+ var->SetInit(2); // mark initialized
+ param->m_nIdent = CBotVar::NextUniqNum();
+ var->SetUniqNum(param->m_nIdent);
+ pStack->AddVar(var); // place on the stack
+
+ if (IsOfType(p, ID_COMMA) || p->GivType() == ID_CLOSEPAR)
+ continue;
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ pStack->SetError(TX_NOTYP, p);
+ delete list;
+ return NULL;
+ }
+ return list;
+ }
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ return NULL;
+}
+
+void CBotDefParam::AddNext(CBotDefParam* p)
+{
+ CBotDefParam* pp = this;
+ while (pp->m_next != NULL) pp = pp->m_next;
+
+ pp->m_next = p;
+}
+
+
+bool CBotDefParam::Execute(CBotVar** ppVars, CBotStack* &pj)
+{
+ int i = 0;
+ CBotDefParam* p = this;
+
+ while ( p != NULL )
+ {
+ // creates a local variable on the stack
+ CBotVar* newvar = CBotVar::Create(p->m_token.GivString(), p->m_type);
+
+ // serves to make the transformation of types:
+ if ( ppVars != NULL && ppVars[i] != NULL )
+ {
+ switch (p->m_type.GivType())
+ {
+ case CBotTypInt:
+ newvar->SetValInt(ppVars[i]->GivValInt());
+ break;
+ case CBotTypFloat:
+ newvar->SetValFloat(ppVars[i]->GivValFloat());
+ break;
+ case CBotTypString:
+ newvar->SetValString(ppVars[i]->GivValString());
+ break;
+ case CBotTypBoolean:
+ newvar->SetValInt(ppVars[i]->GivValInt());
+ break;
+ case CBotTypIntrinsic:
+ ((CBotVarClass*)newvar)->Copy(ppVars[i], false);
+ break;
+ case CBotTypPointer:
+ case CBotTypArrayPointer:
+ {
+ newvar->SetPointer(ppVars[i]->GivPointer());
+ }
+ break;
+ default:
+ ASM_TRAP();
+ }
+ }
+ newvar->SetUniqNum(p->m_nIdent);
+ pj->AddVar(newvar); // add a variable
+ p = p->m_next;
+ i++;
+ }
+
+ return true;
+}
+
+void CBotDefParam::RestoreState(CBotStack* &pj, bool bMain)
+{
+ int i = 0;
+ CBotDefParam* p = this;
+
+ while ( p != NULL )
+ {
+ // creates a local variable on the stack
+ CBotVar* var = pj->FindVar(p->m_token.GivString());
+ var->SetUniqNum(p->m_nIdent);
+ p = p->m_next;
+ }
+}
+
+int CBotDefParam::GivType()
+{
+ return m_type.GivType();
+}
+
+CBotTypResult CBotDefParam::GivTypResult()
+{
+ return m_type;
+}
+
+CBotDefParam* CBotDefParam::GivNext()
+{
+ return m_next;
+}
+
+CBotString CBotDefParam::GivParamString()
+{
+ CBotString param;
+
+ param = m_typename;
+ param += ' ';
+
+ param += m_token.GivString();
+ return param;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// return parameters
+
+CBotReturn::CBotReturn()
+{
+ m_Instr = NULL;
+ name = "CBotReturn"; // debug
+}
+
+CBotReturn::~CBotReturn()
+{
+ delete m_Instr;
+}
+
+CBotInstr* CBotReturn::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p;
+
+ if (!IsOfType(p, ID_RETURN)) return NULL; // should never happen
+
+ CBotReturn* inst = new CBotReturn(); // creates the object
+ inst->SetToken( pp );
+
+ CBotTypResult type = pStack->GivRetType();
+
+ if ( type.GivType() == 0 ) // returned void ?
+ {
+ if ( IsOfType( p, ID_SEP ) ) return inst;
+ pStack->SetError( TX_BADTYPE, pp );
+ return NULL;
+ }
+
+ inst->m_Instr = CBotExpression::Compile(p, pStack);
+ if ( pStack->IsOk() )
+ {
+ CBotTypResult retType = pStack->GivTypResult(2);
+ if (TypeCompatible(retType, type, ID_ASS))
+ {
+ if ( IsOfType( p, ID_SEP ) )
+ return inst;
+
+ pStack->SetError(TX_ENDOF, p->GivStart());
+ }
+ pStack->SetError(TX_BADTYPE, p->GivStart());
+ }
+
+ delete inst;
+ return NULL; // no object, the error is on the stack
+}
+
+bool CBotReturn::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+// if ( pile == EOX ) return true;
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( m_Instr != NULL && !m_Instr->Execute(pile) ) return false; // evaluate the result
+ // the result is on the stack
+ pile->IncState();
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ pile->SetBreak(3, CBotString());
+ return pj->Return(pile);
+}
+
+void CBotReturn::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( m_Instr != NULL ) m_Instr->RestoreState(pile, bMain); // evaluate the result
+ return;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Calls of these functions
+
+CBotInstrCall::CBotInstrCall()
+{
+ m_Parameters = NULL;
+ m_nFuncIdent = 0;
+ name = "CBotInstrCall";
+}
+
+CBotInstrCall::~CBotInstrCall()
+{
+ delete m_Parameters;
+}
+
+CBotInstr* CBotInstrCall::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotVar* ppVars[1000];
+
+ int i = 0;
+
+ CBotToken* pp = p;
+ p = p->GivNext();
+
+ pStack->SetStartError(p->GivStart());
+ CBotCStack* pile = pStack;
+
+ if ( IsOfType(p, ID_OPENPAR) )
+ {
+ int start, end;
+ CBotInstrCall* inst = new CBotInstrCall();
+ inst->SetToken(pp);
+
+ // compile la list of parameters
+ if (!IsOfType(p, ID_CLOSEPAR)) while (true)
+ {
+ start = p->GivStart();
+ pile = pile->TokenStack(); // keeps the results on the stack
+
+ CBotInstr* param = CBotExpression::Compile(p, pile);
+ end = p->GivStart();
+ if ( inst->m_Parameters == NULL ) inst->m_Parameters = param;
+ else inst->m_Parameters->AddNext(param); // constructs the list
+
+ if ( !pile->IsOk() )
+ {
+ delete inst;
+ return pStack->Return(NULL, pile);
+ }
+
+ if ( param != NULL )
+ {
+ if ( pile->GivTypResult().Eq(99) )
+ {
+ delete pStack->TokenStack();
+ pStack->SetError(TX_VOID, p->GivStart());
+ delete inst;
+ return NULL;
+ }
+ ppVars[i] = pile->GivVar();
+ ppVars[i]->GivToken()->SetPos(start, end);
+ i++;
+
+ if (IsOfType(p, ID_COMMA)) continue; // skips the comma
+ if (IsOfType(p, ID_CLOSEPAR)) break;
+ }
+
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ delete pStack->TokenStack();
+ delete inst;
+ return NULL;
+ }
+ ppVars[i] = NULL;
+
+ // the routine is known?
+// CBotClass* pClass = NULL;
+ inst->m_typRes = pStack->CompileCall(pp, ppVars, inst->m_nFuncIdent);
+ if ( inst->m_typRes.GivType() >= 20 )
+ {
+// if (pVar2!=NULL) pp = pVar2->RetToken();
+ pStack->SetError( inst->m_typRes.GivType(), pp );
+ delete pStack->TokenStack();
+ delete inst;
+ return NULL;
+ }
+
+ delete pStack->TokenStack();
+ if ( inst->m_typRes.GivType() > 0 )
+ {
+ CBotVar* pRes = CBotVar::Create("", inst->m_typRes);
+ pStack->SetVar(pRes); // for knowing the type of the result
+ }
+ else pStack->SetVar(NULL); // routine returns void
+
+ return inst;
+ }
+ p = pp;
+ delete pStack->TokenStack();
+ return NULL;
+}
+
+bool CBotInstrCall::Execute(CBotStack* &pj)
+{
+ CBotVar* ppVars[1000];
+ CBotStack* pile = pj->AddStack(this);
+ if ( pile->StackOver() ) return pj->Return( pile );
+
+ CBotStack* pile1 = pile;
+
+ int i = 0;
+
+ CBotInstr* p = m_Parameters;
+ // evaluates parameters
+ // and places the values ​​on the stack
+ // for allow of interruption at any time
+ if ( p != NULL) while ( true )
+ {
+ pile = pile->AddStack(); // place on the stack for the results
+ if ( pile->GivState() == 0 )
+ {
+ if (!p->Execute(pile)) return false; // interrupted here?
+ pile->SetState(1); // mark as special for reknowed parameters \TODO marque spéciale pour reconnaîre parameters
+ }
+ ppVars[i++] = pile->GivVar();
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotStack* pile2 = pile->AddStack();
+ if ( pile2->IfStep() ) return false;
+
+ if ( !pile2->ExecuteCall(m_nFuncIdent, GivToken(), ppVars, m_typRes)) return false; // interrupt
+
+ return pj->Return(pile2); // release the entire stack
+}
+
+void CBotInstrCall::RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ CBotStack* pile1 = pile;
+
+ int i = 0;
+ CBotVar* ppVars[1000];
+ CBotInstr* p = m_Parameters;
+ // evaluate parameters
+ // and place the values on the stack
+ // for allow of interruption at any time
+ if ( p != NULL) while ( true )
+ {
+ pile = pile->RestoreStack(); // place on the stack for the results
+ if ( pile == NULL ) return;
+ if ( pile->GivState() == 0 )
+ {
+ p->RestoreState(pile, bMain); // interrupt here!
+ return;
+ }
+ ppVars[i++] = pile->GivVar(); // constructs the list of parameters
+ p = p->GivNext();
+ if ( p == NULL) break;
+ }
+ ppVars[i] = NULL;
+
+ CBotStack* pile2 = pile->RestoreStack();
+ if ( pile2 == NULL ) return;
+
+ pile2->RestoreCall(m_nFuncIdent, GivToken(), ppVars);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// statement of user classes
+
+// pre-compile a new class
+// analysis is complete except the body of routines
+
+CBotClass* CBotClass::Compile1(CBotToken* &p, CBotCStack* pStack)
+{
+ if ( !IsOfType(p, ID_PUBLIC) )
+ {
+ pStack->SetError(TX_NOPUBLIC, p);
+ return NULL;
+ }
+
+ if ( !IsOfType(p, ID_CLASS) ) return NULL;
+
+ CBotString name = p->GivString();
+
+ CBotClass* pOld = CBotClass::Find(name);
+ if ( pOld != NULL && pOld->m_IsDef )
+ {
+ pStack->SetError( TX_REDEFCLASS, p );
+ return NULL;
+ }
+
+ // a name of the class is there?
+ if (IsOfType(p, TokenTypVar))
+ {
+ CBotClass* pPapa = NULL;
+ if ( IsOfType( p, ID_EXTENDS ) )
+ {
+ CBotString name = p->GivString();
+ pPapa = CBotClass::Find(name);
+
+ if (!IsOfType(p, TokenTypVar) || pPapa == NULL )
+ {
+ pStack->SetError( TX_NOCLASS, p );
+ return NULL;
+ }
+ }
+ CBotClass* classe = (pOld == NULL) ? new CBotClass(name, pPapa) : pOld;
+ classe->Purge(); // emptythe old definitions
+ classe->m_IsDef = false; // current definition
+
+ if ( !IsOfType( p, ID_OPBLK) )
+ {
+ pStack->SetError(TX_OPENBLK, p);
+ return NULL;
+ }
+
+ while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
+ {
+ classe->CompileDefItem(p, pStack, false);
+ }
+
+ if (pStack->IsOk()) return classe;
+ }
+ pStack->SetError(TX_ENDOF, p);
+ return NULL;
+}
+
+bool CBotClass::CompileDefItem(CBotToken* &p, CBotCStack* pStack, bool bSecond)
+{
+ bool bStatic = false;
+ int mProtect = PR_PUBLIC;
+ bool bSynchro = false;
+
+ while (IsOfType(p, ID_SEP)) ;
+
+ CBotTypResult type( -1 );
+
+ if ( IsOfType(p, ID_SYNCHO) ) bSynchro = true;
+ CBotToken* pBase = p;
+
+ if ( IsOfType(p, ID_STATIC) ) bStatic = true;
+ if ( IsOfType(p, ID_PUBLIC) ) mProtect = PR_PUBLIC;
+ if ( IsOfType(p, ID_PRIVATE) ) mProtect = PR_PRIVATE;
+ if ( IsOfType(p, ID_PROTECTED) ) mProtect = PR_PROTECT;
+ if ( IsOfType(p, ID_STATIC) ) bStatic = true;
+
+// CBotClass* pClass = NULL;
+ type = TypeParam(p, pStack); // type of the result
+
+ if ( type.Eq(-1) )
+ {
+ pStack->SetError(TX_NOTYP, p);
+ return false;
+ }
+
+ while (pStack->IsOk())
+ {
+ CBotToken* pp = p;
+ IsOfType(p, ID_NOT); // skips ~ eventual (destructor)
+
+ if (IsOfType(p, TokenTypVar))
+ {
+ CBotInstr* limites = NULL;
+ while ( IsOfType( p, ID_OPBRK ) ) // a table?
+ {
+ CBotInstr* i = NULL;
+
+ if ( p->GivType() != ID_CLBRK )
+ i = CBotExpression::Compile( p, pStack ); // expression for the value
+ else
+ i = new CBotEmpty(); // special if not a formula
+
+ type = CBotTypResult(CBotTypArrayPointer, type);
+
+ if (!pStack->IsOk() || !IsOfType( p, ID_CLBRK ) )
+ {
+ pStack->SetError(TX_CLBRK, p->GivStart());
+ return false;
+ }
+
+/* CBotVar* pv = pStack->GivVar();
+ if ( pv->GivType()>= CBotTypBoolean )
+ {
+ pStack->SetError(TX_BADTYPE, p->GivStart());
+ return false;
+ }*/
+
+ if (limites == NULL) limites = i;
+ else limites->AddNext3(i);
+ }
+
+ if ( p->GivType() == ID_OPENPAR )
+ {
+ if ( !bSecond )
+ {
+ p = pBase;
+ CBotFunction* f =
+ CBotFunction::Compile1(p, pStack, this);
+
+ if ( f == NULL ) return false;
+
+ if (m_pMethod == NULL) m_pMethod = f;
+ else m_pMethod->AddNext(f);
+ }
+ else
+ {
+ // return a method precompiled in pass 1
+ CBotFunction* pf = m_pMethod;
+ CBotFunction* prev = NULL;
+ while ( pf != NULL )
+ {
+ if (pf->GivName() == pp->GivString()) break;
+ prev = pf;
+ pf = pf->Next();
+ }
+
+ bool bConstructor = (pp->GivString() == GivName());
+ CBotCStack* pile = pStack->TokenStack(NULL, true);
+
+ // make "this" known
+ CBotToken TokenThis(CBotString("this"), CBotString());
+ CBotVar* pThis = CBotVar::Create(&TokenThis, CBotTypResult( CBotTypClass, this ) );
+ pThis->SetUniqNum(-2);
+ pile->AddVar(pThis);
+
+ if ( m_pParent )
+ {
+ // makes "super" known
+ CBotToken TokenSuper(CBotString("super"), CBotString());
+ CBotVar* pThis = CBotVar::Create(&TokenSuper, CBotTypResult( CBotTypClass, m_pParent ) );
+ pThis->SetUniqNum(-3);
+ pile->AddVar(pThis);
+ }
+
+// int num = 1;
+ CBotClass* my = this;
+ while (my != NULL)
+ {
+ // places a copy of variables of a class (this) on a stack
+ CBotVar* pv = my->m_pVar;
+ while (pv != NULL)
+ {
+ CBotVar* pcopy = CBotVar::Create(pv);
+ pcopy->SetInit(!bConstructor || pv->IsStatic());
+ pcopy->SetUniqNum(pv->GivUniqNum());
+ pile->AddVar(pcopy);
+ pv = pv->GivNext();
+ }
+ my = my->m_pParent;
+ }
+
+ // compiles a method
+ p = pBase;
+ CBotFunction* f =
+ CBotFunction::Compile(p, pile, NULL/*, false*/);
+
+ if ( f != NULL )
+ {
+ f->m_pProg = pStack->GivBotCall();
+ f->m_bSynchro = bSynchro;
+ // replaces the element in the chain
+ f->m_next = pf->m_next;
+ pf->m_next = NULL;
+ delete pf;
+ if (prev == NULL) m_pMethod = f;
+ else prev->m_next = f;
+ }
+ pStack->Return(NULL, pile);
+ }
+
+ return pStack->IsOk();
+ }
+
+ // definition of an element
+ if (type.Eq(0))
+ {
+ pStack->SetError(TX_ENDOF, p);
+ return false;
+ }
+
+ CBotInstr* i = NULL;
+ if ( IsOfType(p, ID_ASS ) )
+ {
+ if ( type.Eq(CBotTypArrayPointer) )
+ {
+ i = CBotListArray::Compile(p, pStack, type.GivTypElem());
+ }
+ else
+ {
+ // it has an assignmet to calculate
+ i = CBotTwoOpExpr::Compile(p, pStack);
+ }
+ if ( !pStack->IsOk() ) return false;
+ }
+
+
+ if ( !bSecond )
+ {
+ CBotVar* pv = CBotVar::Create(pp->GivString(), type);
+ pv -> SetStatic( bStatic );
+ pv -> SetPrivate( mProtect );
+
+ AddItem( pv );
+
+ pv->m_InitExpr = i;
+ pv->m_LimExpr = limites;
+
+
+ if ( pv->IsStatic() && pv->m_InitExpr != NULL )
+ {
+ CBotStack* pile = CBotStack::FirstStack(); // independent stack
+ while(pile->IsOk() && !pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer
+ pv->SetVal( pile->GivVar() ) ;
+ pile->Delete();
+ }
+ }
+ else
+ delete i;
+
+ if ( IsOfType(p, ID_COMMA) ) continue;
+ if ( IsOfType(p, ID_SEP) ) break;
+ }
+ pStack->SetError(TX_ENDOF, p);
+ }
+ return pStack->IsOk();
+}
+
+
+CBotClass* CBotClass::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ if ( !IsOfType(p, ID_PUBLIC) ) return NULL;
+ if ( !IsOfType(p, ID_CLASS) ) return NULL;
+
+ CBotString name = p->GivString();
+
+ // a name for the class is there?
+ if (IsOfType(p, TokenTypVar))
+ {
+ // the class was created by Compile1
+ CBotClass* pOld = CBotClass::Find(name);
+
+ if ( IsOfType( p, ID_EXTENDS ) )
+ {
+ IsOfType(p, TokenTypVar); // necessarily
+ }
+ IsOfType( p, ID_OPBLK); // necessarily
+
+ while ( pStack->IsOk() && !IsOfType( p, ID_CLBLK ) )
+ {
+ pOld->CompileDefItem(p, pStack, true);
+ }
+
+ pOld->m_IsDef = true; // complete definition
+ if (pStack->IsOk()) return pOld;
+ }
+ pStack->SetError(TX_ENDOF, p);
+ return NULL;
+}
diff --git a/src/CBot/CBotIf.cpp b/src/CBot/CBotIf.cpp
index 626ef0d..84dbd6a 100644
--- a/src/CBot/CBotIf.cpp
+++ b/src/CBot/CBotIf.cpp
@@ -1,159 +1,161 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// instruction if (condition) opération1 else opération2;
-
-#include "CBot.h"
-
-// les divers constructeurs / destructeurs
-CBotIf::CBotIf()
-{
- m_Condition =
- m_Block =
- m_BlockElse = NULL; // NULL pour pouvoir faire delete directement
- name = "CBotIf"; // debug
-}
-
-CBotIf::~CBotIf()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction1
- delete m_BlockElse; // libère le bloc d'instruction2
-}
-
-// compilation (routine statique)
-// appelé lorsque le token "if" a été trouvé
-
-CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p; // conserve le ^au token (début instruction)
-
- if (!IsOfType(p, ID_IF)) return NULL; // ne doit jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- CBotIf* inst = new CBotIf(); // crée l'object
- inst->SetToken( pp );
-
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe bel et bien
-
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (peut être vide)
-
- // regarde si l'instruction suivante est le token "else"
- if (IsOfType(p, ID_ELSE))
- {
- // si oui, compile le bloc d'instruction qui suit
- inst->m_BlockElse = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- if (!pStk->IsOk())
- {
- // il n'y a pas de bloc correct après le else
- // libère l'objet, et transmet l'erreur qui est sur la pile
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- }
-
- // rend l'object correct à qui le demande.
- return pStack->Return(inst, pStk);
- }
- }
-
- // erreur, libère l'objet
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile.
- return pStack->Return(NULL, pStk);
-}
-
-
-// exécution de l'instruction
-
-BOOL CBotIf :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- // selon la reprise, on peut être dans l'un des 2 états
- if( pile->GivState() == 0 )
- {
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return FALSE; // interrompu ici ?
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // passe dans le second état
- if (!pile->SetState(1)) return FALSE; // prêt pour la suite
- }
-
- // second état, évalue les instructions associées
- // le résultat de la condition est sur la pile
-
- if ( pile->GivVal() == TRUE ) // condition était vraie ?
- {
- if ( m_Block != NULL && // bloc peut être absent
- !m_Block->Execute(pile) ) return FALSE; // interrompu ici ?
- }
- else
- {
- if ( m_BlockElse != NULL && // s'il existe un bloc alternatif
- !m_BlockElse->Execute(pile) ) return FALSE; // interrompu ici
- }
-
- // transmet le résultat et libère la pile
- return pj->Return(pile);
-}
-
-
-void CBotIf :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- // selon la reprise, on peut être dans l'un des 2 états
- if( pile->GivState() == 0 )
- {
- // évalue la condition
- m_Condition->RestoreState(pile, bMain); // interrompu ici !
- return;
- }
-
- // second état, évalue les instructions associées
- // le résultat de la condition est sur la pile
-
- if ( pile->GivVal() == TRUE ) // condition était vraie ?
- {
- if ( m_Block != NULL ) // bloc peut être absent
- m_Block->RestoreState(pile, bMain); // interrompu ici !
- }
- else
- {
- if ( m_BlockElse != NULL ) // s'il existe un bloc alternatif
- m_BlockElse->RestoreState(pile, bMain); // interrompu ici !
- }
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+///////////////////////////////////////////////////////////////////////
+// instruction if (condition) operation1 else operation2;
+
+#include "CBot.h"
+
+// various constructors / destructors
+CBotIf::CBotIf()
+{
+ m_Condition =
+ m_Block =
+ m_BlockElse = NULL; // NULL so that delete is not possible further
+ name = "CBotIf"; // debug
+}
+
+CBotIf::~CBotIf()
+{
+ delete m_Condition; // frees the condition
+ delete m_Block; // frees the block of instruction1
+ delete m_BlockElse; // frees the block of instruction2
+}
+
+// compilation (static routine)
+// called when the token "if" has been found
+
+CBotInstr* CBotIf::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p; // preserves at the ^ token (starting instruction)
+
+ if (!IsOfType(p, ID_IF)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ CBotIf* inst = new CBotIf(); // create the object
+ inst->SetToken( pp );
+
+ if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
+ {
+ // the condition does exist
+
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ if ( pStk->IsOk() )
+ {
+ // the statement block is ok (can be empty)
+
+ // see if the next instruction is the token "else"
+ if (IsOfType(p, ID_ELSE))
+ {
+ // if so, compiles the following statement block
+ inst->m_BlockElse = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ if (!pStk->IsOk())
+ {
+ // there is no correct block after the else
+ // frees the object, and transmits the error that is on the stack
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ }
+
+ // return the corrent object to the application
+ return pStack->Return(inst, pStk);
+ }
+ }
+
+ // error, frees the object
+ delete inst;
+ // and transmits the error that is on the stack.
+ return pStack->Return(NULL, pStk);
+}
+
+
+// execution of the instruction
+
+bool CBotIf :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or found in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ // according to recovery, it may be in one of two states
+ if( pile->GivState() == 0 )
+ {
+ // evaluates the condition
+ if ( !m_Condition->Execute(pile) ) return false; // interrupted here?
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // returns the results and releases the stack
+ }
+
+ // passes into the second state
+ if (!pile->SetState(1)) return false; // ready for further
+ }
+
+ // second state, evaluates the associated instructions
+ // the result of the condition is on the stack
+
+ if ( pile->GivVal() == true ) // condition was true?
+ {
+ if ( m_Block != NULL && // block may be absent
+ !m_Block->Execute(pile) ) return false; // interrupted here?
+ }
+ else
+ {
+ if ( m_BlockElse != NULL && // if there is an alternate block
+ !m_BlockElse->Execute(pile) ) return false; // interrupted here
+ }
+
+ // sends the results and releases the stack
+ return pj->Return(pile);
+}
+
+
+void CBotIf :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ // according to recovery, it may be in one of two states
+ if( pile->GivState() == 0 )
+ {
+ // evaluates the condition
+ m_Condition->RestoreState(pile, bMain); // interrupted here!
+ return;
+ }
+
+ // second state, evaluates the associated instructions
+ // the result of the condition is on the stack
+
+ if ( pile->GivVal() == true ) // condition was true?
+ {
+ if ( m_Block != NULL ) // block may be absent
+ m_Block->RestoreState(pile, bMain); // interrupted here!
+ }
+ else
+ {
+ if ( m_BlockElse != NULL ) // if there is an alternate block
+ m_BlockElse->RestoreState(pile, bMain); // interrupted here!
+ }
+}
+
diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp
index f157c4c..d9be052 100644
--- a/src/CBot/CBotProgram.cpp
+++ b/src/CBot/CBotProgram.cpp
@@ -1,1116 +1,1113 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.//////////////////////////////////////////////////////////////////////
-// gestion de base d'un programme CBot
-
-#include "CBot.h"
-#include <stdio.h>
-
-CBotProgram::CBotProgram()
-{
- m_Prog = NULL;
- m_pRun = NULL;
- m_pClass = NULL;
- m_pStack = NULL;
- m_pInstance = NULL;
-
- m_ErrorCode = 0;
- m_Ident = 0;
- m_bDebugDD = 0;
-}
-
-CBotProgram::CBotProgram(CBotVar* pInstance)
-{
- m_Prog = NULL;
- m_pRun = NULL;
- m_pClass = NULL;
- m_pStack = NULL;
- m_pInstance = pInstance;
-
- m_ErrorCode = 0;
- m_Ident = 0;
- m_bDebugDD = 0;
-}
-
-
-CBotProgram::~CBotProgram()
-{
-// delete m_pClass;
- m_pClass->Purge();
- m_pClass = NULL;
-
- CBotClass::FreeLock(this);
-
- delete m_Prog;
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
-}
-
-
-BOOL CBotProgram::Compile( const char* program, CBotStringArray& ListFonctions, void* pUser )
-{
- int error = 0;
- Stop();
-
-// delete m_pClass;
- m_pClass->Purge(); // purge les anciennes définitions des classes
- // mais sans détruire l'object
- m_pClass = NULL;
- delete m_Prog; m_Prog= NULL;
-
- ListFonctions.SetSize(0);
- m_ErrorCode = 0;
-
- if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
- pUser = m_pInstance->m_pUserPtr;
-
- // transforme le programme en Tokens
- CBotToken* pBaseToken = CBotToken::CompileTokens(program, error);
- if ( pBaseToken == NULL ) return FALSE;
-
-
- CBotCStack* pStack = new CBotCStack(NULL);
- CBotToken* p = pBaseToken->GivNext(); // saute le 1er token (séparateur)
-
- pStack->SetBotCall(this); // défini les routines utilisables
- CBotCall::SetPUser(pUser);
-
- // fait une première passe rapide juste pour prendre les entêtes de routines et de classes
- while ( pStack->IsOk() && p != NULL && p->GivType() != 0)
- {
- if ( IsOfType(p, ID_SEP) ) continue; // des point-virgules qui trainent
-
- if ( p->GivType() == ID_CLASS ||
- ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
- {
- CBotClass* nxt = CBotClass::Compile1(p, pStack);
- if (m_pClass == NULL ) m_pClass = nxt;
- else m_pClass->AddNext(nxt);
- }
- else
- {
- CBotFunction* next = CBotFunction::Compile1(p, pStack, NULL);
- if (m_Prog == NULL ) m_Prog = next;
- else m_Prog->AddNext(next);
- }
- }
- if ( !pStack->IsOk() )
- {
- m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
- delete m_Prog;
- m_Prog = NULL;
- delete pBaseToken;
- return FALSE;
- }
-
-// CBotFunction* temp = NULL;
- CBotFunction* next = m_Prog; // reprend la liste
-
- p = pBaseToken->GivNext(); // revient au début
-
- while ( pStack->IsOk() && p != NULL && p->GivType() != 0 )
- {
- if ( IsOfType(p, ID_SEP) ) continue; // des point-virgules qui trainent
-
- if ( p->GivType() == ID_CLASS ||
- ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
- {
- m_bCompileClass = TRUE;
- CBotClass::Compile(p, pStack); // complète la définition de la classe
- }
- else
- {
- m_bCompileClass = FALSE;
- CBotFunction::Compile(p, pStack, next);
- if (next->IsExtern()) ListFonctions.Add(next->GivName()/* + next->GivParams()*/);
- next->m_pProg = this; // garde le pointeur au module
- next = next->Next();
- }
- }
-
-// delete m_Prog; // la liste de la 1ère passe
-// m_Prog = temp; // la liste de la seconde passe
-
- if ( !pStack->IsOk() )
- {
- m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
- delete m_Prog;
- m_Prog = NULL;
- }
-
- delete pBaseToken;
- delete pStack;
-
- return (m_Prog != NULL);
-}
-
-
-BOOL CBotProgram::Start(const char* name)
-{
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
-
- m_pRun = m_Prog;
- while (m_pRun != NULL)
- {
- if ( m_pRun->GivName() == name ) break;
- m_pRun = m_pRun->m_next;
- }
-
- if ( m_pRun == NULL )
- {
- m_ErrorCode = TX_NORUN;
- return FALSE;
- }
-
-#if STACKMEM
- m_pStack = CBotStack::FirstStack();
-#else
- m_pStack = new CBotStack(NULL); // crée une pile d'exécution
-#endif
-
- m_pStack->SetBotCall(this); // bases pour les routines
-
- return TRUE; // on est prêt pour un Run()
-}
-
-BOOL CBotProgram::GetPosition(const char* name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
-{
- CBotFunction* p = m_Prog;
- while (p != NULL)
- {
- if ( p->GivName() == name ) break;
- p = p->m_next;
- }
-
- if ( p == NULL ) return FALSE;
-
- p->GetPosition(start, stop, modestart, modestop);
- return TRUE;
-}
-
-BOOL CBotProgram::Run(void* pUser, int timer)
-{
- BOOL ok;
-
- if (m_pStack == NULL || m_pRun == NULL) goto error;
-
- m_ErrorCode = 0;
- if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
- pUser = m_pInstance->m_pUserPtr;
-
- m_pStack->Reset(pUser); // vide l'éventuelle erreur précédente, et remet le timer
- if ( timer >= 0 ) m_pStack->SetTimer(timer);
-
- m_pStack->SetBotCall(this); // bases pour les routines
-
-#if STACKRUN
- // reprend l'exécution sur le haut de la pile
- ok = m_pStack->Execute();
- if ( ok )
- {
-#ifdef _DEBUG
- CBotVar* ppVar[3];
- ppVar[0] = CBotVar::Create("aa", CBotTypInt);
- ppVar[1] = CBotVar::Create("bb", CBotTypInt);
- ppVar[2] = NULL;
- ok = m_pRun->Execute(ppVar, m_pStack, m_pInstance);
-#else
- // revient sur l'exécution normale
- ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
-#endif
- }
-#else
- ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
-#endif
-
- // terminé sur une erreur ?
- if (!ok && !m_pStack->IsOk())
- {
- m_ErrorCode = m_pStack->GivError(m_ErrorStart, m_ErrorEnd);
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
- return TRUE; // exécution terminée !!
- }
-
- if ( ok ) m_pRun = NULL; // plus de fonction en exécution
- return ok;
-
-error:
- m_ErrorCode = TX_NORUN;
- return TRUE;
-}
-
-void CBotProgram::Stop()
-{
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
- m_pRun = NULL;
-}
-
-
-
-BOOL CBotProgram::GetRunPos(const char* &FunctionName, int &start, int &end)
-{
- FunctionName = NULL;
- start = end = 0;
- if (m_pStack == NULL) return FALSE;
-
- m_pStack->GetRunPos(FunctionName, start, end);
- return TRUE;
-}
-
-CBotVar* CBotProgram::GivStackVars(const char* &FunctionName, int level)
-{
- FunctionName = NULL;
- if (m_pStack == NULL) return NULL;
-
- return m_pStack->GivStackVars(FunctionName, level);
-}
-
-
-
-
-
-
-
-void CBotProgram::SetTimer(int n)
-{
- CBotStack::SetTimer( n );
-}
-
-int CBotProgram::GivError()
-{
- return m_ErrorCode;
-}
-
-void CBotProgram::SetIdent(long n)
-{
- m_Ident = n;
-}
-
-long CBotProgram::GivIdent()
-{
- return m_Ident;
-}
-
-BOOL CBotProgram::GetError(int& code, int& start, int& end)
-{
- code = m_ErrorCode;
- start = m_ErrorStart;
- end = m_ErrorEnd;
- return code > 0;
-}
-
-BOOL CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg)
-{
- code = m_ErrorCode;
- start = m_ErrorStart;
- end = m_ErrorEnd;
- pProg = this;
- return code > 0;
-}
-
-CBotString CBotProgram::GivErrorText(int code)
-{
- CBotString TextError;
-
- TextError.LoadString( code );
- if (TextError.IsEmpty())
- {
- char buf[100];
- sprintf(buf, "Exception numéro %d.", code);
- TextError = buf;
- }
- return TextError;
-}
-
-
-CBotFunction* CBotProgram::GivFunctions()
-{
- return m_Prog;
-}
-
-BOOL CBotProgram::AddFunction(const char* name,
- BOOL rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- // mémorise les pointeurs aux deux fonctions
- return CBotCall::AddFunction(name, rExec, rCompile);
-}
-
-
-BOOL WriteWord(FILE* pf, WORD w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( WORD ), 1, pf );
-
- return (lg == 1);
-}
-
-BOOL ReadWord(FILE* pf, WORD& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( WORD ), 1, pf );
-
- return (lg == 1);
-}
-
-BOOL WriteFloat(FILE* pf, float w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( float ), 1, pf );
-
- return (lg == 1);
-}
-
-BOOL ReadFloat(FILE* pf, float& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( float ), 1, pf );
-
- return (lg == 1);
-}
-
-BOOL WriteLong(FILE* pf, long w)
-{
- size_t lg;
-
- lg = fwrite(&w, sizeof( long ), 1, pf );
-
- return (lg == 1);
-}
-
-BOOL ReadLong(FILE* pf, long& w)
-{
- size_t lg;
-
- lg = fread(&w, sizeof( long ), 1, pf );
-
- return (lg == 1);
-}
-
-BOOL WriteString(FILE* pf, CBotString s)
-{
- size_t lg1, lg2;
-
- lg1 = s.GivLength();
- if (!WriteWord(pf, lg1)) return FALSE;
-
- lg2 = fwrite(s, 1, lg1, pf );
- return (lg1 == lg2);
-}
-
-BOOL ReadString(FILE* pf, CBotString& s)
-{
- WORD w;
- char buf[1000];
- size_t lg1, lg2;
-
- if (!ReadWord(pf, w)) return FALSE;
- lg1 = w;
- lg2 = fread(buf, 1, lg1, pf );
- buf[lg2] = 0;
-
- s = buf;
- return (lg1 == lg2);
-}
-
-BOOL WriteType(FILE* pf, CBotTypResult type)
-{
- int typ = type.GivType();
- if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
- if ( !WriteWord(pf, typ) ) return FALSE;
- if ( typ == CBotTypClass )
- {
- CBotClass* p = type.GivClass();
- if ( !WriteString(pf, p->GivName()) ) return FALSE;
- }
- if ( type.Eq( CBotTypArrayBody ) ||
- type.Eq( CBotTypArrayPointer ) )
- {
- if ( !WriteWord(pf, type.GivLimite()) ) return FALSE;
- if ( !WriteType(pf, type.GivTypElem()) ) return FALSE;
- }
- return TRUE;
-}
-
-BOOL ReadType(FILE* pf, CBotTypResult& type)
-{
- WORD w, ww;
- if ( !ReadWord(pf, w) ) return FALSE;
- type.SetType(w);
-
- if ( type.Eq( CBotTypIntrinsic ) )
- {
- type = CBotTypResult( w, "point" );
- }
-
- if ( type.Eq( CBotTypClass ) )
- {
- CBotString s;
- if ( !ReadString(pf, s) ) return FALSE;
- type = CBotTypResult( w, s );
- }
-
- if ( type.Eq( CBotTypArrayPointer ) ||
- type.Eq( CBotTypArrayBody ) )
- {
- CBotTypResult r;
- if ( !ReadWord(pf, ww) ) return FALSE;
- if ( !ReadType(pf, r) ) return FALSE;
- type = CBotTypResult( w, r );
- type.SetLimite((short)ww);
- }
- return TRUE;
-}
-
-
-BOOL CBotProgram::DefineNum(const char* name, long val)
-{
- return CBotToken::DefineNum(name, val);
-}
-
-
-BOOL CBotProgram::SaveState(FILE* pf)
-{
- if (!WriteWord( pf, CBOTVERSION)) return FALSE;
-
-
- if ( m_pStack != NULL )
- {
- if (!WriteWord( pf, 1)) return FALSE;
- if (!WriteString( pf, m_pRun->GivName() )) return FALSE;
- if (!m_pStack->SaveState(pf)) return FALSE;
- }
- else
- {
- if (!WriteWord( pf, 0)) return FALSE;
- }
- return TRUE;
-}
-
-
-BOOL CBotProgram::RestoreState(FILE* pf)
-{
- WORD w;
- CBotString s;
-
- Stop();
-
- if (!ReadWord( pf, w )) return FALSE;
- if ( w != CBOTVERSION ) return FALSE;
-
- if (!ReadWord( pf, w )) return FALSE;
- if ( w == 0 ) return TRUE;
-
- if (!ReadString( pf, s )) return FALSE;
- Start(s); // point de reprise
-
-#if STACKMEM
- m_pStack->Delete();
-#else
- delete m_pStack;
-#endif
- m_pStack = NULL;
-
- // récupère la pile depuis l'enregistrement
- // utilise un pointeur NULL (m_pStack) mais c'est ok comme ça
- if (!m_pStack->RestoreState(pf, m_pStack)) return FALSE;
- m_pStack->SetBotCall(this); // bases pour les routines
-
- // rétabli certains états dans la pile selon la structure
- m_pRun->RestoreState(NULL, m_pStack, m_pInstance);
- return TRUE;
-}
-
-int CBotProgram::GivVersion()
-{
- return CBOTVERSION;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////
-
-CBotCall* CBotCall::m_ListCalls = NULL;
-
-CBotCall::CBotCall(const char* name,
- BOOL rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- m_name = name;
- m_rExec = rExec;
- m_rComp = rCompile;
- m_next = NULL;
- m_nFuncIdent = CBotVar::NextUniqNum();
-}
-
-CBotCall::~CBotCall()
-{
- if (m_next) delete m_next;
- m_next = NULL;
-}
-
-void CBotCall::Free()
-{
- delete CBotCall::m_ListCalls;
-}
-
-BOOL CBotCall::AddFunction(const char* name,
- BOOL rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
- CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
-{
- CBotCall* p = m_ListCalls;
- CBotCall* pp = NULL;
-
- if ( p != NULL ) while ( p->m_next != NULL )
- {
- if ( p->GivName() == name )
- {
- // libère une fonction qu'on redéfini
- if ( pp ) pp->m_next = p->m_next;
- else m_ListCalls = p->m_next;
- pp = p;
- p = p->m_next;
- pp->m_next = NULL; // ne pas détruire la suite de la liste
- delete pp;
- continue;
- }
- pp = p; // pointeur précédent
- p = p->m_next;
- }
-
- pp = new CBotCall(name, rExec, rCompile);
-
- if (p) p->m_next = pp;
- else m_ListCalls = pp;
-
- return TRUE;
-}
-
-
-// transforme le tableau de pointeurs aux variables
-// en une liste de variables chaînées
-CBotVar* MakeListVars(CBotVar** ppVars, BOOL bSetVal=FALSE)
-{
- int i = 0;
- CBotVar* pVar = NULL;
-
- while( TRUE )
- {
- ppVars[i];
- if ( ppVars[i] == NULL ) break;
-
- CBotVar* pp = CBotVar::Create(ppVars[i]);
- if (bSetVal) pp->Copy(ppVars[i]);
- else
- if ( ppVars[i]->GivType() == CBotTypPointer )
- pp->SetClass( ppVars[i]->GivClass());
-// copier le pointeur selon indirection
- if (pVar == NULL) pVar = pp;
- else pVar->AddNext(pp);
- i++;
- }
- return pVar;
-}
-
-// trouve un appel acceptable selon le nom de la procédure
-// et les paramètres donnés
-
-CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent)
-{
- nIdent = 0;
- CBotCall* pt = m_ListCalls;
- CBotString name = p->GivString();
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- CBotVar* pVar = MakeListVars(ppVar);
- CBotVar* pVar2 = pVar;
- CBotTypResult r = pt->m_rComp(pVar2, m_pUser);
- int ret = r.GivType();
-
- // si une classe est retournée, c'est en fait un pointeur
- if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer );
-
- if ( ret > 20 )
- {
- if (pVar2) pStack->SetError(ret, p /*pVar2->GivToken()*/ );
- }
- delete pVar;
- nIdent = pt->m_nFuncIdent;
- return r;
- }
- pt = pt->m_next;
- }
- return -1;
-}
-
-void* CBotCall::m_pUser = NULL;
-
-void CBotCall::SetPUser(void* pUser)
-{
- m_pUser = pUser;
-}
-
-int CBotCall::CheckCall(const char* name)
-{
- CBotCall* p = m_ListCalls;
-
- while ( p != NULL )
- {
- if ( name == p->GivName() ) return TRUE;
- p = p->m_next;
- }
- return FALSE;
-}
-
-
-
-CBotString CBotCall::GivName()
-{
- return m_name;
-}
-
-CBotCall* CBotCall::Next()
-{
- return m_next;
-}
-
-
-int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype)
-{
- CBotCall* pt = m_ListCalls;
-
- if ( nIdent ) while ( pt != NULL )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- goto fund;
- }
- pt = pt->m_next;
- }
-
- pt = m_ListCalls;
-
- if ( token != NULL )
- {
- CBotString name = token->GivString();
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- nIdent = pt->m_nFuncIdent;
- goto fund;
- }
- pt = pt->m_next;
- }
- }
-
- return -1;
-
-fund:
-#if !STACKRUN
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVar, TRUE);
- CBotVar* pVarToDelete = pVar;
-
- // crée une variable pour le résultat
- CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
-
- CBotVar* pRes = pResult;
- int Exception = 0;
- int res = pt->m_rExec(pVar, pResult, Exception, pStack->GivPUser());
-
- if ( pResult != pRes ) delete pRes; // si résultat différent rendu
- delete pVarToDelete;
-
- if (res == FALSE)
- {
- if (Exception!=0)
- {
- pStack->SetError(Exception, token);
- }
- delete pResult;
- return FALSE;
- }
- pStack->SetVar(pResult);
-
- if ( rettype.GivType() > 0 && pResult == NULL )
- {
- pStack->SetError(TX_NORETVAL, token);
- }
- nIdent = pt->m_nFuncIdent;
- return TRUE;
-
-#else
-
- CBotStack* pile = pStack->AddStackEOX(pt);
- if ( pile == EOX ) return TRUE;
-
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVar, TRUE);
- CBotVar* pVarToDelete = pVar;
-
- // crée une variable pour le résultat
- CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
-
- pile->SetVar( pVar );
-
- CBotStack* pile2 = pile->AddStack();
- pile2->SetVar( pResult );
-
- pile->SetError(0, token); // pour la position en cas d'erreur + loin
- return pt->Run( pStack );
-
-#endif
-
-}
-
-#if STACKRUN
-
-BOOL CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack)
-{
- CBotCall* pt = m_ListCalls;
-
- {
- CBotString name = token->GivString();
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- nIdent = pt->m_nFuncIdent;
-
- CBotStack* pile = pStack->RestoreStackEOX(pt);
- if ( pile == NULL ) return TRUE;
-
- CBotStack* pile2 = pile->RestoreStack();
- return TRUE;
- }
- pt = pt->m_next;
- }
- }
-
- return FALSE;
-}
-
-BOOL CBotCall::Run(CBotStack* pStack)
-{
- CBotStack* pile = pStack->AddStackEOX(this);
- if ( pile == EOX ) return TRUE;
- CBotVar* pVar = pile->GivVar();
-
- CBotStack* pile2 = pile->AddStack();
- CBotVar* pResult = pile2->GivVar();
- CBotVar* pRes = pResult;
-
- int Exception = 0;
- int res = m_rExec(pVar, pResult, Exception, pStack->GivPUser());
-
- if (res == FALSE)
- {
- if (Exception!=0)
- {
- pStack->SetError(Exception);
- }
- if ( pResult != pRes ) delete pResult; // si résultat différent rendu
- return FALSE;
- }
-
- if ( pResult != NULL ) pStack->SetCopyVar( pResult );
- if ( pResult != pRes ) delete pResult; // si résultat différent rendu
-
- return TRUE;
-}
-
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////
-
-CBotCallMethode::CBotCallMethode(const char* name,
- BOOL rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
- CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
-{
- m_name = name;
- m_rExec = rExec;
- m_rComp = rCompile;
- m_next = NULL;
- m_nFuncIdent = CBotVar::NextUniqNum();
-}
-
-CBotCallMethode::~CBotCallMethode()
-{
- delete m_next;
- m_next = NULL;
-}
-
-// trouve un appel acceptable selon le nom de la procédure
-// et les paramètres donnés
-
-CBotTypResult CBotCallMethode::CompileCall(const char* name, CBotVar* pThis,
- CBotVar** ppVar, CBotCStack* pStack,
- long& nIdent)
-{
- CBotCallMethode* pt = this;
- nIdent = 0;
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- CBotVar* pVar = MakeListVars(ppVar, TRUE);
- CBotVar* pVar2 = pVar;
- CBotTypResult r = pt->m_rComp(pThis, pVar2);
- int ret = r.GivType();
- if ( ret > 20 )
- {
- if (pVar2) pStack->SetError(ret, pVar2->GivToken());
- }
- delete pVar;
- nIdent = pt->m_nFuncIdent;
- return r;
- }
- pt = pt->m_next;
- }
- return CBotTypResult(-1);
-}
-
-
-CBotString CBotCallMethode::GivName()
-{
- return m_name;
-}
-
-CBotCallMethode* CBotCallMethode::Next()
-{
- return m_next;
-}
-
-void CBotCallMethode::AddNext(CBotCallMethode* pt)
-{
- CBotCallMethode* p = this;
- while ( p->m_next != NULL ) p = p->m_next;
-
- p->m_next = pt;
-}
-
-
-int CBotCallMethode::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pToken)
-{
- CBotCallMethode* pt = this;
-
- // recherche selon l'identificateur
-
- if ( nIdent ) while ( pt != NULL )
- {
- if ( pt->m_nFuncIdent == nIdent )
- {
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVars, TRUE);
- CBotVar* pVarToDelete = pVar;
-
- // puis appelle la routine externe au module
-
- int Exception = 0;
- int res = pt->m_rExec(pThis, pVar, pResult, Exception);
- pStack->SetVar(pResult);
-
- if (res == FALSE)
- {
- if (Exception!=0)
- {
-// pStack->SetError(Exception, pVar->GivToken());
- pStack->SetError(Exception, pToken);
- }
- delete pVarToDelete;
- return FALSE;
- }
- delete pVarToDelete;
- return TRUE;
- }
- pt = pt->m_next;
- }
-
- // recherche selon le nom
-
- while ( pt != NULL )
- {
- if ( pt->m_name == name )
- {
- // fait la liste des paramètres selon le contenu de la pile (pStackVar)
-
- CBotVar* pVar = MakeListVars(ppVars, TRUE);
- CBotVar* pVarToDelete = pVar;
-
- int Exception = 0;
- int res = pt->m_rExec(pThis, pVar, pResult, Exception);
- pStack->SetVar(pResult);
-
- if (res == FALSE)
- {
- if (Exception!=0)
- {
-// pStack->SetError(Exception, pVar->GivToken());
- pStack->SetError(Exception, pToken);
- }
- delete pVarToDelete;
- return FALSE;
- }
- delete pVarToDelete;
- nIdent = pt->m_nFuncIdent;
- return TRUE;
- }
- pt = pt->m_next;
- }
-
- return -1;
-}
-
-BOOL rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- if ( pVar == NULL ) return TX_LOWPARAM;
-
- int i = 0;
- pVar = pVar->GivItemList();
-
- while ( pVar != NULL )
- {
- i++;
- pVar = pVar->GivNext();
- }
-
- pResult->SetValInt(i);
- return TRUE;
-}
-
-CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
-{
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
- if ( pVar->GivType() != CBotTypArrayPointer )
- return CBotTypResult( TX_BADPARAM );
- return CBotTypResult( CBotTypInt );
-}
-
-
-CBotString CBotProgram::m_DebugVarStr = "";
-
-BOOL rCBotDebug( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- pResult->SetValString( CBotProgram::m_DebugVarStr );
-
- return TRUE;
-}
-
-CBotTypResult cCBotDebug( CBotVar* &pVar, void* pUser )
-{
- // pas de paramètre
- if ( pVar != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // la fonction retourne un résultat "string"
- return CBotTypResult( CBotTypString );
-}
-
-
-#include "StringFunctions.cpp"
-
-void CBotProgram::Init()
-{
- CBotToken::DefineNum( "CBotErrOpenPar", 5000) ; // manque la parenthèse ouvrante
- CBotToken::DefineNum( "CBotErrClosePar", 5001) ; // manque la parenthèse fermante
- CBotToken::DefineNum( "CBotErrNotBoolean", 5002) ; // l'expression doit être un boolean
- CBotToken::DefineNum( "CBotErrUndefVar", 5003) ; // variable non déclarée
- CBotToken::DefineNum( "CBotErrBadLeft", 5004) ; // assignation impossible ( 5 = ... )
- CBotToken::DefineNum( "CBotErrNoTerminator", 5005) ;// point-virgule attendu
- CBotToken::DefineNum( "CBotErrCaseOut", 5006) ; // case en dehors d'un switch
- CBotToken::DefineNum( "CBotErrCloseBlock", 5008) ; // manque " } "
- CBotToken::DefineNum( "CBotErrElseWhitoutIf", 5009) ;// else sans if correspondant
- CBotToken::DefineNum( "CBotErrOpenBlock", 5010) ; // manque " { "
- CBotToken::DefineNum( "CBotErrBadType1", 5011) ; // mauvais type pour l'assignation
- CBotToken::DefineNum( "CBotErrRedefVar", 5012) ; // redéfinition de la variable
- CBotToken::DefineNum( "CBotErrBadType2", 5013) ; // 2 opérandes de type incompatibles
- CBotToken::DefineNum( "CBotErrUndefCall", 5014) ; // routine inconnue
- CBotToken::DefineNum( "CBotErrNoDoubleDots", 5015) ;// " : " attendu
- CBotToken::DefineNum( "CBotErrBreakOutside", 5017) ;// break en dehors d'une boucle
- CBotToken::DefineNum( "CBotErrUndefLabel", 5019) ; // label inconnu
- CBotToken::DefineNum( "CBotErrLabel", 5018) ; // label ne peut se mettre ici
- CBotToken::DefineNum( "CBotErrNoCase", 5020) ; // manque " case "
- CBotToken::DefineNum( "CBotErrBadNum", 5021) ; // nombre attendu
- CBotToken::DefineNum( "CBotErrVoid", 5022) ; // " void " pas possible ici
- CBotToken::DefineNum( "CBotErrNoType", 5023) ; // déclaration de type attendue
- CBotToken::DefineNum( "CBotErrNoVar", 5024) ; // nom de variable attendu
- CBotToken::DefineNum( "CBotErrNoFunc", 5025) ; // nom de fonction attendu
- CBotToken::DefineNum( "CBotErrOverParam", 5026) ; // trop de paramètres
- CBotToken::DefineNum( "CBotErrRedefFunc", 5027) ; // cette fonction existe déjà
- CBotToken::DefineNum( "CBotErrLowParam", 5028) ; // pas assez de paramètres
- CBotToken::DefineNum( "CBotErrBadParam", 5029) ; // mauvais types de paramètres
- CBotToken::DefineNum( "CBotErrNbParam", 5030) ; // mauvais nombre de paramètres
- CBotToken::DefineNum( "CBotErrUndefItem", 5031) ; // élément n'existe pas dans la classe
- CBotToken::DefineNum( "CBotErrUndefClass", 5032) ; // variable n'est pas une classe
- CBotToken::DefineNum( "CBotErrNoConstruct", 5033) ; // pas de constructeur approprié
- CBotToken::DefineNum( "CBotErrRedefClass", 5034) ; // classe existe déjà
- CBotToken::DefineNum( "CBotErrCloseIndex", 5035) ; // " ] " attendu
- CBotToken::DefineNum( "CBotErrReserved", 5036) ; // mot réservé (par un DefineNum)
-
-// voici la liste des erreurs pouvant être retournées par le module
-// pour l'exécution
-
- CBotToken::DefineNum( "CBotErrZeroDiv", 6000) ; // division par zéro
- CBotToken::DefineNum( "CBotErrNotInit", 6001) ; // variable non initialisée
- CBotToken::DefineNum( "CBotErrBadThrow", 6002) ; // throw d'une valeur négative
- CBotToken::DefineNum( "CBotErrNoRetVal", 6003) ; // fonction n'a pas retourné de résultat
- CBotToken::DefineNum( "CBotErrNoRun", 6004) ; // Run() sans fonction active
- CBotToken::DefineNum( "CBotErrUndefFunc", 6005) ; // appel d'une fonction qui n'existe plus
-
- CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf );
-
- InitStringFunctions();
-
- // une fonction juste pour les debug divers
- CBotProgram::AddFunction("CBOTDEBUGDD", rCBotDebug, cCBotDebug);
- DeleteFile("CbotDebug.txt");
-
-}
-
-void CBotProgram::Free()
-{
- CBotToken::Free() ;
- CBotCall ::Free() ;
- CBotClass::Free() ;
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+//////////////////////////////////////////////////////////////////////
+// database management of CBoT program
+
+#include "CBot.h"
+#include <stdio.h>
+
+CBotProgram::CBotProgram()
+{
+ m_Prog = NULL;
+ m_pRun = NULL;
+ m_pClass = NULL;
+ m_pStack = NULL;
+ m_pInstance = NULL;
+
+ m_ErrorCode = 0;
+ m_Ident = 0;
+ m_bDebugDD = 0;
+}
+
+CBotProgram::CBotProgram(CBotVar* pInstance)
+{
+ m_Prog = NULL;
+ m_pRun = NULL;
+ m_pClass = NULL;
+ m_pStack = NULL;
+ m_pInstance = pInstance;
+
+ m_ErrorCode = 0;
+ m_Ident = 0;
+ m_bDebugDD = 0;
+}
+
+
+CBotProgram::~CBotProgram()
+{
+// delete m_pClass;
+ m_pClass->Purge();
+ m_pClass = NULL;
+
+ CBotClass::FreeLock(this);
+
+ delete m_Prog;
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+}
+
+
+bool CBotProgram::Compile( const char* program, CBotStringArray& ListFonctions, void* pUser )
+{
+ int error = 0;
+ Stop();
+
+// delete m_pClass;
+ m_pClass->Purge(); // purge the old definitions of classes
+ // but without destroying the object
+ m_pClass = NULL;
+ delete m_Prog; m_Prog= NULL;
+
+ ListFonctions.SetSize(0);
+ m_ErrorCode = 0;
+
+ if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
+ pUser = m_pInstance->m_pUserPtr;
+
+ // transforms the program in Tokens
+ CBotToken* pBaseToken = CBotToken::CompileTokens(program, error);
+ if ( pBaseToken == NULL ) return false;
+
+
+ CBotCStack* pStack = new CBotCStack(NULL);
+ CBotToken* p = pBaseToken->GivNext(); // skips the first token (separator)
+
+ pStack->SetBotCall(this); // defined used routines
+ CBotCall::SetPUser(pUser);
+
+ // first made a quick pass just to take the headers of routines and classes
+ while ( pStack->IsOk() && p != NULL && p->GivType() != 0)
+ {
+ if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
+
+ if ( p->GivType() == ID_CLASS ||
+ ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
+ {
+ CBotClass* nxt = CBotClass::Compile1(p, pStack);
+ if (m_pClass == NULL ) m_pClass = nxt;
+ else m_pClass->AddNext(nxt);
+ }
+ else
+ {
+ CBotFunction* next = CBotFunction::Compile1(p, pStack, NULL);
+ if (m_Prog == NULL ) m_Prog = next;
+ else m_Prog->AddNext(next);
+ }
+ }
+ if ( !pStack->IsOk() )
+ {
+ m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
+ delete m_Prog;
+ m_Prog = NULL;
+ delete pBaseToken;
+ return false;
+ }
+
+// CBotFunction* temp = NULL;
+ CBotFunction* next = m_Prog; // rewind the list
+
+ p = pBaseToken->GivNext(); // returns to the beginning
+
+ while ( pStack->IsOk() && p != NULL && p->GivType() != 0 )
+ {
+ if ( IsOfType(p, ID_SEP) ) continue; // semicolons lurking
+
+ if ( p->GivType() == ID_CLASS ||
+ ( p->GivType() == ID_PUBLIC && p->GivNext()->GivType() == ID_CLASS ))
+ {
+ m_bCompileClass = true;
+ CBotClass::Compile(p, pStack); // completes the definition of the class
+ }
+ else
+ {
+ m_bCompileClass = false;
+ CBotFunction::Compile(p, pStack, next);
+ if (next->IsExtern()) ListFonctions.Add(next->GivName()/* + next->GivParams()*/);
+ next->m_pProg = this; // keeps pointers to the module
+ next = next->Next();
+ }
+ }
+
+// delete m_Prog; // the list of first pass
+// m_Prog = temp; // list of the second pass
+
+ if ( !pStack->IsOk() )
+ {
+ m_ErrorCode = pStack->GivError(m_ErrorStart, m_ErrorEnd);
+ delete m_Prog;
+ m_Prog = NULL;
+ }
+
+ delete pBaseToken;
+ delete pStack;
+
+ return (m_Prog != NULL);
+}
+
+
+bool CBotProgram::Start(const char* name)
+{
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+
+ m_pRun = m_Prog;
+ while (m_pRun != NULL)
+ {
+ if ( m_pRun->GivName() == name ) break;
+ m_pRun = m_pRun->m_next;
+ }
+
+ if ( m_pRun == NULL )
+ {
+ m_ErrorCode = TX_NORUN;
+ return false;
+ }
+
+#if STACKMEM
+ m_pStack = CBotStack::FirstStack();
+#else
+ m_pStack = new CBotStack(NULL); // creates an execution stack
+#endif
+
+ m_pStack->SetBotCall(this); // bases for routines
+
+ return true; // we are ready for Run ()
+}
+
+bool CBotProgram::GetPosition(const char* name, int& start, int& stop, CBotGet modestart, CBotGet modestop)
+{
+ CBotFunction* p = m_Prog;
+ while (p != NULL)
+ {
+ if ( p->GivName() == name ) break;
+ p = p->m_next;
+ }
+
+ if ( p == NULL ) return false;
+
+ p->GetPosition(start, stop, modestart, modestop);
+ return true;
+}
+
+bool CBotProgram::Run(void* pUser, int timer)
+{
+ bool ok;
+
+ if (m_pStack == NULL || m_pRun == NULL) goto error;
+
+ m_ErrorCode = 0;
+ if (m_pInstance != NULL && m_pInstance->m_pUserPtr != NULL)
+ pUser = m_pInstance->m_pUserPtr;
+
+ m_pStack->Reset(pUser); // empty the possible previous error, and resets the timer
+ if ( timer >= 0 ) m_pStack->SetTimer(timer);
+
+ m_pStack->SetBotCall(this); // bases for routines
+
+#if STACKRUN
+ // resumes execution on the top of the stack
+ ok = m_pStack->Execute();
+ if ( ok )
+ {
+#ifdef _DEBUG
+ CBotVar* ppVar[3];
+ ppVar[0] = CBotVar::Create("aa", CBotTypInt);
+ ppVar[1] = CBotVar::Create("bb", CBotTypInt);
+ ppVar[2] = NULL;
+ ok = m_pRun->Execute(ppVar, m_pStack, m_pInstance);
+#else
+ // returns to normal execution
+ ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
+#endif
+ }
+#else
+ ok = m_pRun->Execute(NULL, m_pStack, m_pInstance);
+#endif
+
+ // completed on a mistake?
+ if (!ok && !m_pStack->IsOk())
+ {
+ m_ErrorCode = m_pStack->GivError(m_ErrorStart, m_ErrorEnd);
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+ return true; // execution is finished!
+ }
+
+ if ( ok ) m_pRun = NULL; // more function in execution
+ return ok;
+
+error:
+ m_ErrorCode = TX_NORUN;
+ return true;
+}
+
+void CBotProgram::Stop()
+{
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+ m_pRun = NULL;
+}
+
+
+
+bool CBotProgram::GetRunPos(const char* &FunctionName, int &start, int &end)
+{
+ FunctionName = NULL;
+ start = end = 0;
+ if (m_pStack == NULL) return false;
+
+ m_pStack->GetRunPos(FunctionName, start, end);
+ return true;
+}
+
+CBotVar* CBotProgram::GivStackVars(const char* &FunctionName, int level)
+{
+ FunctionName = NULL;
+ if (m_pStack == NULL) return NULL;
+
+ return m_pStack->GivStackVars(FunctionName, level);
+}
+
+void CBotProgram::SetTimer(int n)
+{
+ CBotStack::SetTimer( n );
+}
+
+int CBotProgram::GivError()
+{
+ return m_ErrorCode;
+}
+
+void CBotProgram::SetIdent(long n)
+{
+ m_Ident = n;
+}
+
+long CBotProgram::GivIdent()
+{
+ return m_Ident;
+}
+
+bool CBotProgram::GetError(int& code, int& start, int& end)
+{
+ code = m_ErrorCode;
+ start = m_ErrorStart;
+ end = m_ErrorEnd;
+ return code > 0;
+}
+
+bool CBotProgram::GetError(int& code, int& start, int& end, CBotProgram* &pProg)
+{
+ code = m_ErrorCode;
+ start = m_ErrorStart;
+ end = m_ErrorEnd;
+ pProg = this;
+ return code > 0;
+}
+
+CBotString CBotProgram::GivErrorText(int code)
+{
+ CBotString TextError;
+
+ TextError.LoadString( code );
+ if (TextError.IsEmpty())
+ {
+ char buf[100];
+ sprintf(buf, "Exception numéro %d.", code);
+ TextError = buf;
+ }
+ return TextError;
+}
+
+
+CBotFunction* CBotProgram::GivFunctions()
+{
+ return m_Prog;
+}
+
+bool CBotProgram::AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
+{
+ // stores pointers to the two functions
+ return CBotCall::AddFunction(name, rExec, rCompile);
+}
+
+
+bool WriteWord(FILE* pf, unsigned short w)
+{
+ size_t lg;
+
+ lg = fwrite(&w, sizeof( unsigned short ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool ReadWord(FILE* pf, unsigned short& w)
+{
+ size_t lg;
+
+ lg = fread(&w, sizeof( unsigned short ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool WriteFloat(FILE* pf, float w)
+{
+ size_t lg;
+
+ lg = fwrite(&w, sizeof( float ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool ReadFloat(FILE* pf, float& w)
+{
+ size_t lg;
+
+ lg = fread(&w, sizeof( float ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool WriteLong(FILE* pf, long w)
+{
+ size_t lg;
+
+ lg = fwrite(&w, sizeof( long ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool ReadLong(FILE* pf, long& w)
+{
+ size_t lg;
+
+ lg = fread(&w, sizeof( long ), 1, pf );
+
+ return (lg == 1);
+}
+
+bool WriteString(FILE* pf, CBotString s)
+{
+ size_t lg1, lg2;
+
+ lg1 = s.GivLength();
+ if (!WriteWord(pf, lg1)) return false;
+
+ lg2 = fwrite(s, 1, lg1, pf );
+ return (lg1 == lg2);
+}
+
+bool ReadString(FILE* pf, CBotString& s)
+{
+ unsigned short w;
+ char buf[1000];
+ size_t lg1, lg2;
+
+ if (!ReadWord(pf, w)) return false;
+ lg1 = w;
+ lg2 = fread(buf, 1, lg1, pf );
+ buf[lg2] = 0;
+
+ s = buf;
+ return (lg1 == lg2);
+}
+
+bool WriteType(FILE* pf, CBotTypResult type)
+{
+ int typ = type.GivType();
+ if ( typ == CBotTypIntrinsic ) typ = CBotTypClass;
+ if ( !WriteWord(pf, typ) ) return false;
+ if ( typ == CBotTypClass )
+ {
+ CBotClass* p = type.GivClass();
+ if ( !WriteString(pf, p->GivName()) ) return false;
+ }
+ if ( type.Eq( CBotTypArrayBody ) ||
+ type.Eq( CBotTypArrayPointer ) )
+ {
+ if ( !WriteWord(pf, type.GivLimite()) ) return false;
+ if ( !WriteType(pf, type.GivTypElem()) ) return false;
+ }
+ return true;
+}
+
+bool ReadType(FILE* pf, CBotTypResult& type)
+{
+ unsigned short w, ww;
+ if ( !ReadWord(pf, w) ) return false;
+ type.SetType(w);
+
+ if ( type.Eq( CBotTypIntrinsic ) )
+ {
+ type = CBotTypResult( w, "point" );
+ }
+
+ if ( type.Eq( CBotTypClass ) )
+ {
+ CBotString s;
+ if ( !ReadString(pf, s) ) return false;
+ type = CBotTypResult( w, s );
+ }
+
+ if ( type.Eq( CBotTypArrayPointer ) ||
+ type.Eq( CBotTypArrayBody ) )
+ {
+ CBotTypResult r;
+ if ( !ReadWord(pf, ww) ) return false;
+ if ( !ReadType(pf, r) ) return false;
+ type = CBotTypResult( w, r );
+ type.SetLimite((short)ww);
+ }
+ return true;
+}
+
+
+bool CBotProgram::DefineNum(const char* name, long val)
+{
+ return CBotToken::DefineNum(name, val);
+}
+
+
+bool CBotProgram::SaveState(FILE* pf)
+{
+ if (!WriteWord( pf, CBOTVERSION)) return false;
+
+
+ if ( m_pStack != NULL )
+ {
+ if (!WriteWord( pf, 1)) return false;
+ if (!WriteString( pf, m_pRun->GivName() )) return false;
+ if (!m_pStack->SaveState(pf)) return false;
+ }
+ else
+ {
+ if (!WriteWord( pf, 0)) return false;
+ }
+ return true;
+}
+
+
+bool CBotProgram::RestoreState(FILE* pf)
+{
+ unsigned short w;
+ CBotString s;
+
+ Stop();
+
+ if (!ReadWord( pf, w )) return false;
+ if ( w != CBOTVERSION ) return false;
+
+ if (!ReadWord( pf, w )) return false;
+ if ( w == 0 ) return true;
+
+ if (!ReadString( pf, s )) return false;
+ Start(s); // point de reprise
+
+#if STACKMEM
+ m_pStack->Delete();
+#else
+ delete m_pStack;
+#endif
+ m_pStack = NULL;
+
+ // retrieves the stack from the memory
+ // uses a NULL pointer (m_pStack) but it's ok like that
+ if (!m_pStack->RestoreState(pf, m_pStack)) return false;
+ m_pStack->SetBotCall(this); // bases for routines
+
+ // restored some states in the stack according to the structure
+ m_pRun->RestoreState(NULL, m_pStack, m_pInstance);
+ return true;
+}
+
+int CBotProgram::GivVersion()
+{
+ return CBOTVERSION;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+CBotCall* CBotCall::m_ListCalls = NULL;
+
+CBotCall::CBotCall(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
+{
+ m_name = name;
+ m_rExec = rExec;
+ m_rComp = rCompile;
+ m_next = NULL;
+ m_nFuncIdent = CBotVar::NextUniqNum();
+}
+
+CBotCall::~CBotCall()
+{
+ if (m_next) delete m_next;
+ m_next = NULL;
+}
+
+void CBotCall::Free()
+{
+ delete CBotCall::m_ListCalls;
+}
+
+bool CBotCall::AddFunction(const char* name,
+ bool rExec (CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser),
+ CBotTypResult rCompile (CBotVar* &pVar, void* pUser))
+{
+ CBotCall* p = m_ListCalls;
+ CBotCall* pp = NULL;
+
+ if ( p != NULL ) while ( p->m_next != NULL )
+ {
+ if ( p->GivName() == name )
+ {
+ // frees redefined function
+ if ( pp ) pp->m_next = p->m_next;
+ else m_ListCalls = p->m_next;
+ pp = p;
+ p = p->m_next;
+ pp->m_next = NULL; // not to destroy the following list
+ delete pp;
+ continue;
+ }
+ pp = p; // previous pointer
+ p = p->m_next;
+ }
+
+ pp = new CBotCall(name, rExec, rCompile);
+
+ if (p) p->m_next = pp;
+ else m_ListCalls = pp;
+
+ return true;
+}
+
+
+// transforms the array of pointers to variables
+// in a chained list of variables
+CBotVar* MakeListVars(CBotVar** ppVars, bool bSetVal=false)
+{
+ int i = 0;
+ CBotVar* pVar = NULL;
+
+ while( true )
+ {
+ ppVars[i];
+ if ( ppVars[i] == NULL ) break;
+
+ CBotVar* pp = CBotVar::Create(ppVars[i]);
+ if (bSetVal) pp->Copy(ppVars[i]);
+ else
+ if ( ppVars[i]->GivType() == CBotTypPointer )
+ pp->SetClass( ppVars[i]->GivClass());
+// copy the pointer according to indirections
+ if (pVar == NULL) pVar = pp;
+ else pVar->AddNext(pp);
+ i++;
+ }
+ return pVar;
+}
+
+// is acceptable by a call procedure name
+// and given parameters
+
+CBotTypResult CBotCall::CompileCall(CBotToken* &p, CBotVar** ppVar, CBotCStack* pStack, long& nIdent)
+{
+ nIdent = 0;
+ CBotCall* pt = m_ListCalls;
+ CBotString name = p->GivString();
+
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ CBotVar* pVar = MakeListVars(ppVar);
+ CBotVar* pVar2 = pVar;
+ CBotTypResult r = pt->m_rComp(pVar2, m_pUser);
+ int ret = r.GivType();
+
+ // if a class is returned, it is actually a pointer
+ if ( ret == CBotTypClass ) r.SetType( ret = CBotTypPointer );
+
+ if ( ret > 20 )
+ {
+ if (pVar2) pStack->SetError(ret, p /*pVar2->GivToken()*/ );
+ }
+ delete pVar;
+ nIdent = pt->m_nFuncIdent;
+ return r;
+ }
+ pt = pt->m_next;
+ }
+ return -1;
+}
+
+void* CBotCall::m_pUser = NULL;
+
+void CBotCall::SetPUser(void* pUser)
+{
+ m_pUser = pUser;
+}
+
+bool CBotCall::CheckCall(const char* name)
+{
+ CBotCall* p = m_ListCalls;
+
+ while ( p != NULL )
+ {
+ if ( name == p->GivName() ) return true;
+ p = p->m_next;
+ }
+ return false;
+}
+
+
+
+CBotString CBotCall::GivName()
+{
+ return m_name;
+}
+
+CBotCall* CBotCall::Next()
+{
+ return m_next;
+}
+
+
+int CBotCall::DoCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack, CBotTypResult& rettype)
+{
+ CBotCall* pt = m_ListCalls;
+
+ if ( nIdent ) while ( pt != NULL )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ goto fund;
+ }
+ pt = pt->m_next;
+ }
+
+ pt = m_ListCalls;
+
+ if ( token != NULL )
+ {
+ CBotString name = token->GivString();
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ nIdent = pt->m_nFuncIdent;
+ goto fund;
+ }
+ pt = pt->m_next;
+ }
+ }
+
+ return -1;
+
+fund:
+#if !STACKRUN
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVar, true);
+ CBotVar* pVarToDelete = pVar;
+
+ // creates a variable to the result
+ CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
+
+ CBotVar* pRes = pResult;
+ int Exception = 0;
+ int res = pt->m_rExec(pVar, pResult, Exception, pStack->GivPUser());
+
+ if ( pResult != pRes ) delete pRes; // different result if made
+ delete pVarToDelete;
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+ pStack->SetError(Exception, token);
+ }
+ delete pResult;
+ return false;
+ }
+ pStack->SetVar(pResult);
+
+ if ( rettype.GivType() > 0 && pResult == NULL )
+ {
+ pStack->SetError(TX_NORETVAL, token);
+ }
+ nIdent = pt->m_nFuncIdent;
+ return true;
+
+#else
+
+ CBotStack* pile = pStack->AddStackEOX(pt);
+ if ( pile == EOX ) return true;
+
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVar, true);
+ CBotVar* pVarToDelete = pVar;
+
+ // creates a variable to the result
+ CBotVar* pResult = rettype.Eq(0) ? NULL : CBotVar::Create("", rettype);
+
+ pile->SetVar( pVar );
+
+ CBotStack* pile2 = pile->AddStack();
+ pile2->SetVar( pResult );
+
+ pile->SetError(0, token); // for the position on error + away
+ return pt->Run( pStack );
+
+#endif
+
+}
+
+#if STACKRUN
+
+bool CBotCall::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotStack* pStack)
+{
+ CBotCall* pt = m_ListCalls;
+
+ {
+ CBotString name = token->GivString();
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ nIdent = pt->m_nFuncIdent;
+
+ CBotStack* pile = pStack->RestoreStackEOX(pt);
+ if ( pile == NULL ) return true;
+
+ CBotStack* pile2 = pile->RestoreStack();
+ return true;
+ }
+ pt = pt->m_next;
+ }
+ }
+
+ return false;
+}
+
+bool CBotCall::Run(CBotStack* pStack)
+{
+ CBotStack* pile = pStack->AddStackEOX(this);
+ if ( pile == EOX ) return true;
+ CBotVar* pVar = pile->GivVar();
+
+ CBotStack* pile2 = pile->AddStack();
+ CBotVar* pResult = pile2->GivVar();
+ CBotVar* pRes = pResult;
+
+ int Exception = 0;
+ int res = m_rExec(pVar, pResult, Exception, pStack->GivPUser());
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+ pStack->SetError(Exception);
+ }
+ if ( pResult != pRes ) delete pResult; // different result if made
+ return false;
+ }
+
+ if ( pResult != NULL ) pStack->SetCopyVar( pResult );
+ if ( pResult != pRes ) delete pResult; // different result if made
+
+ return true;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+CBotCallMethode::CBotCallMethode(const char* name,
+ bool rExec (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception),
+ CBotTypResult rCompile (CBotVar* pThis, CBotVar* &pVar))
+{
+ m_name = name;
+ m_rExec = rExec;
+ m_rComp = rCompile;
+ m_next = NULL;
+ m_nFuncIdent = CBotVar::NextUniqNum();
+}
+
+CBotCallMethode::~CBotCallMethode()
+{
+ delete m_next;
+ m_next = NULL;
+}
+
+// is acceptable by a call procedure name
+// and given parameters
+
+CBotTypResult CBotCallMethode::CompileCall(const char* name, CBotVar* pThis,
+ CBotVar** ppVar, CBotCStack* pStack,
+ long& nIdent)
+{
+ CBotCallMethode* pt = this;
+ nIdent = 0;
+
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ CBotVar* pVar = MakeListVars(ppVar, true);
+ CBotVar* pVar2 = pVar;
+ CBotTypResult r = pt->m_rComp(pThis, pVar2);
+ int ret = r.GivType();
+ if ( ret > 20 )
+ {
+ if (pVar2) pStack->SetError(ret, pVar2->GivToken());
+ }
+ delete pVar;
+ nIdent = pt->m_nFuncIdent;
+ return r;
+ }
+ pt = pt->m_next;
+ }
+ return CBotTypResult(-1);
+}
+
+
+CBotString CBotCallMethode::GivName()
+{
+ return m_name;
+}
+
+CBotCallMethode* CBotCallMethode::Next()
+{
+ return m_next;
+}
+
+void CBotCallMethode::AddNext(CBotCallMethode* pt)
+{
+ CBotCallMethode* p = this;
+ while ( p->m_next != NULL ) p = p->m_next;
+
+ p->m_next = pt;
+}
+
+
+int CBotCallMethode::DoCall(long& nIdent, const char* name, CBotVar* pThis, CBotVar** ppVars, CBotVar* &pResult, CBotStack* pStack, CBotToken* pToken)
+{
+ CBotCallMethode* pt = this;
+
+ // search by the identifier
+
+ if ( nIdent ) while ( pt != NULL )
+ {
+ if ( pt->m_nFuncIdent == nIdent )
+ {
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVars, true);
+ CBotVar* pVarToDelete = pVar;
+
+ // then calls the routine external to the module
+
+ int Exception = 0;
+ int res = pt->m_rExec(pThis, pVar, pResult, Exception);
+ pStack->SetVar(pResult);
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+// pStack->SetError(Exception, pVar->GivToken());
+ pStack->SetError(Exception, pToken);
+ }
+ delete pVarToDelete;
+ return false;
+ }
+ delete pVarToDelete;
+ return true;
+ }
+ pt = pt->m_next;
+ }
+
+ // search by name
+
+ while ( pt != NULL )
+ {
+ if ( pt->m_name == name )
+ {
+ // lists the parameters depending on the contents of the stack (pStackVar)
+
+ CBotVar* pVar = MakeListVars(ppVars, true);
+ CBotVar* pVarToDelete = pVar;
+
+ int Exception = 0;
+ int res = pt->m_rExec(pThis, pVar, pResult, Exception);
+ pStack->SetVar(pResult);
+
+ if (res == false)
+ {
+ if (Exception!=0)
+ {
+// pStack->SetError(Exception, pVar->GivToken());
+ pStack->SetError(Exception, pToken);
+ }
+ delete pVarToDelete;
+ return false;
+ }
+ delete pVarToDelete;
+ nIdent = pt->m_nFuncIdent;
+ return true;
+ }
+ pt = pt->m_next;
+ }
+
+ return -1;
+}
+
+bool rSizeOf( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ if ( pVar == NULL ) return TX_LOWPARAM;
+
+ int i = 0;
+ pVar = pVar->GivItemList();
+
+ while ( pVar != NULL )
+ {
+ i++;
+ pVar = pVar->GivNext();
+ }
+
+ pResult->SetValInt(i);
+ return true;
+}
+
+CBotTypResult cSizeOf( CBotVar* &pVar, void* pUser )
+{
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+ if ( pVar->GivType() != CBotTypArrayPointer )
+ return CBotTypResult( TX_BADPARAM );
+ return CBotTypResult( CBotTypInt );
+}
+
+
+CBotString CBotProgram::m_DebugVarStr = "";
+
+bool rCBotDebug( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ pResult->SetValString( CBotProgram::m_DebugVarStr );
+
+ return true;
+}
+
+CBotTypResult cCBotDebug( CBotVar* &pVar, void* pUser )
+{
+ // no parameter
+ if ( pVar != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // function returns a result "string"
+ return CBotTypResult( CBotTypString );
+}
+
+
+#include "StringFunctions.cpp"
+
+void CBotProgram::Init()
+{
+ CBotToken::DefineNum( "CBotErrOpenPar", 5000) ; // missing the opening parenthesis
+ CBotToken::DefineNum( "CBotErrClosePar", 5001) ; // missing the closing parenthesis
+ CBotToken::DefineNum( "CBotErrNotBoolean", 5002) ; // expression must be a boolean
+ CBotToken::DefineNum( "CBotErrUndefVar", 5003) ; // undeclared variable
+ CBotToken::DefineNum( "CBotErrBadLeft", 5004) ; // impossible assignment (5 = ...)
+ CBotToken::DefineNum( "CBotErrNoTerminator", 5005) ;// semicolon expected
+ CBotToken::DefineNum( "CBotErrCaseOut", 5006) ; // case outside a switch
+ CBotToken::DefineNum( "CBotErrCloseBlock", 5008) ; // missing " } "
+ CBotToken::DefineNum( "CBotErrElseWhitoutIf", 5009) ;// else without matching if
+ CBotToken::DefineNum( "CBotErrOpenBlock", 5010) ; // missing " { "
+ CBotToken::DefineNum( "CBotErrBadType1", 5011) ; // wrong type for the assignment
+ CBotToken::DefineNum( "CBotErrRedefVar", 5012) ; // redefinition of the variable
+ CBotToken::DefineNum( "CBotErrBadType2", 5013) ; // two operands are incompatible
+ CBotToken::DefineNum( "CBotErrUndefCall", 5014) ; // routine unknown
+ CBotToken::DefineNum( "CBotErrNoDoubleDots", 5015) ;// " : " expected
+ CBotToken::DefineNum( "CBotErrBreakOutside", 5017) ;// break outside of a loop
+ CBotToken::DefineNum( "CBotErrUndefLabel", 5019) ; // unknown label
+ CBotToken::DefineNum( "CBotErrLabel", 5018) ; // label can not get here
+ CBotToken::DefineNum( "CBotErrNoCase", 5020) ; // missing " case "
+ CBotToken::DefineNum( "CBotErrBadNum", 5021) ; // expected number
+ CBotToken::DefineNum( "CBotErrVoid", 5022) ; // " void " not possble here
+ CBotToken::DefineNum( "CBotErrNoType", 5023) ; // type declaration expected
+ CBotToken::DefineNum( "CBotErrNoVar", 5024) ; // variable name expected
+ CBotToken::DefineNum( "CBotErrNoFunc", 5025) ; // expected function name
+ CBotToken::DefineNum( "CBotErrOverParam", 5026) ; // too many parameters
+ CBotToken::DefineNum( "CBotErrRedefFunc", 5027) ; // this function already exists
+ CBotToken::DefineNum( "CBotErrLowParam", 5028) ; // not enough parameters
+ CBotToken::DefineNum( "CBotErrBadParam", 5029) ; // mauvais types de paramètres
+ CBotToken::DefineNum( "CBotErrNbParam", 5030) ; // wrong number of parameters
+ CBotToken::DefineNum( "CBotErrUndefItem", 5031) ; // element does not exist in the class
+ CBotToken::DefineNum( "CBotErrUndefClass", 5032) ; // variable is not a class
+ CBotToken::DefineNum( "CBotErrNoConstruct", 5033) ; // no appropriate constructor
+ CBotToken::DefineNum( "CBotErrRedefClass", 5034) ; // Class already exists
+ CBotToken::DefineNum( "CBotErrCloseIndex", 5035) ; // " ] " expected
+ CBotToken::DefineNum( "CBotErrReserved", 5036) ; // reserved word (for a DefineNum)
+
+// Here are the list of errors that can be returned by the module
+// for the execution
+
+ CBotToken::DefineNum( "CBotErrZeroDiv", 6000) ; // division by zero
+ CBotToken::DefineNum( "CBotErrNotInit", 6001) ; // uninitialized variable
+ CBotToken::DefineNum( "CBotErrBadThrow", 6002) ; // throw a negative value
+ CBotToken::DefineNum( "CBotErrNoRetVal", 6003) ; // function did not return results
+ CBotToken::DefineNum( "CBotErrNoRun", 6004) ; // active Run () without a function
+ CBotToken::DefineNum( "CBotErrUndefFunc", 6005) ; // Calling a function that no longer exists
+
+ CBotProgram::AddFunction("sizeof", rSizeOf, cSizeOf );
+
+ InitStringFunctions();
+
+ // just a function for various debug
+ CBotProgram::AddFunction("CBOTDEBUGDD", rCBotDebug, cCBotDebug);
+ //TODO implement this deletion
+ // DeleteFile("CbotDebug.txt");
+
+}
+
+void CBotProgram::Free()
+{
+ CBotToken::Free() ;
+ CBotCall ::Free() ;
+ CBotClass::Free() ;
+}
+
diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp
index b5aaba0..ddb26c6 100644
--- a/src/CBot/CBotStack.cpp
+++ b/src/CBot/CBotStack.cpp
@@ -1,1475 +1,1471 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.//////////////////////////////////////////////////////////////////////
-// gestion de la pile (stack)
-
-#include "CBot.h"
-
-
-#define ITIMER 100
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de la pile d'exécution
-////////////////////////////////////////////////////////////////////////////
-
-int CBotStack::m_initimer = ITIMER; // init la variable statique
-int CBotStack::m_timer = 0; // init la variable statique
-CBotVar* CBotStack::m_retvar = NULL; // init la variable statique
-int CBotStack::m_error = 0; // init la variable statique
-int CBotStack::m_start = 0; // init la variable statique
-int CBotStack::m_end = 0; // init la variable statique
-CBotString CBotStack::m_labelBreak=""; // init la variable statique
-void* CBotStack::m_pUser = NULL;
-
-#if STACKMEM
-
-CBotStack* CBotStack::FirstStack()
-{
- CBotStack* p;
-
- long size = sizeof(CBotStack);
- size *= (MAXSTACK+10);
-
- // demande une tranche mémoire pour la pile
- p = (CBotStack*)malloc(size);
-
- // la vide totalement
- memset(p, 0, size);
-
- p-> m_bBlock = TRUE;
- m_timer = m_initimer; // met le timer au début
-
- CBotStack* pp = p;
- pp += MAXSTACK;
- int i;
- for ( i = 0 ; i< 10 ; i++ )
- {
- pp->m_bOver = TRUE;
- pp ++;
- }
-#ifdef _DEBUG
- int n = 1;
- pp = p;
- for ( i = 0 ; i< MAXSTACK+10 ; i++ )
- {
- pp->m_index = n++;
- pp ++;
- }
-#endif
-
- m_error = 0; // évite des blocages car m_error est static
- return p;
-}
-
-CBotStack::CBotStack(CBotStack* ppapa)
-{
- // constructeur doit exister, sinon le destructeur n'est jamais appelé !
- ASM_TRAP();
-}
-
-CBotStack::~CBotStack()
-{
- ASM_TRAP(); // utiliser Delete() à la place
-}
-
-void CBotStack::Delete()
-{
- if ( this == NULL || this == EOX ) return;
-
- m_next->Delete();
- m_next2->Delete();
-
- if (m_prev != NULL)
- {
- if ( m_prev->m_next == this )
- m_prev->m_next = NULL; // enlève de la chaîne
-
- if ( m_prev->m_next2 == this )
- m_prev->m_next2 = NULL; // enlève de la chaîne
- }
-
- delete m_var;
- delete m_listVar;
-
- CBotStack* p = m_prev;
- BOOL bOver = m_bOver;
-#ifdef _DEBUG
- int n = m_index;
-#endif
-
- // efface le bloc libéré
- memset(this, 0, sizeof(CBotStack));
- m_bOver = bOver;
-#ifdef _DEBUG
- m_index = n;
-#endif
-
- if ( p == NULL )
- free( this );
-}
-
-
-// routine optimisée
-CBotStack* CBotStack::AddStack(CBotInstr* instr, BOOL bBlock)
-{
- if (m_next != NULL)
- {
- return m_next; // reprise dans une pile existante
- }
-
-#ifdef _DEBUG
- int n = 0;
-#endif
- CBotStack* p = this;
- do
- {
- p ++;
-#ifdef _DEBUG
- n ++;
-#endif
- }
- while ( p->m_prev != NULL );
-
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_instr = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- p->m_prev = this;
- p->m_state = 0;
- p->m_call = NULL;
- p->m_bFunc = FALSE;
- return p;
-}
-
-CBotStack* CBotStack::AddStackEOX(CBotCall* instr, BOOL bBlock)
-{
- if (m_next != NULL)
- {
- if ( m_next == EOX )
- {
- m_next = NULL;
- return EOX;
- }
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = AddStack(NULL, bBlock);
- p->m_call = instr;
- p->m_bFunc = 2; // spécial
- return p;
-}
-
-CBotStack* CBotStack::AddStack2(BOOL bBlock)
-{
- if (m_next2 != NULL)
- {
- m_next2->m_prog = m_prog; // spécial évite un RestoreStack2
- return m_next2; // reprise dans une pile existante
- }
-
- CBotStack* p = this;
- do
- {
- p ++;
- }
- while ( p->m_prev != NULL );
-
- m_next2 = p; // chaîne l'élément
- p->m_prev = this;
- p->m_bBlock = bBlock;
- p->m_prog = m_prog;
- p->m_step = 0;
- return p;
-}
-
-BOOL CBotStack::GivBlock()
-{
- return m_bBlock;
-}
-
-BOOL CBotStack::Return(CBotStack* pfils)
-{
- if ( pfils == this ) return TRUE; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- m_next->Delete();m_next = NULL; // libère la pile au dessus
- m_next2->Delete();m_next2 = NULL; // aussi la seconde pile (catch)
-
- return (m_error == 0); // interrompu si erreur
-}
-
-BOOL CBotStack::ReturnKeep(CBotStack* pfils)
-{
- if ( pfils == this ) return TRUE; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- return (m_error == 0); // interrompu si erreur
-}
-
-BOOL CBotStack::StackOver()
-{
- if (!m_bOver) return FALSE;
- m_error = TX_STACKOVER;
- return TRUE;
-}
-
-#else
-
-CBotStack::CBotStack(CBotStack* ppapa)
-{
- m_next = NULL;
- m_next2 = NULL;
- m_prev = ppapa;
-
- m_bBlock = (ppapa == NULL) ? TRUE : FALSE;
-
- m_state = 0;
- m_step = 1;
-
- if (ppapa == NULL) m_timer = m_initimer; // met le timer au début
-
- m_listVar = NULL;
- m_bDontDelete = FALSE;
-
- m_var = NULL;
- m_prog = NULL;
- m_instr = NULL;
- m_call = NULL;
- m_bFunc = FALSE;
-}
-
-// destructeur
-CBotStack::~CBotStack()
-{
- if ( m_next != EOX) delete m_next;
- delete m_next2;
- if (m_prev != NULL && m_prev->m_next == this )
- m_prev->m_next = NULL; // enlève de la chaîne
-
- delete m_var;
- if ( !m_bDontDelete ) delete m_listVar;
-}
-
-// routine à optimiser
-CBotStack* CBotStack::AddStack(CBotInstr* instr, BOOL bBlock)
-{
- if (m_next != NULL)
- {
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = new CBotStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_instr = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- return p;
-}
-
-CBotStack* CBotStack::AddStackEOX(CBotCall* instr, BOOL bBlock)
-{
- if (m_next != NULL)
- {
- if ( m_next == EOX )
- {
- m_next = NULL;
- return EOX;
- }
- return m_next; // reprise dans une pile existante
- }
- CBotStack* p = new CBotStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_call = instr;
- p->m_prog = m_prog;
- p->m_step = 0;
- p->m_bFunc = 2; // spécial
- return p;
-}
-
-CBotStack* CBotStack::AddStack2(BOOL bBlock)
-{
- if (m_next2 != NULL)
- {
- m_next2->m_prog = m_prog; // spécial évite un RestoreStack2
- return m_next2; // reprise dans une pile existante
- }
-
- CBotStack* p = new CBotStack(this);
- m_next2 = p; // chaîne l'élément
- p->m_bBlock = bBlock;
- p->m_prog = m_prog;
- p->m_step = 0;
-
- return p;
-}
-
-BOOL CBotStack::Return(CBotStack* pfils)
-{
- if ( pfils == this ) return TRUE; // spécial
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruite la variable
-
- if ( m_next != EOX ) delete m_next; // libère la pile au dessus
- delete m_next2;m_next2 = NULL; // aussi la seconde pile (catch)
-
- return (m_error == 0); // interrompu si erreur
-}
-
-BOOL CBotStack::StackOver()
-{
- return FALSE; // pas de test de débordement dans cette version
-}
-
-#endif
-
-void CBotStack::Reset(void* pUser)
-{
- m_timer = m_initimer; // remet le timer
- m_error = 0;
-// m_start = 0;
-// m_end = 0;
- m_labelBreak.Empty();
- m_pUser = pUser;
-}
-
-
-
-
-CBotStack* CBotStack::RestoreStack(CBotInstr* instr)
-{
- if (m_next != NULL)
- {
- m_next->m_instr = instr; // réinit (si reprise après restitution)
- m_next->m_prog = m_prog;
- return m_next; // reprise dans une pile existante
- }
- return NULL;
-}
-
-CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr)
-{
- CBotStack* p = RestoreStack();
- p->m_call = instr;
- return p;
-}
-
-
-
-// routine pour l'exécution pas à pas
-BOOL CBotStack::IfStep()
-{
- if ( m_initimer > 0 || m_step++ > 0 ) return FALSE;
- return TRUE;
-}
-
-
-BOOL CBotStack::BreakReturn(CBotStack* pfils, const char* name)
-{
- if ( m_error>=0 ) return FALSE; // sortie normale
- if ( m_error==-3 ) return FALSE; // sortie normale (return en cours)
-
- if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name))
- return FALSE; // c'est pas pour moi
-
- m_error = 0;
- m_labelBreak.Empty();
- return Return(pfils);
-}
-
-BOOL CBotStack::IfContinue(int state, const char* name)
-{
- if ( m_error != -2 ) return FALSE;
-
- if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name))
- return FALSE; // c'est pas pour moi
-
- m_state = state; // où reprendre ?
- m_error = 0;
- m_labelBreak.Empty();
- if ( m_next != EOX ) m_next->Delete(); // purge la pile au dessus
- return TRUE;
-}
-
-void CBotStack::SetBreak(int val, const char* name)
-{
- m_error = -val; // réagit comme une Exception
- m_labelBreak = name;
- if (val == 3) // pour un return
- {
- m_retvar = m_var;
- m_var = NULL;
- }
-}
-
-// remet sur la pile la valeur calculée par le dernier CBotReturn
-
-BOOL CBotStack::GivRetVar(BOOL bRet)
-{
- if (m_error == -3)
- {
- if ( m_var ) delete m_var;
- m_var = m_retvar;
- m_retvar = NULL;
- m_error = 0;
- return TRUE;
- }
- return bRet; // interrompu par autre chose que return
-}
-
-int CBotStack::GivError(int& start, int& end)
-{
- start = m_start;
- end = m_end;
- return m_error;
-}
-
-
-// type d'instruction sur la pile
-int CBotStack::GivType(int mode)
-{
- if (m_var == NULL) return -1;
- return m_var->GivType(mode);
-}
-
-// type d'instruction sur la pile
-CBotTypResult CBotStack::GivTypResult(int mode)
-{
- if (m_var == NULL) return -1;
- return m_var->GivTypResult(mode);
-}
-
-// type d'instruction sur la pile
-void CBotStack::SetType(CBotTypResult& type)
-{
- if (m_var == NULL) return;
- m_var->SetType( type );
-}
-
-
-// trouve une variable par son token
-// ce peut être une variable composée avec un point
-CBotVar* CBotStack::FindVar(CBotToken* &pToken, BOOL bUpdate, BOOL bModif)
-{
- CBotStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivName() == name)
- {
- if ( bUpdate )
- pp->Maj(m_pUser, FALSE);
-
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotStack::FindVar(const char* name)
-{
- CBotStack* p = this;
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivName() == name)
- {
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-// retrouve une variable sur la pile selon son numéro d'identification
-// ce qui va plus vite que de comparer les noms.
-
-CBotVar* CBotStack::FindVar(long ident, BOOL bUpdate, BOOL bModif)
-{
- CBotStack* p = this;
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (pp->GivUniqNum() == ident)
- {
- if ( bUpdate )
- pp->Maj(m_pUser, FALSE);
-
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-
-CBotVar* CBotStack::FindVar(CBotToken& Token, BOOL bUpdate, BOOL bModif)
-{
- CBotToken* pt = &Token;
- return FindVar(pt, bUpdate, bModif);
-}
-
-
-CBotVar* CBotStack::CopyVar(CBotToken& Token, BOOL bUpdate)
-{
- CBotVar* pVar = FindVar( Token, bUpdate );
-
- if ( pVar == NULL) return NULL;
-
- CBotVar* pCopy = CBotVar::Create(pVar);
- pCopy->Copy(pVar);
- return pCopy;
-}
-
-
-BOOL CBotStack::SetState(int n, int limite)
-{
- m_state = n;
-
- m_timer--; // décompte les opérations
- return ( m_timer > limite ); // interrompu si timer passé
-}
-
-BOOL CBotStack::IncState(int limite)
-{
- m_state++;
-
- m_timer--; // décompte les opérations
- return ( m_timer > limite ); // interrompu si timer passé
-}
-
-
-void CBotStack::SetError(int n, CBotToken* token)
-{
- if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante
- m_error = n;
- if (token != NULL)
- {
- m_start = token->GivStart();
- m_end = token->GivEnd();
- }
-}
-
-void CBotStack::ResetError(int n, int start, int end)
-{
- m_error = n;
- m_start = start;
- m_end = end;
-}
-
-void CBotStack::SetPosError(CBotToken* token)
-{
- m_start = token->GivStart();
- m_end = token->GivEnd();
-}
-
-void CBotStack::SetTimer(int n)
-{
- m_initimer = n;
-}
-
-BOOL CBotStack::Execute()
-{
- CBotCall* instr = NULL; // instruction la plus élevée
- CBotStack* pile;
-
- CBotStack* p = this;
-
- while (p != NULL)
- {
- if ( p->m_next2 != NULL ) break;
- if ( p->m_call != NULL )
- {
- instr = p->m_call;
- pile = p->m_prev ;
- }
- p = p->m_next;
- }
-
- if ( instr == NULL ) return TRUE; // exécution normale demandée
-
- if (!instr->Run(pile)) return FALSE; // exécution à partir de là
-
-#if STACKMEM
- pile->m_next->Delete();
-#else
- delete pile->m_next;
-#endif
-
- pile->m_next = EOX; // spécial pour reprise
- return TRUE;
-}
-
-// met sur le stack le pointeur à une variable
-void CBotStack::SetVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
- m_var = var;
-}
-
-// met sur le stack une copie d'une variable
-void CBotStack::SetCopyVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
-
- m_var = CBotVar::Create("", var->GivTypResult(2));
- m_var->Copy( var );
-}
-
-CBotVar* CBotStack::GivVar()
-{
- return m_var;
-}
-
-CBotVar* CBotStack::GivPtVar()
-{
- CBotVar* p = m_var;
- m_var = NULL; // ne sera pas détruit donc
- return p;
-}
-
-CBotVar* CBotStack::GivCopyVar()
-{
- if (m_var == NULL) return NULL;
- CBotVar* v = CBotVar::Create("", m_var->GivType());
- v->Copy( m_var );
- return v;
-}
-
-long CBotStack::GivVal()
-{
- if (m_var == NULL) return 0;
- return m_var->GivValInt();
-}
-
-
-
-
-void CBotStack::AddVar(CBotVar* pVar)
-{
- CBotStack* p = this;
-
- // revient sur l'élement père
- while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
-
- if ( p == NULL ) return;
-
-/// p->m_bDontDelete = bDontDelete;
-
- CBotVar** pp = &p->m_listVar;
- while ( *pp != NULL ) pp = &(*pp)->m_next;
-
- *pp = pVar; // ajoute à la suite
-
-#ifdef _DEBUG
- if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
-#endif
-}
-
-/*void CBotStack::RestoreVar(CBotVar* pVar)
-{
- if ( !m_bDontDelete ) __asm int 3;
- delete m_listVar;
- m_listVar = pVar; // remplace directement
-}*/
-
-void CBotStack::SetBotCall(CBotProgram* p)
-{
- m_prog = p;
- m_bFunc = TRUE;
-}
-
-CBotProgram* CBotStack::GivBotCall(BOOL bFirst)
-{
- if ( ! bFirst ) return m_prog;
- CBotStack* p = this;
- while ( p->m_prev != NULL ) p = p->m_prev;
- return p->m_prog;
-}
-
-void* CBotStack::GivPUser()
-{
- return m_pUser;
-}
-
-
-BOOL CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype)
-{
- CBotTypResult res;
-
- // cherche d'abord selon l'identificateur
-
- res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype );
- if (res.GivType() >= 0) return res.GivType();
-
- res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token );
- if (res.GivType() >= 0) return res.GivType();
-
- // si pas trouvé (recompilé ?) cherche selon le nom
-
- nIdent = 0;
- res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype );
- if (res.GivType() >= 0) return res.GivType();
-
- res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token );
- if (res.GivType() >= 0) return res.GivType();
-
- SetError(TX_NOCALL, token);
- return TRUE;
-}
-
-void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
-{
- if ( m_next == NULL ) return;
-
- if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) )
- m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this );
-}
-
-
-BOOL SaveVar(FILE* pf, CBotVar* pVar)
-{
- while ( TRUE )
- {
- if ( pVar == NULL )
- {
- return WriteWord(pf, 0); // met un terminateur
- }
-
- if ( !pVar->Save0State(pf)) return FALSE; // entête commune
- if ( !pVar->Save1State(pf) ) return FALSE; // sauve selon la classe fille
-
- pVar = pVar->GivNext();
- }
-}
-
-void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end)
-{
- CBotProgram* prog = m_prog; // programme courrant
-
- CBotInstr* funct = NULL; // fonction trouvée
- CBotInstr* instr = NULL; // instruction la plus élevée
-
- CBotStack* p = this;
-
- while (p->m_next != NULL)
- {
- if ( p->m_instr != NULL ) instr = p->m_instr;
- if ( p->m_bFunc == 1 ) funct = p->m_instr;
- if ( p->m_next->m_prog != prog ) break ;
-
- if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
- else p = p->m_next;
- }
-
- if ( p->m_instr != NULL ) instr = p->m_instr;
- if ( p->m_bFunc == 1 ) funct = p->m_instr;
-
- if ( funct == NULL ) return;
-
- CBotToken* t = funct->GivToken();
- FunctionName = t->GivString();
-
-// if ( p->m_instr != NULL ) instr = p->m_instr;
-
- t = instr->GivToken();
- start = t->GivStart();
- end = t->GivEnd();
-}
-
-CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level)
-{
- CBotProgram* prog = m_prog; // programme courrant
- FunctionName = NULL;
-
- // remonte la pile dans le module courant
- CBotStack* p = this;
-
- while (p->m_next != NULL)
- {
- if ( p->m_next->m_prog != prog ) break ;
-
- if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
- else p = p->m_next;
- }
-
-
- // descend sur les éléments de block
- while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
-
- while ( p != NULL && level++ < 0 )
- {
- p = p->m_prev;
- while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
- }
-
- if ( p == NULL ) return NULL;
-
- // recherche le nom de la fonction courante
- CBotStack* pp = p;
- while ( pp != NULL )
- {
- if ( pp->m_bFunc == 1 ) break;
- pp = pp->m_prev;
- }
-
- if ( pp == NULL || pp->m_instr == NULL ) return NULL;
-
- CBotToken* t = pp->m_instr->GivToken();
- FunctionName = t->GivString();
-
- return p->m_listVar;
-}
-
-BOOL CBotStack::SaveState(FILE* pf)
-{
- if ( this == NULL ) // fin de l'arbre ?
- {
- return WriteWord(pf, 0); // met un terminateur
- }
-
- if ( m_next2 != NULL )
- {
- if (!WriteWord(pf, 2)) return FALSE; // une marque de poursuite
- if (!m_next2->SaveState(pf)) return FALSE;
- }
- else
- {
- if (!WriteWord(pf, 1)) return FALSE; // une marque de poursuite
- }
- if (!WriteWord(pf, m_bBlock)) return FALSE; // est-ce un bloc local
- if (!WriteWord(pf, m_state)) return FALSE; // dans quel état
- if (!WriteWord(pf, 0)) return FALSE; // par compatibilité m_bDontDelete
- if (!WriteWord(pf, m_step)) return FALSE; // dans quel état
-
-
- if (!SaveVar(pf, m_var)) return FALSE; // le résultat courant
- if (!SaveVar(pf, m_listVar)) return FALSE; // les variables locales
-
- return m_next->SaveState(pf); // enregistre la suite
-}
-
-
-BOOL CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
-{
- WORD w;
-
- pStack = NULL;
- if (!ReadWord(pf, w)) return FALSE;
- if ( w == 0 ) return TRUE;
-
-#if STACKMEM
- if ( this == NULL ) pStack = FirstStack();
- else pStack = AddStack();
-#else
- pStack = new CBotStack(this);
-#endif
-
- if ( w == 2 )
- {
- if (!pStack->RestoreState(pf, pStack->m_next2)) return FALSE;
- }
-
- if (!ReadWord(pf, w)) return FALSE; // est-ce un bloc local
- pStack->m_bBlock = w;
-
- if (!ReadWord(pf, w)) return FALSE; // dans quel état j'ère ?
- pStack->SetState((short)w); // dans le bon état
-
- if (!ReadWord(pf, w)) return FALSE; // dont delete ?
- // plus utilisé
-
- if (!ReadWord(pf, w)) return FALSE; // pas à pas
- pStack->m_step = w;
-
- if (!CBotVar::RestoreState(pf, pStack->m_var)) return FALSE; // la variable temp
- if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return FALSE;// les variables locales
-
- return pStack->RestoreState(pf, pStack->m_next);
-}
-
-
-BOOL CBotVar::Save0State(FILE* pf)
-{
- if (!WriteWord(pf, 100+m_mPrivate))return FALSE; // variable privée ?
- if (!WriteWord(pf, m_bStatic))return FALSE; // variable static ?
- if (!WriteWord(pf, m_type.GivType()))return FALSE; // enregiste le type (toujours non nul)
- if (!WriteWord(pf, m_binit))return FALSE; // variable définie ?
- return WriteString(pf, m_token->GivString()); // et le nom de la variable
-}
-
-BOOL CBotVarInt::Save0State(FILE* pf)
-{
- if ( !m_defnum.IsEmpty() )
- {
- if(!WriteWord(pf, 200 )) return FALSE; // marqueur spécial
- if(!WriteString(pf, m_defnum)) return FALSE; // nom de la valeur
- }
-
- return CBotVar::Save0State(pf);
-}
-
-BOOL CBotVarInt::Save1State(FILE* pf)
-{
- return WriteWord(pf, m_val); // la valeur de la variable
-}
-
-BOOL CBotVarBoolean::Save1State(FILE* pf)
-{
- return WriteWord(pf, m_val); // la valeur de la variable
-}
-
-BOOL CBotVarFloat::Save1State(FILE* pf)
-{
- return WriteFloat(pf, m_val); // la valeur de la variable
-}
-
-BOOL CBotVarString::Save1State(FILE* pf)
-{
- return WriteString(pf, m_val); // la valeur de la variable
-}
-
-
-
-BOOL CBotVarClass::Save1State(FILE* pf)
-{
- if ( !WriteType(pf, m_type) ) return FALSE;
- if ( !WriteLong(pf, m_ItemIdent) ) return FALSE;
-
- return SaveVar(pf, m_pVar); // contenu de l'objet
-}
-
-BOOL CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
-{
- WORD w, wi, prv, st;
- float ww;
- CBotString name, s;
-
- delete pVar;
-
- pVar = NULL;
- CBotVar* pNew = NULL;
- CBotVar* pPrev = NULL;
-
- while ( TRUE ) // recupère toute une liste
- {
- if (!ReadWord(pf, w)) return FALSE; // privé ou type ?
- if ( w == 0 ) return TRUE;
-
- CBotString defnum;
- if ( w == 200 )
- {
- if (!ReadString(pf, defnum)) return FALSE; // nombre avec un identifiant
- if (!ReadWord(pf, w)) return FALSE; // type
- }
-
- prv = 100; st = 0;
- if ( w >= 100 )
- {
- prv = w;
- if (!ReadWord(pf, st)) return FALSE; // statique
- if (!ReadWord(pf, w)) return FALSE; // type
- }
-
- if ( w == CBotTypClass ) w = CBotTypIntrinsic; // forcément intrinsèque
-
- if (!ReadWord(pf, wi)) return FALSE; // init ?
-
- if (!ReadString(pf, name)) return FALSE; // nom de la variable
-
- CBotToken token(name, CBotString());
-
- switch (w)
- {
- case CBotTypInt:
- case CBotTypBoolean:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadWord(pf, w)) return FALSE;
- pNew->SetValInt((short)w, defnum);
- break;
- case CBotTypFloat:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadFloat(pf, ww)) return FALSE;
- pNew->SetValFloat(ww);
- break;
- case CBotTypString:
- pNew = CBotVar::Create(&token, w); // crée une variable
- if (!ReadString(pf, s)) return FALSE;
- pNew->SetValString(s);
- break;
-
- // restitue un objet intrinsic ou un élément d'un array
- case CBotTypIntrinsic:
- case CBotTypArrayBody:
- {
- CBotTypResult r;
- long id;
- if (!ReadType(pf, r)) return FALSE; // type complet
- if (!ReadLong(pf, id) ) return FALSE;
-
-// if (!ReadString(pf, s)) return FALSE;
- {
- CBotVar* p = NULL;
- if ( id ) p = CBotVarClass::Find(id) ;
-
- pNew = new CBotVarClass(&token, r); // crée directement une instance
- // attention cptuse = 0
- if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return FALSE;
- pNew->SetIdent(id);
-
- if ( p != NULL )
- {
- delete pNew;
- pNew = p; // reprend l'élément connu
- }
- }
- }
- break;
-
- case CBotTypPointer:
- case CBotTypNullPointer:
- if (!ReadString(pf, s)) return FALSE;
- {
- pNew = CBotVar::Create(&token, CBotTypResult(w, s));// crée une variable
- CBotVarClass* p = NULL;
- long id;
- ReadLong(pf, id);
-// if ( id ) p = CBotVarClass::Find(id); // retrouve l'instance ( fait par RestoreInstance )
-
- // restitue une copie de l'instance d'origine
- CBotVar* pInstance = NULL;
- if ( !CBotVar::RestoreState( pf, pInstance ) ) return FALSE;
- ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus
-
-// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // plutôt celui-ci !
-
- }
- break;
-
- case CBotTypArrayPointer:
- {
- CBotTypResult r;
- if (!ReadType(pf, r)) return FALSE;
-
- pNew = CBotVar::Create(&token, r); // crée une variable
-
- // restitue une copie de l'instance d'origine
- CBotVar* pInstance = NULL;
- if ( !CBotVar::RestoreState( pf, pInstance ) ) return FALSE;
- ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // et pointe dessus
- }
- break;
- default:
- ASM_TRAP();
- }
-
- if ( pPrev != NULL ) pPrev->m_next = pNew;
- if ( pVar == NULL ) pVar = pNew;
-
- pNew->m_binit = wi; // pNew->SetInit(wi);
- pNew->SetStatic(st);
- pNew->SetPrivate(prv-100);
- pPrev = pNew;
- }
- return TRUE;
-}
-
-
-
-
-////////////////////////////////////////////////////////////////////////////
-// gestion de la pile à la compilation
-////////////////////////////////////////////////////////////////////////////
-
-CBotProgram* CBotCStack::m_prog = NULL; // init la variable statique
-int CBotCStack::m_error = 0;
-int CBotCStack::m_end = 0;
-CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0);
-//CBotToken* CBotCStack::m_retClass= NULL;
-
-
-CBotCStack::CBotCStack(CBotCStack* ppapa)
-{
- m_next = NULL;
- m_prev = ppapa;
-
- if (ppapa == NULL)
- {
- m_error = 0;
- m_start = 0;
- m_end = 0;
- m_bBlock = TRUE;
- }
- else
- {
- m_start = ppapa->m_start;
- m_bBlock = FALSE;
- }
-
- m_listVar = NULL;
- m_var = NULL;
-}
-
-// destructeur
-CBotCStack::~CBotCStack()
-{
- if (m_next != NULL) delete m_next;
- if (m_prev != NULL) m_prev->m_next = NULL; // enlève de la chaîne
-
- delete m_var;
- delete m_listVar;
-}
-
-// utilisé uniquement à la compilation
-CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, BOOL bBlock)
-{
- if (m_next != NULL) return m_next; // reprise dans une pile existante
-
- CBotCStack* p = new CBotCStack(this);
- m_next = p; // chaîne l'élément
- p->m_bBlock = bBlock;
-
- if (pToken != NULL) p->SetStartError(pToken->GivStart());
-
- return p;
-}
-
-
-CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
-{
- if ( pfils == this ) return inst;
-
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- if (m_error)
- {
- m_start = pfils->m_start; // récupère la position de l'erreur
- m_end = pfils->m_end;
- }
-
- delete pfils;
- return inst;
-}
-
-CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
-{
- if (m_var != NULL) delete m_var; // valeur remplacée ?
- m_var = pfils->m_var; // résultat transmis
- pfils->m_var = NULL; // ne pas détruire la variable
-
- if (m_error)
- {
- m_start = pfils->m_start; // récupère la position de l'erreur
- m_end = pfils->m_end;
- }
-
- delete pfils;
- return inst;
-}
-
-int CBotCStack::GivError(int& start, int& end)
-{
- start = m_start;
- end = m_end;
- return m_error;
-}
-
-int CBotCStack::GivError()
-{
- return m_error;
-}
-
-// type d'instruction sur la pile
-CBotTypResult CBotCStack::GivTypResult(int mode)
-{
- if (m_var == NULL)
- return CBotTypResult(99);
- return m_var->GivTypResult(mode);
-}
-
-// type d'instruction sur la pile
-int CBotCStack::GivType(int mode)
-{
- if (m_var == NULL)
- return 99;
- return m_var->GivType(mode);
-}
-
-// pointeur sur la pile est de quelle classe ?
-CBotClass* CBotCStack::GivClass()
-{
- if ( m_var == NULL )
- return NULL;
- if ( m_var->GivType(1) != CBotTypPointer ) return NULL;
-
- return m_var->GivClass();
-}
-
-// type d'instruction sur la pile
-void CBotCStack::SetType(CBotTypResult& type)
-{
- if (m_var == NULL) return;
- m_var->SetType( type );
-}
-
-// cherche une variable sur la pile
-// le token peut être une suite de TokenTypVar (objet d'une classe)
-// ou un pointeur dans le source
-
-CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
-{
- CBotCStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (name == pp->GivName())
- {
- return pp;
- }
- pp = pp->m_next;
- }
- p = p->m_prev;
- }
- return NULL;
-}
-
-CBotVar* CBotCStack::FindVar(CBotToken& Token)
-{
- CBotToken* pt = &Token;
- return FindVar(pt);
-}
-
-CBotVar* CBotCStack::CopyVar(CBotToken& Token)
-{
- CBotVar* pVar = FindVar( Token );
-
- if ( pVar == NULL) return NULL;
-
- CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() );
- pCopy->Copy(pVar);
- return pCopy;
-}
-
-BOOL CBotCStack::IsOk()
-{
- return (m_error == 0);
-}
-
-
-void CBotCStack::SetStartError( int pos )
-{
- if ( m_error != 0) return; // ne change pas une erreur déjà existante
- m_start = pos;
-}
-
-void CBotCStack::SetError(int n, int pos)
-{
- if ( n!= 0 && m_error != 0) return; // ne change pas une erreur déjà existante
- m_error = n;
- m_end = pos;
-}
-
-void CBotCStack::SetError(int n, CBotToken* p)
-{
- if (m_error) return; // ne change pas une erreur déjà existante
- m_error = n;
- m_start = p->GivStart();
- m_end = p->GivEnd();
-}
-
-void CBotCStack::ResetError(int n, int start, int end)
-{
- m_error = n;
- m_start = start;
- m_end = end;
-}
-
-BOOL CBotCStack::NextToken(CBotToken* &p)
-{
- CBotToken* pp = p;
-
- p = p->GivNext();
- if (p!=NULL) return TRUE;
-
- SetError(TX_ENDOF, pp->GivEnd());
- return FALSE;
-}
-
-void CBotCStack::SetBotCall(CBotProgram* p)
-{
- m_prog = p;
-}
-
-CBotProgram* CBotCStack::GivBotCall()
-{
- return m_prog;
-}
-
-void CBotCStack::SetRetType(CBotTypResult& type)
-{
- m_retTyp = type;
-}
-
-CBotTypResult CBotCStack::GivRetType()
-{
- return m_retTyp;
-}
-
-void CBotCStack::SetVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
- m_var = var;
-}
-
-// met sur le stack une copie d'une variable
-void CBotCStack::SetCopyVar( CBotVar* var )
-{
- if (m_var) delete m_var; // remplacement d'une variable
-
- if ( var == NULL ) return;
- m_var = CBotVar::Create("", var->GivTypResult(2));
- m_var->Copy( var );
-}
-
-CBotVar* CBotCStack::GivVar()
-{
- return m_var;
-}
-
-void CBotCStack::AddVar(CBotVar* pVar)
-{
- CBotCStack* p = this;
-
- // revient sur l'élement père
- while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
-
- if ( p == NULL ) return;
-
- CBotVar** pp = &p->m_listVar;
- while ( *pp != NULL ) pp = &(*pp)->m_next;
-
- *pp = pVar; // ajoute à la suite
-
-#ifdef _DEBUG
- if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
-#endif
-}
-
-// test si une variable est déjà définie localement
-
-BOOL CBotCStack::CheckVarLocal(CBotToken* &pToken)
-{
- CBotCStack* p = this;
- CBotString name = pToken->GivString();
-
- while (p != NULL)
- {
- CBotVar* pp = p->m_listVar;
- while ( pp != NULL)
- {
- if (name == pp->GivName())
- return TRUE;
- pp = pp->m_next;
- }
- if ( p->m_bBlock ) return FALSE;
- p = p->m_prev;
- }
- return FALSE;
-}
-
-CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent)
-{
- nIdent = 0;
- CBotTypResult val(-1);
-
- val = CBotCall::CompileCall(p, ppVars, this, nIdent);
- if (val.GivType() < 0)
- {
- val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent);
- if ( val.GivType() < 0 )
- {
- // pVar = NULL; // l'erreur n'est pas sur un paramètre en particulier
- SetError( -val.GivType(), p );
- val.SetType(-val.GivType());
- return val;
- }
- }
- return val;
-}
-
-// test si un nom de procédure est déjà défini quelque part
-
-BOOL CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
-{
- CBotString name = pToken->GivString();
-
- if ( CBotCall::CheckCall(name) ) return TRUE;
-
- CBotFunction* pp = m_prog->GivFunctions();
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return TRUE;
- }
- pp = pp->Next();
- }
-
- pp = CBotFunction::m_listPublic;
- while ( pp != NULL )
- {
- if ( pToken->GivString() == pp->GivName() )
- {
- // les paramètres sont-ils exactement les mêmes ?
- if ( pp->CheckParam( pParam ) )
- return TRUE;
- }
- pp = pp->m_nextpublic;
- }
-
- return FALSE;
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+//Management of the stack
+
+
+#include "CBot.h"
+#include <cstdlib>
+#include <cstring>
+
+
+#define ITIMER 100
+
+////////////////////////////////////////////////////////////////////////////
+// management of a execution of a stack
+////////////////////////////////////////////////////////////////////////////
+
+int CBotStack::m_initimer = ITIMER;
+int CBotStack::m_timer = 0;
+CBotVar* CBotStack::m_retvar = NULL;
+int CBotStack::m_error = 0;
+int CBotStack::m_start = 0;
+int CBotStack::m_end = 0;
+CBotString CBotStack::m_labelBreak="";
+void* CBotStack::m_pUser = NULL;
+
+#if STACKMEM
+
+CBotStack* CBotStack::FirstStack()
+{
+ CBotStack* p;
+
+ long size = sizeof(CBotStack);
+ size *= (MAXSTACK+10);
+
+ // request a slice of memory for the stack
+ p = (CBotStack*)malloc(size);
+
+ // completely empty
+ memset(p, 0, size);
+
+ p-> m_bBlock = true;
+ m_timer = m_initimer; // sets the timer at the beginning
+
+ CBotStack* pp = p;
+ pp += MAXSTACK;
+ int i;
+ for ( i = 0 ; i< 10 ; i++ )
+ {
+ pp->m_bOver = true;
+ pp ++;
+ }
+#ifdef _DEBUG
+ int n = 1;
+ pp = p;
+ for ( i = 0 ; i< MAXSTACK+10 ; i++ )
+ {
+ pp->m_index = n++;
+ pp ++;
+ }
+#endif
+
+ m_error = 0; // avoids deadlocks because m_error is static
+ return p;
+}
+
+CBotStack::CBotStack(CBotStack* ppapa)
+{
+ // constructor must exist or the destructor is never called!
+ ASM_TRAP();
+}
+
+CBotStack::~CBotStack()
+{
+ ASM_TRAP(); // use Delete () instead
+}
+
+void CBotStack::Delete()
+{
+ if ( this == NULL || this == EOX ) return;
+
+ m_next->Delete();
+ m_next2->Delete();
+
+ if (m_prev != NULL)
+ {
+ if ( m_prev->m_next == this )
+ m_prev->m_next = NULL; // removes chain
+
+ if ( m_prev->m_next2 == this )
+ m_prev->m_next2 = NULL; // removes chain
+ }
+
+ delete m_var;
+ delete m_listVar;
+
+ CBotStack* p = m_prev;
+ bool bOver = m_bOver;
+#ifdef _DEBUG
+ int n = m_index;
+#endif
+
+ // clears the freed block
+ memset(this, 0, sizeof(CBotStack));
+ m_bOver = bOver;
+#ifdef _DEBUG
+ m_index = n;
+#endif
+
+ if ( p == NULL )
+ free( this );
+}
+
+
+// routine improved
+CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ return m_next; // included in an existing stack
+ }
+
+#ifdef _DEBUG
+ int n = 0;
+#endif
+ CBotStack* p = this;
+ do
+ {
+ p ++;
+#ifdef _DEBUG
+ n ++;
+#endif
+ }
+ while ( p->m_prev != NULL );
+
+ m_next = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_instr = instr;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ p->m_prev = this;
+ p->m_state = 0;
+ p->m_call = NULL;
+ p->m_bFunc = false;
+ return p;
+}
+
+CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ if ( m_next == EOX )
+ {
+ m_next = NULL;
+ return EOX;
+ }
+ return m_next; // included in an existing stack
+ }
+ CBotStack* p = AddStack(NULL, bBlock);
+ p->m_call = instr;
+ p->m_bFunc = 2; // special
+ return p;
+}
+
+CBotStack* CBotStack::AddStack2(bool bBlock)
+{
+ if (m_next2 != NULL)
+ {
+ m_next2->m_prog = m_prog; // special avoids RestoreStack2
+ return m_next2; // included in an existing stack
+ }
+
+ CBotStack* p = this;
+ do
+ {
+ p ++;
+ }
+ while ( p->m_prev != NULL );
+
+ m_next2 = p; // chain an element
+ p->m_prev = this;
+ p->m_bBlock = bBlock;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ return p;
+}
+
+bool CBotStack::GivBlock()
+{
+ return m_bBlock;
+}
+
+bool CBotStack::Return(CBotStack* pfils)
+{
+ if ( pfils == this ) return true; // special
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ m_next->Delete();m_next = NULL; // releases the stack above
+ m_next2->Delete();m_next2 = NULL; // also the second stack (catch)
+
+ return (m_error == 0); // interrupted if error
+}
+
+bool CBotStack::ReturnKeep(CBotStack* pfils)
+{
+ if ( pfils == this ) return true; // special
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ return (m_error == 0); // interrupted if error
+}
+
+bool CBotStack::StackOver()
+{
+ if (!m_bOver) return false;
+ m_error = TX_STACKOVER;
+ return true;
+}
+
+#else
+
+CBotStack::CBotStack(CBotStack* ppapa)
+{
+ m_next = NULL;
+ m_next2 = NULL;
+ m_prev = ppapa;
+
+ m_bBlock = (ppapa == NULL) ? true : false;
+
+ m_state = 0;
+ m_step = 1;
+
+ if (ppapa == NULL) m_timer = m_initimer; // sets the timer at the beginning
+
+ m_listVar = NULL;
+ m_bDontDelete = false;
+
+ m_var = NULL;
+ m_prog = NULL;
+ m_instr = NULL;
+ m_call = NULL;
+ m_bFunc = false;
+}
+
+// destructor
+CBotStack::~CBotStack()
+{
+ if ( m_next != EOX) delete m_next;
+ delete m_next2;
+ if (m_prev != NULL && m_prev->m_next == this )
+ m_prev->m_next = NULL; // removes chain
+
+ delete m_var;
+ if ( !m_bDontDelete ) delete m_listVar;
+}
+
+// \TODO routine has/to optimize
+CBotStack* CBotStack::AddStack(CBotInstr* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ return m_next; // included in an existing stack
+ }
+ CBotStack* p = new CBotStack(this);
+ m_next = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_instr = instr;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ return p;
+}
+
+CBotStack* CBotStack::AddStackEOX(CBotCall* instr, bool bBlock)
+{
+ if (m_next != NULL)
+ {
+ if ( m_next == EOX )
+ {
+ m_next = NULL;
+ return EOX;
+ }
+ return m_next; // included in an existing stack
+ }
+ CBotStack* p = new CBotStack(this);
+ m_next = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_call = instr;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+ p->m_bFunc = 2; // special
+ return p;
+}
+
+CBotStack* CBotStack::AddStack2(bool bBlock)
+{
+ if (m_next2 != NULL)
+ {
+ m_next2->m_prog = m_prog; // special avoids RestoreStack2
+ return m_next2; // included in an existing stack
+ }
+
+ CBotStack* p = new CBotStack(this);
+ m_next2 = p; // chain an element
+ p->m_bBlock = bBlock;
+ p->m_prog = m_prog;
+ p->m_step = 0;
+
+ return p;
+}
+
+bool CBotStack::Return(CBotStack* pfils)
+{
+ if ( pfils == this ) return true; // special
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // do not destroy the variable
+
+ if ( m_next != EOX ) delete m_next; // releases the stack above
+ delete m_next2;m_next2 = NULL; // also the second stack (catch)
+
+ return (m_error == 0); // interrupted if error
+}
+
+bool CBotStack::StackOver()
+{
+ return false; // no overflow check in this version
+}
+
+#endif
+
+void CBotStack::Reset(void* pUser)
+{
+ m_timer = m_initimer; // resets the timer
+ m_error = 0;
+// m_start = 0;
+// m_end = 0;
+ m_labelBreak.Empty();
+ m_pUser = pUser;
+}
+
+
+
+
+CBotStack* CBotStack::RestoreStack(CBotInstr* instr)
+{
+ if (m_next != NULL)
+ {
+ m_next->m_instr = instr; // reset (if recovery after )
+ m_next->m_prog = m_prog;
+ return m_next; // included in an existing stack
+ }
+ return NULL;
+}
+
+CBotStack* CBotStack::RestoreStackEOX(CBotCall* instr)
+{
+ CBotStack* p = RestoreStack();
+ p->m_call = instr;
+ return p;
+}
+
+
+
+// routine for execution step by step
+bool CBotStack::IfStep()
+{
+ if ( m_initimer > 0 || m_step++ > 0 ) return false;
+ return true;
+}
+
+
+bool CBotStack::BreakReturn(CBotStack* pfils, const char* name)
+{
+ if ( m_error>=0 ) return false; // normal output
+ if ( m_error==-3 ) return false; // normal output (return current)
+
+ if (!m_labelBreak.IsEmpty() && (name[0] == 0 || m_labelBreak != name))
+ return false; // it's not for me
+
+ m_error = 0;
+ m_labelBreak.Empty();
+ return Return(pfils);
+}
+
+bool CBotStack::IfContinue(int state, const char* name)
+{
+ if ( m_error != -2 ) return false;
+
+ if (!m_labelBreak.IsEmpty() && (name == NULL || m_labelBreak != name))
+ return false; // it's not for me
+
+ m_state = state; // where again?
+ m_error = 0;
+ m_labelBreak.Empty();
+ if ( m_next != EOX ) m_next->Delete(); // purge above stack
+ return true;
+}
+
+void CBotStack::SetBreak(int val, const char* name)
+{
+ m_error = -val; // reacts as an Exception
+ m_labelBreak = name;
+ if (val == 3) // for a return
+ {
+ m_retvar = m_var;
+ m_var = NULL;
+ }
+}
+
+// gives on the stack value calculated by the last CBotReturn
+
+bool CBotStack::GivRetVar(bool bRet)
+{
+ if (m_error == -3)
+ {
+ if ( m_var ) delete m_var;
+ m_var = m_retvar;
+ m_retvar = NULL;
+ m_error = 0;
+ return true;
+ }
+ return bRet; // interrupted by something other than return
+}
+
+int CBotStack::GivError(int& start, int& end)
+{
+ start = m_start;
+ end = m_end;
+ return m_error;
+}
+
+
+int CBotStack::GivType(int mode)
+{
+ if (m_var == NULL) return -1;
+ return m_var->GivType(mode);
+}
+
+CBotTypResult CBotStack::GivTypResult(int mode)
+{
+ if (m_var == NULL) return -1;
+ return m_var->GivTypResult(mode);
+}
+
+void CBotStack::SetType(CBotTypResult& type)
+{
+ if (m_var == NULL) return;
+ m_var->SetType( type );
+}
+
+
+CBotVar* CBotStack::FindVar(CBotToken* &pToken, bool bUpdate, bool bModif)
+{
+ CBotStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivName() == name)
+ {
+ if ( bUpdate )
+ pp->Maj(m_pUser, false);
+
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+CBotVar* CBotStack::FindVar(const char* name)
+{
+ CBotStack* p = this;
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivName() == name)
+ {
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+CBotVar* CBotStack::FindVar(long ident, bool bUpdate, bool bModif)
+{
+ CBotStack* p = this;
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivUniqNum() == ident)
+ {
+ if ( bUpdate )
+ pp->Maj(m_pUser, false);
+
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+
+CBotVar* CBotStack::FindVar(CBotToken& Token, bool bUpdate, bool bModif)
+{
+ CBotToken* pt = &Token;
+ return FindVar(pt, bUpdate, bModif);
+}
+
+
+CBotVar* CBotStack::CopyVar(CBotToken& Token, bool bUpdate)
+{
+ CBotVar* pVar = FindVar( Token, bUpdate );
+
+ if ( pVar == NULL) return NULL;
+
+ CBotVar* pCopy = CBotVar::Create(pVar);
+ pCopy->Copy(pVar);
+ return pCopy;
+}
+
+
+bool CBotStack::SetState(int n, int limite)
+{
+ m_state = n;
+
+ m_timer--; // decrement the operations \TODO decrement the operations
+ return ( m_timer > limite ); // interrupted if timer pass
+}
+
+bool CBotStack::IncState(int limite)
+{
+ m_state++;
+
+ m_timer--; // decrement the operations \TODO decompte les operations
+ return ( m_timer > limite ); // interrupted if timer pass
+}
+
+
+void CBotStack::SetError(int n, CBotToken* token)
+{
+ if ( n!= 0 && m_error != 0) return; // does not change existing error
+ m_error = n;
+ if (token != NULL)
+ {
+ m_start = token->GivStart();
+ m_end = token->GivEnd();
+ }
+}
+
+void CBotStack::ResetError(int n, int start, int end)
+{
+ m_error = n;
+ m_start = start;
+ m_end = end;
+}
+
+void CBotStack::SetPosError(CBotToken* token)
+{
+ m_start = token->GivStart();
+ m_end = token->GivEnd();
+}
+
+void CBotStack::SetTimer(int n)
+{
+ m_initimer = n;
+}
+
+bool CBotStack::Execute()
+{
+ CBotCall* instr = NULL; // the most highest instruction
+ CBotStack* pile;
+
+ CBotStack* p = this;
+
+ while (p != NULL)
+ {
+ if ( p->m_next2 != NULL ) break;
+ if ( p->m_call != NULL )
+ {
+ instr = p->m_call;
+ pile = p->m_prev ;
+ }
+ p = p->m_next;
+ }
+
+ if ( instr == NULL ) return true; // normal execution request
+
+ if (!instr->Run(pile)) return false; // \TODO exécution à partir de là
+
+#if STACKMEM
+ pile->m_next->Delete();
+#else
+ delete pile->m_next;
+#endif
+
+ pile->m_next = EOX; // special for recovery
+ return true;
+}
+
+// puts on the stack pointer to a variable
+void CBotStack::SetVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+ m_var = var;
+}
+
+// puts on the stack a copy of a variable
+void CBotStack::SetCopyVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+
+ m_var = CBotVar::Create("", var->GivTypResult(2));
+ m_var->Copy( var );
+}
+
+CBotVar* CBotStack::GivVar()
+{
+ return m_var;
+}
+
+CBotVar* CBotStack::GivPtVar()
+{
+ CBotVar* p = m_var;
+ m_var = NULL; // therefore will not be destroyed
+ return p;
+}
+
+CBotVar* CBotStack::GivCopyVar()
+{
+ if (m_var == NULL) return NULL;
+ CBotVar* v = CBotVar::Create("", m_var->GivType());
+ v->Copy( m_var );
+ return v;
+}
+
+long CBotStack::GivVal()
+{
+ if (m_var == NULL) return 0;
+ return m_var->GivValInt();
+}
+
+
+
+
+void CBotStack::AddVar(CBotVar* pVar)
+{
+ CBotStack* p = this;
+
+ // returns to the father element
+ while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
+
+ if ( p == NULL ) return;
+
+/// p->m_bDontDelete = bDontDelete;
+
+ CBotVar** pp = &p->m_listVar;
+ while ( *pp != NULL ) pp = &(*pp)->m_next;
+
+ *pp = pVar; // added after
+
+#ifdef _DEBUG
+ if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
+#endif
+}
+
+/*void CBotStack::RestoreVar(CBotVar* pVar)
+{
+ if ( !m_bDontDelete ) __asm int 3;
+ delete m_listVar;
+ m_listVar = pVar; // direct replacement
+}*/
+
+void CBotStack::SetBotCall(CBotProgram* p)
+{
+ m_prog = p;
+ m_bFunc = true;
+}
+
+CBotProgram* CBotStack::GivBotCall(bool bFirst)
+{
+ if ( ! bFirst ) return m_prog;
+ CBotStack* p = this;
+ while ( p->m_prev != NULL ) p = p->m_prev;
+ return p->m_prog;
+}
+
+void* CBotStack::GivPUser()
+{
+ return m_pUser;
+}
+
+
+bool CBotStack::ExecuteCall(long& nIdent, CBotToken* token, CBotVar** ppVar, CBotTypResult& rettype)
+{
+ CBotTypResult res;
+
+ // first looks by the identifier
+
+ res = CBotCall::DoCall(nIdent, NULL, ppVar, this, rettype );
+ if (res.GivType() >= 0) return res.GivType();
+
+ res = m_prog->GivFunctions()->DoCall(nIdent, NULL, ppVar, this, token );
+ if (res.GivType() >= 0) return res.GivType();
+
+ // if not found (recompile?) seeks by name
+
+ nIdent = 0;
+ res = CBotCall::DoCall(nIdent, token, ppVar, this, rettype );
+ if (res.GivType() >= 0) return res.GivType();
+
+ res = m_prog->GivFunctions()->DoCall(nIdent, token->GivString(), ppVar, this, token );
+ if (res.GivType() >= 0) return res.GivType();
+
+ SetError(TX_NOCALL, token);
+ return true;
+}
+
+void CBotStack::RestoreCall(long& nIdent, CBotToken* token, CBotVar** ppVar)
+{
+ if ( m_next == NULL ) return;
+
+ if ( !CBotCall::RestoreCall(nIdent, token, ppVar, this) )
+ m_prog->GivFunctions()->RestoreCall(nIdent, token->GivString(), ppVar, this );
+}
+
+
+bool SaveVar(FILE* pf, CBotVar* pVar)
+{
+ while ( true )
+ {
+ if ( pVar == NULL )
+ {
+ return WriteWord(pf, 0); // is a terminator
+ }
+
+ if ( !pVar->Save0State(pf)) return false; // common header
+ if ( !pVar->Save1State(pf) ) return false; // saves as the child class
+
+ pVar = pVar->GivNext();
+ }
+}
+
+void CBotStack::GetRunPos(const char* &FunctionName, int &start, int &end)
+{
+ CBotProgram* prog = m_prog; // Current program
+
+ CBotInstr* funct = NULL; // function found
+ CBotInstr* instr = NULL; // the highest intruction
+
+ CBotStack* p = this;
+
+ while (p->m_next != NULL)
+ {
+ if ( p->m_instr != NULL ) instr = p->m_instr;
+ if ( p->m_bFunc == 1 ) funct = p->m_instr;
+ if ( p->m_next->m_prog != prog ) break ;
+
+ if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
+ else p = p->m_next;
+ }
+
+ if ( p->m_instr != NULL ) instr = p->m_instr;
+ if ( p->m_bFunc == 1 ) funct = p->m_instr;
+
+ if ( funct == NULL ) return;
+
+ CBotToken* t = funct->GivToken();
+ FunctionName = t->GivString();
+
+// if ( p->m_instr != NULL ) instr = p->m_instr;
+
+ t = instr->GivToken();
+ start = t->GivStart();
+ end = t->GivEnd();
+}
+
+CBotVar* CBotStack::GivStackVars(const char* &FunctionName, int level)
+{
+ CBotProgram* prog = m_prog; // current program
+ FunctionName = NULL;
+
+ // back the stack in the current module
+ CBotStack* p = this;
+
+ while (p->m_next != NULL)
+ {
+ if ( p->m_next->m_prog != prog ) break ;
+
+ if (p->m_next2 && p->m_next2->m_state != 0) p = p->m_next2 ;
+ else p = p->m_next;
+ }
+
+
+ // descends upon the elements of block
+ while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
+
+ while ( p != NULL && level++ < 0 )
+ {
+ p = p->m_prev;
+ while ( p != NULL && !p->m_bBlock ) p = p->m_prev;
+ }
+
+ if ( p == NULL ) return NULL;
+
+ // search the name of the current function
+ CBotStack* pp = p;
+ while ( pp != NULL )
+ {
+ if ( pp->m_bFunc == 1 ) break;
+ pp = pp->m_prev;
+ }
+
+ if ( pp == NULL || pp->m_instr == NULL ) return NULL;
+
+ CBotToken* t = pp->m_instr->GivToken();
+ FunctionName = t->GivString();
+
+ return p->m_listVar;
+}
+
+bool CBotStack::SaveState(FILE* pf)
+{
+ if ( this == NULL ) // end of the tree?
+ {
+ return WriteWord(pf, 0); // is a terminator
+ }
+
+ if ( m_next2 != NULL )
+ {
+ if (!WriteWord(pf, 2)) return false; // a mark of pursuit
+ if (!m_next2->SaveState(pf)) return false;
+ }
+ else
+ {
+ if (!WriteWord(pf, 1)) return false; // a mark of pursuit
+ }
+ if (!WriteWord(pf, m_bBlock)) return false; // is a local block
+ if (!WriteWord(pf, m_state)) return false; // in what state?
+ if (!WriteWord(pf, 0)) return false; // by compatibility m_bDontDelete
+ if (!WriteWord(pf, m_step)) return false; // in what state?
+
+
+ if (!SaveVar(pf, m_var)) return false; // current result
+ if (!SaveVar(pf, m_listVar)) return false; // local variables
+
+ return m_next->SaveState(pf); // saves the following
+}
+
+
+bool CBotStack::RestoreState(FILE* pf, CBotStack* &pStack)
+{
+ unsigned short w;
+
+ pStack = NULL;
+ if (!ReadWord(pf, w)) return false;
+ if ( w == 0 ) return true;
+
+#if STACKMEM
+ if ( this == NULL ) pStack = FirstStack();
+ else pStack = AddStack();
+#else
+ pStack = new CBotStack(this);
+#endif
+
+ if ( w == 2 )
+ {
+ if (!pStack->RestoreState(pf, pStack->m_next2)) return false;
+ }
+
+ if (!ReadWord(pf, w)) return false; // is a local block
+ pStack->m_bBlock = w;
+
+ if (!ReadWord(pf, w)) return false; // in what state ?
+ pStack->SetState((short)w); // in a good state
+
+ if (!ReadWord(pf, w)) return false; // dont delete?
+ // uses more
+
+ if (!ReadWord(pf, w)) return false; // step by step
+ pStack->m_step = w;
+
+ if (!CBotVar::RestoreState(pf, pStack->m_var)) return false; // temp variable
+ if (!CBotVar::RestoreState(pf, pStack->m_listVar)) return false;// local variables
+
+ return pStack->RestoreState(pf, pStack->m_next);
+}
+
+
+bool CBotVar::Save0State(FILE* pf)
+{
+ if (!WriteWord(pf, 100+m_mPrivate))return false; // private variable?
+ if (!WriteWord(pf, m_bStatic))return false; // static variable?
+ if (!WriteWord(pf, m_type.GivType()))return false; // saves the type (always non-zero)
+ if (!WriteWord(pf, m_binit))return false; // variable defined?
+ return WriteString(pf, m_token->GivString()); // and variable name
+}
+
+bool CBotVarInt::Save0State(FILE* pf)
+{
+ if ( !m_defnum.IsEmpty() )
+ {
+ if(!WriteWord(pf, 200 )) return false; // special marker
+ if(!WriteString(pf, m_defnum)) return false; // name of the value
+ }
+
+ return CBotVar::Save0State(pf);
+}
+
+bool CBotVarInt::Save1State(FILE* pf)
+{
+ return WriteWord(pf, m_val); // the value of the variable
+}
+
+bool CBotVarBoolean::Save1State(FILE* pf)
+{
+ return WriteWord(pf, m_val); // the value of the variable
+}
+
+bool CBotVarFloat::Save1State(FILE* pf)
+{
+ return WriteFloat(pf, m_val); // the value of the variable
+}
+
+bool CBotVarString::Save1State(FILE* pf)
+{
+ return WriteString(pf, m_val); // the value of the variable
+}
+
+
+
+bool CBotVarClass::Save1State(FILE* pf)
+{
+ if ( !WriteType(pf, m_type) ) return false;
+ if ( !WriteLong(pf, m_ItemIdent) ) return false;
+
+ return SaveVar(pf, m_pVar); // content of the object
+}
+
+bool CBotVar::RestoreState(FILE* pf, CBotVar* &pVar)
+{
+ unsigned short w, wi, prv, st;
+ float ww;
+ CBotString name, s;
+
+ delete pVar;
+
+ pVar = NULL;
+ CBotVar* pNew = NULL;
+ CBotVar* pPrev = NULL;
+
+ while ( true ) // retrieves a list
+ {
+ if (!ReadWord(pf, w)) return false; // private or type?
+ if ( w == 0 ) return true;
+
+ CBotString defnum;
+ if ( w == 200 )
+ {
+ if (!ReadString(pf, defnum)) return false; // number with identifier
+ if (!ReadWord(pf, w)) return false; // type
+ }
+
+ prv = 100; st = 0;
+ if ( w >= 100 )
+ {
+ prv = w;
+ if (!ReadWord(pf, st)) return false; // static
+ if (!ReadWord(pf, w)) return false; // type
+ }
+
+ if ( w == CBotTypClass ) w = CBotTypIntrinsic; // necessarily intrinsic
+
+ if (!ReadWord(pf, wi)) return false; // init ?
+
+ if (!ReadString(pf, name)) return false; // variable name
+
+ CBotToken token(name, CBotString());
+
+ switch (w)
+ {
+ case CBotTypInt:
+ case CBotTypBoolean:
+ pNew = CBotVar::Create(&token, w); // creates a variable
+ if (!ReadWord(pf, w)) return false;
+ pNew->SetValInt((short)w, defnum);
+ break;
+ case CBotTypFloat:
+ pNew = CBotVar::Create(&token, w); // creates a variable
+ if (!ReadFloat(pf, ww)) return false;
+ pNew->SetValFloat(ww);
+ break;
+ case CBotTypString:
+ pNew = CBotVar::Create(&token, w); // creates a variable
+ if (!ReadString(pf, s)) return false;
+ pNew->SetValString(s);
+ break;
+
+ // returns an intrinsic object or element of an array
+ case CBotTypIntrinsic:
+ case CBotTypArrayBody:
+ {
+ CBotTypResult r;
+ long id;
+ if (!ReadType(pf, r)) return false; // complete type
+ if (!ReadLong(pf, id) ) return false;
+
+// if (!ReadString(pf, s)) return false;
+ {
+ CBotVar* p = NULL;
+ if ( id ) p = CBotVarClass::Find(id) ;
+
+ pNew = new CBotVarClass(&token, r); // directly creates an instance
+ // attention cptuse = 0
+ if ( !RestoreState(pf, ((CBotVarClass*)pNew)->m_pVar)) return false;
+ pNew->SetIdent(id);
+
+ if ( p != NULL )
+ {
+ delete pNew;
+ pNew = p; // resume known element
+ }
+ }
+ }
+ break;
+
+ case CBotTypPointer:
+ case CBotTypNullPointer:
+ if (!ReadString(pf, s)) return false;
+ {
+ pNew = CBotVar::Create(&token, CBotTypResult(w, s));// creates a variable
+ CBotVarClass* p = NULL;
+ long id;
+ ReadLong(pf, id);
+// if ( id ) p = CBotVarClass::Find(id); // found the instance (made by RestoreInstance)
+
+ // returns a copy of the original instance
+ CBotVar* pInstance = NULL;
+ if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
+ ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over
+
+// if ( p != NULL ) ((CBotVarPointer*)pNew)->SetPointer( p ); // rather this one
+
+ }
+ break;
+
+ case CBotTypArrayPointer:
+ {
+ CBotTypResult r;
+ if (!ReadType(pf, r)) return false;
+
+ pNew = CBotVar::Create(&token, r); // creates a variable
+
+ // returns a copy of the original instance
+ CBotVar* pInstance = NULL;
+ if ( !CBotVar::RestoreState( pf, pInstance ) ) return false;
+ ((CBotVarPointer*)pNew)->SetPointer( pInstance ); // and point over
+ }
+ break;
+ default:
+ ASM_TRAP();
+ }
+
+ if ( pPrev != NULL ) pPrev->m_next = pNew;
+ if ( pVar == NULL ) pVar = pNew;
+
+ pNew->m_binit = wi; // pNew->SetInit(wi);
+ pNew->SetStatic(st);
+ pNew->SetPrivate(prv-100);
+ pPrev = pNew;
+ }
+ return true;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////////
+// management of the compile stack
+////////////////////////////////////////////////////////////////////////////
+
+CBotProgram* CBotCStack::m_prog = NULL; // init the static variable
+int CBotCStack::m_error = 0;
+int CBotCStack::m_end = 0;
+CBotTypResult CBotCStack::m_retTyp = CBotTypResult(0);
+//CBotToken* CBotCStack::m_retClass= NULL;
+
+
+CBotCStack::CBotCStack(CBotCStack* ppapa)
+{
+ m_next = NULL;
+ m_prev = ppapa;
+
+ if (ppapa == NULL)
+ {
+ m_error = 0;
+ m_start = 0;
+ m_end = 0;
+ m_bBlock = true;
+ }
+ else
+ {
+ m_start = ppapa->m_start;
+ m_bBlock = false;
+ }
+
+ m_listVar = NULL;
+ m_var = NULL;
+}
+
+// destructor
+CBotCStack::~CBotCStack()
+{
+ if (m_next != NULL) delete m_next;
+ if (m_prev != NULL) m_prev->m_next = NULL; // removes chain
+
+ delete m_var;
+ delete m_listVar;
+}
+
+// used only at compile
+CBotCStack* CBotCStack::TokenStack(CBotToken* pToken, bool bBlock)
+{
+ if (m_next != NULL) return m_next; // include on an existing stack
+
+ CBotCStack* p = new CBotCStack(this);
+ m_next = p; // channel element
+ p->m_bBlock = bBlock;
+
+ if (pToken != NULL) p->SetStartError(pToken->GivStart());
+
+ return p;
+}
+
+
+CBotInstr* CBotCStack::Return(CBotInstr* inst, CBotCStack* pfils)
+{
+ if ( pfils == this ) return inst;
+
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ if (m_error)
+ {
+ m_start = pfils->m_start; // retrieves the position of the error
+ m_end = pfils->m_end;
+ }
+
+ delete pfils;
+ return inst;
+}
+
+CBotFunction* CBotCStack::ReturnFunc(CBotFunction* inst, CBotCStack* pfils)
+{
+ if (m_var != NULL) delete m_var; // value replaced?
+ m_var = pfils->m_var; // result transmitted
+ pfils->m_var = NULL; // not to destroy the variable
+
+ if (m_error)
+ {
+ m_start = pfils->m_start; // retrieves the position of the error
+ m_end = pfils->m_end;
+ }
+
+ delete pfils;
+ return inst;
+}
+
+int CBotCStack::GivError(int& start, int& end)
+{
+ start = m_start;
+ end = m_end;
+ return m_error;
+}
+
+int CBotCStack::GivError()
+{
+ return m_error;
+}
+
+// type of instruction on the stack
+CBotTypResult CBotCStack::GivTypResult(int mode)
+{
+ if (m_var == NULL)
+ return CBotTypResult(99);
+ return m_var->GivTypResult(mode);
+}
+
+// type of instruction on the stack
+int CBotCStack::GivType(int mode)
+{
+ if (m_var == NULL)
+ return 99;
+ return m_var->GivType(mode);
+}
+
+// pointer on the stack is in what class?
+CBotClass* CBotCStack::GivClass()
+{
+ if ( m_var == NULL )
+ return NULL;
+ if ( m_var->GivType(1) != CBotTypPointer ) return NULL;
+
+ return m_var->GivClass();
+}
+
+// type of instruction on the stack
+void CBotCStack::SetType(CBotTypResult& type)
+{
+ if (m_var == NULL) return;
+ m_var->SetType( type );
+}
+
+// seeks a variable on the stack
+// the token may be a result of TokenTypVar (object of a class)
+// or a pointer in the source
+
+CBotVar* CBotCStack::FindVar(CBotToken* &pToken)
+{
+ CBotCStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (name == pp->GivName())
+ {
+ return pp;
+ }
+ pp = pp->m_next;
+ }
+ p = p->m_prev;
+ }
+ return NULL;
+}
+
+CBotVar* CBotCStack::FindVar(CBotToken& Token)
+{
+ CBotToken* pt = &Token;
+ return FindVar(pt);
+}
+
+CBotVar* CBotCStack::CopyVar(CBotToken& Token)
+{
+ CBotVar* pVar = FindVar( Token );
+
+ if ( pVar == NULL) return NULL;
+
+ CBotVar* pCopy = CBotVar::Create( "", pVar->GivType() );
+ pCopy->Copy(pVar);
+ return pCopy;
+}
+
+bool CBotCStack::IsOk()
+{
+ return (m_error == 0);
+}
+
+
+void CBotCStack::SetStartError( int pos )
+{
+ if ( m_error != 0) return; // does not change existing error
+ m_start = pos;
+}
+
+void CBotCStack::SetError(int n, int pos)
+{
+ if ( n!= 0 && m_error != 0) return; // does not change existing error
+ m_error = n;
+ m_end = pos;
+}
+
+void CBotCStack::SetError(int n, CBotToken* p)
+{
+ if (m_error) return; // does not change existing error
+ m_error = n;
+ m_start = p->GivStart();
+ m_end = p->GivEnd();
+}
+
+void CBotCStack::ResetError(int n, int start, int end)
+{
+ m_error = n;
+ m_start = start;
+ m_end = end;
+}
+
+bool CBotCStack::NextToken(CBotToken* &p)
+{
+ CBotToken* pp = p;
+
+ p = p->GivNext();
+ if (p!=NULL) return true;
+
+ SetError(TX_ENDOF, pp->GivEnd());
+ return false;
+}
+
+void CBotCStack::SetBotCall(CBotProgram* p)
+{
+ m_prog = p;
+}
+
+CBotProgram* CBotCStack::GivBotCall()
+{
+ return m_prog;
+}
+
+void CBotCStack::SetRetType(CBotTypResult& type)
+{
+ m_retTyp = type;
+}
+
+CBotTypResult CBotCStack::GivRetType()
+{
+ return m_retTyp;
+}
+
+void CBotCStack::SetVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+ m_var = var;
+}
+
+// puts on the stack a copy of a variable
+void CBotCStack::SetCopyVar( CBotVar* var )
+{
+ if (m_var) delete m_var; // replacement of a variable
+
+ if ( var == NULL ) return;
+ m_var = CBotVar::Create("", var->GivTypResult(2));
+ m_var->Copy( var );
+}
+
+CBotVar* CBotCStack::GivVar()
+{
+ return m_var;
+}
+
+void CBotCStack::AddVar(CBotVar* pVar)
+{
+ CBotCStack* p = this;
+
+ // returns to the father element
+ while (p != NULL && p->m_bBlock == 0) p = p->m_prev;
+
+ if ( p == NULL ) return;
+
+ CBotVar** pp = &p->m_listVar;
+ while ( *pp != NULL ) pp = &(*pp)->m_next;
+
+ *pp = pVar; // added after
+
+#ifdef _DEBUG
+ if ( pVar->GivUniqNum() == 0 ) ASM_TRAP();
+#endif
+}
+
+// test whether a variable is already defined locally
+
+bool CBotCStack::CheckVarLocal(CBotToken* &pToken)
+{
+ CBotCStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (name == pp->GivName())
+ return true;
+ pp = pp->m_next;
+ }
+ if ( p->m_bBlock ) return false;
+ p = p->m_prev;
+ }
+ return false;
+}
+
+CBotTypResult CBotCStack::CompileCall(CBotToken* &p, CBotVar** ppVars, long& nIdent)
+{
+ nIdent = 0;
+ CBotTypResult val(-1);
+
+ val = CBotCall::CompileCall(p, ppVars, this, nIdent);
+ if (val.GivType() < 0)
+ {
+ val = m_prog->GivFunctions()->CompileCall(p->GivString(), ppVars, nIdent);
+ if ( val.GivType() < 0 )
+ {
+ // pVar = NULL; // the error is not on a particular parameter
+ SetError( -val.GivType(), p );
+ val.SetType(-val.GivType());
+ return val;
+ }
+ }
+ return val;
+}
+
+// test if a procedure name is already defined somewhere
+
+bool CBotCStack::CheckCall(CBotToken* &pToken, CBotDefParam* pParam)
+{
+ CBotString name = pToken->GivString();
+
+ if ( CBotCall::CheckCall(name) ) return true;
+
+ CBotFunction* pp = m_prog->GivFunctions();
+ while ( pp != NULL )
+ {
+ if ( pToken->GivString() == pp->GivName() )
+ {
+ // are parameters exactly the same?
+ if ( pp->CheckParam( pParam ) )
+ return true;
+ }
+ pp = pp->Next();
+ }
+
+ pp = CBotFunction::m_listPublic;
+ while ( pp != NULL )
+ {
+ if ( pToken->GivString() == pp->GivName() )
+ {
+ // are parameters exactly the same?
+ if ( pp->CheckParam( pParam ) )
+ return true;
+ }
+ pp = pp->m_nextpublic;
+ }
+
+ return false;
+}
+
diff --git a/src/CBot/CBotString.cpp b/src/CBot/CBotString.cpp
index 53b0f27..1b42c23 100644
--- a/src/CBot/CBotString.cpp
+++ b/src/CBot/CBotString.cpp
@@ -1,603 +1,692 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/./////////////////////////////////////////////////////
-// gestion de chaine
-// basé sur le CString de MFC
-// mais moins complet
-
-#include "CBot.h"
-
-#include <string.h>
-
-HINSTANCE CBotString::m_hInstance = (HINSTANCE)LoadLibrary("libCbot.dll"); // comment le récupérer autrement ??
-
-
-CBotString::CBotString()
-{
- m_ptr = NULL; // chaine vide
- m_lg = 0;
-}
-
-CBotString::~CBotString()
-{
- if (m_ptr != NULL) free(m_ptr);
-}
-
-
-CBotString::CBotString(const char* p)
-{
- m_lg = lstrlen( p );
-
- m_ptr = NULL;
- if (m_lg>0)
- {
- m_ptr = (char*)malloc(m_lg+1);
- lstrcpy(m_ptr, p);
- }
-}
-
-CBotString::CBotString(const CBotString& srcString)
-{
- m_lg = srcString.m_lg;
-
- m_ptr = NULL;
- if (m_lg>0)
- {
- m_ptr = (char*)malloc(m_lg+1);
- lstrcpy(m_ptr, srcString.m_ptr);
- }
-}
-
-
-
-
-int CBotString::GivLength()
-{
- if ( m_ptr == NULL ) return 0;
- return lstrlen( m_ptr );
-}
-
-
-
-CBotString CBotString::Left(int nCount) const
-{
- char chaine[2000];
-
- int i;
- for (i = 0; i < m_lg && i < nCount && i < 1999; i++)
- {
- chaine[i] = m_ptr[i];
- }
- chaine[i] = 0 ;
-
- return CBotString( chaine );
-}
-
-CBotString CBotString::Right(int nCount) const
-{
- char chaine[2000];
-
- int i = m_lg - nCount;
- if ( i < 0 ) i = 0;
-
- int j;
- for ( j = 0 ; i < m_lg && i < 1999; i++)
- {
- chaine[j++] = m_ptr[i];
- }
- chaine[j] = 0 ;
-
- return CBotString( chaine );
-}
-
-CBotString CBotString::Mid(int nFirst, int nCount) const
-{
- char chaine[2000];
-
- int i;
-
- for ( i = nFirst; i < m_lg && i < 1999 && i <= nFirst + nCount; i++)
- {
- chaine[i] = m_ptr[i];
- }
- chaine[i] = 0 ;
-
- return CBotString( chaine );
-}
-
-CBotString CBotString::Mid(int nFirst) const
-{
- char chaine[2000];
-
- int i;
-
- for ( i = nFirst; i < m_lg && i < 1999 ; i++)
- {
- chaine[i] = m_ptr[i];
- }
- chaine[i] = 0 ;
-
- return CBotString( chaine );
-}
-
-
-int CBotString::Find(const char c)
-{
- int i;
- for (i = 0; i < m_lg; i++)
- {
- if (m_ptr[i] == c) return i;
- }
- return -1;
-}
-
-int CBotString::Find(LPCTSTR lpsz)
-{
- int i, j;
- int l = lstrlen(lpsz);
-
- for (i = 0; i <= m_lg-l; i++)
- {
- for (j = 0; j < l; j++)
- {
- if (m_ptr[i+j] != lpsz[j]) goto bad;
- }
- return i;
-bad:;
- }
- return -1;
-}
-
-int CBotString::ReverseFind(const char c)
-{
- int i;
- for (i = m_lg-1; i >= 0; i--)
- {
- if (m_ptr[i] == c) return i;
- }
- return -1;
-}
-
-int CBotString::ReverseFind(LPCTSTR lpsz)
-{
- int i, j;
- int l = lstrlen(lpsz);
-
- for (i = m_lg-l; i >= 0; i--)
- {
- for (j = 0; j < l; j++)
- {
- if (m_ptr[i+j] != lpsz[j]) goto bad;
- }
- return i;
-bad:;
- }
- return -1;
-}
-
-CBotString CBotString::Mid(int start, int lg)
-{
- CBotString res;
- if (start >= m_lg) return res;
-
- if ( lg < 0 ) lg = m_lg - start;
-
- char* p = (char*)malloc(m_lg+1);
- lstrcpy(p, m_ptr+start);
- p[lg] = 0;
-
- res = p;
- free(p);
- return res;
-}
-
-void CBotString::MakeUpper()
-{
- int i;
-
- for ( i = 0; i < m_lg && i < 1999 ; i++)
- {
- char c = m_ptr[i];
- if ( c >= 'a' && c <= 'z' ) m_ptr[i] = c - 'a' + 'A';
- }
-}
-
-void CBotString::MakeLower()
-{
- int i;
-
- for ( i = 0; i < m_lg && i < 1999 ; i++)
- {
- char c = m_ptr[i];
- if ( c >= 'A' && c <= 'Z' ) m_ptr[i] = c - 'A' + 'a';
- }
-}
-
-
-
-#define MAXSTRING 256
-
-BOOL CBotString::LoadString(UINT id)
-{
- char buffer[MAXSTRING];
-
- m_lg = ::LoadString( m_hInstance, id, buffer, MAXSTRING );
-
- if (m_ptr != NULL) free(m_ptr);
-
- m_ptr = NULL;
- if (m_lg > 0)
- {
- m_ptr = (char*)malloc(m_lg+1);
- lstrcpy(m_ptr, buffer);
- return TRUE;
- }
- return FALSE;
-}
-
-
-const CBotString& CBotString::operator=(const CBotString& stringSrc)
-{
- if (m_ptr != NULL) free(m_ptr);
-
- m_lg = stringSrc.m_lg;
- m_ptr = NULL;
-
- if (m_lg > 0)
- {
- m_ptr = (char*)malloc(m_lg+1);
- lstrcpy(m_ptr, stringSrc.m_ptr);
- }
-
- return *this;
-}
-
-CBotString operator+(const CBotString& string, LPCTSTR lpsz)
-{
- CBotString s ( string );
- s += lpsz;
- return s;
-}
-
-const CBotString& CBotString::operator+(const CBotString& stringSrc)
-{
- char* p = (char*)malloc(m_lg+stringSrc.m_lg+1);
-
- lstrcpy(p, m_ptr);
- char* pp = p + m_lg;
- lstrcpy(pp, stringSrc.m_ptr);
-
- if (m_ptr != NULL) free(m_ptr);
- m_ptr = p;
- m_lg += stringSrc.m_lg;
-
- return *this;
-}
-
-const CBotString& CBotString::operator=(const char ch)
-{
- if (m_ptr != NULL) free(m_ptr);
-
- m_lg = 1;
-
- m_ptr = (char*)malloc(2);
- m_ptr[0] = ch;
- m_ptr[1] = 0;
-
- return *this;
-}
-
-const CBotString& CBotString::operator=(const char* pString)
-{
- if (m_ptr != NULL) free(m_ptr);
- m_ptr = NULL;
-
- if ( pString != NULL )
- {
- m_lg = lstrlen(pString);
-
- if (m_lg != 0)
- {
- m_ptr = (char*)malloc(m_lg+1);
- lstrcpy(m_ptr, pString);
- }
- }
-
- return *this;
-}
-
-
-const CBotString& CBotString::operator+=(const char ch)
-{
- char* p = (char*)malloc(m_lg+2);
-
- if (m_ptr!=NULL) lstrcpy(p, m_ptr);
- p[m_lg++] = ch;
- p[m_lg] = 0;
-
- if (m_ptr != NULL) free(m_ptr);
-
- m_ptr = p;
-
- return *this;
-}
-
-const CBotString& CBotString::operator+=(const CBotString& str)
-{
- char* p = (char*)malloc(m_lg+str.m_lg+1);
-
- lstrcpy(p, m_ptr);
- char* pp = p + m_lg;
- lstrcpy(pp, str.m_ptr);
-
- m_lg = m_lg + str.m_lg;
-
- if (m_ptr != NULL) free(m_ptr);
-
- m_ptr = p;
-
- return *this;
-}
-
-BOOL CBotString::operator==(const CBotString& str)
-{
- return Compare(str) == 0;
-}
-
-BOOL CBotString::operator==(const char* p)
-{
- return Compare(p) == 0;
-}
-
-BOOL CBotString::operator!=(const CBotString& str)
-{
- return Compare(str) != 0;
-}
-
-BOOL CBotString::operator!=(const char* p)
-{
- return Compare(p) != 0;
-}
-
-BOOL CBotString::operator>(const CBotString& str)
-{
- return Compare(str) > 0;
-}
-
-BOOL CBotString::operator>(const char* p)
-{
- return Compare(p) > 0;
-}
-
-BOOL CBotString::operator>=(const CBotString& str)
-{
- return Compare(str) >= 0;
-}
-
-BOOL CBotString::operator>=(const char* p)
-{
- return Compare(p) >= 0;
-}
-
-BOOL CBotString::operator<(const CBotString& str)
-{
- return Compare(str) < 0;
-}
-
-BOOL CBotString::operator<(const char* p)
-{
- return Compare(p) < 0;
-}
-
-BOOL CBotString::operator<=(const CBotString& str)
-{
- return Compare(str) <= 0;
-}
-
-BOOL CBotString::operator<=(const char* p)
-{
- return Compare(p) <= 0;
-}
-
-BOOL CBotString::IsEmpty() const
-{
- return (m_lg == 0);
-}
-
-void CBotString::Empty()
-{
- if (m_ptr != NULL) free(m_ptr);
- m_ptr = NULL;
- m_lg = 0;
-}
-
-static char nilstring[] = {0};
-
-CBotString::operator LPCTSTR() const
-{
- if (this == NULL || m_ptr == NULL) return nilstring;
- return m_ptr;
-}
-
-
-int CBotString::Compare(LPCTSTR lpsz) const
-{
- char* p = m_ptr;
- if (lpsz == NULL) lpsz = nilstring;
- if (m_ptr == NULL) p = nilstring;
- return strcmp(p, lpsz); // wcscmp
-}
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////
-// tableaux de chaines
-
-CBotStringArray::CBotStringArray()
-{
- m_pData = NULL;
- m_nSize = m_nMaxSize = 0;
-}
-
-CBotStringArray::~CBotStringArray()
-{
- SetSize(0); // détruit les données !
-}
-
-
-int CBotStringArray::GivSize()
-{
- return m_nSize;
-}
-
-void CBotStringArray::Add(const CBotString& str)
-{
- SetSize(m_nSize+1);
-
- m_pData[m_nSize-1] = str;
-}
-
-
-///////////////////////////////////////////////////////////////////////
-// routines utilitaires
-
-static inline void ConstructElement(CBotString* pNewData)
-{
- memset(pNewData, 0, sizeof(CBotString));
-}
-
-static inline void DestructElement(CBotString* pOldData)
-{
- pOldData->~CBotString();
-}
-
-static inline void CopyElement(CBotString* pSrc, CBotString* pDest)
-{
- *pSrc = *pDest;
-}
-
-static void ConstructElements(CBotString* pNewData, int nCount)
-{
- while (nCount--)
- {
- ConstructElement(pNewData);
- pNewData++;
- }
-}
-
-static void DestructElements(CBotString* pOldData, int nCount)
-{
- while (nCount--)
- {
- DestructElement(pOldData);
- pOldData++;
- }
-}
-
-static void CopyElements(CBotString* pDest, CBotString* pSrc, int nCount)
-{
- while (nCount--)
- {
- *pDest = *pSrc;
- ++pDest;
- ++pSrc;
- }
-}
-
-
-
-// sélect la taille du tableau
-
-void CBotStringArray::SetSize(int nNewSize)
-{
- if (nNewSize == 0)
- {
- // shrink to nothing
-
- DestructElements(m_pData, m_nSize);
- delete[] (BYTE*)m_pData;
- m_pData = NULL;
- m_nSize = m_nMaxSize = 0;
- }
- else if (m_pData == NULL)
- {
- // create one with exact size
- m_pData = (CBotString*) new BYTE[nNewSize * sizeof(CBotString)];
-
- ConstructElements(m_pData, nNewSize);
-
- m_nSize = m_nMaxSize = nNewSize;
- }
- else if (nNewSize <= m_nMaxSize)
- {
- // it fits
- if (nNewSize > m_nSize)
- {
- // initialize the new elements
-
- ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
-
- }
-
- else if (m_nSize > nNewSize) // destroy the old elements
- DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
-
- m_nSize = nNewSize;
- }
- else
- {
- // otherwise, grow array
- int nGrowBy;
- {
- // heuristically determine growth when nGrowBy == 0
- // (this avoids heap fragmentation in many situations)
- nGrowBy = min(1024, max(4, m_nSize / 8));
- }
- int nNewMax;
- if (nNewSize < m_nMaxSize + nGrowBy)
- nNewMax = m_nMaxSize + nGrowBy; // granularity
- else
- nNewMax = nNewSize; // no slush
-
- CBotString* pNewData = (CBotString*) new BYTE[nNewMax * sizeof(CBotString)];
-
- // copy new data from old
- memcpy(pNewData, m_pData, m_nSize * sizeof(CBotString));
-
- // construct remaining elements
- ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
-
-
- // Ret rid of old stuff (note: no destructors called)
- delete[] (BYTE*)m_pData;
- m_pData = pNewData;
- m_nSize = nNewSize;
- m_nMaxSize = nNewMax;
- }
-}
-
-
-CBotString& CBotStringArray::operator[](int nIndex)
-{
- return ElementAt(nIndex);
-}
-
-CBotString& CBotStringArray::ElementAt(int nIndex)
-{
- return m_pData[nIndex];
-}
-
-
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+/////////////////////////////////////////////////////
+
+//strings management
+
+#include "CBot.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+
+//Map is filled with id-string pars that are needed for CBot language parsing
+const std::map<EID, char *> CBotString::s_keywordString =
+{
+ {ID_IF, "if"},
+ {ID_ELSE, "else"},
+ {ID_WHILE, "while"},
+ {ID_DO, "do"},
+ {ID_FOR, "for"},
+ {ID_BREAK, "break"},
+ {ID_CONTINUE, "continue"},
+ {ID_SWITCH, "switch"},
+ {ID_CASE, "case"},
+ {ID_DEFAULT, "default"},
+ {ID_TRY, "try"},
+ {ID_THROW, "throw"},
+ {ID_CATCH, "catch"},
+ {ID_FINALLY, "finally"},
+ {ID_TXT_AND, "and"},
+ {ID_TXT_OR, "or"},
+ {ID_TXT_NOT, "not"},
+ {ID_RETURN, "return"},
+ {ID_CLASS, "class"},
+ {ID_EXTENDS, "extends"},
+ {ID_SYNCHO, "synchronized"},
+ {ID_NEW, "new"},
+ {ID_PUBLIC, "public"},
+ {ID_EXTERN, "extern"},
+ {ID_FINAL, "final"},
+ {ID_STATIC, "static"},
+ {ID_PROTECTED, "protected"},
+ {ID_PRIVATE, "private"},
+ {ID_REPEAT, "repeat"},
+ {ID_DEBUGDD, "STARTDEBUGDD"},
+ {ID_INT, "int"},
+ {ID_FLOAT, "float"},
+ {ID_BOOLEAN, "boolean"},
+ {ID_STRING, "string"},
+ {ID_VOID, "void"},
+ {ID_BOOL, "bool"},
+ {ID_TRUE, "true"},
+ {ID_FALSE, "false"},
+ {ID_NULL, "null"},
+ {ID_NAN, "nan"},
+ {ID_OPENPAR, "("},
+ {ID_CLOSEPAR, ")"},
+ {ID_OPBLK, "{"},
+ {ID_CLBLK, "}"},
+ {ID_SEP, "},"},
+ {ID_COMMA, ","},
+ {ID_DOTS, ":"},
+ {ID_DOT, "."},
+ {ID_OPBRK, "["},
+ {ID_CLBRK, "]"},
+ {ID_DBLDOTS, "::"},
+ {ID_LOGIC, "?"},
+ {ID_ADD, "+"},
+ {ID_SUB, "-"},
+ {ID_MUL, "*"},
+ {ID_DIV, "/"},
+ {ID_ASS, "="},
+ {ID_ASSADD, "+="},
+ {ID_ASSSUB, "-="},
+ {ID_ASSMUL, "*="},
+ {ID_ASSDIV, "/="},
+ {ID_ASSOR, "|="},
+ {ID_ASSAND, "&="},
+ {ID_ASSXOR, "^="},
+ {ID_ASSSL, "<<="},
+ {ID_ASSSR, ">>>="},
+ {ID_ASSASR, ">>="},
+ {ID_SL, "<<"},
+ {ID_SR, ">>"},
+ {ID_ASR, ">>"},
+ {ID_INC, "++"},
+ {ID_DEC, "--"},
+ {ID_LO, "<"},
+ {ID_HI, ">"},
+ {ID_LS, "<<"},
+ {ID_HS, ">="},
+ {ID_EQ, "=="},
+ {ID_NE, "!="},
+ {ID_AND, "&"},
+ {ID_XOR, "^"},
+ {ID_OR, "|"},
+ {ID_LOG_AND, "&&"},
+ {ID_LOG_OR, "||"},
+ {ID_LOG_NOT, "!"},
+ {ID_NOT, "~"},
+ {ID_MODULO, "%"},
+ {ID_POWER, "**"},
+ {ID_ASSMODULO, "%="},
+ {ID_SUPER, "super"},
+ {TX_UNDEF, "undefined"},
+ {TX_NAN, "not a number"}
+};
+
+CBotString::CBotString()
+{
+ m_ptr = NULL;
+ m_lg = 0;
+}
+
+CBotString::~CBotString()
+{
+ free(m_ptr); //we can call free on null pointer as it's save
+}
+
+
+CBotString::CBotString(const char* p)
+{
+ m_lg = strlen(p);
+
+ m_ptr = NULL;
+ if (m_lg>0)
+ {
+ m_ptr = (char*)malloc(m_lg+1);
+ strcpy(m_ptr, p);
+ }
+}
+
+CBotString::CBotString(const CBotString& srcString)
+{
+ m_lg = srcString.m_lg;
+
+ m_ptr = NULL;
+ if (m_lg>0)
+ {
+ m_ptr = (char*)malloc(m_lg+1);
+ strcpy(m_ptr, srcString.m_ptr);
+ }
+}
+
+
+
+
+int CBotString::GivLength()
+{
+ if (m_ptr == NULL) return 0;
+ return strlen( m_ptr );
+}
+
+
+
+CBotString CBotString::Left(int nCount) const
+{
+ char chain[2000];
+
+ size_t i;
+ for (i = 0; i < m_lg && i < nCount && i < 1999; ++i)
+ {
+ chain[i] = m_ptr[i];
+ }
+ chain[i] = 0 ;
+
+ return CBotString(chain);
+}
+
+CBotString CBotString::Right(int nCount) const
+{
+ char chain[2000];
+
+ int i = m_lg - nCount;
+ if ( i < 0 ) i = 0;
+
+ size_t j;
+ for (size_t j = 0 ; i < m_lg && i < 1999; ++i)
+ {
+ chain[j++] = m_ptr[i];
+ }
+ chain[j] = 0 ;
+
+ return CBotString(chain);
+}
+
+CBotString CBotString::Mid(int nFirst, int nCount) const
+{
+ char chain[2000];
+
+ size_t i;
+ for (i = nFirst; i < m_lg && i < 1999 && i <= nFirst + nCount; ++i)
+ {
+ chain[i] = m_ptr[i];
+ }
+ chain[i] = 0 ;
+
+ return CBotString(chain);
+}
+
+CBotString CBotString::Mid(int nFirst) const
+{
+ char chain[2000];
+
+ size_t i;
+ for (i = nFirst; i < m_lg && i < 1999 ; ++i)
+ {
+ chain[i] = m_ptr[i];
+ }
+ chain[i] = 0 ;
+
+ return CBotString(chain);
+}
+
+
+int CBotString::Find(const char c)
+{
+ for (size_t i = 0; i < m_lg; ++i)
+ {
+ if (m_ptr[i] == c) return i;
+ }
+ return -1;
+}
+
+int CBotString::Find(const char * lpsz)
+{
+ int l = strlen(lpsz);
+
+ for (size_t i = 0; i <= m_lg-l; ++i)
+ {
+ for (size_t j = 0; j < l; ++j)
+ {
+ if (m_ptr[i+j] != lpsz[j]) goto bad;
+ }
+ return i;
+bad:;
+ }
+ return -1;
+}
+
+int CBotString::ReverseFind(const char c)
+{
+ int i;
+ for (i = m_lg-1; i >= 0; --i)
+ {
+ if (m_ptr[i] == c) return i;
+ }
+ return -1;
+}
+
+int CBotString::ReverseFind(const char * lpsz)
+{
+ int i, j;
+ int l = strlen(lpsz);
+
+ for (i = m_lg-l; i >= 0; --i)
+ {
+ for (j = 0; j < l; ++j)
+ {
+ if (m_ptr[i+j] != lpsz[j]) goto bad;
+ }
+ return i;
+bad:;
+ }
+ return -1;
+}
+
+CBotString CBotString::Mid(int start, int lg)
+{
+ CBotString res;
+ if (start >= m_lg) return res;
+
+ if ( lg < 0 ) lg = m_lg - start;
+
+ char* p = (char*)malloc(m_lg+1);
+ strcpy(p, m_ptr+start);
+ p[lg] = 0;
+
+ res = p;
+ free(p);
+ return res;
+}
+
+void CBotString::MakeUpper()
+{
+ for (size_t i = 0; i < m_lg && i < 1999 ; ++i)
+ {
+ char c = m_ptr[i];
+ if ( c >= 'a' && c <= 'z' ) m_ptr[i] = c - 'a' + 'A';
+ }
+}
+
+void CBotString::MakeLower()
+{
+ for (size_t i = 0; i < m_lg && i < 1999 ; ++i)
+ {
+ char c = m_ptr[i];
+ if ( c >= 'A' && c <= 'Z' ) m_ptr[i] = c - 'A' + 'a';
+ }
+}
+
+bool CBotString::LoadString(unsigned int id)
+{
+ const char * str = NULL;
+ str = MapIdToString((EID)id);
+ if (m_ptr != NULL) free(m_ptr);
+
+ m_lg = strlen(str);
+ m_ptr = NULL;
+ if (m_lg > 0)
+ {
+ m_ptr = (char*)malloc(m_lg+1);
+ strcpy(m_ptr, str);
+ return true;
+ }
+ return false;
+}
+
+
+const CBotString& CBotString::operator=(const CBotString& stringSrc)
+{
+ free(m_ptr);
+ m_ptr = NULL;
+
+ m_lg = stringSrc.m_lg;
+
+ if (m_lg > 0)
+ {
+ m_ptr = (char*)malloc(m_lg+1);
+ strcpy(m_ptr, stringSrc.m_ptr);
+ }
+
+ return *this;
+}
+
+CBotString operator+(const CBotString& string, const char * lpsz)
+{
+ CBotString s(string);
+ s += lpsz;
+ return s;
+}
+
+const CBotString& CBotString::operator+(const CBotString& stringSrc)
+{
+ char* p = (char*)malloc(m_lg+stringSrc.m_lg+1);
+
+ strcpy(p, m_ptr);
+ char* pp = p + m_lg;
+ strcpy(pp, stringSrc.m_ptr);
+
+ free(m_ptr);
+ m_ptr = p;
+ m_lg += stringSrc.m_lg;
+
+ return *this;
+}
+
+const CBotString& CBotString::operator=(const char ch)
+{
+ free(m_ptr);
+
+ m_lg = 1;
+
+ m_ptr = (char*)malloc(2);
+ m_ptr[0] = ch;
+ m_ptr[1] = 0;
+
+ return *this;
+}
+
+const CBotString& CBotString::operator=(const char* pString)
+{
+ free(m_ptr);
+ m_ptr = NULL;
+
+ if (pString != NULL)
+ {
+ m_lg = strlen(pString);
+
+ if (m_lg != 0)
+ {
+ m_ptr = (char*)malloc(m_lg+1);
+ strcpy(m_ptr, pString);
+ }
+ }
+
+ return *this;
+}
+
+
+const CBotString& CBotString::operator+=(const char ch)
+{
+ char* p = (char*)malloc(m_lg+2);
+
+ if (m_ptr!=NULL) strcpy(p, m_ptr);
+ p[m_lg++] = ch;
+ p[m_lg] = 0;
+
+ free(m_ptr);
+
+ m_ptr = p;
+
+ return *this;
+}
+
+const CBotString& CBotString::operator+=(const CBotString& str)
+{
+ char* p = (char*)malloc(m_lg+str.m_lg+1);
+
+ strcpy(p, m_ptr);
+ char* pp = p + m_lg;
+ strcpy(pp, str.m_ptr);
+
+ m_lg = m_lg + str.m_lg;
+
+ free(m_ptr);
+
+ m_ptr = p;
+
+ return *this;
+}
+
+bool CBotString::operator==(const CBotString& str)
+{
+ return Compare(str) == 0;
+}
+
+bool CBotString::operator==(const char* p)
+{
+ return Compare(p) == 0;
+}
+
+bool CBotString::operator!=(const CBotString& str)
+{
+ return Compare(str) != 0;
+}
+
+bool CBotString::operator!=(const char* p)
+{
+ return Compare(p) != 0;
+}
+
+bool CBotString::operator>(const CBotString& str)
+{
+ return Compare(str) > 0;
+}
+
+bool CBotString::operator>(const char* p)
+{
+ return Compare(p) > 0;
+}
+
+bool CBotString::operator>=(const CBotString& str)
+{
+ return Compare(str) >= 0;
+}
+
+bool CBotString::operator>=(const char* p)
+{
+ return Compare(p) >= 0;
+}
+
+bool CBotString::operator<(const CBotString& str)
+{
+ return Compare(str) < 0;
+}
+
+bool CBotString::operator<(const char* p)
+{
+ return Compare(p) < 0;
+}
+
+bool CBotString::operator<=(const CBotString& str)
+{
+ return Compare(str) <= 0;
+}
+
+bool CBotString::operator<=(const char* p)
+{
+ return Compare(p) <= 0;
+}
+
+bool CBotString::IsEmpty() const
+{
+ return (m_lg == 0);
+}
+
+void CBotString::Empty()
+{
+ free(m_ptr);
+ m_ptr = NULL;
+ m_lg = 0;
+}
+
+static char emptyString[] = {0};
+
+CBotString::operator const char * () const
+{
+ if (this == NULL || m_ptr == NULL) return emptyString;
+ return m_ptr;
+}
+
+
+int CBotString::Compare(const char * lpsz) const
+{
+ char* p = m_ptr;
+ if (lpsz == NULL) lpsz = emptyString;
+ if (m_ptr == NULL) p = emptyString;
+ return strcmp(p, lpsz); // wcscmp
+}
+
+const char * CBotString::MapIdToString(EID id)
+{
+ if (s_keywordString.find(id) != s_keywordString.end())
+ {
+ return s_keywordString.at(id);
+ }
+ else
+ {
+ return emptyString;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// arrays of strings
+
+CBotStringArray::CBotStringArray()
+{
+ m_pData = NULL;
+ m_nSize = m_nMaxSize = 0;
+}
+
+CBotStringArray::~CBotStringArray()
+{
+ SetSize(0); // destroys data !
+}
+
+
+int CBotStringArray::GivSize()
+{
+ return m_nSize;
+}
+
+void CBotStringArray::Add(const CBotString& str)
+{
+ SetSize(m_nSize+1);
+
+ m_pData[m_nSize-1] = str;
+}
+
+///////////////////////////////////////////////////////////////////////
+// utility routines
+
+static inline void ConstructElement(CBotString* pNewData)
+{
+ memset(pNewData, 0, sizeof(CBotString));
+}
+
+static inline void DestructElement(CBotString* pOldData)
+{
+ pOldData->~CBotString();
+}
+
+static inline void CopyElement(CBotString* pSrc, CBotString* pDest)
+{
+ *pSrc = *pDest;
+}
+
+static void ConstructElements(CBotString* pNewData, int nCount)
+{
+ while (nCount--)
+ {
+ ConstructElement(pNewData);
+ pNewData++;
+ }
+}
+
+static void DestructElements(CBotString* pOldData, int nCount)
+{
+ while (nCount--)
+ {
+ DestructElement(pOldData);
+ pOldData++;
+ }
+}
+
+static void CopyElements(CBotString* pDest, CBotString* pSrc, int nCount)
+{
+ while (nCount--)
+ {
+ *pDest = *pSrc;
+ ++pDest;
+ ++pSrc;
+ }
+}
+
+
+
+// set the array size
+
+void CBotStringArray::SetSize(int nNewSize)
+{
+ if (nNewSize == 0)
+ {
+ // shrink to nothing
+
+ DestructElements(m_pData, m_nSize);
+ delete[] (unsigned char *)m_pData;
+ m_pData = NULL;
+ m_nSize = m_nMaxSize = 0;
+ }
+ else if (m_pData == NULL)
+ {
+ // create one with exact size
+ m_pData = (CBotString*) new unsigned char[nNewSize * sizeof(CBotString)];
+
+ ConstructElements(m_pData, nNewSize);
+
+ m_nSize = m_nMaxSize = nNewSize;
+ }
+ else if (nNewSize <= m_nMaxSize)
+ {
+ // it fits
+ if (nNewSize > m_nSize)
+ {
+ // initialize the new elements
+
+ ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
+
+ }
+
+ else if (m_nSize > nNewSize) // destroy the old elements
+ DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
+
+ m_nSize = nNewSize;
+ }
+ else
+ {
+ // otherwise, grow array
+ int nGrowBy;
+ {
+ // heuristically determine growth when nGrowBy == 0
+ // (this avoids heap fragmentation in many situations)
+ nGrowBy = std::min(1024, std::max(4, m_nSize / 8));
+ }
+ int nNewMax;
+ if (nNewSize < m_nMaxSize + nGrowBy)
+ nNewMax = m_nMaxSize + nGrowBy; // granularity
+ else
+ nNewMax = nNewSize; // no slush
+
+ CBotString* pNewData = (CBotString*) new unsigned char[nNewMax * sizeof(CBotString)];
+
+ // copy new data from old
+ memcpy(pNewData, m_pData, m_nSize * sizeof(CBotString));
+
+ // construct remaining elements
+ ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
+
+
+ // Get rid of old stuff (note: no destructors called)
+ delete[] (unsigned char *)m_pData;
+ m_pData = pNewData;
+ m_nSize = nNewSize;
+ m_nMaxSize = nNewMax;
+ }
+}
+
+
+CBotString& CBotStringArray::operator[](int nIndex)
+{
+ return ElementAt(nIndex);
+}
+
+CBotString& CBotStringArray::ElementAt(int nIndex)
+{
+ return m_pData[nIndex];
+}
+
diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp
index fbf6726..2c0bfae 100644
--- a/src/CBot/CBotToken.cpp
+++ b/src/CBot/CBotToken.cpp
@@ -1,554 +1,562 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.//////////////////////////////////////////////////////////////////
-// Gestion des Tokens
-// le texte d'un programme est d'abord transformé
-// en une suite de tokens pour facilité l'interprétation
-
-// il faudra traiter le seul cas d'erreur possible
-// qui est un caractère illégal dans une string
-
-
-#include "CBot.h"
-
-CBotStringArray CBotToken::m_ListKeyWords;
-int CBotToken::m_ListIdKeyWords[200];
-CBotStringArray CBotToken::m_ListKeyDefine;
-long CBotToken::m_ListKeyNums[MAXDEFNUM];
-
-// constructeurs
-CBotToken::CBotToken()
-{
- m_next = NULL;
- m_prev = NULL;
-
- m_type = TokenTypVar; // à priori un nom d'une variable
- m_IdKeyWord = -1;
-}
-
-CBotToken::CBotToken(const CBotToken* pSrc)
-{
- m_next = NULL;
- m_prev = NULL;
-
- m_Text.Empty();
- m_Sep.Empty();
-
- m_type = 0;
- m_IdKeyWord = 0;
-
- m_start = 0;
- m_end = 0;
-
- if ( pSrc != NULL )
- {
- m_Text = pSrc->m_Text;
- m_Sep = pSrc->m_Sep;
-
- m_type = pSrc->m_type;
- m_IdKeyWord = pSrc->m_IdKeyWord;
-
- m_start = pSrc->m_start;
- m_end = pSrc->m_end;
- }
-}
-
-CBotToken::CBotToken(const CBotString& mot, const CBotString& sep, int start, int end)
-{
- m_Text = mot; // mot trouvé comme token
- m_Sep = sep; // séparateurs qui suivent
- m_next = NULL;
- m_prev = NULL;
- m_start = start;
- m_end = end;
-
- m_type = TokenTypVar; // à priori un nom d'une variable
- m_IdKeyWord = -1;
-}
-
-CBotToken::CBotToken(const char* mot, const char* sep)
-{
- m_Text = mot;
- if ( sep != NULL ) m_Sep = sep;
- m_next = NULL;
- m_prev = NULL;
-
- m_type = TokenTypVar; // à priori un nom d'une variable
- m_IdKeyWord = -1;
-}
-
-CBotToken::~CBotToken()
-{
- delete m_next; // récursif
- m_next = NULL;
-}
-
-void CBotToken::Free()
-{
- m_ListKeyDefine.SetSize(0);
-}
-
-const CBotToken& CBotToken::operator=(const CBotToken& src)
-{
- if (m_next != NULL) delete(m_next);
- m_next = NULL;
- m_prev = NULL;
-
- m_Text = src.m_Text;
- m_Sep = src.m_Sep;
-
- m_type = src.m_type;
- m_IdKeyWord = src.m_IdKeyWord;
-
- m_start = src.m_start;
- m_end = src.m_end;
- return *this;
-}
-
-
-int CBotToken::GivType()
-{
- if (this == NULL) return 0;
- if (m_type == TokenTypKeyWord) return m_IdKeyWord;
- return m_type;
-}
-
-long CBotToken::GivIdKey()
-{
- return m_IdKeyWord;
-}
-
-CBotToken* CBotToken::GivNext()
-{
- if (this == NULL) return NULL;
- return m_next;
-}
-
-CBotToken* CBotToken::GivPrev()
-{
- if (this == NULL) return NULL;
- return m_prev;
-}
-
-void CBotToken::AddNext(CBotToken* p)
-{
- CBotToken* n = new CBotToken(p);
- CBotToken* pt = this;
-
- while ( pt->m_next != NULL ) pt = pt->m_next;
-
- pt->m_next = n;
- n->m_prev = pt;
-}
-
-
-CBotString& CBotToken::GivString()
-{
- return m_Text;
-}
-
-CBotString& CBotToken::GivSep()
-{
- return m_Sep;
-}
-
-void CBotToken::SetString(const char* name)
-{
- m_Text = name;
-}
-
-
-int CBotToken::GivStart()
-{
- if (this == NULL) return -1;
- return m_start;
-}
-
-int CBotToken::GivEnd()
-{
- if (this == NULL) return -1;
- return m_end;
-}
-
-void CBotToken::SetPos(int start, int end)
-{
- m_start = start;
- m_end = end;
-}
-
-BOOL CharInList(const char c, const char* list)
-{
- int i = 0;
-
- while (TRUE)
- {
- if (c == list[i++]) return TRUE;
- if (list[i] == 0) return FALSE;
- }
-}
-
-BOOL Char2InList(const char c, const char cc, const char* list)
-{
- int i = 0;
-
- while (TRUE)
- {
- if (c == list[i++] &&
- cc == list[i++]) return TRUE;
-
- if (list[i] == 0) return FALSE;
- }
-}
-
-static char* sep1 = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
-static char* sep2 = " \r\n\t"; // séparateurs pures
-static char* sep3 = ",:()[]{}-+*/=;<>!~^|&%."; // séparateurs opérationnels
-static char* num = "0123456789"; // le point (unique) est testé séparément
-static char* hexnum = "0123456789ABCDEFabcdef";
-static char* nch = "\"\r\n\t"; // refusé dans les chaines
-
-//static char* duo = "+=-=*=/===!=<=>=++--///**/||&&";// les opérateurs doubles
-
-// cherche le prochain token dans une phrase
-// ne doit pas commencer par des séparateurs
-// qui sont pris avec le token précédent
-CBotToken* CBotToken::NextToken(char* &program, int& error, BOOL first)
-{
- CBotString mot; // le mot trouvé
- CBotString sep; // les séparateurs qui le suivent
- char c;
- BOOL stop = first;
-
- if (*program == 0) return NULL;
-
- c = *(program++); // prochain caractère
-
- if (!first)
- {
- mot = c; // construit le mot
- c = *(program++); // prochain caractère
-
- // cas particulier pour les chaînes de caractères
- if ( mot[0] == '\"' )
- {
- while (c != 0 && !CharInList(c, nch))
- {
- mot += c;
- c = *(program++); // prochain caractère
- if ( c == '\\' )
- {
- c = *(program++); // prochain caractère
- if ( c == 'n' ) c = '\n';
- if ( c == 'r' ) c = '\r';
- if ( c == 't' ) c = '\t';
- mot += c;
- c = *(program++); // prochain caractère
- }
- }
- if ( c == '\"' )
- {
- mot += c; // chaîne complète
- c = *(program++); // prochain caractère
- }
- stop = TRUE;
- }
-
- // cas particulier pour les nombres
- if ( CharInList(mot[0], num ))
- {
- BOOL bdot = FALSE; // trouvé un point ?
- BOOL bexp = FALSE; // trouvé un exposant ?
-
- char* liste = num;
- if (mot[0] == '0' && c == 'x') // valeur hexadécimale ?
- {
- mot += c;
- c = *(program++); // prochain caractère
- liste = hexnum;
- }
-cw:
- while (c != 0 && CharInList(c, liste))
- {
-cc: mot += c;
- c = *(program++); // prochain caractère
- }
- if ( liste == num ) // pas pour les exadécimaux
- {
- if ( !bdot && c == '.' ) { bdot = TRUE; goto cc; }
- if ( !bexp && ( c == 'e' || c == 'E' ) )
- {
- bexp = TRUE;
- mot += c;
- c = *(program++); // prochain caractère
- if ( c == '-' ||
- c == '+' ) goto cc;
- goto cw;
- }
-
- }
- stop = TRUE;
- }
-
- if (CharInList(mot[0], sep3)) // un séparateur opérationnel ?
- {
- CBotString motc = mot;
- while (motc += c, c != 0 && GivKeyWords(motc)>0) // cherche l'opérande le plus long possible
- {
- mot += c; // construit le mot
- c = *(program++); // prochain caractère
- }
-
- stop = TRUE;
- }
- }
-
-
-
- while (TRUE)
- {
- if (stop || c == 0 || CharInList(c, sep1))
- {
- if (!first && mot.IsEmpty()) return NULL; // fin de l'analyse
-bis:
- while (CharInList(c, sep2))
- {
- sep += c; // tous les séparateurs qui suivent
- c = *(program++);
- }
- if (c == '/' && *program == '/') // un commentaire dans le tas ?
- {
- while( c != '\n' && c != 0 )
- {
- sep += c;
- c = *(program++); // prochain caractère
- }
- goto bis;
- }
-
- if (c == '/' && *program == '*') // un commentaire dans le tas ?
- {
- while( c != 0 && (c != '*' || *program != '/'))
- {
- sep += c;
- c = *(program++); // prochain caractère
- }
- if ( c != 0 )
- {
- sep += c;
- c = *(program++); // prochain caractère
- sep += c;
- c = *(program++); // prochain caractère
- }
- goto bis;
- }
-
- program--;
-
- CBotToken* token = new CBotToken(mot, sep);
-
- if (CharInList( mot[0], num )) token->m_type = TokenTypNum;
- if (mot[0] == '\"') token->m_type = TokenTypString;
- if (first) token->m_type = 0;
-
- token->m_IdKeyWord = GivKeyWords(mot);
- if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord;
- else GivKeyDefNum(mot, token) ; // traite les DefineNum
-
- return token;
- }
-
- mot += c; // construit le mot
- c = *(program++); // prochain caractère
- }
-}
-
-CBotToken* CBotToken::CompileTokens(const char* program, int& error)
-{
- CBotToken *nxt, *prv, *tokenbase;
- char* p = (char*) program;
- int pos = 0;
-
- error = 0;
- prv = tokenbase = NextToken(p, error, TRUE);
-
- if (tokenbase == NULL) return NULL;
-
- tokenbase->m_start = pos;
- pos += tokenbase->m_Text.GivLength();
- tokenbase->m_end = pos;
- pos += tokenbase->m_Sep.GivLength();
-
- char* pp = p;
- while (NULL != (nxt = NextToken(p, error)))
- {
- prv->m_next = nxt; // ajoute à la suite
- nxt->m_prev = prv;
- prv = nxt; // avance
-
- nxt->m_start = pos;
-/* pos += nxt->m_Text.GivLength(); // la chaîne peut être plus courte (BOA supprimés)
- nxt->m_end = pos;
- pos += nxt->m_Sep.GivLength();*/
- pos += (p - pp); // taille totale
- nxt->m_end = pos - nxt->m_Sep.GivLength();
- pp = p;
- }
-
- // ajoute un token comme terminateur
- // ( utile pour avoir le précédent )
- nxt = new CBotToken();
- nxt->m_type = 0;
- prv->m_next = nxt; // ajoute à la suite
- nxt->m_prev = prv;
-
- return tokenbase;
-}
-
-void CBotToken::Delete(CBotToken* pToken)
-{
- delete pToken;
-}
-
-
-// recherche si un mot fait parti des mots clefs
-
-int CBotToken::GivKeyWords(const char* w)
-{
- int i;
- int l = m_ListKeyWords.GivSize();
-
- if (l == 0)
- {
- LoadKeyWords(); // prend la liste la première fois
- l = m_ListKeyWords.GivSize();
- }
-
- for (i = 0; i < l; i++)
- {
- if (m_ListKeyWords[i] == w) return m_ListIdKeyWords[ i ];
- }
-
- return -1;
-}
-
-BOOL CBotToken::GivKeyDefNum(const char* w, CBotToken* &token)
-{
- int i;
- int l = m_ListKeyDefine.GivSize();
-
- for (i = 0; i < l; i++)
- {
- if (m_ListKeyDefine[i] == w)
- {
- token->m_IdKeyWord = m_ListKeyNums[i];
- token->m_type = TokenTypDef;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-// reprend la liste des mots clefs dans les ressources
-
-void CBotToken::LoadKeyWords()
-{
- CBotString s;
- int i, n = 0;
-
- i = TokenKeyWord;
- while (s.LoadString(i))
- {
- m_ListKeyWords.Add(s);
- m_ListIdKeyWords[n++] = i++;
- }
-
- i = TokenKeyDeclare;
- while (s.LoadString(i))
- {
- m_ListKeyWords.Add(s);
- m_ListIdKeyWords[n++] = i++;
- }
-
-
- i = TokenKeyVal;
- while (s.LoadString(i))
- {
- m_ListKeyWords.Add(s);
- m_ListIdKeyWords[n++] = i++;
- }
-
- i = TokenKeyOp;
- while (s.LoadString(i))
- {
- m_ListKeyWords.Add(s);
- m_ListIdKeyWords[n++] = i++;
- }
-}
-
-BOOL CBotToken::DefineNum(const char* name, long val)
-{
- int i;
- int l = m_ListKeyDefine.GivSize();
-
- for (i = 0; i < l; i++)
- {
- if (m_ListKeyDefine[i] == name) return FALSE;
- }
- if ( i == MAXDEFNUM ) return FALSE;
-
- m_ListKeyDefine.Add( name );
- m_ListKeyNums[i] = val;
- return TRUE;
-}
-
-BOOL IsOfType(CBotToken* &p, int type1, int type2)
-{
- if (p->GivType() == type1 ||
- p->GivType() == type2 )
- {
- p = p->GivNext();
- return TRUE;
- }
- return FALSE;
-}
-
-// idem avec un nombre indéfini d'arguments
-// il faut mettre un zéro comme dernier argument
-BOOL IsOfTypeList(CBotToken* &p, int type1, ...)
-{
- int i = type1;
- int max = 20;
- int type = p->GivType();
-
- va_list marker;
- va_start( marker, type1 ); /* Initialize variable arguments. */
-
- while (TRUE)
- {
- if (type == i)
- {
- p = p->GivNext();
- va_end( marker ); /* Reset variable arguments. */
- return TRUE;
- }
- if (--max == 0 || 0 == (i = va_arg( marker, int)))
- {
- va_end( marker ); /* Reset variable arguments. */
- return FALSE;
- }
- }
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+
+//CBotToken.cpp
+
+//////////////////////////////////////////////////////////////////
+// Managing Tokens
+// the text of a program is first transformed
+// into a sequence of tokens for easy interpretation
+// it will only treat the case as an error
+// where there is an illegal character in a string
+
+
+#include "CBot.h"
+#include <cstdarg>
+
+CBotStringArray CBotToken::m_ListKeyWords;
+int CBotToken::m_ListIdKeyWords[200];
+CBotStringArray CBotToken::m_ListKeyDefine;
+long CBotToken::m_ListKeyNums[MAXDEFNUM];
+
+//! contructors
+CBotToken::CBotToken()
+{
+ m_next = NULL;
+ m_prev = NULL;
+ m_type = TokenTypVar; // at the beginning a default variable type
+ m_IdKeyWord = -1;
+}
+
+CBotToken::CBotToken(const CBotToken* pSrc)
+{
+ m_next = NULL;
+ m_prev = NULL;
+
+ m_Text.Empty();
+ m_Sep.Empty();
+
+ m_type = 0;
+ m_IdKeyWord = 0;
+
+ m_start = 0;
+ m_end = 0;
+
+ if ( pSrc != NULL )
+ {
+
+ m_type = pSrc->m_type;
+ m_IdKeyWord = pSrc->m_IdKeyWord;
+
+ m_Text = pSrc->m_Text;
+ m_Sep = pSrc->m_Sep;
+
+ m_start = pSrc->m_start;
+ m_end = pSrc->m_end;
+ }
+}
+
+CBotToken::CBotToken(const CBotString& mot, const CBotString& sep, int start, int end)
+{
+ m_Text = mot; // word (mot) found as token
+ m_Sep = sep; // separator
+ m_next = NULL;
+ m_prev = NULL;
+ m_start = start;
+ m_end = end;
+
+ m_type = TokenTypVar; // at the beginning a default variable type
+ m_IdKeyWord = -1;
+}
+
+CBotToken::CBotToken(const char* mot, const char* sep)
+{
+ m_Text = mot;
+ if ( sep != NULL ) m_Sep = sep;
+ m_next = NULL;
+ m_prev = NULL;
+
+ m_type = TokenTypVar; // at the beginning a default variable type
+ m_IdKeyWord = -1;
+}
+
+CBotToken::~CBotToken()
+{
+ delete m_next; // recursive
+ m_next = NULL;
+}
+
+void CBotToken::Free()
+{
+ m_ListKeyDefine.SetSize(0);
+}
+
+const CBotToken& CBotToken::operator=(const CBotToken& src)
+{
+ if (m_next != NULL) delete(m_next);
+ m_next = NULL;
+ m_prev = NULL;
+
+ m_Text = src.m_Text;
+ m_Sep = src.m_Sep;
+
+ m_type = src.m_type;
+ m_IdKeyWord = src.m_IdKeyWord;
+
+ m_start = src.m_start;
+ m_end = src.m_end;
+ return *this;
+}
+
+
+int CBotToken::GivType()
+{
+ if (this == NULL) return 0;
+ if (m_type == TokenTypKeyWord) return m_IdKeyWord;
+ return m_type;
+}
+
+long CBotToken::GivIdKey()
+{
+ return m_IdKeyWord;
+}
+
+CBotToken* CBotToken::GivNext()
+{
+ if (this == NULL) return NULL;
+ return m_next;
+}
+
+CBotToken* CBotToken::GivPrev()
+{
+ if (this == NULL) return NULL;
+ return m_prev;
+}
+
+void CBotToken::AddNext(CBotToken* p)
+{
+ CBotToken* n = new CBotToken(p);
+ CBotToken* pt = this;
+
+ while ( pt->m_next != NULL ) pt = pt->m_next;
+
+ pt->m_next = n;
+ n->m_prev = pt;
+}
+
+
+CBotString& CBotToken::GivString()
+{
+ return m_Text;
+}
+
+CBotString& CBotToken::GivSep()
+{
+ return m_Sep;
+}
+
+void CBotToken::SetString(const char* name)
+{
+ m_Text = name;
+}
+
+
+int CBotToken::GivStart()
+{
+ if (this == NULL) return -1;
+ return m_start;
+}
+
+int CBotToken::GivEnd()
+{
+ if (this == NULL) return -1;
+ return m_end;
+}
+
+void CBotToken::SetPos(int start, int end)
+{
+ m_start = start;
+ m_end = end;
+}
+
+bool CharInList(const char c, const char* list)
+{
+ int i = 0;
+
+ while (true)
+ {
+ if (c == list[i++]) return true;
+ if (list[i] == 0) return false;
+ }
+}
+
+bool Char2InList(const char c, const char cc, const char* list)
+{
+ int i = 0;
+
+ while (true)
+ {
+ if (c == list[i++] &&
+ cc == list[i++]) return true;
+
+ if (list[i] == 0) return false;
+ }
+}
+
+static char* sep1 = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
+static char* sep2 = " \r\n\t"; // only separators
+static char* sep3 = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators
+static char* num = "0123456789"; // point (single) is tested separately
+static char* hexnum = "0123456789ABCDEFabcdef";
+static char* nch = "\"\r\n\t"; // forbidden in chains
+
+//static char* duo = "+=-=*=/===!=<=>=++--///**/||&&"; // double operators
+
+// looking for the next token in a sentence
+// do not start with separators
+// which are made in the previous token
+CBotToken* CBotToken::NextToken(char* &program, int& error, bool first)
+{
+ CBotString mot; // the word which is found
+ CBotString sep; // separators that are after
+ char c;
+ bool stop = first;
+
+ if (*program == 0) return NULL;
+
+ c = *(program++); // next character
+
+ if (!first)
+ {
+ mot = c; // built the word
+ c = *(program++); // next character
+
+ // special case for strings
+ if ( mot[0] == '\"' )
+ {
+ while (c != 0 && !CharInList(c, nch))
+ {
+ mot += c;
+ c = *(program++); // next character
+ if ( c == '\\' )
+ {
+ c = *(program++); // next character
+ if ( c == 'n' ) c = '\n';
+ if ( c == 'r' ) c = '\r';
+ if ( c == 't' ) c = '\t';
+ mot += c;
+ c = *(program++); // next character
+ }
+ }
+ if ( c == '\"' )
+ {
+ mot += c; // string is complete
+ c = *(program++); // next character
+ }
+ stop = true;
+ }
+
+ // special case for numbers
+ if ( CharInList(mot[0], num ))
+ {
+ bool bdot = false; // found a point?
+ bool bexp = false; // found an exponent?
+
+ char* liste = num;
+ if (mot[0] == '0' && c == 'x') // hexadecimal value?
+ {
+ mot += c;
+ c = *(program++); // next character
+ liste = hexnum;
+ }
+cw:
+ while (c != 0 && CharInList(c, liste))
+ {
+cc: mot += c;
+ c = *(program++); // next character
+ }
+ if ( liste == num ) // not for hexadecimal
+ {
+ if ( !bdot && c == '.' ) { bdot = true; goto cc; }
+ if ( !bexp && ( c == 'e' || c == 'E' ) )
+ {
+ bexp = true;
+ mot += c;
+ c = *(program++); // next character
+ if ( c == '-' ||
+ c == '+' ) goto cc;
+ goto cw;
+ }
+
+ }
+ stop = true;
+ }
+
+ if (CharInList(mot[0], sep3)) // an operational separator?
+ {
+ CBotString motc = mot;
+ while (motc += c, c != 0 && GivKeyWords(motc)>0) // operand seeks the longest possible
+ {
+ mot += c; // build the word
+ c = *(program++); // next character
+ }
+
+ stop = true;
+ }
+ }
+
+
+
+ while (true)
+ {
+ if (stop || c == 0 || CharInList(c, sep1))
+ {
+ if (!first && mot.IsEmpty()) return NULL; // end of the analysis
+bis:
+ while (CharInList(c, sep2))
+ {
+ sep += c; // after all the separators
+ c = *(program++);
+ }
+ if (c == '/' && *program == '/') // comment on the heap?
+ {
+ while( c != '\n' && c != 0 )
+ {
+ sep += c;
+ c = *(program++); // next character
+ }
+ goto bis;
+ }
+
+ if (c == '/' && *program == '*') // comment on the heap?
+ {
+ while( c != 0 && (c != '*' || *program != '/'))
+ {
+ sep += c;
+ c = *(program++); // next character
+ }
+ if ( c != 0 )
+ {
+ sep += c;
+ c = *(program++); // next character
+ sep += c;
+ c = *(program++); // next character
+ }
+ goto bis;
+ }
+
+ program--;
+
+ CBotToken* token = new CBotToken(mot, sep);
+
+ if (CharInList( mot[0], num )) token->m_type = TokenTypNum;
+ if (mot[0] == '\"') token->m_type = TokenTypString;
+ if (first) token->m_type = 0;
+
+ token->m_IdKeyWord = GivKeyWords(mot);
+ if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord;
+ else GivKeyDefNum(mot, token) ; // treats DefineNum
+
+ return token;
+ }
+
+ mot += c; // built the word
+ c = *(program++); // next character
+ }
+}
+
+CBotToken* CBotToken::CompileTokens(const char* program, int& error)
+{
+ CBotToken *nxt, *prv, *tokenbase;
+ char* p = (char*) program;
+ int pos = 0;
+
+ error = 0;
+ prv = tokenbase = NextToken(p, error, true);
+
+ if (tokenbase == NULL) return NULL;
+
+ tokenbase->m_start = pos;
+ pos += tokenbase->m_Text.GivLength();
+ tokenbase->m_end = pos;
+ pos += tokenbase->m_Sep.GivLength();
+
+ char* pp = p;
+ while (NULL != (nxt = NextToken(p, error)))
+ {
+ prv->m_next = nxt; // added after
+ nxt->m_prev = prv;
+ prv = nxt; // advance
+
+ nxt->m_start = pos;
+/* pos += nxt->m_Text.GivLength(); // chain may be shorter (BOA deleted)
+ nxt->m_end = pos;
+ pos += nxt->m_Sep.GivLength();*/
+ pos += (p - pp); // total size
+ nxt->m_end = pos - nxt->m_Sep.GivLength();
+ pp = p;
+ }
+
+ // adds a token as a terminator
+ // ( useful for the previous )
+ nxt = new CBotToken();
+ nxt->m_type = 0;
+ prv->m_next = nxt; // added after
+ nxt->m_prev = prv;
+
+ return tokenbase;
+}
+
+void CBotToken::Delete(CBotToken* pToken)
+{
+ delete pToken;
+}
+
+
+// search if a word is part of the keywords
+
+int CBotToken::GivKeyWords(const char* w)
+{
+ int i;
+ int l = m_ListKeyWords.GivSize();
+
+ if (l == 0)
+ {
+ LoadKeyWords(); // takes the list for the first time
+ l = m_ListKeyWords.GivSize();
+ }
+
+ for (i = 0; i < l; i++)
+ {
+ if (m_ListKeyWords[i] == w) return m_ListIdKeyWords[ i ];
+ }
+
+ return -1;
+}
+
+bool CBotToken::GivKeyDefNum(const char* w, CBotToken* &token)
+{
+ int i;
+ int l = m_ListKeyDefine.GivSize();
+
+ for (i = 0; i < l; i++)
+ {
+ if (m_ListKeyDefine[i] == w)
+ {
+ token->m_IdKeyWord = m_ListKeyNums[i];
+ token->m_type = TokenTypDef;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/// \todo Fixme Figure out how this should work.
+
+// recreates the list of keywords and its IDs basing on some resources
+// defines of TokenKey.. are in CBotDll.h
+
+void CBotToken::LoadKeyWords()
+{
+ CBotString s;
+ int i, n = 0;
+
+ i = TokenKeyWord; //start with keywords of the language
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+
+ i = TokenKeyDeclare; //keywords of declarations
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+
+
+ i = TokenKeyVal; //keywords of values
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+
+ i = TokenKeyOp; //operators
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+}
+
+bool CBotToken::DefineNum(const char* name, long val)
+{
+ int i;
+ int l = m_ListKeyDefine.GivSize();
+
+ for (i = 0; i < l; i++)
+ {
+ if (m_ListKeyDefine[i] == name) return false;
+ }
+ if ( i == MAXDEFNUM ) return false;
+
+ m_ListKeyDefine.Add( name );
+ m_ListKeyNums[i] = val;
+ return true;
+}
+
+bool IsOfType(CBotToken* &p, int type1, int type2)
+{
+ if (p->GivType() == type1 ||
+ p->GivType() == type2 )
+ {
+ p = p->GivNext();
+ return true;
+ }
+ return false;
+}
+// Same with any number of arguments
+// There must be a zero as the last argument
+bool IsOfTypeList(CBotToken* &p, int type1, ...)
+{
+ int i = type1;
+ int max = 20;
+ int type = p->GivType();
+
+ va_list marker;
+ va_start( marker, type1 ); /* Initialize variable arguments. */
+
+ while (true)
+ {
+ if (type == i)
+ {
+ p = p->GivNext();
+ va_end( marker ); /* Reset variable arguments. */
+ return true;
+ }
+ if (--max == 0 || 0 == (i = va_arg( marker, int)))
+ {
+ va_end( marker ); /* Reset variable arguments. */
+ return false;
+ }
+ }
+}
+
diff --git a/src/CBot/CBotToken.h b/src/CBot/CBotToken.h
index 2d92409..6f11bb2 100644
--- a/src/CBot/CBotToken.h
+++ b/src/CBot/CBotToken.h
@@ -1,37 +1,38 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.////////////////////////////////////////////////////////////////////
-// interpréteur pour le language CBot du jeu COLOBOT
-
-
-// un programme écrit est tout d'abord transformé en une liste de tokens
-// avant d'aborder le compilateur proprement dit
-// par exemple
-// int var = 3 * ( pos.y + x )
-// est décomposé en (chaque ligne est un token)
-// int
-// var
-// =
-// 3
-// *
-// (
-// pos.y
-// +
-// x
-// )
-
-
-extern BOOL IsOfType(CBotToken* &p, int type1, int type2 = -1);
-extern BOOL IsOfTypeList(CBotToken* &p, int type1, ...);
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+
+// interpreter of the lanuage CBot for game COLOBOT
+// writing a program is first transformed into a list of tokens
+// before tackling the compiler itself
+// for example
+// int var = 3 * ( pos.y + x )
+// is decomposed into (each line is a token)
+// int
+// var
+// =
+// 3
+// *
+// (
+// pos.y
+// +
+// x
+// )
+
+#pragma once
+
+extern bool IsOfType(CBotToken* &p, int type1, int type2 = -1);
+extern bool IsOfTypeList(CBotToken* &p, int type1, ...);
diff --git a/src/CBot/CBotTwoOpExpr.cpp b/src/CBot/CBotTwoOpExpr.cpp
index d8f4ee7..62290da 100644
--- a/src/CBot/CBotTwoOpExpr.cpp
+++ b/src/CBot/CBotTwoOpExpr.cpp
@@ -1,566 +1,568 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////
-// expression du genre Opérande1 + Opérande2
-// Opérande1 > Opérande2
-
-#include "CBot.h"
-
-// divers constructeurs
-
-CBotTwoOpExpr::CBotTwoOpExpr()
-{
- m_leftop =
- m_rightop = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotTwoOpExpr"; // debug
-}
-
-CBotTwoOpExpr::~CBotTwoOpExpr()
-{
- delete m_leftop;
- delete m_rightop;
-}
-
-CBotLogicExpr::CBotLogicExpr()
-{
- m_condition =
- m_op1 =
- m_op2 = NULL; // NULL pour pouvoir faire delete sans autre
- name = "CBotLogicExpr"; // debug
-}
-
-CBotLogicExpr::~CBotLogicExpr()
-{
- delete m_condition;
- delete m_op1;
- delete m_op2;
-}
-
-
-// type d'opérandes acceptés par les opérations
-#define ENTIER ((1<<CBotTypByte)|(1<<CBotTypShort)|(1<<CBotTypChar)|(1<<CBotTypInt)|(1<<CBotTypLong))
-#define FLOTANT ((1<<CBotTypFloat)|(1<<CBotTypDouble))
-#define BOOLEEN (1<<CBotTypBoolean)
-#define CHAINE (1<<CBotTypString)
-#define POINTER (1<<CBotTypPointer)
-#define INSTANCE (1<<CBotTypClass)
-
-// liste des opérations (précéance)
-// type acceptable, opérande
-// le zéro termine un niveau de précéance
-
-static int ListOp[] =
-{
- BOOLEEN, ID_LOGIC, 0,
- BOOLEEN, ID_TXT_OR,
- BOOLEEN, ID_LOG_OR, 0,
- BOOLEEN, ID_TXT_AND,
- BOOLEEN, ID_LOG_AND, 0,
- BOOLEEN|ENTIER, ID_OR, 0,
- BOOLEEN|ENTIER, ID_XOR, 0,
- BOOLEEN|ENTIER, ID_AND, 0,
- BOOLEEN|ENTIER|FLOTANT
- |CHAINE
- |POINTER
- |INSTANCE,ID_EQ,
- BOOLEEN|ENTIER|FLOTANT
- |CHAINE
- |POINTER
- |INSTANCE,ID_NE, 0,
- ENTIER|FLOTANT|CHAINE, ID_HI,
- ENTIER|FLOTANT|CHAINE, ID_LO,
- ENTIER|FLOTANT|CHAINE, ID_HS,
- ENTIER|FLOTANT|CHAINE, ID_LS, 0,
- ENTIER, ID_SR,
- ENTIER, ID_SL,
- ENTIER, ID_ASR, 0,
- ENTIER|FLOTANT|CHAINE, ID_ADD,
- ENTIER|FLOTANT, ID_SUB, 0,
- ENTIER|FLOTANT, ID_MUL,
- ENTIER|FLOTANT, ID_DIV,
- ENTIER|FLOTANT, ID_MODULO, 0,
- ENTIER|FLOTANT, ID_POWER, 0,
- 0,
-};
-
-BOOL IsInList( int val, int* list, int& typemasque )
-{
- while (TRUE)
- {
- if ( *list == 0 ) return FALSE;
- typemasque = *list++;
- if ( *list++ == val ) return TRUE;
- }
-}
-
-BOOL TypeOk( int type, int test )
-{
- while (TRUE)
- {
- if ( type == 0 ) return (test & 1);
- type--; test /= 2;
- }
-}
-
-// compile une instruction de type A op B
-
-CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
-{
- int typemasque;
-
- if ( pOperations == NULL ) pOperations = ListOp;
- int* pOp = pOperations;
- while ( *pOp++ != 0 ); // suite de la table
-
- CBotCStack* pStk = pStack->TokenStack(); // un bout de pile svp
-
- // cherche des instructions qui peuvent convenir à gauche de l'opération
- CBotInstr* left = (*pOp == 0) ?
- CBotParExpr::Compile( p, pStk ) : // expression (...) à gauche
- CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B à gauche
-
- if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
-
- // est-ce qu'on a l'opérande prévu ensuite ?
- int TypeOp = p->GivType();
- if ( IsInList( TypeOp, pOperations, typemasque ) )
- {
- CBotTypResult type1, type2;
- type1 = pStk->GivTypResult(); // de quel type le premier opérande ?
-
- if ( TypeOp == ID_LOGIC ) // cas spécial pour condition ? op1 : op2 ;
- {
- if ( !type1.Eq(CBotTypBoolean) )
- {
- pStk->SetError( TX_BADTYPE, p);
- return pStack->Return(NULL, pStk);
- }
- CBotLogicExpr* inst = new CBotLogicExpr();
- inst->m_condition = left;
-
- p = p->GivNext(); // saute le token de l'opération
- inst->m_op1 = CBotExpression::Compile(p, pStk);
- CBotToken* pp = p;
- if ( inst->m_op1 == NULL || !IsOfType( p, ID_DOTS ) )
- {
- pStk->SetError( TX_MISDOTS, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- type1 = pStk->GivTypResult();
-
- inst->m_op2 = CBotExpression::Compile(p, pStk);
- if ( inst->m_op2 == NULL )
- {
- pStk->SetError( TX_ENDOF, p->GivStart() );
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- type2 = pStk->GivTypResult();
- if (!TypeCompatible(type1, type2))
- {
- pStk->SetError( TX_BAD2TYPE, pp );
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- pStk->SetType(type1); // le plus grand des 2 types
-
- return pStack->Return(inst, pStk);
- }
-
- CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // élément pour opération
- inst->SetToken(p); // mémorise l'opération
-
-
- p = p->GivNext(); // saute le token de l'opération
-
- // cherche des instructions qui peuvent convenir à droite
-
- if ( NULL != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
- // expression (...) à droite
- {
- // il y a un second opérande acceptable
-
- type2 = pStk->GivTypResult(); // de quel type le résultat ?
-
- // quel est le type du résultat ?
- int TypeRes = MAX( type1.GivType(3), type2.GivType(3) );
- if ( TypeOp == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- type2 = type1; // tout type convertible en chaîne
- }
- else if ( TypeOp == ID_ADD && type2.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- type1 = type2; // tout type convertible en chaîne
- }
- else if (!TypeOk( TypeRes, typemasque )) type1.SetType(99);// erreur de type
-
- switch ( TypeOp )
- {
- case ID_LOG_OR:
- case ID_LOG_AND:
- case ID_TXT_OR:
- case ID_TXT_AND:
- case ID_EQ:
- case ID_NE:
- case ID_HI:
- case ID_LO:
- case ID_HS:
- case ID_LS:
- TypeRes = CBotTypBoolean;
- }
- if ( TypeCompatible (type1, type2, TypeOp ) ) // les résultats sont-ils compatibles
- {
- // si ok, enregistre l'opérande dans l'objet
- inst->m_leftop = left;
-
- // spécial pour évaluer les opérations de même niveau de gauche à droite
- while ( IsInList( p->GivType(), pOperations, typemasque ) ) // même(s) opération(s) suit ?
- {
- TypeOp = p->GivType();
- CBotTwoOpExpr* i = new CBotTwoOpExpr(); // élément pour opération
- i->SetToken(p); // mémorise l'opération
- i->m_leftop = inst; // opérande de gauche
- type1 = TypeRes;
-
- p = p->GivNext(); // avance à la suite
- i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
- type2 = pStk->GivTypResult();
-
- if ( !TypeCompatible (type1, type2, TypeOp) ) // les résultats sont-ils compatibles
- {
- pStk->SetError(TX_BAD2TYPE, &i->m_token);
- delete i;
- return pStack->Return(NULL, pStk);
- }
-
- if ( TypeRes != CBotTypString )
- TypeRes = MAX(type1.GivType(), type2.GivType());
- inst = i;
- }
-
- CBotTypResult t(type1);
- t.SetType(TypeRes);
- // met une variable sur la pile pour avoir le type de résultat
- pStk->SetVar(CBotVar::Create((CBotToken*)NULL, t));
-
- // et rend l'object à qui l'a demandé
- return pStack->Return(inst, pStk);
- }
- pStk->SetError(TX_BAD2TYPE, &inst->m_token);
- }
-
- // en cas d'erreur, libère les éléments
- delete left;
- delete inst;
- // et transmet l'erreur qui se trouve sur la pile
- return pStack->Return(NULL, pStk);
- }
-
- // si on n'a pas affaire à une opération + ou -
- // rend à qui l'a demandé, l'opérande (de gauche) trouvé
- // à la place de l'objet "addition"
- return pStack->Return(left, pStk);
-}
-
-
-BOOL IsNan(CBotVar* left, CBotVar* right, int* err = NULL)
-{
- if ( left ->GivInit() > IS_DEF || right->GivInit() > IS_DEF )
- {
- if ( err != NULL ) *err = TX_OPNAN ;
- return TRUE;
- }
- return FALSE;
-}
-
-
-// fait l'opération sur 2 opérandes
-
-BOOL CBotTwoOpExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pStk1 == EOX ) return TRUE;
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GivState() == 0 ) // 1er état, évalue l'opérande de gauche
- {
- if (!m_leftop->Execute(pStk1) ) return FALSE; // interrompu ici ?
-
- // pour les OU et ET logique, n'évalue pas la seconde expression si pas nécessaire
- if ( (GivTokenType() == ID_LOG_AND || GivTokenType() == ID_TXT_AND ) && pStk1->GivVal() == FALSE )
- {
- CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
- res->SetValInt(FALSE);
- pStk1->SetVar(res);
- return pStack->Return(pStk1); // transmet le résultat
- }
- if ( (GivTokenType() == ID_LOG_OR||GivTokenType() == ID_TXT_OR) && pStk1->GivVal() == TRUE )
- {
- CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
- res->SetValInt(TRUE);
- pStk1->SetVar(res);
- return pStack->Return(pStk1); // transmet le résultat
- }
-
- // passe à l'étape suivante
- pStk1->SetState(1); // prêt pour la suite
- }
-
-
- // demande un peu plus de stack pour ne pas toucher le résultat de gauche
- // qui se trouve sur la pile, justement.
-
- CBotStack* pStk2 = pStk1->AddStack(); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-
- // 2e état, évalue l'opérande de droite
- if ( pStk2->GivState() == 0 )
- {
- if ( !m_rightop->Execute(pStk2) ) return FALSE; // interrompu ici ?
- pStk2->IncState();
- }
-
- CBotTypResult type1 = pStk1->GivTypResult(); // de quels types les résultats ?
- CBotTypResult type2 = pStk2->GivTypResult();
-
- CBotStack* pStk3 = pStk2->AddStack(this); // ajoute un élément à la pile
- if ( pStk3->IfStep() ) return FALSE; // montre l'opération si step by step
-
- // crée une variable temporaire pour y mettre le résultat
- // quel est le type du résultat ?
- int TypeRes = MAX(type1.GivType(), type2.GivType());
-
- if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- }
-
- switch ( GivTokenType() )
- {
- case ID_LOG_OR:
- case ID_LOG_AND:
- case ID_TXT_OR:
- case ID_TXT_AND:
- case ID_EQ:
- case ID_NE:
- case ID_HI:
- case ID_LO:
- case ID_HS:
- case ID_LS:
- TypeRes = CBotTypBoolean;
- break;
- case ID_DIV:
- TypeRes = MAX(TypeRes, CBotTypFloat);
- }
-
- // crée une variable pour le résultat
- CBotVar* result = CBotVar::Create( (CBotToken*)NULL, TypeRes);
-
- // crée une variable pour effectuer le calcul dans le type adapté
- TypeRes = MAX(type1.GivType(), type2.GivType());
-
- if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
- {
- TypeRes = CBotTypString;
- }
-
- CBotVar* temp;
-
- if ( TypeRes == CBotTypPointer ) TypeRes = CBotTypNullPointer;
- if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( (CBotToken*)NULL, CBotTypResult(CBotTypIntrinsic, type1.GivClass() ) );
- else temp = CBotVar::Create( (CBotToken*)NULL, TypeRes );
-
- int err = 0;
- // fait l'opération selon la demande
- CBotVar* left = pStk1->GivVar();
- CBotVar* right = pStk2->GivVar();
-
- switch (GivTokenType())
- {
- case ID_ADD:
- if ( !IsNan(left, right, &err) ) result->Add(left , right); // additionne
- break;
- case ID_SUB:
- if ( !IsNan(left, right, &err) ) result->Sub(left , right); // soustrait
- break;
- case ID_MUL:
- if ( !IsNan(left, right, &err) ) result->Mul(left , right); // multiplie
- break;
- case ID_POWER:
- if ( !IsNan(left, right, &err) ) result->Power(left , right); // puissance
- break;
- case ID_DIV:
- if ( !IsNan(left, right, &err) ) err = result->Div(left , right);// divise
- break;
- case ID_MODULO:
- if ( !IsNan(left, right, &err) ) err = result->Modulo(left , right);// reste de division
- break;
- case ID_LO:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Lo(left , right)); // inférieur
- break;
- case ID_HI:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Hi(left , right)); // supérieur
- break;
- case ID_LS:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Ls(left , right)); // inférieur ou égal
- break;
- case ID_HS:
- if ( !IsNan(left, right, &err) )
- result->SetValInt(temp->Hs(left , right)); // supérieur ou égal
- break;
- case ID_EQ:
- if ( IsNan(left, right) )
- result->SetValInt(left->GivInit() == right->GivInit()) ;
- else
- result->SetValInt(temp->Eq(left , right)); // égal
- break;
- case ID_NE:
- if ( IsNan(left, right) )
- result->SetValInt(left ->GivInit() != right->GivInit()) ;
- else
- result->SetValInt(temp->Ne(left , right)); // différent
- break;
- case ID_TXT_AND:
- case ID_LOG_AND:
- case ID_AND:
- if ( !IsNan(left, right, &err) ) result->And(left , right); // ET
- break;
- case ID_TXT_OR:
- case ID_LOG_OR:
- case ID_OR:
- if ( !IsNan(left, right, &err) ) result->Or(left , right); // OU
- break;
- case ID_XOR:
- if ( !IsNan(left, right, &err) ) result->XOr(left , right); // OU exclusif
- break;
- case ID_ASR:
- if ( !IsNan(left, right, &err) ) result->ASR(left , right);
- break;
- case ID_SR:
- if ( !IsNan(left, right, &err) ) result->SR(left , right);
- break;
- case ID_SL:
- if ( !IsNan(left, right, &err) ) result->SL(left , right);
- break;
- default:
- ASM_TRAP();
- }
- delete temp;
-
- pStk2->SetVar(result); // met le résultat sur la pile
- if ( err ) pStk2->SetError(err, &m_token); // et l'erreur éventuelle (division par zéro)
-
-// pStk1->Return(pStk2); // libère la pile
- return pStack->Return(pStk2); // transmet le résultat
-}
-
-void CBotTwoOpExpr::RestoreState(CBotStack* &pStack, BOOL bMain)
-{
- if ( !bMain ) return;
- CBotStack* pStk1 = pStack->RestoreStack(this); // ajoute un élément à la pile
- if ( pStk1 == NULL ) return;
-
- // selon la reprise, on peut être dans l'un des 2 états
-
- if ( pStk1->GivState() == 0 ) // 1er état, évalue l'opérande de gauche
- {
- m_leftop->RestoreState(pStk1, bMain); // interrompu ici !
- return;
- }
-
- CBotStack* pStk2 = pStk1->RestoreStack(); // ajoute un élément à la pile
- if ( pStk2 == NULL ) return;
-
- // 2e état, évalue l'opérande de droite
- if ( pStk2->GivState() == 0 )
- {
- m_rightop->RestoreState(pStk2, bMain); // interrompu ici !
- return;
- }
-}
-
-
-BOOL CBotLogicExpr::Execute(CBotStack* &pStack)
-{
- CBotStack* pStk1 = pStack->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pStk1 == EOX ) return TRUE;
-
- if ( pStk1->GivState() == 0 )
- {
- if ( !m_condition->Execute(pStk1) ) return FALSE;
- if (!pStk1->SetState(1)) return FALSE;
- }
-
- if ( pStk1->GivVal() == TRUE )
- {
- if ( !m_op1->Execute(pStk1) ) return FALSE;
- }
- else
- {
- if ( !m_op2->Execute(pStk1) ) return FALSE;
- }
-
- return pStack->Return(pStk1); // transmet le résultat
-}
-
-void CBotLogicExpr::RestoreState(CBotStack* &pStack, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pStk1 = pStack->RestoreStack(this); // ajoute un élément à la pile
- if ( pStk1 == NULL ) return;
-
- if ( pStk1->GivState() == 0 )
- {
- m_condition->RestoreState(pStk1, bMain);
- return;
- }
-
- if ( pStk1->GivVal() == TRUE )
- {
- m_op1->RestoreState(pStk1, bMain);
- }
- else
- {
- m_op2->RestoreState(pStk1, bMain);
- }
-}
-
-#if 0
-void t()
-{
- int x,y;
- 1>0 ? x = 0 : y = 0;
-}
-#endif
-
-#if 01
-void t(BOOL t)
-{
- int x;
- x = 1 + t ? 1 : 3 + 4 * 2 ;
- t ? 0 : "test";
-}
-#endif
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+///////////////////////////////////////////////////
+// expression of type Opérande1 + Opérande2
+// Opérande1 > Opérande2
+
+#include "CBot.h"
+
+// various constructors
+
+CBotTwoOpExpr::CBotTwoOpExpr()
+{
+ m_leftop =
+ m_rightop = NULL; // NULL to be able to delete without other
+ name = "CBotTwoOpExpr"; // debug
+}
+
+CBotTwoOpExpr::~CBotTwoOpExpr()
+{
+ delete m_leftop;
+ delete m_rightop;
+}
+
+CBotLogicExpr::CBotLogicExpr()
+{
+ m_condition =
+ m_op1 =
+ m_op2 = NULL; // NULL to be able to delete without other
+ name = "CBotLogicExpr"; // debug
+}
+
+CBotLogicExpr::~CBotLogicExpr()
+{
+ delete m_condition;
+ delete m_op1;
+ delete m_op2;
+}
+
+
+// type of operands accepted by operations
+#define ENTIER ((1<<CBotTypByte)|(1<<CBotTypShort)|(1<<CBotTypChar)|(1<<CBotTypInt)|(1<<CBotTypLong))
+#define FLOTANT ((1<<CBotTypFloat)|(1<<CBotTypDouble))
+#define BOOLEEN (1<<CBotTypBoolean)
+#define CHAINE (1<<CBotTypString)
+#define POINTER (1<<CBotTypPointer)
+#define INSTANCE (1<<CBotTypClass)
+
+// list of operations (précéance)
+// acceptable type, operand
+// zero ends level \TODO précéance
+
+static int ListOp[] =
+{
+ BOOLEEN, ID_LOGIC, 0,
+ BOOLEEN, ID_TXT_OR,
+ BOOLEEN, ID_LOG_OR, 0,
+ BOOLEEN, ID_TXT_AND,
+ BOOLEEN, ID_LOG_AND, 0,
+ BOOLEEN|ENTIER, ID_OR, 0,
+ BOOLEEN|ENTIER, ID_XOR, 0,
+ BOOLEEN|ENTIER, ID_AND, 0,
+ BOOLEEN|ENTIER|FLOTANT
+ |CHAINE
+ |POINTER
+ |INSTANCE,ID_EQ,
+ BOOLEEN|ENTIER|FLOTANT
+ |CHAINE
+ |POINTER
+ |INSTANCE,ID_NE, 0,
+ ENTIER|FLOTANT|CHAINE, ID_HI,
+ ENTIER|FLOTANT|CHAINE, ID_LO,
+ ENTIER|FLOTANT|CHAINE, ID_HS,
+ ENTIER|FLOTANT|CHAINE, ID_LS, 0,
+ ENTIER, ID_SR,
+ ENTIER, ID_SL,
+ ENTIER, ID_ASR, 0,
+ ENTIER|FLOTANT|CHAINE, ID_ADD,
+ ENTIER|FLOTANT, ID_SUB, 0,
+ ENTIER|FLOTANT, ID_MUL,
+ ENTIER|FLOTANT, ID_DIV,
+ ENTIER|FLOTANT, ID_MODULO, 0,
+ ENTIER|FLOTANT, ID_POWER, 0,
+ 0,
+};
+
+bool IsInList( int val, int* list, int& typemasque )
+{
+ while (true)
+ {
+ if ( *list == 0 ) return false;
+ typemasque = *list++;
+ if ( *list++ == val ) return true;
+ }
+}
+
+bool TypeOk( int type, int test )
+{
+ while (true)
+ {
+ if ( type == 0 ) return (test & 1);
+ type--; test /= 2;
+ }
+}
+
+// compiles a instruction of type A op B
+
+CBotInstr* CBotTwoOpExpr::Compile(CBotToken* &p, CBotCStack* pStack, int* pOperations)
+{
+ int typemasque;
+
+ if ( pOperations == NULL ) pOperations = ListOp;
+ int* pOp = pOperations;
+ while ( *pOp++ != 0 ); // follows the table
+
+ CBotCStack* pStk = pStack->TokenStack(); // one end of stack please
+
+ // search the intructions that may be suitable to the left of the operation
+ CBotInstr* left = (*pOp == 0) ?
+ CBotParExpr::Compile( p, pStk ) : // expression (...) left
+ CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A * B left
+
+ if (left == NULL) return pStack->Return(NULL, pStk); // if error, transmit
+
+ // did we expected the operand?
+ int TypeOp = p->GivType();
+ if ( IsInList( TypeOp, pOperations, typemasque ) )
+ {
+ CBotTypResult type1, type2;
+ type1 = pStk->GivTypResult(); // what kind of the first operand?
+
+ if ( TypeOp == ID_LOGIC ) // special case provided for: ? op1: op2;
+ {
+ if ( !type1.Eq(CBotTypBoolean) )
+ {
+ pStk->SetError( TX_BADTYPE, p);
+ return pStack->Return(NULL, pStk);
+ }
+ CBotLogicExpr* inst = new CBotLogicExpr();
+ inst->m_condition = left;
+
+ p = p->GivNext(); // skip the token of the operation
+ inst->m_op1 = CBotExpression::Compile(p, pStk);
+ CBotToken* pp = p;
+ if ( inst->m_op1 == NULL || !IsOfType( p, ID_DOTS ) )
+ {
+ pStk->SetError( TX_MISDOTS, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ type1 = pStk->GivTypResult();
+
+ inst->m_op2 = CBotExpression::Compile(p, pStk);
+ if ( inst->m_op2 == NULL )
+ {
+ pStk->SetError( TX_ENDOF, p->GivStart() );
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ type2 = pStk->GivTypResult();
+ if (!TypeCompatible(type1, type2))
+ {
+ pStk->SetError( TX_BAD2TYPE, pp );
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ pStk->SetType(type1); // the greatest of 2 types
+
+ return pStack->Return(inst, pStk);
+ }
+
+ CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // element for operation
+ inst->SetToken(p); // stores the operation
+
+
+ p = p->GivNext(); // skip the token of the operation
+
+ // looking statements that may be suitable for right
+
+ if ( NULL != (inst->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp )) )
+ // expression (...) right
+ {
+ // there is an second operand acceptable
+
+ type2 = pStk->GivTypResult(); // what kind of results?
+
+ // what kind of result?
+ int TypeRes = MAX( type1.GivType(3), type2.GivType(3) );
+ if ( TypeOp == ID_ADD && type1.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ type2 = type1; // any type convertible chain
+ }
+ else if ( TypeOp == ID_ADD && type2.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ type1 = type2; // any type convertible chain
+ }
+ else if (!TypeOk( TypeRes, typemasque )) type1.SetType(99);// error of type
+
+ switch ( TypeOp )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_AND:
+ case ID_TXT_OR:
+ case ID_TXT_AND:
+ case ID_EQ:
+ case ID_NE:
+ case ID_HI:
+ case ID_LO:
+ case ID_HS:
+ case ID_LS:
+ TypeRes = CBotTypBoolean;
+ }
+ if ( TypeCompatible (type1, type2, TypeOp ) ) // the results are compatible
+ {
+ // ok so, saves the operand in the object
+ inst->m_leftop = left;
+
+ // special for evaluation of the operations of the same level from left to right
+ while ( IsInList( p->GivType(), pOperations, typemasque ) ) // same operation(s) follows?
+ {
+ TypeOp = p->GivType();
+ CBotTwoOpExpr* i = new CBotTwoOpExpr(); // element for operation
+ i->SetToken(p); // stores the operation
+ i->m_leftop = inst; // left operand
+ type1 = TypeRes;
+
+ p = p->GivNext(); // advance after
+ i->m_rightop = CBotTwoOpExpr::Compile( p, pStk, pOp );
+ type2 = pStk->GivTypResult();
+
+ if ( !TypeCompatible (type1, type2, TypeOp) ) // the results are compatible
+ {
+ pStk->SetError(TX_BAD2TYPE, &i->m_token);
+ delete i;
+ return pStack->Return(NULL, pStk);
+ }
+
+ if ( TypeRes != CBotTypString )
+ TypeRes = MAX(type1.GivType(), type2.GivType());
+ inst = i;
+ }
+
+ CBotTypResult t(type1);
+ t.SetType(TypeRes);
+ // is a variable on the stack for the type of result
+ pStk->SetVar(CBotVar::Create((CBotToken*)NULL, t));
+
+ // and returns the requested object
+ return pStack->Return(inst, pStk);
+ }
+ pStk->SetError(TX_BAD2TYPE, &inst->m_token);
+ }
+
+ // in case of error, releases the elements
+ delete left;
+ delete inst;
+ // and transmits the error to the stack
+ return pStack->Return(NULL, pStk);
+ }
+
+ // if we are not dealing with an operation + or -
+ // goes to that requested, the operand (left) found
+ // instead of the object "addition"
+ return pStack->Return(left, pStk);
+}
+
+
+bool IsNan(CBotVar* left, CBotVar* right, int* err = NULL)
+{
+ if ( left ->GivInit() > IS_DEF || right->GivInit() > IS_DEF )
+ {
+ if ( err != NULL ) *err = TX_OPNAN ;
+ return true;
+ }
+ return false;
+}
+
+
+// performes the operation on two operands
+
+bool CBotTwoOpExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack
+ // or return in case of recovery
+// if ( pStk1 == EOX ) return true;
+
+ // according to recovery, it may be in one of two states
+
+ if ( pStk1->GivState() == 0 ) // first state, evaluates the left operand
+ {
+ if (!m_leftop->Execute(pStk1) ) return false; // interrupted here?
+
+ // for OR and AND logic does not evaluate the second expression if not necessary
+ if ( (GivTokenType() == ID_LOG_AND || GivTokenType() == ID_TXT_AND ) && pStk1->GivVal() == false )
+ {
+ CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
+ res->SetValInt(false);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmits the result
+ }
+ if ( (GivTokenType() == ID_LOG_OR||GivTokenType() == ID_TXT_OR) && pStk1->GivVal() == true )
+ {
+ CBotVar* res = CBotVar::Create( (CBotToken*)NULL, CBotTypBoolean);
+ res->SetValInt(true);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmits the result
+ }
+
+ // passes to the next step
+ pStk1->SetState(1); // ready for further
+ }
+
+
+ // requires a little more stack to avoid touching the result
+ // of which is left on the stack, precisely
+
+ CBotStack* pStk2 = pStk1->AddStack(); // adds an item to the stack
+ // or return in case of recovery
+
+ // 2e état, évalue l'opérande de droite
+ if ( pStk2->GivState() == 0 )
+ {
+ if ( !m_rightop->Execute(pStk2) ) return false; // interrupted here?
+ pStk2->IncState();
+ }
+
+ CBotTypResult type1 = pStk1->GivTypResult(); // what kind of results?
+ CBotTypResult type2 = pStk2->GivTypResult();
+
+ CBotStack* pStk3 = pStk2->AddStack(this); // adds an item to the stack
+ if ( pStk3->IfStep() ) return false; // shows the operation if step by step
+
+ // creates a temporary variable to put the result
+ // what kind of result?
+ int TypeRes = MAX(type1.GivType(), type2.GivType());
+
+ if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ }
+
+ switch ( GivTokenType() )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_AND:
+ case ID_TXT_OR:
+ case ID_TXT_AND:
+ case ID_EQ:
+ case ID_NE:
+ case ID_HI:
+ case ID_LO:
+ case ID_HS:
+ case ID_LS:
+ TypeRes = CBotTypBoolean;
+ break;
+ case ID_DIV:
+ TypeRes = MAX(TypeRes, CBotTypFloat);
+ }
+
+ // creates a variable for the result
+ CBotVar* result = CBotVar::Create( (CBotToken*)NULL, TypeRes);
+
+ // creates a variable to perform the calculation in the appropriate type
+ TypeRes = MAX(type1.GivType(), type2.GivType());
+
+ if ( GivTokenType() == ID_ADD && type1.Eq(CBotTypString) )
+ {
+ TypeRes = CBotTypString;
+ }
+
+ CBotVar* temp;
+
+ if ( TypeRes == CBotTypPointer ) TypeRes = CBotTypNullPointer;
+ if ( TypeRes == CBotTypClass ) temp = CBotVar::Create( (CBotToken*)NULL, CBotTypResult(CBotTypIntrinsic, type1.GivClass() ) );
+ else temp = CBotVar::Create( (CBotToken*)NULL, TypeRes );
+
+ int err = 0;
+ // is a operation according to request
+ CBotVar* left = pStk1->GivVar();
+ CBotVar* right = pStk2->GivVar();
+
+ switch (GivTokenType())
+ {
+ case ID_ADD:
+ if ( !IsNan(left, right, &err) ) result->Add(left , right); // addition
+ break;
+ case ID_SUB:
+ if ( !IsNan(left, right, &err) ) result->Sub(left , right); // substraction
+ break;
+ case ID_MUL:
+ if ( !IsNan(left, right, &err) ) result->Mul(left , right); // multiplies
+ break;
+ case ID_POWER:
+ if ( !IsNan(left, right, &err) ) result->Power(left , right); // power
+ break;
+ case ID_DIV:
+ if ( !IsNan(left, right, &err) ) err = result->Div(left , right);// division
+ break;
+ case ID_MODULO:
+ if ( !IsNan(left, right, &err) ) err = result->Modulo(left , right);// remainder of division
+ break;
+ case ID_LO:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Lo(left , right)); // lower
+ break;
+ case ID_HI:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Hi(left , right)); // top
+ break;
+ case ID_LS:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Ls(left , right)); // less than or equal
+ break;
+ case ID_HS:
+ if ( !IsNan(left, right, &err) )
+ result->SetValInt(temp->Hs(left , right)); // greater than or equal
+ break;
+ case ID_EQ:
+ if ( IsNan(left, right) )
+ result->SetValInt(left->GivInit() == right->GivInit()) ;
+ else
+ result->SetValInt(temp->Eq(left , right)); // equal
+ break;
+ case ID_NE:
+ if ( IsNan(left, right) )
+ result->SetValInt(left ->GivInit() != right->GivInit()) ;
+ else
+ result->SetValInt(temp->Ne(left , right)); // different
+ break;
+ case ID_TXT_AND:
+ case ID_LOG_AND:
+ case ID_AND:
+ if ( !IsNan(left, right, &err) ) result->And(left , right); // AND
+ break;
+ case ID_TXT_OR:
+ case ID_LOG_OR:
+ case ID_OR:
+ if ( !IsNan(left, right, &err) ) result->Or(left , right); // OR
+ break;
+ case ID_XOR:
+ if ( !IsNan(left, right, &err) ) result->XOr(left , right); // exclusive OR
+ break;
+ case ID_ASR:
+ if ( !IsNan(left, right, &err) ) result->ASR(left , right);
+ break;
+ case ID_SR:
+ if ( !IsNan(left, right, &err) ) result->SR(left , right);
+ break;
+ case ID_SL:
+ if ( !IsNan(left, right, &err) ) result->SL(left , right);
+ break;
+ default:
+ ASM_TRAP();
+ }
+ delete temp;
+
+ pStk2->SetVar(result); // puts the result on the stack
+ if ( err ) pStk2->SetError(err, &m_token); // and the possible error (division by zero)
+
+// pStk1->Return(pStk2); // releases the stack
+ return pStack->Return(pStk2); // transmits the result
+}
+
+void CBotTwoOpExpr::RestoreState(CBotStack* &pStack, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pStk1 = pStack->RestoreStack(this); // adds an item to the stack
+ if ( pStk1 == NULL ) return;
+
+ // according to recovery, it may be in one of two states
+
+ if ( pStk1->GivState() == 0 ) // first state, evaluates the left operand
+ {
+ m_leftop->RestoreState(pStk1, bMain); // interrupted here!
+ return;
+ }
+
+ CBotStack* pStk2 = pStk1->RestoreStack(); // adds an item to the stack
+ if ( pStk2 == NULL ) return;
+
+ // second state, evaluates the right operand
+ if ( pStk2->GivState() == 0 )
+ {
+ m_rightop->RestoreState(pStk2, bMain); // interrupted here!
+ return;
+ }
+}
+
+
+bool CBotLogicExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(this); // adds an item to the stack
+ // or return in case of recovery
+// if ( pStk1 == EOX ) return true;
+
+ if ( pStk1->GivState() == 0 )
+ {
+ if ( !m_condition->Execute(pStk1) ) return false;
+ if (!pStk1->SetState(1)) return false;
+ }
+
+ if ( pStk1->GivVal() == true )
+ {
+ if ( !m_op1->Execute(pStk1) ) return false;
+ }
+ else
+ {
+ if ( !m_op2->Execute(pStk1) ) return false;
+ }
+
+ return pStack->Return(pStk1); // transmits the result
+}
+
+void CBotLogicExpr::RestoreState(CBotStack* &pStack, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pStk1 = pStack->RestoreStack(this); // adds an item to the stack
+ if ( pStk1 == NULL ) return;
+
+ if ( pStk1->GivState() == 0 )
+ {
+ m_condition->RestoreState(pStk1, bMain);
+ return;
+ }
+
+ if ( pStk1->GivVal() == true )
+ {
+ m_op1->RestoreState(pStk1, bMain);
+ }
+ else
+ {
+ m_op2->RestoreState(pStk1, bMain);
+ }
+}
+
+#if 0
+void t()
+{
+ int x,y;
+ 1>0 ? x = 0 : y = 0;
+}
+#endif
+
+#if 01
+void t(bool t)
+{
+ int x;
+ x = 1 + t ? 1 : 3 + 4 * 2 ;
+ t ? 0 : "test";
+}
+#endif
diff --git a/src/CBot/CBotVar.cpp b/src/CBot/CBotVar.cpp
index 37c8fb4..0d9bfb3 100644
--- a/src/CBot/CBotVar.cpp
+++ b/src/CBot/CBotVar.cpp
@@ -1,2245 +1,2248 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.////////////////////////////////////////////////////////////////////
-// Définition pour la classe CBotVar
-// gestion des variables du langage CBot
-
-// on ne crée jamais d'instance de la class mère CBotVar
-
-
-#include "CBot.h"
-#include <math.h>
-#include <stdio.h>
-
-long CBotVar::m_identcpt = 0;
-
-CBotVar::CBotVar( )
-{
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = -1;
- m_binit = FALSE;
- m_ident = 0;
- m_bStatic = FALSE;
- m_mPrivate = 0;
-}
-
-CBotVarInt::CBotVarInt( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypInt;
- m_binit = FALSE;
- m_bStatic = FALSE;
- m_mPrivate = 0;
-
- m_val = 0;
-}
-
-CBotVarFloat::CBotVarFloat( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypFloat;
- m_binit = FALSE;
- m_bStatic = FALSE;
- m_mPrivate = 0;
-
- m_val = 0;
-}
-
-CBotVarString::CBotVarString( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypString;
- m_binit = FALSE;
- m_bStatic = FALSE;
- m_mPrivate = 0;
-
- m_val.Empty();
-}
-
-CBotVarBoolean::CBotVarBoolean( const CBotToken* name )
-{
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_type = CBotTypBoolean;
- m_binit = FALSE;
- m_bStatic = FALSE;
- m_mPrivate = 0;
-
- m_val = 0;
-}
-
-CBotVarClass* CBotVarClass::m_ExClass = NULL;
-
-CBotVarClass::CBotVarClass( const CBotToken* name, const CBotTypResult& type)
-{
-/*
-// int nIdent = 0;
- InitCBotVarClass( name, type ) //, nIdent );
-}
-
-CBotVarClass::CBotVarClass( const CBotToken* name, CBotTypResult& type) //, int &nIdent )
-{
- InitCBotVarClass( name, type ); //, nIdent );
-}
-
-void CBotVarClass::InitCBotVarClass( const CBotToken* name, CBotTypResult& type ) //, int &nIdent )
-{*/
- if ( !type.Eq(CBotTypClass) &&
- !type.Eq(CBotTypIntrinsic) && // par comodité accepte ces types
- !type.Eq(CBotTypPointer) &&
- !type.Eq(CBotTypArrayPointer) &&
- !type.Eq(CBotTypArrayBody)) ASM_TRAP();
-
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = OBJECTCREATED;//NULL;
- m_InitExpr = NULL;
- m_LimExpr = NULL;
- m_pVar = NULL;
- m_type = type;
- if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody );
- else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass );
- // type officel pour cet object
-
- m_pClass = NULL;
- m_pParent = NULL;
- m_binit = FALSE;
- m_bStatic = FALSE;
- m_mPrivate = 0;
- m_bConstructor = FALSE;
- m_CptUse = 0;
- m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum();
-
- // se place tout seul dans la liste
- if (m_ExClass) m_ExClass->m_ExPrev = this;
- m_ExNext = m_ExClass;
- m_ExPrev = NULL;
- m_ExClass = this;
-
- CBotClass* pClass = type.GivClass();
- CBotClass* pClass2 = pClass->GivParent();
- if ( pClass2 != NULL )
- {
- // crée également une instance dans la classe père
- m_pParent = new CBotVarClass(name, CBotTypResult(type.GivType(),pClass2) ); //, nIdent);
- }
-
- SetClass( pClass ); //, nIdent );
-
-}
-
-CBotVarClass::~CBotVarClass( )
-{
- if ( m_CptUse != 0 )
- ASM_TRAP();
-
- if ( m_pParent ) delete m_pParent;
- m_pParent = NULL;
-
- // libère l'objet indirect s'il y a lieu
-// if ( m_Indirect != NULL )
-// m_Indirect->DecrementUse();
-
- // retire la classe de la liste
- if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
- else m_ExClass = m_ExNext;
-
- if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
- m_ExPrev = NULL;
- m_ExNext = NULL;
-
- delete m_pVar;
-}
-
-void CBotVarClass::ConstructorSet()
-{
- m_bConstructor = TRUE;
-}
-
-
-CBotVar::~CBotVar( )
-{
- delete m_token;
- delete m_next;
-}
-
-void CBotVar::debug()
-{
- const char* p = (LPCTSTR) m_token->GivString();
- CBotString s = (LPCTSTR) GivValString();
- const char* v = (LPCTSTR) s;
-
- if ( m_type.Eq(CBotTypClass) )
- {
- CBotVar* pv = ((CBotVarClass*)this)->m_pVar;
- while (pv != NULL)
- {
- pv->debug();
- pv = pv->GivNext();
- }
- }
-}
-
-void CBotVar::ConstructorSet()
-{
- // nop
-}
-
-void CBotVar::SetUserPtr(void* pUser)
-{
- m_pUserPtr = pUser;
- if (m_type.Eq(CBotTypPointer) &&
- ((CBotVarPointer*)this)->m_pVarClass != NULL )
- ((CBotVarPointer*)this)->m_pVarClass->SetUserPtr(pUser);
-}
-
-void CBotVar::SetIdent(long n)
-{
- if (m_type.Eq(CBotTypPointer) &&
- ((CBotVarPointer*)this)->m_pVarClass != NULL )
- ((CBotVarPointer*)this)->m_pVarClass->SetIdent(n);
-}
-
-void CBotVar::SetUniqNum(long n)
-{
- m_ident = n;
-
- if ( n == 0 ) ASM_TRAP();
-}
-
-long CBotVar::NextUniqNum()
-{
- if (++m_identcpt < 10000) m_identcpt = 10000;
- return m_identcpt;
-}
-
-long CBotVar::GivUniqNum()
-{
- return m_ident;
-}
-
-
-void* CBotVar::GivUserPtr()
-{
- return m_pUserPtr;
-}
-
-BOOL CBotVar::Save1State(FILE* pf)
-{
- // cette routine "virtual" ne doit jamais être appellée,
- // il doit y avoir une routine pour chaque classe fille (CBotVarInt, CBotVarFloat, etc)
- // ( voir le type dans m_type )
- ASM_TRAP();
- return FALSE;
-}
-
-void CBotVar::Maj(void* pUser, BOOL bContinu)
-{
-/* if (!bContinu && m_pMyThis != NULL)
- m_pMyThis->Maj(pUser, TRUE);*/
-}
-
-
-// crée une variable selon son type
-
-CBotVar* CBotVar::Create(const CBotToken* name, int type )
-{
- CBotTypResult t(type);
- return Create(name, t);
-}
-
-CBotVar* CBotVar::Create(const CBotToken* name, CBotTypResult type)
-{
- switch (type.GivType())
- {
- case CBotTypShort:
- case CBotTypInt:
- return new CBotVarInt(name);
- case CBotTypFloat:
- return new CBotVarFloat(name);
- case CBotTypBoolean:
- return new CBotVarBoolean(name);
- case CBotTypString:
- return new CBotVarString(name);
- case CBotTypPointer:
- case CBotTypNullPointer:
- return new CBotVarPointer(name, type);
- case CBotTypIntrinsic:
- return new CBotVarClass(name, type);
-
- case CBotTypClass:
- // crée une nouvelle instance d'une classe
- // et retourne le POINTER sur cette instance
- {
- CBotVarClass* instance = new CBotVarClass(name, type);
- CBotVarPointer* pointer = new CBotVarPointer(name, type);
- pointer->SetPointer( instance );
- return pointer;
- }
-
- case CBotTypArrayPointer:
- return new CBotVarArray(name, type);
-
- case CBotTypArrayBody:
- {
- CBotVarClass* instance = new CBotVarClass(name, type);
- CBotVarArray* array = new CBotVarArray(name, type);
- array->SetPointer( instance );
-
- CBotVar* pv = array;
- while (type.Eq(CBotTypArrayBody))
- {
- type = type.GivTypElem();
- pv = ((CBotVarArray*)pv)->GivItem(0, TRUE); // crée au moins l'élément [0]
- }
-
- return array;
- }
- }
-
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::Create( CBotVar* pVar )
-{
- CBotVar* p = Create(pVar->m_token->GivString(), pVar->GivTypResult(2));
- return p;
-}
-
-
-CBotVar* CBotVar::Create( const char* n, CBotTypResult type)
-{
- CBotToken name(n);
-
- switch (type.GivType())
- {
- case CBotTypShort:
- case CBotTypInt:
- return new CBotVarInt(&name);
- case CBotTypFloat:
- return new CBotVarFloat(&name);
- case CBotTypBoolean:
- return new CBotVarBoolean(&name);
- case CBotTypString:
- return new CBotVarString(&name);
- case CBotTypPointer:
- case CBotTypNullPointer:
- {
- CBotVarPointer* p = new CBotVarPointer(&name, type);
-// p->SetClass(type.GivClass());
- return p;
- }
- case CBotTypIntrinsic:
- {
- CBotVarClass* p = new CBotVarClass(&name, type);
-// p->SetClass(type.GivClass());
- return p;
- }
-
- case CBotTypClass:
- // crée une nouvelle instance d'une classe
- // et retourne le POINTER sur cette instance
- {
- CBotVarClass* instance = new CBotVarClass(&name, type);
- CBotVarPointer* pointer = new CBotVarPointer(&name, type);
- pointer->SetPointer( instance );
-// pointer->SetClass( type.GivClass() );
- return pointer;
- }
-
- case CBotTypArrayPointer:
- return new CBotVarArray(&name, type);
-
- case CBotTypArrayBody:
- {
- CBotVarClass* instance = new CBotVarClass(&name, type);
- CBotVarArray* array = new CBotVarArray(&name, type);
- array->SetPointer( instance );
-
- CBotVar* pv = array;
- while (type.Eq(CBotTypArrayBody))
- {
- type = type.GivTypElem();
- pv = ((CBotVarArray*)pv)->GivItem(0, TRUE); // crée au moins l'élément [0]
- }
-
- return array;
- }
- }
-
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::Create( const char* name, int type, CBotClass* pClass)
-{
- CBotToken token( name, "" );
- CBotVar* pVar = Create( &token, type );
-
- if ( type == CBotTypPointer && pClass == NULL ) // pointeur "null" ?
- return pVar;
-
- if ( type == CBotTypClass || type == CBotTypPointer ||
- type == CBotTypIntrinsic )
- {
- if (pClass == NULL)
- {
- delete pVar;
- return NULL;
- }
- pVar->SetClass( pClass );
- }
- return pVar;
-}
-
-CBotVar* CBotVar::Create( const char* name, CBotClass* pClass)
-{
- CBotToken token( name, "" );
- CBotVar* pVar = Create( &token, CBotTypResult( CBotTypClass, pClass ) );
-// pVar->SetClass( pClass );
- return pVar;
-}
-
-CBotTypResult CBotVar::GivTypResult(int mode)
-{
- CBotTypResult r = m_type;
-
- if ( mode == 1 && m_type.Eq(CBotTypClass) )
- r.SetType(CBotTypPointer);
- if ( mode == 2 && m_type.Eq(CBotTypClass) )
- r.SetType(CBotTypIntrinsic);
-
- return r;
-}
-
-int CBotVar::GivType(int mode)
-{
- if ( mode == 1 && m_type.Eq(CBotTypClass) )
- return CBotTypPointer;
- if ( mode == 2 && m_type.Eq(CBotTypClass) )
- return CBotTypIntrinsic;
- return m_type.GivType();
-}
-
-void CBotVar::SetType(CBotTypResult& type)
-{
- m_type = type;
-}
-
-
-int CBotVar::GivInit()
-{
- if ( m_type.Eq(CBotTypClass) ) return IS_DEF; // toujours défini !
-
- return m_binit;
-}
-
-void CBotVar::SetInit(BOOL bInit)
-{
- m_binit = bInit;
- if ( bInit == 2 ) m_binit = IS_DEF; // cas spécial
-
- if ( m_type.Eq(CBotTypPointer) && bInit == 2 )
- {
- CBotVarClass* instance = GivPointer();
- if ( instance == NULL )
- {
- instance = new CBotVarClass(NULL, m_type);
-// instance->SetClass(((CBotVarPointer*)this)->m_pClass);
- SetPointer(instance);
- }
- instance->SetInit(1);
- }
-
- if ( m_type.Eq(CBotTypClass) || m_type.Eq(CBotTypIntrinsic) )
- {
- CBotVar* p = ((CBotVarClass*)this)->m_pVar;
- while( p != NULL )
- {
- p->SetInit( bInit );
- p->m_pMyThis = (CBotVarClass*)this;
- p = p->GivNext();
- }
- }
-}
-
-CBotString CBotVar::GivName()
-{
- return m_token->GivString();
-}
-
-void CBotVar::SetName(const char* name)
-{
- m_token->SetString(name);
-}
-
-CBotToken* CBotVar::GivToken()
-{
- return m_token;
-}
-
-CBotVar* CBotVar::GivItem(const char* name)
-{
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::GivItemRef(int nIdent)
-{
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::GivItemList()
-{
- ASM_TRAP();
- return NULL;
-}
-
-CBotVar* CBotVar::GivItem(int row, BOOL bGrow)
-{
- ASM_TRAP();
- return NULL;
-}
-
-// dit si une variable appartient à une classe donnée
-BOOL CBotVar::IsElemOfClass(const char* name)
-{
- CBotClass* pc = NULL;
-
- if ( m_type.Eq(CBotTypPointer) )
- {
- pc = ((CBotVarPointer*)this)->m_pClass;
- }
- if ( m_type.Eq(CBotTypClass) )
- {
- pc = ((CBotVarClass*)this)->m_pClass;
- }
-
- while ( pc != NULL )
- {
- if ( pc->GivName() == name ) return TRUE;
- pc = pc->GivParent();
- }
-
- return FALSE;
-}
-
-
-CBotVar* CBotVar::GivStaticVar()
-{
- // rend le pointeur à la variable si elle est statique
- if ( m_bStatic == 0 || m_pMyThis == NULL ) return this;
-
- CBotClass* pClass = m_pMyThis->GivClass();
- return pClass->GivItem( m_token->GivString() );
-}
-
-
-CBotVar* CBotVar::GivNext()
-{
- return m_next;
-}
-
-void CBotVar::AddNext(CBotVar* pVar)
-{
- CBotVar* p = this;
- while (p->m_next != NULL) p = p->m_next;
-
- p->m_next = pVar;
-}
-
-void CBotVar::SetVal(CBotVar* var)
-{
- switch (/*var->*/GivType())
- {
- case CBotTypBoolean:
- SetValInt(var->GivValInt());
- break;
- case CBotTypInt:
- SetValInt(var->GivValInt(), ((CBotVarInt*)var)->m_defnum);
- break;
- case CBotTypFloat:
- SetValFloat(var->GivValFloat());
- break;
- case CBotTypString:
- SetValString(var->GivValString());
- break;
- case CBotTypPointer:
- case CBotTypNullPointer:
- case CBotTypArrayPointer:
- SetPointer(var->GivPointer());
- break;
- case CBotTypClass:
- {
- delete ((CBotVarClass*)this)->m_pVar;
- ((CBotVarClass*)this)->m_pVar = NULL;
- Copy(var, FALSE);
- }
- break;
- default:
- ASM_TRAP();
- }
-
- m_binit = var->m_binit; // copie l'état nan s'il y a
-}
-
-void CBotVar::SetStatic(BOOL bStatic)
-{
- m_bStatic = bStatic;
-}
-
-void CBotVar::SetPrivate(int mPrivate)
-{
- m_mPrivate = mPrivate;
-}
-
-BOOL CBotVar::IsStatic()
-{
- return m_bStatic;
-}
-
-BOOL CBotVar::IsPrivate(int mode)
-{
- return m_mPrivate >= mode;
-}
-
-int CBotVar::GivPrivate()
-{
- return m_mPrivate;
-}
-
-
-void CBotVar::SetPointer(CBotVar* pVarClass)
-{
- ASM_TRAP();
-}
-
-CBotVarClass* CBotVar::GivPointer()
-{
- ASM_TRAP();
- return NULL;
-}
-
-// toutes ces fonctions doivent être définies dans les classes filles
-// dérivées de la classe CBotVar
-
-int CBotVar::GivValInt()
-{
- ASM_TRAP();
- return 0;
-}
-
-float CBotVar::GivValFloat()
-{
- ASM_TRAP();
- return 0;
-}
-
-void CBotVar::SetValInt(int c, const char* s)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SetValFloat(float c)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Mul(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Power(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-int CBotVar::Div(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return 0;
-}
-
-int CBotVar::Modulo(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return 0;
-}
-
-void CBotVar::Add(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Sub(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-BOOL CBotVar::Lo(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return FALSE;
-}
-
-BOOL CBotVar::Hi(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return FALSE;
-}
-
-BOOL CBotVar::Ls(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return FALSE;
-}
-
-BOOL CBotVar::Hs(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return FALSE;
-}
-
-BOOL CBotVar::Eq(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return FALSE;
-}
-
-BOOL CBotVar::Ne(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
- return FALSE;
-}
-
-void CBotVar::And(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Or(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::XOr(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::ASR(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SR(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SL(CBotVar* left, CBotVar* right)
-{
- ASM_TRAP();
-}
-
-void CBotVar::Neg()
-{
- ASM_TRAP();
-}
-
-void CBotVar::Not()
-{
- ASM_TRAP();
-}
-
-void CBotVar::Inc()
-{
- ASM_TRAP();
-}
-void CBotVar::Dec()
-{
- ASM_TRAP();
-}
-
-void CBotVar::Copy(CBotVar* pSrc, BOOL bName)
-{
- ASM_TRAP();
-}
-
-void CBotVar::SetValString(const char* p)
-{
- ASM_TRAP();
-}
-
-CBotString CBotVar::GivValString()
-{
- ASM_TRAP();
- return CBotString();
-}
-
-void CBotVar::SetClass(CBotClass* pClass)
-{
- ASM_TRAP();
-}
-
-CBotClass* CBotVar::GivClass()
-{
- ASM_TRAP();
- return NULL;
-}
-
-/*
-void CBotVar::SetIndirection(CBotVar* pVar)
-{
- // nop, uniquement pour CBotVarPointer::SetIndirection
-}
-*/
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarInt::Copy(CBotVar* pSrc, BOOL bName)
-{
- CBotVarInt* p = (CBotVarInt*)pSrc;
-
- if ( bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
- m_pMyThis = NULL;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-
- m_defnum = p->m_defnum;
-}
-
-
-
-
-void CBotVarInt::SetValInt(int val, const char* defnum)
-{
- m_val = val;
- m_binit = TRUE;
- m_defnum = defnum;
-}
-
-
-
-void CBotVarInt::SetValFloat(float val)
-{
- m_val = (int)val;
- m_binit = TRUE;
-}
-
-int CBotVarInt::GivValInt()
-{
- return m_val;
-}
-
-float CBotVarInt::GivValFloat()
-{
- return (float)m_val;
-}
-
-CBotString CBotVarInt::GivValString()
-{
- if ( !m_defnum.IsEmpty() ) return m_defnum;
-
- CBotString res;
-
- if ( !m_binit )
- {
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- res.LoadString(TX_NAN);
- return res;
- }
-
- char buffer[300];
- sprintf(buffer, "%d", m_val);
- res = buffer;
-
- return res;
-}
-
-
-void CBotVarInt::Mul(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() * right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::Power(CBotVar* left, CBotVar* right)
-{
- m_val = (int) pow( (double) left->GivValInt() , (double) right->GivValInt() );
- m_binit = TRUE;
-}
-
-int CBotVarInt::Div(CBotVar* left, CBotVar* right)
-{
- int r = right->GivValInt();
- if ( r != 0 )
- {
- m_val = left->GivValInt() / r;
- m_binit = TRUE;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-int CBotVarInt::Modulo(CBotVar* left, CBotVar* right)
-{
- int r = right->GivValInt();
- if ( r != 0 )
- {
- m_val = left->GivValInt() % r;
- m_binit = TRUE;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-void CBotVarInt::Add(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() + right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::Sub(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() - right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::XOr(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() ^ right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::And(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() & right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::Or(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() | right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::SL(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() << right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::ASR(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() >> right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarInt::SR(CBotVar* left, CBotVar* right)
-{
- int source = left->GivValInt();
- int shift = right->GivValInt();
- if (shift>=1) source &= 0x7fffffff;
- m_val = source >> shift;
- m_binit = TRUE;
-}
-
-void CBotVarInt::Neg()
-{
- m_val = -m_val;
-}
-
-void CBotVarInt::Not()
-{
- m_val = ~m_val;
-}
-
-void CBotVarInt::Inc()
-{
- m_val++;
- m_defnum.Empty();
-}
-
-void CBotVarInt::Dec()
-{
- m_val--;
- m_defnum.Empty();
-}
-
-BOOL CBotVarInt::Lo(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() < right->GivValInt();
-}
-
-BOOL CBotVarInt::Hi(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() > right->GivValInt();
-}
-
-BOOL CBotVarInt::Ls(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() <= right->GivValInt();
-}
-
-BOOL CBotVarInt::Hs(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() >= right->GivValInt();
-}
-
-BOOL CBotVarInt::Eq(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() == right->GivValInt();
-}
-
-BOOL CBotVarInt::Ne(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() != right->GivValInt();
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarFloat::Copy(CBotVar* pSrc, BOOL bName)
-{
- CBotVarFloat* p = (CBotVarFloat*)pSrc;
-
- if (bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-
-
-
-void CBotVarFloat::SetValInt(int val, const char* s)
-{
- m_val = (float)val;
- m_binit = TRUE;
-}
-
-void CBotVarFloat::SetValFloat(float val)
-{
- m_val = val;
- m_binit = TRUE;
-}
-
-int CBotVarFloat::GivValInt()
-{
- return (int)m_val;
-}
-
-float CBotVarFloat::GivValFloat()
-{
- return m_val;
-}
-
-CBotString CBotVarFloat::GivValString()
-{
- CBotString res;
-
- if ( !m_binit )
- {
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- res.LoadString(TX_NAN);
- return res;
- }
-
- char buffer[300];
- sprintf(buffer, "%.2f", m_val);
- res = buffer;
-
- return res;
-}
-
-
-void CBotVarFloat::Mul(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValFloat() * right->GivValFloat();
- m_binit = TRUE;
-}
-
-void CBotVarFloat::Power(CBotVar* left, CBotVar* right)
-{
- m_val = (float)pow( left->GivValFloat() , right->GivValFloat() );
- m_binit = TRUE;
-}
-
-int CBotVarFloat::Div(CBotVar* left, CBotVar* right)
-{
- float r = right->GivValFloat();
- if ( r != 0 )
- {
- m_val = left->GivValFloat() / r;
- m_binit = TRUE;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right)
-{
- float r = right->GivValFloat();
- if ( r != 0 )
- {
- m_val = (float)fmod( left->GivValFloat() , r );
- m_binit = TRUE;
- }
- return ( r == 0 ? TX_DIVZERO : 0 );
-}
-
-void CBotVarFloat::Add(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValFloat() + right->GivValFloat();
- m_binit = TRUE;
-}
-
-void CBotVarFloat::Sub(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValFloat() - right->GivValFloat();
- m_binit = TRUE;
-}
-
-void CBotVarFloat::Neg()
-{
- m_val = -m_val;
-}
-
-void CBotVarFloat::Inc()
-{
- m_val++;
-}
-
-void CBotVarFloat::Dec()
-{
- m_val--;
-}
-
-
-BOOL CBotVarFloat::Lo(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() < right->GivValFloat();
-}
-
-BOOL CBotVarFloat::Hi(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() > right->GivValFloat();
-}
-
-BOOL CBotVarFloat::Ls(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() <= right->GivValFloat();
-}
-
-BOOL CBotVarFloat::Hs(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() >= right->GivValFloat();
-}
-
-BOOL CBotVarFloat::Eq(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() == right->GivValFloat();
-}
-
-BOOL CBotVarFloat::Ne(CBotVar* left, CBotVar* right)
-{
- return left->GivValFloat() != right->GivValFloat();
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarBoolean::Copy(CBotVar* pSrc, BOOL bName)
-{
- CBotVarBoolean* p = (CBotVarBoolean*)pSrc;
-
- if (bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-
-
-
-void CBotVarBoolean::SetValInt(int val, const char* s)
-{
- m_val = (BOOL)val;
- m_binit = TRUE;
-}
-
-void CBotVarBoolean::SetValFloat(float val)
-{
- m_val = (BOOL)val;
- m_binit = TRUE;
-}
-
-int CBotVarBoolean::GivValInt()
-{
- return m_val;
-}
-
-float CBotVarBoolean::GivValFloat()
-{
- return (float)m_val;
-}
-
-CBotString CBotVarBoolean::GivValString()
-{
- CBotString ret;
-
- CBotString res;
-
- if ( !m_binit )
- {
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- res.LoadString(TX_NAN);
- return res;
- }
-
- ret.LoadString( m_val > 0 ? ID_TRUE : ID_FALSE );
- return ret;
-}
-
-void CBotVarBoolean::And(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() && right->GivValInt();
- m_binit = TRUE;
-}
-void CBotVarBoolean::Or(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() || right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValInt() ^ right->GivValInt();
- m_binit = TRUE;
-}
-
-void CBotVarBoolean::Not()
-{
- m_val = m_val ? FALSE : TRUE ;
-}
-
-BOOL CBotVarBoolean::Eq(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() == right->GivValInt();
-}
-
-BOOL CBotVarBoolean::Ne(CBotVar* left, CBotVar* right)
-{
- return left->GivValInt() != right->GivValInt();
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarString::Copy(CBotVar* pSrc, BOOL bName)
-{
- CBotVarString* p = (CBotVarString*)pSrc;
-
- if (bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_val = p->m_val;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-
-void CBotVarString::SetValString(const char* p)
-{
- m_val = p;
- m_binit = TRUE;
-}
-
-CBotString CBotVarString::GivValString()
-{
- if ( !m_binit )
- {
- CBotString res;
- res.LoadString(TX_UNDEF);
- return res;
- }
- if ( m_binit == IS_NAN )
- {
- CBotString res;
- res.LoadString(TX_NAN);
- return res;
- }
-
- return m_val;
-}
-
-
-void CBotVarString::Add(CBotVar* left, CBotVar* right)
-{
- m_val = left->GivValString() + right->GivValString();
- m_binit = TRUE;
-}
-
-BOOL CBotVarString::Eq(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-BOOL CBotVarString::Ne(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() != right->GivValString());
-}
-
-
-BOOL CBotVarString::Lo(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-BOOL CBotVarString::Hi(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-BOOL CBotVarString::Ls(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-BOOL CBotVarString::Hs(CBotVar* left, CBotVar* right)
-{
- return (left->GivValString() == right->GivValString());
-}
-
-
-////////////////////////////////////////////////////////////////
-
-// copie une variable dans une autre
-void CBotVarClass::Copy(CBotVar* pSrc, BOOL bName)
-{
- pSrc = pSrc->GivPointer(); // si source donné par un pointeur
-
- if ( pSrc->GivType() != CBotTypClass )
- ASM_TRAP();
-
- CBotVarClass* p = (CBotVarClass*)pSrc;
-
- if (bName) *m_token = *p->m_token;
-
- m_type = p->m_type;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_pClass = p->m_pClass;
- if ( p->m_pParent )
- {
- ASM_TRAP(); "que faire du pParent";
- }
-
-// m_next = NULL;
- m_pUserPtr = p->m_pUserPtr;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_ItemIdent = p->m_ItemIdent;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-
- delete m_pVar;
- m_pVar = NULL;
-
- CBotVar* pv = p->m_pVar;
- while( pv != NULL )
- {
- CBotVar* pn = CBotVar::Create(pv);
- pn->Copy( pv );
- if ( m_pVar == NULL ) m_pVar = pn;
- else m_pVar->AddNext(pn);
-
- pv = pv->GivNext();
- }
-}
-
-void CBotVarClass::SetItemList(CBotVar* pVar)
-{
- delete m_pVar;
- m_pVar = pVar; // remplace le pointeur existant
-}
-
-void CBotVarClass::SetIdent(long n)
-{
- m_ItemIdent = n;
-}
-
-void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
-{
- m_type.m_pClass = pClass;
-
- if ( m_pClass == pClass ) return;
-
- m_pClass = pClass;
-
- // initialise les variables associées à cette classe
- delete m_pVar;
- m_pVar = NULL;
-
- if (pClass == NULL) return;
-
- CBotVar* pv = pClass->GivVar(); // premier de la liste
- while ( pv != NULL )
- {
- // cherche les dimensions max du tableau
- CBotInstr* p = pv->m_LimExpr; // les différentes formules
- if ( p != NULL )
- {
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
- int n = 0;
- int max[100];
-
- while (p != NULL)
- {
- while( pile->IsOk() && !p->Execute(pile) ) ; // calcul de la taille sans interruptions
- CBotVar* v = pile->GivVar(); // résultat
- max[n] = v->GivValInt(); // valeur
- n++;
- p = p->GivNext3();
- }
- while (n<100) max[n++] = 0;
-
- pv->m_type.SetArray( max ); // mémorise les limitations
- pile->Delete();
- }
-
- CBotVar* pn = CBotVar::Create( pv ); // une copie
- pn->SetStatic(pv->IsStatic());
- pn->SetPrivate(pv->GivPrivate());
-
- if ( pv->m_InitExpr != NULL ) // expression pour l'initialisation ?
- {
-#if STACKMEM
- CBotStack* pile = CBotStack::FirstStack(); // une pile indépendante
-
- while(pile->IsOk() && !pv->m_InitExpr->Execute(pile, pn)); // évalue l'expression sans timer
-
- pile->Delete();
-#else
- CBotStack* pile = new CBotStack(NULL); // une pile indépendante
- while(!pv->m_InitExpr->Execute(pile)); // évalue l'expression sans timer
- pn->SetVal( pile->GivVar() ) ;
- delete pile;
-#endif
- }
-
-// pn->SetUniqNum(CBotVar::NextUniqNum()); // numérote les éléments
- pn->SetUniqNum(pv->GivUniqNum()); //++nIdent
- pn->m_pMyThis = this;
-
- if ( m_pVar == NULL) m_pVar = pn;
- else m_pVar->AddNext( pn );
- pv = pv->GivNext();
- }
-}
-
-CBotClass* CBotVarClass::GivClass()
-{
- return m_pClass;
-}
-
-
-void CBotVarClass::Maj(void* pUser, BOOL bContinu)
-{
-/* if (!bContinu && m_pMyThis != NULL)
- m_pMyThis->Maj(pUser, TRUE);*/
-
- // une routine de mise à jour existe-elle ?
-
- if ( m_pClass->m_rMaj == NULL ) return;
-
- // récupère le pointeur user selon la classe
- // ou selon le paramètre passé au CBotProgram::Run()
-
- if ( m_pUserPtr != NULL) pUser = m_pUserPtr;
- if ( pUser == OBJECTDELETED ||
- pUser == OBJECTCREATED ) return;
- m_pClass->m_rMaj( this, pUser );
-}
-
-CBotVar* CBotVarClass::GivItem(const char* name)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivName() == name ) return p;
- p = p->GivNext();
- }
-
- if ( m_pParent != NULL ) return m_pParent->GivItem(name);
- return NULL;
-}
-
-CBotVar* CBotVarClass::GivItemRef(int nIdent)
-{
- CBotVar* p = m_pVar;
-
- while ( p != NULL )
- {
- if ( p->GivUniqNum() == nIdent ) return p;
- p = p->GivNext();
- }
-
- if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
- return NULL;
-}
-
-// pour la gestion d'un tableau
-// bExtend permet d'agrandir le tableau, mais pas au dela de la taille fixée par SetArray()
-
-CBotVar* CBotVarClass::GivItem(int n, BOOL bExtend)
-{
- CBotVar* p = m_pVar;
-
- if ( n < 0 ) return NULL;
- if ( n > MAXARRAYSIZE ) return NULL;
-
- if ( m_type.GivLimite() >= 0 && n >= m_type.GivLimite() ) return NULL;
-
- if ( p == NULL && bExtend )
- {
- p = CBotVar::Create("", m_type.GivTypElem());
- m_pVar = p;
- }
-
- if ( n == 0 ) return p;
-
- while ( n-- > 0 )
- {
- if ( p->m_next == NULL )
- {
- if ( bExtend ) p->m_next = CBotVar::Create("", m_type.GivTypElem());
- if ( p->m_next == NULL ) return NULL;
- }
- p = p->m_next;
- }
-
- return p;
-}
-
-CBotVar* CBotVarClass::GivItemList()
-{
- return m_pVar;
-}
-
-
-CBotString CBotVarClass::GivValString()
-{
-// if ( m_Indirect != NULL) return m_Indirect->GivValString();
-
- CBotString res;
-
- if ( m_pClass != NULL ) // pas utilisé pour un array
- {
- res = m_pClass->GivName() + CBotString("( ");
-
- CBotVarClass* my = this;
- while ( my != NULL )
- {
- CBotVar* pv = my->m_pVar;
- while ( pv != NULL )
- {
- res += pv->GivName() + CBotString("=");
-
- if ( pv->IsStatic() )
- {
- CBotVar* pvv = my->m_pClass->GivItem(pv->GivName());
- res += pvv->GivValString();
- }
- else
- {
- res += pv->GivValString();
- }
- pv = pv->GivNext();
- if ( pv != NULL ) res += ", ";
- }
- my = my->m_pParent;
- if ( my != NULL )
- {
- res += ") extends ";
- res += my->m_pClass->GivName();
- res += " (";
- }
- }
- }
- else
- {
- res = "( ";
-
- CBotVar* pv = m_pVar;
- while ( pv != NULL )
- {
- res += pv->GivValString();
- if ( pv->GivNext() != NULL ) res += ", ";
- pv = pv->GivNext();
- }
- }
-
- res += " )";
- return res;
-}
-
-void CBotVarClass::IncrementUse()
-{
- m_CptUse++;
-}
-
-void CBotVarClass::DecrementUse()
-{
- m_CptUse--;
- if ( m_CptUse == 0 )
- {
- // s'il y en a un, appel le destructeur
- // mais seulement si un constructeur avait été appelé.
- if ( m_bConstructor )
- {
- m_CptUse++; // ne revient pas dans le destructeur
-
- // m_error est static dans le stack
- // sauve la valeur pour la remettre ensuite
- int err, start, end;
- CBotStack* pile = NULL;
- err = pile->GivError(start,end); // pile == NULL ça ne derange pas !!
-
- pile = CBotStack::FirstStack(); // efface l'erreur
- CBotVar* ppVars[1];
- ppVars[0] = NULL;
-
- CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer);
- pThis->SetPointer(this);
- CBotVar* pResult = NULL;
-
- CBotString nom = "~" + m_pClass->GivName();
- long ident = 0;
-
- while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, NULL)) ; // attend la fin
-
- pile->ResetError(err, start,end);
-
- pile->Delete();
- delete pThis;
- m_CptUse--;
- }
-
- delete this; // s'auto-détruit !!
- }
-}
-
-CBotVarClass* CBotVarClass::GivPointer()
-{
- return this;
-}
-
-
-// trouve une instance selon son numéro unique
-
-CBotVarClass* CBotVarClass::Find(long id)
-{
- CBotVarClass* p = m_ExClass;
-
- while ( p != NULL )
- {
- if ( p->m_ItemIdent == id ) return p;
- p = p->m_ExNext;
- }
-
- return NULL;
-}
-
-BOOL CBotVarClass::Eq(CBotVar* left, CBotVar* right)
-{
- CBotVar* l = left->GivItemList();
- CBotVar* r = right->GivItemList();
-
- while ( l != NULL && r != NULL )
- {
- if ( l->Ne(l, r) ) return FALSE;
- l = l->GivNext();
- r = r->GivNext();
- }
-
- // devrait toujours arrivé simultanément au bout (mêmes classes)
- return l == r;
-}
-
-BOOL CBotVarClass::Ne(CBotVar* left, CBotVar* right)
-{
- CBotVar* l = left->GivItemList();
- CBotVar* r = right->GivItemList();
-
- while ( l != NULL && r != NULL )
- {
- if ( l->Ne(l, r) ) return TRUE;
- l = l->GivNext();
- r = r->GivNext();
- }
-
- // devrait toujours arrivé simultanément au bout (mêmes classes)
- return l != r;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// gestion des tableaux de variables
-
-CBotVarArray::CBotVarArray(const CBotToken* name, CBotTypResult& type )
-{
- if ( !type.Eq(CBotTypArrayPointer) &&
- !type.Eq(CBotTypArrayBody)) ASM_TRAP();
-
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
-
- m_type = type;
- m_type.SetType(CBotTypArrayPointer);
- m_binit = FALSE;
-
- m_pInstance = NULL; // la liste des éléments du tableau
-}
-
-CBotVarArray::~CBotVarArray()
-{
- if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); // une référence en moins
-}
-
-// copie une variable dans une autre
-void CBotVarArray::Copy(CBotVar* pSrc, BOOL bName)
-{
- if ( pSrc->GivType() != CBotTypArrayPointer )
- ASM_TRAP();
-
- CBotVarArray* p = (CBotVarArray*)pSrc;
-
- if ( bName) *m_token = *p->m_token;
- m_type = p->m_type;
- m_pInstance = p->GivPointer();
-
- if ( m_pInstance != NULL )
- m_pInstance->IncrementUse(); // une référence en plus
-
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-void CBotVarArray::SetPointer(CBotVar* pVarClass)
-{
- m_binit = TRUE; // init, même sur un pointeur null
-
- if ( m_pInstance == pVarClass) return; // spécial, ne pas décrémenter et réincrémenter
- // car le décrément peut détruire l'object
-
- if ( pVarClass != NULL )
- {
- if ( pVarClass->GivType() == CBotTypArrayPointer )
- pVarClass = pVarClass->GivPointer(); // le vrai pointeur à l'objet
-
- if ( !pVarClass->m_type.Eq(CBotTypClass) &&
- !pVarClass->m_type.Eq(CBotTypArrayBody))
- ASM_TRAP();
-
- ((CBotVarClass*)pVarClass)->IncrementUse(); // une référence en plus
- }
-
- if ( m_pInstance != NULL ) m_pInstance->DecrementUse();
- m_pInstance = (CBotVarClass*)pVarClass;
-}
-
-
-CBotVarClass* CBotVarArray::GivPointer()
-{
- if ( m_pInstance == NULL ) return NULL;
- return m_pInstance->GivPointer();
-}
-
-CBotVar* CBotVarArray::GivItem(int n, BOOL bExtend)
-{
- if ( m_pInstance == NULL )
- {
- if ( !bExtend ) return NULL;
- // crée une instance pour le tableau
-
- CBotVarClass* instance = new CBotVarClass(NULL, m_type);
- SetPointer( instance );
- }
- return m_pInstance->GivItem(n, bExtend);
-}
-
-CBotVar* CBotVarArray::GivItemList()
-{
- if ( m_pInstance == NULL) return NULL;
- return m_pInstance->GivItemList();
-}
-
-CBotString CBotVarArray::GivValString()
-{
- if ( m_pInstance == NULL ) return ( CBotString( "Null pointer" ) ) ;
- return m_pInstance->GivValString();
-}
-
-BOOL CBotVarArray::Save1State(FILE* pf)
-{
- if ( !WriteType(pf, m_type) ) return FALSE;
- return SaveVar(pf, m_pInstance); // sauve l'instance qui gère le tableau
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-// gestion des pointeurs à une instance donnée
-
-CBotVarPointer::CBotVarPointer(const CBotToken* name, CBotTypResult& type )
-{
- if ( !type.Eq(CBotTypPointer) &&
- !type.Eq(CBotTypNullPointer) &&
- !type.Eq(CBotTypClass) && // par commodité accepte Class et Intrinsic
- !type.Eq(CBotTypIntrinsic) ) ASM_TRAP();
-
- m_token = new CBotToken(name);
- m_next = NULL;
- m_pMyThis = NULL;
- m_pUserPtr = NULL;
-
- m_type = type;
- if ( !type.Eq(CBotTypNullPointer) )
- m_type.SetType(CBotTypPointer); // quoi qu'il en soit, c'est un pointeur
- m_binit = FALSE;
- m_pClass = NULL;
- m_pVarClass = NULL; // sera défini par un SetPointer()
-
- SetClass(type.GivClass() );
-}
-
-CBotVarPointer::~CBotVarPointer()
-{
- if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); // une référence en moins
-}
-
-
-void CBotVarPointer::Maj(void* pUser, BOOL bContinu)
-{
-/* if ( !bContinu && m_pMyThis != NULL )
- m_pMyThis->Maj(pUser, FALSE);*/
-
- if ( m_pVarClass != NULL) m_pVarClass->Maj(pUser, FALSE);
-}
-
-CBotVar* CBotVarPointer::GivItem(const char* name)
-{
- if ( m_pVarClass == NULL) // pas d'instance existant ?
- return m_pClass->GivItem(name); // rend le pointeur dans la classe elle-même
-
- return m_pVarClass->GivItem(name);
-}
-
-CBotVar* CBotVarPointer::GivItemRef(int nIdent)
-{
- if ( m_pVarClass == NULL) // pas d'instance existant ?
- return m_pClass->GivItemRef(nIdent);// rend le pointeur dans la classe elle-même
-
- return m_pVarClass->GivItemRef(nIdent);
-}
-
-CBotVar* CBotVarPointer::GivItemList()
-{
- if ( m_pVarClass == NULL) return NULL;
- return m_pVarClass->GivItemList();
-}
-
-CBotString CBotVarPointer::GivValString()
-{
- CBotString s = "Pointer to ";
- if ( m_pVarClass == NULL ) s = "Null pointer" ;
- else s += m_pVarClass->GivValString();
- return s;
-}
-
-
-void CBotVarPointer::ConstructorSet()
-{
- if ( m_pVarClass != NULL) m_pVarClass->ConstructorSet();
-}
-
-// initialise le pointeur vers l'instance d'une classe
-
-void CBotVarPointer::SetPointer(CBotVar* pVarClass)
-{
- m_binit = TRUE; // init, même sur un pointeur null
-
- if ( m_pVarClass == pVarClass) return; // spécial, ne pas décrémenter et réincrémenter
- // car le décrément peut détruire l'object
-
- if ( pVarClass != NULL )
- {
- if ( pVarClass->GivType() == CBotTypPointer )
- pVarClass = pVarClass->GivPointer(); // le vrai pointeur à l'objet
-
-// if ( pVarClass->GivType() != CBotTypClass )
- if ( !pVarClass->m_type.Eq(CBotTypClass) )
- ASM_TRAP();
-
- ((CBotVarClass*)pVarClass)->IncrementUse(); // une référence en plus
- m_pClass = ((CBotVarClass*)pVarClass)->m_pClass;
- m_pUserPtr = pVarClass->m_pUserPtr; // pas vraiment indispensable
- m_type = CBotTypResult(CBotTypPointer, m_pClass); // un pointeur de quel genre
- }
-
- if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse();
- m_pVarClass = (CBotVarClass*)pVarClass;
-
-}
-
-CBotVarClass* CBotVarPointer::GivPointer()
-{
- if ( m_pVarClass == NULL ) return NULL;
- return m_pVarClass->GivPointer();
-}
-
-void CBotVarPointer::SetIdent(long n)
-{
- if ( m_pVarClass == NULL ) return;
- m_pVarClass->SetIdent( n );
-}
-
-long CBotVarPointer::GivIdent()
-{
- if ( m_pVarClass == NULL ) return 0;
- return m_pVarClass->m_ItemIdent;
-}
-
-
-void CBotVarPointer::SetClass(CBotClass* pClass)
-{
-// int nIdent = 0;
- m_type.m_pClass = m_pClass = pClass;
- if ( m_pVarClass != NULL ) m_pVarClass->SetClass(pClass); //, nIdent);
-}
-
-CBotClass* CBotVarPointer::GivClass()
-{
- if ( m_pVarClass != NULL ) return m_pVarClass->GivClass();
-
- return m_pClass;
-}
-
-
-BOOL CBotVarPointer::Save1State(FILE* pf)
-{
- if ( m_pClass )
- {
- if (!WriteString(pf, m_pClass->GivName())) return FALSE; // nom de la classe
- }
- else
- {
- if (!WriteString(pf, "")) return FALSE;
- }
-
- if (!WriteLong(pf, GivIdent())) return FALSE; // la référence unique
-
- // sauve aussi une copie de l'instance
- return SaveVar(pf, GivPointer());
-}
-
-// copie une variable dans une autre
-void CBotVarPointer::Copy(CBotVar* pSrc, BOOL bName)
-{
- if ( pSrc->GivType() != CBotTypPointer &&
- pSrc->GivType() != CBotTypNullPointer)
- ASM_TRAP();
-
- CBotVarPointer* p = (CBotVarPointer*)pSrc;
-
- if ( bName) *m_token = *p->m_token;
- m_type = p->m_type;
-// m_pVarClass = p->m_pVarClass;
- m_pVarClass = p->GivPointer();
-
- if ( m_pVarClass != NULL )
- m_pVarClass->IncrementUse(); // une référence en plus
-
- m_pClass = p->m_pClass;
- m_binit = p->m_binit;
-//- m_bStatic = p->m_bStatic;
- m_next = NULL;
- m_pMyThis = NULL;//p->m_pMyThis;
- m_pUserPtr = p->m_pUserPtr;
-
- // garde le même idendificateur (par défaut)
- if (m_ident == 0 ) m_ident = p->m_ident;
-}
-
-BOOL CBotVarPointer::Eq(CBotVar* left, CBotVar* right)
-{
- CBotVarClass* l = left->GivPointer();
- CBotVarClass* r = right->GivPointer();
-
- if ( l == r ) return TRUE;
- if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return TRUE;
- if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return TRUE;
- return FALSE;
-}
-
-BOOL CBotVarPointer::Ne(CBotVar* left, CBotVar* right)
-{
- CBotVarClass* l = left->GivPointer();
- CBotVarClass* r = right->GivPointer();
-
- if ( l == r ) return FALSE;
- if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return FALSE;
- if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return FALSE;
- return TRUE;
-}
-
-
-
-///////////////////////////////////////////////////////
-// gestion des types de résultats
-
-
-CBotTypResult::CBotTypResult(int type)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = NULL;
- m_limite = -1;
-}
-
-CBotTypResult::CBotTypResult(int type, const char* name)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = NULL;
- m_limite = -1;
-
- if ( type == CBotTypPointer ||
- type == CBotTypClass ||
- type == CBotTypIntrinsic )
- {
- m_pClass = CBotClass::Find(name);
- if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic;
- }
-}
-
-CBotTypResult::CBotTypResult(int type, CBotClass* pClass)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = pClass;
- m_limite = -1;
-
- if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic;
-}
-
-CBotTypResult::CBotTypResult(int type, CBotTypResult elem)
-{
- m_type = type;
- m_pNext = NULL;
- m_pClass = NULL;
- m_limite = -1;
-
- if ( type == CBotTypArrayPointer ||
- type == CBotTypArrayBody )
- m_pNext = new CBotTypResult( elem );
-}
-
-CBotTypResult::CBotTypResult(const CBotTypResult& typ)
-{
- m_type = typ.m_type;
- m_pClass = typ.m_pClass;
- m_pNext = NULL;
- m_limite = typ.m_limite;
-
- if ( typ.m_pNext )
- m_pNext = new CBotTypResult( *typ.m_pNext );
-}
-
-CBotTypResult::CBotTypResult()
-{
- m_type = 0;
- m_limite = -1;
- m_pNext = NULL;
- m_pClass = NULL;
-}
-
-CBotTypResult::~CBotTypResult()
-{
- delete m_pNext;
-}
-
-int CBotTypResult::GivType(int mode) const
-{
-#ifdef _DEBUG
- if ( m_type == CBotTypPointer ||
- m_type == CBotTypClass ||
- m_type == CBotTypIntrinsic )
-
- if ( m_pClass == NULL ) ASM_TRAP();
-
-
- if ( m_type == CBotTypArrayPointer )
- if ( m_pNext == NULL ) ASM_TRAP();
-#endif
- if ( mode == 3 && m_type == CBotTypNullPointer ) return CBotTypPointer;
- return m_type;
-}
-
-void CBotTypResult::SetType(int n)
-{
- m_type = n;
-}
-
-CBotClass* CBotTypResult::GivClass() const
-{
- return m_pClass;
-}
-
-CBotTypResult& CBotTypResult::GivTypElem() const
-{
- return *m_pNext;
-}
-
-int CBotTypResult::GivLimite() const
-{
- return m_limite;
-}
-
-void CBotTypResult::SetLimite(int n)
-{
- m_limite = n;
-}
-
-void CBotTypResult::SetArray( int* max )
-{
- m_limite = *max;
- if (m_limite < 1) m_limite = -1;
-
- if ( m_pNext != NULL ) // dernière dimension ?
- {
- m_pNext->SetArray( max+1 );
- }
-}
-
-
-
-BOOL CBotTypResult::Compare(const CBotTypResult& typ) const
-{
- if ( m_type != typ.m_type ) return FALSE;
-
- if ( m_type == CBotTypArrayPointer ) return m_pNext->Compare(*typ.m_pNext);
-
- if ( m_type == CBotTypPointer ||
- m_type == CBotTypClass ||
- m_type == CBotTypIntrinsic )
- {
- return m_pClass == typ.m_pClass;
- }
-
- return TRUE;
-}
-
-BOOL CBotTypResult::Eq(int type) const
-{
- return m_type == type;
-}
-
-CBotTypResult&
- CBotTypResult::operator=(const CBotTypResult& src)
-{
- m_type = src.m_type;
- m_limite = src.m_limite;
- m_pClass = src.m_pClass;
- m_pNext = NULL;
- if ( src.m_pNext != NULL )
- {
- m_pNext = new CBotTypResult(*src.m_pNext);
- }
- return *this;
-}
-
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+////////////////////////////////////////////////////////////////////
+// Definition for the class CBotVar
+// variables management of the language CBoT
+
+// it never creates an instance of the class mother CBotVar
+
+#include "CBot.h"
+#include <math.h>
+#include <stdio.h>
+
+long CBotVar::m_identcpt = 0;
+
+CBotVar::CBotVar( )
+{
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+ m_InitExpr = NULL;
+ m_LimExpr = NULL;
+ m_type = -1;
+ m_binit = false;
+ m_ident = 0;
+ m_bStatic = false;
+ m_mPrivate = 0;
+}
+
+CBotVarInt::CBotVarInt( const CBotToken* name )
+{
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+ m_InitExpr = NULL;
+ m_LimExpr = NULL;
+ m_type = CBotTypInt;
+ m_binit = false;
+ m_bStatic = false;
+ m_mPrivate = 0;
+
+ m_val = 0;
+}
+
+CBotVarFloat::CBotVarFloat( const CBotToken* name )
+{
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+ m_InitExpr = NULL;
+ m_LimExpr = NULL;
+ m_type = CBotTypFloat;
+ m_binit = false;
+ m_bStatic = false;
+ m_mPrivate = 0;
+
+ m_val = 0;
+}
+
+CBotVarString::CBotVarString( const CBotToken* name )
+{
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+ m_InitExpr = NULL;
+ m_LimExpr = NULL;
+ m_type = CBotTypString;
+ m_binit = false;
+ m_bStatic = false;
+ m_mPrivate = 0;
+
+ m_val.Empty();
+}
+
+CBotVarBoolean::CBotVarBoolean( const CBotToken* name )
+{
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+ m_InitExpr = NULL;
+ m_LimExpr = NULL;
+ m_type = CBotTypBoolean;
+ m_binit = false;
+ m_bStatic = false;
+ m_mPrivate = 0;
+
+ m_val = 0;
+}
+
+CBotVarClass* CBotVarClass::m_ExClass = NULL;
+
+CBotVarClass::CBotVarClass( const CBotToken* name, const CBotTypResult& type)
+{
+/*
+// int nIdent = 0;
+ InitCBotVarClass( name, type ) //, nIdent );
+}
+
+CBotVarClass::CBotVarClass( const CBotToken* name, CBotTypResult& type) //, int &nIdent )
+{
+ InitCBotVarClass( name, type ); //, nIdent );
+}
+
+void CBotVarClass::InitCBotVarClass( const CBotToken* name, CBotTypResult& type ) //, int &nIdent )
+{*/
+ if ( !type.Eq(CBotTypClass) &&
+ !type.Eq(CBotTypIntrinsic) && // by convenience there accepts these types
+ !type.Eq(CBotTypPointer) &&
+ !type.Eq(CBotTypArrayPointer) &&
+ !type.Eq(CBotTypArrayBody)) ASM_TRAP();
+
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = OBJECTCREATED;//NULL;
+ m_InitExpr = NULL;
+ m_LimExpr = NULL;
+ m_pVar = NULL;
+ m_type = type;
+ if ( type.Eq(CBotTypArrayPointer) ) m_type.SetType( CBotTypArrayBody );
+ else if ( !type.Eq(CBotTypArrayBody) ) m_type.SetType( CBotTypClass );
+ // officel type for this object
+
+ m_pClass = NULL;
+ m_pParent = NULL;
+ m_binit = false;
+ m_bStatic = false;
+ m_mPrivate = 0;
+ m_bConstructor = false;
+ m_CptUse = 0;
+ m_ItemIdent = type.Eq(CBotTypIntrinsic) ? 0 : CBotVar::NextUniqNum();
+
+ // se place tout seul dans la liste
+ // TODO stands alone in the list (stands only in a list)
+ if (m_ExClass) m_ExClass->m_ExPrev = this;
+ m_ExNext = m_ExClass;
+ m_ExPrev = NULL;
+ m_ExClass = this;
+
+ CBotClass* pClass = type.GivClass();
+ CBotClass* pClass2 = pClass->GivParent();
+ if ( pClass2 != NULL )
+ {
+ // also creates an instance of the parent class
+ m_pParent = new CBotVarClass(name, CBotTypResult(type.GivType(),pClass2) ); //, nIdent);
+ }
+
+ SetClass( pClass ); //, nIdent );
+
+}
+
+CBotVarClass::~CBotVarClass( )
+{
+ if ( m_CptUse != 0 )
+ ASM_TRAP();
+
+ if ( m_pParent ) delete m_pParent;
+ m_pParent = NULL;
+
+ // frees the indirect object if necessary
+// if ( m_Indirect != NULL )
+// m_Indirect->DecrementUse();
+
+ // removes the class list
+ if ( m_ExPrev ) m_ExPrev->m_ExNext = m_ExNext;
+ else m_ExClass = m_ExNext;
+
+ if ( m_ExNext ) m_ExNext->m_ExPrev = m_ExPrev;
+ m_ExPrev = NULL;
+ m_ExNext = NULL;
+
+ delete m_pVar;
+}
+
+void CBotVarClass::ConstructorSet()
+{
+ m_bConstructor = true;
+}
+
+
+CBotVar::~CBotVar( )
+{
+ delete m_token;
+ delete m_next;
+}
+
+void CBotVar::debug()
+{
+ const char* p = (const char*) m_token->GivString();
+ CBotString s = (const char*) GivValString();
+ const char* v = (const char*) s;
+
+ if ( m_type.Eq(CBotTypClass) )
+ {
+ CBotVar* pv = ((CBotVarClass*)this)->m_pVar;
+ while (pv != NULL)
+ {
+ pv->debug();
+ pv = pv->GivNext();
+ }
+ }
+}
+
+void CBotVar::ConstructorSet()
+{
+ // nop
+}
+
+void CBotVar::SetUserPtr(void* pUser)
+{
+ m_pUserPtr = pUser;
+ if (m_type.Eq(CBotTypPointer) &&
+ ((CBotVarPointer*)this)->m_pVarClass != NULL )
+ ((CBotVarPointer*)this)->m_pVarClass->SetUserPtr(pUser);
+}
+
+void CBotVar::SetIdent(long n)
+{
+ if (m_type.Eq(CBotTypPointer) &&
+ ((CBotVarPointer*)this)->m_pVarClass != NULL )
+ ((CBotVarPointer*)this)->m_pVarClass->SetIdent(n);
+}
+
+void CBotVar::SetUniqNum(long n)
+{
+ m_ident = n;
+
+ if ( n == 0 ) ASM_TRAP();
+}
+
+long CBotVar::NextUniqNum()
+{
+ if (++m_identcpt < 10000) m_identcpt = 10000;
+ return m_identcpt;
+}
+
+long CBotVar::GivUniqNum()
+{
+ return m_ident;
+}
+
+
+void* CBotVar::GivUserPtr()
+{
+ return m_pUserPtr;
+}
+
+bool CBotVar::Save1State(FILE* pf)
+{
+ // this routine "virtual" must never be called,
+ // there must be a routine for each of the subclasses (CBotVarInt, CBotVarFloat, etc)
+ // ( see the type in m_type )
+ ASM_TRAP();
+ return false;
+}
+
+void CBotVar::Maj(void* pUser, bool bContinu)
+{
+/* if (!bContinu && m_pMyThis != NULL)
+ m_pMyThis->Maj(pUser, true);*/
+}
+
+
+// creates a variable depending on its type
+
+CBotVar* CBotVar::Create(const CBotToken* name, int type )
+{
+ CBotTypResult t(type);
+ return Create(name, t);
+}
+
+CBotVar* CBotVar::Create(const CBotToken* name, CBotTypResult type)
+{
+ switch (type.GivType())
+ {
+ case CBotTypShort:
+ case CBotTypInt:
+ return new CBotVarInt(name);
+ case CBotTypFloat:
+ return new CBotVarFloat(name);
+ case CBotTypBoolean:
+ return new CBotVarBoolean(name);
+ case CBotTypString:
+ return new CBotVarString(name);
+ case CBotTypPointer:
+ case CBotTypNullPointer:
+ return new CBotVarPointer(name, type);
+ case CBotTypIntrinsic:
+ return new CBotVarClass(name, type);
+
+ case CBotTypClass:
+ // creates a new instance of a class
+ // and returns the POINTER on this instance
+ {
+ CBotVarClass* instance = new CBotVarClass(name, type);
+ CBotVarPointer* pointer = new CBotVarPointer(name, type);
+ pointer->SetPointer( instance );
+ return pointer;
+ }
+
+ case CBotTypArrayPointer:
+ return new CBotVarArray(name, type);
+
+ case CBotTypArrayBody:
+ {
+ CBotVarClass* instance = new CBotVarClass(name, type);
+ CBotVarArray* array = new CBotVarArray(name, type);
+ array->SetPointer( instance );
+
+ CBotVar* pv = array;
+ while (type.Eq(CBotTypArrayBody))
+ {
+ type = type.GivTypElem();
+ pv = ((CBotVarArray*)pv)->GivItem(0, true); // creates at least the element [0]
+ }
+
+ return array;
+ }
+ }
+
+ ASM_TRAP();
+ return NULL;
+}
+
+CBotVar* CBotVar::Create( CBotVar* pVar )
+{
+ CBotVar* p = Create(pVar->m_token->GivString(), pVar->GivTypResult(2));
+ return p;
+}
+
+
+CBotVar* CBotVar::Create( const char* n, CBotTypResult type)
+{
+ CBotToken name(n);
+
+ switch (type.GivType())
+ {
+ case CBotTypShort:
+ case CBotTypInt:
+ return new CBotVarInt(&name);
+ case CBotTypFloat:
+ return new CBotVarFloat(&name);
+ case CBotTypBoolean:
+ return new CBotVarBoolean(&name);
+ case CBotTypString:
+ return new CBotVarString(&name);
+ case CBotTypPointer:
+ case CBotTypNullPointer:
+ {
+ CBotVarPointer* p = new CBotVarPointer(&name, type);
+// p->SetClass(type.GivClass());
+ return p;
+ }
+ case CBotTypIntrinsic:
+ {
+ CBotVarClass* p = new CBotVarClass(&name, type);
+// p->SetClass(type.GivClass());
+ return p;
+ }
+
+ case CBotTypClass:
+ // creates a new instance of a class
+ // and returns the POINTER on this instance
+ {
+ CBotVarClass* instance = new CBotVarClass(&name, type);
+ CBotVarPointer* pointer = new CBotVarPointer(&name, type);
+ pointer->SetPointer( instance );
+// pointer->SetClass( type.GivClass() );
+ return pointer;
+ }
+
+ case CBotTypArrayPointer:
+ return new CBotVarArray(&name, type);
+
+ case CBotTypArrayBody:
+ {
+ CBotVarClass* instance = new CBotVarClass(&name, type);
+ CBotVarArray* array = new CBotVarArray(&name, type);
+ array->SetPointer( instance );
+
+ CBotVar* pv = array;
+ while (type.Eq(CBotTypArrayBody))
+ {
+ type = type.GivTypElem();
+ pv = ((CBotVarArray*)pv)->GivItem(0, true); // creates at least the element [0]
+ }
+
+ return array;
+ }
+ }
+
+ ASM_TRAP();
+ return NULL;
+}
+
+CBotVar* CBotVar::Create( const char* name, int type, CBotClass* pClass)
+{
+ CBotToken token( name, "" );
+ CBotVar* pVar = Create( &token, type );
+
+ if ( type == CBotTypPointer && pClass == NULL ) // pointer "null" ?
+ return pVar;
+
+ if ( type == CBotTypClass || type == CBotTypPointer ||
+ type == CBotTypIntrinsic )
+ {
+ if (pClass == NULL)
+ {
+ delete pVar;
+ return NULL;
+ }
+ pVar->SetClass( pClass );
+ }
+ return pVar;
+}
+
+CBotVar* CBotVar::Create( const char* name, CBotClass* pClass)
+{
+ CBotToken token( name, "" );
+ CBotVar* pVar = Create( &token, CBotTypResult( CBotTypClass, pClass ) );
+// pVar->SetClass( pClass );
+ return pVar;
+}
+
+CBotTypResult CBotVar::GivTypResult(int mode)
+{
+ CBotTypResult r = m_type;
+
+ if ( mode == 1 && m_type.Eq(CBotTypClass) )
+ r.SetType(CBotTypPointer);
+ if ( mode == 2 && m_type.Eq(CBotTypClass) )
+ r.SetType(CBotTypIntrinsic);
+
+ return r;
+}
+
+int CBotVar::GivType(int mode)
+{
+ if ( mode == 1 && m_type.Eq(CBotTypClass) )
+ return CBotTypPointer;
+ if ( mode == 2 && m_type.Eq(CBotTypClass) )
+ return CBotTypIntrinsic;
+ return m_type.GivType();
+}
+
+void CBotVar::SetType(CBotTypResult& type)
+{
+ m_type = type;
+}
+
+
+int CBotVar::GivInit()
+{
+ if ( m_type.Eq(CBotTypClass) ) return IS_DEF; // always set!
+
+ return m_binit;
+}
+
+void CBotVar::SetInit(int bInit)
+{
+ m_binit = bInit;
+ if ( bInit == 2 ) m_binit = IS_DEF; // cas spécial
+
+ if ( m_type.Eq(CBotTypPointer) && bInit == 2 )
+ {
+ CBotVarClass* instance = GivPointer();
+ if ( instance == NULL )
+ {
+ instance = new CBotVarClass(NULL, m_type);
+// instance->SetClass(((CBotVarPointer*)this)->m_pClass);
+ SetPointer(instance);
+ }
+ instance->SetInit(1);
+ }
+
+ if ( m_type.Eq(CBotTypClass) || m_type.Eq(CBotTypIntrinsic) )
+ {
+ CBotVar* p = ((CBotVarClass*)this)->m_pVar;
+ while( p != NULL )
+ {
+ p->SetInit( bInit );
+ p->m_pMyThis = (CBotVarClass*)this;
+ p = p->GivNext();
+ }
+ }
+}
+
+CBotString CBotVar::GivName()
+{
+ return m_token->GivString();
+}
+
+void CBotVar::SetName(const char* name)
+{
+ m_token->SetString(name);
+}
+
+CBotToken* CBotVar::GivToken()
+{
+ return m_token;
+}
+
+CBotVar* CBotVar::GivItem(const char* name)
+{
+ ASM_TRAP();
+ return NULL;
+}
+
+CBotVar* CBotVar::GivItemRef(int nIdent)
+{
+ ASM_TRAP();
+ return NULL;
+}
+
+CBotVar* CBotVar::GivItemList()
+{
+ ASM_TRAP();
+ return NULL;
+}
+
+CBotVar* CBotVar::GivItem(int row, bool bGrow)
+{
+ ASM_TRAP();
+ return NULL;
+}
+
+// check if a variable belongs to a given class
+bool CBotVar::IsElemOfClass(const char* name)
+{
+ CBotClass* pc = NULL;
+
+ if ( m_type.Eq(CBotTypPointer) )
+ {
+ pc = ((CBotVarPointer*)this)->m_pClass;
+ }
+ if ( m_type.Eq(CBotTypClass) )
+ {
+ pc = ((CBotVarClass*)this)->m_pClass;
+ }
+
+ while ( pc != NULL )
+ {
+ if ( pc->GivName() == name ) return true;
+ pc = pc->GivParent();
+ }
+
+ return false;
+}
+
+
+CBotVar* CBotVar::GivStaticVar()
+{
+ // makes the pointer to the variable if it is static
+ if ( m_bStatic == 0 || m_pMyThis == NULL ) return this;
+
+ CBotClass* pClass = m_pMyThis->GivClass();
+ return pClass->GivItem( m_token->GivString() );
+}
+
+
+CBotVar* CBotVar::GivNext()
+{
+ return m_next;
+}
+
+void CBotVar::AddNext(CBotVar* pVar)
+{
+ CBotVar* p = this;
+ while (p->m_next != NULL) p = p->m_next;
+
+ p->m_next = pVar;
+}
+
+void CBotVar::SetVal(CBotVar* var)
+{
+ switch (/*var->*/GivType())
+ {
+ case CBotTypBoolean:
+ SetValInt(var->GivValInt());
+ break;
+ case CBotTypInt:
+ SetValInt(var->GivValInt(), ((CBotVarInt*)var)->m_defnum);
+ break;
+ case CBotTypFloat:
+ SetValFloat(var->GivValFloat());
+ break;
+ case CBotTypString:
+ SetValString(var->GivValString());
+ break;
+ case CBotTypPointer:
+ case CBotTypNullPointer:
+ case CBotTypArrayPointer:
+ SetPointer(var->GivPointer());
+ break;
+ case CBotTypClass:
+ {
+ delete ((CBotVarClass*)this)->m_pVar;
+ ((CBotVarClass*)this)->m_pVar = NULL;
+ Copy(var, false);
+ }
+ break;
+ default:
+ ASM_TRAP();
+ }
+
+ m_binit = var->m_binit; // copie l'état nan s'il y a
+}
+
+void CBotVar::SetStatic(bool bStatic)
+{
+ m_bStatic = bStatic;
+}
+
+void CBotVar::SetPrivate(int mPrivate)
+{
+ m_mPrivate = mPrivate;
+}
+
+bool CBotVar::IsStatic()
+{
+ return m_bStatic;
+}
+
+bool CBotVar::IsPrivate(int mode)
+{
+ return m_mPrivate >= mode;
+}
+
+int CBotVar::GivPrivate()
+{
+ return m_mPrivate;
+}
+
+
+void CBotVar::SetPointer(CBotVar* pVarClass)
+{
+ ASM_TRAP();
+}
+
+CBotVarClass* CBotVar::GivPointer()
+{
+ ASM_TRAP();
+ return NULL;
+}
+
+// All these functions must be defined in the subclasses
+// derived from class CBotVar
+
+int CBotVar::GivValInt()
+{
+ ASM_TRAP();
+ return 0;
+}
+
+float CBotVar::GivValFloat()
+{
+ ASM_TRAP();
+ return 0;
+}
+
+void CBotVar::SetValInt(int c, const char* s)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::SetValFloat(float c)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Mul(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Power(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+int CBotVar::Div(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return 0;
+}
+
+int CBotVar::Modulo(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return 0;
+}
+
+void CBotVar::Add(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Sub(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+bool CBotVar::Lo(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return false;
+}
+
+bool CBotVar::Hi(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return false;
+}
+
+bool CBotVar::Ls(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return false;
+}
+
+bool CBotVar::Hs(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return false;
+}
+
+bool CBotVar::Eq(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return false;
+}
+
+bool CBotVar::Ne(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+ return false;
+}
+
+void CBotVar::And(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Or(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::XOr(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::ASR(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::SR(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::SL(CBotVar* left, CBotVar* right)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Neg()
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Not()
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Inc()
+{
+ ASM_TRAP();
+}
+void CBotVar::Dec()
+{
+ ASM_TRAP();
+}
+
+void CBotVar::Copy(CBotVar* pSrc, bool bName)
+{
+ ASM_TRAP();
+}
+
+void CBotVar::SetValString(const char* p)
+{
+ ASM_TRAP();
+}
+
+CBotString CBotVar::GivValString()
+{
+ ASM_TRAP();
+ return CBotString();
+}
+
+void CBotVar::SetClass(CBotClass* pClass)
+{
+ ASM_TRAP();
+}
+
+CBotClass* CBotVar::GivClass()
+{
+ ASM_TRAP();
+ return NULL;
+}
+
+/*
+void CBotVar::SetIndirection(CBotVar* pVar)
+{
+ // nop, only CBotVarPointer::SetIndirection
+}
+*/
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+// copy a variable in to another
+void CBotVarInt::Copy(CBotVar* pSrc, bool bName)
+{
+ CBotVarInt* p = (CBotVarInt*)pSrc;
+
+ if ( bName) *m_token = *p->m_token;
+ m_type = p->m_type;
+ m_val = p->m_val;
+ m_binit = p->m_binit;
+ m_pMyThis = NULL;
+ m_pUserPtr = p->m_pUserPtr;
+
+ // identificator is the same (by défaut)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+
+ m_defnum = p->m_defnum;
+}
+
+
+
+
+void CBotVarInt::SetValInt(int val, const char* defnum)
+{
+ m_val = val;
+ m_binit = true;
+ m_defnum = defnum;
+}
+
+
+
+void CBotVarInt::SetValFloat(float val)
+{
+ m_val = (int)val;
+ m_binit = true;
+}
+
+int CBotVarInt::GivValInt()
+{
+ return m_val;
+}
+
+float CBotVarInt::GivValFloat()
+{
+ return (float)m_val;
+}
+
+CBotString CBotVarInt::GivValString()
+{
+ if ( !m_defnum.IsEmpty() ) return m_defnum;
+
+ CBotString res;
+
+ if ( !m_binit )
+ {
+ res.LoadString(TX_UNDEF);
+ return res;
+ }
+ if ( m_binit == IS_NAN )
+ {
+ res.LoadString(TX_NAN);
+ return res;
+ }
+
+ char buffer[300];
+ sprintf(buffer, "%d", m_val);
+ res = buffer;
+
+ return res;
+}
+
+
+void CBotVarInt::Mul(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() * right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::Power(CBotVar* left, CBotVar* right)
+{
+ m_val = (int) pow( (double) left->GivValInt() , (double) right->GivValInt() );
+ m_binit = true;
+}
+
+int CBotVarInt::Div(CBotVar* left, CBotVar* right)
+{
+ int r = right->GivValInt();
+ if ( r != 0 )
+ {
+ m_val = left->GivValInt() / r;
+ m_binit = true;
+ }
+ return ( r == 0 ? TX_DIVZERO : 0 );
+}
+
+int CBotVarInt::Modulo(CBotVar* left, CBotVar* right)
+{
+ int r = right->GivValInt();
+ if ( r != 0 )
+ {
+ m_val = left->GivValInt() % r;
+ m_binit = true;
+ }
+ return ( r == 0 ? TX_DIVZERO : 0 );
+}
+
+void CBotVarInt::Add(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() + right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::Sub(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() - right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::XOr(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() ^ right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::And(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() & right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::Or(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() | right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::SL(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() << right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::ASR(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() >> right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarInt::SR(CBotVar* left, CBotVar* right)
+{
+ int source = left->GivValInt();
+ int shift = right->GivValInt();
+ if (shift>=1) source &= 0x7fffffff;
+ m_val = source >> shift;
+ m_binit = true;
+}
+
+void CBotVarInt::Neg()
+{
+ m_val = -m_val;
+}
+
+void CBotVarInt::Not()
+{
+ m_val = ~m_val;
+}
+
+void CBotVarInt::Inc()
+{
+ m_val++;
+ m_defnum.Empty();
+}
+
+void CBotVarInt::Dec()
+{
+ m_val--;
+ m_defnum.Empty();
+}
+
+bool CBotVarInt::Lo(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() < right->GivValInt();
+}
+
+bool CBotVarInt::Hi(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() > right->GivValInt();
+}
+
+bool CBotVarInt::Ls(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() <= right->GivValInt();
+}
+
+bool CBotVarInt::Hs(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() >= right->GivValInt();
+}
+
+bool CBotVarInt::Eq(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() == right->GivValInt();
+}
+
+bool CBotVarInt::Ne(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() != right->GivValInt();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+// copy a variable into another
+void CBotVarFloat::Copy(CBotVar* pSrc, bool bName)
+{
+ CBotVarFloat* p = (CBotVarFloat*)pSrc;
+
+ if (bName) *m_token = *p->m_token;
+ m_type = p->m_type;
+ m_val = p->m_val;
+ m_binit = p->m_binit;
+//- m_bStatic = p->m_bStatic;
+ m_next = NULL;
+ m_pMyThis = NULL;//p->m_pMyThis;
+ m_pUserPtr = p->m_pUserPtr;
+
+ // keeps indentificator the same (by default)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+}
+
+
+
+
+void CBotVarFloat::SetValInt(int val, const char* s)
+{
+ m_val = (float)val;
+ m_binit = true;
+}
+
+void CBotVarFloat::SetValFloat(float val)
+{
+ m_val = val;
+ m_binit = true;
+}
+
+int CBotVarFloat::GivValInt()
+{
+ return (int)m_val;
+}
+
+float CBotVarFloat::GivValFloat()
+{
+ return m_val;
+}
+
+CBotString CBotVarFloat::GivValString()
+{
+ CBotString res;
+
+ if ( !m_binit )
+ {
+ res.LoadString(TX_UNDEF);
+ return res;
+ }
+ if ( m_binit == IS_NAN )
+ {
+ res.LoadString(TX_NAN);
+ return res;
+ }
+
+ char buffer[300];
+ sprintf(buffer, "%.2f", m_val);
+ res = buffer;
+
+ return res;
+}
+
+
+void CBotVarFloat::Mul(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValFloat() * right->GivValFloat();
+ m_binit = true;
+}
+
+void CBotVarFloat::Power(CBotVar* left, CBotVar* right)
+{
+ m_val = (float)pow( left->GivValFloat() , right->GivValFloat() );
+ m_binit = true;
+}
+
+int CBotVarFloat::Div(CBotVar* left, CBotVar* right)
+{
+ float r = right->GivValFloat();
+ if ( r != 0 )
+ {
+ m_val = left->GivValFloat() / r;
+ m_binit = true;
+ }
+ return ( r == 0 ? TX_DIVZERO : 0 );
+}
+
+int CBotVarFloat::Modulo(CBotVar* left, CBotVar* right)
+{
+ float r = right->GivValFloat();
+ if ( r != 0 )
+ {
+ m_val = (float)fmod( left->GivValFloat() , r );
+ m_binit = true;
+ }
+ return ( r == 0 ? TX_DIVZERO : 0 );
+}
+
+void CBotVarFloat::Add(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValFloat() + right->GivValFloat();
+ m_binit = true;
+}
+
+void CBotVarFloat::Sub(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValFloat() - right->GivValFloat();
+ m_binit = true;
+}
+
+void CBotVarFloat::Neg()
+{
+ m_val = -m_val;
+}
+
+void CBotVarFloat::Inc()
+{
+ m_val++;
+}
+
+void CBotVarFloat::Dec()
+{
+ m_val--;
+}
+
+
+bool CBotVarFloat::Lo(CBotVar* left, CBotVar* right)
+{
+ return left->GivValFloat() < right->GivValFloat();
+}
+
+bool CBotVarFloat::Hi(CBotVar* left, CBotVar* right)
+{
+ return left->GivValFloat() > right->GivValFloat();
+}
+
+bool CBotVarFloat::Ls(CBotVar* left, CBotVar* right)
+{
+ return left->GivValFloat() <= right->GivValFloat();
+}
+
+bool CBotVarFloat::Hs(CBotVar* left, CBotVar* right)
+{
+ return left->GivValFloat() >= right->GivValFloat();
+}
+
+bool CBotVarFloat::Eq(CBotVar* left, CBotVar* right)
+{
+ return left->GivValFloat() == right->GivValFloat();
+}
+
+bool CBotVarFloat::Ne(CBotVar* left, CBotVar* right)
+{
+ return left->GivValFloat() != right->GivValFloat();
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+// copy a variable into another
+void CBotVarBoolean::Copy(CBotVar* pSrc, bool bName)
+{
+ CBotVarBoolean* p = (CBotVarBoolean*)pSrc;
+
+ if (bName) *m_token = *p->m_token;
+ m_type = p->m_type;
+ m_val = p->m_val;
+ m_binit = p->m_binit;
+//- m_bStatic = p->m_bStatic;
+ m_next = NULL;
+ m_pMyThis = NULL;//p->m_pMyThis;
+ m_pUserPtr = p->m_pUserPtr;
+
+ // keeps indentificator the same (by default)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+}
+
+
+
+
+void CBotVarBoolean::SetValInt(int val, const char* s)
+{
+ m_val = (bool)val;
+ m_binit = true;
+}
+
+void CBotVarBoolean::SetValFloat(float val)
+{
+ m_val = (bool)val;
+ m_binit = true;
+}
+
+int CBotVarBoolean::GivValInt()
+{
+ return m_val;
+}
+
+float CBotVarBoolean::GivValFloat()
+{
+ return (float)m_val;
+}
+
+CBotString CBotVarBoolean::GivValString()
+{
+ CBotString ret;
+
+ CBotString res;
+
+ if ( !m_binit )
+ {
+ res.LoadString(TX_UNDEF);
+ return res;
+ }
+ if ( m_binit == IS_NAN )
+ {
+ res.LoadString(TX_NAN);
+ return res;
+ }
+
+ ret.LoadString( m_val > 0 ? ID_TRUE : ID_FALSE );
+ return ret;
+}
+
+void CBotVarBoolean::And(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() && right->GivValInt();
+ m_binit = true;
+}
+void CBotVarBoolean::Or(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() || right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarBoolean::XOr(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValInt() ^ right->GivValInt();
+ m_binit = true;
+}
+
+void CBotVarBoolean::Not()
+{
+ m_val = m_val ? false : true ;
+}
+
+bool CBotVarBoolean::Eq(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() == right->GivValInt();
+}
+
+bool CBotVarBoolean::Ne(CBotVar* left, CBotVar* right)
+{
+ return left->GivValInt() != right->GivValInt();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+// copy a variable into another
+void CBotVarString::Copy(CBotVar* pSrc, bool bName)
+{
+ CBotVarString* p = (CBotVarString*)pSrc;
+
+ if (bName) *m_token = *p->m_token;
+ m_type = p->m_type;
+ m_val = p->m_val;
+ m_binit = p->m_binit;
+//- m_bStatic = p->m_bStatic;
+ m_next = NULL;
+ m_pMyThis = NULL;//p->m_pMyThis;
+ m_pUserPtr = p->m_pUserPtr;
+
+ // keeps indentificator the same (by default)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+}
+
+
+void CBotVarString::SetValString(const char* p)
+{
+ m_val = p;
+ m_binit = true;
+}
+
+CBotString CBotVarString::GivValString()
+{
+ if ( !m_binit )
+ {
+ CBotString res;
+ res.LoadString(TX_UNDEF);
+ return res;
+ }
+ if ( m_binit == IS_NAN )
+ {
+ CBotString res;
+ res.LoadString(TX_NAN);
+ return res;
+ }
+
+ return m_val;
+}
+
+
+void CBotVarString::Add(CBotVar* left, CBotVar* right)
+{
+ m_val = left->GivValString() + right->GivValString();
+ m_binit = true;
+}
+
+bool CBotVarString::Eq(CBotVar* left, CBotVar* right)
+{
+ return (left->GivValString() == right->GivValString());
+}
+
+bool CBotVarString::Ne(CBotVar* left, CBotVar* right)
+{
+ return (left->GivValString() != right->GivValString());
+}
+
+
+bool CBotVarString::Lo(CBotVar* left, CBotVar* right)
+{
+ return (left->GivValString() == right->GivValString());
+}
+
+bool CBotVarString::Hi(CBotVar* left, CBotVar* right)
+{
+ return (left->GivValString() == right->GivValString());
+}
+
+bool CBotVarString::Ls(CBotVar* left, CBotVar* right)
+{
+ return (left->GivValString() == right->GivValString());
+}
+
+bool CBotVarString::Hs(CBotVar* left, CBotVar* right)
+{
+ return (left->GivValString() == right->GivValString());
+}
+
+
+////////////////////////////////////////////////////////////////
+
+// copy a variable into another
+void CBotVarClass::Copy(CBotVar* pSrc, bool bName)
+{
+ pSrc = pSrc->GivPointer(); // if source given by a pointer
+
+ if ( pSrc->GivType() != CBotTypClass )
+ ASM_TRAP();
+
+ CBotVarClass* p = (CBotVarClass*)pSrc;
+
+ if (bName) *m_token = *p->m_token;
+
+ m_type = p->m_type;
+ m_binit = p->m_binit;
+//- m_bStatic = p->m_bStatic;
+ m_pClass = p->m_pClass;
+ if ( p->m_pParent )
+ {
+ ASM_TRAP(); "que faire du pParent";
+ }
+
+// m_next = NULL;
+ m_pUserPtr = p->m_pUserPtr;
+ m_pMyThis = NULL;//p->m_pMyThis;
+ m_ItemIdent = p->m_ItemIdent;
+
+ // keeps indentificator the same (by default)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+
+ delete m_pVar;
+ m_pVar = NULL;
+
+ CBotVar* pv = p->m_pVar;
+ while( pv != NULL )
+ {
+ CBotVar* pn = CBotVar::Create(pv);
+ pn->Copy( pv );
+ if ( m_pVar == NULL ) m_pVar = pn;
+ else m_pVar->AddNext(pn);
+
+ pv = pv->GivNext();
+ }
+}
+
+void CBotVarClass::SetItemList(CBotVar* pVar)
+{
+ delete m_pVar;
+ m_pVar = pVar; // replaces the existing pointer
+}
+
+void CBotVarClass::SetIdent(long n)
+{
+ m_ItemIdent = n;
+}
+
+void CBotVarClass::SetClass(CBotClass* pClass)//, int &nIdent)
+{
+ m_type.m_pClass = pClass;
+
+ if ( m_pClass == pClass ) return;
+
+ m_pClass = pClass;
+
+ // initializes the variables associated with this class
+ delete m_pVar;
+ m_pVar = NULL;
+
+ if (pClass == NULL) return;
+
+ CBotVar* pv = pClass->GivVar(); // first on a list
+ while ( pv != NULL )
+ {
+ // seeks the maximum dimensions of the table
+ CBotInstr* p = pv->m_LimExpr; // the different formulas
+ if ( p != NULL )
+ {
+ CBotStack* pile = CBotStack::FirstStack(); // an independent stack
+ int n = 0;
+ int max[100];
+
+ while (p != NULL)
+ {
+ while( pile->IsOk() && !p->Execute(pile) ) ; // calculate size without interruptions
+ CBotVar* v = pile->GivVar(); // result
+ max[n] = v->GivValInt(); // value
+ n++;
+ p = p->GivNext3();
+ }
+ while (n<100) max[n++] = 0;
+
+ pv->m_type.SetArray( max ); // stores the limitations
+ pile->Delete();
+ }
+
+ CBotVar* pn = CBotVar::Create( pv ); // a copy
+ pn->SetStatic(pv->IsStatic());
+ pn->SetPrivate(pv->GivPrivate());
+
+ if ( pv->m_InitExpr != NULL ) // expression for initialization?
+ {
+#if STACKMEM
+ CBotStack* pile = CBotStack::FirstStack(); // an independent stack
+
+ while(pile->IsOk() && !pv->m_InitExpr->Execute(pile, pn)); // evaluates the expression without timer
+
+ pile->Delete();
+#else
+ CBotStack* pile = new CBotStack(NULL); // an independent stack
+ while(!pv->m_InitExpr->Execute(pile)); // evaluates the expression without timer
+ pn->SetVal( pile->GivVar() ) ;
+ delete pile;
+#endif
+ }
+
+// pn->SetUniqNum(CBotVar::NextUniqNum()); // enumerate elements
+ pn->SetUniqNum(pv->GivUniqNum()); //++nIdent
+ pn->m_pMyThis = this;
+
+ if ( m_pVar == NULL) m_pVar = pn;
+ else m_pVar->AddNext( pn );
+ pv = pv->GivNext();
+ }
+}
+
+CBotClass* CBotVarClass::GivClass()
+{
+ return m_pClass;
+}
+
+
+void CBotVarClass::Maj(void* pUser, bool bContinu)
+{
+/* if (!bContinu && m_pMyThis != NULL)
+ m_pMyThis->Maj(pUser, true);*/
+
+ // an update routine exist?
+
+ if ( m_pClass->m_rMaj == NULL ) return;
+
+ // retrieves the user pointer according to the class
+ // or according to the parameter passed to CBotProgram::Run()
+
+ if ( m_pUserPtr != NULL) pUser = m_pUserPtr;
+ if ( pUser == OBJECTDELETED ||
+ pUser == OBJECTCREATED ) return;
+ m_pClass->m_rMaj( this, pUser );
+}
+
+CBotVar* CBotVarClass::GivItem(const char* name)
+{
+ CBotVar* p = m_pVar;
+
+ while ( p != NULL )
+ {
+ if ( p->GivName() == name ) return p;
+ p = p->GivNext();
+ }
+
+ if ( m_pParent != NULL ) return m_pParent->GivItem(name);
+ return NULL;
+}
+
+CBotVar* CBotVarClass::GivItemRef(int nIdent)
+{
+ CBotVar* p = m_pVar;
+
+ while ( p != NULL )
+ {
+ if ( p->GivUniqNum() == nIdent ) return p;
+ p = p->GivNext();
+ }
+
+ if ( m_pParent != NULL ) return m_pParent->GivItemRef(nIdent);
+ return NULL;
+}
+
+// for the management of an array
+// bExtend can enlarge the table, but not beyond the threshold size of SetArray ()
+
+CBotVar* CBotVarClass::GivItem(int n, bool bExtend)
+{
+ CBotVar* p = m_pVar;
+
+ if ( n < 0 ) return NULL;
+ if ( n > MAXARRAYSIZE ) return NULL;
+
+ if ( m_type.GivLimite() >= 0 && n >= m_type.GivLimite() ) return NULL;
+
+ if ( p == NULL && bExtend )
+ {
+ p = CBotVar::Create("", m_type.GivTypElem());
+ m_pVar = p;
+ }
+
+ if ( n == 0 ) return p;
+
+ while ( n-- > 0 )
+ {
+ if ( p->m_next == NULL )
+ {
+ if ( bExtend ) p->m_next = CBotVar::Create("", m_type.GivTypElem());
+ if ( p->m_next == NULL ) return NULL;
+ }
+ p = p->m_next;
+ }
+
+ return p;
+}
+
+CBotVar* CBotVarClass::GivItemList()
+{
+ return m_pVar;
+}
+
+
+CBotString CBotVarClass::GivValString()
+{
+// if ( m_Indirect != NULL) return m_Indirect->GivValString();
+
+ CBotString res;
+
+ if ( m_pClass != NULL ) // not used for an array
+ {
+ res = m_pClass->GivName() + CBotString("( ");
+
+ CBotVarClass* my = this;
+ while ( my != NULL )
+ {
+ CBotVar* pv = my->m_pVar;
+ while ( pv != NULL )
+ {
+ res += pv->GivName() + CBotString("=");
+
+ if ( pv->IsStatic() )
+ {
+ CBotVar* pvv = my->m_pClass->GivItem(pv->GivName());
+ res += pvv->GivValString();
+ }
+ else
+ {
+ res += pv->GivValString();
+ }
+ pv = pv->GivNext();
+ if ( pv != NULL ) res += ", ";
+ }
+ my = my->m_pParent;
+ if ( my != NULL )
+ {
+ res += ") extends ";
+ res += my->m_pClass->GivName();
+ res += " (";
+ }
+ }
+ }
+ else
+ {
+ res = "( ";
+
+ CBotVar* pv = m_pVar;
+ while ( pv != NULL )
+ {
+ res += pv->GivValString();
+ if ( pv->GivNext() != NULL ) res += ", ";
+ pv = pv->GivNext();
+ }
+ }
+
+ res += " )";
+ return res;
+}
+
+void CBotVarClass::IncrementUse()
+{
+ m_CptUse++;
+}
+
+void CBotVarClass::DecrementUse()
+{
+ m_CptUse--;
+ if ( m_CptUse == 0 )
+ {
+ // if there is one, call the destructor
+ // but only if a constructor had been called.
+ if ( m_bConstructor )
+ {
+ m_CptUse++; // does not return to the destructor
+
+ // m_error is static in the stack
+ // saves the value for return
+ int err, start, end;
+ CBotStack* pile = NULL;
+ err = pile->GivError(start,end); // stack == NULL it does not bother!
+
+ pile = CBotStack::FirstStack(); // clears the error
+ CBotVar* ppVars[1];
+ ppVars[0] = NULL;
+
+ CBotVar* pThis = CBotVar::Create("this", CBotTypNullPointer);
+ pThis->SetPointer(this);
+ CBotVar* pResult = NULL;
+
+ CBotString nom = "~" + m_pClass->GivName();
+ long ident = 0;
+
+ while ( pile->IsOk() && !m_pClass->ExecuteMethode(ident, nom, pThis, ppVars, pResult, pile, NULL)) ; // waits for the end
+
+ pile->ResetError(err, start,end);
+
+ pile->Delete();
+ delete pThis;
+ m_CptUse--;
+ }
+
+ delete this; // self-destructs!
+ }
+}
+
+CBotVarClass* CBotVarClass::GivPointer()
+{
+ return this;
+}
+
+
+// makes an instance according to its unique number
+
+CBotVarClass* CBotVarClass::Find(long id)
+{
+ CBotVarClass* p = m_ExClass;
+
+ while ( p != NULL )
+ {
+ if ( p->m_ItemIdent == id ) return p;
+ p = p->m_ExNext;
+ }
+
+ return NULL;
+}
+
+bool CBotVarClass::Eq(CBotVar* left, CBotVar* right)
+{
+ CBotVar* l = left->GivItemList();
+ CBotVar* r = right->GivItemList();
+
+ while ( l != NULL && r != NULL )
+ {
+ if ( l->Ne(l, r) ) return false;
+ l = l->GivNext();
+ r = r->GivNext();
+ }
+
+ // should always arrived simultaneously at the end (same classes)
+ return l == r;
+}
+
+bool CBotVarClass::Ne(CBotVar* left, CBotVar* right)
+{
+ CBotVar* l = left->GivItemList();
+ CBotVar* r = right->GivItemList();
+
+ while ( l != NULL && r != NULL )
+ {
+ if ( l->Ne(l, r) ) return true;
+ l = l->GivNext();
+ r = r->GivNext();
+ }
+
+ // should always arrived simultaneously at the end (same classes)
+ return l != r;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// management of arrays
+
+CBotVarArray::CBotVarArray(const CBotToken* name, CBotTypResult& type )
+{
+ if ( !type.Eq(CBotTypArrayPointer) &&
+ !type.Eq(CBotTypArrayBody)) ASM_TRAP();
+
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+
+ m_type = type;
+ m_type.SetType(CBotTypArrayPointer);
+ m_binit = false;
+
+ m_pInstance = NULL; // the list of the array elements
+}
+
+CBotVarArray::~CBotVarArray()
+{
+ if ( m_pInstance != NULL ) m_pInstance->DecrementUse(); // the lowest reference
+}
+
+// copy a variable into another
+void CBotVarArray::Copy(CBotVar* pSrc, bool bName)
+{
+ if ( pSrc->GivType() != CBotTypArrayPointer )
+ ASM_TRAP();
+
+ CBotVarArray* p = (CBotVarArray*)pSrc;
+
+ if ( bName) *m_token = *p->m_token;
+ m_type = p->m_type;
+ m_pInstance = p->GivPointer();
+
+ if ( m_pInstance != NULL )
+ m_pInstance->IncrementUse(); // a reference increase
+
+ m_binit = p->m_binit;
+//- m_bStatic = p->m_bStatic;
+ m_pMyThis = NULL;//p->m_pMyThis;
+ m_pUserPtr = p->m_pUserPtr;
+
+ // keeps indentificator the same (by default)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+}
+
+void CBotVarArray::SetPointer(CBotVar* pVarClass)
+{
+ m_binit = true; // init, even on a null pointer
+
+ if ( m_pInstance == pVarClass) return; // Special, not decrement and reincrement
+ // because the decrement can destroy the object
+
+ if ( pVarClass != NULL )
+ {
+ if ( pVarClass->GivType() == CBotTypArrayPointer )
+ pVarClass = pVarClass->GivPointer(); // the real pointer to the object
+
+ if ( !pVarClass->m_type.Eq(CBotTypClass) &&
+ !pVarClass->m_type.Eq(CBotTypArrayBody))
+ ASM_TRAP();
+
+ ((CBotVarClass*)pVarClass)->IncrementUse(); // incement the reference
+ }
+
+ if ( m_pInstance != NULL ) m_pInstance->DecrementUse();
+ m_pInstance = (CBotVarClass*)pVarClass;
+}
+
+
+CBotVarClass* CBotVarArray::GivPointer()
+{
+ if ( m_pInstance == NULL ) return NULL;
+ return m_pInstance->GivPointer();
+}
+
+CBotVar* CBotVarArray::GivItem(int n, bool bExtend)
+{
+ if ( m_pInstance == NULL )
+ {
+ if ( !bExtend ) return NULL;
+ // creates an instance of the table
+
+ CBotVarClass* instance = new CBotVarClass(NULL, m_type);
+ SetPointer( instance );
+ }
+ return m_pInstance->GivItem(n, bExtend);
+}
+
+CBotVar* CBotVarArray::GivItemList()
+{
+ if ( m_pInstance == NULL) return NULL;
+ return m_pInstance->GivItemList();
+}
+
+CBotString CBotVarArray::GivValString()
+{
+ if ( m_pInstance == NULL ) return ( CBotString( "Null pointer" ) ) ;
+ return m_pInstance->GivValString();
+}
+
+bool CBotVarArray::Save1State(FILE* pf)
+{
+ if ( !WriteType(pf, m_type) ) return false;
+ return SaveVar(pf, m_pInstance); // saves the instance that manages the table
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// gestion des pointeurs à une instance donnée
+// TODO management of pointers to a given instance
+
+CBotVarPointer::CBotVarPointer(const CBotToken* name, CBotTypResult& type )
+{
+ if ( !type.Eq(CBotTypPointer) &&
+ !type.Eq(CBotTypNullPointer) &&
+ !type.Eq(CBotTypClass) && // for convenience accepts Class and Intrinsic
+ !type.Eq(CBotTypIntrinsic) ) ASM_TRAP();
+
+ m_token = new CBotToken(name);
+ m_next = NULL;
+ m_pMyThis = NULL;
+ m_pUserPtr = NULL;
+
+ m_type = type;
+ if ( !type.Eq(CBotTypNullPointer) )
+ m_type.SetType(CBotTypPointer); // anyway, this is a pointer
+ m_binit = false;
+ m_pClass = NULL;
+ m_pVarClass = NULL; // will be defined by a SetPointer()
+
+ SetClass(type.GivClass() );
+}
+
+CBotVarPointer::~CBotVarPointer()
+{
+ if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse(); // decrement reference
+}
+
+
+void CBotVarPointer::Maj(void* pUser, bool bContinu)
+{
+/* if ( !bContinu && m_pMyThis != NULL )
+ m_pMyThis->Maj(pUser, false);*/
+
+ if ( m_pVarClass != NULL) m_pVarClass->Maj(pUser, false);
+}
+
+CBotVar* CBotVarPointer::GivItem(const char* name)
+{
+ if ( m_pVarClass == NULL) // no existing instance?
+ return m_pClass->GivItem(name); // makes the pointer in the class itself
+
+ return m_pVarClass->GivItem(name);
+}
+
+CBotVar* CBotVarPointer::GivItemRef(int nIdent)
+{
+ if ( m_pVarClass == NULL) // no existing instance?
+ return m_pClass->GivItemRef(nIdent);// makes the pointer to the class itself
+
+ return m_pVarClass->GivItemRef(nIdent);
+}
+
+CBotVar* CBotVarPointer::GivItemList()
+{
+ if ( m_pVarClass == NULL) return NULL;
+ return m_pVarClass->GivItemList();
+}
+
+CBotString CBotVarPointer::GivValString()
+{
+ CBotString s = "Pointer to ";
+ if ( m_pVarClass == NULL ) s = "Null pointer" ;
+ else s += m_pVarClass->GivValString();
+ return s;
+}
+
+
+void CBotVarPointer::ConstructorSet()
+{
+ if ( m_pVarClass != NULL) m_pVarClass->ConstructorSet();
+}
+
+// initializes the pointer to the instance of a class
+
+void CBotVarPointer::SetPointer(CBotVar* pVarClass)
+{
+ m_binit = true; // init, even on a null pointer
+
+ if ( m_pVarClass == pVarClass) return; // special, not decrement and reincrement
+ // because the decrement can destroy the object
+
+ if ( pVarClass != NULL )
+ {
+ if ( pVarClass->GivType() == CBotTypPointer )
+ pVarClass = pVarClass->GivPointer(); // the real pointer to the object
+
+// if ( pVarClass->GivType() != CBotTypClass )
+ if ( !pVarClass->m_type.Eq(CBotTypClass) )
+ ASM_TRAP();
+
+ ((CBotVarClass*)pVarClass)->IncrementUse(); // increment the reference
+ m_pClass = ((CBotVarClass*)pVarClass)->m_pClass;
+ m_pUserPtr = pVarClass->m_pUserPtr; // not really necessary
+ m_type = CBotTypResult(CBotTypPointer, m_pClass); // what kind of a pointer
+ }
+
+ if ( m_pVarClass != NULL ) m_pVarClass->DecrementUse();
+ m_pVarClass = (CBotVarClass*)pVarClass;
+
+}
+
+CBotVarClass* CBotVarPointer::GivPointer()
+{
+ if ( m_pVarClass == NULL ) return NULL;
+ return m_pVarClass->GivPointer();
+}
+
+void CBotVarPointer::SetIdent(long n)
+{
+ if ( m_pVarClass == NULL ) return;
+ m_pVarClass->SetIdent( n );
+}
+
+long CBotVarPointer::GivIdent()
+{
+ if ( m_pVarClass == NULL ) return 0;
+ return m_pVarClass->m_ItemIdent;
+}
+
+
+void CBotVarPointer::SetClass(CBotClass* pClass)
+{
+// int nIdent = 0;
+ m_type.m_pClass = m_pClass = pClass;
+ if ( m_pVarClass != NULL ) m_pVarClass->SetClass(pClass); //, nIdent);
+}
+
+CBotClass* CBotVarPointer::GivClass()
+{
+ if ( m_pVarClass != NULL ) return m_pVarClass->GivClass();
+
+ return m_pClass;
+}
+
+
+bool CBotVarPointer::Save1State(FILE* pf)
+{
+ if ( m_pClass )
+ {
+ if (!WriteString(pf, m_pClass->GivName())) return false; // name of the class
+ }
+ else
+ {
+ if (!WriteString(pf, "")) return false;
+ }
+
+ if (!WriteLong(pf, GivIdent())) return false; // the unique reference
+
+ // also saves the proceedings copies
+ return SaveVar(pf, GivPointer());
+}
+
+// copy a variable into another
+void CBotVarPointer::Copy(CBotVar* pSrc, bool bName)
+{
+ if ( pSrc->GivType() != CBotTypPointer &&
+ pSrc->GivType() != CBotTypNullPointer)
+ ASM_TRAP();
+
+ CBotVarPointer* p = (CBotVarPointer*)pSrc;
+
+ if ( bName) *m_token = *p->m_token;
+ m_type = p->m_type;
+// m_pVarClass = p->m_pVarClass;
+ m_pVarClass = p->GivPointer();
+
+ if ( m_pVarClass != NULL )
+ m_pVarClass->IncrementUse(); // incerement the reference
+
+ m_pClass = p->m_pClass;
+ m_binit = p->m_binit;
+//- m_bStatic = p->m_bStatic;
+ m_next = NULL;
+ m_pMyThis = NULL;//p->m_pMyThis;
+ m_pUserPtr = p->m_pUserPtr;
+
+ // keeps indentificator the same (by default)
+ if (m_ident == 0 ) m_ident = p->m_ident;
+}
+
+bool CBotVarPointer::Eq(CBotVar* left, CBotVar* right)
+{
+ CBotVarClass* l = left->GivPointer();
+ CBotVarClass* r = right->GivPointer();
+
+ if ( l == r ) return true;
+ if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return true;
+ if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return true;
+ return false;
+}
+
+bool CBotVarPointer::Ne(CBotVar* left, CBotVar* right)
+{
+ CBotVarClass* l = left->GivPointer();
+ CBotVarClass* r = right->GivPointer();
+
+ if ( l == r ) return false;
+ if ( l == NULL && r->GivUserPtr() == OBJECTDELETED ) return false;
+ if ( r == NULL && l->GivUserPtr() == OBJECTDELETED ) return false;
+ return true;
+}
+
+
+
+///////////////////////////////////////////////////////
+// management of results types
+
+
+CBotTypResult::CBotTypResult(int type)
+{
+ m_type = type;
+ m_pNext = NULL;
+ m_pClass = NULL;
+ m_limite = -1;
+}
+
+CBotTypResult::CBotTypResult(int type, const char* name)
+{
+ m_type = type;
+ m_pNext = NULL;
+ m_pClass = NULL;
+ m_limite = -1;
+
+ if ( type == CBotTypPointer ||
+ type == CBotTypClass ||
+ type == CBotTypIntrinsic )
+ {
+ m_pClass = CBotClass::Find(name);
+ if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic;
+ }
+}
+
+CBotTypResult::CBotTypResult(int type, CBotClass* pClass)
+{
+ m_type = type;
+ m_pNext = NULL;
+ m_pClass = pClass;
+ m_limite = -1;
+
+ if ( m_pClass && m_pClass->IsIntrinsic() ) m_type = CBotTypIntrinsic;
+}
+
+CBotTypResult::CBotTypResult(int type, CBotTypResult elem)
+{
+ m_type = type;
+ m_pNext = NULL;
+ m_pClass = NULL;
+ m_limite = -1;
+
+ if ( type == CBotTypArrayPointer ||
+ type == CBotTypArrayBody )
+ m_pNext = new CBotTypResult( elem );
+}
+
+CBotTypResult::CBotTypResult(const CBotTypResult& typ)
+{
+ m_type = typ.m_type;
+ m_pClass = typ.m_pClass;
+ m_pNext = NULL;
+ m_limite = typ.m_limite;
+
+ if ( typ.m_pNext )
+ m_pNext = new CBotTypResult( *typ.m_pNext );
+}
+
+CBotTypResult::CBotTypResult()
+{
+ m_type = 0;
+ m_limite = -1;
+ m_pNext = NULL;
+ m_pClass = NULL;
+}
+
+CBotTypResult::~CBotTypResult()
+{
+ delete m_pNext;
+}
+
+int CBotTypResult::GivType(int mode) const
+{
+#ifdef _DEBUG
+ if ( m_type == CBotTypPointer ||
+ m_type == CBotTypClass ||
+ m_type == CBotTypIntrinsic )
+
+ if ( m_pClass == NULL ) ASM_TRAP();
+
+
+ if ( m_type == CBotTypArrayPointer )
+ if ( m_pNext == NULL ) ASM_TRAP();
+#endif
+ if ( mode == 3 && m_type == CBotTypNullPointer ) return CBotTypPointer;
+ return m_type;
+}
+
+void CBotTypResult::SetType(int n)
+{
+ m_type = n;
+}
+
+CBotClass* CBotTypResult::GivClass() const
+{
+ return m_pClass;
+}
+
+CBotTypResult& CBotTypResult::GivTypElem() const
+{
+ return *m_pNext;
+}
+
+int CBotTypResult::GivLimite() const
+{
+ return m_limite;
+}
+
+void CBotTypResult::SetLimite(int n)
+{
+ m_limite = n;
+}
+
+void CBotTypResult::SetArray( int* max )
+{
+ m_limite = *max;
+ if (m_limite < 1) m_limite = -1;
+
+ if ( m_pNext != NULL ) // last dimension?
+ {
+ m_pNext->SetArray( max+1 );
+ }
+}
+
+
+
+bool CBotTypResult::Compare(const CBotTypResult& typ) const
+{
+ if ( m_type != typ.m_type ) return false;
+
+ if ( m_type == CBotTypArrayPointer ) return m_pNext->Compare(*typ.m_pNext);
+
+ if ( m_type == CBotTypPointer ||
+ m_type == CBotTypClass ||
+ m_type == CBotTypIntrinsic )
+ {
+ return m_pClass == typ.m_pClass;
+ }
+
+ return true;
+}
+
+bool CBotTypResult::Eq(int type) const
+{
+ return m_type == type;
+}
+
+CBotTypResult&
+ CBotTypResult::operator=(const CBotTypResult& src)
+{
+ m_type = src.m_type;
+ m_limite = src.m_limite;
+ m_pClass = src.m_pClass;
+ m_pNext = NULL;
+ if ( src.m_pNext != NULL )
+ {
+ m_pNext = new CBotTypResult(*src.m_pNext);
+ }
+ return *this;
+}
+
+
diff --git a/src/CBot/CBotWhile.cpp b/src/CBot/CBotWhile.cpp
index 124fb3d..51310a9 100644
--- a/src/CBot/CBotWhile.cpp
+++ b/src/CBot/CBotWhile.cpp
@@ -1,1427 +1,1433 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.///////////////////////////////////////////////////////////////////////
-// ce fichier défini les instructions suivantes:
-// CBotWhile "while (condition) {instructions}"
-// CBotDo "do {instructions} while (condition)"
-// CBotFor "for (init, condition, incr) {instructions}"
-// CBotSwitch "switch (val) {instructions}"
-// CBotCase "case val:"
-// CBotBreak "break", "break label", "continu", "continu label"
-// CBotTry "try {instructions}"
-// CBotCatch "catch (condition) {instructions}" ou "finally"
-// CBotThrow "throw execption"
-
-
-#include "CBot.h"
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "while"
-
-CBotWhile::CBotWhile()
-{
- m_Condition =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotWhile"; // debug
-}
-
-CBotWhile::~CBotWhile()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotWhile* inst = new CBotWhile(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_WHILE)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe
-
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (il peut être vide !
-
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "while"
-
-BOOL CBotWhile :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- while( TRUE ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return FALSE; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != TRUE )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // la condition est vrai, passe dans le second mode
-
- if (!pile->SetState(1)) return FALSE; // prêt pour la suite
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(0, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au test pour recommencer
- if (!pile->SetState(0, 0)) return FALSE;
- continue;
- }
-}
-
-void CBotWhile :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- m_Condition->RestoreState(pile, bMain);
- return;
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "repeat"
-
-CBotRepeat::CBotRepeat()
-{
- m_NbIter =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotRepeat"; // debug
-}
-
-CBotRepeat::~CBotRepeat()
-{
- delete m_NbIter; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotRepeat* inst = new CBotRepeat(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_REPEAT)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( IsOfType(p, ID_OPENPAR ) )
- {
- CBotToken* ppp = p; // conserve le ^au token (position début)
- if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) )
- {
- if ( pStk->GivType() < CBotTypLong )
- {
- if ( IsOfType(p, ID_CLOSEPAR ) )
- {
-
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- // le bloc d'instruction est ok (il peut être vide !
-
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStk->SetStartError(ppp->GivStart());
- pStk->SetError( TX_BADTYPE, p->GivStart() );
- }
- pStack->SetError(TX_ENDOF, p);
- }
- pStack->SetError(TX_OPENPAR, p->GivStart()); // manque la parenthèse
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "repeat"
-
-BOOL CBotRepeat :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- while( TRUE ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue le nombre d'itération
- if ( !m_NbIter->Execute(pile) ) return FALSE; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- int n;
- if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // met le nombre d'itération +1 dans le "state"
-
- if (!pile->SetState(n+1)) return FALSE; // prêt pour la suite
- continue; // passe à la suite
-
- case 1:
- // fin normale de la boucle
- return pj->Return(pile); // transmet le résultat et libère la pile
-
- default:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au test pour recommencer
- if (!pile->SetState(pile->GivState()-1, 0)) return FALSE;
- continue;
- }
-}
-
-void CBotRepeat :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue la condition
- m_NbIter->RestoreState(pile, bMain);
- return;
-
- case 1:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "do"
-
-CBotDo::CBotDo()
-{
- m_Condition =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotDo"; // debug
-}
-
-CBotDo::~CBotDo()
-{
- delete m_Condition; // libère la condition
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotDo* inst = new CBotDo(); // crée l'objet
-
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_DO)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
-
- // cherche un bloc d'instruction après le do
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- DecLvl();
-
- if ( pStk->IsOk() )
- {
- if (IsOfType(p, ID_WHILE))
- {
- if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
- {
- // la condition existe
- if (IsOfType(p, ID_SEP))
- {
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- pStk->SetError(TX_ENDOF, p->GivStart());
- }
- }
- pStk->SetError(TX_WHILE, p->GivStart());
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "do"
-
-BOOL CBotDo :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this); // ajoute un élément à la pile
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- while( TRUE ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(1, m_label)) continue; // si continue, repasse au test
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- if (!pile->SetState(1)) return FALSE; // prêt pour la suite
-
- case 1:
- // évalue la condition
- if ( !m_Condition->Execute(pile) ) return FALSE; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != TRUE )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- // repasse au bloc d'instruction pour recommencer
- if (!pile->SetState(0, 0)) return FALSE;
- continue;
- }
-}
-
-void CBotDo :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 2 états possibles (selon reprise)
- case 0:
- // restitue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
- return;
-
- case 1:
- // restitue la condition
- m_Condition->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "for"
-
-CBotFor::CBotFor()
-{
- m_Init =
- m_Test =
- m_Incr =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotFor"; // debug
-}
-
-CBotFor::~CBotFor()
-{
- delete m_Init;
- delete m_Test;
- delete m_Incr;
- delete m_Block; // libère le bloc d'instruction
-}
-
-CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotFor* inst = new CBotFor(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if ( IsOfType( p, TokenTypVar ) &&
- IsOfType( p, ID_DOTS ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- }
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_FOR)) return NULL; // ne devrait jamais arriver
-
- if ( !IsOfType(p, ID_OPENPAR)) // manque la parenthèse ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- return NULL;
- }
-
- CBotCStack* pStk = pStack->TokenStack(pp, TRUE); // un petit bout de pile svp
-
- // compile les instructions pour initialisation
- inst->m_Init = CBotListExpression::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( !IsOfType(p, ID_SEP)) // manque le point-virgule ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
- }
- inst->m_Test = CBotBoolExpr::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( !IsOfType(p, ID_SEP)) // manque le point-virgule ?
- {
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
- }
- inst->m_Incr = CBotListExpression::Compile( p, pStk );
- if ( pStk->IsOk() )
- {
- if ( IsOfType(p, ID_CLOSEPAR)) // manque la parenthèse ?
- {
- IncLvl(inst->m_label);
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- DecLvl();
- if ( pStk->IsOk() )
- return pStack->Return(inst, pStk);;
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- }
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction "for"
-
-BOOL CBotFor :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this, TRUE); // ajoute un élément à la pile (variables locales)
- // ou le retrouve en cas de reprise
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- while( TRUE ) switch( pile->GivState() ) // exécute la boucle
- { // il y a 4 états possibles (selon reprise)
- case 0:
- // évalue l'initialisation
- if ( m_Init != NULL &&
- !m_Init->Execute(pile) ) return FALSE; // interrompu ici ?
- if (!pile->SetState(1)) return FALSE; // prêt pour la suite
-
- case 1:
- // évalue la condition
- if ( m_Test != NULL ) // pas de condition ? -> vrai !
- {
- if (!m_Test->Execute(pile) ) return FALSE; // interrompu ici ?
-
- // le résultat de la condition est sur la pile
-
- // termine s'il y a une erreur ou si la condition est fausse
- if ( !pile->IsOk() || pile->GivVal() != TRUE )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
- }
-
- // la condition est vrai, passe à la suite
- if (!pile->SetState(2)) return FALSE; // prêt pour la suite
-
- case 2:
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL &&
- !m_Block->Execute(pile) )
- {
- if (pile->IfContinue(3, m_label)) continue; // si continue, passe à l'incrémentation
- return pj->BreakReturn(pile, m_label); // transmet le résultat et libère la pile
- }
-
- // termine s'il y a une erreur
- if ( !pile->IsOk() )
- {
- return pj->Return(pile); // transmet le résultat et libère la pile
- }
-
- if (!pile->SetState(3)) return FALSE; // prêt pour la suite
-
- case 3:
- // évalue l'incrémentation
- if ( m_Incr != NULL &&
- !m_Incr->Execute(pile) ) return FALSE; // interrompu ici ?
-
- // repasse au test pour recommencer
- if (!pile->SetState(1, 0)) return FALSE; // revient au test
- continue;
- }
-}
-
-void CBotFor :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this); // ajoute un élément à la pile (variables locales)
- if ( pile == NULL ) return;
-
- switch( pile->GivState() )
- { // il y a 4 états possibles (selon reprise)
- case 0:
- // évalue l'initialisation
- if ( m_Init != NULL ) m_Init->RestoreState(pile, TRUE); // interrompu ici !
- return;
-
- case 1:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, FALSE); // définitions variables
-
- // évalue la condition
- if ( m_Test != NULL ) m_Test->RestoreState(pile, TRUE); // interrompu ici !
- return;
-
- case 2:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, FALSE); // définitions variables
-
- // évalue le bloc d'instruction associé
- if ( m_Block != NULL ) m_Block->RestoreState(pile, TRUE);
- return;
-
- case 3:
- if ( m_Init != NULL ) m_Init->RestoreState(pile, FALSE); // définitions variables
-
- // évalue l'incrémentation
- if ( m_Incr != NULL ) m_Incr->RestoreState(pile, TRUE); // interrompu ici !
- return;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////////
-// compile une liste d'expression
-// n'est utilisé que pour l'instruction for
-// dans l'intitialisation et dans l'incrémentation
-
-CBotListExpression::CBotListExpression()
-{
- m_Expr = NULL;
- name = "CBotListExpression";
-}
-
-CBotListExpression::~CBotListExpression()
-{
- delete m_Expr;
-}
-
-// cherche une déclaration de variable ou une expression
-
-static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack)
-{
- CBotInstr* i = CBotInt::Compile( p, pStack, FALSE, TRUE ); // est-ce une déclaration d'un entier ?
- if ( i== NULL ) i = CBotFloat::Compile( p, pStack, FALSE, TRUE ); // ou d'un nombre réel ?
- if ( i== NULL ) i = CBotBoolean::Compile( p, pStack, FALSE, TRUE ); // ou d'un booléen ?
- if ( i== NULL ) i = CBotIString::Compile( p, pStack, FALSE, TRUE ); // ou d'une chaîne ?
- if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compile une expression
- return i;
-}
-
-CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotListExpression* inst = new CBotListExpression();
-
- inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile la première expression de la liste
- if (pStack->IsOk())
- {
- while ( IsOfType(p, ID_COMMA) ) // plusieurs instructions ?
- {
- CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // est-ce une déclaration d'un entier ?
- inst->m_Expr->AddNext(i); // ajoute à la suite
- if ( !pStack->IsOk() )
- {
- delete inst;
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
- }
- return inst;
- }
- delete inst;
- return NULL;
-}
-
-BOOL CBotListExpression::Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack();// indispensable
- CBotInstr* p = m_Expr; // la première expression
-
- int state = pile->GivState();
- while (state-->0) p = p->GivNext(); // revient sur l'opération interrompue
-
- if ( p != NULL ) while (TRUE)
- {
- if ( !p->Execute(pile) ) return FALSE;
- p = p->GivNext();
- if ( p == NULL ) break;
- if (!pile->IncState()) return FALSE; // prêt pour la suivante
- }
- return pj->Return(pile);
-}
-
-void CBotListExpression::RestoreState(CBotStack* &pj, BOOL bMain)
-{
- CBotStack* pile = pj;
- int state = 0x7000;
-
- if ( bMain )
- {
- pile = pj->RestoreStack();
- if ( pile == NULL ) return;
- state = pile->GivState();
- }
-
- CBotInstr* p = m_Expr; // la première expression
-
- while (p != NULL && state-->0)
- {
- p->RestoreState(pile, FALSE);
- p = p->GivNext(); // revient sur l'opération interrompue
- }
-
- if ( p != NULL )
- {
- p->RestoreState(pile, bMain);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "switch"
-
-CBotSwitch::CBotSwitch()
-{
- m_Value =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotSwitch"; // debug
-}
-
-CBotSwitch::~CBotSwitch()
-{
- delete m_Value; // libère la valeur
- delete m_Block; // libère le bloc d'instruction
-}
-
-
-CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotSwitch* inst = new CBotSwitch(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_SWITCH)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- if ( IsOfType(p, ID_OPENPAR ) )
- {
- if ( NULL != (inst->m_Value = CBotExpression::Compile( p, pStk )) )
- {
- if ( pStk->GivType() < CBotTypLong )
- {
- if ( IsOfType(p, ID_CLOSEPAR ) )
- {
- if ( IsOfType(p, ID_OPBLK ) )
- {
- IncLvl();
-
- while( !IsOfType( p, ID_CLBLK ) )
- {
- if ( p->GivType() == ID_CASE || p->GivType() == ID_DEFAULT)
- {
- CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp
-
- CBotInstr* i = CBotCase::Compile( p, pStk2 );
- if (i == NULL)
- {
- delete inst;
- return pStack->Return(NULL, pStk2);
- }
- delete pStk2;
- if ( inst->m_Block == NULL ) inst->m_Block = i;
- else inst->m_Block->AddNext(i);
- continue;
- }
-
- if ( inst->m_Block == NULL )
- {
- pStk->SetError(TX_NOCASE, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
-
- CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, TRUE );
- if ( !pStk->IsOk() )
- {
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- inst->m_Block->AddNext(i);
-
- if ( p == NULL )
- {
- pStk->SetError(TX_CLOSEBLK, -1);
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- }
- DecLvl();
-
- if ( inst->m_Block == NULL )
- {
- pStk->SetError(TX_NOCASE, p->GivStart());
- delete inst;
- return pStack->Return(NULL, pStk);
- }
- // le bloc d'instruction est ok
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
- pStk->SetError( TX_OPENBLK, p->GivStart() );
- }
- pStk->SetError( TX_CLOSEPAR, p->GivStart() );
- }
- pStk->SetError( TX_BADTYPE, p->GivStart() );
- }
- }
- pStk->SetError( TX_OPENPAR, p->GivStart());
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute une instruction "switch"
-
-BOOL CBotSwitch :: Execute(CBotStack* &pj)
-{
- CBotStack* pile1 = pj->AddStack(this); // ajoute un élément à la pile
-// if ( pile1 == EOX ) return TRUE;
-
- CBotInstr* p = m_Block; // la première expression
-
- int state = pile1->GivState();
- if (state == 0)
- {
- if ( !m_Value->Execute(pile1) ) return FALSE;
- pile1->SetState(state = -1);
- }
-
- if ( pile1->IfStep() ) return FALSE;
-
- if ( state == -1 )
- {
- state = 0;
- int val = pile1->GivVal(); // résultat de la valeur
-
- CBotStack* pile2 = pile1->AddStack();
- while ( p != NULL ) // recherche le case correspondant dans la liste
- {
- state++;
- if ( p->CompCase( pile2, val ) ) break; // trouvé le case
- p = p->GivNext();
- }
- pile2->Delete();
-
- if ( p == NULL ) return pj->Return(pile1); // terminé si plus rien
-
- if ( !pile1->SetState(state) ) return FALSE;
- }
-
- p = m_Block; // revient au début
- while (state-->0) p = p->GivNext(); // avance dans la liste
-
- while( p != NULL )
- {
- if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1);
- if ( !pile1->IncState() ) return FALSE;
- p = p->GivNext();
- }
- return pj->Return(pile1);
-}
-
-void CBotSwitch :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile1 = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile1 == NULL ) return;
-
- CBotInstr* p = m_Block; // la première expression
-
- int state = pile1->GivState();
- if (state == 0)
- {
- m_Value->RestoreState(pile1, bMain);
- return;
- }
-
- if ( state == -1 )
- {
- return;
- }
-
-// p = m_Block; // revient au début
- while ( p != NULL && state-- > 0 )
- {
- p->RestoreState(pile1, FALSE);
- p = p->GivNext(); // avance dans la liste
- }
-
- if( p != NULL )
- {
- p->RestoreState(pile1, TRUE);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "case"
-// on est forcément dans un bloc d'instruction "switch"
-
-CBotCase::CBotCase()
-{
- m_Value = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotCase"; // debug
-}
-
-CBotCase::~CBotCase()
-{
- delete m_Value; // libère la valeur
-}
-
-
-CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCase* inst = new CBotCase(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return NULL; // ne devrait jamais arriver
-
- if ( pp->GivType() == ID_CASE )
- {
- pp = p;
- inst->m_Value = CBotExprNum::Compile(p, pStack);
- if ( inst->m_Value == NULL )
- {
- pStack->SetError( TX_BADNUM, pp );
- delete inst;
- return NULL;
- }
- }
- if ( !IsOfType( p, ID_DOTS ))
- {
- pStack->SetError( TX_MISDOTS, p->GivStart() );
- delete inst;
- return NULL;
- }
-
- return inst;
-}
-
-// exécution de l'instruction "case"
-
-BOOL CBotCase::Execute(CBotStack* &pj)
-{
- return TRUE; // l'instruction "case" ne fait rien !
-}
-
-void CBotCase::RestoreState(CBotStack* &pj, BOOL bMain)
-{
-}
-
-// routine permettant de trouver le point d'entrée "case"
-// correspondant à la valeur cherchée
-
-BOOL CBotCase::CompCase(CBotStack* &pile, int val)
-{
- if ( m_Value == NULL ) return TRUE; // cas pour "default"
-
- while (!m_Value->Execute(pile)); // met sur la pile la valeur correpondant (sans interruption)
- return (pile->GivVal() == val); // compare avec la valeur cherchée
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "break" ou "continu"
-
-CBotBreak::CBotBreak()
-{
- name = "CBotBreak"; // debug
-}
-
-CBotBreak::~CBotBreak()
-{
-}
-
-CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotToken* pp = p; // conserve le ^au token (position début)
- int type = p->GivType();
-
- if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return NULL; // ne devrait jamais arriver
-
- if ( !ChkLvl(CBotString(), type ) )
- {
- pStack->SetError(TX_BREAK, pp);
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
-
- CBotBreak* inst = new CBotBreak(); // crée l'objet
- inst->SetToken(pp); // garde l'opération
-
- pp = p;
- if ( IsOfType( p, TokenTypVar ) )
- {
- inst->m_label = pp->GivString(); // enregistre le nom du label
- if ( !ChkLvl(inst->m_label, type ) )
- {
- delete inst;
- pStack->SetError(TX_NOLABEL, pp);
- return NULL; // pas d'objet, l'erreur est sur la pile
- }
- }
-
- if (IsOfType(p, ID_SEP))
- {
- return inst; // et le donne à qui veux
- }
- delete inst;
-
- pStack->SetError(TX_ENDOF, p->GivStart());
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécution l'instructino "break" ou "continu"
-
-BOOL CBotBreak :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->IfStep() ) return FALSE;
-
- pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label);
- return pj->Return(pile);
-}
-
-void CBotBreak :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain ) pj->RestoreStack(this);
-}
-
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "try"
-
-CBotTry::CBotTry()
-{
- m_ListCatch = NULL;
- m_FinalInst =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- name = "CBotTry"; // debug
-}
-
-CBotTry::~CBotTry()
-{
- delete m_ListCatch; // libère la liste
- delete m_Block; // libère le bloc d'instruction
- delete m_FinalInst;
-}
-
-CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotTry* inst = new CBotTry(); // crée l'objet
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_TRY)) return NULL; // ne devrait jamais arriver
-
- CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
-
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk );
- CBotCatch** pn = &inst->m_ListCatch;
-
- while (pStk->IsOk() && p->GivType() == ID_CATCH)
- {
- CBotCatch* i = CBotCatch::Compile(p, pStk);
- *pn = i;
- pn = &i->m_next;
- }
-
- if (pStk->IsOk() && IsOfType( p, ID_FINALLY) )
- {
- inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk );
- }
-
- if (pStk->IsOk())
- {
- return pStack->Return(inst, pStk); // rend l'objet à qui le demande
- }
-
- delete inst; // erreur, libère la place
- return pStack->Return(NULL, pStk); // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction Try
-// gère le retour d'exceptions
-// les arrêts par suspension
-// et les "finaly"
-
-BOOL CBotTry :: Execute(CBotStack* &pj)
-{
- int val;
-
- CBotStack* pile1 = pj->AddStack(this); // ajoute un élément à la pile
-// if ( pile1 == EOX ) return TRUE;
-
- if ( pile1->IfStep() ) return FALSE;
- // ou le retrouve en cas de reprise
- CBotStack* pile0 = pj->AddStack2(); // ajoute un élément à la pile secondaire
- CBotStack* pile2 = pile0->AddStack();
-
- if ( pile1->GivState() == 0 )
- {
- if ( m_Block->Execute(pile1) )
- {
- if ( m_FinalInst == NULL ) return pj->Return(pile1);
- pile1->SetState(-2); // passe au final
- }
-
- val = pile1->GivError();
- if ( val == 0 && CBotStack::m_initimer == 0 ) // en mode de step ?
- return FALSE; // ne fait pas le catch
-
- pile1->IncState();
- pile2->SetState(val); // mémorise le numéro de l'erreur
- pile1->SetError(0); // pour l'instant il n'y a plus d'erreur !
-
- if ( val == 0 && CBotStack::m_initimer < 0 ) // en mode de step ?
- return FALSE; // ne fait pas le catch
- }
-
- // il y a eu une interruption
- // voir de quoi il en retourne
-
- CBotCatch* pc = m_ListCatch;
- int state = (short)pile1->GivState(); // où en étions-nous ?
- val = pile2->GivState(); // pour quelle erreur ?
- pile0->SetState(1); // marquage pour GetRunPos
-
- if ( val >= 0 && state > 0 ) while ( pc != NULL )
- {
- if ( --state <= 0 )
- {
- // demande au bloc catch s'il se sent concerné
- if ( !pc->TestCatch(pile2, val) ) return FALSE; // suspendu !
- pile1->IncState();
- }
- if ( --state <= 0 )
- {
- if ( pile2->GivVal() == TRUE )
- {
-// pile0->SetState(1);
-
- if ( !pc->Execute(pile2) ) return FALSE; // exécute l'opération
- if ( m_FinalInst == NULL )
- return pj->Return(pile2); // termine le try
-
- pile1->SetState(-2); // passe au final
- break;
- }
- pile1->IncState();
- }
- pc = pc->m_next;
- }
- if ( m_FinalInst != NULL &&
- pile1->GivState() > 0 && val != 0 ) pile1->SetState(-1);// si arret alors fait le final
-
- if (pile1->GivState() <= -1)
- {
-// pile0->SetState(1);
-
- if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return FALSE;
- if (!pile2->IsOk()) return pj->Return(pile2); // garde cette exception
- pile2->SetError(pile1->GivState()==-1 ? val : 0); // remet l'erreur initiale
- return pj->Return(pile2);
- }
-
- pile1->SetState(0); // revient à l'évaluation
- pile0->SetState(0); // revient à l'évaluation
- if ( val != 0 && m_ListCatch == NULL && m_FinalInst == NULL )
- return pj->Return(pile2); // termine le try sans exception aucune
-
- pile1->SetError(val); // remet l'erreur
- return FALSE; // ce n'est pas pour nous
-}
-
-
-void CBotTry :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- int val;
- CBotStack* pile1 = pj->RestoreStack(this); // ajoute un élément à la pile
- if ( pile1 == NULL ) return;
- // ou le retrouve en cas de reprise
- CBotStack* pile0 = pj->AddStack2(); // ajoute un élément à la pile secondaire
- if ( pile0 == NULL ) return;
-
- CBotStack* pile2 = pile0->RestoreStack();
- if ( pile2 == NULL ) return;
-
- m_Block->RestoreState(pile1, bMain);
- if ( pile0->GivState() == 0 )
- {
- return;
- }
-
- // il y a eu une interruption
- // voir de quoi il en retourne
-
- CBotCatch* pc = m_ListCatch;
- int state = pile1->GivState(); // où en étions-nous ?
- val = pile2->GivState(); // pour quelle erreur ?
-
- if ( val >= 0 && state > 0 ) while ( pc != NULL )
- {
- if ( --state <= 0 )
- {
- // demande au bloc catch s'il se sent concerné
- pc->RestoreCondState(pile2, bMain); // suspendu !
- return;
- }
- if ( --state <= 0 )
- {
- if ( pile2->GivVal() == TRUE )
- {
- pc->RestoreState(pile2, bMain); // exécute l'opération
- return;
- }
- }
- pc = pc->m_next;
- }
-
- if (pile1->GivState() <= -1)
- {
- m_FinalInst->RestoreState(pile2, bMain);
- return;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "catch"
-
-CBotCatch::CBotCatch()
-{
- m_Cond =
- m_Block = NULL; // NULL pour que delete soit possible sans autre
- m_next = NULL;
-
- name = "CBotCatch"; // debug
-}
-
-CBotCatch::~CBotCatch()
-{
- delete m_Cond; // libère la liste
- delete m_Block; // libère le bloc d'instruction
- delete m_next; // et la suite
-}
-
-CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- CBotCatch* inst = new CBotCatch(); // crée l'objet
- pStack->SetStartError(p->GivStart());
-
- inst->SetToken(p);
- if (!IsOfType(p, ID_CATCH)) return NULL; // ne devrait jamais arriver
-
- if (IsOfType(p, ID_OPENPAR))
- {
- inst->m_Cond = CBotExpression::Compile(p, pStack);
- if (( pStack->GivType() < CBotTypLong ||
- pStack->GivTypResult().Eq(CBotTypBoolean) )&& pStack->IsOk() )
- {
- if (IsOfType(p, ID_CLOSEPAR))
- {
- inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStack );
- if ( pStack->IsOk() )
- return inst; // rend l'objet à qui le demande
- }
- pStack->SetError(TX_CLOSEPAR, p->GivStart());
- }
- pStack->SetError(TX_BADTYPE, p->GivStart());
- }
- pStack->SetError(TX_OPENPAR, p->GivStart());
- delete inst; // erreur, libère la place
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécution de "catch"
-
-BOOL CBotCatch :: Execute(CBotStack* &pj)
-{
- if ( m_Block == NULL ) return TRUE;
- return m_Block->Execute(pj); // exécute le bloc associé
-}
-
-void CBotCatch :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain);
-}
-
-void CBotCatch :: RestoreCondState(CBotStack* &pj, BOOL bMain)
-{
- m_Cond->RestoreState(pj, bMain);
-}
-
-// routine pour savoir si le catch est à faire ou non
-
-BOOL CBotCatch :: TestCatch(CBotStack* &pile, int val)
-{
- if ( !m_Cond->Execute(pile) ) return FALSE;
-
- if ( val > 0 || pile->GivType() != CBotTypBoolean )
- {
- CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
- var->SetValInt( pile->GivVal() == val );
- pile->SetVar(var); // remet sur la pile
- }
-
- return TRUE;
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// compile une instruction "throw"
-
-CBotThrow::CBotThrow()
-{
- m_Value = NULL; // NULL pour que delete soit possible sans autre
-
- name = "CBotThrow"; // debug
-}
-
-CBotThrow::~CBotThrow()
-{
- delete m_Value;
-}
-
-CBotInstr* CBotThrow::Compile(CBotToken* &p, CBotCStack* pStack)
-{
- pStack->SetStartError(p->GivStart());
-
- CBotThrow* inst = new CBotThrow(); // crée l'objet
- inst->SetToken(p);
-
- CBotToken* pp = p; // conserve le ^au token (position début)
-
- if (!IsOfType(p, ID_THROW)) return NULL; // ne devrait jamais arriver
-
- inst->m_Value = CBotExpression::Compile( p, pStack );
-
- if (pStack->GivType() < CBotTypLong && pStack->IsOk())
- {
- return inst; // rend l'objet à qui le demande
- }
- pStack->SetError(TX_BADTYPE, pp);
-
- delete inst; // erreur, libère la place
- return NULL; // pas d'objet, l'erreur est sur la pile
-}
-
-// exécute l'instruction "throw"
-
-BOOL CBotThrow :: Execute(CBotStack* &pj)
-{
- CBotStack* pile = pj->AddStack(this);
-// if ( pile == EOX ) return TRUE;
-
- if ( pile->GivState() == 0 )
- {
- if ( !m_Value->Execute(pile) ) return FALSE;
- pile->IncState();
- }
-
- if ( pile->IfStep() ) return FALSE;
-
- int val = pile->GivVal();
- if ( val < 0 ) val = TX_BADTHROW;
- pile->SetError( val, &m_token );
- return pj->Return( pile );
-}
-
-void CBotThrow :: RestoreState(CBotStack* &pj, BOOL bMain)
-{
- if ( !bMain ) return;
-
- CBotStack* pile = pj->RestoreStack(this);
- if ( pile == NULL ) return;
-
- if ( pile->GivState() == 0 )
- {
- m_Value->RestoreState(pile, bMain);
- return;
- }
-}
-
-
-
-////////////////////////////////////////////////////////////
-
-
-CBotStartDebugDD::CBotStartDebugDD()
-{
- name = "CBotStartDebugDD"; // debug
-}
-
-CBotStartDebugDD::~CBotStartDebugDD()
-{
-}
-
-CBotInstr* CBotStartDebugDD::Compile(CBotToken* &p, CBotCStack* pStack)
-{
-
- if (!IsOfType(p, ID_DEBUGDD)) return NULL; // ne devrait jamais arriver
-
- return new CBotStartDebugDD(); // crée l'objet
-
-}
-
-// exécute l'instruction "throw"
-
-BOOL CBotStartDebugDD :: Execute(CBotStack* &pj)
-{
- CBotProgram* p = pj->GivBotCall();
- p->m_bDebugDD = TRUE;
-
- return TRUE;
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+///////////////////////////////////////////////////////////////////////
+// This file defined the following statements:
+// CBotWhile "while (condition) {instructions}"
+// CBotDo "do {instructions} while (condition)"
+// CBotFor "for (init, condition, incr) {instructions}"
+// CBotSwitch "switch (val) {instructions}"
+// CBotCase "case val:"
+// CBotBreak "break", "break label", "continu", "continu label"
+// CBotTry "try {instructions}"
+// CBotCatch "catch (condition) {instructions}" or "finally"
+// CBotThrow "throw execption"
+
+
+#include "CBot.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compile an instruction "while"
+
+CBotWhile::CBotWhile()
+{
+ m_Condition =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotWhile"; // debug
+}
+
+CBotWhile::~CBotWhile()
+{
+ delete m_Condition; // frees the condition
+ delete m_Block; // releases the block instruction
+}
+
+CBotInstr* CBotWhile::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotWhile* inst = new CBotWhile(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // records the name of the label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_WHILE)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+ // a bit of battery please (??)
+
+ if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
+ {
+ // the condition exists
+
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+
+ if ( pStk->IsOk() )
+ {
+ // the statement block is ok (it may be empty!
+
+ return pStack->Return(inst, pStk); // return an object to the application
+ // makes the object to which the application
+ }
+ }
+
+ delete inst; // error, frees the place
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// executes a "while" instruction
+
+bool CBotWhile :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the condition
+ if ( !m_Condition->Execute(pile) ) return false; // interrupted here?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ if ( !pile->IsOk() || pile->GivVal() != true )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // the condition is true, pass in the second mode
+
+ if (!pile->SetState(1)) return false; // ready for further
+
+ case 1:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(0, m_label)) continue; // if continued, will return to test
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // returns to the test again
+ if (!pile->SetState(0, 0)) return false;
+ continue;
+ }
+}
+
+void CBotWhile :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the condition
+ m_Condition->RestoreState(pile, bMain);
+ return;
+
+ case 1:
+ // evaluates the associated statement block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "repeat"
+
+CBotRepeat::CBotRepeat()
+{
+ m_NbIter =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotRepeat"; // debug
+}
+
+CBotRepeat::~CBotRepeat()
+{
+ delete m_NbIter; // frees the condition
+ delete m_Block; // frees the instruction block
+}
+
+CBotInstr* CBotRepeat::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotRepeat* inst = new CBotRepeat(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_REPEAT)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ if ( IsOfType(p, ID_OPENPAR ) )
+ {
+ CBotToken* ppp = p; // preserves the ^ token (starting position)
+ if ( NULL != (inst->m_NbIter = CBotExpression::Compile( p, pStk )) )
+ {
+ if ( pStk->GivType() < CBotTypLong )
+ {
+ if ( IsOfType(p, ID_CLOSEPAR ) )
+ {
+
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+
+ if ( pStk->IsOk() )
+ {
+ // the statement block is ok (it may be empty!
+
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ pStk->SetStartError(ppp->GivStart());
+ pStk->SetError( TX_BADTYPE, p->GivStart() );
+ }
+ pStack->SetError(TX_ENDOF, p);
+ }
+ pStack->SetError(TX_OPENPAR, p->GivStart()); // missing parenthesis
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// execution of intruction "repeat"
+
+bool CBotRepeat :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the number of iterations
+ if ( !m_NbIter->Execute(pile) ) return false; // interrupted here ?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ int n;
+ if ( !pile->IsOk() || ( n = pile->GivVal() ) < 1 )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // puts the number of iterations +1 to the "state"
+
+ if (!pile->SetState(n+1)) return false; // ready for further
+ continue; // continue as a result
+
+ case 1:
+ // normal end of the loop
+ return pj->Return(pile); // sends the results and releases the stack
+
+ default:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(pile->GivState()-1, m_label)) continue; // if continued, will return to test
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // returns to the test again
+ if (!pile->SetState(pile->GivState()-1, 0)) return false;
+ continue;
+ }
+}
+
+void CBotRepeat :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the condition
+ m_NbIter->RestoreState(pile, bMain);
+ return;
+
+ case 1:
+ // evaluates the associated statement block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compile the instruction "do"
+
+CBotDo::CBotDo()
+{
+ m_Condition =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotDo"; // debug
+}
+
+CBotDo::~CBotDo()
+{
+ delete m_Condition; // frees the condition
+ delete m_Block; // frees the instruction block
+}
+
+CBotInstr* CBotDo::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotDo* inst = new CBotDo(); // creates the object
+
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_DO)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+
+ // looking for a statement block after the do
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+
+ if ( pStk->IsOk() )
+ {
+ if (IsOfType(p, ID_WHILE))
+ {
+ if ( NULL != (inst->m_Condition = CBotCondition::Compile( p, pStk )) )
+ {
+ // the condition exists
+ if (IsOfType(p, ID_SEP))
+ {
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+ pStk->SetError(TX_ENDOF, p->GivStart());
+ }
+ }
+ pStk->SetError(TX_WHILE, p->GivStart());
+ }
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// executes instruction "do"
+
+bool CBotDo :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this); // adds an item to the stack
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(1, m_label)) continue; // if continued, will return to test
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ if (!pile->SetState(1)) return false; // ready for further
+
+ case 1:
+ // evaluates the condition
+ if ( !m_Condition->Execute(pile) ) return false; // interrupted here ?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ if ( !pile->IsOk() || pile->GivVal() != true )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ // returns to instruction block to start
+ if (!pile->SetState(0, 0)) return false;
+ continue;
+ }
+}
+
+void CBotDo :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are two possible states (depending on recovery)
+ case 0:
+ // restores the assosiated statement's block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, bMain);
+ return;
+
+ case 1:
+ // restores the condition
+ m_Condition->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "for"
+
+CBotFor::CBotFor()
+{
+ m_Init =
+ m_Test =
+ m_Incr =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotFor"; // debug
+}
+
+CBotFor::~CBotFor()
+{
+ delete m_Init;
+ delete m_Test;
+ delete m_Incr;
+ delete m_Block; // frees the instruction block
+}
+
+CBotInstr* CBotFor::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotFor* inst = new CBotFor(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if ( IsOfType( p, TokenTypVar ) &&
+ IsOfType( p, ID_DOTS ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ }
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_FOR)) return NULL; // should never happen
+
+ if ( !IsOfType(p, ID_OPENPAR)) // missing parenthesis ?
+ {
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ return NULL;
+ }
+
+ CBotCStack* pStk = pStack->TokenStack(pp, true); // un petit bout de pile svp
+
+ // compiles instructions for initialization
+ inst->m_Init = CBotListExpression::Compile( p, pStk );
+ if ( pStk->IsOk() )
+ {
+ if ( !IsOfType(p, ID_SEP)) // lack the semicolon?
+ {
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+ }
+ inst->m_Test = CBotBoolExpr::Compile( p, pStk );
+ if ( pStk->IsOk() )
+ {
+ if ( !IsOfType(p, ID_SEP)) // lack the semicolon?
+ {
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+ }
+ inst->m_Incr = CBotListExpression::Compile( p, pStk );
+ if ( pStk->IsOk() )
+ {
+ if ( IsOfType(p, ID_CLOSEPAR)) // missing parenthesis ?
+ {
+ IncLvl(inst->m_label);
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ DecLvl();
+ if ( pStk->IsOk() )
+ return pStack->Return(inst, pStk);;
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ }
+ }
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// execution of instruction "for"
+
+bool CBotFor :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this, true); // adds an item to the stack (variables locales)
+ // or find in case of recovery
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ while( true ) switch( pile->GivState() ) // executes the loop
+ { // there are four possible states (depending on recovery)
+ case 0:
+ // initialize
+ if ( m_Init != NULL &&
+ !m_Init->Execute(pile) ) return false; // interrupted here ?
+ if (!pile->SetState(1)) return false; // ready for further
+
+ case 1:
+ // evaluates the condition
+ if ( m_Test != NULL ) // no strings attached? -> True!
+ {
+ if (!m_Test->Execute(pile) ) return false; // interrupted here ?
+
+ // the result of the condition is on the stack
+
+ // terminates if an error or if the condition is false
+ if ( !pile->IsOk() || pile->GivVal() != true )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+ }
+
+ // la condition est vrai, passe à la suite
+ if (!pile->SetState(2)) return false; // ready for further
+
+ case 2:
+ // evaluates the associated statement block
+ if ( m_Block != NULL &&
+ !m_Block->Execute(pile) )
+ {
+ if (pile->IfContinue(3, m_label)) continue; // if continued, going on to incrementation
+ return pj->BreakReturn(pile, m_label); // sends the results and releases the stack
+ }
+
+ // terminates if there is an error
+ if ( !pile->IsOk() )
+ {
+ return pj->Return(pile); // sends the results and releases the stack
+ }
+
+ if (!pile->SetState(3)) return false; // ready for further
+
+ case 3:
+ // evalutate the incrementation
+ if ( m_Incr != NULL &&
+ !m_Incr->Execute(pile) ) return false; // interrupted here ?
+
+ // returns to the test again
+ if (!pile->SetState(1, 0)) return false; // returns to the test
+ continue;
+ }
+}
+
+void CBotFor :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this); // adds an item to the stack (variables locales)
+ if ( pile == NULL ) return;
+
+ switch( pile->GivState() )
+ { // there are four possible states (depending on recovery)
+ case 0:
+ // initialize
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, true); // interrupted here !
+ return;
+
+ case 1:
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variables definitions
+
+ // evaluates the condition
+ if ( m_Test != NULL ) m_Test->RestoreState(pile, true); // interrupted here !
+ return;
+
+ case 2:
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variable definitions
+
+ // evaluates the associated statement block
+ if ( m_Block != NULL ) m_Block->RestoreState(pile, true);
+ return;
+
+ case 3:
+ if ( m_Init != NULL ) m_Init->RestoreState(pile, false); // variable definitions
+
+ // evaluate the incrementation
+ if ( m_Incr != NULL ) m_Incr->RestoreState(pile, true); // interrupted here !
+ return;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// compiles a list of expressions
+// is used only in "for" statement
+// in incrementing and intitialisation
+
+CBotListExpression::CBotListExpression()
+{
+ m_Expr = NULL;
+ name = "CBotListExpression";
+}
+
+CBotListExpression::~CBotListExpression()
+{
+ delete m_Expr;
+}
+
+// seeks a declaration of variable or expression
+
+static CBotInstr* CompileInstrOrDefVar(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotInstr* i = CBotInt::Compile( p, pStack, false, true ); // Is this a declaration of an integer?
+ if ( i== NULL ) i = CBotFloat::Compile( p, pStack, false, true ); // or a real number?
+ if ( i== NULL ) i = CBotBoolean::Compile( p, pStack, false, true ); // or a boolean?
+ if ( i== NULL ) i = CBotIString::Compile( p, pStack, false, true ); // ar a string?
+ if ( i== NULL ) i = CBotExpression::Compile( p, pStack ); // compiles an expression
+ return i;
+}
+
+CBotInstr* CBotListExpression::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotListExpression* inst = new CBotListExpression();
+
+ inst->m_Expr = CompileInstrOrDefVar( p, pStack ); // compile the first expression in a list
+ if (pStack->IsOk())
+ {
+ while ( IsOfType(p, ID_COMMA) ) // more instructions?
+ {
+ CBotInstr* i = CompileInstrOrDefVar( p, pStack ); // Is this a declaration of an integer?
+ inst->m_Expr->AddNext(i); // added after
+ if ( !pStack->IsOk() )
+ {
+ delete inst;
+ return NULL; // no object, the error is on the stack
+ }
+ }
+ return inst;
+ }
+ delete inst;
+ return NULL;
+}
+
+bool CBotListExpression::Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(); // essential
+ CBotInstr* p = m_Expr; // the first expression
+
+ int state = pile->GivState();
+ while (state-->0) p = p->GivNext(); // returns to the interrupted operation
+
+ if ( p != NULL ) while (true)
+ {
+ if ( !p->Execute(pile) ) return false;
+ p = p->GivNext();
+ if ( p == NULL ) break;
+ if (!pile->IncState()) return false; // ready for next
+ }
+ return pj->Return(pile);
+}
+
+void CBotListExpression::RestoreState(CBotStack* &pj, bool bMain)
+{
+ CBotStack* pile = pj;
+ int state = 0x7000;
+
+ if ( bMain )
+ {
+ pile = pj->RestoreStack();
+ if ( pile == NULL ) return;
+ state = pile->GivState();
+ }
+
+ CBotInstr* p = m_Expr; // the first expression
+
+ while (p != NULL && state-->0)
+ {
+ p->RestoreState(pile, false);
+ p = p->GivNext(); // returns to the interrupted operation
+ }
+
+ if ( p != NULL )
+ {
+ p->RestoreState(pile, bMain);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "switch"
+
+CBotSwitch::CBotSwitch()
+{
+ m_Value =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotSwitch"; // debug
+}
+
+CBotSwitch::~CBotSwitch()
+{
+ delete m_Value; // frees the value
+ delete m_Block; // frees the instruction block
+}
+
+
+CBotInstr* CBotSwitch::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotSwitch* inst = new CBotSwitch(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_SWITCH)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ if ( IsOfType(p, ID_OPENPAR ) )
+ {
+ if ( NULL != (inst->m_Value = CBotExpression::Compile( p, pStk )) )
+ {
+ if ( pStk->GivType() < CBotTypLong )
+ {
+ if ( IsOfType(p, ID_CLOSEPAR ) )
+ {
+ if ( IsOfType(p, ID_OPBLK ) )
+ {
+ IncLvl();
+
+ while( !IsOfType( p, ID_CLBLK ) )
+ {
+ if ( p->GivType() == ID_CASE || p->GivType() == ID_DEFAULT)
+ {
+ CBotCStack* pStk2 = pStk->TokenStack(p); // un petit bout de pile svp
+
+ CBotInstr* i = CBotCase::Compile( p, pStk2 );
+ if (i == NULL)
+ {
+ delete inst;
+ return pStack->Return(NULL, pStk2);
+ }
+ delete pStk2;
+ if ( inst->m_Block == NULL ) inst->m_Block = i;
+ else inst->m_Block->AddNext(i);
+ continue;
+ }
+
+ if ( inst->m_Block == NULL )
+ {
+ pStk->SetError(TX_NOCASE, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+
+ CBotInstr* i = CBotBlock::CompileBlkOrInst( p, pStk, true );
+ if ( !pStk->IsOk() )
+ {
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ inst->m_Block->AddNext(i);
+
+ if ( p == NULL )
+ {
+ pStk->SetError(TX_CLOSEBLK, -1);
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ }
+ DecLvl();
+
+ if ( inst->m_Block == NULL )
+ {
+ pStk->SetError(TX_NOCASE, p->GivStart());
+ delete inst;
+ return pStack->Return(NULL, pStk);
+ }
+ // the statement block is ok
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+ pStk->SetError( TX_OPENBLK, p->GivStart() );
+ }
+ pStk->SetError( TX_CLOSEPAR, p->GivStart() );
+ }
+ pStk->SetError( TX_BADTYPE, p->GivStart() );
+ }
+ }
+ pStk->SetError( TX_OPENPAR, p->GivStart());
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// executes instruction "switch"
+
+bool CBotSwitch :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack
+// if ( pile1 == EOX ) return true;
+
+ CBotInstr* p = m_Block; // first expression
+
+ int state = pile1->GivState();
+ if (state == 0)
+ {
+ if ( !m_Value->Execute(pile1) ) return false;
+ pile1->SetState(state = -1);
+ }
+
+ if ( pile1->IfStep() ) return false;
+
+ if ( state == -1 )
+ {
+ state = 0;
+ int val = pile1->GivVal(); // result of the value
+
+ CBotStack* pile2 = pile1->AddStack();
+ while ( p != NULL ) // search for the corresponding case in a list
+ {
+ state++;
+ if ( p->CompCase( pile2, val ) ) break; // found the case
+ p = p->GivNext();
+ }
+ pile2->Delete();
+
+ if ( p == NULL ) return pj->Return(pile1); // completed if nothing
+
+ if ( !pile1->SetState(state) ) return false;
+ }
+
+ p = m_Block; // returns to the beginning
+ while (state-->0) p = p->GivNext(); // advance in the list
+
+ while( p != NULL )
+ {
+ if ( !p->Execute(pile1) ) return pj->BreakReturn(pile1);
+ if ( !pile1->IncState() ) return false;
+ p = p->GivNext();
+ }
+ return pj->Return(pile1);
+}
+
+void CBotSwitch :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile1 == NULL ) return;
+
+ CBotInstr* p = m_Block; // first expression
+
+ int state = pile1->GivState();
+ if (state == 0)
+ {
+ m_Value->RestoreState(pile1, bMain);
+ return;
+ }
+
+ if ( state == -1 )
+ {
+ return;
+ }
+
+// p = m_Block; // returns to the beginning
+ while ( p != NULL && state-- > 0 )
+ {
+ p->RestoreState(pile1, false);
+ p = p->GivNext(); // advance in the list
+ }
+
+ if( p != NULL )
+ {
+ p->RestoreState(pile1, true);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "case"
+// we are bound to the statement block "switch"
+
+CBotCase::CBotCase()
+{
+ m_Value = NULL; // NULL so that delete is not possible further
+ name = "CBotCase"; // debug
+}
+
+CBotCase::~CBotCase()
+{
+ delete m_Value; // frees the value
+}
+
+
+CBotInstr* CBotCase::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCase* inst = new CBotCase(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_CASE, ID_DEFAULT)) return NULL; // should never happen
+
+ if ( pp->GivType() == ID_CASE )
+ {
+ pp = p;
+ inst->m_Value = CBotExprNum::Compile(p, pStack);
+ if ( inst->m_Value == NULL )
+ {
+ pStack->SetError( TX_BADNUM, pp );
+ delete inst;
+ return NULL;
+ }
+ }
+ if ( !IsOfType( p, ID_DOTS ))
+ {
+ pStack->SetError( TX_MISDOTS, p->GivStart() );
+ delete inst;
+ return NULL;
+ }
+
+ return inst;
+}
+
+// execution of instruction "case"
+
+bool CBotCase::Execute(CBotStack* &pj)
+{
+ return true; // the "case" statement does nothing!
+}
+
+void CBotCase::RestoreState(CBotStack* &pj, bool bMain)
+{
+}
+
+// routine to find the entry point of "case"
+// corresponding to the value seen
+
+bool CBotCase::CompCase(CBotStack* &pile, int val)
+{
+ if ( m_Value == NULL ) return true; // "default" case
+
+ while (!m_Value->Execute(pile)); // puts the value on the correspondent stack (without interruption)
+ return (pile->GivVal() == val); // compared with the given value
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "break" or "continu"
+
+CBotBreak::CBotBreak()
+{
+ name = "CBotBreak"; // debug
+}
+
+CBotBreak::~CBotBreak()
+{
+}
+
+CBotInstr* CBotBreak::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+ int type = p->GivType();
+
+ if (!IsOfType(p, ID_BREAK, ID_CONTINUE)) return NULL; // should never happen
+
+ if ( !ChkLvl(CBotString(), type ) )
+ {
+ pStack->SetError(TX_BREAK, pp);
+ return NULL; // no object, the error is on the stack
+ }
+
+ CBotBreak* inst = new CBotBreak(); // creates the object
+ inst->SetToken(pp); // keeps the operation
+
+ pp = p;
+ if ( IsOfType( p, TokenTypVar ) )
+ {
+ inst->m_label = pp->GivString(); // register the name of label
+ if ( !ChkLvl(inst->m_label, type ) )
+ {
+ delete inst;
+ pStack->SetError(TX_NOLABEL, pp);
+ return NULL; // no object, the error is on the stack
+ }
+ }
+
+ if (IsOfType(p, ID_SEP))
+ {
+ return inst; // return what it wants
+ }
+ delete inst;
+
+ pStack->SetError(TX_ENDOF, p->GivStart());
+ return NULL; // no object, the error is on the stack
+}
+
+// execution of statement "break" or "continu"
+
+bool CBotBreak :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+// if ( pile == EOX ) return true;
+
+ if ( pile->IfStep() ) return false;
+
+ pile->SetBreak(m_token.GivType()==ID_BREAK ? 1 : 2, m_label);
+ return pj->Return(pile);
+}
+
+void CBotBreak :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( bMain ) pj->RestoreStack(this);
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "try"
+
+CBotTry::CBotTry()
+{
+ m_ListCatch = NULL;
+ m_FinalInst =
+ m_Block = NULL; // NULL so that delete is not possible further
+ name = "CBotTry"; // debug
+}
+
+CBotTry::~CBotTry()
+{
+ delete m_ListCatch; // frees the list
+ delete m_Block; // frees the instruction block
+ delete m_FinalInst;
+}
+
+CBotInstr* CBotTry::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotTry* inst = new CBotTry(); // creates the object
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_TRY)) return NULL; // should never happen
+
+ CBotCStack* pStk = pStack->TokenStack(pp); // un petit bout de pile svp
+
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStk );
+ CBotCatch** pn = &inst->m_ListCatch;
+
+ while (pStk->IsOk() && p->GivType() == ID_CATCH)
+ {
+ CBotCatch* i = CBotCatch::Compile(p, pStk);
+ *pn = i;
+ pn = &i->m_next;
+ }
+
+ if (pStk->IsOk() && IsOfType( p, ID_FINALLY) )
+ {
+ inst->m_FinalInst = CBotBlock::CompileBlkOrInst( p, pStk );
+ }
+
+ if (pStk->IsOk())
+ {
+ return pStack->Return(inst, pStk); // return an object to the application
+ }
+
+ delete inst; // error, frees up
+ return pStack->Return(NULL, pStk); // no object, the error is on the stack
+}
+
+// execution of instruction Try
+// manages the return of exceptions
+// stops (judgements) by suspension
+// and "finally"
+
+bool CBotTry :: Execute(CBotStack* &pj)
+{
+ int val;
+
+ CBotStack* pile1 = pj->AddStack(this); // adds an item to the stack
+// if ( pile1 == EOX ) return true;
+
+ if ( pile1->IfStep() ) return false;
+ // or find in case of recovery
+ CBotStack* pile0 = pj->AddStack2(); // adds an element to the secondary stack
+ CBotStack* pile2 = pile0->AddStack();
+
+ if ( pile1->GivState() == 0 )
+ {
+ if ( m_Block->Execute(pile1) )
+ {
+ if ( m_FinalInst == NULL ) return pj->Return(pile1);
+ pile1->SetState(-2); // passes final
+ }
+
+ val = pile1->GivError();
+ if ( val == 0 && CBotStack::m_initimer == 0 ) // mode step?
+ return false; // does not make the catch
+
+ pile1->IncState();
+ pile2->SetState(val); // stores the error number
+ pile1->SetError(0); // for now there is are more errors!
+
+ if ( val == 0 && CBotStack::m_initimer < 0 ) // mode step?
+ return false; // does not make the catch
+ }
+
+ // there was an interruption
+ // see what it returns
+
+ CBotCatch* pc = m_ListCatch;
+ int state = (short)pile1->GivState(); // where were we?
+ val = pile2->GivState(); // what error?
+ pile0->SetState(1); // marking the GetRunPos
+
+ if ( val >= 0 && state > 0 ) while ( pc != NULL )
+ {
+ if ( --state <= 0 )
+ {
+ // request to the catch block if they feel concerned
+ // demande au bloc catch s'il se sent concerné
+ if ( !pc->TestCatch(pile2, val) ) return false; // suspend !
+ pile1->IncState();
+ }
+ if ( --state <= 0 )
+ {
+ if ( pile2->GivVal() == true )
+ {
+// pile0->SetState(1);
+
+ if ( !pc->Execute(pile2) ) return false; // performs the operation
+ if ( m_FinalInst == NULL )
+ return pj->Return(pile2); // ends the try
+
+ pile1->SetState(-2); // passes final
+ break;
+ }
+ pile1->IncState();
+ }
+ pc = pc->m_next;
+ }
+ if ( m_FinalInst != NULL &&
+ pile1->GivState() > 0 && val != 0 ) pile1->SetState(-1);// if stop then made the final
+
+ if (pile1->GivState() <= -1)
+ {
+// pile0->SetState(1);
+
+ if (!m_FinalInst->Execute(pile2) && pile2->IsOk()) return false;
+ if (!pile2->IsOk()) return pj->Return(pile2); // keep this exception
+ pile2->SetError(pile1->GivState()==-1 ? val : 0); // gives the initial error
+ return pj->Return(pile2);
+ }
+
+ pile1->SetState(0); // returns to the evaluation
+ pile0->SetState(0); // returns to the evaluation
+ if ( val != 0 && m_ListCatch == NULL && m_FinalInst == NULL )
+ return pj->Return(pile2); // ends the try without exception
+
+ pile1->SetError(val); // gives the error
+ return false; // it's not for us
+}
+
+
+void CBotTry :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ int val;
+ CBotStack* pile1 = pj->RestoreStack(this); // adds an item to the stack
+ if ( pile1 == NULL ) return;
+ // or find in case of recovery
+ CBotStack* pile0 = pj->AddStack2(); // adds an item to the secondary stack
+ if ( pile0 == NULL ) return;
+
+ CBotStack* pile2 = pile0->RestoreStack();
+ if ( pile2 == NULL ) return;
+
+ m_Block->RestoreState(pile1, bMain);
+ if ( pile0->GivState() == 0 )
+ {
+ return;
+ }
+
+ // there was an interruption
+ // see what it returns
+
+ CBotCatch* pc = m_ListCatch;
+ int state = pile1->GivState(); // where were we ?
+ val = pile2->GivState(); // what error ?
+
+ if ( val >= 0 && state > 0 ) while ( pc != NULL )
+ {
+ if ( --state <= 0 )
+ {
+ // request to the catch block if they feel concerned
+ // demande au bloc catch s'il se sent concerné
+ pc->RestoreCondState(pile2, bMain); // suspend !
+ return;
+ }
+ if ( --state <= 0 )
+ {
+ if ( pile2->GivVal() == true )
+ {
+ pc->RestoreState(pile2, bMain); // execute the operation
+ return;
+ }
+ }
+ pc = pc->m_next;
+ }
+
+ if (pile1->GivState() <= -1)
+ {
+ m_FinalInst->RestoreState(pile2, bMain);
+ return;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "catch"
+
+CBotCatch::CBotCatch()
+{
+ m_Cond =
+ m_Block = NULL; // NULL so that delete is not possible further
+ m_next = NULL;
+
+ name = "CBotCatch"; // debug
+}
+
+CBotCatch::~CBotCatch()
+{
+ delete m_Cond; // frees the list
+ delete m_Block; // frees the instruction block
+ delete m_next; // and subsequent
+}
+
+CBotCatch* CBotCatch::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCatch* inst = new CBotCatch(); // creates the object
+ pStack->SetStartError(p->GivStart());
+
+ inst->SetToken(p);
+ if (!IsOfType(p, ID_CATCH)) return NULL; // should never happen
+
+ if (IsOfType(p, ID_OPENPAR))
+ {
+ inst->m_Cond = CBotExpression::Compile(p, pStack);
+ if (( pStack->GivType() < CBotTypLong ||
+ pStack->GivTypResult().Eq(CBotTypBoolean) )&& pStack->IsOk() )
+ {
+ if (IsOfType(p, ID_CLOSEPAR))
+ {
+ inst->m_Block = CBotBlock::CompileBlkOrInst( p, pStack );
+ if ( pStack->IsOk() )
+ return inst; // return an object to the application
+ }
+ pStack->SetError(TX_CLOSEPAR, p->GivStart());
+ }
+ pStack->SetError(TX_BADTYPE, p->GivStart());
+ }
+ pStack->SetError(TX_OPENPAR, p->GivStart());
+ delete inst; // error, frees up
+ return NULL; // no object, the error is on the stack
+}
+
+// execution of "catch"
+
+bool CBotCatch :: Execute(CBotStack* &pj)
+{
+ if ( m_Block == NULL ) return true;
+ return m_Block->Execute(pj); // executes the associated block
+}
+
+void CBotCatch :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( bMain && m_Block != NULL ) m_Block->RestoreState(pj, bMain);
+}
+
+void CBotCatch :: RestoreCondState(CBotStack* &pj, bool bMain)
+{
+ m_Cond->RestoreState(pj, bMain);
+}
+
+// routine to see if the catch is to do or not
+
+bool CBotCatch :: TestCatch(CBotStack* &pile, int val)
+{
+ if ( !m_Cond->Execute(pile) ) return false;
+
+ if ( val > 0 || pile->GivType() != CBotTypBoolean )
+ {
+ CBotVar* var = CBotVar::Create((CBotToken*)NULL, CBotTypBoolean);
+ var->SetValInt( pile->GivVal() == val );
+ pile->SetVar(var); // calls on the stack
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// compiles instruction "throw"
+
+CBotThrow::CBotThrow()
+{
+ m_Value = NULL; // NULL so that delete is not possible further
+
+ name = "CBotThrow"; // debug
+}
+
+CBotThrow::~CBotThrow()
+{
+ delete m_Value;
+}
+
+CBotInstr* CBotThrow::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ pStack->SetStartError(p->GivStart());
+
+ CBotThrow* inst = new CBotThrow(); // creates the object
+ inst->SetToken(p);
+
+ CBotToken* pp = p; // preserves at the ^ token (starting position)
+
+ if (!IsOfType(p, ID_THROW)) return NULL; // should never happen
+
+ inst->m_Value = CBotExpression::Compile( p, pStack );
+
+ if (pStack->GivType() < CBotTypLong && pStack->IsOk())
+ {
+ return inst; // return an object to the application
+ }
+ pStack->SetError(TX_BADTYPE, pp);
+
+ delete inst; // error, frees up
+ return NULL; // no object, the error is on the stack
+}
+
+// execution of instruction "throw"
+
+bool CBotThrow :: Execute(CBotStack* &pj)
+{
+ CBotStack* pile = pj->AddStack(this);
+// if ( pile == EOX ) return true;
+
+ if ( pile->GivState() == 0 )
+ {
+ if ( !m_Value->Execute(pile) ) return false;
+ pile->IncState();
+ }
+
+ if ( pile->IfStep() ) return false;
+
+ int val = pile->GivVal();
+ if ( val < 0 ) val = TX_BADTHROW;
+ pile->SetError( val, &m_token );
+ return pj->Return( pile );
+}
+
+void CBotThrow :: RestoreState(CBotStack* &pj, bool bMain)
+{
+ if ( !bMain ) return;
+
+ CBotStack* pile = pj->RestoreStack(this);
+ if ( pile == NULL ) return;
+
+ if ( pile->GivState() == 0 )
+ {
+ m_Value->RestoreState(pile, bMain);
+ return;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////
+
+
+CBotStartDebugDD::CBotStartDebugDD()
+{
+ name = "CBotStartDebugDD"; // debug
+}
+
+CBotStartDebugDD::~CBotStartDebugDD()
+{
+}
+
+CBotInstr* CBotStartDebugDD::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+
+ if (!IsOfType(p, ID_DEBUGDD)) return NULL; // should never happen
+
+ return new CBotStartDebugDD(); // creates the object
+
+}
+
+// execution of instruction "throw"
+
+bool CBotStartDebugDD :: Execute(CBotStack* &pj)
+{
+ CBotProgram* p = pj->GivBotCall();
+ p->m_bDebugDD = true;
+
+ return true;
+}
+
diff --git a/src/CBot/CMakeLists.txt b/src/CBot/CMakeLists.txt
index 9933e9c..409ef3b 100644
--- a/src/CBot/CMakeLists.txt
+++ b/src/CBot/CMakeLists.txt
@@ -10,7 +10,6 @@ CBotToken.cpp
CBotTwoOpExpr.cpp
CBotVar.cpp
CBotWhile.cpp
-CBot.rc
)
add_library(CBot SHARED ${SOURCES})
diff --git a/src/CBot/ClassFILE.cpp b/src/CBot/ClassFILE.cpp
index e4dd578..f73a1ac 100644
--- a/src/CBot/ClassFILE.cpp
+++ b/src/CBot/ClassFILE.cpp
@@ -1,426 +1,428 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.// ClassFile.cpp
-//
-// définition des méthodes pour la classe FILE
-
-
-
-// Variables statiques
-
-static CBotClass* m_pClassFILE;
-static CBotProgram* m_pFuncFile;
-static int m_CompteurFileOpen = 0;
-
-
-
-// Prépare un nom de fichier.
-
-void PrepareFilename(CBotString &filename) //DD!
-{
- int pos;
-
- pos = filename.ReverseFind('\\');
- if ( pos > 0 )
- {
- filename = filename.Mid(pos+1); // enlève les dossiers
- }
-
- pos = filename.ReverseFind('/');
- if ( pos > 0 )
- {
- filename = filename.Mid(pos+1); // aussi ceux avec /
- }
-
- pos = filename.ReverseFind(':');
- if ( pos > 0 )
- {
- filename = filename.Mid(pos+1); // enlève aussi la lettre d'unité C:
- }
-
- filename = CBotString("files\\") + filename;
-}
-
-
-// constructeur de la classe
-// reçois le nom du fichier en paramètre
-
-// exécution
-BOOL rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- CBotString mode;
-
- // accepte sans paramètre
- if ( pVar == NULL ) return TRUE;
-
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
-
- CBotString filename = pVar->GivValString();
- PrepareFilename(filename); //DR
-
- // il peut y avoir un second paramètre
- pVar = pVar->GivNext();
- if ( pVar != NULL )
- {
- // récupère le mode
- mode = pVar->GivValString();
- if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
- }
-
- // enregistre le nom du fichier
- pVar = pThis->GivItem("filename");
- pVar->SetValString(filename);
-
- if ( ! mode.IsEmpty() )
- {
- // ouvre le ficher demandé
- FILE* pFile = fopen( filename, mode );
- if ( pFile == NULL ) { Exception = CBotErrFileOpen; return FALSE; }
-
- m_CompteurFileOpen ++;
-
- // enregiste le canal du fichier
- pVar = pThis->GivItem("handle");
- pVar->SetValInt((long)pFile);
- }
-
- return TRUE;
-}
-
-// compilation
-CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
-{
- // accepte sans paramètre
- if ( pVar == NULL ) return CBotTypResult( 0 );
-
- // qui doit être une chaine
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( CBotErrBadString );
-
- // il peut y avoir un second paramètre
- pVar = pVar->GivNext();
- if ( pVar != NULL )
- {
- // qui doit être une chaine
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( CBotErrBadString );
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
- }
-
- // le résultat est de type void (constructeur)
- return CBotTypResult( 0 );
-}
-
-
-// destructeur de la classe
-
-// exécution
-BOOL rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- // récupère l'élément "handle"
- pVar = pThis->GivItem("handle");
-
- // pas ouvert ? pas de problème
- if ( pVar->GivInit() != IS_DEF) return TRUE;
-
- FILE* pFile= (FILE*)pVar->GivValInt();
- fclose(pFile);
- m_CompteurFileOpen --;
-
- pVar->SetInit(IS_NAN);
-
- return TRUE;
-}
-
-
-// méthode FILE :: open
-// reçois le mode r/w en paramètre
-
-// exécution
-BOOL rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- // il doit y avoir un paramètre
- if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
-
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
-
- // il peut y avoir un second paramètre
- if ( pVar->GivNext() != NULL )
- {
- // dans ce cas le premier paramètre est le nom du fichier
- CBotString filename = pVar->GivValString();
- PrepareFilename(filename); //DR
-
- // enregistre le nom du fichier
- CBotVar* pVar2 = pThis->GivItem("filename");
- pVar2->SetValString(filename);
-
- // paramètre suivant est le mode
- pVar = pVar -> GivNext();
- }
-
- CBotString mode = pVar->GivValString();
- if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return FALSE; }
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return FALSE; }
-
- // récupère l'élément "handle"
- pVar = pThis->GivItem("handle");
-
- // qui doit pas être initialisé
- if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return FALSE; }
-
- // reprend le nom du fichier
- pVar = pThis->GivItem("filename");
- CBotString filename = pVar->GivValString();
-
- PrepareFilename(filename); //DD! (si le nom a été attribué par h.filename = "...";
-
- // ouvre le ficher demandé
- FILE* pFile = fopen( filename, mode );
- if ( pFile == NULL ) //DR
- {
- pResult->SetValInt(FALSE); //DR
- return TRUE; //DR
- }
-
- m_CompteurFileOpen ++;
-
- // enregiste le canal du fichier
- pVar = pThis->GivItem("handle");
- pVar->SetValInt((long)pFile);
-
- pResult->SetValInt(TRUE); //DR
- return TRUE;
-}
-
-// compilation
-CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar)
-{
- // il doit y avoir un paramètre
- if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
-
- // qui doit être une chaine
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( CBotErrBadString );
-
- // il peut y avoir un second paramètre
- pVar = pVar->GivNext();
- if ( pVar != NULL )
- {
- // qui doit être une chaine
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( CBotErrBadString );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
- }
-
- // le résultat est de type bool
- return CBotTypResult(CBotTypBoolean); //DR
-}
-
-
-// méthode FILE :: close
-
-// exécution
-BOOL rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) return CBotErrOverParam;
-
- // récupère l'élément "handle"
- pVar = pThis->GivItem("handle");
-
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
-
- FILE* pFile= (FILE*)pVar->GivValInt();
- fclose(pFile);
- m_CompteurFileOpen --;
-
- pVar->SetInit(IS_NAN);
-
- return TRUE;
-}
-
-// compilation
-CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
-{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
-
- // la fonction retourne un résultat "void"
- return CBotTypResult( 0 );
-}
-
-// méthode FILE :: writeln
-
-// exécution
-BOOL rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- // il doit y avoir un paramètre
- if ( pVar == NULL ) { Exception = CBotErrLowParam; return FALSE; }
-
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return FALSE; }
-
- CBotString param = pVar->GivValString();
-
- // récupère l'élément "handle"
- pVar = pThis->GivItem("handle");
-
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
-
- FILE* pFile= (FILE*)pVar->GivValInt();
-
- int res = fputs(param+CBotString("\n"), pFile);
-
- // en cas d'erreur génère une exception
- if ( res < 0 ) { Exception = CBotErrWrite; return FALSE; }
-
- return TRUE;
-}
-
-// compilation
-CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
-{
- // il doit y avoir un paramètre
- if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
-
- // qui doit être une chaîne de caractères
- if ( pVar->GivType() != CBotTypString ) return CBotTypResult( CBotErrBadString );
-
- // pas d'autre paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
-
- // la fonction retourne un résultat void
- return CBotTypResult( 0 );
-}
-
-// méthode FILE :: readln
-
-// exécution
-BOOL rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
-
- // récupère l'élément "handle"
- pVar = pThis->GivItem("handle");
-
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
-
- FILE* pFile= (FILE*)pVar->GivValInt();
-
- char chaine[2000];
- int i;
- for ( i = 0 ; i < 2000 ; i++ ) chaine[i] = 0;
-
- fgets(chaine, 1999, pFile);
-
- for ( i = 0 ; i < 2000 ; i++ ) if (chaine[i] == '\n') chaine[i] = 0;
-
- // en cas d'erreur génère une exception
- if ( ferror(pFile) ) { Exception = CBotErrRead; return FALSE; }
-
- pResult->SetValString( chaine );
-
- return TRUE;
-}
-
-// compilation
-CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
-{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
-
- // la fonction retourne un résultat "string"
- return CBotTypResult( CBotTypString );
-}
-// méthode FILE :: readln
-
-
-// exécution
-BOOL rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
-{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) { Exception = CBotErrOverParam; return FALSE; }
-
- // récupère l'élément "handle"
- pVar = pThis->GivItem("handle");
-
- if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return FALSE; }
-
- FILE* pFile= (FILE*)pVar->GivValInt();
-
- pResult->SetValInt( feof( pFile ) );
-
- return TRUE;
-}
-
-// compilation
-CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
-{
- // il ne doit pas y avoir de paramètre
- if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
-
- // la fonction retourne un résultat booleen
- return CBotTypResult( CBotTypBoolean );
-}
-
-
-
-
-
-void InitClassFILE()
-{
-// crée une classe pour la gestion des fichiers
-// l'utilisation en est la suivante:
-// file canal( "NomFichier.txt" )
-// canal.open( "r" ); // ouvre en lecture
-// s = canal.readln( ); // lit une ligne
-// canal.close(); // referme le fichier
-
- // crée la classe FILE
- m_pClassFILE = new CBotClass("file", NULL);
- // ajoute le composant ".filename"
- m_pClassFILE->AddItem("filename", CBotTypString);
- // ajoute le composant ".handle"
- m_pClassFILE->AddItem("handle", CBotTypInt, PR_PRIVATE);
-
- // défini un constructeur et un destructeur
- m_pClassFILE->AddFunction("file", rfconstruct, cfconstruct );
- m_pClassFILE->AddFunction("~file", rfdestruct, NULL );
-
- // défini les méthodes associées
- m_pClassFILE->AddFunction("open", rfopen, cfopen );
- m_pClassFILE->AddFunction("close", rfclose, cfclose );
- m_pClassFILE->AddFunction("writeln", rfwrite, cfwrite );
- m_pClassFILE->AddFunction("readln", rfread, cfread );
- m_pClassFILE->AddFunction("eof", rfeof, cfeof );
-
- m_pFuncFile = new CBotProgram( );
- CBotStringArray ListFonctions;
- m_pFuncFile->Compile( "public file openfile(string name, string mode) {return new file(name, mode);}", ListFonctions);
- m_pFuncFile->SetIdent(-2); // identificateur spécial pour RestoreState dans cette fonction
-}
-
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// ClassFile.cpp
+//
+// definition of methods for class FILE
+
+
+
+// Static variables
+
+static CBotClass* m_pClassFILE;
+static CBotProgram* m_pFuncFile;
+static int m_CompteurFileOpen = 0;
+
+
+
+// Prepares a file name.
+
+void PrepareFilename(CBotString &filename) //DD!
+{
+ int pos;
+
+ pos = filename.ReverseFind('\\');
+ if ( pos > 0 )
+ {
+ filename = filename.Mid(pos+1); // remove the records (files)??
+ }
+
+ pos = filename.ReverseFind('/');
+ if ( pos > 0 )
+ {
+ filename = filename.Mid(pos+1); // also those with /
+ }
+
+ pos = filename.ReverseFind(':');
+ if ( pos > 0 )
+ {
+ filename = filename.Mid(pos+1); // also removes the drive letter C:
+ }
+
+ filename = CBotString("files\\") + filename;
+}
+
+
+// constructor of the class
+// gets the filename as a parameter
+
+// execution
+bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ CBotString mode;
+
+ // accepts no parameters
+ if ( pVar == NULL ) return true;
+
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
+
+ CBotString filename = pVar->GivValString();
+ PrepareFilename(filename); //DR
+
+ // there may be a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar != NULL )
+ {
+ // recovers the mode
+ mode = pVar->GivValString();
+ if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
+
+ // no third parameter, only two or one possible
+ if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return false; }
+ }
+
+ // save the file name
+ pVar = pThis->GivItem("filename");
+ pVar->SetValString(filename);
+
+ if ( ! mode.IsEmpty() )
+ {
+ // open the called file
+ FILE* pFile = fopen( filename, mode );
+ if ( pFile == NULL ) { Exception = CBotErrFileOpen; return false; }
+
+ m_CompteurFileOpen ++;
+
+ // save the handle of file
+ pVar = pThis->GivItem("handle");
+ pVar->SetValInt((long)pFile);
+ }
+
+ return true;
+}
+
+// compilation
+CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
+{
+ // accepts no parameters
+ if ( pVar == NULL ) return CBotTypResult( 0 );
+
+ // must be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( CBotErrBadString );
+
+ // there may be a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar != NULL )
+ {
+ // must be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( CBotErrBadString );
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
+ }
+
+ // le r�sultat est de type void (constructeur)
+ return CBotTypResult( 0 );
+}
+
+
+// destructor of the class
+
+// execution
+bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ // retrieves the element "handle"
+ pVar = pThis->GivItem("handle");
+
+ // not open? no problem
+ if ( pVar->GivInit() != IS_DEF) return true;
+
+ FILE* pFile= (FILE*)pVar->GivValInt();
+ fclose(pFile);
+ m_CompteurFileOpen --;
+
+ pVar->SetInit(IS_NAN);
+
+ return true;
+}
+
+
+// FILE :: open method
+// get the r / w mode as a parameter
+
+// execution
+bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ // there must be a parameter
+ if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
+
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
+
+ // there may be a second parameter
+ if ( pVar->GivNext() != NULL )
+ {
+ // in this case the first parameter is the file name
+ CBotString filename = pVar->GivValString();
+ PrepareFilename(filename); //DR
+
+ // saves the file name
+ CBotVar* pVar2 = pThis->GivItem("filename");
+ pVar2->SetValString(filename);
+
+ // next parameter is the mode
+ pVar = pVar -> GivNext();
+ }
+
+ CBotString mode = pVar->GivValString();
+ if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
+
+ // No third parameter
+ if ( pVar->GivNext() != NULL ) { Exception = CBotErrOverParam; return false; }
+
+ // retrieves the element "handle"
+ pVar = pThis->GivItem("handle");
+
+ // which must not be initialized
+ if ( pVar->GivInit() == IS_DEF) { Exception = CBotErrFileOpen; return false; }
+
+ // contains filename
+ pVar = pThis->GivItem("filename");
+ CBotString filename = pVar->GivValString();
+
+ PrepareFilename(filename); //DD! (if the name was assigned by h.filename = "...";
+
+ // open requsted file
+ FILE* pFile = fopen( filename, mode );
+ if ( pFile == NULL ) //DR
+ {
+ pResult->SetValInt(false); //DR
+ return true; //DR
+ }
+
+ m_CompteurFileOpen ++;
+
+ // saves the handle of file
+ pVar = pThis->GivItem("handle");
+ pVar->SetValInt((long)pFile);
+
+ pResult->SetValInt(true); //DR
+ return true;
+}
+
+// compilation
+CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar)
+{
+ // there must be a parameter
+ if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
+
+ // must be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( CBotErrBadString );
+
+ // there may be a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar != NULL )
+ {
+ // must be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( CBotErrBadString );
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
+ }
+
+ // the result is of type bool
+ return CBotTypResult(CBotTypBoolean); //DR
+}
+
+
+// FILE :: close method
+
+// execution
+bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ // it should not be any parameter
+ if ( pVar != NULL ) return CBotErrOverParam;
+
+ // retrieves the element "handle"
+ pVar = pThis->GivItem("handle");
+
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
+
+ FILE* pFile= (FILE*)pVar->GivValInt();
+ fclose(pFile);
+ m_CompteurFileOpen --;
+
+ pVar->SetInit(IS_NAN);
+
+ return true;
+}
+
+// compilation
+CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
+{
+ // it should not be any parameter
+ if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
+
+ // function returns a result "void"
+ return CBotTypResult( 0 );
+}
+
+// FILE :: writeln method
+
+// execution
+bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ // there must be a parameter
+ if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
+
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
+
+ CBotString param = pVar->GivValString();
+
+ //retrieves the element "handle"
+ pVar = pThis->GivItem("handle");
+
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
+
+ FILE* pFile= (FILE*)pVar->GivValInt();
+
+ int res = fputs(param+CBotString("\n"), pFile);
+
+ // on error throws an exception
+ if ( res < 0 ) { Exception = CBotErrWrite; return false; }
+
+ return true;
+}
+
+// compilation
+CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
+{
+ // there must be a parameter
+ if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
+
+ // must be a string
+ if ( pVar->GivType() != CBotTypString ) return CBotTypResult( CBotErrBadString );
+
+ // no other parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( CBotErrOverParam );
+
+ // function returns "void" result
+ return CBotTypResult( 0 );
+}
+
+// FILE :: readln method
+
+// execution
+bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ // there shouldn't be any parameter
+ if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
+
+ //retrieves the element "handle"
+ pVar = pThis->GivItem("handle");
+
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
+
+ FILE* pFile= (FILE*)pVar->GivValInt();
+
+ char chaine[2000];
+ int i;
+ for ( i = 0 ; i < 2000 ; i++ ) chaine[i] = 0;
+
+ fgets(chaine, 1999, pFile);
+
+ for ( i = 0 ; i < 2000 ; i++ ) if (chaine[i] == '\n') chaine[i] = 0;
+
+ // on error throws an exception
+ if ( ferror(pFile) ) { Exception = CBotErrRead; return false; }
+
+ pResult->SetValString( chaine );
+
+ return true;
+}
+
+// compilation
+CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
+{
+ // there shouldn't be any parameter
+ if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
+
+ // function return "string" result
+ return CBotTypResult( CBotTypString );
+}
+// FILE :: readln method
+
+
+// execution
+bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
+{
+ // there shouldn't be any parameter
+ if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
+
+ // retrieves the element "handle"
+ pVar = pThis->GivItem("handle");
+
+ if ( pVar->GivInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
+
+ FILE* pFile= (FILE*)pVar->GivValInt();
+
+ pResult->SetValInt( feof( pFile ) );
+
+ return true;
+}
+
+// compilation
+CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
+{
+ // there shouldn't be any parameter
+ if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
+
+ // function return boolean result
+ return CBotTypResult( CBotTypBoolean );
+}
+
+
+
+
+
+void InitClassFILE()
+{
+// creates a class for file management
+// the usage is as follows:
+// file canal( "NomFichier.txt" )
+// canal.open( "r" ); // open reading
+// s = canal.readln( ); // reads a line
+// canal.close(); // closes the file
+
+ // create class FILE
+ m_pClassFILE = new CBotClass("file", NULL);
+ // add the component ".filename"
+ m_pClassFILE->AddItem("filename", CBotTypString);
+ // add the component ".handle"
+ m_pClassFILE->AddItem("handle", CBotTypInt, PR_PRIVATE);
+
+ // define a constructor and destructor
+ m_pClassFILE->AddFunction("file", rfconstruct, cfconstruct );
+ m_pClassFILE->AddFunction("~file", rfdestruct, NULL );
+
+ // defined associated methods
+ m_pClassFILE->AddFunction("open", rfopen, cfopen );
+ m_pClassFILE->AddFunction("close", rfclose, cfclose );
+ m_pClassFILE->AddFunction("writeln", rfwrite, cfwrite );
+ m_pClassFILE->AddFunction("readln", rfread, cfread );
+ m_pClassFILE->AddFunction("eof", rfeof, cfeof );
+
+ m_pFuncFile = new CBotProgram( );
+ CBotStringArray ListFonctions;
+ m_pFuncFile->Compile( "public file openfile(string name, string mode) {return new file(name, mode);}", ListFonctions);
+ m_pFuncFile->SetIdent(-2); // restoreState as a special identifier for this function
+}
+
diff --git a/src/CBot/StringFunctions.cpp b/src/CBot/StringFunctions.cpp
index 2c3cfc2..39bafca 100644
--- a/src/CBot/StringFunctions.cpp
+++ b/src/CBot/StringFunctions.cpp
@@ -1,434 +1,436 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.// définition des fonctions sur les chaînes
-
-
-// donne la longueur d'une chaîne
-// exécution
-
-BOOL rStrLen( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // pas de second paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // met la longueur sur la pile
- pResult->SetValInt( s.GivLength() );
- return TRUE;
-}
-
-// int xxx ( string )
-// compilation
-
-CBotTypResult cIntStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADPARAM );
-
- // pas de second paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre entier
- return CBotTypResult( CBotTypInt );
-}
-
-
-// donne la partie gauche d'une chaîne
-// exécution
-
-BOOL rStrLeft( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return TRUE; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return TRUE; }
-
- // prend la partie intéressante
- s = s.Left( n );
-
- // la met sur la pile
- pResult->SetValString( s );
- return TRUE;
-}
-
-// string xxx ( string, int )
-// compilation
-
-CBotTypResult cStrStrInt( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-// donne la partie droite d'une chaîne
-// exécution
-
-BOOL rStrRight( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return TRUE; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return TRUE; }
-
- // prend la partie intéressante
- s = s.Right( n );
-
- // la met sur la pile
- pResult->SetValString( s );
- return TRUE;
-}
-
-// donne la partie centrale d'une chaîne
-// exécution
-
-BOOL rStrMid( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return TRUE; }
-
- // récupère ce nombre
- int n = pVar->GivValInt();
-
- // 3e paramètre optionnel
- if ( pVar->GivNext() != NULL )
- {
- pVar = pVar->GivNext();
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return TRUE; }
-
- // récupère ce nombre
- int l = pVar->GivValInt();
-
- // mais pas de 4e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return TRUE; }
-
- // prend la partie intéressante
- s = s.Mid( n, l );
- }
- else
- {
- // prend la partie intéressante
- s = s.Mid( n );
- }
-
- // la met sur la pile
- pResult->SetValString( s );
- return TRUE;
-}
-
-// donne la partie centrale d'une chaîne
-// compilation
-
-CBotTypResult cStrStrIntInt( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // 3e paramètre optionnel
- if ( pVar->GivNext() != NULL )
- {
-
- pVar = pVar->GivNext();
- // qui doit être un nombre
- if ( pVar->GivType() > CBotTypDouble )
- return CBotTypResult( TX_BADNUM );
-
- // pas de 4e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
- }
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-
-// donne le nombre contenu dans une chaîne
-// exécution
-
-BOOL rStrVal( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return TRUE; }
-
- float val = GivNumFloat(s);
-
- // la met la valeur sur la pile
- pResult->SetValFloat( val );
- return TRUE;
-}
-
-// float xxx ( string )
-// compilation
-
-CBotTypResult cFloatStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 2e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre
- return CBotTypResult( CBotTypFloat );
-}
-
-
-// trouve une chaine dans une autre
-// exécution
-
-BOOL rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // récupère ce nombre
- CBotString s2 = pVar->GivValString();
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return TRUE; }
-
- // met le résultat sur la pile
- int res = s.Find(s2);
- pResult->SetValInt( res );
- if ( res < 0 ) pResult->SetInit( IS_NAN );
- return TRUE;
-}
-
-// int xxx ( string, string )
-// compilation
-
-CBotTypResult cIntStrStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // il faut un second paramètre
- pVar = pVar->GivNext();
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 3e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est un nombre
- return CBotTypResult( CBotTypInt );
-}
-
-// donne une chaine en majuscule
-// exécution
-
-BOOL rStrUpper( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return TRUE; }
-
-
- s.MakeUpper();
-
- // la met la valeur sur la pile
- pResult->SetValString( s );
- return TRUE;
-}
-
-// donne une chaine en minuscules
-// exécution
-
-BOOL rStrLower( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) { ex = TX_LOWPARAM ; return TRUE; }
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return TRUE; }
-
- // recupére le contenu de la string
- CBotString s = pVar->GivValString();
-
- // mais pas de 2e paramètre
- if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return TRUE; }
-
-
- s.MakeLower();
-
- // la met la valeur sur la pile
- pResult->SetValString( s );
- return TRUE;
-}
-
-// string xxx ( string )
-// compilation
-
-CBotTypResult cStrStr( CBotVar* &pVar, void* pUser )
-{
- // il faut un paramètre
- if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
-
- // qui doit être une string
- if ( pVar->GivType() != CBotTypString )
- return CBotTypResult( TX_BADSTRING );
-
- // pas de 2e paramètre
- if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
-
- // le résultat final est une string
- return CBotTypResult( CBotTypString );
-}
-
-
-void InitStringFunctions()
-{
- CBotProgram::AddFunction("strlen", rStrLen, cIntStr );
- CBotProgram::AddFunction("strleft", rStrLeft, cStrStrInt );
- CBotProgram::AddFunction("strright", rStrRight, cStrStrInt );
- CBotProgram::AddFunction("strmid", rStrMid, cStrStrIntInt );
-
- CBotProgram::AddFunction("strval", rStrVal, cFloatStr );
- CBotProgram::AddFunction("strfind", rStrFind, cIntStrStr );
-
- CBotProgram::AddFunction("strupper", rStrUpper, cStrStr );
- CBotProgram::AddFunction("strlower", rStrLower, cStrStr );
-}
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// definition of string functions
+
+
+// gives the length of a chain
+// execution
+
+bool rStrLen( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // puts the length of the stack
+ pResult->SetValInt( s.GivLength() );
+ return true;
+}
+
+// int xxx ( string )
+// compilation
+
+CBotTypResult cIntStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADPARAM );
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is an integer
+ return CBotTypResult( CBotTypInt );
+}
+
+
+// gives the left side of a chain
+// execution
+
+bool rStrLeft( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int n = pVar->GivValInt();
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // takes the interesting part
+ s = s.Left( n );
+
+ // puts on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// string xxx ( string, int )
+// compilation
+
+CBotTypResult cStrStrInt( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble )
+ return CBotTypResult( TX_BADNUM );
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a string
+ return CBotTypResult( CBotTypString );
+}
+
+// gives the right of a string
+// execution
+
+bool rStrRight( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int n = pVar->GivValInt();
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // takes the interesting part
+ s = s.Right( n );
+
+ // puts on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// gives the central part of a chain
+// execution
+
+bool rStrMid( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int n = pVar->GivValInt();
+
+ // third parameter optional
+ if ( pVar->GivNext() != NULL )
+ {
+ pVar = pVar->GivNext();
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble ) { ex = TX_BADNUM ; return true; }
+
+ // retrieves this number
+ int l = pVar->GivValInt();
+
+ // but no fourth parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+ // takes the interesting part
+ s = s.Mid( n, l );
+ }
+ else
+ {
+ // takes the interesting part
+ s = s.Mid( n );
+ }
+
+ // puts on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// gives the central part of a chain
+// compilation
+
+CBotTypResult cStrStrIntInt( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble )
+ return CBotTypResult( TX_BADNUM );
+
+ // third parameter optional
+ if ( pVar->GivNext() != NULL )
+ {
+
+ pVar = pVar->GivNext();
+ // which must be a number
+ if ( pVar->GivType() > CBotTypDouble )
+ return CBotTypResult( TX_BADNUM );
+
+ // no fourth parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+ }
+
+ // the end result is a string
+ return CBotTypResult( CBotTypString );
+}
+
+
+// gives the number stored in a string
+// execution
+
+bool rStrVal( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // but no second parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+ float val = GivNumFloat(s);
+
+ // puts the value on the stack
+ pResult->SetValFloat( val );
+ return true;
+}
+
+// float xxx ( string )
+// compilation
+
+CBotTypResult cFloatStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a number
+ return CBotTypResult( CBotTypFloat );
+}
+
+
+// find string in other
+// exécution
+
+bool rStrFind( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // retrieves this number
+ CBotString s2 = pVar->GivValString();
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) { ex = TX_OVERPARAM ; return true; }
+
+ // puts the result on the stack
+ int res = s.Find(s2);
+ pResult->SetValInt( res );
+ if ( res < 0 ) pResult->SetInit( IS_NAN );
+ return true;
+}
+
+// int xxx ( string, string )
+// compilation
+
+CBotTypResult cIntStrStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // it takes a second parameter
+ pVar = pVar->GivNext();
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // no third parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a number
+ return CBotTypResult( CBotTypInt );
+}
+
+// gives a string to uppercase
+// exécution
+
+bool rStrUpper( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // but no second parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+
+ s.MakeUpper();
+
+ // puts the value on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// gives a string to lowercase
+// exécution
+
+bool rStrLower( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) { ex = TX_LOWPARAM ; return true; }
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString ) { ex = TX_BADSTRING ; return true; }
+
+ // get the contents of the string
+ CBotString s = pVar->GivValString();
+
+ // but no second parameter
+ if ( pVar->GivNext() != NULL ){ ex = TX_OVERPARAM ; return true; }
+
+
+ s.MakeLower();
+
+ // puts the value on the stack
+ pResult->SetValString( s );
+ return true;
+}
+
+// string xxx ( string )
+// compilation
+
+CBotTypResult cStrStr( CBotVar* &pVar, void* pUser )
+{
+ // it takes a parameter
+ if ( pVar == NULL ) return CBotTypResult( TX_LOWPARAM );
+
+ // to be a string
+ if ( pVar->GivType() != CBotTypString )
+ return CBotTypResult( TX_BADSTRING );
+
+ // no second parameter
+ if ( pVar->GivNext() != NULL ) return CBotTypResult( TX_OVERPARAM );
+
+ // the end result is a string
+ return CBotTypResult( CBotTypString );
+}
+
+
+void InitStringFunctions()
+{
+ CBotProgram::AddFunction("strlen", rStrLen, cIntStr );
+ CBotProgram::AddFunction("strleft", rStrLeft, cStrStrInt );
+ CBotProgram::AddFunction("strright", rStrRight, cStrStrInt );
+ CBotProgram::AddFunction("strmid", rStrMid, cStrStrIntInt );
+
+ CBotProgram::AddFunction("strval", rStrVal, cFloatStr );
+ CBotProgram::AddFunction("strfind", rStrFind, cIntStrStr );
+
+ CBotProgram::AddFunction("strupper", rStrUpper, cStrStr );
+ CBotProgram::AddFunction("strlower", rStrLower, cStrStr );
+}
diff --git a/src/CBot/_Copy.bat b/src/CBot/_Copy.bat
deleted file mode 100644
index 510dc5a..0000000
--- a/src/CBot/_Copy.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-copy debug\cbot.dll "F:\Program Files\Ceebot\cbot.dll"
-cls \ No newline at end of file
diff --git a/src/CBot/colobot.ini b/src/CBot/colobot.ini
deleted file mode 100644
index 32163db..0000000
--- a/src/CBot/colobot.ini
+++ /dev/null
@@ -1,49 +0,0 @@
-[Directory]
-scene=scene
-savegame=savegame
-public=program
-user=user
-[Setup]
-TotoMode=1
-Tooltips=1
-InterfaceGlint=1
-NiceMouse=0
-Movies=1
-NiceReset=1
-HimselfDamage=1
-CameraScroll=1
-CameraInvertX=0
-InterfaceEffect=1
-GroundShadow=1
-GroundSpot=1
-ObjectDirty=1
-FogMode=1
-LensMode=1
-SkyMode=1
-PlanetMode=1
-LightMode=1
-UseJoystick=0
-ParticuleDensity=1.00
-ClippingDistance=1.00
-ObjectDetail=2.00
-GadgetQuantity=1.00
-TextureQuality=1
-AudioVolume=20
-MidiVolume=15
-Sound3D=0
-EditIndentMode=1
-EditIndentValue=4
-KeyMap=37+0 39+0 38+0 40+0 16+0 17+0 32+258 96+262 13+257 107+261 109+260 9+259 36+263 27+0 112+0 113+0 110+0 115+0 116+0 117+0
-[Engine]
-AlphaMode=1
-StateColor=-1
-BlackSrcBlend=0
-BlackDestBlend=0
-WhiteSrcBlend=0
-WhiteDestBlend=0
-DiffuseSrcBlend=0
-DiffuseDestBlend=0
-AlphaSrcBlend=0
-AlphaDestBlend=0
-[Gamer]
-LastName=Player
diff --git a/src/CBot/idees.txt b/src/CBot/idees.txt
index 7153789..3966ee1 100644
--- a/src/CBot/idees.txt
+++ b/src/CBot/idees.txt
@@ -1,39 +1,41 @@
-pour la gestion des instances d'une classe.
-l'objet créé actuellement avec CBotVar::Create(nom, pClasse)
-est a conserver tel quel, en dehors des vars sur la pile
+for managing instances of a class.
-il faut un autre type de variable pour garder les pointeurs
-CBotTypPtClass par exemple
+the object being created with CBotVar :: Create (name, pClasse)
+ is to keep as is, outside the vars on the stack
-L'instance de la classe doit avoir un compteur d'utilisation
-qui est le nombre d'objet de classe CBotTypPtClass qui y réfèrent.
-Le compteur est décrémenté lorsque le pointeur est détruit,
-l'objet supprimé lorsqu'il n'y a plus de pointeurs.
+ we need another type of variable to keep the pointers
+ For example CBotTypPtClass
+ The instance of the class must have a usage count
+ which is the number of class object to which they refer CBotTypPtClass.
+ The counter is decremented when the pointer is destroyed,
+ be deleted when there is more pointers.
-Dans le cas des robots, Daniel crée une instance de sa classe "Object"
-et peut retourner des pointeurs à cette instance par des routines genre FindRobot()
-Object FindRobot(int n) { }
+ In the case of robots, Daniel creates an instance of class "Object"
+ and can return pointers to this proceeding by routines such FindRobot ()
-pResult dans ce cas est un pointeur CBotTypPtClass
-lorsqu'il a trouvé le robot concerné, il lui faudra faire
+ Object FindRobot (int n) {}
-pResult->SetPointeur(InstanceDeLaClassObject);
+ pResult in this case is a pointer CBotTypPtClass
+ when he found the robot concerned, it must make
-cette opération incrémente le compteur des références
+ pResult-> SetPointeur (InstanceDeLaClassObject);
---
+ this operation increments the reference
-lorsque le robot est détruit, l'instance de la classe Object correspondant
-est détruit également.
-s'il reste des pointeurs à cet objet, et l'on risque la planté
+ -
-solution 1:
- garder non pas le pointeur à l'objet directement, mais
- un index dans une tables de pointeurs
+ when the robot is destroyed, the instance of the Object class corresponding
+ is also destroyed.
+ if there are pointers to that object, and we planted the risk
+
+ Solution 1:
+ not keep the pointer to the object directly, but
+ an index into a table of pointers
+
+ Solution 2:
+ not destroy the object when there imédiatement pointers
+ but marked as virtually destroyed
-solution 2:
- ne pas détruire l'objet imédiatement lorsqu'il reste des pointeurs
- mais le marqué comme virtuellement détruit \ No newline at end of file
diff --git a/src/CBot/old b/src/CBot/old
deleted file mode 100644
index ea18736..0000000
--- a/src/CBot/old
+++ /dev/null
@@ -1,15 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/. \ No newline at end of file
diff --git a/src/CBot/resource.h b/src/CBot/resource.h
index 7e57d32..96a01ba 100644
--- a/src/CBot/resource.h
+++ b/src/CBot/resource.h
@@ -1,180 +1,177 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.//{{NO_DEPENDENCIES}}
-// Microsoft Developer Studio generated include file.
-// Used by CBot.rc
-//
-#define ID_KEYWORDS 2000
-#define ID_IF 2000
-#define ID_ELSE 2001
-#define ID_WHILE 2002
-#define ID_DO 2003
-#define ID_FOR 2004
-#define ID_BREAK 2005
-#define ID_CONTINUE 2006
-#define ID_SWITCH 2007
-#define ID_CASE 2008
-#define ID_DEFAULT 2009
-#define ID_TRY 2010
-#define ID_THROW 2011
-#define ID_CATCH 2012
-#define ID_FINALLY 2013
-#define ID_TXT_AND 2014
-#define ID_TXT_OR 2015
-#define ID_TXT_NOT 2016
-#define ID_RETURN 2017
-#define ID_CLASS 2018
-#define ID_EXTENDS 2019
-#define ID_SYNCHO 2020
-#define ID_NEW 2021
-#define ID_PUBLIC 2022
-#define ID_EXTERN 2023
-#define ID_FINAL 2024
-#define ID_STATIC 2025
-#define ID_PROTECTED 2026
-#define ID_PRIVATE 2027
-#define ID_REPEAT 2028
-#define ID_DEBUGDD 2099
-#define ID_INT 2100
-#define ID_FLOAT 2101
-#define ID_BOOLEAN 2102
-#define ID_STRING 2103
-#define ID_VOID 2104
-#define ID_BOOL 2105
-#define ID_TRUE 2200
-#define ID_FALSE 2201
-#define ID_NULL 2202
-#define ID_NAN 2203
-#define ID_OPENPAR 2300
-#define ID_CLOSEPAR 2301
-#define ID_OPBLK 2302
-#define ID_CLBLK 2303
-#define ID_SEP 2304
-#define ID_COMMA 2305
-#define ID_DOTS 2306
-#define ID_DOT 2307
-#define ID_OPBRK 2308
-#define ID_CLBRK 2309
-#define ID_DBLDOTS 2310
-#define ID_LOGIC 2311
-#define ID_ADD 2312
-#define ID_SUB 2313
-#define ID_MUL 2314
-#define ID_DIV 2315
-#define ID_ASS 2316
-#define ID_ASSADD 2317
-#define ID_ASSSUB 2318
-#define ID_ASSMUL 2319
-#define ID_ASSDIV 2320
-#define ID_ASSOR 2321
-#define ID_ASSAND 2322
-#define ID_ASSXOR 2323
-#define ID_ASSSL 2324
-#define ID_ASSSR 2325
-#define ID_ASSASR 2326
-#define ID_SL 2327
-#define ID_SR 2328
-#define ID_ASR 2329
-#define ID_INC 2330
-#define ID_DEC 2331
-#define ID_LO 2332
-#define ID_HI 2333
-#define ID_LS 2334
-#define ID_HS 2335
-#define ID_EQ 2336
-#define ID_NE 2337
-#define ID_AND 2338
-#define ID_XOR 2339
-#define ID_OR 2340
-#define ID_LOG_AND 2341
-#define ID_LOG_OR 2342
-#define ID_LOG_NOT 2343
-#define ID_NOT 2344
-#define ID_MODULO 2345
-#define ID_POWER 2346
-#define ID_ASSMODULO 2347
-#define TX_UNDEF 4000
-#define TX_NAN 4001
-#define TX_OPENPAR 5000
-#define TX_CLOSEPAR 5001
-#define TX_NOTBOOL 5002
-#define TX_UNDEFVAR 5003
-#define TX_BADLEFT 5004
-#define TX_ENDOF 5005
-#define TX_OUTCASE 5006
-#define TX_NOTERM 5007
-#define TX_CLOSEBLK 5008
-#define TX_ELSEWITHOUTIF 5009
-#define TX_OPENBLK 5010
-#define TX_BADTYPE 5011
-#define TX_REDEFVAR 5012
-#define TX_BAD2TYPE 5013
-#define TX_UNDEFCALL 5014
-#define TX_MISDOTS 5015
-#define TX_WHILE 5016
-#define TX_BREAK 5017
-#define TX_LABEL 5018
-#define TX_NOLABEL 5019
-#define TX_NOCASE 5020
-#define TX_BADNUM 5021
-#define TX_VOID 5022
-#define TX_NOTYP 5023
-#define TX_NOVAR 5024
-#define TX_NOFONC 5025
-#define TX_OVERPARAM 5026
-#define TX_REDEF 5027
-#define TX_LOWPARAM 5028
-#define TX_BADPARAM 5029
-#define TX_NUMPARAM 5030
-#define TX_NOITEM 5031
-#define TX_DOT 5032
-#define TX_NOCONST 5033
-#define TX_REDEFCLASS 5034
-#define TX_CLBRK 5035
-#define TX_RESERVED 5036
-#define TX_BADNEW 5037
-#define TX_OPBRK 5038
-#define TX_BADSTRING 5039
-#define TX_BADINDEX 5040
-#define TX_PRIVATE 5041
-#define TX_NOPUBLIC 5042
-#define TX_DIVZERO 6000
-#define TX_NOTINIT 6001
-#define TX_BADTHROW 6002
-#define TX_NORETVAL 6003
-#define TX_NORUN 6004
-#define TX_NOCALL 6005
-#define TX_NOCLASS 6006
-#define TX_NULLPT 6007
-#define TX_OPNAN 6008
-#define TX_OUTARRAY 6009
-#define TX_STACKOVER 6010
-#define TX_DELETEDPT 6011
-#define TX_FILEOPEN 6012
-#define TX_NOTOPEN 6013
-#define TX_ERRREAD 6014
-#define TX_ERRWRITE 6015
-#define ID_SUPER 62020
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 101
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1000
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+#pragma once
+#ifndef _RESOURCE_H_
+#define _RESOURCE_H_
+
+enum EID
+{
+ ID_IF = 2000,
+ ID_ELSE,
+ ID_WHILE,
+ ID_DO,
+ ID_FOR,
+ ID_BREAK,
+ ID_CONTINUE,
+ ID_SWITCH,
+ ID_CASE,
+ ID_DEFAULT,
+ ID_TRY,
+ ID_THROW,
+ ID_CATCH,
+ ID_FINALLY,
+ ID_TXT_AND,
+ ID_TXT_OR,
+ ID_TXT_NOT,
+ ID_RETURN,
+ ID_CLASS,
+ ID_EXTENDS,
+ ID_SYNCHO,
+ ID_NEW,
+ ID_PUBLIC,
+ ID_EXTERN,
+ ID_FINAL,
+ ID_STATIC,
+ ID_PROTECTED,
+ ID_PRIVATE,
+ ID_REPEAT,
+ ID_DEBUGDD,
+ ID_INT,
+ ID_FLOAT,
+ ID_BOOLEAN,
+ ID_STRING,
+ ID_VOID,
+ ID_BOOL,
+
+ ID_TRUE = 2200,
+ ID_FALSE,
+ ID_NULL,
+ ID_NAN,
+
+ ID_OPENPAR = 2300,
+ ID_CLOSEPAR,
+ ID_OPBLK,
+ ID_CLBLK,
+ ID_SEP,
+ ID_COMMA,
+ ID_DOTS,
+ ID_DOT,
+ ID_OPBRK,
+ ID_CLBRK,
+ ID_DBLDOTS,
+ ID_LOGIC,
+ ID_ADD,
+ ID_SUB,
+ ID_MUL,
+ ID_DIV,
+ ID_ASS,
+ ID_ASSADD,
+ ID_ASSSUB,
+ ID_ASSMUL,
+ ID_ASSDIV,
+ ID_ASSOR,
+ ID_ASSAND,
+ ID_ASSXOR,
+ ID_ASSSL,
+ ID_ASSSR,
+ ID_ASSASR,
+ ID_SL,
+ ID_SR,
+ ID_ASR,
+ ID_INC,
+ ID_DEC,
+ ID_LO,
+ ID_HI,
+ ID_LS,
+ ID_HS,
+ ID_EQ,
+ ID_NE,
+ ID_AND,
+ ID_XOR,
+ ID_OR,
+ ID_LOG_AND,
+ ID_LOG_OR,
+ ID_LOG_NOT,
+ ID_NOT,
+ ID_MODULO,
+ ID_POWER,
+ ID_ASSMODULO,
+ TX_UNDEF = 4000,
+ TX_NAN,
+ ID_SUPER = 6000
+};
+#define TX_OPENPAR 5000
+#define TX_CLOSEPAR 5001
+#define TX_NOTBOOL 5002
+#define TX_UNDEFVAR 5003
+#define TX_BADLEFT 5004
+#define TX_ENDOF 5005
+#define TX_OUTCASE 5006
+#define TX_NOTERM 5007
+#define TX_CLOSEBLK 5008
+#define TX_ELSEWITHOUTIF 5009
+#define TX_OPENBLK 5010
+#define TX_BADTYPE 5011
+#define TX_REDEFVAR 5012
+#define TX_BAD2TYPE 5013
+#define TX_UNDEFCALL 5014
+#define TX_MISDOTS 5015
+#define TX_WHILE 5016
+#define TX_BREAK 5017
+#define TX_LABEL 5018
+#define TX_NOLABEL 5019
+#define TX_NOCASE 5020
+#define TX_BADNUM 5021
+#define TX_VOID 5022
+#define TX_NOTYP 5023
+#define TX_NOVAR 5024
+#define TX_NOFONC 5025
+#define TX_OVERPARAM 5026
+#define TX_REDEF 5027
+#define TX_LOWPARAM 5028
+#define TX_BADPARAM 5029
+#define TX_NUMPARAM 5030
+#define TX_NOITEM 5031
+#define TX_DOT 5032
+#define TX_NOCONST 5033
+#define TX_REDEFCLASS 5034
+#define TX_CLBRK 5035
+#define TX_RESERVED 5036
+#define TX_BADNEW 5037
+#define TX_OPBRK 5038
+#define TX_BADSTRING 5039
+#define TX_BADINDEX 5040
+#define TX_PRIVATE 5041
+#define TX_NOPUBLIC 5042
+#define TX_DIVZERO 6000
+#define TX_NOTINIT 6001
+#define TX_BADTHROW 6002
+#define TX_NORETVAL 6003
+#define TX_NORUN 6004
+#define TX_NOCALL 6005
+#define TX_NOCLASS 6006
+#define TX_NULLPT 6007
+#define TX_OPNAN 6008
+#define TX_OUTARRAY 6009
+#define TX_STACKOVER 6010
+#define TX_DELETEDPT 6011
+#define TX_FILEOPEN 6012
+#define TX_NOTOPEN 6013
+#define TX_ERRREAD 6014
+#define TX_ERRWRITE 6015
+
+#endif //_RESOURCE_H_
diff --git a/src/CBot/TestCBot/CBotConsoleDlg.cpp b/src/CBot/tests/TestCBot/CBotConsoleDlg.cpp
index 55a271a..55a271a 100644
--- a/src/CBot/TestCBot/CBotConsoleDlg.cpp
+++ b/src/CBot/tests/TestCBot/CBotConsoleDlg.cpp
diff --git a/src/CBot/TestCBot/CBotConsoleDlg.h b/src/CBot/tests/TestCBot/CBotConsoleDlg.h
index f289a4d..f289a4d 100644
--- a/src/CBot/TestCBot/CBotConsoleDlg.h
+++ b/src/CBot/tests/TestCBot/CBotConsoleDlg.h
diff --git a/src/CBot/TestCBot/ChildFrm.cpp b/src/CBot/tests/TestCBot/ChildFrm.cpp
index 4c40f90..4c40f90 100644
--- a/src/CBot/TestCBot/ChildFrm.cpp
+++ b/src/CBot/tests/TestCBot/ChildFrm.cpp
diff --git a/src/CBot/TestCBot/ChildFrm.h b/src/CBot/tests/TestCBot/ChildFrm.h
index 2ad57b6..2ad57b6 100644
--- a/src/CBot/TestCBot/ChildFrm.h
+++ b/src/CBot/tests/TestCBot/ChildFrm.h
diff --git a/src/CBot/TestCBot/MainFrm.cpp b/src/CBot/tests/TestCBot/MainFrm.cpp
index 6669350..6669350 100644
--- a/src/CBot/TestCBot/MainFrm.cpp
+++ b/src/CBot/tests/TestCBot/MainFrm.cpp
diff --git a/src/CBot/TestCBot/MainFrm.h b/src/CBot/tests/TestCBot/MainFrm.h
index a1d34f4..a1d34f4 100644
--- a/src/CBot/TestCBot/MainFrm.h
+++ b/src/CBot/tests/TestCBot/MainFrm.h
diff --git a/src/CBot/TestCBot/PerformDlg.cpp b/src/CBot/tests/TestCBot/PerformDlg.cpp
index 8abbb4b..8abbb4b 100644
--- a/src/CBot/TestCBot/PerformDlg.cpp
+++ b/src/CBot/tests/TestCBot/PerformDlg.cpp
diff --git a/src/CBot/TestCBot/PerformDlg.h b/src/CBot/tests/TestCBot/PerformDlg.h
index 29d567f..29d567f 100644
--- a/src/CBot/TestCBot/PerformDlg.h
+++ b/src/CBot/tests/TestCBot/PerformDlg.h
diff --git a/src/CBot/TestCBot/Routines.cpp b/src/CBot/tests/TestCBot/Routines.cpp
index b37f027..b37f027 100644
--- a/src/CBot/TestCBot/Routines.cpp
+++ b/src/CBot/tests/TestCBot/Routines.cpp
diff --git a/src/CBot/TestCBot/StdAfx.cpp b/src/CBot/tests/TestCBot/StdAfx.cpp
index 7dd0f00..7dd0f00 100644
--- a/src/CBot/TestCBot/StdAfx.cpp
+++ b/src/CBot/tests/TestCBot/StdAfx.cpp
diff --git a/src/CBot/TestCBot/StdAfx.h b/src/CBot/tests/TestCBot/StdAfx.h
index c3659fb..c3659fb 100644
--- a/src/CBot/TestCBot/StdAfx.h
+++ b/src/CBot/tests/TestCBot/StdAfx.h
diff --git a/src/CBot/TestCBot/TestCBot.clw b/src/CBot/tests/TestCBot/TestCBot.clw
index 13f20f4..13f20f4 100644
--- a/src/CBot/TestCBot/TestCBot.clw
+++ b/src/CBot/tests/TestCBot/TestCBot.clw
diff --git a/src/CBot/TestCBot/TestCBot.cpp b/src/CBot/tests/TestCBot/TestCBot.cpp
index a76040a..a76040a 100644
--- a/src/CBot/TestCBot/TestCBot.cpp
+++ b/src/CBot/tests/TestCBot/TestCBot.cpp
diff --git a/src/CBot/TestCBot/TestCBot.dsp b/src/CBot/tests/TestCBot/TestCBot.dsp
index 8ed9b11..8ed9b11 100644
--- a/src/CBot/TestCBot/TestCBot.dsp
+++ b/src/CBot/tests/TestCBot/TestCBot.dsp
diff --git a/src/CBot/TestCBot/TestCBot.h b/src/CBot/tests/TestCBot/TestCBot.h
index b3b15db..c2595b6 100644
--- a/src/CBot/TestCBot/TestCBot.h
+++ b/src/CBot/tests/TestCBot/TestCBot.h
@@ -26,7 +26,7 @@
#error include 'stdafx.h' before including this file for PCH
#endif
-#include "resource.h" // main symbols
+#include "resource.h" // main symbols
//#include "../CbotDll.h" // librairie CBot
#include "../Cbot.h" // complet pour Browse
@@ -43,7 +43,7 @@ public:
CTestCBotApp();
CEdit* m_pConsole;
- CTestCBotView* m_LastActive;
+ CTestCBotView* m_LastActive;
CBotClass* m_pClassPoint;
CBotClass* m_pClassPointIntr;
diff --git a/src/CBot/TestCBot/TestCBot.rc b/src/CBot/tests/TestCBot/TestCBot.rc
index 137458c..137458c 100644
--- a/src/CBot/TestCBot/TestCBot.rc
+++ b/src/CBot/tests/TestCBot/TestCBot.rc
diff --git a/src/CBot/TestCBot/TestCBotDoc.cpp b/src/CBot/tests/TestCBot/TestCBotDoc.cpp
index 8880c57..8880c57 100644
--- a/src/CBot/TestCBot/TestCBotDoc.cpp
+++ b/src/CBot/tests/TestCBot/TestCBotDoc.cpp
diff --git a/src/CBot/TestCBot/TestCBotDoc.h b/src/CBot/tests/TestCBot/TestCBotDoc.h
index 548607f..548607f 100644
--- a/src/CBot/TestCBot/TestCBotDoc.h
+++ b/src/CBot/tests/TestCBot/TestCBotDoc.h
diff --git a/src/CBot/TestCBot/TestCBotView.cpp b/src/CBot/tests/TestCBot/TestCBotView.cpp
index bca3c56..bca3c56 100644
--- a/src/CBot/TestCBot/TestCBotView.cpp
+++ b/src/CBot/tests/TestCBot/TestCBotView.cpp
diff --git a/src/CBot/TestCBot/TestCBotView.h b/src/CBot/tests/TestCBot/TestCBotView.h
index 065ee08..065ee08 100644
--- a/src/CBot/TestCBot/TestCBotView.h
+++ b/src/CBot/tests/TestCBot/TestCBotView.h
diff --git a/src/CBot/TestCBot/a§1.txt b/src/CBot/tests/TestCBot/a§1.txt~
index 0c57950..0c57950 100644
--- a/src/CBot/TestCBot/a§1.txt
+++ b/src/CBot/tests/TestCBot/a§1.txt~
diff --git a/src/CBot/TestCBot/res/TestCBot.ico b/src/CBot/tests/TestCBot/res/TestCBot.ico
index 06a649d..06a649d 100644
--- a/src/CBot/TestCBot/res/TestCBot.ico
+++ b/src/CBot/tests/TestCBot/res/TestCBot.ico
Binary files differ
diff --git a/src/CBot/TestCBot/res/TestCBot.rc2 b/src/CBot/tests/TestCBot/res/TestCBot.rc2
index b55f0d9..b55f0d9 100644
--- a/src/CBot/TestCBot/res/TestCBot.rc2
+++ b/src/CBot/tests/TestCBot/res/TestCBot.rc2
diff --git a/src/CBot/TestCBot/res/TestCBotDoc.ico b/src/CBot/tests/TestCBot/res/TestCBotDoc.ico
index 3545614..3545614 100644
--- a/src/CBot/TestCBot/res/TestCBotDoc.ico
+++ b/src/CBot/tests/TestCBot/res/TestCBotDoc.ico
Binary files differ
diff --git a/src/CBot/TestCBot/res/Toolbar.bmp b/src/CBot/tests/TestCBot/res/Toolbar.bmp
index 04a71af..04a71af 100644
--- a/src/CBot/TestCBot/res/Toolbar.bmp
+++ b/src/CBot/tests/TestCBot/res/Toolbar.bmp
Binary files differ
diff --git a/src/CBot/TestCBot/resource.h b/src/CBot/tests/TestCBot/resource.h
index d661201..d661201 100644
--- a/src/CBot/TestCBot/resource.h
+++ b/src/CBot/tests/TestCBot/resource.h
diff --git a/src/CBot/TestCBot/B.txt b/src/CBot/tests/TestCBot/scenarios/B.txt
index 53715f8..53715f8 100644
--- a/src/CBot/TestCBot/B.txt
+++ b/src/CBot/tests/TestCBot/scenarios/B.txt
diff --git a/src/CBot/TestCBot/BUG2.txt b/src/CBot/tests/TestCBot/scenarios/BUG2.txt
index 44de05a..44de05a 100644
--- a/src/CBot/TestCBot/BUG2.txt
+++ b/src/CBot/tests/TestCBot/scenarios/BUG2.txt
diff --git a/src/CBot/TestCBot/Deleted.txt b/src/CBot/tests/TestCBot/scenarios/Deleted.txt
index 469a624..469a624 100644
--- a/src/CBot/TestCBot/Deleted.txt
+++ b/src/CBot/tests/TestCBot/scenarios/Deleted.txt
diff --git a/src/CBot/TestCBot/MaClass.txt b/src/CBot/tests/TestCBot/scenarios/MaClass.txt
index ac472b4..ac472b4 100644
--- a/src/CBot/TestCBot/MaClass.txt
+++ b/src/CBot/tests/TestCBot/scenarios/MaClass.txt
diff --git a/src/CBot/TestCBot/Mc2.txt b/src/CBot/tests/TestCBot/scenarios/Mc2.txt
index 172c259..172c259 100644
--- a/src/CBot/TestCBot/Mc2.txt
+++ b/src/CBot/tests/TestCBot/scenarios/Mc2.txt
diff --git a/src/CBot/TestCBot/Mon fichier.txt b/src/CBot/tests/TestCBot/scenarios/Mon fichier.txt
index 6b35bf8..6b35bf8 100644
--- a/src/CBot/TestCBot/Mon fichier.txt
+++ b/src/CBot/tests/TestCBot/scenarios/Mon fichier.txt
diff --git a/src/CBot/TestCBot/Nop.txt b/src/CBot/tests/TestCBot/scenarios/Nop.txt
index 6a66f6f..6a66f6f 100644
--- a/src/CBot/TestCBot/Nop.txt
+++ b/src/CBot/tests/TestCBot/scenarios/Nop.txt
diff --git a/src/CBot/TestCBot/POS.txt b/src/CBot/tests/TestCBot/scenarios/POS.txt
index 688e4fb..688e4fb 100644
--- a/src/CBot/TestCBot/POS.txt
+++ b/src/CBot/tests/TestCBot/scenarios/POS.txt
diff --git a/src/CBot/TestCBot/T.txt b/src/CBot/tests/TestCBot/scenarios/T.txt
index 50a792b..50a792b 100644
--- a/src/CBot/TestCBot/T.txt
+++ b/src/CBot/tests/TestCBot/scenarios/T.txt
diff --git a/src/CBot/TestCBot/TESTALL.txt b/src/CBot/tests/TestCBot/scenarios/TESTALL.txt
index 82247a0..82247a0 100644
--- a/src/CBot/TestCBot/TESTALL.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TESTALL.txt
diff --git a/src/CBot/TestCBot/TestCB1.txt b/src/CBot/tests/TestCBot/scenarios/TestCB1.txt
index 516db47..516db47 100644
--- a/src/CBot/TestCBot/TestCB1.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestCB1.txt
diff --git a/src/CBot/TestCBot/TestCBot1.txt b/src/CBot/tests/TestCBot/scenarios/TestCBot1.txt
index d27b4f8..d27b4f8 100644
--- a/src/CBot/TestCBot/TestCBot1.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestCBot1.txt
diff --git a/src/CBot/TestCBot/TestCBot3.txt b/src/CBot/tests/TestCBot/scenarios/TestCBot3.txt
index b915f96..b915f96 100644
--- a/src/CBot/TestCBot/TestCBot3.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestCBot3.txt
diff --git a/src/CBot/TestCBot/TestNull.txt b/src/CBot/tests/TestCBot/scenarios/TestNull.txt
index f447245..f447245 100644
--- a/src/CBot/TestCBot/TestNull.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestNull.txt
diff --git a/src/CBot/TestCBot/TestRestoreState.txt b/src/CBot/tests/TestCBot/scenarios/TestRestoreState.txt
index 1e49e37..1e49e37 100644
--- a/src/CBot/TestCBot/TestRestoreState.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestRestoreState.txt
diff --git a/src/CBot/TestCBot/TestStatic.txt b/src/CBot/tests/TestCBot/scenarios/TestStatic.txt
index f501aa5..f501aa5 100644
--- a/src/CBot/TestCBot/TestStatic.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestStatic.txt
diff --git a/src/CBot/TestCBot/TestStr.txt b/src/CBot/tests/TestCBot/scenarios/TestStr.txt
index 683ec1b..683ec1b 100644
--- a/src/CBot/TestCBot/TestStr.txt
+++ b/src/CBot/tests/TestCBot/scenarios/TestStr.txt
diff --git a/src/CBot/TestCBot/Z.txt b/src/CBot/tests/TestCBot/scenarios/Z.txt
index 714119b..714119b 100644
--- a/src/CBot/TestCBot/Z.txt
+++ b/src/CBot/tests/TestCBot/scenarios/Z.txt
diff --git a/src/CBot/TestCBot/až1.txt b/src/CBot/tests/TestCBot/scenarios/a1.txt
index 165bc95..165bc95 100644
--- a/src/CBot/TestCBot/až1.txt
+++ b/src/CBot/tests/TestCBot/scenarios/a1.txt
diff --git a/src/CBot/TestCBot/array.txt b/src/CBot/tests/TestCBot/scenarios/array.txt
index 081b60e..081b60e 100644
--- a/src/CBot/TestCBot/array.txt
+++ b/src/CBot/tests/TestCBot/scenarios/array.txt
diff --git a/src/CBot/tests/TestCBot/scenarios/až1.txt b/src/CBot/tests/TestCBot/scenarios/až1.txt
new file mode 100644
index 0000000..165bc95
--- /dev/null
+++ b/src/CBot/tests/TestCBot/scenarios/až1.txt
@@ -0,0 +1,96 @@
+object radarGuepe(point orig, float dist)
+{
+ int i;
+ object pr, r;
+ float mindist;
+
+ i = 0;
+ mindist = 1000;
+ while (i<30)
+ {
+ pr = radar(i);
+ if (pr != null)
+ {
+
+ if (F(orig, pr.position) < mindist and pr.category == AlienWasp and pr.altitude > 3)
+ {
+ mindist = distance(orig, pr.position);
+ r = pr;
+ }
+ }
+ i = i+1;
+ }
+ if (mindist < dist) return(r); else return(null);
+}
+
+
+class Guepe
+{
+
+ point pos;
+
+
+ void cherche(point orig, float dist)
+ {
+ object p;
+ point o;
+
+ p = radarGuepe(orig, dist);
+ while (p == null)
+ {
+ wait(0.1);
+ p = radarGuepe(orig, dist);
+ }
+
+ pos.x = p.position.x;
+ pos.y = p.position.y;
+ pos.z = p.position.z;
+
+ //o = p.position;
+ //wait(0.1);
+
+ //vitessex = (p.position.x - o.x)/0.1;
+ //vitessey = (p.position.y - o.y)/0.1;
+ //vitessez = (p.position.z - o.z)/0.1;
+
+ }
+
+
+ void tire(point orig, float orient)
+ {
+ //float t = 3; //temps d'anticipation
+ float angle;
+ point cible;
+
+ cible.x = pos.x;// + t*vitessex;
+ cible.y = pos.y;// + t*vitessey;
+ cible.z = pos.z;// + t*vitessez;
+
+ if (cible.x == 0) angle = 90; else
+ angle = atan(cible.y / cible.x);
+ if (cible.x < 0) angle = angle + 180;
+ angle = angle - orient;
+ if (angle > 180) angle = angle - 360;
+ if (angle < -180) angle = angle + 360;
+ turn(angle);
+
+ angle = atan((cible.z-orig.z) / distance2d(orig, cible));
+ aim(angle);
+
+ fire(0.1);
+
+ }
+}
+
+extern void object::Fourmi6()
+{
+ //fps(1000);
+ Guepe guepe = new Guepe();
+
+ while (true)
+ {
+ guepe.cherche(position, 50);
+
+ guepe.tire(position, orientation);
+ }
+}
diff --git a/src/CBot/tests/TestCBot/scenarios/a§1.txt b/src/CBot/tests/TestCBot/scenarios/a§1.txt
new file mode 100644
index 0000000..0c57950
--- /dev/null
+++ b/src/CBot/tests/TestCBot/scenarios/a§1.txt
@@ -0,0 +1,96 @@
+object radarGuepe(point orig, float dist)
+{
+ int i;
+ object pr, r;
+ float mindist;
+
+ i = 0;
+ mindist = 1000;
+ while (i<30)
+ {
+ pr = radar(i);
+ if (pr != null)
+ {
+
+ if (F(orig, pr.position) < mindist and pr.category == AlienWasp and pr.altitude > 3)
+ {
+ mindist = distance(orig, pr.position);
+ r = pr;
+ }
+ }
+ i = i+1;
+ }
+ if (mindist < dist) return(r); else return(null);
+}
+
+
+class Guepe
+{
+
+ point pos;
+
+
+ void cherche(point orig, float dist)
+ {
+ object p;
+ point o;
+
+ p = radarGuepe(orig, dist);
+ while (p == null)
+ {
+ wait(0.1);
+ p = radarGuepe(orig, dist);
+ }
+
+ pos.x = p.position.x;
+ pos.y = p.position.y;
+ pos.z = p.position.z;
+
+ //o = p.position;
+ //wait(0.1);
+
+ //vitessex = (p.position.x - o.x)/0.1;
+ //vitessey = (p.position.y - o.y)/0.1;
+ //vitessez = (p.position.z - o.z)/0.1;
+
+ }
+
+
+ void tire(point orig, float orient)
+ {
+ //float t = 3; //temps d'anticipation
+ float angle;
+ point cible;
+
+ cible.x = pos.x;// + t*vitessex;
+ cible.y = pos.y;// + t*vitessey;
+ cible.z = pos.z;// + t*vitessez;
+
+ if (cible.x == 0) angle = 90; else
+ angle = atan(cible.y / cible.x);
+ if (cible.x < 0) angle = angle + 180;
+ angle = angle - orient;
+ if (angle > 180) angle = angle - 360;
+ if (angle < -180) angle = angle + 360;
+ turn(angle);
+
+ angle = atan((cible.z-orig.z) / distance2d(orig, cible));
+ aim(angle);
+
+ fire(0.1);
+
+ }
+}
+
+extern void object::Fourmi6()
+{
+ //fps(1000);
+ Guepe guepe = new Guepe();
+
+ while (true)
+ {
+ guepe.cherche(position, 50);
+
+ guepe.tire(position, orientation);
+ }
+}
diff --git a/src/CBot/TestCBot/bug.txt b/src/CBot/tests/TestCBot/scenarios/bug.txt
index 4ec6eb3..4ec6eb3 100644
--- a/src/CBot/TestCBot/bug.txt
+++ b/src/CBot/tests/TestCBot/scenarios/bug.txt
diff --git a/src/CBot/TestCBot/bugmw.txt b/src/CBot/tests/TestCBot/scenarios/bugmw.txt
index 284ee43..284ee43 100644
--- a/src/CBot/TestCBot/bugmw.txt
+++ b/src/CBot/tests/TestCBot/scenarios/bugmw.txt
diff --git a/src/CBot/TestCBot/ccc.txt b/src/CBot/tests/TestCBot/scenarios/ccc.txt
index dbcd1d5..dbcd1d5 100644
--- a/src/CBot/TestCBot/ccc.txt
+++ b/src/CBot/tests/TestCBot/scenarios/ccc.txt
diff --git a/src/CBot/TestCBot/enum.txt b/src/CBot/tests/TestCBot/scenarios/enum.txt
index a592a7f..a592a7f 100644
--- a/src/CBot/TestCBot/enum.txt
+++ b/src/CBot/tests/TestCBot/scenarios/enum.txt
diff --git a/src/CBot/TestCBot/fibo.txt b/src/CBot/tests/TestCBot/scenarios/fibo.txt
index 88f5357..88f5357 100644
--- a/src/CBot/TestCBot/fibo.txt
+++ b/src/CBot/tests/TestCBot/scenarios/fibo.txt
diff --git a/src/CBot/TestCBot/file.txt b/src/CBot/tests/TestCBot/scenarios/file.txt
index 2a22dd9..2a22dd9 100644
--- a/src/CBot/TestCBot/file.txt
+++ b/src/CBot/tests/TestCBot/scenarios/file.txt
diff --git a/src/CBot/TestCBot/h.txt b/src/CBot/tests/TestCBot/scenarios/h.txt
index c395319..c395319 100644
--- a/src/CBot/TestCBot/h.txt
+++ b/src/CBot/tests/TestCBot/scenarios/h.txt
diff --git a/src/CBot/TestCBot/include.txt b/src/CBot/tests/TestCBot/scenarios/include.txt
index e8f8cc9..e8f8cc9 100644
--- a/src/CBot/TestCBot/include.txt
+++ b/src/CBot/tests/TestCBot/scenarios/include.txt
diff --git a/src/CBot/TestCBot/intrinsic.txt b/src/CBot/tests/TestCBot/scenarios/intrinsic.txt
index f215791..f215791 100644
--- a/src/CBot/TestCBot/intrinsic.txt
+++ b/src/CBot/tests/TestCBot/scenarios/intrinsic.txt
diff --git a/src/CBot/TestCBot/methode1.txt b/src/CBot/tests/TestCBot/scenarios/methode1.txt
index 080bba2..080bba2 100644
--- a/src/CBot/TestCBot/methode1.txt
+++ b/src/CBot/tests/TestCBot/scenarios/methode1.txt
diff --git a/src/CBot/TestCBot/methode2.txt b/src/CBot/tests/TestCBot/scenarios/methode2.txt
index 76ce7f4..76ce7f4 100644
--- a/src/CBot/TestCBot/methode2.txt
+++ b/src/CBot/tests/TestCBot/scenarios/methode2.txt
diff --git a/src/CBot/TestCBot/mp1.txt b/src/CBot/tests/TestCBot/scenarios/mp1.txt
index 599cfc4..599cfc4 100644
--- a/src/CBot/TestCBot/mp1.txt
+++ b/src/CBot/tests/TestCBot/scenarios/mp1.txt
diff --git a/src/CBot/TestCBot/mp2.txt b/src/CBot/tests/TestCBot/scenarios/mp2.txt
index 1c2972c..1c2972c 100644
--- a/src/CBot/TestCBot/mp2.txt
+++ b/src/CBot/tests/TestCBot/scenarios/mp2.txt
diff --git a/src/CBot/TestCBot/mw.txt b/src/CBot/tests/TestCBot/scenarios/mw.txt
index c237670..c237670 100644
--- a/src/CBot/TestCBot/mw.txt
+++ b/src/CBot/tests/TestCBot/scenarios/mw.txt
diff --git a/src/CBot/TestCBot/null.txt b/src/CBot/tests/TestCBot/scenarios/null.txt
index ae76b74..ae76b74 100644
--- a/src/CBot/TestCBot/null.txt
+++ b/src/CBot/tests/TestCBot/scenarios/null.txt
diff --git a/src/CBot/TestCBot/opnew.txt b/src/CBot/tests/TestCBot/scenarios/opnew.txt
index 7d6838c..7d6838c 100644
--- a/src/CBot/TestCBot/opnew.txt
+++ b/src/CBot/tests/TestCBot/scenarios/opnew.txt
diff --git a/src/CBot/TestCBot/plante.txt b/src/CBot/tests/TestCBot/scenarios/plante.txt
index 363461b..363461b 100644
--- a/src/CBot/TestCBot/plante.txt
+++ b/src/CBot/tests/TestCBot/scenarios/plante.txt
diff --git a/src/CBot/TestCBot/pointer.txt b/src/CBot/tests/TestCBot/scenarios/pointer.txt
index 2d4d907..2d4d907 100644
--- a/src/CBot/TestCBot/pointer.txt
+++ b/src/CBot/tests/TestCBot/scenarios/pointer.txt
diff --git a/src/CBot/TestCBot/postinc.txt b/src/CBot/tests/TestCBot/scenarios/postinc.txt
index cdf6ab5..cdf6ab5 100644
--- a/src/CBot/TestCBot/postinc.txt
+++ b/src/CBot/tests/TestCBot/scenarios/postinc.txt
diff --git a/src/CBot/TestCBot/radar.txt b/src/CBot/tests/TestCBot/scenarios/radar.txt
index 09d84a2..09d84a2 100644
--- a/src/CBot/TestCBot/radar.txt
+++ b/src/CBot/tests/TestCBot/scenarios/radar.txt
diff --git a/src/CBot/TestCBot/solution.txt b/src/CBot/tests/TestCBot/scenarios/solution.txt
index f78cf12..f78cf12 100644
--- a/src/CBot/TestCBot/solution.txt
+++ b/src/CBot/tests/TestCBot/scenarios/solution.txt
diff --git a/src/CBot/TestCBot/test.txt b/src/CBot/tests/TestCBot/scenarios/test.txt
index a912415..a912415 100644
--- a/src/CBot/TestCBot/test.txt
+++ b/src/CBot/tests/TestCBot/scenarios/test.txt
diff --git a/src/CBot/TestCBot/test23.txt b/src/CBot/tests/TestCBot/scenarios/test23.txt
index d6e1ddd..d6e1ddd 100644
--- a/src/CBot/TestCBot/test23.txt
+++ b/src/CBot/tests/TestCBot/scenarios/test23.txt
diff --git a/src/CBot/TestCBot/testmw.txt b/src/CBot/tests/TestCBot/scenarios/testmw.txt
index 6570f6d..6570f6d 100644
--- a/src/CBot/TestCBot/testmw.txt
+++ b/src/CBot/tests/TestCBot/scenarios/testmw.txt
diff --git a/src/CBot/TestCBot/this.txt b/src/CBot/tests/TestCBot/scenarios/this.txt
index b8a9e04..b8a9e04 100644
--- a/src/CBot/TestCBot/this.txt
+++ b/src/CBot/tests/TestCBot/scenarios/this.txt
diff --git a/src/CBot/TestCBot/tt.txt b/src/CBot/tests/TestCBot/scenarios/tt.txt
index cd13c9d..cd13c9d 100644
--- a/src/CBot/TestCBot/tt.txt
+++ b/src/CBot/tests/TestCBot/scenarios/tt.txt
diff --git a/src/CBot/TestCBot/tt2.txt b/src/CBot/tests/TestCBot/scenarios/tt2.txt
index ad9dc1d..ad9dc1d 100644
--- a/src/CBot/TestCBot/tt2.txt
+++ b/src/CBot/tests/TestCBot/scenarios/tt2.txt
diff --git a/src/CBot/TestCBot/vide.txt b/src/CBot/tests/TestCBot/scenarios/vide.txt
index e69de29..e69de29 100644
--- a/src/CBot/TestCBot/vide.txt
+++ b/src/CBot/tests/TestCBot/scenarios/vide.txt
diff --git a/src/CBot/TestCBot/zz.txt b/src/CBot/tests/TestCBot/scenarios/zz.txt
index da764ac..da764ac 100644
--- a/src/CBot/TestCBot/zz.txt
+++ b/src/CBot/tests/TestCBot/scenarios/zz.txt
diff --git a/src/CBot/TestCBot/xTestCBot.clw b/src/CBot/tests/TestCBot/xTestCBot.clw
index 5b84c16..5b84c16 100644
--- a/src/CBot/TestCBot/xTestCBot.clw
+++ b/src/CBot/tests/TestCBot/xTestCBot.clw
diff --git a/src/CBot/old TstCBot/BotConsoleDlg.cpp b/src/CBot/tests/old TstCBot/BotConsoleDlg.cpp
index 077f080..077f080 100644
--- a/src/CBot/old TstCBot/BotConsoleDlg.cpp
+++ b/src/CBot/tests/old TstCBot/BotConsoleDlg.cpp
diff --git a/src/CBot/old TstCBot/BotConsoleDlg.h b/src/CBot/tests/old TstCBot/BotConsoleDlg.h
index 9b54ff2..9b54ff2 100644
--- a/src/CBot/old TstCBot/BotConsoleDlg.h
+++ b/src/CBot/tests/old TstCBot/BotConsoleDlg.h
diff --git a/src/CBot/old TstCBot/BotErrorDlg.cpp b/src/CBot/tests/old TstCBot/BotErrorDlg.cpp
index 87d56f0..87d56f0 100644
--- a/src/CBot/old TstCBot/BotErrorDlg.cpp
+++ b/src/CBot/tests/old TstCBot/BotErrorDlg.cpp
diff --git a/src/CBot/old TstCBot/BotErrorDlg.h b/src/CBot/tests/old TstCBot/BotErrorDlg.h
index 522afad..522afad 100644
--- a/src/CBot/old TstCBot/BotErrorDlg.h
+++ b/src/CBot/tests/old TstCBot/BotErrorDlg.h
diff --git a/src/CBot/old TstCBot/CBotTest.txt b/src/CBot/tests/old TstCBot/CBotTest.txt
index ce20e26..ce20e26 100644
--- a/src/CBot/old TstCBot/CBotTest.txt
+++ b/src/CBot/tests/old TstCBot/CBotTest.txt
diff --git a/src/CBot/old TstCBot/CMyThread.cpp b/src/CBot/tests/old TstCBot/CMyThread.cpp
index ca92c77..ca92c77 100644
--- a/src/CBot/old TstCBot/CMyThread.cpp
+++ b/src/CBot/tests/old TstCBot/CMyThread.cpp
diff --git a/src/CBot/old TstCBot/CMyThread.h b/src/CBot/tests/old TstCBot/CMyThread.h
index 1134077..1134077 100644
--- a/src/CBot/old TstCBot/CMyThread.h
+++ b/src/CBot/tests/old TstCBot/CMyThread.h
diff --git a/src/CBot/old TstCBot/MainFrm.cpp b/src/CBot/tests/old TstCBot/MainFrm.cpp
index 6c0962c..6c0962c 100644
--- a/src/CBot/old TstCBot/MainFrm.cpp
+++ b/src/CBot/tests/old TstCBot/MainFrm.cpp
diff --git a/src/CBot/old TstCBot/MainFrm.h b/src/CBot/tests/old TstCBot/MainFrm.h
index 56b9c41..56b9c41 100644
--- a/src/CBot/old TstCBot/MainFrm.h
+++ b/src/CBot/tests/old TstCBot/MainFrm.h
diff --git a/src/CBot/old TstCBot/ReadMe.txt b/src/CBot/tests/old TstCBot/ReadMe.txt
index 67dc05b..67dc05b 100644
--- a/src/CBot/old TstCBot/ReadMe.txt
+++ b/src/CBot/tests/old TstCBot/ReadMe.txt
diff --git a/src/CBot/old TstCBot/Resource.h b/src/CBot/tests/old TstCBot/Resource.h
index 6863fd8..6863fd8 100644
--- a/src/CBot/old TstCBot/Resource.h
+++ b/src/CBot/tests/old TstCBot/Resource.h
diff --git a/src/CBot/old TstCBot/StdAfx.cpp b/src/CBot/tests/old TstCBot/StdAfx.cpp
index ae0ec93..ae0ec93 100644
--- a/src/CBot/old TstCBot/StdAfx.cpp
+++ b/src/CBot/tests/old TstCBot/StdAfx.cpp
diff --git a/src/CBot/old TstCBot/StdAfx.h b/src/CBot/tests/old TstCBot/StdAfx.h
index 7d46ace..7d46ace 100644
--- a/src/CBot/old TstCBot/StdAfx.h
+++ b/src/CBot/tests/old TstCBot/StdAfx.h
diff --git a/src/CBot/old TstCBot/TstCBot.clw b/src/CBot/tests/old TstCBot/TstCBot.clw
index 4c54168..4c54168 100644
--- a/src/CBot/old TstCBot/TstCBot.clw
+++ b/src/CBot/tests/old TstCBot/TstCBot.clw
diff --git a/src/CBot/old TstCBot/TstCBot.cpp b/src/CBot/tests/old TstCBot/TstCBot.cpp
index 8ac4557..8ac4557 100644
--- a/src/CBot/old TstCBot/TstCBot.cpp
+++ b/src/CBot/tests/old TstCBot/TstCBot.cpp
diff --git a/src/CBot/old TstCBot/TstCBot.dsp b/src/CBot/tests/old TstCBot/TstCBot.dsp
index 35e5c0b..35e5c0b 100644
--- a/src/CBot/old TstCBot/TstCBot.dsp
+++ b/src/CBot/tests/old TstCBot/TstCBot.dsp
diff --git a/src/CBot/old TstCBot/TstCBot.h b/src/CBot/tests/old TstCBot/TstCBot.h
index 616db43..616db43 100644
--- a/src/CBot/old TstCBot/TstCBot.h
+++ b/src/CBot/tests/old TstCBot/TstCBot.h
diff --git a/src/CBot/old TstCBot/TstCBot.rc b/src/CBot/tests/old TstCBot/TstCBot.rc
index 9e91c76..9e91c76 100644
--- a/src/CBot/old TstCBot/TstCBot.rc
+++ b/src/CBot/tests/old TstCBot/TstCBot.rc
diff --git a/src/CBot/old TstCBot/TstCBotDoc.cpp b/src/CBot/tests/old TstCBot/TstCBotDoc.cpp
index 7d7e2ef..7d7e2ef 100644
--- a/src/CBot/old TstCBot/TstCBotDoc.cpp
+++ b/src/CBot/tests/old TstCBot/TstCBotDoc.cpp
diff --git a/src/CBot/old TstCBot/TstCBotDoc.h b/src/CBot/tests/old TstCBot/TstCBotDoc.h
index ae1d0f7..ae1d0f7 100644
--- a/src/CBot/old TstCBot/TstCBotDoc.h
+++ b/src/CBot/tests/old TstCBot/TstCBotDoc.h
diff --git a/src/CBot/old TstCBot/TstCBotView.cpp b/src/CBot/tests/old TstCBot/TstCBotView.cpp
index 3ee9094..3ee9094 100644
--- a/src/CBot/old TstCBot/TstCBotView.cpp
+++ b/src/CBot/tests/old TstCBot/TstCBotView.cpp
diff --git a/src/CBot/old TstCBot/TstCBotView.h b/src/CBot/tests/old TstCBot/TstCBotView.h
index d5aede5..d5aede5 100644
--- a/src/CBot/old TstCBot/TstCBotView.h
+++ b/src/CBot/tests/old TstCBot/TstCBotView.h
diff --git a/src/CBot/old TstCBot/res/TstCBot.ico b/src/CBot/tests/old TstCBot/res/TstCBot.ico
index 7eef0bc..7eef0bc 100644
--- a/src/CBot/old TstCBot/res/TstCBot.ico
+++ b/src/CBot/tests/old TstCBot/res/TstCBot.ico
Binary files differ
diff --git a/src/CBot/old TstCBot/res/TstCBot.rc2 b/src/CBot/tests/old TstCBot/res/TstCBot.rc2
index 2186272..2186272 100644
--- a/src/CBot/old TstCBot/res/TstCBot.rc2
+++ b/src/CBot/tests/old TstCBot/res/TstCBot.rc2
diff --git a/src/CBot/old TstCBot/res/TstCBotDoc.ico b/src/CBot/tests/old TstCBot/res/TstCBotDoc.ico
index 2a1f1ae..2a1f1ae 100644
--- a/src/CBot/old TstCBot/res/TstCBotDoc.ico
+++ b/src/CBot/tests/old TstCBot/res/TstCBotDoc.ico
Binary files differ
diff --git a/src/CBot/old TstCBot/test complet 1.txt b/src/CBot/tests/old TstCBot/test complet 1.txt
index 0fd4fa5..0fd4fa5 100644
--- a/src/CBot/old TstCBot/test complet 1.txt
+++ b/src/CBot/tests/old TstCBot/test complet 1.txt
diff --git a/src/CBot/old TstCBot/x.txt b/src/CBot/tests/old TstCBot/x.txt
index 95856e0..95856e0 100644
--- a/src/CBot/old TstCBot/x.txt
+++ b/src/CBot/tests/old TstCBot/x.txt
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 03bb03c..9bcd288 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,35 +1,63 @@
# CBot shared library is built separately
-# add_subdirectory(CBot) -- not yet WinAPI-independent
+add_subdirectory(CBot)
# Configure options
option(DEBUG "Enable debug output" ON)
+set(PLATFORM_LIBS "")
+
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(PLATFORM_WINDOWS 1)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 0)
+ # On Windows, GLEW is required
+ if (${USE_GLEW} MATCHES "auto")
+ set(USE_GLEW 1)
+ endif()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 1)
set(PLATFORM_OTHER 0)
+ # On Linux, we should be fine without GLEW
+ if (${USE_GLEW} MATCHES "auto")
+ set(USE_GLEW 0)
+ endif()
+ # for clock_gettime
+ set(PLATFORM_LIBS "-lrt")
else()
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 1)
+ # Use GLEW to be safe
+ if (${USE_GLEW} MATCHES "auto")
+ set(USE_GLEW 1)
+ endif()
+endif()
+
+set(OPTIONAL_LIBS "")
+set(OPTIONAL_INCLUDE_DIRS "")
+
+if(${USE_GLEW} EQUAL 1)
+ find_package(GLEW REQUIRED)
+ set(OPTIONAL_LIBS ${OPTIONAL_LIBS} ${GLEW_LIBRARY})
+ set(OPTIONAL_INCLUDE_DIRS ${OPTIONAL_INCLUDE_DIRS} ${GLEW_INCLUDE_PATH})
endif()
+
# Configure file
configure_file(common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
# Source files
# Commented out files are still dependent on DirectX or WinAPI
+
set(SOURCES
app/app.cpp
app/main.cpp
app/system.cpp
common/event.cpp
+common/image.cpp
common/logger.cpp
common/iman.cpp
# common/metafile.cpp
@@ -37,23 +65,21 @@ common/iman.cpp
# common/modfile.cpp
# common/profile.cpp
# common/restext.cpp
-graphics/common/camera.cpp
-graphics/common/cloud.cpp
-graphics/common/color.cpp
-graphics/common/device.cpp
-graphics/common/engine.cpp
-graphics/common/light.cpp
-graphics/common/lightning.cpp
-graphics/common/model.cpp
-graphics/common/modfile.cpp
-graphics/common/particle.cpp
-graphics/common/planet.cpp
-graphics/common/pyro.cpp
-graphics/common/terrain.cpp
-graphics/common/text.cpp
-graphics/common/water.cpp
+common/stringutils.cpp
+graphics/core/color.cpp
+# graphics/engine/camera.cpp # new code but depends on other modules
+graphics/engine/cloud.cpp
+graphics/engine/engine.cpp
+graphics/engine/lightman.cpp
+graphics/engine/lightning.cpp
+graphics/engine/modelfile.cpp
+graphics/engine/particle.cpp
+graphics/engine/planet.cpp
+graphics/engine/pyro.cpp
+graphics/engine/terrain.cpp
+graphics/engine/text.cpp
+graphics/engine/water.cpp
graphics/opengl/gldevice.cpp
-graphics/opengl/glengine.cpp
# object/auto/auto.cpp
# object/auto/autobase.cpp
# object/auto/autoconvert.cpp
@@ -151,10 +177,19 @@ set(LIBS
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
${OPENGL_LIBRARY}
-#CBot -- not yet WinAPI-independent
+${PNG_LIBRARIES}
+${OPTIONAL_LIBS}
+${PLATFORM_LIBS}
+CBot
)
-include_directories(. ${CMAKE_CURRENT_BINARY_DIR})
+include_directories(. ${CMAKE_CURRENT_BINARY_DIR}
+${SDL_INCLUDE_DIR}
+${SDL_IMAGE_INCLUDE_DIR}
+${SDLTTF_INCLUDE_DIR}
+${PNG_INCLUDE_DIRS}
+${OPTIONAL_INCLUDE_DIRS}
+)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/CBot)
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 68131fc..d20232d 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -20,12 +20,27 @@
#include "app/app.h"
#include "app/system.h"
+#include "common/logger.h"
#include "common/iman.h"
+#include "common/image.h"
+#include "graphics/opengl/gldevice.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
+#include <stdio.h>
+
+
+template<> CApplication* CSingleton<CApplication>::mInstance = NULL;
+
+
+//! Interval of timer called to update joystick state
+const int JOYSTICK_TIMER_INTERVAL = 1000/30;
+
+//! Function called by the timer
+Uint32 JoystickTimerCallback(Uint32 interval, void *);
+
/**
* \struct ApplicationPrivate
@@ -41,57 +56,44 @@ struct ApplicationPrivate
SDL_Event currentEvent;
//! Joystick
SDL_Joystick *joystick;
- //! Index of joystick device
- int joystickDevice;
+ //! Id of joystick timer
+ SDL_TimerID joystickTimer;
ApplicationPrivate()
{
memset(&currentEvent, 0, sizeof(SDL_Event));
surface = NULL;
joystick = NULL;
- joystickDevice = 0;
+ joystickTimer = 0;
}
};
+
CApplication::CApplication()
{
- m_private = new ApplicationPrivate();
- m_exitCode = 0;
+ m_private = new ApplicationPrivate();
+ m_iMan = new CInstanceManager();
+ m_eventQueue = new CEventQueue(m_iMan);
- m_iMan = new CInstanceManager();
- m_event = new CEvent(m_iMan);
-
- m_engine = 0;
- m_robotMain = 0;
- m_sound = 0;
+ m_engine = NULL;
+ m_device = NULL;
+ m_robotMain = NULL;
+ m_sound = NULL;
m_keyState = 0;
- m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f);
- m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f);
- m_vidMemTotal = 0;
- m_active = false;
- m_activateApp = false;
- m_ready = false;
- m_joystick = false;
- m_time = 0.0f;
+ m_exitCode = 0;
+ m_active = false;
+ m_debugMode = false;
- for (int i = 0; i < 32; i++)
- {
- m_joyButton[i] = false;
- }
+ m_windowTitle = "COLOBOT";
- m_windowTitle = "COLOBOT";
+ m_joystickEnabled = false;
- m_appUseZBuffer = true;
- m_appUseStereo = true;
- m_showStats = false;
- m_debugMode = false;
- m_audioState = true;
- m_audioTrack = true;
- m_niceMouse = false;
- m_setupMode = true;
+ m_dataPath = "./data";
ResetKey();
}
@@ -101,93 +103,163 @@ CApplication::~CApplication()
delete m_private;
m_private = NULL;
+ delete m_eventQueue;
+ m_eventQueue = NULL;
+
delete m_iMan;
m_iMan = NULL;
}
-Error CApplication::ParseArguments(int argc, char *argv[])
+bool CApplication::ParseArguments(int argc, char *argv[])
{
+ bool waitDataDir = false;
+
for (int i = 1; i < argc; ++i)
{
std::string arg = argv[i];
+ if (waitDataDir)
+ {
+ waitDataDir = false;
+ m_dataPath = arg;
+ }
+
if (arg == "-debug")
{
- m_showStats = true;
SetDebugMode(true);
}
- else if (arg == "-audiostate")
+ else if (arg == "-datadir")
{
- m_audioState = false;
+ waitDataDir = true;
}
- else if (arg == "-audiotrack")
+ else
{
- m_audioTrack = false;
+ m_exitCode = 1;
+ return false;
}
- // TODO else {} report invalid argument
}
- return ERR_OK;
+ // Data dir not given?
+ if (waitDataDir)
+ return false;
+
+ return true;
}
bool CApplication::Create()
{
-/*
-TODO
- Full screen by default unless in debug mode
- if (! m_debugMode)
- m_deviceConfig.fullScreen = true;
-
- int full = 0;
- if (GetProfileInt("Device", "FullScreen", full))
- m_deviceConfig.fullScreen = full == 1;
-*/
+ // TODO: verify that data directory exists
// Temporarily -- only in windowed mode
m_deviceConfig.fullScreen = false;
-/*
-TODO
- // Create the 3D engine.
- m_engine = new CEngine(m_iMan, this);
+ // Create the 3D engine
+ m_engine = new Gfx::CEngine(m_iMan, this);
- // Initialize the app's custom scene stuff
- if (! m_engine->OneTimeSceneInit())
- {
- SystemDialog(SDT_ERROR, "COLOBOT - Error", m_engine->RetError());
- return false;
- }
- // Create the sound instance.
+/* // Create the sound instance.
m_sound = new CSound(m_iMan);
// Create the robot application.
- m_robotMain = new CRobotMain(m_iMan);
-*/
+ m_robotMain = new CRobotMain(m_iMan); */
- Uint32 initFlags = SDL_INIT_VIDEO;
- if (m_joystick)
- initFlags |= SDL_INIT_JOYSTICK;
+
+ /* SDL initialization sequence */
+
+
+ Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER;
if (SDL_Init(initFlags) < 0)
{
- SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL initialization error:\n" + std::string(SDL_GetError()) );
+ SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error",
+ "SDL initialization error:\n" +
+ std::string(SDL_GetError()) );
+ m_exitCode = 2;
+ return false;
+ }
+
+ if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0)
+ {
+ SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error",
+ std::string("SDL_Image initialization error:\n") +
+ std::string(IMG_GetError()) );
+ m_exitCode = 3;
+ return false;
+ }
+
+ if (! CreateVideoSurface())
+ return false; // dialog is in function
+
+ if (m_private->surface == NULL)
+ {
+ SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
+ std::string("SDL error while setting video mode:\n") +
+ std::string(SDL_GetError()) );
+ m_exitCode = 2;
+ return false;
+ }
+
+ SDL_WM_SetCaption(m_windowTitle.c_str(), m_windowTitle.c_str());
+
+ // Enable translating key codes of key press events to unicode chars
+ SDL_EnableUNICODE(1);
+
+ // Don't generate joystick events
+ SDL_JoystickEventState(SDL_IGNORE);
+
+
+ // For now, enable joystick for testing
+ SetJoystickEnabled(true);
+
+
+ // The video is ready, we can create and initalize the graphics device
+ m_device = new Gfx::CGLDevice(m_deviceConfig);
+ if (! m_device->Create() )
+ {
+ SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
+ std::string("Error in CDevice::Create() :\n") +
+ std::string(m_device->GetError()) );
+ m_exitCode = 1;
return false;
}
+ m_engine->SetDevice(m_device);
+ if (! m_engine->Create() )
+ {
+ SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
+ std::string("Error in CEngine::Create() :\n") +
+ std::string(m_engine->GetError()) );
+ m_exitCode = 1;
+ return false;
+ }
+
+ if (! m_engine->AfterDeviceSetInit() )
+ {
+ SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
+ std::string("Error in CEngine::AfterDeviceSetInit() :\n") +
+ std::string(m_engine->GetError()) );
+ m_exitCode = 1;
+ return false;
+ }
+
+ return true;
+}
+
+bool CApplication::CreateVideoSurface()
+{
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
- if (! videoInfo)
+ if (videoInfo == NULL)
{
- SystemDialog( SDT_ERROR, "COLOBOT - Error", "SDL error while getting video info:\n " + std::string(SDL_GetError()) );
+ SystemDialog( SDT_ERROR, "COLOBOT - Fatal Error",
+ std::string("SDL error while getting video info:\n ") +
+ std::string(SDL_GetError()) );
+ m_exitCode = 2;
return false;
}
Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
- if (m_deviceConfig.resizeable)
- videoFlags |= SDL_RESIZABLE;
-
// Use hardware surface if available
if (videoInfo->hw_available)
videoFlags |= SDL_HWSURFACE;
@@ -201,134 +273,320 @@ TODO
if (m_deviceConfig.fullScreen)
videoFlags |= SDL_FULLSCREEN;
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+ if (m_deviceConfig.resizeable)
+ videoFlags |= SDL_RESIZABLE;
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+ // Set OpenGL attributes
- if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0)
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, m_deviceConfig.redSize);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, m_deviceConfig.greenSize);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, m_deviceConfig.blueSize);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, m_deviceConfig.alphaSize);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, m_deviceConfig.depthSize);
+
+ if (m_deviceConfig.doubleBuf)
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ /* If hardware acceleration specifically requested, this will force the hw accel
+ and fail with error if not available */
+ if (m_deviceConfig.hardwareAccel)
+ SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
+
+ m_private->surface = SDL_SetVideoMode(m_deviceConfig.size.w, m_deviceConfig.size.h,
+ m_deviceConfig.bpp, videoFlags);
+
+ return true;
+}
+
+void CApplication::Destroy()
+{
+ /*if (m_robotMain != NULL)
{
- SystemDialog( SDT_ERROR, "COLOBOT - Error", std::string("SDL_Image initialization error:\n") +
- std::string(IMG_GetError()) );
- return false;
+ delete m_robotMain;
+ m_robotMain = NULL;
}
- m_private->surface = SDL_SetVideoMode(m_deviceConfig.width, m_deviceConfig.height,
- m_deviceConfig.bpp, videoFlags);
+ if (m_sound != NULL)
+ {
+ delete m_sound;
+ m_sound = NULL;
+ }*/
- if (! m_private->surface)
+ if (m_engine != NULL)
{
- SystemDialog( SDT_ERROR, "COLOBT - Error", std::string("SDL error while setting video mode:\n") +
- std::string(SDL_GetError()) );
- return false;
+ if (m_engine->GetWasInit())
+ m_engine->Destroy();
+
+ delete m_engine;
+ m_engine = NULL;
}
- SDL_WM_SetCaption(m_windowTitle.c_str(), m_windowTitle.c_str());
+ if (m_device != NULL)
+ {
+ if (m_device->GetWasInit())
+ m_device->Destroy();
- SDL_EnableUNICODE(1);
+ delete m_device;
+ m_device = NULL;
+ }
+ if (m_private->joystick != NULL)
+ {
+ SDL_JoystickClose(m_private->joystick);
+ m_private->joystick = NULL;
+ }
-/*
-TODO
+ if (m_private->surface != NULL)
+ {
+ SDL_FreeSurface(m_private->surface);
+ m_private->surface = NULL;
+ }
+
+ IMG_Quit();
- InitJoystick();
+ SDL_Quit();
+}
+
+bool CApplication::ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig)
+{
+ static bool restore = false;
+
+ m_lastDeviceConfig = m_deviceConfig;
+ m_deviceConfig = newConfig;
+
+
+ SDL_FreeSurface(m_private->surface);
- if ( !GetProfileInt("Setup", "Sound3D", b3D) )
+ if (! CreateVideoSurface())
{
- b3D = true;
+ // Fatal error, so post the quit event
+ m_eventQueue->AddEvent(Event(EVENT_QUIT));
+ return false;
}
- m_pSound->SetDebugMode(m_bDebugMode);
- m_pSound->Create(m_hWnd, b3D);
- m_pSound->CacheAll();
- m_pSound->SetState(m_bAudioState);
- m_pSound->SetAudioTrack(m_bAudioTrack);
- m_pSound->SetCDpath(m_CDpath);
- // First execution?
- if ( !GetProfileInt("Setup", "ObjectDirty", iValue) )
+ if (m_private->surface == NULL)
{
- m_pD3DEngine->FirstExecuteAdapt(true);
+ if (! restore)
+ {
+ SystemDialog( SDT_ERROR, "COLOBT - Error",
+ std::string("SDL error while setting video mode:\n") +
+ std::string(SDL_GetError()) + std::string("\n") +
+ std::string("Previous mode will be restored") );
+
+ restore = true;
+ ChangeVideoConfig(m_lastDeviceConfig);
+ return false;
+ }
+ else
+ {
+ restore = false;
+
+ SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
+ std::string("SDL error while restoring previous video mode:\n") +
+ std::string(SDL_GetError()) );
+
+
+ // Fatal error, so post the quit event
+ m_eventQueue->AddEvent(Event(EVENT_QUIT));
+ return false;
+ }
}
- // Creates the file colobot.ini at the first execution.
- m_pRobotMain->CreateIni();
+ ( static_cast<Gfx::CGLDevice*>(m_device) )->ConfigChanged(m_deviceConfig);
+
+ m_engine->ResetAfterDeviceChanged();
+
+ return true;
+}
+
+bool CApplication::OpenJoystick()
+{
+ if ( (m_joystick.index < 0) || (m_joystick.index >= SDL_NumJoysticks()) )
+ return false;
+
+ m_private->joystick = SDL_JoystickOpen(m_joystick.index);
+ if (m_private->joystick == NULL)
+ return false;
- m_pRobotMain->ChangePhase(PHASE_WELCOME2);
+ m_joystick.axisCount = SDL_JoystickNumAxes(m_private->joystick);
+ m_joystick.buttonCount = SDL_JoystickNumButtons(m_private->joystick);
- m_engine->TimeInit();
-*/
+ // Create the vectors with joystick axis & button states to exactly the required size
+ m_joyAxeState = std::vector<int>(m_joystick.axisCount, 0);
+ m_joyButtonState = std::vector<bool>(m_joystick.buttonCount, false);
- // The app is ready to go
- m_ready = true;
+ // Create a timer for polling joystick state
+ m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL);
return true;
}
-void CApplication::Destroy()
+void CApplication::CloseJoystick()
+{
+ // Timer will remove itself automatically
+
+ SDL_JoystickClose(m_private->joystick);
+ m_private->joystick = NULL;
+}
+
+bool CApplication::ChangeJoystick(const JoystickDevice &newJoystick)
{
+ if ( (newJoystick.index < 0) || (newJoystick.index >= SDL_NumJoysticks()) )
+ return false;
+
if (m_private->joystick != NULL)
+ CloseJoystick();
+
+ return OpenJoystick();
+}
+
+Uint32 JoystickTimerCallback(Uint32 interval, void *)
+{
+ CApplication *app = CApplication::GetInstancePointer();
+ if ((app == NULL) || (! app->GetJoystickEnabled()))
+ return 0; // don't run the timer again
+
+ app->UpdateJoystick();
+
+ return interval; // run for the same interval again
+}
+
+/** Updates the state info in CApplication and on change, creates SDL events and pushes them to SDL event queue.
+ This way, the events get handled properly in the main event loop and besides, SDL_PushEvent() ensures thread-safety. */
+void CApplication::UpdateJoystick()
+{
+ if (! m_joystickEnabled)
+ return;
+
+ SDL_JoystickUpdate();
+
+ for (int axis = 0; axis < static_cast<int>( m_joyAxeState.size() ); ++axis)
{
- SDL_JoystickClose(m_private->joystick);
- m_private->joystick = NULL;
+ int newValue = SDL_JoystickGetAxis(m_private->joystick, axis);
+
+ if (m_joyAxeState[axis] != newValue)
+ {
+ m_joyAxeState[axis] = newValue;
+
+ SDL_Event joyAxisEvent;
+
+ joyAxisEvent.jaxis.type = SDL_JOYAXISMOTION;
+ joyAxisEvent.jaxis.which = 0;
+ joyAxisEvent.jaxis.axis = axis;
+ joyAxisEvent.jaxis.value = newValue;
+
+ SDL_PushEvent(&joyAxisEvent);
+ }
}
- SDL_FreeSurface(m_private->surface);
- m_private->surface = NULL;
+ for (int button = 0; button < static_cast<int>( m_joyButtonState.size() ); ++button)
+ {
+ bool newValue = SDL_JoystickGetButton(m_private->joystick, button) == 1;
- IMG_Quit();
+ if (m_joyButtonState[button] != newValue)
+ {
+ m_joyButtonState[button] = newValue;
- SDL_Quit();
+ SDL_Event joyButtonEvent;
+
+ if (newValue)
+ {
+ joyButtonEvent.jbutton.type = SDL_JOYBUTTONDOWN;
+ joyButtonEvent.jbutton.state = SDL_PRESSED;
+ }
+ else
+ {
+ joyButtonEvent.jbutton.type = SDL_JOYBUTTONUP;
+ joyButtonEvent.jbutton.state = SDL_RELEASED;
+ }
+ joyButtonEvent.jbutton.which = 0;
+ joyButtonEvent.jbutton.button = button;
+
+ SDL_PushEvent(&joyButtonEvent);
+ }
+ }
}
int CApplication::Run()
{
m_active = true;
- while (m_private->currentEvent.type != SDL_QUIT)
+ while (true)
{
- // Use SDL_PeepEvents() if the app is active, so we can use idle time to
- // render the scene. Else, use SDL_PollEvent() to avoid eating CPU time.
- int count = 0;
+ // To be sure no old event remains
+ m_private->currentEvent.type = SDL_NOEVENT;
+
+ // Call SDL_PumpEvents() only once here
+ // (SDL_PeepEvents() doesn't call it)
if (m_active)
- {
SDL_PumpEvents();
- count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS);
- }
- else
- {
- SDL_PollEvent(&m_private->currentEvent);
- }
- // If received an event
- if ((m_active && count > 0) || (!m_active))
+ bool haveEvent = true;
+ while (haveEvent)
{
- ParseEvent();
+ haveEvent = false;
+
+ int count = 0;
+ // Use SDL_PeepEvents() if the app is active, so we can use idle time to
+ // render the scene. Else, use SDL_WaitEvent() to avoid eating CPU time.
+ if (m_active)
+ count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS);
+ else
+ count = SDL_WaitEvent(&m_private->currentEvent);
+
+ // If received an event
+ if (count > 0)
+ {
+ haveEvent = true;
+
+ Event event = ParseEvent();
+
+ if (event.type == EVENT_QUIT)
+ goto end; // exit the loop
+
+ if (event.type != EVENT_NULL)
+ {
+ bool passOn = ProcessEvent(event);
+
+ if (m_engine != NULL && passOn)
+ passOn = m_engine->ProcessEvent(event);
+
+ if (passOn)
+ m_eventQueue->AddEvent(event);
+ }
+ }
}
- // Render a frame during idle time (no messages are waiting)
- if (m_active && m_ready)
+ // Enter game update & frame rendering only if active
+ if (m_active)
{
Event event;
- while (m_event->GetEvent(event))
+ while (m_eventQueue->GetEvent(event))
{
- if (event.event == EVENT_QUIT)
- {
+ if (event.type == EVENT_QUIT)
goto end; // exit both loops
+
+ bool passOn = true;
+
+ // Skip system events (they have been processed earlier)
+ if (! event.systemEvent)
+ {
+ passOn = ProcessEvent(event);
+
+ if (passOn && m_engine != NULL)
+ passOn = m_engine->ProcessEvent(event);
}
- //m_robotMain->EventProcess(event);
+ /*if (passOn && m_robotMain != NULL)
+ m_robotMain->ProcessEvent(event); */
}
- //if ( !RetNiceMouse())
- //{
- // SetMouseType(m_engine->RetMouseType());
- //}
+ // Update game and render a frame during idle time (no messages are waiting)
+ bool ok = Render();
// If an error occurs, push quit event to the queue
- if (! Render())
+ if (! ok)
{
SDL_Event quitEvent;
memset(&quitEvent, 0, sizeof(SDL_Event));
@@ -339,7 +597,6 @@ int CApplication::Run()
}
end:
- //m_sound->StopMusic();
Destroy();
return m_exitCode;
@@ -350,54 +607,174 @@ int CApplication::GetExitCode()
return m_exitCode;
}
-void CApplication::ParseEvent()
+//! Translates SDL press state to PressState
+PressState TranslatePressState(unsigned char state)
+{
+ if (state == SDL_PRESSED)
+ return STATE_PRESSED;
+ else
+ return STATE_RELEASED;
+}
+
+/** Conversion of the position of the mouse from window coords to interface coords:
+ - x: 0=left, 1=right
+ - y: 0=down, 1=up */
+Math::Point CApplication::WindowToInterfaceCoords(Math::IntPoint pos)
+{
+ return Math::Point( static_cast<float>(pos.x) / static_cast<float>(m_deviceConfig.size.w),
+ 1.0f - static_cast<float>(pos.y) / static_cast<float>(m_deviceConfig.size.h) );
+}
+
+Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos)
+{
+ return Math::IntPoint(static_cast<int>(pos.x * m_deviceConfig.size.w),
+ static_cast<int>((1.0f - pos.y) * m_deviceConfig.size.h));
+}
+
+/** The SDL event parsed is stored internally.
+ If event is not available or is not understood, returned event is of type EVENT_NULL. */
+Event CApplication::ParseEvent()
{
-/* Event event;
+ Event event;
- if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
+ event.systemEvent = true;
+
+ if (m_private->currentEvent.type == SDL_QUIT)
{
- if (m_private->currentEvent.button.button == SDL_BUTTON_LEFT)
- event.event = EVENT_LBUTTONDOWN;
- else if (m_private->currentEvent.button.button == SDL_BUTTON_RIGHT)
- event.event = EVENT_RBUTTONDOWN;
+ event.type = EVENT_QUIT;
}
- else if (m_private->currentEvent.type == SDL_MOUSEBUTTONUP)
+ else if ( (m_private->currentEvent.type == SDL_KEYDOWN) ||
+ (m_private->currentEvent.type == SDL_KEYUP) )
{
- if (m_private->currentEvent.button.button == SDL_BUTTON_LEFT)
- event.event = EVENT_LBUTTONUP;
- else if (m_private->currentEvent.button.button == SDL_BUTTON_RIGHT)
- event.event = EVENT_RBUTTONUP;
+ if (m_private->currentEvent.type == SDL_KEYDOWN)
+ event.type = EVENT_KEY_DOWN;
+ else
+ event.type = EVENT_KEY_UP;
+
+ event.key.key = m_private->currentEvent.key.keysym.sym;
+ event.key.mod = m_private->currentEvent.key.keysym.mod;
+ event.key.state = TranslatePressState(m_private->currentEvent.key.state);
+ event.key.unicode = m_private->currentEvent.key.keysym.unicode;
}
- else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
+ else if ( (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN) ||
+ (m_private->currentEvent.type == SDL_MOUSEBUTTONUP) )
{
- event.event = EVENT_MOUSEMOVE;
+ if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
+ event.type = EVENT_MOUSE_BUTTON_DOWN;
+ else
+ event.type = EVENT_MOUSE_BUTTON_UP;
+
+ event.mouseButton.button = m_private->currentEvent.button.button;
+ event.mouseButton.state = TranslatePressState(m_private->currentEvent.button.state);
+ event.mouseButton.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
}
- else if (m_private->currentEvent.type == SDL_KEYDOWN)
+ else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
{
- event.event = EVENT_KEYDOWN;
+ event.type = EVENT_MOUSE_MOVE;
+
+ event.mouseMove.state = TranslatePressState(m_private->currentEvent.button.state);
+ event.mouseMove.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
}
- else if (m_private->currentEvent.type == SDL_KEYUP)
+ else if (m_private->currentEvent.type == SDL_JOYAXISMOTION)
{
- event.event = EVENT_KEYUP;
- }
+ event.type = EVENT_JOY_AXIS;
- if (m_robotMain != NULL && event.event != EVENT_NULL)
+ event.joyAxis.axis = m_private->currentEvent.jaxis.axis;
+ event.joyAxis.value = m_private->currentEvent.jaxis.value;
+ }
+ else if ( (m_private->currentEvent.type == SDL_JOYBUTTONDOWN) ||
+ (m_private->currentEvent.type == SDL_JOYBUTTONUP) )
{
- m_robotMain->EventProcess(event);
+ if (m_private->currentEvent.type == SDL_JOYBUTTONDOWN)
+ event.type = EVENT_JOY_BUTTON_DOWN;
+ else
+ event.type = EVENT_JOY_BUTTON_UP;
+
+ event.joyButton.button = m_private->currentEvent.jbutton.button;
+ event.joyButton.state = TranslatePressState(m_private->currentEvent.jbutton.state);
}
- if (m_engine != NULL)
+ else if (m_private->currentEvent.type == SDL_ACTIVEEVENT)
{
- m_engine->MsgProc( hWnd, uMsg, wParam, lParam );
+ event.type = EVENT_ACTIVE;
+
+ if (m_private->currentEvent.active.type & SDL_APPINPUTFOCUS)
+ event.active.flags |= ACTIVE_INPUT;
+ if (m_private->currentEvent.active.type & SDL_APPMOUSEFOCUS)
+ event.active.flags |= ACTIVE_MOUSE;
+ if (m_private->currentEvent.active.type & SDL_APPACTIVE)
+ event.active.flags |= ACTIVE_APP;
+
+ event.active.gain = m_private->currentEvent.active.gain == 1;
}
- ProcessEvent(event);*/
+ return event;
}
-void CApplication::ProcessEvent(Event event)
+/** Processes incoming events. It is the first function called after an event is captures.
+ Function returns \c true if the event is to be passed on to other processing functions
+ or \c false if not. */
+bool CApplication::ProcessEvent(const Event &event)
{
+ CLogger *l = GetLogger();
+
+ if (event.type == EVENT_ACTIVE)
+ {
+ m_active = event.active.gain;
+ if (m_debugMode)
+ l->Info("Focus change: active = %s\n", m_active ? "true" : "false");
+ }
+ // Print the events in debug mode to test the code
+ if (m_debugMode)
+ {
+ switch (event.type)
+ {
+ case EVENT_KEY_DOWN:
+ case EVENT_KEY_UP:
+ l->Info("EVENT_KEY_%s:\n", (event.type == EVENT_KEY_DOWN) ? "DOWN" : "UP");
+ l->Info(" key = %4x\n", event.key.key);
+ l->Info(" state = %s\n", (event.key.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ l->Info(" mod = %4x\n", event.key.mod);
+ l->Info(" unicode = %4x\n", event.key.unicode);
+ break;
+ case EVENT_MOUSE_MOVE:
+ l->Info("EVENT_MOUSE_MOVE:\n");
+ l->Info(" state = %s\n", (event.mouseMove.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ l->Info(" pos = (%f, %f)\n", event.mouseMove.pos.x, event.mouseMove.pos.y);
+ break;
+ case EVENT_MOUSE_BUTTON_DOWN:
+ case EVENT_MOUSE_BUTTON_UP:
+ l->Info("EVENT_MOUSE_BUTTON_%s:\n", (event.type == EVENT_MOUSE_BUTTON_DOWN) ? "DOWN" : "UP");
+ l->Info(" button = %d\n", event.mouseButton.button);
+ l->Info(" state = %s\n", (event.mouseButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ l->Info(" pos = (%f, %f)\n", event.mouseButton.pos.x, event.mouseButton.pos.y);
+ break;
+ case EVENT_JOY_AXIS:
+ l->Info("EVENT_JOY_AXIS:\n");
+ l->Info(" axis = %d\n", event.joyAxis.axis);
+ l->Info(" value = %d\n", event.joyAxis.value);
+ break;
+ case EVENT_JOY_BUTTON_DOWN:
+ case EVENT_JOY_BUTTON_UP:
+ l->Info("EVENT_JOY_BUTTON_%s:\n", (event.type == EVENT_JOY_BUTTON_DOWN) ? "DOWN" : "UP");
+ l->Info(" button = %d\n", event.joyButton.button);
+ l->Info(" state = %s\n", (event.joyButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
+ break;
+ case EVENT_ACTIVE:
+ l->Info("EVENT_ACTIVE:\n");
+ l->Info(" flags = 0x%x\n", event.active.flags);
+ l->Info(" gain = %s\n", event.active.gain ? "true" : "false");
+ break;
+ default:
+ break;
+ }
+ }
+
+ // By default, pass on all events
+ return true;
}
+/** Renders the frame and swaps buffers as necessary. Returns \c false on error. */
bool CApplication::Render()
{
bool result = m_engine->Render();
@@ -410,47 +787,62 @@ bool CApplication::Render()
return true;
}
-void CApplication::Pause(bool pause)
+void CApplication::StepSimulation(float rTime)
{
// TODO
}
-void CApplication::SetMousePos(Math::Point pos)
+VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntSize> &resolutions,
+ bool fullScreen, bool resizeable)
{
- // TODO
-}
+ resolutions.clear();
-void CApplication::StepSimulation(float rTime)
-{
- // TODO
-}
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+ if (videoInfo == NULL)
+ return VIDEO_QUERY_ERROR;
-void SetShowStat(bool show)
-{
- // TODO
-}
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
-bool CApplication::RetShowStat()
-{
- // TODO
- return false;
-}
+ // Use hardware surface if available
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
-void CApplication::SetDebugMode(bool mode)
-{
- // TODO
+ // Enable hardware blit if available
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+ if (resizeable)
+ videoFlags |= SDL_RESIZABLE;
+
+ if (fullScreen)
+ videoFlags |= SDL_FULLSCREEN;
+
+
+ SDL_Rect **modes = SDL_ListModes(NULL, videoFlags);
+
+ if (modes == reinterpret_cast<SDL_Rect **>(0) )
+ return VIDEO_QUERY_NONE; // no modes available
+
+ if (modes == reinterpret_cast<SDL_Rect **>(-1) )
+ return VIDEO_QUERY_ALL; // all resolutions are possible
+
+
+ for (int i = 0; modes[i] != NULL; ++i)
+ resolutions.push_back(Math::IntSize(modes[i]->w, modes[i]->h));
+
+ return VIDEO_QUERY_OK;
}
-bool CApplication::RetDebugMode()
+void CApplication::SetDebugMode(bool mode)
{
- // TODO
- return false;
+ m_debugMode = mode;
}
-bool CApplication::RetSetupMode()
+bool CApplication::GetDebugMode()
{
- // TODO
- return false;
+ return m_debugMode;
}
void CApplication::FlushPressKey()
@@ -468,64 +860,92 @@ void CApplication::SetKey(int keyRank, int option, int key)
// TODO
}
-int CApplication::RetKey(int keyRank, int option)
+int CApplication::GetKey(int keyRank, int option)
{
// TODO
return 0;
}
-void CApplication::SetJoystick(bool enable)
+void CApplication::SetGrabInput(bool grab)
{
- // TODO
+ SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF);
}
-bool CApplication::RetJoystick()
+bool CApplication::GetGrabInput()
{
- // TODO
- return false;
+ int result = SDL_WM_GrabInput(SDL_GRAB_QUERY);
+ return result == SDL_GRAB_ON;
}
-void SetMouseType(Gfx::MouseType type)
+void CApplication::SetSystemMouseVisible(bool visible)
{
- // TODO
+ SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE);
}
-void SetNiceMouse(bool nice)
+bool CApplication::GetSystemMouseVisibile()
{
- // TODO
+ int result = SDL_ShowCursor(SDL_QUERY);
+ return result == SDL_ENABLE;
}
-bool CApplication::RetNiceMouse()
+
+void CApplication::SetSystemMousePos(Math::Point pos)
{
- return false;
+ Math::IntPoint windowPos = InterfaceToWindowCoords(pos);
+ SDL_WarpMouse(windowPos.x, windowPos.y);
+ m_systemMousePos = pos;
}
-bool CApplication::RetNiceMouseCap()
+Math::Point CApplication::GetSystemMousePos()
{
- return false;
+ return m_systemMousePos;
}
-bool CApplication::WriteScreenShot(char *filename, int width, int height)
+std::vector<JoystickDevice> CApplication::GetJoystickList()
{
- // TODO
+ std::vector<JoystickDevice> result;
+
+ int count = SDL_NumJoysticks();
+
+ for (int index = 0; index < count; ++index)
+ {
+ JoystickDevice device;
+ device.index = index;
+ device.name = SDL_JoystickName(index);
+ result.push_back(device);
+ }
+
+ return result;
}
-void CApplication::InitText()
+JoystickDevice CApplication::GetJoystick()
{
- // TODO
+ return m_joystick;
}
-void CApplication::DrawSuppl()
+void CApplication::SetJoystickEnabled(bool enable)
{
- // TODO
+ m_joystickEnabled = enable;
+
+ if (m_joystickEnabled)
+ {
+ if (! OpenJoystick())
+ {
+ m_joystickEnabled = false;
+ }
+ }
+ else
+ {
+ CloseJoystick();
+ }
}
-void CApplication::ShowStats()
+bool CApplication::GetJoystickEnabled()
{
- // TODO
+ return m_joystickEnabled;
}
-void CApplication::OutputText(long x, long y, char* str)
+std::string CApplication::GetDataFilePath(const std::string& dirName, const std::string& fileName)
{
- // TODO
+ return m_dataPath + "/" + dirName + "/" + fileName;
}
diff --git a/src/app/app.h b/src/app/app.h
index f776b10..483aa55 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -21,10 +21,14 @@
#include "common/misc.h"
-#include "graphics/common/device.h"
-#include "graphics/common/engine.h"
+#include "common/singleton.h"
+#include "graphics/core/device.h"
+#include "graphics/engine/engine.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/intsize.h"
#include <string>
+#include <vector>
class CInstanceManager;
@@ -32,19 +36,82 @@ class CEvent;
class CRobotMain;
class CSound;
-struct ApplicationPrivate;
+/**
+ \struct JoystickDevice
+ \brief Information about a joystick device */
+struct JoystickDevice
+{
+ //! Device index (-1 = invalid device)
+ int index;
+ //! Device name
+ std::string name;
+ //! Number of axes (only available after joystick opened)
+ int axisCount;
+ //! Number of buttons (only available after joystick opened)
+ int buttonCount;
+
+ JoystickDevice()
+ : index(-1), axisCount(0), buttonCount(0) {}
+};
+
+/**
+ \enum VideoQueryResult
+ \brief Result of querying for available video resolutions */
+enum VideoQueryResult
+{
+ VIDEO_QUERY_ERROR,
+ VIDEO_QUERY_NONE,
+ VIDEO_QUERY_ALL,
+ VIDEO_QUERY_OK
+};
+struct ApplicationPrivate;
+
/**
* \class CApplication
* \brief Main application
*
- * This class is responsible for creating and handling main application window,
- * receiving events, etc.
+ * This class is responsible for main application execution, including creating
+ * and handling main application window, receiving events, etc.
+ *
+ * It is a singleton class with only one instance that can be created.
+ *
+ * \section Creation Creation of other main objects
+ *
+ * The class creates the only instance of CInstanceManager, CEventQueue, CEngine,
+ * CRobotMain and CSound classes.
+ *
+ * \section Window Window management
+ *
+ * The class is responsible for creating app window, setting and changing the video mode,
+ * joystick management, grabbing input and changing the system mouse cursor
+ * position and visibility.
+ * ("System mouse cursor" means the cursor displayed by the OS in constrast to the cursor
+ * displayed by CEngine).
+ *
+ * \section Events Events
+ *
+ * Events are taken from SDL event queue, translated to common events from src/common.h
+ * and pushed to global event queue CEventQueue.
+ *
+ * Joystick events are generated somewhat differently, by running a separate timer,
+ * polling the device for changes and synthesising events on change. It avoids flooding
+ * the event queue with too many joystick events and the granularity of the timer can be
+ * adjusted.
+ *
+ * The events are passed to ProcessEvent() of classes in this order: CApplication, CEngine
+ * and CRobotMain. CApplication and CEngine's ProcessEvent() functions return bool, which
+ * means whether to pass the event on, or stop the chain. This is to enable handling some
+ * events which are internal to CApplication or CEngine.
+ *
+ * \section Portability Portability
+ *
+ * Currently, the class only handles OpenGL devices. SDL can be used with DirectX, but
+ * for that to work, video initialization and video setting must be done differently.
*
- * ...
*/
-class CApplication
+class CApplication : public CSingleton<CApplication>
{
public:
//! Constructor (can only be called once!)
@@ -54,104 +121,145 @@ public:
public:
//! Parses commandline arguments
- Error ParseArguments(int argc, char *argv[]);
+ bool ParseArguments(int argc, char *argv[]);
//! Initializes the application
bool Create();
//! Main event loop
int Run();
-
//! Returns the code to be returned at main() exit
int GetExitCode();
-protected:
//! Cleans up before exit
void Destroy();
- //! Processes an SDL event to Event struct
- void ParseEvent();
- //! Handles some incoming events
- void ProcessEvent(Event event);
- //! Renders the image in window
- bool Render();
-public:
- void Pause(bool pause);
+ //! Returns a list of possible video modes
+ VideoQueryResult GetVideoResolutionList(std::vector<Math::IntSize> &resolutions,
+ bool fullScreen, bool resizeable);
+
+ //! Returns the current video mode
+ Gfx::GLDeviceConfig GetVideoConfig();
+
+ //! Change the video mode to given mode
+ bool ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig);
+
+ //! Updates the simulation state
void StepSimulation(float rTime);
- void SetMousePos(Math::Point pos);
+ //! Returns a list of available joystick devices
+ std::vector<JoystickDevice> GetJoystickList();
- void SetShowStat(bool show);
- bool RetShowStat();
- void SetDebugMode(bool mode);
- bool RetDebugMode();
- bool RetSetupMode();
+ //! Returns info about the current joystick
+ JoystickDevice GetJoystick();
+
+ //! Change the current joystick device
+ bool ChangeJoystick(const JoystickDevice &newJoystick);
+
+ //! Enables/disables joystick
+ void SetJoystickEnabled(bool enable);
+ //! Returns whether joystick is enabled
+ bool GetJoystickEnabled();
+
+ //! Polls the state of joystick axes and buttons
+ void UpdateJoystick();
void FlushPressKey();
void ResetKey();
void SetKey(int keyRank, int option, int key);
- int RetKey(int keyRank, int option);
+ int GetKey(int keyRank, int option);
+
+ //! Sets the grab mode for input (keyboard & mouse)
+ void SetGrabInput(bool grab);
+ //! Returns the grab mode
+ bool GetGrabInput();
- void SetJoystick(bool enable);
- bool RetJoystick();
+ //! Sets the visiblity of system mouse cursor
+ void SetSystemMouseVisible(bool visible);
+ //! Returns the visiblity of system mouse cursor
+ bool GetSystemMouseVisibile();
- void SetMouseType(Gfx::MouseType type);
- void SetNiceMouse(bool nice);
- bool RetNiceMouse();
- bool RetNiceMouseCap();
+ //! Sets the position of system mouse cursor (in interface coords)
+ void SetSystemMousePos(Math::Point pos);
+ //! Returns the position of system mouse cursor (in interface coords)
+ Math::Point GetSystemMousePos();
+
+ //! Enables/disables debug mode (prints more info in logger)
+ void SetDebugMode(bool mode);
+ //! Returns whether debug mode is enabled
+ bool GetDebugMode();
- bool WriteScreenShot(char *filename, int width, int height);
+ //! Returns the full path to a file in data directory
+ std::string GetDataFilePath(const std::string &dirName, const std::string &fileName);
protected:
- //HRESULT ConfirmDevice( DDCAPS* pddDriverCaps, D3DDEVICEDESC7* pd3dDeviceDesc );
- //HRESULT Initialize3DEnvironment();
- //HRESULT Change3DEnvironment();
- //HRESULT CreateZBuffer(GUID* pDeviceGUID);
- //HRESULT Render3DEnvironment();
- //VOID Cleanup3DEnvironment();
- //VOID DeleteDeviceObjects();
- //VOID DisplayFrameworkError( HRESULT, DWORD );
-
- void InitText();
- void DrawSuppl();
- void ShowStats();
- void OutputText(long x, long y, char* str);
+ //! Creates the window's SDL_Surface
+ bool CreateVideoSurface();
+
+ //! Processes the captured SDL event to Event struct
+ Event ParseEvent();
+ //! Handles some incoming events
+ bool ProcessEvent(const Event &event);
+ //! Renders the image in window
+ bool Render();
+
+ //! Opens the joystick device
+ bool OpenJoystick();
+ //! Closes the joystick device
+ void CloseJoystick();
+
+ //! Converts window coords to interface coords
+ Math::Point WindowToInterfaceCoords(Math::IntPoint pos);
+ //! Converts the interface coords to window coords
+ Math::IntPoint InterfaceToWindowCoords(Math::Point pos);
protected:
+ //! Instance manager
+ CInstanceManager* m_iMan;
//! Private (SDL-dependent data)
ApplicationPrivate* m_private;
- CInstanceManager* m_iMan;
- Gfx::DeviceConfig m_deviceConfig;
+ //! Global event queue
+ CEventQueue* m_eventQueue;
+ //! Graphics engine
Gfx::CEngine* m_engine;
- CEvent* m_event;
- CRobotMain* m_robotMain;
+ //! Graphics device
+ Gfx::CDevice* m_device;
+ //! Sound subsystem
CSound* m_sound;
+ //! Main class of the proper game engine
+ CRobotMain* m_robotMain;
//! Code to return at exit
int m_exitCode;
-
+ //! Whether application window is active
bool m_active;
- bool m_activateApp;
- bool m_ready;
- bool m_joystick;
+ //! Whether debug mode is enabled
+ bool m_debugMode;
+
+ //! Current configuration of OpenGL display device
+ Gfx::GLDeviceConfig m_deviceConfig;
+ //! Previous configuration of OpenGL display device
+ Gfx::GLDeviceConfig m_lastDeviceConfig;
+ //! Text set as window title
std::string m_windowTitle;
- long m_vidMemTotal;
- bool m_appUseZBuffer;
- bool m_appUseStereo;
- bool m_showStats;
- bool m_debugMode;
- bool m_audioState;
- bool m_audioTrack;
- bool m_niceMouse;
- bool m_setupMode;
int m_keyState;
Math::Vector m_axeKey;
Math::Vector m_axeJoy;
- bool m_joyButton[32];
- Math::Point m_mousePos;
+ Math::Point m_systemMousePos;
long m_mouseWheel;
- float m_time;
long m_key[50][2];
+
+ //! Info about current joystick device
+ JoystickDevice m_joystick;
+ //! Whether joystick is enabled
+ bool m_joystickEnabled;
+ //! Current state of joystick axes; may be updated from another thread
+ std::vector<int> m_joyAxeState;
+ //! Current state of joystick buttons; may be updated from another thread
+ std::vector<bool> m_joyButtonState;
+
+ //! Path to directory with data files
+ std::string m_dataPath;
};
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 151cd20..dce13da 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -24,6 +24,48 @@
#include "common/restext.h"
+/* Doxygen main page */
+
+/**
+
+\mainpage
+
+Doxygen documentation of Colobot project
+
+\section Intro Introduction
+
+The source code released by Epitec was sparsely documented. This documentation, written from scratch,
+will aim to describe the various components of the code.
+
+Currently, the only documented classes are the ones written from scratch or the old ones rewritten
+to match the new code.
+In time, the documentation will be extended to cover every major part of the code.
+
+\section Structure Code structure
+
+The source code was split from the original all-in-one directory to subdirectories,
+each containing one major part of the project.
+The current layout is the following:
+ - src/CBot - separate library with CBot language
+ - src/app - class CApplication and everything concerned with SDL plus other system-dependent
+ code such as displaying a message box, finding files, etc.
+ - src/common - shared structs, enums, defines, etc.; should not have any external dependencies
+ - src/graphics/core - abstract interface of graphics device (abstract CDevice class)
+ (split from old src/graphics/common)
+ - src/graphics/engine - main graphics engine based on abstract graphics device; is composed
+ of CEngine class and associated classes implementing the 3D engine (split from old src/graphics/common)
+ - src/graphics/opengl - concrete implementation of CDevice class in OpenGL: CGLDevice
+ - src/graphics/d3d - in (far) future - perhaps a newer implementation in DirectX (9? 10?)
+ - src/math - mathematical structures and functions
+ - src/object - non-graphical game engine, that is robots, buildings, etc.
+ - src/ui - 2D user interface (menu, buttons, check boxes, etc.)
+ - src/sound - sound and music engine written using fmod library
+ - src/physics - physics engine
+ - src/script - link with the CBot library
+ - src/metafile - separate program for packing data files to .dat format
+*/
+
+
//! Entry point to the program
int main(int argc, char *argv[])
{
@@ -33,16 +75,17 @@ int main(int argc, char *argv[])
CApplication app; // single instance of the application
- Error err = app.ParseArguments(argc, argv);
- if (err != ERR_OK)
+ if (! app.ParseArguments(argc, argv))
{
SystemDialog(SDT_ERROR, "COLOBOT", "Invalid commandline arguments!\n");
+ return app.GetExitCode();
}
int code = 0;
if (! app.Create())
{
+ app.Destroy(); // ensure a clean exit
code = app.GetExitCode();
logger.Info("Didn't run main loop. Exiting with code %d\n", code);
return code;
diff --git a/src/app/system.cpp b/src/app/system.cpp
index a765e11..eb0321b 100644
--- a/src/app/system.cpp
+++ b/src/app/system.cpp
@@ -21,19 +21,21 @@
#include "common/config.h"
+
#if defined(PLATFORM_WINDOWS)
-#include <windows.h>
+#include "system_windows.h"
+
#elif defined(PLATFORM_LINUX)
-#include <cstdlib>
+#include "system_linux.h"
+
#else
-#include <iostream>
+#include "system_other.h"
+
#endif
+#include <cassert>
-SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message);
-SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message);
-SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message);
/**
* Displays a system dialog with info, error, question etc. message.
@@ -45,209 +47,103 @@ SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string&
*/
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
{
- #if defined(PLATFORM_WINDOWS)
+#if defined(PLATFORM_WINDOWS)
return SystemDialog_Windows(type, title, message);
- #elif defined(PLATFORM_LINUX)
+#elif defined(PLATFORM_LINUX)
return SystemDialog_Linux(type, title, message);
- #else
+#else
return SystemDialog_Other(type, title, message);
- #endif
+#endif
}
-
-
-#if defined(PLATFORM_WINDOWS)
-
-// Convert a wide Unicode string to an UTF8 string
-std::string UTF8_Encode_Windows(const std::wstring &wstr)
+SystemTimeStamp* CreateTimeStamp()
{
- int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
- std::string strTo(size_needed, 0);
- WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
- return strTo;
+ return new SystemTimeStamp();
}
-// Convert an UTF8 string to a wide Unicode String
-std::wstring UTF8_Decode_Windows(const std::string &str)
+void DestroyTimeStamp(SystemTimeStamp *stamp)
{
- int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
- std::wstring wstrTo(size_needed, 0);
- MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
- return wstrTo;
+ delete stamp;
}
-SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message)
+void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
{
- unsigned int windowsType = 0;
- std::wstring windowsMessage = UTF8_Decode_Windows(message);
- std::wstring windowsTitle = UTF8_Decode_Windows(title);
-
- switch (type)
- {
- case SDT_INFO:
- default:
- windowsType = MB_ICONINFORMATION|MB_OK;
- break;
- case SDT_WARNING:
- windowsType = MB_ICONWARNING|MB_OK;
- break;
- case SDT_ERROR:
- windowsType = MB_ICONERROR|MB_OK;
- break;
- case SDT_YES_NO:
- windowsType = MB_ICONQUESTION|MB_YESNO;
- break;
- case SDT_OK_CANCEL:
- windowsType = MB_ICONWARNING|MB_OKCANCEL;
- break;
- }
-
- switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType))
- {
- case IDOK:
- return SDR_OK;
- case IDCANCEL:
- return SDR_CANCEL;
- case IDYES:
- return SDR_YES;
- case IDNO:
- return SDR_NO;
- default:
- break;
- }
-
- return SDR_OK;
+ *dst = *src;
}
+void GetCurrentTimeStamp(SystemTimeStamp *stamp)
+{
+#if defined(PLATFORM_WINDOWS)
+ GetCurrentTimeStamp_Windows(stamp);
#elif defined(PLATFORM_LINUX)
+ GetCurrentTimeStamp_Linux(stamp);
+#else
+ GetCurrentTimeStamp_Other(stamp);
+#endif
+}
-SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message)
+float GetTimeStampResolution(SystemTimeUnit unit)
{
- std::string options = "";
- switch (type)
- {
- case SDT_INFO:
- default:
- options = "--info";
- break;
- case SDT_WARNING:
- options = "--warning";
- break;
- case SDT_ERROR:
- options = "--error";
- break;
- case SDT_YES_NO:
- options = "--question --ok-label=\"Yes\" --cancel-label=\"No\"";
- break;
- case SDT_OK_CANCEL:
- options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\"";
- break;
- }
-
- std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\"";
- int code = system(command.c_str());
-
- SystemDialogResult result = SDR_OK;
- switch (type)
- {
- case SDT_YES_NO:
- result = code ? SDR_NO : SDR_YES;
- break;
- case SDT_OK_CANCEL:
- result = code ? SDR_CANCEL : SDR_OK;
- break;
- default:
- break;
- }
-
+ unsigned long long exact = 0;
+#if defined(PLATFORM_WINDOWS)
+ exact = GetTimeStampExactResolution_Windows();
+#elif defined(PLATFORM_LINUX)
+ exact = GetTimeStampExactResolution_Linux();
+#else
+ exact = GetTimeStampExactResolution_Other();
+#endif
+ float result = 0.0f;
+ if (unit == STU_SEC)
+ result = exact * 1e-9;
+ else if (unit == STU_MSEC)
+ result = exact * 1e-6;
+ else if (unit == STU_USEC)
+ result = exact * 1e-3;
+ else
+ assert(false);
return result;
}
+long long GetTimeStampExactResolution()
+{
+#if defined(PLATFORM_WINDOWS)
+ return GetTimeStampExactResolution_Windows();
+#elif defined(PLATFORM_LINUX)
+ return GetTimeStampExactResolution_Linux();
#else
+ return GetTimeStampExactResolution_Other();
+#endif
+}
-SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message)
+float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit)
{
- switch (type)
- {
- case SDT_INFO:
- std::cout << "INFO: ";
- break;
- case SDT_WARNING:
- std::cout << "WARNING:";
- break;
- case SDT_ERROR:
- std::cout << "ERROR: ";
- break;
- case SDT_YES_NO:
- case SDT_OK_CANCEL:
- std::cout << "QUESTION: ";
- break;
- }
-
- std::cout << message << std::endl;
-
- std::string line;
-
- SystemDialogResult result = SDR_OK;
-
- bool done = false;
- while (!done)
- {
- switch (type)
- {
- case SDT_INFO:
- case SDT_WARNING:
- case SDT_ERROR:
- std::cout << "Press ENTER to continue";
- break;
-
- case SDT_YES_NO:
- std::cout << "Type 'Y' for Yes or 'N' for No";
- break;
-
- case SDT_OK_CANCEL:
- std::cout << "Type 'O' for OK or 'C' for Cancel";
- break;
- }
-
- std::getline(std::cin, line);
-
- switch (type)
- {
- case SDT_INFO:
- case SDT_WARNING:
- case SDT_ERROR:
- done = true;
- break;
-
- case SDT_YES_NO:
- if (line == "Y" || line == "y")
- {
- result = SDR_YES;
- done = true;
- }
- else if (line == "N" || line == "n")
- {
- result = SDR_NO;
- done = true;
- }
- break;
-
- case SDT_OK_CANCEL:
- if (line == "O" || line == "o")
- {
- done = true;
- result = SDR_OK;
- }
- else if (line == "C" || line == "c")
- {
- done = true;
- result = SDR_CANCEL;
- }
- break;
- }
- }
-
+ long long exact = 0;
+#if defined(PLATFORM_WINDOWS)
+ exact = TimeStampExactDiff_Windows(before, after);
+#elif defined(PLATFORM_LINUX)
+ exact = TimeStampExactDiff_Linux(before, after);
+#else
+ exact = TimeStampExactDiff_Other(before, after);
+#endif
+ float result = 0.0f;
+ if (unit == STU_SEC)
+ result = exact * 1e-9;
+ else if (unit == STU_MSEC)
+ result = exact * 1e-6;
+ else if (unit == STU_USEC)
+ result = exact * 1e-3;
+ else
+ assert(false);
return result;
}
-#endif // if defined(PLATFORM_WINDOWS)
+
+long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+#if defined(PLATFORM_WINDOWS)
+ return TimeStampExactDiff_Windows(before, after);
+#elif defined(PLATFORM_LINUX)
+ return TimeStampExactDiff_Linux(before, after);
+#else
+ return TimeStampExactDiff_Other(before, after);
+#endif
+}
diff --git a/src/app/system.h b/src/app/system.h
index 3bf6457..3c04760 100644
--- a/src/app/system.h
+++ b/src/app/system.h
@@ -23,6 +23,8 @@
#include <string>
+/* Dialog utils */
+
/**
* \enum SysDialogType
* \brief Type of system dialog
@@ -57,3 +59,47 @@ enum SystemDialogResult
//! Displays a system dialog
SystemDialogResult SystemDialog(SystemDialogType, const std::string &title, const std::string &message);
+
+
+/* Time utils */
+
+enum SystemTimeUnit
+{
+ //! seconds
+ STU_SEC,
+ //! milliseconds
+ STU_MSEC,
+ //! microseconds
+ STU_USEC
+};
+
+/* Forward declaration of time stamp struct
+ * SystemTimeStamp should be used in a pointer context.
+ * The implementation details are hidden because of platform dependence. */
+struct SystemTimeStamp;
+
+//! Creates a new time stamp object
+SystemTimeStamp* CreateTimeStamp();
+
+//! Destroys a time stamp object
+void DestroyTimeStamp(SystemTimeStamp *stamp);
+
+//! Copies the time stamp from \a src to \a dst
+void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
+
+//! Returns a time stamp associated with current time
+void GetCurrentTimeStamp(SystemTimeStamp *stamp);
+
+//! Returns the platform's expected time stamp resolution
+float GetTimeStampResolution(SystemTimeUnit unit = STU_SEC);
+
+//! Returns the platform's exact (in nanosecond units) expected time stamp resolution
+long long GetTimeStampExactResolution();
+
+//! Returns a difference between two timestamps in given time unit
+/** The difference is \a after - \a before. */
+float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit = STU_SEC);
+
+//! Returns the exact (in nanosecond units) difference between two timestamps
+/** The difference is \a after - \a before. */
+long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after);
diff --git a/src/app/system_linux.h b/src/app/system_linux.h
new file mode 100644
index 0000000..f58c9a1
--- /dev/null
+++ b/src/app/system_linux.h
@@ -0,0 +1,101 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// system_linux.h
+
+/* This header contains Linux-specific code for system utils
+ from system.h. There is no separate .cpp module for simplicity.*/
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+
+
+SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message);
+
+void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp);
+long long GetTimeStampExactResolution_Linux();
+long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after);
+
+struct SystemTimeStamp
+{
+ timespec clockTime;
+
+ SystemTimeStamp()
+ {
+ clockTime.tv_sec = clockTime.tv_nsec = 0;
+ }
+};
+
+
+SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message)
+{
+ std::string options = "";
+ switch (type)
+ {
+ case SDT_INFO:
+ default:
+ options = "--info";
+ break;
+ case SDT_WARNING:
+ options = "--warning";
+ break;
+ case SDT_ERROR:
+ options = "--error";
+ break;
+ case SDT_YES_NO:
+ options = "--question --ok-label=\"Yes\" --cancel-label=\"No\"";
+ break;
+ case SDT_OK_CANCEL:
+ options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\"";
+ break;
+ }
+
+ std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\"";
+ int code = system(command.c_str());
+
+ SystemDialogResult result = SDR_OK;
+ switch (type)
+ {
+ case SDT_YES_NO:
+ result = code ? SDR_NO : SDR_YES;
+ break;
+ case SDT_OK_CANCEL:
+ result = code ? SDR_CANCEL : SDR_OK;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp)
+{
+ clock_gettime(CLOCK_MONOTONIC, &stamp->clockTime);
+}
+
+long long GetTimeStampExactResolution_Linux()
+{
+ return 1ll;
+}
+
+long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+ return (after->clockTime.tv_nsec - before->clockTime.tv_nsec) +
+ (after->clockTime.tv_sec - before->clockTime.tv_sec) * 1000000000ll;
+}
diff --git a/src/app/system_other.h b/src/app/system_other.h
new file mode 100644
index 0000000..9f13ffa
--- /dev/null
+++ b/src/app/system_other.h
@@ -0,0 +1,146 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// system_other.h
+
+/* This header contains fallback code for other platforms for system utils
+ from system.h. There is no separate .cpp module for simplicity.*/
+
+#include <SDL/SDL.h>
+
+#include <iostream>
+
+
+SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message);
+
+void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp);
+long long GetTimeStampExactResolution_Other();
+long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after);
+
+struct SystemTimeStamp
+{
+ Uint32 sdlTicks;
+
+ SystemTimeStamp()
+ {
+ sdlTicks = 0;
+ }
+};
+
+
+SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message)
+{
+ switch (type)
+ {
+ case SDT_INFO:
+ std::cout << "INFO: ";
+ break;
+ case SDT_WARNING:
+ std::cout << "WARNING:";
+ break;
+ case SDT_ERROR:
+ std::cout << "ERROR: ";
+ break;
+ case SDT_YES_NO:
+ case SDT_OK_CANCEL:
+ std::cout << "QUESTION: ";
+ break;
+ }
+
+ std::cout << message << std::endl;
+
+ std::string line;
+
+ SystemDialogResult result = SDR_OK;
+
+ bool done = false;
+ while (!done)
+ {
+ switch (type)
+ {
+ case SDT_INFO:
+ case SDT_WARNING:
+ case SDT_ERROR:
+ std::cout << "Press ENTER to continue";
+ break;
+
+ case SDT_YES_NO:
+ std::cout << "Type 'Y' for Yes or 'N' for No";
+ break;
+
+ case SDT_OK_CANCEL:
+ std::cout << "Type 'O' for OK or 'C' for Cancel";
+ break;
+ }
+
+ std::getline(std::cin, line);
+
+ switch (type)
+ {
+ case SDT_INFO:
+ case SDT_WARNING:
+ case SDT_ERROR:
+ done = true;
+ break;
+
+ case SDT_YES_NO:
+ if (line == "Y" || line == "y")
+ {
+ result = SDR_YES;
+ done = true;
+ }
+ else if (line == "N" || line == "n")
+ {
+ result = SDR_NO;
+ done = true;
+ }
+ break;
+
+ case SDT_OK_CANCEL:
+ if (line == "O" || line == "o")
+ {
+ done = true;
+ result = SDR_OK;
+ }
+ else if (line == "C" || line == "c")
+ {
+ done = true;
+ result = SDR_CANCEL;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+
+void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp)
+{
+ stamp->sdlTicks = SDL_GetTicks();
+}
+
+long long GetTimeStampExactResolution_Other()
+{
+ return 1000000ll;
+}
+
+long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+ return (after->sdlTicks - before->sdlTicks) * 1000000ll;
+}
diff --git a/src/app/system_windows.h b/src/app/system_windows.h
new file mode 100644
index 0000000..eb6beec
--- /dev/null
+++ b/src/app/system_windows.h
@@ -0,0 +1,122 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// system_windows.h
+
+/* This header contains Windows-specific code for system utils
+ from system.h. There is no separate .cpp module for simplicity.*/
+
+#include <windows.h>
+
+
+std::string UTF8_Encode_Windows(const std::wstring &wstr);
+std::wstring UTF8_Decode_Windows(const std::string &str);
+SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message);
+
+void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp);
+long long GetTimeStampExactResolution_Windows();
+long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after);
+
+struct SystemTimeStamp
+{
+ FILETIME fileTime;
+
+ SystemTimeStamp()
+ {
+ fileTime.dwHighDateTime = fileTime.dwLowDateTime = 0;
+ }
+};
+
+
+// Convert a wide Unicode string to an UTF8 string
+std::string UTF8_Encode_Windows(const std::wstring &wstr)
+{
+ int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
+ std::string strTo(size_needed, 0);
+ WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
+ return strTo;
+}
+
+// Convert an UTF8 string to a wide Unicode String
+std::wstring UTF8_Decode_Windows(const std::string &str)
+{
+ int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
+ std::wstring wstrTo(size_needed, 0);
+ MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
+ return wstrTo;
+}
+
+SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message)
+{
+ unsigned int windowsType = 0;
+ std::wstring windowsMessage = UTF8_Decode_Windows(message);
+ std::wstring windowsTitle = UTF8_Decode_Windows(title);
+
+ switch (type)
+ {
+ case SDT_INFO:
+ default:
+ windowsType = MB_ICONINFORMATION|MB_OK;
+ break;
+ case SDT_WARNING:
+ windowsType = MB_ICONWARNING|MB_OK;
+ break;
+ case SDT_ERROR:
+ windowsType = MB_ICONERROR|MB_OK;
+ break;
+ case SDT_YES_NO:
+ windowsType = MB_ICONQUESTION|MB_YESNO;
+ break;
+ case SDT_OK_CANCEL:
+ windowsType = MB_ICONWARNING|MB_OKCANCEL;
+ break;
+ }
+
+ switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType))
+ {
+ case IDOK:
+ return SDR_OK;
+ case IDCANCEL:
+ return SDR_CANCEL;
+ case IDYES:
+ return SDR_YES;
+ case IDNO:
+ return SDR_NO;
+ default:
+ break;
+ }
+
+ return SDR_OK;
+}
+
+
+void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp)
+{
+ GetSystemTimeAsFileTime(&stamp->fileTime);
+}
+
+long long GetTimeStampExactResolution_Windows()
+{
+ return 100ll;
+}
+
+long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after)
+{
+ long long tH = (1ll << 32) * (after->fileTime.dwHighDateTime - before->fileTime.dwHighDateTime);
+ long long tL = after->fileTime.dwLowDateTime - before->fileTime.dwLowDateTime;
+ return (tH + tL) * 100ll;
+}
diff --git a/src/common/config.h.cmake b/src/common/config.h.cmake
index b066387..f496db0 100644
--- a/src/common/config.h.cmake
+++ b/src/common/config.h.cmake
@@ -1,8 +1,10 @@
-#pragma once
-
-// Macros set by CMake
-#cmakedefine DEBUG
-#cmakedefine PLATFORM_WINDOWS @PLATFORM_WINDOWS@
-#cmakedefine PLATFORM_LINUX @PLATFORM_LINUX@
-#cmakedefine PLATFORM_OTHER @PLATFORM_OTHER@
-
+#pragma once
+
+// Macros set by CMake
+#cmakedefine DEBUG
+
+#cmakedefine PLATFORM_WINDOWS @PLATFORM_WINDOWS@
+#cmakedefine PLATFORM_LINUX @PLATFORM_LINUX@
+#cmakedefine PLATFORM_OTHER @PLATFORM_OTHER@
+
+#cmakedefine USE_GLEW @USE_GLEW@
diff --git a/src/common/event.cpp b/src/common/event.cpp
index 9af4691..6a5f4d3 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -16,27 +16,12 @@
// event.cpp
-#include "common/iman.h"
#include "common/event.h"
-
-#include <string.h>
-
-
-Event::Event()
-{
- event = EVENT_NULL;
- param = 0;
- axeX = 0.0f;
- axeY = 0.0f;
- axeZ = 0.0f;
- keyState = 0;
- rTime = 0.0f;
-}
+#include "common/iman.h"
-// Object's constructor.
-CEvent::CEvent(CInstanceManager* iMan)
+CEventQueue::CEventQueue(CInstanceManager* iMan)
{
m_iMan = iMan;
m_iMan->AddInstance(CLASS_EVENT, this);
@@ -44,51 +29,38 @@ CEvent::CEvent(CInstanceManager* iMan)
Flush();
}
-// Object's destructor.
-
-CEvent::~CEvent()
+CEventQueue::~CEventQueue()
{
}
-
-// Empty the FIFO of events.
-
-void CEvent::Flush()
+void CEventQueue::Flush()
{
m_head = 0;
m_tail = 0;
m_total = 0;
}
-// Produces an event.
-
-void CEvent::MakeEvent(Event &event, EventMsg msg)
-{
- memset(&event, 0, sizeof(Event));
- event.event = msg;
-}
-
-// Adds an event in the FIFO.
-
-bool CEvent::AddEvent(const Event &event)
+/** If the maximum size of queue has been reached, returns \c false.
+ Else, adds the event to the queue and returns \c true. */
+bool CEventQueue::AddEvent(const Event &event)
{
- if ( m_total >= MAXEVENT ) return false;
+ if ( m_total >= MAX_EVENT_QUEUE ) return false;
m_fifo[m_head++] = event;
- if ( m_head >= MAXEVENT ) m_head = 0;
+ if ( m_head >= MAX_EVENT_QUEUE ) m_head = 0;
m_total ++;
return true;
}
-// Removes an event from the FIFO.
-
-bool CEvent::GetEvent(Event &event)
+/** If the queue is empty, returns \c false.
+ Else, gets the event from the front, puts it into \a event and returns \c true. */
+bool CEventQueue::GetEvent(Event &event)
{
if ( m_head == m_tail ) return false;
event = m_fifo[m_tail++];
- if ( m_tail >= MAXEVENT ) m_tail = 0;
+ if ( m_tail >= MAX_EVENT_QUEUE ) m_tail = 0;
m_total --;
return true;
diff --git a/src/common/event.h b/src/common/event.h
index 8174fab..0d9aa7c 100644
--- a/src/common/event.h
+++ b/src/common/event.h
@@ -19,40 +19,54 @@
#pragma once
+#include "common/key.h"
#include "math/point.h"
+#include <string.h>
-#if !defined (WM_XBUTTONDOWN)
-#define WM_XBUTTONDOWN 0x020B
-#define WM_XBUTTONUP 0x020C
-#define XBUTTON1 0x0001
-#define XBUTTON2 0x0002
-#endif
+class CInstanceManager;
+/**
+ \enum EventType
+ \brief Type of event message
+ */
+enum EventType
+{
-class CInstanceManager;
+// TODO: document the meaning of each value
+ //! Invalid event / no event
+ EVENT_NULL = 0,
-const int MAXEVENT = 100;
+ //! Event sent on user or system quit request
+ EVENT_QUIT = 1,
-// Events.
+ //? EVENT_FRAME = 2,
-enum EventMsg
-{
- EVENT_NULL = 0,
+ //! Event sent after pressing a mouse button
+ EVENT_MOUSE_BUTTON_DOWN = 3,
+ //! Event sent after releasing a mouse button
+ EVENT_MOUSE_BUTTON_UP = 4,
+ //! Event sent after moving the mouse
+ EVENT_MOUSE_MOVE = 7,
+ //! Event sent after pressing a key
+ EVENT_KEY_DOWN = 8,
+ //! Event sent after releasing a key
+ EVENT_KEY_UP = 9,
- EVENT_QUIT = 1,
- EVENT_FRAME = 2,
- EVENT_LBUTTONDOWN = 3,
- EVENT_RBUTTONDOWN = 4,
- EVENT_LBUTTONUP = 5,
- EVENT_RBUTTONUP = 6,
- EVENT_MOUSEMOVE = 7,
- EVENT_KEYDOWN = 8,
- EVENT_KEYUP = 9,
- EVENT_CHAR = 10,
- EVENT_FOCUS = 11,
+ //! Event sent when application window loses/gains focus
+ EVENT_ACTIVE = 10,
+
+ //? EVENT_CHAR = 10,
+ //? EVENT_FOCUS = 11,
+
+ //! Event sent after moving joystick axes
+ EVENT_JOY_AXIS = 12,
+ //! Event sent after pressing a joystick button
+ EVENT_JOY_BUTTON_DOWN = 13,
+ //! Event sent after releasing a joystick button
+ EVENT_JOY_BUTTON_UP = 14,
EVENT_UPDINTERFACE = 20,
EVENT_WIN = 30,
@@ -525,60 +539,168 @@ enum EventMsg
EVENT_STUDIO_STEP = 2053,
EVENT_USER = 10000,
- EVENT_FORCE_DWORD = 0x7fffffff
+ EVENT_FORCE_LONG = 0x7fffffff
+};
+
+
+/** \enum PressState
+ \brief State of key/mouse button */
+enum PressState
+{
+ STATE_PRESSED,
+ STATE_RELEASED
+};
+
+
+/** \struct KeyEventData
+ \brief Additional data for keyboard event */
+struct KeyEventData
+{
+ //! STATE_PRESSED or STATE_RELEASED */
+ PressState state;
+ //! Key symbol: KEY(...) macro value (from common/key.h)
+ unsigned int key;
+ //! Keyboard modifiers: a bitmask made of KEY_MOD(...) macro values (from common/key.h)
+ unsigned int mod;
+ //! Unicode character
+ unsigned int unicode;
+
+ KeyEventData()
+ : state(STATE_PRESSED), key(0), mod(0), unicode(0) {}
+};
+
+/** \struct MouseMotionEventData
+ \brief Additional data for mouse move event */
+struct MouseMoveEventData
+{
+ //! Current button state
+ unsigned char state;
+ //! Position of mouse in normalized coordinates (0..1)
+ Math::Point pos;
+
+ MouseMoveEventData()
+ : state(STATE_PRESSED) {}
+};
+
+/** \struct MouseButtonEventData
+ \brief Additional data mouse button event */
+struct MouseButtonEventData
+{
+ //! The mouse button index
+ unsigned char button;
+ //! STATE_PRESSED or STATE_RELEASED
+ PressState state;
+ //! Position of mouse in normalized coordinates (0..1)
+ Math::Point pos;
+
+ MouseButtonEventData()
+ : button(0), state(STATE_PRESSED) {}
+};
+
+/** \struct JoyAxisEventData
+ \brief Additional data for joystick axis event */
+struct JoyAxisEventData
+{
+ //! The joystick axis index
+ unsigned char axis;
+ //! The axis value (range: -32768 to 32767)
+ int value;
+
+ JoyAxisEventData()
+ : axis(axis), value(value) {}
+};
+
+/** \struct JoyButtonEventData
+ \brief Additional data for joystick button event */
+struct JoyButtonEventData
+{
+ //! The joystick button index
+ unsigned char button;
+ //! STATE_PRESSED or STATE_RELEASED
+ PressState state;
+
+ JoyButtonEventData()
+ : button(0), state(STATE_PRESSED) {}
+};
+
+/** \enum ActiveEventFlags
+ \brief Type of focus gained/lost */
+enum ActiveEventFlags
+{
+ //! Application window focus
+ ACTIVE_APP = 0x01,
+ //! Input focus
+ ACTIVE_INPUT = 0x02,
+ //! Mouse focus
+ ACTIVE_MOUSE = 0x04
+
+};
+
+/** \struct ActiveEventData
+ \brief Additional data for active event */
+struct ActiveEventData
+{
+ //! Flags (bitmask of enum values ActiveEventFlags)
+ unsigned char flags = 0;
+ //! True if the focus was gained; false otherwise
+ bool gain;
+
+ ActiveEventData()
+ : flags(0), gain(false) {}
};
+
+/**
+ \struct Event
+ \brief Event sent by system, interface or game
+
+ Event is described by its type (EventType) and the union
+ \a data contains additional data about the event.
+ Different members of the union are filled with different event types.
+ With some events, nothing is filled (it's zeroed out).
+ The union contains roughly the same information as SDL_Event struct
+ but packaged to independent structs and fields.
+ **/
struct Event
{
- EventMsg event; // event (EVENT *)
- long param; // parameter
- Math::Point pos; // mouse position (0 .. 1)
- float axeX; // control the X axis (-1 .. 1)
- float axeY; // control of the Y axis (-1 .. 1)
- float axeZ; // control the Z axis (-1 .. 1)
- short keyState; // state of the keyboard (KS_ *)
- float rTime; // relative time
-
- Event();
+ //! Type of event (EVENT_*)
+ EventType type;
+
+ //! If true, the event was produced by system (SDL); else, it has come from user interface
+ bool systemEvent;
+
+ //! Additional data for EVENT_KEY_DOWN and EVENT_KEY_UP
+ KeyEventData key;
+ //! Additional data for EVENT_MOUSE_BUTTON_DOWN and EVENT_MOUSE_BUTTON_UP
+ MouseButtonEventData mouseButton;
+ //! Additional data for EVENT_MOUSE_MOVE
+ MouseMoveEventData mouseMove;
+ //! Additional data for EVENT_JOY
+ JoyAxisEventData joyAxis;
+ //! Additional data for EVENT_JOY_AXIS
+ JoyButtonEventData joyButton;
+ //! Additional data for EVENT_ACTIVE
+ ActiveEventData active;
+
+ //? long param; // parameter
+ //? Math::Point pos; // mouse position (0 .. 1)
+ //? float axeX; // control the X axis (-1 .. 1)
+ //? float axeY; // control of the Y axis (-1 .. 1)
+ //? float axeZ; // control the Z axis (-1 .. 1)
+ //? short keyState; // state of the keyboard (KS_ *)
+ //? float rTime; // relative time
+
+ Event(EventType aType = EVENT_NULL)
+ : type(aType), systemEvent(false) {}
};
-const int VK_BUTTON1 = (0x100+1); // joystick button 1
-const int VK_BUTTON2 = (0x100+2); // joystick button 2
-const int VK_BUTTON3 = (0x100+3); // joystick button 3
-const int VK_BUTTON4 = (0x100+4); // joystick button 4
-const int VK_BUTTON5 = (0x100+5); // joystick button 5
-const int VK_BUTTON6 = (0x100+6); // joystick button 6
-const int VK_BUTTON7 = (0x100+7); // joystick button 7
-const int VK_BUTTON8 = (0x100+8); // joystick button 8
-const int VK_BUTTON9 = (0x100+9); // joystick button 9
-const int VK_BUTTON10 = (0x100+10); // joystick button 10
-const int VK_BUTTON11 = (0x100+11); // joystick button 11
-const int VK_BUTTON12 = (0x100+12); // joystick button 12
-const int VK_BUTTON13 = (0x100+13); // joystick button 13
-const int VK_BUTTON14 = (0x100+14); // joystick button 14
-const int VK_BUTTON15 = (0x100+15); // joystick button 15
-const int VK_BUTTON16 = (0x100+16); // joystick button 16
-const int VK_BUTTON17 = (0x100+17); // joystick button 17
-const int VK_BUTTON18 = (0x100+18); // joystick button 18
-const int VK_BUTTON19 = (0x100+19); // joystick button 19
-const int VK_BUTTON20 = (0x100+20); // joystick button 20
-const int VK_BUTTON21 = (0x100+21); // joystick button 21
-const int VK_BUTTON22 = (0x100+22); // joystick button 22
-const int VK_BUTTON23 = (0x100+23); // joystick button 23
-const int VK_BUTTON24 = (0x100+24); // joystick button 24
-const int VK_BUTTON25 = (0x100+25); // joystick button 25
-const int VK_BUTTON26 = (0x100+26); // joystick button 26
-const int VK_BUTTON27 = (0x100+27); // joystick button 27
-const int VK_BUTTON28 = (0x100+28); // joystick button 28
-const int VK_BUTTON29 = (0x100+29); // joystick button 29
-const int VK_BUTTON30 = (0x100+30); // joystick button 30
-const int VK_BUTTON31 = (0x100+31); // joystick button 31
-const int VK_BUTTON32 = (0x100+32); // joystick button 32
-
-const int VK_WHEELUP = (0x200+1); // Mousewheel up
-const int VK_WHEELDOWN = (0x200+2); // Mousewheel down
+/**
+ \enum KeyRank
+ \brief Slots for key assignment of user controls
+ */
+// TODO: move to global.h ?
enum KeyRank
{
@@ -609,25 +731,37 @@ enum KeyRank
};
+/**
+ \class CEventQueue
+ \brief Global event queue
-class CEvent
+ Provides an interface to a global FIFO queue with events (both system- and user-generated).
+ The queue has a fixed maximum size but it should not be a problem.
+ */
+class CEventQueue
{
public:
- CEvent(CInstanceManager* iMan);
- ~CEvent();
+ //! Constant maximum size of queue
+ static const int MAX_EVENT_QUEUE = 100;
+public:
+ //! Object's constructor
+ CEventQueue(CInstanceManager* iMan);
+ //! Object's destructor
+ ~CEventQueue();
+
+ //! Empties the FIFO of events
void Flush();
- void MakeEvent(Event &event, EventMsg msg);
+ //! Adds an event to the queue
bool AddEvent(const Event &event);
bool GetEvent(Event &event);
protected:
CInstanceManager* m_iMan;
-
- Event m_fifo[MAXEVENT];
- int m_head;
- int m_tail;
- int m_total;
+ Event m_fifo[MAX_EVENT_QUEUE];
+ int m_head;
+ int m_tail;
+ int m_total;
};
diff --git a/src/common/image.cpp b/src/common/image.cpp
new file mode 100644
index 0000000..3d64377
--- /dev/null
+++ b/src/common/image.cpp
@@ -0,0 +1,221 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// image.cpp
+
+#include "image.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <png.h>
+
+
+/* <---------------------------------------------------------------> */
+
+/* The following code is from savesurf program by Angelo "Encelo" Theodorou
+ Source: http://encelo.netsons.org/old/sdl/
+ The code was refactored and modified slightly to fit the needs.
+ The copyright information below is kept unchanged. */
+
+
+/* SaveSurf: an example on how to save a SDLSurface in PNG
+ Copyright (C) 2006 Angelo "Encelo" Theodorou
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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
+
+ NOTE:
+
+ This program is part of "Mars, Land of No Mercy" SDL examples,
+ you can find other examples on http://marsnomercy.org
+*/
+
+std::string PNG_ERROR = "";
+
+void PNGUserError(png_structp ctx, png_const_charp str)
+{
+ PNG_ERROR = std::string(str);
+}
+
+int PNGColortypeFromSurface(SDL_Surface *surface)
+{
+ int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
+
+ if (surface->format->palette)
+ colortype |= PNG_COLOR_MASK_PALETTE;
+ else if (surface->format->Amask)
+ colortype |= PNG_COLOR_MASK_ALPHA;
+
+ return colortype;
+}
+
+bool PNGSaveSurface(const char *filename, SDL_Surface *surf)
+{
+ FILE *fp;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ int i, colortype;
+ png_bytep *row_pointers;
+
+ PNG_ERROR = "";
+
+ /* Opening output file */
+ fp = fopen(filename, "wb");
+ if (fp == NULL)
+ {
+ PNG_ERROR = std::string("Could not open file '") + std::string(filename) + std::string("' for saving");
+ return false;
+ }
+
+ /* Initializing png structures and callbacks */
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, PNGUserError, NULL);
+ if (png_ptr == NULL)
+ return false;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL)
+ {
+ png_destroy_write_struct(&png_ptr, static_cast<png_infopp>(NULL));
+ PNG_ERROR = "png_create_info_struct() error!";
+ return false;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return false;
+ }
+
+ png_init_io(png_ptr, fp);
+
+ colortype = PNGColortypeFromSurface(surf);
+ png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ /* Writing the image */
+ png_write_info(png_ptr, info_ptr);
+ png_set_packing(png_ptr);
+
+ row_pointers = static_cast<png_bytep*>( malloc(sizeof(png_bytep)*surf->h) );
+ for (i = 0; i < surf->h; i++)
+ row_pointers[i] = static_cast<png_bytep>( static_cast<Uint8 *>(surf->pixels) ) + i*surf->pitch;
+ png_write_image(png_ptr, row_pointers);
+ png_write_end(png_ptr, info_ptr);
+
+ /* Cleaning out... */
+ free(row_pointers);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+
+ return true;
+}
+
+/* <---------------------------------------------------------------> */
+
+
+CImage::CImage()
+{
+ m_data = NULL;
+}
+
+CImage::~CImage()
+{
+ Free();
+}
+
+bool CImage::IsEmpty()
+{
+ return m_data == NULL;
+}
+
+void CImage::Free()
+{
+ if (m_data != NULL)
+ {
+ if (m_data->surface != NULL)
+ {
+ SDL_FreeSurface(m_data->surface);
+ m_data->surface = NULL;
+ }
+ delete m_data;
+ m_data = NULL;
+ }
+}
+
+ImageData* CImage::GetData()
+{
+ return m_data;
+}
+
+std::string CImage::GetError()
+{
+ return m_error;
+}
+
+bool CImage::Load(const std::string& fileName)
+{
+ if (! IsEmpty() )
+ Free();
+
+ m_data = new ImageData();
+
+ m_error = "";
+
+ m_data->surface = IMG_Load(fileName.c_str());
+ if (m_data->surface == NULL)
+ {
+ delete m_data;
+ m_data = NULL;
+
+ m_error = std::string(IMG_GetError());
+ return false;
+ }
+
+ return true;
+}
+
+bool CImage::SavePNG(const std::string& fileName)
+{
+ if (IsEmpty())
+ {
+ m_error = "Empty image!";
+ return false;
+ }
+
+ m_error = "";
+
+ if (! PNGSaveSurface(fileName.c_str(), m_data->surface) )
+ {
+ m_error = PNG_ERROR;
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/common/image.h b/src/common/image.h
new file mode 100644
index 0000000..4d86d31
--- /dev/null
+++ b/src/common/image.h
@@ -0,0 +1,84 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// image.h
+
+#pragma once
+
+
+#include <stddef.h>
+#include <string>
+
+
+// Forward declaration without including headers to clutter the code
+struct SDL_Surface;
+
+//! Implementation-specific image data
+/** Note that the struct has no destructor and the surface
+ will not be freed at destruction. */
+struct ImageData
+{
+ //! SDL surface with image data
+ SDL_Surface* surface;
+
+ ImageData() { surface = NULL; }
+};
+
+/**
+ \class CImage
+ \brief Image loaded from file
+
+ Wrapper around SDL_Image library to load images. Also contains
+ function for saving images to PNG.
+ */
+class CImage
+{
+private:
+ //! Blocked!
+ CImage(const CImage &other) {}
+ //! Blocked!
+ void operator=(const CImage &other) {}
+
+public:
+ //! Constructs empty image (with NULL data)
+ CImage();
+ //! Destroys image, calling Free()
+ virtual ~CImage();
+
+ //! Frees the allocated image data
+ void Free();
+
+ //! Returns whether the image is empty (has NULL data)
+ bool IsEmpty();
+
+ //! Returns the image data; if empty - returns NULL
+ ImageData* GetData();
+
+ //! Loads an image from the specified file
+ bool Load(const std::string &fileName);
+
+ //! Saves the image to the specified file in PNG format
+ bool SavePNG(const std::string &fileName);
+
+ //! Returns the last error
+ std::string GetError();
+
+private:
+ //! Last encountered error
+ std::string m_error;
+ //! Image data
+ ImageData* m_data;
+};
diff --git a/src/common/iman.cpp b/src/common/iman.cpp
index 9e94f24..4c70cde 100644
--- a/src/common/iman.cpp
+++ b/src/common/iman.cpp
@@ -108,7 +108,7 @@ bool CInstanceManager::AddInstance(ClassType classType, void* pointer, int max)
if ( m_table[classType].classPointer == 0 )
{
- m_table[classType].classPointer = (void**)malloc(max*sizeof(void*));
+ m_table[classType].classPointer = static_cast<void**>( malloc(max*sizeof(void*)) );
m_table[classType].totalPossible = max;
m_table[classType].totalUsed = 0;
}
diff --git a/src/common/ioutils.h b/src/common/ioutils.h
new file mode 100644
index 0000000..a7bd044
--- /dev/null
+++ b/src/common/ioutils.h
@@ -0,0 +1,85 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// ioutils.h
+
+#pragma once
+
+
+#include <iostream>
+
+#include <cstring>
+
+namespace IOUtils {
+
+//! Writes a binary number to output stream
+/**
+ \c T is a numeric type (int, unsigned int, etc.)
+ \c N is number of bytes
+ Write order is little-endian */
+template<int N, typename T>
+void WriteBinary(T value, std::ostream &ostr)
+{
+ for (int i = 0; i < N; ++i)
+ {
+ unsigned char byte = (value >> (i*8)) & 0xFF;
+ ostr.write(reinterpret_cast<char*>(&byte), 1);
+ }
+}
+
+//! Reads a binary number from input stream
+/**
+ \c T is a numeric type (int, unsigned int, etc.)
+ \c N is number of bytes
+ Read order is little-endian */
+template<int N, typename T>
+T ReadBinary(std::istream &istr)
+{
+ T value = 0;
+ for (int i = 0; i < N; ++i)
+ {
+ unsigned char byte = 0;
+ istr.read(reinterpret_cast<char*>(&byte), 1);
+ value |= byte << (i*8);
+ }
+ return value;
+}
+
+//! Writes a binary 32-bit float to output stream
+/**
+ Write order is little-endian
+ NOTE: code is probably not portable as there are platforms with other float representations. */
+void WriteBinaryFloat(float value, std::ostream &ostr)
+{
+ union { float fValue; unsigned int iValue; } u;
+ memset(&u, 0, sizeof(u));
+ u.fValue = value;
+ IOUtils::WriteBinary<4, unsigned int>(u.iValue, ostr);
+}
+
+//! Reads a binary 32-bit float from input stream
+/**
+ Read order is little-endian
+ NOTE: code is probably not portable as there are platforms with other float representations. */
+float ReadBinaryFloat(std::istream &istr)
+{
+ union { float fValue; unsigned int iValue; } u;
+ memset(&u, 0, sizeof(u));
+ u.iValue = IOUtils::ReadBinary<4, unsigned int>(istr);
+ return u.fValue;
+}
+
+}; // namespace IOUtils
diff --git a/src/graphics/common/device.h b/src/common/key.h
index 5900570..de31c09 100644
--- a/src/graphics/common/device.h
+++ b/src/common/key.h
@@ -1,5 +1,4 @@
// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
// *
// * This program is free software: you can redistribute it and/or modify
@@ -15,38 +14,21 @@
// * You should have received a copy of the GNU General Public License
// * along with this program. If not, see http://www.gnu.org/licenses/.
-// device.h
+// key.h
#pragma once
-namespace Gfx {
+#include "SDL/SDL_keysym.h"
-struct DeviceConfig
-{
- //! Screen width
- int width;
- //! Screen height
- int height;
- //! Bits per pixel
- int bpp;
- //! Full screen
- bool fullScreen;
- //! Resizeable window
- bool resizeable;
- //! Hardware acceleration
- bool hardwareAccel;
- //! Double buffering
- bool doubleBuf;
- //! No window frame (also set with full screen)
- bool noFrame;
+/* Key definitions are specially defined here so that it is clear in other parts of the code
+ that these are used. It is to avoid having SDL-related enum values or #defines lying around
+ unchecked. With this approach it will be easier to maintain the code later on. */
- DeviceConfig();
-};
+// Key symbol defined as concatenation to SDLK_...
+// If need arises, it can be changed to custom function or anything else
+#define KEY(x) SDLK_ ## x
-class CDevice
-{
- // TODO
-};
-
-}; // namespace Gfx
+// Key modifier defined as concatenation to KMOD_...
+// If need arises, it can be changed to custom function or anything else
+#define KEY_MOD(x) KMOD_ ## x
diff --git a/src/common/logger.cpp b/src/common/logger.cpp
index acd1d27..f24726e 100644
--- a/src/common/logger.cpp
+++ b/src/common/logger.cpp
@@ -18,6 +18,8 @@
#include <common/logger.h>
+#include <stdio.h>
+
template<> CLogger* CSingleton<CLogger>::mInstance = 0;
@@ -53,7 +55,7 @@ void CLogger::Log(LogType type, const char *str, va_list args)
{
if (type < mLogLevel)
return;
-
+
switch (type) {
case LOG_WARN: fprintf(IsOpened() ? mFile : stderr, "[WARN]: "); break;
case LOG_INFO: fprintf(IsOpened() ? mFile : stderr, "[INFO]: "); break;
diff --git a/src/common/logger.h b/src/common/logger.h
index 3a48210..2d0ab3e 100644
--- a/src/common/logger.h
+++ b/src/common/logger.h
@@ -50,7 +50,7 @@ enum LogType
*
* @brief Class for loggin information to file or console
*
-*/
+*/
class CLogger : public CSingleton<CLogger>
{
public:
diff --git a/src/common/misc.h b/src/common/misc.h
index e863b69..4853856 100644
--- a/src/common/misc.h
+++ b/src/common/misc.h
@@ -219,7 +219,7 @@ const int KS_NUMMINUS = (1<<15);
// Procedures.
-extern EventMsg GetUniqueEventMsg();
+extern EventType GetUniqueEventType();
extern char RetNoAccent(char letter);
extern char RetToUpper(char letter);
diff --git a/src/common/modfile.cpp b/src/common/modfile.cpp
deleted file mode 100644
index fc202b7..0000000
--- a/src/common/modfile.cpp
+++ /dev/null
@@ -1,695 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// modfile.cpp
-
-
-#include <windows.h>
-#include <stdio.h>
-#include <d3d.h>
-
-#include "common/struct.h"
-#include "math/geometry.h"
-#include "old/d3dengine.h"
-#include "old/d3dmath.h"
-#include "common/language.h"
-#include "common/event.h"
-#include "common/misc.h"
-#include "common/iman.h"
-#include "old/math3d.h"
-#include "common/modfile.h"
-
-
-
-const int MAX_VERTICES = 2000;
-
-
-
-// Object's constructor.
-
-CModFile::CModFile(CInstanceManager* iMan)
-{
- m_iMan = iMan;
-
- m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
-
- m_triangleUsed = 0;
- m_triangleTable = (ModelTriangle*)malloc(sizeof(ModelTriangle)*MAX_VERTICES);
- ZeroMemory(m_triangleTable, sizeof(ModelTriangle)*MAX_VERTICES);
-}
-
-// Object's destructor.
-
-CModFile::~CModFile()
-{
- free(m_triangleTable);
-}
-
-
-
-
-// Creates a triangle in the internal structure.
-
-bool CModFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3,
- float min, float max)
-{
- Math::Vector n;
- int i;
-
- if ( m_triangleUsed >= MAX_VERTICES )
- {
- OutputDebugString("ERROR: CreateTriangle::Too many triangles\n");
- return false;
- }
-
- i = m_triangleUsed++;
-
- ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle));
-
- m_triangleTable[i].bUsed = true;
- m_triangleTable[i].bSelect = false;
-
- n = Math::NormalToPlane(p3, p2, p1);
- m_triangleTable[i].p1 = D3DVERTEX2( p1, n);
- m_triangleTable[i].p2 = D3DVERTEX2( p2, n);
- m_triangleTable[i].p3 = D3DVERTEX2( p3, n);
-
- m_triangleTable[i].material.diffuse.r = 1.0f;
- m_triangleTable[i].material.diffuse.g = 1.0f;
- m_triangleTable[i].material.diffuse.b = 1.0f; // white
- m_triangleTable[i].material.ambient.r = 0.5f;
- m_triangleTable[i].material.ambient.g = 0.5f;
- m_triangleTable[i].material.ambient.b = 0.5f;
-
- m_triangleTable[i].min = min;
- m_triangleTable[i].max = max;
-
- return true;
-}
-
-// Reads a DXF file.
-
-bool CModFile::ReadDXF(char *filename, float min, float max)
-{
- FILE* file = NULL;
- char line[100];
- int command, rankSommet, nbSommet, nbFace;
- Math::Vector table[MAX_VERTICES];
- bool bWaitNbSommet;
- bool bWaitNbFace;
- bool bWaitSommetX;
- bool bWaitSommetY;
- bool bWaitSommetZ;
- bool bWaitFaceX;
- bool bWaitFaceY;
- bool bWaitFaceZ;
- float x,y,z;
- int p1,p2,p3;
-
- file = fopen(filename, "r");
- if ( file == NULL ) return false;
-
- m_triangleUsed = 0;
-
- rankSommet = 0;
- bWaitNbSommet = false;
- bWaitNbFace = false;
- bWaitSommetX = false;
- bWaitSommetY = false;
- bWaitSommetZ = false;
- bWaitFaceX = false;
- bWaitFaceY = false;
- bWaitFaceZ = false;
-
- while ( fgets(line, 100, file) != NULL )
- {
- sscanf(line, "%d", &command);
- if ( fgets(line, 100, file) == NULL ) break;
-
- if ( command == 66 )
- {
- bWaitNbSommet = true;
- }
-
- if ( command == 71 && bWaitNbSommet )
- {
- bWaitNbSommet = false;
- sscanf(line, "%d", &nbSommet);
- if ( nbSommet > MAX_VERTICES ) nbSommet = MAX_VERTICES;
- rankSommet = 0;
- bWaitNbFace = true;
-
-//? sprintf(s, "Waiting for %d sommets\n", nbSommet);
-//? OutputDebugString(s);
- }
-
- if ( command == 72 && bWaitNbFace )
- {
- bWaitNbFace = false;
- sscanf(line, "%d", &nbFace);
- bWaitSommetX = true;
-
-//? sprintf(s, "Waiting for %d faces\n", nbFace);
-//? OutputDebugString(s);
- }
-
- if ( command == 10 && bWaitSommetX )
- {
- bWaitSommetX = false;
- sscanf(line, "%f", &x);
- bWaitSommetY = true;
- }
-
- if ( command == 20 && bWaitSommetY )
- {
- bWaitSommetY = false;
- sscanf(line, "%f", &y);
- bWaitSommetZ = true;
- }
-
- if ( command == 30 && bWaitSommetZ )
- {
- bWaitSommetZ = false;
- sscanf(line, "%f", &z);
-
- nbSommet --;
- if ( nbSommet >= 0 )
- {
- Math::Vector p(x,z,y); // permutation of Y and Z!
- table[rankSommet++] = p;
- bWaitSommetX = true;
-
-//? sprintf(s, "Sommet[%d]=%f;%f;%f\n", rankSommet, p.x,p.y,p.z);
-//? OutputDebugString(s);
- }
- else
- {
- bWaitFaceX = true;
- }
- }
-
- if ( command == 71 && bWaitFaceX )
- {
- bWaitFaceX = false;
- sscanf(line, "%d", &p1);
- if ( p1 < 0 ) p1 = -p1;
- bWaitFaceY = true;
- }
-
- if ( command == 72 && bWaitFaceY )
- {
- bWaitFaceY = false;
- sscanf(line, "%d", &p2);
- if ( p2 < 0 ) p2 = -p2;
- bWaitFaceZ = true;
- }
-
- if ( command == 73 && bWaitFaceZ )
- {
- bWaitFaceZ = false;
- sscanf(line, "%d", &p3);
- if ( p3 < 0 ) p3 = -p3;
-
- nbFace --;
- if ( nbFace >= 0 )
- {
- CreateTriangle( table[p3-1], table[p2-1], table[p1-1], min,max );
- bWaitFaceX = true;
-
-//? sprintf(s, "Face=%d;%d;%d\n", p1,p2,p3);
-//? OutputDebugString(s);
- }
- }
-
- }
-
- fclose(file);
- return true;
-}
-
-
-
-struct InfoMOD
-{
- int rev;
- int vers;
- int total;
- int reserve[10];
-};
-
-
-// Change nom.bmp to nom.tga
-
-void ChangeBMPtoTGA(char *filename)
-{
- char* p;
-
- p = strstr(filename, ".bmp");
- if ( p != 0 ) strcpy(p, ".tga");
-}
-
-
-// Reads a MOD file.
-
-bool CModFile::AddModel(char *filename, int first, bool bEdit, bool bMeta)
-{
- FILE* file;
- InfoMOD info;
- float limit[2];
- int i, nb, err;
- char* p;
-
- if ( m_engine->RetDebugMode() )
- {
- bMeta = false;
- }
-
- if ( bMeta )
- {
- p = strchr(filename, '\\');
- if ( p == 0 )
- {
-#if _SCHOOL
- err = g_metafile.Open("ceebot2.dat", filename);
-#else
- err = g_metafile.Open("colobot2.dat", filename);
-#endif
- }
- else
- {
-#if _SCHOOL
- err = g_metafile.Open("ceebot2.dat", p+1);
-#else
- err = g_metafile.Open("colobot2.dat", p+1);
-#endif
- }
- if ( err != 0 ) bMeta = false;
- }
- if ( !bMeta )
- {
- file = fopen(filename, "rb");
- if ( file == NULL ) return false;
- }
-
- if ( bMeta )
- {
- g_metafile.Read(&info, sizeof(InfoMOD));
- }
- else
- {
- fread(&info, sizeof(InfoMOD), 1, file);
- }
- nb = info.total;
- m_triangleUsed += nb;
-
- if ( info.rev == 1 && info.vers == 0 )
- {
- OldModelTriangle1 old;
-
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- if ( bMeta )
- {
- g_metafile.Read(&old, sizeof(OldModelTriangle1));
- }
- else
- {
- fread(&old, sizeof(OldModelTriangle1), 1, file);
- }
-
- ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle));
- m_triangleTable[i].bUsed = old.bUsed;
- m_triangleTable[i].bSelect = old.bSelect;
-
- m_triangleTable[i].p1.x = old.p1.x;
- m_triangleTable[i].p1.y = old.p1.y;
- m_triangleTable[i].p1.z = old.p1.z;
- m_triangleTable[i].p1.nx = old.p1.nx;
- m_triangleTable[i].p1.ny = old.p1.ny;
- m_triangleTable[i].p1.nz = old.p1.nz;
- m_triangleTable[i].p1.tu = old.p1.tu;
- m_triangleTable[i].p1.tv = old.p1.tv;
-
- m_triangleTable[i].p2.x = old.p2.x;
- m_triangleTable[i].p2.y = old.p2.y;
- m_triangleTable[i].p2.z = old.p2.z;
- m_triangleTable[i].p2.nx = old.p2.nx;
- m_triangleTable[i].p2.ny = old.p2.ny;
- m_triangleTable[i].p2.nz = old.p2.nz;
- m_triangleTable[i].p2.tu = old.p2.tu;
- m_triangleTable[i].p2.tv = old.p2.tv;
-
- m_triangleTable[i].p3.x = old.p3.x;
- m_triangleTable[i].p3.y = old.p3.y;
- m_triangleTable[i].p3.z = old.p3.z;
- m_triangleTable[i].p3.nx = old.p3.nx;
- m_triangleTable[i].p3.ny = old.p3.ny;
- m_triangleTable[i].p3.nz = old.p3.nz;
- m_triangleTable[i].p3.tu = old.p3.tu;
- m_triangleTable[i].p3.tv = old.p3.tv;
-
- m_triangleTable[i].material = old.material;
- strcpy(m_triangleTable[i].texName, old.texName);
- m_triangleTable[i].min = old.min;
- m_triangleTable[i].max = old.max;
- }
- }
- else if ( info.rev == 1 && info.vers == 1 )
- {
- OldModelTriangle2 old;
-
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- if ( bMeta )
- {
- g_metafile.Read(&old, sizeof(OldModelTriangle2));
- }
- else
- {
- fread(&old, sizeof(OldModelTriangle2), 1, file);
- }
-
- ZeroMemory(&m_triangleTable[i], sizeof(ModelTriangle));
- m_triangleTable[i].bUsed = old.bUsed;
- m_triangleTable[i].bSelect = old.bSelect;
-
- m_triangleTable[i].p1.x = old.p1.x;
- m_triangleTable[i].p1.y = old.p1.y;
- m_triangleTable[i].p1.z = old.p1.z;
- m_triangleTable[i].p1.nx = old.p1.nx;
- m_triangleTable[i].p1.ny = old.p1.ny;
- m_triangleTable[i].p1.nz = old.p1.nz;
- m_triangleTable[i].p1.tu = old.p1.tu;
- m_triangleTable[i].p1.tv = old.p1.tv;
-
- m_triangleTable[i].p2.x = old.p2.x;
- m_triangleTable[i].p2.y = old.p2.y;
- m_triangleTable[i].p2.z = old.p2.z;
- m_triangleTable[i].p2.nx = old.p2.nx;
- m_triangleTable[i].p2.ny = old.p2.ny;
- m_triangleTable[i].p2.nz = old.p2.nz;
- m_triangleTable[i].p2.tu = old.p2.tu;
- m_triangleTable[i].p2.tv = old.p2.tv;
-
- m_triangleTable[i].p3.x = old.p3.x;
- m_triangleTable[i].p3.y = old.p3.y;
- m_triangleTable[i].p3.z = old.p3.z;
- m_triangleTable[i].p3.nx = old.p3.nx;
- m_triangleTable[i].p3.ny = old.p3.ny;
- m_triangleTable[i].p3.nz = old.p3.nz;
- m_triangleTable[i].p3.tu = old.p3.tu;
- m_triangleTable[i].p3.tv = old.p3.tv;
-
- m_triangleTable[i].material = old.material;
- strcpy(m_triangleTable[i].texName, old.texName);
- m_triangleTable[i].min = old.min;
- m_triangleTable[i].max = old.max;
- m_triangleTable[i].state = old.state;
- m_triangleTable[i].reserve2 = old.reserve2;
- m_triangleTable[i].reserve3 = old.reserve3;
- m_triangleTable[i].reserve4 = old.reserve4;
- }
- }
- else
- {
- if ( bMeta )
- {
- g_metafile.Read(m_triangleTable+first, sizeof(ModelTriangle)*nb);
- }
- else
- {
- fread(m_triangleTable+first, sizeof(ModelTriangle), nb, file);
- }
- }
-
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- ChangeBMPtoTGA(m_triangleTable[i].texName);
- }
-
- if ( !bEdit )
- {
- limit[0] = m_engine->RetLimitLOD(0); // frontier AB as config
- limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config
-
- // Standard frontiers -> config.
- for ( i=first ; i<m_triangleUsed ; i++ )
- {
- if ( m_triangleTable[i].min == 0.0f &&
- m_triangleTable[i].max == 100.0f ) // resolution A ?
- {
- m_triangleTable[i].max = limit[0];
- }
- else if ( m_triangleTable[i].min == 100.0f &&
- m_triangleTable[i].max == 200.0f ) // resolution B ?
- {
- m_triangleTable[i].min = limit[0];
- m_triangleTable[i].max = limit[1];
- }
- else if ( m_triangleTable[i].min == 200.0f &&
- m_triangleTable[i].max == 1000000.0f ) // resolution C ?
- {
- m_triangleTable[i].min = limit[1];
- }
- }
- }
-
- if ( bMeta )
- {
- g_metafile.Close();
- }
- else
- {
- fclose(file);
- }
- return true;
-}
-
-// Reads a MOD file.
-
-bool CModFile::ReadModel(char *filename, bool bEdit, bool bMeta)
-{
- m_triangleUsed = 0;
- return AddModel(filename, 0, bEdit, bMeta);
-}
-
-
-// Writes a MOD file.
-
-bool CModFile::WriteModel(char *filename)
-{
- FILE* file;
- InfoMOD info;
-
- if ( m_triangleUsed == 0 ) return false;
-
- file = fopen(filename, "wb");
- if ( file == NULL ) return false;
-
- ZeroMemory(&info, sizeof(InfoMOD));
- info.rev = 1;
- info.vers = 2;
- info.total = m_triangleUsed;
- fwrite(&info, sizeof(InfoMOD), 1, file);
-
- fwrite(m_triangleTable, sizeof(ModelTriangle), m_triangleUsed, file);
-
- fclose(file);
- return true;
-}
-
-
-// Creates the object in the 3D engine.
-
-bool CModFile::CreateEngineObject(int objRank, int addState)
-{
-#if 0
- char texName2[20];
- int texNum, i, state;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- if ( !m_triangleTable[i].bUsed ) continue;
-
- state = m_triangleTable[i].state;
- texName2[0] = 0;
-
- if ( m_triangleTable[i].texNum2 != 0 )
- {
- if ( m_triangleTable[i].texNum2 == 1 )
- {
- texNum = m_engine->RetSecondTexture();
- }
- else
- {
- texNum = m_triangleTable[i].texNum2;
- }
-
- if ( texNum >= 1 && texNum <= 10 )
- {
- state = m_triangleTable[i].state|D3DSTATEDUALb;
- }
- if ( texNum >= 11 && texNum <= 20 )
- {
- state = m_triangleTable[i].state|D3DSTATEDUALw;
- }
- sprintf(texName2, "dirty%.2d.bmp", texNum);
- }
-
- m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3,
- m_triangleTable[i].material,
- state+addState,
- m_triangleTable[i].texName, texName2,
- m_triangleTable[i].min,
- m_triangleTable[i].max, false);
- }
- return true;
-#else
- char texName1[20];
- char texName2[20];
- int texNum, i, state;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- if ( !m_triangleTable[i].bUsed ) continue;
-
- state = m_triangleTable[i].state;
- strcpy(texName1, m_triangleTable[i].texName);
- texName2[0] = 0;
-
- if ( strcmp(texName1, "plant.tga") == 0 )
- {
- state |= D3DSTATEALPHA;
- }
-
- if ( m_triangleTable[i].texNum2 != 0 )
- {
- if ( m_triangleTable[i].texNum2 == 1 )
- {
- texNum = m_engine->RetSecondTexture();
- }
- else
- {
- texNum = m_triangleTable[i].texNum2;
- }
-
- if ( texNum >= 1 && texNum <= 10 )
- {
- state |= D3DSTATEDUALb;
- }
- if ( texNum >= 11 && texNum <= 20 )
- {
- state |= D3DSTATEDUALw;
- }
- sprintf(texName2, "dirty%.2d.tga", texNum);
- }
-
- m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3,
- m_triangleTable[i].material,
- state+addState,
- texName1, texName2,
- m_triangleTable[i].min,
- m_triangleTable[i].max, false);
- }
- return true;
-#endif
-}
-
-
-// Performs a mirror according to Z.
-
-void CModFile::Mirror()
-{
- D3DVERTEX2 t;
- int i;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- t = m_triangleTable[i].p1;
- m_triangleTable[i].p1 = m_triangleTable[i].p2;
- m_triangleTable[i].p2 = t;
-
- m_triangleTable[i].p1.z = -m_triangleTable[i].p1.z;
- m_triangleTable[i].p2.z = -m_triangleTable[i].p2.z;
- m_triangleTable[i].p3.z = -m_triangleTable[i].p3.z;
-
- m_triangleTable[i].p1.nz = -m_triangleTable[i].p1.nz;
- m_triangleTable[i].p2.nz = -m_triangleTable[i].p2.nz;
- m_triangleTable[i].p3.nz = -m_triangleTable[i].p3.nz;
- }
-}
-
-
-// Returns the pointer to the list of triangles.
-
-void CModFile::SetTriangleUsed(int total)
-{
- m_triangleUsed = total;
-}
-
-int CModFile::RetTriangleUsed()
-{
- return m_triangleUsed;
-}
-
-int CModFile::RetTriangleMax()
-{
- return MAX_VERTICES;
-}
-
-ModelTriangle* CModFile::RetTriangleList()
-{
- return m_triangleTable;
-}
-
-
-// Returns the height according to a position (x - z);
-
-float CModFile::RetHeight(Math::Vector pos)
-{
- Math::Vector p1, p2, p3;
- float limit;
- int i;
-
- limit = 5.0f;
-
- for ( i=0 ; i<m_triangleUsed ; i++ )
- {
- if ( !m_triangleTable[i].bUsed ) continue;
-
- if ( fabs(pos.x-m_triangleTable[i].p1.x) < limit &&
- fabs(pos.z-m_triangleTable[i].p1.z) < limit )
- {
- return m_triangleTable[i].p1.y;
- }
-
- if ( fabs(pos.x-m_triangleTable[i].p2.x) < limit &&
- fabs(pos.z-m_triangleTable[i].p2.z) < limit )
- {
- return m_triangleTable[i].p2.y;
- }
-
- if ( fabs(pos.x-m_triangleTable[i].p3.x) < limit &&
- fabs(pos.z-m_triangleTable[i].p3.z) < limit )
- {
- return m_triangleTable[i].p3.y;
- }
- }
-
- return 0.0f;
-}
-
-
diff --git a/src/common/modfile.h b/src/common/modfile.h
deleted file mode 100644
index c852c1e..0000000
--- a/src/common/modfile.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// modfile.h
-
-#pragma once
-
-
-#include "math/vector.h"
-#include "old/d3dengine.h"
-
-
-class CInstanceManager;
-
-
-
-
-struct OldModelTriangle1
-{
- char bUsed; // true -> using
- char bSelect; // true -> selected
- D3DVERTEX p1;
- D3DVERTEX p2;
- D3DVERTEX p3;
- D3DMATERIAL7 material;
- char texName[20];
- float min;
- float max;
-}; // length = 196 bytes
-
-struct OldModelTriangle2
-{
- char bUsed; // true -> used
- char bSelect; // true -> selected
- D3DVERTEX p1;
- D3DVERTEX p2;
- D3DVERTEX p3;
- D3DMATERIAL7 material;
- char texName[20];
- float min;
- float max;
- long state;
- short reserve1;
- short reserve2;
- short reserve3;
- short reserve4;
-};
-
-struct ModelTriangle
-{
- char bUsed; // true -> used
- char bSelect; // true -> selected
- D3DVERTEX2 p1;
- D3DVERTEX2 p2;
- D3DVERTEX2 p3;
- D3DMATERIAL7 material;
- char texName[20];
- float min;
- float max;
- long state;
- short texNum2;
- short reserve2;
- short reserve3;
- short reserve4;
-}; // length = 208 bytes
-
-
-
-
-class CModFile
-{
-public:
- CModFile(CInstanceManager* iMan);
- ~CModFile();
-
- bool ReadDXF(char *filename, float min, float max);
- bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true);
- bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true);
- bool WriteModel(char *filename);
-
- bool CreateEngineObject(int objRank, int addState=0);
- void Mirror();
-
- void SetTriangleUsed(int total);
- int RetTriangleUsed();
- int RetTriangleMax();
- ModelTriangle* RetTriangleList();
-
- float RetHeight(Math::Vector pos);
-
-protected:
- bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
-
-protected:
- CInstanceManager* m_iMan;
- CD3DEngine* m_engine;
-
- ModelTriangle* m_triangleTable;
- int m_triangleUsed;
-};
-
-
diff --git a/src/common/singleton.h b/src/common/singleton.h
index dc09645..4df7878 100644
--- a/src/common/singleton.h
+++ b/src/common/singleton.h
@@ -29,25 +29,25 @@ template<typename T> class CSingleton
public:
static T& GetInstance() {
- aserrt(mInstance);
+ assert(mInstance != NULL);
return *mInstance;
}
- static T& GetInstancePointer() {
- aserrt(mInstance);
+ static T* GetInstancePointer() {
+ assert(mInstance != NULL);
return mInstance;
}
static bool IsCreated() {
- return mInstance != NULL;
+ return mInstance != NULL;
}
CSingleton() {
- assert(!mInstance);
+ assert(mInstance == NULL);
mInstance = static_cast<T *>(this);
}
- ~CSingleton() {
+ virtual ~CSingleton() {
mInstance = NULL;
}
diff --git a/src/common/stringutils.cpp b/src/common/stringutils.cpp
new file mode 100644
index 0000000..585bb46
--- /dev/null
+++ b/src/common/stringutils.cpp
@@ -0,0 +1,149 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// stringutils.cpp
+
+#include "stringutils.h"
+
+
+std::string StrUtils::Replace(const std::string &str, const std::string &oldStr, const std::string &newStr)
+{
+ std::string result = str;
+ size_t pos = 0;
+ while ((pos = str.find(oldStr, pos)) != std::string::npos)
+ {
+ result.replace(pos, oldStr.length(), newStr);
+ pos += newStr.length();
+ }
+ return result;
+}
+
+std::string StrUtils::UnicodeCharToUtf8(unsigned int ch)
+{
+ std::string result;
+ if (ch < 0x0080)
+ {
+ result += static_cast<char>(ch);
+ }
+ else if (ch < 0x0800)
+ {
+ char ch1 = 0xC0 | ((ch & 0x07C0) >> 6);
+ char ch2 = 0x80 | (ch & 0x3F);
+ result += ch1;
+ result += ch2;
+ }
+ else
+ {
+ char ch1 = 0xE0 | ((ch & 0xF000) >> 12);
+ char ch2 = 0x80 | ((ch & 0x07C0) >> 6);
+ char ch3 = 0x80 | (ch & 0x3F);
+ result += ch1;
+ result += ch2;
+ result += ch3;
+ }
+ return result;
+}
+
+std::string StrUtils::UnicodeStringToUtf8(const std::wstring &str)
+{
+ std::string result;
+ for (unsigned int i = 0; i < str.size(); ++i)
+ result += StrUtils::UnicodeCharToUtf8(static_cast<unsigned int>(str[i]));
+
+ return result;
+}
+
+unsigned int StrUtils::Utf8CharToUnicode(const std::string &ch)
+{
+ if (ch.empty())
+ return 0;
+
+ unsigned int result = 0;
+ if ((ch[0] & 0x80) == 0)
+ {
+ if (ch.size() == 1)
+ result = static_cast<unsigned int>(ch[0]);
+ }
+ else if ((ch[0] & 0xC0) == 0xC0)
+ {
+ if (ch.size() == 2)
+ {
+ unsigned int ch1 = (ch[0] & 0x1F) << 6;
+ unsigned int ch2 = (ch[1] & 0x3F);
+ result = ch1 | ch2;
+ }
+ }
+ else
+ {
+ if (ch.size() == 3)
+ {
+ unsigned int ch1 = (ch[0] & 0xF0) << 12;
+ unsigned int ch2 = (ch[1] & 0xC0) << 6;
+ unsigned int ch3 = (ch[2] & 0xC0);
+ result = ch1 | ch2 | ch3;
+ }
+ }
+
+ return result;
+}
+
+std::wstring StrUtils::Utf8StringToUnicode(const std::string &str)
+{
+ std::wstring result;
+ unsigned int pos = 0;
+ while (pos < str.size())
+ {
+ int len = StrUtils::Utf8CharSizeAt(str, pos);
+ if (len == 0)
+ break;
+
+ std::string ch = str.substr(pos, len);
+ result += static_cast<wchar_t>(StrUtils::Utf8CharToUnicode(ch));
+ pos += len;
+ }
+ return result;
+}
+
+int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos)
+{
+ if (pos >= str.size())
+ return 0;
+
+ if ((str[pos] & 0x80) == 0)
+ return 1;
+ else if ((str[pos] & 0xC0) == 0xC0)
+ return 2;
+ else
+ return 3;
+
+ return 0;
+}
+
+size_t StrUtils::Utf8StringLength(const std::string &str)
+{
+ size_t result = 0;
+ for (unsigned int i = 0; i < str.size(); ++i)
+ {
+ char ch = str[i];
+ if ((ch & 0x80) == 0)
+ ++result;
+ else if ((ch & 0xC0) == 0xC0)
+ result += 2;
+ else
+ result += 3;
+ }
+ return result;
+}
diff --git a/src/common/stringutils.h b/src/common/stringutils.h
new file mode 100644
index 0000000..a0cae70
--- /dev/null
+++ b/src/common/stringutils.h
@@ -0,0 +1,77 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// stringutils.h
+
+#pragma once
+
+
+#include <string>
+#include <sstream>
+
+namespace StrUtils {
+
+//! Converts a value to string
+/** If given, \a ok is set to true/false on success/failure.
+ Warning: To avoid unnecessary problems, *always* give full template qualifier e.g. ToString\<int\> */
+template<class T>
+std::string ToString(T value, bool *ok = NULL)
+{
+ std::ostringstream s;
+ s << value;
+ if (ok != NULL)
+ *ok = !s.fail();
+ return s.str();
+}
+
+//! Converts a value to string
+/** If given, \a ok is set to true/false on success/failure.
+ Warning: To avoid unnecessary problems, *always* give full template qualifier e.g. FromString\<int\> */
+template<class T>
+T FromString(const std::string &str, bool *ok = NULL)
+{
+ std::istringstream s;
+ s.str(str);
+ T value;
+ s >> value;
+ if (ok != NULL)
+ *ok = !s.fail();
+ return value;
+}
+
+//! Returns a string with every occurence of \a oldStr in \a str replaced to \a newStr
+std::string Replace(const std::string &str, const std::string &oldStr, const std::string &newStr);
+
+
+//! Converts a wide Unicode char to a single UTF-8 encoded char
+std::string UnicodeCharToUtf8(unsigned int ch);
+
+//! Converts a wide Unicode string to a UTF-8 encoded string
+std::string UnicodeStringToUtf8(const std::wstring &str);
+
+//! Converts a UTF-8 encoded single character to wide Unicode char
+unsigned int Utf8CharToUnicode(const std::string &ch);
+
+//! Converts a UTF-8 encoded string to wide Unicode string
+std::wstring Utf8StringToUnicode(const std::string &str);
+
+//! Returns the size in bytes of UTF-8 character at given \a pos in a UTF-8 \a str
+int Utf8CharSizeAt(const std::string &str, unsigned int pos);
+
+//! Returns the length in characters of UTF-8 string \a str
+size_t Utf8StringLength(const std::string &str);
+
+}; // namespace StrUtil
diff --git a/src/common/test/CMakeLists.txt b/src/common/test/CMakeLists.txt
new file mode 100644
index 0000000..680116c
--- /dev/null
+++ b/src/common/test/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+add_executable(image_test ../image.cpp image_test.cpp)
diff --git a/src/common/test/image_test.cpp b/src/common/test/image_test.cpp
new file mode 100644
index 0000000..0ad1ee2
--- /dev/null
+++ b/src/common/test/image_test.cpp
@@ -0,0 +1,34 @@
+#include "../image.h"
+
+#include <SDL/SDL.h>
+#include <stdio.h>
+
+/* For now, just a simple test: loading a file from image
+ * and saving it to another in PNG. */
+
+int main(int argc, char *argv[])
+{
+ if (argc != 3)
+ {
+ printf("Usage: %s in_image out_image\n", argv[0]);
+ return 0;
+ }
+
+ CImage image;
+
+ if (! image.Load(argv[1]))
+ {
+ std::string err = image.GetError();
+ printf("Error loading '%s': %s\n", err.c_str());
+ return 1;
+ }
+
+ if (! image.SavePNG(argv[2]))
+ {
+ std::string err = image.GetError();
+ printf("Error saving PNG '%s': %s\n", err.c_str());
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/src/graphics/common/README.txt b/src/graphics/common/README.txt
deleted file mode 100644
index 495a453..0000000
--- a/src/graphics/common/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-src/graphics/common
-
-Universal structs and classes used in graphics engine
-
-Concrete implementation in OpenGL is in graphics/opengl directory.
diff --git a/src/graphics/common/camera.cpp b/src/graphics/common/camera.cpp
deleted file mode 100644
index 9990d01..0000000
--- a/src/graphics/common/camera.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// camera.cpp
-
-#include "graphics/common/camera.h"
-
-
-// TODO implementation
diff --git a/src/graphics/common/camera.h b/src/graphics/common/camera.h
deleted file mode 100644
index f17ecef..0000000
--- a/src/graphics/common/camera.h
+++ /dev/null
@@ -1,273 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// camera.h
-
-#pragma once
-
-#include "engine.h"
-#include "common/event.h"
-
-
-class CInstanceManager;
-class Gfx::CEngine;
-class Gfx::CTerrain;
-class Gfx::CWater;
-class CObject;
-
-namespace Gfx {
-
-
-enum CameraType
-{
- CAMERA_NULL = 0, // camera undefined
- CAMERA_FREE = 1, // camera free (never in principle)
- CAMERA_EDIT = 2, // camera while editing a program
- CAMERA_ONBOARD = 3, // camera on board a robot
- CAMERA_BACK = 4, // camera behind a robot
- CAMERA_FIX = 5, // static camera following robot
- CAMERA_EXPLO = 6, // camera steady after explosion
- CAMERA_SCRIPT = 7, // camera during a film script
- CAMERA_INFO = 8, // camera for displaying information
- CAMERA_VISIT = 9, // visit instead of an error
- CAMERA_DIALOG = 10, // camera for dialogue
- CAMERA_PLANE = 11, // static camera height
-};
-
-enum CameraSmooth
-{
- CS_NONE = 0, // sharp
- CS_NORM = 1, // normal
- CS_HARD = 2, // hard
- CS_SPEC = 3, // special
-};
-
-enum CenteringPhase
-{
- CP_NULL = 0,
- CP_START = 1,
- CP_WAIT = 2,
- CP_STOP = 3,
-};
-
-enum CameraEffect
-{
- CE_NULL = 0, // no effect
- CE_TERRAFORM = 1, // digging in
- CE_CRASH = 2, // Vehicle driving is severely
- CE_EXPLO = 3, // explosion
- CE_SHOT = 4, // not mortal shot
- CE_VIBRATION = 5, // vibration during construction
- CE_PET = 6, // spleen reactor
-};
-
-enum OverEffect
-{
- OE_NULL = 0, // no effect
- OE_BLOOD = 1, // flash red
- OE_FADEINw = 2, // white -> nothing
- OE_FADEOUTw = 3, // nothing -> white
- OE_FADEOUTb = 4, // nothing -> blue
- OE_BLITZ = 5, // lightning
-};
-
-
-
-class CCamera {
-
- public:
- CCamera(CInstanceManager* iMan);
- ~CCamera();
-
- bool EventProcess(const Event &event);
-
- void Init(Math::Vector eye, Math::Vector lookat, float delay);
-
- void SetObject(CObject* object);
- CObject* RetObject();
-
- void SetType(CameraType type);
- CameraType RetType();
-
- void SetSmooth(CameraSmooth type);
- CameraSmooth RetSmoth();
-
- void SetDist(float dist);
- float RetDist();
-
- void SetFixDirection(float angle);
- float RetFixDirection();
-
- void SetRemotePan(float value);
- float RetRemotePan();
-
- void SetRemoteZoom(float value);
- float RetRemoteZoom();
-
- void StartVisit(Math::Vector goal, float dist);
- void StopVisit();
-
- void RetCamera(Math::Vector &eye, Math::Vector &lookat);
-
- bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time);
- bool StopCentering(CObject *object, float time);
- void AbortCentering();
-
- void FlushEffect();
- void StartEffect(CameraEffect effect, Math::Vector pos, float force);
-
- void FlushOver();
- void SetOverBaseColor(Gfx::Color color);
- void StartOver(OverEffect effect, Math::Vector pos, float force);
-
- void FixCamera();
- void SetScriptEye(Math::Vector eye);
- void SetScriptLookat(Math::Vector lookat);
-
- void SetEffect(bool bEnable);
- void SetCameraScroll(bool bScroll);
- void SetCameraInvertX(bool bInvert);
- void SetCameraInvertY(bool bInvert);
-
- float RetMotorTurn();
- Gfx::MouseType RetMouseDef(Math::Point pos);
-
-protected:
- bool EventMouseMove(const Event &event);
- void EventMouseWheel(int dir);
- bool EventFrame(const Event &event);
- bool EventFrameFree(const Event &event);
- bool EventFrameEdit(const Event &event);
- bool EventFrameDialog(const Event &event);
- bool EventFrameBack(const Event &event);
- bool EventFrameFix(const Event &event);
- bool EventFrameExplo(const Event &event);
- bool EventFrameOnBoard(const Event &event);
- bool EventFrameInfo(const Event &event);
- bool EventFrameVisit(const Event &event);
- bool EventFrameScript(const Event &event);
-
- void SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime);
- bool IsCollision(Math::Vector &eye, Math::Vector lookat);
- bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat);
- bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat);
-
- Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV);
- Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV);
-
- void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up);
- void EffectFrame(const Event &event);
- void OverFrame(const Event &event);
-
-protected:
- CInstanceManager* m_iMan;
- Gfx::CEngine* m_engine;
- CTerrain* m_terrain;
- CWater* m_water;
-
- CameraType m_type; // the type of camera (CAMERA *)
- CameraSmooth m_smooth; // type of smoothing
- CObject* m_cameraObj; // object linked to the camera
-
- float m_eyeDistance; // distance between the eyes
- float m_initDelay; // time of initial centering
-
- Math::Vector m_actualEye; // current eye
- Math::Vector m_actualLookat; // aim current
- Math::Vector m_finalEye; // final eye
- Math::Vector m_finalLookat; // aim final
- Math::Vector m_normEye; // normal eye
- Math::Vector m_normLookat; // aim normal
- float m_focus;
-
- bool m_bRightDown;
- Math::Point m_rightPosInit;
- Math::Point m_rightPosCenter;
- Math::Point m_rightPosMove;
-
- Math::Vector m_eyePt; // CAMERA_FREE: eye
- float m_directionH; // CAMERA_FREE: horizontal direction
- float m_directionV; // CAMERA_FREE: vertical direction
- float m_heightEye; // CAMERA_FREE: height above the ground
- float m_heightLookat; // CAMERA_FREE: height above the ground
- float m_speed; // CAMERA_FREE: speed of movement
-
- float m_backDist; // CAMERA_BACK: distance
- float m_backMin; // CAMERA_BACK: distance minimal
- float m_addDirectionH; // CAMERA_BACK: additional direction
- float m_addDirectionV; // CAMERA_BACK: additional direction
- bool m_bTransparency;
-
- float m_fixDist; // CAMERA_FIX: distance
- float m_fixDirectionH; // CAMERA_FIX: direction
- float m_fixDirectionV; // CAMERA_FIX: direction
-
- Math::Vector m_visitGoal; // CAMERA_VISIT: target position
- float m_visitDist; // CAMERA_VISIT: distance
- float m_visitTime; // CAMERA_VISIT: relative time
- CameraType m_visitType; // CAMERA_VISIT: initial type
- float m_visitDirectionH; // CAMERA_VISIT: direction
- float m_visitDirectionV; // CAMERA_VISIT: direction
-
- float m_editHeight; // CAMERA_EDIT: height
-
- float m_remotePan;
- float m_remoteZoom;
-
- Math::Point m_mousePos;
- float m_mouseDirH;
- float m_mouseDirV;
- float m_mouseMarging;
-
- float m_motorTurn;
-
- CenteringPhase m_centeringPhase;
- float m_centeringAngleH;
- float m_centeringAngleV;
- float m_centeringDist;
- float m_centeringCurrentH;
- float m_centeringCurrentV;
- float m_centeringTime;
- float m_centeringProgress;
-
- CameraEffect m_effectType;
- Math::Vector m_effectPos;
- float m_effectForce;
- float m_effectProgress;
- Math::Vector m_effectOffset;
-
- OverEffect m_overType;
- float m_overForce;
- float m_overTime;
- Gfx::Color m_overColorBase;
- Gfx::Color m_overColor;
- int m_overMode;
- float m_overFadeIn;
- float m_overFadeOut;
-
- Math::Vector m_scriptEye;
- Math::Vector m_scriptLookat;
-
- bool m_bEffect; // shocks if explosion?
- bool m_bCameraScroll; // scroll in the edges?
- bool m_bCameraInvertX; // X inversion in the edges?
- bool m_bCameraInvertY; // Y inversion in the edges?
-
-};
-
-
-}; // namespace Gfx
diff --git a/src/graphics/common/color.cpp b/src/graphics/common/color.cpp
deleted file mode 100644
index dd502f9..0000000
--- a/src/graphics/common/color.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// color.cpp
-
-#include "graphics/common/color.h"
-
-#include "math/func.h"
-
-
-// Returns the color corresponding long.
-
-long Gfx::RetColor(float intensity)
-{
- long color;
-
- if ( intensity <= 0.0f ) return 0x00000000;
- if ( intensity >= 1.0f ) return 0xffffffff;
-
- color = (int)(intensity*255.0f)<<24;
- color |= (int)(intensity*255.0f)<<16;
- color |= (int)(intensity*255.0f)<<8;
- color |= (int)(intensity*255.0f);
-
- return color;
-}
-
-// Returns the color corresponding long.
-
-long Gfx::RetColor(Gfx::Color intensity)
-{
- long color;
-
- color = (int)(intensity.a*255.0f)<<24;
- color |= (int)(intensity.r*255.0f)<<16;
- color |= (int)(intensity.g*255.0f)<<8;
- color |= (int)(intensity.b*255.0f);
-
- return color;
-}
-
-// Returns the color corresponding Color.
-
-Gfx::Color Gfx::RetColor(long intensity)
-{
- Gfx::Color color;
-
- color.r = (float)((intensity>>16)&0xff)/256.0f;
- color.g = (float)((intensity>>8 )&0xff)/256.0f;
- color.b = (float)((intensity>>0 )&0xff)/256.0f;
- color.a = (float)((intensity>>24)&0xff)/256.0f;
-
- return color;
-}
-
-
-// RGB to HSV conversion.
-
-void Gfx::RGB2HSV(Gfx::Color src, Gfx::ColorHSV &dest)
-{
- float min, max, delta;
-
- min = Math::Min(src.r, src.g, src.b);
- max = Math::Max(src.r, src.g, src.b);
-
- dest.v = max; // intensity
-
- if ( max == 0.0f )
- {
- dest.s = 0.0f; // saturation
- dest.h = 0.0f; // undefined color!
- }
- else
- {
- delta = max-min;
- dest.s = delta/max; // saturation
-
- if ( src.r == max ) // between yellow & magenta
- {
- dest.h = (src.g-src.b)/delta;
- }
- else if ( src.g == max ) // between cyan & yellow
- {
- dest.h = 2.0f+(src.b-src.r)/delta;
- }
- else // between magenta & cyan
- {
- dest.h = 4.0f+(src.r-src.g)/delta;
- }
-
- dest.h *= 60.0f; // in degrees
- if ( dest.h < 0.0f ) dest.h += 360.0f;
- dest.h /= 360.0f; // 0..1
- }
-}
-
-// HSV to RGB conversion.
-
-void Gfx::HSV2RGB(Gfx::ColorHSV src, Gfx::Color &dest)
-{
- int i;
- float f,v,p,q,t;
-
- src.h = Math::Norm(src.h)*360.0f;
- src.s = Math::Norm(src.s);
- src.v = Math::Norm(src.v);
-
- if ( src.s == 0.0f ) // zero saturation?
- {
- dest.r = src.v;
- dest.g = src.v;
- dest.b = src.v; // gray
- }
- else
- {
- if ( src.h == 360.0f ) src.h = 0.0f;
- src.h /= 60.0f;
- i = (int)src.h; // integer part (0 .. 5)
- f = src.h-i; // fractional part
-
- v = src.v;
- p = src.v*(1.0f-src.s);
- q = src.v*(1.0f-(src.s*f));
- t = src.v*(1.0f-(src.s*(1.0f-f)));
-
- switch (i)
- {
- case 0: dest.r=v; dest.g=t; dest.b=p; break;
- case 1: dest.r=q; dest.g=v; dest.b=p; break;
- case 2: dest.r=p; dest.g=v; dest.b=t; break;
- case 3: dest.r=p; dest.g=q; dest.b=v; break;
- case 4: dest.r=t; dest.g=p; dest.b=v; break;
- case 5: dest.r=v; dest.g=p; dest.b=q; break;
- }
- }
-}
-
diff --git a/src/graphics/common/color.h b/src/graphics/common/color.h
deleted file mode 100644
index 12f008f..0000000
--- a/src/graphics/common/color.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// color.h
-
-#pragma once
-
-
-namespace Gfx {
-
-struct Color
-{
- float r, g, b, a;
-
- Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f)
- : r(aR), g(aG), b(aB), a(aA) {}
-};
-
-
-struct ColorHSV
-{
- float h, s, v;
-
- ColorHSV(float aH = 0.0f, float aS = 0.0f, float aV = 0.0f)
- : h(aH), s(aS), v(aV) {}
-};
-
-
-long RetColor(float intensity);
-long RetColor(Color intensity);
-Color RetColor(long intensity);
-
-void RGB2HSV(Color src, ColorHSV &dest);
-void HSV2RGB(ColorHSV src, Color &dest);
-
-}; // namespace Gfx
-
diff --git a/src/graphics/common/device.cpp b/src/graphics/common/device.cpp
deleted file mode 100644
index 53274b3..0000000
--- a/src/graphics/common/device.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "graphics/common/device.h"
-
-//! Sets the default values
-Gfx::DeviceConfig::DeviceConfig()
-{
- width = 800;
- height = 600;
- bpp = 16;
- fullScreen = false;
- resizeable = false;
- hardwareAccel = true;
- doubleBuf = true;
- noFrame = false;
-} \ No newline at end of file
diff --git a/src/graphics/common/engine.cpp b/src/graphics/common/engine.cpp
deleted file mode 100644
index 3b9a89d..0000000
--- a/src/graphics/common/engine.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// engine.cpp
-
-#include "graphics/common/engine.h"
-
-#include <GL/gl.h>
-#include <GL/glu.h>
-
-
-// TODO implementation
-
-Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
-{
- // TODO
-}
-
-Gfx::CEngine::~CEngine()
-{
- // TODO
-}
-
-int Gfx::CEngine::Render()
-{
- /* Just a hello world for now */
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- glShadeModel(GL_SMOOTH);
- glDisable(GL_DEPTH_TEST);
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
-
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- //glTranslatef(0.0f, 0.0f, -6.0f);
-
- glBegin(GL_TRIANGLES);
- {
- glColor3f(1.0f, 0.0f, 0.0f);
- glVertex2f(-2.0f, -1.0f);
- glColor3f(0.0f, 1.0f, 0.0f);
- glVertex2f(2.0f, -1.0f);
- glColor3f(0.0f, 0.0f, 1.0f);
- glVertex2f(0.0f, 1.5f);
- }
- glEnd();
-
- glFlush();
-
- return 1;
-}
diff --git a/src/graphics/common/engine.h b/src/graphics/common/engine.h
deleted file mode 100644
index 6d2937c..0000000
--- a/src/graphics/common/engine.h
+++ /dev/null
@@ -1,715 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// engine.h
-
-#pragma once
-
-
-#include "graphics/common/color.h"
-#include "graphics/common/material.h"
-#include "graphics/common/vertex.h"
-#include "math/intpoint.h"
-#include "math/matrix.h"
-#include "math/point.h"
-#include "math/vector.h"
-
-
-class CApplication;
-class CInstanceManager;
-class CObject;
-class CSound;
-
-
-namespace Gfx {
-
-class CDevice;
-class CLight;
-class CText;
-class CParticle;
-class CWater;
-class CCloud;
-class CLightning;
-class CPlanet;
-class CTerrain;
-
-
-//const int MAXOBJECT = 1200;
-//const int MAXSHADOW = 500;
-//const int MAXGROUNDSPOT = 100;
-
-
-enum ObjectType
-{
- //! Object doesn't exist
- OBJTYPE_NULL = 0,
- //! Terrain
- OBJTYPE_TERRAIN = 1,
- //! Fixed object
- OBJTYPE_FIX = 2,
- //! Moving object
- OBJTYPE_VEHICULE = 3,
- //! Part of a moving object
- OBJTYPE_DESCENDANT = 4,
- //! Fixed object type quartz
- OBJTYPE_QUARTZ = 5,
- //! Fixed object type metal
- OBJTYPE_METAL = 6
-};
-
-enum TriangleType
-{
- //! triangles
- TRIANGLE_TYPE_6T = 1,
- //! surfaces
- TRIANGLE_TYPE_6S = 2
-};
-
-enum Mapping
-{
- MAPPING_X = 1,
- MAPPING_Y = 2,
- MAPPING_Z = 3,
- MAPPING_1X = 4,
- MAPPING_1Y = 5,
- MAPPING_1Z = 6
-};
-
-enum MouseType
-{
- MOUSE_HIDE = 0, // no mouse
- MOUSE_NORM = 1,
- MOUSE_WAIT = 2,
- MOUSE_EDIT = 3,
- MOUSE_HAND = 4,
- MOUSE_CROSS = 5,
- MOUSE_SHOW = 6,
- MOUSE_NO = 7,
- MOUSE_MOVE = 8, // +
- MOUSE_MOVEH = 9, // -
- MOUSE_MOVEV = 10, // |
- MOUSE_MOVED = 11, // /
- MOUSE_MOVEI = 12, // \ //
- MOUSE_SCROLLL = 13, // <<
- MOUSE_SCROLLR = 14, // >>
- MOUSE_SCROLLU = 15, // ^
- MOUSE_SCROLLD = 16, // v
- MOUSE_TARGET = 17
-};
-
-enum ShadowType
-{
- SHADOW_NORM = 0,
- SHADOW_WORM = 1
-};
-
-enum RenderState
-{
- //! Normal opaque materials
- RSTATE_NORMAL = 0,
- //! The transparent texture (black = no)
- RSTATE_TTEXTURE_BLACK = (1<<0),
- //! The transparent texture (white = no)
- RSTATE_TTEXTURE_WHITE = (1<<1),
- //! The transparent diffuse color
- RSTATE_TDIFFUSE = (1<<2),
- //! Texture wrap
- RSTATE_WRAP = (1<<3),
- //! Texture borders with solid color
- RSTATE_CLAMP = (1<<4),
- //! Light texture (ambient max)
- RSTATE_LIGHT = (1<<5),
- //! Double black texturing
- RSTATE_DUAL_BLACK = (1<<6),
- //! Double white texturing
- RSTATE_DUAL_WHITE = (1<<7),
- //! Part 1 (no change in. MOD!)
- RSTATE_PART1 = (1<<8),
- //! Part 2
- RSTATE_PART2 = (1<<9),
- //! Part 3
- RSTATE_PART3 = (1<<10),
- //! Part 4
- RSTATE_PART4 = (1<<11),
- //! Double-sided face
- RSTATE_2FACE = (1<<12),
- //! Image using alpha channel
- RSTATE_ALPHA = (1<<13),
- //! Always use 2nd floor texturing
- RSTATE_SECOND = (1<<14),
- //! Causes the fog
- RSTATE_FOG = (1<<15),
- //! The transparent color (black = no)
- RSTATE_TCOLOR_BLACK = (1<<16),
- //! The transparent color (white = no)
- RSTATE_TCOLOR_WHITE = (1<<17)
-};
-
-
-struct Triangle
-{
- Gfx::VertexTex2 triangle[3];
- Gfx::Material material;
- int state;
- char texName1[20];
- char texName2[20];
-};
-
-
-struct ObjLevel6
-{
- int totalPossible;
- int totalUsed;
- Gfx::Material material;
- int state;
- Gfx::TriangleType type;
- Gfx::VertexTex2 vertex[1];
-};
-
-struct ObjLevel5
-{
- int totalPossible;
- int totalUsed;
- int reserve;
- Gfx::ObjLevel6* table[1];
-};
-
-struct ObjLevel4
-{
- int totalPossible;
- int totalUsed;
- float min, max;
- Gfx::ObjLevel5* table[1];
-};
-
-struct ObjLevel3
-{
- int totalPossible;
- int totalUsed;
- int objRank;
- Gfx::ObjLevel4* table[1];
-};
-
-struct ObjLevel2
-{
- int totalPossible;
- int totalUsed;
- char texName1[20];
- char texName2[20];
- Gfx::ObjLevel3* table[1];
-};
-
-struct ObjLevel1
-{
- int totalPossible;
- int totalUsed;
- Gfx::ObjLevel2* table[1];
-};
-
-
-struct Object
-{
- bool used; // true -> object exists
- bool visible; // true -> visible object
- bool drawWorld; // true -> shape behind the interface
- bool drawFront; // true -> shape before the interface
- int totalTriangle; // number of triangles used
- Gfx::ObjectType type; // type of the object (TYPE*)
- Math::Matrix transform; // transformation matrix
- float distance; // distance point of view - original
- Math::Vector bboxMin; // bounding box of the object
- Math::Vector bboxMax; // (the origin 0, 0, 0 is always included)
- float radius; // radius of the sphere at the origin
- int shadowRank; // rank of the associated shadow
- float transparency; // transparency of the object (0 .. 1)
-};
-
-struct Shadow
-{
- bool used; // true -> object exists
- bool hide; // true -> invisible shadow (object carried by ex.)
- int objRank; // rank of the object
- Gfx::ShadowType type; // type of shadow
- Math::Vector pos; // position for the shadow
- Math::Vector normal; // normal terrain
- float angle; // angle of the shadow
- float radius; // radius of the shadow
- float intensity; // intensity of the shadow
- float height; // height from the ground
-};
-
-struct GroundSpot
-{
- bool used; // true -> object exists
- Gfx::Color color; // color of the shadow
- float min, max; // altitudes min / max
- float smooth; // transition area
- Math::Vector pos; // position for the shadow
- float radius; // radius of the shadow
- Math::Vector drawPos; // drawn to position the shade
- float drawRadius; // radius of the shadow drawn
-};
-
-struct GroundMark
-{
- bool used; // true -> object exists
- bool draw; // true -> drawn mark
- int phase; // 1 = increase, 2 = fixed, 3 = decrease
- float delay[3]; // time for 3 phases
- float fix; // fixed time
- Math::Vector pos; // position for marks
- float radius; // radius of marks
- float intensity; // color intensity
- Math::Vector drawPos; // drawn in position marks
- float drawRadius; // radius marks drawn
- float drawIntensity; // current drawn
- int dx, dy; // dimensions table
- char* table; // pointer to the table
-};
-
-
-
-class CEngine
-{
-public:
- CEngine(CInstanceManager *iMan, CApplication *app);
- ~CEngine();
-
- void SetDevice(Gfx::CDevice *device);
- Gfx::CDevice* RetDevice();
-
- void SetTerrain(Gfx::CTerrain* terrain);
-
- bool WriteProfile();
-
- void SetPause(bool pause);
- bool RetPause();
-
- void SetMovieLock(bool lock);
- bool RetMovieLock();
-
- void SetShowStat(bool show);
- bool RetShowStat();
-
- void SetRenderEnable(bool enable);
-
- int OneTimeSceneInit();
- int InitDeviceObjects();
- int DeleteDeviceObjects();
- int RestoreSurfaces();
- int Render();
- int FrameMove(float rTime);
- void StepSimul(float rTime);
- int FinalCleanup();
- void AddStatisticTriangle(int nb);
- int RetStatisticTriangle();
- void SetHiliteRank(int *rankList);
- bool GetHilite(Math::Point &p1, Math::Point &p2);
- bool GetSpriteCoord(int &x, int &y);
- void SetInfoText(int line, char* text);
- char * RetInfoText(int line);
- //LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- void FirstExecuteAdapt(bool first);
- //int GetVidMemTotal();
- //bool IsVideo8MB();
- //bool IsVideo32MB();
-
- bool EnumDevices(char *bufDevices, int lenDevices, char *bufModes, int lenModes, int &totalDevices, int &selectDevices, int &totalModes, int &selectModes);
- bool RetFullScreen();
- bool ChangeDevice(char *device, char *mode, bool full);
-
- Math::Matrix* RetMatView();
- Math::Matrix* RetMatLeftView();
- Math::Matrix* RetMatRightView();
-
- void TimeInit();
- void TimeEnterGel();
- void TimeExitGel();
- float TimeGet();
-
- int RetRestCreate();
- int CreateObject();
- void FlushObject();
- bool DeleteObject(int objRank);
- bool SetDrawWorld(int objRank, bool draw);
- bool SetDrawFront(int objRank, bool draw);
- bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, bool globalUpdate);
- bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, bool globalUpdate);
- bool AddQuick(int objRank, Gfx::ObjLevel6* buffer, char* texName1, char* texName2, float min, float max, bool globalUpdate);
- Gfx::ObjLevel6* SearchTriangle(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max);
- void ChangeLOD();
- bool ChangeSecondTexture(int objRank, char* texName2);
- int RetTotalTriangles(int objRank);
- int GetTriangles(int objRank, float min, float max, Gfx::Triangle* buffer, int size, float percent);
- bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max);
- bool ChangeTextureMapping(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, Gfx::Mapping mode, float au, float bu, float av, float bv);
- bool TrackTextureMapping(int objRank, const Gfx::Material &mat, int state, char* texName1, char* texName2, float min, float max, Gfx::Mapping mode, float pos, float factor, float tl, float ts, float tt);
- bool SetObjectTransform(int objRank, const Math::Matrix &transform);
- bool GetObjectTransform(int objRank, Math::Matrix &transform);
- bool SetObjectType(int objRank, Gfx::ObjectType type);
- Gfx::ObjectType RetObjectType(int objRank);
- bool SetObjectTransparency(int objRank, float value);
-
- bool ShadowCreate(int objRank);
- void ShadowDelete(int objRank);
- bool SetObjectShadowHide(int objRank, bool hide);
- bool SetObjectShadowType(int objRank, Gfx::ShadowType type);
- bool SetObjectShadowPos(int objRank, const Math::Vector &pos);
- bool SetObjectShadowNormal(int objRank, const Math::Vector &n);
- bool SetObjectShadowAngle(int objRank, float angle);
- bool SetObjectShadowRadius(int objRank, float radius);
- bool SetObjectShadowIntensity(int objRank, float intensity);
- bool SetObjectShadowHeight(int objRank, float h);
- float RetObjectShadowRadius(int objRank);
-
- void GroundSpotFlush();
- int GroundSpotCreate();
- void GroundSpotDelete(int rank);
- bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos);
- bool SetObjectGroundSpotRadius(int rank, float radius);
- bool SetObjectGroundSpotColor(int rank, const Gfx::Color &color);
- bool SetObjectGroundSpotMinMax(int rank, float min, float max);
- bool SetObjectGroundSpotSmooth(int rank, float smooth);
-
- int GroundMarkCreate(Math::Vector pos, float radius, float delay1, float delay2, float delay3, int dx, int dy, char* table);
- bool GroundMarkDelete(int rank);
-
- void Update();
-
- void SetViewParams(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, const Math::Vector &vUpVec, float fEyeDistance);
-
- bool FreeTexture(char* name);
- bool LoadTexture(char* name, int stage=0);
- bool LoadAllTexture();
-
- void SetLimitLOD(int rank, float limit);
- float RetLimitLOD(int rank, bool last=false);
-
- void SetTerrainVision(float vision);
-
- void SetGroundSpot(bool mode);
- bool RetGroundSpot();
- void SetShadow(bool mode);
- bool RetShadow();
- void SetDirty(bool mode);
- bool RetDirty();
- void SetFog(bool mode);
- bool RetFog();
- bool RetStateColor();
-
- void SetSecondTexture(int texNum);
- int RetSecondTexture();
-
- void SetRankView(int rank);
- int RetRankView();
-
- void SetDrawWorld(bool draw);
- void SetDrawFront(bool draw);
-
- void SetAmbiantColor(const Gfx::Color &color, int rank=0);
- Gfx::Color RetAmbiantColor(int rank=0);
-
- void SetWaterAddColor(const Gfx::Color &color);
- Gfx::Color RetWaterAddColor();
-
- void SetFogColor(const Gfx::Color &color, int rank=0);
- Gfx::Color RetFogColor(int rank=0);
-
- void SetDeepView(float length, int rank=0, bool ref=false);
- float RetDeepView(int rank=0);
-
- void SetFogStart(float start, int rank=0);
- float RetFogStart(int rank=0);
-
- void SetBackground(char *name, Gfx::Color up=Gfx::Color(), Gfx::Color down=Gfx::Color(), Gfx::Color cloudUp=Gfx::Color(), Gfx::Color cloudDown=Gfx::Color(), bool full=false, bool quarter=false);
- void RetBackground(char *name, Gfx::Color &up, Gfx::Color &down, Gfx::Color &cloudUp, Gfx::Color &cloudDown, bool &full, bool &quarter);
- void SetFrontsizeName(char *name);
- void SetOverFront(bool front);
- void SetOverColor(const Gfx::Color &color=Gfx::Color(), int mode=RSTATE_TCOLOR_BLACK);
-
- void SetParticuleDensity(float value);
- float RetParticuleDensity();
- float ParticuleAdapt(float factor);
-
- void SetClippingDistance(float value);
- float RetClippingDistance();
-
- void SetObjectDetail(float value);
- float RetObjectDetail();
-
- void SetGadgetQuantity(float value);
- float RetGadgetQuantity();
-
- void SetTextureQuality(int value);
- int RetTextureQuality();
-
- void SetTotoMode(bool present);
- bool RetTotoMode();
-
- void SetLensMode(bool present);
- bool RetLensMode();
-
- void SetWaterMode(bool present);
- bool RetWaterMode();
-
- void SetBlitzMode(bool present);
- bool RetBlitzMode();
-
- void SetSkyMode(bool present);
- bool RetSkyMode();
-
- void SetBackForce(bool present);
- bool RetBackForce();
-
- void SetPlanetMode(bool present);
- bool RetPlanetMode();
-
- void SetLightMode(bool present);
- bool RetLightMode();
-
- void SetEditIndentMode(bool auto);
- bool RetEditIndentMode();
-
- void SetEditIndentValue(int value);
- int RetEditIndentValue();
-
- void SetSpeed(float speed);
- float RetSpeed();
-
- void SetTracePrecision(float factor);
- float RetTracePrecision();
-
- void SetFocus(float focus);
- float RetFocus();
- Math::Vector RetEyePt();
- Math::Vector RetLookatPt();
- float RetEyeDirH();
- float RetEyeDirV();
- Math::Point RetDim();
- void UpdateMatProj();
-
- void ApplyChange();
-
- void FlushPressKey();
- void ResetKey();
- void SetKey(int keyRank, int option, int key);
- int RetKey(int keyRank, int option);
-
- void SetJoystick(bool enable);
- bool RetJoystick();
-
- void SetDebugMode(bool mode);
- bool RetDebugMode();
- bool RetSetupMode();
-
- bool IsVisiblePoint(const Math::Vector &pos);
-
- int DetectObject(Math::Point mouse);
- void SetState(int state, Gfx::Color color=Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f));
- void SetTexture(char *name, int stage=0);
- void SetMaterial(const Gfx::Material &mat);
-
- void MoveMousePos(Math::Point pos);
- void SetMousePos(Math::Point pos);
- Math::Point RetMousePos();
- void SetMouseType(Gfx::MouseType type);
- Gfx::MouseType RetMouseType();
- void SetMouseHide(bool hide);
- bool RetMouseHide();
- void SetNiceMouse(bool nice);
- bool RetNiceMouse();
- bool RetNiceMouseCap();
-
- CText* RetText();
-
- bool ChangeColor(char *name, Gfx::Color colorRef1, Gfx::Color colorNew1, Gfx::Color colorRef2, Gfx::Color colorNew2, float tolerance1, float tolerance2, Math::Point ts, Math::Point ti, Math::Point *pExclu=0, float shift=0.0f, bool hSV=false);
- bool OpenImage(char *name);
- bool CopyImage();
- bool LoadImage();
- bool ScrollImage(int dx, int dy);
- bool SetDot(int x, int y, Gfx::Color color);
- bool CloseImage();
- bool WriteScreenShot(char *filename, int width, int height);
- //bool GetRenderDC(HDC &hDC);
- //bool ReleaseRenderDC(HDC &hDC);
- //PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp);
- //bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);
-
-protected:
- void MemSpace1(Gfx::ObjLevel1 *&p, int nb);
- void MemSpace2(Gfx::ObjLevel2 *&p, int nb);
- void MemSpace3(Gfx::ObjLevel3 *&p, int nb);
- void MemSpace4(Gfx::ObjLevel4 *&p, int nb);
- void MemSpace5(Gfx::ObjLevel5 *&p, int nb);
- void MemSpace6(Gfx::ObjLevel6 *&p, int nb);
-
- Gfx::ObjLevel2* AddLevel1(Gfx::ObjLevel1 *&p1, char* texName1, char* texName2);
- Gfx::ObjLevel3* AddLevel2(Gfx::ObjLevel2 *&p2, int objRank);
- Gfx::ObjLevel4* AddLevel3(Gfx::ObjLevel3 *&p3, float min, float max);
- Gfx::ObjLevel5* AddLevel4(Gfx::ObjLevel4 *&p4, int reserve);
- Gfx::ObjLevel6* AddLevel5(Gfx::ObjLevel5 *&p5, Gfx::TriangleType type, const Gfx::Material &mat, int state, int nb);
-
- bool IsVisible(int objRank);
- bool DetectBBox(int objRank, Math::Point mouse);
- bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2 *triangle, int objRank, float &dist);
- bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D);
- void ComputeDistance();
- void UpdateGeometry();
- void RenderGroundSpot();
- void DrawShadow();
- void DrawBackground();
- void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down);
- void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name);
- void DrawBackgroundImage();
- void DrawPlanet();
- void DrawFrontsize();
- void DrawOverColor();
- bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max);
- void DrawHilite();
- void DrawMouse();
- void DrawSprite(Math::Point pos, Math::Point dim, int icon);
-
-protected:
- CInstanceManager* m_iMan;
- CApplication* m_app;
- Gfx::CDevice* m_device;
- Gfx::CText* m_text;
- Gfx::CLight* m_light;
- Gfx::CParticle* m_particule;
- Gfx::CWater* m_water;
- Gfx::CCloud* m_cloud;
- Gfx::CLightning* m_blitz;
- Gfx::CPlanet* m_planet;
- Gfx::CTerrain* m_terrain;
- CSound* m_sound;
-
- int m_blackSrcBlend[2];
- int m_blackDestBlend[2];
- int m_whiteSrcBlend[2];
- int m_whiteDestBlend[2];
- int m_diffuseSrcBlend[2];
- int m_diffuseDestBlend[2];
- int m_alphaSrcBlend[2];
- int m_alphaDestBlend[2];
-
- Math::Matrix m_matProj;
- Math::Matrix m_matLeftView;
- Math::Matrix m_matRightView;
- Math::Matrix m_matView;
- float m_focus;
-
- Math::Matrix m_matWorldInterface;
- Math::Matrix m_matProjInterface;
- Math::Matrix m_matViewInterface;
-
- long m_baseTime;
- long m_stopTime;
- float m_absTime;
- float m_lastTime;
- float m_speed;
- bool m_pause;
- bool m_render;
- bool m_movieLock;
-
- Math::IntPoint m_dim;
- Math::IntPoint m_lastDim;
- Gfx::ObjLevel1* m_objectPointer;
- int m_objectParamTotal;
- Gfx::Object* m_objectParam;
- int m_shadowTotal;
- Gfx::Shadow* m_shadow;
- Gfx::GroundSpot* m_groundSpot;
- Gfx::GroundMark m_groundMark;
- Math::Vector m_eyePt;
- Math::Vector m_lookatPt;
- float m_eyeDirH;
- float m_eyeDirV;
- int m_rankView;
- Gfx::Color m_ambiantColor[2];
- Gfx::Color m_backColor[2];
- Gfx::Color m_fogColor[2];
- float m_deepView[2];
- float m_fogStart[2];
- Gfx::Color m_waterAddColor;
- int m_statisticTriangle;
- bool m_updateGeometry;
- char m_infoText[10][200];
- int m_alphaMode;
- bool m_stateColor;
- bool m_forceStateColor;
- bool m_groundSpotVisible;
- bool m_shadowVisible;
- bool m_dirty;
- bool m_fog;
- bool m_firstGroundSpot;
- int m_secondTexNum;
- char m_backgroundName[50];
- Gfx::Color m_backgroundColorUp;
- Gfx::Color m_backgroundColorDown;
- Gfx::Color m_backgroundCloudUp;
- Gfx::Color m_backgroundCloudDown;
- bool m_backgroundFull;
- bool m_backgroundQuarter;
- bool m_overFront;
- Gfx::Color m_overColor;
- int m_overMode;
- char m_frontsizeName[50];
- bool m_drawWorld;
- bool m_drawFront;
- float m_limitLOD[2];
- float m_particuleDensity;
- float m_clippingDistance;
- float m_lastClippingDistance;
- float m_objectDetail;
- float m_lastObjectDetail;
- float m_terrainVision;
- float m_gadgetQuantity;
- int m_textureQuality;
- bool m_totoMode;
- bool m_lensMode;
- bool m_waterMode;
- bool m_skyMode;
- bool m_backForce;
- bool m_planetMode;
- bool m_lightMode;
- bool m_editIndentMode;
- int m_editIndentValue;
- float m_tracePrecision;
-
- int m_hiliteRank[100];
- bool m_hilite;
- Math::Point m_hiliteP1;
- Math::Point m_hiliteP2;
-
- int m_lastState;
- Gfx::Color m_lastColor;
- char m_lastTexture[2][50];
- Gfx::Material m_lastMaterial;
-
- Math::Point m_mousePos;
- Gfx::MouseType m_mouseType;
- bool m_mouseHide;
- bool m_niceMouse;
-
- //LPDIRECTDRAWSURFACE7 m_imageSurface;
- //DDSURFACEDESC2 m_imageDDSD;
- //WORD* m_imageCopy;
- //int m_imageDX;
- //int m_imageDY;
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/common/light.cpp b/src/graphics/common/light.cpp
deleted file mode 100644
index d938256..0000000
--- a/src/graphics/common/light.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// light.cpp
-
-#include "graphics/common/light.h"
-
-// TODO implementation \ No newline at end of file
diff --git a/src/graphics/common/light.h b/src/graphics/common/light.h
deleted file mode 100644
index dec9912..0000000
--- a/src/graphics/common/light.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// light.h
-
-#pragma once
-
-
-#include "graphics/common/color.h"
-#include "math/vector.h"
-
-
-namespace Gfx {
-
-/** \enum LightType
- * \brief Type of light */
-enum LightType
-{
- LT_Point,
- LT_Spot,
- LT_Directional
-};
-
-/**
- * \struct Light
- * \brief Light
- *
- * This structure was created as analog to DirectX's D3DLIGHT.
- *
- * It contains analogous fields as the D3DLIGHT struct.
- */
-struct Light
-{
- //! Type of light source
- Gfx::LightType type;
- //! Color of light
- Gfx::Color color;
- //! Position in world space
- Math::Vector position;
- //! Direction in world space
- Math::Vector direction;
- //! Cutoff range
- float range;
- //! Falloff
- float falloff;
- //! Constant attenuation
- float attenuation0;
- //! Linear attenuation
- float attenuation1;
- //! Quadratic attenuation
- float attenuation2;
- //! Inner angle of spotlight cone
- float theta;
- //! Outer angle of spotlight cone
- float phi;
-
- Light() : type(LT_Point), range(0.0f), falloff(0.0f),
- attenuation0(0.0f), attenuation1(0.0f), attenuation2(0.0f),
- theta(0.0f), phi(0.0f) {}
-};
-
-struct LightProg
-{
- float starting;
- float ending;
- float current;
- float progress;
- float speed;
-};
-
-/**
- * \struct SceneLight
- * \brief Dynamic light in 3D scene
- *
- * TODO documentation
- */
-struct SceneLight
-{
- //! true -> light exists
- bool used;
- //! true -> light turned on
- bool enable;
-
- //! Type of all objects included
- //D3DTypeObj incluType;
- //! Type of all objects excluded
- //D3DTypeObj excluType;
-
- //! Configuration of the light
- Gfx::Light light;
-
- //! intensity (0 .. 1)
- Gfx::LightProg intensity;
- Gfx::LightProg colorRed;
- Gfx::LightProg colorGreen;
- Gfx::LightProg colorBlue;
-};
-
-// TODO CLight
-
-}; // namespace Gfx
diff --git a/src/graphics/common/model.cpp b/src/graphics/common/model.cpp
deleted file mode 100644
index c415fb8..0000000
--- a/src/graphics/common/model.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// model.cpp
-
-#include "graphics/common/model.h"
-
-
-// TODO implementation
diff --git a/src/graphics/common/model.h b/src/graphics/common/model.h
deleted file mode 100644
index e8a5f19..0000000
--- a/src/graphics/common/model.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// model.h
-
-#pragma once
-
-#include "engine.h"
-#include "common/event.h"
-#include "modfile.h"
-#include "vertex.h"
-#include "math/point.h"
-
-
-class CInstanceManager;
-class CModFile;
-class CInterface;
-
-
-namespace Gfx {
-
-class CEngine;
-
-
-class CModel {
- public:
- CModel(CInstanceManager* iMan);
- ~CModel();
-
- void StartUserAction();
- void StopUserAction();
-
- bool EventProcess(const Event &event);
-
- void InitView();
- void InitViewFromSelect();
- void UpdateView();
- void ViewMove(const Event &event, float speed);
-
- protected:
- bool EventFrame(const Event &event);
- bool GetVertex(int rank, Gfx::VertexTex2 &vertex);
- bool SetVertex(int rank, Gfx::VertexTex2 &vertex);
- Math::Vector RetSelectCDG();
- Math::Vector RetSelectNormal();
- void SmoothSelect();
- void PlaneSelect();
- void ColorSelect();
- void StateSelect();
- void MoveSelect(Math::Vector move);
- void OperSelect(Math::Vector move, char oper);
- void ReadScript(char *filename);
- void BBoxCompute(Math::Vector &min, Math::Vector &max);
- bool IsMappingSelectPlausible(Gfx::Mapping D3Dmode);
- void MappingSelect(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelectSpherical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- Math::Vector RetMappingCenter(Math::Vector pos, Math::Vector min);
- void MappingSelectCylindrical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelectFace(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelect2(int texNum2, int subdiv, int offsetU, int offsetV, bool bMirrorX, bool bMirrorY);
- void MappingSelectPlane2(int mode, bool bMirrorX, bool bMirrorY);
- void MappingSelectSpherical2(bool bMirrorX, bool bMirrorY);
- void MappingSelectMagic2(bool bMirrorX, bool bMirrorY);
- int SearchNext(int rank, int step);
- int SearchSamePlane(int first, int step);
- void CurrentSearchNext(int step, bool bControl);
- void CurrentInit();
- void CurrentSelect(bool bSelect);
- void DeselectAll();
- void SelectAll();
- void SelectZone(int first, int last);
- void SelectTerm();
- void DefaultSelect();
- void SelectDelete();
- void Compress();
- void MinMaxSelect();
- void MinMaxChange();
- void UpdateInfoText();
- int* RetTextureTable();
- void TexturePartUpdate();
- void TextureRankChange(int step);
- void TexturePartChange(int step);
- void PutTextureValues();
- void GetTextureValues();
- void GetModelName(char *buffer);
- void GetDXFName(char *buffer);
- void GetScriptName(char *buffer);
- bool IsEditFocus();
-
- protected:
- CInstanceManager* m_iMan;
- Gfx::CEngine* m_engine;
- CModFile* m_modFile;
- CInterface* m_interface;
-
- float m_time;
- ModelTriangle* m_triangleTable;
- int m_triangleSel1;
- int m_triangleSel2;
- int m_mode;
- int m_textureMode;
- int m_textureRotate;
- bool m_bTextureMirrorX;
- bool m_bTextureMirrorY;
- Math::Point m_textureInf;
- Math::Point m_textureSup;
- int m_texturePart;
- int m_textureRank;
- char m_textureName[20];
- bool m_bDisplayTransparent;
- bool m_bDisplayOnlySelection;
- float m_viewHeight;
- float m_viewDist;
- float m_viewAngleH;
- float m_viewAngleV;
- int m_color;
- int m_state;
- int m_secondTexNum;
- int m_secondSubdiv;
- int m_secondOffsetU;
- int m_secondOffsetV;
- char m_oper;
- float m_min;
- float m_max;
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/common/modfile.cpp b/src/graphics/common/modfile.cpp
deleted file mode 100644
index 6f80be7..0000000
--- a/src/graphics/common/modfile.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// modfile.cpp
-
-#include "graphics/common/modfile.h"
-
-
-// TODO implementation \ No newline at end of file
diff --git a/src/graphics/common/modfile.h b/src/graphics/common/modfile.h
deleted file mode 100644
index c81739b..0000000
--- a/src/graphics/common/modfile.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// modfile.h
-
-#include "engine.h"
-#include "vertex.h"
-#include "material.h"
-#include "math/vector.h"
-
-
-class CInstanceManager;
-
-
-namespace Gfx {
-
-struct OldModelTriangle1
-{
- char bUsed; // TRUE -> using
- char bSelect; // TRUE -> selected
- Vertex p1;
- Vertex p2;
- Vertex p3;
- Material material;
- char texName[20];
- float min;
- float max;
-}; // length = 196 bytes
-
-struct OldModelTriangle2
-{
- char bUsed; // TRUE -> used
- char bSelect; // TRUE -> selected
- Vertex p1;
- Vertex p2;
- Vertex p3;
- Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short reserve1;
- short reserve2;
- short reserve3;
- short reserve4;
-};
-
-struct ModelTriangle
-{
- char bUsed; // TRUE -> used
- char bSelect; // TRUE -> selected
- VertexTex2 p1;
- VertexTex2 p2;
- VertexTex2 p3;
- Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short texNum2;
- short reserve2;
- short reserve3;
- short reserve4;
-}; // length = 208 bytes
-
-
-
-
-class CModFile {
-public:
- CModFile(CInstanceManager* iMan);
- ~CModFile();
-
- bool ReadDXF(char *filename, float min, float max);
- bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true);
- bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true);
- bool WriteModel(char *filename);
-
- bool CreateEngineObject(int objRank, int addState=0);
- void Mirror();
-
- void SetTriangleUsed(int total);
- int RetTriangleUsed();
- int RetTriangleMax();
- ModelTriangle* RetTriangleList();
-
- float RetHeight(Math::Vector pos);
-
-protected:
- bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
-
-protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
-
- ModelTriangle* m_triangleTable;
- int m_triangleUsed;
-};
-
-};
diff --git a/src/graphics/common/vertex.h b/src/graphics/common/vertex.h
deleted file mode 100644
index 0cc6402..0000000
--- a/src/graphics/common/vertex.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// vertex.h
-
-#pragma once
-
-
-#include "math/vector.h"
-#include "math/point.h"
-
-namespace Gfx {
-
-/**
- * \struct Vertex
- * \brief Vertex of a primitive
- *
- * This structure was created as analog to DirectX's D3DVERTEX.
- *
- * It contains:
- * - vertex coordinates (x,y,z) as Math::Vector,
- * - normal coordinates (nx,ny,nz) as Math::Vector
- * - texture coordinates (u,v) as Math::Point.
- */
-struct Vertex
-{
- Math::Vector coord;
- Math::Vector normal;
- Math::Point texCoord;
-
- Vertex(Math::Vector aCoord = Math::Vector(),
- Math::Vector aNormal = Math::Vector(),
- Math::Point aTexCoord = Math::Point())
- : coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
-};
-
-/**
- * \struct VertexTex2
- * \brief Vertex with secondary texture coordinates
- *
- * In addition to fields from Gfx::Vector, it contains
- * secondary texture coordinates (u2, v2) as Math::Point
- */
-struct VertexTex2 : public Gfx::Vertex
-{
- Math::Point texCoord2;
-
- VertexTex2(Math::Vector aCoord = Math::Vector(),
- Math::Vector aNormal = Math::Vector(),
- Math::Point aTexCoord = Math::Point(),
- Math::Point aTexCoord2 = Math::Point())
- : Vertex(aCoord, aNormal, aTexCoord), texCoord2(aTexCoord2) {}
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/core/README.txt b/src/graphics/core/README.txt
new file mode 100644
index 0000000..12beef9
--- /dev/null
+++ b/src/graphics/core/README.txt
@@ -0,0 +1,6 @@
+src/graphics/core
+
+Abstract core of graphics engine
+
+Core types, enums, structs and CDevice abstract class that define
+the abstract graphics device used in graphics engine
diff --git a/src/graphics/core/color.cpp b/src/graphics/core/color.cpp
new file mode 100644
index 0000000..f241227
--- /dev/null
+++ b/src/graphics/core/color.cpp
@@ -0,0 +1,103 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// color.cpp
+
+#include "graphics/core/color.h"
+
+#include "math/func.h"
+
+
+Gfx::ColorHSV Gfx::RGB2HSV(Gfx::Color color)
+{
+ Gfx::ColorHSV result;
+
+ float min = Math::Min(color.r, color.g, color.b);
+ float max = Math::Max(color.r, color.g, color.b);
+
+ result.v = max; // intensity
+
+ if ( max == 0.0f )
+ {
+ result.s = 0.0f; // saturation
+ result.h = 0.0f; // undefined color!
+ }
+ else
+ {
+ float delta = max-min;
+ result.s = delta/max; // saturation
+
+ if ( color.r == max ) // between yellow & magenta
+ {
+ result.h = (color.g-color.b)/delta;
+ }
+ else if ( color.g == max ) // between cyan & yellow
+ {
+ result.h = 2.0f+(color.b-color.r)/delta;
+ }
+ else // between magenta & cyan
+ {
+ result.h = 4.0f+(color.r-color.g)/delta;
+ }
+
+ result.h *= 60.0f; // in degrees
+ if ( result.h < 0.0f ) result.h += 360.0f;
+ result.h /= 360.0f; // 0..1
+ }
+
+ return result;
+}
+
+Gfx::Color Gfx::HSV2RGB(Gfx::ColorHSV color)
+{
+ Gfx::Color result;
+
+ color.h = Math::Norm(color.h)*360.0f;
+ color.s = Math::Norm(color.s);
+ color.v = Math::Norm(color.v);
+
+ if ( color.s == 0.0f ) // zero saturation?
+ {
+ result.r = color.v;
+ result.g = color.v;
+ result.b = color.v; // gray
+ }
+ else
+ {
+ if ( color.h == 360.0f ) color.h = 0.0f;
+ color.h /= 60.0f;
+ int i = static_cast<int>(color.h); // integer part (0 .. 5)
+ float f = color.h-i; // fractional part
+
+ float v = color.v;
+ float p = color.v*(1.0f-color.s);
+ float q = color.v*(1.0f-(color.s*f));
+ float t = color.v*(1.0f-(color.s*(1.0f-f)));
+
+ switch (i)
+ {
+ case 0: result.r=v; result.g=t; result.b=p; break;
+ case 1: result.r=q; result.g=v; result.b=p; break;
+ case 2: result.r=p; result.g=v; result.b=t; break;
+ case 3: result.r=p; result.g=q; result.b=v; break;
+ case 4: result.r=t; result.g=p; result.b=v; break;
+ case 5: result.r=v; result.g=p; result.b=q; break;
+ }
+ }
+
+ return result;
+}
+
diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h
new file mode 100644
index 0000000..6973644
--- /dev/null
+++ b/src/graphics/core/color.h
@@ -0,0 +1,98 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// color.h
+
+#pragma once
+
+
+#include <sstream>
+
+
+namespace Gfx {
+
+/**
+ \struct Color
+ \brief RGBA color */
+struct Color
+{
+ //! Red, green, blue and alpha components
+ float r, g, b, a;
+
+ //! Constructor; default values are (0,0,0,0) = black
+ Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f)
+ : r(aR), g(aG), b(aB), a(aA) {}
+
+ inline Gfx::Color Inverse() const
+ {
+ return Gfx::Color(1.0f - r, 1.0f - g, 1.0f - b, 1.0f - a);
+ }
+
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return reinterpret_cast<float*>(this);
+ }
+
+ //! Returns the struct cast to <tt>const float*</tt> array; use with care!
+ inline const float* Array() const
+ {
+ return reinterpret_cast<const float*>(this);
+ }
+
+ //! Returns a string (r, g, b, a)
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(" << r << ", " << g << ", " << b << ", " << a << ")";
+ return s.str();
+ }
+
+ inline bool operator==(const Gfx::Color &other) const
+ {
+ return r == other.r && g == other.g && b == other.b && a == other.a;
+ }
+};
+
+/**
+ \struct ColorHSV
+ \brief HSV color */
+struct ColorHSV
+{
+ float h, s, v;
+
+ ColorHSV(float aH = 0.0f, float aS = 0.0f, float aV = 0.0f)
+ : h(aH), s(aS), v(aV) {}
+
+ //! Returns a string "(h, s, v)"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(" << h << ", " << s << ", " << v << ")";
+ return s.str();
+ }
+};
+
+//! Converts a RGB color to HSV color
+Gfx::ColorHSV RGB2HSV(Gfx::Color color);
+
+//! Converts a HSV color to RGB color
+Gfx::Color HSV2RGB(Gfx::ColorHSV color);
+
+}; // namespace Gfx
+
diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h
new file mode 100644
index 0000000..c10b853
--- /dev/null
+++ b/src/graphics/core/device.h
@@ -0,0 +1,412 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// device.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "graphics/core/light.h"
+#include "graphics/core/material.h"
+#include "graphics/core/texture.h"
+#include "graphics/core/vertex.h"
+#include "math/intsize.h"
+#include "math/matrix.h"
+
+#include <string>
+
+
+class CImage;
+
+
+namespace Gfx {
+
+/**
+ \struct DeviceConfig
+ \brief General config for graphics device
+
+ These settings are common window options set by SDL.
+*/
+struct DeviceConfig
+{
+ //! Screen size
+ Math::IntSize size;
+ //! Bits per pixel
+ int bpp;
+ //! Full screen
+ bool fullScreen;
+ //! Resizeable window
+ bool resizeable;
+ //! Double buffering
+ bool doubleBuf;
+ //! No window frame (also set with full screen)
+ bool noFrame;
+
+ //! Constructor calls LoadDefault()
+ DeviceConfig() { LoadDefault(); }
+
+ //! Loads the default values
+ inline void LoadDefault()
+ {
+ size = Math::IntSize(800, 600);
+ bpp = 32;
+ fullScreen = false;
+ resizeable = false;
+ doubleBuf = true;
+ noFrame = false;
+ }
+};
+
+
+/**
+ \enum TransformType
+ \brief Type of transformation in rendering pipeline
+
+ These correspond to DirectX's three transformation matrices. */
+enum TransformType
+{
+ TRANSFORM_WORLD,
+ TRANSFORM_VIEW,
+ TRANSFORM_PROJECTION
+};
+
+/**
+ \enum RenderState
+ \brief Render states that can be enabled/disabled */
+enum RenderState
+{
+ RENDER_STATE_LIGHTING,
+ RENDER_STATE_TEXTURING,
+ RENDER_STATE_BLENDING,
+ RENDER_STATE_FOG,
+ RENDER_STATE_DEPTH_TEST,
+ RENDER_STATE_DEPTH_WRITE,
+ RENDER_STATE_ALPHA_TEST,
+ RENDER_STATE_CULLING,
+ RENDER_STATE_DITHERING
+};
+
+/**
+ \enum CompFunc
+ \brief Type of function used to compare values */
+enum CompFunc
+{
+ COMP_FUNC_NEVER,
+ COMP_FUNC_LESS,
+ COMP_FUNC_EQUAL,
+ COMP_FUNC_NOTEQUAL,
+ COMP_FUNC_LEQUAL,
+ COMP_FUNC_GREATER,
+ COMP_FUNC_GEQUAL,
+ COMP_FUNC_ALWAYS
+};
+
+/**
+ \enum BlendFunc
+ \brief Type of blending function */
+enum BlendFunc
+{
+ BLEND_ZERO,
+ BLEND_ONE,
+ BLEND_SRC_COLOR,
+ BLEND_INV_SRC_COLOR,
+ BLEND_DST_COLOR,
+ BLEND_INV_DST_COLOR,
+ BLEND_SRC_ALPHA,
+ BLEND_INV_SRC_ALPHA,
+ BLEND_DST_ALPHA,
+ BLEND_INV_DST_ALPHA,
+ BLEND_SRC_ALPHA_SATURATE
+};
+
+/**
+ \enum FogMode
+ \brief Type of fog calculation function */
+enum FogMode
+{
+ FOG_LINEAR,
+ FOG_EXP,
+ FOG_EXP2
+};
+
+/**
+ \enum CullMode
+ \brief Culling mode for polygons */
+enum CullMode
+{
+ //! Cull clockwise side
+ CULL_CW,
+ //! Cull counter-clockwise side
+ CULL_CCW
+};
+
+/**
+ \enum ShadeModel
+ \brief Shade model used in rendering */
+enum ShadeModel
+{
+ SHADE_FLAT,
+ SHADE_SMOOTH
+};
+
+/**
+ \enum FillMode
+ \brief Polygon fill mode */
+enum FillMode
+{
+ //! Draw only points
+ FILL_POINT,
+ //! Draw only lines
+ FILL_LINES,
+ //! Draw full polygons
+ FILL_FILL
+};
+
+/**
+ \enum PrimitiveType
+ \brief Type of primitive to render */
+enum PrimitiveType
+{
+ PRIMITIVE_POINTS,
+ PRIMITIVE_LINES,
+ PRIMITIVE_LINE_STRIP,
+ PRIMITIVE_TRIANGLES,
+ PRIMITIVE_TRIANGLE_STRIP
+};
+
+/**
+ \enum IntersectPlane
+ \brief Intersection plane of projection volume
+
+ These flags can be OR'd together. */
+enum IntersectPlane
+{
+ INTERSECT_PLANE_LEFT = 0x01,
+ INTERSECT_PLANE_RIGHT = 0x02,
+ INTERSECT_PLANE_TOP = 0x04,
+ INTERSECT_PLANE_BOTTOM = 0x08,
+ INTERSECT_PLANE_FRONT = 0x10,
+ INTERSECT_PLANE_BACK = 0x20,
+ INTERSECT_PLANE_ALL = INTERSECT_PLANE_LEFT | INTERSECT_PLANE_RIGHT |
+ INTERSECT_PLANE_TOP | INTERSECT_PLANE_BOTTOM |
+ INTERSECT_PLANE_FRONT | INTERSECT_PLANE_BACK
+};
+
+/*
+
+Notes for rewriting DirectX code:
+
+>> SetRenderState() translates to many functions depending on param
+
+D3DRENDERSTATE_ALPHABLENDENABLE -> SetRenderState() with RENDER_STATE_BLENDING
+D3DRENDERSTATE_ALPHAFUNC -> SetAlphaTestFunc() func
+D3DRENDERSTATE_ALPHAREF -> SetAlphaTestFunc() ref
+D3DRENDERSTATE_ALPHATESTENABLE -> SetRenderState() with RENDER_STATE_ALPHA_TEST
+D3DRENDERSTATE_AMBIENT -> SetGlobalAmbient()
+D3DRENDERSTATE_CULLMODE -> SetCullMode()
+D3DRENDERSTATE_DESTBLEND -> SetBlendFunc() dest blending func
+D3DRENDERSTATE_DITHERENABLE -> SetRenderState() with RENDER_STATE_DITHERING
+D3DRENDERSTATE_FILLMODE -> SetFillMode()
+D3DRENDERSTATE_FOGCOLOR -> SetFogParams()
+D3DRENDERSTATE_FOGENABLE -> SetRenderState() with RENDER_STATE_FOG
+D3DRENDERSTATE_FOGEND -> SetFogParams()
+D3DRENDERSTATE_FOGSTART -> SetFogParams()
+D3DRENDERSTATE_FOGVERTEXMODE -> SetFogParams() fog model
+D3DRENDERSTATE_LIGHTING -> SetRenderState() with RENDER_STATE_LIGHTING
+D3DRENDERSTATE_SHADEMODE -> SetShadeModel()
+D3DRENDERSTATE_SPECULARENABLE -> doesn't matter (always enabled)
+D3DRENDERSTATE_SRCBLEND -> SetBlendFunc() src blending func
+D3DRENDERSTATE_TEXTUREFACTOR -> SetTextureFactor()
+D3DRENDERSTATE_ZBIAS -> SetDepthBias()
+D3DRENDERSTATE_ZENABLE -> SetRenderState() with RENDER_STATE_DEPTH_TEST
+D3DRENDERSTATE_ZFUNC -> SetDepthTestFunc()
+D3DRENDERSTATE_ZWRITEENABLE -> SetRenderState() with RENDER_STATE_DEPTH_WRITE
+
+
+>> SetTextureStageState() translates to SetTextureParams() or CreateTexture() for some params
+
+Params from enum in struct TextureCreateParams or TextureParams
+ D3DTSS_ADDRESS -> Gfx::TexWrapMode wrapS, wrapT
+ D3DTSS_ALPHAARG1 -> Gfx::TexMixArgument alphaArg1
+ D3DTSS_ALPHAARG2 -> Gfx::TexMixArgument alphaArg2
+ D3DTSS_ALPHAOP -> Gfx::TexMixOperation alphaOperation
+ D3DTSS_COLORARG1 -> Gfx::TexMixArgument colorArg1
+ D3DTSS_COLORARG2 -> Gfx::TexMixArgument colorArg2
+ D3DTSS_COLOROP -> Gfx::TexMixOperation colorOperation
+ D3DTSS_MAGFILTER -> Gfx::TexMagFilter magFilter
+ D3DTSS_MINFILTER -> Gfx::TexMinFilter minFilter
+ D3DTSS_TEXCOORDINDEX -> doesn't matter (texture coords are set explicitly by glMultiTexCoordARB*)
+
+Note that D3DTSS_ALPHAOP or D3DTSS_COLOROP set to D3DTOP_DISABLE must translate to disabling the whole texture stage.
+In DirectX, you shouldn't mix enabling one and disabling the other.
+Also, if previous stage is disabled in DirectX, the later ones are disabled, too. In OpenGL, that is not the case.
+
+*/
+
+/**
+ \class CDevice
+ \brief Abstract interface of graphics device
+
+ It is based on DIRECT3DDEVICE class from DirectX to make it easier to port existing code.
+ It encapsulates the general graphics device state and provides a common interface
+ to graphics-specific functions which will be used throughout the program,
+ both in CEngine class and in UI classes. Note that it doesn't contain all functions from DirectX,
+ only those that were used in old code.
+
+ */
+class CDevice
+{
+public:
+ virtual ~CDevice() {}
+
+ //! Initializes the device, setting the initial state
+ virtual bool Create() = 0;
+ //! Destroys the device, releasing every acquired resource
+ virtual void Destroy() = 0;
+
+ //! Returns whether the device has been initialized
+ virtual bool GetWasInit() = 0;
+ //! Returns the last encountered error
+ virtual std::string GetError() = 0;
+
+ //! Begins drawing the 3D scene
+ virtual void BeginScene() = 0;
+ //! Ends drawing the 3D scene
+ virtual void EndScene() = 0;
+
+ //! Clears the screen to blank
+ virtual void Clear() = 0;
+
+ //! Sets the transform matrix of given type
+ virtual void SetTransform(TransformType type, const Math::Matrix &matrix) = 0;
+ //! Returns the current transform matrix of given type
+ virtual const Math::Matrix& GetTransform(TransformType type) = 0;
+ //! Multiplies the current transform matrix of given type by given matrix
+ virtual void MultiplyTransform(TransformType type, const Math::Matrix &matrix) = 0;
+
+ //! Sets the current material
+ virtual void SetMaterial(const Gfx::Material &material) = 0;
+ //! Returns the current material
+ virtual const Gfx::Material& GetMaterial() = 0;
+
+ //! Returns the maximum number of lights available
+ virtual int GetMaxLightCount() = 0;
+ //! Sets the light at given index
+ virtual void SetLight(int index, const Gfx::Light &light) = 0;
+ //! Returns the current light at given index
+ virtual const Gfx::Light& GetLight(int index) = 0;
+ //! Enables/disables the light at given index
+ virtual void SetLightEnabled(int index, bool enabled) = 0;
+ //! Returns the current enable state of light at given index
+ virtual bool GetLightEnabled(int index) = 0;
+
+ //! Creates a texture from image; the image can be safely removed after that
+ virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams &params) = 0;
+ //! Deletes a given texture, freeing it from video memory
+ virtual void DestroyTexture(const Gfx::Texture &texture) = 0;
+ //! Deletes all textures created so far
+ virtual void DestroyAllTextures() = 0;
+
+ //! Returns the maximum number of multitexture stages
+ virtual int GetMaxTextureCount() = 0;
+ //! Sets the (multi)texture at given index
+ virtual void SetTexture(int index, const Gfx::Texture &texture) = 0;
+ //! Returns the (multi)texture at given index
+ virtual Gfx::Texture GetTexture(int index) = 0;
+ //! Enables/disables the given texture stage
+ virtual void SetTextureEnabled(int index, bool enabled) = 0;
+ //! Returns the current enable state of given texture stage
+ virtual bool GetTextureEnabled(int index) = 0;
+
+ //! Sets the params for texture stage with given index
+ virtual void SetTextureStageParams(int index, const Gfx::TextureStageParams &params) = 0;
+ //! Returns the current params of texture stage with given index
+ virtual Gfx::TextureStageParams GetTextureStageParams(int index) = 0;
+
+ //! Sets the texture factor to the given color value
+ virtual void SetTextureFactor(const Gfx::Color &color) = 0;
+ //! Returns the current texture factor
+ virtual Gfx::Color GetTextureFactor() = 0;
+
+ //! Renders primitive composed of vertices with single texture
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::Vertex *vertices , int vertexCount) = 0;
+ //! Renders primitive composed of vertices with color information and single texture
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices , int vertexCount) = 0;
+ //! Renders primitive composed of vertices with multitexturing (2 textures)
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount) = 0;
+
+ //! Tests whether a sphere intersects the 6 clipping planes of projection volume
+ virtual int ComputeSphereVisibility(const Math::Vector &center, float radius) = 0;
+
+ //! Enables/disables the given render state
+ virtual void SetRenderState(Gfx::RenderState state, bool enabled) = 0;
+ //! Returns the current setting of given render state
+ virtual bool GetRenderState(Gfx::RenderState state) = 0;
+
+ //! Sets the function of depth test
+ virtual void SetDepthTestFunc(Gfx::CompFunc func) = 0;
+ //! Returns the current function of depth test
+ virtual Gfx::CompFunc GetDepthTestFunc() = 0;
+
+ //! Sets the depth bias (constant value added to Z-coords)
+ virtual void SetDepthBias(float factor) = 0;
+ //! Returns the current depth bias
+ virtual float GetDepthBias() = 0;
+
+ //! Sets the alpha test function and reference value
+ virtual void SetAlphaTestFunc(Gfx::CompFunc func, float refValue) = 0;
+ //! Returns the current alpha test function and reference value
+ virtual void GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue) = 0;
+
+ //! Sets the blending functions for source and destination operations
+ virtual void SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend) = 0;
+ //! Returns the current blending functions for source and destination operations
+ virtual void GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend) = 0;
+
+ //! Sets the clear color
+ virtual void SetClearColor(const Gfx::Color &color) = 0;
+ //! Returns the current clear color
+ virtual Gfx::Color GetClearColor() = 0;
+
+ //! Sets the global ambient color
+ virtual void SetGlobalAmbient(const Gfx::Color &color) = 0;
+ //! Returns the global ambient color
+ virtual Gfx::Color GetGlobalAmbient() = 0;
+
+ //! Sets the fog parameters: mode, color, start distance, end distance and density (for exp models)
+ virtual void SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density) = 0;
+ //! Returns the current fog parameters: mode, color, start distance, end distance and density (for exp models)
+ virtual void GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density) = 0;
+
+ //! Sets the current cull mode
+ virtual void SetCullMode(Gfx::CullMode mode) = 0;
+ //! Returns the current cull mode
+ virtual Gfx::CullMode GetCullMode() = 0;
+
+ //! Sets the shade model
+ virtual void SetShadeModel(Gfx::ShadeModel model) = 0;
+ //! Returns the current shade model
+ virtual Gfx::ShadeModel GetShadeModel() = 0;
+
+ //! Sets the current fill mode
+ virtual void SetFillMode(Gfx::FillMode mode) = 0;
+ //! Returns the current fill mode
+ virtual Gfx::FillMode GetFillMode() = 0;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/core/light.h b/src/graphics/core/light.h
new file mode 100644
index 0000000..b787cb2
--- /dev/null
+++ b/src/graphics/core/light.h
@@ -0,0 +1,91 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// light.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "math/vector.h"
+
+
+namespace Gfx {
+
+/**
+ \enum LightType
+ \brief Type of light in 3D scene */
+enum LightType
+{
+ LIGHT_POINT,
+ LIGHT_SPOT,
+ LIGHT_DIRECTIONAL
+};
+
+/**
+ \struct Light
+ \brief Properties of light in 3D scene
+
+ This structure was created as analog to DirectX's D3DLIGHT. */
+struct Light
+{
+ //! Type of light source
+ Gfx::LightType type;
+ //! Color of ambient light
+ Gfx::Color ambient;
+ //! Color of diffuse light
+ Gfx::Color diffuse;
+ //! Color of specular light
+ Gfx::Color specular;
+ //! Position in world space (for point & spot lights)
+ Math::Vector position;
+ //! Direction in world space (for directional & spot lights)
+ Math::Vector direction;
+ //! Constant attenuation factor
+ float attenuation0;
+ //! Linear attenuation factor
+ float attenuation1;
+ //! Quadratic attenuation factor
+ float attenuation2;
+ //! Angle of spotlight cone (0-90 degrees)
+ float spotAngle;
+ //! Intensity of spotlight (0 = uniform; 128 = most intense)
+ float spotIntensity;
+
+ //! Constructor; calls LoadDefault()
+ Light()
+ {
+ LoadDefault();
+ }
+
+ //! Loads default values
+ void LoadDefault()
+ {
+ type = LIGHT_POINT;
+ ambient = Gfx::Color(0.4f, 0.4f, 0.4f);
+ diffuse = Gfx::Color(0.8f, 0.8f, 0.8f);
+ specular = Gfx::Color(1.0f, 1.0f, 1.0f);
+ position = Math::Vector(0.0f, 0.0f, 0.0f);
+ direction = Math::Vector(0.0f, 0.0f, 1.0f);
+ attenuation0 = 1.0f;
+ attenuation1 = attenuation2 = 0.0f;
+ spotAngle = 90.0f;
+ spotIntensity = 0.0f;
+ }
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/material.h b/src/graphics/core/material.h
index f71923f..31b42f3 100644
--- a/src/graphics/common/material.h
+++ b/src/graphics/core/material.h
@@ -19,6 +19,9 @@
#pragma once
+#include "graphics/core/color.h"
+
+
namespace Gfx {
/**
diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h
new file mode 100644
index 0000000..8d6b082
--- /dev/null
+++ b/src/graphics/core/texture.h
@@ -0,0 +1,237 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// texture.h
+
+#pragma once
+
+#include "math/intsize.h"
+
+
+namespace Gfx {
+
+/**
+ \enum TexImgFormat
+ \brief Format of image data */
+enum TexImgFormat
+{
+ //! Try to determine automatically (may not work)
+ TEX_IMG_AUTO,
+ //! RGB triplet, 3 bytes
+ TEX_IMG_RGB,
+ //! BGR triplet, 3 bytes
+ TEX_IMG_BGR,
+ //! RGBA triplet, 4 bytes
+ TEX_IMG_RGBA,
+ //! BGRA triplet, 4 bytes
+ TEX_IMG_BGRA
+};
+
+/**
+ \enum TexMinFilter
+ \brief Texture minification filter
+
+ Corresponds to OpenGL modes but should translate to DirectX too. */
+enum TexMinFilter
+{
+ TEX_MIN_FILTER_NEAREST,
+ TEX_MIN_FILTER_LINEAR,
+ TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST,
+ TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST,
+ TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR,
+ TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR
+};
+
+/**
+ \enum TexMagFilter
+ \brief Texture magnification filter */
+enum TexMagFilter
+{
+ TEX_MAG_FILTER_NEAREST,
+ TEX_MAG_FILTER_LINEAR
+};
+
+/**
+ \enum TexWrapMode
+ \brief Wrapping mode for texture coords */
+enum TexWrapMode
+{
+ TEX_WRAP_CLAMP,
+ TEX_WRAP_REPEAT
+};
+
+/**
+ \enum TexMixOperation
+ \brief Multitexture mixing operation */
+enum TexMixOperation
+{
+ //! Default operation on default params (modulate on computed & texture)
+ TEX_MIX_OPER_DEFAULT,
+ //! = Arg1
+ TEX_MIX_OPER_REPLACE,
+ //! = Arg1 * Arg2
+ TEX_MIX_OPER_MODULATE,
+ //! = Arg1 + Arg2
+ TEX_MIX_OPER_ADD,
+ //! = Arg1 - Arg2
+ TEX_MIX_OPER_SUBTRACT
+};
+
+/**
+ \enum TexMixArgument
+ \brief Multitexture mixing argument */
+enum TexMixArgument
+{
+ //! Color from current texture
+ TEX_MIX_ARG_TEXTURE,
+ //! Color computed by previous texture unit (current in DirectX; previous in OpenGL)
+ TEX_MIX_ARG_COMPUTED_COLOR,
+ //! (Source) color of textured fragment (diffuse in DirectX; primary color in OpenGL)
+ TEX_MIX_ARG_SRC_COLOR,
+ //! Constant color (texture factor in DirectX; texture env color in OpenGL)
+ TEX_MIX_ARG_FACTOR
+};
+
+/**
+ \struct TextureCreateParams
+ \brief Parameters for texture creation
+
+ These params define how particular texture is created and later displayed.
+ They must be specified at texture creation time and cannot be changed later. */
+struct TextureCreateParams
+{
+ //! Whether to generate mipmaps
+ bool mipmap;
+ //! Format of source image data
+ Gfx::TexImgFormat format;
+ //! Minification filter
+ Gfx::TexMinFilter minFilter;
+ //! Magnification filter
+ Gfx::TexMagFilter magFilter;
+
+ //! Constructor; calls LoadDefault()
+ TextureCreateParams()
+ { LoadDefault(); }
+
+ //! Loads the default values
+ inline void LoadDefault()
+ {
+ format = Gfx::TEX_IMG_RGB;
+ mipmap = false;
+
+ minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
+ magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+ }
+};
+
+/**
+ \struct TextureStageParams
+ \brief Parameters for a texture unit
+
+ These params define the behavior of texturing units (stages).
+ They can be changed freely and are feature of graphics engine, not any particular texture. */
+struct TextureStageParams
+{
+ //! Mixing operation done on color values
+ Gfx::TexMixOperation colorOperation;
+ //! 1st argument of color operations
+ Gfx::TexMixArgument colorArg1;
+ //! 2nd argument of color operations
+ Gfx::TexMixArgument colorArg2;
+ //! Mixing operation done on alpha values
+ Gfx::TexMixOperation alphaOperation;
+ //! 1st argument of alpha operations
+ Gfx::TexMixArgument alphaArg1;
+ //! 2nd argument of alpha operations
+ Gfx::TexMixArgument alphaArg2;
+ //! Wrap mode for 1st tex coord
+ Gfx::TexWrapMode wrapS;
+ //! Wrap mode for 2nd tex coord
+ Gfx::TexWrapMode wrapT;
+
+ //! Constructor; calls LoadDefault()
+ TextureStageParams()
+ { LoadDefault(); }
+
+ //! Loads the default values
+ inline void LoadDefault()
+ {
+ colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ colorArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE;
+
+ alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ alphaArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ alphaArg2 = Gfx::TEX_MIX_ARG_TEXTURE;
+
+ wrapS = wrapT = Gfx::TEX_WRAP_REPEAT;
+ }
+};
+
+/**
+ \struct Texture
+ \brief Info about a texture
+
+ Identifies (through id) a texture created in graphics engine.
+ Also contains some additional data. */
+struct Texture
+{
+ //! Whether the texture (ID) is valid
+ bool valid;
+ //! ID of the texture in graphics engine
+ unsigned int id;
+ //! Size of texture
+ Math::IntSize size;
+ //! Whether the texture has alpha channel
+ bool alpha;
+
+ Texture()
+ {
+ valid = false;
+ id = 0;
+ alpha = false;
+ }
+
+ //! Comparator for use in texture maps and sets
+ inline bool operator<(const Gfx::Texture &other) const
+ {
+ // Invalid textures are always "less than" every other texture
+
+ if ( (!valid) && (!other.valid) )
+ return false;
+
+ if (!valid)
+ return true;
+
+ if (!other.valid)
+ return false;
+
+ return id < other.id;
+ }
+
+ //! Comparator
+ inline bool operator==(const Gfx::Texture &other) const
+ {
+ if (valid != other.valid)
+ return false;
+ if ( (!valid) && (!other.valid) )
+ return true;
+
+ return id == other.id;
+ }
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h
new file mode 100644
index 0000000..b7fab1c
--- /dev/null
+++ b/src/graphics/core/vertex.h
@@ -0,0 +1,141 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// vertex.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "math/vector.h"
+#include "math/point.h"
+
+#include <sstream>
+
+namespace Gfx {
+
+/**
+ * \struct Vertex
+ * \brief Vertex of a primitive
+ *
+ * This structure was created as analog to DirectX's D3DVERTEX.
+ *
+ * It contains:
+ * - vertex coordinates (x,y,z) as Math::Vector,
+ * - normal coordinates (nx,ny,nz) as Math::Vector
+ * - texture coordinates (u,v) as Math::Point.
+ */
+struct Vertex
+{
+ Math::Vector coord;
+ Math::Vector normal;
+ Math::Point texCoord;
+
+ Vertex(Math::Vector aCoord = Math::Vector(),
+ Math::Vector aNormal = Math::Vector(),
+ Math::Point aTexCoord = Math::Point())
+ : coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
+
+
+ //! Returns a string "(c: [...], n: [...], tc: [...])"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(c: " << coord.ToString() << ", n: " << normal.ToString()
+ << ", tc: " << texCoord.ToString() << ")";
+ return s.str();
+ }
+};
+
+/**
+ * \struct VertexCol
+ * \brief Vertex with color information
+ *
+ * This structure was created as analog to DirectX's D3DLVERTEX.
+ *
+ * It contains:
+ * - vertex coordinates (x,y,z) as Math::Vector,
+ * - RGBA color as Gfx::Color,
+ * - RGBA specular color as Gfx::Color,
+ * - texture coordinates (u,v) as Math::Point.
+ */
+struct VertexCol
+{
+ Math::Vector coord;
+ Gfx::Color color;
+ Gfx::Color specular;
+ Math::Point texCoord;
+
+ VertexCol(Math::Vector aCoord = Math::Vector(),
+ Gfx::Color aColor = Gfx::Color(),
+ Gfx::Color aSpecular = Gfx::Color(),
+ Math::Point aTexCoord = Math::Point())
+ : coord(aCoord), color(aColor), specular(aSpecular), texCoord(aTexCoord) {}
+
+ //! Returns a string "(c: [...], col: [...], sp: [...], tc: [...])"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(c: " << coord.ToString() << ", col: " << color.ToString() << ", sp: "
+ << specular.ToString() << ", tc: " << texCoord.ToString() << ")";
+ return s.str();
+ }
+};
+
+
+/**
+ * \struct VertexTex2
+ * \brief Vertex with secondary texture coordinates
+ *
+ * In addition to fields from Gfx::Vector, it contains
+ * secondary texture coordinates (u2, v2) as Math::Point
+ */
+struct VertexTex2
+{
+ Math::Vector coord;
+ Math::Vector normal;
+ Math::Point texCoord;
+ Math::Point texCoord2;
+
+ VertexTex2(Math::Vector aCoord = Math::Vector(),
+ Math::Vector aNormal = Math::Vector(),
+ Math::Point aTexCoord = Math::Point(),
+ Math::Point aTexCoord2 = Math::Point())
+ : coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
+
+ //! Sets the fields from Gfx::Vertex with texCoord2 = (0,0)
+ void FromVertex(const Gfx::Vertex &v)
+ {
+ coord = v.coord;
+ normal = v.normal;
+ texCoord = v.texCoord;
+ texCoord2 = Math::Point();
+ }
+
+ //! Returns a string "(c: [...], n: [...], tc: [...], tc2: [...])"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "(c: " << coord.ToString() << ", n: " << normal.ToString()
+ << ", tc: " << texCoord.ToString() << ", tc2: " << texCoord2.ToString() << ")";
+ return s.str();
+ }
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/engine/README.txt b/src/graphics/engine/README.txt
new file mode 100644
index 0000000..308b601
--- /dev/null
+++ b/src/graphics/engine/README.txt
@@ -0,0 +1,8 @@
+src/graphics/engine
+
+Graphics engine
+
+CEngine class and various other classes implementing the main features
+of graphics engine from model loading to decorative particles
+
+Graphics operations are done on abstract interface from src/graphics/core
diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp
new file mode 100644
index 0000000..c7ca503
--- /dev/null
+++ b/src/graphics/engine/camera.cpp
@@ -0,0 +1,1664 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// camera.cpp
+
+#include "graphics/engine/camera.h"
+
+#include "common/iman.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/terrain.h"
+#include "graphics/engine/water.h"
+#include "math/const.h"
+#include "math/geometry.h"
+#include "object/object.h"
+#include "physics/physics.h"
+
+
+//! Changes the level of transparency of an object and objects transported (battery & cargo)
+void SetTransparency(CObject* obj, float value)
+{
+ obj->SetTransparency(value);
+
+ CObject *fret = obj->GetFret();
+ if (fret != NULL)
+ fret->SetTransparency(value);
+
+ fret = obj->GetPower();
+ if (fret != NULL)
+ fret->SetTransparency(value);
+}
+
+
+
+Gfx::CCamera::CCamera(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_CAMERA, this);
+
+ m_engine = static_cast<Gfx::CEngine*> ( m_iMan->SearchInstance(CLASS_ENGINE) );
+ m_terrain = static_cast<Gfx::CTerrain*>( m_iMan->SearchInstance(CLASS_TERRAIN) );
+ m_water = static_cast<Gfx::CWater*> ( m_iMan->SearchInstance(CLASS_WATER) );
+
+ m_type = Gfx::CAM_TYPE_FREE;
+ m_smooth = Gfx::CAM_SMOOTH_NORM;
+ m_cameraObj = 0;
+
+ m_eyeDistance = 10.0f;
+ m_initDelay = 0.0f;
+
+ m_actualEye = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_actualLookat = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_finalEye = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_finalLookat = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_normEye = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_normLookat = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_focus = 1.0f;
+
+ m_rightDown = false;
+ m_rightPosInit = Math::Point(0.5f, 0.5f);
+ m_rightPosCenter = Math::Point(0.5f, 0.5f);
+ m_rightPosMove = Math::Point(0.5f, 0.5f);
+
+ m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_directionH = 0.0f;
+ m_directionV = 0.0f;
+ m_heightEye = 20.0f;
+ m_heightLookat = 0.0f;
+ m_speed = 2.0f;
+
+ m_backDist = 0.0f;
+ m_backMin = 0.0f;
+ m_addDirectionH = 0.0f;
+ m_addDirectionV = 0.0f;
+ m_transparency = false;
+
+ m_fixDist = 0.0f;
+ m_fixDirectionH = 0.0f;
+ m_fixDirectionV = 0.0f;
+
+ m_visitGoal = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_visitDist = 0.0f;
+ m_visitTime = 0.0f;
+ m_visitType = Gfx::CAM_TYPE_NULL;
+ m_visitDirectionH = 0.0f;
+ m_visitDirectionV = 0.0f;
+
+ m_editHeight = 40.0f;
+
+ m_remotePan = 0.0f;
+ m_remoteZoom = 0.0f;
+
+ m_mouseDirH = 0.0f;
+ m_mouseDirV = 0.0f;
+ m_mouseMarging = 0.01f;
+
+ m_motorTurn = 0.0f;
+
+ m_centeringPhase = Gfx::CAM_PHASE_NULL;
+ m_centeringAngleH = 0.0f;
+ m_centeringAngleV = 0.0f;
+ m_centeringDist = 0.0f;
+ m_centeringCurrentH = 0.0f;
+ m_centeringCurrentV = 0.0f;
+ m_centeringTime = 0.0f;
+ m_centeringProgress = 0.0f;
+
+ m_effectType = Gfx::CAM_EFFECT_NULL;
+ m_effectPos = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_effectForce = 0.0f;
+ m_effectProgress = 0.0f;
+ m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f);
+
+ m_scriptEye = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_scriptLookat = Math::Vector(0.0f, 0.0f, 0.0f);
+
+ m_effect = true;
+ m_cameraScroll = true;
+ m_cameraInvertX = false;
+ m_cameraInvertY = false;
+}
+
+Gfx::CCamera::~CCamera()
+{
+}
+
+void Gfx::CCamera::SetEffect(bool enable)
+{
+ m_effect = enable;
+}
+
+void Gfx::CCamera::SetCameraScroll(bool scroll)
+{
+ m_cameraScroll = scroll;
+}
+
+void Gfx::CCamera::SetCameraInvertX(bool invert)
+{
+ m_cameraInvertX = invert;
+}
+
+void Gfx::CCamera::SetCameraInvertY(bool invert)
+{
+ m_cameraInvertY = invert;
+}
+
+float Gfx::CCamera::GetMotorTurn()
+{
+ if (m_type == Gfx::CAM_TYPE_BACK)
+ return m_motorTurn;
+ return 0.0f;
+}
+
+void Gfx::CCamera::Init(Math::Vector eye, Math::Vector lookat, float delay)
+{
+ m_initDelay = delay;
+
+ eye.y += m_terrain->GetFloorLevel(eye, true);
+ lookat.y += m_terrain->GetFloorLevel(lookat, true);
+
+ m_type = Gfx::CAM_TYPE_FREE;
+ m_eyePt = eye;
+
+ m_directionH = Math::RotateAngle(eye.x - lookat.x, eye.z - lookat.z) + Math::PI / 2.0f;
+ m_directionV = -Math::RotateAngle(Math::DistanceProjected(eye, lookat), eye.y - lookat.y);
+
+ m_eyeDistance = 10.0f;
+ m_heightLookat = 10.0f;
+ m_backDist = 30.0f;
+ m_backMin = 10.0f;
+ m_addDirectionH = 0.0f;
+ m_addDirectionV = -Math::PI*0.05f;
+ m_fixDist = 50.0f;
+ m_fixDirectionH = Math::PI*0.25f;
+ m_fixDirectionV = -Math::PI*0.10f;
+ m_centeringPhase = Gfx::CAM_PHASE_NULL;
+ m_actualEye = m_eyePt;
+ m_actualLookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
+ m_finalEye = m_actualEye;
+ m_finalLookat = m_actualLookat;
+ m_scriptEye = m_actualEye;
+ m_scriptLookat = m_actualLookat;
+ m_focus = 1.00f;
+ m_remotePan = 0.0f;
+ m_remoteZoom = 0.0f;
+
+ FlushEffect();
+ FlushOver();
+ SetType(Gfx::CAM_TYPE_FREE);
+}
+
+
+void Gfx::CCamera::SetObject(CObject* object)
+{
+ m_cameraObj = object;
+}
+
+CObject* Gfx::CCamera::GetObject()
+{
+ return m_cameraObj;
+}
+
+void Gfx::CCamera::SetType(CameraType type)
+{
+ m_remotePan = 0.0f;
+ m_remoteZoom = 0.0f;
+
+ if ( (m_type == Gfx::CAM_TYPE_BACK) && m_transparency )
+ {
+ for (int i = 0; i < 1000000; i++)
+ {
+ CObject* obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) );
+ if (obj == NULL)
+ break;
+
+ if (obj->GetTruck())
+ continue; // battery or cargo?
+
+ SetTransparency(obj, 0.0f); // opaque object
+ }
+ }
+ m_transparency = false;
+
+ if (type == Gfx::CAM_TYPE_INFO ||
+ type == Gfx::CAM_TYPE_VISIT) // xx -> info ?
+ {
+ m_normEye = m_engine->GetEyePt();
+ m_normLookat = m_engine->GetLookatPt();
+
+ m_engine->SetFocus(1.00f); // normal
+ m_type = type;
+ return;
+ }
+
+ if (m_type == Gfx::CAM_TYPE_INFO ||
+ m_type == Gfx::CAM_TYPE_VISIT) // info -> xx ?
+ {
+ m_engine->SetFocus(m_focus); // gives initial focus
+ m_type = type;
+
+ Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f);
+ SetViewParams(m_normEye, m_normLookat, upVec);
+ return;
+ }
+
+ if ( m_type == Gfx::CAM_TYPE_BACK && type == Gfx::CAM_TYPE_FREE ) // back -> free ?
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f);
+
+ if ( m_type == Gfx::CAM_TYPE_BACK && type == Gfx::CAM_TYPE_EDIT ) // back -> edit ?
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f);
+
+ if ( m_type == Gfx::CAM_TYPE_ONBOARD && type == Gfx::CAM_TYPE_FREE ) // onboard -> free ?
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f);
+
+ if ( m_type == Gfx::CAM_TYPE_ONBOARD && type == Gfx::CAM_TYPE_EDIT ) // onboard -> edit ?
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f);
+
+ if ( m_type == Gfx::CAM_TYPE_ONBOARD && type == Gfx::CAM_TYPE_EXPLO ) // onboard -> explo ?
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f);
+
+ if ( m_type == Gfx::CAM_TYPE_BACK && type == Gfx::CAM_TYPE_EXPLO ) // back -> explo ?
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f);
+
+ if ( type == Gfx::CAM_TYPE_FIX ||
+ type == Gfx::CAM_TYPE_PLANE )
+ AbortCentering(); // Special stops framing
+
+ m_fixDist = 50.0f;
+ if ( type == Gfx::CAM_TYPE_PLANE )
+ m_fixDist = 60.0f;
+
+ if ( type == Gfx::CAM_TYPE_BACK )
+ {
+ AbortCentering(); // Special stops framing
+ m_addDirectionH = 0.0f;
+ m_addDirectionV = -Math::PI*0.05f;
+
+ ObjectType oType;
+ if ( m_cameraObj == 0 ) oType = OBJECT_NULL;
+ else oType = m_cameraObj->GetType();
+
+ m_backDist = 30.0f;
+ if ( oType == OBJECT_BASE ) m_backDist = 200.0f;
+ if ( oType == OBJECT_HUMAN ) m_backDist = 20.0f;
+ if ( oType == OBJECT_TECH ) m_backDist = 20.0f;
+ if ( oType == OBJECT_FACTORY ) m_backDist = 50.0f;
+ if ( oType == OBJECT_RESEARCH ) m_backDist = 40.0f;
+ if ( oType == OBJECT_DERRICK ) m_backDist = 40.0f;
+ if ( oType == OBJECT_REPAIR ) m_backDist = 35.0f;
+ if ( oType == OBJECT_DESTROYER) m_backDist = 35.0f;
+ if ( oType == OBJECT_TOWER ) m_backDist = 45.0f;
+ if ( oType == OBJECT_NUCLEAR ) m_backDist = 70.0f;
+ if ( oType == OBJECT_PARA ) m_backDist = 180.0f;
+ if ( oType == OBJECT_SAFE ) m_backDist = 50.0f;
+ if ( oType == OBJECT_HUSTON ) m_backDist = 120.0f;
+
+ m_backMin = m_backDist/3.0f;
+ if ( oType == OBJECT_HUMAN ) m_backMin = 10.0f;
+ if ( oType == OBJECT_TECH ) m_backMin = 10.0f;
+ if ( oType == OBJECT_FACTORY ) m_backMin = 30.0f;
+ if ( oType == OBJECT_RESEARCH ) m_backMin = 20.0f;
+ if ( oType == OBJECT_NUCLEAR ) m_backMin = 32.0f;
+ if ( oType == OBJECT_PARA ) m_backMin = 40.0f;
+ if ( oType == OBJECT_SAFE ) m_backMin = 25.0f;
+ if ( oType == OBJECT_HUSTON ) m_backMin = 80.0f;
+ }
+
+ if ( type != Gfx::CAM_TYPE_ONBOARD && m_cameraObj != 0 )
+ m_cameraObj->SetGunGoalH(0.0f); // puts the cannon right
+
+ if ( type == Gfx::CAM_TYPE_ONBOARD )
+ m_focus = 1.50f; // Wide
+ else
+ m_focus = 1.00f; // normal
+ m_engine->SetFocus(m_focus);
+
+ m_type = type;
+
+ SetSmooth(Gfx::CAM_SMOOTH_NORM);
+}
+
+CameraType Gfx::CCamera::GetType()
+{
+ return m_type;
+}
+
+void Gfx::CCamera::SetSmooth(CameraSmooth type)
+{
+ m_smooth = type;
+}
+
+CameraSmooth Gfx::CCamera::GetSmoth()
+{
+ return m_smooth;
+}
+
+void Gfx::CCamera::SetDist(float dist)
+{
+ m_fixDist = dist;
+}
+
+float Gfx::CCamera::GetDist()
+{
+ return m_fixDist;
+}
+
+void Gfx::CCamera::SetFixDirection(float angle)
+{
+ m_fixDirectionH = angle;
+}
+
+float Gfx::CCamera::GetFixDirection()
+{
+ return m_fixDirectionH;
+}
+
+void Gfx::CCamera::SetRemotePan(float value)
+{
+ m_remotePan = value;
+}
+
+float Gfx::CCamera::GetRemotePan()
+{
+ return m_remotePan;
+}
+
+void Gfx::CCamera::SetRemoteZoom(float value)
+{
+ value = Math::Norm(value);
+
+ if ( m_type == Gfx::CAM_TYPE_BACK )
+ m_backDist = m_backMin + (200.0f - m_backMin) * value;
+
+ if ( m_type == Gfx::CAM_TYPE_FIX ||
+ m_type == Gfx::CAM_TYPE_PLANE )
+ m_fixDist = 10.0f + (200.0f - 10.0f) * value;
+}
+
+float Gfx::CCamera::GetRemoteZoom()
+{
+ if ( m_type == Gfx::CAM_TYPE_BACK )
+ return (m_backDist - m_backMin) / (200.0f - m_backMin);
+
+ if ( m_type == Gfx::CAM_TYPE_FIX ||
+ m_type == Gfx::CAM_TYPE_PLANE )
+ return (m_fixDist - 10.0f) / (200.0f - 10.0f);
+
+ return 0.0f;
+}
+
+void Gfx::CCamera::StartVisit(Math::Vector goal, float dist)
+{
+ m_visitType = m_type;
+ SetType(Gfx::CAM_TYPE_VISIT);
+ m_visitGoal = goal;
+ m_visitDist = dist;
+ m_visitTime = 0.0f;
+ m_visitDirectionH = 0.0f;
+ m_visitDirectionV = -Math::PI*0.10f;
+}
+
+void Gfx::CCamera::StopVisit()
+{
+ SetType(m_visitType); // presents the initial type
+}
+
+void Gfx::CCamera::GetCamera(Math::Vector &eye, Math::Vector &lookat)
+{
+ eye = m_eyePt;
+ lookat = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
+}
+
+bool Gfx::CCamera::StartCentering(CObject *object, float angleH, float angleV,
+ float dist, float time)
+{
+ if (m_type != Gfx::CAM_TYPE_BACK)
+ return false;
+ if (object != m_cameraObj)
+ return false;
+
+ if (m_centeringPhase != Gfx::CAM_PHASE_NULL)
+ return false;
+
+ if (m_addDirectionH > Math::PI)
+ angleH = Math::PI * 2.0f - angleH;
+
+ m_centeringPhase = Gfx::CAM_PHASE_START;
+ m_centeringAngleH = angleH;
+ m_centeringAngleV = angleV;
+ m_centeringDist = dist;
+ m_centeringCurrentH = 0.0f;
+ m_centeringCurrentV = 0.0f;
+ m_centeringTime = time;
+ m_centeringProgress = 0.0f;
+
+ return true;
+}
+
+bool Gfx::CCamera::StopCentering(CObject *object, float time)
+{
+ if (m_type != Gfx::CAM_TYPE_BACK)
+ return false;
+ if (object != m_cameraObj)
+ return false;
+
+ if (m_centeringPhase != Gfx::CAM_PHASE_START &&
+ m_centeringPhase != Gfx::CAM_PHASE_WAIT)
+ return false;
+
+ m_centeringPhase = Gfx::CAM_PHASE_STOP;
+
+ if (m_centeringAngleH != 99.9f)
+ m_centeringAngleH = m_centeringCurrentH;
+
+ if (m_centeringAngleV != 99.9f)
+ m_centeringAngleV = m_centeringCurrentV;
+
+ m_centeringTime = time;
+ m_centeringProgress = 0.0f;
+
+ return true;
+}
+
+void Gfx::CCamera::AbortCentering()
+{
+ if (m_type == Gfx::CAM_TYPE_INFO ||
+ m_type == Gfx::CAM_TYPE_VISIT )
+ return;
+
+ if (m_centeringPhase == Gfx::CAM_PHASE_NULL)
+ return;
+
+ m_centeringPhase = Gfx::CAM_PHASE_NULL;
+
+ if ( m_centeringAngleH != 99.9f )
+ m_addDirectionH = m_centeringCurrentH;
+
+ if (m_centeringAngleV != 99.9f)
+ m_addDirectionV = m_centeringCurrentV;
+}
+
+void Gfx::CCamera::FlushEffect()
+{
+ m_effectType = Gfx::CAM_EFFECT_NULL;
+ m_effectForce = 0.0f;
+ m_effectProgress = 0.0f;
+ m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f);
+}
+
+void Gfx::CCamera::StartEffect(CameraEffect effect, Math::Vector pos, float force)
+{
+ if ( !m_effect ) return;
+
+ m_effectType = effect;
+ m_effectPos = pos;
+ m_effectForce = force;
+ m_effectProgress = 0.0f;
+}
+
+void Gfx::CCamera::EffectFrame(const Event &event)
+{
+ if (m_type == Gfx::CAM_TYPE_INFO ||
+ m_type == Gfx::CAM_TYPE_VISIT)
+ return;
+
+ if (m_effectType == Gfx::CAM_EFFECT_NULL)
+ return;
+
+ m_effectOffset = Math::Vector(0.0f, 0.0f, 0.0f);
+
+ float force = m_effectForce;
+
+ if ( m_effectType == Gfx::CAM_EFFECT_TERRAFORM )
+ {
+ m_effectProgress += event.rTime * 0.7f;
+ m_effectOffset.x = (Math::Rand() - 0.5f) * 10.0f;
+ m_effectOffset.y = (Math::Rand() - 0.5f) * 10.0f;
+ m_effectOffset.z = (Math::Rand() - 0.5f) * 10.0f;
+
+ force *= 1.0f-m_effectProgress;
+ }
+
+ if ( m_effectType == Gfx::CAM_EFFECT_EXPLO )
+ {
+ m_effectProgress += event.rTime * 1.0f;
+ m_effectOffset.x = (Math::Rand() - 0.5f) *5.0f;
+ m_effectOffset.y = (Math::Rand() - 0.5f) * 5.0f;
+ m_effectOffset.z = (Math::Rand() - 0.5f) * 5.0f;
+
+ force *= 1.0f-m_effectProgress;
+ }
+
+ if ( m_effectType == Gfx::CAM_EFFECT_SHOT )
+ {
+ m_effectProgress += event.rTime * 1.0f;
+ m_effectOffset.x = (Math::Rand() - 0.5f) * 2.0f;
+ m_effectOffset.y = (Math::Rand() - 0.5f) * 2.0f;
+ m_effectOffset.z = (Math::Rand() - 0.5f) * 2.0f;
+
+ force *= 1.0f-m_effectProgress;
+ }
+
+ if ( m_effectType == Gfx::CAM_EFFECT_CRASH )
+ {
+ m_effectProgress += event.rTime * 5.0f;
+ m_effectOffset.y = sinf(m_effectProgress * Math::PI) * 1.5f;
+ m_effectOffset.x = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress);
+ m_effectOffset.z = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress);
+ }
+
+ if ( m_effectType == Gfx::CAM_EFFECT_VIBRATION )
+ {
+ m_effectProgress += event.rTime * 0.1f;
+ m_effectOffset.y = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress);
+ m_effectOffset.x = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress);
+ m_effectOffset.z = (Math::Rand() - 0.5f) * 1.0f * (1.0f - m_effectProgress);
+ }
+
+ if ( m_effectType == Gfx::CAM_EFFECT_PET )
+ {
+ m_effectProgress += event.rTime *5.0f;
+ m_effectOffset.x = (Math::Rand() - 0.5f) * 0.2f;
+ m_effectOffset.y = (Math::Rand() - 0.5f) * 2.0f;
+ m_effectOffset.z = (Math::Rand() - 0.5f) * 0.2f;
+ }
+
+ float dist = Math::Distance(m_eyePt, m_effectPos);
+ dist = Math::Norm((dist - 100.f) / 100.0f);
+
+ force *= 1.0f-dist;
+#if _TEEN
+ force *= 2.0f;
+#endif
+ m_effectOffset *= force;
+
+ if (m_effectProgress >= 1.0f)
+ FlushEffect();
+}
+
+void Gfx::CCamera::FlushOver()
+{
+ m_overType = Gfx::CAM_OVER_EFFECT_NULL;
+ m_overColorBase = Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f); // black
+ m_engine->SetOverColor(); // nothing
+}
+
+void Gfx::CCamera::SetOverBaseColor(Gfx::Color color)
+{
+ m_overColorBase = color;
+}
+
+void Gfx::CCamera::StartOver(Gfx::CameraOverEffect effect, Math::Vector pos, float force)
+{
+ m_overType = effect;
+ m_overTime = 0.0f;
+
+ float decay;
+ if (m_overType == Gfx::CAM_OVER_EFFECT_LIGHTNING)
+ decay = 400.0f;
+ else
+ decay = 100.0f;
+
+ float dist = Math::Distance(m_eyePt, pos);
+ dist = (dist - decay) / decay;
+ if (dist < 0.0f) dist = 0.0f;
+ if (dist > 1.0f) dist = 1.0f;
+
+ m_overForce = force * (1.0f - dist);
+
+ if (m_overType == Gfx::CAM_OVER_EFFECT_BLOOD)
+ {
+ m_overColor = Gfx::Color(0.8f, 0.1f, 0.1f); // red
+ m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK;
+
+ m_overFadeIn = 0.4f;
+ m_overFadeOut = 0.8f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == Gfx::CAM_OVER_EFFECT_FADEIN_WHITE )
+ {
+ m_overColor = Gfx::Color(1.0f, 1.0f, 1.0f); // white
+ m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK;
+
+ m_overFadeIn = 0.0f;
+ m_overFadeOut = 20.0f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == Gfx::CAM_OVER_EFFECT_FADEOUT_WHITE )
+ {
+ m_overColor = Gfx::Color(1.0f, 1.0f, 1.0f); // white
+ m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK;
+
+ m_overFadeIn = 6.0f;
+ m_overFadeOut = 100000.0f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == Gfx::CAM_OVER_EFFECT_FADEOUT_BLACK )
+ {
+ m_overColor = m_engine->GetFogColor(1); // fog color underwater
+ m_overMode = Gfx::ENG_RSTATE_TTEXTURE_WHITE;
+
+ m_overFadeIn = 4.0f;
+ m_overFadeOut = 100000.0f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == Gfx::CAM_OVER_EFFECT_LIGHTNING )
+ {
+ m_overColor = Gfx::Color(0.9f, 1.0f, 1.0f); // white-cyan
+ m_overMode = Gfx::ENG_RSTATE_TCOLOR_BLACK;
+
+ m_overFadeIn = 0.0f;
+ m_overFadeOut = 1.0f;
+ }
+}
+
+void Gfx::CCamera::OverFrame(const Event &event)
+{
+ if (m_type == Gfx::CAM_TYPE_INFO ||
+ m_type == Gfx::CAM_TYPE_VISIT)
+ return;
+
+ if (m_overType == Gfx::CAM_OVER_EFFECT_NULL)
+ return;
+
+ m_overTime += event.rTime;
+
+ if (m_overType == Gfx::CAM_OVER_EFFECT_LIGHTNING)
+ {
+ Gfx::Color color;
+ if (rand() % 2 == 0)
+ {
+ color.r = m_overColor.r * m_overForce;
+ color.g = m_overColor.g * m_overForce;
+ color.b = m_overColor.b * m_overForce;
+ }
+ else
+ {
+ color = Gfx::Color(0.0f. 0.0f, 0.0f);
+ }
+ color.a = 0.0f;
+ m_engine->SetOverColor(color, m_overMode);
+ }
+ else
+ {
+ if ( (m_overFadeIn > 0.0f) && (m_overTime < m_overFadeIn) )
+ {
+ float intensity = m_overTime / m_overFadeIn;
+ intensity *= m_overForce;
+
+ Gfx::Color color;
+ if (m_overMode == Gfx::ENG_RSTATE_TCOLOR_WHITE)
+ {
+ color.r = 1.0f - (1.0f - m_overColor.r) * intensity;
+ color.g = 1.0f - (1.0f - m_overColor.g) * intensity;
+ color.b = 1.0f - (1.0f - m_overColor.b) * intensity;
+ }
+ else
+ {
+ color.r = m_overColor.r * intensity;
+ color.g = m_overColor.g * intensity;
+ color.b = m_overColor.b * intensity;
+
+ color.r = 1.0f - (1.0f - color.r) * (1.0f - m_overColorBase.r);
+ color.g = 1.0f - (1.0f - color.g) * (1.0f - m_overColorBase.g);
+ color.b = 1.0f - (1.0f - color.b) * (1.0f - m_overColorBase.b);
+ }
+ color.a = 0.0f;
+ m_engine->SetOverColor(color, m_overMode);
+ }
+ else if ( (m_overFadeOut > 0.0f) && (m_overTime - m_overFadeIn < m_overFadeOut) )
+ {
+ float intensity = 1.0f - (m_overTime - m_overFadeIn) / m_overFadeOut;
+ intensity *= m_overForce;
+
+ Gfx::Color color;
+ if (m_overMode == Gfx::ENG_RSTATE_TCOLOR_WHITE)
+ {
+ color.r = 1.0f-(1.0f-m_overColor.r) * intensity;
+ color.g = 1.0f-(1.0f-m_overColor.g) * intensity;
+ color.b = 1.0f-(1.0f-m_overColor.b) * intensity;
+ }
+ else
+ {
+ color.r = m_overColor.r * intensity;
+ color.g = m_overColor.g * intensity;
+ color.b = m_overColor.b * intensity;
+
+ color.r = 1.0f - (1.0f - color.r)*(1.0f - m_overColorBase.r);
+ color.g = 1.0f - (1.0f - color.g)*(1.0f - m_overColorBase.g);
+ color.b = 1.0f - (1.0f - color.b)*(1.0f - m_overColorBase.b);
+ }
+ color.a = 0.0f;
+ m_engine->SetOverColor(color, m_overMode);
+ }
+ }
+
+ if ( m_overTime >= m_overFadeIn+m_overFadeOut )
+ {
+ FlushOver();
+ return;
+ }
+}
+
+void Gfx::CCamera::FixCamera()
+{
+ m_initDelay = 0.0f;
+ m_actualEye = m_finalEye = m_scriptEye;
+ m_actualLookat = m_finalLookat = m_scriptLookat;
+ SetViewTime(m_scriptEye, m_scriptLookat, 0.0f);
+}
+
+void Gfx::CCamera::SetViewTime(const Math::Vector &eyePt,
+ const Math::Vector &lookatPt,
+ float rTime)
+{
+ Math::Vector eye, lookat;
+
+ if (m_type == Gfx::CAM_TYPE_INFO)
+ {
+ eye = eyePt;
+ lookat = lookatPt;
+ }
+ else
+ {
+ if (m_initDelay > 0.0f)
+ {
+ m_initDelay -= rTime;
+ if (m_initDelay < 0.0f)
+ m_initDelay = 0.0f;
+ rTime /= 1.0f+m_initDelay;
+ }
+
+ eye = eyePt;
+ lookat = lookatPt;
+ if ( !IsCollision(eye, lookat) )
+ {
+ m_finalEye = eye;
+ m_finalLookat = lookat;
+ }
+
+ float prog = 0.0f;
+ float dist = Math::Distance(m_finalEye, m_actualEye);
+
+ if (m_smooth == Gfx::CAM_SMOOTH_NONE) prog = dist;
+ if (m_smooth == Gfx::CAM_SMOOTH_NORM) prog = powf(dist, 1.5f) * rTime * 0.5f;
+ if (m_smooth == Gfx::CAM_SMOOTH_HARD) prog = powf(dist, 1.0f) * rTime * 4.0f;
+ if (m_smooth == Gfx::CAM_SMOOTH_SPEC) prog = powf(dist, 1.0f) * rTime * 0.05f;
+ if (dist == 0.0f)
+ {
+ m_actualEye = m_finalEye;
+ }
+ else
+ {
+ if (prog > dist)
+ prog = dist;
+ m_actualEye = (m_finalEye - m_actualEye) / dist * prog + m_actualEye;
+ }
+
+ dist = Math::Distance(m_finalLookat, m_actualLookat);
+ if ( m_smooth == Gfx::CAM_SMOOTH_NONE ) prog = dist;
+ if ( m_smooth == Gfx::CAM_SMOOTH_NORM ) prog = powf(dist, 1.5f) * rTime * 2.0f;
+ if ( m_smooth == Gfx::CAM_SMOOTH_HARD ) prog = powf(dist, 1.0f) * rTime * 4.0f;
+ if ( m_smooth == Gfx::CAM_SMOOTH_SPEC ) prog = powf(dist, 1.0f) * rTime * 4.0f;
+ if ( dist == 0.0f )
+ {
+ m_actualLookat = m_finalLookat;
+ }
+ else
+ {
+ if (prog > dist)
+ prog = dist;
+ m_actualLookat = (m_finalLookat - m_actualLookat) / dist * prog + m_actualLookat;
+ }
+
+ eye = m_effectOffset+m_actualEye;
+ m_water->AdjustEye(eye);
+
+ float h = m_terrain->GetFloorLevel(eye);
+ if (eye.y < h + 4.0f)
+ eye.y = h + 4.0f;
+
+ lookat = m_effectOffset+m_actualLookat;
+ }
+
+ Math::Vector upVec = Math::Vector(0.0f, 1.0f, 0.0f);
+ SetViewParams(eye, lookat, upVec);
+}
+
+bool Gfx::CCamera::IsCollision(Math::Vector &eye, Math::Vector lookat)
+{
+ if (m_type == Gfx::CAM_TYPE_BACK ) return IsCollisionBack(eye, lookat);
+ if (m_type == Gfx::CAM_TYPE_FIX ) return IsCollisionFix (eye, lookat);
+ if (m_type == Gfx::CAM_TYPE_PLANE) return IsCollisionFix (eye, lookat);
+ return false;
+}
+
+bool Gfx::CCamera::IsCollisionBack(Math::Vector &eye, Math::Vector lookat)
+{
+ ObjectType iType;
+ if (m_cameraObj == NULL)
+ iType = OBJECT_NULL;
+ else
+ iType = m_cameraObj->GetType();
+
+ Math::Vector min;
+ min.x = Math::Min(m_actualEye.x, m_actualLookat.x);
+ min.y = Math::Min(m_actualEye.y, m_actualLookat.y);
+ min.z = Math::Min(m_actualEye.z, m_actualLookat.z);
+
+ Math::Vector max;
+ max.x = Math::Max(m_actualEye.x, m_actualLookat.x);
+ max.y = Math::Max(m_actualEye.y, m_actualLookat.y);
+ max.z = Math::Max(m_actualEye.z, m_actualLookat.z);
+
+ m_transparency = false;
+
+ for (int i = 0 ;i < 1000000; i++)
+ {
+ CObject *obj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if (obj == NULL) break;
+
+ if (obj->GetTruck()) continue; // battery or cargo?
+
+ SetTransparency(obj, 0.0f); // opaque object
+
+ if (obj == m_cameraObj) continue;
+
+ if ( iType == OBJECT_BASE || // building?
+ iType == OBJECT_DERRICK ||
+ iType == OBJECT_FACTORY ||
+ iType == OBJECT_STATION ||
+ iType == OBJECT_CONVERT ||
+ iType == OBJECT_REPAIR ||
+ iType == OBJECT_DESTROYER||
+ iType == OBJECT_TOWER ||
+ iType == OBJECT_RESEARCH ||
+ iType == OBJECT_RADAR ||
+ iType == OBJECT_ENERGY ||
+ iType == OBJECT_LABO ||
+ iType == OBJECT_NUCLEAR ||
+ iType == OBJECT_PARA ||
+ iType == OBJECT_SAFE ||
+ iType == OBJECT_HUSTON ) continue;
+
+ ObjType oType = obj->GetType();
+ if ( oType == OBJECT_HUMAN ||
+ oType == OBJECT_TECH ||
+ oType == OBJECT_TOTO ||
+ oType == OBJECT_FIX ||
+ oType == OBJECT_FRET ||
+ oType == OBJECT_ANT ||
+ oType == OBJECT_SPIDER ||
+ oType == OBJECT_BEE ||
+ oType == OBJECT_WORM ) continue;
+
+ Math::Vector oPos;
+ float oRadius = 0.0f;
+ obj->GetGlobalSphere(oPos, oRadius);
+ if ( oRadius <= 2.0f ) continue; // ignores small objects
+
+ if ( oPos.x+oRadius < min.x ||
+ oPos.y+oRadius < min.y ||
+ oPos.z+oRadius < min.z ||
+ oPos.x-oRadius > max.x ||
+ oPos.y-oRadius > max.y ||
+ oPos.z-oRadius > max.z ) continue;
+
+ Math::Vector proj = Projection(m_actualEye, m_actualLookat, oPos);
+ float dpp = Math::Distance(proj, oPos);
+ if ( dpp > oRadius ) continue;
+
+ if ( oType == OBJECT_FACTORY )
+ {
+ float angle = Math::RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW !
+ angle = Math::Direction(angle, obj->GetAngleY(0));
+ if ( fabs(angle) < 30.0f*Math::PI/180.0f ) continue; // in the gate?
+ }
+
+ float del = Math::Distance(m_actualEye, m_actualLookat);
+ if (oType == OBJECT_FACTORY)
+ del += oRadius;
+
+ float len = Math::Distance(m_actualEye, proj);
+ if (len > del) continue;
+
+ SetTransparency(obj, 1.0f); // transparent object
+ m_transparency = true;
+ }
+ return false;
+}
+
+bool Gfx::CCamera::IsCollisionFix(Math::Vector &eye, Math::Vector lookat)
+{
+ for (int i = 0; i < 1000000; i++)
+ {
+ CObject *obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) );
+ if (obj == NULL) break;
+
+ if (obj == m_cameraObj) continue;
+
+ ObjectType type = obj->GetType();
+ if ( type == OBJECT_TOTO ||
+ type == OBJECT_FRET ||
+ type == OBJECT_STONE ||
+ type == OBJECT_URANIUM ||
+ type == OBJECT_METAL ||
+ type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC ||
+ type == OBJECT_BULLET ||
+ type == OBJECT_BBOX ||
+ type == OBJECT_KEYa ||
+ type == OBJECT_KEYb ||
+ type == OBJECT_KEYc ||
+ type == OBJECT_KEYd ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ) continue;
+
+ Math::Vector objPos;
+ float objRadius = 0.0f;
+ obj->GetGlobalSphere(objPos, objRadius);
+ if (objRadius == 0.0f) continue;
+
+ float dist = Math::Distance(eye, objPos);
+ if (dist < objRadius)
+ {
+ dist = Math::Distance(eye, lookat);
+ Math::Vector proj = Projection(eye, lookat, objPos);
+ eye = (lookat - eye) * objRadius / dist + proj;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool Gfx::CCamera::EventProcess(const Event &event)
+{
+ switch (event.type)
+ {
+ // TODO: frame update event
+ case EVENT_FRAME:
+ EventFrame(event);
+ break;
+
+ case EVENT_MOUSE_MOVE:
+ EventMouseMove(event);
+ break;
+
+ case EVENT_KEY_DOWN:
+ // TODO: mouse wheel event
+ if ( event.param == VK_WHEELUP ) EventMouseWheel(+1);
+ if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1);
+ break;
+
+ default:
+ break;
+ }
+ return true;
+}
+
+bool Gfx::CCamera::EventMouseMove(const Event &event)
+{
+ m_mousePos = event.pos;
+ return true;
+}
+
+void Gfx::CCamera::EventMouseWheel(int dir)
+{
+ if (m_type == Gfx::CAM_TYPE_BACK)
+ {
+ if (dir > 0)
+ {
+ m_backDist -= 8.0f;
+ if (m_backDist < m_backMin)
+ m_backDist = m_backMin;
+ }
+ if (dir < 0)
+ {
+ m_backDist += 8.0f;
+ if (m_backDist > 200.0f)
+ m_backDist = 200.0f;
+ }
+ }
+
+ if ( m_type == Gfx::CAM_TYPE_FIX ||
+ m_type == Gfx::CAM_TYPE_PLANE )
+ {
+ if (dir > 0)
+ {
+ m_fixDist -= 8.0f;
+ if (m_fixDist < 10.0f)
+ m_fixDist = 10.0f;
+ }
+ if (dir < 0)
+ {
+ m_fixDist += 8.0f;
+ if (m_fixDist > 200.0f)
+ m_fixDist = 200.0f;
+ }
+ }
+
+ if ( m_type == Gfx::CAM_TYPE_VISIT )
+ {
+ if (dir > 0)
+ {
+ m_visitDist -= 8.0f;
+ if (m_visitDist < 20.0f)
+ m_visitDist = 20.0f;
+ }
+ if (dir < 0)
+ {
+ m_visitDist += 8.0f;
+ if (m_visitDist > 200.0f)
+ m_visitDist = 200.0f;
+ }
+ }
+}
+
+bool Gfx::CCamera::EventFrame(const Event &event)
+{
+ EffectFrame(event);
+ OverFrame(event);
+
+ if (m_type == Gfx::CAM_TYPE_FREE)
+ return EventFrameFree(event);
+
+ if (m_type == Gfx::CAM_TYPE_EDIT)
+ return EventFrameEdit(event);
+
+ if (m_type == Gfx::CAM_TYPE_DIALOG)
+ return EventFrameDialog(event);
+
+ if (m_type == Gfx::CAM_TYPE_BACK)
+ return EventFrameBack(event);
+
+ if (m_type == Gfx::CAM_TYPE_FIX ||
+ m_type == Gfx::CAM_TYPE_PLANE)
+ return EventFrameFix(event);
+
+ if (m_type == Gfx::CAM_TYPE_EXPLO)
+ return EventFrameExplo(event);
+
+ if (m_type == Gfx::CAM_TYPE_ONBOARD)
+ return EventFrameOnBoard(event);
+
+ if (m_type == Gfx::CAM_TYPE_SCRIPT)
+ return EventFrameScript(event);
+
+ if (m_type == Gfx::CAM_TYPE_INFO)
+ return EventFrameInfo(event);
+
+ if (m_type == Gfx::CAM_TYPE_VISIT)
+ return EventFrameVisit(event);
+
+ return true;
+}
+
+Gfx::EngineMouseType Gfx::CCamera::GetMouseDef(Math::Point pos)
+{
+ Gfx::EngineMouseType type = Gfx::ENG_MOUSE_NORM;
+ m_mousePos = pos;
+
+ if (m_type == Gfx::CAM_TYPE_INFO)
+ return type;
+
+ if (m_rightDown) // the right button pressed?
+ {
+ m_rightPosMove.x = pos.x - m_rightPosCenter.x;
+ m_rightPosMove.y = pos.y - m_rightPosCenter.y;
+ type = Gfx::ENG_MOUSE_MOVE;
+ }
+ else
+ {
+ if (!m_cameraScroll)
+ return type;
+
+ m_mouseDirH = 0.0f;
+ m_mouseDirV = 0.0f;
+
+ if (pos.x < m_mouseMarging)
+ m_mouseDirH = pos.x / m_mouseMarging - 1.0f;
+
+ if (pos.x > 1.0f - m_mouseMarging)
+ m_mouseDirH = 1.0f - (1.0f - pos.x) / m_mouseMarging;
+
+ if (pos.y < m_mouseMarging)
+ m_mouseDirV = pos.y / m_mouseMarging - 1.0f;
+
+ if (pos.y > 1.0f-m_mouseMarging)
+ m_mouseDirV = 1.0f - (1.0f - pos.y) / m_mouseMarging;
+
+ if ( m_type == Gfx::CAM_TYPE_FREE ||
+ m_type == Gfx::CAM_TYPE_EDIT ||
+ m_type == Gfx::CAM_TYPE_BACK ||
+ m_type == Gfx::CAM_TYPE_FIX ||
+ m_type == Gfx::CAM_TYPE_PLANE ||
+ m_type == Gfx::CAM_TYPE_EXPLO )
+ {
+ if (m_mouseDirH > 0.0f)
+ type = Gfx::ENG_MOUSE_SCROLLR;
+ if (m_mouseDirH < 0.0f)
+ type = Gfx::ENG_MOUSE_SCROLLL;
+ }
+
+ if ( m_type == Gfx::CAM_TYPE_FREE ||
+ m_type == Gfx::CAM_TYPE_EDIT )
+ {
+ if (m_mouseDirV > 0.0f)
+ type = Gfx::ENG_MOUSE_SCROLLU;
+ if (m_mouseDirV < 0.0f)
+ type = Gfx::ENG_MOUSE_SCROLLD;
+ }
+
+ if (m_cameraInvertX)
+ m_mouseDirH = -m_mouseDirH;
+ }
+
+ return type;
+}
+
+bool Gfx::CCamera::EventFrameFree(const Event &event)
+{
+ float factor = m_heightEye * 0.5f + 30.0f;
+
+ if ( m_mouseDirH != 0.0f )
+ m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
+ if ( m_mouseDirV != 0.0f )
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV * event.rTime * factor * m_speed);
+
+ // Up/Down
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, event.axeY * event.rTime * factor * m_speed);
+
+ // Left/Right
+ if ( event.keyState & KS_CONTROL )
+ {
+ if ( event.axeX < 0.0f )
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH + Math::PI / 2.0f, m_directionV, -event.axeX * event.rTime * factor * m_speed);
+ if ( event.axeX > 0.0f )
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH - Math::PI / 2.0f, m_directionV, event.axeX * event.rTime * factor * m_speed);
+ }
+ else
+ {
+ m_directionH -= event.axeX * event.rTime * 0.7f * m_speed;
+ }
+
+ // PageUp/PageDown
+ if ( event.keyState & KS_NUMMINUS )
+ {
+ if (m_heightEye < 500.0f)
+ m_heightEye += event.rTime * factor * m_speed;
+ }
+ if ( event.keyState & KS_NUMPLUS )
+ {
+ if (m_heightEye > -2.0f)
+ m_heightEye -= event.rTime * factor * m_speed;
+ }
+
+ m_terrain->ValidPosition(m_eyePt, 10.0f);
+
+ if (m_terrain->MoveOnFloor(m_eyePt, true))
+ {
+ m_eyePt.y += m_heightEye;
+
+ Math::Vector pos = m_eyePt;
+ if (m_terrain->MoveOnFloor(pos, true))
+ {
+ pos.y -= 2.0f;
+ if (m_eyePt.y < pos.y)
+ m_eyePt.y = pos.y;
+ }
+
+ }
+
+ Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
+
+ if (m_terrain->MoveOnFloor(lookatPt, true))
+ lookatPt.y += m_heightLookat;
+
+ SetViewTime(m_eyePt, lookatPt, event.rTime);
+
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameEdit(const Event &event)
+{
+ float factor = m_editHeight * 0.5f + 30.0f;
+
+ if (m_mouseDirH != 0.0f)
+ m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
+ if (m_mouseDirV != 0.0f)
+ m_eyePt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV * event.rTime * factor * m_speed);
+
+ if (m_cameraScroll)
+ {
+ // Left/Right.
+ m_fixDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed;
+ m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
+ }
+
+ m_terrain->ValidPosition(m_eyePt, 10.0f);
+
+ if (m_terrain->MoveOnFloor(m_eyePt, false))
+ {
+ m_eyePt.y += m_editHeight;
+
+ Math::Vector pos = m_eyePt;
+ if (m_terrain->MoveOnFloor(pos, false))
+ {
+ pos.y += 2.0f;
+ if (m_eyePt.y < pos.y)
+ m_eyePt.y = pos.y;
+ }
+
+ }
+
+ Math::Vector lookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
+
+ if ( m_terrain->MoveOnFloor(lookatPt, true))
+ lookatPt.y += m_heightLookat;
+
+ SetViewTime(m_eyePt, lookatPt, event.rTime);
+
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameDialog(const Event &event)
+{
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameBack(const Event &event)
+{
+ ObjectType type;
+ if (m_cameraObj == NULL)
+ type = OBJECT_NULL;
+ else
+ type = m_cameraObj->GetType();
+
+ // +/-.
+ if (event.keyState & KS_NUMPLUS)
+ {
+ m_backDist -= event.rTime * 30.0f * m_speed;
+ if (m_backDist < m_backMin) m_backDist = m_backMin;
+ }
+ if (event.keyState & KS_NUMMINUS)
+ {
+ m_backDist += event.rTime * 30.0f * m_speed;
+ if (m_backDist > 200.0f) m_backDist = 200.0f;
+ }
+
+ m_motorTurn = 0.0f;
+
+ if (m_rightDown)
+ {
+ m_addDirectionH = m_rightPosMove.x * 6.0f;
+ m_addDirectionV = -m_rightPosMove.y * 2.0f;
+ }
+ else
+ {
+ if (m_cameraScroll)
+ {
+ // Left/Right
+ m_addDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed;
+ m_addDirectionH = Math::NormAngle(m_addDirectionH);
+ }
+ }
+
+ if ((m_mouseDirH != 0) || (m_mouseDirV != 0))
+ AbortCentering(); // special stops framing
+
+ // Increase the special framework
+ float centeringH = 0.0f;
+ float centeringV = 0.0f;
+ float centeringD = 0.0f;
+
+ if (m_centeringPhase == Gfx::CAM_PHASE_START)
+ {
+ m_centeringProgress += event.rTime / m_centeringTime;
+ if (m_centeringProgress > 1.0f) m_centeringProgress = 1.0f;
+ centeringH = m_centeringProgress;
+ centeringV = m_centeringProgress;
+ centeringD = m_centeringProgress;
+ if (m_centeringProgress >= 1.0f)
+ m_centeringPhase = Gfx::CAM_PHASE_WAIT;
+ }
+
+ if (m_centeringPhase == Gfx::CAM_PHASE_WAIT)
+ {
+ centeringH = 1.0f;
+ centeringV = 1.0f;
+ centeringD = 1.0f;
+ }
+
+ if (m_centeringPhase == Gfx::CAM_PHASE_STOP)
+ {
+ m_centeringProgress += event.rTime / m_centeringTime;
+ if (m_centeringProgress > 1.0f) m_centeringProgress = 1.0f;
+ centeringH = 1.0f-m_centeringProgress;
+ centeringV = 1.0f-m_centeringProgress;
+ centeringD = 1.0f-m_centeringProgress;
+ if (m_centeringProgress >= 1.0f)
+ m_centeringPhase = Gfx::CAM_PHASE_NULL;
+ }
+
+ if (m_centeringAngleH == 99.9f) centeringH = 0.0f;
+ if (m_centeringAngleV == 99.9f) centeringV = 0.0f;
+ if (m_centeringDist == 0.0f) centeringD = 0.0f;
+
+ if (m_cameraObj != NULL)
+ {
+ Math::Vector lookatPt = m_cameraObj->GetPosition(0);
+ if (type == OBJECT_BASE ) lookatPt.y += 40.0f;
+ else if (type == OBJECT_HUMAN) lookatPt.y += 1.0f;
+ else if (type == OBJECT_TECH ) lookatPt.y += 1.0f;
+ else lookatPt.y += 4.0f;
+
+ float h = -m_cameraObj->GetAngleY(0); // angle vehicle / building
+
+ if ( type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH ||
+ type == OBJECT_RADAR ||
+ type == OBJECT_INFO ||
+ type == OBJECT_ENERGY ||
+ type == OBJECT_LABO ||
+ type == OBJECT_NUCLEAR ||
+ type == OBJECT_PARA ||
+ type == OBJECT_SAFE ||
+ type == OBJECT_HUSTON ||
+ type == OBJECT_START ||
+ type == OBJECT_END ) // building?
+ {
+ h += Math::PI * 0.20f; // nearly face
+ }
+ else // vehicle?
+ {
+ h += Math::PI; // back
+ }
+ h = Math::NormAngle(h)+m_remotePan;
+ float v = 0.0f; //?
+
+ h += m_centeringCurrentH;
+ h += m_addDirectionH * (1.0f - centeringH);
+ h = Math::NormAngle(h);
+
+ if (type == OBJECT_MOBILEdr) // designer?
+ v -= 0.3f; // Camera top
+
+ v += m_centeringCurrentV;
+ v += m_addDirectionV * (1.0f - centeringV);
+
+ float d = m_backDist;
+ d += m_centeringDist * centeringD;
+
+ m_centeringCurrentH = m_centeringAngleH * centeringH;
+ m_centeringCurrentV = m_centeringAngleV * centeringV;
+
+ m_eyePt = RotateView(lookatPt, h, v, d);
+
+ CPhysics* physics = m_cameraObj->GetPhysics();
+ if ( (physics != NULL) && physics->GetLand() ) // ground?
+ {
+ Math::Vector pos = lookatPt + (lookatPt - m_eyePt);
+ float floor = m_terrain->GetFloorHeight(pos) - 4.0f;
+ if (floor > 0.0f)
+ m_eyePt.y += floor; // shows the descent in front
+ }
+
+ m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v);
+ m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v);
+
+ SetViewTime(m_eyePt, lookatPt, event.rTime);
+
+ m_directionH = h + Math::PI / 2.0f;
+ m_directionV = v;
+ }
+
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameFix(const Event &event)
+{
+ // +/-.
+ if (event.keyState & KS_NUMPLUS)
+ {
+ m_fixDist -= event.rTime * 30.0f * m_speed;
+ if (m_fixDist < 10.0f) m_fixDist = 10.0f;
+ }
+ if (event.keyState & KS_NUMMINUS)
+ {
+ m_fixDist += event.rTime * 30.0f * m_speed;
+ if (m_fixDist > 200.0f) m_fixDist = 200.0f;
+ }
+
+ if (m_cameraScroll)
+ {
+ // Left/Right
+ m_fixDirectionH += m_mouseDirH * event.rTime * 1.0f * m_speed;
+ m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
+ }
+
+ if ((m_mouseDirH != 0) || (m_mouseDirV != 0))
+ AbortCentering(); // special stops framing
+
+ if (m_cameraObj != NULL)
+ {
+ Math::Vector lookatPt = m_cameraObj->GetPosition(0);
+
+ float h = m_fixDirectionH + m_remotePan;
+ float v = m_fixDirectionV;
+
+ float d = m_fixDist;
+ m_eyePt = RotateView(lookatPt, h, v, d);
+ if (m_type == Gfx::CAM_TYPE_PLANE) m_eyePt.y += m_fixDist / 2.0f;
+ m_eyePt = ExcludeTerrain(m_eyePt, lookatPt, h, v);
+ m_eyePt = ExcludeObject(m_eyePt, lookatPt, h, v);
+
+ SetViewTime(m_eyePt, lookatPt, event.rTime);
+
+ m_directionH = h + Math::PI / 2.0f;
+ m_directionV = v;
+ }
+
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameExplo(const Event &event)
+{
+ float factor = m_heightEye * 0.5f + 30.0f;
+
+ if (m_mouseDirH != 0.0f)
+ m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
+
+ m_terrain->ValidPosition(m_eyePt, 10.0f);
+
+ if ( m_terrain->MoveOnFloor(m_eyePt, false) )
+ {
+ m_eyePt.y += m_heightEye;
+
+ Math::Vector pos = m_eyePt;
+ if ( m_terrain->MoveOnFloor(pos, false) )
+ {
+ pos.y += 2.0f;
+ if ( m_eyePt.y < pos.y )
+ m_eyePt.y = pos.y;
+ }
+
+ }
+
+ Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
+
+ if (m_terrain->MoveOnFloor(lookatPt, true))
+ lookatPt.y += m_heightLookat;
+
+ SetViewTime(m_eyePt, lookatPt, event.rTime);
+
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameOnBoard(const Event &event)
+{
+ if (m_cameraObj != NULL)
+ {
+ Math::Vector lookatPt, upVec;
+ m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV,
+ lookatPt, vUpVec, m_type);
+ Math::Vector eye = m_effectOffset * 0.3f + m_eyePt;
+ Math::Vector lookat = m_effectOffset * 0.3f + lookatPt;
+
+ SetViewParams(eye, lookat, upVec);
+ m_actualEye = eye;
+ m_actualLookat = lookat;
+ }
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameInfo(const Event &event)
+{
+ SetViewTime(Math::Vector(0.0f, 0.0f, 0.0f),
+ Math::Vector(0.0f, 0.0f, 1.0f),
+ event.rTime);
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameVisit(const Event &event)
+{
+ m_visitTime += event.rTime;
+
+ // +/-.
+ if (event.keyState & KS_NUMPLUS)
+ {
+ m_visitDist -= event.rTime * 50.0f * m_speed;
+ if (m_visitDist < 20.0f) m_visitDist = 20.0f;
+ }
+ if (event.keyState & KS_NUMMINUS)
+ {
+ m_visitDist += event.rTime * 50.0f * m_speed;
+ if (m_visitDist > 200.0f) m_visitDist = 200.0f;
+ }
+
+ // PageUp/Down.
+ if (event.keyState & KS_PAGEUP)
+ {
+ m_visitDirectionV -= event.rTime * 1.0f * m_speed;
+ if (m_visitDirectionV < -Math::PI * 0.40f) m_visitDirectionV = -Math::PI * 0.40f;
+ }
+ if (event.keyState & KS_PAGEDOWN)
+ {
+ m_visitDirectionV += event.rTime * 1.0f * m_speed;
+ if (m_visitDirectionV > 0.0f ) m_visitDirectionV = 0.0f;
+ }
+
+ if (m_cameraScroll)
+ {
+ m_visitDist -= m_mouseDirV * event.rTime * 30.0f * m_speed;
+ if (m_visitDist < 20.0f) m_visitDist = 20.0f;
+ if (m_visitDist > 200.0f) m_visitDist = 200.0f;
+ }
+
+ float angleH = (m_visitTime / 10.0f) * (Math::PI * 2.0f);
+ float angleV = m_visitDirectionV;
+ Math::Vector eye = RotateView(m_visitGoal, angleH, angleV, m_visitDist);
+ eye = ExcludeTerrain(eye, m_visitGoal, angleH, angleV);
+ eye = ExcludeObject(eye, m_visitGoal, angleH, angleV);
+ SetViewTime(eye, m_visitGoal, event.rTime);
+
+ return true;
+}
+
+bool Gfx::CCamera::EventFrameScript(const Event &event)
+{
+ SetViewTime(m_scriptEye + m_effectOffset,
+ m_scriptLookat + m_effectOffset, event.rTime);
+ return true;
+}
+
+void Gfx::CCamera::SetScriptEye(Math::Vector eye)
+{
+ m_scriptEye = eye;
+}
+
+void Gfx::CCamera::SetScriptLookat(Math::Vector lookat)
+{
+ m_scriptLookat = lookat;
+}
+
+void Gfx::CCamera::SetViewParams(const Math::Vector &eye, const Math::Vector &lookat,
+ const Math::Vector &up)
+{
+ m_engine->SetViewParams(eye, lookat, up, m_eyeDistance);
+
+ bool under = (eye.y < m_water->GetLevel()); // Is it underwater?
+ if (m_type == Gfx::CAM_TYPE_INFO)
+ under = false;
+
+ m_engine->SetRankView(under ? 1 : 0);
+}
+
+Math::Vector Gfx::CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat,
+ float &angleH, float &angleV)
+{
+ Math::Vector pos = eye;
+ if (m_terrain->MoveOnFloor(pos))
+ {
+ float dist = Math::DistanceProjected(lookat, pos);
+ pos.y += 2.0f+dist*0.1f;
+ if ( pos.y > eye.y )
+ {
+ angleV = -Math::RotateAngle(dist, pos.y-lookat.y);
+ eye = RotateView(lookat, angleH, angleV, dist);
+ }
+ }
+ return eye;
+}
+
+Math::Vector Gfx::CCamera::ExcludeObject(Math::Vector eye, Math::Vector lookat,
+ float &angleH, float &angleV)
+{
+ return eye;
+
+// TODO: check the commented out code:
+/*
+ for (int i = 0; i < 1000000; i++)
+ {
+ CObject* obj = static_cast<CObject*>( m_iMan->SearchInstance(CLASS_OBJECT, i) );
+ if (obj == NULL)
+ break;
+
+ int j = 0;
+ Math::Vector oPos;
+ float oRad;
+ while (obj->GetCrashSphere(j++, oPos, oRad))
+ {
+ float dist = Math::Distance(oPos, eye);
+ if (dist < oRad + 2.0f)
+ eye.y = oPos.y + oRad + 2.0f;
+ }
+ }
+
+ return eye;*/
+}
diff --git a/src/graphics/engine/camera.h b/src/graphics/engine/camera.h
new file mode 100644
index 0000000..935f8b0
--- /dev/null
+++ b/src/graphics/engine/camera.h
@@ -0,0 +1,386 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// camera.h
+
+#pragma once
+
+#include "engine.h"
+#include "common/event.h"
+
+
+class CInstanceManager;
+class CObject;
+
+namespace Gfx {
+
+
+/**
+ \enum CameraType
+ \brief Type of camera */
+enum CameraType
+{
+ //! Undefined
+ CAM_TYPE_NULL = 0,
+ //! Free camera (? never in principle ?)
+ CAM_TYPE_FREE = 1,
+ //! Camera while editing a program
+ CAM_TYPE_EDIT = 2,
+ //! Camera on board a robot
+ CAM_TYPE_ONBOARD = 3,
+ //! Camera behind a robot
+ CAM_TYPE_BACK = 4,
+ //! Static camera following robot
+ CAM_TYPE_FIX = 5,
+ //! Camera steady after explosion
+ CAM_TYPE_EXPLO = 6,
+ //! Camera during a film script
+ CAM_TYPE_SCRIPT = 7,
+ //! Camera for displaying information
+ CAM_TYPE_INFO = 8,
+ //! Visit instead of an error
+ CAM_TYPE_VISIT = 9,
+ //! Camera for dialog
+ CAM_TYPE_DIALOG = 10,
+ //! Static camera height
+ CAM_TYPE_PLANE = 11,
+};
+
+enum CameraSmooth
+{
+ //! Sharp
+ CAM_SMOOTH_NONE = 0,
+ //! Normal
+ CAM_SMOOTH_NORM = 1,
+ //! Hard
+ CAM_SMOOTH_HARD = 2,
+ //! Special
+ CAM_SMOOTH_SPEC = 3,
+};
+
+enum CenteringPhase
+{
+ CAM_PHASE_NULL = 0,
+ CAM_PHASE_START = 1,
+ CAM_PHASE_WAIT = 2,
+ CAM_PHASE_STOP = 3,
+};
+
+enum CameraEffect
+{
+ //! No effect
+ CAM_EFFECT_NULL = 0,
+ //! Digging in
+ CAM_EFFECT_TERRAFORM = 1,
+ //! ? Vehicle driving is severely ?
+ CAM_EFFECT_CRASH = 2,
+ //! Explosion
+ CAM_EFFECT_EXPLO = 3,
+ //! ? Not mortal shot ?
+ CAM_EFFECT_SHOT = 4,
+ //! Vibration during construction
+ CAM_EFFECT_VIBRATION = 5,
+ //! ? Spleen reactor ?
+ CAM_EFFECT_PET = 6,
+};
+
+enum CameraOverEffect
+{
+ //! No effect
+ CAM_OVER_EFFECT_NULL = 0,
+ //! Flash red
+ CAM_OVER_EFFECT_BLOOD = 1,
+ //! White -> nothing
+ CAM_OVER_EFFECT_FADEIN_WHITE = 2,
+ //! Nothing -> white
+ CAM_OVER_EFFECT_FADEOUT_WHITE = 3,
+ //! Nothing -> blue
+ CAM_OVER_EFFECT_FADEOUT_BLACK = 4,
+ //! Lightning
+ CAM_OVER_EFFECT_LIGHTNING = 5,
+};
+
+
+/**
+ \class CCamera
+ \brief Camera moving in 3D scene
+
+ ... */
+class CCamera {
+
+ public:
+ CCamera(CInstanceManager* iMan);
+ ~CCamera();
+
+ //! Management of an event
+ bool EventProcess(const Event &event);
+
+ //! Initializes the camera
+ void Init(Math::Vector eye, Math::Vector lookat, float delay);
+
+ //! Sets the object controlling the camera
+ void SetObject(CObject* object);
+ CObject* GetObject();
+
+ //! Change the type of camera
+ void SetType(Gfx::CameraType type);
+ Gfx::CameraType GetType();
+
+ //! Management of the smoothing mode
+ void SetSmooth(CameraSmooth type);
+ Gfx::CameraSmooth GetSmoth();
+
+ //! Management of the setback distance
+ void SetDist(float dist);
+ float GetDist();
+
+ //! Manage angle mode Gfx::CAM_TYPE_FIX
+ void SetFixDirection(float angle);
+ float GetFixDirection();
+
+ //! Managing the triggering mode of the camera panning
+ void SetRemotePan(float value);
+ float GetRemotePan();
+
+ //! Management of the remote zoom (0 .. 1) of the camera
+ void SetRemoteZoom(float value);
+ float GetRemoteZoom();
+
+ //! Start with a tour round the camera
+ void StartVisit(Math::Vector goal, float dist);
+ //! Circular end of a visit with the camera
+ void StopVisit();
+
+ //! Returns the point of view of the camera
+ void GetCamera(Math::Vector &eye, Math::Vector &lookat);
+
+ //! Specifies a special movement of camera to frame action
+ bool StartCentering(CObject *object, float angleH, float angleV, float dist, float time);
+ //! Ends a special movement of camera to frame action
+ bool StopCentering(CObject *object, float time);
+ //! Stop framing special in the current position
+ void AbortCentering();
+
+ //! Removes the special effect with the camera
+ void FlushEffect();
+ //! Starts a special effect with the camera
+ void StartEffect(Gfx::CameraEffect effect, Math::Vector pos, float force);
+
+ //! Removes the effect of superposition in the foreground
+ void FlushOver();
+ //! Specifies the base color
+ void SetOverBaseColor(Gfx::Color color);
+ void StartOver(Gfx::CameraOverEffect effect, Math::Vector pos, float force);
+
+ //! Sets the soft movement of the camera
+ void FixCamera();
+ void SetScriptEye(Math::Vector eye);
+ void SetScriptLookat(Math::Vector lookat);
+
+ void SetEffect(bool enable);
+ void SetCameraScroll(bool scroll);
+ void SetCameraInvertX(bool invert);
+ void SetCameraInvertY(bool invert);
+
+ //! Returns an additional force to turn
+ float GetMotorTurn();
+ //! Returns the default sprite to use for the mouse
+ Gfx::EngineMouseType GetMouseDef(Math::Point pos);
+
+protected:
+ //! Changes the camera according to the mouse moved
+ bool EventMouseMove(const Event &event);
+ //! Mouse wheel operation
+ void EventMouseWheel(int dir);
+ //! Changes the camera according to the time elapsed
+ bool EventFrame(const Event &event);
+ //! Moves the point of view
+ bool EventFrameFree(const Event &event);
+ //! Moves the point of view
+ bool EventFrameEdit(const Event &event);
+ //! Moves the point of view
+ bool EventFrameDialog(const Event &event);
+ //! Moves the point of view
+ bool EventFrameBack(const Event &event);
+ //! Moves the point of view
+ bool EventFrameFix(const Event &event);
+ //! Moves the point of view
+ bool EventFrameExplo(const Event &event);
+ //! Moves the point of view
+ bool EventFrameOnBoard(const Event &event);
+ //! Moves the point of view
+ bool EventFrameInfo(const Event &event);
+ //! Moves the point of view
+ bool EventFrameVisit(const Event &event);
+ //! Moves the point of view
+ bool EventFrameScript(const Event &event);
+
+ //! Specifies the location and direction of view to the 3D engine
+ void SetViewTime(const Math::Vector &vEyePt, const Math::Vector &vLookatPt, float rTime);
+ //! Avoid the obstacles
+ bool IsCollision(Math::Vector &eye, Math::Vector lookat);
+ //! Avoid the obstacles
+ bool IsCollisionBack(Math::Vector &eye, Math::Vector lookat);
+ //! Avoid the obstacles
+ bool IsCollisionFix(Math::Vector &eye, Math::Vector lookat);
+
+ //! Adjusts the camera not to enter the ground
+ Math::Vector ExcludeTerrain(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV);
+ //! Adjusts the camera not to enter an object
+ Math::Vector ExcludeObject(Math::Vector eye, Math::Vector lookat, float &angleH, float &angleV);
+
+ //! Specifies the location and direction of view
+ void SetViewParams(const Math::Vector &eye, const Math::Vector &lookat, const Math::Vector &up);
+ //! Advances the effect of the camera
+ void EffectFrame(const Event &event);
+ //! Advanced overlay effect in the foreground
+ void OverFrame(const Event &event);
+
+protected:
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
+ Gfx::CTerrain* m_terrain;
+ Gfx::CWater* m_water;
+
+ //! The type of camera
+ Gfx::CameraType m_type;
+ //! Type of smoothing
+ Gfx::CameraSmooth m_smooth;
+ //! Object linked to the camera
+ CObject* m_cameraObj;
+
+ //! Distance between the eyes
+ float m_eyeDistance;
+ //! Time of initial centering
+ float m_initDelay;
+
+ //! Current eye
+ Math::Vector m_actualEye;
+ //! Current aim
+ Math::Vector m_actualLookat;
+ //! Final eye
+ Math::Vector m_finalEye;
+ //! Final aim
+ Math::Vector m_finalLookat;
+ //! Normal eye
+ Math::Vector m_normEye;
+ //! Normal aim
+ Math::Vector m_normLookat;
+
+ float m_focus;
+
+ bool m_rightDown;
+ Math::Point m_rightPosInit;
+ Math::Point m_rightPosCenter;
+ Math::Point m_rightPosMove;
+
+ //! CAM_TYPE_FREE: eye
+ Math::Vector m_eyePt;
+ //! CAM_TYPE_FREE: horizontal direction
+ float m_directionH;
+ //! CAM_TYPE_FREE: vertical direction
+ float m_directionV;
+ //! CAM_TYPE_FREE: height above the ground
+ float m_heightEye;
+ //! CAM_TYPE_FREE: height above the ground
+ float m_heightLookat;
+ //! CAM_TYPE_FREE: speed of movement
+ float m_speed;
+
+ //! CAM_TYPE_BACK: distance
+ float m_backDist;
+ //! CAM_TYPE_BACK: distance minimal
+ float m_backMin;
+ //! CAM_TYPE_BACK: additional direction
+ float m_addDirectionH;
+ //! CAM_TYPE_BACK: additional direction
+ float m_addDirectionV;
+ bool m_transparency;
+
+ //! CAM_TYPE_FIX: distance
+ float m_fixDist;
+ //! CAM_TYPE_FIX: direction
+ float m_fixDirectionH;
+ //! CAM_TYPE_FIX: direction
+ float m_fixDirectionV;
+
+ //! CAM_TYPE_VISIT: target position
+ Math::Vector m_visitGoal;
+ //! CAM_TYPE_VISIT: distance
+ float m_visitDist;
+ //! CAM_TYPE_VISIT: relative time
+ float m_visitTime;
+ //! CAM_TYPE_VISIT: initial type
+ Gfx::CameraType m_visitType;
+ //! CAM_TYPE_VISIT: direction
+ float m_visitDirectionH;
+ //! CAM_TYPE_VISIT: direction
+ float m_visitDirectionV;
+
+ //! CAM_TYPE_EDIT: height
+ float m_editHeight;
+
+ float m_remotePan;
+ float m_remoteZoom;
+
+ Math::Point m_mousePos;
+ float m_mouseDirH;
+ float m_mouseDirV;
+ float m_mouseMarging;
+
+ float m_motorTurn;
+
+ Gfx::CenteringPhase m_centeringPhase;
+ float m_centeringAngleH;
+ float m_centeringAngleV;
+ float m_centeringDist;
+ float m_centeringCurrentH;
+ float m_centeringCurrentV;
+ float m_centeringTime;
+ float m_centeringProgress;
+
+ CameraEffect m_effectType;
+ Math::Vector m_effectPos;
+ float m_effectForce;
+ float m_effectProgress;
+ Math::Vector m_effectOffset;
+
+ OverEffect m_overType;
+ float m_overForce;
+ float m_overTime;
+ Gfx::Color m_overColorBase;
+ Gfx::Color m_overColor;
+ int m_overMode;
+ float m_overFadeIn;
+ float m_overFadeOut;
+
+ Math::Vector m_scriptEye;
+ Math::Vector m_scriptLookat;
+
+ //! Shocks if explosion?
+ bool m_effect;
+ //! Scroll in the edges?
+ bool m_cameraScroll;
+ //! X inversion in the edges?
+ bool m_cameraInvertX;
+ //! Y inversion in the edges?
+ bool m_cameraInvertY;
+
+};
+
+
+}; // namespace Gfx
diff --git a/src/graphics/common/cloud.cpp b/src/graphics/engine/cloud.cpp
index 707f641..d0e5ed8 100644
--- a/src/graphics/common/cloud.cpp
+++ b/src/graphics/engine/cloud.cpp
@@ -17,7 +17,7 @@
// cloud.cpp
-#include "graphics/common/cloud.h"
+#include "graphics/engine/cloud.h"
// TODO implementation
diff --git a/src/graphics/common/cloud.h b/src/graphics/engine/cloud.h
index 19b689f..d2d29d7 100644
--- a/src/graphics/common/cloud.h
+++ b/src/graphics/engine/cloud.h
@@ -20,7 +20,7 @@
#pragma once
#include "common/event.h"
-#include "graphics/common/color.h"
+#include "graphics/core/color.h"
#include "math/point.h"
#include "math/vector.h"
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
new file mode 100644
index 0000000..e544ee3
--- /dev/null
+++ b/src/graphics/engine/engine.cpp
@@ -0,0 +1,743 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// engine.cpp
+
+#include "graphics/engine/engine.h"
+
+#include "app/app.h"
+#include "common/iman.h"
+#include "common/image.h"
+#include "common/key.h"
+#include "common/logger.h"
+#include "graphics/core/device.h"
+#include "math/geometry.h"
+
+// Initial size of various vectors
+const int OBJECT_PREALLOCATE_COUNT = 1200;
+const int SHADOW_PREALLOCATE_COUNT = 500;
+const int GROUNDSPOT_PREALLOCATE_COUNT = 100;
+
+const int LEVEL1_PREALLOCATE_COUNT = 50;
+const int LEVEL2_PREALLOCATE_COUNT = 100;
+const int LEVEL3_PREALLOCATE_COUNT = 5;
+const int LEVEL4_PREALLOCATE_COUNT = 10;
+const int LEVEL5_PREALLOCATE_COUNT = 100;
+const int LEVEL5_VERTEX_PREALLOCATE_COUNT = 200;
+
+
+Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
+{
+ m_iMan = iMan;
+ m_app = app;
+ m_device = NULL;
+
+ m_wasInit = false;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_ENGINE, this);
+ m_app = app;
+
+ m_lightMan = NULL;
+ m_text = NULL;
+ m_particle = NULL;
+ m_water = NULL;
+ m_cloud = NULL;
+ m_lightning = NULL;
+ m_planet = NULL;
+ m_sound = NULL;
+ m_terrain = NULL;
+
+ m_focus = 0.75f;
+ m_baseTime = 0;
+ m_lastTime = 0;
+ m_absTime = 0.0f;
+ m_rankView = 0;
+
+ m_ambientColor[0] = Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f);
+ m_ambientColor[1] = Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f);
+ m_fogColor[0] = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f);
+ m_fogColor[1] = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f);
+ m_deepView[0] = 1000.0f;
+ m_deepView[1] = 1000.0f;
+ m_fogStart[0] = 0.75f;
+ m_fogStart[1] = 0.75f;
+ m_waterAddColor = Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f);
+
+ m_pause = false;
+ m_render = true;
+ m_movieLock = false;
+ m_shadowVisible = true;
+ m_groundSpotVisible = true;
+ m_dirty = true;
+ m_fog = true;
+ m_speed = 1.0f;
+ m_secondTexNum = 0;
+ m_eyeDirH = 0.0f;
+ m_eyeDirV = 0.0f;
+ m_backgroundName = ""; // no background image
+ m_backgroundColorUp = 0;
+ m_backgroundColorDown = 0;
+ m_backgroundCloudUp = 0;
+ m_backgroundCloudDown = 0;
+ m_backgroundFull = false;
+ m_backgroundQuarter = false;
+ m_overFront = true;
+ m_overColor = 0;
+ m_overMode = ENG_RSTATE_TCOLOR_BLACK;
+ m_frontsizeName = ""; // no front image
+ m_hiliteRank[0] = -1; // empty list
+ m_eyePt = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_lookatPt = Math::Vector(0.0f, 0.0f, 1.0f);
+ m_drawWorld = true;
+ m_drawFront = false;
+ m_limitLOD[0] = 100.0f;
+ m_limitLOD[1] = 200.0f;
+ m_particuleDensity = 1.0f;
+ m_clippingDistance = 1.0f;
+ m_lastClippingDistance = m_clippingDistance;
+ m_objectDetail = 1.0f;
+ m_lastObjectDetail = m_objectDetail;
+ m_terrainVision = 1000.0f;
+ m_gadgetQuantity = 1.0f;
+ m_textureQuality = 1;
+ m_totoMode = true;
+ m_lensMode = true;
+ m_waterMode = true;
+ m_skyMode = true;
+ m_backForce = true;
+ m_planetMode = true;
+ m_lightMode = true;
+ m_editIndentMode = true;
+ m_editIndentValue = 4;
+ m_tracePrecision = 1.0f;
+
+ m_alphaMode = 1;
+
+ m_forceStateColor = true;
+ m_stateColor = false;
+
+ m_blackSrcBlend[0] = 0;
+ m_blackDestBlend[0] = 0;
+ m_whiteSrcBlend[0] = 0;
+ m_whiteDestBlend[0] = 0;
+ m_diffuseSrcBlend[0] = 0;
+ m_diffuseDestBlend[0] = 0;
+ m_alphaSrcBlend[0] = 0;
+ m_alphaDestBlend[0] = 0;
+
+ m_updateGeometry = false;
+
+ m_mice[Gfx::ENG_MOUSE_NORM] = Gfx::EngineMouse( 0, 1, 32, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 1.0f, 1.0f));
+ m_mice[Gfx::ENG_MOUSE_WAIT] = Gfx::EngineMouse( 2, 3, 33, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 8.0f, 12.0f));
+ m_mice[Gfx::ENG_MOUSE_HAND] = Gfx::EngineMouse( 4, 5, 34, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point( 7.0f, 2.0f));
+ m_mice[Gfx::ENG_MOUSE_NO] = Gfx::EngineMouse( 6, 7, 35, Gfx::ENG_RSTATE_TCOLOR_WHITE, Gfx::ENG_RSTATE_TCOLOR_BLACK, Math::Point(10.0f, 10.0f));
+ m_mice[Gfx::ENG_MOUSE_EDIT] = Gfx::EngineMouse( 8, 9, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 6.0f, 10.0f));
+ m_mice[Gfx::ENG_MOUSE_CROSS] = Gfx::EngineMouse(10, 11, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(10.0f, 10.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVEV] = Gfx::EngineMouse(12, 13, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 5.0f, 11.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVEH] = Gfx::EngineMouse(14, 15, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(11.0f, 5.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVED] = Gfx::EngineMouse(16, 17, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVEI] = Gfx::EngineMouse(18, 19, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_MOVE] = Gfx::EngineMouse(20, 21, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(11.0f, 11.0f));
+ m_mice[Gfx::ENG_MOUSE_TARGET] = Gfx::EngineMouse(22, 23, -1, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(15.0f, 15.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLL] = Gfx::EngineMouse(24, 25, 43, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 2.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLR] = Gfx::EngineMouse(26, 27, 44, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point(17.0f, 9.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLU] = Gfx::EngineMouse(28, 29, 45, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 2.0f));
+ m_mice[Gfx::ENG_MOUSE_SCROLLD] = Gfx::EngineMouse(30, 31, 46, Gfx::ENG_RSTATE_TCOLOR_BLACK, Gfx::ENG_RSTATE_TCOLOR_WHITE, Math::Point( 9.0f, 17.0f));
+
+ m_mouseSize = Math::Point(0.04f, 0.04f * (800.0f / 600.0f));
+ m_mousePos = Math::Point(0.5f, 0.5f);
+ m_mouseType = Gfx::ENG_MOUSE_NORM;
+ m_mouseVisible = false;
+
+ m_texPath = "textures/";
+ m_defaultTexParams.format = Gfx::TEX_IMG_RGBA;
+ m_defaultTexParams.mipmap = true;
+ m_defaultTexParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
+ m_defaultTexParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
+
+ m_objectTree.reserve(LEVEL1_PREALLOCATE_COUNT);
+ m_objects.reserve(OBJECT_PREALLOCATE_COUNT);
+ m_shadow.reserve(SHADOW_PREALLOCATE_COUNT);
+ m_groundSpot.reserve(GROUNDSPOT_PREALLOCATE_COUNT);
+}
+
+Gfx::CEngine::~CEngine()
+{
+ m_iMan = NULL;
+ m_app = NULL;
+ m_device = NULL;
+
+ m_sound = NULL;
+ m_terrain = NULL;
+}
+
+bool Gfx::CEngine::GetWasInit()
+{
+ return m_wasInit;
+}
+
+std::string Gfx::CEngine::GetError()
+{
+ return m_error;
+}
+
+bool Gfx::CEngine::Create()
+{
+ m_wasInit = true;
+
+ /*m_lightMan = new Gfx::CLight(m_iMan, this);
+ m_text = new Gfx::CText(m_iMan, this);
+ m_particle = new Gfx::CParticle(m_iMan, this);
+ m_water = new Gfx::CWater(m_iMan, this);
+ m_cloud = new Gfx::CCloud(m_iMan, this);
+ m_lightning = new Gfx::CLightning(m_iMan, this);
+ m_planet = new Gfx::CPlanet(m_iMan, this);*/
+
+ m_matWorldInterface.LoadIdentity();
+ m_matViewInterface.LoadIdentity();
+ Math::LoadOrthoProjectionMatrix(m_matProjInterface, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
+
+ return true;
+}
+
+void Gfx::CEngine::Destroy()
+{
+ // TODO
+
+ /*delete m_lightMan;
+ m_lightMan = NULL;
+
+ delete m_text;
+ m_text = NULL;
+
+ delete m_particle;
+ m_particle = NULL;
+
+ delete m_water;
+ m_water = NULL;
+
+ delete m_cloud;
+ m_cloud = NULL;
+
+ delete m_lightning;
+ m_lightning = NULL;
+
+ delete m_planet;
+ m_planet = NULL;*/
+
+ m_wasInit = false;
+}
+
+void Gfx::CEngine::SetDevice(Gfx::CDevice *device)
+{
+ m_device = device;
+}
+
+Gfx::CDevice* Gfx::CEngine::GetDevice()
+{
+ return m_device;
+}
+
+bool Gfx::CEngine::AfterDeviceSetInit()
+{
+ m_device->SetClearColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f));
+
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+
+ Gfx::TextureCreateParams params;
+ params.format = Gfx::TEX_IMG_RGB;
+ params.minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
+ params.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+ params.mipmap = false;
+ m_miceTexture = CreateTexture("mouse.png", params);
+
+ return true;
+}
+
+void Gfx::CEngine::ResetAfterDeviceChanged()
+{
+ // TODO
+}
+
+
+Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
+{
+ CImage img;
+ if (! img.Load(m_app->GetDataFilePath(m_texPath, texName)))
+ {
+ std::stringstream str;
+ str << "Couldn't load texture '" << texName << "': " << img.GetError();
+ m_error = str.str();
+ return Gfx::Texture(); // invalid texture
+ }
+
+ Gfx::Texture result = m_device->CreateTexture(&img, params);
+
+ if (! result.valid)
+ {
+ std::stringstream str;
+ str << "Couldn't load texture '" << texName << "': " << m_device->GetError();
+ m_error = str.str();
+ return result;
+ }
+
+ m_texNameMap[texName] = result;
+ m_revTexNameMap[result] = texName;
+
+ return result;
+}
+
+Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName)
+{
+ return CreateTexture(texName, m_defaultTexParams);
+}
+
+void Gfx::CEngine::DestroyTexture(const std::string &texName)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(texName);
+ if (it == m_texNameMap.end())
+ return;
+
+ std::map<Gfx::Texture, std::string>::iterator revIt = m_revTexNameMap.find((*it).second);
+
+ m_device->DestroyTexture((*it).second);
+
+ m_revTexNameMap.erase(revIt);
+ m_texNameMap.erase(it);
+}
+
+void Gfx::CEngine::SetTexture(const std::string &name, int stage)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = m_texNameMap.find(name);
+ if (it != m_texNameMap.end())
+ m_device->SetTexture(stage, (*it).second);
+
+ // TODO if not present...
+}
+
+void Gfx::CEngine::SetMaterial(const Gfx::Material &mat)
+{
+ m_device->SetMaterial(mat);
+}
+
+void Gfx::CEngine::SetState(int state, Gfx::Color color)
+{
+ if ( state == m_lastState && color == m_lastColor )
+ return;
+
+ m_lastState = state;
+ m_lastColor = color;
+
+ if ( m_alphaMode != 1 && (state & Gfx::ENG_RSTATE_ALPHA) )
+ {
+ state &= ~Gfx::ENG_RSTATE_ALPHA;
+
+ if (m_alphaMode == 2)
+ state |= Gfx::ENG_RSTATE_TTEXTURE_BLACK;
+ }
+
+ // TODO other modes & thorough testing
+
+ if (state & Gfx::ENG_RSTATE_TTEXTURE_BLACK) // The transparent black texture?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ m_device->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR);
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureFactor(color);
+
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+ params.colorArg2 = Gfx::TEX_MIX_ARG_FACTOR;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ m_device->SetTextureStageParams(0, params);
+ }
+ else if (state & Gfx::ENG_RSTATE_TTEXTURE_WHITE) // The transparent white texture?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ m_device->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO);
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureFactor(color.Inverse());
+
+ Gfx::TextureStageParams params;
+ params.colorOperation = Gfx::TEX_MIX_OPER_ADD;
+ params.colorArg1 = Gfx::TEX_MIX_ARG_TEXTURE;
+ params.colorArg2 = Gfx::TEX_MIX_ARG_FACTOR;
+ params.alphaOperation = Gfx::TEX_MIX_OPER_MODULATE;
+ m_device->SetTextureStageParams(0, params);
+ }
+ else if (state & Gfx::ENG_RSTATE_TCOLOR_BLACK) // The transparent black color?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ m_device->SetBlendFunc(Gfx::BLEND_ONE, Gfx::BLEND_INV_SRC_COLOR);
+
+ m_device->SetTextureFactor(color);
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+ }
+ else if (state & Gfx::ENG_RSTATE_TCOLOR_WHITE) // The transparent white color?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ m_device->SetBlendFunc(Gfx::BLEND_DST_COLOR, Gfx::BLEND_ZERO);
+
+ m_device->SetTextureFactor(color.Inverse());
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+ }
+ else if (state & Gfx::ENG_RSTATE_TDIFFUSE) // diffuse color as transparent?
+ {
+ /*m_device->SetRenderState(D3DRENDERSTATE_FOGENABLE, false);
+ m_device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, false);
+ m_device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, true);
+ m_device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, false);
+ m_device->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_diffuseSrcBlend[1]);
+ m_device->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_diffuseDestBlend[1]);
+
+ m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/
+ }
+ else if (state & Gfx::ENG_RSTATE_ALPHA) // image with alpha channel?
+ {
+ /*m_device->SetRenderState(D3DRENDERSTATE_FOGENABLE, true);
+ m_device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, true);
+ m_device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, false);
+ m_device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, true);
+ m_device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER);
+ m_device->SetRenderState(D3DRENDERSTATE_ALPHAREF, (DWORD)(128));
+ m_device->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_alphaSrcBlend[1]);
+ m_device->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_alphaSrcBlend[1]);
+
+ m_device->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ m_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);*/
+ }
+ else // normal ?
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_WRITE, true);
+ m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_ALPHA_TEST, false);
+ m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ m_device->SetTextureEnabled(0, true);
+ m_device->SetTextureStageParams(0, Gfx::TextureStageParams());
+
+ /*m_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ m_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);*/
+ }
+
+ if (state & Gfx::ENG_RSTATE_FOG)
+ m_device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
+
+
+ bool second = m_groundSpotVisible || m_dirty;
+
+ if ( !m_groundSpotVisible && (state & Gfx::ENG_RSTATE_SECOND) != 0 ) second = false;
+ if ( !m_dirty && (state & Gfx::ENG_RSTATE_SECOND) == 0 ) second = false;
+
+ if ( (state & ENG_RSTATE_DUAL_BLACK) && second )
+ {
+ /*m_device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
+ m_device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ m_device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);*/
+ }
+ else if ( (state & ENG_RSTATE_DUAL_WHITE) && second )
+ {
+ /*m_device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);
+ m_device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
+ m_device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ m_device->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);*/
+ }
+ else
+ {
+ m_device->SetTextureEnabled(1, false);
+ }
+
+ if (state & Gfx::ENG_RSTATE_WRAP)
+ {
+ /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
+ m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);*/
+ }
+ else if (state & Gfx::ENG_RSTATE_CLAMP)
+ {
+ /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/
+ }
+ else
+ {
+ /*m_device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);*/
+ }
+
+ if (state & Gfx::ENG_RSTATE_2FACE)
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_CULLING, false);
+ }
+ else
+ {
+ m_device->SetRenderState(Gfx::RENDER_STATE_CULLING, true);
+ m_device->SetCullMode(Gfx::CULL_CCW);
+ }
+
+ if (state & Gfx::ENG_RSTATE_LIGHT)
+ m_device->SetGlobalAmbient(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f));
+ else
+ m_device->SetGlobalAmbient(m_ambientColor[m_rankView]);
+}
+
+bool Gfx::CEngine::ProcessEvent(const Event &event)
+{
+ if (event.type == EVENT_MOUSE_MOVE)
+ {
+ m_mousePos = event.mouseMove.pos;
+ }
+ else if (event.type == EVENT_KEY_DOWN)
+ {
+ // !! Debug, to be removed later !!
+
+ if (event.key.key == KEY(F1))
+ {
+ m_mouseVisible = !m_mouseVisible;
+ m_app->SetSystemMouseVisible(! m_app->GetSystemMouseVisibile());
+ }
+ else if (event.key.key == KEY(F2))
+ {
+ int index = static_cast<int>(m_mouseType);
+ m_mouseType = static_cast<Gfx::EngineMouseType>( (index + 1) % Gfx::ENG_MOUSE_COUNT );
+ }
+ }
+
+ // By default, pass on all events
+ return true;
+}
+
+bool Gfx::CEngine::Render()
+{
+ m_statisticTriangle = 0;
+
+ m_lastState = -1;
+ SetState(Gfx::ENG_RSTATE_NORMAL);
+
+ m_device->BeginScene();
+
+ SetUp3DView();
+
+ if (! Draw3DScene() )
+ return false;
+
+ SetUpInterfaceView();
+
+ if (! DrawInterface() )
+ return false;
+
+ m_device->EndScene();
+
+ return true;
+}
+
+void Gfx::CEngine::SetUp3DView()
+{
+ // TODO
+}
+
+bool Gfx::CEngine::Draw3DScene()
+{
+ // TODO
+ return true;
+}
+
+void Gfx::CEngine::SetUpInterfaceView()
+{
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_matWorldInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_VIEW, m_matViewInterface);
+ m_device->SetTransform(Gfx::TRANSFORM_PROJECTION, m_matProjInterface);
+}
+
+bool Gfx::CEngine::DrawInterface()
+{
+ Gfx::VertexCol vertices[3] =
+ {
+ Gfx::VertexCol(Math::Vector( 0.25f, 0.25f, 0.0f), Gfx::Color(1.0f, 0.0f, 0.0f)),
+ Gfx::VertexCol(Math::Vector( 0.75f, 0.25f, 0.0f), Gfx::Color(0.0f, 1.0f, 0.0f)),
+ Gfx::VertexCol(Math::Vector( 0.5f, 0.75f, 0.0f), Gfx::Color(0.0f, 0.0f, 1.0f))
+ };
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, vertices, 3);
+
+ DrawMouse();
+
+ return true;
+}
+
+void Gfx::CEngine::DrawMouse()
+{
+ if (! m_mouseVisible)
+ return;
+
+ if (m_app->GetSystemMouseVisibile())
+ return;
+
+ Gfx::Material material;
+ material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f);
+ material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f);
+
+ m_device->SetMaterial(material);
+ m_device->SetTexture(0, m_miceTexture);
+
+ int index = static_cast<int>(m_mouseType);
+
+ Math::Point pos = m_mousePos;
+ pos.x = m_mousePos.x - (m_mice[index].hotPoint.x * m_mouseSize.x) / 32.0f;
+ pos.y = m_mousePos.y - ((32.0f - m_mice[index].hotPoint.y) * m_mouseSize.y) / 32.0f;
+
+ Math::Point shadowPos;
+ shadowPos.x = pos.x + (4.0f/800.0f);
+ shadowPos.y = pos.y - (3.0f/600.0f);
+
+ SetState(Gfx::ENG_RSTATE_TCOLOR_WHITE);
+ DrawMouseSprite(shadowPos, m_mouseSize, m_mice[index].iconShadow);
+
+ SetState(m_mice[index].mode1);
+ DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon1);
+
+ SetState(m_mice[index].mode2);
+ DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon2);
+}
+
+void Gfx::CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon)
+{
+ if (icon == -1)
+ return;
+
+ Math::Point p1 = pos;
+ Math::Point p2 = p1 + size;
+
+ float u1 = (32.0f / 256.0f) * (icon % 8);
+ float v1 = (32.0f / 256.0f) * (icon / 8);
+ float u2 = u1 + (32.0f / 256.0f);
+ float v2 = v1 + (32.0f / 256.0f);
+
+ float dp = 0.5f / 256.0f;
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ Math::Vector normal(0.0f, 0.0f, -1.0f);
+
+ Gfx::Vertex vertex[4] =
+ {
+ Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), normal, Math::Point(u1, v2)),
+ Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), normal, Math::Point(u2, v2)),
+ Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), normal, Math::Point(u1, v1)),
+ Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), normal, Math::Point(u2, v1))
+ };
+
+ m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, vertex, 4);
+ AddStatisticTriangle(2);
+}
+
+bool Gfx::CEngine::GetPause()
+{
+ return m_pause;
+}
+
+Math::Vector Gfx::CEngine::GetLookatPt()
+{
+ return m_lookatPt;
+}
+
+Math::Vector Gfx::CEngine::GetEyePt()
+{
+ return m_eyePt;
+}
+
+void Gfx::CEngine::SetMouseVisible(bool visible)
+{
+ m_mouseVisible = visible;
+}
+
+bool Gfx::CEngine::GetMouseVisible()
+{
+ return m_mouseVisible;
+}
+
+void Gfx::CEngine::SetMousePos(Math::Point pos)
+{
+ m_mousePos = pos;
+}
+
+Math::Point Gfx::CEngine::GetMousePos()
+{
+ return m_mousePos;
+}
+
+void Gfx::CEngine::SetMouseType(Gfx::EngineMouseType type)
+{
+ m_mouseType = type;
+}
+
+Gfx::EngineMouseType Gfx::CEngine::GetMouseType()
+{
+ return m_mouseType;
+}
+
+void Gfx::CEngine::AddStatisticTriangle(int count)
+{
+ m_statisticTriangle += count;
+}
+
+void Gfx::CEngine::SetShowStat(bool show)
+{
+ m_showStats = show;
+}
+
+bool Gfx::CEngine::GetShowStat()
+{
+ return m_showStats;
+}
+
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
new file mode 100644
index 0000000..25c5e5d
--- /dev/null
+++ b/src/graphics/engine/engine.h
@@ -0,0 +1,1002 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// engine.h
+
+#pragma once
+
+
+#include "common/event.h"
+#include "graphics/core/color.h"
+#include "graphics/core/material.h"
+#include "graphics/core/texture.h"
+#include "graphics/core/vertex.h"
+#include "math/intpoint.h"
+#include "math/intsize.h"
+#include "math/matrix.h"
+#include "math/point.h"
+#include "math/vector.h"
+
+
+#include <string>
+#include <vector>
+#include <map>
+
+
+class CApplication;
+class CInstanceManager;
+class CObject;
+class CSound;
+
+
+namespace Gfx {
+
+class CDevice;
+class CLightManager;
+class CText;
+class CParticle;
+class CWater;
+class CCloud;
+class CLightning;
+class CPlanet;
+class CTerrain;
+
+
+/**
+ \enum EngineTriangleType
+ \brief Type of triangles drawn for engine objects */
+enum EngineTriangleType
+{
+ //! Triangles
+ ENG_TRIANGLE_TYPE_6T = 1,
+ //! Surfaces
+ ENG_TRIANGLE_TYPE_6S = 2
+};
+
+/**
+ \struct EngineTriangle
+ \brief A triangle drawn by the graphics engine */
+struct EngineTriangle
+{
+ //! Triangle vertices
+ Gfx::VertexTex2 triangle[3];
+ //! Material
+ Gfx::Material material;
+ //! Render state (TODO: ?)
+ int state;
+ //! 1st texture
+ Gfx::Texture tex1;
+ //! 2nd texture
+ Gfx::Texture tex2;
+
+ EngineTriangle()
+ {
+ state = 0;
+ }
+};
+
+/**
+ \enum EngineObjectType
+ \brief Class of graphics engine object */
+enum EngineObjectType
+{
+ //! Object doesn't exist
+ ENG_OBJTYPE_NULL = 0,
+ //! Terrain
+ ENG_OBJTYPE_TERRAIN = 1,
+ //! Fixed object
+ ENG_OBJTYPE_FIX = 2,
+ //! Moving object
+ ENG_OBJTYPE_VEHICULE = 3,
+ //! Part of a moving object
+ ENG_OBJTYPE_DESCENDANT = 4,
+ //! Fixed object type quartz
+ ENG_OBJTYPE_QUARTZ = 5,
+ //! Fixed object type metal
+ ENG_OBJTYPE_METAL = 6
+};
+
+/**
+ \struct EngineObject
+ \brief Object drawn by the graphics engine */
+struct EngineObject
+{
+ //! If true, the object is drawn
+ bool visible;
+ //! If true, object is behind the 2D interface
+ bool drawWorld;
+ //! If true, the shape is before the 2D interface
+ bool drawFront;
+ //! Number of triangles
+ int totalTriangles;
+ //! Type of object
+ Gfx::EngineObjectType type;
+ //! Transformation matrix
+ Math::Matrix transform;
+ //! Distance view - origin (TODO: ?)
+ float distance;
+ //! Bounding box min (origin 0,0,0 always included)
+ Math::Vector bboxMin;
+ //! bounding box max (origin 0,0,0 always included)
+ Math::Vector bboxMax;
+ //! Radius of the sphere at the origin
+ float radius;
+ //! Rank of the associated shadow
+ int shadowRank;
+ //! Transparency of the object [0, 1]
+ float transparency;
+
+ EngineObject()
+ {
+ visible = false;
+ drawWorld = false;
+ drawFront = false;
+ totalTriangles = 0;
+ distance = 0.0f;
+ radius = 0.0f;
+ shadowRank = 0;
+ transparency = 0.0f;
+ }
+};
+
+struct EngineObjLevel1;
+struct EngineObjLevel2;
+struct EngineObjLevel3;
+struct EngineObjLevel4;
+struct EngineObjLevel5;
+
+/**
+ \struct EngineObjLevel5
+ \brief Tier 5 of object tree */
+struct EngineObjLevel5
+{
+ Gfx::Material material;
+ int state;
+ Gfx::EngineTriangleType type;
+ std::vector<Gfx::VertexTex2> vertices;
+
+ EngineObjLevel5();
+};
+
+/**
+ \struct EngineObjLevel4
+ \brief Tier 4 of object tree */
+struct EngineObjLevel4
+{
+ int reserved;
+ std::vector<Gfx::EngineObjLevel5> up;
+ Gfx::EngineObjLevel3* down;
+
+ EngineObjLevel4();
+};
+
+/**
+ \struct EngineObjLevel3
+ \brief Tier 3 of object tree */
+struct EngineObjLevel3
+{
+ float min;
+ float max;
+ std::vector<Gfx::EngineObjLevel4> up;
+ Gfx::EngineObjLevel2* down;
+
+ EngineObjLevel3();
+};
+
+/**
+ \struct EngineObjLevel2
+ \brief Tier 2 of object tree */
+struct EngineObjLevel2
+{
+ int objRank;
+ std::vector<Gfx::EngineObjLevel3> up;
+ Gfx::EngineObjLevel1* down;
+
+ EngineObjLevel2();
+};
+
+/**
+ \struct EngineObjLevel1
+ \brief Tier 1 of object tree */
+struct EngineObjLevel1
+{
+ Gfx::Texture tex1;
+ Gfx::Texture tex2;
+ std::vector<Gfx::EngineObjLevel2> up;
+
+ EngineObjLevel1();
+};
+
+/**
+ \struct EngineShadowType
+ \brief Type of shadow drawn by the graphics engine */
+enum EngineShadowType
+{
+ //! Normal shadow
+ ENG_SHADOW_NORM = 0,
+ //! TODO: ?
+ ENG_SHADOW_WORM = 1
+};
+
+/**
+ \struct EngineShadow
+ \brief Shadow drawn by the graphics engine */
+struct EngineShadow
+{
+ //! If true, shadow is invisible (object being carried for example)
+ bool hide;
+ //! Rank of the associated object
+ int objRank;
+ //! Type of shadow
+ Gfx::EngineShadowType type;
+ //! Position of the shadow
+ Math::Vector pos;
+ //! Normal to the terrain
+ Math::Vector normal;
+ //! Angle of the shadow
+ float angle;
+ //! Radius of the shadow
+ float radius;
+ //! Intensity of the shadow
+ float intensity;
+ //! Height from the ground
+ float height;
+
+ EngineShadow()
+ {
+ hide = false;
+ objRank = 0;
+ angle = radius = intensity = height = 0.0f;
+ }
+};
+
+/**
+ \struct EngineGroundSpot
+ \brief A spot (large shadow) drawn on the ground by the graphics engine */
+struct EngineGroundSpot
+{
+ //! Color of the shadow
+ Gfx::Color color;
+ //! Min altitude
+ float min;
+ //! Max altitude
+ float max;
+ //! Transition area
+ float smooth;
+ //! Position for the shadow
+ Math::Vector pos;
+ //! Radius of the shadow
+ float radius;
+ //! Position of the shadow drawn
+ Math::Vector drawPos;
+ //! Radius of the shadow drawn
+ float drawRadius;
+
+ EngineGroundSpot()
+ {
+ min = max = smooth = radius = drawRadius = 0.0f;
+ }
+};
+
+/**
+ \enum EngineGroundMarkPhase
+ \brief Phase of life of an EngineGroundMark */
+enum EngineGroundMarkPhase
+{
+ //! Increase
+ ENG_GR_MARK_PHASE_INC = 1,
+ //! Fixed
+ ENG_GR_MARK_PHASE_FIX = 2,
+ //! Decrease
+ ENG_GR_MARK_PHASE_DEC = 2
+};
+
+/**
+ \struct EngineGroundMark
+ \brief A mark on ground drawn by the graphics engine */
+struct EngineGroundMark
+{
+ //! If true, draw mark
+ bool draw;
+ //! Phase of life
+ Gfx::EngineGroundMarkPhase phase;
+ //! Times for 3 life phases
+ float delay[3];
+ //! Fixed time
+ float fix;
+ //! Position for marks
+ Math::Vector pos;
+ //! Radius of marks
+ float radius;
+ //! Color intensity
+ float intensity;
+ //! Draw position for marks
+ Math::Vector drawPos;
+ //! Radius for marks
+ float drawRadius;
+ //! Draw intensity for marks
+ float drawIntensity;
+ //! X dimension of table
+ int dx;
+ //! Y dimension of table
+ int dy;
+ //! Pointer to the table
+ char* table;
+
+ EngineGroundMark()
+ {
+ draw = false;
+ delay[0] = delay[1] = delay[2] = 0.0f;
+ fix = radius = intensity = drawRadius = drawIntensity = 0.0f;
+ dx = dy = 0;
+ table = NULL;
+ }
+};
+
+/**
+ \enum EngineTextureMapping
+ \brief Type of texture mapping
+ */
+enum EngineTextureMapping
+{
+ ENG_TEX_MAPPING_X = 1,
+ ENG_TEX_MAPPING_Y = 2,
+ ENG_TEX_MAPPING_Z = 3,
+ ENG_TEX_MAPPING_1X = 4,
+ ENG_TEX_MAPPING_1Y = 5,
+ ENG_TEX_MAPPING_1Z = 6
+};
+
+
+/**
+ \enum EngineRenderState
+ \brief Render state of graphics engine
+
+ States are used for settings certain modes, for instance texturing and blending.
+ The enum is a bitmask and some of the states can be OR'd together. */
+enum EngineRenderState
+{
+ //! Normal opaque materials
+ ENG_RSTATE_NORMAL = 0,
+ //! The transparent texture (black = no)
+ ENG_RSTATE_TTEXTURE_BLACK = (1<<0),
+ //! The transparent texture (white = no)
+ ENG_RSTATE_TTEXTURE_WHITE = (1<<1),
+ //! The transparent diffuse color
+ ENG_RSTATE_TDIFFUSE = (1<<2),
+ //! Texture wrap
+ ENG_RSTATE_WRAP = (1<<3),
+ //! Texture borders with solid color
+ ENG_RSTATE_CLAMP = (1<<4),
+ //! Light texture (ambient max)
+ ENG_RSTATE_LIGHT = (1<<5),
+ //! Double black texturing
+ ENG_RSTATE_DUAL_BLACK = (1<<6),
+ //! Double white texturing
+ ENG_RSTATE_DUAL_WHITE = (1<<7),
+ //! Part 1 (no change in. MOD!)
+ ENG_RSTATE_PART1 = (1<<8),
+ //! Part 2
+ ENG_RSTATE_PART2 = (1<<9),
+ //! Part 3
+ ENG_RSTATE_PART3 = (1<<10),
+ //! Part 4
+ ENG_RSTATE_PART4 = (1<<11),
+ //! Double-sided face
+ ENG_RSTATE_2FACE = (1<<12),
+ //! Image using alpha channel
+ ENG_RSTATE_ALPHA = (1<<13),
+ //! Always use 2nd floor texturing
+ ENG_RSTATE_SECOND = (1<<14),
+ //! Causes the fog
+ ENG_RSTATE_FOG = (1<<15),
+ //! The transparent color (black = no)
+ ENG_RSTATE_TCOLOR_BLACK = (1<<16),
+ //! The transparent color (white = no)
+ ENG_RSTATE_TCOLOR_WHITE = (1<<17)
+};
+
+
+/**
+ \enum EngineMouseType
+ \brief Type of mouse cursor displayed in-game */
+enum EngineMouseType
+{
+ //! Normal cursor (arrow)
+ ENG_MOUSE_NORM = 0,
+ //! Busy
+ ENG_MOUSE_WAIT = 1,
+ //! Edit (I-beam)
+ ENG_MOUSE_EDIT = 2,
+ //! Hand
+ ENG_MOUSE_HAND = 3,
+ //! Small cross
+ ENG_MOUSE_CROSS = 4,
+ //! TODO: ?
+ ENG_MOUSE_SHOW = 5,
+ //! Crossed out sign
+ ENG_MOUSE_NO = 6,
+ //! Resize
+ ENG_MOUSE_MOVE = 7,
+ //! Resize horizontally
+ ENG_MOUSE_MOVEH = 8,
+ //! Resize vertically
+ ENG_MOUSE_MOVEV = 9,
+ //! Resize diagonally bottom-left to top-right
+ ENG_MOUSE_MOVED = 10,
+ //! Resize diagonally top-left to bottom-right
+ ENG_MOUSE_MOVEI = 11,
+ //! Scroll to the left
+ ENG_MOUSE_SCROLLL = 12,
+ //! Scroll to the right
+ ENG_MOUSE_SCROLLR = 13,
+ //! Scroll up
+ ENG_MOUSE_SCROLLU = 14,
+ //! Scroll down
+ ENG_MOUSE_SCROLLD = 15,
+ //! Larger crosshair
+ ENG_MOUSE_TARGET = 16,
+
+ //! Number of items in enum
+ ENG_MOUSE_COUNT
+};
+
+/**
+ \struct EngineMouse
+ \brief Information about mouse cursor */
+struct EngineMouse
+{
+ //! Index of texture element for 1st image
+ int icon1;
+ //! Index of texture element for 2nd image
+ int icon2;
+ //! Shadow texture part
+ int iconShadow;
+ //! Mode to render 1st image in
+ Gfx::EngineRenderState mode1;
+ //! Mode to render 2nd image in
+ Gfx::EngineRenderState mode2;
+ //! Hot point
+ Math::Point hotPoint;
+
+ EngineMouse(int icon1 = -1, int icon2 = -1, int iconShadow = -1,
+ Gfx::EngineRenderState mode1 = Gfx::ENG_RSTATE_NORMAL,
+ Gfx::EngineRenderState mode2 = Gfx::ENG_RSTATE_NORMAL,
+ Math::Point hotPoint = Math::Point())
+ {
+ this->icon1 = icon1;
+ this->icon2 = icon2;
+ this->iconShadow = iconShadow;
+ this->mode1 = mode1;
+ this->mode2 = mode2;
+ this->hotPoint = hotPoint;
+ }
+};
+
+
+/**
+ \class CEngine
+ \brief The graphics engine
+
+ This is the main class for graphics engine. It is responsible for drawing the 3D scene,
+ setting various render states, and facilitating the drawing of 2D interface.
+
+ It uses a lower-level CDevice object which is implementation-independent core engine.
+
+ \section Objecs Engine objects
+
+ The 3D scene is composed of objects which are basically collections of triangles forming
+ a surface or simply independent triangles in space. Objects are stored in the engine
+ as a tree structure which is composed of 5 tiers (EngineObjLevel1, EngineObjLevel2 and so on).
+ Each tier stores some data about object triangle, like textures or materials used.
+ Additional information on objects stored are in EngineObject structure.
+ Each object is uniquely identified by its rank.
+
+ ...
+ */
+class CEngine
+{
+public:
+ CEngine(CInstanceManager *iMan, CApplication *app);
+ ~CEngine();
+
+ //! Returns whether the device was initialized
+ bool GetWasInit();
+ //! Returns the last error encountered
+ std::string GetError();
+
+ //! Performs the first initialization, before a device was set
+ bool Create();
+ //! Frees all resources before exit
+ void Destroy();
+
+ //! Sets the device to be used
+ void SetDevice(Gfx::CDevice *device);
+ //! Returns the current device
+ Gfx::CDevice* GetDevice();
+
+ //! Performs initialization after a device was created and set
+ bool AfterDeviceSetInit();
+
+ //! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
+ void ResetAfterDeviceChanged();
+
+ void SetTerrain(Gfx::CTerrain* terrain);
+
+ //! Processes incoming event
+ bool ProcessEvent(const Event &event);
+
+ //! Renders a single frame
+ bool Render();
+
+
+ bool WriteProfile();
+
+ void SetPause(bool pause);
+ bool GetPause();
+
+ void SetMovieLock(bool lock);
+ bool GetMovieLock();
+
+ void SetShowStat(bool show);
+ bool GetShowStat();
+
+ void SetRenderEnable(bool enable);
+
+ int OneTimeSceneInit();
+ int InitDeviceObjects();
+ int DeleteDeviceObjects();
+ int RestoreSurfaces();
+ int FrameMove(float rTime);
+ void StepSimulation(float rTime);
+ int FinalCleanup();
+ void AddStatisticTriangle(int nb);
+ int GetStatisticTriangle();
+ void SetHiliteRank(int *rankList);
+ bool GetHilite(Math::Point &p1, Math::Point &p2);
+ bool GetSpriteCoord(int &x, int &y);
+ void SetInfoText(int line, char* text);
+ char* GetInfoText(int line);
+ void FirstExecuteAdapt(bool first);
+
+ bool GetFullScreen();
+
+ Math::Matrix* GetMatView();
+ Math::Matrix* GetMatLeftView();
+ Math::Matrix* GetMatRightView();
+
+ void TimeInit();
+ void TimeEnterGel();
+ void TimeExitGel();
+ float TimeGet();
+
+ int GetRestCreate();
+ int CreateObject();
+ void FlushObject();
+ bool DeleteObject(int objRank);
+ bool SetDrawWorld(int objRank, bool draw);
+ bool SetDrawFront(int objRank, bool draw);
+
+ bool AddTriangle(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat,
+ int state, std::string texName1, std::string texName2,
+ float min, float max, bool globalUpdate);
+ bool AddSurface(int objRank, Gfx::VertexTex2* vertex, int nb, const Gfx::Material &mat,
+ int state, std::string texName1, std::string texName2,
+ float min, float max, bool globalUpdate);
+ bool AddQuick(int objRank, Gfx::EngineObjLevel5* buffer,
+ std::string texName1, std::string texName2,
+ float min, float max, bool globalUpdate);
+ Gfx::EngineObjLevel5* SearchTriangle(int objRank, const Gfx::Material &mat,
+ int state, std::string texName1, std::string texName2,
+ float min, float max);
+
+ void ChangeLOD();
+ bool ChangeSecondTexture(int objRank, char* texName2);
+ int GetTotalTriangles(int objRank);
+ int GetTriangles(int objRank, float min, float max, Gfx::EngineTriangle* buffer, int size, float percent);
+ bool GetBBox(int objRank, Math::Vector &min, Math::Vector &max);
+ bool ChangeTextureMapping(int objRank, const Gfx::Material &mat, int state,
+ const std::string &texName1, const std::string &texName2,
+ float min, float max, Gfx::EngineTextureMapping mode,
+ float au, float bu, float av, float bv);
+ bool TrackTextureMapping(int objRank, const Gfx::Material &mat, int state,
+ const std::string &texName1, const std::string &texName2,
+ float min, float max, Gfx::EngineTextureMapping mode,
+ float pos, float factor, float tl, float ts, float tt);
+ bool SetObjectTransform(int objRank, const Math::Matrix &transform);
+ bool GetObjectTransform(int objRank, Math::Matrix &transform);
+ bool SetObjectType(int objRank, Gfx::EngineObjectType type);
+ Gfx::EngineObjectType GetObjectType(int objRank);
+ bool SetObjectTransparency(int objRank, float value);
+
+ bool ShadowCreate(int objRank);
+ void ShadowDelete(int objRank);
+ bool SetObjectShadowHide(int objRank, bool hide);
+ bool SetObjectShadowType(int objRank, Gfx::EngineShadowType type);
+ bool SetObjectShadowPos(int objRank, const Math::Vector &pos);
+ bool SetObjectShadowNormal(int objRank, const Math::Vector &n);
+ bool SetObjectShadowAngle(int objRank, float angle);
+ bool SetObjectShadowRadius(int objRank, float radius);
+ bool SetObjectShadowIntensity(int objRank, float intensity);
+ bool SetObjectShadowHeight(int objRank, float h);
+ float GetObjectShadowRadius(int objRank);
+
+ void GroundSpotFlush();
+ int GroundSpotCreate();
+ void GroundSpotDelete(int rank);
+ bool SetObjectGroundSpotPos(int rank, const Math::Vector &pos);
+ bool SetObjectGroundSpotRadius(int rank, float radius);
+ bool SetObjectGroundSpotColor(int rank, const Gfx::Color &color);
+ bool SetObjectGroundSpotMinMax(int rank, float min, float max);
+ bool SetObjectGroundSpotSmooth(int rank, float smooth);
+
+ int GroundMarkCreate(Math::Vector pos, float radius,
+ float delay1, float delay2, float delay3,
+ int dx, int dy, char* table);
+ bool GroundMarkDelete(int rank);
+
+ void Update();
+
+ void SetViewParams(const Math::Vector &eyePt, const Math::Vector &lookatPt,
+ const Math::Vector &upVec, float eyeDistance);
+
+ Gfx::Texture CreateTexture(const std::string &texName,
+ const Gfx::TextureCreateParams &params);
+ Gfx::Texture CreateTexture(const std::string &texName);
+ void DestroyTexture(const std::string &texName);
+
+ bool LoadTexture(const std::string &name, int stage = 0);
+ bool LoadAllTextures();
+
+ void SetLimitLOD(int rank, float limit);
+ float GetLimitLOD(int rank, bool last=false);
+
+ void SetTerrainVision(float vision);
+
+ void SetGroundSpot(bool mode);
+ bool GetGroundSpot();
+ void SetShadow(bool mode);
+ bool GetShadow();
+ void SetDirty(bool mode);
+ bool GetDirty();
+ void SetFog(bool mode);
+ bool GetFog();
+ bool GetStateColor();
+
+ void SetSecondTexture(int texNum);
+ int GetSecondTexture();
+
+ void SetRankView(int rank);
+ int GetRankView();
+
+ void SetDrawWorld(bool draw);
+ void SetDrawFront(bool draw);
+
+ void SetAmbientColor(const Gfx::Color &color, int rank = 0);
+ Gfx::Color GetAmbientColor(int rank = 0);
+
+ void SetWaterAddColor(const Gfx::Color &color);
+ Gfx::Color GetWaterAddColor();
+
+ void SetFogColor(const Gfx::Color &color, int rank = 0);
+ Gfx::Color GetFogColor(int rank = 0);
+
+ void SetDeepView(float length, int rank = 0, bool ref=false);
+ float GetDeepView(int rank = 0);
+
+ void SetFogStart(float start, int rank = 0);
+ float GetFogStart(int rank = 0);
+
+ void SetBackground(const std::string &name, Gfx::Color up = Gfx::Color(), Gfx::Color down = Gfx::Color(),
+ Gfx::Color cloudUp = Gfx::Color(), Gfx::Color cloudDown = Gfx::Color(),
+ bool full = false, bool quarter = false);
+ void GetBackground(const std::string &name, Gfx::Color &up, Gfx::Color &down,
+ Gfx::Color &cloudUp, Gfx::Color &cloudDown,
+ bool &full, bool &quarter);
+ void SetFrontsizeName(char *name);
+ void SetOverFront(bool front);
+ void SetOverColor(const Gfx::Color &color = Gfx::Color(), int mode = ENG_RSTATE_TCOLOR_BLACK);
+
+ void SetParticleDensity(float value);
+ float GetParticleDensity();
+ float ParticleAdapt(float factor);
+
+ void SetClippingDistance(float value);
+ float GetClippingDistance();
+
+ void SetObjectDetail(float value);
+ float GetObjectDetail();
+
+ void SetGadgetQuantity(float value);
+ float GetGadgetQuantity();
+
+ void SetTextureQuality(int value);
+ int GetTextureQuality();
+
+ void SetTotoMode(bool present);
+ bool GetTotoMode();
+
+ void SetLensMode(bool present);
+ bool GetLensMode();
+
+ void SetWaterMode(bool present);
+ bool GetWaterMode();
+
+ void SetLightingMode(bool present);
+ bool GetLightingMode();
+
+ void SetSkyMode(bool present);
+ bool GetSkyMode();
+
+ void SetBackForce(bool present);
+ bool GetBackForce();
+
+ void SetPlanetMode(bool present);
+ bool GetPlanetMode();
+
+ void SetLightMode(bool present);
+ bool GetLightMode();
+
+ void SetEditIndentMode(bool autoIndent);
+ bool GetEditIndentMode();
+
+ void SetEditIndentValue(int value);
+ int GetEditIndentValue();
+
+ void SetSpeed(float speed);
+ float GetSpeed();
+
+ void SetTracePrecision(float factor);
+ float GetTracePrecision();
+
+ void SetFocus(float focus);
+ float GetFocus();
+ Math::Vector GetEyePt();
+ Math::Vector GetLookatPt();
+ float GetEyeDirH();
+ float GetEyeDirV();
+ Math::Point GetDim();
+ void UpdateMatProj();
+
+ void ApplyChange();
+
+ void FlushPressKey();
+ void ResetKey();
+ void SetKey(int keyRank, int option, int key);
+ int GetKey(int keyRank, int option);
+
+ void SetJoystick(bool enable);
+ bool GetJoystick();
+
+ void SetDebugMode(bool mode);
+ bool GetDebugMode();
+ bool GetSetupMode();
+
+ bool IsVisiblePoint(const Math::Vector &pos);
+
+ int DetectObject(Math::Point mouse);
+ void SetState(int state, Gfx::Color color = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f));
+ void SetTexture(const std::string &name, int stage = 0);
+ void SetMaterial(const Gfx::Material &mat);
+
+ void SetMouseVisible(bool show);
+ bool GetMouseVisible();
+ void SetMousePos(Math::Point pos);
+ Math::Point GetMousePos();
+ void SetMouseType(Gfx::EngineMouseType type);
+ Gfx::EngineMouseType GetMouseType();
+
+ CText* GetText();
+
+ bool ChangeColor(char *name, Gfx::Color colorRef1, Gfx::Color colorNew1,
+ Gfx::Color colorRef2, Gfx::Color colorNew2,
+ float tolerance1, float tolerance2,
+ Math::Point ts, Math::Point ti,
+ Math::Point *pExclu=0, float shift=0.0f, bool hSV=false);
+ bool OpenImage(char *name);
+ bool CopyImage();
+ bool LoadImage();
+ bool ScrollImage(int dx, int dy);
+ bool SetDot(int x, int y, Gfx::Color color);
+ bool CloseImage();
+ bool WriteScreenShot(char *filename, int width, int height);
+ //bool GetRenderDC(HDC &hDC);
+ //bool ReleaseRenderDC(HDC &hDC);
+ //PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp);
+ //bool CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);
+
+protected:
+
+ void SetUp3DView();
+ bool Draw3DScene();
+
+ void SetUpInterfaceView();
+ bool DrawInterface();
+
+ void DrawGroundSpot();
+ void DrawShadow();
+ void DrawBackground();
+ void DrawBackgroundGradient(Gfx::Color up, Gfx::Color down);
+ void DrawBackgroundImageQuarter(Math::Point p1, Math::Point p2, char *name);
+ void DrawBackgroundImage();
+ void DrawPlanet();
+ void DrawFrontsize();
+ void DrawOverColor();
+ void DrawHilite();
+ void DrawMouse();
+ void DrawMouseSprite(Math::Point pos, Math::Point dim, int icon);
+
+ /*
+ Gfx::ObjLevel2* AddLevel1(Gfx::ObjLevel1 *&p1, char* texName1, char* texName2);
+ Gfx::ObjLevel3* AddLevel2(Gfx::ObjLevel2 *&p2, int objRank);
+ Gfx::ObjLevel4* AddLevel3(Gfx::ObjLevel3 *&p3, float min, float max);
+ Gfx::ObjLevel5* AddLevel4(Gfx::ObjLevel4 *&p4, int reserve);
+ Gfx::ObjLevel6* AddLevel5(Gfx::ObjLevel5 *&p5, Gfx::TriangleType type, const Gfx::Material &mat, int state, int nb);*/
+
+ bool IsVisible(int objRank);
+ bool DetectBBox(int objRank, Math::Point mouse);
+ bool GetBBox2D(int objRank, Math::Point &min, Math::Point &max);
+ bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2 *triangle, int objRank, float &dist);
+ bool TransformPoint(Math::Vector &p2D, int objRank, Math::Vector p3D);
+ void ComputeDistance();
+ void UpdateGeometry();
+
+protected:
+ CInstanceManager* m_iMan;
+ CApplication* m_app;
+ CSound* m_sound;
+ Gfx::CDevice* m_device;
+ Gfx::CText* m_text;
+ Gfx::CLightManager* m_lightMan;
+ Gfx::CParticle* m_particle;
+ Gfx::CWater* m_water;
+ Gfx::CCloud* m_cloud;
+ Gfx::CLightning* m_lightning;
+ Gfx::CPlanet* m_planet;
+ Gfx::CTerrain* m_terrain;
+
+ bool m_wasInit;
+ std::string m_error;
+
+ //! Whether to show stats (FPS, etc)
+ bool m_showStats;
+
+ int m_blackSrcBlend[2];
+ int m_blackDestBlend[2];
+ int m_whiteSrcBlend[2];
+ int m_whiteDestBlend[2];
+ int m_diffuseSrcBlend[2];
+ int m_diffuseDestBlend[2];
+ int m_alphaSrcBlend[2];
+ int m_alphaDestBlend[2];
+
+ Math::Matrix m_matProj;
+ Math::Matrix m_matLeftView;
+ Math::Matrix m_matRightView;
+ Math::Matrix m_matView;
+ float m_focus;
+
+ Math::Matrix m_matWorldInterface;
+ Math::Matrix m_matProjInterface;
+ Math::Matrix m_matViewInterface;
+
+ long m_baseTime;
+ long m_stopTime;
+ float m_absTime;
+ float m_lastTime;
+ float m_speed;
+ bool m_pause;
+ bool m_render;
+ bool m_movieLock;
+
+ //! Current size of window
+ Math::IntSize m_size;
+ Math::IntSize m_lastSize;
+
+ std::vector<Gfx::EngineObjLevel1> m_objectTree;
+ std::vector<Gfx::EngineObject> m_objects;
+ std::vector<Gfx::EngineShadow> m_shadow;
+ std::vector<Gfx::EngineGroundSpot> m_groundSpot;
+ Gfx::EngineGroundMark m_groundMark;
+
+ Math::Vector m_eyePt;
+ Math::Vector m_lookatPt;
+ float m_eyeDirH;
+ float m_eyeDirV;
+ int m_rankView;
+ Gfx::Color m_ambientColor[2];
+ Gfx::Color m_backColor[2];
+ Gfx::Color m_fogColor[2];
+ float m_deepView[2];
+ float m_fogStart[2];
+ Gfx::Color m_waterAddColor;
+ int m_statisticTriangle;
+ bool m_updateGeometry;
+ //char m_infoText[10][200];
+ int m_alphaMode;
+ bool m_stateColor;
+ bool m_forceStateColor;
+ bool m_groundSpotVisible;
+ bool m_shadowVisible;
+ bool m_dirty;
+ bool m_fog;
+ bool m_firstGroundSpot;
+ int m_secondTexNum;
+ std::string m_backgroundName;
+ Gfx::Color m_backgroundColorUp;
+ Gfx::Color m_backgroundColorDown;
+ Gfx::Color m_backgroundCloudUp;
+ Gfx::Color m_backgroundCloudDown;
+ bool m_backgroundFull;
+ bool m_backgroundQuarter;
+ bool m_overFront;
+ Gfx::Color m_overColor;
+ int m_overMode;
+ std::string m_frontsizeName;
+ bool m_drawWorld;
+ bool m_drawFront;
+ float m_limitLOD[2];
+ float m_particuleDensity;
+ float m_clippingDistance;
+ float m_lastClippingDistance;
+ float m_objectDetail;
+ float m_lastObjectDetail;
+ float m_terrainVision;
+ float m_gadgetQuantity;
+ int m_textureQuality;
+ bool m_totoMode;
+ bool m_lensMode;
+ bool m_waterMode;
+ bool m_skyMode;
+ bool m_backForce;
+ bool m_planetMode;
+ bool m_lightMode;
+ bool m_editIndentMode;
+ int m_editIndentValue;
+ float m_tracePrecision;
+
+ int m_hiliteRank[100];
+ bool m_hilite;
+ Math::Point m_hiliteP1;
+ Math::Point m_hiliteP2;
+
+ int m_lastState;
+ Gfx::Color m_lastColor;
+ char m_lastTexture[2][50];
+ Gfx::Material m_lastMaterial;
+
+ std::string m_texPath;
+ Gfx::TextureCreateParams m_defaultTexParams;
+
+ std::map<std::string, Gfx::Texture> m_texNameMap;
+ std::map<Gfx::Texture, std::string> m_revTexNameMap;
+
+ Gfx::EngineMouse m_mice[Gfx::ENG_MOUSE_COUNT];
+ Gfx::Texture m_miceTexture;
+ Math::Point m_mouseSize;
+ Gfx::EngineMouseType m_mouseType;
+ Math::Point m_mousePos;
+ bool m_mouseVisible;
+
+ //LPDIRECTDRAWSURFACE7 m_imageSurface;
+ //DDSURFACEDESC2 m_imageDDSD;
+ //WORD* m_imageCopy;
+ //int m_imageDX;
+ //int m_imageDY;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp
new file mode 100644
index 0000000..9e15b5a
--- /dev/null
+++ b/src/graphics/engine/lightman.cpp
@@ -0,0 +1,416 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// light.cpp
+
+#include "graphics/engine/lightman.h"
+
+#include "common/iman.h"
+#include "graphics/core/device.h"
+#include "math/geometry.h"
+
+#include <cmath>
+
+
+void Gfx::LightProgression::Init(float value)
+{
+ starting = value;
+ ending = value;
+ current = value;
+ progress = 0.0f;
+ speed = 100.0f;
+}
+
+void Gfx::LightProgression::Update(float rTime)
+{
+ if (speed < 100.0f)
+ {
+ if (progress < 1.0f)
+ {
+ progress += speed * rTime;
+ if (progress > 1.0f)
+ progress = 1.0f;
+ }
+
+ current = starting + progress * (ending - starting);
+ }
+ else
+ {
+ current = ending;
+ }
+}
+
+void Gfx::LightProgression::SetTarget(float value)
+{
+ starting = current;
+ ending = value;
+ progress = 0.0f;
+}
+
+
+Gfx::DynamicLight::DynamicLight()
+{
+ used = enabled = false;
+}
+
+
+
+Gfx::CLightManager::CLightManager(CInstanceManager* iMan, Gfx::CEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_LIGHT, this);
+
+ m_device = NULL;
+ m_engine = engine;
+
+ m_time = 0.0f;
+}
+
+Gfx::CLightManager::~CLightManager()
+{
+ m_iMan->DeleteInstance(CLASS_LIGHT, this);
+
+ m_iMan = NULL;
+ m_device = NULL;
+ m_engine = NULL;
+}
+
+void Gfx::CLightManager::SetDevice(Gfx::CDevice* device)
+{
+ m_device = device;
+
+ m_dynLights = std::vector<Gfx::DynamicLight>(m_device->GetMaxLightCount(), Gfx::DynamicLight());
+}
+
+void Gfx::CLightManager::FlushLights()
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ m_dynLights[i].used = false;
+ m_device->SetLightEnabled(i, false);
+ }
+}
+
+/** Returns the index of light created or -1 if all lights are used. */
+int Gfx::CLightManager::CreateLight()
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (m_dynLights[i].used) continue;
+
+ m_dynLights[i] = Gfx::DynamicLight();
+
+ m_dynLights[i].used = true;
+ m_dynLights[i].enabled = true;
+
+ m_dynLights[i].includeType = Gfx::ENG_OBJTYPE_NULL;
+ m_dynLights[i].excludeType = Gfx::ENG_OBJTYPE_NULL;
+
+ m_dynLights[i].light.type = Gfx::LIGHT_DIRECTIONAL;
+ m_dynLights[i].light.diffuse = Gfx::Color(0.5f, 0.5f, 0.5f);
+ m_dynLights[i].light.position = Math::Vector(-100.0f, 100.0f, -100.0f);
+ m_dynLights[i].light.direction = Math::Vector( 1.0f, -1.0f, 1.0f);
+
+ m_dynLights[i].intensity.Init(1.0f); // maximum
+ m_dynLights[i].colorRed.Init(0.5f);
+ m_dynLights[i].colorGreen.Init(0.5f);
+ m_dynLights[i].colorBlue.Init(0.5f); // gray
+
+ return i;
+ }
+
+ return -1;
+}
+
+bool Gfx::CLightManager::DeleteLight(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].used = false;
+ m_device->SetLightEnabled(lightRank, false);
+
+ return true;
+}
+
+// Specifies a light.
+
+bool Gfx::CLightManager::SetLight(int lightRank, const Gfx::Light &light)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].light = light;
+
+ m_dynLights[lightRank].colorRed.Init(m_dynLights[lightRank].light.diffuse.r);
+ m_dynLights[lightRank].colorGreen.Init(m_dynLights[lightRank].light.diffuse.g);
+ m_dynLights[lightRank].colorBlue.Init(m_dynLights[lightRank].light.diffuse.b);
+
+ return true;
+}
+
+bool Gfx::CLightManager::GetLight(int lightRank, Gfx::Light &light)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ light = m_dynLights[lightRank].light;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightEnabled(int lightRank, bool enabled)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].enabled = enabled;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightIncludeType(int lightRank, Gfx::EngineObjectType type)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].includeType = type;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightExcludeType(int lightRank, Gfx::EngineObjectType type)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].excludeType = type;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightPos(int lightRank, const Math::Vector &pos)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].light.position = pos;
+ return true;
+}
+
+Math::Vector Gfx::CLightManager::GetLightPos(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return Math::Vector(0.0f, 0.0f, 0.0f);
+
+ return m_dynLights[lightRank].light.position;
+}
+
+bool Gfx::CLightManager::SetLightDir(int lightRank, const Math::Vector &dir)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].light.direction = dir;
+ return true;
+}
+
+Math::Vector Gfx::CLightManager::GetLightDir(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return Math::Vector(0.0f, 0.0f, 0.0f);
+
+ return m_dynLights[lightRank].light.direction;
+}
+
+bool Gfx::CLightManager::SetLightIntensitySpeed(int lightRank, float speed)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].intensity.speed = speed;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightIntensity(int lightRank, float value)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].intensity.SetTarget(value);
+ return true;
+}
+
+float Gfx::CLightManager::GetLightIntensity(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return 0.0f;
+
+ return m_dynLights[lightRank].intensity.current;
+}
+
+
+bool Gfx::CLightManager::SetLightColorSpeed(int lightRank, float speed)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].colorRed.speed = speed;
+ m_dynLights[lightRank].colorGreen.speed = speed;
+ m_dynLights[lightRank].colorBlue.speed = speed;
+ return true;
+}
+
+bool Gfx::CLightManager::SetLightColor(int lightRank, const Gfx::Color &color)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return false;
+
+ m_dynLights[lightRank].colorRed.SetTarget(color.r);
+ m_dynLights[lightRank].colorGreen.SetTarget(color.g);
+ m_dynLights[lightRank].colorBlue.SetTarget(color.b);
+ return true;
+}
+
+Gfx::Color Gfx::CLightManager::GetLightColor(int lightRank)
+{
+ if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
+ return Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f);
+
+ Gfx::Color color;
+ color.r = m_dynLights[lightRank].colorRed.current;
+ color.g = m_dynLights[lightRank].colorGreen.current;
+ color.b = m_dynLights[lightRank].colorBlue.current;
+ return color;
+}
+
+void Gfx::CLightManager::AdaptLightColor(const Gfx::Color &color, float factor)
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+
+ Gfx::Color value;
+ value.r = m_dynLights[i].colorRed.current;
+ value.g = m_dynLights[i].colorGreen.current;
+ value.b = m_dynLights[i].colorBlue.current;
+
+ value.r += color.r * factor;
+ value.g += color.g * factor;
+ value.b += color.b * factor;
+
+ m_dynLights[i].colorRed.Init(value.r);
+ m_dynLights[i].colorGreen.Init(value.g);
+ m_dynLights[i].colorBlue.Init(value.b);
+ }
+
+ UpdateLights();
+}
+
+void Gfx::CLightManager::UpdateProgression(float rTime)
+{
+ if (m_engine->GetPause())
+ return;
+
+ m_time += rTime;
+
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+
+ m_dynLights[i].intensity.Update(rTime);
+ m_dynLights[i].colorRed.Update(rTime);
+ m_dynLights[i].colorGreen.Update(rTime);
+ m_dynLights[i].colorBlue.Update(rTime);
+
+ if (m_dynLights[i].includeType == Gfx::ENG_OBJTYPE_QUARTZ)
+ {
+ m_dynLights[i].light.direction.x = sinf(1.0f * (m_time + i*Math::PI*0.5f));
+ m_dynLights[i].light.direction.z = cosf(1.1f * (m_time + i*Math::PI*0.5f));
+ m_dynLights[i].light.direction.y = -1.0f + 0.5f * cosf((m_time + i*Math::PI*0.5f)*2.7f);
+ }
+
+ if (m_dynLights[i].includeType == Gfx::ENG_OBJTYPE_METAL)
+ {
+ Math::Vector dir = m_engine->GetEyePt() - m_engine->GetLookatPt();
+ float angle = Math::RotateAngle(dir.x, dir.z);
+ angle += Math::PI * 0.5f * i;
+ m_dynLights[i].light.direction.x = sinf(2.0f * angle);
+ m_dynLights[i].light.direction.z = cosf(2.0f * angle);
+ }
+ }
+}
+
+
+void Gfx::CLightManager::UpdateLights()
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+
+ bool enabled = m_dynLights[i].enabled;
+ if (m_dynLights[i].intensity.current == 0.0f)
+ enabled = false;
+
+ if (enabled)
+ {
+ float value = m_dynLights[i].colorRed.current * m_dynLights[i].intensity.current;
+ m_dynLights[i].light.diffuse.r = value;
+
+ value = m_dynLights[i].colorGreen.current * m_dynLights[i].intensity.current;
+ m_dynLights[i].light.diffuse.g = value;
+
+ value = m_dynLights[i].colorBlue.current * m_dynLights[i].intensity.current;
+ m_dynLights[i].light.diffuse.b = value;
+
+ m_device->SetLight(i, m_dynLights[i].light);
+ m_device->SetLightEnabled(i, enabled);
+ }
+ else
+ {
+ m_dynLights[i].light.diffuse.r = 0.0f;
+ m_dynLights[i].light.diffuse.g = 0.0f;
+ m_dynLights[i].light.diffuse.b = 0.0f;
+
+ m_device->SetLightEnabled(i, enabled);
+ }
+ }
+}
+
+void Gfx::CLightManager::UpdateLightsEnableState(Gfx::EngineObjectType type)
+{
+ for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++)
+ {
+ if (! m_dynLights[i].used)
+ continue;
+ if (! m_dynLights[i].enabled)
+ continue;
+ if (m_dynLights[i].intensity.current == 0.0f)
+ continue;
+
+ if (m_dynLights[i].includeType != Gfx::ENG_OBJTYPE_NULL)
+ {
+ bool enabled = (m_dynLights[i].includeType == type);
+ m_device->SetLightEnabled(i, enabled);
+ }
+
+ if (m_dynLights[i].excludeType != Gfx::ENG_OBJTYPE_NULL)
+ {
+ bool enabled = (m_dynLights[i].excludeType != type);
+ m_device->SetLightEnabled(i, enabled);
+ }
+ }
+}
diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h
new file mode 100644
index 0000000..8272125
--- /dev/null
+++ b/src/graphics/engine/lightman.h
@@ -0,0 +1,181 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// lightman.h
+
+#pragma once
+
+
+#include "graphics/core/color.h"
+#include "graphics/core/light.h"
+#include "graphics/engine/engine.h"
+#include "math/vector.h"
+
+
+namespace Gfx {
+
+/**
+ \struct LightProgression
+ \brief Describes the progression of light parameters change */
+struct LightProgression
+{
+ //! Starting value
+ float starting;
+ //! Ending (destination) value
+ float ending;
+ //! Current value
+ float current;
+ //! Progress from start to end
+ float progress;
+ //! Speed of progression
+ float speed;
+
+ LightProgression()
+ {
+ starting = ending = current = progress = speed = 0.0f;
+ }
+
+ //! Initializes the progression
+ void Init(float value);
+
+ //! Updates the progression
+ void Update(float rTime);
+
+ //! Sets the new end value (starting is set to current)
+ void SetTarget(float value);
+};
+
+/**
+ \struct DynamicLight
+ \brief Dynamic light in 3D scene
+
+ It is an extension over standard light properties. Added are dynamic progressions for light
+ colors and intensity and types of objects included/excluded in lighting. */
+struct DynamicLight
+{
+ //! Whether the light is used
+ bool used;
+ //! Whether the light is turned on
+ bool enabled;
+
+ //! Configuration of the light
+ Gfx::Light light;
+
+ //! Progression of intensity [0, 1]
+ Gfx::LightProgression intensity;
+ //! Progression of red diffuse color
+ Gfx::LightProgression colorRed;
+ //! Progression of green diffuse color
+ Gfx::LightProgression colorGreen;
+ //! Progression of blue diffuse color
+ Gfx::LightProgression colorBlue;
+
+ //! Type of objects included in lighting with this light; if Gfx::ENG_OBJTYPE_NULL is used, it is ignored
+ Gfx::EngineObjectType includeType;
+ //! Type of objects excluded from lighting with this light; if Gfx::ENG_OBJTYPE_NULL is used, it is ignored
+ Gfx::EngineObjectType excludeType;
+
+ DynamicLight();
+};
+
+/**
+ \class CLightManager
+ \brief Manager for dynamic lights in 3D scene
+
+ (Old CLight class)
+
+ The class is responsible for managing dynamic lights (struct Gfx::DynamicLight) used in 3D scene.
+ The dynamic lights are created, updated and deleted through the class' interface.
+
+ Number of available lights depends on graphics device used. Class allocates vector
+ for the total number of lights, but only some are used.
+ */
+class CLightManager
+{
+public:
+ //! Constructor
+ CLightManager(CInstanceManager *iMan, Gfx::CEngine* engine);
+ //! Destructor
+ virtual ~CLightManager();
+
+ //! Sets the device to be used
+ void SetDevice(Gfx::CDevice* device);
+
+ //! Clears and disables all lights
+ void FlushLights();
+ //! Creates a new dynamic light and returns its index (lightRank)
+ int CreateLight();
+ //! Deletes and disables the given dynamic light
+ bool DeleteLight(int lightRank);
+ //! Sets the light parameters for dynamic light
+ bool SetLight(int lightRank, const Gfx::Light &light);
+ //! Returns the light parameters for given dynamic light
+ bool GetLight(int lightRank, Gfx::Light &light);
+ //! Enables/disables the given dynamic light
+ bool SetLightEnabled(int lightRank, bool enable);
+
+ //! Sets what objects are included in given dynamic light
+ bool SetLightIncludeType(int lightRank, Gfx::EngineObjectType type);
+ //! Sets what objects are excluded from given dynamic light
+ bool SetLightExcludeType(int lightRank, Gfx::EngineObjectType type);
+
+ //! Sets the position of dynamic light
+ bool SetLightPos(int lightRank, const Math::Vector &pos);
+ //! Returns the position of dynamic light
+ Math::Vector GetLightPos(int lightRank);
+
+ //! Sets the direction of dynamic light
+ bool SetLightDir(int lightRank, const Math::Vector &dir);
+ //! Returns the direction of dynamic light
+ Math::Vector GetLightDir(int lightRank);
+
+ //! Sets the destination intensity for dynamic light's intensity progression
+ bool SetLightIntensity(int lightRank, float value);
+ //! Returns the current light intensity
+ float GetLightIntensity(int lightRank);
+ //! Sets the rate of change for dynamic light intensity
+ bool SetLightIntensitySpeed(int lightRank, float speed);
+
+ //! Adjusts the color of all dynamic lights
+ void AdaptLightColor(const Gfx::Color &color, float factor);
+
+ //! Sets the destination color for dynamic light's color progression
+ bool SetLightColor(int lightRank, const Gfx::Color &color);
+ //! Returns current light color
+ Gfx::Color GetLightColor(int lightRank);
+ //! Sets the rate of change for dynamic light colors (RGB)
+ bool SetLightColorSpeed(int lightRank, float speed);
+
+ //! Updates progression of dynamic lights
+ void UpdateProgression(float rTime);
+ //! Updates (recalculates) all dynamic lights
+ void UpdateLights();
+ //! Enables or disables dynamic lights affecting the given object type
+ void UpdateLightsEnableState(Gfx::EngineObjectType type);
+
+protected:
+ CInstanceManager* m_iMan;
+ CEngine* m_engine;
+ CDevice* m_device;
+
+ //! Current time
+ float m_time;
+ //! List of dynamic lights
+ std::vector<Gfx::DynamicLight> m_dynLights;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/lightning.cpp b/src/graphics/engine/lightning.cpp
index 076fcb4..4db5511 100644
--- a/src/graphics/common/lightning.cpp
+++ b/src/graphics/engine/lightning.cpp
@@ -17,7 +17,7 @@
// lightning.cpp (aka blitz.cpp)
-#include "graphics/common/lightning.h"
+#include "graphics/engine/lightning.h"
// TODO implementation
diff --git a/src/graphics/common/lightning.h b/src/graphics/engine/lightning.h
index 957344c..957344c 100644
--- a/src/graphics/common/lightning.h
+++ b/src/graphics/engine/lightning.h
diff --git a/src/graphics/engine/modelfile.cpp b/src/graphics/engine/modelfile.cpp
new file mode 100644
index 0000000..844958f
--- /dev/null
+++ b/src/graphics/engine/modelfile.cpp
@@ -0,0 +1,841 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// modelfile.cpp (aka modfile.cpp)
+
+#include "graphics/engine/modelfile.h"
+
+#include "common/iman.h"
+#include "common/ioutils.h"
+#include "common/logger.h"
+#include "common/stringutils.h"
+#include "math/geometry.h"
+
+#include <string.h>
+
+#include <fstream>
+
+
+//! How big the triangle vector is by default
+const int TRIANGLE_PREALLOCATE_COUNT = 2000;
+
+/**
+ \struct ModelHeader
+ \brief Header info for model file
+ */
+struct ModelHeader
+{
+ //! Revision number
+ int revision;
+ //! Version number
+ int version;
+ //! Total number of vertices
+ int totalVertices;
+ //! Reserved area
+ int reserved[10];
+
+ ModelHeader()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+struct OldModelTriangle1
+{
+ char used;
+ char selected;
+ Gfx::Vertex p1;
+ Gfx::Vertex p2;
+ Gfx::Vertex p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+
+ OldModelTriangle1()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+struct OldModelTriangle2
+{
+ char used;
+ char selected;
+ Gfx::Vertex p1;
+ Gfx::Vertex p2;
+ Gfx::Vertex p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ long state;
+ short reserved1;
+ short reserved2;
+ short reserved3;
+ short reserved4;
+ OldModelTriangle2()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+struct NewModelTriangle
+{
+ char used;
+ char selected;
+ Gfx::VertexTex2 p1;
+ Gfx::VertexTex2 p2;
+ Gfx::VertexTex2 p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ long state;
+ short texNum2;
+ short reserved2;
+ short reserved3;
+ short reserved4;
+
+ NewModelTriangle()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+Gfx::Vertex ReadBinaryVertex(std::istream &stream)
+{
+ Gfx::Vertex result;
+
+ result.coord.x = IOUtils::ReadBinaryFloat(stream);
+ result.coord.y = IOUtils::ReadBinaryFloat(stream);
+ result.coord.z = IOUtils::ReadBinaryFloat(stream);
+ result.normal.x = IOUtils::ReadBinaryFloat(stream);
+ result.normal.y = IOUtils::ReadBinaryFloat(stream);
+ result.normal.z = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.x = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.y = IOUtils::ReadBinaryFloat(stream);
+
+ return result;
+}
+
+void WriteBinaryVertex(Gfx::Vertex vertex, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+}
+
+Gfx::VertexTex2 ReadBinaryVertexTex2(std::istream &stream)
+{
+ Gfx::VertexTex2 result;
+
+ result.coord.x = IOUtils::ReadBinaryFloat(stream);
+ result.coord.y = IOUtils::ReadBinaryFloat(stream);
+ result.coord.z = IOUtils::ReadBinaryFloat(stream);
+ result.normal.x = IOUtils::ReadBinaryFloat(stream);
+ result.normal.y = IOUtils::ReadBinaryFloat(stream);
+ result.normal.z = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.x = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord.y = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord2.x = IOUtils::ReadBinaryFloat(stream);
+ result.texCoord2.y = IOUtils::ReadBinaryFloat(stream);
+
+ return result;
+}
+
+void WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord2.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord2.y, stream);
+}
+
+Gfx::Material ReadBinaryMaterial(std::istream &stream)
+{
+ Gfx::Material result;
+
+ result.diffuse.r = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.g = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.b = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.a = IOUtils::ReadBinaryFloat(stream);
+
+ result.ambient.r = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.g = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.b = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.a = IOUtils::ReadBinaryFloat(stream);
+
+ result.specular.r = IOUtils::ReadBinaryFloat(stream);
+ result.specular.g = IOUtils::ReadBinaryFloat(stream);
+ result.specular.b = IOUtils::ReadBinaryFloat(stream);
+ result.specular.a = IOUtils::ReadBinaryFloat(stream);
+
+ /* emissive.r = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.g = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.b = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.a = */ IOUtils::ReadBinaryFloat(stream);
+
+ /* power = */ IOUtils::ReadBinaryFloat(stream);
+
+ return result;
+}
+
+void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(material.diffuse.r, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.g, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.b, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.a, stream);
+
+ IOUtils::WriteBinaryFloat(material.ambient.r, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.g, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.b, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.a, stream);
+
+ IOUtils::WriteBinaryFloat(material.specular.r, stream);
+ IOUtils::WriteBinaryFloat(material.specular.g, stream);
+ IOUtils::WriteBinaryFloat(material.specular.b, stream);
+ IOUtils::WriteBinaryFloat(material.specular.a, stream);
+
+ /* emissive.r */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.g */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.b */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.a */ IOUtils::WriteBinaryFloat(0.0f, stream);
+
+ /* power */ IOUtils::WriteBinaryFloat(0.0f, stream);
+}
+
+Gfx::ModelTriangle::ModelTriangle()
+{
+ min = 0.0f;
+ max = 0.0f;
+ state = 0L;
+}
+
+
+Gfx::CModelFile::CModelFile(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+
+ m_engine = static_cast<CEngine*>(m_iMan->SearchInstance(CLASS_ENGINE));
+
+ m_triangles.reserve(TRIANGLE_PREALLOCATE_COUNT);
+}
+
+Gfx::CModelFile::~CModelFile()
+{
+}
+
+std::string Gfx::CModelFile::GetError()
+{
+ return m_error;
+}
+
+
+bool Gfx::CModelFile::ReadModel(const std::string &filename, bool edit, bool meta)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ std::ifstream stream;
+ stream.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (! stream.good())
+ {
+ m_error = std::string("Could not open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return ReadModel(stream, edit, meta);
+}
+
+bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ // FIXME: for now, reading models only from files, not metafile
+
+ ModelHeader header;
+
+ header.revision = IOUtils::ReadBinary<4, int>(stream);
+ header.version = IOUtils::ReadBinary<4, int>(stream);
+ header.totalVertices = IOUtils::ReadBinary<4, int>(stream);
+ for (int i = 0; i < 10; ++i)
+ header.reserved[i] = IOUtils::ReadBinary<4, int>(stream);
+
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model file header";
+ return false;
+ }
+
+ // Old model version #1
+ if ( (header.revision == 1) && (header.version == 0) )
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ OldModelTriangle1 t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ t.p1 = ReadBinaryVertex(stream);
+ t.p2 = ReadBinaryVertex(stream);
+ t.p3 = ReadBinaryVertex(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1.FromVertex(t.p1);
+ triangle.p2.FromVertex(t.p2);
+ triangle.p3.FromVertex(t.p3);
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ triangle.min = t.min;
+ triangle.max = t.max;
+
+ m_triangles.push_back(triangle);
+ }
+ }
+ else if ( header.revision == 1 && header.version == 1 )
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ OldModelTriangle2 t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ t.p1 = ReadBinaryVertex(stream);
+ t.p2 = ReadBinaryVertex(stream);
+ t.p3 = ReadBinaryVertex(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, long>(stream);
+
+ t.reserved1 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved2 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1.FromVertex(t.p1);
+ triangle.p2.FromVertex(t.p2);
+ triangle.p3.FromVertex(t.p3);
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
+
+ m_triangles.push_back(triangle);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ NewModelTriangle t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ /* padding */ IOUtils::ReadBinary<2, unsigned int>(stream);
+
+ t.p1 = ReadBinaryVertexTex2(stream);
+ t.p2 = ReadBinaryVertexTex2(stream);
+ t.p3 = ReadBinaryVertexTex2(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, long>(stream);
+ t.texNum2 = IOUtils::ReadBinary<2, short>(stream);
+
+ t.reserved2 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1 = t.p1;
+ triangle.p2 = t.p2;
+ triangle.p3 = t.p3;
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ char tex2Name[20] = { 0 };
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
+
+ if (t.texNum2 != 0)
+ sprintf(tex2Name, "dirty%.2d.tga", t.texNum2); // hardcoded as in the original code
+
+ triangle.tex2Name = std::string(tex2Name);
+
+ m_triangles.push_back(triangle);
+ }
+ }
+
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
+ {
+ m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "bmp", "tga");
+
+ GetLogger()->Info("ModelTriangle %d\n", i+1);
+ std::string s1 = m_triangles[i].p1.ToString();
+ GetLogger()->Info(" p1: %s\n", s1.c_str());
+ std::string s2 = m_triangles[i].p2.ToString();
+ GetLogger()->Info(" p2: %s\n", s2.c_str());
+ std::string s3 = m_triangles[i].p3.ToString();
+ GetLogger()->Info(" p3: %s\n", s3.c_str());
+
+ std::string d = m_triangles[i].material.diffuse.ToString();
+ std::string a = m_triangles[i].material.ambient.ToString();
+ std::string s = m_triangles[i].material.specular.ToString();
+ GetLogger()->Info(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str());
+
+ GetLogger()->Info(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str());
+ GetLogger()->Info(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max);
+ GetLogger()->Info(" state: %ld\n", m_triangles[i].state);
+ }
+
+ /*
+ if (! edit)
+ {
+ float limit[2];
+ limit[0] = m_engine->RetLimitLOD(0); // frontier AB as config
+ limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config
+
+ // Standard frontiers -> config.
+ for (int i = 0; i < m_triangles.size(); ++i)
+ {
+ if ( m_triangles[i].min == 0.0f &&
+ m_triangles[i].max == 100.0f ) // resolution A ?
+ {
+ m_triangles[i].max = limit[0];
+ }
+ else if ( m_triangles[i].min == 100.0f &&
+ m_triangles[i].max == 200.0f ) // resolution B ?
+ {
+ m_triangles[i].min = limit[0];
+ m_triangles[i].max = limit[1];
+ }
+ else if ( m_triangles[i].min == 200.0f &&
+ m_triangles[i].max == 1000000.0f ) // resolution C ?
+ {
+ m_triangles[i].min = limit[1];
+ }
+ }
+ }*/
+
+ return true;
+}
+
+bool Gfx::CModelFile::WriteModel(const std::string &filename)
+{
+ m_error = "";
+
+ std::ofstream stream;
+ stream.open(filename.c_str(), std::ios_base::out | std::ios_base::binary);
+ if (! stream.good())
+ {
+ m_error = std::string("Could not open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return WriteModel(stream);
+}
+
+bool Gfx::CModelFile::WriteModel(std::ostream &stream)
+{
+ m_error = "";
+
+ if (m_triangles.size() == 0)
+ {
+ m_error = "Empty model";
+ return false;
+ }
+
+ ModelHeader header;
+ header.revision = 1;
+ header.version = 2;
+ header.totalVertices = m_triangles.size();
+
+ IOUtils::WriteBinary<4, int>(header.revision, stream);
+ IOUtils::WriteBinary<4, int>(header.version, stream);
+ IOUtils::WriteBinary<4, int>(header.totalVertices, stream);
+ for (int i = 0; i < 10; ++i)
+ IOUtils::WriteBinary<4, int>(header.reserved[i], stream);
+
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
+ {
+ NewModelTriangle t;
+
+ t.used = true;
+
+ t.p1 = m_triangles[i].p1;
+ t.p2 = m_triangles[i].p2;
+ t.p3 = m_triangles[i].p3;
+
+ t.material = m_triangles[i].material;
+ strncpy(t.texName, m_triangles[i].tex1Name.c_str(), 20);
+ t.min = m_triangles[i].min;
+ t.max = m_triangles[i].max;
+ t.state = m_triangles[i].state;
+ int no = 0;
+ sscanf(m_triangles[i].tex2Name.c_str(), "dirty%d.tga", &no); // hardcoded as in the original code
+ t.texNum2 = no;
+
+
+ IOUtils::WriteBinary<1, char>(t.used, stream);
+ IOUtils::WriteBinary<1, char>(t.selected, stream);
+
+ WriteBinaryVertexTex2(t.p1, stream);
+ WriteBinaryVertexTex2(t.p2, stream);
+ WriteBinaryVertexTex2(t.p3, stream);
+
+ WriteBinaryMaterial(t.material, stream);
+ stream.write(t.texName, 20);
+ IOUtils::WriteBinaryFloat(t.min, stream);
+ IOUtils::WriteBinaryFloat(t.max, stream);
+ IOUtils::WriteBinary<4, long>(t.state, stream);
+ IOUtils::WriteBinary<2, short>(t.texNum2, stream);
+
+ IOUtils::WriteBinary<2, short>(t.reserved2, stream);
+ IOUtils::WriteBinary<2, short>(t.reserved3, stream);
+ IOUtils::WriteBinary<2, short>(t.reserved4, stream);
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::ReadDXF(const std::string &filename, float min, float max)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ std::ifstream stream;
+ stream.open(filename.c_str(), std::ios_base::in);
+ if (! stream.good())
+ {
+ m_error = std::string("Couldn't open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return ReadDXF(stream, min, max);
+}
+
+bool Gfx::CModelFile::ReadDXF(std::istream &stream, float min, float max)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ if (! stream.good())
+ {
+ m_error = "Invalid stream";
+ return false;
+ }
+
+ // Input state
+ bool waitNumVertex = false;
+ bool waitNumFace = false;
+ bool waitVertexX = false;
+ bool waitVertexY = false;
+ bool waitVertexZ = false;
+ bool waitFaceX = false;
+ bool waitFaceY = false;
+ bool waitFaceZ = false;
+
+ // Vertex array
+ std::vector<Math::Vector> vertices;
+ vertices.reserve(TRIANGLE_PREALLOCATE_COUNT);
+
+ // Number of vertices & faces of the primitive to be read
+ int vertexNum = 0, faceNum = 0;
+ // Vertex coords
+ Math::Vector coords;
+ // Indexes of face (triangle) points
+ int p1 = 0, p2 = 0, p3 = 0;
+
+ // Input line
+ std::string line;
+ while (! stream.eof() )
+ {
+ // Read line with command
+ std::getline(stream, line);
+ int command = StrUtils::FromString<int>(line);
+
+ // Read line with param
+ std::getline(stream, line);
+
+ bool ok = true;
+
+
+ if (command == 66)
+ {
+ waitNumVertex = true;
+ }
+
+ if ( command == 71 && waitNumVertex )
+ {
+ waitNumVertex = false;
+ vertexNum = StrUtils::FromString<int>(line, &ok);
+ waitNumFace = true;
+ }
+
+ if ( command == 72 && waitNumFace )
+ {
+ waitNumFace = false;
+ faceNum = StrUtils::FromString<int>(line, &ok);
+ waitVertexX = true;
+ }
+
+ if ( command == 10 && waitVertexX )
+ {
+ waitVertexX = false;
+ coords.x = StrUtils::FromString<float>(line, &ok);
+ waitVertexY = true;
+ }
+
+ if ( command == 20 && waitVertexY )
+ {
+ waitVertexY = false;
+ coords.y = StrUtils::FromString<float>(line, &ok);
+ waitVertexZ = true;
+ }
+
+ if ( command == 30 && waitVertexZ )
+ {
+ waitVertexZ = false;
+ coords.z = StrUtils::FromString<float>(line, &ok);
+
+ vertexNum --;
+ if ( vertexNum >= 0 )
+ {
+ Math::Vector p(coords.x, coords.z, coords.y); // permutation of Y and Z!
+ vertices.push_back(p);
+ waitVertexX = true;
+ }
+ else
+ {
+ waitFaceX = true;
+ }
+ }
+
+ if ( command == 71 && waitFaceX )
+ {
+ waitFaceX = false;
+ p1 = StrUtils::FromString<int>(line, &ok);
+ if ( p1 < 0 ) p1 = -p1;
+ waitFaceY = true;
+ }
+
+ if ( command == 72 && waitFaceY )
+ {
+ waitFaceY = false;
+ p2 = StrUtils::FromString<int>(line, &ok);
+ if ( p2 < 0 ) p2 = -p2;
+ waitFaceZ = true;
+ }
+
+ if ( command == 73 && waitFaceZ )
+ {
+ waitFaceZ = false;
+ p3 = StrUtils::FromString<int>(line, &ok);
+ if ( p3 < 0 ) p3 = -p3;
+
+ faceNum --;
+ if ( faceNum >= 0 )
+ {
+ assert( (p1-1 >= 0) && (p1-1 < static_cast<int>(vertices.size())) );
+ assert( (p2-1 >= 0) && (p2-1 < static_cast<int>(vertices.size())) );
+ assert( (p3-1 >= 0) && (p3-1 < static_cast<int>(vertices.size())) );
+
+ CreateTriangle(vertices[p3-1], vertices[p2-1], vertices[p1-1], min, max);
+ waitFaceX = true;
+ }
+ }
+
+ if (! ok)
+ {
+ m_error = "Error reading data";
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState)
+{
+ /*char texName1[20];
+ char texName2[20];
+ int texNum, i, state;
+
+ for (int i = 0; i < m_trianglesUsed; i++)
+ {
+ if (! m_triangles[i].used) continue;
+
+ state = m_triangles[i].state;
+ strcpy(texName1, m_triangles[i].texName);
+ texName2[0] = 0;
+
+ if ( strcmp(texName1, "plant.tga") == 0 ) // ???
+ {
+ state |= D3DSTATEALPHA;
+ }
+
+ if ( m_triangles[i].texNum2 != 0 )
+ {
+ if ( m_triangles[i].texNum2 == 1 )
+ {
+ texNum = m_engine->RetSecondTexture();
+ }
+ else
+ {
+ texNum = m_triangles[i].texNum2;
+ }
+
+ if ( texNum >= 1 && texNum <= 10 )
+ {
+ state |= D3DSTATEDUALb;
+ }
+ if ( texNum >= 11 && texNum <= 20 )
+ {
+ state |= D3DSTATEDUALw;
+ }
+ sprintf(texName2, "dirty%.2d.tga", texNum); // ???
+ }
+
+ m_engine->AddTriangle(objRank, &m_triangles[i].p1, 3,
+ m_triangles[i].material,
+ state + addState,
+ texName1, texName2,
+ m_triangles[i].min,
+ m_triangles[i].max, false);
+ }*/
+ return true;
+}
+
+void Gfx::CModelFile::Mirror()
+{
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++)
+ {
+ Gfx::VertexTex2 t = m_triangles[i].p1;
+ m_triangles[i].p1 = m_triangles[i].p2;
+ m_triangles[i].p2 = t;
+
+ m_triangles[i].p1.coord.z = -m_triangles[i].p1.coord.z;
+ m_triangles[i].p2.coord.z = -m_triangles[i].p2.coord.z;
+ m_triangles[i].p3.coord.z = -m_triangles[i].p3.coord.z;
+
+ m_triangles[i].p1.normal.z = -m_triangles[i].p1.normal.z;
+ m_triangles[i].p2.normal.z = -m_triangles[i].p2.normal.z;
+ m_triangles[i].p3.normal.z = -m_triangles[i].p3.normal.z;
+ }
+}
+
+std::vector<Gfx::ModelTriangle>& Gfx::CModelFile::GetTriangles()
+{
+ return m_triangles;
+}
+
+int Gfx::CModelFile::GetTriangleCount()
+{
+ return m_triangles.size();
+}
+
+float Gfx::CModelFile::GetHeight(Math::Vector pos)
+{
+ float limit = 5.0f;
+
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++)
+ {
+ if ( fabs(pos.x - m_triangles[i].p1.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p1.coord.z) < limit )
+ return m_triangles[i].p1.coord.y;
+
+ if ( fabs(pos.x - m_triangles[i].p2.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p2.coord.z) < limit )
+ return m_triangles[i].p2.coord.y;
+
+ if ( fabs(pos.x - m_triangles[i].p3.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p3.coord.z) < limit )
+ return m_triangles[i].p3.coord.y;
+ }
+
+ return 0.0f;
+}
+
+void Gfx::CModelFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max)
+{
+ Gfx::ModelTriangle triangle;
+
+ Math::Vector n = Math::NormalToPlane(p3, p2, p1);
+ triangle.p1 = Gfx::VertexTex2(p1, n);
+ triangle.p2 = Gfx::VertexTex2(p2, n);
+ triangle.p3 = Gfx::VertexTex2(p3, n);
+
+ triangle.material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f, 0.0f);
+ triangle.material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f);
+
+ triangle.min = min;
+ triangle.max = max;
+
+ m_triangles.push_back(triangle);
+}
diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h
new file mode 100644
index 0000000..6a30487
--- /dev/null
+++ b/src/graphics/engine/modelfile.h
@@ -0,0 +1,120 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// modelfile.h (aka modfile.h)
+
+#include "graphics/engine/engine.h"
+#include "graphics/core/vertex.h"
+#include "graphics/core/material.h"
+#include "math/vector.h"
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+
+class CInstanceManager;
+
+
+namespace Gfx {
+
+/**
+ \struct ModelTriangle
+ \brief Triangle of a 3D model
+ */
+struct ModelTriangle
+{
+ //! 1st vertex
+ Gfx::VertexTex2 p1;
+ //! 2nd vertex
+ Gfx::VertexTex2 p2;
+ //! 3rd vertex
+ Gfx::VertexTex2 p3;
+ //! Material
+ Gfx::Material material;
+ //! Name of 1st texture
+ std::string tex1Name;
+ //! Name of 2nd texture
+ std::string tex2Name;
+ //! Min LOD threshold
+ float min;
+ //! Max LOD threshold
+ float max;
+ //! Rendering state to be set
+ long state;
+
+ ModelTriangle();
+};
+
+
+/**
+ \class CModelFile
+ \brief Model file reader/writer
+
+ Allows reading and writing model objects. Models are collections of ModelTriangle structs. */
+class CModelFile
+{
+public:
+ CModelFile(CInstanceManager* iMan);
+ ~CModelFile();
+
+ //! Returns the last error encountered
+ std::string GetError();
+
+ //! Reads a binary Colobot model from file
+ bool ReadModel(const std::string &filename, bool edit = false, bool meta = true);
+ //! Reads a binary Colobot model from stream
+ bool ReadModel(std::istream &stream, bool edit = false, bool meta = true);
+ //! Writes the model to Colobot binary model file
+ bool WriteModel(const std::string &filename);
+ //! Writes the model to Colobot binary model file
+ bool WriteModel(std::ostream &stream);
+
+ //! Reads a DXF model from file
+ bool ReadDXF(const std::string &filename, float min, float max);
+ //! Reads a DXF model from stream
+ bool ReadDXF(std::istream &stream, float min, float max);
+
+ //! Returns the number of triangles in model
+ int GetTriangleCount();
+ //! Returns the triangle vector
+ std::vector<Gfx::ModelTriangle>& GetTriangles();
+ //! Returns the height of model -- closest point to X and Z coords of \a pos
+ float GetHeight(Math::Vector pos);
+
+ //! Mirrors the model along the Z axis
+ void Mirror();
+
+ //! Creates an object in the graphics engine from the model
+ bool CreateEngineObject(int objRank, int addState = 0);
+
+protected:
+ //! Adds a triangle to the list
+ void CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
+
+protected:
+ CInstanceManager* m_iMan;
+ Gfx::CEngine* m_engine;
+
+ //! Last error
+ std::string m_error;
+
+ //! Model triangles
+ std::vector<Gfx::ModelTriangle> m_triangles;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/particle.cpp b/src/graphics/engine/particle.cpp
index 322c2d0..84e2f9d 100644
--- a/src/graphics/common/particle.cpp
+++ b/src/graphics/engine/particle.cpp
@@ -17,7 +17,7 @@
// particle.cpp (aka particule.cpp)
-#include "graphics/common/particle.h"
+#include "graphics/engine/particle.h"
// TODO implementation
diff --git a/src/graphics/common/particle.h b/src/graphics/engine/particle.h
index e430e2a..bd9741f 100644
--- a/src/graphics/common/particle.h
+++ b/src/graphics/engine/particle.h
@@ -25,9 +25,8 @@
class CInstanceManager;
class CRobotMain;
-class Gfx::CTerrain;
-class Gfx::CWater;
class CObject;
+class CSound;
@@ -52,7 +51,7 @@ const short SH_MAX = 3;
// type == 4 -> text (white background)
-enum ParticuleType
+enum ParticleType
{
PARTIEXPLOT = 1, // technology explosion
PARTIEXPLOO = 2, // organic explosion
@@ -195,20 +194,20 @@ enum ParticuleType
PARTITRACE19 = 159, // trace
};
-enum ParticulePhase
+enum ParticlePhase
{
PARPHSTART = 0,
PARPHEND = 1,
};
-struct Particule
+struct Particle
{
char bUsed; // TRUE -> particle used
char bRay; // TRUE -> ray with goal
unsigned short uniqueStamp; // unique mark
short sheet; // sheet (0..n)
- ParticuleType type; // type PARTI*
- ParticulePhase phase; // phase PARPH*
+ ParticleType type; // type PARTI*
+ ParticlePhase phase; // phase PARPH*
float mass; // mass of the particle (in rebounding)
float weight; // weight of the particle (for noise)
float duration; // length of life
@@ -235,7 +234,7 @@ struct Particule
struct Track
{
char bUsed; // TRUE -> drag used
- char bDrawParticule;
+ char bDrawParticle;
float step; // duration of not
float last; // increase last not memorized
float intensity; // intensity at starting (0..1)
@@ -248,7 +247,7 @@ struct Track
struct WheelTrace
{
- ParticuleType type; // type PARTI*
+ ParticleType type; // type PARTI*
Math::Vector pos[4]; // rectangle positions
float startTime; // beginning of life
};
@@ -263,16 +262,16 @@ public:
void SetGLDevice(CDevice device);
- void FlushParticule();
- void FlushParticule(int sheet);
- int CreateParticule(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreateFrag(Math::Vector pos, Math::Vector speed, Triangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreatePart(Math::Vector pos, Math::Vector speed, ParticuleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0);
- int CreateRay(Math::Vector pos, Math::Vector goal, ParticuleType type, Math::Point dim, float duration=1.0f, int sheet=0);
- int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f);
- void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticuleType type);
- void DeleteParticule(ParticuleType type);
- void DeleteParticule(int channel);
+ void FlushParticle();
+ void FlushParticle(int sheet);
+ int CreateParticle(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
+ int CreateFrag(Math::Vector pos, Math::Vector speed, Gfx::EngineTriangle *triangle, ParticleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
+ int CreatePart(Math::Vector pos, Math::Vector speed, ParticleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0);
+ int CreateRay(Math::Vector pos, Math::Vector goal, ParticleType type, Math::Point dim, float duration=1.0f, int sheet=0);
+ int CreateTrack(Math::Vector pos, Math::Vector speed, Math::Point dim, ParticleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f);
+ void CreateWheelTrace(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3, const Math::Vector &p4, ParticleType type);
+ void DeleteParticle(ParticleType type);
+ void DeleteParticle(int channel);
void SetObjectLink(int channel, CObject *object);
void SetObjectFather(int channel, CObject *object);
void SetPosition(int channel, Math::Vector pos);
@@ -281,57 +280,57 @@ public:
void SetAngle(int channel, float angle);
void SetIntensity(int channel, float intensity);
void SetParam(int channel, Math::Vector pos, Math::Point dim, float zoom, float angle, float intensity);
- void SetPhase(int channel, ParticulePhase phase, float duration);
+ void SetPhase(int channel, ParticlePhase phase, float duration);
bool GetPosition(int channel, Math::Vector &pos);
Gfx::Color RetFogColor(Math::Vector pos);
void SetFrameUpdate(int sheet, bool bUpdate);
- void FrameParticule(float rTime);
- void DrawParticule(int sheet);
+ void FrameParticle(float rTime);
+ void DrawParticle(int sheet);
bool WriteWheelTrace(char *filename, int width, int height, Math::Vector dl, Math::Vector ur);
protected:
void DeleteRank(int rank);
bool CheckChannel(int &channel);
- void DrawParticuleTriangle(int i);
- void DrawParticuleNorm(int i);
- void DrawParticuleFlat(int i);
- void DrawParticuleFog(int i);
- void DrawParticuleRay(int i);
- void DrawParticuleSphere(int i);
- void DrawParticuleCylinder(int i);
- void DrawParticuleWheel(int i);
- CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticuleType type, CObject *father);
- CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticuleType type, CObject *father);
- void Play(Snd::Sound sound, Math::Vector pos, float amplitude);
+ void DrawParticleTriangle(int i);
+ void DrawParticleNorm(int i);
+ void DrawParticleFlat(int i);
+ void DrawParticleFog(int i);
+ void DrawParticleRay(int i);
+ void DrawParticleSphere(int i);
+ void DrawParticleCylinder(int i);
+ void DrawParticleWheel(int i);
+ CObject* SearchObjectGun(Math::Vector old, Math::Vector pos, ParticleType type, CObject *father);
+ CObject* SearchObjectRay(Math::Vector pos, Math::Vector goal, ParticleType type, CObject *father);
+ void Play(Sound sound, Math::Vector pos, float amplitude);
bool TrackMove(int i, Math::Vector pos, float progress);
- void TrackDraw(int i, ParticuleType type);
+ void TrackDraw(int i, ParticleType type);
protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
- CDevice* m_pDevice;
- CRobotMain* m_main;
- CTerrain* m_terrain;
- CWater* m_water;
- CSound* m_sound;
+ CInstanceManager* m_iMan;
+ CEngine* m_engine;
+ CDevice* m_pDevice;
+ CRobotMain* m_main;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CSound* m_sound;
- Particule m_particule[MAXPARTICULE*MAXPARTITYPE];
- Gfx::Triangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0
- Track m_track[MAXTRACK];
- int m_wheelTraceTotal;
- int m_wheelTraceIndex;
- WheelTrace m_wheelTrace[MAXWHEELTRACE];
- int m_totalInterface[MAXPARTITYPE][SH_MAX];
- bool m_bFrameUpdate[SH_MAX];
- int m_fogTotal;
- int m_fog[MAXPARTIFOG];
- int m_uniqueStamp;
- int m_exploGunCounter;
- float m_lastTimeGunDel;
- float m_absTime;
+ Gfx::Particle m_particule[MAXPARTICULE*MAXPARTITYPE];
+ Gfx::EngineTriangle m_triangle[MAXPARTICULE]; // triangle if PartiType == 0
+ Track m_track[MAXTRACK];
+ int m_wheelTraceTotal;
+ int m_wheelTraceIndex;
+ WheelTrace m_wheelTrace[MAXWHEELTRACE];
+ int m_totalInterface[MAXPARTITYPE][SH_MAX];
+ bool m_bFrameUpdate[SH_MAX];
+ int m_fogTotal;
+ int m_fog[MAXPARTIFOG];
+ int m_uniqueStamp;
+ int m_exploGunCounter;
+ float m_lastTimeGunDel;
+ float m_absTime;
};
diff --git a/src/graphics/common/planet.cpp b/src/graphics/engine/planet.cpp
index 4fa17a1..4f1f614 100644
--- a/src/graphics/common/planet.cpp
+++ b/src/graphics/engine/planet.cpp
@@ -17,7 +17,7 @@
// planet.cpp
-#include "graphics/common/planet.h"
+#include "graphics/engine/planet.h"
// TODO implementation
diff --git a/src/graphics/common/planet.h b/src/graphics/engine/planet.h
index 264d05c..264d05c 100644
--- a/src/graphics/common/planet.h
+++ b/src/graphics/engine/planet.h
diff --git a/src/graphics/common/pyro.cpp b/src/graphics/engine/pyro.cpp
index 6b5b1af..e699db2 100644
--- a/src/graphics/common/pyro.cpp
+++ b/src/graphics/engine/pyro.cpp
@@ -17,7 +17,7 @@
// pyro.cpp
-#include "graphics/common/pyro.h"
+#include "graphics/engine/pyro.h"
// TODO implementation
diff --git a/src/graphics/common/pyro.h b/src/graphics/engine/pyro.h
index fda74b3..d663ca5 100644
--- a/src/graphics/common/pyro.h
+++ b/src/graphics/engine/pyro.h
@@ -20,7 +20,7 @@
#pragma once
#include "common/misc.h"
-#include "graphics/common/engine.h"
+#include "graphics/engine/engine.h"
//#include "object/object.h"
// TEMPORARILY!
enum ObjectType {};
diff --git a/src/graphics/common/terrain.cpp b/src/graphics/engine/terrain.cpp
index 9b61dfc..c489321 100644
--- a/src/graphics/common/terrain.cpp
+++ b/src/graphics/engine/terrain.cpp
@@ -17,7 +17,7 @@
// terrain.cpp
-#include "graphics/common/terrain.h"
+#include "graphics/engine/terrain.h"
// TODO implementation
diff --git a/src/graphics/common/terrain.h b/src/graphics/engine/terrain.h
index fd9a1a6..8d8b165 100644
--- a/src/graphics/common/terrain.h
+++ b/src/graphics/engine/terrain.h
@@ -19,7 +19,7 @@
#pragma once
-#include "graphics/common/engine.h"
+#include "graphics/engine/engine.h"
class CInstanceManager;
diff --git a/src/graphics/engine/test/CMakeLists.txt b/src/graphics/engine/test/CMakeLists.txt
new file mode 100644
index 0000000..bd83773
--- /dev/null
+++ b/src/graphics/engine/test/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+include_directories(. ../../..)
+add_executable(modelfile_test modelfile_test.cpp ../modelfile.cpp ../../../common/logger.cpp ../../../common/stringutils.cpp ../../../common/iman.cpp)
diff --git a/src/graphics/engine/test/modelfile_test.cpp b/src/graphics/engine/test/modelfile_test.cpp
new file mode 100644
index 0000000..f7ed87f
--- /dev/null
+++ b/src/graphics/engine/test/modelfile_test.cpp
@@ -0,0 +1,48 @@
+#include "graphics/engine/modelfile.h"
+#include "common/iman.h"
+
+#include <iostream>
+
+
+int main(int argc, char *argv[])
+{
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
+ return 1;
+ }
+
+ CInstanceManager iMan;
+ Gfx::CModelFile modfile(&iMan);
+
+ std::string mode(argv[1]);
+ if (mode == "mod")
+ {
+ if (! modfile.ReadModel(argv[2], false, false) )
+ {
+ std::cerr << "Read error: " << modfile.GetError() << std::endl;
+ return 2;
+ }
+ }
+ else if (mode == "dxf")
+ {
+ if (! modfile.ReadDXF(argv[2], false, false) )
+ {
+ std::cerr << "Read error: " << modfile.GetError() << std::endl;
+ return 2;
+ }
+ }
+ else
+ {
+ std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
+ return 1;
+ }
+
+ if (! modfile.WriteModel(argv[3]) )
+ {
+ std::cerr << "Write error: " << modfile.GetError() << std::endl;
+ return 3;
+ }
+
+ return 0;
+}
diff --git a/src/graphics/common/text.cpp b/src/graphics/engine/text.cpp
index 0c5eb66..2a9543c 100644
--- a/src/graphics/common/text.cpp
+++ b/src/graphics/engine/text.cpp
@@ -17,7 +17,7 @@
// text.cpp
-#include "graphics/common/text.h"
+#include "graphics/engine/text.h"
// TODO implementation
diff --git a/src/graphics/common/text.h b/src/graphics/engine/text.h
index 00b73f2..c2de220 100644
--- a/src/graphics/common/text.h
+++ b/src/graphics/engine/text.h
@@ -19,8 +19,8 @@
#pragma once
-#include "graphics/common/engine.h"
-#include "graphics/common/device.h"
+#include "graphics/engine/engine.h"
+#include "graphics/core/device.h"
#include "math/point.h"
@@ -73,7 +73,7 @@ public:
CText(CInstanceManager *iMan, Gfx::CEngine* engine);
~CText();
- void SetGLDevice(Gfx::CDevice device);
+ void SetDevice(Gfx::CDevice *device);
void DrawText(char *string, char *format, int len, Math::Point pos, float width, int justif, float size, float stretch, int eol);
void DrawText(char *string, char *format, Math::Point pos, float width, int justif, float size, float stretch, int eol);
@@ -106,7 +106,7 @@ protected:
protected:
CInstanceManager* m_iMan;
Gfx::CEngine* m_engine;
- Gfx::CDevice m_pDevice;
+ Gfx::CDevice* m_device;
};
diff --git a/src/graphics/common/water.cpp b/src/graphics/engine/water.cpp
index 5172b9f..a157e82 100644
--- a/src/graphics/common/water.cpp
+++ b/src/graphics/engine/water.cpp
@@ -17,7 +17,7 @@
// water.cpp
-#include "graphics/common/water.h"
+#include "graphics/engine/water.h"
// TODO implementation
diff --git a/src/graphics/common/water.h b/src/graphics/engine/water.h
index 5999eac..67be9dc 100644
--- a/src/graphics/common/water.h
+++ b/src/graphics/engine/water.h
@@ -19,8 +19,8 @@
#pragma once
-#include "graphics/common/engine.h"
-#include "graphics/common/particle.h"
+#include "graphics/engine/engine.h"
+#include "graphics/engine/particle.h"
#include "common/event.h"
@@ -48,7 +48,7 @@ const short MAXWATVAPOR = 10;
struct WaterVapor
{
bool bUsed;
- ParticuleType type;
+ ParticleType type;
Math::Vector pos;
float delay;
float time;
@@ -96,7 +96,7 @@ protected:
bool CreateLine(int x, int y, int len);
void VaporFlush();
- bool VaporCreate(ParticuleType type, Math::Vector pos, float delay);
+ bool VaporCreate(ParticleType type, Math::Vector pos, float delay);
void VaporFrame(int i, float rTime);
protected:
diff --git a/src/graphics/opengl/README.txt b/src/graphics/opengl/README.txt
index 11aba8d..0aba0ed 100644
--- a/src/graphics/opengl/README.txt
+++ b/src/graphics/opengl/README.txt
@@ -2,5 +2,5 @@ src/graphics/opengl
OpenGL engine implementation
-Contains the concreate implementation using OpenGL of functions
-of grahpics engine in graphics/common.
+Contains the concrete implementation using OpenGL of abstract CDevice class
+from src/graphics/core
diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp
index 7938e62..3a255f4 100644
--- a/src/graphics/opengl/gldevice.cpp
+++ b/src/graphics/opengl/gldevice.cpp
@@ -18,4 +18,1194 @@
#include "graphics/opengl/gldevice.h"
-// TODO
+#include "common/config.h"
+#include "common/image.h"
+#include "math/geometry.h"
+
+
+#if defined(USE_GLEW)
+
+// When using GLEW, only glew.h is needed
+#include <GL/glew.h>
+
+#else
+
+// Should define prototypes of used extensions as OpenGL functions
+#define GL_GLEXT_PROTOTYPES
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glext.h>
+
+#endif // if defined(GLEW)
+
+#include <SDL/SDL.h>
+
+#include <cassert>
+
+
+
+void Gfx::GLDeviceConfig::LoadDefault()
+{
+ Gfx::DeviceConfig::LoadDefault();
+
+ hardwareAccel = true;
+
+ redSize = 8;
+ blueSize = 8;
+ greenSize = 8;
+ alphaSize = 8;
+ depthSize = 24;
+}
+
+
+
+
+Gfx::CGLDevice::CGLDevice(const Gfx::GLDeviceConfig &config)
+{
+ m_config = config;
+ m_wasInit = false;
+ m_lighting = false;
+ m_texturing = false;
+}
+
+
+Gfx::CGLDevice::~CGLDevice()
+{
+}
+
+bool Gfx::CGLDevice::GetWasInit()
+{
+ return m_wasInit;
+}
+
+std::string Gfx::CGLDevice::GetError()
+{
+ return m_error;
+}
+
+bool Gfx::CGLDevice::Create()
+{
+#if defined(USE_GLEW)
+ static bool glewInited = false;
+
+ if (!glewInited)
+ {
+ glewInited = true;
+
+ if (glewInit() != GLEW_OK)
+ {
+ m_error = "GLEW initialization failed";
+ return false;
+ }
+
+ if ( (! GLEW_ARB_multitexture) || (! GLEW_EXT_texture_env_combine) || (! GLEW_EXT_secondary_color) )
+ {
+ m_error = "GLEW reports required extensions not supported";
+ return false;
+ }
+ }
+#endif
+
+ /* NOTE: when not using GLEW, extension testing is not performed, as it is assumed that
+ glext.h is up-to-date and the OpenGL shared library has the required functions present. */
+
+ m_wasInit = true;
+
+ // This is mostly done in all modern hardware by default
+ // DirectX doesn't even allow the option to turn off perspective correction anymore
+ // So turn it on permanently
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+
+ // To use separate specular color in drawing primitives
+ glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+
+ // To avoid problems with scaling & lighting
+ glEnable(GL_RESCALE_NORMAL);
+
+ // Set just to be sure
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glViewport(0, 0, m_config.size.w, m_config.size.h);
+
+
+ m_lights = std::vector<Gfx::Light>(GL_MAX_LIGHTS, Gfx::Light());
+ m_lightsEnabled = std::vector<bool> (GL_MAX_LIGHTS, false);
+
+ int maxTextures = 0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextures);
+
+ m_currentTextures = std::vector<Gfx::Texture> (maxTextures, Gfx::Texture());
+ m_texturesEnabled = std::vector<bool> (maxTextures, false);
+ m_textureStageParams = std::vector<Gfx::TextureStageParams>(maxTextures, Gfx::TextureStageParams());
+
+ return true;
+}
+
+void Gfx::CGLDevice::Destroy()
+{
+ // Delete the remaining textures
+ // Should not be strictly necessary, but just in case
+ DestroyAllTextures();
+
+ m_lights.clear();
+ m_lightsEnabled.clear();
+
+ m_currentTextures.clear();
+ m_texturesEnabled.clear();
+ m_textureStageParams.clear();
+
+ m_wasInit = false;
+}
+
+void Gfx::CGLDevice::ConfigChanged(const Gfx::GLDeviceConfig& newConfig)
+{
+ m_config = newConfig;
+
+ // Reset state
+ m_lighting = false;
+ m_texturing = false;
+ Destroy();
+ Create();
+}
+
+void Gfx::CGLDevice::BeginScene()
+{
+ Clear();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(m_projectionMat.Array());
+
+ UpdateModelviewMatrix();
+}
+
+void Gfx::CGLDevice::EndScene()
+{
+ glFlush();
+}
+
+void Gfx::CGLDevice::Clear()
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void Gfx::CGLDevice::SetTransform(Gfx::TransformType type, const Math::Matrix &matrix)
+{
+ if (type == Gfx::TRANSFORM_WORLD)
+ {
+ m_worldMat = matrix;
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_VIEW)
+ {
+ m_viewMat = matrix;
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_PROJECTION)
+ {
+ m_projectionMat = matrix;
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(m_projectionMat.Array());
+ }
+ else
+ {
+ assert(false);
+ }
+}
+
+const Math::Matrix& Gfx::CGLDevice::GetTransform(Gfx::TransformType type)
+{
+ if (type == Gfx::TRANSFORM_WORLD)
+ return m_worldMat;
+ else if (type == Gfx::TRANSFORM_VIEW)
+ return m_viewMat;
+ else if (type == Gfx::TRANSFORM_PROJECTION)
+ return m_projectionMat;
+ else
+ assert(false);
+
+ return m_worldMat; // to avoid warning
+}
+
+void Gfx::CGLDevice::MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix)
+{
+ if (type == Gfx::TRANSFORM_WORLD)
+ {
+ m_worldMat = Math::MultiplyMatrices(m_worldMat, matrix);
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_VIEW)
+ {
+ m_viewMat = Math::MultiplyMatrices(m_viewMat, matrix);
+ UpdateModelviewMatrix();
+ }
+ else if (type == Gfx::TRANSFORM_PROJECTION)
+ {
+ m_projectionMat = Math::MultiplyMatrices(m_projectionMat, matrix);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(m_projectionMat.Array());
+ }
+ else
+ {
+ assert(false);
+ }
+}
+
+void Gfx::CGLDevice::UpdateModelviewMatrix()
+{
+ m_modelviewMat = Math::MultiplyMatrices(m_viewMat, m_worldMat);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glScalef(1.0f, 1.0f, -1.0f);
+ glMultMatrixf(m_modelviewMat.Array());
+
+ if (m_lighting)
+ {
+ for (int index = 0; index < static_cast<int>( m_lights.size() ); ++index)
+ UpdateLightPosition(index);
+ }
+}
+
+void Gfx::CGLDevice::SetMaterial(const Gfx::Material &material)
+{
+ m_material = material;
+
+ glMaterialfv(GL_FRONT, GL_AMBIENT, m_material.ambient.Array());
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, m_material.diffuse.Array());
+ glMaterialfv(GL_FRONT, GL_SPECULAR, m_material.specular.Array());
+}
+
+const Gfx::Material& Gfx::CGLDevice::GetMaterial()
+{
+ return m_material;
+}
+
+int Gfx::CGLDevice::GetMaxLightCount()
+{
+ return m_lights.size();
+}
+
+void Gfx::CGLDevice::SetLight(int index, const Gfx::Light &light)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_lights.size() ));
+
+ m_lights[index] = light;
+
+ // Indexing from GL_LIGHT0 should always work
+ glLightfv(GL_LIGHT0 + index, GL_AMBIENT, const_cast<GLfloat*>(light.ambient.Array()));
+ glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, const_cast<GLfloat*>(light.diffuse.Array()));
+ glLightfv(GL_LIGHT0 + index, GL_SPECULAR, const_cast<GLfloat*>(light.specular.Array()));
+
+ glLightf(GL_LIGHT0 + index, GL_CONSTANT_ATTENUATION, light.attenuation0);
+ glLightf(GL_LIGHT0 + index, GL_LINEAR_ATTENUATION, light.attenuation1);
+ glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, light.attenuation2);
+
+ if (light.type == Gfx::LIGHT_SPOT)
+ {
+ glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle);
+ glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity);
+ }
+ else
+ {
+ glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f);
+ }
+
+ UpdateLightPosition(index);
+}
+
+void Gfx::CGLDevice::UpdateLightPosition(int index)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_lights.size() ));
+
+ if ((! m_lighting) || (! m_lightsEnabled[index]))
+ return;
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ glLoadIdentity();
+ glScalef(1.0f, 1.0f, -1.0f);
+ glMultMatrixf(m_viewMat.Array());
+
+ if (m_lights[index].type == LIGHT_DIRECTIONAL)
+ {
+ GLfloat position[4] = { m_lights[index].direction.x, m_lights[index].direction.y, m_lights[index].direction.z, 0.0f };
+ glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
+ }
+ else
+ {
+ GLfloat position[4] = { m_lights[index].position.x, m_lights[index].position.y, m_lights[index].position.z, 1.0f };
+ glLightfv(GL_LIGHT0 + index, GL_POSITION, position);
+ }
+
+ if (m_lights[index].type == Gfx::LIGHT_SPOT)
+ {
+ GLfloat direction[4] = { m_lights[index].direction.x, m_lights[index].direction.y, m_lights[index].direction.z, 0.0f };
+ glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction);
+ }
+
+ glPopMatrix();
+}
+
+const Gfx::Light& Gfx::CGLDevice::GetLight(int index)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_lights.size() ));
+
+ return m_lights[index];
+}
+
+void Gfx::CGLDevice::SetLightEnabled(int index, bool enabled)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_lights.size() ));
+
+ m_lightsEnabled[index] = enabled;
+
+ glEnable(GL_LIGHT0 + index);
+}
+
+bool Gfx::CGLDevice::GetLightEnabled(int index)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_lights.size() ));
+
+ return m_lightsEnabled[index];
+}
+
+/** If image is invalid, returns invalid texture.
+ Otherwise, returns pointer to new Gfx::Texture struct.
+ This struct must not be deleted in other way than through DeleteTexture() */
+Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCreateParams &params)
+{
+ Gfx::Texture result;
+
+ ImageData *data = image->GetData();
+ if (data == NULL)
+ {
+ m_error = "Invalid texture data";
+ return result; // invalid texture
+ }
+
+ result.valid = true;
+ result.size.w = data->surface->w;
+ result.size.h = data->surface->h;
+
+ // Use & enable 1st texture stage
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glGenTextures(1, &result.id);
+ glBindTexture(GL_TEXTURE_2D, result.id);
+
+ // Set params
+
+ GLint minF = 0;
+ if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST) minF = GL_NEAREST;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR) minF = GL_LINEAR;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST) minF = GL_NEAREST_MIPMAP_NEAREST;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_NEAREST) minF = GL_LINEAR_MIPMAP_NEAREST;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_LINEAR) minF = GL_NEAREST_MIPMAP_LINEAR;
+ else if (params.minFilter == Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR) minF = GL_LINEAR_MIPMAP_LINEAR;
+ else assert(false);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF);
+
+ GLint magF = 0;
+ if (params.magFilter == Gfx::TEX_MAG_FILTER_NEAREST) magF = GL_NEAREST;
+ else if (params.magFilter == Gfx::TEX_MAG_FILTER_LINEAR) magF = GL_LINEAR;
+ else assert(false);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF);
+
+ if (params.mipmap)
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
+
+ GLenum sourceFormat = 0;
+ if (params.format == Gfx::TEX_IMG_RGB)
+ {
+ sourceFormat = GL_RGB;
+ result.alpha = false;
+ }
+ else if (params.format == Gfx::TEX_IMG_BGR)
+ {
+ sourceFormat = GL_BGR;
+ result.alpha = false;
+ }
+ else if (params.format == Gfx::TEX_IMG_RGBA)
+ {
+ sourceFormat = GL_RGBA;
+ result.alpha = true;
+ }
+ else if (params.format == Gfx::TEX_IMG_BGRA)
+ {
+ sourceFormat = GL_BGRA;
+ result.alpha = true;
+ }
+ else
+ assert(false);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data->surface->w, data->surface->h,
+ 0, sourceFormat, GL_UNSIGNED_BYTE, data->surface->pixels);
+
+
+ // Restore the previous state of 1st stage
+ if (m_currentTextures[0].valid)
+ glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
+ else
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ if ( (! m_texturing) || (! m_texturesEnabled[0]) )
+ glDisable(GL_TEXTURE_2D);
+
+ return result;
+}
+
+void Gfx::CGLDevice::DestroyTexture(const Gfx::Texture &texture)
+{
+ std::set<Gfx::Texture>::iterator it = m_allTextures.find(texture);
+ if (it != m_allTextures.end())
+ m_allTextures.erase(it);
+
+ // Unbind the texture if in use anywhere
+ for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index)
+ {
+ if (m_currentTextures[index] == texture)
+ SetTexture(index, Gfx::Texture()); // set to invalid texture
+ }
+
+ glDeleteTextures(1, &texture.id);
+}
+
+void Gfx::CGLDevice::DestroyAllTextures()
+{
+ std::set<Gfx::Texture> allCopy = m_allTextures;
+ std::set<Gfx::Texture>::iterator it;
+ for (it = allCopy.begin(); it != allCopy.end(); ++it)
+ DestroyTexture(*it);
+}
+
+int Gfx::CGLDevice::GetMaxTextureCount()
+{
+ return m_currentTextures.size();
+}
+
+/**
+ If \a texture is invalid, unbinds the given texture.
+ If valid, binds the texture and enables the given texture stage.
+ The setting is remembered, even if texturing is disabled at the moment. */
+void Gfx::CGLDevice::SetTexture(int index, const Gfx::Texture &texture)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ // Enable the given texture stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ m_currentTextures[index] = texture; // remember the change
+
+ if (! texture.valid)
+ {
+ glBindTexture(GL_TEXTURE_2D, 0); // unbind texture
+ }
+ else
+ {
+ glBindTexture(GL_TEXTURE_2D, texture.id); // bind the texture
+ SetTextureStageParams(index, m_textureStageParams[index]); // texture stage params need to be re-set for the new texture
+ }
+
+ // Disable the stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[index]) )
+ glDisable(GL_TEXTURE_2D);
+}
+
+/**
+ Returns the previously assigned texture or invalid texture if the given stage is not enabled. */
+Gfx::Texture Gfx::CGLDevice::GetTexture(int index)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ return m_currentTextures[index];
+}
+
+void Gfx::CGLDevice::SetTextureEnabled(int index, bool enabled)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ m_texturesEnabled[index] = enabled;
+
+ glActiveTexture(GL_TEXTURE0 + index);
+ if (enabled)
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+}
+
+bool Gfx::CGLDevice::GetTextureEnabled(int index)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ return m_texturesEnabled[index];
+}
+
+/**
+ Sets the texture parameters for the given texture stage.
+ If the given texture was not set (bound) yet, nothing happens.
+ The settings are remembered, even if texturing is disabled at the moment. */
+void Gfx::CGLDevice::SetTextureStageParams(int index, const Gfx::TextureStageParams &params)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ // Remember the settings
+ m_textureStageParams[index] = params;
+
+ // Don't actually do anything if texture not set
+ if (! m_currentTextures[index].valid)
+ return;
+
+ // Enable the given stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ glBindTexture(GL_TEXTURE_2D, m_currentTextures[index].id);
+
+ // To save some trouble
+ if ( (params.colorOperation == Gfx::TEX_MIX_OPER_DEFAULT) &&
+ (params.alphaOperation == Gfx::TEX_MIX_OPER_DEFAULT) )
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ goto after_tex_operations;
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+
+ // Only these modes of getting color & alpha are used
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+
+ // Color operation
+
+ if (params.colorOperation == Gfx::TEX_MIX_OPER_DEFAULT)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
+ goto after_tex_color;
+ }
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_REPLACE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_MODULATE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_ADD)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_SUBTRACT)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
+ else assert(false);
+
+ // Color arg1
+ if (params.colorArg1 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
+ else if (params.colorArg1 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
+ else if (params.colorArg1 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
+ else if (params.colorArg1 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
+ else assert(false);
+
+ // Color arg2
+ if (params.colorArg2 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
+ else if (params.colorArg2 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
+ else if (params.colorArg2 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
+ else if (params.colorArg2 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
+ else assert(false);
+
+
+after_tex_color:
+
+ // Alpha operation
+ if (params.alphaOperation == Gfx::TEX_MIX_OPER_DEFAULT)
+ {
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
+ goto after_tex_operations;
+ }
+ else if (params.colorOperation == Gfx::TEX_MIX_OPER_REPLACE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ else if (params.alphaOperation == Gfx::TEX_MIX_OPER_MODULATE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ else if (params.alphaOperation == Gfx::TEX_MIX_OPER_ADD)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
+ else if (params.alphaOperation == Gfx::TEX_MIX_OPER_SUBTRACT)
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_SUBTRACT);
+ else assert(false);
+
+ // Alpha arg1
+ if (params.alphaArg1 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
+ else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
+ else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
+ else if (params.alphaArg1 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);
+ else assert(false);
+
+ // Alpha arg2
+ if (params.alphaArg2 == Gfx::TEX_MIX_ARG_TEXTURE)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
+ else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_COMPUTED_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
+ else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_SRC_COLOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
+ else if (params.alphaArg2 == Gfx::TEX_MIX_ARG_FACTOR)
+ glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT);
+ else assert(false);
+
+
+after_tex_operations:
+
+ if (params.wrapS == Gfx::TEX_WRAP_CLAMP)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ else if (params.wrapS == Gfx::TEX_WRAP_REPEAT)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ else assert(false);
+
+ if (params.wrapT == Gfx::TEX_WRAP_CLAMP)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ else if (params.wrapT == Gfx::TEX_WRAP_REPEAT)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ else assert(false);
+
+ // Disable the stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[index]) )
+ glDisable(GL_TEXTURE_2D);
+}
+
+Gfx::TextureStageParams Gfx::CGLDevice::GetTextureStageParams(int index)
+{
+ assert(index >= 0);
+ assert(index < static_cast<int>( m_currentTextures.size() ));
+
+ return m_textureStageParams[index];
+}
+
+void Gfx::CGLDevice::SetTextureFactor(const Gfx::Color &color)
+{
+ // Needs to be set for all texture stages
+ for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index)
+ {
+ // Activate stage
+ glActiveTexture(GL_TEXTURE0 + index);
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.Array());
+
+ // Disable the stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[index]) )
+ glDisable(GL_TEXTURE_2D);
+ }
+}
+
+Gfx::Color Gfx::CGLDevice::GetTextureFactor()
+{
+ // Get from 1st stage (should be the same for all stages)
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+
+ GLfloat color[4] = { 0.0f };
+ glGetTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
+
+ // Disable the 1st stage if it is set so
+ if ( (! m_texturing) || (! m_texturesEnabled[0]) )
+ glDisable(GL_TEXTURE_2D);
+
+ return Gfx::Color(color[0], color[1], color[2], color[3]);
+}
+
+GLenum TranslateGfxPrimitive(Gfx::PrimitiveType type)
+{
+ GLenum flag = 0;
+ switch (type)
+ {
+ case Gfx::PRIMITIVE_POINTS: flag = GL_POINTS; break;
+ case Gfx::PRIMITIVE_LINES: flag = GL_LINES; break;
+ case Gfx::PRIMITIVE_LINE_STRIP: flag = GL_LINE_STRIP; break;
+ case Gfx::PRIMITIVE_TRIANGLES: flag = GL_TRIANGLES; break;
+ case Gfx::PRIMITIVE_TRIANGLE_STRIP: flag = GL_TRIANGLE_STRIP; break;
+ default: assert(false); break;
+ }
+ return flag;
+}
+
+void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const Vertex *vertices, int vertexCount)
+{
+ glBegin(TranslateGfxPrimitive(type));
+
+ glColor3f(1.0f, 1.0f, 1.0f);
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ glNormal3fv(const_cast<GLfloat*>(vertices[i].normal.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array()));
+ }
+
+ glEnd();
+}
+
+void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount)
+{
+ glBegin(TranslateGfxPrimitive(type));
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ glColor4fv(const_cast<GLfloat*>(vertices[i].color.Array()));
+ glSecondaryColor3fv(const_cast<GLfloat*>(vertices[i].specular.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array()));
+ }
+
+ glEnd();
+}
+
+void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, const VertexTex2 *vertices, int vertexCount)
+{
+ glBegin(TranslateGfxPrimitive(type));
+
+ glColor3f(1.0f, 1.0f, 1.0f);
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ glNormal3fv(const_cast<GLfloat*>(vertices[i].normal.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE0, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glMultiTexCoord2fv(GL_TEXTURE1, const_cast<GLfloat*>(vertices[i].texCoord.Array()));
+ glVertex3fv(const_cast<GLfloat*>(vertices[i].coord.Array()));
+ }
+
+ glEnd();
+}
+
+bool InPlane(Math::Vector normal, float originPlane, Math::Vector center, float radius)
+{
+ float distance = (originPlane + Math::DotProduct(normal, center)) / normal.Length();
+
+ if (distance < -radius)
+ return true;
+
+ return false;
+}
+
+/*
+ The implementation of ComputeSphereVisibility is taken from libwine's device.c
+ Copyright of the WINE team, licensed under GNU LGPL v 2.1
+ */
+
+// TODO: testing
+int Gfx::CGLDevice::ComputeSphereVisibility(const Math::Vector &center, float radius)
+{
+ Math::Matrix m;
+ m.LoadIdentity();
+ m = Math::MultiplyMatrices(m, m_worldMat);
+ m = Math::MultiplyMatrices(m, m_viewMat);
+ m = Math::MultiplyMatrices(m, m_projectionMat);
+
+ Math::Vector vec[6];
+ float originPlane[6];
+
+ // Left plane
+ vec[0].x = m.Get(4, 1) + m.Get(1, 1);
+ vec[0].y = m.Get(4, 2) + m.Get(1, 2);
+ vec[0].z = m.Get(4, 3) + m.Get(1, 3);
+ originPlane[0] = m.Get(4, 4) + m.Get(1, 4);
+
+ // Right plane
+ vec[1].x = m.Get(4, 1) - m.Get(1, 1);
+ vec[1].y = m.Get(4, 2) - m.Get(1, 2);
+ vec[1].z = m.Get(4, 3) - m.Get(1, 3);
+ originPlane[1] = m.Get(4, 4) - m.Get(1, 4);
+
+ // Top plane
+ vec[2].x = m.Get(4, 1) - m.Get(2, 1);
+ vec[2].y = m.Get(4, 2) - m.Get(2, 2);
+ vec[2].z = m.Get(4, 3) - m.Get(2, 3);
+ originPlane[2] = m.Get(4, 4) - m.Get(2, 4);
+
+ // Bottom plane
+ vec[3].x = m.Get(4, 1) + m.Get(2, 1);
+ vec[3].y = m.Get(4, 2) + m.Get(2, 2);
+ vec[3].z = m.Get(4, 3) + m.Get(2, 3);
+ originPlane[3] = m.Get(4, 4) + m.Get(2, 4);
+
+ // Front plane
+ vec[4].x = m.Get(3, 1);
+ vec[4].y = m.Get(3, 2);
+ vec[4].z = m.Get(3, 3);
+ originPlane[4] = m.Get(3, 4);
+
+ // Back plane
+ vec[5].x = m.Get(4, 1) - m.Get(3, 1);
+ vec[5].y = m.Get(4, 2) - m.Get(3, 2);
+ vec[5].z = m.Get(4, 3) - m.Get(3, 3);
+ originPlane[5] = m.Get(4, 4) - m.Get(3, 4);
+
+ int result = 0;
+
+ if (InPlane(vec[0], originPlane[0], center, radius))
+ result |= Gfx::INTERSECT_PLANE_LEFT;
+ if (InPlane(vec[1], originPlane[1], center, radius))
+ result |= Gfx::INTERSECT_PLANE_RIGHT;
+ if (InPlane(vec[2], originPlane[2], center, radius))
+ result |= Gfx::INTERSECT_PLANE_TOP;
+ if (InPlane(vec[3], originPlane[3], center, radius))
+ result |= Gfx::INTERSECT_PLANE_BOTTOM;
+ if (InPlane(vec[4], originPlane[4], center, radius))
+ result |= Gfx::INTERSECT_PLANE_FRONT;
+ if (InPlane(vec[5], originPlane[5], center, radius))
+ result |= Gfx::INTERSECT_PLANE_BACK;
+
+ return result;
+}
+
+void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled)
+{
+ if (state == Gfx::RENDER_STATE_DEPTH_WRITE)
+ {
+ glDepthMask(enabled ? GL_TRUE : GL_FALSE);
+ return;
+ }
+ else if (state == Gfx::RENDER_STATE_LIGHTING)
+ {
+ m_lighting = enabled;
+
+ if (enabled)
+ glEnable(GL_LIGHTING);
+ else
+ glDisable(GL_LIGHTING);
+
+ if (enabled)
+ {
+ for (int index = 0; index < static_cast<int>( m_lights.size() ); ++index)
+ UpdateLightPosition(index);
+ }
+
+ return;
+ }
+ else if (state == Gfx::RENDER_STATE_TEXTURING)
+ {
+ m_texturing = enabled;
+
+ // Enable/disable stages with new setting
+ for (int index = 0; index < static_cast<int>( m_currentTextures.size() ); ++index)
+ {
+ glActiveTexture(GL_TEXTURE0 + index);
+ if (m_texturing && m_texturesEnabled[index])
+ glEnable(GL_TEXTURE_2D);
+ else
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ return;
+ }
+
+ GLenum flag = 0;
+
+ switch (state)
+ {
+ case Gfx::RENDER_STATE_BLENDING: flag = GL_BLEND; break;
+ case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break;
+ case Gfx::RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
+ case Gfx::RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
+ case Gfx::RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
+ case Gfx::RENDER_STATE_DITHERING: flag = GL_DITHER; break;
+ default: assert(false); break;
+ }
+
+ if (enabled)
+ glEnable(flag);
+ else
+ glDisable(flag);
+}
+
+bool Gfx::CGLDevice::GetRenderState(Gfx::RenderState state)
+{
+ if (state == Gfx::RENDER_STATE_LIGHTING)
+ return m_lighting;
+
+ if (state == Gfx::RENDER_STATE_TEXTURING)
+ return m_texturing;
+
+ GLenum flag = 0;
+
+ switch (state)
+ {
+ case Gfx::RENDER_STATE_DEPTH_WRITE: flag = GL_DEPTH_WRITEMASK; break;
+ case Gfx::RENDER_STATE_BLENDING: flag = GL_BLEND; break;
+ case Gfx::RENDER_STATE_FOG: flag = GL_FOG; break;
+ case Gfx::RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
+ case Gfx::RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
+ case Gfx::RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
+ case Gfx::RENDER_STATE_DITHERING: flag = GL_DITHER; break;
+ default: assert(false); break;
+ }
+
+ GLboolean result = GL_FALSE;
+ glGetBooleanv(flag, &result);
+
+ return result == GL_TRUE;
+}
+
+Gfx::CompFunc TranslateGLCompFunc(GLenum flag)
+{
+ switch (flag)
+ {
+ case GL_NEVER: return Gfx::COMP_FUNC_NEVER;
+ case GL_LESS: return Gfx::COMP_FUNC_LESS;
+ case GL_EQUAL: return Gfx::COMP_FUNC_EQUAL;
+ case GL_NOTEQUAL: return Gfx::COMP_FUNC_NOTEQUAL;
+ case GL_LEQUAL: return Gfx::COMP_FUNC_LEQUAL;
+ case GL_GREATER: return Gfx::COMP_FUNC_GREATER;
+ case GL_GEQUAL: return Gfx::COMP_FUNC_GEQUAL;
+ case GL_ALWAYS: return Gfx::COMP_FUNC_ALWAYS;
+ default: assert(false); break;
+ }
+ return Gfx::COMP_FUNC_NEVER;
+}
+
+GLenum TranslateGfxCompFunc(Gfx::CompFunc func)
+{
+ switch (func)
+ {
+ case Gfx::COMP_FUNC_NEVER: return GL_NEVER;
+ case Gfx::COMP_FUNC_LESS: return GL_LESS;
+ case Gfx::COMP_FUNC_EQUAL: return GL_EQUAL;
+ case Gfx::COMP_FUNC_NOTEQUAL: return GL_NOTEQUAL;
+ case Gfx::COMP_FUNC_LEQUAL: return GL_LEQUAL;
+ case Gfx::COMP_FUNC_GREATER: return GL_GREATER;
+ case Gfx::COMP_FUNC_GEQUAL: return GL_GEQUAL;
+ case Gfx::COMP_FUNC_ALWAYS: return GL_ALWAYS;
+ default: assert(false); break;
+ }
+ return 0;
+}
+
+void Gfx::CGLDevice::SetDepthTestFunc(Gfx::CompFunc func)
+{
+ glDepthFunc(TranslateGfxCompFunc(func));
+}
+
+Gfx::CompFunc Gfx::CGLDevice::GetDepthTestFunc()
+{
+ GLint flag = 0;
+ glGetIntegerv(GL_DEPTH_FUNC, &flag);
+ return TranslateGLCompFunc(static_cast<GLenum>(flag));
+}
+
+void Gfx::CGLDevice::SetDepthBias(float factor)
+{
+ glPolygonOffset(factor, 0.0f);
+}
+
+float Gfx::CGLDevice::GetDepthBias()
+{
+ GLfloat result = 0.0f;
+ glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &result);
+ return result;
+}
+
+void Gfx::CGLDevice::SetAlphaTestFunc(Gfx::CompFunc func, float refValue)
+{
+ glAlphaFunc(TranslateGfxCompFunc(func), refValue);
+}
+
+void Gfx::CGLDevice::GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue)
+{
+ GLint flag = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, &flag);
+ func = TranslateGLCompFunc(static_cast<GLenum>(flag));
+
+ glGetFloatv(GL_ALPHA_TEST_REF, static_cast<GLfloat*>(&refValue));
+}
+
+Gfx::BlendFunc TranslateGLBlendFunc(GLenum flag)
+{
+ switch (flag)
+ {
+ case GL_ZERO: return Gfx::BLEND_ZERO;
+ case GL_ONE: return Gfx::BLEND_ONE;
+ case GL_SRC_COLOR: return Gfx::BLEND_SRC_COLOR;
+ case GL_ONE_MINUS_SRC_COLOR: return Gfx::BLEND_INV_SRC_COLOR;
+ case GL_DST_COLOR: return Gfx::BLEND_DST_COLOR;
+ case GL_ONE_MINUS_DST_COLOR: return Gfx::BLEND_INV_DST_COLOR;
+ case GL_SRC_ALPHA: return Gfx::BLEND_SRC_ALPHA;
+ case GL_ONE_MINUS_SRC_ALPHA: return Gfx::BLEND_INV_SRC_ALPHA;
+ case GL_DST_ALPHA: return Gfx::BLEND_DST_ALPHA;
+ case GL_ONE_MINUS_DST_ALPHA: return Gfx::BLEND_INV_DST_ALPHA;
+ case GL_SRC_ALPHA_SATURATE: return Gfx::BLEND_SRC_ALPHA_SATURATE;
+ default: assert(false); break;
+ }
+
+ return Gfx::BLEND_ZERO;
+}
+
+GLenum TranslateGfxBlendFunc(Gfx::BlendFunc func)
+{
+ switch (func)
+ {
+ case Gfx::BLEND_ZERO: return GL_ZERO;
+ case Gfx::BLEND_ONE: return GL_ONE;
+ case Gfx::BLEND_SRC_COLOR: return GL_SRC_COLOR;
+ case Gfx::BLEND_INV_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
+ case Gfx::BLEND_DST_COLOR: return GL_DST_COLOR;
+ case Gfx::BLEND_INV_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
+ case Gfx::BLEND_SRC_ALPHA: return GL_SRC_ALPHA;
+ case Gfx::BLEND_INV_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
+ case Gfx::BLEND_DST_ALPHA: return GL_DST_ALPHA;
+ case Gfx::BLEND_INV_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
+ case Gfx::BLEND_SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE;
+ default: assert(false); break;
+ }
+ return 0;
+}
+
+void Gfx::CGLDevice::SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend)
+{
+ glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend));
+}
+
+void Gfx::CGLDevice::GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend)
+{
+ GLint srcFlag = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, &srcFlag);
+ srcBlend = TranslateGLBlendFunc(static_cast<GLenum>(srcFlag));
+
+ GLint dstFlag = 0;
+ glGetIntegerv(GL_ALPHA_TEST_FUNC, &dstFlag);
+ dstBlend = TranslateGLBlendFunc(static_cast<GLenum>(dstFlag));
+}
+
+void Gfx::CGLDevice::SetClearColor(const Gfx::Color &color)
+{
+ glClearColor(color.r, color.g, color.b, color.a);
+}
+
+Gfx::Color Gfx::CGLDevice::GetClearColor()
+{
+ GLfloat color[4] = { 0.0f };
+ glGetFloatv(GL_COLOR_CLEAR_VALUE, color);
+ return Gfx::Color(color[0], color[1], color[2], color[3]);
+}
+
+void Gfx::CGLDevice::SetGlobalAmbient(const Gfx::Color &color)
+{
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array());
+}
+
+Gfx::Color Gfx::CGLDevice::GetGlobalAmbient()
+{
+ GLfloat color[4] = { 0.0f };
+ glGetFloatv(GL_LIGHT_MODEL_AMBIENT, color);
+ return Gfx::Color(color[0], color[1], color[2], color[3]);
+}
+
+void Gfx::CGLDevice::SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density)
+{
+ if (mode == Gfx::FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR);
+ else if (mode == Gfx::FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP);
+ else if (mode == Gfx::FOG_EXP2) glFogi(GL_FOG_MODE, GL_EXP2);
+ else assert(false);
+
+ glFogf(GL_FOG_START, start);
+ glFogf(GL_FOG_END, end);
+ glFogf(GL_FOG_DENSITY, density);
+}
+
+void Gfx::CGLDevice::GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density)
+{
+ GLint flag = 0;
+ glGetIntegerv(GL_FOG_MODE, &flag);
+ if (flag == GL_LINEAR) mode = Gfx::FOG_LINEAR;
+ else if (flag == GL_EXP) mode = Gfx::FOG_EXP;
+ else if (flag == GL_EXP2) mode = Gfx::FOG_EXP2;
+ else assert(false);
+
+ glGetFloatv(GL_FOG_START, static_cast<GLfloat*>(&start));
+ glGetFloatv(GL_FOG_END, static_cast<GLfloat*>(&end));
+ glGetFloatv(GL_FOG_DENSITY, static_cast<GLfloat*>(&density));
+}
+
+void Gfx::CGLDevice::SetCullMode(Gfx::CullMode mode)
+{
+ if (mode == Gfx::CULL_CW) glCullFace(GL_CW);
+ else if (mode == Gfx::CULL_CCW) glCullFace(GL_CCW);
+ else assert(false);
+}
+
+Gfx::CullMode Gfx::CGLDevice::GetCullMode()
+{
+ GLint flag = 0;
+ glGetIntegerv(GL_CULL_FACE, &flag);
+ if (flag == GL_CW) return Gfx::CULL_CW;
+ else if (flag == GL_CCW) return Gfx::CULL_CCW;
+ else assert(false);
+ return Gfx::CULL_CW;
+}
+
+void Gfx::CGLDevice::SetShadeModel(Gfx::ShadeModel model)
+{
+ if (model == Gfx::SHADE_FLAT) glShadeModel(GL_FLAT);
+ else if (model == Gfx::SHADE_SMOOTH) glShadeModel(GL_SMOOTH);
+ else assert(false);
+}
+
+Gfx::ShadeModel Gfx::CGLDevice::GetShadeModel()
+{
+ GLint flag = 0;
+ glGetIntegerv(GL_SHADE_MODEL, &flag);
+ if (flag == GL_FLAT) return Gfx::SHADE_FLAT;
+ else if (flag == GL_SMOOTH) return Gfx::SHADE_SMOOTH;
+ else assert(false);
+ return Gfx::SHADE_FLAT;
+}
+
+void Gfx::CGLDevice::SetFillMode(Gfx::FillMode mode)
+{
+ if (mode == Gfx::FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+ else if (mode == Gfx::FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ else if (mode == Gfx::FILL_FILL) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ else assert(false);
+}
+
+Gfx::FillMode Gfx::CGLDevice::GetFillMode()
+{
+ GLint flag = 0;
+ glGetIntegerv(GL_POLYGON_MODE, &flag);
+ if (flag == GL_POINT) return Gfx::FILL_POINT;
+ else if (flag == GL_LINE) return Gfx::FILL_LINES;
+ else if (flag == GL_FILL) return Gfx::FILL_FILL;
+ else assert(false);
+ return Gfx::FILL_POINT;
+}
diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h
index a2fb4a0..1864000 100644
--- a/src/graphics/opengl/gldevice.h
+++ b/src/graphics/opengl/gldevice.h
@@ -19,13 +19,185 @@
#pragma once
-#include "graphics/common/device.h"
+#include "graphics/core/device.h"
+
+#include <string>
+#include <vector>
+#include <set>
+
namespace Gfx {
+/**
+ \struct GLDeviceConfig
+ \brief Additional config with OpenGL-specific settings */
+struct GLDeviceConfig : public DeviceConfig
+{
+ //! Size of red channel in bits
+ int redSize;
+ //! Size of green channel in bits
+ int greenSize;
+ //! Size of blue channel in bits
+ int blueSize;
+ //! Size of alpha channel in bits
+ int alphaSize;
+ //! Color depth in bits
+ int depthSize;
+
+ //! Force hardware acceleration (video mode set will fail on lack of hw accel)
+ bool hardwareAccel;
+
+ //! Constructor calls LoadDefaults()
+ GLDeviceConfig() { LoadDefault(); }
+
+ //! Loads the default values
+ void LoadDefault();
+};
+
+struct GLDevicePrivate;
+
+/**
+ \class CGLDevice
+ \brief Implementation of CDevice interface in OpenGL
+
+ Provides the concrete implementation of 3D device in OpenGL.
+
+ This class should be initialized (by calling Initialize() ) only after
+ setting the video mode by CApplication, once the OpenGL context is defined.
+ Because of that, CGLDeviceConfig is outside the CDevice class and must be set
+ in CApplication.
+*/
class CGLDevice : public Gfx::CDevice
{
- // TODO
+public:
+ CGLDevice(const Gfx::GLDeviceConfig &config);
+ virtual ~CGLDevice();
+
+ virtual bool GetWasInit();
+ virtual std::string GetError();
+
+ virtual bool Create();
+ virtual void Destroy();
+
+ void ConfigChanged(const Gfx::GLDeviceConfig &newConfig);
+
+ virtual void BeginScene();
+ virtual void EndScene();
+
+ virtual void Clear();
+
+ virtual void SetTransform(Gfx::TransformType type, const Math::Matrix &matrix);
+ virtual const Math::Matrix& GetTransform(Gfx::TransformType type);
+ virtual void MultiplyTransform(Gfx::TransformType type, const Math::Matrix &matrix);
+
+ virtual void SetMaterial(const Gfx::Material &material);
+ virtual const Gfx::Material& GetMaterial();
+
+ virtual int GetMaxLightCount();
+ virtual void SetLight(int index, const Gfx::Light &light);
+ virtual const Gfx::Light& GetLight(int index);
+ virtual void SetLightEnabled(int index, bool enabled);
+ virtual bool GetLightEnabled(int index);
+
+ virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams &params);
+ virtual void DestroyTexture(const Gfx::Texture &texture);
+ virtual void DestroyAllTextures();
+
+ virtual int GetMaxTextureCount();
+ virtual void SetTexture(int index, const Gfx::Texture &texture);
+ virtual Gfx::Texture GetTexture(int index);
+ virtual void SetTextureEnabled(int index, bool enabled);
+ virtual bool GetTextureEnabled(int index);
+
+ virtual void SetTextureStageParams(int index, const Gfx::TextureStageParams &params);
+ virtual Gfx::TextureStageParams GetTextureStageParams(int index);
+
+ virtual void SetTextureFactor(const Gfx::Color &color);
+ virtual Gfx::Color GetTextureFactor();
+
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::Vertex *vertices, int vertexCount);
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount);
+ virtual void DrawPrimitive(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount);
+
+ virtual int ComputeSphereVisibility(const Math::Vector &center, float radius);
+
+ virtual void SetRenderState(Gfx::RenderState state, bool enabled);
+ virtual bool GetRenderState(Gfx::RenderState state);
+
+ virtual void SetDepthTestFunc(Gfx::CompFunc func);
+ virtual Gfx::CompFunc GetDepthTestFunc();
+
+ virtual void SetDepthBias(float factor);
+ virtual float GetDepthBias();
+
+ virtual void SetAlphaTestFunc(Gfx::CompFunc func, float refValue);
+ virtual void GetAlphaTestFunc(Gfx::CompFunc &func, float &refValue);
+
+ virtual void SetBlendFunc(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend);
+ virtual void GetBlendFunc(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend);
+
+ virtual void SetClearColor(const Gfx::Color &color);
+ virtual Gfx::Color GetClearColor();
+
+ virtual void SetGlobalAmbient(const Gfx::Color &color);
+ virtual Gfx::Color GetGlobalAmbient();
+
+ virtual void SetFogParams(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density);
+ virtual void GetFogParams(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density);
+
+ virtual void SetCullMode(Gfx::CullMode mode);
+ virtual Gfx::CullMode GetCullMode();
+
+ virtual void SetShadeModel(Gfx::ShadeModel model);
+ virtual Gfx::ShadeModel GetShadeModel();
+
+ virtual void SetFillMode(Gfx::FillMode mode) ;
+ virtual Gfx::FillMode GetFillMode();
+
+private:
+ //! Updates internal modelview matrix
+ void UpdateModelviewMatrix();
+ //! Updates position for given light based on transformation matrices
+ void UpdateLightPosition(int index);
+
+private:
+ //! Current config
+ Gfx::GLDeviceConfig m_config;
+ //! Was initialized?
+ bool m_wasInit;
+ //! Last encountered error
+ std::string m_error;
+
+ //! Current world matrix
+ Math::Matrix m_worldMat;
+ //! Current view matrix
+ Math::Matrix m_viewMat;
+ //! OpenGL modelview matrix = world matrix * view matrix
+ Math::Matrix m_modelviewMat;
+ //! Current projection matrix
+ Math::Matrix m_projectionMat;
+
+ //! The current material
+ Gfx::Material m_material;
+
+ //! Whether lighting is enabled
+ bool m_lighting;
+ //! Current lights
+ std::vector<Gfx::Light> m_lights;
+ //! Current lights enable status
+ std::vector<bool> m_lightsEnabled;
+
+ //! Whether texturing is enabled in general
+ bool m_texturing;
+ //! Current textures; \c NULL value means unassigned
+ std::vector<Gfx::Texture> m_currentTextures;
+ //! Current texture stages enable status
+ std::vector<bool> m_texturesEnabled;
+ //! Current texture params
+ std::vector<Gfx::TextureStageParams> m_textureStageParams;
+
+ //! Set of all created textures
+ std::set<Gfx::Texture> m_allTextures;
};
}; // namespace Gfx
diff --git a/src/graphics/opengl/glengine.cpp b/src/graphics/opengl/glengine.cpp
deleted file mode 100644
index 9aab348..0000000
--- a/src/graphics/opengl/glengine.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// glengine.h
-
-#include "graphics/opengl/glengine.h"
-
-// TODO \ No newline at end of file
diff --git a/src/graphics/opengl/glengine.h b/src/graphics/opengl/glengine.h
deleted file mode 100644
index fa67bfe..0000000
--- a/src/graphics/opengl/glengine.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// glengine.h
-
-#pragma once
-
-
-#include "graphics/common/engine.h"
-
-namespace Gfx
-{
-
-class CGLEngine : public Gfx::CEngine
-{
- // TODO
-};
-
-};
diff --git a/src/graphics/opengl/test/CMakeLists.txt b/src/graphics/opengl/test/CMakeLists.txt
new file mode 100644
index 0000000..8ed7364
--- /dev/null
+++ b/src/graphics/opengl/test/CMakeLists.txt
@@ -0,0 +1,87 @@
+cmake_minimum_required(VERSION 2.8)
+
+find_package(OpenGL REQUIRED)
+find_package(SDL REQUIRED)
+find_package(SDL_image REQUIRED)
+find_package(PNG REQUIRED)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+set(ADD_LIBS "")
+
+if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
+ set(PLATFORM_WINDOWS 1)
+ set(PLATFORM_LINUX 0)
+ set(PLATFORM_OTHER 0)
+elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ set(PLATFORM_WINDOWS 0)
+ set(PLATFORM_LINUX 1)
+ set(PLATFORM_OTHER 0)
+ set(ADD_LIBS "-lrt")
+else()
+ set(PLATFORM_WINDOWS 0)
+ set(PLATFORM_LINUX 0)
+ set(PLATFORM_OTHER 1)
+endif()
+
+configure_file(../../../common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
+
+
+set(TEXTURE_SOURCES
+../gldevice.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+texture_test.cpp
+)
+
+set(MODEL_SOURCES
+../gldevice.cpp
+../../engine/modelfile.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../common/stringutils.cpp
+../../../app/system.cpp
+model_test.cpp
+)
+
+set(TRANSFORM_SOURCES
+../gldevice.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../app/system.cpp
+transform_test.cpp
+)
+
+set(LIGHT_SOURCES
+../gldevice.cpp
+../../../common/logger.cpp
+../../../common/image.cpp
+../../../common/iman.cpp
+../../../app/system.cpp
+light_test.cpp
+)
+
+include_directories(../../../ ${CMAKE_CURRENT_BINARY_DIR})
+
+set(LIBS
+${SDL_LIBRARY}
+${SDLIMAGE_LIBRARY}
+${OPENGL_LIBRARY}
+${PNG_LIBRARIES}
+${ADD_LIBS}
+)
+
+add_executable(texture_test ${TEXTURE_SOURCES})
+target_link_libraries(texture_test ${LIBS})
+
+add_executable(model_test ${MODEL_SOURCES})
+target_link_libraries(model_test ${LIBS})
+
+add_executable(transform_test ${TRANSFORM_SOURCES})
+target_link_libraries(transform_test ${LIBS})
+
+add_executable(light_test ${LIGHT_SOURCES})
+target_link_libraries(light_test ${LIBS})
diff --git a/src/graphics/opengl/test/README.txt b/src/graphics/opengl/test/README.txt
new file mode 100644
index 0000000..c618415
--- /dev/null
+++ b/src/graphics/opengl/test/README.txt
@@ -0,0 +1,9 @@
+Test programs for OpenGL engine:
+ - texture_test -> multitexturing test with 2 textures (included as files: ./tex1.png, ./tex2.png)
+ - model_test -> simple model viewer to test model loading
+ usage: ./model_test {dxf|mod} model_file
+ second argument is the loaded format (DXF or Colobot .mod files)
+ requires ./tex folder (or symlink) with Colobot textures
+ viewer is controlled from keyboard - the bindings can be found in code
+ - transform_test -> simple "walk around" test for world & view transformations
+ - light test -> test for lighting
diff --git a/src/graphics/opengl/test/light_test.cpp b/src/graphics/opengl/test/light_test.cpp
new file mode 100644
index 0000000..80fa911
--- /dev/null
+++ b/src/graphics/opengl/test/light_test.cpp
@@ -0,0 +1,437 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <map>
+
+enum KeySlots
+{
+ K_Forward,
+ K_Back,
+ K_Left,
+ K_Right,
+ K_Up,
+ K_Down,
+ K_Count
+};
+bool KEYMAP[K_Count] = { false };
+
+Math::Point MOUSE_POS_BASE;
+
+Math::Vector TRANSLATION(0.0f, 2.0f, 0.0f);
+Math::Vector ROTATION, ROTATION_BASE;
+
+float CUBE_ORBIT = 0.0f;
+
+const int FRAME_DELAY = 5000;
+
+SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL;
+
+void Init(Gfx::CGLDevice *device)
+{
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+}
+
+void Render(Gfx::CGLDevice *device)
+{
+ device->BeginScene();
+
+ /* Unlit part of scene */
+
+ device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, false);
+ device->SetRenderState(Gfx::RENDER_STATE_CULLING, false); // Double-sided drawing
+
+ Math::Matrix persp;
+ Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp);
+
+
+ Math::Matrix viewMat;
+ Math::Matrix mat;
+
+ viewMat.LoadIdentity();
+
+ Math::LoadRotationXMatrix(mat, -ROTATION.x);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadRotationYMatrix(mat, -ROTATION.y);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadTranslationMatrix(mat, -TRANSLATION);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat);
+
+ Math::Matrix worldMat;
+ worldMat.LoadIdentity();
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ Gfx::VertexCol line[2] = { Gfx::VertexCol() };
+
+ for (int x = -40; x <= 40; ++x)
+ {
+ line[0].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[0].coord.z = -40;
+ line[0].coord.x = x;
+ line[1].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[1].coord.z = 40;
+ line[1].coord.x = x;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+ for (int z = -40; z <= 40; ++z)
+ {
+ line[0].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[0].coord.z = z;
+ line[0].coord.x = -40;
+ line[1].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[1].coord.z = z;
+ line[1].coord.x = 40;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+
+ Gfx::VertexCol quad[6] = { Gfx::VertexCol() };
+
+ quad[0].coord = Math::Vector(-1.0f, -1.0f, 0.0f);
+ quad[1].coord = Math::Vector( 1.0f, -1.0f, 0.0f);
+ quad[2].coord = Math::Vector(-1.0f, 1.0f, 0.0f);
+ quad[3].coord = Math::Vector( 1.0f, 1.0f, 0.0f);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 1.0f, 0.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(40.0f, 2.0f, 40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(0.0f, 1.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 0.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(10.0f, 4.5f, 5.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
+
+ /* Moving lit cube */
+ device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+ device->SetRenderState(Gfx::RENDER_STATE_CULLING, true); // Culling (CCW faces)
+
+ device->SetGlobalAmbient(Gfx::Color(0.4f, 0.4f, 0.4f));
+
+ Gfx::Light light1;
+ light1.type = Gfx::LIGHT_POINT;
+ light1.position = Math::Vector(10.0f, 4.5f, 5.0f);
+ light1.ambient = Gfx::Color(0.2f, 0.2f, 0.2f);
+ light1.diffuse = Gfx::Color(1.0f, 0.1f, 0.1f);
+ light1.specular = Gfx::Color(0.0f, 0.0f, 0.0f);
+ device->SetLight(0, light1);
+ device->SetLightEnabled(0, true);
+
+ /*Gfx::Light light2;
+ device->SetLight(1, light2);
+ device->SetLightEnabled(1, true);*/
+
+ Gfx::Material material;
+ material.ambient = Gfx::Color(0.3f, 0.3f, 0.3f);
+ material.diffuse = Gfx::Color(0.8f, 0.7f, 0.6f);
+ material.specular = Gfx::Color(0.0f, 0.0f, 0.0f);
+ device->SetMaterial(material);
+
+ const Gfx::Vertex cube[6][4] =
+ {
+ {
+ // Front
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 0.0f, -1.0f))
+ },
+
+ {
+ // Back
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 0.0f, 1.0f))
+ },
+
+ {
+ // Top
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 0.0f, 1.0f, 0.0f))
+ },
+
+ {
+ // Bottom
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, -1.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 0.0f, -1.0f, 0.0f))
+ },
+
+ {
+ // Left
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, 1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, 1.0f), Math::Vector(-1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector(-1.0f, 1.0f, -1.0f), Math::Vector(-1.0f, 0.0f, 0.0f))
+ },
+
+ {
+ // Right
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, -1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, -1.0f, 1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, -1.0f), Math::Vector( 1.0f, 0.0f, 0.0f)),
+ Gfx::Vertex(Math::Vector( 1.0f, 1.0f, 1.0f), Math::Vector( 1.0f, 0.0f, 0.0f))
+ }
+ };
+
+ Math::Matrix cubeTrans;
+ Math::LoadTranslationMatrix(cubeTrans, Math::Vector(10.0f, 2.0f, 5.0f));
+ Math::Matrix cubeRot;
+ Math::LoadRotationMatrix(cubeRot, Math::Vector(0.0f, 1.0f, 0.0f), CUBE_ORBIT);
+ Math::Matrix cubeRotInv;
+ Math::LoadRotationMatrix(cubeRotInv, Math::Vector(0.0f, 1.0f, 0.0f), -CUBE_ORBIT);
+ Math::Matrix cubeTransRad;
+ Math::LoadTranslationMatrix(cubeTransRad, Math::Vector(0.0f, 0.0f, 6.0f));
+ worldMat = Math::MultiplyMatrices(cubeTransRad, cubeRotInv);
+ worldMat = Math::MultiplyMatrices(cubeRot, worldMat);
+ worldMat = Math::MultiplyMatrices(cubeTrans, worldMat);
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ for (int i = 0; i < 6; ++i)
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, cube[i], 4);
+
+ device->EndScene();
+}
+
+void Update()
+{
+ const float TRANS_SPEED = 6.0f; // units / sec
+
+ GetCurrentTimeStamp(CURR_TIME);
+ float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
+ CopyTimeStamp(PREV_TIME, CURR_TIME);
+
+ CUBE_ORBIT += timeDiff * (Math::PI / 4.0f);
+
+ Math::Vector incTrans;
+
+ if (KEYMAP[K_Forward])
+ incTrans.z = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Back])
+ incTrans.z = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Right])
+ incTrans.x = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Left])
+ incTrans.x = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Up])
+ incTrans.y = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Down])
+ incTrans.y = -TRANS_SPEED * timeDiff;
+
+ Math::Point rotTrans = Math::RotatePoint(-ROTATION.y, Math::Point(incTrans.x, incTrans.z));
+ incTrans.x = rotTrans.x;
+ incTrans.z = rotTrans.y;
+ TRANSLATION += incTrans;
+}
+
+void KeyboardDown(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = true;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = true;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = true;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = true;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = true;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KeyboardUp(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = false;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = false;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = false;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = false;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = false;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void MouseMove(int x, int y)
+{
+ Math::Point currentPos((float)x, (float)y);
+
+ static bool first = true;
+ if (first || (x < 10) || (y < 10) || (x > 790) || (y > 590))
+ {
+ SDL_WarpMouse(400, 300);
+ MOUSE_POS_BASE.x = 400;
+ MOUSE_POS_BASE.y = 300;
+ ROTATION_BASE = ROTATION;
+ first = false;
+ return;
+ }
+
+ ROTATION.y = ROTATION_BASE.y + ((float) (x - MOUSE_POS_BASE.x) / 800.0f) * Math::PI;
+ ROTATION.x = ROTATION_BASE.x + ((float) (y - MOUSE_POS_BASE.y) / 600.0f) * Math::PI;
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+
+ PREV_TIME = CreateTimeStamp();
+ CURR_TIME = CreateTimeStamp();
+
+ GetCurrentTimeStamp(PREV_TIME);
+ GetCurrentTimeStamp(CURR_TIME);
+
+ CInstanceManager iMan;
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Light Test", "Light Test");
+
+ //SDL_WM_GrabInput(SDL_GRAB_ON);
+ SDL_ShowCursor(SDL_DISABLE);
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device);
+ Update();
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ if (event.type == SDL_QUIT)
+ {
+ break;
+ done = true;
+ }
+ else if (event.type == SDL_KEYDOWN)
+ {
+ if (event.key.keysym.sym == SDLK_q)
+ {
+ done = true;
+ break;
+ }
+ else
+ KeyboardDown(event.key.keysym.sym);
+ }
+ else if (event.type == SDL_KEYUP)
+ KeyboardUp(event.key.keysym.sym);
+ else if (event.type == SDL_MOUSEMOTION)
+ MouseMove(event.motion.x, event.motion.y);
+ }
+
+ usleep(FRAME_DELAY);
+ }
+
+ //SDL_WM_GrabInput(SDL_GRAB_OFF);
+ SDL_ShowCursor(SDL_ENABLE);
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ DestroyTimeStamp(PREV_TIME);
+ DestroyTimeStamp(CURR_TIME);
+
+ return 0;
+}
diff --git a/src/graphics/opengl/test/model_test.cpp b/src/graphics/opengl/test/model_test.cpp
new file mode 100644
index 0000000..3e8efe6
--- /dev/null
+++ b/src/graphics/opengl/test/model_test.cpp
@@ -0,0 +1,377 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/engine/modelfile.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <map>
+
+enum KeySlots
+{
+ K_RotXUp,
+ K_RotXDown,
+ K_RotYLeft,
+ K_RotYRight,
+ K_Forward,
+ K_Back,
+ K_Left,
+ K_Right,
+ K_Up,
+ K_Down,
+ K_Count
+};
+bool KEYMAP[K_Count] = { false };
+
+Math::Vector TRANSLATION(0.0f, 0.0f, 30.0f);
+Math::Vector ROTATION;
+
+const int FRAME_DELAY = 5000;
+
+std::map<std::string, Gfx::Texture> TEXS;
+
+SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL;
+
+Gfx::Texture GetTexture(const std::string &name)
+{
+ std::map<std::string, Gfx::Texture>::iterator it = TEXS.find(name);
+ if (it == TEXS.end())
+ return Gfx::Texture();
+
+ return (*it).second;
+}
+
+void LoadTexture(Gfx::CGLDevice *device, const std::string &name)
+{
+ if (name.empty())
+ return;
+
+ Gfx::Texture tex = GetTexture(name);
+
+ if (tex.valid)
+ return;
+
+ CImage img;
+ if (! img.Load(std::string("tex/") + name))
+ {
+ std::string err = img.GetError();
+ GetLogger()->Error("Texture not loaded, error: %s!\n", err.c_str());
+ }
+ else
+ {
+ Gfx::TextureCreateParams texCreateParams;
+ texCreateParams.mipmap = true;
+ if (img.GetData()->surface->format->Amask == 0)
+ texCreateParams.format = Gfx::TEX_IMG_BGR;
+ else
+ texCreateParams.format = Gfx::TEX_IMG_BGRA;
+ texCreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
+ texCreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
+
+ tex = device->CreateTexture(&img, texCreateParams);
+ }
+
+ TEXS[name] = tex;
+}
+
+void Init(Gfx::CGLDevice *device, Gfx::CModelFile *model)
+{
+ std::vector<Gfx::ModelTriangle> &triangles = model->GetTriangles();
+
+ for (int i = 0; i < (int) triangles.size(); ++i)
+ {
+ LoadTexture(device, triangles[i].tex1Name);
+ LoadTexture(device, triangles[i].tex2Name);
+ }
+
+ device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+ device->SetRenderState(Gfx::RENDER_STATE_LIGHTING, true);
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+
+ Gfx::Light light;
+ light.type = Gfx::LIGHT_DIRECTIONAL;
+ light.ambient = Gfx::Color(0.4f, 0.4f, 0.4f, 0.0f);
+ light.diffuse = Gfx::Color(0.8f, 0.8f, 0.8f, 0.0f);
+ light.specular = Gfx::Color(0.2f, 0.2f, 0.2f, 0.0f);
+ light.position = Math::Vector(0.0f, 0.0f, -1.0f);
+ light.direction = Math::Vector(0.0f, 0.0f, 1.0f);
+
+ device->SetGlobalAmbient(Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f));
+ device->SetLight(0, light);
+ device->SetLightEnabled(0, true);
+}
+
+void Render(Gfx::CGLDevice *device, Gfx::CModelFile *modelFile)
+{
+ device->BeginScene();
+
+ Math::Matrix persp;
+ Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp);
+
+ Math::Matrix id;
+ id.LoadIdentity();
+ device->SetTransform(Gfx::TRANSFORM_WORLD, id);
+
+ Math::Matrix viewMat;
+ Math::LoadTranslationMatrix(viewMat, TRANSLATION);
+ Math::Matrix rot;
+ Math::LoadRotationXZYMatrix(rot, ROTATION);
+ viewMat = Math::MultiplyMatrices(viewMat, rot);
+ device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat);
+
+ std::vector<Gfx::ModelTriangle> &triangles = modelFile->GetTriangles();
+
+ Gfx::VertexTex2 tri[3];
+
+ for (int i = 0; i < (int) triangles.size(); ++i)
+ {
+ device->SetTexture(0, GetTexture(triangles[i].tex1Name));
+ device->SetTexture(1, GetTexture(triangles[i].tex2Name));
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, true);
+
+ device->SetMaterial(triangles[i].material);
+
+ tri[0] = triangles[i].p1;
+ tri[1] = triangles[i].p2;
+ tri[2] = triangles[i].p3;
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, tri, 3);
+ }
+
+ device->EndScene();
+}
+
+void Update()
+{
+ const float ROT_SPEED = 80.0f * Math::DEG_TO_RAD; // rad / sec
+ const float TRANS_SPEED = 3.0f; // units / sec
+
+ GetCurrentTimeStamp(CURR_TIME);
+ float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
+ CopyTimeStamp(PREV_TIME, CURR_TIME);
+
+ if (KEYMAP[K_RotYLeft])
+ ROTATION.y -= ROT_SPEED * timeDiff;
+ if (KEYMAP[K_RotYRight])
+ ROTATION.y += ROT_SPEED * timeDiff;
+ if (KEYMAP[K_RotXDown])
+ ROTATION.x -= ROT_SPEED * timeDiff;
+ if (KEYMAP[K_RotXUp])
+ ROTATION.x += ROT_SPEED * timeDiff;
+
+ if (KEYMAP[K_Forward])
+ TRANSLATION.z -= TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Back])
+ TRANSLATION.z += TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Left])
+ TRANSLATION.x += TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Right])
+ TRANSLATION.x -= TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Up])
+ TRANSLATION.y += TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Down])
+ TRANSLATION.y -= TRANS_SPEED * timeDiff;
+}
+
+void KeyboardDown(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_LEFT:
+ KEYMAP[K_RotYLeft] = true;
+ break;
+ case SDLK_RIGHT:
+ KEYMAP[K_RotYRight] = true;
+ break;
+ case SDLK_UP:
+ KEYMAP[K_RotXUp] = true;
+ break;
+ case SDLK_DOWN:
+ KEYMAP[K_RotXDown] = true;
+ break;
+ case SDLK_w:
+ KEYMAP[K_Forward] = true;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = true;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = true;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = true;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = true;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KeyboardUp(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_LEFT:
+ KEYMAP[K_RotYLeft] = false;
+ break;
+ case SDLK_RIGHT:
+ KEYMAP[K_RotYRight] = false;
+ break;
+ case SDLK_UP:
+ KEYMAP[K_RotXUp] = false;
+ break;
+ case SDLK_DOWN:
+ KEYMAP[K_RotXDown] = false;
+ break;
+ case SDLK_w:
+ KEYMAP[K_Forward] = false;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = false;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = false;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = false;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = false;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = false;
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+
+ PREV_TIME = CreateTimeStamp();
+ CURR_TIME = CreateTimeStamp();
+
+ GetCurrentTimeStamp(PREV_TIME);
+ GetCurrentTimeStamp(CURR_TIME);
+
+ if (argc != 3)
+ {
+ std::cerr << "Usage: " << argv[0] << "{mod|dxf} model_file" << std::endl;
+ return 1;
+ }
+
+ CInstanceManager iMan;
+
+ Gfx::CModelFile *modelFile = new Gfx::CModelFile(&iMan);
+ if (std::string(argv[1]) == "mod")
+ {
+ if (! modelFile->ReadModel(argv[2], false, false))
+ {
+ std::cerr << "Error reading MOD: " << modelFile->GetError() << std::endl;
+ return 1;
+ }
+ }
+ else if (std::string(argv[1]) == "dxf")
+ {
+ if (! modelFile->ReadDXF(argv[2], 0.0f, 0.0f))
+ {
+ std::cerr << "Error reading DXF: " << modelFile->GetError() << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Usage: " << argv[0] << "{mod|dxf} model_file" << std::endl;
+ return 1;
+ }
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Model Test", "Model Test");
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device, modelFile);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device, modelFile);
+ Update();
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ SDL_PollEvent(&event);
+ if (event.type == SDL_QUIT)
+ done = true;
+ else if (event.type == SDL_KEYDOWN)
+ KeyboardDown(event.key.keysym.sym);
+ else if (event.type == SDL_KEYUP)
+ KeyboardUp(event.key.keysym.sym);
+
+ usleep(FRAME_DELAY);
+ }
+
+ delete modelFile;
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ DestroyTimeStamp(PREV_TIME);
+ DestroyTimeStamp(CURR_TIME);
+
+ return 0;
+}
diff --git a/src/graphics/opengl/test/tex1.png b/src/graphics/opengl/test/tex1.png
new file mode 100644
index 0000000..46c68a0
--- /dev/null
+++ b/src/graphics/opengl/test/tex1.png
Binary files differ
diff --git a/src/graphics/opengl/test/tex2.png b/src/graphics/opengl/test/tex2.png
new file mode 100644
index 0000000..ebdae0d
--- /dev/null
+++ b/src/graphics/opengl/test/tex2.png
Binary files differ
diff --git a/src/graphics/opengl/test/texture_test.cpp b/src/graphics/opengl/test/texture_test.cpp
new file mode 100644
index 0000000..c3c568b
--- /dev/null
+++ b/src/graphics/opengl/test/texture_test.cpp
@@ -0,0 +1,193 @@
+#include "common/logger.h"
+#include "common/image.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+
+void Init(Gfx::CGLDevice *device)
+{
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
+ device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
+
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, true);
+
+ CImage img1;
+ if (! img1.Load("tex1.png"))
+ {
+ std::string err = img1.GetError();
+ GetLogger()->Error("texture 1 not loaded, error: %d!\n", err.c_str());
+ }
+ CImage img2;
+ if (! img2.Load("tex2.png"))
+ {
+ std::string err = img2.GetError();
+ GetLogger()->Error("texture 2 not loaded, error: %d!\n", err.c_str());
+ }
+
+ Gfx::TextureCreateParams tex1CreateParams;
+ tex1CreateParams.mipmap = true;
+ tex1CreateParams.format = Gfx::TEX_IMG_RGBA;
+ tex1CreateParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
+ tex1CreateParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
+
+ Gfx::TextureCreateParams tex2CreateParams;
+ tex2CreateParams.mipmap = true;
+ tex2CreateParams.format = Gfx::TEX_IMG_RGBA;
+ tex2CreateParams.minFilter = Gfx::TEX_MIN_FILTER_NEAREST_MIPMAP_NEAREST;
+ tex2CreateParams.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
+
+ Gfx::Texture tex1 = device->CreateTexture(&img1, tex1CreateParams);
+ Gfx::Texture tex2 = device->CreateTexture(&img2, tex2CreateParams);
+
+ device->SetTexture(0, tex1);
+ device->SetTexture(1, tex2);
+}
+
+void Render(Gfx::CGLDevice *device)
+{
+ device->BeginScene();
+
+ Math::Matrix ortho;
+ Math::LoadOrthoProjectionMatrix(ortho, -10, 10, -10, 10);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, ortho);
+
+ Math::Matrix id;
+ id.LoadIdentity();
+
+ device->SetTransform(Gfx::TRANSFORM_WORLD, id);
+ device->SetTransform(Gfx::TRANSFORM_VIEW, id);
+
+ static Gfx::VertexTex2 quad[] =
+ {
+ Gfx::VertexTex2(Math::Vector(-2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 0.0f), Math::Point(0.0f, 0.0f)),
+ Gfx::VertexTex2(Math::Vector( 2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 0.0f), Math::Point(1.0f, 0.0f)),
+ Gfx::VertexTex2(Math::Vector( 2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 1.0f), Math::Point(1.0f, 1.0f)),
+
+ Gfx::VertexTex2(Math::Vector( 2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(1.0f, 1.0f), Math::Point(1.0f, 1.0f)),
+ Gfx::VertexTex2(Math::Vector(-2.0f, -2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 1.0f), Math::Point(0.0f, 1.0f)),
+ Gfx::VertexTex2(Math::Vector(-2.0f, 2.0f, 0.0f), Math::Vector(), Math::Point(0.0f, 0.0f), Math::Point(0.0f, 0.0f)),
+ };
+
+ Gfx::TextureStageParams tex1StageParams;
+ tex1StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ tex1StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(0, tex1StageParams);
+
+ Gfx::TextureStageParams tex2StageParams;
+ tex2StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ tex2StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(1, tex2StageParams);
+
+ Math::Matrix t;
+ Math::LoadTranslationMatrix(t, Math::Vector(-4.0f, 4.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_VIEW, t);
+
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, false);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ Math::LoadTranslationMatrix(t, Math::Vector( 4.0f, 4.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_VIEW, t);
+
+ device->SetTextureEnabled(0, false);
+ device->SetTextureEnabled(1, true);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ Math::LoadTranslationMatrix(t, Math::Vector( 0.0f, -4.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_VIEW, t);
+
+ device->SetTextureEnabled(0, true);
+ device->SetTextureEnabled(1, true);
+
+ tex1StageParams.colorOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ tex1StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(0, tex1StageParams);
+
+ tex2StageParams.colorOperation = Gfx::TEX_MIX_OPER_ADD;
+ tex2StageParams.colorArg1 = Gfx::TEX_MIX_ARG_COMPUTED_COLOR;
+ tex2StageParams.colorArg2 = Gfx::TEX_MIX_ARG_TEXTURE;
+ tex2StageParams.alphaOperation = Gfx::TEX_MIX_OPER_DEFAULT;
+ device->SetTextureStageParams(1, tex2StageParams);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ device->EndScene();
+}
+
+int main()
+{
+ CLogger();
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Texture Test", "Texture Test");
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device);
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ SDL_PollEvent(&event);
+ if (event.type == SDL_QUIT)
+ done = true;
+
+ usleep(10000);
+ }
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ return 0;
+}
diff --git a/src/graphics/opengl/test/transform_test.cpp b/src/graphics/opengl/test/transform_test.cpp
new file mode 100644
index 0000000..83819b8
--- /dev/null
+++ b/src/graphics/opengl/test/transform_test.cpp
@@ -0,0 +1,339 @@
+#include "app/system.h"
+#include "common/logger.h"
+#include "common/image.h"
+#include "common/iman.h"
+#include "graphics/opengl/gldevice.h"
+#include "math/geometry.h"
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <map>
+
+enum KeySlots
+{
+ K_Forward,
+ K_Back,
+ K_Left,
+ K_Right,
+ K_Up,
+ K_Down,
+ K_Count
+};
+bool KEYMAP[K_Count] = { false };
+
+Math::Point MOUSE_POS_BASE;
+
+Math::Vector TRANSLATION(0.0f, 2.0f, 0.0f);
+Math::Vector ROTATION, ROTATION_BASE;
+
+const int FRAME_DELAY = 5000;
+
+SystemTimeStamp *PREV_TIME = NULL, *CURR_TIME = NULL;
+
+void Init(Gfx::CGLDevice *device)
+{
+ device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, true);
+ device->SetShadeModel(Gfx::SHADE_SMOOTH);
+}
+
+void Render(Gfx::CGLDevice *device)
+{
+ device->BeginScene();
+
+ Math::Matrix persp;
+ Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f);
+ device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp);
+
+
+ Math::Matrix viewMat;
+ Math::Matrix mat;
+
+ viewMat.LoadIdentity();
+
+ Math::LoadRotationXMatrix(mat, -ROTATION.x);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadRotationYMatrix(mat, -ROTATION.y);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ Math::LoadTranslationMatrix(mat, -TRANSLATION);
+ viewMat = Math::MultiplyMatrices(viewMat, mat);
+
+ device->SetTransform(Gfx::TRANSFORM_VIEW, viewMat);
+
+
+ Math::Matrix worldMat;
+ worldMat.LoadIdentity();
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ Gfx::VertexCol line[2] = { Gfx::VertexCol() };
+
+ for (int x = -40; x <= 40; ++x)
+ {
+ line[0].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[0].coord.z = -40;
+ line[0].coord.x = x;
+ line[1].color = Gfx::Color(0.7f + x / 120.0f, 0.0f, 0.0f);
+ line[1].coord.z = 40;
+ line[1].coord.x = x;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+ for (int z = -40; z <= 40; ++z)
+ {
+ line[0].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[0].coord.z = z;
+ line[0].coord.x = -40;
+ line[1].color = Gfx::Color(0.0f, 0.7f + z / 120.0f, 0.0f);
+ line[1].coord.z = z;
+ line[1].coord.x = 40;
+ device->DrawPrimitive(Gfx::PRIMITIVE_LINES, line, 2);
+ }
+
+
+ Gfx::VertexCol quad[6] = { Gfx::VertexCol() };
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 1.0f, 0.0f);
+
+ quad[0].coord = Math::Vector(-1.0f, -1.0f, 0.0f);
+ quad[1].coord = Math::Vector( 1.0f, -1.0f, 0.0f);
+ quad[2].coord = Math::Vector( 1.0f, 1.0f, 0.0f);
+ quad[3].coord = Math::Vector( 1.0f, 1.0f, 0.0f);
+ quad[4].coord = Math::Vector(-1.0f, 1.0f, 0.0f);
+ quad[5].coord = Math::Vector(-1.0f, -1.0f, 0.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(40.0f, 2.0f, 40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(0.0f, 1.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ for (int i = 0; i < 6; ++i)
+ quad[i].color = Gfx::Color(1.0f, 0.0f, 1.0f);
+
+ Math::LoadTranslationMatrix(worldMat, Math::Vector(0.0f, 10.0f, 0.0f));
+ device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat);
+
+ device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLES, quad, 6);
+
+ device->EndScene();
+}
+
+void Update()
+{
+ const float TRANS_SPEED = 6.0f; // units / sec
+
+ GetCurrentTimeStamp(CURR_TIME);
+ float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
+ CopyTimeStamp(PREV_TIME, CURR_TIME);
+
+ Math::Vector incTrans;
+
+ if (KEYMAP[K_Forward])
+ incTrans.z = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Back])
+ incTrans.z = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Right])
+ incTrans.x = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Left])
+ incTrans.x = -TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Up])
+ incTrans.y = +TRANS_SPEED * timeDiff;
+ if (KEYMAP[K_Down])
+ incTrans.y = -TRANS_SPEED * timeDiff;
+
+ Math::Point rotTrans = Math::RotatePoint(-ROTATION.y, Math::Point(incTrans.x, incTrans.z));
+ incTrans.x = rotTrans.x;
+ incTrans.z = rotTrans.y;
+ TRANSLATION += incTrans;
+}
+
+void KeyboardDown(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = true;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = true;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = true;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = true;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = true;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KeyboardUp(SDLKey key)
+{
+ switch (key)
+ {
+ case SDLK_w:
+ KEYMAP[K_Forward] = false;
+ break;
+ case SDLK_s:
+ KEYMAP[K_Back] = false;
+ break;
+ case SDLK_d:
+ KEYMAP[K_Right] = false;
+ break;
+ case SDLK_a:
+ KEYMAP[K_Left] = false;
+ break;
+ case SDLK_z:
+ KEYMAP[K_Down] = false;
+ break;
+ case SDLK_x:
+ KEYMAP[K_Up] = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void MouseMove(int x, int y)
+{
+ Math::Point currentPos((float)x, (float)y);
+
+ static bool first = true;
+ if (first || (x < 10) || (y < 10) || (x > 790) || (y > 590))
+ {
+ SDL_WarpMouse(400, 300);
+ MOUSE_POS_BASE.x = 400;
+ MOUSE_POS_BASE.y = 300;
+ ROTATION_BASE = ROTATION;
+ first = false;
+ return;
+ }
+
+ ROTATION.y = ROTATION_BASE.y + ((float) (x - MOUSE_POS_BASE.x) / 800.0f) * Math::PI;
+ ROTATION.x = ROTATION_BASE.x + ((float) (y - MOUSE_POS_BASE.y) / 600.0f) * Math::PI;
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+
+ PREV_TIME = CreateTimeStamp();
+ CURR_TIME = CreateTimeStamp();
+
+ GetCurrentTimeStamp(PREV_TIME);
+ GetCurrentTimeStamp(CURR_TIME);
+
+ CInstanceManager iMan;
+
+ // Without any error checking, for simplicity
+
+ SDL_Init(SDL_INIT_VIDEO);
+
+ IMG_Init(IMG_INIT_PNG);
+
+ const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
+
+ Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
+
+ if (videoInfo->hw_available)
+ videoFlags |= SDL_HWSURFACE;
+ else
+ videoFlags |= SDL_SWSURFACE;
+
+ if (videoInfo->blit_hw)
+ videoFlags |= SDL_HWACCEL;
+
+
+ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
+
+ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+
+ SDL_Surface *surface = SDL_SetVideoMode(800, 600, 32, videoFlags);
+
+
+ SDL_WM_SetCaption("Transform Test", "Transform Test");
+
+ //SDL_WM_GrabInput(SDL_GRAB_ON);
+ SDL_ShowCursor(SDL_DISABLE);
+
+ Gfx::CGLDevice *device = new Gfx::CGLDevice();
+ device->Create();
+
+ Init(device);
+
+ bool done = false;
+ while (! done)
+ {
+ Render(device);
+ Update();
+
+ SDL_GL_SwapBuffers();
+
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ if (event.type == SDL_QUIT)
+ {
+ break;
+ done = true;
+ }
+ else if (event.type == SDL_KEYDOWN)
+ {
+ if (event.key.keysym.sym == SDLK_q)
+ {
+ done = true;
+ break;
+ }
+ else
+ KeyboardDown(event.key.keysym.sym);
+ }
+ else if (event.type == SDL_KEYUP)
+ KeyboardUp(event.key.keysym.sym);
+ else if (event.type == SDL_MOUSEMOTION)
+ MouseMove(event.motion.x, event.motion.y);
+ }
+
+ usleep(FRAME_DELAY);
+ }
+
+ //SDL_WM_GrabInput(SDL_GRAB_OFF);
+ SDL_ShowCursor(SDL_ENABLE);
+
+ device->Destroy();
+ delete device;
+
+ SDL_FreeSurface(surface);
+
+ IMG_Quit();
+
+ SDL_Quit();
+
+ DestroyTimeStamp(PREV_TIME);
+ DestroyTimeStamp(CURR_TIME);
+
+ return 0;
+}
diff --git a/src/math/func.h b/src/math/func.h
index 8f0e4ab..2127d1a 100644
--- a/src/math/func.h
+++ b/src/math/func.h
@@ -34,15 +34,15 @@ namespace Math
/* @{ */ // start of group
//! Compares \a a and \a b within \a tolerance
-inline bool IsEqual(float a, float b, float tolerance = TOLERANCE)
+inline bool IsEqual(float a, float b, float tolerance = Math::TOLERANCE)
{
return fabs(a - b) < tolerance;
}
//! Compares \a a to zero within \a tolerance
-inline bool IsZero(float a, float tolerance = TOLERANCE)
+inline bool IsZero(float a, float tolerance = Math::TOLERANCE)
{
- return IsEqual(a, 0.0f, tolerance);
+ return Math::IsEqual(a, 0.0f, tolerance);
}
//! Minimum
@@ -59,12 +59,12 @@ inline float Min(float a, float b, float c)
inline float Min(float a, float b, float c, float d)
{
- return Min( Min(a, b), Min(c, d) );
+ return Math::Min( Math::Min(a, b), Math::Min(c, d) );
}
inline float Min(float a, float b, float c, float d, float e)
{
- return Min( Min(a, b), Min(c, d), e );
+ return Math::Min( Math::Min(a, b), Math::Min(c, d), e );
}
//! Maximum
@@ -76,17 +76,17 @@ inline float Max(float a, float b)
inline float Max(float a, float b, float c)
{
- return Max( Max(a, b), c );
+ return Math::Max( Math::Max(a, b), c );
}
inline float Max(float a, float b, float c, float d)
{
- return Max( Max(a, b), Max(c, d) );
+ return Math::Max( Math::Max(a, b), Math::Max(c, d) );
}
inline float Max(float a, float b, float c, float d, float e)
{
- return Max( Max(a, b), Max(c, d), e );
+ return Math::Max( Math::Max(a, b), Math::Max(c, d), e );
}
//! Returns the normalized value (0 .. 1)
@@ -118,19 +118,19 @@ inline void Swap(float &a, float &b)
Mod(n, 1) = fractional part of n */
inline float Mod(float a, float m)
{
- return a - ((int)(a/m))*m;
+ return a - ( static_cast<int>(a / m) ) * m;
}
//! Returns a random value between 0 and 1.
inline float Rand()
{
- return (float)rand()/RAND_MAX;
+ return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
}
//! Returns a normalized angle, that is in other words between 0 and 2 * PI
inline float NormAngle(float angle)
{
- angle = Mod(angle, PI*2.0f);
+ angle = Math::Mod(angle, PI*2.0f);
if ( angle < 0.0f )
return PI*2.0f + angle;
@@ -140,9 +140,9 @@ inline float NormAngle(float angle)
//! Test if a angle is between two terminals
inline bool TestAngle(float angle, float min, float max)
{
- angle = NormAngle(angle);
- min = NormAngle(min);
- max = NormAngle(max);
+ angle = Math::NormAngle(angle);
+ min = Math::NormAngle(min);
+ max = Math::NormAngle(max);
if ( min > max )
return ( angle <= max || angle >= min );
@@ -153,18 +153,18 @@ inline bool TestAngle(float angle, float min, float max)
//! Calculates a value (radians) proportional between a and b (degrees)
inline float PropAngle(int a, int b, float p)
{
- float aa = (float)a * DEG_TO_RAD;
- float bb = (float)b * DEG_TO_RAD;
+ float aa = static_cast<float>(a) * DEG_TO_RAD;
+ float bb = static_cast<float>(b) * DEG_TO_RAD;
- return aa+p*(bb-aa);
+ return aa + p * (bb - aa);
}
//! Calculates the angle to rotate the angle \a a to the angle \a g
/** A positive angle is counterclockwise (CCW). */
inline float Direction(float a, float g)
{
- a = NormAngle(a);
- g = NormAngle(g);
+ a = Math::NormAngle(a);
+ g = Math::NormAngle(g);
if ( a < g )
{
diff --git a/src/math/geometry.h b/src/math/geometry.h
index 2f937e5..61d1868 100644
--- a/src/math/geometry.h
+++ b/src/math/geometry.h
@@ -40,7 +40,7 @@ namespace Math
//! Returns py up on the line \a a - \a b
-inline float MidPoint(const Point &a, const Point &b, float px)
+inline float MidPoint(const Math::Point &a, const Math::Point &b, float px)
{
if (IsEqual(a.x, b.x))
{
@@ -53,7 +53,7 @@ inline float MidPoint(const Point &a, const Point &b, float px)
}
//! Tests whether the point \a p is inside the triangle (\a a,\a b,\a c)
-inline bool IsInsideTriangle(Point a, Point b, Point c, Point p)
+inline bool IsInsideTriangle(Math::Point a, Math::Point b, Math::Point c, Math::Point p)
{
float n, m;
@@ -82,13 +82,13 @@ inline bool IsInsideTriangle(Point a, Point b, Point c, Point p)
/** \a center center of rotation
\a angle angle is in radians (positive is counterclockwise (CCW) )
\a p the point */
-inline Point RotatePoint(const Point &center, float angle, const Point &p)
+inline Math::Point RotatePoint(const Math::Point &center, float angle, const Math::Point &p)
{
- Point a;
+ Math::Point a;
a.x = p.x-center.x;
a.y = p.y-center.y;
- Point b;
+ Math::Point b;
b.x = a.x*cosf(angle) - a.y*sinf(angle);
b.y = a.x*sinf(angle) + a.y*cosf(angle);
@@ -101,23 +101,23 @@ inline Point RotatePoint(const Point &center, float angle, const Point &p)
//! Rotates a point around the origin (0,0)
/** \a angle angle in radians (positive is counterclockwise (CCW) )
\a p the point */
-inline Point RotatePoint(float angle, const Point &p)
+inline Math::Point RotatePoint(float angle, const Math::Point &p)
{
float x = p.x*cosf(angle) - p.y*sinf(angle);
float y = p.x*sinf(angle) + p.y*cosf(angle);
- return Point(x, y);
+ return Math::Point(x, y);
}
//! Rotates a vector (dist, 0).
/** \a angle angle is in radians (positive is counterclockwise (CCW) )
\a dist distance to origin */
-inline Point RotatePoint(float angle, float dist)
+inline Math::Point RotatePoint(float angle, float dist)
{
float x = dist*cosf(angle);
float y = dist*sinf(angle);
- return Point(x, y);
+ return Math::Point(x, y);
}
//! TODO documentation
@@ -140,13 +140,13 @@ inline void RotatePoint(float cx, float cy, float angle, float &px, float &py)
\a angleH,angleV rotation angles in radians (positive is counterclockwise (CCW) ) )
\a p the point
\returns the rotated point */
-inline void RotatePoint(const Vector &center, float angleH, float angleV, Vector &p)
+inline void RotatePoint(const Math::Vector &center, float angleH, float angleV, Math::Vector &p)
{
p.x -= center.x;
p.y -= center.y;
p.z -= center.z;
- Vector b;
+ Math::Vector b;
b.x = p.x*cosf(angleH) - p.z*sinf(angleH);
b.y = p.z*sinf(angleV) + p.y*cosf(angleV);
b.z = p.x*sinf(angleH) + p.z*cosf(angleH);
@@ -159,18 +159,18 @@ inline void RotatePoint(const Vector &center, float angleH, float angleV, Vector
\a angleH,angleV rotation angles in radians (positive is counterclockwise (CCW) ) )
\a p the point
\returns the rotated point */
-inline void RotatePoint2(const Vector center, float angleH, float angleV, Vector &p)
+inline void RotatePoint2(const Math::Vector center, float angleH, float angleV, Math::Vector &p)
{
p.x -= center.x;
p.y -= center.y;
p.z -= center.z;
- Vector a;
+ Math::Vector a;
a.x = p.x*cosf(angleH) - p.z*sinf(angleH);
a.y = p.y;
a.z = p.x*sinf(angleH) + p.z*cosf(angleH);
- Vector b;
+ Math::Vector b;
b.x = a.x;
b.y = a.z*sinf(angleV) + a.y*cosf(angleV);
b.z = a.z*cosf(angleV) - a.y*sinf(angleV);
@@ -196,7 +196,7 @@ inline float RotateAngle(float x, float y)
/** \a center the center point
\a p1,p2 the two points
\returns The angle in radians (positive is counterclockwise (CCW) ) */
-inline float RotateAngle(const Point &center, const Point &p1, const Point &p2)
+inline float RotateAngle(const Math::Point &center, const Math::Point &p1, const Math::Point &p2)
{
if (PointsEqual(p1, center))
return 0;
@@ -221,11 +221,12 @@ inline float RotateAngle(const Point &center, const Point &p1, const Point &p2)
/** \a from origin
\a at view direction
\a worldUp up vector */
-inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, const Vector &worldUp)
+inline void LoadViewMatrix(Math::Matrix &mat, const Math::Vector &from,
+ const Math::Vector &at, const Math::Vector &worldUp)
{
// Get the z basis vector, which points straight ahead. This is the
// difference from the eyepoint to the lookat point.
- Vector view = at - from;
+ Math::Vector view = at - from;
float length = view.Length();
assert(! IsZero(length) );
@@ -237,18 +238,18 @@ inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, co
// vector onto the up vector. The projection is the y basis vector.
float dotProduct = DotProduct(worldUp, view);
- Vector up = worldUp - dotProduct * view;
+ Math::Vector up = worldUp - dotProduct * view;
// If this vector has near-zero length because the input specified a
// bogus up vector, let's try a default up vector
if ( IsZero(length = up.Length()) )
{
- up = Vector(0.0f, 1.0f, 0.0f) - view.y * view;
+ up = Math::Vector(0.0f, 1.0f, 0.0f) - view.y * view;
// If we still have near-zero length, resort to a different axis.
if ( IsZero(length = up.Length()) )
{
- up = Vector(0.0f, 0.0f, 1.0f) - view.z * view;
+ up = Math::Vector(0.0f, 0.0f, 1.0f) - view.z * view;
assert(! IsZero(up.Length()) );
}
@@ -259,7 +260,7 @@ inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, co
// The x basis vector is found simply with the cross product of the y
// and z basis vectors
- Vector right = CrossProduct(up, view);
+ Math::Vector right = CrossProduct(up, view);
// Start building the matrix. The first three rows contains the basis
// vectors used to rotate the view to point at the lookat point
@@ -286,28 +287,44 @@ inline void LoadViewMatrix(Matrix &mat, const Vector &from, const Vector &at, co
\a aspect aspect ratio (width / height)
\a nearPlane distance to near cut plane
\a farPlane distance to far cut plane */
-inline void LoadProjectionMatrix(Matrix &mat, float fov = 1.570795f, float aspect = 1.0f,
+inline void LoadProjectionMatrix(Math::Matrix &mat, float fov = Math::PI / 2.0f, float aspect = 1.0f,
float nearPlane = 1.0f, float farPlane = 1000.0f)
{
assert(fabs(farPlane - nearPlane) >= 0.01f);
assert(fabs(sin(fov / 2)) >= 0.01f);
- float w = aspect * (cosf(fov / 2) / sinf(fov / 2));
- float h = 1.0f * (cosf(fov / 2) / sinf(fov / 2));
- float q = farPlane / (farPlane - nearPlane);
+ float f = cosf(fov / 2.0f) / sinf(fov / 2.0f);
mat.LoadZero();
- /* (1,1) */ mat.m[0 ] = w;
- /* (2,2) */ mat.m[5 ] = h;
- /* (3,3) */ mat.m[10] = q;
- /* (4,3) */ mat.m[11] = 1.0f;
- /* (3,4) */ mat.m[14] = -q * nearPlane;
+ /* (1,1) */ mat.m[0 ] = f / aspect;
+ /* (2,2) */ mat.m[5 ] = f;
+ /* (3,3) */ mat.m[10] = (nearPlane + farPlane) / (nearPlane - farPlane);
+ /* (4,3) */ mat.m[11] = -1.0f;
+ /* (3,4) */ mat.m[14] = (2.0f * farPlane * nearPlane) / (nearPlane - farPlane);
+}
+
+//! Loads an othogonal projection matrix
+/** \a left,right coordinates for left and right vertical clipping planes
+ \a bottom,top coordinates for bottom and top horizontal clipping planes
+ \a zNear,zFar distance to nearer and farther depth clipping planes */
+inline void LoadOrthoProjectionMatrix(Math::Matrix &mat, float left, float right, float bottom, float top,
+ float zNear = -1.0f, float zFar = 1.0f)
+{
+ mat.LoadIdentity();
+
+ /* (1,1) */ mat.m[0 ] = 2.0f / (right - left);
+ /* (2,2) */ mat.m[5 ] = 2.0f / (top - bottom);
+ /* (3,3) */ mat.m[10] = -2.0f / (zFar - zNear);
+
+ /* (1,4) */ mat.m[12] = - (right + left) / (right - left);
+ /* (2,4) */ mat.m[13] = - (top + bottom) / (top - bottom);
+ /* (3,4) */ mat.m[14] = - (zFar + zNear) / (zFar - zNear);
}
//! Loads a translation matrix from given vector
/** \a trans vector of translation*/
-inline void LoadTranslationMatrix(Matrix &mat, const Vector &trans)
+inline void LoadTranslationMatrix(Math::Matrix &mat, const Math::Vector &trans)
{
mat.LoadIdentity();
/* (1,4) */ mat.m[12] = trans.x;
@@ -317,7 +334,7 @@ inline void LoadTranslationMatrix(Matrix &mat, const Vector &trans)
//! Loads a scaling matrix fom given vector
/** \a scale vector with scaling factors for X, Y, Z */
-inline void LoadScaleMatrix(Matrix &mat, const Vector &scale)
+inline void LoadScaleMatrix(Math::Matrix &mat, const Math::Vector &scale)
{
mat.LoadIdentity();
/* (1,1) */ mat.m[0 ] = scale.x;
@@ -327,7 +344,7 @@ inline void LoadScaleMatrix(Matrix &mat, const Vector &scale)
//! Loads a rotation matrix along the X axis
/** \a angle angle in radians */
-inline void LoadRotationXMatrix(Matrix &mat, float angle)
+inline void LoadRotationXMatrix(Math::Matrix &mat, float angle)
{
mat.LoadIdentity();
/* (2,2) */ mat.m[5 ] = cosf(angle);
@@ -338,7 +355,7 @@ inline void LoadRotationXMatrix(Matrix &mat, float angle)
//! Loads a rotation matrix along the Y axis
/** \a angle angle in radians */
-inline void LoadRotationYMatrix(Matrix &mat, float angle)
+inline void LoadRotationYMatrix(Math::Matrix &mat, float angle)
{
mat.LoadIdentity();
/* (1,1) */ mat.m[0 ] = cosf(angle);
@@ -349,7 +366,7 @@ inline void LoadRotationYMatrix(Matrix &mat, float angle)
//! Loads a rotation matrix along the Z axis
/** \a angle angle in radians */
-inline void LoadRotationZMatrix(Matrix &mat, float angle)
+inline void LoadRotationZMatrix(Math::Matrix &mat, float angle)
{
mat.LoadIdentity();
/* (1,1) */ mat.m[0 ] = cosf(angle);
@@ -361,11 +378,11 @@ inline void LoadRotationZMatrix(Matrix &mat, float angle)
//! Loads a rotation matrix along the given axis
/** \a dir axis of rotation
\a angle angle in radians */
-inline void LoadRotationMatrix(Matrix &mat, const Vector &dir, float angle)
+inline void LoadRotationMatrix(Math::Matrix &mat, const Math::Vector &dir, float angle)
{
float cos = cosf(angle);
float sin = sinf(angle);
- Vector v = Normalize(dir);
+ Math::Vector v = Normalize(dir);
mat.LoadIdentity();
@@ -383,9 +400,9 @@ inline void LoadRotationMatrix(Matrix &mat, const Vector &dir, float angle)
}
//! Calculates the matrix to make three rotations in the order X, Z and Y
-inline void LoadRotationXZYMatrix(Matrix &mat, const Vector &angle)
+inline void LoadRotationXZYMatrix(Math::Matrix &mat, const Math::Vector &angle)
{
- Matrix temp;
+ Math::Matrix temp;
LoadRotationXMatrix(temp, angle.x);
LoadRotationZMatrix(mat, angle.z);
@@ -396,9 +413,9 @@ inline void LoadRotationXZYMatrix(Matrix &mat, const Vector &angle)
}
//! Calculates the matrix to make three rotations in the order Z, X and Y
-inline void LoadRotationZXYMatrix(Matrix &mat, const Vector &angle)
+inline void LoadRotationZXYMatrix(Math::Matrix &mat, const Math::Vector &angle)
{
- Matrix temp;
+ Math::Matrix temp;
LoadRotationZMatrix(temp, angle.z);
LoadRotationXMatrix(mat, angle.x);
@@ -409,7 +426,7 @@ inline void LoadRotationZXYMatrix(Matrix &mat, const Vector &angle)
}
//! Returns the distance between projections on XZ plane of two vectors
-inline float DistanceProjected(const Vector &a, const Vector &b)
+inline float DistanceProjected(const Math::Vector &a, const Math::Vector &b)
{
return sqrtf( (a.x-b.x)*(a.x-b.x) +
(a.z-b.z)*(a.z-b.z) );
@@ -417,10 +434,10 @@ inline float DistanceProjected(const Vector &a, const Vector &b)
//! Returns the normal vector to a plane
/** \param p1,p2,p3 points defining the plane */
-inline Vector NormalToPlane(const Vector &p1, const Vector &p2, const Vector &p3)
+inline Math::Vector NormalToPlane(const Math::Vector &p1, const Math::Vector &p2, const Math::Vector &p3)
{
- Vector u = p3 - p1;
- Vector v = p2 - p1;
+ Math::Vector u = p3 - p1;
+ Math::Vector v = p2 - p1;
return Normalize(CrossProduct(u, v));
}
@@ -428,7 +445,7 @@ inline Vector NormalToPlane(const Vector &p1, const Vector &p2, const Vector &p3
//! Returns a point on the line \a p1 - \a p2, in \a dist distance from \a p1
/** \a p1,p2 line start and end
\a dist scaling factor from \a p1, relative to distance between \a p1 and \a p2 */
-inline Vector SegmentPoint(const Vector &p1, const Vector &p2, float dist)
+inline Math::Vector SegmentPoint(const Math::Vector &p1, const Math::Vector &p2, float dist)
{
return p1 + (p2 - p1) * dist;
}
@@ -436,9 +453,10 @@ inline Vector SegmentPoint(const Vector &p1, const Vector &p2, float dist)
//! Returns the distance between given point and a plane
/** \param p the point
\param a,b,c points defining the plane */
-inline float DistanceToPlane(const Vector &a, const Vector &b, const Vector &c, const Vector &p)
+inline float DistanceToPlane(const Math::Vector &a, const Math::Vector &b,
+ const Math::Vector &c, const Math::Vector &p)
{
- Vector n = NormalToPlane(a, b, c);
+ Math::Vector n = NormalToPlane(a, b, c);
float d = -(n.x*a.x + n.y*a.y + n.z*a.z);
return fabs(n.x*p.x + n.y*p.y + n.z*p.z + d);
@@ -447,10 +465,10 @@ inline float DistanceToPlane(const Vector &a, const Vector &b, const Vector &c,
//! Checks if two planes defined by three points are the same
/** \a plane1 array of three vectors defining the first plane
\a plane2 array of three vectors defining the second plane */
-inline bool IsSamePlane(const Vector (&plane1)[3], const Vector (&plane2)[3])
+inline bool IsSamePlane(const Math::Vector (&plane1)[3], const Math::Vector (&plane2)[3])
{
- Vector n1 = NormalToPlane(plane1[0], plane1[1], plane1[2]);
- Vector n2 = NormalToPlane(plane2[0], plane2[1], plane2[2]);
+ Math::Vector n1 = NormalToPlane(plane1[0], plane1[1], plane1[2]);
+ Math::Vector n2 = NormalToPlane(plane2[0], plane2[1], plane2[2]);
if ( fabs(n1.x-n2.x) > 0.1f ||
fabs(n1.y-n2.y) > 0.1f ||
@@ -465,7 +483,8 @@ inline bool IsSamePlane(const Vector (&plane1)[3], const Vector (&plane2)[3])
}
//! Calculates the intersection "i" right "of" the plane "abc".
-inline bool Intersect(const Vector &a, const Vector &b, const Vector &c, const Vector &d, const Vector &e, Vector &i)
+inline bool Intersect(const Math::Vector &a, const Math::Vector &b, const Math::Vector &c,
+ const Math::Vector &d, const Math::Vector &e, Math::Vector &i)
{
float d1 = (d.x-a.x)*((b.y-a.y)*(c.z-a.z)-(c.y-a.y)*(b.z-a.z)) -
(d.y-a.y)*((b.x-a.x)*(c.z-a.z)-(c.x-a.x)*(b.z-a.z)) +
@@ -487,7 +506,7 @@ inline bool Intersect(const Vector &a, const Vector &b, const Vector &c, const V
//! Calculates the intersection of the straight line passing through p (x, z)
/** Line is parallel to the y axis, with the plane abc. Returns p.y. */
-inline bool IntersectY(const Vector &a, const Vector &b, const Vector &c, Vector &p)
+inline bool IntersectY(const Math::Vector &a, const Math::Vector &b, const Math::Vector &c, Math::Vector &p)
{
float d = (b.x-a.x)*(c.z-a.z) - (c.x-a.x)*(b.z-a.z);
float d1 = (p.x-a.x)*(c.z-a.z) - (c.x-a.x)*(p.z-a.z);
@@ -502,9 +521,9 @@ inline bool IntersectY(const Vector &a, const Vector &b, const Vector &c, Vector
}
//! Calculates the end point
-inline Vector LookatPoint(const Vector &eye, float angleH, float angleV, float length)
+inline Math::Vector LookatPoint(const Math::Vector &eye, float angleH, float angleV, float length)
{
- Vector lookat = eye;
+ Math::Vector lookat = eye;
lookat.z += length;
RotatePoint(eye, angleH, angleV, lookat);
@@ -513,7 +532,7 @@ inline Vector LookatPoint(const Vector &eye, float angleH, float angleV, float l
}
//! TODO documentation
-inline Vector Transform(const Matrix &m, const Vector &p)
+inline Math::Vector Transform(const Math::Matrix &m, const Math::Vector &p)
{
return MatrixVectorMultiply(m, p);
}
@@ -521,7 +540,7 @@ inline Vector Transform(const Matrix &m, const Vector &p)
//! Calculates the projection of the point \a p on a straight line \a a to \a b.
/** \a p point to project
\a a,b two ends of the line */
-inline Vector Projection(const Vector &a, const Vector &b, const Vector &p)
+inline Math::Vector Projection(const Math::Vector &a, const Math::Vector &b, const Math::Vector &p)
{
float k = DotProduct(b - a, p - a);
k /= DotProduct(b - a, b - a);
@@ -530,15 +549,15 @@ inline Vector Projection(const Vector &a, const Vector &b, const Vector &p)
}
//! Calculates point of view to look at a center two angles and a distance
-inline Vector RotateView(Vector center, float angleH, float angleV, float dist)
+inline Math::Vector RotateView(Math::Vector center, float angleH, float angleV, float dist)
{
- Matrix mat1, mat2;
+ Math::Matrix mat1, mat2;
LoadRotationZMatrix(mat1, -angleV);
LoadRotationYMatrix(mat2, -angleH);
- Matrix mat = MultiplyMatrices(mat2, mat1);
+ Math::Matrix mat = MultiplyMatrices(mat2, mat1);
- Vector eye;
+ Math::Vector eye;
eye.x = 0.0f+dist;
eye.y = 0.0f;
eye.z = 0.0f;
diff --git a/src/math/intsize.h b/src/math/intsize.h
new file mode 100644
index 0000000..f4b2431
--- /dev/null
+++ b/src/math/intsize.h
@@ -0,0 +1,61 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+/** @defgroup MathIntSizeModule math/intsize.h
+ Contains the IntSize struct.
+ */
+
+#pragma once
+
+// Math module namespace
+namespace Math
+{
+
+/* @{ */ // start of group
+
+/** \struct IntSize math/size.h
+ \brief 2D size with integer dimensions */
+struct IntSize
+{
+ //! Width
+ int w;
+ //! Height
+ int h;
+
+ //! Constructs a zero size: (0,0)
+ inline IntSize()
+ {
+ LoadZero();
+ }
+
+ //! Constructs a size from given dimensions: (w,h)
+ inline explicit IntSize(int w, int h)
+ {
+ this->w = w;
+ this->h = h;
+ }
+
+ //! Sets the zero size: (0,0)
+ inline void LoadZero()
+ {
+ w = h = 0;
+ }
+}; // struct Size
+
+
+/* @} */ // end of group
+
+}; // namespace Math
diff --git a/src/math/matrix.h b/src/math/matrix.h
index 9b29f46..45a7d75 100644
--- a/src/math/matrix.h
+++ b/src/math/matrix.h
@@ -118,6 +118,12 @@ struct Matrix
/* (4,4) */ m[15] = 1.0f;
}
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return reinterpret_cast<float*>(this);
+ }
+
//! Transposes the matrix
inline void Transpose()
{
@@ -382,9 +388,9 @@ inline bool MatricesEqual(const Matrix &m1, const Matrix &m2,
}
//! Convenience function for getting transposed matrix
-inline Matrix Transpose(const Matrix &m)
+inline Math::Matrix Transpose(const Math::Matrix &m)
{
- Matrix result = m;
+ Math::Matrix result = m;
result.Transpose();
return result;
}
@@ -393,7 +399,7 @@ inline Matrix Transpose(const Matrix &m)
/** \a left left-hand matrix
\a right right-hand matrix
\returns multiplied matrices */
-inline Matrix MultiplyMatrices(const Matrix &left, const Matrix &right)
+inline Math::Matrix MultiplyMatrices(const Math::Matrix &left, const Math::Matrix &right)
{
return left.Multiply(right);
}
@@ -407,25 +413,25 @@ inline Matrix MultiplyMatrices(const Matrix &left, const Matrix &right)
The result, a 4x1 vector is then converted to 3x1 by dividing
x,y,z coords by the fourth coord (w). */
-inline Vector MatrixVectorMultiply(const Matrix &m, const Vector &v, bool wDivide = false)
+inline Math::Vector MatrixVectorMultiply(const Math::Matrix &m, const Math::Vector &v, bool wDivide = false)
{
float x = v.x * m.m[0 ] + v.y * m.m[4 ] + v.z * m.m[8 ] + m.m[12];
float y = v.x * m.m[1 ] + v.y * m.m[5 ] + v.z * m.m[9 ] + m.m[13];
float z = v.x * m.m[2 ] + v.y * m.m[6 ] + v.z * m.m[10] + m.m[14];
if (!wDivide)
- return Vector(x, y, z);
+ return Math::Vector(x, y, z);
float w = v.x * m.m[3 ] + v.y * m.m[7 ] + v.z * m.m[11] + m.m[15];
if (IsZero(w))
- return Vector(x, y, z);
+ return Math::Vector(x, y, z);
x /= w;
y /= w;
z /= w;
- return Vector(x, y, z);
+ return Math::Vector(x, y, z);
}
/* @} */ // end of group
diff --git a/src/math/point.h b/src/math/point.h
index 84be190..ea20db9 100644
--- a/src/math/point.h
+++ b/src/math/point.h
@@ -24,6 +24,7 @@
#include "func.h"
#include <cmath>
+#include <sstream>
// Math module namespace
@@ -67,6 +68,18 @@ struct Point
x = y = 0.0f;
}
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return reinterpret_cast<float*>(this);
+ }
+
+ //! Returns the struct cast to <tt>const float*</tt> array; use with care!
+ inline const float* Array() const
+ {
+ return reinterpret_cast<const float*>(this);
+ }
+
//! Returns the distance from (0,0) to the point (x,y)
inline float Length()
{
@@ -141,6 +154,15 @@ struct Point
return Point(left.x / right, left.y / right);
}
+
+ //! Returns a string "[x, y]"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "[" << x << ", " << y << "]";
+ return s.str();
+ }
}; // struct Point
diff --git a/src/math/size.h b/src/math/size.h
new file mode 100644
index 0000000..781b9a4
--- /dev/null
+++ b/src/math/size.h
@@ -0,0 +1,66 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+/** @defgroup MathSizeModule math/size.h
+ Contains the Size struct.
+ */
+
+#pragma once
+
+// Math module namespace
+namespace Math
+{
+
+/* @{ */ // start of group
+
+/** \struct Size math/size.h
+ \brief 2D size
+
+ Represents a 2D size (w, h).
+ Is separate from Math::Point to avoid confusion.
+
+ */
+struct Size
+{
+ //! Width
+ float w;
+ //! Height
+ float h;
+
+ //! Constructs a zero size: (0,0)
+ inline Size()
+ {
+ LoadZero();
+ }
+
+ //! Constructs a size from given dimensions: (w,h)
+ inline explicit Size(float w, float h)
+ {
+ this->w = w;
+ this->h = h;
+ }
+
+ //! Sets the zero size: (0,0)
+ inline void LoadZero()
+ {
+ w = h = 0.0f;
+ }
+}; // struct Size
+
+
+/* @} */ // end of group
+
+}; // namespace Math
diff --git a/src/math/vector.h b/src/math/vector.h
index 3c756f2..147869f 100644
--- a/src/math/vector.h
+++ b/src/math/vector.h
@@ -24,6 +24,7 @@
#include "func.h"
#include <cmath>
+#include <sstream>
// Math module namespace
@@ -72,6 +73,18 @@ struct Vector
x = y = z = 0.0f;
}
+ //! Returns the struct cast to \c float* array; use with care!
+ inline float* Array()
+ {
+ return reinterpret_cast<float*>(this);
+ }
+
+ //! Returns the struct cast to <tt>const float*</tt> array; use with care!
+ inline const float* Array() const
+ {
+ return reinterpret_cast<const float*>(this);
+ }
+
//! Returns the vector length
inline float Length() const
{
@@ -196,10 +209,20 @@ struct Vector
return Vector(left.x / right, left.y / right, left.z / right);
}
+
+ //! Returns a string "[x, y, z]"
+ inline std::string ToString() const
+ {
+ std::stringstream s;
+ s.precision(3);
+ s << "[" << x << ", " << y << ", " << z << "]";
+ return s.str();
+ }
+
}; // struct Point
//! Checks if two vectors are equal within given \a tolerance
-inline bool VectorsEqual(const Vector &a, const Vector &b, float tolerance = TOLERANCE)
+inline bool VectorsEqual(const Math::Vector &a, const Math::Vector &b, float tolerance = TOLERANCE)
{
return IsEqual(a.x, b.x, tolerance)
&& IsEqual(a.y, b.y, tolerance)
@@ -207,7 +230,7 @@ inline bool VectorsEqual(const Vector &a, const Vector &b, float tolerance = TOL
}
//! Convenience function for getting normalized vector
-inline Vector Normalize(const Vector &v)
+inline Vector Normalize(const Math::Vector &v)
{
Vector result = v;
result.Normalize();
@@ -215,25 +238,25 @@ inline Vector Normalize(const Vector &v)
}
//! Convenience function for calculating dot product
-inline float DotProduct(const Vector &left, const Vector &right)
+inline float DotProduct(const Math::Vector &left, const Math::Vector &right)
{
return left.DotMultiply(right);
}
//! Convenience function for calculating cross product
-inline Vector CrossProduct(const Vector &left, const Vector &right)
+inline Vector CrossProduct(const Math::Vector &left, const Math::Vector &right)
{
return left.CrossMultiply(right);
}
//! Convenience function for calculating angle (in radians) between two vectors
-inline float Angle(const Vector &a, const Vector &b)
+inline float Angle(const Math::Vector &a, const Math::Vector &b)
{
return a.Angle(b);
}
//! Returns the distance between the ends of two vectors
-inline float Distance(const Vector &a, const Vector &b)
+inline float Distance(const Math::Vector &a, const Math::Vector &b)
{
return sqrtf( (a.x-b.x)*(a.x-b.x) +
(a.y-b.y)*(a.y-b.y) +
diff --git a/src/sound/sound.h b/src/sound/sound.h
index 1bf9ae5..d323918 100644
--- a/src/sound/sound.h
+++ b/src/sound/sound.h
@@ -1,315 +1,322 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
-// *
-// * 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, either version 3 of the License, or
-// * (at your option) any later version.
-// *
-// * 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, see http://www.gnu.org/licenses/.
-
-// soundinterface.h
-
-/**
- * @file sound/soundinterface.h
- * @brief Sound plugin interface
- */
-
-#pragma once
-
-#include <math/vector.h>
-
-#include <plugins/plugininterface.h>
-
-/*!
- * Maximum possible audio volume
- */
-#define MAXVOLUME 100
-
-
-/**
- * \public
- * \enum Sound sound/soundinterface.h
- * \brief Sound enum representing sound file
-**/
-enum Sound
-{
- SOUND_CLICK = 0,
- SOUND_BOUM = 1,
- SOUND_EXPLO = 2,
- SOUND_FLYh = 3, /*!< human */
- SOUND_FLY = 4,
- SOUND_STEPs = 5, /*!< smooth */
- SOUND_MOTORw = 6, /*!< wheel */
- SOUND_MOTORt = 7, /*!< tank */
- SOUND_MOTORr = 8, /*!< roller */
- SOUND_ERROR = 9,
- SOUND_CONVERT = 10,
- SOUND_ENERGY = 11,
- SOUND_PLOUF = 12,
- SOUND_BLUP = 13,
- SOUND_WARNING = 14,
- SOUND_DERRICK = 15,
- SOUND_LABO = 16,
- SOUND_STATION = 17,
- SOUND_REPAIR = 18,
- SOUND_RESEARCH = 19,
- SOUND_INSECTs = 20, /*!< spider */
- SOUND_BURN = 21,
- SOUND_TZOING = 22,
- SOUND_GGG = 23,
- SOUND_MANIP = 24,
- SOUND_FIRE = 25, /*!< shooting with fireball */
- SOUND_HUMAN1 = 26, /*!< breathing */
- SOUND_STEPw = 27, /*!< water */
- SOUND_SWIM = 28,
- SOUND_RADAR = 29,
- SOUND_BUILD = 30,
- SOUND_ALARM = 31, /*!< energy alarm */
- SOUND_SLIDE = 32,
- SOUND_EXPLOi = 33, /*!< insect */
- SOUND_INSECTa = 34, /*!< ant */
- SOUND_INSECTb = 35, /*!< bee */
- SOUND_INSECTw = 36, /*!< worm */
- SOUND_INSECTm = 37, /*!< mother */
- SOUND_TREMBLE = 38,
- SOUND_PSHHH = 39,
- SOUND_NUCLEAR = 40,
- SOUND_INFO = 41,
- SOUND_OPEN = 42,
- SOUND_CLOSE = 43,
- SOUND_FACTORY = 44,
- SOUND_EGG = 45,
- SOUND_MOTORs = 46, /*!< submarine */
- SOUND_MOTORi = 47, /*!< insect (legs) */
- SOUND_SHIELD = 48,
- SOUND_FIREi = 49, /*!< shooting with orgaball (insect) */
- SOUND_GUNDEL = 50,
- SOUND_PSHHH2 = 51, /*!< shield */
- SOUND_MESSAGE = 52,
- SOUND_BOUMm = 53, /*!< metal */
- SOUND_BOUMv = 54, /*!< plant */
- SOUND_BOUMs = 55, /*!< smooth */
- SOUND_EXPLOl = 56, /*!< little */
- SOUND_EXPLOlp = 57, /*!< little power */
- SOUND_EXPLOp = 58, /*!< power */
- SOUND_STEPh = 59, /*!< hard */
- SOUND_STEPm = 60, /*!< metal */
- SOUND_POWERON = 61,
- SOUND_POWEROFF = 62,
- SOUND_AIE = 63,
- SOUND_WAYPOINT = 64,
- SOUND_RECOVER = 65,
- SOUND_DEADi = 66,
- SOUND_JOSTLE = 67,
- SOUND_GFLAT = 68,
- SOUND_DEADg = 69, /*!< shooting death */
- SOUND_DEADw = 70, /*!< drowning */
- SOUND_FLYf = 71, /*!< reactor fail */
- SOUND_ALARMt = 72, /*!< temperature alarm */
- SOUND_FINDING = 73, /*!< finds a cache object */
- SOUND_THUMP = 74,
- SOUND_TOUCH = 75,
- SOUND_BLITZ = 76,
- SOUND_MUSHROOM = 77,
- SOUND_FIREp = 78, /*!< shooting with phazer */
- SOUND_EXPLOg1 = 79, /*!< impact gun 1 */
- SOUND_EXPLOg2 = 80, /*!< impact gun 2 */
- SOUND_MOTORd = 81, /*!< engine friction */
-};
-
-
-/**
- * \public
- * \enum SoundNext sound/soundinterface.h
- * \brief Enum representing operation that will be performend on a sound at given time
-**/
-enum SoundNext
-{
- SOPER_CONTINUE = 1, /*!< continue playing */
- SOPER_STOP = 2, /*!< stop playing */
- SOPER_LOOP = 3, /*!< start over */
-};
-
-
-/**
-* @class CSoundInterface
-*
-* @brief Sound plugin interface
-*
-*/
-class CSoundInterface : public CPluginInterface
-{
- public:
- CSoundInterface() {};
- virtual ~CSoundInterface() = 0;
-
- /** Function to initialize sound device
- * @param bool b3D - enable support for 3D sound
- */
- virtual bool Create(bool b3D) = 0;
-
- /** Function called to cache all sound effect files.
- * Function calls \link CSoundInterface::Cache() \endlink for each file
- */
- virtual void CacheAll() = 0;
-
- /** Function called to cache sound effect file.
- * This function is called by plugin interface for each file.
- * @param Sound bSound - id of a file, will be used to identify sound files
- * @param std::string bFile - file to load
- * @return return true on success
- */
- virtual bool Cache(Sound bSound, std::string bFile) = 0;
-
- /** Return if plugin is enabled
- * @return return true if plugin is enabled
- */
- virtual bool RetEnable() = 0;
-
- /** Change sound mode to 2D/3D
- * @param bool bMode - true to enable 3D sound
- */
- virtual void SetSound3D(bool bMode) = 0;
-
- /** Return if we use 3D sound
- * @return true if we have 3D sound enabled
- */
- virtual bool RetSound3D() = 0;
-
- /** Return if we have 3D sound capable card
- * @return true for 3D sound support
- */
- virtual bool RetSound3DCap() = 0;
-
- /** Change global sound volume
- * @param int volume - range from 0 to MAXVOLUME
- */
- virtual void SetAudioVolume(int volume) = 0;
-
- /** Return global sound volume
- * @return global volume as int in range from 0 to MAXVOLUME
- */
- virtual int RetAudioVolume() = 0;
-
- /** Set music volume
- * @param int volume - range from 0 to MAXVOLUME
- */
- virtual void SetMusicVolume(int volume) = 0;
-
- /** Return music volume
- * @return music volume as int in range from 0 to MAXVOLUME
- */
- virtual int RetMusicVolume() = 0;
-
- /** Set listener position
- * @param Math::Vector eye - position of listener
- * @param Math::Vector lookat - direction listener is looking at
- */
- virtual void SetListener(Math::Vector eye, Math::Vector lookat) = 0;
-
- /** Update data each frame
- * @param float rTime - time since last update
- */
- virtual void FrameMove(float rTime) = 0;
-
- /** Play specific sound
- * @param Sound sound - sound to play
- * @param float amplitude - change amplitude of sound before playing
- * @param float frequency - change sound frequency before playing (0.5 octave down, 2.0 octave up)
- * @param bool bLoop - loop sound
- * @return identifier of channel that sound will be played on
- */
- virtual int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false) = 0;
-
- /** Play specific sound
- * @param Sound sound - sound to play
- * @param Math:Vector pos - position of sound in space
- * @param float amplitude - change amplitude of sound before playing
- * @param float frequency - change sound frequency before playing (0.5 octave down, 2.0 octave up)
- * @param bool bLoop - loop sound
- * @return identifier of channel that sound will be played on
- */
- virtual int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false) = 0;
-
- /** Remove all operations that would be made on sound in channel.
- * @param int channel - channel to work on
- * @return return true on success
- */
- virtual bool FlushEnvelope(int channel) = 0;
-
- /** Add envelope to sound. Envelope is a operatino that will be performend on sound in future like changing frequency
- * @param int channel - channel to work on
- * @param float amplitude - change amplitude
- * @param float frequency - change frequency
- * @param float time - when to change (sample time)
- * @param SoundNext oper - operation to perform
- * @return return true on success
- */
- virtual bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper) = 0;
-
- /** Set sound position in space
- * @param int channel - channel to work on
- * @param Math::Vector pos - new positino of a sound
- * @return return true on success
- */
- virtual bool Position(int channel, Math::Vector pos) = 0;
-
- /** Set sound frequency
- * @param int channel - channel to work on
- * @param float frequency - change sound frequency
- * @return return true on success
- */
- virtual bool Frequency(int channel, float frequency) = 0;
-
- /** Stop playing sound
- * @param int channel - channel to work on
- * @return return true on success
- */
- virtual bool Stop(int channel) = 0;
-
- /** Stop playing all sounds
- * @return return true on success
- */
- virtual bool StopAll() = 0;
-
- /** Mute/unmute all sounds
- * @param bool bMute
- * @return return true on success
- */
- virtual bool MuteAll(bool bMute) = 0;
-
- /** Start playing music
- * @param int rank - track number
- * @param bool bRepeat - repeat playing
- * @return return true on success
- */
- virtual bool PlayMusic(int rank, bool bRepeat) = 0;
-
- /** Restart music
- * @return return true on success
- */
- virtual bool RestartMusic() = 0;
-
- /** Susspend paying music
- * @return return true on success
- */
- virtual void SuspendMusic() = 0;
-
- /** Stop playing music
- * @return return true on success
- */
- virtual void StopMusic() = 0;
-
- /** Check if music if playing
- * @return return true if music is playing
- */
- virtual bool IsPlayingMusic() = 0;
-};
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * 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, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * 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, see http://www.gnu.org/licenses/.
+
+// soundinterface.h
+
+/**
+ * @file sound/soundinterface.h
+ * @brief Sound plugin interface
+ */
+
+#pragma once
+
+#include <math/vector.h>
+
+#include <plugins/plugin.h>
+
+#include <string>
+
+
+/*!
+ * Maximum possible audio volume
+ */
+#define MAXVOLUME 100
+
+
+/**
+ * \public
+ * \enum Sound sound/soundinterface.h
+ * \brief Sound enum representing sound file
+**/
+enum Sound
+{
+ SOUND_CLICK = 0,
+ SOUND_BOUM = 1,
+ SOUND_EXPLO = 2,
+ SOUND_FLYh = 3, /*!< human */
+ SOUND_FLY = 4,
+ SOUND_STEPs = 5, /*!< smooth */
+ SOUND_MOTORw = 6, /*!< wheel */
+ SOUND_MOTORt = 7, /*!< tank */
+ SOUND_MOTORr = 8, /*!< roller */
+ SOUND_ERROR = 9,
+ SOUND_CONVERT = 10,
+ SOUND_ENERGY = 11,
+ SOUND_PLOUF = 12,
+ SOUND_BLUP = 13,
+ SOUND_WARNING = 14,
+ SOUND_DERRICK = 15,
+ SOUND_LABO = 16,
+ SOUND_STATION = 17,
+ SOUND_REPAIR = 18,
+ SOUND_RESEARCH = 19,
+ SOUND_INSECTs = 20, /*!< spider */
+ SOUND_BURN = 21,
+ SOUND_TZOING = 22,
+ SOUND_GGG = 23,
+ SOUND_MANIP = 24,
+ SOUND_FIRE = 25, /*!< shooting with fireball */
+ SOUND_HUMAN1 = 26, /*!< breathing */
+ SOUND_STEPw = 27, /*!< water */
+ SOUND_SWIM = 28,
+ SOUND_RADAR = 29,
+ SOUND_BUILD = 30,
+ SOUND_ALARM = 31, /*!< energy alarm */
+ SOUND_SLIDE = 32,
+ SOUND_EXPLOi = 33, /*!< insect */
+ SOUND_INSECTa = 34, /*!< ant */
+ SOUND_INSECTb = 35, /*!< bee */
+ SOUND_INSECTw = 36, /*!< worm */
+ SOUND_INSECTm = 37, /*!< mother */
+ SOUND_TREMBLE = 38,
+ SOUND_PSHHH = 39,
+ SOUND_NUCLEAR = 40,
+ SOUND_INFO = 41,
+ SOUND_OPEN = 42,
+ SOUND_CLOSE = 43,
+ SOUND_FACTORY = 44,
+ SOUND_EGG = 45,
+ SOUND_MOTORs = 46, /*!< submarine */
+ SOUND_MOTORi = 47, /*!< insect (legs) */
+ SOUND_SHIELD = 48,
+ SOUND_FIREi = 49, /*!< shooting with orgaball (insect) */
+ SOUND_GUNDEL = 50,
+ SOUND_PSHHH2 = 51, /*!< shield */
+ SOUND_MESSAGE = 52,
+ SOUND_BOUMm = 53, /*!< metal */
+ SOUND_BOUMv = 54, /*!< plant */
+ SOUND_BOUMs = 55, /*!< smooth */
+ SOUND_EXPLOl = 56, /*!< little */
+ SOUND_EXPLOlp = 57, /*!< little power */
+ SOUND_EXPLOp = 58, /*!< power */
+ SOUND_STEPh = 59, /*!< hard */
+ SOUND_STEPm = 60, /*!< metal */
+ SOUND_POWERON = 61,
+ SOUND_POWEROFF = 62,
+ SOUND_AIE = 63,
+ SOUND_WAYPOINT = 64,
+ SOUND_RECOVER = 65,
+ SOUND_DEADi = 66,
+ SOUND_JOSTLE = 67,
+ SOUND_GFLAT = 68,
+ SOUND_DEADg = 69, /*!< shooting death */
+ SOUND_DEADw = 70, /*!< drowning */
+ SOUND_FLYf = 71, /*!< reactor fail */
+ SOUND_ALARMt = 72, /*!< temperature alarm */
+ SOUND_FINDING = 73, /*!< finds a cache object */
+ SOUND_THUMP = 74,
+ SOUND_TOUCH = 75,
+ SOUND_BLITZ = 76,
+ SOUND_MUSHROOM = 77,
+ SOUND_FIREp = 78, /*!< shooting with phazer */
+ SOUND_EXPLOg1 = 79, /*!< impact gun 1 */
+ SOUND_EXPLOg2 = 80, /*!< impact gun 2 */
+ SOUND_MOTORd = 81, /*!< engine friction */
+};
+
+
+/**
+ * \public
+ * \enum SoundNext sound/soundinterface.h
+ * \brief Enum representing operation that will be performend on a sound at given time
+**/
+enum SoundNext
+{
+ SOPER_CONTINUE = 1, /*!< continue playing */
+ SOPER_STOP = 2, /*!< stop playing */
+ SOPER_LOOP = 3, /*!< start over */
+};
+
+
+/**
+* @class CSoundInterface
+*
+* @brief Sound plugin interface
+*
+*/
+class CSoundInterface : public CPlugin
+{
+ public:
+ CSoundInterface() {
+ //CInstanceManager::getInstance().AddInstance(CLASS_SOUND, this);
+ //m_iMan->AddInstance(CLASS_SOUND, this);
+ };
+ virtual ~CSoundInterface() = 0;
+
+ /** Function to initialize sound device
+ * @param bool b3D - enable support for 3D sound
+ */
+ virtual bool Create(bool b3D) = 0;
+
+ /** Function called to cache all sound effect files.
+ * Function calls \link CSoundInterface::Cache() \endlink for each file
+ */
+ virtual void CacheAll() = 0;
+
+ /** Function called to cache sound effect file.
+ * This function is called by plugin interface for each file.
+ * @param Sound bSound - id of a file, will be used to identify sound files
+ * @param std::string bFile - file to load
+ * @return return true on success
+ */
+ virtual bool Cache(Sound bSound, std::string bFile) = 0;
+
+ /** Return if plugin is enabled
+ * @return return true if plugin is enabled
+ */
+ virtual bool RetEnable() = 0;
+
+ /** Change sound mode to 2D/3D
+ * @param bool bMode - true to enable 3D sound
+ */
+ virtual void SetSound3D(bool bMode) = 0;
+
+ /** Return if we use 3D sound
+ * @return true if we have 3D sound enabled
+ */
+ virtual bool RetSound3D() = 0;
+
+ /** Return if we have 3D sound capable card
+ * @return true for 3D sound support
+ */
+ virtual bool RetSound3DCap() = 0;
+
+ /** Change global sound volume
+ * @param int volume - range from 0 to MAXVOLUME
+ */
+ virtual void SetAudioVolume(int volume) = 0;
+
+ /** Return global sound volume
+ * @return global volume as int in range from 0 to MAXVOLUME
+ */
+ virtual int RetAudioVolume() = 0;
+
+ /** Set music volume
+ * @param int volume - range from 0 to MAXVOLUME
+ */
+ virtual void SetMusicVolume(int volume) = 0;
+
+ /** Return music volume
+ * @return music volume as int in range from 0 to MAXVOLUME
+ */
+ virtual int RetMusicVolume() = 0;
+
+ /** Set listener position
+ * @param Math::Vector eye - position of listener
+ * @param Math::Vector lookat - direction listener is looking at
+ */
+ virtual void SetListener(Math::Vector eye, Math::Vector lookat) = 0;
+
+ /** Update data each frame
+ * @param float rTime - time since last update
+ */
+ virtual void FrameMove(float rTime) = 0;
+
+ /** Play specific sound
+ * @param Sound sound - sound to play
+ * @param float amplitude - change amplitude of sound before playing
+ * @param float frequency - change sound frequency before playing (0.5 octave down, 2.0 octave up)
+ * @param bool bLoop - loop sound
+ * @return identifier of channel that sound will be played on
+ */
+ virtual int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false) = 0;
+
+ /** Play specific sound
+ * @param Sound sound - sound to play
+ * @param Math:Vector pos - position of sound in space
+ * @param float amplitude - change amplitude of sound before playing
+ * @param float frequency - change sound frequency before playing (0.5 octave down, 2.0 octave up)
+ * @param bool bLoop - loop sound
+ * @return identifier of channel that sound will be played on
+ */
+ virtual int Play(Sound sound, Math::Vector pos, float amplitude=1.0f, float frequency=1.0f, bool bLoop = false) = 0;
+
+ /** Remove all operations that would be made on sound in channel.
+ * @param int channel - channel to work on
+ * @return return true on success
+ */
+ virtual bool FlushEnvelope(int channel) = 0;
+
+ /** Add envelope to sound. Envelope is a operatino that will be performend on sound in future like changing frequency
+ * @param int channel - channel to work on
+ * @param float amplitude - change amplitude
+ * @param float frequency - change frequency
+ * @param float time - when to change (sample time)
+ * @param SoundNext oper - operation to perform
+ * @return return true on success
+ */
+ virtual bool AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper) = 0;
+
+ /** Set sound position in space
+ * @param int channel - channel to work on
+ * @param Math::Vector pos - new positino of a sound
+ * @return return true on success
+ */
+ virtual bool Position(int channel, Math::Vector pos) = 0;
+
+ /** Set sound frequency
+ * @param int channel - channel to work on
+ * @param float frequency - change sound frequency
+ * @return return true on success
+ */
+ virtual bool Frequency(int channel, float frequency) = 0;
+
+ /** Stop playing sound
+ * @param int channel - channel to work on
+ * @return return true on success
+ */
+ virtual bool Stop(int channel) = 0;
+
+ /** Stop playing all sounds
+ * @return return true on success
+ */
+ virtual bool StopAll() = 0;
+
+ /** Mute/unmute all sounds
+ * @param bool bMute
+ * @return return true on success
+ */
+ virtual bool MuteAll(bool bMute) = 0;
+
+ /** Start playing music
+ * @param int rank - track number
+ * @param bool bRepeat - repeat playing
+ * @return return true on success
+ */
+ virtual bool PlayMusic(int rank, bool bRepeat) = 0;
+
+ /** Restart music
+ * @return return true on success
+ */
+ virtual bool RestartMusic() = 0;
+
+ /** Susspend paying music
+ * @return return true on success
+ */
+ virtual void SuspendMusic() = 0;
+
+ /** Stop playing music
+ * @return return true on success
+ */
+ virtual void StopMusic() = 0;
+
+ /** Check if music if playing
+ * @return return true if music is playing
+ */
+ virtual bool IsPlayingMusic() = 0;
+};
+