summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoradiblol <adiblol@1tbps.org>2012-03-08 19:32:05 +0100
committeradiblol <adiblol@1tbps.org>2012-03-08 19:32:05 +0100
commita4c804b49ec872b71bd5a0167c3ad45704a3cc30 (patch)
tree8c931235247d662ca46a99695beb328fdfc8e8a8 /src
downloadcolobot-a4c804b49ec872b71bd5a0167c3ad45704a3cc30.tar.gz
colobot-a4c804b49ec872b71bd5a0167c3ad45704a3cc30.tar.bz2
colobot-a4c804b49ec872b71bd5a0167c3ad45704a3cc30.zip
Initial commit, Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
Diffstat (limited to 'src')
-rw-r--r--src/CBot.dllbin0 -> 434176 bytes
-rw-r--r--src/CBot/CBot.apsbin0 -> 44112 bytes
-rw-r--r--src/CBot/CBot.cpp4055
-rw-r--r--src/CBot/CBot.dsp158
-rw-r--r--src/CBot/CBot.dsw44
-rw-r--r--src/CBot/CBot.h1611
-rw-r--r--src/CBot/CBot.libbin0 -> 107676 bytes
-rw-r--r--src/CBot/CBot.optbin0 -> 53760 bytes
-rw-r--r--src/CBot/CBot.plg61
-rw-r--r--src/CBot/CBot.rc279
-rw-r--r--src/CBot/CBotAddExpr.cpp128
-rw-r--r--src/CBot/CBotClass.cpp867
-rw-r--r--src/CBot/CBotCompExpr.cpp117
-rw-r--r--src/CBot/CBotDll.h1185
-rw-r--r--src/CBot/CBotFunction.cpp1634
-rw-r--r--src/CBot/CBotIf.cpp145
-rw-r--r--src/CBot/CBotProgram.cpp1102
-rw-r--r--src/CBot/CBotStack.cpp1460
-rw-r--r--src/CBot/CBotString.cpp588
-rw-r--r--src/CBot/CBotToken.cpp540
-rw-r--r--src/CBot/CBotToken.h23
-rw-r--r--src/CBot/CBotTwoOpExpr ordre inversé.cpp302
-rw-r--r--src/CBot/CBotTwoOpExpr.cpp552
-rw-r--r--src/CBot/CBotVar.cpp2231
-rw-r--r--src/CBot/CBotWhile.cpp1413
-rw-r--r--src/CBot/ClassFILE.cpp412
-rw-r--r--src/CBot/Copie de CBot.rc184
-rw-r--r--src/CBot/Copie de CBotTwoOpExpr.cpp295
-rw-r--r--src/CBot/StringFunctions.cpp420
-rw-r--r--src/CBot/TestCBot/B.txt18
-rw-r--r--src/CBot/TestCBot/BUG2.txt107
-rw-r--r--src/CBot/TestCBot/CBotConsoleDlg.cpp205
-rw-r--r--src/CBot/TestCBot/CBotConsoleDlg.h69
-rw-r--r--src/CBot/TestCBot/ChildFrm.cpp58
-rw-r--r--src/CBot/TestCBot/ChildFrm.h50
-rw-r--r--src/CBot/TestCBot/Deleted.txt23
-rw-r--r--src/CBot/TestCBot/MaClass.txt16
-rw-r--r--src/CBot/TestCBot/MainFrm.cpp100
-rw-r--r--src/CBot/TestCBot/MainFrm.h56
-rw-r--r--src/CBot/TestCBot/Mc2.txt4
-rw-r--r--src/CBot/TestCBot/Mon fichier.txt2
-rw-r--r--src/CBot/TestCBot/Nop.txt4
-rw-r--r--src/CBot/TestCBot/POS.txt14
-rw-r--r--src/CBot/TestCBot/PerformDlg.cpp161
-rw-r--r--src/CBot/TestCBot/PerformDlg.h62
-rw-r--r--src/CBot/TestCBot/Routines.cpp139
-rw-r--r--src/CBot/TestCBot/StdAfx.cpp6
-rw-r--r--src/CBot/TestCBot/StdAfx.h26
-rw-r--r--src/CBot/TestCBot/T.txt4
-rw-r--r--src/CBot/TestCBot/TESTALL.txt161
-rw-r--r--src/CBot/TestCBot/TestCB1.txt18
-rw-r--r--src/CBot/TestCBot/TestCBot.clw316
-rw-r--r--src/CBot/TestCBot/TestCBot.cpp253
-rw-r--r--src/CBot/TestCBot/TestCBot.dsp201
-rw-r--r--src/CBot/TestCBot/TestCBot.h64
-rw-r--r--src/CBot/TestCBot/TestCBot.rc564
-rw-r--r--src/CBot/TestCBot/TestCBot1.txt27
-rw-r--r--src/CBot/TestCBot/TestCBot3.txt24
-rw-r--r--src/CBot/TestCBot/TestCBotDoc.cpp683
-rw-r--r--src/CBot/TestCBot/TestCBotDoc.h64
-rw-r--r--src/CBot/TestCBot/TestCBotView.cpp126
-rw-r--r--src/CBot/TestCBot/TestCBotView.h64
-rw-r--r--src/CBot/TestCBot/TestNull.txt15
-rw-r--r--src/CBot/TestCBot/TestRestoreState.txt67
-rw-r--r--src/CBot/TestCBot/TestStatic.txt31
-rw-r--r--src/CBot/TestCBot/TestStr.txt17
-rw-r--r--src/CBot/TestCBot/Z.txt14
-rw-r--r--src/CBot/TestCBot/array.txt24
-rw-r--r--src/CBot/TestCBot/a§1.txt96
-rw-r--r--src/CBot/TestCBot/bug.txt12
-rw-r--r--src/CBot/TestCBot/bugmw.txt9
-rw-r--r--src/CBot/TestCBot/ccc.txt8
-rw-r--r--src/CBot/TestCBot/enum.txt9
-rw-r--r--src/CBot/TestCBot/fibo.txt25
-rw-r--r--src/CBot/TestCBot/file.txt70
-rw-r--r--src/CBot/TestCBot/h.txt5
-rw-r--r--src/CBot/TestCBot/include.txt27
-rw-r--r--src/CBot/TestCBot/intrinsic.txt16
-rw-r--r--src/CBot/TestCBot/methode1.txt57
-rw-r--r--src/CBot/TestCBot/methode2.txt50
-rw-r--r--src/CBot/TestCBot/mp1.txt25
-rw-r--r--src/CBot/TestCBot/mp2.txt28
-rw-r--r--src/CBot/TestCBot/mw.txt16
-rw-r--r--src/CBot/TestCBot/null.txt5
-rw-r--r--src/CBot/TestCBot/opnew.txt20
-rw-r--r--src/CBot/TestCBot/plante.txt25
-rw-r--r--src/CBot/TestCBot/pointer.txt41
-rw-r--r--src/CBot/TestCBot/postinc.txt7
-rw-r--r--src/CBot/TestCBot/radar.txt39
-rw-r--r--src/CBot/TestCBot/res/TestCBot.icobin0 -> 1078 bytes
-rw-r--r--src/CBot/TestCBot/res/TestCBot.rc213
-rw-r--r--src/CBot/TestCBot/res/TestCBotDoc.icobin0 -> 1078 bytes
-rw-r--r--src/CBot/TestCBot/res/Toolbar.bmpbin0 -> 1198 bytes
-rw-r--r--src/CBot/TestCBot/resource.h30
-rw-r--r--src/CBot/TestCBot/solution.txt13
-rw-r--r--src/CBot/TestCBot/test.txt8
-rw-r--r--src/CBot/TestCBot/test23.txt10
-rw-r--r--src/CBot/TestCBot/testmw.txt14
-rw-r--r--src/CBot/TestCBot/this.txt13
-rw-r--r--src/CBot/TestCBot/tt.txt12
-rw-r--r--src/CBot/TestCBot/tt2.txt5
-rw-r--r--src/CBot/TestCBot/vide.txt0
-rw-r--r--src/CBot/TestCBot/xTestCBot.clw245
-rw-r--r--src/CBot/TestCBot/zz.txt6
-rw-r--r--src/CBot/_Copy.bat2
-rw-r--r--src/CBot/colobot.ini49
-rw-r--r--src/CBot/idees.txt39
-rw-r--r--src/CBot/old CBotAddExpr.cpp130
-rw-r--r--src/CBot/old CBotCompExpr.cpp120
-rw-r--r--src/CBot/old TstCBot/BotConsoleDlg.cpp164
-rw-r--r--src/CBot/old TstCBot/BotConsoleDlg.h65
-rw-r--r--src/CBot/old TstCBot/BotErrorDlg.cpp56
-rw-r--r--src/CBot/old TstCBot/BotErrorDlg.h51
-rw-r--r--src/CBot/old TstCBot/CBotTest.txt36
-rw-r--r--src/CBot/old TstCBot/CMyThread.cpp107
-rw-r--r--src/CBot/old TstCBot/CMyThread.h44
-rw-r--r--src/CBot/old TstCBot/MainFrm.cpp91
-rw-r--r--src/CBot/old TstCBot/MainFrm.h55
-rw-r--r--src/CBot/old TstCBot/ReadMe.txt93
-rw-r--r--src/CBot/old TstCBot/Resource.h68
-rw-r--r--src/CBot/old TstCBot/StdAfx.cpp6
-rw-r--r--src/CBot/old TstCBot/StdAfx.h26
-rw-r--r--src/CBot/old TstCBot/TstCBot.clw189
-rw-r--r--src/CBot/old TstCBot/TstCBot.cpp412
-rw-r--r--src/CBot/old TstCBot/TstCBot.dsp180
-rw-r--r--src/CBot/old TstCBot/TstCBot.h62
-rw-r--r--src/CBot/old TstCBot/TstCBot.rc471
-rw-r--r--src/CBot/old TstCBot/TstCBotDoc.cpp83
-rw-r--r--src/CBot/old TstCBot/TstCBotDoc.h55
-rw-r--r--src/CBot/old TstCBot/TstCBotView.cpp291
-rw-r--r--src/CBot/old TstCBot/TstCBotView.h81
-rw-r--r--src/CBot/old TstCBot/res/TstCBot.icobin0 -> 1078 bytes
-rw-r--r--src/CBot/old TstCBot/res/TstCBot.rc213
-rw-r--r--src/CBot/old TstCBot/res/TstCBotDoc.icobin0 -> 1078 bytes
-rw-r--r--src/CBot/old TstCBot/test complet 1.txt213
-rw-r--r--src/CBot/old TstCBot/x.txt43
-rw-r--r--src/CBot/resource.h166
-rw-r--r--src/ClassFILE.cpp413
-rw-r--r--src/Copie de taskgoto.cpp2136
-rw-r--r--src/DirectX.icobin0 -> 1078 bytes
-rw-r--r--src/accents.txt5
-rw-r--r--src/auto.cpp447
-rw-r--r--src/auto.h95
-rw-r--r--src/autobase.cpp1446
-rw-r--r--src/autobase.h102
-rw-r--r--src/autoconvert.cpp532
-rw-r--r--src/autoconvert.h62
-rw-r--r--src/autoderrick.cpp591
-rw-r--r--src/autoderrick.h65
-rw-r--r--src/autodestroyer.cpp383
-rw-r--r--src/autodestroyer.h57
-rw-r--r--src/autoegg.cpp359
-rw-r--r--src/autoegg.h64
-rw-r--r--src/autoenergy.cpp652
-rw-r--r--src/autoenergy.h63
-rw-r--r--src/autofactory.cpp947
-rw-r--r--src/autofactory.h66
-rw-r--r--src/autoflag.cpp164
-rw-r--r--src/autoflag.h40
-rw-r--r--src/autohuston.cpp301
-rw-r--r--src/autohuston.h59
-rw-r--r--src/autoinfo.cpp523
-rw-r--r--src/autoinfo.h60
-rw-r--r--src/autojostle.cpp153
-rw-r--r--src/autojostle.h40
-rw-r--r--src/autokid.cpp208
-rw-r--r--src/autokid.h41
-rw-r--r--src/autolabo.cpp615
-rw-r--r--src/autolabo.h67
-rw-r--r--src/automush.cpp348
-rw-r--r--src/automush.h55
-rw-r--r--src/autonest.cpp277
-rw-r--r--src/autonest.h55
-rw-r--r--src/autonuclear.cpp490
-rw-r--r--src/autonuclear.h60
-rw-r--r--src/autopara.cpp333
-rw-r--r--src/autopara.h57
-rw-r--r--src/autoportico.cpp432
-rw-r--r--src/autoportico.h61
-rw-r--r--src/autoradar.cpp312
-rw-r--r--src/autoradar.h56
-rw-r--r--src/autorepair.cpp348
-rw-r--r--src/autorepair.h55
-rw-r--r--src/autoresearch.cpp613
-rw-r--r--src/autoresearch.h64
-rw-r--r--src/autoroot.cpp121
-rw-r--r--src/autoroot.h38
-rw-r--r--src/autosafe.cpp622
-rw-r--r--src/autosafe.h66
-rw-r--r--src/autostation.cpp373
-rw-r--r--src/autostation.h48
-rw-r--r--src/autotower.cpp547
-rw-r--r--src/autotower.h68
-rw-r--r--src/blitz.cpp456
-rw-r--r--src/blitz.h64
-rw-r--r--src/brain.cpp2985
-rw-r--r--src/brain.h202
-rw-r--r--src/bug.txt94
-rw-r--r--src/bug1.txt68
-rw-r--r--src/bugs/Colobot_image blèm.pspbin0 -> 42641 bytes
-rw-r--r--src/bugs/Image1.gifbin0 -> 195965 bytes
-rw-r--r--src/bugs/Image2.gifbin0 -> 172230 bytes
-rw-r--r--src/bugs/Image3.gifbin0 -> 123415 bytes
-rw-r--r--src/bugs/Image4.gifbin0 -> 15063 bytes
-rw-r--r--src/bugs/Image9.gifbin0 -> 173575 bytes
-rw-r--r--src/bugs/borne.gifbin0 -> 195790 bytes
-rw-r--r--src/button.cpp237
-rw-r--r--src/button.h42
-rw-r--r--src/camera.cpp2095
-rw-r--r--src/camera.h252
-rw-r--r--src/cbottoken.cpp507
-rw-r--r--src/cbottoken.h24
-rw-r--r--src/ceebot.ini66
-rw-r--r--src/check.cpp156
-rw-r--r--src/check.h32
-rw-r--r--src/cloud.cpp317
-rw-r--r--src/cloud.h71
-rw-r--r--src/cmdtoken.cpp964
-rw-r--r--src/cmdtoken.h50
-rw-r--r--src/colobot.ini75
-rw-r--r--src/color.cpp215
-rw-r--r--src/color.h41
-rw-r--r--src/compass.cpp165
-rw-r--r--src/compass.h36
-rw-r--r--src/control.cpp862
-rw-r--r--src/control.h118
-rw-r--r--src/cur00001.curbin0 -> 326 bytes
-rw-r--r--src/cur00002.curbin0 -> 326 bytes
-rw-r--r--src/cur00003.curbin0 -> 326 bytes
-rw-r--r--src/cursor1.curbin0 -> 326 bytes
-rw-r--r--src/cursorha.curbin0 -> 326 bytes
-rw-r--r--src/cursorsc.curbin0 -> 326 bytes
-rw-r--r--src/d3dapp.cpp2433
-rw-r--r--src/d3dapp.h153
-rw-r--r--src/d3dengine.cpp5711
-rw-r--r--src/d3dengine.h669
-rw-r--r--src/d3denum.cpp603
-rw-r--r--src/d3denum.h120
-rw-r--r--src/d3dframe.cpp607
-rw-r--r--src/d3dframe.h126
-rw-r--r--src/d3dmath.cpp327
-rw-r--r--src/d3dmath.h81
-rw-r--r--src/d3dres.h43
-rw-r--r--src/d3dtextr.cpp1064
-rw-r--r--src/d3dtextr.h64
-rw-r--r--src/d3dutil.cpp311
-rw-r--r--src/d3dutil.h98
-rw-r--r--src/dd.cpp159
-rw-r--r--src/displayinfo.cpp1206
-rw-r--r--src/displayinfo.h72
-rw-r--r--src/displaytext.cpp599
-rw-r--r--src/displaytext.h77
-rw-r--r--src/edit.cpp3305
-rw-r--r--src/edit.h238
-rw-r--r--src/editvalue.cpp368
-rw-r--r--src/editvalue.h69
-rw-r--r--src/event.cpp75
-rw-r--r--src/event.h617
-rw-r--r--src/gauge.cpp146
-rw-r--r--src/gauge.h36
-rw-r--r--src/global.h48
-rw-r--r--src/group.cpp632
-rw-r--r--src/group.h32
-rw-r--r--src/image.cpp145
-rw-r--r--src/image.h36
-rw-r--r--src/iman.cpp149
-rw-r--r--src/iman.h42
-rw-r--r--src/interface.cpp591
-rw-r--r--src/interface.h77
-rw-r--r--src/joystick.cpp222
-rw-r--r--src/joystick.h15
-rw-r--r--src/key.cpp277
-rw-r--r--src/key.h38
-rw-r--r--src/label.cpp81
-rw-r--r--src/label.h32
-rw-r--r--src/language.h35
-rw-r--r--src/light.cpp487
-rw-r--r--src/light.h95
-rw-r--r--src/list.cpp858
-rw-r--r--src/list.h100
-rw-r--r--src/maindialog.cpp6922
-rw-r--r--src/maindialog.h242
-rw-r--r--src/mainmap.cpp388
-rw-r--r--src/mainmap.h52
-rw-r--r--src/mainmovie.cpp233
-rw-r--r--src/mainmovie.h64
-rw-r--r--src/mainshort.cpp360
-rw-r--r--src/mainshort.h45
-rw-r--r--src/map.cpp1327
-rw-r--r--src/map.h126
-rw-r--r--src/math3d.cpp1026
-rw-r--r--src/math3d.h90
-rw-r--r--src/metafile.cpp403
-rw-r--r--src/metafile.h60
-rw-r--r--src/micent2.txt13
-rw-r--r--src/misc.cpp425
-rw-r--r--src/misc.h223
-rw-r--r--src/mixer.txt486
-rw-r--r--src/model.cpp3214
-rw-r--r--src/model.h118
-rw-r--r--src/modfile.cpp681
-rw-r--r--src/modfile.h101
-rw-r--r--src/motion.cpp241
-rw-r--r--src/motion.h75
-rw-r--r--src/motionant.cpp886
-rw-r--r--src/motionant.h61
-rw-r--r--src/motionbee.cpp647
-rw-r--r--src/motionbee.h54
-rw-r--r--src/motionhuman.cpp1784
-rw-r--r--src/motionhuman.h82
-rw-r--r--src/motionmother.cpp527
-rw-r--r--src/motionmother.h48
-rw-r--r--src/motionspider.cpp774
-rw-r--r--src/motionspider.h59
-rw-r--r--src/motiontoto.cpp870
-rw-r--r--src/motiontoto.h61
-rw-r--r--src/motionvehicle.cpp2075
-rw-r--r--src/motionvehicle.h63
-rw-r--r--src/motionworm.cpp365
-rw-r--r--src/motionworm.h56
-rw-r--r--src/object.cpp7599
-rw-r--r--src/object.h767
-rw-r--r--src/particule.cpp4357
-rw-r--r--src/particule.h326
-rw-r--r--src/patch16.txt10
-rw-r--r--src/physics.cpp3873
-rw-r--r--src/physics.h228
-rw-r--r--src/planet.cpp232
-rw-r--r--src/planet.h60
-rw-r--r--src/profile.cpp100
-rw-r--r--src/profile.h20
-rw-r--r--src/projet1.dsp608
-rw-r--r--src/projet1.dsw29
-rw-r--r--src/projet1.mak8659
-rw-r--r--src/projet1.optbin0 -> 58880 bytes
-rw-r--r--src/projet1.plg199
-rw-r--r--src/pyro.cpp2470
-rw-r--r--src/pyro.h158
-rw-r--r--src/readme.txt872
-rw-r--r--src/resource.h39
-rw-r--r--src/restext-old.cpp2527
-rw-r--r--src/restext.cpp3649
-rw-r--r--src/restext.h141
-rw-r--r--src/robotmain.cpp7018
-rw-r--r--src/robotmain.h449
-rw-r--r--src/script.cpp3762
-rw-r--r--src/script.h99
-rw-r--r--src/scroll.cpp459
-rw-r--r--src/scroll.h67
-rw-r--r--src/shortcut.cpp229
-rw-r--r--src/shortcut.h34
-rw-r--r--src/slider.cpp570
-rw-r--r--src/slider.h67
-rw-r--r--src/sound.cpp1640
-rw-r--r--src/sound.h225
-rw-r--r--src/struct.h57
-rw-r--r--src/studio.cpp1649
-rw-r--r--src/studio.h97
-rw-r--r--src/t.txt11
-rw-r--r--src/target.cpp271
-rw-r--r--src/target.h34
-rw-r--r--src/task.cpp93
-rw-r--r--src/task.h70
-rw-r--r--src/taskadvance.cpp143
-rw-r--r--src/taskadvance.h39
-rw-r--r--src/taskbuild.cpp806
-rw-r--r--src/taskbuild.h74
-rw-r--r--src/taskfire.cpp382
-rw-r--r--src/taskfire.h42
-rw-r--r--src/taskfireant.cpp211
-rw-r--r--src/taskfireant.h53
-rw-r--r--src/taskflag.cpp305
-rw-r--r--src/taskflag.h48
-rw-r--r--src/taskgoto.cpp2340
-rw-r--r--src/taskgoto.h147
-rw-r--r--src/taskgungoal.cpp145
-rw-r--r--src/taskgungoal.h38
-rw-r--r--src/taskinfo.cpp217
-rw-r--r--src/taskinfo.h38
-rw-r--r--src/taskmanager.cpp275
-rw-r--r--src/taskmanager.h62
-rw-r--r--src/taskmanip.cpp1383
-rw-r--r--src/taskmanip.h88
-rw-r--r--src/taskpen.cpp288
-rw-r--r--src/taskpen.h58
-rw-r--r--src/taskrecover.cpp415
-rw-r--r--src/taskrecover.h56
-rw-r--r--src/taskreset.cpp329
-rw-r--r--src/taskreset.h53
-rw-r--r--src/tasksearch.cpp318
-rw-r--r--src/tasksearch.h60
-rw-r--r--src/taskshield.cpp557
-rw-r--r--src/taskshield.h74
-rw-r--r--src/taskspiderexplo.cpp108
-rw-r--r--src/taskspiderexplo.h34
-rw-r--r--src/tasktake.cpp596
-rw-r--r--src/tasktake.h65
-rw-r--r--src/taskterraform.cpp413
-rw-r--r--src/taskterraform.h52
-rw-r--r--src/taskturn.cpp131
-rw-r--r--src/taskturn.h36
-rw-r--r--src/taskwait.cpp73
-rw-r--r--src/taskwait.h34
-rw-r--r--src/terrain.cpp2263
-rw-r--r--src/terrain.h195
-rw-r--r--src/text.cpp1865
-rw-r--r--src/text.h96
-rw-r--r--src/tracks.txt17
-rw-r--r--src/traduc.txt151
-rw-r--r--src/version.txt108
-rw-r--r--src/water.cpp819
-rw-r--r--src/water.h118
-rw-r--r--src/window.cpp1610
-rw-r--r--src/window.h132
-rw-r--r--src/winmain.apsbin0 -> 40696 bytes
-rw-r--r--src/winmain.cpp24
-rw-r--r--src/winmain.rc265
417 files changed, 175301 insertions, 0 deletions
diff --git a/src/CBot.dll b/src/CBot.dll
new file mode 100644
index 0000000..5b9c1bb
--- /dev/null
+++ b/src/CBot.dll
Binary files differ
diff --git a/src/CBot/CBot.aps b/src/CBot/CBot.aps
new file mode 100644
index 0000000..cd294ec
--- /dev/null
+++ b/src/CBot/CBot.aps
Binary files differ
diff --git a/src/CBot/CBot.cpp b/src/CBot/CBot.cpp
new file mode 100644
index 0000000..79a0b6f
--- /dev/null
+++ b/src/CBot/CBot.cpp
@@ -0,0 +1,4055 @@
+///////////////////////////////////////////////////////////////////////
+// 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(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 int 3; // 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 int 3; // ne doit jamais passer par cette routine
+ // mais utiliser les routines des classes filles
+}
+
+
+BOOL CBotInstr::ExecuteVar(CBotVar* &pVar, CBotCStack* &pile)
+{
+ __asm int 3; // papa sait pas faire, voir les filles
+ return FALSE;
+}
+
+BOOL CBotInstr::ExecuteVar(CBotVar* &pVar, CBotStack* &pile, CBotToken* prevToken, BOOL bStep, BOOL bExtend)
+{
+ __asm int 3; // papa sait pas faire, voir les filles
+ return FALSE;
+}
+
+void CBotInstr::RestoreStateVar(CBotStack* &pile, BOOL bMain)
+{
+ __asm int 3; // 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 int 3;
+
+ 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 int 3;
+ }
+ 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 int 3;
+
+ 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 int 3;
+
+ 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 int 3;
+
+// 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 int 3;
+
+ 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 int 3;
+#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 int 3;
+#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( CBotTypResult& type1, 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
diff --git a/src/CBot/CBot.dsp b/src/CBot/CBot.dsp
new file mode 100644
index 0000000..062660a
--- /dev/null
+++ b/src/CBot/CBot.dsp
@@ -0,0 +1,158 @@
+# Microsoft Developer Studio Project File - Name="CBot" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=CBot - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "CBot.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "CBot.mak" CFG="CBot - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "CBot - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "CBot - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "CBot - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x40c /d "NDEBUG"
+# ADD RSC /l 0x40c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "CBot - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x40c /d "_DEBUG"
+# ADD RSC /l 0x40c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
+# Begin Custom Build
+InputPath=.\Debug\CBot.dll
+SOURCE=$(InputPath)
+
+".\TestCBot\CBot.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ copy .\Debug\CBot.dll .\TestCBot\CBot.dll
+ copy .\Debug\CBot.dll "C:\Program Files\Colobot\CBot.dll"
+ _Copy.bat
+
+# End Custom Build
+
+!ENDIF
+
+# Begin Target
+
+# Name "CBot - Win32 Release"
+# Name "CBot - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\CBot.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBot.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBot.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotClass.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotDll.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotFunction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotIf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotProgram.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotStack.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotToken.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotToken.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotTwoOpExpr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotVar.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CBotWhile.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/src/CBot/CBot.dsw b/src/CBot/CBot.dsw
new file mode 100644
index 0000000..31e2133
--- /dev/null
+++ b/src/CBot/CBot.dsw
@@ -0,0 +1,44 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "CBot"=".\CBot.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "TestCBot"=".\TestCBot\TestCBot.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name CBot
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/src/CBot/CBot.h b/src/CBot/CBot.h
new file mode 100644
index 0000000..bf95c90
--- /dev/null
+++ b/src/CBot/CBot.h
@@ -0,0 +1,1611 @@
+////////////////////////////////////////////////////////////////////
+// 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
+
+/////////////////////////////////////////////////////////////////////
+// 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(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 : 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 : 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 : 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, 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( CBotTypResult& type1, 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 );
+
+#ifdef _DEBUG
+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);
+};
+
+
diff --git a/src/CBot/CBot.lib b/src/CBot/CBot.lib
new file mode 100644
index 0000000..548361f
--- /dev/null
+++ b/src/CBot/CBot.lib
Binary files differ
diff --git a/src/CBot/CBot.opt b/src/CBot/CBot.opt
new file mode 100644
index 0000000..9387019
--- /dev/null
+++ b/src/CBot/CBot.opt
Binary files differ
diff --git a/src/CBot/CBot.plg b/src/CBot/CBot.plg
new file mode 100644
index 0000000..dae6fc9
--- /dev/null
+++ b/src/CBot/CBot.plg
@@ -0,0 +1,61 @@
+--------------------Configuration: CBot - Win32 Release--------------------
+Begining build with project "D:\Robot\projet1\CBot\CBot.dsp", at root.
+Active configuration is Win32 (x86) Dynamic-Link Library (based on Win32 (x86) Dynamic-Link Library)
+
+Project's tools are:
+ "32-bit C/C++ Compiler for 80x86" with flags "/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR"Release/" /Fp"Release/CBot.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c "
+ "OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
+ "Win32 Resource Compiler" with flags "/l 0x40c /fo"Release/CBot.res" /d "NDEBUG" "
+ "Browser Database Maker" with flags "/nologo /o"Release/CBot.bsc" "
+ "COFF Linker for 80x86" with flags "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"Release/CBot.pdb" /machine:I386 /out:"Release/CBot.dll" /implib:"Release/CBot.lib" "
+ "Custom Build" with flags ""
+ "<Component 0xa>" with flags ""
+
+Creating command line "rc.exe /l 0x40c /fo"Release/CBot.res" /d "NDEBUG" "D:\Robot\projet1\CBot\CBot.rc""
+Creating temp file "C:\DOCUME~1\ROUXDA~1\LOCALS~1\Temp\RSP9.tmp" with contents </nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR"Release/" /Fp"Release/CBot.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
+"D:\Robot\projet1\CBot\CBot.cpp"
+"D:\Robot\projet1\CBot\CBotClass.cpp"
+"D:\Robot\projet1\CBot\CBotFunction.cpp"
+"D:\Robot\projet1\CBot\CBotIf.cpp"
+"D:\Robot\projet1\CBot\CBotProgram.cpp"
+"D:\Robot\projet1\CBot\CBotStack.cpp"
+"D:\Robot\projet1\CBot\CBotString.cpp"
+"D:\Robot\projet1\CBot\CBotToken.cpp"
+"D:\Robot\projet1\CBot\CBotTwoOpExpr.cpp"
+"D:\Robot\projet1\CBot\CBotVar.cpp"
+"D:\Robot\projet1\CBot\CBotWhile.cpp"
+>
+Creating command line "cl.exe @C:\DOCUME~1\ROUXDA~1\LOCALS~1\Temp\RSP9.tmp"
+Creating temp file "C:\DOCUME~1\ROUXDA~1\LOCALS~1\Temp\RSPA.tmp" with contents <kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"Release/CBot.pdb" /machine:I386 /out:"Release/CBot.dll" /implib:"Release/CBot.lib"
+.\Release\CBot.obj
+.\Release\CBotClass.obj
+.\Release\CBotFunction.obj
+.\Release\CBotIf.obj
+.\Release\CBotProgram.obj
+.\Release\CBotStack.obj
+.\Release\CBotString.obj
+.\Release\CBotToken.obj
+.\Release\CBotTwoOpExpr.obj
+.\Release\CBotVar.obj
+.\Release\CBotWhile.obj
+.\Release\CBot.res>
+Creating command line "link.exe @C:\DOCUME~1\ROUXDA~1\LOCALS~1\Temp\RSPA.tmp"
+Compiling resources...
+Compiling...
+CBot.cpp
+CBotClass.cpp
+CBotFunction.cpp
+CBotIf.cpp
+CBotProgram.cpp
+CBotStack.cpp
+CBotString.cpp
+CBotToken.cpp
+CBotTwoOpExpr.cpp
+CBotVar.cpp
+CBotWhile.cpp
+Linking...
+ Creating library Release/CBot.lib and object Release/CBot.exp
+
+
+
+CBot.dll - 0 error(s), 0 warning(s)
diff --git a/src/CBot/CBot.rc b/src/CBot/CBot.rc
new file mode 100644
index 0000000..d8b5b74
--- /dev/null
+++ b/src/CBot/CBot.rc
@@ -0,0 +1,279 @@
+//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
new file mode 100644
index 0000000..1d2555a
--- /dev/null
+++ b/src/CBot/CBotAddExpr.cpp
@@ -0,0 +1,128 @@
+///////////////////////////////////////////////////
+// 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
+}
+
+
diff --git a/src/CBot/CBotClass.cpp b/src/CBot/CBotClass.cpp
new file mode 100644
index 0000000..180faf3
--- /dev/null
+++ b/src/CBot/CBotClass.cpp
@@ -0,0 +1,867 @@
+///////////////////////////////////////////////////////////////////////
+// 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;
+}
+
diff --git a/src/CBot/CBotCompExpr.cpp b/src/CBot/CBotCompExpr.cpp
new file mode 100644
index 0000000..99abfb9
--- /dev/null
+++ b/src/CBot/CBotCompExpr.cpp
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////
+// 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
+}
+
diff --git a/src/CBot/CBotDll.h b/src/CBot/CBotDll.h
new file mode 100644
index 0000000..4e0c5b1
--- /dev/null
+++ b/src/CBot/CBotDll.h
@@ -0,0 +1,1185 @@
+////////////////////////////////////////////////////////////////////////
+// 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
+
+
+////////////////////////////////////////////////////////////////////////
+// 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(CBotTypResult& typ);
+ // pour les assignations
+ DllExport
+ CBotTypResult();
+ // pour par défaut
+ DllExport
+ ~CBotTypResult();
+
+ DllExport
+ int GivType(int mode = 0);
+ // rend le type CBotTyp* du résultat
+
+ void SetType(int n);
+ // modifie le type
+
+ DllExport
+ CBotClass* GivClass();
+ // rend le pointeur à la classe (pour les CBotTypClass, CBotTypPointer)
+
+ DllExport
+ int GivLimite();
+ // 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();
+ // rend le type des éléments du tableau (CBotTypArray)
+
+ DllExport
+ BOOL Compare(CBotTypResult& typ);
+ // compare si les types sont compatibles
+ DllExport
+ BOOL Eq(int type);
+ // 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();
+ 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(CBotString& mot, 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
diff --git a/src/CBot/CBotFunction.cpp b/src/CBot/CBotFunction.cpp
new file mode 100644
index 0000000..43dbc83
--- /dev/null
+++ b/src/CBot/CBotFunction.cpp
@@ -0,0 +1,1634 @@
+///////////////////////////////////////////////////////////////////////
+// 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 int 3;
+ }
+ }
+ 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;
+}
diff --git a/src/CBot/CBotIf.cpp b/src/CBot/CBotIf.cpp
new file mode 100644
index 0000000..c0f561a
--- /dev/null
+++ b/src/CBot/CBotIf.cpp
@@ -0,0 +1,145 @@
+///////////////////////////////////////////////////////////////////////
+// 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 !
+ }
+}
+
diff --git a/src/CBot/CBotProgram.cpp b/src/CBot/CBotProgram.cpp
new file mode 100644
index 0000000..ba14f89
--- /dev/null
+++ b/src/CBot/CBotProgram.cpp
@@ -0,0 +1,1102 @@
+//////////////////////////////////////////////////////////////////////
+// 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() ;
+}
+
diff --git a/src/CBot/CBotStack.cpp b/src/CBot/CBotStack.cpp
new file mode 100644
index 0000000..c313a8b
--- /dev/null
+++ b/src/CBot/CBotStack.cpp
@@ -0,0 +1,1460 @@
+//////////////////////////////////////////////////////////////////////
+// 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;
+ for ( int 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 int 3;
+}
+
+CBotStack::~CBotStack()
+{
+ __asm int 3; // 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 int 3;
+#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 int 3;
+ }
+
+ 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 int 3;
+#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;
+}
+
diff --git a/src/CBot/CBotString.cpp b/src/CBot/CBotString.cpp
new file mode 100644
index 0000000..bcbe399
--- /dev/null
+++ b/src/CBot/CBotString.cpp
@@ -0,0 +1,588 @@
+/////////////////////////////////////////////////////
+// gestion de chaine
+// basé sur le CString de MFC
+// mais moins complet
+
+#include "CBot.h"
+
+#include <string.h>
+
+HINSTANCE CBotString::m_hInstance = (HINSTANCE)LoadLibrary("Cbot.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;
+
+ for ( int 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()
+{
+ 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];
+}
+
+
+
diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp
new file mode 100644
index 0000000..4e99cf9
--- /dev/null
+++ b/src/CBot/CBotToken.cpp
@@ -0,0 +1,540 @@
+//////////////////////////////////////////////////////////////////
+// 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(CBotString& mot, 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;
+ }
+ }
+}
+
diff --git a/src/CBot/CBotToken.h b/src/CBot/CBotToken.h
new file mode 100644
index 0000000..2715dd5
--- /dev/null
+++ b/src/CBot/CBotToken.h
@@ -0,0 +1,23 @@
+////////////////////////////////////////////////////////////////////
+// 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, ...);
diff --git a/src/CBot/CBotTwoOpExpr ordre inversé.cpp b/src/CBot/CBotTwoOpExpr ordre inversé.cpp
new file mode 100644
index 0000000..65adcba
--- /dev/null
+++ b/src/CBot/CBotTwoOpExpr ordre inversé.cpp
@@ -0,0 +1,302 @@
+///////////////////////////////////////////////////
+// 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;
+}
+
+// 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 CLASSE (1<<CBotTypClass)
+
+// liste des opérations (précéance)
+static int ListOp[] =
+{
+ BOOLEEN, ID_LOG_OR, 0,
+ BOOLEEN, ID_LOG_AND, 0,
+ BOOLEEN|ENTIER, ID_OR, 0,
+ ENTIER, ID_XOR, 0,
+ BOOLEEN|ENTIER, ID_AND, 0,
+ BOOLEEN|ENTIER|FLOTANT, ID_EQ,
+ BOOLEEN|ENTIER|FLOTANT, ID_NE, 0,
+ ENTIER|FLOTANT, ID_HI,
+ ENTIER|FLOTANT, ID_LO,
+ ENTIER|FLOTANT, ID_HS,
+ ENTIER|FLOTANT, 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,
+ 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 = CBotParExpr::Compile( p, pStk ) ; // expression (...) à gauche
+
+ if (left == NULL) return pStack->Return(NULL, pStk); // si erreur, la transmet
+
+
+ CBotToken* pp = p;
+ int TypeOp = pp->GetType(); // type d'opération
+ p = p->Next(); // saute le token de l'opération
+
+ // cherche des instructions qui peuvent convenir à droite
+
+ CBotInstr* right = (*pOp == 0) ?
+ CBotParExpr::Compile( p, pStk ) : // expression (...) à droite
+ CBotTwoOpExpr::Compile( p, pStk, pOp ); // expression A op B à droite
+
+ if (right == NULL) return pStack->Return(left, pStk); // pas d'opérande à droite ?
+
+ // est-ce qu'on a l'opération prévue entre les deux ?
+ if ( IsInList( TypeOp, pOperations, typemasque ) )
+ {
+ CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // élément pour opération
+ inst->SetToken(pp); // mémorise l'opération
+
+ int type1, type2;
+ type1 = pStk->GetType(); // de quel type le premier opérande ?
+
+ inst->m_rightop = right;
+ {
+ // il y a un second opérande acceptable
+
+ type2 = pStk->GetType(); // de quel type le résultat ?
+
+ // quel est le type du résultat ?
+ int TypeRes = MAX( type1, type2 );
+ if (!TypeOk( TypeRes, typemasque )) type1 = 99; // erreur de type
+
+ switch ( TypeOp )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_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) || // les résultats sont-ils compatibles
+ // cas particulier pour les concaténation de chaînes
+ (TypeOp == ID_ADD && (type1 == CBotTypString || type2 == CBotTypString)))
+ {
+ // si ok, enregistre l'opérande dans l'objet
+ inst->m_leftop = left;
+ // met une variable sur la pile pour avoir le type de résultat
+ pStk->SetVar(new CBotVar(NULL, TypeRes));
+ // 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);
+}
+
+
+
+
+// fait l'opération d'addition ou de soustraction
+
+BOOL CBotTwoOpExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(); // 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->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
+
+ // pour les OU et ET logique, n'évalue pas la seconde expression si pas nécessaire
+ if ( GetTokenType() == ID_LOG_AND && pStk1->GetVal() == FALSE )
+ {
+ CBotVar* res = CBotVar::Create( NULL, CBotTypBoolean);
+ res->SetValInt(FALSE);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmet le résultat
+ }
+ if ( GetTokenType() == ID_LOG_OR && pStk1->GetVal() == TRUE )
+ {
+ CBotVar* res = CBotVar::Create( NULL, CBotTypBoolean);
+ res->SetValInt(TRUE);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmet le résultat
+ }
+
+ // 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
+ // quel est le type du résultat ?
+ int TypeRes = MAX(type1, type2);
+ switch ( GetTokenType() )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_AND:
+ case ID_EQ:
+ case ID_NE:
+ case ID_HI:
+ case ID_LO:
+ case ID_HS:
+ case ID_LS:
+ TypeRes = CBotTypBoolean;
+ }
+ CBotVar* result = CBotVar::Create( NULL, TypeRes);
+ CBotVar* temp = CBotVar::Create( NULL, MAX(type1, type2) );
+
+ int err = 0;
+ // 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;
+ case ID_MUL:
+ result->Mul(pStk1->GetVar(), pStk2->GetVar()); // multiplie
+ break;
+ case ID_DIV:
+ err = result->Div(pStk1->GetVar(), pStk2->GetVar());// divise
+ break;
+ case ID_MODULO:
+ err = result->Modulo(pStk1->GetVar(), pStk2->GetVar());// reste de division
+ break;
+ case ID_LO:
+ temp->Lo(pStk1->GetVar(), pStk2->GetVar()); // inférieur
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_HI:
+ temp->Hi(pStk1->GetVar(), pStk2->GetVar()); // supérieur
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_LS:
+ temp->Ls(pStk1->GetVar(), pStk2->GetVar()); // inférieur ou égal
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_HS:
+ temp->Hs(pStk1->GetVar(), pStk2->GetVar()); // supérieur ou égal
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_EQ:
+ temp->Eq(pStk1->GetVar(), pStk2->GetVar()); // égal
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_NE:
+ temp->Ne(pStk1->GetVar(), pStk2->GetVar()); // différent
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_LOG_AND:
+ case ID_AND:
+ result->And(pStk1->GetVar(), pStk2->GetVar()); // ET
+ break;
+ case ID_LOG_OR:
+ case ID_OR:
+ result->Or(pStk1->GetVar(), pStk2->GetVar()); // OU
+ break;
+ case ID_XOR:
+ result->XOr(pStk1->GetVar(), pStk2->GetVar()); // OU exclusif
+ break;
+ case ID_ASR:
+ result->ASR(pStk1->GetVar(), pStk2->GetVar());
+ break;
+ case ID_SR:
+ result->SR(pStk1->GetVar(), pStk2->GetVar());
+ break;
+ case ID_SL:
+ result->SL(pStk1->GetVar(), pStk2->GetVar());
+ break;
+ default:
+ __asm int 3;
+ }
+ 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(pStk1); // transmet le résultat
+}
+
+
diff --git a/src/CBot/CBotTwoOpExpr.cpp b/src/CBot/CBotTwoOpExpr.cpp
new file mode 100644
index 0000000..bc06873
--- /dev/null
+++ b/src/CBot/CBotTwoOpExpr.cpp
@@ -0,0 +1,552 @@
+///////////////////////////////////////////////////
+// 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 int 3;
+ }
+ 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 \ No newline at end of file
diff --git a/src/CBot/CBotVar.cpp b/src/CBot/CBotVar.cpp
new file mode 100644
index 0000000..bd5e889
--- /dev/null
+++ b/src/CBot/CBotVar.cpp
@@ -0,0 +1,2231 @@
+////////////////////////////////////////////////////////////////////
+// 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, 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 int 3;
+
+ 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 int 3;
+
+ 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 int 3;
+}
+
+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 int 3;
+ 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 int 3;
+ 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 int 3;
+ 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 int 3;
+ return NULL;
+}
+
+CBotVar* CBotVar::GivItemRef(int nIdent)
+{
+ __asm int 3;
+ return NULL;
+}
+
+CBotVar* CBotVar::GivItemList()
+{
+ __asm int 3;
+ return NULL;
+}
+
+CBotVar* CBotVar::GivItem(int row, BOOL bGrow)
+{
+ __asm int 3;
+ 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 int 3;
+ }
+
+ 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 int 3;
+}
+
+CBotVarClass* CBotVar::GivPointer()
+{
+ __asm int 3;
+ return NULL;
+}
+
+// toutes ces fonctions doivent être définies dans les classes filles
+// dérivées de la classe CBotVar
+
+int CBotVar::GivValInt()
+{
+ __asm int 3;
+ return 0;
+}
+
+float CBotVar::GivValFloat()
+{
+ __asm int 3;
+ return 0;
+}
+
+void CBotVar::SetValInt(int c, const char* s)
+{
+ __asm int 3;
+}
+
+void CBotVar::SetValFloat(float c)
+{
+ __asm int 3;
+}
+
+void CBotVar::Mul(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::Power(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+int CBotVar::Div(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return 0;
+}
+
+int CBotVar::Modulo(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return 0;
+}
+
+void CBotVar::Add(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::Sub(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+BOOL CBotVar::Lo(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return FALSE;
+}
+
+BOOL CBotVar::Hi(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return FALSE;
+}
+
+BOOL CBotVar::Ls(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return FALSE;
+}
+
+BOOL CBotVar::Hs(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return FALSE;
+}
+
+BOOL CBotVar::Eq(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return FALSE;
+}
+
+BOOL CBotVar::Ne(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+ return FALSE;
+}
+
+void CBotVar::And(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::Or(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::XOr(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::ASR(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::SR(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::SL(CBotVar* left, CBotVar* right)
+{
+ __asm int 3;
+}
+
+void CBotVar::Neg()
+{
+ __asm int 3;
+}
+
+void CBotVar::Not()
+{
+ __asm int 3;
+}
+
+void CBotVar::Inc()
+{
+ __asm int 3;
+}
+void CBotVar::Dec()
+{
+ __asm int 3;
+}
+
+void CBotVar::Copy(CBotVar* pSrc, BOOL bName)
+{
+ __asm int 3;
+}
+
+void CBotVar::SetValString(const char* p)
+{
+ __asm int 3;
+}
+
+CBotString CBotVar::GivValString()
+{
+ __asm int 3;
+ return CBotString();
+}
+
+void CBotVar::SetClass(CBotClass* pClass)
+{
+ __asm int 3;
+}
+
+CBotClass* CBotVar::GivClass()
+{
+ __asm int 3;
+ 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( left->GivValInt() , 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 int 3;
+
+ 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 int 3; "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() + "( ";
+
+ CBotVarClass* my = this;
+ while ( my != NULL )
+ {
+ CBotVar* pv = my->m_pVar;
+ while ( pv != NULL )
+ {
+ res += pv->GivName() + "=";
+
+ 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 int 3;
+
+ 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 int 3;
+
+ 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 int 3;
+
+ ((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 int 3;
+
+ 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 int 3;
+
+ ((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 int 3;
+
+ 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(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)
+{
+#ifdef _DEBUG
+ if ( m_type == CBotTypPointer ||
+ m_type == CBotTypClass ||
+ m_type == CBotTypIntrinsic )
+
+ if ( m_pClass == NULL ) __asm int 3;
+
+
+ if ( m_type == CBotTypArrayPointer )
+ if ( m_pNext == NULL ) __asm int 3;
+#endif
+ if ( mode == 3 && m_type == CBotTypNullPointer ) return CBotTypPointer;
+ return m_type;
+}
+
+void CBotTypResult::SetType(int n)
+{
+ m_type = n;
+}
+
+CBotClass* CBotTypResult::GivClass()
+{
+ return m_pClass;
+}
+
+CBotTypResult& CBotTypResult::GivTypElem()
+{
+ return *m_pNext;
+}
+
+int CBotTypResult::GivLimite()
+{
+ 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(CBotTypResult& typ)
+{
+ 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)
+{
+ 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
new file mode 100644
index 0000000..7a1ca1f
--- /dev/null
+++ b/src/CBot/CBotWhile.cpp
@@ -0,0 +1,1413 @@
+///////////////////////////////////////////////////////////////////////
+// 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;
+}
+
diff --git a/src/CBot/ClassFILE.cpp b/src/CBot/ClassFILE.cpp
new file mode 100644
index 0000000..21bd39e
--- /dev/null
+++ b/src/CBot/ClassFILE.cpp
@@ -0,0 +1,412 @@
+// 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+"\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
+}
+
diff --git a/src/CBot/Copie de CBot.rc b/src/CBot/Copie de CBot.rc
new file mode 100644
index 0000000..52ef23a
--- /dev/null
+++ b/src/CBot/Copie de CBot.rc
@@ -0,0 +1,184 @@
+//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_ADD "+"
+ ID_SUB "-"
+ ID_MUL "*"
+ ID_DIV "/"
+ ID_OPENPAR "("
+ ID_CLOSEPAR ")"
+ ID_SEP ";"
+ ID_INT "int"
+ ID_ASS "="
+ ID_TRUE "true"
+ ID_FALSE "false"
+ ID_OPBLK "{"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_CLBLK "}"
+ ID_FOR "for"
+ ID_COMMA ","
+ ID_LO "<"
+ ID_HI ">"
+ ID_LS "<="
+ ID_HS ">="
+ ID_EQ "=="
+ ID_NE "!="
+ ID_FLOAT "float"
+ ID_STRING "String"
+ ID_BOOLEAN "boolean"
+ ID_AND "&"
+ ID_XOR "^"
+ ID_OR "|"
+ ID_LOG_AND "&&"
+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 "Instruction non terminée."
+ 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"", un ""do"" ou un ""switch""."
+ TX_NOLABEL "Cette étiquette n'existe pas"
+ TX_NOCASE "Manque une instruction ""case""."
+ TX_BADNUM "Un nombre est attendu."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ TX_DIVZERO "Division par zéro."
+ TX_NOTINIT "Variable non initialisée."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_LOG_OR "||"
+ ID_LOG_NOT "!"
+ ID_NOT "~"
+ 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 ">>"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_INC "++"
+ ID_DEC "--"
+ ID_MODULO "%"
+ ID_ASSMODULO "%="
+ ID_LOGIC "?"
+ ID_DOTS ":"
+ ID_BREAK "break"
+ ID_SWITCH "switch"
+ ID_CASE "case"
+ ID_CONTINUE "continue"
+ ID_TRY "try"
+ ID_CATCH "catch"
+ ID_THROW "throw"
+ ID_FINALLY "finally"
+ ID_DEFAULT "default"
+END
+
+#endif // French (France) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/CBot/Copie de CBotTwoOpExpr.cpp b/src/CBot/Copie de CBotTwoOpExpr.cpp
new file mode 100644
index 0000000..7a95b55
--- /dev/null
+++ b/src/CBot/Copie de CBotTwoOpExpr.cpp
@@ -0,0 +1,295 @@
+///////////////////////////////////////////////////
+// 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;
+}
+
+// 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 CLASSE (1<<CBotTypClass)
+
+// liste des opérations (précéance)
+static int ListOp[] =
+{
+ BOOLEEN, ID_LOG_OR, 0,
+ BOOLEEN, ID_LOG_AND, 0,
+ BOOLEEN|ENTIER, ID_OR, 0,
+ ENTIER, ID_XOR, 0,
+ BOOLEEN|ENTIER, ID_AND, 0,
+ BOOLEEN|ENTIER|FLOTANT, ID_EQ,
+ BOOLEEN|ENTIER|FLOTANT, ID_NE, 0,
+ ENTIER|FLOTANT, ID_HI,
+ ENTIER|FLOTANT, ID_LO,
+ ENTIER|FLOTANT, ID_HS,
+ ENTIER|FLOTANT, 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,
+ 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->GetType();
+ if ( IsInList( TypeOp, pOperations, typemasque ) )
+ {
+ CBotTwoOpExpr* inst = new CBotTwoOpExpr(); // élément pour opération
+ inst->SetToken(p); // mémorise l'opération
+
+ int type1, type2;
+ type1 = pStk->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 = CBotTwoOpExpr::Compile( p, pStk, pOperations )) )
+ // expression (...) à droite
+ {
+ // il y a un second opérande acceptable
+
+ type2 = pStk->GetType(); // de quel type le résultat ?
+
+ // quel est le type du résultat ?
+ int TypeRes = MAX( type1, type2 );
+ if (!TypeOk( TypeRes, typemasque )) type1 = 99; // erreur de type
+
+ switch ( TypeOp )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_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) || // les résultats sont-ils compatibles
+ // cas particulier pour les concaténation de chaînes
+ (TypeOp == ID_ADD && (type1 == CBotTypString || type2 == CBotTypString)))
+ {
+ // si ok, enregistre l'opérande dans l'objet
+ inst->m_leftop = left;
+ // met une variable sur la pile pour avoir le type de résultat
+ pStk->SetVar(new CBotVar(NULL, TypeRes));
+ // 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);
+}
+
+
+
+
+// fait l'opération d'addition ou de soustraction
+
+BOOL CBotTwoOpExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(); // ajoute un élément à la pile
+ // ou le retrouve en cas de reprise
+
+ // 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
+
+ // pour les OU et ET logique, n'évalue pas la seconde expression si pas nécessaire
+ if ( GetTokenType() == ID_LOG_AND && pStk1->GetVal() == FALSE )
+ {
+ CBotVar* res = CBotVar::Create( NULL, CBotTypBoolean);
+ res->SetValInt(FALSE);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmet le résultat
+ }
+ if ( GetTokenType() == ID_LOG_OR && pStk1->GetVal() == TRUE )
+ {
+ CBotVar* res = CBotVar::Create( NULL, CBotTypBoolean);
+ res->SetValInt(TRUE);
+ pStk1->SetVar(res);
+ return pStack->Return(pStk1); // transmet le résultat
+ }
+
+ // 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
+ // quel est le type du résultat ?
+ int TypeRes = MAX(type1, type2);
+ switch ( GetTokenType() )
+ {
+ case ID_LOG_OR:
+ case ID_LOG_AND:
+ case ID_EQ:
+ case ID_NE:
+ case ID_HI:
+ case ID_LO:
+ case ID_HS:
+ case ID_LS:
+ TypeRes = CBotTypBoolean;
+ }
+ CBotVar* result = CBotVar::Create( NULL, TypeRes);
+ CBotVar* temp = CBotVar::Create( NULL, MAX(type1, type2) );
+
+ int err = 0;
+ // 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;
+ case ID_MUL:
+ result->Mul(pStk1->GetVar(), pStk2->GetVar()); // multiplie
+ break;
+ case ID_DIV:
+ err = result->Div(pStk1->GetVar(), pStk2->GetVar());// divise
+ break;
+ case ID_MODULO:
+ err = result->Modulo(pStk1->GetVar(), pStk2->GetVar());// reste de division
+ break;
+ case ID_LO:
+ temp->Lo(pStk1->GetVar(), pStk2->GetVar()); // inférieur
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_HI:
+ temp->Hi(pStk1->GetVar(), pStk2->GetVar()); // supérieur
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_LS:
+ temp->Ls(pStk1->GetVar(), pStk2->GetVar()); // inférieur ou égal
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_HS:
+ temp->Hs(pStk1->GetVar(), pStk2->GetVar()); // supérieur ou égal
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_EQ:
+ temp->Eq(pStk1->GetVar(), pStk2->GetVar()); // égal
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_NE:
+ temp->Ne(pStk1->GetVar(), pStk2->GetVar()); // différent
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ break;
+ case ID_LOG_AND:
+ case ID_AND:
+ result->And(pStk1->GetVar(), pStk2->GetVar()); // ET
+ break;
+ case ID_LOG_OR:
+ case ID_OR:
+ result->Or(pStk1->GetVar(), pStk2->GetVar()); // OU
+ break;
+ case ID_XOR:
+ result->XOr(pStk1->GetVar(), pStk2->GetVar()); // OU exclusif
+ break;
+ case ID_ASR:
+ result->ASR(pStk1->GetVar(), pStk2->GetVar());
+ break;
+ case ID_SR:
+ result->SR(pStk1->GetVar(), pStk2->GetVar());
+ break;
+ case ID_SL:
+ result->SL(pStk1->GetVar(), pStk2->GetVar());
+ break;
+ default:
+ __asm int 3;
+ }
+ 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(pStk1); // transmet le résultat
+}
+
+
diff --git a/src/CBot/StringFunctions.cpp b/src/CBot/StringFunctions.cpp
new file mode 100644
index 0000000..803ffd9
--- /dev/null
+++ b/src/CBot/StringFunctions.cpp
@@ -0,0 +1,420 @@
+// 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 );
+}
diff --git a/src/CBot/TestCBot/B.txt b/src/CBot/TestCBot/B.txt
new file mode 100644
index 0000000..53715f8
--- /dev/null
+++ b/src/CBot/TestCBot/B.txt
@@ -0,0 +1,18 @@
+
+ float [ ] TEST2 ( int [ ] param )
+ {
+ float [ ] z;
+ for ( int i = 0 ; i < sizeof( param ) ; i++ ) try { z [i] = param [i] / 3; }
+ return z;
+ }
+
+extern public void T()
+{
+ int a [4];
+ for ( int i = 0 ; i < 3 ; i++ ) a[i] = 4*i;
+ a [2] = 22;
+
+ float [] b ;
+ b = TEST2 ( a ) ;
+ show ( a, b );
+}
diff --git a/src/CBot/TestCBot/BUG2.txt b/src/CBot/TestCBot/BUG2.txt
new file mode 100644
index 0000000..44de05a
--- /dev/null
+++ b/src/CBot/TestCBot/BUG2.txt
@@ -0,0 +1,107 @@
+object object :: TT ( int n )
+{
+ object XX = radar();
+ if ( n == 0 ) return null;
+
+ while ( null == XX ) XX = radar();
+ return XX;
+}
+
+extern void object::Attack( )
+{
+ show ( TT ( 0 ) ) ;
+ show ( TT ( 1 ) ) ;
+ return;
+
+ int list[];
+ int i;
+ object p;
+ float dist, prox;
+ point dest;
+ boolean advance = true;
+
+ TEST(0); // ne stoppe pas si erreur
+// while ( F () != 0 ) F(1);
+
+ i = 0;
+ list[i++] = WingedGrabber;
+ list[i++] = TrackedGrabber;
+ list[i++] = WheeledGrabber;
+ list[i++] = LeggedGrabber;
+ list[i++] = WingedShooter;
+ list[i++] = TrackedShooter;
+ list[i++] = WheeledShooter;
+ list[i++] = LeggedShooter;
+ list[i++] = WingedOrgaShooter;
+ list[i++] = TrackedOrgaShooter;
+ list[i++] = WheeledOrgaShooter;
+ list[i++] = LeggedOrgaShooter;
+ list[i++] = WingedSniffer;
+ list[i++] = TrackedSniffer;
+ list[i++] = WheeledSniffer;
+ list[i++] = LeggedSniffer;
+ list[i++] = Thumper;
+ list[i++] = PhazerShooter;
+ list[i++] = Recycler;
+ list[i++] = Shielder;
+ list[i++] = Subber;
+ list[i++] = Me;
+ list[i++] = 3333;
+ list[i++] = 3334;
+ list[i++] = 3335;
+ list[i++] = 3336;
+ list[i++] = 3337;
+ list[i++] = 3338;
+ list[i++] = 3339;
+ list[i++] = 3331;
+ list[i++] = 3332;
+ list[i++] = 3330;
+ list[i++] = 1111;
+ list[i++] = 1112;
+
+ F(F(0));
+
+ while ( true )
+ {
+ p = radar(list, 0, 360, 0, 1000);
+ if ( p == null )
+ {
+ F(2);
+ }
+ else
+ {
+ dist = F(p.position, position);
+ if ( dist <= 40 && !advance )
+ {
+ fire(p.position);
+ advance = true;
+ }
+ else
+ {
+//? if ( RetBaseDistance() > 20 )
+ {
+ prox = dist-(5+F()*5);
+ if ( prox < 5 ) prox = 5;
+ dest.x = (position.x-p.position.x)*prox/dist + p.position.x;
+ dest.y = (position.y-p.position.y)*prox/dist + p.position.y;
+ dest.z = (position.z-p.position.z)*prox/dist + p.position.z;
+ goto(dest);
+ advance = false;
+ }
+ }
+ }
+ }
+}
+
+// Calcule la distance jusqu'à la base.
+
+float object::RetBaseDistance()
+{
+ object p;
+ float dist;
+
+ p = radar(4444, 0, 360, 0, 1000);
+ if ( p == null ) return 1000;
+ dist = F(p.position, position);
+ return dist;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/CBotConsoleDlg.cpp b/src/CBot/TestCBot/CBotConsoleDlg.cpp
new file mode 100644
index 0000000..5f29e86
--- /dev/null
+++ b/src/CBot/TestCBot/CBotConsoleDlg.cpp
@@ -0,0 +1,205 @@
+// CBotConsoleDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "TestCBot.h"
+#include "CBotConsoleDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotConsoleDlg dialog
+
+
+CBotConsoleDlg::CBotConsoleDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CBotConsoleDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CBotConsoleDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+ m_pProg = NULL;
+ m_threadinfo.m_bRun = FALSE;
+ m_code = 0;
+}
+
+
+void CBotConsoleDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CBotConsoleDlg)
+ DDX_Control(pDX, IDOK, m_cOK);
+ DDX_Control(pDX, IDC_EDIT2, m_Edit2);
+ DDX_Control(pDX, IDC_EDIT1, m_Edit1);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CBotConsoleDlg, CDialog)
+ //{{AFX_MSG_MAP(CBotConsoleDlg)
+ ON_MESSAGE(WM_ENDPROG, EndProg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotConsoleDlg message handlers
+
+UINT ThreadProc(ThreadInfo *info)
+{
+ CTime t0 = CTime::GetCurrentTime();
+ int Cpt = 0;
+
+ info->m_pProg->Start("LaCommande");
+ while ( !info->m_bStop && !info->m_pProg->Run() )
+ {
+#if 0
+ const char* FunctionName;
+ const char* FN;
+ int start, end;
+
+ info->m_pProg->GetRunPos(FunctionName, start, end);
+
+ if ( FunctionName != NULL )
+ {
+ info->m_pEditx->SetSel(start, end);
+
+ char buffer[200];
+ sprintf( buffer, "step %s, %d, %d",FunctionName, start, end);
+ AfxMessageBox( buffer );
+
+ int level = 0;
+ do
+ {
+ CBotVar* t = info->m_pProg->GivStackVars(FN, level--);
+ if ( FN != FunctionName ) break;
+ if ( t != NULL )
+ {
+ CString s ;
+ while ( t != NULL )
+ {
+ if (s.IsEmpty()) s+= "Stack -> ";
+ else s+= " , ";
+ s += t->GivValString();
+ t = t->GivNext();
+ }
+ AfxMessageBox(s);
+ }
+ } while (TRUE);
+ }
+#endif
+ Cpt++;
+ if ( Cpt%50 == 0 ) info->m_pEdit1->ReplaceSel(".");
+ }
+
+ if ( info->m_bStop )
+ {
+ info->m_pEdit1->ReplaceSel("\r\nInterrompu\r\n");
+ }
+ else if (info->m_pProg->GivError() == 0)
+ {
+ CTime t = CTime::GetCurrentTime();
+ CTimeSpan ts = t - t0;
+
+ char buffer[200];
+ sprintf( buffer, "\r\nExécution terminée en %d secondes.\r\nInterrompue %d fois.\r\n",
+ ts.GetTotalSeconds(), Cpt);
+
+ info->m_pEdit1->ReplaceSel(buffer);
+ }
+
+ info->m_pWndMessage->SendMessage(WM_ENDPROG, 0, 0) ;
+ return 0 ;
+}
+
+LONG CBotConsoleDlg::EndProg(UINT wparam, LONG lparam)
+{
+ m_threadinfo.m_bRun = FALSE;
+
+ if (m_pProg->GetError(m_code, m_start, m_end))
+ {
+ CBotString TextError;
+ TextError = CBotProgram::GivErrorText(m_code);
+ AfxMessageBox(TextError);
+ CDialog::OnCancel();
+ return 1;
+ }
+ delete m_pProg;
+ m_pProg = NULL;
+
+ m_Edit2.EnableWindow(TRUE);
+ m_cOK.EnableWindow(TRUE);
+
+ m_Edit2.SetWindowText("");
+ m_Edit2.SetFocus();
+ return 0 ;
+}
+
+void CBotConsoleDlg::OnOK()
+{
+ CTestCBotApp* pApp = (CTestCBotApp*)AfxGetApp();
+ pApp->m_pConsole = &m_Edit1;
+ m_code = 0;
+
+ CString Commande;
+ m_Edit2.GetWindowText(Commande);
+
+ CString s = "void LaCommande() { " + Commande + " ;}";
+ m_pProg = new CBotProgram();
+ CBotStringArray liste;
+ m_pProg->Compile(s, liste);
+
+ int err, start, end;
+ if ( m_pProg->GetError(err, start, end) )
+ {
+ CBotString TextError;
+ TextError = CBotProgram::GivErrorText(err);
+ AfxMessageBox(TextError);
+ m_Edit2.SetSel(start-20, end-20);
+ return;
+ }
+
+ m_Edit1.ReplaceSel("\r\n" + Commande + " ->\r\n");
+
+ m_Edit2.SetWindowText("");
+ m_Edit1.SetFocus();
+ m_Edit2.EnableWindow(FALSE);
+ m_cOK.EnableWindow(FALSE);
+
+ // lance un processus paralèle pour l'exécution
+ m_threadinfo.m_pWndMessage = this ;
+
+ m_threadinfo.m_pEdit1 = &m_Edit1;
+ m_threadinfo.m_pEditx = m_pEditx;
+ m_threadinfo.m_pProg = m_pProg;
+ m_threadinfo.m_bStop = FALSE;
+ m_threadinfo.m_bRun = TRUE;
+
+ AfxBeginThread((AFX_THREADPROC)ThreadProc, &m_threadinfo) ;
+}
+
+void CBotConsoleDlg::OnCancel()
+{
+ if (!m_threadinfo.m_bRun) CDialog::OnCancel();
+ m_threadinfo.m_bStop = TRUE ;
+}
+
+
+BOOL CBotConsoleDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ m_Edit1.ReplaceSel("Les fonctions suivantes sont disponibles:\r\n");
+ for ( int i = 0; i < m_pListe->GivSize(); i++ )
+ {
+ CBotString x = (*m_pListe)[i] + "\r\n";
+ m_Edit1.ReplaceSel(x);
+ }
+ m_Edit1.ReplaceSel("Entrez une commande ci-dessous.\r\n\r\n");
+
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
diff --git a/src/CBot/TestCBot/CBotConsoleDlg.h b/src/CBot/TestCBot/CBotConsoleDlg.h
new file mode 100644
index 0000000..bae9793
--- /dev/null
+++ b/src/CBot/TestCBot/CBotConsoleDlg.h
@@ -0,0 +1,69 @@
+#if !defined(AFX_BOTCONSOLEDLG_H__A11450A2_8E09_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_BOTCONSOLEDLG_H__A11450A2_8E09_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// CBotConsoleDlg.h : header file
+//
+
+struct ThreadInfo
+{
+ CEdit* m_pEdit1 ;
+ CEdit* m_pEditx ;
+ CBotProgram* m_pProg;
+ CWnd* m_pWndMessage;
+ BOOL m_bStop;
+ BOOL m_bRun;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotConsoleDlg dialog
+
+class CBotConsoleDlg : public CDialog
+{
+// Construction
+public:
+ CBotConsoleDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CBotConsoleDlg)
+ enum { IDD = IDD_CONSOLE };
+ CButton m_cOK;
+ CEdit m_Edit2;
+ CEdit m_Edit1;
+ //}}AFX_DATA
+
+ CBotProgram* m_pProg;
+ ThreadInfo m_threadinfo;
+
+ CBotStringArray*
+ m_pListe;
+ int m_code, m_start, m_end;
+ CEdit* m_pEditx;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CBotConsoleDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CBotConsoleDlg)
+ virtual void OnOK();
+ virtual void OnCancel();
+ virtual BOOL OnInitDialog();
+ afx_msg LONG EndProg(UINT wparam, LONG lparam) ;
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_BOTCONSOLEDLG_H__A11450A2_8E09_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/ChildFrm.cpp b/src/CBot/TestCBot/ChildFrm.cpp
new file mode 100644
index 0000000..9005c72
--- /dev/null
+++ b/src/CBot/TestCBot/ChildFrm.cpp
@@ -0,0 +1,58 @@
+// ChildFrm.cpp : implementation of the CChildFrame class
+//
+
+#include "stdafx.h"
+#include "TestCBot.h"
+
+#include "ChildFrm.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CChildFrame
+
+IMPLEMENT_DYNCREATE(CChildFrame, CMDIChildWnd)
+
+BEGIN_MESSAGE_MAP(CChildFrame, CMDIChildWnd)
+ //{{AFX_MSG_MAP(CChildFrame)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CChildFrame construction/destruction
+
+CChildFrame::CChildFrame()
+{
+}
+
+CChildFrame::~CChildFrame()
+{
+}
+
+BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
+{
+ return CMDIChildWnd::PreCreateWindow(cs);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CChildFrame diagnostics
+
+#ifdef _DEBUG
+void CChildFrame::AssertValid() const
+{
+ CMDIChildWnd::AssertValid();
+}
+
+void CChildFrame::Dump(CDumpContext& dc) const
+{
+ CMDIChildWnd::Dump(dc);
+}
+
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CChildFrame message handlers
diff --git a/src/CBot/TestCBot/ChildFrm.h b/src/CBot/TestCBot/ChildFrm.h
new file mode 100644
index 0000000..ebcbeb2
--- /dev/null
+++ b/src/CBot/TestCBot/ChildFrm.h
@@ -0,0 +1,50 @@
+// ChildFrm.h : interface of the CChildFrame class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_CHILDFRM_H__4D1BB909_8E74_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_CHILDFRM_H__4D1BB909_8E74_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CChildFrame : public CMDIChildWnd
+{
+ DECLARE_DYNCREATE(CChildFrame)
+public:
+ CChildFrame();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CChildFrame)
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CChildFrame();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CChildFrame)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_CHILDFRM_H__4D1BB909_8E74_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/Deleted.txt b/src/CBot/TestCBot/Deleted.txt
new file mode 100644
index 0000000..469a624
--- /dev/null
+++ b/src/CBot/TestCBot/Deleted.txt
@@ -0,0 +1,23 @@
+public extern void object :: ESSAI()
+{
+ while(true)
+ {
+ if ( true )
+ {
+ goto(12);
+ break;
+ }
+ }
+ object x = null ;
+
+ while ( x == null ) x = radar();
+
+ show ( x.position ) ;
+
+ TEST(5, x);
+
+ if ( x == null ) show ( "DELETED" );
+
+ show ( x.position ) ;
+
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/MaClass.txt b/src/CBot/TestCBot/MaClass.txt
new file mode 100644
index 0000000..ac472b4
--- /dev/null
+++ b/src/CBot/TestCBot/MaClass.txt
@@ -0,0 +1,16 @@
+
+class MaClass
+{
+ int a = 1 ;
+ MaClass pointeur ;
+ MaClass next = null ;
+ CPoint autre = new CPoint( 1 , 1 ) ;
+}
+
+extern public void Test ( )
+{
+ MaClass x () ;
+ x.next = new MaClass ( ) ;
+ println ( x ) ;
+}
+
diff --git a/src/CBot/TestCBot/MainFrm.cpp b/src/CBot/TestCBot/MainFrm.cpp
new file mode 100644
index 0000000..e151cce
--- /dev/null
+++ b/src/CBot/TestCBot/MainFrm.cpp
@@ -0,0 +1,100 @@
+// MainFrm.cpp : implementation of the CMainFrame class
+//
+
+#include "stdafx.h"
+#include "TestCBot.h"
+
+#include "MainFrm.h"
+#include "TestCBotDoc.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame
+
+IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
+
+BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
+ //{{AFX_MSG_MAP(CMainFrame)
+ ON_WM_CREATE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+static UINT indicators[] =
+{
+ ID_SEPARATOR, // status line indicator
+ ID_INDICATOR_CAPS,
+ ID_INDICATOR_NUM,
+ ID_INDICATOR_SCRL,
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame construction/destruction
+
+CMainFrame::CMainFrame()
+{
+}
+
+CMainFrame::~CMainFrame()
+{
+}
+
+int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+ if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
+ return -1;
+
+ if (!m_wndToolBar.Create(this) ||
+ !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
+ {
+ TRACE0("Failed to create toolbar\n");
+ return -1; // fail to create
+ }
+
+ if (!m_wndStatusBar.Create(this) ||
+ !m_wndStatusBar.SetIndicators(indicators,
+ sizeof(indicators)/sizeof(UINT)))
+ {
+ TRACE0("Failed to create status bar\n");
+ return -1; // fail to create
+ }
+
+ m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
+ CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
+
+ m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
+ EnableDocking(CBRS_ALIGN_ANY);
+ DockControlBar(&m_wndToolBar);
+
+ return 0;
+}
+
+BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
+{
+ return CMDIFrameWnd::PreCreateWindow(cs);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame diagnostics
+
+#ifdef _DEBUG
+void CMainFrame::AssertValid() const
+{
+ CMDIFrameWnd::AssertValid();
+}
+
+void CMainFrame::Dump(CDumpContext& dc) const
+{
+ CMDIFrameWnd::Dump(dc);
+}
+
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame message handlers
+
+
diff --git a/src/CBot/TestCBot/MainFrm.h b/src/CBot/TestCBot/MainFrm.h
new file mode 100644
index 0000000..b9d68db
--- /dev/null
+++ b/src/CBot/TestCBot/MainFrm.h
@@ -0,0 +1,56 @@
+// MainFrm.h : interface of the CMainFrame class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_MAINFRM_H__4D1BB907_8E74_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_MAINFRM_H__4D1BB907_8E74_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CMainFrame : public CMDIFrameWnd
+{
+ DECLARE_DYNAMIC(CMainFrame)
+public:
+ CMainFrame();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMainFrame)
+ public:
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CMainFrame();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected: // control bar embedded members
+ CStatusBar m_wndStatusBar;
+ CToolBar m_wndToolBar;
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CMainFrame)
+ afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MAINFRM_H__4D1BB907_8E74_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/Mc2.txt b/src/CBot/TestCBot/Mc2.txt
new file mode 100644
index 0000000..172c259
--- /dev/null
+++ b/src/CBot/TestCBot/Mc2.txt
@@ -0,0 +1,4 @@
+class MaClass
+{
+ int t = 12;
+}
diff --git a/src/CBot/TestCBot/Mon fichier.txt b/src/CBot/TestCBot/Mon fichier.txt
new file mode 100644
index 0000000..6b35bf8
--- /dev/null
+++ b/src/CBot/TestCBot/Mon fichier.txt
@@ -0,0 +1,2 @@
+Voici encore du texte
+et une seconde ligne
diff --git a/src/CBot/TestCBot/Nop.txt b/src/CBot/TestCBot/Nop.txt
new file mode 100644
index 0000000..6a66f6f
--- /dev/null
+++ b/src/CBot/TestCBot/Nop.txt
@@ -0,0 +1,4 @@
+public extern void Nop()
+{
+ while ( true ) {}
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/POS.txt b/src/CBot/TestCBot/POS.txt
new file mode 100644
index 0000000..688e4fb
--- /dev/null
+++ b/src/CBot/TestCBot/POS.txt
@@ -0,0 +1,14 @@
+void object :: T ( )
+{
+ show ( position ) ;
+}
+
+public extern void object :: POS()
+{
+ for ( int i = 0; i < 10 ; i++ )
+ {
+ if ( i == 2 ) TEST ( 12 ) ;
+// show ( position );
+ T ( ) ;
+ }
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/PerformDlg.cpp b/src/CBot/TestCBot/PerformDlg.cpp
new file mode 100644
index 0000000..a541f0b
--- /dev/null
+++ b/src/CBot/TestCBot/PerformDlg.cpp
@@ -0,0 +1,161 @@
+// PerformDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "testcbot.h"
+#include "PerformDlg.h"
+
+//#include <stdio.h>
+#include <sys/timeb.h>
+//#include <time.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPerformDlg dialog
+
+
+CPerformDlg::CPerformDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CPerformDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CPerformDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+
+void CPerformDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CPerformDlg)
+ DDX_Control(pDX, IDC_EDIT3, m_Edit3);
+ DDX_Control(pDX, IDC_EDIT1, m_Edit1);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CPerformDlg, CDialog)
+ //{{AFX_MSG_MAP(CPerformDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPerformDlg message handlers
+
+/* Pauses for a specified number of milliseconds. */
+
+/*void sleep( double waitseconds )
+{
+ clock_t wait = (clock_t)(waitseconds * CLOCKS_PER_SEC);
+ clock_t goal;
+ goal = wait + clock();
+ while( goal > clock() )
+ ;
+}*/
+
+void sleep( clock_t wait )
+{
+ clock_t goal;
+ goal = wait + clock();
+ while( goal > clock() )
+ TRACE("%d \n", clock() );
+}
+
+void sleep2( clock_t wait )
+{
+ struct _timeb timebuffer;
+ char *timeline;
+
+ _ftime( &timebuffer );
+ timeline = ctime( & ( timebuffer.time ) );
+ long x = timebuffer.millitm;
+ while( x == timebuffer.millitm ) _ftime( &timebuffer );
+}
+
+#define NBLP 20
+
+UINT ThreadProc2(ThreadInfo2 *info)
+{
+ int lp = NBLP;
+ int i;
+ clock_t start = clock();
+
+ while ( !info->m_bStop )
+ {
+ for ( i = 0; i< info->m_nbscripts; i++ )
+ {
+ info->m_pProg[i]->Run();
+ }
+
+#ifdef _DEBUG
+ sleep2( 1 );
+#else
+ CString s ( "xx" );
+ for ( long z = 0x5000; z>0; z-- ) s = s.Left(1);
+#endif
+ if ( --lp == 0 )
+ {
+ clock_t finish = clock();
+ double n = (double)NBLP / (double)(finish-start) * CLOCKS_PER_SEC;
+ char b[30];
+ sprintf( b, "%f", n);
+ info->m_pEdit->SetWindowText(b);
+
+ n = n * 1100 / 200; // performances
+ sprintf( b, "%f", n);
+ info->m_pEdit3->SetWindowText(b);
+ start = finish;
+ lp = NBLP;
+ }
+ }
+
+ return 0 ;
+}
+
+BOOL CPerformDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+
+ CBotStringArray liste;
+ // crée les scripts pour les tests
+ for ( int i = 0; i < 100; i++ )
+ {
+ m_pProg[i] = new CBotProgram();
+ m_pProg[i]->Compile(m_Script, liste);
+ m_pProg[i]->Start(liste[0]);
+ }
+
+ // lance un processus paralèle pour l'exécution
+// m_threadinfo2.m_pWndMessage = this ;
+
+ m_threadinfo2.m_pEdit = &m_Edit1;
+ m_threadinfo2.m_pEdit3 = &m_Edit3;
+ m_threadinfo2.m_pProg = m_pProg;
+ m_threadinfo2.m_bStop = FALSE;
+ m_threadinfo2.m_nbscripts = 30;
+
+
+ AfxBeginThread((AFX_THREADPROC)ThreadProc2, &m_threadinfo2) ;
+ // TODO: Add extra initialization here
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CPerformDlg::OnCancel()
+{
+ m_threadinfo2.m_bStop = TRUE;
+ sleep ( 2000 );
+
+ CDialog::OnCancel();
+
+ for ( int i = 0; i < 100; i++ )
+ {
+ delete m_pProg[i];
+ }
+}
diff --git a/src/CBot/TestCBot/PerformDlg.h b/src/CBot/TestCBot/PerformDlg.h
new file mode 100644
index 0000000..77ca71a
--- /dev/null
+++ b/src/CBot/TestCBot/PerformDlg.h
@@ -0,0 +1,62 @@
+#if !defined(AFX_PERFORMDLG_H__EAF2D560_97D8_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_PERFORMDLG_H__EAF2D560_97D8_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// PerformDlg.h : header file
+//
+
+struct ThreadInfo2
+{
+ CEdit* m_pEdit ;
+ CEdit* m_pEdit3 ;
+
+ CBotProgram** m_pProg;
+ BOOL m_bStop;
+ int m_nbscripts;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CPerformDlg dialog
+
+class CPerformDlg : public CDialog
+{
+// Construction
+public:
+ CPerformDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CPerformDlg)
+ enum { IDD = IDD_DIALOG1 };
+ CEdit m_Edit3;
+ CEdit m_Edit1;
+ //}}AFX_DATA
+
+ CBotProgram* m_pProg[100];
+ ThreadInfo2 m_threadinfo2;
+ CString m_Script;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CPerformDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CPerformDlg)
+ virtual BOOL OnInitDialog();
+ virtual void OnCancel();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_PERFORMDLG_H__EAF2D560_97D8_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/Routines.cpp b/src/CBot/TestCBot/Routines.cpp
new file mode 100644
index 0000000..cd3a32b
--- /dev/null
+++ b/src/CBot/TestCBot/Routines.cpp
@@ -0,0 +1,139 @@
+
+
+////////////////////////////////////////////////////////////////////
+// routine show()
+// utilisable depuis le programme écrit en CBot
+
+// exécution
+BOOL rShow( CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser )
+{
+ CString s;
+
+ while ( pVar != NULL )
+ {
+ CString ss;
+ ss.LoadString( TX_TYPENAMES + pVar->GivType() );
+ s += ss + " ";
+
+ ss = pVar->GivName();
+ if (ss.IsEmpty()) ss = "<sans nom>";
+ s += ss + " = ";
+
+ s += pVar->GivValString();
+ s += "\n";
+ pVar = pVar->GivNext();
+ }
+
+ AfxMessageBox(s, MB_OK|MB_ICONINFORMATION);
+
+ return TRUE; // pas d'interruption
+}
+
+CBotTypResult cShow( CBotVar* &pVar, void* pUser)
+{
+ if ( pVar == NULL ) return CBotTypResult(5028);
+ return CBotTypResult(0); // tous paramètres acceptés, void en retour
+}
+
+
+////////////////////////////////////////////////////////////////////
+// routine print()
+// utilisable depuis le programme écrit en CBot
+
+// exécution
+BOOL rPrintLn( CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser )
+{
+ CString s;
+
+ CTestCBotApp* pApp = (CTestCBotApp*)AfxGetApp();
+ CEdit* pEdit = pApp->m_pConsole;
+
+ if (pEdit == NULL) return TRUE;
+ pEdit->GetWindowText(s);
+
+ while ( pVar != NULL )
+ {
+ if ( !s.IsEmpty() ) s += " ";
+ s += pVar->GivValString();
+ pVar = pVar->GivNext();
+ }
+ s += "\r\n";
+
+ pEdit->SetWindowText(s);
+ pEdit->SetSel(s.GetLength(), s.GetLength());
+ pEdit->SetFocus();
+ return TRUE; // pas d'interruption
+}
+
+BOOL rPrint( CBotVar* pVar, CBotVar* pResult, int& Exception, void* pUser )
+{
+ CString s;
+
+ CTestCBotApp* pApp = (CTestCBotApp*)AfxGetApp();
+ CEdit* pEdit = pApp->m_pConsole;
+
+ if (pEdit == NULL) return TRUE;
+ pEdit->GetWindowText(s);
+
+ while ( pVar != NULL )
+ {
+ if ( !s.IsEmpty() ) s += " ";
+ s += pVar->GivValString();
+ pVar = pVar->GivNext();
+ }
+
+ pEdit->SetWindowText(s);
+ pEdit->SetSel(s.GetLength(), s.GetLength());
+ pEdit->SetFocus();
+ return TRUE; // pas d'interruption
+}
+
+CBotTypResult cPrint( CBotVar* &pVar, void* pUser)
+{
+ return CBotTypResult(0); // tous paramètres acceptés, un entier en retour
+}
+
+
+//////////////////////////////////////////////////////////////////
+// class CPoint pour essayer
+
+// exécution
+BOOL rCPoint( CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ CString s;
+
+ if ( pVar == NULL )return TRUE; // constructeur sans paramètres est ok
+
+ CBotVar* pX = pThis->GivItem("x");
+ pX->SetValFloat( pVar->GivValFloat() );
+ pVar = pVar->GivNext();
+
+ CBotVar* pY = pThis->GivItem("y");
+ pY->SetValFloat( pVar->GivValFloat() );
+ pVar = pVar->GivNext();
+
+ return TRUE; // pas d'interruption
+}
+
+CBotTypResult cCPoint( CBotVar* pThis, CBotVar* &pVar)
+{
+ // ok si aucun paramètres !
+ if ( pVar == NULL ) return CBotTypResult(0);
+
+ // paramètre de type numérique svp
+ if ( pVar->GivType() > CBotTypDouble ) return CBotTypResult(5011);
+ pVar = pVar->GivNext();
+
+ // il doit y avoir un second paramètre
+ if ( pVar == NULL ) return 5028;
+ // également de type numérique
+ if ( pVar->GivType() > CBotTypDouble )return CBotTypResult(5011);
+ pVar = pVar->GivNext();
+
+ // et pas plus de 2 paramètres svp
+ if ( pVar != NULL ) return CBotTypResult(5026);
+
+ return CBotTypResult(0); // cette fonction retourne void
+}
+
+
diff --git a/src/CBot/TestCBot/StdAfx.cpp b/src/CBot/TestCBot/StdAfx.cpp
new file mode 100644
index 0000000..b1dde8d
--- /dev/null
+++ b/src/CBot/TestCBot/StdAfx.cpp
@@ -0,0 +1,6 @@
+// stdafx.cpp : source file that includes just the standard includes
+// TestCBot.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/src/CBot/TestCBot/StdAfx.h b/src/CBot/TestCBot/StdAfx.h
new file mode 100644
index 0000000..7be8c40
--- /dev/null
+++ b/src/CBot/TestCBot/StdAfx.h
@@ -0,0 +1,26 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__4D1BB905_8E74_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_STDAFX_H__4D1BB905_8E74_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+#include <afxdisp.h> // MFC OLE automation classes
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__4D1BB905_8E74_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/T.txt b/src/CBot/TestCBot/T.txt
new file mode 100644
index 0000000..50a792b
--- /dev/null
+++ b/src/CBot/TestCBot/T.txt
@@ -0,0 +1,4 @@
+public extern int T ( float n )
+{
+ return n * 1.1;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/TESTALL.txt b/src/CBot/TestCBot/TESTALL.txt
new file mode 100644
index 0000000..82247a0
--- /dev/null
+++ b/src/CBot/TestCBot/TESTALL.txt
@@ -0,0 +1,161 @@
+int T ( int z )
+{
+ return 45 + z ;
+}
+
+class toto
+{
+ int val = 3 ;
+ int x = 3 * 3 ;
+ void toto( int n )
+ { val = n + 3 ; }
+ int retval ( int param )
+ { int r = val + param + x ;
+ val = param ;
+ return r ; }
+}
+
+public extern void object :: Chose( )
+{
+ int z [ 6 ];
+ for ( int i = 0 ; i < 6 ; ) z [ i++ ] = 3 - i ;
+ show ( z ) ;
+ return;
+
+ // test des tableaux
+ int [ ] a [ 3 ] ;
+// a = null;
+ if ( a == null ) show ( "NULL" );
+
+ a [ 2 / 2 ] [ 2 ]= 5 ;
+ int [ ] b ; b = a [1] ;
+ b [ 0 ] = -4;
+ a [ 4 / 2 ] [ 1 ]= 1 ;
+ show ( a , b ) ;
+ return ;
+ {
+ toto chose = new toto (5 ) ;
+ toto truc = chose ;
+ show ( chose, chose.retval( 100 ) ,
+ truc, truc.retval (40 ) ) ;
+
+ return;
+ }
+ {
+ point A = new
+ point ( 4 * 4 , 2 ) ;
+ show ( A ) ;
+ return;
+ }
+ {
+ show ( T ( 1 ) , T ( 3.7 ) ) ;
+ return;
+ }
+
+ {
+ point A ( 3, 4 ) ,
+ B = A ;
+
+ int n = -4;
+ show ( n );
+
+ show ( A, B ) ;
+
+ boolean a = false;
+ boolean b = a or true;
+ if ( not a and b ) ;
+ return;
+ }
+ {
+ // test try
+ float x = nan ; int z = 0 ;
+ try {
+// throw ( 3 * 4 + 33 ) ;
+ int zz ; goto ( 12 ) ; z = 1 ; z = 0 / 0 ; z = 2 ;
+ }
+ catch ( 45 + 0 * 6000 )
+ {
+ show( "Exception 6000", z ) ;
+ }
+ catch ( x == 0 ) { show( "x nul" ) ; }
+ finally { show ( "fini" ) ; }
+ show ( "continue" );
+ return;
+ }
+ {
+ // test des if
+ int a = 3;
+ if ( a == 3 ) show ( "33");
+ else show ( "44");
+ if ( a != 3 ) show ( "333");
+ else show ( "444");
+ return;
+ }
+ {
+ int a = 0;
+ // test break
+un:
+ while ( true )
+ {
+deux:
+ while ( true )
+ {
+ a++;
+ if ( a == 2 ) continue;
+ if ( a == 3 ) break deux;
+ show ( a ) ;
+ if ( a == 5 ) break un;
+ }
+ show ( "DEUX" );
+ }
+ return;
+ }
+ {
+ // test switch
+ int a = 0;
+
+ switch ( a )
+ {
+ case 1 : show( "un" ) ; break;
+ case 2 : show( "deux" ) ; // break;
+ case 3 : show( "trois" ) ; break;
+ case 4 : show( "quatre" ) ; // break;
+ default : show( "par défaut" ) ;
+ }
+ return;
+ }
+ {
+ // test boucle while
+ float z = 3.3;
+ while ( z > 0 )
+ { show ( z-- ) ; }
+ return;
+ }
+
+ {
+ // test boucle do
+ float y = 3.3;
+ do { int x = 0; show(y); y++; } while ( y < 7 ) ;
+ return;
+ }
+ // test boucle for
+ int j = -7; show ( j );
+ for ( int ii = 3, j = 31; ii < 6 ; ++ii, j = j -3 )
+ {
+ j = 10 * j;
+ show ( ii, j );
+ }
+ return;
+{
+ // déclarations de variables
+ int a; int b = 3; int c = 4*b, d = 1, e;
+ float x; float y = 3.3; float z = y / 2, u = 1, v;
+ boolean t; boolean tt = true or false; boolean ttt = false, tttt = true, t5;
+ string s; string ss = "hello"; string s2 = ss + " plus", s3 = "s3", s4;
+
+ show( b, c, d );
+ show( y, z, u );
+ show( tt, ttt, tttt );
+ show( ss, s2, s3 );
+}
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/TestCB1.txt b/src/CBot/TestCBot/TestCB1.txt
new file mode 100644
index 0000000..516db47
--- /dev/null
+++ b/src/CBot/TestCBot/TestCB1.txt
@@ -0,0 +1,18 @@
+extern public void toto()
+{
+ print( "hello" ) ;
+ print( fac(5) );
+ print( t() ) ;
+}
+
+public int fac(int n)
+{
+ if ( n<2 ) return 1;
+ return n * fac(n-1);
+}
+
+point t()
+{
+ point a(1,2);
+ return a;
+}
diff --git a/src/CBot/TestCBot/TestCBot.clw b/src/CBot/TestCBot/TestCBot.clw
new file mode 100644
index 0000000..13f20f4
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot.clw
@@ -0,0 +1,316 @@
+; CLW file contains information for the MFC ClassWizard
+
+[General Info]
+Version=1
+LastClass=CPerformDlg
+LastTemplate=CDialog
+NewFileInclude1=#include "stdafx.h"
+NewFileInclude2=#include "testcbot.h"
+LastPage=0
+
+ClassCount=8
+Class1=CBotConsoleDlg
+Class2=CChildFrame
+Class3=CMainFrame
+Class4=CTestCBotApp
+Class5=CAboutDlg
+Class6=CTestCBotDoc
+Class7=CTestCBotView
+
+ResourceCount=12
+Resource1=IDD_CONSOLE
+Resource2=IDR_TESTCBTYPE (French (France))
+Resource3=IDD_ABOUTBOX (French (France))
+Resource4=IDR_MAINFRAME (French (France))
+Resource5=IDR_MAINFRAME
+Resource6=IDR_TESTCBTYPE
+Resource7=IDD_ABOUTBOX
+Resource8=IDD_CONSOLE (French (Switzerland))
+Class8=CPerformDlg
+Resource9=IDD_DIALOG1
+Resource10=IDD_DIALOG2
+Resource11=IDD_DIALOG1 (French (Switzerland))
+Resource12=IDD_DIALOG2 (French (France))
+
+[CLS:CBotConsoleDlg]
+Type=0
+BaseClass=CDialog
+HeaderFile=CBotConsoleDlg.h
+ImplementationFile=CBotConsoleDlg.cpp
+LastObject=IDC_EDIT1
+
+[CLS:CChildFrame]
+Type=0
+BaseClass=CMDIChildWnd
+HeaderFile=ChildFrm.h
+ImplementationFile=ChildFrm.cpp
+
+[CLS:CMainFrame]
+Type=0
+BaseClass=CMDIFrameWnd
+HeaderFile=MainFrm.h
+ImplementationFile=MainFrm.cpp
+Filter=T
+VirtualFilter=fWC
+LastObject=CMainFrame
+
+[CLS:CTestCBotApp]
+Type=0
+BaseClass=CWinApp
+HeaderFile=TestCBot.h
+ImplementationFile=TestCBot.cpp
+Filter=N
+VirtualFilter=AC
+LastObject=ID_TEST
+
+[CLS:CAboutDlg]
+Type=0
+BaseClass=CDialog
+HeaderFile=TestCBot.cpp
+ImplementationFile=TestCBot.cpp
+LastObject=CAboutDlg
+
+[CLS:CTestCBotDoc]
+Type=0
+BaseClass=CDocument
+HeaderFile=TestCBotDoc.h
+ImplementationFile=TestCBotDoc.cpp
+LastObject=CTestCBotDoc
+Filter=N
+VirtualFilter=DC
+
+[CLS:CTestCBotView]
+Type=0
+BaseClass=CView
+HeaderFile=TestCBotView.h
+ImplementationFile=TestCBotView.cpp
+LastObject=CTestCBotView
+Filter=C
+VirtualFilter=VWC
+
+[DLG:IDD_CONSOLE]
+Type=1
+Class=CBotConsoleDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342308352
+Control2=IDC_EDIT2,edit,1350631552
+Control3=IDOK,button,1342242817
+Control4=IDC_EDIT1,edit,1352734724
+
+[DLG:IDD_ABOUTBOX]
+Type=1
+Class=CAboutDlg
+ControlCount=7
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308480
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+Control5=IDC_STATIC,static,1342308352
+Control6=IDC_STATIC,static,1342308352
+Control7=IDC_STATIC,static,1342308352
+
+[TB:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command4=ID_EDIT_CUT
+Command5=ID_EDIT_COPY
+Command6=ID_EDIT_PASTE
+Command7=ID_FILE_PRINT
+Command8=ID_RUN
+Command9=ID_APP_ABOUT
+CommandCount=9
+
+[MNU:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_MRU_FILE1
+Command4=ID_APP_EXIT
+Command5=ID_VIEW_TOOLBAR
+Command6=ID_VIEW_STATUS_BAR
+Command7=ID_APP_ABOUT
+CommandCount=7
+
+[MNU:IDR_TESTCBTYPE (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_CLOSE
+Command4=ID_FILE_SAVE
+Command5=ID_FILE_SAVE_AS
+Command6=ID_FILE_MRU_FILE1
+Command7=ID_APP_EXIT
+Command8=ID_EDIT_UNDO
+Command9=ID_EDIT_CUT
+Command10=ID_EDIT_COPY
+Command11=ID_EDIT_PASTE
+Command12=ID_VIEW_TOOLBAR
+Command13=ID_VIEW_STATUS_BAR
+Command14=ID_WINDOW_NEW
+Command15=ID_WINDOW_CASCADE
+Command16=ID_WINDOW_TILE_HORZ
+Command17=ID_WINDOW_ARRANGE
+Command18=ID_APP_ABOUT
+CommandCount=18
+
+[ACL:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_EDIT_COPY
+Command2=ID_FILE_NEW
+Command3=ID_FILE_OPEN
+Command4=ID_FILE_SAVE
+Command5=ID_EDIT_PASTE
+Command6=ID_EDIT_UNDO
+Command7=ID_EDIT_CUT
+Command8=ID_RUN
+Command9=ID_NEXT_PANE
+Command10=ID_PREV_PANE
+Command11=ID_RUN
+Command12=ID_TEST
+Command13=ID_EDIT_COPY
+Command14=ID_EDIT_PASTE
+Command15=ID_EDIT_CUT
+Command16=ID_EDIT_UNDO
+CommandCount=16
+
+[DLG:IDD_ABOUTBOX (French (France))]
+Type=1
+Class=CAboutDlg
+ControlCount=7
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308480
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+Control5=IDC_STATIC,static,1342308352
+Control6=IDC_STATIC,static,1342308352
+Control7=IDC_STATIC,static,1342308352
+
+[ACL:IDR_MAINFRAME]
+Type=1
+Command1=ID_EDIT_COPY
+Command2=ID_FILE_NEW
+Command3=ID_FILE_OPEN
+Command4=ID_FILE_SAVE
+Command5=ID_EDIT_PASTE
+Command6=ID_EDIT_UNDO
+Command7=ID_EDIT_CUT
+Command8=ID_RUN
+Command9=ID_NEXT_PANE
+Command10=ID_PREV_PANE
+Command11=ID_RUN
+Command12=ID_TEST
+Command13=ID_EDIT_COPY
+Command14=ID_EDIT_PASTE
+Command15=ID_EDIT_CUT
+Command16=ID_EDIT_UNDO
+CommandCount=16
+
+[TB:IDR_MAINFRAME]
+Type=1
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command4=ID_EDIT_CUT
+Command5=ID_EDIT_COPY
+Command6=ID_EDIT_PASTE
+Command7=ID_FILE_PRINT
+Command8=ID_RUN
+Command9=ID_APP_ABOUT
+CommandCount=9
+
+[MNU:IDR_MAINFRAME]
+Type=1
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_MRU_FILE1
+Command4=ID_APP_EXIT
+Command5=ID_VIEW_TOOLBAR
+Command6=ID_VIEW_STATUS_BAR
+Command7=ID_APP_ABOUT
+CommandCount=7
+
+[MNU:IDR_TESTCBTYPE]
+Type=1
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_CLOSE
+Command4=ID_FILE_SAVE
+Command5=ID_FILE_SAVE_AS
+Command6=ID_FILE_MRU_FILE1
+Command7=ID_APP_EXIT
+Command8=ID_EDIT_UNDO
+Command9=ID_EDIT_CUT
+Command10=ID_EDIT_COPY
+Command11=ID_EDIT_PASTE
+Command12=ID_VIEW_TOOLBAR
+Command13=ID_VIEW_STATUS_BAR
+Command14=ID_WINDOW_NEW
+Command15=ID_WINDOW_CASCADE
+Command16=ID_WINDOW_TILE_HORZ
+Command17=ID_WINDOW_ARRANGE
+Command18=ID_APP_ABOUT
+CommandCount=18
+
+[DLG:IDD_CONSOLE (French (Switzerland))]
+Type=1
+Class=CBotConsoleDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342308352
+Control2=IDC_EDIT2,edit,1350631552
+Control3=IDOK,button,1342242817
+Control4=IDC_EDIT1,edit,1352734724
+
+[DLG:IDD_DIALOG1]
+Type=1
+Class=CPerformDlg
+ControlCount=9
+Control1=IDC_STATIC,static,1342308352
+Control2=IDC_EDIT1,edit,1350633600
+Control3=IDC_STATIC,static,1342308352
+Control4=IDC_EDIT2,edit,1350631552
+Control5=IDC_SPIN1,msctls_updown32,1342177312
+Control6=IDC_COMBO1,combobox,1344339971
+Control7=IDC_STATIC,static,1342308352
+Control8=IDC_STATIC,static,1342308352
+Control9=IDC_EDIT3,edit,1350633600
+
+[CLS:CPerformDlg]
+Type=0
+HeaderFile=PerformDlg.h
+ImplementationFile=PerformDlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+LastObject=IDC_EDIT3
+
+[DLG:IDD_DIALOG2]
+Type=1
+ControlCount=2
+Control1=IDOK,button,1342242817
+Control2=IDCANCEL,button,1342242816
+
+[DLG:IDD_DIALOG1 (French (Switzerland))]
+Type=1
+ControlCount=9
+Control1=IDC_STATIC,static,1342308352
+Control2=IDC_EDIT1,edit,1350633600
+Control3=IDC_STATIC,static,1342308352
+Control4=IDC_EDIT2,edit,1350631552
+Control5=IDC_SPIN1,msctls_updown32,1342177312
+Control6=IDC_COMBO1,combobox,1344339971
+Control7=IDC_STATIC,static,1342308352
+Control8=IDC_STATIC,static,1342308352
+Control9=IDC_EDIT3,edit,1350633600
+
+[DLG:IDD_DIALOG2 (French (France))]
+Type=1
+ControlCount=2
+Control1=IDOK,button,1342242817
+Control2=IDCANCEL,button,1342242816
+
diff --git a/src/CBot/TestCBot/TestCBot.cpp b/src/CBot/TestCBot/TestCBot.cpp
new file mode 100644
index 0000000..7e2aabb
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot.cpp
@@ -0,0 +1,253 @@
+// TestCBot.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "TestCBot.h"
+
+#include "MainFrm.h"
+#include "ChildFrm.h"
+#include "TestCBotDoc.h"
+#include "TestCBotView.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotApp
+
+BEGIN_MESSAGE_MAP(CTestCBotApp, CWinApp)
+ //{{AFX_MSG_MAP(CTestCBotApp)
+ ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
+ //}}AFX_MSG_MAP
+ // Standard file based document commands
+ ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
+ ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotApp construction
+
+CTestCBotApp::CTestCBotApp()
+{
+ m_pConsole = NULL;
+ m_LastActive = NULL;
+ m_pClassPoint= NULL;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CTestCBotApp object
+
+CTestCBotApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotApp initialization
+
+#include "Routines.cpp"
+
+
+static char BASED_CODE szSection[] = "Recent File List";
+static char BASED_CODE szFilename[] = "File1";
+
+
+#include "../ClassFILE.cpp"
+
+// routine pour mettre à jour l'instance de la classe Bot courante
+void rMajObject( CBotVar* pThis, void* pUser )
+{
+ if (!pThis->IsElemOfClass("object"))
+ return ;
+ CBotVar* pPos = pThis->GivItem("position");
+ CBotVar* pX = pPos->GivItem("x");
+ CBotVar* pY = pPos->GivItem("y");
+ CBotVar* pZ = pPos->GivItem("z");
+// CBotVar* pPt = pThis->GivItem("transport");
+
+ CBotString p = pX->GivValString();
+
+// pX->SetValFloat( pUser == (void*)1 ? (float)12.5 : (float)44.4 );
+ pZ->SetValFloat( (float)0 );
+ pY->SetValFloat( (float)-3.33 );
+ pX->SetValFloat( pX->GivValFloat() + 10 ) ;
+
+// pX = pThis->GivItem( "xx" );
+// pX->SetValFloat( (float)22 );
+
+ // crée une instance sur une classe object
+// CBotVar* pAutre = CBotVar::Create("autre", CBotTypClass, "object");
+// pAutre->SetUserPtr( (void*)3 );
+// pPt->SetPointer( pAutre );
+// pPt->SetPointer( NULL );
+// delete pAutre;
+}
+
+
+BOOL CTestCBotApp::InitInstance()
+{
+//////////////////////////////////////////////
+// défini les mots clefs supplémentaires
+// -------------------------------------------
+
+ CBotProgram::Init();
+
+//////////////////////////////////////////////
+// défini les fonctions "show()" et "print()"
+// -------------------------------------------
+
+ CBotProgram::AddFunction("show", rShow, cShow);
+ CBotProgram::AddFunction("print", rPrint, cPrint);
+ CBotProgram::AddFunction("println", rPrintLn, cPrint);
+
+
+///////////////////////////////////
+// définie la classe globale CPoint
+// --------------------------------
+
+ m_pClassPoint = new CBotClass("CPoint", NULL);
+ // ajoute le composant ".x"
+ m_pClassPoint->AddItem("x", CBotTypFloat);
+ // ajoute le composant ".y"
+ m_pClassPoint->AddItem("y", CBotTypFloat);
+
+ // ajoute le constructeur pour cette classe
+ m_pClassPoint->AddFunction("CPoint", rCPoint, cCPoint);
+
+ m_pClassPointIntr = new CBotClass("point", NULL, TRUE);
+ // ajoute le composant ".x"
+ m_pClassPointIntr->AddItem("x", CBotTypFloat);
+ // ajoute le composant ".y"
+ m_pClassPointIntr->AddItem("y", CBotTypFloat);
+ // ajoute le composant ".z"
+ m_pClassPointIntr->AddItem("z", CBotTypFloat);
+
+ // ajoute le constructeur pour cette classe
+ m_pClassPointIntr->AddFunction("point", rCPoint, cCPoint);
+
+ // défini la classe "object"
+ CBotClass* pClassObject = new CBotClass( "object", NULL ) ;
+ pClassObject->AddItem( "xx", CBotTypFloat );
+ pClassObject->AddItem( "position", CBotTypResult( CBotTypIntrinsic, "point" ) );
+ pClassObject->AddItem( "transport", CBotTypResult( CBotTypPointer, "object" ) );
+ pClassObject->AddUpdateFunc( rMajObject );
+
+ InitClassFILE();
+
+ AfxEnableControlContainer();
+
+ // Standard initialization
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+ // Change the registry key under which our settings are stored.
+ SetRegistryKey(_T("Local AppWizard-Generated Applications"));
+
+ LoadStdProfileSettings(); // Load standard INI file options (including MRU)
+
+ // Register document templates
+
+ CMultiDocTemplate* pDocTemplate;
+ pDocTemplate = new CMultiDocTemplate(
+ IDR_TESTCBTYPE,
+ RUNTIME_CLASS(CTestCBotDoc),
+ RUNTIME_CLASS(CChildFrame), // custom MDI child frame
+ RUNTIME_CLASS(CTestCBotView));
+ AddDocTemplate(pDocTemplate);
+
+ // create main MDI Frame window
+ CMainFrame* pMainFrame = new CMainFrame;
+ if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
+ return FALSE;
+ m_pMainWnd = pMainFrame;
+
+ // Parse command line for standard shell commands, DDE, file open
+ CCommandLineInfo cmdInfo;
+ ParseCommandLine(cmdInfo);
+
+ if (m_lpCmdLine[0] == 0)
+ {
+ CString Filename = GetProfileString(szSection, szFilename);
+ if (Filename.IsEmpty()) Filename = "TstCbot.txt";
+ else OpenDocumentFile(Filename);
+ }
+ else
+ // Dispatch commands specified on the command line
+ if (!ProcessShellCommand(cmdInfo))
+ return FALSE;
+ pMainFrame->ShowWindow(m_nCmdShow);
+ pMainFrame->UpdateWindow();
+
+
+ return TRUE;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CAboutDlg dialog used for App About
+
+class CAboutDlg : public CDialog
+{
+public:
+ CAboutDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CAboutDlg)
+ enum { IDD = IDD_ABOUTBOX };
+ //}}AFX_DATA
+
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAboutDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ //{{AFX_MSG(CAboutDlg)
+ // No message handlers
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CAboutDlg)
+ //}}AFX_DATA_INIT
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAboutDlg)
+ //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+ //{{AFX_MSG_MAP(CAboutDlg)
+ // No message handlers
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+// App command to run the dialog
+void CTestCBotApp::OnAppAbout()
+{
+ CAboutDlg aboutDlg;
+ aboutDlg.DoModal();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotApp commands
+
+int CTestCBotApp::ExitInstance()
+{
+ delete m_pFuncFile;
+
+ CBotProgram::Free();
+ return CWinApp::ExitInstance();
+}
diff --git a/src/CBot/TestCBot/TestCBot.dsp b/src/CBot/TestCBot/TestCBot.dsp
new file mode 100644
index 0000000..8ed9b11
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot.dsp
@@ -0,0 +1,201 @@
+# Microsoft Developer Studio Project File - Name="TestCBot" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=TestCBot - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "TestCBot.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "TestCBot.mak" CFG="TestCBot - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "TestCBot - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "TestCBot - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "TestCBot - Win32 Release"
+
+# PROP BASE Use_MFC 5
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 5
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x100c /d "NDEBUG"
+# ADD RSC /l 0x100c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
+# ADD LINK32 /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "TestCBot - Win32 Debug"
+
+# PROP BASE Use_MFC 5
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 5
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x100c /d "_DEBUG"
+# ADD RSC /l 0x100c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 /nologo /stack:0x7010 /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "TestCBot - Win32 Release"
+# Name "TestCBot - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\CBotConsoleDlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ChildFrm.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MainFrm.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PerformDlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBot.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBot.rc
+
+!IF "$(CFG)" == "TestCBot - Win32 Release"
+
+!ELSEIF "$(CFG)" == "TestCBot - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBotDoc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBotView.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\CBotConsoleDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ChildFrm.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MainFrm.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PerformDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBot.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBotDoc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TestCBotView.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\res\TestCBot.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\TestCBot.rc2
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\TestCBotDoc.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\Toolbar.bmp
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\Debug\CBot.lib
+# End Source File
+# End Target
+# End Project
diff --git a/src/CBot/TestCBot/TestCBot.h b/src/CBot/TestCBot/TestCBot.h
new file mode 100644
index 0000000..f101fd1
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot.h
@@ -0,0 +1,64 @@
+// TestCBot.h : main header file for the TESTCBOT application
+//
+
+#if !defined(AFX_TESTCBOT_H__4D1BB903_8E74_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_TESTCBOT_H__4D1BB903_8E74_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+//#include "../CbotDll.h" // librairie CBot
+#include "../Cbot.h" // complet pour Browse
+
+class CTestCBotView;
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotApp:
+// See TestCBot.cpp for the implementation of this class
+//
+
+class CTestCBotApp : public CWinApp
+{
+public:
+ CTestCBotApp();
+
+ CEdit* m_pConsole;
+ CTestCBotView* m_LastActive;
+ CBotClass* m_pClassPoint;
+ CBotClass* m_pClassPointIntr;
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTestCBotApp)
+ public:
+ virtual BOOL InitInstance();
+ virtual int ExitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CTestCBotApp)
+ afx_msg void OnAppAbout();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TESTCBOT_H__4D1BB903_8E74_11D4_A439_00D059085115__INCLUDED_)
+
+
+#define WM_STARTPROG WM_APP + 0
+#define WM_ENDPROG WM_APP + 1
+#define WM_ACTWINDOW WM_APP + 2
diff --git a/src/CBot/TestCBot/TestCBot.rc b/src/CBot/TestCBot/TestCBot.rc
new file mode 100644
index 0000000..137458c
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot.rc
@@ -0,0 +1,564 @@
+//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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\TestCBot.ico"
+IDR_TESTCBTYPE ICON DISCARDABLE "res\\TestCBotDoc.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDR_MAINFRAME BITMAP MOVEABLE PURE "res\\Toolbar.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Toolbar
+//
+
+IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15
+BEGIN
+ BUTTON ID_FILE_NEW
+ BUTTON ID_FILE_OPEN
+ BUTTON ID_FILE_SAVE
+ SEPARATOR
+ BUTTON ID_EDIT_CUT
+ BUTTON ID_EDIT_COPY
+ BUTTON ID_EDIT_PASTE
+ SEPARATOR
+ BUTTON ID_FILE_PRINT
+ BUTTON ID_RUN
+ SEPARATOR
+ BUTTON ID_APP_ABOUT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MAINFRAME MENU PRELOAD DISCARDABLE
+BEGIN
+ POPUP "&Fichier"
+ BEGIN
+ MENUITEM "&Nouveau\tCtrl+N", ID_FILE_NEW
+ MENUITEM "&Ouvrir...\tCtrl+O", ID_FILE_OPEN
+ MENUITEM SEPARATOR
+ MENUITEM "Fichier récent", ID_FILE_MRU_FILE1, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "&Quitter", ID_APP_EXIT
+ END
+ POPUP "&Affichage"
+ BEGIN
+ MENUITEM "&Barre d'outils", ID_VIEW_TOOLBAR
+ MENUITEM "Barre d'é&tat", ID_VIEW_STATUS_BAR
+ END
+ POPUP "&?"
+ BEGIN
+ MENUITEM "&A propos de TestCBot...", ID_APP_ABOUT
+ END
+END
+
+IDR_TESTCBTYPE MENU PRELOAD DISCARDABLE
+BEGIN
+ POPUP "&Fichier"
+ BEGIN
+ MENUITEM "&Nouveau\tCtrl+N", ID_FILE_NEW
+ MENUITEM "&Ouvrir...\tCtrl+O", ID_FILE_OPEN
+ MENUITEM "&Fermer", ID_FILE_CLOSE
+ MENUITEM "&Enregistrer\tCtrl+S", ID_FILE_SAVE
+ MENUITEM "En&registrer sous...", ID_FILE_SAVE_AS
+ MENUITEM SEPARATOR
+ MENUITEM "Fichier récent", ID_FILE_MRU_FILE1, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "&Quitter", ID_APP_EXIT
+ END
+ POPUP "&Edition"
+ BEGIN
+ MENUITEM "&Annuler\tCtrl+Z", ID_EDIT_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "&Couper\tCtrl+X", ID_EDIT_CUT
+ MENUITEM "&Copier\tCtrl+C", ID_EDIT_COPY
+ MENUITEM "C&oller\tCtrl+V", ID_EDIT_PASTE
+ END
+ POPUP "&Affichage"
+ BEGIN
+ MENUITEM "&Barre d'outils", ID_VIEW_TOOLBAR
+ MENUITEM "Barre d'é&tat", ID_VIEW_STATUS_BAR
+ END
+ POPUP "Fe&nêtre"
+ BEGIN
+ MENUITEM "&Nouvelle fenêtre", ID_WINDOW_NEW
+ MENUITEM "&Cascade", ID_WINDOW_CASCADE
+ MENUITEM "&Mosaïque", ID_WINDOW_TILE_HORZ
+ MENUITEM "&Réorganiser les icônes", ID_WINDOW_ARRANGE
+ END
+ POPUP "&?"
+ BEGIN
+ MENUITEM "&A propos de TestCBot...", ID_APP_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
+BEGIN
+ "C", ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
+ "N", ID_FILE_NEW, VIRTKEY, CONTROL, NOINVERT
+ "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
+ "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
+ "V", ID_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
+ VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
+ VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT, NOINVERT
+ VK_F5, ID_RUN, VIRTKEY, NOINVERT
+ VK_F6, ID_NEXT_PANE, VIRTKEY, NOINVERT
+ VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT, NOINVERT
+ VK_F7, ID_RUN, VIRTKEY, NOINVERT
+ VK_F9, ID_TEST, VIRTKEY, NOINVERT
+ VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
+ VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT, NOINVERT
+ "X", ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
+ "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 265, 206
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "A propos de TestCBot"
+FONT 8, "MS Sans Serif"
+BEGIN
+ ICON IDR_MAINFRAME,IDC_STATIC,11,17,21,20
+ LTEXT "TestCBot version 1.0",IDC_STATIC,40,10,119,8,
+ SS_NOPREFIX
+ LTEXT "Copyright D. Dumoulin (C) 2000",IDC_STATIC,40,25,119,8
+ DEFPUSHBUTTON "OK",IDOK,226,7,32,14,WS_GROUP
+ LTEXT "Programme de test pour la librairie CBot\n\nLes fonctions doivent être déclarées comme ""extern"" pour apparaître dans la liste lors de l'exécution.\n\n",
+ IDC_STATIC,39,43,191,41
+ LTEXT "Mais en fait, on peut accèder à toutes les fonctions marquées ""public"" quelles soient dans la fenêtre active ou non.",
+ IDC_STATIC,39,89,187,36
+ LTEXT "Les fonctions print( ... ) et println( ...) permettent d'afficher des résultats dans la console.\n\nLa fonction show( ... ) affiche les paramètres dans un dialogue, et suspend donc l'exécution.",
+ IDC_STATIC,39,130,187,54
+END
+
+IDD_DIALOG2 DIALOG DISCARDABLE 0, 0, 186, 95
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,129,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040C04B0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "Application MFC TestCBot\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "TestCBot\0"
+ VALUE "LegalCopyright", "Copyright (C) 1900\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "TestCBot.EXE\0"
+ VALUE "ProductName", "Application TestCBot\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Traduction", 0x40c, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 258
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 199
+ END
+
+ IDD_DIALOG2, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 88
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE PRELOAD DISCARDABLE
+BEGIN
+ IDR_MAINFRAME "TestCBot"
+ IDR_TESTCBTYPE "\nTestCBot\nTestCBot\nCBot (*.txt)\n.txt\nTestCBot.Document\nTestCB Document"
+END
+
+STRINGTABLE PRELOAD DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "TestCBot"
+ AFX_IDS_IDLEMESSAGE "Prêt"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_INDICATOR_EXT "EXT"
+ ID_INDICATOR_CAPS "MAJ"
+ ID_INDICATOR_NUM "NUM"
+ ID_INDICATOR_SCRL "DEF"
+ ID_INDICATOR_OVR "ECR"
+ ID_INDICATOR_REC "ENR"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_FILE_NEW "Crée un nouveau document\nNouveau"
+ ID_FILE_OPEN "Ouvre un document existant\nOuvrir"
+ ID_FILE_CLOSE "Ferme le document actif\nFermer"
+ ID_FILE_SAVE "Enregistre le document actif\nEnregistrer"
+ ID_FILE_SAVE_AS "Enregistre le document actif sous un nouveau nom\nEnregistrer sous"
+ ID_FILE_PRINT "Imprime le document\nImprime"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_APP_ABOUT "Affiche des informations sur le programme\nA propos de"
+ ID_APP_EXIT "Ferme l'application ; propose d'enregistrer les documents\nQuitter"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_FILE_MRU_FILE1 "Ouvre ce document"
+ ID_FILE_MRU_FILE2 "Ouvre ce document"
+ ID_FILE_MRU_FILE3 "Ouvre ce document"
+ ID_FILE_MRU_FILE4 "Ouvre ce document"
+ ID_FILE_MRU_FILE5 "Ouvre ce document"
+ ID_FILE_MRU_FILE6 "Ouvre ce document"
+ ID_FILE_MRU_FILE7 "Ouvre ce document"
+ ID_FILE_MRU_FILE8 "Ouvre ce document"
+ ID_FILE_MRU_FILE9 "Ouvre ce document"
+ ID_FILE_MRU_FILE10 "Ouvre ce document"
+ ID_FILE_MRU_FILE11 "Ouvre ce document"
+ ID_FILE_MRU_FILE12 "Ouvre ce document"
+ ID_FILE_MRU_FILE13 "Ouvre ce document"
+ ID_FILE_MRU_FILE14 "Ouvre ce document"
+ ID_FILE_MRU_FILE15 "Ouvre ce document"
+ ID_FILE_MRU_FILE16 "Ouvre ce document"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_NEXT_PANE "Passe au volet de fenêtre suivant\nVolet suivant"
+ ID_PREV_PANE "Revient au volet précédent\nVolet précédent"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_WINDOW_NEW "Ouvre une nouvelle fenêtre pour le document actif\nNouvelle fenêtre"
+ ID_WINDOW_ARRANGE "Réorganise les icônes en bas de la fenêtre\nRéorganise les icônes"
+ ID_WINDOW_CASCADE "Réorganise les fenêtres en cascade\nCascade"
+ ID_WINDOW_TILE_HORZ "Réorganise les fenêtres en une mosaïque\nMosaïque"
+ ID_WINDOW_TILE_VERT "Réorganise les fenêtres en une mosaïque\nMosaïque"
+ ID_WINDOW_SPLIT "Fractionne la fenêtre active en deux volets\nFractionner"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_EDIT_CLEAR "Efface la sélection\nEffacer"
+ ID_EDIT_CLEAR_ALL "Efface tout\nEffacer tout"
+ ID_EDIT_COPY "Copie la sélection et la place dans le Presse-papiers\nCopier"
+ ID_EDIT_CUT "Supprime la sélection et la place dans le Presse-papiers\nCopier"
+ ID_EDIT_FIND "Recherche le texte spécifié\nRechercher"
+ ID_EDIT_PASTE "Insère le contenu du Presse-papiers\nColler"
+ ID_EDIT_REPEAT "Répète la dernière action\nRépéter"
+ ID_EDIT_REPLACE "Remplace le texte spécifique par un texte différent\nRemplacer"
+ ID_EDIT_SELECT_ALL "Sélectionne le document entier\nSélectionner tout"
+ ID_EDIT_UNDO "Annule la dernière action\nAnnuler"
+ ID_EDIT_REDO "Rétablit l'action précédemment annulée\nRétablir"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_VIEW_TOOLBAR "Affiche ou masque la barre d'outils\nBarre d'outils"
+ ID_VIEW_STATUS_BAR "Affiche ou masque la barre d'état\nBarre d'état"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_SCSIZE "Change la taille de la fenêtre"
+ AFX_IDS_SCMOVE "Change la position de la fenêtre"
+ AFX_IDS_SCMINIMIZE "Réduit la fenêtre en icône"
+ AFX_IDS_SCMAXIMIZE "Agrandit la fenêtre au format de l'écran"
+ AFX_IDS_SCNEXTWINDOW "Passe à la fenêtre de document suivante"
+ AFX_IDS_SCPREVWINDOW "Passe à la fenêtre de document précédente"
+ AFX_IDS_SCCLOSE "Ferme la fenêtre active et propose l'enregistrement des documents"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_SCRESTORE "Restaure la fenêtre à sa taille d'origine"
+ AFX_IDS_SCTASKLIST "Active la liste des tâches"
+ AFX_IDS_MDICHILD "Active cette fenêtre"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_RUN "Execute le programme CBot\nExecute (F5)"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ TX_TYPENAMES "les différents types"
+ 1001 "Byte"
+ 1002 "Short"
+ 1003 "Char"
+ 1004 "Int"
+ 1005 "Long"
+ 1006 "Real"
+ 1007 "Double"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ 1008 "Boolean"
+ 1009 "String"
+ 1010 "Array"
+ 1011 "Arraybody"
+ 1012 "Pointer"
+ 1013 "Nullpointer"
+ 1014 "nop"
+ 1015 "Class"
+ 1016 "Intrinsic"
+END
+
+#endif // French (France) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// French (Switzerland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRS)
+#ifdef _WIN32
+LANGUAGE LANG_FRENCH, SUBLANG_FRENCH_SWISS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONSOLE DIALOG DISCARDABLE 0, 0, 401, 210
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "CBot Console"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Commande :",IDC_STATIC,7,177,40,8
+ EDITTEXT IDC_EDIT2,7,189,329,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Exécute",IDOK,344,189,50,14
+ EDITTEXT IDC_EDIT1,7,7,387,167,ES_MULTILINE | ES_READONLY |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 177, 100
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Test performances"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Boucles par seconde",IDC_STATIC,7,9,68,8
+ EDITTEXT IDC_EDIT1,111,7,51,14,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Nombre de scripts",IDC_STATIC,7,55,58,8
+ EDITTEXT IDC_EDIT2,111,52,40,14,ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_SPIN1,"msctls_updown32",UDS_ARROWKEYS,152,52,
+ 10,14
+ COMBOBOX IDC_COMBO1,111,74,52,111,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Timer",IDC_STATIC,7,77,18,8
+ LTEXT "Performance %",IDC_STATIC,7,28,48,8
+ EDITTEXT IDC_EDIT3,111,25,51,14,ES_AUTOHSCROLL | ES_READONLY
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_CONSOLE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 394
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 203
+ END
+
+ IDD_DIALOG1, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 170
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 93
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#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
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 12, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\TestCBot.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""l.fra\\afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog Info
+//
+
+IDD_DIALOG1 DLGINIT
+BEGIN
+ IDC_COMBO1, 0x403, 2, 0
+0x0031,
+ IDC_COMBO1, 0x403, 3, 0
+0x3031, "\000"
+ IDC_COMBO1, 0x403, 4, 0
+0x3031, 0x0030,
+ IDC_COMBO1, 0x403, 5, 0
+0x3031, 0x3030, "\000"
+ 0
+END
+
+#endif // French (Switzerland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
+#ifdef _WIN32
+LANGUAGE 12, 1
+#pragma code_page(1252)
+#endif
+#include "res\TestCBot.rc2" // non-Microsoft Visual C++ edited resources
+#include "l.fra\afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/CBot/TestCBot/TestCBot1.txt b/src/CBot/TestCBot/TestCBot1.txt
new file mode 100644
index 0000000..d27b4f8
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot1.txt
@@ -0,0 +1,27 @@
+
+class CPoint2
+{
+ float x, y;
+ void CPoint2(float x, float y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+public extern void T ( )
+{
+ CPoint2 X( 12, 33 ), Y ( -4, 4/3 );
+ print ( X, Y ) ;
+}
+
+public extern void Hello ( )
+
+{
+ println ( "Hello" );
+}
+
+public extern void test ( int n )
+{
+ for ( int i = n; i>0 ; i--) print (i);
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/TestCBot3.txt b/src/CBot/TestCBot/TestCBot3.txt
new file mode 100644
index 0000000..b915f96
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBot3.txt
@@ -0,0 +1,24 @@
+public extern void Test ()
+{
+ for ( int x = 100000; x>0 ; x-- ) { }
+}
+
+float MaRoutine( CPoint A, CPoint B )
+{
+ A.x -= B.x ; // distance en x
+ A.y -= B.y ; // distance en y
+ A.x *= A.x; // carré de la distance
+ A.y += A.y; // carré de la distance
+ println ( A, B ) ;
+ return ( A.x + A.y ) ;
+}
+
+public extern void TestAB ( )
+{
+ CPoint A(3, 5) ;
+ CPoint B(4, -2);
+ println ( A, B ) ;
+ MaRoutine( A, B ) ;
+ println ( A, B ) ;
+}
+
diff --git a/src/CBot/TestCBot/TestCBotDoc.cpp b/src/CBot/TestCBot/TestCBotDoc.cpp
new file mode 100644
index 0000000..e033dd5
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBotDoc.cpp
@@ -0,0 +1,683 @@
+// TestCBotDoc.cpp : implementation of the CTestCBotDoc class
+//
+
+#include "stdafx.h"
+#include "TestCBot.h"
+
+#include "TestCBotDoc.h"
+#include "TestCBotView.h"
+#include "CBotConsoleDlg.h"
+#include "PerformDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotDoc
+
+IMPLEMENT_DYNCREATE(CTestCBotDoc, CDocument)
+
+BEGIN_MESSAGE_MAP(CTestCBotDoc, CDocument)
+ //{{AFX_MSG_MAP(CTestCBotDoc)
+ ON_COMMAND(ID_RUN, OnRun)
+ ON_EN_CHANGE(IDC_EDIT1, OnChangeEdit1)
+ ON_COMMAND(ID_TEST, OnTest)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotDoc construction/destruction
+
+static BOOL test = FALSE;
+
+
+CTestCBotDoc::CTestCBotDoc()
+{
+ m_pEdit = NULL;
+ m_pProg = NULL;
+ m_bModified = FALSE;
+}
+
+CTestCBotDoc::~CTestCBotDoc()
+{
+ delete m_pEdit;
+ delete m_pProg;
+}
+
+BOOL CTestCBotDoc::OnNewDocument()
+{
+ if (!CDocument::OnNewDocument())
+ return FALSE;
+
+ return TRUE;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotDoc serialization
+
+void CTestCBotDoc::Serialize(CArchive& ar)
+{
+ if (ar.IsStoring())
+ {
+ m_pEdit->GetWindowText(m_DocText);
+ int w = m_DocText.GetLength();
+ ar.Write((LPCTSTR)m_DocText, w);
+ }
+ else
+ {
+ int r;
+ char buf[10001];
+
+ r = ar.Read(buf, 10000);
+ buf[r] = 0;
+ m_DocText = buf;
+
+ if ( m_pProg == NULL ) m_pProg = new CBotProgram();
+
+ if (!m_pProg->Compile(m_DocText, m_Liste, NULL))
+ {
+ delete m_pProg;
+ m_pProg = NULL;
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotDoc diagnostics
+
+#ifdef _DEBUG
+void CTestCBotDoc::AssertValid() const
+{
+ CDocument::AssertValid();
+}
+
+void CTestCBotDoc::Dump(CDumpContext& dc) const
+{
+ CDocument::Dump(dc);
+}
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotDoc commands
+
+void CTestCBotDoc::OnRun()
+{
+ OnFileSave();
+
+ m_pEdit->GetWindowText(m_DocText);
+
+ CString TextError;
+ int code, start, end;
+
+ if ( m_pProg == NULL ) m_pProg = new CBotProgram();
+
+ CTestCBotApp* pApp = (CTestCBotApp*)AfxGetApp();
+
+ if (!m_pProg->Compile(m_DocText, m_Liste, NULL))
+ {
+ m_pProg->GetError(code, start, end);
+ delete m_pProg;
+ m_pProg = NULL;
+
+ m_pEdit->SetSel( start, end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ TextError = CBotProgram::GivErrorText( code );
+ AfxMessageBox( TextError );
+
+ m_pEdit->SetFocus();
+ return;
+ }
+
+ if( m_Liste.GivSize() == 0 )
+ {
+ AfxMessageBox("Aucune fonction marquée \"extern\" !");
+ return;
+ }
+
+ for ( int i = 0; i < m_Liste.GivSize(); i++ )
+ {
+ int start, stop;
+ m_pProg->GetPosition(m_Liste[i], start, stop, GetPosNom, GetPosParam);
+ m_Liste[i] = m_DocText.Mid( start, stop-start );
+ }
+
+ CBotConsoleDlg dlg;
+ dlg.m_pListe = &m_Liste;
+ dlg.m_pEditx = m_pEdit;
+
+ dlg.DoModal(); // dialogue pour faire la console
+
+ if ( dlg.m_code>0 )
+ {
+ CString TextError;
+
+ TextError = m_pProg->GivErrorText( dlg.m_code );
+
+ m_pEdit->SetSel( dlg.m_start, dlg.m_end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ AfxMessageBox(TextError);
+ }
+
+ m_pEdit->SetFocus();
+
+ return;
+}
+
+
+void CTestCBotDoc::OnChangeEdit1()
+{
+ SetModifiedFlag();
+ m_bModified = TRUE;
+}
+
+BOOL CTestCBotDoc::Compile()
+{
+ m_pEdit->GetWindowText(m_DocText);
+
+ CString TextError;
+ int code, start, end;
+
+ if ( m_pProg == NULL ) m_pProg = new CBotProgram();
+
+ char buffer[100];
+ strcpy(buffer, "le pointeur à passer pour voir");
+
+ if (m_bModified && !m_pProg->Compile(m_DocText, m_Liste, (void*)buffer))
+ {
+ m_pProg->GetError(code, start, end);
+ delete m_pProg;
+ m_pProg = NULL;
+
+ m_pEdit->SetSel( start, end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ TextError = CBotProgram::GivErrorText( code );
+ AfxMessageBox( TextError );
+
+ m_pEdit->SetFocus();
+ m_bModified = FALSE;
+ return FALSE;
+ }
+
+ if ( m_pProg->GetPosition( "TheTest", start, end) )
+ {
+ m_pEdit->SetSel( start, end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+ }
+
+ m_bModified = FALSE;
+ return TRUE;
+}
+
+
+
+static int compt = 0;
+// routine retournant le "pointeur" à un autre object
+BOOL rRetObject( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ pResult->SetPointer( NULL );
+ compt+=45671;
+ if (compt&0x11) return TRUE;
+
+ CBotVar* pAutre = CBotVar::Create("autre", CBotTypResult( CBotTypClass, "object" ));
+ pAutre->SetUserPtr( (void*)2 );
+ pResult->SetPointer( pAutre );
+
+ if (!pResult->IsElemOfClass("object"))
+ return TRUE;
+
+ delete pAutre;
+ return TRUE;
+}
+
+CBotTypResult cRetObject( CBotVar* &pVar, void* pUser )
+{
+ return CBotTypResult( CBotTypPointer, "object");
+}
+
+BOOL roRadar( CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ pResult->SetPointer( NULL );
+ compt+=45671;
+ if (compt&0x11) return TRUE;
+
+ CBotVar* pAutre = CBotVar::Create("autre", CBotTypResult( CBotTypClass, "object" ));
+ pAutre->SetUserPtr( (void*)2 );
+ pResult->SetPointer( pAutre );
+
+ if (!pResult->IsElemOfClass("object"))
+ return TRUE;
+
+ delete pAutre;
+ return TRUE;
+}
+
+CBotTypResult coRadar( CBotVar* pThis, CBotVar* &pVar )
+{
+ void* pUser = pThis->GivUserPtr();
+ return CBotTypResult( CBotTypPointer, "object");
+}
+
+BOOL rMove( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ if ( test < 12 )
+ {
+ test++;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+CBotTypResult cMove( CBotVar* &pVar, void* pUser )
+{
+ return CBotTypResult( 0 );
+}
+
+BOOL rTurn( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ return TRUE;
+}
+
+CBotTypResult cTurn( CBotVar* &pVar, void* pUser )
+{
+ return CBotTypResult( 0 );
+}
+
+BOOL rRadar( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ pResult->SetPointer( NULL );
+
+ if ( pVar ) pVar->debug();
+
+ compt+=45671;
+ if (compt&0x11)
+ {
+ return FALSE; // TRUE;
+ }
+
+ CBotVar* pAutre = CBotVar::Create("autre", CBotTypResult( CBotTypClass, "object" ));
+ pAutre->SetUserPtr( (void*)2 );
+ pResult->SetPointer( pAutre );
+
+ if (!pResult->IsElemOfClass("object"))
+ return TRUE;
+
+ delete pAutre;
+ return TRUE;
+}
+
+CBotTypResult cRadar( CBotVar* &pVar, void* pUser )
+{
+ return CBotTypResult( CBotTypPointer, "object");
+}
+
+// routine retournant le "pointeur" à un autre object
+BOOL rTEST( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ test = 1 ;
+ if ( pVar == NULL ) return TRUE;
+
+ test = pVar->GivValInt();
+ if ( test == 5 )
+ {
+ pVar = pVar->GivNext();
+ pVar->SetUserPtr( OBJECTDELETED );
+ }
+ return TRUE;
+}
+
+CBotTypResult cTEST( CBotVar* &pVar, void* pUser )
+{
+ return CBotTypResult( 0 );
+}
+
+// routine retournant le "pointeur" à un autre object
+BOOL rF( CBotVar* pVar, CBotVar* pResult, int& ex, void* pUser )
+{
+ if ( pResult == NULL ) return TRUE;
+ pResult->SetValInt(3);
+ return TRUE;
+}
+
+CBotTypResult cF( CBotVar* &pVar, void* pUser )
+{
+ return CBotTypResult( CBotTypFloat );
+}
+
+/////////////////////////////////////////////////////////////////
+
+// Compilation d'une procédure avec un "point".
+
+CBotTypResult cPoint(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult( CBotErrLowParam );
+
+ if ( var->GivType() <= CBotTypDouble )
+ {
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult( CBotErrLowParam );
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum );
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult( CBotErrLowParam );
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum );
+ var = var->GivNext();
+ return CBotTypResult( 0 );
+ }
+
+ if ( var->GivType() == CBotTypClass )
+ {
+ if ( !var->IsElemOfClass("point") ) return CBotTypResult( CBotErrBadParam );
+ var = var->GivNext();
+ return CBotTypResult( 0 );
+ }
+
+ return CBotTypResult( CBotErrBadParam );
+}
+
+// Donne un paramètre de type "point".
+#define UNIT 1
+
+
+CBotTypResult cSpace(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult( CBotTypIntrinsic, "point" );
+ ret = cPoint(var, user);
+ if ( !ret.Eq(0) ) return ret;
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum );
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum );
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult( CBotErrBadNum );
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotErrOverParam;
+ return CBotTypResult( CBotTypIntrinsic, "point" );
+}
+
+// Instruction "space(center, rMin, rMax, dist)".
+
+BOOL rSpace(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CBotVar* pSub;
+ float rMin, rMax, dist;
+
+ rMin = 5.0f*UNIT;
+ rMax = 50.0f*UNIT;
+ dist = 4.0f*UNIT;
+
+ if ( var == 0 )
+ {
+// center = pThis->RetPosition(0);
+ }
+ else
+ {
+ if ( var != 0 )
+ {
+ rMin = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+
+ if ( var != 0 )
+ {
+ rMax = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+
+ if ( var != 0 )
+ {
+ dist = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+ }
+ }
+ }
+ }
+
+ if ( result != 0 )
+ {
+ pSub = result->GivItemList();
+ if ( pSub != 0 )
+ {
+ pSub->SetValFloat(1);
+ pSub = pSub->GivNext(); // "y"
+ pSub->SetValFloat(2);
+ pSub = pSub->GivNext(); // "z"
+// pSub->SetValFloat(3);
+ }
+ }
+ return TRUE;
+}
+//////////////////////////////////////////////////////////////
+
+
+void CTestCBotDoc::OnTest()
+{
+ CBotProgram::DefineNum("WingedGrabber", 1);
+ CBotProgram::DefineNum("TrackedGrabber", 2);
+ CBotProgram::DefineNum("WheeledGrabber", 3);
+ CBotProgram::DefineNum("LeggedGrabber", 4);
+ CBotProgram::DefineNum("WingedShooter", 5);
+ CBotProgram::DefineNum("TrackedShooter", 6);
+ CBotProgram::DefineNum("WheeledShooter", 7);
+ CBotProgram::DefineNum("LeggedShooter", 8);
+ CBotProgram::DefineNum("WingedOrgaShooter", 9);
+ CBotProgram::DefineNum("TrackedOrgaShooter", 10);
+ CBotProgram::DefineNum("WheeledOrgaShooter", 11);
+ CBotProgram::DefineNum("LeggedOrgaShooter", 12);
+ CBotProgram::DefineNum("WingedSniffer", 13);
+ CBotProgram::DefineNum("TrackedSniffer", 14);
+ CBotProgram::DefineNum("WheeledSniffer", 14);
+ CBotProgram::DefineNum("LeggedSniffer", 15);
+ CBotProgram::DefineNum("Thumper", 16);
+ CBotProgram::DefineNum("PhazerShooter", 17);
+ CBotProgram::DefineNum("Recycler", 18);
+ CBotProgram::DefineNum("Shielder", 19);
+ CBotProgram::DefineNum("Subber", 20);
+ CBotProgram::DefineNum("Me", 21);
+
+ CBotProgram::DefineNum("TypeMarkPath", 111);
+
+ OnFileSave();
+
+// CPerformDlg dlg;
+// dlg.m_Script = m_DocText;
+// dlg.DoModal();
+
+ // défini la routine RetObject
+ CBotProgram::AddFunction( "Radar", rRetObject, cRetObject );
+
+ // ajoute une routine pour cette classe
+ CBotProgram::AddFunction("Space", rSpace, cSpace);
+
+ // défini la routine Test
+ CBotProgram::AddFunction( "TEST", rTEST, cTEST );
+ CBotProgram::AddFunction( "F", rF, cF );
+
+ CBotProgram::AddFunction( "goto", rMove, cMove );
+ CBotProgram::AddFunction( "fire", rTurn, cTurn );
+ CBotProgram::AddFunction( "radar", rRadar, cRadar );
+
+ // crée une instance de la classe "Bot" pour ce robot
+ CBotVar* pThisRobot = CBotVar::Create( "", CBotTypResult(CBotTypClass, "object") );
+ pThisRobot->SetUserPtr( (void*)1 );
+ pThisRobot->SetIdent( 1234 );
+
+ delete m_pProg;
+ // crée un objet programme associé à cette instance
+ m_pProg = new CBotProgram(pThisRobot);
+
+ // compile le programme
+ CString TextError;
+ int code, start, end;
+
+ m_pEdit->GetWindowText(m_DocText);
+ if (!m_pProg->Compile(m_DocText, m_Liste, (void*) 44))
+ {
+ m_pProg->GetError(code, start, end);
+ delete m_pProg;
+ m_pProg = NULL;
+
+ delete pThisRobot;
+
+ m_pEdit->SetSel( start, end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ TextError = CBotProgram::GivErrorText( code );
+ AfxMessageBox( TextError );
+
+ m_pEdit->SetFocus();
+ return;
+ }
+
+ // exécute pour voir
+ m_pProg->Start(m_Liste[0]);
+
+ int mode = -1;
+
+ if ( mode >= 0 ) {
+
+ // sauve et restore à chaque pas possible
+ while (!m_pProg->Run(NULL, 1))
+ {
+ const char* FunctionName;
+ int start1, end1;
+ m_pProg->GetRunPos(FunctionName, start1, end1);
+ if ( end1 <= 0 )
+ m_pProg->GetRunPos(FunctionName, start1, end1);
+ m_pEdit->SetSel(start1, end1);
+
+if ( mode == 0 ) continue;
+
+ FILE* pf;
+ pf = fOpen( "TEST.CBO", "wb" );
+ CBotClass::SaveStaticState(pf);
+ m_pProg->SaveState(pf);
+ fClose(pf);
+
+if ( mode == 2 ) if (!m_pProg->Compile(m_DocText, m_Liste, (void*) 44))
+ {
+ m_pProg->GetError(code, start, end);
+ delete m_pProg;
+ m_pProg = NULL;
+
+ delete pThisRobot;
+
+ m_pEdit->SetSel( start, end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ TextError = CBotProgram::GivErrorText( code );
+ AfxMessageBox( TextError );
+
+ m_pEdit->SetFocus();
+ return;
+ }
+
+ pf = fOpen( "TEST.CBO", "rb" );
+ CBotClass::RestoreStaticState(pf);
+ m_pProg->RestoreState(pf);
+ fClose(pf);
+
+ int start2, end2;
+ m_pProg->GetRunPos(FunctionName, start2, end2);
+ if ( end2 <= 0 )
+ m_pProg->GetRunPos(FunctionName, start2, end2);
+
+ if ( start1 != start2 || end1 != end2 )
+ m_pProg->GetRunPos(FunctionName, start2, end2);
+ m_pEdit->SetSel(start2, end2);
+ }
+
+ if (m_pProg->GetError(code, start, end))
+ {
+ m_pEdit->SetSel(start, end);
+ TextError = CBotProgram::GivErrorText(code);
+ AfxMessageBox(TextError);
+ }
+ return;}
+
+ while (!m_pProg->Run(NULL, 0))
+ {
+ const char* FunctionName;
+ int start, end;
+ m_pProg->GetRunPos(FunctionName, start, end);
+ m_pEdit->SetSel(start, end);
+
+ if ( FunctionName == NULL ) continue;
+ CString info (FunctionName);
+ CString sep (":\n");
+
+ int level = 0;
+ const char* Name;
+ while ( TRUE )
+ {
+ CBotVar* pVar = m_pProg->GivStackVars(Name, level--);
+ if ( Name != FunctionName ) break;
+ if ( pVar == NULL ) continue;
+// pVar->Maj(NULL, FALSE);
+ while ( pVar != NULL )
+ {
+ info += sep;
+ info += pVar->GivName() + " = " + pVar->GivValString();
+ sep = ", ";
+ pVar = pVar->GivNext();
+ }
+ sep = "\n";
+ }
+ if ( IDOK != AfxMessageBox(info, MB_OKCANCEL) ) break;
+
+ if ( test == 1 )
+ {
+ test = 0;
+ FILE* pf;
+ pf = fOpen( "TEST.CBO", "wb" );
+ m_pProg->SaveState(pf);
+ fClose(pf);
+ }
+
+ if ( test == 2 )
+ {
+ test = 0;
+ FILE* pf;
+ pf = fOpen( "TEST.CBO", "rb" );
+ m_pProg->RestoreState(pf);
+ fClose(pf);
+ }
+
+ if ( test == 12 )
+ {
+ test = 0;
+ FILE* pf;
+ pf = fOpen( "TEST.CBO", "wb" );
+ m_pProg->SaveState(pf);
+ fClose(pf);
+
+ pf = fOpen( "TEST.CBO", "rb" );
+ m_pProg->RestoreState(pf);
+ fClose(pf);
+
+ test = 13;
+ }
+ }
+
+ if (m_pProg->GetError(code, start, end))
+ {
+ m_pEdit->SetSel(start, end);
+ TextError = CBotProgram::GivErrorText(code);
+ AfxMessageBox(TextError);
+ }
+
+ delete pThisRobot;
+}
+
diff --git a/src/CBot/TestCBot/TestCBotDoc.h b/src/CBot/TestCBot/TestCBotDoc.h
new file mode 100644
index 0000000..d8275b5
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBotDoc.h
@@ -0,0 +1,64 @@
+// TestCBotDoc.h : interface of the CTestCBotDoc class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_TESTCBOTDOC_H__4D1BB90B_8E74_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_TESTCBOTDOC_H__4D1BB90B_8E74_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+
+class CTestCBotDoc : public CDocument
+{
+protected: // create from serialization only
+ CTestCBotDoc();
+ DECLARE_DYNCREATE(CTestCBotDoc)
+
+// Attributes
+public:
+ CEdit* m_pEdit; // pour mémoriser le texte, et l'afficher
+ CBotProgram* m_pProg; // le programme compilé
+ CString m_DocText;
+ CBotStringArray m_Liste;
+ BOOL m_bModified;
+
+// Operations
+public:
+ BOOL Compile();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTestCBotDoc)
+ public:
+ virtual BOOL OnNewDocument();
+ virtual void Serialize(CArchive& ar);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CTestCBotDoc();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CTestCBotDoc)
+ afx_msg void OnRun();
+ afx_msg void OnChangeEdit1();
+ afx_msg void OnTest();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TESTCBOTDOC_H__4D1BB90B_8E74_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/TestCBotView.cpp b/src/CBot/TestCBot/TestCBotView.cpp
new file mode 100644
index 0000000..052e756
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBotView.cpp
@@ -0,0 +1,126 @@
+// TestCBotView.cpp : implementation of the CTestCBotView class
+//
+
+#include "stdafx.h"
+#include "TestCBot.h"
+
+#include "TestCBotDoc.h"
+#include "TestCBotView.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotView
+
+IMPLEMENT_DYNCREATE(CTestCBotView, CView)
+
+BEGIN_MESSAGE_MAP(CTestCBotView, CView)
+ //{{AFX_MSG_MAP(CTestCBotView)
+ ON_WM_SIZE()
+ ON_MESSAGE(WM_ACTWINDOW, ActWindow)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotView construction/destruction
+
+CTestCBotView::CTestCBotView()
+{
+}
+
+CTestCBotView::~CTestCBotView()
+{
+}
+
+BOOL CTestCBotView::PreCreateWindow(CREATESTRUCT& cs)
+{
+ return CView::PreCreateWindow(cs);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotView drawing
+
+void CTestCBotView::OnDraw(CDC* pDC)
+{
+ CTestCBotDoc* pDoc = GetDocument();
+ ASSERT_VALID(pDoc);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotView diagnostics
+
+#ifdef _DEBUG
+void CTestCBotView::AssertValid() const
+{
+ CView::AssertValid();
+}
+
+void CTestCBotView::Dump(CDumpContext& dc) const
+{
+ CView::Dump(dc);
+}
+
+CTestCBotDoc* CTestCBotView::GetDocument() // non-debug version is inline
+{
+ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTestCBotDoc)));
+ return (CTestCBotDoc*)m_pDocument;
+}
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CTestCBotView message handlers
+
+void CTestCBotView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
+{
+ CTestCBotDoc* pDoc = GetDocument();
+// CTestCBotApp* pApp = (CTestCBotApp*)AfxGetApp();
+
+ if ( pDoc->m_pEdit == NULL)
+ {
+ pDoc->m_pEdit = new CEdit();
+ CRect rect;
+ GetClientRect( rect );
+
+ pDoc->m_pEdit->Create( WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_MULTILINE|ES_WANTRETURN|ES_NOHIDESEL|ES_AUTOVSCROLL,
+ rect, this, IDC_EDIT1 );
+ pDoc->m_pEdit->SetTabStops(12);
+ pDoc->m_pEdit->SetWindowText(pDoc->m_DocText);
+ }
+
+ if ( !bActivate && !pDoc->Compile() )
+ {
+// comment faire pour réactiver l'ancien document
+ }
+
+ CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
+
+ if ( bActivate ) pDoc->m_pEdit->SetFocus();
+}
+
+
+void CTestCBotView::OnSize(UINT nType, int cx, int cy)
+{
+ CView::OnSize(nType, cx, cy);
+
+ CTestCBotDoc* pDoc = GetDocument();
+ if ( pDoc->m_pEdit != NULL )
+ {
+ CRect rect;
+ GetClientRect( rect );
+ pDoc->m_pEdit->MoveWindow( rect );
+ pDoc->m_pEdit->SetFocus();
+ }
+}
+
+
+
+LONG CTestCBotView::ActWindow(UINT wparam, LONG lparam)
+{
+// GetParentFrame()->SetActiveView( this, TRUE );
+// CMDIChildWnd::OnMDIActivate(1, this, this)
+ return 0;
+}
diff --git a/src/CBot/TestCBot/TestCBotView.h b/src/CBot/TestCBot/TestCBotView.h
new file mode 100644
index 0000000..bca156f
--- /dev/null
+++ b/src/CBot/TestCBot/TestCBotView.h
@@ -0,0 +1,64 @@
+// TestCBotView.h : interface of the CTestCBotView class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_TESTCBOTVIEW_H__4D1BB90D_8E74_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_TESTCBOTVIEW_H__4D1BB90D_8E74_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CTestCBotView : public CView
+{
+protected: // create from serialization only
+ CTestCBotView();
+ DECLARE_DYNCREATE(CTestCBotView)
+
+// Attributes
+public:
+ CTestCBotDoc* GetDocument();
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTestCBotView)
+ public:
+ virtual void OnDraw(CDC* pDC); // overridden to draw this view
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+ protected:
+ virtual void OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CTestCBotView();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CTestCBotView)
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg LONG ActWindow(UINT wparam, LONG lparam) ;
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+#ifndef _DEBUG // debug version in TestCBotView.cpp
+inline CTestCBotDoc* CTestCBotView::GetDocument()
+ { return (CTestCBotDoc*)m_pDocument; }
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TESTCBOTVIEW_H__4D1BB90D_8E74_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/TestCBot/TestNull.txt b/src/CBot/TestCBot/TestNull.txt
new file mode 100644
index 0000000..f447245
--- /dev/null
+++ b/src/CBot/TestCBot/TestNull.txt
@@ -0,0 +1,15 @@
+extern public void TestNull ()
+{
+ CPoint pointeur = null;
+
+ try {
+ pointeur.x = 4; }
+ catch ( 6007 ) {}
+
+ pointeur = new CPoint(1,2);
+
+ print ( pointeur.x, pointeur.y,
+ pointeur );
+
+ pointeur.x = 5;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/TestRestoreState.txt b/src/CBot/TestCBot/TestRestoreState.txt
new file mode 100644
index 0000000..1e49e37
--- /dev/null
+++ b/src/CBot/TestCBot/TestRestoreState.txt
@@ -0,0 +1,67 @@
+// routine de Daniel qui plante après RestoreState
+
+extern void object::Attack( )
+{
+ int list[], i;
+ object p;
+ float dist, prox;
+ point nav1, nav2, dest;
+ boolean advance = true;
+
+ i = 0;
+ list[i++] = WingedGrabber;
+ list[i++] = TrackedGrabber;
+ list[i++] = WheeledGrabber;
+ list[i++] = LeggedGrabber;
+ list[i++] = WingedShooter;
+ list[i++] = TrackedShooter;
+ list[i++] = WheeledShooter;
+ list[i++] = LeggedShooter;
+ list[i++] = WingedOrgaShooter;
+ list[i++] = TrackedOrgaShooter;
+ list[i++] = WheeledOrgaShooter;
+ list[i++] = LeggedOrgaShooter;
+ list[i++] = WingedSniffer;
+ list[i++] = TrackedSniffer;
+ list[i++] = WheeledSniffer;
+ list[i++] = LeggedSniffer;
+ list[i++] = Thumper;
+ list[i++] = PhazerShooter;
+ list[i++] = Recycler;
+ list[i++] = Shielder;
+ list[i++] = Subber;
+ list[i++] = Me;
+
+ nav1.x = 1;//cmdline(0);
+ nav1.y = 1;//cmdline(1);
+ nav2.x = 2;//cmdline(2);
+ nav2.y = 2;//cmdline(3);
+
+ while ( true )
+ {
+ while ( true )
+ {
+ // ennemi à proximité ?
+ p = radar(list, 0, 360, 0, 40);
+ if ( p == null ) break;
+ // lui tire dessus
+ fire(p.position);
+ }
+
+ // se promène vers le point A
+ goto(nav1);
+
+ while ( true )
+ {
+ // ennemi à proximité ?
+ p = radar(list, 0, 360, 0, 40);
+ if ( p == null ) break;
+ // lui tire dessus
+ fire(p.position);
+ }
+
+ // se promène vers le point B
+ goto(nav2);
+ }
+}
+
diff --git a/src/CBot/TestCBot/TestStatic.txt b/src/CBot/TestCBot/TestStatic.txt
new file mode 100644
index 0000000..f501aa5
--- /dev/null
+++ b/src/CBot/TestCBot/TestStatic.txt
@@ -0,0 +1,31 @@
+class ESSAI
+{
+ int x = 0;
+ static int nb = 3;
+ static int [ ] array ;
+
+ void Put( int val)
+ {
+show(nb);
+ array[ nb ] = val;
+// this.nb++;
+ this.nb = this.nb + 1;
+show(nb, array);
+ }
+ int Get( )
+ {
+ nb--;
+show("out", nb, array);
+ return array[ nb ] ;
+ }
+}
+
+extern public void T()
+{
+ ESSAI t1 ( ) ;
+ ESSAI t2 ( ) ;
+ t1.nb++;
+ t1.Put( 11 ); t1.Put( 12 ); t2.Put( 13 );
+
+ show ( t1.Get(), t2.Get(), t2.Get() ) ;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/TestStr.txt b/src/CBot/TestCBot/TestStr.txt
new file mode 100644
index 0000000..683ec1b
--- /dev/null
+++ b/src/CBot/TestCBot/TestStr.txt
@@ -0,0 +1,17 @@
+extern public void TSTR()
+{
+ string s = "C'est un essai";
+
+ print ( s, strlen(s), strleft(s, 3), strright(s,3), strmid(s, 2), strmid(s,2,3), strfind(s, "un"), strfind(s, "sdgfld") );
+
+ show ( strupper(s), strlower(s) );
+
+ s = "123.45" ;
+ print ( strval(s) );
+
+
+ string sub = strright("abcdef", 2); // sub vaut "ef###", # étant un caractère bizarre quelconque
+ show (sub);
+ int pos = strfind("abcdef", "xy"); // pos vaut -1. Pourquoi pas nan ?
+ show(pos);
+}
diff --git a/src/CBot/TestCBot/Z.txt b/src/CBot/TestCBot/Z.txt
new file mode 100644
index 0000000..714119b
--- /dev/null
+++ b/src/CBot/TestCBot/Z.txt
@@ -0,0 +1,14 @@
+public extern void tp()
+{
+ int a [4], b[];
+ a [ 0 ] = 8 ;
+
+ b = T ( a ) ;
+ show ( a, b );
+}
+
+int[] T ( int[] Z )
+{
+ for ( int i = 0; i < 4 ; i++ ) Z[ i ] = i * i ;
+ return Z;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/array.txt b/src/CBot/TestCBot/array.txt
new file mode 100644
index 0000000..081b60e
--- /dev/null
+++ b/src/CBot/TestCBot/array.txt
@@ -0,0 +1,24 @@
+
+public extern void TestTableau ()
+{
+ int tableau [ 12 ] ;
+
+ point array[ 12 ] [ 14 ] ;
+
+ point zéro ( 1, 2 ) ;
+ point a = zéro ;
+
+ for ( int i = 0 ; i < 10 ; i++ ) array[ i ] [ i ]= zéro ;
+
+ array[ 5 ] [3 ] . x =1.5 ;
+
+ array[ 2 ] [ 2 ] . y = array[ 5 ] [ 5 ] . x ;
+
+ array[ 4 ] = array [ 2 ] ;
+
+ for ( int i = 0 ; i < 10 ; i++ ) for ( int j = 0 ; j < 4 ; j++ ) println ( i, j, array [ i ] [ j ] ) ;
+
+ show( zéro, a, array );
+
+}
+
diff --git a/src/CBot/TestCBot/a§1.txt b/src/CBot/TestCBot/a§1.txt
new file mode 100644
index 0000000..0c57950
--- /dev/null
+++ b/src/CBot/TestCBot/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/TestCBot/bug.txt
new file mode 100644
index 0000000..4ec6eb3
--- /dev/null
+++ b/src/CBot/TestCBot/bug.txt
@@ -0,0 +1,12 @@
+public extern void object::Bug()
+{
+ point a;
+ a = position;
+ TEST();
+ float d=dist(a, position);
+}
+
+float dist(point a, point b)
+{
+ return a.x-b.x;
+}
diff --git a/src/CBot/TestCBot/bugmw.txt b/src/CBot/TestCBot/bugmw.txt
new file mode 100644
index 0000000..284ee43
--- /dev/null
+++ b/src/CBot/TestCBot/bugmw.txt
@@ -0,0 +1,9 @@
+extern public void main()
+{
+ show(fact(30)) ;
+}
+
+public int fact(int n)
+{
+ return (fact(n-1)*n) ;
+}
diff --git a/src/CBot/TestCBot/ccc.txt b/src/CBot/TestCBot/ccc.txt
new file mode 100644
index 0000000..dbcd1d5
--- /dev/null
+++ b/src/CBot/TestCBot/ccc.txt
@@ -0,0 +1,8 @@
+public extern void ccc()
+{
+ int a;
+ a = 0 ;
+
+ if ( a == 0 );
+
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/enum.txt b/src/CBot/TestCBot/enum.txt
new file mode 100644
index 0000000..a592a7f
--- /dev/null
+++ b/src/CBot/TestCBot/enum.txt
@@ -0,0 +1,9 @@
+
+enum JourDeLaSemaine {
+ lundi = 1,
+ mardi,
+ mercredi,
+ jeudi,
+ vendredi,
+ samedi,
+ dimanche = 0 } \ No newline at end of file
diff --git a/src/CBot/TestCBot/fibo.txt b/src/CBot/TestCBot/fibo.txt
new file mode 100644
index 0000000..88f5357
--- /dev/null
+++ b/src/CBot/TestCBot/fibo.txt
@@ -0,0 +1,25 @@
+
+extern public int Fibo( int n, boolean b )
+{
+ if ( n < 2 ) return n;
+ int a = Fibo(n-1, b) + Fibo(n-2, false);
+ if ( b ) print (n + "=" + a);
+ return a;
+}
+
+extern public void t()
+{
+ Fibo( 23, true);
+}
+
+extern public void tt()
+{
+ t();
+}
+
+// cette routine n'est évidemment pas du tout obtimisée
+// c'est même un très mauvais exemple de programmation récursive
+
+// pour un test de durée, Fibo(23, true) prend
+// en mode Debug 67 secondes
+// en mode Release 8 secondes
diff --git a/src/CBot/TestCBot/file.txt b/src/CBot/TestCBot/file.txt
new file mode 100644
index 0000000..2a22dd9
--- /dev/null
+++ b/src/CBot/TestCBot/file.txt
@@ -0,0 +1,70 @@
+class CLASS22
+{
+ static int nb = 2;
+ void T22 ( ) { nb = nb / 0 ; }
+}
+
+public extern void object :: TEST()
+{
+ switch ( 1 )
+ {
+ case 1:
+ {
+ file h();
+ h.open("Mon Fichier.txt", "r");
+show ( h.filename, h.handle );
+h.filename = "xx";
+h.handle = 1 ;
+ h.readln();
+ h.close();
+ }
+ case 2:
+ {
+ file h("Mon Fichier.txt");
+ h.open("r");
+ h.readln();
+ h.close();
+ }
+ case 3:
+ {
+ file h("Mon Fichier.txt", "r");
+ h.readln();
+ h.close();
+ }
+ case 4:
+ {
+ file h();
+ h.filename = "Mon Fichier.txt";
+ h.open("r");
+ h.readln();
+ h.close();
+ }
+ case 5:
+ {
+ file h = fileopen( "Mon 2Fichier.txt", "r" );
+ h.readln();
+ h.close();
+ }
+ }
+{
+ file h( ) ;
+ h.filename = "Test.h";
+ h.open ( "r" );
+
+
+ file pf ( "Mon Fichier.txt" ) ;
+ pf . open ( "w" ) ;
+ pf . writeln ( "Voici encore du texte" ) ;
+ pf . writeln ( "et une seconde ligne" ) ;
+ pf . close( );
+
+ pf . open ( "r" ) ;
+
+ while ( not pf . eof( ) )
+ {
+ string s = pf . readln ( );
+ show ( s );
+ }
+ pf.close( );
+}
+}
diff --git a/src/CBot/TestCBot/h.txt b/src/CBot/TestCBot/h.txt
new file mode 100644
index 0000000..c395319
--- /dev/null
+++ b/src/CBot/TestCBot/h.txt
@@ -0,0 +1,5 @@
+void tf()
+{
+ file h;
+ h.handle += 1 ;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/include.txt b/src/CBot/TestCBot/include.txt
new file mode 100644
index 0000000..e8f8cc9
--- /dev/null
+++ b/src/CBot/TestCBot/include.txt
@@ -0,0 +1,27 @@
+class Z
+{
+ static int x = 0;
+ private int y;
+
+ void T( )
+ {
+ // autorisé ici
+ y = x ;
+ this.y = this.x ;
+ x = y ;
+ this.x = this.y ;
+ }
+}
+
+extern public void test()
+{
+ Z a();
+ 3 * a.x; // autorisé
+//vu 3 * a.y; // interdit
+//vu a.y = 3; // interdit ici
+ a.x = 1; // autorisé
+
+ show ( a );
+ a.T();
+ show ( a );
+}
diff --git a/src/CBot/TestCBot/intrinsic.txt b/src/CBot/TestCBot/intrinsic.txt
new file mode 100644
index 0000000..f215791
--- /dev/null
+++ b/src/CBot/TestCBot/intrinsic.txt
@@ -0,0 +1,16 @@
+public extern void TestIntrinsic()
+{
+ point a ( 1, 2 );
+ print (a);
+
+ a.x = 3;
+ a.y = 4;
+
+ point b = a;
+
+ println ( b.x, b.y, b ) ;
+ if ( b == a ) b.y = 0;
+ println (a,b);
+ if ( b != a ) b.y = a.y;
+ println(a,b);
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/methode1.txt b/src/CBot/TestCBot/methode1.txt
new file mode 100644
index 0000000..080bba2
--- /dev/null
+++ b/src/CBot/TestCBot/methode1.txt
@@ -0,0 +1,57 @@
+class t {
+ point p;
+}
+
+void object :: toto()
+{
+ show ( Position ) ;
+}
+
+extern public void object :: XX()
+{
+ int test [];
+ test [ 9999 ] = 3;
+
+ toto () ;
+/*
+ Radar();
+
+ object test ;
+ test = this. Radar();
+
+ do {
+ test = this.Radar();
+ } while ( test == null );
+
+/*
+ t test [ 4 ];
+ for ( int i = 0 ; i < 4 ; i++ ) test [ i ] = new t();
+ test [ 3 ] .p.x = 2;
+ show ( test );
+/*
+ int a = nan;
+ show ( a ) ;
+
+ a = TypeMarkPath;
+ show ( a, a++, --a ) ;
+
+ if ( a != nan ) a += 1 ;
+
+ a = TypeMarkPath;
+ float q = a ;
+ show ( a, q ) ;
+
+return;
+
+ a += ++a;
+ show ( a ) ;
+
+ boolean i = false;
+
+ if ( i == true ) {}
+
+ object p;
+ if ( p == null) { p = p ; }
+*/
+}
+
diff --git a/src/CBot/TestCBot/methode2.txt b/src/CBot/TestCBot/methode2.txt
new file mode 100644
index 0000000..76ce7f4
--- /dev/null
+++ b/src/CBot/TestCBot/methode2.txt
@@ -0,0 +1,50 @@
+
+extern void Toto()
+{
+ TEST(12);
+
+ for ( int i = 0 ; i<1000; i++)
+ {
+ int j = 1;
+ if (i==55) TEST(12);
+ }
+
+ TEST(2);
+
+
+// Nouveau();
+ int toto[4];
+ point Z[3];
+
+ Z[1].x = 11; Z[1].y = 12;
+
+ toto[2] = 12;
+ toto[1] = nan;
+
+// point test, autre(2,3) ;
+// object titi = Radar();
+
+ TEST ( 1 ) ;
+
+ toto[0] = 11;
+
+ TEST ( 2 ) ;
+
+ toto[6] = 0;
+}
+
+extern void object::Nouveau()
+{
+ point a;
+ a = np(Position);
+}
+
+point np(point b)
+{
+ point c;
+ c.x = b.y;
+ c.y = b.x;
+ return c ;
+}
+
+
diff --git a/src/CBot/TestCBot/mp1.txt b/src/CBot/TestCBot/mp1.txt
new file mode 100644
index 0000000..599cfc4
--- /dev/null
+++ b/src/CBot/TestCBot/mp1.txt
@@ -0,0 +1,25 @@
+class Guepet
+{
+
+ float a;
+ float b;
+
+ void init()
+ {
+ a = 12.34;
+ b = 56.78;
+ }
+
+
+}
+
+extern void object::Fourmi6()
+{
+ Guepet guepe =new Guepet();
+
+ guepe.init();
+
+
+ show("test "+guepe.a+" "+guepe.b);
+
+}
diff --git a/src/CBot/TestCBot/mp2.txt b/src/CBot/TestCBot/mp2.txt
new file mode 100644
index 0000000..1c2972c
--- /dev/null
+++ b/src/CBot/TestCBot/mp2.txt
@@ -0,0 +1,28 @@
+class Guepet
+{
+
+ float a;
+ float b;
+
+ void init()
+ {
+ a = 12.34;
+ b = 56.78;
+
+ object x = radar(123);
+ show("radar "+x.position.x);
+ show("C'est fait");
+ }
+
+
+}
+
+extern void object::Fourmi6()
+{
+ Guepet guepe=new Guepet();
+
+ guepe.init();
+
+ show("test "+guepe.a+" "+guepe.b);
+
+}
diff --git a/src/CBot/TestCBot/mw.txt b/src/CBot/TestCBot/mw.txt
new file mode 100644
index 0000000..c237670
--- /dev/null
+++ b/src/CBot/TestCBot/mw.txt
@@ -0,0 +1,16 @@
+extern public void main()
+{
+// goto( 3, 4 );
+
+ while( true )
+ {
+ try { goto (12) ; }
+ catch( FF( ) )
+ { show( "ko"); }
+ }
+}
+
+boolean FF()
+{
+ return false;
+}
diff --git a/src/CBot/TestCBot/null.txt b/src/CBot/TestCBot/null.txt
new file mode 100644
index 0000000..ae76b74
--- /dev/null
+++ b/src/CBot/TestCBot/null.txt
@@ -0,0 +1,5 @@
+extern public void xxx ()
+{
+ CPoint test = null ;
+ if ( test == null ) show ( "NULL" );
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/opnew.txt b/src/CBot/TestCBot/opnew.txt
new file mode 100644
index 0000000..7d6838c
--- /dev/null
+++ b/src/CBot/TestCBot/opnew.txt
@@ -0,0 +1,20 @@
+extern public void xx ()
+{
+ CPoint pointeur, test = null ;
+ pointeur = new CPoint ( 3, 4 );
+
+ if ( test == null ) show ( "NULL" );
+
+ CPoint pp = pointeur;
+
+show( pointeur , pp );
+
+ pp.x = 33.3;
+ if ( pointeur.x != pp.x ) 0/0;
+
+ pp = new CPoint();
+// pointeur = pp;
+
+show( pointeur , pp );
+
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/plante.txt b/src/CBot/TestCBot/plante.txt
new file mode 100644
index 0000000..363461b
--- /dev/null
+++ b/src/CBot/TestCBot/plante.txt
@@ -0,0 +1,25 @@
+class Guepet
+{
+
+ point pos;
+ float t = 0.1;
+
+ void init()
+ {
+ pos.x = 12.123;
+ pos.y = 34.345;
+
+ F(t);
+ }
+
+
+}
+
+extern void object::Fourmi6()
+{
+ Guepet guepe=new Guepet();
+
+ guepe.init();
+
+ show ( guepe );
+}
diff --git a/src/CBot/TestCBot/pointer.txt b/src/CBot/TestCBot/pointer.txt
new file mode 100644
index 0000000..2d4d907
--- /dev/null
+++ b/src/CBot/TestCBot/pointer.txt
@@ -0,0 +1,41 @@
+extern public void x ()
+{
+ show ( 3 ** 4 );
+ float z = 1e-3;
+ show ( z );
+
+ CPoint b ( 4,5 );
+ show ( b );
+
+ CPoint a ( ) ;
+ a.x = 21; a.y = 12;
+ show ( a ) ;
+
+ CPoint test = new CPoint ( 1,1 );
+ test = new CPoint ( 2, 2 );
+ show ( test );
+}
+
+// crée un objet et retourne son pointeur
+CPoint newcpoint()
+{
+ CPoint p = new CPoint ( 3, 3 );
+ return p;
+}
+
+extern public void y ()
+{
+ CPoint test = newcpoint();
+ println ( test );
+ dontmodif( test );
+ println ( test );
+}
+
+// ne doit pas modifier l'objet en paramètre
+void dontmodif ( CPoint pp )
+{
+ pp.x = 5;
+ pp.y = 2;
+ println ( pp, pp.x, pp.y );
+}
+
diff --git a/src/CBot/TestCBot/postinc.txt b/src/CBot/TestCBot/postinc.txt
new file mode 100644
index 0000000..cdf6ab5
--- /dev/null
+++ b/src/CBot/TestCBot/postinc.txt
@@ -0,0 +1,7 @@
+extern public void X()
+{
+ point A [ ] ;
+ A[5] = new point (2,3);
+ int val = A[5].x++ + --A[5].y;
+ show ( A, val );
+}
diff --git a/src/CBot/TestCBot/radar.txt b/src/CBot/TestCBot/radar.txt
new file mode 100644
index 0000000..09d84a2
--- /dev/null
+++ b/src/CBot/TestCBot/radar.txt
@@ -0,0 +1,39 @@
+extern void object::Bug( )
+{
+ try{ int a = 44 ; a = 12 / 0 ; }
+ catch(6000) { int b = 4 ; }
+ finally { int z = 1 ; }
+
+// tp ( A, B );
+
+/* int a = 4, b = 2, c = nan;
+ float x, y = 3/2, z = nan;
+ boolean i, j = false, k = true;
+
+ string s, ss = "xyz";
+
+ while ( false )
+ {
+ object left, right;
+
+ left = Radar(TypeMarkPath, -45, 120, 100);
+ right = Radar(TypeMarkPath, 45, 120, 100);
+
+ if ( left == null && right == null )
+ {
+ }
+ }
+ int t = fact ( 4 ) ;*/
+}
+
+void tp( point a , point b )
+{
+ a.x += b.x;
+}
+
+
+int fact( int n )
+{
+ if ( n < 2 ) return n;
+ return n * fact ( n - 1 ) ;
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/res/TestCBot.ico b/src/CBot/TestCBot/res/TestCBot.ico
new file mode 100644
index 0000000..06a649d
--- /dev/null
+++ b/src/CBot/TestCBot/res/TestCBot.ico
Binary files differ
diff --git a/src/CBot/TestCBot/res/TestCBot.rc2 b/src/CBot/TestCBot/res/TestCBot.rc2
new file mode 100644
index 0000000..b55f0d9
--- /dev/null
+++ b/src/CBot/TestCBot/res/TestCBot.rc2
@@ -0,0 +1,13 @@
+//
+// TESTCBOT.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/src/CBot/TestCBot/res/TestCBotDoc.ico b/src/CBot/TestCBot/res/TestCBotDoc.ico
new file mode 100644
index 0000000..3545614
--- /dev/null
+++ b/src/CBot/TestCBot/res/TestCBotDoc.ico
Binary files differ
diff --git a/src/CBot/TestCBot/res/Toolbar.bmp b/src/CBot/TestCBot/res/Toolbar.bmp
new file mode 100644
index 0000000..04a71af
--- /dev/null
+++ b/src/CBot/TestCBot/res/Toolbar.bmp
Binary files differ
diff --git a/src/CBot/TestCBot/resource.h b/src/CBot/TestCBot/resource.h
new file mode 100644
index 0000000..bed36ca
--- /dev/null
+++ b/src/CBot/TestCBot/resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by TestCBot.rc
+//
+#define IDD_ABOUTBOX 100
+#define IDR_MAINFRAME 128
+#define IDR_TESTCBTYPE 129
+#define IDD_DIALOG1 130
+#define IDD_CONSOLE 131
+#define IDD_DIALOG2 133
+#define IDC_EDIT1 1000
+#define TX_TYPENAMES 1000
+#define IDC_SPIN1 1001
+#define IDC_EDIT2 1002
+#define IDC_COMBO1 1003
+#define IDC_EDIT3 1004
+#define ID_RUN 32771
+#define ID_TEST 32772
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_3D_CONTROLS 1
+#define _APS_NEXT_RESOURCE_VALUE 135
+#define _APS_NEXT_COMMAND_VALUE 32773
+#define _APS_NEXT_CONTROL_VALUE 1004
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/CBot/TestCBot/solution.txt b/src/CBot/TestCBot/solution.txt
new file mode 100644
index 0000000..f78cf12
--- /dev/null
+++ b/src/CBot/TestCBot/solution.txt
@@ -0,0 +1,13 @@
+extern void object::Solution( )
+{
+show ( "Solution " + Position );
+ Carré(15);
+ Carré(25);
+}
+
+void object::Carré(float côté)
+{
+show ( "Carré " + Position );
+ Move(côté);
+ Turn(-90);
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/test.txt b/src/CBot/TestCBot/test.txt
new file mode 100644
index 0000000..a912415
--- /dev/null
+++ b/src/CBot/TestCBot/test.txt
@@ -0,0 +1,8 @@
+extern public void x()
+{
+ float a= 1, b = 2;
+ a = b * ( 2 + 2 );
+// print (a);
+ a += 4;
+// print (a);
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/test23.txt b/src/CBot/TestCBot/test23.txt
new file mode 100644
index 0000000..d6e1ddd
--- /dev/null
+++ b/src/CBot/TestCBot/test23.txt
@@ -0,0 +1,10 @@
+extern public void object::TEST23()
+{
+ CLASS22 T;
+ T.T22( ) ;
+
+ show( position );
+ show( this.position );
+
+// T22();
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/testmw.txt b/src/CBot/TestCBot/testmw.txt
new file mode 100644
index 0000000..6570f6d
--- /dev/null
+++ b/src/CBot/TestCBot/testmw.txt
@@ -0,0 +1,14 @@
+extern public int testmw( int a)
+{
+ boolean b = true ;
+
+ if (b)
+ return 1 ;
+ else
+ return a ; 0 * testmw(a-1) ;
+}
+
+public int Fibo2 ( int n )
+{
+ print ( " bof " );
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/this.txt b/src/CBot/TestCBot/this.txt
new file mode 100644
index 0000000..b8a9e04
--- /dev/null
+++ b/src/CBot/TestCBot/this.txt
@@ -0,0 +1,13 @@
+extern void object :: TEST22 ( )
+{
+ show( position );
+ show( this.position );
+
+ T();
+}
+
+public void object :: T22()
+{
+ show( position );
+ show( this.position );
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/tt.txt b/src/CBot/TestCBot/tt.txt
new file mode 100644
index 0000000..cd13c9d
--- /dev/null
+++ b/src/CBot/TestCBot/tt.txt
@@ -0,0 +1,12 @@
+extern public void T() { T1(); }
+
+public void T1()
+{
+ show( "T1" );
+ T2();
+}
+
+public void T2()
+{
+ show( "T2" );
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/tt2.txt b/src/CBot/TestCBot/tt2.txt
new file mode 100644
index 0000000..ad9dc1d
--- /dev/null
+++ b/src/CBot/TestCBot/tt2.txt
@@ -0,0 +1,5 @@
+extern public void TT()
+{
+ T1();
+ T2();
+} \ No newline at end of file
diff --git a/src/CBot/TestCBot/vide.txt b/src/CBot/TestCBot/vide.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/CBot/TestCBot/vide.txt
diff --git a/src/CBot/TestCBot/xTestCBot.clw b/src/CBot/TestCBot/xTestCBot.clw
new file mode 100644
index 0000000..5b84c16
--- /dev/null
+++ b/src/CBot/TestCBot/xTestCBot.clw
@@ -0,0 +1,245 @@
+; CLW file contains information for the MFC ClassWizard
+
+[General Info]
+Version=1
+LastClass=CBotConsoleDlg
+LastTemplate=CDialog
+NewFileInclude1=#include "stdafx.h"
+NewFileInclude2=#include "TestCBot.h"
+LastPage=0
+
+ClassCount=7
+Class1=CTestCBotApp
+Class2=CTestCBotDoc
+Class3=CTestCBotView
+Class4=CMainFrame
+
+ResourceCount=7
+Resource1=IDD_ABOUTBOX
+Resource2=IDR_MAINFRAME
+Resource3=IDR_TESTCBTYPE
+Class5=CAboutDlg
+Class6=CChildFrame
+Resource4=IDD_ABOUTBOX (French (France))
+Resource5=IDR_TESTCBTYPE (French (France))
+Resource6=IDD_CONSOLE
+Class7=CBotConsoleDlg
+Resource7=IDR_MAINFRAME (French (France))
+
+[CLS:CTestCBotApp]
+Type=0
+HeaderFile=TestCBot.h
+ImplementationFile=TestCBot.cpp
+Filter=N
+
+[CLS:CTestCBotDoc]
+Type=0
+HeaderFile=TestCBotDoc.h
+ImplementationFile=TestCBotDoc.cpp
+Filter=N
+BaseClass=CDocument
+VirtualFilter=DC
+LastObject=IDC_EDIT2
+
+[CLS:CTestCBotView]
+Type=0
+HeaderFile=TestCBotView.h
+ImplementationFile=TestCBotView.cpp
+Filter=C
+BaseClass=CView
+VirtualFilter=VWC
+LastObject=CTestCBotView
+
+[CLS:CMainFrame]
+Type=0
+HeaderFile=MainFrm.h
+ImplementationFile=MainFrm.cpp
+Filter=T
+BaseClass=CMDIFrameWnd
+VirtualFilter=fWC
+LastObject=CMainFrame
+
+
+[CLS:CChildFrame]
+Type=0
+HeaderFile=ChildFrm.h
+ImplementationFile=ChildFrm.cpp
+Filter=M
+
+[CLS:CAboutDlg]
+Type=0
+HeaderFile=TestCBot.cpp
+ImplementationFile=TestCBot.cpp
+Filter=D
+
+[DLG:IDD_ABOUTBOX]
+Type=1
+ControlCount=4
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308352
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+Class=CAboutDlg
+
+[MNU:IDR_MAINFRAME]
+Type=1
+Class=CMainFrame
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command4=ID_APP_EXIT
+Command5=ID_VIEW_TOOLBAR
+Command6=ID_VIEW_STATUS_BAR
+Command7=ID_APP_ABOUT
+CommandCount=7
+Command3=ID_FILE_MRU_FILE1
+
+[TB:IDR_MAINFRAME]
+Type=1
+Class=CMainFrame
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command4=ID_EDIT_CUT
+Command5=ID_EDIT_COPY
+Command6=ID_EDIT_PASTE
+Command7=ID_FILE_PRINT
+CommandCount=8
+Command8=ID_APP_ABOUT
+
+[MNU:IDR_TESTCBTYPE]
+Type=1
+Class=CTestCBotView
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_CLOSE
+Command4=ID_FILE_SAVE
+Command5=ID_FILE_SAVE_AS
+Command9=ID_EDIT_CUT
+Command10=ID_EDIT_COPY
+Command11=ID_EDIT_PASTE
+Command12=ID_VIEW_TOOLBAR
+Command13=ID_VIEW_STATUS_BAR
+Command14=ID_WINDOW_NEW
+CommandCount=18
+Command6=ID_FILE_MRU_FILE1
+Command7=ID_APP_EXIT
+Command8=ID_EDIT_UNDO
+Command15=ID_WINDOW_CASCADE
+Command16=ID_WINDOW_TILE_HORZ
+Command17=ID_WINDOW_ARRANGE
+Command18=ID_APP_ABOUT
+
+[ACL:IDR_MAINFRAME]
+Type=1
+Class=CMainFrame
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command5=ID_EDIT_CUT
+Command6=ID_EDIT_COPY
+Command7=ID_EDIT_PASTE
+Command8=ID_EDIT_UNDO
+Command9=ID_EDIT_CUT
+Command10=ID_EDIT_COPY
+Command11=ID_EDIT_PASTE
+Command12=ID_NEXT_PANE
+CommandCount=13
+Command4=ID_EDIT_UNDO
+Command13=ID_PREV_PANE
+
+
+[TB:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command4=ID_EDIT_CUT
+Command5=ID_EDIT_COPY
+Command6=ID_EDIT_PASTE
+Command7=ID_FILE_PRINT
+Command8=ID_RUN
+Command9=ID_APP_ABOUT
+CommandCount=9
+
+[MNU:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_MRU_FILE1
+Command4=ID_APP_EXIT
+Command5=ID_VIEW_TOOLBAR
+Command6=ID_VIEW_STATUS_BAR
+Command7=ID_APP_ABOUT
+CommandCount=7
+
+[MNU:IDR_TESTCBTYPE (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_CLOSE
+Command4=ID_FILE_SAVE
+Command5=ID_FILE_SAVE_AS
+Command6=ID_FILE_MRU_FILE1
+Command7=ID_APP_EXIT
+Command8=ID_EDIT_UNDO
+Command9=ID_EDIT_CUT
+Command10=ID_EDIT_COPY
+Command11=ID_EDIT_PASTE
+Command12=ID_VIEW_TOOLBAR
+Command13=ID_VIEW_STATUS_BAR
+Command14=ID_WINDOW_NEW
+Command15=ID_WINDOW_CASCADE
+Command16=ID_WINDOW_TILE_HORZ
+Command17=ID_WINDOW_ARRANGE
+Command18=ID_APP_ABOUT
+CommandCount=18
+
+[ACL:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_EDIT_COPY
+Command2=ID_FILE_NEW
+Command3=ID_FILE_OPEN
+Command4=ID_FILE_SAVE
+Command5=ID_EDIT_PASTE
+Command6=ID_EDIT_UNDO
+Command7=ID_EDIT_CUT
+Command8=ID_RUN
+Command9=ID_NEXT_PANE
+Command10=ID_PREV_PANE
+Command11=ID_RUN
+Command12=ID_EDIT_COPY
+Command13=ID_EDIT_PASTE
+Command14=ID_EDIT_CUT
+Command15=ID_EDIT_UNDO
+CommandCount=15
+
+[DLG:IDD_ABOUTBOX (French (France))]
+Type=1
+Class=CAboutDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308480
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+
+[DLG:IDD_CONSOLE]
+Type=1
+Class=CBotConsoleDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342308352
+Control2=IDC_EDIT2,edit,1350631552
+Control3=IDOK,button,1342242817
+Control4=IDC_EDIT1,edit,1352734724
+
+[CLS:CBotConsoleDlg]
+Type=0
+HeaderFile=CBotConsoleDlg.h
+ImplementationFile=CBotConsoleDlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+
diff --git a/src/CBot/TestCBot/zz.txt b/src/CBot/TestCBot/zz.txt
new file mode 100644
index 0000000..da764ac
--- /dev/null
+++ b/src/CBot/TestCBot/zz.txt
@@ -0,0 +1,6 @@
+extern public void zz()
+{
+ MaClass TOTO ();
+
+ show (TOTO);
+} \ No newline at end of file
diff --git a/src/CBot/_Copy.bat b/src/CBot/_Copy.bat
new file mode 100644
index 0000000..510dc5a
--- /dev/null
+++ b/src/CBot/_Copy.bat
@@ -0,0 +1,2 @@
+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
new file mode 100644
index 0000000..32163db
--- /dev/null
+++ b/src/CBot/colobot.ini
@@ -0,0 +1,49 @@
+[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
new file mode 100644
index 0000000..7153789
--- /dev/null
+++ b/src/CBot/idees.txt
@@ -0,0 +1,39 @@
+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
+
+il faut un autre type de variable pour garder les pointeurs
+CBotTypPtClass par exemple
+
+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.
+
+
+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) { }
+
+pResult dans ce cas est un pointeur CBotTypPtClass
+lorsqu'il a trouvé le robot concerné, il lui faudra faire
+
+pResult->SetPointeur(InstanceDeLaClassObject);
+
+cette opération incrémente le compteur des références
+
+--
+
+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
+
+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 CBotAddExpr.cpp b/src/CBot/old CBotAddExpr.cpp
new file mode 100644
index 0000000..85b7588
--- /dev/null
+++ b/src/CBot/old CBotAddExpr.cpp
@@ -0,0 +1,130 @@
+///////////////////////////////////////////////////
+// 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, CBotCStack* pStack)
+{
+ CBotCStack* 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 = pStk->GetType(CBotTypChar); // 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 = pStk->GetType(CBotTypChar); // de quel type le résultat ?
+
+ if ( type1 == type2 && // les résultats sont-ils compatibles
+ type1 != CBotTypBoolean &&
+ (inst->m_token.GetType() != ID_SUB ||
+ type1 < CBotTypBoolean )) // pas de soustraction de chaînes !
+ {
+ // 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);
+ }
+ 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);
+}
+
+
+
+
+// fait l'opération d'addition ou de soustraction
+
+BOOL CBotAddExpr::Execute(CBotStack* &pStack)
+{
+ CBotStack* pStk1 = pStack->AddStack(); // ajoute un élément à la pile
+ // ou le retrouve en cas de reprise
+
+ // 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 = CBotVar::Create( 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
+}
+
+
diff --git a/src/CBot/old CBotCompExpr.cpp b/src/CBot/old CBotCompExpr.cpp
new file mode 100644
index 0000000..e7439b7
--- /dev/null
+++ b/src/CBot/old CBotCompExpr.cpp
@@ -0,0 +1,120 @@
+///////////////////////////////////////////////////
+// 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;
+}
+
+
+// compile une instruction de type A < B
+
+CBotInstr* CBotCompExpr::Compile(CBotToken* &p, CBotCStack* pStack)
+{
+ CBotCStack* pStk = pStack->TokenStack();
+
+ 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 = pStk->GetType(CBotTypChar);
+
+ p = p->Next();
+ if ( NULL != (inst->m_rightop = CBotAddExpr::Compile( p, pStk )) ) // expression A + B à droite
+ {
+ type2 = pStk->GetType(CBotTypChar);
+ // les résultats sont-ils compatibles
+ if ( type1 == type2 && type1 != CBotTypBoolean && type1 != CBotTypClass)
+ {
+ inst->m_leftop = left;
+ pStk->SetVar(new CBotVar(NULL, CBotTypBoolean));
+ // le résultat est un boolean
+ return pStack->Return(inst, pStk);
+ }
+ pStk->SetError(TX_BAD2TYPE, &inst->m_token);
+ }
+
+ 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();
+
+ 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* temp = CBotVar::Create( NULL, MAX(type1, type2) );
+ CBotVar* result = CBotVar::Create( NULL, CBotTypBoolean );
+
+ switch (GetTokenType())
+ {
+ case ID_LO:
+ temp->Lo(pStk1->GetVar(), pStk2->GetVar()); // inférieur
+ break;
+ case ID_HI:
+ temp->Hi(pStk1->GetVar(), pStk2->GetVar()); // supérieur
+ break;
+ case ID_LS:
+ temp->Ls(pStk1->GetVar(), pStk2->GetVar()); // inférieur ou égal
+ break;
+ case ID_HS:
+ temp->Hs(pStk1->GetVar(), pStk2->GetVar()); // supérieur ou égal
+ break;
+ case ID_EQ:
+ temp->Eq(pStk1->GetVar(), pStk2->GetVar()); // égal
+ break;
+ case ID_NE:
+ temp->Ne(pStk1->GetVar(), pStk2->GetVar()); // différent
+ break;
+ }
+ result->SetValInt(temp->GetValInt()); // converti le résultat
+ delete temp;
+
+ 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
+}
+
diff --git a/src/CBot/old TstCBot/BotConsoleDlg.cpp b/src/CBot/old TstCBot/BotConsoleDlg.cpp
new file mode 100644
index 0000000..077f080
--- /dev/null
+++ b/src/CBot/old TstCBot/BotConsoleDlg.cpp
@@ -0,0 +1,164 @@
+// BotConsoleDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+#include "BotConsoleDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotConsoleDlg dialog
+
+
+CBotConsoleDlg::CBotConsoleDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CBotConsoleDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CBotConsoleDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+ m_pProg = NULL;
+ m_threadinfo.m_bRun = FALSE;
+}
+
+
+void CBotConsoleDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CBotConsoleDlg)
+ DDX_Control(pDX, IDOK, m_cOK);
+ DDX_Control(pDX, IDC_EDIT2, m_Edit2);
+ DDX_Control(pDX, IDC_EDIT1, m_Edit1);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CBotConsoleDlg, CDialog)
+ //{{AFX_MSG_MAP(CBotConsoleDlg)
+ ON_MESSAGE(WM_ENDPROG, EndProg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotConsoleDlg message handlers
+
+UINT ThreadProc(ThreadInfo *info)
+{
+ CTime t0 = CTime::GetCurrentTime();
+ int Cpt = 0;
+
+ info->m_pProg->Start("LaCommande");
+ while ( !info->m_bStop && !info->m_pProg->Run() )
+ {
+ Cpt++;
+ if ( Cpt%20 == 0 ) info->m_pEdit1->ReplaceSel(".");
+ }
+
+ if ( info->m_bStop )
+ {
+ info->m_pEdit1->ReplaceSel("\r\nInterrompu\r\n");
+ }
+ else if (info->m_pProg->GivError() == 0)
+ {
+ CTime t = CTime::GetCurrentTime();
+ CTimeSpan ts = t - t0;
+
+ char buffer[200];
+ sprintf( buffer, "\r\nExécution terminée en %d secondes.\r\nInterrompue %d fois.\r\n",
+ ts.GetTotalSeconds(), Cpt);
+
+ info->m_pEdit1->ReplaceSel(buffer);
+ }
+
+ info->m_pWndMessage->SendMessage(WM_ENDPROG, 0, 0) ;
+ return 0 ;
+}
+
+LONG CBotConsoleDlg::EndProg(UINT wparam, LONG lparam)
+{
+ m_threadinfo.m_bRun = FALSE;
+
+ if (m_pProg->GetError(m_code, m_start, m_end))
+ {
+ AfxMessageBox(m_code);
+ CDialog::OnCancel();
+ return 1;
+ }
+ delete m_pProg;
+ m_pProg = NULL;
+
+ m_Edit2.EnableWindow(TRUE);
+ m_cOK.EnableWindow(TRUE);
+
+ m_Edit2.SetWindowText("");
+ m_Edit2.SetFocus();
+ return 0 ;
+}
+
+void CBotConsoleDlg::OnOK()
+{
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+ pApp->m_pConsole = &m_Edit1;
+
+ CString Commande;
+ m_Edit2.GetWindowText(Commande);
+
+ CString s = "void LaCommande() { " + Commande + " ;}";
+ m_pProg = new CBotProgram();
+ CBotStringArray liste;
+ m_pProg->Compile(s, liste);
+ int err, start, end;
+ if ( m_pProg->GetError(err, start, end) )
+ {
+ AfxMessageBox(err);
+ m_Edit2.SetSel(start-20, end-20);
+ return;
+ }
+
+ m_Edit1.ReplaceSel(Commande + " ->\r\n");
+
+ m_Edit2.SetWindowText("");
+ m_Edit1.SetFocus();
+ m_Edit2.EnableWindow(FALSE);
+ m_cOK.EnableWindow(FALSE);
+
+ // lance un processus paralèle pour l'exécution
+ m_threadinfo.m_pWndMessage = this ;
+
+ m_threadinfo.m_pEdit1 = &m_Edit1;
+ m_threadinfo.m_pProg = m_pProg;
+ m_threadinfo.m_bStop = FALSE;
+ m_threadinfo.m_bRun = TRUE;
+
+ AfxBeginThread((AFX_THREADPROC)ThreadProc, &m_threadinfo) ;
+}
+
+void CBotConsoleDlg::OnCancel()
+{
+ if (!m_threadinfo.m_bRun) CDialog::OnCancel();
+ m_threadinfo.m_bStop = TRUE ;
+}
+
+
+BOOL CBotConsoleDlg::OnInitDialog()
+{
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+
+ CDialog::OnInitDialog();
+
+ m_Edit1.ReplaceSel("Les fonctions suivantes sont disponibles:\r\n");
+ for ( int i = 0; i < pApp->m_Liste.RetSize(); i++ )
+ {
+ CBotString x = CString(pApp->m_Liste[i]) + "\r\n";
+ m_Edit1.ReplaceSel(x);
+ }
+ m_Edit1.ReplaceSel("Entrez une commande ci-dessous.\r\n\r\n");
+
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
diff --git a/src/CBot/old TstCBot/BotConsoleDlg.h b/src/CBot/old TstCBot/BotConsoleDlg.h
new file mode 100644
index 0000000..9b54ff2
--- /dev/null
+++ b/src/CBot/old TstCBot/BotConsoleDlg.h
@@ -0,0 +1,65 @@
+#if !defined(AFX_BOTCONSOLEDLG_H__A11450A2_8E09_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_BOTCONSOLEDLG_H__A11450A2_8E09_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// BotConsoleDlg.h : header file
+//
+
+struct ThreadInfo
+{
+ CEdit* m_pEdit1 ;
+ CBotProgram* m_pProg;
+ CWnd* m_pWndMessage;
+ BOOL m_bStop;
+ BOOL m_bRun;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotConsoleDlg dialog
+
+class CBotConsoleDlg : public CDialog
+{
+// Construction
+public:
+ CBotConsoleDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CBotConsoleDlg)
+ enum { IDD = IDD_CONSOLE };
+ CButton m_cOK;
+ CEdit m_Edit2;
+ CEdit m_Edit1;
+ //}}AFX_DATA
+
+ CBotProgram* m_pProg;
+ ThreadInfo m_threadinfo;
+
+ int m_code, m_start, m_end;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CBotConsoleDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CBotConsoleDlg)
+ virtual void OnOK();
+ virtual void OnCancel();
+ virtual BOOL OnInitDialog();
+ afx_msg LONG EndProg(UINT wparam, LONG lparam) ;
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_BOTCONSOLEDLG_H__A11450A2_8E09_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/old TstCBot/BotErrorDlg.cpp b/src/CBot/old TstCBot/BotErrorDlg.cpp
new file mode 100644
index 0000000..87d56f0
--- /dev/null
+++ b/src/CBot/old TstCBot/BotErrorDlg.cpp
@@ -0,0 +1,56 @@
+// BotErrorDlg.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+#include "BotErrorDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotErrorDlg dialog
+
+
+CBotErrorDlg::CBotErrorDlg(CWnd* pParent /*=NULL*/)
+ : CDialog(CBotErrorDlg::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CBotErrorDlg)
+ m_TextProgram = _T("");
+ //}}AFX_DATA_INIT
+}
+
+
+void CBotErrorDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CBotErrorDlg)
+ DDX_Control(pDX, IDC_EDIT1, m_eProgram);
+ DDX_Control(pDX, IDC_STATIC1, m_sMessage);
+ DDX_Text(pDX, IDC_EDIT1, m_TextProgram);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CBotErrorDlg, CDialog)
+ //{{AFX_MSG_MAP(CBotErrorDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotErrorDlg message handlers
+
+BOOL CBotErrorDlg::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ m_sMessage.SetWindowText(m_TextError);
+ m_eProgram.SetFocus();
+ m_eProgram.SetSel(m_start, m_end);
+
+ return FALSE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
diff --git a/src/CBot/old TstCBot/BotErrorDlg.h b/src/CBot/old TstCBot/BotErrorDlg.h
new file mode 100644
index 0000000..522afad
--- /dev/null
+++ b/src/CBot/old TstCBot/BotErrorDlg.h
@@ -0,0 +1,51 @@
+#if !defined(AFX_BOTERRORDLG_H__80E73D20_7454_11D4_A439_00D059085115__INCLUDED_)
+#define AFX_BOTERRORDLG_H__80E73D20_7454_11D4_A439_00D059085115__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// BotErrorDlg.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CBotErrorDlg dialog
+
+class CBotErrorDlg : public CDialog
+{
+// Construction
+public:
+ CBotErrorDlg(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CBotErrorDlg)
+ enum { IDD = IDD_DIALOG1 };
+ CEdit m_eProgram;
+ CStatic m_sMessage;
+ CString m_TextProgram;
+ //}}AFX_DATA
+
+
+ CString m_TextError;
+ int m_start, m_end;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CBotErrorDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CBotErrorDlg)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_BOTERRORDLG_H__80E73D20_7454_11D4_A439_00D059085115__INCLUDED_)
diff --git a/src/CBot/old TstCBot/CBotTest.txt b/src/CBot/old TstCBot/CBotTest.txt
new file mode 100644
index 0000000..ce20e26
--- /dev/null
+++ b/src/CBot/old TstCBot/CBotTest.txt
@@ -0,0 +1,36 @@
+
+extern void TheTest()
+{
+ for (int x = 130; x>0; x--) print (x);
+}
+
+extern void Test()
+{
+ int var = 10000 ;
+ while (var > 0) var = var -1;
+}
+// exécuté en 30 secondes
+
+extern void Autre()
+{
+ int var = 10000 ;
+ while (var > 0) if ( var > 0 ) var = var -1;
+}
+// exécuté en 45 secondes
+
+int Y ( int n )
+{
+ if ( n < 2 ) return n;
+ int a = Y(n-1) + Y(n-2);
+ return a;
+}
+
+extern int X ( int n )
+{
+ if ( n < 2 ) { print(n); return n; }
+ int a = X(n-1) + Y(n-2);
+ print (a);
+ return a;
+}
+
+
diff --git a/src/CBot/old TstCBot/CMyThread.cpp b/src/CBot/old TstCBot/CMyThread.cpp
new file mode 100644
index 0000000..ca92c77
--- /dev/null
+++ b/src/CBot/old TstCBot/CMyThread.cpp
@@ -0,0 +1,107 @@
+// CMyThread.cpp : pour créer un processus pour la console
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+#include "CMyThread.h"
+#include "BotConsoleDlg.h"
+
+
+//IMPLEMENT_DYNAMIC (CMyThread, CWinThread)
+IMPLEMENT_DYNCREATE (CMyThread, CWinThread)
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyThread
+
+BEGIN_MESSAGE_MAP(CMyThread, CWinThread)
+ //{{AFX_MSG_MAP(CMyThread)
+ //}}AFX_MSG_MAP
+ // Standard file based document commands
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyThread construction
+
+CMyThread::CMyThread()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyThread initialization
+/*
+BOOL CMyThread::InitInstance()
+{
+ AfxEnableControlContainer();
+
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+
+ // ouvre une fenêtre pour afficher les sorties
+ CRect rect;
+ AfxGetMainWnd()->GetClientRect( rect );
+ rect += CPoint(30,30);
+
+ CWnd* pWnd = new CWnd();
+ pWnd->CreateEx( 0,
+ AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
+ "CBot console", WS_POPUPWINDOW|WS_CAPTION|WS_VISIBLE,
+ rect,
+ AfxGetMainWnd()->GetParent(), NULL, NULL);
+ m_pMainWnd = pWnd;
+
+ pApp->m_pEdit2 = new CEdit();
+
+ m_pMainWnd->GetClientRect( rect );
+ rect.bottom -= 40;
+ pApp->m_pEdit2->Create( WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_MULTILINE|ES_WANTRETURN|
+ ES_AUTOVSCROLL|ES_READONLY,
+ rect, m_pMainWnd, IDC_EDIT2 );
+
+ pApp->m_pEdit2->ReplaceSel("Les fonctions suivantes sont disponibles:\n\r");
+ for ( int i = 0; i < pApp->m_Liste.RetSize(); i++ )
+ {
+ pApp->m_pEdit2->ReplaceSel(pApp->m_Liste[i] + "\r\n");
+ }
+ pApp->m_pEdit2->ReplaceSel("Entrez une commande ci-dessous.\r\r");
+
+
+// pApp->m_pEdit2->SetFocus();
+
+ pApp->m_pEdit3 = new CEdit();
+ m_pMainWnd->GetClientRect( rect );
+ rect.top = rect.bottom-40;
+ pApp->m_pEdit3->Create( WS_VISIBLE|WS_BORDER|WS_TABSTOP,
+ rect, m_pMainWnd, IDC_EDIT1 );
+ pApp->m_pEdit3->SetFocus();
+
+ return TRUE;
+}*/
+
+BOOL CMyThread::InitInstance()
+{
+ CBotConsoleDlg dlg;
+ m_pMainWnd = &dlg; // cela ferme l'application avec la DBOX !
+
+ int nResponse = dlg.DoModal();
+
+ return TRUE;
+}
+
+
+int CMyThread::ExitInstance()
+{
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CMyThread message handlers
+
+
+void CMyThread::OnReturn()
+{
+ // TODO: Add your command handler code here
+ __asm int 3;
+}
diff --git a/src/CBot/old TstCBot/CMyThread.h b/src/CBot/old TstCBot/CMyThread.h
new file mode 100644
index 0000000..1134077
--- /dev/null
+++ b/src/CBot/old TstCBot/CMyThread.h
@@ -0,0 +1,44 @@
+// CMyThread.h : pour créer un processus pour la console
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_MAINFRM_H__20B3756C_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+#define AFX_MAINFRM_H__20B3756C_5DFD_11D4_A15E_00E0189013DF__INCLUDED_
+
+
+#include "stdafx.h"
+#include "TstCBot.h"
+
+class CMyThread : public CWinThread
+{
+// DECLARE_DYNAMIC(CMyThread)
+ DECLARE_DYNCREATE(CMyThread)
+
+public:
+
+
+// Constructor
+ CMyThread();
+ virtual BOOL InitInstance();
+ virtual int ExitInstance(); // return app exit code
+
+// Implementation
+
+ //{{AFX_MSG(CTstCBotApp)
+ afx_msg void OnAppAbout();
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CMainFrame)
+ afx_msg void OnReturn();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MAINFRM_H__20B3756C_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
diff --git a/src/CBot/old TstCBot/MainFrm.cpp b/src/CBot/old TstCBot/MainFrm.cpp
new file mode 100644
index 0000000..6c0962c
--- /dev/null
+++ b/src/CBot/old TstCBot/MainFrm.cpp
@@ -0,0 +1,91 @@
+// MainFrm.cpp : implementation of the CMainFrame class
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+
+#include "MainFrm.h"
+#include "BotErrorDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame
+
+IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
+
+BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
+ //{{AFX_MSG_MAP(CMainFrame)
+ ON_WM_CREATE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+static UINT indicators[] =
+{
+ ID_SEPARATOR, // status line indicator
+ ID_INDICATOR_CAPS,
+ ID_INDICATOR_NUM,
+ ID_INDICATOR_SCRL,
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame construction/destruction
+
+CMainFrame::CMainFrame()
+{
+ // TODO: add member initialization code here
+
+}
+
+CMainFrame::~CMainFrame()
+{
+}
+
+int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+ if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
+ return -1;
+
+ if (!m_wndStatusBar.Create(this) ||
+ !m_wndStatusBar.SetIndicators(indicators,
+ sizeof(indicators)/sizeof(UINT)))
+ {
+ TRACE0("Failed to create status bar\n");
+ return -1; // fail to create
+ }
+
+ return 0;
+}
+
+BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
+{
+ // TODO: Modify the Window class or styles here by modifying
+ // the CREATESTRUCT cs
+
+ return CFrameWnd::PreCreateWindow(cs);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame diagnostics
+
+#ifdef _DEBUG
+void CMainFrame::AssertValid() const
+{
+ CFrameWnd::AssertValid();
+}
+
+void CMainFrame::Dump(CDumpContext& dc) const
+{
+ CFrameWnd::Dump(dc);
+}
+
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CMainFrame message handlers
+
+
diff --git a/src/CBot/old TstCBot/MainFrm.h b/src/CBot/old TstCBot/MainFrm.h
new file mode 100644
index 0000000..56b9c41
--- /dev/null
+++ b/src/CBot/old TstCBot/MainFrm.h
@@ -0,0 +1,55 @@
+// MainFrm.h : interface of the CMainFrame class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_MAINFRM_H__70B3756C_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+#define AFX_MAINFRM_H__70B3756C_5DFD_11D4_A15E_00E0189013DF__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CMainFrame : public CFrameWnd
+{
+protected: // create from serialization only
+ CMainFrame();
+ DECLARE_DYNCREATE(CMainFrame)
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMainFrame)
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CMainFrame();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected: // control bar embedded members
+ CStatusBar m_wndStatusBar;
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CMainFrame)
+ afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+ afx_msg void OnCp1();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MAINFRM_H__70B3756C_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
diff --git a/src/CBot/old TstCBot/ReadMe.txt b/src/CBot/old TstCBot/ReadMe.txt
new file mode 100644
index 0000000..67dc05b
--- /dev/null
+++ b/src/CBot/old TstCBot/ReadMe.txt
@@ -0,0 +1,93 @@
+========================================================================
+ MICROSOFT FOUNDATION CLASS LIBRARY : TstCBot
+========================================================================
+
+
+AppWizard has created this TstCBot application for you. This application
+not only demonstrates the basics of using the Microsoft Foundation classes
+but is also a starting point for writing your application.
+
+This file contains a summary of what you will find in each of the files that
+make up your TstCBot application.
+
+TstCBot.h
+ This is the main header file for the application. It includes other
+ project specific headers (including Resource.h) and declares the
+ CTstCBotApp application class.
+
+TstCBot.cpp
+ This is the main application source file that contains the application
+ class CTstCBotApp.
+
+TstCBot.rc
+ This is a listing of all of the Microsoft Windows resources that the
+ program uses. It includes the icons, bitmaps, and cursors that are stored
+ in the RES subdirectory. This file can be directly edited in Microsoft
+ Developer Studio.
+
+res\TstCBot.ico
+ This is an icon file, which is used as the application's icon. This
+ icon is included by the main resource file TstCBot.rc.
+
+res\TstCBot.rc2
+ This file contains resources that are not edited by Microsoft
+ Developer Studio. You should place all resources not
+ editable by the resource editor in this file.
+
+TstCBot.clw
+ This file contains information used by ClassWizard to edit existing
+ classes or add new classes. ClassWizard also uses this file to store
+ information needed to create and edit message maps and dialog data
+ maps and to create prototype member functions.
+
+/////////////////////////////////////////////////////////////////////////////
+
+For the main frame window:
+
+MainFrm.h, MainFrm.cpp
+ These files contain the frame class CMainFrame, which is derived from
+ CFrameWnd and controls all SDI frame features.
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+AppWizard creates one document type and one view:
+
+TstCBotDoc.h, TstCBotDoc.cpp - the document
+ These files contain your CTstCBotDoc class. Edit these files to
+ add your special document data and to implement file saving and loading
+ (via CTstCBotDoc::Serialize).
+
+TstCBotView.h, TstCBotView.cpp - the view of the document
+ These files contain your CTstCBotView class.
+ CTstCBotView objects are used to view CTstCBotDoc objects.
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named TstCBot.pch and a precompiled types file named StdAfx.obj.
+
+Resource.h
+ This is the standard header file, which defines new resource IDs.
+ Microsoft Developer Studio reads and updates this file.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" to indicate parts of the source code you
+should add to or customize.
+
+If your application uses MFC in a shared DLL, and your application is
+in a language other than the operating system's current language, you
+will need to copy the corresponding localized resources MFC40XXX.DLL
+from the Microsoft Visual C++ CD-ROM onto the system or system32 directory,
+and rename it to be MFCLOC.DLL. ("XXX" stands for the language abbreviation.
+For example, MFC40DEU.DLL contains resources translated to German.) If you
+don't do this, some of the UI elements of your application will remain in the
+language of the operating system.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/src/CBot/old TstCBot/Resource.h b/src/CBot/old TstCBot/Resource.h
new file mode 100644
index 0000000..6863fd8
--- /dev/null
+++ b/src/CBot/old TstCBot/Resource.h
@@ -0,0 +1,68 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by TstCBot.rc
+//
+#define IDD_ABOUTBOX 100
+#define IDR_MAINFRAME 128
+#define IDR_TSTCBOTYPE 129
+#define IDD_DIALOG1 130
+#define IDD_CONSOLE 131
+#define IDC_EDIT1 1000
+#define TX_TYPENAMES 1000
+#define IDC_STATIC1 1001
+#define IDC_EDIT2 1002
+#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_DIVZERO 6000
+#define TX_NOTINIT 6001
+#define TX_BADTHROW 6002
+#define TX_NORETVAL 6003
+#define TX_NORUN 6004
+#define TX_NOCALL 6005
+#define ID_CP1 32771
+#define ID_EXE 32772
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_3D_CONTROLS 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 32775
+#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/CBot/old TstCBot/StdAfx.cpp b/src/CBot/old TstCBot/StdAfx.cpp
new file mode 100644
index 0000000..ae0ec93
--- /dev/null
+++ b/src/CBot/old TstCBot/StdAfx.cpp
@@ -0,0 +1,6 @@
+// stdafx.cpp : source file that includes just the standard includes
+// TstCBot.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/src/CBot/old TstCBot/StdAfx.h b/src/CBot/old TstCBot/StdAfx.h
new file mode 100644
index 0000000..7d46ace
--- /dev/null
+++ b/src/CBot/old TstCBot/StdAfx.h
@@ -0,0 +1,26 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#if !defined(AFX_STDAFX_H__70B3756A_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+#define AFX_STDAFX_H__70B3756A_5DFD_11D4_A15E_00E0189013DF__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+#include <afxdisp.h> // MFC OLE automation classes
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_STDAFX_H__70B3756A_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
diff --git a/src/CBot/old TstCBot/TstCBot.clw b/src/CBot/old TstCBot/TstCBot.clw
new file mode 100644
index 0000000..4c54168
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBot.clw
@@ -0,0 +1,189 @@
+; CLW file contains information for the MFC ClassWizard
+
+[General Info]
+Version=1
+LastClass=CTstCBotView
+LastTemplate=CDialog
+NewFileInclude1=#include "stdafx.h"
+NewFileInclude2=#include "TstCBot.h"
+LastPage=0
+
+ClassCount=7
+Class1=CTstCBotApp
+Class2=CTstCBotDoc
+Class3=CTstCBotView
+Class4=CMainFrame
+
+ResourceCount=6
+Resource1=IDD_ABOUTBOX
+Resource2=IDR_MAINFRAME
+Class5=CAboutDlg
+Resource3=IDD_ABOUTBOX (French (France))
+Resource4=IDD_CONSOLE
+Class6=CBotErrorDlg
+Resource5=IDD_DIALOG1 (French (Switzerland))
+Class7=CBotConsoleDlg
+Resource6=IDR_MAINFRAME (French (France))
+
+[CLS:CTstCBotApp]
+Type=0
+HeaderFile=TstCBot.h
+ImplementationFile=TstCBot.cpp
+Filter=N
+
+[CLS:CTstCBotDoc]
+Type=0
+HeaderFile=TstCBotDoc.h
+ImplementationFile=TstCBotDoc.cpp
+Filter=N
+BaseClass=CDocument
+VirtualFilter=DC
+LastObject=CTstCBotDoc
+
+[CLS:CTstCBotView]
+Type=0
+HeaderFile=TstCBotView.h
+ImplementationFile=TstCBotView.cpp
+Filter=C
+BaseClass=CView
+VirtualFilter=VWC
+LastObject=CTstCBotView
+
+[CLS:CMainFrame]
+Type=0
+HeaderFile=MainFrm.h
+ImplementationFile=MainFrm.cpp
+Filter=T
+BaseClass=CFrameWnd
+VirtualFilter=fWC
+LastObject=CMainFrame
+
+
+
+[CLS:CAboutDlg]
+Type=0
+HeaderFile=TstCBot.cpp
+ImplementationFile=TstCBot.cpp
+Filter=D
+
+[DLG:IDD_ABOUTBOX]
+Type=1
+Class=CAboutDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308480
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+
+[MNU:IDR_MAINFRAME]
+Type=1
+Class=CMainFrame
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command4=ID_FILE_SAVE_AS
+Command5=ID_FILE_MRU_FILE1
+Command6=ID_APP_EXIT
+Command7=ID_EDIT_UNDO
+Command8=ID_EDIT_CUT
+Command9=ID_EDIT_COPY
+Command10=ID_EDIT_PASTE
+Command11=ID_VIEW_STATUS_BAR
+Command12=ID_CP1
+Command13=ID_EXE
+Command14=ID_APP_ABOUT
+CommandCount=14
+
+[ACL:IDR_MAINFRAME]
+Type=1
+Class=CMainFrame
+Command1=ID_CP1
+Command2=ID_FILE_NEW
+Command3=ID_FILE_OPEN
+Command4=ID_FILE_SAVE
+Command5=ID_EXE
+Command6=ID_EDIT_UNDO
+Command7=ID_EDIT_CUT
+Command8=ID_EXE
+Command9=ID_CP1
+Command10=ID_EXE
+CommandCount=10
+
+[MNU:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_FILE_NEW
+Command2=ID_FILE_OPEN
+Command3=ID_FILE_SAVE
+Command4=ID_FILE_SAVE_AS
+Command5=ID_FILE_MRU_FILE1
+Command6=ID_APP_EXIT
+Command7=ID_EDIT_UNDO
+Command8=ID_EDIT_CUT
+Command9=ID_EDIT_COPY
+Command10=ID_EDIT_PASTE
+Command11=ID_VIEW_STATUS_BAR
+Command12=ID_CP1
+Command13=ID_EXE
+Command14=ID_APP_ABOUT
+CommandCount=14
+
+[ACL:IDR_MAINFRAME (French (France))]
+Type=1
+Class=?
+Command1=ID_CP1
+Command2=ID_FILE_NEW
+Command3=ID_FILE_OPEN
+Command4=ID_FILE_SAVE
+Command5=ID_EXE
+Command6=ID_EDIT_UNDO
+Command7=ID_EDIT_CUT
+Command8=ID_EXE
+Command9=ID_CP1
+Command10=ID_EXE
+CommandCount=10
+
+[DLG:IDD_ABOUTBOX (French (France))]
+Type=1
+Class=CAboutDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342177283
+Control2=IDC_STATIC,static,1342308480
+Control3=IDC_STATIC,static,1342308352
+Control4=IDOK,button,1342373889
+
+[CLS:CBotErrorDlg]
+Type=0
+HeaderFile=BotErrorDlg.h
+ImplementationFile=BotErrorDlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+LastObject=CBotErrorDlg
+
+[DLG:IDD_DIALOG1 (French (Switzerland))]
+Type=1
+ControlCount=4
+Control1=IDOK,button,1342242817
+Control2=IDC_EDIT1,edit,1352728708
+Control3=IDC_STATIC,static,1342308352
+Control4=IDC_STATIC1,static,1342308352
+
+[DLG:IDD_CONSOLE]
+Type=1
+Class=CBotConsoleDlg
+ControlCount=4
+Control1=IDC_STATIC,static,1342308352
+Control2=IDC_EDIT2,edit,1350631552
+Control3=IDOK,button,1342242817
+Control4=IDC_EDIT1,edit,1352734724
+
+[CLS:CBotConsoleDlg]
+Type=0
+HeaderFile=BotConsoleDlg.h
+ImplementationFile=BotConsoleDlg.cpp
+BaseClass=CDialog
+Filter=D
+VirtualFilter=dWC
+LastObject=IDOK
+
diff --git a/src/CBot/old TstCBot/TstCBot.cpp b/src/CBot/old TstCBot/TstCBot.cpp
new file mode 100644
index 0000000..8ac4557
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBot.cpp
@@ -0,0 +1,412 @@
+// TstCBot.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+
+#include "MainFrm.h"
+#include "TstCBotDoc.h"
+#include "TstCBotView.h"
+#include "CMyThread.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+////////////////////////////////////////////////////////////////////
+// routine show()
+// utilisable depuis le programme écrit en CBot
+
+// exécution
+BOOL rShow( CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ CString s;
+
+ if ( pVar == NULL )
+ {
+ Exception = 22; return FALSE;
+ }
+
+ while ( pVar != NULL )
+ {
+ CString ss;
+ ss.LoadString( TX_TYPENAMES + pVar->RetType() );
+ s += ss + " ";
+
+ ss = pVar->RetName();
+ if (ss.IsEmpty()) ss = "<sans nom>";
+ s += ss + " = ";
+
+ s += pVar->RetValString();
+ s += "\n";
+ pVar = pVar->RetNext();
+ }
+
+ AfxMessageBox(s, MB_OK|MB_ICONINFORMATION);
+
+// if ( pResult && pResult->RetType() == CBotTypInt) pResult->SetValInt(123);
+
+ return TRUE; // pas d'interruption
+}
+
+int cShow( CBotVar* &pVar, CBotString& RetClass)
+{
+ if ( pVar == NULL ) return 22;
+ return CBotTypInt; // tous paramètres acceptés, un entier en retour
+}
+
+int cErr( CBotVar* &pVar, CBotString& RetClass)
+{
+ pVar = pVar->RetNext(); // avance le pointeur sur l'erreur
+ return 6666;
+}
+
+////////////////////////////////////////////////////////////////////
+// routine print()
+// utilisable depuis le programme écrit en CBot
+
+// exécution
+BOOL rPrintLn( CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ CString s;
+
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+ CEdit* pEdit = pApp->m_pConsole;
+
+ if (pEdit == NULL) return TRUE;
+ pEdit->GetWindowText(s);
+
+ while ( pVar != NULL )
+ {
+ if ( !s.IsEmpty() ) s += "\r\n";
+ s += pVar->RetValString();
+ pVar = pVar->RetNext();
+ }
+
+ pEdit->SetWindowText(s);
+ pEdit->SetSel(s.GetLength(), s.GetLength());
+ pEdit->SetFocus();
+ return TRUE; // pas d'interruption
+}
+
+BOOL rPrint( CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ CString s;
+
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+ CEdit* pEdit = pApp->m_pConsole;
+
+ if (pEdit == NULL) return TRUE;
+ pEdit->GetWindowText(s);
+
+ while ( pVar != NULL )
+ {
+ if ( !s.IsEmpty() ) s += " ";
+ s += pVar->RetValString();
+ pVar = pVar->RetNext();
+ }
+
+ pEdit->SetWindowText(s);
+ pEdit->SetSel(s.GetLength(), s.GetLength());
+ pEdit->SetFocus();
+ return TRUE; // pas d'interruption
+}
+
+int cPrint( CBotVar* &pVar, CBotString& RetClass)
+{
+ return 0; // tous paramètres acceptés, un entier en retour
+}
+
+
+//////////////////////////////////////////////////////////////////
+// class CPoint pour essayer
+
+// exécution
+BOOL rCPoint( CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ CString s;
+
+ if ( pVar == NULL )return TRUE; // constructeur sans paramètres est ok
+
+ if ( pVar->RetType() > CBotTypDouble )
+ {
+ Exception = 6023; return FALSE;
+ }
+
+ CBotVar* pX = pThis->RetItem("x");
+ if ( pX == NULL )
+ {
+ Exception = 6024; return FALSE;
+ }
+
+ pX->SetValFloat( pVar->RetValFloat() );
+ pVar = pVar->RetNext();
+
+ if ( pVar == NULL )
+ {
+ Exception = 6022; return FALSE;
+ }
+
+ if ( pVar->RetType() > CBotTypDouble )
+ {
+ Exception = 6023; return FALSE;
+ }
+
+ CBotVar* pY = pThis->RetItem("y");
+ if ( pY == NULL )
+ {
+ Exception = 6024; return FALSE;
+ }
+
+ pY->SetValFloat( pVar->RetValFloat() );
+ pVar = pVar->RetNext();
+
+ if ( pVar != NULL )
+ {
+ Exception = 6025; return FALSE;
+ }
+
+ return TRUE; // pas d'interruption
+}
+
+int cCPoint( CBotVar* pThis, CBotVar* &pVar, CBotString& RetClass)
+{
+ // l'objet doit être de la classe CPoint
+ if ( !pThis->IsElemOfClass("CPoint") ) return 6021;
+
+ // ok si aucun paramètres !
+ if ( pVar == NULL ) return 0;
+
+ // paramètre de type numérique svp
+ if ( pVar->RetType() > CBotTypDouble ) return 6023;
+ pVar = pVar->RetNext();
+
+ // il doit y avoir un second paramètre
+ if ( pVar == NULL ) return 6022;
+ // également de type numérique
+ if ( pVar->RetType() > CBotTypDouble )return 6023;
+ pVar = pVar->RetNext();
+
+ // et pas plus de 2 paramètres svp
+ if ( pVar != NULL ) return 6025;
+
+ return 0; // cette fonction retourne void
+}
+
+// méthode déterminant l'opposé
+BOOL rOppose( CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception )
+{
+ CString s;
+
+ if ( pVar != NULL ) // pas de paramètre
+ {
+ Exception = 6025; return FALSE;
+ }
+
+ CBotVar* pvar = pThis->RetItemList(); // demande la chaîne des items
+
+ // tous les paramètres sont des nombres
+ while (pvar != NULL)
+ {
+ pvar->SetValFloat( -pvar->RetValFloat() );
+ pvar = pvar->RetNext();
+ }
+
+ pResult->Copy(pThis);
+ return TRUE; // pas d'interruption
+}
+
+int cOppose( CBotVar* pThis, CBotVar* &pVar, CBotString& RetClass)
+{
+ // l'objet doit être de la classe CPoint
+ if ( !pThis->IsElemOfClass("CPoint") ) return 6021;
+
+ RetClass = "CPoint"; // l'objet rendu est de cette class
+
+ // ok si aucun paramètres !
+ if ( pVar == NULL ) return CBotTypClass; // le paramètre retourné est une instance de la classe
+
+ return TX_OVERPARAM; // ça va pas
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotApp
+
+BEGIN_MESSAGE_MAP(CTstCBotApp, CWinApp)
+ //{{AFX_MSG_MAP(CTstCBotApp)
+ ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ // DO NOT EDIT what you see in these blocks of generated code!
+ //}}AFX_MSG_MAP
+ // Standard file based document commands
+ ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
+ ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotApp construction
+
+CTstCBotApp::CTstCBotApp()
+{
+ // TODO: add construction code here,
+ // Place all significant initialization in InitInstance
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CTstCBotApp object
+
+CTstCBotApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotApp initialization
+
+BOOL CTstCBotApp::InitInstance()
+{
+ AfxEnableControlContainer();
+
+ // Standard initialization
+ // If you are not using these features and wish to reduce the size
+ // of your final executable, you should remove from the following
+ // the specific initialization routines you do not need.
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+ // Change the registry key under which our settings are stored.
+ // You should modify this string to be something appropriate
+ // such as the name of your company or organization.
+ SetRegistryKey(_T("Local AppWizard-Generated Applications"));
+
+ LoadStdProfileSettings(); // Load standard INI file options (including MRU)
+
+ // Register the application's document templates. Document templates
+ // serve as the connection between documents, frame windows and views.
+
+ CSingleDocTemplate* pDocTemplate;
+ pDocTemplate = new CSingleDocTemplate(
+ IDR_MAINFRAME,
+ RUNTIME_CLASS(CTstCBotDoc),
+ RUNTIME_CLASS(CMainFrame), // main SDI frame window
+ RUNTIME_CLASS(CTstCBotView));
+ AddDocTemplate(pDocTemplate);
+
+ // Parse command line for standard shell commands, DDE, file open
+ CCommandLineInfo cmdInfo;
+ ParseCommandLine(cmdInfo);
+
+ // Dispatch commands specified on the command line
+ if (!ProcessShellCommand(cmdInfo))
+ return FALSE;
+
+ // The one and only window has been initialized, so show and update it.
+ m_pMainWnd->ShowWindow(SW_SHOW);
+ m_pMainWnd->UpdateWindow();
+
+
+
+///////////////////////////////////
+// défini la fonction "show()"
+// --------------------------------
+
+ CBotProgram::AddFunction("show", rShow, cShow);
+ CBotProgram::AddFunction("err", rShow, cErr);
+ CBotProgram::AddFunction("print", rPrint, cPrint);
+ CBotProgram::AddFunction("println", rPrintLn, cPrint);
+
+
+///////////////////////////////////
+// définie la classe globale CPoint
+// --------------------------------
+
+ CBotClass* m_pClassPoint;
+
+ m_pClassPoint = new CBotClass("CPoint", NULL);
+ // ajoute le composant ".x"
+ m_pClassPoint->AddItem("x", CBotTypFloat);
+ // ajoute le composant ".y"
+ m_pClassPoint->AddItem("y", CBotTypFloat);
+
+ // ajoute le constructeur pour cette classe
+ m_pClassPoint->AddFunction("CPoint", rCPoint, cCPoint);
+ // ajoute la méthode Opposé
+ m_pClassPoint->AddFunction("Opposé", rOppose, cOppose);
+
+
+//////////////////////////////////////////////////////////////////
+// compile un bout de programme pour voir s'il est bien accessible
+// depuis un autre "module"
+
+ CBotProgram* p = new CBotProgram;
+ CBotStringArray Liste;
+ p->Compile(" public void MonProgram( ) { show (\"mon programme\") ;}", Liste );
+
+ // l'objet n'est pas détruit et plus référencé
+ // je sais c'est pas bien
+
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CAboutDlg dialog used for App About
+
+class CAboutDlg : public CDialog
+{
+public:
+ CAboutDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CAboutDlg)
+ enum { IDD = IDD_ABOUTBOX };
+ //}}AFX_DATA
+
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAboutDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ //{{AFX_MSG(CAboutDlg)
+ // No message handlers
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CAboutDlg)
+ //}}AFX_DATA_INIT
+}
+
+void CAboutDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAboutDlg)
+ //}}AFX_DATA_MAP
+}
+
+BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
+ //{{AFX_MSG_MAP(CAboutDlg)
+ // No message handlers
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+// App command to run the dialog
+void CTstCBotApp::OnAppAbout()
+{
+ CAboutDlg aboutDlg;
+ aboutDlg.DoModal();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotApp commands
diff --git a/src/CBot/old TstCBot/TstCBot.dsp b/src/CBot/old TstCBot/TstCBot.dsp
new file mode 100644
index 0000000..35e5c0b
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBot.dsp
@@ -0,0 +1,180 @@
+# Microsoft Developer Studio Project File - Name="TstCBot" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=TstCBot - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "TstCBot.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "TstCBot.mak" CFG="TstCBot - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "TstCBot - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "TstCBot - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "TstCBot - Win32 Release"
+
+# PROP BASE Use_MFC 6
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 6
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /FR /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x40c /d "NDEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x40c /d "NDEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
+# ADD LINK32 /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "TstCBot - Win32 Debug"
+
+# PROP BASE Use_MFC 6
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 6
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /FR /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x40c /d "_DEBUG" /d "_AFXDLL"
+# ADD RSC /l 0x40c /d "_DEBUG" /d "_AFXDLL"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "TstCBot - Win32 Release"
+# Name "TstCBot - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\BotConsoleDlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MainFrm.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBot.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBot.rc
+
+!IF "$(CFG)" == "TstCBot - Win32 Release"
+
+!ELSEIF "$(CFG)" == "TstCBot - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBotDoc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBotView.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\BotConsoleDlg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MainFrm.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBot.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBotDoc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TstCBotView.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\res\TstCBot.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\TstCBot.rc2
+# End Source File
+# Begin Source File
+
+SOURCE=.\res\TstCBotDoc.ico
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\ReadMe.txt
+# End Source File
+# End Target
+# End Project
diff --git a/src/CBot/old TstCBot/TstCBot.h b/src/CBot/old TstCBot/TstCBot.h
new file mode 100644
index 0000000..616db43
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBot.h
@@ -0,0 +1,62 @@
+// TstCBot.h : main header file for the TSTCBOT application
+//
+
+#if !defined(AFX_TSTCBOT_H__70B37568_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+#define AFX_TSTCBOT_H__70B37568_5DFD_11D4_A15E_00E0189013DF__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+#include "..\CBotDll.h"
+
+
+class CMyThread;
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotApp:
+// See TstCBot.cpp for the implementation of this class
+//
+
+class CTstCBotApp : public CWinApp
+{
+public:
+ CTstCBotApp();
+
+ CMyThread* m_pThread;
+ CWnd* m_pView;
+ CEdit* m_pConsole;
+ CBotStringArray m_Liste;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTstCBotApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CTstCBotApp)
+ afx_msg void OnAppAbout();
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TSTCBOT_H__70B37568_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+
+#define WM_STARTPROG WM_APP + 0
+#define WM_ENDPROG WM_APP + 1
diff --git a/src/CBot/old TstCBot/TstCBot.rc b/src/CBot/old TstCBot/TstCBot.rc
new file mode 100644
index 0000000..9e91c76
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBot.rc
@@ -0,0 +1,471 @@
+//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
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 12, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\TstCBot.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""l.fra\\afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\TstCBot.ico"
+IDR_TSTCBOTYPE ICON DISCARDABLE "res\\TstCBotDoc.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MAINFRAME MENU PRELOAD DISCARDABLE
+BEGIN
+ POPUP "&Fichier"
+ BEGIN
+ MENUITEM "&Nouveau\tCtrl+N", ID_FILE_NEW
+ MENUITEM "&Ouvrir...\tCtrl+O", ID_FILE_OPEN
+ MENUITEM "&Enregistrer\tCtrl+S", ID_FILE_SAVE
+ MENUITEM "En&registrer sous...", ID_FILE_SAVE_AS
+ MENUITEM SEPARATOR
+ MENUITEM "Fichier récent", ID_FILE_MRU_FILE1, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "&Quitter", ID_APP_EXIT
+ END
+ POPUP "&Edition"
+ BEGIN
+ MENUITEM "&Annuler\tCtrl+Z", ID_EDIT_UNDO
+ MENUITEM SEPARATOR
+ MENUITEM "&Couper\tCtrl+X", ID_EDIT_CUT
+ MENUITEM "&Copier\tCtrl+C", ID_EDIT_COPY
+ MENUITEM "C&oller\tCtrl+V", ID_EDIT_PASTE
+ END
+ POPUP "&Affichage"
+ BEGIN
+ MENUITEM "Barre d'é&tat", ID_VIEW_STATUS_BAR
+ END
+ POPUP "&Tests"
+ BEGIN
+ MENUITEM "&Compile\tAlt+C", ID_CP1
+ MENUITEM "&Execute\tAlt+V", ID_EXE
+ END
+ POPUP "&?"
+ BEGIN
+ MENUITEM "&A propos de TstCBot...", ID_APP_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
+BEGIN
+ "C", ID_CP1, VIRTKEY, ALT, NOINVERT
+ "N", ID_FILE_NEW, VIRTKEY, CONTROL, NOINVERT
+ "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
+ "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
+ "V", ID_EXE, VIRTKEY, ALT, NOINVERT
+ VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
+ VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT, NOINVERT
+ VK_F5, ID_EXE, VIRTKEY, NOINVERT
+ VK_F7, ID_CP1, VIRTKEY, NOINVERT
+ "X", ID_EXE, VIRTKEY, ALT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 217, 55
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "A propos de TstCBot"
+FONT 8, "MS Sans Serif"
+BEGIN
+ ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
+ LTEXT "TstCBot version 1.0",IDC_STATIC,40,10,119,8,SS_NOPREFIX
+ LTEXT "Copyright (C) 1900",IDC_STATIC,40,25,119,8
+ DEFPUSHBUTTON "OK",IDOK,178,7,32,14,WS_GROUP
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040C04B0"
+ BEGIN
+ VALUE "CompanyName", "\0"
+ VALUE "FileDescription", "Application MFC TstCBot\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "TstCBot\0"
+ VALUE "LegalCopyright", "Copyright (C) 1900\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "TstCBot.EXE\0"
+ VALUE "ProductName", "Application TstCBot\0"
+ VALUE "ProductVersion", "1, 0, 0, 1\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Traduction", 0x40c, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_ABOUTBOX, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 210
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 48
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE PRELOAD DISCARDABLE
+BEGIN
+ IDR_MAINFRAME "TstCBot\n\nTstCBo\n\n\nTstCBot.Document\nTstCBo Document"
+END
+
+STRINGTABLE PRELOAD DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "TstCBot"
+ AFX_IDS_IDLEMESSAGE "Prêt"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_INDICATOR_EXT "EXT"
+ ID_INDICATOR_CAPS "MAJ"
+ ID_INDICATOR_NUM "NUM"
+ ID_INDICATOR_SCRL "DEF"
+ ID_INDICATOR_OVR "ECR"
+ ID_INDICATOR_REC "ENR"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_FILE_NEW "Crée un nouveau document\nNouveau"
+ ID_FILE_OPEN "Ouvre un document existant\nOuvrir"
+ ID_FILE_CLOSE "Ferme le document actif\nFermer"
+ ID_FILE_SAVE "Enregistre le document actif\nEnregistrer"
+ ID_FILE_SAVE_AS "Enregistre le document actif sous un nouveau nom\nEnregistrer sous"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_APP_ABOUT "Affiche des informations sur le programme, le numéro de version et le copyright\nA propos de"
+ ID_APP_EXIT "Ferme l'application ; propose d'enregistrer les documents\nQuitter"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_FILE_MRU_FILE1 "Ouvre ce document"
+ ID_FILE_MRU_FILE2 "Ouvre ce document"
+ ID_FILE_MRU_FILE3 "Ouvre ce document"
+ ID_FILE_MRU_FILE4 "Ouvre ce document"
+ ID_FILE_MRU_FILE5 "Ouvre ce document"
+ ID_FILE_MRU_FILE6 "Ouvre ce document"
+ ID_FILE_MRU_FILE7 "Ouvre ce document"
+ ID_FILE_MRU_FILE8 "Ouvre ce document"
+ ID_FILE_MRU_FILE9 "Ouvre ce document"
+ ID_FILE_MRU_FILE10 "Ouvre ce document"
+ ID_FILE_MRU_FILE11 "Ouvre ce document"
+ ID_FILE_MRU_FILE12 "Ouvre ce document"
+ ID_FILE_MRU_FILE13 "Ouvre ce document"
+ ID_FILE_MRU_FILE14 "Ouvre ce document"
+ ID_FILE_MRU_FILE15 "Ouvre ce document"
+ ID_FILE_MRU_FILE16 "Ouvre ce document"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_NEXT_PANE "Passe au volet de fenêtre suivant\nVolet suivant"
+ ID_PREV_PANE "Revient au volet précédent\nVolet précédent"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_WINDOW_SPLIT "Fractionne la fenêtre active en deux volets\nFractionner"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_EDIT_CLEAR "Efface la sélection\nEffacer"
+ ID_EDIT_CLEAR_ALL "Efface tout\nEffacer tout"
+ ID_EDIT_COPY "Copie la sélection et la place dans le Presse-papiers\nCopier"
+ ID_EDIT_CUT "Supprime la sélection et la place dans le Presse-papiers\nCopier"
+ ID_EDIT_FIND "Recherche le texte spécifié\nRechercher"
+ ID_EDIT_PASTE "Insère le contenu du Presse-papiers\nColler"
+ ID_EDIT_REPEAT "Répète la dernière action\nRépéter"
+ ID_EDIT_REPLACE "Remplace le texte spécifique par un texte différent\nRemplacer"
+ ID_EDIT_SELECT_ALL "Sélectionne le document entier\nSélectionner tout"
+ ID_EDIT_UNDO "Annule la dernière action\nAnnuler"
+ ID_EDIT_REDO "Rétablit l'action précédemment annulée\nRétablir"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ID_VIEW_STATUS_BAR "Affiche ou masque la barre d'état\nBarre d'état"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_SCSIZE "Change la taille de la fenêtre"
+ AFX_IDS_SCMOVE "Change la position de la fenêtre"
+ AFX_IDS_SCMINIMIZE "Réduit la fenêtre en icône"
+ AFX_IDS_SCMAXIMIZE "Agrandit la fenêtre au format de l'écran"
+ AFX_IDS_SCNEXTWINDOW "Passe à la fenêtre de document suivante"
+ AFX_IDS_SCPREVWINDOW "Passe à la fenêtre de document précédente"
+ AFX_IDS_SCCLOSE "Ferme la fenêtre active et propose l'enregistrement des documents"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_SCRESTORE "Restaure la fenêtre à sa taille d'origine"
+ AFX_IDS_SCTASKLIST "Active la liste des tâches"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ TX_TYPENAMES "les différents types"
+ 1001 "Byte"
+ 1002 "Short"
+ 1003 "Char"
+ 1004 "Int"
+ 1005 "Long"
+ 1006 "Real"
+ 1007 "Double"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ 1008 "Boolean"
+ 1009 "Class"
+ 1010 "String"
+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 "Instruction non terminée."
+ 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"", un ""do"" ou un ""switch""."
+ 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"
+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'exite 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à."
+END
+
+#endif // French (France) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// French (Switzerland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRS)
+#ifdef _WIN32
+LANGUAGE LANG_FRENCH, SUBLANG_FRENCH_SWISS
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONSOLE DIALOG DISCARDABLE 0, 0, 401, 210
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "CBot Console"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Commande :",IDC_STATIC,7,177,40,8
+ EDITTEXT IDC_EDIT2,7,189,329,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Exécute",IDOK,344,189,50,14
+ EDITTEXT IDC_EDIT1,7,7,387,167,ES_MULTILINE | ES_READONLY |
+ ES_WANTRETURN | WS_VSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_CONSOLE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 394
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 203
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // French (Switzerland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA)
+#ifdef _WIN32
+LANGUAGE 12, 1
+#pragma code_page(1252)
+#endif
+#include "res\TstCBot.rc2" // non-Microsoft Visual C++ edited resources
+#include "l.fra\afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/CBot/old TstCBot/TstCBotDoc.cpp b/src/CBot/old TstCBot/TstCBotDoc.cpp
new file mode 100644
index 0000000..7d7e2ef
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBotDoc.cpp
@@ -0,0 +1,83 @@
+// TstCBotDoc.cpp : implementation of the CTstCBotDoc class
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+
+#include "TstCBotDoc.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotDoc
+
+IMPLEMENT_DYNCREATE(CTstCBotDoc, CDocument)
+
+BEGIN_MESSAGE_MAP(CTstCBotDoc, CDocument)
+ //{{AFX_MSG_MAP(CTstCBotDoc)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotDoc construction/destruction
+
+CTstCBotDoc::CTstCBotDoc()
+{
+ // TODO: add one-time construction code here
+
+}
+
+CTstCBotDoc::~CTstCBotDoc()
+{
+}
+
+BOOL CTstCBotDoc::OnNewDocument()
+{
+ if (!CDocument::OnNewDocument())
+ return FALSE;
+
+ // TODO: add reinitialization code here
+ // (SDI documents will reuse this document)
+
+ return TRUE;
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotDoc serialization
+
+void CTstCBotDoc::Serialize(CArchive& ar)
+{
+ if (ar.IsStoring())
+ {
+ // TODO: add storing code here
+ }
+ else
+ {
+ // TODO: add loading code here
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotDoc diagnostics
+
+#ifdef _DEBUG
+void CTstCBotDoc::AssertValid() const
+{
+ CDocument::AssertValid();
+}
+
+void CTstCBotDoc::Dump(CDumpContext& dc) const
+{
+ CDocument::Dump(dc);
+}
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotDoc commands
+
diff --git a/src/CBot/old TstCBot/TstCBotDoc.h b/src/CBot/old TstCBot/TstCBotDoc.h
new file mode 100644
index 0000000..ae1d0f7
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBotDoc.h
@@ -0,0 +1,55 @@
+// TstCBotDoc.h : interface of the CTstCBotDoc class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_TSTCBOTDOC_H__70B3756E_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+#define AFX_TSTCBOTDOC_H__70B3756E_5DFD_11D4_A15E_00E0189013DF__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+
+class CTstCBotDoc : public CDocument
+{
+protected: // create from serialization only
+ CTstCBotDoc();
+ DECLARE_DYNCREATE(CTstCBotDoc)
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTstCBotDoc)
+ public:
+ virtual BOOL OnNewDocument();
+ virtual void Serialize(CArchive& ar);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CTstCBotDoc();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CTstCBotDoc)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TSTCBOTDOC_H__70B3756E_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
diff --git a/src/CBot/old TstCBot/TstCBotView.cpp b/src/CBot/old TstCBot/TstCBotView.cpp
new file mode 100644
index 0000000..3ee9094
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBotView.cpp
@@ -0,0 +1,291 @@
+// TstCBotView.cpp : implementation of the CTstCBotView class
+//
+
+#include "stdafx.h"
+#include "TstCBot.h"
+
+#include "TstCBotDoc.h"
+#include "TstCBotView.h"
+#include "BotConsoleDlg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotView
+
+IMPLEMENT_DYNCREATE(CTstCBotView, CView)
+
+BEGIN_MESSAGE_MAP(CTstCBotView, CView)
+ //{{AFX_MSG_MAP(CTstCBotView)
+ ON_WM_SIZE()
+ ON_COMMAND(ID_CP1, OnCp1)
+ ON_COMMAND(ID_EXE, OnExe)
+ ON_COMMAND(ID_FILE_SAVE, OnFileSave)
+ ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotView construction/destruction
+
+CTstCBotView::CTstCBotView()
+{
+ // TODO: add construction code here
+ m_pEdit = NULL;
+ m_pProg = NULL;
+}
+
+CTstCBotView::~CTstCBotView()
+{
+}
+
+BOOL CTstCBotView::PreCreateWindow(CREATESTRUCT& cs)
+{
+ // TODO: Modify the Window class or styles here by modifying
+ // the CREATESTRUCT cs
+
+ return CView::PreCreateWindow(cs);
+}
+
+void CTstCBotView::OnActivateView( BOOL bActivate, CView* pActivateView, CView* pDeactiveView )
+{
+ if ( m_pEdit == NULL)
+ {
+ m_pEdit = new CEdit();
+ CRect rect;
+ GetClientRect( rect );
+
+ m_pEdit->Create( WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_MULTILINE|ES_WANTRETURN|ES_NOHIDESEL|ES_AUTOVSCROLL,
+ rect, this, IDC_EDIT1 );
+ m_pEdit->SetTabStops(12);
+ LoadEdition("CBotTest.txt");
+ m_pEdit->SetFocus();
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotView drawing
+
+void CTstCBotView::OnDraw(CDC* pDC)
+{
+ CTstCBotDoc* pDoc = GetDocument();
+ ASSERT_VALID(pDoc);
+
+ // TODO: add draw code for native data here
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotView diagnostics
+
+#ifdef _DEBUG
+void CTstCBotView::AssertValid() const
+{
+ CView::AssertValid();
+}
+
+void CTstCBotView::Dump(CDumpContext& dc) const
+{
+ CView::Dump(dc);
+}
+
+CTstCBotDoc* CTstCBotView::GetDocument() // non-debug version is inline
+{
+ ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTstCBotDoc)));
+ return (CTstCBotDoc*)m_pDocument;
+}
+#endif //_DEBUG
+
+/////////////////////////////////////////////////////////////////////////////
+// CTstCBotView message handlers
+
+void CTstCBotView::OnSize(UINT nType, int cx, int cy)
+{
+ CView::OnSize(nType, cx, cy);
+
+ if ( m_pEdit != NULL )
+ {
+ CRect rect;
+ GetClientRect( rect );
+ m_pEdit->MoveWindow( rect );
+ m_pEdit->SetFocus();
+ }
+}
+
+void CTstCBotView::SaveEdition(const char* filename)
+{
+ CString program;
+
+ m_pEdit->GetWindowText(program);
+
+ FILE* pf = fopen(filename, "wb");
+ if (pf==NULL) return;
+
+ fputs (program, pf);
+ fclose(pf);
+}
+
+void CTstCBotView::LoadEdition(const char* filename)
+{
+ CString program("{ int x = 10000; while (x > 0) x = x-1; }");
+
+ FILE* pf = fopen(filename, "r");
+ if (pf!=NULL)
+ {
+ char buffer[10000];
+ program.Empty();
+
+ while (NULL != fgets (buffer, 100000, pf))
+ {
+ program += buffer;
+ program = program.Left(program.GetLength()-1) + "\r\n";
+ }
+
+ fclose(pf);
+ }
+
+ m_pEdit->SetWindowText(program);
+}
+
+
+
+// compile le programme
+#include <stdio.h>
+
+void CTstCBotView::OnCp1()
+{
+ CString program;
+
+ SaveEdition("CBotTest.txt");
+
+ m_pEdit->GetWindowText(program);
+
+ CString TextError;
+ int code, start, end;
+
+ if ( m_pProg == NULL ) m_pProg = new CBotProgram();
+
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+
+ if (m_pProg->Compile(program, pApp->m_Liste))
+ {
+ CString done = "Compilation sans erreur.\nLes fonctions suivantes sont externes:\n";
+
+ for ( int i = 0; i < pApp->m_Liste.RetSize(); i++)
+ {
+ done += CString(pApp->m_Liste[i]) + "\n";
+ }
+
+ AfxMessageBox( done );
+ }
+ else
+ {
+ m_pProg->GetError(code, start, end);
+ delete m_pProg;
+ m_pProg = NULL;
+
+ m_pEdit->SetSel( start, end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ TextError.LoadString( code );
+ if (TextError.IsEmpty())
+ {
+ char buf[100];
+ sprintf(buf, "Erreur numéro %d.", code);
+ TextError = buf;
+ }
+ AfxMessageBox( TextError );
+ }
+
+ m_pEdit->SetFocus();
+}
+
+
+//////////////////////////////////////////////////////
+
+
+void CTstCBotView::OnExe()
+{
+ CTstCBotApp* pApp = (CTstCBotApp*)AfxGetApp();
+
+ if( m_pProg == NULL)
+ {
+ AfxMessageBox("Pas de programme compilé !");
+ return;
+ }
+
+ if( pApp->m_Liste.RetSize() == 0 )
+ {
+ AfxMessageBox("Aucune fonction marquée \"extern\" !");
+ return;
+ }
+
+
+
+ CBotConsoleDlg dlg;
+ dlg.DoModal(); // dialogue pour faire la console
+
+ if ( dlg.m_code>0 )
+ {
+ CString TextError;
+
+ m_pEdit->SetSel( dlg.m_start, dlg.m_end );
+ m_pEdit->SetFocus(); // met en évidence la partie avec problème
+
+ TextError.LoadString( dlg.m_code );
+ if (TextError.IsEmpty())
+ {
+ char buf[100];
+ sprintf(buf, "Erreur numéro %d.", dlg.m_code);
+ TextError = buf;
+ }
+// AfxMessageBox( TextError );
+ }
+
+ m_pEdit->SetFocus();
+
+ return;
+}
+
+
+
+void CTstCBotView::OnFileSave()
+{
+ // TODO: Add your command handler code here
+ SaveEdition("CBotTest.txt");
+}
+
+void CTstCBotView::OnFileSaveAs()
+{
+ CFileDialog *pDlg;
+ CString s;
+
+ pDlg = new CFileDialog(FALSE, "TXT", NULL,
+ OFN_OVERWRITEPROMPT|OFN_HIDEREADONLY,
+ "cboxtest|*.txt", this);
+ if ( pDlg == NULL ) return;
+
+ if ( pDlg->DoModal() == IDOK ) // choix du fichier ...
+ {
+ SaveEdition(pDlg->GetPathName());
+ }
+
+ delete pDlg;
+}
+
+#if 0
+void test()
+{
+ int y,z;
+
+ for (;;);
+ for (x = 0; y = 1; z = 3) int q = 6;
+ for (int x = 0; int y = 1; int z = 3) int q = 6;
+ // pour voir
+}
+#endif
+
diff --git a/src/CBot/old TstCBot/TstCBotView.h b/src/CBot/old TstCBot/TstCBotView.h
new file mode 100644
index 0000000..d5aede5
--- /dev/null
+++ b/src/CBot/old TstCBot/TstCBotView.h
@@ -0,0 +1,81 @@
+// TstCBotView.h : interface of the CTstCBotView class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_TSTCBOTVIEW_H__70B37570_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+#define AFX_TSTCBOTVIEW_H__70B37570_5DFD_11D4_A15E_00E0189013DF__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+
+class CBotProgram;
+class CBotClass;
+
+
+class CTstCBotView : public CView
+{
+protected: // create from serialization only
+ CTstCBotView();
+ DECLARE_DYNCREATE(CTstCBotView)
+
+ CEdit* m_pEdit; // texte en édition
+ CWnd* m_pWnd;
+ CBotProgram* m_pProg; // programme compilé
+
+// Attributes
+public:
+ CTstCBotDoc* GetDocument();
+
+// Operations
+public:
+ void LoadEdition(const char* name);
+ void SaveEdition(const char* name);
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTstCBotView)
+ public:
+ virtual void OnDraw(CDC* pDC); // overridden to draw this view
+ virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
+ virtual void OnActivateView( BOOL bActivate, CView* pActivateView, CView* pDeactiveView );
+ protected:
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CTstCBotView();
+#ifdef _DEBUG
+ virtual void AssertValid() const;
+ virtual void Dump(CDumpContext& dc) const;
+#endif
+
+protected:
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CTstCBotView)
+ afx_msg void OnSize(UINT nType, int cx, int cy);
+ afx_msg void OnCp1();
+ afx_msg void OnExe();
+ afx_msg void OnFileSave();
+ afx_msg void OnFileSaveAs();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+#ifndef _DEBUG // debug version in TstCBotView.cpp
+inline CTstCBotDoc* CTstCBotView::GetDocument()
+ { return (CTstCBotDoc*)m_pDocument; }
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TSTCBOTVIEW_H__70B37570_5DFD_11D4_A15E_00E0189013DF__INCLUDED_)
+
+
+
diff --git a/src/CBot/old TstCBot/res/TstCBot.ico b/src/CBot/old TstCBot/res/TstCBot.ico
new file mode 100644
index 0000000..7eef0bc
--- /dev/null
+++ b/src/CBot/old TstCBot/res/TstCBot.ico
Binary files differ
diff --git a/src/CBot/old TstCBot/res/TstCBot.rc2 b/src/CBot/old TstCBot/res/TstCBot.rc2
new file mode 100644
index 0000000..2186272
--- /dev/null
+++ b/src/CBot/old TstCBot/res/TstCBot.rc2
@@ -0,0 +1,13 @@
+//
+// TSTCBOT.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/src/CBot/old TstCBot/res/TstCBotDoc.ico b/src/CBot/old TstCBot/res/TstCBotDoc.ico
new file mode 100644
index 0000000..2a1f1ae
--- /dev/null
+++ b/src/CBot/old TstCBot/res/TstCBotDoc.ico
Binary files differ
diff --git a/src/CBot/old TstCBot/test complet 1.txt b/src/CBot/old TstCBot/test complet 1.txt
new file mode 100644
index 0000000..0fd4fa5
--- /dev/null
+++ b/src/CBot/old TstCBot/test complet 1.txt
@@ -0,0 +1,213 @@
+// test de l'interpréteur CBot, (c) D. Dumoulin 2000
+
+Int Somme ( Int x, Int y )
+{
+ return x + y;
+}
+
+Real Somme ( Real x, Real y )
+{
+ return x + y;
+}
+
+void A_Faire()
+{
+ CPoint position; // utilise une classe externe
+ position.x = 123.5;
+ position.y = -45.1;
+
+ show ( position );
+}
+
+/* Les nouveautés sont les suivantes
+ __________________________________________________
+
+ On peut définir des fonctions, avec la syntaxe habituelle au C
+ void MaFonction( Int x, Real y ) { ... }
+
+ Les caractéristiques sont pour l'instant les suivantes:
+
+ - ce programme TstCBot exécute la dernière fonction définie
+
+ - on peut définir deux fonctions du même nom,
+ si la liste de paramètres est différente.
+ Par exemple
+ Int Somme( Int x, Int y )
+ Real Somme( Real x, Real y );
+ Note: si la seconde n'existait pas, Somme ( 1.3, 4.8 )
+ serait fait sur les nombres entier 1 + 4
+ La priorité est donnée à la routine qui ne pert pas
+ de bits dans la conversion des paramètres.
+
+ - il n'y a pas d'erreur de compilation si une routine
+ ne retourne pas de valeur alors qu'elle devrait,
+ par contre il y a une erreur "correcte" à l'exécution
+
+ - il est possible d'utiliser une fonction qui est définie
+ plus bas dans le programme.
+ __________________________________________________
+
+ Tous les blocs d'instructions existent maintenant, à savoir
+
+ label :
+ while (condition) { instructions; break label; continue label; }
+
+ label :
+ do { instructions; break label; continue label; } while (condition)
+
+ label:
+ for (initial; condition; incrément) { instructions; break; continue }
+
+ switch ( valeur ) { case 1: instructions; case 2: break ; }
+
+ try {instructions; throw exception; } catch (exception) {instructions;}
+ catch (testlogique) {instructions;}
+ finally {instructions;}
+ // le bloc finally est exécuter dans tous les cas
+ // qu'il y ait eu exception ou non, et aussi en cas de break, continue ou return
+ __________________________________________________
+
+ Les "exceptions" sont juste des numéros (31 bits)
+ 6000 = division par zéro
+ 6001 = variable non initialisée
+ 6002 = valeur négative pour un throw
+ 6003 = la fonction n'a pas retourné de valeur
+
+ les autres numéros sont à disposition
+ (COLOBOT aura surement des numéros d'exception propre)
+ l'association d'un mot clef pour ces exceptions est à venir.
+ __________________________________________________
+
+ L'interpréteur a été un peu optimiser, une boucle de un millon de décrément
+ ne prend plus que
+*/
+
+void Test ()
+{ // début du bloc d'instructions
+
+ Int z = 1000000;
+ while ( z>0 ) z--;
+
+ return;
+ {
+ // test la préséance pour les assignations
+ Int a = 9;
+ a += (a = 3);
+ if ( a != 12 ) 1/0; // le résultat correct est 12
+
+ Int b = 9;
+ b = b + (b = 3);
+ if (b != 12) 1/0; // même chose
+
+ // la fonction show est une fonction externe
+ // définie par TstCBot
+ // elle peut prendre un nombre quelconque de paramètres
+ show ( a, b );
+ }
+
+ {
+ // petit test sur les chaînes
+ String x = "ch." ;
+ String y ;
+ x += y = x + " de la brume.";
+
+ // concaténation de chaînes, accepte des autres types
+ String s = 1 + 2 + " test " + 3 + 4 ;
+
+ show( x, y, s );
+
+ // les tests sur les chaînes ne sont pas standard en Java
+ // mais c'est si pratique :
+
+ if ( s != "3 test 34" ) 1/0; // le résultat correct est "3 test 34"
+ // car 1+2 est évalué en premier entre 2 nombres
+ // et ensuite on additionne des chaînes "3" "4"
+ }
+
+ {
+ // teste toutes les opérations avec les entiers (32 bits)
+ Int a = 4;
+ Int b = 4;
+
+ Int c = a++ * --b; // post incrément, pré décrément
+ if ( c != 12 ) 1/0;
+
+ c = ++a * b--; // pré incrément, post décrément
+ if ( c!=18 ) 1/0;
+
+ a = a+b-a*b/a%3; // 6 + 2 - ( 6 * 2 / 6 % 3 ) -> 6
+ if ( a != 6 ) 1/0;
+
+ a += 2; a-=1; a*=3; a/=4; a%=3; // (6+2 -1) *3 /4 modulo 3 = 21 / 4 modulo 3 = 2
+ if ( a!= 2) 0/0;
+
+ if (-5 << 3 != -40) 0/0; // shift à gauche
+ if ( -5 >> 1 != -3) 0/0; // shift arithmétique à droite 11111011 -> 11111101 = -3
+ if ( -5 >>> 1 != 0x3ffffffd) 0/0; // shift non signé à droite
+
+ a = -10; // fait la même chose en assignation
+ a <<= 1; // -20
+ a >>= 2; // -5
+ a >>>= 1; // pert le signe
+ if ( a != 0x3ffffffd) 0/0; //
+
+ Int x = 5/3; // division d'entiers
+ if ( x != 1 ) 0/0;
+ Int xx = 5.0/3.0; // division de réels, assigné à un entier
+ if ( xx != 1 ) 0/0;
+
+ Int y = 0xF0035678;
+ if ( ~y != 0x0FFCA987 ) 0/0; // NOT bit à bit
+ if ( (0x3456 ^ 0x54f0) != 0x60A6) // XOR bit à bit
+ 0/0;
+ if ( (0x23 | 0x83) != 0xA3 ) 0/0; // OR bit à bit
+ if ( (0x23 & 0x83) != 0x03 ) 0/0; // AND bit à bit
+
+ Int z = 0x0123;
+ z |= 0x8010; if ( z != 0x8133) 0/0;
+ z &= 0xF018; if ( z != 0x8010) 0/0;
+ z ^= 0xFF17; if ( z != 0x7F07) 0/0;
+ }
+
+ {
+ // test pour les booléens
+ Boolean a, b= true, c = false;
+ a = b | c & b;
+ if ( a != b ) 0/0;
+ if ( !a ) 0/0;
+ if ( b ^ a ) 0/0; // XOR
+ if ( true || 0/0<1 ) {};
+ if ( false && 0/0<1) {};
+ // a ? "vrai" : "faux";
+ }
+
+ {
+ // petit test sur les nombres réels
+ Real x = 1. / 3, y = 0;
+
+ if ( 3 * x != 1 ) x = x / y; // provoque une division par zéro
+ else y = 1.123;
+ }
+
+
+ // test de durée
+ // attention, le programme de test ne stoppe qu'à la fin d'exécution
+ // bien que la boucle est interrompue plusieures fois
+
+ // la boucle est plus rapide si elle est au début du programme !
+ {
+ Int z = 10000;
+ while ( z > 0 ) z = z - 1;
+ }
+
+}
+
+void t()
+{
+ A_Faire();
+
+ show ( Somme ( 1, 2 ) );
+ show ( Somme ( 1., 2 ) );
+ show ( Somme ( 4.5, 2.7 ) );
+}
+
diff --git a/src/CBot/old TstCBot/x.txt b/src/CBot/old TstCBot/x.txt
new file mode 100644
index 0000000..95856e0
--- /dev/null
+++ b/src/CBot/old TstCBot/x.txt
@@ -0,0 +1,43 @@
+// test de l'interpréteur CBot, (c) D. Dumoulin 2000
+
+// pour l'instant, seule les primitives suivantes sont implémentées
+
+// { ... ; ... ; ... } un bloc d'instructions
+// int x, y = 12, z; // déclaration de nombre entier
+// float a, b= 2/3, c=b+1; // déclaration de nombres réels
+// boolean tst = true; // déclaration d'un booléen
+// String x = "hello"; // déclaration d'une chaînes
+
+// z = x = x * y / ( z + 1 - x ); // assignation en chaîne et les 4 opérations
+
+// while ( x >= 0 ) x = x - 1; // boucle while, et test > >= < <= == !=
+// if ( x < y ) x = x + 1; // test si
+// else y = y + 1; // sinon
+
+/* et les opérations suivantes:
+ + plus unaire x = +y;
+ - moins unaire x = -y;
+
+ || OU logique
+ && ET logique
+ ! NOT logique
+ | OU bit à bit
+ & ET bit à bit
+ ^ XOR bit à bit
+ ~ NON bit à bit
+
+// les commentaires sont acceptés
+/* y compris les commentaires
+ sur plusieures lignes */
+
+
+{
+String str ;
+
+str = "abc" ;
+
+show (str) ;
+
+show( str = str + "+++" , ) ;
+
+}
diff --git a/src/CBot/resource.h b/src/CBot/resource.h
new file mode 100644
index 0000000..659ee69
--- /dev/null
+++ b/src/CBot/resource.h
@@ -0,0 +1,166 @@
+//{{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
diff --git a/src/ClassFILE.cpp b/src/ClassFILE.cpp
new file mode 100644
index 0000000..cdfe26b
--- /dev/null
+++ b/src/ClassFILE.cpp
@@ -0,0 +1,413 @@
+// 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;
+static char* m_filesDir;
+
+
+
+// Prépare un nom de fichier.
+
+void PrepareFilename(CBotString &filename)
+{
+ 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(m_filesDir) + CBotString("\\") + 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);
+
+ // 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);
+
+ // 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); // si le nom a été attribué par h.filename = "...";
+
+ // ouvre le ficher demandé
+ FILE* pFile = fopen( filename, mode );
+ if ( pFile == NULL )
+ {
+ pResult->SetValInt(FALSE);
+ return TRUE;
+ }
+
+ m_CompteurFileOpen ++;
+
+ // enregiste le canal du fichier
+ pVar = pThis->GivItem("handle");
+ pVar->SetValInt((long)pFile);
+
+ pResult->SetValInt(TRUE);
+ 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);
+}
+
+
+// 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+"\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
+}
+
diff --git a/src/Copie de taskgoto.cpp b/src/Copie de taskgoto.cpp
new file mode 100644
index 0000000..ddb9a40
--- /dev/null
+++ b/src/Copie de taskgoto.cpp
@@ -0,0 +1,2136 @@
+// taskgoto.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskgoto.h"
+
+
+
+#define BM_DIM_STEP 5.0f
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskGoto::CTaskGoto(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_bmArray = 0;
+}
+
+// Destructeur de l'objet.
+
+CTaskGoto::~CTaskGoto()
+{
+ BitmapClose();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskGoto::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, goal;
+ FPOINT rot, repulse;
+ float a, g, dist, linSpeed, cirSpeed, h, w, factor, dir, floor;
+ Error ret;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ // Objet momentanément immobile (fourmi sur le dos) ?
+ if ( m_object->RetFixed() )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ return TRUE;
+ }
+
+ if ( m_error != ERR_OK ) return FALSE;
+
+ if ( m_bWorm )
+ {
+ WormFrame(event.rTime);
+ }
+
+ if ( m_phase == TGP_BEAMLEAK ) // fuite ?
+ {
+ m_leakTime += event.rTime;
+
+ pos = m_object->RetPosition(0);
+
+ rot.x = m_leakPos.x-pos.x;
+ rot.y = m_leakPos.z-pos.z;
+ dist = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ a = Direction(a, g)*1.0f;
+ cirSpeed = a;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ a = NormAngle(a);
+ if ( a > PI*0.5f && a < PI*1.5f )
+ {
+ linSpeed = 1.0f; // obstacle derrière -> avance
+ cirSpeed = -cirSpeed;
+ }
+ else
+ {
+ linSpeed = -1.0f; // obstacle devant -> recule
+ }
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(linSpeed); // avance
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMSEARCH ) // recherche chemin ?
+ {
+//? OutputDebugString("CTaskGoto::EventProcess TGP_BEAMSEARCH\n");
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_bmFretObject == 0 )
+ {
+ goal = m_goal;
+ dist = 0.0f;
+ }
+ else
+ {
+ goal = m_goalObject;
+ dist = TAKE_DIST;
+ }
+
+ ret = BeamSearch(pos, goal, dist);
+ if ( ret == ERR_OK )
+ {
+#if 1
+ D3DVECTOR min, max;
+ min = pos;
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 50.0f;
+ min.z -= 50.0f;
+ max.x += 50.0f;
+ max.z += 50.0f;
+ BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
+#endif
+ m_phase = TGP_BEAMUP;
+ m_bmIndex = 0;
+ m_bmWatchDogPos = m_object->RetPosition(0);
+ m_bmWatchDogTime = 0.0f;
+ }
+ if ( ret == ERR_GOTO_IMPOSSIBLE || ret == ERR_GOTO_ITER )
+ {
+#if 1
+ D3DVECTOR min, max;
+ min = pos;
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 50.0f;
+ min.z -= 50.0f;
+ max.x += 50.0f;
+ max.z += 50.0f;
+ BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
+#endif
+ m_error = ret;
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMUP ) // décolle ?
+ {
+ m_physics->SetMotorSpeedY(1.0f); // monte
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMGOTO ) // goto dot list ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ }
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ goal = m_bmPoints[m_bmIndex];
+ dist = Length2d(pos, goal);
+ if ( dist != 0.0f ) // anticipe ?
+ {
+ linSpeed = m_physics->RetLinMotionX(MO_REASPEED);
+ linSpeed /= m_physics->RetLinMotionX(MO_ADVSPEED);
+ goal.x = pos.x + (goal.x-pos.x)*linSpeed*20.0f/dist;
+ goal.z = pos.z + (goal.z-pos.z)*linSpeed*20.0f/dist;
+ }
+ floor = m_terrain->RetFloorLevel(goal, TRUE);
+ w = m_water->RetLevel();
+ if ( floor < w ) floor = w; // jamais en-dessous de l'eau
+ h = pos.y-floor; // h <- hauteur jusqu'au sol
+
+ linSpeed = 0.0f;
+ if ( h < m_altitude-1.0f )
+ {
+ linSpeed = 0.2f+((m_altitude-1.0f)-h)*0.1f; // monte
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+ }
+ if ( h > m_altitude+1.0f )
+ {
+ linSpeed = -0.2f; // descend
+ }
+ m_physics->SetMotorSpeedY(linSpeed);
+ }
+
+ dist = Length2d(pos, m_bmWatchDogPos);
+ if ( dist < 1.0f )
+ {
+ m_bmWatchDogTime += event.rTime;
+ }
+ else
+ {
+ m_bmWatchDogTime = 0.0f;
+ m_bmWatchDogPos = pos;
+ }
+
+ if ( m_bmWatchDogTime >= 1.0f ) // immobile depuis longtemps ?
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ BeamStart();
+ return TRUE;
+ }
+
+ rot.x = m_bmPoints[m_bmIndex].x-pos.x;
+ rot.y = m_bmPoints[m_bmIndex].z-pos.z;
+ dist = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ if ( m_bmIndex == m_bmTotal ) // dernier point ?
+ {
+ dist = Length2d(m_bmPoints[m_bmIndex], pos);
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+ }
+ else
+ {
+ linSpeed = 1.0f; // fonce sans s'arrêter
+ }
+
+ linSpeed *= 1.0f-(1.0f-0.3f)*Abs(cirSpeed);
+
+ if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ {
+ linSpeed = 0.0f; // tourne d'abord, puis avance
+ }
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(linSpeed); // avance
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMDOWN ) // atterri ?
+ {
+ m_physics->SetMotorSpeedY(-0.5f); // tombe
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_LAND ) // atterri ?
+ {
+ m_physics->SetMotorSpeedY(-0.5f); // tombe
+ return TRUE;
+ }
+
+ if ( m_goalMode == TGG_EXPRESS )
+ {
+ if ( m_crashMode == TGC_HALT )
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_error = ERR_STOP;
+ return TRUE;
+ }
+ }
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_altitude > 0.0f )
+ {
+ h = m_terrain->RetFloorHeight(pos, TRUE);
+ linSpeed = 0.0f;
+ if ( h < m_altitude )
+ {
+ linSpeed = 0.1f; // monte
+ }
+ if ( h > m_altitude )
+ {
+ linSpeed = -0.2f; // descend
+ }
+ m_physics->SetMotorSpeedY(linSpeed);
+ }
+
+ rot.x = m_goal.x-pos.x;
+ rot.y = m_goal.z-pos.z;
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(1.0f); // avance
+ return TRUE;
+ }
+
+ if ( m_phase != TGP_TURN &&
+ m_physics->RetType() == TYPE_FLYING &&
+ m_altitude > 0.0f )
+ {
+ pos = m_object->RetPosition(0);
+ dist = Length2d(m_goal, pos);
+ factor = (dist-20.0f)/20.0f;
+ if ( factor < 0.0f ) factor = 0.0f;
+ if ( factor > 1.0f ) factor = 1.0f;
+
+ h = m_terrain->RetFloorHeight(m_object->RetPosition(0), TRUE);
+ linSpeed = 0.0f;
+ if ( h < (m_altitude-0.5f)*factor && factor == 1.0f )
+ {
+ linSpeed = 0.1f; // monte
+ }
+ if ( h > m_altitude*factor )
+ {
+ linSpeed = -0.2f; // descend
+ }
+ ComputeFlyingRepulse(dir);
+ linSpeed += dir*0.2f;
+
+ m_physics->SetMotorSpeedY(linSpeed);
+ }
+
+ if ( m_phase == TGP_ADVANCE ) // va vers l'objectif ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_time = 0.0f;
+ m_phase = TGP_CRWAIT;
+ return TRUE;
+ }
+
+#if 0
+ pos = m_object->RetPosition(0);
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(m_goal.x-pos.x, pos.z-m_goal.z); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ dist = Length2d(m_goal, pos);
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+
+ if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ {
+ linSpeed = 0.0f; // tourne d'abord, puis avance
+ }
+#else
+ pos = m_object->RetPosition(0);
+
+ rot.x = m_goal.x-pos.x;
+ rot.y = m_goal.z-pos.z;
+ dist = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ ComputeRepulse(repulse);
+ rot.x += repulse.x*2.0f;
+ rot.y += repulse.y*2.0f;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+//? if ( m_physics->RetType() == TYPE_FLYING &&
+//? m_physics->RetLand() ) // volant au sol ?
+//? {
+//? cirSpeed *= 4.0f; // plus de pèche
+//? }
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ dist = Length2d(m_goal, pos);
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+//? if ( m_physics->RetType() == TYPE_FLYING &&
+//? m_physics->RetLand() ) // volant au sol ?
+//? {
+//? linSpeed *= 8.0f; // plus de pèche
+//? }
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+
+ linSpeed *= 1.0f-(1.0f-0.3f)*Abs(cirSpeed);
+
+ if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ {
+ linSpeed = 0.0f; // tourne d'abord, puis avance
+ }
+#endif
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(linSpeed); // avance
+ }
+
+ if ( m_phase == TGP_TURN || // tourne vers l'objet ?
+ m_phase == TGP_CRTURN || // tourne après collision ?
+ m_phase == TGP_CLTURN ) // tourne après collision ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ }
+
+ if ( m_phase == TGP_CRWAIT || // attend après collision ?
+ m_phase == TGP_CLWAIT ) // attend après collision ?
+ {
+ m_time += event.rTime;
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ }
+
+ if ( m_phase == TGP_CRADVANCE ) // avance après collision ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_time = 0.0f;
+ m_phase = TGP_CLWAIT;
+ return TRUE;
+ }
+ m_physics->SetMotorSpeedX(0.5f); // avance mollo
+ }
+
+ if ( m_phase == TGP_CLADVANCE ) // avance après collision ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_time = 0.0f;
+ m_phase = TGP_CRWAIT;
+ return TRUE;
+ }
+ m_physics->SetMotorSpeedX(0.5f); // avance mollo
+ }
+
+ if ( m_phase == TGP_MOVE ) // avance finale ?
+ {
+ m_bmTimeLimit -= event.rTime;
+ m_physics->SetMotorSpeedX(1.0f);
+ }
+
+ return TRUE;
+}
+
+
+// Cherche une cible pour le ver.
+
+CObject* CTaskGoto::WormSearch(D3DVECTOR &impact)
+{
+ CObject* pObj;
+ CObject* pBest = 0;
+ D3DVECTOR iPos, oPos;
+ ObjectType oType;
+ float distance, min, radius;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ min = 1000000.0f;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( oType != OBJECT_MOBILEfa &&
+ oType != OBJECT_MOBILEta &&
+ oType != OBJECT_MOBILEwa &&
+ oType != OBJECT_MOBILEia &&
+ oType != OBJECT_MOBILEfc &&
+ oType != OBJECT_MOBILEtc &&
+ oType != OBJECT_MOBILEwc &&
+ oType != OBJECT_MOBILEic &&
+ oType != OBJECT_MOBILEfi &&
+ oType != OBJECT_MOBILEti &&
+ oType != OBJECT_MOBILEwi &&
+ oType != OBJECT_MOBILEii &&
+ oType != OBJECT_MOBILEfs &&
+ oType != OBJECT_MOBILEts &&
+ oType != OBJECT_MOBILEws &&
+ oType != OBJECT_MOBILEis &&
+ oType != OBJECT_MOBILErt &&
+ oType != OBJECT_MOBILErc &&
+ oType != OBJECT_MOBILErr &&
+ oType != OBJECT_MOBILErs &&
+ oType != OBJECT_MOBILEsa &&
+ oType != OBJECT_MOBILEtg &&
+ oType != OBJECT_MOBILEft &&
+ oType != OBJECT_MOBILEtt &&
+ oType != OBJECT_MOBILEwt &&
+ oType != OBJECT_MOBILEit &&
+ oType != OBJECT_DERRICK &&
+ oType != OBJECT_STATION &&
+ oType != OBJECT_FACTORY &&
+ oType != OBJECT_REPAIR &&
+ oType != OBJECT_CONVERT &&
+ oType != OBJECT_TOWER &&
+ oType != OBJECT_RESEARCH &&
+ oType != OBJECT_RADAR &&
+ oType != OBJECT_INFO &&
+ oType != OBJECT_ENERGY &&
+ oType != OBJECT_LABO &&
+ oType != OBJECT_NUCLEAR &&
+ oType != OBJECT_PARA &&
+ oType != OBJECT_SAFE &&
+ oType != OBJECT_HUSTON ) continue;
+
+ if ( pObj->RetVirusMode() ) continue; // objet infecté ?
+
+ if ( !pObj->GetCrashSphere(0, oPos, radius) ) continue;
+ distance = Length2d(oPos, iPos);
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ }
+ }
+ if ( pBest == 0 ) return 0;
+
+ impact = pBest->RetPosition(0);
+ return pBest;
+}
+
+// Contamine les objets proches du ver.
+
+void CTaskGoto::WormFrame(float rTime)
+{
+ CObject* pObj;
+ D3DVECTOR impact, pos;
+ float dist;
+
+ m_wormLastTime += rTime;
+
+ if ( m_wormLastTime >= 0.5f )
+ {
+ m_wormLastTime = 0.0f;
+
+ pObj = WormSearch(impact);
+ if ( pObj != 0 )
+ {
+ pos = m_object->RetPosition(0);
+ dist = Length(pos, impact);
+ if ( dist <= 15.0f )
+ {
+ pObj->SetVirusMode(TRUE); // paf, infecté !
+ }
+ }
+ }
+}
+
+
+
+// Assigne le but à atteindre.
+// "dist" est la distance de laquelle il faut s'éloigner pour
+// prendre ou déposer un objet.
+
+Error CTaskGoto::Start(D3DVECTOR goal, float altitude,
+ TaskGotoGoal goalMode, TaskGotoCrash crashMode)
+{
+ D3DVECTOR pos;
+ CObject* target;
+ ObjectType type;
+ float dist;
+ int x, y;
+
+ type = m_object->RetType();
+
+ if ( goalMode == TGG_DEFAULT )
+ {
+ goalMode = TGG_STOP;
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_WORM )
+ {
+ goalMode = TGG_EXPRESS;
+ }
+ }
+
+ if ( crashMode == TGC_DEFAULT )
+ {
+//? crashMode = TGC_RIGHTLEFT;
+ crashMode = TGC_BEAM;
+ if ( type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_WORM ||
+ type == OBJECT_BEE )
+ {
+ crashMode = TGC_HALT;
+ }
+ }
+
+ m_altitude = altitude;
+ m_goalMode = goalMode;
+ m_crashMode = crashMode;
+ m_goalObject = goal;
+ m_goal = goal;
+
+ m_bTake = FALSE;
+ m_phase = TGP_ADVANCE;
+ m_error = ERR_OK;
+ m_try = 0;
+ m_bmFretObject = 0;
+ m_bmFinalMove = 0.0f;
+
+ pos = m_object->RetPosition(0);
+ dist = Length2d(pos, m_goal);
+ if ( dist < 10.0f && m_crashMode == TGC_BEAM )
+ {
+ m_crashMode = TGC_RIGHTLEFT;
+ }
+
+ m_bWorm = FALSE;
+ if ( type == OBJECT_WORM )
+ {
+ m_bWorm = TRUE;
+ m_wormLastTime = 0.0f;
+ }
+
+ m_bApprox = FALSE;
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ m_bApprox = TRUE;
+ }
+
+ if ( !m_bApprox && m_crashMode != TGC_BEAM )
+ {
+ target = SearchTarget(goal, 1.0f);
+ if ( target != 0 )
+ {
+ m_goal = target->RetPosition(0);
+ dist = 0.0f;
+ if ( !AdjustBuilding(m_goal, 1.0f, dist) )
+ {
+ dist = 0.0f;
+ AdjustTarget(target, m_goal, dist);
+ }
+ m_bTake = TRUE; // objet à prendre à l'arrivée (rotation finale)
+ }
+ }
+
+ m_lastDistance = 1000.0f;
+ m_physics->SetCollision(FALSE);
+
+ if ( m_crashMode == TGC_BEAM )
+ {
+ target = SearchTarget(goal, 1.0f);
+ if ( target != 0 )
+ {
+ m_goal = target->RetPosition(0);
+ dist = 4.0f;
+ if ( AdjustBuilding(m_goal, 1.0f, dist) )
+ {
+ m_bmFinalMove = dist;
+ }
+ else
+ {
+ dist = 4.0f;
+ if ( AdjustTarget(target, m_goal, dist) )
+ {
+ m_bmFretObject = target; // fret posé au sol
+ }
+ else
+ {
+ m_bmFinalMove = dist;
+ }
+ }
+ m_bTake = TRUE; // objet à prendre à l'arrivée (rotation finale)
+ }
+
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f )
+ {
+ pos = m_object->RetPosition(0);
+ dist = Length2d(pos, m_goal);
+ if ( dist > 40.0f ) // plus de 10 mètres ?
+ {
+ m_altitude = 20.0f; // altitude par défaut
+ }
+ }
+
+ BeamStart();
+
+ if ( m_bmFretObject == 0 )
+ {
+ x = (int)((m_goal.x+1600.0f)/BM_DIM_STEP);
+ y = (int)((m_goal.z+1600.0f)/BM_DIM_STEP);
+ if ( BitmapTestDot(0, x, y) ) // arrivée occupée ?
+ {
+ m_error = ERR_GOTO_IMPOSSIBLE;
+ return m_error;
+ }
+ }
+ }
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskGoto::IsEnded()
+{
+ D3DVECTOR pos;
+ float limit, angle, dist, h;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_error != ERR_OK ) return m_error;
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_phase == TGP_BEAMLEAK ) // fuite ?
+ {
+ if ( m_leakTime >= m_leakDelay )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ BeamInit();
+ m_phase = TGP_BEAMSEARCH; // faudra chercher le chemin
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TGP_BEAMSEARCH ) // recherche du chemin ?
+ {
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TGP_BEAMUP ) // décolle ?
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ h = m_terrain->RetFloorHeight(pos, TRUE);
+ if ( h < m_altitude-20.0f ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedY(0.0f); // stoppe la montée
+ }
+ m_phase = TGP_BEAMGOTO;
+ }
+
+ if ( m_phase == TGP_BEAMGOTO ) // goto dot list ?
+ {
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ limit = 1.0f;
+ }
+ else // en vol ?
+ {
+ limit = 2.0f;
+ if ( m_bmIndex < m_bmTotal ) limit *= 2.0f; // point intermédiaire
+ }
+ if ( m_bApprox ) limit = 2.0f;
+
+ if ( Abs(pos.x - m_bmPoints[m_bmIndex].x) < limit &&
+ Abs(pos.z - m_bmPoints[m_bmIndex].z) < limit )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+
+ m_bmIndex = BeamShortcut();
+
+ if ( m_bmIndex > m_bmTotal )
+ {
+ m_phase = TGP_BEAMDOWN;
+ }
+ }
+ }
+
+ if ( m_phase == TGP_BEAMDOWN ) // atteri ?
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ if ( !m_physics->RetLand() ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedY(0.0f); // stoppe la descente
+ }
+
+ if ( m_bTake )
+ {
+ m_angle = RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z);
+ m_phase = TGP_TURN;
+ }
+ else
+ {
+ return ERR_STOP;
+ }
+ }
+
+ if ( m_goalMode == TGG_EXPRESS )
+ {
+ dist = Length2d(m_goal, pos);
+ if ( dist < 10.0f && dist > m_lastDistance )
+ {
+ return ERR_STOP;
+ }
+ m_lastDistance = dist;
+ }
+
+ if ( m_phase == TGP_ADVANCE ) // va vers l'objectif ?
+ {
+ if ( m_physics->RetLand() ) limit = 0.1f; // au sol
+ else limit = 1.0f; // en vol
+ if ( m_bApprox ) limit = 2.0f;
+
+ if ( Abs(pos.x - m_goal.x) < limit &&
+ Abs(pos.z - m_goal.z) < limit )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_phase = TGP_LAND;
+ }
+ }
+
+ if ( m_phase == TGP_LAND ) // atterri ?
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ if ( !m_physics->RetLand() ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedY(0.0f);
+ }
+
+ if ( m_bTake )
+ {
+ m_angle = RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z);
+ m_phase = TGP_TURN;
+ }
+ else
+ {
+ return ERR_STOP;
+ }
+ }
+
+ if ( m_phase == TGP_TURN ) // tourne vers l'objet ?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.02f;
+ if ( m_bApprox ) limit = 0.10f;
+ if ( Abs(angle-m_angle) < limit )
+ {
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ if ( m_bmFinalMove == 0.0f ) return ERR_STOP;
+
+ m_bmFinalPos = m_object->RetPosition(0);
+ m_bmFinalDist = m_physics->RetLinLength(m_bmFinalMove);
+ m_bmTimeLimit = m_physics->RetLinTimeLength(Abs(m_bmFinalMove))*1.5f;
+ if ( m_bmTimeLimit < 0.5f ) m_bmTimeLimit = 0.5f;
+ m_phase = TGP_MOVE;
+ }
+ }
+
+ if ( m_phase == TGP_CRWAIT ) // attend après collision ?
+ {
+ if ( m_crashMode == TGC_HALT )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_error = ERR_GENERIC;
+ return m_error;
+ }
+ if ( m_time >= 1.0f )
+ {
+ if ( m_crashMode == TGC_RIGHTLEFT ||
+ m_crashMode == TGC_RIGHT ) angle = PI/2.0f; // 90 à droite
+ else angle = -PI/2.0f; // 90 à gauche
+ m_angle = NormAngle(m_object->RetAngleY(0)+angle);
+ m_phase = TGP_CRTURN;
+//? m_phase = TGP_ADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CRTURN ) // tourne après collision ?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.1f;
+ if ( Abs(angle-m_angle) < limit )
+ {
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_pos = pos;
+ m_phase = TGP_CRADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CRADVANCE ) // avance après collision ?
+ {
+ if ( Length(pos, m_pos) >= 5.0f )
+ {
+ m_phase = TGP_ADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CLWAIT ) // attend après collision ?
+ {
+ if ( m_time >= 1.0f )
+ {
+ if ( m_crashMode == TGC_RIGHTLEFT ) angle = -PI;
+ if ( m_crashMode == TGC_LEFTRIGHT ) angle = PI;
+ if ( m_crashMode == TGC_RIGHT ) angle = PI/2.0f;
+ if ( m_crashMode == TGC_LEFT ) angle = -PI/2.0f;
+ m_angle = NormAngle(m_object->RetAngleY(0)+angle);
+ m_phase = TGP_CLTURN;
+ }
+ }
+
+ if ( m_phase == TGP_CLTURN ) // tourne après collision ?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.1f;
+ if ( Abs(angle-m_angle) < limit )
+ {
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_pos = pos;
+ m_phase = TGP_CLADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CLADVANCE ) // avance après collision ?
+ {
+ if ( Length(pos, m_pos) >= 10.0f )
+ {
+ m_phase = TGP_ADVANCE;
+ m_try ++;
+ }
+ }
+
+ if ( m_phase == TGP_MOVE ) // avance finale ?
+ {
+ if ( m_bmTimeLimit <= 0.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe
+ Abort();
+ return ERR_STOP;
+ }
+
+ dist = Length(m_bmFinalPos, m_object->RetPosition(0));
+ if ( dist < m_bmFinalDist ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ return ERR_STOP;
+ }
+
+ return ERR_CONTINUE;
+}
+
+
+// Cherche l'objet à la position cible.
+
+CObject* CTaskGoto::SearchTarget(D3DVECTOR pos, float margin)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ float dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(pos, oPos);
+
+ if ( dist <= margin ) return pObj;
+ }
+
+ return 0;
+}
+
+// Ajuste la cible en fonction de l'objet.
+// Retourne TRUE s'il s'agit de fret posé au sol.
+
+BOOL CTaskGoto::AdjustTarget(CObject* pObj, D3DVECTOR &pos, float &distance)
+{
+ ObjectType type;
+ Character* character;
+ D3DMATRIX* mat;
+ D3DVECTOR goal;
+ float dist, suppl;
+
+ type = m_object->RetType();
+ if ( type == OBJECT_BEE ||
+ type == OBJECT_WORM )
+ {
+ pos = pObj->RetPosition(0);
+ return FALSE;
+ }
+
+ type = pObj->RetType();
+
+ if ( 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_TNT ||
+ type == OBJECT_BOMB )
+ {
+ pos = m_object->RetPosition(0);
+ goal = pObj->RetPosition(0);
+ dist = Length(goal, pos);
+ pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal;
+ return TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit )
+ {
+ character = pObj->RetCharacter();
+ pos = character->posPower;
+ pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance;
+ mat = pObj->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ return FALSE;
+ }
+
+ if ( GetHotPoint(pObj, goal, TRUE, distance, suppl) )
+ {
+ pos = goal;
+ distance += suppl;
+ return FALSE;
+ }
+
+ pos = pObj->RetPosition(0);
+ return FALSE;
+}
+
+// S'il on est sur un objet produit par un bâtiment (minerai produit
+// par derrick), modifie la position par-rapport au bâtiment.
+
+BOOL CTaskGoto::AdjustBuilding(D3DVECTOR &pos, float margin, float &distance)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ float dist, suppl;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+
+ if ( !GetHotPoint(pObj, oPos, FALSE, 0.0f, suppl) ) continue;
+ dist = Length2d(pos, oPos);
+ if ( dist <= margin )
+ {
+ GetHotPoint(pObj, pos, TRUE, distance, suppl);
+ distance += suppl;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Retourne le point où est produit ou posé qq chose sur un bâtiment.
+
+BOOL CTaskGoto::GetHotPoint(CObject *pObj, D3DVECTOR &pos,
+ BOOL bTake, float distance, float &suppl)
+{
+ ObjectType type;
+ D3DMATRIX* mat;
+
+ pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ suppl = 0.0f;
+ type = pObj->RetType();
+
+ if ( type == OBJECT_DERRICK )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 7.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_CONVERT )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 0.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_RESEARCH )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 7.5f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_ENERGY )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 0.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_TOWER )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 5.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_LABO )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 0.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_NUCLEAR )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 22.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_FACTORY )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 4.0f;
+ if ( bTake && distance != 0.0f ) suppl = 3.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_STATION )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ if ( bTake ) pos.x += distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ suppl = 0.0f;
+ return FALSE;
+}
+
+
+// Cherche un objet trop proche qu'il faut fuire.
+
+BOOL CTaskGoto::LeakSearch(D3DVECTOR &pos, float &delay)
+{
+ CObject* pObj;
+ D3DVECTOR iPos, oPos, bPos;
+ float iRadius, oRadius, bRadius, dist, min;
+ int i, j;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ min = 100000.0f;
+ bRadius = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length2d(oPos, iPos);
+ if ( dist < min )
+ {
+ min = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ }
+ }
+ }
+ if ( min > iRadius+bRadius+4.0f ) return FALSE;
+
+ pos = bPos;
+ delay = m_physics->RetLinTimeLength(4.0f);
+ return TRUE;
+}
+
+
+// Calcule la force de répulsion en fonction des obstacles.
+// La longueur du vecteur rendu est comprise entre 0 et 1.
+
+void CTaskGoto::ComputeRepulse(FPOINT &dir)
+{
+#if 0
+ D3DVECTOR iPos, oPos;
+ FPOINT repulse;
+ CObject *pObj;
+ float dist, iRadius, oRadius;
+ int i;
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_goalObject);
+ if ( dist <= 1.0f ) continue;
+
+ pObj->GetGlobalSphere(oPos, oRadius);
+ oRadius += iRadius+m_physics->RetLinStopLength()*1.1f;
+ dist = Length2d(oPos, iPos);
+ if ( dist <= oRadius )
+ {
+ repulse.x = iPos.x-oPos.x;
+ repulse.y = iPos.z-oPos.z;
+
+//? dist = 0.2f-(0.2f*dist/oRadius);
+ dist = powf(dist/oRadius, 2.0f);
+ dist = 0.2f-0.2f*dist;
+ repulse.x *= dist;
+ repulse.y *= dist;
+//? repulse.x /= dist;
+//? repulse.y /= dist;
+
+ dir.x += repulse.x;
+ dir.y += repulse.y;
+ }
+ }
+#else
+ ObjectType iType, oType;
+ D3DVECTOR iPos, oPos;
+ FPOINT repulse;
+ CObject *pObj;
+ float gDist, add, addi, fac, dist, iRadius, oRadius;
+ int i, j;
+ BOOL bAlien;
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+
+ // Le ver passe partout et à travers tout !
+ iType = m_object->RetType();
+ if ( iType == OBJECT_WORM ) return;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+ gDist = Length(iPos, m_goal);
+
+ add = m_physics->RetLinStopLength()*1.1f; // distance de freinage
+ fac = 2.0f;
+
+ if ( iType == OBJECT_MOBILEwa ||
+ iType == OBJECT_MOBILEwc ||
+ iType == OBJECT_MOBILEwi ||
+ iType == OBJECT_MOBILEws ||
+ iType == OBJECT_MOBILEwt ) // roues ?
+ {
+ add = 5.0f;
+ fac = 1.5f;
+ }
+ if ( iType == OBJECT_MOBILEta ||
+ iType == OBJECT_MOBILEtc ||
+ iType == OBJECT_MOBILEti ||
+ iType == OBJECT_MOBILEts ||
+ iType == OBJECT_MOBILEtt ) // chenilles ?
+ {
+ add = 4.0f;
+ fac = 1.5f;
+ }
+ if ( iType == OBJECT_MOBILEfa ||
+ iType == OBJECT_MOBILEfc ||
+ iType == OBJECT_MOBILEfi ||
+ iType == OBJECT_MOBILEfs ||
+ iType == OBJECT_MOBILEft ) // volant ?
+ {
+ if ( m_physics->RetLand() )
+ {
+ add = 5.0f;
+ fac = 1.5f;
+ }
+ else
+ {
+ add = 10.0f;
+ fac = 1.5f;
+ }
+ }
+ if ( iType == OBJECT_MOBILEia ||
+ iType == OBJECT_MOBILEic ||
+ iType == OBJECT_MOBILEii ||
+ iType == OBJECT_MOBILEis ||
+ iType == OBJECT_MOBILEit ) // pattes ?
+ {
+ add = 4.0f;
+ fac = 1.5f;
+ }
+ if ( iType == OBJECT_BEE ) // guêpe ?
+ {
+ if ( m_physics->RetLand() )
+ {
+ add = 3.0f;
+ fac = 1.5f;
+ }
+ else
+ {
+ add = 5.0f;
+ fac = 1.5f;
+ }
+ }
+
+ bAlien = FALSE;
+ if ( iType == OBJECT_MOTHER ||
+ iType == OBJECT_ANT ||
+ iType == OBJECT_SPIDER ||
+ iType == OBJECT_BEE ||
+ iType == OBJECT_WORM )
+ {
+ bAlien = TRUE;
+ }
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oType = pObj->RetType();
+
+ if ( oType == OBJECT_WORM ) continue;
+
+ if ( bAlien )
+ {
+ if ( oType == OBJECT_STONE ||
+ oType == OBJECT_URANIUM ||
+ oType == OBJECT_METAL ||
+ oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_BULLET ||
+ oType == OBJECT_BBOX ||
+ oType == OBJECT_KEYa ||
+ oType == OBJECT_KEYb ||
+ oType == OBJECT_KEYc ||
+ oType == OBJECT_KEYd ||
+ oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB ||
+ (oType >= OBJECT_PLANT0 &&
+ oType <= OBJECT_PLANT19 ) ||
+ (oType >= OBJECT_MUSHROOM0 &&
+ oType <= OBJECT_MUSHROOM9 ) ) continue;
+ }
+
+ addi = add;
+ if ( iType == OBJECT_BEE &&
+ oType == OBJECT_BEE )
+ {
+ addi = 2.0f; // entre guèpes, faut pas trop s'embêter
+ }
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( oPos.y-oRadius > iPos.y+iRadius ) continue;
+ if ( oPos.y+oRadius < iPos.y-iRadius ) continue;
+
+ dist = Length(oPos, m_goal);
+ if ( dist <= 1.0f ) continue; // sur le but ?
+
+ oRadius += iRadius+addi;
+ dist = Length2d(oPos, iPos);
+ if ( dist > gDist ) continue; // plus loin que le but ?
+ if ( dist <= oRadius )
+ {
+ repulse.x = iPos.x-oPos.x;
+ repulse.y = iPos.z-oPos.z;
+
+ dist = powf(dist/oRadius, fac);
+ dist = 0.2f-0.2f*dist;
+ repulse.x *= dist;
+ repulse.y *= dist;
+
+ dir.x += repulse.x;
+ dir.y += repulse.y;
+ }
+ }
+ }
+#endif
+}
+
+// Calcule la force de répulsion verticale en fonction des obstacles.
+// La longueur du vecteur rendu est comprise entre -1 et 1.
+
+void CTaskGoto::ComputeFlyingRepulse(float &dir)
+{
+ ObjectType oType;
+ D3DVECTOR iPos, oPos;
+ CObject *pObj;
+ float add, fac, dist, iRadius, oRadius, repulse;
+ int i, j;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ add = 0.0f;
+ fac = 1.5f;
+ dir = 0.0f;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oType = pObj->RetType();
+
+ if ( oType == OBJECT_WORM ) continue;
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ oRadius += iRadius+add;
+ dist = Length2d(oPos, iPos);
+ if ( dist <= oRadius )
+ {
+ repulse = iPos.y-oPos.y;
+
+ dist = powf(dist/oRadius, fac);
+ dist = 0.2f-0.2f*dist;
+ repulse *= dist;
+
+ dir += repulse;
+ }
+ }
+ }
+
+ if ( dir < -1.0f ) dir = -1.0f;
+ if ( dir > 1.0f ) dir = 1.0f;
+}
+
+
+
+// Parmi tous les points suivants, cherche s'il en existe un qui
+// permet d'y aller directement à vol d'oiseau. Si oui, saute tous
+// les points intermédiaires inutiles.
+
+int CTaskGoto::BeamShortcut()
+{
+ int i;
+
+ for ( i=m_bmTotal ; i>=m_bmIndex+2 ; i-- ) // cherche depuis le dernier
+ {
+ if ( BitmapTestLine(m_bmPoints[m_bmIndex], m_bmPoints[i], 0.0f, FALSE) )
+ {
+ return i; // bingo, trouvé
+ }
+ }
+
+ return m_bmIndex+1; // va simplement au point suivant
+}
+
+// C'est le grand départ.
+
+void CTaskGoto::BeamStart()
+{
+ D3DVECTOR min, max;
+
+//? OutputDebugString("CTaskGoto::Start TGC_BEAM\n");
+ BitmapOpen();
+ BitmapObject();
+
+ min = m_object->RetPosition(0);
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 10.0f*BM_DIM_STEP;
+ min.z -= 10.0f*BM_DIM_STEP;
+ max.x += 10.0f*BM_DIM_STEP;
+ max.z += 10.0f*BM_DIM_STEP;
+ BitmapTerrain(min, max);
+
+ if ( LeakSearch(m_leakPos, m_leakDelay) )
+ {
+ m_phase = TGP_BEAMLEAK; // il faut d'abord fuire
+ m_leakTime = 0.0f;
+ }
+ else
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ BeamInit();
+ m_phase = TGP_BEAMSEARCH; // faudra chercher le chemin
+ }
+}
+
+// Initialisation avant le premier BeamSearch.
+
+void CTaskGoto::BeamInit()
+{
+ int i;
+
+ for ( i=0 ; i<MAXPOINTS ; i++ )
+ {
+ m_bmIter[i] = -1;
+ }
+}
+
+// Calcule les points par où passer pour aller de start à goal.
+// Retourne :
+// ERR_OK si c'est bon
+// ERR_GOTO_IMPOSSIBLE si impossible
+// ERR_GOTO_ITER si avorté car trop de récursions
+// ERR_CONTINUE si pas encore fini
+// goalRadius: distance à laquelle il faut s'approcher du but
+
+Error CTaskGoto::BeamSearch(const D3DVECTOR &start, const D3DVECTOR &goal,
+ float goalRadius)
+{
+ float step, len;
+ int nbIter;
+
+ len = Length2d(start, goal);
+ step = len/5.0f;
+ if ( step < BM_DIM_STEP*2.0f ) step = BM_DIM_STEP*2.0f;
+ if ( step > 20.0f ) step = 20.0f;
+ nbIter = 200; // pour ne pas trop baisser le framerate
+ m_bmIterCounter = 0;
+ return BeamExplore(start, start, goal, goalRadius, 165.0f*PI/180.0f, 22, step, 0, nbIter);
+}
+
+// prevPos: position précédente
+// curPos: position courante
+// goalPos: position qu'on cherche à atteindre
+// angle: angle par rapport au but qu'on explore
+// nbDiv: nombre du sous-divisions qu'on fait avec angle
+// step longuer d'un pas
+// i nombre de récursions effectuées
+// nbIter nombre max. d'iterations qu'on a le droit de faire avant d'interrompre provisoirement
+
+Error CTaskGoto::BeamExplore(const D3DVECTOR &prevPos, const D3DVECTOR &curPos,
+ const D3DVECTOR &goalPos, float goalRadius,
+ float angle, int nbDiv, float step,
+ int i, int nbIter)
+{
+ D3DVECTOR newPos;
+ Error ret;
+ int iDiv, iClear, iLar;
+
+ iLar = 0;
+ if ( i >= MAXPOINTS ) return ERR_GOTO_ITER; // trop de récursion
+
+ if ( m_bmIter[i] == -1 )
+ {
+ m_bmIter[i] = 0;
+
+ if ( i == 0 )
+ {
+ m_bmPoints[i] = curPos;
+ }
+ else
+ {
+ if ( !BitmapTestLine(prevPos, curPos, angle/nbDiv, TRUE) ) return ERR_GOTO_IMPOSSIBLE;
+
+ m_bmPoints[i] = curPos;
+
+ if ( Length2d(curPos, goalPos)-goalRadius <= step )
+ {
+ if ( goalRadius == 0.0f )
+ {
+ newPos = goalPos;
+ }
+ else
+ {
+ newPos = BeamPoint(curPos, goalPos, 0, Length2d(curPos, curPos)-goalRadius);
+ }
+ if ( BitmapTestLine(curPos, newPos, angle/nbDiv, FALSE) )
+ {
+ m_bmPoints[i+1] = newPos;
+ m_bmTotal = i+1;
+ return ERR_OK;
+ }
+ }
+ }
+ }
+
+ if ( iLar >= m_bmIter[i] )
+ {
+ newPos = BeamPoint(curPos, goalPos, 0, step);
+ ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
+ if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
+ m_bmIter[i] = iLar+1;
+ for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
+ m_bmIterCounter ++;
+ if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
+ }
+ iLar ++;
+
+ for ( iDiv=1 ; iDiv<=nbDiv ; iDiv++ )
+ {
+ if ( iLar >= m_bmIter[i] )
+ {
+ newPos = BeamPoint(curPos, goalPos, angle*iDiv/nbDiv, step);
+ ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
+ if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
+ m_bmIter[i] = iLar+1;
+ for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
+ m_bmIterCounter ++;
+ if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
+ }
+ iLar ++;
+
+ if ( iLar >= m_bmIter[i] )
+ {
+ newPos = BeamPoint(curPos, goalPos, -angle*iDiv/nbDiv, step);
+ ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
+ if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
+ m_bmIter[i] = iLar+1;
+ for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
+ m_bmIterCounter ++;
+ if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
+ }
+ iLar ++;
+ }
+
+ return ERR_GOTO_IMPOSSIBLE;
+}
+
+// Soit une droite "start-goal". Calcule le point situé à la distance
+// "step" du point "start" et faisant un angle "angle" avec la droite.
+
+D3DVECTOR CTaskGoto::BeamPoint(const D3DVECTOR &startPoint,
+ const D3DVECTOR &goalPoint,
+ float angle, float step)
+{
+ D3DVECTOR resPoint;
+ float goalAngle;
+
+ goalAngle = RotateAngle(goalPoint.x-startPoint.x, goalPoint.z-startPoint.z);
+
+ resPoint.x = startPoint.x + cosf(goalAngle+angle)*step;
+ resPoint.z = startPoint.z + sinf(goalAngle+angle)*step;
+ resPoint.y = 0.0f;
+
+ return resPoint;
+}
+
+// Affiche une partion de bitmap.
+
+void CTaskGoto::BitmapDebug(const D3DVECTOR &min, const D3DVECTOR &max,
+ const D3DVECTOR &start, const D3DVECTOR &goal)
+{
+ int minx, miny, maxx, maxy, x, y, i ,n;
+ char s[2000];
+
+ minx = (int)((min.x+1600.0f)/BM_DIM_STEP);
+ miny = (int)((min.z+1600.0f)/BM_DIM_STEP);
+ maxx = (int)((max.x+1600.0f)/BM_DIM_STEP);
+ maxy = (int)((max.z+1600.0f)/BM_DIM_STEP);
+
+ if ( minx > maxx ) Swap(minx, maxx);
+ if ( miny > maxy ) Swap(miny, maxy);
+
+ OutputDebugString("Bitmap :\n");
+ for ( y=miny ; y<=maxy ; y++ )
+ {
+ s[0] = 0;
+ for ( x=minx ; x<=maxx ; x++ )
+ {
+ n = -1;
+ for ( i=0 ; i<=m_bmTotal ; i++ )
+ {
+ if ( x == (int)((m_bmPoints[i].x+1600.0f)/BM_DIM_STEP) &&
+ y == (int)((m_bmPoints[i].z+1600.0f)/BM_DIM_STEP) )
+ {
+ n = i;
+ break;
+ }
+ }
+
+ if ( BitmapTestDot(0, x,y) )
+ {
+ strcat(s, "o");
+ }
+ else
+ {
+ if ( BitmapTestDot(1, x,y) )
+ {
+ strcat(s, "-");
+ }
+ else
+ {
+ strcat(s, ".");
+ }
+ }
+
+ if ( x == (int)((start.x+1600.0f)/BM_DIM_STEP) &&
+ y == (int)((start.z+1600.0f)/BM_DIM_STEP) )
+ {
+ strcat(s, "s");
+ }
+ else
+ if ( x == (int)((goal.x+1600.0f)/BM_DIM_STEP) &&
+ y == (int)((goal.z+1600.0f)/BM_DIM_STEP) )
+ {
+ strcat(s, "g");
+ }
+ else
+ if ( n != -1 )
+ {
+ char ss[2];
+ ss[0] = 'A'+n;
+ ss[1] = 0;
+ strcat(s, ss);
+ }
+ else
+ {
+ strcat(s, " ");
+ }
+ }
+ strcat(s, "\n");
+ OutputDebugString(s);
+ }
+}
+
+// Teste si un chemin le long d'une droite est possible.
+
+BOOL CTaskGoto::BitmapTestLine(const D3DVECTOR &start, const D3DVECTOR &goal,
+ float stepAngle, BOOL bSecond)
+{
+ D3DVECTOR pos, inc;
+ float dist, step;
+ float distNoB2;
+ int i, max, x, y;
+
+ if ( m_bmArray == 0 ) return TRUE;
+
+ dist = Length2d(start, goal);
+ if ( dist == 0.0f ) return TRUE;
+ step = BM_DIM_STEP*0.5f;
+
+ inc.x = (goal.x-start.x)*step/dist;
+ inc.z = (goal.z-start.z)*step/dist;
+
+ pos = start;
+
+ if ( bSecond )
+ {
+ x = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ y = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+ BitmapSetDot(1, x, y); // met le flag du point de départ
+ }
+
+ max = (int)(dist/step);
+ if ( max == 0 ) max = 1;
+ distNoB2 = BM_DIM_STEP*sqrtf(2.0f)/sinf(stepAngle);
+ for ( i=0 ; i<max ; i++ )
+ {
+ if ( i == max-1 )
+ {
+ pos = goal; // teste le point d'arrivée
+ }
+ else
+ {
+ pos.x += inc.x;
+ pos.z += inc.z;
+ }
+
+ x = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ y = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+
+ if ( bSecond )
+ {
+ if ( i > 2 && BitmapTestDot(1, x, y) ) return FALSE;
+
+ if ( step*(i+1) > distNoB2 && i < max-2 )
+ {
+ BitmapSetDot(1, x, y);
+ }
+ }
+
+ if ( BitmapTestDot(0, x, y) ) return FALSE;
+ }
+ return TRUE;
+}
+
+// Ajoute les objets dans le bitmap.
+
+void CTaskGoto::BitmapObject()
+{
+ CObject *pObj;
+ D3DVECTOR iPos, oPos;
+ float iRadius, oRadius, h;
+ int i, j;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj == m_bmFretObject ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ h = m_terrain->RetFloorLevel(pObj->RetPosition(0), TRUE);
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ h += m_altitude;
+ }
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) // volant ?
+ {
+ if ( oPos.y-oRadius > h+8.0f ||
+ oPos.y+oRadius < h-8.0f ) continue;
+ }
+ else // rampant ?
+ {
+ if ( oPos.y-oRadius > h+8.0f ) continue;
+ }
+
+ BitmapSetCircle(oPos, oRadius+iRadius+4.0f);
+ }
+ }
+}
+
+// Ajoute une portion de terrain dans le bitmap.
+
+void CTaskGoto::BitmapTerrain(const D3DVECTOR &min, const D3DVECTOR &max)
+{
+ int minx, miny, maxx, maxy;
+
+ minx = (int)((min.x+1600.0f)/BM_DIM_STEP);
+ miny = (int)((min.z+1600.0f)/BM_DIM_STEP);
+ maxx = (int)((max.x+1600.0f)/BM_DIM_STEP);
+ maxy = (int)((max.z+1600.0f)/BM_DIM_STEP);
+
+ BitmapTerrain(minx, miny, maxx, maxy);
+}
+
+// Ajoute une portion de terrain dans le bitmap.
+
+void CTaskGoto::BitmapTerrain(int minx, int miny, int maxx, int maxy)
+{
+ ObjectType type;
+ D3DVECTOR p;
+ float aLimit, angle, h;
+ int x, y;
+ BOOL bAcceptWater, bFly;
+
+ if ( minx > maxx ) Swap(minx, maxx);
+ if ( miny > maxy ) Swap(miny, maxy);
+
+ if ( minx < 0 ) minx = 0;
+ if ( miny < 0 ) miny = 0;
+ if ( maxx > m_bmSize-1 ) maxx = m_bmSize-1;
+ if ( maxy > m_bmSize-1 ) maxy = m_bmSize-1;
+
+ if ( minx > m_bmMinX ) minx = m_bmMinX;
+ if ( miny > m_bmMinY ) miny = m_bmMinY;
+ if ( maxx < m_bmMaxX ) maxx = m_bmMaxX;
+ if ( maxy < m_bmMaxY ) maxy = m_bmMaxY;
+
+ if ( minx >= m_bmMinX && maxx <= m_bmMaxX &&
+ miny >= m_bmMinY && maxy <= m_bmMaxY ) return;
+
+ aLimit = 20.0f*PI/180.0f;
+ bAcceptWater = FALSE;
+ bFly = FALSE;
+
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEtg ) // roues ?
+ {
+ aLimit = 20.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ) // chenilles ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEsa ) // chenilles sous-marin ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ bAcceptWater = TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+ aLimit = 15.0f*PI/180.0f;
+ bFly = TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEii ) // pattes d'insecte ?
+ {
+ aLimit = 60.0f*PI/180.0f;
+ }
+
+ for ( y=miny ; y<=maxy ; y++ )
+ {
+ for ( x=minx ; x<=maxx ; x++ )
+ {
+ if ( x >= m_bmMinX && x <= m_bmMaxX &&
+ y >= m_bmMinY && y <= m_bmMaxY ) continue;
+
+ p.x = x*BM_DIM_STEP-1600.0f;
+ p.z = y*BM_DIM_STEP-1600.0f;
+
+ if ( bFly ) // robot volant ?
+ {
+ h = m_terrain->RetFloorLevel(p, TRUE);
+ if ( h >= m_terrain->RetFlyingMaxHeight()-5.0f )
+ {
+ BitmapSetDot(0, x, y);
+ }
+ continue;
+ }
+
+ if ( !bAcceptWater ) // ne va pas sous l'eau ?
+ {
+ h = m_terrain->RetFloorLevel(p, TRUE);
+//? if ( h <= m_water->RetLevel()+1.0f ) // sous l'eau ?
+ if ( h < m_water->RetLevel()-2.0f ) // sous l'eau ?
+ {
+//? BitmapSetDot(0, x, y);
+ BitmapSetCircle(p, BM_DIM_STEP*1.0f);
+ continue;
+ }
+ }
+
+ angle = m_terrain->RetFineSlope(p);
+ if ( angle > aLimit )
+ {
+ BitmapSetDot(0, x, y);
+ }
+ }
+ }
+
+ m_bmMinX = minx;
+ m_bmMinY = miny;
+ m_bmMaxX = maxx;
+ m_bmMaxY = maxy;
+}
+
+// Ouvre un bitmap vide.
+
+BOOL CTaskGoto::BitmapOpen()
+{
+ BitmapClose();
+
+ m_bmSize = (int)(3200.0f/BM_DIM_STEP);
+ m_bmArray = (unsigned char*)malloc(m_bmSize*m_bmSize/8*2);
+ ZeroMemory(m_bmArray, m_bmSize*m_bmSize/8*2);
+
+ m_bmOffset = m_bmSize/2;
+ m_bmLine = m_bmSize/8;
+
+ m_bmMinX = m_bmSize;
+ m_bmMinY = m_bmSize;
+ m_bmMaxX = 0;
+ m_bmMaxY = 0;
+
+ return TRUE;
+}
+
+// Ferme le bitmap.
+
+BOOL CTaskGoto::BitmapClose()
+{
+ free(m_bmArray);
+ m_bmArray = 0;
+ return TRUE;
+}
+
+// Met un cercle dans le bitmap.
+
+void CTaskGoto::BitmapSetCircle(const D3DVECTOR &pos, float radius)
+{
+ float d, r;
+ int cx, cy, ix, iy;
+
+ cx = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ cy = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+ r = radius/BM_DIM_STEP;
+
+ for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ )
+ {
+ for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ )
+ {
+ d = Length((float)(ix-cx), (float)(iy-cy));
+ if ( d > r ) continue;
+ BitmapSetDot(0, ix, iy);
+ }
+ }
+}
+
+// Met un point dans le bitmap.
+// x:y: 0..m_bmSize-1
+
+void CTaskGoto::BitmapSetDot(int rank, int x, int y)
+{
+ if ( x < 0 || x >= m_bmSize ||
+ y < 0 || y >= m_bmSize ) return;
+
+ m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] |= (1<<x%8);
+}
+
+// Teste un point dans le bitmap.
+// x:y: 0..m_bmSize-1
+
+BOOL CTaskGoto::BitmapTestDot(int rank, int x, int y)
+{
+ if ( x < 0 || x >= m_bmSize ||
+ y < 0 || y >= m_bmSize ) return FALSE;
+
+ if ( x < m_bmMinX || x > m_bmMaxX ||
+ y < m_bmMinY || y > m_bmMaxY )
+ {
+ BitmapTerrain(x-10,y-10, x+10,y+10); // refait une couche
+ }
+
+ return m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] & (1<<x%8);
+}
+
+
diff --git a/src/DirectX.ico b/src/DirectX.ico
new file mode 100644
index 0000000..9752f54
--- /dev/null
+++ b/src/DirectX.ico
Binary files differ
diff --git a/src/accents.txt b/src/accents.txt
new file mode 100644
index 0000000..9473b1b
--- /dev/null
+++ b/src/accents.txt
@@ -0,0 +1,5 @@
+!"#$%&'()*+,-./0123456789:;<=>?
+@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^
+_abcdefghijklmnopqrstuvwxyz{|}~
+ÁÀÂÄÃÇÉÈÊËÍÌÎÏÑÓÒÔÖÕÚÙÛÜ
+áàâäãçéèêëíìîïñóòôöõúùûü
diff --git a/src/auto.cpp b/src/auto.cpp
new file mode 100644
index 0000000..3f0d549
--- /dev/null
+++ b/src/auto.cpp
@@ -0,0 +1,447 @@
+// auto.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "water.h"
+#include "cloud.h"
+#include "planet.h"
+#include "blitz.h"
+#include "camera.h"
+#include "object.h"
+#include "modfile.h"
+#include "interface.h"
+#include "button.h"
+#include "list.h"
+#include "label.h"
+#include "gauge.h"
+#include "window.h"
+#include "robotmain.h"
+#include "displaytext.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "auto.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAuto::CAuto(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_AUTO, this, 100);
+
+ m_object = object;
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_cloud = (CCloud*)m_iMan->SearchInstance(CLASS_CLOUD);
+ m_planet = (CPlanet*)m_iMan->SearchInstance(CLASS_PLANET);
+ m_blitz = (CBlitz*)m_iMan->SearchInstance(CLASS_BLITZ);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_type = m_object->RetType();
+ m_time = 0.0f;
+ m_lastUpdateTime = 0.0f;
+ m_bMotor = FALSE;
+ m_progressTime = 0.0f;
+ m_progressTotal = 1.0f;
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAuto::~CAuto()
+{
+ m_iMan->DeleteInstance(CLASS_AUTO, this);
+}
+
+
+// Détruit l'objet.
+
+void CAuto::DeleteObject(BOOL bAll)
+{
+}
+
+
+// Initialise l'objet.
+
+void CAuto::Init()
+{
+ m_bBusy = FALSE;
+}
+
+// Démarre l'objet.
+
+void CAuto::Start(int param)
+{
+}
+
+
+// Donne un type.
+
+BOOL CAuto::SetType(ObjectType type)
+{
+ return FALSE;
+}
+
+// Donne une valeur.
+
+BOOL CAuto::SetValue(int rank, float value)
+{
+ return FALSE;
+}
+
+// Donne la string.
+
+BOOL CAuto::SetString(char *string)
+{
+ return FALSE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAuto::EventProcess(const Event &event)
+{
+ if ( event.event == EVENT_FRAME &&
+ !m_engine->RetPause() )
+ {
+ m_time += event.rTime;
+ UpdateInterface(event.rTime);
+ }
+
+ if ( !m_object->RetSelect() ) // robot pas sélectionné ?
+ {
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+// Indique si l'automate a terminé son activité.
+
+Error CAuto::IsEnded()
+{
+ return ERR_CONTINUE;
+}
+
+// Stoppe l'automate.
+
+BOOL CAuto::Abort()
+{
+ return FALSE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAuto::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+ char name[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 )
+ {
+ pw->Flush(); // détruit les boutons de la fenêtre
+ m_interface->DeleteControl(EVENT_WINDOW0); // détruit la fenêtre
+ }
+
+ if ( !bSelect ) return TRUE;
+
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ dim.x = 540.0f/640.0f;
+//? dim.y = 70.0f/480.0f;
+ dim.y = 86.0f/480.0f;
+ m_interface->CreateWindows(pos, dim, 3, EVENT_WINDOW0);
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ m_object->GetTooltipName(name);
+ pos.x = 0.0f;
+ pos.y = 64.0f/480.0f;
+ ddim.x = 540.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, name);
+
+ dim.x = 33.0f/640.0f;
+ dim.y = 33.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*0.6f;
+ ddim.x = 160.0f/640.0f;
+ ddim.y = 26.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 0, EVENT_OBJECT_GPROGRESS);
+
+ if ( m_type != OBJECT_BASE &&
+ m_type != OBJECT_SAFE &&
+ m_type != OBJECT_HUSTON )
+ {
+ pos.x = ox+sx*2.1f;
+ pos.y = oy+sy*0;
+ ddim.x = dim.x*0.6f;
+ ddim.y = dim.y*0.6f;
+ pw->CreateButton(pos, ddim, 12, EVENT_OBJECT_DELETE);
+ }
+
+#if 0
+ pos.x = ox+sx*12.4f;
+ pos.y = oy+sy*1;
+ pw->CreateButton(pos, dim, 63, EVENT_OBJECT_BHELP);
+
+ pos.x = ox+sx*12.4f;
+ pos.y = oy+sy*0;
+ pw->CreateButton(pos, dim, 19, EVENT_OBJECT_HELP);
+
+ if ( m_main->RetSceneSoluce() )
+ {
+ pos.x = ox+sx*13.4f;
+ pos.y = oy+sy*1;
+ pw->CreateButton(pos, dim, 20, EVENT_OBJECT_SOLUCE);
+ }
+
+ pos.x = ox+sx*13.4f;
+ pos.y = oy+sy*0;
+ pw->CreateButton(pos, dim, 10, EVENT_OBJECT_DESELECT);
+#else
+ pos.x = ox+sx*12.3f;
+ pos.y = oy+sy*-0.1f;
+ ddim.x = dim.x*1.0f;
+ ddim.y = dim.y*2.1f;
+ pw->CreateGroup(pos, ddim, 20, EVENT_NULL); // fond bleu uni
+
+ pos.x = ox+sx*12.3f;
+ pos.y = oy+sy*1;
+ pw->CreateGroup(pos, dim, 19, EVENT_NULL); // signe SatCom
+
+ pos.x = ox+sx*12.4f;
+ pos.y = oy+sy*0.5f;
+ ddim.x = dim.x*0.8f;
+ ddim.y = dim.y*0.5f;
+ pw->CreateButton(pos, ddim, 18, EVENT_OBJECT_BHELP);
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, ddim, 19, EVENT_OBJECT_HELP);
+
+ pos.x = ox+sx*13.4f;
+ pos.y = oy+sy*0;
+ pw->CreateButton(pos, dim, 10, EVENT_OBJECT_DESELECT);
+#endif
+
+ pos.x = ox+sx*14.9f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 3, EVENT_OBJECT_GSHIELD);
+
+ UpdateInterface();
+ m_lastUpdateTime = 0.0f;
+ UpdateInterface(0.0f);
+
+ return TRUE;
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CAuto::CheckInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_CHECK, bState);
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CAuto::EnableInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_ENABLE, bState);
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CAuto::VisibleInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_VISIBLE, bState);
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CAuto::DeadInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_DEAD, !bState);
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CAuto::UpdateInterface()
+{
+ CWindow* pw;
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ VisibleInterface(pw, EVENT_OBJECT_GPROGRESS, m_bBusy);
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CAuto::UpdateInterface(float rTime)
+{
+ CWindow* pw;
+ CGauge* pg;
+
+ if ( m_time < m_lastUpdateTime+0.1f ) return;
+ m_lastUpdateTime = m_time;
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GSHIELD);
+ if ( pg != 0 )
+ {
+ pg->SetLevel(m_object->RetShield());
+ }
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GPROGRESS);
+ if ( pg != 0 )
+ {
+ pg->SetLevel(m_progressTime);
+ }
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAuto::RetError()
+{
+ return ERR_OK;
+}
+
+
+// Gestion de l'occupation.
+
+BOOL CAuto::RetBusy()
+{
+ return m_bBusy;
+}
+
+void CAuto::SetBusy(BOOL bBusy)
+{
+ m_bBusy = bBusy;
+}
+
+void CAuto::InitProgressTotal(float total)
+{
+ m_progressTime = 0.0f;
+ m_progressTotal = total;
+}
+
+void CAuto::EventProgress(float rTime)
+{
+ m_progressTime += rTime/m_progressTotal;
+}
+
+
+// Gestion du moteur.
+
+BOOL CAuto::RetMotor()
+{
+ return m_bMotor;
+}
+
+void CAuto::SetMotor(BOOL bMotor)
+{
+ m_bMotor = bMotor;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAuto::Write(char *line)
+{
+ char name[100];
+
+ sprintf(name, " aType=%d", m_type);
+ strcat(line, name);
+
+ sprintf(name, " aBusy=%d", m_bBusy);
+ strcat(line, name);
+
+ sprintf(name, " aTime=%.2f", m_time);
+ strcat(line, name);
+
+ sprintf(name, " aProgressTime=%.2f", m_progressTime);
+ strcat(line, name);
+
+ sprintf(name, " aProgressTotal=%.2f", m_progressTotal);
+ strcat(line, name);
+
+ return FALSE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAuto::Read(char *line)
+{
+ m_type = (ObjectType)OpInt(line, "aType", OBJECT_NULL);
+ m_bBusy = OpInt(line, "aBusy", 0);
+ m_time = OpFloat(line, "aTime", 0.0f);
+ m_progressTime = OpFloat(line, "aProgressTime", 0.0f);
+ m_progressTotal = OpFloat(line, "aProgressTotal", 0.0f);
+
+ return FALSE;
+}
+
diff --git a/src/auto.h b/src/auto.h
new file mode 100644
index 0000000..5b0f331
--- /dev/null
+++ b/src/auto.h
@@ -0,0 +1,95 @@
+// auto.h
+
+#ifndef _AUTO_H_
+#define _AUTO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CLight;
+class CTerrain;
+class CWater;
+class CCloud;
+class CPlanet;
+class CBlitz;
+class CCamera;
+class CObject;
+class CInterface;
+class CRobotMain;
+class CDisplayText;
+class CWindow;
+class CSound;
+
+
+
+
+class CAuto
+{
+public:
+ CAuto(CInstanceManager* iMan, CObject* object);
+ ~CAuto();
+
+ virtual void DeleteObject(BOOL bAll=FALSE);
+
+ virtual void Init();
+ virtual void Start(int param);
+ virtual BOOL EventProcess(const Event &event);
+ virtual Error IsEnded();
+ virtual BOOL Abort();
+
+ virtual BOOL SetType(ObjectType type);
+ virtual BOOL SetValue(int rank, float value);
+ virtual BOOL SetString(char *string);
+
+ virtual BOOL CreateInterface(BOOL bSelect);
+ virtual Error RetError();
+
+ virtual BOOL RetBusy();
+ virtual void SetBusy(BOOL bBuse);
+ virtual void InitProgressTotal(float total);
+ virtual void EventProgress(float rTime);
+
+ virtual BOOL RetMotor();
+ virtual void SetMotor(BOOL bMotor);
+
+ virtual BOOL Write(char *line);
+ virtual BOOL Read(char *line);
+
+protected:
+ void CheckInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void EnableInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void VisibleInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void DeadInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void UpdateInterface();
+ void UpdateInterface(float rTime);
+
+protected:
+ CInstanceManager* m_iMan;
+ CEvent* m_event;
+ CD3DEngine* m_engine;
+ CParticule* m_particule;
+ CLight* m_light;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCloud * m_cloud;
+ CPlanet * m_planet;
+ CBlitz* m_blitz;
+ CCamera* m_camera;
+ CInterface* m_interface;
+ CRobotMain* m_main;
+ CDisplayText* m_displayText;
+ CObject* m_object;
+ CSound* m_sound;
+
+ ObjectType m_type;
+ BOOL m_bBusy;
+ BOOL m_bMotor;
+ float m_time;
+ float m_lastUpdateTime;
+ float m_progressTime;
+ float m_progressTotal;
+};
+
+
+#endif //_AUTO_H_
diff --git a/src/autobase.cpp b/src/autobase.cpp
new file mode 100644
index 0000000..db046ef
--- /dev/null
+++ b/src/autobase.cpp
@@ -0,0 +1,1446 @@
+// autobase.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "cloud.h"
+#include "planet.h"
+#include "blitz.h"
+#include "camera.h"
+#include "object.h"
+#include "physics.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "displaytext.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "auto.h"
+#include "autobase.h"
+
+
+
+#define BASE_LAND_TIME 7.5f // durée atterrissage
+#define BASE_TAKO_TIME 10.0f // durée atterrissage
+#define BASE_DOOR_TIME 6.0f // durée ouverture/fermeture
+#define BASE_DOOR_TIME2 2.0f // durée ouverture/fermeture suppl.
+#define BASE_PORTICO_TIME_MOVE 16.0f // durée avance portique
+#define BASE_PORTICO_TIME_DOWN 4.0f // durée descente portique
+#define BASE_PORTICO_TIME_OPEN 4.0f // durée ouverture portique
+#define BASE_TRANSIT_TIME 15.0f // durée transit
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoBase::CAutoBase(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ m_fogStart = m_engine->RetFogStart();
+ m_deepView = m_engine->RetDeepView();
+ Init();
+ m_phase = ABP_WAIT;
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CAutoBase::~CAutoBase()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoBase::DeleteObject(BOOL bAll)
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoBase::Init()
+{
+ m_bOpen = FALSE;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_lastMotorParticule = 0.0f;
+
+ m_pos = m_object->RetPosition(0);
+ m_lastPos = m_pos;
+
+ m_phase = ABP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+}
+
+
+// Démarre l'objet.
+
+void CAutoBase::Start(int param)
+{
+ m_phase = ABP_START;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ m_param = param;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoBase::EventProcess(const Event &event)
+{
+ D3DMATRIX* mat;
+ Event newEvent;
+ CObject* pObj;
+ D3DVECTOR pos, speed, vibCir, iPos;
+ FPOINT dim, p;
+ Error err;
+ float angle, dist, time, h, len, vSpeed;
+ int i, max;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+begin:
+ iPos = m_object->RetPosition(0);
+
+ if ( m_phase == ABP_START )
+ {
+ if ( m_param != PARAM_STOP && // pas posé au sol ?
+ m_param != PARAM_FIXSCENE )
+ {
+ FreezeCargo(TRUE); // gèle toute la cargaison
+ }
+
+ if ( m_param == PARAM_STOP ) // posé au sol ?
+ {
+ m_phase = ABP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f-124.0f*PI/180.0f);
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f);
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f);
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, -11.5f));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, 11.5f));
+ }
+
+ pObj = m_main->RetSelectObject();
+ m_main->SelectObject(pObj);
+ m_camera->SetObject(pObj);
+ if ( pObj == 0 )
+ {
+ m_camera->SetType(CAMERA_BACK);
+ }
+ else
+ {
+ m_camera->SetType(pObj->RetCameraType());
+ m_camera->SetDist(pObj->RetCameraDist());
+ }
+
+ m_main->StartMusic();
+ }
+
+ if ( m_param == PARAM_FIXSCENE ) // posé au sol ?
+ {
+ m_phase = ABP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f-124.0f*PI/180.0f);
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f);
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f);
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, -11.5f));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, 11.5f));
+ }
+ }
+
+ if ( m_param == PARAM_LANDING ) // atterrissage ?
+ {
+ m_phase = ABP_LAND;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_LAND_TIME;
+
+ m_main->SetMovieLock(TRUE); // bloque tout jusqu'à la fin de l'atterrissage
+ m_bMotor = TRUE; // allume le réacteur
+
+ m_camera->SetType(CAMERA_SCRIPT);
+
+ pos = m_pos;
+ pos.x -= 150.0f;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 10.0f;
+ m_camera->SetScriptEye(pos);
+ m_posSound = pos;
+
+ pos = m_object->RetPosition(0);
+ pos.y += 300.0f+50.0f;
+ m_camera->SetScriptLookat(pos);
+
+ m_camera->FixCamera();
+ m_engine->SetFocus(2.0f);
+
+ m_engine->SetFogStart(0.9f);
+
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_FLY, m_posSound, 0.3f, 2.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.5f, BASE_LAND_TIME, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 2.0f, SOPER_STOP);
+ }
+
+ m_main->StartMusic();
+ }
+
+ if ( m_param == PARAM_PORTICO ) // porté par le portique ?
+ {
+ pos = m_object->RetPosition(0);
+ m_finalPos = pos;
+ pos.z += BASE_PORTICO_TIME_MOVE*5.0f; // recule
+ pos.y += 10.0f; // monte (porté par le portique)
+ m_object->SetPosition(0, pos);
+ MoveCargo(); // déplace toute la cargaison
+
+ m_phase = ABP_PORTICO_MOVE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_PORTICO_TIME_MOVE;
+
+ m_main->StartMusic();
+ }
+
+ if ( m_param == PARAM_TRANSIT1 ||
+ m_param == PARAM_TRANSIT2 ||
+ m_param == PARAM_TRANSIT3 ) // transit dans l'espace ?
+ {
+ m_phase = ABP_TRANSIT_MOVE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_TRANSIT_TIME;
+
+ m_object->SetAngleZ(0, -PI/2.0f);
+ pos = m_object->RetPosition(0);
+ pos.y += 10000.0f; // dans l'espace
+ m_finalPos = pos;
+ m_object->SetPosition(0, pos);
+
+ m_main->SetMovieLock(TRUE); // bloque tout jusqu'à la fin de l'atterrissage
+ m_bMotor = TRUE; // allume le réacteur
+
+ m_camera->SetType(CAMERA_SCRIPT);
+ pos.x += 1000.0f;
+ pos.z -= 60.0f;
+ pos.y += 80.0f;
+ m_camera->SetScriptEye(pos);
+ m_posSound = pos;
+ m_camera->FixCamera();
+ m_engine->SetFocus(1.0f);
+
+ BeginTransit();
+
+ mat = m_object->RetWorldMatrix(0);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 10.0f;
+ dim.y = dim.x;
+ pos = D3DVECTOR(42.0f, -2.0f, 17.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[0] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(17.0f, -2.0f, 42.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[1] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(42.0f, -2.0f, -17.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[2] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(17.0f, -2.0f, -42.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[3] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-42.0f, -2.0f, 17.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[4] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-17.0f, -2.0f, 42.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[5] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-42.0f, -2.0f, -17.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[6] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-17.0f, -2.0f, -42.0f);
+ pos = Transform(*mat, pos);
+ m_partiChannel[7] = m_particule->CreateParticule(pos, speed, dim, PARTILENS1, BASE_TRANSIT_TIME+1.0f, 0.0f, 0.0f);
+
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_FLY, m_posSound, 0.0f, 1.2f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, BASE_TRANSIT_TIME*0.55f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 0.8f, BASE_TRANSIT_TIME*0.45f, SOPER_STOP);
+ }
+ }
+ }
+
+ if ( event.event == EVENT_UPDINTERFACE )
+ {
+ if ( m_object->RetSelect() ) CreateInterface(TRUE);
+ }
+
+ if ( event.event == EVENT_OBJECT_BTAKEOFF )
+ {
+ err = CheckCloseDoor();
+ if ( err != ERR_OK )
+ {
+ m_displayText->DisplayError(err, m_object);
+ return FALSE;
+ }
+
+ err = m_main->CheckEndMission(FALSE);
+ if ( err != ERR_OK )
+ {
+ m_displayText->DisplayError(err, m_object);
+ return FALSE;
+ }
+
+ FreezeCargo(TRUE); // gèle toute la cargaison
+ m_main->SetMovieLock(TRUE); // bloque tout jusqu'à la fin
+ m_main->DeselectAll();
+
+ m_event->MakeEvent(newEvent, EVENT_UPDINTERFACE);
+ m_event->AddEvent(newEvent);
+
+ m_camera->SetType(CAMERA_SCRIPT);
+
+ pos = m_pos;
+ pos.x -= 110.0f;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 10.0f;
+ m_camera->SetScriptEye(pos);
+ m_posSound = pos;
+
+ pos = m_object->RetPosition(0);
+ pos.y += 50.0f;
+ m_camera->SetScriptLookat(pos);
+
+ m_engine->SetFocus(1.0f);
+
+ m_soundChannel = m_sound->Play(SOUND_MANIP, m_posSound, 0.3f, 1.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 1.5f, BASE_DOOR_TIME2, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.5f, 0.5f, SOPER_STOP);
+
+ m_phase = ABP_CLOSE2;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_DOOR_TIME2;
+ return TRUE;
+ }
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_phase == ABP_WAIT ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == ABP_LAND )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_pos;
+ pos.y += powf(1.0f-m_progress, 2.0f)*300.0f;
+ m_object->SetPosition(0, pos);
+ MoveCargo(); // déplace toute la cargaison
+
+ vibCir.z = sinf(m_time*PI* 2.01f)*(PI/150.0f)+
+ sinf(m_time*PI* 2.51f)*(PI/200.0f)+
+ sinf(m_time*PI*19.01f)*(PI/400.0f);
+ vibCir.x = sinf(m_time*PI* 2.03f)*(PI/150.0f)+
+ sinf(m_time*PI* 2.52f)*(PI/200.0f)+
+ sinf(m_time*PI*19.53f)*(PI/400.0f);
+ vibCir.y = 0.0f;
+ vibCir *= Min(1.0f, (1.0f-m_progress)*3.0f);
+ m_object->SetCirVibration(vibCir);
+
+ pos = m_pos;
+ pos.x -= 150.0f;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 10.0f;
+ m_camera->SetScriptEye(pos);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 50.0f;
+ m_camera->SetScriptLookat(pos);
+
+ m_engine->SetFocus(1.0f+(1.0f-m_progress));
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ // Poussière éjectée au sol.
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ angle = Rand()*(PI*2.0f);
+ dist = m_progress*50.0f;
+ p = RotatePoint(angle, dist);
+ speed.x = p.x;
+ speed.z = p.y;
+ speed.y = 0.0f;
+ dim.x = (Rand()*15.0f+15.0f)*m_progress;
+ dim.y = dim.x;
+ if ( dim.x >= 1.0f )
+ {
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 2.0f);
+ }
+
+ // Particules éjectées du réacteur.
+ pos = m_object->RetPosition(0);
+ pos.y += 6.0f;
+ h = m_terrain->RetFloorHeight(pos)/300.0f;
+ speed.x = (Rand()-0.5f)*(80.0f-50.0f*h);
+ speed.z = (Rand()-0.5f)*(80.0f-50.0f*h);
+ speed.y = -(Rand()*(h+1.0f)*40.0f+(h+1.0f)*40.0f);
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 2.0f, 10.0f, 2.0f);
+
+ // Fumée noire du réacteur.
+ if ( m_progress > 0.8f )
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*8.0f;
+ pos.z += (Rand()-0.5f)*8.0f;
+ pos.y += 3.0f;
+ speed.x = (Rand()-0.5f)*8.0f;
+ speed.z = (Rand()-0.5f)*8.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*4.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f, 0.0f, 2.0f);
+ }
+ }
+ }
+ else
+ {
+ m_bMotor = FALSE; // éteint le réacteur
+
+ m_object->SetPosition(0, m_pos); // posé au sol
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ MoveCargo(); // déplace toute la cargaison
+
+ // Choc avec le sol.
+ max = (int)(50.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ angle = Rand()*(PI*2.0f);
+ p = RotatePoint(angle, 46.0f);
+ pos = m_pos;
+ pos.x += p.x;
+ pos.z += p.y;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*10.0f+10.0f;
+ dim.y = dim.x;
+ time = Rand()*2.0f+1.5f;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, time, 0.0f, 2.0f);
+ }
+
+//? m_camera->StartEffect(CE_CRASH, m_pos, 1.0f);
+ m_camera->StartEffect(CE_EXPLO, m_pos, 2.0f);
+ m_engine->SetFocus(1.0f);
+ m_sound->Play(SOUND_BOUM, m_posSound, 0.6f, 0.5f);
+
+ m_phase = ABP_OPENWAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == ABP_OPENWAIT )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ // Fumée noire du réacteur.
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*8.0f;
+ pos.z += (Rand()-0.5f)*8.0f;
+ pos.y += 3.0f;
+ speed.x = (Rand()-0.5f)*8.0f;
+ speed.z = (Rand()-0.5f)*8.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*4.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f, 0.0f, 2.0f);
+ }
+ }
+ else
+ {
+ m_soundChannel = m_sound->Play(SOUND_MANIP, m_posSound, 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 0.3f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 1.0f, BASE_DOOR_TIME-1.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.3f, 1.0f, SOPER_STOP);
+
+ m_phase = ABP_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_DOOR_TIME;
+ }
+ }
+
+ if ( m_phase == ABP_OPEN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = -m_progress*124.0f*PI/180.0f;
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f+angle);
+ }
+
+ if ( m_param != PARAM_PORTICO )
+ {
+ angle = m_progress*PI*2.0f;
+ p = RotatePoint(angle, -150.0f);
+ pos = m_pos;
+ pos.x += p.x;
+ pos.z += p.y;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 10.0f;
+ pos.y += m_progress*40.0f;
+ m_camera->SetScriptEye(pos);
+
+ m_engine->SetFogStart(0.9f-(0.9f-m_fogStart)*m_progress);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f-124.0f*PI/180.0f);
+ }
+
+ // Choc des portes avec le sol.
+ max = (int)(20.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ angle = Rand()*(20.0f*PI/180.0f)-(10.0f*PI/180.0f);
+ angle += (PI/4.0f)*(rand()%8);
+ p = RotatePoint(angle, 74.0f);
+ pos = m_pos;
+ pos.x += p.x;
+ pos.z += p.y;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*8.0f+8.0f;
+ dim.y = dim.x;
+ time = Rand()*2.0f+1.5f;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, time, 0.0f, 2.0f);
+ }
+
+ m_soundChannel = m_sound->Play(SOUND_MANIP, m_posSound, 0.3f, 1.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 1.5f, BASE_DOOR_TIME2, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.5f, 0.5f, SOPER_STOP);
+
+ m_phase = ABP_OPEN2;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_DOOR_TIME2;
+ }
+ }
+
+ if ( m_phase == ABP_OPEN2 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ len = 7.0f-m_progress*(7.0f+11.5f);
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, len));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, -len));
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f*m_progress);
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f*m_progress);
+ }
+
+ if ( m_param != PARAM_PORTICO )
+ {
+ angle = m_progress*PI/2.0f;
+ p = RotatePoint(angle, -150.0f);
+ pos = m_pos;
+ pos.x += p.x;
+ pos.z += p.y;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 10.0f;
+ pos.y += m_progress*40.0f;
+ m_camera->SetScriptEye(pos);
+
+ m_engine->SetFogStart(0.9f-(0.9f-m_fogStart)*m_progress);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, -11.5f));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, 11.5f));
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f);
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f);
+ }
+
+ m_phase = ABP_LDWAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ABP_LDWAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ FreezeCargo(FALSE); // libère toute la cargaison
+
+ if ( m_param != PARAM_PORTICO )
+ {
+ m_main->SetMovieLock(FALSE); // on peut jouer !
+
+ pObj = m_main->RetSelectObject();
+ m_main->SelectObject(pObj);
+ m_camera->SetObject(pObj);
+ if ( pObj == 0 )
+ {
+ m_camera->SetType(CAMERA_BACK);
+ }
+ else
+ {
+ m_camera->SetType(pObj->RetCameraType());
+ m_camera->SetDist(pObj->RetCameraDist());
+ }
+ m_sound->Play(SOUND_BOUM, m_object->RetPosition(0));
+ m_soundChannel = -1;
+
+ m_engine->SetFogStart(m_fogStart);
+ }
+
+ m_bOpen = TRUE;
+ m_phase = ABP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ABP_CLOSE2 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ len = 7.0f-(1.0f-m_progress)*(7.0f+11.5f);
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, len));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, -len));
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f*(1.0f-m_progress));
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f*(1.0f-m_progress));
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, 7.0f));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, -7.0f));
+ m_object->SetAngleX(10+i, 0.0f);
+ m_object->SetAngleX(18+i, 0.0f);
+ }
+
+ m_soundChannel = m_sound->Play(SOUND_MANIP, m_posSound, 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 0.3f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 1.0f, BASE_DOOR_TIME-1.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.3f, 1.0f, SOPER_STOP);
+
+ m_phase = ABP_CLOSE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_DOOR_TIME;
+ }
+ }
+
+ if ( m_phase == ABP_CLOSE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = -(1.0f-m_progress)*124.0f*PI/180.0f;
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f+angle);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f);
+ }
+ m_bMotor = TRUE; // allume le réacteur
+
+ // Choc de la fermeture des portes.
+ max = (int)(20.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ angle = Rand()*PI*2.0f;
+ p = RotatePoint(angle, 32.0f);
+ pos = m_pos;
+ pos.x += p.x;
+ pos.z += p.y;
+ pos.y += 85.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*3.0f+3.0f;
+ dim.y = dim.x;
+ time = Rand()*1.0f+1.0f;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, time);
+ }
+ m_sound->Play(SOUND_BOUM, m_object->RetPosition(0));
+
+ m_soundChannel = -1;
+ m_bOpen = FALSE;
+ m_phase = ABP_TOWAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == ABP_TOWAIT )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_FLY, m_posSound, 0.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.5f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 2.0f, BASE_TAKO_TIME, SOPER_STOP);
+ }
+
+ vibCir.z = sinf(m_time*PI*19.01f)*(PI/400.0f);
+ vibCir.x = sinf(m_time*PI*19.53f)*(PI/400.0f);
+ vibCir.y = 0.0f;
+ vibCir *= m_progress*1.0f;
+ m_object->SetCirVibration(vibCir);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ // Particules éjectées du réacteur.
+ pos = m_object->RetPosition(0);
+ pos.y += 6.0f;
+ speed.x = (Rand()-0.5f)*160.0f;
+ speed.z = (Rand()-0.5f)*160.0f;
+ speed.y = -(Rand()*10.0f+10.0f);
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 2.0f, 10.0f, 2.0f);
+ }
+
+ m_engine->SetFogStart(m_fogStart+(0.9f-m_fogStart)*m_progress);
+ }
+ else
+ {
+ m_engine->SetFogStart(0.9f);
+
+ m_phase = ABP_TAKEOFF;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_TAKO_TIME;
+ }
+ }
+
+ if ( m_phase == ABP_TAKEOFF )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_pos;
+ pos.y += powf(m_progress, 2.0f)*600.0f;
+ m_object->SetPosition(0, pos);
+ MoveCargo(); // déplace toute la cargaison
+
+ vibCir.z = sinf(m_time*PI*19.01f)*(PI/400.0f);
+ vibCir.x = sinf(m_time*PI*19.53f)*(PI/400.0f);
+ vibCir.y = 0.0f;
+ m_object->SetCirVibration(vibCir);
+
+ pos = m_pos;
+ pos.x -= 110.0f+m_progress*250.0f;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 10.0f;
+ m_camera->SetScriptEye(pos);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 50.0f;
+ m_camera->SetScriptLookat(pos);
+
+ m_engine->SetFocus(1.0f+m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ // Poussière éjectée au sol.
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ angle = Rand()*(PI*2.0f);
+ dist = (1.0f-m_progress)*50.0f;
+ p = RotatePoint(angle, dist);
+ speed.x = p.x;
+ speed.z = p.y;
+ speed.y = 0.0f;
+ dim.x = (Rand()*10.0f+10.0f)*(1.0f-m_progress);
+ dim.y = dim.x;
+ if ( dim.x >= 1.0f )
+ {
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 2.0f);
+ }
+
+ // Particules éjectées du réacteur.
+ pos = m_object->RetPosition(0);
+ pos.y += 6.0f;
+ speed.x = (Rand()-0.5f)*40.0f;
+ speed.z = (Rand()-0.5f)*40.0f;
+ time = 5.0f+150.0f*m_progress;
+ speed.y = -(Rand()*time+time);
+ time = 2.0f+m_progress*12.0f;
+ dim.x = Rand()*time+time;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 2.0f, 10.0f, 2.0f);
+
+ // Fumée noire du réacteur.
+ pos = m_object->RetPosition(0);
+ pos.y += 3.0f;
+ speed.x = (Rand()-0.5f)*10.0f*(4.0f-m_progress*3.0f);
+ speed.z = (Rand()-0.5f)*10.0f*(4.0f-m_progress*3.0f);
+ speed.y = 0.0f;
+ dim.x = Rand()*20.0f+20.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 10.0f, 0.0f, 2.0f);
+ }
+ }
+ else
+ {
+ m_soundChannel = -1;
+ m_event->MakeEvent(newEvent, EVENT_WIN);
+ m_event->AddEvent(newEvent);
+
+ m_phase = ABP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == ABP_PORTICO_MOVE ) // avance du portique ?
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.z -= event.rTime*5.0f;
+ m_object->SetPosition(0, pos);
+ MoveCargo(); // déplace toute la cargaison
+ }
+ else
+ {
+ m_phase = ABP_PORTICO_WAIT1;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ABP_PORTICO_WAIT1 ) // attente du portique ?
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_phase = ABP_PORTICO_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_PORTICO_TIME_DOWN;
+ }
+ }
+
+ if ( m_phase == ABP_PORTICO_DOWN ) // descente du portique ?
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.y -= event.rTime*(10.0f/BASE_PORTICO_TIME_DOWN);
+ m_object->SetPosition(0, pos);
+ MoveCargo(); // déplace toute la cargaison
+ }
+ else
+ {
+ // Choc avec le sol.
+ max = (int)(50.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ angle = Rand()*(PI*2.0f);
+ p = RotatePoint(angle, 46.0f);
+ pos = m_pos;
+ pos.x += p.x;
+ pos.z += p.y;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*10.0f+10.0f;
+ dim.y = dim.x;
+ time = Rand()*2.0f+1.5f;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, time, 0.0f, 2.0f);
+ }
+
+ m_phase = ABP_PORTICO_WAIT2;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ABP_PORTICO_WAIT2 ) // attente du portique ?
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_phase = ABP_PORTICO_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/BASE_PORTICO_TIME_OPEN;
+ }
+ }
+
+ if ( m_phase == ABP_PORTICO_OPEN ) // ouverture du portique ?
+ {
+ if ( m_progress < 1.0f )
+ {
+ }
+ else
+ {
+ m_phase = ABP_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == ABP_TRANSIT_MOVE ) // transit dans l'espace ?
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += event.rTime*(2000.0f/BASE_TRANSIT_TIME);
+ m_object->SetPosition(0, pos);
+ pos.x += 60.0f;
+ m_camera->SetScriptLookat(pos);
+ }
+ else
+ {
+ m_object->SetAngleZ(0, 0.0f);
+
+ m_param = PARAM_LANDING;
+ m_phase = ABP_START;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ EndTransit();
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.8f, 0.01f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+ goto begin;
+ }
+ }
+
+ if ( m_bMotor )
+ {
+ if ( m_lastMotorParticule+m_engine->ParticuleAdapt(0.02f) <= m_time )
+ {
+ m_lastMotorParticule = m_time;
+
+ mat = m_object->RetWorldMatrix(0);
+
+ if ( event.rTime == 0.0f )
+ {
+ vSpeed = 0.0f;
+ }
+ else
+ {
+ pos = m_object->RetPosition(0);
+ if ( m_phase == ABP_TRANSIT_MOVE )
+ {
+ vSpeed = (pos.x-iPos.x)/event.rTime;
+ }
+ else
+ {
+ vSpeed = (pos.y-iPos.y)/event.rTime;
+ }
+ if ( vSpeed < 0.0f ) vSpeed *= 1.5f;
+ }
+
+ pos = D3DVECTOR(0.0f, 6.0f, 0.0f);
+ speed.x = (Rand()-0.5f)*4.0f;
+ speed.z = (Rand()-0.5f)*4.0f;
+ speed.y = vSpeed*0.8f-(8.0f+Rand()*6.0f);
+ speed += pos;
+ pos = Transform(*mat, pos);
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = 4.0f+Rand()*4.0f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIBASE, 3.0f, 0.0f, 0.0f);
+
+ if ( m_phase == ABP_TRANSIT_MOVE )
+ {
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 12.0f;
+ dim.y = dim.x;
+ pos = D3DVECTOR(0.0f, 7.0f, 0.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 1.0f, 0.0f, 0.0f);
+
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 4.0f;
+ dim.y = dim.x;
+ pos = D3DVECTOR(42.0f, 0.0f, 17.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(17.0f, 0.0f, 42.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(42.0f, 0.0f, -17.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(17.0f, 0.0f, -42.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-42.0f, 0.0f, 17.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-17.0f, 0.0f, 42.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-42.0f, 0.0f, -17.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+ pos = D3DVECTOR(-17.0f, 0.0f, -42.0f);
+ pos.x += (Rand()-0.5f)*2.0f; pos.z += (Rand()-0.5f)*2.0f;
+ pos = Transform(*mat, pos);
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 0.5f, 0.0f, 0.0f);
+
+ pos = D3DVECTOR(42.0f, -2.0f, 17.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[0], pos);
+ pos = D3DVECTOR(17.0f, -2.0f, 42.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[1], pos);
+ pos = D3DVECTOR(42.0f, -2.0f, -17.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[2], pos);
+ pos = D3DVECTOR(17.0f, -2.0f, -42.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[3], pos);
+ pos = D3DVECTOR(-42.0f, -2.0f, 17.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[4], pos);
+ pos = D3DVECTOR(-17.0f, -2.0f, 42.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[5], pos);
+ pos = D3DVECTOR(-42.0f, -2.0f, -17.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[6], pos);
+ pos = D3DVECTOR(-17.0f, -2.0f, -42.0f);
+ pos = Transform(*mat, pos);
+ m_particule->SetPosition(m_partiChannel[7], pos);
+ }
+ }
+ }
+
+ if ( m_soundChannel != -1 )
+ {
+ pos = m_engine->RetEyePt();
+ m_sound->Position(m_soundChannel, pos);
+ }
+
+ return TRUE;
+}
+
+// Stoppe l'automate.
+
+BOOL CAutoBase::Abort()
+{
+ Event newEvent;
+ CObject* pObj;
+ int i;
+
+ if ( m_phase == ABP_TRANSIT_MOVE ) // transit ?
+ {
+ m_object->SetAngleZ(0, 0.0f);
+
+ m_param = PARAM_LANDING;
+ m_phase = ABP_START;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ EndTransit();
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.8f, 0.01f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+ return TRUE;
+ }
+
+ if ( m_param == PARAM_PORTICO ) // porté par le portique ?
+ {
+ m_object->SetPosition(0, m_finalPos);
+ MoveCargo(); // déplace toute la cargaison
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f-124.0f*PI/180.0f);
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f);
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f);
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, -11.5f));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, 11.5f));
+ }
+ }
+ else
+ {
+ if ( m_phase == ABP_LAND ||
+ m_phase == ABP_OPENWAIT ||
+ m_phase == ABP_OPEN ||
+ m_phase == ABP_OPEN2 ) // atterrissage ?
+ {
+ m_bMotor = FALSE; // éteint le réacteur
+ m_bOpen = TRUE;
+
+ m_object->SetPosition(0, m_pos); // posé au sol
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ MoveCargo(); // déplace toute la cargaison
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ m_object->SetAngleZ(1+i, PI/2.0f-124.0f*PI/180.0f);
+ m_object->SetAngleX(10+i, -10.0f*PI/180.0f);
+ m_object->SetAngleX(18+i, 10.0f*PI/180.0f);
+ m_object->SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, -11.5f));
+ m_object->SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, 11.5f));
+ }
+
+ m_main->SetMovieLock(FALSE); // on peut jouer !
+
+ pObj = m_main->RetSelectObject();
+ m_main->SelectObject(pObj);
+ m_camera->SetObject(pObj);
+ if ( pObj == 0 )
+ {
+ m_camera->SetType(CAMERA_BACK);
+ }
+ else
+ {
+ m_camera->SetType(pObj->RetCameraType());
+ m_camera->SetDist(pObj->RetCameraDist());
+ }
+
+ m_engine->SetFogStart(m_fogStart);
+ }
+
+ if ( m_phase == ABP_CLOSE2 ||
+ m_phase == ABP_CLOSE ||
+ m_phase == ABP_TOWAIT ||
+ m_phase == ABP_TAKEOFF ) // décollage ?
+ {
+ m_event->MakeEvent(newEvent, EVENT_WIN);
+ m_event->AddEvent(newEvent);
+ }
+ }
+
+ m_object->SetAngleZ(0, 0.0f);
+ FreezeCargo(FALSE); // libère toute la cargaison
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_phase = ABP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoBase::RetError()
+{
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoBase::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+ float sleep, delay, magnetic, progress;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ dim.x = 33.0f/640.0f;
+ dim.y = 33.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ ddim.x = dim.x*1.5f;
+ ddim.y = dim.y*1.5f;
+
+//? pos.x = ox+sx*7.25f;
+//? pos.y = oy+sy*0.25f;
+//? pw->CreateButton(pos, ddim, 63, EVENT_OBJECT_BHELP);
+
+ pos.x = ox+sx*8.00f;
+ pos.y = oy+sy*0.25f;
+ pw->CreateButton(pos, ddim, 28, EVENT_OBJECT_BTAKEOFF);
+
+ if ( m_blitz->GetStatus(sleep, delay, magnetic, progress) )
+ {
+ pos.x = ox+sx*10.2f;
+ pos.y = oy+sy*0.5f;
+ ddim.x = dim.x*1.0f;
+ ddim.y = dim.y*1.0f;
+ pw->CreateButton(pos, ddim, 41, EVENT_OBJECT_LIMIT);
+ }
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 100, EVENT_OBJECT_TYPE);
+
+ UpdateInterface();
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CAutoBase::UpdateInterface()
+{
+ CWindow* pw;
+
+ if ( !m_object->RetSelect() ) return;
+
+ CAuto::UpdateInterface();
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+}
+
+
+// Gèle ou libère toute la cargaison.
+
+void CAutoBase::FreezeCargo(BOOL bFreeze)
+{
+ CObject* pObj;
+ CPhysics* physics;
+ D3DVECTOR oPos;
+ float dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ pObj->SetCargo(FALSE);
+
+ if ( pObj == m_object ) continue; // soi-même ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(m_pos, oPos);
+ if ( dist < 32.0f )
+ {
+ if ( bFreeze )
+ {
+ pObj->SetCargo(TRUE);
+ }
+
+ physics = pObj->RetPhysics();
+ if ( physics != 0 )
+ {
+ physics->SetFreeze(bFreeze);
+ }
+ }
+ }
+}
+
+// Déplace verticalement toute la cargaison avec le vaisseau.
+
+void CAutoBase::MoveCargo()
+{
+ CObject* pObj;
+ D3DVECTOR oPos, sPos;
+ int i;
+
+ sPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetCargo() ) continue;
+
+ oPos = pObj->RetPosition(0);
+ oPos.y = sPos.y+30.0f;
+ oPos.y += pObj->RetCharacter()->height;
+ oPos.x += sPos.x-m_lastPos.x;
+ oPos.z += sPos.z-m_lastPos.z;
+ pObj->SetPosition(0, oPos);
+ }
+
+ m_lastPos = sPos;
+}
+
+
+// Vérifie s'il est possible de fermer les portes.
+
+Error CAutoBase::CheckCloseDoor()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float oRad, dist;
+ int i, j;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue; // soi-même ?
+ if ( !pObj->RetActif() ) continue; // inactif ?
+
+ type = pObj->RetType();
+ if ( type == OBJECT_PORTICO ) continue;
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRad) )
+ {
+ dist = Length2d(m_pos, oPos);
+ if ( dist+oRad > 32.0f &&
+ dist-oRad < 72.0f )
+ {
+ return ERR_BASE_DLOCK;
+ }
+
+ if ( type == OBJECT_HUMAN &&
+ dist+oRad > 32.0f )
+ {
+ return ERR_BASE_DHUMAN;
+ }
+ }
+ }
+ return ERR_OK;
+}
+
+
+// Début d'un transit.
+
+void CAutoBase::BeginTransit()
+{
+ BOOL bFull, bQuarter;
+
+ if ( m_param == PARAM_TRANSIT2 )
+ {
+ strcpy(m_bgBack, "back01.tga"); // nuages oranges/bleus
+ }
+ else if ( m_param == PARAM_TRANSIT3 )
+ {
+ strcpy(m_bgBack, "back22.tga"); // nuages bleutés
+ }
+ else
+ {
+#if _DEMO
+ strcpy(m_bgBack, "back46b.tga"); // étoiles
+#else
+ strcpy(m_bgBack, "back46.tga"); // étoiles
+#endif
+ }
+
+ m_engine->SetFogStart(0.9f); // presque pas de brouillard
+ m_engine->SetDeepView(2000.0f); // on voit très loin
+ m_engine->ApplyChange();
+
+ m_engine->RetBackground(m_bgName, m_bgUp, m_bgDown, m_bgCloudUp, m_bgCloudDown, bFull, bQuarter);
+ m_engine->FreeTexture(m_bgName);
+
+ m_engine->SetBackground(m_bgBack, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
+ m_engine->LoadTexture(m_bgBack);
+
+ m_cloud->SetEnable(FALSE); // cache les nuages
+ m_planet->SetMode(1);
+}
+
+// Fin d'un transit.
+
+void CAutoBase::EndTransit()
+{
+ m_engine->SetFogStart(m_fogStart); // remet brouillard initial
+ m_engine->SetDeepView(m_deepView); // remet profondeur initiale
+ m_engine->ApplyChange();
+
+ m_engine->FreeTexture(m_bgBack);
+
+ m_engine->SetBackground(m_bgName, m_bgUp, m_bgDown, m_bgCloudUp, m_bgCloudDown);
+ m_engine->LoadTexture(m_bgName);
+
+ m_cloud->SetEnable(TRUE); // remet les nuages
+ m_planet->SetMode(0);
+
+ m_main->StartMusic();
+}
+
diff --git a/src/autobase.h b/src/autobase.h
new file mode 100644
index 0000000..bfc0220
--- /dev/null
+++ b/src/autobase.h
@@ -0,0 +1,102 @@
+// autobase.h
+
+#ifndef _AUTOBASE_H_
+#define _AUTOBASE_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+#define PARAM_STOP 0 // run=0 -> stoppé et ouvert
+#define PARAM_LANDING 1 // run=1 -> atterrissage
+#define PARAM_PORTICO 2 // run=2 -> porté par le portique
+#define PARAM_FIXSCENE 3 // run=3 -> stoppé et ouvert pour win/lost
+#define PARAM_TRANSIT1 11 // run=11 -> transit dans l'espace
+#define PARAM_TRANSIT2 12 // run=12 -> transit dans l'espace
+#define PARAM_TRANSIT3 13 // run=13 -> transit dans l'espace
+
+
+enum AutoBasePhase
+{
+ ABP_WAIT = 1, // attend
+ ABP_START = 2, // démarrage
+
+ ABP_LAND = 3, // atterissage
+ ABP_OPENWAIT = 4, // attente avant ouverture
+ ABP_OPEN = 5, // ouvre les portes
+ ABP_OPEN2 = 6, // ouvre les suppléments
+ ABP_LDWAIT = 7, // attend
+
+ ABP_CLOSE2 = 8, // ferme les suppléments
+ ABP_CLOSE = 9, // ferme les portes
+ ABP_TOWAIT = 10, // attente avant décollage
+ ABP_TAKEOFF = 11, // décollage
+
+ ABP_PORTICO_MOVE = 12, // portique avance
+ ABP_PORTICO_WAIT1= 13, // portique attend
+ ABP_PORTICO_DOWN = 14, // portique descend
+ ABP_PORTICO_WAIT2= 15, // portique attend
+ ABP_PORTICO_OPEN = 16, // portique s'ouvre
+
+ ABP_TRANSIT_MOVE = 17, // transit - déplacement
+};
+
+
+
+class CAutoBase : public CAuto
+{
+public:
+ CAutoBase(CInstanceManager* iMan, CObject* object);
+ ~CAutoBase();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param);
+ BOOL EventProcess(const Event &event);
+ BOOL Abort();
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+protected:
+ void UpdateInterface();
+ void FreezeCargo(BOOL bFreeze);
+ void MoveCargo();
+ Error CheckCloseDoor();
+ void BeginTransit();
+ void EndTransit();
+
+protected:
+ AutoBasePhase m_phase;
+ BOOL m_bOpen;
+ float m_progress;
+ float m_speed;
+ float m_lastParticule;
+ float m_lastMotorParticule;
+ float m_fogStart;
+ float m_deepView;
+ D3DVECTOR m_pos;
+ D3DVECTOR m_posSound;
+ D3DVECTOR m_finalPos;
+ D3DVECTOR m_lastPos;
+ int m_param;
+ int m_soundChannel;
+ int m_partiChannel[8];
+
+ char m_bgBack[100];
+ char m_bgName[100];
+ D3DCOLOR m_bgUp;
+ D3DCOLOR m_bgDown;
+ D3DCOLOR m_bgCloudUp;
+ D3DCOLOR m_bgCloudDown;
+};
+
+
+#endif //_AUTOBASE_H_
diff --git a/src/autoconvert.cpp b/src/autoconvert.cpp
new file mode 100644
index 0000000..7a11ac3
--- /dev/null
+++ b/src/autoconvert.cpp
@@ -0,0 +1,532 @@
+// autoconvert.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autoconvert.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoConvert::CAutoConvert(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_phase = ACP_STOP;
+ m_bResetDelete = FALSE;
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CAutoConvert::~CAutoConvert()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoConvert::DeleteObject(BOOL bAll)
+{
+ CObject* fret;
+
+ if ( !bAll )
+ {
+ fret = SearchStone(OBJECT_STONE);
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // détruit la pierre
+ delete fret;
+ }
+ }
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoConvert::Init()
+{
+ m_phase = ACP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoConvert::EventProcess(const Event &event)
+{
+ CObject* fret;
+ D3DVECTOR pos, speed;
+ FPOINT dim, c, p;
+ float angle;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ angle = (Rand()-0.5f)*0.3f;
+ m_object->SetAngleY(1, angle);
+ m_object->SetAngleY(2, angle);
+ m_object->SetAngleY(3, angle+PI);
+
+ m_object->SetAngleX(2, -PI*0.35f*(0.8f+Rand()*0.2f));
+ m_object->SetAngleX(3, -PI*0.35f*(0.8f+Rand()*0.2f));
+ }
+ return TRUE;
+ }
+
+ EventProgress(event.rTime);
+
+ if ( m_phase == ACP_STOP ) return TRUE;
+
+ if ( m_phase == ACP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ fret = SearchStone(OBJECT_STONE); // pierre à transformer ?
+ if ( fret == 0 || SearchVehicle() )
+ {
+ m_phase = ACP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ else
+ {
+ fret->SetLock(TRUE); // pierre plus utilisable
+
+ SetBusy(TRUE);
+ InitProgressTotal(3.0f+10.0f+1.5f);
+ UpdateInterface();
+
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 1.0f);
+ m_bSoundClose = FALSE;
+
+ m_phase = ACP_CLOSE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+ }
+
+ if ( m_phase == ACP_CLOSE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_progress >= 0.8f && !m_bSoundClose )
+ {
+ m_bSoundClose = TRUE;
+ m_sound->Play(SOUND_CLOSE, m_object->RetPosition(0), 1.0f, 0.8f);
+ }
+ angle = -PI*0.35f*(1.0f-Bounce(m_progress, 0.85f, 0.05f));
+ m_object->SetAngleX(2, angle);
+ m_object->SetAngleX(3, angle);
+ }
+ else
+ {
+ m_object->SetAngleX(2, 0.0f);
+ m_object->SetAngleX(3, 0.0f);
+
+ m_soundChannel = m_sound->Play(SOUND_CONVERT, m_object->RetPosition(0), 0.0f, 0.25f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.25f, 0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.00f, 4.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.25f, 4.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.25f, 0.5f, SOPER_STOP);
+
+ m_phase = ACP_ROTATE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/10.0f;
+ }
+ }
+
+ if ( m_phase == ACP_ROTATE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_progress < 0.5f )
+ {
+ angle = powf((m_progress*2.0f)*5.0f, 2.0f); // accélère
+ }
+ else
+ {
+ angle = -powf((2.0f-m_progress*2.0f)*5.0f, 2.0f); // freine
+ }
+ m_object->SetAngleY(1, angle);
+ m_object->SetAngleY(2, angle);
+ m_object->SetAngleY(3, angle+PI);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ c.x = pos.x;
+ c.y = pos.z;
+ p.x = c.x;
+ p.y = c.y+6.0f;
+ p = RotatePoint(c, Rand()*PI*2.0f, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ pos.y += 1.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*2.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ m_object->SetAngleY(1, 0.0f);
+ m_object->SetAngleY(2, 0.0f);
+ m_object->SetAngleY(3, PI);
+
+ fret = SearchStone(OBJECT_STONE);
+ if ( fret != 0 )
+ {
+ m_bResetDelete = ( fret->RetResetCap() != RESET_NONE );
+ fret->DeleteObject(); // détruit la pierre
+ delete fret;
+ }
+
+ CreateMetal(); // c'est du métal
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 1.5f);
+
+ m_phase = ACP_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ACP_OPEN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = -PI*0.35f*Bounce(m_progress, 0.7f, 0.2f);
+ m_object->SetAngleX(2, angle);
+ m_object->SetAngleX(3, angle);
+
+ if ( m_progress < 0.9f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*6.0f;
+ pos.z += (Rand()-0.5f)*6.0f;
+ pos.y += Rand()*4.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*4.0f+3.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ m_soundChannel = -1;
+ m_object->SetAngleX(2, -PI*0.35f);
+ m_object->SetAngleX(3, -PI*0.35f);
+
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ m_phase = ACP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoConvert::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ if ( m_phase == ACP_WAIT ) return ERR_CONVERT_EMPTY;
+ return ERR_OK;
+}
+
+// Annule la transformation en cours.
+
+BOOL CAutoConvert::Abort()
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_object->SetAngleY(1, 0.0f);
+ m_object->SetAngleY(2, 0.0f);
+ m_object->SetAngleY(3, PI);
+ m_object->SetAngleX(2, -PI*0.35f);
+ m_object->SetAngleX(3, -PI*0.35f);
+
+ m_phase = ACP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoConvert::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 103, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoConvert::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ACP_STOP ||
+ m_phase == ACP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoConvert::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoConvertPhase)OpInt(line, "aPhase", ACP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
+// Cherche l'objet avant ou pendant transformation.
+
+CObject* CAutoConvert::SearchStone(ObjectType type)
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType oType;
+ float dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( oType != type ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, cPos);
+
+ if ( dist <= 5.0f ) return pObj;
+ }
+
+ return 0;
+}
+
+// Cherche si un véhicule est trop proche.
+
+BOOL CAutoConvert::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_METAL &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_TNT &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, cPos)-oRadius;
+
+ if ( dist < 8.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Crée un objet métal.
+
+void CAutoConvert::CreateMetal()
+{
+ D3DVECTOR pos;
+ float angle;
+ CObject* fret;
+
+ pos = m_object->RetPosition(0);
+ angle = m_object->RetAngleY(0);
+
+ fret = new CObject(m_iMan);
+ if ( !fret->CreateResource(pos, angle, OBJECT_METAL) )
+ {
+ delete fret;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return;
+ }
+
+ if ( m_bResetDelete )
+ {
+ fret->SetResetCap(RESET_DELETE);
+ }
+
+ m_displayText->DisplayError(INFO_CONVERT, m_object);
+}
+
diff --git a/src/autoconvert.h b/src/autoconvert.h
new file mode 100644
index 0000000..3cdbf57
--- /dev/null
+++ b/src/autoconvert.h
@@ -0,0 +1,62 @@
+// autoconvert.h
+
+#ifndef _AUTOCONVERT_H_
+#define _AUTOCONVERT_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoConvertPhase
+{
+ ACP_STOP = 1,
+ ACP_WAIT = 2,
+ ACP_CLOSE = 3, // ferme le couvervle
+ ACP_ROTATE = 4, // tourne le couvercle
+ ACP_OPEN = 5, // ouvre le couvercle
+};
+
+
+
+class CAutoConvert : public CAuto
+{
+public:
+ CAutoConvert(CInstanceManager* iMan, CObject* object);
+ ~CAutoConvert();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+ BOOL Abort();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ CObject* SearchStone(ObjectType type);
+ BOOL SearchVehicle();
+ void CreateMetal();
+
+protected:
+ AutoConvertPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ BOOL m_bResetDelete;
+ BOOL m_bSoundClose;
+ int m_soundChannel;
+};
+
+
+#endif //_AUTOCONVERT_H_
diff --git a/src/autoderrick.cpp b/src/autoderrick.cpp
new file mode 100644
index 0000000..077dc35
--- /dev/null
+++ b/src/autoderrick.cpp
@@ -0,0 +1,591 @@
+// autoderrick.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autoderrick.h"
+
+
+
+#define DERRICK_DELAY 10.0f // durée de l'extraction
+#define DERRICK_DELAYu 30.0f // idem, mais pour l'uranium
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoDerrick::CAutoDerrick(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_phase = ADP_WAIT; // en pause jusqu'au premier Init()
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CAutoDerrick::~CAutoDerrick()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoDerrick::DeleteObject(BOOL bAll)
+{
+ CObject* fret;
+
+ if ( !bAll )
+ {
+ fret = SearchFret();
+ if ( fret != 0 && fret->RetLock() )
+ {
+ fret->DeleteObject();
+ delete fret;
+ }
+ }
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoDerrick::Init()
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ TerrainRes res;
+
+ pos = m_object->RetPosition(0);
+ res = m_terrain->RetResource(pos);
+
+ if ( res == TR_STONE ||
+ res == TR_URANIUM ||
+ res == TR_KEYa ||
+ res == TR_KEYb ||
+ res == TR_KEYc ||
+ res == TR_KEYd )
+ {
+ m_type = OBJECT_FRET;
+ if ( res == TR_STONE ) m_type = OBJECT_STONE;
+ if ( res == TR_URANIUM ) m_type = OBJECT_URANIUM;
+ if ( res == TR_KEYa ) m_type = OBJECT_KEYa;
+ if ( res == TR_KEYb ) m_type = OBJECT_KEYb;
+ if ( res == TR_KEYc ) m_type = OBJECT_KEYc;
+ if ( res == TR_KEYd ) m_type = OBJECT_KEYd;
+
+ m_phase = ADP_EXCAVATE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(m_type==OBJECT_URANIUM?DERRICK_DELAYu:DERRICK_DELAY);
+ }
+ else
+ {
+ m_phase = ADP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f;
+ }
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+ m_lastTrack = 0.0f;
+
+ pos = D3DVECTOR(7.0f, 0.0f, 0.0f);
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ m_terrain->MoveOnFloor(pos);
+ m_fretPos = pos;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoDerrick::EventProcess(const Event &event)
+{
+ CObject* fret;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle, duration, factor;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_phase == ADP_WAIT ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ pos.x = 0.0f;
+ pos.z = 0.0f;
+ pos.y = -2.0f*Rand();
+ m_object->SetPosition(1, pos); // monte/descend le foret
+
+ m_object->SetAngleY(1, Rand()*0.5f); // tourne le foret
+ }
+ return TRUE;
+ }
+
+ if ( m_phase == ADP_EXCAVATE )
+ {
+ if ( m_soundChannel == -1 )
+ {
+ if ( m_type == OBJECT_URANIUM )
+ {
+ factor = DERRICK_DELAYu/DERRICK_DELAY;
+ }
+ else
+ {
+ factor = 1.0f;
+ }
+ m_soundChannel = m_sound->Play(SOUND_DERRICK, m_object->RetPosition(0), 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.5f, 4.0f*factor, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.3f, 6.0f*factor, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.5f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.5f, 4.0f, SOPER_STOP);
+ }
+
+ if ( m_progress >= 6.0f/16.0f && // pénètre dans le sol ?
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ if ( m_progress >= 6.0f/16.0f && // pénètre dans le sol ?
+ m_lastTrack+m_engine->ParticuleAdapt(0.5f) <= m_time )
+ {
+ m_lastTrack = m_time;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+ speed.y = Rand()*10.0f+10.0f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*2.0f+2.0f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK5,
+ duration, Rand()*10.0f+15.0f,
+ duration*0.2f, 1.0f);
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ pos.x = 0.0f;
+ pos.z = 0.0f;
+ pos.y = -m_progress*16.0f;
+ m_object->SetPosition(1, pos); // descend le foret
+
+ angle = m_object->RetAngleY(1);
+ angle += event.rTime*8.0f;
+ m_object->SetAngleY(1, angle); // tourne le foret
+ }
+ else
+ {
+ m_phase = ADP_ASCEND;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+ }
+
+ if ( m_phase == ADP_ASCEND )
+ {
+ if ( m_progress <= 7.0f/16.0f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ if ( m_progress <= 4.0f/16.0f &&
+ m_lastTrack+m_engine->ParticuleAdapt(1.0f) <= m_time )
+ {
+ m_lastTrack = m_time;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+ speed.y = Rand()*10.0f+10.0f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*2.0f+2.0f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK5,
+ duration, Rand()*10.0f+15.0f,
+ duration*0.2f, 1.0f);
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ pos.x = 0.0f;
+ pos.z = 0.0f;
+ pos.y = -(1.0f-m_progress)*16.0f;
+ m_object->SetPosition(1, pos); // remonte le foret
+
+ angle = m_object->RetAngleY(1);
+ angle -= event.rTime*2.0f;
+ m_object->SetAngleY(1, angle); // tourne le foret
+ }
+ else
+ {
+ m_soundChannel = -1;
+ m_bSoundFall = FALSE;
+
+ m_phase = ADP_EXPORT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+ }
+
+ if ( m_phase == ADP_ISFREE )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_bSoundFall = FALSE;
+
+ m_phase = ADP_EXPORT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+ }
+
+ if ( m_phase == ADP_EXPORT )
+ {
+ if ( m_progress == 0.0f )
+ {
+ if ( SearchFree(m_fretPos) )
+ {
+ angle = m_object->RetAngleY(0);
+ CreateFret(m_fretPos, angle, m_type, 16.0f);
+ }
+ else
+ {
+ m_phase = ADP_ISFREE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ return TRUE;
+ }
+ }
+
+ fret = SearchFret();
+
+ if ( fret != 0 &&
+ m_progress <= 0.5f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ if ( m_progress < 0.3f )
+ {
+ pos = fret->RetPosition(0);
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ pos.y += (Rand()-0.5f)*5.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 3.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIRE, 1.0f, 0.0f, 0.0f);
+ }
+ else
+ {
+ pos = fret->RetPosition(0);
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ pos.y += Rand()*2.5f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ if ( fret != 0 )
+ {
+ pos = fret->RetPosition(0);
+ pos.y -= event.rTime*20.0f; // tombe
+ if ( !m_bSoundFall && pos.y < m_fretPos.y )
+ {
+ m_sound->Play(SOUND_BOUM, m_fretPos);
+ m_bSoundFall = TRUE;
+ }
+ if ( pos.y < m_fretPos.y )
+ {
+ pos.y = m_fretPos.y;
+ fret->SetLock(FALSE); // objet utilisable
+ }
+ fret->SetPosition(0, pos);
+ }
+ }
+ else
+ {
+ if ( ExistKey() ) // clé existe déjà ?
+ {
+ m_phase = ADP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/10.0f;
+ }
+ else
+ {
+ m_phase = ADP_EXCAVATE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(m_type==OBJECT_URANIUM?DERRICK_DELAYu:DERRICK_DELAY);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoDerrick::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 109, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoDerrick::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ADP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoDerrick::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoDerrickPhase)OpInt(line, "aPhase", ADP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
+// Cherche l'objet fret.
+
+CObject* CAutoDerrick::SearchFret()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_DERRICK ) continue;
+
+ oPos = pObj->RetPosition(0);
+
+ if ( oPos.x == m_fretPos.x &&
+ oPos.z == m_fretPos.z ) return pObj;
+ }
+
+ return 0;
+}
+
+// Cherche si un emplacement est libre.
+
+BOOL CAutoDerrick::SearchFree(D3DVECTOR pos)
+{
+ CObject* pObj;
+ D3DVECTOR sPos;
+ ObjectType type;
+ float sRadius, distance;
+ int i, j;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_DERRICK ) continue;
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, sPos, sRadius) )
+ {
+ distance = Length(sPos, pos);
+ distance -= sRadius;
+ if ( distance < 2.0f ) return FALSE; // emplacement occupé
+ }
+ }
+
+ return TRUE; // emplacement libre
+}
+
+// Crée un objet transportable.
+
+void CAutoDerrick::CreateFret(D3DVECTOR pos, float angle, ObjectType type,
+ float height)
+{
+ CObject* fret;
+
+ fret = new CObject(m_iMan);
+ if ( !fret->CreateResource(pos, angle, type) )
+ {
+ delete fret;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return;
+ }
+ fret->SetLock(TRUE); // objet pas encore utilisable
+
+ if ( m_object->RetResetCap() == RESET_MOVE )
+ {
+ fret->SetResetCap(RESET_DELETE);
+ }
+
+ pos = fret->RetPosition(0);
+ pos.y += height;
+ fret->SetPosition(0, pos);
+}
+
+// Cherche s'il existe déjà une clé.
+
+BOOL CAutoDerrick::ExistKey()
+{
+ CObject* pObj;
+ ObjectType type;
+ int i;
+
+ if ( m_type != OBJECT_KEYa &&
+ m_type != OBJECT_KEYb &&
+ m_type != OBJECT_KEYc &&
+ m_type != OBJECT_KEYd ) return FALSE;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == m_type ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoDerrick::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ if ( m_phase == ADP_WAIT ) return ERR_DERRICK_NULL;
+ return ERR_OK;
+}
+
+
diff --git a/src/autoderrick.h b/src/autoderrick.h
new file mode 100644
index 0000000..cb5ccb4
--- /dev/null
+++ b/src/autoderrick.h
@@ -0,0 +1,65 @@
+// autoderrick.h
+
+#ifndef _AUTODERRICK_H_
+#define _AUTODERRICK_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+enum AutoDerrickPhase
+{
+ ADP_WAIT = 1,
+ ADP_EXCAVATE = 2, // descend le foret
+ ADP_ASCEND = 3, // remonte le foret
+ ADP_EXPORT = 4, // exporte la matière
+ ADP_ISFREE = 5, // attend disparition matière
+};
+
+
+
+class CAutoDerrick : public CAuto
+{
+public:
+ CAutoDerrick(CInstanceManager* iMan, CObject* object);
+ ~CAutoDerrick();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ CObject* SearchFret();
+ BOOL SearchFree(D3DVECTOR pos);
+ void CreateFret(D3DVECTOR pos, float angle, ObjectType type, float height);
+ BOOL ExistKey();
+
+protected:
+ AutoDerrickPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ float m_lastTrack;
+ D3DVECTOR m_fretPos;
+ int m_soundChannel;
+ BOOL m_bSoundFall;
+};
+
+
+#endif //_AUTODERRICK_H_
diff --git a/src/autodestroyer.cpp b/src/autodestroyer.cpp
new file mode 100644
index 0000000..28f548f
--- /dev/null
+++ b/src/autodestroyer.cpp
@@ -0,0 +1,383 @@
+// autodestroyer.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "physics.h"
+#include "pyro.h"
+#include "sound.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "robotmain.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autodestroyer.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoDestroyer::CAutoDestroyer(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_phase = ADEP_WAIT; // en pause jusqu'au premier Init()
+}
+
+// Destructeur de l'objet.
+
+CAutoDestroyer::~CAutoDestroyer()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoDestroyer::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoDestroyer::Init()
+{
+ m_phase = ADEP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.5f;
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoDestroyer::EventProcess(const Event &event)
+{
+ CObject* scrap;
+ CPyro* pyro;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ if ( m_phase == ADEP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ scrap = SearchPlastic();
+ if ( scrap == 0 )
+ {
+ m_phase = ADEP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.5f;
+ }
+ else
+ {
+ scrap->SetLock(TRUE); // déchet plus utilisable
+//? scrap->SetTruck(m_object); // déchet plus utilisable
+
+ if ( SearchVehicle() )
+ {
+ m_phase = ADEP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.5f;
+ }
+ else
+ {
+ m_sound->Play(SOUND_PSHHH2, m_object->RetPosition(0), 1.0f, 1.0f);
+
+ m_phase = ADEP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_bExplo = FALSE;
+ }
+ }
+ }
+ }
+
+ if ( m_phase == ADEP_DOWN )
+ {
+ if ( m_progress >= 0.3f-0.05f && !m_bExplo )
+ {
+ scrap = SearchPlastic();
+ if ( scrap != 0 )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, scrap);
+ }
+ m_bExplo = TRUE;
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ pos = D3DVECTOR(0.0f, -10.0f, 0.0f);
+ pos.y = -Bounce(m_progress, 0.3f)*10.0f;
+ m_object->SetPosition(1, pos);
+ }
+ else
+ {
+ m_object->SetPosition(1, D3DVECTOR(0.0f, -10.0f, 0.0f));
+ m_sound->Play(SOUND_REPAIR, m_object->RetPosition(0));
+
+ m_phase = ADEP_REPAIR;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ADEP_REPAIR )
+ {
+ if ( m_progress < 1.0f )
+ {
+ }
+ else
+ {
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 0.8f);
+
+ m_phase = ADEP_UP;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+
+ if ( m_phase == ADEP_UP )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = D3DVECTOR(0.0f, -10.0f, 0.0f);
+ pos.y = -(1.0f-m_progress)*10.0f;
+ m_object->SetPosition(1, pos);
+ }
+ else
+ {
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ m_phase = ADEP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.5f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoDestroyer::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 106, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Cherche le déchet placé sous le destructeur.
+
+CObject* CAutoDestroyer::SearchPlastic()
+{
+ CObject* pObj;
+ D3DVECTOR sPos, oPos;
+ ObjectType type;
+ float dist;
+ int i;
+
+ sPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_SCRAP4 &&
+ type != OBJECT_SCRAP5 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, sPos);
+ if ( dist <= 5.0f ) return pObj;
+ }
+
+ return 0;
+}
+
+// Cherche si un véhicule est trop proche.
+
+BOOL CAutoDestroyer::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, cPos)-oRadius;
+
+ if ( dist < 20.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoDestroyer::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ return ERR_OK;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoDestroyer::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ADEP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoDestroyer::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoDestroyerPhase)OpInt(line, "aPhase", ADEP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autodestroyer.h b/src/autodestroyer.h
new file mode 100644
index 0000000..3b48f66
--- /dev/null
+++ b/src/autodestroyer.h
@@ -0,0 +1,57 @@
+// autodestroyer.h
+
+#ifndef _AUTODESTROYER_H_
+#define _AUTODESTROYER_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoDestroyerPhase
+{
+ ADEP_WAIT = 1, // attend métal
+ ADEP_DOWN = 2, // descend le couvercle
+ ADEP_REPAIR = 3, // construit le véhicule
+ ADEP_UP = 4, // remonte le couvercle
+};
+
+
+
+class CAutoDestroyer : public CAuto
+{
+public:
+ CAutoDestroyer(CInstanceManager* iMan, CObject* object);
+ ~CAutoDestroyer();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ CObject* SearchPlastic();
+ BOOL SearchVehicle();
+
+protected:
+ AutoDestroyerPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ BOOL m_bExplo;
+};
+
+
+#endif //_AUTODESTROYER_H_
diff --git a/src/autoegg.cpp b/src/autoegg.cpp
new file mode 100644
index 0000000..a8eec72
--- /dev/null
+++ b/src/autoegg.cpp
@@ -0,0 +1,359 @@
+// autoegg.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "pyro.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autoegg.h"
+
+
+
+// Constructeur de l'objet.
+
+CAutoEgg::CAutoEgg(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ m_type = OBJECT_NULL;
+ m_value = 0.0f;
+ m_string[0] = 0;
+
+ m_param = 0;
+ m_phase = AEP_NULL;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoEgg::~CAutoEgg()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoEgg::DeleteObject(BOOL bAll)
+{
+ CObject* alien;
+
+ CAuto::DeleteObject(bAll);
+
+ if ( !bAll )
+ {
+ alien = SearchAlien();
+ if ( alien != 0 )
+ {
+ if ( alien->RetZoom(0) == 1.0f )
+ {
+ alien->SetLock(FALSE);
+ alien->SetActivity(TRUE); // l'insect né est actif
+ }
+ else
+ {
+ alien->DeleteObject();
+ delete alien;
+ }
+ }
+ }
+}
+
+
+// Initialise l'objet.
+
+void CAutoEgg::Init()
+{
+ CObject* alien;
+
+ alien = SearchAlien();
+ if ( alien == 0 )
+ {
+ m_phase = AEP_NULL;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ m_time = 0.0f;
+ return;
+ }
+
+ m_phase = AEP_INCUB;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ m_time = 0.0f;
+
+ m_type = alien->RetType();
+
+ if ( m_type == OBJECT_ANT ||
+ m_type == OBJECT_SPIDER ||
+ m_type == OBJECT_BEE )
+ {
+ alien->SetZoom(0, 0.2f);
+ }
+ if ( m_type == OBJECT_WORM )
+ {
+ alien->SetZoom(0, 0.01f); // invisible !
+ }
+ alien->SetLock(TRUE);
+ alien->SetActivity(FALSE);
+}
+
+
+// Donne une valeur.
+
+BOOL CAutoEgg::SetType(ObjectType type)
+{
+ m_type = type;
+ return TRUE;
+}
+
+// Donne une valeur.
+
+BOOL CAutoEgg::SetValue(int rank, float value)
+{
+ if ( rank != 0 ) return FALSE;
+ m_value = value;
+ return TRUE;
+}
+
+// Donne la string.
+
+BOOL CAutoEgg::SetString(char *string)
+{
+ strcpy(m_string, string);
+ return TRUE;
+}
+
+
+// Démarre l'objet.
+
+void CAutoEgg::Start(int param)
+{
+ if ( m_type == OBJECT_NULL ) return;
+ if ( m_value == 0.0f ) return;
+
+ m_phase = AEP_DELAY;
+ m_progress = 0.0f;
+ m_speed = 1.0f/m_value;
+
+ m_param = param;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoEgg::EventProcess(const Event &event)
+{
+ CObject* alien;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_phase == AEP_NULL ) return TRUE;
+
+ if ( m_phase == AEP_DELAY )
+ {
+ m_progress += event.rTime*m_speed;
+ if ( m_progress < 1.0f ) return TRUE;
+
+ alien = new CObject(m_iMan);
+ if ( !alien->CreateInsect(m_object->RetPosition(0), m_object->RetAngleY(0), m_type) )
+ {
+ delete alien;
+ m_phase = AEP_DELAY;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ return TRUE;
+ }
+ alien->SetActivity(FALSE);
+ alien->ReadProgram(0, m_string);
+ alien->RunProgram(0);
+ Init();
+ }
+
+ alien = SearchAlien();
+ if ( alien == 0 ) return TRUE;
+ alien->SetActivity(FALSE);
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == AEP_ZOOM )
+ {
+ if ( m_type == OBJECT_ANT ||
+ m_type == OBJECT_SPIDER ||
+ m_type == OBJECT_BEE )
+ {
+ alien->SetZoom(0, 0.2f+m_progress*0.8f); // ça pousse
+ }
+ }
+
+ return TRUE;
+}
+
+// Indique si l'automate a terminé son activité.
+
+Error CAutoEgg::IsEnded()
+{
+ CObject* alien;
+ CPyro* pyro;
+
+ if ( m_phase == AEP_DELAY )
+ {
+ return ERR_CONTINUE;
+ }
+
+ alien = SearchAlien();
+ if ( alien == 0 ) return ERR_STOP;
+
+ if ( m_phase == AEP_INCUB )
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = AEP_ZOOM;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+
+ if ( m_phase == AEP_ZOOM )
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_EGG, m_object); // explosion de l'oeuf
+
+ alien->SetZoom(0, 1.0f); // c'est un grand garçon, maintenant
+
+ m_phase = AEP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+
+ if ( m_phase == AEP_WAIT )
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ alien->SetLock(FALSE);
+ alien->SetActivity(TRUE); // l'insect né est actif
+ }
+
+ return ERR_STOP;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoEgg::RetError()
+{
+ return ERR_OK;
+}
+
+
+// Cherche l'insect qui prend naissance dans l'oeuf.
+
+CObject* CAutoEgg::SearchAlien()
+{
+ CObject* pObj;
+ CObject* pBest;
+ D3DVECTOR cPos, oPos;
+ ObjectType type;
+ float dist, min;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_ANT &&
+ type != OBJECT_BEE &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_WORM ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, cPos);
+ if ( dist < 8.0f && dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+ return pBest;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoEgg::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == AEP_NULL ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.5f", m_speed);
+ strcat(line, name);
+
+ sprintf(name, " aParamType=%s", GetTypeObject(m_type));
+ strcat(line, name);
+
+ sprintf(name, " aParamValue1=%.2f", m_value);
+ strcat(line, name);
+
+ sprintf(name, " aParamString=\"%s\"", m_string);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoEgg::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoEggPhase)OpInt(line, "aPhase", AEP_NULL);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+ m_type = OpTypeObject(line, "aParamType", OBJECT_NULL);
+ m_value = OpFloat(line, "aParamValue1", 0.0f);
+ OpString(line, "aParamString", m_string);
+
+ return TRUE;
+}
+
diff --git a/src/autoegg.h b/src/autoegg.h
new file mode 100644
index 0000000..bc4be7b
--- /dev/null
+++ b/src/autoegg.h
@@ -0,0 +1,64 @@
+// autoegg.h
+
+#ifndef _AUTOEGG_H_
+#define _AUTOEGG_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+enum AutoEggPhase
+{
+ AEP_NULL = 0,
+ AEP_DELAY = 1,
+ AEP_INCUB = 3,
+ AEP_ZOOM = 4,
+ AEP_WAIT = 5,
+};
+
+
+
+class CAutoEgg : public CAuto
+{
+public:
+ CAutoEgg(CInstanceManager* iMan, CObject* object);
+ ~CAutoEgg();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param);
+ BOOL EventProcess(const Event &event);
+ Error IsEnded();
+ Error RetError();
+
+ BOOL SetType(ObjectType type);
+ BOOL SetValue(int rank, float value);
+ BOOL SetString(char *string);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ CObject* SearchAlien();
+
+protected:
+ ObjectType m_type;
+ float m_value;
+ char m_string[100];
+ int m_param;
+ AutoEggPhase m_phase;
+ float m_progress;
+ float m_speed;
+};
+
+
+#endif //_AUTOEGG_H_
diff --git a/src/autoenergy.cpp b/src/autoenergy.cpp
new file mode 100644
index 0000000..1456f01
--- /dev/null
+++ b/src/autoenergy.cpp
@@ -0,0 +1,652 @@
+// autoenergy.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "gauge.h"
+#include "window.h"
+#include "displaytext.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autoenergy.h"
+
+
+
+#define ENERGY_POWER 0.4f // énergie nécessaire pour une pile
+#define ENERGY_DELAY 12.0f // durée de la transformation
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoEnergy::CAutoEnergy(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ m_partiSphere = -1;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoEnergy::~CAutoEnergy()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoEnergy::DeleteObject(BOOL bAll)
+{
+ CObject* fret;
+
+ if ( m_partiSphere != -1 )
+ {
+ m_particule->DeleteParticule(m_partiSphere);
+ m_partiSphere = -1;
+ }
+
+ if ( !bAll )
+ {
+ fret = SearchMetal();
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // détruit le métal
+ delete fret;
+ }
+
+ fret = SearchPower();
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // détruit la pile
+ delete fret;
+ }
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoEnergy::Init()
+{
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastUpdateTime = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_phase = AENP_WAIT; // attend ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoEnergy::EventProcess(const Event &event)
+{
+ CObject* fret;
+ D3DVECTOR pos, ppos, speed;
+ FPOINT dim, c, p;
+ TerrainRes res;
+ float big;
+ BOOL bGO;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+ pos = m_object->RetPosition(0);
+ pos.y += 10.0f;
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = -7.0f;
+ dim.x = Rand()*0.5f+0.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIREZ, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ return TRUE;
+ }
+
+ UpdateInterface(event.rTime);
+ EventProgress(event.rTime);
+
+ big = m_object->RetEnergy();
+
+ res = m_terrain->RetResource(m_object->RetPosition(0));
+ if ( res == TR_POWER )
+ {
+ big += event.rTime*0.01f; // recharge la grosse pile
+ }
+
+ if ( m_phase == AENP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ bGO = FALSE;
+ fret = SearchMetal(); // métal à transformer ?
+ if ( fret != 0 )
+ {
+ if ( fret->RetType() == OBJECT_METAL )
+ {
+ if ( big > ENERGY_POWER ) bGO = TRUE;
+ }
+ else
+ {
+ if ( !SearchVehicle() ) bGO = TRUE;
+ }
+ }
+
+ if ( bGO )
+ {
+ if ( fret->RetType() == OBJECT_METAL )
+ {
+ fret->SetLock(TRUE); // métal plus utilisable
+ CreatePower(); // crée la pile
+ }
+
+ SetBusy(TRUE);
+ InitProgressTotal(ENERGY_DELAY);
+ CAuto::UpdateInterface();
+
+ pos = m_object->RetPosition(0);
+ pos.y += 4.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 3.0f;
+ dim.y = dim.x;
+ m_partiSphere = m_particule->CreateParticule(pos, speed, dim, PARTISPHERE1, ENERGY_DELAY, 0.0f, 0.0f);
+
+ m_phase = AENP_CREATE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/ENERGY_DELAY;
+ }
+ else
+ {
+ if ( rand()%3 == 0 && big > 0.01f )
+ {
+ m_phase = AENP_BLITZ;
+ m_progress = 0.0f;
+ m_speed = 1.0f/Rand()*1.0f+1.0f;
+ }
+ else
+ {
+ m_phase = AENP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+ }
+ }
+
+ if ( m_phase == AENP_BLITZ )
+ {
+ if ( m_progress < 1.0f && big > 0.01f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+ pos = m_object->RetPosition(0);
+ pos.y += 10.0f;
+ speed.x = (Rand()-0.5f)*1.0f;
+ speed.z = (Rand()-0.5f)*1.0f;
+ speed.y = -7.0f;
+ dim.x = Rand()*0.5f+0.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIREZ, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ m_phase = AENP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == AENP_CREATE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ fret = SearchMetal();
+ if ( fret != 0 )
+ {
+ if ( fret->RetType() == OBJECT_METAL )
+ {
+ big -= event.rTime/ENERGY_DELAY*ENERGY_POWER;
+ }
+ else
+ {
+ big += event.rTime/ENERGY_DELAY*0.25f;
+ }
+ fret->SetZoom(0, 1.0f-m_progress);
+ }
+
+ fret = SearchPower();
+ if ( fret != 0 )
+ {
+ fret->SetZoom(0, m_progress);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ c.x = pos.x;
+ c.y = pos.z;
+ p.x = c.x;
+ p.y = c.y+2.0f;
+ p = RotatePoint(c, Rand()*PI*2.0f, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ pos.y += 2.5f+Rand()*3.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*2.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 1.0f, 0.0f, 0.0f);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 3.0f;
+ speed.x = (Rand()-0.5f)*30.0f;
+ speed.z = (Rand()-0.5f)*30.0f;
+ speed.y = Rand()*20.0f+10.0f;
+ dim.x = Rand()*0.4f+0.4f;
+ dim.y = dim.x;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK2, 2.0f, 50.0f, 1.2f, 1.2f);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 10.0f;
+ speed.x = (Rand()-0.5f)*1.5f;
+ speed.z = (Rand()-0.5f)*1.5f;
+ speed.y = -6.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIREZ, 1.0f, 0.0f, 0.0f);
+
+ m_sound->Play(SOUND_ENERGY, m_object->RetPosition(0),
+ 1.0f, 1.0f+Rand()*1.5f);
+ }
+ }
+ else
+ {
+ fret = SearchMetal();
+ if ( fret != 0 )
+ {
+ m_object->SetPower(0);
+ fret->DeleteObject(); // détruit le métal
+ delete fret;
+ }
+
+ fret = SearchPower();
+ if ( fret != 0 )
+ {
+ fret->SetZoom(0, 1.0f);
+ fret->SetLock(FALSE); // pile utilisable
+ fret->SetTruck(m_object);
+ fret->SetPosition(0, D3DVECTOR(0.0f, 3.0f, 0.0f));
+ m_object->SetPower(fret);
+
+ m_displayText->DisplayError(INFO_ENERGY, m_object);
+ }
+
+ SetBusy(FALSE);
+ CAuto::UpdateInterface();
+
+ m_phase = AENP_SMOKE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+ }
+
+ if ( m_phase == AENP_SMOKE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y += 17.0f;
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 6.0f+Rand()*6.0f;
+ dim.x = Rand()*1.5f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+ }
+ else
+ {
+ m_phase = AENP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( big < 0.0f ) big = 0.0f;
+ if ( big > 1.0f ) big = 1.0f;
+ m_object->SetEnergy(big); // màj la grosse pile
+
+ return TRUE;
+}
+
+
+// Cherche l'objet métal.
+
+CObject* CAutoEnergy::SearchMetal()
+{
+ CObject* pObj;
+ ObjectType type;
+
+ pObj = m_object->RetPower();
+ if ( pObj == 0 ) return 0;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_METAL ||
+ type == OBJECT_SCRAP1 ||
+ type == OBJECT_SCRAP2 ||
+ type == OBJECT_SCRAP3 ) return pObj;
+
+ return 0;
+}
+
+// Cherche si un véhicule est trop proche.
+
+BOOL CAutoEnergy::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, cPos)-oRadius;
+
+ if ( dist < 10.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Crée un objet pile.
+
+void CAutoEnergy::CreatePower()
+{
+ CObject* power;
+ D3DVECTOR pos;
+ float angle;
+
+ pos = m_object->RetPosition(0);
+ angle = m_object->RetAngleY(0);
+
+ power = new CObject(m_iMan);
+ if ( !power->CreateResource(pos, angle, OBJECT_POWER) )
+ {
+ delete power;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return;
+ }
+ power->SetLock(TRUE); // pile pas encore utilisable
+
+ pos = power->RetPosition(0);
+ pos.y += 3.0f;
+ power->SetPosition(0, pos);
+}
+
+// Cherche la pile en cours de fabrication.
+
+CObject* CAutoEnergy::SearchPower()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType type;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetLock() ) continue;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_POWER ) continue;
+
+ oPos = pObj->RetPosition(0);
+ if ( oPos.x == cPos.x &&
+ oPos.z == cPos.z )
+ {
+ return pObj;
+ }
+ }
+
+ return 0;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoEnergy::RetError()
+{
+ CObject* pObj;
+ ObjectType type;
+ TerrainRes res;
+
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ if ( m_phase != AENP_WAIT &&
+ m_phase != AENP_BLITZ ) return ERR_OK;
+
+ res = m_terrain->RetResource(m_object->RetPosition(0));
+ if ( res != TR_POWER ) return ERR_ENERGY_NULL;
+
+ if ( m_object->RetEnergy() < ENERGY_POWER ) return ERR_ENERGY_LOW;
+
+ pObj = m_object->RetPower();
+ if ( pObj == 0 ) return ERR_ENERGY_EMPTY;
+ type = pObj->RetType();
+ if ( type == OBJECT_POWER ) return ERR_OK;
+ if ( type != OBJECT_METAL &&
+ type != OBJECT_SCRAP1 &&
+ type != OBJECT_SCRAP2 &&
+ type != OBJECT_SCRAP3 ) return ERR_ENERGY_BAD;
+
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoEnergy::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*14.5f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 0, EVENT_OBJECT_GENERGY);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 108, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CAutoEnergy::UpdateInterface(float rTime)
+{
+ CWindow* pw;
+ CGauge* pg;
+
+ CAuto::UpdateInterface(rTime);
+
+ if ( m_time < m_lastUpdateTime+0.1f ) return;
+ m_lastUpdateTime = m_time;
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GENERGY);
+ if ( pg != 0 )
+ {
+ pg->SetLevel(m_object->RetEnergy());
+ }
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoEnergy::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == AENP_STOP ||
+ m_phase == AENP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoEnergy::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoEnergyPhase)OpInt(line, "aPhase", AENP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastUpdateTime = 0.0f;
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
diff --git a/src/autoenergy.h b/src/autoenergy.h
new file mode 100644
index 0000000..5aa4631
--- /dev/null
+++ b/src/autoenergy.h
@@ -0,0 +1,63 @@
+// autoenergy.h
+
+#ifndef _AUTOENERGY_H_
+#define _AUTOENERGY_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoEnergyPhase
+{
+ AENP_STOP = 1,
+ AENP_WAIT = 2,
+ AENP_BLITZ = 3,
+ AENP_CREATE = 4,
+ AENP_SMOKE = 5,
+};
+
+
+
+class CAutoEnergy : public CAuto
+{
+public:
+ CAutoEnergy(CInstanceManager* iMan, CObject* object);
+ ~CAutoEnergy();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void UpdateInterface(float rTime);
+
+ CObject* SearchMetal();
+ BOOL SearchVehicle();
+ void CreatePower();
+ CObject* SearchPower();
+
+protected:
+ AutoEnergyPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastUpdateTime;
+ float m_lastParticule;
+ int m_partiSphere;
+};
+
+
+#endif //_AUTOENERGY_H_
diff --git a/src/autofactory.cpp b/src/autofactory.cpp
new file mode 100644
index 0000000..4d913f6
--- /dev/null
+++ b/src/autofactory.cpp
@@ -0,0 +1,947 @@
+// autofactory.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "restext.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "displaytext.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autofactory.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoFactory::CAutoFactory(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_type = OBJECT_MOBILEws;
+ m_phase = AFP_WAIT; // en pause jusqu'au premier Init()
+ m_channelSound = -1;
+}
+
+// Destructeur de l'objet.
+
+CAutoFactory::~CAutoFactory()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoFactory::DeleteObject(BOOL bAll)
+{
+ CObject* fret;
+ CObject* vehicle;
+
+ if ( !bAll )
+ {
+ fret = SearchFret(); // métal à transformer ?
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // détruit le métal
+ delete fret;
+ }
+
+ vehicle = SearchVehicle();
+ if ( vehicle != 0 )
+ {
+ vehicle->DeleteObject(); // détruit le véhicule
+ delete vehicle;
+ }
+ }
+
+ if ( m_channelSound != -1 )
+ {
+ m_sound->FlushEnvelope(m_channelSound);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_channelSound = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoFactory::Init()
+{
+ m_phase = AFP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_fretPos = m_object->RetPosition(0);
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoFactory::EventProcess(const Event &event)
+{
+ CObject* fret;
+ CObject* vehicle;
+ D3DMATRIX* mat;
+ CPhysics* physics;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ ObjectType type;
+ float zoom, angle, prog;
+ int i;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ if ( m_object->RetSelect() ) // usine sélectionnée ?
+ {
+ if ( event.event == EVENT_UPDINTERFACE )
+ {
+ CreateInterface(TRUE);
+ }
+
+ type = OBJECT_NULL;
+ if ( event.event == EVENT_OBJECT_FACTORYwa ) type = OBJECT_MOBILEwa;
+ if ( event.event == EVENT_OBJECT_FACTORYta ) type = OBJECT_MOBILEta;
+ if ( event.event == EVENT_OBJECT_FACTORYfa ) type = OBJECT_MOBILEfa;
+ if ( event.event == EVENT_OBJECT_FACTORYia ) type = OBJECT_MOBILEia;
+ if ( event.event == EVENT_OBJECT_FACTORYws ) type = OBJECT_MOBILEws;
+ if ( event.event == EVENT_OBJECT_FACTORYts ) type = OBJECT_MOBILEts;
+ if ( event.event == EVENT_OBJECT_FACTORYfs ) type = OBJECT_MOBILEfs;
+ if ( event.event == EVENT_OBJECT_FACTORYis ) type = OBJECT_MOBILEis;
+ if ( event.event == EVENT_OBJECT_FACTORYwc ) type = OBJECT_MOBILEwc;
+ if ( event.event == EVENT_OBJECT_FACTORYtc ) type = OBJECT_MOBILEtc;
+ if ( event.event == EVENT_OBJECT_FACTORYfc ) type = OBJECT_MOBILEfc;
+ if ( event.event == EVENT_OBJECT_FACTORYic ) type = OBJECT_MOBILEic;
+ if ( event.event == EVENT_OBJECT_FACTORYwi ) type = OBJECT_MOBILEwi;
+ if ( event.event == EVENT_OBJECT_FACTORYti ) type = OBJECT_MOBILEti;
+ if ( event.event == EVENT_OBJECT_FACTORYfi ) type = OBJECT_MOBILEfi;
+ if ( event.event == EVENT_OBJECT_FACTORYii ) type = OBJECT_MOBILEii;
+ if ( event.event == EVENT_OBJECT_FACTORYrt ) type = OBJECT_MOBILErt;
+ if ( event.event == EVENT_OBJECT_FACTORYrc ) type = OBJECT_MOBILErc;
+ if ( event.event == EVENT_OBJECT_FACTORYrr ) type = OBJECT_MOBILErr;
+ if ( event.event == EVENT_OBJECT_FACTORYrs ) type = OBJECT_MOBILErs;
+ if ( event.event == EVENT_OBJECT_FACTORYsa ) type = OBJECT_MOBILEsa;
+
+ if ( type != OBJECT_NULL )
+ {
+ m_type = type;
+
+ if ( m_phase != AFP_WAIT )
+ {
+ return FALSE;
+ }
+
+ fret = SearchFret(); // métal à transformer ?
+ if ( fret == 0 )
+ {
+ m_displayText->DisplayError(ERR_FACTORY_NULL, m_object);
+ return FALSE;
+ }
+ if ( NearestVehicle() )
+ {
+ m_displayText->DisplayError(ERR_FACTORY_NEAR, m_object);
+ return FALSE;
+ }
+
+ SetBusy(TRUE);
+ InitProgressTotal(3.0f+2.0f+15.0f+2.0f+3.0f);
+ UpdateInterface();
+
+ fret->SetLock(TRUE); // métal plus utilisable
+ SoundManip(3.0f, 1.0f, 0.5f);
+
+ m_phase = AFP_CLOSE_S;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ return TRUE;
+ }
+ }
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ EventProgress(event.rTime);
+
+ if ( m_phase == AFP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_phase = AFP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == AFP_CLOSE_S )
+ {
+ if ( m_progress < 1.0f )
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ zoom = 0.30f+(m_progress-0.5f+i/16.0f)*2.0f*0.70f;
+ if ( zoom < 0.30f ) zoom = 0.30f;
+ if ( zoom > 1.00f ) zoom = 1.00f;
+ m_object->SetZoomZ( 1+i, zoom);
+ m_object->SetZoomZ(10+i, zoom);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ m_object->SetZoomZ( 1+i, 1.0f);
+ m_object->SetZoomZ(10+i, 1.0f);
+ }
+
+ SoundManip(2.0f, 1.0f, 1.2f);
+
+ m_phase = AFP_CLOSE_T;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == AFP_CLOSE_T )
+ {
+ if ( m_progress < 1.0f )
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ angle = -m_progress*(PI/2.0f)+PI/2.0f;
+ m_object->SetAngleZ( 1+i, angle);
+ m_object->SetAngleZ(10+i, -angle);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ m_object->SetAngleZ( 1+i, 0.0f);
+ m_object->SetAngleZ(10+i, 0.0f);
+ }
+
+ m_channelSound = m_sound->Play(SOUND_FACTORY, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, 11.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 2.0f, SOPER_STOP);
+
+ m_phase = AFP_BUILD;
+ m_progress = 0.0f;
+ m_speed = 1.0f/15.0f;
+ }
+ }
+
+ if ( m_phase == AFP_BUILD )
+ {
+ if ( m_progress == 0.0f )
+ {
+ if ( !CreateVehicle() )
+ {
+ fret = SearchFret(); // métal à transformer ?
+ if ( fret != 0 )
+ {
+ fret->SetLock(FALSE); // métal de nouveau utilisable
+ }
+
+ if ( m_channelSound != -1 )
+ {
+ m_sound->FlushEnvelope(m_channelSound);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_channelSound = -1;
+ }
+
+ m_phase = AFP_OPEN_T;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ return TRUE;
+ }
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ if ( m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErc ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs )
+ {
+ prog = 1.0f-m_progress*1.5f;
+ if ( prog < 0.0f ) prog = 0.0f;
+ }
+ else
+ {
+ prog = 1.0f-m_progress;
+ }
+ angle = powf(prog*10.0f, 2.0f)+m_object->RetAngleY(0);
+
+ vehicle = SearchVehicle();
+ if ( vehicle != 0 )
+ {
+ vehicle->SetAngleY(0, angle+PI);
+ vehicle->SetZoom(0, m_progress);
+ }
+
+ fret = SearchFret(); // métal à transformer ?
+ if ( fret != 0 )
+ {
+ fret->SetZoom(0, 1.0f-m_progress);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+#if 0
+ pos = m_fretPos;
+ pos.x += (Rand()-0.5f)*20.0f;
+ pos.z += (Rand()-0.5f)*20.0f;
+ pos.y += 1.0f;
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+ speed.y = Rand()*12.0f;
+ dim.x = Rand()*12.0f+10.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, 1.0f, 0.0f, 0.0f);
+#else
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(-12.0f, 20.0f, -4.0f); // position cheminée
+ pos = Transform(*mat, pos);
+ pos.y += 2.0f;
+ pos.x += (Rand()-0.5f)*2.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 6.0f+Rand()*6.0f;
+ dim.x = Rand()*1.5f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+#endif
+ }
+ }
+ else
+ {
+ m_displayText->DisplayError(INFO_FACTORY, m_object);
+ SoundManip(2.0f, 1.0f, 1.2f);
+
+ fret = SearchFret(); // métal à transformer ?
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // supprime le métal
+ delete fret;
+ }
+
+ vehicle = SearchVehicle();
+ if ( vehicle != 0 )
+ {
+ physics = vehicle->RetPhysics();
+ if ( physics != 0 )
+ {
+ physics->SetFreeze(FALSE); // on peut bouger
+ }
+
+ vehicle->SetLock(FALSE); // véhicule utilisable
+//? vehicle->RetPhysics()->RetBrain()->StartTaskAdvance(16.0f);
+ vehicle->SetAngleY(0, m_object->RetAngleY(0)+PI);
+ vehicle->SetZoom(0, 1.0f);
+ }
+
+ m_main->CreateShortcuts();
+
+ m_phase = AFP_OPEN_T;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == AFP_OPEN_T )
+ {
+ if ( m_progress < 1.0f )
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ angle = -(1.0f-m_progress)*(PI/2.0f)+PI/2.0f;
+ m_object->SetAngleZ( 1+i, angle);
+ m_object->SetAngleZ(10+i, -angle);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_fretPos;
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ pos.y += Rand()*10.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ m_object->SetAngleZ( 1+i, PI/2.0f);
+ m_object->SetAngleZ(10+i, -PI/2.0f);
+ }
+
+ SoundManip(3.0f, 1.0f, 0.5f);
+
+ m_phase = AFP_OPEN_S;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+
+ if ( m_phase == AFP_OPEN_S )
+ {
+ if ( m_progress < 1.0f )
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ zoom = 0.30f+((1.0f-m_progress)-0.5f+i/16.0f)*2.0f*0.70f;
+ if ( zoom < 0.30f ) zoom = 0.30f;
+ if ( zoom > 1.00f ) zoom = 1.00f;
+ m_object->SetZoomZ( 1+i, zoom);
+ m_object->SetZoomZ(10+i, zoom);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_fretPos;
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ pos.y += Rand()*10.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<9 ; i++ )
+ {
+ m_object->SetZoomZ( 1+i, 0.30f);
+ m_object->SetZoomZ(10+i, 0.30f);
+ }
+
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ m_phase = AFP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoFactory::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == AFP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoFactory::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoFactoryPhase)OpInt(line, "aPhase", AFP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+ m_fretPos = m_object->RetPosition(0);
+
+ return TRUE;
+}
+
+
+// Cherche l'objet fret.
+
+CObject* CAutoFactory::SearchFret()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_METAL ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_fretPos);
+
+ if ( dist < 8.0f ) return pObj;
+ }
+
+ return 0;
+}
+
+// Cherche si un véhicule est trop proche.
+
+BOOL CAutoFactory::NearestVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, cPos)-oRadius;
+
+ if ( dist < 10.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// Crée un véhicule pas utilisable tout de suite.
+
+BOOL CAutoFactory::CreateVehicle()
+{
+ CObject* vehicle;
+ D3DMATRIX* mat;
+ CPhysics* physics;
+ D3DVECTOR pos;
+ float angle;
+ char* name;
+ int i;
+
+ angle = m_object->RetAngleY(0);
+
+ mat = m_object->RetWorldMatrix(0);
+ if ( m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErc ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs )
+ {
+ pos = D3DVECTOR(2.0f, 0.0f, 0.0f);
+ }
+ else
+ {
+ pos = D3DVECTOR(4.0f, 0.0f, 0.0f);
+ }
+ pos = Transform(*mat, pos);
+
+ vehicle = new CObject(m_iMan);
+ if ( !vehicle->CreateVehicle(pos, angle, m_type, -1.0f, FALSE, FALSE) )
+ {
+ delete vehicle;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return FALSE;
+ }
+ vehicle->UpdateMapping();
+ vehicle->SetLock(TRUE); // pas utilisable
+ vehicle->SetRange(30.0f);
+
+ physics = vehicle->RetPhysics();
+ if ( physics != 0 )
+ {
+ physics->SetFreeze(TRUE); // on ne bouge plus
+ }
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ name = m_main->RetNewScriptName(m_type, i);
+ if ( name == 0 ) break;
+ vehicle->ReadProgram(i, name);
+ }
+
+ return TRUE;
+}
+
+// Cherche le véhicule en cours de fabrication.
+
+CObject* CAutoFactory::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetLock() ) continue;
+
+ type = pObj->RetType();
+ if ( type != m_type ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_fretPos);
+
+ if ( dist < 8.0f ) return pObj;
+ }
+
+ return 0;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoFactory::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ dim.x = 33.0f/640.0f;
+ dim.y = 33.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = 0.0f;
+ pos.y = oy+sy*2.6f;
+ ddim.x = 138.0f/640.0f;
+ ddim.y = 222.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 6, EVENT_WINDOW3);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*8.2f;
+ pw->CreateButton(pos, dim, 128+9, EVENT_OBJECT_FACTORYwa);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+10, EVENT_OBJECT_FACTORYta);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+11, EVENT_OBJECT_FACTORYfa);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+22, EVENT_OBJECT_FACTORYia);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*7.1f;
+ pw->CreateButton(pos, dim, 128+12, EVENT_OBJECT_FACTORYws);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+13, EVENT_OBJECT_FACTORYts);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+14, EVENT_OBJECT_FACTORYfs);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+24, EVENT_OBJECT_FACTORYis);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*6.0f;
+ pw->CreateButton(pos, dim, 128+15, EVENT_OBJECT_FACTORYwc);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+16, EVENT_OBJECT_FACTORYtc);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+17, EVENT_OBJECT_FACTORYfc);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+23, EVENT_OBJECT_FACTORYic);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*4.9f;
+ pw->CreateButton(pos, dim, 128+25, EVENT_OBJECT_FACTORYwi);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+26, EVENT_OBJECT_FACTORYti);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+27, EVENT_OBJECT_FACTORYfi);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+28, EVENT_OBJECT_FACTORYii);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*3.8f;
+ pw->CreateButton(pos, dim, 128+18, EVENT_OBJECT_FACTORYrt);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+19, EVENT_OBJECT_FACTORYrc);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+20, EVENT_OBJECT_FACTORYrr);
+ pos.x += dim.x;
+ pw->CreateButton(pos, dim, 128+29, EVENT_OBJECT_FACTORYrs);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*2.7f;
+ pw->CreateButton(pos, dim, 128+21, EVENT_OBJECT_FACTORYsa);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 101, EVENT_OBJECT_TYPE);
+
+ UpdateInterface();
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CAutoFactory::UpdateInterface()
+{
+ CWindow* pw;
+
+ if ( !m_object->RetSelect() ) return;
+
+ CAuto::UpdateInterface();
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+
+ UpdateButton(pw, EVENT_OBJECT_FACTORYwa, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYta, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYfa, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYia, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYws, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYts, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYfs, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYis, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYwc, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYtc, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYfc, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYic, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYwi, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYti, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYfi, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYii, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYrt, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYrc, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYrr, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYrs, m_bBusy);
+ UpdateButton(pw, EVENT_OBJECT_FACTORYsa, m_bBusy);
+}
+
+// Met à jour un bouton de l'interface.
+
+void CAutoFactory::UpdateButton(CWindow *pw, EventMsg event, BOOL bBusy)
+{
+ BOOL bEnable = TRUE;
+
+ EnableInterface(pw, event, !bBusy);
+
+ if ( event == EVENT_OBJECT_FACTORYta )
+ {
+ bEnable = g_researchDone&RESEARCH_TANK;
+ }
+ if ( event == EVENT_OBJECT_FACTORYfa )
+ {
+ bEnable = g_researchDone&RESEARCH_FLY;
+ }
+ if ( event == EVENT_OBJECT_FACTORYia )
+ {
+ bEnable = g_researchDone&RESEARCH_iPAW;
+ }
+
+ if ( event == EVENT_OBJECT_FACTORYws )
+ {
+ bEnable = g_researchDone&RESEARCH_SNIFFER;
+ }
+ if ( event == EVENT_OBJECT_FACTORYts )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_SNIFFER) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYfs )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_SNIFFER) &&
+ (g_researchDone&RESEARCH_FLY) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYis )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_SNIFFER) &&
+ (g_researchDone&RESEARCH_iPAW) );
+ }
+
+ if ( event == EVENT_OBJECT_FACTORYwc )
+ {
+ bEnable = g_researchDone&RESEARCH_CANON;
+ }
+ if ( event == EVENT_OBJECT_FACTORYtc )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_CANON) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYfc )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_CANON) &&
+ (g_researchDone&RESEARCH_FLY) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYic )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_CANON) &&
+ (g_researchDone&RESEARCH_iPAW) );
+ }
+
+ if ( event == EVENT_OBJECT_FACTORYwi )
+ {
+ bEnable = g_researchDone&RESEARCH_iGUN;
+ }
+ if ( event == EVENT_OBJECT_FACTORYti )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_iGUN) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYfi )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_iGUN) &&
+ (g_researchDone&RESEARCH_FLY) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYii )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_iGUN) &&
+ (g_researchDone&RESEARCH_iPAW) );
+ }
+
+ if ( event == EVENT_OBJECT_FACTORYrt )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_THUMP) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYrc )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_PHAZER) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYrr )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_RECYCLER) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+ if ( event == EVENT_OBJECT_FACTORYrs )
+ {
+ bEnable = ( (g_researchDone&RESEARCH_SHIELD) &&
+ (g_researchDone&RESEARCH_TANK) );
+ }
+
+ if ( event == EVENT_OBJECT_FACTORYsa )
+ {
+ bEnable = g_researchDone&RESEARCH_SUBM;
+ }
+
+ DeadInterface(pw, event, bEnable);
+}
+
+// Fait entendre le son du bras manipulateur.
+
+void CAutoFactory::SoundManip(float time, float amplitude, float frequency)
+{
+ int i;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f*frequency, TRUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
+}
+
diff --git a/src/autofactory.h b/src/autofactory.h
new file mode 100644
index 0000000..c635608
--- /dev/null
+++ b/src/autofactory.h
@@ -0,0 +1,66 @@
+// autofactory.h
+
+#ifndef _AUTOFACTORY_H_
+#define _AUTOFACTORY_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoFactoryPhase
+{
+ AFP_WAIT = 1, // attend métal
+ AFP_CLOSE_S = 2, // ferme les portes (shift)
+ AFP_CLOSE_T = 3, // ferme les portes (turn)
+ AFP_BUILD = 4, // construit le véhicule
+ AFP_OPEN_T = 5, // ouvre les portes (turn)
+ AFP_OPEN_S = 6, // ouvre les portes (shift)
+ AFP_ADVANCE = 7, // avance devant la porte
+};
+
+
+
+class CAutoFactory : public CAuto
+{
+public:
+ CAutoFactory(CInstanceManager* iMan, CObject* object);
+ ~CAutoFactory();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void UpdateInterface();
+ void UpdateButton(CWindow *pw, EventMsg event, BOOL bBusy);
+
+ CObject* SearchFret();
+ BOOL NearestVehicle();
+ BOOL CreateVehicle();
+ CObject* SearchVehicle();
+
+ void SoundManip(float time, float amplitude, float frequency);
+
+protected:
+ AutoFactoryPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_lastParticule;
+ D3DVECTOR m_fretPos;
+ int m_channelSound;
+};
+
+
+#endif //_AUTOFACTORY_H_
diff --git a/src/autoflag.cpp b/src/autoflag.cpp
new file mode 100644
index 0000000..46b529c
--- /dev/null
+++ b/src/autoflag.cpp
@@ -0,0 +1,164 @@
+// autoflag.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "auto.h"
+#include "autoflag.h"
+
+
+
+#define ADJUST_ANGLE FALSE // TRUE -> ajuste les angles des membres
+
+
+#if ADJUST_ANGLE
+static float g_flag1 = 6.00f;
+static float g_flag2 = 0.10f;
+static float g_flag3 = 2.00f;
+#endif
+
+
+// Constructeur de l'objet.
+
+CAutoFlag::CAutoFlag(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoFlag::~CAutoFlag()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoFlag::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoFlag::Init()
+{
+ D3DVECTOR wind;
+ float angle;
+
+ m_time = 0.0f;
+ m_param = 0;
+ m_progress = 0.0f;
+
+ wind = m_terrain->RetWind();
+ angle = RotateAngle(wind.x, -wind.z);
+ m_object->SetAngleY(0, angle); // oriente le drapeau dans le vent
+
+ m_strong = Length(wind);
+}
+
+
+// Début d'une action (1 = secoue).
+
+void CAutoFlag::Start(int param)
+{
+ if ( m_param == 0 )
+ {
+ m_param = param;
+ m_progress = 0.0f;
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoFlag::EventProcess(const Event &event)
+{
+ float angle;
+ int i;
+
+ CAuto::EventProcess(event);
+
+#if ADJUST_ANGLE
+ if ( event.event == EVENT_KEYDOWN )
+ {
+ if ( event.param == 'E' ) g_flag1 += 0.1f;
+ if ( event.param == 'D' ) g_flag1 -= 0.1f;
+ if ( event.param == 'R' ) g_flag2 += 0.1f;
+ if ( event.param == 'F' ) g_flag2 -= 0.1f;
+ if ( event.param == 'T' ) g_flag3 += 0.1f;
+ if ( event.param == 'G' ) g_flag3 -= 0.1f;
+ }
+#endif
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ if ( m_param == 1 ) // secoue ?
+ {
+ m_progress += event.rTime*(1.0f/2.0f);
+ if ( m_progress < 1.0f )
+ {
+ angle = sinf(m_progress*PI*8.0f)*0.3f*(1.0f-m_progress);
+ m_object->SetAngleX(0, angle);
+ angle = sinf(m_progress*PI*4.0f)*0.3f*(1.0f-m_progress);
+ m_object->SetAngleZ(0, angle);
+ }
+ else
+ {
+ m_object->SetAngleX(0, 0.0f);
+ m_object->SetAngleZ(0, 0.0f);
+ m_param = 0;
+ m_progress = 0.0f;
+ }
+ }
+
+ if ( m_strong == 0.0f ) return TRUE; // pas de vent ?
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+#if ADJUST_ANGLE
+ angle = sinf(m_time*g_flag1+i*2.0f)*((i+g_flag3)*g_flag2);
+#else
+ angle = sinf(m_time*6.0f+i*2.0f)*((i+2.0f)*0.1f);
+#endif
+ m_object->SetAngleY(1+i, angle);
+ }
+
+#if ADJUST_ANGLE
+ char s[100];
+ sprintf(s, "a=%.2f b=%.2f c=%.2f", g_flag1, g_flag2, g_flag3);
+ m_engine->SetInfoText(4, s);
+#endif
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoFlag::RetError()
+{
+ return ERR_OK;
+}
+
+
diff --git a/src/autoflag.h b/src/autoflag.h
new file mode 100644
index 0000000..9d928c5
--- /dev/null
+++ b/src/autoflag.h
@@ -0,0 +1,40 @@
+// autoflag.h
+
+#ifndef _AUTOFLAG_H_
+#define _AUTOFLAG_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+class CAutoFlag : public CAuto
+{
+public:
+ CAutoFlag(CInstanceManager* iMan, CObject* object);
+ ~CAutoFlag();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param);
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+protected:
+
+protected:
+ float m_strong;
+ int m_param;
+ float m_progress;
+};
+
+
+#endif //_AUTOFLAG_H_
diff --git a/src/autohuston.cpp b/src/autohuston.cpp
new file mode 100644
index 0000000..5e5c282
--- /dev/null
+++ b/src/autohuston.cpp
@@ -0,0 +1,301 @@
+// autohuston.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "auto.h"
+#include "autohuston.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoHuston::CAutoHuston(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ D3DVECTOR pos;
+ int i;
+
+ CAuto::CAuto(iMan, object);
+
+ for ( i=0 ; i<HUSTONMAXLENS ; i++ )
+ {
+ m_lens[i].parti = -1;
+ }
+
+ pos = m_object->RetPosition(0);
+ m_lens[0].type = PARTISELR;
+ m_lens[1].type = PARTISELR;
+ m_lens[2].type = PARTISELR;
+ m_lens[3].type = PARTISELR;
+ m_lens[0].pos = pos+D3DVECTOR(0.0f+13.0f, 34.0f, 30.0f );
+ m_lens[1].pos = pos+D3DVECTOR(0.0f-13.0f, 34.0f, 30.0f );
+ m_lens[2].pos = pos+D3DVECTOR(0.0f , 34.0f, 30.0f+13.0f);
+ m_lens[3].pos = pos+D3DVECTOR(0.0f , 34.0f, 30.0f-13.0f);
+ m_lens[0].dim = 4.0f;
+ m_lens[1].dim = 4.0f;
+ m_lens[2].dim = 4.0f;
+ m_lens[3].dim = 4.0f;
+ m_lens[0].total = 1.0f;
+ m_lens[1].total = 1.0f;
+ m_lens[2].total = 1.0f;
+ m_lens[3].total = 1.0f;
+ m_lens[0].off = 0.4f;
+ m_lens[1].off = 0.4f;
+ m_lens[2].off = 0.4f;
+ m_lens[3].off = 0.4f;
+
+ // Pièce sous radar.
+ i = 4;
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 9.9f, 40.1f);
+ m_lens[i].dim = 1.8f;
+ m_lens[i].total = 0.4f;
+ m_lens[i].off = 0.2f;
+ i ++;
+
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 7.2f, 34.8f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.7f;
+ m_lens[i].off = 0.3f;
+ i ++;
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 6.5f, 34.3f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.7f;
+ m_lens[i].off = 0.3f;
+ i ++;
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 6.5f, 33.4f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.0f;
+ m_lens[i].off = 0.0f;
+ i ++;
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 6.5f, 33.0f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 1.0f;
+ m_lens[i].off = 0.5f;
+ i ++;
+
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 8.5f, 14.0f);
+ m_lens[i].dim = 1.2f;
+ m_lens[i].total = 0.8f;
+ m_lens[i].off = 0.2f;
+ i ++;
+
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(4.0f, 6.0f, 8.6f);
+ m_lens[i].dim = 1.0f;
+ m_lens[i].total = 0.9f;
+ m_lens[i].off = 0.7f;
+ i ++;
+
+ // Pièce avec 3 fenêtres.
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 9.9f, -19.9f);
+ m_lens[i].dim = 1.0f;
+ m_lens[i].total = 0.6f;
+ m_lens[i].off = 0.3f;
+ i ++;
+
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 7.2f, 34.8f-60.0f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.7f;
+ m_lens[i].off = 0.3f;
+ i ++;
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 6.5f, 34.3f-60.0f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.0f;
+ m_lens[i].off = 0.0f;
+ i ++;
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 6.5f, 33.4f-60.0f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.6f;
+ m_lens[i].off = 0.4f;
+ i ++;
+ m_lens[i].type = PARTISELR;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 6.5f, 33.0f-60.0f);
+ m_lens[i].dim = 0.4f;
+ m_lens[i].total = 0.8f;
+ m_lens[i].off = 0.2f;
+ i ++;
+
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-6.5f, 13.5f, -37.0f);
+ m_lens[i].dim = 1.0f;
+ m_lens[i].total = 0.0f;
+ m_lens[i].off = 0.0f;
+ i ++;
+
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 12.2f, -39.8f);
+ m_lens[i].dim = 1.8f;
+ m_lens[i].total = 1.5f;
+ m_lens[i].off = 0.5f;
+ i ++;
+
+ m_lens[i].type = PARTISELY;
+ m_lens[i].pos = pos+D3DVECTOR(-7.0f, 8.5f, -47.0f);
+ m_lens[i].dim = 0.6f;
+ m_lens[i].total = 0.7f;
+ m_lens[i].off = 0.5f;
+ i ++;
+
+ m_lensTotal = i;
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoHuston::~CAutoHuston()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoHuston::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoHuston::Init()
+{
+ m_time = 0.0f;
+
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+}
+
+
+// Démarre l'objet.
+
+void CAutoHuston::Start(int param)
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoHuston::EventProcess(const Event &event)
+{
+ D3DVECTOR speed;
+ FPOINT dim;
+ float angle;
+ int i;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ angle = -m_time*1.0f;
+ m_object->SetAngleY(1, angle); // fait tourner le radar
+ angle = sinf(m_time*4.0f)*0.3f;
+ m_object->SetAngleX(2, angle);
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ // Fait clignotter les clés.
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ for ( i=0 ; i<m_lensTotal ; i++ )
+ {
+ if ( m_lens[i].total != 0.0f &&
+ Mod(m_time, m_lens[i].total) < m_lens[i].off )
+ {
+ if ( m_lens[i].parti != -1 )
+ {
+ m_particule->DeleteParticule(m_lens[i].parti);
+ m_lens[i].parti = -1;
+ }
+ }
+ else
+ {
+ if ( m_lens[i].parti == -1 )
+ {
+ dim.x = m_lens[i].dim;
+ dim.y = dim.x;
+ m_lens[i].parti = m_particule->CreateParticule(m_lens[i].pos, speed, dim, m_lens[i].type, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+// Stoppe l'automate.
+
+BOOL CAutoHuston::Abort()
+{
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoHuston::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 115, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoHuston::RetError()
+{
+ return ERR_OK;
+}
+
diff --git a/src/autohuston.h b/src/autohuston.h
new file mode 100644
index 0000000..150edd5
--- /dev/null
+++ b/src/autohuston.h
@@ -0,0 +1,59 @@
+// autohuston.h
+
+#ifndef _AUTOHUSTON_H_
+#define _AUTOHUSTON_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ParticuleType;
+
+
+
+typedef struct
+{
+ int parti;
+ ParticuleType type;
+ D3DVECTOR pos;
+ float dim;
+ float total;
+ float off;
+}
+HustonLens;
+
+
+#define HUSTONMAXLENS 20
+
+
+class CAutoHuston : public CAuto
+{
+public:
+ CAutoHuston(CInstanceManager* iMan, CObject* object);
+ ~CAutoHuston();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param);
+ BOOL EventProcess(const Event &event);
+ BOOL Abort();
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+protected:
+
+protected:
+ float m_progress;
+ float m_speed;
+ HustonLens m_lens[HUSTONMAXLENS];
+ int m_lensTotal;
+};
+
+
+#endif //_AUTOHUSTON_H_
diff --git a/src/autoinfo.cpp b/src/autoinfo.cpp
new file mode 100644
index 0000000..f6de5a6
--- /dev/null
+++ b/src/autoinfo.cpp
@@ -0,0 +1,523 @@
+// autoinfo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "list.h"
+#include "window.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autoinfo.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoInfo::CAutoInfo(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoInfo::~CAutoInfo()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoInfo::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoInfo::Init()
+{
+ m_phase = AIP_WAIT;
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_bLastVirus = FALSE;
+
+ CAuto::Init();
+}
+
+
+// Démarre une émission.
+
+void CAutoInfo::Start(int param)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ if ( param == 0 ) // instruction "receive" ?
+ {
+ m_phase = AIP_EMETTE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ else if ( param == 2 ) // instruction "send" ?
+ {
+ m_phase = AIP_RECEIVE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ else
+ {
+ m_phase = AIP_ERROR;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+
+ m_lastParticule = 0;
+ m_goal = m_object->RetPosition(0);
+
+ if ( m_phase == AIP_EMETTE )
+ {
+ pos = m_goal;
+ pos.y += 9.5f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 30.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISPHERE4, 1.5f, 0.0f, 0.0f);
+
+ m_sound->Play(SOUND_LABO, pos, 1.0f, 2.0f);
+ }
+ if ( m_phase == AIP_RECEIVE )
+ {
+ pos = m_goal;
+ pos.y += 9.5f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 50.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISPHERE6, 1.5f, 0.0f, 0.0f);
+
+ m_sound->Play(SOUND_LABO, pos, 1.0f, 2.0f);
+ }
+ if ( m_phase == AIP_ERROR )
+ {
+ m_sound->Play(SOUND_GGG, pos, 1.0f, 0.5f);
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoInfo::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float duration, angle, rTime;
+ int i;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ angle = m_object->RetAngleY(1);
+ angle += Rand()*0.3f;
+ m_object->SetAngleY(1, angle);
+
+ m_object->SetAngleX(2, (Rand()-0.5f)*0.3f);
+ m_object->SetAngleX(4, (Rand()-0.5f)*0.3f);
+ m_object->SetAngleX(6, (Rand()-0.5f)*0.3f);
+
+ m_object->SetAngleZ(2, (Rand()-0.5f)*0.3f);
+ m_object->SetAngleZ(4, (Rand()-0.5f)*0.3f);
+ m_object->SetAngleZ(6, (Rand()-0.5f)*0.3f);
+
+ UpdateListVirus();
+ }
+ m_bLastVirus = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ if ( m_bLastVirus )
+ {
+ m_bLastVirus = FALSE;
+ UpdateList(); // remet la liste normalement
+ }
+ else
+ {
+ if ( m_object->RetInfoUpdate() )
+ {
+ UpdateList(); // actualise la liste
+ }
+ }
+ }
+
+ UpdateInterface(event.rTime);
+
+ rTime = event.rTime;
+
+ if ( m_phase == AIP_EMETTE ) // instruction "receive" ?
+ {
+ if ( m_progress < 0.5f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos = m_goal;
+ pos.y += 9.5f;
+ speed.x = (Rand()-0.5f)*50.0f;
+ speed.z = (Rand()-0.5f)*50.0f;
+ speed.y = (Rand()-0.5f)*50.0f;
+ speed *= 0.5f+m_progress*0.5f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ duration = Rand()*0.5f+0.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ m_progress += rTime*m_speed;
+
+ m_object->SetAngleZ(2, m_progress*2.0f*PI);
+ m_object->SetAngleZ(4, m_progress*2.0f*PI);
+ m_object->SetAngleZ(6, m_progress*2.0f*PI);
+ }
+ else
+ {
+ m_phase = AIP_WAIT;
+
+ m_object->SetAngleX(2, 0.0f);
+ m_object->SetAngleX(4, 0.0f);
+ m_object->SetAngleX(6, 0.0f);
+
+ m_object->SetAngleZ(2, 0.0f);
+ m_object->SetAngleZ(4, 0.0f);
+ m_object->SetAngleZ(6, 0.0f);
+ }
+ }
+
+ if ( m_phase == AIP_RECEIVE ) // instruction "send" ?
+ {
+ if ( m_progress < 0.5f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos = m_goal;
+ pos.y += 9.5f;
+ speed = pos;
+ pos.x += (Rand()-0.5f)*40.0f;
+ pos.y += (Rand()-0.5f)*40.0f;
+ pos.z += (Rand()-0.5f)*40.0f;
+ speed = (speed-pos)*1.0f;
+//? speed *= 0.5f+m_progress*0.5f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ duration = Rand()*0.5f+0.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ m_progress += rTime*m_speed;
+
+ m_object->SetAngleZ(2, m_progress*2.0f*PI);
+ m_object->SetAngleZ(4, m_progress*2.0f*PI);
+ m_object->SetAngleZ(6, m_progress*2.0f*PI);
+ }
+ else
+ {
+ m_phase = AIP_WAIT;
+
+ m_object->SetAngleX(2, 0.0f);
+ m_object->SetAngleX(4, 0.0f);
+ m_object->SetAngleX(6, 0.0f);
+
+ m_object->SetAngleZ(2, 0.0f);
+ m_object->SetAngleZ(4, 0.0f);
+ m_object->SetAngleZ(6, 0.0f);
+ }
+ }
+
+ if ( m_phase == AIP_ERROR )
+ {
+ if ( m_progress < 0.5f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_goal;
+ speed.x = (Rand()-0.5f)*5.0f;
+ speed.z = (Rand()-0.5f)*5.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = 5.0f+Rand()*5.0f;
+ dim.y = dim.x;
+ duration = Rand()*0.5f+0.5f;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 4.0f);
+ }
+
+ if ( m_progress < 1.0f )
+ {
+ m_progress += rTime*m_speed;
+ rTime = 0.0f; // stoppe la rotation
+
+ if ( m_progress < 0.5f )
+ {
+ angle = m_progress/0.5f;
+ }
+ else
+ {
+ angle = 1.0f-(m_progress-0.5f)/0.5f;
+ }
+ m_object->SetAngleX(2, angle*0.5f);
+ m_object->SetAngleX(4, angle*0.5f);
+ m_object->SetAngleX(6, angle*0.5f);
+
+ m_object->SetAngleZ(2, (Rand()-0.5f)*0.2f);
+ m_object->SetAngleZ(4, (Rand()-0.5f)*0.2f);
+ m_object->SetAngleZ(6, (Rand()-0.5f)*0.2f);
+ }
+ else
+ {
+ m_phase = AIP_WAIT;
+
+ m_object->SetAngleX(2, 0.0f);
+ m_object->SetAngleX(4, 0.0f);
+ m_object->SetAngleX(6, 0.0f);
+
+ m_object->SetAngleZ(2, 0.0f);
+ m_object->SetAngleZ(4, 0.0f);
+ m_object->SetAngleZ(6, 0.0f);
+ }
+ }
+
+ angle = m_object->RetAngleY(1);
+ angle += rTime*0.5f;
+ m_object->SetAngleY(1, angle);
+
+ m_object->SetAngleX(3, sinf(m_time*6.0f+PI*0.0f/3.0f)*0.3f);
+ m_object->SetAngleX(5, sinf(m_time*6.0f+PI*2.0f/3.0f)*0.3f);
+ m_object->SetAngleX(7, sinf(m_time*6.0f+PI*4.0f/3.0f)*0.3f);
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoInfo::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoInfo::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ CList* pl;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*0.0f;
+ ddim.x = 160.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pl = pw->CreateList(pos, ddim, 1, EVENT_OBJECT_GINFO, 1.10f);
+ pl->SetSelectCap(FALSE);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 112, EVENT_OBJECT_TYPE);
+
+ UpdateList();
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CAutoInfo::UpdateInterface(float rTime)
+{
+ CAuto::UpdateInterface(rTime);
+}
+
+
+// Met à jour le contenu de la liste.
+
+void CAutoInfo::UpdateList()
+{
+ CWindow* pw;
+ CList* pl;
+ Info info;
+ int total, i;
+ char text[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pl = (CList*)pw->SearchControl(EVENT_OBJECT_GINFO);
+ if ( pl == 0 ) return;
+
+ pl->Flush();
+ total = m_object->RetInfoTotal();
+ if ( total == 0 )
+ {
+ pl->ClearState(STATE_ENABLE);
+ }
+ else
+ {
+ pl->SetState(STATE_ENABLE);
+
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = m_object->RetInfo(i);
+ sprintf(text, "%s = %.2f", info.name, info.value);
+ pl->SetName(i, text);
+ }
+ }
+
+ m_object->SetInfoUpdate(FALSE);
+}
+
+// Met à jour le contenu contaminé de la liste.
+
+void CAutoInfo::UpdateListVirus()
+{
+ CWindow* pw;
+ CList* pl;
+ int i, j, max;
+ char text[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pl = (CList*)pw->SearchControl(EVENT_OBJECT_GINFO);
+ if ( pl == 0 ) return;
+
+ pl->SetState(STATE_ENABLE);
+
+ pl->Flush();
+ for ( i=0 ; i<4 ; i++ )
+ {
+ max = (int)(2.0f+Rand()*10.0f);
+ for ( j=0 ; j<max ; j++ )
+ {
+ do
+ {
+ text[j] = ' '+(int)(Rand()*94.0f);
+ }
+ while ( text[j] == '\\' );
+ }
+ text[j] = 0;
+
+ pl->SetName(i, text);
+ }
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoInfo::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == AIP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoInfo::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoInfoPhase)OpInt(line, "aPhase", AIP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autoinfo.h b/src/autoinfo.h
new file mode 100644
index 0000000..f7ce998
--- /dev/null
+++ b/src/autoinfo.h
@@ -0,0 +1,60 @@
+// autoinfo.h
+
+#ifndef _AUTOINFO_H_
+#define _AUTOINFO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoInfoPhase
+{
+ AIP_WAIT = 1,
+ AIP_EMETTE = 2,
+ AIP_RECEIVE = 3,
+ AIP_ERROR = 4,
+};
+
+
+
+class CAutoInfo : public CAuto
+{
+public:
+ CAutoInfo(CInstanceManager* iMan, CObject* object);
+ ~CAutoInfo();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param);
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void UpdateInterface(float rTime);
+ void UpdateList();
+ void UpdateListVirus();
+
+protected:
+ AutoInfoPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ D3DVECTOR m_goal;
+ BOOL m_bLastVirus;
+};
+
+
+#endif //_AUTOINFO_H_
diff --git a/src/autojostle.cpp b/src/autojostle.cpp
new file mode 100644
index 0000000..057ca90
--- /dev/null
+++ b/src/autojostle.cpp
@@ -0,0 +1,153 @@
+// autojostle.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "list.h"
+#include "window.h"
+#include "sound.h"
+#include "auto.h"
+#include "autojostle.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoJostle::CAutoJostle(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoJostle::~CAutoJostle()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoJostle::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoJostle::Init()
+{
+ m_time = 0.0f;
+ m_error = ERR_CONTINUE;
+
+ CAuto::Init();
+}
+
+
+// Démarre une émission.
+
+void CAutoJostle::Start(int param, float force)
+{
+ ObjectType type;
+
+ if ( force < 0.0f ) force = 0.0f;
+ if ( force > 1.0f ) force = 1.0f;
+
+ m_force = force;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(0.5f+force*1.0f); // 0.5 .. 1.5
+ m_time = 0.0f;
+ m_error = ERR_CONTINUE;
+
+ type = m_object->RetType();
+ if ( type >= OBJECT_PLANT5 &&
+ type <= OBJECT_PLANT7 ) // trèfle ?
+ {
+ m_force *= 3.0f;
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoJostle::EventProcess(const Event &event)
+{
+ D3DVECTOR dir;
+ float factor, angle, zoom;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ if ( m_progress < 1.0f )
+ {
+ m_progress += event.rTime*m_speed;
+
+ if ( m_progress < 0.5f )
+ {
+ factor = m_progress/0.5f;
+ }
+ else
+ {
+ factor = 2.0f-m_progress/0.5f;
+ }
+ factor *= m_force;
+
+ dir.x = sinf(m_progress*PI*4.0f);
+ dir.z = cosf(m_progress*PI*4.0f);
+
+ angle = sinf(m_time*10.0f)*factor*0.04f;
+ m_object->SetAngleX(0, angle*dir.z);
+ m_object->SetAngleZ(0, angle*dir.x);
+
+ zoom = 1.0f+sinf(m_time*8.0f)*factor*0.06f;
+ m_object->SetZoomX(0, zoom);
+ zoom = 1.0f+sinf(m_time*5.0f)*factor*0.06f;
+ m_object->SetZoomY(0, zoom);
+ zoom = 1.0f+sinf(m_time*7.0f)*factor*0.06f;
+ m_object->SetZoomZ(0, zoom);
+ }
+ else
+ {
+ m_object->SetAngleX(0, 0.0f);
+ m_object->SetAngleZ(0, 0.0f);
+ m_object->SetZoom(0, D3DVECTOR(1.0f, 1.0f, 1.0f));
+ m_error = ERR_STOP;
+ }
+
+ return TRUE;
+}
+
+
+// Indique si l'automate a terminé son activité.
+
+Error CAutoJostle::IsEnded()
+{
+ return m_error;
+}
+
+
diff --git a/src/autojostle.h b/src/autojostle.h
new file mode 100644
index 0000000..3527c93
--- /dev/null
+++ b/src/autojostle.h
@@ -0,0 +1,40 @@
+// autojostle.h
+
+#ifndef _AUTOJOSTLE_H_
+#define _AUTOJOSTLE_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+class CAutoJostle : public CAuto
+{
+public:
+ CAutoJostle(CInstanceManager* iMan, CObject* object);
+ ~CAutoJostle();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param, float force);
+ BOOL EventProcess(const Event &event);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_force;
+ float m_progress;
+ float m_speed;
+ float m_lastParticule;
+ Error m_error;
+};
+
+
+#endif //_AUTOJOSTLE_H_
diff --git a/src/autokid.cpp b/src/autokid.cpp
new file mode 100644
index 0000000..4685319
--- /dev/null
+++ b/src/autokid.cpp
@@ -0,0 +1,208 @@
+// autokid.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "camera.h"
+#include "object.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autokid.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoKid::CAutoKid(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ m_soundChannel = -1;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoKid::~CAutoKid()
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoKid::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoKid::Init()
+{
+ D3DVECTOR pos;
+
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ m_lastParticule = 0.0f;
+
+ if ( m_type == OBJECT_TEEN36 ) // tronc ?
+ {
+ pos = m_object->RetPosition(0);
+ m_speed = 1.0f/(1.0f+(Mod(pos.x/10.0f-0.5f, 1.0f)*0.2f));
+ m_progress = Mod(pos.x/10.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_TEEN37 ) // bateau ?
+ {
+ pos = m_object->RetPosition(0);
+ m_speed = 1.0f/(1.0f+(Mod(pos.x/10.0f-0.5f, 1.0f)*0.2f))*2.5f;
+ m_progress = Mod(pos.x/10.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_TEEN38 ) // ventillateur ?
+ {
+ if ( m_soundChannel == -1 )
+ {
+//? m_soundChannel = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 1.0f, 0.5f, TRUE);
+ m_bSilent = FALSE;
+ }
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoKid::EventProcess(const Event &event)
+{
+ D3DVECTOR vib, pos, speed;
+ FPOINT dim;
+
+ CAuto::EventProcess(event);
+
+ if ( m_soundChannel != -1 )
+ {
+ if ( m_engine->RetPause() )
+ {
+ if ( !m_bSilent )
+ {
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.1f, SOPER_CONTINUE);
+ m_bSilent = TRUE;
+ }
+ }
+ else
+ {
+ if ( m_bSilent )
+ {
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.5f, 0.1f, SOPER_CONTINUE);
+ m_bSilent = FALSE;
+ }
+ }
+ }
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_type == OBJECT_TEEN36 ) // tronc ?
+ {
+ vib.x = 0.0f;
+ vib.y = sinf(m_progress)*1.0f;
+ vib.z = 0.0f;
+ m_object->SetLinVibration(vib);
+
+ vib.x = 0.0f;
+ vib.y = 0.0f;
+ vib.z = sinf(m_progress*0.5f)*0.05f;
+ m_object->SetCirVibration(vib);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.15f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y = m_water->RetLevel()+1.0f;
+ pos.x += (Rand()-0.5f)*50.0f;
+ pos.z += (Rand()-0.5f)*50.0f;
+ speed.y = 0.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = 50.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLIC, 3.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_type == OBJECT_TEEN37 ) // bateau ?
+ {
+ vib.x = 0.0f;
+ vib.y = sinf(m_progress)*1.0f;
+ vib.z = 0.0f;
+ m_object->SetLinVibration(vib);
+
+ vib.x = 0.0f;
+ vib.y = 0.0f;
+ vib.z = sinf(m_progress*0.5f)*0.15f;
+ m_object->SetCirVibration(vib);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.15f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y = m_water->RetLevel()+1.0f;
+ pos.x += (Rand()-0.5f)*20.0f;
+ pos.z += (Rand()-0.5f)*20.0f;
+ speed.y = 0.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = 20.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLIC, 3.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_type == OBJECT_TEEN38 ) // ventillateur ?
+ {
+ m_object->SetAngleY(1, sinf(m_progress*0.6f)*0.4f);
+ m_object->SetAngleX(2, m_progress*5.0f);
+ }
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoKid::RetError()
+{
+ return ERR_OK;
+}
+
+
diff --git a/src/autokid.h b/src/autokid.h
new file mode 100644
index 0000000..a51effd
--- /dev/null
+++ b/src/autokid.h
@@ -0,0 +1,41 @@
+// autokid.h
+
+#ifndef _AUTOKID_H_
+#define _AUTOKID_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+class CAutoKid : public CAuto
+{
+public:
+ CAutoKid(CInstanceManager* iMan, CObject* object);
+ ~CAutoKid();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+protected:
+
+protected:
+ float m_speed;
+ float m_progress;
+ float m_lastParticule;
+ int m_soundChannel;
+ BOOL m_bSilent;
+};
+
+
+#endif //_AUTOKID_H_
diff --git a/src/autolabo.cpp b/src/autolabo.cpp
new file mode 100644
index 0000000..8fc3da2
--- /dev/null
+++ b/src/autolabo.cpp
@@ -0,0 +1,615 @@
+// autolabo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "displaytext.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autolabo.h"
+
+
+
+#define LABO_DELAY 20.0f // durée de l'analyse
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoLabo::CAutoLabo(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ int i;
+
+ CAuto::CAuto(iMan, object);
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_partiRank[i] = -1;
+ }
+ m_partiSphere = -1;
+
+ m_soundChannel = -1;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoLabo::~CAutoLabo()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoLabo::DeleteObject(BOOL bAll)
+{
+ int i;
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ if ( m_partiRank[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_partiRank[i]);
+ m_partiRank[i] = -1;
+ }
+ }
+
+ if ( m_partiSphere != -1 )
+ {
+ m_particule->DeleteParticule(m_partiSphere);
+ m_partiSphere = -1;
+ }
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoLabo::Init()
+{
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_phase = ALAP_WAIT; // attend ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoLabo::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DVECTOR pos, goal, speed;
+ FPOINT dim, rot;
+ float angle;
+ int i;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ if ( event.event == EVENT_UPDINTERFACE )
+ {
+ if ( m_object->RetSelect() ) CreateInterface(TRUE);
+ }
+
+ if ( m_object->RetSelect() && // centre sélectionné ?
+ (event.event == EVENT_OBJECT_RiPAW ||
+ event.event == EVENT_OBJECT_RiGUN) )
+ {
+ if ( m_phase != ALAP_WAIT )
+ {
+ return FALSE;
+ }
+
+ m_research = event.event;
+
+ if ( TestResearch(m_research) )
+ {
+ m_displayText->DisplayError(ERR_LABO_ALREADY, m_object);
+ return FALSE;
+ }
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ m_displayText->DisplayError(ERR_LABO_NULL, m_object);
+ return FALSE;
+ }
+ if ( power->RetType() != OBJECT_BULLET )
+ {
+ m_displayText->DisplayError(ERR_LABO_BAD, m_object);
+ return FALSE;
+ }
+
+ SetBusy(TRUE);
+ InitProgressTotal(1.0f+1.5f+1.5f+LABO_DELAY+1.5f+1.5f+1.0f);
+ UpdateInterface();
+
+ power->SetLock(TRUE); // boulet plus utilisable
+
+ SoundManip(1.0f, 1.0f, 1.0f);
+ m_phase = ALAP_OPEN1;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ return TRUE;
+ }
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ EventProgress(event.rTime);
+
+ if ( m_phase == ALAP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_phase = ALAP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == ALAP_OPEN1 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = 80.0f-(35.0f*m_progress);
+ m_object->SetAngleZ(3, angle*PI/180.0f);
+ m_object->SetAngleZ(4, angle*PI/180.0f);
+ m_object->SetAngleZ(5, angle*PI/180.0f);
+ }
+ else
+ {
+ m_object->SetAngleZ(3, 45.0f*PI/180.0f);
+ m_object->SetAngleZ(4, 45.0f*PI/180.0f);
+ m_object->SetAngleZ(5, 45.0f*PI/180.0f);
+
+ SoundManip(1.5f, 1.0f, 0.7f);
+ m_phase = ALAP_OPEN2;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ALAP_OPEN2 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos.x = -9.0f;
+ pos.y = 3.0f+m_progress*10.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(1, pos);
+ }
+ else
+ {
+ m_object->SetPosition(1, D3DVECTOR(-9.0f, 13.0f, 0.0f));
+
+ SoundManip(1.5f, 1.0f, 0.5f);
+ m_phase = ALAP_OPEN3;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ALAP_OPEN3 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = (1.0f-m_progress)*PI/2.0f;
+ m_object->SetAngleZ(1, angle);
+ }
+ else
+ {
+ m_object->SetAngleZ(1, 0.0f);
+
+ goal = m_object->RetPosition(0);
+ goal.y += 3.0f;
+ pos = goal;
+ pos.x -= 4.0f;
+ pos.y += 4.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_partiRank[i] = m_particule->CreateRay(pos, goal,
+ PARTIRAY2,
+ FPOINT(2.9f, 2.9f),
+ LABO_DELAY);
+ }
+
+ m_soundChannel = m_sound->Play(SOUND_LABO, m_object->RetPosition(0), 0.0f, 0.25f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.60f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 2.00f, 8.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 0.60f, 8.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.25f, 2.0f, SOPER_STOP);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 4.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 4.0f;
+ dim.y = dim.x;
+ m_partiSphere = m_particule->CreateParticule(pos, speed, dim, PARTISPHERE2, LABO_DELAY, 0.0f, 0.0f);
+
+ m_phase = ALAP_ANALYSE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/LABO_DELAY;
+ }
+ }
+
+ if ( m_phase == ALAP_ANALYSE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f-m_progress);
+ }
+
+ angle = m_object->RetAngleY(2);
+ if ( m_progress < 0.5f )
+ {
+ angle -= event.rTime*m_progress*20.0f;
+ }
+ else
+ {
+ angle -= event.rTime*(20.0f-m_progress*20.0f);
+ }
+ m_object->SetAngleY(2, angle); // tourne l'analyseur
+
+ angle += m_object->RetAngleY(0);
+ for ( i=0 ; i<3 ; i++ )
+ {
+ rot = RotatePoint(-angle, -4.0f);
+ pos = m_object->RetPosition(0);
+ pos.x += rot.x;
+ pos.z += rot.y;
+ pos.y += 3.0f+4.0f;;
+ m_particule->SetPosition(m_partiRank[i], pos); // ajuste rayon
+
+ angle += PI*2.0f/3.0f;
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ if ( m_progress > 0.25f &&
+ m_progress < 0.80f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.y += 3.0f;
+ pos.x += (Rand()-0.5f)*2.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+ speed.y = Rand()*5.0f+5.0f;
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ dim.x = Rand()*0.4f*m_progress+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK2,
+ 2.0f+2.0f*m_progress, 10.0f, 1.5f, 1.4f);
+ }
+ }
+ }
+ else
+ {
+ SetResearch(m_research); // recherche effectuée
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ m_object->SetPower(0);
+ power->DeleteObject(); // détruit le boulet
+ delete power;
+ }
+
+ m_displayText->DisplayError(INFO_LABO, m_object);
+
+ SoundManip(1.5f, 1.0f, 0.5f);
+ m_phase = ALAP_CLOSE1;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ALAP_CLOSE1 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = m_progress*PI/2.0f;
+ m_object->SetAngleZ(1, angle);
+ }
+ else
+ {
+ m_object->SetAngleZ(1, PI/2.0f);
+
+ SoundManip(1.5f, 1.0f, 0.7f);
+ m_phase = ALAP_CLOSE2;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ALAP_CLOSE2 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos.x = -9.0f;
+ pos.y = 3.0f+(1.0f-m_progress)*10.0f;;
+ pos.z = 0.0f;
+ m_object->SetPosition(1, pos);
+ }
+ else
+ {
+ m_object->SetPosition(1, D3DVECTOR(-9.0f, 3.0f, 0.0f));
+
+ SoundManip(1.0f, 1.0f, 1.0f);
+ m_phase = ALAP_CLOSE3;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ALAP_CLOSE3 )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = 45.0f+(35.0f*m_progress);
+ m_object->SetAngleZ(3, angle*PI/180.0f);
+ m_object->SetAngleZ(4, angle*PI/180.0f);
+ m_object->SetAngleZ(5, angle*PI/180.0f);
+ }
+ else
+ {
+ m_object->SetAngleZ(3, 80.0f*PI/180.0f);
+ m_object->SetAngleZ(4, 80.0f*PI/180.0f);
+ m_object->SetAngleZ(5, 80.0f*PI/180.0f);
+
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ m_phase = ALAP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoLabo::RetError()
+{
+ CObject* pObj;
+ ObjectType type;
+
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ pObj = m_object->RetPower();
+ if ( pObj == 0 ) return ERR_LABO_NULL;
+ type = pObj->RetType();
+ if ( type != OBJECT_BULLET ) return ERR_LABO_BAD;
+
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoLabo::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ dim.x = 33.0f/640.0f;
+ dim.y = 33.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 64+45, EVENT_OBJECT_RiPAW);
+
+ pos.x = ox+sx*8.0f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 64+46, EVENT_OBJECT_RiGUN);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 111, EVENT_OBJECT_TYPE);
+
+ UpdateInterface();
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CAutoLabo::UpdateInterface()
+{
+ CWindow* pw;
+
+ if ( !m_object->RetSelect() ) return;
+
+ CAuto::UpdateInterface();
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ DeadInterface(pw, EVENT_OBJECT_RiPAW, g_researchEnable&RESEARCH_iPAW);
+ DeadInterface(pw, EVENT_OBJECT_RiGUN, g_researchEnable&RESEARCH_iGUN);
+
+ OkayButton(pw, EVENT_OBJECT_RiPAW);
+ OkayButton(pw, EVENT_OBJECT_RiGUN);
+
+ VisibleInterface(pw, EVENT_OBJECT_RiPAW, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RiGUN, !m_bBusy);
+}
+
+// Indique les recherches déjà effectuées pour un bouton.
+
+void CAutoLabo::OkayButton(CWindow *pw, EventMsg event)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_OKAY, TestResearch(event));
+}
+
+
+// Teste si une recherche a déjà été effectuée.
+
+BOOL CAutoLabo::TestResearch(EventMsg event)
+{
+ if ( event == EVENT_OBJECT_RiPAW ) return (g_researchDone & RESEARCH_iPAW);
+ if ( event == EVENT_OBJECT_RiGUN ) return (g_researchDone & RESEARCH_iGUN);
+
+ return FALSE;
+}
+
+// Indique une recherche comme effectuée.
+
+void CAutoLabo::SetResearch(EventMsg event)
+{
+ Event newEvent;
+
+ if ( event == EVENT_OBJECT_RiPAW ) g_researchDone |= RESEARCH_iPAW;
+ if ( event == EVENT_OBJECT_RiGUN ) g_researchDone |= RESEARCH_iGUN;
+
+ m_main->WriteFreeParam();
+
+ m_event->MakeEvent(newEvent, EVENT_UPDINTERFACE);
+ m_event->AddEvent(newEvent);
+ UpdateInterface();
+}
+
+// Fait entendre le son du bras manipulateur.
+
+void CAutoLabo::SoundManip(float time, float amplitude, float frequency)
+{
+ int i;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f*frequency, TRUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoLabo::Write(char *line)
+{
+ D3DVECTOR pos;
+ char name[100];
+
+ if ( m_phase == ALAP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ sprintf(name, " aResearch=%d", m_research);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoLabo::Read(char *line)
+{
+ D3DVECTOR pos;
+
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoLaboPhase)OpInt(line, "aPhase", ALAP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+ m_research = (EventMsg)OpInt(line, "aResearch", 0);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autolabo.h b/src/autolabo.h
new file mode 100644
index 0000000..71a68bc
--- /dev/null
+++ b/src/autolabo.h
@@ -0,0 +1,67 @@
+// autolabo.h
+
+#ifndef _AUTOLABO_H_
+#define _AUTOLABO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoLaboPhase
+{
+ ALAP_WAIT = 1,
+ ALAP_OPEN1 = 2,
+ ALAP_OPEN2 = 3,
+ ALAP_OPEN3 = 4,
+ ALAP_ANALYSE = 5,
+ ALAP_CLOSE1 = 6,
+ ALAP_CLOSE2 = 7,
+ ALAP_CLOSE3 = 8,
+};
+
+
+
+class CAutoLabo : public CAuto
+{
+public:
+ CAutoLabo(CInstanceManager* iMan, CObject* object);
+ ~CAutoLabo();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void UpdateInterface();
+ void OkayButton(CWindow *pw, EventMsg event);
+ BOOL TestResearch(EventMsg event);
+ void SetResearch(EventMsg event);
+ void SoundManip(float time, float amplitude, float frequency);
+
+protected:
+ AutoLaboPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ EventMsg m_research;
+ int m_partiRank[3];
+ int m_partiSphere;
+ int m_soundChannel;
+};
+
+
+#endif //_AUTOLABO_H_
diff --git a/src/automush.cpp b/src/automush.cpp
new file mode 100644
index 0000000..e9a1a3a
--- /dev/null
+++ b/src/automush.cpp
@@ -0,0 +1,348 @@
+// automush.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "cmdtoken.h"
+#include "sound.h"
+#include "auto.h"
+#include "automush.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoMush::CAutoMush(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoMush::~CAutoMush()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoMush::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoMush::Init()
+{
+ m_phase = AMP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/4.0f;
+
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoMush::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed, dir;
+ FPOINT dim;
+ float factor, zoom, size, angle;
+ int i, channel;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ factor = 0.0f;
+ size = 1.0f;
+
+ if ( m_phase == AMP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ if ( !SearchTarget() )
+ {
+ m_phase = AMP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(2.0f+Rand()*2.0f);
+ }
+ else
+ {
+ m_phase = AMP_SNIF;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+ }
+
+ if ( m_phase == AMP_SNIF )
+ {
+ if ( m_progress < 1.0f )
+ {
+ factor = m_progress;
+ }
+ else
+ {
+ m_phase = AMP_ZOOM;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == AMP_ZOOM )
+ {
+ if ( m_progress < 1.0f )
+ {
+ factor = 1.0f;
+ size = 1.0f+m_progress*0.3f;
+ }
+ else
+ {
+ m_sound->Play(SOUND_MUSHROOM, m_object->RetPosition(0));
+
+ m_phase = AMP_FIRE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == AMP_FIRE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ factor = 1.0f-m_progress;
+ size = 1.0f+(1.0f-m_progress)*0.3f;
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.y += 5.0f;
+ speed.x = (Rand()-0.5f)*200.0f;
+ speed.z = (Rand()-0.5f)*200.0f;
+ speed.y = -(20.0f+Rand()*20.0f);
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN2, 2.0f, 100.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+ }
+ }
+ else
+ {
+ m_phase = AMP_SMOKE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == AMP_SMOKE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y += 5.0f;
+ speed.x = (Rand()-0.5f)*4.0f;
+ speed.z = (Rand()-0.5f)*4.0f;
+ speed.y = -(0.5f+Rand()*0.5f);
+ dim.x = Rand()*2.5f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ m_phase = AMP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(2.0f+Rand()*2.0f);
+ }
+ }
+
+ if ( factor != 0.0f || size != 1.0f )
+ {
+ dir.x = sinf(m_time*PI*4.0f);
+ dir.z = cosf(m_time*PI*4.0f);
+
+ angle = sinf(m_time*10.0f)*factor*0.04f;
+ m_object->SetAngleX(0, angle*dir.z);
+ m_object->SetAngleZ(0, angle*dir.x);
+
+ zoom = 1.0f+sinf(m_time*8.0f)*factor*0.06f;
+ m_object->SetZoomX(0, zoom*size);
+ zoom = 1.0f+sinf(m_time*5.0f)*factor*0.06f;
+ m_object->SetZoomY(0, zoom*size);
+ zoom = 1.0f+sinf(m_time*7.0f)*factor*0.06f;
+ m_object->SetZoomZ(0, zoom*size);
+ }
+ else
+ {
+ m_object->SetAngleX(0, 0.0f);
+ m_object->SetAngleZ(0, 0.0f);
+ m_object->SetZoom(0, D3DVECTOR(1.0f, 1.0f, 1.0f));
+ }
+
+ return TRUE;
+}
+
+
+// Cherche une cible proche.
+
+BOOL CAutoMush::SearchTarget()
+{
+ CObject* pObj;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float dist;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetLock() ) continue;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_DERRICK &&
+ type != OBJECT_STATION &&
+ type != OBJECT_FACTORY &&
+ type != OBJECT_REPAIR &&
+ type != OBJECT_DESTROYER&&
+ 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_HUMAN ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, iPos);
+ if ( dist < 50.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoMush::RetError()
+{
+ return ERR_OK;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoMush::Write(char *line)
+{
+ D3DVECTOR pos;
+ char name[100];
+
+ if ( m_phase == AMP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoMush::Read(char *line)
+{
+ D3DVECTOR pos;
+
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoMushPhase)OpInt(line, "aPhase", AMP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/automush.h b/src/automush.h
new file mode 100644
index 0000000..03f2d28
--- /dev/null
+++ b/src/automush.h
@@ -0,0 +1,55 @@
+// automush.h
+
+#ifndef _AUTOMUSH_H_
+#define _AUTOMUSH_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+enum AutoMushPhase
+{
+ AMP_WAIT = 1,
+ AMP_SNIF = 2,
+ AMP_ZOOM = 3,
+ AMP_FIRE = 4,
+ AMP_SMOKE = 5,
+};
+
+
+
+class CAutoMush : public CAuto
+{
+public:
+ CAutoMush(CInstanceManager* iMan, CObject* object);
+ ~CAutoMush();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ BOOL SearchTarget();
+
+protected:
+ AutoMushPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_lastParticule;
+};
+
+
+#endif //_AUTOMUSH_H_
diff --git a/src/autonest.cpp b/src/autonest.cpp
new file mode 100644
index 0000000..1885ce8
--- /dev/null
+++ b/src/autonest.cpp
@@ -0,0 +1,277 @@
+// autonest.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autonest.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoNest::CAutoNest(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoNest::~CAutoNest()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoNest::DeleteObject(BOOL bAll)
+{
+ CObject* fret;
+
+ if ( !bAll )
+ {
+ fret = SearchFret();
+ if ( fret != 0 )
+ {
+ fret->DeleteObject();
+ delete fret;
+ }
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoNest::Init()
+{
+ D3DVECTOR pos;
+
+ m_phase = ANP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/4.0f;
+
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ pos = m_object->RetPosition(0);
+ m_terrain->MoveOnFloor(pos);
+ m_fretPos = pos;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoNest::EventProcess(const Event &event)
+{
+ CObject* fret;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == ANP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ if ( !SearchFree(m_fretPos) )
+ {
+ m_phase = ANP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/4.0f;
+ }
+ else
+ {
+ CreateFret(m_fretPos, 0.0f, OBJECT_BULLET);
+ m_phase = ANP_BIRTH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+ }
+ }
+
+ if ( m_phase == ANP_BIRTH )
+ {
+ fret = SearchFret();
+
+ if ( m_progress < 1.0f )
+ {
+ if ( fret != 0 )
+ {
+ fret->SetZoom(0, m_progress);
+ }
+ }
+ else
+ {
+ if ( fret != 0 )
+ {
+ fret->SetZoom(0, 1.0f);
+ fret->SetLock(FALSE);
+ }
+
+ m_phase = ANP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/5.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Cherche si un emplacement est libre.
+
+BOOL CAutoNest::SearchFree(D3DVECTOR pos)
+{
+ CObject* pObj;
+ D3DVECTOR sPos;
+ ObjectType type;
+ float sRadius, distance;
+ int i, j;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_NEST ) continue;
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, sPos, sRadius) )
+ {
+ distance = Length(sPos, pos);
+ distance -= sRadius;
+ if ( distance < 2.0f ) return FALSE; // emplacement occupé
+ }
+ }
+
+ return TRUE; // emplacement libre
+}
+
+// Crée un objet transportable.
+
+void CAutoNest::CreateFret(D3DVECTOR pos, float angle, ObjectType type)
+{
+ CObject* fret;
+
+ fret = new CObject(m_iMan);
+ if ( !fret->CreateResource(pos, angle, type) )
+ {
+ delete fret;
+ return;
+ }
+ fret->SetLock(TRUE); // pas utilisable
+ fret->SetZoom(0, 0.0f);
+}
+
+// Cherche le boullet en cours de fabrication.
+
+CObject* CAutoNest::SearchFret()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetLock() ) continue;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_BULLET ) continue;
+
+ oPos = pObj->RetPosition(0);
+ if ( oPos.x == m_fretPos.x &&
+ oPos.z == m_fretPos.z )
+ {
+ return pObj;
+ }
+ }
+
+ return 0;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoNest::RetError()
+{
+ return ERR_OK;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoNest::Write(char *line)
+{
+ D3DVECTOR pos;
+ char name[100];
+
+ if ( m_phase == ANP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoNest::Read(char *line)
+{
+ D3DVECTOR pos;
+
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoNestPhase)OpInt(line, "aPhase", ANP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autonest.h b/src/autonest.h
new file mode 100644
index 0000000..50a3687
--- /dev/null
+++ b/src/autonest.h
@@ -0,0 +1,55 @@
+// autonest.h
+
+#ifndef _AUTONEST_H_
+#define _AUTONEST_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+enum AutoNestPhase
+{
+ ANP_WAIT = 1,
+ ANP_BIRTH = 2, // apparition d'un boulet
+};
+
+
+
+class CAutoNest : public CAuto
+{
+public:
+ CAutoNest(CInstanceManager* iMan, CObject* object);
+ ~CAutoNest();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ BOOL SearchFree(D3DVECTOR pos);
+ void CreateFret(D3DVECTOR pos, float angle, ObjectType type);
+ CObject* SearchFret();
+
+protected:
+ AutoNestPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_lastParticule;
+ D3DVECTOR m_fretPos;
+};
+
+
+#endif //_AUTONEST_H_
diff --git a/src/autonuclear.cpp b/src/autonuclear.cpp
new file mode 100644
index 0000000..b33dd4c
--- /dev/null
+++ b/src/autonuclear.cpp
@@ -0,0 +1,490 @@
+// autonuclear.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autonuclear.h"
+
+
+
+#define NUCLEAR_DELAY 30.0f // durée de la génération
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoNuclear::CAutoNuclear(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ m_channelSound = -1;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoNuclear::~CAutoNuclear()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoNuclear::DeleteObject(BOOL bAll)
+{
+ CObject* fret;
+
+ if ( !bAll )
+ {
+ fret = SearchUranium();
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // détruit le métal
+ delete fret;
+ }
+ }
+
+ if ( m_channelSound != -1 )
+ {
+ m_sound->FlushEnvelope(m_channelSound);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_channelSound = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoNuclear::Init()
+{
+ D3DMATRIX* mat;
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ mat = m_object->RetWorldMatrix(0);
+ m_pos = Transform(*mat, D3DVECTOR(22.0f, 4.0f, 0.0f));
+
+ m_phase = ANUP_WAIT; // attend ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoNuclear::EventProcess(const Event &event)
+{
+ CObject* fret;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, goal, speed;
+ FPOINT dim, rot;
+ float angle;
+ int i, max;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ EventProgress(event.rTime);
+
+ if ( m_phase == ANUP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ fret = SearchUranium(); // uranium à transformer ?
+ if ( fret == 0 || SearchVehicle() )
+ {
+ m_phase = ANUP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ else
+ {
+ fret->SetLock(TRUE); // uranium plus utilisable
+
+ SetBusy(TRUE);
+ InitProgressTotal(1.5f+NUCLEAR_DELAY+1.5f);
+ UpdateInterface();
+
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 1.4f);
+
+ m_phase = ANUP_CLOSE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+ }
+
+ if ( m_phase == ANUP_CLOSE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = (1.0f-m_progress)*(135.0f*PI/180.0f);
+ m_object->SetAngleZ(1, angle);
+ }
+ else
+ {
+ m_object->SetAngleZ(1, 0.0f);
+
+ mat = m_object->RetWorldMatrix(0);
+ max = (int)(10.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ pos.x = 27.0f;
+ pos.y = 0.0f;
+ pos.z = (Rand()-0.5f)*8.0f;
+ pos = Transform(*mat, pos);
+ speed.y = 0.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH);
+ }
+
+ m_sound->Play(SOUND_CLOSE, m_object->RetPosition(0), 1.0f, 1.0f);
+
+ m_channelSound = m_sound->Play(SOUND_NUCLEAR, m_object->RetPosition(0), 1.0f, 0.1f, TRUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, NUCLEAR_DELAY-1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 2.0f, SOPER_STOP);
+
+ m_phase = ANUP_GENERATE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/NUCLEAR_DELAY;
+ }
+ }
+
+ if ( m_phase == ANUP_GENERATE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y += 30.0f;
+ pos.x += (Rand()-0.5f)*6.0f;
+ pos.z += (Rand()-0.5f)*6.0f;
+ speed.y = Rand()*15.0f+15.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = Rand()*8.0f+8.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH);
+
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.y = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ fret = SearchUranium();
+ if ( fret != 0 )
+ {
+ fret->DeleteObject(); // détruit l'uranium
+ delete fret;
+ m_object->SetPower(0);
+ }
+
+ CreatePower(); // crée la pile atomique
+
+ max = (int)(20.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.y += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ speed.y = 0.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, Rand()*5.0f+5.0f, 0.0f, 0.0f);
+ }
+
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 1.4f);
+
+ m_phase = ANUP_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ANUP_OPEN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = m_progress*(135.0f*PI/180.0f);
+ m_object->SetAngleZ(1, angle);
+ }
+ else
+ {
+ m_object->SetAngleZ(1, 135.0f*PI/180.0f);
+
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ m_displayText->DisplayError(INFO_NUCLEAR, m_object);
+
+ m_phase = ANUP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoNuclear::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 110, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Cherche l'objet uranium.
+
+CObject* CAutoNuclear::SearchUranium()
+{
+ CObject* pObj;
+
+ pObj = m_object->RetPower();
+ if ( pObj == 0 ) return 0;
+ if ( pObj->RetType() == OBJECT_URANIUM ) return pObj;
+ return 0;
+}
+
+// Cherche si un véhicule est trop proche.
+
+BOOL CAutoNuclear::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, m_pos)-oRadius;
+
+ if ( dist < 10.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Crée un objet pile.
+
+void CAutoNuclear::CreatePower()
+{
+ CObject* power;
+ D3DVECTOR pos;
+ float angle;
+
+ pos = m_object->RetPosition(0);
+ angle = m_object->RetAngleY(0);
+
+ power = new CObject(m_iMan);
+ if ( !power->CreateResource(pos, angle, OBJECT_ATOMIC) )
+ {
+ delete power;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return;
+ }
+
+ power->SetTruck(m_object);
+ power->SetPosition(0, D3DVECTOR(22.0f, 3.0f, 0.0f));
+ m_object->SetPower(power);
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoNuclear::RetError()
+{
+ CObject* pObj;
+ ObjectType type;
+//? TerrainRes res;
+
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+//? res = m_terrain->RetResource(m_object->RetPosition(0));
+//? if ( res != TR_POWER ) return ERR_NUCLEAR_NULL;
+
+//? if ( m_object->RetEnergy() < ENERGY_POWER ) return ERR_NUCLEAR_LOW;
+
+ pObj = m_object->RetPower();
+ if ( pObj == 0 ) return ERR_NUCLEAR_EMPTY;
+ if ( pObj->RetLock() ) return ERR_OK;
+ type = pObj->RetType();
+ if ( type == OBJECT_ATOMIC ) return ERR_OK;
+ if ( type != OBJECT_URANIUM ) return ERR_NUCLEAR_BAD;
+
+ return ERR_OK;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoNuclear::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ANUP_STOP ||
+ m_phase == ANUP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoNuclear::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoNuclearPhase)OpInt(line, "aPhase", ANUP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autonuclear.h b/src/autonuclear.h
new file mode 100644
index 0000000..f58921e
--- /dev/null
+++ b/src/autonuclear.h
@@ -0,0 +1,60 @@
+// autonuclear.h
+
+#ifndef _AUTONUCLEAR_H_
+#define _AUTONUCLEAR_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoNuclearPhase
+{
+ ANUP_STOP = 1,
+ ANUP_WAIT = 2,
+ ANUP_CLOSE = 3,
+ ANUP_GENERATE = 4,
+ ANUP_OPEN = 5,
+};
+
+
+
+class CAutoNuclear : public CAuto
+{
+public:
+ CAutoNuclear(CInstanceManager* iMan, CObject* object);
+ ~CAutoNuclear();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ CObject* SearchUranium();
+ BOOL SearchVehicle();
+ void CreatePower();
+
+protected:
+ AutoNuclearPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ D3DVECTOR m_pos;
+ int m_channelSound;
+};
+
+
+#endif //_AUTONUCLEAR_H_
diff --git a/src/autopara.cpp b/src/autopara.cpp
new file mode 100644
index 0000000..15177af
--- /dev/null
+++ b/src/autopara.cpp
@@ -0,0 +1,333 @@
+// autopara.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autopara.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoPara::CAutoPara(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ m_channelSound = -1;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoPara::~CAutoPara()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoPara::DeleteObject(BOOL bAll)
+{
+ if ( m_channelSound != -1 )
+ {
+ m_sound->FlushEnvelope(m_channelSound);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_channelSound = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoPara::Init()
+{
+ D3DMATRIX* mat;
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ mat = m_object->RetWorldMatrix(0);
+ m_pos = Transform(*mat, D3DVECTOR(22.0f, 4.0f, 0.0f));
+
+ m_phase = APAP_WAIT; // attend ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ CAuto::Init();
+}
+
+
+// Réception de l'éclair.
+
+void CAutoPara::StartBlitz()
+{
+ m_phase = APAP_BLITZ;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoPara::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ EventProgress(event.rTime);
+
+ if ( m_phase == APAP_BLITZ )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*m_progress*40.0f;
+ pos.z += (Rand()-0.5f)*m_progress*40.0f;
+ pos.y += 50.0f-m_progress*50.0f;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 1.0f, 20.0f, 0.5f);
+ }
+ }
+ }
+ else
+ {
+ m_phase = APAP_CHARGE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_phase == APAP_CHARGE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<2 ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.y += 16.0f;
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = -Rand()*30.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 1.0f, 0.0f, 0.0f);
+ }
+ }
+
+ ChargeObject(event.rTime);
+ }
+ else
+ {
+ m_phase = APAP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoPara::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 113, EVENT_OBJECT_TYPE);
+
+ pos.x = ox+sx*10.2f;
+ pos.y = oy+sy*0.5f;
+ ddim.x = 33.0f/640.0f;
+ ddim.y = 33.0f/480.0f;
+ pw->CreateButton(pos, ddim, 41, EVENT_OBJECT_LIMIT);
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoPara::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+ return ERR_OK;
+}
+
+
+// Charge tous les objets placés sous le paratonnerre.
+
+void CAutoPara::ChargeObject(float rTime)
+{
+ CObject* pObj;
+ CObject* power;
+ D3DVECTOR sPos, oPos;
+ float dist, energy;
+ int i;
+
+ sPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, sPos);
+ if ( dist > 20.0f ) continue;
+
+ if ( pObj->RetTruck() == 0 && pObj->RetType() == OBJECT_POWER )
+ {
+ energy = pObj->RetEnergy();
+ energy += rTime/2.0f;
+ if ( energy > 1.0f ) energy = 1.0f;
+ pObj->SetEnergy(energy);
+ }
+
+ power = pObj->RetPower();
+ if ( power != 0 && power->RetType() == OBJECT_POWER )
+ {
+ energy = power->RetEnergy();
+ energy += rTime/2.0f;
+ if ( energy > 1.0f ) energy = 1.0f;
+ power->SetEnergy(energy);
+ }
+
+ power = pObj->RetFret();
+ if ( power != 0 && power->RetType() == OBJECT_POWER )
+ {
+ energy = power->RetEnergy();
+ energy += rTime/2.0f;
+ if ( energy > 1.0f ) energy = 1.0f;
+ power->SetEnergy(energy);
+ }
+ }
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoPara::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == APAP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoPara::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoParaPhase)OpInt(line, "aPhase", APAP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autopara.h b/src/autopara.h
new file mode 100644
index 0000000..691c508
--- /dev/null
+++ b/src/autopara.h
@@ -0,0 +1,57 @@
+// autopara.h
+
+#ifndef _AUTOPARA_H_
+#define _AUTOPARA_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoParaPhase
+{
+ APAP_WAIT = 1,
+ APAP_BLITZ = 2,
+ APAP_CHARGE = 3,
+};
+
+
+
+class CAutoPara : public CAuto
+{
+public:
+ CAutoPara(CInstanceManager* iMan, CObject* object);
+ ~CAutoPara();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+ void StartBlitz();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void ChargeObject(float rTime);
+
+protected:
+ AutoParaPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ D3DVECTOR m_pos;
+ int m_channelSound;
+};
+
+
+#endif //_AUTOPARA_H_
diff --git a/src/autoportico.cpp b/src/autoportico.cpp
new file mode 100644
index 0000000..12dcbca
--- /dev/null
+++ b/src/autoportico.cpp
@@ -0,0 +1,432 @@
+// autoportico.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "displaytext.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "auto.h"
+#include "autoportico.h"
+
+
+
+#define PARAM_DEPOSE 2 // run=2 -> dépose le vaisseau
+
+#define PORTICO_POSa 75.0f
+#define PORTICO_POSb 65.0f
+#define PORTICO_ANGLE1a ( 25.0f*PI/180.0f)
+#define PORTICO_ANGLE1b ( 70.0f*PI/180.0f)
+#define PORTICO_ANGLE2a (-37.5f*PI/180.0f)
+#define PORTICO_ANGLE2b (-62.5f*PI/180.0f)
+#define PORTICO_ANGLE3a (-77.5f*PI/180.0f)
+#define PORTICO_ANGLE3b (-30.0f*PI/180.0f)
+
+#define PORTICO_TIME_MOVE 16.0f
+#define PORTICO_TIME_DOWN 4.0f
+#define PORTICO_TIME_OPEN 12.0f
+
+
+
+
+// Si progress=0, return a.
+// Si progress=1, return b.
+
+float Progress(float a, float b, float progress)
+{
+ return a+(b-a)*progress;
+}
+
+
+
+// Constructeur de l'objet.
+
+CAutoPortico::CAutoPortico(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_phase = APOP_WAIT;
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CAutoPortico::~CAutoPortico()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoPortico::DeleteObject(BOOL bAll)
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoPortico::Init()
+{
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_posTrack = 0.0f;
+
+ m_phase = APOP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ m_cameraProgress = 0.0f;
+ m_cameraSpeed = 1.0f/(PORTICO_TIME_MOVE-2.0f);
+}
+
+
+// Démarre l'objet.
+
+void CAutoPortico::Start(int param)
+{
+ D3DVECTOR pos;
+
+ pos = m_object->RetPosition(0);
+ m_finalPos = pos;
+ pos.z += PORTICO_TIME_MOVE*5.0f; // recule au départ
+ m_object->SetPosition(0, pos);
+ m_finalPos.z += PORTICO_TIME_OPEN*5.3f;
+
+ m_object->SetPosition(1, D3DVECTOR(0.0f, PORTICO_POSa, 0.0f));
+ m_object->SetAngleY(2, PORTICO_ANGLE1a);
+ m_object->SetAngleY(3, PORTICO_ANGLE2a);
+ m_object->SetAngleY(4, PORTICO_ANGLE3a);
+ m_object->SetAngleY(5, -PORTICO_ANGLE1a);
+ m_object->SetAngleY(6, -PORTICO_ANGLE2a);
+ m_object->SetAngleY(7, -PORTICO_ANGLE3a);
+
+ m_phase = APOP_START;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ m_param = param;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoPortico::EventProcess(const Event &event)
+{
+ CObject* pObj;
+ D3DVECTOR pos;
+ float angle;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ if ( m_phase == APOP_START )
+ {
+ if ( m_param == PARAM_DEPOSE ) // dépose le vaisseau ?
+ {
+ m_startPos = m_object->RetPosition(0);
+
+ m_soundChannel = m_sound->Play(SOUND_MOTORr, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.6f, 0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.6f, PORTICO_TIME_MOVE-0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.3f, 0.5f, SOPER_STOP);
+
+ m_phase = APOP_MOVE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/PORTICO_TIME_MOVE;
+
+ m_main->SetMovieLock(TRUE); // bloque tout jusqu'à la fin de l'atterrissage
+
+ m_camera->SetType(CAMERA_SCRIPT);
+
+ pos = m_startPos;
+ pos.x += -100.0f;
+ pos.y += 9.0f;
+ pos.z += -200.0f;
+ m_camera->SetScriptEye(pos);
+
+ pos = m_object->RetPosition(0);
+ pos.x += 0.0f;
+ pos.y += 10.0f;
+ pos.z += -40.0f;
+ m_camera->SetScriptLookat(pos);
+
+ m_camera->FixCamera();
+ }
+ }
+
+ angle = -m_time*1.0f;
+ m_object->SetAngleY(8, angle); // fait tourner le radar droite
+ angle = sinf(m_time*4.0f)*0.3f;
+ m_object->SetAngleX(9, angle);
+
+ angle = -m_time*1.0f+PI/2.3f;
+ m_object->SetAngleY(10, angle); // fait tourner le radar gauche
+ angle = sinf(m_time*4.0f)*0.3f;
+ m_object->SetAngleX(11, angle);
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_phase == APOP_WAIT ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_cameraProgress += event.rTime*m_cameraSpeed;
+
+ if ( m_phase == APOP_MOVE )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.z -= event.rTime*5.0f; // avance
+ m_object->SetPosition(0, pos);
+
+ m_posTrack += event.rTime*0.5f;
+ UpdateTrackMapping(m_posTrack, m_posTrack);
+ }
+ else
+ {
+ m_phase = APOP_WAIT1;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == APOP_WAIT1 )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_soundChannel = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 0.5f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.3f, 0.6f, PORTICO_TIME_DOWN-1.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.3f, 1.0f, SOPER_STOP);
+
+ m_phase = APOP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/PORTICO_TIME_DOWN;
+ }
+ }
+
+ if ( m_phase == APOP_DOWN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos.x = 0.0f;
+ pos.y = Progress(PORTICO_POSa, PORTICO_POSb, m_progress);
+ pos.z = 0.0f;
+ m_object->SetPosition(1, pos);
+ }
+ else
+ {
+ pos.x = 0.0f;
+ pos.y = PORTICO_POSb;
+ pos.z = 0.0f;
+ m_object->SetPosition(1, pos);
+
+ m_phase = APOP_WAIT2;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == APOP_WAIT2 )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_soundChannel = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 1.0f, 0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 1.0f, PORTICO_TIME_OPEN/2.0f-0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.5f, SOPER_STOP);
+
+ m_soundChannel = m_sound->Play(SOUND_MOTORr, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.6f, 0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.6f, PORTICO_TIME_OPEN-0.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.3f, 0.5f, SOPER_STOP);
+
+ m_phase = APOP_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/PORTICO_TIME_OPEN;
+ }
+ }
+
+ if ( m_phase == APOP_OPEN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.z += event.rTime*5.3f; // recule
+ m_object->SetPosition(0, pos);
+
+ m_posTrack -= event.rTime*1.0f;
+ UpdateTrackMapping(m_posTrack, m_posTrack);
+
+ if ( m_progress < 0.5f )
+ {
+ angle = Progress(PORTICO_ANGLE1a, PORTICO_ANGLE1b, m_progress/0.5f);
+ m_object->SetAngleY(2, angle);
+ m_object->SetAngleY(5, -angle);
+ angle = Progress(PORTICO_ANGLE2a, PORTICO_ANGLE2b, m_progress/0.5f);
+ m_object->SetAngleY(3, angle);
+ m_object->SetAngleY(6, -angle);
+ angle = Progress(PORTICO_ANGLE3a, PORTICO_ANGLE3b, m_progress/0.5f);
+ m_object->SetAngleY(4, angle);
+ m_object->SetAngleY(7, -angle);
+ }
+ else
+ {
+ m_object->SetAngleY(2, PORTICO_ANGLE1b);
+ m_object->SetAngleY(3, PORTICO_ANGLE2b);
+ m_object->SetAngleY(4, PORTICO_ANGLE3b);
+ m_object->SetAngleY(5, -PORTICO_ANGLE1b);
+ m_object->SetAngleY(6, -PORTICO_ANGLE2b);
+ m_object->SetAngleY(7, -PORTICO_ANGLE3b);
+ }
+ }
+ else
+ {
+ m_main->SetMovieLock(FALSE); // on peut jouer !
+
+ pObj = m_main->SearchHuman();
+ m_main->SelectObject(pObj);
+ m_camera->SetObject(pObj);
+ m_camera->SetType(CAMERA_BACK);
+
+ m_phase = APOP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+ }
+ }
+
+ if ( m_soundChannel != -1 )
+ {
+//? m_sound->Position(m_soundChannel, m_object->RetPosition(0));
+ pos = m_engine->RetEyePt();
+ m_sound->Position(m_soundChannel, pos);
+ }
+
+ if ( m_cameraProgress < 1.0f )
+ {
+ if ( m_cameraProgress < 0.5f )
+ {
+ }
+ else
+ {
+ pos = m_startPos;
+ pos.x += -100.0f-(m_cameraProgress-0.5f)*1.0f*120.0f;
+ pos.y += 9.0f;
+ pos.z += -200.0f+(m_cameraProgress-0.5f)*1.0f*210.0f;
+ m_camera->SetScriptEye(pos);
+ }
+
+ pos = m_object->RetPosition(0);
+ pos.x += 0.0f;
+ pos.y += 10.0f;
+ pos.z += -40.0f;
+ m_camera->SetScriptLookat(pos);
+ }
+
+ return TRUE;
+}
+
+// Stoppe l'automate.
+
+BOOL CAutoPortico::Abort()
+{
+ CObject* pObj;
+
+ m_object->SetPosition(0, m_finalPos);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, PORTICO_POSb, 0.0f));
+ m_object->SetAngleY(2, PORTICO_ANGLE1b);
+ m_object->SetAngleY(3, PORTICO_ANGLE2b);
+ m_object->SetAngleY(4, PORTICO_ANGLE3b);
+ m_object->SetAngleY(5, -PORTICO_ANGLE1b);
+ m_object->SetAngleY(6, -PORTICO_ANGLE2b);
+ m_object->SetAngleY(7, -PORTICO_ANGLE3b);
+
+ m_main->SetMovieLock(FALSE); // on peut jouer !
+
+ pObj = m_main->SearchHuman();
+ m_main->SelectObject(pObj);
+ m_camera->SetObject(pObj);
+ m_camera->SetType(CAMERA_BACK);
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_phase = APOP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/2.0f;
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoPortico::RetError()
+{
+ return ERR_OK;
+}
+
+
+// Met à jour le mapping de la texture des chenilles.
+
+void CAutoPortico::UpdateTrackMapping(float left, float right)
+{
+ D3DMATERIAL7 mat;
+ float limit[2];
+ int rank;
+
+ ZeroMemory( &mat, sizeof(D3DMATERIAL7) );
+ mat.diffuse.r = 1.0f;
+ mat.diffuse.g = 1.0f;
+ mat.diffuse.b = 1.0f; // blanc
+ mat.ambient.r = 0.5f;
+ mat.ambient.g = 0.5f;
+ mat.ambient.b = 0.5f;
+
+ rank = m_object->RetObjectRank(0);
+
+ limit[0] = 0.0f;
+ limit[1] = 1000000.0f;
+
+ m_engine->TrackTextureMapping(rank, mat, D3DSTATEPART1, "lemt.tga", "",
+ limit[0], limit[1], D3DMAPPINGX,
+ right, 8.0f, 8.0f, 192.0f, 256.0f);
+
+ m_engine->TrackTextureMapping(rank, mat, D3DSTATEPART2, "lemt.tga", "",
+ limit[0], limit[1], D3DMAPPINGX,
+ left, 8.0f, 8.0f, 192.0f, 256.0f);
+}
+
diff --git a/src/autoportico.h b/src/autoportico.h
new file mode 100644
index 0000000..611a4b2
--- /dev/null
+++ b/src/autoportico.h
@@ -0,0 +1,61 @@
+// autoportico.h
+
+#ifndef _AUTOPORTICO_H_
+#define _AUTOPORTICO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoPorticoPhase
+{
+ APOP_WAIT = 1, // attend
+ APOP_START = 2, // départ de l'action
+ APOP_MOVE = 3, // avance
+ APOP_WAIT1 = 4, // attend
+ APOP_DOWN = 5, // descend
+ APOP_WAIT2 = 6, // attend
+ APOP_OPEN = 7, // ouvre
+};
+
+
+
+class CAutoPortico : public CAuto
+{
+public:
+ CAutoPortico(CInstanceManager* iMan, CObject* object);
+ ~CAutoPortico();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ void Start(int param);
+ BOOL EventProcess(const Event &event);
+ BOOL Abort();
+ Error RetError();
+
+protected:
+ void UpdateTrackMapping(float left, float right);
+
+protected:
+ AutoPorticoPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_cameraProgress;
+ float m_cameraSpeed;
+ float m_lastParticule;
+ D3DVECTOR m_finalPos;
+ D3DVECTOR m_startPos;
+ float m_posTrack;
+ int m_param;
+ int m_soundChannel;
+};
+
+
+#endif //_AUTOPORTICO_H_
diff --git a/src/autoradar.cpp b/src/autoradar.cpp
new file mode 100644
index 0000000..3c10e59
--- /dev/null
+++ b/src/autoradar.cpp
@@ -0,0 +1,312 @@
+// autoradar.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "gauge.h"
+#include "sound.h"
+#include "auto.h"
+#include "autoradar.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoRadar::CAutoRadar(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_phase = ARAP_WAIT;
+ m_totalDetect = 0;
+}
+
+// Destructeur de l'objet.
+
+CAutoRadar::~CAutoRadar()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoRadar::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoRadar::Init()
+{
+ m_phase = ARAP_SEARCH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+
+ m_aTime = 0.0f;
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoRadar::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, ePos;
+ float speed, angle, prog, freq, ampl;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_phase == ARAP_WAIT ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_aTime += event.rTime;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ angle = m_object->RetAngleY(1);
+ angle += (Rand()-0.2f)*0.5f;
+ m_object->SetAngleY(1, angle);
+
+ angle = m_object->RetAngleY(2);
+ angle += (Rand()-0.8f)*1.0f;
+ m_object->SetAngleY(2, angle);
+
+ m_object->SetAngleX(3, (Rand()-0.5f)*0.3f);
+
+ m_totalDetect = (int)(Rand()*10.0f);
+ UpdateInterface();
+ }
+ return TRUE;
+ }
+
+ if ( m_phase == ARAP_SEARCH )
+ {
+ if ( m_progress < 1.0f )
+ {
+ speed = Min(10.0f, m_progress*50.0f);
+ angle = m_object->RetAngleY(1);
+ angle += event.rTime*speed;
+ m_object->SetAngleY(1, angle);
+ }
+ else
+ {
+ if ( !SearchEnemy(ePos) )
+ {
+ m_phase = ARAP_SEARCH;
+ m_progress = 10.0f/50.0f; // plein régime tout de suite
+ m_speed = 1.0f/3.0f;
+ }
+ else
+ {
+ pos = m_object->RetPosition(0);
+ m_start = m_object->RetAngleY(1);
+ m_angle = m_start-NormAngle(m_start)+PI*2.0f;
+ m_angle += RotateAngle(pos.x-ePos.x, ePos.z-pos.z);
+ m_angle += PI-m_object->RetAngleY(0);
+
+ m_phase = ARAP_SHOW;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(Abs(m_angle-m_start)/10.0f);
+ }
+ }
+ }
+
+ if ( m_phase == ARAP_SHOW )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = m_start + (m_angle-m_start)*m_progress;
+ m_object->SetAngleY(1, angle);
+ }
+ else
+ {
+ m_sound->Play(SOUND_RADAR, m_object->RetPosition(0));
+
+ m_phase = ARAP_SINUS;
+ m_progress = 0.0f;
+ m_speed = 1.0f/4.0f;
+ m_time = 0.0f;
+ }
+ }
+
+ if ( m_phase == ARAP_SINUS )
+ {
+ if ( m_progress < 1.0f )
+ {
+ prog = Min(1.0f, m_progress*2.0f);
+ freq = 16.0f*(prog+1.0f);
+ ampl = 0.2f-prog*0.2f;
+ angle = m_angle + sinf(m_time*freq)*ampl;
+ m_object->SetAngleY(1, angle);
+ }
+ else
+ {
+ m_phase = ARAP_SEARCH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+
+ angle = -m_aTime*2.0f;
+ m_object->SetAngleY(2, angle);
+
+ angle = sinf(m_aTime*4.0f)*0.3f;
+ m_object->SetAngleX(3, angle);
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoRadar::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoRadar::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*0.6f;
+ dim.x = 160.0f/640.0f;
+ dim.y = 26.0f/480.0f;
+ pw->CreateGauge(pos, dim, 1, EVENT_OBJECT_GRADAR);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 105, EVENT_OBJECT_TYPE);
+
+ UpdateInterface();
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CAutoRadar::UpdateInterface()
+{
+ CWindow* pw;
+ CGauge* pg;
+ float level;
+
+ if ( !m_object->RetSelect() ) return;
+
+ CAuto::UpdateInterface();
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GRADAR);
+ if ( pg != 0 )
+ {
+ level = (float)m_totalDetect*(1.0f/8.0f);
+ if ( level > 1.0f ) level = 1.0f;
+ pg->SetLevel(level);
+ }
+}
+
+
+// Cherche la position d'un ennemi.
+
+BOOL CAutoRadar::SearchEnemy(D3DVECTOR &pos)
+{
+ CObject* pObj;
+ CObject* pBest = 0;
+ D3DVECTOR iPos, oPos;
+ ObjectType oType;
+ float distance, min;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ min = 1000000.0f;
+ m_totalDetect = 0;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+
+ oType = pObj->RetType();
+ if ( oType != OBJECT_ANT &&
+ oType != OBJECT_SPIDER &&
+ oType != OBJECT_BEE &&
+ oType != OBJECT_WORM &&
+ oType != OBJECT_MOTHER ) continue;
+
+ m_totalDetect ++;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ }
+ }
+
+ UpdateInterface();
+
+ if ( pBest == 0 ) return FALSE;
+ pos = pBest->RetPosition(0);
+ return TRUE;
+}
+
+
diff --git a/src/autoradar.h b/src/autoradar.h
new file mode 100644
index 0000000..29c6bf6
--- /dev/null
+++ b/src/autoradar.h
@@ -0,0 +1,56 @@
+// autoradar.h
+
+#ifndef _AUTORADAR_H_
+#define _AUTORADAR_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoRadarPhase
+{
+ ARAP_WAIT = 1, // attend
+ ARAP_SEARCH = 2, // cherche
+ ARAP_SHOW = 3, // montre
+ ARAP_SINUS = 4, // oscille
+};
+
+
+
+class CAutoRadar : public CAuto
+{
+public:
+ CAutoRadar(CInstanceManager* iMan, CObject* object);
+ ~CAutoRadar();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ BOOL CreateInterface(BOOL bSelect);
+ Error RetError();
+
+protected:
+ void UpdateInterface();
+ BOOL SearchEnemy(D3DVECTOR &pos);
+
+protected:
+ AutoRadarPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_aTime;
+ float m_timeVirus;
+ float m_lastParticule;
+ float m_angle;
+ float m_start;
+ int m_totalDetect;
+};
+
+
+#endif //_AUTORADAR_H_
diff --git a/src/autorepair.cpp b/src/autorepair.cpp
new file mode 100644
index 0000000..84335ee
--- /dev/null
+++ b/src/autorepair.cpp
@@ -0,0 +1,348 @@
+// autorepair.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "physics.h"
+#include "sound.h"
+#include "interface.h"
+#include "button.h"
+#include "window.h"
+#include "robotmain.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autorepair.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoRepair::CAutoRepair(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+ m_phase = ARP_WAIT; // en pause jusqu'au premier Init()
+}
+
+// Destructeur de l'objet.
+
+CAutoRepair::~CAutoRepair()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoRepair::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoRepair::Init()
+{
+ m_phase = ARP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoRepair::EventProcess(const Event &event)
+{
+ CObject* vehicule;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle, shield;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ if ( m_phase == ARP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ if ( SearchVehicle() == 0 )
+ {
+ m_phase = ARP_WAIT; // attend encore ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ else
+ {
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 0.8f);
+
+ m_phase = ARP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+ }
+
+ if ( m_phase == ARP_DOWN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = -m_progress*(PI/2.0f)+PI/2.0f;
+ m_object->SetAngleZ(1, angle);
+ }
+ else
+ {
+ m_object->SetAngleZ(1, 0.0f);
+ m_sound->Play(SOUND_REPAIR, m_object->RetPosition(0));
+
+ m_phase = ARP_REPAIR;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ARP_REPAIR )
+ {
+ vehicule = SearchVehicle();
+ if ( m_progress < 1.0f ||
+ (vehicule != 0 && vehicule->RetShield() < 1.0f) )
+ {
+ if ( vehicule != 0 )
+ {
+ shield = vehicule->RetShield();
+ shield += event.rTime*0.2f;
+ if ( shield > 1.0f ) shield = 1.0f;
+ vehicule->SetShield(shield);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ pos.y += 1.0f;
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ else
+ {
+ m_sound->Play(SOUND_OPEN, m_object->RetPosition(0), 1.0f, 0.8f);
+
+ m_phase = ARP_UP;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+
+ if ( m_phase == ARP_UP )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = -(1.0f-m_progress)*(PI/2.0f)+PI/2.0f;
+ m_object->SetAngleZ(1, angle);
+ }
+ else
+ {
+ m_object->SetAngleZ(1, PI/2.0f);
+
+ m_phase = ARP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoRepair::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 106, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Cherche le véhicule placé sur la station.
+
+CObject* CAutoRepair::SearchVehicle()
+{
+ CObject* pObj;
+ CPhysics* physics;
+ D3DVECTOR sPos, oPos;
+ ObjectType type;
+ float dist;
+ int i;
+
+ sPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr ) continue;
+
+ physics = pObj->RetPhysics();
+ if ( physics != 0 && !physics->RetLand() ) continue; // en vol ?
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, sPos);
+ if ( dist <= 5.0f ) return pObj;
+ }
+
+ return 0;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoRepair::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ return ERR_OK;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoRepair::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ARP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoRepair::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoRepairPhase)OpInt(line, "aPhase", ARP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autorepair.h b/src/autorepair.h
new file mode 100644
index 0000000..c29b21f
--- /dev/null
+++ b/src/autorepair.h
@@ -0,0 +1,55 @@
+// autorepair.h
+
+#ifndef _AUTOREPAIR_H_
+#define _AUTOREPAIR_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoRepairPhase
+{
+ ARP_WAIT = 1, // attend métal
+ ARP_DOWN = 2, // descend le couvercle
+ ARP_REPAIR = 3, // construit le véhicule
+ ARP_UP = 4, // remonte le couvercle
+};
+
+
+
+class CAutoRepair : public CAuto
+{
+public:
+ CAutoRepair(CInstanceManager* iMan, CObject* object);
+ ~CAutoRepair();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ CObject* SearchVehicle();
+
+protected:
+ AutoRepairPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+};
+
+
+#endif //_AUTOREPAIR_H_
diff --git a/src/autoresearch.cpp b/src/autoresearch.cpp
new file mode 100644
index 0000000..fcaa29e
--- /dev/null
+++ b/src/autoresearch.cpp
@@ -0,0 +1,613 @@
+// autoresearch.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "gauge.h"
+#include "window.h"
+#include "displaytext.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autoresearch.h"
+
+
+
+#define SEARCH_TIME 30.0f // durée d'une recherche
+
+
+
+// Constructeur de l'objet.
+
+CAutoResearch::CAutoResearch(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ int i;
+
+ CAuto::CAuto(iMan, object);
+
+ for ( i=0 ; i<6 ; i++ )
+ {
+ m_partiStop[i] = -1;
+ }
+ m_channelSound = -1;
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoResearch::~CAutoResearch()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoResearch::DeleteObject(BOOL bAll)
+{
+ if ( m_channelSound != -1 )
+ {
+ m_sound->FlushEnvelope(m_channelSound);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_channelSound = -1;
+ }
+
+ FireStopUpdate(0.0f, FALSE);
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoResearch::Init()
+{
+ m_phase = ALP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastUpdateTime = 0.0f;
+ m_lastParticule = 0.0f;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoResearch::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ Error message;
+ FPOINT dim;
+ float angle, time;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ if ( event.event == EVENT_UPDINTERFACE )
+ {
+ if ( m_object->RetSelect() ) CreateInterface(TRUE);
+ }
+
+ if ( m_object->RetSelect() && // centre sélectionné ?
+ (event.event == EVENT_OBJECT_RTANK ||
+ event.event == EVENT_OBJECT_RFLY ||
+ event.event == EVENT_OBJECT_RTHUMP ||
+ event.event == EVENT_OBJECT_RCANON ||
+ event.event == EVENT_OBJECT_RTOWER ||
+ event.event == EVENT_OBJECT_RPHAZER ||
+ event.event == EVENT_OBJECT_RSHIELD ||
+ event.event == EVENT_OBJECT_RATOMIC ) )
+ {
+ if ( m_phase != ALP_WAIT )
+ {
+ return FALSE;
+ }
+
+ m_research = event.event;
+
+ if ( TestResearch(m_research) )
+ {
+ m_displayText->DisplayError(ERR_RESEARCH_ALREADY, m_object);
+ return FALSE;
+ }
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ m_displayText->DisplayError(ERR_RESEARCH_POWER, m_object);
+ return FALSE;
+ }
+ if ( power->RetCapacity() > 1.0f )
+ {
+ m_displayText->DisplayError(ERR_RESEARCH_TYPE, m_object);
+ return FALSE;
+ }
+ if ( power->RetEnergy() < 1.0f )
+ {
+ m_displayText->DisplayError(ERR_RESEARCH_ENERGY, m_object);
+ return FALSE;
+ }
+
+ time = SEARCH_TIME;
+ if ( event.event == EVENT_OBJECT_RTANK ) time *= 0.3f;
+ if ( event.event == EVENT_OBJECT_RFLY ) time *= 0.3f;
+ if ( event.event == EVENT_OBJECT_RATOMIC ) time *= 2.0f;
+
+ SetBusy(TRUE);
+ InitProgressTotal(time);
+ UpdateInterface();
+
+ m_channelSound = m_sound->Play(SOUND_RESEARCH, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 1.0f, time-4.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 2.0f, SOPER_STOP);
+
+ m_phase = ALP_SEARCH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/time;
+ return TRUE;
+ }
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ UpdateInterface(event.rTime);
+ EventProgress(event.rTime);
+
+ angle = m_time*0.1f;
+ m_object->SetAngleY(1, angle); // tourne l'antenne
+
+ angle = (30.0f+sinf(m_time*0.3f)*20.0f)*PI/180.0f;
+ m_object->SetAngleZ(2, angle); // oriente l'antenne
+
+ if ( m_phase == ALP_WAIT )
+ {
+ FireStopUpdate(m_progress, FALSE); // éteint
+ return TRUE;
+ }
+
+ if ( m_phase == ALP_SEARCH )
+ {
+ FireStopUpdate(m_progress, TRUE); // clignotte
+ if ( m_progress < 1.0f )
+ {
+ power = m_object->RetPower();
+ if ( power == 0 ) // plus de pile ?
+ {
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ m_phase = ALP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ return TRUE;
+ }
+ power->SetEnergy(1.0f-m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*6.0f;
+ pos.z += (Rand()-0.5f)*6.0f;
+ pos.y += 11.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = Rand()*20.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR);
+ }
+ }
+ else
+ {
+ SetResearch(m_research); // recherche effectuée
+ m_displayText->DisplayError(INFO_RESEARCH, m_object);
+
+ message = ERR_OK;
+ if ( m_research == EVENT_OBJECT_RTANK ) message = INFO_RESEARCHTANK;
+ if ( m_research == EVENT_OBJECT_RFLY ) message = INFO_RESEARCHFLY;
+ if ( m_research == EVENT_OBJECT_RTHUMP ) message = INFO_RESEARCHTHUMP;
+ if ( m_research == EVENT_OBJECT_RCANON ) message = INFO_RESEARCHCANON;
+ if ( m_research == EVENT_OBJECT_RTOWER ) message = INFO_RESEARCHTOWER;
+ if ( m_research == EVENT_OBJECT_RPHAZER ) message = INFO_RESEARCHPHAZER;
+ if ( m_research == EVENT_OBJECT_RSHIELD ) message = INFO_RESEARCHSHIELD;
+ if ( m_research == EVENT_OBJECT_RATOMIC ) message = INFO_RESEARCHATOMIC;
+ if ( message != ERR_OK )
+ {
+ m_displayText->DisplayError(message, m_object);
+ }
+
+ SetBusy(FALSE);
+ UpdateInterface();
+
+ m_phase = ALP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoResearch::RetError()
+{
+ CObject* power;
+
+ if ( m_phase == ALP_SEARCH )
+ {
+ return ERR_OK;
+ }
+
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ return ERR_RESEARCH_POWER;
+ }
+ if ( power != 0 && power->RetCapacity() > 1.0f )
+ {
+ return ERR_RESEARCH_TYPE;
+ }
+ if ( power != 0 && power->RetEnergy() < 1.0f )
+ {
+ return ERR_RESEARCH_ENERGY;
+ }
+
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoResearch::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ dim.x = 33.0f/640.0f;
+ dim.y = 33.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, dim, 64+0, EVENT_OBJECT_RTANK);
+
+ pos.x = ox+sx*8.0f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, dim, 64+1, EVENT_OBJECT_RFLY);
+
+ pos.x = ox+sx*9.0f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, dim, 64+3, EVENT_OBJECT_RCANON);
+
+ pos.x = ox+sx*10.0f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, dim, 64+4, EVENT_OBJECT_RTOWER);
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, dim, 64+7, EVENT_OBJECT_RATOMIC);
+
+ pos.x = ox+sx*8.0f;
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, dim, 64+2, EVENT_OBJECT_RTHUMP);
+
+ pos.x = ox+sx*9.0f;
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, dim, 64+6, EVENT_OBJECT_RSHIELD);
+
+ pos.x = ox+sx*10.0f;
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, dim, 64+5, EVENT_OBJECT_RPHAZER);
+
+ pos.x = ox+sx*14.5f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 0, EVENT_OBJECT_GENERGY);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 102, EVENT_OBJECT_TYPE);
+
+ UpdateInterface();
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CAutoResearch::UpdateInterface()
+{
+ CWindow* pw;
+
+ if ( !m_object->RetSelect() ) return;
+
+ CAuto::UpdateInterface();
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ DeadInterface(pw, EVENT_OBJECT_RTANK, g_researchEnable&RESEARCH_TANK);
+ DeadInterface(pw, EVENT_OBJECT_RFLY, g_researchEnable&RESEARCH_FLY);
+ DeadInterface(pw, EVENT_OBJECT_RTHUMP, g_researchEnable&RESEARCH_THUMP);
+ DeadInterface(pw, EVENT_OBJECT_RCANON, g_researchEnable&RESEARCH_CANON);
+ DeadInterface(pw, EVENT_OBJECT_RTOWER, g_researchEnable&RESEARCH_TOWER);
+ DeadInterface(pw, EVENT_OBJECT_RPHAZER, g_researchEnable&RESEARCH_PHAZER);
+ DeadInterface(pw, EVENT_OBJECT_RSHIELD, g_researchEnable&RESEARCH_SHIELD);
+ DeadInterface(pw, EVENT_OBJECT_RATOMIC, g_researchEnable&RESEARCH_ATOMIC);
+
+ OkayButton(pw, EVENT_OBJECT_RTANK);
+ OkayButton(pw, EVENT_OBJECT_RFLY);
+ OkayButton(pw, EVENT_OBJECT_RTHUMP);
+ OkayButton(pw, EVENT_OBJECT_RCANON);
+ OkayButton(pw, EVENT_OBJECT_RTOWER);
+ OkayButton(pw, EVENT_OBJECT_RPHAZER);
+ OkayButton(pw, EVENT_OBJECT_RSHIELD);
+ OkayButton(pw, EVENT_OBJECT_RATOMIC);
+
+ VisibleInterface(pw, EVENT_OBJECT_RTANK, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RFLY, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RTHUMP, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RCANON, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RTOWER, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RPHAZER, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RSHIELD, !m_bBusy);
+ VisibleInterface(pw, EVENT_OBJECT_RATOMIC, !m_bBusy);
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CAutoResearch::UpdateInterface(float rTime)
+{
+ CWindow* pw;
+ CGauge* pg;
+ CObject* power;
+ float energy;
+
+ CAuto::UpdateInterface(rTime);
+
+ if ( m_time < m_lastUpdateTime+0.1f ) return;
+ m_lastUpdateTime = m_time;
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GENERGY);
+ if ( pg != 0 )
+ {
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+ pg->SetLevel(energy);
+ }
+}
+
+// Indique les recherches déjà effectuées pour un bouton.
+
+void CAutoResearch::OkayButton(CWindow *pw, EventMsg event)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_OKAY, TestResearch(event));
+}
+
+
+// Teste si une recherche a déjà été effectuée.
+
+BOOL CAutoResearch::TestResearch(EventMsg event)
+{
+ if ( event == EVENT_OBJECT_RTANK ) return (g_researchDone & RESEARCH_TANK );
+ if ( event == EVENT_OBJECT_RFLY ) return (g_researchDone & RESEARCH_FLY );
+ if ( event == EVENT_OBJECT_RTHUMP ) return (g_researchDone & RESEARCH_THUMP );
+ if ( event == EVENT_OBJECT_RCANON ) return (g_researchDone & RESEARCH_CANON );
+ if ( event == EVENT_OBJECT_RTOWER ) return (g_researchDone & RESEARCH_TOWER );
+ if ( event == EVENT_OBJECT_RPHAZER ) return (g_researchDone & RESEARCH_PHAZER );
+ if ( event == EVENT_OBJECT_RSHIELD ) return (g_researchDone & RESEARCH_SHIELD);
+ if ( event == EVENT_OBJECT_RATOMIC ) return (g_researchDone & RESEARCH_ATOMIC);
+
+ return FALSE;
+}
+
+// Indique une recherche comme effectuée.
+
+void CAutoResearch::SetResearch(EventMsg event)
+{
+ Event newEvent;
+
+ if ( event == EVENT_OBJECT_RTANK ) g_researchDone |= RESEARCH_TANK;
+ if ( event == EVENT_OBJECT_RFLY ) g_researchDone |= RESEARCH_FLY;
+ if ( event == EVENT_OBJECT_RTHUMP ) g_researchDone |= RESEARCH_THUMP;
+ if ( event == EVENT_OBJECT_RCANON ) g_researchDone |= RESEARCH_CANON;
+ if ( event == EVENT_OBJECT_RTOWER ) g_researchDone |= RESEARCH_TOWER;
+ if ( event == EVENT_OBJECT_RPHAZER ) g_researchDone |= RESEARCH_PHAZER;
+ if ( event == EVENT_OBJECT_RSHIELD ) g_researchDone |= RESEARCH_SHIELD;
+ if ( event == EVENT_OBJECT_RATOMIC ) g_researchDone |= RESEARCH_ATOMIC;
+
+ m_main->WriteFreeParam();
+
+ m_event->MakeEvent(newEvent, EVENT_UPDINTERFACE);
+ m_event->AddEvent(newEvent);
+ UpdateInterface();
+}
+
+
+// Met à jour les feux de stop.
+
+void CAutoResearch::FireStopUpdate(float progress, BOOL bLightOn)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i;
+
+ static float listpos[12] =
+ {
+ 9.5f, 0.0f,
+ 4.7f, 8.2f,
+ -4.7f, 8.2f,
+ -9.5f, 0.0f,
+ -4.7f, -8.2f,
+ 4.7f, -8.2f,
+ };
+
+ if ( !bLightOn ) // éteint ?
+ {
+ for ( i=0 ; i<6 ; i++ )
+ {
+ if ( m_partiStop[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_partiStop[i]);
+ m_partiStop[i] = -1;
+ }
+ }
+ return;
+ }
+
+ mat = m_object->RetWorldMatrix(0);
+
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f;
+ dim.y = dim.x;
+
+ for ( i=0 ; i<6 ; i++ )
+ {
+ if ( Mod(progress, 0.025f) < 0.005f )
+ {
+ if ( m_partiStop[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_partiStop[i]);
+ m_partiStop[i] = -1;
+ }
+ }
+ else
+ {
+ if ( m_partiStop[i] == -1 )
+ {
+ pos.x = listpos[i*2+0];
+ pos.y = 11.5f;
+ pos.z = listpos[i*2+1];
+ pos = Transform(*mat, pos);
+ m_partiStop[i] = m_particule->CreateParticule(pos, speed,
+ dim, PARTISELY,
+ 1.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoResearch::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ALP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ sprintf(name, " aResearch=%d", m_research);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoResearch::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoResearchPhase)OpInt(line, "aPhase", ALP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+ m_research = (EventMsg)OpInt(line, "aResearch", 0);
+
+ m_lastUpdateTime = 0.0f;
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autoresearch.h b/src/autoresearch.h
new file mode 100644
index 0000000..ec5f09d
--- /dev/null
+++ b/src/autoresearch.h
@@ -0,0 +1,64 @@
+// autoresearch.h
+
+#ifndef _AUTORESEARCH_H_
+#define _AUTORESEARCH_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+enum AutoResearchPhase
+{
+ ALP_WAIT = 1,
+ ALP_SEARCH = 2, // recherche en cours
+};
+
+
+
+class CAutoResearch : public CAuto
+{
+public:
+ CAutoResearch(CInstanceManager* iMan, CObject* object);
+ ~CAutoResearch();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void UpdateInterface();
+ void UpdateInterface(float rTime);
+ void OkayButton(CWindow *pw, EventMsg event);
+ BOOL TestResearch(EventMsg event);
+ void SetResearch(EventMsg event);
+ void FireStopUpdate(float progress, BOOL bLightOn);
+
+protected:
+ AutoResearchPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastUpdateTime;
+ float m_lastParticule;
+ EventMsg m_research;
+ int m_partiStop[6];
+ int m_channelSound;
+};
+
+
+#endif //_AUTORESEARCH_H_
diff --git a/src/autoroot.cpp b/src/autoroot.cpp
new file mode 100644
index 0000000..5d65448
--- /dev/null
+++ b/src/autoroot.cpp
@@ -0,0 +1,121 @@
+// autoroot.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "auto.h"
+#include "autoroot.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoRoot::CAutoRoot(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoRoot::~CAutoRoot()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoRoot::DeleteObject(BOOL bAll)
+{
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoRoot::Init()
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(-5.0f, 28.0f, -4.0f); // position pointe
+ pos = Transform(*mat, pos);
+ m_center = pos;
+
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 100.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(m_center, speed, dim, PARTISPHERE5, 0.5f, 0.0f, 0.0f);
+
+ m_terrain->AddFlyingLimit(pos, 100.0f, 80.0f, pos.y-60.0f);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoRoot::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_object->SetZoomX(1, 1.0f+sinf(m_time*2.0f)*0.2f);
+ m_object->SetZoomY(1, 1.0f+sinf(m_time*2.3f)*0.2f);
+ m_object->SetZoomZ(1, 1.0f+sinf(m_time*2.7f)*0.2f);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_center;
+ pos.x += (Rand()-0.5f)*8.0f;
+ pos.z += (Rand()-0.5f)*8.0f;
+ pos.y += 0.0f;
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+ speed.y = Rand()*12.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIROOT, 1.0f, 0.0f, 0.0f);
+ }
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoRoot::RetError()
+{
+ return ERR_OK;
+}
+
+
diff --git a/src/autoroot.h b/src/autoroot.h
new file mode 100644
index 0000000..50ca034
--- /dev/null
+++ b/src/autoroot.h
@@ -0,0 +1,38 @@
+// autoroot.h
+
+#ifndef _AUTOROOT_H_
+#define _AUTOROOT_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+class CAutoRoot : public CAuto
+{
+public:
+ CAutoRoot(CInstanceManager* iMan, CObject* object);
+ ~CAutoRoot();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+protected:
+
+protected:
+ float m_lastParticule;
+ D3DVECTOR m_center;
+};
+
+
+#endif //_AUTOROOT_H_
diff --git a/src/autosafe.cpp b/src/autosafe.cpp
new file mode 100644
index 0000000..e9c1959
--- /dev/null
+++ b/src/autosafe.cpp
@@ -0,0 +1,622 @@
+// autosafe.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "robotmain.h"
+#include "window.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autosafe.h"
+
+
+
+#define OPEN_DELAY 8.0f // durée de l'ouverture
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoSafe::CAutoSafe(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ int i;
+
+ CAuto::CAuto(iMan, object);
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ m_bKey[i] = FALSE;
+ m_keyParti[i] = -1;
+ }
+
+ m_bLock = FALSE;
+ m_lastParticule = 0.0f;
+ m_channelSound = -1;
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoSafe::~CAutoSafe()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoSafe::DeleteObject(BOOL bAll)
+{
+ CObject* pObj;
+
+ pObj = SearchVehicle();
+ if ( pObj != 0 )
+ {
+ pObj->DeleteObject();
+ delete pObj;
+ }
+
+ if ( m_channelSound != -1 )
+ {
+ m_sound->FlushEnvelope(m_channelSound);
+ m_sound->AddEnvelope(m_channelSound, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_channelSound = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoSafe::Init()
+{
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_countKeys = 0;
+ m_actualAngle = 0.0f;
+ m_finalAngle = 0.0f;
+
+ m_phase = ASAP_WAIT; // attend ...
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoSafe::EventProcess(const Event &event)
+{
+ CObject* pObj;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i, count;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+ }
+ return TRUE;
+ }
+
+ EventProgress(event.rTime);
+
+ if ( !m_bLock )
+ {
+ pObj = SearchVehicle();
+ if ( pObj != 0 )
+ {
+ pObj->SetLock(TRUE); // objet pas encore utilisable
+ m_main->CreateShortcuts();
+ m_bLock = TRUE;
+ }
+ }
+
+ if ( m_phase == ASAP_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ count = CountKeys(); // compte les clés présentes
+ if ( count != m_countKeys )
+ {
+ m_countKeys = count;
+
+ if ( count == 0 ) m_finalAngle = 0.0f*PI/180.0f;
+ if ( count == 1 ) m_finalAngle = 5.0f*PI/180.0f;
+ if ( count == 2 ) m_finalAngle = 10.0f*PI/180.0f;
+ if ( count == 3 ) m_finalAngle = 15.0f*PI/180.0f;
+ if ( count == 4 ) m_finalAngle = 120.0f*PI/180.0f;
+
+ if ( count == 4 ) // toutes les clés ?
+ {
+ LockKeys();
+
+ m_channelSound = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 1.0f, 0.25f, TRUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 2.00f, OPEN_DELAY, SOPER_STOP);
+
+ m_phase = ASAP_OPEN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/OPEN_DELAY;
+ return TRUE;
+ }
+ else
+ {
+ m_channelSound = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 1.0f, 0.25f, TRUE);
+ m_sound->AddEnvelope(m_channelSound, 1.0f, 0.35f, 0.5f, SOPER_STOP);
+ }
+ }
+
+ m_phase = ASAP_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ASAP_OPEN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ DownKeys(m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ speed.x = (Rand()-0.5f)*4.0f;
+ speed.z = (Rand()-0.5f)*4.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, 1.0f, 0.0f, 0.0f);
+ }
+
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ speed.x = (Rand()-0.5f)*4.0f;
+ speed.z = (Rand()-0.5f)*4.0f;
+ speed.y = Rand()*10.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 1.0f, 0.0f, 0.0f);
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos = m_keyPos[i];
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 1.0f+Rand()*1.0f;
+ dim.x = Rand()*1.5f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+ else
+ {
+ DeleteKeys();
+
+ pObj = SearchVehicle();
+ if ( pObj != 0 )
+ {
+ pObj->SetLock(FALSE); // objet utilisable
+ m_main->CreateShortcuts();
+ }
+
+ m_object->FlushCrashShere();
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 0.0f);
+
+ m_sound->Play(SOUND_FINDING, m_object->RetPosition(0));
+
+ m_phase = ASAP_FINISH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/100.0f;
+ }
+ }
+
+ if ( m_phase == ASAP_FINISH )
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_phase = ASAP_FINISH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/100.0f;
+ }
+ }
+
+ // Ouvre ou ferme les portes.
+ if ( m_actualAngle != m_finalAngle )
+ {
+ if ( m_actualAngle < m_finalAngle )
+ {
+ m_actualAngle += (105.0f*PI/180.0f)*event.rTime/OPEN_DELAY;
+ if ( m_actualAngle > m_finalAngle ) m_actualAngle = m_finalAngle;
+ }
+ else
+ {
+ m_actualAngle -= (105.0f*PI/180.0f)*event.rTime/OPEN_DELAY;
+ if ( m_actualAngle < m_finalAngle ) m_actualAngle = m_finalAngle;
+ }
+ m_object->SetAngleZ(1, m_actualAngle);
+ m_object->SetAngleZ(2, -m_actualAngle);
+ }
+
+ // Fait clignotter les clés.
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ for ( i=0 ; i<4 ; i++ )
+ {
+ if ( m_phase != ASAP_WAIT || !m_bKey[i] || Mod(m_time, 1.0f) < 0.4f )
+ {
+ if ( m_keyParti[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_keyParti[i]);
+ m_keyParti[i] = -1;
+ }
+ }
+ else
+ {
+ if ( m_keyParti[i] == -1 )
+ {
+ pos = m_keyPos[i];
+ pos.y += 2.2f;
+ m_keyParti[i] = m_particule->CreateParticule(pos, speed, dim, PARTISELY, 1.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoSafe::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 114, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoSafe::RetError()
+{
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+ return ERR_OK;
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoSafe::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ASAP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoSafe::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoSafePhase)OpInt(line, "aPhase", ASAP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+
+ m_lastParticule = 0.0f;
+
+ return TRUE;
+}
+
+
+// Compte le nombre de clés présentes.
+
+int CAutoSafe::CountKeys()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ FPOINT rot;
+ ObjectType oType;
+ float dist, angle, limit, cAngle, oAngle;
+ int i, index;
+
+ cPos = m_object->RetPosition(0);
+ cAngle = m_object->RetAngleY(0);
+
+ for ( index=0 ; index<4 ; index++ )
+ {
+ m_bKey[index] = FALSE;
+ m_keyPos[index] = cPos;
+ }
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ if ( oType != OBJECT_KEYa &&
+ oType != OBJECT_KEYb &&
+ oType != OBJECT_KEYc &&
+ oType != OBJECT_KEYd ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, cPos);
+ if ( dist > 20.0f ) continue;
+
+ if ( oType == OBJECT_KEYa )
+ {
+ limit = PI*1.0f;
+ oAngle = PI*0.0f;
+ index = 0;
+ }
+ if ( oType == OBJECT_KEYb )
+ {
+ limit = PI*0.0f;
+ oAngle = PI*1.0f;
+ index = 1;
+ }
+ if ( oType == OBJECT_KEYc )
+ {
+ limit = PI*1.5f;
+ oAngle = PI*0.5f;
+ index = 2;
+ }
+ if ( oType == OBJECT_KEYd )
+ {
+ limit = PI*0.5f;
+ oAngle = PI*0.0f;
+ index = 3;
+ }
+
+ angle = RotateAngle(oPos.x-cPos.x, oPos.z-cPos.z)+cAngle;
+ if ( !TestAngle(angle, limit-8.0f*PI/180.0f, limit+8.0f*PI/180.0f) ) continue;
+
+ // Déplace la clé sur la forme du socle.
+ rot = RotatePoint(FPOINT(cPos.x, cPos.z), limit-cAngle, FPOINT(cPos.x+16.0f, cPos.z));
+ oPos.x = rot.x;
+ oPos.z = rot.y;
+ oPos.y = cPos.y+1.0f;
+ pObj->SetPosition(0, oPos);
+ pObj->SetAngleY(0, oAngle+cAngle);
+ m_keyPos[index] = oPos;
+
+ m_bKey[index] = TRUE;
+ }
+
+ i = 0;
+ for ( index=0 ; index<4 ; index++ )
+ {
+ if ( m_bKey[index] ) i++;
+ }
+ return i;
+}
+
+// Bloque toutes les clés présentes.
+
+void CAutoSafe::LockKeys()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType oType;
+ float dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ if ( oType != OBJECT_KEYa &&
+ oType != OBJECT_KEYb &&
+ oType != OBJECT_KEYc &&
+ oType != OBJECT_KEYd ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, cPos);
+ if ( dist > 20.0f ) continue;
+
+ pObj->SetLock(TRUE);
+ }
+}
+
+// Fait descendre toutes les clés présentes.
+
+void CAutoSafe::DownKeys(float progress)
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType oType;
+ float dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ if ( oType != OBJECT_KEYa &&
+ oType != OBJECT_KEYb &&
+ oType != OBJECT_KEYc &&
+ oType != OBJECT_KEYd ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, cPos);
+ if ( dist > 20.0f ) continue;
+
+ oPos.y = cPos.y+1.0f-progress*2.2f;
+ pObj->SetPosition(0, oPos);
+ }
+}
+
+// Supprime toutes les clés présentes.
+
+void CAutoSafe::DeleteKeys()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType oType;
+ float dist;
+ int i;
+ BOOL bDelete;
+
+ cPos = m_object->RetPosition(0);
+
+ do
+ {
+ bDelete = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ if ( oType != OBJECT_KEYa &&
+ oType != OBJECT_KEYb &&
+ oType != OBJECT_KEYc &&
+ oType != OBJECT_KEYd ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, cPos);
+ if ( dist > 20.0f ) continue;
+
+ pObj->DeleteObject();
+ delete pObj;
+ bDelete = TRUE;
+ }
+ }
+ while ( bDelete );
+}
+
+// Cherche le véhicule dans le coffre-fort.
+
+CObject* CAutoSafe::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR cPos, oPos;
+ ObjectType oType;
+ float dist;
+ int i;
+
+ cPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, cPos);
+ if ( dist <= 4.0f ) return pObj;
+ }
+ return 0;
+}
+
+
+
diff --git a/src/autosafe.h b/src/autosafe.h
new file mode 100644
index 0000000..66d5573
--- /dev/null
+++ b/src/autosafe.h
@@ -0,0 +1,66 @@
+// autosafe.h
+
+#ifndef _AUTOSAFE_H_
+#define _AUTOSAFE_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+enum AutoSafePhase
+{
+ ASAP_WAIT = 1,
+ ASAP_OPEN = 2,
+ ASAP_FINISH = 3,
+};
+
+
+
+class CAutoSafe : public CAuto
+{
+public:
+ CAutoSafe(CInstanceManager* iMan, CObject* object);
+ ~CAutoSafe();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ int CountKeys();
+ void LockKeys();
+ void DownKeys(float progress);
+ void DeleteKeys();
+ CObject* SearchVehicle();
+
+protected:
+ AutoSafePhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastParticule;
+ int m_channelSound;
+ BOOL m_bLock;
+ int m_countKeys;
+ float m_actualAngle;
+ float m_finalAngle;
+ BOOL m_bKey[4];
+ D3DVECTOR m_keyPos[4];
+ int m_keyParti[4];
+};
+
+
+#endif //_AUTOSAFE_H_
diff --git a/src/autostation.cpp b/src/autostation.cpp
new file mode 100644
index 0000000..3594eaf
--- /dev/null
+++ b/src/autostation.cpp
@@ -0,0 +1,373 @@
+// autostation.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "light.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "interface.h"
+#include "button.h"
+#include "gauge.h"
+#include "window.h"
+#include "sound.h"
+#include "auto.h"
+#include "autostation.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CAutoStation::CAutoStation(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ CAuto::CAuto(iMan, object);
+
+ Init();
+}
+
+// Destructeur de l'objet.
+
+CAutoStation::~CAutoStation()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoStation::DeleteObject(BOOL bAll)
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->Stop(m_soundChannel);
+ m_soundChannel = -1;
+ }
+
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoStation::Init()
+{
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastUpdateTime = 0.0f;
+ m_lastParticule = 0.0f;
+ m_soundChannel = -1;
+ m_bLastVirus = FALSE;
+
+ CAuto::Init();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoStation::EventProcess(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, ppos, speed;
+ FPOINT dim;
+ CObject* vehicule;
+ CObject* power;
+ TerrainRes res;
+ float big, energy, used, add, freq;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( !m_bLastVirus )
+ {
+ m_bLastVirus = TRUE;
+ m_energyVirus = m_object->RetEnergy();
+ }
+
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ m_object->SetEnergy(Rand());
+ }
+ return TRUE;
+ }
+ else
+ {
+ if ( m_bLastVirus )
+ {
+ m_bLastVirus = FALSE;
+ m_object->SetEnergy(m_energyVirus);
+ }
+ }
+
+ UpdateInterface(event.rTime);
+
+ big = m_object->RetEnergy();
+
+ res = m_terrain->RetResource(m_object->RetPosition(0));
+ if ( res == TR_POWER )
+ {
+ big += event.rTime*0.01f; // recharge la grosse pile
+ }
+
+ used = big;
+ freq = 1.0f;
+ if ( big > 0.0f )
+ {
+ vehicule = SearchVehicle();
+ if ( vehicule != 0 )
+ {
+ power = vehicule->RetPower();
+ if ( power != 0 && power->RetCapacity() == 1.0f )
+ {
+ energy = power->RetEnergy();
+ add = event.rTime*0.2f;
+ if ( add > big*4.0f ) add = big*4.0f;
+ if ( add > 1.0f-energy ) add = 1.0f-energy;
+ energy += add; // recharge la pile
+ power->SetEnergy(energy);
+ if ( energy < freq ) freq = energy;
+ big -= add/4.0f; // décharge la grosse pile
+ }
+
+ power = vehicule->RetFret();
+ if ( power != 0 && power->RetType() == OBJECT_POWER )
+ {
+ energy = power->RetEnergy();
+ add = event.rTime*0.2f;
+ if ( add > big*4.0f ) add = big*4.0f;
+ if ( add > 1.0f-energy ) add = 1.0f-energy;
+ energy += add; // recharge la pile
+ power->SetEnergy(energy);
+ if ( energy < freq ) freq = energy;
+ big -= add/4.0f; // décharge la grosse pile
+ }
+ }
+ }
+ used -= big; // énergie utilisée
+
+ if ( freq < 1.0f ) // charge en cours ?
+ {
+ freq = 1.0f+3.0f*freq;
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_STATION, m_object->RetPosition(0),
+ 0.3f, freq, TRUE);
+ }
+ m_sound->Frequency(m_soundChannel, freq);
+ }
+ else
+ {
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->Stop(m_soundChannel);
+ m_soundChannel = -1;
+ }
+ }
+
+ if ( used != 0.0f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(-15.0f, 7.0f, 0.0f); // position batterie
+ pos = Transform(*mat, pos);
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.y = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ ppos.x = pos.x;
+ ppos.y = pos.y+(Rand()-0.5f)*4.0f;
+ ppos.z = pos.z;
+ dim.x = 1.5f;
+ dim.y = 1.5f;
+ m_particule->CreateParticule(ppos, speed, dim, PARTIBLITZ, 1.0f, 0.0f, 0.0f);
+
+#if 0
+ ppos = pos;
+ ppos.y += 1.0f;
+ ppos.x += (Rand()-0.5f)*3.0f;
+ ppos.z += (Rand()-0.5f)*3.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 2.5f+Rand()*6.0f;
+ dim.x = Rand()*1.5f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(ppos, speed, dim, PARTISMOKE3, 4.0f);
+#else
+ ppos = pos;
+ ppos.y += 1.0f;
+ ppos.x += (Rand()-0.5f)*3.0f;
+ ppos.z += (Rand()-0.5f)*3.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 2.5f+Rand()*5.0f;
+ dim.x = Rand()*1.0f+0.6f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(ppos, speed, dim, PARTIVAPOR, 3.0f);
+#endif
+ }
+
+ if ( big < 0.0f ) big = 0.0f;
+ if ( big > 1.0f ) big = 1.0f;
+ m_object->SetEnergy(big); // màj la grosse pile
+
+ return TRUE;
+}
+
+
+// Cherche le véhicule placé sur la station.
+
+CObject* CAutoStation::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR sPos, oPos;
+ ObjectType type;
+ float dist;
+ int i;
+
+ sPos = m_object->RetPosition(0);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, sPos);
+ if ( dist <= 5.0f ) return pObj;
+ }
+
+ return 0;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoStation::RetError()
+{
+ TerrainRes res;
+
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ res = m_terrain->RetResource(m_object->RetPosition(0));
+ if ( res != TR_POWER ) return ERR_STATION_NULL;
+
+ return ERR_OK;
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoStation::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*14.5f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 0, EVENT_OBJECT_GENERGY);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 104, EVENT_OBJECT_TYPE);
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CAutoStation::UpdateInterface(float rTime)
+{
+ CWindow* pw;
+ CGauge* pg;
+
+ CAuto::UpdateInterface(rTime);
+
+ if ( m_time < m_lastUpdateTime+0.1f ) return;
+ m_lastUpdateTime = m_time;
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GENERGY);
+ if ( pg != 0 )
+ {
+ pg->SetLevel(m_object->RetEnergy());
+ }
+}
+
+
diff --git a/src/autostation.h b/src/autostation.h
new file mode 100644
index 0000000..9fd02b0
--- /dev/null
+++ b/src/autostation.h
@@ -0,0 +1,48 @@
+// autostation.h
+
+#ifndef _AUTOSTATION_H_
+#define _AUTOSTATION_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+
+
+class CAutoStation : public CAuto
+{
+public:
+ CAutoStation(CInstanceManager* iMan, CObject* object);
+ ~CAutoStation();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+protected:
+ void UpdateInterface(float rTime);
+
+ CObject* SearchVehicle();
+
+protected:
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastUpdateTime;
+ float m_lastParticule;
+ int m_soundChannel;
+ D3DVECTOR m_fretPos;
+ BOOL m_bLastVirus;
+ float m_energyVirus;
+};
+
+
+#endif //_AUTOSTATION_H_
diff --git a/src/autotower.cpp b/src/autotower.cpp
new file mode 100644
index 0000000..68a6e9e
--- /dev/null
+++ b/src/autotower.cpp
@@ -0,0 +1,547 @@
+// autotower.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "camera.h"
+#include "object.h"
+#include "physics.h"
+#include "interface.h"
+#include "button.h"
+#include "gauge.h"
+#include "window.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "auto.h"
+#include "autotower.h"
+
+
+
+#define TOWER_SCOPE 200.0f // portée du rayon
+#define ENERGY_FIRE 0.125f // énergie consommée par tir
+
+
+// Constructeur de l'objet.
+
+CAutoTower::CAutoTower(CInstanceManager* iMan, CObject* object)
+ : CAuto(iMan, object)
+{
+ int i;
+
+ CAuto::CAuto(iMan, object);
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ m_partiStop[i] = -1;
+ }
+
+ Init();
+ m_phase = ATP_WAIT; // en pause jusqu'au premier Init()
+ m_time = 0.0f;
+ m_lastUpdateTime = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CAutoTower::~CAutoTower()
+{
+ CAuto::~CAuto();
+}
+
+
+// Détruit l'objet.
+
+void CAutoTower::DeleteObject(BOOL bAll)
+{
+ FireStopUpdate(0.0f, FALSE);
+ CAuto::DeleteObject(bAll);
+}
+
+
+// Initialise l'objet.
+
+void CAutoTower::Init()
+{
+ m_phase = ATP_ZERO;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+
+ m_time = 0.0f;
+ m_timeVirus = 0.0f;
+ m_lastUpdateTime = 0.0f;
+ m_lastParticule = 0.0f;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CAutoTower::EventProcess(const Event &event)
+{
+ CObject* power;
+ CObject* target;
+ D3DVECTOR pos;
+ float angle, energy, quick;
+
+ CAuto::EventProcess(event);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_timeVirus -= event.rTime;
+
+ if ( m_object->RetVirusMode() ) // contaminé par un virus ?
+ {
+ if ( m_timeVirus <= 0.0f )
+ {
+ m_timeVirus = 0.1f+Rand()*0.3f;
+
+ angle = m_object->RetAngleY(1);
+ angle += Rand()*0.5f;
+ m_object->SetAngleY(1, angle);
+
+ m_object->SetAngleZ(2, Rand()*0.5f);
+ }
+ return TRUE;
+ }
+
+ UpdateInterface(event.rTime);
+
+ if ( m_phase == ATP_WAIT ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == ATP_ZERO )
+ {
+ FireStopUpdate(m_progress, TRUE); // clignotte
+ if ( m_progress < 1.0f )
+ {
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+ if ( energy >= ENERGY_FIRE )
+ {
+ m_phase = ATP_SEARCH;
+ m_progress = 0.0f;
+ m_speed = 1.0f/3.0f;
+ }
+ }
+ else
+ {
+ m_phase = ATP_ZERO;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ if ( m_phase == ATP_SEARCH )
+ {
+ FireStopUpdate(m_progress, FALSE); // éteint
+ if ( m_progress < 1.0f )
+ {
+ quick = 1.0f;
+//? if ( g_researchDone & RESEARCH_QUICK ) quick = 3.0f;
+
+ angle = m_object->RetAngleY(1);
+ angle -= event.rTime*quick*2.0f;
+ m_object->SetAngleY(1, angle);
+
+ angle = m_object->RetAngleZ(2);
+ angle += event.rTime*quick*0.5f;
+ if ( angle > 0.0f ) angle = 0.0f;
+ m_object->SetAngleZ(2, angle);
+ }
+ else
+ {
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+
+ target = SearchTarget(m_targetPos);
+ if ( energy < ENERGY_FIRE )
+ {
+ m_displayText->DisplayError(ERR_TOWER_ENERGY, m_object);
+ }
+ if ( target == 0 || energy < ENERGY_FIRE )
+ {
+ m_phase = ATP_ZERO;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ else
+ {
+ pos = m_object->RetPosition(0);
+ pos.y += 24.5f;
+ m_angleYfinal = RotateAngle(m_targetPos.x-pos.x, pos.z-m_targetPos.z); // CW !
+ m_angleYfinal += PI*2.0f;
+ m_angleYfinal -= m_object->RetAngleY(0);
+ m_angleYactual = NormAngle(m_object->RetAngleY(1));
+
+ m_angleZfinal = -PI/2.0f;
+ m_angleZfinal -= RotateAngle(Length2d(m_targetPos, pos), pos.y-m_targetPos.y); // CW !
+ m_angleZactual = m_object->RetAngleZ(2);
+
+ m_phase = ATP_TURN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+//? if ( g_researchDone & RESEARCH_QUICK ) m_speed = 1.0f/0.2f;
+ }
+ }
+ }
+
+ if ( m_phase == ATP_TURN )
+ {
+ if ( m_progress < 1.0f )
+ {
+ angle = m_angleYactual+(m_angleYfinal-m_angleYactual)*m_progress;
+ m_object->SetAngleY(1, angle);
+
+ angle = m_angleZactual+(m_angleZfinal-m_angleZactual)*m_progress;
+ m_object->SetAngleZ(2, angle);
+ }
+ else
+ {
+ m_object->SetAngleY(1, m_angleYfinal);
+ m_object->SetAngleZ(2, m_angleZfinal);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ energy -= ENERGY_FIRE/power->RetCapacity();
+ power->SetEnergy(energy);
+ }
+
+ m_sound->Play(SOUND_GGG, m_object->RetPosition(0));
+
+ m_phase = ATP_FIRE;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ }
+ }
+
+ if ( m_phase == ATP_FIRE )
+ {
+ if ( m_progress == 0.0f )
+ {
+ pos = m_object->RetPosition(0);
+ pos.y += 24.5f;
+ m_particule->CreateRay(pos, m_targetPos, PARTIRAY1,
+ FPOINT(5.0f, 5.0f), 1.5f);
+ }
+ if ( m_progress >= 1.0f )
+ {
+ m_phase = ATP_ZERO;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Cherche l'objet cible le plus proche.
+
+CObject* CAutoTower::SearchTarget(D3DVECTOR &impact)
+{
+ CObject* pObj;
+ CObject* pBest = 0;
+ CPhysics* physics;
+ D3DVECTOR iPos, oPos;
+ ObjectType oType;
+ float distance, min, radius, speed;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ min = 1000000.0f;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( oType != OBJECT_MOTHER &&
+ oType != OBJECT_ANT &&
+ oType != OBJECT_SPIDER &&
+ oType != OBJECT_BEE &&
+ oType != OBJECT_WORM ) continue;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+
+//? if ( g_researchDone & RESEARCH_QUICK )
+ if ( FALSE )
+ {
+ physics = pObj->RetPhysics();
+ if ( physics != 0 )
+ {
+ speed = Abs(physics->RetLinMotionX(MO_REASPEED));
+ if ( speed > 20.0f ) continue; // avance trop vite ?
+ }
+ }
+
+ if ( !pObj->GetCrashSphere(0, oPos, radius) ) continue;
+ distance = Length(oPos, iPos);
+ if ( distance > TOWER_SCOPE ) continue; // trop loin
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ }
+ }
+ if ( pBest == 0 ) return 0;
+
+ impact = pBest->RetPosition(0);
+ return pBest;
+}
+
+
+// Retourne une erreur liée à l'état de l'automate.
+
+Error CAutoTower::RetError()
+{
+ CObject* power;
+
+ if ( m_object->RetVirusMode() )
+ {
+ return ERR_BAT_VIRUS;
+ }
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ return ERR_TOWER_POWER; // pas de pile
+ }
+ else
+ {
+ if ( power->RetEnergy() < ENERGY_FIRE )
+ {
+ return ERR_TOWER_ENERGY; // plus assez d'énergie
+ }
+ }
+ return ERR_OK;
+}
+
+
+// Met à jour les feux de stop.
+
+void CAutoTower::FireStopUpdate(float progress, BOOL bLightOn)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i;
+
+ static float listpos[8] =
+ {
+ 4.5f, 0.0f,
+ 0.0f, 4.5f,
+ -4.5f, 0.0f,
+ 0.0f, -4.5f,
+ };
+
+ if ( !bLightOn ) // éteint ?
+ {
+ for ( i=0 ; i<4 ; i++ )
+ {
+ if ( m_partiStop[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_partiStop[i]);
+ m_partiStop[i] = -1;
+ }
+ }
+ return;
+ }
+
+ mat = m_object->RetWorldMatrix(0);
+
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f;
+ dim.y = dim.x;
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ if ( Mod(progress+i*0.125f, 0.5f) < 0.2f )
+ {
+ if ( m_partiStop[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_partiStop[i]);
+ m_partiStop[i] = -1;
+ }
+ }
+ else
+ {
+ if ( m_partiStop[i] == -1 )
+ {
+ pos.x = listpos[i*2+0];
+ pos.y = 18.0f;
+ pos.z = listpos[i*2+1];
+ pos = Transform(*mat, pos);
+ m_partiStop[i] = m_particule->CreateParticule(pos, speed,
+ dim, PARTISELR,
+ 1.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CAutoTower::CreateInterface(BOOL bSelect)
+{
+ CWindow* pw;
+ FPOINT pos, ddim;
+ float ox, oy, sx, sy;
+
+ CAuto::CreateInterface(bSelect);
+
+ if ( !bSelect ) return TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ pos.x = ox+sx*14.5f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 0, EVENT_OBJECT_GENERGY);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0;
+ ddim.x = 66.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 107, EVENT_OBJECT_TYPE);
+
+ pos.x = ox+sx*10.2f;
+ pos.y = oy+sy*0.5f;
+ ddim.x = 33.0f/640.0f;
+ ddim.y = 33.0f/480.0f;
+ pw->CreateButton(pos, ddim, 41, EVENT_OBJECT_LIMIT);
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CAutoTower::UpdateInterface(float rTime)
+{
+ CWindow* pw;
+ CGauge* pg;
+ CObject* power;
+ float energy;
+
+ CAuto::UpdateInterface(rTime);
+
+ if ( m_time < m_lastUpdateTime+0.1f ) return;
+ m_lastUpdateTime = m_time;
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GENERGY);
+ if ( pg != 0 )
+ {
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+ pg->SetLevel(energy);
+ }
+}
+
+
+// Sauve tous les paramètres de l'automate.
+
+BOOL CAutoTower::Write(char *line)
+{
+ char name[100];
+
+ if ( m_phase == ATP_WAIT ) return FALSE;
+
+ sprintf(name, " aExist=%d", 1);
+ strcat(line, name);
+
+ CAuto::Write(line);
+
+ sprintf(name, " aPhase=%d", m_phase);
+ strcat(line, name);
+
+ sprintf(name, " aProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ sprintf(name, " aSpeed=%.2f", m_speed);
+ strcat(line, name);
+
+ sprintf(name, " aTargetPos=%.2f;%.2f;%.2f", m_targetPos.x, m_targetPos.y, m_targetPos.z);
+ strcat(line, name);
+
+ sprintf(name, " aAngleYactual=%.2f", m_angleYactual);
+ strcat(line, name);
+
+ sprintf(name, " aAngleZactual=%.2f", m_angleZactual);
+ strcat(line, name);
+
+ sprintf(name, " aAngleYfinal=%.2f", m_angleYfinal);
+ strcat(line, name);
+
+ sprintf(name, " aAngleZfinal=%.2f", m_angleZfinal);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'automate.
+
+BOOL CAutoTower::Read(char *line)
+{
+ if ( OpInt(line, "aExist", 0) == 0 ) return FALSE;
+
+ CAuto::Read(line);
+
+ m_phase = (AutoTowerPhase)OpInt(line, "aPhase", ATP_WAIT);
+ m_progress = OpFloat(line, "aProgress", 0.0f);
+ m_speed = OpFloat(line, "aSpeed", 1.0f);
+ m_targetPos = OpDir(line, "aTargetPos");
+ m_angleYactual = OpFloat(line, "aAngleYactual", 0.0f);
+ m_angleZactual = OpFloat(line, "aAngleZactual", 0.0f);
+ m_angleYfinal = OpFloat(line, "aAngleYfinal", 0.0f);
+ m_angleZfinal = OpFloat(line, "aAngleZfinal", 0.0f);
+
+ m_lastUpdateTime = 0.0f;
+
+ return TRUE;
+}
+
+
diff --git a/src/autotower.h b/src/autotower.h
new file mode 100644
index 0000000..6fe5032
--- /dev/null
+++ b/src/autotower.h
@@ -0,0 +1,68 @@
+// autotower.h
+
+#ifndef _AUTOTOWER_H_
+#define _AUTOTOWER_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CObject;
+
+enum ObjectType;
+
+
+
+enum AutoTowerPhase
+{
+ ATP_WAIT = 1,
+ ATP_ZERO = 2, // plus d'énergie
+ ATP_SEARCH = 3, // cherche une cible
+ ATP_TURN = 4, // tourne vers la cible
+ ATP_FIRE = 5, // tire sur la cible
+};
+
+
+
+class CAutoTower : public CAuto
+{
+public:
+ CAutoTower(CInstanceManager* iMan, CObject* object);
+ ~CAutoTower();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void Init();
+ BOOL EventProcess(const Event &event);
+ Error RetError();
+
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+protected:
+ void UpdateInterface(float rTime);
+
+ CObject* SearchTarget(D3DVECTOR &impact);
+ void FireStopUpdate(float progress, BOOL bLightOn);
+
+protected:
+ AutoTowerPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_timeVirus;
+ float m_lastUpdateTime;
+ float m_lastParticule;
+ D3DVECTOR m_targetPos;
+ float m_angleYactual;
+ float m_angleZactual;
+ float m_angleYfinal;
+ float m_angleZfinal;
+ int m_partiStop[4];
+};
+
+
+#endif //_AUTOTOWER_H_
diff --git a/src/blitz.cpp b/src/blitz.cpp
new file mode 100644
index 0000000..cef567e
--- /dev/null
+++ b/src/blitz.cpp
@@ -0,0 +1,456 @@
+// blitz.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "math3d.h"
+#include "object.h"
+#include "camera.h"
+#include "auto.h"
+#include "autopara.h"
+#include "sound.h"
+#include "blitz.h"
+
+
+
+
+// Constructeur du terrain.
+
+CBlitz::CBlitz(CInstanceManager* iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_BLITZ, this);
+
+ m_engine = engine;
+ m_terrain = 0;
+ m_camera = 0;
+ m_sound = 0;
+ Flush();
+}
+
+// Destructeur du terrain.
+
+CBlitz::~CBlitz()
+{
+}
+
+
+// Supprime les éclairs.
+
+void CBlitz::Flush()
+{
+ int i;
+
+ m_bBlitzExist = FALSE;
+ m_time = 0.0f;
+ m_phase = BPH_WAIT;
+ m_speed = 0.0f;
+ m_progress = 0.0f;
+
+ for ( i=0 ; i<BLITZMAX ; i++ )
+ {
+ m_shift[i] = FPOINT(0.0f, 0.0f);
+ m_width[i] = 1.0f;
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CBlitz::EventProcess(const Event &event)
+{
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+ return TRUE;
+}
+
+// Fait évoluer les éclairs.
+
+BOOL CBlitz::EventFrame(const Event &event)
+{
+ CObject* pObj;
+ CAutoPara* automat;
+ ObjectType type;
+ D3DVECTOR eye, pos;
+ float dist, deep, max;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( m_engine->RetMovieLock() ) return TRUE;
+
+ m_time += event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == BPH_WAIT )
+ {
+ if ( m_progress >= 1.0f )
+ {
+#if 1
+ m_pos.x = (Rand()-0.5f)*(3200.0f-200.0f);
+ m_pos.z = (Rand()-0.5f)*(3200.0f-200.0f);
+#else
+ m_pos.x = (Rand()-0.5f)*(3200.0f-2800.0f);
+ m_pos.z = (Rand()-0.5f)*(3200.0f-2800.0f);
+#endif
+ m_pos.y = 0.0f;
+
+ pObj = SearchObject(m_pos);
+ if ( pObj == 0 )
+ {
+ m_terrain->MoveOnFloor(m_pos, TRUE);
+ }
+ else
+ {
+ m_pos = pObj->RetPosition(0);
+ m_terrain->MoveOnFloor(m_pos, TRUE);
+
+ type = pObj->RetType();
+ if ( type == OBJECT_BASE )
+ {
+ m_pos.y += 120.0f; // sommet de la fusée
+ }
+ else if ( type == OBJECT_PARA )
+ {
+ automat = (CAutoPara*)pObj->RetAuto();
+ if ( automat != 0 )
+ {
+ automat->StartBlitz();
+ }
+ m_pos.y += 67.0f; // sommet du paratonnerre
+ }
+ else
+ {
+ pObj->ExploObject(EXPLO_BOUM, 1.0f);
+ }
+ }
+
+ eye = m_engine->RetEyePt();
+ dist = Length(m_pos, eye);
+ deep = m_engine->RetDeepView();
+
+ if ( dist < deep )
+ {
+ pos = eye+((m_pos-eye)*0.2f); // comme si proche !
+ m_sound->Play(SOUND_BLITZ, pos);
+
+ m_camera->StartOver(OE_BLITZ, m_pos, 1.0f);
+
+ m_phase = BPH_BLITZ;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ }
+ }
+ }
+
+ if ( m_phase == BPH_BLITZ )
+ {
+ if ( m_progress < 1.0f )
+ {
+ max = 5.0f;
+ for ( i=0 ; i<BLITZMAX ; i++ )
+ {
+ max += 0.4f;
+
+ m_shift[i].x += (Rand()-0.5f)*max*2.0f;
+ if ( m_shift[i].x < -max ) m_shift[i].x = -max;
+ if ( m_shift[i].x > max ) m_shift[i].x = max;
+
+ m_shift[i].y += (Rand()-0.5f)*max*2.0f;
+ if ( m_shift[i].y < -max ) m_shift[i].y = -max;
+ if ( m_shift[i].y > max ) m_shift[i].y = max;
+
+ m_width[i] += (Rand()-0.5f)*2.0f;
+ if ( m_width[i] < 1.0f ) m_width[i] = 1.0f;
+ if ( m_width[i] > 6.0f ) m_width[i] = 6.0f;
+ }
+ m_shift[0].x = 0.0f;
+ m_shift[0].y = 0.0f;
+ m_width[0] = 0.0f;
+ }
+ else
+ {
+ m_phase = BPH_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/(1.0f+Rand()*m_delay);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Dessine les éclairs.
+
+void CBlitz::Draw()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR corner[4], eye, n, p, p1, p2;
+ D3DMATRIX matrix;
+ FPOINT texInf, texSup, rot;
+ float a;
+ int i;
+
+ if ( !m_bBlitzExist ) return;
+ if ( m_phase != BPH_BLITZ ) return;
+
+ device = m_engine->RetD3DDevice();
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ m_engine->SetTexture("effect00.tga");
+ m_engine->SetState(D3DSTATETTb);
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 33.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 34.0f/256.0f; // blanc
+
+ p1 = m_pos;
+ eye = m_engine->RetEyePt();
+ a = RotateAngle(eye.x-p1.x, eye.z-p1.z);
+ n = Normalize(p1-eye);
+
+ for ( i=0 ; i<BLITZMAX-1 ; i++ )
+ {
+ p2 = p1;
+ p2.y += 8.0f+0.2f*i;
+
+ p = p1;
+ p.x += m_width[i];
+ rot = RotatePoint(FPOINT(p1.x, p1.z), a+PI/2.0f, FPOINT(p.x, p.z));
+ corner[0].x = rot.x+m_shift[i].x;
+ corner[0].y = p1.y;
+ corner[0].z = rot.y+m_shift[i].y;
+ rot = RotatePoint(FPOINT(p1.x, p1.z), a-PI/2.0f, FPOINT(p.x, p.z));
+ corner[1].x = rot.x+m_shift[i].x;
+ corner[1].y = p1.y;
+ corner[1].z = rot.y+m_shift[i].y;
+
+ p = p2;
+ p.x += m_width[i+1];
+ rot = RotatePoint(FPOINT(p2.x, p2.z), a+PI/2.0f, FPOINT(p.x, p.z));
+ corner[2].x = rot.x+m_shift[i+1].x;
+ corner[2].y = p2.y;
+ corner[2].z = rot.y+m_shift[i+1].y;
+ rot = RotatePoint(FPOINT(p2.x, p2.z), a-PI/2.0f, FPOINT(p.x, p.z));
+ corner[3].x = rot.x+m_shift[i+1].x;
+ corner[3].y = p2.y;
+ corner[3].z = rot.y+m_shift[i+1].y;
+
+ if ( p2.y < p1.y )
+ {
+ vertex[0] = D3DVERTEX2(corner[1], n, texSup.x, texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, texInf.x, texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, texSup.x, texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, texInf.x, texInf.y);
+ }
+ else
+ {
+ vertex[0] = D3DVERTEX2(corner[0], n, texSup.x, texSup.y);
+ vertex[1] = D3DVERTEX2(corner[1], n, texInf.x, texSup.y);
+ vertex[2] = D3DVERTEX2(corner[2], n, texSup.x, texInf.y);
+ vertex[3] = D3DVERTEX2(corner[3], n, texInf.x, texInf.y);
+ }
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+ p1 = p2;
+ }
+
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+}
+
+
+// Enclanche les éclairs.
+
+BOOL CBlitz::Create(float sleep, float delay, float magnetic)
+{
+ m_bBlitzExist = TRUE;
+ if ( sleep < 1.0f ) sleep = 1.0f;
+ m_sleep = sleep;
+ m_delay = delay;
+ m_magnetic = magnetic;
+
+ m_phase = BPH_WAIT;
+ m_progress = 0.0f;
+ m_speed = 1.0f/m_sleep;
+
+ if ( m_terrain == 0 )
+ {
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ }
+
+ if ( m_camera == 0 )
+ {
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ }
+
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+
+ return FALSE;
+}
+
+
+// Donne l'état des éclairs.
+
+BOOL CBlitz::GetStatus(float &sleep, float &delay, float &magnetic, float &progress)
+{
+ if ( !m_bBlitzExist ) return FALSE;
+
+ sleep = m_sleep;
+ delay = m_delay;
+ magnetic = m_magnetic;
+ progress = m_progress;
+
+ return TRUE;
+}
+
+// Spécifie l'état des éclairs.
+
+BOOL CBlitz::SetStatus(float sleep, float delay, float magnetic, float progress)
+{
+ m_bBlitzExist = TRUE;
+
+ m_sleep = sleep;
+ m_delay = delay;
+ m_magnetic = magnetic;
+ m_progress = progress;
+ m_phase = BPH_WAIT;
+ m_speed = 1.0f/m_sleep;
+
+ return TRUE;
+}
+
+
+// Cherche l'objet le plus proche de l'éclair.
+
+CObject* CBlitz::SearchObject(D3DVECTOR pos)
+{
+ CObject *pObj, *pBest, *pObjPara[100];
+ D3DVECTOR oPos, pPos[100];
+ ObjectType type;
+ float min, dist, detect;
+ int i, nbPara;
+
+ // Cherche l'objet le plus proche du point d'impact de la foudre.
+ pBest = 0;
+ min = 100000.0f;
+ nbPara = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // objet inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+
+ type = pObj->RetType();
+ if ( type == OBJECT_BASE ||
+ type == OBJECT_PARA ) // bâtiment à effet paratonnerre ?
+ {
+ pObjPara[nbPara] = pObj;
+ pPos[nbPara] = pObj->RetPosition(0);
+ nbPara ++;
+ }
+
+ detect = 0.0f;
+ if ( type == OBJECT_BASE ||
+ 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 )
+ {
+ detect = m_magnetic;
+ }
+ if ( type == OBJECT_METAL ||
+ type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC )
+ {
+ detect = m_magnetic*0.3f;
+ }
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr )
+ {
+ detect = m_magnetic*0.5f;
+ }
+ if ( detect == 0.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, pos);
+ if ( dist > detect ) continue;
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+ if ( pBest == 0 ) return 0; // rien trouvé
+
+ // Sous la protection d'un paratonnerre ?
+ oPos = pBest->RetPosition(0);
+ for ( i=nbPara-1 ; i>=0 ; i-- )
+ {
+ dist = Length2d(oPos, pPos[i]);
+ if ( dist <= BLITZPARA )
+ {
+ return pObjPara[i];
+ }
+ }
+ return pBest;
+}
+
diff --git a/src/blitz.h b/src/blitz.h
new file mode 100644
index 0000000..df6e70e
--- /dev/null
+++ b/src/blitz.h
@@ -0,0 +1,64 @@
+// blitz.h
+
+#ifndef _BLITZ_H_
+#define _BLITZ_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CTerrain;
+class CCamera;
+class CSound;
+
+
+
+#define BLITZPARA 200.0f // rayon de protection du paratonnerre
+#define BLITZMAX 50
+
+enum BlitzPhase
+{
+ BPH_WAIT,
+ BPH_BLITZ,
+};
+
+
+
+class CBlitz
+{
+public:
+ CBlitz(CInstanceManager* iMan, CD3DEngine* engine);
+ ~CBlitz();
+
+ void Flush();
+ BOOL EventProcess(const Event &event);
+ BOOL Create(float sleep, float delay, float magnetic);
+ BOOL GetStatus(float &sleep, float &delay, float &magnetic, float &progress);
+ BOOL SetStatus(float sleep, float delay, float magnetic, float progress);
+ void Draw();
+
+protected:
+ BOOL EventFrame(const Event &event);
+ CObject* SearchObject(D3DVECTOR pos);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CTerrain* m_terrain;
+ CCamera* m_camera;
+ CSound* m_sound;
+
+ BOOL m_bBlitzExist;
+ float m_sleep;
+ float m_delay;
+ float m_magnetic;
+ BlitzPhase m_phase;
+ float m_time;
+ float m_speed;
+ float m_progress;
+ D3DVECTOR m_pos;
+ FPOINT m_shift[BLITZMAX];
+ float m_width[BLITZMAX];
+};
+
+
+#endif //_BLITZ_H_
diff --git a/src/brain.cpp b/src/brain.cpp
new file mode 100644
index 0000000..5155eb2
--- /dev/null
+++ b/src/brain.cpp
@@ -0,0 +1,2985 @@
+// brain.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "cbot/cbotdll.h"
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "robotmain.h"
+#include "terrain.h"
+#include "water.h"
+#include "camera.h"
+#include "object.h"
+#include "physics.h"
+#include "motion.h"
+#include "motionspider.h"
+#include "pyro.h"
+#include "taskmanager.h"
+#include "task.h"
+#include "taskmanip.h"
+#include "taskflag.h"
+#include "taskshield.h"
+#include "script.h"
+#include "studio.h"
+#include "interface.h"
+#include "button.h"
+#include "color.h"
+#include "edit.h"
+#include "list.h"
+#include "label.h"
+#include "group.h"
+#include "gauge.h"
+#include "slider.h"
+#include "compass.h"
+#include "target.h"
+#include "window.h"
+#include "displaytext.h"
+#include "text.h"
+#include "sound.h"
+#include "particule.h"
+#include "cmdtoken.h"
+#include "brain.h"
+
+
+
+#define MAXTRACERECORD 1000
+
+
+
+// Constructeur de l'objet.
+
+CBrain::CBrain(CInstanceManager* iMan, CObject* object)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_BRAIN, this, 100);
+
+ m_object = object;
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_physics = 0;
+ m_motion = 0;
+ m_primaryTask = 0;
+ m_secondaryTask = 0;
+ m_studio = 0;
+
+ m_program = -1;
+ m_bActivity = TRUE;
+ m_bBurn = FALSE;
+ m_bActiveVirus = FALSE;
+ m_time = 0.0f;
+ m_burnTime = 0.0f;
+ m_lastUpdateTime = 0.0f;
+ m_lastHumanTime = 0.0f;
+ m_lastWormTime = 0.0f;
+ m_antTarget = 0;
+ m_beeBullet = 0;
+ m_lastAlarmTime = 0.0f;
+ m_soundChannelAlarm = -1;
+ m_flagColor = 0;
+
+ m_buttonAxe = EVENT_NULL;
+ m_defaultEnter = EVENT_NULL;
+ m_manipStyle = EVENT_OBJECT_MFRONT;
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ m_script[i] = 0;
+ m_scriptName[i][0] = 0;
+ }
+ m_scriptRun = -1;
+ m_soluceName[0] = 0;
+ m_selScript = 0;
+
+ m_bTraceRecord = FALSE;
+ m_traceRecordBuffer = 0;
+}
+
+// Destructeur de l'objet.
+
+CBrain::~CBrain()
+{
+ int i;
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ delete m_script[i];
+ }
+
+ delete m_primaryTask;
+ delete m_secondaryTask;
+ delete m_studio;
+ delete m_traceRecordBuffer;
+ m_iMan->DeleteInstance(CLASS_BRAIN, this);
+}
+
+
+// Détruit l'objet.
+
+void CBrain::DeleteObject(BOOL bAll)
+{
+ if ( m_soundChannelAlarm != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannelAlarm);
+ m_sound->AddEnvelope(m_soundChannelAlarm, 0.0f, 0.5f, 0.5f, SOPER_STOP);
+ m_soundChannelAlarm = -1;
+ }
+
+ if ( !bAll )
+ {
+ if ( m_beeBullet != 0 )
+ {
+ m_beeBullet->DeleteObject();
+ delete m_beeBullet;
+ m_beeBullet = 0;
+ }
+ }
+
+ if ( m_studio != 0 ) // édition en cours ?
+ {
+ StopEditScript(TRUE);
+ }
+}
+
+
+void CBrain::SetPhysics(CPhysics* physics)
+{
+ m_physics = physics;
+}
+
+void CBrain::SetMotion(CMotion* motion)
+{
+ m_motion = motion;
+}
+
+
+// Sauve tous les paramètres de l'objet.
+
+BOOL CBrain::Write(char *line)
+{
+ char name[100];
+
+ sprintf(name, " bVirusActive=%d", m_bActiveVirus);
+ strcat(line, name);
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'objet.
+
+BOOL CBrain::Read(char *line)
+{
+ m_bActiveVirus = OpInt(line, "bVirusActive", 0);
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CBrain::EventProcess(const Event &event)
+{
+ CWindow* pw;
+ CControl* pc;
+ CSlider* ps;
+ EventMsg action;
+ ObjectType type;
+ Error err;
+ float axeX, axeY, axeZ, factor;
+
+ type = m_object->RetType();
+
+ if ( m_primaryTask != 0 ) // tâche en cours ?
+ {
+ m_primaryTask->EventProcess(event);
+ }
+
+ if ( m_secondaryTask != 0 ) // tâche en cours ?
+ {
+ m_secondaryTask->EventProcess(event);
+ }
+
+ action = EVENT_NULL;
+
+ if ( event.event == EVENT_KEYDOWN &&
+ (event.param == m_engine->RetKey(KEYRANK_ACTION, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_ACTION, 1) ) &&
+ !m_main->RetEditLock() )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 )
+ {
+ pc = pw->SearchControl(m_defaultEnter);
+ if ( pc != 0 )
+ {
+ if ( pc->TestState(STATE_ENABLE) )
+ {
+ action = m_defaultEnter;
+ }
+ }
+ }
+ }
+ else
+ {
+ action = event.event;
+ }
+
+ if ( action == EVENT_NULL ) return TRUE;
+
+ if ( action == EVENT_UPDINTERFACE )
+ {
+ if ( m_object->RetSelect() ) CreateInterface(TRUE);
+ }
+
+ if ( action == EVENT_FRAME )
+ {
+ EventFrame(event);
+ }
+
+ if ( m_object->RetSelect() && // robot sélectionné ?
+ m_studio != 0 ) // édition en cours ?
+ {
+ m_studio->EventProcess(event);
+
+ if ( action == EVENT_OBJECT_PROGRUN )
+ {
+ if ( m_program == -1 )
+ {
+ RunProgram(m_selScript);
+ }
+ else
+ {
+ StopProgram();
+ }
+ }
+ if ( action == EVENT_OBJECT_PROGSTART )
+ {
+ m_main->SaveOneScript(m_object);
+ RunProgram(m_selScript);
+ }
+ if ( action == EVENT_OBJECT_PROGSTOP )
+ {
+ StopProgram();
+ }
+ if ( action == EVENT_STUDIO_OK )
+ {
+ StopEditScript(FALSE);
+ m_main->SaveOneScript(m_object);
+ }
+ if ( action == EVENT_STUDIO_CANCEL )
+ {
+ StopEditScript(TRUE);
+ m_main->SaveOneScript(m_object);
+ }
+ return TRUE;
+ }
+
+ if ( !m_object->RetSelect() && // robot pas sélectionné ?
+ m_program == -1 &&
+ m_primaryTask == 0 )
+ {
+ axeX = 0.0f;
+ axeY = 0.0f;
+ axeZ = 0.0f;
+ if ( m_object->RetBurn() ) // brûle ?
+ {
+ if ( !m_bBurn ) // début ?
+ {
+ m_bBurn = TRUE;
+ m_burnTime = 0.0f;
+ }
+
+ axeZ = -1.0f; // tombe
+
+ if ( !m_object->RetFixed() &&
+ (type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_WORM ) )
+ {
+ axeY = 2.0f; // zig-zag désordonné rapide
+ if ( type == OBJECT_WORM ) axeY = 5.0f;
+ axeX = 0.5f+sinf(m_time* 1.0f)*0.5f+
+ sinf(m_time* 6.0f)*2.0f+
+ sinf(m_time*21.0f)*0.2f;
+ factor = 1.0f-m_burnTime/15.0f; // ralenti
+ if ( factor < 0.0f ) factor = 0.0f;
+ axeY *= factor;
+ axeX *= factor;
+ }
+ }
+ m_physics->SetMotorSpeedX(axeY); // avancer/reculer
+ m_physics->SetMotorSpeedY(axeZ); // monter/descendre
+ m_physics->SetMotorSpeedZ(axeX); // tourner
+ return TRUE;
+ }
+
+ if ( m_program != -1 &&
+ m_object->RetRuin() )
+ {
+ StopProgram();
+ return TRUE;
+ }
+
+ if ( !m_object->RetSelect() ) // robot pas sélectionné ?
+ {
+ return TRUE;
+ }
+
+ if ( m_secondaryTask != 0 ) // tâche en cours ?
+ {
+ if ( action == EVENT_OBJECT_ENDSHIELD )
+ {
+ m_secondaryTask->StartTaskShield(TSM_DOWN, 0.0f);
+ }
+ }
+ if ( m_primaryTask != 0 || // tâche en cours ?
+ m_program != -1 )
+ {
+ if ( action == EVENT_OBJECT_PROGRUN )
+ {
+ StopProgram();
+ }
+ if ( action == EVENT_OBJECT_PROGEDIT )
+ {
+ StartEditScript(m_selScript, m_main->RetScriptName());
+ }
+ if ( m_primaryTask == 0 || !m_primaryTask->IsPilot() ) return TRUE;
+ }
+
+ if ( action == EVENT_OBJECT_LEFT ||
+ action == EVENT_OBJECT_RIGHT ||
+ action == EVENT_OBJECT_UP ||
+ action == EVENT_OBJECT_DOWN ||
+ action == EVENT_OBJECT_GASUP ||
+ action == EVENT_OBJECT_GASDOWN )
+ {
+ m_buttonAxe = action;
+ }
+ if ( action == EVENT_LBUTTONUP ||
+ action == EVENT_RBUTTONUP )
+ {
+ m_buttonAxe = EVENT_NULL;
+ }
+
+ axeX = event.axeX;
+ axeY = event.axeY;
+ axeZ = event.axeZ;
+
+ if ( !m_main->RetTrainerPilot() &&
+ m_object->RetTrainer() ) // véhicule d'entraînement ?
+ {
+ axeX = 0.0f;
+ axeY = 0.0f;
+ axeZ = 0.0f; // télécommande impossible !
+ }
+
+ if ( m_buttonAxe == EVENT_OBJECT_LEFT ) axeX = -1.0f;
+ if ( m_buttonAxe == EVENT_OBJECT_RIGHT ) axeX = 1.0f;
+ if ( m_buttonAxe == EVENT_OBJECT_UP ) axeY = 1.0f;
+ if ( m_buttonAxe == EVENT_OBJECT_DOWN ) axeY = -1.0f;
+ if ( m_buttonAxe == EVENT_OBJECT_GASUP ) axeZ = 1.0f;
+ if ( m_buttonAxe == EVENT_OBJECT_GASDOWN ) axeZ = -1.0f;
+
+ if ( m_object->RetManual() ) // scribbler en mode manuel ?
+ {
+ if ( axeX != 0.0f ) axeY = 0.0f; // si tourne -> n'avance pas !
+ axeX *= 0.5f;
+ axeY *= 0.5f;
+ }
+
+ if ( (g_researchDone&RESEARCH_FLY) == 0 )
+ {
+ axeZ = -1.0f; // tombe
+ }
+
+ axeX += m_camera->RetMotorTurn(); // force additionnelle selon caméra
+ if ( axeX > 1.0f ) axeX = 1.0f;
+ if ( axeX < -1.0f ) axeX = -1.0f;
+
+ m_physics->SetMotorSpeedX(axeY); // avancer/reculer
+ m_physics->SetMotorSpeedY(axeZ); // monter/descendre
+ m_physics->SetMotorSpeedZ(axeX); // tourner
+
+ if ( action == EVENT_OBJECT_PROGLIST )
+ {
+ m_selScript = RetSelScript();
+ UpdateInterface();
+ }
+
+ if ( action == EVENT_OBJECT_PROGEDIT )
+ {
+ StartEditScript(m_selScript, m_main->RetScriptName());
+ }
+
+ if ( action == EVENT_OBJECT_PROGRUN )
+ {
+ StopProgram(); // stoppe programme en cours
+ RunProgram(m_selScript);
+ UpdateInterface();
+ }
+
+ err = ERR_OK;
+
+ if ( m_program == -1 )
+ {
+ if ( action == EVENT_OBJECT_HTAKE )
+ {
+ err = StartTaskTake();
+ }
+
+ if ( action == EVENT_OBJECT_MFRONT ||
+ action == EVENT_OBJECT_MBACK ||
+ action == EVENT_OBJECT_MPOWER )
+ {
+ m_manipStyle = action;
+ UpdateInterface();
+ }
+
+ if ( action == EVENT_OBJECT_MTAKE )
+ {
+ if ( m_manipStyle == EVENT_OBJECT_MFRONT )
+ {
+ err = StartTaskManip(TMO_AUTO, TMA_FFRONT);
+ }
+ if ( m_manipStyle == EVENT_OBJECT_MBACK )
+ {
+ err = StartTaskManip(TMO_AUTO, TMA_FBACK);
+ if ( err == ERR_OK )
+ {
+ m_manipStyle = EVENT_OBJECT_MFRONT;
+ UpdateInterface();
+ }
+ }
+ if ( m_manipStyle == EVENT_OBJECT_MPOWER )
+ {
+ err = StartTaskManip(TMO_AUTO, TMA_POWER);
+ if ( err == ERR_OK )
+ {
+ m_manipStyle = EVENT_OBJECT_MFRONT;
+ UpdateInterface();
+ }
+ }
+ }
+
+ if ( action == EVENT_OBJECT_BDERRICK )
+ {
+ err = StartTaskBuild(OBJECT_DERRICK);
+ }
+ if ( action == EVENT_OBJECT_BSTATION )
+ {
+ err = StartTaskBuild(OBJECT_STATION);
+ }
+ if ( action == EVENT_OBJECT_BFACTORY )
+ {
+ err = StartTaskBuild(OBJECT_FACTORY);
+ }
+ if ( action == EVENT_OBJECT_BREPAIR )
+ {
+ err = StartTaskBuild(OBJECT_REPAIR);
+ }
+ if ( action == EVENT_OBJECT_BCONVERT )
+ {
+ err = StartTaskBuild(OBJECT_CONVERT);
+ }
+ if ( action == EVENT_OBJECT_BTOWER )
+ {
+ err = StartTaskBuild(OBJECT_TOWER);
+ }
+ if ( action == EVENT_OBJECT_BRESEARCH )
+ {
+ err = StartTaskBuild(OBJECT_RESEARCH);
+ }
+ if ( action == EVENT_OBJECT_BRADAR )
+ {
+ err = StartTaskBuild(OBJECT_RADAR);
+ }
+ if ( action == EVENT_OBJECT_BENERGY )
+ {
+ err = StartTaskBuild(OBJECT_ENERGY);
+ }
+ if ( action == EVENT_OBJECT_BLABO )
+ {
+ err = StartTaskBuild(OBJECT_LABO);
+ }
+ if ( action == EVENT_OBJECT_BNUCLEAR )
+ {
+ err = StartTaskBuild(OBJECT_NUCLEAR);
+ }
+ if ( action == EVENT_OBJECT_BPARA )
+ {
+ err = StartTaskBuild(OBJECT_PARA);
+ }
+ if ( action == EVENT_OBJECT_BINFO )
+ {
+ err = StartTaskBuild(OBJECT_INFO);
+ }
+
+ if ( action == EVENT_OBJECT_GFLAT )
+ {
+ GroundFlat();
+ }
+ if ( action == EVENT_OBJECT_FCREATE )
+ {
+ err = StartTaskFlag(TFL_CREATE, m_flagColor);
+ }
+ if ( action == EVENT_OBJECT_FDELETE )
+ {
+ err = StartTaskFlag(TFL_DELETE, m_flagColor);
+ }
+ if ( action == EVENT_OBJECT_FCOLORb ||
+ action == EVENT_OBJECT_FCOLORr ||
+ action == EVENT_OBJECT_FCOLORg ||
+ action == EVENT_OBJECT_FCOLORy ||
+ action == EVENT_OBJECT_FCOLORv )
+ {
+ ColorFlag(action-EVENT_OBJECT_FCOLORb);
+ }
+
+ if ( action == EVENT_OBJECT_SEARCH )
+ {
+ err = StartTaskSearch();
+ }
+
+ if ( action == EVENT_OBJECT_TERRAFORM )
+ {
+ err = StartTaskTerraform();
+ }
+
+ if ( action == EVENT_OBJECT_RECOVER )
+ {
+ err = StartTaskRecover();
+ }
+
+ if ( action == EVENT_OBJECT_BEGSHIELD )
+ {
+ err = StartTaskShield(TSM_UP);
+ }
+
+ if ( action == EVENT_OBJECT_DIMSHIELD )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 )
+ {
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_DIMSHIELD);
+ if ( ps != 0 )
+ {
+ m_object->SetParam((ps->RetVisibleValue()-(RADIUS_SHIELD_MIN/g_unit))/((RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)/g_unit));
+ }
+ }
+ }
+
+ if ( action == EVENT_OBJECT_FIRE && m_primaryTask == 0 && !m_object->RetTrainer())
+ {
+ if ( m_camera->RetType() != CAMERA_ONBOARD )
+ {
+ m_camera->SetType(CAMERA_ONBOARD);
+ }
+ err = StartTaskFire(0.0f);
+ }
+ if ( action == EVENT_OBJECT_TARGET && !m_object->RetTrainer() )
+ {
+ err = StartTaskGunGoal((event.pos.y-0.50f)*1.3f, (event.pos.x-0.50f)*2.0f);
+ }
+
+ if ( action == EVENT_OBJECT_FIREANT )
+ {
+//? err = StartTaskFireAnt();
+ }
+
+ if ( action == EVENT_OBJECT_PEN0 ) // up
+ {
+ err = StartTaskPen(FALSE, m_object->RetTraceColor());
+ m_object->SetTraceDown(FALSE);
+ }
+ if ( action == EVENT_OBJECT_PEN1 ) // noir
+ {
+ err = StartTaskPen(TRUE, 1);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(1);
+ }
+ if ( action == EVENT_OBJECT_PEN2 ) // jaune
+ {
+ err = StartTaskPen(TRUE, 8);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(8);
+ }
+ if ( action == EVENT_OBJECT_PEN3 ) // orange
+ {
+ err = StartTaskPen(TRUE, 7);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(7);
+ }
+ if ( action == EVENT_OBJECT_PEN4 ) // rouge
+ {
+ err = StartTaskPen(TRUE, 4);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(4);
+ }
+ if ( action == EVENT_OBJECT_PEN5 ) // violet
+ {
+ err = StartTaskPen(TRUE, 6);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(6);
+ }
+ if ( action == EVENT_OBJECT_PEN6 ) // bleu
+ {
+ err = StartTaskPen(TRUE, 14);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(14);
+ }
+ if ( action == EVENT_OBJECT_PEN7 ) // vert
+ {
+ err = StartTaskPen(TRUE, 12);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(12);
+ }
+ if ( action == EVENT_OBJECT_PEN8 ) // brun
+ {
+ err = StartTaskPen(TRUE, 10);
+ m_object->SetTraceDown(TRUE);
+ m_object->SetTraceColor(10);
+ }
+
+ if ( action == EVENT_OBJECT_REC ) // enregistre ?
+ {
+ if ( m_bTraceRecord )
+ {
+ m_bTraceRecord = FALSE;
+ TraceRecordStop();
+ }
+ else
+ {
+ m_bTraceRecord = TRUE;
+ TraceRecordStart();
+ }
+ UpdateInterface();
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 )
+ {
+ UpdateScript(pw);
+ }
+ }
+ if ( action == EVENT_OBJECT_STOP ) // stoppe ?
+ {
+ if ( m_bTraceRecord )
+ {
+ m_bTraceRecord = FALSE;
+ TraceRecordStop();
+ }
+ UpdateInterface();
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 )
+ {
+ UpdateScript(pw);
+ }
+ }
+
+ if ( action == EVENT_OBJECT_RESET )
+ {
+ m_main->ResetObject(); // reset tous les objets
+ UpdateInterface();
+ }
+
+#if 0
+ if ( event.param == 'T' )
+ {
+ D3DVECTOR p1, p2;
+ float h;
+ p1 = m_object->RetPosition(0);
+ h = m_terrain->RetFloorLevel(p1);
+ p2 = p1;
+ p1.x -= 20.0f;
+ p1.z -= 20.0f;
+ p2.x += 20.0f;
+ p2.z += 20.0f;
+ m_terrain->Terraform(p1, p2, h+1.0f);
+ }
+ if ( event.param == 'R' )
+ {
+ D3DVECTOR p1, p2;
+ float h;
+ p1 = m_object->RetPosition(0);
+ h = m_terrain->RetFloorLevel(p1);
+ p2 = p1;
+ p1.x -= 20.0f;
+ p1.z -= 20.0f;
+ p2.x += 20.0f;
+ p2.z += 20.0f;
+ m_terrain->Terraform(p1, p2, h-1.0f);
+ }
+#endif
+ }
+
+ if ( err != ERR_OK )
+ {
+ m_displayText->DisplayError(err, m_object);
+ }
+
+ return TRUE;
+}
+
+
+// Fait évoluer le cerveau selon le temps écoulé.
+
+BOOL CBrain::EventFrame(const Event &event)
+{
+ m_time += event.rTime;
+ if ( m_bBurn ) m_burnTime += event.rTime;
+
+ if ( m_soundChannelAlarm != -1 )
+ {
+ m_sound->Position(m_soundChannelAlarm, m_object->RetPosition(0));
+ }
+
+ if ( m_studio != 0 ) // édition en cours ?
+ {
+ m_studio->EventProcess(event);
+ }
+
+ UpdateInterface(event.rTime);
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( !m_bActivity ) return TRUE; // attend si inactif
+ if ( EndedTask() == ERR_CONTINUE ) return TRUE; // attend si pas fini ...
+
+ if ( m_program != -1 ) // programme en cours ?
+ {
+ if ( m_script[m_program]->Continue(event) )
+ {
+ StopProgram();
+ }
+ }
+
+ if ( m_bTraceRecord ) // enregistrement du dessin en cours ?
+ {
+ TraceRecordFrame();
+ }
+
+ return TRUE;
+}
+
+
+// Stoppe le programme en cours.
+
+void CBrain::StopProgram()
+{
+ StopTask();
+
+ if ( m_object->RetType() == OBJECT_HUMAN ||
+ m_object->RetType() == OBJECT_TECH ) return;
+
+ if ( m_program != -1 &&
+ m_script[m_program] != 0 )
+ {
+ m_script[m_program]->Stop();
+ }
+
+ BlinkScript(FALSE); // ne clignotte plus
+
+ m_program = -1;
+
+ m_physics->SetMotorSpeedX(0.0f);
+ m_physics->SetMotorSpeedY(0.0f);
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ m_motion->SetAction(-1);
+
+ UpdateInterface();
+ m_main->UpdateShortcuts();
+ m_object->CreateSelectParticule();
+}
+
+// Stoppe la tâche en cours.
+
+void CBrain::StopTask()
+{
+ if ( m_primaryTask != 0 )
+ {
+ m_primaryTask->Abort();
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+}
+
+
+// Introduit un virus dans un programme.
+// Retourne TRUE s'il a été introduit.
+
+BOOL CBrain::IntroduceVirus()
+{
+ int i, j;
+
+ for ( i=0 ; i<50 ; i++ )
+ {
+ j = rand()%BRAINMAXSCRIPT;
+ if ( m_script[j] != 0 )
+ {
+ if ( m_script[j]->IntroduceVirus() ) // essaye d'introduire
+ {
+ m_bActiveVirus = TRUE; // virus actif
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+// ActiveVirus indique que l'objet est contaminé. Contrairement aux
+// chtites lettres qui disparaissent automatiquement après un certain
+// temps, ActiveVirus ne disparaît qu'après avoir édité le programme
+// (même si le virus n'est pas corrigé).
+
+void CBrain::SetActiveVirus(BOOL bActive)
+{
+ m_bActiveVirus = bActive;
+
+ if ( !m_bActiveVirus ) // virus désactivé ?
+ {
+ m_object->SetVirusMode(FALSE); // chtites lettres aussi
+ }
+}
+
+BOOL CBrain::RetActiveVirus()
+{
+ return m_bActiveVirus;
+}
+
+
+// Début de l'édition d'un programme.
+
+void CBrain::StartEditScript(int rank, char* name)
+{
+ CreateInterface(FALSE); // supprime les boutons de commande
+
+ if ( m_script[rank] == 0 )
+ {
+ m_script[rank] = new CScript(m_iMan, m_object, &m_secondaryTask);
+ }
+
+ m_studio = new CStudio(m_iMan);
+ m_studio->StartEditScript(m_script[rank], name, rank);
+}
+
+// Fin de l'édition d'un programme.
+
+void CBrain::StopEditScript(BOOL bCancel)
+{
+ if ( !bCancel ) SetActiveVirus(FALSE);
+
+ if ( !m_studio->StopEditScript(bCancel) ) return;
+
+ delete m_studio;
+ m_studio = 0;
+
+ CreateInterface(TRUE); // remet les boutons de commande
+}
+
+
+
+// Bouge le bras manipulateur.
+
+Error CBrain::StartTaskTake()
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskTake();
+ UpdateInterface();
+ return err;
+}
+
+// Bouge le bras manipulateur.
+
+Error CBrain::StartTaskManip(TaskManipOrder order, TaskManipArm arm)
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskManip(order, arm);
+ UpdateInterface();
+ return err;
+}
+
+// Met ou enlève un drapeau.
+
+Error CBrain::StartTaskFlag(TaskFlagOrder order, int rank)
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskFlag(order, rank);
+ UpdateInterface();
+ return err;
+}
+
+// Construit un batiment.
+
+Error CBrain::StartTaskBuild(ObjectType type)
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskBuild(type);
+ UpdateInterface();
+ return err;
+}
+
+// Sonde le sol.
+
+Error CBrain::StartTaskSearch()
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskSearch();
+ UpdateInterface();
+ return err;
+}
+
+// Terraforme le sol.
+
+Error CBrain::StartTaskTerraform()
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskTerraform();
+ UpdateInterface();
+ return err;
+}
+
+// Change de crayon.
+
+Error CBrain::StartTaskPen(BOOL bDown, int color)
+{
+ Error err;
+
+ m_physics->SetMotorSpeedX(0.0f);
+ m_physics->SetMotorSpeedY(0.0f);
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskPen(bDown, color);
+ UpdateInterface();
+ return err;
+}
+
+// Récupère une ruine.
+
+Error CBrain::StartTaskRecover()
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskRecover();
+ UpdateInterface();
+ return err;
+}
+
+// Déploie le bouclier.
+
+Error CBrain::StartTaskShield(TaskShieldMode mode)
+{
+ Error err;
+
+ if ( m_secondaryTask != 0 )
+ {
+ delete m_secondaryTask; // stoppe la tâche en cours
+ m_secondaryTask = 0;
+ }
+
+ m_secondaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_secondaryTask->StartTaskShield(mode, 1000.0f);
+ UpdateInterface();
+ return err;
+}
+
+// Tire.
+
+Error CBrain::StartTaskFire(float delay)
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskFire(delay);
+ UpdateInterface();
+ return err;
+}
+
+// Tire avec la fourmi.
+
+Error CBrain::StartTaskFireAnt(D3DVECTOR impact)
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskFireAnt(impact);
+ UpdateInterface();
+ return err;
+}
+
+// Ajuste la hausse.
+
+Error CBrain::StartTaskGunGoal(float dirV, float dirH)
+{
+ Error err;
+
+ if ( m_secondaryTask != 0 )
+ {
+ delete m_secondaryTask; // stoppe la tâche en cours
+ m_secondaryTask = 0;
+ }
+
+ m_secondaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_secondaryTask->StartTaskGunGoal(dirV, dirH);
+ UpdateInterface();
+ return err;
+}
+
+// Reset.
+
+Error CBrain::StartTaskReset(D3DVECTOR goal, D3DVECTOR angle)
+{
+ Error err;
+
+ if ( m_primaryTask != 0 )
+ {
+ delete m_primaryTask; // stoppe la tâche en cours
+ m_primaryTask = 0;
+ }
+
+ m_primaryTask = new CTaskManager(m_iMan, m_object);
+ err = m_primaryTask->StartTaskReset(goal, angle);
+ UpdateInterface();
+ return err;
+}
+
+// Termine la tâche lorsque le moment est venu.
+
+Error CBrain::EndedTask()
+{
+ Error err;
+
+ if ( m_secondaryTask != 0 ) // tâche en cours ?
+ {
+ err = m_secondaryTask->IsEnded();
+ if ( err != ERR_CONTINUE ) // tâche terminée ?
+ {
+ delete m_secondaryTask;
+ m_secondaryTask = 0;
+ UpdateInterface();
+ }
+ }
+
+ if ( m_primaryTask != 0 ) // tâche en cours ?
+ {
+ err = m_primaryTask->IsEnded();
+ if ( err != ERR_CONTINUE ) // tâche terminée ?
+ {
+ delete m_primaryTask;
+ m_primaryTask = 0;
+ UpdateInterface();
+ }
+ return err;
+ }
+ return ERR_STOP;
+}
+
+
+
+// Montre les zones plates dans le terrain.
+
+void CBrain::GroundFlat()
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ Error err;
+ float level;
+
+ if ( !m_physics->RetLand() )
+ {
+ err = ERR_FLAG_FLY;
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel() ) err = ERR_FLAG_WATER;
+ m_displayText->DisplayError(err, m_object);
+ return;
+ }
+
+ pos = m_object->RetPosition(0);
+ m_terrain->GroundFlat(pos);
+ m_sound->Play(SOUND_GFLAT, pos);
+
+ level = m_terrain->RetFloorLevel(pos)+2.0f;
+ if ( pos.y < level ) pos.y = level; // pas en-dessous du sol
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 40.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGFLAT, 1.0f);
+}
+
+
+// Choix de la couleur pour un indicateur de couleur.
+
+void CBrain::ColorFlag(int color)
+{
+ m_flagColor = color;
+ UpdateInterface();
+}
+
+
+// Crée toute l'interface lorsque l'objet est sélectionné.
+
+BOOL CBrain::CreateInterface(BOOL bSelect)
+{
+ ObjectType type;
+ CWindow* pw;
+ CButton* pb;
+ CColor* pc;
+ CSlider* ps;
+ CTarget* pt;
+ CLabel* pl;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+ char name[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 )
+ {
+ pw->Flush(); // détruit les boutons de la fenêtre
+ m_interface->DeleteControl(EVENT_WINDOW0); // détruit la fenêtre
+ }
+ m_defaultEnter = EVENT_NULL;
+
+ if ( !bSelect ) return TRUE;
+
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ dim.x = 540.0f/640.0f;
+ if ( !m_main->RetShowMap() ) dim.x = 640.0f/640.0f;
+ dim.y = 86.0f/480.0f;
+ m_interface->CreateWindows(pos, dim, 3, EVENT_WINDOW0);
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return FALSE;
+
+ m_object->GetTooltipName(name);
+ pos.x = 0.0f;
+ pos.y = 64.0f/480.0f;
+ ddim.x = 540.0f/640.0f;
+ if ( !m_main->RetShowMap() ) ddim.x = 640.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pw->CreateLabel(pos, ddim, 0, EVENT_LABEL0, name);
+
+ dim.x = 33.0f/640.0f;
+ dim.y = 33.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = 33.0f/640.0f;
+ sy = 33.0f/480.0f;
+
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ) // véhicule ?
+ {
+ ddim.x = dim.x*5.1f;
+ ddim.y = dim.y*2.0f;
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0.0f;
+ pw->CreateList(pos, ddim, -1, EVENT_OBJECT_PROGLIST, 1.10f);
+ UpdateScript(pw);
+
+ pos.x = ox+sx*5.2f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, dim, 8, EVENT_OBJECT_PROGRUN);
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, dim, 22, EVENT_OBJECT_PROGEDIT);
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_BEE ) // volant ?
+ {
+ pos.x = ox+sx*6.4f;
+ pos.y = oy+sy*0;
+ pb = pw->CreateButton(pos, dim, 29, EVENT_OBJECT_GASDOWN);
+ pb->SetImmediat(TRUE);
+
+ pos.x = ox+sx*6.4f;
+ pos.y = oy+sy*1;
+ pb = pw->CreateButton(pos, dim, 28, EVENT_OBJECT_GASUP);
+ pb->SetImmediat(TRUE);
+
+ if ( type != OBJECT_HUMAN ||
+ m_object->RetOption() != 2 )
+ {
+ pos.x = ox+sx*15.3f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 2, EVENT_OBJECT_GRANGE);
+ }
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 31, EVENT_OBJECT_HTAKE);
+ DefaultEnter(pw, EVENT_OBJECT_HTAKE);
+ }
+
+ if ( (type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ) && // bras ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 32, EVENT_OBJECT_MTAKE);
+ DefaultEnter(pw, EVENT_OBJECT_MTAKE);
+
+ pos.x = ox+sx*8.9f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 34, EVENT_OBJECT_MBACK);
+
+ pos.x = ox+sx*9.9f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 35, EVENT_OBJECT_MPOWER);
+
+ pos.x = ox+sx*10.9f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 33, EVENT_OBJECT_MFRONT);
+ }
+
+ if ( type == OBJECT_MOBILEsa && // sous-marin ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 32, EVENT_OBJECT_MTAKE);
+ DefaultEnter(pw, EVENT_OBJECT_MTAKE);
+ }
+
+ if ( type == OBJECT_HUMAN ) // constructeur ?
+ {
+ pos.x = 1.0f/640.0f;
+ pos.y = 4.0f/480.0f;
+ ddim.x = 212.0f/640.0f;
+ ddim.y = 64.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 27, EVENT_NULL);
+
+ ddim.x = dim.x*0.9f;
+ ddim.y = dim.y*0.9f;
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+35, EVENT_OBJECT_BRESEARCH);
+ DeadInterface(pw, EVENT_OBJECT_BRESEARCH, g_build&BUILD_RESEARCH);
+
+ pos.x = ox+sx*0.9f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+32, EVENT_OBJECT_BFACTORY);
+ DeadInterface(pw, EVENT_OBJECT_BFACTORY, g_build&BUILD_FACTORY);
+
+ pos.x = ox+sx*1.8f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+34, EVENT_OBJECT_BCONVERT);
+ DeadInterface(pw, EVENT_OBJECT_BCONVERT, g_build&BUILD_CONVERT);
+
+ pos.x = ox+sx*2.7f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+36, EVENT_OBJECT_BSTATION);
+ DeadInterface(pw, EVENT_OBJECT_BSTATION, g_build&BUILD_STATION);
+
+ pos.x = ox+sx*3.6f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+40, EVENT_OBJECT_BRADAR);
+ DeadInterface(pw, EVENT_OBJECT_BRADAR, g_build&BUILD_RADAR);
+
+ pos.x = ox+sx*4.5f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+41, EVENT_OBJECT_BREPAIR);
+ DeadInterface(pw, EVENT_OBJECT_BREPAIR, g_build&BUILD_REPAIR);
+
+ pos.x = ox+sx*5.4f;
+ pos.y = oy+sy*1.0f;
+ pw->CreateButton(pos, ddim, 128+44, EVENT_OBJECT_BINFO);
+ DeadInterface(pw, EVENT_OBJECT_BINFO, g_build&BUILD_INFO);
+
+ pos.x = ox+sx*0.0f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+37, EVENT_OBJECT_BTOWER);
+ DeadInterface(pw, EVENT_OBJECT_BTOWER,
+ (g_build&BUILD_TOWER) &&
+ (g_researchDone & RESEARCH_TOWER));
+
+ pos.x = ox+sx*0.9f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+39, EVENT_OBJECT_BENERGY);
+ DeadInterface(pw, EVENT_OBJECT_BENERGY, g_build&BUILD_ENERGY);
+
+ pos.x = ox+sx*1.8f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+33, EVENT_OBJECT_BDERRICK);
+ DeadInterface(pw, EVENT_OBJECT_BDERRICK, g_build&BUILD_DERRICK);
+
+ pos.x = ox+sx*2.7f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+42, EVENT_OBJECT_BNUCLEAR);
+ DeadInterface(pw, EVENT_OBJECT_BNUCLEAR,
+ (g_build&BUILD_NUCLEAR) &&
+ (g_researchDone & RESEARCH_ATOMIC));
+
+ pos.x = ox+sx*3.6f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+38, EVENT_OBJECT_BLABO);
+ DeadInterface(pw, EVENT_OBJECT_BLABO, g_build&BUILD_LABO);
+
+ pos.x = ox+sx*4.5f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+46, EVENT_OBJECT_BPARA);
+ DeadInterface(pw, EVENT_OBJECT_BPARA, g_build&BUILD_PARA);
+
+ pos.x = ox+sx*5.4f;
+ pos.y = oy+sy*0.1f;
+ pw->CreateButton(pos, ddim, 128+56, EVENT_OBJECT_BXXXX);
+ DeadInterface(pw, EVENT_OBJECT_BXXXX, FALSE);
+
+ if ( g_build&BUILD_GFLAT )
+ {
+ pos.x = ox+sx*9.0f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 64+47, EVENT_OBJECT_GFLAT);
+ }
+
+ if ( g_build&BUILD_FLAG )
+ {
+ pos.x = ox+sx*10.1f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 64+54, EVENT_OBJECT_FCREATE);
+
+ pos.x = ox+sx*11.1f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 64+55, EVENT_OBJECT_FDELETE);
+
+ ddim.x = dim.x*0.4f;
+ ddim.y = dim.y*0.4f;
+ pos.x = ox+sx*10.1f;
+ pos.y = oy+sy*2.0f-ddim.y;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORb);
+ pc->SetColor(RetColor((D3DCOLOR)0x004890ff));
+ pos.x += ddim.x;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORr);
+ pc->SetColor(RetColor((D3DCOLOR)0x00ff0000));
+ pos.x += ddim.x;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORg);
+ pc->SetColor(RetColor((D3DCOLOR)0x0000ce00));
+ pos.x += ddim.x;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORy);
+ pc->SetColor(RetColor((D3DCOLOR)0x00ffec00));
+ pos.x += ddim.x;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_FCOLORv);
+ pc->SetColor(RetColor((D3DCOLOR)0x00d101fe));
+ }
+ }
+
+ if ( (type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ) && // chercheur ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 40, EVENT_OBJECT_SEARCH);
+ DefaultEnter(pw, EVENT_OBJECT_SEARCH);
+ }
+
+ if ( type == OBJECT_MOBILErt && // terraformeur ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 128+18, EVENT_OBJECT_TERRAFORM);
+ DefaultEnter(pw, EVENT_OBJECT_TERRAFORM);
+
+ pos.x = ox+sx*10.2f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 41, EVENT_OBJECT_LIMIT);
+ }
+
+ if ( type == OBJECT_MOBILErr && // récupérateur ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 128+20, EVENT_OBJECT_RECOVER);
+ DefaultEnter(pw, EVENT_OBJECT_RECOVER);
+ }
+
+ if ( type == OBJECT_MOBILErs && // bouclier ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 39, EVENT_OBJECT_BEGSHIELD);
+ DefaultEnter(pw, EVENT_OBJECT_BEGSHIELD);
+
+ pos.x = ox+sx*9.0f;
+ pos.y = oy+sy*0.5f;
+ pw->CreateButton(pos, dim, 47, EVENT_OBJECT_ENDSHIELD);
+
+//? pos.x = ox+sx*10.2f;
+//? pos.y = oy+sy*0.5f;
+//? pw->CreateButton(pos, dim, 41, EVENT_OBJECT_LIMIT);
+
+ pos.x = ox+sx*10.5f;
+ pos.y = oy+sy*0.0f;
+ ddim.x = dim.x*0.5f;
+ ddim.y = dim.y*2.0f;
+ ps = pw->CreateSlider(pos, ddim, 0, EVENT_OBJECT_DIMSHIELD);
+ ps->SetState(STATE_VALUE);
+ ps->SetLimit((RADIUS_SHIELD_MIN/g_unit), (RADIUS_SHIELD_MAX/g_unit));
+ ps->SetArrowStep(1.0f);
+ }
+
+ if ( (type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILErc ) && // canon ?
+ !m_object->RetTrainer() )
+ {
+ pos.x = ox+sx*7.7f;
+ pos.y = oy+sy*0.5f;
+ pb = pw->CreateButton(pos, dim, 42, EVENT_OBJECT_FIRE);
+ pb->SetImmediat(TRUE);
+ DefaultEnter(pw, EVENT_OBJECT_FIRE);
+
+//? pos.x = ox+sx*10.2f;
+//? pos.y = oy+sy*0.5f;
+//? pw->CreateButton(pos, dim, 41, EVENT_OBJECT_LIMIT);
+ }
+
+ if ( type == OBJECT_MOBILEdr &&
+ m_object->RetManual() ) // scribbler en mode manuel ?
+ {
+ pos.x = ox+sx*6.9f;
+ pos.y = oy+sy*0.0f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = dim.y*2.0f;
+ pw->CreateGroup(pos, ddim, 20, EVENT_NULL); // fond bleu uni
+
+ pos.x = ox+sx*9.3f;
+ pos.y = oy+sy*0.0f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = dim.y*2.0f;
+ pw->CreateGroup(pos, ddim, 20, EVENT_NULL); // fond bleu uni
+
+ pos.x = ox+sx*9.90f;
+ pos.y = oy+sy*0.50f;
+ pw->CreateButton(pos, dim, 43, EVENT_OBJECT_PEN0);
+
+ ddim.x = dim.x*0.5f;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*10.15f;
+ pos.y = oy+sy*1.50f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN1); // noir
+ pc->SetColor(RetColor((D3DCOLOR)0x00000000));
+ pos.x = ox+sx*10.65f;
+ pos.y = oy+sy*1.25f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN2); // jaune
+ pc->SetColor(RetColor((D3DCOLOR)0x00ffff00));
+ pos.x = ox+sx*10.90f;
+ pos.y = oy+sy*0.75f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN3); // orange
+ pc->SetColor(RetColor((D3DCOLOR)0x00ff8800));
+ pos.x = ox+sx*10.65f;
+ pos.y = oy+sy*0.25f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN4); // rouge
+ pc->SetColor(RetColor((D3DCOLOR)0x00ff0000));
+ pos.x = ox+sx*10.15f;
+ pos.y = oy+sy*0.00f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN5); // violet
+ pc->SetColor(RetColor((D3DCOLOR)0x00ff00ff));
+ pos.x = ox+sx*9.65f;
+ pos.y = oy+sy*0.25f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN6); // bleu
+ pc->SetColor(RetColor((D3DCOLOR)0x000066ff));
+ pos.x = ox+sx*9.40f;
+ pos.y = oy+sy*0.75f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN7); // vert
+ pc->SetColor(RetColor((D3DCOLOR)0x0000cc00));
+ pos.x = ox+sx*9.65f;
+ pos.y = oy+sy*1.25f;
+ pc = pw->CreateColor(pos, ddim, -1, EVENT_OBJECT_PEN8); // brun
+ pc->SetColor(RetColor((D3DCOLOR)0x00884400));
+
+ pos.x = ox+sx*6.9f;
+ pos.y = oy+sy*1.2f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = dim.y*0.4f;
+ GetResource(RES_TEXT, RT_INTERFACE_REC, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name);
+ pl->SetFontSize(9.0f);
+
+ pos.x = ox+sx*7.0f;
+ pos.y = oy+sy*0.3f;
+ pw->CreateButton(pos, dim, 44, EVENT_OBJECT_REC);
+ pos.x = ox+sx*8.0f;
+ pos.y = oy+sy*0.3f;
+ pw->CreateButton(pos, dim, 45, EVENT_OBJECT_STOP);
+ }
+
+ if ( m_object->RetToy() )
+ {
+ pos.x = ox+sx*12.1f;
+ pos.y = oy+sy*-0.1f;
+ ddim.x = dim.x*1.2f;
+ ddim.y = dim.y*2.1f;
+ pw->CreateGroup(pos, ddim, 20, EVENT_NULL); // fond bleu uni
+
+ pos.x = ox+sx*12.2f;
+ pos.y = oy+sy*1;
+ pw->CreateGroup(pos, dim, 19, EVENT_NULL); // signe SatCom
+
+ pos.x = ox+sx*12.2f;
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, dim, 128+57, EVENT_OBJECT_BHELP);
+ }
+ else
+ {
+ pos.x = ox+sx*12.3f;
+ pos.y = oy+sy*-0.1f;
+ ddim.x = dim.x*1.0f;
+ ddim.y = dim.y*2.1f;
+ pw->CreateGroup(pos, ddim, 20, EVENT_NULL); // fond bleu uni
+
+ pos.x = ox+sx*12.3f;
+ pos.y = oy+sy*1;
+ pw->CreateGroup(pos, dim, 19, EVENT_NULL); // signe SatCom
+
+ pos.x = ox+sx*12.4f;
+ pos.y = oy+sy*0.5f;
+ ddim.x = dim.x*0.8f;
+ ddim.y = dim.y*0.5f;
+ pw->CreateButton(pos, ddim, 18, EVENT_OBJECT_BHELP);
+ pos.y = oy+sy*0.0f;
+ pw->CreateButton(pos, ddim, 19, EVENT_OBJECT_HELP);
+ }
+
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_TECH &&
+ !m_object->RetCameraLock() )
+ {
+//? if ( m_main->RetShowMap() )
+ if ( TRUE )
+ {
+ pos.x = ox+sx*13.4f;
+ pos.y = oy+sy*1;
+ pw->CreateButton(pos, dim, 13, EVENT_OBJECT_CAMERA);
+ }
+ else
+ {
+ ddim.x = dim.x*0.66f;
+ ddim.y = dim.y*0.66f;
+ pos.x = ox+sx*(17.0f+0.66f);
+ pos.y = oy+sy*0.66f;
+ pw->CreateButton(pos, ddim, 13, EVENT_OBJECT_CAMERA);
+ }
+ }
+
+ if ( m_object->RetToy() && !m_object->RetManual() )
+ {
+#if 0
+ ddim.x = dim.x*0.66f;
+ ddim.y = dim.y*0.66f;
+ pos.x = ox+sx*10.0f;
+ pos.y = oy+sy*0.66f;
+ pb = pw->CreateButton(pos, ddim, 55, EVENT_OBJECT_CAMERAleft);
+ pb->SetImmediat(TRUE);
+ pos.x = ox+sx*(10.0f+0.66f*2.0f);
+ pos.y = oy+sy*0.66f;
+ pb = pw->CreateButton(pos, ddim, 48, EVENT_OBJECT_CAMERAright);
+ pb->SetImmediat(TRUE);
+ pos.x = ox+sx*(10.0f+0.66f);
+ pos.y = oy+sy*(0.66f*2.0f);
+ pb = pw->CreateButton(pos, ddim, 49, EVENT_OBJECT_CAMERAnear);
+ pb->SetImmediat(TRUE);
+ pos.x = ox+sx*(10.0f+0.66f);
+ pos.y = oy+sy*0.0f;
+ pb = pw->CreateButton(pos, ddim, 50, EVENT_OBJECT_CAMERAaway);
+ pb->SetImmediat(TRUE);
+#else
+ pos.x = ox+sx*9.0f;
+ pos.y = oy+sy*0;
+ pb = pw->CreateButton(pos, dim, 55, EVENT_OBJECT_CAMERAleft);
+ pb->SetImmediat(TRUE);
+ pos.x = ox+sx*11.0f;
+ pos.y = oy+sy*0;
+ pb = pw->CreateButton(pos, dim, 48, EVENT_OBJECT_CAMERAright);
+ pb->SetImmediat(TRUE);
+ pos.x = ox+sx*10.0f;
+ pos.y = oy+sy*1;
+ pb = pw->CreateButton(pos, dim, 49, EVENT_OBJECT_CAMERAnear);
+ pb->SetImmediat(TRUE);
+ pos.x = ox+sx*10.0f;
+ pos.y = oy+sy*0;
+ pb = pw->CreateButton(pos, dim, 50, EVENT_OBJECT_CAMERAaway);
+ pb->SetImmediat(TRUE);
+#endif
+ }
+
+ pos.x = ox+sx*13.4f;
+ pos.y = oy+sy*0;
+#if _TEEN
+ pw->CreateButton(pos, dim, 9, EVENT_OBJECT_RESET);
+#else
+ if ( m_object->RetTrainer() ) // entraînement ?
+ {
+ pw->CreateButton(pos, dim, 9, EVENT_OBJECT_RESET);
+ }
+ else
+ {
+ pw->CreateButton(pos, dim, 10, EVENT_OBJECT_DESELECT);
+ }
+#endif
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ) // véhicule ?
+ {
+ pos.x = ox+sx*14.5f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 0, EVENT_OBJECT_GENERGY);
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ) // véhicule ?
+ {
+ pos.x = ox+sx*14.9f;
+ pos.y = oy+sy*0;
+ ddim.x = 14.0f/640.0f;
+ ddim.y = 66.0f/480.0f;
+ pw->CreateGauge(pos, ddim, 3, EVENT_OBJECT_GSHIELD);
+ }
+
+#if 0
+ if ( FALSE )
+ {
+ pos.x = 505.0f/640.0f;
+ pos.y = 3.0f/480.0f;
+ ddim.x = 33.0f/640.0f;
+ ddim.y = 33.0f/480.0f;
+ pw->CreateCompass(pos, ddim, 0, EVENT_OBJECT_COMPASS);
+
+ pc = (CCompass*)pw->SearchControl(EVENT_OBJECT_COMPASS);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_VISIBLE, m_main->RetShowMap());
+ }
+ }
+#endif
+
+ if ( type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILErc ) // canon ?
+ {
+ ddim.x = 64.0f/640.0f;
+ ddim.y = 64.0f/480.0f;
+ pos.x = 0.5f-ddim.x/2.0f;
+ pos.y = 0.5f-ddim.y/2.0f;
+ pw->CreateGroup(pos, ddim, 12, EVENT_OBJECT_CROSSHAIR);
+
+ pos.x = 20.0f/640.0f;
+ pos.y = 100.0f/480.0f;
+ ddim.x = 600.0f/640.0f;
+ ddim.y = 340.0f/480.0f;
+ pt = pw->CreateTarget(pos, ddim, 0, EVENT_OBJECT_TARGET);
+ pt->ClearState(STATE_GLINT);
+ }
+
+ ddim.x = 64.0f/640.0f;
+ ddim.y = 64.0f/480.0f;
+ pos.x = 30.0f/640.0f;
+ pos.y = 430.0f/480.0f-ddim.y;
+ pw->CreateGroup(pos, ddim, 13, EVENT_OBJECT_CORNERul);
+
+ ddim.x = 64.0f/640.0f;
+ ddim.y = 64.0f/480.0f;
+ pos.x = 610.0f/640.0f-ddim.x;
+ pos.y = 430.0f/480.0f-ddim.y;
+ pw->CreateGroup(pos, ddim, 14, EVENT_OBJECT_CORNERur);
+
+ ddim.x = 64.0f/640.0f;
+ ddim.y = 64.0f/480.0f;
+ pos.x = 30.0f/640.0f;
+ pos.y = 110.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 15, EVENT_OBJECT_CORNERdl);
+
+ ddim.x = 64.0f/640.0f;
+ ddim.y = 64.0f/480.0f;
+ pos.x = 610.0f/640.0f-ddim.x;
+ pos.y = 110.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 16, EVENT_OBJECT_CORNERdr);
+
+ UpdateInterface();
+ m_lastUpdateTime = 0.0f;
+ UpdateInterface(0.0f);
+
+ return TRUE;
+}
+
+// Met à jour l'état de tous les boutons de l'interface,
+// suite au temps qui s'écoule ...
+
+void CBrain::UpdateInterface(float rTime)
+{
+ CWindow* pw;
+#if _TEEN
+ CButton* pb;
+#endif
+ CGauge* pg;
+ CCompass* pc;
+ CGroup* pgr;
+ CTarget* ptg;
+ CObject* power;
+ D3DVECTOR pos, hPos;
+ FPOINT ppos;
+ float energy, limit, angle, range;
+ int icon;
+ BOOL bOnBoard;
+
+ m_lastAlarmTime += rTime;
+ if ( m_time < m_lastUpdateTime+0.1f ) return;
+ m_lastUpdateTime = m_time;
+
+ if ( !m_object->RetSelect() )
+ {
+ if ( m_soundChannelAlarm != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannelAlarm);
+ m_sound->AddEnvelope(m_soundChannelAlarm, 0.0f, 1.0f, 0.1f, SOPER_STOP);
+ m_soundChannelAlarm = -1;
+ }
+ return;
+ }
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GENERGY);
+ if ( pg != 0 )
+ {
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ energy = 0.0f;
+ }
+ else
+ {
+ energy = power->RetEnergy();
+ limit = energy*power->RetCapacity();
+ }
+ icon = 0; // rouge/vert
+
+ if ( limit < 0.2f && energy != 0.0f ) // niveau bas mais non nul ?
+ {
+ if ( m_lastAlarmTime >= 0.8f ) // clignotte ?
+ {
+ energy = 1.0f;
+ icon = 1; // brun
+ }
+ if ( m_lastAlarmTime >= 1.0f )
+ {
+ m_sound->Play(SOUND_ALARM, 0.5f); // bip-bip-bip
+ m_lastAlarmTime = 0.0f;
+ }
+ }
+ pg->SetLevel(energy);
+ pg->SetIcon(icon);
+ }
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GSHIELD);
+ if ( pg != 0 )
+ {
+ pg->SetLevel(m_object->RetShield());
+ }
+
+ pg = (CGauge*)pw->SearchControl(EVENT_OBJECT_GRANGE);
+ if ( pg != 0 )
+ {
+ icon = 2; // bleu/rouge
+ range = m_physics->RetReactorRange();
+
+ if ( range < 0.2f && range != 0.0f && !m_physics->RetLand() )
+ {
+ if ( Mod(m_time, 0.5f) >= 0.2f ) // clignotte ?
+ {
+ range = 1.0f;
+ icon = 1; // jaune
+ }
+ if ( m_soundChannelAlarm == -1 )
+ {
+ m_soundChannelAlarm = m_sound->Play(SOUND_ALARMt, m_object->RetPosition(0), 0.0f, 0.1f, TRUE);
+ m_sound->AddEnvelope(m_soundChannelAlarm, 1.0f, 1.0f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannelAlarm, 1.0f, 1.0f, 1.0f, SOPER_LOOP);
+ }
+ }
+ else
+ {
+ if ( m_soundChannelAlarm != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannelAlarm);
+ m_sound->AddEnvelope(m_soundChannelAlarm, 0.0f, 0.1f, 1.0f, SOPER_STOP);
+ m_soundChannelAlarm = -1;
+ }
+ }
+
+ pg->SetLevel(1.0f-range);
+ pg->SetIcon(icon);
+ }
+
+ pc = (CCompass*)pw->SearchControl(EVENT_OBJECT_COMPASS);
+ if ( pc != 0 )
+ {
+ angle = -(m_object->RetAngleY(0)+PI/2.0f);
+ pc->SetDirection(angle);
+
+ pc->SetState(STATE_VISIBLE, m_main->RetShowMap());
+ }
+
+#if _TEEN
+ pb = (CButton*)pw->SearchControl(EVENT_OBJECT_REC);
+ if ( pb != 0 )
+ {
+ if ( m_bTraceRecord && Mod(m_time, 0.4f) >= 0.2f )
+ {
+ pb->SetState(STATE_CHECK);
+ }
+ else
+ {
+ pb->ClearState(STATE_CHECK);
+ }
+ }
+#endif
+
+ bOnBoard = m_camera->RetType() == CAMERA_ONBOARD;
+
+ pgr = (CGroup*)pw->SearchControl(EVENT_OBJECT_CROSSHAIR);
+ if ( pgr != 0 )
+ {
+ if ( bOnBoard )
+ {
+#if 0
+ angle = m_object->RetGunGoalV();
+ if ( m_object->RetType() != OBJECT_MOBILErc )
+ {
+ angle += 10.0f*PI/360.0f;
+ }
+ ppos.x = 0.5f-(64.0f/640.0f)/2.0f;
+ ppos.y = 0.5f-(64.0f/480.0f)/2.0f;
+ ppos.y += sinf(angle)*0.6f;
+ pgr->SetPos(ppos);
+#else
+ ppos.x = 0.50f-(64.0f/640.0f)/2.0f;
+ ppos.y = 0.50f-(64.0f/480.0f)/2.0f;
+ ppos.x += m_object->RetGunGoalH()/2.0f;
+ ppos.y += m_object->RetGunGoalV()/1.3f;
+ pgr->SetPos(ppos);
+#endif
+ pgr->SetState(STATE_VISIBLE, !m_main->RetFriendAim());
+ }
+ else
+ {
+ pgr->ClearState(STATE_VISIBLE);
+ }
+ }
+
+ ptg = (CTarget*)pw->SearchControl(EVENT_OBJECT_TARGET);
+ if ( ptg != 0 )
+ {
+ if ( bOnBoard )
+ {
+ ptg->SetState(STATE_VISIBLE);
+ }
+ else
+ {
+ ptg->ClearState(STATE_VISIBLE);
+ }
+ }
+
+ pgr = (CGroup*)pw->SearchControl(EVENT_OBJECT_CORNERul);
+ if ( pgr != 0 )
+ {
+ pgr->SetState(STATE_VISIBLE, bOnBoard);
+ }
+
+ pgr = (CGroup*)pw->SearchControl(EVENT_OBJECT_CORNERur);
+ if ( pgr != 0 )
+ {
+ pgr->SetState(STATE_VISIBLE, bOnBoard);
+ }
+
+ pgr = (CGroup*)pw->SearchControl(EVENT_OBJECT_CORNERdl);
+ if ( pgr != 0 )
+ {
+ pgr->SetState(STATE_VISIBLE, bOnBoard);
+ }
+
+ pgr = (CGroup*)pw->SearchControl(EVENT_OBJECT_CORNERdr);
+ if ( pgr != 0 )
+ {
+ pgr->SetState(STATE_VISIBLE, bOnBoard);
+ }
+}
+
+// Met à jour l'état de tous les boutons de l'interface.
+
+void CBrain::UpdateInterface()
+{
+ ObjectType type;
+ CWindow* pw;
+ CButton* pb;
+ CSlider* ps;
+#if _TEEN
+ CColor* pc;
+ int color;
+#endif
+ BOOL bEnable, bFly, bRun;
+ char title[100];
+
+ if ( !m_object->RetSelect() ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ type = m_object->RetType();
+
+ bEnable = ( m_secondaryTask == 0 && m_program == -1 );
+
+ bEnable = ( m_primaryTask == 0 && m_program == -1 );
+
+ EnableInterface(pw, EVENT_OBJECT_PROGEDIT, (m_primaryTask == 0 && !m_bTraceRecord));
+ EnableInterface(pw, EVENT_OBJECT_PROGLIST, bEnable && !m_bTraceRecord);
+ EnableInterface(pw, EVENT_OBJECT_LEFT, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_RIGHT, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_UP, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_DOWN, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_HTAKE, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_MTAKE, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_MBACK, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_MPOWER, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_MFRONT, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_GFLAT, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_FCREATE, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_FDELETE, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_SEARCH, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_TERRAFORM, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_RECOVER, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_FIRE, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_RESET, bEnable);
+#if _TEEN
+ EnableInterface(pw, EVENT_OBJECT_PEN0, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN1, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN2, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN3, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN4, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN5, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN6, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN7, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_PEN8, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_REC, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_STOP, bEnable);
+#endif
+
+ if ( type == OBJECT_HUMAN ) // constructeur ?
+ {
+ EnableInterface(pw, EVENT_OBJECT_BFACTORY, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BDERRICK, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BCONVERT, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BSTATION, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BREPAIR, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BTOWER, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BRESEARCH, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BRADAR, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BENERGY, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BLABO, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BNUCLEAR, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BPARA, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BINFO, bEnable);
+ EnableInterface(pw, EVENT_OBJECT_BXXXX, bEnable);
+ }
+
+ pb = (CButton*)pw->SearchControl(EVENT_OBJECT_GFLAT);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_VISIBLE, m_engine->RetGroundSpot());
+ }
+
+ if ( type == OBJECT_HUMAN || // constructeur ?
+ type == OBJECT_TECH )
+ {
+ CheckInterface(pw, EVENT_OBJECT_FCOLORb, m_flagColor==0);
+ CheckInterface(pw, EVENT_OBJECT_FCOLORr, m_flagColor==1);
+ CheckInterface(pw, EVENT_OBJECT_FCOLORg, m_flagColor==2);
+ CheckInterface(pw, EVENT_OBJECT_FCOLORy, m_flagColor==3);
+ CheckInterface(pw, EVENT_OBJECT_FCOLORv, m_flagColor==4);
+ }
+
+ if ( type == OBJECT_MOBILErs ) // bouclier ?
+ {
+ if ( (m_secondaryTask == 0 || !m_secondaryTask->IsBusy()) && m_program == -1 )
+ {
+ EnableInterface(pw, EVENT_OBJECT_BEGSHIELD, (m_secondaryTask == 0));
+ EnableInterface(pw, EVENT_OBJECT_ENDSHIELD, (m_secondaryTask != 0));
+ DefaultEnter (pw, EVENT_OBJECT_BEGSHIELD, (m_secondaryTask == 0));
+ DefaultEnter (pw, EVENT_OBJECT_ENDSHIELD, (m_secondaryTask != 0));
+ }
+ else
+ {
+ EnableInterface(pw, EVENT_OBJECT_BEGSHIELD, FALSE);
+ EnableInterface(pw, EVENT_OBJECT_ENDSHIELD, FALSE);
+ DefaultEnter (pw, EVENT_OBJECT_BEGSHIELD, FALSE);
+ DefaultEnter (pw, EVENT_OBJECT_ENDSHIELD, FALSE);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_DIMSHIELD);
+ if ( ps != 0 )
+ {
+ ps->SetVisibleValue((RADIUS_SHIELD_MIN/g_unit)+m_object->RetParam()*((RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)/g_unit));
+ }
+ }
+
+ bFly = bEnable;
+ if ( bFly && (type == OBJECT_HUMAN || type == OBJECT_TECH) )
+ {
+ if ( m_object->RetFret() != 0 ) bFly = FALSE; // si porte -> ne vole pas
+ }
+ EnableInterface(pw, EVENT_OBJECT_GASUP, bFly);
+ EnableInterface(pw, EVENT_OBJECT_GASDOWN, bFly);
+ if ( m_object->RetTrainer() ) // entraînement ?
+ {
+ DeadInterface(pw, EVENT_OBJECT_GASUP, FALSE);
+ DeadInterface(pw, EVENT_OBJECT_GASDOWN, FALSE);
+ }
+ else
+ {
+ DeadInterface(pw, EVENT_OBJECT_GASUP, g_researchDone&RESEARCH_FLY);
+ DeadInterface(pw, EVENT_OBJECT_GASDOWN, g_researchDone&RESEARCH_FLY);
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ) // véhicule ?
+ {
+ bRun = FALSE;
+ if ( m_script[m_selScript] != 0 )
+ {
+ m_script[m_selScript]->GetTitle(title);
+ if ( title[0] != 0 )
+ {
+ bRun = TRUE;
+ }
+ }
+ if ( !bEnable && m_program == -1 ) bRun = FALSE;
+ if ( m_bTraceRecord ) bRun = FALSE;
+ EnableInterface(pw, EVENT_OBJECT_PROGRUN, bRun);
+
+ pb = (CButton*)pw->SearchControl(EVENT_OBJECT_PROGRUN);
+ if ( pb != 0 )
+ {
+ pb->SetIcon(m_program==-1?21:8); // run/stop
+ }
+
+//? pb = (CButton*)pw->SearchControl(EVENT_OBJECT_PROGEDIT);
+//? if ( pb != 0 )
+//? {
+//? pb->SetIcon(m_program==-1?22:40); // edit/debug
+//? }
+
+ BlinkScript(m_program != -1); // clignotte si script en exécution
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ) // bras ?
+ {
+ CheckInterface(pw, EVENT_OBJECT_MPOWER, m_manipStyle==EVENT_OBJECT_MPOWER);
+ CheckInterface(pw, EVENT_OBJECT_MBACK, m_manipStyle==EVENT_OBJECT_MBACK);
+ CheckInterface(pw, EVENT_OBJECT_MFRONT, m_manipStyle==EVENT_OBJECT_MFRONT);
+ }
+
+#if _TEEN
+ if ( m_object->RetTraceDown() )
+ {
+ pb = (CButton*)pw->SearchControl(EVENT_OBJECT_PEN0);
+ if ( pb != 0 )
+ {
+ pb->ClearState(STATE_CHECK);
+ }
+
+ color = m_object->RetTraceColor();
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN1);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==1);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN2);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==8);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN3);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==7);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN4);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==4);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN5);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==6);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN6);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==14);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN7);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==12);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN8);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, color==10);
+ }
+ }
+ else
+ {
+ pb = (CButton*)pw->SearchControl(EVENT_OBJECT_PEN0);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_CHECK);
+ }
+
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN1);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN2);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN3);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN4);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN5);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN6);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN7);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ pc = (CColor*)pw->SearchControl(EVENT_OBJECT_PEN8);
+ if ( pc != 0 )
+ {
+ pc->ClearState(STATE_CHECK);
+ }
+ }
+#endif
+}
+
+// Met à jour la liste des programmes.
+
+void CBrain::UpdateScript(CWindow *pw)
+{
+ CList* pl;
+ char name[100];
+ char title[100];
+ int i;
+ BOOL bSoluce;
+
+ pl = (CList*)pw->SearchControl(EVENT_OBJECT_PROGLIST);
+ if ( pl == 0 ) return;
+
+#if _SCHOOL
+ bSoluce = m_main->RetSoluce4();
+#else
+ bSoluce = TRUE;
+#endif
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ sprintf(name, "%d", i+1);
+
+ if ( m_script[i] != 0 )
+ {
+ m_script[i]->GetTitle(title);
+ if ( !bSoluce && i == 3 )
+ {
+ title[0] = 0;
+ }
+ if ( title[0] != 0 )
+ {
+ sprintf(name, "%d: %s", i+1, title);
+ }
+ }
+
+ pl->SetName(i, name);
+ }
+
+ if ( !bSoluce )
+ {
+ pl->SetEnable(3, FALSE);
+ }
+
+ pl->SetSelect(m_selScript);
+ pl->ShowSelect(TRUE);
+}
+
+// Retourne le rang du script sélectionné.
+
+int CBrain::RetSelScript()
+{
+ CWindow* pw;
+ CList* pl;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return -1;
+
+ pl = (CList*)pw->SearchControl(EVENT_OBJECT_PROGLIST);
+ if ( pl == 0 ) return -1;
+
+ return pl->RetSelect();
+}
+
+// Fait clignotter le programme en exécution.
+
+void CBrain::BlinkScript(BOOL bEnable)
+{
+ CWindow* pw;
+ CList* pl;
+
+ if ( !m_object->RetSelect() ) return; // robot pas sélectionné ?
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw == 0 ) return;
+
+ pl = (CList*)pw->SearchControl(EVENT_OBJECT_PROGLIST);
+ if ( pl == 0 ) return;
+
+ pl->SetBlink(bEnable);
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CBrain::CheckInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_CHECK, bState);
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CBrain::EnableInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_ENABLE, bState);
+}
+
+// Modifie l'état d'un bouton de l'interface.
+
+void CBrain::DeadInterface(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ control->SetState(STATE_DEAD, !bState);
+}
+
+// Modifie l'état d'entrée par défaut d'un bouton de l'onterface.
+
+void CBrain::DefaultEnter(CWindow *pw, EventMsg event, BOOL bState)
+{
+ CControl* control;
+
+ control = pw->SearchControl(event);
+ if ( control == 0 ) return;
+
+ if ( bState )
+ {
+ control->SetState(STATE_DEFAULT);
+ m_defaultEnter = event;
+ }
+ else
+ {
+ control->ClearState(STATE_DEFAULT);
+ }
+}
+
+
+// Indique si l'objet est occupé dans une tâche.
+
+BOOL CBrain::IsBusy()
+{
+ return (m_primaryTask != 0);
+}
+
+// Gestion de l'activité d'un objet.
+
+void CBrain::SetActivity(BOOL bMode)
+{
+ m_bActivity = bMode;
+}
+
+BOOL CBrain::RetActivity()
+{
+ return m_bActivity;
+}
+
+// Indique si un programme est en cours d'exécution.
+
+BOOL CBrain::IsProgram()
+{
+ return ( m_program != -1 );
+}
+
+// Indique si un programme existe.
+
+BOOL CBrain::ProgramExist(int rank)
+{
+ return ( m_script[rank] != 0 );
+}
+
+// Démarre un programme donné.
+
+void CBrain::RunProgram(int rank)
+{
+ if ( rank < 0 ) return;
+
+ if ( m_script[rank] != 0 &&
+ m_script[rank]->Run() )
+ {
+ m_program = rank; // démarre nouveau programme
+ BlinkScript(TRUE); // clignotte
+ m_object->CreateSelectParticule();
+ m_main->UpdateShortcuts();
+ }
+}
+
+// Retourne le premier programme libre.
+
+int CBrain::FreeProgram()
+{
+ int i;
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ if ( m_script[i] == 0 ) return i;
+ }
+ return -1;
+}
+
+
+// Retourne le programme en cours.
+
+int CBrain::RetProgram()
+{
+ return m_program;
+}
+
+
+// Gestion du nom des scripts à charger.
+
+void CBrain::SetScriptRun(int rank)
+{
+ m_scriptRun = rank;
+}
+
+int CBrain::RetScriptRun()
+{
+ return m_scriptRun;
+}
+
+void CBrain::SetScriptName(int rank, char *name)
+{
+ strcpy(m_scriptName[rank], name);
+}
+
+char* CBrain::RetScriptName(int rank)
+{
+ return m_scriptName[rank];
+}
+
+void CBrain::SetSoluceName(char *name)
+{
+ strcpy(m_soluceName, name);
+}
+
+char* CBrain::RetSoluceName()
+{
+ return m_soluceName;
+}
+
+
+// Charge un script solution, dans le premier script libre.
+// S'il existe déjà un script identique, rien n'est chargé.
+
+BOOL CBrain::ReadSoluce(char* filename)
+{
+ int rank, i;
+
+ rank = FreeProgram();
+ if ( rank == -1 ) return FALSE;
+
+ if ( !ReadProgram(rank, filename) ) return FALSE; // charge solution
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ if ( i == rank || m_script[i] == 0 ) continue;
+
+ if ( m_script[i]->Compare(m_script[rank]) ) // déjà un même ?
+ {
+ delete m_script[rank];
+ m_script[rank] = 0;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// Charge un script avec un fichier texte.
+
+BOOL CBrain::ReadProgram(int rank, char* filename)
+{
+ if ( m_script[rank] == 0 )
+ {
+ m_script[rank] = new CScript(m_iMan, m_object, &m_secondaryTask);
+ }
+
+ if ( m_script[rank]->ReadScript(filename) ) return TRUE;
+
+ delete m_script[rank];
+ m_script[rank] = 0;
+
+ return FALSE;
+}
+
+// Indique si un programme est correctement compilé.
+
+BOOL CBrain::RetCompile(int rank)
+{
+ if ( m_script[rank] == 0 ) return FALSE;
+ return m_script[rank]->RetCompile();
+}
+
+// Sauve un script dans un fichier texte.
+
+BOOL CBrain::WriteProgram(int rank, char* filename)
+{
+ if ( m_script[rank] == 0 )
+ {
+ m_script[rank] = new CScript(m_iMan, m_object, &m_secondaryTask);
+ }
+
+ if ( m_script[rank]->WriteScript(filename) ) return TRUE;
+
+ delete m_script[rank];
+ m_script[rank] = 0;
+
+ return FALSE;
+}
+
+
+// Charge un stack de script en exécution avec un fichier.
+
+BOOL CBrain::ReadStack(FILE *file)
+{
+ short op;
+
+ fRead(&op, sizeof(short), 1, file);
+ if ( op == 1 ) // run ?
+ {
+ fRead(&op, sizeof(short), 1, file); // program rank
+ if ( op >= 0 && op < BRAINMAXSCRIPT )
+ {
+ m_program = op; // redémarre programme
+ m_selScript = op;
+ BlinkScript(TRUE); // clignotte
+
+ if ( m_script[op] == 0 )
+ {
+ m_script[op] = new CScript(m_iMan, m_object, &m_secondaryTask);
+ }
+ if ( !m_script[op]->ReadStack(file) ) return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// Sauve le stack du script en exécution dans un fichier.
+
+BOOL CBrain::WriteStack(FILE *file)
+{
+ short op;
+
+ if ( m_program != -1 && // programme en cours ?
+ m_script[m_program]->IsRunning() )
+ {
+ op = 1; // run
+ fWrite(&op, sizeof(short), 1, file);
+
+ op = m_program;
+ fWrite(&op, sizeof(short), 1, file);
+
+ return m_script[m_program]->WriteStack(file);
+ }
+
+ op = 0; // stop
+ fWrite(&op, sizeof(short), 1, file);
+ return TRUE;
+}
+
+
+
+// Début de l'enregistrement du dessin.
+
+void CBrain::TraceRecordStart()
+{
+ m_traceOper = TO_STOP;
+
+ m_tracePos = m_object->RetPosition(0);
+ m_traceAngle = m_object->RetAngleY(0);
+
+ if ( m_object->RetTraceDown() ) // crayon baissé ?
+ {
+ m_traceColor = m_object->RetTraceColor();
+ }
+ else // crayon levé ?
+ {
+ m_traceColor = -1;
+ }
+
+ delete m_traceRecordBuffer;
+ m_traceRecordBuffer = (TraceRecord*)malloc(sizeof(TraceRecord)*MAXTRACERECORD);
+ m_traceRecordIndex = 0;
+}
+
+// Enregistrement du dessin en cours.
+
+void CBrain::TraceRecordFrame()
+{
+ TraceOper oper = TO_STOP;
+ D3DVECTOR pos;
+ float angle, len, speed;
+ int color;
+
+ speed = m_physics->RetLinMotionX(MO_REASPEED);
+ if ( speed > 0.0f ) oper = TO_ADVANCE;
+ if ( speed < 0.0f ) oper = TO_RECEDE;
+
+ speed = m_physics->RetCirMotionY(MO_REASPEED);
+ if ( speed != 0.0f ) oper = TO_TURN;
+
+ if ( m_object->RetTraceDown() ) // crayon baissé ?
+ {
+ color = m_object->RetTraceColor();
+ }
+ else // crayon levé ?
+ {
+ color = -1;
+ }
+
+ if ( oper != m_traceOper ||
+ color != m_traceColor )
+ {
+ if ( m_traceOper == TO_ADVANCE ||
+ m_traceOper == TO_RECEDE )
+ {
+ pos = m_object->RetPosition(0);
+ len = Length2d(pos, m_tracePos);
+ TraceRecordOper(m_traceOper, len);
+ }
+ if ( m_traceOper == TO_TURN )
+ {
+ angle = m_object->RetAngleY(0)-m_traceAngle;
+ TraceRecordOper(m_traceOper, angle);
+ }
+
+ if ( color != m_traceColor )
+ {
+ TraceRecordOper(TO_PEN, (float)color);
+ }
+
+ m_traceOper = oper;
+ m_tracePos = m_object->RetPosition(0);
+ m_traceAngle = m_object->RetAngleY(0);
+ m_traceColor = color;
+ }
+}
+
+// Fin de l'enregistrement du dessin. Génère le programme CBOT.
+
+void CBrain::TraceRecordStop()
+{
+ TraceOper lastOper, curOper;
+ float lastParam, curParam;
+ int max, i;
+ char* buffer;
+
+ if ( m_traceRecordBuffer == 0 ) return;
+
+ max = 10000;
+ buffer = (char*)malloc(max);
+ *buffer = 0;
+ strncat(buffer, "extern void object::AutoDraw()\n{\n", max-1);
+
+ lastOper = TO_STOP;
+ lastParam = 0.0f;
+ for ( i=0 ; i<m_traceRecordIndex ; i++ )
+ {
+ curOper = m_traceRecordBuffer[i].oper;
+ curParam = m_traceRecordBuffer[i].param;
+
+ if ( curOper == lastOper )
+ {
+ if ( curOper == TO_PEN )
+ {
+ lastParam = curParam;
+ }
+ else
+ {
+ lastParam += curParam;
+ }
+ }
+ else
+ {
+ TraceRecordPut(buffer, max, lastOper, lastParam);
+ lastOper = curOper;
+ lastParam = curParam;
+ }
+ }
+ TraceRecordPut(buffer, max, lastOper, lastParam);
+
+ delete m_traceRecordBuffer;
+ m_traceRecordBuffer = 0;
+
+ strncat(buffer, "}\n", max-1);
+ buffer[max-1] = 0;
+
+ i = m_selScript;
+ if ( m_script[i] == 0 )
+ {
+ m_script[i] = new CScript(m_iMan, m_object, &m_secondaryTask);
+ }
+ m_script[i]->SendScript(buffer);
+ delete buffer;
+}
+
+// Enregistre une instruction CBOT.
+
+BOOL CBrain::TraceRecordOper(TraceOper oper, float param)
+{
+ int i;
+
+ i = m_traceRecordIndex;
+ if ( i >= MAXTRACERECORD ) return FALSE;
+
+ m_traceRecordBuffer[i].oper = oper;
+ m_traceRecordBuffer[i].param = param;
+
+ m_traceRecordIndex = i+1;
+ return TRUE;
+}
+
+// Génère une instruction CBOT.
+
+BOOL CBrain::TraceRecordPut(char *buffer, int max, TraceOper oper, float param)
+{
+ char line[100];
+ int color;
+
+ if ( oper == TO_ADVANCE )
+ {
+ param /= g_unit;
+ sprintf(line, "\tmove(%.1f);\n", param);
+ strncat(buffer, line, max-1);
+ }
+
+ if ( oper == TO_RECEDE )
+ {
+ param /= g_unit;
+ sprintf(line, "\tmove(-%.1f);\n", param);
+ strncat(buffer, line, max-1);
+ }
+
+ if ( oper == TO_TURN )
+ {
+ param = -param*180.0f/PI;
+ sprintf(line, "\tturn(%d);\n", (int)param);
+//? sprintf(line, "\tturn(%.1f);\n", param);
+ strncat(buffer, line, max-1);
+ }
+
+ if ( oper == TO_PEN )
+ {
+ color = (int)param;
+ if ( color == -1 ) strncat(buffer, "\tpenup();\n", max-1);
+ if ( color == 1 ) strncat(buffer, "\tpendown(Black);\n", max-1);
+ if ( color == 8 ) strncat(buffer, "\tpendown(Yellow);\n", max-1);
+ if ( color == 7 ) strncat(buffer, "\tpendown(Orange);\n", max-1);
+ if ( color == 4 ) strncat(buffer, "\tpendown(Red);\n", max-1);
+ if ( color == 6 ) strncat(buffer, "\tpendown(Purple);\n", max-1);
+ if ( color == 14 ) strncat(buffer, "\tpendown(Blue);\n", max-1);
+ if ( color == 12 ) strncat(buffer, "\tpendown(Green);\n", max-1);
+ if ( color == 10 ) strncat(buffer, "\tpendown(Brown);\n", max-1);
+ }
+
+ return TRUE;
+}
+
diff --git a/src/brain.h b/src/brain.h
new file mode 100644
index 0000000..071c4b1
--- /dev/null
+++ b/src/brain.h
@@ -0,0 +1,202 @@
+// brain.h
+
+#ifndef _BRAIN_H_
+#define _BRAIN_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CTerrain;
+class CWater;
+class CCamera;
+class CObject;
+class CPhysics;
+class CMotion;
+class CTaskManager;
+class CInterface;
+class CWindow;
+class CDisplayText;
+class CScript;
+class CRobotMain;
+class CStudio;
+class CSound;
+class CParticule;
+
+enum ObjectType;
+enum TaskManipOrder;
+enum TaskManipArm;
+enum TaskFlagOrder;
+enum TaskShieldMode;
+
+
+#define BRAINMAXSCRIPT 10
+
+
+
+enum TraceOper
+{
+ TO_STOP = 0, // arrêt
+ TO_ADVANCE = 1, // avance
+ TO_RECEDE = 2, // recule
+ TO_TURN = 3, // tourne
+ TO_PEN = 4, // changement de couleur
+};
+
+typedef struct
+{
+ TraceOper oper;
+ float param;
+}
+TraceRecord;
+
+
+
+class CBrain
+{
+public:
+ CBrain(CInstanceManager* iMan, CObject* object);
+ ~CBrain();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ void SetPhysics(CPhysics* physics);
+ void SetMotion(CMotion* motion);
+
+ BOOL EventProcess(const Event &event);
+ BOOL CreateInterface(BOOL bSelect);
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+ BOOL IsBusy();
+ void SetActivity(BOOL bMode);
+ BOOL RetActivity();
+ BOOL IsProgram();
+ BOOL ProgramExist(int rank);
+ void RunProgram(int rank);
+ int FreeProgram();
+ int RetProgram();
+ void StopProgram();
+ void StopTask();
+
+ BOOL IntroduceVirus();
+ void SetActiveVirus(BOOL bActive);
+ BOOL RetActiveVirus();
+
+ void SetScriptRun(int rank);
+ int RetScriptRun();
+ void SetScriptName(int rank, char *name);
+ char* RetScriptName(int rank);
+ void SetSoluceName(char *name);
+ char* RetSoluceName();
+
+ BOOL ReadSoluce(char* filename);
+ BOOL ReadProgram(int rank, char* filename);
+ BOOL RetCompile(int rank);
+ BOOL WriteProgram(int rank, char* filename);
+ BOOL ReadStack(FILE *file);
+ BOOL WriteStack(FILE *file);
+
+ Error StartTaskTake();
+ Error StartTaskManip(TaskManipOrder order, TaskManipArm arm);
+ Error StartTaskFlag(TaskFlagOrder order, int rank);
+ Error StartTaskBuild(ObjectType type);
+ Error StartTaskSearch();
+ Error StartTaskTerraform();
+ Error StartTaskPen(BOOL bDown, int color);
+ Error StartTaskRecover();
+ Error StartTaskShield(TaskShieldMode mode);
+ Error StartTaskFire(float delay);
+ Error StartTaskFireAnt(D3DVECTOR impact);
+ Error StartTaskGunGoal(float dirV, float dirH);
+ Error StartTaskReset(D3DVECTOR goal, D3DVECTOR angle);
+
+ void UpdateInterface(float rTime);
+ void UpdateInterface();
+
+protected:
+ BOOL EventFrame(const Event &event);
+
+ void StartEditScript(int rank, char* name);
+ void StopEditScript(BOOL bCancel);
+
+ Error EndedTask();
+
+ void GroundFlat();
+ void ColorFlag(int color);
+
+ void UpdateScript(CWindow *pw);
+ int RetSelScript();
+ void BlinkScript(BOOL bEnable);
+
+ void CheckInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void EnableInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void DeadInterface(CWindow *pw, EventMsg event, BOOL bState);
+ void DefaultEnter(CWindow *pw, EventMsg event, BOOL bState=TRUE);
+
+ void TraceRecordStart();
+ void TraceRecordFrame();
+ void TraceRecordStop();
+ BOOL TraceRecordOper(TraceOper oper, float param);
+ BOOL TraceRecordPut(char *buffer, int max, TraceOper oper, float param);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCamera* m_camera;
+ CObject* m_object;
+ CPhysics* m_physics;
+ CMotion* m_motion;
+ CInterface* m_interface;
+ CDisplayText* m_displayText;
+ CRobotMain* m_main;
+ CStudio* m_studio;
+ CSound* m_sound;
+ CParticule* m_particule;
+ CTaskManager* m_primaryTask;
+ CTaskManager* m_secondaryTask;
+
+ CScript* m_script[BRAINMAXSCRIPT];
+ int m_selScript; // rang du script sélectionné
+ int m_program; // rang du programme exécuté / -1
+ BOOL m_bActivity;
+ BOOL m_bBurn;
+ BOOL m_bActiveVirus;
+
+ int m_scriptRun;
+ char m_scriptName[BRAINMAXSCRIPT][50];
+ char m_soluceName[50];
+
+ EventMsg m_buttonAxe;
+ EventMsg m_manipStyle;
+ EventMsg m_defaultEnter;
+ EventMsg m_interfaceEvent[100];
+
+ CObject* m_antTarget;
+ CObject* m_beeBullet;
+ float m_beeBulletSpeed;
+ D3DVECTOR m_startPos;
+ float m_time;
+ float m_burnTime;
+ float m_lastUpdateTime;
+ float m_lastHumanTime;
+ float m_lastSpiderTime;
+ float m_lastWormTime;
+ float m_lastBulletTime;
+ float m_lastAlarmTime;
+ int m_soundChannelAlarm;
+ int m_flagColor;
+
+ BOOL m_bTraceRecord;
+ TraceOper m_traceOper;
+ D3DVECTOR m_tracePos;
+ float m_traceAngle;
+ int m_traceColor;
+ int m_traceRecordIndex;
+ TraceRecord* m_traceRecordBuffer;
+};
+
+
+#endif //_BRAIN_H_
diff --git a/src/bug.txt b/src/bug.txt
new file mode 100644
index 0000000..b598ad0
--- /dev/null
+++ b/src/bug.txt
@@ -0,0 +1,94 @@
+void CD3DApplication::StepSimul(float rTime)
+{
+ Event event;
+
+ if ( m_pRobotMain == 0 ) return;
+
+ if ( rTime > 0.5f ) rTime = 0.5f; // jamais plus de 0.5s !
+
+ ZeroMemory(&event, sizeof(Event));
+ event.event = EVENT_FRAME;
+ event.rTime = rTime;
+ event.axeX = AxeLimit(m_axeKey.x + m_axeJoy.x);
+ event.axeY = AxeLimit(m_axeKey.y + m_axeJoy.y);
+ event.axeZ = AxeLimit(m_axeKey.z + m_axeJoy.z);
+ event.keyState = m_keyState;
+
+//?char s[100];
+//?sprintf(s, "StepSimul %.3f\n", event.rTime);
+//?OutputDebugString(s);
+ m_pRobotMain->EventProcess(event);
+}
+
+
+
+1347: void CD3DApplication::StepSimul(float rTime)
+1348: {
+0041E950 sub esp,24h
+0041E953 push esi
+0041E954 mov esi,ecx
+1349: Event event;
+1350:
+1351: if ( m_pRobotMain == 0 ) return;
+0041E956 mov eax,dword ptr [esi+0ECh]
+0041E95C test eax,eax
+0041E95E je CD3DApplication::StepSimul(0x0041ea08)+0B8h
+1352:
+1353: if ( rTime > 0.5f ) rTime = 0.5f; // jamais plus de 0.5s !
+0041E964 fld dword ptr [esp+2Ch]
+0041E968 fcomp dword ptr [??_7CControl@@6B@(0x004b9ed4)+94h]
+0041E96E push edi
+0041E96F fnstsw ax
+0041E971 test ah,41h
+0041E974 jne CD3DApplication::StepSimul(0x0041e97e)+2Eh
+0041E976 mov dword ptr [esp+30h],3F000000h
+1354:
+1355: ZeroMemory(&event, sizeof(Event));
+1356: event.event = EVENT_FRAME;
+1357: event.rTime = rTime;
+1358: event.axeX = AxeLimit(m_axeKey.x + m_axeJoy.x);
+0041E97E fld dword ptr [esi+0F8h]
+0041E984 fadd dword ptr [esi+104h]
+0041E98A mov eax,dword ptr [esp+30h]
+0041E98E mov ecx,9
+0041E993 mov dword ptr [esp+28h],eax
+0041E997 push ecx
+0041E998 xor eax,eax
+0041E99A lea edi,dword ptr [esp+0Ch]
+0041E99E fstp dword ptr [esp]
+0041E9A1 rep stos dword ptr es:[edi]
+0041E9A3 mov dword ptr [esp+0Ch],2
+0041E9AB call AxeLimit(0x0041cae0)
+1359: event.axeY = AxeLimit(m_axeKey.y + m_axeJoy.y);
+0041E9B0 fld dword ptr [esi+0FCh]
+0041E9B6 fadd dword ptr [esi+108h]
+0041E9BC fxch st(1)
+0041E9BE fstp dword ptr [esp+1Ch]
+0041E9C2 fstp dword ptr [esp]
+0041E9C5 call AxeLimit(0x0041cae0)
+1360: event.axeZ = AxeLimit(m_axeKey.z + m_axeJoy.z);
+0041E9CA fld dword ptr [esi+100h]
+0041E9D0 fadd dword ptr [esi+10Ch]
+0041E9D6 fxch st(1)
+0041E9D8 fstp dword ptr [esp+20h]
+0041E9DC fstp dword ptr [esp]
+0041E9DF call AxeLimit(0x0041cae0)
+1361: event.keyState = m_keyState;
+1362:
+1363: //?char s[100];
+1364: //?sprintf(s, "StepSimul %.3f\n", event.rTime);
+1365: //?OutputDebugString(s);
+1366: m_pRobotMain->EventProcess(event);
+0041E9E4 mov dx,word ptr [esi+0F4h]
+0041E9EB mov ecx,dword ptr [esi+0ECh]
+0041E9F1 fstp dword ptr [esp+24h]
+0041E9F5 add esp,4
+0041E9F8 lea eax,dword ptr [esp+8]
+0041E9FC mov word ptr [esp+24h],dx
+0041EA01 push eax
+0041EA02 call CRobotMain::EventProcess(0x0047fba0)
+0041EA07 pop edi
+1367: }
+0041EA08 pop esi
+0041EA09 add esp,24h
+0041EA0C ret 4
diff --git a/src/bug1.txt b/src/bug1.txt
new file mode 100644
index 0000000..59b0ca4
--- /dev/null
+++ b/src/bug1.txt
@@ -0,0 +1,68 @@
+extern void object::Solution( )
+{
+ while ( true )
+ {
+ object left, right;
+
+ left = Radar(TypeMarkPath, -45, 120, 100);
+ right = Radar(TypeMarkPath, 45, 120, 100);
+
+ if ( left == null && right == null )
+ {
+ }
+ }
+}
+
+CBotString::CBotString(const CBotString &)
+CBotVar::GivName()
+CBotStack::FindVar(CBotToken * &, int, int)
+CBotStack::FindVar(CBotToken &, int, int)
+CBotStack::CopyVar(CBotToken &, int)
+CBotExpression::Execute(CBotStack * &)
+CBotListInstr::Execute(CBotStack * &)
+CBotWhile::Execute(CBotStack * &)
+CBotListInstr::Execute(CBotStack * &)
+CBotFunction::Execute(CBotVar * *, CBotStack * &)
+CBotProgram::Run(void *)
+CScript::Continue(const Event &)
+
+
+
+CBotString::CBotString(const CBotString &) :
+ m_token = 0xdddddddd
+
+CBotVar::GivName() :
+ return m_token->GivString();
+
+CBotStack::FindVar(CBotToken * &, int, int) :
+ CBotStack* p = this;
+ CBotString name = pToken->GivString();
+
+ while (p != NULL)
+ {
+ CBotVar* pp = p->m_listVar;
+ while ( pp != NULL)
+ {
+ if (pp->GivName() == name) <- paf
+
+ avec :
+ pp->__vfprt = 0xdddddddd
+ pp->m_token = 0xdddddddd
+ pp->m_next = 0xdddddddd
+ pp->m_type = -572662307
+ pp->m_binit = -572662307
+ pp->m_pMyThis = 0xdddddddd
+ pp->m_pUserPtr = 0xdddddddd
+ pp->m_InitExpr = 0xdddddddd
+
+CBotStack::FindVar(CBotToken &, int, int) :
+ CBotToken* pt = &Token;
+ pt->m_next = 0
+ pt->m_prev = 0
+ pt->m_type = 4
+ pt->m_IdKeyWord = -1
+ pt->m_Text = "right"
+ pt->m_Sep = " "
+ pt->m_start = 124
+ pt->m_end = 129
+
diff --git a/src/bugs/Colobot_image blèm.psp b/src/bugs/Colobot_image blèm.psp
new file mode 100644
index 0000000..905ae5c
--- /dev/null
+++ b/src/bugs/Colobot_image blèm.psp
Binary files differ
diff --git a/src/bugs/Image1.gif b/src/bugs/Image1.gif
new file mode 100644
index 0000000..309c3fb
--- /dev/null
+++ b/src/bugs/Image1.gif
Binary files differ
diff --git a/src/bugs/Image2.gif b/src/bugs/Image2.gif
new file mode 100644
index 0000000..4d98992
--- /dev/null
+++ b/src/bugs/Image2.gif
Binary files differ
diff --git a/src/bugs/Image3.gif b/src/bugs/Image3.gif
new file mode 100644
index 0000000..ac1a602
--- /dev/null
+++ b/src/bugs/Image3.gif
Binary files differ
diff --git a/src/bugs/Image4.gif b/src/bugs/Image4.gif
new file mode 100644
index 0000000..88cb30a
--- /dev/null
+++ b/src/bugs/Image4.gif
Binary files differ
diff --git a/src/bugs/Image9.gif b/src/bugs/Image9.gif
new file mode 100644
index 0000000..d516eac
--- /dev/null
+++ b/src/bugs/Image9.gif
Binary files differ
diff --git a/src/bugs/borne.gif b/src/bugs/borne.gif
new file mode 100644
index 0000000..3046e6c
--- /dev/null
+++ b/src/bugs/borne.gif
Binary files differ
diff --git a/src/button.cpp b/src/button.cpp
new file mode 100644
index 0000000..9e57eea
--- /dev/null
+++ b/src/button.cpp
@@ -0,0 +1,237 @@
+// button.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "button.h"
+
+
+
+#define DELAY1 0.4f
+#define DELAY2 0.1f
+
+
+
+// Constructeur de l'objet.
+
+CButton::CButton(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_bCapture = FALSE;
+ m_bImmediat = FALSE;
+ m_bRepeat = FALSE;
+ m_repeat = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CButton::~CButton()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CButton::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ if ( icon == -1 )
+ {
+ char name[100];
+ char* p;
+
+ GetResource(RES_EVENT, eventMsg, name);
+ p = strchr(name, '\\');
+ if ( p != 0 ) *p = 0;
+ SetName(name);
+ }
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CButton::EventProcess(const Event &event)
+{
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ if ( m_bRepeat && m_repeat != 0.0f )
+ {
+ m_repeat -= event.rTime;
+ if ( m_repeat <= 0.0f )
+ {
+ m_repeat = DELAY2;
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ m_bCapture = TRUE;
+ m_repeat = DELAY1;
+
+ if ( m_bImmediat || m_bRepeat )
+ {
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+ return FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && m_bCapture )
+ {
+ }
+
+ if ( event.event == EVENT_LBUTTONUP && m_bCapture )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ if ( !m_bImmediat && !m_bRepeat )
+ {
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+ }
+
+ m_bCapture = FALSE;
+ m_repeat = 0.0f;
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CButton::Draw()
+{
+ FPOINT pos, dim, uv1, uv2;
+#if !_NEWLOOK
+ float dp;
+#endif
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_WARNING ) // hachures jaunes-noires ?
+ {
+ pos.x = m_pos.x-( 8.0f/640.0f);
+ pos.y = m_pos.y-( 4.0f/480.0f);
+ dim.x = m_dim.x+(16.0f/640.0f);
+ dim.y = m_dim.y+( 8.0f/480.0f);
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(pos, dim);
+ }
+ DrawWarning(pos, dim);
+ }
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ CControl::Draw();
+
+#if !_NEWLOOK
+ if ( m_name[0] != 0 && // bouton avec nom ?
+ (m_state & STATE_CARD ) == 0 &&
+ (m_state & STATE_SIMPLY) == 0 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ dp = 0.5f/256.0f;
+
+ uv1.x = 128.0f/256.0f;
+ uv1.y = 96.0f/256.0f;
+ uv2.x = 136.0f/256.0f;
+ uv2.y = 128.0f/256.0f;
+
+ if ( (m_state & STATE_ENABLE) == 0 )
+ {
+ uv1.x += 16.0f/256.0f;
+ uv2.x += 16.0f/256.0f;
+ }
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ pos.y = m_pos.y+5.0f/480.0f;
+ dim.y = m_dim.y-10.0f/480.0f;
+ pos.x = m_pos.x+5.0f/640.0f;
+ dim.x = 3.0f/640.0f;
+ DrawIcon(pos, dim, uv1, uv2, 0.0f);
+
+ uv1.x += 8.0f/256.0f;
+ uv2.x += 8.0f/256.0f;
+ pos.x = m_pos.x+m_dim.x-5.0f/640.0f-3.0f/640.0f;
+ DrawIcon(pos, dim, uv1, uv2, 0.0f);
+ }
+#endif
+}
+
+
+// Gestion du mode immédiat, qui envoie l'événement "pressé"
+// avant que le bouton de la souris soit relâché.
+
+void CButton::SetImmediat(BOOL bImmediat)
+{
+ m_bImmediat = bImmediat;
+}
+
+BOOL CButton::RetImmediat()
+{
+ return m_bImmediat;
+}
+
+
+// Gestion du mode "répétition automatique", lorsque le bouton
+// de la souris est maintenu pressé.
+
+void CButton::SetRepeat(BOOL bRepeat)
+{
+ m_bRepeat = bRepeat;
+}
+
+BOOL CButton::RetRepeat()
+{
+ return m_bRepeat;
+}
+
diff --git a/src/button.h b/src/button.h
new file mode 100644
index 0000000..1e6ef90
--- /dev/null
+++ b/src/button.h
@@ -0,0 +1,42 @@
+// button.h
+
+#ifndef _BUTTON_H_
+#define _BUTTON_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CButton : public CControl
+{
+public:
+ CButton(CInstanceManager* iMan);
+ ~CButton();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+ void SetImmediat(BOOL bRepeat);
+ BOOL RetImmediat();
+
+ void SetRepeat(BOOL bRepeat);
+ BOOL RetRepeat();
+
+protected:
+
+protected:
+ BOOL m_bCapture;
+ BOOL m_bImmediat;
+ BOOL m_bRepeat;
+ float m_repeat;
+};
+
+
+#endif //_BUTTON_H_
diff --git a/src/camera.cpp b/src/camera.cpp
new file mode 100644
index 0000000..21371dc
--- /dev/null
+++ b/src/camera.cpp
@@ -0,0 +1,2095 @@
+// camera.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "camera.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CCamera::CCamera(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_CAMERA, this);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+
+ m_type = CAMERA_FREE;
+ m_smooth = CS_NORM;
+ m_cameraObj = 0;
+
+ m_eyeDistance = 10.0f;
+ m_initDelay = 0.0f;
+
+ m_actualEye = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_actualLookat = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_finalEye = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_finalLookat = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_normEye = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_normLookat = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_focus = 1.0f;
+
+ m_bRightDown = FALSE;
+ m_rightPosInit = FPOINT(0.5f, 0.5f);
+ m_rightPosCenter = FPOINT(0.5f, 0.5f);
+ m_rightPosMove = FPOINT(0.5f, 0.5f);
+
+ m_eyePt = D3DVECTOR(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_bTransparency = FALSE;
+
+ m_fixDist = 0.0f;
+ m_fixDirectionH = 0.0f;
+ m_fixDirectionV = 0.0f;
+
+ m_visitGoal = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_visitDist = 0.0f;
+ m_visitTime = 0.0f;
+ m_visitType = CAMERA_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 = CP_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 = CE_NULL;
+ m_effectPos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_effectForce = 0.0f;
+ m_effectProgress = 0.0f;
+ m_effectOffset = D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ m_scriptEye = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_scriptLookat = D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ m_bEffect = TRUE;
+ m_bCameraScroll = TRUE;
+ m_bCameraInvertX = FALSE;
+ m_bCameraInvertY = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CCamera::~CCamera()
+{
+}
+
+
+void CCamera::SetEffect(BOOL bEnable)
+{
+ m_bEffect = bEnable;
+}
+
+void CCamera::SetCameraScroll(BOOL bScroll)
+{
+ m_bCameraScroll = bScroll;
+}
+
+void CCamera::SetCameraInvertX(BOOL bInvert)
+{
+ m_bCameraInvertX = bInvert;
+}
+
+void CCamera::SetCameraInvertY(BOOL bInvert)
+{
+ m_bCameraInvertY = bInvert;
+}
+
+
+// Retourne une force additionnelle pour tourner.
+
+float CCamera::RetMotorTurn()
+{
+ if ( m_type == CAMERA_BACK ) return m_motorTurn;
+ return 0.0f;
+}
+
+
+
+// Initialise la caméra.
+
+void CCamera::Init(D3DVECTOR eye, D3DVECTOR lookat, float delay)
+{
+ D3DVECTOR vUpVec;
+
+ m_initDelay = delay;
+
+ eye.y += m_terrain->RetFloorLevel(eye, TRUE);
+ lookat.y += m_terrain->RetFloorLevel(lookat, TRUE);
+
+ m_type = CAMERA_FREE;
+ m_eyePt = eye;
+
+ m_directionH = RotateAngle(eye.x-lookat.x, eye.z-lookat.z)+PI/2.0f;
+ m_directionV = -RotateAngle(Length2d(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 = -PI*0.05f;
+ m_fixDist = 50.0f;
+ m_fixDirectionH = PI*0.25f;
+ m_fixDirectionV = -PI*0.10f;
+ m_centeringPhase = CP_NULL;
+ m_actualEye = m_eyePt;
+ m_actualLookat = 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(CAMERA_FREE);
+}
+
+
+// Donne l'objet pilotant la caméra.
+
+void CCamera::SetObject(CObject* object)
+{
+ m_cameraObj = object;
+}
+
+CObject* CCamera::RetObject()
+{
+ return m_cameraObj;
+}
+
+
+// Modifie le niveau de transparence d'un objet et des objets
+// transportés (pile & fret).
+
+void SetTransparency(CObject* pObj, float value)
+{
+ CObject* pFret;
+
+ pObj->SetTransparency(value);
+
+ pFret = pObj->RetFret();
+ if ( pFret != 0 )
+ {
+ pFret->SetTransparency(value);
+ }
+
+ pFret = pObj->RetPower();
+ if ( pFret != 0 )
+ {
+ pFret->SetTransparency(value);
+ }
+}
+
+// Modifie le type de la caméra.
+
+void CCamera::SetType(CameraType type)
+{
+ CObject* pObj;
+ ObjectType oType;
+ D3DVECTOR vUpVec;
+ int i;
+
+ m_remotePan = 0.0f;
+ m_remoteZoom = 0.0f;
+
+ if ( m_type == CAMERA_BACK && m_bTransparency )
+ {
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetTruck() ) continue; // pile ou fret?
+
+ SetTransparency(pObj, 0.0f); // objet opaque
+ }
+ }
+ m_bTransparency = FALSE;
+
+ if ( type == CAMERA_INFO ||
+ type == CAMERA_VISIT ) // xx -> info ?
+ {
+ m_normEye = m_engine->RetEyePt();
+ m_normLookat = m_engine->RetLookatPt();
+
+ m_engine->SetFocus(1.00f); // normal
+ m_type = type;
+ return;
+ }
+
+ if ( m_type == CAMERA_INFO ||
+ m_type == CAMERA_VISIT ) // info -> xx ?
+ {
+ m_engine->SetFocus(m_focus); // remet focus initial
+ m_type = type;
+
+ vUpVec = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ SetViewParams(m_normEye, m_normLookat, vUpVec);
+ return;
+ }
+
+ if ( m_type == CAMERA_BACK && type == CAMERA_FREE ) // back -> free ?
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f);
+ }
+
+ if ( m_type == CAMERA_BACK && type == CAMERA_EDIT ) // back -> edit ?
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -1.0f);
+ }
+
+ if ( m_type == CAMERA_ONBOARD && type == CAMERA_FREE ) // onboard -> free ?
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f);
+ }
+
+ if ( m_type == CAMERA_ONBOARD && type == CAMERA_EDIT ) // onboard -> edit ?
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -30.0f);
+ }
+
+ if ( m_type == CAMERA_ONBOARD && type == CAMERA_EXPLO ) // onboard -> explo ?
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -50.0f);
+ }
+
+ if ( m_type == CAMERA_BACK && type == CAMERA_EXPLO ) // back -> explo ?
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH, m_directionV, -20.0f);
+ }
+
+ if ( type == CAMERA_FIX ||
+ type == CAMERA_PLANE )
+ {
+ AbortCentering(); // stoppe cadrage spécial
+ }
+
+ m_fixDist = 50.0f;
+ if ( type == CAMERA_PLANE )
+ {
+ m_fixDist = 60.0f;
+ }
+
+ if ( type == CAMERA_BACK )
+ {
+ AbortCentering(); // stoppe cadrage spécial
+ m_addDirectionH = 0.0f;
+ m_addDirectionV = -PI*0.05f;
+
+ if ( m_cameraObj == 0 ) oType = OBJECT_NULL;
+ else oType = m_cameraObj->RetType();
+
+ 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 != CAMERA_ONBOARD && m_cameraObj != 0 )
+ {
+ m_cameraObj->SetGunGoalH(0.0f); // met le canon droit
+ }
+
+ if ( type == CAMERA_ONBOARD )
+ {
+ m_focus = 1.50f; // grand-angle
+ }
+ else
+ {
+ m_focus = 1.00f; // normal
+ }
+ m_engine->SetFocus(m_focus);
+
+ m_type = type;
+
+ SetSmooth(CS_NORM);
+}
+
+CameraType CCamera::RetType()
+{
+ return m_type;
+}
+
+
+// Gestion du mode de lissage.
+
+void CCamera::SetSmooth(CameraSmooth type)
+{
+ m_smooth = type;
+}
+
+CameraSmooth CCamera::RetSmoth()
+{
+ return m_smooth;
+}
+
+
+// Gestion de la distance de recul.
+
+void CCamera::SetDist(float dist)
+{
+ m_fixDist = dist;
+}
+
+float CCamera::RetDist()
+{
+ return m_fixDist;
+}
+
+
+// Gestion de l'angle en mode CAMERA_FIX.
+
+void CCamera::SetFixDirection(float angle)
+{
+ m_fixDirectionH = angle;
+}
+
+float CCamera::RetFixDirection()
+{
+ return m_fixDirectionH;
+}
+
+
+// Gestion de la télécommande panoramique de la caméra.
+
+void CCamera::SetRemotePan(float value)
+{
+ m_remotePan = value;
+}
+
+float CCamera::RetRemotePan()
+{
+ return m_remotePan;
+}
+
+// Gestion de la télécommande zoom (0..1) de la caméra.
+
+void CCamera::SetRemoteZoom(float value)
+{
+ value = Norm(value);
+
+ if ( m_type == CAMERA_BACK )
+ {
+ m_backDist = m_backMin+(200.0f-m_backMin)*value;
+ }
+
+ if ( m_type == CAMERA_FIX ||
+ m_type == CAMERA_PLANE )
+ {
+ m_fixDist = 10.0f+(200.0f-10.0f)*value;
+ }
+}
+
+float CCamera::RetRemoteZoom()
+{
+ if ( m_type == CAMERA_BACK )
+ {
+ return (m_backDist-m_backMin)/(200.0f-m_backMin);
+ }
+
+ if ( m_type == CAMERA_FIX ||
+ m_type == CAMERA_PLANE )
+ {
+ return (m_fixDist-10.0f)/(200.0f-10.0f);
+ }
+ return 0.0f;
+}
+
+
+
+// Début d'une visite circulaire avec la caméra.
+
+void CCamera::StartVisit(D3DVECTOR goal, float dist)
+{
+ m_visitType = m_type;
+ SetType(CAMERA_VISIT);
+ m_visitGoal = goal;
+ m_visitDist = dist;
+ m_visitTime = 0.0f;
+ m_visitDirectionH = 0.0f;
+ m_visitDirectionV = -PI*0.10f;
+}
+
+// Fin d'une visite circulaire avec la caméra.
+
+void CCamera::StopVisit()
+{
+ SetType(m_visitType); // remet le type initial
+}
+
+
+// Retourne le point de vue de la caméra.
+
+void CCamera::RetCamera(D3DVECTOR &eye, D3DVECTOR &lookat)
+{
+ eye = m_eyePt;
+ lookat = LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
+}
+
+
+// Spécifie un mouvement spécial de caméra pour cadrer une action.
+
+BOOL CCamera::StartCentering(CObject *object, float angleH, float angleV,
+ float dist, float time)
+{
+ if ( m_type != CAMERA_BACK ) return FALSE;
+ if ( object != m_cameraObj ) return FALSE;
+
+ if ( m_centeringPhase != CP_NULL ) return FALSE;
+
+ if ( m_addDirectionH > PI )
+ {
+ angleH = PI*2.0f-angleH;
+ }
+
+ m_centeringPhase = CP_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;
+}
+
+// Termine un mouvement spécial de caméra pour cadrer une action.
+
+BOOL CCamera::StopCentering(CObject *object, float time)
+{
+ if ( m_type != CAMERA_BACK ) return FALSE;
+ if ( object != m_cameraObj ) return FALSE;
+
+ if ( m_centeringPhase != CP_START &&
+ m_centeringPhase != CP_WAIT ) return FALSE;
+
+ m_centeringPhase = CP_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;
+}
+
+// Stoppe le cadrage spécial dans la position actuelle.
+
+void CCamera::AbortCentering()
+{
+ if ( m_type == CAMERA_INFO ||
+ m_type == CAMERA_VISIT ) return;
+
+ if ( m_centeringPhase == CP_NULL ) return;
+
+ m_centeringPhase = CP_NULL;
+
+ if ( m_centeringAngleH != 99.9f )
+ {
+ m_addDirectionH = m_centeringCurrentH;
+ }
+ if ( m_centeringAngleV != 99.9f )
+ {
+ m_addDirectionV = m_centeringCurrentV;
+ }
+}
+
+
+
+// Supprime l'effet spécial avec la caméra.
+
+void CCamera::FlushEffect()
+{
+ m_effectType = CE_NULL;
+ m_effectForce = 0.0f;
+ m_effectProgress = 0.0f;
+ m_effectOffset = D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+// Démarre un effet spécial avec la caméra.
+
+void CCamera::StartEffect(CameraEffect effect, D3DVECTOR pos, float force)
+{
+ if ( !m_bEffect ) return;
+
+ m_effectType = effect;
+ m_effectPos = pos;
+ m_effectForce = force;
+ m_effectProgress = 0.0f;
+}
+
+// Fait progresser l'effet de la caméra.
+
+void CCamera::EffectFrame(const Event &event)
+{
+ float dist, force;
+
+ if ( m_type == CAMERA_INFO ||
+ m_type == CAMERA_VISIT ) return;
+
+ if ( m_effectType == CE_NULL ) return;
+
+ m_effectOffset = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ force = m_effectForce;
+
+ if ( m_effectType == CE_TERRAFORM )
+ {
+ m_effectProgress += event.rTime*0.7f;
+ m_effectOffset.x = (Rand()-0.5f)*10.0f;
+ m_effectOffset.y = (Rand()-0.5f)*10.0f;
+ m_effectOffset.z = (Rand()-0.5f)*10.0f;
+
+ force *= 1.0f-m_effectProgress;
+ }
+
+ if ( m_effectType == CE_EXPLO )
+ {
+ m_effectProgress += event.rTime*1.0f;
+ m_effectOffset.x = (Rand()-0.5f)*5.0f;
+ m_effectOffset.y = (Rand()-0.5f)*5.0f;
+ m_effectOffset.z = (Rand()-0.5f)*5.0f;
+
+ force *= 1.0f-m_effectProgress;
+ }
+
+ if ( m_effectType == CE_SHOT )
+ {
+ m_effectProgress += event.rTime*1.0f;
+ m_effectOffset.x = (Rand()-0.5f)*2.0f;
+ m_effectOffset.y = (Rand()-0.5f)*2.0f;
+ m_effectOffset.z = (Rand()-0.5f)*2.0f;
+
+ force *= 1.0f-m_effectProgress;
+ }
+
+ if ( m_effectType == CE_CRASH )
+ {
+ m_effectProgress += event.rTime*5.0f;
+ m_effectOffset.y = sinf(m_effectProgress*PI)*1.5f;
+ m_effectOffset.x = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress);
+ m_effectOffset.z = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress);
+ }
+
+ if ( m_effectType == CE_VIBRATION )
+ {
+ m_effectProgress += event.rTime*0.1f;
+ m_effectOffset.y = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress);
+ m_effectOffset.x = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress);
+ m_effectOffset.z = (Rand()-0.5f)*1.0f*(1.0f-m_effectProgress);
+ }
+
+ if ( m_effectType == CE_PET )
+ {
+ m_effectProgress += event.rTime*5.0f;
+ m_effectOffset.x = (Rand()-0.5f)*0.2f;
+ m_effectOffset.y = (Rand()-0.5f)*2.0f;
+ m_effectOffset.z = (Rand()-0.5f)*0.2f;
+ }
+
+ dist = Length(m_eyePt, m_effectPos);
+ dist = 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();
+ }
+}
+
+
+// Supprime l'effet de superposition au premier plan.
+
+void CCamera::FlushOver()
+{
+ m_overType = OE_NULL;
+ m_overColorBase.r = 0.0f; // noir
+ m_overColorBase.g = 0.0f;
+ m_overColorBase.b = 0.0f;
+ m_overColorBase.a = 0.0f;
+ m_engine->SetOverColor(); // rien
+}
+
+// Spécifie la couleur de base.
+
+void CCamera::SetOverBaseColor(D3DCOLORVALUE color)
+{
+ m_overColorBase = color;
+}
+
+// Démarre un effet de superposition au premier plan.
+
+void CCamera::StartOver(OverEffect effect, D3DVECTOR pos, float force)
+{
+ D3DCOLOR color;
+ float dist, decay;
+
+ m_overType = effect;
+ m_overTime = 0.0f;
+
+ if ( m_overType == OE_BLITZ ) decay = 400.0f;
+ else decay = 100.0f;
+ dist = Length(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 == OE_BLOOD )
+ {
+ m_overColor.r = 0.8f;
+ m_overColor.g = 0.1f;
+ m_overColor.b = 0.1f; // rouge
+ m_overMode = D3DSTATETCb;
+
+ m_overFadeIn = 0.4f;
+ m_overFadeOut = 0.8f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == OE_FADEINw )
+ {
+ m_overColor.r = 1.0f;
+ m_overColor.g = 1.0f;
+ m_overColor.b = 1.0f; // blanc
+ m_overMode = D3DSTATETCb;
+
+ m_overFadeIn = 0.0f;
+ m_overFadeOut =20.0f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == OE_FADEOUTw )
+ {
+ m_overColor.r = 1.0f;
+ m_overColor.g = 1.0f;
+ m_overColor.b = 1.0f; // blanc
+ m_overMode = D3DSTATETCb;
+
+ m_overFadeIn = 6.0f;
+ m_overFadeOut = 100000.0f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == OE_FADEOUTb )
+ {
+ color = m_engine->RetFogColor(1); // couleur brouillard sous-marin
+ m_overColor = RetColor(color);
+ m_overMode = D3DSTATETCw;
+
+ m_overFadeIn = 4.0f;
+ m_overFadeOut = 100000.0f;
+ m_overForce = 1.0f;
+ }
+
+ if ( m_overType == OE_BLITZ )
+ {
+ m_overColor.r = 0.9f;
+ m_overColor.g = 1.0f;
+ m_overColor.b = 1.0f; // blanc-cyan
+ m_overMode = D3DSTATETCb;
+
+ m_overFadeIn = 0.0f;
+ m_overFadeOut = 1.0f;
+ }
+}
+
+// Fait progresser l'effet de superposition au premier plan.
+
+void CCamera::OverFrame(const Event &event)
+{
+ D3DCOLORVALUE color;
+ float intensity;
+
+ if ( m_type == CAMERA_INFO ||
+ m_type == CAMERA_VISIT ) return;
+
+ if ( m_overType == OE_NULL )
+ {
+ return;
+ }
+
+ m_overTime += event.rTime;
+
+ if ( m_overType == OE_BLITZ )
+ {
+ 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.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ }
+ color.a = 0.0f;
+ m_engine->SetOverColor(RetColor(color), m_overMode);
+ }
+ else
+ {
+ if ( m_overFadeIn > 0.0f && m_overTime < m_overFadeIn )
+ {
+ intensity = m_overTime/m_overFadeIn;
+ intensity *= m_overForce;
+
+ if ( m_overMode == D3DSTATETCw )
+ {
+ 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(RetColor(color), m_overMode);
+ }
+ else if ( m_overFadeOut > 0.0f && m_overTime-m_overFadeIn < m_overFadeOut )
+ {
+ intensity = 1.0f-(m_overTime-m_overFadeIn)/m_overFadeOut;
+ intensity *= m_overForce;
+
+ if ( m_overMode == D3DSTATETCw )
+ {
+ 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(RetColor(color), m_overMode);
+ }
+ }
+
+ if ( m_overTime >= m_overFadeIn+m_overFadeOut )
+ {
+ FlushOver();
+ return;
+ }
+}
+
+
+
+// Fixe le mouvement mou de la caméra.
+
+void 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);
+}
+
+// Spécifie l'emplacement et la direction du point de vue au moteur 3D.
+
+void CCamera::SetViewTime(const D3DVECTOR &vEyePt,
+ const D3DVECTOR &vLookatPt,
+ float rTime)
+{
+ D3DVECTOR vUpVec, eye, lookat;
+ float prog, dist, h;
+
+ if ( m_type == CAMERA_INFO )
+ {
+ eye = vEyePt;
+ lookat = vLookatPt;
+ }
+ else
+ {
+ if ( m_initDelay > 0.0f )
+ {
+ m_initDelay -= rTime;
+ if ( m_initDelay < 0.0f ) m_initDelay = 0.0f;
+ rTime /= 1.0f+m_initDelay;
+ }
+
+ eye = vEyePt;
+ lookat = vLookatPt;
+ if ( !IsCollision(eye, lookat) )
+ {
+ m_finalEye = eye;
+ m_finalLookat = lookat;
+ }
+
+ dist = Length(m_finalEye, m_actualEye);
+ if ( m_smooth == CS_NONE ) prog = dist;
+ if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*0.5f;
+ if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f;
+ if ( m_smooth == CS_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 = Length(m_finalLookat, m_actualLookat);
+ if ( m_smooth == CS_NONE ) prog = dist;
+ if ( m_smooth == CS_NORM ) prog = powf(dist, 1.5f)*rTime*2.0f;
+ if ( m_smooth == CS_HARD ) prog = powf(dist, 1.0f)*rTime*4.0f;
+ if ( m_smooth == CS_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);
+
+ h = m_terrain->RetFloorLevel(eye);
+ if ( eye.y < h+4.0f )
+ {
+ eye.y = h+4.0f;
+ }
+
+ lookat = m_effectOffset+m_actualLookat;
+ }
+
+ vUpVec = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ SetViewParams(eye, lookat, vUpVec);
+}
+
+
+// Evite les obstacles.
+
+BOOL CCamera::IsCollision(D3DVECTOR &eye, D3DVECTOR lookat)
+{
+ if ( m_type == CAMERA_BACK ) return IsCollisionBack(eye, lookat);
+ if ( m_type == CAMERA_FIX ) return IsCollisionFix(eye, lookat);
+ if ( m_type == CAMERA_PLANE ) return IsCollisionFix(eye, lookat);
+ return FALSE;
+}
+
+// Evite les obstacles.
+
+BOOL CCamera::IsCollisionBack(D3DVECTOR &eye, D3DVECTOR lookat)
+{
+#if 0
+ CObject *pObj;
+ D3DVECTOR oPos, min, max, proj;
+ ObjectType oType, iType;
+ float oRadius, dpp, dpl, del, dist, len, prox;
+ int i;
+
+ if ( m_cameraObj == 0 )
+ {
+ iType = OBJECT_NULL;
+ }
+ else
+ {
+ iType = m_cameraObj->RetType();
+ }
+
+ min.x = Min(eye.x, lookat.x);
+ min.y = Min(eye.y, lookat.y);
+ min.z = Min(eye.z, lookat.z);
+
+ max.x = Max(eye.x, lookat.x);
+ max.y = Max(eye.y, lookat.y);
+ max.z = Max(eye.z, lookat.z);
+
+ prox = 8.0f; // proximité maximale du véhicule
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_cameraObj ) continue;
+
+ oType = pObj->RetType();
+ if ( oType == OBJECT_TOTO ||
+ oType == OBJECT_FIX ||
+ oType == OBJECT_FRET ||
+ oType == OBJECT_STONE ||
+ oType == OBJECT_URANIUM ||
+ oType == OBJECT_METAL ||
+ oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_BULLET ||
+ oType == OBJECT_BBOX ||
+ oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB ||
+ oType == OBJECT_WAYPOINTb ||
+ oType == OBJECT_WAYPOINTr ||
+ oType == OBJECT_WAYPOINTg ||
+ oType == OBJECT_WAYPOINTy ||
+ oType == OBJECT_WAYPOINTv ||
+ oType == OBJECT_FLAGb ||
+ oType == OBJECT_FLAGr ||
+ oType == OBJECT_FLAGg ||
+ oType == OBJECT_FLAGy ||
+ oType == OBJECT_FLAGv ||
+ oType == OBJECT_ANT ||
+ oType == OBJECT_SPIDER ||
+ oType == OBJECT_BEE ||
+ oType == OBJECT_WORM ) continue;
+
+ pObj->GetGlobalSphere(oPos, oRadius);
+ if ( oRadius <= 0.0f ) continue;
+
+ 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;
+
+ if ( iType == OBJECT_FACTORY )
+ {
+ dpl = Length(oPos, lookat);
+ if ( dpl < oRadius ) continue;
+ }
+
+ proj = Projection(eye, lookat, oPos);
+ dpp = Length(proj, oPos);
+ if ( dpp > oRadius ) continue;
+
+ del = Length(eye, lookat);
+ len = Length(eye, proj);
+ if ( len > del ) continue;
+
+ dist = sqrtf(oRadius*oRadius + dpp*dpp)-3.0f;
+ if ( dist < 0.0f ) dist = 0.0f;
+ proj = (lookat-eye)*dist/del + proj;
+ len = Length(eye, proj);
+
+ if ( len < del-prox )
+ {
+ eye = proj;
+ eye.y += len/5.0f;
+ return FALSE;
+ }
+ else
+ {
+ eye = (eye-lookat)*prox/del + lookat;
+ eye.y += (del-prox)/5.0f;
+ return FALSE;
+ }
+ }
+ return FALSE;
+#else
+ CObject *pObj;
+ D3DVECTOR oPos, min, max, proj;
+ ObjectType oType, iType;
+ float oRadius, dpp, del, len, angle;
+ int i;
+
+ if ( m_cameraObj == 0 )
+ {
+ iType = OBJECT_NULL;
+ }
+ else
+ {
+ iType = m_cameraObj->RetType();
+ }
+
+ min.x = Min(m_actualEye.x, m_actualLookat.x);
+ min.y = Min(m_actualEye.y, m_actualLookat.y);
+ min.z = Min(m_actualEye.z, m_actualLookat.z);
+
+ max.x = Max(m_actualEye.x, m_actualLookat.x);
+ max.y = Max(m_actualEye.y, m_actualLookat.y);
+ max.z = Max(m_actualEye.z, m_actualLookat.z);
+
+ m_bTransparency = FALSE;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetTruck() ) continue; // pile ou fret?
+
+ SetTransparency(pObj, 0.0f); // objet opaque
+
+ if ( pObj == m_cameraObj ) continue;
+
+ if ( iType == OBJECT_BASE || // bâtiment ?
+ 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;
+
+ oType = pObj->RetType();
+ 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;
+
+ pObj->GetGlobalSphere(oPos, oRadius);
+ if ( oRadius <= 2.0f ) continue; // ignore les petits objets
+
+ 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;
+
+ proj = Projection(m_actualEye, m_actualLookat, oPos);
+ dpp = Length(proj, oPos);
+ if ( dpp > oRadius ) continue;
+
+ if ( oType == OBJECT_FACTORY )
+ {
+ angle = RotateAngle(m_actualEye.x-oPos.x, oPos.z-m_actualEye.z); // CW !
+ angle = Direction(angle, pObj->RetAngleY(0));
+ if ( Abs(angle) < 30.0f*PI/180.0f ) continue; // dans la porte ?
+ }
+
+ del = Length(m_actualEye, m_actualLookat);
+ if ( oType == OBJECT_FACTORY )
+ {
+ del += oRadius;
+ }
+
+ len = Length(m_actualEye, proj);
+ if ( len > del ) continue;
+
+ SetTransparency(pObj, 1.0f); // objet transparent
+ m_bTransparency = TRUE;
+ }
+ return FALSE;
+#endif
+}
+
+// Evite les obstacles.
+
+BOOL CCamera::IsCollisionFix(D3DVECTOR &eye, D3DVECTOR lookat)
+{
+ CObject *pObj;
+ D3DVECTOR oPos, proj;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_cameraObj ) continue;
+
+ type = pObj->RetType();
+ 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;
+
+ pObj->GetGlobalSphere(oPos, oRadius);
+ if ( oRadius == 0.0f ) continue;
+
+ dist = Length(eye, oPos);
+ if ( dist < oRadius )
+ {
+ dist = Length(eye, lookat);
+ proj = Projection(eye, lookat, oPos);
+ eye = (lookat-eye)*oRadius/dist + proj;
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CCamera::EventProcess(const Event &event)
+{
+ switch( event.event )
+ {
+ case EVENT_FRAME:
+ EventFrame(event);
+ break;
+
+#if 0
+ case EVENT_RBUTTONDOWN:
+ m_bRightDown = TRUE;
+ m_rightPosInit = event.pos;
+ m_rightPosCenter = FPOINT(0.5f, 0.5f);
+ m_engine->MoveMousePos(m_rightPosCenter);
+//? m_engine->SetMouseHide(TRUE); // cache la souris
+ break;
+
+ case EVENT_RBUTTONUP:
+ m_bRightDown = FALSE;
+ m_engine->MoveMousePos(m_rightPosInit);
+//? m_engine->SetMouseHide(FALSE); // remontre la souris
+ m_addDirectionH = 0.0f;
+ m_addDirectionV = -PI*0.05f;
+ break;
+#endif
+
+ case EVENT_MOUSEMOVE:
+ EventMouseMove(event);
+ break;
+
+ case EVENT_KEYDOWN:
+ if ( event.param == VK_WHEELUP ) EventMouseWheel(+1);
+ if ( event.param == VK_WHEELDOWN ) EventMouseWheel(-1);
+ break;
+ }
+ return TRUE;
+}
+
+// Fait évoluer la caméra selon la souris déplacée.
+
+BOOL CCamera::EventMouseMove(const Event &event)
+{
+ m_mousePos = event.pos;
+ return TRUE;
+}
+
+// Molette souris actionnée.
+
+void CCamera::EventMouseWheel(int dir)
+{
+ if ( m_type == CAMERA_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 == CAMERA_FIX ||
+ m_type == CAMERA_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 == CAMERA_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;
+ }
+ }
+}
+
+// Fait évoluer la caméra selon le temps écoulé.
+
+BOOL CCamera::EventFrame(const Event &event)
+{
+ EffectFrame(event);
+ OverFrame(event);
+
+ if ( m_type == CAMERA_FREE )
+ {
+ return EventFrameFree(event);
+ }
+ if ( m_type == CAMERA_EDIT )
+ {
+ return EventFrameEdit(event);
+ }
+ if ( m_type == CAMERA_DIALOG )
+ {
+ return EventFrameDialog(event);
+ }
+ if ( m_type == CAMERA_BACK )
+ {
+ return EventFrameBack(event);
+ }
+ if ( m_type == CAMERA_FIX ||
+ m_type == CAMERA_PLANE )
+ {
+ return EventFrameFix(event);
+ }
+ if ( m_type == CAMERA_EXPLO )
+ {
+ return EventFrameExplo(event);
+ }
+ if ( m_type == CAMERA_ONBOARD )
+ {
+ return EventFrameOnBoard(event);
+ }
+ if ( m_type == CAMERA_SCRIPT )
+ {
+ return EventFrameScript(event);
+ }
+ if ( m_type == CAMERA_INFO )
+ {
+ return EventFrameInfo(event);
+ }
+ if ( m_type == CAMERA_VISIT )
+ {
+ return EventFrameVisit(event);
+ }
+
+ return TRUE;
+}
+
+
+// Retourne le sprite par défaut à utiliser pour la souris.
+
+D3DMouse CCamera::RetMouseDef(FPOINT pos)
+{
+ D3DMouse type;
+
+ type = D3DMOUSENORM;
+ m_mousePos = pos;
+
+ if ( m_type == CAMERA_INFO ) return type;
+
+ if ( m_bRightDown ) // bouton droite pressé ?
+ {
+ m_rightPosMove.x = pos.x - m_rightPosCenter.x;
+ m_rightPosMove.y = pos.y - m_rightPosCenter.y;
+ type = D3DMOUSEMOVE;
+ }
+ else
+ {
+ if ( !m_bCameraScroll ) 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 == CAMERA_FREE ||
+ m_type == CAMERA_EDIT ||
+ m_type == CAMERA_BACK ||
+ m_type == CAMERA_FIX ||
+ m_type == CAMERA_PLANE ||
+ m_type == CAMERA_EXPLO )
+ {
+ if ( m_mouseDirH > 0.0f )
+ {
+ type = D3DMOUSESCROLLR;
+ }
+ if ( m_mouseDirH < 0.0f )
+ {
+ type = D3DMOUSESCROLLL;
+ }
+ }
+
+ if ( m_type == CAMERA_FREE ||
+ m_type == CAMERA_EDIT )
+ {
+ if ( m_mouseDirV > 0.0f )
+ {
+ type = D3DMOUSESCROLLU;
+ }
+ if ( m_mouseDirV < 0.0f )
+ {
+ type = D3DMOUSESCROLLD;
+ }
+ }
+
+ if ( m_bCameraInvertX )
+ {
+ m_mouseDirH = -m_mouseDirH;
+ }
+ }
+
+ return type;
+}
+
+
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameFree(const Event &event)
+{
+ D3DVECTOR pos, vLookatPt;
+ float factor;
+
+ 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 = LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed);
+ }
+
+ // Up/Down.
+ m_eyePt = 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 = LookatPoint(m_eyePt, m_directionH+PI/2.0f, m_directionV, -event.axeX*event.rTime*factor*m_speed);
+ }
+ if ( event.axeX > 0.0f )
+ {
+ m_eyePt = LookatPoint(m_eyePt, m_directionH-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;
+
+ pos = m_eyePt;
+ if ( m_terrain->MoveOnFloor(pos, TRUE) )
+ {
+ pos.y -= 2.0f;
+ if ( m_eyePt.y < pos.y )
+ {
+ m_eyePt.y = pos.y;
+ }
+ }
+
+ }
+
+ vLookatPt = LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
+
+ if ( m_terrain->MoveOnFloor(vLookatPt, TRUE) )
+ {
+ vLookatPt.y += m_heightLookat;
+ }
+
+ SetViewTime(m_eyePt, vLookatPt, event.rTime);
+
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameEdit(const Event &event)
+{
+ D3DVECTOR pos, vLookatPt;
+ float factor;
+
+ 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 = LookatPoint(m_eyePt, m_directionH, m_directionV, m_mouseDirV*event.rTime*factor*m_speed);
+ }
+
+ if ( m_bCameraScroll )
+ {
+ // Left/Right.
+ m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed;
+ m_fixDirectionH = NormAngle(m_fixDirectionH);
+
+ // Up/Down.
+//? m_fixDirectionV -= m_mouseDirV*event.rTime*0.5f*m_speed;
+//? if ( m_fixDirectionV < -PI*0.40f ) m_fixDirectionV = -PI*0.40f;
+//? if ( m_fixDirectionV > PI*0.20f ) m_fixDirectionV = PI*0.20f;
+ }
+
+ m_terrain->ValidPosition(m_eyePt, 10.0f);
+
+ if ( m_terrain->MoveOnFloor(m_eyePt, FALSE) )
+ {
+ m_eyePt.y += m_editHeight;
+
+ pos = m_eyePt;
+ if ( m_terrain->MoveOnFloor(pos, FALSE) )
+ {
+ pos.y += 2.0f;
+ if ( m_eyePt.y < pos.y )
+ {
+ m_eyePt.y = pos.y;
+ }
+ }
+
+ }
+
+ vLookatPt = LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
+
+ if ( m_terrain->MoveOnFloor(vLookatPt, TRUE) )
+ {
+ vLookatPt.y += m_heightLookat;
+ }
+
+ SetViewTime(m_eyePt, vLookatPt, event.rTime);
+
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameDialog(const Event &event)
+{
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameBack(const Event &event)
+{
+ CPhysics* physics;
+ ObjectType type;
+ D3DVECTOR pos, vLookatPt;
+ FPOINT mouse;
+ float centeringH, centeringV, centeringD, h, v, d, floor;
+
+ if ( m_cameraObj == 0 )
+ {
+ type = OBJECT_NULL;
+ }
+ else
+ {
+ type = m_cameraObj->RetType();
+ }
+
+ // +/-.
+ 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_bRightDown )
+ {
+ m_addDirectionH = m_rightPosMove.x*6.0f;
+ m_addDirectionV = -m_rightPosMove.y*2.0f;
+ }
+ else
+ {
+ if ( m_bCameraScroll )
+ {
+#if 1
+ // Left/Right.
+ m_addDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed;
+ m_addDirectionH = NormAngle(m_addDirectionH);
+
+ // Up/Down.
+//? m_backDist -= m_mouseDirV*event.rTime*30.0f*m_speed;
+//? if ( m_backDist < 10.0f ) m_backDist = 10.0f;
+//? if ( m_backDist > 200.0f ) m_backDist = 200.0f;
+#else
+ if ( m_mousePos.y >= 0.18f && m_mousePos.y <= 0.93f )
+ {
+//? m_addDirectionH = -(m_mousePos.x-0.5f)*4.0f;
+ m_addDirectionV = (m_mousePos.y-0.5f)*2.0f;
+//? if ( m_bCameraInvertX ) m_addDirectionH = -m_addDirectionH;
+ if ( m_bCameraInvertY ) m_addDirectionV = -m_addDirectionV;
+
+ if ( m_mousePos.x < 0.5f ) m_motorTurn = -1.0f;
+ if ( m_mousePos.x > 0.5f ) m_motorTurn = 1.0f;
+
+ mouse = m_mousePos;
+ mouse.x = 0.5f;
+ m_engine->MoveMousePos(mouse);
+ }
+ else
+ {
+ m_addDirectionH = 0.0f;
+ m_addDirectionV = 0.0f;
+ }
+#endif
+ }
+ }
+
+ if ( m_mouseDirH != 0 || m_mouseDirV != 0 )
+ {
+ AbortCentering(); // stoppe cadrage spécial
+ }
+
+ // Progression du cadrage spécial.
+ centeringH = 0.0f;
+ centeringV = 0.0f;
+ centeringD = 0.0f;
+
+ if ( m_centeringPhase == CP_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 = CP_WAIT;
+ }
+ }
+
+ if ( m_centeringPhase == CP_WAIT )
+ {
+ centeringH = 1.0f;
+ centeringV = 1.0f;
+ centeringD = 1.0f;
+ }
+
+ if ( m_centeringPhase == CP_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 = CP_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 != 0 )
+ {
+ vLookatPt = m_cameraObj->RetPosition(0);
+ if ( type == OBJECT_BASE ) vLookatPt.y += 40.0f;
+ else if ( type == OBJECT_HUMAN ) vLookatPt.y += 1.0f;
+ else if ( type == OBJECT_TECH ) vLookatPt.y += 1.0f;
+ else vLookatPt.y += 4.0f;
+
+ h = -m_cameraObj->RetAngleY(0); // angle véhicule/batiment
+
+ 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 ) // batiment ?
+ {
+ h += PI*0.20f; // presque de face
+ }
+ else // véhicule ?
+ {
+ h += PI; // de dos
+ }
+ h = NormAngle(h)+m_remotePan;
+ v = 0.0f; //?
+
+ h += m_centeringCurrentH;
+ h += m_addDirectionH*(1.0f-centeringH);
+ h = NormAngle(h);
+
+ if ( type == OBJECT_MOBILEdr ) // dessinateur ?
+ {
+ v -= 0.3f; // caméra plus haute
+ }
+
+ v += m_centeringCurrentV;
+ v += m_addDirectionV*(1.0f-centeringV);
+
+ d = m_backDist;
+ d += m_centeringDist*centeringD;
+
+ m_centeringCurrentH = m_centeringAngleH*centeringH;
+ m_centeringCurrentV = m_centeringAngleV*centeringV;
+
+ m_eyePt = RotateView(vLookatPt, h, v, d);
+
+ physics = m_cameraObj->RetPhysics();
+ if ( physics != 0 && physics->RetLand() ) // au sol ?
+ {
+ pos = vLookatPt+(vLookatPt-m_eyePt);
+ floor = m_terrain->RetFloorHeight(pos)-4.0f;
+ if ( floor > 0.0f )
+ {
+ m_eyePt.y += floor; // montre la descente devant
+ }
+ }
+
+ m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v);
+ m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v);
+
+ SetViewTime(m_eyePt, vLookatPt, event.rTime);
+
+ m_directionH = h+PI/2.0f;
+ m_directionV = v;
+ }
+
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameFix(const Event &event)
+{
+ D3DVECTOR pos, vLookatPt;
+ float h, v, d;
+
+ // +/-.
+ 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_bCameraScroll )
+ {
+ // Left/Right.
+ m_fixDirectionH += m_mouseDirH*event.rTime*1.0f*m_speed;
+ m_fixDirectionH = NormAngle(m_fixDirectionH);
+
+ // Up/Down.
+//? m_fixDist -= m_mouseDirV*event.rTime*30.0f*m_speed;
+//? if ( m_fixDist < 10.0f ) m_fixDist = 10.0f;
+//? if ( m_fixDist > 200.0f ) m_fixDist = 200.0f;
+ }
+
+ if ( m_mouseDirH != 0 || m_mouseDirV != 0 )
+ {
+ AbortCentering(); // stoppe cadrage spécial
+ }
+
+ if ( m_cameraObj != 0 )
+ {
+ vLookatPt = m_cameraObj->RetPosition(0);
+
+ h = m_fixDirectionH+m_remotePan;
+ v = m_fixDirectionV;
+
+ d = m_fixDist;
+//- if ( m_type == CAMERA_PLANE ) d += 20.0f;
+ m_eyePt = RotateView(vLookatPt, h, v, d);
+//- if ( m_type == CAMERA_PLANE ) m_eyePt.y += 50.0f;
+ if ( m_type == CAMERA_PLANE ) m_eyePt.y += m_fixDist/2.0f;
+ m_eyePt = ExcludeTerrain(m_eyePt, vLookatPt, h, v);
+ m_eyePt = ExcludeObject(m_eyePt, vLookatPt, h, v);
+
+ SetViewTime(m_eyePt, vLookatPt, event.rTime);
+
+ m_directionH = h+PI/2.0f;
+ m_directionV = v;
+ }
+
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameExplo(const Event &event)
+{
+ D3DVECTOR pos, vLookatPt;
+ float factor;
+
+ 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;
+
+ pos = m_eyePt;
+ if ( m_terrain->MoveOnFloor(pos, FALSE) )
+ {
+ pos.y += 2.0f;
+ if ( m_eyePt.y < pos.y )
+ {
+ m_eyePt.y = pos.y;
+ }
+ }
+
+ }
+
+ vLookatPt = LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
+
+ if ( m_terrain->MoveOnFloor(vLookatPt, TRUE) )
+ {
+ vLookatPt.y += m_heightLookat;
+ }
+
+ SetViewTime(m_eyePt, vLookatPt, event.rTime);
+
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameOnBoard(const Event &event)
+{
+ D3DVECTOR vLookatPt, vUpVec, eye, lookat, pos;
+
+ if ( m_cameraObj != 0 )
+ {
+ m_cameraObj->SetViewFromHere(m_eyePt, m_directionH, m_directionV,
+ vLookatPt, vUpVec, m_type);
+ eye = m_effectOffset*0.3f+m_eyePt;
+ lookat = m_effectOffset*0.3f+vLookatPt;
+
+ SetViewParams(eye, lookat, vUpVec);
+ m_actualEye = eye;
+ m_actualLookat = lookat;
+ }
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameInfo(const Event &event)
+{
+ SetViewTime(D3DVECTOR(0.0f, 0.0f, 0.0f),
+ D3DVECTOR(0.0f, 0.0f, 1.0f),
+ event.rTime);
+ return TRUE;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameVisit(const Event &event)
+{
+ D3DVECTOR eye;
+ float angleH, angleV;
+
+ 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 < -PI*0.40f ) m_visitDirectionV = -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_bCameraScroll )
+ {
+ 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;
+ }
+
+ angleH = (m_visitTime/10.0f)*(PI*2.0f);
+ angleV = m_visitDirectionV;
+ 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;
+}
+
+// Déplace le point de vue.
+
+BOOL CCamera::EventFrameScript(const Event &event)
+{
+ SetViewTime(m_scriptEye+m_effectOffset,
+ m_scriptLookat+m_effectOffset, event.rTime);
+ return TRUE;
+}
+
+void CCamera::SetScriptEye(D3DVECTOR eye)
+{
+ m_scriptEye = eye;
+}
+
+void CCamera::SetScriptLookat(D3DVECTOR lookat)
+{
+ m_scriptLookat = lookat;
+}
+
+
+// Spécifie l'emplacement et la direction du point de vue.
+
+void CCamera::SetViewParams(const D3DVECTOR &eye, const D3DVECTOR &lookat,
+ const D3DVECTOR &up)
+{
+ BOOL bUnder;
+
+ m_engine->SetViewParams(eye, lookat, up, m_eyeDistance);
+
+ bUnder = (eye.y < m_water->RetLevel()); // est-on sous l'eau ?
+ if ( m_type == CAMERA_INFO ) bUnder = FALSE;
+ m_engine->SetRankView(bUnder?1:0);
+}
+
+
+// Adapte la caméra pour ne pas entrer dans le terrain.
+
+D3DVECTOR CCamera::ExcludeTerrain(D3DVECTOR eye, D3DVECTOR lookat,
+ float &angleH, float &angleV)
+{
+ D3DVECTOR pos;
+ float dist;
+
+ pos = eye;
+ if ( m_terrain->MoveOnFloor(pos) )
+ {
+ dist = Length2d(lookat, pos);
+ pos.y += 2.0f+dist*0.1f;
+ if ( pos.y > eye.y )
+ {
+ angleV = -RotateAngle(dist, pos.y-lookat.y);
+ eye = RotateView(lookat, angleH, angleV, dist);
+ }
+ }
+ return eye;
+}
+
+// Adapte la caméra pour ne pas pénétrer dans un objet.
+
+D3DVECTOR CCamera::ExcludeObject(D3DVECTOR eye, D3DVECTOR lookat,
+ float &angleH, float &angleV)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ float oRad, dist;
+ int i, j;
+
+return eye;
+//?
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRad) )
+ {
+ dist = Length(oPos, eye);
+ if ( dist < oRad+2.0f )
+ {
+ eye.y = oPos.y+oRad+2.0f;
+ }
+ }
+ }
+
+ return eye;
+}
+
+
diff --git a/src/camera.h b/src/camera.h
new file mode 100644
index 0000000..1f2c41c
--- /dev/null
+++ b/src/camera.h
@@ -0,0 +1,252 @@
+// camera.h
+
+#ifndef _CAMERA_H_
+#define _CAMERA_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CTerrain;
+class CWater;
+class CObject;
+enum D3DMouse;
+
+
+enum CameraType
+{
+ CAMERA_NULL = 0, // caméra indéfinie
+ CAMERA_FREE = 1, // caméra libre (jamais en principe)
+ CAMERA_EDIT = 2, // caméra pendant l'édition d'un programme
+ CAMERA_ONBOARD = 3, // caméra à bord d'un robot
+ CAMERA_BACK = 4, // caméra derrière un robot
+ CAMERA_FIX = 5, // caméra fixe après robot
+ CAMERA_EXPLO = 6, // caméra immobile après explosion
+ CAMERA_SCRIPT = 7, // caméra pendant un film scripté
+ CAMERA_INFO = 8, // caméra pendant l'affichage des informations
+ CAMERA_VISIT = 9, // visite du lieu d'une erreur
+ CAMERA_DIALOG = 10, // caméra pendant dialogue
+ CAMERA_PLANE = 11, // caméra fixe en hauteur
+};
+
+enum CameraSmooth
+{
+ CS_NONE = 0, // brusque
+ CS_NORM = 1, // normal
+ CS_HARD = 2, // dur
+ CS_SPEC = 3, // spécial
+};
+
+enum CenteringPhase
+{
+ CP_NULL = 0,
+ CP_START = 1,
+ CP_WAIT = 2,
+ CP_STOP = 3,
+};
+
+enum CameraEffect
+{
+ CE_NULL = 0, // pas d'effet
+ CE_TERRAFORM = 1, // terrassement
+ CE_CRASH = 2, // véhicule volant posé violemment
+ CE_EXPLO = 3, // explosion
+ CE_SHOT = 4, // coup non mortel
+ CE_VIBRATION = 5, // vibration pendant construction
+ CE_PET = 6, // raté du réacteur
+};
+
+enum OverEffect
+{
+ OE_NULL = 0, // pas d'effet
+ OE_BLOOD = 1, // flash rouge
+ OE_FADEINw = 2, // blanc -> rien
+ OE_FADEOUTw = 3, // rien -> blanc
+ OE_FADEOUTb = 4, // rien -> bleu
+ OE_BLITZ = 5, // éclair
+};
+
+
+
+class CCamera
+{
+public:
+ CCamera(CInstanceManager* iMan);
+ ~CCamera();
+
+ BOOL EventProcess(const Event &event);
+
+ void Init(D3DVECTOR eye, D3DVECTOR 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(D3DVECTOR goal, float dist);
+ void StopVisit();
+
+ void RetCamera(D3DVECTOR &eye, D3DVECTOR &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, D3DVECTOR pos, float force);
+
+ void FlushOver();
+ void SetOverBaseColor(D3DCOLORVALUE color);
+ void StartOver(OverEffect effect, D3DVECTOR pos, float force);
+
+ void FixCamera();
+ void SetScriptEye(D3DVECTOR eye);
+ void SetScriptLookat(D3DVECTOR lookat);
+
+ void SetEffect(BOOL bEnable);
+ void SetCameraScroll(BOOL bScroll);
+ void SetCameraInvertX(BOOL bInvert);
+ void SetCameraInvertY(BOOL bInvert);
+
+ float RetMotorTurn();
+ D3DMouse RetMouseDef(FPOINT 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 D3DVECTOR &vEyePt, const D3DVECTOR &vLookatPt, float rTime);
+ BOOL IsCollision(D3DVECTOR &eye, D3DVECTOR lookat);
+ BOOL IsCollisionBack(D3DVECTOR &eye, D3DVECTOR lookat);
+ BOOL IsCollisionFix(D3DVECTOR &eye, D3DVECTOR lookat);
+
+ D3DVECTOR ExcludeTerrain(D3DVECTOR eye, D3DVECTOR lookat, float &angleH, float &angleV);
+ D3DVECTOR ExcludeObject(D3DVECTOR eye, D3DVECTOR lookat, float &angleH, float &angleV);
+
+ void SetViewParams(const D3DVECTOR &eye, const D3DVECTOR &lookat, const D3DVECTOR &up);
+ void EffectFrame(const Event &event);
+ void OverFrame(const Event &event);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CTerrain* m_terrain;
+ CWater* m_water;
+
+ CameraType m_type; // type de la caméra (CAMERA_*)
+ CameraSmooth m_smooth; // type de lissage
+ CObject* m_cameraObj; // objet lié à la caméra
+
+ float m_eyeDistance; // distance entre les yeux
+ float m_initDelay; // délai du centrage initial
+
+ D3DVECTOR m_actualEye; // oeil actuel
+ D3DVECTOR m_actualLookat; // visée actuelle
+ D3DVECTOR m_finalEye; // oeil final
+ D3DVECTOR m_finalLookat; // visée finale
+ D3DVECTOR m_normEye; // oeil normal
+ D3DVECTOR m_normLookat; // visée normale
+ float m_focus;
+
+ BOOL m_bRightDown;
+ FPOINT m_rightPosInit;
+ FPOINT m_rightPosCenter;
+ FPOINT m_rightPosMove;
+
+ D3DVECTOR m_eyePt; // CAMERA_FREE: oeil
+ float m_directionH; // CAMERA_FREE: direction horizontale
+ float m_directionV; // CAMERA_FREE: direction verticale
+ float m_heightEye; // CAMERA_FREE: hauteur au-dessus du sol
+ float m_heightLookat; // CAMERA_FREE: hauteur au-dessus du sol
+ float m_speed; // CAMERA_FREE: vitesse de déplacement
+
+ float m_backDist; // CAMERA_BACK: éloignement
+ float m_backMin; // CAMERA_BACK: éloignement minimal
+ float m_addDirectionH; // CAMERA_BACK: direction supplémentaire
+ float m_addDirectionV; // CAMERA_BACK: direction supplémentaire
+ BOOL m_bTransparency;
+
+ float m_fixDist; // CAMERA_FIX: éloignement
+ float m_fixDirectionH; // CAMERA_FIX: direction
+ float m_fixDirectionV; // CAMERA_FIX: direction
+
+ D3DVECTOR m_visitGoal; // CAMERA_VISIT: position visée
+ float m_visitDist; // CAMERA_VISIT: éloignement
+ float m_visitTime; // CAMERA_VISIT: temps relatif
+ CameraType m_visitType; // CAMERA_VISIT: type initial
+ float m_visitDirectionH; // CAMERA_VISIT: direction
+ float m_visitDirectionV; // CAMERA_VISIT: direction
+
+ float m_editHeight; // CAMERA_EDIT: hauteur
+
+ float m_remotePan;
+ float m_remoteZoom;
+
+ FPOINT 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;
+ D3DVECTOR m_effectPos;
+ float m_effectForce;
+ float m_effectProgress;
+ D3DVECTOR m_effectOffset;
+
+ OverEffect m_overType;
+ float m_overForce;
+ float m_overTime;
+ D3DCOLORVALUE m_overColorBase;
+ D3DCOLORVALUE m_overColor;
+ int m_overMode;
+ float m_overFadeIn;
+ float m_overFadeOut;
+
+ D3DVECTOR m_scriptEye;
+ D3DVECTOR m_scriptLookat;
+
+ BOOL m_bEffect; // secousses si explosion ?
+ BOOL m_bCameraScroll; // scroll dans les bords ?
+ BOOL m_bCameraInvertX; // inversion X dans les bords ?
+ BOOL m_bCameraInvertY; // inversion Y dans les bords ?
+};
+
+
+#endif //_CAMERA_H_
diff --git a/src/cbottoken.cpp b/src/cbottoken.cpp
new file mode 100644
index 0000000..db07edf
--- /dev/null
+++ b/src/cbottoken.cpp
@@ -0,0 +1,507 @@
+// cbottoken.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "global.h"
+#include "event.h"
+#include "object.h"
+#include "cbottoken.h"
+
+
+
+
+// Cherche le nom d'un objet.
+
+char* RetObjectName(ObjectType type)
+{
+ if ( type == OBJECT_PORTICO ) return "Portico";
+ if ( type == OBJECT_BASE ) return "SpaceShip";
+ if ( type == OBJECT_DERRICK ) return "Derrick";
+ if ( type == OBJECT_FACTORY ) return "BotFactory";
+ if ( type == OBJECT_STATION ) return "PowerStation";
+ if ( type == OBJECT_CONVERT ) return "Converter";
+ if ( type == OBJECT_REPAIR ) return "RepairCenter";
+ if ( type == OBJECT_DESTROYER ) return "Destroyer";
+ if ( type == OBJECT_TOWER ) return "DefenseTower";
+ if ( type == OBJECT_NEST ) return "AlienNest";
+ if ( type == OBJECT_RESEARCH ) return "ResearchCenter";
+ if ( type == OBJECT_RADAR ) return "RadarStation";
+ if ( type == OBJECT_INFO ) return "ExchangePost";
+ if ( type == OBJECT_ENERGY ) return "PowerPlant";
+ if ( type == OBJECT_LABO ) return "AutoLab";
+ if ( type == OBJECT_NUCLEAR ) return "NuclearPlant";
+ if ( type == OBJECT_PARA ) return "PowerCaptor";
+ if ( type == OBJECT_SAFE ) return "Vault";
+ if ( type == OBJECT_HUSTON ) return "Houston";
+ if ( type == OBJECT_TARGET1 ) return "Target1";
+ if ( type == OBJECT_TARGET2 ) return "Target2";
+ if ( type == OBJECT_START ) return "StartArea";
+ if ( type == OBJECT_END ) return "GoalArea";
+ if ( type == OBJECT_TEEN34 ) return "Stone";
+ if ( type == OBJECT_STONE ) return "TitaniumOre";
+ if ( type == OBJECT_URANIUM ) return "UraniumOre";
+ if ( type == OBJECT_METAL ) return "Titanium";
+ if ( type == OBJECT_POWER ) return "PowerCell";
+ if ( type == OBJECT_ATOMIC ) return "NuclearCell";
+ if ( type == OBJECT_BULLET ) return "OrgaMatter";
+ if ( type == OBJECT_BBOX ) return "BlackBox";
+ if ( type == OBJECT_KEYa ) return "KeyA";
+ if ( type == OBJECT_KEYb ) return "KeyB";
+ if ( type == OBJECT_KEYc ) return "KeyC";
+ if ( type == OBJECT_KEYd ) return "KeyD";
+ if ( type == OBJECT_TNT ) return "TNT";
+ if ( type == OBJECT_SCRAP1 ) return "Scrap";
+ if ( type == OBJECT_BOMB ) return "Mine";
+ if ( type == OBJECT_BARRIER1 ) return "Barrier";
+ if ( type == OBJECT_WAYPOINT ) return "WayPoint";
+ if ( type == OBJECT_FLAGb ) return "BlueFlag";
+ if ( type == OBJECT_FLAGr ) return "RedFlag";
+ if ( type == OBJECT_FLAGg ) return "GreenFlag";
+ if ( type == OBJECT_FLAGy ) return "YellowFlag";
+ if ( type == OBJECT_FLAGv ) return "VioletFlag";
+ if ( type == OBJECT_MARKPOWER ) return "PowerSpot";
+ if ( type == OBJECT_MARKSTONE ) return "TitaniumSpot";
+ if ( type == OBJECT_MARKURANIUM ) return "UraniumSpot";
+ if ( type == OBJECT_MARKKEYa ) return "KeyASpot";
+ if ( type == OBJECT_MARKKEYb ) return "KeyBSpot";
+ if ( type == OBJECT_MARKKEYc ) return "KeyCSpot";
+ if ( type == OBJECT_MARKKEYd ) return "KeyDSpot";
+ if ( type == OBJECT_MOBILEwt ) return "PracticeBot";
+ if ( type == OBJECT_MOBILEwa ) return "WheeledGrabber";
+ if ( type == OBJECT_MOBILEta ) return "TrackedGrabber";
+ if ( type == OBJECT_MOBILEfa ) return "WingedGrabber";
+ if ( type == OBJECT_MOBILEia ) return "LeggedGrabber";
+ if ( type == OBJECT_MOBILEwc ) return "WheeledShooter";
+ if ( type == OBJECT_MOBILEtc ) return "TrackedShooter";
+ if ( type == OBJECT_MOBILEfc ) return "WingedShooter";
+ if ( type == OBJECT_MOBILEic ) return "LeggedShooter";
+ if ( type == OBJECT_MOBILEwi ) return "WheeledOrgaShooter";
+ if ( type == OBJECT_MOBILEti ) return "TrackedOrgaShooter";
+ if ( type == OBJECT_MOBILEfi ) return "WingedOrgaShooter";
+ if ( type == OBJECT_MOBILEii ) return "LeggedOrgaShooter";
+ if ( type == OBJECT_MOBILEws ) return "WheeledSniffer";
+ if ( type == OBJECT_MOBILEts ) return "TrackedSniffer";
+ if ( type == OBJECT_MOBILEfs ) return "WingedSniffer";
+ if ( type == OBJECT_MOBILEis ) return "LeggedSniffer";
+ if ( type == OBJECT_MOBILErt ) return "Thumper";
+ if ( type == OBJECT_MOBILErc ) return "PhazerShooter";
+ if ( type == OBJECT_MOBILErr ) return "Recycler";
+ if ( type == OBJECT_MOBILErs ) return "Shielder";
+ if ( type == OBJECT_MOBILEsa ) return "Subber";
+ if ( type == OBJECT_MOBILEtg ) return "TargetBot";
+ if ( type == OBJECT_MOBILEdr ) return "Scribbler";
+ if ( type == OBJECT_HUMAN ) return "Me";
+ if ( type == OBJECT_TECH ) return "Tech";
+ if ( type == OBJECT_MOTHER ) return "AlienQueen";
+ if ( type == OBJECT_EGG ) return "AlienEgg";
+ if ( type == OBJECT_ANT ) return "AlienAnt";
+ if ( type == OBJECT_SPIDER ) return "AlienSpider";
+ if ( type == OBJECT_BEE ) return "AlienWasp";
+ if ( type == OBJECT_WORM ) return "AlienWorm";
+ if ( type == OBJECT_RUINmobilew1) return "Wreck";
+ return "";
+}
+
+// Cherche le nom secondaire d'un objet.
+// (à cause d'Otto qui pense que les allemands n'aiment pas le nucléaire)
+
+char* RetObjectAlias(ObjectType type)
+{
+ if ( type == OBJECT_NUCLEAR ) return "FuelCellPlant";
+ if ( type == OBJECT_URANIUM ) return "PlatinumOre";
+ if ( type == OBJECT_ATOMIC ) return "FuelCell";
+ if ( type == OBJECT_MARKURANIUM ) return "PlatinumSpot";
+ if ( type == OBJECT_ENERGY ) return "Disintegrator"; // pour CeeBot-K
+ return "";
+}
+
+
+// Retourne le fichier d'aide à utiliser pour l'objet.
+
+char* RetHelpFilename(ObjectType type)
+{
+ if ( type == OBJECT_BASE ) return "help\\object\\base.txt";
+ if ( type == OBJECT_DERRICK ) return "help\\object\\derrick.txt";
+ if ( type == OBJECT_FACTORY ) return "help\\object\\factory.txt";
+ if ( type == OBJECT_STATION ) return "help\\object\\station.txt";
+ if ( type == OBJECT_CONVERT ) return "help\\object\\convert.txt";
+ if ( type == OBJECT_REPAIR ) return "help\\object\\repair.txt";
+ if ( type == OBJECT_DESTROYER ) return "help\\object\\destroy.txt";
+ if ( type == OBJECT_TOWER ) return "help\\object\\tower.txt";
+ if ( type == OBJECT_NEST ) return "help\\object\\nest.txt";
+ if ( type == OBJECT_RESEARCH ) return "help\\object\\research.txt";
+ if ( type == OBJECT_RADAR ) return "help\\object\\radar.txt";
+ if ( type == OBJECT_INFO ) return "help\\object\\exchange.txt";
+ if ( type == OBJECT_ENERGY ) return "help\\object\\energy.txt";
+ if ( type == OBJECT_LABO ) return "help\\object\\labo.txt";
+ if ( type == OBJECT_NUCLEAR ) return "help\\object\\nuclear.txt";
+ if ( type == OBJECT_PARA ) return "help\\object\\captor.txt";
+ if ( type == OBJECT_SAFE ) return "help\\object\\safe.txt";
+ if ( type == OBJECT_HUSTON ) return "help\\object\\huston.txt";
+ if ( type == OBJECT_START ) return "help\\object\\start.txt";
+ if ( type == OBJECT_END ) return "help\\object\\goal.txt";
+ if ( type == OBJECT_STONE ) return "help\\object\\titanore.txt";
+ if ( type == OBJECT_URANIUM ) return "help\\object\\uranore.txt";
+ if ( type == OBJECT_METAL ) return "help\\object\\titan.txt";
+ if ( type == OBJECT_POWER ) return "help\\object\\power.txt";
+ if ( type == OBJECT_ATOMIC ) return "help\\object\\atomic.txt";
+ if ( type == OBJECT_BULLET ) return "help\\object\\bullet.txt";
+ if ( type == OBJECT_BBOX ) return "help\\object\\bbox.txt";
+ if ( type == OBJECT_KEYa ) return "help\\object\\key.txt";
+ if ( type == OBJECT_KEYb ) return "help\\object\\key.txt";
+ if ( type == OBJECT_KEYc ) return "help\\object\\key.txt";
+ if ( type == OBJECT_KEYd ) return "help\\object\\key.txt";
+ if ( type == OBJECT_TNT ) return "help\\object\\tnt.txt";
+ if ( type == OBJECT_SCRAP1 ) return "help\\object\\scrap.txt";
+ if ( type == OBJECT_BOMB ) return "help\\object\\mine.txt";
+ if ( type == OBJECT_BARRIER1 ) return "help\\object\\barrier.txt";
+ if ( type == OBJECT_WAYPOINT ) return "help\\object\\waypoint.txt";
+ if ( type == OBJECT_FLAGb ) return "help\\object\\flag.txt";
+ if ( type == OBJECT_FLAGr ) return "help\\object\\flag.txt";
+ if ( type == OBJECT_FLAGg ) return "help\\object\\flag.txt";
+ if ( type == OBJECT_FLAGy ) return "help\\object\\flag.txt";
+ if ( type == OBJECT_FLAGv ) return "help\\object\\flag.txt";
+ if ( type == OBJECT_MARKPOWER ) return "help\\object\\enerspot.txt";
+ if ( type == OBJECT_MARKSTONE ) return "help\\object\\stonspot.txt";
+ if ( type == OBJECT_MARKURANIUM ) return "help\\object\\uranspot.txt";
+ if ( type == OBJECT_MOBILEwa ) return "help\\object\\botgr.txt";
+ if ( type == OBJECT_MOBILEta ) return "help\\object\\botgc.txt";
+ if ( type == OBJECT_MOBILEfa ) return "help\\object\\botgj.txt";
+ if ( type == OBJECT_MOBILEia ) return "help\\object\\botgs.txt";
+ if ( type == OBJECT_MOBILEws ) return "help\\object\\botsr.txt";
+ if ( type == OBJECT_MOBILEts ) return "help\\object\\botsc.txt";
+ if ( type == OBJECT_MOBILEfs ) return "help\\object\\botsj.txt";
+ if ( type == OBJECT_MOBILEis ) return "help\\object\\botss.txt";
+ if ( type == OBJECT_MOBILEwi ) return "help\\object\\botor.txt";
+ if ( type == OBJECT_MOBILEti ) return "help\\object\\botoc.txt";
+ if ( type == OBJECT_MOBILEfi ) return "help\\object\\botoj.txt";
+ if ( type == OBJECT_MOBILEii ) return "help\\object\\botos.txt";
+ if ( type == OBJECT_MOBILEwc ) return "help\\object\\botfr.txt";
+ if ( type == OBJECT_MOBILEtc ) return "help\\object\\botfc.txt";
+ if ( type == OBJECT_MOBILEfc ) return "help\\object\\botfj.txt";
+ if ( type == OBJECT_MOBILEic ) return "help\\object\\botfs.txt";
+ if ( type == OBJECT_MOBILErt ) return "help\\object\\bottump.txt";
+ if ( type == OBJECT_MOBILErc ) return "help\\object\\botphaz.txt";
+ if ( type == OBJECT_MOBILErr ) return "help\\object\\botrecy.txt";
+ if ( type == OBJECT_MOBILErs ) return "help\\object\\botshld.txt";
+ if ( type == OBJECT_MOBILEsa ) return "help\\object\\botsub.txt";
+ if ( type == OBJECT_MOBILEwt ) return "help\\object\\bottr.txt";
+ if ( type == OBJECT_MOBILEtg ) return "help\\object\\bottarg.txt";
+ if ( type == OBJECT_MOBILEdr ) return "help\\object\\botdraw.txt";
+ if ( type == OBJECT_APOLLO2 ) return "help\\object\\lrv.txt";
+ if ( type == OBJECT_HUMAN ) return "help\\object\\human.txt";
+ if ( type == OBJECT_MOTHER ) return "help\\object\\mother.txt";
+ if ( type == OBJECT_EGG ) return "help\\object\\egg.txt";
+ if ( type == OBJECT_ANT ) return "help\\object\\ant.txt";
+ if ( type == OBJECT_SPIDER ) return "help\\object\\spider.txt";
+ if ( type == OBJECT_BEE ) return "help\\object\\wasp.txt";
+ if ( type == OBJECT_WORM ) return "help\\object\\worm.txt";
+ if ( type == OBJECT_RUINmobilew1) return "help\\object\\wreck.txt";
+ return "";
+}
+
+
+// Retourne le fichier d'aide à utiliser pour une instruction.
+
+char* RetHelpFilename(const char *token)
+{
+ if ( strcmp(token, "if" ) == 0 ) return "help\\cbot\\if.txt";
+ if ( strcmp(token, "else" ) == 0 ) return "help\\cbot\\if.txt";
+ if ( strcmp(token, "repeat" ) == 0 ) return "help\\cbot\\repeat.txt";
+ if ( strcmp(token, "for" ) == 0 ) return "help\\cbot\\for.txt";
+ if ( strcmp(token, "while" ) == 0 ) return "help\\cbot\\while.txt";
+ if ( strcmp(token, "do" ) == 0 ) return "help\\cbot\\do.txt";
+ if ( strcmp(token, "break" ) == 0 ) return "help\\cbot\\break.txt";
+ if ( strcmp(token, "continue" ) == 0 ) return "help\\cbot\\continue.txt";
+ if ( strcmp(token, "return" ) == 0 ) return "help\\cbot\\return.txt";
+ if ( strcmp(token, "sizeof" ) == 0 ) return "help\\cbot\\sizeof.txt";
+ if ( strcmp(token, "int" ) == 0 ) return "help\\cbot\\int.txt";
+ if ( strcmp(token, "float" ) == 0 ) return "help\\cbot\\float.txt";
+ if ( strcmp(token, "bool" ) == 0 ) return "help\\cbot\\bool.txt";
+ if ( strcmp(token, "string" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "point" ) == 0 ) return "help\\cbot\\point.txt";
+ if ( strcmp(token, "object" ) == 0 ) return "help\\cbot\\object.txt";
+ if ( strcmp(token, "file" ) == 0 ) return "help\\cbot\\file.txt";
+ if ( strcmp(token, "void" ) == 0 ) return "help\\cbot\\void.txt";
+ if ( strcmp(token, "null" ) == 0 ) return "help\\cbot\\null.txt";
+ if ( strcmp(token, "nan" ) == 0 ) return "help\\cbot\\nan.txt";
+ if ( strcmp(token, "true" ) == 0 ) return "help\\cbot\\true.txt";
+ if ( strcmp(token, "false" ) == 0 ) return "help\\cbot\\false.txt";
+ if ( strcmp(token, "sin" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "cos" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "tan" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "asin" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "acos" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "atan" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "sqrt" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "pow" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "rand" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "abs" ) == 0 ) return "help\\cbot\\expr.txt";
+ if ( strcmp(token, "retobject" ) == 0 ) return "help\\cbot\\retobj.txt";
+ if ( strcmp(token, "search" ) == 0 ) return "help\\cbot\\search.txt";
+ if ( strcmp(token, "radar" ) == 0 ) return "help\\cbot\\radar.txt";
+ if ( strcmp(token, "direction" ) == 0 ) return "help\\cbot\\direct.txt";
+ if ( strcmp(token, "distance" ) == 0 ) return "help\\cbot\\dist.txt";
+ if ( strcmp(token, "distance2d" ) == 0 ) return "help\\cbot\\dist2d.txt";
+ if ( strcmp(token, "space" ) == 0 ) return "help\\cbot\\space.txt";
+ if ( strcmp(token, "flatground" ) == 0 ) return "help\\cbot\\flatgrnd.txt";
+ if ( strcmp(token, "wait" ) == 0 ) return "help\\cbot\\wait.txt";
+ if ( strcmp(token, "move" ) == 0 ) return "help\\cbot\\move.txt";
+ if ( strcmp(token, "turn" ) == 0 ) return "help\\cbot\\turn.txt";
+ if ( strcmp(token, "goto" ) == 0 ) return "help\\cbot\\goto.txt";
+ if ( strcmp(token, "find" ) == 0 ) return "help\\cbot\\find.txt";
+ if ( strcmp(token, "grab" ) == 0 ) return "help\\cbot\\grab.txt";
+ if ( strcmp(token, "drop" ) == 0 ) return "help\\cbot\\drop.txt";
+ if ( strcmp(token, "sniff" ) == 0 ) return "help\\cbot\\sniff.txt";
+ if ( strcmp(token, "receive" ) == 0 ) return "help\\cbot\\receive.txt";
+ if ( strcmp(token, "send" ) == 0 ) return "help\\cbot\\send.txt";
+ if ( strcmp(token, "deleteinfo" ) == 0 ) return "help\\cbot\\delinfo.txt";
+ if ( strcmp(token, "testinfo" ) == 0 ) return "help\\cbot\\testinfo.txt";
+ if ( strcmp(token, "thump" ) == 0 ) return "help\\cbot\\thump.txt";
+ if ( strcmp(token, "recycle" ) == 0 ) return "help\\cbot\\recycle.txt";
+ if ( strcmp(token, "shield" ) == 0 ) return "help\\cbot\\shield.txt";
+ if ( strcmp(token, "fire" ) == 0 ) return "help\\cbot\\fire.txt";
+ if ( strcmp(token, "antfire" ) == 0 ) return "help\\cbot\\antfire.txt";
+ if ( strcmp(token, "aim" ) == 0 ) return "help\\cbot\\aim.txt";
+ if ( strcmp(token, "motor" ) == 0 ) return "help\\cbot\\motor.txt";
+ if ( strcmp(token, "jet" ) == 0 ) return "help\\cbot\\jet.txt";
+ if ( strcmp(token, "topo" ) == 0 ) return "help\\cbot\\topo.txt";
+ if ( strcmp(token, "message" ) == 0 ) return "help\\cbot\\message.txt";
+ if ( strcmp(token, "abstime" ) == 0 ) return "help\\cbot\\abstime.txt";
+ if ( strcmp(token, "BlackArrow" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "RedArrow" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "White" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Black" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Gray" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "LightGray" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Red" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Pink" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Purple" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Orange" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Yellow" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Beige" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Brown" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Skin" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Green" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "LightGreen" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "Blue" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "LightBlue" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "InFront" ) == 0 ) return "help\\cbot\\grab.txt";
+ if ( strcmp(token, "Behind" ) == 0 ) return "help\\cbot\\grab.txt";
+ if ( strcmp(token, "EnergyCell" ) == 0 ) return "help\\cbot\\grab.txt";
+ if ( strcmp(token, "DisplayError" ) == 0 ) return "help\\cbot\\message.txt";
+ if ( strcmp(token, "DisplayWarning") == 0 ) return "help\\cbot\\message.txt";
+ if ( strcmp(token, "DisplayInfo" ) == 0 ) return "help\\cbot\\message.txt";
+ if ( strcmp(token, "DisplayMessage") == 0 ) return "help\\cbot\\message.txt";
+ if ( strcmp(token, "strlen" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strleft" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strright" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strmid" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strval" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strfind" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strlower" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "strupper" ) == 0 ) return "help\\cbot\\string.txt";
+ if ( strcmp(token, "open" ) == 0 ) return "help\\cbot\\open.txt";
+ if ( strcmp(token, "close" ) == 0 ) return "help\\cbot\\close.txt";
+ if ( strcmp(token, "writeln" ) == 0 ) return "help\\cbot\\writeln.txt";
+ if ( strcmp(token, "readln " ) == 0 ) return "help\\cbot\\readln.txt";
+ if ( strcmp(token, "eof" ) == 0 ) return "help\\cbot\\eof.txt";
+ if ( strcmp(token, "deletefile" ) == 0 ) return "help\\cbot\\deletef.txt";
+ if ( strcmp(token, "openfile" ) == 0 ) return "help\\cbot\\openfile.txt";
+ if ( strcmp(token, "pendown" ) == 0 ) return "help\\cbot\\pendown.txt";
+ if ( strcmp(token, "penup" ) == 0 ) return "help\\cbot\\penup.txt";
+ if ( strcmp(token, "pencolor" ) == 0 ) return "help\\cbot\\pencolor.txt";
+ if ( strcmp(token, "penwidth" ) == 0 ) return "help\\cbot\\penwidth.txt";
+ if ( strcmp(token, "extern" ) == 0 ) return "help\\cbot\\extern.txt";
+ if ( strcmp(token, "class" ) == 0 ) return "help\\cbot\\class.txt";
+ if ( strcmp(token, "static" ) == 0 ) return "help\\cbot\\static.txt";
+ if ( strcmp(token, "public" ) == 0 ) return "help\\cbot\\public.txt";
+ if ( strcmp(token, "private" ) == 0 ) return "help\\cbot\\private.txt";
+ if ( strcmp(token, "synchronized" ) == 0 ) return "help\\cbot\\synchro.txt";
+ if ( strcmp(token, "new" ) == 0 ) return "help\\cbot\\new.txt";
+ if ( strcmp(token, "this" ) == 0 ) return "help\\cbot\\this.txt";
+ return "";
+}
+
+
+// Teste si un mot clé est un type de variable.
+
+BOOL IsType(const char *token)
+{
+ if ( strcmp(token, "void" ) == 0 ) return TRUE;
+ if ( strcmp(token, "int" ) == 0 ) return TRUE;
+ if ( strcmp(token, "float" ) == 0 ) return TRUE;
+ if ( strcmp(token, "bool" ) == 0 ) return TRUE;
+ if ( strcmp(token, "string" ) == 0 ) return TRUE;
+ if ( strcmp(token, "point" ) == 0 ) return TRUE;
+ if ( strcmp(token, "object" ) == 0 ) return TRUE;
+ if ( strcmp(token, "file" ) == 0 ) return TRUE;
+ if ( strcmp(token, "this" ) == 0 ) return TRUE;
+ return FALSE;
+}
+
+// Teste si un mot clé est une fonction.
+
+BOOL IsFunction(const char *token)
+{
+ if ( strcmp(token, "sin" ) == 0 ) return TRUE;
+ if ( strcmp(token, "cos" ) == 0 ) return TRUE;
+ if ( strcmp(token, "tan" ) == 0 ) return TRUE;
+ if ( strcmp(token, "asin" ) == 0 ) return TRUE;
+ if ( strcmp(token, "acos" ) == 0 ) return TRUE;
+ if ( strcmp(token, "atan" ) == 0 ) return TRUE;
+ if ( strcmp(token, "sqrt" ) == 0 ) return TRUE;
+ if ( strcmp(token, "pow" ) == 0 ) return TRUE;
+ if ( strcmp(token, "rand" ) == 0 ) return TRUE;
+ if ( strcmp(token, "abs" ) == 0 ) return TRUE;
+ if ( strcmp(token, "retobject" ) == 0 ) return TRUE;
+ if ( strcmp(token, "search" ) == 0 ) return TRUE;
+ if ( strcmp(token, "radar" ) == 0 ) return TRUE;
+ if ( strcmp(token, "detect" ) == 0 ) return TRUE;
+ if ( strcmp(token, "direction" ) == 0 ) return TRUE;
+ if ( strcmp(token, "distance" ) == 0 ) return TRUE;
+ if ( strcmp(token, "distance2d" ) == 0 ) return TRUE;
+ if ( strcmp(token, "space" ) == 0 ) return TRUE;
+ if ( strcmp(token, "flatground" ) == 0 ) return TRUE;
+ if ( strcmp(token, "wait" ) == 0 ) return TRUE;
+ if ( strcmp(token, "move" ) == 0 ) return TRUE;
+ if ( strcmp(token, "turn" ) == 0 ) return TRUE;
+ if ( strcmp(token, "goto" ) == 0 ) return TRUE;
+ if ( strcmp(token, "find" ) == 0 ) return TRUE;
+ if ( strcmp(token, "grab" ) == 0 ) return TRUE;
+ if ( strcmp(token, "drop" ) == 0 ) return TRUE;
+ if ( strcmp(token, "sniff" ) == 0 ) return TRUE;
+ if ( strcmp(token, "receive" ) == 0 ) return TRUE;
+ if ( strcmp(token, "send" ) == 0 ) return TRUE;
+ if ( strcmp(token, "deleteinfo" ) == 0 ) return TRUE;
+ if ( strcmp(token, "testinfo" ) == 0 ) return TRUE;
+ if ( strcmp(token, "thump" ) == 0 ) return TRUE;
+ if ( strcmp(token, "recycle" ) == 0 ) return TRUE;
+ if ( strcmp(token, "shield" ) == 0 ) return TRUE;
+ if ( strcmp(token, "fire" ) == 0 ) return TRUE;
+ if ( strcmp(token, "antfire" ) == 0 ) return TRUE;
+ if ( strcmp(token, "aim" ) == 0 ) return TRUE;
+ if ( strcmp(token, "motor" ) == 0 ) return TRUE;
+ if ( strcmp(token, "jet" ) == 0 ) return TRUE;
+ if ( strcmp(token, "topo" ) == 0 ) return TRUE;
+ if ( strcmp(token, "message" ) == 0 ) return TRUE;
+ if ( strcmp(token, "abstime" ) == 0 ) return TRUE;
+ if ( strcmp(token, "ismovie" ) == 0 ) return TRUE;
+ if ( strcmp(token, "errmode" ) == 0 ) return TRUE;
+ if ( strcmp(token, "ipf" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strlen" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strleft" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strright" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strmid" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strval" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strfind" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strlower" ) == 0 ) return TRUE;
+ if ( strcmp(token, "strupper" ) == 0 ) return TRUE;
+ if ( strcmp(token, "open" ) == 0 ) return TRUE;
+ if ( strcmp(token, "close" ) == 0 ) return TRUE;
+ if ( strcmp(token, "writeln" ) == 0 ) return TRUE;
+ if ( strcmp(token, "readln" ) == 0 ) return TRUE;
+ if ( strcmp(token, "eof" ) == 0 ) return TRUE;
+ if ( strcmp(token, "deletefile" ) == 0 ) return TRUE;
+ if ( strcmp(token, "openfile" ) == 0 ) return TRUE;
+ if ( strcmp(token, "pendown" ) == 0 ) return TRUE;
+ if ( strcmp(token, "penup" ) == 0 ) return TRUE;
+ if ( strcmp(token, "pencolor" ) == 0 ) return TRUE;
+ if ( strcmp(token, "penwidth" ) == 0 ) return TRUE;
+ if ( strcmp(token, "sizeof" ) == 0 ) return TRUE;
+ return FALSE;
+}
+
+
+// Retourne l'aide compacte pour une instruction.
+
+char* RetHelpText(const char *token)
+{
+ if ( strcmp(token, "if" ) == 0 ) return "if ( condition ) { bloc }";
+ if ( strcmp(token, "else" ) == 0 ) return "else { bloc }";
+ if ( strcmp(token, "repeat" ) == 0 ) return "repeat ( number )";
+ if ( strcmp(token, "for" ) == 0 ) return "for ( before ; condition ; end )";
+ if ( strcmp(token, "while" ) == 0 ) return "while ( condition ) { bloc }";
+ if ( strcmp(token, "do" ) == 0 ) return "do { bloc } while ( condition );";
+ if ( strcmp(token, "break" ) == 0 ) return "break;";
+ if ( strcmp(token, "continue" ) == 0 ) return "continue;";
+ if ( strcmp(token, "return" ) == 0 ) return "return;";
+ if ( strcmp(token, "sizeof" ) == 0 ) return "sizeof( array );";
+ if ( strcmp(token, "int" ) == 0 ) return "int";
+ if ( strcmp(token, "sin" ) == 0 ) return "sin ( angle );";
+ if ( strcmp(token, "cos" ) == 0 ) return "cos ( angle );";
+ if ( strcmp(token, "tan" ) == 0 ) return "tan ( angle );";
+ if ( strcmp(token, "asin" ) == 0 ) return "asin ( value );";
+ if ( strcmp(token, "acos" ) == 0 ) return "acos ( value );";
+ if ( strcmp(token, "atan" ) == 0 ) return "atan ( value );";
+ if ( strcmp(token, "sqrt" ) == 0 ) return "sqrt ( value );";
+ if ( strcmp(token, "pow" ) == 0 ) return "pow ( x, y );";
+ if ( strcmp(token, "rand" ) == 0 ) return "rand ( );";
+ if ( strcmp(token, "abs" ) == 0 ) return "abs ( value );";
+ if ( strcmp(token, "retobject" ) == 0 ) return "retobjet ( );";
+ if ( strcmp(token, "search" ) == 0 ) return "search ( );";
+ if ( strcmp(token, "radar" ) == 0 ) return "radar ( cat, angle, focus, min, max, sens );";
+ if ( strcmp(token, "detect" ) == 0 ) return "detect ( cat );";
+ if ( strcmp(token, "direction" ) == 0 ) return "direction ( position );";
+ if ( strcmp(token, "distance2d") == 0 ) return "distance2d ( p1, p2 );";
+ if ( strcmp(token, "distance" ) == 0 ) return "distance ( p1, p2 );";
+ if ( strcmp(token, "space" ) == 0 ) return "space ( center, rmin, rmax, dist );";
+ if ( strcmp(token, "flatground") == 0 ) return "flatground ( center, rmax );";
+ if ( strcmp(token, "wait" ) == 0 ) return "wait ( time );";
+ if ( strcmp(token, "move" ) == 0 ) return "move ( distance );";
+ if ( strcmp(token, "turn" ) == 0 ) return "turn ( angle );";
+ if ( strcmp(token, "goto" ) == 0 ) return "goto ( position, altitude );";
+ if ( strcmp(token, "find" ) == 0 ) return "find ( cat );";
+ if ( strcmp(token, "grab" ) == 0 ) return "grab ( order );";
+ if ( strcmp(token, "drop" ) == 0 ) return "drop ( order );";
+ if ( strcmp(token, "sniff" ) == 0 ) return "sniff ( );";
+ if ( strcmp(token, "receive" ) == 0 ) return "receive ( name, power );";
+ if ( strcmp(token, "send" ) == 0 ) return "send ( name, value, power );";
+ if ( strcmp(token, "deleteinfo") == 0 ) return "deleteinfo ( name, power );";
+ if ( strcmp(token, "testinfo" ) == 0 ) return "testinfo ( name, power );";
+ if ( strcmp(token, "thump" ) == 0 ) return "thump ( );";
+ if ( strcmp(token, "recycle" ) == 0 ) return "recycle ( );";
+ if ( strcmp(token, "shield" ) == 0 ) return "shield ( oper, radius );";
+ if ( strcmp(token, "fire" ) == 0 ) return "fire ( time );";
+ if ( strcmp(token, "antfire" ) == 0 ) return "antfire ( );";
+ if ( strcmp(token, "aim" ) == 0 ) return "aim ( angle );";
+ if ( strcmp(token, "motor" ) == 0 ) return "motor ( left, right );";
+ if ( strcmp(token, "jet" ) == 0 ) return "jet ( power );";
+ if ( strcmp(token, "topo" ) == 0 ) return "topo ( position );";
+ if ( strcmp(token, "message" ) == 0 ) return "message ( string, type );";
+ if ( strcmp(token, "abstime" ) == 0 ) return "abstime ( );";
+ if ( strcmp(token, "ismovie" ) == 0 ) return "ismovie ( );";
+ if ( strcmp(token, "errmode" ) == 0 ) return "errmode ( mdoe );";
+ if ( strcmp(token, "ipf" ) == 0 ) return "ipf ( number );";
+ if ( strcmp(token, "strlen" ) == 0 ) return "strlen ( string );";
+ if ( strcmp(token, "strleft" ) == 0 ) return "strleft ( string, len );";
+ if ( strcmp(token, "strright" ) == 0 ) return "strright ( string, len );";
+ if ( strcmp(token, "strmid" ) == 0 ) return "strmid ( string, pos, len );";
+ if ( strcmp(token, "strval" ) == 0 ) return "strval ( string );";
+ if ( strcmp(token, "strfind" ) == 0 ) return "strfind ( string, substring );";
+ if ( strcmp(token, "strlower" ) == 0 ) return "strlower ( string );";
+ if ( strcmp(token, "strupper" ) == 0 ) return "strupper ( string );";
+ if ( strcmp(token, "open" ) == 0 ) return "open ( filename, mode );";
+ if ( strcmp(token, "close" ) == 0 ) return "close ( );";
+ if ( strcmp(token, "writeln" ) == 0 ) return "writeln ( string );";
+ if ( strcmp(token, "readln" ) == 0 ) return "readln ( );";
+ if ( strcmp(token, "eof" ) == 0 ) return "eof ( );";
+ if ( strcmp(token, "deletefile") == 0 ) return "deletefile ( filename );";
+ if ( strcmp(token, "openfile" ) == 0 ) return "openfile ( filename, mode );";
+ if ( strcmp(token, "pendown" ) == 0 ) return "pendown ( color, width );";
+ if ( strcmp(token, "penup" ) == 0 ) return "penup ( );";
+ if ( strcmp(token, "pencolor" ) == 0 ) return "pencolor ( color );";
+ if ( strcmp(token, "penwidth" ) == 0 ) return "penwidth ( width );";
+ return "";
+}
+
+
diff --git a/src/cbottoken.h b/src/cbottoken.h
new file mode 100644
index 0000000..34c391c
--- /dev/null
+++ b/src/cbottoken.h
@@ -0,0 +1,24 @@
+// cbottoken.h
+
+#ifndef _CBOTTOKEN_H_
+#define _CBOTTOKEN_H_
+
+
+
+enum ObjectType;
+
+
+
+// Procédures.
+
+extern char* RetObjectName(ObjectType type);
+extern char* RetObjectAlias(ObjectType type);
+extern char* RetHelpFilename(ObjectType type);
+extern char* RetHelpFilename(const char *token);
+extern BOOL IsType(const char *token);
+extern BOOL IsFunction(const char *token);
+extern char* RetHelpText(const char *token);
+
+
+
+#endif //_CBOTTOKEN_H_
diff --git a/src/ceebot.ini b/src/ceebot.ini
new file mode 100644
index 0000000..0de7a32
--- /dev/null
+++ b/src/ceebot.ini
@@ -0,0 +1,66 @@
+[Directory]
+scene=scene
+savegame=savegame
+public=program
+user=user
+files=files
+[Setup]
+TotoMode=1
+Tooltips=1
+InterfaceGlint=1
+NiceMouse=0
+Movies=1
+NiceReset=1
+HimselfDamage=1
+CameraScroll=0
+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=4
+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
+DeleteGamer=1
+Soluce4=1
+[Engine]
+AlphaMode=1
+StateColor=-1
+BlackSrcBlend=0
+BlackDestBlend=0
+WhiteSrcBlend=0
+WhiteDestBlend=0
+DiffuseSrcBlend=0
+DiffuseDestBlend=0
+AlphaSrcBlend=0
+AlphaDestBlend=0
+[Gamer]
+LastName=Linda
+[Edit]
+FontSize=9.00
+WindowPos.x=0.09
+WindowPos.y=0.08
+WindowDim.x=0.69
+WindowDim.y=0.84
+IOPos.x=0.36
+IOPos.y=0.15
+IODim.x=0.50
+IODim.y=0.55
+[Device]
+Name=Direct3D HAL
+Mode=1600 x 1200 x 32
+FullScreen=0
diff --git a/src/check.cpp b/src/check.cpp
new file mode 100644
index 0000000..4c8637b
--- /dev/null
+++ b/src/check.cpp
@@ -0,0 +1,156 @@
+// check.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "text.h"
+#include "check.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CCheck::CCheck(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+}
+
+// Destructeur de l'objet.
+
+CCheck::~CCheck()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CCheck::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ char name[100];
+ char* p;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ GetResource(RES_EVENT, eventMsg, name);
+ p = strchr(name, '\\');
+ if ( p != 0 ) *p = 0;
+ SetName(name);
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CCheck::EventProcess(const Event &event)
+{
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CCheck::Draw()
+{
+ FPOINT iDim, pos;
+ float zoomExt, zoomInt;
+ int icon;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ iDim = m_dim;
+ m_dim.x = m_dim.y*0.75f; // carré
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ zoomExt = 1.00f;
+ zoomInt = 0.95f;
+
+ icon = 2;
+ if ( m_state & STATE_DEFAULT )
+ {
+ DrawPart(23, 1.3f, 0.0f);
+
+ zoomExt *= 1.15f;
+ zoomInt *= 1.15f;
+ }
+ if ( m_state & STATE_HILIGHT )
+ {
+ icon = 1;
+ }
+ if ( m_state & STATE_PRESS )
+ {
+ icon = 3;
+ zoomInt *= 0.9f;
+ }
+ if ( (m_state & STATE_ENABLE) == 0 )
+ {
+ icon = 7;
+ }
+ if ( m_state & STATE_DEAD )
+ {
+ icon = 17;
+ }
+ DrawPart(icon, zoomExt, 0.0f); // dessine le bouton
+
+ if ( (m_state & STATE_DEAD) == 0 )
+ {
+ m_engine->SetState(D3DSTATETTw);
+
+ if ( m_state & STATE_CHECK )
+ {
+ icon = 16; // vu
+ DrawPart(icon, zoomInt, 0.0f); // dessine l'icône
+ }
+ }
+
+ m_dim = iDim;
+
+ if ( m_state & STATE_DEAD ) return;
+
+ // Dessine le nom.
+ pos.x = m_pos.x+m_dim.y/0.9f;
+ pos.y = m_pos.y+m_dim.y*0.50f;
+ pos.y -= m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2.0f;
+ m_engine->RetText()->DrawText(m_name, pos, m_dim.x, 1, m_fontSize, m_fontStretch, m_fontType, 0);
+}
+
+
diff --git a/src/check.h b/src/check.h
new file mode 100644
index 0000000..35aa543
--- /dev/null
+++ b/src/check.h
@@ -0,0 +1,32 @@
+// check.h
+
+#ifndef _CHECK_H_
+#define _CHECK_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CCheck : public CControl
+{
+public:
+ CCheck(CInstanceManager* iMan);
+ ~CCheck();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+protected:
+
+protected:
+};
+
+
+#endif //_CHECK_H_
diff --git a/src/cloud.cpp b/src/cloud.cpp
new file mode 100644
index 0000000..ee41c48
--- /dev/null
+++ b/src/cloud.cpp
@@ -0,0 +1,317 @@
+// cloud.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "terrain.h"
+#include "object.h"
+#include "cloud.h"
+
+
+
+#define DIMEXPAND 4 // extension des dimensions
+
+
+
+// Constructeur des nuages.
+
+CCloud::CCloud(CInstanceManager* iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_CLOUD, this);
+
+ m_engine = engine;
+ m_terrain = 0;
+
+ m_level = 0.0f;
+ m_wind = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_subdiv = 8;
+ m_filename[0] = 0;
+ m_bEnable = TRUE;
+}
+
+// Destructeur des nuages.
+
+CCloud::~CCloud()
+{
+}
+
+
+BOOL CCloud::EventProcess(const Event &event)
+{
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ return TRUE;
+}
+
+// Fait évoluer les nuages.
+
+BOOL CCloud::EventFrame(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+
+ m_time += event.rTime;
+
+ if ( m_level == 0.0f ) return TRUE;
+
+ if ( m_time-m_lastTest < 0.2f ) return TRUE;
+ m_lastTest = m_time;
+
+ return TRUE;
+}
+
+
+// Ajuste la position et la normale, pour imiter des nuages
+// en mouvement.
+
+void CCloud::AdjustLevel(D3DVECTOR &pos, D3DVECTOR &eye, float deep,
+ FPOINT &uv1, FPOINT &uv2)
+{
+ float dist, factor;
+
+ uv1.x = (pos.x+20000.0f)/1280.0f;
+ uv1.y = (pos.z+20000.0f)/1280.0f;
+ uv1.x -= m_time*(m_wind.x/100.0f);
+ uv1.y -= m_time*(m_wind.z/100.0f);
+
+ uv2.x = 0.0f;
+ uv2.y = 0.0f;
+
+ dist = Length2d(pos, eye);
+ factor = powf(dist/deep, 2.0f);
+ pos.y -= m_level*factor*10.0f;
+}
+
+inline DWORD F2DW( FLOAT f )
+{
+ return *((DWORD*)&f);
+}
+
+// Dessine les nuages.
+
+void CCloud::Draw()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2* vertex;
+ D3DMATRIX* matView;
+ D3DMATERIAL7 material;
+ D3DMATRIX matrix;
+ D3DVECTOR n, pos, p, eye;
+ FPOINT uv1, uv2;
+ float iDeep, deep, size, fogStart, fogEnd;
+ int i, j, u;
+
+ if ( !m_bEnable ) return;
+ if ( m_level == 0.0f ) return;
+ if ( m_lineUsed == 0 ) return;
+
+ vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2);
+
+ iDeep = m_engine->RetDeepView();
+ deep = (m_brick*m_size)/2.0f;
+ m_engine->SetDeepView(deep);
+ m_engine->SetFocus(m_engine->RetFocus());
+ m_engine->UpdateMatProj(); // augmente la profondeur de vue
+
+//? fogStart = deep*0.10f;
+//? fogEnd = deep*0.16f;
+ fogStart = deep*0.15f;
+ fogEnd = deep*0.24f;
+
+ device = m_engine->RetD3DDevice();
+ device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0x00000000);
+ device->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ device->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+//? device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ device->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ device->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(fogStart));
+ device->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(fogEnd));
+
+ matView = m_engine->RetMatView();
+ device->SetTransform(D3DTRANSFORMSTATE_VIEW, matView);
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse = m_diffuse;
+ material.ambient = m_ambient;
+ m_engine->SetMaterial(material);
+
+ m_engine->SetTexture(m_filename, 0);
+ m_engine->SetTexture(m_filename, 1);
+
+//? m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP);
+ m_engine->SetState(D3DSTATETTb|D3DSTATEFOG|D3DSTATEWRAP);
+//? m_engine->SetState(D3DSTATEWRAP);
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ size = m_size/2.0f;
+ eye = m_engine->RetEyePt();
+ n = D3DVECTOR(0.0f, -1.0f, 0.0f);
+
+ // Dessine toutes les lignes.
+ for ( i=0 ; i<m_lineUsed ; i++ )
+ {
+ pos.y = m_level;
+ pos.z = m_line[i].pz;
+ pos.x = m_line[i].px1;
+
+ u = 0;
+ p.x = pos.x-size;
+ p.z = pos.z+size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x-size;
+ p.z = pos.z-size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ for ( j=0 ; j<m_line[i].len ; j++ )
+ {
+ p.x = pos.x+size;
+ p.z = pos.z+size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x+size;
+ p.z = pos.z-size;
+ p.y = pos.y;
+ AdjustLevel(p, eye, deep, uv1, uv2);
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ pos.x += size*2.0f;
+ }
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL);
+ m_engine->AddStatisticTriangle(u-2);
+ }
+
+ m_engine->SetDeepView(iDeep);
+ m_engine->SetFocus(m_engine->RetFocus());
+ m_engine->UpdateMatProj(); // remet profondeur de vue initiale
+
+ free(vertex);
+}
+
+
+// Met à jour les positions par-rapport au terrain.
+
+BOOL CCloud::CreateLine(int x, int y, int len)
+{
+ float offset;
+
+ m_line[m_lineUsed].x = x;
+ m_line[m_lineUsed].y = y;
+ m_line[m_lineUsed].len = len;
+
+ offset = m_brick*m_size/2.0f - m_size/2.0f;
+
+ m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset;
+ m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset;
+ m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset;
+
+ m_lineUsed ++;
+
+ return ( m_lineUsed < MAXCLOUDLINE );
+}
+
+// Crée toutes les étendues de nuages.
+
+BOOL CCloud::Create(const char *filename,
+ D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient,
+ float level)
+{
+ int y;
+
+ m_diffuse = diffuse;
+ m_ambient = ambient;
+ m_level = level;
+ m_time = 0.0f;
+ m_lastTest = 0.0f;
+ strcpy(m_filename, filename);
+
+ if ( m_filename[0] != 0 )
+ {
+ m_engine->LoadTexture(m_filename, 0);
+ m_engine->LoadTexture(m_filename, 1);
+ }
+
+ if ( m_terrain == 0 )
+ {
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ }
+
+ m_wind = m_terrain->RetWind();
+
+ m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic()*DIMEXPAND;
+ m_size = m_terrain->RetSize();
+
+ m_brick /= m_subdiv*DIMEXPAND;
+ m_size *= m_subdiv*DIMEXPAND;
+
+ if ( m_level == 0.0f ) return TRUE;
+
+ m_lineUsed = 0;
+ for ( y=0 ; y<m_brick ; y++ )
+ {
+ CreateLine(0, y, m_brick);
+ }
+ return TRUE;
+}
+
+// Supprime tous les nuages.
+
+void CCloud::Flush()
+{
+ m_level = 0.0f;
+}
+
+
+// Modifie le niveau des nuages.
+
+BOOL CCloud::SetLevel(float level)
+{
+ m_level = level;
+
+ return Create(m_filename, m_diffuse, m_ambient,
+ m_level);
+}
+
+// Retourne le niveau actuel des nuages.
+
+float CCloud::RetLevel()
+{
+ return m_level;
+}
+
+
+// Gestion de l'activation des nuages.
+
+void CCloud::SetEnable(BOOL bEnable)
+{
+ m_bEnable = bEnable;
+}
+
+BOOL CCloud::RetEnable()
+{
+ return m_bEnable;
+}
+
diff --git a/src/cloud.h b/src/cloud.h
new file mode 100644
index 0000000..049b17d
--- /dev/null
+++ b/src/cloud.h
@@ -0,0 +1,71 @@
+// cloud.h
+
+#ifndef _CLOUD_H_
+#define _CLOUD_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CTerrain;
+
+
+
+#define MAXCLOUDLINE 100
+
+typedef struct
+{
+ short x, y; // début
+ short len; // longueur en x
+ float px1, px2, pz;
+}
+CloudLine;
+
+
+class CCloud
+{
+public:
+ CCloud(CInstanceManager* iMan, CD3DEngine* engine);
+ ~CCloud();
+
+ BOOL EventProcess(const Event &event);
+ void Flush();
+ BOOL Create(const char *filename, D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, float level);
+ void Draw();
+
+ BOOL SetLevel(float level);
+ float RetLevel();
+
+ void SetEnable(BOOL bEnable);
+ BOOL RetEnable();
+
+protected:
+ BOOL EventFrame(const Event &event);
+ void AdjustLevel(D3DVECTOR &pos, D3DVECTOR &eye, float deep, FPOINT &uv1, FPOINT &uv2);
+ BOOL CreateLine(int x, int y, int len);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CTerrain* m_terrain;
+
+ char m_filename[100];
+ float m_level; // niveau global
+ FPOINT m_speed; // vitesse d'avance (vent)
+ D3DCOLORVALUE m_diffuse; // couleur diffuse
+ D3DCOLORVALUE m_ambient; // couleur ambiante
+ float m_time;
+ float m_lastTest;
+ int m_subdiv;
+
+ D3DVECTOR m_wind; // vitesse du vent
+ int m_brick; // nb de briques*mosaïque
+ float m_size; // taille d'un élément dans une brique
+
+ int m_lineUsed;
+ CloudLine m_line[MAXCLOUDLINE];
+
+ BOOL m_bEnable;
+};
+
+
+#endif //_CLOUD_H_
diff --git a/src/cmdtoken.cpp b/src/cmdtoken.cpp
new file mode 100644
index 0000000..fcd8e37
--- /dev/null
+++ b/src/cmdtoken.cpp
@@ -0,0 +1,964 @@
+// cmdtoken.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "global.h"
+#include "event.h"
+#include "water.h"
+#include "pyro.h"
+#include "camera.h"
+#include "object.h"
+#include "cmdtoken.h"
+
+
+
+
+
+// Saute les espaces.
+
+char* SkipSpace(char *line)
+{
+ while ( *line == ' ' )
+ {
+ line ++;
+ }
+ return line;
+}
+
+// Vérifie si une ligne contient une commande.
+
+BOOL Cmd(char *line, char *token)
+{
+ char* p;
+
+ line = SkipSpace(line);
+ p = strstr(line, token);
+ return ( p == line ); // commande au début ?
+}
+
+// Cherche un opérateur.
+
+char* SearchOp(char *line, char *op)
+{
+ char opeq[50];
+ char* p;
+
+ strcpy(opeq, " ");
+ strcat(opeq, op);
+ strcat(opeq, "=");
+
+ p = strstr(line, opeq);
+ if ( p == 0 ) // pas trouvé ?
+ {
+ return line+strlen(line); // pointe le zéro terminateur
+ }
+ return p+strlen(opeq); // pointe après le "="
+}
+
+// Cherche le nième argument.
+
+char* SearchArg(char *line, int rank)
+{
+ int i;
+ char c;
+
+ for ( i=0 ; i<rank ; i++ )
+ {
+ while ( TRUE )
+ {
+ c = *line++;
+ if ( c == ';' ) break;
+ if ( c == '=' ||
+ c == 0 ) return line+strlen(line);
+ }
+ }
+
+ line = SkipSpace(line);
+ return line;
+}
+
+// Lit un nombre entier, éventuellement hexadécimal.
+
+int GetInt(char *line, int rank, int def)
+{
+ char* p;
+ int n = 0;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return def;
+
+ if ( p[0] == '0' &&
+ p[1] == 'x' ) // commence par "0x" (hexa) ?
+ {
+ p += 2;
+ while ( TRUE )
+ {
+ if ( *p >= '0' && *p <= '9' )
+ {
+ n *= 16;
+ n += (*p++)-'0';
+ continue;
+ }
+ if ( *p >= 'a' && *p <= 'f' )
+ {
+ n *= 16;
+ n += (*p++)-'a'+10;
+ continue;
+ }
+ break;
+ }
+ }
+ else // nombre entier ?
+ {
+ sscanf(p, "%d", &n);
+ }
+ return n;
+}
+
+// Lit un nombre réel.
+
+float GetFloat(char *line, int rank, float def)
+{
+ char* p;
+ float n = 0.0f;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return def;
+
+ sscanf(p, "%f", &n);
+ return n;
+}
+
+// Lit une chaîne.
+
+void GetString(char *line, int rank, char *buffer)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ *buffer = 0;
+ if ( *p++ != '"' ) return;
+
+ while ( p[0] != 0 )
+ {
+ if ( p[0] == '"' &&
+ p[1] == '"' )
+ {
+ *buffer++ = *p++;
+ p++;
+ continue;
+ }
+ if ( p[0] == '"' ) break;
+
+ *buffer++ = *p++;
+ }
+ *buffer = 0;
+}
+
+// Retourne le type d'un objet.
+
+ObjectType GetTypeObject(char *line, int rank, ObjectType def)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return def;
+
+ if ( Cmd(p, "All" ) ) return OBJECT_NULL;
+ if ( Cmd(p, "Portico" ) ) return OBJECT_PORTICO;
+ if ( Cmd(p, "SpaceShip" ) ) return OBJECT_BASE;
+ if ( Cmd(p, "PracticeBot" ) ) return OBJECT_MOBILEwt;
+ if ( Cmd(p, "WingedGrabber" ) ) return OBJECT_MOBILEfa;
+ if ( Cmd(p, "TrackedGrabber" ) ) return OBJECT_MOBILEta;
+ if ( Cmd(p, "WheeledGrabber" ) ) return OBJECT_MOBILEwa;
+ if ( Cmd(p, "LeggedGrabber" ) ) return OBJECT_MOBILEia;
+ if ( Cmd(p, "WingedShooter" ) ) return OBJECT_MOBILEfc;
+ if ( Cmd(p, "TrackedShooter" ) ) return OBJECT_MOBILEtc;
+ if ( Cmd(p, "WheeledShooter" ) ) return OBJECT_MOBILEwc;
+ if ( Cmd(p, "LeggedShooter" ) ) return OBJECT_MOBILEic;
+ if ( Cmd(p, "WingedOrgaShooter" ) ) return OBJECT_MOBILEfi;
+ if ( Cmd(p, "TrackedOrgaShooter") ) return OBJECT_MOBILEti;
+ if ( Cmd(p, "WheeledOrgaShooter") ) return OBJECT_MOBILEwi;
+ if ( Cmd(p, "LeggedOrgaShooter" ) ) return OBJECT_MOBILEii;
+ if ( Cmd(p, "WingedSniffer" ) ) return OBJECT_MOBILEfs;
+ if ( Cmd(p, "TrackedSniffer" ) ) return OBJECT_MOBILEts;
+ if ( Cmd(p, "WheeledSniffer" ) ) return OBJECT_MOBILEws;
+ if ( Cmd(p, "LeggedSniffer" ) ) return OBJECT_MOBILEis;
+ if ( Cmd(p, "Thumper" ) ) return OBJECT_MOBILErt;
+ if ( Cmd(p, "PhazerShooter" ) ) return OBJECT_MOBILErc;
+ if ( Cmd(p, "Recycler" ) ) return OBJECT_MOBILErr;
+ if ( Cmd(p, "Shielder" ) ) return OBJECT_MOBILErs;
+ if ( Cmd(p, "Subber" ) ) return OBJECT_MOBILEsa;
+ if ( Cmd(p, "TargetBot" ) ) return OBJECT_MOBILEtg;
+ if ( Cmd(p, "Scribbler" ) ) return OBJECT_MOBILEdr;
+ if ( Cmd(p, "PowerSpot" ) ) return OBJECT_MARKPOWER;
+ if ( Cmd(p, "TitaniumSpot" ) ) return OBJECT_MARKSTONE;
+ if ( Cmd(p, "UraniumSpot" ) ) return OBJECT_MARKURANIUM;
+ if ( Cmd(p, "PlatinumSpot" ) ) return OBJECT_MARKURANIUM;
+ if ( Cmd(p, "KeyASpot" ) ) return OBJECT_MARKKEYa;
+ if ( Cmd(p, "KeyBSpot" ) ) return OBJECT_MARKKEYb;
+ if ( Cmd(p, "KeyCSpot" ) ) return OBJECT_MARKKEYc;
+ if ( Cmd(p, "KeyDSpot" ) ) return OBJECT_MARKKEYd;
+ if ( Cmd(p, "WayPoint" ) ) return OBJECT_WAYPOINT;
+ if ( Cmd(p, "BlueFlag" ) ) return OBJECT_FLAGb;
+ if ( Cmd(p, "RedFlag" ) ) return OBJECT_FLAGr;
+ if ( Cmd(p, "GreenFlag" ) ) return OBJECT_FLAGg;
+ if ( Cmd(p, "YellowFlag" ) ) return OBJECT_FLAGy;
+ if ( Cmd(p, "VioletFlag" ) ) return OBJECT_FLAGv;
+ if ( Cmd(p, "PowerCell" ) ) return OBJECT_POWER;
+ if ( Cmd(p, "FuelCellPlant" ) ) return OBJECT_NUCLEAR;
+ if ( Cmd(p, "FuelCell" ) ) return OBJECT_ATOMIC;
+ if ( Cmd(p, "NuclearCell" ) ) return OBJECT_ATOMIC;
+ if ( Cmd(p, "TitaniumOre" ) ) return OBJECT_STONE;
+ if ( Cmd(p, "UraniumOre" ) ) return OBJECT_URANIUM;
+ if ( Cmd(p, "PlatinumOre" ) ) return OBJECT_URANIUM;
+ if ( Cmd(p, "Titanium" ) ) return OBJECT_METAL;
+ if ( Cmd(p, "OrgaMatter" ) ) return OBJECT_BULLET;
+ if ( Cmd(p, "BlackBox" ) ) return OBJECT_BBOX;
+ if ( Cmd(p, "KeyA" ) ) return OBJECT_KEYa;
+ if ( Cmd(p, "KeyB" ) ) return OBJECT_KEYb;
+ if ( Cmd(p, "KeyC" ) ) return OBJECT_KEYc;
+ if ( Cmd(p, "KeyD" ) ) return OBJECT_KEYd;
+ if ( Cmd(p, "TNT" ) ) return OBJECT_TNT;
+ if ( Cmd(p, "Scrap1" ) ) return OBJECT_SCRAP1;
+ if ( Cmd(p, "Scrap2" ) ) return OBJECT_SCRAP2;
+ if ( Cmd(p, "Scrap3" ) ) return OBJECT_SCRAP3;
+ if ( Cmd(p, "Scrap4" ) ) return OBJECT_SCRAP4;
+ if ( Cmd(p, "Scrap5" ) ) return OBJECT_SCRAP5;
+ if ( Cmd(p, "Mine" ) ) return OBJECT_BOMB;
+ if ( Cmd(p, "Firework" ) ) return OBJECT_WINFIRE;
+ if ( Cmd(p, "Bag" ) ) return OBJECT_BAG;
+ if ( Cmd(p, "Greenery10" ) ) return OBJECT_PLANT10;
+ if ( Cmd(p, "Greenery11" ) ) return OBJECT_PLANT11;
+ if ( Cmd(p, "Greenery12" ) ) return OBJECT_PLANT12;
+ if ( Cmd(p, "Greenery13" ) ) return OBJECT_PLANT13;
+ if ( Cmd(p, "Greenery14" ) ) return OBJECT_PLANT14;
+ if ( Cmd(p, "Greenery15" ) ) return OBJECT_PLANT15;
+ if ( Cmd(p, "Greenery16" ) ) return OBJECT_PLANT16;
+ if ( Cmd(p, "Greenery17" ) ) return OBJECT_PLANT17;
+ if ( Cmd(p, "Greenery18" ) ) return OBJECT_PLANT18;
+ if ( Cmd(p, "Greenery19" ) ) return OBJECT_PLANT19;
+ if ( Cmd(p, "Greenery0" ) ) return OBJECT_PLANT0;
+ if ( Cmd(p, "Greenery1" ) ) return OBJECT_PLANT1;
+ if ( Cmd(p, "Greenery2" ) ) return OBJECT_PLANT2;
+ if ( Cmd(p, "Greenery3" ) ) return OBJECT_PLANT3;
+ if ( Cmd(p, "Greenery4" ) ) return OBJECT_PLANT4;
+ if ( Cmd(p, "Greenery5" ) ) return OBJECT_PLANT5;
+ if ( Cmd(p, "Greenery6" ) ) return OBJECT_PLANT6;
+ if ( Cmd(p, "Greenery7" ) ) return OBJECT_PLANT7;
+ if ( Cmd(p, "Greenery8" ) ) return OBJECT_PLANT8;
+ if ( Cmd(p, "Greenery9" ) ) return OBJECT_PLANT9;
+ if ( Cmd(p, "Tree0" ) ) return OBJECT_TREE0;
+ if ( Cmd(p, "Tree1" ) ) return OBJECT_TREE1;
+ if ( Cmd(p, "Tree2" ) ) return OBJECT_TREE2;
+ if ( Cmd(p, "Tree3" ) ) return OBJECT_TREE3;
+ if ( Cmd(p, "Tree4" ) ) return OBJECT_TREE4;
+ if ( Cmd(p, "Tree5" ) ) return OBJECT_TREE5;
+ if ( Cmd(p, "Tree6" ) ) return OBJECT_TREE6;
+ if ( Cmd(p, "Tree7" ) ) return OBJECT_TREE7;
+ if ( Cmd(p, "Tree8" ) ) return OBJECT_TREE8;
+ if ( Cmd(p, "Tree9" ) ) return OBJECT_TREE9;
+ if ( Cmd(p, "Mushroom0" ) ) return OBJECT_MUSHROOM0;
+ if ( Cmd(p, "Mushroom1" ) ) return OBJECT_MUSHROOM1;
+ if ( Cmd(p, "Mushroom2" ) ) return OBJECT_MUSHROOM2;
+ if ( Cmd(p, "Mushroom3" ) ) return OBJECT_MUSHROOM3;
+ if ( Cmd(p, "Mushroom4" ) ) return OBJECT_MUSHROOM4;
+ if ( Cmd(p, "Mushroom5" ) ) return OBJECT_MUSHROOM5;
+ if ( Cmd(p, "Mushroom6" ) ) return OBJECT_MUSHROOM6;
+ if ( Cmd(p, "Mushroom7" ) ) return OBJECT_MUSHROOM7;
+ if ( Cmd(p, "Mushroom8" ) ) return OBJECT_MUSHROOM8;
+ if ( Cmd(p, "Mushroom9" ) ) return OBJECT_MUSHROOM9;
+ if ( Cmd(p, "Home" ) ) return OBJECT_HOME1;
+ if ( Cmd(p, "Derrick" ) ) return OBJECT_DERRICK;
+ if ( Cmd(p, "BotFactory" ) ) return OBJECT_FACTORY;
+ if ( Cmd(p, "PowerStation" ) ) return OBJECT_STATION;
+ if ( Cmd(p, "Converter" ) ) return OBJECT_CONVERT;
+ if ( Cmd(p, "RepairCenter" ) ) return OBJECT_REPAIR;
+ if ( Cmd(p, "Destroyer" ) ) return OBJECT_DESTROYER;
+ if ( Cmd(p, "DefenseTower" ) ) return OBJECT_TOWER;
+ if ( Cmd(p, "AlienNest" ) ) return OBJECT_NEST;
+ if ( Cmd(p, "ResearchCenter" ) ) return OBJECT_RESEARCH;
+ if ( Cmd(p, "RadarStation" ) ) return OBJECT_RADAR;
+ if ( Cmd(p, "ExchangePost" ) ) return OBJECT_INFO;
+ if ( Cmd(p, "PowerPlant" ) ) return OBJECT_ENERGY;
+ if ( Cmd(p, "AutoLab" ) ) return OBJECT_LABO;
+ if ( Cmd(p, "NuclearPlant" ) ) return OBJECT_NUCLEAR;
+ if ( Cmd(p, "PowerCaptor" ) ) return OBJECT_PARA;
+ if ( Cmd(p, "Vault" ) ) return OBJECT_SAFE;
+ if ( Cmd(p, "Houston" ) ) return OBJECT_HUSTON;
+ if ( Cmd(p, "Target1" ) ) return OBJECT_TARGET1;
+ if ( Cmd(p, "Target2" ) ) return OBJECT_TARGET2;
+ if ( Cmd(p, "StartArea" ) ) return OBJECT_START;
+ if ( Cmd(p, "GoalArea" ) ) return OBJECT_END;
+ if ( Cmd(p, "AlienQueen" ) ) return OBJECT_MOTHER;
+ if ( Cmd(p, "AlienEgg" ) ) return OBJECT_EGG;
+ if ( Cmd(p, "AlienAnt" ) ) return OBJECT_ANT;
+ if ( Cmd(p, "AlienSpider" ) ) return OBJECT_SPIDER;
+ if ( Cmd(p, "AlienWasp" ) ) return OBJECT_BEE;
+ if ( Cmd(p, "AlienWorm" ) ) return OBJECT_WORM;
+ if ( Cmd(p, "WreckBotw1" ) ) return OBJECT_RUINmobilew1;
+ if ( Cmd(p, "WreckBotw2" ) ) return OBJECT_RUINmobilew2;
+ if ( Cmd(p, "WreckBott1" ) ) return OBJECT_RUINmobilet1;
+ if ( Cmd(p, "WreckBott2" ) ) return OBJECT_RUINmobilet2;
+ if ( Cmd(p, "WreckBotr1" ) ) return OBJECT_RUINmobiler1;
+ if ( Cmd(p, "WreckBotr2" ) ) return OBJECT_RUINmobiler2;
+ if ( Cmd(p, "RuinBotFactory" ) ) return OBJECT_RUINfactory;
+ if ( Cmd(p, "RuinDoor" ) ) return OBJECT_RUINdoor;
+ if ( Cmd(p, "RuinSupport" ) ) return OBJECT_RUINsupport;
+ if ( Cmd(p, "RuinRadar" ) ) return OBJECT_RUINradar;
+ if ( Cmd(p, "RuinConvert" ) ) return OBJECT_RUINconvert;
+ if ( Cmd(p, "RuinBaseCamp" ) ) return OBJECT_RUINbase;
+ if ( Cmd(p, "RuinHeadCamp" ) ) return OBJECT_RUINhead;
+ if ( Cmd(p, "Barrier0" ) ) return OBJECT_BARRIER0;
+ if ( Cmd(p, "Barrier1" ) ) return OBJECT_BARRIER1;
+ if ( Cmd(p, "Barrier2" ) ) return OBJECT_BARRIER2;
+ if ( Cmd(p, "Barrier3" ) ) return OBJECT_BARRIER3;
+ if ( Cmd(p, "Barrier4" ) ) return OBJECT_BARRIER4;
+ if ( Cmd(p, "Teen40" ) ) return OBJECT_TEEN40;
+ if ( Cmd(p, "Teen41" ) ) return OBJECT_TEEN41;
+ if ( Cmd(p, "Teen42" ) ) return OBJECT_TEEN42;
+ if ( Cmd(p, "Teen43" ) ) return OBJECT_TEEN43;
+ if ( Cmd(p, "Teen44" ) ) return OBJECT_TEEN44;
+ if ( Cmd(p, "Teen45" ) ) return OBJECT_TEEN45;
+ if ( Cmd(p, "Teen46" ) ) return OBJECT_TEEN46;
+ if ( Cmd(p, "Teen47" ) ) return OBJECT_TEEN47;
+ if ( Cmd(p, "Teen48" ) ) return OBJECT_TEEN48;
+ if ( Cmd(p, "Teen49" ) ) return OBJECT_TEEN49;
+ if ( Cmd(p, "Teen30" ) ) return OBJECT_TEEN30;
+ if ( Cmd(p, "Teen31" ) ) return OBJECT_TEEN31;
+ if ( Cmd(p, "Teen32" ) ) return OBJECT_TEEN32;
+ if ( Cmd(p, "Teen33" ) ) return OBJECT_TEEN33;
+ if ( Cmd(p, "Stone" ) ) return OBJECT_TEEN34;
+ if ( Cmd(p, "Teen35" ) ) return OBJECT_TEEN35;
+ if ( Cmd(p, "Teen36" ) ) return OBJECT_TEEN36;
+ if ( Cmd(p, "Teen37" ) ) return OBJECT_TEEN37;
+ if ( Cmd(p, "Teen38" ) ) return OBJECT_TEEN38;
+ if ( Cmd(p, "Teen39" ) ) return OBJECT_TEEN39;
+ if ( Cmd(p, "Teen20" ) ) return OBJECT_TEEN20;
+ if ( Cmd(p, "Teen21" ) ) return OBJECT_TEEN21;
+ if ( Cmd(p, "Teen22" ) ) return OBJECT_TEEN22;
+ if ( Cmd(p, "Teen23" ) ) return OBJECT_TEEN23;
+ if ( Cmd(p, "Teen24" ) ) return OBJECT_TEEN24;
+ if ( Cmd(p, "Teen25" ) ) return OBJECT_TEEN25;
+ if ( Cmd(p, "Teen26" ) ) return OBJECT_TEEN26;
+ if ( Cmd(p, "Teen27" ) ) return OBJECT_TEEN27;
+ if ( Cmd(p, "Teen28" ) ) return OBJECT_TEEN28;
+ if ( Cmd(p, "Teen29" ) ) return OBJECT_TEEN29;
+ if ( Cmd(p, "Teen10" ) ) return OBJECT_TEEN10;
+ if ( Cmd(p, "Teen11" ) ) return OBJECT_TEEN11;
+ if ( Cmd(p, "Teen12" ) ) return OBJECT_TEEN12;
+ if ( Cmd(p, "Teen13" ) ) return OBJECT_TEEN13;
+ if ( Cmd(p, "Teen14" ) ) return OBJECT_TEEN14;
+ if ( Cmd(p, "Teen15" ) ) return OBJECT_TEEN15;
+ if ( Cmd(p, "Teen16" ) ) return OBJECT_TEEN16;
+ if ( Cmd(p, "Teen17" ) ) return OBJECT_TEEN17;
+ if ( Cmd(p, "Teen18" ) ) return OBJECT_TEEN18;
+ if ( Cmd(p, "Teen19" ) ) return OBJECT_TEEN19;
+ if ( Cmd(p, "Teen0" ) ) return OBJECT_TEEN0;
+ if ( Cmd(p, "Teen1" ) ) return OBJECT_TEEN1;
+ if ( Cmd(p, "Teen2" ) ) return OBJECT_TEEN2;
+ if ( Cmd(p, "Teen3" ) ) return OBJECT_TEEN3;
+ if ( Cmd(p, "Teen4" ) ) return OBJECT_TEEN4;
+ if ( Cmd(p, "Teen5" ) ) return OBJECT_TEEN5;
+ if ( Cmd(p, "Teen6" ) ) return OBJECT_TEEN6;
+ if ( Cmd(p, "Teen7" ) ) return OBJECT_TEEN7;
+ if ( Cmd(p, "Teen8" ) ) return OBJECT_TEEN8;
+ if ( Cmd(p, "Teen9" ) ) return OBJECT_TEEN9;
+ if ( Cmd(p, "Quartz0" ) ) return OBJECT_QUARTZ0;
+ if ( Cmd(p, "Quartz1" ) ) return OBJECT_QUARTZ1;
+ if ( Cmd(p, "Quartz2" ) ) return OBJECT_QUARTZ2;
+ if ( Cmd(p, "Quartz3" ) ) return OBJECT_QUARTZ3;
+ if ( Cmd(p, "Quartz4" ) ) return OBJECT_QUARTZ4;
+ if ( Cmd(p, "Quartz5" ) ) return OBJECT_QUARTZ5;
+ if ( Cmd(p, "Quartz6" ) ) return OBJECT_QUARTZ6;
+ if ( Cmd(p, "Quartz7" ) ) return OBJECT_QUARTZ7;
+ if ( Cmd(p, "Quartz8" ) ) return OBJECT_QUARTZ8;
+ if ( Cmd(p, "Quartz9" ) ) return OBJECT_QUARTZ9;
+ if ( Cmd(p, "MegaStalk0" ) ) return OBJECT_ROOT0;
+ if ( Cmd(p, "MegaStalk1" ) ) return OBJECT_ROOT1;
+ if ( Cmd(p, "MegaStalk2" ) ) return OBJECT_ROOT2;
+ if ( Cmd(p, "MegaStalk3" ) ) return OBJECT_ROOT3;
+ if ( Cmd(p, "MegaStalk4" ) ) return OBJECT_ROOT4;
+ if ( Cmd(p, "MegaStalk5" ) ) return OBJECT_ROOT5;
+ if ( Cmd(p, "MegaStalk6" ) ) return OBJECT_ROOT6;
+ if ( Cmd(p, "MegaStalk7" ) ) return OBJECT_ROOT7;
+ if ( Cmd(p, "MegaStalk8" ) ) return OBJECT_ROOT8;
+ if ( Cmd(p, "MegaStalk9" ) ) return OBJECT_ROOT9;
+ if ( Cmd(p, "ApolloLEM" ) ) return OBJECT_APOLLO1;
+ if ( Cmd(p, "ApolloJeep" ) ) return OBJECT_APOLLO2;
+ if ( Cmd(p, "ApolloFlag" ) ) return OBJECT_APOLLO3;
+ if ( Cmd(p, "ApolloModule" ) ) return OBJECT_APOLLO4;
+ if ( Cmd(p, "ApolloAntenna" ) ) return OBJECT_APOLLO5;
+ if ( Cmd(p, "Me" ) ) return OBJECT_HUMAN;
+ if ( Cmd(p, "Tech" ) ) return OBJECT_TECH;
+
+ return def;
+}
+
+// Retourne le nom d'un type d'objet.
+
+char* GetTypeObject(ObjectType type)
+{
+ if ( type == OBJECT_PORTICO ) return "Portico";
+ if ( type == OBJECT_BASE ) return "SpaceShip";
+ if ( type == OBJECT_MOBILEwt ) return "PracticeBot";
+ if ( type == OBJECT_MOBILEfa ) return "WingedGrabber";
+ if ( type == OBJECT_MOBILEta ) return "TrackedGrabber";
+ if ( type == OBJECT_MOBILEwa ) return "WheeledGrabber";
+ if ( type == OBJECT_MOBILEia ) return "LeggedGrabber";
+ if ( type == OBJECT_MOBILEfc ) return "WingedShooter";
+ if ( type == OBJECT_MOBILEtc ) return "TrackedShooter";
+ if ( type == OBJECT_MOBILEwc ) return "WheeledShooter";
+ if ( type == OBJECT_MOBILEic ) return "LeggedShooter";
+ if ( type == OBJECT_MOBILEfi ) return "WingedOrgaShooter";
+ if ( type == OBJECT_MOBILEti ) return "TrackedOrgaShooter";
+ if ( type == OBJECT_MOBILEwi ) return "WheeledOrgaShooter";
+ if ( type == OBJECT_MOBILEii ) return "LeggedOrgaShooter";
+ if ( type == OBJECT_MOBILEfs ) return "WingedSniffer";
+ if ( type == OBJECT_MOBILEts ) return "TrackedSniffer";
+ if ( type == OBJECT_MOBILEws ) return "WheeledSniffer";
+ if ( type == OBJECT_MOBILEis ) return "LeggedSniffer";
+ if ( type == OBJECT_MOBILErt ) return "Thumper";
+ if ( type == OBJECT_MOBILErc ) return "PhazerShooter";
+ if ( type == OBJECT_MOBILErr ) return "Recycler";
+ if ( type == OBJECT_MOBILErs ) return "Shielder";
+ if ( type == OBJECT_MOBILEsa ) return "Subber";
+ if ( type == OBJECT_MOBILEtg ) return "TargetBot";
+ if ( type == OBJECT_MOBILEdr ) return "Scribbler";
+ if ( type == OBJECT_MARKPOWER ) return "PowerSpot";
+ if ( type == OBJECT_MARKSTONE ) return "TitaniumSpot";
+#if _GERMAN | _WG
+ if ( type == OBJECT_MARKURANIUM ) return "PlatinumSpot";
+#else
+ if ( type == OBJECT_MARKURANIUM ) return "UraniumSpot";
+#endif
+ if ( type == OBJECT_MARKKEYa ) return "KeyASpot";
+ if ( type == OBJECT_MARKKEYb ) return "KeyBSpot";
+ if ( type == OBJECT_MARKKEYc ) return "KeyCSpot";
+ if ( type == OBJECT_MARKKEYd ) return "KeyDSpot";
+ if ( type == OBJECT_WAYPOINT ) return "WayPoint";
+ if ( type == OBJECT_FLAGb ) return "BlueFlag";
+ if ( type == OBJECT_FLAGr ) return "RedFlag";
+ if ( type == OBJECT_FLAGg ) return "GreenFlag";
+ if ( type == OBJECT_FLAGy ) return "YellowFlag";
+ if ( type == OBJECT_FLAGv ) return "VioletFlag";
+ if ( type == OBJECT_POWER ) return "PowerCell";
+#if _GERMAN | _WG
+ if ( type == OBJECT_ATOMIC ) return "FuelCell";
+#else
+ if ( type == OBJECT_ATOMIC ) return "NuclearCell";
+#endif
+ if ( type == OBJECT_STONE ) return "TitaniumOre";
+#if _GERMAN | _WG
+ if ( type == OBJECT_URANIUM ) return "PlatinumOre";
+#else
+ if ( type == OBJECT_URANIUM ) return "UraniumOre";
+#endif
+ if ( type == OBJECT_METAL ) return "Titanium";
+ if ( type == OBJECT_BULLET ) return "OrgaMatter";
+ if ( type == OBJECT_BBOX ) return "BlackBox";
+ if ( type == OBJECT_KEYa ) return "KeyA";
+ if ( type == OBJECT_KEYb ) return "KeyB";
+ if ( type == OBJECT_KEYc ) return "KeyC";
+ if ( type == OBJECT_KEYd ) return "KeyD";
+ if ( type == OBJECT_TNT ) return "TNT";
+ if ( type == OBJECT_SCRAP1 ) return "Scrap1";
+ if ( type == OBJECT_SCRAP2 ) return "Scrap2";
+ if ( type == OBJECT_SCRAP3 ) return "Scrap3";
+ if ( type == OBJECT_SCRAP4 ) return "Scrap4";
+ if ( type == OBJECT_SCRAP5 ) return "Scrap5";
+ if ( type == OBJECT_BOMB ) return "Mine";
+ if ( type == OBJECT_WINFIRE ) return "Firework";
+ if ( type == OBJECT_BAG ) return "Bag";
+ if ( type == OBJECT_PLANT0 ) return "Greenery0";
+ if ( type == OBJECT_PLANT1 ) return "Greenery1";
+ if ( type == OBJECT_PLANT2 ) return "Greenery2";
+ if ( type == OBJECT_PLANT3 ) return "Greenery3";
+ if ( type == OBJECT_PLANT4 ) return "Greenery4";
+ if ( type == OBJECT_PLANT5 ) return "Greenery5";
+ if ( type == OBJECT_PLANT6 ) return "Greenery6";
+ if ( type == OBJECT_PLANT7 ) return "Greenery7";
+ if ( type == OBJECT_PLANT8 ) return "Greenery8";
+ if ( type == OBJECT_PLANT9 ) return "Greenery9";
+ if ( type == OBJECT_PLANT10 ) return "Greenery10";
+ if ( type == OBJECT_PLANT11 ) return "Greenery11";
+ if ( type == OBJECT_PLANT12 ) return "Greenery12";
+ if ( type == OBJECT_PLANT13 ) return "Greenery13";
+ if ( type == OBJECT_PLANT14 ) return "Greenery14";
+ if ( type == OBJECT_PLANT15 ) return "Greenery15";
+ if ( type == OBJECT_PLANT16 ) return "Greenery16";
+ if ( type == OBJECT_PLANT17 ) return "Greenery17";
+ if ( type == OBJECT_PLANT18 ) return "Greenery18";
+ if ( type == OBJECT_PLANT19 ) return "Greenery19";
+ if ( type == OBJECT_TREE0 ) return "Tree0";
+ if ( type == OBJECT_TREE1 ) return "Tree1";
+ if ( type == OBJECT_TREE2 ) return "Tree2";
+ if ( type == OBJECT_TREE3 ) return "Tree3";
+ if ( type == OBJECT_TREE4 ) return "Tree4";
+ if ( type == OBJECT_TREE5 ) return "Tree5";
+ if ( type == OBJECT_TREE6 ) return "Tree6";
+ if ( type == OBJECT_TREE7 ) return "Tree7";
+ if ( type == OBJECT_TREE8 ) return "Tree8";
+ if ( type == OBJECT_TREE9 ) return "Tree9";
+ if ( type == OBJECT_MUSHROOM0 ) return "Mushroom0";
+ if ( type == OBJECT_MUSHROOM1 ) return "Mushroom1";
+ if ( type == OBJECT_MUSHROOM2 ) return "Mushroom2";
+ if ( type == OBJECT_MUSHROOM3 ) return "Mushroom3";
+ if ( type == OBJECT_MUSHROOM4 ) return "Mushroom4";
+ if ( type == OBJECT_MUSHROOM5 ) return "Mushroom5";
+ if ( type == OBJECT_MUSHROOM6 ) return "Mushroom6";
+ if ( type == OBJECT_MUSHROOM7 ) return "Mushroom7";
+ if ( type == OBJECT_MUSHROOM8 ) return "Mushroom8";
+ if ( type == OBJECT_MUSHROOM9 ) return "Mushroom9";
+ if ( type == OBJECT_HOME1 ) return "Home";
+ if ( type == OBJECT_DERRICK ) return "Derrick";
+ if ( type == OBJECT_FACTORY ) return "BotFactory";
+ if ( type == OBJECT_STATION ) return "PowerStation";
+ if ( type == OBJECT_CONVERT ) return "Converter";
+ if ( type == OBJECT_REPAIR ) return "RepairCenter";
+ if ( type == OBJECT_DESTROYER ) return "Destroyer";
+ if ( type == OBJECT_TOWER ) return "DefenseTower";
+ if ( type == OBJECT_NEST ) return "AlienNest";
+ if ( type == OBJECT_RESEARCH ) return "ResearchCenter";
+ if ( type == OBJECT_RADAR ) return "RadarStation";
+ if ( type == OBJECT_INFO ) return "ExchangePost";
+ if ( type == OBJECT_ENERGY ) return "PowerPlant";
+ if ( type == OBJECT_LABO ) return "AutoLab";
+#if _GERMAN | _WG
+ if ( type == OBJECT_NUCLEAR ) return "FuelCellPlant";
+#else
+ if ( type == OBJECT_NUCLEAR ) return "NuclearPlant";
+#endif
+ if ( type == OBJECT_PARA ) return "PowerCaptor";
+ if ( type == OBJECT_SAFE ) return "Vault";
+ if ( type == OBJECT_HUSTON ) return "Houston";
+ if ( type == OBJECT_TARGET1 ) return "Target1";
+ if ( type == OBJECT_TARGET2 ) return "Target2";
+ if ( type == OBJECT_START ) return "StartArea";
+ if ( type == OBJECT_END ) return "GoalArea";
+ if ( type == OBJECT_MOTHER ) return "AlienQueen";
+ if ( type == OBJECT_EGG ) return "AlienEgg";
+ if ( type == OBJECT_ANT ) return "AlienAnt";
+ if ( type == OBJECT_SPIDER ) return "AlienSpider";
+ if ( type == OBJECT_BEE ) return "AlienWasp";
+ if ( type == OBJECT_WORM ) return "AlienWorm";
+ if ( type == OBJECT_RUINmobilew1 ) return "WreckBotw1";
+ if ( type == OBJECT_RUINmobilew2 ) return "WreckBotw2";
+ if ( type == OBJECT_RUINmobilet1 ) return "WreckBott1";
+ if ( type == OBJECT_RUINmobilet2 ) return "WreckBott2";
+ if ( type == OBJECT_RUINmobiler1 ) return "WreckBotr1";
+ if ( type == OBJECT_RUINmobiler2 ) return "WreckBotr2";
+ if ( type == OBJECT_RUINfactory ) return "RuinBotFactory";
+ if ( type == OBJECT_RUINdoor ) return "RuinDoor";
+ if ( type == OBJECT_RUINsupport ) return "RuinSupport";
+ if ( type == OBJECT_RUINradar ) return "RuinRadar";
+ if ( type == OBJECT_RUINconvert ) return "RuinConvert";
+ if ( type == OBJECT_RUINbase ) return "RuinBaseCamp";
+ if ( type == OBJECT_RUINhead ) return "RuinHeadCamp";
+ if ( type == OBJECT_BARRIER0 ) return "Barrier0";
+ if ( type == OBJECT_BARRIER1 ) return "Barrier1";
+ if ( type == OBJECT_BARRIER2 ) return "Barrier2";
+ if ( type == OBJECT_BARRIER3 ) return "Barrier3";
+ if ( type == OBJECT_BARRIER4 ) return "Barrier4";
+ if ( type == OBJECT_TEEN0 ) return "Teen0";
+ if ( type == OBJECT_TEEN1 ) return "Teen1";
+ if ( type == OBJECT_TEEN2 ) return "Teen2";
+ if ( type == OBJECT_TEEN3 ) return "Teen3";
+ if ( type == OBJECT_TEEN4 ) return "Teen4";
+ if ( type == OBJECT_TEEN5 ) return "Teen5";
+ if ( type == OBJECT_TEEN6 ) return "Teen6";
+ if ( type == OBJECT_TEEN7 ) return "Teen7";
+ if ( type == OBJECT_TEEN8 ) return "Teen8";
+ if ( type == OBJECT_TEEN9 ) return "Teen9";
+ if ( type == OBJECT_TEEN10 ) return "Teen10";
+ if ( type == OBJECT_TEEN11 ) return "Teen11";
+ if ( type == OBJECT_TEEN12 ) return "Teen12";
+ if ( type == OBJECT_TEEN13 ) return "Teen13";
+ if ( type == OBJECT_TEEN14 ) return "Teen14";
+ if ( type == OBJECT_TEEN15 ) return "Teen15";
+ if ( type == OBJECT_TEEN16 ) return "Teen16";
+ if ( type == OBJECT_TEEN17 ) return "Teen17";
+ if ( type == OBJECT_TEEN18 ) return "Teen18";
+ if ( type == OBJECT_TEEN19 ) return "Teen19";
+ if ( type == OBJECT_TEEN20 ) return "Teen20";
+ if ( type == OBJECT_TEEN21 ) return "Teen21";
+ if ( type == OBJECT_TEEN22 ) return "Teen22";
+ if ( type == OBJECT_TEEN23 ) return "Teen23";
+ if ( type == OBJECT_TEEN24 ) return "Teen24";
+ if ( type == OBJECT_TEEN25 ) return "Teen25";
+ if ( type == OBJECT_TEEN26 ) return "Teen26";
+ if ( type == OBJECT_TEEN27 ) return "Teen27";
+ if ( type == OBJECT_TEEN28 ) return "Teen28";
+ if ( type == OBJECT_TEEN29 ) return "Teen29";
+ if ( type == OBJECT_TEEN30 ) return "Teen30";
+ if ( type == OBJECT_TEEN31 ) return "Teen31";
+ if ( type == OBJECT_TEEN32 ) return "Teen32";
+ if ( type == OBJECT_TEEN33 ) return "Teen33";
+ if ( type == OBJECT_TEEN34 ) return "Stone";
+ if ( type == OBJECT_TEEN35 ) return "Teen35";
+ if ( type == OBJECT_TEEN36 ) return "Teen36";
+ if ( type == OBJECT_TEEN37 ) return "Teen37";
+ if ( type == OBJECT_TEEN38 ) return "Teen38";
+ if ( type == OBJECT_TEEN39 ) return "Teen39";
+ if ( type == OBJECT_TEEN40 ) return "Teen40";
+ if ( type == OBJECT_TEEN41 ) return "Teen41";
+ if ( type == OBJECT_TEEN42 ) return "Teen42";
+ if ( type == OBJECT_TEEN43 ) return "Teen43";
+ if ( type == OBJECT_TEEN44 ) return "Teen44";
+ if ( type == OBJECT_TEEN45 ) return "Teen45";
+ if ( type == OBJECT_TEEN46 ) return "Teen46";
+ if ( type == OBJECT_TEEN47 ) return "Teen47";
+ if ( type == OBJECT_TEEN48 ) return "Teen48";
+ if ( type == OBJECT_TEEN49 ) return "Teen49";
+ if ( type == OBJECT_QUARTZ0 ) return "Quartz0";
+ if ( type == OBJECT_QUARTZ1 ) return "Quartz1";
+ if ( type == OBJECT_QUARTZ2 ) return "Quartz2";
+ if ( type == OBJECT_QUARTZ3 ) return "Quartz3";
+ if ( type == OBJECT_QUARTZ4 ) return "Quartz4";
+ if ( type == OBJECT_QUARTZ5 ) return "Quartz5";
+ if ( type == OBJECT_QUARTZ6 ) return "Quartz6";
+ if ( type == OBJECT_QUARTZ7 ) return "Quartz7";
+ if ( type == OBJECT_QUARTZ8 ) return "Quartz8";
+ if ( type == OBJECT_QUARTZ9 ) return "Quartz9";
+ if ( type == OBJECT_ROOT0 ) return "MegaStalk0";
+ if ( type == OBJECT_ROOT1 ) return "MegaStalk1";
+ if ( type == OBJECT_ROOT2 ) return "MegaStalk2";
+ if ( type == OBJECT_ROOT3 ) return "MegaStalk3";
+ if ( type == OBJECT_ROOT4 ) return "MegaStalk4";
+ if ( type == OBJECT_ROOT5 ) return "MegaStalk5";
+ if ( type == OBJECT_ROOT6 ) return "MegaStalk6";
+ if ( type == OBJECT_ROOT7 ) return "MegaStalk7";
+ if ( type == OBJECT_ROOT8 ) return "MegaStalk8";
+ if ( type == OBJECT_ROOT9 ) return "MegaStalk9";
+ if ( type == OBJECT_APOLLO1 ) return "ApolloLEM";
+ if ( type == OBJECT_APOLLO2 ) return "ApolloJeep";
+ if ( type == OBJECT_APOLLO3 ) return "ApolloFlag";
+ if ( type == OBJECT_APOLLO4 ) return "ApolloModule";
+ if ( type == OBJECT_APOLLO5 ) return "ApolloAntenna";
+ if ( type == OBJECT_HUMAN ) return "Me";
+ if ( type == OBJECT_TECH ) return "Tech";
+ return "";
+}
+
+// Retourne le type de l'eau.
+
+WaterType GetTypeWater(char *line, int rank, WaterType def)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return def;
+
+ if ( Cmd(p, "NULL" ) ) return WATER_NULL;
+ if ( Cmd(p, "TT" ) ) return WATER_TT;
+ if ( Cmd(p, "TO" ) ) return WATER_TO;
+ if ( Cmd(p, "CT" ) ) return WATER_CT;
+ if ( Cmd(p, "CO" ) ) return WATER_CO;
+
+ return def;
+}
+
+// Retourne le type de terrain.
+
+D3DTypeObj GetTypeTerrain(char *line, int rank, D3DTypeObj def)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return def;
+
+ if ( Cmd(p, "Terrain" ) ) return TYPETERRAIN;
+ if ( Cmd(p, "Object" ) ) return TYPEFIX;
+ if ( Cmd(p, "Quartz" ) ) return TYPEQUARTZ;
+ if ( Cmd(p, "Metal" ) ) return TYPEMETAL;
+
+ return def;
+}
+
+// Retourne le numéro d'un bâtiment.
+
+int GetBuild(char *line, int rank)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return 0;
+
+ if ( Cmd(p, "BotFactory" ) ) return BUILD_FACTORY;
+ if ( Cmd(p, "Derrick" ) ) return BUILD_DERRICK;
+ if ( Cmd(p, "Converter" ) ) return BUILD_CONVERT;
+ if ( Cmd(p, "RadarStation" ) ) return BUILD_RADAR;
+ if ( Cmd(p, "PowerPlant" ) ) return BUILD_ENERGY;
+ if ( Cmd(p, "NuclearPlant" ) ) return BUILD_NUCLEAR;
+ if ( Cmd(p, "FuelCellPlant" ) ) return BUILD_NUCLEAR;
+ if ( Cmd(p, "PowerStation" ) ) return BUILD_STATION;
+ if ( Cmd(p, "RepairCenter" ) ) return BUILD_REPAIR;
+ if ( Cmd(p, "DefenseTower" ) ) return BUILD_TOWER;
+ if ( Cmd(p, "ResearchCenter") ) return BUILD_RESEARCH;
+ if ( Cmd(p, "AutoLab" ) ) return BUILD_LABO;
+ if ( Cmd(p, "PowerCaptor" ) ) return BUILD_PARA;
+ if ( Cmd(p, "ExchangePost" ) ) return BUILD_INFO;
+ if ( Cmd(p, "FlatGround" ) ) return BUILD_GFLAT;
+ if ( Cmd(p, "Flag" ) ) return BUILD_FLAG;
+
+ return 0;
+}
+
+// Retourne le numéro d'une recherche.
+
+int GetResearch(char *line, int rank)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return 0;
+
+ if ( Cmd(p, "TRACKER" ) ) return RESEARCH_TANK;
+ if ( Cmd(p, "WINGER" ) ) return RESEARCH_FLY;
+ if ( Cmd(p, "THUMPER" ) ) return RESEARCH_THUMP;
+ if ( Cmd(p, "SHOOTER" ) ) return RESEARCH_CANON;
+ if ( Cmd(p, "TOWER" ) ) return RESEARCH_TOWER;
+ if ( Cmd(p, "PHAZER" ) ) return RESEARCH_PHAZER;
+ if ( Cmd(p, "SHIELDER") ) return RESEARCH_SHIELD;
+ if ( Cmd(p, "ATOMIC" ) ) return RESEARCH_ATOMIC;
+ if ( Cmd(p, "iPAW" ) ) return RESEARCH_iPAW;
+ if ( Cmd(p, "iGUN" ) ) return RESEARCH_iGUN;
+ if ( Cmd(p, "RECYCLER") ) return RESEARCH_RECYCLER;
+ if ( Cmd(p, "SUBBER" ) ) return RESEARCH_SUBM;
+ if ( Cmd(p, "SNIFFER" ) ) return RESEARCH_SNIFFER;
+
+ return 0;
+}
+
+// Retourne le type d'un effet pyrotechnique.
+
+PyroType GetPyro(char *line, int rank)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return PT_NULL;
+
+ if ( Cmd(p, "FRAGt" ) ) return PT_FRAGT;
+ if ( Cmd(p, "FRAGo" ) ) return PT_FRAGO;
+ if ( Cmd(p, "FRAGw" ) ) return PT_FRAGW;
+ if ( Cmd(p, "EXPLOt" ) ) return PT_EXPLOT;
+ if ( Cmd(p, "EXPLOo" ) ) return PT_EXPLOO;
+ if ( Cmd(p, "EXPLOw" ) ) return PT_EXPLOW;
+ if ( Cmd(p, "SHOTt" ) ) return PT_SHOTT;
+ if ( Cmd(p, "SHOTh" ) ) return PT_SHOTH;
+ if ( Cmd(p, "SHOTm" ) ) return PT_SHOTM;
+ if ( Cmd(p, "SHOTw" ) ) return PT_SHOTW;
+ if ( Cmd(p, "EGG" ) ) return PT_EGG;
+ if ( Cmd(p, "BURNt" ) ) return PT_BURNT;
+ if ( Cmd(p, "BURNo" ) ) return PT_BURNO;
+ if ( Cmd(p, "SPIDER" ) ) return PT_SPIDER;
+ if ( Cmd(p, "FALL" ) ) return PT_FALL;
+ if ( Cmd(p, "RESET" ) ) return PT_RESET;
+ if ( Cmd(p, "WIN" ) ) return PT_WIN;
+ if ( Cmd(p, "LOST" ) ) return PT_LOST;
+
+ return PT_NULL;
+}
+
+// Retourne le type d'une caméra.
+
+CameraType GetCamera(char *line, int rank)
+{
+ char* p;
+
+ p = SearchArg(line, rank);
+ if ( *p == 0 ) return CAMERA_NULL;
+
+ if ( Cmd(p, "BACK" ) ) return CAMERA_BACK;
+ if ( Cmd(p, "PLANE" ) ) return CAMERA_PLANE;
+ if ( Cmd(p, "ONBOARD" ) ) return CAMERA_ONBOARD;
+ if ( Cmd(p, "FIX" ) ) return CAMERA_FIX;
+
+ return CAMERA_NULL;
+}
+
+// Retourne le nom d'une camera.
+
+char* GetCamera(CameraType type)
+{
+ if ( type == CAMERA_ONBOARD ) return "ONBOARD";
+ if ( type == CAMERA_FIX ) return "FIX";
+ return "BACK";
+}
+
+// Retourne un nombre entier.
+
+int OpInt(char *line, char *op, int def)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+ return GetInt(line, 0, def);
+}
+
+// Retourne un nombre réel.
+
+float OpFloat(char *line, char *op, float def)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+ return GetFloat(line, 0, def);
+}
+
+// Retourne une chaîne de caractères.
+
+void OpString(char *line, char *op, char *buffer)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 )
+ {
+ buffer[0] = 0;
+ }
+ else
+ {
+ GetString(line, 0, buffer);
+ }
+}
+
+// Retourne le type d'un objet.
+
+ObjectType OpTypeObject(char *line, char *op, ObjectType def)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+ return GetTypeObject(line, 0, def);
+}
+
+// Retourne le type d'un objet.
+
+WaterType OpTypeWater(char *line, char *op, WaterType def)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+ return GetTypeWater(line, 0, def);
+}
+
+// Retourne le type d'un objet.
+
+D3DTypeObj OpTypeTerrain(char *line, char *op, D3DTypeObj def)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+ return GetTypeTerrain(line, 0, def);
+}
+
+// Retourne le numéro d'une recherche.
+
+int OpResearch(char *line, char *op)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return 0;
+ return GetResearch(line, 0);
+}
+
+// Retourne le type d'un effet pyrotechnique.
+
+PyroType OpPyro(char *line, char *op)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return PT_NULL;
+ return GetPyro(line, 0);
+}
+
+// Retourne le type d'une caméra.
+
+CameraType OpCamera(char *line, char *op)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return CAMERA_NULL;
+ return GetCamera(line, 0);
+}
+
+// Retourne le numéro d'un bâtiment.
+
+int OpBuild(char *line, char *op)
+{
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return 0;
+ return GetBuild(line, 0);
+}
+
+// Retourne une position dans le plan XZ (vue d'en haut).
+
+D3DVECTOR OpPos(char *line, char *op)
+{
+ D3DVECTOR pos;
+
+ line = SearchOp(line, op);
+ if ( *line == 0 )
+ {
+ pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ return pos;
+ }
+ pos.x = GetFloat(line, 0, 0.0f);
+ pos.y = 0.0f;
+ pos.z = GetFloat(line, 1, 0.0f);
+ return pos;
+}
+
+// Retourne une direction.
+
+D3DVECTOR OpDir(char *line, char *op)
+{
+ D3DVECTOR dir;
+
+ line = SearchOp(line, op);
+ if ( *line == 0 )
+ {
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ return dir;
+ }
+ dir.x = GetFloat(line, 0, 0.0f);
+ dir.y = GetFloat(line, 1, 0.0f);
+ dir.z = GetFloat(line, 2, 0.0f);
+ return dir;
+}
+
+// Lit une couleur (0..255).
+
+D3DCOLOR OpColor(char *line, char *op, D3DCOLOR def)
+{
+ D3DCOLOR color;
+
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+
+ color = 0;
+ color |= (GetInt(line, 0, 0)&0xff)<<16; // r
+ color |= (GetInt(line, 1, 0)&0xff)<<8; // g
+ color |= (GetInt(line, 2, 0)&0xff)<<0; // b
+ color |= (GetInt(line, 3, 0)&0xff)<<24; // a
+ return color;
+}
+
+// Lit une couleur (-1..1).
+
+D3DCOLORVALUE OpColorValue(char *line, char *op, D3DCOLORVALUE def)
+{
+ D3DCOLORVALUE color;
+
+ line = SearchOp(line, op);
+ if ( *line == 0 ) return def;
+
+ color.r = GetFloat(line, 0, 0.0f);
+ color.g = GetFloat(line, 1, 0.0f);
+ color.b = GetFloat(line, 2, 0.0f);
+ color.a = GetFloat(line, 3, 0.0f);
+ return color;
+}
+
+
diff --git a/src/cmdtoken.h b/src/cmdtoken.h
new file mode 100644
index 0000000..6745689
--- /dev/null
+++ b/src/cmdtoken.h
@@ -0,0 +1,50 @@
+// cmdtoken.h
+
+#ifndef _CMDTOKEN_H_
+#define _CMDTOKEN_H_
+
+
+
+enum ObjectType;
+enum WaterType;
+enum PyroType;
+enum CameraType;
+
+
+
+// Procédures.
+
+extern BOOL Cmd(char *line, char *token);
+extern char* SearchOp(char *line, char *op);
+
+extern int GetInt(char *line, int rank, int def);
+extern float GetFloat(char *line, int rank, float def);
+extern void GetString(char *line, int rank, char *buffer);
+extern ObjectType GetTypeObject(char *line, int rank, ObjectType def);
+extern char* GetTypeObject(ObjectType type);
+extern WaterType GetTypeWater(char *line, int rank, WaterType def);
+extern D3DTypeObj GetTypeTerrain(char *line, int rank, D3DTypeObj def);
+extern int GetBuild(char *line, int rank);
+extern int GetResearch(char *line, int rank);
+extern PyroType GetPyro(char *line, int rank);
+extern CameraType GetCamera(char *line, int rank);
+extern char* GetCamera(CameraType type);
+
+extern int OpInt(char *line, char *op, int def);
+extern float OpFloat(char *line, char *op, float def);
+extern void OpString(char *line, char *op, char *buffer);
+extern ObjectType OpTypeObject(char *line, char *op, ObjectType def);
+extern WaterType OpTypeWater(char *line, char *op, WaterType def);
+extern D3DTypeObj OpTypeTerrain(char *line, char *op, D3DTypeObj def);
+extern int OpResearch(char *line, char *op);
+extern PyroType OpPyro(char *line, char *op);
+extern CameraType OpCamera(char *line, char *op);
+extern int OpBuild(char *line, char *op);
+extern D3DVECTOR OpPos(char *line, char *op);
+extern D3DVECTOR OpDir(char *line, char *op);
+extern D3DCOLOR OpColor(char *line, char *op, D3DCOLOR def);
+extern D3DCOLORVALUE OpColorValue(char *line, char *op, D3DCOLORVALUE def);
+
+
+
+#endif //_CMDTOKEN_H_
diff --git a/src/colobot.ini b/src/colobot.ini
new file mode 100644
index 0000000..de547ec
--- /dev/null
+++ b/src/colobot.ini
@@ -0,0 +1,75 @@
+[Gamer]
+LastName=Joueur
+
+[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=15
+MidiVolume=20
+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
+FullScreenActivateEnable=0
+AccessMission=1
+AccessUser=1
+DeleteGamer=1
+Soluce4=1
+
+[Engine]
+StateColor=-1
+BlackSrcBlend=0
+BlackDestBlend=0
+WhiteSrcBlend=0
+WhiteDestBlend=0
+DiffuseSrcBlend=0
+DiffuseDestBlend=0
+AlphaSrcBlend=0
+AlphaDestBlend=0
+AlphaMode=1
+
+[Device]
+Name=Direct3D HAL
+Mode=1600 x 1200 x 32
+FullScreen=0
+
+[Edit]
+WindowPos.x=0.19
+WindowPos.y=0.15
+WindowDim.x=0.66
+WindowDim.y=0.69
+FontSize=9.00
+IOPos.x=0.29
+IOPos.y=0.34
+IODim.x=0.50
+IODim.y=0.55
+IOPublic=0
+
+[Directory]
+scene=scene
+savegame=savegame
+public=program
+user=user
+files=files
diff --git a/src/color.cpp b/src/color.cpp
new file mode 100644
index 0000000..25036eb
--- /dev/null
+++ b/src/color.cpp
@@ -0,0 +1,215 @@
+// color.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "color.h"
+
+
+
+#define DELAY1 0.4f
+#define DELAY2 0.1f
+
+
+
+// Constructeur de l'objet.
+
+CColor::CColor(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_bRepeat = FALSE;
+ m_repeat = 0.0f;
+
+ m_color.r = 0.0f;
+ m_color.g = 0.0f;
+ m_color.b = 0.0f;
+ m_color.a = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CColor::~CColor()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CColor::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ if ( icon == -1 )
+ {
+ char name[100];
+ char* p;
+
+ GetResource(RES_EVENT, eventMsg, name);
+ p = strchr(name, '\\');
+ if ( p != 0 ) *p = 0;
+ SetName(name);
+ }
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CColor::EventProcess(const Event &event)
+{
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME && m_bRepeat )
+ {
+ if ( m_repeat != 0.0f )
+ {
+ m_repeat -= event.rTime;
+ if ( m_repeat <= 0.0f )
+ {
+ m_repeat = DELAY2;
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ m_repeat = DELAY1;
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONUP )
+ {
+ m_repeat = 0.0f;
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CColor::Draw()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DLVERTEX vertex[4]; // 2 triangles
+ D3DCOLOR color;
+ FPOINT p1, p2;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ CControl::Draw();
+
+#if _TEEN
+ color = ::RetColor(m_color);
+
+ m_engine->SetTexture("xxx.tga"); // pas de texture
+ m_engine->SetState(D3DSTATENORMAL);
+
+ device = m_engine->RetD3DDevice();
+
+ p1.x = m_pos.x+(4.0f/640.0f);
+ p1.y = m_pos.y+(4.0f/480.0f);
+ p2.x = m_pos.x+m_dim.x-(4.0f/640.0f);
+ p2.y = m_pos.y+m_dim.y-(4.0f/480.0f);
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), 0x00000000,0x00000000, 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), 0x00000000,0x00000000, 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), 0x00000000,0x00000000, 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), 0x00000000,0x00000000, 0.0f,0.0f);
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+
+ p1.x = m_pos.x+(5.0f/640.0f);
+ p1.y = m_pos.y+(5.0f/480.0f);
+ p2.x = m_pos.x+m_dim.x-(5.0f/640.0f);
+ p2.y = m_pos.y+m_dim.y-(5.0f/480.0f);
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+
+ m_engine->AddStatisticTriangle(4);
+#else
+ p1.x = m_pos.x+(3.0f/640.0f);
+ p1.y = m_pos.y+(3.0f/480.0f);
+ p2.x = m_pos.x+m_dim.x-(3.0f/640.0f);
+ p2.y = m_pos.y+m_dim.y-(3.0f/480.0f);
+
+ color = ::RetColor(m_color);
+
+ m_engine->SetTexture("xxx.tga"); // pas de texture
+ m_engine->SetState(D3DSTATENORMAL);
+
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), color,0x00000000, 0.0f,0.0f);
+
+ device = m_engine->RetD3DDevice();
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+#endif
+}
+
+
+void CColor::SetRepeat(BOOL bRepeat)
+{
+ m_bRepeat = bRepeat;
+}
+
+BOOL CColor::RetRepeat()
+{
+ return m_bRepeat;
+}
+
+
+void CColor::SetColor(D3DCOLORVALUE color)
+{
+ m_color = color;
+}
+
+D3DCOLORVALUE CColor::RetColor()
+{
+ return m_color;
+}
+
+
diff --git a/src/color.h b/src/color.h
new file mode 100644
index 0000000..9189b41
--- /dev/null
+++ b/src/color.h
@@ -0,0 +1,41 @@
+// color.h
+
+#ifndef _COLOR_H_
+#define _COLOR_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CColor : public CControl
+{
+public:
+ CColor(CInstanceManager* iMan);
+ ~CColor();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+ void SetRepeat(BOOL bRepeat);
+ BOOL RetRepeat();
+
+ void SetColor(D3DCOLORVALUE color);
+ D3DCOLORVALUE RetColor();
+
+protected:
+
+protected:
+ BOOL m_bRepeat;
+ float m_repeat;
+ D3DCOLORVALUE m_color;
+};
+
+
+#endif //_COLOR_H_
diff --git a/src/compass.cpp b/src/compass.cpp
new file mode 100644
index 0000000..55c8f9e
--- /dev/null
+++ b/src/compass.cpp
@@ -0,0 +1,165 @@
+// compass.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "compass.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CCompass::CCompass(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_dir = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CCompass::~CCompass()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CCompass::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CCompass::EventProcess(const Event &event)
+{
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CCompass::Draw()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2, p3, c, uv1, uv2;
+ D3DVECTOR n;
+ float dp;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ device = m_engine->RetD3DDevice();
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ p1.x = m_pos.x;
+ p1.y = m_pos.y;
+ p2.x = m_pos.x + m_dim.x;
+ p2.y = m_pos.y + m_dim.y;
+
+ c.x = (p1.x+p2.x)/2.0f;
+ c.y = (p1.y+p2.y)/2.0f; // centre
+
+ uv1.x = 64.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, uv2.x,uv2.y);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv2.x,uv1.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+ if ( m_state & STATE_ENABLE )
+ {
+ p1.x = c.x;
+ p1.y = c.y+m_dim.x*0.40f;
+ p1 = RotatePoint(c, m_dir, p1);
+ p1.x = c.x+(p1.x-c.x)*(m_dim.x/m_dim.y);
+
+ p2.x = c.x+m_dim.x*0.20f;
+ p2.y = c.y-m_dim.x*0.40f;
+ p2 = RotatePoint(c, m_dir, p2);
+ p2.x = c.x+(p2.x-c.x)*(m_dim.x/m_dim.y);
+
+ p3.x = c.x-m_dim.x*0.20f;
+ p3.y = c.y-m_dim.x*0.40f;
+ p3 = RotatePoint(c, m_dir, p3);
+ p3.x = c.x+(p3.x-c.x)*(m_dim.x/m_dim.y);
+
+ uv1.x = 96.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 104.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p3.x, p3.y, 0.0f), n, uv2.x,uv2.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX2, vertex, 3, NULL);
+ m_engine->AddStatisticTriangle(1);
+ }
+}
+
+
+// Gestion des directions de la boussole.
+
+void CCompass::SetDirection(float dir)
+{
+ m_dir = dir;
+}
+
+float CCompass::RetDirection()
+{
+ return m_dir;
+}
+
+
diff --git a/src/compass.h b/src/compass.h
new file mode 100644
index 0000000..46ed00d
--- /dev/null
+++ b/src/compass.h
@@ -0,0 +1,36 @@
+// compass.h
+
+#ifndef _COMPASS_H_
+#define _COMPASS_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CCompass : public CControl
+{
+public:
+ CCompass(CInstanceManager* iMan);
+ ~CCompass();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+ void SetDirection(float dir);
+ float RetDirection();
+
+protected:
+
+protected:
+ float m_dir;
+};
+
+
+#endif //_COMPASS_H_
diff --git a/src/control.cpp b/src/control.cpp
new file mode 100644
index 0000000..5e786cc
--- /dev/null
+++ b/src/control.cpp
@@ -0,0 +1,862 @@
+// control.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "restext.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "robotmain.h"
+#include "particule.h"
+#include "misc.h"
+#include "iman.h"
+#include "text.h"
+#include "sound.h"
+#include "control.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CControl::CControl(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ m_eventMsg = EVENT_NULL;
+ m_state = STATE_ENABLE|STATE_VISIBLE|STATE_GLINT;
+ m_fontSize = SMALLFONT;
+ m_fontStretch = NORMSTRETCH;
+ m_fontType = FONT_COLOBOT;
+ m_justif = 0;
+ m_name[0] = 0;
+ m_tooltip[0] = 0;
+ m_bFocus = FALSE;
+ m_bCapture = FALSE;
+
+ m_bGlint = FALSE;
+ m_glintCorner1 = FPOINT(0.0f, 0.0f);
+ m_glintCorner2 = FPOINT(0.0f, 0.0f);
+ m_glintProgress = 999.0f;
+ m_glintMouse = FPOINT(0.0f, 0.0f);
+}
+
+// Destructeur de l'objet.
+
+CControl::~CControl()
+{
+}
+
+
+// Crée un nouveau bouton.
+// pos: [0..1]
+
+BOOL CControl::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ char text[100];
+ char* p;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ m_pos = pos;
+ m_dim = dim;
+ m_icon = icon;
+ m_eventMsg = eventMsg;
+
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+m_dim.y;
+ GlintCreate(pos);
+
+ GetResource(RES_EVENT, m_eventMsg, text);
+ p = strchr(text, '\\');
+ if ( p == 0 )
+ {
+ if ( icon != -1 )
+ {
+ strcpy(m_tooltip, text);
+ }
+ }
+ else
+ {
+ strcpy(m_tooltip, p+1); // texte après "\\"
+ }
+
+ return TRUE;
+}
+
+
+void CControl::SetPos(FPOINT pos)
+{
+ m_pos = pos;
+
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+m_dim.y;
+ GlintCreate(pos);
+}
+
+FPOINT CControl::RetPos()
+{
+ return m_pos;
+}
+
+void CControl::SetDim(FPOINT dim)
+{
+ FPOINT pos;
+
+ m_dim = dim;
+
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+m_dim.y;
+ GlintCreate(pos);
+}
+
+FPOINT CControl::RetDim()
+{
+ return m_dim;
+}
+
+
+// Modifie un attribut d'état.
+
+BOOL CControl::SetState(int state, BOOL bState)
+{
+ if ( bState ) m_state |= state;
+ else m_state &= ~state;
+ return TRUE;
+}
+
+// Met un attribut d'état.
+
+BOOL CControl::SetState(int state)
+{
+ m_state |= state;
+ return TRUE;
+}
+
+// Enlève un attribut d'état.
+
+BOOL CControl::ClearState(int state)
+{
+ m_state &= ~state;
+ return TRUE;
+}
+
+// Teste un attribut d'état.
+
+BOOL CControl::TestState(int state)
+{
+ return (m_state & state) ? TRUE:FALSE;
+}
+
+// Retourne tous les attributs d'état.
+
+int CControl::RetState()
+{
+ return m_state;
+}
+
+
+// Gestion de l'icône.
+
+void CControl::SetIcon(int icon)
+{
+ m_icon = icon;
+}
+
+int CControl::RetIcon()
+{
+ return m_icon;
+}
+
+
+// Gestion du nom du bouton.
+
+void CControl::SetName(char* name, BOOL bTooltip)
+{
+ char* p;
+
+ if ( bTooltip )
+ {
+ p = strchr(name, '\\');
+ if ( p == 0 )
+ {
+ strncpy(m_name, name, 100);
+ m_name[100-1] = 0;
+ }
+ else
+ {
+ char buffer[100];
+
+ strncpy(m_tooltip, p+1, 100); // texte après "\\"
+ m_tooltip[100-1] = 0;
+
+ strncpy(buffer, name, 100);
+ buffer[100-1] = 0;
+ p = strchr(buffer, '\\');
+ if ( p != 0 ) *p = 0;
+ strncpy(m_name, buffer, 100);
+ m_name[100-1] = 0;
+ }
+ }
+ else
+ {
+ strncpy(m_name, name, 100);
+ m_name[100-1] = 0;
+ }
+}
+
+char* CControl::RetName()
+{
+ return m_name;
+}
+
+
+// Gestion du mode de justification (-1,0,1).
+
+void CControl::SetJustif(int mode)
+{
+ m_justif = mode;
+}
+
+int CControl::RetJustif()
+{
+ return m_justif;
+}
+
+
+// Gestion de la taille de la fonte.
+
+void CControl::SetFontSize(float size)
+{
+ m_fontSize = size;
+}
+
+float CControl::RetFontSize()
+{
+ return m_fontSize;
+}
+
+
+// Gestion du stretch de la fonte.
+
+void CControl::SetFontStretch(float stretch)
+{
+ m_fontStretch = stretch;
+}
+
+float CControl::RetFontStretch()
+{
+ return m_fontStretch;
+}
+
+
+// Choix de la fonte.
+
+void CControl::SetFontType(FontType font)
+{
+ m_fontType = font;
+}
+
+FontType CControl::RetFontType()
+{
+ return m_fontType;
+}
+
+
+// Spécifie le tooltip.
+
+BOOL CControl::SetTooltip(char* name)
+{
+ strcpy(m_tooltip, name);
+ return TRUE;
+}
+
+BOOL CControl::GetTooltip(FPOINT pos, char* name)
+{
+ if ( m_tooltip[0] == 0 ) return FALSE;
+ if ( (m_state & STATE_VISIBLE) == 0 ) return FALSE;
+ if ( (m_state & STATE_ENABLE) == 0 ) return FALSE;
+ if ( m_state & STATE_DEAD ) return FALSE;
+ if ( !Detect(pos) ) return FALSE;
+
+ strcpy(name, m_tooltip);
+ return TRUE;
+}
+
+
+// Gestion de qui a la focus.
+
+void CControl::SetFocus(BOOL bFocus)
+{
+ m_bFocus = bFocus;
+}
+
+BOOL CControl::RetFocus()
+{
+ return m_bFocus;
+}
+
+
+// Retourne l'événement associé au contrôle.
+
+EventMsg CControl::RetEventMsg()
+{
+ return m_eventMsg;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CControl::EventProcess(const Event &event)
+{
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ if ( event.event == EVENT_FRAME && m_bGlint )
+ {
+ GlintFrame(event);
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ m_glintMouse = event.pos;
+
+ if ( Detect(event.pos) )
+ {
+ if ( (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE ) )
+ {
+ m_engine->SetMouseType(D3DMOUSEHAND);
+ }
+ SetState(STATE_HILIGHT);
+ }
+ else
+ {
+ ClearState(STATE_HILIGHT);
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( Detect(event.pos) )
+ {
+ m_bCapture = TRUE;
+ SetState(STATE_PRESS);
+ }
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && m_bCapture )
+ {
+ if ( Detect(event.pos) )
+ {
+ SetState(STATE_PRESS);
+ }
+ else
+ {
+ ClearState(STATE_PRESS);
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONUP && m_bCapture )
+ {
+ m_bCapture = FALSE;
+ ClearState(STATE_PRESS);
+ }
+
+ return TRUE;
+}
+
+
+// Supprime le reflet.
+
+void CControl::GlintDelete()
+{
+ m_bGlint = FALSE;
+}
+
+// Crée un reflet pour ce bouton.
+
+void CControl::GlintCreate(FPOINT ref, BOOL bLeft, BOOL bUp)
+{
+ float offset;
+
+ offset = 8.0f/640.0f;
+ if ( offset > m_dim.x/4.0f) offset = m_dim.x/4.0f;
+
+ if ( bLeft )
+ {
+ m_glintCorner1.x = ref.x;
+ m_glintCorner2.x = ref.x+offset;
+ }
+ else
+ {
+ m_glintCorner1.x = ref.x-offset;
+ m_glintCorner2.x = ref.x;
+ }
+
+ offset = 8.0f/480.0f;
+ if ( offset > m_dim.y/4.0f) offset = m_dim.y/4.0f;
+
+ if ( bUp )
+ {
+ m_glintCorner1.y = ref.y-offset;
+ m_glintCorner2.y = ref.y;
+ }
+ else
+ {
+ m_glintCorner1.y = ref.y;
+ m_glintCorner2.y = ref.y+offset;
+ }
+
+ m_bGlint = TRUE;
+}
+
+// Gestion du reflet.
+
+void CControl::GlintFrame(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ if ( (m_state & STATE_GLINT ) == 0 ||
+ (m_state & STATE_ENABLE ) == 0 ||
+ (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( !m_main->RetGlint() ) return;
+
+ m_glintProgress += event.rTime;
+
+ if ( m_glintProgress >= 2.0f && Detect(m_glintMouse) )
+ {
+ pos.x = m_glintCorner1.x + (m_glintCorner2.x-m_glintCorner1.x)*Rand();
+ pos.y = m_glintCorner1.y + (m_glintCorner2.y-m_glintCorner1.y)*Rand();
+ pos.z = 0.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = ((15.0f+Rand()*15.0f)/640.0f);
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTICONTROL,
+ 1.0f, 0.0f, 0.0f, SH_INTERFACE);
+
+ m_glintProgress = 0.0f;
+ }
+}
+
+
+// Dessine le bouton.
+
+void CControl::Draw()
+{
+ FPOINT pos;
+ float zoomExt, zoomInt;
+ int icon;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ zoomExt = 1.00f;
+ zoomInt = 0.95f;
+
+ if ( m_icon >= 128 )
+ {
+ zoomInt = 0.80f;
+ }
+
+ icon = 2;
+ if ( m_state & STATE_CARD )
+ {
+ icon = 26;
+ }
+ if ( m_state & STATE_DEFAULT )
+ {
+ DrawPart(23, 1.3f, 0.0f);
+
+ zoomExt *= 1.15f;
+ zoomInt *= 1.15f;
+ }
+ if ( m_state & STATE_HILIGHT )
+ {
+ icon = 1;
+ }
+ if ( m_state & STATE_CHECK )
+ {
+ if ( m_state & STATE_CARD )
+ {
+ icon = 27;
+ }
+ else
+ {
+ icon = 0;
+ }
+ }
+ if ( m_state & STATE_PRESS )
+ {
+ icon = 3;
+ zoomInt *= 0.9f;
+ }
+ if ( (m_state & STATE_ENABLE) == 0 )
+ {
+ icon = 7;
+ }
+ if ( m_state & STATE_DEAD )
+ {
+ icon = 17;
+ }
+
+ if ( m_state & STATE_OKAY )
+ {
+ m_engine->SetTexture("button3.tga");
+ icon = 3; // jaune pressé avec point vert
+ }
+
+ if ( m_name[0] == 0 ) // bouton sans nom ?
+ {
+//? DrawPart(icon, zoomExt, 0.0f);
+ DrawPart(icon, zoomExt, 8.0f/256.0f);
+
+ if ( m_state & STATE_DEAD ) return;
+
+ icon = m_icon;
+ if ( icon >= 192 )
+ {
+ icon -= 192;
+#if _POLISH
+ m_engine->SetTexture("textp.tga");
+#else
+ m_engine->SetTexture("text.tga");
+#endif
+ m_engine->SetState(D3DSTATETTw);
+ }
+ else if ( icon >= 128 )
+ {
+ icon -= 128;
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATETTw);
+ }
+ else if ( icon >= 64 )
+ {
+ icon -= 64;
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ }
+ else
+ {
+ m_engine->SetState(D3DSTATETTw);
+ }
+ if ( icon != -1 )
+ {
+ DrawPart(icon, zoomInt, 0.0f);
+ }
+ }
+ else // bouton avec nom ?
+ {
+ DrawPart(icon, 1.0f, 8.0f/256.0f);
+
+ if ( m_state & STATE_DEAD ) return;
+
+ if ( m_justif < 0 )
+ {
+ pos.x = m_pos.x+m_dim.x-m_dim.y*0.5f;
+ pos.y = m_pos.y+m_dim.y*0.5f;
+ pos.y -= m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2;
+ m_engine->RetText()->DrawText(m_name, pos, m_dim.x, m_justif, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ else if ( m_justif > 0 )
+ {
+ pos.x = m_pos.x+m_dim.y*0.5f;
+ pos.y = m_pos.y+m_dim.y*0.5f;
+ pos.y -= m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2.0f;
+ m_engine->RetText()->DrawText(m_name, pos, m_dim.x, m_justif, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ else
+ {
+ pos.x = m_pos.x+m_dim.x*0.5f;
+ pos.y = m_pos.y+m_dim.y*0.5f;
+ pos.y -= m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2.0f;
+ m_engine->RetText()->DrawText(m_name, pos, m_dim.x, m_justif, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ }
+}
+
+// Dessine le tableau des vertex.
+
+void CControl::DrawPart(int icon, float zoom, float ex)
+{
+ FPOINT p1, p2, c, uv1, uv2;
+ float dp;
+
+ p1.x = m_pos.x;
+ p1.y = m_pos.y;
+ p2.x = m_pos.x + m_dim.x;
+ p2.y = m_pos.y + m_dim.y;
+
+ if ( (m_state & STATE_CARD ) &&
+ (m_state & STATE_CHECK) )
+ {
+ p2.y += (2.0f/480.0f); // un poil plus haut
+ }
+
+ c.x = (p1.x+p2.x)/2.0f;
+ c.y = (p1.y+p2.y)/2.0f; // centre
+
+ p1.x = (p1.x-c.x)*zoom + c.x;
+ p1.y = (p1.y-c.y)*zoom + c.y;
+ p2.x = (p2.x-c.x)*zoom + c.x;
+ p2.y = (p2.y-c.y)*zoom + c.y;
+
+ p2.x -= p1.x;
+ p2.y -= p1.y;
+
+ uv1.x = (32.0f/256.0f)*(icon%8);
+ uv1.y = (32.0f/256.0f)*(icon/8); // uv texture
+ uv2.x = (32.0f/256.0f)+uv1.x;
+ uv2.y = (32.0f/256.0f)+uv1.y;
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(p1, p2, uv1, uv2, ex);
+}
+
+// Dessine une icône rectangulaire composée de 1 (si ex=0)
+// ou 3 morceaux.
+
+void CControl::DrawIcon(FPOINT pos, FPOINT dim, FPOINT uv1, FPOINT uv2,
+ float ex)
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[8]; // 6 triangles
+ FPOINT p1, p2, p3, p4;
+ D3DVECTOR n;
+
+ device = m_engine->RetD3DDevice();
+
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + dim.x;
+ p2.y = pos.y + dim.y;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ if ( ex == 0.0f ) // un seul morceau ?
+ {
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, uv2.x,uv2.y);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv2.x,uv1.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+ }
+ else // 3 morceaux ?
+ {
+ if ( dim.x >= dim.y )
+ {
+ p3.x = p1.x + ex*dim.y/(uv2.y-uv1.y);
+ p4.x = p2.x - ex*dim.y/(uv2.y-uv1.y);
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x, uv2.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, uv1.x, uv1.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p3.x, p1.y, 0.0f), n, uv1.x+ex,uv2.y);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p3.x, p2.y, 0.0f), n, uv1.x+ex,uv1.y);
+ vertex[4] = D3DVERTEX2(D3DVECTOR(p4.x, p1.y, 0.0f), n, uv2.x-ex,uv2.y);
+ vertex[5] = D3DVERTEX2(D3DVECTOR(p4.x, p2.y, 0.0f), n, uv2.x-ex,uv1.y);
+ vertex[6] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, uv2.x, uv2.y);
+ vertex[7] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv2.x, uv1.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 8, NULL);
+ m_engine->AddStatisticTriangle(6);
+ }
+ else
+ {
+ p3.y = p1.y + ex*dim.x/(uv2.x-uv1.x);
+ p4.y = p2.y - ex*dim.x/(uv2.x-uv1.x);
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, uv2.x,uv2.y );
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv2.y );
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p3.y, 0.0f), n, uv2.x,uv2.y-ex);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p1.x, p3.y, 0.0f), n, uv1.x,uv2.y-ex);
+ vertex[4] = D3DVERTEX2(D3DVECTOR(p2.x, p4.y, 0.0f), n, uv2.x,uv1.y+ex);
+ vertex[5] = D3DVERTEX2(D3DVECTOR(p1.x, p4.y, 0.0f), n, uv1.x,uv1.y+ex);
+ vertex[6] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv2.x,uv1.y );
+ vertex[7] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, uv1.x,uv1.y );
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 8, NULL);
+ m_engine->AddStatisticTriangle(6);
+ }
+ }
+}
+
+// Dessine une icône rectangulaire composée de 9 morceaux.
+
+void CControl::DrawIcon(FPOINT pos, FPOINT dim, FPOINT uv1, FPOINT uv2,
+ FPOINT corner, float ex)
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[8]; // 6 triangles
+ FPOINT p1, p2, p3, p4;
+ D3DVECTOR n;
+
+ device = m_engine->RetD3DDevice();
+
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + dim.x;
+ p2.y = pos.y + dim.y;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ if ( corner.x > dim.x/2.0f ) corner.x = dim.x/2.0f;
+ if ( corner.y > dim.y/2.0f ) corner.y = dim.y/2.0f;
+
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + dim.x;
+ p2.y = pos.y + dim.y;
+ p3.x = p1.x + corner.x;
+ p3.y = p1.y + corner.y;
+ p4.x = p2.x - corner.x;
+ p4.y = p2.y - corner.y;
+
+ // Bande horizontale inférieure.
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x, uv2.y );
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p3.y, 0.0f), n, uv1.x, uv2.y-ex);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p3.x, p1.y, 0.0f), n, uv1.x+ex,uv2.y );
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p3.x, p3.y, 0.0f), n, uv1.x+ex,uv2.y-ex);
+ vertex[4] = D3DVERTEX2(D3DVECTOR(p4.x, p1.y, 0.0f), n, uv2.x-ex,uv2.y );
+ vertex[5] = D3DVERTEX2(D3DVECTOR(p4.x, p3.y, 0.0f), n, uv2.x-ex,uv2.y-ex);
+ vertex[6] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, uv2.x, uv2.y );
+ vertex[7] = D3DVERTEX2(D3DVECTOR(p2.x, p3.y, 0.0f), n, uv2.x, uv2.y-ex);
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 8, NULL);
+ m_engine->AddStatisticTriangle(6);
+
+ // Bande horizontale médiane.
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p3.y, 0.0f), n, uv1.x, uv2.y-ex);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p4.y, 0.0f), n, uv1.x, uv1.y+ex);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p3.x, p3.y, 0.0f), n, uv1.x+ex,uv2.y-ex);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p3.x, p4.y, 0.0f), n, uv1.x+ex,uv1.y+ex);
+ vertex[4] = D3DVERTEX2(D3DVECTOR(p4.x, p3.y, 0.0f), n, uv2.x-ex,uv2.y-ex);
+ vertex[5] = D3DVERTEX2(D3DVECTOR(p4.x, p4.y, 0.0f), n, uv2.x-ex,uv1.y+ex);
+ vertex[6] = D3DVERTEX2(D3DVECTOR(p2.x, p3.y, 0.0f), n, uv2.x, uv2.y-ex);
+ vertex[7] = D3DVERTEX2(D3DVECTOR(p2.x, p4.y, 0.0f), n, uv2.x, uv1.y+ex);
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 8, NULL);
+ m_engine->AddStatisticTriangle(6);
+
+ // Bande horizontale supérieure.
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p4.y, 0.0f), n, uv1.x, uv1.y+ex);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, uv1.x, uv1.y );
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p3.x, p4.y, 0.0f), n, uv1.x+ex,uv1.y+ex);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p3.x, p2.y, 0.0f), n, uv1.x+ex,uv1.y );
+ vertex[4] = D3DVERTEX2(D3DVECTOR(p4.x, p4.y, 0.0f), n, uv2.x-ex,uv1.y+ex);
+ vertex[5] = D3DVERTEX2(D3DVECTOR(p4.x, p2.y, 0.0f), n, uv2.x-ex,uv1.y );
+ vertex[6] = D3DVERTEX2(D3DVECTOR(p2.x, p4.y, 0.0f), n, uv2.x, uv1.y+ex);
+ vertex[7] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv2.x, uv1.y );
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 8, NULL);
+ m_engine->AddStatisticTriangle(6);
+}
+
+// Dessine les hachures autour d'un bouton.
+
+void CControl::DrawWarning(FPOINT pos, FPOINT dim)
+{
+ FPOINT uv1, uv2;
+ float dp;
+
+ dp = 0.5f/256.0f;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ uv1.x = 64.0f/256.0f;
+ uv1.y = 208.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ if ( dim.x < dim.y*4.0f )
+ {
+ dim.y /= 2.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ pos.y += dim.y;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+ else
+ {
+ dim.x /= 2.0f;
+ dim.y /= 2.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ pos.x += dim.x;
+ DrawIcon(pos, dim, uv1, uv2);
+ pos.x -= dim.x;
+ pos.y += dim.y;
+ DrawIcon(pos, dim, uv1, uv2);
+ pos.x += dim.x;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+}
+
+// Dessine l'ombre sous un bouton.
+
+void CControl::DrawShadow(FPOINT pos, FPOINT dim, float deep)
+{
+ FPOINT uv1, uv2, corner;
+ float dp;
+
+ dp = 0.5f/256.0f;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+
+ pos.x += deep*0.010f*0.75f;
+ pos.y -= deep*0.015f;
+ dim.x += deep*0.005f*0.75f;
+ dim.y += deep*0.005f;
+
+ uv1.x = 192.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ corner.x = 10.0f/640.0f;
+ corner.y = 10.0f/480.0f;
+
+ DrawIcon(pos, dim, uv1, uv2, corner, 6.0f/256.0f);
+}
+
+
+// Détecte si une position est dans le bouton.
+
+BOOL CControl::Detect(FPOINT pos)
+{
+ return ( pos.x >= m_pos.x &&
+ pos.x <= m_pos.x+m_dim.x &&
+ pos.y >= m_pos.y &&
+ pos.y <= m_pos.y+m_dim.y );
+}
+
+
diff --git a/src/control.h b/src/control.h
new file mode 100644
index 0000000..d40b3a1
--- /dev/null
+++ b/src/control.h
@@ -0,0 +1,118 @@
+// control.h
+
+#ifndef _CONTROL_H_
+#define _CONTROL_H_
+
+
+class CInstanceManager;
+class CEvent;
+class CD3DEngine;
+class CRobotMain;
+class CParticule;
+class CSound;
+
+enum FontType;
+
+
+#define STATE_ENABLE (1<<0) // actif
+#define STATE_CHECK (1<<1) // enfoncé
+#define STATE_HILIGHT (1<<2) // survolé par la souris
+#define STATE_PRESS (1<<3) // pressé par la souris
+#define STATE_VISIBLE (1<<4) // visible
+#define STATE_DEAD (1<<5) // inaccessible (x)
+#define STATE_DEFAULT (1<<6) // actionné par RETURN
+#define STATE_OKAY (1<<7) // point vert en bas à droite
+#define STATE_SHADOW (1<<8) // ombre
+#define STATE_GLINT (1<<9) // reflet dynamique
+#define STATE_CARD (1<<10) // onglet
+#define STATE_EXTEND (1<<11) // mode étendu
+#define STATE_SIMPLY (1<<12) // sans ornements
+#define STATE_FRAME (1<<13) // cadre de mise en évidence
+#define STATE_WARNING (1<<14) // cadre hachuré jaune/noir
+#define STATE_VALUE (1<<15) // affiche la valeur
+#define STATE_RUN (1<<16) // programme en cours
+
+
+
+class CControl
+{
+public:
+ CControl(CInstanceManager* iMan);
+ virtual ~CControl();
+
+ virtual BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ virtual BOOL EventProcess(const Event &event);
+
+ virtual void SetPos(FPOINT pos);
+ virtual FPOINT RetPos();
+ virtual void SetDim(FPOINT dim);
+ virtual FPOINT RetDim();
+ virtual BOOL SetState(int state, BOOL bState);
+ virtual BOOL SetState(int state);
+ virtual BOOL ClearState(int state);
+ virtual BOOL TestState(int state);
+ virtual int RetState();
+ virtual void SetIcon(int icon);
+ virtual int RetIcon();
+ virtual void SetName(char* name, BOOL bTooltip=TRUE);
+ virtual char* RetName();
+ virtual void SetJustif(int mode);
+ virtual int RetJustif();
+ virtual void SetFontSize(float size);
+ virtual float RetFontSize();
+ virtual void SetFontStretch(float stretch);
+ virtual float RetFontStretch();
+ virtual void SetFontType(FontType font);
+ virtual FontType RetFontType();
+ virtual BOOL SetTooltip(char* name);
+ virtual BOOL GetTooltip(FPOINT pos, char* name);
+ virtual void SetFocus(BOOL bFocus);
+ virtual BOOL RetFocus();
+
+ virtual EventMsg RetEventMsg();
+
+ virtual void Draw();
+
+protected:
+ void GlintDelete();
+ void GlintCreate(FPOINT ref, BOOL bLeft=TRUE, BOOL bUp=TRUE);
+ void GlintFrame(const Event &event);
+ void DrawPart(int icon, float zoom, float ex);
+ void DrawIcon(FPOINT pos, FPOINT dim, FPOINT uv1, FPOINT uv2, float ex=0.0f);
+ void DrawIcon(FPOINT pos, FPOINT dim, FPOINT uv1, FPOINT uv2, FPOINT corner, float ex);
+ void DrawWarning(FPOINT pos, FPOINT dim);
+ void DrawShadow(FPOINT pos, FPOINT dim, float deep=1.0f);
+ virtual BOOL Detect(FPOINT pos);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CEvent* m_event;
+ CRobotMain* m_main;
+ CParticule* m_particule;
+ CSound* m_sound;
+
+ FPOINT m_pos; // coin sup/gauche
+ FPOINT m_dim; // dimensions
+ int m_icon;
+ EventMsg m_eventMsg; // message à envoyer si clic
+ int m_state; // états (STATE_*)
+ float m_fontSize; // taille du nom du bouton
+ float m_fontStretch; // stretch de la fonte
+ FontType m_fontType; // type de la fonte
+ int m_justif; // type de justification (-1,0,1)
+ char m_name[100]; // nom du bouton
+ char m_tooltip[100]; // nom du tooltip
+ BOOL m_bFocus;
+ BOOL m_bCapture;
+
+ BOOL m_bGlint;
+ FPOINT m_glintCorner1;
+ FPOINT m_glintCorner2;
+ float m_glintProgress;
+ FPOINT m_glintMouse;
+};
+
+
+#endif //_CONTROL_H_
diff --git a/src/cur00001.cur b/src/cur00001.cur
new file mode 100644
index 0000000..e19873e
--- /dev/null
+++ b/src/cur00001.cur
Binary files differ
diff --git a/src/cur00002.cur b/src/cur00002.cur
new file mode 100644
index 0000000..2376e8e
--- /dev/null
+++ b/src/cur00002.cur
Binary files differ
diff --git a/src/cur00003.cur b/src/cur00003.cur
new file mode 100644
index 0000000..8a4745a
--- /dev/null
+++ b/src/cur00003.cur
Binary files differ
diff --git a/src/cursor1.cur b/src/cursor1.cur
new file mode 100644
index 0000000..1f51251
--- /dev/null
+++ b/src/cursor1.cur
Binary files differ
diff --git a/src/cursorha.cur b/src/cursorha.cur
new file mode 100644
index 0000000..7b80435
--- /dev/null
+++ b/src/cursorha.cur
Binary files differ
diff --git a/src/cursorsc.cur b/src/cursorsc.cur
new file mode 100644
index 0000000..52004ac
--- /dev/null
+++ b/src/cursorsc.cur
Binary files differ
diff --git a/src/d3dapp.cpp b/src/d3dapp.cpp
new file mode 100644
index 0000000..7ca6d5a
--- /dev/null
+++ b/src/d3dapp.cpp
@@ -0,0 +1,2433 @@
+// D3DApp.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <pbt.h>
+#include <mmsystem.h>
+#include <stdio.h>
+#include <direct.h>
+#include <tchar.h>
+#include <zmouse.h>
+#include <dinput.h>
+
+#include "struct.h"
+#include "D3DTextr.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "event.h"
+#include "profile.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "joystick.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "D3DApp.h"
+
+
+
+
+#define AUDIO_TRACK 13 // nb total de pistes audio sur le CD
+#define MAX_STEP 0.2f // temps maximum pour un step
+
+#define WINDOW_DX (640+6) // dimensions en mode fenêtré
+#define WINDOW_DY (480+25)
+
+#define USE_THREAD FALSE // TRUE ne fonctionne pas !
+#define TIME_THREAD 0.02f
+
+
+
+
+// Limite le débattement des commandes clavier & joystick.
+
+float AxeLimit(float value)
+{
+ if ( value < -1.0f ) value = -1.0f;
+ if ( value > 1.0f ) value = 1.0f;
+ return value;
+}
+
+
+// Entry point to the program. Initializes everything, and goes into a
+// message-processing loop. Idle time is used to render the scene.
+
+INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
+{
+ Error err;
+ char string[100];
+
+ CD3DApplication d3dApp; // unique instance de l'application
+
+ err = d3dApp.CheckMistery(strCmdLine);
+ if ( err != ERR_OK )
+ {
+ GetResource(RES_ERR, err, string);
+#if _NEWLOOK
+ MessageBox( NULL, string, _T("CeeBot"), MB_ICONERROR|MB_OK );
+#else
+ MessageBox( NULL, string, _T("COLOBOT"), MB_ICONERROR|MB_OK );
+#endif
+ return 0;
+ }
+
+ if ( FAILED(d3dApp.Create(hInst, strCmdLine)) )
+ {
+ return 0;
+ }
+
+ return d3dApp.Run(); // exécution du tout
+}
+
+
+// Internal function prototypes and variables.
+
+enum APPMSGTYPE { MSG_NONE, MSGERR_APPMUSTEXIT, MSGWARN_SWITCHEDTOSOFTWARE };
+
+static INT CALLBACK AboutProc( HWND, UINT, WPARAM, LPARAM );
+static LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
+
+static CD3DApplication* g_pD3DApp;
+
+
+
+// Constructor.
+
+CD3DApplication::CD3DApplication()
+{
+ int i;
+
+ m_iMan = new(CInstanceManager);
+ m_event = new CEvent(m_iMan);
+
+ m_pD3DEngine = 0;
+ m_pRobotMain = 0;
+ m_pSound = 0;
+ m_pFramework = 0;
+ m_instance = 0;
+ m_hWnd = 0;
+ m_pDD = 0;
+ m_pD3D = 0;
+ m_pD3DDevice = 0;
+
+ m_CDpath[0] = 0;
+
+ m_pddsRenderTarget = 0;
+ m_pddsDepthBuffer = 0;
+
+ m_keyState = 0;
+ m_axeKey = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_axeJoy = D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ m_vidMemTotal = 0;
+ m_bActive = FALSE;
+ m_bActivateApp = FALSE;
+ m_bReady = FALSE;
+ m_bJoystick = FALSE;
+ m_aTime = 0.0f;
+
+ for ( i=0 ; i<32 ; i++ )
+ {
+ m_bJoyButton[i] = FALSE;
+ }
+
+#if _NEWLOOK
+ m_strWindowTitle = _T("CeeBot");
+#else
+ m_strWindowTitle = _T("COLOBOT");
+#endif
+ m_bAppUseZBuffer = TRUE;
+ m_bAppUseStereo = TRUE;
+ m_bShowStats = FALSE;
+ m_bDebugMode = FALSE;
+ m_bAudioState = TRUE;
+ m_bAudioTrack = TRUE;
+ m_bNiceMouse = FALSE;
+ m_bSetupMode = TRUE;
+ m_fnConfirmDevice = 0;
+
+ ResetKey();
+
+ g_pD3DApp = this;
+
+ // Demande l'événement envoyé par les souris Logitech.
+ m_mshMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL);
+
+ _mkdir("files\\");
+}
+
+
+// Destructor.
+
+CD3DApplication::~CD3DApplication()
+{
+ delete m_iMan;
+}
+
+
+
+// Retourne le chemin d'accès du CD.
+
+char* CD3DApplication::RetCDpath()
+{
+ return m_CDpath;
+}
+
+// Lit les informations dans la base de registre.
+
+Error CD3DApplication::RegQuery()
+{
+ FILE* file = NULL;
+ HKEY key;
+ LONG i;
+ DWORD type, len;
+ char filename[100];
+
+#if _NEWLOOK
+ #if _TEEN
+ i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\CeeBot-Teen\\Setup",
+ #else
+ i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\CeeBot-A\\Setup",
+ #endif
+#else
+ i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Epsitec\\Colobot\\Setup",
+#endif
+ 0, KEY_READ, &key);
+ if ( i != ERROR_SUCCESS ) return ERR_INSTALL;
+
+ type = REG_SZ;
+ len = sizeof(m_CDpath);
+ i = RegQueryValueEx(key, "CDpath", NULL, &type, (LPBYTE)m_CDpath, &len);
+ if ( i != ERROR_SUCCESS || type != REG_SZ ) return ERR_INSTALL;
+
+ filename[0] = m_CDpath[0];
+ filename[1] = ':';
+ filename[2] = '\\';
+ filename[3] = 0;
+ i = GetDriveType(filename);
+ if ( i != DRIVE_CDROM ) return ERR_NOCD;
+
+ strcat(filename, "install.ini");
+ file = fopen(filename, "rb"); // fichier install.ini inexistant ?
+ if ( file == NULL ) return ERR_NOCD;
+ fclose(file);
+
+ return ERR_OK;
+}
+
+// Vérifie la présence des pistes audio sur le CD.
+
+Error CD3DApplication::AudioQuery()
+{
+ MCI_OPEN_PARMS mciOpenParms;
+ MCI_STATUS_PARMS mciStatusParms;
+ DWORD dwReturn;
+ UINT deviceID;
+ char device[10];
+
+ // Open the device by specifying the device and filename.
+ // MCI will attempt to choose the MIDI mapper as the output port.
+ memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS));
+ mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
+ if ( m_CDpath[0] == 0 )
+ {
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
+ (DWORD)(LPVOID)&mciOpenParms);
+ }
+ else
+ {
+ device[0] = m_CDpath[0];
+ device[1] = ':';
+ device[2] = 0;
+ mciOpenParms.lpstrElementName = device;
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT,
+ (DWORD)(LPVOID)&mciOpenParms);
+ }
+ if ( dwReturn != 0 )
+ {
+ return ERR_NOCD;
+ }
+
+ // The device opened successfully; get the device ID.
+ deviceID = mciOpenParms.wDeviceID;
+
+ memset(&mciStatusParms, 0, sizeof(MCI_STATUS_PARMS));
+ mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
+ dwReturn = mciSendCommand(deviceID,
+ MCI_STATUS,
+ MCI_WAIT|MCI_STATUS_ITEM,
+ (DWORD)&mciStatusParms);
+ if ( dwReturn != 0 )
+ {
+ mciSendCommand(deviceID, MCI_CLOSE, 0, NULL);
+ return ERR_NOCD;
+ }
+
+ if ( mciStatusParms.dwReturn != AUDIO_TRACK )
+ {
+ mciSendCommand(deviceID, MCI_CLOSE, 0, NULL);
+ return ERR_NOCD;
+ }
+
+ mciSendCommand(deviceID, MCI_CLOSE, 0, NULL);
+ return ERR_OK;
+}
+
+// Vérifie la présence de la clé.
+
+Error CD3DApplication::CheckMistery(char *strCmdLine)
+{
+ if ( strstr(strCmdLine, "-debug") != 0 )
+ {
+ m_bShowStats = TRUE;
+ SetDebugMode(TRUE);
+ }
+
+ if ( strstr(strCmdLine, "-audiostate") != 0 )
+ {
+ m_bAudioState = FALSE;
+ }
+
+ if ( strstr(strCmdLine, "-audiotrack") != 0 )
+ {
+ m_bAudioTrack = FALSE;
+ }
+
+ m_CDpath[0] = 0;
+#if _FULL
+ if ( strstr(strCmdLine, "-nocd") == 0 && !m_bDebugMode )
+ {
+ Error err;
+
+ err = RegQuery();
+ if ( err != ERR_OK ) return err;
+
+ //?err = AudioQuery();
+ //?if ( err != ERR_OK ) return err;
+ }
+#endif
+#if _SCHOOL & _EDU
+ if ( strstr(strCmdLine, "-nosetup") != 0 )
+ {
+ m_bSetupMode = FALSE;
+ }
+ m_bAudioTrack = FALSE;
+#endif
+#if _SCHOOL & _PERSO
+ Error err = RegQuery();
+ if ( err != ERR_OK ) return err;
+ m_bAudioTrack = FALSE;
+#endif
+#if _SCHOOL & _CEEBOTDEMO
+ m_bAudioTrack = FALSE;
+#endif
+#if _NET
+ m_bAudioTrack = FALSE;
+#endif
+#if _DEMO
+ m_bAudioTrack = FALSE;
+#endif
+
+ return ERR_OK;
+}
+
+
+// Retourne la quantité totale de mémoire vidéo pour les textures.
+
+int CD3DApplication::GetVidMemTotal()
+{
+ return m_vidMemTotal;
+}
+
+BOOL CD3DApplication::IsVideo8MB()
+{
+ if ( m_vidMemTotal == 0 ) return FALSE;
+ return (m_vidMemTotal <= 8388608L); // 8 Mb ou moins (2^23) ?
+}
+
+BOOL CD3DApplication::IsVideo32MB()
+{
+ if ( m_vidMemTotal == 0 ) return FALSE;
+ return (m_vidMemTotal > 16777216L); // plus de 16 Mb (2^24) ?
+}
+
+
+void CD3DApplication::SetShowStat(BOOL bShow)
+{
+ m_bShowStats = bShow;
+}
+
+BOOL CD3DApplication::RetShowStat()
+{
+ return m_bShowStats;
+}
+
+
+void CD3DApplication::SetDebugMode(BOOL bMode)
+{
+ m_bDebugMode = bMode;
+ D3DTextr_SetDebugMode(m_bDebugMode);
+}
+
+BOOL CD3DApplication::RetDebugMode()
+{
+ return m_bDebugMode;
+}
+
+BOOL CD3DApplication::RetSetupMode()
+{
+ return m_bSetupMode;
+}
+
+
+
+
+// Processus fils de gestion du temps.
+
+DWORD WINAPI ThreadRoutine(LPVOID)
+{
+ Event event;
+ float time;
+ int ms, start, end, delay;
+
+ ms = (int)(TIME_THREAD*1000.0f);
+ time = 0.0f;
+ while ( TRUE )
+ {
+ start = timeGetTime();
+
+ g_pD3DApp->m_pD3DEngine->FrameMove(TIME_THREAD);
+
+ ZeroMemory(&event, sizeof(Event));
+ event.event = EVENT_FRAME;
+ event.rTime = TIME_THREAD;
+ event.axeX = AxeLimit(g_pD3DApp->m_axeKey.x + g_pD3DApp->m_axeJoy.x);
+ event.axeY = AxeLimit(g_pD3DApp->m_axeKey.y + g_pD3DApp->m_axeJoy.y);
+ event.axeZ = AxeLimit(g_pD3DApp->m_axeKey.z + g_pD3DApp->m_axeJoy.z);
+ event.keyState = g_pD3DApp->m_keyState;
+
+ if ( g_pD3DApp->m_pRobotMain != 0 )
+ {
+ g_pD3DApp->m_pRobotMain->EventProcess(event);
+ }
+
+ end = timeGetTime();
+
+ delay = ms-(end-start);
+ if ( delay > 0 )
+ {
+ Sleep(delay); // attend 20ms-used
+ }
+ time += TIME_THREAD;
+ }
+ return 0;
+}
+
+
+// Called during device intialization, this code checks the device
+// for some minimum set of capabilities.
+
+HRESULT CD3DApplication::ConfirmDevice( DDCAPS* pddDriverCaps,
+ D3DDEVICEDESC7* pd3dDeviceDesc )
+{
+//? if( pd3dDeviceDesc->wMaxVertexBlendMatrices < 2 )
+//? return E_FAIL;
+
+ return S_OK;
+}
+
+// Create the application.
+
+HRESULT CD3DApplication::Create( HINSTANCE hInst, TCHAR* strCmdLine )
+{
+ HRESULT hr;
+ char deviceName[100];
+ char modeName[100];
+ int iValue;
+ DWORD style;
+ BOOL bFull, b3D;
+
+ m_instance = hInst;
+
+ InitCurrentDirectory();
+
+ // Enumerate available D3D devices. The callback is used so the app can
+ // confirm/reject each enumerated device depending on its capabilities.
+ if( FAILED( hr = D3DEnum_EnumerateDevices( m_fnConfirmDevice ) ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ return hr;
+ }
+
+ if( FAILED( hr = D3DEnum_SelectDefaultDevice( &m_pDeviceInfo ) ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ return hr;
+ }
+
+ if ( !m_bDebugMode )
+ {
+ m_pDeviceInfo->bWindowed = FALSE; // plein écran
+ }
+ if ( GetProfileInt("Device", "FullScreen", bFull) )
+ {
+ m_pDeviceInfo->bWindowed = !bFull;
+ }
+
+ // Create the 3D engine.
+ if( (m_pD3DEngine = new CD3DEngine(m_iMan, this)) == NULL )
+ {
+ DisplayFrameworkError( D3DENUMERR_ENGINE, MSGERR_APPMUSTEXIT );
+ return E_OUTOFMEMORY;
+ }
+ SetEngine(m_pD3DEngine);
+
+ // Initialize the app's custom scene stuff
+ if( FAILED( hr = m_pD3DEngine->OneTimeSceneInit() ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ return hr;
+ }
+
+ // Create a new CD3DFramework class. This class does all of our D3D
+ // initialization and manages the common D3D objects.
+ if( (m_pFramework = new CD3DFramework7()) == NULL )
+ {
+ DisplayFrameworkError( E_OUTOFMEMORY, MSGERR_APPMUSTEXIT );
+ return E_OUTOFMEMORY;
+ }
+
+ // Create the sound instance.
+ if( (m_pSound = new CSound(m_iMan)) == NULL )
+ {
+ DisplayFrameworkError( D3DENUMERR_SOUND, MSGERR_APPMUSTEXIT );
+ return E_OUTOFMEMORY;
+ }
+
+ // Create the robot application.
+ if( (m_pRobotMain = new CRobotMain(m_iMan)) == NULL )
+ {
+ DisplayFrameworkError( D3DENUMERR_ROBOT, MSGERR_APPMUSTEXIT );
+ return E_OUTOFMEMORY;
+ }
+
+ // Register the window class
+ WNDCLASS wndClass = { 0, WndProc, 0, 0, hInst,
+ LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON) ),
+ LoadCursor( NULL, IDC_ARROW ),
+ (HBRUSH)GetStockObject(WHITE_BRUSH),
+ NULL, _T("D3D Window") };
+ RegisterClass( &wndClass );
+
+ // Create the render window
+ style = WS_CAPTION|WS_VISIBLE;
+ if ( m_bDebugMode ) style |= WS_SYSMENU; // case de fermeture
+ m_hWnd = CreateWindow( _T("D3D Window"), m_strWindowTitle,
+//? WS_OVERLAPPEDWINDOW|WS_VISIBLE,
+ style, CW_USEDEFAULT, CW_USEDEFAULT,
+ WINDOW_DX, WINDOW_DY, 0L,
+//? LoadMenu( hInst, MAKEINTRESOURCE(IDR_MENU) ),
+ NULL,
+ hInst, 0L );
+ UpdateWindow( m_hWnd );
+
+ if ( !GetProfileInt("Setup", "Sound3D", b3D) )
+ {
+ b3D = TRUE;
+ }
+ 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);
+
+ // Initialize the 3D environment for the app
+ if( FAILED( hr = Initialize3DEnvironment() ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ Cleanup3DEnvironment();
+ return E_FAIL;
+ }
+
+ // Change the display device driver.
+ GetProfileString("Device", "Name", deviceName, 100);
+ GetProfileString("Device", "Mode", modeName, 100);
+ GetProfileInt("Device", "FullScreen", bFull);
+ if ( deviceName[0] != 0 && modeName[0] != 0 && bFull )
+ {
+ ChangeDevice(deviceName, modeName, bFull);
+ }
+
+ // Première exécution ?
+ if ( !GetProfileInt("Setup", "ObjectDirty", iValue) )
+ {
+ m_pD3DEngine->FirstExecuteAdapt(TRUE);
+ }
+
+ // Crée le fichier colobot.ini à la première exécution.
+ m_pRobotMain->CreateIni();
+
+#if _DEMO
+ m_pRobotMain->ChangePhase(PHASE_NAME);
+#else
+#if _NET | _SCHOOL
+ m_pRobotMain->ChangePhase(PHASE_WELCOME2);
+#else
+#if _FRENCH
+ m_pRobotMain->ChangePhase(PHASE_WELCOME2);
+#endif
+#if _ENGLISH
+ m_pRobotMain->ChangePhase(PHASE_WELCOME2);
+#endif
+#if _GERMAN
+ m_pRobotMain->ChangePhase(PHASE_WELCOME2);
+#endif
+#if _WG
+ m_pRobotMain->ChangePhase(PHASE_WELCOME1);
+#endif
+#if _POLISH
+ m_pRobotMain->ChangePhase(PHASE_WELCOME1);
+#endif
+#endif
+#endif
+ m_pD3DEngine->TimeInit();
+
+#if USE_THREAD
+ m_thread = CreateThread(NULL, 0, ThreadRoutine, this, 0, &m_threadId);
+ SetThreadPriority(m_thread, THREAD_PRIORITY_ABOVE_NORMAL);
+#endif
+
+ // The app is ready to go
+ m_bReady = TRUE;
+
+ return S_OK;
+}
+
+
+// Message-processing loop. Idle time is used to render the scene.
+
+INT CD3DApplication::Run()
+{
+ // Load keyboard accelerators
+ HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
+
+ // Now we're ready to recieve and process Windows messages.
+ BOOL bGotMsg;
+ MSG msg;
+ PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
+
+ while( WM_QUIT != msg.message )
+ {
+ // Use PeekMessage() if the app is active, so we can use idle time to
+ // render the scene. Else, use GetMessage() to avoid eating CPU time.
+ if( m_bActive )
+ bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
+ else
+ bGotMsg = GetMessage( &msg, NULL, 0U, 0U );
+
+ if( bGotMsg )
+ {
+ // Translate and dispatch the message
+ if( TranslateAccelerator( m_hWnd, hAccel, &msg ) == 0 )
+ {
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+ }
+ else
+ {
+ // Render a frame during idle time (no messages are waiting)
+ if( m_bActive && m_bReady )
+ {
+ Event event;
+
+ while ( m_event->GetEvent(event) )
+ {
+ if ( event.event == EVENT_QUIT )
+ {
+//? SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
+ m_pSound->StopMusic();
+ Cleanup3DEnvironment();
+ PostQuitMessage(0);
+ return msg.wParam;
+ }
+ m_pRobotMain->EventProcess(event);
+ }
+
+ if ( !RetNiceMouse() )
+ {
+ SetMouseType(m_pD3DEngine->RetMouseType());
+ }
+
+ if( FAILED( Render3DEnvironment() ) )
+ DestroyWindow( m_hWnd );
+ }
+ }
+ }
+
+ return msg.wParam;
+}
+
+
+
+// Conversion de la position de la souris.
+// x: 0=gauche, 1=droite
+// y: 0=bas, 1=haut
+
+FPOINT CD3DApplication::ConvPosToInterface(HWND hWnd, LPARAM lParam)
+{
+ POINT cpos;
+ FPOINT pos;
+ float px, py, w, h;
+
+ cpos.x = (short)LOWORD(lParam);
+ cpos.y = (short)HIWORD(lParam);
+
+ if ( !m_pDeviceInfo->bWindowed )
+ {
+ ClientToScreen(hWnd, &cpos);
+ }
+
+ px = (float)cpos.x;
+ py = (float)cpos.y;
+ w = (float)m_ddsdRenderTarget.dwWidth;
+ h = (float)m_ddsdRenderTarget.dwHeight;
+
+ pos.x = px/w;
+ pos.y = 1.0f-py/h;
+
+ return pos;
+}
+
+// Déplace physiquement la souris.
+
+void CD3DApplication::SetMousePos(FPOINT pos)
+{
+ POINT p;
+
+ pos.y = 1.0f-pos.y;
+
+ pos.x *= m_ddsdRenderTarget.dwWidth;
+ pos.y *= m_ddsdRenderTarget.dwHeight;
+
+ p.x = (int)pos.x;
+ p.y = (int)pos.y;
+ ClientToScreen(m_hWnd, &p);
+
+ SetCursorPos(p.x, p.y);
+}
+
+// Choix du type de curseur pour la souris.
+
+void CD3DApplication::SetMouseType(D3DMouse type)
+{
+ HCURSOR hc;
+
+ if ( type == D3DMOUSEHAND )
+ {
+ hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORHAND));
+ }
+ else if ( type == D3DMOUSECROSS )
+ {
+ hc = LoadCursor(NULL, IDC_CROSS);
+ }
+ else if ( type == D3DMOUSEEDIT )
+ {
+ hc = LoadCursor(NULL, IDC_IBEAM);
+ }
+ else if ( type == D3DMOUSENO )
+ {
+ hc = LoadCursor(NULL, IDC_NO);
+ }
+ else if ( type == D3DMOUSEMOVE )
+ {
+ hc = LoadCursor(NULL, IDC_SIZEALL);
+ }
+ else if ( type == D3DMOUSEMOVEH )
+ {
+ hc = LoadCursor(NULL, IDC_SIZEWE);
+ }
+ else if ( type == D3DMOUSEMOVEV )
+ {
+ hc = LoadCursor(NULL, IDC_SIZENS);
+ }
+ else if ( type == D3DMOUSEMOVED )
+ {
+ hc = LoadCursor(NULL, IDC_SIZENESW);
+ }
+ else if ( type == D3DMOUSEMOVEI )
+ {
+ hc = LoadCursor(NULL, IDC_SIZENWSE);
+ }
+ else if ( type == D3DMOUSEWAIT )
+ {
+ hc = LoadCursor(NULL, IDC_WAIT);
+ }
+ else if ( type == D3DMOUSESCROLLL )
+ {
+ hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLL));
+ }
+ else if ( type == D3DMOUSESCROLLR )
+ {
+ hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLR));
+ }
+ else if ( type == D3DMOUSESCROLLU )
+ {
+ hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLU));
+ }
+ else if ( type == D3DMOUSESCROLLD )
+ {
+ hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORSCROLLD));
+ }
+ else if ( type == D3DMOUSETARGET )
+ {
+ hc = LoadCursor(m_instance, MAKEINTRESOURCE(IDC_CURSORTARGET));
+ }
+ else
+ {
+ hc = LoadCursor(NULL, IDC_ARROW);
+ }
+
+ if ( hc != NULL )
+ {
+ SetCursor(hc);
+ }
+}
+
+// Choix du mode pour la souris.
+
+void CD3DApplication::SetNiceMouse(BOOL bNice)
+{
+ if ( bNice == m_bNiceMouse ) return;
+ m_bNiceMouse = bNice;
+
+ if ( m_bNiceMouse )
+ {
+ ShowCursor(FALSE); // cache la vilaine souris windows
+ SetCursor(NULL);
+ }
+ else
+ {
+ ShowCursor(TRUE); // montre la vilaine souris windows
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ }
+}
+
+// Indique s'il faut utiliser la jolie souris ombrée.
+
+BOOL CD3DApplication::RetNiceMouse()
+{
+ if ( m_pDeviceInfo->bWindowed ) return FALSE;
+ if ( !m_pDeviceInfo->bHardware ) return FALSE;
+
+ return m_bNiceMouse;
+}
+
+// Indique s'il est possible d'utiliser la jolie souris ombrée.
+
+BOOL CD3DApplication::RetNiceMouseCap()
+{
+ if ( m_pDeviceInfo->bWindowed ) return FALSE;
+ if ( !m_pDeviceInfo->bHardware ) return FALSE;
+
+ return TRUE;
+}
+
+
+// Static msg handler which passes messages to the application class.
+
+LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ if ( g_pD3DApp != 0 )
+ {
+ Event event;
+ short move;
+
+ ZeroMemory(&event, sizeof(Event));
+
+#if 0
+ if ( uMsg == WM_KEYDOWN ||
+ uMsg == WM_CHAR ||
+ uMsg == WM_XBUTTONDOWN ||
+ uMsg == WM_XBUTTONUP )
+ {
+ char s[100];
+ sprintf(s, "event: %d %d %d\n", uMsg, wParam, lParam);
+ OutputDebugString(s);
+ }
+#endif
+
+ if ( uMsg == WM_LBUTTONDOWN ) event.event = EVENT_LBUTTONDOWN;
+ if ( uMsg == WM_RBUTTONDOWN ) event.event = EVENT_RBUTTONDOWN;
+ if ( uMsg == WM_LBUTTONUP ) event.event = EVENT_LBUTTONUP;
+ if ( uMsg == WM_RBUTTONUP ) event.event = EVENT_RBUTTONUP;
+ if ( uMsg == WM_MOUSEMOVE ) event.event = EVENT_MOUSEMOVE;
+ if ( uMsg == WM_KEYDOWN ) event.event = EVENT_KEYDOWN;
+ if ( uMsg == WM_KEYUP ) event.event = EVENT_KEYUP;
+ if ( uMsg == WM_CHAR ) event.event = EVENT_CHAR;
+
+ if ( uMsg == WM_XBUTTONUP )
+ {
+ if ( (wParam>>16) == XBUTTON1 ) event.event = EVENT_HYPER_PREV;
+ if ( (wParam>>16) == XBUTTON2 ) event.event = EVENT_HYPER_NEXT;
+ }
+
+ event.param = wParam;
+ event.axeX = AxeLimit(g_pD3DApp->m_axeKey.x + g_pD3DApp->m_axeJoy.x);
+ event.axeY = AxeLimit(g_pD3DApp->m_axeKey.y + g_pD3DApp->m_axeJoy.y);
+ event.axeZ = AxeLimit(g_pD3DApp->m_axeKey.z + g_pD3DApp->m_axeJoy.z);
+ event.keyState = g_pD3DApp->m_keyState;
+
+ if ( uMsg == WM_LBUTTONDOWN ||
+ uMsg == WM_RBUTTONDOWN ||
+ uMsg == WM_LBUTTONUP ||
+ uMsg == WM_RBUTTONUP ||
+ uMsg == WM_MOUSEMOVE ) // événement souris ?
+ {
+ event.pos = g_pD3DApp->ConvPosToInterface(hWnd, lParam);
+ g_pD3DApp->m_mousePos = event.pos;
+ g_pD3DApp->m_pD3DEngine->SetMousePos(event.pos);
+ }
+
+ if ( uMsg == WM_MOUSEWHEEL ) // molette souris ?
+ {
+ event.event = EVENT_KEYDOWN;
+ event.pos = g_pD3DApp->m_mousePos;
+ move = HIWORD(wParam);
+ if ( move/WHEEL_DELTA > 0 ) event.param = VK_WHEELUP;
+ if ( move/WHEEL_DELTA < 0 ) event.param = VK_WHEELDOWN;
+ }
+ if ( g_pD3DApp->m_mshMouseWheel != 0 &&
+ uMsg == g_pD3DApp->m_mshMouseWheel ) // molette souris Logitech ?
+ {
+ event.event = EVENT_KEYDOWN;
+ event.pos = g_pD3DApp->m_mousePos;
+ move = LOWORD(wParam);
+ if ( move/WHEEL_DELTA > 0 ) event.param = VK_WHEELUP;
+ if ( move/WHEEL_DELTA < 0 ) event.param = VK_WHEELDOWN;
+ }
+
+ if ( event.event == EVENT_KEYDOWN ||
+ event.event == EVENT_KEYUP ||
+ event.event == EVENT_CHAR )
+ {
+ if ( event.param == 0 )
+ {
+ event.event = EVENT_NULL;
+ }
+ }
+
+ if ( g_pD3DApp->m_pRobotMain != 0 && event.event != 0 )
+ {
+ g_pD3DApp->m_pRobotMain->EventProcess(event);
+//? if ( !g_pD3DApp->RetNiceMouse() )
+//? {
+//? g_pD3DApp->SetMouseType(g_pD3DApp->m_pD3DEngine->RetMouseType());
+//? }
+ }
+ if ( g_pD3DApp->m_pD3DEngine != 0 )
+ {
+ g_pD3DApp->m_pD3DEngine->MsgProc( hWnd, uMsg, wParam, lParam );
+ }
+ return g_pD3DApp->MsgProc( hWnd, uMsg, wParam, lParam );
+ }
+
+ return DefWindowProc( hWnd, uMsg, wParam, lParam );
+}
+
+
+// Minimal message proc function for the about box.
+
+BOOL CALLBACK AboutProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM )
+{
+ if( WM_COMMAND == uMsg )
+ if( IDOK == LOWORD(wParam) || IDCANCEL == LOWORD(wParam) )
+ EndDialog( hWnd, TRUE );
+
+ return WM_INITDIALOG == uMsg ? TRUE : FALSE;
+}
+
+
+
+// Ignore les touches pressées.
+
+void CD3DApplication::FlushPressKey()
+{
+ m_keyState = 0;
+ m_axeKey = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_axeJoy = D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+// Remet les touches par défaut.
+
+void CD3DApplication::ResetKey()
+{
+ int i;
+
+ for ( i=0 ; i<50 ; i++ )
+ {
+ m_key[i][0] = 0;
+ m_key[i][1] = 0;
+ }
+ m_key[KEYRANK_LEFT ][0] = VK_LEFT;
+ m_key[KEYRANK_RIGHT ][0] = VK_RIGHT;
+ m_key[KEYRANK_UP ][0] = VK_UP;
+ m_key[KEYRANK_DOWN ][0] = VK_DOWN;
+ m_key[KEYRANK_GUP ][0] = VK_SHIFT;
+ m_key[KEYRANK_GDOWN ][0] = VK_CONTROL;
+ m_key[KEYRANK_CAMERA ][0] = VK_SPACE;
+ m_key[KEYRANK_CAMERA ][1] = VK_BUTTON2;
+ m_key[KEYRANK_DESEL ][0] = VK_NUMPAD0;
+ m_key[KEYRANK_DESEL ][1] = VK_BUTTON6;
+ m_key[KEYRANK_ACTION ][0] = VK_RETURN;
+ m_key[KEYRANK_ACTION ][1] = VK_BUTTON1;
+ m_key[KEYRANK_NEAR ][0] = VK_ADD;
+ m_key[KEYRANK_NEAR ][1] = VK_BUTTON5;
+ m_key[KEYRANK_AWAY ][0] = VK_SUBTRACT;
+ m_key[KEYRANK_AWAY ][1] = VK_BUTTON4;
+ m_key[KEYRANK_NEXT ][0] = VK_TAB;
+ m_key[KEYRANK_NEXT ][1] = VK_BUTTON3;
+ m_key[KEYRANK_HUMAN ][0] = VK_HOME;
+ m_key[KEYRANK_HUMAN ][1] = VK_BUTTON7;
+ m_key[KEYRANK_QUIT ][0] = VK_ESCAPE;
+ m_key[KEYRANK_HELP ][0] = VK_F1;
+ m_key[KEYRANK_PROG ][0] = VK_F2;
+ m_key[KEYRANK_CBOT ][0] = VK_F3;
+ m_key[KEYRANK_VISIT ][0] = VK_DECIMAL;
+ m_key[KEYRANK_SPEED10][0] = VK_F4;
+ m_key[KEYRANK_SPEED15][0] = VK_F5;
+ m_key[KEYRANK_SPEED20][0] = VK_F6;
+// m_key[KEYRANK_SPEED30][0] = VK_F7;
+}
+
+// Modifie une touche.
+
+void CD3DApplication::SetKey(int keyRank, int option, int key)
+{
+ if ( keyRank < 0 ||
+ keyRank >= 50 ) return;
+
+ if ( option < 0 ||
+ option >= 2 ) return;
+
+ m_key[keyRank][option] = key;
+}
+
+// Donne une touche.
+
+int CD3DApplication::RetKey(int keyRank, int option)
+{
+ if ( keyRank < 0 ||
+ keyRank >= 50 ) return 0;
+
+ if ( option < 0 ||
+ option >= 2 ) return 0;
+
+ return m_key[keyRank][option];
+}
+
+
+
+// Utilise le joystick ou le clavier.
+
+void CD3DApplication::SetJoystick(BOOL bEnable)
+{
+ m_bJoystick = bEnable;
+
+ if ( m_bJoystick ) // joystick ?
+ {
+ if ( !InitDirectInput(m_instance, m_hWnd) ) // initialise joystick
+ {
+ m_bJoystick = FALSE;
+ }
+ else
+ {
+ SetAcquire(TRUE);
+ SetTimer(m_hWnd, 0, 1000/30, NULL);
+ }
+ }
+ else // clavier ?
+ {
+ KillTimer(m_hWnd, 0);
+ SetAcquire(FALSE);
+ FreeDirectInput();
+ }
+}
+
+BOOL CD3DApplication::RetJoystick()
+{
+ return m_bJoystick;
+}
+
+
+// Message handling function.
+
+LRESULT CD3DApplication::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam,
+ LPARAM lParam )
+{
+ HRESULT hr;
+ DIJOYSTATE js;
+ int i;
+
+ // La touche F10 envoie un autre message pour activer
+ // le menu dans les applications Windows standard !
+ if ( uMsg == WM_SYSKEYDOWN && wParam == VK_F10 )
+ {
+ uMsg = WM_KEYDOWN;
+ }
+ if ( uMsg == WM_SYSKEYUP && wParam == VK_F10 )
+ {
+ uMsg = WM_KEYUP;
+ }
+
+ // Mange l'événement "menu" envoyé par Alt ou F10.
+ if ( uMsg == WM_SYSCOMMAND && wParam == SC_KEYMENU )
+ {
+ return 0;
+ }
+
+ if ( uMsg == WM_KEYDOWN || uMsg == WM_KEYUP )
+ {
+ if ( GetKeyState(VK_SHIFT) & 0x8000 )
+ {
+ m_keyState |= KS_SHIFT;
+ }
+ else
+ {
+ m_keyState &= ~KS_SHIFT;
+ }
+
+ if ( GetKeyState(VK_CONTROL) & 0x8000 )
+ {
+ m_keyState |= KS_CONTROL;
+ }
+ else
+ {
+ m_keyState &= ~KS_CONTROL;
+ }
+ }
+
+ switch( uMsg )
+ {
+ case WM_KEYDOWN:
+ if ( wParam == m_key[KEYRANK_UP ][0] ) m_axeKey.y = 1.0f;
+ if ( wParam == m_key[KEYRANK_UP ][1] ) m_axeKey.y = 1.0f;
+ if ( wParam == m_key[KEYRANK_DOWN ][0] ) m_axeKey.y = -1.0f;
+ if ( wParam == m_key[KEYRANK_DOWN ][1] ) m_axeKey.y = -1.0f;
+ if ( wParam == m_key[KEYRANK_LEFT ][0] ) m_axeKey.x = -1.0f;
+ if ( wParam == m_key[KEYRANK_LEFT ][1] ) m_axeKey.x = -1.0f;
+ if ( wParam == m_key[KEYRANK_RIGHT][0] ) m_axeKey.x = 1.0f;
+ if ( wParam == m_key[KEYRANK_RIGHT][1] ) m_axeKey.x = 1.0f;
+ if ( wParam == m_key[KEYRANK_GUP ][0] ) m_axeKey.z = 1.0f;
+ if ( wParam == m_key[KEYRANK_GUP ][1] ) m_axeKey.z = 1.0f;
+ if ( wParam == m_key[KEYRANK_GDOWN][0] ) m_axeKey.z = -1.0f;
+ if ( wParam == m_key[KEYRANK_GDOWN][1] ) m_axeKey.z = -1.0f;
+ if ( wParam == m_key[KEYRANK_NEAR ][0] ) m_keyState |= KS_NUMPLUS;
+ if ( wParam == m_key[KEYRANK_NEAR ][1] ) m_keyState |= KS_NUMPLUS;
+ if ( wParam == m_key[KEYRANK_AWAY ][0] ) m_keyState |= KS_NUMMINUS;
+ if ( wParam == m_key[KEYRANK_AWAY ][1] ) m_keyState |= KS_NUMMINUS;
+ if ( wParam == VK_PRIOR ) m_keyState |= KS_PAGEUP;
+ if ( wParam == VK_NEXT ) m_keyState |= KS_PAGEDOWN;
+//? if ( wParam == VK_SHIFT ) m_keyState |= KS_SHIFT;
+//? if ( wParam == VK_CONTROL ) m_keyState |= KS_CONTROL;
+ if ( wParam == VK_NUMPAD8 ) m_keyState |= KS_NUMUP;
+ if ( wParam == VK_NUMPAD2 ) m_keyState |= KS_NUMDOWN;
+ if ( wParam == VK_NUMPAD4 ) m_keyState |= KS_NUMLEFT;
+ if ( wParam == VK_NUMPAD6 ) m_keyState |= KS_NUMRIGHT;
+ break;
+
+ case WM_KEYUP:
+ if ( wParam == m_key[KEYRANK_UP ][0] ) m_axeKey.y = 0.0f;
+ if ( wParam == m_key[KEYRANK_UP ][1] ) m_axeKey.y = 0.0f;
+ if ( wParam == m_key[KEYRANK_DOWN ][0] ) m_axeKey.y = 0.0f;
+ if ( wParam == m_key[KEYRANK_DOWN ][1] ) m_axeKey.y = 0.0f;
+ if ( wParam == m_key[KEYRANK_LEFT ][0] ) m_axeKey.x = 0.0f;
+ if ( wParam == m_key[KEYRANK_LEFT ][1] ) m_axeKey.x = 0.0f;
+ if ( wParam == m_key[KEYRANK_RIGHT][0] ) m_axeKey.x = 0.0f;
+ if ( wParam == m_key[KEYRANK_RIGHT][1] ) m_axeKey.x = 0.0f;
+ if ( wParam == m_key[KEYRANK_GUP ][0] ) m_axeKey.z = 0.0f;
+ if ( wParam == m_key[KEYRANK_GUP ][1] ) m_axeKey.z = 0.0f;
+ if ( wParam == m_key[KEYRANK_GDOWN][0] ) m_axeKey.z = 0.0f;
+ if ( wParam == m_key[KEYRANK_GDOWN][1] ) m_axeKey.z = 0.0f;
+ if ( wParam == m_key[KEYRANK_NEAR ][0] ) m_keyState &= ~KS_NUMPLUS;
+ if ( wParam == m_key[KEYRANK_NEAR ][1] ) m_keyState &= ~KS_NUMPLUS;
+ if ( wParam == m_key[KEYRANK_AWAY ][0] ) m_keyState &= ~KS_NUMMINUS;
+ if ( wParam == m_key[KEYRANK_AWAY ][1] ) m_keyState &= ~KS_NUMMINUS;
+ if ( wParam == VK_PRIOR ) m_keyState &= ~KS_PAGEUP;
+ if ( wParam == VK_NEXT ) m_keyState &= ~KS_PAGEDOWN;
+//? if ( wParam == VK_SHIFT ) m_keyState &= ~KS_SHIFT;
+//? if ( wParam == VK_CONTROL ) m_keyState &= ~KS_CONTROL;
+ if ( wParam == VK_NUMPAD8 ) m_keyState &= ~KS_NUMUP;
+ if ( wParam == VK_NUMPAD2 ) m_keyState &= ~KS_NUMDOWN;
+ if ( wParam == VK_NUMPAD4 ) m_keyState &= ~KS_NUMLEFT;
+ if ( wParam == VK_NUMPAD6 ) m_keyState &= ~KS_NUMRIGHT;
+ break;
+
+ case WM_LBUTTONDOWN:
+ m_keyState |= KS_MLEFT;
+ break;
+
+ case WM_RBUTTONDOWN:
+ m_keyState |= KS_MRIGHT;
+ break;
+
+ case WM_LBUTTONUP:
+ m_keyState &= ~KS_MLEFT;
+ break;
+
+ case WM_RBUTTONUP:
+ m_keyState &= ~KS_MRIGHT;
+ break;
+
+ case WM_PAINT:
+ // Handle paint messages when the app is not ready
+ if( m_pFramework && !m_bReady )
+ {
+ if( m_pDeviceInfo->bWindowed )
+ m_pFramework->ShowFrame();
+ else
+ m_pFramework->FlipToGDISurface( TRUE );
+ }
+ break;
+
+ case WM_MOVE:
+ // If in windowed mode, move the Framework's window
+ if( m_pFramework && m_bActive && m_bReady && m_pDeviceInfo->bWindowed )
+ m_pFramework->Move( (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam) );
+ break;
+
+ case WM_SIZE:
+ // Check to see if we are losing our window...
+ if( SIZE_MAXHIDE==wParam || SIZE_MINIMIZED==wParam )
+ {
+ m_bActive = FALSE;
+ }
+ else
+ {
+ m_bActive = TRUE;
+ }
+//? char s[100];
+//? sprintf(s, "WM_SIZE %d %d %d\n", m_bActive, m_bReady, m_pDeviceInfo->bWindowed);
+//? OutputDebugString(s);
+
+ // A new window size will require a new backbuffer
+ // size, so the 3D structures must be changed accordingly.
+ if( m_bActive && m_bReady && m_pDeviceInfo->bWindowed )
+ {
+ m_bReady = FALSE;
+
+//? OutputDebugString("WM_SIZE Change3DEnvironment\n");
+ if( FAILED( hr = Change3DEnvironment() ) )
+ return 0;
+
+ m_bReady = TRUE;
+ }
+ break;
+
+ case WM_TIMER:
+ if ( m_bActivateApp && m_bJoystick )
+ {
+ if ( UpdateInputState(js) )
+ {
+ m_axeJoy.x = js.lX/1000.0f+js.lRz/1000.0f; // tourner
+ m_axeJoy.y = -js.lY/1000.0f; // avancer
+ m_axeJoy.z = -js.rglSlider[0]/1000.0f; // monter
+
+ m_axeJoy.x = Neutral(m_axeJoy.x, 0.2f);
+ m_axeJoy.y = Neutral(m_axeJoy.y, 0.2f);
+ m_axeJoy.z = Neutral(m_axeJoy.z, 0.2f);
+
+//? char s[100];
+//? sprintf(s, "x=%d y=%d z=% x=%d y=%d z=%d\n", js.lX,js.lY,js.lZ,js.lRx,js.lRy,js.lRz);
+//? OutputDebugString(s);
+
+ for ( i=0 ; i<32 ; i++ )
+ {
+ if ( js.rgbButtons[i] != 0 && !m_bJoyButton[i] )
+ {
+ m_bJoyButton[i] = TRUE;
+ PostMessage(m_hWnd, WM_KEYDOWN, VK_BUTTON1+i, 0);
+ }
+ if ( js.rgbButtons[i] == 0 && m_bJoyButton[i] )
+ {
+ m_bJoyButton[i] = FALSE;
+ PostMessage(m_hWnd, WM_KEYUP, VK_BUTTON1+i, 0);
+ }
+ }
+ }
+ else
+ {
+ OutputDebugString("UpdateInputState error\n");
+ }
+ }
+ break;
+
+ case WM_ACTIVATE:
+ if( LOWORD(wParam) == WA_INACTIVE )
+ {
+ m_bActivateApp = FALSE;
+ }
+ else
+ {
+ m_bActivateApp = TRUE;
+ }
+
+ if ( m_bActivateApp && m_bJoystick )
+ {
+ SetAcquire(TRUE); // ré-active le joystick
+ }
+ break;
+
+ case MM_MCINOTIFY:
+ if ( wParam == MCI_NOTIFY_SUCCESSFUL )
+ {
+ OutputDebugString("Event MM_MCINOTIFY\n");
+ m_pSound->SuspendMusic();
+ m_pSound->RestartMusic();
+ }
+ break;
+
+ case WM_SETCURSOR:
+ // Prevent a cursor in fullscreen mode
+ if( m_bActive && m_bReady && !m_pDeviceInfo->bWindowed )
+ {
+//? SetCursor(NULL);
+ return 1;
+ }
+ break;
+
+ case WM_ENTERMENULOOP:
+ // Pause the app when menus are displayed
+ Pause(TRUE);
+ break;
+ case WM_EXITMENULOOP:
+ Pause(FALSE);
+ break;
+
+ case WM_ENTERSIZEMOVE:
+ // Halt frame movement while the app is sizing or moving
+ m_pD3DEngine->TimeEnterGel();
+ break;
+ case WM_EXITSIZEMOVE:
+ m_pD3DEngine->TimeExitGel();
+ break;
+
+ case WM_NCHITTEST:
+ // Prevent the user from selecting the menu in fullscreen mode
+ if( !m_pDeviceInfo->bWindowed )
+ return HTCLIENT;
+
+ break;
+
+ case WM_POWERBROADCAST:
+ switch( wParam )
+ {
+ case PBT_APMQUERYSUSPEND:
+ // At this point, the app should save any data for open
+ // network connections, files, etc.., and prepare to go into
+ // a suspended mode.
+ return OnQuerySuspend( (DWORD)lParam );
+
+ case PBT_APMRESUMESUSPEND:
+ // At this point, the app should recover any data, network
+ // connections, files, etc.., and resume running from when
+ // the app was suspended.
+ return OnResumeSuspend( (DWORD)lParam );
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ // Prevent moving/sizing and power loss in fullscreen mode
+ switch( wParam )
+ {
+ case SC_MOVE:
+ case SC_SIZE:
+ case SC_MAXIMIZE:
+ case SC_MONITORPOWER:
+ if( FALSE == m_pDeviceInfo->bWindowed )
+ return 1;
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch( LOWORD(wParam) )
+ {
+ case IDM_CHANGEDEVICE:
+ // Display the device-selection dialog box.
+ if( m_bActive && m_bReady )
+ {
+ Pause(TRUE);
+
+ if( SUCCEEDED( D3DEnum_UserChangeDevice( &m_pDeviceInfo ) ) )
+ {
+ if( FAILED( hr = Change3DEnvironment() ) )
+ return 0;
+ }
+ Pause(FALSE);
+ }
+ return 0;
+
+ case IDM_ABOUT:
+ // Display the About box
+ Pause(TRUE);
+ DialogBox( (HINSTANCE)GetWindowLong( hWnd, GWL_HINSTANCE ),
+ MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutProc );
+ Pause(FALSE);
+ return 0;
+
+ case IDM_EXIT:
+ // Recieved key/menu command to exit app
+ SendMessage( hWnd, WM_CLOSE, 0, 0 );
+ return 0;
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow( hWnd );
+ return 0;
+
+ case WM_DESTROY:
+ Cleanup3DEnvironment();
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ return DefWindowProc( hWnd, uMsg, wParam, lParam );
+}
+
+
+// Enumeration function to report valid pixel formats for z-buffers.
+
+HRESULT WINAPI EnumZBufferFormatsCallback(DDPIXELFORMAT* pddpf,
+ VOID* pContext)
+{
+ DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext;
+
+ char s[100];
+ sprintf(s, "EnumZBufferFormatsCallback %d\n", pddpf->dwRGBBitCount);
+ OutputDebugString(s);
+
+ if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount )
+ {
+ (*pddpfOut) = (*pddpf);
+ return D3DENUMRET_CANCEL;
+ }
+
+ return D3DENUMRET_OK;
+}
+
+// Internal function called by Create() to make and attach a zbuffer
+// to the renderer.
+
+HRESULT CD3DApplication::CreateZBuffer(GUID* pDeviceGUID)
+{
+ HRESULT hr;
+
+ // Check if the device supports z-bufferless hidden surface removal. If so,
+ // we don't really need a z-buffer
+ D3DDEVICEDESC7 ddDesc;
+ m_pD3DDevice->GetCaps( &ddDesc );
+ if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )
+ return S_OK;
+
+ // Get z-buffer dimensions from the render target
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsRenderTarget->GetSurfaceDesc( &ddsd );
+
+ // Setup the surface desc for the z-buffer.
+ ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | DDSCAPS_VIDEOMEMORY;
+ ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized
+
+ // Get an appropiate pixel format from enumeration of the formats. On the
+ // first pass, we look for a zbuffer dpeth which is equal to the frame
+ // buffer depth (as some cards unfornately require this).
+ m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
+ (VOID*)&ddsd.ddpfPixelFormat );
+ if( 0 == ddsd.ddpfPixelFormat.dwSize )
+ {
+ // Try again, just accepting any 16-bit zbuffer
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
+ m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
+ (VOID*)&ddsd.ddpfPixelFormat );
+
+ if( 0 == ddsd.ddpfPixelFormat.dwSize )
+ {
+ DEBUG_MSG( _T("Device doesn't support requested zbuffer format") );
+ return D3DFWERR_NOZBUFFER;
+ }
+ }
+
+ // Create and attach a z-buffer
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsDepthBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOZBUFFER;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ if( FAILED( m_pddsRenderTarget->AddAttachedSurface( m_pddsDepthBuffer ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") );
+ return D3DFWERR_NOZBUFFER;
+ }
+
+ // Finally, this call rebuilds internal structures
+ if( FAILED( m_pD3DDevice->SetRenderTarget( m_pddsRenderTarget, 0L ) ) )
+ {
+ DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") );
+ return D3DFWERR_NOZBUFFER;
+ }
+
+ return S_OK;
+}
+
+// Initializes the sample framework, then calls the app-specific function
+// to initialize device specific objects. This code is structured to
+// handled any errors that may occur duing initialization.
+
+HRESULT CD3DApplication::Initialize3DEnvironment()
+{
+ HRESULT hr;
+ DDSCAPS2 ddsCaps2;
+ DWORD dwFrameworkFlags = 0L;
+ DWORD dwTotal;
+ DWORD dwFree;
+
+ dwFrameworkFlags |= ( !m_pDeviceInfo->bWindowed ? D3DFW_FULLSCREEN : 0L );
+ dwFrameworkFlags |= ( m_pDeviceInfo->bStereo ? D3DFW_STEREO : 0L );
+ dwFrameworkFlags |= ( m_bAppUseZBuffer ? D3DFW_ZBUFFER : 0L );
+
+ // Initialize the D3D framework
+ if( SUCCEEDED( hr = m_pFramework->Initialize( m_hWnd,
+ m_pDeviceInfo->pDriverGUID, m_pDeviceInfo->pDeviceGUID,
+ &m_pDeviceInfo->ddsdFullscreenMode, dwFrameworkFlags ) ) )
+ {
+ m_pDD = m_pFramework->GetDirectDraw();
+ m_pD3D = m_pFramework->GetDirect3D();
+ m_pD3DDevice = m_pFramework->GetD3DDevice();
+
+ m_pD3DEngine->SetD3DDevice(m_pD3DDevice);
+
+ m_pddsRenderTarget = m_pFramework->GetRenderSurface();
+
+ m_ddsdRenderTarget.dwSize = sizeof(m_ddsdRenderTarget);
+ m_pddsRenderTarget->GetSurfaceDesc( &m_ddsdRenderTarget );
+
+ // Demande la quantité de mémoire vidéo.
+ ZeroMemory(&ddsCaps2, sizeof(ddsCaps2));
+ ddsCaps2.dwCaps = DDSCAPS_TEXTURE;
+ dwTotal = 0;
+ hr = m_pDD->GetAvailableVidMem(&ddsCaps2, &dwTotal, &dwFree);
+ m_vidMemTotal = dwTotal;
+
+ // Let the app run its startup code which creates the 3d scene.
+ if( SUCCEEDED( hr = m_pD3DEngine->InitDeviceObjects() ) )
+ {
+//? CreateZBuffer(m_pDeviceInfo->pDeviceGUID);
+ return S_OK;
+ }
+ else
+ {
+ DeleteDeviceObjects();
+ m_pFramework->DestroyObjects();
+ }
+ }
+
+ // If we get here, the first initialization passed failed. If that was with a
+ // hardware device, try again using a software rasterizer instead.
+ if( m_pDeviceInfo->bHardware )
+ {
+ // Try again with a software rasterizer
+ DisplayFrameworkError( hr, MSGWARN_SWITCHEDTOSOFTWARE );
+ D3DEnum_SelectDefaultDevice( &m_pDeviceInfo, D3DENUM_SOFTWAREONLY );
+ return Initialize3DEnvironment();
+ }
+
+ return hr;
+}
+
+
+// Handles driver, device, and/or mode changes for the app.
+
+HRESULT CD3DApplication::Change3DEnvironment()
+{
+#if 0
+ HRESULT hr;
+ static BOOL bOldWindowedState = TRUE;
+ static DWORD dwSavedStyle;
+ static RECT rcSaved;
+
+ // Release all scene objects that will be re-created for the new device
+ DeleteDeviceObjects();
+
+ // Release framework objects, so a new device can be created
+ if( FAILED( hr = m_pFramework->DestroyObjects() ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
+ return hr;
+ }
+
+ // Check if going from fullscreen to windowed mode, or vice versa.
+ if( bOldWindowedState != m_pDeviceInfo->bWindowed )
+ {
+ if( m_pDeviceInfo->bWindowed )
+ {
+ // Coming from fullscreen mode, so restore window properties
+ SetWindowLong( m_hWnd, GWL_STYLE, dwSavedStyle );
+ SetWindowPos( m_hWnd, HWND_NOTOPMOST, rcSaved.left, rcSaved.top,
+ ( rcSaved.right - rcSaved.left ),
+ ( rcSaved.bottom - rcSaved.top ), SWP_SHOWWINDOW );
+ }
+ else
+ {
+ // Going to fullscreen mode, save/set window properties as needed
+ dwSavedStyle = GetWindowLong( m_hWnd, GWL_STYLE );
+ GetWindowRect( m_hWnd, &rcSaved );
+ SetWindowLong( m_hWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
+ }
+
+ bOldWindowedState = m_pDeviceInfo->bWindowed;
+ }
+
+ // Inform the framework class of the driver change. It will internally
+ // re-create valid surfaces, a d3ddevice, etc.
+ if( FAILED( hr = Initialize3DEnvironment() ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
+ return hr;
+ }
+
+ return S_OK;
+#else
+ HRESULT hr;
+
+ // Release all scene objects that will be re-created for the new device
+ DeleteDeviceObjects();
+
+ // Release framework objects, so a new device can be created
+ if( FAILED( hr = m_pFramework->DestroyObjects() ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
+ return hr;
+ }
+
+ if( m_pDeviceInfo->bWindowed )
+ {
+ SetWindowPos(m_hWnd, HWND_NOTOPMOST, 10, 10, WINDOW_DX, WINDOW_DY, SWP_SHOWWINDOW);
+ }
+
+ // Inform the framework class of the driver change. It will internally
+ // re-create valid surfaces, a d3ddevice, etc.
+ if( FAILED( hr = Initialize3DEnvironment() ) )
+ {
+ DisplayFrameworkError( hr, MSGERR_APPMUSTEXIT );
+ SendMessage( m_hWnd, WM_CLOSE, 0, 0 );
+ return hr;
+ }
+
+ m_pD3DEngine->ChangeLOD();
+
+ if( m_pDeviceInfo->bWindowed )
+ {
+ SetNiceMouse(FALSE); // cache la vilaine souris windows
+ }
+
+ return S_OK;
+#endif
+}
+
+
+
+// Fait évoluer tout le jeu.
+
+void CD3DApplication::StepSimul(float rTime)
+{
+ Event event;
+
+ if ( m_pRobotMain == 0 ) return;
+
+ ZeroMemory(&event, sizeof(Event));
+ event.event = EVENT_FRAME; // drôle de bug en release "Maximize speed" !!!
+ event.rTime = rTime;
+ event.axeX = AxeLimit(m_axeKey.x + m_axeJoy.x);
+ event.axeY = AxeLimit(m_axeKey.y + m_axeJoy.y);
+ event.axeZ = AxeLimit(m_axeKey.z + m_axeJoy.z);
+ event.keyState = m_keyState;
+
+//?char s[100];
+//?sprintf(s, "StepSimul %.3f\n", event.rTime);
+//?OutputDebugString(s);
+ m_pRobotMain->EventProcess(event);
+}
+
+
+// Draws the scene.
+
+HRESULT CD3DApplication::Render3DEnvironment()
+{
+ HRESULT hr;
+ float rTime;
+
+ // Check the cooperative level before rendering
+ if( FAILED( hr = m_pDD->TestCooperativeLevel() ) )
+ {
+ switch( hr )
+ {
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ case DDERR_NOEXCLUSIVEMODE:
+ OutputDebugString("DDERR_EXCLUSIVEMODEALREADYSET\n");
+ // Do nothing because some other app has exclusive mode
+ return S_OK;
+
+ case DDERR_WRONGMODE:
+ OutputDebugString("DDERR_WRONGMODE\n");
+ // The display mode changed on us. Resize accordingly
+ if( m_pDeviceInfo->bWindowed )
+ return Change3DEnvironment();
+ break;
+ }
+ return hr;
+ }
+
+ // Get the relative time, in seconds
+ rTime = m_pD3DEngine->TimeGet();
+ if ( rTime > MAX_STEP ) rTime = MAX_STEP; // jamais plus de 0.5s !
+ m_aTime += rTime;
+
+#if !USE_THREAD
+ if( FAILED( hr = m_pD3DEngine->FrameMove(rTime) ) )
+ return hr;
+
+ // FrameMove (animate) the scene
+ StepSimul(rTime);
+#endif
+
+ // Render the scene.
+ if( FAILED( hr = m_pD3DEngine->Render() ) )
+ return hr;
+
+ DrawSuppl();
+
+ // Show the frame rate, etc.
+ if( m_bShowStats )
+ ShowStats();
+
+ // Show the frame on the primary surface.
+ if( FAILED( hr = m_pFramework->ShowFrame() ) )
+ {
+ if( DDERR_SURFACELOST != hr )
+ return hr;
+
+ m_pFramework->RestoreSurfaces();
+ m_pD3DEngine->RestoreSurfaces();
+ }
+
+ return S_OK;
+}
+
+
+// Cleanup scene objects
+
+VOID CD3DApplication::Cleanup3DEnvironment()
+{
+ m_bActive = FALSE;
+ m_bReady = FALSE;
+
+ if( m_pFramework )
+ {
+ DeleteDeviceObjects();
+ SAFE_DELETE( m_pFramework );
+
+ m_pD3DEngine->FinalCleanup();
+ }
+
+ D3DEnum_FreeResources();
+//? FreeDirectInput();
+}
+
+// Called when the app is exitting, or the device is being changed,
+// this function deletes any device dependant objects.
+
+VOID CD3DApplication::DeleteDeviceObjects()
+{
+ if( m_pFramework )
+ {
+ m_pD3DEngine->DeleteDeviceObjects();
+ SAFE_RELEASE( m_pddsDepthBuffer );
+ }
+}
+
+
+
+// Called in to toggle the pause state of the app. This function
+// brings the GDI surface to the front of the display, so drawing
+// output like message boxes and menus may be displayed.
+
+VOID CD3DApplication::Pause( BOOL bPause )
+{
+ static DWORD dwAppPausedCount = 0L;
+
+ dwAppPausedCount += ( bPause ? +1 : -1 );
+ m_bReady = ( dwAppPausedCount ? FALSE : TRUE );
+
+ // Handle the first pause request (of many, nestable pause requests)
+ if( bPause && ( 1 == dwAppPausedCount ) )
+ {
+ // Get a surface for the GDI
+ if( m_pFramework )
+ m_pFramework->FlipToGDISurface( TRUE );
+
+ // Stop the scene from animating
+ m_pD3DEngine->TimeEnterGel();
+ }
+
+ if( 0 == dwAppPausedCount )
+ {
+ // Restart the scene
+ m_pD3DEngine->TimeExitGel();
+ }
+}
+
+
+// Called when the app receives a PBT_APMQUERYSUSPEND message, meaning
+// the computer is about to be suspended. At this point, the app should
+// save any data for open network connections, files, etc.., and prepare
+// to go into a suspended mode.
+
+LRESULT CD3DApplication::OnQuerySuspend( DWORD dwFlags )
+{
+ OutputDebugString("OnQuerySuspend\n");
+ Pause(TRUE);
+ return TRUE;
+}
+
+
+// Called when the app receives a PBT_APMRESUMESUSPEND message, meaning
+// the computer has just resumed from a suspended state. At this point,
+// the app should recover any data, network connections, files, etc..,
+// and resume running from when the app was suspended.
+
+LRESULT CD3DApplication::OnResumeSuspend( DWORD dwData )
+{
+ OutputDebugString("OnResumeSuspend\n");
+ Pause(FALSE);
+ return TRUE;
+}
+
+
+// Dessine tous les éléments graphiques supplémentaires.
+
+void CD3DApplication::DrawSuppl()
+{
+ HDC hDC;
+ FPOINT p1, p2;
+ POINT list[3];
+ RECT rect;
+ HPEN hPen;
+ HGDIOBJ old;
+ FPOINT pos;
+ float d;
+ int nbOut;
+
+ if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return;
+
+ // Affiche le rectangle de sélection.
+ if ( m_pD3DEngine->GetHilite(p1, p2) )
+ {
+ nbOut = 0;
+ if ( p1.x < 0.0f || p1.x > 1.0f ) nbOut ++;
+ if ( p1.y < 0.0f || p1.y > 1.0f ) nbOut ++;
+ if ( p2.x < 0.0f || p2.x > 1.0f ) nbOut ++;
+ if ( p2.y < 0.0f || p2.y > 1.0f ) nbOut ++;
+ if ( nbOut <= 2 )
+ {
+#if 0
+ time = Mod(m_aTime, 0.5f);
+ if ( time < 0.25f ) d = time*4.0f;
+ else d = (2.0f-time*4.0f);
+#endif
+#if 0
+ time = Mod(m_aTime, 0.5f);
+ if ( time < 0.4f ) d = time/0.4f;
+ else d = 1.0f-(time-0.4f)/0.1f;
+#endif
+#if 1
+ d = 0.5f+sinf(m_aTime*6.0f)*0.5f;
+#endif
+ d *= (p2.x-p1.x)*0.1f;
+ p1.x += d;
+ p1.y += d;
+ p2.x -= d;
+ p2.y -= d;
+
+ hPen = CreatePen(PS_SOLID, 1, RGB(255,255,0)); // jaune
+ old = SelectObject(hDC, hPen);
+
+ rect.left = (int)(p1.x*m_ddsdRenderTarget.dwWidth);
+ rect.right = (int)(p2.x*m_ddsdRenderTarget.dwWidth);
+ rect.top = (int)((1.0f-p2.y)*m_ddsdRenderTarget.dwHeight);
+ rect.bottom = (int)((1.0f-p1.y)*m_ddsdRenderTarget.dwHeight);
+
+ list[0].x = rect.left;
+ list[0].y = rect.top+(rect.bottom-rect.top)/5;
+ list[1].x = rect.left;
+ list[1].y = rect.top;
+ list[2].x = rect.left+(rect.right-rect.left)/5;
+ list[2].y = rect.top;
+ Polyline(hDC, list, 3);
+
+ list[0].x = rect.right;
+ list[0].y = rect.top+(rect.bottom-rect.top)/5;
+ list[1].x = rect.right;
+ list[1].y = rect.top;
+ list[2].x = rect.right+(rect.left-rect.right)/5;
+ list[2].y = rect.top;
+ Polyline(hDC, list, 3);
+
+ list[0].x = rect.left;
+ list[0].y = rect.bottom+(rect.top-rect.bottom)/5;
+ list[1].x = rect.left;
+ list[1].y = rect.bottom;
+ list[2].x = rect.left+(rect.right-rect.left)/5;
+ list[2].y = rect.bottom;
+ Polyline(hDC, list, 3);
+
+ list[0].x = rect.right;
+ list[0].y = rect.bottom+(rect.top-rect.bottom)/5;
+ list[1].x = rect.right;
+ list[1].y = rect.bottom;
+ list[2].x = rect.right+(rect.left-rect.right)/5;
+ list[2].y = rect.bottom;
+ Polyline(hDC, list, 3);
+
+ if ( old != 0 ) SelectObject(hDC, old);
+ DeleteObject(hPen);
+ }
+ }
+
+ m_pddsRenderTarget->ReleaseDC(hDC);
+}
+
+// Shows frame rate and dimensions of the rendering device.
+
+VOID CD3DApplication::ShowStats()
+{
+ static FLOAT fFPS = 0.0f;
+ static FLOAT fLastTime = 0.0f;
+ static DWORD dwFrames = 0L;
+
+ // Keep track of the time lapse and frame count
+ FLOAT fTime = timeGetTime() * 0.001f; // Get current time in seconds
+ ++dwFrames;
+
+ // Update the frame rate once per second
+ if( fTime - fLastTime > 1.0f )
+ {
+ fFPS = dwFrames / (fTime - fLastTime);
+ fLastTime = fTime;
+ dwFrames = 0L;
+ }
+
+ int t = m_pD3DEngine->RetStatisticTriangle();
+
+ // Setup the text buffer to write out dimensions
+ TCHAR buffer[100];
+ sprintf( buffer, _T("%7.02f fps T=%d (%dx%dx%d)"), fFPS, t,
+ m_ddsdRenderTarget.dwWidth, m_ddsdRenderTarget.dwHeight,
+ m_ddsdRenderTarget.ddpfPixelFormat.dwRGBBitCount );
+ OutputText( 400, 2, buffer );
+
+ int x, y, i;
+ if ( m_pD3DEngine->GetSpriteCoord(x, y) )
+ {
+ OutputText( x, y, "+" );
+ }
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ char* info = m_pD3DEngine->RetInfoText(i);
+ x = 50;
+ y = m_ddsdRenderTarget.dwHeight-20-i*20;
+ OutputText( x, y, info );
+ }
+}
+
+
+// Draws text on the window.
+
+VOID CD3DApplication::OutputText( DWORD x, DWORD y, TCHAR* str )
+{
+ HDC hDC;
+
+ // Get a DC for the surface. Then, write out the buffer
+ if( m_pddsRenderTarget )
+ {
+ if( SUCCEEDED( m_pddsRenderTarget->GetDC(&hDC) ) )
+ {
+ SetTextColor( hDC, RGB(255,255,0) );
+ SetBkMode( hDC, TRANSPARENT );
+ ExtTextOut( hDC, x, y, 0, NULL, str, lstrlen(str), NULL );
+ m_pddsRenderTarget->ReleaseDC(hDC);
+ }
+ }
+}
+
+
+
+
+// Defines a function that allocates memory for and initializes
+// members within a BITMAPINFOHEADER structure
+
+PBITMAPINFO CD3DApplication::CreateBitmapInfoStruct(HBITMAP hBmp)
+{
+ BITMAP bmp;
+ PBITMAPINFO pbmi;
+ WORD cClrBits;
+
+ // Retrieve the bitmap's color format, width, and height.
+ if ( !GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp) )
+ return 0;
+
+ // Convert the color format to a count of bits.
+ cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
+
+ if ( cClrBits == 1 ) cClrBits = 1;
+ else if ( cClrBits <= 4 ) cClrBits = 4;
+ else if ( cClrBits <= 8 ) cClrBits = 8;
+ else if ( cClrBits <= 16 ) cClrBits = 16;
+ else if ( cClrBits <= 24 ) cClrBits = 24;
+ else cClrBits = 32;
+
+ // Allocate memory for the BITMAPINFO structure. (This structure
+ // contains a BITMAPINFOHEADER structure and an array of RGBQUAD data
+ // structures.)
+ if ( cClrBits != 24 )
+ {
+ pbmi = (PBITMAPINFO)LocalAlloc(LPTR,
+ sizeof(BITMAPINFOHEADER) +
+ sizeof(RGBQUAD) * (2^cClrBits));
+ }
+ // There is no RGBQUAD array for the 24-bit-per-pixel format.
+ else
+ {
+ pbmi = (PBITMAPINFO)LocalAlloc(LPTR,
+ sizeof(BITMAPINFOHEADER));
+ }
+
+ // Initialize the fields in the BITMAPINFO structure.
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biWidth = bmp.bmWidth;
+ pbmi->bmiHeader.biHeight = bmp.bmHeight;
+ pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
+ pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
+ if ( cClrBits < 24 )
+ pbmi->bmiHeader.biClrUsed = 2^cClrBits;
+
+ // If the bitmap is not compressed, set the BI_RGB flag.
+ pbmi->bmiHeader.biCompression = BI_RGB;
+
+ // Compute the number of bytes in the array of color
+ // indices and store the result in biSizeImage.
+ pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8
+ * pbmi->bmiHeader.biHeight
+ * cClrBits;
+
+ // Set biClrImportant to 0, indicating that all of the
+ // device colors are important.
+ pbmi->bmiHeader.biClrImportant = 0;
+
+ return pbmi;
+}
+
+// Defines a function that initializes the remaining structures,
+// retrieves the array of palette indices, opens the file, copies
+// the data, and closes the file.
+
+BOOL CD3DApplication::CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
+{
+ FILE* file; // file handle
+ BITMAPFILEHEADER hdr; // bitmap file-header
+ PBITMAPINFOHEADER pbih; // bitmap info-header
+ LPBYTE lpBits; // memory pointer
+ DWORD dwTotal; // total count of bytes
+
+ pbih = (PBITMAPINFOHEADER)pbi;
+ lpBits = (LPBYTE)GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
+ if ( !lpBits ) return FALSE;
+
+ // Retrieve the color table (RGBQUAD array) and the bits
+ // (array of palette indices) from the DIB.
+ if ( !GetDIBits(hDC, hBMP, 0, (WORD)pbih->biHeight,
+ lpBits, pbi, DIB_RGB_COLORS) )
+ return FALSE;
+
+ // Create the .BMP file.
+ file = fopen(pszFile, "wb");
+ if ( file == NULL ) return FALSE;
+
+ hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
+
+ // Compute the size of the entire file.
+ hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) +
+ pbih->biSize + pbih->biClrUsed
+ * sizeof(RGBQUAD) + pbih->biSizeImage);
+
+ hdr.bfReserved1 = 0;
+ hdr.bfReserved2 = 0;
+
+ // Compute the offset to the array of color indices.
+ hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) +
+ pbih->biSize + pbih->biClrUsed
+ * sizeof (RGBQUAD);
+
+ // Copy the BITMAPFILEHEADER into the .BMP file.
+ fwrite(&hdr, sizeof(BITMAPFILEHEADER), 1, file);
+
+ // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
+ fwrite(pbih, sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD), 1, file);
+
+ // Copy the array of color indices into the .BMP file.
+ dwTotal = pbih->biSizeImage;
+ fwrite(lpBits, dwTotal, 1, file);
+
+ // Close the .BMP file.
+ fclose(file);
+
+ // Free memory.
+ GlobalFree((HGLOBAL)lpBits);
+ return TRUE;
+}
+
+// Ecrit un fichier .BMP copie d'écran.
+
+BOOL CD3DApplication::WriteScreenShot(char *filename, int width, int height)
+{
+ D3DVIEWPORT7 vp;
+ HDC hDC;
+ HDC hDCImage;
+ HBITMAP hb;
+ PBITMAPINFO info;
+ int dx, dy;
+
+ m_pD3DDevice->GetViewport(&vp);
+ dx = vp.dwWidth;
+ dy = vp.dwHeight;
+
+ if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return FALSE;
+
+ hDCImage = CreateCompatibleDC(hDC);
+ if ( hDCImage == 0 )
+ {
+ m_pddsRenderTarget->ReleaseDC(hDC);
+ return FALSE;
+ }
+
+ hb = CreateCompatibleBitmap(hDC, width, height);
+ if ( hb == 0 )
+ {
+ DeleteDC(hDCImage);
+ m_pddsRenderTarget->ReleaseDC(hDC);
+ return FALSE;
+ }
+
+ SelectObject(hDCImage, hb);
+ StretchBlt(hDCImage, 0, 0, width, height, hDC, 0, 0, dx, dy, SRCCOPY);
+
+ info = CreateBitmapInfoStruct(hb);
+ if ( info == 0 )
+ {
+ DeleteObject(hb);
+ DeleteDC(hDCImage);
+ m_pddsRenderTarget->ReleaseDC(hDC);
+ return FALSE;
+ }
+
+ CreateBMPFile(filename, info, hb, hDCImage);
+
+ DeleteObject(hb);
+ DeleteDC(hDCImage);
+ m_pddsRenderTarget->ReleaseDC(hDC);
+ return TRUE;
+}
+
+
+// Initialise un hDC sur la surface de rendu.
+
+BOOL CD3DApplication::GetRenderDC(HDC &hDC)
+{
+ if ( FAILED(m_pddsRenderTarget->GetDC(&hDC)) ) return FALSE;
+ return TRUE;
+}
+
+// Libère le hDC sur la surface de rendu.
+
+BOOL CD3DApplication::ReleaseRenderDC(HDC &hDC)
+{
+ m_pddsRenderTarget->ReleaseDC(hDC);
+ return TRUE;
+}
+
+
+
+
+// Effectue la liste de tous les devices graphiques disponibles.
+// Pour le device sélectionné, donne la liste des modes plein écran
+// possibles.
+// buf* --> nom1<0> nom2<0> <0>
+
+BOOL CD3DApplication::EnumDevices(char *bufDevices, int lenDevices,
+ char *bufModes, int lenModes,
+ int &totalDevices, int &selectDevices,
+ int &totalModes, int &selectModes)
+{
+ D3DEnum_DeviceInfo* pDeviceList;
+ D3DEnum_DeviceInfo* pDevice;
+ DDSURFACEDESC2* pddsdMode;
+ DWORD numDevices, device, mode;
+ int len;
+ char text[100];
+
+ D3DEnum_GetDevices(&pDeviceList, &numDevices);
+
+ selectDevices = -1;
+ selectModes = -1;
+ totalModes = 0;
+ for( device=0 ; device<numDevices ; device++ )
+ {
+ pDevice = &pDeviceList[device];
+
+ len = strlen(pDevice->strDesc)+1;
+ if ( len >= lenDevices ) break; // bufDevices plein !
+ strcpy(bufDevices, pDevice->strDesc);
+ bufDevices += len;
+ lenDevices -= len;
+
+ if ( pDevice == m_pDeviceInfo ) // select device ?
+ {
+ selectDevices = device;
+
+ for( mode=0 ; mode<pDevice->dwNumModes ; mode++ )
+ {
+ pddsdMode = &pDevice->pddsdModes[mode];
+
+ sprintf(text, "%ld x %ld x %ld",
+ pddsdMode->dwWidth,
+ pddsdMode->dwHeight,
+ pddsdMode->ddpfPixelFormat.dwRGBBitCount);
+
+ len = strlen(text)+1;
+ if ( len >= lenModes ) break; // bufModes plein !
+ strcpy(bufModes, text);
+ bufModes += len;
+ lenModes -= len;
+
+ if ( mode == m_pDeviceInfo->dwCurrentMode ) // select mode ?
+ {
+ selectModes = mode;
+ }
+ }
+ bufModes[0] = 0;
+ totalModes = pDevice->dwNumModes;
+ }
+ }
+ bufDevices[0] = 0;
+ totalDevices = numDevices;
+
+ return TRUE;
+}
+
+// Indique si on est en mode plein écran.
+
+BOOL CD3DApplication::RetFullScreen()
+{
+ return !m_pDeviceInfo->bWindowed;
+}
+
+// Change le mode graphique.
+
+BOOL CD3DApplication::ChangeDevice(char *deviceName, char *modeName,
+ BOOL bFull)
+{
+ D3DEnum_DeviceInfo* pDeviceList;
+ D3DEnum_DeviceInfo* pDevice;
+ DDSURFACEDESC2* pddsdMode;
+ DWORD numDevices, device, mode;
+ HRESULT hr;
+ char text[100];
+
+ D3DEnum_GetDevices(&pDeviceList, &numDevices);
+
+ for( device=0 ; device<numDevices ; device++ )
+ {
+ pDevice = &pDeviceList[device];
+
+ if ( strcmp(pDevice->strDesc, deviceName) == 0 ) // device found ?
+ {
+ for( mode=0 ; mode<pDevice->dwNumModes ; mode++ )
+ {
+ pddsdMode = &pDevice->pddsdModes[mode];
+
+ sprintf(text, "%ld x %ld x %ld",
+ pddsdMode->dwWidth,
+ pddsdMode->dwHeight,
+ pddsdMode->ddpfPixelFormat.dwRGBBitCount);
+
+ if ( strcmp(text, modeName) == 0 ) // mode found ?
+ {
+ m_pDeviceInfo = pDevice;
+ pDevice->bWindowed = !bFull;
+ pDevice->dwCurrentMode = mode;
+ pDevice->ddsdFullscreenMode = pDevice->pddsdModes[mode];
+
+ m_bReady = FALSE;
+
+ if ( FAILED( hr = Change3DEnvironment() ) )
+ {
+ return FALSE;
+ }
+
+ SetProfileString("Device", "Name", deviceName);
+ SetProfileString("Device", "Mode", modeName);
+ SetProfileInt("Device", "FullScreen", bFull);
+ m_bReady = TRUE;
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+// Displays error messages in a message box.
+
+VOID CD3DApplication::DisplayFrameworkError( HRESULT hr, DWORD dwType )
+{
+ TCHAR strMsg[512];
+
+ switch( hr )
+ {
+ case D3DENUMERR_ENGINE:
+ lstrcpy( strMsg, _T("Could not create 3D Engine application!") );
+ break;
+ case D3DENUMERR_ROBOT:
+ lstrcpy( strMsg, _T("Could not create Robot application!") );
+ break;
+ case D3DENUMERR_NODIRECTDRAW:
+ lstrcpy( strMsg, _T("Could not create DirectDraw!") );
+ break;
+ case D3DENUMERR_NOCOMPATIBLEDEVICES:
+ lstrcpy( strMsg, _T("Could not find any compatible Direct3D\n"
+ "devices.") );
+ break;
+ case D3DENUMERR_SUGGESTREFRAST:
+ lstrcpy( strMsg, _T("Could not find any compatible devices.\n\n"
+ "Try enabling the reference rasterizer using\n"
+ "EnableRefRast.reg.") );
+ break;
+ case D3DENUMERR_ENUMERATIONFAILED:
+ lstrcpy( strMsg, _T("Enumeration failed. Your system may be in an\n"
+ "unstable state and need to be rebooted") );
+ break;
+ case D3DFWERR_INITIALIZATIONFAILED:
+ lstrcpy( strMsg, _T("Generic initialization error.\n\nEnable "
+ "debug output for detailed information.") );
+ break;
+ case D3DFWERR_NODIRECTDRAW:
+ lstrcpy( strMsg, _T("No DirectDraw") );
+ break;
+ case D3DFWERR_NODIRECT3D:
+ lstrcpy( strMsg, _T("No Direct3D") );
+ break;
+ case D3DFWERR_INVALIDMODE:
+ lstrcpy( strMsg, _T("COLOBOT requires a 16-bit (or higher) "
+ "display mode\nto run in a window.\n\nPlease "
+ "switch your desktop settings accordingly.") );
+ break;
+ case D3DFWERR_COULDNTSETCOOPLEVEL:
+ lstrcpy( strMsg, _T("Could not set Cooperative Level") );
+ break;
+ case D3DFWERR_NO3DDEVICE:
+ lstrcpy( strMsg, _T("Could not create the Direct3DDevice object.") );
+
+ if( MSGWARN_SWITCHEDTOSOFTWARE == dwType )
+ lstrcat( strMsg, _T("\nThe 3D hardware chipset may not support"
+ "\nrendering in the current display mode.") );
+ break;
+ case D3DFWERR_NOZBUFFER:
+ lstrcpy( strMsg, _T("No ZBuffer") );
+ break;
+ case D3DFWERR_INVALIDZBUFFERDEPTH:
+ lstrcpy( strMsg, _T("Invalid Z-buffer depth. Try switching modes\n"
+ "from 16- to 32-bit (or vice versa)") );
+ break;
+ case D3DFWERR_NOVIEWPORT:
+ lstrcpy( strMsg, _T("No Viewport") );
+ break;
+ case D3DFWERR_NOPRIMARY:
+ lstrcpy( strMsg, _T("No primary") );
+ break;
+ case D3DFWERR_NOCLIPPER:
+ lstrcpy( strMsg, _T("No Clipper") );
+ break;
+ case D3DFWERR_BADDISPLAYMODE:
+ lstrcpy( strMsg, _T("Bad display mode") );
+ break;
+ case D3DFWERR_NOBACKBUFFER:
+ lstrcpy( strMsg, _T("No backbuffer") );
+ break;
+ case D3DFWERR_NONZEROREFCOUNT:
+ lstrcpy( strMsg, _T("A DDraw object has a non-zero reference\n"
+ "count (meaning it was not properly cleaned up)." ) );
+ break;
+ case D3DFWERR_NORENDERTARGET:
+ lstrcpy( strMsg, _T("No render target") );
+ break;
+ case E_OUTOFMEMORY:
+ lstrcpy( strMsg, _T("Not enough memory!") );
+ break;
+ case DDERR_OUTOFVIDEOMEMORY:
+ lstrcpy( strMsg, _T("There was insufficient video memory "
+ "to use the\nhardware device.") );
+ break;
+ default:
+ lstrcpy( strMsg, _T("Generic application error.\n\nEnable "
+ "debug output for detailed information.") );
+ }
+
+ if( MSGERR_APPMUSTEXIT == dwType )
+ {
+ lstrcat( strMsg, _T("\n\nCOLOBOT will now exit.") );
+ MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONERROR|MB_OK );
+ }
+ else
+ {
+ if( MSGWARN_SWITCHEDTOSOFTWARE == dwType )
+ lstrcat( strMsg, _T("\n\nSwitching to software rasterizer.") );
+ MessageBox( NULL, strMsg, m_strWindowTitle, MB_ICONWARNING|MB_OK );
+ }
+}
+
+
diff --git a/src/d3dapp.h b/src/d3dapp.h
new file mode 100644
index 0000000..4808e68
--- /dev/null
+++ b/src/d3dapp.h
@@ -0,0 +1,153 @@
+// D3DApp.h
+
+
+#ifndef _D3DAPP_H
+#define _D3DAPP_H
+
+#define D3D_OVERLOADS
+
+#include <d3d.h>
+#include "D3DFrame.h"
+#include "D3DEnum.h"
+#include "D3DUtil.h"
+#include "D3DRes.h"
+
+
+
+class CInstanceManager;
+class CEvent;
+class CD3DEngine;
+class CRobotMain;
+class CSound;
+
+enum D3DMouse;
+enum Error;
+
+
+
+class CD3DApplication
+{
+public:
+ CD3DApplication();
+ ~CD3DApplication();
+
+protected:
+ LRESULT OnQuerySuspend( DWORD dwFlags );
+ LRESULT OnResumeSuspend( DWORD dwData );
+
+public:
+ Error RegQuery();
+ Error AudioQuery();
+ Error CheckMistery(char *strCmdLine);
+ int GetVidMemTotal();
+ BOOL IsVideo8MB();
+ BOOL IsVideo32MB();
+ HRESULT Create( HINSTANCE, TCHAR* );
+ INT Run();
+ LRESULT MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
+ VOID Pause( BOOL bPause );
+ FPOINT ConvPosToInterface(HWND hWnd, LPARAM lParam);
+ void SetMousePos(FPOINT pos);
+ void StepSimul(float rTime);
+ char* RetCDpath();
+
+ void SetShowStat(BOOL bShow);
+ BOOL RetShowStat();
+ void SetDebugMode(BOOL bMode);
+ BOOL RetDebugMode();
+ BOOL RetSetupMode();
+
+ 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 bFull);
+
+ void FlushPressKey();
+ void ResetKey();
+ void SetKey(int keyRank, int option, int key);
+ int RetKey(int keyRank, int option);
+
+ void SetJoystick(BOOL bEnable);
+ BOOL RetJoystick();
+
+ void SetMouseType(D3DMouse type);
+ void SetNiceMouse(BOOL bNice);
+ BOOL RetNiceMouse();
+ BOOL RetNiceMouseCap();
+
+ 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:
+ 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( DWORD x, DWORD y, TCHAR* str );
+
+protected:
+ CInstanceManager* m_iMan;
+ CEvent* m_event;
+
+ HINSTANCE m_instance;
+ HWND m_hWnd;
+ D3DEnum_DeviceInfo* m_pDeviceInfo;
+ LPDIRECTDRAW7 m_pDD;
+ LPDIRECT3D7 m_pD3D;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+ LPDIRECTDRAWSURFACE7 m_pddsRenderTarget;
+ DDSURFACEDESC2 m_ddsdRenderTarget;
+ LPDIRECTDRAWSURFACE7 m_pddsDepthBuffer;
+
+ HANDLE m_thread;
+ DWORD m_threadId;
+
+ char m_CDpath[100];
+
+ CD3DFramework7* m_pFramework;
+ BOOL m_bActive;
+ BOOL m_bActivateApp;
+ BOOL m_bReady;
+ BOOL m_bJoystick;
+
+ DWORD m_vidMemTotal;
+ TCHAR* m_strWindowTitle;
+ BOOL m_bAppUseZBuffer;
+ BOOL m_bAppUseStereo;
+ BOOL m_bShowStats;
+ BOOL m_bDebugMode;
+ BOOL m_bAudioState;
+ BOOL m_bAudioTrack;
+ BOOL m_bNiceMouse;
+ BOOL m_bSetupMode;
+ HRESULT (*m_fnConfirmDevice)(DDCAPS*, D3DDEVICEDESC7*);
+
+public:
+ CD3DEngine* m_pD3DEngine;
+ CRobotMain* m_pRobotMain;
+ CSound* m_pSound;
+
+ int m_keyState;
+ D3DVECTOR m_axeKey;
+ D3DVECTOR m_axeJoy;
+ BOOL m_bJoyButton[32];
+ FPOINT m_mousePos;
+ DWORD m_mshMouseWheel;
+
+ float m_aTime;
+ DWORD m_key[50][2];
+};
+
+
+#endif // _D3DAPP_H
diff --git a/src/d3dengine.cpp b/src/d3dengine.cpp
new file mode 100644
index 0000000..20bff34
--- /dev/null
+++ b/src/d3dengine.cpp
@@ -0,0 +1,5711 @@
+// D3DEngine.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <stdio.h>
+#include <math.h>
+
+#include "struct.h"
+#include "D3DApp.h"
+#include "D3DTextr.h"
+#include "D3DUtil.h"
+#include "D3DMath.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "iman.h"
+#include "event.h"
+#include "profile.h"
+#include "math3d.h"
+#include "object.h"
+#include "interface.h"
+#include "light.h"
+#include "text.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "cloud.h"
+#include "blitz.h"
+#include "planet.h"
+#include "sound.h"
+
+
+
+#define SIZEBLOC_TEXTURE 50
+#define SIZEBLOC_TRANSFORM 100
+#define SIZEBLOC_MINMAX 5
+#define SIZEBLOC_LIGHT 10
+#define SIZEBLOC_MATERIAL 100
+#define SIZEBLOC_TRIANGLE 200
+
+
+
+#if 0
+static int debug_blend1 = 1;
+static int debug_blend2 = 3;
+static int debug_blend3 = 8;
+static int debug_blend4 = 0;
+
+static int table_blend[13] =
+{
+ D3DBLEND_ZERO, // 0
+ D3DBLEND_ONE, // 1
+ D3DBLEND_SRCCOLOR, // 2
+ D3DBLEND_INVSRCCOLOR, // 3
+ D3DBLEND_SRCALPHA, // 4
+ D3DBLEND_INVSRCALPHA, // 5
+ D3DBLEND_DESTALPHA, // 6
+ D3DBLEND_INVDESTALPHA, // 7
+ D3DBLEND_DESTCOLOR, // 8
+ D3DBLEND_INVDESTCOLOR, // 9
+ D3DBLEND_SRCALPHASAT, // 10
+ D3DBLEND_BOTHSRCALPHA, // 11
+ D3DBLEND_BOTHINVSRCALPHA, // 12
+};
+#endif
+
+static int s_resol = 0;
+
+
+
+// Converts a FLOAT to a DWORD for use in SetRenderState() calls.
+
+inline DWORD F2DW( FLOAT f )
+{
+ return *((DWORD*)&f);
+}
+
+
+
+
+// Application constructor. Sets attributes for the app.
+
+CD3DEngine::CD3DEngine(CInstanceManager *iMan, CD3DApplication *app)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_ENGINE, this);
+ m_app = app;
+
+ m_light = new CLight(m_iMan, this);
+ m_text = new CText(m_iMan, this);
+ m_particule = new CParticule(m_iMan, this);
+ m_water = new CWater(m_iMan, this);
+ m_cloud = new CCloud(m_iMan, this);
+ m_blitz = new CBlitz(m_iMan, this);
+ m_planet = new CPlanet(m_iMan, this);
+ m_pD3DDevice = 0;
+ m_sound = 0;
+ m_terrain = 0;
+
+ m_dim.x = 640;
+ m_dim.y = 480;
+ m_lastDim = m_dim;
+ m_focus = 0.75f;
+ m_baseTime = 0;
+ m_lastTime = 0;
+ m_absTime = 0.0f;
+ m_rankView = 0;
+ m_ambiantColor[0] = 0x80808080;
+ m_ambiantColor[1] = 0x80808080;
+ m_fogColor[0] = 0xffffffff; // white
+ m_fogColor[1] = 0xffffffff; // white
+ m_deepView[0] = 1000.0f;
+ m_deepView[1] = 1000.0f;
+ m_fogStart[0] = 0.75f;
+ m_fogStart[1] = 0.75f;
+ m_waterAddColor.r = 0.0f;
+ m_waterAddColor.g = 0.0f;
+ m_waterAddColor.b = 0.0f;
+ m_waterAddColor.a = 0.0f;
+ m_bPause = FALSE;
+ m_bRender = TRUE;
+ m_bMovieLock = FALSE;
+ m_bShadow = TRUE;
+ m_bGroundSpot = TRUE;
+ m_bDirty = TRUE;
+ m_bFog = TRUE;
+ m_speed = 1.0f;
+ m_secondTexNum = 0;
+ m_eyeDirH = 0.0f;
+ m_eyeDirV = 0.0f;
+ m_backgroundName[0] = 0; // pas d'image de fond
+ m_backgroundColorUp = 0;
+ m_backgroundColorDown = 0;
+ m_backgroundCloudUp = 0;
+ m_backgroundCloudDown = 0;
+ m_bBackgroundFull = FALSE;
+ m_bBackgroundQuarter = FALSE;
+ m_bOverFront = TRUE;
+ m_overColor = 0;
+ m_overMode = D3DSTATETCb;
+ m_frontsizeName[0] = 0; // pas d'image de devant
+ m_hiliteRank[0] = -1; // liste vide
+ m_mousePos = FPOINT(0.5f, 0.5f);
+ m_mouseType = D3DMOUSENORM;
+ m_bMouseHide = FALSE;
+ m_imageSurface = 0;
+ m_imageCopy = 0;
+ m_eyePt = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_lookatPt = D3DVECTOR(0.0f, 0.0f, 1.0f);
+ m_bDrawWorld = TRUE;
+ m_bDrawFront = 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_bTotoMode = TRUE;
+ m_bLensMode = TRUE;
+ m_bWaterMode = TRUE;
+ m_bSkyMode = TRUE;
+ m_bBackForce = TRUE;
+ m_bPlanetMode = TRUE;
+ m_bLightMode = TRUE;
+ m_bEditIndentMode = TRUE;
+ m_editIndentValue = 4;
+ m_tracePrecision = 1.0f;
+
+ m_alphaMode = 1;
+ if ( GetProfileInt("Engine", "AlphaMode", i) )
+ {
+ m_alphaMode = i;
+ }
+
+ if ( GetProfileInt("Engine", "StateColor", i) && i != -1 )
+ {
+ m_bForceStateColor = TRUE;
+ m_bStateColor = i;
+ }
+ else
+ {
+ m_bForceStateColor = FALSE;
+ m_bStateColor = 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;
+
+ if ( GetProfileInt("Engine", "BlackSrcBlend", i) ) m_blackSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "BlackDestBlend", i) ) m_blackDestBlend[0] = i;
+ if ( GetProfileInt("Engine", "WhiteSrcBlend", i) ) m_whiteSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "WhiteDestBlend", i) ) m_whiteDestBlend[0] = i;
+ if ( GetProfileInt("Engine", "DiffuseSrcBlend", i) ) m_diffuseSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "DiffuseDestBlend", i) ) m_diffuseDestBlend[0] = i;
+ if ( GetProfileInt("Engine", "AlphaSrcBlend", i) ) m_alphaSrcBlend[0] = i;
+ if ( GetProfileInt("Engine", "AlphaDestBlend", i) ) m_alphaDestBlend[0] = i;
+
+ m_bUpdateGeometry = FALSE;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ m_infoText[i][0] = 0;
+ }
+
+ m_objectPointer = 0;
+ MemSpace1(m_objectPointer, 0);
+
+ m_objectParam = (D3DObject*)malloc(sizeof(D3DObject)*D3DMAXOBJECT);
+ ZeroMemory(m_objectParam, sizeof(D3DObject)*D3DMAXOBJECT);
+ m_objectParamTotal = 0;
+
+ m_shadow = (D3DShadow*)malloc(sizeof(D3DShadow)*D3DMAXSHADOW);
+ ZeroMemory(m_shadow, sizeof(D3DShadow)*D3DMAXSHADOW);
+ m_shadowTotal = 0;
+
+ m_groundSpot = (D3DGroundSpot*)malloc(sizeof(D3DGroundSpot)*D3DMAXGROUNDSPOT);
+ ZeroMemory(m_groundSpot, sizeof(D3DGroundSpot)*D3DMAXGROUNDSPOT);
+
+ ZeroMemory(&m_groundMark, sizeof(D3DGroundMark));
+
+ D3DTextr_SetTexturePath("textures\\");
+}
+
+// Application destructor. Free memory.
+
+CD3DEngine::~CD3DEngine()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ free(p6);
+ }
+ free(p5);
+ }
+ free(p4);
+ }
+ free(p3);
+ }
+ free(p2);
+ }
+ free(p1);
+
+ delete m_light;
+ delete m_particule;
+ delete m_water;
+ delete m_cloud;
+ delete m_blitz;
+ delete m_planet;
+}
+
+
+
+void CD3DEngine::SetD3DDevice(LPDIRECT3DDEVICE7 device)
+{
+ D3DDEVICEDESC7 ddDesc;
+
+ m_pD3DDevice = device;
+ m_light->SetD3DDevice(device);
+ m_text->SetD3DDevice(device);
+ m_particule->SetD3DDevice(device);
+
+ if ( !m_bForceStateColor )
+ {
+ m_pD3DDevice->GetCaps(&ddDesc);
+ if( ddDesc.dpcTriCaps.dwTextureBlendCaps & D3DPTBLENDCAPS_ADD )
+ {
+ m_bStateColor = TRUE;
+ }
+ else
+ {
+ m_bStateColor = FALSE;
+ }
+ }
+
+ m_blackSrcBlend[1] = D3DBLEND_ONE; // = 2
+ m_blackDestBlend[1] = D3DBLEND_INVSRCCOLOR; // = 4
+ m_whiteSrcBlend[1] = D3DBLEND_DESTCOLOR; // = 9
+ m_whiteDestBlend[1] = D3DBLEND_ZERO; // = 1
+ m_diffuseSrcBlend[1] = D3DBLEND_SRCALPHA; // = 5
+ m_diffuseDestBlend[1] = D3DBLEND_DESTALPHA; // = 7
+ m_alphaSrcBlend[1] = D3DBLEND_ONE; // = 2
+ m_alphaDestBlend[1] = D3DBLEND_INVSRCCOLOR; // = 4
+
+//? if ( !m_bStateColor ) m_whiteDestBlend[1] = D3DBLEND_INVSRCALPHA; // = 6
+
+ if ( m_blackSrcBlend[0] ) m_blackSrcBlend[1] = m_blackSrcBlend[0];
+ if ( m_blackDestBlend[0] ) m_blackDestBlend[1] = m_blackDestBlend[0];
+ if ( m_whiteSrcBlend[0] ) m_whiteSrcBlend[1] = m_whiteSrcBlend[0];
+ if ( m_whiteDestBlend[0] ) m_whiteDestBlend[1] = m_whiteDestBlend[0];
+ if ( m_diffuseSrcBlend[0] ) m_diffuseSrcBlend[1] = m_diffuseSrcBlend[0];
+ if ( m_diffuseDestBlend[0] ) m_diffuseDestBlend[1] = m_diffuseDestBlend[0];
+ if ( m_alphaSrcBlend[0] ) m_alphaSrcBlend[1] = m_alphaSrcBlend[0];
+ if ( m_alphaDestBlend[0] ) m_alphaDestBlend[1] = m_alphaDestBlend[0];
+
+#if 0
+ DWORD pass;
+ m_pD3DDevice->ValidateDevice(&pass);
+ char s[100];
+ sprintf(s, "NbPass=%d", pass);
+ SetInfoText(3, s);
+#endif
+}
+
+LPDIRECT3DDEVICE7 CD3DEngine::RetD3DDevice()
+{
+ return m_pD3DDevice;
+}
+
+
+// Donne le pointeur au terrain existant.
+
+void CD3DEngine::SetTerrain(CTerrain* terrain)
+{
+ m_terrain = terrain;
+}
+
+
+// Sauvegarde l'état du moteur graphique dans COLOBOT.INI.
+
+BOOL CD3DEngine::WriteProfile()
+{
+ SetProfileInt("Engine", "AlphaMode", m_alphaMode);
+
+ if ( m_bForceStateColor )
+ {
+ SetProfileInt("Engine", "StateColor", m_bStateColor);
+ }
+ else
+ {
+ SetProfileInt("Engine", "StateColor", -1);
+ }
+
+ SetProfileInt("Engine", "BlackSrcBlend", m_blackSrcBlend[0]);
+ SetProfileInt("Engine", "BlackDestBlend", m_blackDestBlend[0]);
+ SetProfileInt("Engine", "WhiteSrcBlend", m_whiteSrcBlend[0]);
+ SetProfileInt("Engine", "WhiteDestBlend", m_whiteDestBlend[0]);
+ SetProfileInt("Engine", "DiffuseSrcBlend", m_diffuseSrcBlend[0]);
+ SetProfileInt("Engine", "DiffuseDestBlend", m_diffuseDestBlend[0]);
+ SetProfileInt("Engine", "AlphaSrcBlend", m_alphaSrcBlend[0]);
+ SetProfileInt("Engine", "AlphaDestBlend", m_alphaDestBlend[0]);
+
+ return TRUE;
+}
+
+
+// Setup the app so it can support single-stepping.
+
+void CD3DEngine::TimeInit()
+{
+ m_baseTime = timeGetTime();
+ m_lastTime = 0;
+ m_absTime = 0.0f;
+}
+
+void CD3DEngine::TimeEnterGel()
+{
+ m_stopTime = timeGetTime();
+}
+
+void CD3DEngine::TimeExitGel()
+{
+ m_baseTime += timeGetTime() - m_stopTime;
+}
+
+float CD3DEngine::TimeGet()
+{
+ float aTime, rTime;
+
+ aTime = (timeGetTime()-m_baseTime)*0.001f; // en ms
+ rTime = (aTime - m_lastTime)*m_speed;
+ m_absTime += rTime;
+ m_lastTime = aTime;
+
+ return rTime;
+}
+
+
+void CD3DEngine::SetPause(BOOL bPause)
+{
+ m_bPause = bPause;
+}
+
+BOOL CD3DEngine::RetPause()
+{
+ return m_bPause;
+}
+
+
+void CD3DEngine::SetMovieLock(BOOL bLock)
+{
+ m_bMovieLock = bLock;
+}
+
+BOOL CD3DEngine::RetMovieLock()
+{
+ return m_bMovieLock;
+}
+
+
+void CD3DEngine::SetShowStat(BOOL bShow)
+{
+ m_app->SetShowStat(bShow);
+}
+
+BOOL CD3DEngine::RetShowStat()
+{
+ return m_app->RetShowStat();
+}
+
+
+void CD3DEngine::SetRenderEnable(BOOL bEnable)
+{
+ m_bRender = bEnable;
+}
+
+
+// Prépare une structure D3DObjLevel6 pour pouvoir ajouter
+// qq éléments D3DVERTEX2.
+
+void CD3DEngine::MemSpace6(D3DObjLevel6 *&p, int nb)
+{
+ D3DObjLevel6* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_TRIANGLE+nb;
+ size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1);
+ p = (D3DObjLevel6*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_TRIANGLE+nb;
+ size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1);
+ pp = (D3DObjLevel6*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prépare une structure D3DObjLevel5 pour pouvoir ajouter
+// qq éléments D3DObjLevel6.
+
+void CD3DEngine::MemSpace5(D3DObjLevel5 *&p, int nb)
+{
+ D3DObjLevel5* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_MATERIAL+nb;
+ size = sizeof(D3DObjLevel5)+sizeof(D3DObjLevel6*)*(total-1);
+ p = (D3DObjLevel5*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_MATERIAL+nb;
+ size = sizeof(D3DObjLevel5)+sizeof(D3DObjLevel6*)*(total-1);
+ pp = (D3DObjLevel5*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel5)+sizeof(D3DObjLevel6*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prépare une structure D3DObjLevel4 pour pouvoir ajouter
+// qq éléments D3DObjLevel5.
+
+void CD3DEngine::MemSpace4(D3DObjLevel4 *&p, int nb)
+{
+ D3DObjLevel4* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_LIGHT+nb;
+ size = sizeof(D3DObjLevel4)+sizeof(D3DObjLevel5*)*(total-1);
+ p = (D3DObjLevel4*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_LIGHT+nb;
+ size = sizeof(D3DObjLevel4)+sizeof(D3DObjLevel5*)*(total-1);
+ pp = (D3DObjLevel4*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel4)+sizeof(D3DObjLevel5*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prépare une structure D3DObjLevel3 pour pouvoir ajouter
+// qq éléments D3DObjLevel4.
+
+void CD3DEngine::MemSpace3(D3DObjLevel3 *&p, int nb)
+{
+ D3DObjLevel3* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_MINMAX+nb;
+ size = sizeof(D3DObjLevel3)+sizeof(D3DObjLevel4*)*(total-1);
+ p = (D3DObjLevel3*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_MINMAX+nb;
+ size = sizeof(D3DObjLevel3)+sizeof(D3DObjLevel4*)*(total-1);
+ pp = (D3DObjLevel3*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel3)+sizeof(D3DObjLevel4*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prépare une structure D3DObjLevel2 pour pouvoir ajouter
+// qq éléments D3DObjLevel3.
+
+void CD3DEngine::MemSpace2(D3DObjLevel2 *&p, int nb)
+{
+ D3DObjLevel2* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_TRANSFORM+nb;
+ size = sizeof(D3DObjLevel2)+sizeof(D3DObjLevel3*)*(total-1);
+ p = (D3DObjLevel2*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_TRANSFORM+nb;
+ size = sizeof(D3DObjLevel2)+sizeof(D3DObjLevel3*)*(total-1);
+ pp = (D3DObjLevel2*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel2)+sizeof(D3DObjLevel3*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+// Prépare une structure D3DObjLevel1 pour pouvoir ajouter
+// qq éléments D3DObjLevel2.
+
+void CD3DEngine::MemSpace1(D3DObjLevel1 *&p, int nb)
+{
+ D3DObjLevel1* pp;
+ int total, size;
+
+ if ( p == 0 )
+ {
+ total = SIZEBLOC_TEXTURE+nb;
+ size = sizeof(D3DObjLevel1)+sizeof(D3DObjLevel2*)*(total-1);
+ p = (D3DObjLevel1*)malloc(size);
+ ZeroMemory(p, size);
+ p->totalPossible = total;
+ return;
+ }
+
+ if ( p->totalUsed+nb > p->totalPossible )
+ {
+ total = p->totalPossible+SIZEBLOC_TEXTURE+nb;
+ size = sizeof(D3DObjLevel1)+sizeof(D3DObjLevel2*)*(total-1);
+ pp = (D3DObjLevel1*)malloc(size);
+ ZeroMemory(pp, size);
+ CopyMemory(pp, p, sizeof(D3DObjLevel1)+sizeof(D3DObjLevel2*)*(p->totalPossible-1));
+ pp->totalPossible = total;
+ free(p);
+ p = pp;
+ }
+}
+
+
+// Retourne le nombre d'objets qu'il est encore possible de créer.
+
+int CD3DEngine::RetRestCreate()
+{
+ return D3DMAXOBJECT-m_objectParamTotal-2;
+}
+
+// Crée un nouvel objet. Retourne son rang ou -1 en cas d'erreur.
+
+int CD3DEngine::CreateObject()
+{
+ D3DMATRIX mat;
+ int i;
+
+ for ( i=0 ; i<D3DMAXOBJECT ; i++ )
+ {
+ if ( m_objectParam[i].bUsed == FALSE )
+ {
+ ZeroMemory(&m_objectParam[i], sizeof(D3DObject));
+ m_objectParam[i].bUsed = TRUE;
+
+ D3DUtil_SetIdentityMatrix(mat);
+ SetObjectTransform(i, mat);
+
+ m_objectParam[i].bDrawWorld = TRUE;
+ m_objectParam[i].distance = 0.0f;
+ m_objectParam[i].bboxMin = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_objectParam[i].bboxMax = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_objectParam[i].shadowRank = -1;
+
+ if ( i >= m_objectParamTotal )
+ {
+ m_objectParamTotal = i+1;
+ }
+ return i;
+ }
+ }
+ OutputDebugString("CD3DEngine::CreateObject() -> Too many object\n");
+ return -1;
+}
+
+
+// Supprime tous les objets.
+
+void CD3DEngine::FlushObject()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5, i;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ free(p6);
+ }
+ free(p5);
+ }
+ free(p4);
+ }
+ free(p3);
+ }
+ free(p2);
+ p1->table[l1] = 0;
+ }
+ p1->totalUsed = 0;
+
+ for ( i=0 ; i<D3DMAXOBJECT ; i++ )
+ {
+ m_objectParam[i].bUsed = FALSE;
+ }
+ m_objectParamTotal = 0;
+
+ ZeroMemory(m_shadow, sizeof(D3DShadow)*D3DMAXSHADOW);
+ m_shadowTotal = 0;
+
+ GroundSpotFlush();
+}
+
+// Détruit un objet existant.
+
+BOOL CD3DEngine::DeleteObject(int objRank)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5, i;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ free(p6);
+ }
+ free(p5);
+ }
+ free(p4);
+ }
+ free(p3);
+ p2->table[l2] = 0;
+ }
+ }
+
+ ShadowDelete(objRank); // supprime l'ombre
+
+ m_objectParam[objRank].bUsed = FALSE;
+
+ m_objectParamTotal = 0;
+ for ( i=0 ; i<D3DMAXOBJECT ; i++ )
+ {
+ if ( m_objectParam[i].bUsed )
+ {
+ m_objectParamTotal = i+1;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Indique si un objet doit être dessiné par dessous l'interface.
+
+BOOL CD3DEngine::SetDrawWorld(int objRank, BOOL bDraw)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].bDrawWorld = bDraw;
+ return TRUE;
+}
+
+// Indique si un objet doit être dessiné par dessus l'interface.
+
+BOOL CD3DEngine::SetDrawFront(int objRank, BOOL bDraw)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].bDrawFront = bDraw;
+ return TRUE;
+}
+
+
+// Prépare le niveau 1 pour ajouter un triangle.
+
+D3DObjLevel2* CD3DEngine::AddLevel1(D3DObjLevel1 *&p1, char* texName1, char* texName2)
+{
+ D3DObjLevel2* p2;
+ int l1;
+
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ if ( strcmp(p2->texName1, texName1) == 0 &&
+ strcmp(p2->texName2, texName2) == 0 )
+ {
+ MemSpace2(p1->table[l1], 1);
+ return p1->table[l1];
+ }
+ }
+
+ MemSpace1(p1, 1);
+ l1 = p1->totalUsed++;
+ p1->table[l1] = 0;
+
+ MemSpace2(p1->table[l1], 1);
+ strcpy(p1->table[l1]->texName1, texName1);
+ strcpy(p1->table[l1]->texName2, texName2);
+ return p1->table[l1];
+}
+
+// Prépare le niveau 2 pour ajouter un triangle.
+
+D3DObjLevel3* CD3DEngine::AddLevel2(D3DObjLevel2 *&p2, int objRank)
+{
+ D3DObjLevel3* p3;
+ int l2;
+
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank == objRank )
+ {
+ MemSpace3(p2->table[l2], 1);
+ return p2->table[l2];
+ }
+ }
+
+ MemSpace2(p2, 1);
+ l2 = p2->totalUsed++;
+ p2->table[l2] = 0;
+
+ MemSpace3(p2->table[l2], 1);
+ p2->table[l2]->objRank = objRank;
+ return p2->table[l2];
+}
+
+// Prépare le niveau 3 pour ajouter un triangle.
+
+D3DObjLevel4* CD3DEngine::AddLevel3(D3DObjLevel3 *&p3, float min, float max)
+{
+ D3DObjLevel4* p4;
+ int l3;
+
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min == min && p4->max == max )
+ {
+ MemSpace4(p3->table[l3], 1);
+ return p3->table[l3];
+ }
+ }
+
+ MemSpace3(p3, 1);
+ l3 = p3->totalUsed++;
+ p3->table[l3] = 0;
+
+ MemSpace4(p3->table[l3], 1);
+ p3->table[l3]->min = min;
+ p3->table[l3]->max = max;
+ return p3->table[l3];
+}
+
+// Prépare le niveau 4 pour ajouter un triangle.
+
+D3DObjLevel5* CD3DEngine::AddLevel4(D3DObjLevel4 *&p4, int reserve)
+{
+ D3DObjLevel5* p5;
+ int l4;
+
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ if ( p5->reserve == reserve )
+ {
+ MemSpace5(p4->table[l4], 1);
+ return p4->table[l4];
+ }
+ }
+
+ MemSpace4(p4, 1);
+ l4 = p4->totalUsed++;
+ p4->table[l4] = 0;
+
+ MemSpace5(p4->table[l4], 1);
+ p4->table[l4]->reserve = reserve;
+ return p4->table[l4];
+}
+
+// Prépare le niveau 5 pour ajouter des vertex.
+
+D3DObjLevel6* CD3DEngine::AddLevel5(D3DObjLevel5 *&p5, D3DTypeTri type,
+ const D3DMATERIAL7 &mat, int state,
+ int nb)
+{
+ D3DObjLevel6* p6;
+ int l5;
+
+ if ( type == D3DTYPE6T )
+ {
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ if ( p6->type == type &&
+ memcmp(&p6->material, &mat, sizeof(D3DMATERIAL7)) == 0 &&
+ p6->state == state )
+ {
+ MemSpace6(p5->table[l5], nb);
+ return p5->table[l5];
+ }
+ }
+ }
+
+ MemSpace5(p5, 1);
+ l5 = p5->totalUsed++;
+ p5->table[l5] = 0;
+
+ MemSpace6(p5->table[l5], nb);
+ p5->table[l5]->type = type;
+ p5->table[l5]->material = mat;
+ p5->table[l5]->state = state;
+ return p5->table[l5];
+}
+
+// Ajoute un ou plusieurs triangles à un objet existant.
+// Le nombre doit être multiple de 3.
+
+BOOL CD3DEngine::AddTriangle(int objRank, D3DVERTEX2* vertex, int nb,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max, BOOL bGlobalUpdate)
+{
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int i;
+
+ m_lastDim = m_dim;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+
+ p2 = AddLevel1(m_objectPointer, texName1, texName2);
+ p3 = AddLevel2(p2, objRank);
+ p4 = AddLevel3(p3, min, max);
+ p5 = AddLevel4(p4, 0);
+ p6 = AddLevel5(p5, D3DTYPE6T, mat, state, nb); // place pour nb vertex
+
+ CopyMemory(&p6->vertex[p6->totalUsed], vertex, sizeof(D3DVERTEX2)*nb);
+ p6->totalUsed += nb;
+
+ if ( bGlobalUpdate )
+ {
+ m_bUpdateGeometry = TRUE;
+ }
+ else
+ {
+ for ( i=0 ; i<nb ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ m_objectParam[objRank].totalTriangle += nb/3;
+
+ return TRUE;
+}
+
+// Ajoute une surface constituée de triangles jointifs.
+
+BOOL CD3DEngine::AddSurface(int objRank, D3DVERTEX2* vertex, int nb,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max, BOOL bGlobalUpdate)
+{
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int i;
+
+ p2 = AddLevel1(m_objectPointer, texName1, texName2);
+ p3 = AddLevel2(p2, objRank);
+ p4 = AddLevel3(p3, min, max);
+ p5 = AddLevel4(p4, 0);
+ p6 = AddLevel5(p5, D3DTYPE6S, mat, state, nb); // place pour nb vertex
+
+ CopyMemory(&p6->vertex[p6->totalUsed], vertex, sizeof(D3DVERTEX2)*nb);
+ p6->totalUsed += nb;
+
+ if ( bGlobalUpdate )
+ {
+ m_bUpdateGeometry = TRUE;
+ }
+ else
+ {
+ for ( i=0 ; i<nb ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ m_objectParam[objRank].totalTriangle += nb-2;
+
+ return TRUE;
+}
+
+// Ajoute une surface constituée de triangles jointifs.
+// Le buffer n'est pas copié.
+
+BOOL CD3DEngine::AddQuick(int objRank, D3DObjLevel6* buffer,
+ char* texName1, char* texName2,
+ float min, float max, BOOL bGlobalUpdate)
+{
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ int l5, i;
+
+ p2 = AddLevel1(m_objectPointer, texName1, texName2);
+ p3 = AddLevel2(p2, objRank);
+ p4 = AddLevel3(p3, min, max);
+ p5 = AddLevel4(p4, 0);
+
+ MemSpace5(p5, 1);
+ l5 = p5->totalUsed++;
+ p5->table[l5] = buffer;
+
+ if ( bGlobalUpdate )
+ {
+ m_bUpdateGeometry = TRUE;
+ }
+ else
+ {
+ for ( i=0 ; i<buffer->totalUsed ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(buffer->vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(buffer->vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(buffer->vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(buffer->vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(buffer->vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(buffer->vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ m_objectParam[objRank].totalTriangle += buffer->totalUsed-2;
+
+ return TRUE;
+}
+
+
+// Cherche une liste de triangles.
+
+void CD3DEngine::ChangeLOD()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ int l1, l2, l3;
+ float oldLimit[2], newLimit[2];
+ float oldTerrain, newTerrain;
+
+ oldLimit[0] = RetLimitLOD(0, TRUE);
+ oldLimit[1] = RetLimitLOD(1, TRUE);
+
+ newLimit[0] = RetLimitLOD(0, FALSE);
+ newLimit[1] = RetLimitLOD(1, FALSE);
+
+ oldTerrain = m_terrainVision*m_lastClippingDistance;
+ newTerrain = m_terrainVision*m_clippingDistance;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+
+ if ( IsEqual(p4->min, 0.0f ) &&
+ IsEqual(p4->max, oldLimit[0]) )
+ {
+ p4->max = newLimit[0];
+ }
+ else if ( IsEqual(p4->min, oldLimit[0]) &&
+ IsEqual(p4->max, oldLimit[1]) )
+ {
+ p4->min = newLimit[0];
+ p4->max = newLimit[1];
+ }
+ else if ( IsEqual(p4->min, oldLimit[1]) &&
+ IsEqual(p4->max, 1000000.0f ) )
+ {
+ p4->min = newLimit[1];
+ }
+ else if ( IsEqual(p4->min, 0.0f ) &&
+ IsEqual(p4->max, oldTerrain) )
+ {
+ p4->max = newTerrain;
+ }
+ }
+ }
+ }
+
+ m_lastDim = m_dim;
+ m_lastObjectDetail = m_objectDetail;
+ m_lastClippingDistance = m_clippingDistance;
+}
+
+// Cherche une liste de triangles.
+
+D3DObjLevel6* CD3DEngine::SearchTriangle(int objRank,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+//? if ( strcmp(p2->texName1, texName1) != 0 ||
+//? strcmp(p2->texName2, texName2) != 0 ) continue;
+ if ( strcmp(p2->texName1, texName1) != 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min != min ||
+ p4->max != max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+//? if ( p6->state != state ||
+ if ( (p6->state&(~(D3DSTATEDUALb|D3DSTATEDUALw))) != state ||
+ memcmp(&p6->material, &mat, sizeof(D3DMATERIAL7)) != 0 ) continue;
+ return p6;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+// Change la texture secondaire d'un objet.
+
+BOOL CD3DEngine::ChangeSecondTexture(int objRank, char* texName2)
+{
+ D3DObjLevel2* newp2;
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ int l1, l2;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ if ( strcmp(p2->texName2, texName2) == 0 ) continue; // déjà nouvelle
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+
+ newp2 = AddLevel1(m_objectPointer, p2->texName1, texName2);
+
+ if ( newp2->totalUsed >= newp2->totalPossible ) continue; // faire mieux !!!
+ newp2->table[newp2->totalUsed++] = p3;
+
+ p2->table[l2] = 0;
+ }
+ }
+ return TRUE;
+}
+
+
+// Retourne le nombre de triangles de l'objet.
+
+int CD3DEngine::RetTotalTriangles(int objRank)
+{
+ return m_objectParam[objRank].totalTriangle;
+}
+
+// Retourne qq triangles d'un objet. Utilisé pour extraire qq
+// triangles d'un objet qui explose.
+// "percent" est compris entre 0 et 1.
+
+int CD3DEngine::GetTriangles(int objRank, float min, float max,
+ D3DTriangle* buffer, int size, float percent)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, l6, i, rank;
+
+ rank = 0;
+ i = 0;
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+//? if ( p2->texName[0] == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ if ( p3->objRank != objRank ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min != min ||
+ p4->max != max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ for ( l6=0 ; l6<p6->totalUsed/3 ; l6++ )
+ {
+ if ( (float)i/rank <= percent )
+ {
+ if ( i >= size ) break;
+ buffer[i].triangle[0] = pv[0];
+ buffer[i].triangle[1] = pv[1];
+ buffer[i].triangle[2] = pv[2];
+ buffer[i].material = p6->material;
+ buffer[i].state = p6->state;
+ strcpy(buffer[i].texName1, p2->texName1);
+ strcpy(buffer[i].texName2, p2->texName2);
+ i ++;
+ }
+ rank ++;
+ pv += 3;
+ }
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ for ( l6=0 ; l6<p6->totalUsed-2 ; l6++ )
+ {
+ if ( (float)i/rank <= percent )
+ {
+ if ( i >= size ) break;
+ buffer[i].triangle[0] = pv[0];
+ buffer[i].triangle[1] = pv[1];
+ buffer[i].triangle[2] = pv[2];
+ buffer[i].material = p6->material;
+ buffer[i].state = p6->state;
+ strcpy(buffer[i].texName1, p2->texName1);
+ strcpy(buffer[i].texName2, p2->texName2);
+ i ++;
+ }
+ rank ++;
+ pv += 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return i;
+}
+
+// Donne la bbox d'un objet.
+
+BOOL CD3DEngine::GetBBox(int objRank, D3DVECTOR &min, D3DVECTOR &max)
+{
+ min = m_objectParam[objRank].bboxMin;
+ max = m_objectParam[objRank].bboxMax;
+ return TRUE;
+}
+
+
+// Change le mapping de texture pour toute une liste de triangles.
+
+BOOL CD3DEngine::ChangeTextureMapping(int objRank,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max,
+ D3DMaping mode,
+ float au, float bu,
+ float av, float bv)
+{
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l6, nb;
+
+ p6 = SearchTriangle(objRank, mat, state, texName1, texName2, min, max);
+ if ( p6 == 0 ) return FALSE;
+
+ pv = &p6->vertex[0];
+ nb = p6->totalUsed;
+
+ if ( mode == D3DMAPPINGX )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->z*au+bu;
+ pv->tv = pv->y*av+bv;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPINGY )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->x*au+bu;
+ pv->tv = pv->z*av+bv;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPINGZ )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->x*au+bu;
+ pv->tv = pv->y*av+bv;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPING1X )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->x*au+bu;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPING1Y )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tv = pv->y*au+bu;
+ pv ++;
+ }
+ }
+
+ if ( mode == D3DMAPPING1Z )
+ {
+ for ( l6=0 ; l6<nb ; l6++ )
+ {
+ pv->tu = pv->z*au+bu;
+ pv ++;
+ }
+ }
+
+ return TRUE;
+}
+
+// Change le mapping de texture pour toute une liste de triangles,
+// afin de simuler une chenille qui tourne.
+// Seul le mapping selon "u" est changé.
+//
+// pos: position sur le pourtour [p]
+// tl: longeur élément répétitif de la texture [t]
+// ts: début de la texture [t]
+// tt: largeur totale de la texture [t]
+//
+// [p] = distance dans l'univers 3D
+// [t] = position dans la texture (pixels)
+
+// ^ y 5
+// | 6 o---------o 4
+// | / \
+// | o o
+// | 7 | | 3
+// | o current o
+// | \ | /
+// | 0 o---------o 2
+// | 1
+// -o-----------------------> x
+// |
+//
+// Quand l6=1 :
+// 0 1 2 3 4 ... 7
+// o--o---------o--o--o--o-//-o--o développement chenille
+// |ps| |
+// <--> pe |
+// <------------>
+//
+// Texture :
+// o---------------o
+// | |
+// | o-o-o-o-o |
+// | | | | | |<--- texture de la chenille
+// | o-o-o-o-o |
+// | | | tl |
+// | ->|-|<--- |
+// | | |
+// o-----|---------o--> u
+// | ts | |
+// <-----> tt |
+// <--------------->
+
+BOOL CD3DEngine::TrackTextureMapping(int objRank,
+ const D3DMATERIAL7 &mat, int state,
+ char* texName1, char* texName2,
+ float min, float max,
+ D3DMaping mode, float pos, float factor,
+ float tl, float ts, float tt)
+{
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ D3DVECTOR current;
+ float ps, pe, pps, ppe, offset;
+ int l6, nb, i, j, s, e;
+ int is[6], ie[6];
+
+ p6 = SearchTriangle(objRank, mat, state, texName1, texName2, min, max);
+ if ( p6 == 0 ) return FALSE;
+
+ pv = &p6->vertex[0];
+ nb = p6->totalUsed;
+
+ if ( nb < 12 || nb%6 != 0 ) return FALSE;
+
+ while ( pos < 0.0f )
+ {
+ pos += 1000000.0f; // jamais négatif !
+ }
+
+ for ( i=0 ; i<6 ; i++ )
+ {
+ for ( j=0 ; j<6 ; j++ )
+ {
+ if ( pv[i].x == pv[j+6].x &&
+ pv[i].y == pv[j+6].y )
+ {
+ current.x = pv[i].x; // position fin maillon
+ current.y = pv[i].y;
+ break;
+ }
+ }
+ }
+
+ ps = 0.0f; // position de début sur le pourtour
+ for ( l6=0 ; l6<nb/6 ; l6++ )
+ {
+ s = e = 0;
+ for ( i=0 ; i<6 ; i++ )
+ {
+ if ( Abs(pv[i].x-current.x) < 0.0001f &&
+ Abs(pv[i].y-current.y) < 0.0001f )
+ {
+ ie[e++] = i;
+ }
+ else
+ {
+ is[s++] = i;
+ }
+ }
+ if ( s == 3 && e == 3 )
+ {
+ pe = ps+Length(pv[is[0]].x-pv[ie[0]].x,
+ pv[is[0]].y-pv[ie[0]].y)/factor; // position de fin sur le pourtour
+
+ pps = ps+pos;
+ ppe = pe+pos;
+ offset = (float)((int)pps);
+ pps -= offset;
+ ppe -= offset;
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ pv[is[i]].tu = ((pps*tl)+ts)/tt;
+ pv[ie[i]].tu = ((ppe*tl)+ts)/tt;
+ }
+ }
+
+ if ( l6 >= (nb/6)-1 ) break;
+ for ( i=0 ; i<6 ; i++ )
+ {
+ if ( Abs(pv[i+6].x-current.x) > 0.0001f ||
+ Abs(pv[i+6].y-current.y) > 0.0001f )
+ {
+ current.x = pv[i+6].x; // fin maillon suivant
+ current.y = pv[i+6].y;
+ break;
+ }
+ }
+ ps = pe; // position de début suivante sur le pourtour
+ pv += 6;
+ }
+
+ return TRUE;
+}
+
+
+// Met à jour tous les paramètres géométriques des objets.
+
+void CD3DEngine::UpdateGeometry()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ int l1, l2, l3, l4, l5, objRank, i;
+
+ if ( !m_bUpdateGeometry ) return;
+
+ for ( i=0 ; i<m_objectParamTotal ; i++ )
+ {
+ m_objectParam[i].bboxMin.x = 0;
+ m_objectParam[i].bboxMin.y = 0;
+ m_objectParam[i].bboxMin.z = 0;
+ m_objectParam[i].bboxMax.x = 0;
+ m_objectParam[i].bboxMax.y = 0;
+ m_objectParam[i].bboxMax.z = 0;
+ m_objectParam[i].radius = 0;
+ }
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+
+ for ( i=0 ; i<p6->totalUsed ; i++ )
+ {
+ m_objectParam[objRank].bboxMin.x = Min(p6->vertex[i].x, m_objectParam[objRank].bboxMin.x);
+ m_objectParam[objRank].bboxMin.y = Min(p6->vertex[i].y, m_objectParam[objRank].bboxMin.y);
+ m_objectParam[objRank].bboxMin.z = Min(p6->vertex[i].z, m_objectParam[objRank].bboxMin.z);
+ m_objectParam[objRank].bboxMax.x = Max(p6->vertex[i].x, m_objectParam[objRank].bboxMax.x);
+ m_objectParam[objRank].bboxMax.y = Max(p6->vertex[i].y, m_objectParam[objRank].bboxMax.y);
+ m_objectParam[objRank].bboxMax.z = Max(p6->vertex[i].z, m_objectParam[objRank].bboxMax.z);
+ }
+
+ m_objectParam[objRank].radius = Max(Length(m_objectParam[objRank].bboxMin),
+ Length(m_objectParam[objRank].bboxMax));
+ }
+ }
+ }
+ }
+ }
+
+ m_bUpdateGeometry = FALSE;
+}
+
+
+// Détermine si un objet est visible, même partiellement.
+// La transformation "world" doit être faite !
+
+BOOL CD3DEngine::IsVisible(int objRank)
+{
+ D3DVECTOR center;
+ DWORD flags;
+ float radius;
+
+ radius = m_objectParam[objRank].radius;
+ center = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_pD3DDevice->ComputeSphereVisibility(&center, &radius, 1, 0, &flags);
+
+ if ( flags & D3DSTATUS_CLIPINTERSECTIONALL )
+ {
+ m_objectParam[objRank].bVisible = FALSE;
+ return FALSE;
+ }
+ m_objectParam[objRank].bVisible = TRUE;
+ return TRUE;
+}
+
+
+// Détecte l'objet visé par la souris.
+// Retourne le rang de l'objet ou -1.
+
+int CD3DEngine::DetectObject(FPOINT mouse)
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, i, objRank, nearest;
+ float dist, min;
+
+ min = 1000000.0f;
+ nearest = -1;
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !DetectBBox(objRank, mouse) ) continue;
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( p4->min != 0.0f ) continue; // LOD B ou C ?
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ for ( i=0 ; i<p6->totalUsed/3 ; i++ )
+ {
+ if ( DetectTriangle(mouse, pv, objRank, dist) &&
+ dist < min )
+ {
+ min = dist;
+ nearest = objRank;
+ }
+ pv += 3;
+ }
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ for ( i=0 ; i<p6->totalUsed-2 ; i++ )
+ {
+ if ( DetectTriangle(mouse, pv, objRank, dist) &&
+ dist < min )
+ {
+ min = dist;
+ nearest = objRank;
+ }
+ pv += 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nearest;
+}
+
+// Détecte si la souris est dans un triangle.
+
+BOOL CD3DEngine::DetectTriangle(FPOINT mouse, D3DVERTEX2 *triangle,
+ int objRank, float &dist)
+{
+ D3DVECTOR p2D[3], p3D;
+ FPOINT a, b, c;
+ int i;
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ p3D.x = triangle[i].x;
+ p3D.y = triangle[i].y;
+ p3D.z = triangle[i].z;
+ if ( !TransformPoint(p2D[i], objRank, p3D) ) return FALSE;
+ }
+
+ if ( mouse.x < p2D[0].x &&
+ mouse.x < p2D[1].x &&
+ mouse.x < p2D[2].x ) return FALSE;
+ if ( mouse.x > p2D[0].x &&
+ mouse.x > p2D[1].x &&
+ mouse.x > p2D[2].x ) return FALSE;
+ if ( mouse.y < p2D[0].y &&
+ mouse.y < p2D[1].y &&
+ mouse.y < p2D[2].y ) return FALSE;
+ if ( mouse.y > p2D[0].y &&
+ mouse.y > p2D[1].y &&
+ mouse.y > p2D[2].y ) return FALSE;
+
+ a.x = p2D[0].x;
+ a.y = p2D[0].y;
+ b.x = p2D[1].x;
+ b.y = p2D[1].y;
+ c.x = p2D[2].x;
+ c.y = p2D[2].y;
+ if ( !IsInsideTriangle(a, b, c, mouse) ) return FALSE;
+
+ dist = (p2D[0].z+p2D[1].z+p2D[2].z)/3.0f;
+ return TRUE;
+}
+
+// Détecte si un objet est visé par la souris.
+
+BOOL CD3DEngine::DetectBBox(int objRank, FPOINT mouse)
+{
+ D3DVECTOR p, pp;
+ FPOINT min, max;
+ int i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ if ( i & (1<<0) ) p.x = m_objectParam[objRank].bboxMin.x;
+ else p.x = m_objectParam[objRank].bboxMax.x;
+ if ( i & (1<<1) ) p.y = m_objectParam[objRank].bboxMin.y;
+ else p.y = m_objectParam[objRank].bboxMax.y;
+ if ( i & (1<<2) ) p.z = m_objectParam[objRank].bboxMin.z;
+ else p.z = m_objectParam[objRank].bboxMax.z;
+ if ( TransformPoint(pp, objRank, p) )
+ {
+ if ( pp.x < min.x ) min.x = pp.x;
+ if ( pp.x > max.x ) max.x = pp.x;
+ if ( pp.y < min.y ) min.y = pp.y;
+ if ( pp.y > max.y ) max.y = pp.y;
+ }
+ }
+
+ return ( mouse.x >= min.x &&
+ mouse.x <= max.x &&
+ mouse.y >= min.y &&
+ mouse.y <= max.y );
+}
+
+// Transforme un point 3D (x,y,z) dans l'espace 2D (x,y,-) de la fenêtre.
+// La coordonnée p2D.z donne l'éloignement.
+
+BOOL CD3DEngine::TransformPoint(D3DVECTOR &p2D, int objRank, D3DVECTOR p3D)
+{
+ p3D = Transform(m_objectParam[objRank].transform, p3D);
+ p3D = Transform(m_matView, p3D);
+
+ if ( p3D.z < 2.0f ) return FALSE; // derrière ?
+
+ p2D.x = (p3D.x/p3D.z)*m_matProj._11;
+ p2D.y = (p3D.y/p3D.z)*m_matProj._22;
+ p2D.z = p3D.z;
+
+ p2D.x = (p2D.x+1.0f)/2.0f; // [-1..1] -> [0..1]
+ p2D.y = (p2D.y+1.0f)/2.0f;
+
+ return TRUE;
+}
+
+
+// Calcul les distances entre le point de vue et l'origine
+// des différents objets.
+
+void CD3DEngine::ComputeDistance()
+{
+ D3DVECTOR v;
+ int i;
+ float distance;
+
+ if ( s_resol == 0 )
+ {
+ for ( i=0 ; i<m_objectParamTotal ; i++ )
+ {
+ if ( m_objectParam[i].bUsed == FALSE ) continue;
+
+ v.x = m_eyePt.x - m_objectParam[i].transform._41;
+ v.y = m_eyePt.y - m_objectParam[i].transform._42;
+ v.z = m_eyePt.z - m_objectParam[i].transform._43;
+ m_objectParam[i].distance = Length(v);
+ }
+ }
+ else
+ {
+ if ( s_resol == 1 )
+ {
+ distance = 100000.0f;
+ }
+ if ( s_resol == 2 )
+ {
+ distance = (RetLimitLOD(0)+RetLimitLOD(1))/2.0f;
+ }
+ if ( s_resol == 3 )
+ {
+ distance = 0.0f;
+ }
+
+ for ( i=0 ; i<m_objectParamTotal ; i++ )
+ {
+ if ( m_objectParam[i].bUsed == FALSE ) continue;
+
+ if ( m_objectParam[i].type == TYPETERRAIN )
+ {
+ v.x = m_eyePt.x - m_objectParam[i].transform._41;
+ v.y = m_eyePt.y - m_objectParam[i].transform._42;
+ v.z = m_eyePt.z - m_objectParam[i].transform._43;
+ m_objectParam[i].distance = Length(v);
+ }
+ else
+ {
+ m_objectParam[i].distance = distance;
+ }
+ }
+ }
+}
+
+
+// Adapte les réglages lors de la première exécution.
+
+void CD3DEngine::FirstExecuteAdapt(BOOL bFirst)
+{
+ if ( m_app->IsVideo8MB() )
+ {
+ SetGroundSpot(FALSE);
+ SetSkyMode(FALSE);
+ }
+
+ if ( m_app->IsVideo32MB() && bFirst )
+ {
+ SetObjectDetail(2.0f);
+ }
+}
+
+// Retourne la quantité totale de mémoire vidéo pour les textures.
+
+int CD3DEngine::GetVidMemTotal()
+{
+ return m_app->GetVidMemTotal();
+}
+
+BOOL CD3DEngine::IsVideo8MB()
+{
+ return m_app->IsVideo8MB();
+}
+
+BOOL CD3DEngine::IsVideo32MB()
+{
+ return m_app->IsVideo32MB();
+}
+
+
+// Effectue la liste de tous les devices graphiques disponibles.
+
+BOOL CD3DEngine::EnumDevices(char *bufDevices, int lenDevices,
+ char *bufModes, int lenModes,
+ int &totalDevices, int &selectDevices,
+ int &totalModes, int &selectModes)
+{
+ return m_app->EnumDevices(bufDevices, lenDevices,
+ bufModes, lenModes,
+ totalDevices, selectDevices,
+ totalModes, selectModes);
+}
+
+BOOL CD3DEngine::RetFullScreen()
+{
+ return m_app->RetFullScreen();
+}
+
+BOOL CD3DEngine::ChangeDevice(char *device, char *mode, BOOL bFull)
+{
+ return m_app->ChangeDevice(device, mode, bFull);
+}
+
+
+
+D3DMATRIX* CD3DEngine::RetMatView()
+{
+ return &m_matView;
+}
+
+D3DMATRIX* CD3DEngine::RetMatLeftView()
+{
+ return &m_matLeftView;
+}
+
+D3DMATRIX* CD3DEngine::RetMatRightView()
+{
+ return &m_matRightView;
+}
+
+
+// Spécifie l'emplacement et la direction du point de vue.
+
+void CD3DEngine::SetViewParams(const D3DVECTOR &vEyePt,
+ const D3DVECTOR &vLookatPt,
+ const D3DVECTOR &vUpVec,
+ FLOAT fEyeDistance)
+{
+#if 0
+ m_eyePt = vEyePt;
+
+ // Adjust camera position for left or right eye along the axis
+ // perpendicular to the view direction vector and the up vector.
+ D3DVECTOR vView = (vLookatPt) - (vEyePt);
+ vView = CrossProduct( vView, (vUpVec) );
+ vView = Normalize( vView ) * fEyeDistance;
+
+ D3DVECTOR vLeftEyePt = (vEyePt) + vView;
+ D3DVECTOR vRightEyePt = (vEyePt) - vView;
+
+ // Set the view matrices
+ D3DUtil_SetViewMatrix( m_matLeftView, (D3DVECTOR)vLeftEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec );
+ D3DUtil_SetViewMatrix( m_matRightView, (D3DVECTOR)vRightEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec );
+ D3DUtil_SetViewMatrix( m_matView, (D3DVECTOR)vEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec );
+#else
+ m_eyePt = vEyePt;
+ m_lookatPt = vLookatPt;
+ m_eyeDirH = RotateAngle(vEyePt.x-vLookatPt.x, vEyePt.z-vLookatPt.z);
+ m_eyeDirV = RotateAngle(Length2d(vEyePt, vLookatPt), vEyePt.y-vLookatPt.y);
+
+ D3DUtil_SetViewMatrix(m_matView, (D3DVECTOR)vEyePt, (D3DVECTOR)vLookatPt, (D3DVECTOR)vUpVec);
+
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+ m_sound->SetListener(vEyePt, vLookatPt);
+#endif
+}
+
+
+// Spécifie la matrice de transformation d'un objet.
+
+BOOL CD3DEngine::SetObjectTransform(int objRank, const D3DMATRIX &transform)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].transform = transform;
+ return TRUE;
+}
+
+// Donne la matrice de transformation d'un objet.
+
+BOOL CD3DEngine::GetObjectTransform(int objRank, D3DMATRIX &transform)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ transform = m_objectParam[objRank].transform;
+ return TRUE;
+}
+
+// Spécifie le type d'un objet.
+
+BOOL CD3DEngine::SetObjectType(int objRank, D3DTypeObj type)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].type = type;
+ return TRUE;
+}
+
+// Retourne le type d'un objet.
+
+D3DTypeObj CD3DEngine::RetObjectType(int objRank)
+{
+ return m_objectParam[objRank].type;
+}
+
+// Spécifie la transparence d'un objet.
+
+BOOL CD3DEngine::SetObjectTransparency(int objRank, float value)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ m_objectParam[objRank].transparency = value;
+ return TRUE;
+}
+
+
+// Alloue une table pour l'ombre, si nécessaire.
+
+BOOL CD3DEngine::ShadowCreate(int objRank)
+{
+ int i;
+
+ // Déjà alloué ?
+ if ( m_objectParam[objRank].shadowRank != -1 ) return TRUE;
+
+ for ( i=0 ; i<D3DMAXSHADOW ; i++ )
+ {
+ if ( m_shadow[i].bUsed == FALSE ) // libre ?
+ {
+ ZeroMemory(&m_shadow[i], sizeof(D3DShadow));
+
+ m_shadow[i].bUsed = TRUE;
+ m_shadow[i].objRank = objRank;
+ m_shadow[i].height = 0.0f;
+
+ m_objectParam[objRank].shadowRank = i;
+
+ if ( m_shadowTotal < i+1 )
+ {
+ m_shadowTotal = i+1;
+ }
+ return TRUE;
+ }
+ }
+ return FALSE; // pas trouvé
+}
+
+// Supprime l'ombre associée à un objet.
+
+void CD3DEngine::ShadowDelete(int objRank)
+{
+ int i;
+
+ if ( objRank == -1 ) return;
+
+ i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return;
+
+ m_shadow[i].bUsed = FALSE;
+ m_shadow[i].objRank = -1;
+ m_shadow[i].pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_shadow[i].type = D3DSHADOWNORM;
+
+ m_objectParam[objRank].shadowRank = -1;
+
+ m_shadowTotal = 0;
+ for ( i=0 ; i<D3DMAXSHADOW ; i++ )
+ {
+ if ( m_shadow[i].bUsed ) m_shadowTotal = i+1;
+ }
+}
+
+// Spécifie si l'ombre est visible. Par exemple, lorsqu'un objet est
+// porté, il n'a plus d'ombre.
+
+BOOL CD3DEngine::SetObjectShadowHide(int objRank, BOOL bHide)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].bHide = bHide;
+ return TRUE;
+}
+
+// Spécifie le type de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowType(int objRank, D3DShadowType type)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].type = type;
+ return TRUE;
+}
+
+// Spécifie la position de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowPos(int objRank, const D3DVECTOR &pos)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].pos = pos;
+ return TRUE;
+}
+
+// Spécifie la normale au terrain de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowNormal(int objRank, const D3DVECTOR &n)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].normal = n;
+ return TRUE;
+}
+
+// Spécifie l'angle de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowAngle(int objRank, float angle)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].angle = angle;
+ return TRUE;
+}
+
+// Spécifie le rayon de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowRadius(int objRank, float radius)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].radius = radius;
+ return TRUE;
+}
+
+// Retourne le rayon de l'ombre de l'objet.
+
+float CD3DEngine::RetObjectShadowRadius(int objRank)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return 0.0f;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ return m_shadow[i].radius;
+}
+
+// Spécifie l'intensité de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowIntensity(int objRank, float intensity)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].intensity = intensity;
+ return TRUE;
+}
+
+// Spécifie la hauteur de l'ombre de l'objet.
+
+BOOL CD3DEngine::SetObjectShadowHeight(int objRank, float h)
+{
+ if ( objRank < 0 || objRank >= D3DMAXOBJECT ) return FALSE;
+
+ int i = m_objectParam[objRank].shadowRank;
+ if ( i == -1 ) return FALSE;
+
+ m_shadow[i].height = h;
+ return TRUE;
+}
+
+
+// Efface toutes les marques au sol.
+
+void CD3DEngine::GroundSpotFlush()
+{
+ LPDIRECTDRAWSURFACE7 surface;
+ DDSURFACEDESC2 ddsd;
+ WORD* pbSurf;
+ char texName[20];
+ int s, y;
+
+ ZeroMemory(m_groundSpot, sizeof(D3DGroundSpot)*D3DMAXGROUNDSPOT);
+ m_bFirstGroundSpot = TRUE; // force le dessin la première fois
+
+ for ( s=0 ; s<16 ; s++ )
+ {
+ sprintf(texName, "shadow%.2d.tga", s);
+ surface = D3DTextr_GetSurface(texName);
+ if ( surface == 0 ) continue;
+
+ ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
+ ddsd.dwSize = sizeof(DDSURFACEDESC2);
+ if ( surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK ) continue;
+
+ if ( ddsd.ddpfPixelFormat.dwRGBBitCount != 16 ) continue;
+
+ for ( y=0 ; y<(int)ddsd.dwHeight ; y++ )
+ {
+ pbSurf = (WORD*)ddsd.lpSurface;
+ pbSurf += ddsd.lPitch*y/2;
+ memset(pbSurf, -1, ddsd.lPitch); // tout blanc
+ }
+
+ surface->Unlock(NULL);
+ }
+}
+
+// Alloue une table pour une marque au sol, si nécessaire.
+
+int CD3DEngine::GroundSpotCreate()
+{
+ int i;
+
+ for ( i=0 ; i<D3DMAXGROUNDSPOT ; i++ )
+ {
+ if ( m_groundSpot[i].bUsed == FALSE ) // libre ?
+ {
+ ZeroMemory(&m_groundSpot[i], sizeof(D3DGroundSpot));
+ m_groundSpot[i].bUsed = TRUE;
+ m_groundSpot[i].smooth = 1.0f;
+ return i;
+ }
+ }
+ return -1; // pas trouvé
+}
+
+// Supprime une marque au sol.
+
+void CD3DEngine::GroundSpotDelete(int rank)
+{
+ m_groundSpot[rank].bUsed = FALSE;
+ m_groundSpot[rank].pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+// Spécifie la position d'une marque au sol de l'objet.
+
+BOOL CD3DEngine::SetObjectGroundSpotPos(int rank, const D3DVECTOR &pos)
+{
+ m_groundSpot[rank].pos = pos;
+ return TRUE;
+}
+
+// Spécifie le rayon d'une marque au sol de l'objet.
+
+BOOL CD3DEngine::SetObjectGroundSpotRadius(int rank, float radius)
+{
+ m_groundSpot[rank].radius = radius;
+ return TRUE;
+}
+
+// Spécifie la couleur d'une marque au sol.
+
+BOOL CD3DEngine::SetObjectGroundSpotColor(int rank, D3DCOLORVALUE color)
+{
+ m_groundSpot[rank].color = color;
+ return TRUE;
+}
+
+// Spécifie les hauteurs min/max.
+
+BOOL CD3DEngine::SetObjectGroundSpotMinMax(int rank, float min, float max)
+{
+ m_groundSpot[rank].min = min;
+ m_groundSpot[rank].max = max;
+ return TRUE;
+}
+
+// Spécifie le facteur de transition.
+
+BOOL CD3DEngine::SetObjectGroundSpotSmooth(int rank, float smooth)
+{
+ m_groundSpot[rank].smooth = smooth;
+ return TRUE;
+}
+
+
+// Crée les marques au sol.
+
+int CD3DEngine::GroundMarkCreate(D3DVECTOR pos, float radius,
+ float delay1, float delay2, float delay3,
+ int dx, int dy, char* table)
+{
+ ZeroMemory(&m_groundMark, sizeof(D3DGroundMark));
+ m_groundMark.bUsed = TRUE;
+ m_groundMark.phase = 1;
+ m_groundMark.delay[0] = delay1;
+ m_groundMark.delay[1] = delay2;
+ m_groundMark.delay[2] = delay3;
+ m_groundMark.pos = pos;
+ m_groundMark.radius = radius;
+ m_groundMark.intensity = 0.0f;
+ m_groundMark.dx = dx;
+ m_groundMark.dy = dy;
+ m_groundMark.table = table;
+ return 0;
+}
+
+// Efface les marques au sol.
+
+BOOL CD3DEngine::GroundMarkDelete(int rank)
+{
+ ZeroMemory(&m_groundMark, sizeof(D3DGroundMark));
+ return TRUE;
+}
+
+
+// Gestion des frontières (distances limites) pour changer de résolution.
+// LOD = level-of-detail.
+
+void CD3DEngine::SetLimitLOD(int rank, float limit)
+{
+ m_limitLOD[rank] = limit;
+}
+
+float CD3DEngine::RetLimitLOD(int rank, BOOL bLast)
+{
+ float limit;
+
+ if ( bLast )
+ {
+ limit = m_limitLOD[rank];
+ limit *= m_lastDim.x/640.0f; // limite plus loin si fenêtre grande !
+//? limit += m_limitLOD[0]*(m_lastObjectDetail*2.0f-1.0f);
+ limit += m_limitLOD[0]*(m_lastObjectDetail*2.0f);
+ }
+ else
+ {
+ limit = m_limitLOD[rank];
+ limit *= m_dim.x/640.0f; // limite plus loin si fenêtre grande !
+//? limit += m_limitLOD[0]*(m_objectDetail*2.0f-1.0f);
+ limit += m_limitLOD[0]*(m_objectDetail*2.0f);
+ }
+ if ( limit < 0.0f ) limit = 0.0f;
+
+ return limit;
+}
+
+
+// Définition de la distance de vision du terrain.
+
+void CD3DEngine::SetTerrainVision(float vision)
+{
+ m_terrainVision = vision;
+}
+
+
+// Gestion du mode global d'ombrage.
+
+void CD3DEngine::SetShadow(BOOL bMode)
+{
+ m_bShadow = bMode;
+}
+
+BOOL CD3DEngine::RetShadow()
+{
+ return m_bShadow;
+}
+
+
+// Gestion du mode global de marquage au sol.
+
+void CD3DEngine::SetGroundSpot(BOOL bMode)
+{
+ m_bGroundSpot = bMode;
+}
+
+BOOL CD3DEngine::RetGroundSpot()
+{
+ return m_bGroundSpot;
+}
+
+
+// Gestion du mode global de salissure.
+
+void CD3DEngine::SetDirty(BOOL bMode)
+{
+ m_bDirty = bMode;
+}
+
+BOOL CD3DEngine::RetDirty()
+{
+ return m_bDirty;
+}
+
+
+// Gestion du mode global de nappes de brouillard horizontales.
+
+void CD3DEngine::SetFog(BOOL bMode)
+{
+ m_bFog = bMode;
+}
+
+BOOL CD3DEngine::RetFog()
+{
+ return m_bFog;
+}
+
+
+// Indique s'il est possible de donner une couleur dans SetState.
+
+BOOL CD3DEngine::RetStateColor()
+{
+ return m_bStateColor;
+}
+
+
+// Gestion du mode global de texturage secondaire.
+
+void CD3DEngine::SetSecondTexture(int texNum)
+{
+ m_secondTexNum = texNum;
+}
+
+int CD3DEngine::RetSecondTexture()
+{
+ return m_secondTexNum;
+}
+
+
+// Choix du rang de la vue active.
+
+void CD3DEngine::SetRankView(int rank)
+{
+ if ( rank < 0 ) rank = 0;
+ if ( rank > 1 ) rank = 1;
+
+ if ( m_rankView == 0 && rank == 1 ) // entre dans l'eau ?
+ {
+ m_light->AdaptLightColor(m_waterAddColor, +1.0f);
+ }
+
+ if ( m_rankView == 1 && rank == 0 ) // sort de l'eau ?
+ {
+ m_light->AdaptLightColor(m_waterAddColor, -1.0f);
+ }
+
+ m_rankView = rank;
+}
+
+int CD3DEngine::RetRankView()
+{
+ return m_rankView;
+}
+
+// Indique s'il faut dessiner le monde sous l'interface.
+
+void CD3DEngine::SetDrawWorld(BOOL bDraw)
+{
+ m_bDrawWorld = bDraw;
+}
+
+// Indique s'il faut dessiner le monde sur l'interface.
+
+void CD3DEngine::SetDrawFront(BOOL bDraw)
+{
+ m_bDrawFront = bDraw;
+}
+
+// Gestion de la couleur ambiante.
+// color = 0x00rrggbb
+// rr: rouge
+// gg: vert
+// bb: bleu
+
+void CD3DEngine::SetAmbiantColor(D3DCOLOR color, int rank)
+{
+ m_ambiantColor[rank] = color;
+}
+
+D3DCOLOR CD3DEngine::RetAmbiantColor(int rank)
+{
+ return m_ambiantColor[rank];
+}
+
+
+// Gestion de la couleur sous l'eau.
+
+void CD3DEngine::SetWaterAddColor(D3DCOLORVALUE color)
+{
+ m_waterAddColor = color;
+}
+
+D3DCOLORVALUE CD3DEngine::RetWaterAddColor()
+{
+ return m_waterAddColor;
+}
+
+
+// Gestion de la couleur du brouillard.
+
+void CD3DEngine::SetFogColor(D3DCOLOR color, int rank)
+{
+ m_fogColor[rank] = color;
+}
+
+D3DCOLOR CD3DEngine::RetFogColor(int rank)
+{
+ return m_fogColor[rank];
+}
+
+
+// Gestion de la profondeur de champ.
+// Au-delà de cette distance, plus rien n'est visible.
+// Un peu avant (selon SetFogStart), on entre dans le brouillard.
+
+void CD3DEngine::SetDeepView(float length, int rank, BOOL bRef)
+{
+ if ( bRef )
+ {
+ length *= m_clippingDistance;
+ }
+
+ m_deepView[rank] = length;
+}
+
+float CD3DEngine::RetDeepView(int rank)
+{
+ return m_deepView[rank];
+}
+
+
+// Gestion du départ de brouillard.
+// Avec 0.0, le brouillard part du point de vue (brouillard max).
+// Avec 1.0, le brouillard part de la profondeur de champ (pas de brouillard).
+
+void CD3DEngine::SetFogStart(float start, int rank)
+{
+ m_fogStart[rank] = start;
+}
+
+float CD3DEngine::RetFogStart(int rank)
+{
+ return m_fogStart[rank];
+}
+
+
+// Donne l'image d'arrière-plan à utiliser.
+
+void CD3DEngine::SetBackground(char *name, D3DCOLOR up, D3DCOLOR down,
+ D3DCOLOR cloudUp, D3DCOLOR cloudDown,
+ BOOL bFull, BOOL bQuarter)
+{
+ strcpy(m_backgroundName, name);
+ m_backgroundColorUp = up;
+ m_backgroundColorDown = down;
+ m_backgroundCloudUp = cloudUp;
+ m_backgroundCloudDown = cloudDown;
+ m_bBackgroundFull = bFull;
+ m_bBackgroundQuarter = bQuarter;
+}
+
+// Donne l'image d'arrière-plan utilisée.
+
+void CD3DEngine::RetBackground(char *name, D3DCOLOR &up, D3DCOLOR &down,
+ D3DCOLOR &cloudUp, D3DCOLOR &cloudDown,
+ BOOL &bFull, BOOL &bQuarter)
+{
+ strcpy(name, m_backgroundName);
+ up = m_backgroundColorUp;
+ down = m_backgroundColorDown;
+ cloudUp = m_backgroundCloudUp;
+ cloudDown = m_backgroundCloudDown;
+ bFull = m_bBackgroundFull;
+ bQuarter = m_bBackgroundQuarter;
+}
+
+// Donne l'image d'avant-plan à utiliser.
+
+void CD3DEngine::SetFrontsizeName(char *name)
+{
+ if ( m_frontsizeName[0] != 0 )
+ {
+ FreeTexture(m_frontsizeName);
+ }
+
+ strcpy(m_frontsizeName, name);
+}
+
+// Indique s'il faut dessiner d'avant-plan.
+
+void CD3DEngine::SetOverFront(BOOL bFront)
+{
+ m_bOverFront = bFront;
+}
+
+// Donne la couleur d'avant-plan.
+
+void CD3DEngine::SetOverColor(D3DCOLOR color, int mode)
+{
+ m_overColor = color;
+ m_overMode = mode;
+}
+
+
+
+// Gestion de la densité des particules.
+
+void CD3DEngine::SetParticuleDensity(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_particuleDensity = value;
+}
+
+float CD3DEngine::RetParticuleDensity()
+{
+ return m_particuleDensity;
+}
+
+float CD3DEngine::ParticuleAdapt(float factor)
+{
+ if ( m_particuleDensity == 0.0f )
+ {
+ return 1000000.0f;
+ }
+ return factor/m_particuleDensity;
+}
+
+// Gestion de la distance de clipping.
+
+void CD3DEngine::SetClippingDistance(float value)
+{
+ if ( value < 0.5f ) value = 0.5f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_clippingDistance = value;
+}
+
+float CD3DEngine::RetClippingDistance()
+{
+ return m_clippingDistance;
+}
+
+// Gestion du détail des objets.
+
+void CD3DEngine::SetObjectDetail(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 2.0f ) value = 2.0f;
+ m_objectDetail = value;
+}
+
+float CD3DEngine::RetObjectDetail()
+{
+ return m_objectDetail;
+}
+
+// Gestion de la quantité d'objets gadgets.
+
+void CD3DEngine::SetGadgetQuantity(float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+
+ m_gadgetQuantity = value;
+}
+
+float CD3DEngine::RetGadgetQuantity()
+{
+ return m_gadgetQuantity;
+}
+
+// Gestion de la qualité des textures.
+
+void CD3DEngine::SetTextureQuality(int value)
+{
+ if ( value < 0 ) value = 0;
+ if ( value > 2 ) value = 2;
+
+ if ( value != m_textureQuality )
+ {
+ m_textureQuality = value;
+ LoadAllTexture();
+ }
+}
+
+int CD3DEngine::RetTextureQuality()
+{
+ return m_textureQuality;
+}
+
+
+// Gestion du mode de toto.
+
+void CD3DEngine::SetTotoMode(BOOL bPresent)
+{
+ m_bTotoMode = bPresent;
+}
+
+BOOL CD3DEngine::RetTotoMode()
+{
+ return m_bTotoMode;
+}
+
+
+// Gestion du mode d'avant-plan.
+
+void CD3DEngine::SetLensMode(BOOL bPresent)
+{
+ m_bLensMode = bPresent;
+}
+
+BOOL CD3DEngine::RetLensMode()
+{
+ return m_bLensMode;
+}
+
+
+// Gestion du mode de l'eau.
+
+void CD3DEngine::SetWaterMode(BOOL bPresent)
+{
+ m_bWaterMode = bPresent;
+}
+
+BOOL CD3DEngine::RetWaterMode()
+{
+ return m_bWaterMode;
+}
+
+
+// Gestion du mode de ciel.
+
+void CD3DEngine::SetSkyMode(BOOL bPresent)
+{
+ m_bSkyMode = bPresent;
+}
+
+BOOL CD3DEngine::RetSkyMode()
+{
+ return m_bSkyMode;
+}
+
+
+// Gestion du mode d'arrière-plan.
+
+void CD3DEngine::SetBackForce(BOOL bPresent)
+{
+ m_bBackForce = bPresent;
+}
+
+BOOL CD3DEngine::RetBackForce()
+{
+ return m_bBackForce;
+}
+
+
+// Gestion du mode des planètes.
+
+void CD3DEngine::SetPlanetMode(BOOL bPresent)
+{
+ m_bPlanetMode = bPresent;
+}
+
+BOOL CD3DEngine::RetPlanetMode()
+{
+ return m_bPlanetMode;
+}
+
+
+// Gestion du mode des lumières dynamiques.
+
+void CD3DEngine::SetLightMode(BOOL bPresent)
+{
+ m_bLightMode = bPresent;
+}
+
+BOOL CD3DEngine::RetLightMode()
+{
+ return m_bLightMode;
+}
+
+
+// Gestion du mode d'indentation pendant l'édition (CEdit).
+
+void CD3DEngine::SetEditIndentMode(BOOL bAuto)
+{
+ m_bEditIndentMode = bAuto;
+}
+
+BOOL CD3DEngine::RetEditIndentMode()
+{
+ return m_bEditIndentMode;
+}
+
+
+// Gestion de l'avance d'un tabulateur pendant l'édition (CEdit).
+
+void CD3DEngine::SetEditIndentValue(int value)
+{
+ m_editIndentValue = value;
+}
+
+int CD3DEngine::RetEditIndentValue()
+{
+ return m_editIndentValue;
+}
+
+
+void CD3DEngine::SetSpeed(float speed)
+{
+ m_speed = speed;
+}
+
+float CD3DEngine::RetSpeed()
+{
+ return m_speed;
+}
+
+
+void CD3DEngine::SetTracePrecision(float factor)
+{
+ m_tracePrecision = factor;
+}
+
+float CD3DEngine::RetTracePrecision()
+{
+ return m_tracePrecision;
+}
+
+
+// Met à jour la scène après un changement de paramètres.
+
+void CD3DEngine::ApplyChange()
+{
+ m_deepView[0] /= m_lastClippingDistance;
+ m_deepView[1] /= m_lastClippingDistance;
+
+ SetFocus(m_focus);
+ ChangeLOD();
+
+ m_deepView[0] *= m_clippingDistance;
+ m_deepView[1] *= m_clippingDistance;
+}
+
+
+
+// Retourne le point de vue de l'utilisateur.
+
+D3DVECTOR CD3DEngine::RetEyePt()
+{
+ return m_eyePt;
+}
+
+D3DVECTOR CD3DEngine::RetLookatPt()
+{
+ return m_lookatPt;
+}
+
+float CD3DEngine::RetEyeDirH()
+{
+ return m_eyeDirH;
+}
+
+float CD3DEngine::RetEyeDirV()
+{
+ return m_eyeDirV;
+}
+
+POINT CD3DEngine::RetDim()
+{
+ return m_dim;
+}
+
+
+// Génère un nom de quart d'image.
+
+void QuarterName(char *buffer, char *name, int quarter)
+{
+ while ( *name != 0 )
+ {
+ if ( *name == '.' )
+ {
+ *buffer++ = 'a'+quarter;
+ }
+ *buffer++ = *name++;
+ }
+ *buffer++ = 0;
+}
+
+// Libère une texture.
+
+BOOL CD3DEngine::FreeTexture(char* name)
+{
+ if ( name[0] == 0 ) return TRUE;
+
+ if ( D3DTextr_DestroyTexture(name) != S_OK )
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// Charge une texture.
+
+BOOL CD3DEngine::LoadTexture(char* name, int stage)
+{
+ DWORD mode;
+
+ if ( name[0] == 0 ) return TRUE;
+
+ if ( D3DTextr_GetSurface(name) == NULL )
+ {
+ if ( strstr(name, ".tga") == 0 )
+ {
+ mode = 0;
+ }
+ else
+ {
+ mode = D3DTEXTR_CREATEWITHALPHA;
+ }
+
+ if ( D3DTextr_CreateTextureFromFile(name, stage, mode) != S_OK )
+ {
+ return FALSE;
+ }
+
+ if ( D3DTextr_Restore(name, m_pD3DDevice) != S_OK )
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+// Charge toutes les textures de la scène.
+
+BOOL CD3DEngine::LoadAllTexture()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ int l1, i;
+ char name[50];
+ BOOL bOK = TRUE;
+
+#if _POLISH
+ LoadTexture("textp.tga");
+#else
+ LoadTexture("text.tga");
+#endif
+ LoadTexture("mouse.tga");
+ LoadTexture("button1.tga");
+ LoadTexture("button2.tga");
+ LoadTexture("button3.tga");
+ LoadTexture("effect00.tga");
+ LoadTexture("effect01.tga");
+ LoadTexture("effect02.tga");
+ LoadTexture("map.tga");
+
+ if ( m_backgroundName[0] != 0 )
+ {
+ if ( m_bBackgroundQuarter ) // image en 4 morceaux ?
+ {
+ for ( i=0 ; i<4 ; i++ )
+ {
+ QuarterName(name, m_backgroundName, i);
+ LoadTexture(name);
+ }
+ }
+ else
+ {
+ LoadTexture(m_backgroundName);
+ }
+ }
+ if ( m_frontsizeName[0] != 0 )
+ {
+ LoadTexture(m_frontsizeName);
+ }
+
+ m_planet->LoadTexture();
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+
+ if ( p2 == 0 || p2->texName1[0] != 0 )
+ {
+ if ( !LoadTexture(p2->texName1, 0) ) bOK = FALSE;
+ }
+
+ if ( p2 == 0 || p2->texName2[0] != 0 )
+ {
+ if ( !LoadTexture(p2->texName2, 1) ) bOK = FALSE;
+ }
+ }
+ return bOK;
+}
+
+
+// Called during initial app startup, this function performs all the
+// permanent initialization.
+
+HRESULT CD3DEngine::OneTimeSceneInit()
+{
+ return S_OK;
+}
+
+
+// Mise à jour après avoir créé des objets.
+
+void CD3DEngine::Update()
+{
+ ComputeDistance();
+ UpdateGeometry();
+}
+
+// Called once per frame, the call is the entry point for animating
+// the scene.
+
+HRESULT CD3DEngine::FrameMove(float rTime)
+{
+ m_light->FrameLight(rTime);
+ m_particule->FrameParticule(rTime);
+ ComputeDistance();
+ UpdateGeometry();
+
+ if ( m_groundMark.bUsed )
+ {
+ if ( m_groundMark.phase == 1 ) // croissance ?
+ {
+ m_groundMark.intensity += rTime*(1.0f/m_groundMark.delay[0]);
+ if ( m_groundMark.intensity >= 1.0f )
+ {
+ m_groundMark.intensity = 1.0f;
+ m_groundMark.fix = 0.0f;
+ m_groundMark.phase = 2;
+ }
+ }
+ else if ( m_groundMark.phase == 2 ) // fixe ?
+ {
+ m_groundMark.fix += rTime*(1.0f/m_groundMark.delay[1]);
+ if ( m_groundMark.fix >= 1.0f )
+ {
+ m_groundMark.phase = 3;
+ }
+ }
+ else if ( m_groundMark.phase == 3 ) // décroissance ?
+ {
+ m_groundMark.intensity -= rTime*(1.0f/m_groundMark.delay[2]);
+ if ( m_groundMark.intensity < 0.0f )
+ {
+ m_groundMark.intensity = 0.0f;
+ m_groundMark.phase = 0;
+ m_groundMark.bUsed = FALSE;
+ }
+ }
+ }
+
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+ m_sound->FrameMove(rTime);
+
+ return S_OK;
+}
+
+// Fait évoluer tout le jeu.
+
+void CD3DEngine::StepSimul(float rTime)
+{
+ m_app->StepSimul(rTime);
+}
+
+
+
+// Modifie l'état associé à un matériaux.
+// (*) Ne fonctionne pas sans cette instruction, mystère !
+
+void CD3DEngine::SetState(int state, D3DCOLOR color)
+{
+ BOOL bSecond;
+
+ if ( state == m_lastState &&
+ color == m_lastColor ) return;
+ m_lastState = state;
+ m_lastColor = color;
+
+ if ( m_alphaMode != 1 && (state & D3DSTATEALPHA) )
+ {
+ state &= ~D3DSTATEALPHA;
+
+ if ( m_alphaMode == 2 )
+ {
+ state |= D3DSTATETTb;
+ }
+ }
+
+ if ( state & D3DSTATETTb ) // transparent selon noir de la texture ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_blackSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_blackDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend2]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); // (*)
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETTw ) // transparent selon blanc de la texture ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_whiteSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_whiteDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend3]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend4]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, ~color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_ADD);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); // (*)
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TFACTOR);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETCb ) // transparent selon noir de la couleur ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_blackSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_blackDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend2]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETCw ) // transparent selon blanc de la couleur ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_whiteSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_whiteDestBlend[1]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, table_blend[debug_blend3]);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, table_blend[debug_blend4]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, ~color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATETD ) // transparent selon couleur diffuse ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_diffuseSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_diffuseDestBlend[1]);
+
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+ else if ( state & D3DSTATEALPHA ) // image avec canal alpha ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATER);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHAREF, (DWORD)(128));
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND, m_alphaSrcBlend[1]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, m_alphaSrcBlend[1]);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR, color);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+ }
+ else // normal ?
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, FALSE);
+
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+
+ if ( state & D3DSTATEFOG )
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ }
+
+ bSecond = m_bGroundSpot|m_bDirty;
+ if ( !m_bGroundSpot && (state & D3DSTATESECOND) != 0 ) bSecond = FALSE;
+ if ( !m_bDirty && (state & D3DSTATESECOND) == 0 ) bSecond = FALSE;
+
+ if ( (state & D3DSTATEDUALb) && bSecond )
+ {
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
+ }
+ else if ( (state & D3DSTATEDUALw) && bSecond )
+ {
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
+ }
+ else
+ {
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ }
+
+ if ( state & D3DSTATEWRAP )
+ {
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_WRAP0, D3DWRAP_U|D3DWRAP_V);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_WRAP);
+ }
+ else if ( state & D3DSTATECLAMP )
+ {
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_WRAP0, 0);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ }
+ else
+ {
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_WRAP0, 0);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP);
+ }
+
+ if ( state & D3DSTATE2FACE )
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
+ }
+ else
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);
+ }
+
+ if ( state & D3DSTATELIGHT )
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ }
+ else
+ {
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, m_ambiantColor[m_rankView]);
+ }
+}
+
+// Spécifie une texture à utiliser.
+
+void CD3DEngine::SetTexture(char *name, int stage)
+{
+//? if ( stage == 1 && !m_bDirty ) return;
+//? if ( stage == 1 && !m_bShadow ) return;
+
+ if ( strcmp(name, m_lastTexture[stage]) == 0 ) return;
+ strcpy(m_lastTexture[stage], name);
+
+ m_pD3DDevice->SetTexture(stage, D3DTextr_GetSurface(name));
+}
+
+// Spécifie le matérial à utiliser.
+
+void CD3DEngine::SetMaterial(const D3DMATERIAL7 &mat)
+{
+ if ( memcmp(&mat, &m_lastMaterial, sizeof(D3DMATERIAL7)) == 0 ) return;
+ m_lastMaterial = mat;
+
+ m_pD3DDevice->SetMaterial(&m_lastMaterial);
+}
+
+
+// Efface un point dans une surface (dessine en blanc).
+
+inline void ClearDot(DDSURFACEDESC2* ddsd, int x, int y)
+{
+ WORD* pbSurf;
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount != 16 ) return;
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf = 0xffff; // blanc
+}
+
+// Affiche un point dans une surface.
+
+void AddDot(DDSURFACEDESC2* ddsd, int x, int y, D3DCOLORVALUE color)
+{
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount != 16 ) return;
+
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ r = (int)(color.r*32.0f);
+ if ( r >= 32 ) r = 31; // 5 bits
+
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ g = (int)(color.g*32.0f);
+ if ( g >= 32 ) g = 31; // 5 bits
+
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+ b = (int)(color.b*32.0f);
+ if ( b >= 32 ) b = 31; // 5 bits
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ w = (r<<11)|(g<<6)|b;
+ }
+ else if ( ddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ w = (r<<10)|(g<<5)|b;
+ }
+ else
+ {
+ w = -1; // blanc
+ }
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf &= w;
+}
+
+// Affiche un point dans une surface.
+
+void SetDot(DDSURFACEDESC2* ddsd, int x, int y, D3DCOLORVALUE color)
+{
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+
+ r = (int)(color.r*32.0f);
+ g = (int)(color.g*32.0f);
+ b = (int)(color.b*32.0f);
+
+ if ( r >= 32 ) r = 31; // 5 bits
+ if ( g >= 32 ) g = 31; // 5 bits
+ if ( b >= 32 ) b = 31; // 5 bits
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ w = (r<<11)|(g<<6)|b;
+ }
+ else if ( ddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ w = (r<<10)|(g<<5)|b;
+ }
+ else
+ {
+ w = -1; // blanc
+ }
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf = w;
+ }
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 32 ) // image .tga ?
+ {
+ LONG* pbSurf;
+ LONG r,g,b, w;
+
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+
+ r = (int)(color.r*256.0f);
+ g = (int)(color.g*256.0f);
+ b = (int)(color.b*256.0f);
+
+ if ( r >= 256 ) r = 255; // 8 bits
+ if ( g >= 256 ) g = 255; // 8 bits
+ if ( b >= 256 ) b = 255; // 8 bits
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xff0000 )
+ {
+ w = (r<<16)|(g<<8)|b;
+
+ pbSurf = (LONG*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/4;
+ pbSurf += x;
+
+ *pbSurf &= 0xff000000; // garde canal alpha
+ *pbSurf |= w;
+ }
+ }
+}
+
+// Donne un point dans une surface.
+
+D3DCOLORVALUE GetDot(DDSURFACEDESC2* ddsd, int x, int y)
+{
+ D3DCOLORVALUE color;
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ pbSurf = (WORD*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/2;
+ pbSurf += x;
+
+ w = *pbSurf;
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ r = (w>>10)&0x003e;
+ g = (w>> 5)&0x003f;
+ b = (w<< 1)&0x003e;
+ }
+ else if ( ddsd->ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ r = (w>> 9)&0x003e;
+ g = (w>> 4)&0x003e;
+ b = (w<< 1)&0x003e;
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0; // noir
+ }
+
+ color.r = (float)r/63.0f;
+ color.g = (float)g/63.0f;
+ color.b = (float)b/63.0f;
+ color.a = 0.0f;
+ return color;
+ }
+
+ if ( ddsd->ddpfPixelFormat.dwRGBBitCount == 32 ) // image .tga ?
+ {
+ LONG* pbSurf;
+ LONG r,g,b, w;
+
+ pbSurf = (LONG*)ddsd->lpSurface;
+ pbSurf += ddsd->lPitch*y/4;
+ pbSurf += x;
+
+ w = *pbSurf;
+
+ if ( ddsd->ddpfPixelFormat.dwRBitMask == 0xff0000 )
+ {
+ r = (w>>16)&0x00ff;
+ g = (w>> 8)&0x00ff;
+ b = (w<< 0)&0x00ff;
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0; // noir
+ }
+
+ color.r = (float)r/255.0f;
+ color.g = (float)g/255.0f;
+ color.b = (float)b/255.0f;
+ color.a = 0.0f;
+ return color;
+ }
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ color.a = 0.0f; // noir
+ return color;
+}
+
+// Dessine toutes les ombres.
+
+// Il y a 1 pixel de recouvrement autour de chacune des 16 surfaces :
+//
+// |<----------------------->|<----------------------->|<---- ...
+// 0 | 1 2 253 254|255 |
+// |---|---|---|-- ... --|---|---|---| |
+// 0 | 1 2 253 254|255
+// |---|---|---|-- ... --|---|---|---|
+//
+// On dessine donc dans des surfaces de 254x254 pixels. Le pixel de
+// marge tout autour est dessiné à double (dans 2 surfaces adjacentes),
+// pour que le filtrage produise des résultats identiques !
+
+void CD3DEngine::RenderGroundSpot()
+{
+ LPDIRECTDRAWSURFACE7 surface;
+ DDSURFACEDESC2 ddsd;
+ WORD* pbSurf;
+ D3DCOLORVALUE color;
+ D3DVECTOR pos;
+ FPOINT min, max;
+ int s, i, j, dot, ix, iy, y;
+ float tu, tv, cx, cy, px, py, ppx, ppy;
+ float intensity, level;
+ char texName[20];
+ BOOL bClear, bSet;
+
+ if ( !m_bFirstGroundSpot &&
+ m_groundMark.drawPos.x == m_groundMark.pos.x &&
+ m_groundMark.drawPos.z == m_groundMark.pos.z &&
+ m_groundMark.drawRadius == m_groundMark.radius &&
+ m_groundMark.drawIntensity == m_groundMark.intensity ) return;
+
+ for ( s=0 ; s<16 ; s++ )
+ {
+ min.x = (s%4)*254.0f-1.0f; // 1 pixel de recouvrement
+ min.y = (s/4)*254.0f-1.0f;
+ max.x = min.x+254.0f+2.0f;
+ max.y = min.y+254.0f+2.0f;
+
+ bClear = FALSE;
+ bSet = FALSE;
+
+ // Calcule la zone à effacer.
+ dot = (int)(m_groundMark.drawRadius/2.0f);
+
+ tu = (m_groundMark.drawPos.x+1600.0f)/3200.0f;
+ tv = (m_groundMark.drawPos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple de 1
+
+ if ( m_bFirstGroundSpot ||
+ ( m_groundMark.drawRadius != 0.0f &&
+ px+dot >= min.x && py+dot >= min.y &&
+ px-dot <= max.x && py-dot <= max.y ) )
+ {
+ bClear = TRUE;
+ }
+
+ // Calcule la zone à dessiner.
+ dot = (int)(m_groundMark.radius/2.0f);
+
+ tu = (m_groundMark.pos.x+1600.0f)/3200.0f;
+ tv = (m_groundMark.pos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple de 1
+
+ if ( m_groundMark.bUsed &&
+ px+dot >= min.x && py+dot >= min.y &&
+ px-dot <= max.x && py-dot <= max.y )
+ {
+ bSet = TRUE;
+ }
+
+ if ( bClear || bSet )
+ {
+ // Charge le morceau.
+ sprintf(texName, "shadow%.2d.tga", s);
+ surface = D3DTextr_GetSurface(texName);
+ if ( surface == 0 ) continue;
+
+ ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
+ ddsd.dwSize = sizeof(DDSURFACEDESC2);
+ if ( surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK ) continue;
+
+ // Efface en blanc tout le morceau.
+ if ( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ for ( y=0 ; y<(int)ddsd.dwHeight ; y++ )
+ {
+ pbSurf = (WORD*)ddsd.lpSurface;
+ pbSurf += ddsd.lPitch*y/2;
+ memset(pbSurf, -1, ddsd.lPitch); // tout blanc
+ }
+ }
+
+ // Dessine les nouvelles ombres.
+ for ( i=0 ; i<D3DMAXGROUNDSPOT ; i++ )
+ {
+ if ( m_groundSpot[i].bUsed == FALSE ||
+ m_groundSpot[i].radius == 0.0f ) continue;
+
+ if ( m_groundSpot[i].min == 0.0f &&
+ m_groundSpot[i].max == 0.0f )
+ {
+ dot = (int)(m_groundSpot[i].radius/2.0f);
+
+ tu = (m_groundSpot[i].pos.x+1600.0f)/3200.0f;
+ tv = (m_groundSpot[i].pos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple de 1
+
+ if ( px+dot < min.x || py+dot < min.y ||
+ px-dot > max.x || py-dot > max.y ) continue;
+
+ for ( iy=-dot ; iy<=dot ; iy++ )
+ {
+ for ( ix=-dot ; ix<=dot ; ix++ )
+ {
+ ppx = px+ix;
+ ppy = py+iy;
+
+ if ( ppx < min.x || ppy < min.y ||
+ ppx >= max.x || ppy >= max.y ) continue;
+
+ if ( dot == 0 )
+ {
+ intensity = 0.0f;
+ }
+ else
+ {
+ intensity = Length(ppx-cx, ppy-cy)/dot;
+ //? intensity = powf(intensity, m_groundSpot[i].smooth);
+ }
+
+ color.r = m_groundSpot[i].color.r+intensity;
+ color.g = m_groundSpot[i].color.g+intensity;
+ color.b = m_groundSpot[i].color.b+intensity;
+
+ ppx -= min.x; // relatif à la texture
+ ppy -= min.y;
+ AddDot(&ddsd, (int)ppx, (int)ppy, color);
+ }
+ }
+ }
+ else
+ {
+ for ( iy=0 ; iy<256 ; iy++ )
+ {
+ for ( ix=0 ; ix<256 ; ix++ )
+ {
+ pos.x = (256.0f*(s%4)+ix)*3200.0f/1024.0f - 1600.0f;
+ pos.z = (256.0f*(s/4)+iy)*3200.0f/1024.0f - 1600.0f;
+ pos.y = 0.0f;
+ level = m_terrain->RetFloorLevel(pos, TRUE);
+ if ( level < m_groundSpot[i].min ||
+ level > m_groundSpot[i].max ) continue;
+
+ if ( level > (m_groundSpot[i].max+m_groundSpot[i].min)/2.0f )
+ {
+ intensity = 1.0f-(m_groundSpot[i].max-level)/m_groundSpot[i].smooth;
+ }
+ else
+ {
+ intensity = 1.0f-(level-m_groundSpot[i].min)/m_groundSpot[i].smooth;
+ }
+ if ( intensity < 0.0f ) intensity = 0.0f;
+
+ color.r = m_groundSpot[i].color.r+intensity;
+ color.g = m_groundSpot[i].color.g+intensity;
+ color.b = m_groundSpot[i].color.b+intensity;
+
+ AddDot(&ddsd, ix, iy, color);
+ }
+ }
+ }
+ }
+
+ if ( bSet )
+ {
+ dot = (int)(m_groundMark.radius/2.0f);
+
+ tu = (m_groundMark.pos.x+1600.0f)/3200.0f;
+ tv = (m_groundMark.pos.z+1600.0f)/3200.0f; // 0..1
+
+ cx = (tu*254.0f*4.0f)-0.5f;
+ cy = (tv*254.0f*4.0f)-0.5f;
+
+ if ( dot == 0 )
+ {
+ cx += 0.5f;
+ cy += 0.5f;
+ }
+
+ px = cx-Mod(cx, 1.0f);
+ py = cy-Mod(cy, 1.0f); // multiple de 1
+
+ for ( iy=-dot ; iy<=dot ; iy++ )
+ {
+ for ( ix=-dot ; ix<=dot ; ix++ )
+ {
+ ppx = px+ix;
+ ppy = py+iy;
+
+ if ( ppx < min.x || ppy < min.y ||
+ ppx >= max.x || ppy >= max.y ) continue;
+
+ ppx -= min.x; // relatif à la texture
+ ppy -= min.y;
+
+ intensity = 1.0f-Length((float)ix, (float)iy)/dot;
+ if ( intensity <= 0.0f ) continue;
+ intensity *= m_groundMark.intensity;
+
+ j = (ix+dot) + (iy+dot)*m_groundMark.dx;
+ if ( m_groundMark.table[j] == 1 ) // vert ?
+ {
+ color.r = 1.0f-intensity;
+ color.g = 1.0f;
+ color.b = 1.0f-intensity;
+ AddDot(&ddsd, (int)ppx, (int)ppy, color);
+ }
+ if ( m_groundMark.table[j] == 2 ) // rouge ?
+ {
+ color.r = 1.0f;
+ color.g = 1.0f-intensity;
+ color.b = 1.0f-intensity;
+ AddDot(&ddsd, (int)ppx, (int)ppy, color);
+ }
+ }
+ }
+ }
+
+ surface->Unlock(NULL);
+ }
+ }
+
+ for ( i=0 ; i<D3DMAXGROUNDSPOT ; i++ )
+ {
+ if ( m_groundSpot[i].bUsed == FALSE ||
+ m_groundSpot[i].radius == 0.0f )
+ {
+ m_groundSpot[i].drawRadius = 0.0f;
+ }
+ else
+ {
+ m_groundSpot[i].drawPos = m_groundSpot[i].pos;
+ m_groundSpot[i].drawRadius = m_groundSpot[i].radius;
+ }
+ }
+
+ m_groundMark.drawPos = m_groundMark.pos;
+ m_groundMark.drawRadius = m_groundMark.radius;
+ m_groundMark.drawIntensity = m_groundMark.intensity;
+
+ m_bFirstGroundSpot = FALSE;
+}
+
+// Dessine toutes les ombres.
+
+void CD3DEngine::DrawShadow()
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR corner[4], n, pos;
+ D3DMATERIAL7 material;
+ D3DMATRIX matrix;
+ FPOINT ts, ti, rot;
+ float startDeepView, endDeepView;
+ float intensity, lastIntensity, hFactor, radius, max, height;
+ float dp, h, d, D;
+ int i;
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse.r = 1.0f;
+ material.diffuse.g = 1.0f;
+ material.diffuse.b = 1.0f; // blanc
+ material.ambient.r = 0.5f;
+ material.ambient.g = 0.5f;
+ material.ambient.b = 0.5f;
+ SetMaterial(material);
+
+#if _POLISH
+ SetTexture("textp.tga");
+#else
+ SetTexture("text.tga");
+#endif
+
+ dp = 0.5f/256.0f;
+ ts.y = 192.0f/256.0f;
+ ti.y = 224.0f/256.0f;
+ ts.y += dp;
+ ti.y -= dp;
+
+ n = D3DVECTOR(0.0f, 1.0f, 0.0f);
+
+ startDeepView = m_deepView[m_rankView]*m_fogStart[m_rankView];
+ endDeepView = m_deepView[m_rankView];
+
+ lastIntensity = -1.0f;
+ for ( i=0 ; i<m_shadowTotal ; i++ )
+ {
+ if ( !m_shadow[i].bUsed ) continue;
+ if ( m_shadow[i].bHide ) continue;
+
+ pos = m_shadow[i].pos; // pos = centre de l'ombre au sol
+
+ if ( m_eyePt.y == pos.y ) continue; // caméra au même niveau ?
+
+ // h est la hauteur au dessus du sol à laquelle l'ombre
+ // sera dessinée.
+ if ( m_eyePt.y > pos.y ) // caméra en dessus ?
+ {
+ height = m_eyePt.y-pos.y;
+ h = m_shadow[i].radius;
+ max = height*0.5f;
+ if ( h > max ) h = max;
+ if ( h > 4.0f ) h = 4.0f;
+
+ D = Length(m_eyePt, pos);
+ if ( D >= endDeepView ) continue;
+ d = D*h/height;
+
+ pos.x += (m_eyePt.x-pos.x)*d/D;
+ pos.z += (m_eyePt.z-pos.z)*d/D;
+ pos.y += h;
+ }
+ else // caméra en dessous ?
+ {
+ height = pos.y-m_eyePt.y;
+ h = m_shadow[i].radius;
+ max = height*0.1f;
+ if ( h > max ) h = max;
+ if ( h > 4.0f ) h = 4.0f;
+
+ D = Length(m_eyePt, pos);
+ if ( D >= endDeepView ) continue;
+ d = D*h/height;
+
+ pos.x += (m_eyePt.x-pos.x)*d/D;
+ pos.z += (m_eyePt.z-pos.z)*d/D;
+ pos.y -= h;
+ }
+
+ // Le hFactor diminue l'intensité et augmente la taille plus
+ // l'objet est haut par rapport au sol.
+ hFactor = m_shadow[i].height/20.0f;
+ if ( hFactor < 0.0f ) hFactor = 0.0f;
+ if ( hFactor > 1.0f ) hFactor = 1.0f;
+ hFactor = powf(1.0f-hFactor, 2.0f);
+ if ( hFactor < 0.2f ) hFactor = 0.2f;
+
+ radius = m_shadow[i].radius*1.5f;
+ radius *= 2.0f-hFactor; // plus grand si haut
+ radius *= 1.0f-d/D; // plus petit si proche
+
+ if ( m_shadow[i].type == D3DSHADOWNORM )
+ {
+ corner[0].x = +radius;
+ corner[0].z = +radius;
+ corner[0].y = 0.0f;
+
+ corner[1].x = -radius;
+ corner[1].z = +radius;
+ corner[1].y = 0.0f;
+
+ corner[2].x = +radius;
+ corner[2].z = -radius;
+ corner[2].y = 0.0f;
+
+ corner[3].x = -radius;
+ corner[3].z = -radius;
+ corner[3].y = 0.0f;
+
+ ts.x = 64.0f/256.0f;
+ ti.x = 96.0f/256.0f;
+ }
+ else
+ {
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(radius, radius));
+ corner[0].x = rot.x;
+ corner[0].z = rot.y;
+ corner[0].y = 0.0f;
+
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(-radius, radius));
+ corner[1].x = rot.x;
+ corner[1].z = rot.y;
+ corner[1].y = 0.0f;
+
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(radius, -radius));
+ corner[2].x = rot.x;
+ corner[2].z = rot.y;
+ corner[2].y = 0.0f;
+
+ rot = RotatePoint(-m_shadow[i].angle, FPOINT(-radius, -radius));
+ corner[3].x = rot.x;
+ corner[3].z = rot.y;
+ corner[3].y = 0.0f;
+
+ if ( m_shadow[i].type == D3DSHADOWWORM )
+ {
+ ts.x = 96.0f/256.0f;
+ ti.x = 128.0f/256.0f;
+ }
+ else
+ {
+ ts.x = 64.0f/256.0f;
+ ti.x = 96.0f/256.0f;
+ }
+ }
+
+ corner[0] = Cross(corner[0], m_shadow[i].normal);
+ corner[1] = Cross(corner[1], m_shadow[i].normal);
+ corner[2] = Cross(corner[2], m_shadow[i].normal);
+ corner[3] = Cross(corner[3], m_shadow[i].normal);
+
+ corner[0] += pos;
+ corner[1] += pos;
+ corner[2] += pos;
+ corner[3] += pos;
+
+ ts.x += dp;
+ ti.x -= dp;
+
+ vertex[0] = D3DVERTEX2(corner[1], n, ts.x, ts.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, ti.x, ts.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, ts.x, ti.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, ti.x, ti.y);
+
+ intensity = (0.5f+m_shadow[i].intensity*0.5f)*hFactor;
+
+ // Diminue l'intensité de l'ombre si on est dans la zone
+ // comprise entre le début et la fin du brouillard.
+ if ( D > startDeepView )
+ {
+ intensity *= 1.0f-(D-startDeepView)/(endDeepView-startDeepView);
+ }
+
+ // Diminue l'intensité si on est presque à l'horizontale
+ // avec l'ombre (ombre très platte).
+//? if ( height < 4.0f ) intensity *= height/4.0f;
+
+ if ( intensity == 0.0f ) continue;
+
+ if ( lastIntensity != intensity ) // intensité changée ?
+ {
+ lastIntensity = intensity;
+ SetState(D3DSTATETTw, RetColor(intensity));
+ }
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+ }
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+}
+
+
+// Called once per frame, the call is the entry point for 3d
+// rendering. This function sets up render states, clears the
+// viewport, and renders the scene.
+
+HRESULT CD3DEngine::Render()
+{
+ D3DObjLevel1* p1;
+ D3DObjLevel2* p2;
+ D3DObjLevel3* p3;
+ D3DObjLevel4* p4;
+ D3DObjLevel5* p5;
+ D3DObjLevel6* p6;
+ D3DVERTEX2* pv;
+ int l1, l2, l3, l4, l5, objRank, tState;
+ CInterface* pInterface;
+ BOOL bTransparent;
+ D3DCOLOR color, tColor;
+
+ if ( !m_bRender ) return S_OK;
+
+ m_statisticTriangle = 0;
+ m_lastState = -1;
+ m_lastColor = 999;
+ m_lastTexture[0][0] = 0;
+ m_lastTexture[1][0] = 0;
+ ZeroMemory(&m_lastMaterial, sizeof(D3DMATERIAL7));
+
+ if ( m_bGroundSpot )
+ {
+ RenderGroundSpot();
+ }
+
+ // Clear the viewport
+ if ( m_bSkyMode && m_cloud->RetLevel() != 0.0f ) // nuages ?
+ {
+ color = m_backgroundCloudDown;
+ }
+ else
+ {
+ color = m_backgroundColorDown;
+ }
+ m_pD3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
+ color, 1.0f, 0L );
+
+ m_light->LightUpdate();
+
+ // Begin the scene
+ if( FAILED( m_pD3DDevice->BeginScene() ) ) return S_OK;
+
+ if ( m_bDrawWorld )
+ {
+ DrawBackground(); // dessine l'arrière-plan
+ if ( m_bPlanetMode ) DrawPlanet(); // dessine les planètes
+ if ( m_bSkyMode ) m_cloud->Draw(); // dessine les nuages
+
+ // Display the objects
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, F2DW(16));
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProj);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, m_fogColor[m_rankView]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(m_deepView[m_rankView]*m_fogStart[m_rankView]));
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(m_deepView[m_rankView]));
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matView);
+
+ if ( m_bWaterMode ) m_water->DrawBack(); // dessine l'eau
+
+ if ( m_bShadow )
+ {
+ // Dessine le terrain.
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_objectParam[objRank].type != TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DrawShadow(); // dessine les ombres
+ }
+
+ // Dessine les objets.
+ bTransparent = FALSE;
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ if ( m_objectParam[objRank].transparency != 0.0f ) // transparent ?
+ {
+ bTransparent = TRUE;
+ continue;
+ }
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( bTransparent )
+ {
+ if ( m_bStateColor )
+ {
+ tState = D3DSTATETTb|D3DSTATE2FACE;
+ tColor = 0x44444444;
+ }
+ else
+ {
+ tState = D3DSTATETTb;
+ tColor = 0x88888888;
+ }
+
+ // Dessine les objets transparents.
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( m_bShadow && m_objectParam[objRank].type == TYPETERRAIN ) continue;
+ if ( !m_objectParam[objRank].bDrawWorld ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ if ( m_objectParam[objRank].transparency == 0.0f ) continue;
+ SetState(tState, tColor);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_light->LightUpdate(TYPETERRAIN);
+ if ( m_bWaterMode ) m_water->DrawSurf(); // dessine l'eau
+//? m_cloud->Draw(); // dessine les nuages
+
+ m_particule->DrawParticule(SH_WORLD); // dessine les particules du monde 3D
+ m_blitz->Draw(); // dessine les éclairs
+ if ( m_bLensMode ) DrawFrontsize(); // dessine l'avant-plan
+ if ( !m_bOverFront ) DrawOverColor(); // dessine la couleur d'avant-plan
+ }
+
+ // Dessine l'interface utilisateur par-dessus la scène.
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ pInterface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ if ( pInterface != 0 )
+ {
+ pInterface->Draw(); // dessine toute l'interface
+ }
+ m_particule->DrawParticule(SH_INTERFACE); // dessine les particules de l'interface
+
+ if ( m_bDrawFront )
+ {
+ // Display the objects
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZBIAS, F2DW(16));
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProj);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, m_ambiantColor[m_rankView]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, m_fogColor[m_rankView]);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGSTART, F2DW(m_deepView[m_rankView]*m_fogStart[m_rankView]));
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGEND, F2DW(m_deepView[m_rankView]));
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matView);
+
+ p1 = m_objectPointer;
+ for ( l1=0 ; l1<p1->totalUsed ; l1++ )
+ {
+ p2 = p1->table[l1];
+ if ( p2 == 0 ) continue;
+ SetTexture(p2->texName1, 0);
+ SetTexture(p2->texName2, 1);
+ for ( l2=0 ; l2<p2->totalUsed ; l2++ )
+ {
+ p3 = p2->table[l2];
+ if ( p3 == 0 ) continue;
+ objRank = p3->objRank;
+ if ( !m_objectParam[objRank].bDrawFront ) continue;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD,
+ &m_objectParam[objRank].transform);
+ if ( !IsVisible(objRank) ) continue;
+ m_light->LightUpdate(m_objectParam[objRank].type);
+ for ( l3=0 ; l3<p3->totalUsed ; l3++ )
+ {
+ p4 = p3->table[l3];
+ if ( p4 == 0 ) continue;
+ if ( m_objectParam[objRank].distance < p4->min ||
+ m_objectParam[objRank].distance >= p4->max ) continue;
+ for ( l4=0 ; l4<p4->totalUsed ; l4++ )
+ {
+ p5 = p4->table[l4];
+ if ( p5 == 0 ) continue;
+ for ( l5=0 ; l5<p5->totalUsed ; l5++ )
+ {
+ p6 = p5->table[l5];
+ if ( p6 == 0 ) continue;
+ SetMaterial(p6->material);
+ SetState(p6->state);
+ if ( p6->type == D3DTYPE6T )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed/3;
+ }
+ if ( p6->type == D3DTYPE6S )
+ {
+ pv = &p6->vertex[0];
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
+ D3DFVF_VERTEX2,
+ pv, p6->totalUsed,
+ NULL);
+ m_statisticTriangle += p6->totalUsed-2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_particule->DrawParticule(SH_FRONT); // dessine les particules du monde 3D
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+ }
+
+ if ( m_bOverFront ) DrawOverColor(); // dessine la couleur d'avant-plan
+
+ if ( m_mouseType != D3DMOUSEHIDE )
+ {
+ DrawMouse();
+ }
+
+ // End the scene.
+ m_pD3DDevice->EndScene();
+
+ DrawHilite();
+ return S_OK;
+}
+
+
+// Dessine le dégradé d'arrière-plan.
+
+void CD3DEngine::DrawBackground()
+{
+ if ( m_bSkyMode && m_cloud->RetLevel() != 0.0f ) // nuages ?
+ {
+ if ( m_backgroundCloudUp != m_backgroundCloudDown ) // dégradé ?
+ {
+ DrawBackgroundGradient(m_backgroundCloudUp, m_backgroundCloudDown);
+ }
+ }
+ else
+ {
+ if ( m_backgroundColorUp != m_backgroundColorDown ) // dégradé ?
+ {
+ DrawBackgroundGradient(m_backgroundColorUp, m_backgroundColorDown);
+ }
+ }
+
+ if ( m_bBackForce || (m_bSkyMode && m_backgroundName[0] != 0) )
+ {
+ DrawBackgroundImage(); // image
+ }
+}
+
+// Dessine le dégradé d'arrière-plan.
+
+void CD3DEngine::DrawBackgroundGradient(D3DCOLOR up, D3DCOLOR down)
+{
+ D3DLVERTEX vertex[4]; // 2 triangles
+ D3DCOLOR color[3];
+ FPOINT p1, p2;
+
+ p1.x = 0.0f;
+ p1.y = 0.5f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+
+ color[0] = up;
+ color[1] = down;
+ color[2] = 0x00000000;
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture("xxx.tga"); // pas de texture
+ SetState(D3DSTATENORMAL);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+// Dessine une partie de l'image d'arrière-plan.
+
+void CD3DEngine::DrawBackgroundImageQuarter(FPOINT p1, FPOINT p2, char *name)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR n;
+ float u1, u2, v1, v2, h, a;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ if ( m_bBackgroundFull )
+ {
+ u1 = 0.0f;
+ v1 = 0.0f;
+ u2 = 1.0f;
+ v2 = 1.0f;
+
+ if ( m_bBackgroundQuarter )
+ {
+ u1 += 0.5f/512.0f;
+ v1 += 0.5f/384.0f;
+ u2 -= 0.5f/512.0f;
+ v2 -= 0.5f/384.0f;
+ }
+ }
+ else
+ {
+ h = 0.5f; // partie visible verticalement (1=tout)
+ a = m_eyeDirV-PI*0.15f;
+ if ( a > PI ) a -= PI*2.0f; // a = -PI..PI
+ if ( a > PI/4.0f ) a = PI/4.0f;
+ if ( a < -PI/4.0f ) a = -PI/4.0f;
+
+ u1 = -m_eyeDirH/PI;
+ u2 = u1+1.0f/PI;
+//? u1 = -m_eyeDirH/(PI*2.0f);
+//? u2 = u1+1.0f/(PI*2.0f);
+
+ v1 = (1.0f-h)*(0.5f+a/(2.0f*PI/4.0f))+0.1f;
+ v2 = v1+h;
+ }
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture(name);
+ SetState(D3DSTATEWRAP);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+// Dessine l'image d'arrière-plan.
+
+void CD3DEngine::DrawBackgroundImage()
+{
+ FPOINT p1, p2;
+ char name[50];
+
+ if ( m_bBackgroundQuarter )
+ {
+ p1.x = 0.0f;
+ p1.y = 0.5f;
+ p2.x = 0.5f;
+ p2.y = 1.0f;
+ QuarterName(name, m_backgroundName, 0);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.5f;
+ p1.y = 0.5f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ QuarterName(name, m_backgroundName, 1);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 0.5f;
+ p2.y = 0.5f;
+ QuarterName(name, m_backgroundName, 2);
+ DrawBackgroundImageQuarter(p1, p2, name);
+
+ p1.x = 0.5f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 0.5f;
+ QuarterName(name, m_backgroundName, 3);
+ DrawBackgroundImageQuarter(p1, p2, name);
+ }
+ else
+ {
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+ DrawBackgroundImageQuarter(p1, p2, m_backgroundName);
+ }
+}
+
+// Dessine toutes les planètes.
+
+void CD3DEngine::DrawPlanet()
+{
+ if ( !m_planet->PlanetExist() ) return;
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ m_planet->Draw(); // dessine les planètes
+}
+
+// Dessine l'image d'avant-plan.
+
+void CD3DEngine::DrawFrontsize()
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR n;
+ FPOINT p1, p2;
+ float u1, u2, v1, v2;
+
+ if ( m_frontsizeName[0] == 0 ) return;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+
+ u1 = -m_eyeDirH/(PI*0.6f)+PI*0.5f;
+ u2 = u1+0.50f;
+
+ v1 = 0.2f;
+ v2 = 1.0f;
+
+#if 0
+ char s[100];
+ sprintf(s, "h=%.2f v=%.2f u=%.2f;%.2f v=%.2f;%.2f", m_eyeDirH, m_eyeDirV, u1, u2, v1, v2);
+ SetInfoText(3, s);
+#endif
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture(m_frontsizeName);
+ SetState(D3DSTATECLAMP|D3DSTATETTb);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+// Dessine la couleur d'avant-plan.
+
+void CD3DEngine::DrawOverColor()
+{
+ D3DLVERTEX vertex[4]; // 2 triangles
+ D3DCOLOR color[3];
+ FPOINT p1, p2;
+
+ if ( !m_bStateColor ) return;
+ if ( (m_overColor == 0x00000000 && m_overMode == D3DSTATETCb) ||
+ (m_overColor == 0xffffffff && m_overMode == D3DSTATETCw) ) return;
+
+ p1.x = 0.0f;
+ p1.y = 0.0f;
+ p2.x = 1.0f;
+ p2.y = 1.0f;
+
+ color[0] = m_overColor;
+ color[1] = m_overColor;
+ color[2] = 0x00000000;
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE );
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
+
+ SetTexture("xxx.tga"); // pas de texture
+ SetState(m_overMode);
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &m_matViewInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProjInterface);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matWorldInterface);
+
+ vertex[0] = D3DLVERTEX(D3DVECTOR(p1.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[1] = D3DLVERTEX(D3DVECTOR(p1.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+ vertex[2] = D3DLVERTEX(D3DVECTOR(p2.x, p1.y, 0.0f), color[1],color[2], 0.0f,0.0f);
+ vertex[3] = D3DLVERTEX(D3DVECTOR(p2.x, p2.y, 0.0f), color[0],color[2], 0.0f,0.0f);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
+
+// Donne la liste des rangs des objets et sous-objets sélectionnés.
+
+void CD3DEngine::SetHiliteRank(int *rankList)
+{
+ int i;
+
+ i = 0;
+ while ( *rankList != -1 )
+ {
+ m_hiliteRank[i++] = *rankList++;
+ }
+ m_hiliteRank[i] = -1; // terminateur
+}
+
+// Donne la bbox dans l'écran 2D d'un objet quelconque.
+
+BOOL CD3DEngine::GetBBox2D(int objRank, FPOINT &min, FPOINT &max)
+{
+ D3DVECTOR p, pp;
+ int i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ if ( i & (1<<0) ) p.x = m_objectParam[objRank].bboxMin.x;
+ else p.x = m_objectParam[objRank].bboxMax.x;
+ if ( i & (1<<1) ) p.y = m_objectParam[objRank].bboxMin.y;
+ else p.y = m_objectParam[objRank].bboxMax.y;
+ if ( i & (1<<2) ) p.z = m_objectParam[objRank].bboxMin.z;
+ else p.z = m_objectParam[objRank].bboxMax.z;
+ if ( TransformPoint(pp, objRank, p) )
+ {
+ if ( pp.x < min.x ) min.x = pp.x;
+ if ( pp.x > max.x ) max.x = pp.x;
+ if ( pp.y < min.y ) min.y = pp.y;
+ if ( pp.y > max.y ) max.y = pp.y;
+ }
+ }
+
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f ) return FALSE;
+
+ return TRUE;
+}
+
+// Détermine le rectangle de l'objet mis en évidence, qui sera
+// dessiné par CD3DApplication.
+
+void CD3DEngine::DrawHilite()
+{
+ FPOINT min, max, omin, omax;
+ int i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+
+ i = 0;
+ while ( m_hiliteRank[i] != -1 )
+ {
+ if ( GetBBox2D(m_hiliteRank[i++], omin, omax) )
+ {
+ min.x = Min(min.x, omin.x);
+ min.y = Min(min.y, omin.y);
+ max.x = Max(max.x, omax.x);
+ max.y = Max(max.y, omax.y);
+ }
+ }
+
+ if ( min.x == 1000000.0f ||
+ min.y == 1000000.0f ||
+ max.x == -1000000.0f ||
+ max.y == -1000000.0f )
+ {
+ m_bHilite = FALSE; // pas de mise en évidence
+ }
+ else
+ {
+ m_hiliteP1 = min;
+ m_hiliteP2 = max;
+ m_bHilite = TRUE;
+ }
+}
+
+// Donne le rectangle de mise en évidence à dessiner
+// par CD3DApplication.
+
+BOOL CD3DEngine::GetHilite(FPOINT &p1, FPOINT &p2)
+{
+ p1 = m_hiliteP1;
+ p2 = m_hiliteP2;
+ return m_bHilite;
+}
+
+
+// Ajoute qq triangles rendus pour les statistiques.
+
+void CD3DEngine::AddStatisticTriangle(int nb)
+{
+ m_statisticTriangle += nb;
+}
+
+// Retourne le nombre de triangles rendus.
+
+int CD3DEngine::RetStatisticTriangle()
+{
+ return m_statisticTriangle;
+}
+
+BOOL CD3DEngine::GetSpriteCoord(int &x, int &y)
+{
+ D3DVIEWPORT7 vp;
+ D3DVECTOR v, vv;
+
+ return FALSE;
+ //?
+ vv = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ if ( !TransformPoint(v, 20*20+1, vv) ) return FALSE;
+
+ m_pD3DDevice->GetViewport(&vp);
+ v.x *= vp.dwWidth/2;
+ v.y *= vp.dwHeight/2;
+ v.x = v.x+vp.dwWidth/2;
+ v.y = vp.dwHeight-(v.y+vp.dwHeight/2);
+
+ x = (int)v.x;
+ y = (int)v.y;
+ return TRUE;
+}
+
+
+// Teste s'il faut exclure un point.
+
+BOOL IsExcludeColor(FPOINT *pExclu, int x, int y)
+{
+ int i;
+
+ i = 0;
+ while ( pExclu[i+0].x != 0.0f || pExclu[i+0].y != 0.0f ||
+ pExclu[i+1].y != 0.0f || pExclu[i+1].y != 0.0f )
+ {
+ if ( x >= (int)(pExclu[i+0].x*256.0f) &&
+ x < (int)(pExclu[i+1].x*256.0f) &&
+ y >= (int)(pExclu[i+0].y*256.0f) &&
+ y < (int)(pExclu[i+1].y*256.0f) ) return TRUE; // exclure
+
+ i += 2;
+ }
+
+ return FALSE; // point à inclure
+}
+
+// Change la couleur d'une texture.
+
+BOOL CD3DEngine::ChangeColor(char *name,
+ D3DCOLORVALUE colorRef1, D3DCOLORVALUE colorNew1,
+ D3DCOLORVALUE colorRef2, D3DCOLORVALUE colorNew2,
+ float tolerance1, float tolerance2,
+ FPOINT ts, FPOINT ti,
+ FPOINT *pExclu, float shift, BOOL bHSV)
+{
+ LPDIRECTDRAWSURFACE7 surface;
+ DDSURFACEDESC2 ddsd;
+ D3DCOLORVALUE color;
+ ColorHSV cr1, cn1, cr2, cn2, c;
+ int dx, dy, x, y, sx, sy, ex, ey;
+
+ D3DTextr_Invalidate(name);
+ LoadTexture(name); // recharge la texture initiale
+
+ if ( colorRef1.r == colorNew1.r &&
+ colorRef1.g == colorNew1.g &&
+ colorRef1.b == colorNew1.b &&
+ colorRef2.r == colorNew2.r &&
+ colorRef2.g == colorNew2.g &&
+ colorRef2.b == colorNew2.b ) return TRUE;
+
+ surface = D3DTextr_GetSurface(name);
+ if ( surface == 0 ) return FALSE;
+
+ ZeroMemory(&ddsd, sizeof(DDSURFACEDESC2));
+ ddsd.dwSize = sizeof(DDSURFACEDESC2);
+ if ( surface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK ) return FALSE;
+
+ dx = ddsd.dwWidth;
+ dy = ddsd.dwHeight;
+
+ sx = (int)(ts.x*dx);
+ sy = (int)(ts.y*dy);
+ ex = (int)(ti.x*dx);
+ ey = (int)(ti.y*dy);
+
+ RGB2HSV(colorRef1, cr1);
+ RGB2HSV(colorNew1, cn1);
+ RGB2HSV(colorRef2, cr2);
+ RGB2HSV(colorNew2, cn2);
+
+ for ( y=sy ; y<ey ; y++ )
+ {
+ for ( x=sx ; x<ex ; x++ )
+ {
+ if ( pExclu != 0 && IsExcludeColor(pExclu, x,y) ) continue;
+
+ color = GetDot(&ddsd, x, y);
+
+ if ( bHSV )
+ {
+ RGB2HSV(color, c);
+ if ( c.s > 0.01f && Abs(c.h-cr1.h) < tolerance1 )
+ {
+ c.h += cn1.h-cr1.h;
+ c.s += cn1.s-cr1.s;
+ c.v += cn1.v-cr1.v;
+ if ( c.h < 0.0f ) c.h -= 1.0f;
+ if ( c.h > 1.0f ) c.h += 1.0f;
+ HSV2RGB(c, color);
+ color.r += shift;
+ color.g += shift;
+ color.b += shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ else
+ if ( tolerance2 != -1.0f &&
+ c.s > 0.01f && Abs(c.h-cr2.h) < tolerance2 )
+ {
+ c.h += cn2.h-cr2.h;
+ c.s += cn2.s-cr2.s;
+ c.v += cn2.v-cr2.v;
+ if ( c.h < 0.0f ) c.h -= 1.0f;
+ if ( c.h > 1.0f ) c.h += 1.0f;
+ HSV2RGB(c, color);
+ color.r += shift;
+ color.g += shift;
+ color.b += shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ }
+ else
+ {
+ if ( Abs(color.r-colorRef1.r)+
+ Abs(color.g-colorRef1.g)+
+ Abs(color.b-colorRef1.b) < tolerance1*3.0f )
+ {
+ color.r = colorNew1.r+color.r-colorRef1.r+shift;
+ color.g = colorNew1.g+color.g-colorRef1.g+shift;
+ color.b = colorNew1.b+color.b-colorRef1.b+shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ else
+ if ( tolerance2 != -1 &&
+ Abs(color.r-colorRef2.r)+
+ Abs(color.g-colorRef2.g)+
+ Abs(color.b-colorRef2.b) < tolerance2*3.0f )
+ {
+ color.r = colorNew2.r+color.r-colorRef2.r+shift;
+ color.g = colorNew2.g+color.g-colorRef2.g+shift;
+ color.b = colorNew2.b+color.b-colorRef2.b+shift;
+ ::SetDot(&ddsd, x, y, color);
+ }
+ }
+ }
+ }
+
+ surface->Unlock(NULL);
+ return TRUE;
+}
+
+
+// Ouvre une image pour travailler directement dedans.
+
+BOOL CD3DEngine::OpenImage(char *name)
+{
+//? D3DTextr_Invalidate(name);
+//? LoadTexture(name);
+
+ m_imageSurface = D3DTextr_GetSurface(name);
+ if ( m_imageSurface == 0 ) return FALSE;
+
+ ZeroMemory(&m_imageDDSD, sizeof(DDSURFACEDESC2));
+ m_imageDDSD.dwSize = sizeof(DDSURFACEDESC2);
+ if ( m_imageSurface->Lock(NULL, &m_imageDDSD, DDLOCK_WAIT, NULL) != DD_OK )
+ {
+ return FALSE;
+ }
+
+ if ( m_imageDDSD.ddpfPixelFormat.dwRGBBitCount != 16 )
+ {
+ m_imageSurface->Unlock(NULL);
+ return FALSE;
+ }
+
+ m_imageDX = m_imageDDSD.dwWidth;
+ m_imageDY = m_imageDDSD.dwHeight;
+
+ return TRUE;
+}
+
+// Copie l'image de travail.
+
+BOOL CD3DEngine::CopyImage()
+{
+ WORD* pbSurf;
+ int y;
+
+ if ( m_imageCopy == 0 )
+ {
+ m_imageCopy = (WORD*)malloc(m_imageDX*m_imageDY*sizeof(WORD));
+ }
+
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ pbSurf = (WORD*)m_imageDDSD.lpSurface;
+ pbSurf += m_imageDDSD.lPitch*y/2;
+ memcpy(m_imageCopy+y*m_imageDX, pbSurf, m_imageDX*sizeof(WORD));
+ }
+ return TRUE;
+}
+
+// Restitue l'image de travail.
+
+BOOL CD3DEngine::LoadImage()
+{
+ WORD* pbSurf;
+ int y;
+
+ if ( m_imageCopy == 0 ) return FALSE;
+
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ pbSurf = (WORD*)m_imageDDSD.lpSurface;
+ pbSurf += m_imageDDSD.lPitch*y/2;
+ memcpy(pbSurf, m_imageCopy+y*m_imageDX, m_imageDX*sizeof(WORD));
+ }
+ return TRUE;
+}
+
+// Scroll la copie de l'image de travial.
+
+BOOL CD3DEngine::ScrollImage(int dx, int dy)
+{
+ int x, y;
+
+ if ( dx > 0 )
+ {
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ for ( x=0 ; x<m_imageDX-dx ; x++ )
+ {
+ m_imageCopy[x+y*m_imageDX] = m_imageCopy[x+dx+y*m_imageDX];
+ }
+ }
+ }
+
+ if ( dx < 0 )
+ {
+ for ( y=0 ; y<m_imageDY ; y++ )
+ {
+ for ( x=m_imageDX-1 ; x>=-dx ; x-- )
+ {
+ m_imageCopy[x+y*m_imageDX] = m_imageCopy[x+dx+y*m_imageDX];
+ }
+ }
+ }
+
+ if ( dy > 0 )
+ {
+ for ( y=0 ; y<m_imageDY-dy ; y++ )
+ {
+ memcpy(m_imageCopy+y*m_imageDX, m_imageCopy+(y+dy)*m_imageDX, m_imageDX*sizeof(WORD));
+ }
+ }
+
+ if ( dy < 0 )
+ {
+ for ( y=m_imageDY-1 ; y>=-dy ; y-- )
+ {
+ memcpy(m_imageCopy+y*m_imageDX, m_imageCopy+(y+dy)*m_imageDX, m_imageDX*sizeof(WORD));
+ }
+ }
+
+ return TRUE;
+}
+
+// Dessine un point dans l'image de travail.
+
+BOOL CD3DEngine::SetDot(int x, int y, D3DCOLORVALUE color)
+{
+ WORD* pbSurf;
+ WORD r,g,b, w;
+
+ if ( x < 0 || x >= m_imageDX ||
+ y < 0 || y >= m_imageDY ) return FALSE;
+
+#if 1
+ if ( color.r < 0.0f ) color.r = 0.0f;
+ if ( color.r > 1.0f ) color.r = 1.0f;
+ if ( color.g < 0.0f ) color.g = 0.0f;
+ if ( color.g > 1.0f ) color.g = 1.0f;
+ if ( color.b < 0.0f ) color.b = 0.0f;
+ if ( color.b > 1.0f ) color.b = 1.0f;
+
+ r = (int)(color.r*32.0f);
+ g = (int)(color.g*32.0f);
+ b = (int)(color.b*32.0f);
+
+ if ( r >= 32 ) r = 31; // 5 bits
+ if ( g >= 32 ) g = 31; // 5 bits
+ if ( b >= 32 ) b = 31; // 5 bits
+#else
+ r = (int)(color.r*31.0f);
+ g = (int)(color.g*31.0f);
+ b = (int)(color.b*31.0f);
+#endif
+
+ if ( m_imageDDSD.ddpfPixelFormat.dwRBitMask == 0xf800 ) // 565 ?
+ {
+ w = (r<<11)|(g<<6)|b;
+ }
+ else if ( m_imageDDSD.ddpfPixelFormat.dwRBitMask == 0x7c00 ) // 555 ?
+ {
+ w = (r<<10)|(g<<5)|b;
+ }
+ else
+ {
+ w = -1; // blanc
+ }
+
+ pbSurf = (WORD*)m_imageDDSD.lpSurface;
+ pbSurf += m_imageDDSD.lPitch*y/2;
+ pbSurf += x;
+
+ *pbSurf = w;
+ return TRUE;
+}
+
+// Ferme l'image de travail.
+
+BOOL CD3DEngine::CloseImage()
+{
+ m_imageSurface->Unlock(NULL);
+ return TRUE;
+}
+
+
+// Ecrit un fichier .BMP copie d'écran.
+
+BOOL CD3DEngine::WriteScreenShot(char *filename, int width, int height)
+{
+ return m_app->WriteScreenShot(filename, width, height);
+}
+
+// Initialise un hDC sur la surface de rendu.
+
+BOOL CD3DEngine::GetRenderDC(HDC &hDC)
+{
+ return m_app->GetRenderDC(hDC);
+}
+
+// Libère le hDC sur la surface de rendu.
+
+BOOL CD3DEngine::ReleaseRenderDC(HDC &hDC)
+{
+ return m_app->ReleaseRenderDC(hDC);
+}
+
+PBITMAPINFO CD3DEngine::CreateBitmapInfoStruct(HBITMAP hBmp)
+{
+ return m_app->CreateBitmapInfoStruct(hBmp);
+}
+
+BOOL CD3DEngine::CreateBMPFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
+{
+ return m_app->CreateBMPFile(pszFile, pbi, hBMP, hDC);
+}
+
+// Retourne le pointeur à la classe CText.
+
+CText* CD3DEngine::RetText()
+{
+ return m_text;
+}
+
+
+// Gestion du texte d'informations affiché dans la fenêtre.
+
+void CD3DEngine::SetInfoText(int line, char* text)
+{
+ strcpy(m_infoText[line], text);
+}
+
+char* CD3DEngine::RetInfoText(int line)
+{
+ return m_infoText[line];
+}
+
+
+
+// Spécifie la focale de la caméra.
+// 0.75 = normal
+// 1.50 = grand-angle
+
+void CD3DEngine::SetFocus(float focus)
+{
+ D3DVIEWPORT7 vp;
+ float fAspect;
+
+ m_focus = focus;
+
+ if ( m_pD3DDevice != 0 )
+ {
+ m_pD3DDevice->GetViewport(&vp);
+ m_dim.x = vp.dwWidth;
+ m_dim.y = vp.dwHeight;
+ }
+
+ fAspect = ((float)m_dim.y) / m_dim.x;
+//? D3DUtil_SetProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[m_rankView]);
+ D3DUtil_SetProjectionMatrix(m_matProj, m_focus, fAspect, 0.5f, m_deepView[0]);
+}
+
+float CD3DEngine::RetFocus()
+{
+ return m_focus;
+}
+
+//
+
+void CD3DEngine::UpdateMatProj()
+{
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &m_matProj);
+}
+
+
+
+// Ignore les touches pressées.
+
+void CD3DEngine::FlushPressKey()
+{
+ m_app->FlushPressKey();
+}
+
+// Remet les touches par défaut.
+
+void CD3DEngine::ResetKey()
+{
+ m_app->ResetKey();
+}
+
+// Modifie une touche.
+
+void CD3DEngine::SetKey(int keyRank, int option, int key)
+{
+ m_app->SetKey(keyRank, option, key);
+}
+
+// Donne une touche.
+
+int CD3DEngine::RetKey(int keyRank, int option)
+{
+ return m_app->RetKey(keyRank, option);
+}
+
+
+// Utilise le joystick ou le clavier.
+
+void CD3DEngine::SetJoystick(BOOL bEnable)
+{
+ m_app->SetJoystick(bEnable);
+}
+
+BOOL CD3DEngine::RetJoystick()
+{
+ return m_app->RetJoystick();
+}
+
+
+void CD3DEngine::SetDebugMode(BOOL bMode)
+{
+ m_app->SetDebugMode(bMode);
+}
+
+BOOL CD3DEngine::RetDebugMode()
+{
+ return m_app->RetDebugMode();
+}
+
+BOOL CD3DEngine::RetSetupMode()
+{
+ return m_app->RetSetupMode();
+}
+
+
+// Indique si un point est visible.
+
+BOOL CD3DEngine::IsVisiblePoint(const D3DVECTOR &pos)
+{
+ return ( Length(m_eyePt, pos) <= m_deepView[0] );
+}
+
+
+// Initialize scene objects.
+
+HRESULT CD3DEngine::InitDeviceObjects()
+{
+ // Set miscellaneous render states.
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_GOURAUD);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID);
+
+ // Set up the textures.
+ D3DTextr_RestoreAllTextures(m_pD3DDevice);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR);
+ m_pD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_MINFILTER, D3DTFN_LINEAR);
+ m_pD3DDevice->SetTextureStageState(1, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
+
+ SetFocus(m_focus);
+
+ // Définitions des matrices pour l'interface.
+ D3DUtil_SetIdentityMatrix(m_matWorldInterface);
+
+ D3DUtil_SetIdentityMatrix(m_matViewInterface);
+ m_matViewInterface._41 = -0.5f;
+ m_matViewInterface._42 = -0.5f;
+ m_matViewInterface._43 = 1.0f;
+
+ D3DUtil_SetIdentityMatrix(m_matProjInterface);
+ m_matProjInterface._11 = 2.0f;
+ m_matProjInterface._22 = 2.0f;
+ m_matProjInterface._34 = 1.0f;
+ m_matProjInterface._43 = -1.0f;
+ m_matProjInterface._44 = 0.0f;
+
+ return S_OK;
+}
+
+
+// Restore all surfaces.
+
+HRESULT CD3DEngine::RestoreSurfaces()
+{
+ return S_OK;
+}
+
+
+// Called when the app is exitting, or the device is being changed,
+// this function deletes any device dependant objects.
+
+HRESULT CD3DEngine::DeleteDeviceObjects()
+{
+ D3DTextr_InvalidateAllTextures();
+ return S_OK;
+}
+
+
+// Called before the app exits, this function gives the app the chance
+// to cleanup after itself.
+
+HRESULT CD3DEngine::FinalCleanup()
+{
+ return S_OK;
+}
+
+
+// Overrrides the main WndProc, so the sample can do custom message
+// handling (e.g. processing mouse, keyboard, or menu commands).
+
+LRESULT CD3DEngine::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+#if 0
+ if ( uMsg == WM_KEYDOWN ) // Alt+key ?
+ {
+ if ( wParam == 'Q' )
+ {
+ debug_blend1 ++;
+ if ( debug_blend1 > 13 ) debug_blend1 = 0;
+ }
+ if ( wParam == 'W' )
+ {
+ debug_blend2 ++;
+ if ( debug_blend2 > 13 ) debug_blend2 = 0;
+ }
+ if ( wParam == 'E' )
+ {
+ debug_blend3 ++;
+ if ( debug_blend3 > 13 ) debug_blend3 = 0;
+ }
+ if ( wParam == 'R' )
+ {
+ debug_blend4 ++;
+ if ( debug_blend4 > 13 ) debug_blend4 = 0;
+ }
+ char s[100];
+ sprintf(s, "src=%d, dest=%d, src=%d, dest=%d", debug_blend1, debug_blend2, debug_blend3, debug_blend4);
+ SetInfoText(4, s);
+ }
+#endif
+
+#if 1
+ if ( uMsg == WM_SYSKEYDOWN ) // Alt+key ?
+ {
+ if ( wParam == VK_F7 ) // Alt+F7 ?
+ {
+ s_resol = 0;
+ }
+ if ( wParam == VK_F8 ) // Alt+F8 ?
+ {
+ s_resol = 1;
+ }
+ if ( wParam == VK_F9 ) // Alt+F9 ?
+ {
+ s_resol = 2;
+ }
+ if ( wParam == VK_F10 ) // Alt+F10 ?
+ {
+ s_resol = 3;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+// Gestion de la souris.
+
+void CD3DEngine::MoveMousePos(FPOINT pos)
+{
+ m_mousePos = pos;
+ m_app->SetMousePos(pos);
+}
+
+void CD3DEngine::SetMousePos(FPOINT pos)
+{
+ m_mousePos = pos;
+}
+
+FPOINT CD3DEngine::RetMousePos()
+{
+ return m_mousePos;
+}
+
+void CD3DEngine::SetMouseType(D3DMouse type)
+{
+ m_mouseType = type;
+}
+
+D3DMouse CD3DEngine::RetMouseType()
+{
+ return m_mouseType;
+}
+
+void CD3DEngine::SetMouseHide(BOOL bHide)
+{
+ if ( m_bMouseHide == bHide ) return;
+
+ if ( bHide ) // cache la souris ?
+ {
+ m_bNiceMouse = m_app->RetNiceMouse();
+ if ( !m_bNiceMouse )
+ {
+ m_app->SetNiceMouse(TRUE);
+ }
+ m_bMouseHide = TRUE;
+ }
+ else // montre la souris ?
+ {
+ if ( !m_bNiceMouse )
+ {
+ m_app->SetNiceMouse(FALSE);
+ }
+ m_bMouseHide = FALSE;
+ }
+}
+
+BOOL CD3DEngine::RetMouseHide()
+{
+ return m_bMouseHide;
+}
+
+void CD3DEngine::SetNiceMouse(BOOL bNice)
+{
+ m_app->SetNiceMouse(bNice);
+}
+
+BOOL CD3DEngine::RetNiceMouse()
+{
+ return m_app->RetNiceMouse();
+}
+
+BOOL CD3DEngine::RetNiceMouseCap()
+{
+ return m_app->RetNiceMouseCap();
+}
+
+// Dessine le sprite de la souris.
+
+void CD3DEngine::DrawMouse()
+{
+ D3DMATERIAL7 material;
+ FPOINT pos, ppos, dim;
+ int i;
+
+ typedef struct
+ {
+ D3DMouse type;
+ int icon1, icon2, iconShadow;
+ int mode1, mode2;
+ float hotx, hoty;
+ }
+ Mouse;
+
+ static Mouse table[] =
+ {
+ { D3DMOUSENORM, 0, 1,32, D3DSTATETTw, D3DSTATETTb, 1.0f, 1.0f},
+ { D3DMOUSEWAIT, 2, 3,33, D3DSTATETTw, D3DSTATETTb, 8.0f, 12.0f},
+ { D3DMOUSEHAND, 4, 5,34, D3DSTATETTw, D3DSTATETTb, 7.0f, 2.0f},
+ { D3DMOUSENO, 6, 7,35, D3DSTATETTw, D3DSTATETTb, 10.0f, 10.0f},
+ { D3DMOUSEEDIT, 8, 9,-1, D3DSTATETTb, D3DSTATETTw, 6.0f, 10.0f},
+ { D3DMOUSECROSS, 10,11,-1, D3DSTATETTb, D3DSTATETTw, 10.0f, 10.0f},
+ { D3DMOUSEMOVEV, 12,13,-1, D3DSTATETTb, D3DSTATETTw, 5.0f, 11.0f},
+ { D3DMOUSEMOVEH, 14,15,-1, D3DSTATETTb, D3DSTATETTw, 11.0f, 5.0f},
+ { D3DMOUSEMOVED, 16,17,-1, D3DSTATETTb, D3DSTATETTw, 9.0f, 9.0f},
+ { D3DMOUSEMOVEI, 18,19,-1, D3DSTATETTb, D3DSTATETTw, 9.0f, 9.0f},
+ { D3DMOUSEMOVE, 20,21,-1, D3DSTATETTb, D3DSTATETTw, 11.0f, 11.0f},
+ { D3DMOUSETARGET, 22,23,-1, D3DSTATETTb, D3DSTATETTw, 15.0f, 15.0f},
+ { D3DMOUSESCROLLL, 24,25,43, D3DSTATETTb, D3DSTATETTw, 2.0f, 9.0f},
+ { D3DMOUSESCROLLR, 26,27,44, D3DSTATETTb, D3DSTATETTw, 17.0f, 9.0f},
+ { D3DMOUSESCROLLU, 28,29,45, D3DSTATETTb, D3DSTATETTw, 9.0f, 2.0f},
+ { D3DMOUSESCROLLD, 30,31,46, D3DSTATETTb, D3DSTATETTw, 9.0f, 17.0f},
+ { D3DMOUSEHIDE },
+ };
+
+ if ( m_bMouseHide ) return;
+ if ( !m_app->RetNiceMouse() ) return; // souris windows ?
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse.r = 1.0f;
+ material.diffuse.g = 1.0f;
+ material.diffuse.b = 1.0f;
+ material.ambient.r = 0.5f;
+ material.ambient.g = 0.5f;
+ material.ambient.b = 0.5f;
+ SetMaterial(material);
+
+ SetTexture("mouse.tga");
+
+ i = 0;
+ while ( table[i].type != D3DMOUSEHIDE )
+ {
+ if ( m_mouseType == table[i].type )
+ {
+ dim.x = 0.05f*0.75f;
+ dim.y = 0.05f;
+
+ pos.x = m_mousePos.x - (table[i].hotx*dim.x)/32.0f;
+ pos.y = m_mousePos.y - ((32.0f-table[i].hoty)*dim.y)/32.0f;
+
+ ppos.x = pos.x+(4.0f/640.0f);
+ ppos.y = pos.y-(3.0f/480.0f);
+ SetState(D3DSTATETTw);
+ DrawSprite(ppos, dim, table[i].iconShadow);
+
+ SetState(table[i].mode1);
+ DrawSprite(pos, dim, table[i].icon1);
+
+ SetState(table[i].mode2);
+ DrawSprite(pos, dim, table[i].icon2);
+ break;
+ }
+ i ++;
+ }
+}
+
+// Dessine le sprite de la souris.
+
+void CD3DEngine::DrawSprite(FPOINT pos, FPOINT dim, int icon)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2;
+ D3DVECTOR n;
+ float u1, u2, v1, v2, dp;
+
+ if ( icon == -1 ) return;
+
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + dim.x;
+ p2.y = pos.y + dim.y;
+
+ u1 = (32.0f/256.0f)*(icon%8);
+ v1 = (32.0f/256.0f)*(icon/8); // u-v texture
+ u2 = (32.0f/256.0f)+u1;
+ v2 = (32.0f/256.0f)+v1;
+
+ dp = 0.5f/256.0f;
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ AddStatisticTriangle(2);
+}
+
diff --git a/src/d3dengine.h b/src/d3dengine.h
new file mode 100644
index 0000000..8bc2c4e
--- /dev/null
+++ b/src/d3dengine.h
@@ -0,0 +1,669 @@
+// D3DEngine.h
+
+#ifndef _D3DENGINE_H_
+#define _D3DENGINE_H_
+
+#include "D3DApp.h"
+
+
+
+class CInstanceManager;
+class CObject;
+class CLight;
+class CText;
+class CParticule;
+class CWater;
+class CCloud;
+class CBlitz;
+class CPlanet;
+class CSound;
+class CTerrain;
+
+
+#define D3DMAXOBJECT 1200
+#define D3DMAXSHADOW 500
+#define D3DMAXGROUNDSPOT 100
+
+
+enum D3DTypeObj
+{
+ TYPENULL = 0, // object inexistant
+ TYPETERRAIN = 1, // terrain
+ TYPEFIX = 2, // objet fixe
+ TYPEVEHICULE = 3, // objet mobile
+ TYPEDESCENDANT = 4, // partie d'un objet mobile
+ TYPEQUARTZ = 5, // objet fixe de type quartz
+ TYPEMETAL = 6, // objet fixe de type métalique
+};
+
+enum D3DTypeTri
+{
+ D3DTYPE6T = 1, // triangles
+ D3DTYPE6S = 2, // surfaces
+};
+
+enum D3DMaping
+{
+ D3DMAPPINGX = 1,
+ D3DMAPPINGY = 2,
+ D3DMAPPINGZ = 3,
+ D3DMAPPING1X = 4,
+ D3DMAPPING1Y = 5,
+ D3DMAPPING1Z = 6,
+};
+
+enum D3DMouse
+{
+ D3DMOUSEHIDE = 0, // pas de souris
+ D3DMOUSENORM = 1,
+ D3DMOUSEWAIT = 2,
+ D3DMOUSEEDIT = 3,
+ D3DMOUSEHAND = 4,
+ D3DMOUSECROSS = 5,
+ D3DMOUSESHOW = 6,
+ D3DMOUSENO = 7,
+ D3DMOUSEMOVE = 8, // +
+ D3DMOUSEMOVEH = 9, // -
+ D3DMOUSEMOVEV = 10, // |
+ D3DMOUSEMOVED = 11, // /
+ D3DMOUSEMOVEI = 12, // \
+ D3DMOUSESCROLLL = 13, // <<
+ D3DMOUSESCROLLR = 14, // >>
+ D3DMOUSESCROLLU = 15, // ^
+ D3DMOUSESCROLLD = 16, // v
+ D3DMOUSETARGET = 17,
+};
+
+enum D3DShadowType
+{
+ D3DSHADOWNORM = 0,
+ D3DSHADOWWORM = 1,
+};
+
+
+#define D3DSTATENORMAL 0 // matériaux opaque normal
+#define D3DSTATETTb (1<<0) // transparent selon texture (noir=rien)
+#define D3DSTATETTw (1<<1) // transparent selon texture (blanc=rien)
+#define D3DSTATETD (1<<2) // transparent selon couleur diffuse
+#define D3DSTATEWRAP (1<<3) // texture wrappée
+#define D3DSTATECLAMP (1<<4) // texture bordée d'une couleur unie
+#define D3DSTATELIGHT (1<<5) // texture lumineuse (ambiance max)
+#define D3DSTATEDUALb (1<<6) // double texturage noir
+#define D3DSTATEDUALw (1<<7) // double texturage blanc
+#define D3DSTATEPART1 (1<<8) // partie 1 (ne pas changer, dans .MOD !)
+#define D3DSTATEPART2 (1<<9) // partie 2
+#define D3DSTATEPART3 (1<<10) // partie 3
+#define D3DSTATEPART4 (1<<11) // partie 4
+#define D3DSTATE2FACE (1<<12) // mode double-face
+#define D3DSTATEALPHA (1<<13) // image avec canal alpha
+#define D3DSTATESECOND (1<<14) // utilise tjrs 2ème étage de texturage
+#define D3DSTATEFOG (1<<15) // force le brouillard
+#define D3DSTATETCb (1<<16) // transparent selon couleur (noir=rien)
+#define D3DSTATETCw (1<<17) // transparent selon couleur (blanc=rien)
+
+
+typedef struct
+{
+ D3DVERTEX2 triangle[3];
+ D3DMATERIAL7 material;
+ int state;
+ char texName1[20];
+ char texName2[20];
+}
+D3DTriangle;
+
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ D3DMATERIAL7 material;
+ int state;
+ D3DTypeTri type; // D3DTYPE6x
+ D3DVERTEX2 vertex[1];
+}
+D3DObjLevel6;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ int reserve;
+ D3DObjLevel6* table[1];
+}
+D3DObjLevel5;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ float min, max;
+ D3DObjLevel5* table[1];
+}
+D3DObjLevel4;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ int objRank;
+ D3DObjLevel4* table[1];
+}
+D3DObjLevel3;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ char texName1[20];
+ char texName2[20];
+ D3DObjLevel3* table[1];
+}
+D3DObjLevel2;
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ D3DObjLevel2* table[1];
+}
+D3DObjLevel1;
+
+
+typedef struct
+{
+ char bUsed; // TRUE -> objet existe
+ char bVisible; // TRUE -> objet visible
+ char bDrawWorld; // TRUE -> dessine derrière l'interface
+ char bDrawFront; // TRUE -> dessine devant l'interface
+ int totalTriangle; // nb de triangles utilisés
+ D3DTypeObj type; // type de l'objet (TYPE*)
+ D3DMATRIX transform; // matrice de transformation
+ float distance; // distance point de vue - origine
+ D3DVECTOR bboxMin; // bounding box de l'objet
+ D3DVECTOR bboxMax; // (l'origine 0;0;0 est tjrs incluse)
+ float radius; // rayon de la sphère à l'origine
+ int shadowRank; // rang de l'ombre associée
+ float transparency; // transparence de l'objet (0..1)
+}
+D3DObject;
+
+typedef struct
+{
+ char bUsed; // TRUE -> objet existe
+ char bHide; // TRUE -> ombre invisible (objet porté par ex.)
+ int objRank; // rang de l'objet
+ D3DShadowType type; // type de l'ombre
+ D3DVECTOR pos; // position pour l'ombre
+ D3DVECTOR normal; // normale au terrain
+ float angle; // angle de l'ombre
+ float radius; // rayon de l'ombre
+ float intensity; // intensité de l'ombre
+ float height; // hauteur depuis le sol
+}
+D3DShadow;
+
+typedef struct
+{
+ char bUsed; // TRUE -> objet existe
+ D3DCOLORVALUE color; // couleur de l'ombre
+ float min, max; // altitudes min/max
+ float smooth; // zone de transition
+ D3DVECTOR pos; // position pour l'ombre
+ float radius; // rayon de l'ombre
+ D3DVECTOR drawPos; // position pour l'ombre dessinée
+ float drawRadius; // rayon de l'ombre dessinée
+}
+D3DGroundSpot;
+
+typedef struct
+{
+ char bUsed; // TRUE -> objet existe
+ char bDraw; // TRUE -> marque dessinée
+ int phase; // 1=croissance, 2=fixe, 3=décroissance
+ float delay[3]; // délais pour les 3 phases
+ float fix; // temps fixe
+ D3DVECTOR pos; // position pour marques
+ float radius; // rayon des marques
+ float intensity; // intensité couleur
+ D3DVECTOR drawPos; // position pour marques dessinées
+ float drawRadius; // rayon des marques dessinées
+ float drawIntensity; // intensité dessinée
+ int dx, dy; // dimensions table
+ char* table; // pointeur à la table
+}
+D3DGroundMark;
+
+
+
+class CD3DEngine
+{
+public:
+ CD3DEngine(CInstanceManager *iMan, CD3DApplication *app);
+ ~CD3DEngine();
+
+ void SetD3DDevice(LPDIRECT3DDEVICE7 device);
+ LPDIRECT3DDEVICE7 RetD3DDevice();
+
+ void SetTerrain(CTerrain* terrain);
+
+ BOOL WriteProfile();
+
+ void SetPause(BOOL bPause);
+ BOOL RetPause();
+
+ void SetMovieLock(BOOL bLock);
+ BOOL RetMovieLock();
+
+ void SetShowStat(BOOL bShow);
+ BOOL RetShowStat();
+
+ void SetRenderEnable(BOOL bEnable);
+
+ HRESULT OneTimeSceneInit();
+ HRESULT InitDeviceObjects();
+ HRESULT DeleteDeviceObjects();
+ HRESULT RestoreSurfaces();
+ HRESULT Render();
+ HRESULT FrameMove(float rTime);
+ void StepSimul(float rTime);
+ HRESULT FinalCleanup();
+ void AddStatisticTriangle(int nb);
+ int RetStatisticTriangle();
+ void SetHiliteRank(int *rankList);
+ BOOL GetHilite(FPOINT &p1, FPOINT &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 bFirst);
+ 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 bFull);
+
+ D3DMATRIX* RetMatView();
+ D3DMATRIX* RetMatLeftView();
+ D3DMATRIX* RetMatRightView();
+
+ void TimeInit();
+ void TimeEnterGel();
+ void TimeExitGel();
+ float TimeGet();
+
+ int RetRestCreate();
+ int CreateObject();
+ void FlushObject();
+ BOOL DeleteObject(int objRank);
+ BOOL SetDrawWorld(int objRank, BOOL bDraw);
+ BOOL SetDrawFront(int objRank, BOOL bDraw);
+ BOOL AddTriangle(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, BOOL bGlobalUpdate);
+ BOOL AddSurface(int objRank, D3DVERTEX2* vertex, int nb, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, BOOL bGlobalUpdate);
+ BOOL AddQuick(int objRank, D3DObjLevel6* buffer, char* texName1, char* texName2, float min, float max, BOOL bGlobalUpdate);
+ D3DObjLevel6* SearchTriangle(int objRank, const D3DMATERIAL7 &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, D3DTriangle* buffer, int size, float percent);
+ BOOL GetBBox(int objRank, D3DVECTOR &min, D3DVECTOR &max);
+ BOOL ChangeTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float au, float bu, float av, float bv);
+ BOOL TrackTextureMapping(int objRank, const D3DMATERIAL7 &mat, int state, char* texName1, char* texName2, float min, float max, D3DMaping mode, float pos, float factor, float tl, float ts, float tt);
+ BOOL SetObjectTransform(int objRank, const D3DMATRIX &transform);
+ BOOL GetObjectTransform(int objRank, D3DMATRIX &transform);
+ BOOL SetObjectType(int objRank, D3DTypeObj type);
+ D3DTypeObj RetObjectType(int objRank);
+ BOOL SetObjectTransparency(int objRank, float value);
+
+ BOOL ShadowCreate(int objRank);
+ void ShadowDelete(int objRank);
+ BOOL SetObjectShadowHide(int objRank, BOOL bHide);
+ BOOL SetObjectShadowType(int objRank, D3DShadowType type);
+ BOOL SetObjectShadowPos(int objRank, const D3DVECTOR &pos);
+ BOOL SetObjectShadowNormal(int objRank, const D3DVECTOR &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 D3DVECTOR &pos);
+ BOOL SetObjectGroundSpotRadius(int rank, float radius);
+ BOOL SetObjectGroundSpotColor(int rank, D3DCOLORVALUE color);
+ BOOL SetObjectGroundSpotMinMax(int rank, float min, float max);
+ BOOL SetObjectGroundSpotSmooth(int rank, float smooth);
+
+ int GroundMarkCreate(D3DVECTOR pos, float radius, float delay1, float delay2, float delay3, int dx, int dy, char* table);
+ BOOL GroundMarkDelete(int rank);
+
+ void Update();
+
+ void SetViewParams(const D3DVECTOR &vEyePt, const D3DVECTOR &vLookatPt, const D3DVECTOR &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 bLast=FALSE);
+
+ void SetTerrainVision(float vision);
+
+ void SetGroundSpot(BOOL bMode);
+ BOOL RetGroundSpot();
+ void SetShadow(BOOL bMode);
+ BOOL RetShadow();
+ void SetDirty(BOOL bMode);
+ BOOL RetDirty();
+ void SetFog(BOOL bMode);
+ BOOL RetFog();
+ BOOL RetStateColor();
+
+ void SetSecondTexture(int texNum);
+ int RetSecondTexture();
+
+ void SetRankView(int rank);
+ int RetRankView();
+
+ void SetDrawWorld(BOOL bDraw);
+ void SetDrawFront(BOOL bDraw);
+
+ void SetAmbiantColor(D3DCOLOR color, int rank=0);
+ D3DCOLOR RetAmbiantColor(int rank=0);
+
+ void SetWaterAddColor(D3DCOLORVALUE color);
+ D3DCOLORVALUE RetWaterAddColor();
+
+ void SetFogColor(D3DCOLOR color, int rank=0);
+ D3DCOLOR RetFogColor(int rank=0);
+
+ void SetDeepView(float length, int rank=0, BOOL bRef=FALSE);
+ float RetDeepView(int rank=0);
+
+ void SetFogStart(float start, int rank=0);
+ float RetFogStart(int rank=0);
+
+ void SetBackground(char *name, D3DCOLOR up=0, D3DCOLOR down=0, D3DCOLOR cloudUp=0, D3DCOLOR cloudDown=0, BOOL bFull=FALSE, BOOL bQuarter=FALSE);
+ void RetBackground(char *name, D3DCOLOR &up, D3DCOLOR &down, D3DCOLOR &cloudUp, D3DCOLOR &cloudDown, BOOL &bFull, BOOL &bQuarter);
+ void SetFrontsizeName(char *name);
+ void SetOverFront(BOOL bFront);
+ void SetOverColor(D3DCOLOR color=0, int mode=D3DSTATETCb);
+
+ 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 bPresent);
+ BOOL RetTotoMode();
+
+ void SetLensMode(BOOL bPresent);
+ BOOL RetLensMode();
+
+ void SetWaterMode(BOOL bPresent);
+ BOOL RetWaterMode();
+
+ void SetBlitzMode(BOOL bPresent);
+ BOOL RetBlitzMode();
+
+ void SetSkyMode(BOOL bPresent);
+ BOOL RetSkyMode();
+
+ void SetBackForce(BOOL bPresent);
+ BOOL RetBackForce();
+
+ void SetPlanetMode(BOOL bPresent);
+ BOOL RetPlanetMode();
+
+ void SetLightMode(BOOL bPresent);
+ BOOL RetLightMode();
+
+ void SetEditIndentMode(BOOL bAuto);
+ 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();
+ D3DVECTOR RetEyePt();
+ D3DVECTOR RetLookatPt();
+ float RetEyeDirH();
+ float RetEyeDirV();
+ 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 bEnable);
+ BOOL RetJoystick();
+
+ void SetDebugMode(BOOL bMode);
+ BOOL RetDebugMode();
+ BOOL RetSetupMode();
+
+ BOOL IsVisiblePoint(const D3DVECTOR &pos);
+
+ int DetectObject(FPOINT mouse);
+ void SetState(int state, D3DCOLOR color=0xffffffff);
+ void SetTexture(char *name, int stage=0);
+ void SetMaterial(const D3DMATERIAL7 &mat);
+
+ void MoveMousePos(FPOINT pos);
+ void SetMousePos(FPOINT pos);
+ FPOINT RetMousePos();
+ void SetMouseType(D3DMouse type);
+ D3DMouse RetMouseType();
+ void SetMouseHide(BOOL bHide);
+ BOOL RetMouseHide();
+ void SetNiceMouse(BOOL bNice);
+ BOOL RetNiceMouse();
+ BOOL RetNiceMouseCap();
+
+ CText* RetText();
+
+ BOOL ChangeColor(char *name, D3DCOLORVALUE colorRef1, D3DCOLORVALUE colorNew1, D3DCOLORVALUE colorRef2, D3DCOLORVALUE colorNew2, float tolerance1, float tolerance2, FPOINT ts, FPOINT ti, FPOINT *pExclu=0, float shift=0.0f, BOOL bHSV=FALSE);
+ BOOL OpenImage(char *name);
+ BOOL CopyImage();
+ BOOL LoadImage();
+ BOOL ScrollImage(int dx, int dy);
+ BOOL SetDot(int x, int y, D3DCOLORVALUE 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(D3DObjLevel1 *&p, int nb);
+ void MemSpace2(D3DObjLevel2 *&p, int nb);
+ void MemSpace3(D3DObjLevel3 *&p, int nb);
+ void MemSpace4(D3DObjLevel4 *&p, int nb);
+ void MemSpace5(D3DObjLevel5 *&p, int nb);
+ void MemSpace6(D3DObjLevel6 *&p, int nb);
+
+ D3DObjLevel2* AddLevel1(D3DObjLevel1 *&p1, char* texName1, char* texName2);
+ D3DObjLevel3* AddLevel2(D3DObjLevel2 *&p2, int objRank);
+ D3DObjLevel4* AddLevel3(D3DObjLevel3 *&p3, float min, float max);
+ D3DObjLevel5* AddLevel4(D3DObjLevel4 *&p4, int reserve);
+ D3DObjLevel6* AddLevel5(D3DObjLevel5 *&p5, D3DTypeTri type, const D3DMATERIAL7 &mat, int state, int nb);
+
+ BOOL IsVisible(int objRank);
+ BOOL DetectBBox(int objRank, FPOINT mouse);
+ BOOL DetectTriangle(FPOINT mouse, D3DVERTEX2 *triangle, int objRank, float &dist);
+ BOOL TransformPoint(D3DVECTOR &p2D, int objRank, D3DVECTOR p3D);
+ void ComputeDistance();
+ void UpdateGeometry();
+ void RenderGroundSpot();
+ void DrawShadow();
+ void DrawBackground();
+ void DrawBackgroundGradient(D3DCOLOR up, D3DCOLOR down);
+ void DrawBackgroundImageQuarter(FPOINT p1, FPOINT p2, char *name);
+ void DrawBackgroundImage();
+ void DrawPlanet();
+ void DrawFrontsize();
+ void DrawOverColor();
+ BOOL GetBBox2D(int objRank, FPOINT &min, FPOINT &max);
+ void DrawHilite();
+ void DrawMouse();
+ void DrawSprite(FPOINT pos, FPOINT dim, int icon);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DApplication* m_app;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+ CText* m_text;
+ CLight* m_light;
+ CParticule* m_particule;
+ CWater* m_water;
+ CCloud* m_cloud;
+ CBlitz* m_blitz;
+ CPlanet* m_planet;
+ CSound* m_sound;
+ CTerrain* m_terrain;
+
+ 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];
+
+ D3DMATRIX m_matProj;
+ D3DMATRIX m_matLeftView;
+ D3DMATRIX m_matRightView;
+ D3DMATRIX m_matView;
+ float m_focus;
+
+ D3DMATRIX m_matWorldInterface;
+ D3DMATRIX m_matProjInterface;
+ D3DMATRIX m_matViewInterface;
+
+ DWORD m_baseTime;
+ DWORD m_stopTime;
+ float m_absTime;
+ float m_lastTime;
+ float m_speed;
+ BOOL m_bPause;
+ BOOL m_bRender;
+ BOOL m_bMovieLock;
+
+ POINT m_dim;
+ POINT m_lastDim;
+ D3DObjLevel1* m_objectPointer;
+ int m_objectParamTotal;
+ D3DObject* m_objectParam;
+ int m_shadowTotal;
+ D3DShadow* m_shadow;
+ D3DGroundSpot* m_groundSpot;
+ D3DGroundMark m_groundMark;
+ D3DVECTOR m_eyePt;
+ D3DVECTOR m_lookatPt;
+ float m_eyeDirH;
+ float m_eyeDirV;
+ int m_rankView;
+ D3DCOLOR m_ambiantColor[2];
+ D3DCOLOR m_backColor[2];
+ D3DCOLOR m_fogColor[2];
+ float m_deepView[2];
+ float m_fogStart[2];
+ D3DCOLORVALUE m_waterAddColor;
+ int m_statisticTriangle;
+ BOOL m_bUpdateGeometry;
+ char m_infoText[10][200];
+ int m_alphaMode;
+ BOOL m_bStateColor;
+ BOOL m_bForceStateColor;
+ BOOL m_bGroundSpot;
+ BOOL m_bShadow;
+ BOOL m_bDirty;
+ BOOL m_bFog;
+ BOOL m_bFirstGroundSpot;
+ int m_secondTexNum;
+ char m_backgroundName[50];
+ D3DCOLOR m_backgroundColorUp;
+ D3DCOLOR m_backgroundColorDown;
+ D3DCOLOR m_backgroundCloudUp;
+ D3DCOLOR m_backgroundCloudDown;
+ BOOL m_bBackgroundFull;
+ BOOL m_bBackgroundQuarter;
+ BOOL m_bOverFront;
+ D3DCOLOR m_overColor;
+ int m_overMode;
+ char m_frontsizeName[50];
+ BOOL m_bDrawWorld;
+ BOOL m_bDrawFront;
+ 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_bTotoMode;
+ BOOL m_bLensMode;
+ BOOL m_bWaterMode;
+ BOOL m_bSkyMode;
+ BOOL m_bBackForce;
+ BOOL m_bPlanetMode;
+ BOOL m_bLightMode;
+ BOOL m_bEditIndentMode;
+ int m_editIndentValue;
+ float m_tracePrecision;
+
+ int m_hiliteRank[100];
+ BOOL m_bHilite;
+ FPOINT m_hiliteP1;
+ FPOINT m_hiliteP2;
+
+ int m_lastState;
+ D3DCOLOR m_lastColor;
+ char m_lastTexture[2][50];
+ D3DMATERIAL7 m_lastMaterial;
+
+ FPOINT m_mousePos;
+ D3DMouse m_mouseType;
+ BOOL m_bMouseHide;
+ BOOL m_bNiceMouse;
+
+ LPDIRECTDRAWSURFACE7 m_imageSurface;
+ DDSURFACEDESC2 m_imageDDSD;
+ WORD* m_imageCopy;
+ int m_imageDX;
+ int m_imageDY;
+};
+
+
+#endif //_D3DENGINE_H_
diff --git a/src/d3denum.cpp b/src/d3denum.cpp
new file mode 100644
index 0000000..7f24c98
--- /dev/null
+++ b/src/d3denum.cpp
@@ -0,0 +1,603 @@
+//-----------------------------------------------------------------------------
+// File: D3DEnum.cpp
+//
+// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define STRICT
+#include <windowsx.h>
+#include <stdio.h>
+#include <tchar.h>
+#include "D3DEnum.h"
+#include "D3DUtil.h" // For DEBUG_MSG
+#include "D3DRes.h" // For dialog controls
+
+
+
+
+//-----------------------------------------------------------------------------
+// Global data for the enumerator functions
+//-----------------------------------------------------------------------------
+static HRESULT (*g_fnAppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) = NULL;
+
+static D3DEnum_DeviceInfo g_pDeviceList[20];
+static DWORD g_dwNumDevicesEnumerated = 0L;
+static DWORD g_dwNumDevices = 0L;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: SortModesCallback()
+// Desc: Callback function for sorting display modes.
+//-----------------------------------------------------------------------------
+int SortModesCallback( const VOID* arg1, const VOID* arg2 )
+{
+ DDSURFACEDESC2* p1 = (DDSURFACEDESC2*)arg1;
+ DDSURFACEDESC2* p2 = (DDSURFACEDESC2*)arg2;
+
+ if( p1->dwWidth < p2->dwWidth )
+ return -1;
+ if( p1->dwWidth > p2->dwWidth )
+ return +1;
+
+ if( p1->dwHeight < p2->dwHeight )
+ return -1;
+ if( p1->dwHeight > p2->dwHeight )
+ return +1;
+
+ if( p1->ddpfPixelFormat.dwRGBBitCount < p2->ddpfPixelFormat.dwRGBBitCount )
+ return -1;
+ if( p1->ddpfPixelFormat.dwRGBBitCount > p2->ddpfPixelFormat.dwRGBBitCount )
+ return +1;
+
+ return 0;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ModeEnumCallback()
+// Desc: Callback function for enumerating display modes.
+//-----------------------------------------------------------------------------
+static HRESULT WINAPI ModeEnumCallback( DDSURFACEDESC2* pddsd,
+ VOID* pParentInfo )
+{
+ D3DEnum_DeviceInfo* pDevice = (D3DEnum_DeviceInfo*)pParentInfo;
+
+ // Reallocate storage for the modes
+ DDSURFACEDESC2* pddsdNewModes = new DDSURFACEDESC2[pDevice->dwNumModes+1];
+ memcpy( pddsdNewModes, pDevice->pddsdModes,
+ pDevice->dwNumModes * sizeof(DDSURFACEDESC2) );
+ delete pDevice->pddsdModes;
+ pDevice->pddsdModes = pddsdNewModes;
+
+ // Add the new mode
+ pDevice->pddsdModes[pDevice->dwNumModes++] = (*pddsd);
+
+ return DDENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DeviceEnumCallback()
+// Desc: Callback function for enumerating devices
+//-----------------------------------------------------------------------------
+static HRESULT WINAPI DeviceEnumCallback( TCHAR* strDesc, TCHAR* strName,
+ D3DDEVICEDESC7* pDesc,
+ VOID* pParentInfo )
+{
+ // Keep track of # of devices that were enumerated
+ g_dwNumDevicesEnumerated++;
+
+ D3DEnum_DeviceInfo* pDriverInfo = (D3DEnum_DeviceInfo*)pParentInfo;
+ D3DEnum_DeviceInfo* pDeviceInfo = &g_pDeviceList[g_dwNumDevices];
+ ZeroMemory( pDeviceInfo, sizeof(D3DEnum_DeviceInfo) );
+
+ // Select either the HAL or HEL device desc:
+ pDeviceInfo->bHardware = pDesc->dwDevCaps & D3DDEVCAPS_HWRASTERIZATION;
+ memcpy( &pDeviceInfo->ddDeviceDesc, pDesc, sizeof(D3DDEVICEDESC7) );
+
+ // Set up device info for this device
+ pDeviceInfo->bDesktopCompatible = pDriverInfo->bDesktopCompatible;
+ pDeviceInfo->ddDriverCaps = pDriverInfo->ddDriverCaps;
+ pDeviceInfo->ddHELCaps = pDriverInfo->ddHELCaps;
+ pDeviceInfo->guidDevice = pDesc->deviceGUID;
+ pDeviceInfo->pDeviceGUID = &pDeviceInfo->guidDevice;
+ pDeviceInfo->pddsdModes = new DDSURFACEDESC2[pDriverInfo->dwNumModes];
+
+ // Copy the driver GUID and description for the device
+ if( pDriverInfo->pDriverGUID )
+ {
+ pDeviceInfo->guidDriver = pDriverInfo->guidDriver;
+ pDeviceInfo->pDriverGUID = &pDeviceInfo->guidDriver;
+ lstrcpyn( pDeviceInfo->strDesc, pDriverInfo->strDesc, 39 );
+ }
+ else
+ {
+ pDeviceInfo->pDriverGUID = NULL;
+ lstrcpyn( pDeviceInfo->strDesc, strName, 39 );
+ }
+
+//? if( strstr(strName, "T&L") != 0 ) return D3DENUMRET_OK;
+
+ // Avoid duplicates: only enum HW devices for secondary DDraw drivers.
+ if( NULL != pDeviceInfo->pDriverGUID && FALSE == pDeviceInfo->bHardware )
+ return D3DENUMRET_OK;
+
+ // Give the app a chance to accept or reject this device.
+ if( g_fnAppConfirmFn )
+ if( FAILED( g_fnAppConfirmFn( &pDeviceInfo->ddDriverCaps,
+ &pDeviceInfo->ddDeviceDesc ) ) )
+ return D3DENUMRET_OK;
+
+ // Build list of supported modes for the device
+ for( DWORD i=0; i<pDriverInfo->dwNumModes; i++ )
+ {
+ DDSURFACEDESC2 ddsdMode = pDriverInfo->pddsdModes[i];
+ DWORD dwRenderDepths = pDeviceInfo->ddDeviceDesc.dwDeviceRenderBitDepth;
+ DWORD dwDepth = ddsdMode.ddpfPixelFormat.dwRGBBitCount;
+
+ // Accept modes that are compatable with the device
+ if( ( ( dwDepth == 32 ) && ( dwRenderDepths & DDBD_32 ) ) ||
+ ( ( dwDepth == 24 ) && ( dwRenderDepths & DDBD_24 ) ) ||
+ ( ( dwDepth == 16 ) && ( dwRenderDepths & DDBD_16 ) ) )
+ {
+ // Copy compatible modes to the list of device-supported modes
+ pDeviceInfo->pddsdModes[pDeviceInfo->dwNumModes++] = ddsdMode;
+
+ // Record whether the device has any stereo modes
+ if( ddsdMode.ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT )
+ pDeviceInfo->bStereoCompatible = TRUE;
+ }
+ }
+
+ // Bail if the device has no supported modes
+ if( 0 == pDeviceInfo->dwNumModes )
+ return D3DENUMRET_OK;
+
+ // Find a 640x480x16 mode for the default fullscreen mode
+ for( i=0; i<pDeviceInfo->dwNumModes; i++ )
+ {
+ if( ( pDeviceInfo->pddsdModes[i].dwWidth == 640 ) &&
+ ( pDeviceInfo->pddsdModes[i].dwHeight == 480 ) &&
+ ( pDeviceInfo->pddsdModes[i].ddpfPixelFormat.dwRGBBitCount == 16 ) )
+ {
+ pDeviceInfo->ddsdFullscreenMode = pDeviceInfo->pddsdModes[i];
+ pDeviceInfo->dwCurrentMode = i;
+ }
+ }
+
+ // Select whether the device is initially windowed
+ pDeviceInfo->bWindowed = pDeviceInfo->bDesktopCompatible;
+
+ // Accept the device and return
+ g_dwNumDevices++;
+
+ return D3DENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DriverEnumCallback()
+// Desc: Callback function for enumerating drivers.
+//-----------------------------------------------------------------------------
+static BOOL WINAPI DriverEnumCallback( GUID* pGUID, TCHAR* strDesc,
+ TCHAR* strName, VOID*, HMONITOR )
+{
+ D3DEnum_DeviceInfo d3dDeviceInfo;
+ LPDIRECTDRAW7 pDD;
+ LPDIRECT3D7 pD3D;
+ HRESULT hr;
+
+ // Use the GUID to create the DirectDraw object
+ hr = DirectDrawCreateEx( pGUID, (VOID**)&pDD, IID_IDirectDraw7, NULL );
+ if( FAILED(hr) )
+ {
+ DEBUG_MSG( _T("Can't create DDraw during enumeration!") );
+ return D3DENUMRET_OK;
+ }
+
+ // Create a D3D object, to enumerate the d3d devices
+ hr = pDD->QueryInterface( IID_IDirect3D7, (VOID**)&pD3D );
+ if( FAILED(hr) )
+ {
+ pDD->Release();
+ DEBUG_MSG( _T("Can't query IDirect3D7 during enumeration!") );
+ return D3DENUMRET_OK;
+ }
+
+ // Copy data to a device info structure
+ ZeroMemory( &d3dDeviceInfo, sizeof(d3dDeviceInfo) );
+ lstrcpyn( d3dDeviceInfo.strDesc, strDesc, 39 );
+ d3dDeviceInfo.ddDriverCaps.dwSize = sizeof(DDCAPS);
+ d3dDeviceInfo.ddHELCaps.dwSize = sizeof(DDCAPS);
+ pDD->GetCaps( &d3dDeviceInfo.ddDriverCaps, &d3dDeviceInfo.ddHELCaps );
+ if( pGUID )
+ {
+ d3dDeviceInfo.guidDriver = (*pGUID);
+ d3dDeviceInfo.pDriverGUID = &d3dDeviceInfo.guidDriver;
+ }
+
+ // Record whether the device can render into a desktop window
+ if( d3dDeviceInfo.ddDriverCaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED )
+ if( NULL == d3dDeviceInfo.pDriverGUID )
+ d3dDeviceInfo.bDesktopCompatible = TRUE;
+
+ // Enumerate the fullscreen display modes.
+ pDD->EnumDisplayModes( 0, NULL, &d3dDeviceInfo, ModeEnumCallback );
+
+ // Sort list of display modes
+ qsort( d3dDeviceInfo.pddsdModes, d3dDeviceInfo.dwNumModes,
+ sizeof(DDSURFACEDESC2), SortModesCallback );
+
+ // Now, enumerate all the 3D devices
+ pD3D->EnumDevices( DeviceEnumCallback, &d3dDeviceInfo );
+
+ // Clean up and return
+ SAFE_DELETE( d3dDeviceInfo.pddsdModes );
+ pD3D->Release();
+ pDD->Release();
+
+ return DDENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_EnumerateDevices()
+// Desc: Enumerates all drivers, devices, and modes. The callback function is
+// called each device, to confirm that the device supports the feature
+// set required by the app.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_EnumerateDevices( HRESULT (*AppConfirmFn)(DDCAPS*, D3DDEVICEDESC7*) )
+{
+ // Store the device enumeration callback function
+ g_fnAppConfirmFn = AppConfirmFn;
+
+ // Enumerate drivers, devices, and modes
+ DirectDrawEnumerateEx( DriverEnumCallback, NULL,
+ DDENUM_ATTACHEDSECONDARYDEVICES |
+ DDENUM_DETACHEDSECONDARYDEVICES |
+ DDENUM_NONDISPLAYDEVICES );
+
+ // Make sure devices were actually enumerated
+ if( 0 == g_dwNumDevicesEnumerated )
+ {
+ DEBUG_MSG( _T("No devices and/or modes were enumerated!") );
+ return D3DENUMERR_ENUMERATIONFAILED;
+ }
+ if( 0 == g_dwNumDevices )
+ {
+ DEBUG_MSG( _T("No enumerated devices were accepted!") );
+ DEBUG_MSG( _T("Try enabling the D3D Reference Rasterizer.") );
+ return D3DENUMERR_SUGGESTREFRAST;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_FreeResources()
+// Desc: Cleans up any memory allocated during device enumeration
+//-----------------------------------------------------------------------------
+VOID D3DEnum_FreeResources()
+{
+ for( DWORD i=0; i<g_dwNumDevices; i++ )
+ {
+ SAFE_DELETE( g_pDeviceList[i].pddsdModes );
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_GetDevices()
+// Desc: Returns a ptr to the array of D3DEnum_DeviceInfo structures.
+//-----------------------------------------------------------------------------
+VOID D3DEnum_GetDevices( D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount )
+{
+ if( ppDevices )
+ (*ppDevices) = g_pDeviceList;
+ if( pdwCount )
+ (*pdwCount) = g_dwNumDevices;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: UpdateDialogControls()
+// Desc: Builds the list of devices and modes for the combo boxes in the device
+// select dialog box.
+//-----------------------------------------------------------------------------
+static VOID UpdateDialogControls( HWND hDlg, D3DEnum_DeviceInfo* pCurrentDevice,
+ DWORD dwCurrentMode, BOOL bWindowed,
+ BOOL bStereo )
+{
+ // Get access to the enumerated device list
+ D3DEnum_DeviceInfo* pDeviceList;
+ DWORD dwNumDevices;
+ D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
+
+ // Access to UI controls
+ HWND hwndDevice = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
+ HWND hwndMode = GetDlgItem( hDlg, IDC_MODE_COMBO );
+ HWND hwndWindowed = GetDlgItem( hDlg, IDC_WINDOWED_CHECKBOX );
+ HWND hwndStereo = GetDlgItem( hDlg, IDC_STEREO_CHECKBOX );
+ HWND hwndFullscreenText = GetDlgItem( hDlg, IDC_FULLSCREEN_TEXT );
+
+ // Reset the content in each of the combo boxes
+ ComboBox_ResetContent( hwndDevice );
+ ComboBox_ResetContent( hwndMode );
+
+ // Don't let non-GDI devices be windowed
+ if( FALSE == pCurrentDevice->bDesktopCompatible )
+ bWindowed = FALSE;
+
+ // Add a list of devices to the device combo box
+ for( DWORD device = 0; device < dwNumDevices; device++ )
+ {
+ D3DEnum_DeviceInfo* pDevice = &pDeviceList[device];
+
+ // Add device name to the combo box
+ DWORD dwItem = ComboBox_AddString( hwndDevice, pDevice->strDesc );
+
+ // Set the remaining UI states for the current device
+ if( pDevice == pCurrentDevice )
+ {
+ // Set the combobox selection on the current device
+ ComboBox_SetCurSel( hwndDevice, dwItem );
+
+ // Enable/set the fullscreen checkbox, as appropriate
+ if( hwndWindowed )
+ {
+ EnableWindow( hwndWindowed, pDevice->bDesktopCompatible );
+ Button_SetCheck( hwndWindowed, bWindowed );
+ }
+
+ // Enable/set the stereo checkbox, as appropriate
+ if( hwndStereo )
+ {
+ EnableWindow( hwndStereo, pDevice->bStereoCompatible && !bWindowed );
+ Button_SetCheck( hwndStereo, bStereo );
+ }
+
+ // Enable/set the fullscreen modes combo, as appropriate
+ EnableWindow( hwndMode, !bWindowed );
+ EnableWindow( hwndFullscreenText, !bWindowed );
+
+ // Build the list of fullscreen modes
+ for( DWORD mode = 0; mode < pDevice->dwNumModes; mode++ )
+ {
+ DDSURFACEDESC2* pddsdMode = &pDevice->pddsdModes[mode];
+
+ // Skip non-stereo modes, if the device is in stereo mode
+ if( 0 == (pddsdMode->ddsCaps.dwCaps2&DDSCAPS2_STEREOSURFACELEFT) )
+ if( bStereo )
+ continue;
+
+ TCHAR strMode[80];
+ wsprintf( strMode, _T("%ld x %ld x %ld"),
+ pddsdMode->dwWidth, pddsdMode->dwHeight,
+ pddsdMode->ddpfPixelFormat.dwRGBBitCount );
+
+ // Add mode desc to the combo box
+ DWORD dwItem = ComboBox_AddString( hwndMode, strMode );
+
+ // Set the item data to identify this mode
+ ComboBox_SetItemData( hwndMode, dwItem, mode );
+
+ // Set the combobox selection on the current mode
+ if( mode == dwCurrentMode )
+ ComboBox_SetCurSel( hwndMode, dwItem );
+
+ // Since not all modes support stereo, select a default mode in
+ // case none was chosen yet.
+ if( bStereo && ( CB_ERR == ComboBox_GetCurSel( hwndMode ) ) )
+ ComboBox_SetCurSel( hwndMode, dwItem );
+ }
+ }
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ChangeDeviceProc()
+// Desc: Windows message handling function for the device select dialog
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK ChangeDeviceProc( HWND hDlg, UINT uiMsg, WPARAM wParam,
+ LPARAM lParam )
+{
+ static D3DEnum_DeviceInfo** ppDeviceArg;
+ static D3DEnum_DeviceInfo* pCurrentDevice;
+ static DWORD dwCurrentMode;
+ static BOOL bCurrentWindowed;
+ static BOOL bCurrentStereo;
+
+ // Get access to the enumerated device list
+ D3DEnum_DeviceInfo* pDeviceList;
+ DWORD dwNumDevices;
+ D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
+
+ // Handle the initialization message
+ if( WM_INITDIALOG == uiMsg )
+ {
+ // Get the app's current device, passed in as an lParam argument
+ ppDeviceArg = (D3DEnum_DeviceInfo**)lParam;
+ if( NULL == ppDeviceArg )
+ return FALSE;
+
+ // Setup temp storage pointers for dialog
+ pCurrentDevice = (*ppDeviceArg);
+ dwCurrentMode = pCurrentDevice->dwCurrentMode;
+ bCurrentWindowed = pCurrentDevice->bWindowed;
+ bCurrentStereo = pCurrentDevice->bStereo;
+
+ UpdateDialogControls( hDlg, pCurrentDevice, dwCurrentMode,
+ bCurrentWindowed, bCurrentStereo );
+
+ return TRUE;
+ }
+ else if( WM_COMMAND == uiMsg )
+ {
+ HWND hwndDevice = GetDlgItem( hDlg, IDC_DEVICE_COMBO );
+ HWND hwndMode = GetDlgItem( hDlg, IDC_MODE_COMBO );
+ HWND hwndWindowed = GetDlgItem( hDlg, IDC_WINDOWED_CHECKBOX );
+ HWND hwndStereo = GetDlgItem( hDlg, IDC_STEREO_CHECKBOX );
+
+ // Get current UI state
+ DWORD dwDevice = ComboBox_GetCurSel( hwndDevice );
+ DWORD dwModeItem = ComboBox_GetCurSel( hwndMode );
+ DWORD dwMode = ComboBox_GetItemData( hwndMode, dwModeItem );
+ BOOL bWindowed = hwndWindowed ? Button_GetCheck( hwndWindowed ) : 0;
+ BOOL bStereo = hwndStereo ? Button_GetCheck( hwndStereo ) : 0;
+
+ D3DEnum_DeviceInfo* pDevice = &pDeviceList[dwDevice];
+
+ if( IDOK == LOWORD(wParam) )
+ {
+ // Handle the case when the user hits the OK button. Check if any
+ // of the options were changed
+ if( pDevice != pCurrentDevice || dwMode != dwCurrentMode ||
+ bWindowed != bCurrentWindowed || bStereo != bCurrentStereo )
+ {
+ // Return the newly selected device and its new properties
+ (*ppDeviceArg) = pDevice;
+ pDevice->bWindowed = bWindowed;
+ pDevice->bStereo = bStereo;
+ pDevice->dwCurrentMode = dwMode;
+ pDevice->ddsdFullscreenMode = pDevice->pddsdModes[dwMode];
+
+ EndDialog( hDlg, IDOK );
+ }
+ else
+ EndDialog( hDlg, IDCANCEL );
+
+ return TRUE;
+ }
+ else if( IDCANCEL == LOWORD(wParam) )
+ {
+ // Handle the case when the user hits the Cancel button
+ EndDialog( hDlg, IDCANCEL );
+ return TRUE;
+ }
+ else if( CBN_SELENDOK == HIWORD(wParam) )
+ {
+ if( LOWORD(wParam) == IDC_DEVICE_COMBO )
+ {
+ // Handle the case when the user chooses the device combo
+ dwMode = pDeviceList[dwDevice].dwCurrentMode;
+ bWindowed = pDeviceList[dwDevice].bWindowed;
+ bStereo = pDeviceList[dwDevice].bStereo;
+ }
+ }
+
+ // Keep the UI current
+ UpdateDialogControls( hDlg, &pDeviceList[dwDevice], dwMode, bWindowed, bStereo );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_UserChangeDevice()
+// Desc: Pops up a dialog which allows the user to select a new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice )
+{
+ if( IDOK == DialogBoxParam( (HINSTANCE)GetModuleHandle(NULL),
+ MAKEINTRESOURCE(IDD_CHANGEDEVICE),
+ GetForegroundWindow(),
+ ChangeDeviceProc, (LPARAM)ppDevice ) )
+ return S_OK;
+
+ return E_FAIL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_SelectDefaultDevice()
+// Desc: Pick a default device, preferably hardware and desktop compatible.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** ppDevice,
+ DWORD dwFlags )
+{
+ // Check arguments
+ if( NULL == ppDevice )
+ return E_INVALIDARG;
+
+ // Get access to the enumerated device list
+ D3DEnum_DeviceInfo* pDeviceList;
+ DWORD dwNumDevices;
+ D3DEnum_GetDevices( &pDeviceList, &dwNumDevices );
+
+ // Look for windowable software, hardware, and hardware TnL devices
+ D3DEnum_DeviceInfo* pRefRastDevice = NULL;
+ D3DEnum_DeviceInfo* pSoftwareDevice = NULL;
+ D3DEnum_DeviceInfo* pHardwareDevice = NULL;
+ D3DEnum_DeviceInfo* pHardwareTnLDevice = NULL;
+
+ for( DWORD i=0; i<dwNumDevices; i++ )
+ {
+ if( pDeviceList[i].bDesktopCompatible )
+ {
+ if( pDeviceList[i].bHardware )
+ {
+ if( (*pDeviceList[i].pDeviceGUID) == IID_IDirect3DTnLHalDevice )
+ pHardwareTnLDevice = &pDeviceList[i];
+ else
+ pHardwareDevice = &pDeviceList[i];
+ }
+ else
+ {
+ if( (*pDeviceList[i].pDeviceGUID) == IID_IDirect3DRefDevice )
+ pRefRastDevice = &pDeviceList[i];
+ else
+ pSoftwareDevice = &pDeviceList[i];
+ }
+ }
+ }
+
+ // Prefer a hardware non-TnL device first, then a TnL hardware device, and
+ // finally, a software device.
+ if( 0 == ( dwFlags & D3DENUM_SOFTWAREONLY ) && pHardwareDevice )
+ (*ppDevice) = pHardwareDevice;
+ else if( 0 == ( dwFlags & D3DENUM_SOFTWAREONLY ) && pHardwareTnLDevice )
+ (*ppDevice) = pHardwareTnLDevice;
+ else if( pSoftwareDevice )
+ (*ppDevice) = pSoftwareDevice;
+ else if( pRefRastDevice )
+ (*ppDevice) = pRefRastDevice;
+ else
+ return D3DENUMERR_NOCOMPATIBLEDEVICES;
+
+ // Set the windowed state of the newly selected device
+ (*ppDevice)->bWindowed = TRUE;
+
+ return S_OK;
+}
+
+
+
+
+
diff --git a/src/d3denum.h b/src/d3denum.h
new file mode 100644
index 0000000..9b75611
--- /dev/null
+++ b/src/d3denum.h
@@ -0,0 +1,120 @@
+//-----------------------------------------------------------------------------
+// File: D3DEnum.h
+//
+// Desc: Functions to enumerate DDraw/D3D drivers, devices, and modes.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DENUM_H
+#define D3DENUM_H
+#include <d3d.h>
+
+
+//-----------------------------------------------------------------------------
+// Flag and error definitions
+//-----------------------------------------------------------------------------
+#define D3DENUM_SOFTWAREONLY 0x00000001 // Software-devices only flag
+
+#define D3DENUMERR_NODIRECTDRAW 0x81000001 // Could not create DDraw
+#define D3DENUMERR_ENUMERATIONFAILED 0x81000002 // Enumeration failed
+#define D3DENUMERR_SUGGESTREFRAST 0x81000003 // Suggest using the RefRast
+#define D3DENUMERR_NOCOMPATIBLEDEVICES 0x81000004 // No devices were found that
+ // meet the app's desired
+ // capabilities
+#define D3DENUMERR_ENGINE 0x81000005 // 3D engine error
+#define D3DENUMERR_ROBOT 0x81000006 // robot error
+#define D3DENUMERR_SOUND 0x81000007 // sound error
+
+
+//-----------------------------------------------------------------------------
+// Name: struct D3DEnum_DeviceInfo
+// Desc: Structure to hold info about the enumerated Direct3D devices.
+//-----------------------------------------------------------------------------
+struct D3DEnum_DeviceInfo
+{
+ // D3D Device info
+ TCHAR strDesc[40];
+ GUID* pDeviceGUID;
+ D3DDEVICEDESC7 ddDeviceDesc;
+ BOOL bHardware;
+
+ // DDraw Driver info
+ GUID* pDriverGUID;
+ DDCAPS ddDriverCaps;
+ DDCAPS ddHELCaps;
+
+ // DDraw Mode Info
+ DDSURFACEDESC2 ddsdFullscreenMode;
+ BOOL bWindowed;
+ BOOL bStereo;
+
+ // For internal use (apps should not need to use these)
+ GUID guidDevice;
+ GUID guidDriver;
+ DDSURFACEDESC2* pddsdModes;
+ DWORD dwNumModes;
+ DWORD dwCurrentMode;
+ BOOL bDesktopCompatible;
+ BOOL bStereoCompatible;
+};
+
+
+// For code not yet switched to new struct name
+typedef D3DEnum_DeviceInfo D3DDEVICEINFO;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_EnumerateDevices()
+// Desc: Enumerates all drivers, devices, and modes. The callback function is
+// called each device, to confirm that the device supports the feature
+// set required by the app.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_EnumerateDevices( HRESULT (*fn)(DDCAPS*, D3DDEVICEDESC7*) );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_FreeResources()
+// Desc: Cleans up any memory allocated during device enumeration
+//-----------------------------------------------------------------------------
+VOID D3DEnum_FreeResources();
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_GetDevices()
+// Desc: Returns a ptr to the array of enumerated D3DDEVICEINFO structures.
+//-----------------------------------------------------------------------------
+VOID D3DEnum_GetDevices( D3DEnum_DeviceInfo** ppDevices, DWORD* pdwCount );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_SelectDefaultDevice()
+// Desc: Picks a driver based on a set of passed in criteria. The
+// D3DENUM_SOFTWAREONLY flag can be used to pick a software device.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_SelectDefaultDevice( D3DEnum_DeviceInfo** pDevice,
+ DWORD dwFlags = 0L );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DEnum_UserChangeDevice()
+// Desc: Pops up a dialog which allows the user to select a new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DEnum_UserChangeDevice( D3DEnum_DeviceInfo** ppDevice );
+
+
+
+
+#endif // D3DENUM_H
+
+
+
diff --git a/src/d3dframe.cpp b/src/d3dframe.cpp
new file mode 100644
index 0000000..a1189d1
--- /dev/null
+++ b/src/d3dframe.cpp
@@ -0,0 +1,607 @@
+//-----------------------------------------------------------------------------
+// File: D3DFrame.cpp
+//
+// Desc: Class functions to implement a Direct3D app framework.
+//
+// Copyright (c) 1995-1999 by Microsoft, all rights reserved
+//-----------------------------------------------------------------------------
+#define STRICT
+#include <windows.h>
+#include <stdio.h>
+#include <tchar.h>
+#include "D3DFrame.h"
+#include "D3DUtil.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DFramework7()
+// Desc: The constructor. Clears static variables
+//-----------------------------------------------------------------------------
+CD3DFramework7::CD3DFramework7()
+{
+ m_hWnd = NULL;
+ m_bIsFullscreen = FALSE;
+ m_bIsStereo = FALSE;
+ m_dwRenderWidth = 0L;
+ m_dwRenderHeight = 0L;
+
+ m_pddsFrontBuffer = NULL;
+ m_pddsBackBuffer = NULL;
+ m_pddsBackBufferLeft = NULL;
+
+ m_pddsZBuffer = NULL;
+ m_pd3dDevice = NULL;
+ m_pDD = NULL;
+ m_pD3D = NULL;
+ m_dwDeviceMemType = NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~CD3DFramework7()
+// Desc: The destructor. Deletes all objects
+//-----------------------------------------------------------------------------
+CD3DFramework7::~CD3DFramework7()
+{
+ DestroyObjects();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: DestroyObjects()
+// Desc: Cleans everything up upon deletion. This code returns an error
+// if any of the objects have remaining reference counts.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::DestroyObjects()
+{
+ LONG nDD = 0L; // Number of outstanding DDraw references
+ LONG nD3D = 0L; // Number of outstanding D3DDevice references
+
+ if( m_pDD )
+ {
+ HRESULT err = m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
+ char s[100];
+ sprintf(s, "SetCooperativeLevel error=%d\n", err);
+ OutputDebugString(s);
+ }
+
+ // Do a safe check for releasing the D3DDEVICE. RefCount must be zero.
+ if( m_pd3dDevice )
+ if( 0 < ( nD3D = m_pd3dDevice->Release() ) )
+ DEBUG_MSG( _T("Error: D3DDevice object is still referenced!") );
+ m_pd3dDevice = NULL;
+
+ SAFE_RELEASE( m_pddsBackBuffer );
+ SAFE_RELEASE( m_pddsBackBufferLeft );
+ SAFE_RELEASE( m_pddsZBuffer );
+ SAFE_RELEASE( m_pddsFrontBuffer );
+ SAFE_RELEASE( m_pD3D );
+
+ if( m_pDD )
+ {
+ // Do a safe check for releasing DDRAW. RefCount must be zero.
+ if( 0 < ( nDD = m_pDD->Release() ) )
+ DEBUG_MSG( _T("Error: DDraw object is still referenced!") );
+ }
+ m_pDD = NULL;
+
+ // Return successful, unless there are outstanding DD or D3DDevice refs.
+ return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Initialize()
+// Desc: Creates the internal objects for the framework
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::Initialize( HWND hWnd, GUID* pDriverGUID,
+ GUID* pDeviceGUID, DDSURFACEDESC2* pMode,
+ DWORD dwFlags )
+{
+ HRESULT hr;
+
+ // Check params. Note: A NULL mode is valid for windowed modes only.
+ if( ( NULL==hWnd ) || ( NULL==pDeviceGUID ) ||
+ ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) )
+ return E_INVALIDARG;
+
+ // Setup state for windowed/fullscreen mode
+ m_hWnd = hWnd;
+ m_bIsStereo = FALSE;
+ m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? TRUE : FALSE;
+
+ // Support stereoscopic viewing for fullscreen modes which support it
+ if( ( dwFlags & D3DFW_STEREO ) && ( dwFlags & D3DFW_FULLSCREEN ) )
+ if( pMode->ddsCaps.dwCaps2 & DDSCAPS2_STEREOSURFACELEFT )
+ m_bIsStereo = TRUE;
+
+ // Create the D3D rendering environment (surfaces, device, viewport, etc.)
+ if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode,
+ dwFlags ) ) )
+ {
+ DestroyObjects();
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateEnvironment()
+// Desc: Creates the internal objects for the framework
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID,
+ DDSURFACEDESC2* pMode, DWORD dwFlags )
+{
+ HRESULT hr;
+
+ // Select the default memory type, for whether the device is HW or SW
+ if( IsEqualIID( *pDeviceGUID, IID_IDirect3DHALDevice) )
+ m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
+ else if( IsEqualIID( *pDeviceGUID, IID_IDirect3DTnLHalDevice) )
+ m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
+ else
+ m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY;
+
+ // Create the DDraw object
+ hr = CreateDirectDraw( pDriverGUID, dwFlags );
+ if( FAILED( hr ) )
+ return hr;
+
+ // Create the front and back buffers, and attach a clipper
+ if( dwFlags & D3DFW_FULLSCREEN )
+ hr = CreateFullscreenBuffers( pMode );
+ else
+ hr = CreateWindowedBuffers();
+ if( FAILED( hr ) )
+ return hr;
+
+ // Create the Direct3D object and the Direct3DDevice object
+ hr = CreateDirect3D( pDeviceGUID );
+ if( FAILED( hr ) )
+ return hr;
+
+ // Create and attach the zbuffer
+ if( dwFlags & D3DFW_ZBUFFER )
+ hr = CreateZBuffer( pDeviceGUID );
+ if( FAILED( hr ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: EnumZBufferFormatsCallback()
+// Desc: Simply returns the first matching enumerated z-buffer format
+//-----------------------------------------------------------------------------
+static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf,
+ VOID* pContext )
+{
+ DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pContext;
+
+ if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount )
+ {
+ (*pddpfOut) = (*pddpf);
+ return D3DENUMRET_CANCEL;
+ }
+
+ return D3DENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateDirectDraw()
+// Desc: Create the DirectDraw interface
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags )
+{
+ // Create the DirectDraw interface, and query for the DD7 interface
+ if( FAILED( DirectDrawCreateEx( pDriverGUID, (VOID**)&m_pDD,
+ IID_IDirectDraw7, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Could not create DirectDraw") );
+ return D3DFWERR_NODIRECTDRAW;
+ }
+
+ // Set the Windows cooperative level
+ DWORD dwCoopFlags = DDSCL_NORMAL;
+ if( m_bIsFullscreen )
+ dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN;
+
+ // By defualt, set the flag to allow D3D to optimize floating point calcs
+ if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) )
+ dwCoopFlags |= DDSCL_FPUSETUP;
+
+ if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) )
+ {
+ DEBUG_MSG( _T("Couldn't set coop level") );
+ return D3DFWERR_COULDNTSETCOOPLEVEL;
+ }
+
+ // Check that we are NOT in a palettized display. That case will fail,
+ // since the framework doesn't use palettes.
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pDD->GetDisplayMode( &ddsd );
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 )
+ return D3DFWERR_INVALIDMODE;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateFullscreenBuffers()
+// Desc: Creates the primary and (optional) backbuffer for rendering.
+// Windowed mode and fullscreen mode are handled differently.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateFullscreenBuffers( DDSURFACEDESC2* pddsd )
+{
+ HRESULT hr;
+
+ // Get the dimensions of the screen bounds
+ // Store the rectangle which contains the renderer
+ SetRect( &m_rcScreenRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight );
+ m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left;
+ m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;
+
+ // Set the display mode to the requested dimensions. Check for
+ // 320x200x8 modes, and set flag to avoid using ModeX
+ DWORD dwModeFlags = 0;
+
+ if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) &&
+ (8==pddsd->ddpfPixelFormat.dwRGBBitCount) )
+ dwModeFlags |= DDSDM_STANDARDVGAMODE;
+
+ if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight,
+ pddsd->ddpfPixelFormat.dwRGBBitCount,
+ pddsd->dwRefreshRate, dwModeFlags ) ) )
+ {
+ DEBUG_MSG( _T("Can't set display mode") );
+ return D3DFWERR_BADDISPLAYMODE;
+ }
+
+ // Setup to create the primary surface w/backbuffer
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE |
+ DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+ ddsd.dwBackBufferCount = 1;
+
+ // Support for stereoscopic viewing
+ if( m_bIsStereo )
+ {
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+ ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
+ }
+
+ // Create the primary surface
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Can't create primary surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOPRIMARY;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ // Get the backbuffer, which was created along with the primary.
+ DDSCAPS2 ddscaps = { DDSCAPS_BACKBUFFER, 0, 0, 0 };
+ if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBuffer ) ) )
+ {
+ DEBUG_ERR( hr, _T("Error: Can't get the backbuffer") );
+ return D3DFWERR_NOBACKBUFFER;
+ }
+
+ // Increment the backbuffer count (for consistency with windowed mode)
+ m_pddsBackBuffer->AddRef();
+
+ // Support for stereoscopic viewing
+ if( m_bIsStereo )
+ {
+ // Get the left backbuffer, which was created along with the primary.
+ DDSCAPS2 ddscaps = { 0, DDSCAPS2_STEREOSURFACELEFT, 0, 0 };
+ if( FAILED( hr = m_pddsBackBuffer->GetAttachedSurface( &ddscaps,
+ &m_pddsBackBufferLeft ) ) )
+ {
+ DEBUG_ERR( hr, _T("Error: Can't get the left backbuffer") );
+ return D3DFWERR_NOBACKBUFFER;
+ }
+ m_pddsBackBufferLeft->AddRef();
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateWindowedBuffers()
+// Desc: Creates the primary and (optional) backbuffer for rendering.
+// Windowed mode and fullscreen mode are handled differently.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateWindowedBuffers()
+{
+ HRESULT hr;
+
+ // Get the dimensions of the viewport and screen bounds
+ GetClientRect( m_hWnd, &m_rcScreenRect );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left );
+ ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right );
+ m_dwRenderWidth = m_rcScreenRect.right - m_rcScreenRect.left;
+ m_dwRenderHeight = m_rcScreenRect.bottom - m_rcScreenRect.top;
+
+ // Create the primary surface
+ DDSURFACEDESC2 ddsd;
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = DDSD_CAPS;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Can't create primary surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOPRIMARY;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ // If in windowed-mode, create a clipper object
+ LPDIRECTDRAWCLIPPER pcClipper;
+ if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't create clipper") );
+ return D3DFWERR_NOCLIPPER;
+ }
+
+ // Associate the clipper with the window
+ pcClipper->SetHWnd( 0, m_hWnd );
+ m_pddsFrontBuffer->SetClipper( pcClipper );
+ SAFE_RELEASE( pcClipper );
+
+ // Create a backbuffer
+ ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
+ ddsd.dwWidth = m_dwRenderWidth;
+ ddsd.dwHeight = m_dwRenderHeight;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
+ {
+ DEBUG_ERR( hr, _T("Error: Couldn't create the backbuffer") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOBACKBUFFER;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateDirect3D()
+// Desc: Create the Direct3D interface
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateDirect3D( GUID* pDeviceGUID )
+{
+ // Query DirectDraw for access to Direct3D
+ if( FAILED( m_pDD->QueryInterface( IID_IDirect3D7, (VOID**)&m_pD3D ) ) )
+ {
+ DEBUG_MSG( _T("Couldn't get the Direct3D interface") );
+ return D3DFWERR_NODIRECT3D;
+ }
+
+ // Create the device
+ if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsBackBuffer,
+ &m_pd3dDevice) ) )
+ {
+ DEBUG_MSG( _T("Couldn't create the D3DDevice") );
+ return D3DFWERR_NO3DDEVICE;
+ }
+
+ // Finally, set the viewport for the newly created device
+ D3DVIEWPORT7 vp = { 0, 0, m_dwRenderWidth, m_dwRenderHeight, 0.0f, 1.0f };
+
+ if( FAILED( m_pd3dDevice->SetViewport( &vp ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't set current viewport to device") );
+ return D3DFWERR_NOVIEWPORT;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CreateZBuffer()
+// Desc: Internal function called by Create() to make and attach a zbuffer
+// to the renderer
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::CreateZBuffer( GUID* pDeviceGUID )
+{
+ HRESULT hr;
+
+ // Check if the device supports z-bufferless hidden surface removal. If so,
+ // we don't really need a z-buffer
+ D3DDEVICEDESC7 ddDesc;
+ m_pd3dDevice->GetCaps( &ddDesc );
+ if( ddDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )
+ return S_OK;
+
+ // Get z-buffer dimensions from the render target
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsBackBuffer->GetSurfaceDesc( &ddsd );
+
+ // Setup the surface desc for the z-buffer.
+ ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType;
+ ddsd.ddpfPixelFormat.dwSize = 0; // Tag the pixel format as unitialized
+
+ // Get an appropiate pixel format from enumeration of the formats. On the
+ // first pass, we look for a zbuffer dpeth which is equal to the frame
+ // buffer depth (as some cards unfornately require this).
+ m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
+ (VOID*)&ddsd.ddpfPixelFormat );
+ if( 0 == ddsd.ddpfPixelFormat.dwSize )
+ {
+ // Try again, just accepting any 16-bit zbuffer
+ ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
+ m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
+ (VOID*)&ddsd.ddpfPixelFormat );
+
+ if( 0 == ddsd.ddpfPixelFormat.dwSize )
+ {
+ DEBUG_MSG( _T("Device doesn't support requested zbuffer format") );
+ return D3DFWERR_NOZBUFFER;
+ }
+ }
+
+ // Create and attach a z-buffer
+ if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't create a ZBuffer surface") );
+ if( hr != DDERR_OUTOFVIDEOMEMORY )
+ return D3DFWERR_NOZBUFFER;
+ DEBUG_MSG( _T("Error: Out of video memory") );
+ return DDERR_OUTOFVIDEOMEMORY;
+ }
+
+ if( FAILED( m_pddsBackBuffer->AddAttachedSurface( m_pddsZBuffer ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't attach zbuffer to render surface") );
+ return D3DFWERR_NOZBUFFER;
+ }
+
+ // For stereoscopic viewing, attach zbuffer to left surface as well
+ if( m_bIsStereo )
+ {
+ if( FAILED( m_pddsBackBufferLeft->AddAttachedSurface( m_pddsZBuffer ) ) )
+ {
+ DEBUG_MSG( _T("Error: Couldn't attach zbuffer to left render surface") );
+ return D3DFWERR_NOZBUFFER;
+ }
+ }
+
+ // Finally, this call rebuilds internal structures
+ if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsBackBuffer, 0L ) ) )
+ {
+ DEBUG_MSG( _T("Error: SetRenderTarget() failed after attaching zbuffer!") );
+ return D3DFWERR_NOZBUFFER;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: RestoreSurfaces()
+// Desc: Checks for lost surfaces and restores them if lost. Note: Don't
+// restore render surface, since it's just a duplicate ptr.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::RestoreSurfaces()
+{
+ // Restore all surfaces (including video memory vertex buffers)
+ m_pDD->RestoreAllSurfaces();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Move()
+// Desc: Moves the screen rect for windowed renderers
+//-----------------------------------------------------------------------------
+VOID CD3DFramework7::Move( INT x, INT y )
+{
+ if( TRUE == m_bIsFullscreen )
+ return;
+
+ SetRect( &m_rcScreenRect, x, y, x + m_dwRenderWidth, y + m_dwRenderHeight );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: FlipToGDISurface()
+// Desc: Puts the GDI surface in front of the primary, so that dialog
+// boxes and other windows drawing funcs may happen.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::FlipToGDISurface( BOOL bDrawFrame )
+{
+ if( m_pDD && m_bIsFullscreen )
+ {
+ m_pDD->FlipToGDISurface();
+
+ if( bDrawFrame )
+ {
+ DrawMenuBar( m_hWnd );
+ RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME );
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ShowFrame()
+// Desc: Show the frame on the primary surface, via a blt or a flip.
+//-----------------------------------------------------------------------------
+HRESULT CD3DFramework7::ShowFrame()
+{
+ if( NULL == m_pddsFrontBuffer )
+ return D3DFWERR_NOTINITIALIZED;
+
+ if( m_bIsFullscreen )
+ {
+ // We are in fullscreen mode, so perform a flip.
+ if( m_bIsStereo )
+ return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT | DDFLIP_STEREO );
+ else
+ return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT );
+ }
+ else
+ {
+ // We are in windowed mode, so perform a blit.
+ return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer,
+ NULL, DDBLT_WAIT, NULL );
+ }
+}
+
+
+
diff --git a/src/d3dframe.h b/src/d3dframe.h
new file mode 100644
index 0000000..2ac913e
--- /dev/null
+++ b/src/d3dframe.h
@@ -0,0 +1,126 @@
+//-----------------------------------------------------------------------------
+// File: D3DFrame.h
+//
+// Desc: Class to manage the Direct3D environment objects such as buffers,
+// viewports, and 3D devices.
+//
+// The class is initialized with the Initialize() function, after which
+// the Get????() functions can be used to access the objects needed for
+// rendering. If the device or display needs to be changed, the
+// ChangeDevice() function can be called. If the display window is moved
+// the changes need to be reported with the Move() function.
+//
+// After rendering a frame, the ShowFrame() function filps or blits the
+// backbuffer contents to the primary. If surfaces are lost, they can be
+// restored with the RestoreSurfaces() function. Finally, if normal
+// Windows output is needed, the FlipToGDISurface() provides a GDI
+// surface to draw on.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DFRAME_H
+#define D3DFRAME_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DFramework7
+// Desc: The Direct3D sample framework class for DX7. Maintains the D3D
+// surfaces and device used for 3D rendering.
+//-----------------------------------------------------------------------------
+class CD3DFramework7
+{
+ // Internal variables for the framework class
+ HWND m_hWnd; // The window object
+ BOOL m_bIsFullscreen; // Fullscreen vs. windowed
+ BOOL m_bIsStereo; // Stereo view mode
+ DWORD m_dwRenderWidth; // Dimensions of the render target
+ DWORD m_dwRenderHeight;
+ RECT m_rcScreenRect; // Screen rect for window
+ LPDIRECTDRAW7 m_pDD; // The DirectDraw object
+ LPDIRECT3D7 m_pD3D; // The Direct3D object
+ LPDIRECT3DDEVICE7 m_pd3dDevice; // The D3D device
+ LPDIRECTDRAWSURFACE7 m_pddsFrontBuffer; // The primary surface
+ LPDIRECTDRAWSURFACE7 m_pddsBackBuffer; // The backbuffer surface
+ LPDIRECTDRAWSURFACE7 m_pddsBackBufferLeft; // For stereo modes
+ LPDIRECTDRAWSURFACE7 m_pddsZBuffer; // The zbuffer surface
+ DWORD m_dwDeviceMemType;
+
+ // Internal functions for the framework class
+ HRESULT CreateZBuffer( GUID* );
+ HRESULT CreateFullscreenBuffers( DDSURFACEDESC2* );
+ HRESULT CreateWindowedBuffers();
+ HRESULT CreateDirectDraw( GUID*, DWORD );
+ HRESULT CreateDirect3D( GUID* );
+ HRESULT CreateEnvironment( GUID*, GUID*, DDSURFACEDESC2*, DWORD );
+
+public:
+ // Access functions for DirectX objects
+ LPDIRECTDRAW7 GetDirectDraw() { return m_pDD; }
+ LPDIRECT3D7 GetDirect3D() { return m_pD3D; }
+ LPDIRECT3DDEVICE7 GetD3DDevice() { return m_pd3dDevice; }
+ LPDIRECTDRAWSURFACE7 GetFrontBuffer() { return m_pddsFrontBuffer; }
+ LPDIRECTDRAWSURFACE7 GetBackBuffer() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetRenderSurface() { return m_pddsBackBuffer; }
+ LPDIRECTDRAWSURFACE7 GetRenderSurfaceLeft() { return m_pddsBackBufferLeft; }
+
+ // Functions to aid rendering
+ HRESULT RestoreSurfaces();
+ HRESULT ShowFrame();
+ HRESULT FlipToGDISurface( BOOL bDrawFrame = FALSE );
+
+ // Functions for managing screen and viewport bounds
+ BOOL IsFullscreen() { return m_bIsFullscreen; }
+ BOOL IsStereo() { return m_bIsStereo; }
+ VOID Move( INT x, INT y );
+
+ // Creates the Framework
+ HRESULT Initialize( HWND hWnd, GUID* pDriverGUID, GUID* pDeviceGUID,
+ DDSURFACEDESC2* pddsd, DWORD dwFlags );
+ HRESULT DestroyObjects();
+
+ CD3DFramework7();
+ ~CD3DFramework7();
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Flags used for the Initialize() method of a CD3DFramework object
+//-----------------------------------------------------------------------------
+#define D3DFW_FULLSCREEN 0x00000001 // Use fullscreen mode
+#define D3DFW_STEREO 0x00000002 // Use stereo-scopic viewing
+#define D3DFW_ZBUFFER 0x00000004 // Create and use a zbuffer
+#define D3DFW_NO_FPUSETUP 0x00000008 // Don't use default DDSCL_FPUSETUP flag
+
+
+
+
+//-----------------------------------------------------------------------------
+// Errors that the Initialize() and ChangeDriver() calls may return
+//-----------------------------------------------------------------------------
+#define D3DFWERR_INITIALIZATIONFAILED 0x82000000
+#define D3DFWERR_NODIRECTDRAW 0x82000001
+#define D3DFWERR_COULDNTSETCOOPLEVEL 0x82000002
+#define D3DFWERR_NODIRECT3D 0x82000003
+#define D3DFWERR_NO3DDEVICE 0x82000004
+#define D3DFWERR_NOZBUFFER 0x82000005
+#define D3DFWERR_INVALIDZBUFFERDEPTH 0x82000006
+#define D3DFWERR_NOVIEWPORT 0x82000007
+#define D3DFWERR_NOPRIMARY 0x82000008
+#define D3DFWERR_NOCLIPPER 0x82000009
+#define D3DFWERR_BADDISPLAYMODE 0x8200000a
+#define D3DFWERR_NOBACKBUFFER 0x8200000b
+#define D3DFWERR_NONZEROREFCOUNT 0x8200000c
+#define D3DFWERR_NORENDERTARGET 0x8200000d
+#define D3DFWERR_INVALIDMODE 0x8200000e
+#define D3DFWERR_NOTINITIALIZED 0x8200000f
+
+
+#endif // D3DFRAME_H
+
+
diff --git a/src/d3dmath.cpp b/src/d3dmath.cpp
new file mode 100644
index 0000000..79ea56f
--- /dev/null
+++ b/src/d3dmath.cpp
@@ -0,0 +1,327 @@
+//-----------------------------------------------------------------------------
+// File: D3DMath.cpp
+//
+// Desc: Shortcut macros and functions for using DX objects
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define D3D_OVERLOADS
+#define STRICT
+#include <math.h>
+#include <stdio.h>
+#include "D3DMath.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_MatrixMultiply()
+// Desc: Does the matrix operation: [Q] = [A] * [B]. Note that the order of
+// this operation was changed from the previous version of the DXSDK.
+//-----------------------------------------------------------------------------
+VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b )
+{
+ FLOAT* pA = (FLOAT*)&a;
+ FLOAT* pB = (FLOAT*)&b;
+ FLOAT pM[16];
+
+ ZeroMemory( pM, sizeof(D3DMATRIX) );
+
+ for( WORD i=0; i<4; i++ )
+ for( WORD j=0; j<4; j++ )
+ for( WORD k=0; k<4; k++ )
+ pM[4*i+j] += pA[4*i+k] * pB[4*k+j];
+
+ memcpy( &q, pM, sizeof(D3DMATRIX) );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_MatrixInvert()
+// Desc: Does the matrix operation: [Q] = inv[A]. Note: this function only
+// works for matrices with [0 0 0 1] for the 4th column.
+//-----------------------------------------------------------------------------
+HRESULT D3DMath_MatrixInvert( D3DMATRIX& q, D3DMATRIX& a )
+{
+ if( fabs(a._44 - 1.0f) > .001f)
+ return E_INVALIDARG;
+ if( fabs(a._14) > .001f || fabs(a._24) > .001f || fabs(a._34) > .001f )
+ return E_INVALIDARG;
+
+ FLOAT fDetInv = 1.0f / ( a._11 * ( a._22 * a._33 - a._23 * a._32 ) -
+ a._12 * ( a._21 * a._33 - a._23 * a._31 ) +
+ a._13 * ( a._21 * a._32 - a._22 * a._31 ) );
+
+ q._11 = fDetInv * ( a._22 * a._33 - a._23 * a._32 );
+ q._12 = -fDetInv * ( a._12 * a._33 - a._13 * a._32 );
+ q._13 = fDetInv * ( a._12 * a._23 - a._13 * a._22 );
+ q._14 = 0.0f;
+
+ q._21 = -fDetInv * ( a._21 * a._33 - a._23 * a._31 );
+ q._22 = fDetInv * ( a._11 * a._33 - a._13 * a._31 );
+ q._23 = -fDetInv * ( a._11 * a._23 - a._13 * a._21 );
+ q._24 = 0.0f;
+
+ q._31 = fDetInv * ( a._21 * a._32 - a._22 * a._31 );
+ q._32 = -fDetInv * ( a._11 * a._32 - a._12 * a._31 );
+ q._33 = fDetInv * ( a._11 * a._22 - a._12 * a._21 );
+ q._34 = 0.0f;
+
+ q._41 = -( a._41 * q._11 + a._42 * q._21 + a._43 * q._31 );
+ q._42 = -( a._41 * q._12 + a._42 * q._22 + a._43 * q._32 );
+ q._43 = -( a._41 * q._13 + a._42 * q._23 + a._43 * q._33 );
+ q._44 = 1.0f;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_VectorMatrixMultiply()
+// Desc: Multiplies a vector by a matrix
+//-----------------------------------------------------------------------------
+HRESULT D3DMath_VectorMatrixMultiply( D3DVECTOR& vDest, D3DVECTOR& vSrc,
+ D3DMATRIX& mat)
+{
+ FLOAT x = vSrc.x*mat._11 + vSrc.y*mat._21 + vSrc.z* mat._31 + mat._41;
+ FLOAT y = vSrc.x*mat._12 + vSrc.y*mat._22 + vSrc.z* mat._32 + mat._42;
+ FLOAT z = vSrc.x*mat._13 + vSrc.y*mat._23 + vSrc.z* mat._33 + mat._43;
+ FLOAT w = vSrc.x*mat._14 + vSrc.y*mat._24 + vSrc.z* mat._34 + mat._44;
+
+ if( fabs( w ) < g_EPSILON )
+ return E_INVALIDARG;
+
+ vDest.x = x/w;
+ vDest.y = y/w;
+ vDest.z = z/w;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_VertexMatrixMultiply()
+// Desc: Multiplies a vertex by a matrix
+//-----------------------------------------------------------------------------
+HRESULT D3DMath_VertexMatrixMultiply( D3DVERTEX& vDest, D3DVERTEX& vSrc,
+ D3DMATRIX& mat )
+{
+ HRESULT hr;
+ D3DVECTOR* pSrcVec = (D3DVECTOR*)&vSrc.x;
+ D3DVECTOR* pDestVec = (D3DVECTOR*)&vDest.x;
+
+ if( SUCCEEDED( hr = D3DMath_VectorMatrixMultiply( *pDestVec, *pSrcVec,
+ mat ) ) )
+ {
+ pSrcVec = (D3DVECTOR*)&vSrc.nx;
+ pDestVec = (D3DVECTOR*)&vDest.nx;
+ hr = D3DMath_VectorMatrixMultiply( *pDestVec, *pSrcVec, mat );
+ }
+ return hr;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_QuaternionFromRotation()
+// Desc: Converts a normalized axis and angle to a unit quaternion.
+//-----------------------------------------------------------------------------
+VOID D3DMath_QuaternionFromRotation( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w,
+ D3DVECTOR& v, FLOAT fTheta )
+{
+ x = sinf( fTheta/2.0f ) * v.x;
+ y = sinf( fTheta/2.0f ) * v.y;
+ z = sinf( fTheta/2.0f ) * v.z;
+ w = cosf( fTheta/2.0f );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_RotationFromQuaternion()
+// Desc: Converts a normalized axis and angle to a unit quaternion.
+//-----------------------------------------------------------------------------
+VOID D3DMath_RotationFromQuaternion( D3DVECTOR& v, FLOAT& fTheta,
+ FLOAT x, FLOAT y, FLOAT z, FLOAT w )
+
+{
+ fTheta = acosf(w) * 2.0f;
+ v.x = x / sinf( fTheta/2.0f );
+ v.y = y / sinf( fTheta/2.0f );
+ v.z = z / sinf( fTheta/2.0f );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_QuaternionFromAngles()
+// Desc: Converts euler angles to a unit quaternion.
+//-----------------------------------------------------------------------------
+VOID D3DMath_QuaternionFromAngles( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w,
+ FLOAT fYaw, FLOAT fPitch, FLOAT fRoll )
+
+{
+ FLOAT fSinYaw = sinf( fYaw/2.0f );
+ FLOAT fSinPitch = sinf( fPitch/2.0f );
+ FLOAT fSinRoll = sinf( fRoll/2.0f );
+ FLOAT fCosYaw = cosf( fYaw/2.0f );
+ FLOAT fCosPitch = cosf( fPitch/2.0f );
+ FLOAT fCosRoll = cosf( fRoll/2.0f );
+
+ x = fSinRoll * fCosPitch * fCosYaw - fCosRoll * fSinPitch * fSinYaw;
+ y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw;
+ z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw;
+ w = fCosRoll * fCosPitch * fCosYaw + fSinRoll * fSinPitch * fSinYaw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_MatrixFromQuaternion()
+// Desc: Converts a unit quaternion into a rotation matrix.
+//-----------------------------------------------------------------------------
+VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z,
+ FLOAT w )
+{
+ FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z;
+ FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z;
+ FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z;
+
+ mat._11 = 1 - 2 * ( yy + zz );
+ mat._12 = 2 * ( xy - wz );
+ mat._13 = 2 * ( xz + wy );
+
+ mat._21 = 2 * ( xy + wz );
+ mat._22 = 1 - 2 * ( xx + zz );
+ mat._23 = 2 * ( yz - wx );
+
+ mat._31 = 2 * ( xz - wy );
+ mat._32 = 2 * ( yz + wx );
+ mat._33 = 1 - 2 * ( xx + yy );
+
+ mat._14 = mat._24 = mat._34 = 0.0f;
+ mat._41 = mat._42 = mat._43 = 0.0f;
+ mat._44 = 1.0f;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_QuaternionFromMatrix()
+// Desc: Converts a rotation matrix into a unit quaternion.
+//-----------------------------------------------------------------------------
+VOID D3DMath_QuaternionFromMatrix( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w,
+ D3DMATRIX& mat )
+{
+ if( mat._11 + mat._22 + mat._33 > 0.0f )
+ {
+ FLOAT s = sqrtf( mat._11 + mat._22 + mat._33 + mat._44 );
+
+ x = (mat._23-mat._32) / (2*s);
+ y = (mat._31-mat._13) / (2*s);
+ z = (mat._12-mat._21) / (2*s);
+ w = 0.5f * s;
+ }
+ else
+ {
+
+
+ }
+ FLOAT xx = x*x; FLOAT yy = y*y; FLOAT zz = z*z;
+ FLOAT xy = x*y; FLOAT xz = x*z; FLOAT yz = y*z;
+ FLOAT wx = w*x; FLOAT wy = w*y; FLOAT wz = w*z;
+
+ mat._11 = 1 - 2 * ( yy + zz );
+ mat._12 = 2 * ( xy - wz );
+ mat._13 = 2 * ( xz + wy );
+
+ mat._21 = 2 * ( xy + wz );
+ mat._22 = 1 - 2 * ( xx + zz );
+ mat._23 = 2 * ( yz - wx );
+
+ mat._31 = 2 * ( xz - wy );
+ mat._32 = 2 * ( yz + wx );
+ mat._33 = 1 - 2 * ( xx + yy );
+
+ mat._14 = mat._24 = mat._34 = 0.0f;
+ mat._41 = mat._42 = mat._43 = 0.0f;
+ mat._44 = 1.0f;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_QuaternionMultiply()
+// Desc: Mulitples two quaternions together as in {Q} = {A} * {B}.
+//-----------------------------------------------------------------------------
+VOID D3DMath_QuaternionMultiply( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw,
+ FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw,
+ FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw )
+{
+ FLOAT Dx = Ax*Bw + Ay*Bz - Az*By + Aw*Bx;
+ FLOAT Dy = -Ax*Bz + Ay*Bw + Az*Bx + Aw*By;
+ FLOAT Dz = Ax*By - Ay*Bx + Az*Bw + Aw*Bz;
+ FLOAT Dw = -Ax*Bx - Ay*By - Az*Bz + Aw*Bw;
+
+ Qx = Dx; Qy = Dy; Qz = Dz; Qw = Dw;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DMath_SlerpQuaternions()
+// Desc: Compute a quaternion which is the spherical linear interpolation
+// between two other quaternions by dvFraction.
+//-----------------------------------------------------------------------------
+VOID D3DMath_QuaternionSlerp( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw,
+ FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw,
+ FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw,
+ FLOAT fAlpha )
+{
+ // Compute dot product (equal to cosine of the angle between quaternions)
+ FLOAT fCosTheta = Ax*Bx + Ay*By + Az*Bz + Aw*Bw;
+
+ // Check angle to see if quaternions are in opposite hemispheres
+ if( fCosTheta < 0.0f )
+ {
+ // If so, flip one of the quaterions
+ fCosTheta = -fCosTheta;
+ Bx = -Bx; By = -By; Bz = -Bz; Bw = -Bw;
+ }
+
+ // Set factors to do linear interpolation, as a special case where the
+ // quaternions are close together.
+ FLOAT fBeta = 1.0f - fAlpha;
+
+ // If the quaternions aren't close, proceed with spherical interpolation
+ if( 1.0f - fCosTheta > 0.001f )
+ {
+ FLOAT fTheta = acosf( fCosTheta );
+
+ fBeta = sinf( fTheta*fBeta ) / sinf( fTheta);
+ fAlpha = sinf( fTheta*fAlpha ) / sinf( fTheta);
+ }
+
+ // Do the interpolation
+ Qx = fBeta*Ax + fAlpha*Bx;
+ Qy = fBeta*Ay + fAlpha*By;
+ Qz = fBeta*Az + fAlpha*Bz;
+ Qw = fBeta*Aw + fAlpha*Bw;
+}
+
+
+
+
diff --git a/src/d3dmath.h b/src/d3dmath.h
new file mode 100644
index 0000000..8315d88
--- /dev/null
+++ b/src/d3dmath.h
@@ -0,0 +1,81 @@
+//-----------------------------------------------------------------------------
+// File: D3DMath.h
+//
+// Desc: Math functions and shortcuts for Direct3D programming.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DMATH_H
+#define D3DMATH_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+//-----------------------------------------------------------------------------
+// Useful Math constants
+//-----------------------------------------------------------------------------
+const FLOAT g_PI = 3.14159265358979323846f; // Pi
+const FLOAT g_2_PI = 6.28318530717958623200f; // 2 * Pi
+const FLOAT g_PI_DIV_2 = 1.57079632679489655800f; // Pi / 2
+const FLOAT g_PI_DIV_4 = 0.78539816339744827900f; // Pi / 4
+const FLOAT g_INV_PI = 0.31830988618379069122f; // 1 / Pi
+const FLOAT g_DEGTORAD = 0.01745329251994329547f; // Degrees to Radians
+const FLOAT g_RADTODEG = 57.29577951308232286465f; // Radians to Degrees
+const FLOAT g_HUGE = 1.0e+38f; // Huge number for FLOAT
+const FLOAT g_EPSILON = 1.0e-5f; // Tolerance for FLOATs
+
+
+
+
+//-----------------------------------------------------------------------------
+// Fuzzy compares (within tolerance)
+//-----------------------------------------------------------------------------
+inline BOOL D3DMath_IsZero( FLOAT a, FLOAT fTol = g_EPSILON )
+{ return ( a <= 0.0f ) ? ( a >= -fTol ) : ( a <= fTol ); }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Matrix functions
+//-----------------------------------------------------------------------------
+VOID D3DMath_MatrixMultiply( D3DMATRIX& q, D3DMATRIX& a, D3DMATRIX& b );
+HRESULT D3DMath_MatrixInvert( D3DMATRIX& q, D3DMATRIX& a );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Vector functions
+//-----------------------------------------------------------------------------
+HRESULT D3DMath_VectorMatrixMultiply( D3DVECTOR& vDest, D3DVECTOR& vSrc,
+ D3DMATRIX& mat);
+HRESULT D3DMath_VertexMatrixMultiply( D3DVERTEX& vDest, D3DVERTEX& vSrc,
+ D3DMATRIX& mat );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Quaternion functions
+//-----------------------------------------------------------------------------
+VOID D3DMath_QuaternionFromRotation( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w,
+ D3DVECTOR& v, FLOAT fTheta );
+VOID D3DMath_RotationFromQuaternion( D3DVECTOR& v, FLOAT& fTheta,
+ FLOAT x, FLOAT y, FLOAT z, FLOAT w );
+VOID D3DMath_QuaternionFromAngles( FLOAT& x, FLOAT& y, FLOAT& z, FLOAT& w,
+ FLOAT fYaw, FLOAT fPitch, FLOAT fRoll );
+VOID D3DMath_MatrixFromQuaternion( D3DMATRIX& mat, FLOAT x, FLOAT y, FLOAT z,
+ FLOAT w );
+VOID D3DMath_QuaternionFromMatrix( FLOAT &x, FLOAT &y, FLOAT &z, FLOAT &w,
+ D3DMATRIX& mat );
+VOID D3DMath_QuaternionMultiply( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw,
+ FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw,
+ FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw );
+VOID D3DMath_QuaternionSlerp( FLOAT& Qx, FLOAT& Qy, FLOAT& Qz, FLOAT& Qw,
+ FLOAT Ax, FLOAT Ay, FLOAT Az, FLOAT Aw,
+ FLOAT Bx, FLOAT By, FLOAT Bz, FLOAT Bw,
+ FLOAT fAlpha );
+
+
+#endif // D3DMATH_H
diff --git a/src/d3dres.h b/src/d3dres.h
new file mode 100644
index 0000000..c9d1df9
--- /dev/null
+++ b/src/d3dres.h
@@ -0,0 +1,43 @@
+//-----------------------------------------------------------------------------
+// File: D3DRes.h
+//
+// Desc: Resource definitions required by the CD3DApplication class.
+// Any application using the CD3DApplication class must include resources
+// with the following identifiers.
+//
+// Copyright (c) 1999 Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#ifndef D3DRES_H
+#define D3DRES_H
+
+
+#define IDI_MAIN_ICON 101 // Application icon
+#define IDR_MAIN_ACCEL 113 // Keyboard accelerator
+#define IDR_MENU 141 // Application menu
+#define IDR_POPUP 142 // Popup menu
+#define IDD_ABOUT 143 // About dialog box
+#define IDD_CHANGEDEVICE 144 // "Change Device" dialog box
+#define IDC_CURSORHAND 149
+#define IDC_CURSORSCROLLL 150
+#define IDC_CURSORSCROLLR 151
+#define IDC_CURSORSCROLLU 152
+#define IDC_CURSORSCROLLD 153
+#define IDC_CURSORTARGET 154
+
+#define IDC_DEVICE_COMBO 1000 // Device combobox for "Change Device" dlg
+#define IDC_MODE_COMBO 1001 // Mode combobox for "Change Device" dlg
+#define IDC_WINDOWED_CHECKBOX 1012 // Checkbox for windowed-mode
+#define IDC_STEREO_CHECKBOX 1013 // Checkbox for stereo modes
+#define IDC_FULLSCREEN_TEXT 1014 // Group box text label
+
+#define IDM_ABOUT 40001 // Command to invoke About dlg
+#define IDM_CHANGEDEVICE 40002 // Command to invoke "Change Device" dlg
+#define IDM_TOGGLEFULLSCREEN 40003 // Command to toggle fullscreen mode
+#define IDM_TOGGLESTART 40004 // Command to toggle frame animation
+#define IDM_SINGLESTEP 40005 // Command to single step frame animation
+#define IDM_EXIT 40006 // Command to exit the application
+
+
+
+
+#endif // D3DRES_H
diff --git a/src/d3dtextr.cpp b/src/d3dtextr.cpp
new file mode 100644
index 0000000..f3364f6
--- /dev/null
+++ b/src/d3dtextr.cpp
@@ -0,0 +1,1064 @@
+//-----------------------------------------------------------------------------
+// File: D3DTextr.cpp
+//
+// Desc: Functions to manage textures, including creating (loading from a
+// file), restoring lost surfaces, invalidating, and destroying.
+//
+// Note: the implementation of these fucntions maintain an internal list
+// of loaded textures. After creation, individual textures are referenced
+// via their ASCII names.
+//
+// Copyright (c) 1996-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define STRICT
+#include <tchar.h>
+#include <stdio.h>
+#include "D3DTextr.h"
+#include "D3DUtil.h"
+#include "language.h"
+#include "misc.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Macros, function prototypes and static variable
+//-----------------------------------------------------------------------------
+static TCHAR g_strTexturePath[512] = _T(""); // Path for files
+static BOOL g_bDebugMode = FALSE;
+
+
+
+void D3DTextr_SetDebugMode(BOOL bDebug)
+{
+ g_bDebugMode = bDebug;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TextureContainer
+// Desc: Linked list structure to hold info per texture
+//-----------------------------------------------------------------------------
+struct TextureContainer
+{
+ TextureContainer* m_pNext; // Linked list ptr
+
+ TCHAR m_strName[80]; // Name of texture (doubles as image filename)
+ DWORD m_dwWidth;
+ DWORD m_dwHeight;
+ DWORD m_dwStage; // Texture stage (for multitexture devices)
+ DWORD m_dwBPP;
+ DWORD m_dwFlags;
+ BOOL m_bHasAlpha;
+
+ LPDIRECTDRAWSURFACE7 m_pddsSurface; // Surface of the texture
+ HBITMAP m_hbmBitmap; // Bitmap containing texture image
+ DWORD* m_pRGBAData;
+
+public:
+ HRESULT LoadImageData();
+ HRESULT LoadBitmapFile( TCHAR* strPathname );
+ HRESULT LoadTargaFile( TCHAR* strPathname, TCHAR* strFilename );
+ HRESULT Restore( LPDIRECT3DDEVICE7 pd3dDevice );
+ HRESULT CopyBitmapToSurface();
+ HRESULT CopyRGBADataToSurface();
+
+ TextureContainer( TCHAR* strName, DWORD dwStage, DWORD dwFlags );
+ ~TextureContainer();
+};
+
+// Local list of textures
+static TextureContainer* g_ptcTextureList = NULL;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CD3DTextureManager
+// Desc: Class used to automatically construct and destruct the static
+// texture engine class.
+//-----------------------------------------------------------------------------
+class CD3DTextureManager
+{
+public:
+ CD3DTextureManager() {}
+ ~CD3DTextureManager() { if( g_ptcTextureList ) delete g_ptcTextureList; }
+};
+
+// Global instance
+CD3DTextureManager g_StaticTextureEngine;
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: struct TEXTURESEARCHINFO
+// Desc: Structure used to search for texture formats
+//-----------------------------------------------------------------------------
+struct TEXTURESEARCHINFO
+{
+ DWORD dwDesiredBPP; // Input for texture format search
+ BOOL bUseAlpha;
+ BOOL bUsePalette;
+ BOOL bFoundGoodFormat;
+
+ DDPIXELFORMAT* pddpf; // Output of texture format search
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TextureSearchCallback()
+// Desc: Enumeration callback routine to find a best-matching texture format.
+// The param data is the DDPIXELFORMAT of the best-so-far matching
+// texture. Note: the desired BPP is passed in the dwSize field, and the
+// default BPP is passed in the dwFlags field.
+//-----------------------------------------------------------------------------
+static HRESULT CALLBACK TextureSearchCallback( DDPIXELFORMAT* pddpf,
+ VOID* param )
+{
+ if( NULL==pddpf || NULL==param )
+ return DDENUMRET_OK;
+
+ TEXTURESEARCHINFO* ptsi = (TEXTURESEARCHINFO*)param;
+
+ // Skip any funky modes
+ if( pddpf->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) )
+ return DDENUMRET_OK;
+
+ // Check for palettized formats
+ if( ptsi->bUsePalette )
+ {
+ if( !( pddpf->dwFlags & DDPF_PALETTEINDEXED8 ) )
+ return DDENUMRET_OK;
+
+ // Accept the first 8-bit palettized format we get
+ memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
+ ptsi->bFoundGoodFormat = TRUE;
+ return DDENUMRET_CANCEL;
+ }
+
+ // Else, skip any paletized formats (all modes under 16bpp)
+ if( pddpf->dwRGBBitCount < 16 )
+ return DDENUMRET_OK;
+
+ // Skip any FourCC formats
+ if( pddpf->dwFourCC != 0 )
+ return DDENUMRET_OK;
+
+ // Skip any ARGB 4444 formats (which are best used for pre-authored
+ // content designed speciafically for an ARGB 4444 format).
+ if( pddpf->dwRGBAlphaBitMask == 0x0000f000 )
+ return DDENUMRET_OK;
+
+ // Make sure current alpha format agrees with requested format type
+ if( (ptsi->bUseAlpha==TRUE) && !(pddpf->dwFlags&DDPF_ALPHAPIXELS) )
+ return DDENUMRET_OK;
+ if( (ptsi->bUseAlpha==FALSE) && (pddpf->dwFlags&DDPF_ALPHAPIXELS) )
+ return DDENUMRET_OK;
+
+ // Check if we found a good match
+ if( pddpf->dwRGBBitCount == ptsi->dwDesiredBPP )
+ {
+ memcpy( ptsi->pddpf, pddpf, sizeof(DDPIXELFORMAT) );
+ ptsi->bFoundGoodFormat = TRUE;
+ return DDENUMRET_CANCEL;
+ }
+
+ return DDENUMRET_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: FindTexture()
+// Desc: Searches the internal list of textures for a texture specified by
+// its name. Returns the structure associated with that texture.
+//-----------------------------------------------------------------------------
+static TextureContainer* FindTexture( TCHAR* strTextureName )
+{
+ TextureContainer* ptcTexture = g_ptcTextureList;
+
+ while( ptcTexture )
+ {
+ if( !lstrcmpi( strTextureName, ptcTexture->m_strName ) )
+ return ptcTexture;
+ ptcTexture = ptcTexture->m_pNext;
+ }
+
+ return NULL;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: TextureContainer()
+// Desc: Constructor for a texture object
+//-----------------------------------------------------------------------------
+TextureContainer::TextureContainer( TCHAR* strName, DWORD dwStage,
+ DWORD dwFlags )
+{
+ lstrcpy( m_strName, strName );
+ m_dwWidth = 0;
+ m_dwHeight = 0;
+ m_dwStage = dwStage;
+ m_dwBPP = 0;
+ m_dwFlags = dwFlags;
+ m_bHasAlpha = 0;
+
+ m_pddsSurface = NULL;
+ m_hbmBitmap = NULL;
+ m_pRGBAData = NULL;
+
+ // Add the texture to the head of the global texture list
+ m_pNext = g_ptcTextureList;
+ g_ptcTextureList = this;
+
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: ~TextureContainer()
+// Desc: Destructs the contents of the texture container
+//-----------------------------------------------------------------------------
+TextureContainer::~TextureContainer()
+{
+ SAFE_RELEASE( m_pddsSurface );
+ SAFE_DELETE( m_pRGBAData );
+ DeleteObject( m_hbmBitmap );
+
+ // Remove the texture container from the global list
+ if( g_ptcTextureList == this )
+ g_ptcTextureList = m_pNext;
+ else
+ {
+ for( TextureContainer* ptc=g_ptcTextureList; ptc; ptc=ptc->m_pNext )
+ if( ptc->m_pNext == this )
+ ptc->m_pNext = m_pNext;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: LoadImageData()
+// Desc: Loads the texture map's image data
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::LoadImageData()
+{
+ TCHAR* strExtension;
+ TCHAR strMetaname[256];
+ TCHAR strFilename[256];
+
+ if ( g_bDebugMode )
+ {
+ if ( _tcsrchr( m_strName, _T('\\') ) == 0 )
+ {
+ lstrcpy( strMetaname, "" );
+ lstrcpy( strFilename, g_strTexturePath );
+ lstrcat( strFilename, m_strName );
+ }
+ else
+ {
+ lstrcpy( strMetaname, "" );
+ lstrcpy( strFilename, m_strName );
+ }
+ }
+ else
+ {
+ if ( _tcsrchr( m_strName, _T('\\') ) == 0 )
+ {
+#if _SCHOOL
+ lstrcpy( strMetaname, "ceebot1.dat" );
+#else
+ lstrcpy( strMetaname, "colobot1.dat" );
+#endif
+ lstrcpy( strFilename, m_strName );
+ }
+ else
+ {
+ lstrcpy( strMetaname, "" );
+ lstrcpy( strFilename, m_strName );
+ }
+ }
+
+ if ( !g_metafile.IsExist(strMetaname, strFilename) )
+ {
+ return DDERR_NOTFOUND;
+ }
+
+ // Get the filename extension
+ if ( NULL == ( strExtension = _tcsrchr( m_strName, _T('.') ) ) )
+ {
+ return DDERR_UNSUPPORTED;
+ }
+
+ // Load bitmap files
+ if ( strMetaname[0] == 0 && !lstrcmpi( strExtension, _T(".bmp") ) )
+ {
+ return LoadBitmapFile( strFilename );
+ }
+
+ // Load targa files
+ if ( !lstrcmpi( strExtension, _T(".tga") ) )
+ {
+ return LoadTargaFile( strMetaname, strFilename );
+ }
+
+ // Can add code here to check for other file formats before failing
+ return DDERR_UNSUPPORTED;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: LoadBitmapFile()
+// Desc: Loads data from a .bmp file, and stores it in a bitmap structure.
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::LoadBitmapFile( TCHAR* strPathname )
+{
+ // Try to load the bitmap as a file
+ m_hbmBitmap = (HBITMAP)LoadImage( NULL, strPathname, IMAGE_BITMAP, 0, 0,
+ LR_LOADFROMFILE|LR_CREATEDIBSECTION );
+ if( m_hbmBitmap )
+ return S_OK;
+
+ return DDERR_NOTFOUND;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: LoadTargaFile()
+// Desc: Loads RGBA data from a .tga file, and stores it in allocated memory
+// for the specified texture container
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::LoadTargaFile( TCHAR* strMetaname, TCHAR* strFilename )
+{
+ if( g_metafile.Open(strMetaname, strFilename) != 0 )
+ return E_FAIL;
+
+ struct TargaHeader
+ {
+ BYTE IDLength;
+ BYTE ColormapType;
+ BYTE ImageType;
+ BYTE ColormapSpecification[5];
+ WORD XOrigin;
+ WORD YOrigin;
+ WORD ImageWidth;
+ WORD ImageHeight;
+ BYTE PixelDepth;
+ BYTE ImageDescriptor;
+ } tga;
+
+ g_metafile.Read(&tga, sizeof(TargaHeader));
+
+ // Only true color, non-mapped images are supported
+ if( ( 0 != tga.ColormapType ) ||
+ ( tga.ImageType != 10 && tga.ImageType != 2 ) )
+ {
+ g_metafile.Close();
+ return E_FAIL;
+ }
+
+ // Skip the ID field. The first byte of the header is the length of this field
+ if( tga.IDLength )
+ {
+ g_metafile.Seek(tga.IDLength);
+ }
+
+ m_dwWidth = tga.ImageWidth;
+ m_dwHeight = tga.ImageHeight;
+ m_dwBPP = tga.PixelDepth;
+ m_pRGBAData = new DWORD[m_dwWidth*m_dwHeight];
+
+ if( m_pRGBAData == NULL )
+ {
+ g_metafile.Close();
+ return E_FAIL;
+ }
+
+ for( DWORD y=0; y<m_dwHeight; y++ )
+ {
+ DWORD dwOffset = y*m_dwWidth;
+
+ if( 0 == ( tga.ImageDescriptor & 0x0010 ) )
+ dwOffset = (m_dwHeight-y-1)*m_dwWidth;
+
+ for( DWORD x=0; x<m_dwWidth; x )
+ {
+ if( tga.ImageType == 10 )
+ {
+ BYTE PacketInfo = g_metafile.GetByte();
+ WORD PacketType = 0x80 & PacketInfo;
+ WORD PixelCount = ( 0x007f & PacketInfo ) + 1;
+
+ if( PacketType )
+ {
+ DWORD b = g_metafile.GetWord();
+ DWORD g = g_metafile.GetWord();
+ DWORD r = g_metafile.GetWord();
+ DWORD a = 0xff;
+ if( m_dwBPP == 32 )
+ a = g_metafile.GetWord();
+
+ while( PixelCount-- )
+ {
+ m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
+ x++;
+ }
+ }
+ else
+ {
+ while( PixelCount-- )
+ {
+ BYTE b = g_metafile.GetByte();
+ BYTE g = g_metafile.GetByte();
+ BYTE r = g_metafile.GetByte();
+ BYTE a = 0xff;
+ if( m_dwBPP == 32 )
+ a = g_metafile.GetByte();
+
+ m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
+ x++;
+ }
+ }
+ }
+ else
+ {
+ BYTE b = g_metafile.GetByte();
+ BYTE g = g_metafile.GetByte();
+ BYTE r = g_metafile.GetByte();
+ BYTE a = 0xff;
+ if( m_dwBPP == 32 )
+ a = g_metafile.GetByte();
+
+ m_pRGBAData[dwOffset+x] = (r<<24L)+(g<<16L)+(b<<8L)+(a);
+ x++;
+ }
+ }
+ }
+
+ g_metafile.Close();
+
+ // Check for alpha content
+ for( DWORD i=0; i<(m_dwWidth*m_dwHeight); i++ )
+ {
+//? if( m_pRGBAData[i] & 0x000000ff != 0xff )
+ if( (m_pRGBAData[i] & 0x000000ff) != 0xff ) // erreur corrigée !
+ {
+ m_bHasAlpha = TRUE;
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: Restore()
+// Desc: Rebuilds the texture surface using the new device.
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::Restore( LPDIRECT3DDEVICE7 pd3dDevice )
+{
+ // Release any previously created objects
+ SAFE_RELEASE( m_pddsSurface );
+
+ // Check params
+ if( NULL == pd3dDevice )
+ return DDERR_INVALIDPARAMS;
+
+ // Get the device caps
+ D3DDEVICEDESC7 ddDesc;
+ if( FAILED( pd3dDevice->GetCaps( &ddDesc) ) )
+ return E_FAIL;
+
+ // Setup the new surface desc
+ DDSURFACEDESC2 ddsd;
+ D3DUtil_InitSurfaceDesc( ddsd );
+ ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|
+ DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+ ddsd.dwTextureStage = m_dwStage;
+ ddsd.dwWidth = m_dwWidth;
+ ddsd.dwHeight = m_dwHeight;
+
+ // Turn on texture management for hardware devices
+ if( ddDesc.deviceGUID == IID_IDirect3DHALDevice )
+ ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
+ else if( ddDesc.deviceGUID == IID_IDirect3DTnLHalDevice )
+ ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
+ else
+ ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+
+ // Adjust width and height to be powers of 2, if the device requires it
+ if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 )
+ {
+ for( ddsd.dwWidth=1; m_dwWidth>ddsd.dwWidth; ddsd.dwWidth<<=1 );
+ for( ddsd.dwHeight=1; m_dwHeight>ddsd.dwHeight; ddsd.dwHeight<<=1 );
+ }
+
+ // Limit max texture sizes, if the driver can't handle large textures
+ DWORD dwMaxWidth = ddDesc.dwMaxTextureWidth;
+ DWORD dwMaxHeight = ddDesc.dwMaxTextureHeight;
+ ddsd.dwWidth = min( ddsd.dwWidth, ( dwMaxWidth ? dwMaxWidth : 256 ) );
+ ddsd.dwHeight = min( ddsd.dwHeight, ( dwMaxHeight ? dwMaxHeight : 256 ) );
+
+ // Make the texture square, if the driver requires it
+ if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
+ {
+ if( ddsd.dwWidth > ddsd.dwHeight ) ddsd.dwHeight = ddsd.dwWidth;
+ else ddsd.dwWidth = ddsd.dwHeight;
+ }
+
+ // Setup the structure to be used for texture enumration.
+ TEXTURESEARCHINFO tsi;
+ tsi.bFoundGoodFormat = FALSE;
+ tsi.pddpf = &ddsd.ddpfPixelFormat;
+ tsi.dwDesiredBPP = m_dwBPP;
+ tsi.bUsePalette = ( m_dwBPP <= 8 );
+ tsi.bUseAlpha = m_bHasAlpha;
+ if( m_dwFlags & D3DTEXTR_16BITSPERPIXEL )
+ tsi.dwDesiredBPP = 16;
+ else if( m_dwFlags & D3DTEXTR_32BITSPERPIXEL )
+ tsi.dwDesiredBPP = 32;
+
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ {
+ if( tsi.bUsePalette )
+ {
+ if( ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_ALPHAPALETTE )
+ {
+ tsi.bUseAlpha = TRUE;
+ tsi.bUsePalette = TRUE;
+ }
+ else
+ {
+ tsi.bUseAlpha = TRUE;
+ tsi.bUsePalette = FALSE;
+ }
+ }
+ }
+
+ // Enumerate the texture formats, and find the closest device-supported
+ // texture pixel format
+ pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
+
+ // If we couldn't find a format, let's try a default format
+ if( FALSE == tsi.bFoundGoodFormat )
+ {
+ tsi.bUsePalette = FALSE;
+ tsi.dwDesiredBPP = 16;
+ pd3dDevice->EnumTextureFormats( TextureSearchCallback, &tsi );
+
+ // If we still fail, we cannot create this texture
+ if( FALSE == tsi.bFoundGoodFormat )
+ return E_FAIL;
+ }
+
+ // Get the DirectDraw interface for creating surfaces
+ LPDIRECTDRAW7 pDD;
+ LPDIRECTDRAWSURFACE7 pddsRender;
+ pd3dDevice->GetRenderTarget( &pddsRender );
+ pddsRender->GetDDInterface( (VOID**)&pDD );
+ pddsRender->Release();
+
+ // Create a new surface for the texture
+ HRESULT hr = pDD->CreateSurface( &ddsd, &m_pddsSurface, NULL );
+
+ // Done with DDraw
+ pDD->Release();
+
+ if( FAILED(hr) )
+ return hr;
+
+ // For bitmap-based textures, copy the bitmap image.
+ if( m_hbmBitmap )
+ return CopyBitmapToSurface();
+
+ if( m_pRGBAData )
+ return CopyRGBADataToSurface();
+
+ // At this point, code can be added to handle other file formats (such as
+ // .dds files, .jpg files, etc.).
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CopyBitmapToSurface()
+// Desc: Copies the image of a bitmap into a surface
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::CopyBitmapToSurface()
+{
+ // Get a DDraw object to create a temporary surface
+ LPDIRECTDRAW7 pDD;
+ m_pddsSurface->GetDDInterface( (VOID**)&pDD );
+
+ // Get the bitmap structure (to extract width, height, and bpp)
+ BITMAP bm;
+ GetObject( m_hbmBitmap, sizeof(BITMAP), &bm );
+
+ // Setup the new surface desc
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsSurface->GetSurfaceDesc( &ddsd );
+ ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
+ DDSD_TEXTURESTAGE;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
+ ddsd.ddsCaps.dwCaps2 = 0L;
+ ddsd.dwWidth = bm.bmWidth;
+ ddsd.dwHeight = bm.bmHeight;
+
+ // Create a new surface for the texture
+ LPDIRECTDRAWSURFACE7 pddsTempSurface;
+ HRESULT hr;
+ if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
+ {
+ pDD->Release();
+ return hr;
+ }
+
+ // Get a DC for the bitmap
+ HDC hdcBitmap = CreateCompatibleDC( NULL );
+ if( NULL == hdcBitmap )
+ {
+ pddsTempSurface->Release();
+ pDD->Release();
+ return hr;
+ }
+ SelectObject( hdcBitmap, m_hbmBitmap );
+
+ // Handle palettized textures. Need to attach a palette
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount == 8 )
+ {
+ LPDIRECTDRAWPALETTE pPalette;
+ DWORD dwPaletteFlags = DDPCAPS_8BIT|DDPCAPS_ALLOW256;
+ DWORD pe[256];
+ WORD wNumColors = GetDIBColorTable( hdcBitmap, 0, 256, (RGBQUAD*)pe );
+
+ // Create the color table
+ for( WORD i=0; i<wNumColors; i++ )
+ {
+ pe[i] = RGB( GetBValue(pe[i]), GetGValue(pe[i]), GetRValue(pe[i]) );
+
+ // Handle textures with transparent pixels
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ {
+ // Set alpha for opaque pixels
+ if( m_dwFlags & D3DTEXTR_TRANSPARENTBLACK )
+ {
+ if( pe[i] != 0x00000000 )
+ pe[i] |= 0xff000000;
+ }
+ else if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )
+ {
+ if( pe[i] != 0x00ffffff )
+ pe[i] |= 0xff000000;
+ }
+ }
+ }
+ // Add DDPCAPS_ALPHA flag for textures with transparent pixels
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ dwPaletteFlags |= DDPCAPS_ALPHA;
+
+ // Create & attach a palette
+ pDD->CreatePalette( dwPaletteFlags, (PALETTEENTRY*)pe, &pPalette, NULL );
+ pddsTempSurface->SetPalette( pPalette );
+ m_pddsSurface->SetPalette( pPalette );
+ SAFE_RELEASE( pPalette );
+ }
+
+ // Copy the bitmap image to the surface.
+ HDC hdcSurface;
+ if( SUCCEEDED( pddsTempSurface->GetDC( &hdcSurface ) ) )
+ {
+ BitBlt( hdcSurface, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap, 0, 0,
+ SRCCOPY );
+ pddsTempSurface->ReleaseDC( hdcSurface );
+ }
+ DeleteDC( hdcBitmap );
+
+ // Copy the temp surface to the real texture surface
+ m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
+
+ // Done with the temp surface
+ pddsTempSurface->Release();
+
+ // For textures with real alpha (not palettized), set transparent bits
+ if( ddsd.ddpfPixelFormat.dwRGBAlphaBitMask )
+ {
+ if( m_dwFlags & (D3DTEXTR_TRANSPARENTWHITE|D3DTEXTR_TRANSPARENTBLACK) )
+ {
+ // Lock the texture surface
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ while( m_pddsSurface->Lock( NULL, &ddsd, 0, NULL ) ==
+ DDERR_WASSTILLDRAWING );
+
+ DWORD dwAlphaMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
+ DWORD dwRGBMask = ( ddsd.ddpfPixelFormat.dwRBitMask |
+ ddsd.ddpfPixelFormat.dwGBitMask |
+ ddsd.ddpfPixelFormat.dwBBitMask );
+ DWORD dwColorkey = 0x00000000; // Colorkey on black
+ if( m_dwFlags & D3DTEXTR_TRANSPARENTWHITE )
+ dwColorkey = dwRGBMask; // Colorkey on white
+
+ // Add an opaque alpha value to each non-colorkeyed pixel
+ for( DWORD y=0; y<ddsd.dwHeight; y++ )
+ {
+ WORD* p16 = (WORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
+ DWORD* p32 = (DWORD*)((BYTE*)ddsd.lpSurface + y*ddsd.lPitch);
+
+ for( DWORD x=0; x<ddsd.dwWidth; x++ )
+ {
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount == 16 )
+ {
+ if( ( *p16 &= dwRGBMask ) != dwColorkey )
+ *p16 |= dwAlphaMask;
+ p16++;
+ }
+ if( ddsd.ddpfPixelFormat.dwRGBBitCount == 32 )
+ {
+ if( ( *p32 &= dwRGBMask ) != dwColorkey )
+ *p32 |= dwAlphaMask;
+ p32++;
+ }
+ }
+ }
+ m_pddsSurface->Unlock( NULL );
+ }
+ }
+
+ pDD->Release();
+
+ return S_OK;;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: CopyRGBADataToSurface()
+// Desc: Invalidates the current texture objects and rebuilds new ones
+// using the new device.
+//-----------------------------------------------------------------------------
+HRESULT TextureContainer::CopyRGBADataToSurface()
+{
+ // Get a DDraw object to create a temporary surface
+ LPDIRECTDRAW7 pDD;
+ m_pddsSurface->GetDDInterface( (VOID**)&pDD );
+
+ // Setup the new surface desc
+ DDSURFACEDESC2 ddsd;
+ ddsd.dwSize = sizeof(ddsd);
+ m_pddsSurface->GetSurfaceDesc( &ddsd );
+ ddsd.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|
+ DDSD_TEXTURESTAGE;
+ ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE|DDSCAPS_SYSTEMMEMORY;
+ ddsd.ddsCaps.dwCaps2 = 0L;
+ ddsd.dwWidth = m_dwWidth;
+ ddsd.dwHeight = m_dwHeight;
+
+ // Create a new surface for the texture
+ LPDIRECTDRAWSURFACE7 pddsTempSurface;
+ HRESULT hr;
+ if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTempSurface, NULL ) ) )
+ {
+ pDD->Release();
+ return NULL;
+ }
+
+ while( pddsTempSurface->Lock( NULL, &ddsd, 0, 0 ) == DDERR_WASSTILLDRAWING );
+ DWORD lPitch = ddsd.lPitch;
+ BYTE* pBytes = (BYTE*)ddsd.lpSurface;
+
+ DWORD dwRMask = ddsd.ddpfPixelFormat.dwRBitMask;
+ DWORD dwGMask = ddsd.ddpfPixelFormat.dwGBitMask;
+ DWORD dwBMask = ddsd.ddpfPixelFormat.dwBBitMask;
+ DWORD dwAMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
+
+ DWORD dwRShiftL = 8, dwRShiftR = 0;
+ DWORD dwGShiftL = 8, dwGShiftR = 0;
+ DWORD dwBShiftL = 8, dwBShiftR = 0;
+ DWORD dwAShiftL = 8, dwAShiftR = 0;
+
+ DWORD dwMask;
+ for( dwMask=dwRMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwRShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwRShiftL--;
+
+ for( dwMask=dwGMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwGShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwGShiftL--;
+
+ for( dwMask=dwBMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwBShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwBShiftL--;
+
+ for( dwMask=dwAMask; dwMask && !(dwMask&0x1); dwMask>>=1 ) dwAShiftR++;
+ for( ; dwMask; dwMask>>=1 ) dwAShiftL--;
+
+ for( DWORD y=0; y<ddsd.dwHeight; y++ )
+ {
+ DWORD* pDstData32 = (DWORD*)pBytes;
+ WORD* pDstData16 = (WORD*)pBytes;
+
+ for( DWORD x=0; x<ddsd.dwWidth; x++ )
+ {
+ DWORD dwPixel = m_pRGBAData[y*ddsd.dwWidth+x];
+
+ BYTE r = (BYTE)((dwPixel>>24)&0x000000ff);
+ BYTE g = (BYTE)((dwPixel>>16)&0x000000ff);
+ BYTE b = (BYTE)((dwPixel>> 8)&0x000000ff);
+ BYTE a = (BYTE)((dwPixel>> 0)&0x000000ff);
+
+ DWORD dr = ((r>>(dwRShiftL))<<dwRShiftR)&dwRMask;
+ DWORD dg = ((g>>(dwGShiftL))<<dwGShiftR)&dwGMask;
+ DWORD db = ((b>>(dwBShiftL))<<dwBShiftR)&dwBMask;
+ DWORD da = ((a>>(dwAShiftL))<<dwAShiftR)&dwAMask;
+
+ if( 32 == ddsd.ddpfPixelFormat.dwRGBBitCount )
+ pDstData32[x] = (DWORD)(dr+dg+db+da);
+ else
+ pDstData16[x] = (WORD)(dr+dg+db+da);
+ }
+
+ pBytes += ddsd.lPitch;
+ }
+
+ pddsTempSurface->Unlock(0);
+
+ // Copy the temp surface to the real texture surface
+ m_pddsSurface->Blt( NULL, pddsTempSurface, NULL, DDBLT_WAIT, NULL );
+
+ // Done with the temp objects
+ pddsTempSurface->Release();
+ pDD->Release();
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_SetTexturePath()
+// Desc: Enumeration callback routine to find a best-matching texture format.
+//-----------------------------------------------------------------------------
+VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath )
+{
+ if( NULL == strTexturePath )
+ strTexturePath = _T("");
+ lstrcpy( g_strTexturePath, strTexturePath );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_CreateTextureFromFile()
+// Desc: Is passed a filename and creates a local Bitmap from that file.
+// The texture can not be used until it is restored, however.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage,
+ DWORD dwFlags )
+{
+ // Check parameters
+ if( NULL == strName )
+ return E_INVALIDARG;
+
+ // Check first to see if the texture is already loaded
+ if( NULL != FindTexture( strName ) )
+ return S_OK;
+
+ // Allocate and add the texture to the linked list of textures;
+ TextureContainer* ptcTexture = new TextureContainer( strName, dwStage,
+ dwFlags );
+ if( NULL == ptcTexture )
+ return E_OUTOFMEMORY;
+
+ // Create a bitmap and load the texture file into it,
+ if( FAILED( ptcTexture->LoadImageData() ) )
+ {
+ delete ptcTexture;
+ return E_FAIL;
+ }
+
+ // Save the image's dimensions
+ if( ptcTexture->m_hbmBitmap )
+ {
+ BITMAP bm;
+ GetObject( ptcTexture->m_hbmBitmap, sizeof(BITMAP), &bm );
+ ptcTexture->m_dwWidth = (DWORD)bm.bmWidth;
+ ptcTexture->m_dwHeight = (DWORD)bm.bmHeight;
+ ptcTexture->m_dwBPP = (DWORD)bm.bmBitsPixel;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_CreateEmptyTexture()
+// Desc: Creates an empty texture.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwStage,
+ DWORD dwFlags )
+{
+ // Check parameters
+ if( NULL == strName )
+ return E_INVALIDARG;
+
+ // Check first to see if the texture is already loaded
+ if( NULL != FindTexture( strName ) )
+ return E_FAIL;
+
+ // Allocate and add the texture to the linked list of textures;
+ TextureContainer* ptcTexture = new TextureContainer( strName, dwStage,
+ dwFlags );
+ if( NULL == ptcTexture )
+ return E_OUTOFMEMORY;
+
+ // Save dimensions
+ ptcTexture->m_dwWidth = dwWidth;
+ ptcTexture->m_dwHeight = dwHeight;
+ ptcTexture->m_dwBPP = 16;
+ if( ptcTexture->m_dwFlags & D3DTEXTR_32BITSPERPIXEL )
+ ptcTexture->m_dwBPP = 32;
+
+ // Save alpha usage flag
+ if( dwFlags & D3DTEXTR_CREATEWITHALPHA )
+ ptcTexture->m_bHasAlpha = TRUE;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_Restore()
+// Desc: Invalidates the current texture objects and rebuilds new ones
+// using the new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+ if( NULL == ptcTexture )
+ return DDERR_NOTFOUND;
+
+ // Restore the texture (this recreates the new surface for this device).
+ return ptcTexture->Restore( pd3dDevice );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_RestoreAllTextures()
+// Desc: This function is called when a mode is changed. It updates all
+// texture objects to be valid with the new device.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice )
+{
+ TextureContainer* ptcTexture = g_ptcTextureList;
+
+ while( ptcTexture )
+ {
+ D3DTextr_Restore( ptcTexture->m_strName, pd3dDevice );
+ ptcTexture = ptcTexture->m_pNext;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_Invalidate()
+// Desc: Used to bump a texture out of (video) memory, this function
+// actually destroys the d3dtexture and ddsurface of the texture
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_Invalidate( TCHAR* strName )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+ if( NULL == ptcTexture )
+ return DDERR_NOTFOUND;
+
+ SAFE_RELEASE( ptcTexture->m_pddsSurface );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_InvalidateAllTextures()
+// Desc: This function is called when a mode is changed. It invalidates
+// all texture objects so their device can be safely released.
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_InvalidateAllTextures()
+{
+ TextureContainer* ptcTexture = g_ptcTextureList;
+
+ while( ptcTexture )
+ {
+ SAFE_RELEASE( ptcTexture->m_pddsSurface );
+ ptcTexture = ptcTexture->m_pNext;
+ }
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_DestroyTexture()
+// Desc: Frees the resources for the specified texture container
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_DestroyTexture( TCHAR* strName )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+
+ SAFE_DELETE( ptcTexture );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DTextr_GetSurface()
+// Desc: Returns a pointer to a d3dSurface from the name of the texture
+//-----------------------------------------------------------------------------
+LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName )
+{
+ TextureContainer* ptcTexture = FindTexture( strName );
+
+ return ptcTexture ? ptcTexture->m_pddsSurface : NULL;
+}
+
+
+
+
+
diff --git a/src/d3dtextr.h b/src/d3dtextr.h
new file mode 100644
index 0000000..72d4430
--- /dev/null
+++ b/src/d3dtextr.h
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------------
+// File: D3DTextr.h
+//
+// Desc: Functions to manage textures, including creating (loading from a
+// file), restoring lost surfaces, invalidating, and destroying.
+//
+// Note: the implementation of these fucntions maintain an internal list
+// of loaded textures. After creation, individual textures are referenced
+// via their ASCII names.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DTEXTR_H
+#define D3DTEXTR_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Access functions for loaded textures. Note: these functions search
+// an internal list of the textures, and use the texture associated with the
+// ASCII name.
+//-----------------------------------------------------------------------------
+LPDIRECTDRAWSURFACE7 D3DTextr_GetSurface( TCHAR* strName );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Texture invalidation and restoration functions
+//-----------------------------------------------------------------------------
+HRESULT D3DTextr_Invalidate( TCHAR* strName );
+HRESULT D3DTextr_Restore( TCHAR* strName, LPDIRECT3DDEVICE7 pd3dDevice );
+HRESULT D3DTextr_InvalidateAllTextures();
+HRESULT D3DTextr_RestoreAllTextures( LPDIRECT3DDEVICE7 pd3dDevice );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Texture creation and deletion functions
+//-----------------------------------------------------------------------------
+#define D3DTEXTR_TRANSPARENTWHITE 0x00000001
+#define D3DTEXTR_TRANSPARENTBLACK 0x00000002
+#define D3DTEXTR_32BITSPERPIXEL 0x00000004
+#define D3DTEXTR_16BITSPERPIXEL 0x00000008
+#define D3DTEXTR_CREATEWITHALPHA 0x00000010
+
+
+HRESULT D3DTextr_CreateTextureFromFile( TCHAR* strName, DWORD dwStage=0L,
+ DWORD dwFlags=0L );
+HRESULT D3DTextr_CreateEmptyTexture( TCHAR* strName, DWORD dwWidth,
+ DWORD dwHeight, DWORD dwStage,
+ DWORD dwFlags );
+HRESULT D3DTextr_DestroyTexture( TCHAR* strName );
+VOID D3DTextr_SetTexturePath( TCHAR* strTexturePath );
+
+void D3DTextr_SetDebugMode(BOOL bDebug);
+
+
+
+#endif // D3DTEXTR_H
diff --git a/src/d3dutil.cpp b/src/d3dutil.cpp
new file mode 100644
index 0000000..8362f9f
--- /dev/null
+++ b/src/d3dutil.cpp
@@ -0,0 +1,311 @@
+//-----------------------------------------------------------------------------
+// File: D3DUtil.cpp
+//
+// Desc: Shortcut macros and functions for using DX objects
+//
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#define D3D_OVERLOADS
+#define STRICT
+#include <math.h>
+#include <stdio.h>
+#include <tchar.h>
+#include "D3DUtil.h"
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_GetDXSDKMediaPath()
+// Desc: Returns the DirectX SDK media path, as stored in the system registry
+// during the SDK install.
+//-----------------------------------------------------------------------------
+const TCHAR* D3DUtil_GetDXSDKMediaPath()
+{
+ static TCHAR strNull[2] = _T("");
+ static TCHAR strPath[512];
+ HKEY key;
+ DWORD type, size = 512;
+
+ // Open the appropriate registry key
+ LONG result = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ _T("Software\\Microsoft\\DirectX"),
+ 0, KEY_READ, &key );
+ if( ERROR_SUCCESS != result )
+ return strNull;
+
+ result = RegQueryValueEx( key, _T("DXSDK Samples Path"), NULL,
+ &type, (BYTE*)strPath, &size );
+ RegCloseKey( key );
+
+ if( ERROR_SUCCESS != result )
+ return strNull;
+
+ lstrcat( strPath, _T("\\D3DIM\\Media\\") );
+
+ return strPath;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_InitSurfaceDesc()
+// Desc: Helper function called to build a DDSURFACEDESC2 structure,
+// typically before calling CreateSurface() or GetSurfaceDesc()
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags,
+ DWORD dwCaps )
+{
+ ZeroMemory( &ddsd, sizeof(ddsd) );
+ ddsd.dwSize = sizeof(ddsd);
+ ddsd.dwFlags = dwFlags;
+ ddsd.ddsCaps.dwCaps = dwCaps;
+ ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_InitMaterial()
+// Desc: Helper function called to build a D3DMATERIAL7 structure
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r, FLOAT g, FLOAT b,
+ FLOAT a )
+{
+ ZeroMemory( &mtrl, sizeof(D3DMATERIAL7) );
+ mtrl.dcvDiffuse.r = mtrl.dcvAmbient.r = r;
+ mtrl.dcvDiffuse.g = mtrl.dcvAmbient.g = g;
+ mtrl.dcvDiffuse.b = mtrl.dcvAmbient.b = b;
+ mtrl.dcvDiffuse.a = mtrl.dcvAmbient.a = a;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_InitLight()
+// Desc: Initializes a D3DLIGHT7 structure
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType,
+ FLOAT x, FLOAT y, FLOAT z )
+{
+ ZeroMemory( &light, sizeof(D3DLIGHT7) );
+ light.dltType = ltType;
+ light.dcvDiffuse.r = 1.0f;
+ light.dcvDiffuse.g = 1.0f;
+ light.dcvDiffuse.b = 1.0f;
+ light.dcvSpecular = light.dcvDiffuse;
+ light.dvPosition.x = light.dvDirection.x = x;
+ light.dvPosition.y = light.dvDirection.y = y;
+ light.dvPosition.z = light.dvDirection.z = z;
+ light.dvAttenuation0 = 1.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetViewMatrix()
+// Desc: Given an eye point, a lookat point, and an up vector, this
+// function builds a 4x4 view matrix.
+//-----------------------------------------------------------------------------
+HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom,
+ D3DVECTOR& vAt, D3DVECTOR& vWorldUp )
+{
+ // Get the z basis vector, which points straight ahead. This is the
+ // difference from the eyepoint to the lookat point.
+ D3DVECTOR vView = vAt - vFrom;
+
+ FLOAT fLength = Magnitude( vView );
+ if( fLength < 1e-6f )
+ return E_INVALIDARG;
+
+ // Normalize the z basis vector
+ vView /= fLength;
+
+ // Get the dot product, and calculate the projection of the z basis
+ // vector onto the up vector. The projection is the y basis vector.
+ FLOAT fDotProduct = DotProduct( vWorldUp, vView );
+
+ D3DVECTOR vUp = vWorldUp - fDotProduct * vView;
+
+ // If this vector has near-zero length because the input specified a
+ // bogus up vector, let's try a default up vector
+ if( 1e-6f > ( fLength = Magnitude( vUp ) ) )
+ {
+ vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView;
+
+ // If we still have near-zero length, resort to a different axis.
+ if( 1e-6f > ( fLength = Magnitude( vUp ) ) )
+ {
+ vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView;
+
+ if( 1e-6f > ( fLength = Magnitude( vUp ) ) )
+ return E_INVALIDARG;
+ }
+ }
+
+ // Normalize the y basis vector
+ vUp /= fLength;
+
+ // The x basis vector is found simply with the cross product of the y
+ // and z basis vectors
+ D3DVECTOR vRight = CrossProduct( vUp, vView );
+
+ // Start building the matrix. The first three rows contains the basis
+ // vectors used to rotate the view to point at the lookat point
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x;
+ mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y;
+ mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z;
+
+ // Do the translation values (rotations are still about the eyepoint)
+ mat._41 = - DotProduct( vFrom, vRight );
+ mat._42 = - DotProduct( vFrom, vUp );
+ mat._43 = - DotProduct( vFrom, vView );
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetProjectionMatrix()
+// Desc: Sets the passed in 4x4 matrix to a perpsective projection matrix built
+// from the field-of-view (fov, in y), aspect ratio, near plane (D),
+// and far plane (F). Note that the projection matrix is normalized for
+// element [3][4] to be 1.0. This is performed so that W-based range fog
+// will work correctly.
+//-----------------------------------------------------------------------------
+HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV, FLOAT fAspect,
+ FLOAT fNearPlane, FLOAT fFarPlane )
+{
+ if( fabs(fFarPlane-fNearPlane) < 0.01f )
+ return E_INVALIDARG;
+ if( fabs(sin(fFOV/2)) < 0.01f )
+ return E_INVALIDARG;
+
+ FLOAT w = fAspect * ( cosf(fFOV/2)/sinf(fFOV/2) );
+ FLOAT h = 1.0f * ( cosf(fFOV/2)/sinf(fFOV/2) );
+ FLOAT Q = fFarPlane / ( fFarPlane - fNearPlane );
+
+ ZeroMemory( &mat, sizeof(D3DMATRIX) );
+ mat._11 = w;
+ mat._22 = h;
+ mat._33 = Q;
+ mat._34 = 1.0f;
+ mat._43 = -Q*fNearPlane;
+
+ return S_OK;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotateXMatrix()
+// Desc: Create Rotation matrix about X axis
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads )
+{
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._22 = cosf( fRads );
+ mat._23 = sinf( fRads );
+ mat._32 = -sinf( fRads );
+ mat._33 = cosf( fRads );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotateYMatrix()
+// Desc: Create Rotation matrix about Y axis
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads )
+{
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._11 = cosf( fRads );
+ mat._13 = -sinf( fRads );
+ mat._31 = sinf( fRads );
+ mat._33 = cosf( fRads );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotateZMatrix()
+// Desc: Create Rotation matrix about Z axis
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads )
+{
+ D3DUtil_SetIdentityMatrix( mat );
+ mat._11 = cosf( fRads );
+ mat._12 = sinf( fRads );
+ mat._21 = -sinf( fRads );
+ mat._22 = cosf( fRads );
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: D3DUtil_SetRotationMatrix
+// Desc: Create a Rotation matrix about vector direction
+//-----------------------------------------------------------------------------
+VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir, FLOAT fRads )
+{
+ FLOAT fCos = cosf( fRads );
+ FLOAT fSin = sinf( fRads );
+ D3DVECTOR v = Normalize( vDir );
+
+ mat._11 = ( v.x * v.x ) * ( 1.0f - fCos ) + fCos;
+ mat._12 = ( v.x * v.y ) * ( 1.0f - fCos ) - (v.z * fSin);
+ mat._13 = ( v.x * v.z ) * ( 1.0f - fCos ) + (v.y * fSin);
+
+ mat._21 = ( v.y * v.x ) * ( 1.0f - fCos ) + (v.z * fSin);
+ mat._22 = ( v.y * v.y ) * ( 1.0f - fCos ) + fCos ;
+ mat._23 = ( v.y * v.z ) * ( 1.0f - fCos ) - (v.x * fSin);
+
+ mat._31 = ( v.z * v.x ) * ( 1.0f - fCos ) - (v.y * fSin);
+ mat._32 = ( v.z * v.y ) * ( 1.0f - fCos ) + (v.x * fSin);
+ mat._33 = ( v.z * v.z ) * ( 1.0f - fCos ) + fCos;
+
+ mat._14 = mat._24 = mat._34 = 0.0f;
+ mat._41 = mat._42 = mat._43 = 0.0f;
+ mat._44 = 1.0f;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Name: _DbgOut()
+// Desc: Outputs a message to the debug stream
+//-----------------------------------------------------------------------------
+HRESULT _DbgOut( TCHAR* strFile, DWORD dwLine, HRESULT hr, TCHAR* strMsg )
+{
+ TCHAR buffer[256];
+ wsprintf( buffer, _T("%s(%ld): "), strFile, dwLine );
+ OutputDebugString( buffer );
+ OutputDebugString( strMsg );
+
+ if( hr )
+ {
+ wsprintf( buffer, _T("(hr=%08lx)\n"), hr );
+ OutputDebugString( buffer );
+ }
+
+ OutputDebugString( _T("\n") );
+
+ return hr;
+}
+
+
+
diff --git a/src/d3dutil.h b/src/d3dutil.h
new file mode 100644
index 0000000..476f142
--- /dev/null
+++ b/src/d3dutil.h
@@ -0,0 +1,98 @@
+//-----------------------------------------------------------------------------
+// File: D3DUtil.h
+//
+// Desc: Helper functions and typing shortcuts for Direct3D programming.
+//
+// Copyright (c) 1997-1999 Microsoft Corporation. All rights reserved
+//-----------------------------------------------------------------------------
+#ifndef D3DUTIL_H
+#define D3DUTIL_H
+#include <ddraw.h>
+#include <d3d.h>
+
+
+
+
+//-----------------------------------------------------------------------------
+// Miscellaneous helper functions
+//-----------------------------------------------------------------------------
+const TCHAR* D3DUtil_GetDXSDKMediaPath();
+
+#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
+
+
+
+
+//-----------------------------------------------------------------------------
+// Short cut functions for creating and using DX structures
+//-----------------------------------------------------------------------------
+VOID D3DUtil_InitDeviceDesc( D3DDEVICEDESC7& ddDevDesc );
+VOID D3DUtil_InitSurfaceDesc( DDSURFACEDESC2& ddsd, DWORD dwFlags=0,
+ DWORD dwCaps=0 );
+VOID D3DUtil_InitMaterial( D3DMATERIAL7& mtrl, FLOAT r=0.0f, FLOAT g=0.0f,
+ FLOAT b=0.0f, FLOAT a=1.0f );
+VOID D3DUtil_InitLight( D3DLIGHT7& light, D3DLIGHTTYPE ltType,
+ FLOAT x=0.0f, FLOAT y=0.0f, FLOAT z=0.0f );
+
+
+
+
+//-----------------------------------------------------------------------------
+// D3D Matrix functions. For performance reasons, some functions are inline.
+//-----------------------------------------------------------------------------
+HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom,
+ D3DVECTOR& vAt, D3DVECTOR& vUp );
+HRESULT D3DUtil_SetProjectionMatrix( D3DMATRIX& mat, FLOAT fFOV = 1.570795f,
+ FLOAT fAspect = 1.0f,
+ FLOAT fNearPlane = 1.0f,
+ FLOAT fFarPlane = 1000.0f );
+
+inline VOID D3DUtil_SetIdentityMatrix( D3DMATRIX& m )
+{
+ m._12 = m._13 = m._14 = m._21 = m._23 = m._24 = 0.0f;
+ m._31 = m._32 = m._34 = m._41 = m._42 = m._43 = 0.0f;
+ m._11 = m._22 = m._33 = m._44 = 1.0f;
+}
+
+inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, FLOAT tx, FLOAT ty,
+ FLOAT tz )
+{ D3DUtil_SetIdentityMatrix( m ); m._41 = tx; m._42 = ty; m._43 = tz; }
+
+inline VOID D3DUtil_SetTranslateMatrix( D3DMATRIX& m, D3DVECTOR& v )
+{ D3DUtil_SetTranslateMatrix( m, v.x, v.y, v.z ); }
+
+inline VOID D3DUtil_SetScaleMatrix( D3DMATRIX& m, FLOAT sx, FLOAT sy,
+ FLOAT sz )
+{ D3DUtil_SetIdentityMatrix( m ); m._11 = sx; m._22 = sy; m._33 = sz; }
+
+inline VOID SetScaleMatrix( D3DMATRIX& m, D3DVECTOR& v )
+{ D3DUtil_SetScaleMatrix( m, v.x, v.y, v.z ); }
+
+VOID D3DUtil_SetRotateXMatrix( D3DMATRIX& mat, FLOAT fRads );
+VOID D3DUtil_SetRotateYMatrix( D3DMATRIX& mat, FLOAT fRads );
+VOID D3DUtil_SetRotateZMatrix( D3DMATRIX& mat, FLOAT fRads );
+VOID D3DUtil_SetRotationMatrix( D3DMATRIX& mat, D3DVECTOR& vDir,
+ FLOAT fRads );
+
+
+
+
+//-----------------------------------------------------------------------------
+// Debug printing support
+//-----------------------------------------------------------------------------
+
+HRESULT _DbgOut( TCHAR*, DWORD, HRESULT, TCHAR* );
+
+#if defined(DEBUG) | defined(_DEBUG)
+ #define DEBUG_MSG(str) _DbgOut( __FILE__, (DWORD)__LINE__, 0, str )
+ #define DEBUG_ERR(hr,str) _DbgOut( __FILE__, (DWORD)__LINE__, hr, str )
+#else
+ #define DEBUG_MSG(str) (0L)
+ #define DEBUG_ERR(hr,str) (hr)
+#endif
+
+
+
+
+#endif // D3DUTIL_H
diff --git a/src/dd.cpp b/src/dd.cpp
new file mode 100644
index 0000000..6e3dc10
--- /dev/null
+++ b/src/dd.cpp
@@ -0,0 +1,159 @@
+// Compilation d'une procédure avec un "point".
+
+int cPoint(CBotVar* &var, CBotString& retClass, void* user)
+{
+ if ( var == 0 ) return CBotErrLowParam;
+
+ if ( var->GivType() <= CBotTypDouble )
+ {
+ var = var->GivNext();
+ if ( var == 0 ) return CBotErrLowParam;
+ if ( var->GivType() > CBotTypDouble ) return CBotErrBadNum;
+ var = var->GivNext();
+ if ( var == 0 ) return CBotErrLowParam;
+ if ( var->GivType() > CBotTypDouble ) return CBotErrBadNum;
+ var = var->GivNext();
+ return 0;
+ }
+
+ if ( var->GivType() == CBotTypClass )
+ {
+ if ( !var->IsElemOfClass("point") ) return CBotErrBadParam;
+ var = var->GivNext();
+ return 0;
+ }
+
+ return CBotErrBadParam;
+}
+
+// Donne un paramètre de type "point".
+
+BOOL GetPoint(CBotVar* &var, int& exception, D3DVECTOR& pos)
+{
+ CBotVar *pX, *pY, *pZ;
+
+ if ( var->GivType() <= CBotTypDouble )
+ {
+ pos.x = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+
+ pos.z = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+
+ pos.y = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+ }
+ else
+ {
+ pX = var->GivItem("x");
+ if ( pX == NULL )
+ {
+ exception = CBotErrUndefItem; return TRUE;
+ }
+ pos.x = pX->GivValFloat()*UNIT;
+
+ pY = var->GivItem("y");
+ if ( pY == NULL )
+ {
+ exception = CBotErrUndefItem; return TRUE;
+ }
+ pos.z = pY->GivValFloat()*UNIT; // attention y -> z !
+
+ pZ = var->GivItem("z");
+ if ( pZ == NULL )
+ {
+ exception = CBotErrUndefItem; return TRUE;
+ }
+ pos.y = pZ->GivValFloat()*UNIT; // attention z -> y !
+
+ var = var->GivNext();
+ }
+ return TRUE;
+}
+
+
+
+// Compilation de l'instruction "space(center, rMin, rMax, dist)".
+
+int cSpace(CBotVar* &var, CBotString& retClass, void* user)
+{
+ int ret;
+
+ retClass = "point";
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ ret = cPoint(var, retClass, user);
+ if ( ret != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ if ( var->GivType() > CBotTypDouble ) return CBotErrBadNum;
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ if ( var->GivType() > CBotTypDouble ) return CBotErrBadNum;
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypIntrinsic;
+ if ( var->GivType() > CBotTypDouble ) return CBotErrBadNum;
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotErrOverParam;
+ return CBotTypIntrinsic;
+}
+
+// Instruction "space(center, rMin, rMax, dist)".
+
+BOOL rSpace(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CBotVar* pSub;
+ D3DVECTOR center;
+ float rMin, rMax, dist;
+
+ rMin = 5.0f*UNIT;
+ rMax = 50.0f*UNIT;
+ dist = 4.0f*UNIT;
+
+ if ( var == 0 )
+ {
+ center = pThis->RetPosition(0);
+ }
+ else
+ {
+ if ( !GetPoint(var, exception, center) ) return TRUE;
+
+ if ( var != 0 )
+ {
+ rMin = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+
+ if ( var != 0 )
+ {
+ rMax = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+
+ if ( var != 0 )
+ {
+ dist = var->GivValFloat()*UNIT;
+ var = var->GivNext();
+ }
+ }
+ }
+ }
+ script->m_main->FreeSpace(center, rMin, rMax, dist, pThis);
+
+ if ( result != 0 )
+ {
+ pSub = result->GivItemList();
+ if ( pSub != 0 )
+ {
+ pSub->SetValFloat(center.x/UNIT);
+ pSub = pSub->GivNext(); // "y"
+ pSub->SetValFloat(center.z/UNIT);
+ pSub = pSub->GivNext(); // "z"
+ pSub->SetValFloat(center.y/UNIT);
+ }
+ }
+ return TRUE;
+}
diff --git a/src/displayinfo.cpp b/src/displayinfo.cpp
new file mode 100644
index 0000000..3adc5b8
--- /dev/null
+++ b/src/displayinfo.cpp
@@ -0,0 +1,1206 @@
+// displayinfo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "robotmain.h"
+#include "camera.h"
+#include "object.h"
+#include "motion.h"
+#include "motiontoto.h"
+#include "interface.h"
+#include "button.h"
+#include "slider.h"
+#include "edit.h"
+#include "group.h"
+#include "window.h"
+#include "particule.h"
+#include "light.h"
+#include "text.h"
+#include "cbottoken.h"
+#include "displayinfo.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CDisplayInfo::CDisplayInfo(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_STUDIO, this);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+
+ m_bInfoMaximized = TRUE;
+ m_bInfoMinimized = FALSE;
+
+ m_infoFinalPos = m_infoActualPos = m_infoNormalPos = FPOINT(0.00f, 0.00f);
+ m_infoFinalDim = m_infoActualPos = m_infoNormalDim = FPOINT(1.00f, 1.00f);
+
+ m_lightSuppl = -1;
+ m_toto = 0;
+}
+
+// Destructeur de l'objet.
+
+CDisplayInfo::~CDisplayInfo()
+{
+ m_iMan->DeleteInstance(CLASS_STUDIO, this);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CDisplayInfo::EventProcess(const Event &event)
+{
+ CWindow* pw;
+ CEdit* edit;
+ CSlider* slider;
+ CMotionToto* toto;
+
+ if ( event.event == EVENT_FRAME )
+ {
+ EventFrame(event);
+ HyperUpdate();
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ if ( m_toto != 0 )
+ {
+ toto = (CMotionToto*)m_toto->RetMotion();
+ if ( toto != 0 )
+ {
+ toto->SetMousePos(event.pos);
+ }
+ }
+ }
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 )
+ {
+ if ( event.event == pw->RetEventMsgClose() )
+ {
+ Event newEvent = event;
+ newEvent.event = EVENT_OBJECT_INFOOK;
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.event == EVENT_SATCOM_HUSTON )
+ {
+ ChangeIndexButton(SATCOM_HUSTON);
+ }
+ if ( event.event == EVENT_SATCOM_SAT )
+ {
+ ChangeIndexButton(SATCOM_SAT);
+ }
+//? if ( event.event == EVENT_SATCOM_OBJECT )
+//? {
+//? ChangeIndexButton(SATCOM_OBJECT);
+//? }
+ if ( event.event == EVENT_SATCOM_LOADING )
+ {
+ ChangeIndexButton(SATCOM_LOADING);
+ }
+ if ( event.event == EVENT_SATCOM_PROG )
+ {
+ ChangeIndexButton(SATCOM_PROG);
+ }
+ if ( event.event == EVENT_SATCOM_SOLUCE )
+ {
+ ChangeIndexButton(SATCOM_SOLUCE);
+ }
+
+ if ( event.event == EVENT_HYPER_HOME ||
+ event.event == EVENT_HYPER_PREV ||
+ event.event == EVENT_HYPER_NEXT )
+ {
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit != 0 )
+ {
+ edit->HyperGo(event.event);
+ HyperUpdate();
+ }
+ }
+
+ if ( event.event == EVENT_HYPER_SIZE1 ) // taille 1 ?
+ {
+ m_main->SetFontSize(9.0f);
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider != 0 ) slider->SetVisibleValue((m_main->RetFontSize()-9.0f)/6.0f);
+ ViewDisplayInfo();
+ }
+ if ( event.event == EVENT_HYPER_SIZE2 ) // taille 2 ?
+ {
+ m_main->SetFontSize(10.0f);
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider != 0 ) slider->SetVisibleValue((m_main->RetFontSize()-9.0f)/6.0f);
+ ViewDisplayInfo();
+ }
+ if ( event.event == EVENT_HYPER_SIZE3 ) // taille 3 ?
+ {
+ m_main->SetFontSize(12.0f);
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider != 0 ) slider->SetVisibleValue((m_main->RetFontSize()-9.0f)/6.0f);
+ ViewDisplayInfo();
+ }
+ if ( event.event == EVENT_HYPER_SIZE4 ) // taille 4 ?
+ {
+ m_main->SetFontSize(15.0f);
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider != 0 ) slider->SetVisibleValue((m_main->RetFontSize()-9.0f)/6.0f);
+ ViewDisplayInfo();
+ }
+
+ if ( event.event == EVENT_STUDIO_SIZE ) // taille ?
+ {
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider == 0 ) return FALSE;
+ m_main->SetFontSize(9.0f+slider->RetVisibleValue()*6.0f);
+ ViewDisplayInfo();
+ }
+
+ if ( event.event == EVENT_HYPER_COPY ) // copie ?
+ {
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit != 0 )
+ {
+ edit->Copy();
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN ||
+ event.event == EVENT_LBUTTONUP )
+ {
+ UpdateCopyButton();
+ }
+
+ if ( event.event == EVENT_WINDOW4 ) // fenêtre déplacée ?
+ {
+ m_infoNormalPos = m_infoActualPos = m_infoFinalPos = pw->RetPos();
+ m_infoNormalDim = m_infoActualDim = m_infoFinalDim = pw->RetDim();
+ AdjustDisplayInfo(m_infoActualPos, m_infoActualDim);
+ }
+ if ( event.event == pw->RetEventMsgReduce() )
+ {
+ if ( m_bInfoMinimized )
+ {
+ m_infoFinalPos = m_infoNormalPos;
+ m_infoFinalDim = m_infoNormalDim;
+ m_bInfoMinimized = FALSE;
+ m_bInfoMaximized = FALSE;
+ }
+ else
+ {
+ m_infoFinalPos.x = 0.00f;
+ m_infoFinalPos.y = -0.34f;
+ m_infoFinalDim.x = 1.00f;
+ m_infoFinalDim.y = 0.40f;
+ m_bInfoMinimized = TRUE;
+ m_bInfoMaximized = FALSE;
+ }
+//? m_main->SetEditFull(m_bInfoMaximized);
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 )
+ {
+ pw->SetMaximized(m_bInfoMaximized);
+ pw->SetMinimized(m_bInfoMinimized);
+ }
+ }
+ if ( event.event == pw->RetEventMsgFull() )
+ {
+ if ( m_bInfoMaximized )
+ {
+ m_infoFinalPos = m_infoNormalPos;
+ m_infoFinalDim = m_infoNormalDim;
+ m_bInfoMinimized = FALSE;
+ m_bInfoMaximized = FALSE;
+ }
+ else
+ {
+ m_infoFinalPos.x = 0.00f;
+ m_infoFinalPos.y = 0.00f;
+ m_infoFinalDim.x = 1.00f;
+ m_infoFinalDim.y = 1.00f;
+ m_bInfoMinimized = FALSE;
+ m_bInfoMaximized = TRUE;
+ }
+//? m_main->SetEditFull(m_bInfoMaximized);
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 )
+ {
+ pw->SetMaximized(m_bInfoMaximized);
+ pw->SetMinimized(m_bInfoMinimized);
+ }
+ }
+ }
+ return TRUE;
+}
+
+
+// Fait évoluer le cerveau selon le temps écoulé.
+
+BOOL CDisplayInfo::EventFrame(const Event &event)
+{
+ float time;
+
+ if ( m_infoFinalPos.x != m_infoActualPos.x ||
+ m_infoFinalPos.y != m_infoActualPos.y ||
+ m_infoFinalDim.x != m_infoActualDim.x ||
+ m_infoFinalDim.y != m_infoActualDim.y )
+ {
+ time = event.rTime*20.0f;
+ m_infoActualPos.x += (m_infoFinalPos.x-m_infoActualPos.x)*time;
+ m_infoActualPos.y += (m_infoFinalPos.y-m_infoActualPos.y)*time;
+ m_infoActualDim.x += (m_infoFinalDim.x-m_infoActualDim.x)*time;
+ m_infoActualDim.y += (m_infoFinalDim.y-m_infoActualDim.y)*time;
+ AdjustDisplayInfo(m_infoActualPos, m_infoActualDim);
+ }
+
+ return TRUE;
+}
+
+
+// Met à jour les boutons pour les liens hyper-texte.
+
+void CDisplayInfo::HyperUpdate()
+{
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+ BOOL bEnable;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit == 0 ) return;
+
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_HOME);
+ if ( button != 0 )
+ {
+ bEnable = edit->HyperTest(EVENT_HYPER_HOME);
+ button->SetState(STATE_ENABLE, bEnable);
+ }
+
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_PREV);
+ if ( button != 0 )
+ {
+ bEnable = edit->HyperTest(EVENT_HYPER_PREV);
+ button->SetState(STATE_ENABLE, bEnable);
+ }
+
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_NEXT);
+ if ( button != 0 )
+ {
+ bEnable = edit->HyperTest(EVENT_HYPER_NEXT);
+ button->SetState(STATE_ENABLE, bEnable);
+ }
+}
+
+
+// Début de l'affichage des informations.
+
+void CDisplayInfo::StartDisplayInfo(char *filename, int index, BOOL bSoluce)
+{
+ D3DLIGHT7 light;
+ FPOINT pos, dim;
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+ CSlider* slider;
+ CMotionToto* toto;
+
+ m_index = index;
+ m_bSoluce = bSoluce;
+
+//? CreateObjectsFile();
+
+ m_bEditLock = m_main->RetEditLock();
+ if ( m_bEditLock ) // édition programme en cours ?
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 )
+ {
+ pw->ClearState(STATE_ENABLE); // CStudio inactif
+ }
+ }
+
+ m_main->SetEditLock(TRUE, FALSE);
+ m_main->SetEditFull(FALSE);
+ m_bInitPause = m_engine->RetPause();
+ m_engine->SetPause(TRUE);
+ m_infoCamera = m_camera->RetType();
+ m_camera->SetType(CAMERA_INFO);
+
+ pos = m_infoActualPos = m_infoFinalPos;
+ dim = m_infoActualDim = m_infoFinalDim;
+ pw = m_interface->CreateWindows(pos, dim, 4, EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+//? pw->SetClosable(TRUE);
+//? GetResource(RES_TEXT, RT_DISINFO_TITLE, res);
+//? pw->SetName(res);
+//? pw->SetMinDim(FPOINT(0.56f, 0.40f));
+//? pw->SetMaximized(m_bInfoMaximized);
+//? pw->SetMinimized(m_bInfoMinimized);
+//? m_main->SetEditFull(m_bInfoMaximized);
+
+ edit = pw->CreateEdit(pos, dim, 0, EVENT_EDIT1);
+ if ( edit == 0 ) return;
+ edit->SetState(STATE_SHADOW);
+ edit->SetMultiFont(TRUE);
+ edit->SetMaxChar(10000);
+ edit->SetFontType(FONT_COLOBOT);
+ edit->SetSoluceMode(bSoluce);
+ edit->ReadText(filename);
+ edit->HyperHome(filename);
+ edit->SetEditCap(FALSE); // juste pour voir !
+ edit->SetHiliteCap(FALSE);
+ edit->SetFocus(TRUE);
+
+ ViewDisplayInfo();
+
+ button = pw->CreateButton(pos, dim, 128+57, EVENT_SATCOM_HUSTON);
+ button->SetState(STATE_SHADOW);
+#if _TEEN
+#if !_ENGLISH
+ button = pw->CreateButton(pos, dim, 46, EVENT_SATCOM_SAT);
+#endif
+#else
+ button = pw->CreateButton(pos, dim, 128+58, EVENT_SATCOM_SAT);
+#endif
+ button->SetState(STATE_SHADOW);
+//? button = pw->CreateButton(pos, dim, 128+59, EVENT_SATCOM_OBJECT);
+//? button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 53, EVENT_SATCOM_LOADING);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 128+60, EVENT_SATCOM_PROG);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 20, EVENT_SATCOM_SOLUCE);
+ button->SetState(STATE_SHADOW);
+
+ pw->CreateGroup(pos, dim, 18, EVENT_LABEL1); // flèche >
+ pw->CreateGroup(pos, dim, 19, EVENT_LABEL2); // sigle SatCom
+
+ button = pw->CreateButton(pos, dim, 55, EVENT_HYPER_PREV);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 48, EVENT_HYPER_NEXT);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 30, EVENT_HYPER_HOME);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 82, EVENT_HYPER_SIZE1);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 83, EVENT_HYPER_SIZE2);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 90, EVENT_HYPER_SIZE3);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 91, EVENT_HYPER_SIZE4);
+ button->SetState(STATE_SHADOW);
+ slider = pw->CreateSlider(pos, dim, 0, EVENT_STUDIO_SIZE);
+ slider->SetState(STATE_SHADOW);
+ slider->SetVisibleValue((m_main->RetFontSize()-9.0f)/6.0f);
+ button = pw->CreateButton(pos, dim, 61, EVENT_HYPER_COPY);
+ button->SetState(STATE_SHADOW);
+ HyperUpdate();
+
+ button = pw->CreateButton(pos, dim, -1, EVENT_OBJECT_INFOOK);
+ button->SetState(STATE_SHADOW);
+ button->SetState(STATE_SIMPLY);
+ button->SetState(STATE_DEFAULT);
+ pw->CreateGroup(pos, dim, 21, EVENT_LABEL3); // sigle stand-by
+
+ AdjustDisplayInfo(m_infoActualPos, m_infoActualDim);
+ UpdateIndexButton();
+
+ m_engine->SetDrawWorld(FALSE); // ne dessine rien sous l'interface
+ m_engine->SetDrawFront(TRUE); // dessine toto sur l'interface
+ m_particule->SetFrameUpdate(SH_WORLD, FALSE); // pause pour particules dans monde
+
+ m_toto = SearchToto();
+ if ( m_toto != 0 )
+ {
+ m_toto->SetDrawFront(TRUE);
+
+ toto = (CMotionToto*)m_toto->RetMotion();
+ if ( toto != 0 )
+ {
+ toto->StartDisplayInfo();
+ }
+ }
+
+ ZeroMemory(&light, sizeof(light));
+ light.dltType = D3DLIGHT_DIRECTIONAL;
+ light.dcvDiffuse.r = 1.0f;
+ light.dcvDiffuse.g = 1.0f;
+ light.dcvDiffuse.b = 1.0f;
+ light.dvDirection = D3DVECTOR(1.0f, 0.0f, 1.0f);
+ m_lightSuppl = m_light->CreateLight();
+ m_light->SetLight(m_lightSuppl, light);
+ m_light->SetLightExcluType(m_lightSuppl, TYPETERRAIN);
+}
+
+// Repositionne tous les contrôles d'édition.
+
+void CDisplayInfo::AdjustDisplayInfo(FPOINT wpos, FPOINT wdim)
+{
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+ CSlider* slider;
+ CGroup* group;
+ FPOINT pos, dim;
+
+ wpos.x = 50.0f/640.0f;
+ wpos.y = 30.0f/480.0f;
+ wdim.x = 540.0f/640.0f;
+ wdim.y = 420.0f/480.0f;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 )
+ {
+ pw->SetPos(wpos);
+ pw->SetDim(wdim);
+ wdim = pw->RetDim();
+ }
+
+ pos.x = (50.0f+10.0f)/640.0f;
+ pos.y = (30.0f+10.0f+24.0f+10.0f+324.0f-48.0f)/480.0f;
+ dim.x = 48.0f/640.0f;
+ dim.y = 48.0f/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_HUSTON);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.y -= (48.0f+4.0f)/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_SAT);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+//? pos.y -= (48.0f+4.0f)/480.0f;
+//? button = (CButton*)pw->SearchControl(EVENT_SATCOM_OBJECT);
+//? if ( button != 0 )
+//? {
+//? button->SetPos(pos);
+//? button->SetDim(dim);
+//? }
+ pos.y -= (48.0f+4.0f)/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_LOADING);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.y -= (48.0f+4.0f)/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_PROG);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.y -= (48.0f+4.0f)/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_SOLUCE);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+
+ pos.x = (50.0f+10.0f+5.0f)/640.0f;
+ pos.y = (30.0f+10.0f+4.0f)/480.0f;
+ dim.x = (48.0f-10.0f)/640.0f;
+ dim.y = 24.0f/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_OBJECT_INFOOK);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+
+ pos.x = (50.0f+10.0f+48.0f+10.0f)/640.0f;
+ pos.y = (30.0f+10.0f)/480.0f;
+ dim.x = 462.0f/640.0f;
+ dim.y = 358.0f/480.0f;
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit != 0 )
+ {
+ edit->SetPos(pos);
+ edit->SetDim(dim);
+ }
+
+ pos.x = (50.0f+10.0f+48.0f+10.0f)/640.0f;
+ pos.y = (30.0f+10.0f+358.0f+10.0f)/480.0f;
+ dim.x = 32.0f/640.0f;
+ dim.y = 32.0f/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_PREV);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x += 35.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_NEXT);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x += 35.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_HOME);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+
+ pos.x += 50.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_SIZE1);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x += 35.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_SIZE2);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x += 35.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_SIZE3);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x += 35.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_SIZE4);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x += 35.0f/640.0f;
+ dim.x = 18.0f/640.0f;
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider != 0 )
+ {
+ slider->SetPos(pos);
+ slider->SetDim(dim);
+ }
+ pos.x += 50.0f/640.0f;
+ dim.x = 32.0f/640.0f;
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_COPY);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+
+ pos.x = (50.0f+10.0f)/640.0f;
+ pos.y = (30.0f+10.0f+24.0f+10.0f+324.0f+6.0f)/480.0f;
+ dim.x = 48.0f/640.0f;
+ dim.y = 40.0f/480.0f;
+ group = (CGroup*)pw->SearchControl(EVENT_LABEL2); // sigle SatCom
+ if ( group != 0 )
+ {
+ group->SetPos(pos);
+ group->SetDim(dim);
+ }
+
+ pos.x = (50.0f+10.0f+14.0f)/640.0f;
+ pos.y = (30.0f+10.0f+6.0f)/480.0f;
+ dim.x = 20.0f/640.0f;
+ dim.y = 20.0f/480.0f;
+ group = (CGroup*)pw->SearchControl(EVENT_LABEL3); // sigle stand-by
+ if ( group != 0 )
+ {
+ group->SetPos(pos);
+ group->SetDim(dim);
+ }
+}
+
+// Change le bouton d'index.
+
+void CDisplayInfo::ChangeIndexButton(int index)
+{
+ CWindow* pw;
+ CEdit* edit;
+ char* filename;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+
+ if ( m_index != -1 )
+ {
+ m_main->SetDisplayInfoPosition(m_index, RetPosition());
+ }
+ m_index = index;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit != 0 )
+ {
+ filename = m_main->RetDisplayInfoName(m_index);
+ edit->ReadText(filename);
+ edit->HyperHome(filename);
+ SetPosition(m_main->RetDisplayInfoPosition(m_index));
+ }
+
+ UpdateIndexButton();
+}
+
+// Adapte les boutons d'index.
+
+void CDisplayInfo::UpdateIndexButton()
+{
+ CWindow* pw;
+ CButton* button;
+ CGroup* group;
+ CEdit* edit;
+ FPOINT pos, dim;
+ char* filename;
+ char* loading;
+
+ static int table[SATCOM_MAX] =
+ {
+ 0, // SATCOM_HUSTON
+ 1, // SATCOM_SAT
+ -1, // SATCOM_OBJECT
+ 2, // SATCOM_LOADING
+ 3, // SATCOM_PROG
+ 4, // SATCOM_SOLUCE
+ };
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_HUSTON);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_CHECK, m_index==SATCOM_HUSTON);
+ filename = m_main->RetDisplayInfoName(SATCOM_HUSTON);
+ button->SetState(STATE_VISIBLE, filename[0]!=0);
+ }
+
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_SAT);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_CHECK, m_index==SATCOM_SAT);
+ filename = m_main->RetDisplayInfoName(SATCOM_SAT);
+ button->SetState(STATE_VISIBLE, filename[0]!=0);
+ }
+
+//? button = (CButton*)pw->SearchControl(EVENT_SATCOM_OBJECT);
+//? if ( button != 0 )
+//? {
+//? button->SetState(STATE_CHECK, m_index==SATCOM_OBJECT);
+//? filename = m_main->RetDisplayInfoName(SATCOM_OBJECT);
+//? button->SetState(STATE_VISIBLE, filename[0]!=0);
+//? }
+
+ loading = 0;
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_LOADING);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_CHECK, m_index==SATCOM_LOADING);
+ loading = m_main->RetDisplayInfoName(SATCOM_LOADING);
+ button->SetState(STATE_VISIBLE, loading[0]!=0);
+ }
+
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_PROG);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_CHECK, m_index==SATCOM_PROG);
+ filename = m_main->RetDisplayInfoName(SATCOM_PROG);
+ button->SetState(STATE_VISIBLE, filename[0]!=0 && (m_index==SATCOM_LOADING||m_index==SATCOM_PROG||(loading!=0&&loading[0]==0)));
+ }
+
+ button = (CButton*)pw->SearchControl(EVENT_SATCOM_SOLUCE);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_CHECK, m_index==SATCOM_SOLUCE);
+ filename = m_main->RetDisplayInfoName(SATCOM_SOLUCE);
+ button->SetState(STATE_VISIBLE, filename[0]!=0 && m_bSoluce);
+ }
+
+ group = (CGroup*)pw->SearchControl(EVENT_LABEL1);
+ if ( group != 0 )
+ {
+ if ( m_index == -1 )
+ {
+ group->ClearState(STATE_VISIBLE);
+ }
+ else
+ {
+ group->SetState(STATE_VISIBLE);
+
+ pos.x = (50.0f+10.0f+48.0f-3.0f)/640.0f;
+ pos.y = (30.0f+10.0f+24.0f+10.0f+324.0f-48.0f-1.0f)/480.0f;
+ pos.y -= (48.0f+4.0f)/480.0f*table[m_index];
+ dim.x = 15.0f/640.0f;
+ dim.y = 48.0f/480.0f;
+ group->SetPos(pos);
+ group->SetDim(dim);
+ }
+ }
+
+#if 0
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_COPY);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_VISIBLE, m_index==SATCOM_LOADING);
+ }
+#endif
+
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit != 0 )
+ {
+//? edit->SetHiliteCap(m_index==SATCOM_LOADING);
+ edit->SetHiliteCap(TRUE);
+ }
+
+ UpdateCopyButton();
+}
+
+// Adapte le bouton de copie.
+
+void CDisplayInfo::UpdateCopyButton()
+{
+ CWindow* pw;
+ CButton* button;
+ CEdit* edit;
+ int c1, c2;
+
+//? if ( m_index != SATCOM_LOADING ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+
+ button = (CButton*)pw->SearchControl(EVENT_HYPER_COPY);
+ if ( button == 0 ) return;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit == 0 ) return;
+
+ edit->GetCursor(c1, c2);
+ button->SetState(STATE_ENABLE, c1!=c2);
+
+}
+
+// Fin de l'affichage des informations.
+
+void CDisplayInfo::StopDisplayInfo()
+{
+ CWindow* pw;
+ CMotionToto* toto;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+
+ m_interface->DeleteControl(EVENT_WINDOW4);
+
+ if ( m_bEditLock ) // édition programme en cours ?
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 )
+ {
+ pw->SetState(STATE_ENABLE); // CStudio opérationnel
+ }
+ }
+ else
+ {
+ if ( !m_bInitPause ) m_engine->SetPause(FALSE);
+ m_main->SetEditLock(FALSE, FALSE);
+ }
+ m_camera->SetType(m_infoCamera);
+
+ m_engine->SetDrawWorld(TRUE); // dessine tout sous l'interface
+ m_engine->SetDrawFront(FALSE); // ne dessine rien sur l'interface
+ m_particule->SetFrameUpdate(SH_WORLD, TRUE);
+ m_particule->FlushParticule(SH_FRONT);
+ m_particule->FlushParticule(SH_INTERFACE);
+
+ if ( m_toto != 0 )
+ {
+ toto = (CMotionToto*)m_toto->RetMotion();
+ if ( toto != 0 )
+ {
+ toto->StopDisplayInfo();
+ }
+ }
+
+ m_light->DeleteLight(m_lightSuppl);
+ m_lightSuppl = -1;
+}
+
+
+// Spécifie la position.
+
+void CDisplayInfo::SetPosition(int pos)
+{
+ CWindow* pw;
+ CEdit* edit;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit == 0 ) return;
+
+ edit->SetFirstLine(pos);
+}
+
+// Retourne la position.
+
+int CDisplayInfo::RetPosition()
+{
+ CWindow* pw;
+ CEdit* edit;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return 0;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit == 0 ) return 0;
+
+ return edit->RetFirstLine();
+}
+
+
+
+// Changement de la taille de l'affichage des informations.
+
+void CDisplayInfo::ViewDisplayInfo()
+{
+ CWindow* pw;
+ CEdit* edit;
+ POINT dim;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw == 0 ) return;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_EDIT1);
+ if ( edit == 0 ) return;
+
+ dim = m_engine->RetDim();
+ edit->SetFontSize(m_main->RetFontSize()/(dim.x/640.0f));
+}
+
+// Retourne l'objet de l'homme.
+
+CObject* CDisplayInfo::SearchToto()
+{
+ ObjectType type;
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_TOTO )
+ {
+ return pObj;
+ }
+ }
+ return 0;
+}
+
+
+// Création de la liste des objets.
+
+typedef struct
+{
+ int total;
+ ObjectType type;
+}
+ObjectList;
+
+void ObjectAdd(ObjectList list[], ObjectType type)
+{
+ int i;
+
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( list[i].total == 0 )
+ {
+ list[i].total ++;
+ list[i].type = type;
+ list[i+1].total = 0;
+ return;
+ }
+ if ( list[i].type == type )
+ {
+ list[i].total ++;
+ return;
+ }
+ }
+}
+
+void ObjectWrite(FILE* file, ObjectList list[], int i)
+{
+ char line[100];
+ char res[100];
+ char* p;
+
+ if ( list[i].total < 10 )
+ {
+ sprintf(line, "\\c; %dx \\n;\\l;", list[i].total);
+ }
+ else
+ {
+ sprintf(line, "\\c;%dx \\n;\\l;", list[i].total);
+ }
+
+ GetResource(RES_OBJECT, list[i].type, res);
+ if ( res[0] == 0 ) return;
+ strcat(line, res);
+
+ strcat(line, "\\u ");
+ p = RetHelpFilename(list[i].type);
+ if ( p[0] == 0 ) return;
+ strcat(line, p+5); // skip "help\"
+ p = strstr(line, ".txt");
+ if ( p != 0 ) *p = 0;
+ strcat(line, ";\n");
+ fputs(line, file);
+}
+
+// Crée le fichier contenant la liste des objets.
+
+void CDisplayInfo::CreateObjectsFile()
+{
+ FILE* file;
+ CObject* pObj;
+ ObjectType type;
+ ObjectList list[200];
+ char line[100];
+ int i;
+ BOOL bRadar, bAtLeast;
+
+ file = fopen("help\\objects.txt", "w");
+ if ( file == 0 ) return;
+
+ list[0].total = 0; // vide la liste
+ bRadar = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( !pObj->RetSelectable() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_NULL ) continue;
+ if ( type == OBJECT_FIX ) continue;
+
+ ObjectAdd(list, type);
+
+ if ( type == OBJECT_RADAR ) bRadar = TRUE;
+ }
+
+ if ( bRadar )
+ {
+ GetResource(RES_TEXT, RT_SATCOM_LIST, line);
+ fputs(line, file);
+ bAtLeast = FALSE;
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( list[i].total == 0 ) break; // fin de la liste ?
+
+ if ( list[i].type == OBJECT_BASE ||
+ list[i].type == OBJECT_HUMAN )
+ {
+ ObjectWrite(file, list, i);
+ bAtLeast = TRUE;
+ }
+ }
+ if ( !bAtLeast )
+ {
+ GetResource(RES_TEXT, RT_SATCOM_NULL, line);
+ fputs(line, file);
+ }
+
+ strcpy(line, "\n");
+ fputs(line, file);
+ GetResource(RES_TEXT, RT_SATCOM_BOT, line);
+ fputs(line, file);
+ bAtLeast = FALSE;
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( list[i].total == 0 ) break; // fin de la liste ?
+
+ if ( list[i].type == OBJECT_MOBILEwt ||
+ list[i].type == OBJECT_MOBILEtt ||
+ list[i].type == OBJECT_MOBILEft ||
+ list[i].type == OBJECT_MOBILEit ||
+ list[i].type == OBJECT_MOBILEwa ||
+ list[i].type == OBJECT_MOBILEta ||
+ list[i].type == OBJECT_MOBILEfa ||
+ list[i].type == OBJECT_MOBILEia ||
+ list[i].type == OBJECT_MOBILEwc ||
+ list[i].type == OBJECT_MOBILEtc ||
+ list[i].type == OBJECT_MOBILEfc ||
+ list[i].type == OBJECT_MOBILEic ||
+ list[i].type == OBJECT_MOBILEwi ||
+ list[i].type == OBJECT_MOBILEti ||
+ list[i].type == OBJECT_MOBILEfi ||
+ list[i].type == OBJECT_MOBILEii ||
+ list[i].type == OBJECT_MOBILEws ||
+ list[i].type == OBJECT_MOBILEts ||
+ list[i].type == OBJECT_MOBILEfs ||
+ list[i].type == OBJECT_MOBILEis ||
+ list[i].type == OBJECT_MOBILErt ||
+ list[i].type == OBJECT_MOBILErc ||
+ list[i].type == OBJECT_MOBILErr ||
+ list[i].type == OBJECT_MOBILErs ||
+ list[i].type == OBJECT_MOBILEsa ||
+ list[i].type == OBJECT_MOBILEtg ||
+ list[i].type == OBJECT_MOBILEdr )
+ {
+ ObjectWrite(file, list, i);
+ bAtLeast = TRUE;
+ }
+ }
+ if ( !bAtLeast )
+ {
+ GetResource(RES_TEXT, RT_SATCOM_NULL, line);
+ fputs(line, file);
+ }
+
+ strcpy(line, "\n");
+ fputs(line, file);
+ GetResource(RES_TEXT, RT_SATCOM_BUILDING, line);
+ fputs(line, file);
+ bAtLeast = FALSE;
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( list[i].total == 0 ) break; // fin de la liste ?
+
+ if ( list[i].type == OBJECT_DERRICK ||
+ list[i].type == OBJECT_FACTORY ||
+ list[i].type == OBJECT_STATION ||
+ list[i].type == OBJECT_CONVERT ||
+ list[i].type == OBJECT_REPAIR ||
+ list[i].type == OBJECT_DESTROYER||
+ list[i].type == OBJECT_TOWER ||
+ list[i].type == OBJECT_NEST ||
+ list[i].type == OBJECT_RESEARCH ||
+ list[i].type == OBJECT_RADAR ||
+ list[i].type == OBJECT_ENERGY ||
+ list[i].type == OBJECT_LABO ||
+ list[i].type == OBJECT_NUCLEAR ||
+ list[i].type == OBJECT_START ||
+ list[i].type == OBJECT_END ||
+ list[i].type == OBJECT_INFO ||
+ list[i].type == OBJECT_PARA ||
+ list[i].type == OBJECT_TARGET1 ||
+ list[i].type == OBJECT_TARGET2 ||
+ list[i].type == OBJECT_SAFE ||
+ list[i].type == OBJECT_HUSTON )
+ {
+ ObjectWrite(file, list, i);
+ bAtLeast = TRUE;
+ }
+ }
+ if ( !bAtLeast )
+ {
+ GetResource(RES_TEXT, RT_SATCOM_NULL, line);
+ fputs(line, file);
+ }
+
+ strcpy(line, "\n");
+ fputs(line, file);
+ GetResource(RES_TEXT, RT_SATCOM_FRET, line);
+ fputs(line, file);
+ bAtLeast = FALSE;
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( list[i].total == 0 ) break; // fin de la liste ?
+
+ if ( list[i].type == OBJECT_STONE ||
+ list[i].type == OBJECT_URANIUM ||
+ list[i].type == OBJECT_METAL ||
+ list[i].type == OBJECT_POWER ||
+ list[i].type == OBJECT_ATOMIC ||
+ list[i].type == OBJECT_BULLET ||
+ list[i].type == OBJECT_BBOX ||
+ list[i].type == OBJECT_TNT )
+ {
+ ObjectWrite(file, list, i);
+ bAtLeast = TRUE;
+ }
+ }
+ if ( !bAtLeast )
+ {
+ GetResource(RES_TEXT, RT_SATCOM_NULL, line);
+ fputs(line, file);
+ }
+
+ strcpy(line, "\n");
+ fputs(line, file);
+ GetResource(RES_TEXT, RT_SATCOM_ALIEN, line);
+ fputs(line, file);
+ bAtLeast = FALSE;
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( list[i].total == 0 ) break; // fin de la liste ?
+
+ if ( list[i].type == OBJECT_MOTHER ||
+ list[i].type == OBJECT_ANT ||
+ list[i].type == OBJECT_BEE ||
+ list[i].type == OBJECT_WORM ||
+ list[i].type == OBJECT_SPIDER )
+ {
+ ObjectWrite(file, list, i);
+ bAtLeast = TRUE;
+ }
+ }
+ if ( !bAtLeast )
+ {
+ GetResource(RES_TEXT, RT_SATCOM_NULL, line);
+ fputs(line, file);
+ }
+ }
+ else
+ {
+ GetResource(RES_TEXT, RT_SATCOM_ERROR1, line);
+ fputs(line, file);
+ GetResource(RES_TEXT, RT_SATCOM_ERROR2, line);
+ fputs(line, file);
+ }
+
+ strcpy(line, "\n");
+ fputs(line, file);
+
+ fclose(file);
+}
+
+
diff --git a/src/displayinfo.h b/src/displayinfo.h
new file mode 100644
index 0000000..88f3721
--- /dev/null
+++ b/src/displayinfo.h
@@ -0,0 +1,72 @@
+// displayinfo.h
+
+#ifndef _DISPLAYINFO_H_
+#define _DISPLAYINFO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CEvent;
+class CRobotMain;
+class CCamera;
+class CInterface;
+class CObject;
+class CParticule;
+class CLight;
+
+
+class CDisplayInfo
+{
+public:
+ CDisplayInfo(CInstanceManager* iMan);
+ ~CDisplayInfo();
+
+ BOOL EventProcess(const Event &event);
+
+ void StartDisplayInfo(char *filename, int index, BOOL bSoluce);
+ void StopDisplayInfo();
+
+ void SetPosition(int pos);
+ int RetPosition();
+
+protected:
+ BOOL EventFrame(const Event &event);
+ void HyperUpdate();
+ void AdjustDisplayInfo(FPOINT wpos, FPOINT wdim);
+ void ChangeIndexButton(int index);
+ void UpdateIndexButton();
+ void UpdateCopyButton();
+ void ViewDisplayInfo();
+ CObject* SearchToto();
+ void CreateObjectsFile();
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CEvent* m_event;
+ CRobotMain* m_main;
+ CCamera* m_camera;
+ CInterface* m_interface;
+ CParticule* m_particule;
+ CLight* m_light;
+
+ BOOL m_bInfoMaximized;
+ BOOL m_bInfoMinimized;
+
+ int m_index;
+ CameraType m_infoCamera;
+ FPOINT m_infoNormalPos;
+ FPOINT m_infoNormalDim;
+ FPOINT m_infoActualPos;
+ FPOINT m_infoActualDim;
+ FPOINT m_infoFinalPos;
+ FPOINT m_infoFinalDim;
+ int m_lightSuppl;
+ BOOL m_bEditLock;
+ BOOL m_bInitPause;
+ BOOL m_bSoluce;
+ CObject* m_toto;
+};
+
+
+#endif //_DISPLAYINFO_H_
diff --git a/src/displaytext.cpp b/src/displaytext.cpp
new file mode 100644
index 0000000..f9c6312
--- /dev/null
+++ b/src/displaytext.cpp
@@ -0,0 +1,599 @@
+// displaytext.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "event.h"
+#include "misc.h"
+#include "restext.h"
+#include "iman.h"
+#include "object.h"
+#include "motion.h"
+#include "motiontoto.h"
+#include "interface.h"
+#include "button.h"
+#include "label.h"
+#include "window.h"
+#include "group.h"
+#include "text.h"
+#include "sound.h"
+#include "displaytext.h"
+
+
+
+#define FONTSIZE 12.0f
+
+
+
+// Constructeur de l'objet.
+
+CDisplayText::CDisplayText(CInstanceManager* iMan)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_DISPLAYTEXT, this);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ for ( i=0 ; i<MAXDTLINE ; i++ )
+ {
+ m_bExist[i] = FALSE;
+ m_visitGoal[i] = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_visitDist[i] = 0.0f;
+ m_visitHeight[i] = 0.0f;
+ m_time[i] = 0.0f; // rien d'affiché
+ }
+
+ m_bHide = FALSE;
+ m_bEnable = TRUE;
+ m_delayFactor = 1.0f;
+}
+
+// Destructeur de l'objet.
+
+CDisplayText::~CDisplayText()
+{
+ m_iMan->DeleteInstance(CLASS_DISPLAYTEXT, this);
+}
+
+
+// Détruit l'objet.
+
+void CDisplayText::DeleteObject()
+{
+ m_interface->DeleteControl(EVENT_WINDOW2);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CDisplayText::EventProcess(const Event &event)
+{
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ if ( event.event == EVENT_FRAME )
+ {
+ for ( i=0 ; i<MAXDTLINE ; i++ )
+ {
+ if ( !m_bExist[i] ) break;
+ m_time[i] -= event.rTime;
+ }
+ while ( TRUE )
+ {
+ if ( !m_bExist[0] ||
+ m_time[0] > 0.0f ) break;
+ if ( !ClearLastText() ) break;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Affiche une erreur.
+
+void CDisplayText::DisplayError(Error err, CObject* pObj, float time)
+{
+ D3DVECTOR pos;
+ float h, d;
+
+ if ( pObj == 0 ) return;
+
+ pos = pObj->RetPosition(0);
+ h = RetIdealHeight(pObj);
+ d = RetIdealDist(pObj);
+ DisplayError(err, pos, h, d, time);
+}
+
+// Affiche une erreur.
+
+void CDisplayText::DisplayError(Error err, D3DVECTOR goal, float height,
+ float dist, float time)
+{
+ TextType type;
+ char text[100];
+
+ if ( err == ERR_OK ) return;
+
+#if 0
+ type = TT_INFO;
+ if ( err < INFO_FIRST )
+ {
+ type = TT_ERROR;
+ }
+ if ( err == ERR_TOWER_POWER ||
+ err == ERR_RESEARCH_POWER ||
+ err == ERR_ENERGY_EMPTY ||
+ err == ERR_LABO_NULL ||
+ err == ERR_NUCLEAR_EMPTY ||
+ err == ERR_CONVERT_EMPTY )
+ {
+ type = TT_WARNING;
+ }
+#else
+ type = TT_WARNING;
+ if ( err >= INFO_FIRST )
+ {
+ type = TT_INFO;
+ }
+ if ( err == ERR_BAT_VIRUS ||
+ err == ERR_VEH_VIRUS ||
+ err == ERR_DELETEMOBILE ||
+ err == ERR_DELETEBUILDING ||
+ err == ERR_TOOMANY ||
+ err == INFO_LOST )
+ {
+ type = TT_ERROR;
+ }
+#endif
+
+ GetResource(RES_ERR, err, text);
+ DisplayText(text, goal, height, dist, time, type);
+}
+
+// Affiche le texte.
+
+void CDisplayText::DisplayText(char *text, CObject* pObj,
+ float time, TextType type)
+{
+ D3DVECTOR pos;
+ float h, d;
+
+ if ( pObj == 0 ) return;
+
+ pos = pObj->RetPosition(0);
+ h = RetIdealHeight(pObj);
+ d = RetIdealDist(pObj);
+ DisplayText(text, pos, h, d, time, type);
+}
+
+// Affiche le texte.
+
+void CDisplayText::DisplayText(char *text, D3DVECTOR goal, float height,
+ float dist, float time, TextType type)
+{
+ CObject* toto;
+ CMotion* motion;
+ CWindow* pw;
+ CButton* button;
+ CGroup* group;
+ CLabel* label;
+ FPOINT pos, ppos, dim;
+ Sound sound;
+ float hLine, hBox;
+ int nLine, icon, i;
+
+ if ( !m_bEnable ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 )
+ {
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ dim.x = 0.0f;
+ dim.y = 0.0f;
+ pw = m_interface->CreateWindows(pos, dim, 10, EVENT_WINDOW2);
+ }
+
+ hBox = 0.045f;
+ hLine = m_engine->RetText()->RetHeight(FONTSIZE, FONT_COLOBOT);
+
+ nLine = 0;
+ for ( i=0 ; i<MAXDTLINE ; i++ )
+ {
+ group = (CGroup*)pw->SearchControl(EventMsg(EVENT_DT_GROUP0+i));
+ if ( group == 0 ) break;
+ nLine ++;
+ }
+
+ if ( nLine == MAXDTLINE )
+ {
+ ClearLastText();
+ nLine --;
+ }
+
+ pos.x = 0.10f;
+ pos.y = 0.92f-hBox-hBox*nLine;
+ dim.x = 0.80f;
+ dim.y = hBox;
+
+ icon = 1; // jaune
+ if ( type == TT_ERROR ) icon = 9; // rouge
+ if ( type == TT_WARNING ) icon = 10; // bleu
+ if ( type == TT_INFO ) icon = 8; // vert
+ if ( type == TT_MESSAGE ) icon = 11; // jaune
+ pw->CreateGroup(pos, dim, icon, EventMsg(EVENT_DT_GROUP0+nLine));
+
+ pw->SetTrashEvent(FALSE);
+
+ ppos = pos;
+ ppos.y -= hLine/2.0f;
+ label = pw->CreateLabel(ppos, dim, -1, EventMsg(EVENT_DT_LABEL0+nLine), text);
+ if ( label != 0 )
+ {
+ label->SetFontSize(FONTSIZE);
+ }
+
+ dim.x = dim.y*0.75f;
+ pos.x -= dim.x;
+ button = pw->CreateButton(pos, dim, 14, EventMsg(EVENT_DT_VISIT0+nLine));
+
+ if ( goal.x == 0.0f &&
+ goal.y == 0.0f &&
+ goal.z == 0.0f )
+ {
+ button->ClearState(STATE_ENABLE);
+ }
+
+ m_bExist[nLine] = TRUE;
+ m_visitGoal[nLine] = goal;
+ m_visitDist[nLine] = dist;
+ m_visitHeight[nLine] = height;
+ m_time[nLine] = time*m_delayFactor;
+
+ toto = SearchToto();
+ if ( toto != 0 )
+ {
+ motion = toto->RetMotion();
+ if ( motion != 0 )
+ {
+ if ( type == TT_ERROR )
+ {
+ motion->SetAction(MT_ERROR, 4.0f);
+ }
+ if ( type == TT_WARNING )
+ {
+ motion->SetAction(MT_WARNING, 4.0f);
+ }
+ if ( type == TT_INFO )
+ {
+ motion->SetAction(MT_INFO, 4.0f);
+ }
+ if ( type == TT_MESSAGE )
+ {
+ motion->SetAction(MT_MESSAGE, 4.0f);
+ }
+ }
+ }
+
+ if ( m_bHide )
+ {
+ HideText(m_bHide); // cache tout
+ }
+ else
+ {
+ sound = SOUND_CLICK;
+ if ( type == TT_ERROR ) sound = SOUND_ERROR;
+ if ( type == TT_WARNING ) sound = SOUND_WARNING;
+ if ( type == TT_INFO ) sound = SOUND_INFO;
+ if ( type == TT_MESSAGE ) sound = SOUND_MESSAGE;
+
+ if ( sound != SOUND_CLICK )
+ {
+ m_sound->Play(sound);
+ }
+ }
+}
+
+// Efface tous les textes.
+
+void CDisplayText::ClearText()
+{
+ CWindow* pw;
+ int i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+
+ for ( i=0 ; i<MAXDTLINE ; i++ )
+ {
+ if ( pw != 0 )
+ {
+ pw->DeleteControl(EventMsg(EVENT_DT_GROUP0+i));
+ pw->DeleteControl(EventMsg(EVENT_DT_LABEL0+i));
+ pw->DeleteControl(EventMsg(EVENT_DT_VISIT0+i));
+ }
+ m_bExist[i] = FALSE;
+ m_visitGoal[i] = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_visitDist[i] = 0.0f;
+ m_visitHeight[i] = 0.0f;
+ m_time[i] = 0.0f;
+ }
+}
+
+// Cache ou montre tous les textes.
+
+void CDisplayText::HideText(BOOL bHide)
+{
+ CWindow* pw;
+ CGroup* pg;
+ CLabel* pl;
+ CButton* pb;
+ int i;
+
+ m_bHide = bHide;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 ) return;
+
+ for ( i=0 ; i<MAXDTLINE ; i++ )
+ {
+ pg = (CGroup*)pw->SearchControl(EventMsg(EVENT_DT_GROUP0+i));
+ if ( pg != 0 )
+ {
+ pg->SetState(STATE_VISIBLE, !bHide);
+ }
+
+ pl = (CLabel* )pw->SearchControl(EventMsg(EVENT_DT_LABEL0+i));
+ if ( pl != 0 )
+ {
+ pl->SetState(STATE_VISIBLE, !bHide);
+ }
+
+ pb = (CButton*)pw->SearchControl(EventMsg(EVENT_DT_VISIT0+i));
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_VISIBLE, !bHide);
+ }
+ }
+}
+
+// Efface le dernier texte (en haut de la liste).
+
+BOOL CDisplayText::ClearLastText()
+{
+ CWindow *pw;
+ CButton *pb1, *pb2;
+ CGroup *pg1, *pg2;
+ CLabel *pl1, *pl2;
+ int i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 ) return FALSE;
+
+ pb2 = (CButton*)pw->SearchControl(EVENT_DT_VISIT0);
+ if ( pb2 == 0 ) return FALSE; // même pas de première ligne
+ pg2 = (CGroup*)pw->SearchControl(EVENT_DT_GROUP0);
+ if ( pg2 == 0 ) return FALSE;
+ pl2 = (CLabel*)pw->SearchControl(EVENT_DT_LABEL0);
+ if ( pl2 == 0 ) return FALSE;
+
+ for ( i=0 ; i<MAXDTLINE-1 ; i++ )
+ {
+ pb1 = pb2;
+ pg1 = pg2;
+ pl1 = pl2;
+
+ pb2 = (CButton*)pw->SearchControl(EventMsg(EVENT_DT_VISIT0+i+1));
+ if ( pb2 == 0 ) break;
+
+ pg2 = (CGroup*)pw->SearchControl(EventMsg(EVENT_DT_GROUP0+i+1));
+ if ( pg2 == 0 ) break;
+
+ pl2 = (CLabel*)pw->SearchControl(EventMsg(EVENT_DT_LABEL0+i+1));
+ if ( pl2 == 0 ) break;
+
+ pb1->SetState(STATE_ENABLE, pb2->TestState(STATE_ENABLE));
+ pg1->SetIcon(pg2->RetIcon());
+ pl1->SetName(pl2->RetName());
+
+ m_time[i] = m_time[i+1];
+ m_visitGoal[i] = m_visitGoal[i+1];
+ m_visitDist[i] = m_visitDist[i+1];
+ m_visitHeight[i] = m_visitHeight[i+1]; // shift
+ }
+
+ pw->DeleteControl(EventMsg(EVENT_DT_VISIT0+i));
+ pw->DeleteControl(EventMsg(EVENT_DT_GROUP0+i));
+ pw->DeleteControl(EventMsg(EVENT_DT_LABEL0+i));
+ m_bExist[i] = FALSE;
+ return TRUE;
+}
+
+
+// Spécifie le facteur du délai.
+
+void CDisplayText::SetDelay(float factor)
+{
+ m_delayFactor = factor;
+}
+
+
+// Active l'affichage des textes.
+
+void CDisplayText::SetEnable(BOOL bEnable)
+{
+ m_bEnable = bEnable;
+}
+
+
+// Retourne le goal lors d'une visite.
+
+D3DVECTOR CDisplayText::RetVisitGoal(EventMsg event)
+{
+ int i;
+
+ i = event-EVENT_DT_VISIT0;
+ if ( i < 0 || i >= MAXDTLINE ) return D3DVECTOR(0.0f, 0.0f, 0.0f);
+ return m_visitGoal[i];
+}
+
+// Retourne la distance lors d'une visite.
+
+float CDisplayText::RetVisitDist(EventMsg event)
+{
+ int i;
+
+ i = event-EVENT_DT_VISIT0;
+ if ( i < 0 || i >= MAXDTLINE ) return 0.0f;
+ return m_visitDist[i];
+}
+
+// Retourne la hauteur lors d'une visite.
+
+float CDisplayText::RetVisitHeight(EventMsg event)
+{
+ int i;
+
+ i = event-EVENT_DT_VISIT0;
+ if ( i < 0 || i >= MAXDTLINE ) return 0.0f;
+ return m_visitHeight[i];
+}
+
+
+// Retourne la distance de visite idéale pour un objet donné.
+
+float CDisplayText::RetIdealDist(CObject* pObj)
+{
+ ObjectType type;
+
+ if ( pObj == 0 ) return 40.0f;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_PORTICO ) return 200.0f;
+ if ( type == OBJECT_BASE ) return 200.0f;
+ if ( type == OBJECT_NUCLEAR ) return 100.0f;
+ if ( type == OBJECT_PARA ) return 100.0f;
+ if ( type == OBJECT_SAFE ) return 100.0f;
+ if ( type == OBJECT_TOWER ) return 80.0f;
+
+ return 60.0f;
+}
+
+// Retourne la hauteur de visite idéale pour un objet donné.
+
+float CDisplayText::RetIdealHeight(CObject* pObj)
+{
+ ObjectType type;
+
+ if ( pObj == 0 ) return 5.0f;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_DERRICK ) return 35.0f;
+ if ( type == OBJECT_FACTORY ) return 22.0f;
+ if ( type == OBJECT_REPAIR ) return 30.0f;
+ if ( type == OBJECT_DESTROYER) return 30.0f;
+ if ( type == OBJECT_STATION ) return 13.0f;
+ if ( type == OBJECT_CONVERT ) return 20.0f;
+ if ( type == OBJECT_TOWER ) return 30.0f;
+ if ( type == OBJECT_RESEARCH ) return 22.0f;
+ if ( type == OBJECT_RADAR ) return 19.0f;
+ if ( type == OBJECT_INFO ) return 19.0f;
+ if ( type == OBJECT_ENERGY ) return 20.0f;
+ if ( type == OBJECT_LABO ) return 16.0f;
+ if ( type == OBJECT_NUCLEAR ) return 40.0f;
+ if ( type == OBJECT_PARA ) return 40.0f;
+ if ( type == OBJECT_SAFE ) return 20.0f;
+
+ return 15.0f;
+}
+
+
+// Supprime toutes les visites.
+
+void CDisplayText::ClearVisit()
+{
+ CWindow* pw;
+ CButton* pb;
+ int i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 ) return;
+
+ for ( i=0 ; i<MAXDTLINE ; i++ )
+ {
+ pb = (CButton*)pw->SearchControl(EventMsg(EVENT_DT_VISIT0+i));
+ if ( pb == 0 ) break;
+ pb->SetIcon(14); // yeux
+ }
+}
+
+// Met un bouton en mode "visite".
+
+void CDisplayText::SetVisit(EventMsg event)
+{
+ CWindow* pw;
+ CButton* pb;
+ int i;
+
+ i = event-EVENT_DT_VISIT0;
+ if ( i < 0 || i >= MAXDTLINE ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 ) return;
+ pb = (CButton*)pw->SearchControl(EventMsg(EVENT_DT_VISIT0+i));
+ if ( pb == 0 ) return;
+ pb->SetIcon(48); // >
+}
+
+// Indique si un bouton est en mode "visite".
+
+BOOL CDisplayText::IsVisit(EventMsg event)
+{
+ CWindow* pw;
+ CButton* pb;
+ int i;
+
+ i = event-EVENT_DT_VISIT0;
+ if ( i < 0 || i >= MAXDTLINE ) return FALSE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 ) return FALSE;
+ pb = (CButton*)pw->SearchControl(EventMsg(EVENT_DT_VISIT0+i));
+ if ( pb == 0 ) return FALSE;
+ return (pb->RetIcon() == 48); // > ?
+}
+
+
+// Retourne l'objet de toto.
+
+CObject* CDisplayText::SearchToto()
+{
+ ObjectType type;
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_TOTO )
+ {
+ return pObj;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/displaytext.h b/src/displaytext.h
new file mode 100644
index 0000000..3f138f2
--- /dev/null
+++ b/src/displaytext.h
@@ -0,0 +1,77 @@
+// displaytext.h
+
+#ifndef _DISPLAYTEXT_H_
+#define _DISPLAYTEXT_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CInterface;
+class CObject;
+class CSound;
+
+
+enum TextType
+{
+ TT_ERROR = 1,
+ TT_WARNING = 2,
+ TT_INFO = 3,
+ TT_MESSAGE = 4,
+};
+
+#define MAXDTLINE 4
+
+
+class CDisplayText
+{
+public:
+ CDisplayText(CInstanceManager* iMan);
+ ~CDisplayText();
+
+ void DeleteObject();
+
+ BOOL EventProcess(const Event &event);
+
+ void DisplayError(Error err, CObject* pObj, float time=10.0f);
+ void DisplayError(Error err, D3DVECTOR goal, float height=15.0f, float dist=60.0f, float time=10.0f);
+ void DisplayText(char *text, CObject* pObj, float time=10.0f, TextType type=TT_INFO);
+ void DisplayText(char *text, D3DVECTOR goal, float height=15.0f, float dist=60.0f, float time=10.0f, TextType type=TT_INFO);
+ void HideText(BOOL bHide);
+ void ClearText();
+ BOOL ClearLastText();
+ void SetDelay(float factor);
+ void SetEnable(BOOL bEnable);
+
+ D3DVECTOR RetVisitGoal(EventMsg event);
+ float RetVisitDist(EventMsg event);
+ float RetVisitHeight(EventMsg event);
+
+ float RetIdealDist(CObject* pObj);
+ float RetIdealHeight(CObject* pObj);
+
+ void ClearVisit();
+ void SetVisit(EventMsg event);
+ BOOL IsVisit(EventMsg event);
+
+protected:
+ CObject* SearchToto();
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CInterface* m_interface;
+ CSound* m_sound;
+
+ BOOL m_bExist[MAXDTLINE];
+ float m_time[MAXDTLINE];
+ D3DVECTOR m_visitGoal[MAXDTLINE];
+ float m_visitDist[MAXDTLINE];
+ float m_visitHeight[MAXDTLINE];
+
+ BOOL m_bHide;
+ BOOL m_bEnable;
+ float m_delayFactor;
+};
+
+
+#endif //_DISPLAYTEXT_H_
diff --git a/src/edit.cpp b/src/edit.cpp
new file mode 100644
index 0000000..6d4beac
--- /dev/null
+++ b/src/edit.cpp
@@ -0,0 +1,3305 @@
+// edit.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "scroll.h"
+#include "text.h"
+#include "edit.h"
+
+
+#define MARGX (5.0f/640.0f)
+#define MARGY (5.0f/480.0f)
+#define MARGYS (4.0f/480.0f)
+#define MARGY1 (1.0f/480.0f)
+#define DELAY_DBCLICK 0.3f // délai pour double-clic
+#define DELAY_SCROLL 0.1f // délai pour défilement
+#define BIG_FONT 1.6f // agrandissement pour \b;
+
+
+
+
+// Indique si un caractère est un espace.
+
+BOOL IsSpace(int character)
+{
+ return ( character == ' ' ||
+ character == '\t' ||
+ character == '\n' );
+}
+
+// Indique si un caractère fait partie d'un mot.
+
+BOOL IsWord(int character)
+{
+ char c;
+
+ c = tolower(RetNoAccent(character));
+
+ return ( (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' );
+}
+
+// Indique si un caractère est un séparateur de mot.
+
+BOOL IsSep(int character)
+{
+ if ( IsSpace(character) ) return FALSE;
+ return !IsWord(character);
+}
+
+
+
+// Constructeur de l'objet.
+
+CEdit::CEdit(CInstanceManager* iMan) : CControl(iMan)
+{
+ FPOINT pos;
+ int i;
+
+ CControl::CControl(iMan);
+
+ m_maxChar = 100;
+ m_text = (char*)malloc(sizeof(char)*(m_maxChar+1));
+ m_format = 0;
+ m_len = 0;
+
+ m_fontType = FONT_COURIER;
+ m_scroll = 0;
+ m_bEdit = TRUE;
+ m_bHilite = TRUE;
+ m_bInsideScroll = TRUE;
+ m_bCapture = FALSE;
+ m_bDisplaySpec = FALSE;
+ m_bSoluce = FALSE;
+ m_bGeneric = FALSE;
+ m_bAutoIndent = FALSE;
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ m_column = 0;
+ m_imageTotal = 0;
+
+ HyperFlush();
+
+ for ( i=0 ; i<EDITUNDOMAX ; i++ )
+ {
+ m_undo[i].text = 0;
+ }
+ m_bUndoForce = TRUE;
+ m_undoOper = OPERUNDO_SPEC;
+}
+
+// Destructeur de l'objet.
+
+CEdit::~CEdit()
+{
+ int i;
+
+ FreeImage();
+
+ for ( i=0 ; i<EDITUNDOMAX ; i++ )
+ {
+ delete m_undo[i].text;
+ }
+
+ delete m_text;
+ delete m_format;
+ delete m_scroll;
+ CControl::~CControl();
+}
+
+
+// Crée une nouvelle ligne éditable.
+
+BOOL CEdit::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CScroll* pc;
+ FPOINT start, end;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ m_len = 0;
+ m_lineFirst = 0;
+ m_time = 0.0f;
+ m_timeBlink = 0.0f;
+ m_timeLastClick = 0.0f;
+ m_timeLastScroll = 0.0f;
+
+ m_bMulti = FALSE;
+ MoveAdjust();
+ if ( m_lineVisible <= 1 )
+ {
+ m_bMulti = FALSE;
+ }
+ else
+ {
+ m_bMulti = TRUE;
+ MoveAdjust(); // réajuste en mode multi-lignes
+ m_scroll = new CScroll(m_iMan);
+ pc = (CScroll*)m_scroll;
+ pc->Create(pos, dim, -1, EVENT_NULL);
+ MoveAdjust();
+ }
+
+ return TRUE;
+}
+
+
+void CEdit::SetPos(FPOINT pos)
+{
+ CControl::SetPos(pos);
+ MoveAdjust();
+}
+
+void CEdit::SetDim(FPOINT dim)
+{
+ CControl::SetDim(dim);
+ MoveAdjust();
+}
+
+void CEdit::MoveAdjust()
+{
+ FPOINT pos, dim;
+ float height;
+
+ m_lineDescent = m_engine->RetText()->RetDescent(m_fontSize, m_fontType);
+ m_lineAscent = m_engine->RetText()->RetAscent(m_fontSize, m_fontType);
+ m_lineHeight = m_engine->RetText()->RetHeight(m_fontSize, m_fontType);
+
+ height = m_dim.y-(m_bMulti?MARGY*2.0f:MARGY1);
+ m_lineVisible = (int)(height/m_lineHeight);
+
+ if ( m_scroll != 0 )
+ {
+ if ( m_bInsideScroll )
+ {
+ pos.x = m_pos.x+m_dim.x-MARGX-SCROLL_WIDTH;
+ pos.y = m_pos.y+MARGYS;
+ dim.x = SCROLL_WIDTH;
+ dim.y = m_dim.y-MARGYS*2.0f;
+ }
+ else
+ {
+ pos.x = m_pos.x+m_dim.x-SCROLL_WIDTH;
+ pos.y = m_pos.y;
+ dim.x = SCROLL_WIDTH;
+ dim.y = m_dim.y;
+ }
+ m_scroll->SetPos(pos);
+ m_scroll->SetDim(dim);
+ }
+
+ Justif();
+
+ if ( m_lineFirst > m_lineTotal-m_lineVisible )
+ {
+ m_lineFirst = m_lineTotal-m_lineVisible;
+ if ( m_lineFirst < 0 ) m_lineFirst = 0;
+ }
+
+ pos.x = m_pos.x+m_dim.x-(m_bMulti?SCROLL_WIDTH:0.0f);
+ pos.y = m_pos.y;
+ GlintCreate(pos, FALSE, FALSE);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CEdit::EventProcess(const Event &event)
+{
+ BOOL bShift, bControl;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELUP &&
+ Detect(event.pos) )
+ {
+ Scroll(m_lineFirst-3, TRUE);
+ return TRUE;
+ }
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELDOWN &&
+ Detect(event.pos) )
+ {
+ Scroll(m_lineFirst+3, TRUE);
+ return TRUE;
+ }
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ m_time += event.rTime;
+ m_timeBlink += event.rTime;
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ if ( Detect(event.pos) &&
+ event.pos.x < m_pos.x+m_dim.x-(m_bMulti?MARGX+SCROLL_WIDTH:0.0f) )
+ {
+ if ( m_bEdit )
+ {
+ m_engine->SetMouseType(D3DMOUSEEDIT);
+ }
+ else
+ {
+ if ( IsLinkPos(event.pos) )
+ {
+ m_engine->SetMouseType(D3DMOUSEHAND);
+ }
+ else
+ {
+ m_engine->SetMouseType(D3DMOUSENORM);
+ }
+ }
+ }
+ }
+
+ if ( m_scroll != 0 && !m_bGeneric )
+ {
+ m_scroll->EventProcess(event);
+
+ if ( event.event == m_scroll->RetEventMsg() )
+ {
+ Scroll();
+ return TRUE;
+ }
+ }
+
+ if ( event.event == EVENT_KEYDOWN && m_bFocus )
+ {
+ bShift = (event.keyState&KS_SHIFT);
+ bControl = (event.keyState&KS_CONTROL);
+
+ if ( (event.param == 'X' && !bShift && bControl) ||
+ (event.param == VK_DELETE && bShift && !bControl) )
+ {
+ Cut();
+ return TRUE;
+ }
+ if ( (event.param == 'C' && !bShift && bControl) ||
+ (event.param == VK_INSERT && !bShift && bControl) )
+ {
+ Copy();
+ return TRUE;
+ }
+ if ( (event.param == 'V' && !bShift && bControl) ||
+ (event.param == VK_INSERT && bShift && !bControl) )
+ {
+ Paste();
+ return TRUE;
+ }
+
+ if ( event.param == 'A' && !bShift && bControl )
+ {
+ SetCursor(999999, 0);
+ return TRUE;
+ }
+
+ if ( event.param == 'O' && !bShift && bControl )
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, EVENT_STUDIO_OPEN);
+ m_event->AddEvent(newEvent);
+ }
+ if ( event.param == 'S' && !bShift && bControl )
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, EVENT_STUDIO_SAVE);
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.param == 'Z' && !bShift && bControl )
+ {
+ Undo();
+ return TRUE;
+ }
+
+ if ( event.param == 'U' && !bShift && bControl )
+ {
+ if ( MinMaj(FALSE) ) return TRUE;
+ }
+ if ( event.param == 'U' && bShift && bControl )
+ {
+ if ( MinMaj(TRUE) ) return TRUE;
+ }
+
+ if ( event.param == VK_TAB && !bShift && !bControl && !m_bAutoIndent )
+ {
+ if ( Shift(FALSE) ) return TRUE;
+ }
+ if ( event.param == VK_TAB && bShift && !bControl && !m_bAutoIndent )
+ {
+ if ( Shift(TRUE) ) return TRUE;
+ }
+
+ if ( m_bEdit )
+ {
+ if ( event.param == VK_LEFT )
+ {
+ MoveChar(-1, bControl, bShift);
+ return TRUE;
+ }
+ if ( event.param == VK_RIGHT )
+ {
+ MoveChar(1, bControl, bShift);
+ return TRUE;
+ }
+ if ( event.param == VK_UP )
+ {
+ MoveLine(-1, bControl, bShift);
+ return TRUE;
+ }
+ if ( event.param == VK_DOWN )
+ {
+ MoveLine(1, bControl, bShift);
+ return TRUE;
+ }
+
+ if ( event.param == VK_PRIOR ) // PageUp ?
+ {
+ MoveLine(-(m_lineVisible-1), bControl, bShift);
+ return TRUE;
+ }
+ if ( event.param == VK_NEXT ) // PageDown ?
+ {
+ MoveLine(m_lineVisible-1, bControl, bShift);
+ return TRUE;
+ }
+ }
+ else
+ {
+ if ( event.param == VK_LEFT ||
+ event.param == VK_UP )
+ {
+ Scroll(m_lineFirst-1, TRUE);
+ return TRUE;
+ }
+ if ( event.param == VK_RIGHT ||
+ event.param == VK_DOWN )
+ {
+ Scroll(m_lineFirst+1, TRUE);
+ return TRUE;
+ }
+
+ if ( event.param == VK_PRIOR ) // PageUp ?
+ {
+ Scroll(m_lineFirst-(m_lineVisible-1), TRUE);
+ return TRUE;
+ }
+ if ( event.param == VK_NEXT ) // PageDown ?
+ {
+ Scroll(m_lineFirst+(m_lineVisible-1), TRUE);
+ return TRUE;
+ }
+ }
+
+ if ( event.param == VK_HOME )
+ {
+ MoveHome(bControl, bShift);
+ return TRUE;
+ }
+ if ( event.param == VK_END )
+ {
+ MoveEnd(bControl, bShift);
+ return TRUE;
+ }
+
+ if ( event.param == VK_BACK ) // backspace ( <- ) ?
+ {
+ Delete(-1);
+ SendModifEvent();
+ return TRUE;
+ }
+ if ( event.param == VK_DELETE )
+ {
+ Delete(1);
+ SendModifEvent();
+ return TRUE;
+ }
+
+ if ( event.param == VK_RETURN )
+ {
+ Insert('\n');
+ SendModifEvent();
+ return TRUE;
+ }
+ if ( event.param == VK_TAB )
+ {
+ Insert('\t');
+ SendModifEvent();
+ return TRUE;
+ }
+ }
+
+ if ( event.event == EVENT_CHAR && m_bFocus )
+ {
+ if ( event.param >= ' ' && event.param <= 255 )
+ {
+ Insert((char)event.param);
+ SendModifEvent();
+ return TRUE;
+ }
+ }
+
+ if ( event.event == EVENT_FOCUS )
+ {
+ if ( event.param == m_eventMsg )
+ {
+ m_bFocus = TRUE;
+ }
+ else
+ {
+ m_bFocus = FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ m_mouseFirstPos = event.pos;
+ m_mouseLastPos = event.pos;
+ if ( Detect(event.pos) )
+ {
+ if ( event.pos.x < m_pos.x+m_dim.x-(m_bMulti?MARGX+SCROLL_WIDTH:0.0f) )
+ {
+ MouseClick(event.pos);
+ if ( m_bEdit || m_bHilite ) m_bCapture = TRUE;
+ }
+ m_bFocus = TRUE;
+ }
+ else
+ {
+ m_bFocus = FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && m_bCapture )
+ {
+ m_mouseLastPos = event.pos;
+ MouseMove(event.pos);
+ }
+
+ if ( event.event == EVENT_FRAME && m_bCapture )
+ {
+ MouseMove(m_mouseLastPos);
+ }
+
+ if ( event.event == EVENT_LBUTTONUP )
+ {
+ if ( Detect(event.pos) )
+ {
+ if ( event.pos.x < m_pos.x+m_dim.x-(m_bMulti?MARGX+SCROLL_WIDTH:0.0f) )
+ {
+ MouseRelease(m_mouseFirstPos);
+ }
+ }
+ if ( m_bCapture )
+ {
+ if ( m_timeLastClick+DELAY_DBCLICK > m_time ) // double-clic ?
+ {
+ MouseDoubleClick(event.pos);
+ }
+ m_timeLastClick = m_time;
+ m_bCapture = FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Envoie un événement pour indiquer que le texte a été modifié.
+
+void CEdit::SendModifEvent()
+{
+ Event newEvent;
+
+ m_event->MakeEvent(newEvent, m_eventMsg);
+ m_event->AddEvent(newEvent);
+}
+
+
+// Détecte si la souris est sur un caractère lien hypertexte.
+
+BOOL CEdit::IsLinkPos(FPOINT pos)
+{
+ int i;
+
+ if ( m_format == 0 ) return FALSE;
+
+ i = MouseDetect(pos);
+ if ( i == -1 ) return FALSE;
+ if ( i >= m_len ) return FALSE;
+
+ if ( (m_format[i]&COLOR_MASK) == COLOR_LINK ) return TRUE;
+ return FALSE;
+}
+
+
+// Positionne le curseur suite à un double-clic.
+
+void CEdit::MouseDoubleClick(FPOINT mouse)
+{
+ int i, character;
+
+ if ( m_bMulti ) // multi-lignes ?
+ {
+ i = MouseDetect(mouse);
+ if ( i == -1 ) return;
+
+ while ( i > 0 )
+ {
+ character = (unsigned char)m_text[i-1];
+ if ( !IsWord(character) ) break;
+ i --;
+ }
+ m_cursor2 = i;
+
+ while ( i < m_len )
+ {
+ character = (unsigned char)m_text[i];
+ if ( !IsWord(character) ) break;
+ i ++;
+ }
+ m_cursor1 = i;
+ }
+ else // mono-ligne ?
+ {
+ m_cursor2 = 0;
+ m_cursor1 = m_len; // sélectionne tout
+ }
+
+ m_bUndoForce = TRUE;
+
+ Justif();
+ ColumnFix();
+}
+
+// Positionne le curseur suite à un clic.
+
+void CEdit::MouseClick(FPOINT mouse)
+{
+ int i;
+
+ i = MouseDetect(mouse);
+ if ( i == -1 ) return;
+
+ if ( m_bEdit || m_bHilite )
+ {
+ m_cursor1 = i;
+ m_cursor2 = i;
+ m_bUndoForce = TRUE;
+ m_timeBlink = 0.0f; // allume le curseur immédiatement
+ ColumnFix();
+ }
+}
+
+// Positionne le curseur suite à un clic relâché.
+
+void CEdit::MouseRelease(FPOINT mouse)
+{
+ int i, j, rank;
+
+ i = MouseDetect(mouse);
+ if ( i == -1 ) return;
+
+ if ( !m_bEdit )
+ {
+ if ( m_format != 0 && i < m_len && m_cursor1 == m_cursor2 &&
+ (m_format[i]&COLOR_MASK) == COLOR_LINK )
+ {
+ rank = -1;
+ for ( j=0 ; j<=i ; j++ )
+ {
+ if ( (j == 0 || (m_format[j-1]&COLOR_MASK) != COLOR_LINK) &&
+ (m_format[j+0]&COLOR_MASK) == COLOR_LINK )
+ {
+ rank ++;
+ }
+ }
+ HyperJump(m_link[rank].name, m_link[rank].marker);
+ }
+ }
+}
+
+// Positionne le curseur suite à un déplacement.
+
+void CEdit::MouseMove(FPOINT mouse)
+{
+ int i;
+
+ if ( m_bMulti &&
+ m_timeLastScroll+DELAY_SCROLL <= m_time )
+ {
+ if ( mouse.y > m_pos.y+m_dim.y ) // plus haut ?
+ {
+ Scroll(m_lineFirst-1, FALSE);
+ mouse.y = m_pos.y+m_dim.y-MARGY-m_lineHeight/2.0f;
+ }
+ if ( mouse.y < m_pos.y ) // plus bas ?
+ {
+ Scroll(m_lineFirst+1, FALSE);
+ mouse.y = m_pos.y+m_dim.y-MARGY-m_lineVisible*m_lineHeight+m_lineHeight/2.0f;
+ }
+ m_timeLastScroll = m_time;
+ }
+
+ i = MouseDetect(mouse);
+ if ( i != -1 )
+ {
+ m_cursor1 = i;
+ m_bUndoForce = TRUE;
+ m_timeBlink = 0.0f; // allume le curseur immédiatement
+ ColumnFix();
+ }
+}
+
+// Positionne le curseur suite à un clic.
+
+int CEdit::MouseDetect(FPOINT mouse)
+{
+ FPOINT pos;
+ float indentLength, offset, size;
+ int i, len, c;
+ BOOL bTitle;
+
+ if ( m_bAutoIndent )
+ {
+ indentLength = m_engine->RetText()->RetCharWidth(' ', 0.0f, m_fontSize, m_fontStretch, m_fontType)
+ * m_engine->RetEditIndentValue();
+ }
+
+ pos.y = m_pos.y+m_dim.y-m_lineHeight-(m_bMulti?MARGY:MARGY1);
+ for ( i=m_lineFirst ; i<m_lineTotal ; i++ )
+ {
+ bTitle = ( m_format != 0 && (m_format[m_lineOffset[i]]&TITLE_MASK) == TITLE_BIG );
+
+ if ( i >= m_lineFirst+m_lineVisible ) break;
+
+ pos.x = m_pos.x+(10.0f/640.0f);
+ if ( m_bAutoIndent )
+ {
+ pos.x += indentLength*m_lineIndent[i];
+ }
+ offset = mouse.x-pos.x;
+
+ if ( bTitle ) pos.y -= m_lineHeight;
+
+ if ( mouse.y > pos.y )
+ {
+ len = m_lineOffset[i+1] - m_lineOffset[i];
+
+ if ( m_format == 0 )
+ {
+ c = m_engine->RetText()->Detect(m_text+m_lineOffset[i],
+ len, offset, m_fontSize,
+ m_fontStretch, m_fontType);
+ }
+ else
+ {
+ size = m_fontSize;
+ if ( bTitle ) size *= BIG_FONT;
+
+ c = m_engine->RetText()->Detect(m_text+m_lineOffset[i],
+ m_format+m_lineOffset[i],
+ len, offset, size,
+ m_fontStretch);
+ }
+ return m_lineOffset[i]+c;
+ }
+
+ if ( bTitle ) i ++;
+ pos.y -= m_lineHeight;
+ }
+ return -1;
+}
+
+
+// Efface tout l'historique.
+
+void CEdit::HyperFlush()
+{
+ m_historyTotal = 0;
+ m_historyCurrent = -1;
+}
+
+// Indique quelle est la page home.
+
+void CEdit::HyperHome(char *filename)
+{
+ HyperFlush();
+ HyperAdd(filename, 0);
+}
+
+// Effectue un hyper saut à travers un lien.
+
+void CEdit::HyperJump(char *name, char *marker)
+{
+ char filename[100];
+ char sMarker[100];
+ int i, line, pos;
+
+ if ( m_historyCurrent >= 0 )
+ {
+ m_history[m_historyCurrent].firstLine = m_lineFirst;
+ }
+
+ strcpy(sMarker, marker);
+
+//? sprintf(filename, "help\\%s.txt", name);
+ if ( name[0] == '%' )
+ {
+ UserDir(filename, name, "");
+ strcat(filename, ".txt");
+ }
+ else
+ {
+ sprintf(filename, "help\\%s.txt", name);
+ }
+ if ( ReadText(filename) )
+ {
+ Justif();
+
+ line = 0;
+ for ( i=0 ; i<m_markerTotal ; i++ )
+ {
+ if ( strcmp(sMarker, m_marker[i].name) == 0 )
+ {
+ pos = m_marker[i].pos;
+ for ( i=0 ; i<m_lineTotal ; i++ )
+ {
+ if ( pos >= m_lineOffset[i] )
+ {
+ line = i;
+ }
+ }
+ break;
+ }
+ }
+
+ SetFirstLine(line);
+ HyperAdd(filename, line);
+ }
+}
+
+// Ajoute un texte visité à l'historique.
+
+BOOL CEdit::HyperAdd(char *filename, int firstLine)
+{
+ if ( m_historyCurrent >= EDITHISTORYMAX-1 ) return FALSE;
+
+ m_historyCurrent ++;
+ strcpy(m_history[m_historyCurrent].filename, filename);
+ m_history[m_historyCurrent].firstLine = firstLine;
+
+ m_historyTotal = m_historyCurrent+1;
+ return TRUE;
+}
+
+// Indique si un bouton EVENT_HYPER_* est actif ou non.
+
+BOOL CEdit::HyperTest(EventMsg event)
+{
+ if ( event == EVENT_HYPER_HOME )
+ {
+ return ( m_historyCurrent > 0 );
+ }
+
+ if ( event == EVENT_HYPER_PREV )
+ {
+ return ( m_historyCurrent > 0 );
+ }
+
+ if ( event == EVENT_HYPER_NEXT )
+ {
+ return ( m_historyCurrent < m_historyTotal-1 );
+ }
+
+ return FALSE;
+}
+
+// Effectue l'action correspondant à un bouton EVENT_HYPER_*.
+
+BOOL CEdit::HyperGo(EventMsg event)
+{
+ if ( !HyperTest(event) ) return FALSE;
+
+ m_history[m_historyCurrent].firstLine = m_lineFirst;
+
+ if ( event == EVENT_HYPER_HOME )
+ {
+ m_historyCurrent = 0;
+ }
+
+ if ( event == EVENT_HYPER_PREV )
+ {
+ m_historyCurrent --;
+ }
+
+ if ( event == EVENT_HYPER_NEXT )
+ {
+ m_historyCurrent ++;
+ }
+
+ ReadText(m_history[m_historyCurrent].filename);
+ Justif();
+ SetFirstLine(m_history[m_historyCurrent].firstLine);
+ return TRUE;
+}
+
+
+// Dessine la ligne éditable.
+
+void CEdit::Draw()
+{
+ FPOINT pos, ppos, dim, start, end;
+ float size, indentLength;
+ int i, j, beg, len, c1, c2, o1, o2, eol, iIndex, line;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ pos.x = m_pos.x;
+ pos.y = m_pos.y;
+ dim.x = m_dim.x;
+ if ( !m_bInsideScroll ) dim.x -= m_bMulti?SCROLL_WIDTH:0.0f;
+ dim.y = m_dim.y;
+ DrawBack(pos, dim); // fond
+
+ // Affiche toutes les lignes.
+ c1 = m_cursor1;
+ c2 = m_cursor2;
+ if ( c1 > c2 ) Swap(c1, c2); // toujours c1 <= c2
+
+ if ( m_bInsideScroll )
+ {
+ dim.x -= m_bMulti?SCROLL_WIDTH:0.0f + (1.0f/640.0f);
+ }
+
+ if ( m_bAutoIndent )
+ {
+ indentLength = m_engine->RetText()->RetCharWidth(' ', 0.0f, m_fontSize, m_fontStretch, m_fontType)
+ * m_engine->RetEditIndentValue();
+ }
+
+ pos.y = m_pos.y+m_dim.y-m_lineHeight-(m_bMulti?MARGY:MARGY1);
+ for ( i=m_lineFirst ; i<m_lineTotal ; i++ )
+ {
+ if ( i == m_lineFirst && i < m_lineTotal-1 &&
+ m_lineOffset[i] == m_lineOffset[i+1] )
+ {
+ pos.y -= m_lineHeight; // saute double ligne \b;
+ i ++;
+ }
+
+ if ( i >= m_lineFirst+m_lineVisible ) break;
+
+ pos.x = m_pos.x+(10.0f/640.0f);
+ if ( m_bAutoIndent )
+ {
+ for ( j=0 ; j<m_lineIndent[i] ; j++ )
+ {
+ char s = '\t'; // ligne | pointillée
+ m_engine->RetText()->DrawText(&s, 1, pos, 1.0f, 1, m_fontSize, m_fontStretch, m_fontType, 0);
+ pos.x += indentLength;
+ }
+ }
+
+ beg = m_lineOffset[i];
+ len = m_lineOffset[i+1] - m_lineOffset[i];
+
+ ppos = pos;
+ size = m_fontSize;
+
+ // Grand titre \b; ?
+ if ( beg+len < m_len && m_format != 0 &&
+ (m_format[beg]&TITLE_MASK) == TITLE_BIG )
+ {
+ start.x = ppos.x-MARGX;
+ end.x = dim.x-MARGX*2.0f;
+ start.y = ppos.y-(m_bMulti?0.0f:MARGY1)-m_lineHeight*(BIG_FONT-1.0f);
+ end.y = m_lineHeight*BIG_FONT;
+ DrawPart(start, end, 2); // fond bleu dégradé ->
+
+ size *= BIG_FONT;
+ ppos.y -= m_lineHeight*(BIG_FONT-1.0f);
+ }
+
+ // Titre \t; ?
+ if ( beg+len < m_len && m_format != 0 &&
+ (m_format[beg]&TITLE_MASK) == TITLE_NORM )
+ {
+ start.x = ppos.x-MARGX;
+ end.x = dim.x-MARGX*2.0f;
+ start.y = ppos.y-(m_bMulti?0.0f:MARGY1);
+ end.y = m_lineHeight;
+ DrawPart(start, end, 2); // fond bleu dégradé ->
+ }
+
+ // Sous-titre \s; ?
+ if ( beg+len < m_len && m_format != 0 &&
+ (m_format[beg]&TITLE_MASK) == TITLE_LITTLE )
+ {
+ start.x = ppos.x-MARGX;
+ end.x = dim.x-MARGX*2.0f;
+ start.y = ppos.y-(m_bMulti?0.0f:MARGY1);
+ end.y = m_lineHeight;
+ DrawPart(start, end, 3); // fond jaune dégradé ->
+ }
+
+ // Tableau \tab; ?
+ if ( beg+len < m_len && m_format != 0 &&
+ (m_format[beg]&COLOR_MASK) == COLOR_TABLE )
+ {
+ start.x = ppos.x-MARGX;
+ end.x = dim.x-MARGX*2.0f;
+ start.y = ppos.y-(m_bMulti?0.0f:MARGY1);
+ end.y = m_lineHeight;
+ DrawPart(start, end, 11); // fond orange dégradé ->
+ }
+
+ // Image \image; ?
+ if ( beg+len < m_len && m_format != 0 &&
+ (m_format[beg]&IMAGE_MASK) != 0 )
+ {
+ line = 1;
+ while ( true ) // regroupe les tranches d'image
+ {
+ if ( i+line >= m_lineTotal ||
+ i+line >= m_lineFirst+m_lineVisible ||
+ (m_format[beg+line]&IMAGE_MASK) == 0 ) break;
+ line ++;
+ }
+
+ iIndex = m_text[beg]; // caractère = index dans m_image
+ pos.y -= m_lineHeight*(line-1);
+ DrawImage(pos, m_image[iIndex].name,
+ m_image[iIndex].width*(m_fontSize/SMALLFONT),
+ m_image[iIndex].offset, m_image[iIndex].height*line, line);
+ pos.y -= m_lineHeight;
+ i += line-1;
+ continue;
+ }
+
+ if ( ((m_bEdit && m_bFocus && m_bHilite) ||
+ (!m_bEdit && m_bHilite) ) &&
+ c1 != c2 && beg <= c2 && beg+len >= c1 ) // zone sélectionnée ?
+ {
+ o1 = c1; if ( o1 < beg ) o1 = beg;
+ o2 = c2; if ( o2 > beg+len ) o2 = beg+len;
+
+ if ( m_format == 0 )
+ {
+ start.x = ppos.x+m_engine->RetText()->RetStringWidth(m_text+beg, o1-beg, size, m_fontStretch, m_fontType);
+ end.x = m_engine->RetText()->RetStringWidth(m_text+o1, o2-o1, size, m_fontStretch, m_fontType);
+ }
+ else
+ {
+ start.x = ppos.x+m_engine->RetText()->RetStringWidth(m_text+beg, m_format+beg, o1-beg, size, m_fontStretch);
+ end.x = m_engine->RetText()->RetStringWidth(m_text+o1, m_format+o1, o2-o1, size, m_fontStretch);
+ }
+
+ start.y = ppos.y-(m_bMulti?0.0f:MARGY1);
+ end.y = m_lineHeight;
+ if ( m_format != 0 && (m_format[beg]&TITLE_MASK) == TITLE_BIG ) end.y *= BIG_FONT;
+ DrawPart(start, end, 1); // fond jaune uni
+ }
+
+ eol = 16; // >
+ if ( len > 0 && m_text[beg+len-1] == '\n' )
+ {
+ len --; // n'affiche pas le '\n'
+ eol = 0; // rien
+ }
+ if ( beg+len >= m_len )
+ {
+ eol = 2; // carré (eot)
+ }
+ if ( !m_bMulti || !m_bDisplaySpec ) eol = 0;
+ if ( m_format == 0 )
+ {
+ m_engine->RetText()->DrawText(m_text+beg, len, ppos, m_dim.x, 1, size, m_fontStretch, m_fontType, eol);
+ }
+ else
+ {
+ m_engine->RetText()->DrawText(m_text+beg, m_format+beg, len, ppos, m_dim.x, 1, size, m_fontStretch, eol);
+ }
+
+ pos.y -= m_lineHeight;
+
+ if ( i < m_lineTotal-2 && m_lineOffset[i+1] == m_lineOffset[i+2] )
+ {
+ pos.y -= m_lineHeight; // saute double ligne \b;
+ i ++;
+ }
+ }
+
+ // Affiche le curseur.
+ if ( (m_bEdit && m_bFocus && m_bHilite && Mod(m_timeBlink, 1.0f) <= 0.5f) ) // ça clignotte
+ {
+ pos.y = m_pos.y+m_dim.y-m_lineHeight-(m_bMulti?MARGY:MARGY1*2.0f);
+ for ( i=m_lineFirst ; i<m_lineTotal ; i++ )
+ {
+ if ( i == m_lineTotal-1 || m_cursor1 < m_lineOffset[i+1] )
+ {
+ pos.x = m_pos.x+(10.0f/640.0f);
+ if ( m_bAutoIndent )
+ {
+ pos.x += indentLength*m_lineIndent[i];
+ }
+
+ len = m_cursor1 - m_lineOffset[i];
+
+ if ( m_format == 0 )
+ {
+ m_engine->RetText()->DimText(m_text+m_lineOffset[i], len,
+ pos, 1, size,
+ m_fontStretch, m_fontType,
+ start, end);
+ }
+ else
+ {
+ m_engine->RetText()->DimText(m_text+m_lineOffset[i],
+ m_format+m_lineOffset[i],
+ len, pos, 1, size,
+ m_fontStretch,
+ start, end);
+ }
+
+ pos.x = end.x;
+ break;
+ }
+ pos.y -= m_lineHeight;
+ }
+ pos.x -= 1.0f/640.0f;
+ dim.x = 2.0f/640.0f;
+ dim.y = m_lineHeight;
+ DrawPart(pos, dim, 0); // rouge
+ }
+
+ if ( m_scroll != 0 && !m_bGeneric )
+ {
+ m_scroll->Draw();
+ }
+}
+
+// Dessine une partie d'image.
+
+void CEdit::DrawImage(FPOINT pos, char *name, float width,
+ float offset, float height, int nbLine)
+{
+ FPOINT uv1, uv2, dim;
+ float dp;
+ char filename[100];
+
+//? sprintf(filename, "diagram\\%s.bmp", name);
+ UserDir(filename, name, "diagram");
+ strcat(filename, ".bmp");
+
+ m_engine->SetTexture(filename);
+ m_engine->SetState(D3DSTATENORMAL);
+
+ uv1.x = 0.0f;
+ uv2.x = 1.0f;
+ uv1.y = offset;
+ uv2.y = offset+height;
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ dim.x = width;
+ dim.y = m_lineHeight*nbLine;
+ DrawIcon(pos, dim, uv1, uv2);
+}
+
+// Dessine le fond.
+
+void CEdit::DrawBack(FPOINT pos, FPOINT dim)
+{
+ FPOINT uv1,uv2, corner;
+ float dp;
+
+ if ( m_bGeneric ) return;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ if ( m_bMulti )
+ {
+ uv1.x = 128.0f/256.0f; // bleu clair
+ uv1.y = 64.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 96.0f/256.0f;
+ }
+ else
+ {
+ uv1.x = 160.0f/256.0f; // bleu moyen
+ uv1.y = 192.0f/256.0f;
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ }
+ if ( m_icon == 1 )
+ {
+ uv1.x = 192.0f/256.0f; // orange
+ uv1.y = 96.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 128.0f/256.0f;
+ }
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ if ( m_bMulti )
+ {
+ corner.x = 10.0f/640.0f;
+ corner.y = 10.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+ else
+ {
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+}
+
+// Dessine une icône de fond.
+
+void CEdit::DrawPart(FPOINT pos, FPOINT dim, int icon)
+{
+ FPOINT uv1, uv2;
+ float dp;
+
+#if _POLISH
+ m_engine->SetTexture("textp.tga");
+#else
+ m_engine->SetTexture("text.tga");
+#endif
+ m_engine->SetState(D3DSTATENORMAL);
+
+ uv1.x = (16.0f/256.0f)*(icon%16);
+ uv1.y = (240.0f/256.0f);
+ uv2.x = (16.0f/256.0f)+uv1.x;
+ uv2.y = (16.0f/256.0f)+uv1.y;
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(pos, dim, uv1, uv2);
+}
+
+
+// Donne le texte à éditer.
+
+void CEdit::SetText(char *text, BOOL bNew)
+{
+ int i, j, font;
+ BOOL bBOL;
+
+ if ( !bNew ) UndoMemorize(OPERUNDO_SPEC);
+
+ m_len = strlen(text);
+ if ( m_len > m_maxChar ) m_len = m_maxChar;
+
+ if ( m_format == 0 )
+ {
+ if ( m_bAutoIndent )
+ {
+ j = 0;
+ bBOL = TRUE;
+ for ( i=0 ; i<m_len ; i++ )
+ {
+ if ( text[i] == '\t' )
+ {
+ if ( !bBOL ) m_text[j++] = ' ';
+ continue; // enlève les tabulateurs
+ }
+ bBOL = ( text[i] == '\n' );
+
+ m_text[j++] = text[i];
+ }
+ m_len = j;
+ }
+ else
+ {
+ strncpy(m_text, text, m_len);
+ }
+ }
+ else
+ {
+ font = m_fontType;
+ j = 0;
+ bBOL = TRUE;
+ for ( i=0 ; i<m_len ; i++ )
+ {
+ if ( m_bAutoIndent )
+ {
+ if ( text[i] == '\t' )
+ {
+ if ( !bBOL )
+ {
+ m_text[j] = ' ';
+ m_format[j] = font;
+ j ++;
+ }
+ continue; // enlève les tabulateurs
+ }
+ bBOL = ( text[i] == '\n' );
+ }
+
+ if ( text[i] == '\\' && text[i+2] == ';' )
+ {
+ if ( text[i+1] == 'n' ) // normal ?
+ {
+ font &= ~FONT_MASK;
+ font |= FONT_COLOBOT;
+ i += 2;
+ }
+ else if ( text[i+1] == 'c' ) // cbot ?
+ {
+ font &= ~FONT_MASK;
+ font |= FONT_COURIER;
+ i += 2;
+ }
+ else if ( text[i+1] == 'b' ) // big title ?
+ {
+ font &= ~TITLE_MASK;
+ font |= TITLE_BIG;
+ i += 2;
+ }
+ else if ( text[i+1] == 't' ) // title ?
+ {
+ font &= ~TITLE_MASK;
+ font |= TITLE_NORM;
+ i += 2;
+ }
+ else if ( text[i+1] == 's' ) // sbttl ?
+ {
+ font &= ~TITLE_MASK;
+ font |= TITLE_LITTLE;
+ i += 2;
+ }
+ }
+ else
+ {
+ m_text[j] = text[i];
+ m_format[j] = font;
+ j ++;
+
+ font &= ~TITLE_MASK; // reset title
+ }
+ }
+ m_len = j;
+ }
+
+ if ( bNew ) UndoFlush();
+
+ m_cursor1 = 0;
+ m_cursor2 = 0; // curseur au début
+ Justif();
+ ColumnFix();
+}
+
+// Retourne un pointeur au texte édité.
+
+char* CEdit::RetText()
+{
+ m_text[m_len] = 0;
+ return m_text;
+}
+
+// Retourne le texte édité.
+
+void CEdit::GetText(char *buffer, int max)
+{
+ if ( m_len < max ) max = m_len;
+ if ( m_len > max ) max = max-1;
+
+ strncpy(buffer, m_text, max);
+ buffer[max] = 0;
+}
+
+// Retourne la longueur du texte.
+
+int CEdit::RetTextLength()
+{
+ return m_len;
+}
+
+
+
+// Retourne un nom dans une commande.
+// \x nom1 nom2 nom3;
+
+void GetNameParam(char *cmd, int rank, char *buffer)
+{
+ int i;
+
+ for ( i=0 ; i<rank ; i++ )
+ {
+ while ( *cmd != ' ' && *cmd != ';' )
+ {
+ cmd ++;
+ }
+ if ( *cmd != ';' ) cmd ++;
+ }
+
+ while ( *cmd != ' ' && *cmd != ';' )
+ {
+ *buffer++ = *cmd++;
+ }
+ *buffer = 0;
+}
+
+// Retourne un nombre dans une commande.
+// \x nom n1 n2;
+
+int RetValueParam(char *cmd, int rank)
+{
+ int n, i;
+
+ for ( i=0 ; i<rank ; i++ )
+ {
+ while ( *cmd != ' ' && *cmd != ';' )
+ {
+ cmd ++;
+ }
+ if ( *cmd != ';' ) cmd ++;
+ }
+
+ sscanf(cmd, "%d", &n);
+ return n;
+}
+
+// Libère toutes les images.
+
+void CEdit::FreeImage()
+{
+ char filename[100];
+ int i;
+
+ for ( i=0 ; i<m_imageTotal ; i++ )
+ {
+//? sprintf(filename, "diagram\\%s.bmp", m_image[i].name);
+ UserDir(filename, m_image[i].name, "diagram");
+ strcat(filename, ".bmp");
+ m_engine->FreeTexture(filename);
+ }
+}
+
+// Lit la texture d'une image.
+
+void CEdit::LoadImage(char *name)
+{
+ char filename[100];
+
+//? sprintf(filename, "diagram\\%s.bmp", name);
+ UserDir(filename, name, "diagram");
+ strcat(filename, ".bmp");
+ m_engine->LoadTexture(filename);
+}
+
+// Lit le contenu d'un fichier texte.
+
+BOOL CEdit::ReadText(char *filename, int addSize)
+{
+ FILE *file = NULL;
+ char *buffer;
+ int len, i, j, n, font, iIndex, iLines, iCount, iLink, res;
+ char iName[50];
+ char text[50];
+ float iWidth;
+ KeyRank key;
+ BOOL bInSoluce, bBOL;
+
+ if ( filename[0] == 0 ) return FALSE;
+ file = fopen(filename, "rb");
+ if ( file == NULL ) return FALSE;
+
+ fseek(file, 0, SEEK_END);
+ len = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ m_maxChar = len+addSize+100;
+ m_len = len;
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+
+ FreeImage();
+ delete m_text;
+ m_text = (char*)malloc(sizeof(char)*(m_maxChar+1));
+ buffer = (char*)malloc(sizeof(char)*(m_maxChar+1));
+ fread(buffer, 1, len, file);
+
+ if ( m_format != 0 )
+ {
+ delete m_format;
+ m_format = (char*)malloc(sizeof(char)*m_maxChar);
+ }
+
+ fclose(file);
+
+ bInSoluce = FALSE;
+ font = m_fontType;
+ iIndex = 0;
+ iLink = 0;
+ m_imageTotal = 0;
+ m_markerTotal = 0;
+ i = j = 0;
+ bBOL = TRUE;
+ while ( i < m_len )
+ {
+ if ( m_bAutoIndent )
+ {
+ if ( buffer[i] == '\t' )
+ {
+ if ( !bBOL )
+ {
+ m_text[j] = buffer[i];
+ if ( m_format != 0 ) m_format[j] = font;
+ j ++;
+ }
+ i ++;
+ continue; // enlève les tabulateurs
+ }
+ bBOL = ( buffer[i] == '\n' || buffer[i] == '\r' );
+ }
+
+ if ( buffer[i] == '\r' ) // supprime les \r
+ {
+ i ++;
+ }
+ else if ( m_format != 0 && buffer[i] == '\\' && buffer[i+2] == ';' )
+ {
+ if ( buffer[i+1] == 'n' ) // normal ?
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~FONT_MASK;
+ font |= FONT_COLOBOT;
+ }
+ i += 3;
+ }
+ else if ( buffer[i+1] == 'c' ) // cbot ?
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~FONT_MASK;
+ font |= FONT_COURIER;
+ }
+ i += 3;
+ }
+ else if ( buffer[i+1] == 'b' ) // big title ?
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~TITLE_MASK;
+ font |= TITLE_BIG;
+ }
+ i += 3;
+ }
+ else if ( buffer[i+1] == 't' ) // title ?
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~TITLE_MASK;
+ font |= TITLE_NORM;
+ }
+ i += 3;
+ }
+ else if ( buffer[i+1] == 's' ) // sbttl ?
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~TITLE_MASK;
+ font |= TITLE_LITTLE;
+ }
+ i += 3;
+ }
+ else if ( buffer[i+1] == 'l' ) // link ?
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~COLOR_MASK;
+ font |= COLOR_LINK;
+ }
+ i += 3;
+ }
+ else
+ {
+ i += 3;
+ }
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \u nom marker; ?
+ buffer[i+1] == 'u' &&
+ buffer[i+2] == ' ' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ if ( iLink < EDITLINKMAX )
+ {
+ GetNameParam(buffer+i+3, 0, m_link[iLink].name);
+ GetNameParam(buffer+i+3, 1, m_link[iLink].marker);
+ iLink ++;
+ }
+ font &= ~COLOR_MASK;
+ }
+ i += strchr(buffer+i, ';')-(buffer+i)+1;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \m marker; ?
+ buffer[i+1] == 'm' &&
+ buffer[i+2] == ' ' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ if ( m_markerTotal < EDITLINKMAX )
+ {
+ GetNameParam(buffer+i+3, 0, m_marker[m_markerTotal].name);
+ m_marker[m_markerTotal].pos = j;
+ m_markerTotal ++;
+ }
+ }
+ i += strchr(buffer+i, ';')-(buffer+i)+1;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \image nom lx ly; ?
+ buffer[i+1] == 'i' &&
+ buffer[i+2] == 'm' &&
+ buffer[i+3] == 'a' &&
+ buffer[i+4] == 'g' &&
+ buffer[i+5] == 'e' &&
+ buffer[i+6] == ' ' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+#if _DEMO
+ strcpy(iName, "demo");
+#else
+ GetNameParam(buffer+i+7, 0, iName);
+#endif
+//? iWidth = m_lineHeight*RetValueParam(buffer+i+7, 1);
+ iWidth = (float)RetValueParam(buffer+i+7, 1);
+ iWidth *= m_engine->RetText()->RetHeight(SMALLFONT, FONT_COLOBOT);
+ iLines = RetValueParam(buffer+i+7, 2);
+ LoadImage(iName);
+
+ // Une tranche d'image par ligne de texte.
+ for ( iCount=0 ; iCount<iLines ; iCount++ )
+ {
+ strcpy(m_image[iIndex].name, iName);
+ m_image[iIndex].offset = (float)iCount/iLines;
+ m_image[iIndex].height = 1.0f/iLines;
+ m_image[iIndex].width = iWidth*0.75f;
+
+ m_text[j] = (char)(iIndex++); // un car index dans m_image
+ m_format[j] = (unsigned char)IMAGE_MASK;
+ j ++;
+ }
+ }
+ i += strchr(buffer+i, ';')-(buffer+i)+1;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \button; ?
+ buffer[i+1] == 'b' &&
+ buffer[i+2] == 'u' &&
+ buffer[i+3] == 't' &&
+ buffer[i+4] == 't' &&
+ buffer[i+5] == 'o' &&
+ buffer[i+6] == 'n' &&
+ buffer[i+7] == ' ' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ m_text[j] = RetValueParam(buffer+i+8, 0);
+ m_format[j] = font|FONT_BUTTON;
+ j ++;
+ }
+ i += strchr(buffer+i, ';')-(buffer+i)+1;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \token; ?
+ buffer[i+1] == 't' &&
+ buffer[i+2] == 'o' &&
+ buffer[i+3] == 'k' &&
+ buffer[i+4] == 'e' &&
+ buffer[i+5] == 'n' &&
+ buffer[i+6] == ';' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~COLOR_MASK;
+ font |= COLOR_TOKEN;
+ }
+ i += 7;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \type; ?
+ buffer[i+1] == 't' &&
+ buffer[i+2] == 'y' &&
+ buffer[i+3] == 'p' &&
+ buffer[i+4] == 'e' &&
+ buffer[i+5] == ';' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~COLOR_MASK;
+ font |= COLOR_TYPE;
+ }
+ i += 6;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \const; ?
+ buffer[i+1] == 'c' &&
+ buffer[i+2] == 'o' &&
+ buffer[i+3] == 'n' &&
+ buffer[i+4] == 's' &&
+ buffer[i+5] == 't' &&
+ buffer[i+6] == ';' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~COLOR_MASK;
+ font |= COLOR_CONST;
+ }
+ i += 7;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \key; ?
+ buffer[i+1] == 'k' &&
+ buffer[i+2] == 'e' &&
+ buffer[i+3] == 'y' &&
+ buffer[i+4] == ';' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~COLOR_MASK;
+ font |= COLOR_KEY;
+ }
+ i += 5;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \tab; ?
+ buffer[i+1] == 't' &&
+ buffer[i+2] == 'a' &&
+ buffer[i+3] == 'b' &&
+ buffer[i+4] == ';' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font |= COLOR_TABLE;
+ }
+ i += 5;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \norm; ?
+ buffer[i+1] == 'n' &&
+ buffer[i+2] == 'o' &&
+ buffer[i+3] == 'r' &&
+ buffer[i+4] == 'm' &&
+ buffer[i+5] == ';' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ font &= ~COLOR_MASK;
+ }
+ i += 6;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \begin soluce; ?
+ buffer[i+1] == 'b' &&
+ buffer[i+2] == 's' &&
+ buffer[i+3] == ';' )
+ {
+ bInSoluce = TRUE;
+ i += 4;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \end soluce; ?
+ buffer[i+1] == 'e' &&
+ buffer[i+2] == 's' &&
+ buffer[i+3] == ';' )
+ {
+ bInSoluce = FALSE;
+ i += 4;
+ }
+ else if ( m_format != 0 &&
+ buffer[i+0] == '\\' && // \key name; ?
+ buffer[i+1] == 'k' &&
+ buffer[i+2] == 'e' &&
+ buffer[i+3] == 'y' &&
+ buffer[i+4] == ' ' )
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ if ( SearchKey(buffer+i+5, key) )
+ {
+ res = m_engine->RetKey(key, 0);
+ if ( res != 0 )
+ {
+ if ( GetResource(RES_KEY, res, iName) )
+ {
+ m_text[j] = ' ';
+ m_format[j] = font;
+ j ++;
+ n = 0;
+ while ( iName[n] != 0 )
+ {
+ m_text[j] = iName[n++];
+ m_format[j] = font;
+ j ++;
+ }
+ m_text[j] = ' ';
+ m_format[j] = font;
+ j ++;
+
+ res = m_engine->RetKey(key, 1);
+ if ( res != 0 )
+ {
+ if ( GetResource(RES_KEY, res, iName) )
+ {
+ GetResource(RES_TEXT, RT_KEY_OR, text);
+ n = 0;
+ while ( text[n] != 0 )
+ {
+ m_text[j] = text[n++];
+ m_format[j] = font&~COLOR_MASK;
+ j ++;
+ }
+ n = 0;
+ while ( iName[n] != 0 )
+ {
+ m_text[j] = iName[n++];
+ m_format[j] = font;
+ j ++;
+ }
+ m_text[j] = ' ';
+ m_format[j] = font;
+ j ++;
+ }
+ }
+ while ( buffer[i++] != ';' );
+ continue;
+ }
+ }
+ }
+ m_text[j] = '?';
+ m_format[j] = font;
+ j ++;
+ }
+ while ( buffer[i++] != ';' );
+ }
+ else
+ {
+ if ( m_bSoluce || !bInSoluce )
+ {
+ m_text[j] = buffer[i];
+ if ( m_format != 0 ) m_format[j] = font;
+ j ++;
+ }
+ i ++;
+
+ font &= ~TITLE_MASK; // reset title
+
+ if ( (font&COLOR_MASK) == COLOR_TABLE )
+ {
+ font &= ~COLOR_TABLE;
+ }
+ }
+ }
+ m_len = j;
+ m_imageTotal = iIndex;
+
+ delete buffer;
+
+ Justif();
+ ColumnFix();
+ return TRUE;
+}
+
+// Ecrit tout le texte dans un fichier.
+
+BOOL CEdit::WriteText(char *filename)
+{
+ FILE* file;
+ char buffer[1000+20];
+ int i, j, k, n;
+ float iDim;
+
+ if ( filename[0] == 0 ) return FALSE;
+ file = fopen(filename, "wb");
+ if ( file == NULL ) return FALSE;
+
+ if ( m_bAutoIndent )
+ {
+ iDim = m_dim.x;
+ m_dim.x = 1000.0f; // met une largeur infinie !
+ Justif();
+ }
+
+ i = j = k = 0;
+ while ( m_text[i] != 0 && i < m_len )
+ {
+ if ( m_bAutoIndent && i == m_lineOffset[k] )
+ {
+ for ( n=0 ; n<m_lineIndent[k] ; n++ )
+ {
+ buffer[j++] = '\t';
+ }
+ k ++;
+ }
+
+ buffer[j++] = m_text[i];
+
+ if ( m_text[i] == '\n' )
+ {
+ buffer[j-1] = '\r';
+ buffer[j++] = '\n'; // \r\n (0x0D, 0x0A)
+ }
+
+ if ( j >= 1000-1 )
+ {
+ fwrite(buffer, 1, j, file);
+ j = 0;
+ }
+
+ i ++;
+ }
+ if ( j > 0 )
+ {
+ fwrite(buffer, 1, j, file);
+ }
+
+ fclose(file);
+
+ if ( m_bAutoIndent )
+ {
+ m_dim.x = iDim; // remet la largeur initiale
+ Justif();
+ }
+
+ return TRUE;
+}
+
+
+// Gestion du nombre max de caractères éditables.
+
+void CEdit::SetMaxChar(int max)
+{
+ m_maxChar = max;
+ FreeImage();
+ delete m_text;
+ m_text = (char*)malloc(sizeof(char)*(m_maxChar+1));
+
+ if ( m_format != 0 )
+ {
+ delete m_format;
+ m_format = (char*)malloc(sizeof(char)*m_maxChar);
+ }
+
+ m_len = 0;
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ Justif();
+ UndoFlush();
+}
+
+int CEdit::RetMaxChar()
+{
+ return m_maxChar;
+}
+
+
+// Gestion du mode "éditable".
+
+void CEdit::SetEditCap(BOOL bMode)
+{
+ m_bEdit = bMode;
+}
+
+BOOL CEdit::RetEditCap()
+{
+ return m_bEdit;
+}
+
+// Gestion du mode "hilitable" (ça c'est du franch).
+
+void CEdit::SetHiliteCap(BOOL bEnable)
+{
+ m_bHilite = bEnable;
+}
+
+BOOL CEdit::RetHiliteCap()
+{
+ return m_bHilite;
+}
+
+// Ascenseur dans/hors cadre.
+
+void CEdit::SetInsideScroll(BOOL bInside)
+{
+ m_bInsideScroll = bInside;
+}
+
+BOOL CEdit::RetInsideScroll()
+{
+ return m_bInsideScroll;
+}
+
+// Indique s'il faut afficher les liens montrant la solution.
+
+void CEdit::SetSoluceMode(BOOL bSoluce)
+{
+ m_bSoluce = bSoluce;
+}
+
+BOOL CEdit::RetSoluceMode()
+{
+ return m_bSoluce;
+}
+
+// Indique si le texte est un générique qui défile.
+
+void CEdit::SetGenericMode(BOOL bGeneric)
+{
+ m_bGeneric = bGeneric;
+}
+
+BOOL CEdit::RetGenericMode()
+{
+ return m_bGeneric;
+}
+
+
+// Gestion du mode d'indentation automatique avec { }.
+
+void CEdit::SetAutoIndent(BOOL bMode)
+{
+ m_bAutoIndent = bMode;
+}
+
+BOOL CEdit::RetAutoIndent()
+{
+ return m_bAutoIndent;
+}
+
+
+
+// Déplace les curseurs.
+
+void CEdit::SetCursor(int cursor1, int cursor2)
+{
+ if ( cursor1 > m_len ) cursor1 = m_len;
+ if ( cursor2 > m_len ) cursor2 = m_len;
+
+ m_cursor1 = cursor1;
+ m_cursor2 = cursor2;
+ m_bUndoForce = TRUE;
+ ColumnFix();
+}
+
+// Retourne les curseurs.
+
+void CEdit::GetCursor(int &cursor1, int &cursor2)
+{
+ cursor1 = m_cursor1;
+ cursor2 = m_cursor2;
+}
+
+
+// Modifie la première ligne affichée.
+
+void CEdit::SetFirstLine(int rank)
+{
+ Scroll(rank, TRUE);
+}
+
+// Retourne la première ligne affichée.
+
+int CEdit::RetFirstLine()
+{
+ if ( m_historyTotal > 0 )
+ {
+ if ( m_historyCurrent == 0 )
+ {
+ return m_lineFirst;
+ }
+ else
+ {
+ return m_history[0].firstLine;
+ }
+ }
+ return m_lineFirst;
+}
+
+
+// Montre la zone sélectionnée.
+
+void CEdit::ShowSelect()
+{
+ int cursor1, cursor2, line;
+
+ if ( m_cursor1 < m_cursor2 )
+ {
+ cursor1 = m_cursor1;
+ cursor2 = m_cursor2;
+ }
+ else
+ {
+ cursor1 = m_cursor2;
+ cursor2 = m_cursor1;
+ }
+
+ line = RetCursorLine(cursor2);
+ if ( line >= m_lineFirst+m_lineVisible )
+ {
+ line -= m_lineVisible-1;
+ if ( line < 0 ) line = 0;
+ Scroll(line, FALSE);
+ }
+
+ line = RetCursorLine(cursor1);
+ if ( line < m_lineFirst )
+ {
+ Scroll(line, FALSE);
+ }
+}
+
+
+// Gestion du mode d'affichage des caractères spéciaux.
+
+void CEdit::SetDisplaySpec(BOOL bDisplay)
+{
+ m_bDisplaySpec = bDisplay;
+}
+
+BOOL CEdit::RetDisplaySpec()
+{
+ return m_bDisplaySpec;
+}
+
+
+// Gestion du mode multi-fontes.
+
+void CEdit::SetMultiFont(BOOL bMulti)
+{
+ if ( bMulti )
+ {
+ delete m_format;
+ m_format = (char*)malloc(sizeof(char)*m_maxChar);
+ memset(m_format, 0, m_maxChar);
+ }
+ else
+ {
+ delete m_format;
+ m_format = 0;
+ }
+}
+
+BOOL CEdit::RetMultiFont()
+{
+ return ( m_format != 0 );
+}
+
+
+// Gestion de la taille des caractères.
+
+void CEdit::SetFontSize(float size)
+{
+ CControl::SetFontSize(size);
+
+ MoveAdjust();
+}
+
+
+// Déplace la partie visible selon l'ascenseur.
+
+void CEdit::Scroll()
+{
+ float value;
+
+ if ( m_scroll != 0 )
+ {
+ value = m_scroll->RetVisibleValue();
+ value *= m_lineTotal-m_lineVisible;
+ Scroll((int)(value+0.5f), TRUE);
+ }
+}
+
+// Déplace la partie visible selon l'ascenseur.
+
+void CEdit::Scroll(int pos, BOOL bAdjustCursor)
+{
+ int max, line;
+
+ m_lineFirst = pos;
+
+ if ( m_lineFirst < 0 ) m_lineFirst = 0;
+
+ max = m_lineTotal-m_lineVisible;
+ if ( max < 0 ) max = 0;
+ if ( m_lineFirst > max ) m_lineFirst = max;
+
+ line = RetCursorLine(m_cursor1);
+
+ if ( bAdjustCursor && m_bEdit )
+ {
+ // Curseur trop haut ?
+ if ( line < m_lineFirst )
+ {
+ MoveLine(m_lineFirst-line, FALSE, FALSE);
+ return;
+ }
+
+ // Curseur trop bas ?
+ if ( line >= m_lineFirst+m_lineVisible )
+ {
+ MoveLine(m_lineFirst+m_lineVisible-line-1, FALSE, FALSE);
+ return;
+ }
+ }
+
+ Justif();
+}
+
+// Déplace le curseur au début de la ligne.
+
+void CEdit::MoveHome(BOOL bWord, BOOL bSelect)
+{
+ int begin, tab;
+
+ if ( bWord )
+ {
+ m_cursor1 = 0;
+ }
+ else
+ {
+ begin = m_cursor1;
+ while ( begin > 0 && m_text[begin-1] != '\n' )
+ {
+ begin --;
+ }
+
+ tab = begin;
+ while ( tab < m_len && (m_text[tab] == '\t' || m_text[tab] == ' ') )
+ {
+ tab ++;
+ }
+
+ if ( m_cursor1 == tab )
+ {
+ m_cursor1 = begin;
+ }
+ else
+ {
+ m_cursor1 = tab;
+ }
+ }
+ if ( !bSelect ) m_cursor2 = m_cursor1;
+
+ m_bUndoForce = TRUE;
+ Justif();
+ ColumnFix();
+}
+
+// Déplace le curseur à la fin de la ligne.
+
+void CEdit::MoveEnd(BOOL bWord, BOOL bSelect)
+{
+ if ( bWord )
+ {
+ m_cursor1 = m_len;
+ }
+ else
+ {
+ while ( m_cursor1 < m_len && m_text[m_cursor1] != '\n' )
+ {
+ m_cursor1 ++;
+ }
+ }
+ if ( !bSelect ) m_cursor2 = m_cursor1;
+
+ m_bUndoForce = TRUE;
+ Justif();
+ ColumnFix();
+}
+
+// Déplace le curseur par caractères.
+
+void CEdit::MoveChar(int move, BOOL bWord, BOOL bSelect)
+{
+ int character;
+
+ if ( move == -1 ) // recule ?
+ {
+ if ( bWord )
+ {
+ while ( m_cursor1 > 0 )
+ {
+ character = (unsigned char)m_text[m_cursor1-1];
+ if ( !IsSpace(character) ) break;
+ m_cursor1 --;
+ }
+
+ if ( m_cursor1 > 0 )
+ {
+ character = (unsigned char)m_text[m_cursor1-1];
+ if ( IsSpace(character) )
+ {
+ while ( m_cursor1 > 0 )
+ {
+ character = (unsigned char)m_text[m_cursor1-1];
+ if ( !IsSpace(character) ) break;
+ m_cursor1 --;
+ }
+ }
+ else if ( IsWord(character) )
+ {
+ while ( m_cursor1 > 0 )
+ {
+ character = (unsigned char)m_text[m_cursor1-1];
+ if ( !IsWord(character) ) break;
+ m_cursor1 --;
+ }
+ }
+ else if ( IsSep(character) )
+ {
+ while ( m_cursor1 > 0 )
+ {
+ character = (unsigned char)m_text[m_cursor1-1];
+ if ( !IsSep(character) ) break;
+ m_cursor1 --;
+ }
+ }
+ }
+ }
+ else
+ {
+ m_cursor1 --;
+ if ( m_cursor1 < 0 ) m_cursor1 = 0;
+ }
+ }
+
+ if ( move == 1 ) // avance ?
+ {
+ if ( bWord )
+ {
+ if ( m_cursor1 < m_len )
+ {
+ character = (unsigned char)m_text[m_cursor1];
+ if ( IsSpace(character) )
+ {
+ while ( m_cursor1 < m_len )
+ {
+ character = (unsigned char)m_text[m_cursor1];
+ if ( !IsSpace(character) ) break;
+ m_cursor1 ++;
+ }
+ }
+ else if ( IsWord(character) )
+ {
+ while ( m_cursor1 < m_len )
+ {
+ character = (unsigned char)m_text[m_cursor1];
+ if ( !IsWord(character) ) break;
+ m_cursor1 ++;
+ }
+ }
+ else if ( IsSep(character) )
+ {
+ while ( m_cursor1 < m_len )
+ {
+ character = (unsigned char)m_text[m_cursor1];
+ if ( !IsSep(character) ) break;
+ m_cursor1 ++;
+ }
+ }
+ }
+
+ while ( m_cursor1 < m_len )
+ {
+ character = (unsigned char)m_text[m_cursor1];
+ if ( !IsSpace(character) ) break;
+ m_cursor1 ++;
+ }
+ }
+ else
+ {
+ m_cursor1 ++;
+ if ( m_cursor1 > m_len ) m_cursor1 = m_len;
+ }
+ }
+
+ if ( !bSelect ) m_cursor2 = m_cursor1;
+
+ m_bUndoForce = TRUE;
+ Justif();
+ ColumnFix();
+}
+
+// Déplace le curseur par lignes.
+
+void CEdit::MoveLine(int move, BOOL bWord, BOOL bSelect)
+{
+ float column, indentLength;
+ int i, line, c;
+
+ if ( move == 0 ) return;
+
+ for ( i=0 ; i>move ; i-- ) // recule ?
+ {
+ while ( m_cursor1 > 0 && m_text[m_cursor1-1] != '\n' )
+ {
+ m_cursor1 --;
+ }
+ if ( m_cursor1 != 0 )
+ {
+ m_cursor1 --;
+ while ( m_cursor1 > 0 )
+ {
+ if ( m_text[--m_cursor1] == '\n' )
+ {
+ m_cursor1 ++;
+ break;
+ }
+ }
+ }
+ }
+
+ for ( i=0 ; i<move ; i++ ) // avance ?
+ {
+ while ( m_cursor1 < m_len )
+ {
+ if ( m_text[m_cursor1++] == '\n' )
+ {
+ break;
+ }
+ }
+ }
+
+ line = RetCursorLine(m_cursor1);
+
+ column = m_column;
+ if ( m_bAutoIndent )
+ {
+ indentLength = m_engine->RetText()->RetCharWidth(' ', 0.0f, m_fontSize, m_fontStretch, m_fontType)
+ * m_engine->RetEditIndentValue();
+ column -= indentLength*m_lineIndent[line];
+ }
+
+ if ( m_format == 0 )
+ {
+ c = m_engine->RetText()->Detect(m_text+m_lineOffset[line],
+ m_lineOffset[line+1]-m_lineOffset[line],
+ column, m_fontSize,
+ m_fontStretch, m_fontType);
+ }
+ else
+ {
+ c = m_engine->RetText()->Detect(m_text+m_lineOffset[line],
+ m_format+m_lineOffset[line],
+ m_lineOffset[line+1]-m_lineOffset[line],
+ column, m_fontSize, m_fontStretch);
+ }
+
+ m_cursor1 = m_lineOffset[line]+c;
+ if ( !bSelect ) m_cursor2 = m_cursor1;
+
+ m_bUndoForce = TRUE;
+ Justif();
+}
+
+// Fixe la position horizontale.
+
+void CEdit::ColumnFix()
+{
+ float indentLength;
+ int line;
+
+ line = RetCursorLine(m_cursor1);
+
+ if ( m_format == 0 )
+ {
+ m_column = m_engine->RetText()->RetStringWidth
+ (
+ m_text+m_lineOffset[line],
+ m_cursor1-m_lineOffset[line],
+ m_fontSize, m_fontStretch, m_fontType
+ );
+ }
+ else
+ {
+ m_column = m_engine->RetText()->RetStringWidth
+ (
+ m_text+m_lineOffset[line],
+ m_format+m_lineOffset[line],
+ m_cursor1-m_lineOffset[line],
+ m_fontSize, m_fontStretch
+ );
+ }
+
+ if ( m_bAutoIndent )
+ {
+ indentLength = m_engine->RetText()->RetCharWidth(' ', 0.0f, m_fontSize, m_fontStretch, m_fontType)
+ * m_engine->RetEditIndentValue();
+ m_column += indentLength*m_lineIndent[line];
+ }
+}
+
+
+// Coupe les caractères sélectionnés, ou toute la ligne.
+
+BOOL CEdit::Cut()
+{
+ HGLOBAL hg;
+ char* text;
+ char c;
+ int c1, c2, start, len, i, j;
+
+ if ( !m_bEdit ) return FALSE;
+
+ c1 = m_cursor1;
+ c2 = m_cursor2;
+ if ( c1 > c2 ) Swap(c1, c2); // toujours c1 <= c2
+
+ if ( c1 == c2 )
+ {
+ while ( c1 > 0 )
+ {
+ if ( m_text[c1-1] == '\n' ) break;
+ c1 --;
+ }
+ while ( c2 < m_len )
+ {
+ c2 ++;
+ if ( m_text[c2-1] == '\n' ) break;
+ }
+ }
+
+ if ( c1 == c2 ) return FALSE;
+
+ start = c1;
+ len = c2-c1;
+
+ if ( !(hg = GlobalAlloc(GMEM_DDESHARE, len*2+1)) )
+ {
+ return FALSE;
+ }
+ if ( !(text = (char*)GlobalLock(hg)) )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+
+ j = 0;
+ for ( i=start ; i<start+len ; i++ )
+ {
+ c = m_text[i];
+ if ( c == '\n' ) text[j++] = '\r';
+ text[j++] = c;
+ }
+ text[j] = 0;
+ GlobalUnlock(hg);
+
+ if ( !OpenClipboard(NULL) )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+ if ( !EmptyClipboard() )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+ if ( !SetClipboardData(CF_TEXT, hg) )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+ CloseClipboard();
+
+ UndoMemorize(OPERUNDO_SPEC);
+ m_cursor1 = c1;
+ m_cursor2 = c2;
+ DeleteOne(0); // supprime les caractères sélectionnés
+ Justif();
+ ColumnFix();
+ SendModifEvent();
+ return TRUE;
+}
+
+// Copie les caractères sélectionnés, ou toute la ligne.
+
+BOOL CEdit::Copy()
+{
+ HGLOBAL hg;
+ char* text;
+ char c;
+ int c1, c2, start, len, i, j;
+
+ c1 = m_cursor1;
+ c2 = m_cursor2;
+ if ( c1 > c2 ) Swap(c1, c2); // toujours c1 <= c2
+
+ if ( c1 == c2 )
+ {
+ while ( c1 > 0 )
+ {
+ if ( m_text[c1-1] == '\n' ) break;
+ c1 --;
+ }
+ while ( c2 < m_len )
+ {
+ c2 ++;
+ if ( m_text[c2-1] == '\n' ) break;
+ }
+ }
+
+ if ( c1 == c2 ) return FALSE;
+
+ start = c1;
+ len = c2-c1;
+
+ if ( !(hg = GlobalAlloc(GMEM_DDESHARE, len*2+1)) )
+ {
+ return FALSE;
+ }
+ if ( !(text = (char*)GlobalLock(hg)) )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+
+ j = 0;
+ for ( i=start ; i<start+len ; i++ )
+ {
+ c = m_text[i];
+ if ( c == '\n' ) text[j++] = '\r';
+ text[j++] = c;
+ }
+ text[j] = 0;
+ GlobalUnlock(hg);
+
+ if ( !OpenClipboard(NULL) )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+ if ( !EmptyClipboard() )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+ if ( !SetClipboardData(CF_TEXT, hg) )
+ {
+ GlobalFree(hg);
+ return FALSE;
+ }
+ CloseClipboard();
+
+ return TRUE;
+}
+
+// Colle le contenu du bloc-notes.
+
+BOOL CEdit::Paste()
+{
+ HANDLE h;
+ char c;
+ char* p;
+
+ if ( !m_bEdit ) return FALSE;
+
+ if ( !OpenClipboard(NULL) )
+ {
+ return FALSE;
+ }
+
+ if ( !(h = GetClipboardData(CF_TEXT)) )
+ {
+ CloseClipboard();
+ return FALSE;
+ }
+
+ if ( !(p = (char*)GlobalLock(h)) )
+ {
+ CloseClipboard();
+ return FALSE;
+ }
+
+ UndoMemorize(OPERUNDO_SPEC);
+
+ while ( *p != 0 )
+ {
+ c = *p++;
+ if ( c == '\r' ) continue;
+ if ( c == '\t' && m_bAutoIndent ) continue;
+ InsertOne(c);
+ }
+
+ GlobalUnlock(h);
+ CloseClipboard();
+
+ Justif();
+ ColumnFix();
+ SendModifEvent();
+ return TRUE;
+}
+
+
+// Annule la dernière action.
+
+BOOL CEdit::Undo()
+{
+ if ( !m_bEdit ) return FALSE;
+
+ return UndoRecall();
+}
+
+
+// Insère un caractère.
+
+void CEdit::Insert(char character)
+{
+ int i, level, tab;
+
+ if ( !m_bEdit ) return;
+
+ if ( !m_bMulti ) // mono-ligne ?
+ {
+ if ( character == '\n' ||
+ character == '\t' ) return;
+ }
+
+ UndoMemorize(OPERUNDO_INSERT);
+
+ if ( m_bMulti && !m_bAutoIndent )
+ {
+ if ( character == '\n' )
+ {
+ InsertOne(character);
+ level = IndentCompute();
+ for ( i=0 ; i<level ; i++ )
+ {
+ InsertOne('\t');
+ }
+ }
+ else if ( character == '{' )
+ {
+ tab = IndentTabCount();
+ if ( tab != -1 )
+ {
+ level = IndentCompute();
+ IndentTabAdjust(level-tab);
+ }
+ InsertOne(character);
+ }
+ else if ( character == '}' )
+ {
+ tab = IndentTabCount();
+ if ( tab != -1 )
+ {
+ level = IndentCompute()-1;
+ IndentTabAdjust(level-tab);
+ }
+ InsertOne(character);
+ }
+ else
+ {
+ InsertOne(character);
+ }
+ }
+ else if ( m_bAutoIndent )
+ {
+ if ( character == '{' )
+ {
+ InsertOne(character);
+ InsertOne('\n');
+ InsertOne('\n');
+ InsertOne('}');
+ MoveChar(-1, FALSE, FALSE);
+ MoveChar(-1, FALSE, FALSE);
+ }
+#if 0
+ else if ( character == '(' )
+ {
+ InsertOne(character);
+ InsertOne(')');
+ MoveChar(-1, FALSE, FALSE);
+ }
+ else if ( character == '[' )
+ {
+ InsertOne(character);
+ InsertOne(']');
+ MoveChar(-1, FALSE, FALSE);
+ }
+#endif
+ else if ( character == '\t' )
+ {
+ for ( i=0 ; i<m_engine->RetEditIndentValue() ; i++ )
+ {
+ InsertOne(' ');
+ }
+ }
+ else
+ {
+ InsertOne(character);
+ }
+ }
+ else
+ {
+ InsertOne(character);
+ }
+
+ Justif();
+ ColumnFix();
+}
+
+// Insère un caractère brut.
+
+void CEdit::InsertOne(char character)
+{
+ int i;
+
+ if ( !m_bEdit ) return;
+ if ( !m_bMulti && character == '\n' ) return;
+
+ if ( m_cursor1 != m_cursor2 )
+ {
+ DeleteOne(0); // supprime les caractères sélectionnés
+ }
+
+ if ( m_len >= m_maxChar ) return;
+
+ for ( i=m_len ; i>=m_cursor1 ; i-- )
+ {
+ m_text[i] = m_text[i-1]; // pousse
+
+ if ( m_format != 0 )
+ {
+ m_format[i] = m_format[i-1]; // pousse
+ }
+ }
+
+ m_len ++;
+
+ m_text[m_cursor1] = character;
+
+ if ( m_format != 0 )
+ {
+ m_format[m_cursor1] = 0;
+ }
+
+ m_cursor1++;
+ m_cursor2 = m_cursor1;
+}
+
+// Supprime le caractère à gauche du curseur ou tous les
+// caractères sélectionnés.
+
+void CEdit::Delete(int dir)
+{
+ if ( !m_bEdit ) return;
+
+ UndoMemorize(OPERUNDO_DELETE);
+ DeleteOne(dir);
+
+ Justif();
+ ColumnFix();
+}
+
+// Supprime le caractère à gauche du curseur ou tous les
+// caractères sélectionnés brut.
+
+void CEdit::DeleteOne(int dir)
+{
+ int i, end, hole;
+
+ if ( !m_bEdit ) return;
+
+ if ( m_cursor1 == m_cursor2 )
+ {
+ if ( dir < 0 )
+ {
+ if ( m_cursor1 == 0 ) return;
+ m_cursor1 --;
+ }
+ else
+ {
+ if ( m_cursor2 == m_len ) return;
+ m_cursor2 ++;
+ }
+ }
+
+ if ( m_cursor1 > m_cursor2 ) Swap(m_cursor1, m_cursor2);
+ hole = m_cursor2-m_cursor1;
+ end = m_len-hole;
+ for ( i=m_cursor1 ; i<end ; i++ )
+ {
+ m_text[i] = m_text[i+hole];
+
+ if ( m_format != 0 )
+ {
+ m_format[i] = m_format[i+hole];
+ }
+ }
+ m_len -= hole;
+ m_cursor2 = m_cursor1;
+}
+
+
+// Calcule le niveau d'indentation des crochets { et }.
+
+int CEdit::IndentCompute()
+{
+ int i, level;
+
+ level = 0;
+ for ( i=0 ; i<m_cursor1 ; i++ )
+ {
+ if ( m_text[i] == '{' ) level ++;
+ if ( m_text[i] == '}' ) level --;
+ }
+
+ if ( level < 0 ) level = 0;
+ return level;
+}
+
+// Compte le nombre de tabulateurs avant le curseur.
+// Retourne -1 s'il y a autre chose.
+
+int CEdit::IndentTabCount()
+{
+ int i, nb;
+
+ if ( m_cursor1 != m_cursor2 ) return -1;
+
+ i = m_cursor1;
+ nb = 0;
+ while ( i > 0 )
+ {
+ if ( m_text[i-1] == '\n' ) return nb;
+ if ( m_text[i-1] != '\t' ) return -1;
+ nb ++;
+ i --;
+ }
+ return nb;
+}
+
+// Ajoute ou supprime qq tabulateurs.
+
+void CEdit::IndentTabAdjust(int number)
+{
+ int i;
+
+ for ( i=0 ; i<number ; i++ ) // ajoute ?
+ {
+ InsertOne('\t');
+ }
+
+ for ( i=0 ; i>number ; i-- ) // supprime ?
+ {
+ DeleteOne(-1);
+ }
+}
+
+
+// Indente à gauche ou à droite toute la sélection.
+
+BOOL CEdit::Shift(BOOL bLeft)
+{
+ BOOL bInvert = FALSE;
+ int c1, c2, i;
+
+ if ( m_cursor1 == m_cursor2 ) return FALSE;
+
+ UndoMemorize(OPERUNDO_SPEC);
+
+ c1 = m_cursor1;
+ c2 = m_cursor2;
+ if ( c1 > c2 )
+ {
+ Swap(c1, c2); // toujours c1 <= c2
+ bInvert = TRUE;
+ }
+
+ if ( c1 > 0 )
+ {
+ if ( m_text[c1-1] != '\n' ) return FALSE;
+ }
+ if ( c2 < m_len )
+ {
+ if ( m_text[c2-1] != '\n' ) return FALSE;
+ }
+
+ if ( bLeft ) // décale à gauche ?
+ {
+ i = c1;
+ while ( i < c2 )
+ {
+ if ( m_text[i] == '\t' )
+ {
+ m_cursor1 = i;
+ m_cursor2 = i+1;
+ DeleteOne(0);
+ c2 --;
+ }
+ while ( i < c2 && m_text[i++] != '\n' );
+ }
+ }
+ else // décale à droite ?
+ {
+ i = c1;
+ while ( i < c2 )
+ {
+ m_cursor1 = m_cursor2 = i;
+ InsertOne('\t');
+ c2 ++;
+ while ( i < c2 && m_text[i++] != '\n' );
+ }
+ }
+
+ if ( bInvert ) Swap(c1, c2);
+ m_cursor1 = c1;
+ m_cursor2 = c2;
+
+ Justif();
+ ColumnFix();
+ SendModifEvent();
+ return TRUE;
+}
+
+// Conversion min <-> maj de la sélection.
+
+BOOL CEdit::MinMaj(BOOL bMaj)
+{
+ int c1, c2, i, character;
+
+ if ( m_cursor1 == m_cursor2 ) return FALSE;
+
+ UndoMemorize(OPERUNDO_SPEC);
+
+ c1 = m_cursor1;
+ c2 = m_cursor2;
+ if ( c1 > c2 ) Swap(c1, c2); // toujours c1 <= c2
+
+ for ( i=c1 ; i<c2 ; i++ )
+ {
+ character = (unsigned char)m_text[i];
+ if ( bMaj ) character = RetToUpper(character);
+ else character = RetToLower(character);
+ m_text[i] = character;
+ }
+
+ Justif();
+ ColumnFix();
+ SendModifEvent();
+ return TRUE;
+}
+
+
+// Coupe tout le texte en lignes.
+
+void CEdit::Justif()
+{
+ float width, value, size, indentLength;
+ int i, j, line, indent;
+ BOOL bDual, bString, bRem;
+
+ indent = 0;
+ m_lineTotal = 0;
+ m_lineOffset[m_lineTotal] = 0;
+ m_lineIndent[m_lineTotal] = indent;
+ m_lineTotal ++;
+
+ if ( m_bAutoIndent )
+ {
+ indentLength = m_engine->RetText()->RetCharWidth(' ', 0.0f, m_fontSize, m_fontStretch, m_fontType)
+ * m_engine->RetEditIndentValue();
+ }
+
+ bString = bRem = FALSE;
+ i = 0;
+ while ( TRUE )
+ {
+ bDual = FALSE;
+
+ width = m_dim.x-(10.0f/640.0f)*2.0f-(m_bMulti?MARGX*2.0f+SCROLL_WIDTH:0.0f);
+ if ( m_bAutoIndent )
+ {
+ width -= indentLength*m_lineIndent[m_lineTotal-1];
+ }
+
+ if ( m_format == 0 )
+ {
+ i += m_engine->RetText()->Justif(m_text+i, m_len-i, width,
+ m_fontSize, m_fontStretch,
+ m_fontType);
+ }
+ else
+ {
+ size = m_fontSize;
+
+ if ( (m_format[i]&TITLE_MASK) == TITLE_BIG ) // grand titre ?
+ {
+ size *= BIG_FONT;
+ bDual = TRUE;
+ }
+
+ if ( (m_format[i]&IMAGE_MASK) != 0 ) // tranche d'image ?
+ {
+ i ++; // saute juste un caractère (index dans m_image)
+ }
+ else
+ {
+ i += m_engine->RetText()->Justif(m_text+i, m_format+i,
+ m_len-i, width,
+ size, m_fontStretch);
+ }
+ }
+
+ if ( i >= m_len ) break;
+
+ if ( m_bAutoIndent )
+ {
+ for ( j=m_lineOffset[m_lineTotal-1] ; j<i ; j++ )
+ {
+ if ( !bRem && m_text[j] == '\"' ) bString = !bString;
+ if ( !bString &&
+ m_text[j] == '/' &&
+ m_text[j+1] == '/' ) bRem = TRUE;
+ if ( m_text[j] == '\n' ) bString = bRem = FALSE;
+ if ( m_text[j] == '{' && !bString && !bRem ) indent ++;
+ if ( m_text[j] == '}' && !bString && !bRem ) indent --;
+ }
+ if ( indent < 0 ) indent = 0;
+ }
+
+ m_lineOffset[m_lineTotal] = i;
+ m_lineIndent[m_lineTotal] = indent;
+ m_lineTotal ++;
+ if ( bDual )
+ {
+ m_lineOffset[m_lineTotal] = i;
+ m_lineIndent[m_lineTotal] = indent;
+ m_lineTotal ++;
+ }
+ if ( m_lineTotal >= EDITLINEMAX-2 ) break;
+ }
+ if ( m_len > 0 && m_text[m_len-1] == '\n' )
+ {
+ m_lineOffset[m_lineTotal] = m_len;
+ m_lineIndent[m_lineTotal] = 0;
+ m_lineTotal ++;
+ }
+ m_lineOffset[m_lineTotal] = m_len;
+ m_lineIndent[m_lineTotal] = 0;
+
+ if ( m_bAutoIndent )
+ {
+ for ( i=0 ; i<=m_lineTotal ; i++ )
+ {
+ if ( m_text[m_lineOffset[i]] == '}' )
+ {
+ if ( m_lineIndent[i] > 0 ) m_lineIndent[i] --;
+ }
+ }
+ }
+
+ if ( m_bMulti )
+ {
+ if ( m_bEdit )
+ {
+ line = RetCursorLine(m_cursor1);
+ if ( line < m_lineFirst )
+ {
+ m_lineFirst = line;
+ }
+ if ( line >= m_lineFirst+m_lineVisible )
+ {
+ m_lineFirst = line-m_lineVisible+1;
+ }
+ }
+ }
+ else
+ {
+ m_lineFirst = 0;
+ }
+
+ if ( m_scroll != 0 )
+ {
+ if ( m_lineTotal <= m_lineVisible )
+ {
+ m_scroll->SetVisibleRatio(1.0f);
+ m_scroll->SetVisibleValue(0.0f);
+ m_scroll->SetArrowStep(0.0f);
+ }
+ else
+ {
+ value = (float)m_lineVisible/m_lineTotal;
+ m_scroll->SetVisibleRatio(value);
+
+ value = (float)m_lineFirst/(m_lineTotal-m_lineVisible);
+ m_scroll->SetVisibleValue(value);
+
+ value = (float)1.0f/(m_lineTotal-m_lineVisible);
+ m_scroll->SetArrowStep(value);
+ }
+ }
+
+ m_timeBlink = 0.0f; // allume le curseur immédiatement
+}
+
+// Retourne le rang de la ligne dans laquelle se trouve le curseur.
+
+int CEdit::RetCursorLine(int cursor)
+{
+ int line, i;
+
+ line = 0;
+ for ( i=0 ; i<m_lineTotal ; i++ )
+ {
+ if ( cursor >= m_lineOffset[i] )
+ {
+ line = i;
+ }
+ }
+ return line;
+}
+
+
+// Vide le buffer undo.
+
+void CEdit::UndoFlush()
+{
+ int i;
+
+ for ( i=0 ; i<EDITUNDOMAX ; i++ )
+ {
+ delete m_undo[i].text;
+ m_undo[i].text = 0;
+ }
+
+ m_bUndoForce = TRUE;
+ m_undoOper = OPERUNDO_SPEC;
+}
+
+// Mémorise l'état actuel avant une modification.
+
+void CEdit::UndoMemorize(OperUndo oper)
+{
+ int i, len;
+
+ if ( !m_bUndoForce &&
+ oper != OPERUNDO_SPEC &&
+ m_undoOper != OPERUNDO_SPEC &&
+ oper == m_undoOper ) return;
+
+ m_bUndoForce = FALSE;
+ m_undoOper = oper;
+
+ delete m_undo[EDITUNDOMAX-1].text;
+
+ for ( i=EDITUNDOMAX-1 ; i>=1 ; i-- )
+ {
+ m_undo[i] = m_undo[i-1];
+ }
+
+ len = m_len;
+ if ( len == 0 ) len ++;
+ m_undo[0].text = (char*)malloc(sizeof(char)*(len+1));
+ memcpy(m_undo[0].text, m_text, m_len);
+ m_undo[0].len = m_len;
+
+ m_undo[0].cursor1 = m_cursor1;
+ m_undo[0].cursor2 = m_cursor2;
+ m_undo[0].lineFirst = m_lineFirst;
+}
+
+// Revient à l'état précédent.
+
+BOOL CEdit::UndoRecall()
+{
+ int i;
+
+ if ( m_undo[0].text == 0 ) return FALSE;
+
+ m_len = m_undo[0].len;
+ memcpy(m_text, m_undo[0].text, m_len);
+
+ m_cursor1 = m_undo[0].cursor1;
+ m_cursor2 = m_undo[0].cursor2;
+ m_lineFirst = m_undo[0].lineFirst;
+
+ for ( i=0 ; i<EDITUNDOMAX-1 ; i++ )
+ {
+ m_undo[i] = m_undo[i+1];
+ }
+ m_undo[EDITUNDOMAX-1].text = 0;
+
+ m_bUndoForce = TRUE;
+ Justif();
+ ColumnFix();
+ SendModifEvent();
+ return TRUE;
+}
+
+
+// Efface le format de tous les caractères.
+
+BOOL CEdit::ClearFormat()
+{
+ if ( m_format == 0 )
+ {
+ SetMultiFont(TRUE);
+ }
+ memset(m_format, m_fontType, m_len);
+
+ return TRUE;
+}
+
+// Modifie le format d'une suite de caractères.
+
+BOOL CEdit::SetFormat(int cursor1, int cursor2, int format)
+{
+ int i;
+
+ if ( m_format == 0 ) return FALSE;
+
+ for ( i=cursor1 ; i<cursor2 ; i++ )
+ {
+ m_format[i] |= format;
+ }
+
+ return TRUE;
+}
+
+
diff --git a/src/edit.h b/src/edit.h
new file mode 100644
index 0000000..0cc10e5
--- /dev/null
+++ b/src/edit.h
@@ -0,0 +1,238 @@
+// edit.h
+
+#ifndef _EDIT_H_
+#define _EDIT_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CScroll;
+
+
+
+#define EDITSTUDIOMAX 20000 // nb max de caractères pour éditer CBOT
+#define EDITLINEMAX 1000 // nb max total de lignes
+#define EDITIMAGEMAX 50 // nb max total de lignes avec images
+#define EDITLINKMAX 100 // nb max de liens
+#define EDITHISTORYMAX 50 // nb max de niveaux concervés
+
+#define EDITUNDOMAX 20 // nb max de undo successifs
+
+typedef struct
+{
+ char* text; // texte original
+ int len; // longueur du texte
+ int cursor1; // offset curseur
+ int cursor2; // offset curseur
+ int lineFirst; // première ligne affichée.
+
+}
+EditUndo;
+
+enum OperUndo
+{
+ OPERUNDO_SPEC = 0, // opération spéciale
+ OPERUNDO_INSERT = 1, // insertion de caractères
+ OPERUNDO_DELETE = 2, // suppression de caractères
+};
+
+typedef struct
+{
+ char name[40]; // nom de l'image (sans diagram\)
+ float offset; // offset vertical (v texture)
+ float height; // hauteur de la tranche (dv texture)
+ float width; // largeur
+}
+ImageLine;
+
+typedef struct
+{
+ char name[40]; // nom du fichier texte (sans help\)
+ char marker[20]; // nom du marqueur
+}
+HyperLink;
+
+typedef struct
+{
+ char name[20]; // nom du marqueur
+ int pos; // position dans le texte
+}
+HyperMarker;
+
+typedef struct
+{
+ char filename[50]; // nom complet du fichier texte
+ int firstLine; // rang de la première ligne affichée
+}
+HyperHistory;
+
+
+
+
+class CEdit : public CControl
+{
+public:
+ CEdit(CInstanceManager* iMan);
+ ~CEdit();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ void SetPos(FPOINT pos);
+ void SetDim(FPOINT dim);
+
+ BOOL EventProcess(const Event &event);
+ void Draw();
+
+ void SetText(char *text, BOOL bNew=TRUE);
+ void GetText(char *buffer, int max);
+ char* RetText();
+ int RetTextLength();
+
+ BOOL ReadText(char *filename, int addSize=0);
+ BOOL WriteText(char *filename);
+
+ void SetMaxChar(int max);
+ int RetMaxChar();
+
+ void SetEditCap(BOOL bMode);
+ BOOL RetEditCap();
+
+ void SetHiliteCap(BOOL bEnable);
+ BOOL RetHiliteCap();
+
+ void SetInsideScroll(BOOL bInside);
+ BOOL RetInsideScroll();
+
+ void SetSoluceMode(BOOL bSoluce);
+ BOOL RetSoluceMode();
+
+ void SetGenericMode(BOOL bGeneric);
+ BOOL RetGenericMode();
+
+ void SetAutoIndent(BOOL bMode);
+ BOOL RetAutoIndent();
+
+ void SetCursor(int cursor1, int cursor2);
+ void GetCursor(int &cursor1, int &cursor2);
+
+ void SetFirstLine(int rank);
+ int RetFirstLine();
+ void ShowSelect();
+
+ void SetDisplaySpec(BOOL bDisplay);
+ BOOL RetDisplaySpec();
+
+ void SetMultiFont(BOOL bMulti);
+ BOOL RetMultiFont();
+
+ BOOL Cut();
+ BOOL Copy();
+ BOOL Paste();
+ BOOL Undo();
+
+ void HyperFlush();
+ void HyperHome(char *filename);
+ BOOL HyperTest(EventMsg event);
+ BOOL HyperGo(EventMsg event);
+
+ void SetFontSize(float size);
+
+ BOOL ClearFormat();
+ BOOL SetFormat(int cursor1, int cursor2, int format);
+
+protected:
+ void SendModifEvent();
+ BOOL IsLinkPos(FPOINT pos);
+ void MouseDoubleClick(FPOINT mouse);
+ void MouseClick(FPOINT mouse);
+ void MouseMove(FPOINT mouse);
+ void MouseRelease(FPOINT mouse);
+ int MouseDetect(FPOINT mouse);
+ void MoveAdjust();
+
+ void HyperJump(char *name, char *marker);
+ BOOL HyperAdd(char *filename, int firstLine);
+
+ void DrawImage(FPOINT pos, char *name, float width, float offset, float height, int nbLine);
+ void DrawBack(FPOINT pos, FPOINT dim);
+ void DrawPart(FPOINT pos, FPOINT dim, int icon);
+
+ void FreeImage();
+ void LoadImage(char *name);
+ void Scroll(int pos, BOOL bAdjustCursor);
+ void Scroll();
+ void MoveChar(int move, BOOL bWord, BOOL bSelect);
+ void MoveLine(int move, BOOL bWord, BOOL bSelect);
+ void MoveHome(BOOL bWord, BOOL bSelect);
+ void MoveEnd(BOOL bWord, BOOL bSelect);
+ void ColumnFix();
+ void Insert(char character);
+ void InsertOne(char character);
+ void Delete(int dir);
+ void DeleteOne(int dir);
+ int IndentCompute();
+ int IndentTabCount();
+ void IndentTabAdjust(int number);
+ BOOL Shift(BOOL bLeft);
+ BOOL MinMaj(BOOL bMaj);
+ void Justif();
+ int RetCursorLine(int cursor);
+
+ void UndoFlush();
+ void UndoMemorize(OperUndo oper);
+ BOOL UndoRecall();
+
+protected:
+ CScroll* m_scroll; // ascenseur vertical à droite
+
+ int m_maxChar; // lg max du buffer m_text
+ char* m_text; // texte (sans zéro terminateur)
+ char* m_format; // format des caractères
+ int m_len; // longueur utilisée dans m_text
+ int m_cursor1; // offset curseur
+ int m_cursor2; // offset curseur
+
+ BOOL m_bMulti; // TRUE -> multi lignes
+ BOOL m_bEdit; // TRUE -> éditable
+ BOOL m_bHilite; // TRUE -> hilitable
+ BOOL m_bInsideScroll; // TRUE -> ascenseur dans le cadre
+ BOOL m_bDisplaySpec; // TRUE -> affiche les caractères spéciaux
+ BOOL m_bMultiFont; // TRUE -> plusieurs fontes possible
+ BOOL m_bSoluce; // TRUE -> montre les liens-solution
+ BOOL m_bGeneric; // TRUE -> générique qui défile
+ BOOL m_bAutoIndent; // TRUE -> indentation automatique
+ float m_lineHeight; // hauteur d'une ligne
+ float m_lineAscent; // hauteur au-dessus de la ligne de base
+ float m_lineDescent; // hauteur au-dessous de la ligne de base
+ int m_lineVisible; // nb total de ligne affichables
+ int m_lineFirst; // première ligne affichée
+ int m_lineTotal; // nb lignes utilisées (ds m_lineOffset)
+ int m_lineOffset[EDITLINEMAX];
+ char m_lineIndent[EDITLINEMAX];
+ int m_imageTotal;
+ ImageLine m_image[EDITIMAGEMAX];
+ HyperLink m_link[EDITLINKMAX];
+ int m_markerTotal;
+ HyperMarker m_marker[EDITLINKMAX];
+ int m_historyTotal;
+ int m_historyCurrent;
+ HyperHistory m_history[EDITHISTORYMAX];
+ float m_time; // temps absolu
+ float m_timeBlink;
+ float m_timeLastClick;
+ float m_timeLastScroll;
+ FPOINT m_mouseFirstPos;
+ FPOINT m_mouseLastPos;
+ float m_column;
+
+ BOOL m_bCapture;
+
+ BOOL m_bUndoForce;
+ OperUndo m_undoOper;
+ EditUndo m_undo[EDITUNDOMAX];
+};
+
+
+#endif //_EDIT_H_
diff --git a/src/editvalue.cpp b/src/editvalue.cpp
new file mode 100644
index 0000000..2a881ed
--- /dev/null
+++ b/src/editvalue.cpp
@@ -0,0 +1,368 @@
+// editvalue.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "edit.h"
+#include "button.h"
+#include "editvalue.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CEditValue::CEditValue(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_edit = 0;
+ m_buttonUp = 0;
+ m_buttonDown = 0;
+
+ m_type = EVT_100; // %
+ m_stepValue = 0.1f; // 10%
+ m_minValue = 0.0f; // 0%
+ m_maxValue = 1.0f; // 100%
+}
+
+// Destructeur de l'objet.
+
+CEditValue::~CEditValue()
+{
+ delete m_edit;
+ delete m_buttonUp;
+ delete m_buttonDown;
+
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CEditValue::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CEdit* pe;
+ CButton* pc;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ GlintDelete();
+
+ m_edit = new CEdit(m_iMan);
+ pe = (CEdit*)m_edit;
+ pe->Create(pos, dim, 0, EVENT_NULL);
+ pe->SetMaxChar(4);
+
+ m_buttonUp = new CButton(m_iMan);
+ pc = (CButton*)m_buttonUp;
+ pc->Create(pos, dim, 49, EVENT_NULL); // ^
+ pc->SetRepeat(TRUE);
+
+ m_buttonDown = new CButton(m_iMan);
+ pc = (CButton*)m_buttonDown;
+ pc->Create(pos, dim, 50, EVENT_NULL); // v
+ pc->SetRepeat(TRUE);
+
+ MoveAdjust();
+ return TRUE;
+}
+
+
+void CEditValue::SetPos(FPOINT pos)
+{
+ CControl::SetPos(pos);
+ MoveAdjust();
+}
+
+void CEditValue::SetDim(FPOINT dim)
+{
+ CControl::SetDim(dim);
+ MoveAdjust();
+}
+
+void CEditValue::MoveAdjust()
+{
+ FPOINT pos, dim;
+
+ if ( m_edit != 0 )
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y;
+ dim.x = m_dim.x-m_dim.y*0.6f;
+ dim.y = m_dim.y;
+ m_edit->SetPos(pos);
+ m_edit->SetDim(dim);
+ }
+
+ if ( m_buttonUp != 0 )
+ {
+ pos.x = m_pos.x+m_dim.x-m_dim.y*0.6f;
+ pos.y = m_pos.y+m_dim.y*0.5f;
+ dim.x = m_dim.y*0.6f;
+ dim.y = m_dim.y*0.5f;
+ m_buttonUp->SetPos(pos);
+ m_buttonUp->SetDim(dim);
+ }
+
+ if ( m_buttonDown != 0 )
+ {
+ pos.x = m_pos.x+m_dim.x-m_dim.y*0.6f;
+ pos.y = m_pos.y;
+ dim.x = m_dim.y*0.6f;
+ dim.y = m_dim.y*0.5f;
+ m_buttonDown->SetPos(pos);
+ m_buttonDown->SetDim(dim);
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CEditValue::EventProcess(const Event &event)
+{
+ float value;
+
+ CControl::EventProcess(event);
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+ if ( (m_state & STATE_ENABLE) == 0 ) return TRUE;
+
+ if ( m_edit != 0 )
+ {
+ if ( m_edit->RetFocus() &&
+ event.event == EVENT_KEYDOWN &&
+ event.param == VK_RETURN )
+ {
+ value = RetValue();
+ if ( value > m_maxValue ) value = m_maxValue;
+ if ( value < m_minValue ) value = m_minValue;
+ SetValue(value, TRUE);
+ HiliteValue(event);
+ }
+ if ( !m_edit->EventProcess(event) ) return FALSE;
+
+ if ( event.event == m_edit->RetEventMsg() )
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, m_eventMsg);
+ m_event->AddEvent(newEvent);
+ }
+ }
+
+ if ( m_buttonUp != 0 )
+ {
+ if ( event.event == m_buttonUp->RetEventMsg() )
+ {
+ value = RetValue()+m_stepValue;
+ if ( value > m_maxValue ) value = m_maxValue;
+ SetValue(value, TRUE);
+ HiliteValue(event);
+ }
+ if ( !m_buttonUp->EventProcess(event) ) return FALSE;
+ }
+
+ if ( m_buttonDown != 0 )
+ {
+ if ( event.event == m_buttonDown->RetEventMsg() )
+ {
+ value = RetValue()-m_stepValue;
+ if ( value < m_minValue ) value = m_minValue;
+ SetValue(value, TRUE);
+ HiliteValue(event);
+ }
+ if ( !m_buttonDown->EventProcess(event) ) return FALSE;
+ }
+
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELUP &&
+ Detect(event.pos) )
+ {
+ value = RetValue()+m_stepValue;
+ if ( value > m_maxValue ) value = m_maxValue;
+ SetValue(value, TRUE);
+ HiliteValue(event);
+ }
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELDOWN &&
+ Detect(event.pos) )
+ {
+ value = RetValue()-m_stepValue;
+ if ( value < m_minValue ) value = m_minValue;
+ SetValue(value, TRUE);
+ HiliteValue(event);
+ }
+
+ return TRUE;
+}
+
+
+// Met en évidence la valeur éditée.
+
+void CEditValue::HiliteValue(const Event &event)
+{
+ int pos;
+
+ if ( m_edit == 0 ) return;
+
+ pos = m_edit->RetTextLength();
+ if ( m_type == EVT_100 && pos > 0 )
+ {
+ pos --; // ne sélectionne pas le "%"
+ }
+
+ m_edit->SetCursor(pos, 0);
+ m_edit->SetFocus(TRUE);
+
+ Event newEvent = event;
+ newEvent.event = EVENT_FOCUS;
+ newEvent.param = m_edit->RetEventMsg();
+ m_event->AddEvent(newEvent); // défocus les autres objets
+}
+
+
+// Dessine le bouton.
+
+void CEditValue::Draw()
+{
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ if ( m_edit != 0 )
+ {
+ m_edit->Draw();
+ }
+ if ( m_buttonUp != 0 )
+ {
+ m_buttonUp->Draw();
+ }
+ if ( m_buttonDown != 0 )
+ {
+ m_buttonDown->Draw();
+ }
+}
+
+
+// Choix du type de la valeur.
+
+void CEditValue::SetType(EditValueType type)
+{
+ m_type = type;
+}
+
+EditValueType CEditValue::RetType()
+{
+ return m_type;
+}
+
+
+// Modifie la valeur.
+
+void CEditValue::SetValue(float value, BOOL bSendMessage)
+{
+ char text[100];
+
+ if ( m_edit == 0 ) return;
+
+ text[0] = 0;
+
+ if ( m_type == EVT_INT )
+ {
+ sprintf(text, "%d", (int)value);
+ }
+
+ if ( m_type == EVT_FLOAT )
+ {
+ sprintf(text, "%.2f", value);
+ }
+
+ if ( m_type == EVT_100 )
+ {
+ sprintf(text, "%d%%", (int)(value*100.0f));
+ }
+
+ m_edit->SetText(text);
+
+ if ( bSendMessage )
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, m_eventMsg);
+ m_event->AddEvent(newEvent);
+ }
+}
+
+// Retourne la valeur éditée.
+
+float CEditValue::RetValue()
+{
+ char text[100];
+ float value;
+
+ if ( m_edit == 0 ) 0.0f;
+
+ m_edit->GetText(text, 100);
+ sscanf(text, "%f", &value);
+
+ if ( m_type == EVT_100 )
+ {
+ value = (value+0.5f)/100.0f;
+ if ( value < 0.01f ) value = 0.0f; // moins que 1% ?
+ }
+
+ return value;
+}
+
+
+// Gestion du pas pour les boutons.
+
+void CEditValue::SetStepValue(float value)
+{
+ m_stepValue = value;
+}
+
+float CEditValue::RetStepValue()
+{
+ return m_stepValue;
+}
+
+
+// Gestion de la valeur minimale.
+
+void CEditValue::SetMinValue(float value)
+{
+ m_minValue = value;
+}
+
+float CEditValue::RetMinValue()
+{
+ return m_minValue;
+}
+
+
+// Gestion de la valeur maximale.
+
+void CEditValue::SetMaxValue(float value)
+{
+ m_maxValue = value;
+}
+
+float CEditValue::RetMaxValue()
+{
+ return m_maxValue;
+}
+
diff --git a/src/editvalue.h b/src/editvalue.h
new file mode 100644
index 0000000..bef6f00
--- /dev/null
+++ b/src/editvalue.h
@@ -0,0 +1,69 @@
+// editvalue.h
+
+#ifndef _EDITVALUE_H_
+#define _EDITVALUE_H_
+
+
+#include "control.h"
+
+
+enum EditValueType
+{
+ EVT_INT = 1, // valeur entière
+ EVT_FLOAT = 2, // valeur réelle
+ EVT_100 = 3, // pour-cent (0..1)
+};
+
+
+class CD3DEngine;
+class CEdit;
+class CButton;
+
+
+
+class CEditValue : public CControl
+{
+public:
+ CEditValue(CInstanceManager* iMan);
+ ~CEditValue();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ void SetPos(FPOINT pos);
+ void SetDim(FPOINT dim);
+
+ BOOL EventProcess(const Event &event);
+ void Draw();
+
+ void SetType(EditValueType type);
+ EditValueType RetType();
+
+ void SetValue(float value, BOOL bSendMessage=FALSE);
+ float RetValue();
+
+ void SetStepValue(float value);
+ float RetStepValue();
+
+ void SetMinValue(float value);
+ float RetMinValue();
+
+ void SetMaxValue(float value);
+ float RetMaxValue();
+
+protected:
+ void MoveAdjust();
+ void HiliteValue(const Event &event);
+
+protected:
+ CEdit* m_edit;
+ CButton* m_buttonUp;
+ CButton* m_buttonDown;
+
+ EditValueType m_type;
+ float m_stepValue;
+ float m_minValue;
+ float m_maxValue;
+};
+
+
+#endif //_EDITVALUE_H_
diff --git a/src/event.cpp b/src/event.cpp
new file mode 100644
index 0000000..b3480e0
--- /dev/null
+++ b/src/event.cpp
@@ -0,0 +1,75 @@
+// event.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "struct.h"
+#include "iman.h"
+#include "event.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CEvent::CEvent(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_EVENT, this);
+
+ Flush();
+}
+
+// Destructeur de l'objet.
+
+CEvent::~CEvent()
+{
+}
+
+
+// Vide le fifo des événements.
+
+void CEvent::Flush()
+{
+ m_head = 0;
+ m_tail = 0;
+ m_total = 0;
+}
+
+// Fabrique un événement.
+
+void CEvent::MakeEvent(Event &event, EventMsg msg)
+{
+ ZeroMemory(&event, sizeof(Event));
+ event.event = msg;
+}
+
+// Ajoute un événement dans le fifo.
+
+BOOL CEvent::AddEvent(const Event &event)
+{
+ if ( m_total >= MAXEVENT ) return FALSE;
+
+ m_fifo[m_head++] = event;
+ if ( m_head >= MAXEVENT ) m_head = 0;
+ m_total ++;
+
+ return TRUE;
+}
+
+// Enlève un événement du fifo.
+
+BOOL CEvent::GetEvent(Event &event)
+{
+ if ( m_head == m_tail ) return FALSE;
+
+ event = m_fifo[m_tail++];
+ if ( m_tail >= MAXEVENT ) m_tail = 0;
+ m_total --;
+
+ return TRUE;
+}
+
diff --git a/src/event.h b/src/event.h
new file mode 100644
index 0000000..c9877db
--- /dev/null
+++ b/src/event.h
@@ -0,0 +1,617 @@
+// event.h
+
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+
+#if !defined (WM_XBUTTONDOWN)
+#define WM_XBUTTONDOWN 0x020B
+#define WM_XBUTTONUP 0x020C
+#define XBUTTON1 0x0001
+#define XBUTTON2 0x0002
+#endif
+
+
+
+class CInstanceManager;
+
+
+#define MAXEVENT 100
+
+// Evénements.
+
+enum EventMsg
+{
+ EVENT_NULL = 0,
+
+ 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_UPDINTERFACE = 20,
+ EVENT_WIN = 30,
+ EVENT_LOST = 31,
+
+ EVENT_BUTTON_OK = 40,
+ EVENT_BUTTON_CANCEL = 41,
+ EVENT_BUTTON_NEXT = 42,
+ EVENT_BUTTON_PREV = 43,
+ EVENT_BUTTON_QUIT = 44,
+
+ EVENT_BUTTON0 = 50,
+ EVENT_BUTTON1 = 51,
+ EVENT_BUTTON2 = 52,
+ EVENT_BUTTON3 = 53,
+ EVENT_BUTTON4 = 54,
+ EVENT_BUTTON5 = 55,
+ EVENT_BUTTON6 = 56,
+ EVENT_BUTTON7 = 57,
+ EVENT_BUTTON8 = 58,
+ EVENT_BUTTON9 = 59,
+ EVENT_BUTTON10 = 60,
+ EVENT_BUTTON11 = 61,
+ EVENT_BUTTON12 = 62,
+ EVENT_BUTTON13 = 63,
+ EVENT_BUTTON14 = 64,
+ EVENT_BUTTON15 = 65,
+ EVENT_BUTTON16 = 66,
+ EVENT_BUTTON17 = 67,
+ EVENT_BUTTON18 = 68,
+ EVENT_BUTTON19 = 69,
+
+ EVENT_EDIT0 = 70,
+ EVENT_EDIT1 = 71,
+ EVENT_EDIT2 = 72,
+ EVENT_EDIT3 = 73,
+ EVENT_EDIT4 = 74,
+ EVENT_EDIT5 = 75,
+ EVENT_EDIT6 = 76,
+ EVENT_EDIT7 = 77,
+ EVENT_EDIT8 = 78,
+ EVENT_EDIT9 = 79,
+
+ EVENT_WINDOW0 = 80, // tableau de bord en bas
+ EVENT_WINDOW1 = 81, // map
+ EVENT_WINDOW2 = 82, // CDisplayText
+ EVENT_WINDOW3 = 83, // CStudio
+ EVENT_WINDOW4 = 84, // DisplayInfo
+ EVENT_WINDOW5 = 85, // setup
+ EVENT_WINDOW6 = 86,
+ EVENT_WINDOW7 = 87,
+ EVENT_WINDOW8 = 88,
+ EVENT_WINDOW9 = 89, // dialogue
+
+ EVENT_LABEL0 = 90,
+ EVENT_LABEL1 = 91,
+ EVENT_LABEL2 = 92,
+ EVENT_LABEL3 = 93,
+ EVENT_LABEL4 = 94,
+ EVENT_LABEL5 = 95,
+ EVENT_LABEL6 = 96,
+ EVENT_LABEL7 = 97,
+ EVENT_LABEL8 = 98,
+ EVENT_LABEL9 = 99,
+ EVENT_LABEL10 = 100,
+ EVENT_LABEL11 = 101,
+ EVENT_LABEL12 = 102,
+ EVENT_LABEL13 = 103,
+ EVENT_LABEL14 = 104,
+ EVENT_LABEL15 = 105,
+ EVENT_LABEL16 = 106,
+ EVENT_LABEL17 = 107,
+ EVENT_LABEL18 = 108,
+ EVENT_LABEL19 = 109,
+
+ EVENT_LIST0 = 110,
+ EVENT_LIST1 = 111,
+ EVENT_LIST2 = 112,
+ EVENT_LIST3 = 113,
+ EVENT_LIST4 = 114,
+ EVENT_LIST5 = 115,
+ EVENT_LIST6 = 116,
+ EVENT_LIST7 = 117,
+ EVENT_LIST8 = 118,
+ EVENT_LIST9 = 119,
+
+ EVENT_TOOLTIP = 200,
+
+ EVENT_DIALOG_OK = 300,
+ EVENT_DIALOG_CANCEL = 301,
+ EVENT_DIALOG_LABEL = 302,
+ EVENT_DIALOG_LABEL1 = 303,
+ EVENT_DIALOG_LABEL2 = 304,
+ EVENT_DIALOG_LABEL3 = 305,
+ EVENT_DIALOG_LIST = 306,
+ EVENT_DIALOG_EDIT = 307,
+ EVENT_DIALOG_CHECK1 = 308,
+ EVENT_DIALOG_CHECK2 = 309,
+
+ EVENT_INTERFACE_TRAINER = 400,
+ EVENT_INTERFACE_DEFI = 401,
+ EVENT_INTERFACE_MISSION = 402,
+ EVENT_INTERFACE_FREE = 403,
+ EVENT_INTERFACE_PROTO = 404,
+ EVENT_INTERFACE_NAME = 405,
+ EVENT_INTERFACE_SETUP = 406,
+ EVENT_INTERFACE_QUIT = 407,
+ EVENT_INTERFACE_BACK = 408,
+ EVENT_INTERFACE_AGAIN = 409,
+ EVENT_INTERFACE_WRITE = 410,
+ EVENT_INTERFACE_READ = 411,
+ EVENT_INTERFACE_ABORT = 412,
+ EVENT_INTERFACE_USER = 413,
+ EVENT_INTERFACE_TEEN = 414,
+
+ EVENT_INTERFACE_CHAP = 420,
+ EVENT_INTERFACE_LIST = 421,
+ EVENT_INTERFACE_RESUME = 422,
+ EVENT_INTERFACE_PLAY = 423,
+
+ EVENT_INTERFACE_SETUPd = 430,
+ EVENT_INTERFACE_SETUPg = 431,
+ EVENT_INTERFACE_SETUPp = 432,
+ EVENT_INTERFACE_SETUPc = 433,
+ EVENT_INTERFACE_SETUPs = 434,
+
+ EVENT_INTERFACE_DEVICE = 440,
+ EVENT_INTERFACE_RESOL = 441,
+ EVENT_INTERFACE_FULL = 442,
+ EVENT_INTERFACE_APPLY = 443,
+
+ EVENT_INTERFACE_TOTO = 450,
+ EVENT_INTERFACE_SHADOW = 451,
+ EVENT_INTERFACE_DIRTY = 452,
+ EVENT_INTERFACE_LENS = 453,
+ EVENT_INTERFACE_SKY = 454,
+ EVENT_INTERFACE_PLANET = 456,
+ EVENT_INTERFACE_LIGHT = 457,
+ EVENT_INTERFACE_PARTI = 458,
+ EVENT_INTERFACE_CLIP = 459,
+ EVENT_INTERFACE_DETAIL = 460,
+ EVENT_INTERFACE_TEXTURE = 461,
+ EVENT_INTERFACE_RAIN = 462,
+ EVENT_INTERFACE_GLINT = 463,
+ EVENT_INTERFACE_TOOLTIP = 464,
+ EVENT_INTERFACE_MOVIES = 465,
+ EVENT_INTERFACE_NICERST = 466,
+ EVENT_INTERFACE_SCROLL = 467,
+ EVENT_INTERFACE_INVERTX = 468,
+ EVENT_INTERFACE_INVERTY = 469,
+ EVENT_INTERFACE_EFFECT = 470,
+ EVENT_INTERFACE_MOUSE = 471,
+ EVENT_INTERFACE_GROUND = 472,
+ EVENT_INTERFACE_GADGET = 473,
+ EVENT_INTERFACE_FOG = 474,
+ EVENT_INTERFACE_HIMSELF = 475,
+ EVENT_INTERFACE_EDITMODE= 476,
+ EVENT_INTERFACE_EDITVALUE= 477,
+ EVENT_INTERFACE_SOLUCE4 = 478,
+
+ EVENT_INTERFACE_KINFO1 = 500,
+ EVENT_INTERFACE_KINFO2 = 501,
+ EVENT_INTERFACE_KGROUP = 502,
+ EVENT_INTERFACE_KSCROLL = 503,
+ EVENT_INTERFACE_KDEF = 504,
+ EVENT_INTERFACE_KLEFT = 505,
+ EVENT_INTERFACE_KRIGHT = 506,
+ EVENT_INTERFACE_KUP = 507,
+ EVENT_INTERFACE_KDOWN = 508,
+ EVENT_INTERFACE_KGUP = 509,
+ EVENT_INTERFACE_KGDOWN = 510,
+ EVENT_INTERFACE_KCAMERA = 511,
+ EVENT_INTERFACE_KDESEL = 512,
+ EVENT_INTERFACE_KACTION = 513,
+ EVENT_INTERFACE_KNEAR = 514,
+ EVENT_INTERFACE_KAWAY = 515,
+ EVENT_INTERFACE_KNEXT = 516,
+ EVENT_INTERFACE_KHUMAN = 517,
+ EVENT_INTERFACE_KQUIT = 518,
+ EVENT_INTERFACE_KHELP = 519,
+ EVENT_INTERFACE_KPROG = 520,
+ EVENT_INTERFACE_KCBOT = 521,
+ EVENT_INTERFACE_KVISIT = 522,
+ EVENT_INTERFACE_KSPEED10= 523,
+ EVENT_INTERFACE_KSPEED15= 524,
+ EVENT_INTERFACE_KSPEED20= 525,
+ EVENT_INTERFACE_KSPEED30= 526,
+
+ EVENT_INTERFACE_VOLSOUND= 530,
+ EVENT_INTERFACE_VOLMUSIC= 531,
+ EVENT_INTERFACE_SOUND3D = 532,
+
+ EVENT_INTERFACE_MIN = 540,
+ EVENT_INTERFACE_NORM = 541,
+ EVENT_INTERFACE_MAX = 542,
+
+ EVENT_INTERFACE_SILENT = 550,
+ EVENT_INTERFACE_NOISY = 551,
+
+ EVENT_INTERFACE_JOYSTICK= 560,
+ EVENT_INTERFACE_SOLUCE = 561,
+
+ EVENT_INTERFACE_GLINTl = 570,
+ EVENT_INTERFACE_GLINTr = 571,
+ EVENT_INTERFACE_GLINTu = 572,
+ EVENT_INTERFACE_GLINTb = 573,
+
+ EVENT_INTERFACE_NEDIT = 580,
+ EVENT_INTERFACE_NLIST = 581,
+ EVENT_INTERFACE_NOK = 582,
+ EVENT_INTERFACE_NCANCEL = 583,
+ EVENT_INTERFACE_NDELETE = 584,
+ EVENT_INTERFACE_NLABEL = 585,
+
+ EVENT_INTERFACE_IOWRITE = 600,
+ EVENT_INTERFACE_IOREAD = 601,
+ EVENT_INTERFACE_IOLIST = 602,
+ EVENT_INTERFACE_IONAME = 603,
+ EVENT_INTERFACE_IOLABEL = 604,
+ EVENT_INTERFACE_IOIMAGE = 605,
+ EVENT_INTERFACE_IODELETE= 606,
+
+ EVENT_INTERFACE_PERSO = 620,
+ EVENT_INTERFACE_POK = 621,
+ EVENT_INTERFACE_PCANCEL = 622,
+ EVENT_INTERFACE_PDEF = 623,
+ EVENT_INTERFACE_PHEAD = 624,
+ EVENT_INTERFACE_PBODY = 625,
+ EVENT_INTERFACE_PLROT = 626,
+ EVENT_INTERFACE_PRROT = 627,
+ EVENT_INTERFACE_PC0a = 640,
+ EVENT_INTERFACE_PC1a = 641,
+ EVENT_INTERFACE_PC2a = 642,
+ EVENT_INTERFACE_PC3a = 643,
+ EVENT_INTERFACE_PC4a = 644,
+ EVENT_INTERFACE_PC5a = 645,
+ EVENT_INTERFACE_PC6a = 646,
+ EVENT_INTERFACE_PC7a = 647,
+ EVENT_INTERFACE_PC8a = 648,
+ EVENT_INTERFACE_PC9a = 649,
+ EVENT_INTERFACE_PCRa = 650,
+ EVENT_INTERFACE_PCGa = 651,
+ EVENT_INTERFACE_PCBa = 652,
+ EVENT_INTERFACE_PC0b = 660,
+ EVENT_INTERFACE_PC1b = 661,
+ EVENT_INTERFACE_PC2b = 662,
+ EVENT_INTERFACE_PC3b = 663,
+ EVENT_INTERFACE_PC4b = 664,
+ EVENT_INTERFACE_PC5b = 665,
+ EVENT_INTERFACE_PC6b = 666,
+ EVENT_INTERFACE_PC7b = 667,
+ EVENT_INTERFACE_PC8b = 668,
+ EVENT_INTERFACE_PC9b = 669,
+ EVENT_INTERFACE_PCRb = 670,
+ EVENT_INTERFACE_PCGb = 671,
+ EVENT_INTERFACE_PCBb = 672,
+ EVENT_INTERFACE_PFACE1 = 680,
+ EVENT_INTERFACE_PFACE2 = 681,
+ EVENT_INTERFACE_PFACE3 = 682,
+ EVENT_INTERFACE_PFACE4 = 683,
+ EVENT_INTERFACE_PGLASS0 = 690,
+ EVENT_INTERFACE_PGLASS1 = 691,
+ EVENT_INTERFACE_PGLASS2 = 692,
+ EVENT_INTERFACE_PGLASS3 = 693,
+ EVENT_INTERFACE_PGLASS4 = 694,
+ EVENT_INTERFACE_PGLASS5 = 695,
+ EVENT_INTERFACE_PGLASS6 = 696,
+ EVENT_INTERFACE_PGLASS7 = 697,
+ EVENT_INTERFACE_PGLASS8 = 698,
+ EVENT_INTERFACE_PGLASS9 = 699,
+
+ EVENT_DT_GROUP0 = 700,
+ EVENT_DT_GROUP1 = 701,
+ EVENT_DT_GROUP2 = 702,
+ EVENT_DT_GROUP3 = 703,
+ EVENT_DT_GROUP4 = 704,
+ EVENT_DT_LABEL0 = 710,
+ EVENT_DT_LABEL1 = 711,
+ EVENT_DT_LABEL2 = 712,
+ EVENT_DT_LABEL3 = 713,
+ EVENT_DT_LABEL4 = 714,
+ EVENT_DT_VISIT0 = 720,
+ EVENT_DT_VISIT1 = 721,
+ EVENT_DT_VISIT2 = 722,
+ EVENT_DT_VISIT3 = 723,
+ EVENT_DT_VISIT4 = 724,
+ EVENT_DT_END = 725,
+
+ EVENT_CMD = 800,
+ EVENT_SPEED = 801,
+
+ EVENT_HYPER_PREV = 900,
+ EVENT_HYPER_NEXT = 901,
+ EVENT_HYPER_HOME = 902,
+ EVENT_HYPER_COPY = 903,
+ EVENT_HYPER_SIZE1 = 904,
+ EVENT_HYPER_SIZE2 = 905,
+ EVENT_HYPER_SIZE3 = 906,
+ EVENT_HYPER_SIZE4 = 907,
+ EVENT_HYPER_SIZE5 = 908,
+
+ EVENT_SATCOM_HUSTON = 920,
+ EVENT_SATCOM_SAT = 921,
+ EVENT_SATCOM_LOADING = 922,
+ EVENT_SATCOM_OBJECT = 923,
+ EVENT_SATCOM_PROG = 924,
+ EVENT_SATCOM_SOLUCE = 925,
+
+ EVENT_OBJECT_DESELECT = 1000,
+ EVENT_OBJECT_LEFT = 1001,
+ EVENT_OBJECT_RIGHT = 1002,
+ EVENT_OBJECT_UP = 1003,
+ EVENT_OBJECT_DOWN = 1004,
+ EVENT_OBJECT_GASUP = 1005,
+ EVENT_OBJECT_GASDOWN = 1006,
+ EVENT_OBJECT_HTAKE = 1020,
+ EVENT_OBJECT_MTAKE = 1021,
+ EVENT_OBJECT_MFRONT = 1022,
+ EVENT_OBJECT_MBACK = 1023,
+ EVENT_OBJECT_MPOWER = 1024,
+ EVENT_OBJECT_BHELP = 1040,
+ EVENT_OBJECT_BTAKEOFF = 1041,
+ EVENT_OBJECT_BDERRICK = 1050,
+ EVENT_OBJECT_BSTATION = 1051,
+ EVENT_OBJECT_BFACTORY = 1052,
+ EVENT_OBJECT_BCONVERT = 1053,
+ EVENT_OBJECT_BTOWER = 1054,
+ EVENT_OBJECT_BREPAIR = 1055,
+ EVENT_OBJECT_BRESEARCH = 1056,
+ EVENT_OBJECT_BRADAR = 1057,
+ EVENT_OBJECT_BENERGY = 1058,
+ EVENT_OBJECT_BLABO = 1059,
+ EVENT_OBJECT_BNUCLEAR = 1060,
+ EVENT_OBJECT_BPARA = 1061,
+ EVENT_OBJECT_BINFO = 1062,
+ EVENT_OBJECT_BXXXX = 1063,
+ EVENT_OBJECT_GFLAT = 1070,
+ EVENT_OBJECT_FCREATE = 1071,
+ EVENT_OBJECT_FDELETE = 1072,
+ EVENT_OBJECT_FCOLORb = 1073,
+ EVENT_OBJECT_FCOLORr = 1074,
+ EVENT_OBJECT_FCOLORg = 1075,
+ EVENT_OBJECT_FCOLORy = 1076,
+ EVENT_OBJECT_FCOLORv = 1077,
+ EVENT_OBJECT_FACTORYwa = 1080,
+ EVENT_OBJECT_FACTORYta = 1081,
+ EVENT_OBJECT_FACTORYfa = 1082,
+ EVENT_OBJECT_FACTORYia = 1083,
+ EVENT_OBJECT_FACTORYwc = 1084,
+ EVENT_OBJECT_FACTORYtc = 1085,
+ EVENT_OBJECT_FACTORYfc = 1086,
+ EVENT_OBJECT_FACTORYic = 1087,
+ EVENT_OBJECT_FACTORYwi = 1088,
+ EVENT_OBJECT_FACTORYti = 1089,
+ EVENT_OBJECT_FACTORYfi = 1090,
+ EVENT_OBJECT_FACTORYii = 1091,
+ EVENT_OBJECT_FACTORYws = 1092,
+ EVENT_OBJECT_FACTORYts = 1093,
+ EVENT_OBJECT_FACTORYfs = 1094,
+ EVENT_OBJECT_FACTORYis = 1095,
+ EVENT_OBJECT_FACTORYrt = 1096,
+ EVENT_OBJECT_FACTORYrc = 1097,
+ EVENT_OBJECT_FACTORYrr = 1098,
+ EVENT_OBJECT_FACTORYrs = 1099,
+ EVENT_OBJECT_FACTORYsa = 1100,
+ EVENT_OBJECT_SEARCH = 1200,
+ EVENT_OBJECT_TERRAFORM = 1201,
+ EVENT_OBJECT_FIRE = 1202,
+ EVENT_OBJECT_FIREANT = 1203,
+ EVENT_OBJECT_RECOVER = 1220,
+ EVENT_OBJECT_BEGSHIELD = 1221,
+ EVENT_OBJECT_ENDSHIELD = 1222,
+ EVENT_OBJECT_RTANK = 1223,
+ EVENT_OBJECT_RFLY = 1224,
+ EVENT_OBJECT_RTHUMP = 1225,
+ EVENT_OBJECT_RCANON = 1226,
+ EVENT_OBJECT_RTOWER = 1227,
+ EVENT_OBJECT_RPHAZER = 1228,
+ EVENT_OBJECT_RSHIELD = 1229,
+ EVENT_OBJECT_RATOMIC = 1230,
+ EVENT_OBJECT_RiPAW = 1231,
+ EVENT_OBJECT_RiGUN = 1232,
+ EVENT_OBJECT_RESET = 1233,
+ EVENT_OBJECT_DIMSHIELD = 1234,
+ EVENT_OBJECT_TARGET = 1235,
+ EVENT_OBJECT_PROGLIST = 1310,
+ EVENT_OBJECT_PROGRUN = 1311,
+ EVENT_OBJECT_PROGEDIT = 1312,
+ EVENT_OBJECT_PROGSTART = 1313,
+ EVENT_OBJECT_PROGSTOP = 1314,
+ EVENT_OBJECT_INFOOK = 1340,
+ EVENT_OBJECT_DELETE = 1350,
+ EVENT_OBJECT_GENERGY = 1360,
+ EVENT_OBJECT_GSHIELD = 1361,
+ EVENT_OBJECT_GRANGE = 1362,
+ EVENT_OBJECT_COMPASS = 1363,
+ EVENT_OBJECT_MAP = 1364,
+ EVENT_OBJECT_MAPZOOM = 1365,
+ EVENT_OBJECT_GPROGRESS = 1366,
+ EVENT_OBJECT_GRADAR = 1367,
+ EVENT_OBJECT_GINFO = 1368,
+ EVENT_OBJECT_TYPE = 1369,
+ EVENT_OBJECT_CROSSHAIR = 1370,
+ EVENT_OBJECT_CORNERul = 1371,
+ EVENT_OBJECT_CORNERur = 1372,
+ EVENT_OBJECT_CORNERdl = 1373,
+ EVENT_OBJECT_CORNERdr = 1374,
+ EVENT_OBJECT_MAPi = 1375,
+ EVENT_OBJECT_MAPg = 1376,
+ EVENT_OBJECT_CAMERA = 1400,
+ EVENT_OBJECT_HELP = 1401,
+ EVENT_OBJECT_SOLUCE = 1402,
+ EVENT_OBJECT_CAMERAleft = 1403,
+ EVENT_OBJECT_CAMERAright= 1404,
+ EVENT_OBJECT_CAMERAnear = 1405,
+ EVENT_OBJECT_CAMERAaway = 1406,
+ EVENT_OBJECT_SHORTCUT00 = 1500,
+ EVENT_OBJECT_SHORTCUT01 = 1501,
+ EVENT_OBJECT_SHORTCUT02 = 1502,
+ EVENT_OBJECT_SHORTCUT03 = 1503,
+ EVENT_OBJECT_SHORTCUT04 = 1504,
+ EVENT_OBJECT_SHORTCUT05 = 1505,
+ EVENT_OBJECT_SHORTCUT06 = 1506,
+ EVENT_OBJECT_SHORTCUT07 = 1507,
+ EVENT_OBJECT_SHORTCUT08 = 1508,
+ EVENT_OBJECT_SHORTCUT09 = 1509,
+ EVENT_OBJECT_SHORTCUT10 = 1510,
+ EVENT_OBJECT_SHORTCUT11 = 1511,
+ EVENT_OBJECT_SHORTCUT12 = 1512,
+ EVENT_OBJECT_SHORTCUT13 = 1513,
+ EVENT_OBJECT_SHORTCUT14 = 1514,
+ EVENT_OBJECT_SHORTCUT15 = 1515,
+ EVENT_OBJECT_SHORTCUT16 = 1516,
+ EVENT_OBJECT_SHORTCUT17 = 1517,
+ EVENT_OBJECT_SHORTCUT18 = 1518,
+ EVENT_OBJECT_SHORTCUT19 = 1519,
+ EVENT_OBJECT_MOVIELOCK = 1550,
+ EVENT_OBJECT_EDITLOCK = 1551,
+ EVENT_OBJECT_LIMIT = 1560,
+
+ EVENT_OBJECT_PEN0 = 1570,
+ EVENT_OBJECT_PEN1 = 1571,
+ EVENT_OBJECT_PEN2 = 1572,
+ EVENT_OBJECT_PEN3 = 1573,
+ EVENT_OBJECT_PEN4 = 1574,
+ EVENT_OBJECT_PEN5 = 1575,
+ EVENT_OBJECT_PEN6 = 1576,
+ EVENT_OBJECT_PEN7 = 1577,
+ EVENT_OBJECT_PEN8 = 1578,
+ EVENT_OBJECT_REC = 1580,
+ EVENT_OBJECT_STOP = 1581,
+
+ EVENT_STUDIO_OK = 2000,
+ EVENT_STUDIO_CANCEL = 2001,
+ EVENT_STUDIO_EDIT = 2002,
+ EVENT_STUDIO_LIST = 2003,
+ EVENT_STUDIO_NEW = 2010,
+ EVENT_STUDIO_OPEN = 2011,
+ EVENT_STUDIO_SAVE = 2012,
+ EVENT_STUDIO_UNDO = 2013,
+ EVENT_STUDIO_CUT = 2014,
+ EVENT_STUDIO_COPY = 2015,
+ EVENT_STUDIO_PASTE = 2016,
+ EVENT_STUDIO_SIZE = 2017,
+ EVENT_STUDIO_TOOL = 2018,
+ EVENT_STUDIO_HELP = 2019,
+ EVENT_STUDIO_COMPILE = 2050,
+ EVENT_STUDIO_RUN = 2051,
+ EVENT_STUDIO_REALTIME = 2052,
+ EVENT_STUDIO_STEP = 2053,
+
+ EVENT_USER = 10000,
+ EVENT_FORCE_DWORD = 0x7fffffff
+};
+
+typedef struct
+{
+ EventMsg event; // événement (EVENT_*)
+ long param; // paramètre
+ FPOINT pos; // position de la souris (0..1)
+ float axeX; // commande de l'axe X (-1..1)
+ float axeY; // commande de l'axe Y (-1..1)
+ float axeZ; // commande de l'axe Z (-1..1)
+ short keyState; // état du clavier (KS_*)
+ float rTime; // temps relatif
+}
+Event;
+
+
+#define VK_BUTTON1 (0x100+1) // joystick button 1
+#define VK_BUTTON2 (0x100+2) // joystick button 2
+#define VK_BUTTON3 (0x100+3) // joystick button 3
+#define VK_BUTTON4 (0x100+4) // joystick button 4
+#define VK_BUTTON5 (0x100+5) // joystick button 5
+#define VK_BUTTON6 (0x100+6) // joystick button 6
+#define VK_BUTTON7 (0x100+7) // joystick button 7
+#define VK_BUTTON8 (0x100+8) // joystick button 8
+#define VK_BUTTON9 (0x100+9) // joystick button 9
+#define VK_BUTTON10 (0x100+10) // joystick button 10
+#define VK_BUTTON11 (0x100+11) // joystick button 11
+#define VK_BUTTON12 (0x100+12) // joystick button 12
+#define VK_BUTTON13 (0x100+13) // joystick button 13
+#define VK_BUTTON14 (0x100+14) // joystick button 14
+#define VK_BUTTON15 (0x100+15) // joystick button 15
+#define VK_BUTTON16 (0x100+16) // joystick button 16
+#define VK_BUTTON17 (0x100+17) // joystick button 17
+#define VK_BUTTON18 (0x100+18) // joystick button 18
+#define VK_BUTTON19 (0x100+19) // joystick button 19
+#define VK_BUTTON20 (0x100+20) // joystick button 20
+#define VK_BUTTON21 (0x100+21) // joystick button 21
+#define VK_BUTTON22 (0x100+22) // joystick button 22
+#define VK_BUTTON23 (0x100+23) // joystick button 23
+#define VK_BUTTON24 (0x100+24) // joystick button 24
+#define VK_BUTTON25 (0x100+25) // joystick button 25
+#define VK_BUTTON26 (0x100+26) // joystick button 26
+#define VK_BUTTON27 (0x100+27) // joystick button 27
+#define VK_BUTTON28 (0x100+28) // joystick button 28
+#define VK_BUTTON29 (0x100+29) // joystick button 29
+#define VK_BUTTON30 (0x100+30) // joystick button 30
+#define VK_BUTTON31 (0x100+31) // joystick button 31
+#define VK_BUTTON32 (0x100+32) // joystick button 32
+
+#define VK_WHEELUP (0x200+1) // molette souris up
+#define VK_WHEELDOWN (0x200+2) // molette souris down
+
+
+enum KeyRank
+{
+ KEYRANK_LEFT = 0,
+ KEYRANK_RIGHT = 1,
+ KEYRANK_UP = 2,
+ KEYRANK_DOWN = 3,
+ KEYRANK_GUP = 4,
+ KEYRANK_GDOWN = 5,
+ KEYRANK_CAMERA = 6,
+ KEYRANK_DESEL = 7,
+ KEYRANK_ACTION = 8,
+ KEYRANK_NEAR = 9,
+ KEYRANK_AWAY = 10,
+ KEYRANK_NEXT = 11,
+ KEYRANK_HUMAN = 12,
+ KEYRANK_QUIT = 13,
+ KEYRANK_HELP = 14,
+ KEYRANK_PROG = 15,
+ KEYRANK_VISIT = 16,
+ KEYRANK_SPEED10 = 17,
+ KEYRANK_SPEED15 = 18,
+ KEYRANK_SPEED20 = 19,
+ KEYRANK_SPEED30 = 20,
+ KEYRANK_AIMUP = 21,
+ KEYRANK_AIMDOWN = 22,
+ KEYRANK_CBOT = 23,
+};
+
+
+
+class CEvent
+{
+public:
+ CEvent(CInstanceManager* iMan);
+ ~CEvent();
+
+ void Flush();
+ void MakeEvent(Event &event, EventMsg msg);
+ BOOL AddEvent(const Event &event);
+ BOOL GetEvent(Event &event);
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+
+ Event m_fifo[MAXEVENT];
+ int m_head;
+ int m_tail;
+ int m_total;
+};
+
+
+#endif //_EVENT_H_
diff --git a/src/gauge.cpp b/src/gauge.cpp
new file mode 100644
index 0000000..8f3d5bd
--- /dev/null
+++ b/src/gauge.cpp
@@ -0,0 +1,146 @@
+// gauge.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "gauge.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CGauge::CGauge(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_level = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CGauge::~CGauge()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CGauge::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CGauge::EventProcess(const Event &event)
+{
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Dessine la jauge.
+
+void CGauge::Draw()
+{
+ FPOINT pos, dim, ddim, uv1, uv2, corner;
+ float dp;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ dp = 0.5f/256.0f;
+
+ pos = m_pos;
+ dim = m_dim;
+
+ uv1.x = 32.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 64.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ corner.x = 10.0f/640.0f;
+ corner.y = 10.0f/480.0f;
+
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
+
+
+ pos.x += 3.0f/640.0f;
+ pos.y += 3.0f/480.0f;
+ dim.x -= 6.0f/640.0f;
+ dim.y -= 6.0f/480.0f;
+
+ if ( m_dim.x < m_dim.y ) // jauge verticale ?
+ {
+ uv1.x = (0.0f+m_icon*16.0f)/256.0f;
+ uv2.x = uv1.x+16.0f/256.0f;
+ uv1.y = 128.0f/256.0f+m_level*(64.0f/256.0f);
+ uv2.y = uv1.y+64.0f/256.0f;
+ }
+ else // jauge horizontale ?
+ {
+ uv1.x = 64.0f/256.0f+(1.0f-m_level)*(64.0f/256.0f);
+ uv2.x = uv1.x+64.0f/256.0f;
+ uv1.y = (128.0f+m_icon*16.0f)/256.0f;
+ uv2.y = uv1.y+16.0f/256.0f;
+ }
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(pos, dim, uv1, uv2);
+}
+
+
+// Gestion du niveau de la jauge.
+
+void CGauge::SetLevel(float level)
+{
+ if ( level < 0.0f ) level = 0.0f;
+ if ( level > 1.0f ) level = 1.0f;
+ m_level = level;
+}
+
+float CGauge::RetLevel()
+{
+ return m_level;
+}
+
+
diff --git a/src/gauge.h b/src/gauge.h
new file mode 100644
index 0000000..5813268
--- /dev/null
+++ b/src/gauge.h
@@ -0,0 +1,36 @@
+// gauge.h
+
+#ifndef _GAUGE_H_
+#define _GAUGE_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CGauge : public CControl
+{
+public:
+ CGauge(CInstanceManager* iMan);
+ ~CGauge();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+ void SetLevel(float level);
+ float RetLevel();
+
+protected:
+
+protected:
+ float m_level;
+};
+
+
+#endif //_GAUGE_H_
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..5ed5128
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,48 @@
+// global.h
+
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_
+
+
+#define BUILD_FACTORY (1<<0) // usine
+#define BUILD_DERRICK (1<<1) // derrick
+#define BUILD_CONVERT (1<<2) // convertisseur
+#define BUILD_RADAR (1<<3) // radar
+#define BUILD_ENERGY (1<<4) // fabrique à pile
+#define BUILD_NUCLEAR (1<<5) // centrale nucléaire
+#define BUILD_STATION (1<<6) // station de recharge
+#define BUILD_REPAIR (1<<7) // centre de réparation
+#define BUILD_TOWER (1<<8) // tour de défense
+#define BUILD_RESEARCH (1<<9) // centre de recherche
+#define BUILD_LABO (1<<10) // laboratoire
+#define BUILD_PARA (1<<11) // paratonnerre
+#define BUILD_INFO (1<<12) // borne d'information
+#define BUILD_GFLAT (1<<16) // montre le sol plat
+#define BUILD_FLAG (1<<17) // met/enlève drapeau de couleur
+
+
+// Ne pas changer les valeurs à cause des sauvegardes (bits=...).
+
+#define RESEARCH_TANK (1<<0) // chenilles
+#define RESEARCH_FLY (1<<1) // ailes
+#define RESEARCH_CANON (1<<2) // canon
+#define RESEARCH_TOWER (1<<3) // tour de défense
+#define RESEARCH_ATOMIC (1<<4) // nucléaire
+#define RESEARCH_THUMP (1<<5) // thumper
+#define RESEARCH_SHIELD (1<<6) // bouclier
+#define RESEARCH_PHAZER (1<<7) // canon phazer
+#define RESEARCH_iPAW (1<<8) // pattes des insectes
+#define RESEARCH_iGUN (1<<9) // canon des insectes
+#define RESEARCH_RECYCLER (1<<10) // recycleur
+#define RESEARCH_SUBM (1<<11) // sous-marin
+#define RESEARCH_SNIFFER (1<<12) // sniffeur
+
+extern long g_id; // identificateur unique
+extern long g_build; // bâtiments constructibles
+extern long g_researchDone; // recherches effectuées
+extern long g_researchEnable; // recherches accessbles
+extern float g_unit; // facteur de conversion
+
+
+
+#endif //_GLOBAL_H_
diff --git a/src/group.cpp b/src/group.cpp
new file mode 100644
index 0000000..82a0e0d
--- /dev/null
+++ b/src/group.cpp
@@ -0,0 +1,632 @@
+// group.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "group.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CGroup::CGroup(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+}
+
+// Destructeur de l'objet.
+
+CGroup::~CGroup()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CGroup::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ if ( icon == -1 )
+ {
+ char name[100];
+ char* p;
+
+ GetResource(RES_EVENT, eventMsg, name);
+ p = strchr(name, '\\');
+ if ( p != 0 ) *p = 0;
+ SetName(name);
+ }
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CGroup::EventProcess(const Event &event)
+{
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CGroup::Draw()
+{
+ FPOINT uv1,uv2, corner, pos, dim;
+ float dp;
+ int icon;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ dp = 0.5f/256.0f;
+
+ if ( m_icon == 0 ) // cadre en creux ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 160.0f/256.0f;
+ uv1.y = 192.0f/256.0f; // u-v texture
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 10.0f/640.0f;
+ corner.y = 10.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+ if ( m_icon == 1 ) // orange uni opaque ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 104.0f/256.0f;
+ uv1.y = 48.0f/256.0f;
+ uv2.x = 112.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 2 ) // dégradé orange -> transparent ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 112.0f/256.0f;
+ uv1.y = 48.0f/256.0f;
+ uv2.x = 120.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 3 ) // dégradé transparent -> gris ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 120.0f/256.0f;
+ uv1.y = 48.0f/256.0f;
+ uv2.x = 128.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 4 ) // coin bleu dégradé ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 192.0f/256.0f;
+ uv1.y = 128.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 160.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 5 ) // coin orange dégradé ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 224.0f/256.0f;
+ uv1.y = 128.0f/256.0f;
+ uv2.x = 256.0f/256.0f;
+ uv2.y = 160.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 6 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 0.0f/256.0f; // brun transparent
+ uv1.y = 75.0f/256.0f;
+ uv2.x = 64.0f/256.0f;
+ uv2.y = 128.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 4.0f/640.0f;
+ corner.y = 4.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+ if ( m_icon == 7 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2, 8.0f/256.0f);
+ }
+ if ( m_icon == 8 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // vert transparent
+ uv1.y = 160.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 176.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2, 8.0f/256.0f);
+ }
+ if ( m_icon == 9 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // rouge transparent
+ uv1.y = 176.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 192.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2, 8.0f/256.0f);
+ }
+ if ( m_icon == 10 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // bleu transparent
+ uv1.y = 192.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 208.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2, 8.0f/256.0f);
+ }
+ if ( m_icon == 11 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // jaune transparent
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 240.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2, 8.0f/256.0f);
+ }
+ if ( m_icon == 12 ) // viseur en croix ?
+ {
+ dim.x = m_dim.x/2.0f;
+ dim.y = m_dim.y/2.0f;
+
+ m_engine->SetTexture("mouse.tga");
+ m_engine->SetState(D3DSTATETTb);
+ pos.x = m_pos.x-m_dim.x/300.0f;
+ pos.y = m_pos.y+m_dim.y/300.0f+dim.y;
+ uv1.x = 0.5f/256.0f;
+ uv1.y = 192.5f/256.0f;
+ uv2.x = 63.5f/256.0f;
+ uv2.y = 255.5f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2); // ul
+ pos.x += dim.x;
+ Swap(uv1.x, uv2.x);
+ DrawIcon(pos, dim, uv1, uv2); // ur
+ pos.y -= dim.y;
+ Swap(uv1.y, uv2.y);
+ DrawIcon(pos, dim, uv1, uv2); // dr
+ pos.x -= dim.x;
+ Swap(uv1.x, uv2.x);
+ DrawIcon(pos, dim, uv1, uv2); // dl
+
+ m_engine->SetState(D3DSTATETTw);
+ pos.x = m_pos.x+m_dim.x/300.0f;
+ pos.y = m_pos.y-m_dim.y/300.0f+dim.y;
+ uv1.x = 64.5f/256.0f;
+ uv1.y = 192.5f/256.0f;
+ uv2.x = 127.5f/256.0f;
+ uv2.y = 255.5f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2); // ul
+ pos.x += dim.x;
+ Swap(uv1.x, uv2.x);
+ DrawIcon(pos, dim, uv1, uv2); // ur
+ pos.y -= dim.y;
+ Swap(uv1.y, uv2.y);
+ DrawIcon(pos, dim, uv1, uv2); // dr
+ pos.x -= dim.x;
+ Swap(uv1.x, uv2.x);
+ DrawIcon(pos, dim, uv1, uv2); // dl
+ }
+ if ( m_icon == 13 ) // coin sup/gauche ?
+ {
+ m_engine->SetTexture("mouse.tga");
+ m_engine->SetState(D3DSTATETTb);
+ pos.x = m_pos.x-m_dim.x/150.0f;
+ pos.y = m_pos.y+m_dim.y/150.0f;
+ uv1.x = 128.5f/256.0f;
+ uv1.y = 192.5f/256.0f;
+ uv2.x = 191.5f/256.0f;
+ uv2.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+
+ m_engine->SetState(D3DSTATETTw);
+ pos.x = m_pos.x+m_dim.x/150.0f;
+ pos.y = m_pos.y-m_dim.y/150.0f;
+ uv1.x = 192.5f/256.0f;
+ uv1.y = 192.5f/256.0f;
+ uv2.x = 255.5f/256.0f;
+ uv2.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 14 ) // coin sup/droite ?
+ {
+ m_engine->SetTexture("mouse.tga");
+ m_engine->SetState(D3DSTATETTb);
+ pos.x = m_pos.x-m_dim.x/150.0f;
+ pos.y = m_pos.y+m_dim.y/150.0f;
+ uv2.x = 128.5f/256.0f;
+ uv1.y = 192.5f/256.0f;
+ uv1.x = 191.5f/256.0f;
+ uv2.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+
+ m_engine->SetState(D3DSTATETTw);
+ pos.x = m_pos.x+m_dim.x/150.0f;
+ pos.y = m_pos.y-m_dim.y/150.0f;
+ uv2.x = 192.5f/256.0f;
+ uv1.y = 192.5f/256.0f;
+ uv1.x = 255.5f/256.0f;
+ uv2.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 15 ) // coin inf/gauche ?
+ {
+ m_engine->SetTexture("mouse.tga");
+ m_engine->SetState(D3DSTATETTb);
+ pos.x = m_pos.x-m_dim.x/150.0f;
+ pos.y = m_pos.y+m_dim.y/150.0f;
+ uv1.x = 128.5f/256.0f;
+ uv2.y = 192.5f/256.0f;
+ uv2.x = 191.5f/256.0f;
+ uv1.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+
+ m_engine->SetState(D3DSTATETTw);
+ pos.x = m_pos.x+m_dim.x/150.0f;
+ pos.y = m_pos.y-m_dim.y/150.0f;
+ uv1.x = 192.5f/256.0f;
+ uv2.y = 192.5f/256.0f;
+ uv2.x = 255.5f/256.0f;
+ uv1.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 16 ) // coin inf/droite ?
+ {
+ m_engine->SetTexture("mouse.tga");
+ m_engine->SetState(D3DSTATETTb);
+ pos.x = m_pos.x-m_dim.x/150.0f;
+ pos.y = m_pos.y+m_dim.y/150.0f;
+ uv2.x = 128.5f/256.0f;
+ uv2.y = 192.5f/256.0f;
+ uv1.x = 191.5f/256.0f;
+ uv1.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+
+ m_engine->SetState(D3DSTATETTw);
+ pos.x = m_pos.x+m_dim.x/150.0f;
+ pos.y = m_pos.y-m_dim.y/150.0f;
+ uv2.x = 192.5f/256.0f;
+ uv2.y = 192.5f/256.0f;
+ uv1.x = 255.5f/256.0f;
+ uv1.y = 255.5f/256.0f;
+ DrawIcon(pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 17 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 0.0f/256.0f; // cadre bleu
+ uv1.y = 75.0f/256.0f;
+ uv2.x = 64.0f/256.0f;
+ uv2.y = 128.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 6.0f/640.0f;
+ corner.y = 6.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 2.0f/256.0f);
+ }
+ if ( m_icon == 18 ) // flèche > pour SatCom ?
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 0.0f/256.0f; // >
+ uv1.y = 192.0f/256.0f;
+ uv2.x = 32.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 19 ) // sigle SatCom ?
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 224.0f/256.0f; // sigle SatCom
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 256.0f/256.0f;
+ uv2.y = 256.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 20 ) // fond fleu uni ?
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 224.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 256.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 21 ) // sigle stand-by ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 160.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+ if ( m_icon == 22 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f; // jaune opaque
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 240.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 5.0f/640.0f;
+ corner.y = 5.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 3.0f/256.0f);
+ }
+
+ if ( m_icon == 23 )
+ {
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f; // jaune
+ uv1.y = 192.0f/256.0f;
+ uv2.x = 80.0f/256.0f;
+ uv2.y = 208.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 4.0f/640.0f;
+ corner.y = 4.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 2.0f/256.0f);
+ }
+ if ( m_icon == 24 )
+ {
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 80.0f/256.0f; // orangé
+ uv1.y = 192.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 208.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 4.0f/640.0f;
+ corner.y = 4.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 2.0f/256.0f);
+ }
+ if ( m_icon == 25 )
+ {
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f; // orange
+ uv1.y = 208.0f/256.0f;
+ uv2.x = 80.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 4.0f/640.0f;
+ corner.y = 4.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 2.0f/256.0f);
+ }
+ if ( m_icon == 26 )
+ {
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 80.0f/256.0f; // rouge
+ uv1.y = 208.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 4.0f/640.0f;
+ corner.y = 4.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 2.0f/256.0f);
+ }
+ if ( m_icon == 27 )
+ {
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 32.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 64.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+
+ if ( m_icon >= 100 && m_icon <= 120 ) // bâtiment ?
+ {
+ pos = m_pos;
+ dim = m_dim;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 32.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = uv1.x+32.0f/256.0f;
+ uv2.y = uv1.y+32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2);
+
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ pos.x += 8.0f/640.0f;
+ pos.y += 8.0f/480.0f;
+ dim.x -= 16.0f/640.0f;
+ dim.y -= 16.0f/480.0f;
+ uv1.x = 32.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = uv1.x+32.0f/256.0f;
+ uv2.y = uv1.y+32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2);
+
+ m_engine->SetState(D3DSTATENORMAL);
+ pos.x += 2.0f/640.0f;
+ pos.y += 2.0f/480.0f;
+ dim.x -= 4.0f/640.0f;
+ dim.y -= 4.0f/480.0f;
+ uv1.x = 0.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = uv1.x+32.0f/256.0f;
+ uv2.y = uv1.y+32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2);
+
+ m_engine->SetState(D3DSTATETTb);
+ pos.x += 8.0f/640.0f;
+ pos.y += 8.0f/480.0f;
+ dim.x -= 16.0f/640.0f;
+ dim.y -= 16.0f/480.0f;
+ if ( m_icon == 100 ) icon = 43; // base ?
+ if ( m_icon == 101 ) icon = 32; // factory ?
+ if ( m_icon == 102 ) icon = 35; // research ?
+ if ( m_icon == 103 ) icon = 34; // convert ?
+ if ( m_icon == 104 ) icon = 36; // station ?
+ if ( m_icon == 105 ) icon = 40; // radar ?
+ if ( m_icon == 106 ) icon = 41; // repair ?
+ if ( m_icon == 107 ) icon = 37; // tower ?
+ if ( m_icon == 108 ) icon = 39; // energy ?
+ if ( m_icon == 109 ) icon = 33; // derrick ?
+ if ( m_icon == 110 ) icon = 42; // nuclear ?
+ if ( m_icon == 111 ) icon = 38; // labo ?
+ if ( m_icon == 112 ) icon = 44; // info ?
+ if ( m_icon == 113 ) icon = 46; // paratonnerre ?
+ if ( m_icon == 114 ) icon = 47; // coffre-fort ?
+ if ( m_icon == 115 ) icon = 48; // centre de contrôle ?
+ uv1.x = (32.0f/256.0f)*(icon%8);
+ uv1.y = (32.0f/256.0f)*(icon/8); // uv texture
+ uv2.x = uv1.x+32.0f/256.0f;
+ uv2.y = uv1.y+32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+}
+
+
diff --git a/src/group.h b/src/group.h
new file mode 100644
index 0000000..4bd6a9c
--- /dev/null
+++ b/src/group.h
@@ -0,0 +1,32 @@
+// group.h
+
+#ifndef _GROUP_H_
+#define _GROUP_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CGroup : public CControl
+{
+public:
+ CGroup(CInstanceManager* iMan);
+ ~CGroup();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+protected:
+
+protected:
+};
+
+
+#endif //_GROUP_H_
diff --git a/src/image.cpp b/src/image.cpp
new file mode 100644
index 0000000..ce560ef
--- /dev/null
+++ b/src/image.cpp
@@ -0,0 +1,145 @@
+// image.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "image.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CImage::CImage(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_filename[0] = 0;
+}
+
+// Destructeur de l'objet.
+
+CImage::~CImage()
+{
+ if ( m_filename[0] != 0 )
+ {
+ m_engine->FreeTexture(m_filename);
+ }
+
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CImage::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ if ( icon == -1 )
+ {
+ char name[100];
+ char* p;
+
+ GetResource(RES_EVENT, eventMsg, name);
+ p = strchr(name, '\\');
+ if ( p != 0 ) *p = 0;
+ SetName(name);
+ }
+
+ return TRUE;
+}
+
+
+// Spécifie le nom de l'image à afficher.
+
+void CImage::SetFilenameImage(char *name)
+{
+ if ( m_filename[0] != 0 )
+ {
+ m_engine->FreeTexture(m_filename);
+ }
+
+ strcpy(m_filename, name);
+}
+
+char* CImage::RetFilenameImage()
+{
+ return m_filename;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CImage::EventProcess(const Event &event)
+{
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CImage::Draw()
+{
+ FPOINT uv1,uv2, corner, pos, dim;
+ float dp;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ dp = 0.5f/256.0f;
+
+ if ( m_icon == 0 ) // cadre en creux ?
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 160.0f/256.0f;
+ uv1.y = 192.0f/256.0f; // u-v texture
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 10.0f/640.0f;
+ corner.y = 10.0f/480.0f;
+ DrawIcon(m_pos, m_dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+
+ if ( m_filename[0] != 0 ) // affiche une image ?
+ {
+ m_engine->LoadTexture(m_filename);
+ m_engine->SetTexture(m_filename);
+ m_engine->SetState(D3DSTATENORMAL);
+ pos = m_pos;
+ dim = m_dim;
+ pos.x += 5.0f/640.0f;
+ pos.y += 5.0f/480.0f;
+ dim.x -= 10.0f/640.0f;
+ dim.y -= 10.0f/480.0f;
+ uv1.x = 0.0f;
+ uv1.y = 0.0f;
+ uv2.x = 1.0f;
+ uv2.y = 1.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+}
+
+
diff --git a/src/image.h b/src/image.h
new file mode 100644
index 0000000..acbfa10
--- /dev/null
+++ b/src/image.h
@@ -0,0 +1,36 @@
+// image.h
+
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CImage : public CControl
+{
+public:
+ CImage(CInstanceManager* iMan);
+ ~CImage();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+ void SetFilenameImage(char *name);
+ char* RetFilenameImage();
+
+protected:
+
+protected:
+ char m_filename[100];
+};
+
+
+#endif //_IMAGE_H_
diff --git a/src/iman.cpp b/src/iman.cpp
new file mode 100644
index 0000000..9b64b93
--- /dev/null
+++ b/src/iman.cpp
@@ -0,0 +1,149 @@
+// iman.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "struct.h"
+#include "iman.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CInstanceManager::CInstanceManager()
+{
+ int i;
+
+ for ( i=0 ; i<CLASS_MAX ; i++ )
+ {
+ m_table[i].totalPossible = 0;
+ m_table[i].totalUsed = 0;
+ m_table[i].classPointer = 0;
+ }
+}
+
+// Destructeur de l'objet.
+
+CInstanceManager::~CInstanceManager()
+{
+ int i;
+
+ for ( i=0 ; i<CLASS_MAX ; i++ )
+ {
+ if ( m_table[i].classPointer != 0 )
+ {
+ free(m_table[i].classPointer);
+ }
+ }
+}
+
+
+// Vide toute la liste des classes.
+
+void CInstanceManager::Flush()
+{
+ int i;
+
+ for ( i=0 ; i<CLASS_MAX ; i++ )
+ {
+ if ( m_table[i].classPointer != 0 )
+ {
+ free(m_table[i].classPointer);
+ }
+ m_table[i].classPointer = 0;
+ }
+}
+
+// Vide toutes les instances d'une classe donnée.
+
+void CInstanceManager::Flush(ClassType classType)
+{
+ if ( classType < 0 || classType >= CLASS_MAX ) return;
+ if ( m_table[classType].classPointer == 0 ) return;
+
+ free(m_table[classType].classPointer);
+ m_table[classType].classPointer = 0;
+}
+
+
+// Ajoute une nouvelle instance d'une classe.
+
+BOOL CInstanceManager::AddInstance(ClassType classType, void* pointer, int max)
+{
+ int i;
+
+ if ( classType < 0 || classType >= CLASS_MAX ) return FALSE;
+
+ if ( m_table[classType].classPointer == 0 )
+ {
+ m_table[classType].classPointer = (void**)malloc(max*sizeof(void*));
+ m_table[classType].totalPossible = max;
+ m_table[classType].totalUsed = 0;
+ }
+
+ if ( m_table[classType].totalUsed >= m_table[classType].totalPossible ) return FALSE;
+
+ i = m_table[classType].totalUsed++;
+ m_table[classType].classPointer[i] = pointer;
+ return TRUE;
+}
+
+// Supprime une instance d'une classe.
+
+BOOL CInstanceManager::DeleteInstance(ClassType classType, void* pointer)
+{
+ int i;
+
+ if ( classType < 0 || classType >= CLASS_MAX ) return FALSE;
+
+ for ( i=0 ; i<m_table[classType].totalUsed ; i++ )
+ {
+ if ( m_table[classType].classPointer[i] == pointer )
+ {
+ m_table[classType].classPointer[i] = 0;
+ }
+ }
+
+ Compress(classType);
+ return TRUE;
+}
+
+// Cherche une instance existante. Retourne 0 si elle n'existe pas.
+// Doit être super-rapide !
+
+void* CInstanceManager::SearchInstance(ClassType classType, int rank)
+{
+#if _DEBUG
+ if ( classType < 0 || classType >= CLASS_MAX ) return 0;
+ if ( m_table[classType].classPointer == 0 ) return 0;
+#endif
+ if ( rank >= m_table[classType].totalUsed ) return 0;
+
+ return m_table[classType].classPointer[rank];
+}
+
+
+// Bouche les trous dans une table.
+
+void CInstanceManager::Compress(ClassType classType)
+{
+ int i, j;
+
+ if ( classType < 0 || classType >= CLASS_MAX ) return;
+
+ j = 0;
+ for ( i=0 ; i<m_table[classType].totalUsed ; i++ )
+ {
+ if ( m_table[classType].classPointer[i] != 0 )
+ {
+ m_table[classType].classPointer[j++] = m_table[classType].classPointer[i];
+ }
+ }
+ m_table[classType].totalUsed = j;
+}
+
+
diff --git a/src/iman.h b/src/iman.h
new file mode 100644
index 0000000..96a41c9
--- /dev/null
+++ b/src/iman.h
@@ -0,0 +1,42 @@
+// iman.h
+
+#ifndef _IMAN_H_
+#define _IMAN_H_
+
+
+#include "misc.h"
+
+
+
+typedef struct
+{
+ int totalPossible;
+ int totalUsed;
+ void** classPointer;
+}
+BaseClass;
+
+
+
+class CInstanceManager
+{
+public:
+ CInstanceManager();
+ ~CInstanceManager();
+
+ void Flush();
+ void Flush(ClassType classType);
+ BOOL AddInstance(ClassType classType, void* pointer, int max=1);
+ BOOL DeleteInstance(ClassType classType, void* pointer);
+ void* SearchInstance(ClassType classType, int rank=0);
+
+
+protected:
+ void Compress(ClassType classType);
+
+protected:
+ BaseClass m_table[CLASS_MAX];
+};
+
+
+#endif //_IMAN_H_
diff --git a/src/interface.cpp b/src/interface.cpp
new file mode 100644
index 0000000..54d4e9d
--- /dev/null
+++ b/src/interface.cpp
@@ -0,0 +1,591 @@
+// interface.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "control.h"
+#include "button.h"
+#include "color.h"
+#include "check.h"
+#include "key.h"
+#include "group.h"
+#include "image.h"
+#include "label.h"
+#include "edit.h"
+#include "editvalue.h"
+#include "scroll.h"
+#include "slider.h"
+#include "list.h"
+#include "shortcut.h"
+#include "compass.h"
+#include "target.h"
+#include "map.h"
+#include "window.h"
+#include "camera.h"
+#include "interface.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CInterface::CInterface(CInstanceManager* iMan)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_INTERFACE, this);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_camera = 0;
+
+ for ( i=0 ; i<MAXCONTROL ; i++ )
+ {
+ m_table[i] = 0;
+ }
+}
+
+// Destructeur de l'objet.
+
+CInterface::~CInterface()
+{
+ Flush();
+}
+
+
+// Purge tous les contrôles.
+
+void CInterface::Flush()
+{
+ int i;
+
+ for ( i=0 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ delete m_table[i];
+ m_table[i] = 0;
+ }
+ }
+}
+
+
+// Crée un nouveau bouton.
+
+CWindow* CInterface::CreateWindows(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CWindow* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ if ( eventMsg == EVENT_WINDOW0 ) {i=0; goto create;}
+ if ( eventMsg == EVENT_WINDOW1 ) {i=1; goto create;}
+ if ( eventMsg == EVENT_WINDOW2 ) {i=2; goto create;}
+ if ( eventMsg == EVENT_WINDOW3 ) {i=3; goto create;}
+ if ( eventMsg == EVENT_WINDOW4 ) {i=4; goto create;}
+ if ( eventMsg == EVENT_WINDOW5 ) {i=5; goto create;}
+ if ( eventMsg == EVENT_WINDOW6 ) {i=6; goto create;}
+ if ( eventMsg == EVENT_WINDOW7 ) {i=7; goto create;}
+ if ( eventMsg == EVENT_WINDOW8 ) {i=8; goto create;}
+ if ( eventMsg == EVENT_WINDOW9 ) {i=9; goto create;}
+
+ if ( eventMsg == EVENT_TOOLTIP ) {i=MAXCONTROL-1; goto create;}
+
+ for ( i=10 ; i<MAXCONTROL-1 ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ create:
+ m_table[i] = new CWindow(m_iMan);
+ pc = (CWindow*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CButton* CInterface::CreateButton(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CButton* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CButton(m_iMan);
+ pc = (CButton*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CColor* CInterface::CreateColor(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CColor* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CColor(m_iMan);
+ pc = (CColor*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CCheck* CInterface::CreateCheck(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CCheck* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CCheck(m_iMan);
+ pc = (CCheck*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CKey* CInterface::CreateKey(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CKey* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CKey(m_iMan);
+ pc = (CKey*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CGroup* CInterface::CreateGroup(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CGroup* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CGroup(m_iMan);
+ pc = (CGroup*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CImage* CInterface::CreateImage(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CImage* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CImage(m_iMan);
+ pc = (CImage*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau label.
+
+CLabel* CInterface::CreateLabel(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg,
+ char *name)
+{
+ CLabel* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CLabel(m_iMan);
+ pc = (CLabel*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ pc->SetName(name);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau pavé éditable.
+
+CEdit* CInterface::CreateEdit(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CEdit* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CEdit(m_iMan);
+ pc = (CEdit*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau pavé éditable.
+
+CEditValue* CInterface::CreateEditValue(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CEditValue* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CEditValue(m_iMan);
+ pc = (CEditValue*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouvel ascenseur.
+
+CScroll* CInterface::CreateScroll(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CScroll* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CScroll(m_iMan);
+ pc = (CScroll*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau curseur.
+
+CSlider* CInterface::CreateSlider(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CSlider* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CSlider(m_iMan);
+ pc = (CSlider*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle liste.
+
+CList* CInterface::CreateList(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg,
+ float expand)
+{
+ CList* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CList(m_iMan);
+ pc = (CList*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg, expand);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau raccourci.
+
+CShortcut* CInterface::CreateShortcut(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CShortcut* ps;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CShortcut(m_iMan);
+ ps = (CShortcut*)m_table[i];
+ ps->Create(pos, dim, icon, eventMsg);
+ return ps;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouvelle boussole.
+
+CCompass* CInterface::CreateCompass(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CCompass* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CCompass(m_iMan);
+ pc = (CCompass*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouvelle cible.
+
+CTarget* CInterface::CreateTarget(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CTarget* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CTarget(m_iMan);
+ pc = (CTarget*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle carte.
+
+CMap* CInterface::CreateMap(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CMap* pm;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=10 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CMap(m_iMan);
+ pm = (CMap*)m_table[i];
+ pm->Create(pos, dim, icon, eventMsg);
+ return pm;
+ }
+ }
+ return 0;
+}
+
+// Supprime un contrôle.
+
+BOOL CInterface::DeleteControl(EventMsg eventMsg)
+{
+ int i;
+
+ for ( i=0 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( eventMsg == m_table[i]->RetEventMsg() )
+ {
+ delete m_table[i];
+ m_table[i] = 0;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+// Donne un contrôle.
+
+CControl* CInterface::SearchControl(EventMsg eventMsg)
+{
+ int i;
+
+ for ( i=0 ; i<MAXCONTROL ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( eventMsg == m_table[i]->RetEventMsg() )
+ {
+ return m_table[i];
+ }
+ }
+ }
+ return 0;
+}
+
+// Gestion d'un événement.
+
+BOOL CInterface::EventProcess(const Event &event)
+{
+ int i;
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ if ( m_camera == 0 )
+ {
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ }
+ m_engine->SetMouseType(m_camera->RetMouseDef(event.pos));
+ }
+
+ for ( i=MAXCONTROL-1 ; i>=0 ; i-- )
+ {
+ if ( m_table[i] != 0 &&
+ m_table[i]->TestState(STATE_ENABLE) )
+ {
+ if ( !m_table[i]->EventProcess(event) )
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Donne le tooltip lié à la fenêtre.
+
+BOOL CInterface::GetTooltip(FPOINT pos, char* name)
+{
+ int i;
+
+ for ( i=MAXCONTROL-1 ; i>=0 ; i-- )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( m_table[i]->GetTooltip(pos, name) )
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+// Dessine tous les boutons.
+
+void CInterface::Draw()
+{
+ D3DMATERIAL7 material;
+ int i;
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse.r = 1.0f;
+ material.diffuse.g = 1.0f;
+ material.diffuse.b = 1.0f;
+ material.ambient.r = 0.5f;
+ material.ambient.g = 0.5f;
+ material.ambient.b = 0.5f;
+ m_engine->SetMaterial(material);
+
+ for ( i=0 ; i<MAXCONTROL ; i++ )
+//? for ( i=MAXCONTROL-1 ; i>=0 ; i-- )
+ {
+ if ( m_table[i] != 0 )
+ {
+ m_table[i]->Draw();
+ }
+ }
+}
+
+
diff --git a/src/interface.h b/src/interface.h
new file mode 100644
index 0000000..4feb86d
--- /dev/null
+++ b/src/interface.h
@@ -0,0 +1,77 @@
+// interface.h
+
+#ifndef _INTERFACE_H_
+#define _INTERFACE_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CControl;
+class CWindow;
+class CButton;
+class CColor;
+class CCheck;
+class CKey;
+class CGroup;
+class CImage;
+class CLabel;
+class CEdit;
+class CEditValue;
+class CScroll;
+class CSlider;
+class CList;
+class CShortcut;
+class CMap;
+class CGauge;
+class CCompass;
+class CTarget;
+class CCamera;
+
+
+#define MAXCONTROL 100
+
+
+class CInterface
+{
+public:
+ CInterface(CInstanceManager* iMan);
+ ~CInterface();
+
+ BOOL EventProcess(const Event &event);
+ BOOL GetTooltip(FPOINT pos, char* name);
+
+ void Flush();
+ CWindow* CreateWindows(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CButton* CreateButton(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CColor* CreateColor(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CCheck* CreateCheck(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CKey* CreateKey(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CGroup* CreateGroup(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CImage* CreateImage(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CLabel* CreateLabel(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg, char *name);
+ CEdit* CreateEdit(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CEditValue* CreateEditValue(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CScroll* CreateScroll(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CSlider* CreateSlider(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CList* CreateList(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg, float expand=1.2f);
+ CShortcut* CreateShortcut(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CCompass* CreateCompass(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CTarget* CreateTarget(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CMap* CreateMap(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ BOOL DeleteControl(EventMsg eventMsg);
+ CControl* SearchControl(EventMsg eventMsg);
+
+ void Draw();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CCamera* m_camera;
+
+ CControl* m_table[MAXCONTROL];
+};
+
+
+#endif //_INTERFACE_H_
diff --git a/src/joystick.cpp b/src/joystick.cpp
new file mode 100644
index 0000000..41d9f56
--- /dev/null
+++ b/src/joystick.cpp
@@ -0,0 +1,222 @@
+// joystick.cpp
+
+#define STRICT
+
+#include <windows.h>
+#include <dinput.h>
+#include <stdio.h>
+
+#include "joystick.h"
+
+
+
+
+// Global variables.
+
+LPDIRECTINPUT7 g_pDI = NULL;
+LPDIRECTINPUTDEVICE2 g_pJoystick = NULL;
+DIDEVCAPS g_diDevCaps;
+
+
+
+
+
+// Called once for each enumerated joystick. If we find one, create a
+// device interface on it so we can play with it.
+
+BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
+ VOID* pContext )
+{
+ HRESULT hr;
+
+ // Obtain an interface to the enumerated joystick.
+ hr = g_pDI->CreateDeviceEx( pdidInstance->guidInstance, IID_IDirectInputDevice2,
+ (VOID**)&g_pJoystick, NULL );
+
+ // If it failed, then we can't use this joystick. (Maybe the user unplugged
+ // it while we were in the middle of enumerating it.)
+ if( FAILED(hr) )
+ return DIENUM_CONTINUE;
+
+
+ // Stop enumeration. Note: we're just taking the first joystick we get. You
+ // could store all the enumerated joysticks and let the user pick.
+ return DIENUM_STOP;
+}
+
+
+// Callback function for enumerating the axes on a joystick.
+
+BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
+ VOID* pContext )
+{
+ DIPROPRANGE diprg;
+ diprg.diph.dwSize = sizeof(DIPROPRANGE);
+ diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ diprg.diph.dwHow = DIPH_BYOFFSET;
+ diprg.diph.dwObj = pdidoi->dwOfs; // Specify the enumerated axis
+ diprg.lMin = -1000;
+ diprg.lMax = +1000;
+
+ // Set the range for the axis
+ if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) )
+ return DIENUM_STOP;
+
+ // Set the UI to reflect what axes the joystick supports
+ switch( pdidoi->dwOfs )
+ {
+ case DIJOFS_X:
+ OutputDebugString("EnumAxesCallback -x\n");
+ break;
+ case DIJOFS_Y:
+ OutputDebugString("EnumAxesCallback -y\n");
+ break;
+ case DIJOFS_Z:
+ OutputDebugString("EnumAxesCallback -z\n");
+ break;
+ case DIJOFS_RX:
+ OutputDebugString("EnumAxesCallback -rx\n");
+ break;
+ case DIJOFS_RY:
+ OutputDebugString("EnumAxesCallback -ry\n");
+ break;
+ case DIJOFS_RZ:
+ OutputDebugString("EnumAxesCallback -rz\n");
+ break;
+ case DIJOFS_SLIDER(0):
+ OutputDebugString("EnumAxesCallback -s0\n");
+ break;
+ case DIJOFS_SLIDER(1):
+ OutputDebugString("EnumAxesCallback -s1\n");
+ break;
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+
+// Initialize the DirectInput variables.
+
+BOOL InitDirectInput(HINSTANCE hInst, HWND hWnd)
+{
+ HRESULT hr;
+
+ // Register with the DirectInput subsystem and get a pointer
+ // to a IDirectInput interface we can use.
+ hr = DirectInputCreateEx( hInst, DIRECTINPUT_VERSION,IID_IDirectInput7, (LPVOID*)&g_pDI, NULL );
+ if( FAILED(hr) ) return FALSE;;
+
+ // Look for a simple joystick we can use for this sample program.
+ hr = g_pDI->EnumDevices( DIDEVTYPE_JOYSTICK, EnumJoysticksCallback,
+ NULL, DIEDFL_ATTACHEDONLY );
+ if( FAILED(hr) ) return FALSE;
+
+ // Make sure we got a joystick
+ if( NULL == g_pJoystick )
+ {
+//? MessageBox( NULL, "Joystick not found", "DInput Sample",
+//? MB_ICONERROR | MB_OK );
+ return FALSE;
+ }
+
+ // Set the data format to "simple joystick" - a predefined data format
+ //
+ // A data format specifies which controls on a device we are interested in,
+ // and how they should be reported. This tells DInput that we will be
+ // passing a DIJOYSTATE structure to IDirectInputDevice::GetDeviceState().
+ hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick );
+ if( FAILED(hr) ) return FALSE;
+
+ // Set the cooperative level to let DInput know how this device should
+ // interact with the system and with other DInput applications.
+ hr = g_pJoystick->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE|DISCL_FOREGROUND );
+ if( FAILED(hr) ) return FALSE;
+
+ // Determine how many axis the joystick has (so we don't error out setting
+ // properties for unavailable axis)
+ g_diDevCaps.dwSize = sizeof(DIDEVCAPS);
+ hr = g_pJoystick->GetCapabilities(&g_diDevCaps);
+ if( FAILED(hr) ) return FALSE;
+
+
+ // Enumerate the axes of the joyctick and set the range of each axis. Note:
+ // we could just use the defaults, but we're just trying to show an example
+ // of enumerating device objects (axes, buttons, etc.).
+ g_pJoystick->EnumObjects( EnumAxesCallback, (VOID*)g_pJoystick, DIDFT_AXIS );
+
+ return TRUE;
+}
+
+// Acquire or unacquire the keyboard, depending on if the app is active
+// Input device must be acquired before the GetDeviceState is called.
+
+BOOL SetAcquire(BOOL bActive)
+{
+ if ( g_pJoystick )
+ {
+ if( bActive ) g_pJoystick->Acquire();
+ else g_pJoystick->Unacquire();
+ }
+ return TRUE;
+}
+
+
+// Get the input device's state and display it.
+
+BOOL UpdateInputState( DIJOYSTATE &js )
+{
+ HRESULT hr;
+
+ if ( g_pJoystick )
+ {
+ do
+ {
+ // Poll the device to read the current state
+ hr = g_pJoystick->Poll();
+ if ( FAILED(hr) ) return FALSE;
+
+ // Get the input's device state
+ hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js );
+
+ if( hr == DIERR_INPUTLOST )
+ {
+ // DInput is telling us that the input stream has been
+ // interrupted. We aren't tracking any state between polls, so
+ // we don't have any special reset that needs to be done. We
+ // just re-acquire and try again.
+ hr = g_pJoystick->Acquire();
+ if ( FAILED(hr) ) return FALSE;
+ }
+ }
+ while ( DIERR_INPUTLOST == hr );
+ if ( FAILED(hr) ) return FALSE;
+ }
+ return TRUE;
+}
+
+
+// Initialize the DirectInput variables.
+
+BOOL FreeDirectInput()
+{
+ // Unacquire and release any DirectInputDevice objects.
+ if( NULL != g_pJoystick )
+ {
+ // Unacquire the device one last time just in case
+ // the app tried to exit while the device is still acquired.
+ g_pJoystick->Unacquire();
+ g_pJoystick->Release();
+ g_pJoystick = NULL;
+ }
+
+
+ // Release any DirectInput objects.
+ if( g_pDI )
+ {
+ g_pDI->Release();
+ g_pDI = NULL;
+ }
+
+ return TRUE;
+}
+
diff --git a/src/joystick.h b/src/joystick.h
new file mode 100644
index 0000000..99aff58
--- /dev/null
+++ b/src/joystick.h
@@ -0,0 +1,15 @@
+// joystick.h
+
+#ifndef _JOYSTICK_H_
+#define _JOYSTICK_H_
+
+
+
+extern BOOL InitDirectInput(HINSTANCE hInst, HWND hWnd);
+extern BOOL SetAcquire(BOOL bActive);
+extern BOOL UpdateInputState(DIJOYSTATE &js);
+extern BOOL FreeDirectInput();
+
+
+
+#endif //_JOYSTICK_H_
diff --git a/src/key.cpp b/src/key.cpp
new file mode 100644
index 0000000..3319f92
--- /dev/null
+++ b/src/key.cpp
@@ -0,0 +1,277 @@
+// key.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "sound.h"
+#include "text.h"
+#include "key.h"
+
+
+
+
+// COnstruit le nom d'une touche.
+
+void GetKeyName(char *name, int key)
+{
+ if ( !GetResource(RES_KEY, key, name) )
+ {
+ if ( (key >= '0' && key <= '9') ||
+ (key >= 'A' && key <= 'Z') ||
+ (key >= 'a' && key <= 'z') )
+ {
+ name[0] = key;
+ name[1] = 0;
+ }
+ else
+ {
+ sprintf(name, "Code %d", key);
+ }
+ }
+}
+
+
+
+
+// Constructeur de l'objet.
+
+CKey::CKey(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_key[0] = 0;
+ m_key[1] = 0;
+ m_bCatch = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CKey::~CKey()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CKey::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ char name[100];
+ char* p;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ GetResource(RES_EVENT, eventMsg, name);
+ p = strchr(name, '\\');
+ if ( p != 0 ) *p = 0;
+ SetName(name);
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CKey::EventProcess(const Event &event)
+{
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( Detect(event.pos) )
+ {
+ m_bCatch = TRUE;
+ }
+ else
+ {
+ m_bCatch = FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_KEYDOWN && m_bCatch )
+ {
+ m_bCatch = FALSE;
+
+ if ( TestKey(event.param) ) // impossible ?
+ {
+ m_sound->Play(SOUND_TZOING);
+ }
+ else
+ {
+ if ( event.param == m_key[0] ||
+ event.param == m_key[1] )
+ {
+ m_key[0] = event.param;
+ m_key[1] = 0;
+ }
+ else
+ {
+ m_key[1] = m_key[0];
+ m_key[0] = event.param;
+ }
+ m_sound->Play(SOUND_CLICK);
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// Cherche si une touche est déjà utilisée.
+
+BOOL CKey::TestKey(int key)
+{
+ int i, j;
+
+ if ( key == VK_PAUSE ||
+ key == VK_SNAPSHOT ) return TRUE; // touche bloquée
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ for ( j=0 ; j<2 ; j++ )
+ {
+ if ( key == m_engine->RetKey(i, j) ) // touche utilisée ?
+ {
+ m_engine->SetKey(i, j, 0); // plus rien !
+ }
+ }
+
+ if ( m_engine->RetKey(i, 0) == 0 ) // première option libre ?
+ {
+ m_engine->SetKey(i, 0, m_engine->RetKey(i, 1)); // shift
+ m_engine->SetKey(i, 1, 0);
+ }
+ }
+
+ return FALSE; // pas utilisée
+}
+
+
+// Dessine le bouton.
+
+void CKey::Draw()
+{
+ FPOINT iDim, pos;
+ float zoomExt, zoomInt, h;
+ int icon;
+ char text[100];
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ iDim = m_dim;
+ m_dim.x = 200.0f/640.0f;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ zoomExt = 1.00f;
+ zoomInt = 0.95f;
+
+ icon = 2;
+ if ( m_key[0] == 0 &&
+ m_key[1] == 0 ) // pas de raccourci ?
+ {
+ icon = 3;
+ }
+ if ( m_state & STATE_DEFAULT )
+ {
+ DrawPart(23, 1.3f, 0.0f);
+
+ zoomExt *= 1.15f;
+ zoomInt *= 1.15f;
+ }
+ if ( m_state & STATE_HILIGHT )
+ {
+ icon = 1;
+ }
+ if ( m_state & STATE_CHECK )
+ {
+ icon = 0;
+ }
+ if ( m_state & STATE_PRESS )
+ {
+ icon = 3;
+ zoomInt *= 0.9f;
+ }
+ if ( (m_state & STATE_ENABLE) == 0 )
+ {
+ icon = 7;
+ }
+ if ( m_state & STATE_DEAD )
+ {
+ icon = 17;
+ }
+ if ( m_bCatch )
+ {
+ icon = 23;
+ }
+ DrawPart(icon, zoomExt, 8.0f/256.0f); // dessine le bouton
+
+ h = m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2.0f;
+
+ GetKeyName(text, m_key[0]);
+ if ( m_key[1] != 0 )
+ {
+ GetResource(RES_TEXT, RT_KEY_OR, text+strlen(text));
+ GetKeyName(text+strlen(text), m_key[1]);
+ }
+
+ pos.x = m_pos.x+m_dim.x*0.5f;
+ pos.y = m_pos.y+m_dim.y*0.5f;
+ pos.y -= h;
+ m_engine->RetText()->DrawText(text, pos, m_dim.x, 0, m_fontSize, m_fontStretch, m_fontType, 0);
+
+ m_dim = iDim;
+
+ if ( m_state & STATE_DEAD ) return;
+
+ // Dessine le nom.
+ pos.x = m_pos.x+(214.0f/640.0f);
+ pos.y = m_pos.y+m_dim.y*0.5f;
+ pos.y -= h;
+ m_engine->RetText()->DrawText(m_name, pos, m_dim.x, 1, m_fontSize, m_fontStretch, m_fontType, 0);
+}
+
+
+
+void CKey::SetKey(int option, int key)
+{
+ if ( option < 0 ||
+ option > 1 ) return;
+
+ m_key[option] = key;
+}
+
+int CKey::RetKey(int option)
+{
+ if ( option < 0 ||
+ option > 1 ) return 0;
+
+ return m_key[option];
+}
+
diff --git a/src/key.h b/src/key.h
new file mode 100644
index 0000000..c26bfb3
--- /dev/null
+++ b/src/key.h
@@ -0,0 +1,38 @@
+// key.h
+
+#ifndef _KEY_H_
+#define _KEY_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CKey : public CControl
+{
+public:
+ CKey(CInstanceManager* iMan);
+ ~CKey();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+ void SetKey(int option, int key);
+ int RetKey(int option);
+
+protected:
+ BOOL TestKey(int key);
+
+protected:
+ int m_key[2];
+ BOOL m_bCatch;
+};
+
+
+#endif //_KEY_H_
diff --git a/src/label.cpp b/src/label.cpp
new file mode 100644
index 0000000..4bb95fa
--- /dev/null
+++ b/src/label.cpp
@@ -0,0 +1,81 @@
+// label.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "text.h"
+#include "label.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CLabel::CLabel(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+}
+
+// Destructeur de l'objet.
+
+CLabel::~CLabel()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CLabel::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CLabel::EventProcess(const Event &event)
+{
+//? CControl::EventProcess(event);
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CLabel::Draw()
+{
+ FPOINT pos;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ pos.y = m_pos.y+m_dim.y/2.0f;
+
+ if ( m_justif > 0 )
+ {
+ pos.x = m_pos.x;
+ }
+ if ( m_justif == 0 )
+ {
+ pos.x = m_pos.x+m_dim.x/2.0f;
+ }
+ if ( m_justif < 0 )
+ {
+ pos.x = m_pos.x+m_dim.x;
+ }
+ m_engine->RetText()->DrawText(m_name, pos, m_dim.x, m_justif, m_fontSize, m_fontStretch, m_fontType, 0);
+}
+
diff --git a/src/label.h b/src/label.h
new file mode 100644
index 0000000..c2120a8
--- /dev/null
+++ b/src/label.h
@@ -0,0 +1,32 @@
+// label.h
+
+#ifndef _LABEL_H_
+#define _LABEL_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CLabel : public CControl
+{
+public:
+ CLabel(CInstanceManager* iMan);
+ ~CLabel();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+protected:
+
+protected:
+};
+
+
+#endif //_LABEL_H_
diff --git a/src/language.h b/src/language.h
new file mode 100644
index 0000000..f77e6da
--- /dev/null
+++ b/src/language.h
@@ -0,0 +1,35 @@
+// language.h
+
+#define _FULL TRUE // CoLoBoT
+#define _SCHOOL FALSE // CeeBot-A ou Teen
+ #define _TEEN FALSE // FALSE si CeeBot-A, TRUE si CeeBot-Teen
+ #define _EDU FALSE
+ #define _PERSO FALSE
+ #define _CEEBOTDEMO FALSE
+#define _NET FALSE
+#define _DEMO FALSE // DEMO uniquement de CoLoBoT (avec _FULL = FALSE) !
+
+#define _FRENCH TRUE
+#define _ENGLISH FALSE
+#define _GERMAN FALSE
+#define _WG FALSE
+#define _POLISH FALSE
+
+#define _NEWLOOK FALSE // FALSE pour CoLoBoT, TRUE pour tous les CeeBot
+#define _SOUNDTRACKS FALSE // toujours FALSE depuis que InitAudioTrackVolume plante sous Vista
+
+
+// Vérifications
+
+#if !_FULL & !_SCHOOL & !_NET & !_DEMO
+-> aucune version choisie !!!
+#endif
+
+#if _SCHOOL
+#if !_EDU & !_PERSO & !_CEEBOTDEMO
+-> EDU ou PERSO ou CEEBOTDEMO ?
+#endif
+#if _EDU & _PERSO & _CEEBOTDEMO
+-> pas EDU et PERSO et CEEBOTDEMO en même temps !!!
+#endif
+#endif
diff --git a/src/light.cpp b/src/light.cpp
new file mode 100644
index 0000000..e925fea
--- /dev/null
+++ b/src/light.cpp
@@ -0,0 +1,487 @@
+// light.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "light.h"
+
+
+
+
+
+// Initialise une progression.
+
+void ProgInit(LightProg &p, float value)
+{
+ p.starting = value;
+ p.ending = value;
+ p.current = value;
+ p.progress = 0.0f;
+ p.speed = 100.0f;
+}
+
+// Fait évoluer une progression.
+
+void ProgFrame(LightProg &p, float rTime)
+{
+ if ( p.speed < 100.0f )
+ {
+ if ( p.progress < 1.0f )
+ {
+ p.progress += p.speed*rTime;
+ if ( p.progress > 1.0f )
+ {
+ p.progress = 1.0f;
+ }
+ }
+
+ p.current = (p.ending-p.starting)*p.progress + p.starting;
+ }
+ else
+ {
+ p.current = p.ending;
+ }
+}
+
+// Change la valeur courante.
+
+void ProgSet(LightProg &p, float value)
+{
+ p.starting = p.current;
+ p.ending = value;
+ p.progress = 0.0f;
+}
+
+
+
+
+
+// Constructeur de l'objet.
+
+CLight::CLight(CInstanceManager* iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_LIGHT, this);
+
+ m_pD3DDevice = 0;
+ m_engine = engine;
+
+ m_lightUsed = 0;
+ m_lightTable = (Light*)malloc(sizeof(Light)*D3DMAXLIGHT);
+ ZeroMemory(m_lightTable, sizeof(Light)*D3DMAXLIGHT);
+
+ m_time = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CLight::~CLight()
+{
+ free(m_lightTable);
+ m_iMan->DeleteInstance(CLASS_LIGHT, this);
+}
+
+
+void CLight::SetD3DDevice(LPDIRECT3DDEVICE7 device)
+{
+ m_pD3DDevice = device;
+}
+
+
+// Supprime toutes les lumières.
+
+void CLight::FlushLight()
+{
+ int i;
+
+ for ( i=0 ; i<D3DMAXLIGHT ; i++ )
+ {
+ m_lightTable[i].bUsed = FALSE;
+ m_pD3DDevice->LightEnable(i, FALSE);
+ }
+ m_lightUsed = 0;
+}
+
+
+// Crée une nouvelle lumière. Retourne son rang ou -1 en cas d'erreur.
+
+int CLight::CreateLight()
+{
+ int i;
+
+ for ( i=0 ; i<D3DMAXLIGHT ; i++ )
+ {
+ if ( m_lightTable[i].bUsed == FALSE )
+ {
+ ZeroMemory(&m_lightTable[i], sizeof(Light));
+ m_lightTable[i].bUsed = TRUE;
+ m_lightTable[i].bEnable = TRUE;
+
+ m_lightTable[i].incluType = TYPENULL;
+ m_lightTable[i].excluType = TYPENULL;
+
+ m_lightTable[i].light.dltType = D3DLIGHT_DIRECTIONAL;
+ m_lightTable[i].light.dcvDiffuse.r = 0.5f;
+ m_lightTable[i].light.dcvDiffuse.g = 0.5f;
+ m_lightTable[i].light.dcvDiffuse.b = 0.5f; // blanc
+ m_lightTable[i].light.dvPosition.x =-100.0f;
+ m_lightTable[i].light.dvPosition.y = 100.0f;
+ m_lightTable[i].light.dvPosition.z =-100.0f;
+ m_lightTable[i].light.dvDirection.x = 1.0f;
+ m_lightTable[i].light.dvDirection.y = -1.0f;
+ m_lightTable[i].light.dvDirection.z = 1.0f;
+
+ ProgInit(m_lightTable[i].intensity, 1.0f); // maximum
+ ProgInit(m_lightTable[i].colorRed, 0.5f);
+ ProgInit(m_lightTable[i].colorGreen, 0.5f);
+ ProgInit(m_lightTable[i].colorBlue, 0.5f); // gris
+
+ if ( m_lightUsed < i+1 )
+ {
+ m_lightUsed = i+1;
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Supprime une lumière.
+
+BOOL CLight::DeleteLight(int lightRank)
+{
+ int i;
+
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].bUsed = FALSE;
+ m_pD3DDevice->LightEnable(lightRank, FALSE);
+
+ m_lightUsed = 0;
+ for ( i=0 ; i<D3DMAXLIGHT ; i++ )
+ {
+ if ( m_lightTable[i].bUsed == TRUE )
+ {
+ m_lightUsed = i+1;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Spécifie une lumière.
+
+BOOL CLight::SetLight(int lightRank, const D3DLIGHT7 &light)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].light = light;
+
+ ProgInit(m_lightTable[lightRank].colorRed, m_lightTable[lightRank].light.dcvDiffuse.r);
+ ProgInit(m_lightTable[lightRank].colorGreen, m_lightTable[lightRank].light.dcvDiffuse.g);
+ ProgInit(m_lightTable[lightRank].colorBlue, m_lightTable[lightRank].light.dcvDiffuse.b);
+
+ return TRUE;
+}
+
+// Donne les spécifications d'une lumière.
+
+BOOL CLight::GetLight(int lightRank, D3DLIGHT7 &light)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ light = m_lightTable[lightRank].light;
+ return TRUE;
+}
+
+
+// Allume ou éteint une lumière.
+
+BOOL CLight::LightEnable(int lightRank, BOOL bEnable)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].bEnable = bEnable;
+ return TRUE;
+}
+
+
+// Spécifie le type (TYPE*) des objets inclus par cette lumière.
+// Cette lumière n'éclairera donc que ce type d'objets.
+
+BOOL CLight::SetLightIncluType(int lightRank, D3DTypeObj type)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].incluType = type;
+ return TRUE;
+}
+
+// Spécifie le type (TYPE*) des objets exclus par cette lumière.
+// Cette lumière n'éclairera donc jamais ce type d'objets.
+
+BOOL CLight::SetLightExcluType(int lightRank, D3DTypeObj type)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].excluType = type;
+ return TRUE;
+}
+
+
+// Gestion de la position de la lunière.
+
+BOOL CLight::SetLightPos(int lightRank, D3DVECTOR pos)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].light.dvPosition = pos;
+ return TRUE;
+}
+
+D3DVECTOR CLight::RetLightPos(int lightRank)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ return m_lightTable[lightRank].light.dvPosition;
+}
+
+
+// Gestion de la direction de la lumière.
+
+BOOL CLight::SetLightDir(int lightRank, D3DVECTOR dir)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].light.dvDirection = dir;
+ return TRUE;
+}
+
+D3DVECTOR CLight::RetLightDir(int lightRank)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ return m_lightTable[lightRank].light.dvDirection;
+}
+
+
+// Spécifie la vitesse de changement.
+
+BOOL CLight::SetLightIntensitySpeed(int lightRank, float speed)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].intensity.speed = speed;
+ return TRUE;
+}
+
+// Gestion de l'intensité de la lumière.
+
+BOOL CLight::SetLightIntensity(int lightRank, float value)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ ProgSet(m_lightTable[lightRank].intensity, value);
+ return TRUE;
+}
+
+float CLight::RetLightIntensity(int lightRank)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return 0.0f;
+
+ return m_lightTable[lightRank].intensity.current;
+}
+
+
+// Spécifie la vitesse de changement.
+
+BOOL CLight::SetLightColorSpeed(int lightRank, float speed)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ m_lightTable[lightRank].colorRed.speed = speed;
+ m_lightTable[lightRank].colorGreen.speed = speed;
+ m_lightTable[lightRank].colorBlue.speed = speed;
+ return TRUE;
+}
+
+// Gestion de la couleur de la lumière.
+
+BOOL CLight::SetLightColor(int lightRank, D3DCOLORVALUE color)
+{
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT ) return FALSE;
+
+ ProgSet(m_lightTable[lightRank].colorRed, color.r);
+ ProgSet(m_lightTable[lightRank].colorGreen, color.g);
+ ProgSet(m_lightTable[lightRank].colorBlue, color.b);
+ return TRUE;
+}
+
+D3DCOLORVALUE CLight::RetLightColor(int lightRank)
+{
+ D3DCOLORVALUE color;
+
+ if ( lightRank < 0 || lightRank >= D3DMAXLIGHT )
+ {
+ color.r = 0.5f;
+ color.g = 0.5f;
+ color.b = 0.5f;
+ color.a = 0.5f;
+ return color;
+ }
+
+ color.r = m_lightTable[lightRank].colorRed.current;
+ color.g = m_lightTable[lightRank].colorGreen.current;
+ color.b = m_lightTable[lightRank].colorBlue.current;
+ return color;
+}
+
+
+// Adapte la couleur de toutes les lumières.
+
+void CLight::AdaptLightColor(D3DCOLORVALUE color, float factor)
+{
+ D3DCOLORVALUE value;
+ int i;
+
+ for ( i=0 ; i<m_lightUsed ; i++ )
+ {
+ if ( m_lightTable[i].bUsed == FALSE ) continue;
+
+ value.r = m_lightTable[i].colorRed.current;
+ value.g = m_lightTable[i].colorGreen.current;
+ value.b = m_lightTable[i].colorBlue.current;
+
+ value.r += color.r*factor;
+ value.g += color.g*factor;
+ value.b += color.b*factor;
+
+ ProgInit(m_lightTable[i].colorRed, value.r);
+ ProgInit(m_lightTable[i].colorGreen, value.g);
+ ProgInit(m_lightTable[i].colorBlue, value.b);
+ }
+
+ LightUpdate();
+}
+
+
+
+// Fait évoluer toutes les lumières.
+
+void CLight::FrameLight(float rTime)
+{
+ D3DVECTOR dir;
+ float angle;
+ int i;
+
+ if ( m_engine->RetPause() ) return;
+
+ m_time += rTime;
+
+ for ( i=0 ; i<m_lightUsed ; i++ )
+ {
+ if ( m_lightTable[i].bUsed == FALSE ) continue;
+
+ ProgFrame(m_lightTable[i].intensity, rTime);
+ ProgFrame(m_lightTable[i].colorRed, rTime);
+ ProgFrame(m_lightTable[i].colorGreen, rTime);
+ ProgFrame(m_lightTable[i].colorBlue, rTime);
+
+ if ( m_lightTable[i].incluType == TYPEQUARTZ )
+ {
+ m_lightTable[i].light.dvDirection.x = sinf((m_time+i*PI*0.5f)*1.0f);
+ m_lightTable[i].light.dvDirection.z = cosf((m_time+i*PI*0.5f)*1.1f);
+ m_lightTable[i].light.dvDirection.y = -1.0f+cosf((m_time+i*PI*0.5f)*2.7f)*0.5f;
+ }
+
+ if ( m_lightTable[i].incluType == TYPEMETAL )
+ {
+ dir = m_engine->RetEyePt()-m_engine->RetLookatPt();
+ angle = RotateAngle(dir.x, dir.z);
+ angle += PI*0.5f*i;
+ m_lightTable[i].light.dvDirection.x = sinf(angle*2.0f);
+ m_lightTable[i].light.dvDirection.z = cosf(angle*2.0f);
+ }
+ }
+}
+
+
+// Met à jour toutes les lumières.
+
+void CLight::LightUpdate()
+{
+ BOOL bEnable;
+ float value;
+ int i;
+
+ for ( i=0 ; i<m_lightUsed ; i++ )
+ {
+ if ( m_lightTable[i].bUsed == FALSE ) continue;
+
+ bEnable = m_lightTable[i].bEnable;
+ if ( m_lightTable[i].intensity.current == 0.0f ) bEnable = FALSE;
+
+ if ( bEnable )
+ {
+ value = m_lightTable[i].colorRed.current * m_lightTable[i].intensity.current;
+ m_lightTable[i].light.dcvDiffuse.r = value;
+
+ value = m_lightTable[i].colorGreen.current * m_lightTable[i].intensity.current;
+ m_lightTable[i].light.dcvDiffuse.g = value;
+
+ value = m_lightTable[i].colorBlue.current * m_lightTable[i].intensity.current;
+ m_lightTable[i].light.dcvDiffuse.b = value;
+
+ m_pD3DDevice->SetLight(i, &m_lightTable[i].light);
+ m_pD3DDevice->LightEnable(i, bEnable);
+ }
+ else
+ {
+ m_lightTable[i].light.dcvDiffuse.r = 0.0f;
+ m_lightTable[i].light.dcvDiffuse.g = 0.0f;
+ m_lightTable[i].light.dcvDiffuse.b = 0.0f;
+
+ m_pD3DDevice->LightEnable(i, bEnable);
+ }
+ }
+}
+
+// Met à jour les lumières pour un type donné.
+
+void CLight::LightUpdate(D3DTypeObj type)
+{
+ BOOL bEnable;
+ int i;
+
+ for ( i=0 ; i<m_lightUsed ; i++ )
+ {
+ if ( m_lightTable[i].bUsed == FALSE ) continue;
+ if ( m_lightTable[i].bEnable == FALSE ) continue;
+ if ( m_lightTable[i].intensity.current == 0.0f ) continue;
+
+ if ( m_lightTable[i].incluType != TYPENULL )
+ {
+ bEnable = (m_lightTable[i].incluType == type);
+ m_pD3DDevice->LightEnable(i, bEnable);
+ }
+
+ if ( m_lightTable[i].excluType != TYPENULL )
+ {
+ bEnable = (m_lightTable[i].excluType != type);
+ m_pD3DDevice->LightEnable(i, bEnable);
+ }
+ }
+}
+
+
diff --git a/src/light.h b/src/light.h
new file mode 100644
index 0000000..c67f219
--- /dev/null
+++ b/src/light.h
@@ -0,0 +1,95 @@
+// light.h
+
+#ifndef _LIGHT_H_
+#define _LIGHT_H_
+
+
+
+class CInstanceManager;
+class CD3DEngine;
+
+
+#define D3DMAXLIGHT 100
+
+
+typedef struct
+{
+ float starting;
+ float ending;
+ float current;
+ float progress;
+ float speed;
+}
+LightProg;
+
+
+typedef struct
+{
+ char bUsed; // TRUE -> lumière existe
+ char bEnable; // TRUE -> lumière allumée
+
+ D3DTypeObj incluType; // type de tous les objets inclus
+ D3DTypeObj excluType; // type de tous les objets exclus
+
+ D3DLIGHT7 light; // configuration de la lumière
+
+ LightProg intensity; // intensité (0..1)
+ LightProg colorRed;
+ LightProg colorGreen;
+ LightProg colorBlue;
+}
+Light;
+
+
+
+class CLight
+{
+public:
+ CLight(CInstanceManager *iMan, CD3DEngine* engine);
+ ~CLight();
+
+ void SetD3DDevice(LPDIRECT3DDEVICE7 device);
+
+ void FlushLight();
+ int CreateLight();
+ BOOL DeleteLight(int lightRank);
+ BOOL SetLight(int lightRank, const D3DLIGHT7 &light);
+ BOOL GetLight(int lightRank, D3DLIGHT7 &light);
+ BOOL LightEnable(int lightRank, BOOL bEnable);
+
+ BOOL SetLightIncluType(int lightRank, D3DTypeObj type);
+ BOOL SetLightExcluType(int lightRank, D3DTypeObj type);
+
+ BOOL SetLightPos(int lightRank, D3DVECTOR pos);
+ D3DVECTOR RetLightPos(int lightRank);
+
+ BOOL SetLightDir(int lightRank, D3DVECTOR dir);
+ D3DVECTOR RetLightDir(int lightRank);
+
+ BOOL SetLightIntensitySpeed(int lightRank, float speed);
+ BOOL SetLightIntensity(int lightRank, float value);
+ float RetLightIntensity(int lightRank);
+ void AdaptLightColor(D3DCOLORVALUE color, float factor);
+
+ BOOL SetLightColorSpeed(int lightRank, float speed);
+ BOOL SetLightColor(int lightRank, D3DCOLORVALUE color);
+ D3DCOLORVALUE RetLightColor(int lightRank);
+
+ void FrameLight(float rTime);
+ void LightUpdate();
+ void LightUpdate(D3DTypeObj type);
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+
+ float m_time;
+ int m_lightUsed;
+ Light* m_lightTable;
+};
+
+
+#endif //_LIGHT_H_
diff --git a/src/list.cpp b/src/list.cpp
new file mode 100644
index 0000000..79a3dd6
--- /dev/null
+++ b/src/list.cpp
@@ -0,0 +1,858 @@
+// list.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "button.h"
+#include "scroll.h"
+#include "text.h"
+#include "list.h"
+
+
+
+#define MARGING 4.0f
+
+
+
+// Constructeur de l'objet.
+
+CList::CList(CInstanceManager* iMan) : CControl(iMan)
+{
+ int i;
+
+ CControl::CControl(iMan);
+
+ for ( i=0 ; i<LISTMAXDISPLAY ; i++ )
+ {
+ m_button[i] = 0;
+ }
+ m_scroll = 0;
+
+ for ( i=0 ; i<LISTMAXTOTAL ; i++ )
+ {
+ m_text[i][0] = 0;
+ m_check[i] = FALSE;
+ m_enable[i] = TRUE;
+ }
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ m_tabs[i] = 0.0f;
+ m_justifs[i] = 1;
+ }
+
+ m_totalLine = 0;
+ m_displayLine = 0;
+ m_selectLine = -1;
+ m_firstLine = 0;
+ m_bBlink = FALSE;
+ m_bSelectCap = TRUE;
+ m_blinkTime = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CList::~CList()
+{
+ int i;
+
+ for ( i=0 ; i<LISTMAXDISPLAY ; i++ )
+ {
+ delete m_button[i];
+ }
+ delete m_scroll;
+
+ CControl::~CControl();
+}
+
+
+// Crée une nouvelle liste.
+
+BOOL CList::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg,
+ float expand)
+{
+ m_expand = expand;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ m_scroll = new CScroll(m_iMan);
+ m_scroll->Create(pos, dim, 0, EVENT_NULL);
+ m_eventScroll = m_scroll->RetEventMsg();
+
+ return MoveAdjust();
+}
+
+// Ajuste après un changement de dimensions.
+
+BOOL CList::MoveAdjust()
+{
+ FPOINT ipos, idim, ppos, ddim;
+ float marging, h;
+ int i;
+
+ for ( i=0 ; i<LISTMAXDISPLAY ; i++ )
+ {
+ delete m_button[i];
+ m_button[i] = 0;
+ }
+
+ if ( m_icon == 0 ) marging = MARGING;
+ else marging = 0.0f;
+
+ ipos.x = m_pos.x+marging/640.f;
+ ipos.y = m_pos.y+marging/480.f;
+ idim.x = m_dim.x-marging*2.0f/640.f;
+ idim.y = m_dim.y-marging*2.0f/480.f;
+
+ h = m_engine->RetText()->RetHeight(m_fontSize, m_fontType)*m_expand;
+
+ m_displayLine = (int)(idim.y/h);
+ if ( m_displayLine == 0 ) return FALSE;
+ if ( m_displayLine > LISTMAXDISPLAY ) m_displayLine = LISTMAXDISPLAY;
+ idim.y = h*m_displayLine;
+ m_dim.y = idim.y+marging*2.0f/480.f;
+
+ ppos.x = ipos.x;
+ ppos.y = ipos.y+idim.y-h;
+ ddim.x = idim.x-SCROLL_WIDTH;
+ ddim.y = h;
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ m_button[i] = new CButton(m_iMan);
+ m_button[i]->Create(ppos, ddim, -1, EVENT_NULL);
+ m_button[i]->SetJustif(1);
+ m_button[i]->SetState(STATE_SIMPLY);
+ m_button[i]->SetFontType(m_fontType);
+ m_button[i]->SetFontSize(m_fontSize);
+ ppos.y -= h;
+
+ m_eventButton[i] = m_button[i]->RetEventMsg();
+ }
+
+ if ( m_scroll != 0 )
+ {
+ ppos.x = ipos.x+idim.x-SCROLL_WIDTH;
+ ppos.y = ipos.y;
+ ddim.x = SCROLL_WIDTH;
+ ddim.y = idim.y;
+ m_scroll->SetPos(ppos);
+ m_scroll->SetDim(ddim);
+ }
+
+ UpdateScroll();
+ UpdateButton();
+ return TRUE;
+}
+
+
+// Retourne le message d'un bouton.
+
+EventMsg CList::RetEventMsgButton(int i)
+{
+ if ( i < 0 || i >= m_displayLine ) return EVENT_NULL;
+ if ( m_button[i] == 0 ) return EVENT_NULL;
+ return m_button[i]->RetEventMsg();
+}
+
+// Retourne le message de l'ascenseur.
+
+EventMsg CList::RetEventMsgScroll()
+{
+ if ( m_scroll == 0 ) return EVENT_NULL;
+ return m_scroll->RetEventMsg();
+}
+
+
+void CList::SetPos(FPOINT pos)
+{
+ CControl::SetPos(pos);
+}
+
+void CList::SetDim(FPOINT dim)
+{
+ m_dim = dim;
+ MoveAdjust();
+ CControl::SetDim(dim);
+}
+
+
+BOOL CList::SetState(int state, BOOL bState)
+{
+ int i;
+
+ if ( state & STATE_ENABLE )
+ {
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( m_button[i] != 0 ) m_button[i]->SetState(state, bState);
+ }
+ if ( m_scroll != 0 ) m_scroll->SetState(state, bState);
+ }
+
+ return CControl::SetState(state, bState);
+}
+
+BOOL CList::SetState(int state)
+{
+ int i;
+
+ if ( state & STATE_ENABLE )
+ {
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( m_button[i] != 0 ) m_button[i]->SetState(state);
+ }
+ if ( m_scroll != 0 ) m_scroll->SetState(state);
+ }
+
+ return CControl::SetState(state);
+}
+
+BOOL CList::ClearState(int state)
+{
+ int i;
+
+ if ( state & STATE_ENABLE )
+ {
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( m_button[i] != 0 ) m_button[i]->ClearState(state);
+ }
+ if ( m_scroll != 0 ) m_scroll->ClearState(state);
+ }
+
+ return CControl::ClearState(state);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CList::EventProcess(const Event &event)
+{
+ int i;
+
+ if ( m_bBlink && // clignotte ?
+ event.event == EVENT_FRAME )
+ {
+ i = m_selectLine-m_firstLine;
+
+ if ( i >= 0 && i < 4 &&
+ m_button[i] != 0 )
+ {
+ m_blinkTime += event.rTime;
+ if ( Mod(m_blinkTime, 0.7f) < 0.3f )
+ {
+ m_button[i]->ClearState(STATE_ENABLE);
+ m_button[i]->ClearState(STATE_CHECK);
+ }
+ else
+ {
+ m_button[i]->SetState(STATE_ENABLE);
+ m_button[i]->SetState(STATE_CHECK);
+ }
+ }
+ }
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+ if ( (m_state & STATE_ENABLE) == 0 ) return TRUE;
+
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELUP &&
+ Detect(event.pos) )
+ {
+ if ( m_firstLine > 0 ) m_firstLine --;
+ UpdateScroll();
+ UpdateButton();
+ return TRUE;
+ }
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELDOWN &&
+ Detect(event.pos) )
+ {
+ if ( m_firstLine < m_totalLine-m_displayLine ) m_firstLine ++;
+ UpdateScroll();
+ UpdateButton();
+ return TRUE;
+ }
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_MOUSEMOVE && Detect(event.pos) )
+ {
+ m_engine->SetMouseType(D3DMOUSENORM);
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( i+m_firstLine >= m_totalLine ) break;
+ if ( m_button[i] != 0 )
+ {
+ m_button[i]->EventProcess(event);
+ }
+ }
+ }
+
+ if ( m_bSelectCap )
+ {
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( i+m_firstLine >= m_totalLine ) break;
+ if ( m_button[i] != 0 )
+ {
+ if ( !m_button[i]->EventProcess(event) ) return FALSE;
+
+ if ( event.event == m_eventButton[i] )
+ {
+ SetSelect(m_firstLine+i);
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent); // ligne sélectionnée changée
+ }
+ }
+ }
+ }
+
+ if ( m_scroll != 0 )
+ {
+ if ( !m_scroll->EventProcess(event) ) return FALSE;
+
+ if ( event.event == m_eventScroll )
+ {
+ MoveScroll();
+ UpdateButton();
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Dessine la liste.
+
+void CList::Draw()
+{
+ FPOINT uv1, uv2, corner, pos, dim, ppos, ddim;
+ float dp;
+ int i, j;
+ char text[100];
+ char *pb, *pe;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ dp = 0.5f/256.0f;
+
+ if ( m_icon != -1 )
+ {
+ dim = m_dim;
+
+ if ( m_icon == 0 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ uv1.x = 128.0f/256.0f;
+ uv1.y = 64.0f/256.0f; // u-v texture
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 96.0f/256.0f;
+ }
+ else
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ uv1.x = 132.0f/256.0f;
+ uv1.y = 68.0f/256.0f; // u-v texture
+ uv2.x = 156.0f/256.0f;
+ uv2.y = 92.0f/256.0f;
+
+ if ( m_button[0] != 0 )
+ {
+ dim = m_button[0]->RetDim();
+ dim.y *= m_displayLine; // fond pile-poil derrière
+ }
+ }
+
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ corner.x = 10.0f/640.0f;
+ corner.y = 10.0f/480.0f;
+ DrawIcon(m_pos, dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+
+ if ( m_totalLine < m_displayLine ) // boutons pas jusqu'en bas ?
+ {
+ i = m_totalLine;
+ if ( m_button[i] != 0 )
+ {
+ pos = m_button[i]->RetPos();
+ dim = m_button[i]->RetDim();
+ pos.y += dim.y*1.1f;
+ dim.y *= 0.4f;
+ pos.y -= dim.y;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 120.0f/256.0f;
+ uv1.y = 64.0f/256.0f;
+ uv2.x = 128.0f/256.0f;
+ uv2.y = 48.0f/256.0f;
+ uv1.x += dp;
+ uv1.y -= dp;
+ uv2.x -= dp;
+ uv2.y += dp;
+ DrawIcon(pos, dim, uv1, uv2); // ch'tite ombre mignonne
+ }
+ }
+
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( i+m_firstLine >= m_totalLine ) break;
+
+ if ( m_button[i] != 0 )
+ {
+ if ( !m_bBlink && i+m_firstLine < m_totalLine )
+ {
+ m_button[i]->SetState(STATE_ENABLE, m_enable[i+m_firstLine] && (m_state & STATE_ENABLE) );
+ }
+ m_button[i]->Draw(); // dessine une case sans texte
+
+ // dessine le texte dans la case
+ pos = m_button[i]->RetPos();
+ dim = m_button[i]->RetDim();
+ if ( m_tabs[0] == 0.0f )
+ {
+ ppos.x = pos.x+dim.y*0.5f;
+ ppos.y = pos.y+dim.y*0.5f;
+ ppos.y -= m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2.0f;
+ ddim.x = dim.x-dim.y;
+ DrawCase(m_text[i+m_firstLine], ppos, ddim.x, 1);
+ }
+ else
+ {
+ ppos.x = pos.x+dim.y*0.5f;
+ ppos.y = pos.y+dim.y*0.5f;
+ ppos.y -= m_engine->RetText()->RetHeight(m_fontSize, m_fontType)/2.0f;
+ pb = m_text[i+m_firstLine];
+ for ( j=0 ; j<10 ; j++ )
+ {
+ pe = strchr(pb, '\t');
+ if ( pe == 0 )
+ {
+ strcpy(text, pb);
+ }
+ else
+ {
+ strncpy(text, pb, pe-pb);
+ text[pe-pb] = 0;
+ }
+ DrawCase(text, ppos, m_tabs[j], m_justifs[j]);
+
+ if ( pe == 0 ) break;
+ ppos.x += m_tabs[j];
+ pb = pe+1;
+ }
+ }
+
+ if ( (m_state & STATE_EXTEND) && i < m_totalLine )
+ {
+ pos = m_button[i]->RetPos();
+ dim = m_button[i]->RetDim();
+ pos.x += dim.x-dim.y*0.75f;
+ dim.x = dim.y*0.75f;
+ pos.x += 2.0f/640.0f;
+ pos.y += 2.0f/480.0f;
+ dim.x -= 4.0f/640.0f;
+ dim.y -= 4.0f/480.0f;
+
+ if ( m_check[i+m_firstLine] )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // dessine carré
+
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 0.0f/256.0f; // v
+ uv1.y = 64.0f/256.0f;
+ uv2.x = 32.0f/256.0f;
+ uv2.y = 96.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // dessine v
+ }
+ else
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATETTw);
+ if ( i+m_firstLine == m_selectLine )
+ {
+ uv1.x =224.0f/256.0f; // <
+ uv1.y =192.0f/256.0f;
+ uv2.x =256.0f/256.0f;
+ uv2.y =224.0f/256.0f;
+ }
+ else
+ {
+ uv1.x = 96.0f/256.0f; // x
+ uv1.y = 32.0f/256.0f;
+ uv2.x =128.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ }
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // dessine x
+ }
+ }
+ }
+ }
+
+ if ( m_scroll != 0 )
+ {
+ m_scroll->Draw(); // dessine l'ascenseur
+ }
+}
+
+// Affiche un texte dans une case.
+
+void CList::DrawCase(char *text, FPOINT pos, float width, int justif)
+{
+ if ( justif == 1 )
+ {
+ m_engine->RetText()->DrawText(text, pos, width, 1, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ else if ( justif == 0 )
+ {
+ pos.x += width/2.0f;
+ m_engine->RetText()->DrawText(text, pos, width, 0, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ else
+ {
+ pos.x += width;
+ m_engine->RetText()->DrawText(text, pos, width, -1, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+}
+
+
+// Vide complètement la liste.
+
+void CList::Flush()
+{
+ m_totalLine = 0;
+ m_selectLine = -1;
+ m_firstLine = 0;
+ UpdateButton();
+ UpdateScroll();
+}
+
+
+// Spécifie le nombre total de lignes.
+
+void CList::SetTotal(int i)
+{
+ m_totalLine = i;
+}
+
+// Retourne le nombre total de lignes.
+
+int CList::RetTotal()
+{
+ return m_totalLine;
+}
+
+
+// Sélectionne une ligne.
+
+void CList::SetSelect(int i)
+{
+ if ( m_bSelectCap )
+ {
+ m_selectLine = i;
+ }
+ else
+ {
+ m_firstLine = i;
+ UpdateScroll();
+ }
+
+ UpdateButton();
+}
+
+// Retourne la ligne sélectionnée.
+
+int CList::RetSelect()
+{
+ if ( m_bSelectCap )
+ {
+ return m_selectLine;
+ }
+ else
+ {
+ return m_firstLine;
+ }
+}
+
+
+// Gestion de la capacité à sélectionner une case.
+
+void CList::SetSelectCap(BOOL bEnable)
+{
+ m_bSelectCap = bEnable;
+}
+
+BOOL CList::RetSelectCap()
+{
+ return m_bSelectCap;
+}
+
+
+// Fait cligontter une ligne.
+
+void CList::SetBlink(BOOL bEnable)
+{
+ int i;
+
+ m_bBlink = bEnable;
+ m_blinkTime = 0.0f;
+
+ i = m_selectLine-m_firstLine;
+
+ if ( i >= 0 && i < 4 &&
+ m_button[i] != 0 )
+ {
+ if ( !bEnable )
+ {
+ m_button[i]->SetState(STATE_CHECK);
+ m_button[i]->ClearState(STATE_ENABLE);
+ }
+ }
+}
+
+BOOL CList::RetBlink()
+{
+ return m_bBlink;
+}
+
+
+// Spécifie le texte d'une ligne.
+
+void CList::SetName(int i, char* name)
+{
+ if ( i < 0 || i >= LISTMAXTOTAL ) return;
+
+ if ( i >= m_totalLine )
+ {
+ m_totalLine = i+1; // allonge la liste
+ }
+
+ if ( name[0] == 0 )
+ {
+ strcpy(m_text[i], " ");
+ }
+ else
+ {
+ strcpy(m_text[i], name);
+ }
+ UpdateButton();
+ UpdateScroll();
+}
+
+// Retourne le texte d'une ligne.
+
+char* CList::RetName(int i)
+{
+ if ( i < 0 || i >= m_totalLine ) return 0;
+
+ return m_text[i];
+}
+
+
+// Spécifie le bit "check" pour une case.
+
+void CList::SetCheck(int i, BOOL bMode)
+{
+ if ( i < 0 || i >= m_totalLine ) return;
+
+ m_check[i] = bMode;
+}
+
+// Retourne le bit "check" pour une case.
+
+BOOL CList::RetCheck(int i)
+{
+ if ( i < 0 || i >= m_totalLine ) return FALSE;
+
+ return m_check[i];
+}
+
+
+// Spécifie le bit "enable" pour une case.
+
+void CList::SetEnable(int i, BOOL bMode)
+{
+ if ( i < 0 || i >= m_totalLine ) return;
+
+ m_enable[i] = bMode;
+}
+
+// Retourne le bit "enable" pour une case.
+
+BOOL CList::RetEnable(int i)
+{
+ if ( i < 0 || i >= m_totalLine ) return FALSE;
+
+ return m_enable[i];
+}
+
+
+// Gestion de la position des tabulateurs.
+
+void CList::SetTabs(int i, float pos, int justif)
+{
+ if ( i < 0 || i >= 10 ) return;
+ m_tabs[i] = pos;
+ m_justifs[i] = justif;
+}
+
+float CList::RetTabs(int i)
+{
+ if ( i < 0 || i >= 10 ) return 0.0f;
+ return m_tabs[i];
+}
+
+
+// Déplace l'ascenseur de la liste pour voir la ligne sélectionnée.
+
+void CList::ShowSelect(BOOL bFixed)
+{
+ int sel;
+
+ if ( bFixed &&
+ m_selectLine >= m_firstLine &&
+ m_selectLine < m_firstLine+m_displayLine ) return; // tout bon
+
+ sel = m_selectLine;
+
+ // Descend de 1/2*h.
+ sel += m_displayLine/2;
+ if ( sel > m_totalLine-1 ) sel = m_totalLine-1;
+
+ // Remonte de h-1.
+ sel -= m_displayLine-1;
+ if ( sel < 0 ) sel = 0;
+
+ m_firstLine = sel;
+
+ UpdateButton();
+ UpdateScroll();
+}
+
+
+// Met à jour tous les noms des boutons.
+
+void CList::UpdateButton()
+{
+ int state, i, j;
+
+ state = CControl::RetState();
+
+ j = m_firstLine;
+ for ( i=0 ; i<m_displayLine ; i++ )
+ {
+ if ( m_button[i] == 0 ) continue;
+
+ m_button[i]->SetState(STATE_CHECK, (j == m_selectLine));
+
+ if ( j < m_totalLine )
+ {
+//? m_button[i]->SetName(m_text[j]);
+ m_button[i]->SetName(" "); // bouton vide
+ m_button[i]->SetState(STATE_ENABLE, (state & STATE_ENABLE));
+ }
+ else
+ {
+ m_button[i]->SetName(" "); // bouton vide
+ m_button[i]->ClearState(STATE_ENABLE);
+ }
+ j ++;
+ }
+}
+
+// Met à jour l'ascenseur.
+
+void CList::UpdateScroll()
+{
+ float ratio, value, step;
+
+ if ( m_scroll == 0 ) return;
+
+ if ( m_totalLine <= m_displayLine )
+ {
+ ratio = 1.0f;
+ value = 0.0f;
+ step = 0.0f;
+ }
+ else
+ {
+ ratio = (float)m_displayLine/m_totalLine;
+ if ( ratio > 1.0f ) ratio = 1.0f;
+
+ value = (float)m_firstLine/(m_totalLine-m_displayLine);
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+
+ step = (float)1.0f/(m_totalLine-m_displayLine);
+ if ( step < 0.0f ) step = 0.0f;
+ }
+
+ m_scroll->SetVisibleRatio(ratio);
+ m_scroll->SetVisibleValue(value);
+ m_scroll->SetArrowStep(step);
+}
+
+// Mise à jour lorsque l'ascenseur a été bougé.
+
+void CList::MoveScroll()
+{
+ float pos;
+ int n;
+
+ if ( m_scroll == 0 ) return;
+
+ n = m_totalLine-m_displayLine;
+ pos = m_scroll->RetVisibleValue();
+ pos += m_scroll->RetArrowStep()/2.0f; // c'est magique !
+ m_firstLine = (int)(pos*n);
+ if ( m_firstLine < 0 ) m_firstLine = 0;
+ if ( m_firstLine > n ) m_firstLine = n;
+}
+
+
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..f3ff1d5
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,100 @@
+// list.h
+
+#ifndef _LIST_H_
+#define _LIST_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CButton;
+class CScroll;
+
+
+#define LISTMAXDISPLAY 20 // nb max de lignes visibles
+#define LISTMAXTOTAL 100 // nb max de lignes total
+
+
+
+class CList : public CControl
+{
+public:
+ CList(CInstanceManager* iMan);
+ ~CList();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg, float expand);
+
+ void SetPos(FPOINT pos);
+ void SetDim(FPOINT dim);
+
+ BOOL SetState(int state, BOOL bState);
+ BOOL SetState(int state);
+ BOOL ClearState(int state);
+
+ BOOL EventProcess(const Event &event);
+ void Draw();
+
+ void Flush();
+
+ void SetTotal(int i);
+ int RetTotal();
+
+ void SetSelect(int i);
+ int RetSelect();
+
+ void SetSelectCap(BOOL bEnable);
+ BOOL RetSelectCap();
+
+ void SetBlink(BOOL bEnable);
+ BOOL RetBlink();
+
+ void SetName(int i, char* name);
+ char* RetName(int i);
+
+ void SetCheck(int i, BOOL bMode);
+ BOOL RetCheck(int i);
+
+ void SetEnable(int i, BOOL bEnable);
+ BOOL RetEnable(int i);
+
+ void SetTabs(int i, float pos, int justif=1);
+ float RetTabs(int i);
+
+ void ShowSelect(BOOL bFixed);
+
+ EventMsg RetEventMsgButton(int i);
+ EventMsg RetEventMsgScroll();
+
+protected:
+ BOOL MoveAdjust();
+ void UpdateButton();
+ void UpdateScroll();
+ void MoveScroll();
+ void DrawCase(char *text, FPOINT pos, float width, int justif);
+
+protected:
+ CButton* m_button[LISTMAXDISPLAY];
+ CScroll* m_scroll;
+
+ EventMsg m_eventButton[LISTMAXDISPLAY];
+ EventMsg m_eventScroll;
+
+ float m_expand;
+ int m_totalLine; // nb total de lignes
+ int m_displayLine; // nb de lignes visibles
+ int m_selectLine; // ligne sélectionnée
+ int m_firstLine; // première ligne visible
+ BOOL m_bBlink;
+ BOOL m_bSelectCap;
+ float m_blinkTime;
+ float m_tabs[10];
+ int m_justifs[10];
+
+ char m_text[LISTMAXTOTAL][100];
+ char m_check[LISTMAXTOTAL];
+ char m_enable[LISTMAXTOTAL];
+};
+
+
+#endif //_LIST_H_
diff --git a/src/maindialog.cpp b/src/maindialog.cpp
new file mode 100644
index 0000000..b4e67f1
--- /dev/null
+++ b/src/maindialog.cpp
@@ -0,0 +1,6922 @@
+// maindialog.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <time.h>
+#include <direct.h>
+#include <io.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "profile.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "particule.h"
+#include "interface.h"
+#include "button.h"
+#include "color.h"
+#include "check.h"
+#include "key.h"
+#include "group.h"
+#include "image.h"
+#include "scroll.h"
+#include "slider.h"
+#include "list.h"
+#include "label.h"
+#include "window.h"
+#include "edit.h"
+#include "editvalue.h"
+#include "text.h"
+#include "camera.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "robotmain.h"
+#include "maindialog.h"
+
+
+
+#define KEY_VISIBLE 6 // nb de touches redéfinissables visibles
+
+#if _SCHOOL & _TEEN
+#define KEY_TOTAL 13 // nb total de touches redéfinissables
+#else
+#define KEY_TOTAL 21 // nb total de touches redéfinissables
+#endif
+
+#define WELCOME_LENGTH 6.0f
+
+
+
+static int perso_color[3*10*3] =
+{
+ // cheveux :
+ 193, 221, 226, // blanc
+ 255, 255, 181, // jaune
+ 204, 155, 84, // châtin
+ 165, 48, 10, // roux
+ 140, 75, 84, // brun
+ 83, 64, 51, // brun
+ 90, 95, 85, // noir
+ 85, 48, 9, // brun
+ 60, 0, 23, // noir
+ 0, 0, 0, //
+ // combinaison :
+ 203, 206, 204, // blanc sale
+ 0, 205, 203, // bleuté
+ 108, 176, 0, // verdatre
+ 207, 207, 32, // jaune
+ 170, 141, 0, // orangé
+ 108, 84, 0, // brun
+ 0, 84, 136, // bleuté
+ 56, 61, 146, // bleuté
+ 56, 56, 56, // noir
+ 0, 0, 0, //
+ // bandes :
+ 255, 255, 255, // blanc
+ 255, 255, 0, // jaune
+ 255, 132, 1, // orange
+ 255, 0, 255, // magenta
+ 255, 0, 0, // rouge
+ 0, 255, 0, // vert
+ 0, 255, 255, // cyan
+ 0, 0, 255, // bleu
+ 70, 51, 84, // foncé
+ 0, 0, 0, //
+};
+
+
+#if _NET
+// Vérifie si la clé "school" est présente dans la base de registres.
+
+BOOL SchoolCheck()
+{
+ HKEY key;
+ char buffer[100];
+ LONG i;
+ DWORD type, len;
+
+ i = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+#if _NEWLOOK
+ "Software\\Epsitec\\CeeBot\\Setup",
+#else
+ "Software\\Epsitec\\Colobot\\Setup",
+#endif
+ 0, KEY_READ, &key);
+ if ( i != ERROR_SUCCESS ) return FALSE;
+
+ type = REG_SZ;
+ len = sizeof(buffer);
+ i = RegQueryValueEx(key, "School", NULL, &type, (LPBYTE)buffer, &len);
+ if ( i != ERROR_SUCCESS || type != REG_SZ ) return FALSE;
+
+ if ( strcmp(buffer, "ToBoLoC") != 0 ) return FALSE;
+
+ return TRUE;
+}
+#endif
+
+
+// Constructeur de l'application robot.
+
+CMainDialog::CMainDialog(CInstanceManager* iMan)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_DIALOG, this);
+
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_phase = PHASE_NAME;
+ m_phaseSetup = PHASE_SETUPg;
+ m_phaseTerm = PHASE_TRAINER;
+ m_sceneRead[0] = 0;
+ m_stackRead[0] = 0;
+ m_sceneName[0] = 0;
+ m_sceneRank = 0;
+ m_bSceneSoluce = FALSE;
+ m_bSimulSetup = FALSE;
+#if _NET
+ m_accessEnable = SchoolCheck();
+ m_accessMission= FALSE;
+ m_accessUser = FALSE;
+#else
+ m_accessEnable = TRUE;
+ m_accessMission= TRUE;
+ m_accessUser = TRUE;
+#endif
+ m_bDeleteGamer = TRUE;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ m_chap[i] = 0;
+ m_sel[i] = 0;
+ }
+ m_index = 0;
+ m_maxList = 0;
+
+ ZeroMemory(&m_perso, sizeof(GamerPerso));
+ DefPerso();
+
+ m_bTooltip = TRUE;
+ m_bGlint = TRUE;
+ m_bRain = TRUE;
+ m_bSoluce4 = TRUE;
+ m_bMovies = TRUE;
+ m_bNiceReset = TRUE;
+ m_bHimselfDamage = TRUE;
+#if _TEEN
+ m_bCameraScroll = FALSE;
+#else
+ m_bCameraScroll = TRUE;
+#endif
+ m_bCameraInvertX = FALSE;
+ m_bCameraInvertY = FALSE;
+ m_bEffect = TRUE;
+ m_shotDelay = 0;
+
+ m_glintMouse = FPOINT(0.0f, 0.0f);
+ m_glintTime = 1000.0f;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ m_partiPhase[i] = 0;
+ m_partiTime[i] = 0.0f;
+ }
+
+ strcpy(m_sceneDir, "scene");
+ strcpy(m_savegameDir, "savegame");
+ strcpy(m_publicDir, "program");
+ strcpy(m_userDir, "user");
+ strcpy(m_filesDir, "files");
+
+ m_bDialog = FALSE;
+}
+
+// Destructeur de l'application robot.
+
+CMainDialog::~CMainDialog()
+{
+}
+
+
+// Change de phase.
+
+void CMainDialog::ChangePhase(Phase phase)
+{
+ CWindow* pw;
+ CEdit* pe;
+ CEditValue* pv;
+ CLabel* pl;
+ CList* pli;
+ CCheck* pc;
+ CScroll* ps;
+ CSlider* psl;
+ CButton* pb;
+ CColor* pco;
+ CGroup* pg;
+ CImage* pi;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+ char name[100];
+ char* gamer;
+ int res, i, j;
+
+ m_camera->SetType(CAMERA_DIALOG);
+ m_engine->SetOverFront(FALSE);
+ m_engine->SetOverColor(RetColor(0.0f), D3DSTATETCb);
+
+ if ( phase == PHASE_TERM )
+ {
+ phase = m_phaseTerm;
+ }
+ m_phase = phase; // copie l'info de CRobotMain
+ m_phaseTime = 0.0f;
+
+ dim.x = 32.0f/640.0f;
+ dim.y = 32.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = (32.0f+2.0f)/640.0f;
+ sy = (32.0f+2.0f)/480.0f;
+
+ if ( m_phase == PHASE_INIT )
+ {
+ pos.x = 0.35f;
+ pos.y = 0.10f;
+ ddim.x = 0.30f;
+ ddim.y = 0.80f;
+#if _TEEN
+ pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
+#else
+ pw = m_interface->CreateWindows(pos, ddim, 10, EVENT_WINDOW5);
+#endif
+ GetResource(RES_TEXT, RT_TITLE_INIT, name);
+ pw->SetName(name);
+
+ pos.x = 0.35f;
+ pos.y = 0.60f;
+ ddim.x = 0.30f;
+ ddim.y = 0.30f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.35f;
+ pos.y = 0.10f;
+ ddim.x = 0.30f;
+ ddim.y = 0.30f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+#if _SCHOOL
+ ddim.x = 0.20f;
+ ddim.y = dim.y*2.4f;
+ pos.x = 0.40f;
+ pos.y = oy+sy*7.9f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // orangé
+ pg->SetState(STATE_SHADOW);
+ pos.y = oy+sy*3.9f;
+ pg = pw->CreateGroup(pos, ddim, 25, EVENT_LABEL1); // orange
+ pg->SetState(STATE_SHADOW);
+ ddim.y = dim.y*1.2f;
+ pos.y = oy+sy*1.9f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // rouge
+ pg->SetState(STATE_SHADOW);
+#else
+ ddim.x = 0.20f;
+ ddim.y = dim.y*2.4f;
+ pos.x = 0.40f;
+ if ( m_accessEnable && m_accessMission )
+ {
+ pos.y = oy+sy*9.1f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // jaune
+ pg->SetState(STATE_SHADOW);
+ }
+ pos.y = oy+sy*6.8f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // orangé
+ pg->SetState(STATE_SHADOW);
+ pos.y = oy+sy*3.9f;
+ pg = pw->CreateGroup(pos, ddim, 25, EVENT_LABEL1); // orange
+ pg->SetState(STATE_SHADOW);
+ ddim.y = dim.y*1.2f;
+ pos.y = oy+sy*1.9f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // rouge
+ pg->SetState(STATE_SHADOW);
+#endif
+
+#if _SCHOOL
+ ddim.x = 0.18f;
+ ddim.y = dim.y*1;
+ pos.x = 0.41f;
+ pos.y = oy+sy*9.1f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_TRAINER);
+ pb->SetState(STATE_SHADOW);
+
+ pos.y = oy+sy*8.0f;
+#if _TEEN
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_TEEN);
+#else
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_DEFI);
+#endif
+#if _CEEBOTDEMO
+ pb->ClearState(STATE_ENABLE);
+#endif
+ pb->SetState(STATE_SHADOW);
+#else
+ ddim.x = 0.18f;
+ ddim.y = dim.y*1;
+ pos.x = 0.41f;
+
+ if ( m_accessEnable && m_accessMission )
+ {
+ pos.y = oy+sy*10.3f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MISSION);
+ pb->SetState(STATE_SHADOW);
+
+ pos.y = oy+sy*9.2f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_FREE);
+ pb->SetState(STATE_SHADOW);
+ }
+
+ pos.y = oy+sy*8.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_TRAINER);
+ pb->SetState(STATE_SHADOW);
+
+ pos.y = oy+sy*6.9f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_DEFI);
+ pb->SetState(STATE_SHADOW);
+#endif
+
+ if ( m_engine->RetSetupMode() )
+ {
+ pos.y = oy+sy*5.1f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUP);
+ pb->SetState(STATE_SHADOW);
+ }
+
+ pos.y = oy+sy*4.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NAME);
+ pb->SetState(STATE_SHADOW);
+
+ pos.y = oy+sy*2.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_QUIT);
+ pb->SetState(STATE_SHADOW);
+
+#if !_DEMO & !_SCHOOL
+ if ( m_accessEnable && m_accessUser )
+ {
+ pos.x = 447.0f/640.0f;
+ pos.y = 313.0f/480.0f;
+ ddim.x = 0.09f;
+#if _POLISH
+ pos.x -= 5.0f/640.0f;
+ ddim.x += 10.0f/640.0f;
+#endif
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_USER);
+ pb->SetState(STATE_SHADOW);
+ }
+#endif
+
+ if ( m_engine->RetDebugMode() )
+ {
+ pos.x = 139.0f/640.0f;
+ pos.y = 313.0f/480.0f;
+ ddim.x = 0.09f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PROTO);
+ pb->SetState(STATE_SHADOW);
+ }
+
+ pos.x = 0.40f;
+ ddim.x = 0.20f;
+ pos.y = 26.0f/480.0f;
+ ddim.y = 12.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 1, EVENT_LABEL1);
+ pg->SetState(STATE_SHADOW);
+ pos.y -= 5.0f/480.0f;
+#if _WG
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, " ");
+#else
+#if _NEWLOOK
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, "www.epsitec.ch");
+#else
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, "www.ceebot.com");
+#endif
+#endif
+ pl->SetFontType(FONT_COURIER);
+ pl->SetFontSize(8.0f);
+
+ m_engine->SetBackground("inter01.tga", 0,0, 0,0, TRUE, TRUE);
+ m_engine->SetBackForce(TRUE);
+ }
+
+ if ( m_phase == PHASE_NAME )
+ {
+ pos.x = 0.10f;
+ pos.y = 0.10f;
+ ddim.x = 0.80f;
+ ddim.y = 0.80f;
+ pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
+ GetResource(RES_TEXT, RT_TITLE_NAME, name);
+ pw->SetName(name);
+
+#if _NEWLOOK
+ pos.x = 80.0f/640.0f;
+ pos.y = 93.0f/480.0f;
+ ddim.x = 285.0f/640.0f;
+ ddim.y = 266.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ pos.x = 372.0f/640.0f;
+ ddim.x = 188.0f/640.0f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // violet
+ pg->SetState(STATE_SHADOW);
+#endif
+
+ pos.x = 0.10f;
+ pos.y = 0.40f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.40f;
+ pos.y = 0.10f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+ pos.x = 60.0f/640.0f;
+ pos.y = 313.0f/480.0f;
+ ddim.x = 120.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_NLABEL, name);
+ pl = pw->CreateLabel(pos, ddim, -1, EVENT_INTERFACE_NLABEL, name);
+ pl->SetJustif(-1);
+
+ pos.x = 200.0f/640.0f;
+ pos.y = 320.0f/480.0f;
+ ddim.x = 160.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 7, EVENT_LABEL1);
+ pg->SetState(STATE_SHADOW);
+
+ pos.x = 207.0f/640.0f;
+ pos.y = 328.0f/480.0f;
+ ddim.x = 144.0f/640.0f;
+ ddim.y = 18.0f/480.0f;
+ pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_NEDIT);
+ pe->SetMaxChar(15);
+ gamer = m_main->RetGamerName();
+ if ( gamer[0] == 0 )
+ {
+ GetResource(RES_TEXT, RT_NAME_DEFAULT, name);
+ }
+ else
+ {
+ strcpy(name, gamer);
+ }
+ pe->SetText(name);
+ pe->SetCursor(strlen(name), 0);
+ pe->SetFocus(TRUE);
+
+ pos.x = 380.0f/640.0f;
+ pos.y = 320.0f/480.0f;
+ ddim.x =100.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NOK);
+ pb->SetState(STATE_SHADOW);
+
+#if !_TEEN
+ pos.x = 380.0f/640.0f;
+ pos.y = 250.0f/480.0f;
+ ddim.x =100.0f/640.0f;
+ ddim.y = 52.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PERSO);
+ pb->SetState(STATE_SHADOW);
+#endif
+
+ pos.x = 200.0f/640.0f;
+ pos.y = 150.0f/480.0f;
+ ddim.x = 160.0f/640.0f;
+ ddim.y = 160.0f/480.0f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_NLIST);
+ pli->SetState(STATE_SHADOW);
+
+ if ( m_bDeleteGamer )
+ {
+ pos.x = 200.0f/640.0f;
+ pos.y = 100.0f/480.0f;
+ ddim.x = 160.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NDELETE);
+ pb->SetState(STATE_SHADOW);
+ }
+
+ pos.x = 380.0f/640.0f;
+ pos.y = 100.0f/480.0f;
+ ddim.x =100.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NCANCEL);
+ pb->SetState(STATE_SHADOW);
+
+ ReadNameList();
+ UpdateNameList();
+ UpdateNameControl();
+ UpdateNameFace();
+
+ m_engine->SetBackground("inter01.tga", 0,0, 0,0, TRUE, TRUE);
+ m_engine->SetBackForce(TRUE);
+ }
+
+ if ( m_phase == PHASE_PERSO )
+ {
+ pos.x = 0.10f;
+ pos.y = 0.10f;
+ ddim.x = 0.80f;
+ ddim.y = 0.80f;
+ pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
+ GetResource(RES_TEXT, RT_TITLE_PERSO, name);
+ pw->SetName(name);
+
+#if _NEWLOOK
+ pos.x = 95.0f/640.0f;
+ pos.y = 66.0f/480.0f;
+ ddim.x = 443.0f/640.0f;
+ ddim.y = 42.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // violet
+ pg->SetState(STATE_SHADOW);
+#endif
+
+ pos.x = 0.10f;
+ pos.y = 0.40f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.40f;
+ pos.y = 0.10f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+ pos.x = 95.0f/640.0f;
+ pos.y = 108.0f/480.0f;
+ ddim.x = 220.0f/640.0f;
+ ddim.y = 274.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 17, EVENT_NULL); // cadre
+
+ pos.x = 100.0f/640.0f;
+ pos.y = 364.0f/480.0f;
+ ddim.x = 210.0f/640.0f;
+ ddim.y = 14.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 3, EVENT_NULL); // transparent -> gris
+
+ pos.x = 120.0f/640.0f;
+ pos.y = 364.0f/480.0f;
+ ddim.x = 80.0f/640.0f;
+ ddim.y = 28.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PHEAD);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+
+ pos.x = 210.0f/640.0f;
+ pos.y = 364.0f/480.0f;
+ ddim.x = 80.0f/640.0f;
+ ddim.y = 28.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PBODY);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+
+ pos.x = 100.0f/640.0f;
+ pos.y = 354.0f/480.0f;
+ ddim.x = 210.0f/640.0f;
+ ddim.y = 10.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 1, EVENT_INTERFACE_GLINTb); // barre orange
+ pos.x = 100.0f/640.0f;
+ pos.y = 154.0f/480.0f;
+ ddim.x = 210.0f/640.0f;
+ ddim.y = 200.0f/480.0f;
+ pw->CreateGroup(pos, ddim, 2, EVENT_INTERFACE_GLINTu); // orange -> transparent
+
+ // Visage
+ pos.x = 340.0f/640.0f;
+ pos.y = 356.0f/480.0f;
+ ddim.x = 200.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, "");
+ pl->SetJustif(1);
+
+ pos.x = 340.0f/640.0f;
+ pos.y = 312.0f/480.0f;
+ ddim.x = 44.0f/640.0f;
+ ddim.y = 44.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, 43, EVENT_INTERFACE_PFACE1);
+ pb->SetState(STATE_SHADOW);
+ pos.x += 50.0f/640.0f;
+ pb = pw->CreateButton(pos, ddim, 46, EVENT_INTERFACE_PFACE4);
+ pb->SetState(STATE_SHADOW);
+ pos.x += 50.0f/640.0f;
+ pb = pw->CreateButton(pos, ddim, 45, EVENT_INTERFACE_PFACE3);
+ pb->SetState(STATE_SHADOW);
+ pos.x += 50.0f/640.0f;
+ pb = pw->CreateButton(pos, ddim, 44, EVENT_INTERFACE_PFACE2);
+ pb->SetState(STATE_SHADOW);
+
+ // Lunettes
+ pos.x = 340.0f/640.0f;
+ pos.y = 270.0f/480.0f;
+ ddim.x = 200.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, "");
+ pl->SetJustif(1);
+
+ pos.x = 340.0f/640.0f;
+ pos.y = 240.0f/480.0f;
+ ddim.x = 30.0f/640.0f;
+ ddim.y = 30.0f/480.0f;
+ for ( i=0 ; i<6 ; i++ )
+ {
+ int ti[6] = {11, 179, 180, 181, 182, 183};
+ pb = pw->CreateButton(pos, ddim, ti[i], (EventMsg)(EVENT_INTERFACE_PGLASS0+i));
+ pb->SetState(STATE_SHADOW);
+ pos.x += (30.0f+2.8f)/640.0f;
+ }
+
+ // Couleur a
+ pos.x = 340.0f/640.0f;
+ pos.y = 300.0f/480.0f;
+ ddim.x = 200.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL14, "");
+ pl->SetJustif(1);
+
+ pos.y = 282.0f/480.0f;
+ ddim.x = 18.0f/640.0f;
+ ddim.y = 18.0f/480.0f;
+ for ( j=0 ; j<3 ; j++ )
+ {
+ pos.x = 340.0f/640.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ pco = pw->CreateColor(pos, ddim, -1, (EventMsg)(EVENT_INTERFACE_PC0a+j*3+i));
+ pco->SetState(STATE_SHADOW);
+ pos.x += 20.0f/640.0f;
+ }
+ pos.y -= 20.0f/480.0f;
+ }
+
+ pos.x = 420.0f/640.0f;
+ pos.y = 282.0f/480.0f;
+ ddim.x = 100.0f/640.0f;
+ ddim.y = 18.0f/480.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ psl = pw->CreateSlider(pos, ddim, 0, (EventMsg)(EVENT_INTERFACE_PCRa+i));
+ psl->SetState(STATE_SHADOW);
+ psl->SetLimit(0.0f, 255.0f);
+ psl->SetArrowStep(16.0f);
+ pos.y -= 20.0f/480.0f;
+ }
+
+ // Couleur b
+ pos.x = 340.0f/640.0f;
+ pos.y = 192.0f/480.0f;
+ ddim.x = 200.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL13, "");
+ pl->SetJustif(1);
+
+ pos.y = 174.0f/480.0f;
+ ddim.x = 18.0f/640.0f;
+ ddim.y = 18.0f/480.0f;
+ for ( j=0 ; j<3 ; j++ )
+ {
+ pos.x = 340.0f/640.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ pco = pw->CreateColor(pos, ddim, -1, (EventMsg)(EVENT_INTERFACE_PC0b+j*3+i));
+ pco->SetState(STATE_SHADOW);
+ pos.x += 20.0f/640.0f;
+ }
+ pos.y -= 20.0f/480.0f;
+ }
+
+ pos.x = 420.0f/640.0f;
+ pos.y = 174.0f/480.0f;
+ ddim.x = 100.0f/640.0f;
+ ddim.y = 18.0f/480.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ psl = pw->CreateSlider(pos, ddim, 0, (EventMsg)(EVENT_INTERFACE_PCRb+i));
+ psl->SetState(STATE_SHADOW);
+ psl->SetLimit(0.0f, 255.0f);
+ psl->SetArrowStep(16.0f);
+ pos.y -= 20.0f/480.0f;
+ }
+
+ // Rotation
+ pos.x = 100.0f/640.0f;
+ pos.y = 113.0f/480.0f;
+ ddim.x = 20.0f/640.0f;
+ ddim.y = 20.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, 55, EVENT_INTERFACE_PLROT); // <
+ pb->SetState(STATE_SHADOW);
+ pb->SetRepeat(TRUE);
+
+ pos.x = 290.0f/640.0f;
+ pos.y = 113.0f/480.0f;
+ ddim.x = 20.0f/640.0f;
+ ddim.y = 20.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, 48, EVENT_INTERFACE_PRROT); // >
+ pb->SetState(STATE_SHADOW);
+ pb->SetRepeat(TRUE);
+
+ pos.x = 100.0f/640.0f;
+ pos.y = 70.0f/480.0f;
+ ddim.x = 100.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_POK);
+ pb->SetState(STATE_SHADOW);
+
+ pos.x = 210.0f/640.0f;
+ pos.y = 70.0f/480.0f;
+ ddim.x =100.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PCANCEL);
+ pb->SetState(STATE_SHADOW);
+
+ pos.x = 340.0f/640.0f;
+ pos.y = 70.0f/480.0f;
+ ddim.x =194.0f/640.0f;
+ ddim.y = 32.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PDEF);
+ pb->SetState(STATE_SHADOW);
+
+ m_persoCopy = m_perso;
+ m_persoTab = 0;
+ m_persoAngle = -0.6f;
+ UpdatePerso();
+ m_main->ScenePerso();
+ CameraPerso();
+ }
+
+ if ( m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO )
+ {
+ if ( m_phase == PHASE_TRAINER ) m_index = 0;
+ if ( m_phase == PHASE_DEFI ) m_index = 1;
+ if ( m_phase == PHASE_MISSION ) m_index = 2;
+ if ( m_phase == PHASE_FREE ) m_index = 3;
+ if ( m_phase == PHASE_USER ) m_index = 4;
+ if ( m_phase == PHASE_PROTO ) m_index = 5;
+ if ( m_phase == PHASE_TEEN ) m_index = 6;
+
+ if ( m_phase == PHASE_FREE )
+ {
+ strcpy(m_sceneName, "scene");
+ ReadGamerInfo();
+ m_accessChap = RetChapPassed();
+ }
+
+ if ( m_phase == PHASE_TRAINER ) strcpy(m_sceneName, "train");
+ if ( m_phase == PHASE_DEFI ) strcpy(m_sceneName, "defi" );
+ if ( m_phase == PHASE_MISSION ) strcpy(m_sceneName, "scene");
+ if ( m_phase == PHASE_FREE ) strcpy(m_sceneName, "free");
+ if ( m_phase == PHASE_TEEN ) strcpy(m_sceneName, "teen");
+ if ( m_phase == PHASE_USER ) strcpy(m_sceneName, "user");
+ if ( m_phase == PHASE_PROTO ) strcpy(m_sceneName, "proto");
+
+ ReadGamerInfo();
+
+ pos.x = 0.10f;
+ pos.y = 0.10f;
+ ddim.x = 0.80f;
+ ddim.y = 0.80f;
+ pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
+ pw->SetClosable(TRUE);
+ if ( m_phase == PHASE_TRAINER ) res = RT_TITLE_TRAINER;
+ if ( m_phase == PHASE_DEFI ) res = RT_TITLE_DEFI;
+ if ( m_phase == PHASE_MISSION ) res = RT_TITLE_MISSION;
+ if ( m_phase == PHASE_FREE ) res = RT_TITLE_FREE;
+ if ( m_phase == PHASE_TEEN ) res = RT_TITLE_TEEN;
+ if ( m_phase == PHASE_USER ) res = RT_TITLE_USER;
+ if ( m_phase == PHASE_PROTO ) res = RT_TITLE_PROTO;
+ GetResource(RES_TEXT, res, name);
+ pw->SetName(name);
+
+#if _NEWLOOK
+ pos.x = 100.0f/640.0f;
+ pos.y = 226.0f/480.0f;
+ ddim.x = 216.0f/640.0f;
+ ddim.y = 160.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ pos.x = 322.0f/640.0f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // cyan
+ pg->SetState(STATE_SHADOW);
+
+ pos.x = 100.0f/640.0f;
+ pos.y = 122.0f/480.0f;
+ ddim.x = 438.0f/640.0f;
+ ddim.y = 98.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 25, EVENT_LABEL1); // vert
+ pg->SetState(STATE_SHADOW);
+ pos.y = 66.0f/480.0f;
+ ddim.y = 42.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // violet
+ pg->SetState(STATE_SHADOW);
+#endif
+
+ pos.x = 0.10f;
+ pos.y = 0.40f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.40f;
+ pos.y = 0.10f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+ // Affiche la liste des chapitres :
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*10.5f;
+ ddim.x = dim.x*7.5f;
+ ddim.y = dim.y*0.6f;
+ if ( m_phase == PHASE_TRAINER ) res = RT_PLAY_CHAPt;
+ if ( m_phase == PHASE_DEFI ) res = RT_PLAY_CHAPd;
+ if ( m_phase == PHASE_MISSION ) res = RT_PLAY_CHAPm;
+ if ( m_phase == PHASE_FREE ) res = RT_PLAY_CHAPf;
+ if ( m_phase == PHASE_TEEN ) res = RT_PLAY_CHAPte;
+ if ( m_phase == PHASE_USER ) res = RT_PLAY_CHAPu;
+ if ( m_phase == PHASE_PROTO ) res = RT_PLAY_CHAPp;
+ GetResource(RES_TEXT, res, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name);
+ pl->SetJustif(1);
+
+ pos.y = oy+sy*6.7f;
+ ddim.y = dim.y*4.5f;
+ ddim.x = dim.x*6.5f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_CHAP);
+ pli->SetState(STATE_SHADOW);
+ UpdateSceneChap(m_chap[m_index]);
+ if ( m_phase != PHASE_USER ) pli->SetState(STATE_EXTEND);
+
+ // Affiche la liste des missions :
+ pos.x = ox+sx*9.5f;
+ pos.y = oy+sy*10.5f;
+ ddim.x = dim.x*7.5f;
+ ddim.y = dim.y*0.6f;
+ if ( m_phase == PHASE_TRAINER ) res = RT_PLAY_LISTt;
+ if ( m_phase == PHASE_DEFI ) res = RT_PLAY_LISTd;
+ if ( m_phase == PHASE_MISSION ) res = RT_PLAY_LISTm;
+ if ( m_phase == PHASE_FREE ) res = RT_PLAY_LISTf;
+ if ( m_phase == PHASE_TEEN ) res = RT_PLAY_LISTk;
+ if ( m_phase == PHASE_USER ) res = RT_PLAY_LISTu;
+ if ( m_phase == PHASE_PROTO ) res = RT_PLAY_LISTp;
+ GetResource(RES_TEXT, res, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name);
+ pl->SetJustif(1);
+
+ pos.y = oy+sy*6.7f;
+ ddim.y = dim.y*4.5f;
+ ddim.x = dim.x*6.5f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_LIST);
+ pli->SetState(STATE_SHADOW);
+ UpdateSceneList(m_chap[m_index], m_sel[m_index]);
+ if ( m_phase != PHASE_USER ) pli->SetState(STATE_EXTEND);
+ pos = pli->RetPos();
+ ddim = pli->RetDim();
+
+ // Affiche le résumé :
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*5.4f;
+ ddim.x = dim.x*6.5f;
+ ddim.y = dim.y*0.6f;
+ GetResource(RES_TEXT, RT_PLAY_RESUME, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL13, name);
+ pl->SetJustif(1);
+
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*3.6f;
+ ddim.x = dim.x*13.4f;
+ ddim.y = dim.y*1.9f;
+ pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_RESUME);
+ pe->SetState(STATE_SHADOW);
+ pe->SetMaxChar(500);
+ pe->SetEditCap(FALSE); // juste pour voir
+ pe->SetHiliteCap(FALSE);
+
+ // Affiche le bouton "soluce" :
+ if ( m_phase != PHASE_TRAINER &&
+ m_phase != PHASE_FREE &&
+ m_phase != PHASE_TEEN )
+ {
+ pos.x = ox+sx*9.5f;
+ pos.y = oy+sy*5.8f;
+ ddim.x = dim.x*6.5f;
+ ddim.y = dim.y*0.5f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SOLUCE);
+ pc->SetState(STATE_SHADOW);
+ pc->ClearState(STATE_CHECK);
+ }
+ m_bSceneSoluce = FALSE;
+
+ UpdateSceneResume((m_chap[m_index]+1)*100+(m_sel[m_index]+1));
+
+ if ( m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_USER )
+ {
+ pos.x = ox+sx*9.5f;
+ pos.y = oy+sy*2;
+ ddim.x = dim.x*3.7f;
+ ddim.y = dim.y*1;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PLAY);
+ pb->SetState(STATE_SHADOW);
+ if ( m_maxList == 0 )
+ {
+ pb->ClearState(STATE_ENABLE);
+ }
+
+ pos.x += dim.x*4.0f;
+ ddim.x = dim.x*2.5f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_READ);
+ pb->SetState(STATE_SHADOW);
+ if ( !IsIOReadScene() ) // aucun fichier à lire ?
+ {
+ pb->ClearState(STATE_ENABLE);
+ }
+ }
+ else
+ {
+ pos.x = ox+sx*9.5f;
+ pos.y = oy+sy*2;
+ ddim.x = dim.x*6.5f;
+ ddim.y = dim.y*1;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_PLAY);
+ pb->SetState(STATE_SHADOW);
+ if ( m_maxList == 0 )
+ {
+ pb->ClearState(STATE_ENABLE);
+ }
+ }
+
+ pos.x = ox+sx*3;
+ ddim.x = dim.x*4;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK);
+ pb->SetState(STATE_SHADOW);
+
+ m_engine->SetBackground("inter01.tga", 0,0, 0,0, TRUE, TRUE);
+ m_engine->SetBackForce(TRUE);
+ }
+
+ if ( m_phase == PHASE_SETUPd ||
+ m_phase == PHASE_SETUPg ||
+ m_phase == PHASE_SETUPp ||
+ m_phase == PHASE_SETUPc ||
+ m_phase == PHASE_SETUPs ||
+ m_phase == PHASE_SETUPds ||
+ m_phase == PHASE_SETUPgs ||
+ m_phase == PHASE_SETUPps ||
+ m_phase == PHASE_SETUPcs ||
+ m_phase == PHASE_SETUPss )
+ {
+ if ( m_phase == PHASE_SETUPds )
+ {
+ m_phaseSetup = PHASE_SETUPd;
+ m_bSimulSetup = TRUE;
+ }
+ else if ( m_phase == PHASE_SETUPgs )
+ {
+ m_phaseSetup = PHASE_SETUPg;
+ m_bSimulSetup = TRUE;
+ }
+ else if ( m_phase == PHASE_SETUPps )
+ {
+ m_phaseSetup = PHASE_SETUPp;
+ m_bSimulSetup = TRUE;
+ }
+ else if ( m_phase == PHASE_SETUPcs )
+ {
+ m_phaseSetup = PHASE_SETUPc;
+ m_bSimulSetup = TRUE;
+ }
+ else if ( m_phase == PHASE_SETUPss )
+ {
+ m_phaseSetup = PHASE_SETUPs;
+ m_bSimulSetup = TRUE;
+ }
+ else
+ {
+ m_phaseSetup = m_phase;
+ m_bSimulSetup = FALSE;
+ }
+
+ pos.x = 0.10f;
+ pos.y = 0.10f;
+ ddim.x = 0.80f;
+ ddim.y = 0.80f;
+ pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
+ pw->SetClosable(TRUE);
+ GetResource(RES_TEXT, RT_TITLE_SETUP, name);
+ pw->SetName(name);
+
+ pos.x = 0.70f;
+ pos.y = 0.10f;
+ ddim.x = 0.20f;
+ ddim.y = 0.20f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+ pos.x = 0.10f;
+ ddim.x = 0.80f;
+ pos.y = 0.76f;
+ ddim.y = 0.05f;
+ pw->CreateGroup(pos, ddim, 3, EVENT_NULL); // transparent -> gris
+
+#if _NEWLOOK
+ if ( m_phase == PHASE_SETUPd || // setup/display ?
+ m_phase == PHASE_SETUPds )
+ {
+ pos.x = 100.0f/640.0f;
+ pos.y = 130.0f/480.0f;
+ ddim.x = 216.0f/640.0f;
+ ddim.y = 212.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ pos.x = 324.0f/640.0f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // cyan
+ pg->SetState(STATE_SHADOW);
+ }
+ if ( m_phase == PHASE_SETUPg || // setup/graphic ?
+ m_phase == PHASE_SETUPgs )
+ {
+ pos.x = 100.0f/640.0f;
+ pos.y = 130.0f/480.0f;
+ ddim.x = 174.0f/640.0f;
+ ddim.y = 212.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ pos.x = 282.0f/640.0f;
+ ddim.x = 258.0f/640.0f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // cyan
+ pg->SetState(STATE_SHADOW);
+ }
+ if ( m_phase == PHASE_SETUPp || // setup/jeu ?
+ m_phase == PHASE_SETUPps )
+ {
+ pos.x = 100.0f/640.0f;
+ pos.y = 130.0f/480.0f;
+ ddim.x = 226.0f/640.0f;
+ ddim.y = 212.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ pos.x = 334.0f/640.0f;
+ ddim.x = 206.0f/640.0f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // cyan
+ pg->SetState(STATE_SHADOW);
+ }
+ if ( m_phase == PHASE_SETUPc || // setup/commande ?
+ m_phase == PHASE_SETUPcs )
+ {
+ pos.x = 100.0f/640.0f;
+ pos.y = 125.0f/480.0f;
+ ddim.x = 440.0f/640.0f;
+ ddim.y = 222.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ }
+ if ( m_phase == PHASE_SETUPs || // setup/sound ?
+ m_phase == PHASE_SETUPss )
+ {
+ pos.x = 100.0f/640.0f;
+ pos.y = 130.0f/480.0f;
+ ddim.x = 216.0f/640.0f;
+ ddim.y = 212.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 23, EVENT_LABEL1); // bleu
+ pg->SetState(STATE_SHADOW);
+ pos.x = 324.0f/640.0f;
+ pg = pw->CreateGroup(pos, ddim, 24, EVENT_LABEL1); // cyan
+ pg->SetState(STATE_SHADOW);
+ }
+
+ pos.x = 100.0f/640.0f;
+ pos.y = 66.0f/480.0f;
+ ddim.x = 440.0f/640.0f;
+ ddim.y = 42.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // violet
+ pg->SetState(STATE_SHADOW);
+#endif
+
+ ddim.x = 0.78f/5-0.01f;
+ ddim.y = 0.06f;
+ pos.x = 0.115f;
+ pos.y = 0.76f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPd);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+ pb->SetState(STATE_CHECK, (m_phase == PHASE_SETUPd || m_phase == PHASE_SETUPds));
+
+ pos.x += ddim.x+0.01f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPg);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+ pb->SetState(STATE_CHECK, (m_phase == PHASE_SETUPg || m_phase == PHASE_SETUPgs));
+
+ pos.x += ddim.x+0.01f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPp);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+ pb->SetState(STATE_CHECK, (m_phase == PHASE_SETUPp || m_phase == PHASE_SETUPps));
+
+ pos.x += ddim.x+0.01f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPc);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+ pb->SetState(STATE_CHECK, (m_phase == PHASE_SETUPc || m_phase == PHASE_SETUPcs));
+
+ pos.x += ddim.x+0.01f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SETUPs);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_CARD);
+ pb->SetState(STATE_CHECK, (m_phase == PHASE_SETUPs || m_phase == PHASE_SETUPss));
+
+ pos.x = 0.10f;
+ ddim.x = 0.80f;
+ pos.y = 0.34f;
+ ddim.y = 0.42f;
+ pw->CreateGroup(pos, ddim, 2, EVENT_INTERFACE_GLINTu); // orange -> transparent
+ pos.x = 0.10f+(6.0f/640.0f);
+ ddim.x = 0.80f-(11.0f/640.0f);
+ pos.y = 0.74f;
+ ddim.y = 0.02f;
+ pw->CreateGroup(pos, ddim, 1, EVENT_INTERFACE_GLINTb); // barre orange
+
+ ddim.x = dim.x*4;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*2;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK);
+ pb->SetState(STATE_SHADOW);
+
+ if ( !m_bSimulSetup )
+ {
+ m_engine->SetBackground("inter01.tga", 0,0, 0,0, TRUE, TRUE);
+ m_engine->SetBackForce(TRUE);
+ }
+ }
+
+ if ( m_phase == PHASE_SETUPd || // setup/display ?
+ m_phase == PHASE_SETUPds )
+ {
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*9;
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*1;
+ GetResource(RES_TEXT, RT_SETUP_DEVICE, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name);
+ pl->SetJustif(1);
+
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*5.2f;
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*4.5f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_LIST1);
+ pli->SetState(STATE_SHADOW);
+ UpdateDisplayDevice();
+
+ pos.x = ox+sx*10;
+ pos.y = oy+sy*9;
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*1;
+ GetResource(RES_TEXT, RT_SETUP_MODE, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, name);
+ pl->SetJustif(1);
+
+ m_setupFull = m_engine->RetFullScreen();
+ pos.x = ox+sx*10;
+ pos.y = oy+sy*5.2f;
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*4.5f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_LIST2);
+ pli->SetState(STATE_SHADOW);
+ UpdateDisplayMode();
+ pli->SetState(STATE_ENABLE, m_setupFull);
+
+ ddim.x = dim.x*4;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*4.1f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_FULL);
+ pc->SetState(STATE_SHADOW);
+ pc->SetState(STATE_CHECK, m_setupFull);
+
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*10;
+ pos.y = oy+sy*2;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_APPLY);
+ pb->SetState(STATE_SHADOW);
+ UpdateApply();
+ }
+
+ if ( m_phase == PHASE_SETUPg || // setup/graphic ?
+ m_phase == PHASE_SETUPgs )
+ {
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*3;
+ pos.y = 0.65f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SHADOW);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ if ( !m_bSimulSetup )
+ {
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_GROUND);
+ pc->SetState(STATE_SHADOW);
+ if ( m_engine->IsVideo8MB() ) pc->ClearState(STATE_ENABLE);
+ }
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_DIRTY);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SKY);
+ pc->SetState(STATE_SHADOW);
+ if ( m_engine->IsVideo8MB() ) pc->ClearState(STATE_ENABLE);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_LENS);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_PLANET);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_FOG);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ if ( !m_bSimulSetup )
+ {
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_LIGHT);
+ pc->SetState(STATE_SHADOW);
+ }
+
+ pos.x = ox+sx*8.5f;
+ pos.y = 0.65f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = 18.0f/480.0f;
+ pv = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_PARTI);
+ pv->SetState(STATE_SHADOW);
+ pv->SetMinValue(0.0f);
+ pv->SetMaxValue(2.0f);
+ pos.x += 0.13f;
+ pos.y -= 0.015f;
+ ddim.x = 0.40f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_PARTI, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL10, name);
+ pl->SetJustif(1);
+
+ pos.x = ox+sx*8.5f;
+ pos.y = 0.59f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = 18.0f/480.0f;
+ pv = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_CLIP);
+ pv->SetState(STATE_SHADOW);
+ pv->SetMinValue(0.5f);
+ pv->SetMaxValue(2.0f);
+ pos.x += 0.13f;
+ pos.y -= 0.015f;
+ ddim.x = 0.40f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_CLIP, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL11, name);
+ pl->SetJustif(1);
+
+ pos.x = ox+sx*8.5f;
+ pos.y = 0.53f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = 18.0f/480.0f;
+ pv = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_DETAIL);
+ pv->SetState(STATE_SHADOW);
+ pv->SetMinValue(0.0f);
+ pv->SetMaxValue(2.0f);
+ pos.x += 0.13f;
+ pos.y -= 0.015f;
+ ddim.x = 0.40f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_DETAIL, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL12, name);
+ pl->SetJustif(1);
+
+ if ( !m_bSimulSetup )
+ {
+ pos.x = ox+sx*8.5f;
+ pos.y = 0.47f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = 18.0f/480.0f;
+ pv = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_GADGET);
+ pv->SetState(STATE_SHADOW);
+ pv->SetMinValue(0.0f);
+ pv->SetMaxValue(1.0f);
+ pos.x += 0.13f;
+ pos.y -= 0.015f;
+ ddim.x = 0.40f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_GADGET, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL13, name);
+ pl->SetJustif(1);
+ }
+
+#if 0
+ if ( !m_bSimulSetup )
+ {
+ pos.x = ox+sx*8.5f;
+ pos.y = 0.41f;
+ ddim.x = dim.x*2.2f;
+ ddim.y = 18.0f/480.0f;
+ pv = pw->CreateEditValue(pos, ddim, 0, EVENT_INTERFACE_TEXTURE);
+ pv->SetState(STATE_SHADOW);
+ pv->SetType(EVT_INT);
+ pv->SetMinValue(0.0f);
+ pv->SetMaxValue(2.0f);
+ pv->SetStepValue(1.0f);
+ pos.x += 0.13f;
+ pos.y -= 0.015f;
+ ddim.x = 0.40f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_TEXTURE, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL14, name);
+ pl->SetJustif(1);
+ }
+#endif
+
+ ddim.x = dim.x*2;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*10;
+ pos.y = oy+sy*2;
+#if _POLISH
+ ddim.x += 20.0f/640.0f;
+ pos.x -= 20.0f/640.0f*3.0f;
+#endif
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MIN);
+ pb->SetState(STATE_SHADOW);
+ pos.x += ddim.x;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NORM);
+ pb->SetState(STATE_SHADOW);
+ pos.x += ddim.x;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_MAX);
+ pb->SetState(STATE_SHADOW);
+
+ UpdateSetupButtons();
+ }
+
+ if ( m_phase == PHASE_SETUPp || // setup/jeu ?
+ m_phase == PHASE_SETUPps )
+ {
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*3;
+ pos.y = 0.65f;
+//? pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_TOTO);
+//? pc->SetState(STATE_SHADOW);
+//? pos.y -= 0.048f;
+#if _SCHOOL
+ #if _EDU
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SOLUCE4);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ #endif
+#else
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_MOVIES);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+#endif
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SCROLL);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_INVERTX);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_INVERTY);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_EFFECT);
+ pc->SetState(STATE_SHADOW);
+//? pos.y -= 0.048f;
+//? pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_NICERST);
+//? pc->SetState(STATE_SHADOW);
+//? pos.y -= 0.048f;
+//? pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_HIMSELF);
+//? pc->SetState(STATE_SHADOW);
+
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*10;
+ pos.y = 0.65f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_TOOLTIP);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_GLINT);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_RAIN);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_MOUSE);
+ pc->SetState(STATE_SHADOW);
+ pos.y -= 0.048f;
+ pos.y -= 0.048f;
+ if ( !m_bSimulSetup )
+ {
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_EDITMODE);
+ pc->SetState(STATE_SHADOW);
+ }
+ pos.y -= 0.048f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_EDITVALUE);
+ pc->SetState(STATE_SHADOW);
+
+ UpdateSetupButtons();
+ }
+
+ if ( m_phase == PHASE_SETUPc || // setup/commandes ?
+ m_phase == PHASE_SETUPcs )
+ {
+ pos.x = ox+sx*3;
+ pos.y = 320.0f/480.0f;
+ ddim.x = dim.x*15.0f;
+ ddim.y = 18.0f/480.0f;
+ GetResource(RES_TEXT, RT_SETUP_KEY1, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_INTERFACE_KINFO1, name);
+ pl->SetJustif(1);
+
+ pos.x = ox+sx*3;
+ pos.y = 302.0f/480.0f;
+ ddim.x = dim.x*15.0f;
+ ddim.y = 18.0f/480.0f;
+ GetResource(RES_TEXT, RT_SETUP_KEY2, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_INTERFACE_KINFO2, name);
+ pl->SetJustif(1);
+
+ ddim.x = 428.0f/640.0f;
+ ddim.y = 128.0f/480.0f;
+ pos.x = 105.0f/640.0f;
+ pos.y = 164.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 0, EVENT_INTERFACE_KGROUP);
+ pg->ClearState(STATE_ENABLE);
+ pg->SetState(STATE_DEAD);
+ pg->SetState(STATE_SHADOW);
+
+ ddim.x = 18.0f/640.0f;
+ ddim.y = (20.0f/480.0f)*KEY_VISIBLE;
+ pos.x = 510.0f/640.0f;
+ pos.y = 168.0f/480.0f;
+ ps = pw->CreateScroll(pos, ddim, -1, EVENT_INTERFACE_KSCROLL);
+ ps->SetVisibleRatio((float)KEY_VISIBLE/KEY_TOTAL);
+ ps->SetArrowStep(1.0f/((float)KEY_TOTAL-KEY_VISIBLE));
+ UpdateKey();
+
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*3;
+ pos.y = 130.0f/480.0f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_JOYSTICK);
+ pc->SetState(STATE_SHADOW);
+
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*10;
+ pos.y = oy+sy*2;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_KDEF);
+ pb->SetState(STATE_SHADOW);
+
+ UpdateSetupButtons();
+ }
+
+ if ( m_phase == PHASE_SETUPs || // setup/sound ?
+ m_phase == PHASE_SETUPss )
+ {
+ pos.x = ox+sx*3;
+ pos.y = 0.55f;
+ ddim.x = dim.x*4.0f;
+ ddim.y = 18.0f/480.0f;
+ psl = pw->CreateSlider(pos, ddim, 0, EVENT_INTERFACE_VOLSOUND);
+ psl->SetState(STATE_SHADOW);
+ psl->SetLimit(0.0f, MAXVOLUME);
+ psl->SetArrowStep(1.0f);
+ pos.y += ddim.y;
+ GetResource(RES_EVENT, EVENT_INTERFACE_VOLSOUND, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name);
+ pl->SetJustif(1);
+
+#if (_FULL | _NET) & _SOUNDTRACKS
+ pos.x = ox+sx*3;
+ pos.y = 0.40f;
+ ddim.x = dim.x*4.0f;
+ ddim.y = 18.0f/480.0f;
+ psl = pw->CreateSlider(pos, ddim, 0, EVENT_INTERFACE_VOLMUSIC);
+ psl->SetState(STATE_SHADOW);
+ psl->SetLimit(0.0f, MAXVOLUME);
+ psl->SetArrowStep(1.0f);
+ pos.y += ddim.y;
+ GetResource(RES_EVENT, EVENT_INTERFACE_VOLMUSIC, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, name);
+ pl->SetJustif(1);
+#endif
+
+ ddim.x = dim.x*6;
+ ddim.y = dim.y*0.5f;
+ pos.x = ox+sx*10;
+ pos.y = 0.55f;
+ pc = pw->CreateCheck(pos, ddim, -1, EVENT_INTERFACE_SOUND3D);
+ pc->SetState(STATE_SHADOW);
+
+ ddim.x = dim.x*3;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*10;
+ pos.y = oy+sy*2;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_SILENT);
+ pb->SetState(STATE_SHADOW);
+ pos.x += ddim.x;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_NOISY);
+ pb->SetState(STATE_SHADOW);
+
+ UpdateSetupButtons();
+ }
+
+ if ( m_phase == PHASE_WRITE ||
+ m_phase == PHASE_WRITEs )
+ {
+ pos.x = 0.10f;
+ pos.y = 0.10f;
+ ddim.x = 0.80f;
+ ddim.y = 0.80f;
+ pw = m_interface->CreateWindows(pos, ddim, 13, EVENT_WINDOW5);
+ pw->SetClosable(TRUE);
+ GetResource(RES_TEXT, RT_TITLE_WRITE, name);
+ pw->SetName(name);
+
+ pos.x = 0.10f;
+ pos.y = 0.40f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.40f;
+ pos.y = 0.10f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+#if _NEWLOOK
+ pos.x = 100.0f/640.0f;
+ pos.y = 66.0f/480.0f;
+ ddim.x = 438.0f/640.0f;
+ ddim.y = 42.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // violet
+ pg->SetState(STATE_SHADOW);
+#endif
+
+ pos.x = 290.0f/640.0f;
+ ddim.x = 245.0f/640.0f;
+
+ pos.y = 146.0f/480.0f;
+ ddim.y = 18.0f/480.0f;
+ GetResource(RES_EVENT, EVENT_INTERFACE_IOLABEL, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_INTERFACE_IOLABEL, name);
+ pl->SetJustif(1);
+
+ pos.y = 130.0f/480.0f;
+ ddim.y = 18.0f/480.0f;
+ pe = pw->CreateEdit(pos, ddim, 0, EVENT_INTERFACE_IONAME);
+ pe->SetState(STATE_SHADOW);
+ pe->SetFontType(FONT_COLOBOT);
+ pe->SetMaxChar(35);
+ IOReadName();
+
+ pos.y = 190.0f/480.0f;
+ ddim.y = 190.0f/480.0f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_IOLIST);
+ pli->SetState(STATE_SHADOW);
+
+ pos.y = oy+sy*2;
+ ddim.y = dim.y*1;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_IOWRITE);
+ pb->SetState(STATE_SHADOW);
+
+ pos.x = 105.0f/640.0f;
+ pos.y = 190.0f/480.0f;
+ ddim.x = 170.0f/640.0f;
+ ddim.y = dim.y*1;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_IODELETE);
+ pb->SetState(STATE_SHADOW);
+
+ pos.x = 105.0f/640.0f;
+ pos.y = 250.0f/480.0f;
+ ddim.x = 170.0f/640.0f;
+ ddim.y = 128.0f/480.0f;
+ pi = pw->CreateImage(pos, ddim, 0, EVENT_INTERFACE_IOIMAGE);
+ pi->SetState(STATE_SHADOW);
+
+ ddim.x = dim.x*4;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*2;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK);
+ pb->SetState(STATE_SHADOW);
+
+ IOReadList();
+ IOUpdateList();
+ }
+
+ if ( m_phase == PHASE_READ ||
+ m_phase == PHASE_READs )
+ {
+ pos.x = 0.10f;
+ pos.y = 0.10f;
+ ddim.x = 0.80f;
+ ddim.y = 0.80f;
+ pw = m_interface->CreateWindows(pos, ddim, 14, EVENT_WINDOW5);
+ pw->SetClosable(TRUE);
+ GetResource(RES_TEXT, RT_TITLE_READ, name);
+ pw->SetName(name);
+
+ pos.x = 0.10f;
+ pos.y = 0.40f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.40f;
+ pos.y = 0.10f;
+ ddim.x = 0.50f;
+ ddim.y = 0.50f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+#if _NEWLOOK
+ pos.x = 100.0f/640.0f;
+ pos.y = 66.0f/480.0f;
+ ddim.x = 438.0f/640.0f;
+ ddim.y = 42.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 26, EVENT_LABEL1); // violet
+ pg->SetState(STATE_SHADOW);
+#endif
+
+ pos.x = 290.0f/640.0f;
+ ddim.x = 245.0f/640.0f;
+
+ pos.y = 160.0f/480.0f;
+ ddim.y = 190.0f/480.0f;
+ pli = pw->CreateList(pos, ddim, 0, EVENT_INTERFACE_IOLIST);
+ pli->SetState(STATE_SHADOW);
+
+ pos.y = oy+sy*2;
+ ddim.y = dim.y*1;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_IOREAD);
+ pb->SetState(STATE_SHADOW);
+ if ( m_phase == PHASE_READs )
+ {
+ pb->SetState(STATE_WARNING);
+ }
+
+ pos.x = 105.0f/640.0f;
+ pos.y = 160.0f/480.0f;
+ ddim.x = 170.0f/640.0f;
+ ddim.y = dim.y*1;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_IODELETE);
+ pb->SetState(STATE_SHADOW);
+
+ pos.x = 105.0f/640.0f;
+ pos.y = 220.0f/480.0f;
+ ddim.x = 170.0f/640.0f;
+ ddim.y = 128.0f/480.0f;
+ pi = pw->CreateImage(pos, ddim, 0, EVENT_INTERFACE_IOIMAGE);
+ pi->SetState(STATE_SHADOW);
+
+ ddim.x = dim.x*4;
+ ddim.y = dim.y*1;
+ pos.x = ox+sx*3;
+ pos.y = oy+sy*2;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_INTERFACE_BACK);
+ pb->SetState(STATE_SHADOW);
+
+ IOReadList();
+ IOUpdateList();
+
+ if ( m_phase == PHASE_READ )
+ {
+ m_engine->SetBackground("inter01.tga", 0,0, 0,0, TRUE, TRUE);
+ m_engine->SetBackForce(TRUE);
+ }
+ }
+
+ if ( m_phase == PHASE_LOADING )
+ {
+ pos.x = 0.35f;
+ pos.y = 0.10f;
+ ddim.x = 0.30f;
+ ddim.y = 0.80f;
+#if _TEEN
+ pw = m_interface->CreateWindows(pos, ddim, 12, EVENT_WINDOW5);
+#else
+ pw = m_interface->CreateWindows(pos, ddim, 10, EVENT_WINDOW5);
+#endif
+ pw->SetName(" ");
+
+ pos.x = 0.35f;
+ pos.y = 0.60f;
+ ddim.x = 0.30f;
+ ddim.y = 0.30f;
+ pw->CreateGroup(pos, ddim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.35f;
+ pos.y = 0.10f;
+ ddim.x = 0.30f;
+ ddim.y = 0.30f;
+ pw->CreateGroup(pos, ddim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+ pos.x = 254.0f/640.0f;
+ pos.y = 208.0f/480.0f;
+ ddim.x = 132.0f/640.0f;
+ ddim.y = 42.0f/480.0f;
+ pg = pw->CreateGroup(pos, ddim, 22, EVENT_NULL);
+ pg->SetState(STATE_SHADOW);
+
+ pos.x = 220.0f/640.0f;
+ pos.y = 210.0f/480.0f;
+ ddim.x = 200.0f/640.0f;
+ ddim.y = 20.0f/480.0f;
+ GetResource(RES_TEXT, RT_DIALOG_LOADING, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name);
+ pl->SetFontSize(12.0f);
+ pl->SetJustif(0);
+
+ m_engine->SetBackground("inter01.tga", 0,0, 0,0, TRUE, TRUE);
+ m_engine->SetBackForce(TRUE);
+
+ m_loadingCounter = 1; // laisse le temps de s'afficher !
+ }
+
+ if ( m_phase == PHASE_WELCOME1 )
+ {
+ m_sound->StopMusic();
+ m_sound->PlayMusic(11, FALSE);
+
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ ddim.x = 0.0f;
+ ddim.y = 0.0f;
+ pw = m_interface->CreateWindows(pos, ddim, -1, EVENT_WINDOW5);
+
+ m_engine->SetOverColor(RetColor(1.0f), D3DSTATETCb);
+ m_engine->SetOverFront(TRUE);
+
+#if _FRENCH
+ m_engine->SetBackground("alsyd.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+#if _POLISH
+ m_engine->SetBackground("manta.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+#if _WG
+ m_engine->SetBackground("wg.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+ m_engine->SetBackForce(TRUE);
+ }
+ if ( m_phase == PHASE_WELCOME2 )
+ {
+#if _ENGLISH
+ m_sound->StopMusic();
+ m_sound->PlayMusic(11, FALSE);
+#endif
+#if _POLISH
+ m_sound->StopMusic();
+ m_sound->PlayMusic(11, FALSE);
+#endif
+
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ ddim.x = 0.0f;
+ ddim.y = 0.0f;
+ pw = m_interface->CreateWindows(pos, ddim, -1, EVENT_WINDOW5);
+
+ m_engine->SetOverColor(RetColor(1.0f), D3DSTATETCb);
+ m_engine->SetOverFront(TRUE);
+
+ m_engine->SetBackground("colobot.tga", 0,0, 0,0, TRUE, FALSE);
+ m_engine->SetBackForce(TRUE);
+ }
+ if ( m_phase == PHASE_WELCOME3 )
+ {
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ ddim.x = 0.0f;
+ ddim.y = 0.0f;
+ pw = m_interface->CreateWindows(pos, ddim, -1, EVENT_WINDOW5);
+
+ m_engine->SetOverColor(RetColor(0.0f), D3DSTATETCw);
+ m_engine->SetOverFront(TRUE);
+
+#if _FRENCH
+ m_engine->SetBackground("epsitecf.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+#if _ENGLISH
+ m_engine->SetBackground("epsitece.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+#if _GERMAN | _WG
+ m_engine->SetBackground("epsitecd.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+#if _POLISH
+ m_engine->SetBackground("epsitecp.tga", 0,0, 0,0, TRUE, FALSE);
+#endif
+ m_engine->SetBackForce(TRUE);
+ }
+
+ if ( m_phase == PHASE_GENERIC )
+ {
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ ddim.x = 0.0f;
+ ddim.y = 0.0f;
+ pw = m_interface->CreateWindows(pos, ddim, -1, EVENT_WINDOW5);
+
+#if _FULL | _NET
+ pos.x = 80.0f/640.0f;
+ pos.y = 240.0f/480.0f;
+ ddim.x = 490.0f/640.0f;
+ ddim.y = 110.0f/480.0f;
+ pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT1);
+ pe->SetGenericMode(TRUE);
+ pe->SetEditCap(FALSE);
+ pe->SetHiliteCap(FALSE);
+ pe->SetFontType(FONT_COURIER);
+ pe->SetFontSize(8.0f);
+ pe->ReadText("help\\authors.txt");
+
+ pos.x = 80.0f/640.0f;
+ pos.y = 140.0f/480.0f;
+ ddim.x = 490.0f/640.0f;
+ ddim.y = 100.0f/480.0f;
+ pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT2);
+ pe->SetGenericMode(TRUE);
+ pe->SetEditCap(FALSE);
+ pe->SetHiliteCap(FALSE);
+ pe->SetFontType(FONT_COURIER);
+ pe->SetFontSize(6.5f);
+ pe->ReadText("help\\licences.txt");
+#endif
+#if _SCHOOL
+#if _CEEBOTDEMO
+ pos.x = 80.0f/640.0f;
+ pos.y = 210.0f/480.0f;
+ ddim.x = 490.0f/640.0f;
+ ddim.y = 150.0f/480.0f;
+#else
+ pos.x = 80.0f/640.0f;
+ pos.y = 200.0f/480.0f;
+ ddim.x = 490.0f/640.0f;
+ ddim.y = 150.0f/480.0f;
+#endif
+ pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT1);
+ pe->SetGenericMode(TRUE);
+ pe->SetEditCap(FALSE);
+ pe->SetHiliteCap(FALSE);
+ pe->SetFontType(FONT_COURIER);
+ pe->SetFontSize(8.0f);
+ pe->ReadText("help\\authors.txt");
+#endif
+#if _DEMO
+//? pos.x = 80.0f/640.0f;
+//? pos.y = 240.0f/480.0f;
+//? ddim.x = 490.0f/640.0f;
+//? ddim.y = 110.0f/480.0f;
+//? pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT1);
+//? pe->SetGenericMode(TRUE);
+//? pe->SetEditCap(FALSE);
+//? pe->SetHiliteCap(FALSE);
+//? pe->SetFontType(FONT_COURIER);
+//? pe->SetFontSize(8.0f);
+//? pe->ReadText("help\\demo.txt");
+
+//? pos.x = 80.0f/640.0f;
+//? pos.y = 140.0f/480.0f;
+//? ddim.x = 490.0f/640.0f;
+//? ddim.y = 100.0f/480.0f;
+//? pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT2);
+//? pe->SetGenericMode(TRUE);
+//? pe->SetEditCap(FALSE);
+//? pe->SetHiliteCap(FALSE);
+//? pe->SetFontType(FONT_COURIER);
+//? pe->SetFontSize(8.0f);
+//? pe->ReadText("help\\authors.txt");
+#endif
+
+#if !_DEMO
+ pos.x = 40.0f/640.0f;
+ pos.y = 83.0f/480.0f;
+ ddim.x = 246.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ GetResource(RES_TEXT, RT_GENERIC_DEV1, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name);
+ pl->SetFontType(FONT_COURIER);
+ pl->SetFontSize(8.0f);
+
+ pos.y = 13.0f/480.0f;
+ GetResource(RES_TEXT, RT_GENERIC_DEV2, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, name);
+ pl->SetFontType(FONT_COURIER);
+ pl->SetFontSize(8.0f);
+
+ pos.x = 355.0f/640.0f;
+ pos.y = 83.0f/480.0f;
+ ddim.x = 246.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ GetResource(RES_TEXT, RT_GENERIC_EDIT1, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL3, name);
+ pl->SetFontType(FONT_COURIER);
+ pl->SetFontSize(8.0f);
+
+ pos.y = 13.0f/480.0f;
+ GetResource(RES_TEXT, RT_GENERIC_EDIT2, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL4, name);
+ pl->SetFontType(FONT_COURIER);
+ pl->SetFontSize(8.0f);
+#endif
+
+#if _DEMO
+ pos.x = 481.0f/640.0f;
+ pos.y = 51.0f/480.0f;
+ ddim.x = 30.0f/640.0f;
+ ddim.y = 30.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, 49, EVENT_INTERFACE_ABORT);
+ pb->SetState(STATE_SHADOW);
+#else
+ pos.x = 306.0f/640.0f;
+ pos.y = 17.0f/480.0f;
+ ddim.x = 30.0f/640.0f;
+ ddim.y = 30.0f/480.0f;
+ pb = pw->CreateButton(pos, ddim, 49, EVENT_INTERFACE_ABORT);
+ pb->SetState(STATE_SHADOW);
+#endif
+
+#if _NEWLOOK
+#if _CEEBOTDEMO
+#if _TEEN
+ m_engine->SetBackground("genedt.tga", 0,0, 0,0, TRUE, TRUE);
+#else
+ m_engine->SetBackground("geneda.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#else
+ m_engine->SetBackground("genern.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#else
+#if _FRENCH
+#if _DEMO
+ m_engine->SetBackground("genedf.tga", 0,0, 0,0, TRUE, TRUE);
+#else
+ m_engine->SetBackground("generf.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#endif
+#if _ENGLISH
+#if _DEMO
+ m_engine->SetBackground("genede.tga", 0,0, 0,0, TRUE, TRUE);
+#else
+ m_engine->SetBackground("genere.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#endif
+#if _GERMAN
+#if _DEMO
+ m_engine->SetBackground("genedd.tga", 0,0, 0,0, TRUE, TRUE);
+#else
+ m_engine->SetBackground("genere.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#endif
+#if _WG
+#if _DEMO
+ m_engine->SetBackground("genedd.tga", 0,0, 0,0, TRUE, TRUE);
+#else
+ m_engine->SetBackground("generd.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#endif
+#if _POLISH
+#if _DEMO
+ m_engine->SetBackground("genedp.tga", 0,0, 0,0, TRUE, TRUE);
+#else
+ m_engine->SetBackground("generp.tga", 0,0, 0,0, TRUE, TRUE);
+#endif
+#endif
+#endif
+ m_engine->SetBackForce(TRUE);
+ }
+
+ if ( m_phase == PHASE_INIT ||
+ m_phase == PHASE_NAME ||
+ m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO ||
+ m_phase == PHASE_SETUPd ||
+ m_phase == PHASE_SETUPg ||
+ m_phase == PHASE_SETUPp ||
+ m_phase == PHASE_SETUPc ||
+ m_phase == PHASE_SETUPs ||
+ m_phase == PHASE_READ ||
+ m_phase == PHASE_LOADING )
+ {
+#if _SCHOOL
+#if _TEEN
+ pos.x = 50.0f/640.0f;
+ pos.y = 430.0f/480.0f;
+ ddim.x = 200.0f/640.0f;
+ ddim.y = 10.0f/480.0f;
+#else
+ pos.x = 450.0f/640.0f;
+ pos.y = 0.0f/480.0f;
+ ddim.x = 170.0f/640.0f;
+ ddim.y = 9.0f/480.0f;
+#endif
+#else
+ pos.x = 540.0f/640.0f;
+ pos.y = 9.0f/480.0f;
+ ddim.x = 90.0f/640.0f;
+ ddim.y = 10.0f/480.0f;
+#endif
+ GetResource(RES_TEXT, RT_VERSION_ID, name);
+ pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL1, name);
+ pl->SetFontType(FONT_COURIER);
+ pl->SetFontSize(9.0f);
+ }
+
+ m_engine->LoadAllTexture();
+}
+
+
+// Traite un événement.
+// Retourne FALSE si l'événement a été traîté complètement.
+
+BOOL CMainDialog::EventProcess(const Event &event)
+{
+ CWindow* pw;
+ CList* pl;
+ CButton* pb;
+ CCheck* pc;
+ Event newEvent;
+ float welcomeLength;
+
+ if ( event.event == EVENT_FRAME )
+ {
+ m_phaseTime += event.rTime;
+
+//? if ( m_phase == PHASE_WELCOME1 ) welcomeLength = WELCOME_LENGTH+2.0f;
+//? else welcomeLength = WELCOME_LENGTH;
+ welcomeLength = WELCOME_LENGTH;
+
+ if ( m_phase == PHASE_WELCOME1 ||
+ m_phase == PHASE_WELCOME2 ||
+ m_phase == PHASE_WELCOME3 )
+ {
+ float intensity;
+ int mode = D3DSTATETCb;
+
+ if ( m_phaseTime < 1.5f )
+ {
+ intensity = 1.0f-(m_phaseTime-0.5f);
+ }
+ else if ( m_phaseTime < welcomeLength-1.0f )
+ {
+ intensity = 0.0f;
+ }
+ else
+ {
+ intensity = m_phaseTime-(welcomeLength-1.0f);
+ }
+ if ( intensity < 0.0f ) intensity = 0.0f;
+ if ( intensity > 1.0f ) intensity = 1.0f;
+
+ if ( (m_phase == PHASE_WELCOME2 && m_phaseTime > welcomeLength/2.0f) ||
+ m_phase == PHASE_WELCOME3 )
+ {
+ intensity = 1.0f-intensity;
+ mode = D3DSTATETCw;
+ }
+
+ m_engine->SetOverColor(RetColor(intensity), mode);
+ }
+
+ if ( m_phase == PHASE_WELCOME1 && m_phaseTime >= welcomeLength )
+ {
+ ChangePhase(PHASE_WELCOME2);
+ return TRUE;
+ }
+ if ( m_phase == PHASE_WELCOME2 && m_phaseTime >= welcomeLength )
+ {
+ ChangePhase(PHASE_WELCOME3);
+ return TRUE;
+ }
+ if ( m_phase == PHASE_WELCOME3 && m_phaseTime >= welcomeLength )
+ {
+ ChangePhase(PHASE_NAME);
+ return TRUE;
+ }
+
+ if ( m_shotDelay > 0 && !m_bDialog ) // copie d'écran à faire ?
+ {
+ m_shotDelay --;
+ if ( m_shotDelay == 0 )
+ {
+ m_engine->WriteScreenShot(m_shotName, 320, 240);
+//? m_engine->WriteScreenShot(m_shotName, 160, 120);
+ }
+ }
+
+ if ( m_phase == PHASE_LOADING )
+ {
+ if ( m_loadingCounter == 0 )
+ {
+ m_main->ChangePhase(PHASE_SIMUL);
+ }
+ m_loadingCounter --;
+ return FALSE;
+ }
+
+ m_glintTime += event.rTime;
+ GlintMove(); // bouge les reflets
+
+ FrameParticule(event.rTime);
+
+ if ( m_bDialog ) // dialogue présent ?
+ {
+ FrameDialog(event.rTime);
+ }
+
+ return TRUE;
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ m_glintMouse = event.pos;
+ NiceParticule(event.pos, event.keyState&KS_MLEFT);
+ }
+
+ if ( m_bDialog ) // dialogue présent ?
+ {
+ m_interface->EventProcess(event);
+
+ if ( event.event == EVENT_DIALOG_OK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_RETURN ) )
+ {
+ StopDialog();
+ if ( m_phase == PHASE_NAME )
+ {
+ NameDelete();
+ }
+ if ( m_phase == PHASE_INIT )
+ {
+//? m_event->MakeEvent(newEvent, EVENT_QUIT);
+//? m_event->AddEvent(newEvent);
+ m_main->ChangePhase(PHASE_GENERIC);
+ }
+ if ( m_phase == PHASE_SIMUL )
+ {
+ if ( m_bDialogDelete )
+ {
+ m_main->DeleteObject();
+ }
+ else
+ {
+ m_main->ChangePhase(PHASE_TERM);
+ }
+ }
+ }
+ if ( event.event == EVENT_DIALOG_CANCEL ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE ) )
+ {
+ StopDialog();
+ }
+ if ( event.event == EVENT_INTERFACE_SETUP )
+ {
+ StopDialog();
+ StartSuspend();
+ if ( m_phaseSetup == PHASE_SETUPd ) ChangePhase(PHASE_SETUPds);
+ if ( m_phaseSetup == PHASE_SETUPg ) ChangePhase(PHASE_SETUPgs);
+ if ( m_phaseSetup == PHASE_SETUPp ) ChangePhase(PHASE_SETUPps);
+ if ( m_phaseSetup == PHASE_SETUPc ) ChangePhase(PHASE_SETUPcs);
+ if ( m_phaseSetup == PHASE_SETUPs ) ChangePhase(PHASE_SETUPss);
+ }
+ if ( event.event == EVENT_INTERFACE_AGAIN )
+ {
+ StopDialog();
+ m_main->ChangePhase(PHASE_LOADING);
+ }
+ if ( event.event == EVENT_INTERFACE_WRITE )
+ {
+ StopDialog();
+ StartSuspend();
+ ChangePhase(PHASE_WRITEs);
+ }
+ if ( event.event == EVENT_INTERFACE_READ )
+ {
+ StopDialog();
+ StartSuspend();
+ ChangePhase(PHASE_READs);
+ }
+
+ return FALSE;
+ }
+
+ if ( !m_engine->RetMouseHide() &&
+ !m_interface->EventProcess(event) )
+ {
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_INIT )
+ {
+ switch( event.event )
+ {
+ case EVENT_KEYDOWN:
+ if ( event.param == VK_ESCAPE )
+ {
+//? StartQuit(); // voulez-vous quitter ?
+ m_sound->Play(SOUND_TZOING);
+ m_main->ChangePhase(PHASE_GENERIC);
+ }
+ break;
+
+ case EVENT_INTERFACE_QUIT:
+//? StartQuit(); // voulez-vous quitter ?
+ m_sound->Play(SOUND_TZOING);
+ m_main->ChangePhase(PHASE_GENERIC);
+ break;
+
+ case EVENT_INTERFACE_TRAINER:
+ m_main->ChangePhase(PHASE_TRAINER);
+ break;
+
+ case EVENT_INTERFACE_DEFI:
+ m_main->ChangePhase(PHASE_DEFI);
+ break;
+
+ case EVENT_INTERFACE_MISSION:
+ m_main->ChangePhase(PHASE_MISSION);
+ break;
+
+ case EVENT_INTERFACE_FREE:
+ m_main->ChangePhase(PHASE_FREE);
+ break;
+
+ case EVENT_INTERFACE_TEEN:
+ m_main->ChangePhase(PHASE_TEEN);
+ break;
+
+ case EVENT_INTERFACE_USER:
+ m_main->ChangePhase(PHASE_USER);
+ break;
+
+ case EVENT_INTERFACE_PROTO:
+ m_main->ChangePhase(PHASE_PROTO);
+ break;
+
+ case EVENT_INTERFACE_SETUP:
+ m_main->ChangePhase(m_phaseSetup);
+ break;
+
+ case EVENT_INTERFACE_NAME:
+ m_main->ChangePhase(PHASE_NAME);
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_NAME )
+ {
+ switch( event.event )
+ {
+ case EVENT_KEYDOWN:
+ if ( event.param == VK_RETURN )
+ {
+ NameSelect();
+ }
+ if ( event.param == VK_ESCAPE )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) break;
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_NCANCEL);
+ if ( pb == 0 ) break;
+ if ( pb->TestState(STATE_ENABLE) )
+ {
+ m_main->ChangePhase(PHASE_INIT);
+ }
+ }
+ break;
+
+ case EVENT_INTERFACE_NEDIT:
+ UpdateNameList();
+ UpdateNameControl();
+ break;
+
+ case EVENT_INTERFACE_NLIST:
+ UpdateNameEdit();
+ break;
+
+ case EVENT_INTERFACE_NOK:
+ NameSelect();
+ break;
+
+ case EVENT_INTERFACE_PERSO:
+ NameSelect();
+ m_main->ChangePhase(PHASE_PERSO);
+ break;
+
+ case EVENT_INTERFACE_NCANCEL:
+ m_main->ChangePhase(PHASE_INIT);
+ break;
+
+ case EVENT_INTERFACE_NDELETE:
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) break;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) break;
+ StartDeleteGame(pl->RetName(pl->RetSelect()));
+ break;
+ }
+ }
+
+ if ( m_phase == PHASE_PERSO )
+ {
+ switch( event.event )
+ {
+ case EVENT_KEYDOWN:
+ if ( event.param == VK_RETURN )
+ {
+ m_main->ChangePhase(PHASE_INIT);
+ }
+ if ( event.param == VK_ESCAPE )
+ {
+ m_main->ChangePhase(PHASE_NAME);
+ }
+ break;
+
+ case EVENT_INTERFACE_PHEAD:
+ m_persoTab = 0;
+ UpdatePerso();
+ m_main->ScenePerso();
+ CameraPerso();
+ break;
+ case EVENT_INTERFACE_PBODY:
+ m_persoTab = 1;
+ UpdatePerso();
+ m_main->ScenePerso();
+ CameraPerso();
+ break;
+
+ case EVENT_INTERFACE_PFACE1:
+ case EVENT_INTERFACE_PFACE2:
+ case EVENT_INTERFACE_PFACE3:
+ case EVENT_INTERFACE_PFACE4:
+ m_perso.face = event.event-EVENT_INTERFACE_PFACE1;
+ WriteGamerPerso(m_main->RetGamerName());
+ UpdatePerso();
+ m_main->ScenePerso();
+ break;
+
+ case EVENT_INTERFACE_PGLASS0:
+ case EVENT_INTERFACE_PGLASS1:
+ case EVENT_INTERFACE_PGLASS2:
+ case EVENT_INTERFACE_PGLASS3:
+ case EVENT_INTERFACE_PGLASS4:
+ case EVENT_INTERFACE_PGLASS5:
+ case EVENT_INTERFACE_PGLASS6:
+ case EVENT_INTERFACE_PGLASS7:
+ case EVENT_INTERFACE_PGLASS8:
+ case EVENT_INTERFACE_PGLASS9:
+ m_perso.glasses = event.event-EVENT_INTERFACE_PGLASS0;
+ WriteGamerPerso(m_main->RetGamerName());
+ UpdatePerso();
+ m_main->ScenePerso();
+ break;
+
+ case EVENT_INTERFACE_PC0a:
+ case EVENT_INTERFACE_PC1a:
+ case EVENT_INTERFACE_PC2a:
+ case EVENT_INTERFACE_PC3a:
+ case EVENT_INTERFACE_PC4a:
+ case EVENT_INTERFACE_PC5a:
+ case EVENT_INTERFACE_PC6a:
+ case EVENT_INTERFACE_PC7a:
+ case EVENT_INTERFACE_PC8a:
+ case EVENT_INTERFACE_PC9a:
+ FixPerso(event.event-EVENT_INTERFACE_PC0a, 0);
+ WriteGamerPerso(m_main->RetGamerName());
+ UpdatePerso();
+ m_main->ScenePerso();
+ break;
+
+ case EVENT_INTERFACE_PC0b:
+ case EVENT_INTERFACE_PC1b:
+ case EVENT_INTERFACE_PC2b:
+ case EVENT_INTERFACE_PC3b:
+ case EVENT_INTERFACE_PC4b:
+ case EVENT_INTERFACE_PC5b:
+ case EVENT_INTERFACE_PC6b:
+ case EVENT_INTERFACE_PC7b:
+ case EVENT_INTERFACE_PC8b:
+ case EVENT_INTERFACE_PC9b:
+ FixPerso(event.event-EVENT_INTERFACE_PC0b, 1);
+ WriteGamerPerso(m_main->RetGamerName());
+ UpdatePerso();
+ m_main->ScenePerso();
+ break;
+
+ case EVENT_INTERFACE_PCRa:
+ case EVENT_INTERFACE_PCGa:
+ case EVENT_INTERFACE_PCBa:
+ case EVENT_INTERFACE_PCRb:
+ case EVENT_INTERFACE_PCGb:
+ case EVENT_INTERFACE_PCBb:
+ ColorPerso();
+ WriteGamerPerso(m_main->RetGamerName());
+ UpdatePerso();
+ m_main->ScenePerso();
+ break;
+
+ case EVENT_INTERFACE_PDEF:
+ DefPerso();
+ WriteGamerPerso(m_main->RetGamerName());
+ UpdatePerso();
+ m_main->ScenePerso();
+ break;
+
+ case EVENT_INTERFACE_PLROT:
+ m_persoAngle += 0.2f;
+ break;
+ case EVENT_INTERFACE_PRROT:
+ m_persoAngle -= 0.2f;
+ break;
+
+ case EVENT_INTERFACE_POK:
+ m_main->ChangePhase(PHASE_INIT);
+ break;
+
+ case EVENT_INTERFACE_PCANCEL:
+ m_perso = m_persoCopy;
+ WriteGamerPerso(m_main->RetGamerName());
+ m_main->ChangePhase(PHASE_NAME);
+ break;
+ }
+ }
+
+ if ( m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+
+ if ( event.event == pw->RetEventMsgClose() ||
+ event.event == EVENT_INTERFACE_BACK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE) )
+ {
+ m_main->ChangePhase(PHASE_INIT);
+ return FALSE;
+ }
+ }
+
+ if ( m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO )
+ {
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_CHAP:
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_CHAP);
+ if ( pl == 0 ) break;
+ m_chap[m_index] = pl->RetSelect();
+ UpdateSceneList(m_chap[m_index], m_sel[m_index]);
+ UpdateSceneResume((m_chap[m_index]+1)*100+(m_sel[m_index]+1));
+ break;
+
+ case EVENT_INTERFACE_LIST:
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_LIST);
+ if ( pl == 0 ) break;
+ m_sel[m_index] = pl->RetSelect();
+ UpdateSceneResume((m_chap[m_index]+1)*100+(m_sel[m_index]+1));
+ break;
+
+ case EVENT_INTERFACE_SOLUCE:
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_SOLUCE);
+ if ( pb == 0 ) break;
+ m_bSceneSoluce = !m_bSceneSoluce;
+ pb->SetState(STATE_CHECK, m_bSceneSoluce);
+ break;
+
+ case EVENT_INTERFACE_PLAY:
+ if ( m_phase == PHASE_PROTO && m_chap[m_index] == 0 && m_sel[m_index] == 0 )
+ {
+ m_main->ChangePhase(PHASE_MODEL);
+ break;
+ }
+ m_sceneRank = (m_chap[m_index]+1)*100+(m_sel[m_index]+1);
+ m_phaseTerm = m_phase;
+ m_main->ChangePhase(PHASE_LOADING);
+ break;
+
+ case EVENT_INTERFACE_READ:
+ m_phaseTerm = m_phase;
+ m_main->ChangePhase(PHASE_READ);
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_SETUPd ||
+ m_phase == PHASE_SETUPg ||
+ m_phase == PHASE_SETUPp ||
+ m_phase == PHASE_SETUPc ||
+ m_phase == PHASE_SETUPs )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+
+ if ( event.event == pw->RetEventMsgClose() ||
+ event.event == EVENT_INTERFACE_BACK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE) )
+ {
+ SetupMemorize();
+ m_engine->ApplyChange();
+ m_main->ChangePhase(PHASE_INIT);
+ return FALSE;
+ }
+
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_SETUPd:
+ m_main->ChangePhase(PHASE_SETUPd);
+ break;
+
+ case EVENT_INTERFACE_SETUPg:
+ m_main->ChangePhase(PHASE_SETUPg);
+ break;
+
+ case EVENT_INTERFACE_SETUPp:
+ m_main->ChangePhase(PHASE_SETUPp);
+ break;
+
+ case EVENT_INTERFACE_SETUPc:
+ m_main->ChangePhase(PHASE_SETUPc);
+ break;
+
+ case EVENT_INTERFACE_SETUPs:
+ m_main->ChangePhase(PHASE_SETUPs);
+ break;
+ }
+ }
+
+ if ( m_phase == PHASE_SETUPds ||
+ m_phase == PHASE_SETUPgs ||
+ m_phase == PHASE_SETUPps ||
+ m_phase == PHASE_SETUPcs ||
+ m_phase == PHASE_SETUPss )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+
+ if ( event.event == pw->RetEventMsgClose() ||
+ event.event == EVENT_INTERFACE_BACK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE) )
+ {
+ SetupMemorize();
+ m_engine->ApplyChange();
+ m_interface->DeleteControl(EVENT_WINDOW5);
+ ChangePhase(PHASE_SIMUL);
+ StopSuspend();
+ return FALSE;
+ }
+
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_SETUPd:
+ ChangePhase(PHASE_SETUPds);
+ break;
+
+ case EVENT_INTERFACE_SETUPg:
+ ChangePhase(PHASE_SETUPgs);
+ break;
+
+ case EVENT_INTERFACE_SETUPp:
+ ChangePhase(PHASE_SETUPps);
+ break;
+
+ case EVENT_INTERFACE_SETUPc:
+ ChangePhase(PHASE_SETUPcs);
+ break;
+
+ case EVENT_INTERFACE_SETUPs:
+ ChangePhase(PHASE_SETUPss);
+ break;
+ }
+ }
+
+ if ( m_phase == PHASE_SETUPd || // setup/display ?
+ m_phase == PHASE_SETUPds )
+ {
+ switch( event.event )
+ {
+ case EVENT_LIST1:
+ case EVENT_LIST2:
+ UpdateApply();
+ break;
+
+ case EVENT_INTERFACE_FULL:
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) break;
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_FULL);
+ if ( pc == 0 ) break;
+ pl = (CList*)pw->SearchControl(EVENT_LIST2);
+ if ( pl == 0 ) break;
+ if ( pc->TestState(STATE_CHECK) )
+ {
+ pc->ClearState(STATE_CHECK); // fenêtré
+ pl->ClearState(STATE_ENABLE);
+ }
+ else
+ {
+ pc->SetState(STATE_CHECK); // plein écran
+ pl->SetState(STATE_ENABLE);
+ }
+ UpdateApply();
+ break;
+
+ case EVENT_INTERFACE_APPLY:
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) break;
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_APPLY);
+ if ( pb == 0 ) break;
+ pb->ClearState(STATE_PRESS);
+ pb->ClearState(STATE_HILIGHT);
+ ChangeDisplay();
+ UpdateApply();
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_SETUPg || // setup/graphic ?
+ m_phase == PHASE_SETUPgs )
+ {
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_SHADOW:
+ m_engine->SetShadow(!m_engine->RetShadow());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_GROUND:
+ m_engine->SetGroundSpot(!m_engine->RetGroundSpot());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_DIRTY:
+ m_engine->SetDirty(!m_engine->RetDirty());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_FOG:
+ m_engine->SetFog(!m_engine->RetFog());
+ m_camera->SetOverBaseColor(RetColor(RetColor(0.0f)));
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_LENS:
+ m_engine->SetLensMode(!m_engine->RetLensMode());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_SKY:
+ m_engine->SetSkyMode(!m_engine->RetSkyMode());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_PLANET:
+ m_engine->SetPlanetMode(!m_engine->RetPlanetMode());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_LIGHT:
+ m_engine->SetLightMode(!m_engine->RetLightMode());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_PARTI:
+ case EVENT_INTERFACE_CLIP:
+ case EVENT_INTERFACE_DETAIL:
+ case EVENT_INTERFACE_GADGET:
+ case EVENT_INTERFACE_TEXTURE:
+ ChangeSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_MIN:
+ ChangeSetupQuality(-1);
+ UpdateSetupButtons();
+ break;
+ case EVENT_INTERFACE_NORM:
+ ChangeSetupQuality(0);
+ UpdateSetupButtons();
+ break;
+ case EVENT_INTERFACE_MAX:
+ ChangeSetupQuality(1);
+ UpdateSetupButtons();
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_SETUPp || // setup/jeu ?
+ m_phase == PHASE_SETUPps )
+ {
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_TOTO:
+ m_engine->SetTotoMode(!m_engine->RetTotoMode());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_TOOLTIP:
+ m_bTooltip = !m_bTooltip;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_GLINT:
+ m_bGlint = !m_bGlint;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_RAIN:
+ m_bRain = !m_bRain;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_MOUSE:
+ m_engine->SetNiceMouse(!m_engine->RetNiceMouse());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_EDITMODE:
+ m_engine->SetEditIndentMode(!m_engine->RetEditIndentMode());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_EDITVALUE:
+ if ( m_engine->RetEditIndentValue() == 2 )
+ {
+ m_engine->SetEditIndentValue(4);
+ }
+ else
+ {
+ m_engine->SetEditIndentValue(2);
+ }
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_SOLUCE4:
+ m_bSoluce4 = !m_bSoluce4;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_MOVIES:
+ m_bMovies = !m_bMovies;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_NICERST:
+ m_bNiceReset = !m_bNiceReset;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_HIMSELF:
+ m_bHimselfDamage = !m_bHimselfDamage;
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_SCROLL:
+ m_bCameraScroll = !m_bCameraScroll;
+ m_camera->SetCameraScroll(m_bCameraScroll);
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_INVERTX:
+ m_bCameraInvertX = !m_bCameraInvertX;
+ m_camera->SetCameraInvertX(m_bCameraInvertX);
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_INVERTY:
+ m_bCameraInvertY = !m_bCameraInvertY;
+ m_camera->SetCameraInvertY(m_bCameraInvertY);
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_EFFECT:
+ m_bEffect = !m_bEffect;
+ m_camera->SetEffect(m_bEffect);
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_SETUPc || // setup/commandes ?
+ m_phase == PHASE_SETUPcs )
+ {
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_KSCROLL:
+ UpdateKey();
+ break;
+
+ case EVENT_INTERFACE_KLEFT:
+ case EVENT_INTERFACE_KRIGHT:
+ case EVENT_INTERFACE_KUP:
+ case EVENT_INTERFACE_KDOWN:
+ case EVENT_INTERFACE_KGUP:
+ case EVENT_INTERFACE_KGDOWN:
+ case EVENT_INTERFACE_KCAMERA:
+ case EVENT_INTERFACE_KDESEL:
+ case EVENT_INTERFACE_KACTION:
+ case EVENT_INTERFACE_KNEAR:
+ case EVENT_INTERFACE_KAWAY:
+ case EVENT_INTERFACE_KNEXT:
+ case EVENT_INTERFACE_KHUMAN:
+ case EVENT_INTERFACE_KQUIT:
+ case EVENT_INTERFACE_KHELP:
+ case EVENT_INTERFACE_KPROG:
+ case EVENT_INTERFACE_KCBOT:
+ case EVENT_INTERFACE_KSPEED10:
+ case EVENT_INTERFACE_KSPEED15:
+ case EVENT_INTERFACE_KSPEED20:
+ case EVENT_INTERFACE_KSPEED30:
+ case EVENT_INTERFACE_KVISIT:
+ ChangeKey(event.event);
+ UpdateKey();
+ break;
+
+ case EVENT_INTERFACE_KDEF:
+ m_engine->ResetKey();
+ UpdateKey();
+ break;
+
+ case EVENT_INTERFACE_JOYSTICK:
+ m_engine->SetJoystick(!m_engine->RetJoystick());
+ UpdateSetupButtons();
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_SETUPs || // setup/sound ?
+ m_phase == PHASE_SETUPss )
+ {
+ switch( event.event )
+ {
+ case EVENT_INTERFACE_VOLSOUND:
+ case EVENT_INTERFACE_VOLMUSIC:
+ ChangeSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_SOUND3D:
+ m_sound->SetSound3D(!m_sound->RetSound3D());
+ ChangeSetupButtons();
+ UpdateSetupButtons();
+ break;
+
+ case EVENT_INTERFACE_SILENT:
+ m_sound->SetAudioVolume(0);
+ m_sound->SetMidiVolume(0);
+ UpdateSetupButtons();
+ break;
+ case EVENT_INTERFACE_NOISY:
+ m_sound->SetAudioVolume(MAXVOLUME);
+ m_sound->SetMidiVolume(MAXVOLUME*3/4);
+ UpdateSetupButtons();
+ break;
+ }
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_READ )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+
+ if ( event.event == pw->RetEventMsgClose() ||
+ event.event == EVENT_INTERFACE_BACK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE) )
+ {
+ ChangePhase(m_phaseTerm);
+ }
+
+ if ( event.event == EVENT_INTERFACE_IOLIST )
+ {
+ IOUpdateList();
+ }
+ if ( event.event == EVENT_INTERFACE_IODELETE )
+ {
+ IODeleteScene();
+ IOUpdateList();
+ }
+ if ( event.event == EVENT_INTERFACE_IOREAD )
+ {
+ if ( IOReadScene() )
+ {
+ m_main->ChangePhase(PHASE_LOADING);
+ }
+ }
+
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_WRITEs ||
+ m_phase == PHASE_READs )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+
+ if ( event.event == pw->RetEventMsgClose() ||
+ event.event == EVENT_INTERFACE_BACK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE) )
+ {
+ m_interface->DeleteControl(EVENT_WINDOW5);
+ ChangePhase(PHASE_SIMUL);
+ StopSuspend();
+ }
+
+ if ( event.event == EVENT_INTERFACE_IOLIST )
+ {
+ IOUpdateList();
+ }
+ if ( event.event == EVENT_INTERFACE_IODELETE )
+ {
+ IODeleteScene();
+ IOUpdateList();
+ }
+ if ( event.event == EVENT_INTERFACE_IOWRITE )
+ {
+ IOWriteScene();
+ m_interface->DeleteControl(EVENT_WINDOW5);
+ ChangePhase(PHASE_SIMUL);
+ StopSuspend();
+ }
+ if ( event.event == EVENT_INTERFACE_IOREAD )
+ {
+ if ( IOReadScene() )
+ {
+ m_interface->DeleteControl(EVENT_WINDOW5);
+ ChangePhase(PHASE_SIMUL);
+ StopSuspend();
+ m_main->ChangePhase(PHASE_LOADING);
+ }
+ }
+
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_WELCOME1 )
+ {
+ if ( event.event == EVENT_KEYDOWN ||
+ event.event == EVENT_LBUTTONDOWN ||
+ event.event == EVENT_RBUTTONDOWN )
+ {
+ ChangePhase(PHASE_WELCOME2);
+ return TRUE;
+ }
+ }
+ if ( m_phase == PHASE_WELCOME2 )
+ {
+ if ( event.event == EVENT_KEYDOWN ||
+ event.event == EVENT_LBUTTONDOWN ||
+ event.event == EVENT_RBUTTONDOWN )
+ {
+ ChangePhase(PHASE_WELCOME3);
+ return TRUE;
+ }
+ }
+ if ( m_phase == PHASE_WELCOME3 )
+ {
+ if ( event.event == EVENT_KEYDOWN ||
+ event.event == EVENT_LBUTTONDOWN ||
+ event.event == EVENT_RBUTTONDOWN )
+ {
+ ChangePhase(PHASE_NAME);
+ return TRUE;
+ }
+ }
+
+ if ( m_phase == PHASE_GENERIC )
+ {
+ if ( event.event == EVENT_INTERFACE_ABORT )
+ {
+ ChangePhase(PHASE_INIT);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+ if ( event.param == VK_ESCAPE )
+ {
+ ChangePhase(PHASE_INIT);
+ }
+ else
+ {
+ m_event->MakeEvent(newEvent, EVENT_QUIT);
+ m_event->AddEvent(newEvent);
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN ||
+ event.event == EVENT_RBUTTONDOWN )
+ {
+ m_event->MakeEvent(newEvent, EVENT_QUIT);
+ m_event->AddEvent(newEvent);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Fait bouger les reflets.
+
+void CMainDialog::GlintMove()
+{
+ CWindow* pw;
+ CGroup* pg;
+ FPOINT pos, dim, zoom;
+
+ if ( m_phase == PHASE_SIMUL ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ if ( m_phase == PHASE_INIT )
+ {
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTl);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.23f);
+ zoom.y = sinf(m_glintTime*0.37f);
+ pos.x = 0.35f;
+ pos.y = 0.90f;
+ dim.x = 0.30f-0.10f*(zoom.x+1.0f)/2.0f;
+ dim.y = 0.50f-0.30f*(zoom.y+1.0f)/2.0f;
+ pos.y -= dim.y;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTr);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.21f);
+ zoom.y = sinf(m_glintTime*0.26f);
+ pos.x = 0.65f;
+ pos.y = 0.10f;
+ dim.x = 0.30f-0.10f*(zoom.x+1.0f)/2.0f;
+ dim.y = 0.50f-0.30f*(zoom.y+1.0f)/2.0f;
+ pos.x -= dim.x;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+ }
+
+ if ( m_phase == PHASE_NAME ||
+ m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO )
+ {
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTl);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.22f);
+ zoom.y = sinf(m_glintTime*0.37f);
+ pos.x = 0.10f;
+ pos.y = 0.90f;
+ dim.x = 0.60f+0.30f*zoom.x;
+ dim.y = 0.60f+0.30f*zoom.y;
+ pos.y -= dim.y;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTr);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.19f);
+ zoom.y = sinf(m_glintTime*0.28f);
+ pos.x = 0.90f;
+ pos.y = 0.10f;
+ dim.x = 0.60f+0.30f*zoom.x;
+ dim.y = 0.60f+0.30f*zoom.y;
+ pos.x -= dim.x;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+ }
+
+ if ( m_phase == PHASE_SETUPd ||
+ m_phase == PHASE_SETUPg ||
+ m_phase == PHASE_SETUPp ||
+ m_phase == PHASE_SETUPc ||
+ m_phase == PHASE_SETUPs ||
+ m_phase == PHASE_SETUPds ||
+ m_phase == PHASE_SETUPgs ||
+ m_phase == PHASE_SETUPps ||
+ m_phase == PHASE_SETUPcs ||
+ m_phase == PHASE_SETUPss )
+ {
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTu);
+ if ( pg != 0 )
+ {
+ zoom.y = sinf(m_glintTime*0.27f);
+ pos.x = 0.10f;
+ pos.y = 0.76f;
+ dim.x = 0.80f;
+ dim.y = 0.32f+0.20f*zoom.y;
+ pos.y -= dim.y;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTr);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.29f);
+ zoom.y = sinf(m_glintTime*0.14f);
+ pos.x = 0.90f;
+ pos.y = 0.10f;
+ dim.x = 0.40f+0.20f*zoom.x;
+ dim.y = 0.40f+0.20f*zoom.y;
+ pos.x -= dim.x;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+ }
+
+ if ( m_phase == PHASE_WRITE ||
+ m_phase == PHASE_READ ||
+ m_phase == PHASE_WRITEs ||
+ m_phase == PHASE_READs )
+ {
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTl);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.22f);
+ zoom.y = sinf(m_glintTime*0.37f);
+ pos.x = 0.10f;
+ pos.y = 0.90f;
+ dim.x = 0.60f+0.30f*zoom.x;
+ dim.y = 0.60f+0.30f*zoom.y;
+ pos.y -= dim.y;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+
+ pg = (CGroup*)pw->SearchControl(EVENT_INTERFACE_GLINTr);
+ if ( pg != 0 )
+ {
+ zoom.x = sinf(m_glintTime*0.19f);
+ zoom.y = sinf(m_glintTime*0.28f);
+ pos.x = 0.90f;
+ pos.y = 0.10f;
+ dim.x = 0.60f+0.30f*zoom.x;
+ dim.y = 0.60f+0.30f*zoom.y;
+ pos.x -= dim.x;
+ pg->SetPos(pos);
+ pg->SetDim(dim);
+ }
+ }
+}
+
+
+// Retourne la position pour un son.
+
+D3DVECTOR SoundPos(FPOINT pos)
+{
+ D3DVECTOR s;
+
+ s.x = (pos.x-0.5f)*2.0f;
+ s.y = (pos.y-0.5f)*2.0f;
+ s.z = 0.0f;
+
+ return s;
+}
+
+// Retourne une position aléatoire pour un son.
+
+D3DVECTOR SoundRand()
+{
+ D3DVECTOR s;
+
+ s.x = (Rand()-0.5f)*2.0f;
+ s.y = (Rand()-0.5f)*2.0f;
+ s.z = 0.0f;
+
+ return s;
+}
+
+// Fait évoluer qq joiles particules.
+
+void CMainDialog::FrameParticule(float rTime)
+{
+#if _NEWLOOK
+#else
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float *pParti, *pGlint;
+ int nParti, nGlint;
+ int i, r, ii;
+
+ static float partiPosInit[1+5*12] =
+ { // x x t2 t2 type
+ 12.0f,
+ 607.0f, 164.0f, 0.2f, 0.8f, 1.0f, // câble sup.
+ 604.0f, 205.0f, 0.1f, 0.3f, 1.0f, // câble mid.
+ 603.0f, 247.0f, 0.1f, 0.3f, 1.0f, // câble inf.
+ 119.0f, 155.0f, 0.2f, 0.4f, 2.0f, // tuyau gauche
+ 366.0f, 23.0f, 0.5f, 1.5f, 4.0f, // tuyau sup.
+ 560.0f, 414.0f, 0.1f, 0.1f, 1.0f, // bouton inf/droite
+ 20.0f, 413.0f, 0.1f, 0.1f, 2.0f, // bouton inf/gauche
+ 39.0f, 78.0f, 0.1f, 0.2f, 1.0f, // pot gauche
+ 39.0f, 78.0f, 0.5f, 0.9f, 1.0f, // pot gauche
+ 170.0f, 229.0f, 0.5f, 0.5f, 3.0f, // fumée gauche
+ 170.0f, 229.0f, 0.5f, 0.5f, 3.0f, // fumée gauche
+ 474.0f, 229.0f, 0.5f, 0.5f, 3.0f, // fumée droite
+ };
+
+ static float glintPosInit[1+2*14] =
+ {
+ 14.0f,
+ 15.0f, 407.0f,
+ 68.0f, 417.0f,
+ 548.0f, 36.0f,
+ 611.0f, 37.0f,
+ 611.0f, 100.0f,
+ 611.0f, 395.0f,
+ 36.0f, 35.0f,
+ 166.0f, 55.0f,
+ 166.0f, 94.0f,
+ 477.0f, 56.0f,
+ 31.0f, 190.0f,
+ 32.0f, 220.0f,
+ 65.0f, 221.0f,
+ 65.0f, 250.0f,
+ };
+
+ static float partiPosBig[1+5*12] =
+ { // x x t2 t2 type
+ 12.0f,
+ 607.0f, 164.0f, 0.2f, 0.8f, 1.0f, // câble sup.
+ 604.0f, 205.0f, 0.1f, 0.3f, 1.0f, // câble mid.
+ 603.0f, 247.0f, 0.1f, 0.3f, 1.0f, // câble inf.
+ 64.0f, 444.0f, 0.2f, 0.8f, 1.0f, // câble bas gauche
+ 113.0f, 449.0f, 0.1f, 0.3f, 1.0f, // câble bas gauche
+ 340.0f, 463.0f, 0.2f, 0.8f, 1.0f, // câble bas milieu
+ 36.0f, 155.0f, 0.2f, 0.4f, 2.0f, // tuyau gauche
+ 366.0f, 23.0f, 0.5f, 1.5f, 4.0f, // tuyau sup.
+ 612.0f, 414.0f, 0.1f, 0.1f, 1.0f, // bouton inf/droite
+ 20.0f, 413.0f, 0.1f, 0.1f, 2.0f, // bouton inf/gauche
+ 39.0f, 78.0f, 0.1f, 0.2f, 1.0f, // pot gauche
+ 39.0f, 78.0f, 0.5f, 0.9f, 1.0f, // pot gauche
+ };
+
+ static float glintPosBig[1+2*12] =
+ {
+ 12.0f,
+ 15.0f, 407.0f,
+ 48.0f, 399.0f,
+ 611.0f, 37.0f,
+ 611.0f, 100.0f,
+ 611.0f, 395.0f,
+ 36.0f, 35.0f,
+ 31.0f, 190.0f,
+ 32.0f, 220.0f,
+ 31.0f, 221.0f,
+ 31.0f, 189.0f,
+ 255.0f, 18.0f,
+ 279.0f, 18.0f,
+ };
+
+ if ( m_bDialog || !m_bRain ) return;
+
+ if ( m_phase == PHASE_INIT )
+ {
+ pParti = partiPosInit;
+ pGlint = glintPosInit;
+ }
+ else if ( m_phase == PHASE_NAME ||
+ m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO ||
+ m_phase == PHASE_SETUPd ||
+ m_phase == PHASE_SETUPg ||
+ m_phase == PHASE_SETUPp ||
+ m_phase == PHASE_SETUPc ||
+ m_phase == PHASE_SETUPs ||
+ m_phase == PHASE_WRITE ||
+ m_phase == PHASE_READ )
+ {
+ pParti = partiPosBig;
+ pGlint = glintPosBig;
+ }
+ else
+ {
+ return;
+ }
+
+ nParti = (int)(*pParti++);
+ nGlint = (int)(*pGlint++);
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ if ( m_partiPhase[i] == 0 ) // attente ?
+ {
+ m_partiTime[i] -= rTime;
+ if ( m_partiTime[i] <= 0.0f )
+ {
+ r = rand()%3;
+
+ if ( r == 0 )
+ {
+ ii = rand()%nParti;
+ m_partiPos[i].x = pParti[ii*5+0]/640.0f;
+ m_partiPos[i].y = (480.0f-pParti[ii*5+1])/480.0f;
+ m_partiTime[i] = pParti[ii*5+2]+Rand()*pParti[ii*5+3];
+ m_partiPhase[i] = (int)pParti[ii*5+4];
+ if ( m_partiPhase[i] == 3 )
+ {
+ m_sound->Play(SOUND_PSHHH, SoundPos(m_partiPos[i]), 0.3f+Rand()*0.3f);
+ }
+ else
+ {
+ m_sound->Play(SOUND_GGG, SoundPos(m_partiPos[i]), 0.1f+Rand()*0.4f);
+ }
+ }
+
+ if ( r == 1 )
+ {
+ ii = rand()%nGlint;
+ pos.x = pGlint[ii*2+0]/640.0f;
+ pos.y = (480.0f-pGlint[ii*2+1])/480.0f;
+ pos.z = 0.0f;
+ speed.x = 0.0f;
+ speed.y = 0.0f;
+ speed.z = 0.0f;
+ dim.x = 0.04f+Rand()*0.04f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ rand()%2?PARTIGLINT:PARTICONTROL,
+ Rand()*0.4f+0.4f, 0.0f, 0.0f,
+ SH_INTERFACE);
+ m_partiTime[i] = 0.5f+Rand()*0.5f;
+ }
+
+ if ( r == 2 )
+ {
+ ii = rand()%7;
+ if ( ii == 0 )
+ {
+ m_sound->Play(SOUND_ENERGY, SoundRand(), 0.2f+Rand()*0.2f);
+ m_partiTime[i] = 1.0f+Rand()*1.0f;
+ }
+ if ( ii == 1 )
+ {
+ m_sound->Play(SOUND_STATION, SoundRand(), 0.2f+Rand()*0.2f);
+ m_partiTime[i] = 1.0f+Rand()*2.0f;
+ }
+ if ( ii == 2 )
+ {
+ m_sound->Play(SOUND_ALARM, SoundRand(), 0.1f+Rand()*0.1f);
+ m_partiTime[i] = 2.0f+Rand()*4.0f;
+ }
+ if ( ii == 3 )
+ {
+ m_sound->Play(SOUND_INFO, SoundRand(), 0.1f+Rand()*0.1f);
+ m_partiTime[i] = 2.0f+Rand()*4.0f;
+ }
+ if ( ii == 4 )
+ {
+ m_sound->Play(SOUND_RADAR, SoundRand(), 0.2f+Rand()*0.2f);
+ m_partiTime[i] = 0.5f+Rand()*1.0f;
+ }
+ if ( ii == 5 )
+ {
+ m_sound->Play(SOUND_GFLAT, SoundRand(), 0.3f+Rand()*0.3f);
+ m_partiTime[i] = 2.0f+Rand()*4.0f;
+ }
+ if ( ii == 6 )
+ {
+ m_sound->Play(SOUND_ALARMt, SoundRand(), 0.1f+Rand()*0.1f);
+ m_partiTime[i] = 2.0f+Rand()*4.0f;
+ }
+ }
+ }
+ }
+
+ if ( m_partiPhase[i] != 0 ) // génère ?
+ {
+ m_partiTime[i] -= rTime;
+ if ( m_partiTime[i] > 0.0f )
+ {
+ if ( m_partiPhase[i] == 1 ) // étincelles ?
+ {
+ pos.x = m_partiPos[i].x;
+ pos.y = m_partiPos[i].y;
+ pos.z = 0.0f;
+ pos.x += (Rand()-0.5f)*0.01f;
+ pos.y += (Rand()-0.5f)*0.01f;
+ speed.x = (Rand()-0.5f)*0.2f;
+ speed.y = (Rand()-0.5f)*0.2f;
+ speed.z = 0.0f;
+ dim.x = 0.005f+Rand()*0.005f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ,
+ Rand()*0.2f+0.2f, 0.0f, 0.0f,
+ SH_INTERFACE);
+ pos.x = m_partiPos[i].x;
+ pos.y = m_partiPos[i].y;
+ pos.z = 0.0f;
+ speed.x = (Rand()-0.5f)*0.5f;
+ speed.y = (0.3f+Rand()*0.3f);
+ speed.z = 0.0f;
+ dim.x = 0.01f+Rand()*0.01f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%3),
+ Rand()*0.5f+0.5f, 2.0f, 0.0f,
+ SH_INTERFACE);
+ }
+ if ( m_partiPhase[i] == 2 ) // étincelles ?
+ {
+ pos.x = m_partiPos[i].x;
+ pos.y = m_partiPos[i].y;
+ pos.z = 0.0f;
+ pos.x += (Rand()-0.5f)*0.01f;
+ pos.y += (Rand()-0.5f)*0.01f;
+ speed.x = (Rand()-0.5f)*0.2f;
+ speed.y = (Rand()-0.5f)*0.2f;
+ speed.z = 0.0f;
+ dim.x = 0.005f+Rand()*0.005f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ,
+ Rand()*0.2f+0.2f, 0.0f, 0.0f,
+ SH_INTERFACE);
+ pos.x = m_partiPos[i].x;
+ pos.y = m_partiPos[i].y;
+ pos.z = 0.0f;
+ speed.x = (Rand()-0.5f)*0.5f;
+ speed.y = (0.3f+Rand()*0.3f);
+ speed.z = 0.0f;
+ dim.x = 0.005f+Rand()*0.005f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTISCRAPS,
+ Rand()*0.5f+0.5f, 2.0f, 0.0f,
+ SH_INTERFACE);
+ }
+ if ( m_partiPhase[i] == 3 ) // fumée ?
+ {
+ pos.x = m_partiPos[i].x;
+ pos.y = m_partiPos[i].y;
+ pos.z = 0.0f;
+ pos.x += (Rand()-0.5f)*0.03f;
+ pos.y += (Rand()-0.5f)*0.03f;
+ speed.x = (Rand()-0.5f)*0.2f;
+ speed.y = Rand()*0.5f;
+ speed.z = 0.0f;
+ dim.x = 0.03f+Rand()*0.07f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH,
+ Rand()*0.4f+0.4f, 0.0f, 0.0f,
+ SH_INTERFACE);
+ }
+ }
+ else
+ {
+ m_partiPhase[i] = 0;
+ m_partiTime[i] = 2.0f+Rand()*4.0f;
+ }
+ }
+ }
+#endif
+}
+
+// Quelques jolies particules pour suivre la souris.
+
+void CMainDialog::NiceParticule(FPOINT mouse, BOOL bPress)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ if ( !m_bRain ) return;
+ if ( (m_phase == PHASE_SIMUL ||
+ m_phase == PHASE_WIN ||
+ m_phase == PHASE_LOST ||
+ m_phase == PHASE_MODEL ) &&
+ !m_bDialog ) return;
+
+ if ( bPress )
+ {
+ pos.x = mouse.x;
+ pos.y = mouse.y;
+ pos.z = 0.0f;
+ speed.x = (Rand()-0.5f)*0.5f;
+ speed.y = (0.3f+Rand()*0.3f);
+ speed.z = 0.0f;
+ dim.x = 0.005f+Rand()*0.005f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTISCRAPS,
+ Rand()*0.5f+0.5f, 2.0f, 0.0f,
+ SH_INTERFACE);
+ }
+ else
+ {
+ pos.x = mouse.x;
+ pos.y = mouse.y;
+ pos.z = 0.0f;
+ speed.x = (Rand()-0.5f)*0.5f;
+ speed.y = (0.3f+Rand()*0.3f);
+ speed.z = 0.0f;
+ dim.x = 0.01f+Rand()*0.01f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%3),
+ Rand()*0.5f+0.5f, 2.0f, 0.0f,
+ SH_INTERFACE);
+ }
+}
+
+
+
+// Spécifie le dossier spécial utilisateur si nécessaire.
+
+void CMainDialog::SetUserDir(char *base, int rank)
+{
+ char dir[100];
+
+ if ( strcmp(base, "user") == 0 && rank >= 100 )
+ {
+ sprintf(dir, "%s\\%s", m_userDir, m_userList[rank/100-1]);
+ UserDir(TRUE, dir);
+ }
+ else
+ {
+ UserDir(FALSE, "");
+ }
+}
+
+// Construit le nom de fichier d'une mission.
+
+void CMainDialog::BuildSceneName(char *filename, char *base, int rank)
+{
+ if ( strcmp(base, "user") == 0 )
+ {
+ sprintf(filename, "%s\\%s\\scene%.2d.txt", m_userDir, m_userList[rank/100-1], rank%100);
+ }
+ else
+ {
+ sprintf(filename, "%s\\%s%.3d.txt", m_sceneDir, base, rank);
+ }
+}
+
+// Construit le nom descriptif par défaut d'une mission.
+
+void CMainDialog::BuildResumeName(char *filename, char *base, int rank)
+{
+ sprintf(filename, "Scene %s %d", base, rank);
+}
+
+// Retourne le nom du dossier où mettre les fichiers.
+
+char* CMainDialog::RetFilesDir()
+{
+ return m_filesDir;
+}
+
+
+// Met à jour la liste des joueurs d'après les dossiers sur disque.
+
+void CMainDialog::ReadNameList()
+{
+ CWindow* pw;
+ CList* pl;
+ long hFile;
+ struct _finddata_t fBuffer;
+ BOOL bDo;
+ char dir[_MAX_FNAME];
+ char temp[_MAX_FNAME];
+ char filenames[_MAX_FNAME][100];
+ int nbFilenames, i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+ pl->Flush();
+
+ nbFilenames = 0;
+ sprintf(dir, "%s\\*", m_savegameDir);
+ hFile = _findfirst(dir, &fBuffer);
+ if ( hFile != -1 )
+ {
+ do
+ {
+ if ( (fBuffer.attrib & _A_SUBDIR) && fBuffer.name[0] != '.' )
+ {
+ strcpy(filenames[nbFilenames++], fBuffer.name);
+ }
+ }
+ while ( _findnext(hFile, &fBuffer) == 0 && nbFilenames < 100 );
+ }
+ do // trie tous les noms :
+ {
+ bDo = FALSE;
+ for ( i=0 ; i<nbFilenames-1 ; i++ )
+ {
+ if ( strcmp(filenames[i], filenames[i+1]) > 0 )
+ {
+ strcpy(temp, filenames[i]);
+ strcpy(filenames[i], filenames[i+1]);
+ strcpy(filenames[i+1], temp);
+ bDo = TRUE;
+ }
+ }
+ }
+ while ( bDo );
+
+ for ( i=0 ; i<nbFilenames ; i++ )
+ {
+ pl->SetName(i, filenames[i]);
+ }
+}
+
+// Met à jour les contrôles des joueurs.
+
+void CMainDialog::UpdateNameControl()
+{
+ CWindow* pw;
+ CList* pl;
+ CButton* pb;
+ CEdit* pe;
+ char name[100];
+ char* gamer;
+ int total, sel;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_NEDIT);
+ if ( pe == 0 ) return;
+
+ gamer = m_main->RetGamerName();
+ total = pl->RetTotal();
+ sel = pl->RetSelect();
+ pe->GetText(name, 100);
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_NCANCEL);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_ENABLE, gamer[0]!=0);
+ }
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_NDELETE);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_ENABLE, total>0 && sel!=-1);
+ }
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_NOK);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_ENABLE, name[0]!=0 || sel!=-1);
+ }
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_PERSO);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_ENABLE, name[0]!=0 || sel!=-1);
+ }
+}
+
+// Met à jour la liste des joueurs en fonction du nom frapé.
+
+void CMainDialog::UpdateNameList()
+{
+ CWindow* pw;
+ CList* pl;
+ CEdit* pe;
+ char name[100];
+ int total, sel, i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_NEDIT);
+ if ( pe == 0 ) return;
+
+ pe->GetText(name, 100);
+ total = pl->RetTotal();
+ sel = pl->RetSelect();
+
+ for ( i=0 ; i<total ; i++ )
+ {
+ if ( stricmp(name, pl->RetName(i)) == 0 )
+ {
+ pl->SetSelect(i);
+ pl->ShowSelect(FALSE);
+ return;
+ }
+ }
+
+ pl->SetSelect(-1);
+}
+
+// Met à jour le nom du joueur et fonction de la liste sélectionnée.
+
+void CMainDialog::UpdateNameEdit()
+{
+ CWindow* pw;
+ CList* pl;
+ CEdit* pe;
+ char* name;
+ int sel;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_NEDIT);
+ if ( pe == 0 ) return;
+
+ sel = pl->RetSelect();
+ if ( sel == -1 )
+ {
+ pe->SetText("");
+ pe->SetCursor(0, 0);
+ }
+ else
+ {
+ name = pl->RetName(sel);
+ pe->SetText(name);
+ pe->SetCursor(strlen(name), 0);
+ }
+
+ UpdateNameControl();
+}
+
+// Met à jour la représentation du joueur en fonction de la liste sélectionnée.
+
+void CMainDialog::UpdateNameFace()
+{
+ CWindow* pw;
+ CList* pl;
+ char* name;
+ int sel;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+
+ sel = pl->RetSelect();
+ if ( sel == -1 ) return;
+ name = pl->RetName(sel);
+
+ ReadGamerPerso(name);
+}
+
+// Sélectionne un joueur.
+
+void CMainDialog::NameSelect()
+{
+ CWindow* pw;
+ CList* pl;
+ CEdit* pe;
+ char name[100];
+ int sel;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_NEDIT);
+ if ( pe == 0 ) return;
+
+ pe->GetText(name, 100);
+ sel = pl->RetSelect();
+
+ if ( sel == -1 )
+ {
+ NameCreate();
+ }
+ else
+ {
+ m_main->SetGamerName(pl->RetName(sel));
+ m_main->ChangePhase(PHASE_INIT);
+ }
+
+ RetGamerFace(m_main->RetGamerName());
+
+ SetProfileString("Gamer", "LastName", m_main->RetGamerName());
+}
+
+// Crée un nouveau joueur.
+
+void CMainDialog::NameCreate()
+{
+ CWindow* pw;
+ CEdit* pe;
+ char name[100];
+ char dir[100];
+ char c;
+ int len, i, j;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_NEDIT);
+ if ( pe == 0 ) return;
+
+ pe->GetText(name, 100);
+ if ( name[0] == 0 )
+ {
+ m_sound->Play(SOUND_TZOING);
+ return;
+ }
+
+ len = strlen(name);
+ j = 0;
+ for ( i=0 ; i<len ; i++ )
+ {
+ c = RetNoAccent(RetToLower(name[i]));
+ if ( (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ c == ' ' ||
+ c == '-' ||
+ c == '_' ||
+ c == '.' ||
+ c == ',' ||
+ c == '\'' )
+ {
+ name[j++] = name[i];
+ }
+ }
+ name[j] = 0;
+ if ( j == 0 )
+ {
+ m_sound->Play(SOUND_TZOING);
+ return;
+ }
+
+ _mkdir(m_savegameDir); // si n'existe pas encore !
+
+ sprintf(dir, "%s\\%s", m_savegameDir, name);
+ if ( _mkdir(dir) != 0 )
+ {
+ m_sound->Play(SOUND_TZOING);
+ pe->SetText(name);
+ pe->SetCursor(strlen(name), 0);
+ pe->SetFocus(TRUE);
+ return;
+ }
+
+ SetGamerFace(name, 0);
+
+ m_main->SetGamerName(name);
+ m_main->ChangePhase(PHASE_INIT);
+}
+
+// Supprime un dossier et toute sa descendance.
+
+BOOL RemoveDir(char *dirname)
+{
+ long hFile;
+ struct _finddata_t fBuffer;
+ char filename[100];
+
+ sprintf(filename, "%s\\*", dirname);
+ hFile = _findfirst(filename, &fBuffer);
+ if ( hFile != -1 )
+ {
+ do
+ {
+ if ( fBuffer.name[0] != '.' )
+ {
+ if ( fBuffer.attrib & _A_SUBDIR )
+ {
+ sprintf(filename, "%s\\%s", dirname, fBuffer.name);
+ RemoveDir(filename);
+ }
+ else
+ {
+ sprintf(filename, "%s\\%s", dirname, fBuffer.name);
+ remove(filename);
+ }
+ }
+ }
+ while ( _findnext(hFile, &fBuffer) == 0 );
+ }
+
+ if ( _rmdir(dirname) != 0 )
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+// Supprime un joueur.
+
+void CMainDialog::NameDelete()
+{
+ CWindow* pw;
+ CList* pl;
+ int sel;
+ char* gamer;
+ char dir[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_NLIST);
+ if ( pl == 0 ) return;
+
+ sel = pl->RetSelect();
+ if ( sel == -1 )
+ {
+ m_sound->Play(SOUND_TZOING);
+ return;
+ }
+ gamer = pl->RetName(sel);
+
+ // Supprime tout le contenu du dossier.
+ sprintf(dir, "%s\\%s", m_savegameDir, gamer);
+ if ( !RemoveDir(dir) )
+ {
+ m_sound->Play(SOUND_TZOING);
+ return;
+ }
+
+ m_main->SetGamerName("");
+ pl->SetSelect(-1);
+
+ ReadNameList();
+ UpdateNameList();
+ UpdateNameControl();
+}
+
+
+
+// Teste si deux couleurs sont égales ou presque.
+
+BOOL EqColor(const D3DCOLORVALUE &c1, const D3DCOLORVALUE &c2)
+{
+ return (Abs(c1.r-c2.r) < 0.01f &&
+ Abs(c1.g-c2.g) < 0.01f &&
+ Abs(c1.b-c2.b) < 0.01f );
+}
+
+// Met à jour tous les boutons pour le personnage.
+
+void CMainDialog::UpdatePerso()
+{
+ CWindow* pw;
+ CLabel* pl;
+ CButton* pb;
+ CColor* pc;
+ CSlider* ps;
+ D3DCOLORVALUE color;
+ char name[100];
+ int i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_PHEAD);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_CHECK, m_persoTab==0);
+ }
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_PBODY);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_CHECK, m_persoTab==1);
+ }
+
+ pl = (CLabel*)pw->SearchControl(EVENT_LABEL11);
+ if ( pl != 0 )
+ {
+ if ( m_persoTab == 0 )
+ {
+ pl->SetState(STATE_VISIBLE);
+ GetResource(RES_TEXT, RT_PERSO_FACE, name);
+ pl->SetName(name);
+ }
+ else
+ {
+ pl->ClearState(STATE_VISIBLE);
+ }
+ }
+
+ pl = (CLabel*)pw->SearchControl(EVENT_LABEL12);
+ if ( pl != 0 )
+ {
+ if ( m_persoTab == 0 )
+ {
+ pl->SetState(STATE_VISIBLE);
+ GetResource(RES_TEXT, RT_PERSO_GLASSES, name);
+ pl->SetName(name);
+ }
+ else
+ {
+ pl->ClearState(STATE_VISIBLE);
+ }
+ }
+
+ pl = (CLabel*)pw->SearchControl(EVENT_LABEL13);
+ if ( pl != 0 )
+ {
+ if ( m_persoTab == 0 ) GetResource(RES_TEXT, RT_PERSO_HAIR, name);
+ else GetResource(RES_TEXT, RT_PERSO_BAND, name);
+ pl->SetName(name);
+ }
+
+ pl = (CLabel*)pw->SearchControl(EVENT_LABEL14);
+ if ( pl != 0 )
+ {
+ if ( m_persoTab == 0 )
+ {
+ pl->ClearState(STATE_VISIBLE);
+ }
+ else
+ {
+ pl->SetState(STATE_VISIBLE);
+ GetResource(RES_TEXT, RT_PERSO_COMBI, name);
+ pl->SetName(name);
+ }
+ }
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pb = (CButton*)pw->SearchControl((EventMsg)(EVENT_INTERFACE_PFACE1+i));
+ if ( pb == 0 ) break;
+ pb->SetState(STATE_VISIBLE, m_persoTab==0);
+ pb->SetState(STATE_CHECK, i==m_perso.face);
+ }
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pb = (CButton*)pw->SearchControl((EventMsg)(EVENT_INTERFACE_PGLASS0+i));
+ if ( pb == 0 ) break;
+ pb->SetState(STATE_VISIBLE, m_persoTab==0);
+ pb->SetState(STATE_CHECK, i==m_perso.glasses);
+ }
+
+ for ( i=0 ; i<3*3 ; i++ )
+ {
+ pc = (CColor*)pw->SearchControl((EventMsg)(EVENT_INTERFACE_PC0a+i));
+ if ( pc == 0 ) break;
+ if ( m_persoTab == 0 )
+ {
+ pc->ClearState(STATE_VISIBLE);
+ }
+ else
+ {
+ pc->SetState(STATE_VISIBLE);
+ color.r = perso_color[3*10*1+3*i+0]/255.0f;
+ color.g = perso_color[3*10*1+3*i+1]/255.0f;
+ color.b = perso_color[3*10*1+3*i+2]/255.0f;
+ color.a = 0.0f;
+ pc->SetColor(color);
+ pc->SetState(STATE_CHECK, EqColor(color, m_perso.colorCombi));
+ }
+
+ pc = (CColor*)pw->SearchControl((EventMsg)(EVENT_INTERFACE_PC0b+i));
+ if ( pc == 0 ) break;
+ color.r = perso_color[3*10*2*m_persoTab+3*i+0]/255.0f;
+ color.g = perso_color[3*10*2*m_persoTab+3*i+1]/255.0f;
+ color.b = perso_color[3*10*2*m_persoTab+3*i+2]/255.0f;
+ color.a = 0.0f;
+ pc->SetColor(color);
+ pc->SetState(STATE_CHECK, EqColor(color, m_persoTab?m_perso.colorBand:m_perso.colorHair));
+ }
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ ps = (CSlider*)pw->SearchControl((EventMsg)(EVENT_INTERFACE_PCRa+i));
+ if ( ps == 0 ) break;
+ ps->SetState(STATE_VISIBLE, m_persoTab==1);
+ }
+
+ if ( m_persoTab == 1 )
+ {
+ color = m_perso.colorCombi;
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCRa);
+ if ( ps != 0 ) ps->SetVisibleValue(color.r*255.0f);
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCGa);
+ if ( ps != 0 ) ps->SetVisibleValue(color.g*255.0f);
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCBa);
+ if ( ps != 0 ) ps->SetVisibleValue(color.b*255.0f);
+ }
+
+ if ( m_persoTab == 0 ) color = m_perso.colorHair;
+ else color = m_perso.colorBand;
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCRb);
+ if ( ps != 0 ) ps->SetVisibleValue(color.r*255.0f);
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCGb);
+ if ( ps != 0 ) ps->SetVisibleValue(color.g*255.0f);
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCBb);
+ if ( ps != 0 ) ps->SetVisibleValue(color.b*255.0f);
+}
+
+// Met à jour la caméra pour le personnage.
+
+void CMainDialog::CameraPerso()
+{
+ if ( m_persoTab == 0 )
+ {
+//? m_camera->Init(D3DVECTOR(4.0f, 0.0f, 0.0f),
+//? D3DVECTOR(0.0f, 0.0f, 1.0f), 0.0f);
+ m_camera->Init(D3DVECTOR(6.0f, 0.0f, 0.0f),
+ D3DVECTOR(0.0f, 0.2f, 1.5f), 0.0f);
+ }
+ else
+ {
+ m_camera->Init(D3DVECTOR(18.0f, 0.0f, 4.5f),
+ D3DVECTOR(0.0f, 1.6f, 4.5f), 0.0f);
+ }
+
+ m_camera->SetType(CAMERA_SCRIPT);
+ m_camera->FixCamera();
+}
+
+// Met une couleur fixe.
+
+void CMainDialog::FixPerso(int rank, int index)
+{
+ if ( m_persoTab == 0 )
+ {
+ if ( index == 1 )
+ {
+ m_perso.colorHair.r = perso_color[3*10*0+rank*3+0]/255.0f;
+ m_perso.colorHair.g = perso_color[3*10*0+rank*3+1]/255.0f;
+ m_perso.colorHair.b = perso_color[3*10*0+rank*3+2]/255.0f;
+ }
+ }
+ if ( m_persoTab == 1 )
+ {
+ if ( index == 0 )
+ {
+ m_perso.colorCombi.r = perso_color[3*10*1+rank*3+0]/255.0f;
+ m_perso.colorCombi.g = perso_color[3*10*1+rank*3+1]/255.0f;
+ m_perso.colorCombi.b = perso_color[3*10*1+rank*3+2]/255.0f;
+ }
+ if ( index == 1 )
+ {
+ m_perso.colorBand.r = perso_color[3*10*2+rank*3+0]/255.0f;
+ m_perso.colorBand.g = perso_color[3*10*2+rank*3+1]/255.0f;
+ m_perso.colorBand.b = perso_color[3*10*2+rank*3+2]/255.0f;
+ }
+ }
+}
+
+// Met à jour les couleurs du personnage.
+
+void CMainDialog::ColorPerso()
+{
+ CWindow* pw;
+ CSlider* ps;
+ D3DCOLORVALUE color;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ color.a = 0.0f;
+
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCRa);
+ if ( ps != 0 ) color.r = ps->RetVisibleValue()/255.0f;
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCGa);
+ if ( ps != 0 ) color.g = ps->RetVisibleValue()/255.0f;
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCBa);
+ if ( ps != 0 ) color.b = ps->RetVisibleValue()/255.0f;
+ if ( m_persoTab == 1 ) m_perso.colorCombi = color;
+
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCRb);
+ if ( ps != 0 ) color.r = ps->RetVisibleValue()/255.0f;
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCGb);
+ if ( ps != 0 ) color.g = ps->RetVisibleValue()/255.0f;
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_PCBb);
+ if ( ps != 0 ) color.b = ps->RetVisibleValue()/255.0f;
+ if ( m_persoTab == 0 ) m_perso.colorHair = color;
+ else m_perso.colorBand = color;
+}
+
+// Met à jour les paramètres par défaut du personnage.
+
+void CMainDialog::DefPerso()
+{
+ m_perso.colorCombi.r = 206.0f/256.0f;
+ m_perso.colorCombi.g = 206.0f/256.0f;
+ m_perso.colorCombi.b = 204.0f/256.0f; // ~blanc
+ m_perso.colorBand.r = 255.0f/256.0f;
+ m_perso.colorBand.g = 132.0f/256.0f;
+ m_perso.colorBand.b = 1.0f/256.0f; // orange
+
+ if ( m_perso.face == 0 ) // normal ?
+ {
+ m_perso.glasses = 0;
+ m_perso.colorHair.r = 90.0f/256.0f;
+ m_perso.colorHair.g = 95.0f/256.0f;
+ m_perso.colorHair.b = 85.0f/256.0f; // noir
+ }
+ if ( m_perso.face == 1 ) // chauve ?
+ {
+ m_perso.glasses = 0;
+ m_perso.colorHair.r = 83.0f/256.0f;
+ m_perso.colorHair.g = 64.0f/256.0f;
+ m_perso.colorHair.b = 51.0f/256.0f; // brun
+ }
+ if ( m_perso.face == 2 ) // carlos ?
+ {
+ m_perso.glasses = 1;
+ m_perso.colorHair.r = 85.0f/256.0f;
+ m_perso.colorHair.g = 48.0f/256.0f;
+ m_perso.colorHair.b = 9.0f/256.0f; // brun
+ }
+ if ( m_perso.face == 3 ) // blond ?
+ {
+ m_perso.glasses = 4;
+ m_perso.colorHair.r = 255.0f/256.0f;
+ m_perso.colorHair.g = 255.0f/256.0f;
+ m_perso.colorHair.b = 181.0f/256.0f; // jaune
+ }
+
+ m_perso.colorHair.a = 0.0f;
+ m_perso.colorCombi.a = 0.0f;
+ m_perso.colorBand.a = 0.0f;
+}
+
+
+// Indique s'il existe au moins une sauvegarde.
+
+BOOL CMainDialog::IsIOReadScene()
+{
+ FILE* file;
+ char filename[100];
+
+ sprintf(filename, "%s\\%s\\save%c%.3d\\data.sav", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], 0);
+ file = fopen(filename, "r");
+ if ( file == NULL ) return FALSE;
+ fclose(file);
+ return TRUE;
+}
+
+// Construit le nom du fichier par défaut.
+
+void CMainDialog::IOReadName()
+{
+ FILE* file;
+ CWindow* pw;
+ CEdit* pe;
+ char filename[_MAX_FNAME];
+ char op[100];
+ char line[500];
+ char resume[100];
+ char name[100];
+ time_t now;
+ int i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_IONAME);
+ if ( pe == 0 ) return;
+
+ sprintf(resume, "%s %d", m_sceneName, m_chap[m_index]+1);
+ BuildSceneName(filename, m_sceneName, (m_chap[m_index]+1)*100);
+ file = fopen(filename, "r");
+ if ( file != NULL )
+ {
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ sprintf(op, "Title.%c", RetLanguageLetter());
+ if ( Cmd(line, op) )
+ {
+ OpString(line, "resume", resume);
+ break;
+ }
+ }
+ fclose(file);
+ }
+
+ time(&now);
+ TimeToAscii(now, line);
+ sprintf(name, "%s %d - %s", resume, m_sel[m_index]+1, line);
+ pe->SetText(name);
+ pe->SetCursor(strlen(name), 0);
+ pe->SetFocus(TRUE);
+}
+
+// Met à jour la liste des parties enregistrées sur disque.
+
+void CMainDialog::IOReadList()
+{
+ FILE* file = NULL;
+ CWindow* pw;
+ CList* pl;
+ char filename[100];
+ char line[500];
+ char name[100];
+ int i, j;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_IOLIST);
+ if ( pl == 0 ) return;
+
+ pl->Flush();
+
+ for ( j=0 ; j<999 ; j++ )
+ {
+ sprintf(filename, "%s\\%s\\save%c%.3d\\data.sav", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], j);
+ file = fopen(filename, "r");
+ if ( file == NULL ) break;
+
+ strcmp(name, filename); // nom par défaut
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ if ( Cmd(line, "Title") )
+ {
+ OpString(line, "text", name);
+ break;
+ }
+ }
+ fclose(file);
+
+ pl->SetName(j, name);
+ }
+
+ if ( m_phase == PHASE_WRITE ||
+ m_phase == PHASE_WRITEs )
+ {
+ GetResource(RES_TEXT, RT_IO_NEW, name);
+ pl->SetName(j, name);
+ j ++;
+ }
+
+ pl->SetSelect(j-1);
+ pl->ShowSelect(FALSE); // montre la ligne sélectionnée
+}
+
+// Met à jour les boutons en fonction de la partie sélectionnée
+// dans la liste.
+
+void CMainDialog::IOUpdateList()
+{
+ FILE* file = NULL;
+ CWindow* pw;
+ CList* pl;
+ CButton* pb;
+ CImage* pi;
+ char filename[100];
+ int sel, max;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_IOLIST);
+ if ( pl == 0 ) return;
+ pi = (CImage*)pw->SearchControl(EVENT_INTERFACE_IOIMAGE);
+ if ( pi == 0 ) return;
+
+ sel = pl->RetSelect();
+ max = pl->RetTotal();
+
+ sprintf(filename, "%s\\%s\\save%c%.3d\\screen.bmp", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+
+ if ( m_phase == PHASE_WRITE ||
+ m_phase == PHASE_WRITEs )
+ {
+ if ( sel < max-1 )
+ {
+ pi->SetFilenameImage(filename);
+ }
+ else
+ {
+ pi->SetFilenameImage("");
+ }
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_IODELETE);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_ENABLE, sel < max-1);
+ }
+ }
+ else
+ {
+ pi->SetFilenameImage(filename);
+ }
+}
+
+// Supprime la scène sélectionnée.
+
+void CMainDialog::IODeleteScene()
+{
+ CWindow* pw;
+ CList* pl;
+ char dir[100];
+ char old[100];
+ long hFile;
+ struct _finddata_t fBuffer;
+ int sel, max, i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_IOLIST);
+ if ( pl == 0 ) return;
+
+ sel = pl->RetSelect();
+ if ( sel == -1 )
+ {
+ m_sound->Play(SOUND_TZOING);
+ return;
+ }
+
+ // Supprime tout le contenu du dossier.
+ sprintf(dir, "%s\\%s\\save%c%.3d\\*", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+ hFile = _findfirst(dir, &fBuffer);
+ if ( hFile != -1 )
+ {
+ do
+ {
+ if ( fBuffer.name[0] != '.' )
+ {
+ sprintf(dir, "%s\\%s\\save%c%.3d\\%s", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel, fBuffer.name);
+ remove(dir);
+ }
+ }
+ while ( _findnext(hFile, &fBuffer) == 0 );
+ }
+
+ sprintf(dir, "%s\\%s\\save%c%.3d", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+ if ( _rmdir(dir) != 0 )
+ {
+ m_sound->Play(SOUND_TZOING);
+ return;
+ }
+
+ max = pl->RetTotal();
+ for ( i=sel+1 ; i<max ; i++ )
+ {
+ sprintf(old, "%s\\%s\\save%c%.3d", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], i);
+ sprintf(dir, "%s\\%s\\save%c%.3d", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], i-1);
+ rename(old, dir);
+ }
+ IOReadList();
+}
+
+// Ecrit la scène.
+
+BOOL CMainDialog::IOWriteScene()
+{
+ CWindow* pw;
+ CList* pl;
+ CEdit* pe;
+ char filename[100];
+ char filecbot[100];
+ char info[100];
+ int sel;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_IOLIST);
+ if ( pl == 0 ) return FALSE;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_IONAME);
+ if ( pe == 0 ) return FALSE;
+
+ sel = pl->RetSelect();
+ if ( sel == -1 ) return FALSE;
+
+ _mkdir("Savegame"); // si n'existe pas encore !
+ sprintf(filename, "%s\\%s", m_savegameDir, m_main->RetGamerName());
+ _mkdir(filename);
+ sprintf(filename, "%s\\%s\\save%c%.3d", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+ _mkdir(filename);
+
+ sprintf(filename, "%s\\%s\\save%c%.3d\\data.sav", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+ sprintf(filecbot, "%s\\%s\\save%c%.3d\\cbot.run", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+ pe->GetText(info, 100);
+ m_main->IOWriteScene(filename, filecbot, info);
+
+ m_shotDelay = 3;
+ sprintf(m_shotName, "%s\\%s\\save%c%.3d\\screen.bmp", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+
+ return TRUE;
+}
+
+// Lit la scène.
+
+BOOL CMainDialog::IOReadScene()
+{
+ FILE* file;
+ CWindow* pw;
+ CList* pl;
+ char filename[100];
+ char filecbot[100];
+ char line[500];
+ char dir[100];
+ int sel, i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return FALSE;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_IOLIST);
+ if ( pl == 0 ) return FALSE;
+
+ sel = pl->RetSelect();
+ if ( sel == -1 ) return FALSE;
+
+ sprintf(filename, "%s\\%s\\save%c%.3d\\data.sav", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+ sprintf(filecbot, "%s\\%s\\save%c%.3d\\cbot.run", m_savegameDir, m_main->RetGamerName(), m_sceneName[0], sel);
+
+ file = fopen(filename, "r");
+ if ( file == NULL ) return FALSE;
+
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ if ( Cmd(line, "Mission") )
+ {
+ OpString(line, "base", m_sceneName);
+ m_sceneRank = OpInt(line, "rank", 0);
+
+ if ( strcmp(m_sceneName, "user") == 0 )
+ {
+ m_sceneRank = m_sceneRank%100;
+ OpString(line, "dir", dir);
+ for ( i=0 ; i<m_userTotal ; i++ )
+ {
+ if ( strcmp(m_userList[i], dir) == 0 )
+ {
+ m_sceneRank += (i+1)*100;
+ break;
+ }
+ }
+ if ( m_sceneRank/100 == 0 )
+ {
+ fclose(file);
+ return FALSE;
+ }
+ }
+ }
+ }
+ fclose(file);
+
+ m_chap[m_index] = (m_sceneRank/100)-1;
+ m_sel[m_index] = (m_sceneRank%100)-1;
+
+ strcpy(m_sceneRead, filename);
+ strcpy(m_stackRead, filecbot);
+ return TRUE;
+}
+
+
+// Retourne le nombre de chapitres accessibles.
+
+int CMainDialog::RetChapPassed()
+{
+ int j;
+
+ if ( m_main->RetShowAll() ) return 9;
+
+ for ( j=0 ; j<9 ; j++ )
+ {
+ if ( !RetGamerInfoPassed((j+1)*100) )
+ {
+ return j;
+ }
+ }
+ return 9;
+}
+
+// Met à jour les listes selon le cheat code.
+
+void CMainDialog::AllMissionUpdate()
+{
+ if ( m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO )
+ {
+ UpdateSceneChap(m_chap[m_index]);
+ UpdateSceneList(m_chap[m_index], m_sel[m_index]);
+ }
+}
+
+// Met à jour les chapitres des exercices ou missions.
+
+void CMainDialog::UpdateSceneChap(int &chap)
+{
+ FILE* file = NULL;
+ CWindow* pw;
+ CList* pl;
+ long hFile;
+ struct _finddata_t fileBuffer;
+ char filename[_MAX_FNAME];
+ char op[100];
+ char line[500];
+ char name[100];
+ int i, j;
+ BOOL bPassed, bDo;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_CHAP);
+ if ( pl == 0 ) return;
+
+ pl->Flush();
+
+ if ( m_phase == PHASE_USER )
+ {
+ j = 0;
+ hFile = _findfirst("user\\*", &fileBuffer);
+ if ( hFile != -1 )
+ {
+ do
+ {
+ if ( (fileBuffer.attrib & _A_SUBDIR) != 0 &&
+ fileBuffer.name[0] != '.' )
+ {
+ strcpy(m_userList[j++], fileBuffer.name);
+ }
+ }
+ while ( _findnext(hFile, &fileBuffer) == 0 && j < 100 );
+ }
+ m_userTotal = j;
+
+ do // trie tous les noms :
+ {
+ bDo = FALSE;
+ for ( i=0 ; i<m_userTotal-1 ; i++ )
+ {
+ if ( strcmp(m_userList[i], m_userList[i+1]) > 0 )
+ {
+ strcpy(name, m_userList[i]);
+ strcpy(m_userList[i], m_userList[i+1]);
+ strcpy(m_userList[i+1], name);
+ bDo = TRUE;
+ }
+ }
+ }
+ while ( bDo );
+
+ for ( j=0 ; j<m_userTotal ; j++ )
+ {
+ BuildSceneName(filename, m_sceneName, (j+1)*100);
+ file = fopen(filename, "r");
+ if ( file == NULL )
+ {
+ strcpy(name, m_userList[j]);
+ }
+ else
+ {
+ BuildResumeName(name, m_sceneName, j+1); // nom par défaut
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ sprintf(op, "Title.%c", RetLanguageLetter());
+ if ( Cmd(line, op) )
+ {
+ OpString(line, "text", name);
+ break;
+ }
+ }
+ fclose(file);
+ }
+
+ pl->SetName(j, name);
+ pl->SetEnable(j, TRUE);
+ }
+ }
+ else
+ {
+ for ( j=0 ; j<9 ; j++ )
+ {
+#if _SCHOOL
+ if ( m_phase == PHASE_MISSION ) break;
+ if ( m_phase == PHASE_FREE ) break;
+#if _CEEBOTDEMO
+ if ( m_phase == PHASE_TRAINER && j >= 2 ) break;
+#endif
+#endif
+#if _DEMO
+ if ( m_phase == PHASE_MISSION && j >= 4 ) break;
+ if ( m_phase == PHASE_TRAINER && j >= 1 ) break;
+#endif
+ BuildSceneName(filename, m_sceneName, (j+1)*100);
+ file = fopen(filename, "r");
+ if ( file == NULL ) break;
+
+ BuildResumeName(name, m_sceneName, j+1); // nom par défaut
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ sprintf(op, "Title.%c", RetLanguageLetter());
+ if ( Cmd(line, op) )
+ {
+ OpString(line, "text", name);
+ break;
+ }
+ }
+ fclose(file);
+
+ bPassed = RetGamerInfoPassed((j+1)*100);
+ sprintf(line, "%d: %s", j+1, name);
+ pl->SetName(j, line);
+ pl->SetCheck(j, bPassed);
+ pl->SetEnable(j, TRUE);
+
+ if ( m_phase == PHASE_MISSION && !m_main->RetShowAll() && !bPassed )
+ {
+ j ++;
+ break;
+ }
+
+#if _TEEN
+ if ( m_phase == PHASE_TRAINER && !m_main->RetShowAll() && !bPassed )
+ {
+ j ++;
+ break;
+ }
+#endif
+
+ if ( m_phase == PHASE_FREE && j == m_accessChap )
+ {
+ j ++;
+ break;
+ }
+ }
+ }
+
+ if ( chap > j-1 ) chap = j-1;
+
+ pl->SetSelect(chap);
+ pl->ShowSelect(FALSE); // montre la ligne sélectionnée
+}
+
+// Met à jour la liste des exercices ou missions.
+
+void CMainDialog::UpdateSceneList(int chap, int &sel)
+{
+ FILE* file = NULL;
+ CWindow* pw;
+ CList* pl;
+ char filename[_MAX_FNAME];
+ char op[100];
+ char line[500];
+ char name[100];
+ int i, j;
+ BOOL bPassed;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_INTERFACE_LIST);
+ if ( pl == 0 ) return;
+
+ pl->Flush();
+
+ for ( j=0 ; j<99 ; j++ )
+ {
+#if _SCHOOL
+ if ( m_phase == PHASE_MISSION ) break;
+ if ( m_phase == PHASE_FREE ) break;
+#if _CEEBOTDEMO
+#if _TEEN
+ if ( m_phase == PHASE_TRAINER && j >= 5 ) break;
+#else
+ if ( m_phase == PHASE_TRAINER && j >= 3 ) break;
+#endif
+#endif
+#endif
+#if _DEMO
+ if ( m_phase == PHASE_MISSION && j >= 3 ) break;
+ if ( m_phase == PHASE_TRAINER && j >= 5 ) break;
+#endif
+ BuildSceneName(filename, m_sceneName, (chap+1)*100+(j+1));
+ file = fopen(filename, "r");
+ if ( file == NULL ) break;
+
+ BuildResumeName(name, m_sceneName, j+1); // nom par défaut
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ sprintf(op, "Title.%c", RetLanguageLetter());
+ if ( Cmd(line, op) )
+ {
+ OpString(line, "text", name);
+ break;
+ }
+ }
+ fclose(file);
+
+ bPassed = RetGamerInfoPassed((chap+1)*100+(j+1));
+ sprintf(line, "%d: %s", j+1, name);
+ pl->SetName(j, line);
+ pl->SetCheck(j, bPassed);
+ pl->SetEnable(j, TRUE);
+
+ if ( m_phase == PHASE_MISSION && !m_main->RetShowAll() && !bPassed )
+ {
+ j ++;
+ break;
+ }
+
+#if _TEEN
+ if ( m_phase == PHASE_TRAINER && !m_main->RetShowAll() && !bPassed )
+ {
+ j ++;
+ break;
+ }
+#endif
+ }
+
+ BuildSceneName(filename, m_sceneName, (chap+1)*100+(j+1));
+ file = fopen(filename, "r");
+ if ( file == NULL )
+ {
+ m_maxList = j;
+ }
+ else
+ {
+ m_maxList = j+1; // ce n'est pas le dernier !
+ fclose(file);
+ }
+
+ if ( sel > j-1 ) sel = j-1;
+
+ pl->SetSelect(sel);
+ pl->ShowSelect(FALSE); // montre la ligne sélectionnée
+}
+
+// Met à jour le bouton "solution" selon le cheat code.
+
+void CMainDialog::ShowSoluceUpdate()
+{
+ CWindow* pw;
+ CEdit* pe;
+ CCheck* pc;
+
+ if ( m_phase == PHASE_TRAINER ||
+ m_phase == PHASE_DEFI ||
+ m_phase == PHASE_MISSION ||
+ m_phase == PHASE_FREE ||
+ m_phase == PHASE_TEEN ||
+ m_phase == PHASE_USER ||
+ m_phase == PHASE_PROTO )
+ {
+ m_bSceneSoluce = FALSE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_RESUME);
+ if ( pe == 0 ) return;
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SOLUCE);
+ if ( pc == 0 ) return;
+
+ if ( m_main->RetShowSoluce() )
+ {
+ pc->SetState(STATE_VISIBLE);
+ pc->SetState(STATE_CHECK);
+ m_bSceneSoluce = TRUE;
+ }
+ else
+ {
+ pc->ClearState(STATE_VISIBLE);
+ pc->ClearState(STATE_CHECK);
+ m_bSceneSoluce = FALSE;
+ }
+ }
+}
+
+// Met à jour un résumé d'exercice ou de mission.
+
+void CMainDialog::UpdateSceneResume(int rank)
+{
+ FILE* file = NULL;
+ CWindow* pw;
+ CEdit* pe;
+ CCheck* pc;
+ char filename[_MAX_FNAME];
+ char op[100];
+ char line[500];
+ char name[500];
+ int i, numTry;
+ BOOL bPassed, bVisible;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_INTERFACE_RESUME);
+ if ( pe == 0 ) return;
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SOLUCE);
+
+ if ( pc == 0 )
+ {
+ m_bSceneSoluce = FALSE;
+ }
+ else
+ {
+ numTry = RetGamerInfoTry(rank);
+ bPassed = RetGamerInfoPassed(rank);
+ bVisible = ( numTry > 2 || bPassed || m_main->RetShowSoluce() );
+ if ( !RetSoluce4() ) bVisible = FALSE;
+ pc->SetState(STATE_VISIBLE, bVisible);
+ if ( !bVisible )
+ {
+ pc->ClearState(STATE_CHECK);
+ m_bSceneSoluce = FALSE;
+ }
+ }
+
+ BuildSceneName(filename, m_sceneName, rank);
+ file = fopen(filename, "r");
+ if ( file == NULL ) return;
+
+ name[0] = 0;
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ sprintf(op, "Resume.%c", RetLanguageLetter());
+ if ( Cmd(line, op) )
+ {
+ OpString(line, "text", name);
+ break;
+ }
+ }
+ fclose(file);
+
+ pe->SetText(name);
+}
+
+// Met à jour la liste des devices.
+
+void CMainDialog::UpdateDisplayDevice()
+{
+ CWindow* pw;
+ CList* pl;
+ char bufDevices[1000];
+ char bufModes[5000];
+ int i, j, totalDevices, selectDevices, totalModes, selectModes;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_LIST1);
+ if ( pl == 0 ) return;
+ pl->Flush();
+
+ m_engine->EnumDevices(bufDevices, 1000,
+ bufModes, 5000,
+ totalDevices, selectDevices,
+ totalModes, selectModes);
+
+ i = 0;
+ j = 0;
+ while ( bufDevices[i] != 0 )
+ {
+ pl->SetName(j++, bufDevices+i);
+ while ( bufDevices[i++] != 0 );
+ }
+
+ pl->SetSelect(selectDevices);
+ pl->ShowSelect(FALSE);
+
+ m_setupSelDevice = selectDevices;
+}
+
+// Met à jour la liste des modes.
+
+void CMainDialog::UpdateDisplayMode()
+{
+ CWindow* pw;
+ CList* pl;
+ char bufDevices[1000];
+ char bufModes[5000];
+ int i, j, totalDevices, selectDevices, totalModes, selectModes;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_LIST2);
+ if ( pl == 0 ) return;
+ pl->Flush();
+
+ m_engine->EnumDevices(bufDevices, 1000,
+ bufModes, 5000,
+ totalDevices, selectDevices,
+ totalModes, selectModes);
+
+ i = 0;
+ j = 0;
+ while ( bufModes[i] != 0 )
+ {
+ pl->SetName(j++, bufModes+i);
+ while ( bufModes[i++] != 0 );
+ }
+
+ pl->SetSelect(selectModes);
+ pl->ShowSelect(FALSE);
+
+ m_setupSelMode = selectModes;
+}
+
+// Change le mode graphique.
+
+void CMainDialog::ChangeDisplay()
+{
+ CWindow* pw;
+ CList* pl;
+ CCheck* pc;
+ char* device;
+ char* mode;
+ BOOL bFull;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ pl = (CList*)pw->SearchControl(EVENT_LIST1);
+ if ( pl == 0 ) return;
+ m_setupSelDevice = pl->RetSelect();
+ device = pl->RetName(m_setupSelDevice);
+
+ pl = (CList*)pw->SearchControl(EVENT_LIST2);
+ if ( pl == 0 ) return;
+ m_setupSelMode = pl->RetSelect();
+ mode = pl->RetName(m_setupSelMode);
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_FULL);
+ if ( pc == 0 ) return;
+ bFull = pc->TestState(STATE_CHECK);
+ m_setupFull = bFull;
+
+ m_engine->ChangeDevice(device, mode, bFull);
+
+ if ( m_bSimulSetup )
+ {
+ m_main->ChangeColor();
+ m_main->UpdateMap();
+ }
+}
+
+
+
+// Met à jour le bouton "appliquer".
+
+void CMainDialog::UpdateApply()
+{
+ CWindow* pw;
+ CButton* pb;
+ CList* pl;
+ CCheck* pc;
+ int sel1, sel2;
+ BOOL bFull;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ pb = (CButton*)pw->SearchControl(EVENT_INTERFACE_APPLY);
+ if ( pb == 0 ) return;
+
+ pl = (CList*)pw->SearchControl(EVENT_LIST1);
+ if ( pl == 0 ) return;
+ sel1 = pl->RetSelect();
+
+ pl = (CList*)pw->SearchControl(EVENT_LIST2);
+ if ( pl == 0 ) return;
+ sel2 = pl->RetSelect();
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_FULL);
+ bFull = pc->TestState(STATE_CHECK);
+
+ if ( sel1 == m_setupSelDevice &&
+ sel2 == m_setupSelMode &&
+ bFull == m_setupFull )
+ {
+ pb->ClearState(STATE_ENABLE);
+ }
+ else
+ {
+ pb->SetState(STATE_ENABLE);
+ }
+}
+
+// Met à jour les boutons pendant la phase de setup.
+
+void CMainDialog::UpdateSetupButtons()
+{
+ CWindow* pw;
+ CCheck* pc;
+ CEditValue* pv;
+ CSlider* ps;
+ float value;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_TOTO);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetTotoMode());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_TOOLTIP);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bTooltip);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_GLINT);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bGlint);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_RAIN);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bRain);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_MOUSE);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetNiceMouse());
+ pc->SetState(STATE_ENABLE, m_engine->RetNiceMouseCap());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_EDITMODE);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetEditIndentMode());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_EDITVALUE);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetEditIndentValue()>2);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SOLUCE4);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bSoluce4);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_MOVIES);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bMovies);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_NICERST);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bNiceReset);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_HIMSELF);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bHimselfDamage);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SCROLL);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bCameraScroll);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_INVERTX);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bCameraInvertX);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_INVERTY);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bCameraInvertY);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_EFFECT);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_bEffect);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SHADOW);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetShadow());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_GROUND);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetGroundSpot());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_DIRTY);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetDirty());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_FOG);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetFog());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_LENS);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetLensMode());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SKY);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetSkyMode());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_PLANET);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetPlanetMode());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_LIGHT);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetLightMode());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_JOYSTICK);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_engine->RetJoystick());
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_PARTI);
+ if ( pv != 0 )
+ {
+ value = m_engine->RetParticuleDensity();
+ pv->SetValue(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_CLIP);
+ if ( pv != 0 )
+ {
+ value = m_engine->RetClippingDistance();
+ pv->SetValue(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_DETAIL);
+ if ( pv != 0 )
+ {
+ value = m_engine->RetObjectDetail();
+ pv->SetValue(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_GADGET);
+ if ( pv != 0 )
+ {
+ value = m_engine->RetGadgetQuantity();
+ pv->SetValue(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_TEXTURE);
+ if ( pv != 0 )
+ {
+ value = (float)m_engine->RetTextureQuality();
+ pv->SetValue(value);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_VOLSOUND);
+ if ( ps != 0 )
+ {
+ value = (float)m_sound->RetAudioVolume();
+ ps->SetVisibleValue(value);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_VOLMUSIC);
+ if ( ps != 0 )
+ {
+ value = (float)m_sound->RetMidiVolume();
+ ps->SetVisibleValue(value);
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_INTERFACE_SOUND3D);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_sound->RetSound3D());
+ pc->SetState(STATE_ENABLE, m_sound->RetSound3DCap());
+ }
+}
+
+// Met à jour le moteur en fonction des boutons après la phase de setup.
+
+void CMainDialog::ChangeSetupButtons()
+{
+ CWindow* pw;
+ CEditValue* pv;
+ CSlider* ps;
+ float value;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_PARTI);
+ if ( pv != 0 )
+ {
+ value = pv->RetValue();
+ m_engine->SetParticuleDensity(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_CLIP);
+ if ( pv != 0 )
+ {
+ value = pv->RetValue();
+ m_engine->SetClippingDistance(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_DETAIL);
+ if ( pv != 0 )
+ {
+ value = pv->RetValue();
+ m_engine->SetObjectDetail(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_GADGET);
+ if ( pv != 0 )
+ {
+ value = pv->RetValue();
+ m_engine->SetGadgetQuantity(value);
+ }
+
+ pv = (CEditValue*)pw->SearchControl(EVENT_INTERFACE_TEXTURE);
+ if ( pv != 0 )
+ {
+ value = pv->RetValue();
+ m_engine->SetTextureQuality((int)value);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_VOLSOUND);
+ if ( ps != 0 )
+ {
+ value = ps->RetVisibleValue();
+ m_sound->SetAudioVolume((int)value);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_INTERFACE_VOLMUSIC);
+ if ( ps != 0 )
+ {
+ value = ps->RetVisibleValue();
+ m_sound->SetMidiVolume((int)value);
+ }
+}
+
+
+// Mémorise tous les réglages.
+
+void CMainDialog::SetupMemorize()
+{
+ float fValue;
+ int iValue, i, j;
+ char key[500];
+ char num[10];
+
+ SetProfileString("Directory", "scene", m_sceneDir);
+ SetProfileString("Directory", "savegame", m_savegameDir);
+ SetProfileString("Directory", "public", m_publicDir);
+ SetProfileString("Directory", "user", m_userDir);
+ SetProfileString("Directory", "files", m_filesDir);
+
+ iValue = m_engine->RetTotoMode();
+ SetProfileInt("Setup", "TotoMode", iValue);
+
+ iValue = m_bTooltip;
+ SetProfileInt("Setup", "Tooltips", iValue);
+
+ iValue = m_bGlint;
+ SetProfileInt("Setup", "InterfaceGlint", iValue);
+
+ iValue = m_bRain;
+ SetProfileInt("Setup", "InterfaceGlint", iValue);
+
+ iValue = m_engine->RetNiceMouse();
+ SetProfileInt("Setup", "NiceMouse", iValue);
+
+ iValue = m_bSoluce4;
+ SetProfileInt("Setup", "Soluce4", iValue);
+
+ iValue = m_bMovies;
+ SetProfileInt("Setup", "Movies", iValue);
+
+ iValue = m_bNiceReset;
+ SetProfileInt("Setup", "NiceReset", iValue);
+
+ iValue = m_bHimselfDamage;
+ SetProfileInt("Setup", "HimselfDamage", iValue);
+
+ iValue = m_bCameraScroll;
+ SetProfileInt("Setup", "CameraScroll", iValue);
+
+ iValue = m_bCameraInvertX;
+ SetProfileInt("Setup", "CameraInvertX", iValue);
+
+ iValue = m_bEffect;
+ SetProfileInt("Setup", "InterfaceEffect", iValue);
+
+ iValue = m_engine->RetShadow();
+ SetProfileInt("Setup", "GroundShadow", iValue);
+
+ iValue = m_engine->RetGroundSpot();
+ SetProfileInt("Setup", "GroundSpot", iValue);
+
+ iValue = m_engine->RetDirty();
+ SetProfileInt("Setup", "ObjectDirty", iValue);
+
+ iValue = m_engine->RetFog();
+ SetProfileInt("Setup", "FogMode", iValue);
+
+ iValue = m_engine->RetLensMode();
+ SetProfileInt("Setup", "LensMode", iValue);
+
+ iValue = m_engine->RetSkyMode();
+ SetProfileInt("Setup", "SkyMode", iValue);
+
+ iValue = m_engine->RetPlanetMode();
+ SetProfileInt("Setup", "PlanetMode", iValue);
+
+ iValue = m_engine->RetLightMode();
+ SetProfileInt("Setup", "LightMode", iValue);
+
+ iValue = m_engine->RetJoystick();
+ SetProfileInt("Setup", "UseJoystick", iValue);
+
+ fValue = m_engine->RetParticuleDensity();
+ SetProfileFloat("Setup", "ParticuleDensity", fValue);
+
+ fValue = m_engine->RetClippingDistance();
+ SetProfileFloat("Setup", "ClippingDistance", fValue);
+
+ fValue = m_engine->RetObjectDetail();
+ SetProfileFloat("Setup", "ObjectDetail", fValue);
+
+ fValue = m_engine->RetGadgetQuantity();
+ SetProfileFloat("Setup", "GadgetQuantity", fValue);
+
+ iValue = m_engine->RetTextureQuality();
+ SetProfileInt("Setup", "TextureQuality", iValue);
+
+ iValue = m_sound->RetAudioVolume();
+ SetProfileInt("Setup", "AudioVolume", iValue);
+
+ iValue = m_sound->RetMidiVolume();
+ SetProfileInt("Setup", "MidiVolume", iValue);
+
+ iValue = m_sound->RetSound3D();
+ SetProfileInt("Setup", "Sound3D", iValue);
+
+ iValue = m_engine->RetEditIndentMode();
+ SetProfileInt("Setup", "EditIndentMode", iValue);
+
+ iValue = m_engine->RetEditIndentValue();
+ SetProfileInt("Setup", "EditIndentValue", iValue);
+
+ key[0] = 0;
+ for ( i=0 ; i<100 ; i++ )
+ {
+ if ( m_engine->RetKey(i, 0) == 0 ) break;
+
+ for ( j=0 ; j<2 ; j++ )
+ {
+ iValue = m_engine->RetKey(i, j);
+ sprintf(num, "%d%c", iValue, j==0?'+':' ');
+ strcat(key, num);
+ }
+ }
+ SetProfileString("Setup", "KeyMap", key);
+
+#if _NET
+ if ( m_accessEnable )
+ {
+ iValue = m_accessMission;
+ SetProfileInt("Setup", "AccessMission", iValue);
+
+ iValue = m_accessUser;
+ SetProfileInt("Setup", "AccessUser", iValue);
+ }
+#endif
+
+ iValue = m_bDeleteGamer;
+ SetProfileInt("Setup", "DeleteGamer", iValue);
+
+ m_engine->WriteProfile();
+}
+
+// Rappelle tous les réglages.
+
+void CMainDialog::SetupRecall()
+{
+ float fValue;
+ int iValue, i, j;
+ char key[500];
+ char* p;
+
+ if ( GetProfileString("Directory", "scene", key, _MAX_FNAME) )
+ {
+ strcpy(m_sceneDir, key);
+ }
+
+ if ( GetProfileString("Directory", "savegame", key, _MAX_FNAME) )
+ {
+ strcpy(m_savegameDir, key);
+ }
+
+ if ( GetProfileString("Directory", "public", key, _MAX_FNAME) )
+ {
+ strcpy(m_publicDir, key);
+ }
+
+ if ( GetProfileString("Directory", "user", key, _MAX_FNAME) )
+ {
+ strcpy(m_userDir, key);
+ }
+
+ if ( GetProfileString("Directory", "files", key, _MAX_FNAME) )
+ {
+ strcpy(m_filesDir, key);
+ }
+
+
+ if ( GetProfileInt("Setup", "TotoMode", iValue) )
+ {
+ m_engine->SetTotoMode(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "Tooltips", iValue) )
+ {
+ m_bTooltip = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "InterfaceGlint", iValue) )
+ {
+ m_bGlint = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "InterfaceGlint", iValue) )
+ {
+ m_bRain = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "NiceMouse", iValue) )
+ {
+ m_engine->SetNiceMouse(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "Soluce4", iValue) )
+ {
+ m_bSoluce4 = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "Movies", iValue) )
+ {
+ m_bMovies = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "NiceReset", iValue) )
+ {
+ m_bNiceReset = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "HimselfDamage", iValue) )
+ {
+ m_bHimselfDamage = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "CameraScroll", iValue) )
+ {
+ m_bCameraScroll = iValue;
+ m_camera->SetCameraScroll(m_bCameraScroll);
+ }
+
+ if ( GetProfileInt("Setup", "CameraInvertX", iValue) )
+ {
+ m_bCameraInvertX = iValue;
+ m_camera->SetCameraInvertX(m_bCameraInvertX);
+ }
+
+ if ( GetProfileInt("Setup", "CameraInvertY", iValue) )
+ {
+ m_bCameraInvertY = iValue;
+ m_camera->SetCameraInvertY(m_bCameraInvertY);
+ }
+
+ if ( GetProfileInt("Setup", "InterfaceEffect", iValue) )
+ {
+ m_bEffect = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "GroundShadow", iValue) )
+ {
+ m_engine->SetShadow(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "GroundSpot", iValue) )
+ {
+ m_engine->SetGroundSpot(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "ObjectDirty", iValue) )
+ {
+ m_engine->SetDirty(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "FogMode", iValue) )
+ {
+ m_engine->SetFog(iValue);
+ m_camera->SetOverBaseColor(RetColor(RetColor(0.0f)));
+ }
+
+ if ( GetProfileInt("Setup", "LensMode", iValue) )
+ {
+ m_engine->SetLensMode(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "SkyMode", iValue) )
+ {
+ m_engine->SetSkyMode(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "PlanetMode", iValue) )
+ {
+ m_engine->SetPlanetMode(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "LightMode", iValue) )
+ {
+ m_engine->SetLightMode(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "UseJoystick", iValue) )
+ {
+ m_engine->SetJoystick(iValue);
+ }
+
+ if ( GetProfileFloat("Setup", "ParticuleDensity", fValue) )
+ {
+ m_engine->SetParticuleDensity(fValue);
+ }
+
+ if ( GetProfileFloat("Setup", "ClippingDistance", fValue) )
+ {
+ m_engine->SetClippingDistance(fValue);
+ }
+
+ if ( GetProfileFloat("Setup", "ObjectDetail", fValue) )
+ {
+ m_engine->SetObjectDetail(fValue);
+ }
+
+ if ( GetProfileFloat("Setup", "GadgetQuantity", fValue) )
+ {
+ m_engine->SetGadgetQuantity(fValue);
+ }
+
+ if ( GetProfileInt("Setup", "TextureQuality", iValue) )
+ {
+ m_engine->SetTextureQuality(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "AudioVolume", iValue) )
+ {
+ m_sound->SetAudioVolume(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "MidiVolume", iValue) )
+ {
+ m_sound->SetMidiVolume(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "EditIndentMode", iValue) )
+ {
+ m_engine->SetEditIndentMode(iValue);
+ }
+
+ if ( GetProfileInt("Setup", "EditIndentValue", iValue) )
+ {
+ m_engine->SetEditIndentValue(iValue);
+ }
+
+ if ( GetProfileString("Setup", "KeyMap", key, 500) )
+ {
+ p = key;
+ for ( i=0 ; i<100 ; i++ )
+ {
+ if ( p[0] == 0 ) break;
+
+ for ( j=0 ; j<2 ; j++ )
+ {
+ sscanf(p, "%d", &iValue);
+ m_engine->SetKey(i, j, iValue);
+ while ( *p >= '0' && *p <= '9' ) p++;
+ while ( *p == ' ' || *p == '+' ) p++;
+ }
+ }
+ }
+
+#if _NET
+ if ( m_accessEnable )
+ {
+ if ( GetProfileInt("Setup", "AccessMission", iValue) )
+ {
+ m_accessMission = iValue;
+ }
+
+ if ( GetProfileInt("Setup", "AccessUser", iValue) )
+ {
+ m_accessUser = iValue;
+ }
+ }
+#endif
+
+ if ( GetProfileInt("Setup", "DeleteGamer", iValue) )
+ {
+ m_bDeleteGamer = iValue;
+ }
+}
+
+
+// Change le niveau général de qualité.
+
+void CMainDialog::ChangeSetupQuality(int quality)
+{
+ BOOL bEnable;
+ float value;
+ int iValue;
+
+ bEnable = (quality >= 0);
+ m_engine->SetShadow(bEnable);
+ m_engine->SetGroundSpot(bEnable);
+ m_engine->SetDirty(bEnable);
+ m_engine->SetFog(bEnable);
+ m_engine->SetLensMode(bEnable);
+ m_engine->SetSkyMode(bEnable);
+ m_engine->SetPlanetMode(bEnable);
+ m_engine->SetLightMode(bEnable);
+ m_camera->SetOverBaseColor(RetColor(RetColor(0.0f)));
+
+ if ( quality < 0 ) value = 0.0f;
+ if ( quality == 0 ) value = 1.0f;
+ if ( quality > 0 ) value = 2.0f;
+ m_engine->SetParticuleDensity(value);
+
+ if ( quality < 0 ) value = 0.5f;
+ if ( quality == 0 ) value = 1.0f;
+ if ( quality > 0 ) value = 2.0f;
+ m_engine->SetClippingDistance(value);
+
+ if ( quality < 0 ) value = 0.0f;
+ if ( quality == 0 ) value = 1.0f;
+ if ( quality > 0 ) value = 2.0f;
+ m_engine->SetObjectDetail(value);
+
+ if ( quality < 0 ) value = 0.5f;
+ if ( quality == 0 ) value = 1.0f;
+ if ( quality > 0 ) value = 1.0f;
+ m_engine->SetGadgetQuantity(value);
+
+ if ( quality < 0 ) iValue = 0;
+ if ( quality == 0 ) iValue = 1;
+ if ( quality > 0 ) iValue = 2;
+ m_engine->SetTextureQuality(iValue);
+
+ m_engine->FirstExecuteAdapt(FALSE);
+}
+
+
+// Touches redéfinissables :
+
+static int key_table[KEY_TOTAL] =
+{
+#if _SCHOOL & _TEEN
+ KEYRANK_LEFT,
+ KEYRANK_RIGHT,
+ KEYRANK_UP,
+ KEYRANK_DOWN,
+ KEYRANK_CAMERA,
+ KEYRANK_NEAR,
+ KEYRANK_AWAY,
+ KEYRANK_HELP,
+ KEYRANK_PROG,
+ KEYRANK_SPEED10,
+ KEYRANK_SPEED15,
+ KEYRANK_SPEED20,
+ KEYRANK_QUIT,
+#else
+ KEYRANK_LEFT,
+ KEYRANK_RIGHT,
+ KEYRANK_UP,
+ KEYRANK_DOWN,
+ KEYRANK_GUP,
+ KEYRANK_GDOWN,
+ KEYRANK_ACTION,
+ KEYRANK_CAMERA,
+ KEYRANK_VISIT,
+ KEYRANK_NEXT,
+ KEYRANK_HUMAN,
+ KEYRANK_DESEL,
+ KEYRANK_NEAR,
+ KEYRANK_AWAY,
+ KEYRANK_HELP,
+ KEYRANK_PROG,
+ KEYRANK_CBOT,
+ KEYRANK_SPEED10,
+ KEYRANK_SPEED15,
+ KEYRANK_SPEED20,
+ KEYRANK_QUIT,
+#endif
+};
+
+static EventMsg key_event[KEY_TOTAL] =
+{
+#if _SCHOOL & _TEEN
+ EVENT_INTERFACE_KLEFT,
+ EVENT_INTERFACE_KRIGHT,
+ EVENT_INTERFACE_KUP,
+ EVENT_INTERFACE_KDOWN,
+ EVENT_INTERFACE_KCAMERA,
+ EVENT_INTERFACE_KNEAR,
+ EVENT_INTERFACE_KAWAY,
+ EVENT_INTERFACE_KHELP,
+ EVENT_INTERFACE_KPROG,
+ EVENT_INTERFACE_KSPEED10,
+ EVENT_INTERFACE_KSPEED15,
+ EVENT_INTERFACE_KSPEED20,
+ EVENT_INTERFACE_KQUIT,
+#else
+ EVENT_INTERFACE_KLEFT,
+ EVENT_INTERFACE_KRIGHT,
+ EVENT_INTERFACE_KUP,
+ EVENT_INTERFACE_KDOWN,
+ EVENT_INTERFACE_KGUP,
+ EVENT_INTERFACE_KGDOWN,
+ EVENT_INTERFACE_KACTION,
+ EVENT_INTERFACE_KCAMERA,
+ EVENT_INTERFACE_KVISIT,
+ EVENT_INTERFACE_KNEXT,
+ EVENT_INTERFACE_KHUMAN,
+ EVENT_INTERFACE_KDESEL,
+ EVENT_INTERFACE_KNEAR,
+ EVENT_INTERFACE_KAWAY,
+ EVENT_INTERFACE_KHELP,
+ EVENT_INTERFACE_KPROG,
+ EVENT_INTERFACE_KCBOT,
+ EVENT_INTERFACE_KSPEED10,
+ EVENT_INTERFACE_KSPEED15,
+ EVENT_INTERFACE_KSPEED20,
+ EVENT_INTERFACE_KQUIT,
+#endif
+};
+
+// Met à jour la liste des touches.
+
+void CMainDialog::UpdateKey()
+{
+ CWindow* pw;
+ CScroll* ps;
+ CKey* pk;
+ FPOINT pos, dim;
+ int first, i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ ps = (CScroll*)pw->SearchControl(EVENT_INTERFACE_KSCROLL);
+ if ( ps == 0 ) return;
+
+ first = (int)(ps->RetVisibleValue()*(KEY_TOTAL-KEY_VISIBLE));
+
+ for ( i=0 ; i<KEY_TOTAL ; i++ )
+ {
+ pw->DeleteControl(key_event[i]);
+ }
+
+ dim.x = 400.0f/640.0f;
+ dim.y = 20.0f/480.0f;
+ pos.x = 110.0f/640.0f;
+ pos.y = 168.0f/480.0f + dim.y*(KEY_VISIBLE-1);
+ for ( i=0 ; i<KEY_VISIBLE ; i++ )
+ {
+ pw->CreateKey(pos, dim, -1, key_event[first+i]);
+ pk = (CKey*)pw->SearchControl(key_event[first+i]);
+ if ( pk == 0 ) break;
+ pk->SetKey(0, m_engine->RetKey(key_table[first+i], 0));
+ pk->SetKey(1, m_engine->RetKey(key_table[first+i], 1));
+ pos.y -= dim.y;
+ }
+}
+
+// Change une touche.
+
+void CMainDialog::ChangeKey(EventMsg event)
+{
+ CWindow* pw;
+ CScroll* ps;
+ CKey* pk;
+ int i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw == 0 ) return;
+
+ ps = (CScroll*)pw->SearchControl(EVENT_INTERFACE_KSCROLL);
+ if ( ps == 0 ) return;
+
+ for ( i=0 ; i<KEY_TOTAL ; i++ )
+ {
+ if ( key_event[i] == event )
+ {
+ pk = (CKey*)pw->SearchControl(key_event[i]);
+ if ( pk == 0 ) break;
+ m_engine->SetKey(key_table[i], 0, pk->RetKey(0));
+ m_engine->SetKey(key_table[i], 1, pk->RetKey(1));
+ }
+ }
+}
+
+
+
+// Voulez-vous quitter la mission en cours ?
+
+void CMainDialog::StartAbort()
+{
+ CWindow* pw;
+ CButton* pb;
+ FPOINT pos, dim;
+ char name[100];
+
+ StartDialog(FPOINT(0.3f, 0.8f), TRUE, FALSE, FALSE);
+ m_bDialogDelete = FALSE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+
+ pos.x = 0.35f;
+ pos.y = 0.60f;
+ dim.x = 0.30f;
+ dim.y = 0.30f;
+ pw->CreateGroup(pos, dim, 5, EVENT_INTERFACE_GLINTl); // coin orange
+ pos.x = 0.35f;
+ pos.y = 0.10f;
+ dim.x = 0.30f;
+ dim.y = 0.30f;
+ pw->CreateGroup(pos, dim, 4, EVENT_INTERFACE_GLINTr); // coin bleu
+
+ pos.x = 0.40f;
+ dim.x = 0.20f;
+#if _POLISH
+ pos.x -= 7.0f/640.0f;
+ dim.x += 14.0f/640.0f;
+#endif
+ dim.y = 32.0f/480.0f;
+
+ pos.y = 0.74f;
+ pb = pw->CreateButton(pos, dim, -1, EVENT_DIALOG_CANCEL);
+ pb->SetState(STATE_SHADOW);
+ GetResource(RES_TEXT, RT_DIALOG_NO, name);
+ pb->SetName(name);
+
+ if ( m_index == 2 || // missions ?
+ m_index == 3 || // jeux libres ?
+ m_index == 4 ) // user ?
+ {
+ pos.y = 0.62f;
+ pb = pw->CreateButton(pos, dim, -1, EVENT_INTERFACE_WRITE);
+ pb->SetState(STATE_SHADOW);
+ if ( m_main->IsBusy() ) // tâche en cours ?
+ {
+ pb->ClearState(STATE_ENABLE);
+ }
+
+ pos.y = 0.53f;
+ pb = pw->CreateButton(pos, dim, -1, EVENT_INTERFACE_READ);
+ pb->SetState(STATE_SHADOW);
+ if ( !IsIOReadScene() ) // aucun fichier à lire ?
+ {
+ pb->ClearState(STATE_ENABLE);
+ }
+ pb->SetState(STATE_WARNING);
+ }
+
+ if ( m_engine->RetSetupMode() )
+ {
+ pos.y = 0.39f;
+ pb = pw->CreateButton(pos, dim, -1, EVENT_INTERFACE_SETUP);
+ pb->SetState(STATE_SHADOW);
+ }
+
+ pos.y = 0.25f;
+ pb = pw->CreateButton(pos, dim, -1, EVENT_INTERFACE_AGAIN);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_WARNING);
+
+ pos.y = 0.16f;
+ pb = pw->CreateButton(pos, dim, -1, EVENT_DIALOG_OK);
+ pb->SetState(STATE_SHADOW);
+ pb->SetState(STATE_WARNING);
+ GetResource(RES_TEXT, RT_DIALOG_YES, name);
+ pb->SetName(name);
+}
+
+// Voulez-vous détruire le bâtiment ?
+
+void CMainDialog::StartDeleteObject()
+{
+ CWindow* pw;
+ CButton* pb;
+ FPOINT pos, dim;
+ char name[100];
+
+ StartDialog(FPOINT(0.7f, 0.3f), FALSE, TRUE, TRUE);
+ m_bDialogDelete = TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+
+ pos.x = 0.00f;
+ pos.y = 0.50f;
+ dim.x = 1.00f;
+ dim.y = 0.05f;
+ GetResource(RES_TEXT, RT_DIALOG_DELOBJ, name);
+ pw->CreateLabel(pos, dim, -1, EVENT_DIALOG_LABEL, name);
+
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_OK);
+ if ( pb == 0 ) return;
+ GetResource(RES_TEXT, RT_DIALOG_YESDEL, name);
+ pb->SetName(name);
+ pb->SetState(STATE_WARNING);
+
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_CANCEL);
+ if ( pb == 0 ) return;
+ GetResource(RES_TEXT, RT_DIALOG_NODEL, name);
+ pb->SetName(name);
+}
+
+// Voulez-vous détruire le joueur ?
+
+void CMainDialog::StartDeleteGame(char *gamer)
+{
+ CWindow* pw;
+ CButton* pb;
+ FPOINT pos, dim;
+ char name[100];
+ char text[100];
+
+ StartDialog(FPOINT(0.7f, 0.3f), FALSE, TRUE, TRUE);
+ m_bDialogDelete = TRUE;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+
+ pos.x = 0.00f;
+ pos.y = 0.50f;
+ dim.x = 1.00f;
+ dim.y = 0.05f;
+ GetResource(RES_TEXT, RT_DIALOG_DELGAME, name);
+ sprintf(text, name, gamer);
+ pw->CreateLabel(pos, dim, -1, EVENT_DIALOG_LABEL, text);
+
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_OK);
+ if ( pb == 0 ) return;
+ GetResource(RES_TEXT, RT_DIALOG_YESDEL, name);
+ pb->SetName(name);
+ pb->SetState(STATE_WARNING);
+
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_CANCEL);
+ if ( pb == 0 ) return;
+ GetResource(RES_TEXT, RT_DIALOG_NODEL, name);
+ pb->SetName(name);
+}
+
+// Voulez-vous quitter le jeu ?
+
+void CMainDialog::StartQuit()
+{
+ CWindow* pw;
+ CButton* pb;
+ FPOINT pos, dim;
+ char name[100];
+
+ StartDialog(FPOINT(0.6f, 0.3f), FALSE, TRUE, TRUE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+
+ pos.x = 0.00f;
+ pos.y = 0.50f;
+ dim.x = 1.00f;
+ dim.y = 0.05f;
+ GetResource(RES_TEXT, RT_DIALOG_QUIT, name);
+ pw->CreateLabel(pos, dim, -1, EVENT_DIALOG_LABEL, name);
+
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_OK);
+ if ( pb == 0 ) return;
+ GetResource(RES_TEXT, RT_DIALOG_YESQUIT, name);
+ pb->SetName(name);
+ pb->SetState(STATE_WARNING);
+
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_CANCEL);
+ if ( pb == 0 ) return;
+ GetResource(RES_TEXT, RT_DIALOG_NOQUIT, name);
+ pb->SetName(name);
+}
+
+// Début de l'affichage d'un dialogue.
+
+void CMainDialog::StartDialog(FPOINT dim, BOOL bFire, BOOL bOK, BOOL bCancel)
+{
+ CWindow* pw;
+ CButton* pb;
+ FPOINT pos, ddim;
+ char name[100];
+
+ StartSuspend();
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW6);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW7);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW8);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pb = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( pb != 0 )
+ {
+ pb->ClearState(STATE_VISIBLE);
+ }
+
+ m_bDialogFire = bFire;
+
+ pos.x = (1.0f-dim.x)/2.0f;
+ pos.y = (1.0f-dim.y)/2.0f;
+ pw = m_interface->CreateWindows(pos, dim, bFire?12:8, EVENT_WINDOW9);
+ pw->SetState(STATE_SHADOW);
+ GetResource(RES_TEXT, RT_TITLE_BASE, name);
+ pw->SetName(name);
+
+ m_dialogPos = pos;
+ m_dialogDim = dim;
+ m_dialogTime = 0.0f;
+ m_dialogParti = 999.0f;
+
+ if ( bOK )
+ {
+ pos.x = 0.50f-0.15f-0.02f;
+ pos.y = 0.50f-dim.y/2.0f+0.03f;
+ ddim.x = 0.15f;
+ ddim.y = 0.06f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_DIALOG_OK);
+ pb->SetState(STATE_SHADOW);
+ GetResource(RES_EVENT, EVENT_DIALOG_OK, name);
+ pb->SetName(name);
+ }
+
+ if ( bCancel )
+ {
+ pos.x = 0.50f+0.02f;
+ pos.y = 0.50f-dim.y/2.0f+0.03f;
+ ddim.x = 0.15f;
+ ddim.y = 0.06f;
+ pb = pw->CreateButton(pos, ddim, -1, EVENT_DIALOG_CANCEL);
+ pb->SetState(STATE_SHADOW);
+ GetResource(RES_EVENT, EVENT_DIALOG_CANCEL, name);
+ pb->SetName(name);
+ }
+
+ m_sound->Play(SOUND_TZOING);
+ m_bDialog = TRUE;
+}
+
+// Animation d'un dialogue.
+
+void CMainDialog::FrameDialog(float rTime)
+{
+ CWindow* pw;
+ D3DVECTOR pos, speed;
+ FPOINT dim, dpos, ddim;
+ float zoom;
+ int i;
+
+ dpos = m_dialogPos;
+ ddim = m_dialogDim;
+
+ m_dialogTime += rTime;
+ if ( m_dialogTime < 1.0f )
+ {
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw != 0 )
+ {
+ if ( m_dialogTime < 0.50f )
+ {
+ zoom = Bounce(m_dialogTime/0.50f);
+ }
+ else
+ {
+ zoom = 1.0f;
+ }
+
+ dpos.x += ddim.x/2.0f;
+ dpos.y += ddim.y/2.0f;
+
+ ddim.x *= zoom;
+//? ddim.y *= zoom;
+
+ dpos.x -= ddim.x/2.0f;
+ dpos.y -= ddim.y/2.0f;
+
+ pw->SetPos(dpos);
+ pw->SetDim(ddim);
+ }
+ }
+
+ if ( !m_bGlint ) return;
+
+ m_dialogParti += rTime;
+ if ( m_dialogParti < m_engine->ParticuleAdapt(0.05f) ) return;
+ m_dialogParti = 0.0f;
+
+ if ( !m_bDialogFire ) return;
+
+ dpos = m_dialogPos;
+ ddim = m_dialogDim;
+
+ pos.z = 0.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ for ( i=0 ; i<2 ; i++ )
+ {
+ // En bas.
+ pos.x = dpos.x + ddim.x*Rand();
+ pos.y = dpos.y;
+ pos.x += (Rand()-0.5f)*(6.0f/640.0f);
+ pos.y += Rand()*(16.0f/480.0f)-(10.0f/480.0f);
+ dim.x = 0.01f+Rand()*0.01f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%3),
+ 1.0f, 0.0f, 0.0f, SH_INTERFACE);
+
+ // En haut.
+ pos.x = dpos.x + ddim.x*Rand();
+ pos.y = dpos.y + ddim.y;
+ pos.x += (Rand()-0.5f)*(6.0f/640.0f);
+ pos.y -= Rand()*(16.0f/480.0f)-(10.0f/480.0f);
+ dim.x = 0.01f+Rand()*0.01f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%3),
+ 1.0f, 0.0f, 0.0f, SH_INTERFACE);
+
+ // A gauche.
+ pos.y = dpos.y + ddim.y*Rand();
+ pos.x = dpos.x;
+ pos.x += Rand()*(16.0f/640.0f)-(10.0f/640.0f);
+ pos.y += (Rand()-0.5f)*(6.0f/480.0f);
+ dim.x = 0.01f+Rand()*0.01f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%3),
+ 1.0f, 0.0f, 0.0f, SH_INTERFACE);
+
+ // A droite.
+ pos.y = dpos.y + ddim.y*Rand();
+ pos.x = dpos.x + ddim.x;
+ pos.x -= Rand()*(16.0f/640.0f)-(10.0f/640.0f);
+ pos.y += (Rand()-0.5f)*(6.0f/480.0f);
+ dim.x = 0.01f+Rand()*0.01f;
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%3),
+ 1.0f, 0.0f, 0.0f, SH_INTERFACE);
+ }
+}
+
+// Fin de l'affichage d'un dialogue.
+
+void CMainDialog::StopDialog()
+{
+ CWindow* pw;
+ CButton* pb;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW6);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW7);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW8);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pb = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_VISIBLE);
+ }
+
+ StopSuspend();
+ m_interface->DeleteControl(EVENT_WINDOW9);
+ m_bDialog = FALSE;
+}
+
+// Suspend la simulation pour une phase de dialogue.
+
+void CMainDialog::StartSuspend()
+{
+ m_sound->MuteAll(TRUE);
+ m_main->ClearInterface();
+ m_bInitPause = m_engine->RetPause();
+ m_engine->SetPause(TRUE);
+ m_engine->SetOverFront(FALSE); // over plane derrière
+ m_main->CreateShortcuts();
+ m_main->StartSuspend();
+ m_initCamera = m_camera->RetType();
+ m_camera->SetType(CAMERA_DIALOG);
+}
+
+// Reprend la simulation après une phase de dialogue.
+
+void CMainDialog::StopSuspend()
+{
+ m_sound->MuteAll(FALSE);
+ m_main->ClearInterface();
+ if ( !m_bInitPause ) m_engine->SetPause(FALSE);
+ m_engine->SetOverFront(TRUE); // over plane devant
+ m_main->CreateShortcuts();
+ m_main->StopSuspend();
+ m_camera->SetType(m_initCamera);
+}
+
+
+// Indique s'il faut utiliser les tooltips.
+
+BOOL CMainDialog::RetTooltip()
+{
+ return m_bTooltip;
+}
+
+// Indique si un dialogue est affiché.
+
+BOOL CMainDialog::IsDialog()
+{
+ return m_bDialog;
+}
+
+
+
+
+// Spécifie le nom de la scène à lire.
+
+void CMainDialog::SetSceneRead(char* name)
+{
+ strcpy(m_sceneRead, name);
+}
+
+// Retourne le nom de la scène à lire.
+
+char* CMainDialog::RetSceneRead()
+{
+ return m_sceneRead;
+}
+
+// Spécifie le nom de la scène à lire.
+
+void CMainDialog::SetStackRead(char* name)
+{
+ strcpy(m_stackRead, name);
+}
+
+// Retourne le nom de la scène à lire.
+
+char* CMainDialog::RetStackRead()
+{
+ return m_stackRead;
+}
+
+// Spécifie le nom de la scène choisie pour jouer.
+
+void CMainDialog::SetSceneName(char* name)
+{
+ strcpy(m_sceneName, name);
+}
+
+// Retourne le nom de la scène choisie pour jouer.
+
+char* CMainDialog::RetSceneName()
+{
+ return m_sceneName;
+}
+
+// Spécifie le rang de la scène choisie pour jouer.
+
+void CMainDialog::SetSceneRank(int rank)
+{
+ m_sceneRank = rank;
+}
+
+// Retourne le rang de la scène choisie pour jouer.
+
+int CMainDialog::RetSceneRank()
+{
+ return m_sceneRank;
+}
+
+// Retourne nom de dossier de la scène utilisateur choisie pour jouer.
+
+char* CMainDialog::RetSceneDir()
+{
+ int i;
+
+ i = (m_sceneRank/100)-1;
+
+ if ( i < 0 || i >= m_userTotal ) return 0;
+ return m_userList[i];
+}
+
+// Indique s'il faut montrer la solution.
+
+BOOL CMainDialog::RetSceneSoluce()
+{
+ return m_bSceneSoluce;
+}
+
+// Retourne le nom du dossier pour sauvegarder.
+
+char* CMainDialog::RetSavegameDir()
+{
+ return m_savegameDir;
+}
+
+// Retourne le nom du dossier public.
+
+char* CMainDialog::RetPublicDir()
+{
+ return m_publicDir;
+}
+
+
+// Indique s'il y a des reflets sur les boutons.
+
+BOOL CMainDialog::RetGlint()
+{
+ return m_bGlint;
+}
+
+// Indique s'il faut montrer les 4:solutions.
+
+BOOL CMainDialog::RetSoluce4()
+{
+ return m_bSoluce4;
+}
+
+// Indique s'il faut montrer les cinématiques.
+
+BOOL CMainDialog::RetMovies()
+{
+ return m_bMovies;
+}
+
+// Indique s'il faut faire une animation dans CTaskReset.
+
+BOOL CMainDialog::RetNiceReset()
+{
+ return m_bNiceReset;
+}
+
+// Indique si les tirs provoquent des dommages à ses propres unités.
+
+BOOL CMainDialog::RetHimselfDamage()
+{
+ return m_bHimselfDamage;
+}
+
+
+
+// Enregistre la représentation personnalisée du joueur.
+
+void CMainDialog::WriteGamerPerso(char *gamer)
+{
+ FILE* file;
+ char filename[100];
+ char line[100];
+
+ sprintf(filename, "%s\\%s\\face.gam", m_savegameDir, gamer);
+ file = fopen(filename, "w");
+ if ( file == NULL ) return;
+
+ sprintf(line, "Head face=%d glasses=%d hair=%.2f;%.2f;%.2f;%.2f\n",
+ m_perso.face, m_perso.glasses,
+ m_perso.colorHair.r, m_perso.colorHair.g, m_perso.colorHair.b, m_perso.colorHair.a);
+ fputs(line, file);
+
+ sprintf(line, "Body combi=%.2f;%.2f;%.2f;%.2f band=%.2f;%.2f;%.2f;%.2f\n",
+ m_perso.colorCombi.r, m_perso.colorCombi.g, m_perso.colorCombi.b, m_perso.colorCombi.a,
+ m_perso.colorBand.r, m_perso.colorBand.g, m_perso.colorBand.b, m_perso.colorBand.a);
+ fputs(line, file);
+
+ fclose(file);
+}
+
+// Lit la représentation personnalisée du joueur.
+
+void CMainDialog::ReadGamerPerso(char *gamer)
+{
+ FILE* file;
+ char filename[100];
+ char line[100];
+ D3DCOLORVALUE color;
+
+ m_perso.face = 0;
+ DefPerso();
+
+ sprintf(filename, "%s\\%s\\face.gam", m_savegameDir, gamer);
+ file = fopen(filename, "r");
+ if ( file == NULL ) return;
+
+ while ( fgets(line, 100, file) != NULL )
+ {
+ if ( Cmd(line, "Head") )
+ {
+ m_perso.face = OpInt(line, "face", 0);
+ m_perso.glasses = OpInt(line, "glasses", 0);
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ color.a = 0.0f;
+ m_perso.colorHair = OpColorValue(line, "hair", color);
+ }
+
+ if ( Cmd(line, "Body") )
+ {
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ color.a = 0.0f;
+ m_perso.colorCombi = OpColorValue(line, "combi", color);
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ color.a = 0.0f;
+ m_perso.colorBand = OpColorValue(line, "band", color);
+ }
+ }
+
+ fclose(file);
+}
+
+// Spécifie la représentation du joueur.
+
+void CMainDialog::SetGamerFace(char *gamer, int face)
+{
+ m_perso.face = face;
+ WriteGamerPerso(gamer);
+}
+
+// Donne la représentation du joueur.
+
+int CMainDialog::RetGamerFace(char *gamer)
+{
+ ReadGamerPerso(gamer);
+ return m_perso.face;
+}
+
+// Donne la représentation du joueur.
+
+int CMainDialog::RetGamerFace()
+{
+ return m_perso.face;
+}
+
+int CMainDialog::RetGamerGlasses()
+{
+ return m_perso.glasses;
+}
+
+BOOL CMainDialog::RetGamerOnlyHead()
+{
+ return (m_phase == PHASE_PERSO && m_persoTab == 0);
+}
+
+float CMainDialog::RetPersoAngle()
+{
+ return m_persoAngle;
+}
+
+D3DCOLORVALUE CMainDialog::RetGamerColorHair()
+{
+ return m_perso.colorHair;
+}
+
+D3DCOLORVALUE CMainDialog::RetGamerColorCombi()
+{
+ return m_perso.colorCombi;
+}
+
+D3DCOLORVALUE CMainDialog::RetGamerColorBand()
+{
+ return m_perso.colorBand;
+}
+
+
+// Lit le fichier du joueur.
+
+BOOL CMainDialog::ReadGamerInfo()
+{
+ FILE* file;
+ char line[100];
+ int chap, i, numTry, passed;
+
+ for ( i=0 ; i<MAXSCENE ; i++ )
+ {
+ m_sceneInfo[i].numTry = 0;
+ m_sceneInfo[i].bPassed = FALSE;
+ }
+
+ sprintf(line, "%s\\%s\\%s.gam", m_savegameDir, m_main->RetGamerName(), m_sceneName);
+ file = fopen(line, "r");
+ if ( file == NULL ) return FALSE;
+
+ if ( fgets(line, 100, file) != NULL )
+ {
+ sscanf(line, "CurrentChapter=%d CurrentSel=%d\n", &chap, &i);
+ m_chap[m_index] = chap-1;
+ m_sel[m_index] = i-1;
+ }
+
+ while ( fgets(line, 100, file) != NULL )
+ {
+ sscanf(line, "Chapter %d: Scene %d: numTry=%d passed=%d\n",
+ &chap, &i, &numTry, &passed);
+
+ i += chap*100;
+ if ( i >= 0 && i < MAXSCENE )
+ {
+ m_sceneInfo[i].numTry = numTry;
+ m_sceneInfo[i].bPassed = passed;
+ }
+ }
+
+ fclose(file);
+ return TRUE;
+}
+
+// Ecrit le fichier du joueur.
+
+BOOL CMainDialog::WriteGamerInfo()
+{
+ FILE* file;
+ char line[100];
+ int i;
+
+ sprintf(line, "%s\\%s\\%s.gam", m_savegameDir, m_main->RetGamerName(), m_sceneName);
+ file = fopen(line, "w");
+ if ( file == NULL ) return FALSE;
+
+ sprintf(line, "CurrentChapter=%d CurrentSel=%d\n",
+ m_chap[m_index]+1, m_sel[m_index]+1);
+ fputs(line, file);
+
+ for ( i=0 ; i<MAXSCENE ; i++ )
+ {
+ if ( m_sceneInfo[i].numTry == 0 ) continue;
+
+ sprintf(line, "Chapter %d: Scene %d: numTry=%d passed=%d\n",
+ i/100, i%100, m_sceneInfo[i].numTry, m_sceneInfo[i].bPassed);
+ fputs(line, file);
+ }
+
+ fclose(file);
+ return TRUE;
+}
+
+void CMainDialog::SetGamerInfoTry(int rank, int numTry)
+{
+ if ( rank < 0 || rank >= MAXSCENE ) return;
+ if ( numTry > 100 ) numTry = 100;
+ m_sceneInfo[rank].numTry = numTry;
+}
+
+int CMainDialog::RetGamerInfoTry(int rank)
+{
+ if ( rank < 0 || rank >= MAXSCENE ) return 0;
+ return m_sceneInfo[rank].numTry;
+}
+
+void CMainDialog::SetGamerInfoPassed(int rank, BOOL bPassed)
+{
+ int chap, i;
+ BOOL bAll;
+
+ if ( rank < 0 || rank >= MAXSCENE ) return;
+ m_sceneInfo[rank].bPassed = bPassed;
+
+ if ( bPassed )
+ {
+ bAll = TRUE;
+ chap = rank/100;
+ for ( i=0 ; i<m_maxList ; i++ )
+ {
+ bAll &= m_sceneInfo[chap*100+i+1].bPassed;
+ }
+ m_sceneInfo[chap*100].numTry ++;
+ m_sceneInfo[chap*100].bPassed = bAll;
+ }
+}
+
+BOOL CMainDialog::RetGamerInfoPassed(int rank)
+{
+ if ( rank < 0 || rank >= MAXSCENE ) return FALSE;
+ return m_sceneInfo[rank].bPassed;
+}
+
+
+// Passe à la misison suivante, et éventuellement au chapitre suivant.
+
+BOOL CMainDialog::NextMission()
+{
+ m_sel[m_index] ++; // mission suivante
+
+ if ( m_sel[m_index] >= m_maxList ) // dernière mission du chapitre ?
+ {
+ m_chap[m_index] ++; // chapitre suivant
+ m_sel[m_index] = 0; // première mission
+ }
+
+ return TRUE;
+}
+
+
diff --git a/src/maindialog.h b/src/maindialog.h
new file mode 100644
index 0000000..2471964
--- /dev/null
+++ b/src/maindialog.h
@@ -0,0 +1,242 @@
+// maindialog.h
+
+#ifndef _MAINDIALOG_H_
+#define _MAINDIALOG_H_
+
+
+
+class CInstanceManager;
+class CRobotMain;
+class CEvent;
+class CD3DEngine;
+class CInterface;
+class CWindow;
+class CControl;
+class CParticule;
+class CCamera;
+class CSound;
+
+enum Phase;
+enum CameraType;
+
+
+#define USERLISTMAX 100
+#define MAXSCENE 1000
+
+typedef struct
+{
+ char numTry;
+ char bPassed;
+}
+SceneInfo;
+
+typedef struct
+{
+ int face; // visage
+ int glasses; // lunettes
+ D3DCOLORVALUE colorHair; // couleur cheveux
+ D3DCOLORVALUE colorCombi; // couleur combinaison
+ D3DCOLORVALUE colorBand; // couleur bandes
+}
+GamerPerso;
+
+
+
+class CMainDialog
+{
+public:
+ CMainDialog(CInstanceManager* iMan);
+ ~CMainDialog();
+
+ BOOL EventProcess(const Event &event);
+ void ChangePhase(Phase phase);
+
+ void SetSceneRead(char* name);
+ void SetStackRead(char* name);
+ void SetSceneName(char* name);
+ void SetSceneRank(int rank);
+ char* RetSceneRead();
+ char* RetStackRead();
+ char* RetSceneName();
+ int RetSceneRank();
+ char* RetSceneDir();
+ BOOL RetSceneSoluce();
+ char* RetSavegameDir();
+ char* RetPublicDir();
+
+ BOOL RetTooltip();
+ BOOL RetGlint();
+ BOOL RetSoluce4();
+ BOOL RetMovies();
+ BOOL RetNiceReset();
+ BOOL RetHimselfDamage();
+
+ void SetUserDir(char *base, int rank);
+ void BuildSceneName(char *filename, char *base, int rank);
+ void BuildResumeName(char *filename, char *base, int rank);
+ char* RetFilesDir();
+
+ void StartAbort();
+ void StartDeleteObject();
+ void StartDeleteGame(char *gamer);
+ void StartQuit();
+ void StartDialog(FPOINT dim, BOOL bFire, BOOL bOK, BOOL bCancel);
+ void FrameDialog(float rTime);
+ void StopDialog();
+ BOOL IsDialog();
+
+ void StartSuspend();
+ void StopSuspend();
+
+ void SetupMemorize();
+ void SetupRecall();
+
+ BOOL ReadGamerInfo();
+ BOOL WriteGamerInfo();
+ void SetGamerInfoTry(int rank, int numTry);
+ int RetGamerInfoTry(int rank);
+ void SetGamerInfoPassed(int rank, BOOL bPassed);
+ BOOL RetGamerInfoPassed(int rank);
+ BOOL NextMission();
+
+ void WriteGamerPerso(char *gamer);
+ void ReadGamerPerso(char *gamer);
+ void SetGamerFace(char *gamer, int face);
+ int RetGamerFace(char *gamer);
+ int RetGamerFace();
+ int RetGamerGlasses();
+ BOOL RetGamerOnlyHead();
+ float RetPersoAngle();
+ D3DCOLORVALUE RetGamerColorHair();
+ D3DCOLORVALUE RetGamerColorCombi();
+ D3DCOLORVALUE RetGamerColorBand();
+
+ void AllMissionUpdate();
+ void ShowSoluceUpdate();
+
+protected:
+ void GlintMove();
+ void FrameParticule(float rTime);
+ void NiceParticule(FPOINT mouse, BOOL bPress);
+ void ReadNameList();
+ void UpdateNameList();
+ void UpdateNameEdit();
+ void UpdateNameControl();
+ void UpdateNameFace();
+ void NameSelect();
+ void NameCreate();
+ void NameDelete();
+ void UpdatePerso();
+ void CameraPerso();
+ void FixPerso(int rank, int index);
+ void ColorPerso();
+ void DefPerso();
+ BOOL IsIOReadScene();
+ void IOReadName();
+ void IOReadList();
+ void IOUpdateList();
+ void IODeleteScene();
+ BOOL IOWriteScene();
+ BOOL IOReadScene();
+ int RetChapPassed();
+ void UpdateSceneChap(int &chap);
+ void UpdateSceneList(int chap, int &sel);
+ void UpdateSceneResume(int rank);
+ void UpdateDisplayDevice();
+ void UpdateDisplayMode();
+ void ChangeDisplay();
+ void UpdateApply();
+ void UpdateSetupButtons();
+ void ChangeSetupButtons();
+ void ChangeSetupQuality(int quality);
+ void UpdateKey();
+ void ChangeKey(EventMsg event);
+
+protected:
+ CInstanceManager* m_iMan;
+ CRobotMain* m_main;
+ CEvent* m_event;
+ CD3DEngine* m_engine;
+ CInterface* m_interface;
+ CParticule* m_particule;
+ CCamera* m_camera;
+ CSound* m_sound;
+
+ Phase m_phase; // copie de CRobotMain
+ Phase m_phaseSetup; // onglet choisi
+ Phase m_phaseTerm; // phase trainer/scene/proto
+ float m_phaseTime;
+
+ GamerPerso m_perso; // perso: description
+ GamerPerso m_persoCopy; // perso: copie pour annulation
+ int m_persoTab; // perso: onglet choisi
+ float m_persoAngle; // perso: angle de présentation
+
+ char m_sceneDir[_MAX_FNAME]; // dossier scene\
+ char m_savegameDir[_MAX_FNAME]; // dossier savegame\
+ char m_publicDir[_MAX_FNAME]; // dossier program\
+ char m_userDir[_MAX_FNAME]; // dossier user\
+ char m_filesDir[_MAX_FNAME]; // dossier files\
+
+ int m_index; // 0..4
+ int m_chap[10]; // chapitre choisi (0..8)
+ int m_sel[10]; // mission choisie (0..98)
+ int m_maxList;
+ int m_accessChap;
+ char m_sceneRead[100]; // nom de la scène à lire
+ char m_stackRead[100]; // nom de la scène à lire
+ char m_sceneName[20]; // nom de la scène à jouer
+ int m_sceneRank; // rang de la scène à jouer
+ BOOL m_bSceneSoluce; // montre la solution
+ BOOL m_bSimulSetup; // réglages pendant le jeu
+ BOOL m_accessEnable;
+ BOOL m_accessMission;
+ BOOL m_accessUser;
+ BOOL m_bDeleteGamer;
+
+ int m_userTotal;
+ char m_userList[USERLISTMAX][100];
+
+ int m_shotDelay; // nb de frames avant copie
+ char m_shotName[100]; // nom du fichier à générer
+
+ int m_setupSelDevice;
+ int m_setupSelMode;
+ BOOL m_setupFull;
+
+ BOOL m_bTooltip; // info-bulles à afficher ?
+ BOOL m_bGlint; // reflets sur boutons ?
+ BOOL m_bRain; // pluie dans l'interface ?
+ BOOL m_bSoluce4; // solutions dans programme 4 ?
+ BOOL m_bMovies; // cinématiques ?
+ BOOL m_bNiceReset; // pour CTaskReset
+ BOOL m_bHimselfDamage; // pour les tirs
+ BOOL m_bCameraScroll; // pour CCamera
+ BOOL m_bCameraInvertX; // pour CCamera
+ BOOL m_bCameraInvertY; // pour CCamera
+ BOOL m_bEffect; // pour CCamera
+
+ FPOINT m_glintMouse;
+ float m_glintTime;
+
+ int m_loadingCounter;
+
+ BOOL m_bDialog; // dialogue présent ?
+ BOOL m_bDialogFire; // cadre en feu ?
+ BOOL m_bDialogDelete;
+ FPOINT m_dialogPos;
+ FPOINT m_dialogDim;
+ float m_dialogParti;
+ float m_dialogTime;
+ BOOL m_bInitPause;
+ CameraType m_initCamera;
+
+ int m_partiPhase[10];
+ float m_partiTime[10];
+ FPOINT m_partiPos[10];
+
+ SceneInfo m_sceneInfo[MAXSCENE];
+};
+
+
+#endif //_MAINDIALOG_H_
diff --git a/src/mainmap.cpp b/src/mainmap.cpp
new file mode 100644
index 0000000..eed4c97
--- /dev/null
+++ b/src/mainmap.cpp
@@ -0,0 +1,388 @@
+// mainmap.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "iman.h"
+#include "interface.h"
+#include "map.h"
+#include "image.h"
+#include "group.h"
+#include "slider.h"
+#include "scroll.h"
+#include "window.h"
+#include "mainmap.h"
+
+
+
+#define ZOOM_MIN 1.0f
+#define ZOOM_MAX 16.0f
+
+
+
+// Constructeur de l'application carte.
+
+CMainMap::CMainMap(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_MAP, this);
+
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+
+ m_mapMode = 1;
+ m_bFixImage = FALSE;
+}
+
+// Destructeur de l'application robot.
+
+CMainMap::~CMainMap()
+{
+}
+
+
+// Crée la mini-carte et les boutons correspondants.
+
+void CMainMap::CreateMap()
+{
+ CWindow* pw;
+ FPOINT pos, dim;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 )
+ {
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ dim.x = 0.0f;
+ dim.y = 0.0f;
+ pw = m_interface->CreateWindows(pos, dim, 10, EVENT_WINDOW1);
+ }
+
+ dim.x = 10.0f/640.0f;
+ dim.y = 10.0f/480.0f;
+ pos.x = 10.0f/640.0f;
+ pos.y = 10.0f/480.0f;
+ pw->CreateMap (pos, dim, 2, EVENT_OBJECT_MAP);
+ pw->CreateSlider(pos, dim, 0, EVENT_OBJECT_MAPZOOM);
+
+ DimMap();
+}
+
+// Indique si la mini-carte doit afficher une image fixe.
+
+void CMainMap::SetFixImage(char *filename)
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return;
+
+ pw->DeleteControl(EVENT_OBJECT_MAPZOOM);
+ m_bFixImage = TRUE;
+
+ pm->SetFixImage(filename);
+}
+
+// Choix des couleurs du sol et de l'eau pour la mini-carte.
+
+void CMainMap::FloorColorMap(D3DCOLORVALUE floor, D3DCOLORVALUE water)
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm != 0 )
+ {
+ pm->SetFloorColor(floor);
+ pm->SetWaterColor(water);
+ }
+}
+
+// Montre ou cache la mini-carte.
+
+void CMainMap::ShowMap(BOOL bShow)
+{
+ CWindow* pw;
+ CMap* pm;
+ CSlider* ps;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ if ( bShow )
+ {
+ DimMap();
+ }
+ else
+ {
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm != 0 )
+ {
+ pm->ClearState(STATE_VISIBLE);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_MAPZOOM);
+ if ( ps != 0 )
+ {
+ ps->ClearState(STATE_VISIBLE);
+ }
+ }
+}
+
+// Dimensions de la mini-carte.
+
+void CMainMap::DimMap()
+{
+ CWindow* pw;
+ CMap* pm;
+ CSlider* ps;
+ FPOINT pos, dim;
+ float value;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return;
+
+ pm->SetState(STATE_VISIBLE, (m_mapMode != 0));
+
+ dim.x = 100.0f/640.0f;
+ dim.y = 100.0f/480.0f;
+ pos.x = 540.0f/640.0f;
+ pos.y = 0.0f/480.0f;
+ pm->SetPos(pos);
+ pm->SetDim(dim);
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_MAPZOOM);
+ if ( ps != 0 )
+ {
+ ps->SetState(STATE_VISIBLE, (m_mapMode != 0));
+
+ dim.x = SCROLL_WIDTH;
+ dim.y = 66.0f/480.0f;
+ pos.x = 523.0f/640.0f;
+ pos.y = 3.0f/480.0f;
+ ps->SetPos(pos);
+ ps->SetDim(dim);
+
+ value = pm->RetZoom();
+ value = (value-ZOOM_MIN)/(ZOOM_MAX-ZOOM_MIN);
+ value = powf(value, 0.5f);
+ ps->SetVisibleValue(value);
+ ps->SetArrowStep(0.2f);
+ }
+}
+
+// Retourne le zoom actuel de la mini-carte.
+
+float CMainMap::RetZoomMap()
+{
+ CWindow* pw;
+ CMap* pm;
+ CSlider* ps;
+
+ pw = (CWindow*)pw->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return ZOOM_MIN;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return ZOOM_MIN;
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_MAPZOOM);
+ if ( ps == 0 ) return ZOOM_MIN;
+
+ return pm->RetZoom();
+}
+
+// Zoom la mini-carte d'un facteur quelconque.
+
+void CMainMap::ZoomMap(float zoom)
+{
+ CWindow* pw;
+ CMap* pm;
+ CSlider* ps;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return;
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_MAPZOOM);
+ if ( ps == 0 ) return;
+
+ if ( zoom < ZOOM_MIN ) zoom = ZOOM_MIN;
+ if ( zoom > ZOOM_MAX ) zoom = ZOOM_MAX;
+ pm->SetZoom(zoom);
+
+ DimMap();
+}
+
+// Zoom la mini-carte selon le slider.
+
+void CMainMap::ZoomMap()
+{
+ CWindow* pw;
+ CMap* pm;
+ CSlider* ps;
+ float zoom;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return;
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_MAPZOOM);
+ if ( ps == 0 ) return;
+
+ zoom = ps->RetVisibleValue();
+ zoom = powf(zoom, 2.0f);
+ zoom = ZOOM_MIN+zoom*(ZOOM_MAX-ZOOM_MIN);
+ pm->SetZoom(zoom);
+
+ DimMap();
+}
+
+// Active ou désactive la carte.
+
+void CMainMap::MapEnable(BOOL bEnable)
+{
+ CWindow* pw;
+ CMap* pm;
+ CSlider* ps;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm != 0 )
+ {
+ pm->SetEnable(bEnable);
+ }
+
+ ps = (CSlider*)pw->SearchControl(EVENT_OBJECT_MAPZOOM);
+ if ( ps != 0 )
+ {
+ ps->SetState(STATE_ENABLE, bEnable);
+ }
+}
+
+// Spécifie le type de l'icône pour l'objet sélectionné.
+
+void CMainMap::SetToy(BOOL bToy)
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return;
+
+ pm->SetToy(bToy);
+}
+
+// Spécifie les paramètres lors de l'usage d'une image fixe.
+
+void CMainMap::SetFixParam(float zoom, float ox, float oy, float angle,
+ int mode, BOOL bDebug)
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return;
+
+ pm->SetZoom(zoom);
+ pm->SetOffset(ox, oy);
+ pm->SetAngle(angle);
+ pm->SetMode(mode);
+ pm->SetDebug(bDebug);
+}
+
+// Met à jour la mini-carte suite à un changement du terrain.
+
+void CMainMap::UpdateMap()
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm != 0 )
+ {
+ pm->UpdateTerrain();
+ }
+}
+
+// Indique si la mini-carte est visible.
+
+BOOL CMainMap::RetShowMap()
+{
+ return ( m_mapMode != 0 );
+}
+
+// Indique si la mini-carte affiche une image fixe.
+
+BOOL CMainMap::RetFixImage()
+{
+ return m_bFixImage;
+}
+
+
+// Détecte l'objet visé dans la mini-carte.
+
+CObject* CMainMap::DetectMap(FPOINT pos, BOOL &bInMap)
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return 0;
+
+ bInMap = FALSE;
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm == 0 ) return 0;
+ return pm->DetectObject(pos, bInMap);
+}
+
+
+// Indique l'objet survolé par la souris.
+
+void CMainMap::SetHilite(CObject* pObj)
+{
+ CWindow* pw;
+ CMap* pm;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 ) return;
+
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm != 0 )
+ {
+ pm->SetHilite(pObj);
+ }
+}
+
+
diff --git a/src/mainmap.h b/src/mainmap.h
new file mode 100644
index 0000000..68befa1
--- /dev/null
+++ b/src/mainmap.h
@@ -0,0 +1,52 @@
+// mainmap.h
+
+#ifndef _MAINMAP_H_
+#define _MAINMAP_H_
+
+
+class CInstanceManager;
+class CEvent;
+class CD3DEngine;
+class CInterface;
+class CObject;
+
+
+
+class CMainMap
+{
+public:
+ CMainMap(CInstanceManager* iMan);
+ ~CMainMap();
+
+ void UpdateMap();
+ void CreateMap();
+ void SetFixImage(char *filename);
+ void FloorColorMap(D3DCOLORVALUE floor, D3DCOLORVALUE water);
+ void ShowMap(BOOL bShow);
+ void DimMap();
+ float RetZoomMap();
+ void ZoomMap(float zoom);
+ void ZoomMap();
+ void MapEnable(BOOL bEnable);
+ BOOL RetShowMap();
+ BOOL RetFixImage();
+ CObject* DetectMap(FPOINT pos, BOOL &bInMap);
+ void SetHilite(CObject* pObj);
+ void SetToy(BOOL bToy);
+ void SetFixParam(float zoom, float ox, float oy, float angle, int mode, BOOL bDebug);
+
+protected:
+ void CenterMap();
+
+protected:
+ CInstanceManager* m_iMan;
+ CEvent* m_event;
+ CD3DEngine* m_engine;
+ CInterface* m_interface;
+
+ int m_mapMode;
+ BOOL m_bFixImage;
+};
+
+
+#endif //_MAINMAP_H_
diff --git a/src/mainmovie.cpp b/src/mainmovie.cpp
new file mode 100644
index 0000000..b8d0fb5
--- /dev/null
+++ b/src/mainmovie.cpp
@@ -0,0 +1,233 @@
+// mainmovie.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "global.h"
+#include "event.h"
+#include "iman.h"
+#include "math3d.h"
+#include "camera.h"
+#include "object.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "interface.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "mainmovie.h"
+
+
+
+
+// Constructeur de l'application carte.
+
+CMainMovie::CMainMovie(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_SHORT, this);
+
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ Flush();
+}
+
+// Destructeur de l'application robot.
+
+CMainMovie::~CMainMovie()
+{
+}
+
+
+// Stoppe le film en cours.
+
+void CMainMovie::Flush()
+{
+ m_type = MM_NONE;
+}
+
+
+// Début d'un film.
+
+BOOL CMainMovie::Start(MainMovieType type, float time)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ CObject* pObj;
+ CMotion* motion;
+
+ m_type = type;
+ m_speed = 1.0f/time;
+ m_progress = 0.0f;
+
+ if ( m_type == MM_SATCOMopen )
+ {
+ pObj = m_main->SearchHuman();
+ if ( pObj == 0 )
+ {
+ m_type = MM_NONE; // c'est déjà fini !
+ return TRUE;
+ }
+
+ motion = pObj->RetMotion();
+ if ( motion != 0 )
+ {
+ motion->SetAction(MHS_SATCOM, 0.5f); // lit le SatCom
+ }
+
+ m_camera->RetCamera(m_initialEye, m_initialLookat);
+ m_camera->SetType(CAMERA_SCRIPT);
+ m_camera->SetSmooth(CS_HARD);
+ m_camera->SetScriptEye(m_initialEye);
+ m_camera->SetScriptLookat(m_initialLookat);
+ m_camera->FixCamera();
+
+ mat = pObj->RetWorldMatrix(0);
+ m_finalLookat[0] = Transform(*mat, D3DVECTOR( 1.6f, 1.0f, 1.2f));
+ m_finalEye[0] = Transform(*mat, D3DVECTOR(-1.5f, 5.0f, 3.0f));
+ m_finalLookat[1] = Transform(*mat, D3DVECTOR( 1.6f, 1.0f, 1.2f));
+ m_finalEye[1] = Transform(*mat, D3DVECTOR( 0.8f, 3.0f, 0.8f));
+ }
+
+ if ( m_type == MM_SATCOMclose )
+ {
+ pObj = m_main->SearchHuman();
+ if ( pObj != 0 )
+ {
+ motion = pObj->RetMotion();
+ if ( motion != 0 )
+ {
+ motion->SetAction(-1); // termine lecture du SatCom
+ }
+ }
+
+ m_camera->SetType(CAMERA_BACK);
+ m_type = MM_NONE; // c'est déjà fini !
+ }
+
+ return TRUE;
+}
+
+// Stoppe un film en cours.
+
+BOOL CMainMovie::Stop()
+{
+ CObject* pObj;
+ CMotion* motion;
+
+ if ( m_type == MM_SATCOMopen )
+ {
+ pObj = m_main->SearchHuman();
+ if ( pObj != 0 )
+ {
+ motion = pObj->RetMotion();
+ if ( motion != 0 )
+ {
+ motion->SetAction(-1); // termine lecture du SatCom
+ }
+ }
+ }
+
+ m_type = MM_NONE;
+ return TRUE;
+}
+
+// Indique si un film est en cours.
+
+BOOL CMainMovie::IsExist()
+{
+ return (m_type != MM_NONE);
+}
+
+
+// Traite un événement.
+
+BOOL CMainMovie::EventProcess(const Event &event)
+{
+ D3DVECTOR initialEye, initialLookat, finalEye, finalLookat, eye, lookat;
+ float progress;
+
+ if ( m_type == MM_NONE ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_type == MM_SATCOMopen )
+ {
+ if ( m_progress < 1.0f )
+ {
+ progress = 1.0f-powf(1.0f-m_progress, 3.0f);
+
+ if ( progress < 0.6f )
+ {
+ progress = progress/0.6f;
+ initialEye = m_initialEye;
+ initialLookat = m_initialLookat;
+ finalEye = m_finalEye[0];
+ finalLookat = m_finalLookat[0];
+ }
+ else
+ {
+ progress = (progress-0.6f)/0.3f;
+ initialEye = m_finalEye[0];
+ initialLookat = m_finalLookat[0];
+ finalEye = m_finalEye[1];
+ finalLookat = m_finalLookat[1];
+ }
+ if ( progress > 1.0f ) progress = 1.0f;
+
+ eye = (finalEye-initialEye)*progress+initialEye;
+ lookat = (finalLookat-initialLookat)*progress+initialLookat;
+ m_camera->SetScriptEye(eye);
+ m_camera->SetScriptLookat(lookat);
+// m_camera->FixCamera();
+ }
+ else
+ {
+ m_stopType = m_type;
+ Flush();
+ return FALSE;
+ }
+ }
+
+ if ( m_type == MM_SATCOMclose )
+ {
+ if ( m_progress < 1.0f )
+ {
+ }
+ else
+ {
+ m_stopType = m_type;
+ Flush();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Retourne le type du film en cours.
+
+MainMovieType CMainMovie::RetType()
+{
+ return m_type;
+}
+
+// Retourne le type du film stoppé.
+
+MainMovieType CMainMovie::RetStopType()
+{
+ return m_stopType;
+}
+
+
diff --git a/src/mainmovie.h b/src/mainmovie.h
new file mode 100644
index 0000000..9932e1d
--- /dev/null
+++ b/src/mainmovie.h
@@ -0,0 +1,64 @@
+// mainmovie.h
+
+#ifndef _MAINMOVIE_H_
+#define _MAINMOVIE_H_
+
+
+class CInstanceManager;
+class CEvent;
+class CD3DEngine;
+class CInterface;
+class CRobotMain;
+class CCamera;
+class CSound;
+class CObject;
+
+
+
+
+enum MainMovieType
+{
+ MM_NONE,
+ MM_SATCOMopen,
+ MM_SATCOMclose,
+};
+
+
+
+class CMainMovie
+{
+public:
+ CMainMovie(CInstanceManager* iMan);
+ ~CMainMovie();
+
+ void Flush();
+ BOOL Start(MainMovieType type, float time);
+ BOOL Stop();
+ BOOL IsExist();
+ BOOL EventProcess(const Event &event);
+ MainMovieType RetType();
+ MainMovieType RetStopType();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CEvent* m_event;
+ CD3DEngine* m_engine;
+ CInterface* m_interface;
+ CRobotMain* m_main;
+ CCamera* m_camera;
+ CSound* m_sound;
+
+ MainMovieType m_type;
+ MainMovieType m_stopType;
+ float m_speed;
+ float m_progress;
+ D3DVECTOR m_initialEye;
+ D3DVECTOR m_initialLookat;
+ D3DVECTOR m_finalEye[2];
+ D3DVECTOR m_finalLookat[2];
+};
+
+
+#endif //_MAINMOVIE_H_
diff --git a/src/mainshort.cpp b/src/mainshort.cpp
new file mode 100644
index 0000000..15affa3
--- /dev/null
+++ b/src/mainshort.cpp
@@ -0,0 +1,360 @@
+// mainshort.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "global.h"
+#include "event.h"
+#include "iman.h"
+#include "object.h"
+#include "interface.h"
+#include "map.h"
+#include "button.h"
+#include "robotmain.h"
+#include "mainshort.h"
+
+
+
+
+// Constructeur de l'application carte.
+
+CMainShort::CMainShort(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_SHORT, this);
+
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+
+ FlushShortcuts();
+}
+
+// Destructeur de l'application robot.
+
+CMainShort::~CMainShort()
+{
+}
+
+
+
+void CMainShort::SetMode(BOOL bBuilding)
+{
+ m_bBuilding = bBuilding;
+}
+
+
+
+// Remise à zéro de tous les raccourcis.
+
+void CMainShort::FlushShortcuts()
+{
+ int i;
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ m_shortcuts[i] = 0;
+ }
+}
+
+static EventMsg table_sc_em[20] =
+{
+ EVENT_OBJECT_SHORTCUT00,
+ EVENT_OBJECT_SHORTCUT01,
+ EVENT_OBJECT_SHORTCUT02,
+ EVENT_OBJECT_SHORTCUT03,
+ EVENT_OBJECT_SHORTCUT04,
+ EVENT_OBJECT_SHORTCUT05,
+ EVENT_OBJECT_SHORTCUT06,
+ EVENT_OBJECT_SHORTCUT07,
+ EVENT_OBJECT_SHORTCUT08,
+ EVENT_OBJECT_SHORTCUT09,
+ EVENT_OBJECT_SHORTCUT10,
+ EVENT_OBJECT_SHORTCUT11,
+ EVENT_OBJECT_SHORTCUT12,
+ EVENT_OBJECT_SHORTCUT13,
+ EVENT_OBJECT_SHORTCUT14,
+ EVENT_OBJECT_SHORTCUT15,
+ EVENT_OBJECT_SHORTCUT16,
+ EVENT_OBJECT_SHORTCUT17,
+ EVENT_OBJECT_SHORTCUT18,
+ EVENT_OBJECT_SHORTCUT19,
+};
+
+// Crée l'interface des raccourcis aux unités.
+
+BOOL CMainShort::CreateShortcuts()
+{
+ CObject* pObj;
+ CControl* pc;
+ ObjectType type;
+ FPOINT pos, dim;
+ int i, rank, icon;
+ char name[100];
+
+ if ( m_main->RetFixScene() ) return FALSE;
+
+ m_interface->DeleteControl(EVENT_OBJECT_MOVIELOCK);
+ m_interface->DeleteControl(EVENT_OBJECT_EDITLOCK);
+ for ( i=0 ; i<20 ; i++ )
+ {
+ if ( i != 0 && m_shortcuts[i] == 0 ) continue;
+
+ m_interface->DeleteControl(table_sc_em[i]);
+ m_shortcuts[i] = 0;
+ }
+
+ dim.x = 28.0f/640.0f;
+ dim.y = 28.0f/480.0f;
+ pos.x = 4.0f/640.0f;
+ pos.y = (480.0f-32.0f)/480.0f;
+
+ if ( m_main->RetMovieLock() &&
+ !m_main->RetEditLock() ) // bloqué pendant film ?
+ {
+ m_interface->CreateShortcut(pos, dim, 7, EVENT_OBJECT_MOVIELOCK);
+ return TRUE;
+ }
+ if ( !m_main->RetFreePhoto() &&
+ (m_main->RetEditLock() ||
+ m_engine->RetPause()) ) // bloqué pendant édition ?
+ {
+ m_interface->CreateShortcut(pos, dim, 6, EVENT_OBJECT_EDITLOCK);
+ return TRUE;
+ }
+
+ rank = 0;
+
+ m_interface->CreateShortcut(pos, dim, 2, table_sc_em[rank]);
+ pos.x += dim.x*1.2f;
+ m_shortcuts[rank] = 0;
+ rank ++;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( !pObj->RetSelectable() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+
+ type = pObj->RetType();
+ icon = -1;
+ if ( m_bBuilding )
+ {
+ if ( type == OBJECT_FACTORY ) icon = 32;
+ if ( type == OBJECT_DERRICK ) icon = 33;
+ if ( type == OBJECT_CONVERT ) icon = 34;
+ if ( type == OBJECT_RESEARCH ) icon = 35;
+ if ( type == OBJECT_STATION ) icon = 36;
+ if ( type == OBJECT_TOWER ) icon = 37;
+ if ( type == OBJECT_LABO ) icon = 38;
+ if ( type == OBJECT_ENERGY ) icon = 39;
+ if ( type == OBJECT_RADAR ) icon = 40;
+ if ( type == OBJECT_INFO ) icon = 44;
+ if ( type == OBJECT_REPAIR ) icon = 41;
+ if ( type == OBJECT_DESTROYER) icon = 41;
+ if ( type == OBJECT_NUCLEAR ) icon = 42;
+ if ( type == OBJECT_PARA ) icon = 46;
+ if ( type == OBJECT_SAFE ) icon = 47;
+ if ( type == OBJECT_HUSTON ) icon = 48;
+ if ( type == OBJECT_BASE ) icon = 43;
+ }
+ else
+ {
+ if ( type == OBJECT_HUMAN ) icon = 8;
+ if ( type == OBJECT_MOBILEfa ) icon = 11;
+ if ( type == OBJECT_MOBILEta ) icon = 10;
+ if ( type == OBJECT_MOBILEwa ) icon = 9;
+ if ( type == OBJECT_MOBILEia ) icon = 22;
+ if ( type == OBJECT_MOBILEfc ) icon = 17;
+ if ( type == OBJECT_MOBILEtc ) icon = 16;
+ if ( type == OBJECT_MOBILEwc ) icon = 15;
+ if ( type == OBJECT_MOBILEic ) icon = 23;
+ if ( type == OBJECT_MOBILEfi ) icon = 27;
+ if ( type == OBJECT_MOBILEti ) icon = 26;
+ if ( type == OBJECT_MOBILEwi ) icon = 25;
+ if ( type == OBJECT_MOBILEii ) icon = 28;
+ if ( type == OBJECT_MOBILEfs ) icon = 14;
+ if ( type == OBJECT_MOBILEts ) icon = 13;
+ if ( type == OBJECT_MOBILEws ) icon = 12;
+ if ( type == OBJECT_MOBILEis ) icon = 24;
+ if ( type == OBJECT_MOBILErt ) icon = 18;
+ if ( type == OBJECT_MOBILErc ) icon = 19;
+ if ( type == OBJECT_MOBILErr ) icon = 20;
+ if ( type == OBJECT_MOBILErs ) icon = 29;
+ if ( type == OBJECT_MOBILEsa ) icon = 21;
+ if ( type == OBJECT_MOBILEft ) icon = 30;
+ if ( type == OBJECT_MOBILEtt ) icon = 30;
+ if ( type == OBJECT_MOBILEwt ) icon = 30;
+ if ( type == OBJECT_MOBILEit ) icon = 30;
+ if ( type == OBJECT_MOBILEdr ) icon = 48;
+ if ( type == OBJECT_APOLLO2 ) icon = 49;
+ }
+ if ( icon == -1 ) continue;
+
+ m_interface->CreateShortcut(pos, dim, icon, table_sc_em[rank]);
+ pos.x += dim.x;
+ m_shortcuts[rank] = pObj;
+
+ pc = m_interface->SearchControl(table_sc_em[rank]);
+ if ( pc != 0 )
+ {
+ pObj->GetTooltipName(name);
+ pc->SetTooltip(name);
+ }
+ rank ++;
+
+ if ( rank >= 20 ) break;
+ }
+
+ UpdateShortcuts();
+ return TRUE;
+}
+
+// Met à jour l'interface des raccourcis aux unités.
+
+BOOL CMainShort::UpdateShortcuts()
+{
+ CControl* pc;
+ int i;
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ if ( m_shortcuts[i] == 0 ) continue;
+
+ pc = m_interface->SearchControl(table_sc_em[i]);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_shortcuts[i]->RetSelect());
+ pc->SetState(STATE_RUN, m_shortcuts[i]->IsProgram());
+ }
+ }
+ return TRUE;
+}
+
+// Sélectionne un objet à travers un raccourci.
+
+void CMainShort::SelectShortcut(EventMsg event)
+{
+ int i;
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ if ( event == table_sc_em[i] )
+ {
+ if ( i != 0 && m_shortcuts[i] == 0 ) continue;
+
+ if ( i == 0 ) // bâtiments <-> véhicules ?
+ {
+ m_bBuilding = !m_bBuilding;
+ CreateShortcuts();
+ }
+ else
+ {
+ m_main->SelectObject(m_shortcuts[i]);
+ }
+ return;
+ }
+ }
+}
+
+
+// Sélectionne l'objet suivant.
+
+void CMainShort::SelectNext()
+{
+ CObject* pPrev;
+ int i;
+
+ if ( m_main->RetMovieLock() ||
+ m_main->RetEditLock() ||
+ m_engine->RetPause() ) return;
+
+ pPrev = m_main->DeselectAll();
+
+ for ( i=1 ; i<20 ; i++ )
+ {
+ if ( m_shortcuts[i] == pPrev )
+ {
+ if ( m_shortcuts[++i] == 0 ) i = 1;
+ break;
+ }
+ }
+
+ if ( i == 20 || m_shortcuts[i] == 0 )
+ {
+ m_main->SelectHuman();
+ }
+ else
+ {
+ m_main->SelectObject(m_shortcuts[i]);
+ }
+}
+
+
+// Détecte l'objet survolé par la souris.
+
+CObject* CMainShort::DetectShort(FPOINT pos)
+{
+ CControl* pc;
+ FPOINT cpos, cdim;
+ int i;
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ if ( m_shortcuts[i] == 0 ) continue;
+
+ pc = m_interface->SearchControl(table_sc_em[i]);
+ if ( pc != 0 )
+ {
+ cpos = pc->RetPos();
+ cdim = pc->RetDim();
+
+ if ( pos.x >= cpos.x &&
+ pos.x <= cpos.x+cdim.x &&
+ pos.y >= cpos.y &&
+ pos.y <= cpos.y+cdim.y )
+ {
+ return m_shortcuts[i];
+ }
+ }
+ }
+ return 0;
+}
+
+// Signale l'objet survolé par la souris.
+
+void CMainShort::SetHilite(CObject* pObj)
+{
+ CControl* pc;
+ int i;
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ if ( m_shortcuts[i] == 0 ) continue;
+
+ pc = m_interface->SearchControl(table_sc_em[i]);
+ if ( pc == 0 ) continue;
+
+ if ( m_shortcuts[i] == pObj )
+ {
+ pc->SetState(STATE_HILIGHT);
+ pc->SetState(STATE_FRAME);
+ }
+ else
+ {
+ pc->ClearState(STATE_HILIGHT);
+ pc->ClearState(STATE_FRAME);
+ }
+ }
+}
+
diff --git a/src/mainshort.h b/src/mainshort.h
new file mode 100644
index 0000000..3ad3cd7
--- /dev/null
+++ b/src/mainshort.h
@@ -0,0 +1,45 @@
+// mainshort.h
+
+#ifndef _MAINSHORT_H_
+#define _MAINSHORT_H_
+
+
+class CInstanceManager;
+class CEvent;
+class CD3DEngine;
+class CInterface;
+class CRobotMain;
+class CObject;
+
+
+
+class CMainShort
+{
+public:
+ CMainShort(CInstanceManager* iMan);
+ ~CMainShort();
+
+ void SetMode(BOOL bBuilding);
+ void FlushShortcuts();
+ BOOL CreateShortcuts();
+ BOOL UpdateShortcuts();
+ void SelectShortcut(EventMsg event);
+ void SelectNext();
+ CObject* DetectShort(FPOINT pos);
+ void SetHilite(CObject* pObj);
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CEvent* m_event;
+ CD3DEngine* m_engine;
+ CInterface* m_interface;
+ CRobotMain* m_main;
+
+ CObject* m_shortcuts[20];
+ BOOL m_bBuilding;
+};
+
+
+#endif //_MAINSHORT_H_
diff --git a/src/map.cpp b/src/map.cpp
new file mode 100644
index 0000000..bf5fd1c
--- /dev/null
+++ b/src/map.cpp
@@ -0,0 +1,1327 @@
+// map.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "event.h"
+#include "math3d.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "event.h"
+#include "misc.h"
+#include "robotmain.h"
+#include "iman.h"
+#include "map.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CMap::CMap(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+
+ m_bEnable = TRUE;
+ m_time = 0.0f;
+ m_zoom = 2.0f;
+ m_offset.x = 0.0f;
+ m_offset.y = 0.0f;
+ m_angle = 0.0f;
+
+ m_floorColor.r = 1.00f;
+ m_floorColor.g = 0.50f;
+ m_floorColor.b = 0.00f; // orange
+
+ m_waterColor.r = 0.00f;
+ m_waterColor.g = 0.80f;
+ m_waterColor.b = 1.00f; // bleu
+
+ m_half = m_terrain->RetMosaic()*m_terrain->RetBrick()*m_terrain->RetSize()/2.0f;
+
+ m_hiliteRank = -1;
+ FlushObject();
+
+ m_fixImage[0] = 0;
+ m_mode = 0;
+ m_bToy = FALSE;
+ m_bDebug = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CMap::~CMap()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CMap::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+ return TRUE;
+}
+
+
+// Choix de l'offset, lorsqu'une image fixe est affichée.
+
+void CMap::SetOffset(float ox, float oy)
+{
+ m_offset.x = ox;
+ m_offset.y = oy;
+ m_half = m_terrain->RetMosaic()*m_terrain->RetBrick()*m_terrain->RetSize()/2.0f;
+}
+
+// Choix de l'angle global de rotation.
+
+void CMap::SetAngle(float angle)
+{
+ m_angle = angle;
+}
+
+// Spécifie le mode spécial.
+
+void CMap::SetMode(int mode)
+{
+ m_mode = mode;
+}
+
+// Spécifie le type de l'icône pour l'objet sélectionné.
+
+void CMap::SetToy(BOOL bToy)
+{
+ m_bToy = bToy;
+}
+
+void CMap::SetDebug(BOOL bDebug)
+{
+ m_bDebug = bDebug;
+}
+
+
+// Choix du facteur de zoom de la carte.
+
+void CMap::SetZoom(float value)
+{
+ m_zoom = value;
+ m_half = m_terrain->RetMosaic()*m_terrain->RetBrick()*m_terrain->RetSize()/2.0f;
+}
+
+float CMap::RetZoom()
+{
+ return m_zoom;
+}
+
+// Choix d'un offset fixe.
+
+// Active ou désactive la carte.
+
+void CMap::SetEnable(BOOL bEnable)
+{
+ m_bEnable = bEnable;
+ SetState(STATE_DEAD, !bEnable);
+}
+
+BOOL CMap::RetEnable()
+{
+ return m_bEnable;
+}
+
+
+// Choix de la couleur du sol.
+
+void CMap::SetFloorColor(D3DCOLORVALUE color)
+{
+ m_floorColor = color;
+}
+
+// Choix de la couleur de l'eau.
+
+void CMap::SetWaterColor(D3DCOLORVALUE color)
+{
+ m_waterColor = color;
+}
+
+
+// Spécifie une image fixe à la place du dessin du relief.
+
+void CMap::SetFixImage(char *filename)
+{
+ strcpy(m_fixImage, filename);
+}
+
+// Indique si on utilise une image fixe.
+
+BOOL CMap::RetFixImage()
+{
+ return (m_fixImage[0] != 0);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMap::EventProcess(const Event &event)
+{
+ BOOL bInMap;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ m_time += event.rTime;
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && Detect(event.pos) )
+ {
+ m_engine->SetMouseType(D3DMOUSENORM);
+ if ( DetectObject(event.pos, bInMap) != 0 )
+ {
+ m_engine->SetMouseType(D3DMOUSEHAND);
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ SelectObject(event.pos);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+// Ajuste l'offset pour ne pas dépasser la carte.
+
+FPOINT CMap::AdjustOffset(FPOINT offset)
+{
+ float limit;
+
+ limit = m_half - m_half/m_zoom;
+ if ( offset.x < -limit ) offset.x = -limit;
+ if ( offset.x > limit ) offset.x = limit;
+ if ( offset.y < -limit ) offset.y = -limit;
+ if ( offset.y > limit ) offset.y = limit;
+
+ return offset;
+}
+
+// Indique l'objet survolé par la souris.
+
+void CMap::SetHilite(CObject* pObj)
+{
+ int i;
+
+ m_hiliteRank = -1;
+ if ( m_bToy || m_fixImage[0] != 0 ) return; // carte avec image fixe ?
+ if ( pObj == 0 ) return;
+
+ for ( i=0 ; i<MAPMAXOBJECT ; i++ )
+ {
+ if ( !m_map[i].bUsed ) continue;
+
+ if ( m_map[i].object == pObj )
+ {
+ m_hiliteRank = i;
+ break;
+ }
+ }
+}
+
+// Détecte un objet dans la carte.
+
+CObject* CMap::DetectObject(FPOINT pos, BOOL &bInMap)
+{
+ float dist, min;
+ int i, best;
+
+ bInMap = FALSE;
+ if ( pos.x < m_pos.x ||
+ pos.y < m_pos.y ||
+ pos.x > m_pos.x+m_dim.x ||
+ pos.y > m_pos.y+m_dim.y ) return 0;
+
+ bInMap = TRUE;
+
+ pos.x = (pos.x-m_pos.x)/m_dim.x*256.0f;
+ pos.y = (pos.y-m_pos.y)/m_dim.y*256.0f; // 0..256
+ pos.x = (pos.x-128.0f)*m_half/(m_zoom*128.0f)+m_offset.x;
+ pos.y = (pos.y-128.0f)*m_half/(m_zoom*128.0f)+m_offset.y;
+
+ min = 10000.0f;
+ best = -1;
+ for ( i=MAPMAXOBJECT-1 ; i>=0 ; i-- )
+ {
+ if ( !m_map[i].bUsed ) continue;
+ if ( m_map[i].color == MAPCOLOR_BBOX && !m_bRadar ) continue;
+ if ( m_map[i].color == MAPCOLOR_ALIEN && !m_bRadar ) continue;
+
+ dist = Length(m_map[i].pos.x-pos.x, m_map[i].pos.y-pos.y);
+ if ( dist > m_half/m_zoom*8.0f/100.0f ) continue; // trop loin ?
+ if ( dist < min )
+ {
+ min = dist;
+ best = i;
+ }
+ }
+ if ( best == -1 ) return 0;
+ return m_map[best].object;
+}
+
+// Sélectionne un objet.
+
+void CMap::SelectObject(FPOINT pos)
+{
+ CObject *pObj;
+ BOOL bInMap;
+
+ pObj = DetectObject(pos, bInMap);
+ if ( pObj != 0 )
+ {
+ m_main->SelectObject(pObj);
+ }
+}
+
+
+// Dessine la carte.
+
+void CMap::Draw()
+{
+ FPOINT uv1, uv2;
+ int i;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ CControl::Draw(); // dessine le fond (bouton)
+
+ if ( !m_bEnable ) return;
+
+ if ( m_fixImage[0] == 0 && m_map[MAPMAXOBJECT-1].bUsed )
+ {
+ m_offset = AdjustOffset(m_map[MAPMAXOBJECT-1].pos);
+ }
+
+ if ( m_fixImage[0] == 0 ) // dessin du relief ?
+ {
+ m_engine->SetTexture("map.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 0.5f+(m_offset.x-(m_half/m_zoom))/(m_half*2.0f);
+ uv1.y = 0.5f-(m_offset.y+(m_half/m_zoom))/(m_half*2.0f);
+ uv2.x = 0.5f+(m_offset.x+(m_half/m_zoom))/(m_half*2.0f);
+ uv2.y = 0.5f-(m_offset.y-(m_half/m_zoom))/(m_half*2.0f);
+ DrawVertex(uv1, uv2, 0.97f); // dessine la carte
+ }
+ else // image fixe ?
+ {
+ m_engine->LoadTexture(m_fixImage);
+ m_engine->SetTexture(m_fixImage);
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 0.0f;
+ uv1.y = 0.0f;
+ uv2.x = 1.0f;
+ uv2.y = 1.0f;
+ DrawVertex(uv1, uv2, 0.97f); // dessine la carte
+ }
+
+ i = MAPMAXOBJECT-1;
+ if ( m_map[i].bUsed ) // sélection :
+ {
+ DrawFocus(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color);
+ }
+
+ for ( i=0 ; i<m_totalFix ; i++ ) // objets fixes :
+ {
+ if ( i == m_hiliteRank ) continue;
+ DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, FALSE, FALSE);
+ }
+
+ for ( i=MAPMAXOBJECT-2 ; i>m_totalMove ; i-- ) // objets mobiles :
+ {
+ if ( i == m_hiliteRank ) continue;
+ DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, FALSE, FALSE);
+ }
+
+ i = MAPMAXOBJECT-1;
+ if ( m_map[i].bUsed && i != m_hiliteRank ) // sélection :
+ {
+ DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, TRUE, FALSE);
+ }
+
+ if ( m_hiliteRank != -1 && m_map[m_hiliteRank].bUsed )
+ {
+ i = m_hiliteRank;
+ DrawObject(m_map[i].pos, m_map[i].dir, m_map[i].type, m_map[i].color, FALSE, TRUE);
+ DrawHilite(m_map[i].pos);
+ }
+}
+
+// Calcul un point pour DrawFocus.
+
+FPOINT CMap::MapInter(FPOINT pos, float dir)
+{
+ FPOINT p1;
+ float limit;
+
+ p1.x = pos.x+1.0f;
+ p1.y = pos.y;
+ p1 = RotatePoint(pos, dir, p1);
+
+ p1.x -= pos.x;
+ p1.y -= pos.y;
+
+ limit = m_mapPos.x+m_mapDim.x-pos.x;
+ if ( p1.x > limit ) // dépasse à droite ?
+ {
+ p1.y = limit*p1.y/p1.x;
+ p1.x = limit;
+ }
+ limit = m_mapPos.y*0.75f+m_mapDim.y*0.75f-pos.y;
+ if ( p1.y > limit ) // dépasse en haut ?
+ {
+ p1.x = limit*p1.x/p1.y;
+ p1.y = limit;
+ }
+ limit = m_mapPos.x-pos.x;
+ if ( p1.x < limit ) // dépasse à gauche ?
+ {
+ p1.y = limit*p1.y/p1.x;
+ p1.x = limit;
+ }
+ limit = m_mapPos.y*0.75f-pos.y;
+ if ( p1.y < limit ) // dépasse en bas ?
+ {
+ p1.x = limit*p1.x/p1.y;
+ p1.y = limit;
+ }
+
+ p1.x += pos.x;
+ p1.y += pos.y;
+ return p1;
+}
+
+// Dessine le champ de vision de l'objet sélectionné.
+
+void CMap::DrawFocus(FPOINT pos, float dir, ObjectType type, MapColor color)
+{
+ FPOINT p0, p1, p2, uv1, uv2, rel;
+ float aMin, aMax, aOct, focus, a;
+ float limit[5];
+ BOOL bEnding;
+ int quart;
+
+ if ( m_bToy || m_fixImage[0] != 0 ) return; // carte avec image fixe ?
+ if ( color != MAPCOLOR_MOVE ) return;
+
+ pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
+ pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
+
+ if ( pos.x < 0.0f || pos.x > 1.0f ||
+ pos.y < 0.0f || pos.y > 1.0f ) return;
+
+ rel.x = pos.x*2.0f-1.0f;
+ rel.y = pos.y*2.0f-1.0f; // rel [-1..1]
+
+ pos.x = m_mapPos.x+m_mapDim.x*pos.x;
+ pos.y = m_mapPos.y*0.75f+m_mapDim.y*pos.y*0.75f;
+
+ focus = m_engine->RetFocus();
+ dir += PI/2.0f;
+ aMin = NormAngle(dir-PI/4.0f*focus);
+ aMax = NormAngle(dir+PI/4.0f*focus);
+
+ if ( aMin > aMax )
+ {
+ aMax += PI*2.0f; // aMax toujours après aMin
+ }
+
+ limit[0] = RotateAngle( 1.0f-rel.x, 1.0f-rel.y); // sup/droite
+ limit[1] = RotateAngle(-1.0f-rel.x, 1.0f-rel.y); // sup/gauche
+ limit[2] = RotateAngle(-1.0f-rel.x, -1.0f-rel.y); // inf/gauche
+ limit[3] = RotateAngle( 1.0f-rel.x, -1.0f-rel.y); // inf/droite
+ limit[4] = limit[0]+PI*2.0f;
+
+ a = NormAngle(aMin);
+ for ( quart=0 ; quart<4 ; quart++ )
+ {
+ if ( a >= limit[quart+0] &&
+ a <= limit[quart+1] ) break;
+ }
+ if ( quart == 4 ) quart = -1;
+
+ uv1.x = 113.0f/256.0f; // dégradé vert
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 126.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+
+ bEnding = FALSE;
+ do
+ {
+ quart ++;
+ aOct = limit[quart%4];
+ if ( quart >= 4 ) aOct += PI*2.0f;
+ if ( aOct >= aMax-CHOUIA )
+ {
+ aOct = aMax;
+ bEnding = TRUE;
+ }
+
+ p0 = pos;
+ p1 = MapInter(pos, aMin);
+ p2 = MapInter(pos, aOct);
+ p0.y /= 0.75f;
+ p1.y /= 0.75f;
+ p2.y /= 0.75f;
+ DrawTriangle(p0, p2, p1, uv1, uv2);
+
+ aMin = aOct;
+ }
+ while ( !bEnding );
+}
+
+// Dessine un objet.
+
+void CMap::DrawObject(FPOINT pos, float dir, ObjectType type, MapColor color,
+ BOOL bSelect, BOOL bHilite)
+{
+ FPOINT p1, p2, p3, p4, p5, dim, uv1, uv2;
+ BOOL bOut, bUp, bDown, bLeft, bRight;
+
+ pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
+ pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
+
+ bOut = bUp = bDown = bLeft = bRight = FALSE;
+ if ( pos.x < 0.06f ) { pos.x = 0.02f; bOut = bLeft = TRUE; }
+ if ( pos.y < 0.06f ) { pos.y = 0.02f; bOut = bDown = TRUE; }
+ if ( pos.x > 0.94f ) { pos.x = 0.98f; bOut = bRight = TRUE; }
+ if ( pos.y > 0.94f ) { pos.y = 0.98f; bOut = bUp = TRUE; }
+
+ pos.x = m_mapPos.x+m_mapDim.x*pos.x;
+ pos.y = m_mapPos.y+m_mapDim.y*pos.y;
+ dim.x = 2.0f/128.0f*0.75f;
+ dim.y = 2.0f/128.0f;
+
+ if ( bOut ) // hors de la carte ?
+ {
+ if ( color == MAPCOLOR_BBOX && !m_bRadar ) return;
+ if ( color == MAPCOLOR_ALIEN && !m_bRadar ) return;
+
+ if ( Mod(m_time+(pos.x+pos.y)*4.0f, 0.6f) > 0.2f )
+ {
+ return; // clignotte
+ }
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ if ( bUp )
+ {
+ uv1.x = 160.5f/256.0f; // triangle jaune ^
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 175.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ }
+ if ( bDown )
+ {
+ uv1.x = 160.5f/256.0f; // triangle jaune v
+ uv1.y = 255.0f/256.0f;
+ uv2.x = 175.0f/256.0f;
+ uv2.y = 240.5f/256.0f;
+ }
+ if ( bRight )
+ {
+ uv1.x = 176.5f/256.0f; // triangle jaune >
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 191.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ }
+ if ( bLeft )
+ {
+ uv1.x = 191.0f/256.0f; // triangle jaune <
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 176.5f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ }
+ pos.x -= dim.x/2.0f;
+ pos.y -= dim.y/2.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ return;
+ }
+
+ if ( bSelect )
+ {
+ if ( m_bToy )
+ {
+ dim.x *= 1.2f+sinf(m_time*8.0f)*0.1f;
+ dim.y *= 1.2f+sinf(m_time*8.0f)*0.1f;
+ }
+ else
+ {
+ dim.x *= 1.2f+sinf(m_time*8.0f)*0.3f;
+ dim.y *= 1.2f+sinf(m_time*8.0f)*0.3f;
+ }
+ }
+ if ( color == MAPCOLOR_BASE ||
+ color == MAPCOLOR_FIX ||
+ color == MAPCOLOR_MOVE )
+ {
+ if ( bHilite )
+ {
+ dim.x *= 2.2f;
+ dim.y *= 2.2f;
+ }
+ else
+ {
+ dim.x *= 0.6f;
+ dim.y *= 0.6f;
+ }
+ }
+ if ( color == MAPCOLOR_ALIEN )
+ {
+ dim.x *= 1.4f;
+ dim.y *= 1.4f;
+ }
+ if ( type == OBJECT_TEEN28 ) // bouteille ?
+ {
+ dim.x *= 3.0f;
+ dim.y *= 3.0f;
+ bHilite = TRUE;
+ }
+ if ( type == OBJECT_TEEN34 ) // caillou ?
+ {
+ dim.x *= 2.0f;
+ dim.y *= 2.0f;
+ bHilite = TRUE;
+ }
+
+ if ( color == MAPCOLOR_MOVE && bSelect )
+ {
+ if ( m_bToy )
+ {
+ p1.x = pos.x;
+ p1.y = pos.y+dim.y*1.4f;
+ p1 = RotatePoint(pos, dir, p1);
+ p1.x = pos.x+(p1.x-pos.x)*0.75f;
+
+ p2.x = pos.x+dim.x*1.2f;
+ p2.y = pos.y+dim.y*0.8f;
+ p2 = RotatePoint(pos, dir, p2);
+ p2.x = pos.x+(p2.x-pos.x)*0.75f;
+
+ p3.x = pos.x+dim.x*1.2f;
+ p3.y = pos.y-dim.y*1.0f;
+ p3 = RotatePoint(pos, dir, p3);
+ p3.x = pos.x+(p3.x-pos.x)*0.75f;
+
+ p4.x = pos.x-dim.x*1.2f;
+ p4.y = pos.y-dim.y*1.0f;
+ p4 = RotatePoint(pos, dir, p4);
+ p4.x = pos.x+(p4.x-pos.x)*0.75f;
+
+ p5.x = pos.x-dim.x*1.2f;
+ p5.y = pos.y+dim.y*0.8f;
+ p5 = RotatePoint(pos, dir, p5);
+ p5.x = pos.x+(p5.x-pos.x)*0.75f;
+ }
+ else
+ {
+ p1.x = pos.x;
+ p1.y = pos.y+dim.y*2.4f;
+ p1 = RotatePoint(pos, dir, p1);
+ p1.x = pos.x+(p1.x-pos.x)*0.75f;
+
+ p2.x = pos.x+dim.x*1.0f;
+ p2.y = pos.y-dim.y*1.6f;
+ p2 = RotatePoint(pos, dir, p2);
+ p2.x = pos.x+(p2.x-pos.x)*0.75f;
+
+ p3.x = pos.x-dim.x*1.0f;
+ p3.y = pos.y-dim.y*1.6f;
+ p3 = RotatePoint(pos, dir, p3);
+ p3.x = pos.x+(p3.x-pos.x)*0.75f;
+ }
+ }
+
+ pos.x -= dim.x/2.0f;
+ pos.y -= dim.y/2.0f;
+
+ if ( color == MAPCOLOR_BASE ||
+ color == MAPCOLOR_FIX )
+ {
+ DrawObjectIcon(pos, dim, color, type, bHilite);
+ }
+
+ if ( color == MAPCOLOR_MOVE )
+ {
+ if ( bSelect )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ if ( m_bToy )
+ {
+ uv1.x = 164.5f/256.0f; // pentagone noir
+ uv1.y = 228.5f/256.0f;
+ uv2.x = 172.0f/256.0f;
+ uv2.y = 236.0f/256.0f;
+ DrawPenta(p1, p2, p3, p4, p5, uv1, uv2);
+ }
+ else
+ {
+ uv1.x = 144.5f/256.0f; // triangle rouge
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 159.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ DrawTriangle(p1, p2, p3, uv1, uv2);
+ }
+ }
+ DrawObjectIcon(pos, dim, color, type, bHilite);
+ }
+
+ if ( color == MAPCOLOR_BBOX )
+ {
+ if ( m_bRadar )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 64.5f/256.0f; // triangle bleu
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 79.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+ }
+
+ if ( color == MAPCOLOR_ALIEN )
+ {
+ if ( m_bRadar )
+ {
+ DrawObjectIcon(pos, dim, color, type, TRUE);
+ }
+ }
+
+ if ( color == MAPCOLOR_WAYPOINTb )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 192.5f/256.0f; // croix bleue
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 207.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+ if ( color == MAPCOLOR_WAYPOINTr )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 208.5f/256.0f; // croix rouge
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 223.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+ if ( color == MAPCOLOR_WAYPOINTg )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 224.5f/256.0f; // croix verte
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 239.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+ if ( color == MAPCOLOR_WAYPOINTy )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 240.5f/256.0f; // croix jaune
+ uv1.y = 240.5f/256.0f;
+ uv2.x = 255.0f/256.0f;
+ uv2.y = 255.0f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+ if ( color == MAPCOLOR_WAYPOINTv )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 192.5f/256.0f; // croix violette
+ uv1.y = 224.5f/256.0f;
+ uv2.x = 207.0f/256.0f;
+ uv2.y = 239.0f/256.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+ }
+}
+
+// Dessine l'icône d'un objet.
+
+void CMap::DrawObjectIcon(FPOINT pos, FPOINT dim, MapColor color,
+ ObjectType type, BOOL bHilite)
+{
+ FPOINT ppos, ddim, uv1, uv2;
+ float dp;
+ int icon;
+
+ dp = 0.5f/256.0f;
+
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ if ( color == MAPCOLOR_MOVE )
+ {
+ uv1.x = 160.0f/256.0f; // bleu
+ uv1.y = 224.0f/256.0f;
+ }
+ else if ( color == MAPCOLOR_ALIEN )
+ {
+ uv1.x = 224.0f/256.0f; // vert
+ uv1.y = 224.0f/256.0f;
+ }
+ else
+ {
+ uv1.x = 192.0f/256.0f; // jaune
+ uv1.y = 224.0f/256.0f;
+ }
+ uv2.x = uv1.x+32.0f/256.0f;
+ uv2.y = uv1.y+32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // fond coloré
+
+ if ( bHilite )
+ {
+ icon = -1;
+ if ( type == OBJECT_FACTORY ) icon = 32;
+ if ( type == OBJECT_DERRICK ) icon = 33;
+ if ( type == OBJECT_CONVERT ) icon = 34;
+ if ( type == OBJECT_RESEARCH ) icon = 35;
+ if ( type == OBJECT_STATION ) icon = 36;
+ if ( type == OBJECT_TOWER ) icon = 37;
+ if ( type == OBJECT_LABO ) icon = 38;
+ if ( type == OBJECT_ENERGY ) icon = 39;
+ if ( type == OBJECT_RADAR ) icon = 40;
+ if ( type == OBJECT_INFO ) icon = 44;
+ if ( type == OBJECT_REPAIR ) icon = 41;
+ if ( type == OBJECT_DESTROYER) icon = 41;
+ if ( type == OBJECT_NUCLEAR ) icon = 42;
+ if ( type == OBJECT_PARA ) icon = 46;
+ if ( type == OBJECT_SAFE ) icon = 47;
+ if ( type == OBJECT_HUSTON ) icon = 48;
+ if ( type == OBJECT_TARGET1 ) icon = 45;
+ if ( type == OBJECT_BASE ) icon = 43;
+ if ( type == OBJECT_HUMAN ) icon = 8;
+ if ( type == OBJECT_MOBILEfa ) icon = 11;
+ if ( type == OBJECT_MOBILEta ) icon = 10;
+ if ( type == OBJECT_MOBILEwa ) icon = 9;
+ if ( type == OBJECT_MOBILEia ) icon = 22;
+ if ( type == OBJECT_MOBILEfc ) icon = 17;
+ if ( type == OBJECT_MOBILEtc ) icon = 16;
+ if ( type == OBJECT_MOBILEwc ) icon = 15;
+ if ( type == OBJECT_MOBILEic ) icon = 23;
+ if ( type == OBJECT_MOBILEfi ) icon = 27;
+ if ( type == OBJECT_MOBILEti ) icon = 26;
+ if ( type == OBJECT_MOBILEwi ) icon = 25;
+ if ( type == OBJECT_MOBILEii ) icon = 28;
+ if ( type == OBJECT_MOBILEfs ) icon = 14;
+ if ( type == OBJECT_MOBILEts ) icon = 13;
+ if ( type == OBJECT_MOBILEws ) icon = 12;
+ if ( type == OBJECT_MOBILEis ) icon = 24;
+ if ( type == OBJECT_MOBILErt ) icon = 18;
+ if ( type == OBJECT_MOBILErc ) icon = 19;
+ if ( type == OBJECT_MOBILErr ) icon = 20;
+ if ( type == OBJECT_MOBILErs ) icon = 29;
+ if ( type == OBJECT_MOBILEsa ) icon = 21;
+ if ( type == OBJECT_MOBILEft ) icon = 30;
+ if ( type == OBJECT_MOBILEtt ) icon = 30;
+ if ( type == OBJECT_MOBILEwt ) icon = 30;
+ if ( type == OBJECT_MOBILEit ) icon = 30;
+ if ( type == OBJECT_MOBILEtg ) icon = 45;
+ if ( type == OBJECT_MOBILEdr ) icon = 48;
+ if ( type == OBJECT_APOLLO2 ) icon = 49;
+ if ( type == OBJECT_MOTHER ) icon = 31;
+ if ( type == OBJECT_ANT ) icon = 31;
+ if ( type == OBJECT_SPIDER ) icon = 31;
+ if ( type == OBJECT_BEE ) icon = 31;
+ if ( type == OBJECT_WORM ) icon = 31;
+ if ( type == OBJECT_TEEN28 ) icon = 48; // bouteille
+ if ( type == OBJECT_TEEN34 ) icon = 48; // caillou
+ if ( icon == -1 ) return;
+
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = (32.0f/256.0f)*(icon%8);
+ uv1.y = (32.0f/256.0f)*(icon/8);
+ uv2.x = uv1.x+32.0f/256.0f;
+ uv2.y = uv1.y+32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // icône
+ }
+}
+
+// Dessine l'objet survolé par la souris.
+
+void CMap::DrawHilite(FPOINT pos)
+{
+ FPOINT dim, uv1, uv2;
+ BOOL bOut, bUp, bDown, bLeft, bRight;
+
+ if ( m_bToy || m_fixImage[0] != 0 ) return; // carte avec image fixe ?
+
+ pos.x = (pos.x-m_offset.x)*(m_zoom*0.5f)/m_half+0.5f;
+ pos.y = (pos.y-m_offset.y)*(m_zoom*0.5f)/m_half+0.5f;
+
+ bOut = bUp = bDown = bLeft = bRight = FALSE;
+ if ( pos.x < 0.06f ) { pos.x = 0.02f; bOut = bLeft = TRUE; }
+ if ( pos.y < 0.06f ) { pos.y = 0.02f; bOut = bDown = TRUE; }
+ if ( pos.x > 0.94f ) { pos.x = 0.98f; bOut = bRight = TRUE; }
+ if ( pos.y > 0.94f ) { pos.y = 0.98f; bOut = bUp = TRUE; }
+
+ pos.x = m_mapPos.x+m_mapDim.x*pos.x;
+ pos.y = m_mapPos.y+m_mapDim.y*pos.y;
+ dim.x = 2.0f/128.0f*0.75f;
+ dim.y = 2.0f/128.0f;
+ dim.x *= 2.0f+cosf(m_time*8.0f)*0.5f;
+ dim.y *= 2.0f+cosf(m_time*8.0f)*0.5f;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 160.5f/256.0f; // hilite
+ uv1.y = 224.5f/256.0f;
+ uv2.x = 175.0f/256.0f;
+ uv2.y = 239.0f/256.0f;
+ pos.x -= dim.x/2.0f;
+ pos.y -= dim.y/2.0f;
+ DrawIcon(pos, dim, uv1, uv2);
+}
+
+// Dessine une icône triangulaire.
+
+void CMap::DrawTriangle(FPOINT p1, FPOINT p2, FPOINT p3, FPOINT uv1, FPOINT uv2)
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[3]; // 1 triangle
+ D3DVECTOR n;
+
+ device = m_engine->RetD3DDevice();
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p3.x, p3.y, 0.0f), n, uv2.x,uv2.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX2, vertex, 3, NULL);
+ m_engine->AddStatisticTriangle(1);
+}
+
+// Dessine une icône pentagonulaire (à 5 côtés, quoi !).
+
+void CMap::DrawPenta(FPOINT p1, FPOINT p2, FPOINT p3, FPOINT p4, FPOINT p5, FPOINT uv1, FPOINT uv2)
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[5]; // 1 pentagone
+ D3DVECTOR n;
+
+ device = m_engine->RetD3DDevice();
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+#if 1
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p5.x, p5.y, 0.0f), n, uv2.x,uv2.y);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p3.x, p3.y, 0.0f), n, uv2.x,uv2.y);
+ vertex[4] = D3DVERTEX2(D3DVECTOR(p4.x, p4.y, 0.0f), n, uv2.x,uv2.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 5, NULL);
+#else
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p3.x, p3.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p4.x, p4.y, 0.0f), n, uv2.x,uv2.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX2, vertex, 3, NULL);
+#endif
+ m_engine->AddStatisticTriangle(3);
+}
+
+// Dessine le tableau des vertex.
+
+void CMap::DrawVertex(FPOINT uv1, FPOINT uv2, float zoom)
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2, c;
+ D3DVECTOR n;
+
+ device = m_engine->RetD3DDevice();
+
+ p1.x = m_pos.x;
+ p1.y = m_pos.y;
+ p2.x = m_pos.x + m_dim.x;
+ p2.y = m_pos.y + m_dim.y;
+
+ c.x = (p1.x+p2.x)/2.0f;
+ c.y = (p1.y+p2.y)/2.0f; // centre
+
+ p1.x = (p1.x-c.x)*zoom + c.x;
+ p1.y = (p1.y-c.y)*zoom + c.y;
+
+ p2.x = (p2.x-c.x)*zoom + c.x;
+ p2.y = (p2.y-c.y)*zoom + c.y;
+
+ m_mapPos = p1;
+ m_mapDim.x = p2.x-p1.x;
+ m_mapDim.y = p2.y-p1.y;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, uv1.x,uv2.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, uv1.x,uv1.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, uv2.x,uv2.y);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, uv2.x,uv1.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+}
+
+
+// Met à jour le terrain dans la carte.
+
+void CMap::UpdateTerrain()
+{
+ D3DCOLORVALUE color;
+ D3DVECTOR pos;
+ float scale, water, level, intensity;
+ int x, y;
+
+ if ( m_fixImage[0] != 0 ) return; // image fixe ?
+ if ( !m_engine->OpenImage("map.tga") ) return;
+
+ scale = m_terrain->RetScaleRelief();
+ water = m_water->RetLevel();
+ color.a = 0.0f;
+
+ for ( y=0 ; y<256 ; y++ )
+ {
+ for ( x=0 ; x<256 ; x++ )
+ {
+ pos.x = ((float)x-128.0f)*m_half/128.0f;
+ pos.z = -((float)y-128.0f)*m_half/128.0f;
+ pos.y = 0.0f;
+
+ if ( pos.x >= -m_half && pos.x <= m_half &&
+ pos.z >= -m_half && pos.z <= m_half )
+ {
+ level = m_terrain->RetFloorLevel(pos, TRUE)/scale;
+ }
+ else
+ {
+ level = 1000.0f;
+ }
+
+ intensity = level/256.0f;
+ if ( intensity < 0.0f ) intensity = 0.0f;
+ if ( intensity > 1.0f ) intensity = 1.0f;
+
+ if ( level >= water ) // sur l'eau ?
+ {
+ color.r = m_floorColor.r + (intensity-0.5f);
+ color.g = m_floorColor.g + (intensity-0.5f);
+ color.b = m_floorColor.b + (intensity-0.5f);
+ }
+ else // sous l'eau ?
+ {
+ color.r = m_waterColor.r + (intensity-0.5f);
+ color.g = m_waterColor.g + (intensity-0.5f);
+ color.b = m_waterColor.b + (intensity-0.5f);
+ }
+
+ m_engine->SetDot(x, y, color);
+ }
+ }
+
+ m_engine->CopyImage(); // copie avec juste le terrain dessiné
+ m_engine->CloseImage();
+}
+
+// Met à jour le terrain dans la carte.
+
+void CMap::UpdateTerrain(int bx, int by, int ex, int ey)
+{
+ D3DCOLORVALUE color;
+ D3DVECTOR pos;
+ float scale, water, level, intensity;
+ int x, y;
+
+ if ( m_fixImage[0] != 0 ) return; // image fixe ?
+ if ( !m_engine->OpenImage("map.tga") ) return;
+ m_engine->LoadImage();
+
+ scale = m_terrain->RetScaleRelief();
+ water = m_water->RetLevel();
+ color.a = 0.0f;
+
+ for ( y=by ; y<ey ; y++ )
+ {
+ for ( x=bx ; x<ex ; x++ )
+ {
+ pos.x = ((float)x-128.0f)*m_half/128.0f;
+ pos.z = -((float)y-128.0f)*m_half/128.0f;
+ pos.y = 0.0f;
+
+ if ( pos.x >= -m_half && pos.x <= m_half &&
+ pos.z >= -m_half && pos.z <= m_half )
+ {
+ level = m_terrain->RetFloorLevel(pos, TRUE)/scale;
+ }
+ else
+ {
+ level = 1000.0f;
+ }
+
+ intensity = level/256.0f;
+ if ( intensity < 0.0f ) intensity = 0.0f;
+ if ( intensity > 1.0f ) intensity = 1.0f;
+
+ if ( level > water ) // sur l'eau ?
+ {
+ color.r = m_floorColor.r + (intensity-0.5f);
+ color.g = m_floorColor.g + (intensity-0.5f);
+ color.b = m_floorColor.b + (intensity-0.5f);
+ }
+ else // sous l'eau ?
+ {
+ color.r = m_waterColor.r + (intensity-0.5f);
+ color.g = m_waterColor.g + (intensity-0.5f);
+ color.b = m_waterColor.b + (intensity-0.5f);
+ }
+
+ m_engine->SetDot(x, y, color);
+ }
+ }
+
+ m_engine->CopyImage(); // copie avec juste le terrain dessiné
+ m_engine->CloseImage();
+}
+
+
+// Vide tous les objets.
+
+void CMap::FlushObject()
+{
+ int i;
+
+ m_totalFix = 0; // index objet fixes
+ m_totalMove = MAPMAXOBJECT-2; // index véhicules mobiles
+ m_bRadar = m_main->RetCheatRadar(); // pas de radar
+
+ for ( i=0 ; i<MAPMAXOBJECT ; i++ )
+ {
+ m_map[i].bUsed = FALSE;
+ }
+}
+
+// Met à jour un objet dans la carte.
+
+void CMap::UpdateObject(CObject* pObj)
+{
+ ObjectType type;
+ MapColor color;
+ D3DVECTOR pos;
+ FPOINT ppos;
+ float dir;
+
+ if ( !m_bEnable ) return;
+ if ( m_totalFix >= m_totalMove ) return; // table pleine ?
+
+ if ( !pObj->RetActif() ) return;
+ if ( !pObj->RetSelectable() ) return;
+ if ( pObj->RetProxyActivate() ) return;
+ if ( pObj->RetTruck() != 0 ) return;
+
+ type = pObj->RetType();
+ pos = pObj->RetPosition(0);
+ dir = -(pObj->RetAngleY(0)+PI/2.0f);
+
+ if ( m_angle != 0.0f )
+ {
+ ppos = RotatePoint(m_angle, FPOINT(pos.x, pos.z));
+ pos.x = ppos.x;
+ pos.z = ppos.y;
+ dir += m_angle;
+ }
+
+ if ( type == OBJECT_RADAR )
+ {
+ m_bRadar = TRUE; // radar existe
+ }
+
+ color = MAPCOLOR_NULL;
+ if ( type == OBJECT_BASE )
+ {
+ color = MAPCOLOR_BASE;
+ }
+ if ( type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER||
+ 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_TARGET1 ||
+ type == OBJECT_START ||
+ type == OBJECT_END || // objet fixe ?
+ type == OBJECT_TEEN28 || // bouteille ?
+ type == OBJECT_TEEN34 ) // caillou ?
+ {
+ color = MAPCOLOR_FIX;
+ }
+ if ( type == OBJECT_BBOX ||
+ type == OBJECT_KEYa ||
+ type == OBJECT_KEYb ||
+ type == OBJECT_KEYc ||
+ type == OBJECT_KEYd )
+ {
+ color = MAPCOLOR_BBOX;
+ }
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_APOLLO2 ) // véhicule mobile ?
+ {
+ color = MAPCOLOR_MOVE;
+ }
+ if ( type == OBJECT_ANT ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_SPIDER ) // ennemi mobile ?
+ {
+ color = MAPCOLOR_ALIEN;
+ }
+ if ( type == OBJECT_WAYPOINT ||
+ type == OBJECT_FLAGb )
+ {
+ color = MAPCOLOR_WAYPOINTb;
+ }
+ if ( type == OBJECT_FLAGr )
+ {
+ color = MAPCOLOR_WAYPOINTr;
+ }
+ if ( type == OBJECT_FLAGg )
+ {
+ color = MAPCOLOR_WAYPOINTg;
+ }
+ if ( type == OBJECT_FLAGy )
+ {
+ color = MAPCOLOR_WAYPOINTy;
+ }
+ if ( type == OBJECT_FLAGv )
+ {
+ color = MAPCOLOR_WAYPOINTv;
+ }
+
+ if ( color == MAPCOLOR_NULL ) return;
+
+ if ( m_fixImage[0] != 0 && !m_bDebug ) // carte avec image fixe ?
+ {
+ if ( (type == OBJECT_TEEN28 ||
+ type == OBJECT_TEEN34 ) &&
+ m_mode == 0 ) return;
+
+ if ( type != OBJECT_TEEN28 &&
+ type != OBJECT_TEEN34 &&
+ color != MAPCOLOR_MOVE ) return;
+ }
+
+ if ( pObj->RetSelect() )
+ {
+ m_map[MAPMAXOBJECT-1].type = type;
+ m_map[MAPMAXOBJECT-1].object = pObj;
+ m_map[MAPMAXOBJECT-1].color = color;
+ m_map[MAPMAXOBJECT-1].pos.x = pos.x;
+ m_map[MAPMAXOBJECT-1].pos.y = pos.z;
+ m_map[MAPMAXOBJECT-1].dir = dir;
+ m_map[MAPMAXOBJECT-1].bUsed = TRUE;
+ }
+ else
+ {
+ if ( color == MAPCOLOR_BASE ||
+ color == MAPCOLOR_FIX )
+ {
+ m_map[m_totalFix].type = type;
+ m_map[m_totalFix].object = pObj;
+ m_map[m_totalFix].color = color;
+ m_map[m_totalFix].pos.x = pos.x;
+ m_map[m_totalFix].pos.y = pos.z;
+ m_map[m_totalFix].dir = dir;
+ m_map[m_totalFix].bUsed = TRUE;
+ m_totalFix ++;
+ }
+ else
+ {
+ m_map[m_totalMove].type = type;
+ m_map[m_totalMove].object = pObj;
+ m_map[m_totalMove].color = color;
+ m_map[m_totalMove].pos.x = pos.x;
+ m_map[m_totalMove].pos.y = pos.z;
+ m_map[m_totalMove].dir = dir;
+ m_map[m_totalMove].bUsed = TRUE;
+ m_totalMove --;
+ }
+ }
+}
+
diff --git a/src/map.h b/src/map.h
new file mode 100644
index 0000000..f5c9b31
--- /dev/null
+++ b/src/map.h
@@ -0,0 +1,126 @@
+// map.h
+
+#ifndef _MAP_H_
+#define _MAP_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CTerrain;
+class CWater;
+class CObject;
+class CRobotMain;
+
+enum ObjectType;
+
+
+
+#define MAPMAXOBJECT 100
+
+enum MapColor
+{
+ MAPCOLOR_NULL,
+ MAPCOLOR_BASE,
+ MAPCOLOR_FIX,
+ MAPCOLOR_MOVE,
+ MAPCOLOR_ALIEN,
+ MAPCOLOR_WAYPOINTb,
+ MAPCOLOR_WAYPOINTr,
+ MAPCOLOR_WAYPOINTg,
+ MAPCOLOR_WAYPOINTy,
+ MAPCOLOR_WAYPOINTv,
+ MAPCOLOR_BBOX,
+};
+
+typedef struct
+{
+ char bUsed;
+ CObject* object;
+ MapColor color;
+ ObjectType type;
+ FPOINT pos;
+ float dir;
+}
+MapObject;
+
+
+
+class CMap : public CControl
+{
+public:
+ CMap(CInstanceManager* iMan);
+ ~CMap();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ BOOL EventProcess(const Event &event);
+ void Draw();
+
+ void UpdateTerrain();
+ void UpdateTerrain(int bx, int by, int ex, int ey);
+
+ void SetFixImage(char *filename);
+ BOOL RetFixImage();
+
+ void SetOffset(float ox, float oy);
+ void SetAngle(float angle);
+ void SetMode(int mode);
+ void SetToy(BOOL bToy);
+ void SetDebug(BOOL bDebug);
+
+ void SetZoom(float value);
+ float RetZoom();
+
+ void SetEnable(BOOL bEnable);
+ BOOL RetEnable();
+
+ void SetFloorColor(D3DCOLORVALUE color);
+ void SetWaterColor(D3DCOLORVALUE color);
+
+ void FlushObject();
+ void UpdateObject(CObject* pObj);
+
+ CObject* DetectObject(FPOINT pos, BOOL &bInMap);
+ void SetHilite(CObject* pObj);
+
+protected:
+ FPOINT AdjustOffset(FPOINT offset);
+ void SelectObject(FPOINT pos);
+ FPOINT MapInter(FPOINT pos, float dir);
+ void DrawFocus(FPOINT pos, float dir, ObjectType type, MapColor color);
+ void DrawObject(FPOINT pos, float dir, ObjectType type, MapColor color, BOOL bSelect, BOOL bHilite);
+ void DrawObjectIcon(FPOINT pos, FPOINT dim, MapColor color, ObjectType type, BOOL bHilite);
+ void DrawHilite(FPOINT pos);
+ void DrawTriangle(FPOINT p1, FPOINT p2, FPOINT p3, FPOINT uv1, FPOINT uv2);
+ void DrawPenta(FPOINT p1, FPOINT p2, FPOINT p3, FPOINT p4, FPOINT p5, FPOINT uv1, FPOINT uv2);
+ void DrawVertex(FPOINT uv1, FPOINT uv2, float zoom);
+
+protected:
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CRobotMain* m_main;
+
+ BOOL m_bEnable;
+ float m_time;
+ float m_half;
+ float m_zoom;
+ FPOINT m_offset;
+ float m_angle;
+ D3DCOLORVALUE m_floorColor;
+ D3DCOLORVALUE m_waterColor;
+ MapObject m_map[MAPMAXOBJECT];
+ int m_totalFix;
+ int m_totalMove;
+ int m_hiliteRank;
+ FPOINT m_mapPos;
+ FPOINT m_mapDim;
+ BOOL m_bRadar;
+ char m_fixImage[100];
+ int m_mode;
+ BOOL m_bToy;
+ BOOL m_bDebug;
+};
+
+
+#endif //_MAP_H_
diff --git a/src/math3d.cpp b/src/math3d.cpp
new file mode 100644
index 0000000..75e3951
--- /dev/null
+++ b/src/math3d.cpp
@@ -0,0 +1,1026 @@
+// math3d.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <math.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "D3DUtil.h"
+#include "math3d.h"
+
+
+
+// Retourne TRUE si 2 nombres sont presques égaux.
+
+BOOL IsEqual(float a, float b)
+{
+ return Abs(a-b) < CHOUIA;
+}
+
+
+// Retourne la valeur minimale.
+
+inline float Min(float a, float b)
+{
+ if ( a <= b ) return a;
+ else return b;
+}
+
+inline float Min(float a, float b, float c)
+{
+ return Min( Min(a,b), c );
+}
+
+inline float Min(float a, float b, float c, float d)
+{
+ return Min( Min(a,b), 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 );
+}
+
+
+// Retourne la valeur maximale.
+
+inline float Max(float a, float b)
+{
+ if ( a >= b ) return a;
+ else return b;
+}
+
+inline float Max(float a, float b, float c)
+{
+ return Max( Max(a,b), c );
+}
+
+inline float Max(float a, float b, float c, float d)
+{
+ return Max( Max(a,b), 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 );
+}
+
+
+// Retourne la valeur normalisée (0..1).
+
+inline float Norm(float a)
+{
+ if ( a < 0.0f ) return 0.0f;
+ if ( a > 1.0f ) return 1.0f;
+ return a;
+}
+
+
+// Retourne la valeur absolue d'un nombre.
+
+inline float Abs(float a)
+{
+ return (float)fabs(a);
+}
+
+
+// Permute deux entiers.
+
+inline void Swap(int &a, int &b)
+{
+ int c;
+
+ c = a;
+ a = b;
+ b = c;
+}
+
+// Permute deux réels.
+
+inline void Swap(float &a, float &b)
+{
+ float c;
+
+ c = a;
+ a = b;
+ b = c;
+}
+
+// Permute deux points.
+
+inline void Swap(FPOINT &a, FPOINT &b)
+{
+ FPOINT c;
+
+ c = a;
+ a = b;
+ b = c;
+}
+
+// Retourne le modulo d'un nombre flottant.
+// Mod(8.1, 4) = 0.1
+// Mod(n, 1) = partie fractionnaire de n
+
+inline float Mod(float a, float m)
+{
+ return a - ((int)(a/m))*m;
+}
+
+// Retourne un angle normalisé, c'est-à-dire compris entre
+// 0 et 2*PI.
+
+inline float NormAngle(float angle)
+{
+ angle = Mod(angle, PI*2.0f);
+ if ( angle < 0.0f )
+ {
+ return PI*2.0f + angle;
+ }
+ else
+ {
+ return angle;
+ }
+}
+
+// Teste si un angle est compris entre 2 bornes.
+
+BOOL TestAngle(float angle, float min, float max)
+{
+ angle = NormAngle(angle);
+ min = NormAngle(min);
+ max = NormAngle(max);
+
+ if ( min > max )
+ {
+ return ( angle <= max || angle >= min );
+ }
+ else
+ {
+ return ( angle >= min && angle <= max );
+ }
+}
+
+
+// Calcule l'angle permettant de tourner de l'angle a vers l'angle g.
+// Un angle positif est anti-horaire (CCW).
+
+float Direction(float a, float g)
+{
+ a = NormAngle(a);
+ g = NormAngle(g);
+
+ if ( a < g )
+ {
+ if ( a+PI*2.0f-g < g-a ) a += PI*2.0f;
+ }
+ else
+ {
+ if ( g+PI*2.0f-a < a-g ) g += PI*2.0f;
+ }
+ return (g-a);
+}
+
+
+// Fait tourner un point autour d'un centre.
+// L'angle est exprimé en radians.
+// Un angle positif est anti-horaire (CCW).
+
+FPOINT RotatePoint(FPOINT center, float angle, FPOINT p)
+{
+ FPOINT a, b;
+
+ a.x = p.x-center.x;
+ a.y = p.y-center.y;
+
+ b.x = a.x*cosf(angle) - a.y*sinf(angle);
+ b.y = a.x*sinf(angle) + a.y*cosf(angle);
+
+ b.x += center.x;
+ b.y += center.y;
+ return b;
+}
+
+// Fait tourner un point autour de l'origine.
+// L'angle est exprimé en radians.
+// Un angle positif est anti-horaire (CCW).
+
+FPOINT RotatePoint(float angle, FPOINT p)
+{
+ FPOINT a;
+
+ a.x = p.x*cosf(angle) - p.y*sinf(angle);
+ a.y = p.x*sinf(angle) + p.y*cosf(angle);
+
+ return a;
+}
+
+// Fait tourner un vecteur (dist;0).
+// L'angle est exprimé en radians.
+// Un angle positif est anti-horaire (CCW).
+
+FPOINT RotatePoint(float angle, float dist)
+{
+ FPOINT a;
+
+ a.x = dist*cosf(angle);
+ a.y = dist*sinf(angle);
+
+ return a;
+}
+
+// Calcule l'angle d'un triangle rectangle.
+// L'angle est anti-horaire (CCW), compris entre 0 et 2*PI.
+// Pour obtenir un angle horaire (CW), il suffit de passer -y.
+//
+// ^
+// |
+// y o----o
+// | / |
+// |/)a |
+// ----o----o-->
+// | x
+// |
+
+float RotateAngle(float x, float y)
+{
+#if 1
+ if ( x == 0.0f && y == 0.0f ) return 0.0f;
+
+ if ( x >= 0.0f )
+ {
+ if ( y >= 0.0f )
+ {
+ if ( x > y ) return atanf(y/x);
+ else return PI*0.5f - atanf(x/y);
+ }
+ else
+ {
+ if ( x > -y ) return PI*2.0f + atanf(y/x);
+ else return PI*1.5f - atanf(x/y);
+ }
+ }
+ else
+ {
+ if ( y >= 0.0f )
+ {
+ if ( -x > y ) return PI*1.0f + atanf(y/x);
+ else return PI*0.5f - atanf(x/y);
+ }
+ else
+ {
+ if ( -x > -y ) return PI*1.0f + atanf(y/x);
+ else return PI*1.5f - atanf(x/y);
+ }
+ }
+#else
+ float angle;
+
+ if ( x == 0.0f )
+ {
+ if ( y > 0.0f )
+ {
+ return 90.0f*PI/180.0f;
+ }
+ else
+ {
+ return 270.0f*PI/180.0f;
+ }
+ }
+ else
+ {
+ angle = atanf(y/x);
+ if ( x < 0.0f )
+ {
+ angle += PI;
+ }
+ return angle;
+ }
+#endif
+}
+
+// Calcule l'angle entre deux points et un centre.
+// L'angle est exprimé en radians.
+// Un angle positif est anti-horaire (CCW).
+
+float RotateAngle(FPOINT center, FPOINT p1, FPOINT p2)
+{
+ float a1, a2, a;
+
+ if ( p1.x == center.x &&
+ p1.y == center.y ) return 0;
+
+ if ( p2.x == center.x &&
+ p2.y == center.y ) return 0;
+
+ a1 = asinf((p1.y-center.y)/Length(p1,center));
+ a2 = asinf((p2.y-center.y)/Length(p2,center));
+
+ if ( p1.x < center.x ) a1 = PI-a1;
+ if ( p2.x < center.x ) a2 = PI-a2;
+
+ a = a2-a1;
+ if ( a < 0 ) a += PI*2;
+ return a;
+}
+
+// Retourne py placé sur la droite ab.
+
+float MidPoint(FPOINT a, FPOINT b, float px)
+{
+ if ( Abs(a.x-b.x) < CHOUIA )
+ {
+ if ( a.y < b.y ) return BEAUCOUP;
+ else return -BEAUCOUP;
+ }
+ return (b.y-a.y)*(px-a.x)/(b.x-a.x)+a.y;
+}
+
+// Avance de "dist" le long du segment p1-p2.
+
+D3DVECTOR SegmentDist(const D3DVECTOR &p1, const D3DVECTOR &p2, float dist)
+{
+ return p1+Normalize(p2-p1)*dist;
+}
+
+// Vérifie si un point est dans un triangle.
+
+BOOL IsInsideTriangle(FPOINT a, FPOINT b, FPOINT c, FPOINT p)
+{
+ float n, m;
+
+ if ( p.x < a.x && p.x < b.x && p.x < c.x ) return FALSE;
+ if ( p.x > a.x && p.x > b.x && p.x > c.x ) return FALSE;
+ if ( p.y < a.y && p.y < b.y && p.y < c.y ) return FALSE;
+ if ( p.y > a.y && p.y > b.y && p.y > c.y ) return FALSE;
+
+ if ( a.x > b.x ) Swap(a,b);
+ if ( a.x > c.x ) Swap(a,c);
+ if ( c.x < a.x ) Swap(c,a);
+ if ( c.x < b.x ) Swap(c,b);
+
+ n = MidPoint(a, b, p.x);
+ m = MidPoint(a, c, p.x);
+ if ( (n>p.y||p.y>m) && (n<p.y||p.y<m) ) return FALSE;
+
+ n = MidPoint(c, b, p.x);
+ m = MidPoint(c, a, p.x);
+ if ( (n>p.y||p.y>m) && (n<p.y||p.y<m) ) return FALSE;
+
+ return TRUE;
+}
+
+// Calcule l'intersection "i" de la droite "de" avec le plan "abc".
+
+BOOL Intersect(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c,
+ D3DVECTOR d, D3DVECTOR e, D3DVECTOR &i)
+{
+ float d1, d2;
+
+ 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)) +
+ (d.z-a.z)*((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y));
+
+ d2 = (d.x-e.x)*((b.y-a.y)*(c.z-a.z)-(c.y-a.y)*(b.z-a.z)) -
+ (d.y-e.y)*((b.x-a.x)*(c.z-a.z)-(c.x-a.x)*(b.z-a.z)) +
+ (d.z-e.z)*((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y));
+
+ if ( d2 == 0 ) return FALSE;
+
+ i.x = d.x + d1/d2*(e.x-d.x);
+ i.y = d.y + d1/d2*(e.y-d.y);
+ i.z = d.z + d1/d2*(e.z-d.z);
+ return TRUE;
+}
+
+// Calcule l'intersection de la droite passant par p(x,z) parallèle
+// à l'axe y, avec le plan abc. Retourne p.y.
+
+BOOL IntersectY(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR &p)
+{
+#if 0
+ D3DVECTOR d,e,i;
+
+ d.x = p.x;
+ d.y = 0.0f;
+ d.z = p.z;
+ e.x = p.x;
+ e.y = 1.0f;
+ e.z = p.z;
+ if ( !Intersect(a,b,c,d,e,i) ) return FALSE;
+ p.y = i.y;
+ return TRUE;
+#else
+ float d, d1, d2;
+
+ d = (b.x-a.x)*(c.z-a.z) - (c.x-a.x)*(b.z-a.z);
+ d1 = (p.x-a.x)*(c.z-a.z) - (c.x-a.x)*(p.z-a.z);
+ d2 = (b.x-a.x)*(p.z-a.z) - (p.x-a.x)*(b.z-a.z);
+
+ if ( d == 0.0f ) return FALSE;
+
+ p.y = a.y + d1/d*(b.y-a.y) + d2/d*(c.y-a.y);
+ return TRUE;
+#endif
+}
+
+
+// Fait tourner un point autour d'un centre dans le plan.
+// L'angle est exprimé en radians.
+// Un angle positif est anti-horaire (CCW).
+
+void RotatePoint(float cx, float cy, float angle, float &px, float &py)
+{
+ float ax, ay;
+
+ px -= cx;
+ py -= cy;
+
+ ax = px*cosf(angle) - py*sinf(angle);
+ ay = px*sinf(angle) + py*cosf(angle);
+
+ px = cx+ax;
+ py = cy+ay;
+}
+
+// Fait tourner un point autour d'un centre dans l'espace.
+// L'angles sont exprimés en radians.
+// Un angle positif est anti-horaire (CCW).
+
+void RotatePoint(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p)
+{
+ D3DVECTOR a, b;
+
+ p.x -= center.x;
+ p.y -= center.y;
+ p.z -= center.z;
+
+ 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);
+
+ p.x = center.x+b.x;
+ p.y = center.y+b.y;
+ p.z = center.z+b.z;
+}
+
+// Fait tourner un point autour d'un centre dans l'espace.
+// L'angles sont exprimés en radians.
+// Un angle positif est anti-horaire (CCW).
+
+void RotatePoint2(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p)
+{
+ D3DVECTOR a, b;
+
+ p.x -= center.x;
+ p.y -= center.y;
+ p.z -= center.z;
+
+ a.x = p.x*cosf(angleH) - p.z*sinf(angleH);
+ a.y = p.y;
+ a.z = p.x*sinf(angleH) + p.z*cosf(angleH);
+
+ b.x = a.x;
+ b.y = a.z*sinf(angleV) + a.y*cosf(angleV);
+ b.z = a.z*cosf(angleV) - a.y*sinf(angleV);
+
+ p.x = center.x+b.x;
+ p.y = center.y+b.y;
+ p.z = center.z+b.z;
+}
+
+// Calcul le point de vue permettant de regarder un centre selon deux
+// angles et à une certaine distance.
+
+D3DVECTOR RotateView(D3DVECTOR center, float angleH, float angleV, float dist)
+{
+ D3DMATRIX mat1, mat2, mat;
+ D3DVECTOR eye;
+
+ D3DUtil_SetRotateZMatrix(mat1, -angleV);
+ D3DUtil_SetRotateYMatrix(mat2, -angleH);
+ D3DMath_MatrixMultiply(mat, mat1, mat2);
+
+ eye.x = 0.0f+dist;
+ eye.y = 0.0f;
+ eye.z = 0.0f;
+ eye = Transform(mat, eye);
+
+ return eye+center;
+}
+
+// Calcule le point d'arrivée.
+
+D3DVECTOR LookatPoint( D3DVECTOR eye, float angleH, float angleV, float length )
+{
+ D3DVECTOR lookat;
+
+ lookat = eye;
+ lookat.z += length;
+
+//? RotatePoint(eye.x, eye.z, angleH, lookat.x, lookat.z);
+//? RotatePoint(eye.z, eye.y, angleV, lookat.z, lookat.y);
+ RotatePoint(eye, angleH, angleV, lookat);
+
+ return lookat;
+}
+
+
+// Retourne la distance entre deux points.
+
+inline float Length(FPOINT a, FPOINT b)
+{
+ return sqrtf( (a.x-b.x)*(a.x-b.x) +
+ (a.y-b.y)*(a.y-b.y) );
+}
+
+// Retourne l'hypothénuse d'un triangle rectangle.
+
+inline float Length(float x, float y)
+{
+ return sqrtf( (x*x) + (y*y) );
+}
+
+// Retourne la longueur d'un vecteur.
+
+inline float Length(const D3DVECTOR &u)
+{
+ return sqrtf( (u.x*u.x) + (u.y*u.y) + (u.z*u.z) );
+}
+
+// Retourne la distance entre deux points.
+
+inline float Length(const D3DVECTOR &a, const D3DVECTOR &b)
+{
+ return sqrtf( (a.x-b.x)*(a.x-b.x) +
+ (a.y-b.y)*(a.y-b.y) +
+ (a.z-b.z)*(a.z-b.z) );
+}
+
+// Retourne la distance "à plat" entre deux points.
+
+inline float Length2d(const D3DVECTOR &a, const D3DVECTOR &b)
+{
+ return sqrtf( (a.x-b.x)*(a.x-b.x) +
+ (a.z-b.z)*(a.z-b.z) );
+}
+
+
+// Retourne l'angle formé par deux vecteurs.
+
+float Angle( D3DVECTOR u, D3DVECTOR v )
+{
+#if 0
+ return acosf( Abs(u.x*v.x + u.y*v.y + u.z*v.z) / (Length(u)*Length(v)) );
+#endif
+#if 0
+ float d;
+ d = (u.y*v.z-u.z*v.y) + (u.z*v.x-u.x*v.z) + (u.x*v.y-u.y*v.x);
+ return asinf( Abs(d) / (Length(u)*Length(v)) );
+#endif
+#if 0
+ return asinf( Length(Cross(u,v)) / (Length(u)*Length(v)) );
+#endif
+#if 1
+ float len, a, b;
+
+ len = Length(u)*Length(v);
+ a = acosf( (u.x*v.x + u.y*v.y + u.z*v.z) / len );
+ b = asinf( Length(Cross(u,v)) / len );
+ return a;
+#endif
+}
+
+// Retourne le produit vectoriel de deux vecteurs.
+
+inline D3DVECTOR Cross( D3DVECTOR u, D3DVECTOR v )
+{
+ return D3DVECTOR( u.y*v.z - u.z*v.y,
+ u.z*v.x - u.x*v.z,
+ u.x*v.y - u.y*v.x );
+}
+
+// Retourne le vecteur normal d'une face triangulaire.
+
+D3DVECTOR ComputeNormal( D3DVECTOR p1, D3DVECTOR p2, D3DVECTOR p3 )
+{
+ D3DVECTOR u, v;
+
+ u = D3DVECTOR( p3.x-p1.x, p3.y-p1.y, p3.z-p1.z );
+ v = D3DVECTOR( p2.x-p1.x, p2.y-p1.y, p2.z-p1.z );
+
+ return Normalize(Cross(u, v));
+}
+
+
+// Transforme un point selon une matrice, exactement de la
+// même façon que Direct3D.
+
+D3DVECTOR Transform(const D3DMATRIX &m, D3DVECTOR p)
+{
+ D3DVECTOR pp;
+
+ pp.x = p.x*m._11 + p.y*m._21 + p.z*m._31 + m._41;
+ pp.y = p.x*m._12 + p.y*m._22 + p.z*m._32 + m._42;
+ pp.z = p.x*m._13 + p.y*m._23 + p.z*m._33 + m._43;
+
+ return pp;
+}
+
+
+// Calcule la projection d'un point P sur une droite AB.
+
+D3DVECTOR Projection(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &p)
+{
+ float k;
+
+ k = (b.x-a.x)*(p.x-a.x) + (b.y-a.y)*(p.y-a.y) + (b.z-a.z)*(p.z-a.z);
+ k /= (b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y) + (b.z-a.z)*(b.z-a.z);
+
+ return a + k*(b-a);
+}
+
+// Plaque la texture dans le plan xz.
+
+void MappingObject(D3DVERTEX2* pVertices, int nb, float scale)
+{
+ int i;
+
+ for ( i=0 ; i<nb ; i++ )
+ {
+ pVertices[i].tu = pVertices[i].x*scale;
+ pVertices[i].tv = pVertices[i].z*scale;
+ }
+}
+
+// Adoucit les normales.
+
+void SmoothObject(D3DVERTEX2* pVertices, int nb)
+{
+ char* bDone;
+ int index[100];
+ int i, j, rank;
+ D3DVECTOR sum;
+
+ bDone = (char*)malloc(nb*sizeof(char));
+ ZeroMemory(bDone, nb*sizeof(char));
+
+ for ( i=0 ; i<nb ; i++ )
+ {
+ bDone[i] = TRUE;
+ rank = 0;
+ index[rank++] = i;
+
+ for ( j=0 ; j<nb ; j++ )
+ {
+ if ( bDone[j] ) continue;
+ if ( pVertices[j].x == pVertices[i].x &&
+ pVertices[j].y == pVertices[i].y &&
+ pVertices[j].z == pVertices[i].z )
+ {
+ bDone[j] = TRUE;
+ index[rank++] = j;
+ if ( rank >= 100 ) break;
+ }
+ }
+
+ sum.x = 0;
+ sum.y = 0;
+ sum.z = 0;
+ for ( j=0 ; j<rank ; j++ )
+ {
+ sum.x += pVertices[index[j]].nx;
+ sum.y += pVertices[index[j]].ny;
+ sum.z += pVertices[index[j]].nz;
+ }
+ sum = Normalize(sum);
+
+ for ( j=0 ; j<rank ; j++ )
+ {
+ pVertices[index[j]].nx = sum.x;
+ pVertices[index[j]].ny = sum.y;
+ pVertices[index[j]].nz = sum.z;
+ }
+ }
+
+ free(bDone);
+}
+
+
+
+// Calcule les paramètres a et b du segment passant par
+// les points p1 et p2, sachant que :
+// f(x) = ax+b
+// Retourne FALSE si la droite est verticale.
+
+BOOL LineFunction(FPOINT p1, FPOINT p2, float &a, float &b)
+{
+ if ( D3DMath_IsZero(p1.x-p2.x) )
+ {
+ a = g_HUGE; // pente infinie !
+ b = p2.x;
+ return FALSE;
+ }
+
+ a = (p2.y-p1.y)/(p2.x-p1.x);
+ b = p2.y - p2.x*a;
+ return TRUE;
+}
+
+
+// Calcule la distance entre un plan ABC et un point P.
+
+float DistancePlanPoint(const D3DVECTOR &a, const D3DVECTOR &b,
+ const D3DVECTOR &c, const D3DVECTOR &p)
+{
+ D3DVECTOR n;
+ float aa,bb,cc,dd;
+
+ n = ComputeNormal(a,b,c);
+
+ aa = n.x;
+ bb = n.y;
+ cc = n.z;
+ dd = -(n.x*a.x + n.y*a.y + n.z*a.z);
+
+ return Abs(aa*p.x + bb*p.y + cc*p.z + dd);
+}
+
+// Vérifie si deux plans définis par 3 points font partie
+// du même plan.
+
+BOOL IsSamePlane(D3DVECTOR *plan1, D3DVECTOR *plan2)
+{
+ D3DVECTOR n1, n2;
+ float dist;
+
+ n1 = ComputeNormal(plan1[0], plan1[1], plan1[2]);
+ n2 = ComputeNormal(plan2[0], plan2[1], plan2[2]);
+
+ if ( Abs(n1.x-n2.x) > 0.1f ||
+ Abs(n1.y-n2.y) > 0.1f ||
+ Abs(n1.z-n2.z) > 0.1f ) return FALSE;
+
+ dist = DistancePlanPoint(plan1[0], plan1[1], plan1[2], plan2[0]);
+ if ( dist > 0.1f ) return FALSE;
+
+ return TRUE;
+}
+
+
+// Calcule la matrice permettant de faire 3 rotations
+// dans l'ordre X, Z et Y.
+// >>>>>> A OPTIMISER !!!
+
+void MatRotateXZY(D3DMATRIX &mat, D3DVECTOR angle)
+{
+ D3DMATRIX temp;
+
+ D3DUtil_SetRotateXMatrix(temp, angle.x);
+ D3DUtil_SetRotateZMatrix(mat, angle.z);
+ D3DMath_MatrixMultiply(mat, mat, temp);
+ D3DUtil_SetRotateYMatrix(temp, angle.y);
+ D3DMath_MatrixMultiply(mat, mat, temp); // X-Z-Y
+}
+
+// Calcule la matrice permettant de faire 3 rotations
+// dans l'ordre Z, X et Y.
+// >>>>>> A OPTIMISER !!!
+
+void MatRotateZXY(D3DMATRIX &mat, D3DVECTOR angle)
+{
+ D3DMATRIX temp;
+
+ D3DUtil_SetRotateZMatrix(temp, angle.z);
+ D3DUtil_SetRotateXMatrix(mat, angle.x);
+ D3DMath_MatrixMultiply(mat, mat, temp);
+ D3DUtil_SetRotateYMatrix(temp, angle.y);
+ D3DMath_MatrixMultiply(mat, mat, temp); // Z-X-Y
+}
+
+
+// Retourne une valeur aléatoire comprise entre 0 et 1.
+
+float Rand()
+{
+ return (float)rand()/RAND_MAX;
+}
+
+
+// Gestion de la zone neutre d'un joystick.
+
+// in: -1 0 1
+// --|-------|----o----|-------|-->
+// <---->
+// dead
+// out: -1 0 0 1
+
+float Neutral(float value, float dead)
+{
+ if ( Abs(value) <= dead )
+ {
+ return 0.0f;
+ }
+ else
+ {
+ if ( value > 0.0f ) return (value-dead)/(1.0f-dead);
+ else return (value+dead)/(1.0f-dead);
+ }
+}
+
+
+// Calcule une valeur (radians) proportionnelle comprise
+// entre a et b (degrés).
+
+inline float Prop(int a, int b, float p)
+{
+ float aa, bb;
+
+ aa = (float)a*PI/180.0f;
+ bb = (float)b*PI/180.0f;
+
+ return aa+p*(bb-aa);
+}
+
+// Fait progresser mollement une valeur souhaitée à partir de
+// sa valeur actuelle. Plus le temps est grand et plus la
+// progression est rapide.
+
+float Smooth(float actual, float hope, float time)
+{
+ float futur;
+
+ futur = actual + (hope-actual)*time;
+
+ if ( hope > actual )
+ {
+ if ( futur > hope ) futur = hope;
+ }
+ if ( hope < actual )
+ {
+ if ( futur < hope ) futur = hope;
+ }
+
+ return futur;
+}
+
+
+// Fait reboudir un mouvement quelconque.
+
+// out
+// |
+// 1+------o-------o---
+// | o | o o | | bounce
+// | o | o---|---
+// | o | |
+// | o | |
+// -o------|-------+----> progress
+// 0| | 1
+// |<---->|middle
+
+float Bounce(float progress, float middle, float bounce)
+{
+ if ( progress < middle )
+ {
+ progress = progress/middle; // 0..1
+ return 0.5f+sinf(progress*PI-PI/2.0f)/2.0f;
+ }
+ else
+ {
+ progress = (progress-middle)/(1.0f-middle); // 0..1
+ return (1.0f-bounce/2.0f)+sinf((0.5f+progress*2.0f)*PI)*(bounce/2.0f);
+ }
+}
+
+
+// Retourne la couleur D3DCOLOR correspondante.
+
+D3DCOLOR RetColor(float intensity)
+{
+ D3DCOLOR 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;
+}
+
+// Retourne la couleur D3DCOLOR correspondante.
+
+D3DCOLOR RetColor(D3DCOLORVALUE intensity)
+{
+ D3DCOLOR 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;
+}
+
+// Retourne la couleur D3DCOLORVALUE correspondante.
+
+D3DCOLORVALUE RetColor(D3DCOLOR intensity)
+{
+ D3DCOLORVALUE 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;
+}
+
+
+// Conversion RGB vers HSV.
+
+void RGB2HSV(D3DCOLORVALUE src, ColorHSV &dest)
+{
+ float min, max, delta;
+
+ min = Min(src.r, src.g, src.b);
+ max = Max(src.r, src.g, src.b);
+
+ dest.v = max; // intensité
+
+ if ( max == 0.0f )
+ {
+ dest.s = 0.0f; // saturation
+ dest.h = 0.0f; // teinte indéfinie !
+ }
+ 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; // en degrés
+ if ( dest.h < 0.0f ) dest.h += 360.0f;
+ dest.h /= 360.0f; // 0..1
+ }
+}
+
+// Conversion HSV vers RGB.
+
+void HSV2RGB(ColorHSV src, D3DCOLORVALUE &dest)
+{
+ int i;
+ float f,v,p,q,t;
+
+ src.h = Norm(src.h)*360.0f;
+ src.s = Norm(src.s);
+ src.v = Norm(src.v);
+
+ if ( src.s == 0.0f ) // saturation nulle ?
+ {
+ dest.r = src.v;
+ dest.g = src.v;
+ dest.b = src.v; // gris
+ }
+ else
+ {
+ if ( src.h == 360.0f ) src.h = 0.0f;
+ src.h /= 60.0f;
+ i = (int)src.h; // partie entière (0..5)
+ f = src.h-i; // partie fractionnaire
+
+ 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/math3d.h b/src/math3d.h
new file mode 100644
index 0000000..083e418
--- /dev/null
+++ b/src/math3d.h
@@ -0,0 +1,90 @@
+// math3d.h
+
+#ifndef _MATH3D_H_
+#define _MATH3D_H_
+
+
+#define STRICT
+#define D3D_OVERLOADS
+#include <math.h>
+
+
+#define PI 3.14159265358979323846f
+#define CHOUIA 1e-6f
+#define BEAUCOUP 1e6f
+
+
+
+extern BOOL IsEqual(float a, float b);
+
+extern float Min(float a, float b);
+extern float Min(float a, float b, float c);
+extern float Min(float a, float b, float c, float d);
+extern float Min(float a, float b, float c, float d, float e);
+
+extern float Max(float a, float b);
+extern float Max(float a, float b, float c);
+extern float Max(float a, float b, float c, float d);
+extern float Max(float a, float b, float c, float d, float e);
+
+extern float Norm(float a);
+extern float Abs(float a);
+
+extern void Swap(int &a, int &b);
+extern void Swap(float &a, float &b);
+extern void Swap(FPOINT &a, FPOINT &b);
+
+extern float Mod(float a, float m);
+extern float NormAngle(float angle);
+extern BOOL TestAngle(float angle, float min, float max);
+
+extern float Direction(float a, float g);
+extern FPOINT RotatePoint(FPOINT center, float angle, FPOINT p);
+extern FPOINT RotatePoint(float angle, FPOINT p);
+extern FPOINT RotatePoint(float angle, float dist);
+extern float RotateAngle(float x, float y);
+extern float RotateAngle(FPOINT center, FPOINT p1, FPOINT p2);
+extern float MidPoint(FPOINT a, FPOINT b, float px);
+extern D3DVECTOR SegmentDist(const D3DVECTOR &p1, const D3DVECTOR &p2, float dist);
+extern BOOL IsInsideTriangle(FPOINT a, FPOINT b, FPOINT c, FPOINT p);
+extern BOOL Intersect(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR d, D3DVECTOR e, D3DVECTOR &i);
+extern BOOL IntersectY(D3DVECTOR a, D3DVECTOR b, D3DVECTOR c, D3DVECTOR &p);
+extern void RotatePoint(float cx, float cy, float angle, float &px, float &py);
+extern void RotatePoint(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p);
+extern void RotatePoint2(D3DVECTOR center, float angleH, float angleV, D3DVECTOR &p);
+extern D3DVECTOR RotateView(D3DVECTOR center, float angleH, float angleV, float dist);
+extern D3DVECTOR LookatPoint( D3DVECTOR eye, float angleH, float angleV, float length );
+extern float Length(FPOINT a, FPOINT b);
+extern float Length(float x, float y);
+extern float Length(const D3DVECTOR &u);
+extern float Length(const D3DVECTOR &a, const D3DVECTOR &b);
+extern float Length2d(const D3DVECTOR &a, const D3DVECTOR &b);
+extern float Angle( D3DVECTOR u, D3DVECTOR v );
+extern D3DVECTOR Cross( D3DVECTOR u, D3DVECTOR v );
+extern D3DVECTOR ComputeNormal( D3DVECTOR p1, D3DVECTOR p2, D3DVECTOR p3 );
+extern D3DVECTOR Transform(const D3DMATRIX &m, D3DVECTOR p);
+extern D3DVECTOR Projection(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &p);
+
+extern void MappingObject( D3DVERTEX2* pVertices, int nb, float scale );
+extern void SmoothObject( D3DVERTEX2* pVertices, int nb );
+extern BOOL LineFunction(FPOINT p1, FPOINT p2, float &a, float &b);
+extern float DistancePlanPoint(const D3DVECTOR &a, const D3DVECTOR &b, const D3DVECTOR &c, const D3DVECTOR &p);
+extern BOOL IsSamePlane(D3DVECTOR *plan1, D3DVECTOR *plan2);
+extern void MatRotateXZY(D3DMATRIX &mat, D3DVECTOR angle);
+extern void MatRotateZXY(D3DMATRIX &mat, D3DVECTOR angle);
+
+extern float Rand();
+extern float Neutral(float value, float dead);
+
+extern float Prop(int a, int b, float p);
+extern float Smooth(float actual, float hope, float time);
+extern float Bounce(float progress, float middle=0.3f, float bounce=0.4f);
+
+extern D3DCOLOR RetColor(float intensity);
+extern D3DCOLOR RetColor(D3DCOLORVALUE intensity);
+extern D3DCOLORVALUE RetColor(D3DCOLOR intensity);
+
+extern void RGB2HSV(D3DCOLORVALUE src, ColorHSV &dest);
+extern void HSV2RGB(ColorHSV src, D3DCOLORVALUE &dest);
+
+#endif //_MATH3D_H_
diff --git a/src/metafile.cpp b/src/metafile.cpp
new file mode 100644
index 0000000..7cc9cfd
--- /dev/null
+++ b/src/metafile.cpp
@@ -0,0 +1,403 @@
+// metafile.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "language.h"
+#include "metafile.h"
+
+
+
+
+#if _FULL | _NET
+static unsigned char table_codec[23] =
+{
+ 0x85, 0x91, 0x73, 0xcf, 0xa2, 0xbb, 0xf4, 0x77,
+ 0x58, 0x39, 0x37, 0xfd, 0x2a, 0xcc, 0x5f, 0x55,
+ 0x96, 0x90, 0x07, 0xcd, 0x11, 0x88, 0x21,
+};
+
+void Codec(void* buffer, int len, int start)
+{
+ unsigned char *b = (unsigned char*)buffer;
+ int i;
+
+ for ( i=0 ; i<len ; i++ )
+ {
+ b[i] ^= table_codec[(start++)%23];
+ }
+}
+#endif
+
+#if _SCHOOL
+#if _CEEBOTDEMO
+static unsigned char table_codec[136] =
+{
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+};
+
+void Codec(void* buffer, int len, int start)
+{
+ unsigned char *b = (unsigned char*)buffer;
+ int i;
+
+ for ( i=0 ; i<len ; i++ )
+ {
+ b[i] ^= table_codec[(start++)%136];
+ }
+}
+#else
+static unsigned char table_codec[29] =
+{
+ 0x72, 0x91, 0x37, 0xdf, 0xa1, 0xcc, 0xf5, 0x67,
+ 0x53, 0x40, 0xd3, 0xed, 0x3a, 0xbb, 0x5e, 0x43,
+ 0x67, 0x9a, 0x0c, 0xed, 0x33, 0x77, 0x2f, 0xf2,
+ 0xe3, 0x42, 0x11, 0x5e, 0xc2,
+};
+
+void Codec(void* buffer, int len, int start)
+{
+ unsigned char *b = (unsigned char*)buffer;
+ int i;
+
+ for ( i=0 ; i<len ; i++ )
+ {
+ b[i] ^= table_codec[(start++)%29];
+ }
+}
+#endif
+#endif
+
+#if _DEMO
+static unsigned char table_codec[27] =
+{
+ 0x85, 0x91, 0x77, 0xcf, 0xa3, 0xbb, 0xf4, 0x77,
+ 0x58, 0x39, 0x37, 0xfd, 0x2a, 0xcc, 0x7f, 0x55,
+ 0x96, 0x80, 0x07, 0xcd, 0x11, 0x88, 0x21, 0x44,
+ 0x17, 0xee, 0xf0,
+};
+
+void Codec(void* buffer, int len, int start)
+{
+ unsigned char *b = (unsigned char*)buffer;
+ int i;
+
+ for ( i=0 ; i<len ; i++ )
+ {
+ b[i] ^= table_codec[(start++)%27];
+ }
+}
+#endif
+
+
+
+// Constructeur de l'objet.
+
+CMetaFile::CMetaFile()
+{
+ int i;
+
+ for ( i=0 ; i<METAMAX ; i++ )
+ {
+ m_list[i].stream = 0;
+ m_list[i].headers = 0;
+ }
+
+ m_bMeta = FALSE;
+ m_bOpen = FALSE;
+ m_start = 0;
+ m_pos = 0;
+ m_len = 0;
+ m_stream = 0;
+}
+
+// Destructeur de l'objet.
+
+CMetaFile::~CMetaFile()
+{
+ MetaClose();
+}
+
+
+// Teste si un fichier existe.
+
+BOOL CMetaFile::IsExist(char *metaname, char *filename)
+{
+ FILE* file;
+ int index, i;
+
+ if ( metaname[0] == 0 )
+ {
+ file = fopen(filename, "rb");
+ if ( file == NULL ) return FALSE;
+ fclose(file);
+ return TRUE;
+ }
+ else
+ {
+ index = MetaOpen(metaname);
+ if ( index == -1 ) return 1;
+
+ for ( i=0 ; i<m_list[index].total ; i++ )
+ {
+ if ( strcmp(m_list[index].headers[i].name, filename) == 0 )
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+}
+
+// Ouvre un fichier. Si le metaname est vide, on ouvre
+// normalement un fichier.
+
+int CMetaFile::Open(char *metaname, char *filename)
+{
+ int index, i;
+
+ if ( m_bOpen ) // fichier déjà ouvert ?
+ {
+ Close();
+ }
+
+ if ( metaname[0] == 0 )
+ {
+ m_stream = fopen(filename, "rb");
+ if ( m_stream == 0 ) return 1;
+ m_bOpen = TRUE;
+ m_bMeta = FALSE;
+ return 0;
+ }
+ else
+ {
+ index = MetaOpen(metaname);
+ if ( index == -1 ) return 1;
+
+ for ( i=0 ; i<m_list[index].total ; i++ )
+ {
+ if ( strcmp(m_list[index].headers[i].name, filename) == 0 )
+ {
+ m_stream = m_list[index].stream;
+ m_start = m_list[index].headers[i].start;
+ m_len = m_list[index].headers[i].len;
+ m_bOpen = TRUE;
+ m_bMeta = TRUE;
+ Seek(0);
+ return 0;
+ }
+ }
+ return 1;
+ }
+}
+
+// Retourne la longueur d'un fichier.
+
+int CMetaFile::RetLength()
+{
+ int len;
+
+ if ( !m_bOpen ) return 0;
+
+ if ( m_bMeta )
+ {
+ len = m_len;
+ }
+ else
+ {
+ fseek(m_stream, 0, SEEK_END);
+ len = ftell(m_stream);
+ fseek(m_stream, 0, SEEK_SET);
+ }
+ return len;
+}
+
+// Positionnement dans le fichier, relatif au début.
+
+int CMetaFile::Seek(int offset)
+{
+ if ( !m_bOpen ) return 1;
+
+ if ( m_bMeta )
+ {
+ m_pos = m_start+offset;
+ return fseek(m_stream, m_start+offset, SEEK_SET);
+ }
+ else
+ {
+ return fseek(m_stream, offset, SEEK_SET);
+ }
+}
+
+// Lit n bytes.
+
+int CMetaFile::Read(void *buffer, int size)
+{
+ int err;
+
+ if ( !m_bOpen ) return 1;
+
+ if ( m_bMeta )
+ {
+ err = fread(buffer, size, 1, m_stream);
+ Codec(buffer, size, m_pos);
+ m_pos += size;
+ return err;
+ }
+ else
+ {
+ return fread(buffer, size, 1, m_stream);
+ }
+}
+
+// Lit un byte.
+
+int CMetaFile::GetByte()
+{
+ BYTE b;
+
+ if ( !m_bOpen ) return 1;
+
+ b = getc(m_stream);
+ if ( m_bMeta )
+ {
+ Codec(&b, 1, m_pos);
+ m_pos += 1;
+ }
+ return b;
+}
+
+// Lit 2 bytes.
+
+int CMetaFile::GetWord()
+{
+ WORD w;
+
+ if ( !m_bOpen ) return 1;
+
+ w = getc(m_stream);
+ if ( m_bMeta )
+ {
+ Codec(&w, 2, m_pos);
+ m_pos += 2;
+ }
+ return w;
+}
+
+// Ferme le fichier.
+
+int CMetaFile::Close()
+{
+ if ( !m_bOpen ) return 1;
+
+ if ( !m_bMeta )
+ {
+ fclose(m_stream);
+ }
+ m_bOpen = FALSE;
+ m_stream = 0;
+
+ return 0;
+}
+
+
+// Ouvre un metafile. Retourne l'index ou -1.
+
+int CMetaFile::MetaOpen(char *metaname)
+{
+ int i, j, offset;
+
+ i = MetaSearch(metaname);
+ if ( i != -1 ) return i;
+
+ for ( i=0 ; i<METAMAX ; i++ )
+ {
+ if ( m_list[i].stream == 0 )
+ {
+ m_list[i].stream = fopen(metaname, "rb");
+ if ( m_list[i].stream == 0 ) return -1;
+
+ strcpy(m_list[i].name, metaname); // mémorise le nom
+
+ fread(&m_list[i].total, sizeof(int), 1, m_list[i].stream);
+ m_list[i].headers = (MetaHeader*)malloc(sizeof(MetaHeader)*m_list[i].total);
+
+ offset = 4;
+ for ( j=0 ; j<m_list[i].total ; j++ )
+ {
+ fread(&m_list[i].headers[j], sizeof(MetaHeader), 1, m_list[i].stream);
+ Codec(&m_list[i].headers[j], sizeof(MetaHeader), offset);
+ offset += sizeof(MetaHeader);
+ }
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+// Cherche si le metafile est déjà ouvert. Retourne l'index ou -1.
+
+int CMetaFile::MetaSearch(char *metaname)
+{
+ int i;
+
+ for ( i=0 ; i<METAMAX ; i++ )
+ {
+ if ( m_list[i].stream != 0 )
+ {
+ if ( strcmp(m_list[i].name, metaname) == 0 ) return i;
+ }
+ }
+
+ return -1;
+}
+
+// Ferme tous ls metafiles.
+
+int CMetaFile::MetaClose()
+{
+ int i;
+
+ if ( m_stream != 0 )
+ {
+ fclose(m_stream);
+ m_stream = 0;
+ }
+
+ for ( i=0 ; i<METAMAX ; i++ )
+ {
+ if ( m_list[i].stream != 0 )
+ {
+ free(m_list[i].headers);
+ m_list[i].headers = 0;
+
+ fclose(m_list[i].stream);
+ m_list[i].stream = 0;
+ }
+ }
+
+ return 0;
+}
+
+
+
diff --git a/src/metafile.h b/src/metafile.h
new file mode 100644
index 0000000..d455b0d
--- /dev/null
+++ b/src/metafile.h
@@ -0,0 +1,60 @@
+// metafile.h
+
+#ifndef _METAFILE_H_
+#define _METAFILE_H_
+
+
+
+#define METAMAX 5
+
+typedef struct
+{
+ char name[14]; // nom du fichier (8.3 max)
+ int start; // position depuis le début du metafile
+ int len; // longueur du fichier
+}
+MetaHeader;
+
+typedef struct
+{
+ char name[50]; // nom du metafile
+ FILE* stream; // canal
+ int total; // nb de fichiers contenus
+ MetaHeader* headers; // headers des fichiers contenus
+}
+MetaFile;
+
+
+
+class CMetaFile
+{
+public:
+ CMetaFile();
+ ~CMetaFile();
+
+ BOOL IsExist(char *metaname, char *filename);
+ int Open(char *metaname, char *filename);
+ int RetLength();
+ int Seek(int offset);
+ int Read(void *buffer, int size);
+ int GetByte();
+ int GetWord();
+ int Close();
+ int MetaClose();
+
+protected:
+ int MetaOpen(char *metaname);
+ int MetaSearch(char *metaname);
+
+protected:
+ MetaFile m_list[METAMAX]; // metafile ouverts
+ BOOL m_bOpen; // fichier ouvert
+ BOOL m_bMeta; // metafile ouvert
+ FILE* m_stream; // canal
+ int m_start; // position depuis le début
+ int m_pos; // position courante
+ int m_len; // longueur du fichier
+};
+
+
+#endif //_METAFILE_H_
diff --git a/src/micent2.txt b/src/micent2.txt
new file mode 100644
index 0000000..c77d91b
--- /dev/null
+++ b/src/micent2.txt
@@ -0,0 +1,13 @@
+\b;Rapport du satellite
+\c;
+\s;-> SURFACE\c;
+\tab;Température: 25.4 degrés
+\tab;Atmosphère: oxygène, azote, ammoniaque
+\tab;Vent: 0.7 m/s
+\tab;Minerai titanium: aucun
+\tab;Minerai uranium: aucun
+
+\s;-> SOUS-SOL\c;
+\tab;Energie: aucune
+\tab;Minerai titanium: aucun
+\tab;Minerai uranium: aucun
diff --git a/src/misc.cpp b/src/misc.cpp
new file mode 100644
index 0000000..d9151f0
--- /dev/null
+++ b/src/misc.cpp
@@ -0,0 +1,425 @@
+// misc.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <math.h>
+#include <stdio.h>
+#include <direct.h>
+#include <time.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "D3DUtil.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+
+
+
+CMetaFile g_metafile;
+
+static EventMsg g_uniqueEventMsg = EVENT_USER;
+static BOOL g_bUserDir = FALSE;
+static char g_userDir[100] = "";
+
+
+
+// Donne un événement utilisateur unique.
+
+EventMsg GetUniqueEventMsg()
+{
+ int i;
+
+ i = (int)g_uniqueEventMsg+1;
+ g_uniqueEventMsg = (EventMsg)i;
+ return g_uniqueEventMsg;
+}
+
+
+
+// Retourne une lettre non accentuée.
+
+char RetNoAccent(char letter)
+{
+ if ( letter < 0 )
+ {
+ if ( letter == 'á' ||
+ letter == 'à' ||
+ letter == 'â' ||
+ letter == 'ä' ||
+ letter == 'ã' ) return 'a';
+
+ if ( letter == 'é' ||
+ letter == 'è' ||
+ letter == 'ê' ||
+ letter == 'ë' ) return 'e';
+
+ if ( letter == 'í' ||
+ letter == 'ì' ||
+ letter == 'î' ||
+ letter == 'ï' ) return 'i';
+
+ if ( letter == 'ó' ||
+ letter == 'ò' ||
+ letter == 'ô' ||
+ letter == 'ö' ||
+ letter == 'õ' ) return 'o';
+
+ if ( letter == 'ú' ||
+ letter == 'ù' ||
+ letter == 'û' ||
+ letter == 'ü' ) return 'u';
+
+ if ( letter == 'ç' ) return 'c';
+
+ if ( letter == 'ñ' ) return 'n';
+
+ if ( letter == 'Á' ||
+ letter == 'À' ||
+ letter == 'Â' ||
+ letter == 'Ä' ||
+ letter == 'Ã' ) return 'A';
+
+ if ( letter == 'É' ||
+ letter == 'È' ||
+ letter == 'Ê' ||
+ letter == 'Ë' ) return 'E';
+
+ if ( letter == 'Í' ||
+ letter == 'Ì' ||
+ letter == 'Î' ||
+ letter == 'Ï' ) return 'I';
+
+ if ( letter == 'Ó' ||
+ letter == 'Ò' ||
+ letter == 'Ô' ||
+ letter == 'Ö' ||
+ letter == 'Õ' ) return 'O';
+
+ if ( letter == 'Ú' ||
+ letter == 'Ù' ||
+ letter == 'Û' ||
+ letter == 'Ü' ) return 'U';
+
+ if ( letter == 'Ç' ) return 'C';
+
+ if ( letter == 'Ñ' ) return 'N';
+ }
+
+ return letter;
+}
+
+// Retourne une lettre majuscule.
+
+char RetToUpper(char letter)
+{
+ if ( letter < 0 )
+ {
+ if ( letter == 'á' ) return 'Á';
+ if ( letter == 'à' ) return 'À';
+ if ( letter == 'â' ) return 'Â';
+ if ( letter == 'ä' ) return 'Ä';
+ if ( letter == 'ã' ) return 'Ã';
+
+ if ( letter == 'é' ) return 'É';
+ if ( letter == 'è' ) return 'È';
+ if ( letter == 'ê' ) return 'Ê';
+ if ( letter == 'ë' ) return 'Ë';
+
+ if ( letter == 'í' ) return 'Í';
+ if ( letter == 'ì' ) return 'Ì';
+ if ( letter == 'î' ) return 'Î';
+ if ( letter == 'ï' ) return 'Ï';
+
+ if ( letter == 'ó' ) return 'Ó';
+ if ( letter == 'ò' ) return 'Ò';
+ if ( letter == 'ô' ) return 'Ô';
+ if ( letter == 'ö' ) return 'Ö';
+ if ( letter == 'õ' ) return 'Õ';
+
+ if ( letter == 'ú' ) return 'Ú';
+ if ( letter == 'ù' ) return 'Ù';
+ if ( letter == 'û' ) return 'Û';
+ if ( letter == 'ü' ) return 'Ü';
+
+ if ( letter == 'ç' ) return 'Ç';
+
+ if ( letter == 'ñ' ) return 'Ñ';
+ }
+
+ return toupper(letter);
+}
+
+// Retourne une lettre minuscule.
+
+char RetToLower(char letter)
+{
+ if ( letter < 0 )
+ {
+ if ( letter == 'Á' ) return 'á';
+ if ( letter == 'À' ) return 'à';
+ if ( letter == 'Â' ) return 'â';
+ if ( letter == 'Ä' ) return 'ä';
+ if ( letter == 'Ã' ) return 'ã';
+
+ if ( letter == 'É' ) return 'é';
+ if ( letter == 'È' ) return 'è';
+ if ( letter == 'Ê' ) return 'ê';
+ if ( letter == 'Ë' ) return 'ë';
+
+ if ( letter == 'Í' ) return 'í';
+ if ( letter == 'Ì' ) return 'ì';
+ if ( letter == 'Î' ) return 'î';
+ if ( letter == 'Ï' ) return 'ï';
+
+ if ( letter == 'Ó' ) return 'ó';
+ if ( letter == 'Ò' ) return 'ò';
+ if ( letter == 'Ô' ) return 'ô';
+ if ( letter == 'Ö' ) return 'ö';
+ if ( letter == 'Õ' ) return 'õ';
+
+ if ( letter == 'Ú' ) return 'ú';
+ if ( letter == 'Ù' ) return 'ù';
+ if ( letter == 'Û' ) return 'û';
+ if ( letter == 'Ü' ) return 'ü';
+
+ if ( letter == 'Ç' ) return 'ç';
+
+ if ( letter == 'Ñ' ) return 'ñ';
+ }
+
+ return tolower(letter);
+}
+
+
+// Conversion du temps en chaîne.
+
+void TimeToAscii(time_t time, char *buffer)
+{
+ struct tm when;
+ int year;
+
+ when = *localtime(&time);
+ year = when.tm_year+1900;
+ if ( year < 2000 ) year -= 1900;
+ else year -= 2000;
+#if _FRENCH
+ sprintf(buffer, "%.2d.%.2d.%.2d %.2d:%.2d",
+ when.tm_mday, when.tm_mon+1, year,
+ when.tm_hour, when.tm_min);
+#endif
+#if _GERMAN | _WG
+ sprintf(buffer, "%.2d.%.2d.%.2d %.2d:%.2d",
+ when.tm_mday, when.tm_mon+1, year,
+ when.tm_hour, when.tm_min);
+#endif
+#if _ENGLISH
+ char format[10];
+ int hour;
+
+ hour = when.tm_hour; // 0..23
+ if ( hour < 12 ) // matin ?
+ {
+ strcpy(format, "am");
+ }
+ else // après-midi ?
+ {
+ strcpy(format, "pm");
+ hour -= 12; // 0..11
+ }
+ if ( hour == 0 ) hour = 12;
+
+ sprintf(buffer, "%.2d.%.2d.%.2d %.2d:%.2d %s",
+ when.tm_mon+1, when.tm_mday, year,
+ hour, when.tm_min, format);
+#endif
+#if _POLISH
+ sprintf(buffer, "%.2d.%.2d.%.2d %.2d:%.2d",
+ when.tm_mday, when.tm_mon+1, year,
+ when.tm_hour, when.tm_min);
+#endif
+}
+
+
+// Effectue une copie d'un fichier.
+
+BOOL Xfer(char* src, char* dst)
+{
+ FILE *fs, *fd;
+ char *buffer;
+ int len;
+
+ fs = fopen(src, "rb");
+ if ( fs == 0 )
+ {
+ return FALSE;
+ }
+
+ fd = fopen(dst, "wb");
+ if ( fd == 0 )
+ {
+ fclose(fs);
+ return FALSE;
+ }
+
+ buffer = (char*)malloc(10000);
+
+ while ( TRUE )
+ {
+ len = fread(buffer, 1, 10000, fs);
+ if ( len == 0 ) break;
+ fwrite(buffer, 1, len, fd);
+ }
+
+ free(buffer);
+ fclose(fs);
+ fclose(fd);
+ return TRUE;
+}
+
+// Copie un fichier dans le dossier temporaire.
+
+BOOL CopyFileToTemp(char* filename)
+{
+ char src[100];
+ char dst[100];
+ char save[100];
+
+ UserDir(src, filename, "textures");
+
+ strcpy(save, g_userDir);
+ strcpy(g_userDir, "temp");
+ UserDir(dst, filename, "textures");
+ strcpy(g_userDir, save);
+
+ _mkdir("temp");
+ if ( !Xfer(src, dst) ) return FALSE;
+
+ strcpy(filename, dst);
+ return TRUE;
+}
+
+// Copie une liste de fichiers numérotés dans le dossier temporaire.
+
+BOOL CopyFileListToTemp(char* filename, int* list, int total)
+{
+ char name[100];
+ char ext[10];
+ char file[100];
+ char save[100];
+ char* p;
+ int i;
+
+ strcpy(name, filename);
+ p = strchr(name, '.');
+ if ( p == 0 )
+ {
+ strcpy(ext, ".tga");
+ }
+ else
+ {
+ strcpy(ext, p);
+ *p = 0;
+ }
+
+ for ( i=0 ; i<total ; i++ )
+ {
+ sprintf(file, "%s%.3d%s", name, list[i], ext); // nameNNN.ext
+ CopyFileToTemp(file);
+ }
+
+ strcpy(save, g_userDir);
+ strcpy(g_userDir, "temp");
+ UserDir(file, filename, "textures");
+ strcpy(filename, file);
+ strcpy(g_userDir, save);
+
+ return TRUE;
+}
+
+
+// Ajoute une extension à un fichier, s'il n'en a pas déjà une.
+
+void AddExt(char* filename, char* ext)
+{
+ if ( strchr(filename, '.') != 0 ) return; // déjà une extension ?
+ strcat(filename, ext);
+}
+
+
+// Spécifie le dossier utilisateur.
+
+void UserDir(BOOL bUser, char* dir)
+{
+ g_bUserDir = bUser;
+ strcpy(g_userDir, dir);
+}
+
+// Remplace la chaîne %user% par le dossier utilisateur.
+// in: dir = "%user%toto.txt"
+// def = "abc\"
+// out: buffer = "abc\toto.txt"
+
+void UserDir(char* buffer, char* dir, char* def)
+{
+ char ddir[100];
+ char* add;
+
+ if ( strstr(dir, "\\") == 0 && def[0] != 0 )
+ {
+ sprintf(ddir, "%s\\%s", def, dir);
+ }
+ else
+ {
+ strcpy(ddir, dir);
+ }
+ dir = ddir;
+
+ while ( *dir != 0 )
+ {
+ if ( dir[0] == '%' &&
+ dir[1] == 'u' &&
+ dir[2] == 's' &&
+ dir[3] == 'e' &&
+ dir[4] == 'r' &&
+ dir[5] == '%' ) // %user% ?
+ {
+ if ( g_bUserDir ) add = g_userDir;
+ else add = def;
+
+ while ( *add != 0 )
+ {
+ *buffer++ = *add++;
+ }
+ dir += 6; // saute %user%
+ continue;
+ }
+
+ *buffer++ = *dir++;
+ }
+ *buffer = 0;
+}
+
+
+// Retourne la lettre correspondant à la langue.
+
+char RetLanguageLetter()
+{
+#if _FRENCH
+ return 'F';
+#endif
+#if _ENGLISH
+ return 'E';
+#endif
+#if _GERMAN | _WG
+ return 'D';
+#endif
+#if _POLISH
+ return 'P';
+#endif
+ return 'X';
+}
+
diff --git a/src/misc.h b/src/misc.h
new file mode 100644
index 0000000..95ae19a
--- /dev/null
+++ b/src/misc.h
@@ -0,0 +1,223 @@
+// misc.h
+
+#ifndef _MISC_H_
+#define _MISC_H_
+
+#include <time.h>
+#include "metafile.h"
+
+
+extern CMetaFile g_metafile;
+
+
+
+// Classes existantes.
+
+enum ClassType
+{
+ CLASS_EVENT = 1,
+ CLASS_INTERFACE = 2,
+ CLASS_MAIN = 3,
+ CLASS_ENGINE = 4,
+ CLASS_TERRAIN = 5,
+ CLASS_OBJECT = 6,
+ CLASS_PHYSICS = 7,
+ CLASS_BRAIN = 8,
+ CLASS_CAMERA = 9,
+ CLASS_LIGHT = 10,
+ CLASS_PARTICULE = 11,
+ CLASS_AUTO = 12,
+ CLASS_DISPLAYTEXT = 13,
+ CLASS_PYRO = 14,
+ CLASS_SCRIPT = 15,
+ CLASS_TEXT = 16,
+ CLASS_STUDIO = 17,
+ CLASS_WATER = 18,
+ CLASS_CLOUD = 19,
+ CLASS_MOTION = 20,
+ CLASS_SOUND = 21,
+ CLASS_PLANET = 22,
+ CLASS_TASKMANAGER = 23,
+ CLASS_DIALOG = 24,
+ CLASS_MAP = 25,
+ CLASS_SHORT = 26,
+ CLASS_BLITZ = 27,
+};
+
+#define CLASS_MAX 30
+
+
+
+enum Error
+{
+ ERR_OK = 0, // ok
+ ERR_GENERIC = 1, // erreur quelconque
+ ERR_CONTINUE = 2, // continue
+ ERR_STOP = 3, // stoppe
+ ERR_CMD = 4, // commande inconnue
+ ERR_INSTALL = 20, // programme mal installé
+ ERR_NOCD = 21, // CD pas trouvé
+ ERR_MANIP_VEH = 100, // véhicule inadapté
+ ERR_MANIP_FLY = 101, // impossible en vol
+ ERR_MANIP_BUSY = 102, // prend: porte déjà qq chose
+ ERR_MANIP_NIL = 103, // prend: rien à prendre
+ ERR_MANIP_MOTOR = 105, // dépose: impossible en mouvement
+ ERR_MANIP_OCC = 106, // dépose: emplacement déjà occupé
+ ERR_MANIP_FRIEND = 107, // pas d'autre véhicule
+ ERR_MANIP_RADIO = 108, // impossible car radioactif
+ ERR_MANIP_WATER = 109, // impossible sous l'eau
+ ERR_MANIP_EMPTY = 110, // rien à déposer
+ ERR_BUILD_FLY = 120, // impossible en vol
+ ERR_BUILD_WATER = 121, // impossible sous l'eau
+ ERR_BUILD_ENERGY = 122, // pas assez d'énergie
+ ERR_BUILD_METALAWAY = 123, // pas de métal (trop loin)
+ ERR_BUILD_METALNEAR = 124, // pas de métal (trop proche)
+ ERR_BUILD_METALINEX = 125, // métal inexistant
+ ERR_BUILD_FLAT = 126, // sol pas assez plat
+ ERR_BUILD_FLATLIT = 127, // sol plat pas assez grand
+ ERR_BUILD_BUSY = 128, // enplacement occupé
+ ERR_BUILD_BASE = 129, // trop proche de la fusée
+ ERR_BUILD_NARROW = 130, // bâtiments trop serrés
+ ERR_BUILD_MOTOR = 131, // construit: impossible en mouvement
+ ERR_SEARCH_FLY = 140, // impossible en vol
+ ERR_SEARCH_VEH = 141, // véhicule inadapté
+ ERR_SEARCH_MOTOR = 142, // impossible en mouvement
+ ERR_TERRA_VEH = 150, // véhicule inadapté
+ ERR_TERRA_ENERGY = 151, // pas assez d'énergie
+ ERR_TERRA_FLOOR = 152, // terrain inadapté
+ ERR_TERRA_BUILDING = 153, // batiment trop proche
+ ERR_TERRA_OBJECT = 154, // object trop proche
+ ERR_FIRE_VEH = 160, // véhicule inadapté
+ ERR_FIRE_ENERGY = 161, // pas assez d'énergie
+ ERR_FIRE_FLY = 162, // impossible en vol
+ ERR_RECOVER_VEH = 170, // véhicule inadapté
+ ERR_RECOVER_ENERGY = 171, // pas assez d'énergie
+ ERR_RECOVER_NULL = 172, // pas de ruine
+ ERR_CONVERT_EMPTY = 180, // pas de pierre à transformer
+ ERR_SHIELD_VEH = 190, // véhicule inadapté
+ ERR_SHIELD_ENERGY = 191, // pas assez d'énergie
+ ERR_MOVE_IMPOSSIBLE = 200, // move impossible
+ ERR_FIND_IMPOSSIBLE = 201, // find impossible
+ ERR_GOTO_IMPOSSIBLE = 210, // goto impossible
+ ERR_GOTO_ITER = 211, // goto trop compliqué
+ ERR_GOTO_BUSY = 212, // destination goto occupée
+ ERR_DERRICK_NULL = 300, // pas de minerai en sous-sol
+ ERR_STATION_NULL = 301, // pas d'énergie en sous-sol
+ ERR_TOWER_POWER = 310, // pas de pile
+ ERR_TOWER_ENERGY = 311, // plus d'énergie
+ ERR_RESEARCH_POWER = 320, // pas de pile
+ ERR_RESEARCH_ENERGY = 321, // plus d'énergie
+ ERR_RESEARCH_TYPE = 322, // pas le bon type de pile
+ ERR_RESEARCH_ALREADY= 323, // recherche déjà faîte
+ ERR_ENERGY_NULL = 330, // pas d'énergie en sous-sol
+ ERR_ENERGY_LOW = 331, // pas encore assez d'énergie
+ ERR_ENERGY_EMPTY = 332, // pas de métal à transformer
+ ERR_ENERGY_BAD = 333, // ne transforme que le métal
+ ERR_BASE_DLOCK = 340, // portes bloquées
+ ERR_BASE_DHUMAN = 341, // vous devez embarquer
+ ERR_LABO_NULL = 350, // rien à analyser
+ ERR_LABO_BAD = 351, // pas de boulet à analyser
+ ERR_LABO_ALREADY = 352, // analyse déjà faîte
+ ERR_NUCLEAR_NULL = 360, // pas d'énergie en sous-sol
+ ERR_NUCLEAR_LOW = 361, // pas encore assez d'énergie
+ ERR_NUCLEAR_EMPTY = 362, // pas d'uranium à transformer
+ ERR_NUCLEAR_BAD = 363, // ne transforme que l'uranium
+ ERR_FACTORY_NULL = 370, // pas de métal
+ ERR_FACTORY_NEAR = 371, // véhicule trop proche
+ ERR_RESET_NEAR = 380, // véhicule trop proche
+ ERR_INFO_NULL = 390, // pas de borne d'information
+ ERR_VEH_VIRUS = 400, // véhicule infecté par un virus
+ ERR_BAT_VIRUS = 401, // bâtiment infecté par un virus
+ ERR_VEH_POWER = 500, // pas de pile
+ ERR_VEH_ENERGY = 501, // plus d'énergie
+ ERR_FLAG_FLY = 510, // impossible en vol
+ ERR_FLAG_WATER = 511, // impossible en nageant
+ ERR_FLAG_MOTOR = 512, // impossible en mouvement
+ ERR_FLAG_BUSY = 513, // prend: porte déjà qq chose
+ ERR_FLAG_CREATE = 514, // trop d'indicateurs
+ ERR_FLAG_PROXY = 515, // trop proche
+ ERR_FLAG_DELETE = 516, // rien à supprimer
+ ERR_MISSION_NOTERM = 600, // mission pas terminée
+ ERR_DELETEMOBILE = 700, // véhicule détruit
+ ERR_DELETEBUILDING = 701, // bâtiment détruit
+ ERR_TOOMANY = 702, // trop d'objets
+ ERR_OBLIGATORYTOKEN = 800, // instruction obligatoire manquante
+ ERR_PROHIBITEDTOKEN = 801, // instruction interdite
+
+ INFO_FIRST = 10000, // première information
+ INFO_BUILD = 10001, // construction terminée
+ INFO_CONVERT = 10002, // métal disponible
+ INFO_RESEARCH = 10003, // recherche terminée
+ INFO_FACTORY = 10004, // véhicule fabriqué
+ INFO_LABO = 10005, // analyse terminée
+ INFO_ENERGY = 10006, // pile disponible
+ INFO_NUCLEAR = 10007, // pile nucléaire disponible
+ INFO_FINDING = 10008, // pile nucléaire disponible
+ INFO_MARKPOWER = 10020, // emplacement pour station trouvé
+ INFO_MARKURANIUM = 10021, // emplacement pour derrick trouvé
+ INFO_MARKSTONE = 10022, // emplacement pour derrick trouvé
+ INFO_MARKKEYa = 10023, // emplacement pour derrick trouvé
+ INFO_MARKKEYb = 10024, // emplacement pour derrick trouvé
+ INFO_MARKKEYc = 10025, // emplacement pour derrick trouvé
+ INFO_MARKKEYd = 10026, // emplacement pour derrick trouvé
+ INFO_RESEARCHTANK = 10030, // recherche terminée
+ INFO_RESEARCHFLY = 10031, // recherche terminée
+ INFO_RESEARCHTHUMP = 10032, // recherche terminée
+ INFO_RESEARCHCANON = 10033, // recherche terminée
+ INFO_RESEARCHTOWER = 10034, // recherche terminée
+ INFO_RESEARCHPHAZER = 10035, // recherche terminée
+ INFO_RESEARCHSHIELD = 10036, // recherche terminée
+ INFO_RESEARCHATOMIC = 10037, // recherche terminée
+ INFO_WIN = 10040, // gagné
+ INFO_LOST = 10041, // perdu
+ INFO_LOSTq = 10042, // perdu immédiatement
+ INFO_WRITEOK = 10043, // enregistrement effectué
+ INFO_DELETEPATH = 10050, // marque chemin supprimée
+ INFO_DELETEMOTHER = 10100, // insecte tué
+ INFO_DELETEANT = 10101, // insecte tué
+ INFO_DELETEBEE = 10102, // insecte tué
+ INFO_DELETEWORM = 10103, // insecte tué
+ INFO_DELETESPIDER = 10104, // insecte tué
+ INFO_BEGINSATCOM = 10105, // utilisez votre SatCom
+};
+
+
+// Etat du clavier.
+
+#define KS_PAGEUP (1<<4)
+#define KS_PAGEDOWN (1<<5)
+#define KS_SHIFT (1<<6)
+#define KS_CONTROL (1<<7)
+#define KS_MLEFT (1<<8)
+#define KS_MRIGHT (1<<9)
+#define KS_NUMUP (1<<10)
+#define KS_NUMDOWN (1<<11)
+#define KS_NUMLEFT (1<<12)
+#define KS_NUMRIGHT (1<<13)
+#define KS_NUMPLUS (1<<14)
+#define KS_NUMMINUS (1<<15)
+
+
+// Procédures.
+
+enum EventMsg;
+
+extern EventMsg GetUniqueEventMsg();
+
+extern char RetNoAccent(char letter);
+extern char RetToUpper(char letter);
+extern char RetToLower(char letter);
+
+extern void TimeToAscii(time_t time, char *buffer);
+
+extern BOOL CopyFileToTemp(char* filename);
+extern BOOL CopyFileListToTemp(char* filename, int* list, int total);
+extern void AddExt(char* filename, char* ext);
+extern void UserDir(BOOL bUser, char* dir);
+extern void UserDir(char* buffer, char* dir, char* def);
+
+extern char RetLanguageLetter();
+
+
+
+#endif //_MISC_H_
diff --git a/src/mixer.txt b/src/mixer.txt
new file mode 100644
index 0000000..2009c2a
--- /dev/null
+++ b/src/mixer.txt
@@ -0,0 +1,486 @@
+Several people have asked me for the sample code I use to program
+the mixer in Windows. Since it's a fairly short sample and there's
+clearly some interest, I thought I'd post it directly to the newsgroup.
+Here it is ... enjoy! (?)
+
+Julian
+
+// Example routine that manipulates the mixer controls for Win32
+// This code is not a stand-alone application ...
+//
+// It's also not very pretty ...
+//
+// But then, neither is the API ...
+//
+// Julian Bunn, 1998, julianb@altavista.net
+
+
+#include <windows.h>
+#include <mmsystem.h>
+
+
+MIXERCONTROLDETAILS mixDetailsMic,mixDetailsSpk,mixDetailsLin;
+LONG
+lMaximumSpk,lMaximumMic,lMaximumLin,lMinimumMic,lMinimumSpk,lMinimumLin;
+
+int nMixerDevs;
+int nMicMixID;
+
+LPHMIXER hMixer;
+UINT IdMixer;
+
+
+/****************************************************************************
+
+ Function: ProgramInitMixer()
+
+ PURPOSE : Initialises the mixer
+*****************************************************************************/
+
+LONG WINAPI ProgramInitMixer()
+{
+ UINT iS,iD,iDC,iC, itype;
+ UINT volume;
+ MMRESULT mmres;
+ MIXERCAPS mixCaps;
+ MIXERLINE mixLine;
+ MIXERLINECONTROLS mixControls;
+ MIXERCONTROL mixClist[50];
+ MIXERCONTROLDETAILS mixDetails;
+ MIXERCONTROLDETAILS_UNSIGNED mixValue;
+ MIXERCONTROLDETAILS_BOOLEAN mixMute;
+ MIXERCONTROLDETAILS_BOOLEAN mixBoolean[50];
+ MIXERCONTROLDETAILS_LISTTEXT mixList[50];
+ BOOL bDoneMike = FALSE;
+ BOOL bDoneSpkr = FALSE;
+ UINT LineID = 0;
+
+ if(!bMixerOpened) {
+// check first if we have a mixer
+ if((nMixerDevs = mixerGetNumDevs()) < 1) {
+ return (Program_ERROR);
+ }
+
+// really need to pop up a chooser for which mixer device, in
+// cases where there is more than one.
+// In the meantime, I select the last one listed
+
+ IdMixer = nMixerDevs-1;
+
+ mmres = mixerOpen((LPHMIXER) &hMixer, IdMixer, (DWORD) 0, (DWORD)
+NULL,
+ MIXER_OBJECTF_MIXER);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+
+ bMixerOpened = TRUE;
+ }
+
+ mmres = mixerGetDevCaps(IdMixer, (LPMIXERCAPS) &mixCaps,
+sizeof(MIXERCAPS));
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+// Set the manufacturer's name for the mixer ...
+ SetDlgItemText(hWndDialogBox,IDC_MIXERNAME,mixCaps.szPname);
+ if(nMixerDevs>1) {
+ DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_INFOMESSAGE1),
+hWndDialogBox, DialogBoxCallback);
+ }
+
+
+// Loop over the destination mixer lines
+ for (iD=0;iD<mixCaps.cDestinations;iD++) {
+ mixLine.cbStruct = sizeof(MIXERLINE);
+ mixLine.dwDestination = (DWORD) iD;
+ mixLine.dwSource = (DWORD) 0;
+// Get information on this line
+ mmres = mixerGetLineInfo(hMixer, (LPMIXERLINE) &mixLine,
+ MIXER_GETLINEINFOF_DESTINATION);
+
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+
+// I select types I'm interested in: the speaker output, the input
+(voice and wave)
+ itype = 0;
+ if(mixLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS)
+itype = 1; // Output for speakers ... only allow WAVEOUT
+ if(mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_DST_VOICEIN) itype = 2; // Input for ADC ...
+only allow Microphone (or AUX)
+ if(mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_DST_WAVEIN) itype = 2; // Input for ADC ...
+only allow Microphone (or AUX)
+ if(itype == 2 && !bMicrophone) {
+ itype = 3;
+ }
+
+
+ mixControls.cbStruct = sizeof(MIXERLINECONTROLS);
+ mixControls.dwLineID = mixLine.dwLineID;
+ mixControls.cControls = mixLine.cControls;
+ mixControls.cbmxctrl = sizeof(mixClist[0]);
+ mixControls.pamxctrl = (LPMIXERCONTROL) &mixClist[0];
+// Get the controls for the current destination mixer line
+ mmres = mixerGetLineControls(hMixer,
+ (LPMIXERLINECONTROLS) &mixControls,
+ MIXER_GETLINECONTROLSF_ALL);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ for (iDC=0;iDC<mixLine.cControls;iDC++) {
+// For this control, I make various checks on its type
+ if(mixClist[iDC].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ||
+ mixClist[iDC].dwControlType ==
+MIXERCONTROL_CONTROLTYPE_MIXER) {
+
+// This is a control that defines a set of connections ... get all the
+types, and the values
+// for the connection
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iDC].dwControlID;
+ mixDetails.cChannels = 1;//mixLine.cChannels;
+ mixDetails.hwndOwner = (HWND) mixClist[iDC].cMultipleItems;
+ mixDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_LISTTEXT)
+&mixList[0];
+ mmres = mixerGetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_LISTTEXT);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iDC].dwControlID;
+ mixDetails.cChannels = 1;//mixLine.cChannels;
+ mixDetails.hwndOwner = (HWND) mixClist[iDC].cMultipleItems;
+ mixDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_BOOLEAN)
+&mixBoolean[0];
+ mmres = mixerGetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+// In this application, I want to set only the microphone or line as
+input sources ...
+
+for(iS=0;iS<mixClist[iDC].cMultipleItems;iS++) {
+ mixBoolean[iS].fValue = FALSE;
+ if(itype == 2 && mixList[iS].dwParam2
+== MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) {
+ mixBoolean[iS].fValue = TRUE;
+ bDoneMike = TRUE;
+ }
+ if(itype == 3 && (mixList[iS].dwParam2
+== MIXERLINE_COMPONENTTYPE_SRC_LINE ||
+ mixList[iS].dwParam2 ==
+MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY)) {
+ if(strncmp(mixList[iS].szName,"Line",4) == 0) {
+ mixBoolean[iS].fValue = TRUE;
+ bDoneMike = TRUE;
+ }
+ }
+ if(itype == 1 && mixList[iS].dwParam2 ==
+MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) {
+ mixBoolean[iS].fValue = TRUE;
+ bDoneSpkr = TRUE;
+ }
+ }
+// I've prepared the settings accordingly ... now I set them in the
+mixer
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+ if(mixClist[iDC].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME ||
+
+ mixClist[iDC].dwControlType == MIXERCONTROL_CONTROLTYPE_TREBLE ||
+
+ mixClist[iDC].dwControlType == MIXERCONTROL_CONTROLTYPE_BASS) {
+// This is a control of a volume
+ volume = 0;
+
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iDC].dwControlID;
+ mixDetails.cChannels = (DWORD) 1;
+ mixDetails.hwndOwner = NULL;
+ mixDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_UNSIGNED)
+&mixValue;
+ mmres = mixerGetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+// I want to set all volumes to maximum, treble and bass boost to
+minimum
+ if(mixClist[iDC].dwControlType ==
+MIXERCONTROL_CONTROLTYPE_VOLUME) {
+ if(mixValue.dwValue != 0) mixValue.dwValue =
+mixClist[iDC].Bounds.lMaximum;
+ } else {
+ mixValue.dwValue = mixClist[iDC].Bounds.lMinimum;
+ }
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+ if(mixClist[iDC].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE) {
+// A mute control _in principle_ I've already set all these up ...
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iDC].dwControlID;
+ mixDetails.cChannels = (DWORD) 1;
+ mixDetails.hwndOwner = NULL;
+ mixDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_BOOLEAN) &mixMute;
+ mmres = mixerGetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+ mixMute.fValue = mixClist[iDC].Bounds.lMinimum;
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+ if(mixClist[iDC].dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF) {
+// An "on-off" control ... sort of like a mute, but different (used e.g
+for AGC)
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iDC].dwControlID;
+ mixDetails.cChannels = (DWORD) 1;
+ mixDetails.hwndOwner = NULL;
+ mixDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_BOOLEAN) &mixMute;
+ mmres = mixerGetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ mixMute.fValue = mixClist[iDC].Bounds.lMinimum;
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+
+ }
+
+
+ iDC = mixLine.cConnections;
+// Now I start looking over all the source lines coming into this mixer
+line ..
+ for (iS=0;iS<iDC;iS++) {
+ mixLine.cbStruct = sizeof(MIXERLINE);
+ mixLine.dwDestination = (DWORD) iD;
+ mixLine.dwSource = (DWORD) iS;
+
+ mmres = mixerGetLineInfo(hMixer, (LPMIXERLINE) &mixLine,
+ MIXER_GETLINEINFOF_SOURCE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+
+ mixControls.cbStruct = sizeof(MIXERLINECONTROLS);
+ mixControls.dwLineID = mixLine.dwLineID;
+ mixControls.cControls = mixLine.cControls;
+ mixControls.cbmxctrl = sizeof(mixClist[0]);
+ mixControls.pamxctrl = (LPMIXERCONTROL) &mixClist[0];
+ mmres = mixerGetLineControls(hMixer,
+ (LPMIXERLINECONTROLS) &mixControls,
+ MIXER_GETLINECONTROLSF_ALL);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+// for this source line ... loop over all the control. Very like what
+was done above for the
+// destination line ...
+ for(iC=0;iC<mixLine.cControls;iC++) {
+ if(mixClist[iC].dwControlType ==
+MIXERCONTROL_CONTROLTYPE_VOLUME) {
+
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iC].dwControlID;
+ mixDetails.cChannels = (DWORD) 1;
+ mixDetails.hwndOwner = NULL;
+ mixDetails.cbDetails =
+sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_UNSIGNED)
+&mixValue;
+// I want to make a copy of the waveout, microphone, aux and line lines
+for later use .... hence memcpy
+ if(itype == 1 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT) {
+
+memcpy(&mixDetailsSpk,&mixDetails,sizeof(MIXERCONTROLDETAILS));
+ lMaximumSpk = mixClist[iC].Bounds.lMaximum;
+ lMinimumSpk = mixClist[iC].Bounds.lMinimum;
+ }
+ if(itype == 2 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) {
+
+memcpy(&mixDetailsMic,&mixDetails,sizeof(MIXERCONTROLDETAILS));
+ lMaximumMic = mixClist[iC].Bounds.lMaximum;
+ lMinimumMic = mixClist[iC].Bounds.lMinimum;
+ }
+ if(itype == 3 &&
+(mixLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_LINE ||
+ mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY)) {
+// I'm not sure why I had to check the string like this ...
+ if(strncmp(mixLine.szName,"Line",4) == 0) {
+
+memcpy(&mixDetailsLin,&mixDetails,sizeof(MIXERCONTROLDETAILS));
+ lMaximumLin = mixClist[iC].Bounds.lMaximum;
+ lMinimumLin = mixClist[iC].Bounds.lMinimum;
+ }
+ }
+
+
+ mmres = mixerGetControlDetails(hMixer,
+
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+// Now I'm going to set the input levels the way I want them ..
+ mixValue.dwValue = mixClist[iC].Bounds.lMinimum;
+ if(itype == 1 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT) {
+ mixValue.dwValue = mixClist[iC].Bounds.lMaximum;
+ }
+ if(itype == 2 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) {
+ mixValue.dwValue = mixClist[iC].Bounds.lMaximum;
+ }
+ if(itype == 3 &&
+(mixLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_LINE ||
+ mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY)) {
+ if(strncmp(mixLine.szName,"Line",4) == 0) {
+ mixValue.dwValue = mixClist[iC].Bounds.lMaximum;
+ }
+ }
+
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+ if(mixClist[iC].dwControlType ==
+MIXERCONTROL_CONTROLTYPE_MUTE) {
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iC].dwControlID;
+ mixDetails.cChannels = (DWORD) 1;
+ mixDetails.hwndOwner = NULL;
+ mixDetails.cbDetails =
+sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_BOOLEAN)
+&mixMute;
+ mmres = mixerGetControlDetails(hMixer,
+
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+// I run the risk of inverting my boolean selections, so jump out if
+already done ...
+ if(itype != 0 && (bDoneSpkr || bDoneMike)) break;
+
+ mixMute.fValue = mixClist[iC].Bounds.lMaximum;
+ if(itype == 1 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT) {
+ mixMute.fValue = mixClist[iC].Bounds.lMinimum;
+ }
+ if(itype == 2 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) {
+ mixMute.fValue = mixClist[iC].Bounds.lMinimum;
+ }
+ if(itype == 3 &&
+(mixLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_LINE ||
+ mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY)) {
+ if(strncmp(mixLine.szName,"Line",4) == 0) {
+ mixMute.fValue = mixClist[iC].Bounds.lMinimum;
+ }
+ }
+
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+ if(mixClist[iC].dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF)
+{
+ mixDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mixDetails.dwControlID = mixClist[iC].dwControlID;
+ mixDetails.cChannels = (DWORD) 1;
+ mixDetails.hwndOwner = NULL;
+ mixDetails.cbDetails =
+sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mixDetails.paDetails = (LPMIXERCONTROLDETAILS_BOOLEAN)
+&mixMute;
+ mmres = mixerGetControlDetails(hMixer,
+
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_GETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+
+ mixMute.fValue = mixClist[iC].Bounds.lMinimum;
+ if(itype == 1 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT) {
+ mixMute.fValue = mixClist[iC].Bounds.lMaximum;
+ }
+ if(itype == 2 && mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) {
+ mixMute.fValue = mixClist[iC].Bounds.lMaximum;
+ }
+ if(itype == 3 &&
+(mixLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_LINE ||
+ mixLine.dwComponentType ==
+MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY)) {
+ if(strncmp(mixLine.szName,"Line",4) == 0) {
+ mixMute.fValue = mixClist[iC].Bounds.lMaximum;
+ }
+ }
+
+ mmres = mixerSetControlDetails(hMixer,
+ (LPMIXERCONTROLDETAILS) &mixDetails,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if(mmres != MMSYSERR_NOERROR) {
+ return (Program_ERROR);
+ }
+ }
+ }
+ }
+ }
+ return Program_NOERROR;
+}
+
+
diff --git a/src/model.cpp b/src/model.cpp
new file mode 100644
index 0000000..fbc51ed
--- /dev/null
+++ b/src/model.cpp
@@ -0,0 +1,3214 @@
+// model.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "water.h"
+#include "robotmain.h"
+#include "interface.h"
+#include "edit.h"
+#include "button.h"
+#include "cmdtoken.h"
+#include "modfile.h"
+#include "model.h"
+
+
+
+#define MAX_COLORS 9
+
+static float table_color[MAX_COLORS*3] =
+{
+ 1.0f, 1.0f, 1.0f, // blanc
+ 1.0f, 0.0f, 0.0f, // rouge
+ 0.0f, 1.0f, 0.0f, // vert
+ 0.0f, 0.6f, 1.0f, // bleu
+ 1.0f, 1.0f, 0.0f, // jaune
+ 0.0f, 1.0f, 1.0f, // cyan
+ 1.0f, 0.0f, 1.0f, // magenta
+ 0.3f, 0.3f, 0.3f, // gris
+ 0.0f, 0.0f, 0.0f, // noir
+};
+
+
+#define MAX_STATES 10
+
+static int table_state[MAX_STATES] =
+{
+ D3DSTATENORMAL,
+ D3DSTATEPART1,
+ D3DSTATEPART2,
+ D3DSTATEPART3,
+ D3DSTATEPART4,
+ D3DSTATE2FACE, // #5
+ D3DSTATETTw,
+ D3DSTATETTb,
+ D3DSTATETTw|D3DSTATE2FACE, // #8
+ D3DSTATETTb|D3DSTATE2FACE, // #9
+};
+
+
+#define MAX_NAMES 23
+
+
+
+
+// Constructeur de l'objet.
+
+CModel::CModel(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+
+ m_modFile = new CModFile(m_iMan);
+ m_triangleTable = m_modFile->RetTriangleList();
+
+ m_textureRank = 0;
+ strcpy(m_textureName, "lemt.tga");
+ m_color = 0;
+ m_state = 0;
+ m_textureMode = 0;
+ m_textureRotate = 0;
+ m_bTextureMirrorX = FALSE;
+ m_bTextureMirrorY = FALSE;
+ m_texturePart = 0;
+ TexturePartUpdate();
+
+ m_bDisplayTransparent = FALSE;
+ m_bDisplayOnlySelection = FALSE;
+ InitView();
+
+ m_triangleSel1 = 0;
+ m_triangleSel2 = 0;
+
+ m_mode = 1;
+ m_oper = 'P';
+
+ m_secondTexNum = 0;
+ m_secondSubdiv = 1;
+ m_secondOffsetU = 0;
+ m_secondOffsetV = 0;
+
+ m_min = 0.0f;
+ m_max = 1000000.0f;
+}
+
+// Destructeur de l'objet.
+
+CModel::~CModel()
+{
+ delete m_modFile;
+}
+
+
+// Il faut appeler cette procédure avant de modifier interactivement
+// le modèle.
+
+void CModel::StartUserAction()
+{
+ Event event;
+ FPOINT pos, dim;
+ CButton* pb;
+
+ dim.x = 105.0f/640.0f;
+ dim.y = 18.0f/480.0f;
+ pos.x = 10.0f/640.0f;
+ pos.y = 450.0f/480.0f;
+ m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT1);
+
+ dim.x = 50.0f/640.0f;
+ pos.x = 125.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON1);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("Load");
+ pos.x = 185.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON2);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("Script");
+ pos.x = 245.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON3);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("Read");
+ pos.x = 305.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON4);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("Add");
+ pos.x = 365.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON5);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("Write");
+
+ dim.x = 50.0f/640.0f;
+ dim.y = 18.0f/480.0f;
+ pos.x = 10.0f/640.0f;
+ pos.y = 425.0f/480.0f;
+ m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT2);
+ pos.x = 65.0f/640.0f;
+ pos.y = 425.0f/480.0f;
+ m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT3);
+ pos.x = 10.0f/640.0f;
+ pos.y = 400.0f/480.0f;
+ m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT4);
+ pos.x = 65.0f/640.0f;
+ pos.y = 400.0f/480.0f;
+ m_interface->CreateEdit(pos, dim, 0, EVENT_EDIT5);
+
+ dim.x = 20.0f/640.0f;
+ dim.y = 20.0f/480.0f;
+ pos.y = 370.0f/480.0f;
+ pos.x = 10.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON10);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("P");
+ pos.x = 30.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON11);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("R");
+ pos.x = 50.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON12);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("Z");
+ pos.y = 350.0f/480.0f;
+ pos.x = 10.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON13);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("+X");
+ pos.x = 30.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON14);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("+Y");
+ pos.x = 50.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON15);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("+Z");
+ pos.y = 330.0f/480.0f;
+ pos.x = 10.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON16);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("-X");
+ pos.x = 30.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON17);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("-Y");
+ pos.x = 50.0f/640.0f;
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_BUTTON18);
+ pb->SetState(STATE_SIMPLY);
+ pb->SetName("-Z");
+
+//? m_modFile->ReadModel("objects\\io.mod");
+ DeselectAll();
+ CurrentInit();
+
+ ZeroMemory(&event, sizeof(Event));
+ EventFrame(event);
+
+ m_engine->LoadAllTexture();
+ UpdateInfoText();
+}
+
+// Il faut appeler cette procédure après avoir modifié interactivement
+// le modèle.
+
+void CModel::StopUserAction()
+{
+ m_interface->DeleteControl(EVENT_EDIT1);
+ m_interface->DeleteControl(EVENT_EDIT2);
+ m_interface->DeleteControl(EVENT_EDIT3);
+ m_interface->DeleteControl(EVENT_EDIT4);
+ m_interface->DeleteControl(EVENT_EDIT5);
+ m_interface->DeleteControl(EVENT_BUTTON1);
+ m_interface->DeleteControl(EVENT_BUTTON2);
+ m_interface->DeleteControl(EVENT_BUTTON3);
+ m_interface->DeleteControl(EVENT_BUTTON4);
+ m_interface->DeleteControl(EVENT_BUTTON5);
+ m_interface->DeleteControl(EVENT_BUTTON10);
+ m_interface->DeleteControl(EVENT_BUTTON11);
+ m_interface->DeleteControl(EVENT_BUTTON12);
+ m_interface->DeleteControl(EVENT_BUTTON13);
+ m_interface->DeleteControl(EVENT_BUTTON14);
+ m_interface->DeleteControl(EVENT_BUTTON15);
+ m_interface->DeleteControl(EVENT_BUTTON16);
+ m_interface->DeleteControl(EVENT_BUTTON17);
+ m_interface->DeleteControl(EVENT_BUTTON18);
+
+ m_engine->SetInfoText(0, "");
+ m_engine->SetInfoText(1, "");
+}
+
+
+// Met à jour les valeurs éditables pour le mapping des textures.
+
+void CModel::PutTextureValues()
+{
+ CEdit* pe;
+ char s[100];
+ int value;
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2);
+ if ( pe != 0 )
+ {
+ value = (int)(m_textureSup.x*256.0f+0.5f);
+ sprintf(s, "%d", value);
+ pe->SetText(s);
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3);
+ if ( pe != 0 )
+ {
+ value = (int)(m_textureSup.y*256.0f+0.5f);
+ sprintf(s, "%d", value);
+ pe->SetText(s);
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4);
+ if ( pe != 0 )
+ {
+ value = (int)(m_textureInf.x*256.0f-0.5f);
+ sprintf(s, "%d", value);
+ pe->SetText(s);
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5);
+ if ( pe != 0 )
+ {
+ value = (int)(m_textureInf.y*256.0f-0.5f);
+ sprintf(s, "%d", value);
+ pe->SetText(s);
+ }
+}
+
+// Prend les valeurs éditables pour le mapping des textures.
+
+void CModel::GetTextureValues()
+{
+ CEdit* pe;
+ char s[100];
+ int value;
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2);
+ if ( pe != 0 )
+ {
+ pe->GetText(s, 100);
+ sscanf(s, "%d", &value);
+ m_textureSup.x = ((float)value-0.5f)/256.0f;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3);
+ if ( pe != 0 )
+ {
+ pe->GetText(s, 100);
+ sscanf(s, "%d", &value);
+ m_textureSup.y = ((float)value-0.5f)/256.0f;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4);
+ if ( pe != 0 )
+ {
+ pe->GetText(s, 100);
+ sscanf(s, "%d", &value);
+ m_textureInf.x = ((float)value+0.5f)/256.0f;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5);
+ if ( pe != 0 )
+ {
+ pe->GetText(s, 100);
+ sscanf(s, "%d", &value);
+ m_textureInf.y = ((float)value+0.5f)/256.0f;
+ }
+}
+
+
+// Donne le nom du modèle.
+
+void CModel::GetModelName(char *buffer)
+{
+ CEdit* pe;
+ char s[100];
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1);
+ if ( pe == 0 )
+ {
+ strcpy(buffer, "objects\\io.mod");
+ }
+ else
+ {
+ pe->GetText(s, 100);
+ sprintf(buffer, "objects\\%s.mod", s);
+ }
+}
+
+// Donne le nom du modèle.
+
+void CModel::GetDXFName(char *buffer)
+{
+ CEdit* pe;
+ char s[100];
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1);
+ if ( pe == 0 )
+ {
+ strcpy(buffer, "models\\import.dxf");
+ }
+ else
+ {
+ pe->GetText(s, 100);
+ sprintf(buffer, "models\\%s.dxf", s);
+ }
+}
+
+// Donne le nom du modèle.
+
+void CModel::GetScriptName(char *buffer)
+{
+ CEdit* pe;
+ char s[100];
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1);
+ if ( pe == 0 )
+ {
+ strcpy(buffer, "objects\\script.txt");
+ }
+ else
+ {
+ pe->GetText(s, 100);
+ sprintf(buffer, "objects\\%s.txt", s);
+ }
+}
+
+// Indique si l'édition du nom a le focus.
+
+BOOL CModel::IsEditFocus()
+{
+ CEdit* pe;
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT1);
+ if ( pe != 0 )
+ {
+ if ( pe->RetFocus() ) return TRUE;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT2);
+ if ( pe != 0 )
+ {
+ if ( pe->RetFocus() ) return TRUE;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT3);
+ if ( pe != 0 )
+ {
+ if ( pe->RetFocus() ) return TRUE;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT4);
+ if ( pe != 0 )
+ {
+ if ( pe->RetFocus() ) return TRUE;
+ }
+
+ pe = (CEdit*)m_interface->SearchControl(EVENT_EDIT5);
+ if ( pe != 0 )
+ {
+ if ( pe->RetFocus() ) return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CModel::EventProcess(const Event &event)
+{
+ char s[100];
+ int first, last;
+
+ switch( event.event )
+ {
+ case EVENT_FRAME:
+ EventFrame(event);
+ break;
+
+ case EVENT_KEYDOWN:
+ if ( IsEditFocus() )
+ break;
+
+ if ( event.param == '1' )
+ {
+ m_mode = 1;
+ UpdateInfoText();
+ }
+ if ( event.param == '2' )
+ {
+ m_mode = 2;
+ UpdateInfoText();
+ }
+ if ( event.param == '3' )
+ {
+ m_mode = 3;
+ UpdateInfoText();
+ }
+ if ( event.param == VK_ADD ) // plus pavé num ?
+ {
+ if ( event.keyState & KS_SHIFT ) CurrentSelect(TRUE);
+ CurrentSearchNext(+1, (event.keyState & KS_CONTROL));
+ }
+ if ( event.param == VK_SUBTRACT ) // moins pavé num ?
+ {
+ if ( event.keyState & KS_SHIFT ) CurrentSelect(TRUE);
+ CurrentSearchNext(-1, (event.keyState & KS_CONTROL));
+ }
+ if ( event.param == VK_NUMPAD0 )
+ {
+ CurrentSelect(FALSE);
+ }
+ if ( event.param == VK_DECIMAL )
+ {
+ CurrentSelect(TRUE);
+ }
+ if ( event.param == VK_END )
+ {
+ DeselectAll();
+ }
+ if ( event.param == VK_INSERT )
+ {
+ SelectAll();
+ }
+ if ( event.param == VK_BACK ) // Delete normal ?
+ {
+ SelectDelete();
+ }
+ if ( event.param == VK_SPACE )
+ {
+ m_bDisplayTransparent = !m_bDisplayTransparent;
+ m_bDisplayOnlySelection = FALSE;
+ }
+ if ( event.param == 'H' )
+ {
+ m_bDisplayOnlySelection = !m_bDisplayOnlySelection;
+ m_bDisplayTransparent = FALSE;
+ }
+ if ( m_mode == 1 )
+ {
+ if ( event.param == 'S' )
+ {
+ SmoothSelect();
+ }
+ if ( event.param == 'N' )
+ {
+ PlaneSelect();
+ }
+ if ( event.param == 'C' )
+ {
+ ColorSelect();
+ }
+ if ( event.param == 'V' )
+ {
+ m_color ++;
+ if ( m_color >= MAX_COLORS ) m_color = 0;
+ UpdateInfoText();
+ ColorSelect();
+ }
+ if ( event.param == 'J' )
+ {
+ StateSelect();
+ }
+ if ( event.param == 'K' )
+ {
+ m_state ++;
+ if ( m_state >= MAX_STATES ) m_state = 0;
+ UpdateInfoText();
+ StateSelect();
+ }
+ if ( event.param == 'M' )
+ {
+ m_textureMode ++;
+ if ( m_textureMode > 3 ) m_textureMode = 0;
+ UpdateInfoText();
+ GetTextureValues();
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_textureInf, m_textureSup, m_textureName);
+ }
+ if ( event.param == 'Z' )
+ {
+ m_textureRotate ++;
+ if ( m_textureRotate > 2 ) m_textureRotate = 0;
+ UpdateInfoText();
+ GetTextureValues();
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_textureInf, m_textureSup, m_textureName);
+ }
+ if ( event.param == 'X' )
+ {
+ m_bTextureMirrorX = !m_bTextureMirrorX;
+ UpdateInfoText();
+ GetTextureValues();
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_textureInf, m_textureSup, m_textureName);
+ }
+ if ( event.param == 'Y' )
+ {
+ m_bTextureMirrorY = !m_bTextureMirrorY;
+ UpdateInfoText();
+ GetTextureValues();
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_textureInf, m_textureSup, m_textureName);
+ }
+ if ( event.param == 'O' )
+ {
+ TextureRankChange(+1);
+ UpdateInfoText();
+ }
+ if ( event.param == 'P' )
+ {
+ TexturePartChange(+1);
+ UpdateInfoText();
+ GetTextureValues();
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_textureInf, m_textureSup, m_textureName);
+ }
+ if ( event.param == 'T' )
+ {
+ GetTextureValues();
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_textureInf, m_textureSup, m_textureName);
+ }
+ if ( event.param == 'E' )
+ {
+ FPOINT ti, ts;
+ ti.x = 0.00f;
+ ti.y = 0.00f;
+ ts.x = 0.00f;
+ ts.y = 0.00f;
+ MappingSelect(m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ ti, ts, "");
+ }
+ }
+ if ( m_mode == 2 )
+ {
+ if ( event.param == 'E' )
+ {
+ m_secondTexNum = 0;
+ UpdateInfoText();
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ }
+ if ( event.param == 'O' )
+ {
+ m_secondTexNum ++;
+ if ( m_secondTexNum > 10 ) m_secondTexNum = 1;
+ UpdateInfoText();
+ }
+ if ( event.param == 'T' )
+ {
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ m_engine->LoadAllTexture();
+ }
+ if ( event.param == 'U' )
+ {
+ m_secondOffsetU += 45;
+ if ( m_secondOffsetU >= 360 ) m_secondOffsetU = 0;
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ UpdateInfoText();
+ }
+ if ( event.param == 'V' )
+ {
+ m_secondOffsetV += 45;
+ if ( m_secondOffsetV >= 360 ) m_secondOffsetV = 0;
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ UpdateInfoText();
+ }
+ if ( event.param == 'X' )
+ {
+ m_bTextureMirrorX = !m_bTextureMirrorX;
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ UpdateInfoText();
+ }
+ if ( event.param == 'Y' )
+ {
+ m_bTextureMirrorY = !m_bTextureMirrorY;
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ UpdateInfoText();
+ }
+ if ( event.param == 'S' )
+ {
+ m_secondSubdiv ++;
+ if ( m_secondSubdiv > 7 ) m_secondSubdiv = 1;
+ MappingSelect2(m_secondTexNum, m_secondSubdiv, m_secondOffsetU, m_secondOffsetV, m_bTextureMirrorX, m_bTextureMirrorY);
+ UpdateInfoText();
+ }
+ }
+ if ( m_mode == 3 )
+ {
+ if ( event.param == 'M' )
+ {
+ if ( m_min == 0.0f && m_max == 1000000.0f )
+ {
+ m_min = 0.0f; m_max = 100.0f;
+ }
+ else if ( m_min == 0.0f && m_max == 100.0f )
+ {
+ m_min = 100.0f; m_max = 200.0f;
+ }
+ else if ( m_min == 100.0f && m_max == 200.0f )
+ {
+ m_min = 200.0f; m_max = 1000000.0f;
+ }
+ else if ( m_min == 200.0f && m_max == 1000000.0f )
+ {
+ m_min = 0.0f; m_max = 1000000.0f;
+ }
+ UpdateInfoText();
+ }
+ if ( event.param == 'C' )
+ {
+ MinMaxChange();
+ }
+ }
+ break;
+
+ case EVENT_BUTTON1: // import ?
+ GetDXFName(s);
+ m_modFile->ReadDXF(s, m_min, m_max);
+ DeselectAll();
+ CurrentInit();
+ EventFrame(event);
+ m_engine->LoadAllTexture();
+ break;
+
+ case EVENT_BUTTON2: // script ?
+ GetScriptName(s);
+ ReadScript(s);
+ DeselectAll();
+ CurrentInit();
+ EventFrame(event);
+ m_engine->LoadAllTexture();
+ break;
+
+ case EVENT_BUTTON3: // read ?
+ GetModelName(s);
+ m_modFile->ReadModel(s, TRUE, FALSE); // lit avec frontières standard
+ DeselectAll();
+ CurrentInit();
+ EventFrame(event);
+ m_engine->LoadAllTexture();
+ break;
+
+ case EVENT_BUTTON4: // add ?
+ GetModelName(s);
+ first = m_modFile->RetTriangleUsed();
+ m_modFile->AddModel(s, first, TRUE, FALSE); // lit avec frontières standard
+ last = m_modFile->RetTriangleUsed();
+ SelectZone(first, last);
+ EventFrame(event);
+ break;
+
+ case EVENT_BUTTON5: // write ?
+ GetModelName(s);
+ DeselectAll();
+ m_modFile->WriteModel(s);
+ break;
+
+ case EVENT_BUTTON10: // pos ?
+ m_oper = 'P';
+ break;
+ case EVENT_BUTTON11: // rotate ?
+ m_oper = 'R';
+ break;
+ case EVENT_BUTTON12: // zoom ?
+ m_oper = 'Z';
+ break;
+
+ case EVENT_BUTTON13: // +X ?
+ MoveSelect(D3DVECTOR(1.0f, 0.0f, 0.0f));
+ break;
+ case EVENT_BUTTON16: // -X ?
+ MoveSelect(D3DVECTOR(-1.0f, 0.0f, 0.0f));
+ break;
+ case EVENT_BUTTON14: // +Y ?
+ MoveSelect(D3DVECTOR(0.0f, 1.0f, 0.0f));
+ break;
+ case EVENT_BUTTON17: // -Y ?
+ MoveSelect(D3DVECTOR(0.0f, -1.0f, 0.0f));
+ break;
+ case EVENT_BUTTON15: // +Z ?
+ MoveSelect(D3DVECTOR(0.0f, 0.0f, 1.0f));
+ break;
+ case EVENT_BUTTON18: // -Z ?
+ MoveSelect(D3DVECTOR(0.0f, 0.0f, -1.0f));
+ break;
+ }
+
+ return 0;
+}
+
+
+// Anime le modèle.
+
+BOOL CModel::EventFrame(const Event &event)
+{
+ D3DMATERIAL7 matCurrent, matCurrenti, matCurrents, matTrans;
+ D3DMATERIAL7* pMat;
+ D3DVERTEX2 vertex[3];
+ char texName2[20];
+ int i, used, objRank, state;
+
+ m_time += event.rTime;
+
+ m_engine->FlushObject();
+ objRank = m_engine->CreateObject();
+
+ ZeroMemory(&matCurrent, sizeof(D3DMATERIAL7));
+ matCurrent.diffuse.r = 1.0f;
+ matCurrent.diffuse.g = 0.0f;
+ matCurrent.diffuse.b = 0.0f; // rouge
+ matCurrent.ambient.r = 0.5f;
+ matCurrent.ambient.g = 0.5f;
+ matCurrent.ambient.b = 0.5f;
+
+ ZeroMemory(&matCurrents, sizeof(D3DMATERIAL7));
+ matCurrents.diffuse.r = 1.0f;
+ matCurrents.diffuse.g = 1.0f;
+ matCurrents.diffuse.b = 0.0f; // jaune
+ matCurrents.ambient.r = 0.5f;
+ matCurrents.ambient.g = 0.5f;
+ matCurrents.ambient.b = 0.5f;
+
+ ZeroMemory(&matCurrenti, sizeof(D3DMATERIAL7));
+ matCurrenti.diffuse.r = 0.0f;
+ matCurrenti.diffuse.g = 0.0f;
+ matCurrenti.diffuse.b = 1.0f; // bleu
+ matCurrenti.ambient.r = 0.5f;
+ matCurrenti.ambient.g = 0.5f;
+ matCurrenti.ambient.b = 0.5f;
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( !m_triangleTable[i].bUsed ) continue;
+
+ if ( m_triangleTable[i].min != m_min ||
+ m_triangleTable[i].max != m_max ) continue;
+
+ pMat = &m_triangleTable[i].material;
+ state = D3DSTATENORMAL;
+
+ if ( i >= m_triangleSel1 &&
+ i <= m_triangleSel2 &&
+ (int)(m_time*10.0f)%2 == 0 )
+ {
+ pMat = &matCurrent;
+ }
+ else if ( m_triangleTable[i].bSelect &&
+ (int)(m_time*10.0f)%2 == 0 )
+ {
+ pMat = &matCurrents;
+ }
+ else
+ {
+ if ( m_bDisplayOnlySelection ) continue;
+ if ( m_bDisplayTransparent )
+ {
+ matTrans = m_triangleTable[i].material;
+ matTrans.diffuse.a = 0.1f; // très transparent
+ pMat = &matTrans;
+ state = D3DSTATETD;
+ }
+ }
+
+ if ( m_triangleTable[i].texNum2 == 0 )
+ {
+ m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3,
+ *pMat, state,
+ m_triangleTable[i].texName, "",
+ 0.0f, 1000000.0f, FALSE);
+ }
+ else
+ {
+ sprintf(texName2, "dirty%.2d.tga", m_triangleTable[i].texNum2);
+ m_engine->AddTriangle(objRank, &m_triangleTable[i].p1, 3,
+ *pMat, state|D3DSTATEDUALb,
+ m_triangleTable[i].texName, texName2,
+ 0.0f, 1000000.0f, FALSE);
+ }
+
+ if ( m_bDisplayTransparent && // dessine l'intérieur ?
+ i >= m_triangleSel1 &&
+ i <= m_triangleSel2 )
+ {
+ vertex[0] = m_triangleTable[i].p3;
+ vertex[1] = m_triangleTable[i].p2;
+ vertex[2] = m_triangleTable[i].p1;
+
+ m_engine->AddTriangle(objRank, vertex, 3,
+ matCurrenti, D3DSTATENORMAL,
+ m_triangleTable[i].texName, "",
+ 0.0f, 1000000.0f, FALSE);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Donne un vertex.
+
+BOOL CModel::GetVertex(int rank, D3DVERTEX2 &vertex)
+{
+ if ( rank < 0 || rank/3 >= m_modFile->RetTriangleUsed() ) return FALSE;
+ if ( !m_triangleTable[rank/3].bUsed ) return FALSE;
+
+ if ( !m_triangleTable[rank/3].bSelect ) return FALSE;
+
+ if ( rank%3 == 0 )
+ {
+ vertex = m_triangleTable[rank/3].p1;
+ return TRUE;
+ }
+ if ( rank%3 == 1 )
+ {
+ vertex = m_triangleTable[rank/3].p2;
+ return TRUE;
+ }
+ if ( rank%3 == 2 )
+ {
+ vertex = m_triangleTable[rank/3].p3;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Modifie un vertex.
+
+BOOL CModel::SetVertex(int rank, D3DVERTEX2 &vertex)
+{
+ if ( rank < 0 || rank/3 >= m_modFile->RetTriangleUsed() ) return FALSE;
+ if ( !m_triangleTable[rank/3].bUsed ) return FALSE;
+
+ if ( !m_triangleTable[rank/3].bSelect ) return FALSE;
+
+ if ( rank%3 == 0 )
+ {
+ m_triangleTable[rank/3].p1 = vertex;
+ return TRUE;
+ }
+ if ( rank%3 == 1 )
+ {
+ m_triangleTable[rank/3].p2 = vertex;
+ return TRUE;
+ }
+ if ( rank%3 == 2 )
+ {
+ m_triangleTable[rank/3].p3 = vertex;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Adouci les normales des triangles sélectionés.
+
+void CModel::SmoothSelect()
+{
+ char* bDone;
+ int index[100];
+ int used, i, j, rank;
+ D3DVERTEX2 vi, vj;
+ D3DVECTOR sum;
+
+ used = m_modFile->RetTriangleUsed();
+
+ bDone = (char*)malloc(used*3*sizeof(char));
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ bDone[i] = FALSE;
+ }
+
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ bDone[i] = TRUE;
+ rank = 0;
+ index[rank++] = i;
+ if ( !GetVertex(i, vi) ) continue;
+
+ for ( j=0 ; j<used*3 ; j++ )
+ {
+ if ( bDone[j] ) continue;
+ if ( !GetVertex(j, vj) ) continue;
+ if ( vj.x == vi.x &&
+ vj.y == vi.y &&
+ vj.z == vi.z )
+ {
+ bDone[j] = TRUE;
+ index[rank++] = j;
+ if ( rank >= 100 ) break;
+ }
+ }
+
+ sum.x = 0;
+ sum.y = 0;
+ sum.z = 0;
+ for ( j=0 ; j<rank ; j++ )
+ {
+ GetVertex(index[j], vj);
+ sum.x += vj.nx;
+ sum.y += vj.ny;
+ sum.z += vj.nz;
+ }
+ sum = Normalize(sum);
+
+ for ( j=0 ; j<rank ; j++ )
+ {
+ GetVertex(index[j], vj);
+ vj.nx = sum.x;
+ vj.ny = sum.y;
+ vj.nz = sum.z;
+ SetVertex(index[j], vj);
+ }
+ }
+
+ free(bDone);
+
+ SelectTerm();
+}
+
+
+// Durci les normales des triangles sélectionés.
+
+void CModel::PlaneSelect()
+{
+ D3DVECTOR p1, p2, p3, n;
+ int used, i;
+
+ used = m_modFile->RetTriangleUsed();
+
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].bSelect )
+ {
+ p1.x = m_triangleTable[i].p1.x;
+ p1.y = m_triangleTable[i].p1.y;
+ p1.z = m_triangleTable[i].p1.z;
+
+ p2.x = m_triangleTable[i].p2.x;
+ p2.y = m_triangleTable[i].p2.y;
+ p2.z = m_triangleTable[i].p2.z;
+
+ p3.x = m_triangleTable[i].p3.x;
+ p3.y = m_triangleTable[i].p3.y;
+ p3.z = m_triangleTable[i].p3.z;
+
+ n = ComputeNormal(p3, p2, p1);
+
+ m_triangleTable[i].p3.nx = n.x;
+ m_triangleTable[i].p3.ny = n.y;
+ m_triangleTable[i].p3.nz = n.z;
+ }
+ }
+ SelectTerm();
+}
+
+
+// Change la couleur des triangles sélectionés.
+
+void CModel::ColorSelect()
+{
+ int used, i;
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].bSelect )
+ {
+ m_triangleTable[i].material.diffuse.r = table_color[m_color*3+0];
+ m_triangleTable[i].material.diffuse.g = table_color[m_color*3+1];
+ m_triangleTable[i].material.diffuse.b = table_color[m_color*3+2];
+ }
+ }
+ SelectTerm();
+}
+
+// Change l'état des triangles sélectionés.
+
+void CModel::StateSelect()
+{
+ int used, i;
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].bSelect )
+ {
+ m_triangleTable[i].state = table_state[m_state];
+ }
+ }
+ SelectTerm();
+}
+
+// Déplace la sélection.
+
+void CModel::MoveSelect(D3DVECTOR move)
+{
+ if ( m_oper == 'Z' )
+ {
+ if ( move.x == +1 ) move.x = 1.1f;
+ else if ( move.x == -1 ) move.x = 1.0f/1.1f;
+ else move.x = 1.0f;
+ if ( move.y == +1 ) move.y = 1.1f;
+ else if ( move.y == -1 ) move.y = 1.0f/1.1f;
+ else move.y = 1.0f;
+ if ( move.z == +1 ) move.z = 1.1f;
+ else if ( move.z == -1 ) move.z = 1.0f/1.1f;
+ else move.z = 1.0f;
+ }
+ if ( m_oper == 'R' )
+ {
+#if 0
+ if ( move.x == +1 ) move.x = 5.0f*PI/180.0f;
+ else if ( move.x == -1 ) move.x = -5.0f*PI/180.0f;
+ if ( move.y == +1 ) move.y = 5.0f*PI/180.0f;
+ else if ( move.y == -1 ) move.y = -5.0f*PI/180.0f;
+ if ( move.z == +1 ) move.z = 5.0f*PI/180.0f;
+ else if ( move.z == -1 ) move.z = -5.0f*PI/180.0f;
+#else
+ if ( move.x == +1 ) move.x = 45.0f*PI/180.0f;
+ else if ( move.x == -1 ) move.x = -45.0f*PI/180.0f;
+ if ( move.y == +1 ) move.y = 45.0f*PI/180.0f;
+ else if ( move.y == -1 ) move.y = -45.0f*PI/180.0f;
+ if ( move.z == +1 ) move.z = 45.0f*PI/180.0f;
+ else if ( move.z == -1 ) move.z = -45.0f*PI/180.0f;
+#endif
+ }
+
+ OperSelect(move, m_oper);
+}
+
+// Déplace la sélection.
+
+void CModel::OperSelect(D3DVECTOR move, char oper)
+{
+ FPOINT rot;
+ int used, i;
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].bSelect )
+ {
+ if ( oper == 'P' )
+ {
+ m_triangleTable[i].p1.x += move.x;
+ m_triangleTable[i].p1.y += move.y;
+ m_triangleTable[i].p1.z += move.z;
+ m_triangleTable[i].p2.x += move.x;
+ m_triangleTable[i].p2.y += move.y;
+ m_triangleTable[i].p2.z += move.z;
+ m_triangleTable[i].p3.x += move.x;
+ m_triangleTable[i].p3.y += move.y;
+ m_triangleTable[i].p3.z += move.z;
+ }
+ if ( oper == 'Z' )
+ {
+ m_triangleTable[i].p1.x *= move.x;
+ m_triangleTable[i].p1.y *= move.y;
+ m_triangleTable[i].p1.z *= move.z;
+ m_triangleTable[i].p2.x *= move.x;
+ m_triangleTable[i].p2.y *= move.y;
+ m_triangleTable[i].p2.z *= move.z;
+ m_triangleTable[i].p3.x *= move.x;
+ m_triangleTable[i].p3.y *= move.y;
+ m_triangleTable[i].p3.z *= move.z;
+ }
+ if ( oper == 'R' )
+ {
+ if ( move.x != 0 )
+ {
+ rot.x = m_triangleTable[i].p1.z;
+ rot.y = m_triangleTable[i].p1.y;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.x, rot);
+ m_triangleTable[i].p1.z = rot.x;
+ m_triangleTable[i].p1.y = rot.y;
+
+ rot.x = m_triangleTable[i].p2.z;
+ rot.y = m_triangleTable[i].p2.y;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.x, rot);
+ m_triangleTable[i].p2.z = rot.x;
+ m_triangleTable[i].p2.y = rot.y;
+
+ rot.x = m_triangleTable[i].p3.z;
+ rot.y = m_triangleTable[i].p3.y;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.x, rot);
+ m_triangleTable[i].p3.z = rot.x;
+ m_triangleTable[i].p3.y = rot.y;
+ }
+ if ( move.y != 0 )
+ {
+ rot.x = m_triangleTable[i].p1.x;
+ rot.y = m_triangleTable[i].p1.z;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.y, rot);
+ m_triangleTable[i].p1.x = rot.x;
+ m_triangleTable[i].p1.z = rot.y;
+
+ rot.x = m_triangleTable[i].p2.x;
+ rot.y = m_triangleTable[i].p2.z;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.y, rot);
+ m_triangleTable[i].p2.x = rot.x;
+ m_triangleTable[i].p2.z = rot.y;
+
+ rot.x = m_triangleTable[i].p3.x;
+ rot.y = m_triangleTable[i].p3.z;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.y, rot);
+ m_triangleTable[i].p3.x = rot.x;
+ m_triangleTable[i].p3.z = rot.y;
+ }
+ if ( move.z != 0 )
+ {
+ rot.x = m_triangleTable[i].p1.x;
+ rot.y = m_triangleTable[i].p1.y;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.z, rot);
+ m_triangleTable[i].p1.x = rot.x;
+ m_triangleTable[i].p1.y = rot.y;
+
+ rot.x = m_triangleTable[i].p2.x;
+ rot.y = m_triangleTable[i].p2.y;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.z, rot);
+ m_triangleTable[i].p2.x = rot.x;
+ m_triangleTable[i].p2.y = rot.y;
+
+ rot.x = m_triangleTable[i].p3.x;
+ rot.y = m_triangleTable[i].p3.y;
+ rot = RotatePoint(FPOINT(0.0f, 0.0f), move.z, rot);
+ m_triangleTable[i].p3.x = rot.x;
+ m_triangleTable[i].p3.y = rot.y;
+ }
+ }
+ }
+ }
+ SelectTerm();
+}
+
+// Effectue un script de construction.
+
+void CModel::ReadScript(char *filename)
+{
+ FILE* file = NULL;
+ char line[200];
+ char name[200];
+ char buffer[200];
+ int i, first, last;
+ D3DVECTOR move;
+ BOOL bFirst = TRUE;
+
+ file = fopen(filename, "r");
+ if ( file == NULL ) return;
+
+ while ( fgets(line, 200, file) != NULL )
+ {
+ for ( i=0 ; i<200 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ if ( Cmd(line, "Object") )
+ {
+ OpString(line, "name", name);
+ sprintf(buffer, "objects\\%s.mod", name);
+
+ if ( bFirst )
+ {
+ m_modFile->ReadModel(buffer, TRUE, TRUE);
+ last = m_modFile->RetTriangleUsed();
+ SelectZone(0, last);
+ }
+ else
+ {
+ first = m_modFile->RetTriangleUsed();
+ m_modFile->AddModel(buffer, first, TRUE, FALSE);
+ last = m_modFile->RetTriangleUsed();
+ SelectZone(first, last);
+ }
+ bFirst = FALSE;
+
+ move = OpDir(line, "zoom");
+ OperSelect(move, 'Z');
+
+ move = OpDir(line, "rot");
+ move *= PI/180.0f; // degrés -> radians
+ OperSelect(move, 'R');
+
+ move = OpDir(line, "pos");
+ OperSelect(move, 'P');
+ }
+ }
+
+ fclose(file);
+}
+
+
+
+// Calcule la bbox des triangles sélectionnés.
+
+void CModel::BBoxCompute(D3DVECTOR &min, D3DVECTOR &max)
+{
+ D3DVERTEX2 vertex;
+ int used, i;
+
+ min.x = 1000000.0f;
+ min.y = 1000000.0f;
+ min.z = 1000000.0f;
+ max.x = -1000000.0f;
+ max.y = -1000000.0f;
+ max.z = -1000000.0f;
+
+ used = m_modFile->RetTriangleUsed();
+
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ if ( vertex.x < min.x ) min.x = vertex.x;
+ if ( vertex.y < min.y ) min.y = vertex.y;
+ if ( vertex.z < min.z ) min.z = vertex.z;
+
+ if ( vertex.x > max.x ) max.x = vertex.x;
+ if ( vertex.y > max.y ) max.y = vertex.y;
+ if ( vertex.z > max.z ) max.z = vertex.z;
+ }
+}
+
+// Retourne le centre de gravité de la sélection.
+
+D3DVECTOR CModel::RetSelectCDG()
+{
+ D3DVECTOR min, max, cdg;
+
+ BBoxCompute(min, max);
+
+ cdg.x = (min.x+max.x)/2.0f;
+ cdg.y = (min.y+max.y)/2.0f;
+ cdg.z = (min.z+max.z)/2.0f;
+
+ return cdg;
+}
+
+// Retourne le vecteur normal de la sélection.
+
+D3DVECTOR CModel::RetSelectNormal()
+{
+ D3DVECTOR p1, p2, p3, n;
+
+ p1.x = m_triangleTable[m_triangleSel1].p1.nx;
+ p1.y = m_triangleTable[m_triangleSel1].p1.ny;
+ p1.z = m_triangleTable[m_triangleSel1].p1.nz;
+
+ p2.x = m_triangleTable[m_triangleSel1].p2.nx;
+ p2.y = m_triangleTable[m_triangleSel1].p2.ny;
+ p2.z = m_triangleTable[m_triangleSel1].p2.nz;
+
+ p3.x = m_triangleTable[m_triangleSel1].p3.nx;
+ p3.y = m_triangleTable[m_triangleSel1].p3.ny;
+ p3.z = m_triangleTable[m_triangleSel1].p3.nz;
+
+ n = Normalize(p1+p2+p3);
+
+ return n;
+}
+
+// Mappe une texture sur les triangles sélectionnés.
+
+BOOL CModel::IsMappingSelectPlausible(D3DMaping D3Dmode)
+{
+ D3DVERTEX2 vertex[3];
+ D3DVECTOR min, max;
+ FPOINT a, b, ti, ts;
+ float au, bu, av, bv;
+ int used, i, j;
+
+ ti.x = 0.0f;
+ ti.y = 0.0f;
+ ts.x = 1.0f;
+ ts.y = 1.0f;
+
+ BBoxCompute(min, max);
+
+ if ( D3Dmode == D3DMAPPINGX )
+ {
+ a.x = min.z;
+ a.y = min.y;
+ b.x = max.z;
+ b.y = max.y;
+ }
+ if ( D3Dmode == D3DMAPPINGY )
+ {
+ a.x = min.x;
+ a.y = min.z;
+ b.x = max.x;
+ b.y = max.z;
+ }
+ if ( D3Dmode == D3DMAPPINGZ )
+ {
+ a.x = min.x;
+ a.y = min.y;
+ b.x = max.x;
+ b.y = max.y;
+ }
+
+ au = (ts.x-ti.x)/(b.x-a.x);
+ bu = ts.x-b.x*(ts.x-ti.x)/(b.x-a.x);
+
+ av = (ts.y-ti.y)/(b.y-a.y);
+ bv = ts.y-b.y*(ts.y-ti.y)/(b.y-a.y);
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( !GetVertex(i*3+0, vertex[0]) ) continue;
+ if ( !GetVertex(i*3+1, vertex[1]) ) continue;
+ if ( !GetVertex(i*3+2, vertex[2]) ) continue;
+
+ for ( j=0 ; j<3 ; j++ )
+ {
+ if ( D3Dmode == D3DMAPPINGX )
+ {
+ vertex[j].tu = vertex[j].z*au+bu;
+ vertex[j].tv = vertex[j].y*av+bv;
+ }
+ if ( D3Dmode == D3DMAPPINGY )
+ {
+ vertex[j].tu = vertex[j].x*au+bu;
+ vertex[j].tv = vertex[j].z*av+bv;
+ }
+ if ( D3Dmode == D3DMAPPINGZ )
+ {
+ vertex[j].tu = vertex[j].x*au+bu;
+ vertex[j].tv = vertex[j].y*av+bv;
+ }
+ }
+
+ if ( vertex[0].tu == vertex[1].tu &&
+ vertex[0].tu == vertex[2].tu ) return FALSE;
+
+ if ( vertex[0].tv == vertex[1].tv &&
+ vertex[0].tv == vertex[2].tv ) return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Mappe une texture sur les triangles sélectionnés.
+
+void CModel::MappingSelect(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY,
+ FPOINT ti, FPOINT ts, char *texName)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR min, max;
+ FPOINT a, b;
+ D3DMaping D3Dmode;
+ float au, bu, av, bv;
+ int used, i;
+ BOOL bPlausible[3];
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( !m_triangleTable[i].bUsed ) continue;
+ if ( !m_triangleTable[i].bSelect ) continue;
+
+ strcpy(m_triangleTable[i].texName, texName);
+ }
+
+ if ( mode == 1 )
+ {
+ MappingSelectSpherical(mode, rotate, bMirrorX, bMirrorY, ti, ts, texName);
+ return;
+ }
+ if ( mode == 2 )
+ {
+ MappingSelectCylindrical(mode, rotate, bMirrorX, bMirrorY, ti, ts, texName);
+ return;
+ }
+ if ( mode == 3 )
+ {
+ MappingSelectFace(mode, rotate, bMirrorX, bMirrorY, ti, ts, texName);
+ return;
+ }
+
+ BBoxCompute(min, max);
+
+ bPlausible[0] = IsMappingSelectPlausible(D3DMAPPINGX);
+ bPlausible[1] = IsMappingSelectPlausible(D3DMAPPINGY);
+ bPlausible[2] = IsMappingSelectPlausible(D3DMAPPINGZ);
+
+ for ( i=0 ; i<9 ; i++ )
+ {
+ if ( !bPlausible[i%3] ) continue;
+ if ( rotate-- == 0 ) break;
+ }
+ if ( i%3 == 0 ) D3Dmode = D3DMAPPINGX;
+ if ( i%3 == 1 ) D3Dmode = D3DMAPPINGY;
+ if ( i%3 == 2 ) D3Dmode = D3DMAPPINGZ;
+
+ if ( D3Dmode == D3DMAPPINGX )
+ {
+ a.x = min.z;
+ a.y = min.y;
+ b.x = max.z;
+ b.y = max.y;
+ }
+ if ( D3Dmode == D3DMAPPINGY )
+ {
+ a.x = min.x;
+ a.y = min.z;
+ b.x = max.x;
+ b.y = max.z;
+ }
+ if ( D3Dmode == D3DMAPPINGZ )
+ {
+ a.x = min.x;
+ a.y = min.y;
+ b.x = max.x;
+ b.y = max.y;
+ }
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ au = (ts.x-ti.x)/(b.x-a.x);
+ bu = ts.x-b.x*(ts.x-ti.x)/(b.x-a.x);
+
+ av = (ts.y-ti.y)/(b.y-a.y);
+ bv = ts.y-b.y*(ts.y-ti.y)/(b.y-a.y);
+
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ if ( D3Dmode == D3DMAPPINGX )
+ {
+ vertex.tu = vertex.z*au+bu;
+ vertex.tv = vertex.y*av+bv;
+ }
+ if ( D3Dmode == D3DMAPPINGY )
+ {
+ vertex.tu = vertex.x*au+bu;
+ vertex.tv = vertex.z*av+bv;
+ }
+ if ( D3Dmode == D3DMAPPINGZ )
+ {
+ vertex.tu = vertex.x*au+bu;
+ vertex.tv = vertex.y*av+bv;
+ }
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+// Mappe une texture sur les triangles sélectionnés.
+
+void CModel::MappingSelectSpherical(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY,
+ FPOINT ti, FPOINT ts, char *texName)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR min, max, center, dim, p;
+ float radius, k, u, v;
+ int used, i;
+
+ BBoxCompute(min, max);
+ center = (min+max)/2.0f;
+ dim = (max-min)/2.0f;
+ radius = Min(dim.x, dim.y, dim.z);
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ p.x = vertex.x-center.x;
+ p.y = vertex.y-center.y;
+ p.z = vertex.z-center.z;
+
+ k = radius/Length(p);
+ u = k*p.x;
+ v = k*p.z;
+ u = (u/dim.x*2.0f+1.0f)/2.0f; // 0..1
+ v = (v/dim.z*2.0f+1.0f)/2.0f;
+
+ vertex.tu = ti.x+(ts.x-ti.x)*u;
+ vertex.tv = ti.y+(ts.y-ti.y)*v;
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+// Cherche le centre d'un groupe de points.
+
+D3DVECTOR CModel::RetMappingCenter(D3DVECTOR pos, D3DVECTOR min)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR center, p;
+ int used, i, nb;
+
+ center.x = 0.0f;
+ center.y = 0.0f;
+ center.z = 0.0f;
+
+ nb = 0;
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ p.x = vertex.x;
+ p.y = vertex.y;
+ p.z = vertex.z;
+
+ if ( Abs(p.x-pos.x) <= min.x &&
+ Abs(p.y-pos.y) <= min.y &&
+ Abs(p.z-pos.z) <= min.z )
+ {
+ center.x += p.x;
+ center.y += p.y;
+ center.z += p.z;
+ nb ++;
+ }
+ }
+
+ if ( nb == 0 ) return pos;
+
+ center.x /= (float)nb;
+ center.y /= (float)nb;
+ center.z /= (float)nb;
+
+ return center;
+}
+
+// Mappe une texture sur les triangles sélectionnés.
+
+void CModel::MappingSelectCylindrical(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY,
+ FPOINT ti, FPOINT ts, char *texName)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR min, max, center, local, dim, p, pp, box;
+ float radius, u, v;
+ int used, i;
+
+ BBoxCompute(min, max);
+ center = (min+max)/2.0f;
+ dim = (max-min)/2.0f;
+ radius = Min(dim.x, dim.y, dim.z);
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ if ( rotate == 0 )
+ {
+ box.x = 2.0f;
+ box.y = 10.0f;
+ box.z = 10.0f;
+ }
+ if ( rotate == 1 )
+ {
+ box.x = 10.0f;
+ box.y = 2.0f;
+ box.z = 10.0f;
+ }
+ if ( rotate == 2 )
+ {
+ box.x = 10.0f;
+ box.y = 10.0f;
+ box.z = 2.0f;
+ }
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ p.x = vertex.x;
+ p.y = vertex.y;
+ p.z = vertex.z;
+
+#if 1
+ p.x -= center.x;
+ p.y -= center.y;
+ p.z -= center.z;
+
+ pp = p;
+#else
+ local = RetMappingCenter(p, box);
+
+ pp = p;
+ pp.x -= local.x;
+ pp.y -= local.y;
+ pp.z -= local.z;
+
+ p.x -= center.x;
+ p.y -= center.y;
+ p.z -= center.z;
+#endif
+
+ if ( rotate == 0 )
+ {
+ u = RotateAngle(pp.y, pp.z);
+ v = p.x/dim.x/2.0f + 0.5f;
+ }
+ if ( rotate == 1 )
+ {
+ u = RotateAngle(pp.x, pp.z);
+ v = p.y/dim.y/2.0f + 0.5f;
+ }
+ if ( rotate == 2 )
+ {
+ u = RotateAngle(pp.x, pp.y);
+ v = p.z/dim.z/2.0f + 0.5f;
+ }
+
+//? if ( u < PI ) u = u/PI;
+//? else u = 2.0f-u/PI;
+ u = u/(PI*2.0f);
+
+ vertex.tu = ti.x+(ts.x-ti.x)*u;
+ vertex.tv = ti.y+(ts.y-ti.y)*v;
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+
+// Mappe une texture sur les triangles sélectionnés.
+
+void CModel::MappingSelectFace(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY,
+ FPOINT ti, FPOINT ts, char *texName)
+{
+ D3DVERTEX2 vertex[3];
+ D3DVECTOR min, max, center, local, dim, p;
+ float radius, u[3], v[3], m[3], avg;
+ int used, i, j;
+
+ BBoxCompute(min, max);
+ center = (min+max)/2.0f;
+ dim = (max-min)/2.0f;
+ radius = Min(dim.x, dim.y, dim.z);
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ for ( j=0 ; j<3 ; j++ )
+ {
+ if ( !GetVertex(i*3+j, vertex[j]) ) continue;
+
+ p.x = vertex[j].x - center.x;
+ p.y = vertex[j].y - center.y;
+ p.z = vertex[j].z - center.z;
+
+#if 0
+ u[j] = RotateAngle(p.x, p.z)/(PI*2.0f)+0.5f;
+ if ( u[j] > 1.0f ) u[j] -= 1.0f;
+#else
+ u[j] = RotateAngle(p.x, p.z)/PI;
+//? if ( u[j] > 1.0f ) u[j] = 2.0f-u[j];
+ if ( u[j] > 1.0f ) u[j] -= 1.0f;
+#endif
+
+ v[j] = p.y/dim.y/2.0f + 0.5f;
+
+ if ( u[j] < 0.5f ) m[j] = u[j];
+ else m[j] = u[j]-1.0f;
+ }
+
+ avg = (m[0]+m[1]+m[2])/3.0f;
+
+ for ( j=0 ; j<3 ; j++ )
+ {
+ if ( u[j] < 0.05f || u[j] > 0.95f )
+ {
+ if ( avg > 0.0f ) u[j] = 0.0f;
+ else u[j] = 1.0f;
+ }
+
+ vertex[j].tu = ti.x+(ts.x-ti.x)*u[j];
+ vertex[j].tv = ti.y+(ts.y-ti.y)*v[j];
+
+ SetVertex(i*3+j, vertex[j]);
+ }
+ }
+
+ SelectTerm();
+}
+
+
+// Mappe une texture secondaire sur les triangles sélectionnés.
+
+void CModel::MappingSelect2(int texNum2, int subdiv,
+ int offsetU, int offsetV,
+ BOOL bMirrorX, BOOL bMirrorY)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR min, max, center, p;
+ float u ,v;
+ int used, i;
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( !m_triangleTable[i].bUsed ) continue;
+ if ( !m_triangleTable[i].bSelect ) continue;
+
+ m_triangleTable[i].texNum2 = texNum2;
+ }
+
+ if ( subdiv == 6 )
+ {
+ MappingSelectSpherical2(bMirrorX, bMirrorY);
+ return;
+ }
+ if ( subdiv == 7 )
+ {
+ MappingSelectMagic2(bMirrorX, bMirrorY);
+ return;
+ }
+ if ( subdiv > 2 )
+ {
+ MappingSelectPlane2(subdiv-3, bMirrorX, bMirrorY);
+ return;
+ }
+
+ BBoxCompute(min, max);
+ center = (min+max)/2.0f;
+
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ p.x = vertex.x-center.x;
+ p.y = vertex.y-center.y;
+ p.z = vertex.z-center.z;
+
+ u = RotateAngle(p.x, p.z);
+ v = RotateAngle(Length(p.x, p.z), p.y);
+ if ( p.x < 0.0f ) v += PI;
+
+ u = NormAngle(u+(float)offsetU*PI/180.0f);
+ v = NormAngle(v+(float)offsetV*PI/180.0f);
+
+ if ( subdiv == 1 )
+ {
+ u = u/(PI*2.0f);
+ v = v/(PI*2.0f);
+ }
+ if ( subdiv == 2 )
+ {
+ if ( u < PI ) u = u/PI;
+ else u = (PI*2.0f-u)/PI;
+ if ( v < PI ) v = v/PI;
+ else v = (PI*2.0f-v)/PI;
+ }
+
+ vertex.tu2 = u;
+ vertex.tv2 = v;
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+// Mappe une texture secondaire à plat.
+
+void CModel::MappingSelectPlane2(int mode, BOOL bMirrorX, BOOL bMirrorY)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR min, max;
+ FPOINT ti, ts, a, b;
+ float au, bu, av, bv;
+ int used, i;
+
+ ti = FPOINT(0.0f, 0.0f);
+ ts = FPOINT(1.0f, 1.0f);
+
+ BBoxCompute(min, max);
+
+ if ( mode == 0 )
+ {
+ a.x = min.z;
+ a.y = min.y;
+ b.x = max.z;
+ b.y = max.y;
+ }
+ if ( mode == 1 )
+ {
+ a.x = min.x;
+ a.y = min.z;
+ b.x = max.x;
+ b.y = max.z;
+ }
+ if ( mode == 2 )
+ {
+ a.x = min.x;
+ a.y = min.y;
+ b.x = max.x;
+ b.y = max.y;
+ }
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ au = (ts.x-ti.x)/(b.x-a.x);
+ bu = ts.x-b.x*(ts.x-ti.x)/(b.x-a.x);
+
+ av = (ts.y-ti.y)/(b.y-a.y);
+ bv = ts.y-b.y*(ts.y-ti.y)/(b.y-a.y);
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ if ( mode == 0 )
+ {
+ vertex.tu2 = vertex.z*au+bu;
+ vertex.tv2 = vertex.y*av+bv;
+ }
+ if ( mode == 1 )
+ {
+ vertex.tu2 = vertex.x*au+bu;
+ vertex.tv2 = vertex.z*av+bv;
+ }
+ if ( mode == 2 )
+ {
+ vertex.tu2 = vertex.x*au+bu;
+ vertex.tv2 = vertex.y*av+bv;
+ }
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+// Mappe une texture sur les triangles sélectionnés.
+
+void CModel::MappingSelectSpherical2(BOOL bMirrorX, BOOL bMirrorY)
+{
+ D3DVERTEX2 vertex;
+ D3DVECTOR min, max, center, dim, p;
+ FPOINT ti, ts;
+ float radius, k, u, v;
+ int used, i;
+
+ BBoxCompute(min, max);
+ center = (min+max)/2.0f;
+ dim = (max-min)/2.0f;
+ radius = Min(dim.x, dim.y, dim.z);
+
+ ti = FPOINT(0.0f, 0.0f);
+ ts = FPOINT(1.0f, 1.0f);
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( !GetVertex(i, vertex) ) continue;
+
+ p.x = vertex.x-center.x;
+ p.y = vertex.y-center.y;
+ p.z = vertex.z-center.z;
+
+ k = radius/Length(p);
+ u = k*p.x;
+ v = k*p.z;
+ u = (u/dim.x*2.0f+1.0f)/2.0f; // 0..1
+ v = (v/dim.z*2.0f+1.0f)/2.0f;
+
+ vertex.tu2 = ti.x+(ts.x-ti.x)*u;
+ vertex.tv2 = ti.y+(ts.y-ti.y)*v;
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+// Mappe une texture sur les triangles sélectionnés.
+
+void CModel::MappingSelectMagic2(BOOL bMirrorX, BOOL bMirrorY)
+{
+ D3DVERTEX2 vertex, v[3];
+ D3DVECTOR min, max, au, bu, av, bv, n;
+ FPOINT ti, ts;
+ int used, i, mode;
+
+ ti = FPOINT(0.0f, 0.0f);
+ ts = FPOINT(1.0f, 1.0f);
+
+ BBoxCompute(min, max);
+
+ if ( bMirrorX )
+ {
+ Swap(ti.x, ts.x);
+ }
+
+ if ( !bMirrorY ) // test inversé !
+ {
+ Swap(ti.y, ts.y);
+ }
+
+ au.x = (ts.x-ti.x)/(max.x-min.x);
+ bu.x = ts.x-max.x*(ts.x-ti.x)/(max.x-min.x);
+ au.y = (ts.x-ti.x)/(max.y-min.y);
+ bu.y = ts.x-max.y*(ts.x-ti.x)/(max.y-min.y);
+ au.z = (ts.x-ti.x)/(max.z-min.z);
+ bu.z = ts.x-max.z*(ts.x-ti.x)/(max.z-min.z);
+
+ av.x = (ts.y-ti.y)/(max.x-min.x);
+ bv.x = ts.y-max.x*(ts.y-ti.y)/(max.x-min.x);
+ av.y = (ts.y-ti.y)/(max.y-min.y);
+ bv.y = ts.y-max.y*(ts.y-ti.y)/(max.y-min.y);
+ av.z = (ts.y-ti.y)/(max.z-min.z);
+ bv.z = ts.y-max.z*(ts.y-ti.y)/(max.z-min.z);
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used*3 ; i++ )
+ {
+ if ( i%3 == 0 )
+ {
+ if ( !GetVertex(i+0, v[0]) ) continue;
+ if ( !GetVertex(i+1, v[1]) ) continue;
+ if ( !GetVertex(i+2, v[2]) ) continue;
+
+ n = ComputeNormal(D3DVECTOR(v[0].x, v[0].y, v[0].z),
+ D3DVECTOR(v[1].x, v[1].y, v[1].z),
+ D3DVECTOR(v[2].x, v[2].y, v[2].z));
+
+ n.x = Abs(n.x);
+ n.y = Abs(n.y);
+ n.z = Abs(n.z);
+
+ if ( n.x >= Max(n.y, n.z) ) mode = 0;
+ if ( n.y >= Max(n.x, n.z) ) mode = 1;
+ if ( n.z >= Max(n.x, n.y) ) mode = 2;
+ }
+
+ if ( !GetVertex(i, vertex) ) continue;
+
+ if ( mode == 0 )
+ {
+ vertex.tu2 = vertex.z*au.z+bu.z;
+ vertex.tv2 = vertex.y*av.y+bv.y;
+ }
+ if ( mode == 1 )
+ {
+ vertex.tu2 = vertex.x*au.x+bu.x;
+ vertex.tv2 = vertex.z*av.z+bv.z;
+ }
+ if ( mode == 2 )
+ {
+ vertex.tu2 = vertex.x*au.x+bu.x;
+ vertex.tv2 = vertex.y*av.y+bv.y;
+ }
+
+ SetVertex(i, vertex);
+ }
+
+ SelectTerm();
+}
+
+
+// Cherche le triangle suivant.
+
+int CModel::SearchNext(int rank, int step)
+{
+ int max, i;
+
+ max = m_modFile->RetTriangleUsed();
+
+ for ( i=0 ; i<max ; i++ )
+ {
+ rank += step;
+ if ( rank < 0 ) rank = max-1;
+ if ( rank >= max ) rank = 0;
+
+ if ( m_triangleTable[rank].min != m_min ||
+ m_triangleTable[rank].max != m_max ) continue;
+
+ if ( m_triangleTable[rank].bUsed ) break;
+ }
+ return rank;
+}
+
+// Cherche tous les triangles faisant partie du même plan.
+
+int CModel::SearchSamePlane(int first, int step)
+{
+ D3DVECTOR vFirst[3], vNext[3];
+ int last, i;
+
+ vFirst[0].x = m_triangleTable[first].p1.x;
+ vFirst[0].y = m_triangleTable[first].p1.y;
+ vFirst[0].z = m_triangleTable[first].p1.z;
+ vFirst[1].x = m_triangleTable[first].p2.x;
+ vFirst[1].y = m_triangleTable[first].p2.y;
+ vFirst[1].z = m_triangleTable[first].p2.z;
+ vFirst[2].x = m_triangleTable[first].p3.x;
+ vFirst[2].y = m_triangleTable[first].p3.y;
+ vFirst[2].z = m_triangleTable[first].p3.z;
+
+ for ( i=0 ; i<1000 ; i++ )
+ {
+ last = first;
+ first = SearchNext(first, step);
+
+ vNext[0].x = m_triangleTable[first].p1.x;
+ vNext[0].y = m_triangleTable[first].p1.y;
+ vNext[0].z = m_triangleTable[first].p1.z;
+ vNext[1].x = m_triangleTable[first].p2.x;
+ vNext[1].y = m_triangleTable[first].p2.y;
+ vNext[1].z = m_triangleTable[first].p2.z;
+ vNext[2].x = m_triangleTable[first].p3.x;
+ vNext[2].y = m_triangleTable[first].p3.y;
+ vNext[2].z = m_triangleTable[first].p3.z;
+
+ if ( !IsSamePlane(vFirst, vNext) ) // autre plan ?
+ {
+ return last;
+ }
+ }
+ return first;
+}
+
+// Cherche le triangle suivant.
+
+void CModel::CurrentSearchNext(int step, BOOL bControl)
+{
+ if ( step > 0 ) // en avant ?
+ {
+ m_triangleSel1 = SearchNext(m_triangleSel2, step);
+ if ( bControl )
+ {
+ m_triangleSel2 = m_triangleSel1;
+ }
+ else
+ {
+ m_triangleSel2 = SearchSamePlane(m_triangleSel1, step);
+ }
+ }
+ if ( step < 0 ) // en arrière ?
+ {
+ m_triangleSel2 = SearchNext(m_triangleSel1, step);
+ if ( bControl )
+ {
+ m_triangleSel1 = m_triangleSel2;
+ }
+ else
+ {
+ m_triangleSel1 = SearchSamePlane(m_triangleSel2, step);
+ }
+ }
+
+#if 0
+ char s[100];
+ sprintf(s, "(%.2f;%.2f;%.2f) (%.2f;%.2f;%.2f) (%.2f;%.2f;%.2f)",
+ m_triangleTable[m_triangleSel1].p1.x,
+ m_triangleTable[m_triangleSel1].p1.y,
+ m_triangleTable[m_triangleSel1].p1.z,
+ m_triangleTable[m_triangleSel1].p2.x,
+ m_triangleTable[m_triangleSel1].p2.y,
+ m_triangleTable[m_triangleSel1].p2.z,
+ m_triangleTable[m_triangleSel1].p3.x,
+ m_triangleTable[m_triangleSel1].p3.y,
+ m_triangleTable[m_triangleSel1].p3.z);
+ m_engine->SetInfoText(2, s);
+ sprintf(s, "(%.2f;%.2f) (%.2f;%.2f) (%.2f;%.2f)",
+ m_triangleTable[m_triangleSel1].p1.tu2,
+ m_triangleTable[m_triangleSel1].p1.tv2,
+ m_triangleTable[m_triangleSel1].p2.tu2,
+ m_triangleTable[m_triangleSel1].p2.tv2,
+ m_triangleTable[m_triangleSel1].p3.tu2,
+ m_triangleTable[m_triangleSel1].p3.tv2);
+ m_engine->SetInfoText(3, s);
+#endif
+
+ InitViewFromSelect();
+ UpdateInfoText();
+}
+
+// Initialise les triangles courants initiaux.
+
+void CModel::CurrentInit()
+{
+ m_triangleSel1 = 0;
+ m_triangleSel2 = SearchSamePlane(m_triangleSel1, +1);
+
+ InitViewFromSelect();
+ UpdateInfoText();
+}
+
+// Sélectionne les triangles courants.
+
+void CModel::CurrentSelect(BOOL bSelect)
+{
+ int i;
+
+ for ( i=m_triangleSel1 ; i<=m_triangleSel2 ; i++ )
+ {
+ m_triangleTable[i].bSelect = bSelect;
+ }
+}
+
+
+// Désélectionne tous les triangles.
+
+void CModel::DeselectAll()
+{
+ int used, i;
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ m_triangleTable[i].bSelect = FALSE;
+ }
+}
+
+// Sélectionne une zone.
+
+void CModel::SelectZone(int first, int last)
+{
+ int used, i;
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ m_triangleTable[i].bSelect = FALSE;
+ if ( i >= first && i < last )
+ {
+ m_triangleTable[i].bSelect = TRUE;
+ }
+ }
+ m_triangleSel1 = first;
+ m_triangleSel2 = last-1;
+}
+
+// Sélectionne tous les triangles.
+
+void CModel::SelectAll()
+{
+ int used, i;
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].min == m_min &&
+ m_triangleTable[i].max == m_max )
+ {
+ m_triangleTable[i].bSelect = TRUE;
+ }
+ }
+}
+
+// Désélectionne tous les triangles.
+
+void CModel::SelectTerm()
+{
+ int used, i;
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( i >= m_triangleSel1 && i <= m_triangleSel2 )
+ {
+ if ( !m_triangleTable[i].bSelect ) return;
+ }
+ else
+ {
+ if ( m_triangleTable[i].bSelect ) return;
+ }
+ }
+
+ DeselectAll();
+}
+
+// Sélectionne les triangles courants.
+
+void CModel::DefaultSelect()
+{
+ int used, i;
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=m_triangleSel1 ; i<=m_triangleSel2 ; i++ )
+ {
+ m_triangleTable[i].bSelect = TRUE;
+ }
+}
+
+
+
+// Supprime tous les triangles sélectionnés.
+
+void CModel::SelectDelete()
+{
+ int used ,i;
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].bSelect )
+ {
+ m_triangleTable[i].bUsed = FALSE;
+ }
+ }
+
+ i = m_triangleSel1;
+ Compress();
+
+ m_triangleSel1 = i;
+ m_triangleSel2 = SearchSamePlane(m_triangleSel1, +1);
+ InitViewFromSelect();
+ UpdateInfoText();
+}
+
+// Compresse tous les triangles.
+
+void CModel::Compress()
+{
+ int used, i, j;
+
+ j = 0;
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( m_triangleTable[i].bUsed )
+ {
+ m_triangleTable[j++] = m_triangleTable[i];
+ }
+ }
+ m_modFile->SetTriangleUsed(j);
+ CurrentInit();
+}
+
+
+// Change le min/max de tous les triangles sélectionnés.
+
+void CModel::MinMaxChange()
+{
+ int used, i;
+
+ DefaultSelect();
+
+ used = m_modFile->RetTriangleUsed();
+ for ( i=0 ; i<used ; i++ )
+ {
+ if ( !m_triangleTable[i].bSelect ) continue;
+
+ m_triangleTable[i].min = m_min;
+ m_triangleTable[i].max = m_max;
+ }
+}
+
+
+// Initialise le point de vue.
+
+void CModel::InitView()
+{
+ m_viewHeight = 5.0f;
+ m_viewDist = 50.0f;
+ m_viewAngleH = 0.0f;
+ m_viewAngleV = 0.0f;
+}
+
+// Initialise le point de vue pour voir les triangles sélectionnés.
+
+void CModel::InitViewFromSelect()
+{
+#if 0
+ D3DVECTOR n;
+ float h,v;
+
+ n = RetSelectNormal();
+
+ m_viewAngleH = RotateAngle(n.x, n.z)+PI;
+ m_viewAngleV = RotateAngle(sqrtf(n.x*n.x+n.z*n.z), n.y)+PI;
+ h = m_viewAngleH;
+ v = m_viewAngleV;
+
+ while ( m_viewAngleV <= -PI )
+ {
+ m_viewAngleV += PI;
+ m_viewAngleH += PI;
+ }
+ while ( m_viewAngleV >= PI )
+ {
+ m_viewAngleV -= PI;
+ m_viewAngleH -= PI;
+ }
+ m_viewAngleV *= 0.75f;
+
+ char s[100];
+ sprintf(s, "angle=%f %f -> %f %f\n", h,v, m_viewAngleH, m_viewAngleV);
+ OutputDebugString(s);
+#endif
+}
+
+// Met à jour les paramètres pour le point de vue.
+
+void CModel::UpdateView()
+{
+ D3DVECTOR eye, lookat, vUpVec;
+
+//? lookat = RetSelectCDG();
+ lookat = D3DVECTOR(0.0f, m_viewHeight, 0.0f);
+ eye = RotateView(lookat, m_viewAngleH, m_viewAngleV, m_viewDist);
+
+ vUpVec = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ m_engine->SetViewParams(eye, lookat, vUpVec, 10.0f);
+ m_engine->SetRankView(0);
+}
+
+// Déplace le point de vue.
+
+void CModel::ViewMove(const Event &event, float speed)
+{
+ if ( IsEditFocus() ) return;
+
+ // Up/Down.
+ if ( event.axeY > 0.5f )
+ {
+ if ( event.keyState & KS_CONTROL )
+ {
+ m_viewHeight += event.rTime*10.0f*speed;
+ if ( m_viewHeight > 100.0f ) m_viewHeight = 100.0f;
+ }
+ else
+ {
+ m_viewAngleV -= event.rTime*1.0f*speed;
+ if ( m_viewAngleV < -PI*0.49f ) m_viewAngleV = -PI*0.49f;
+ }
+ }
+ if ( event.axeY < -0.5f )
+ {
+ if ( event.keyState & KS_CONTROL )
+ {
+ m_viewHeight -= event.rTime*10.0f*speed;
+ if ( m_viewHeight < -100.0f ) m_viewHeight = -100.0f;
+ }
+ else
+ {
+ m_viewAngleV += event.rTime*1.0f*speed;
+ if ( m_viewAngleV > PI*0.49f ) m_viewAngleV = PI*0.49f;
+ }
+ }
+
+ // Left/Right.
+ if ( event.axeX < -0.5f )
+ {
+ m_viewAngleH -= event.rTime*1.0f*speed;
+ }
+ if ( event.axeX > 0.5f )
+ {
+ m_viewAngleH += event.rTime*1.0f*speed;
+ }
+
+ // PageUp/PageDown.
+ if ( event.keyState & KS_PAGEUP )
+ {
+ m_viewDist -= event.rTime*30.0f*speed;
+ if ( m_viewDist < 1.0f ) m_viewDist = 1.0f;
+ }
+ if ( event.keyState & KS_PAGEDOWN )
+ {
+ m_viewDist += event.rTime*30.0f*speed;
+ if ( m_viewDist > 300.0f ) m_viewDist = 300.0f;
+ }
+}
+
+
+
+// Met à jour le texte d'informations.
+
+void CModel::UpdateInfoText()
+{
+ char info[100];
+
+ if ( m_mode == 1 )
+ {
+ sprintf(info, "[1] V:color=%d K:state=%d Sel=%d..%d (T=%d)",
+ m_color, m_state,
+ m_triangleSel1, m_triangleSel2,
+ m_triangleSel2-m_triangleSel1+1);
+ m_engine->SetInfoText(0, info);
+
+ sprintf(info, "M:mode=%d Z:rot=%d XY:mir=%d;%d P:part=%d O:name=%s",
+ m_textureMode, m_textureRotate,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_texturePart, m_textureName);
+ m_engine->SetInfoText(1, info);
+ }
+
+ if ( m_mode == 2 )
+ {
+ sprintf(info, "[2] Sel=%d..%d (T=%d)",
+ m_triangleSel1, m_triangleSel2,
+ m_triangleSel2-m_triangleSel1+1);
+ m_engine->SetInfoText(0, info);
+
+ sprintf(info, "O:dirty=%d UV:offset=%d;%d XY:mir=%d;%d S:subdiv=%d",
+ m_secondTexNum,
+ m_secondOffsetU, m_secondOffsetV,
+ m_bTextureMirrorX, m_bTextureMirrorY,
+ m_secondSubdiv);
+ m_engine->SetInfoText(1, info);
+ }
+
+ if ( m_mode == 3 )
+ {
+ sprintf(info, "[3] LOD Min/max=%d..%d Sel=%d..%d (T=%d)",
+ (int)m_min, (int)m_max,
+ m_triangleSel1, m_triangleSel2,
+ m_triangleSel2-m_triangleSel1+1);
+ m_engine->SetInfoText(0, info);
+
+ sprintf(info, "[Change]");
+ m_engine->SetInfoText(1, info);
+ }
+}
+
+
+
+static int tablePartT[] = // lemt.tga
+{
+ 192, 0, 256, 32, // profil chenille
+ 0, 64, 128, 128, // roues pour chenille
+ 0, 0, 128, 64, // profil
+ 90, 0, 128, 28, // pivot trainer
+ 128, 0, 192, 44, // coffre avant
+ 128, 44, 192, 58, // callandre
+ 128, 58, 192, 87, // coffre arrière
+ 128, 87, 192, 128, // callandre arrière
+ 128, 128, 192, 144, // sous-callandre arrière
+ 0, 128, 32, 152, // garde boue arrière
+ 0, 152, 32, 182, // garde boue milieu
+ 0, 182, 32, 256, // garde boue avant
+ 32, 128, 112, 176, // aile
+ 224, 48, 232, 64, // tuyère
+ 192, 32, 224, 64, // feu sous réacteur
+ 224, 32, 256, 48, // pied
+ 192, 64, 256, 128, // capteur
+ 192, 128, 224, 176, // support pile
+ 192, 216, 248, 248, // côté canon
+ 220, 216, 222, 245, // côté canon
+ 64, 176, 128, 224, // dessus canon
+ 128, 152, 192, 160, // extérieur canon
+ 128, 144, 192, 152, // intérieur canon
+ 192, 176, 224, 192, // petit canon
+ 128, 236, 192, 256, // canon organique
+ 214, 192, 224, 216, // réticule de visée
+ 224, 128, 248, 152, // articulation
+ 128, 192, 192, 214, // piston côté
+ 128, 214, 192, 236, // piston face
+ 192, 192, 214, 214, // piston tranche
+ 128, 192, 161, 214, // piston petit côté
+ 32, 176, 64, 198, // piston pour radar
+ 128, 160, 160, 192, // roue
+ 232, 48, 255, 56, // profil pneu
+ 240, 152, 248, 216, // hachures verticales
+ 248, 192, 256, 256, // batterie
+ 224, 152, 240, 168, // roche
+ 144, 80, 176, 112, // nucléaire
+ 140, 76, 180, 116, // nucléaire grand
+ 144, 80, 152, 88, // jaune nucléaire
+ 224, 168, 240, 192, // capot résolution C
+ 224, 192, 240, 210, // arrière résolution C
+ 32, 224, 96, 235, // bras résolution C
+ 32, 235, 96, 246, // bras résolution C
+ 161, 1, 164, 4, // blanc
+ 168, 1, 171, 4, // gris moyen
+ 154, 1, 157, 4, // gris foncé uni
+ 147, 1, 150, 4, // bleu uni
+ 114, 130, 118, 134, // rouge uni
+ 121, 130, 125, 134, // vert uni
+ 114, 137, 118, 141, // jaune uni
+ 121, 137, 125, 141, // violet uni
+ -1
+};
+
+static int tablePartR[] = // roller.tga
+{
+ 0, 0, 128, 52, // roues pour chenille
+ 48, 137, 128, 201, // côté radiateur
+ 0, 52, 32, 84, // avant radiateur
+ 32, 52, 43, 84, // arrière radiateur
+ 0, 84, 96, 137, // grand côté
+ 128, 0, 192, 85, // avant
+ 128, 173, 192, 256, // arrière
+ 192, 0, 256, 42, // dessus
+ 128, 85, 192, 109, // côté pillon
+ 128, 109, 192, 173, // dessus pillon
+ 192, 85, 240, 109, // côté porte pillon
+ 0, 137, 24, 256, // côté verrin
+ 24, 137, 48, 256, // côté verrin
+ 48, 201, 128, 233, // support canon
+ 192, 109, 256, 173, // fond canon
+ 192, 173, 240, 205, // canon 1
+ 192, 173, 240, 177, // canon 2
+ 43, 52, 75, 84, // avant canon
+ 48, 233, 128, 247, // piston
+ 96, 105, 128, 137, // avant phazer
+ 96, 97, 128, 105, // canon phazer
+ 75, 52, 107, 84, // échappement
+ 192, 205, 243, 256, // instruction centrale nucléaire
+ 192, 42, 256, 85, // reflet vitres
+ -1
+};
+
+static int tablePartW[] = // subm.tga
+{
+ 0, 0, 128, 26, // chenilles
+ 0, 26, 22, 114, // portique 1
+ 0, 114, 22, 202, // portique 2
+ 22, 26, 82, 56, // côté hublot
+ 22, 56, 82, 86, // côté ligne rouge
+ 22, 86, 82, 116, // côté simple
+ 22, 116, 82, 146, // avant/arrière
+ 22, 146, 82, 176, // avant/arrière + phare
+ 132, 82, 196, 166, // capot trainer
+ 132, 166, 196, 177, // capot trainer
+ 132, 177, 196, 188, // capot trainer
+ 0, 224, 96, 256, // côté trainer
+ 30, 224, 48, 256, // arrière trainer
+ 136, 240, 216, 256, // barrière courte
+ 96, 240, 256, 256, // barrière longue
+ 128, 0, 160, 32, // black-box 1
+ 160, 0, 192, 32, // black-box 2
+ 192, 0, 224, 32, // black-box 3
+ 224, 105, 256, 137, // TNT 1
+ 224, 137, 256, 169, // TNT 2
+ 82, 32, 146, 82, // factory résolution C
+ 146, 32, 210, 82, // factory résolution C
+ 224, 0, 256, 105, // tower résolution C
+ 82, 82, 132, 150, // research résolution C
+ 199, 169, 256, 233, // sac résolution C
+ 106, 150, 130, 214, // clé A
+ 82, 150, 106, 214, // clé B
+ 132, 188, 196, 212, // clé C
+ 132, 212, 196, 236, // clé D
+ 210, 32, 224, 46, // gris
+ 56, 176, 82, 224, // sol coffre-fort
+ -1
+};
+
+static int tablePartDr[] = // drawer.tga
+{
+ 128, 0, 134, 6, // bleu
+ 128, 6, 134, 12, // gris foncé
+ 128, 12, 134, 18, // gris clair
+ 0, 0, 128, 32, // roues chenille
+ 192, 0, 256, 32, // profil chenille
+ 140, 0, 160, 8, // profil phare
+ 160, 0, 192, 32, // face phare
+ 0, 32, 160, 48, // hachure
+ 160, 32, 192, 48, // côté
+ 0, 48, 96, 96, // tableau de bord
+ 96, 48, 192, 112, // radiateur
+ 192, 32, 256, 112, // grille latérale
+ 192, 112, 256, 128, // capot
+ 0, 96, 8, 160, // chassis
+ 8, 96, 96, 104, // axe chenilles
+ 8, 104, 16, 160, // axe carrousel
+ 16, 128, 24, 160, // flan support
+ 224, 128, 256, 160, // rotule
+ 24, 104, 32, 160, // bocal (18)
+ 32, 104, 40, 160, // bocal
+ 40, 104, 48, 160, // bocal
+ 24, 152, 48, 160, // bocal fond
+ 0, 240, 32, 256, // crayon 1: couleur (22)
+ 0, 160, 32, 192, // crayon 1: dessus
+ 0, 192, 32, 256, // crayon 1: pointe
+ 32, 240, 64, 256, // crayon 2: couleur
+ 32, 160, 64, 192, // crayon 2: dessus
+ 32, 192, 64, 256, // crayon 2: pointe
+ 64, 240, 96, 256, // crayon 3: couleur
+ 64, 160, 96, 192, // crayon 3: dessus
+ 64, 192, 96, 256, // crayon 3: pointe
+ 96, 240, 128, 256, // crayon 4: couleur
+ 96, 160, 128, 192, // crayon 4: dessus
+ 96, 192, 128, 256, // crayon 4: pointe
+ 128, 240, 160, 256, // crayon 5: couleur
+ 128, 160, 160, 192, // crayon 5: dessus
+ 128, 192, 160, 256, // crayon 5: pointe
+ 160, 240, 192, 256, // crayon 6: couleur
+ 160, 160, 192, 192, // crayon 6: dessus
+ 160, 192, 192, 256, // crayon 6: pointe
+ 192, 240, 224, 256, // crayon 7: couleur
+ 192, 160, 224, 192, // crayon 7: dessus
+ 192, 192, 224, 256, // crayon 7: pointe
+ 224, 240, 256, 256, // crayon 8: couleur
+ 224, 160, 256, 192, // crayon 8: dessus
+ 224, 192, 256, 256, // crayon 8: pointe
+ -1
+};
+
+static int tablePartKi[] = // kid.tga
+{
+ 0, 0, 128, 53, // ciseaux
+ 128, 0, 256, 128, // CD
+ 0, 0, 8, 8, // livre 1: fond
+ 8, 0, 16, 8, // livre 2: fond
+ 16, 0, 24, 8, // livre: fond
+ 24, 0, 32, 8, // livre: fond
+ 32, 0, 40, 8, // livre: fond
+ 40, 0, 48, 8, // livre: fond
+ 0, 53, 22, 138, // livre 1: tranche
+ 22, 53, 86, 138, // livre 1: face
+ 0, 138, 22, 224, // livre 2: tranche
+ 22, 138, 86, 224, // livre 2: face
+ 86, 53, 94, 85, // livre: pages
+ 94, 53, 110, 139, // livre: tranche
+ 110, 53, 126, 139, // livre: tranche
+ 86, 139, 102, 225, // livre: tranche
+ 102, 139, 118, 225, // livre: tranche
+ 118, 139, 134, 225, // livre: tranche
+ 64, 0, 72, 8, // fauille: fond
+ 155, 155, 256, 256, // feuille: carreaux
+ 72, 0, 80, 8, // lampe
+ 80, 0, 88, 8, // lampe
+ 80, 8, 88, 16, // ampoule
+ 72, 8, 80, 16, // rayons (23)
+ 86, 85, 94, 139, // lampe
+ 0, 224, 32, 256, // lampe rotule
+ 64, 8, 72, 16, // arrosoir: fond
+ 134, 128, 142, 256, // arrosoir: corps
+ 142, 128, 150, 256, // arrosoir: tuyau
+ 128, 225, 134, 256, // arrosoir: intérieur
+ 32, 224, 64, 256, // arrosoir: ponneau
+ 56, 8, 64, 16, // skate: roues (31)
+ 48, 8, 56, 16, // skate: axes
+ 40, 8, 48, 16, // skate: grip
+ 32, 8, 40, 16, // skate: tranche
+ 24, 8, 32, 16, // skate: dessous
+ 150, 128, 200, 256, // skate: motif 1
+ 200, 128, 250, 256, // skate: motif 2
+ 64, 224, 96, 256, // skate: roue (38)
+ 96, 225, 104, 256, // skate: amortisseur
+ -1
+};
+
+static int tablePartKi2[] = // kid2.tga
+{
+ 2, 2, 62, 62, // coca: dessus
+ 0, 64, 8, 192, // coca: flan
+ 8, 64, 96, 192, // coca: logo
+ 128, 0, 256, 85, // carton
+ 128, 85, 256, 91, // carton tranche
+ 128, 128, 256, 256, // roue
+ 192, 96, 256, 128, // pneu
+ 184, 96, 192, 128, // jante
+ 128, 96, 160, 128, // intérieur
+ 160, 96, 168, 104, // porte bois
+ 160, 104, 168, 112, // porte métal
+ 160, 112, 184, 128, // vitre
+ 96, 0, 128, 256, // bouteille: corps (12)
+ 64, 0, 96, 32, // bouteille: bouchon
+ 168, 96, 176, 104, // bouteille: vert
+ 0, 192, 96, 224, // bois clair
+ 0, 224, 96, 256, // bois foncé
+ 64, 32, 96, 64, // bateau
+ 168, 104, 176, 112, // ballon (18)
+ 176, 104, 184, 112, // ballon
+ 176, 96, 184, 104, // intérieur caisse
+ -1
+};
+
+static int tablePartKi3[] = // kid3.tga
+{
+ 0, 0, 32, 28, // écrou: flan
+ 0, 28, 32, 44, // écrou: profil
+ 0, 44, 32, 60, // écrou: pas de vis
+ 0, 60, 32, 64, // tuyau
+ 0, 64, 32, 68, // tuyau
+ 0, 68, 8, 76, // tuyau
+ 0, 76, 32, 108, // plastic
+ 8, 68, 16, 76, // saut: gris clair (7)
+ 16, 68, 24, 76, // saut: gris foncé
+ 24, 68, 32, 76, // saut: gris bois
+ 0, 108, 32, 140, // saut: rotule
+ 0, 140, 32, 144, // saut: axe
+ 128, 0, 256, 128, // saut: flan
+ 0, 144, 8, 152, // basket: gris foncé (13)
+ 8, 144, 16, 152, // basket: gris clair
+ 16, 144, 24, 152, // basket: gris lacets
+ 24, 144, 32, 152, // basket: gris semelle
+ 0, 152, 8, 181, // basket: intérieur
+ 0, 181, 192, 256, // basket: côté
+ 192, 181, 226, 256, // basket: arrière
+ 32, 135, 96, 181, // basket: dessus (20)
+ 96, 168, 128, 181, // basket: avant
+ 8, 152, 16, 160, // chaise: plastique
+ 16, 152, 24, 160, // chaise: métal
+ 32, 0, 64, 32, // chaise: roue
+ 8, 177, 24, 181, // chaise: roue
+ 226, 181, 234, 256, // chaise: piston (26)
+ 64, 96, 128, 128, // chaise: relief
+ 96, 135, 128, 167, // chaise: dessous
+ 32, 128, 250, 135, // paille 1
+ 38, 128, 256, 135, // paille 2
+ 234, 181, 242, 256, // allumette
+ 8, 160, 16, 168, // allumette (dessus)
+ 128, 135, 224, 181, // panneau
+ 242, 135, 256, 256, // poteau (34)
+ 24, 152, 32, 160, // clou
+ 16, 160, 24, 168, // tuyau métalique
+ 112, 181, 192, 185, // tuyau intérieur
+ 32, 32, 48, 80, // pas de vis
+ 24, 160, 32, 168, // ventillateur: plastique (39)
+ 40, 80, 56, 96, // ventillateur: plastique dégradé
+ 8, 168, 16, 176, // ventillateur: métal
+ 32, 80, 40, 112, // ventillateur: socle 1
+ 64, 0, 96, 16, // ventillateur: socle 2
+ 48, 32, 56, 80, // ventillateur: socle 3
+ 64, 16, 96, 32, // ventillateur: moteur flan
+ 96, 0, 128, 32, // ventillateur: moteur face
+ 102, 6, 122, 26, // ventillateur: socle dessus
+ 16, 168, 24, 176, // pot: uni (48)
+ 56, 32, 64, 64, // pot: haut
+ 56, 64, 64, 96, // pot: bas
+ 64, 32, 128, 96, // pot: terre
+ -1
+};
+
+static int tablePartF[] = // factory.tga
+{
+ 0, 0, 152, 152, // plancher octogonal fabrique
+ 50, 50, 102, 102, // dessus pile
+ 0, 152, 128, 252, // avant
+ 128, 152, 256, 252, // arrière
+ 152, 28, 225, 128, // côté
+ 152, 28, 176, 128, // côté partiel
+ 152, 0, 216, 16, // hachures
+ 236, 0, 256, 40, // axe
+ 152, 128, 224, 152, // support cible
+ -1
+};
+
+static int tablePartD[] = // derrick.tga
+{
+ 0, 0, 64, 32, // grand côté
+ 64, 0, 96, 24, // petit côté
+ 96, 0, 136, 24, // attention
+ 0, 32, 8, 160, // tube 1
+ 8, 32, 16, 96, // tube 2
+ 16, 32, 24, 160, // pilier
+ 24, 32, 32, 160, // tige foret
+ 32, 32, 40, 160, // tige destructeur
+ 8, 96, 16, 128, // foret
+ 136, 0, 256, 120, // plancher octogonal station de recharge
+ 40, 32, 64, 56, // cube métal
+ 64, 24, 128, 48, // côté tour haut
+ 64, 48, 128, 229, // côté tour bas
+ 136, 120, 256, 240, // intérieur usine
+ 0, 160, 64, 224, // toît usine
+ -1
+};
+
+static int tablePartC[] = // convert.tga
+{
+ 0, 0, 120, 120, // plancher octogonal convertisseur
+ 0, 120, 128, 176, // grand côté
+ 128, 120, 192, 176, // petit côté
+ 192, 120, 256, 184, // couvercle convertisseur
+ 120, 0, 216, 64, // face trianble
+ 216, 0, 248, 64, // côté triangle
+ 120, 64, 160, 84, // axe
+ 0, 141, 128, 176, // recherche: base
+ 0, 176, 128, 214, // recherche: haut
+ 0, 214, 128, 252, // recherche: haut (!)
+ 174, 64, 190, 120, // recherche: montant
+ 190, 64, 206, 120, // recherche: montant
+ 206, 64, 254, 85, // radar
+ 192, 168, 256, 232, // hachures carrées
+ 248, 0, 256, 64, // cône fabrique de piles
+ 128, 176, 192, 240, // dessus centrale nucléaire
+ 120, 85, 174, 120, // technicien, visage
+ 206, 106, 256, 120, // technicien, casquette
+ 160, 64, 174, 78, // technicien, visière
+ -1
+};
+
+static int tablePartS[] = // search.tga
+{
+ 0, 0, 128, 128, // usine 1
+ 128, 0, 256, 128, // usine 2
+ 0, 128, 128, 256, // pile
+ 128, 128, 228, 240, // support pile
+ 228, 128, 256, 184, // antenne
+ 128, 128, 192, 160, // contrôle 1
+ 128, 160, 192, 192, // contrôle 2
+ 128, 192, 192, 224, // contrôle 3
+ 128, 224, 192, 256, // contrôle 4
+ -1
+};
+
+static int tablePartP[] = // plant.tga
+{
+ 0, 160, 48, 256, // feuille 1
+ 0, 0, 94, 100, // feuille 2
+ 48, 156, 108, 256, // feuille 3
+ 94, 0, 104, 100, // tige 1
+ 185, 0, 195, 100, // tige 2
+ 108, 100, 182, 256, // fougère
+ 104, 0, 144, 100, // courge
+ 203, 0, 256, 83, // armature derrick résolution C
+ -1
+};
+
+static int tablePartV[] = // vegetal.tga
+{
+ 0, 0, 94, 100, // racine
+ 186, 0, 256, 256, // tronc
+ 162, 0, 168, 128, // mat drapeau bleu
+ 168, 0, 174, 128, // mat drapeau rouge
+ 174, 0, 180, 128, // mat drapeau vert
+ 180, 0, 186, 128, // mat drapeau jaune
+ 180, 128, 186, 256, // mat drapeau violet
+ 94, 0, 107, 32, // drapeau bleu
+ 107, 0, 120, 32, // drapeau rouge
+ 120, 0, 133, 32, // drapeau vert
+ 133, 0, 146, 32, // drapeau jaune
+ 146, 0, 159, 32, // drapeau violet
+ 94, 64, 126, 96, // verre 1
+ 126, 64, 158, 86, // verre 2
+ 128, 128, 180, 144, // verre 3a
+ 128, 144, 180, 160, // verre 3b
+ 128, 94, 162, 128, // verre 4
+ 0, 100, 32, 228, // champignon 1
+ 32, 100, 48, 228, // champignon 1
+ 48, 100, 112, 228, // champignon 2
+ 112, 100, 128, 228, // champignon 2
+ 128, 160, 180, 212, // tronc (21)
+ -1
+};
+
+static int tablePartM[] = // mother.tga
+{
+ 0, 0, 128, 128, // corps arrière
+ 128, 0, 192, 128, // corps avant
+ 0, 128, 64, 192, // tête
+ 64, 128, 192, 160, // pince ext.
+ 64, 160, 192, 192, // pince int.
+ 0, 192, 64, 256, // mire
+ -1
+};
+
+static int tablePartA[] = // ant.tga
+{
+ 0, 0, 64, 64, // queue
+ 0, 96, 128, 160, // queue abeille
+ 64, 0, 128, 64, // corps
+ 128, 0, 192, 64, // tête
+ 0, 64, 64, 72, // patte
+ 0, 72, 64, 80, // antenne
+ 64, 64, 150, 96, // queue ver
+ 150, 64, 182, 96, // corps ver
+ 182, 64, 256, 96, // tête ver
+ 224, 32, 256, 64, // articulation ver
+ 128, 96, 220, 160, // aile
+ 0, 80, 16, 96, // oeil
+ 200, 0, 208, 8, // vert clair
+ 200, 8, 208, 16, // vert foncé
+ 0, 160, 64, 224, // corps araignée
+ 64, 160, 128, 192, // tête araignée
+ 208, 0, 216, 64, // patte araignée
+ 216, 0, 224, 32, // patte araignée
+ 224, 0, 256, 8, // antenne araignée
+ 192, 0, 200, 8, // brun clair
+ 192, 8, 200, 16, // brun foncé
+ 128, 160, 256, 256, // SatCom
+ -1
+};
+
+static int tablePartH[] = // human.tga
+{
+ 0, 0, 64, 64, // vissière
+ 64, 0, 96, 64, // cuisse
+ 96, 0, 128, 64, // jambe
+ 128, 0, 192, 32, // bras
+ 128, 32, 192, 64, // avant-bras
+ 0, 64, 128, 224, // ventre
+ 128, 64, 256, 224, // dos
+ 64, 224, 112, 256, // dessus pied
+ 144, 224, 168, 240, // dessous pied
+ 112, 224, 144, 240, // côté pied
+ 112, 224, 128, 240, // côté pied
+ 0, 224, 64, 256, // gant
+ 168, 224, 200, 256, // oreille
+ 112, 240, 144, 256, // ligne casque
+ 200, 224, 208, 256, // intérieur coup
+ 240, 0, 244, 64, // bombone orange
+ 244, 0, 248, 64, // bombone orange (reflet)
+ 248, 0, 252, 64, // bombone bleu
+ 252, 0, 256, 64, // bombone bleu (reflet)
+ 144, 240, 156, 256, // gris habit
+ 156, 240, 168, 256, // gris articulation
+//? 208, 224, 256, 256, // SatCom
+ 192, 0, 240, 64, // quartz
+ -1
+};
+
+static int tablePartG[] = // apollo.tga
+{
+ 0, 0, 64, 64, // revètement LEM
+ 64, 0, 128, 64, // revètement LEM
+ 128, 8, 136, 128, // pied
+ 0, 64, 64, 128, // roue
+ 136, 24, 152, 44, // profil pneu
+ 136, 8, 160, 24, // garde boue
+ 64, 64, 128, 128, // siège
+ 64, 128, 128, 192, // siège
+ 64, 192, 128, 212, // siège
+ 128, 128, 240, 192, // moteur
+ 0, 192, 28, 256, // moteur
+ 32, 128, 60, 256, // moteur
+ 224, 0, 256, 128, // avant
+ 206, 0, 224, 128, // avant
+ 136, 44, 168, 62, // avant
+ 64, 212, 108, 256, // panneau de commande
+ 198, 0, 206, 128, // mat
+ 190, 64, 198, 128, // mat
+ 160, 8, 176, 24, // caméra
+ 176, 8, 192, 24, // moyeu
+ 136, 64, 168, 96, // module
+ 168, 64, 190, 96, // module
+ 136, 96, 168, 128, // module
+ 128, 192, 230, 252, // drapeau
+ 0, 128, 32, 192, // antenne
+ 128, 0, 136, 8, // jaune
+ 136, 0, 144, 8, // beige
+ 144, 0, 152, 8, // brun
+ 168, 0, 176, 8, // gris très clair
+ 152, 0, 160, 8, // gris clair
+ 160, 0, 168, 8, // gris foncé
+ -1
+};
+
+static int tablePartB[] = // base1.tga
+{
+ 0, 0, 80, 256, // intérieur porte
+ 80, 0, 88, 256, // tranche porte
+ 116, 0, 180, 64, // coiffe 1
+ 116, 64, 180, 102, // coiffe 2
+ 180, 0, 244, 37, // base
+ 180, 37, 196, 101, // support
+ 88, 0, 116, 256, // colonne
+ 212, 37, 256, 128, // supplément
+ 128, 128, 256, 256, // 1/4 du sol
+ 196, 37, 212, 53, // gris foncé
+ 196, 53, 212, 69, // gris clair
+ -1
+};
+
+static int tablePartCe[] = // cellar01.tga
+{
+ 0, 128, 64, 192, // briques
+ 64, 128, 128, 192, // briques
+ 128, 128, 192, 192, // briques
+ 192, 128, 256, 192, // briques
+ -1
+};
+
+static int tablePartFa[] = // face01.tga
+{
+ 0, 0, 256, 256, // visage
+ -1
+};
+
+// Retourne le pointeur la table.
+
+int* CModel::RetTextureTable()
+{
+ if ( m_textureRank == 0 ) return tablePartT;
+ if ( m_textureRank == 1 ) return tablePartR;
+ if ( m_textureRank == 2 ) return tablePartW;
+ if ( m_textureRank == 3 ) return tablePartDr;
+ if ( m_textureRank == 4 ) return tablePartKi;
+ if ( m_textureRank == 5 ) return tablePartKi2;
+ if ( m_textureRank == 6 ) return tablePartKi3;
+ if ( m_textureRank == 7 ) return tablePartF;
+ if ( m_textureRank == 8 ) return tablePartD;
+ if ( m_textureRank == 9 ) return tablePartC;
+ if ( m_textureRank == 10 ) return tablePartS;
+ if ( m_textureRank == 11 ) return tablePartP;
+ if ( m_textureRank == 12 ) return tablePartV;
+ if ( m_textureRank == 13 ) return tablePartM;
+ if ( m_textureRank == 14 ) return tablePartA;
+ if ( m_textureRank == 15 ) return tablePartH;
+ if ( m_textureRank == 16 ) return tablePartG;
+ if ( m_textureRank == 17 ) return tablePartB;
+ if ( m_textureRank == 18 ) return tablePartCe;
+ if ( m_textureRank == 19 ) return tablePartFa;
+ if ( m_textureRank == 20 ) return tablePartFa;
+ if ( m_textureRank == 21 ) return tablePartFa;
+ if ( m_textureRank == 22 ) return tablePartFa;
+ return 0;
+}
+
+// Met à jour la partie de texture.
+
+void CModel::TexturePartUpdate()
+{
+ int *table;
+
+ table = RetTextureTable();
+ if ( table == 0 ) return;
+
+ m_textureInf.x = (table[m_texturePart*4+0]+0.5f)/256.0f;
+ m_textureInf.y = (table[m_texturePart*4+1]+0.5f)/256.0f;
+ m_textureSup.x = (table[m_texturePart*4+2]-0.5f)/256.0f;
+ m_textureSup.y = (table[m_texturePart*4+3]-0.5f)/256.0f;
+
+ PutTextureValues();
+}
+
+// Change la texture.
+
+void CModel::TextureRankChange(int step)
+{
+ m_textureRank += step;
+
+ if ( m_textureRank >= MAX_NAMES ) m_textureRank = 0;
+ if ( m_textureRank < 0 ) m_textureRank = MAX_NAMES-1;
+
+ if ( m_textureRank == 0 ) strcpy(m_textureName, "lemt.tga");
+ if ( m_textureRank == 1 ) strcpy(m_textureName, "roller.tga");
+ if ( m_textureRank == 2 ) strcpy(m_textureName, "subm.tga");
+ if ( m_textureRank == 3 ) strcpy(m_textureName, "drawer.tga");
+ if ( m_textureRank == 4 ) strcpy(m_textureName, "kid.tga");
+ if ( m_textureRank == 5 ) strcpy(m_textureName, "kid2.tga");
+ if ( m_textureRank == 6 ) strcpy(m_textureName, "kid3.tga");
+ if ( m_textureRank == 7 ) strcpy(m_textureName, "factory.tga");
+ if ( m_textureRank == 8 ) strcpy(m_textureName, "derrick.tga");
+ if ( m_textureRank == 9 ) strcpy(m_textureName, "convert.tga");
+ if ( m_textureRank == 10 ) strcpy(m_textureName, "search.tga");
+ if ( m_textureRank == 11 ) strcpy(m_textureName, "plant.tga");
+ if ( m_textureRank == 12 ) strcpy(m_textureName, "vegetal.tga");
+ if ( m_textureRank == 13 ) strcpy(m_textureName, "mother.tga");
+ if ( m_textureRank == 14 ) strcpy(m_textureName, "ant.tga");
+ if ( m_textureRank == 15 ) strcpy(m_textureName, "human.tga");
+ if ( m_textureRank == 16 ) strcpy(m_textureName, "apollo.tga");
+ if ( m_textureRank == 17 ) strcpy(m_textureName, "base1.tga");
+ if ( m_textureRank == 18 ) strcpy(m_textureName, "cellar01.tga");
+ if ( m_textureRank == 19 ) strcpy(m_textureName, "face01.tga");
+ if ( m_textureRank == 20 ) strcpy(m_textureName, "face02.tga");
+ if ( m_textureRank == 21 ) strcpy(m_textureName, "face03.tga");
+ if ( m_textureRank == 22 ) strcpy(m_textureName, "face04.tga");
+
+ m_texturePart = 0;
+}
+
+// Change la partie de texture.
+
+void CModel::TexturePartChange(int step)
+{
+ int *table;
+
+ table = RetTextureTable();
+ if ( table == 0 ) return;
+
+ m_texturePart ++;
+
+ if ( table[m_texturePart*4] == -1 )
+ {
+ m_texturePart = 0;
+ }
+
+ TexturePartUpdate();
+}
+
+
diff --git a/src/model.h b/src/model.h
new file mode 100644
index 0000000..2f686ee
--- /dev/null
+++ b/src/model.h
@@ -0,0 +1,118 @@
+// model.h
+
+#ifndef _MODEL_H_
+#define _MODEL_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CModFile;
+class CInterface;
+
+
+
+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, D3DVERTEX2 &vertex);
+ BOOL SetVertex(int rank, D3DVERTEX2 &vertex);
+ D3DVECTOR RetSelectCDG();
+ D3DVECTOR RetSelectNormal();
+ void SmoothSelect();
+ void PlaneSelect();
+ void ColorSelect();
+ void StateSelect();
+ void MoveSelect(D3DVECTOR move);
+ void OperSelect(D3DVECTOR move, char oper);
+ void ReadScript(char *filename);
+ void BBoxCompute(D3DVECTOR &min, D3DVECTOR &max);
+ BOOL IsMappingSelectPlausible(D3DMaping D3Dmode);
+ void MappingSelect(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT ts, char *texName);
+ void MappingSelectSpherical(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT ts, char *texName);
+ D3DVECTOR RetMappingCenter(D3DVECTOR pos, D3DVECTOR min);
+ void MappingSelectCylindrical(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT ts, char *texName);
+ void MappingSelectFace(int mode, int rotate, BOOL bMirrorX, BOOL bMirrorY, FPOINT ti, FPOINT 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;
+ CD3DEngine* 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;
+ FPOINT m_textureInf;
+ FPOINT 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;
+};
+
+
+#endif //_MODEL_H_
diff --git a/src/modfile.cpp b/src/modfile.cpp
new file mode 100644
index 0000000..f54f3c9
--- /dev/null
+++ b/src/modfile.cpp
@@ -0,0 +1,681 @@
+// modfile.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "modfile.h"
+
+
+
+#define MAX_VERTICES 2000
+
+
+
+// Constructeur de l'objet.
+
+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);
+}
+
+// Destructeur de l'objet.
+
+CModFile::~CModFile()
+{
+ free(m_triangleTable);
+}
+
+
+
+
+// Crée un triangle dans la structure interne.
+
+BOOL CModFile::CreateTriangle(D3DVECTOR p1, D3DVECTOR p2, D3DVECTOR p3,
+ float min, float max)
+{
+ D3DVECTOR 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 = ComputeNormal(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; // blanc
+ 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;
+}
+
+// Lit un fichier DXF.
+
+BOOL CModFile::ReadDXF(char *filename, float min, float max)
+{
+ FILE* file = NULL;
+ char line[100];
+ int command, rankSommet, nbSommet, nbFace;
+ D3DVECTOR 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 )
+ {
+ D3DVECTOR p(x,z,y); // permutation de Y et 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;
+}
+
+
+
+typedef struct
+{
+ int rev;
+ int vers;
+ int total;
+ int reserve[10];
+}
+InfoMOD;
+
+
+// Change un nom.bmp en nom.tga
+
+void ChangeBMPtoTGA(char *filename)
+{
+ char* p;
+
+ p = strstr(filename, ".bmp");
+ if ( p != 0 ) strcpy(p, ".tga");
+}
+
+
+// Lit un fichier MOD.
+
+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); // frontière AB selon config
+ limit[1] = m_engine->RetLimitLOD(1); // frontière BC selon config
+
+ // Frontières standard -> config.
+ for ( i=first ; i<m_triangleUsed ; i++ )
+ {
+ if ( m_triangleTable[i].min == 0.0f &&
+ m_triangleTable[i].max == 100.0f ) // résolution A ?
+ {
+ m_triangleTable[i].max = limit[0];
+ }
+ else if ( m_triangleTable[i].min == 100.0f &&
+ m_triangleTable[i].max == 200.0f ) // résolution 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 ) // résolution C ?
+ {
+ m_triangleTable[i].min = limit[1];
+ }
+ }
+ }
+
+ if ( bMeta )
+ {
+ g_metafile.Close();
+ }
+ else
+ {
+ fclose(file);
+ }
+ return TRUE;
+}
+
+// Lit un fichier MOD.
+
+BOOL CModFile::ReadModel(char *filename, BOOL bEdit, BOOL bMeta)
+{
+ m_triangleUsed = 0;
+ return AddModel(filename, 0, bEdit, bMeta);
+}
+
+
+// Ecrit un fichier MOD.
+
+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;
+}
+
+
+// Crée l'objet dans le moteur 3D.
+
+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
+}
+
+
+// Effectue un miroir selon 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;
+ }
+}
+
+
+// Retourne le pointeur à la liste de 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;
+}
+
+
+// Retourne la hauteur en fonction d'une position (x;-;z);
+
+float CModFile::RetHeight(D3DVECTOR pos)
+{
+ D3DVECTOR p1, p2, p3;
+ float limit;
+ int i;
+
+ limit = 5.0f;
+
+ for ( i=0 ; i<m_triangleUsed ; i++ )
+ {
+ if ( !m_triangleTable[i].bUsed ) continue;
+
+ if ( Abs(pos.x-m_triangleTable[i].p1.x) < limit &&
+ Abs(pos.z-m_triangleTable[i].p1.z) < limit )
+ {
+ return m_triangleTable[i].p1.y;
+ }
+
+ if ( Abs(pos.x-m_triangleTable[i].p2.x) < limit &&
+ Abs(pos.z-m_triangleTable[i].p2.z) < limit )
+ {
+ return m_triangleTable[i].p2.y;
+ }
+
+ if ( Abs(pos.x-m_triangleTable[i].p3.x) < limit &&
+ Abs(pos.z-m_triangleTable[i].p3.z) < limit )
+ {
+ return m_triangleTable[i].p3.y;
+ }
+ }
+
+ return 0.0f;
+}
+
+
diff --git a/src/modfile.h b/src/modfile.h
new file mode 100644
index 0000000..2db74a3
--- /dev/null
+++ b/src/modfile.h
@@ -0,0 +1,101 @@
+// modfile.h
+
+#ifndef _MODFILE_H_
+#define _MODFILE_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+
+
+
+
+typedef struct
+{
+ char bUsed; // TRUE -> utilisé
+ char bSelect; // TRUE -> sélectionné
+ D3DVERTEX p1;
+ D3DVERTEX p2;
+ D3DVERTEX p3;
+ D3DMATERIAL7 material;
+ char texName[20];
+ float min;
+ float max;
+}
+OldModelTriangle1; // longueur = 196 bytes
+
+typedef struct
+{
+ char bUsed; // TRUE -> utilisé
+ char bSelect; // TRUE -> sélectionné
+ 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;
+}
+OldModelTriangle2;
+
+typedef struct
+{
+ char bUsed; // TRUE -> utilisé
+ char bSelect; // TRUE -> sélectionné
+ 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;
+}
+ModelTriangle; // longueur = 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(D3DVECTOR pos);
+
+protected:
+ BOOL CreateTriangle(D3DVECTOR p1, D3DVECTOR p2, D3DVECTOR p3, float min, float max);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+
+ ModelTriangle* m_triangleTable;
+ int m_triangleUsed;
+};
+
+
+#endif //_MODFILE_H_
diff --git a/src/motion.cpp b/src/motion.cpp
new file mode 100644
index 0000000..5553f69
--- /dev/null
+++ b/src/motion.cpp
@@ -0,0 +1,241 @@
+// motion.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "cmdtoken.h"
+#include "motion.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CMotion::CMotion(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_MOTION, this, 100);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_object = object;
+ m_physics = 0;
+ m_brain = 0;
+
+ m_actionType = -1;
+ m_actionTime = 0.0f;
+ m_progress = 0.0f;
+
+ m_linVibration = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_cirVibration = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_inclinaison = D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+// Destructeur de l'objet.
+
+CMotion::~CMotion()
+{
+ m_iMan->DeleteInstance(CLASS_MOTION, this);
+}
+
+// Supprime l'objet.
+
+void CMotion::DeleteObject(BOOL bAll)
+{
+}
+
+
+void CMotion::SetPhysics(CPhysics* physics)
+{
+ m_physics = physics;
+}
+
+void CMotion::SetBrain(CBrain* brain)
+{
+ m_brain = brain;
+}
+
+
+// Crée.
+
+BOOL CMotion::Create(D3DVECTOR pos, float angle, ObjectType type, float power)
+{
+ return TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CMotion::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, dir;
+ float time;
+
+ if ( m_object->RetType() != OBJECT_TOTO &&
+ m_engine->RetPause() ) return TRUE;
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_actionTime;
+ if ( m_progress > 1.0f ) m_progress = 1.0f; // (*)
+
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel(m_object) ) // sous l'eau ?
+ {
+ time = event.rTime*3.0f; // tout est plus lent
+ }
+ else
+ {
+ time = event.rTime*10.0f;
+ }
+
+ dir = m_object->RetLinVibration();
+ dir.x = Smooth(dir.x, m_linVibration.x, time);
+ dir.y = Smooth(dir.y, m_linVibration.y, time);
+ dir.z = Smooth(dir.z, m_linVibration.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir = m_object->RetCirVibration();
+ dir.x = Smooth(dir.x, m_cirVibration.x, time);
+ dir.y = Smooth(dir.y, m_cirVibration.y, time);
+ dir.z = Smooth(dir.z, m_cirVibration.z, time);
+ m_object->SetCirVibration(dir);
+
+ dir = m_object->RetInclinaison();
+ dir.x = Smooth(dir.x, m_inclinaison.x, time);
+ dir.y = Smooth(dir.y, m_inclinaison.y, time);
+ dir.z = Smooth(dir.z, m_inclinaison.z, time);
+ m_object->SetInclinaison(dir);
+
+ return TRUE;
+}
+
+// (*) Evite le bug des fourmis retournées par le thumper et dont
+// l'abdomen grossi à l'infini !
+
+
+// Démarre une action.
+
+Error CMotion::SetAction(int action, float time)
+{
+ m_actionType = action;
+ m_actionTime = 1.0f/time;
+ m_progress = 0.0f;
+ return ERR_OK;
+}
+
+// Retourne l'action en cours.
+
+int CMotion::RetAction()
+{
+ return m_actionType;
+}
+
+
+// Spécifie un paramètre spécial.
+
+BOOL CMotion::SetParam(int rank, float value)
+{
+ return FALSE;
+}
+
+float CMotion::RetParam(int rank)
+{
+ return 0.0f;
+}
+
+
+// Sauve tous les paramètres de l'objet.
+
+BOOL CMotion::Write(char *line)
+{
+ char name[100];
+
+ if ( m_actionType == -1 ) return FALSE;
+
+ sprintf(name, " mType=%d", m_actionType);
+ strcat(line, name);
+
+ sprintf(name, " mTime=%.2f", m_actionTime);
+ strcat(line, name);
+
+ sprintf(name, " mProgress=%.2f", m_progress);
+ strcat(line, name);
+
+ return FALSE;
+}
+
+// Restitue tous les paramètres de l'objet.
+
+BOOL CMotion::Read(char *line)
+{
+ m_actionType = OpInt(line, "mType", -1);
+ m_actionTime = OpFloat(line, "mTime", 0.0f);
+ m_progress = OpFloat(line, "mProgress", 0.0f);
+
+ return FALSE;
+}
+
+
+// Donne la vibration linéaire.
+
+void CMotion::SetLinVibration(D3DVECTOR dir)
+{
+ m_linVibration = dir;
+}
+
+D3DVECTOR CMotion::RetLinVibration()
+{
+ return m_linVibration;
+}
+
+// Donne la vibration circulaire.
+
+void CMotion::SetCirVibration(D3DVECTOR dir)
+{
+ m_cirVibration = dir;
+}
+
+D3DVECTOR CMotion::RetCirVibration()
+{
+ return m_cirVibration;
+}
+
+// Donne l'inclinaison.
+
+void CMotion::SetInclinaison(D3DVECTOR dir)
+{
+ m_inclinaison = dir;
+}
+
+D3DVECTOR CMotion::RetInclinaison()
+{
+ return m_inclinaison;
+}
+
diff --git a/src/motion.h b/src/motion.h
new file mode 100644
index 0000000..dcbd595
--- /dev/null
+++ b/src/motion.h
@@ -0,0 +1,75 @@
+// motion.h
+
+#ifndef _MOTION_H_
+#define _MOTION_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CWater;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+class CRobotMain;
+class CSound;
+
+
+class CMotion
+{
+public:
+ CMotion(CInstanceManager* iMan, CObject* object);
+ virtual ~CMotion();
+
+ void SetPhysics(CPhysics* physics);
+ void SetBrain(CBrain* brain);
+
+ virtual void DeleteObject(BOOL bAll=FALSE);
+ virtual BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ virtual BOOL EventProcess(const Event &event);
+ virtual Error SetAction(int action, float time=0.2f);
+ virtual int RetAction();
+
+ virtual BOOL SetParam(int rank, float value);
+ virtual float RetParam(int rank);
+
+ virtual BOOL Write(char *line);
+ virtual BOOL Read(char *line);
+
+ virtual void SetLinVibration(D3DVECTOR dir);
+ virtual D3DVECTOR RetLinVibration();
+ virtual void SetCirVibration(D3DVECTOR dir);
+ virtual D3DVECTOR RetCirVibration();
+ virtual void SetInclinaison(D3DVECTOR dir);
+ virtual D3DVECTOR RetInclinaison();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CLight* m_light;
+ CParticule* m_particule;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCamera* m_camera;
+ CObject* m_object;
+ CBrain* m_brain;
+ CPhysics* m_physics;
+ CRobotMain* m_main;
+ CSound* m_sound;
+
+ int m_actionType;
+ float m_actionTime;
+ float m_progress;
+
+ D3DVECTOR m_linVibration; // vibration linéaire
+ D3DVECTOR m_cirVibration; // vibration circulaire
+ D3DVECTOR m_inclinaison; // inclinaison
+};
+
+
+#endif //_MOTION_H_
diff --git a/src/motionant.cpp b/src/motionant.cpp
new file mode 100644
index 0000000..4fd76f6
--- /dev/null
+++ b/src/motionant.cpp
@@ -0,0 +1,886 @@
+// motionant.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionant.h"
+
+
+
+#define ADJUST_ANGLE FALSE // TRUE -> ajuste les angles des membres
+#define START_TIME 1000.0f // début du temps relatif
+
+
+
+// Constructeur de l'objet.
+
+CMotionAnt::CMotionAnt(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_armMember = START_TIME;
+ m_armTimeAbs = START_TIME;
+ m_armTimeMarch = START_TIME;
+ m_armTimeAction = START_TIME;
+ m_armTimeIndex = 0;
+ m_armPartIndex = 0;
+ m_armMemberIndex = 0;
+ m_armLastAction = -1;
+ m_bArmStop = FALSE;
+ m_lastParticule = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CMotionAnt::~CMotionAnt()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionAnt::DeleteObject(BOOL bAll)
+{
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionAnt::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 3+18 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+
+ pModFile->ReadModel("objects\\ant1.mod");
+ pModFile->CreateEngineObject(rank);
+
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, -2.0f, 0.0f), 4.0f, SOUND_BOUM, 0.20f);
+ m_object->SetGlobalSphere(D3DVECTOR(-0.5f, 1.0f, 0.0f), 4.0f);
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\ant2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(2.0f, 0.0f, 0.0f));
+
+ // Crée la queue.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\ant3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(-1.0f, 0.0f, 0.0f));
+
+ // Crée la cuisse 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(-0.4f, -0.1f, -0.3f));
+
+ // Crée la jambe 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 3);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 4);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.1f, -0.1f, -0.4f));
+
+ // Crée la jambe 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 6);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 7);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(1.4f, -0.1f, -0.6f));
+
+ // Crée la jambe 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(10, rank);
+ m_object->SetObjectParent(10, 9);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(10, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(11, rank);
+ m_object->SetObjectParent(11, 10);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(11, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(12, rank);
+ m_object->SetObjectParent(12, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(12, D3DVECTOR(-0.4f, -0.1f, 0.3f));
+
+ // Crée la jambe 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(13, rank);
+ m_object->SetObjectParent(13, 12);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(13, D3DVECTOR(0.0f, 0.0f, 1.0f));
+
+ // Crée le pied 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(14, rank);
+ m_object->SetObjectParent(14, 13);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(14, D3DVECTOR(0.0f, 0.0f, 2.0f));
+
+ // Crée la cuisse 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(15, rank);
+ m_object->SetObjectParent(15, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(15, D3DVECTOR(0.1f, -0.1f, 0.4f));
+
+ // Crée la jambe 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(16, rank);
+ m_object->SetObjectParent(16, 15);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(16, D3DVECTOR(0.0f, 0.0f, 1.0f));
+
+ // Crée le pied 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(17, rank);
+ m_object->SetObjectParent(17, 16);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(17, D3DVECTOR(0.0f, 0.0f, 2.0f));
+
+ // Crée la cuisse 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(18, rank);
+ m_object->SetObjectParent(18, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(18, D3DVECTOR(1.4f, -0.1f, 0.6f));
+
+ // Crée la jambe 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(19, rank);
+ m_object->SetObjectParent(19, 18);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(19, D3DVECTOR(0.0f, 0.0f, 1.0f));
+
+ // Crée le pied 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(20, rank);
+ m_object->SetObjectParent(20, 19);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(20, D3DVECTOR(0.0f, 0.0f, 2.0f));
+
+ m_object->CreateShadowCircle(4.0f, 0.5f);
+
+ CreatePhysics();
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionAnt::CreatePhysics()
+{
+ Character* character;
+ int i;
+
+ int member_march[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 0,45,0, 0,45,0, 0,50,0, // t0: cuisses 1..3
+ 30,-70,0, 20,-105,20, 25,-100,0, // t0: jambes 1..3
+ -70,75,0, -30,80,0, -80,80,0, // t0: pieds 1..3
+ // au sol devant :
+ 0,30,0, 0,20,0, 0,15,0, // t1: cuisses 1..3
+ -15,-50,0, -20,-60,0, -10,-75,0, // t1: jambes 1..3
+ -40,50,0, -25,15,0, -50,35,0, // t1: pieds 1..3
+ // au sol derrière :
+ 0,35,0, 0,30,0, 0,20,0, // t2: cuisses 1..3
+ -20,-15,0, -30,-55,0, -25,-70,15, // t2: jambes 1..3
+ -25,25,0, -20,60,0, -30,95,0, // t2: pieds 1..3
+ };
+
+ int member_stop[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 0,30,0, 0,20,0, 0,15,0, // t0: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // t0: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // t0: pieds 1..3
+ // au sol devant :
+ 0,30,0, 0,20,0, 0,15,0, // t1: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // t1: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // t1: pieds 1..3
+ // au sol derrière :
+ 0,30,0, 0,20,0, 0,15,0, // t2: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // t2: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // t2: pieds 1..3
+ };
+
+ int member_spec[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // prépare le tir :
+ 0,20,0, 0,10,0, 0,50,0, // s0: cuisses 1..3
+ -50,-30,0, -20,-15,0, 35,-65,0, // s0: jambes 1..3
+ -5,-40,0, 20,-70,0, -10,-40,0, // s0: pieds 1..3
+ // tir :
+ 0,20,0, 0,10,0, 0,50,0, // s1: cuisses 1..3
+ -50,-30,0, -20,-15,0, 35,-65,0, // s1: jambes 1..3
+ -5,-40,0, 20,-70,0, -10,-40,0, // s1: pieds 1..3
+ // termine le tir :
+ 0,30,0, 0,20,0, 0,15,0, // s2: cuisses 1..3
+ -15,-50,0, -20,-60,0, -10,-75,0, // s2: jambes 1..3
+ -40,50,0, -25,15,0, -50,35,0, // s2: pieds 1..3
+ // brûle :
+ 0,30,0, 0,20,0, 0,15,0, // s3: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // s3: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // s3: pieds 1..3
+ // ruine :
+ 0,30,0, 0,20,0, 0,15,0, // s4: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // s4: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // s4: pieds 1..3
+ // back1 :
+ 0,30,0, 0,20,0, 0,15,0, // s5: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // s5: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // s5: pieds 1..3
+ // back2 :
+ 0,45,0, 0,45,0, 0,50,0, // s6: cuisses 1..3
+ -35,-70,0, -20,-85,-25,-25,-100,0, // s6: jambes 1..3
+ -110,75,-15,-130,80,-25,-125,40,0, // s6: pieds 1..3
+ // back3 :
+ 0,30,0, 0,20,0, 0,15,0, // s7: cuisses 1..3
+ -15,-35,0, -20,-60,0, -15,-75,0, // s7: jambes 1..3
+ -35,35,0, -25,40,0, -40,65,0, // s7: pieds 1..3
+ };
+
+ m_physics->SetType(TYPE_ROLLING);
+
+ character = m_object->RetCharacter();
+ character->wheelFront = 3.0f;
+ character->wheelBack = 3.0f;
+ character->wheelLeft = 5.0f;
+ character->wheelRight = 5.0f;
+ character->height = 1.2f;
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 12.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 12.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 15.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 15.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 5.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 10.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 1.0f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 1.0f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 20.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 40.0f);
+
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MA_MARCH+i] = member_march[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MA_STOP+i] = member_stop[i];
+ }
+ for ( i=0 ; i<3*3*3*8 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MA_SPEC+i] = member_spec[i];
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionAnt::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if ADJUST_ANGLE
+ int i;
+
+ if ( event.param == 'A' ) m_armTimeIndex++;
+ if ( m_armTimeIndex >= 3 ) m_armTimeIndex = 0;
+
+ if ( event.param == 'Q' ) m_armPartIndex++;
+ if ( m_armPartIndex >= 3 ) m_armPartIndex = 0;
+
+ if ( event.param == 'W' ) m_armMemberIndex++;
+ if ( m_armMemberIndex >= 3 ) m_armMemberIndex = 0;
+
+ i = m_armMemberIndex*3;
+ i += m_armPartIndex*3*3;
+ i += m_armTimeIndex*3*3*3;
+//? i += 3*3*3*3;
+
+ if ( event.param == 'E' ) m_armAngles[i+0] += 5;
+ if ( event.param == 'D' ) m_armAngles[i+0] -= 5;
+ if ( event.param == 'R' ) m_armAngles[i+1] += 5;
+ if ( event.param == 'F' ) m_armAngles[i+1] -= 5;
+ if ( event.param == 'T' ) m_armAngles[i+2] += 5;
+ if ( event.param == 'G' ) m_armAngles[i+2] -= 5;
+
+ if ( event.param == 'Y' ) m_bArmStop = !m_bArmStop;
+#endif
+ }
+
+ return TRUE;
+}
+
+// Calcule une valeur (radians) proportionnelle comprise
+// entre a et b (degrés).
+
+inline float Propf(float a, float b, float p)
+{
+ float aa, bb;
+
+ aa = a*PI/180.0f;
+ bb = b*PI/180.0f;
+
+ return aa+p*(bb-aa);
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionAnt::EventFrame(const Event &event)
+{
+ D3DVECTOR dir, pos, speed;
+ FPOINT dim;
+ float s, a, prog, time;
+ float tSt[9], tNd[9];
+ int i, ii, st, nd, action;
+ BOOL bStop;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return TRUE;
+
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*1.5f;
+ a = Abs(m_physics->RetCirMotionY(MO_MOTSPEED)*2.0f);
+
+ if ( s == 0.0f && a != 0.0f ) a *= 1.5f;
+
+ m_armTimeAbs += event.rTime;
+ m_armTimeMarch += (s)*event.rTime*0.15f;
+ m_armMember += (s+a)*event.rTime*0.15f;
+
+ bStop = ( a == 0.0f && s == 0.0f ); // a l'arrêt ?
+
+ action = MA_MARCH; // marche
+ if ( s == 0.0f && a == 0.0f )
+ {
+ action = MA_STOP; // stop
+ }
+
+ if ( bStop )
+ {
+ prog = Mod(m_armTimeAbs, 2.0f)/10.0f;
+ a = Mod(m_armMember, 1.0f);
+ a = (prog-a)*event.rTime*2.0f; // vient gentiment à position stop
+ m_armMember += a;
+ }
+
+ if ( m_object->RetRuin() ) // ruine ?
+ {
+ m_actionType = MAS_RUIN;
+ }
+ if ( m_object->RetBurn() ) // brûle ?
+ {
+ if ( m_object->RetFixed() )
+ {
+ m_actionType = MAS_BURN;
+ }
+ else
+ {
+ m_actionType = -1;
+ }
+ }
+
+ for ( i=0 ; i<6 ; i++ ) // les 6 pattes
+ {
+ if ( m_actionType != -1 ) // action spéciale en cours ?
+ {
+ st = 3*3*3*3*MA_SPEC + 3*3*3*m_actionType + (i%3)*3;
+ nd = st;
+ time = event.rTime*m_actionTime;
+ m_armTimeAction = 0.0f;
+ }
+ else
+ {
+ if ( i < 3 ) prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.0f, 1.0f);
+ else prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.3f, 1.0f);
+ if ( m_bArmStop )
+ {
+ prog = (float)m_armTimeIndex/3.0f;
+ }
+ if ( prog < 0.33f ) // t0..t1 ?
+ {
+ prog = prog/0.33f; // 0..1
+ st = 0; // index start
+ nd = 1; // index end
+ }
+ else if ( prog < 0.67f ) // t1..t2 ?
+ {
+ prog = (prog-0.33f)/0.33f; // 0..1
+ st = 1; // index start
+ nd = 2; // index end
+ }
+ else // t2..t0 ?
+ {
+ prog = (prog-0.67f)/0.33f; // 0..1
+ st = 2; // index start
+ nd = 0; // index end
+ }
+ st = 3*3*3*3*action + st*3*3*3 + (i%3)*3;
+ nd = 3*3*3*3*action + nd*3*3*3 + (i%3)*3;
+
+ // De moins en moins mou ...
+ time = event.rTime*(10.0f+Min(m_armTimeAction*100.0f, 200.0f));
+ }
+
+ tSt[0] = m_armAngles[st+ 0]; // x
+ tSt[1] = m_armAngles[st+ 1]; // y
+ tSt[2] = m_armAngles[st+ 2]; // z
+ tSt[3] = m_armAngles[st+ 9]; // x
+ tSt[4] = m_armAngles[st+10]; // y
+ tSt[5] = m_armAngles[st+11]; // z
+ tSt[6] = m_armAngles[st+18]; // x
+ tSt[7] = m_armAngles[st+19]; // y
+ tSt[8] = m_armAngles[st+20]; // z
+
+ tNd[0] = m_armAngles[nd+ 0]; // x
+ tNd[1] = m_armAngles[nd+ 1]; // y
+ tNd[2] = m_armAngles[nd+ 2]; // z
+ tNd[3] = m_armAngles[nd+ 9]; // x
+ tNd[4] = m_armAngles[nd+10]; // y
+ tNd[5] = m_armAngles[nd+11]; // z
+ tNd[6] = m_armAngles[nd+18]; // x
+ tNd[7] = m_armAngles[nd+19]; // y
+ tNd[8] = m_armAngles[nd+20]; // z
+
+ if ( m_actionType == MAS_BACK2 ) // sur le dos ?
+ {
+ for ( ii=0 ; ii<9 ; ii++ )
+ {
+ tSt[ii] += Rand()*50.0f;
+ tNd[ii] = tSt[ii];
+ }
+//? time = 100.0f;
+ time = event.rTime*10.0f;
+ }
+
+ if ( i < 3 ) // patte droite (1..3) ?
+ {
+ m_object->SetAngleX(3+3*i+0, Smooth(m_object->RetAngleX(3+3*i+0), Propf(tSt[0], tNd[0], prog), time));
+ m_object->SetAngleY(3+3*i+0, Smooth(m_object->RetAngleY(3+3*i+0), Propf(tSt[1], tNd[1], prog), time));
+ m_object->SetAngleZ(3+3*i+0, Smooth(m_object->RetAngleZ(3+3*i+0), Propf(tSt[2], tNd[2], prog), time));
+ m_object->SetAngleX(3+3*i+1, Smooth(m_object->RetAngleX(3+3*i+1), Propf(tSt[3], tNd[3], prog), time));
+ m_object->SetAngleY(3+3*i+1, Smooth(m_object->RetAngleY(3+3*i+1), Propf(tSt[4], tNd[4], prog), time));
+ m_object->SetAngleZ(3+3*i+1, Smooth(m_object->RetAngleZ(3+3*i+1), Propf(tSt[5], tNd[5], prog), time));
+ m_object->SetAngleX(3+3*i+2, Smooth(m_object->RetAngleX(3+3*i+2), Propf(tSt[6], tNd[6], prog), time));
+ m_object->SetAngleY(3+3*i+2, Smooth(m_object->RetAngleY(3+3*i+2), Propf(tSt[7], tNd[7], prog), time));
+ m_object->SetAngleZ(3+3*i+2, Smooth(m_object->RetAngleZ(3+3*i+2), Propf(tSt[8], tNd[8], prog), time));
+ }
+ else // patte gauche (4..6) ?
+ {
+ m_object->SetAngleX(3+3*i+0, Smooth(m_object->RetAngleX(3+3*i+0), Propf(-tSt[0], -tNd[0], prog), time));
+ m_object->SetAngleY(3+3*i+0, Smooth(m_object->RetAngleY(3+3*i+0), Propf(-tSt[1], -tNd[1], prog), time));
+ m_object->SetAngleZ(3+3*i+0, Smooth(m_object->RetAngleZ(3+3*i+0), Propf( tSt[2], tNd[2], prog), time));
+ m_object->SetAngleX(3+3*i+1, Smooth(m_object->RetAngleX(3+3*i+1), Propf(-tSt[3], -tNd[3], prog), time));
+ m_object->SetAngleY(3+3*i+1, Smooth(m_object->RetAngleY(3+3*i+1), Propf(-tSt[4], -tNd[4], prog), time));
+ m_object->SetAngleZ(3+3*i+1, Smooth(m_object->RetAngleZ(3+3*i+1), Propf( tSt[5], tNd[5], prog), time));
+ m_object->SetAngleX(3+3*i+2, Smooth(m_object->RetAngleX(3+3*i+2), Propf(-tSt[6], -tNd[6], prog), time));
+ m_object->SetAngleY(3+3*i+2, Smooth(m_object->RetAngleY(3+3*i+2), Propf(-tSt[7], -tNd[7], prog), time));
+ m_object->SetAngleZ(3+3*i+2, Smooth(m_object->RetAngleZ(3+3*i+2), Propf( tSt[8], tNd[8], prog), time));
+ }
+ }
+
+#if ADJUST_ANGLE
+ if ( m_object->RetSelect() )
+ {
+ char s[100];
+ sprintf(s, "A:time=%d Q:part=%d W:member=%d", m_armTimeIndex, m_armPartIndex, m_armMemberIndex);
+ m_engine->SetInfoText(4, s);
+ }
+#endif
+
+ if ( m_actionType == MAS_PREPARE ) // prépare le tir ?
+ {
+ prog = m_progress;
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = Prop(0, -50, prog);
+ SetInclinaison(dir);
+ m_object->SetAngleZ(1, Prop(0, 65, prog)); // tête
+ m_object->SetAngleZ(2, Prop(0, -95, prog)); // queue
+ }
+ else if ( m_actionType == MAS_FIRE ) // tir ?
+ {
+ if ( m_progress < 0.75f ) a = m_progress/0.75f;
+ else a = (1.0f-m_progress)/0.25f;
+ m_object->SetZoom(2, (a*0.5f)+1.0f); // queue
+ m_object->SetAngleX(2, (Rand()-0.5f)*0.3f*a);
+ m_object->SetAngleY(2, (Rand()-0.5f)*0.3f*a);
+
+ dir.x = (Rand()-0.5f)*0.02f*a;
+ dir.y = (Rand()-0.5f)*0.05f*a;
+ dir.z = (Rand()-0.5f)*0.03f*a;
+ SetCirVibration(dir);
+ }
+ else if ( m_actionType == MAS_TERMINATE ) // termine le tir ?
+ {
+ prog = 1.0f-m_progress;
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = Prop(0, -50, prog);
+ SetInclinaison(dir);
+ m_object->SetAngleZ(1, Prop(0, 65, prog)); // tête
+ m_object->SetAngleZ(2, Prop(0, -95, prog)); // queue
+ }
+ else if ( m_actionType == MAS_BURN ) // brûle ?
+ {
+ dir = D3DVECTOR(PI, 0.0f, 0.0f);
+ SetCirVibration(dir);
+ dir = D3DVECTOR(0.0f, -1.5f, 0.0f);
+ SetLinVibration(dir);
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ time = event.rTime*1.0f;
+ m_object->SetAngleZ(1, Smooth(m_object->RetAngleZ(1), 0.0f, time)); // tête
+ m_object->SetAngleZ(2, Smooth(m_object->RetAngleZ(2), 0.0f, time)); // queue
+ }
+ else if ( m_actionType == MAS_RUIN ) // ruine ?
+ {
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetLinVibration(dir);
+ SetCirVibration(dir);
+ SetInclinaison(dir);
+ }
+ else if ( m_actionType == MAS_BACK1 ) // se met sur le dos ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_armTimeAbs )
+ {
+ m_lastParticule = m_armTimeAbs;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ if ( m_progress < 0.5f )
+ {
+ dir.x = 0.0f;
+ dir.y = powf(m_progress/0.5f, 2.0f)*12.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ else
+ {
+ dir.x = 0.0f;
+ dir.y = powf(2.0f-m_progress/0.5f, 2.0f)*12.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ dir.x = m_progress*PI;
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ SetCirVibration(dir);
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(MAS_BACK2, 55.0f+Rand()*10.0f);
+ }
+ }
+ else if ( m_actionType == MAS_BACK2 ) // bouge sur le dos ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_armTimeAbs )
+ {
+ m_lastParticule = m_armTimeAbs;
+
+ if ( rand()%10 == 0 )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ pos.y -= 1.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = Rand()*2.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+ }
+
+ dir = D3DVECTOR(0.0f, -1.0f, 0.0f);
+ SetLinVibration(dir);
+ dir.x = sinf(m_armTimeAbs* 4.0f)*0.10f+
+ sinf(m_armTimeAbs* 7.0f)*0.20f+
+ sinf(m_armTimeAbs*10.0f)*0.40f+
+ sinf(m_armTimeAbs*21.0f)*0.50f+PI;
+ dir.y = sinf(m_armTimeAbs* 3.0f)*0.01f+
+ sinf(m_armTimeAbs* 6.0f)*0.02f+
+ sinf(m_armTimeAbs*11.0f)*0.04f+
+ sinf(m_armTimeAbs*20.0f)*0.02f;
+ dir.z = sinf(m_armTimeAbs* 5.0f)*0.01f+
+ sinf(m_armTimeAbs* 8.0f)*0.02f+
+ sinf(m_armTimeAbs* 9.0f)*0.04f+
+ sinf(m_armTimeAbs*23.0f)*0.03f;
+ SetCirVibration(dir);
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*8.0f)*0.7f); // tête
+ m_object->SetAngleY(2, cosf(m_armTimeAbs*8.0f)*0.7f); // queue
+ m_object->SetAngleZ(1, 0.0f); // tête
+ m_object->SetAngleZ(2, 0.0f); // queue
+
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(MAS_BACK3, 0.4f);
+ }
+ }
+ else if ( m_actionType == MAS_BACK3 ) // se remet sur les pattes ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_armTimeAbs )
+ {
+ m_lastParticule = m_armTimeAbs;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ if ( m_progress < 0.5f )
+ {
+ dir.x = 0.0f;
+ dir.y = powf(m_progress/0.5f, 2.0f)*5.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ else
+ {
+ dir.x = 0.0f;
+ dir.y = powf(2.0f-m_progress/0.5f, 2.0f)*5.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ dir.x = (1.0f-m_progress)*PI;
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ SetCirVibration(dir);
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(-1);
+ m_object->SetFixed(FALSE); // bouge de nouveau
+ }
+ }
+ else
+ {
+ m_object->SetZoom(2, 1.0f); // queue
+ m_object->SetAngleX(2, 0.0f);
+ m_object->SetAngleY(2, 0.0f);
+
+ if ( bStop )
+ {
+ m_object->SetAngleZ(2, sinf(m_armTimeAbs*1.7f)*0.15f); // queue
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetLinVibration(dir);
+ SetInclinaison(dir);
+ }
+ else
+ {
+ a = Mod(m_armTimeMarch, 1.0f);
+ if ( a < 0.5f ) a = -1.0f+4.0f*a; // -1..1
+ else a = 3.0f-4.0f*a; // 1..-1
+ dir.x = sinf(a)*0.05f;
+
+ s = Mod(m_armTimeMarch/2.0f, 1.0f);
+ if ( s < 0.5f ) s = -1.0f+4.0f*s; // -1..1
+ else s = 3.0f-4.0f*s; // 1..-1
+ dir.z = sinf(s)*0.1f;
+
+ dir.y = 0.0f;
+ SetInclinaison(dir);
+
+ m_object->SetAngleZ(2, -sinf(a)*0.3f); // queue
+
+ a = Mod(m_armMember-0.1f, 1.0f);
+ if ( a < 0.33f )
+ {
+ dir.y = -(1.0f-(a/0.33f))*0.3f;
+ }
+ else if ( a < 0.67f )
+ {
+ dir.y = 0.0f;
+ }
+ else
+ {
+ dir.y = -(a-0.67f)/0.33f*0.3f;
+ }
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetCirVibration(dir);
+
+ m_object->SetAngleZ(1, sinf(m_armTimeAbs*1.4f)*0.20f); // tête
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*1.9f)*0.10f); // tête
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*2.1f)*0.50f); // tête
+ }
+
+ return TRUE;
+}
+
+
diff --git a/src/motionant.h b/src/motionant.h
new file mode 100644
index 0000000..0365927
--- /dev/null
+++ b/src/motionant.h
@@ -0,0 +1,61 @@
+// motionant.h
+
+#ifndef _MOTIONANT_H_
+#define _MOTIONANT_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define MA_MARCH 0
+#define MA_STOP 1
+#define MA_SPEC 2
+
+#define MAS_PREPARE 0
+#define MAS_FIRE 1
+#define MAS_TERMINATE 2
+#define MAS_BURN 3
+#define MAS_RUIN 4
+#define MAS_BACK1 5
+#define MAS_BACK2 6
+#define MAS_BACK3 7
+
+
+class CMotionAnt : public CMotion
+{
+public:
+ CMotionAnt(CInstanceManager* iMan, CObject* object);
+ ~CMotionAnt();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+
+protected:
+ void CreatePhysics();
+ BOOL EventFrame(const Event &event);
+
+protected:
+ float m_armMember;
+ float m_armTimeAbs;
+ float m_armTimeMarch;
+ float m_armTimeAction;
+ short m_armAngles[3*3*3*3*3 + 3*3*3*8];
+ int m_armTimeIndex;
+ int m_armPartIndex;
+ int m_armMemberIndex;
+ int m_armLastAction;
+ BOOL m_bArmStop;
+ float m_lastParticule;
+};
+
+
+#endif //_MOTIONANT_H_
diff --git a/src/motionbee.cpp b/src/motionbee.cpp
new file mode 100644
index 0000000..8d4de31
--- /dev/null
+++ b/src/motionbee.cpp
@@ -0,0 +1,647 @@
+// motionbee.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionbee.h"
+
+
+
+#define ADJUST_ANGLE FALSE // TRUE -> ajuste les angles des membres
+#define START_TIME 1000.0f // début du temps relatif
+
+
+
+// Constructeur de l'objet.
+
+CMotionBee::CMotionBee(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_armMember = START_TIME;
+ m_armTimeAbs = START_TIME;
+ m_armTimeMarch = START_TIME;
+ m_armTimeAction = START_TIME;
+ m_armTimeIndex = 0;
+ m_armPartIndex = 0;
+ m_armMemberIndex = 0;
+ m_armLastAction = -1;
+ m_bArmStop = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CMotionBee::~CMotionBee()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionBee::DeleteObject(BOOL bAll)
+{
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionBee::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 3+18+2 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+
+ pModFile->ReadModel("objects\\bee1.mod");
+ pModFile->CreateEngineObject(rank);
+
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUM, 0.20f);
+ m_object->SetGlobalSphere(D3DVECTOR(-1.0f, 1.0f, 0.0f), 5.0f);
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\bee2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(1.6f, 0.3f, 0.0f));
+
+ // Crée la queue.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\bee3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(-0.8f, 0.0f, 0.0f));
+
+ // Crée la cuisse 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(-0.3f, -0.1f, -0.2f));
+
+ // Crée la jambe 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 3);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 4);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.3f, -0.1f, -0.4f));
+
+ // Crée la jambe 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 6);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 7);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(1.0f, -0.1f, -0.7f));
+
+ // Crée la jambe 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(10, rank);
+ m_object->SetObjectParent(10, 9);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(10, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(11, rank);
+ m_object->SetObjectParent(11, 10);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(11, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(12, rank);
+ m_object->SetObjectParent(12, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(12, D3DVECTOR(-0.3f, -0.1f, 0.2f));
+ m_object->SetAngleY(12, PI);
+
+ // Crée la jambe 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(13, rank);
+ m_object->SetObjectParent(13, 12);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(13, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(14, rank);
+ m_object->SetObjectParent(14, 13);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(14, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(15, rank);
+ m_object->SetObjectParent(15, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(15, D3DVECTOR(0.3f, -0.1f, 0.4f));
+ m_object->SetAngleY(15, PI);
+
+ // Crée la jambe 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(16, rank);
+ m_object->SetObjectParent(16, 15);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(16, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(17, rank);
+ m_object->SetObjectParent(17, 16);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(17, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée la cuisse 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(18, rank);
+ m_object->SetObjectParent(18, 0);
+ pModFile->ReadModel("objects\\ant4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(18, D3DVECTOR(1.0f, -0.1f, 0.7f));
+ m_object->SetAngleY(18, PI);
+
+ // Crée la jambe 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(19, rank);
+ m_object->SetObjectParent(19, 18);
+ pModFile->ReadModel("objects\\ant5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(19, D3DVECTOR(0.0f, 0.0f, -1.0f));
+
+ // Crée le pied 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(20, rank);
+ m_object->SetObjectParent(20, 19);
+ pModFile->ReadModel("objects\\ant6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(20, D3DVECTOR(0.0f, 0.0f, -2.0f));
+
+ // Crée l'aile droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(21, rank);
+ m_object->SetObjectParent(21, 0);
+ pModFile->ReadModel("objects\\bee7.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(21, D3DVECTOR(0.8f, 0.4f, -0.5f));
+
+ // Crée l'aile gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(22, rank);
+ m_object->SetObjectParent(22, 0);
+ pModFile->ReadModel("objects\\bee7.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(22, D3DVECTOR(0.8f, 0.4f, 0.5f));
+
+ m_object->CreateShadowCircle(6.0f, 0.5f);
+
+ CreatePhysics();
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionBee::CreatePhysics()
+{
+ Character* character;
+ int i;
+
+ int member_march[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 0,45,0, 0,45,0, 0,50,0, // t0: cuisses 1..3
+ 30,-70,0, 20,-105,20, 25,-100,0, // t0: jambes 1..3
+ -70,75,0, -30,80,0, -80,80,0, // t0: pieds 1..3
+ // au sol devant :
+ 0,30,0, 0,20,0, 0,15,0, // t1: cuisses 1..3
+ -15,-50,0, -20,-60,0, -10,-75,0, // t1: jambes 1..3
+ -40,50,0, -25,15,0, -50,35,0, // t1: pieds 1..3
+ // au sol derrière :
+ 0,35,0, 0,30,0, 0,20,0, // t2: cuisses 1..3
+ -20,-15,0, -30,-55,0, -25,-70,15, // t2: jambes 1..3
+ -25,25,0, -20,60,0, -30,95,0, // t2: pieds 1..3
+ };
+
+ int member_spec[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // porte boulet :
+ 0,45,0, 0,45,0, 0,50,0, // s0: cuisses 1..3
+ -35,-70,0, -20,-85,-25,-25,-100,0, // s0: jambes 1..3
+ -110,75,-15,-130,80,-25,-125,40,0, // s0: pieds 1..3
+ // brûle :
+ 0,45,0, 0,45,0, 0,50,0, // s1: cuisses 1..3
+ -35,-70,0, -20,-85,-25,-25,-100,0, // s1: jambes 1..3
+ -110,75,-15,-130,80,-25,-125,40,0, // s1: pieds 1..3
+ // ruine :
+ 0,45,0, 0,45,0, 0,50,0, // s2: cuisses 1..3
+ -35,-70,0, -20,-85,-25,-25,-100,0, // s2: jambes 1..3
+ -110,75,-15,-130,80,-25,-125,40,0, // s2: pieds 1..3
+ };
+
+ m_physics->SetType(TYPE_FLYING);
+
+ character = m_object->RetCharacter();
+ character->wheelFront = 3.0f;
+ character->wheelBack = 3.0f;
+ character->wheelLeft = 5.0f;
+ character->wheelRight = 5.0f;
+ character->height = 2.5f;
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 50.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 50.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+ m_physics->SetLinMotionY(MO_ADVSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_RECSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionY(MO_RECACCEL, 50.0f);
+ m_physics->SetLinMotionY(MO_STOACCEL, 50.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 1.0f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 1.0f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 20.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 40.0f);
+
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MB_MARCH+i] = member_march[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MB_SPEC+i] = member_spec[i];
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionBee::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if ADJUST_ANGLE
+ int i;
+
+ if ( event.param == 'A' ) m_armTimeIndex++;
+ if ( m_armTimeIndex >= 3 ) m_armTimeIndex = 0;
+
+ if ( event.param == 'Q' ) m_armPartIndex++;
+ if ( m_armPartIndex >= 3 ) m_armPartIndex = 0;
+
+ if ( event.param == 'W' ) m_armMemberIndex++;
+ if ( m_armMemberIndex >= 3 ) m_armMemberIndex = 0;
+
+ i = m_armMemberIndex*3;
+ i += m_armPartIndex*3*3;
+ i += m_armTimeIndex*3*3*3;
+//? i += 3*3*3*3;
+
+ if ( event.param == 'E' ) m_armAngles[i+0] += 5;
+ if ( event.param == 'D' ) m_armAngles[i+0] -= 5;
+ if ( event.param == 'R' ) m_armAngles[i+1] += 5;
+ if ( event.param == 'F' ) m_armAngles[i+1] -= 5;
+ if ( event.param == 'T' ) m_armAngles[i+2] += 5;
+ if ( event.param == 'G' ) m_armAngles[i+2] -= 5;
+
+ if ( event.param == 'Y' ) m_bArmStop = !m_bArmStop;
+#endif
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionBee::EventFrame(const Event &event)
+{
+ D3DVECTOR dir;
+ float s, a, prog;
+ int action, i, st, nd;
+ BOOL bStop;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return TRUE;
+
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*0.30f;
+ a = Abs(m_physics->RetCirMotionY(MO_MOTSPEED)*2.00f);
+
+ if ( s == 0.0f && a != 0.0f ) a *= 1.5f;
+
+ m_armTimeAbs += event.rTime;
+ m_armTimeMarch += (s)*event.rTime*0.15f;
+ m_armMember += (s+a)*event.rTime*0.15f;
+
+ bStop = ( a == 0.0f && s == 0.0f ); // a l'arrêt ?
+ if ( !m_physics->RetLand() ) bStop = TRUE;
+
+ if ( bStop )
+ {
+ prog = Mod(m_armTimeAbs, 2.0f)/10.0f;
+ a = Mod(m_armMember, 1.0f);
+ a = (prog-a)*event.rTime*2.0f; // vient gentiment à position stop
+ m_armMember += a;
+ }
+
+ action = MB_MARCH; // marche
+
+ m_actionType = -1;
+ if ( m_object->RetFret() != 0 ) m_actionType = MBS_HOLD; // porte le boulet
+
+ if ( m_object->RetRuin() ) // ruine ?
+ {
+ m_actionType = MBS_RUIN;
+ }
+ if ( m_object->RetBurn() ) // brûle ?
+ {
+ m_actionType = MBS_BURN;
+ }
+
+ for ( i=0 ; i<6 ; i++ ) // les 6 pattes
+ {
+ if ( m_actionType != -1 ) // action spéciale en cours ?
+ {
+ st = 3*3*3*3*MB_SPEC + 3*3*3*m_actionType + (i%3)*3;
+ nd = st;
+ }
+ else
+ {
+ if ( i < 3 ) prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.0f, 1.0f);
+ else prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.3f, 1.0f);
+ if ( m_bArmStop )
+ {
+ prog = (float)m_armTimeIndex/3.0f;
+ }
+ if ( prog < 0.33f ) // t0..t1 ?
+ {
+ prog = prog/0.33f; // 0..1
+ st = 0; // index start
+ nd = 1; // index end
+ }
+ else if ( prog < 0.67f ) // t1..t2 ?
+ {
+ prog = (prog-0.33f)/0.33f; // 0..1
+ st = 1; // index start
+ nd = 2; // index end
+ }
+ else // t2..t0 ?
+ {
+ prog = (prog-0.67f)/0.33f; // 0..1
+ st = 2; // index start
+ nd = 0; // index end
+ }
+ st = 3*3*3*3*action + st*3*3*3 + (i%3)*3;
+ nd = 3*3*3*3*action + nd*3*3*3 + (i%3)*3;
+ }
+
+ if ( i < 3 ) // patte droite (1..3) ?
+ {
+ m_object->SetAngleX(3+3*i+0, Prop(m_armAngles[st+ 0], m_armAngles[nd+ 0], prog));
+ m_object->SetAngleY(3+3*i+0, Prop(m_armAngles[st+ 1], m_armAngles[nd+ 1], prog));
+ m_object->SetAngleZ(3+3*i+0, Prop(m_armAngles[st+ 2], m_armAngles[nd+ 2], prog));
+ m_object->SetAngleX(3+3*i+1, Prop(m_armAngles[st+ 9], m_armAngles[nd+ 9], prog));
+ m_object->SetAngleY(3+3*i+1, Prop(m_armAngles[st+10], m_armAngles[nd+10], prog));
+ m_object->SetAngleZ(3+3*i+1, Prop(m_armAngles[st+11], m_armAngles[nd+11], prog));
+ m_object->SetAngleX(3+3*i+2, Prop(m_armAngles[st+18], m_armAngles[nd+18], prog));
+ m_object->SetAngleY(3+3*i+2, Prop(m_armAngles[st+19], m_armAngles[nd+19], prog));
+ m_object->SetAngleZ(3+3*i+2, Prop(m_armAngles[st+20], m_armAngles[nd+20], prog));
+ }
+ else // patte gauche (4..6) ?
+ {
+ m_object->SetAngleX(3+3*i+0, Prop( -m_armAngles[st+ 0], -m_armAngles[nd+ 0], prog));
+ m_object->SetAngleY(3+3*i+0, Prop(180-m_armAngles[st+ 1], 180-m_armAngles[nd+ 1], prog));
+ m_object->SetAngleZ(3+3*i+0, Prop( -m_armAngles[st+ 2], -m_armAngles[nd+ 2], prog));
+ m_object->SetAngleX(3+3*i+1, Prop( m_armAngles[st+ 9], m_armAngles[nd+ 9], prog));
+ m_object->SetAngleY(3+3*i+1, Prop( -m_armAngles[st+10], -m_armAngles[nd+10], prog));
+ m_object->SetAngleZ(3+3*i+1, Prop( -m_armAngles[st+11], -m_armAngles[nd+11], prog));
+ m_object->SetAngleX(3+3*i+2, Prop( m_armAngles[st+18], m_armAngles[nd+18], prog));
+ m_object->SetAngleY(3+3*i+2, Prop( -m_armAngles[st+19], -m_armAngles[nd+19], prog));
+ m_object->SetAngleZ(3+3*i+2, Prop( -m_armAngles[st+20], -m_armAngles[nd+20], prog));
+ }
+ }
+
+#if ADJUST_ANGLE
+ if ( m_object->RetSelect() )
+ {
+ char s[100];
+ sprintf(s, "A:time=%d Q:part=%d W:member=%d", m_armTimeIndex, m_armPartIndex, m_armMemberIndex);
+ m_engine->SetInfoText(4, s);
+ }
+#endif
+
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ if ( m_object->RetRuin() )
+ {
+ }
+ else if ( bStop || m_object->RetBurn() )
+ {
+ m_object->SetAngleZ(2, sinf(m_armTimeAbs*1.7f)*0.15f+0.35f); // queue
+ }
+ else
+ {
+ a = Mod(m_armTimeMarch, 1.0f);
+ if ( a < 0.5f ) a = -1.0f+4.0f*a; // -1..1
+ else a = 3.0f-4.0f*a; // 1..-1
+ dir.x = sinf(a)*0.05f;
+
+ s = Mod(m_armTimeMarch/2.0f, 1.0f);
+ if ( s < 0.5f ) s = -1.0f+4.0f*s; // -1..1
+ else s = 3.0f-4.0f*s; // 1..-1
+ dir.z = sinf(s)*0.1f;
+
+ dir.y = 0.0f;
+ m_object->SetInclinaison(dir);
+
+ m_object->SetAngleZ(2, -sinf(a)*0.3f); // queue
+
+ a = Mod(m_armMember-0.1f, 1.0f);
+ if ( a < 0.33f )
+ {
+ dir.y = -(1.0f-(a/0.33f))*0.3f;
+ }
+ else if ( a < 0.67f )
+ {
+ dir.y = 0.0f;
+ }
+ else
+ {
+ dir.y = -(a-0.67f)/0.33f*0.3f;
+ }
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ m_object->SetLinVibration(dir);
+ }
+ }
+
+ if ( m_physics->RetLand() )
+ {
+ if ( bStop ) prog = 0.05f;
+ else prog = 0.15f;
+ }
+ else
+ {
+ prog = 1.00f;
+ }
+
+#if 0
+ a = Rand()*PI/2.0f*prog;
+ m_object->SetAngleX(21, a); // aile droite
+ a = -Rand()*PI/4.0f*prog;
+ m_object->SetAngleY(21, a);
+
+ a = -Rand()*PI/2.0f*prog;
+ m_object->SetAngleX(22, a); // aile gauche
+ a = Rand()*PI/4.0f*prog;
+ m_object->SetAngleY(22, a);
+#else
+ m_object->SetAngleX(21, (sinf(m_armTimeAbs*30.0f)+1.0f)*(PI/4.0f)*prog);
+ m_object->SetAngleY(21, -Rand()*PI/6.0f*prog);
+
+ m_object->SetAngleX(22, -(sinf(m_armTimeAbs*30.0f)+1.0f)*(PI/4.0f)*prog);
+ m_object->SetAngleY(22, Rand()*PI/6.0f*prog);
+#endif
+
+ m_object->SetAngleZ(1, sinf(m_armTimeAbs*1.4f)*0.20f); // tête
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*1.9f)*0.10f); // tête
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*2.1f)*0.50f); // tête
+
+#if 0
+ h = m_terrain->RetFloorHeight(RetPosition(0));
+ radius = 4.0f+h/4.0f;
+ color.r = 0.3f+h/80.0f;
+ color.g = color.r;
+ color.b = color.r;
+ color.a = color.r;
+ m_engine->SetObjectShadowRadius(m_objectPart[0].object, radius);
+ m_engine->SetObjectShadowColor(m_objectPart[0].object, color);
+#endif
+
+ return TRUE;
+}
+
+
diff --git a/src/motionbee.h b/src/motionbee.h
new file mode 100644
index 0000000..18636c2
--- /dev/null
+++ b/src/motionbee.h
@@ -0,0 +1,54 @@
+// motionbee.h
+
+#ifndef _MOTIONBEE_H_
+#define _MOTIONBEE_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define MB_MARCH 0
+#define MB_SPEC 1
+
+#define MBS_HOLD 0
+#define MBS_BURN 1
+#define MBS_RUIN 2
+
+
+class CMotionBee : public CMotion
+{
+public:
+ CMotionBee(CInstanceManager* iMan, CObject* object);
+ ~CMotionBee();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+
+protected:
+ void CreatePhysics();
+ BOOL EventFrame(const Event &event);
+
+protected:
+ float m_armMember;
+ float m_armTimeAbs;
+ float m_armTimeMarch;
+ float m_armTimeAction;
+ short m_armAngles[3*3*3*3*2];
+ int m_armTimeIndex;
+ int m_armPartIndex;
+ int m_armMemberIndex;
+ int m_armLastAction;
+ BOOL m_bArmStop;
+};
+
+
+#endif //_MOTIONBEE_H_
diff --git a/src/motionhuman.cpp b/src/motionhuman.cpp
new file mode 100644
index 0000000..9306b43
--- /dev/null
+++ b/src/motionhuman.cpp
@@ -0,0 +1,1784 @@
+// motionhuman.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionhuman.h"
+
+
+
+#define ADJUST_ANGLE FALSE // TRUE -> ajuste les angles des membres
+#define ADJUST_ACTION (3*3*3*3*MH_SPEC+3*3*3*MHS_SATCOM)
+
+#define START_TIME 1000.0f // début du temps relatif
+
+
+
+// Constructeur de l'objet.
+
+CMotionHuman::CMotionHuman(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_partiReactor = -1;
+ m_armMember = START_TIME;
+ m_armTimeAbs = START_TIME;
+ m_armTimeAction = START_TIME;
+ m_armTimeSwim = START_TIME;
+ m_armTimeIndex = 0;
+ m_armPartIndex = 0;
+ m_armMemberIndex = 0;
+ m_armLastAction = -1;
+ m_bArmStop = FALSE;
+ m_lastSoundMarch = 0.0f;
+ m_lastSoundHhh = 0.0f;
+ m_time = 0.0f;
+ m_tired = 0.0f;
+ m_bDisplayPerso = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CMotionHuman::~CMotionHuman()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionHuman::DeleteObject(BOOL bAll)
+{
+ if ( m_partiReactor != -1 )
+ {
+ m_particule->DeleteParticule(m_partiReactor);
+ m_partiReactor = -1;
+ }
+}
+
+
+// Démarre une action.
+
+Error CMotionHuman::SetAction(int action, float time)
+{
+ CMotion::SetAction(action, time);
+ m_time = 0.0f;
+ return ERR_OK;
+}
+
+
+// Crée le cosmonaute posé sur le sol.
+
+BOOL CMotionHuman::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ char filename[100];
+ int rank, option, face, glasses;
+
+ if ( m_engine->RetRestCreate() < 16 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+ option = m_object->RetOption();
+
+ if ( m_main->RetGamerOnlyHead() )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+ face = m_main->RetGamerFace();
+ sprintf(filename, "objects\\human2h%d.mod", face+1);
+ pModFile->ReadModel(filename);
+ pModFile->CreateEngineObject(rank);
+
+ glasses = m_main->RetGamerGlasses();
+ if ( glasses != 0 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ sprintf(filename, "objects\\human2g%d.mod", glasses);
+ pModFile->ReadModel(filename);
+ pModFile->CreateEngineObject(rank);
+ }
+
+ CreatePhysics(type);
+ m_object->SetFloorHeight(0.0f);
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+ }
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+
+ if ( option == 0 ) // tête dans casque ?
+ {
+ pModFile->ReadModel("objects\\human1c.mod");
+ }
+ if ( option == 1 ) // tête à l'air ?
+ {
+ pModFile->ReadModel("objects\\human1h.mod");
+ }
+ if ( option == 2 ) // sans sac à dos ?
+ {
+ pModFile->ReadModel("objects\\human1v.mod");
+ }
+ pModFile->CreateEngineObject(rank);
+
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 2.0f, SOUND_AIE, 0.20f);
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 4.0f);
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+
+ if ( type == OBJECT_HUMAN )
+ {
+ if ( option == 0 ) // tête dans casque ?
+ {
+ face = m_main->RetGamerFace();
+ sprintf(filename, "objects\\human2c%d.mod", face+1);
+ pModFile->ReadModel(filename);
+ }
+ if ( option == 1 || // tête à l'air ?
+ option == 2 ) // sans sac à dos ?
+ {
+ face = m_main->RetGamerFace();
+ sprintf(filename, "objects\\human2h%d.mod", face+1);
+ pModFile->ReadModel(filename);
+ }
+ }
+ if ( type == OBJECT_TECH )
+ {
+ pModFile->ReadModel("objects\\human2t.mod");
+ }
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 2.7f, 0.0f));
+ if ( option == 1 || // tête à l'air ?
+ option == 2 ) // sans sac à dos ?
+ {
+ m_object->SetZoom(1, D3DVECTOR(1.0f, 1.05f, 1.0f));
+ }
+
+ // Crée les lunettes.
+ glasses = m_main->RetGamerGlasses();
+ if ( glasses != 0 && type == OBJECT_HUMAN )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(15, rank);
+ m_object->SetObjectParent(15, 1);
+ sprintf(filename, "objects\\human2g%d.mod", glasses);
+ pModFile->ReadModel(filename);
+ pModFile->CreateEngineObject(rank);
+ }
+
+ // Crée le bras droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\human3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(0.0f, 2.3f, -1.2f));
+ m_object->SetAngle(2, D3DVECTOR(90.0f*PI/180.0f, 90.0f*PI/180.0f, -50.0f*PI/180.0f));
+
+ // Crée l'avant-bras droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\human4r.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(1.3f, 0.0f, 0.0f));
+ m_object->SetAngle(3, D3DVECTOR(0.0f*PI/180.0f, -20.0f*PI/180.0f, 0.0f*PI/180.0f));
+
+ // Crée la main droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 3);
+ pModFile->ReadModel("objects\\human5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(1.2f, 0.0f, 0.0f));
+
+ // Crée la cuisse droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 0);
+ pModFile->ReadModel("objects\\human6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(0.0f, 0.0f, -0.7f));
+ m_object->SetAngle(5, D3DVECTOR(10.0f*PI/180.0f, 0.0f*PI/180.0f, 5.0f*PI/180.0f));
+
+ // Crée la jambe droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 5);
+ pModFile->ReadModel("objects\\human7.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.0f, -1.5f, 0.0f));
+ m_object->SetAngle(6, D3DVECTOR(0.0f*PI/180.0f, 0.0f*PI/180.0f, -10.0f*PI/180.0f));
+
+ // Crée le pied droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 6);
+ pModFile->ReadModel("objects\\human8.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, -1.5f, 0.0f));
+ m_object->SetAngle(7, D3DVECTOR(-10.0f*PI/180.0f, 5.0f*PI/180.0f, 5.0f*PI/180.0f));
+
+ // Crée le bras gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\human3.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(0.0f, 2.3f, 1.2f));
+ m_object->SetAngle(8, D3DVECTOR(-90.0f*PI/180.0f, -90.0f*PI/180.0f, -50.0f*PI/180.0f));
+
+ // Crée l'avant-bras gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 8);
+ pModFile->ReadModel("objects\\human4l.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(1.3f, 0.0f, 0.0f));
+ m_object->SetAngle(9, D3DVECTOR(0.0f*PI/180.0f, 20.0f*PI/180.0f, 0.0f*PI/180.0f));
+
+ // Crée la main gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(10, rank);
+ m_object->SetObjectParent(10, 9);
+ pModFile->ReadModel("objects\\human5.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(10, D3DVECTOR(1.2f, 0.0f, 0.0f));
+
+ // Crée la cuisse gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(11, rank);
+ m_object->SetObjectParent(11, 0);
+ pModFile->ReadModel("objects\\human6.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(11, D3DVECTOR(0.0f, 0.0f, 0.7f));
+ m_object->SetAngle(11, D3DVECTOR(-10.0f*PI/180.0f, 0.0f*PI/180.0f, 5.0f*PI/180.0f));
+
+ // Crée la jambe gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(12, rank);
+ m_object->SetObjectParent(12, 11);
+ pModFile->ReadModel("objects\\human7.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(12, D3DVECTOR(0.0f, -1.5f, 0.0f));
+ m_object->SetAngle(12, D3DVECTOR(0.0f*PI/180.0f, 0.0f*PI/180.0f, -10.0f*PI/180.0f));
+
+ // Crée le pied gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(13, rank);
+ m_object->SetObjectParent(13, 12);
+ pModFile->ReadModel("objects\\human8.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(13, D3DVECTOR(0.0f, -1.5f, 0.0f));
+ m_object->SetAngle(13, D3DVECTOR(10.0f*PI/180.0f, -5.0f*PI/180.0f, 5.0f*PI/180.0f));
+
+ // Crée le pistolet.
+ if ( option != 2 ) // avec sac à dos ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(14, rank);
+ m_object->SetObjectParent(14, 0);
+ pModFile->ReadModel("objects\\human9.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(14, D3DVECTOR(-1.5f, 0.3f, -1.35f));
+ m_object->SetAngleZ(14, PI);
+ }
+
+ m_object->CreateShadowCircle(2.0f, 0.8f);
+
+ CreatePhysics(type);
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionHuman::CreatePhysics(ObjectType type)
+{
+ Character* character;
+ int i;
+
+ int member_march[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 90,90,-50, 10,0,55, 0,0,0, // t0: bras/cuisses/-
+ 0,-20,0, -5,0,-110, 0,0,0, // t0: avant-bras/jambes/-
+ 0,0,0, -5,0,40, 0,0,0, // t0: mains/pieds/-
+ // au sol devant :
+ 125,115,-45,10,0,50, 0,0,0, // t1: bras/cuisses/-
+ 0,-20,0, -5,0,-15, 0,0,0, // t1: avant-bras/jambes/-
+ 0,0,0, -5,0,0, 0,0,0, // t1: mains/pieds/-
+ // au sol derrière :
+ 25,55,-40, 10,0,-15, 0,0,0, // t2: bras/cuisses/-
+ 30,-50,40, -5,0,-55, 0,0,0, // t2: avant-bras/jambes/-
+ 0,0,0, -5,0,25, 0,0,0, // t2: mains/pieds/-
+ };
+
+ int member_march_take[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 15,50,-50, 10,0,55, 0,0,0, // t0: bras/cuisses/-
+ 45,-70,10, -5,0,-110, 0,0,0, // t0: avant-bras/jambes/-
+ -10,25,0, -5,0,40, 0,0,0, // t0: mains/pieds/-
+ // au sol devant :
+ 15,50,-55, 10,0,50, 0,0,0, // t1: bras/cuisses/-
+ 45,-70,10, -5,0,-15, 0,0,0, // t1: avant-bras/jambes/-
+ -10,25,0, -5,0,0, 0,0,0, // t1: mains/pieds/-
+ // au sol derrière :
+ 15,50,-45, 10,0,-15, 0,0,0, // t2: bras/cuisses/-
+ 45,-70,10, -5,0,-55, 0,0,0, // t2: avant-bras/jambes/-
+ -10,25,0, -5,0,45, 0,0,0, // t2: mains/pieds/-
+ };
+
+ int member_turn[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 90,90,-50, 10,0,30, 0,0,0, // t0: bras/cuisses/-
+ 0,-20,0, -5,0,-60, 0,0,0, // t0: avant-bras/jambes/-
+ 0,0,0, -5,0,30, 0,0,0, // t0: mains/pieds/-
+ // au sol devant :
+ 90,110,-45, 10,0,0, 0,0,0, // t1: bras/cuisses/-
+ 0,-20,0, -5,5,0, 0,0,0, // t1: avant-bras/jambes/-
+ 0,0,0, -5,10,0, 0,0,0, // t1: mains/pieds/-
+ // au sol derrière :
+ 90,70,-45, 10,0,0, 0,0,0, // t2: bras/cuisses/-
+ 0,-20,10, -5,-5,0, 0,0,0, // t2: avant-bras/jambes/-
+ 0,0,0, -5,-10,0, 0,0,0, // t2: mains/pieds/-
+ };
+
+ int member_stop[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3,
+ 90,90,-50, 10,0,5, 0,0,0, // bras/cuisses/-
+ 0,-20,0, 0,0,-10, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // mains/pieds/-
+ //
+ 90,90,-55, 10,0,5, 0,0,0, // bras/cuisses/-
+ 0,-15,0, 0,0,-10, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // mains/pieds/-
+ //
+ 90,90,-60, 10,0,5, 0,0,0, // bras/cuisses/-
+ 0,-10,0, 0,0,-10, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // mains/pieds/-
+ };
+
+ int member_fly[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3,
+ -5,90,-60, 20,5,-25, 0,0,0, // bras/cuisses/-
+ 85,-40,-25, 10,0,-30, 0,0,0, // avant-bras/jambes/-
+ 40,10,25, 0,15,0, 0,0,0, // mains/pieds/-
+ //
+ -15,90,-40, 20,5,-35, 0,0,0, // bras/cuisses/-
+ 85,-40,-25, 10,0,-40, 0,0,0, // avant-bras/jambes/-
+ 45,5,20, 0,15,0, 0,0,0, // mains/pieds/-
+ //
+ -25,90,-50, 20,5,-20, 0,0,0, // bras/cuisses/-
+ 85,-40,-25, 10,0,-10, 0,0,0, // avant-bras/jambes/-
+ 30,15,25, 0,15,0, 0,0,0, // mains/pieds/-
+ };
+
+ int member_swim[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3,
+#if 1
+ 130,-70,200,10,20,55, 0,0,0, // bras/cuisses/-
+ 115,-125,0, -5,0,-110, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,10,-5, 0,0,0, // mains/pieds/-
+ //
+ 130,-95,115,55,5,5, 0,0,0, // bras/cuisses/-
+ 75,-50,25, -5,0,-15, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,5,-30, 0,0,0, // mains/pieds/-
+ //
+ 130,-100,220,5,0,0, 0,0,0, // bras/cuisses/-
+ 150,5,0, -5,0,-15, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,30,-20, 0,0,0, // mains/pieds/-
+#endif
+#if 0
+ 130,-70,200,5,0,0, 0,0,0, // bras/cuisses/-
+ 115,-125,0, -5,0,-15, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,30,-20, 0,0,0, // mains/pieds/-
+ //
+ 130,-95,115,10,20,55, 0,0,0, // bras/cuisses/-
+ 75,-50,25, -5,0,-110, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,10,-5, 0,0,0, // mains/pieds/-
+ //
+ 130,-100,220,55,5,5, 0,0,0, // bras/cuisses/-
+ 150,5,0, -5,0,-15, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,5,-30, 0,0,0, // mains/pieds/-
+#endif
+#if 0
+ 130,-70,200,55,5,5, 0,0,0, // bras/cuisses/-
+ 115,-125,0, -5,0,-15, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,5,-30, 0,0,0, // mains/pieds/-
+ //
+ 130,-95,115,5,0,0, 0,0,0, // bras/cuisses/-
+ 75,-50,25, -5,0,-15, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,30,-20, 0,0,0, // mains/pieds/-
+ //
+ 130,-100,220,10,20,55, 0,0,0, // bras/cuisses/-
+ 150,5,0, -5,0,-110, 0,0,0, // avant-bras/jambes/-
+ 0,0,0, -5,10,-5, 0,0,0, // mains/pieds/-
+#endif
+ };
+
+ int member_spec[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // tir :
+ 65,5,-20, 10,0,40, 0,0,0, // s0: bras/cuisses/-
+ -50,-30,50, 0,0,-70, 0,0,0, // s0: avant-bras/jambes/-
+ 0,50,0, -10,0,35, 0,0,0, // s0: mains/pieds/-
+ // prend arme :
+ 160,135,-20,10,0,5, 0,0,0, // s1: bras/cuisses/-
+ 10,-60,40, 0,0,-10, 0,0,0, // s1: avant-bras/jambes/-
+ 0,-5,-25, -10,5,5, 0,0,0, // s1: mains/pieds/-
+ // porte à terre :
+ 25,40,-40, 10,0,60, 0,0,0, // s2: bras/cuisses/-
+ 0,-45,0, 0,0,-120, 0,0,0, // s2: avant-bras/jambes/-
+ 0,15,5, -10,0,70, 0,0,0, // s2: mains/pieds/-
+ // porte devant :
+ 25,20,5, 10,0,55, 0,0,0, // s3: bras/cuisses/-
+ -15,-30,10, 0,0,-110, 0,0,0, // s3: avant-bras/jambes/-
+ 0,0,0, -10,0,65, 0,0,0, // s3: mains/pieds/-
+ // porte en hauteur :
+ -30,15,-5, 10,0,15, 0,0,0, // s4: bras/cuisses/-
+ 0,-15,15, 0,0,-30, 0,0,0, // s4: avant-bras/jambes/-
+ 35,0,-15, -10,0,25, 0,0,0, // s4: mains/pieds/-
+ // se relève :
+ 15,50,-50, 10,0,5, 0,0,0, // s5: bras/cuisses/-
+ 45,-70,10, 0,0,-10, 0,0,0, // s5: avant-bras/jambes/-
+ -10,25,0, -10,5,5, 0,0,0, // s5: mains/pieds/-
+ // gagné :
+ 90,90,-30, 20,0,5, 0,0,0, // s6: bras/cuisses/-
+ 0,-90,0, -10,0,-10, 0,0,0, // s6: avant-bras/jambes/-
+ 0,25,0, -10,5,5, 0,0,0, // s6: mains/pieds/-
+ // perdu :
+ -70,45,35, 10,0,40, 0,0,0, // s7: bras/cuisses/-
+ 15,-95,-5, 0,0,-70, 0,0,0, // s7: avant-bras/jambes/-
+ 0,0,0, -10,0,35, 0,0,0, // s7: mains/pieds/-
+ // mort par balle (tombe) :
+ 90,90,-50, 10,0,5, 0,0,0, // s8: bras/cuisses/-
+ 0,-20,0, 0,0,-10, 0,0,0, // s8: avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // s8: mains/pieds/-
+ // mort par balle (genoux) :
+ 110,105,-5, 10,0,25, 0,0,0, // s9: bras/cuisses/-
+ 0,-40,20, 0,0,-120, 0,0,0, // s9: avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // s9: mains/pieds/-
+ // mort par balle (genoux) :
+ 110,120,-25,10,0,25, 0,0,0, // s10: bras/cuisses/-
+ 0,-40,20, 0,0,-120, 0,0,0, // s10: avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // s10: mains/pieds/-
+ // mort par balle (plat ventre) :
+ 110,100,-25,25,0,10, 0,0,0, // s11: bras/cuisses/-
+ 0,-40,20, 0,0,-25, 0,0,0, // s11: avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // s11: mains/pieds/-
+ // mort par balle (plat ventre) :
+ 110,100,-25,25,0,10, 0,0,0, // s12: bras/cuisses/-
+ 0,-40,20, 0,0,-25, 0,0,0, // s12: avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // s12: mains/pieds/-
+ // mort noyé :
+ 110,100,-25,25,0,10, 0,0,0, // s13: bras/cuisses/-
+ 0,-40,20, 0,0,-25, 0,0,0, // s13: avant-bras/jambes/-
+ 0,0,0, -10,5,5, 0,0,0, // s13: mains/pieds/-
+ // met/enlève drapeau :
+ 85,45,-50, 10,0,60, 0,0,0, // s14: bras/cuisses/-
+ -60,15,65, 0,0,-105, 0,0,0, // s14: avant-bras/jambes/-
+ 0,10,0, -10,0,60, 0,0,0, // s14: mains/pieds/-
+ // lit SatCom :
+ 70,30,-20, 10,0,5, 0,0,0, // s15: bras/cuisses/-
+ 115,-65,60, 0,0,-10, 0,0,0, // s15: avant-bras/jambes/-
+ 0,20,0, -10,5,5, 0,0,0, // s15: mains/pieds/-
+ };
+
+ m_physics->SetType(TYPE_FLYING);
+
+ character = m_object->RetCharacter();
+ character->wheelFront = 4.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 4.0f;
+ character->wheelRight = 4.0f;
+ character->height = 3.5f;
+
+ if ( type == OBJECT_HUMAN )
+ {
+ m_physics->SetLinMotionX(MO_ADVSPEED, 50.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 35.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 70.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 40.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+ m_physics->SetLinMotionY(MO_ADVSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_RECSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionY(MO_RECACCEL, 50.0f);
+ m_physics->SetLinMotionY(MO_STOACCEL, 50.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.8f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.8f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 6.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 6.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 4.0f);
+ }
+ else
+ {
+ m_physics->SetLinMotionX(MO_ADVSPEED, 40.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 15.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 8.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 8.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 8.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 50.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 50.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+ m_physics->SetLinMotionY(MO_ADVSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_RECSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionY(MO_RECACCEL, 50.0f);
+ m_physics->SetLinMotionY(MO_STOACCEL, 50.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.6f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.6f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 4.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 4.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 3.0f);
+ }
+
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_MARCH+i] = member_march[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_MARCHTAKE+i] = member_march_take[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_TURN+i] = member_turn[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_STOP+i] = member_stop[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_FLY+i] = member_fly[i];
+ }
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_SWIM+i] = member_swim[i];
+ }
+ for ( i=0 ; i<3*3*3*16 ; i++ )
+ {
+ m_armAngles[3*3*3*3*MH_SPEC+i] = member_spec[i];
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionHuman::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if ADJUST_ANGLE
+ int i;
+
+ if ( event.param == 'A' ) m_armTimeIndex++;
+ if ( m_armTimeIndex >= 3 ) m_armTimeIndex = 0;
+
+ if ( event.param == 'Q' ) m_armPartIndex++;
+ if ( m_armPartIndex >= 3 ) m_armPartIndex = 0;
+
+ if ( event.param == 'W' ) m_armMemberIndex++;
+ if ( m_armMemberIndex >= 3 ) m_armMemberIndex = 0;
+
+ i = m_armMemberIndex*3;
+ i += m_armPartIndex*3*3;
+ i += m_armTimeIndex*3*3*3;
+ i += ADJUST_ACTION;
+
+ if ( event.param == 'E' ) m_armAngles[i+0] += 5;
+ if ( event.param == 'D' ) m_armAngles[i+0] -= 5;
+ if ( event.param == 'R' ) m_armAngles[i+1] += 5;
+ if ( event.param == 'F' ) m_armAngles[i+1] -= 5;
+ if ( event.param == 'T' ) m_armAngles[i+2] += 5;
+ if ( event.param == 'G' ) m_armAngles[i+2] -= 5;
+
+ if ( event.param == 'Y' ) m_bArmStop = !m_bArmStop;
+
+ if ( event.param == 'Y' )
+ {
+ char s[100];
+ sprintf(s, "index dans table = %d %d %d\n", i, i+9, i+18);
+ OutputDebugString(s);
+ }
+#endif
+ }
+
+ return TRUE;
+}
+
+// Calcule une valeur (radians) proportionnelle comprise
+// entre a et b (degrés).
+
+inline float Propf(float a, float b, float p)
+{
+ float aa, bb;
+
+ aa = a*PI/180.0f;
+ bb = b*PI/180.0f;
+
+ return aa+p*(bb-aa);
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionHuman::EventFrame(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR dir, actual, pos, speed, pf;
+ FPOINT center, dim, p2;
+ float s, a, prog, rTime[2], lTime[2], time, rot, hr, hl;
+ float al, ar, af;
+ float tSt[9], tNd[9];
+ float aa, bb, shield, deadFactor, level;
+ int i, ii, st, nd, action, legAction, armAction;
+ BOOL bOnBoard, bSwim, bStop;
+
+ if ( m_engine->RetPause() )
+ {
+ if ( m_actionType == MHS_SATCOM )
+ {
+ m_progress += event.rTime*m_actionTime;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
+ bOnBoard = FALSE;
+ if ( m_object->RetSelect() &&
+ m_camera->RetType() == CAMERA_ONBOARD )
+ {
+ bOnBoard = TRUE;
+ }
+
+ if ( m_bDisplayPerso && m_main->RetGamerOnlyHead() )
+ {
+ m_time += event.rTime;
+ m_object->SetLinVibration(D3DVECTOR(0.0f, -0.55f, 0.0f));
+ m_object->SetCirVibration(D3DVECTOR(0.0f, m_main->RetPersoAngle(), 0.0f));
+ return TRUE;
+ }
+ if ( m_bDisplayPerso )
+ {
+ m_object->SetCirVibration(D3DVECTOR(0.0f, m_main->RetPersoAngle()+0.2f, 0.0f));
+ }
+
+ shield = m_object->RetShield();
+ shield += event.rTime*(1.0f/120.0f); // régénération en 120 secondes
+ if ( shield > 1.0f ) shield = 1.0f;
+ m_object->SetShield(shield);
+
+ bSwim = m_physics->RetSwim();
+
+#if 0
+ rot = m_physics->RetCirMotionY(MO_MOTSPEED);
+ s = m_physics->RetLinMotionX(MO_REASPEED)*2.0f;
+ a = m_physics->RetLinMotionX(MO_TERSPEED);
+ if ( a < 0.0f ) // monte ?
+ {
+ if ( s > 0.0f && s < 20.0f ) s = 20.0f; // avance lentement ?
+//? if ( s < 0.0f && s > -10.0f ) s = 0.0f; // recule lentement ?
+ }
+ if ( a > 0.0f && !bSwim ) // descend ?
+ {
+ if ( s > 0.0f && s < 10.0f ) s = 0.0f; // avance lentement ?
+//? if ( s < 0.0f && s > -5.0f ) s = -5.0f; // recule lentement ?
+ }
+ a = Abs(rot*12.0f);
+
+ if ( !m_physics->RetLand() && !bSwim ) // en vol ?
+ {
+ s = 0.0f;
+ }
+
+ if ( m_object->RetFret() != 0 ) // porte qq chose ?
+ {
+ s *= 1.3f;
+ }
+#else
+ rot = m_physics->RetCirMotionY(MO_MOTSPEED);
+#if 0
+ s = m_physics->RetLinMotionX(MO_REASPEED);
+#else
+ a = m_physics->RetLinMotionX(MO_REASPEED);
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*0.2f;
+ if ( Abs(a) > Abs(s) ) s = a; // la plus grande valeur
+#endif
+ a = m_physics->RetLinMotionX(MO_TERSPEED);
+ if ( a < 0.0f ) // monte ?
+ {
+ a += m_physics->RetLinMotionX(MO_TERSLIDE);
+ if ( a < 0.0f ) s -= a;
+ }
+ if ( a > 0.0f ) // descend ?
+ {
+ a -= m_physics->RetLinMotionX(MO_TERSLIDE);
+ if ( a > 0.0f ) s -= a;
+ }
+ s *= 2.0f;
+ a = Abs(rot*12.0f);
+
+ if ( !m_physics->RetLand() && !bSwim ) // en vol ?
+ {
+ s = 0.0f;
+ }
+
+ if ( m_object->RetFret() != 0 ) // porte qq chose ?
+ {
+ s *= 1.3f;
+ }
+#endif
+
+ m_time += event.rTime;
+ m_armTimeAbs += event.rTime;
+ m_armTimeAction += event.rTime;
+ m_armMember += s*event.rTime*0.05f;
+
+ // Gestion de la fatigue lorsqu'on court.
+ if ( m_physics->RetLand() && s != 0.0f ) // au sol ?
+ {
+ m_tired += event.rTime*0.1f;
+ if ( m_tired > 1.0f )
+ {
+ m_tired = 1.0f;
+ if ( m_lastSoundHhh > 3.0f ) m_lastSoundHhh = 0.5f;
+ }
+ }
+ else
+ {
+ m_tired -= event.rTime*0.2f;
+ if ( m_tired < 0.0f ) m_tired = 0.0f;
+ }
+
+ if ( bSwim ) // nage ?
+ {
+ s += Abs(m_physics->RetLinMotionY(MO_REASPEED)*2.0f);
+ a *= 2.0f;
+ m_armTimeSwim += Min(Max(s,a,3.0f),15.0f)*event.rTime*0.05f;
+ }
+
+ bStop = ( s == 0.0f ); // à l'arrêt ?
+ prog = 0.0f;
+
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ if ( s == 0.0f && a == 0.0f )
+ {
+ action = MH_STOP; // stop
+ rTime[0] = rTime[1] = m_armTimeAbs*0.21f;
+ lTime[0] = lTime[1] = m_armTimeAbs*0.25f;
+ m_armMember = START_TIME;
+ }
+ else
+ {
+ if ( s == 0.0f )
+ {
+ action = MH_TURN; // turn
+ rTime[0] = rTime[1] = m_armTimeAbs;
+ lTime[0] = lTime[1] = m_armTimeAbs+0.5f;
+ if ( rot < 0.0f )
+ {
+ rTime[1] = 1000000.0f-rTime[1];
+ }
+ else
+ {
+ lTime[1] = 1000000.0f-lTime[1];
+ }
+ m_armMember = START_TIME;
+ }
+ else
+ {
+ action = MH_MARCH; // march
+ if ( m_object->RetFret() != 0 ) action = MH_MARCHTAKE; // march-take
+ rTime[0] = rTime[1] = m_armMember;
+ lTime[0] = lTime[1] = m_armMember+0.5f;
+ }
+ }
+ if ( bSwim )
+ {
+ rTime[0] *= 0.6f;
+ rTime[1] *= 0.6f;
+ lTime[0] = rTime[0]+0.5f;
+ lTime[1] = rTime[1]+0.5f;
+ }
+ }
+ else
+ {
+ if ( bSwim )
+ {
+ action = MH_SWIM; // nage
+ rTime[0] = rTime[1] = m_armTimeSwim;
+ lTime[0] = lTime[1] = m_armTimeSwim;
+ }
+ else
+ {
+ action = MH_FLY; // fly
+ rTime[0] = rTime[1] = m_armTimeAbs*0.30f;
+ lTime[0] = lTime[1] = m_armTimeAbs*0.31f;
+ m_armMember = START_TIME;
+ }
+ }
+
+ if ( action != m_armLastAction )
+ {
+ m_armLastAction = action;
+ m_armTimeAction = 0.0f;
+ }
+
+ armAction = action;
+ legAction = action;
+
+ if ( m_object->RetFret() != 0 ) // porte qq chose ?
+ {
+ armAction = MH_MARCHTAKE; // march-take
+ }
+
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ a = m_object->RetAngleY(0);
+ pos = m_object->RetPosition(0);
+ m_terrain->MoveOnFloor(pos);
+
+ pf.x = pos.x+cosf(a+PI*1.5f)*0.7f;
+ pf.y = pos.y;
+ pf.z = pos.z-sinf(a+PI*1.5f)*0.7f;
+ m_terrain->MoveOnFloor(pf);
+ al = atanf((pf.y-pos.y)/0.7f); // angle pour jambe gauche
+
+ pf = pos;
+ pf.x = pos.x+cosf(a+PI*0.5f)*0.7f;
+ pf.y = pos.y;
+ pf.z = pos.z-sinf(a+PI*0.5f)*0.7f;
+ m_terrain->MoveOnFloor(pf);
+ ar = atanf((pf.y-pos.y)/0.7f); // angle pour jambe droite
+
+ pf.x = pos.x+cosf(a+PI)*0.3f;
+ pf.y = pos.y;
+ pf.z = pos.z-sinf(a+PI)*0.3f;
+ m_terrain->MoveOnFloor(pf);
+ af = atanf((pf.y-pos.y)/0.3f); // angle pour pieds
+ }
+ else
+ {
+ al = 0.0f;
+ ar = 0.0f;
+ af = 0.0f;
+ }
+
+ for ( i=0 ; i<4 ; i++ ) // les 4 membres
+ {
+ if ( m_bArmStop ) // mise au point ?
+ {
+ st = ADJUST_ACTION + (i%2)*3;
+ nd = st;
+ time = 100.0f;
+ m_armTimeAction = 0.0f;
+ }
+ else if ( m_actionType != -1 ) // action spéciale en cours ?
+ {
+ st = 3*3*3*3*MH_SPEC + 3*3*3*m_actionType + (i%2)*3;
+ nd = st;
+ time = event.rTime*m_actionTime;
+ m_armTimeAction = 0.0f;
+ }
+ else
+ {
+ if ( i < 2 ) prog = Mod(rTime[i%2], 1.0f);
+ else prog = Mod(lTime[i%2], 1.0f);
+ if ( prog < 0.25f ) // t0..t1 ?
+ {
+ prog = prog/0.25f; // 0..1
+ st = 0; // index start
+ nd = 1; // index end
+ }
+ else if ( prog < 0.75f ) // t1..t2 ?
+ {
+ prog = (prog-0.25f)/0.50f; // 0..1
+ st = 1; // index start
+ nd = 2; // index end
+ }
+ else // t2..t0 ?
+ {
+ prog = (prog-0.75f)/0.25f; // 0..1
+ st = 2; // index start
+ nd = 0; // index end
+ }
+ if ( i%2 == 0 ) // bras ?
+ {
+ st = 3*3*3*3*armAction + st*3*3*3 + (i%2)*3;
+ nd = 3*3*3*3*armAction + nd*3*3*3 + (i%2)*3;
+ }
+ else // jambe ?
+ {
+ st = 3*3*3*3*legAction + st*3*3*3 + (i%2)*3;
+ nd = 3*3*3*3*legAction + nd*3*3*3 + (i%2)*3;
+ }
+
+ // De moins en moins mou ...
+ time = event.rTime*(5.0f+Min(m_armTimeAction*50.0f, 100.0f));
+ if ( bSwim ) time *= 0.25f;
+ }
+
+ tSt[0] = m_armAngles[st+ 0]; // x
+ tSt[1] = m_armAngles[st+ 1]; // y
+ tSt[2] = m_armAngles[st+ 2]; // z
+ tSt[3] = m_armAngles[st+ 9]; // x
+ tSt[4] = m_armAngles[st+10]; // y
+ tSt[5] = m_armAngles[st+11]; // z
+ tSt[6] = m_armAngles[st+18]; // x
+ tSt[7] = m_armAngles[st+19]; // y
+ tSt[8] = m_armAngles[st+20]; // z
+
+ tNd[0] = m_armAngles[nd+ 0]; // x
+ tNd[1] = m_armAngles[nd+ 1]; // y
+ tNd[2] = m_armAngles[nd+ 2]; // z
+ tNd[3] = m_armAngles[nd+ 9]; // x
+ tNd[4] = m_armAngles[nd+10]; // y
+ tNd[5] = m_armAngles[nd+11]; // z
+ tNd[6] = m_armAngles[nd+18]; // x
+ tNd[7] = m_armAngles[nd+19]; // y
+ tNd[8] = m_armAngles[nd+20]; // z
+
+ aa = 0.5f;
+ if ( i%2 == 0 ) // bras ?
+ {
+ if ( m_object->RetFret() == 0 ) // ne porte rien ?
+ {
+ aa = 2.0f; // bouge beaucoup
+ }
+ else
+ {
+ aa = 0.0f; // immobile
+ }
+ }
+
+ if ( i < 2 ) // gauche ?
+ {
+ bb = sinf(m_time*1.1f)*aa; tSt[0] += bb; tNd[0] += bb;
+ bb = sinf(m_time*1.0f)*aa; tSt[1] += bb; tNd[1] += bb;
+ bb = sinf(m_time*1.2f)*aa; tSt[2] += bb; tNd[2] += bb;
+ bb = sinf(m_time*2.5f)*aa; tSt[3] += bb; tNd[3] += bb;
+ bb = sinf(m_time*2.0f)*aa; tSt[4] += bb; tNd[4] += bb;
+ bb = sinf(m_time*3.8f)*aa; tSt[5] += bb; tNd[5] += bb;
+ bb = sinf(m_time*3.0f)*aa; tSt[6] += bb; tNd[6] += bb;
+ bb = sinf(m_time*2.3f)*aa; tSt[7] += bb; tNd[7] += bb;
+ bb = sinf(m_time*4.0f)*aa; tSt[8] += bb; tNd[8] += bb;
+ }
+ else // droite ?
+ {
+ bb = sinf(m_time*0.9f)*aa; tSt[0] += bb; tNd[0] += bb;
+ bb = sinf(m_time*1.2f)*aa; tSt[1] += bb; tNd[1] += bb;
+ bb = sinf(m_time*1.4f)*aa; tSt[2] += bb; tNd[2] += bb;
+ bb = sinf(m_time*2.9f)*aa; tSt[3] += bb; tNd[3] += bb;
+ bb = sinf(m_time*1.4f)*aa; tSt[4] += bb; tNd[4] += bb;
+ bb = sinf(m_time*3.1f)*aa; tSt[5] += bb; tNd[5] += bb;
+ bb = sinf(m_time*3.7f)*aa; tSt[6] += bb; tNd[6] += bb;
+ bb = sinf(m_time*2.0f)*aa; tSt[7] += bb; tNd[7] += bb;
+ bb = sinf(m_time*3.1f)*aa; tSt[8] += bb; tNd[8] += bb;
+ }
+
+#if 1
+ if ( i%2 == 1 && // jambe ?
+ m_actionType == -1 ) // pas action spéciale ?
+ {
+ if ( i == 1 ) // jambe droite ?
+ {
+ ii = 5;
+ a = ar*0.25f;
+ }
+ else
+ {
+ ii = 11;
+ a = al*0.25f;
+ }
+ if ( a < -0.2f ) a = -0.2f;
+ if ( a > 0.2f ) a = 0.2f;
+
+ pos = m_object->RetPosition(ii+0);
+ pos.y = 0.0f+a;
+ m_object->SetPosition(ii+0, pos); // allonge/raccourci cuisse
+
+ pos = m_object->RetPosition(ii+1);
+ pos.y = -1.5f+a;
+ m_object->SetPosition(ii+1, pos); // allonge/raccourci jambe
+
+ pos = m_object->RetPosition(ii+2);
+ pos.y = -1.5f+a;
+ m_object->SetPosition(ii+2, pos); // allonge/raccourci pied
+
+ if ( i == 1 ) // jambe droite ?
+ {
+ aa = (ar*180.0f/PI*0.5f);
+ }
+ else // jambe gauche ?
+ {
+ aa = (al*180.0f/PI*0.5f);
+ }
+ tSt[6] += aa;
+ tNd[6] += aa; // augmente l'angle X du pied
+
+ if ( i == 1 ) // jambe droite ?
+ {
+ aa = (ar*180.0f/PI);
+ }
+ else // jambe gauche ?
+ {
+ aa = (al*180.0f/PI);
+ }
+ if ( aa < 0.0f ) aa = 0.0f;
+ if ( aa > 30.0f ) aa = 30.0f;
+
+ tSt[2] += aa;
+ tNd[2] += aa; // augmente l'angle Z de la cuisse
+ tSt[5] -= aa*2;
+ tNd[5] -= aa*2; // augmente l'angle Z de la jambe
+ tSt[8] += aa;
+ tNd[8] += aa; // augmente l'angle Z du pied
+
+ aa = (af*180.0f/PI)*0.7f;
+ if ( aa < -30.0f ) aa = -30.0f;
+ if ( aa > 30.0f ) aa = 30.0f;
+
+ tSt[8] -= aa;
+ tNd[8] -= aa; // augmente l'angle Z du pied
+ }
+#endif
+
+ if ( m_actionType == MHS_DEADw ) // mort noyé ?
+ {
+ if ( m_progress < 0.5f )
+ {
+ deadFactor = m_progress/0.5f;
+ }
+ else
+ {
+ deadFactor = 1.0f-(m_progress-0.5f)/0.5f;
+ }
+ if ( deadFactor < 0.0f ) deadFactor = 0.0f;
+ if ( deadFactor > 1.0f ) deadFactor = 1.0f;
+
+ for ( ii=0 ; ii<9 ; ii++ )
+ {
+ tSt[ii] += Rand()*20.0f*deadFactor;
+ tNd[ii] = tSt[ii];
+ }
+ time = 100.0f;
+ }
+
+ if ( i < 2 ) // membre droite (0..1) ?
+ {
+ m_object->SetAngleX(2+3*i+0, Smooth(m_object->RetAngleX(2+3*i+0), Propf(tSt[0], tNd[0], prog), time));
+ m_object->SetAngleY(2+3*i+0, Smooth(m_object->RetAngleY(2+3*i+0), Propf(tSt[1], tNd[1], prog), time));
+ m_object->SetAngleZ(2+3*i+0, Smooth(m_object->RetAngleZ(2+3*i+0), Propf(tSt[2], tNd[2], prog), time));
+ m_object->SetAngleX(2+3*i+1, Smooth(m_object->RetAngleX(2+3*i+1), Propf(tSt[3], tNd[3], prog), time));
+ m_object->SetAngleY(2+3*i+1, Smooth(m_object->RetAngleY(2+3*i+1), Propf(tSt[4], tNd[4], prog), time));
+ m_object->SetAngleZ(2+3*i+1, Smooth(m_object->RetAngleZ(2+3*i+1), Propf(tSt[5], tNd[5], prog), time));
+ m_object->SetAngleX(2+3*i+2, Smooth(m_object->RetAngleX(2+3*i+2), Propf(tSt[6], tNd[6], prog), time));
+ m_object->SetAngleY(2+3*i+2, Smooth(m_object->RetAngleY(2+3*i+2), Propf(tSt[7], tNd[7], prog), time));
+ m_object->SetAngleZ(2+3*i+2, Smooth(m_object->RetAngleZ(2+3*i+2), Propf(tSt[8], tNd[8], prog), time));
+ }
+ else // membre gauche (2..3) ?
+ {
+ m_object->SetAngleX(2+3*i+0, Smooth(m_object->RetAngleX(2+3*i+0), Propf(-tSt[0], -tNd[0], prog), time));
+ m_object->SetAngleY(2+3*i+0, Smooth(m_object->RetAngleY(2+3*i+0), Propf(-tSt[1], -tNd[1], prog), time));
+ m_object->SetAngleZ(2+3*i+0, Smooth(m_object->RetAngleZ(2+3*i+0), Propf( tSt[2], tNd[2], prog), time));
+ m_object->SetAngleX(2+3*i+1, Smooth(m_object->RetAngleX(2+3*i+1), Propf(-tSt[3], -tNd[3], prog), time));
+ m_object->SetAngleY(2+3*i+1, Smooth(m_object->RetAngleY(2+3*i+1), Propf(-tSt[4], -tNd[4], prog), time));
+ m_object->SetAngleZ(2+3*i+1, Smooth(m_object->RetAngleZ(2+3*i+1), Propf( tSt[5], tNd[5], prog), time));
+ m_object->SetAngleX(2+3*i+2, Smooth(m_object->RetAngleX(2+3*i+2), Propf(-tSt[6], -tNd[6], prog), time));
+ m_object->SetAngleY(2+3*i+2, Smooth(m_object->RetAngleY(2+3*i+2), Propf(-tSt[7], -tNd[7], prog), time));
+ m_object->SetAngleZ(2+3*i+2, Smooth(m_object->RetAngleZ(2+3*i+2), Propf( tSt[8], tNd[8], prog), time));
+ }
+ }
+
+#if ADJUST_ANGLE
+ if ( m_object->RetSelect() )
+ {
+ char s[100];
+ sprintf(s, "A:time=%d Q:part=%d W:member=%d", m_armTimeIndex, m_armPartIndex, m_armMemberIndex);
+ m_engine->SetInfoText(4, s);
+ }
+#endif
+
+ // Calcule la hauteur de rabaissement en fonction de la
+ // position des jambes.
+ hr = 1.5f*(1.0f-cosf(m_object->RetAngleZ(5))) +
+ 1.5f*(1.0f-cosf(m_object->RetAngleZ(5)+m_object->RetAngleZ(6)));
+ a = 1.0f*sinf(m_object->RetAngleZ(5)+m_object->RetAngleZ(6)+m_object->RetAngleZ(7));
+ if ( a < 0.0f ) hr += a;
+
+ hl = 1.5f*(1.0f-cosf(m_object->RetAngleZ(11))) +
+ 1.5f*(1.0f-cosf(m_object->RetAngleZ(11)+m_object->RetAngleZ(12)));
+ a = 1.0f*sinf(m_object->RetAngleZ(11)+m_object->RetAngleZ(12)+m_object->RetAngleZ(13));
+ if ( a < 0.0f ) hl += a;
+
+ hr = Min(hr, hl);
+
+ if ( m_actionType == MHS_FIRE ) // tir ?
+ {
+ time = event.rTime*m_actionTime;
+
+ dir.x = (Rand()-0.5f)/8.0f;
+ dir.z = (Rand()-0.5f)/8.0f;
+ dir.y = -0.5f; // légèrement plus bas
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+//? dir.y = Smooth(actual.y, dir.y, time);
+ dir.y = -hr;
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.y = (Rand()-0.5f)/3.0f;
+ dir.z = -0.1f; // légèrement penché en avant
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_TAKE || // prend ?
+ m_actionType == MHS_TAKEOTHER ) // drapeau ?
+ {
+ time = event.rTime*m_actionTime*2.0f;
+
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ dir.y = -1.5f; // légèrement plus bas
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+//? dir.y = Smooth(actual.y, dir.y, time);
+ dir.y = -hr;
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = -0.2f;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_TAKEHIGH ) // prend ?
+ {
+ time = event.rTime*m_actionTime*2.0f;
+
+ dir.x = 0.4f; // avance légèrement
+ dir.z = 0.0f;
+ dir.y = 0.0f;
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+//? dir.y = Smooth(actual.y, dir.y, time);
+ dir.y = -hr;
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = -0.2f;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_FLAG ) // drapeau ?
+ {
+ time = event.rTime*m_actionTime*2.0f;
+
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ dir.y = -2.0f; // légèrement plus bas
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+//? dir.y = Smooth(actual.y, dir.y, time);
+ dir.y = -hr;
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = -0.4f;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_DEADg ) // mort par balle (tombe) ?
+ {
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ SetAction(MHS_DEADg1, 0.5f); // genoux
+ }
+ }
+ else if ( m_actionType == MHS_DEADg1 ) // mort par balle (genoux) ?
+ {
+ prog = m_progress;
+ if ( prog >= 1.0f )
+ {
+ prog = 1.0f;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ m_terrain->MoveOnFloor(pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 1.2f+Rand()*1.2f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.0f);
+ }
+ m_sound->Play(SOUND_BOUMv, m_object->RetPosition(0));
+
+ SetAction(MHS_DEADg2, 1.0f); // attente genoux
+ }
+
+ time = 100.0f;
+
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ dir.y = -1.5f*prog;
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = -(20.0f*PI/180.0f)*prog;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_DEADg2 ) // mort par balle (genoux) ?
+ {
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(MHS_DEADg3, 1.0f); // plat ventre
+ }
+
+ time = 100.0f;
+
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ dir.y = -1.5f;
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = -(20.0f*PI/180.0f);
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_DEADg3 ) // mort par balle (plat ventre) ?
+ {
+ prog = m_progress;
+ if ( prog >= 1.0f )
+ {
+ prog = 1.0f;
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*8.0f;
+ pos.z += (Rand()-0.5f)*8.0f;
+ m_terrain->MoveOnFloor(pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f+Rand()*1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.0f);
+ }
+ m_sound->Play(SOUND_BOUMv, m_object->RetPosition(0));
+
+ SetAction(MHS_DEADg4, 3.0f); // attente plat ventre
+ }
+
+ time = 100.0f;
+ prog = powf(prog, 3.0f);
+
+ dir.y = -(1.5f+1.5f*prog);
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.z = -((20.0f*PI/180.0f)+(70.0f*PI/180.0f)*prog);
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_DEADg4 ) // mort par balle (plat ventre) ?
+ {
+ if ( m_progress >= 1.0f )
+ {
+ m_object->SetEnable(FALSE);
+ }
+
+ time = 100.0f;
+
+ dir.y = -(1.5f+1.5f);
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetLinVibration(dir);
+
+ dir.z = -((20.0f*PI/180.0f)+(70.0f*PI/180.0f));
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+ }
+ else if ( m_actionType == MHS_DEADw ) // mort noyé ?
+ {
+ pos = m_object->RetPosition(0);
+ level = m_water->RetLevel()-0.5f;
+ if ( pos.y < level )
+ {
+ pos.y += 4.0f*event.rTime; // remonte à la surface
+ if ( pos.y > level ) pos.y = level;
+ m_object->SetPosition(0, pos);
+ }
+ if ( pos.y > level )
+ {
+ pos.y -= 10.0f*event.rTime; // descend vite
+ if ( pos.y < level ) pos.y = level;
+ m_object->SetPosition(0, pos);
+ }
+
+ prog = m_progress;
+ if ( prog >= 1.0f )
+ {
+ prog = 1.0f;
+ if ( pos.y >= level ) m_object->SetEnable(FALSE);
+ }
+
+ prog *= 2.0f;
+ if ( prog > 1.0f ) prog = 1.0f;
+
+ time = 100.0f;
+
+ dir.z = -(90.0f*PI/180.0f)*prog;
+ dir.x = Rand()*0.3f*deadFactor;
+ dir.y = Rand()*0.3f*deadFactor;
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ m_object->SetInclinaison(dir);
+
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ }
+ else if ( m_actionType == MHS_LOST ) // perdu ?
+ {
+ time = m_time;
+ if ( time < 10.0f ) time *= time/10.0f; // démarre lentement
+
+ dir.x = time*2.0f;
+ dir.y = sinf(m_time*0.8f)*0.8f;
+ dir.z = sinf(m_time*0.6f)*0.5f;
+ m_object->SetInclinaison(dir);
+ SetInclinaison(dir);
+
+//? dir.x = -(sinf(time*0.05f+PI*1.5f)+1.0f)*100.0f;
+ dir.x = -(powf(Min(time/30.0f), 4.0f))*1000.0f; // part au loin
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ m_object->SetLinVibration(dir);
+ SetLinVibration(dir);
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(0.5f, 3.7f, 0.0f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.y += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = (Rand()-0.5f)*0.5f;
+ speed.y = (Rand()-0.5f)*0.5f;
+ speed.z = (Rand()-0.5f)*0.5f;
+ dim.x = 0.5f+Rand()*0.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTILENS1, 5.0f, 0.0f, 0.0f);
+ }
+ else if ( m_actionType == MHS_SATCOM ) // regarde le SatCom ?
+ {
+ SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ SetLinVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ }
+ else
+ {
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ time = event.rTime*8.0f;
+ if ( bSwim ) time *= 0.25f;
+
+ if ( action == MH_MARCH ) // march ?
+ {
+ dir.x = sinf(Mod(rTime[0]+0.5f, 1.0f)*PI*2.0f)*0.10f;
+ dir.y = sinf(Mod(rTime[0]+0.6f, 1.0f)*PI*2.0f)*0.20f;
+ s = m_physics->RetLinMotionX(MO_REASPEED)*0.03f;
+ }
+ else if ( action == MH_MARCHTAKE ) // march-take ?
+ {
+ dir.x = sinf(Mod(rTime[0]+0.5f, 1.0f)*PI*2.0f)*0.10f;
+ dir.y = sinf(Mod(rTime[0]+0.6f, 1.0f)*PI*2.0f)*0.15f;
+ s = m_physics->RetLinMotionX(MO_REASPEED)*0.02f;
+ }
+ else
+ {
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ s = m_physics->RetLinMotionX(MO_REASPEED)*0.03f;
+ }
+
+ if ( s < 0.0f ) s *= 0.5f;
+ dir.z = -s*0.7f;
+
+ actual = m_object->RetInclinaison();
+ dir.x = Smooth(actual.x, dir.x, time);
+ dir.y = Smooth(actual.y, dir.y, time);
+ dir.z = Smooth(actual.z, dir.z, time);
+ if ( bOnBoard ) dir *= 0.3f;
+ m_object->SetInclinaison(dir);
+ SetInclinaison(dir);
+
+ if ( action == MH_MARCH ) // march ?
+ {
+ p2.x = 0.0f;
+ p2.y = sinf(Mod(rTime[0]+0.5f, 1.0f)*PI*2.0f)*0.5f;
+ p2 = RotatePoint(-m_object->RetAngleY(0), p2);
+ dir.x = p2.x;
+ dir.z = p2.y;
+ dir.y = sinf(Mod(rTime[0]*2.0f, 1.0f)*PI*2.0f)*0.3f;
+ }
+ else if ( action == MH_MARCHTAKE ) // march-take ?
+ {
+ p2.x = 0.0f;
+ p2.y = sinf(Mod(rTime[0]+0.5f, 1.0f)*PI*2.0f)*0.25f;
+ p2 = RotatePoint(-m_object->RetAngleY(0), p2);
+ dir.x = p2.x;
+ dir.z = p2.y;
+ dir.y = sinf(Mod(rTime[0]*2.0f, 1.0f)*PI*2.0f)*0.05f-0.3f;
+ }
+ else
+ {
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ dir.y = 0.0f;
+ }
+
+ actual = m_object->RetLinVibration();
+ dir.x = Smooth(actual.x, dir.x, time);
+ if ( action == MH_MARCHTAKE ) // march-take ?
+ {
+ dir.y = -hr;
+ }
+ else
+ {
+ s = Min(m_armTimeAction, 1.0f);
+ dir.y = Smooth(actual.y, dir.y, time)*s;
+ dir.y += -hr*(1.0f-s);
+ }
+ dir.z = Smooth(actual.z, dir.z, time);
+ if ( bOnBoard ) dir *= 0.3f;
+ m_object->SetLinVibration(dir);
+
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ dir.y = 0.0f;
+ SetCirVibration(dir);
+ }
+ }
+
+ // Gestion de la tête.
+ if ( m_actionType == MHS_TAKE || // prend ?
+ m_actionType == MHS_FLAG ) // prend ?
+ {
+ m_object->SetAngleZ(1, Smooth(m_object->RetAngleZ(1), sinf(m_armTimeAbs*1.0f)*0.2f-0.6f, event.rTime*5.0f));
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*1.1f)*0.1f);
+ m_object->SetAngleY(1, Smooth(m_object->RetAngleY(1), sinf(m_armTimeAbs*1.3f)*0.2f+rot*0.3f, event.rTime*5.0f));
+ }
+ else if ( m_actionType == MHS_TAKEOTHER || // prend ?
+ m_actionType == MHS_TAKEHIGH ) // prend ?
+ {
+ m_object->SetAngleZ(1, Smooth(m_object->RetAngleZ(1), sinf(m_armTimeAbs*1.0f)*0.2f-0.3f, event.rTime*5.0f));
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*1.1f)*0.1f);
+ m_object->SetAngleY(1, Smooth(m_object->RetAngleY(1), sinf(m_armTimeAbs*1.3f)*0.2f+rot*0.3f, event.rTime*5.0f));
+ }
+ else if ( m_actionType == MHS_WIN ) // gagné ?
+ {
+ float factor = 0.6f+(sinf(m_armTimeAbs*0.5f)*0.40f);
+ m_object->SetAngleZ(1, sinf(m_armTimeAbs*5.0f)*0.20f*factor);
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*0.6f)*0.10f);
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*1.5f)*0.15f);
+ }
+ else if ( m_actionType == MHS_LOST ) // perdu ?
+ {
+ float factor = 0.6f+(sinf(m_armTimeAbs*0.5f)*0.40f);
+ m_object->SetAngleZ(1, sinf(m_armTimeAbs*0.6f)*0.10f);
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*0.7f)*0.10f);
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*3.0f)*0.30f*factor);
+ }
+ else if ( m_object->RetDead() ) // mort ?
+ {
+ }
+ else
+ {
+ m_object->SetAngleZ(1, Smooth(m_object->RetAngleZ(1), sinf(m_armTimeAbs*1.0f)*0.2f, event.rTime*5.0f));
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*1.1f)*0.1f);
+ m_object->SetAngleY(1, Smooth(m_object->RetAngleY(1), sinf(m_armTimeAbs*1.3f)*0.2f+rot*0.3f, event.rTime*5.0f));
+ }
+
+ if ( bOnBoard )
+ {
+ m_object->SetAngleZ(1, 0.0f);
+ m_object->SetAngleX(1, 0.0f);
+ m_object->SetAngleY(1, 0.0f);
+ }
+
+ // Bruitage des pas.
+ if ( legAction == MH_MARCH ||
+ legAction == MH_MARCHTAKE )
+ {
+ Sound sound[2];
+ float speed, synchro, volume[2], freq[2], hard, level;
+
+ speed = m_physics->RetLinMotionX(MO_REASPEED);
+
+ if ( m_object->RetFret() == 0 )
+ {
+ if ( speed > 0.0f ) synchro = 0.21f; // synchro en avant
+ else synchro = 0.29f; // synchro en arrière
+ }
+ else
+ {
+ if ( speed > 0.0f ) synchro = 0.15f; // synchro en avant
+ else synchro = 0.35f; // synchro en arrière
+ }
+ time = rTime[1]+synchro;
+
+ if ( Abs(m_lastSoundMarch-time) > 0.4f &&
+ Mod(time, 0.5f) < 0.1f )
+ {
+ volume[0] = 0.5f;
+ freq[0] = 1.0f;
+ if ( m_object->RetFret() != 0 )
+ {
+//? volume[0] *= 2.0f;
+ freq[0] = 0.7f;
+ }
+ volume[1] = volume[0];
+ freq[1] = freq[0];
+ sound[0] = SOUND_CLICK;
+ sound[1] = SOUND_CLICK;
+
+ pos = m_object->RetPosition(0);
+
+ level = m_water->RetLevel();
+ if ( pos.y <= level+3.0f ) // sous l'eau ?
+ {
+ sound[0] = SOUND_STEPw;
+ }
+ else
+ {
+ hard = m_terrain->RetHardness(pos);
+
+ if ( hard >= 0.875 )
+ {
+ sound[0] = SOUND_STEPm; // metal
+ }
+ else
+ {
+ hard /= 0.875;
+ sound[0] = SOUND_STEPs; // smooth
+ sound[1] = SOUND_STEPh; // hard
+
+ volume[0] *= 1.0f-hard;
+ volume[1] *= hard;
+ if ( hard < 0.5f )
+ {
+ volume[0] *= 1.0f+hard*2.0f;
+ volume[1] *= 1.0f+hard*2.0f;
+ }
+ else
+ {
+ volume[0] *= 3.0f-hard*2.0f;
+ volume[1] *= 3.0f-hard*2.0f;
+ }
+ freq[0] *= 1.0f+hard;
+ freq[1] *= 0.5f+hard;
+ }
+ }
+
+ if ( sound[0] != SOUND_CLICK )
+ {
+ m_sound->Play(sound[0], pos, volume[0], freq[0]);
+ }
+ if ( sound[1] != SOUND_CLICK )
+ {
+ m_sound->Play(sound[1], pos, volume[1], freq[1]);
+ }
+ m_lastSoundMarch = time;
+ }
+ }
+
+ if ( legAction == MH_SWIM )
+ {
+ time = rTime[0]+0.5f;
+
+ if ( Abs(m_lastSoundMarch-time) > 0.9f &&
+ Mod(time, 1.0f) < 0.1f )
+ {
+ m_sound->Play(SOUND_SWIM, m_object->RetPosition(0), 0.5f);
+ m_lastSoundMarch = time;
+ }
+ }
+
+ m_lastSoundHhh -= event.rTime;
+ if ( m_lastSoundHhh <= 0.0f &&
+ m_object->RetSelect() &&
+ m_object->RetOption() == 0 ) // casque ?
+ {
+ m_sound->Play(SOUND_HUMAN1, m_object->RetPosition(0), (0.5f+m_tired*0.2f));
+ m_lastSoundHhh = (4.0f-m_tired*2.5f)+(4.0f-m_tired*2.5f)*Rand();
+ }
+
+ return TRUE;
+}
+
+
+// Gestion du mode d'affichage lors de la personnalisation du perso.
+
+void CMotionHuman::StartDisplayPerso()
+{
+ m_bDisplayPerso = TRUE;
+}
+
+void CMotionHuman::StopDisplayPerso()
+{
+ m_bDisplayPerso = FALSE;
+}
+
+
diff --git a/src/motionhuman.h b/src/motionhuman.h
new file mode 100644
index 0000000..d312c97
--- /dev/null
+++ b/src/motionhuman.h
@@ -0,0 +1,82 @@
+// motionhuman.h
+
+#ifndef _MOTIONHUMAN_H_
+#define _MOTIONHUMAN_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define MH_MARCH 0
+#define MH_MARCHTAKE 1
+#define MH_TURN 2
+#define MH_STOP 3
+#define MH_FLY 4
+#define MH_SWIM 5
+#define MH_SPEC 6
+
+#define MHS_FIRE 0
+#define MHS_GUN 1
+#define MHS_TAKE 2
+#define MHS_TAKEOTHER 3
+#define MHS_TAKEHIGH 4
+#define MHS_UPRIGHT 5
+#define MHS_WIN 6
+#define MHS_LOST 7
+#define MHS_DEADg 8
+#define MHS_DEADg1 9
+#define MHS_DEADg2 10
+#define MHS_DEADg3 11
+#define MHS_DEADg4 12
+#define MHS_DEADw 13
+#define MHS_FLAG 14
+#define MHS_SATCOM 15
+
+
+class CMotionHuman : public CMotion
+{
+public:
+ CMotionHuman(CInstanceManager* iMan, CObject* object);
+ ~CMotionHuman();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+ Error SetAction(int action, float time=0.2f);
+
+ void StartDisplayPerso();
+ void StopDisplayPerso();
+
+protected:
+ void CreatePhysics(ObjectType type);
+ BOOL EventFrame(const Event &event);
+
+protected:
+ int m_partiReactor;
+ float m_armMember;
+ float m_armTimeAbs;
+ float m_armTimeAction;
+ float m_armTimeSwim;
+ short m_armAngles[3*3*3*3*7 + 3*3*3*16];
+ int m_armTimeIndex;
+ int m_armPartIndex;
+ int m_armMemberIndex;
+ int m_armLastAction;
+ BOOL m_bArmStop;
+ float m_lastSoundMarch;
+ float m_lastSoundHhh;
+ float m_time;
+ float m_tired;
+ BOOL m_bDisplayPerso;
+};
+
+
+#endif //_MOTIONHUMAN_H_
diff --git a/src/motionmother.cpp b/src/motionmother.cpp
new file mode 100644
index 0000000..b342eb8
--- /dev/null
+++ b/src/motionmother.cpp
@@ -0,0 +1,527 @@
+// motionmother.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionmother.h"
+
+
+
+#define ADJUST_ANGLE FALSE // TRUE -> ajuste les angles des membres
+#define START_TIME 1000.0f // début du temps relatif
+
+
+
+// Constructeur de l'objet.
+
+CMotionMother::CMotionMother(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_armMember = START_TIME;
+ m_armTimeAbs = START_TIME;
+ m_armTimeMarch = START_TIME;
+ m_armTimeAction = START_TIME;
+ m_armTimeIndex = 0;
+ m_armPartIndex = 0;
+ m_armMemberIndex = 0;
+ m_armLastAction = -1;
+ m_specAction = -1;
+ m_bArmStop = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CMotionMother::~CMotionMother()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionMother::DeleteObject(BOOL bAll)
+{
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionMother::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 2+12+6 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+
+ pModFile->ReadModel("objects\\mother1.mod");
+ pModFile->CreateEngineObject(rank);
+
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 20.0f, SOUND_BOUM, 0.20f);
+ m_object->SetGlobalSphere(D3DVECTOR(-2.0f, 10.0f, 0.0f), 25.0f);
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\mother2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(16.0f, 3.0f, 0.0f));
+
+ // Crée la jambe 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\mother3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(-5.0f, -1.0f, -12.0f));
+
+ // Crée le pied 1 arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\mother4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(0.0f, 0.0f, -8.5f));
+
+ // Crée la jambe 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 0);
+ pModFile->ReadModel("objects\\mother3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(3.5f, -1.0f, -12.0f));
+
+ // Crée le pied 2 milieu-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 4);
+ pModFile->ReadModel("objects\\mother4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(0.0f, 0.0f, -8.5f));
+
+ // Crée la jambe 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\mother3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(10.0f, -1.0f, -10.0f));
+
+ // Crée le pied 3 avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 6);
+ pModFile->ReadModel("objects\\mother4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 0.0f, -8.5f));
+
+ // Crée la jambe 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\mother3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(-5.0f, -1.0f, 12.0f));
+ m_object->SetAngleY(8, PI);
+
+ // Crée le pied 1 arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 8);
+ pModFile->ReadModel("objects\\mother4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(0.0f, 0.0f, -8.5f));
+
+ // Crée la jambe 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(10, rank);
+ m_object->SetObjectParent(10, 0);
+ pModFile->ReadModel("objects\\mother3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(10, D3DVECTOR(3.5f, -1.0f, 12.0f));
+ m_object->SetAngleY(10, PI);
+
+ // Crée le pied 2 milieu-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(11, rank);
+ m_object->SetObjectParent(11, 10);
+ pModFile->ReadModel("objects\\mother4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(11, D3DVECTOR(0.0f, 0.0f, -8.5f));
+
+ // Crée la jambe 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(12, rank);
+ m_object->SetObjectParent(12, 0);
+ pModFile->ReadModel("objects\\mother3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(12, D3DVECTOR(10.0f, -1.0f, 10.0f));
+ m_object->SetAngleY(12, PI);
+
+ // Crée le pied 3 avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(13, rank);
+ m_object->SetObjectParent(13, 12);
+ pModFile->ReadModel("objects\\mother4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(13, D3DVECTOR(0.0f, 0.0f, -8.5f));
+
+ // Crée l'antenne droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(14, rank);
+ m_object->SetObjectParent(14, 1);
+ pModFile->ReadModel("objects\\mother5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(14, D3DVECTOR(6.0f, 1.0f, -2.5f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(15, rank);
+ m_object->SetObjectParent(15, 14);
+ pModFile->ReadModel("objects\\mother6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(15, D3DVECTOR(8.0f, 0.0f, 0.0f));
+
+ // Crée l'antenne gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(16, rank);
+ m_object->SetObjectParent(16, 1);
+ pModFile->ReadModel("objects\\mother5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(16, D3DVECTOR(6.0f, 1.0f, 2.5f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(17, rank);
+ m_object->SetObjectParent(17, 16);
+ pModFile->ReadModel("objects\\mother6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(17, D3DVECTOR(8.0f, 0.0f, 0.0f));
+
+ // Crée la pince droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(18, rank);
+ m_object->SetObjectParent(18, 1);
+ pModFile->ReadModel("objects\\mother7.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(18, D3DVECTOR(-4.0f, -3.5f, -8.0f));
+ m_object->SetZoomX(18, 1.2f);
+
+ // Crée la pince gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(19, rank);
+ m_object->SetObjectParent(19, 1);
+ pModFile->ReadModel("objects\\mother7.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(19, D3DVECTOR(-4.0f, -3.5f, 8.0f));
+ m_object->SetZoomX(19, 1.2f);
+
+ m_object->CreateShadowCircle(18.0f, 0.8f);
+
+ CreatePhysics();
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionMother::CreatePhysics()
+{
+ Character* character;
+ int i;
+
+ int member[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 30,30,10, 35,-15,10, 35,-35,10, // t0: jambes 1..3
+ -80,-45,-35, -115,-40,-35, -90,10,-55, // t0: pieds 1..3
+ 0,0,0, 0,0,0, 0,0,0, // t0: inutilisé
+ // au sol devant :
+ 15,-5,10, 10,-30,10, 5,-50,10, // t1: jambes 1..3
+ -90,-15,-15, -110,-55,-35, -75,-75,-30, // t1: pieds 1..3
+ 0,0,0, 0,0,0, 0,0,0, // t1: inutilisé
+ // au sol derrière :
+ 0,40,10, 5,5,10, 0,-15,10, // t2: jambes 1..3
+ -45,0,-55, -65,10,-50, -125,-85,-45, // t2: pieds 1..3
+ 0,0,0, 0,0,0, 0,0,0, // t2: inutilisé
+ };
+
+ m_physics->SetType(TYPE_ROLLING);
+
+ character = m_object->RetCharacter();
+ character->wheelFront = 10.0f;
+ character->wheelBack = 10.0f;
+ character->wheelLeft = 20.0f;
+ character->wheelRight = 20.0f;
+ character->height = 3.0f;
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 8.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 8.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 30.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 20.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.1f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.1f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 20.0f);
+
+ for ( i=0 ; i<3*3*3*3 ; i++ )
+ {
+ m_armAngles[i] = member[i];
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionMother::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if ADJUST_ANGLE
+ int i;
+
+ if ( event.param == 'A' ) m_armTimeIndex++;
+ if ( m_armTimeIndex >= 3 ) m_armTimeIndex = 0;
+
+ if ( event.param == 'Q' ) m_armPartIndex++;
+ if ( m_armPartIndex >= 3 ) m_armPartIndex = 0;
+
+ if ( event.param == 'W' ) m_armMemberIndex++;
+ if ( m_armMemberIndex >= 3 ) m_armMemberIndex = 0;
+
+ i = m_armMemberIndex*3;
+ i += m_armPartIndex*3*3;
+ i += m_armTimeIndex*3*3*3;
+//? i += 3*3*3*3;
+
+ if ( event.param == 'E' ) m_armAngles[i+0] += 5;
+ if ( event.param == 'D' ) m_armAngles[i+0] -= 5;
+ if ( event.param == 'R' ) m_armAngles[i+1] += 5;
+ if ( event.param == 'F' ) m_armAngles[i+1] -= 5;
+ if ( event.param == 'T' ) m_armAngles[i+2] += 5;
+ if ( event.param == 'G' ) m_armAngles[i+2] -= 5;
+
+ if ( event.param == 'Y' ) m_bArmStop = !m_bArmStop;
+#endif
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionMother::EventFrame(const Event &event)
+{
+ D3DVECTOR dir;
+ float s, a, prog;
+ int i, st, nd;
+ BOOL bStop;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return TRUE;
+
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*1.5f;
+ a = Abs(m_physics->RetCirMotionY(MO_MOTSPEED)*26.0f);
+
+ if ( s == 0.0f && a != 0.0f ) a *= 1.5f;
+
+ m_armTimeAbs += event.rTime;
+ m_armTimeMarch += (s)*event.rTime*0.05f;
+ m_armMember += (s+a)*event.rTime*0.05f;
+
+ bStop = ( a == 0.0f && s == 0.0f ); // a l'arrêt ?
+
+ if ( bStop )
+ {
+ prog = Mod(m_armTimeAbs, 2.0f)/10.0f;
+ a = Mod(m_armMember, 1.0f);
+ a = (prog-a)*event.rTime*1.0f; // vient gentiment à position stop
+ m_armMember += a;
+ }
+
+ for ( i=0 ; i<6 ; i++ ) // les 6 pattes
+ {
+ if ( i < 3 ) prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.0f, 1.0f);
+ else prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.3f, 1.0f);
+ if ( m_bArmStop )
+ {
+ prog = (float)m_armTimeIndex/3.0f;
+ }
+ if ( prog < 0.33f ) // t0..t1 ?
+ {
+ prog = prog/0.33f; // 0..1
+ st = 0; // index start
+ nd = 1; // index end
+ }
+ else if ( prog < 0.67f ) // t1..t2 ?
+ {
+ prog = (prog-0.33f)/0.33f; // 0..1
+ st = 1; // index start
+ nd = 2; // index end
+ }
+ else // t2..t0 ?
+ {
+ prog = (prog-0.67f)/0.33f; // 0..1
+ st = 2; // index start
+ nd = 0; // index end
+ }
+ st = st*27+(i%3)*3;
+ nd = nd*27+(i%3)*3;
+ if ( i < 3 ) // patte droite (1..3) ?
+ {
+ m_object->SetAngleX(2+2*i+0, Prop(m_armAngles[st+ 0], m_armAngles[nd+ 0], prog));
+ m_object->SetAngleY(2+2*i+0, Prop(m_armAngles[st+ 1], m_armAngles[nd+ 1], prog));
+ m_object->SetAngleZ(2+2*i+0, Prop(m_armAngles[st+ 2], m_armAngles[nd+ 2], prog));
+ m_object->SetAngleX(2+2*i+1, Prop(m_armAngles[st+ 9], m_armAngles[nd+ 9], prog));
+ m_object->SetAngleY(2+2*i+1, Prop(m_armAngles[st+10], m_armAngles[nd+10], prog));
+ m_object->SetAngleZ(2+2*i+1, Prop(m_armAngles[st+11], m_armAngles[nd+11], prog));
+ }
+ else // patte gauche (4..6) ?
+ {
+ m_object->SetAngleX(2+2*i+0, Prop( m_armAngles[st+ 0], m_armAngles[nd+ 0], prog));
+ m_object->SetAngleY(2+2*i+0, Prop(180-m_armAngles[st+ 1], 180-m_armAngles[nd+ 1], prog));
+ m_object->SetAngleZ(2+2*i+0, Prop( -m_armAngles[st+ 2], -m_armAngles[nd+ 2], prog));
+ m_object->SetAngleX(2+2*i+1, Prop( m_armAngles[st+ 9], m_armAngles[nd+ 9], prog));
+ m_object->SetAngleY(2+2*i+1, Prop( -m_armAngles[st+10], -m_armAngles[nd+10], prog));
+ m_object->SetAngleZ(2+2*i+1, Prop( -m_armAngles[st+11], -m_armAngles[nd+11], prog));
+ }
+ }
+
+#if ADJUST_ANGLE
+ if ( m_object->RetSelect() )
+ {
+ char s[100];
+ sprintf(s, "A:time=%d Q:part=%d W:member=%d", m_armTimeIndex, m_armPartIndex, m_armMemberIndex);
+ m_engine->SetInfoText(4, s);
+ }
+#endif
+
+ if ( !bStop && !m_object->RetRuin() )
+ {
+ a = Mod(m_armTimeMarch, 1.0f);
+ if ( a < 0.5f ) a = -1.0f+4.0f*a; // -1..1
+ else a = 3.0f-4.0f*a; // 1..-1
+ dir.x = sinf(a)*0.03f;
+
+ s = Mod(m_armTimeMarch/2.0f, 1.0f);
+ if ( s < 0.5f ) s = -1.0f+4.0f*s; // -1..1
+ else s = 3.0f-4.0f*s; // 1..-1
+ dir.z = sinf(s)*0.05f;
+
+ dir.y = 0.0f;
+ m_object->SetInclinaison(dir);
+
+ a = Mod(m_armMember-0.1f, 1.0f);
+ if ( a < 0.33f )
+ {
+ dir.y = -(1.0f-(a/0.33f))*0.3f;
+ }
+ else if ( a < 0.67f )
+ {
+ dir.y = 0.0f;
+ }
+ else
+ {
+ dir.y = -(a-0.67f)/0.33f*0.3f;
+ }
+ dir.x = 0.0f;
+ dir.z = 0.0f;
+ m_object->SetLinVibration(dir);
+ }
+
+ m_object->SetAngleZ(1, sinf(m_armTimeAbs*0.5f)*0.20f); // tête
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*0.6f)*0.10f); // tête
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*0.7f)*0.20f); // tête
+
+ m_object->SetAngleZ(14, 0.50f);
+ m_object->SetAngleZ(16, 0.50f);
+ m_object->SetAngleY(14, 0.80f+sinf(m_armTimeAbs*1.1f)*0.53f); // antenne droite
+ m_object->SetAngleY(15, 0.70f-sinf(m_armTimeAbs*1.7f)*0.43f);
+ m_object->SetAngleY(16, -0.80f+sinf(m_armTimeAbs*0.9f)*0.53f); // antenne gauche
+ m_object->SetAngleY(17, -0.70f-sinf(m_armTimeAbs*1.3f)*0.43f);
+
+ m_object->SetAngleY(18, sinf(m_armTimeAbs*1.1f)*0.20f); // pince droite
+ m_object->SetAngleZ(18, -0.20f);
+ m_object->SetAngleY(19, sinf(m_armTimeAbs*0.9f)*0.20f); // pince gauche
+ m_object->SetAngleZ(19, -0.20f);
+
+ return TRUE;
+}
+
+
diff --git a/src/motionmother.h b/src/motionmother.h
new file mode 100644
index 0000000..1555a22
--- /dev/null
+++ b/src/motionmother.h
@@ -0,0 +1,48 @@
+// motionmother.h
+
+#ifndef _MOTIONMOTHER_H_
+#define _MOTIONMOTHER_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CMotionMother : public CMotion
+{
+public:
+ CMotionMother(CInstanceManager* iMan, CObject* object);
+ ~CMotionMother();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+
+protected:
+ void CreatePhysics();
+ BOOL EventFrame(const Event &event);
+
+protected:
+ float m_armMember;
+ float m_armTimeAbs;
+ float m_armTimeMarch;
+ float m_armTimeAction;
+ short m_armAngles[3*3*3*3*10];
+ int m_armTimeIndex;
+ int m_armPartIndex;
+ int m_armMemberIndex;
+ int m_armLastAction;
+ int m_specAction;
+ float m_specTime;
+ BOOL m_bArmStop;
+};
+
+
+#endif //_MOTIONMOTHER_H_
diff --git a/src/motionspider.cpp b/src/motionspider.cpp
new file mode 100644
index 0000000..dee9391
--- /dev/null
+++ b/src/motionspider.cpp
@@ -0,0 +1,774 @@
+// motionspider.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionspider.h"
+
+
+
+#define ADJUST_ANGLE FALSE // TRUE -> ajuste les angles des membres
+#define START_TIME 1000.0f // début du temps relatif
+
+
+
+// Constructeur de l'objet.
+
+CMotionSpider::CMotionSpider(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_armMember = START_TIME;
+ m_armTimeAbs = START_TIME;
+ m_armTimeMarch = START_TIME;
+ m_armTimeAction = START_TIME;
+ m_armTimeIndex = 0;
+ m_armPartIndex = 0;
+ m_armMemberIndex = 0;
+ m_armLastAction = -1;
+ m_bArmStop = FALSE;
+ m_lastParticule = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CMotionSpider::~CMotionSpider()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionSpider::DeleteObject(BOOL bAll)
+{
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionSpider::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ int rank, i, j, parent;
+ char name[50];
+
+ float table[] =
+ {
+ // x y z
+ 0.6f, 0.0f, 0.0f, // patte arrière
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+
+ 0.8f, 0.0f, -0.2f, // patte arrière-milieu
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+
+ 1.0f, 0.0f, -0.2f, // patte avant-milieu
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+
+ 1.2f, 0.0f, 0.0f, // patte avant
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+ 0.0f, 0.0f, -2.0f,
+ };
+
+ if ( m_engine->RetRestCreate() < 3+32+2 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\spider0.mod"); // n'existe pas
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, -2.0f, 0.0f), 4.0f, SOUND_BOUM, 0.20f);
+ m_object->SetGlobalSphere(D3DVECTOR(-0.5f, 1.0f, 0.0f), 4.0f);
+
+ // Crée l'abdomen.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\spider1.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(1.0f, 0.0f, 0.0f));
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\spider2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(1.0f, 0.0f, 0.0f));
+
+ // Crée les pattes.
+ for ( i=0 ; i<4 ; i++ )
+ {
+ for ( j=0 ; j<4 ; j++ )
+ {
+ sprintf(name, "objects\\spider%d.mod", j+3); // 3..6
+
+ // Crée la patte droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3+i*4+j, rank);
+ if ( j == 0 ) parent = 0;
+ else parent = 3+i*4+j-1;
+ m_object->SetObjectParent(3+i*4+j, parent);
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+ pos.x = table[i*12+j*3+0];
+ pos.y = table[i*12+j*3+1];
+ pos.z = table[i*12+j*3+2];
+ m_object->SetPosition(3+i*4+j, pos);
+
+ // Crée la patte gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(19+i*4+j, rank);
+ if ( j == 0 ) parent = 0;
+ else parent = 19+i*4+j-1;
+ m_object->SetObjectParent(19+i*4+j, parent);
+ pModFile->ReadModel(name);
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ pos.x = table[i*12+j*3+0];
+ pos.y = table[i*12+j*3+1];
+ pos.z = -table[i*12+j*3+2];
+ m_object->SetPosition(19+i*4+j, pos);
+ }
+ }
+
+ // Crée la mandibule droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(35, rank);
+ m_object->SetObjectParent(35, 1);
+ pModFile->ReadModel("objects\\spider7.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(35, D3DVECTOR(0.0f, 0.0f, -0.3f));
+
+ // Crée la mandibule gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(36, rank);
+ m_object->SetObjectParent(36, 1);
+ pModFile->ReadModel("objects\\spider7.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(36, D3DVECTOR(0.0f, 0.0f, 0.3f));
+
+ m_object->CreateShadowCircle(4.0f, 0.5f);
+
+ CreatePhysics();
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionSpider::CreatePhysics()
+{
+ Character* character;
+ int i;
+
+ int member_march[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4, // en l'air :
+ 60,25,0, 60,0,0, 60,-25,0, 60,-50,0, // t0: cuisses 1..4
+ -35,40,0, -35,0,0, -35,0,0, -35,-40,0, // t0: jambes 1..4
+ -65,0,-30, -65,0,0, -65,0,0, -65,0,30, // t0: pieds 1..4
+ 25,0,0, 25,0,0, 25,0,0, 25,0,0, // t0: doigt 1..4
+ // au sol devant :
+ 30,15,0, 30,-10,0, 30,-35,0, 30,-60,0, // t1: cuisses 1..4
+ -10,40,0, -45,0,0, -45,0,0, -45,-40,0, // t1: jambes 1..4
+ -90,0,0, -20,0,0, -20,0,0, -20,0,0, // t1: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // t1: doigt 1..4
+ // au sol derrière :
+ 35,35,0, 40,10,0, 40,-15,0, 40,-40,0, // t2: cuisses 1..4
+ -35,40,0, -35,0,0, -35,0,0, -25,-40,0, // t2: jambes 1..4
+ -50,-25,-30,-65,0,0, -65,0,0, -90,0,30, // t2: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // t2: doigt 1..4
+ };
+
+ int member_stop[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4, // en l'air :
+ 35,35,0, 30,0,0, 30,-25,0, 30,-50,0, // t0: cuisses 1..4
+ -35,40,0, -45,0,0, -45,0,0, -45,-40,0, // t0: jambes 1..4
+ -50,-25,-30,-20,0,0, -20,0,0, -20,0,30, // t0: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // t0: doigt 1..4
+ // au sol devant :
+ 35,35,0, 30,0,0, 30,-25,0, 30,-50,0, // t1: cuisses 1..4
+ -30,40,0, -40,0,0, -40,0,0, -40,-40,0, // t1: jambes 1..4
+ -55,-25,-30,-25,0,0, -25,0,0, -25,0,0, // t1: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // t1: doigt 1..4
+ // au sol derrière :
+ 35,35,0, 30,0,0, 30,-25,0, 30,-50,0, // t2: cuisses 1..4
+ -30,40,0, -40,0,0, -40,0,0, -40,-40,0, // t2: jambes 1..4
+ -50,-25,-30,-20,0,0, -20,0,0, -20,0,30, // t2: pieds 1..4
+ -10,0,0, -10,0,0, -10,0,0, -10,0,0, // t2: doigt 1..4
+ };
+
+ int member_spec[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4, // brûle :
+ 30,25,0, 30,0,0, 30,-25,0, 30,-50,0, // s0: cuisses 1..4
+ -45,0,0, -45,0,0, -45,0,0, -45,0,0, // s0: jambes 1..4
+ -20,0,0, -20,0,0, -20,0,0, -20,0,0, // s0: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // s0: doigt 1..4
+ // ruine :
+ 30,25,0, 30,0,0, 30,-25,0, 30,-50,0, // s1: cuisses 1..4
+ -45,0,0, -45,0,0, -45,0,0, -45,0,0, // s1: jambes 1..4
+ -20,0,0, -20,0,0, -20,0,0, -20,0,0, // s1: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // s1: doigt 1..4
+ // explose :
+ 40,25,0, 40,0,0, 40,-25,0, 40,-50,0, // s2: cuisses 1..4
+ -55,0,0, -55,0,0, -55,0,0, -55,0,0, // s2: jambes 1..4
+ -30,0,0, -30,0,0, -30,0,0, -30,0,0, // s2: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // s2: doigt 1..4
+ // back1 :
+ 35,35,0, 30,0,0, 30,-25,0, 30,-50,0, // s3: cuisses 1..4
+ -30,40,0, -40,0,0, -40,0,0, -40,-40,0, // s3: jambes 1..4
+ -55,-25,-30,-25,0,0, -25,0,0, -25,0,0, // s3: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // s3: doigt 1..4
+ // back2 :
+ 15,35,0, 15,0,0, 15,-25,0, 15,-50,0, // s4: cuisses 1..4
+ -60,40,0, -60,0,0, -60,0,0, -60,-40,0, // s4: jambes 1..4
+ -65,-25,-30,-65,0,0, -65,0,0, -65,0,0, // s4: pieds 1..4
+ -15,0,0, -15,0,0, -15,0,0, -15,0,0, // s4: doigt 1..4
+ // back3 :
+ 35,35,0, 30,0,0, 30,-25,0, 30,-50,0, // s5: cuisses 1..4
+ -30,40,0, -40,0,0, -40,0,0, -40,-40,0, // s5: jambes 1..4
+ -55,-25,-30,-25,0,0, -25,0,0, -25,0,0, // s5: pieds 1..4
+ -5,0,0, -5,0,0, -5,0,0, -5,0,0, // s5: doigt 1..4
+ };
+
+ m_physics->SetType(TYPE_ROLLING);
+
+ character = m_object->RetCharacter();
+ character->wheelFront = 4.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 6.0f;
+ character->wheelRight = 6.0f;
+ character->height = 0.6f;
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 12.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 12.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 15.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 15.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 5.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 10.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 1.0f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 1.0f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 20.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 40.0f);
+
+ for ( i=0 ; i<3*4*4*3 ; i++ )
+ {
+ m_armAngles[3*4*4*3*MS_MARCH+i] = member_march[i];
+ }
+ for ( i=0 ; i<3*4*4*3 ; i++ )
+ {
+ m_armAngles[3*4*4*3*MS_STOP+i] = member_stop[i];
+ }
+ for ( i=0 ; i<3*4*4*6 ; i++ )
+ {
+ m_armAngles[3*4*4*3*MS_SPEC+i] = member_spec[i];
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionSpider::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if ADJUST_ANGLE
+ int i;
+
+ if ( event.param == 'A' ) m_armTimeIndex++;
+ if ( m_armTimeIndex >= 3 ) m_armTimeIndex = 0;
+
+ if ( event.param == 'Q' ) m_armPartIndex++;
+ if ( m_armPartIndex >= 4 ) m_armPartIndex = 0;
+
+ if ( event.param == 'W' ) m_armMemberIndex++;
+ if ( m_armMemberIndex >= 4 ) m_armMemberIndex = 0;
+
+ i = m_armMemberIndex*3;
+ i += m_armPartIndex*3*4;
+ i += m_armTimeIndex*3*4*4;
+
+ if ( event.param == 'E' ) m_armAngles[i+0] += 5;
+ if ( event.param == 'D' ) m_armAngles[i+0] -= 5;
+ if ( event.param == 'R' ) m_armAngles[i+1] += 5;
+ if ( event.param == 'F' ) m_armAngles[i+1] -= 5;
+ if ( event.param == 'T' ) m_armAngles[i+2] += 5;
+ if ( event.param == 'G' ) m_armAngles[i+2] -= 5;
+ if ( event.param == 'Z' ) m_armAngles[i+3] += 5;
+ if ( event.param == 'H' ) m_armAngles[i+3] -= 5;
+
+ if ( event.param == 'Y' ) m_bArmStop = !m_bArmStop;
+#endif
+ }
+
+ return TRUE;
+}
+
+// Calcule une valeur (radians) proportionnelle comprise
+// entre a et b (degrés).
+
+inline float Propf(float a, float b, float p)
+{
+ float aa, bb;
+
+ aa = a*PI/180.0f;
+ bb = b*PI/180.0f;
+
+ return aa+p*(bb-aa);
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionSpider::EventFrame(const Event &event)
+{
+ D3DVECTOR dir, pos, speed;
+ FPOINT dim;
+ float s, a, prog, time;
+ float tSt[12], tNd[12];
+ int i, ii, st, nd, action;
+ BOOL bStop;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return TRUE;
+
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*1.5f;
+ a = Abs(m_physics->RetCirMotionY(MO_MOTSPEED)*2.0f);
+
+ if ( s == 0.0f && a != 0.0f ) a *= 1.5f;
+
+ m_armTimeAbs += event.rTime;
+ m_armTimeAction += event.rTime;
+ m_armTimeMarch += (s)*event.rTime*0.15f;
+ m_armMember += (s+a)*event.rTime*0.15f;
+
+ bStop = ( a == 0.0f && s == 0.0f ); // a l'arrêt ?
+
+ action = MS_MARCH; // marche
+ if ( s == 0.0f && a == 0.0f )
+ {
+ action = MS_STOP; // stop
+ }
+
+ if ( bStop )
+ {
+ prog = Mod(m_armTimeAbs, 2.0f)/10.0f;
+ a = Mod(m_armMember, 1.0f);
+ a = (prog-a)*event.rTime*2.0f; // vient gentiment à position stop
+ m_armMember += a;
+ }
+
+ if ( m_object->RetRuin() ) // ruine ?
+ {
+ m_actionType = MSS_RUIN;
+ }
+ if ( m_object->RetBurn() ) // brûle ?
+ {
+ if ( m_object->RetFixed() )
+ {
+ m_actionType = MSS_BURN;
+ }
+ else
+ {
+ m_actionType = -1;
+ }
+ }
+
+ for ( i=0 ; i<8 ; i++ ) // les 8 pattes
+ {
+ if ( m_actionType != -1 ) // action spéciale en cours ?
+ {
+ st = 3*4*4*3*MS_SPEC + 3*4*4*m_actionType + (i%4)*3;
+ nd = st;
+ time = event.rTime*m_actionTime;
+ m_armTimeAction = 0.0f;
+ }
+ else
+ {
+//? if ( i < 4 ) prog = Mod(m_armMember+(2.0f-(i%4))*0.25f+0.0f, 1.0f);
+//? else prog = Mod(m_armMember+(2.0f-(i%4))*0.25f+0.3f, 1.0f);
+ if ( i < 4 ) prog = Mod(m_armMember+(2.0f-(i%4))*0.25f+0.0f, 1.0f);
+ else prog = Mod(m_armMember+(2.0f-(i%4))*0.25f+0.5f, 1.0f);
+ if ( m_bArmStop )
+ {
+ prog = (float)m_armTimeIndex/3.0f;
+ action = MS_MARCH;
+ }
+ if ( prog < 0.33f ) // t0..t1 ?
+ {
+ prog = prog/0.33f; // 0..1
+ st = 0; // index start
+ nd = 1; // index end
+ }
+ else if ( prog < 0.67f ) // t1..t2 ?
+ {
+ prog = (prog-0.33f)/0.33f; // 0..1
+ st = 1; // index start
+ nd = 2; // index end
+ }
+ else // t2..t0 ?
+ {
+ prog = (prog-0.67f)/0.33f; // 0..1
+ st = 2; // index start
+ nd = 0; // index end
+ }
+ st = 3*4*4*3*action + st*3*4*4 + (i%4)*3;
+ nd = 3*4*4*3*action + nd*3*4*4 + (i%4)*3;
+
+ // De moins en moins mou ...
+//? time = event.rTime*(2.0f+Min(m_armTimeAction*20.0f, 40.0f));
+ time = event.rTime*10.0f;
+ }
+
+ tSt[ 0] = m_armAngles[st+ 0]; // x
+ tSt[ 1] = m_armAngles[st+ 1]; // y
+ tSt[ 2] = m_armAngles[st+ 2]; // z
+ tSt[ 3] = m_armAngles[st+12]; // x
+ tSt[ 4] = m_armAngles[st+13]; // y
+ tSt[ 5] = m_armAngles[st+14]; // z
+ tSt[ 6] = m_armAngles[st+24]; // x
+ tSt[ 7] = m_armAngles[st+25]; // y
+ tSt[ 8] = m_armAngles[st+26]; // z
+ tSt[ 9] = m_armAngles[st+36]; // x
+ tSt[10] = m_armAngles[st+37]; // y
+ tSt[11] = m_armAngles[st+38]; // z
+
+ tNd[ 0] = m_armAngles[nd+ 0]; // x
+ tNd[ 1] = m_armAngles[nd+ 1]; // y
+ tNd[ 2] = m_armAngles[nd+ 2]; // z
+ tNd[ 3] = m_armAngles[nd+12]; // x
+ tNd[ 4] = m_armAngles[nd+13]; // y
+ tNd[ 5] = m_armAngles[nd+14]; // z
+ tNd[ 6] = m_armAngles[nd+24]; // x
+ tNd[ 7] = m_armAngles[nd+25]; // y
+ tNd[ 8] = m_armAngles[nd+26]; // z
+ tNd[ 9] = m_armAngles[nd+36]; // z
+ tNd[10] = m_armAngles[nd+37]; // z
+ tNd[11] = m_armAngles[nd+38]; // z
+
+ if ( m_actionType == MSS_BACK2 ) // sur le dos ?
+ {
+ for ( ii=0 ; ii<12 ; ii++ )
+ {
+ tSt[ii] += Rand()*20.0f;
+ tNd[ii] = tSt[ii];
+ }
+//? time = 100.0f;
+ time = event.rTime*10.0f;
+ }
+
+ if ( i < 4 ) // patte droite (1..4) ?
+ {
+ m_object->SetAngleX(3+4*i+0, Smooth(m_object->RetAngleX(3+4*i+0), Propf(tSt[ 0], tNd[ 0], prog), time));
+ m_object->SetAngleY(3+4*i+0, Smooth(m_object->RetAngleY(3+4*i+0), Propf(tSt[ 1], tNd[ 1], prog), time));
+ m_object->SetAngleZ(3+4*i+0, Smooth(m_object->RetAngleZ(3+4*i+0), Propf(tSt[ 2], tNd[ 2], prog), time));
+ m_object->SetAngleX(3+4*i+1, Smooth(m_object->RetAngleX(3+4*i+1), Propf(tSt[ 3], tNd[ 3], prog), time));
+ m_object->SetAngleY(3+4*i+1, Smooth(m_object->RetAngleY(3+4*i+1), Propf(tSt[ 4], tNd[ 4], prog), time));
+ m_object->SetAngleZ(3+4*i+1, Smooth(m_object->RetAngleZ(3+4*i+1), Propf(tSt[ 5], tNd[ 5], prog), time));
+ m_object->SetAngleX(3+4*i+2, Smooth(m_object->RetAngleX(3+4*i+2), Propf(tSt[ 6], tNd[ 6], prog), time));
+ m_object->SetAngleY(3+4*i+2, Smooth(m_object->RetAngleY(3+4*i+2), Propf(tSt[ 7], tNd[ 7], prog), time));
+ m_object->SetAngleZ(3+4*i+2, Smooth(m_object->RetAngleZ(3+4*i+2), Propf(tSt[ 8], tNd[ 8], prog), time));
+ m_object->SetAngleX(3+4*i+3, Smooth(m_object->RetAngleX(3+4*i+3), Propf(tSt[ 9], tNd[ 9], prog), time));
+ m_object->SetAngleY(3+4*i+3, Smooth(m_object->RetAngleY(3+4*i+3), Propf(tSt[10], tNd[10], prog), time));
+ m_object->SetAngleZ(3+4*i+3, Smooth(m_object->RetAngleZ(3+4*i+3), Propf(tSt[11], tNd[11], prog), time));
+ }
+ else // patte gauche (5..8) ?
+ {
+ m_object->SetAngleX(3+4*i+0, Smooth(m_object->RetAngleX(3+4*i+0), Propf(-tSt[ 0], -tNd[ 0], prog), time));
+ m_object->SetAngleY(3+4*i+0, Smooth(m_object->RetAngleY(3+4*i+0), Propf(-tSt[ 1], -tNd[ 1], prog), time));
+ m_object->SetAngleZ(3+4*i+0, Smooth(m_object->RetAngleZ(3+4*i+0), Propf( tSt[ 2], tNd[ 2], prog), time));
+ m_object->SetAngleX(3+4*i+1, Smooth(m_object->RetAngleX(3+4*i+1), Propf(-tSt[ 3], -tNd[ 3], prog), time));
+ m_object->SetAngleY(3+4*i+1, Smooth(m_object->RetAngleY(3+4*i+1), Propf(-tSt[ 4], -tNd[ 4], prog), time));
+ m_object->SetAngleZ(3+4*i+1, Smooth(m_object->RetAngleZ(3+4*i+1), Propf( tSt[ 5], tNd[ 5], prog), time));
+ m_object->SetAngleX(3+4*i+2, Smooth(m_object->RetAngleX(3+4*i+2), Propf(-tSt[ 6], -tNd[ 6], prog), time));
+ m_object->SetAngleY(3+4*i+2, Smooth(m_object->RetAngleY(3+4*i+2), Propf(-tSt[ 7], -tNd[ 7], prog), time));
+ m_object->SetAngleZ(3+4*i+2, Smooth(m_object->RetAngleZ(3+4*i+2), Propf( tSt[ 8], tNd[ 8], prog), time));
+ m_object->SetAngleX(3+4*i+3, Smooth(m_object->RetAngleX(3+4*i+3), Propf(-tSt[ 9], -tNd[ 9], prog), time));
+ m_object->SetAngleY(3+4*i+3, Smooth(m_object->RetAngleY(3+4*i+3), Propf(-tSt[10], -tNd[10], prog), time));
+ m_object->SetAngleZ(3+4*i+3, Smooth(m_object->RetAngleZ(3+4*i+3), Propf( tSt[11], tNd[11], prog), time));
+ }
+ }
+
+#if ADJUST_ANGLE
+ if ( m_object->RetSelect() )
+ {
+ char s[100];
+ sprintf(s, "A:time=%d Q:part=%d W:member=%d", m_armTimeIndex, m_armPartIndex, m_armMemberIndex);
+ m_engine->SetInfoText(4, s);
+ }
+#endif
+
+ if ( m_actionType == MSS_BURN ) // brûle ?
+ {
+ dir = D3DVECTOR(PI, 0.0f, 0.0f);
+ SetCirVibration(dir);
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetLinVibration(dir);
+ SetInclinaison(dir);
+
+ time = event.rTime*1.0f;
+ m_object->SetAngleZ(1, Smooth(m_object->RetAngleZ(1), 0.0f, time)); // tête
+ }
+ else if ( m_actionType == MSS_RUIN ) // ruine ?
+ {
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetLinVibration(dir);
+ SetCirVibration(dir);
+ SetInclinaison(dir);
+ }
+ else if ( m_actionType == MSS_EXPLO ) // explose ?
+ {
+ m_object->SetZoomY(1, 1.0f+m_progress);
+ m_object->SetZoomZ(1, 1.0f+m_progress);
+ m_object->SetZoomX(1, 1.0f+m_progress/2.0f);
+
+ dir.x = (Rand()-0.5f)*0.1f*m_progress;
+ dir.y = (Rand()-0.5f)*0.1f*m_progress;
+ dir.z = (Rand()-0.5f)*0.1f*m_progress;
+ m_object->SetCirVibration(dir);
+ }
+ else if ( m_actionType == MSS_BACK1 ) // se met sur le dos ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_armTimeAbs )
+ {
+ m_lastParticule = m_armTimeAbs;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ if ( m_progress < 0.5f )
+ {
+ dir.x = 0.0f;
+ dir.y = powf(m_progress/0.5f, 2.0f)*12.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ else
+ {
+ dir.x = 0.0f;
+ dir.y = powf(2.0f-m_progress/0.5f, 2.0f)*12.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ dir.x = m_progress*PI;
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ SetCirVibration(dir);
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(MSS_BACK2, 55.0f+Rand()*10.0f);
+ }
+ }
+ else if ( m_actionType == MSS_BACK2 ) // bouge sur le dos ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_armTimeAbs )
+ {
+ m_lastParticule = m_armTimeAbs;
+
+ if ( rand()%10 == 0 )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*8.0f;
+ pos.z += (Rand()-0.5f)*8.0f;
+ pos.y -= 1.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = Rand()*2.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+ }
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetLinVibration(dir);
+ dir.x = sinf(m_armTimeAbs* 3.0f)*0.20f+
+ sinf(m_armTimeAbs* 6.0f)*0.20f+
+ sinf(m_armTimeAbs*10.0f)*0.20f+
+ sinf(m_armTimeAbs*17.0f)*0.30f+PI;
+ dir.y = sinf(m_armTimeAbs* 4.0f)*0.02f+
+ sinf(m_armTimeAbs* 5.0f)*0.02f+
+ sinf(m_armTimeAbs*11.0f)*0.02f+
+ sinf(m_armTimeAbs*18.0f)*0.03f;
+ dir.z = sinf(m_armTimeAbs* 2.0f)*0.02f+
+ sinf(m_armTimeAbs* 7.0f)*0.02f+
+ sinf(m_armTimeAbs*13.0f)*0.02f+
+ sinf(m_armTimeAbs*15.0f)*0.03f;
+ SetCirVibration(dir);
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*5.0f)*0.05f); // queue
+ m_object->SetAngleY(2, cosf(m_armTimeAbs*5.0f)*0.20f); // tête
+ m_object->SetAngleZ(1, 0.4f); // queue
+ m_object->SetAngleZ(2, 0.0f); // tête
+
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(MSS_BACK3, 0.4f);
+ }
+ }
+ else if ( m_actionType == MSS_BACK3 ) // se remet sur les pattes ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_armTimeAbs )
+ {
+ m_lastParticule = m_armTimeAbs;
+
+ pos = m_object->RetPosition(0);
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*3.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ if ( m_progress < 0.5f )
+ {
+ dir.x = 0.0f;
+ dir.y = powf(m_progress/0.5f, 2.0f)*5.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ else
+ {
+ dir.x = 0.0f;
+ dir.y = powf(2.0f-m_progress/0.5f, 2.0f)*5.0f;
+ dir.z = 0.0f;
+ SetLinVibration(dir);
+ }
+ dir.x = (1.0f-m_progress)*PI;
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ SetCirVibration(dir);
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+
+ if ( m_progress >= 1.0f )
+ {
+ SetAction(-1);
+ m_object->SetFixed(FALSE); // bouge de nouveau
+ }
+ }
+ else
+ {
+ if ( bStop )
+ {
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetInclinaison(dir);
+ }
+ else
+ {
+ a = Mod(m_armMember, 1.0f);
+ if ( a < 0.5f ) a = -1.0f+4.0f*a; // -1..1
+ else a = 3.0f-4.0f*a; // 1..-1
+ dir.x = sinf(a)*0.05f;
+
+ s = Mod(m_armMember/2.0f, 1.0f);
+ if ( s < 0.5f ) s = -1.0f+4.0f*s; // -1..1
+ else s = 3.0f-4.0f*s; // 1..-1
+ dir.z = sinf(s)*0.1f;
+
+ dir.y = 0.0f;
+ SetInclinaison(dir);
+ }
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ SetLinVibration(dir);
+ SetCirVibration(dir);
+
+ m_object->SetAngleZ(1, sinf(m_armTimeAbs*1.7f)*0.02f); // queue
+ m_object->SetAngleX(1, sinf(m_armTimeAbs*1.3f)*0.05f);
+ m_object->SetAngleY(1, sinf(m_armTimeAbs*2.4f)*0.10f);
+ m_object->SetZoom(1, 1.0f+sinf(m_armTimeAbs*3.3f)*0.05f);
+
+ m_object->SetAngleZ(2, sinf(m_armTimeAbs*1.4f)*0.20f); // tête
+ m_object->SetAngleX(2, sinf(m_armTimeAbs*1.9f)*0.10f);
+ m_object->SetAngleY(2, sinf(m_armTimeAbs*2.1f)*0.10f);
+
+ m_object->SetAngleY(35, sinf(m_armTimeAbs*3.1f)*0.20f); // mandibule
+ m_object->SetAngleY(36, -sinf(m_armTimeAbs*3.1f)*0.20f); // mandibule
+ }
+
+ return TRUE;
+}
+
+
diff --git a/src/motionspider.h b/src/motionspider.h
new file mode 100644
index 0000000..b010a2c
--- /dev/null
+++ b/src/motionspider.h
@@ -0,0 +1,59 @@
+// motionspider.h
+
+#ifndef _MOTIONSPIDER_H_
+#define _MOTIONSPIDER_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define MS_MARCH 0
+#define MS_STOP 1
+#define MS_SPEC 2
+
+#define MSS_BURN 0
+#define MSS_RUIN 1
+#define MSS_EXPLO 2
+#define MSS_BACK1 3
+#define MSS_BACK2 4
+#define MSS_BACK3 5
+
+
+class CMotionSpider : public CMotion
+{
+public:
+ CMotionSpider(CInstanceManager* iMan, CObject* object);
+ ~CMotionSpider();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+
+protected:
+ void CreatePhysics();
+ BOOL EventFrame(const Event &event);
+
+protected:
+ float m_armMember;
+ float m_armTimeAbs;
+ float m_armTimeMarch;
+ float m_armTimeAction;
+ short m_armAngles[3*4*4*3*3 + 3*4*4*6];
+ int m_armTimeIndex;
+ int m_armPartIndex;
+ int m_armMemberIndex;
+ int m_armLastAction;
+ BOOL m_bArmStop;
+ float m_lastParticule;
+};
+
+
+#endif //_MOTIONSPIDER_H_
diff --git a/src/motiontoto.cpp b/src/motiontoto.cpp
new file mode 100644
index 0000000..1e4a8ae
--- /dev/null
+++ b/src/motiontoto.cpp
@@ -0,0 +1,870 @@
+// motiontoto.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "modfile.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "motion.h"
+#include "motiontoto.h"
+
+
+
+#define START_TIME 1000.0f // début du temps relatif
+
+
+
+// Constructeur de l'objet.
+
+CMotionToto::CMotionToto(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_time = 0.0f;
+ m_bDisplayInfo = FALSE;
+ m_bQuickPos = FALSE;
+ m_bStartAction = FALSE;
+ m_speedAction = 20.0f;
+ m_soundChannel = -1;
+ m_clownRadius = 0.0f;
+ m_clownDelay = 0.0f;
+ m_clownTime = 0.0f;
+ m_blinkTime = 0.0f;
+ m_blinkProgress = -1.0f;
+ m_lastMotorParticule = 0.0f;
+ m_type = OBJECT_NULL;
+ m_mousePos = FPOINT(0.0f, 0.0f);
+}
+
+// Destructeur de l'objet.
+
+CMotionToto::~CMotionToto()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionToto::DeleteObject(BOOL bAll)
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->Stop(m_soundChannel);
+ m_soundChannel = -1;
+ }
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionToto::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 10 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\toto1.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Crée la bouche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\toto2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(1.00f, 0.17f, 0.00f));
+
+ // Crée l'oeil gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\toto3.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(0.85f, 1.04f, 0.25f));
+ m_object->SetAngleY(2, -20.0f*PI/180.0f);
+
+ // Crée l'oeil droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 0);
+ pModFile->ReadModel("objects\\toto3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(0.85f, 1.04f, -0.25f));
+ m_object->SetAngleY(3, 20.0f*PI/180.0f);
+
+ // Crée l'antenne gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 0);
+ pModFile->ReadModel("objects\\toto4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(0.0f, 1.9f, 0.3f));
+ m_object->SetAngleX(4, 30.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 4);
+ pModFile->ReadModel("objects\\toto4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(0.0f, 0.67f, 0.0f));
+ m_object->SetAngleX(5, 30.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 5);
+ pModFile->ReadModel("objects\\toto5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.0f, 0.70f, 0.0f));
+ m_object->SetAngleX(6, 30.0f*PI/180.0f);
+
+ // Crée l'antenne droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\toto4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 1.9f, -0.3f));
+ m_object->SetAngleX(7, -30.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 7);
+ pModFile->ReadModel("objects\\toto4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(0.0f, 0.67f, 0.0f));
+ m_object->SetAngleX(8, -30.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 8);
+ pModFile->ReadModel("objects\\toto5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(0.0f, 0.70f, 0.0f));
+ m_object->SetAngleX(9, -30.0f*PI/180.0f);
+
+ m_object->SetZoom(0, 0.5f); // c'est p'tit
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+
+// Début de l'affichage des informations, avec toto dans la marge gauche.
+
+void CMotionToto::StartDisplayInfo()
+{
+return;
+//?
+ m_bDisplayInfo = TRUE;
+
+ m_actionType = -1;
+ m_actionTime = 0.0f;
+ m_progress = 0.0f;
+
+ m_object->SetAngleY(0, 0.0f);
+ m_mousePos = FPOINT(0.5f, 0.5f);
+}
+
+// Fin de l'affichage des informartions.
+
+void CMotionToto::StopDisplayInfo()
+{
+ m_bDisplayInfo = FALSE;
+ m_bQuickPos = TRUE;
+}
+
+// Donne la position de la souris.
+
+void CMotionToto::SetMousePos(FPOINT pos)
+{
+ m_mousePos = pos;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionToto::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionToto::EventFrame(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR eye, lookat, dir, perp, nPos, aPos, pos, speed;
+ D3DVECTOR vibLin, vibCir, dirSpeed, aAntenna;
+ FPOINT dim;
+ POINT wDim;
+ ParticuleType type;
+ float progress, focus, distance, shift, verti, level, zoom;
+ float aAngle, nAngle, mAngle, angle, linSpeed, cirSpeed;
+ int sheet, i, r;
+ BOOL bHidden;
+
+ if ( m_engine->RetPause() &&
+ !m_main->RetInfoLock() ) return TRUE;
+
+ if ( m_bDisplayInfo ) // "regarde" la souris ?
+ {
+ bHidden = FALSE;
+ }
+ else
+ {
+ bHidden = FALSE;
+
+ if ( m_main->RetMovieLock() ) // film en cours ?
+ {
+ bHidden = TRUE;
+ }
+ if ( !m_engine->RetTotoMode() )
+ {
+ if ( !m_main->RetEditLock() ) // édition en cours ?
+ {
+ bHidden = TRUE;
+ }
+ }
+ }
+
+ if ( bHidden )
+ {
+ nPos = m_object->RetPosition(0);
+ m_terrain->MoveOnFloor(nPos, TRUE);
+ nPos.y -= 100.0f; // cache sous le sol !
+ m_object->SetPosition(0, nPos);
+ return TRUE;
+ }
+
+ m_time += event.rTime;
+ m_blinkTime -= event.rTime;
+
+ progress = 0.0f;
+ if ( m_actionType != -1 ) // action en cours ?
+ {
+ if ( m_progress < 0.15f )
+ {
+ progress = m_progress/0.15f;
+ }
+ else if ( m_progress < 0.85f )
+ {
+ progress = 1.0f;
+ }
+ else
+ {
+ progress = (1.0f-m_progress)/0.15f;
+ }
+ }
+
+ if ( m_progress >= 1.0f )
+ {
+ m_actionType = -1; // action terminée
+ m_actionTime = 0.0f;
+ m_progress = 0.0f;
+
+ m_clownTime = 0.0f;
+ m_clownDelay = 0.0f;
+ }
+
+ focus = m_engine->RetFocus();
+ eye = m_engine->RetEyePt();
+ lookat = m_engine->RetLookatPt();
+
+ vibLin = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ vibCir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ aAntenna = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ aAntenna.x += 30.0f*PI/180.0f;
+
+ // Calcule la nouvelle position.
+ if ( m_bDisplayInfo )
+ {
+ wDim = m_engine->RetDim();
+ nPos.x = -4.0f*((float)wDim.x/(float)wDim.y)/(640.0f/480.0f);
+ nPos.y = -0.5f;
+ nPos.z = 7.0f; // dans la marge gauche
+
+ linSpeed = 0.0f;
+ }
+ else
+ {
+#if 0
+ distance = 30.0f-progress*24.5f; // éloignement
+ shift = 18.0f-progress*15.4f; // décalage à gauche
+ verti = 10.0f-progress* 9.6f; // décalage en haut
+#else
+ distance = 30.0f-progress*18.0f; // éloignement
+ shift = 18.0f-progress*11.0f; // décalage à gauche
+ verti = 10.0f-progress* 8.0f; // décalage en haut
+#endif
+
+ if ( m_actionType == -1 &&
+ (m_type == OBJECT_HUMAN ||
+ m_type == OBJECT_TECH ||
+ m_type == OBJECT_MOBILEwa ||
+ m_type == OBJECT_MOBILEta ||
+ m_type == OBJECT_MOBILEfa ||
+ m_type == OBJECT_MOBILEia ||
+ m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEic ||
+ m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEii ||
+ m_type == OBJECT_MOBILEws ||
+ m_type == OBJECT_MOBILEts ||
+ m_type == OBJECT_MOBILEfs ||
+ m_type == OBJECT_MOBILEis ||
+ m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErc ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs ||
+ m_type == OBJECT_MOBILEsa ||
+ m_type == OBJECT_MOBILEwt ||
+ m_type == OBJECT_MOBILEtt ||
+ m_type == OBJECT_MOBILEft ||
+ m_type == OBJECT_MOBILEit ||
+ m_type == OBJECT_MOBILEdr ) ) // véhicule ?
+ {
+ m_clownTime += event.rTime;
+ if ( m_clownTime >= m_clownDelay )
+ {
+ if ( rand()%10 < 2 )
+ {
+ m_clownRadius = 2.0f+Rand()*10.0f;
+//? m_clownDelay = m_clownRadius/(2.0f+Rand()*2.0f);
+ m_clownDelay = 1.5f+Rand()*1.0f;
+ }
+ else
+ {
+ m_clownRadius = 0.0f;
+ m_clownDelay = 2.0f+Rand()*2.0f;
+ }
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel() ) // sous l'eau ?
+ {
+ m_clownRadius /= 1.5f;
+ m_clownDelay *= 2.0f;
+ }
+ m_clownTime = 0.0f;
+ }
+ else
+ {
+ distance -= m_clownRadius*sinf(m_clownTime*PI*2.0f/m_clownDelay);
+ shift -= m_clownRadius-m_clownRadius*cosf(m_clownTime*PI*2.0f/m_clownDelay);
+ }
+
+ verti += (18.0f-shift)*0.2f;
+ }
+
+ distance /= focus;
+//? shift *= focus;
+ verti /= focus;
+
+ dir = Normalize(lookat-eye);
+ nPos = eye + dir*distance;
+
+ perp.x = -dir.z;
+ perp.y = dir.y;
+ perp.z = dir.x;
+ nPos = nPos + perp*shift;
+
+ nPos.y += verti;
+
+ if ( m_bQuickPos ) // tout de suite en place ?
+ {
+ m_bQuickPos = FALSE;
+ linSpeed = 0.0f;
+ }
+ else
+ {
+ aPos = m_object->RetPosition(0);
+ if ( m_actionType == -1 )
+ {
+ level = 4.0f;
+ }
+ else
+ {
+ if ( m_bStartAction )
+ {
+ m_bStartAction = FALSE;
+ m_speedAction = Length(nPos, aPos)/15.0f;
+ if ( m_speedAction < 20.0f ) m_speedAction = 20.0f;
+ }
+ level = m_speedAction;
+ }
+ if ( level > 1.0f/event.rTime ) level = 1.0f/event.rTime;
+ nPos = aPos + (nPos-aPos)*event.rTime*level; // progression aPos -> nPos
+
+ linSpeed = Length2d(nPos, aPos)/event.rTime;
+ dirSpeed = (nPos-aPos)/event.rTime;
+ nPos.y -= linSpeed*0.015f*(1.0f-progress); // au raz du sol si avance vite
+ }
+ }
+
+ // Calcule le nouvel angle.
+ nAngle = NormAngle(RotateAngle(eye.x-lookat.x, lookat.z-eye.z)-0.9f);
+ if ( linSpeed == 0.0f || m_actionType != -1 )
+ {
+ mAngle = nAngle;
+ }
+ else
+ {
+ mAngle = NormAngle(RotateAngle(dirSpeed.x, -dirSpeed.z));
+ }
+ level = Min(linSpeed*0.1f, 1.0f);
+ nAngle = nAngle*(1.0f-level) + mAngle*level;
+ aAngle = NormAngle(m_object->RetAngleY(0));
+
+ if ( nAngle < aAngle )
+ {
+ if ( nAngle+PI*2.0f-aAngle < aAngle-nAngle ) nAngle += PI*2.0f;
+ }
+ else
+ {
+ if ( aAngle+PI*2.0f-nAngle < nAngle-aAngle ) aAngle += PI*2.0f;
+ }
+ nAngle = aAngle + (nAngle-aAngle)*event.rTime*4.0f;
+
+ // Penche de côté si tourne.
+ cirSpeed = (aAngle-nAngle)/event.rTime;
+ angle = cirSpeed*0.3f*(1.0f-progress);
+ if ( angle > 0.7f ) angle = 0.7f;
+ if ( angle < -0.7f ) angle = -0.7f;
+ vibCir.x += angle*1.5f;
+ aAntenna.x += Abs(angle)*0.8f; // écarte
+
+ // Penche en avant si avance vite.
+ angle = linSpeed*0.10f*(1.0f-progress);
+ if ( angle > 1.0f ) angle = 1.0f;
+ vibCir.z -= angle/2.0f; // penche en avant
+ aAntenna.z -= angle; // penche en avant
+
+ // Calcule le mouvement résiduel.
+#if 1
+ vibLin.y += (sinf(m_time*2.00f)*0.5f+
+ sinf(m_time*2.11f)*0.2f)*(1.0f-progress);
+
+ vibCir.z += sinf(m_time*PI* 2.01f)*(PI/ 75.0f)+
+ sinf(m_time*PI* 2.51f)*(PI/100.0f)+
+ sinf(m_time*PI*19.01f)*(PI/200.0f);
+
+ vibCir.x += sinf(m_time*PI* 2.03f)*(PI/ 75.0f)+
+ sinf(m_time*PI* 2.52f)*(PI/100.0f)+
+ sinf(m_time*PI*19.53f)*(PI/200.0f);
+
+ vibCir.y += (sinf(m_time*PI* 1.07f)*(PI/ 10.0f)+
+ sinf(m_time*PI* 1.19f)*(PI/ 17.0f)+
+ sinf(m_time*PI* 1.57f)*(PI/ 31.0f))*(1.0f-progress);
+#endif
+
+ // Calcule les animations lors d'une action.
+ if ( m_actionType == MT_ERROR ) // non-non ?
+ {
+ vibCir.y += progress*sinf(m_progress*PI*11.0f)*1.0f;
+ vibCir.z -= progress*0.5f; // penche en avant
+
+ aAntenna.x -= progress*0.4f; // resserre
+ aAntenna.z += progress*1.0f; // penche en arrière
+ }
+
+ if ( m_actionType == MT_WARNING ) // avertissement ?
+ {
+ vibCir.x += progress*sinf(m_progress*PI*17.0f)*0.5f;
+
+ aAntenna.x += progress*sinf(m_progress*PI*17.0f)*0.5f; // écarte
+ aAntenna.z += progress*cosf(m_progress*PI*17.0f)*0.5f; // tourne
+ }
+
+ if ( m_actionType == MT_INFO ) // oui-oui ?
+ {
+ vibCir.z += progress*sinf(m_progress*PI*19.0f)*0.7f;
+
+ aAntenna.x -= progress*0.2f; // resserre
+ aAntenna.z -= progress*cosf(m_progress*PI*19.0f)*0.9f; // tourne
+ }
+
+ if ( m_actionType == MT_MESSAGE ) // message ?
+ {
+ vibCir.x += progress*sinf(m_progress*PI*15.0f)*0.3f;
+ vibCir.z += progress*cosf(m_progress*PI*15.0f)*0.3f;
+
+ aAntenna.x -= progress*0.4f; // resserre
+ aAntenna.z -= progress*cosf(m_progress*PI*19.0f)*0.8f;
+ }
+
+ // Initialise l'objet.
+ if ( m_bDisplayInfo ) // "regarde" la souris ?
+ {
+ if ( m_mousePos.x < 0.15f )
+ {
+ progress = 1.0f-m_mousePos.x/0.15f;
+ vibCir.y += progress*PI/2.0f;
+ }
+ else
+ {
+ progress = (m_mousePos.x-0.15f)/0.85f;
+ vibCir.y -= progress*PI/3.0f;
+ }
+
+ angle = RotateAngle(m_mousePos.x-0.1f, m_mousePos.y-0.5f-vibLin.y*0.2f);
+ if ( angle < PI )
+ {
+ if ( angle > PI*0.5f ) angle = PI-angle;
+ if ( angle > PI*0.3f ) angle = PI*0.3f;
+ vibCir.z += angle;
+ }
+ else
+ {
+ angle = PI*2.0f-angle;
+ if ( angle > PI*0.5f ) angle = PI-angle;
+ if ( angle > PI*0.3f ) angle = PI*0.3f;
+ vibCir.z -= angle;
+ }
+ }
+ else
+ {
+ nPos.y += vibLin.y;
+ level = m_terrain->RetFloorLevel(nPos);
+ if ( nPos.y < level+2.0f )
+ {
+ nPos.y = level+2.0f; // juste au-dessus du sol
+ }
+ nPos.y -= vibLin.y;
+ }
+ m_object->SetPosition(0, nPos);
+ m_object->SetAngleY(0, nAngle);
+
+ SetLinVibration(vibLin);
+ SetCirVibration(vibCir);
+
+ // Calcule le mouvement résiduel des antennes.
+ pos = aAntenna*0.40f;
+ pos.x += sinf(m_time*PI*2.07f)*(PI/50.0f)+
+ sinf(m_time*PI*2.59f)*(PI/70.0f)+
+ sinf(m_time*PI*2.67f)*(PI/90.0f);
+
+ pos.y += sinf(m_time*PI*2.22f)*(PI/50.0f)+
+ sinf(m_time*PI*2.36f)*(PI/70.0f)+
+ sinf(m_time*PI*3.01f)*(PI/90.0f);
+
+ pos.z += sinf(m_time*PI*2.11f)*(PI/50.0f)+
+ sinf(m_time*PI*2.83f)*(PI/70.0f)+
+ sinf(m_time*PI*3.09f)*(PI/90.0f);
+
+ m_object->SetAngle(4, pos); // antenne gauche
+ m_object->SetAngle(5, pos); // antenne gauche
+ m_object->SetAngle(6, pos); // antenne gauche
+
+ pos = aAntenna*0.40f;
+ pos.x = -pos.x;
+ pos.x += sinf(m_time*PI*2.33f)*(PI/50.0f)+
+ sinf(m_time*PI*2.19f)*(PI/70.0f)+
+ sinf(m_time*PI*2.07f)*(PI/90.0f);
+
+ pos.y += sinf(m_time*PI*2.44f)*(PI/50.0f)+
+ sinf(m_time*PI*2.77f)*(PI/70.0f)+
+ sinf(m_time*PI*3.22f)*(PI/90.0f);
+
+ pos.z += sinf(m_time*PI*2.05f)*(PI/50.0f)+
+ sinf(m_time*PI*2.38f)*(PI/70.0f)+
+ sinf(m_time*PI*2.79f)*(PI/90.0f);
+
+ m_object->SetAngle(7, pos); // antenne droite
+ m_object->SetAngle(8, pos); // antenne droite
+ m_object->SetAngle(9, pos); // antenne droite
+
+ // Mouvement de la bouche.
+ if ( m_actionType == MT_ERROR ) // non-non ?
+ {
+ m_object->SetAngleX(1, 0.0f);
+ m_object->SetAngleZ(1, 0.2f+sinf(m_time*10.0f)*0.2f);
+ m_object->SetZoomY(1, 2.0f+sinf(m_time*10.0f));
+ m_object->SetZoomZ(1, 1.0f);
+ }
+ else if ( m_actionType == MT_WARNING ) // avertissement ?
+ {
+ m_object->SetAngleX(1, 15.0f*PI/180.0f);
+ m_object->SetAngleZ(1, 0.0f);
+ m_object->SetZoomY(1, 1.0f);
+ m_object->SetZoomZ(1, 1.0f);
+ }
+ else if ( m_actionType == MT_INFO ) // oui-oui ?
+ {
+ m_object->SetAngleX(1, 0.0f);
+ m_object->SetAngleZ(1, 0.0f);
+ m_object->SetZoomY(1, 1.0f);
+ m_object->SetZoomZ(1, 0.7f+sinf(m_time*10.0f)*0.3f);
+ }
+ else if ( m_actionType == MT_MESSAGE ) // message ?
+ {
+ m_object->SetAngleX(1, 0.0f);
+ m_object->SetAngleZ(1, 0.0f);
+ m_object->SetZoomY(1, 1.0f);
+ m_object->SetZoomZ(1, 0.8f+sinf(m_time*7.0f)*0.2f);
+ }
+ else
+ {
+ m_object->SetAngleX(1, 0.0f);
+ m_object->SetAngleZ(1, 0.0f);
+ m_object->SetZoomY(1, 1.0f);
+ m_object->SetZoomZ(1, 1.0f);
+ }
+
+ // Gestion du clignement des yeux.
+ if ( m_blinkTime <= 0.0f && m_blinkProgress == -1.0f )
+ {
+ m_blinkProgress = 0.0f;
+ }
+
+ if ( m_blinkProgress >= 0.0f )
+ {
+ m_blinkProgress += event.rTime*3.2f;
+
+ if ( m_blinkProgress < 1.0f )
+ {
+ if ( m_blinkProgress < 0.5f ) zoom = m_blinkProgress/0.5f;
+ else zoom = 2.0f-m_blinkProgress/0.5f;
+ m_object->SetZoomY(2, 1.0f-zoom*0.9f);
+ m_object->SetZoomY(3, 1.0f-zoom*0.9f);
+ }
+ else
+ {
+ m_blinkProgress = -1.0f;
+ m_blinkTime = 0.1f+Rand()*4.0f;
+ m_object->SetZoomY(2, 1.0f);
+ m_object->SetZoomY(3, 1.0f);
+ }
+ }
+
+ if ( m_actionType == MT_ERROR ) // non-non ?
+ {
+ m_object->SetAngleX(2, -30.0f*PI/180.0f);
+ m_object->SetAngleX(3, 30.0f*PI/180.0f);
+ }
+ else if ( m_actionType == MT_WARNING ) // avertissement ?
+ {
+ m_object->SetAngleX(2, -15.0f*PI/180.0f);
+ m_object->SetAngleX(3, 15.0f*PI/180.0f);
+ }
+ else if ( m_actionType == MT_INFO ) // oui-oui ?
+ {
+ m_object->SetAngleX(2, 40.0f*PI/180.0f);
+ m_object->SetAngleX(3, -40.0f*PI/180.0f);
+ }
+ else if ( m_actionType == MT_MESSAGE ) // message ?
+ {
+ m_object->SetAngleX(2, 20.0f*PI/180.0f);
+ m_object->SetAngleX(3, -20.0f*PI/180.0f);
+ }
+ else
+ {
+ m_object->SetAngleX(2, 0.0f);
+ m_object->SetAngleX(3, 0.0f);
+ }
+
+ mat = m_object->RetWorldMatrix(0); // doit être fait chaque fois !
+
+ // Génère les particules.
+ if ( m_time-m_lastMotorParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ m_lastMotorParticule = m_time;
+
+ if ( m_bDisplayInfo ) sheet = SH_FRONT;
+ else sheet = SH_WORLD;
+
+ pos = m_object->RetPosition(0);
+ if ( !m_bDisplayInfo &&
+ pos.y < m_water->RetLevel() ) // sous l'eau ?
+ {
+ float t = Mod(m_time, 3.5f);
+ if ( t >= 2.2f || ( t >= 1.2f && t <= 1.4f ) ) // respire ?
+ {
+ pos = D3DVECTOR(1.0f, 0.2f, 0.0f);
+ pos.z += (Rand()-0.5f)*0.5f;
+
+ speed = pos;
+ speed.y += 5.0f+Rand()*5.0f;
+ speed.x += Rand()*2.0f;
+ speed.z += (Rand()-0.5f)*2.0f;
+
+ pos = Transform(*mat, pos);
+ speed = Transform(*mat, speed)-pos;
+
+ dim.x = 0.12f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBUBBLE, 3.0f, 0.0f, 0.0f);
+ }
+ }
+ else // hors de l'eau ?
+ {
+ pos = D3DVECTOR(0.0f, -0.5f, 0.0f);
+ pos.z += (Rand()-0.5f)*0.5f;
+
+ speed = pos;
+ speed.y -= (1.5f+Rand()*1.5f) + vibLin.y;
+ speed.x += (Rand()-0.5f)*2.0f;
+ speed.z += (Rand()-0.5f)*2.0f;
+
+// mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed = Transform(*mat, speed)-pos;
+
+ dim.x = (Rand()*0.4f+0.4f)*(1.0f+Min(linSpeed*0.1f, 5.0f));
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTITOTO, 1.0f+Rand()*1.0f, 0.0f, 1.0f, sheet);
+ }
+
+ if ( m_actionType != -1 && // action en cours ?
+ m_progress <= 0.85f )
+ {
+ pos.x = (Rand()-0.5f)*1.0f;
+ pos.y = (Rand()-0.5f)*1.0f+3.5f;
+ pos.z = (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = (Rand()*0.3f+0.3f);
+ dim.y = dim.x;
+ if ( m_actionType == MT_ERROR ) type = PARTIERROR;
+ if ( m_actionType == MT_WARNING ) type = PARTIWARNING;
+ if ( m_actionType == MT_INFO ) type = PARTIINFO;
+ if ( m_actionType == MT_MESSAGE ) type = PARTIWARNING;
+ m_particule->CreateParticule(pos, speed, dim, type, 0.5f+Rand()*0.5f, 0.0f, 1.0f, sheet);
+
+ pos.x = 0.50f+(Rand()-0.5f)*0.80f;
+ pos.y = 0.86f+(Rand()-0.5f)*0.08f;
+ pos.z = 0.00f;
+ dim.x = (Rand()*0.04f+0.04f);
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, type, 0.5f+Rand()*0.5f, 0.0f, 1.0f, SH_INTERFACE);
+ }
+
+//? if ( m_bDisplayInfo && m_main->RetGlint() )
+ if ( FALSE )
+ {
+ pos.x = (Rand()-0.5f)*1.4f;
+ pos.y = (Rand()-0.5f)*1.4f+3.5f;
+ pos.z = (Rand()-0.5f)*1.4f;
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = (Rand()*0.5f+0.5f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 0.5f+Rand()*0.5f, 0.0f, 1.0f, sheet);
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pos.x = 0.60f+(Rand()-0.5f)*0.76f;
+ pos.y = 0.47f+(Rand()-0.5f)*0.90f;
+ pos.z = 0.00f;
+ r = rand()%4;
+ if ( r == 0 ) pos.x = 0.21f; // sur le bord gauche
+ else if ( r == 1 ) pos.x = 0.98f; // sur le bord droite
+ else if ( r == 2 ) pos.y = 0.02f; // sur le bord inférieur
+ else pos.y = 0.92f; // sur le bord supérieur
+ dim.x = (Rand()*0.02f+0.02f);
+ dim.y = dim.x/0.75f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 0.5f+Rand()*0.5f, 0.0f, 1.0f, SH_INTERFACE);
+ }
+ }
+ }
+
+ // Bouge le son.
+ if ( m_soundChannel != -1 )
+ {
+ if ( !m_sound->Position(m_soundChannel, m_object->RetPosition(0)) )
+ {
+ m_soundChannel = -1;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Démarre une action.
+
+Error CMotionToto::SetAction(int action, float time)
+{
+ Sound sound;
+
+ CMotion::SetAction(action, time);
+
+ m_bStartAction = TRUE;
+
+ sound = SOUND_CLICK;
+ if ( action == MT_ERROR ) sound = SOUND_ERROR;
+ if ( action == MT_WARNING ) sound = SOUND_WARNING;
+ if ( action == MT_INFO ) sound = SOUND_INFO;
+ if ( action == MT_MESSAGE ) sound = SOUND_MESSAGE;
+
+ if ( sound != SOUND_CLICK )
+ {
+ m_soundChannel = m_sound->Play(sound, m_object->RetPosition(0));
+ }
+
+ return ERR_OK;
+}
+
+// Spécifie le type de l'objet rattaché à toto.
+
+void CMotionToto::SetLinkType(ObjectType type)
+{
+ m_type = type;
+}
+
+
diff --git a/src/motiontoto.h b/src/motiontoto.h
new file mode 100644
index 0000000..e6821e8
--- /dev/null
+++ b/src/motiontoto.h
@@ -0,0 +1,61 @@
+// motiontoto.h
+
+#ifndef _MOTIONTOTO_H_
+#define _MOTIONTOTO_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define MT_ERROR 0
+#define MT_WARNING 1
+#define MT_INFO 2
+#define MT_MESSAGE 3
+
+
+class CMotionToto : public CMotion
+{
+public:
+ CMotionToto(CInstanceManager* iMan, CObject* object);
+ ~CMotionToto();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+ Error SetAction(int action, float time=0.2f);
+ void SetLinkType(ObjectType type);
+
+ void StartDisplayInfo();
+ void StopDisplayInfo();
+ void SetMousePos(FPOINT pos);
+
+protected:
+ BOOL EventFrame(const Event &event);
+
+protected:
+ float m_time;
+ float m_lastMotorParticule;
+ BOOL m_bDisplayInfo;
+ BOOL m_bQuickPos;
+ BOOL m_bStartAction;
+ float m_speedAction;
+ float m_clownRadius;
+ float m_clownDelay;
+ float m_clownTime;
+ float m_blinkTime;
+ float m_blinkProgress;
+ int m_soundChannel;
+ ObjectType m_type;
+ FPOINT m_mousePos;
+};
+
+
+#endif //_MOTIONTOTO_H_
diff --git a/src/motionvehicle.cpp b/src/motionvehicle.cpp
new file mode 100644
index 0000000..4546533
--- /dev/null
+++ b/src/motionvehicle.cpp
@@ -0,0 +1,2075 @@
+// motionvehicle.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionvehicle.h"
+
+
+
+#define ARM_NEUTRAL_ANGLE1 110.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE2 -130.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE3 -50.0f*PI/180.0f
+
+
+
+// Constructeur de l'objet.
+
+CMotionVehicle::CMotionVehicle(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ int i;
+
+ CMotion::CMotion(iMan, object);
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ m_wheelTurn[i] = 0.0f;
+ }
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_flyPaw[i] = 0.0f;
+ }
+ m_posTrackLeft = 0.0f;
+ m_posTrackRight = 0.0f;
+ m_partiReactor = -1;
+ m_armTimeAbs = 1000.0f;
+ m_armMember = 1000.0f;
+ m_canonTime = 0.0f;
+ m_lastTimeCanon = 0.0f;
+ m_wheelLastPos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_wheelLastAngle = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_posKey = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_bFlyFix = FALSE;
+
+ m_bTraceDown = FALSE;
+ m_traceColor = 1; // black
+ m_traceWidth = 0.5f;
+}
+
+// Destructeur de l'objet.
+
+CMotionVehicle::~CMotionVehicle()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionVehicle::DeleteObject(BOOL bAll)
+{
+ if ( m_partiReactor != -1 )
+ {
+ m_particule->DeleteParticule(m_partiReactor);
+ m_partiReactor = -1;
+ }
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionVehicle::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ CObject* pPower;
+ int rank, i, j, parent;
+ D3DCOLORVALUE color;
+ char name[50];
+
+ if ( m_engine->RetRestCreate() < 1+5+18+1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs )
+ {
+ pModFile->ReadModel("objects\\lem1f.mod");
+ }
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts )
+ {
+ pModFile->ReadModel("objects\\lem1t.mod");
+ }
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEws )
+ {
+ if ( m_object->RetTrainer() )
+ {
+ pModFile->ReadModel("objects\\lem1wt.mod");
+ }
+ else
+ {
+ pModFile->ReadModel("objects\\lem1w.mod");
+ }
+ }
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis )
+ {
+ pModFile->ReadModel("objects\\lem1i.mod");
+ }
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ pModFile->ReadModel("objects\\roller1.mod");
+ }
+ if ( type == OBJECT_MOBILEsa )
+ {
+ pModFile->ReadModel("objects\\subm1.mod");
+ }
+ if ( type == OBJECT_MOBILEtg )
+ {
+ pModFile->ReadModel("objects\\target.mod");
+ }
+ if ( type == OBJECT_MOBILEwt )
+ {
+ pModFile->ReadModel("objects\\trainerw.mod");
+ }
+ if ( type == OBJECT_MOBILEft )
+ {
+ pModFile->ReadModel("objects\\trainerf.mod");
+ }
+ if ( type == OBJECT_MOBILEtt )
+ {
+ pModFile->ReadModel("objects\\trainert.mod");
+ }
+ if ( type == OBJECT_MOBILEit )
+ {
+ pModFile->ReadModel("objects\\traineri.mod");
+ }
+ if ( type == OBJECT_MOBILEdr )
+ {
+ pModFile->ReadModel("objects\\drawer1.mod");
+ }
+ if ( type == OBJECT_APOLLO2 )
+ {
+ pModFile->ReadModel("objects\\apolloj1.mod");
+ }
+ pModFile->CreateEngineObject(rank);
+
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 6.5f, SOUND_BOUMm, 0.45f);
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 7.0f);
+ }
+ else if ( type == OBJECT_MOBILEsa )
+ {
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 4.5f, SOUND_BOUMm, 0.45f);
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 6.0f);
+ }
+ else if ( type == OBJECT_MOBILEdr )
+ {
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 7.0f);
+ }
+ else if ( type == OBJECT_APOLLO2 )
+ {
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ }
+ else
+ {
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 4.5f, SOUND_BOUMm, 0.45f);
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 6.0f);
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia )
+ {
+ // Crée le bras.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\lem2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 5.3f, 0.0f));
+ m_object->SetAngleZ(1, ARM_NEUTRAL_ANGLE1);
+
+ // Crée l'avant-bras.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\lem3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(5.0f, 0.0f, 0.0f));
+ m_object->SetAngleZ(2, ARM_NEUTRAL_ANGLE2);
+
+ // Crée la main.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\lem4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(3.5f, 0.0f, 0.0f));
+ m_object->SetAngleZ(3, ARM_NEUTRAL_ANGLE3);
+ m_object->SetAngleX(3, PI/2.0f);
+
+ // Crée la pince proche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 3);
+ pModFile->ReadModel("objects\\lem5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(1.5f, 0.0f, 0.0f));
+ m_object->SetAngleZ(4, -PI*0.10f);
+
+ // Crée la pince éloignée.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 3);
+ pModFile->ReadModel("objects\\lem6.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(1.5f, 0.0f, 0.0f));
+ m_object->SetAngleZ(5, PI*0.10f);
+ }
+
+ if ( type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis )
+ {
+ // Crée le bras.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\lem2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 5.3f, 0.0f));
+ m_object->SetAngleZ(1, 110.0f*PI/180.0f);
+
+ // Crée l'avant-bras.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\lem3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(5.0f, 0.0f, 0.0f));
+ m_object->SetAngleZ(2, -110.0f*PI/180.0f);
+
+ // Crée le capteur.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\lem4s.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(3.5f, 0.0f, 0.0f));
+ m_object->SetAngleZ(3, -65.0f*PI/180.0f);
+ }
+
+ if ( type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic )
+ {
+ // Crée le canon.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\canon.mod");
+ pModFile->CreateEngineObject(rank);
+//? m_object->SetPosition(1, D3DVECTOR(0.0f, 5.3f, 0.0f));
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 5.3f, 0.0f));
+ m_object->SetAngleZ(1, 0.0f);
+ }
+
+ if ( type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii )
+ {
+ // Crée le canon insecte.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\canoni1.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 5.3f, 0.0f));
+ m_object->SetAngleZ(1, 0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\canoni2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(0.0f, 2.5f, 0.0f));
+ m_object->SetAngleZ(2, 0.0f);
+ }
+
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEwt )
+ {
+ // Crée la roue arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(-3.0f, 1.0f, -3.0f));
+
+ // Crée la roue arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(-3.0f, 1.0f, 3.0f));
+ m_object->SetAngleY(7, PI);
+
+ // Crée la roue avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(2.0f, 1.0f, -3.0f));
+
+ // Crée la roue avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(2.0f, 1.0f, 3.0f));
+ m_object->SetAngleY(9, PI);
+ }
+
+ if ( type == OBJECT_MOBILEtg )
+ {
+ // Crée la roue arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(-2.0f, 1.0f, -3.0f));
+
+ // Crée la roue arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(-2.0f, 1.0f, 3.0f));
+ m_object->SetAngleY(7, PI);
+
+ // Crée la roue avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(3.0f, 1.0f, -3.0f));
+
+ // Crée la roue avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 0);
+ pModFile->ReadModel("objects\\lem2w.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(3.0f, 1.0f, 3.0f));
+ m_object->SetAngleY(9, PI);
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ) // chenilles ?
+ {
+ // Crée la chenille droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\lem2t.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.0f, 2.0f, -3.0f));
+
+ // Crée la chenille gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\lem3t.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 2.0f, 3.0f));
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ // Crée la chenille droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\roller2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.0f, 2.0f, -3.0f));
+
+ // Crée la chenille gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\roller3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 2.0f, 3.0f));
+ }
+
+ if ( type == OBJECT_MOBILEsa ) // chenilles sous-marin ?
+ {
+ // Crée la chenille droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\subm4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.0f, 1.0f, -3.0f));
+
+ // Crée la chenille gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\subm5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 1.0f, 3.0f));
+ }
+
+ if ( type == OBJECT_MOBILEdr ) // chenilles ?
+ {
+ // Crée la chenille droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\drawer2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(0.0f, 1.0f, -3.0f));
+
+ // Crée la chenille gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\drawer3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(0.0f, 1.0f, 3.0f));
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+ // Crée le pied avant.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\lem2f.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(1.7f, 3.0f, 0.0f));
+
+ // Crée le pied arrière droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\lem2f.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(-1.8f, 3.0f, -1.5f));
+ m_object->SetAngleY(7, 120.0f*PI/180.0f);
+
+ // Crée le pied arrière gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\lem2f.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(-1.8f, 3.0f, 1.5f));
+ m_object->SetAngleY(8, -120.0f*PI/180.0f);
+ }
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEii ) // pattes d'insecte ?
+ {
+ float table[] =
+ {
+ // x y z
+ -1.5f, 1.2f, -0.7f, // patte arrière
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -2.0f,
+
+ 0.0f, 1.2f, -0.9f, // patte milieu
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -2.0f,
+
+ 1.5f, 1.2f, -0.7f, // patte avant
+ 0.0f, 0.0f, -1.0f,
+ 0.0f, 0.0f, -2.0f,
+ };
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ for ( j=0 ; j<3 ; j++ )
+ {
+ sprintf(name, "objects\\ant%d.mod", j+4); // 4..6
+
+ // Crée la patte droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6+i*3+j, rank);
+ if ( j == 0 ) parent = 0;
+ else parent = 6+i*3+j-1;
+ m_object->SetObjectParent(6+i*3+j, parent);
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+ pos.x = table[i*9+j*3+0];
+ pos.y = table[i*9+j*3+1];
+ pos.z = table[i*9+j*3+2];
+ m_object->SetPosition(6+i*3+j, pos);
+
+ // Crée la patte gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(15+i*3+j, rank);
+ if ( j == 0 ) parent = 0;
+ else parent = 15+i*3+j-1;
+ m_object->SetObjectParent(15+i*3+j, parent);
+ pModFile->ReadModel(name);
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ pos.x = table[i*9+j*3+0];
+ pos.y = table[i*9+j*3+1];
+ pos.z = -table[i*9+j*3+2];
+ m_object->SetPosition(15+i*3+j, pos);
+ }
+ }
+ }
+
+ if ( type == OBJECT_MOBILErt )
+ {
+ // Crée le support.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\roller2t.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetAngleZ(1, 0.0f);
+
+ // Crée le pilon.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\roller3t.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(9.0f, 4.0f, 0.0f));
+ m_object->SetAngleZ(2, 0.0f);
+ }
+
+ if ( type == OBJECT_MOBILErc )
+ {
+ // Crée le support.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\roller2c.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(3.0f, 4.6f, 0.0f));
+ m_object->SetAngleZ(1, PI/8.0f);
+
+ // Crée le canon.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\roller3p.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(7.0f, 6.5f, 0.0f));
+ m_object->SetAngleZ(2, 0.0f);
+ }
+
+ if ( type == OBJECT_MOBILErr )
+ {
+ // Crée le support.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\recover1.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(2.0f, 5.0f, 0.0f));
+
+ // Crée le bras droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\recover2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(0.1f, 0.0f, -5.0f));
+ m_object->SetAngleZ(2, 126.0f*PI/180.0f);
+
+ // Crée l'avant-bras droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\recover3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(5.0f, 0.0f, -0.5f));
+ m_object->SetAngleZ(3, -144.0f*PI/180.0f);
+
+ // Crée le bras gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(4, rank);
+ m_object->SetObjectParent(4, 1);
+ pModFile->ReadModel("objects\\recover2.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(4, D3DVECTOR(0.1f, 0.0f, 5.0f));
+ m_object->SetAngleZ(4, 126.0f*PI/180.0f);
+
+ // Crée l'avant-bras gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(5, rank);
+ m_object->SetObjectParent(5, 4);
+ pModFile->ReadModel("objects\\recover3.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(5, D3DVECTOR(5.0f, 0.0f, 0.5f));
+ m_object->SetAngleZ(5, -144.0f*PI/180.0f);
+ }
+
+ if ( type == OBJECT_MOBILErs )
+ {
+ // Crée le support.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\roller2s.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetAngleZ(1, 0.0f);
+
+ // Crée le piston intermédiaire.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\roller3s.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(7.0f, 4.5f, 0.0f));
+ m_object->SetAngleZ(2, 0.0f);
+
+ // Crée le piston avec la sphère.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\roller4s.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(0.0f, 1.0f, 0.0f));
+ m_object->SetAngleZ(3, 0.0f);
+ }
+
+ if ( type == OBJECT_MOBILEsa )
+ {
+ // Crée le support.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\subm2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(4.2f, 3.0f, 0.0f));
+
+ // Crée la pince droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\subm3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(0.5f, 0.0f, -1.5f));
+
+ // Crée la pince gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(3, rank);
+ m_object->SetObjectParent(3, 1);
+ pModFile->ReadModel("objects\\subm3.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(3, D3DVECTOR(0.5f, 0.0f, 1.5f));
+ }
+
+ if ( type == OBJECT_MOBILEdr )
+ {
+ // Crée le carousel.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\drawer4.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(-3.0f, 3.0f, 0.0f));
+
+ // Crée la clé.
+ if ( m_object->RetToy() )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\drawer5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_posKey = D3DVECTOR(3.0f, 5.7f, 0.0f);
+ m_object->SetPosition(2, m_posKey);
+ m_object->SetAngleY(2, 90.0f*PI/180.0f);
+ }
+
+ // Crée les crayons.
+ for ( i=0 ; i<8 ; i++ )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(10+i, rank);
+ m_object->SetObjectParent(10+i, 1);
+ sprintf(name, "objects\\drawer%d.mod", 10+i);
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(10+i, D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetAngleY(10+i, 45.0f*PI/180.0f*i);
+ }
+ }
+
+ if ( type == OBJECT_MOBILEwt )
+ {
+ // Crée la clé.
+ if ( m_object->RetToy() )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\drawer5.mod");
+ pModFile->CreateEngineObject(rank);
+ m_posKey = D3DVECTOR(0.2f, 4.1f, 0.0f);
+ m_object->SetPosition(2, m_posKey);
+ m_object->SetAngleY(2, 90.0f*PI/180.0f);
+ }
+ }
+
+ if ( type == OBJECT_APOLLO2 )
+ {
+ // Crée les accessoirs.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\apolloj2.mod"); // antenne
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(5.5f, 8.8f, 2.0f));
+ m_object->SetAngleY(1, -120.0f*PI/180.0f);
+ m_object->SetAngleZ(1, 45.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2, rank);
+ m_object->SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\apolloj3.mod"); // caméra
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2, D3DVECTOR(5.5f, 2.8f, -2.0f));
+ m_object->SetAngleY(2, 30.0f*PI/180.0f);
+
+ // Crée les roues.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(6, rank);
+ m_object->SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(6, D3DVECTOR(-5.75f, 1.65f, -5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(7, rank);
+ m_object->SetObjectParent(7, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(7, D3DVECTOR(-5.75f, 1.65f, 5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(8, rank);
+ m_object->SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(8, D3DVECTOR(5.75f, 1.65f, -5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(9, rank);
+ m_object->SetObjectParent(9, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(9, D3DVECTOR(5.75f, 1.65f, 5.00f));
+
+ // Crée les gardes boues.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(10, rank);
+ m_object->SetObjectParent(10, 0);
+ pModFile->ReadModel("objects\\apolloj6.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(10, D3DVECTOR(-5.75f, 1.65f, -5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(11, rank);
+ m_object->SetObjectParent(11, 0);
+ pModFile->ReadModel("objects\\apolloj6.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(11, D3DVECTOR(-5.75f, 1.65f, 5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(12, rank);
+ m_object->SetObjectParent(12, 0);
+ pModFile->ReadModel("objects\\apolloj5.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(12, D3DVECTOR(5.75f, 1.65f, -5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(13, rank);
+ m_object->SetObjectParent(13, 0);
+ pModFile->ReadModel("objects\\apolloj5.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(13, D3DVECTOR(5.75f, 1.65f, 5.00f));
+ }
+
+#if 1
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ m_object->CreateShadowCircle(6.0f, 1.0f);
+ }
+ else if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEsa )
+ {
+ m_object->CreateShadowCircle(5.0f, 1.0f);
+ }
+ else if ( type == OBJECT_MOBILEdr )
+ {
+ m_object->CreateShadowCircle(4.5f, 1.0f);
+ }
+ else if ( type == OBJECT_APOLLO2 )
+ {
+ m_object->CreateShadowCircle(7.0f, 0.8f);
+ }
+ else
+ {
+ m_object->CreateShadowCircle(4.0f, 1.0f);
+ }
+#else
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ m_object->CreateShadowCircle(6.0f, 1.0f, D3DSHADOWTANK);
+ }
+ else if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts )
+ {
+ m_object->CreateShadowCircle(4.0f, 1.0f, D3DSHADOWTANK);
+ }
+ else if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs )
+ {
+ m_object->CreateShadowCircle(4.0f, 1.0f, D3DSHADOWFLY);
+ }
+ else if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEws )
+ {
+ m_object->CreateShadowCircle(4.0f, 1.0f, D3DSHADOWWHEEL);
+ }
+ else if ( type == OBJECT_APOLLO2 )
+ {
+ m_object->CreateShadowCircle(6.0f, 0.8f);
+ }
+ else
+ {
+ m_object->CreateShadowCircle(4.0f, 1.0f, D3DSHADOWNORM);
+ }
+#endif
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+//? color.r = 0.5f-1.0f;
+//? color.g = 0.2f-1.0f;
+//? color.b = 0.0f-1.0f; // orange
+//? color.r = 0.8f;
+//? color.g = 0.6f;
+//? color.b = 0.0f; // jaune-orange
+ color.r = 0.0f;
+ color.g = 0.4f;
+ color.b = 0.8f; // bleu
+ color.a = 0.0f;
+ m_object->CreateShadowLight(50.0f, color);
+ }
+
+ CreatePhysics(type);
+ m_object->SetFloorHeight(0.0f);
+
+ if ( power > 0.0f &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_APOLLO2 )
+ {
+ color.r = 1.0f;
+ color.g = 1.0f;
+ color.b = 0.0f; // jaune
+ color.a = 0.0f;
+ m_object->CreateEffectLight(20.0f, color);
+
+ // Crée la pile.
+ pPower = new CObject(m_iMan);
+ pPower->SetType(power<=1.0f?OBJECT_POWER:OBJECT_ATOMIC);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ pPower->SetObjectRank(0, rank);
+
+ if ( power <= 1.0f ) pModFile->ReadModel("objects\\power.mod");
+ else pModFile->ReadModel("objects\\atomic.mod");
+ pModFile->CreateEngineObject(rank);
+
+ pPower->SetPosition(0, m_object->RetCharacter()->posPower);
+ pPower->CreateCrashSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ pPower->SetGlobalSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 1.5f);
+
+ pPower->SetTruck(m_object);
+ m_object->SetPower(pPower);
+
+ if ( power <= 1.0f ) pPower->SetEnergy(power);
+ else pPower->SetEnergy(power/100.0f);
+ }
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionVehicle::CreatePhysics(ObjectType type)
+{
+ Character* character;
+
+ character = m_object->RetCharacter();
+
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEwt ) // roues ?
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 3.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 4.0f;
+ character->wheelRight = 4.0f;
+ character->posPower = D3DVECTOR(-3.2f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 20.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 10.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 50.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 30.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 20.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.8f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.8f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 8.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 8.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 12.0f);
+ }
+
+ if ( type == OBJECT_MOBILEtg )
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 4.0f;
+ character->wheelBack = 3.0f;
+ character->wheelLeft = 4.0f;
+ character->wheelRight = 4.0f;
+ character->posPower = D3DVECTOR(-3.2f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 20.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 10.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 50.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 20.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 20.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.8f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.8f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 15.0f);
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ) // chenilles ?
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 4.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 4.8f;
+ character->wheelRight = 4.8f;
+ character->posPower = D3DVECTOR(-3.2f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 15.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 8.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 15.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 8.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 20.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 6.0f);
+ }
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis ) // pattes ?
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 4.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 5.0f;
+ character->wheelRight = 5.0f;
+ character->posPower = D3DVECTOR(-3.2f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 15.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 8.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 10.0f);
+//? m_physics->SetLinMotionX(MO_TERFORCE, 15.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 15.0f);
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+ m_physics->SetType(TYPE_FLYING);
+
+ character->wheelFront = 5.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 4.5f;
+ character->wheelRight = 4.5f;
+ character->posPower = D3DVECTOR(-3.2f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 50.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 50.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 50.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 50.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+ m_physics->SetLinMotionY(MO_ADVSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_RECSPEED, 60.0f);
+ m_physics->SetLinMotionY(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionY(MO_RECACCEL, 50.0f);
+ m_physics->SetLinMotionY(MO_STOACCEL, 50.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.4f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.4f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 2.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 2.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 2.0f);
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 5.0f;
+ character->wheelBack = 5.0f;
+ character->wheelLeft = 6.0f;
+ character->wheelRight = 6.0f;
+ character->posPower = D3DVECTOR(-5.8f, 4.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 10.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 5.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 5.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 20.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.3f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.3f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 2.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 2.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 4.0f);
+ }
+
+ if ( type == OBJECT_MOBILEsa )
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 4.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 4.0f;
+ character->wheelRight = 4.0f;
+ character->posPower = D3DVECTOR(-5.0f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 15.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 10.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 20.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 5.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 5.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 10.0f);
+ }
+
+ if ( type == OBJECT_MOBILEdr )
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 4.0f;
+ character->wheelBack = 4.0f;
+ character->wheelLeft = 4.0f;
+ character->wheelRight = 4.0f;
+ character->posPower = D3DVECTOR(-5.0f, 3.0f, 0.0f);
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 15.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 10.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 20.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.5f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 5.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 5.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 10.0f);
+ }
+
+ if ( type == OBJECT_APOLLO2 ) // jeep ?
+ {
+ m_physics->SetType(TYPE_ROLLING);
+
+ character->wheelFront = 6.0f;
+ character->wheelBack = 6.0f;
+ character->wheelLeft = 5.0f;
+ character->wheelRight = 5.0f;
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 15.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 10.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 20.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 2.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 2.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 30.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 10.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 20.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.4f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.4f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 2.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 2.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 4.0f);
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CMotionVehicle::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionVehicle::EventFrame(const Event &event)
+{
+ D3DMATRIX* mat;
+ Character* character;
+ D3DVECTOR pos, angle, floor;
+ ObjectType type;
+ float s, a, speedBL, speedBR, speedFL, speedFR, h, a1, a2;
+ float back, front, dist, radius, limit[2];
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return TRUE;
+
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_APOLLO2 ) // roues ?
+ {
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*1.0f;
+ a = m_physics->RetCirMotionY(MO_MOTSPEED)*3.0f;
+
+ if ( type == OBJECT_APOLLO2 ) s *= 0.5f;
+
+ speedBR = -s+a;
+ speedBL = s+a;
+ speedFR = -s+a;
+ speedFL = s+a;
+
+ m_object->SetAngleZ(6, m_object->RetAngleZ(6)+event.rTime*speedBR); // tourne les roues
+ m_object->SetAngleZ(7, m_object->RetAngleZ(7)+event.rTime*speedBL);
+ m_object->SetAngleZ(8, m_object->RetAngleZ(8)+event.rTime*speedFR);
+ m_object->SetAngleZ(9, m_object->RetAngleZ(9)+event.rTime*speedFL);
+
+ if ( s > 0.0f )
+ {
+ m_wheelTurn[0] = -a*0.05f;
+ m_wheelTurn[1] = -a*0.05f+PI;
+ m_wheelTurn[2] = a*0.05f;
+ m_wheelTurn[3] = a*0.05f+PI;
+ }
+ else if ( s < 0.0f )
+ {
+ m_wheelTurn[0] = a*0.05f;
+ m_wheelTurn[1] = a*0.05f+PI;
+ m_wheelTurn[2] = -a*0.05f;
+ m_wheelTurn[3] = -a*0.05f+PI;
+ }
+ else
+ {
+ m_wheelTurn[0] = Abs(a)*0.05f;
+ m_wheelTurn[1] = -Abs(a)*0.05f+PI;
+ m_wheelTurn[2] = -Abs(a)*0.05f;
+ m_wheelTurn[3] = Abs(a)*0.05f+PI;
+ }
+ m_object->SetAngleY(6, m_object->RetAngleY(6)+(m_wheelTurn[0]-m_object->RetAngleY(6))*event.rTime*8.0f);
+ m_object->SetAngleY(7, m_object->RetAngleY(7)+(m_wheelTurn[1]-m_object->RetAngleY(7))*event.rTime*8.0f);
+ m_object->SetAngleY(8, m_object->RetAngleY(8)+(m_wheelTurn[2]-m_object->RetAngleY(8))*event.rTime*8.0f);
+ m_object->SetAngleY(9, m_object->RetAngleY(9)+(m_wheelTurn[3]-m_object->RetAngleY(9))*event.rTime*8.0f);
+
+ if ( type == OBJECT_APOLLO2 )
+ {
+ m_object->SetAngleY(10, m_object->RetAngleY(6)+(m_wheelTurn[0]-m_object->RetAngleY(6))*event.rTime*8.0f);
+ m_object->SetAngleY(11, m_object->RetAngleY(7)+(m_wheelTurn[1]-m_object->RetAngleY(7))*event.rTime*8.0f+PI);
+ m_object->SetAngleY(12, m_object->RetAngleY(8)+(m_wheelTurn[2]-m_object->RetAngleY(8))*event.rTime*8.0f);
+ m_object->SetAngleY(13, m_object->RetAngleY(9)+(m_wheelTurn[3]-m_object->RetAngleY(9))*event.rTime*8.0f+PI);
+ }
+
+ pos = m_object->RetPosition(0);
+ angle = m_object->RetAngle(0);
+ if ( pos.x != m_wheelLastPos.x ||
+ pos.y != m_wheelLastPos.y ||
+ pos.z != m_wheelLastPos.z ||
+ angle.x != m_wheelLastAngle.x ||
+ angle.y != m_wheelLastAngle.y ||
+ angle.z != m_wheelLastAngle.z )
+ {
+ m_wheelLastPos = pos;
+ m_wheelLastAngle = angle;
+
+ if ( type == OBJECT_MOBILEtg )
+ {
+ back = -2.0f; // position roues arrières
+ front = 3.0f; // position roues avants
+ dist = 3.0f; // éloignement roues Z
+ radius = 1.0f;
+ }
+ else if ( type == OBJECT_APOLLO2 )
+ {
+ back = -5.75f; // position roues arrières
+ front = 5.75f; // position roues avants
+ dist = 5.00f; // éloignement roues Z
+ radius = 1.65f;
+ }
+ else
+ {
+ back = -3.0f; // position roues arrières
+ front = 2.0f; // position roues avants
+ dist = 3.0f; // éloignement roues Z
+ radius = 1.0f;
+ }
+
+ if ( Length(pos, m_engine->RetEyePt()) < 50.0f ) // suspension ?
+ {
+ character = m_object->RetCharacter();
+ mat = m_object->RetWorldMatrix(0);
+
+ pos.x = -character->wheelBack; // roue arrière droite
+ pos.z = -character->wheelRight;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ h = m_terrain->RetFloorHeight(pos);
+ if ( h > 0.5f ) h = 0.5f;
+ if ( h < -0.5f ) h = -0.5f;
+ pos.x = back;
+ pos.y = radius-h;
+ pos.z = -dist;
+ m_object->SetPosition(6, pos);
+ if ( type == OBJECT_APOLLO2 ) m_object->SetPosition(10, pos);
+
+ pos.x = -character->wheelBack; // roue arrière gauche
+ pos.z = character->wheelLeft;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ h = m_terrain->RetFloorHeight(pos);
+ if ( h > 0.5f ) h = 0.5f;
+ if ( h < -0.5f ) h = -0.5f;
+ pos.x = back;
+ pos.y = radius-h;
+ pos.z = dist;
+ m_object->SetPosition(7, pos);
+ if ( type == OBJECT_APOLLO2 ) m_object->SetPosition(11, pos);
+
+ pos.x = character->wheelFront; // roue avant droite
+ pos.z = -character->wheelRight;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ h = m_terrain->RetFloorHeight(pos);
+ if ( h > 0.5f ) h = 0.5f;
+ if ( h < -0.5f ) h = -0.5f;
+ pos.x = front;
+ pos.y = radius-h;
+ pos.z = -dist;
+ m_object->SetPosition(8, pos);
+ if ( type == OBJECT_APOLLO2 ) m_object->SetPosition(12, pos);
+
+ pos.x = character->wheelFront; // roue avant gauche
+ pos.z = character->wheelLeft;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ h = m_terrain->RetFloorHeight(pos);
+ if ( h > 0.5f ) h = 0.5f;
+ if ( h < -0.5f ) h = -0.5f;
+ pos.x = front;
+ pos.y = radius-h;
+ pos.z = dist;
+ m_object->SetPosition(9, pos);
+ if ( type == OBJECT_APOLLO2 ) m_object->SetPosition(13, pos);
+ }
+ else
+ {
+ m_object->SetPosition(6, D3DVECTOR(back, radius, -dist));
+ m_object->SetPosition(7, D3DVECTOR(back, radius, dist));
+ m_object->SetPosition(8, D3DVECTOR(front, radius, -dist));
+ m_object->SetPosition(9, D3DVECTOR(front, radius, dist));
+
+ if ( type == OBJECT_APOLLO2 )
+ {
+ m_object->SetPosition(10, D3DVECTOR(back, radius, -dist));
+ m_object->SetPosition(11, D3DVECTOR(back, radius, dist));
+ m_object->SetPosition(12, D3DVECTOR(front, radius, -dist));
+ m_object->SetPosition(13, D3DVECTOR(front, radius, dist));
+ }
+ }
+ }
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEdr ) // chenilles ?
+ {
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*0.7f;
+ a = m_physics->RetCirMotionY(MO_MOTSPEED)*2.5f;
+
+ m_posTrackLeft += event.rTime*(s+a);
+ m_posTrackRight += event.rTime*(s-a);
+
+ UpdateTrackMapping(m_posTrackLeft, m_posTrackRight, type);
+
+ pos = m_object->RetPosition(0);
+ angle = m_object->RetAngle(0);
+ if ( pos.x != m_wheelLastPos.x ||
+ pos.y != m_wheelLastPos.y ||
+ pos.z != m_wheelLastPos.z ||
+ angle.x != m_wheelLastAngle.x ||
+ angle.y != m_wheelLastAngle.y ||
+ angle.z != m_wheelLastAngle.z )
+ {
+ m_wheelLastPos = pos;
+ m_wheelLastAngle = angle;
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts )
+ {
+ limit[0] = 8.0f*PI/180.0f;
+ limit[1] = -12.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_MOBILEsa )
+ {
+ limit[0] = 15.0f*PI/180.0f;
+ limit[1] = -15.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_MOBILEdr )
+ {
+ limit[0] = 10.0f*PI/180.0f;
+ limit[1] = -10.0f*PI/180.0f;
+ }
+ else
+ {
+ limit[0] = 15.0f*PI/180.0f;
+ limit[1] = -10.0f*PI/180.0f;
+ }
+
+ if ( Length(pos, m_engine->RetEyePt()) < 50.0f ) // suspension ?
+ {
+ character = m_object->RetCharacter();
+ mat = m_object->RetWorldMatrix(0);
+
+ pos.x = character->wheelFront; // roue avant droite
+ pos.z = -character->wheelRight;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ a1 = atanf(m_terrain->RetFloorHeight(pos)/character->wheelFront);
+
+ pos.x = -character->wheelBack; // roue arrière droite
+ pos.z = -character->wheelRight;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ a2 = atanf(m_terrain->RetFloorHeight(pos)/character->wheelBack);
+
+ a = (a2-a1)/2.0f;
+ if ( a > limit[0] ) a = limit[0];
+ if ( a < limit[1] ) a = limit[1];
+ m_object->SetAngleZ(6, a);
+
+ pos.x = character->wheelFront; // roue avant gauche
+ pos.z = character->wheelLeft;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ a1 = atanf(m_terrain->RetFloorHeight(pos)/character->wheelFront);
+
+ pos.x = -character->wheelBack; // roue arrière gauche
+ pos.z = character->wheelLeft;
+ pos.y = 0.0f;
+ pos = Transform(*mat, pos);
+ a2 = atanf(m_terrain->RetFloorHeight(pos)/character->wheelBack);
+
+ a = (a2-a1)/2.0f;
+ if ( a > limit[0] ) a = limit[0];
+ if ( a < limit[1] ) a = limit[1];
+ m_object->SetAngleZ(7, a);
+ }
+ else
+ {
+ m_object->SetAngleZ(6, 0.0f);
+ m_object->SetAngleZ(7, 0.0f);
+ }
+ }
+ }
+
+ if ( type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEdr ) // jouet à clé ?
+ {
+ pos = m_posKey;
+ if ( m_object->RetSelect() &&
+ m_camera->RetType() == CAMERA_ONBOARD )
+ {
+ pos.y += 10.0f; // hors du champ de vision !
+ }
+ m_object->SetPosition(2, pos);
+
+ s = -Abs(m_physics->RetLinMotionX(MO_MOTSPEED)*0.1f);
+ s += -Abs(m_physics->RetCirMotionY(MO_MOTSPEED)*1.5f);
+ m_object->SetAngleY(2, m_object->RetAngleY(2)+event.rTime*s); // tourne la clé
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+ EventFrameFly(event);
+ }
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis ) // pattes ?
+ {
+ EventFrameInsect(event);
+ }
+
+ if ( type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEii ) // canon-insecte ?
+ {
+ EventFrameCanoni(event);
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement pour un robot volant.
+
+BOOL CMotionVehicle::EventFrameFly(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, angle, paw[3];
+ float hope[3], actual, final, h, a;
+ int i;
+
+ pos = m_object->RetPosition(0);
+ angle = m_object->RetAngle(0);
+ if ( m_bFlyFix &&
+ pos.x == m_wheelLastPos.x &&
+ pos.y == m_wheelLastPos.y &&
+ pos.z == m_wheelLastPos.z &&
+ angle.x == m_wheelLastAngle.x &&
+ angle.y == m_wheelLastAngle.y &&
+ angle.z == m_wheelLastAngle.z ) return TRUE;
+
+ m_wheelLastPos = pos;
+ m_wheelLastAngle = angle;
+
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ mat = m_object->RetWorldMatrix(0);
+ paw[0] = Transform(*mat, D3DVECTOR( 4.2f, 0.0f, 0.0f)); // avant
+ paw[1] = Transform(*mat, D3DVECTOR(-3.0f, 0.0f, -3.7f)); // arrière droite
+ paw[2] = Transform(*mat, D3DVECTOR(-3.0f, 0.0f, 3.7f)); // arrière gauche
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ h = m_terrain->RetFloorHeight(paw[i]);
+ a = -atanf(h*0.5f);
+ if ( a > PI*0.2f ) a = PI*0.2f;
+ if ( a < -PI*0.2f ) a = -PI*0.2f;
+ hope[i] = a;
+ }
+ }
+ else // en vol ?
+ {
+ hope[0] = 0.0f; // avant
+ hope[1] = 0.0f; // arrière droite
+ hope[2] = 0.0f; // arrière gauche
+ }
+
+ m_bFlyFix = TRUE;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ actual = m_object->RetAngleZ(6+i);
+ final = Smooth(actual, hope[i], event.rTime*5.0f);
+ if ( final != actual )
+ {
+ m_bFlyFix = FALSE; // ça a bougé
+ m_object->SetAngleZ(6+i, final);
+ }
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement pour un insecte à pattes.
+
+BOOL CMotionVehicle::EventFrameInsect(const Event &event)
+{
+ D3DVECTOR dir;
+ float s, a, prog, time;
+ int i, st, nd, action;
+ BOOL bStop, bOnBoard;
+
+ static int table[] =
+ {
+ // x1,y1,z1, x2,y2,z2, x3,y3,z3, // en l'air :
+ 60,25,0, 60,0,0, 60,-25,0, // t0: cuisses 1..4
+ -35,0,0, -35,0,0, -35,0,0, // t0: jambes 1..4
+ -65,0,0, -65,0,0, -65,0,0, // t0: pieds 1..4
+ // au sol devant :
+ 30,10,0, 30,-15,0, 30,-40,0, // t1: cuisses 1..4
+ -45,0,0, -45,0,0, -45,0,0, // t1: jambes 1..4
+ -20,0,0, -20,0,0, -20,0,0, // t1: pieds 1..4
+ // au sol derrière :
+ 35,40,0, 40,15,0, 40,-10,0, // t2: cuisses 1..4
+ -35,0,0, -35,0,0, -35,0,0, // t2: jambes 1..4
+ -50,0,0, -65,0,0, -65,0,0, // t2: pieds 1..4
+ // stoppe :
+ 35,35,0, 40,10,0, 40,-15,0, // s0: cuisses 1..4
+ -35,0,0, -35,0,0, -35,0,0, // s0: jambes 1..4
+ -50,0,0, -65,0,0, -65,0,0, // s0: pieds 1..4
+ };
+
+ bOnBoard = FALSE;
+ if ( m_object->RetSelect() &&
+ m_camera->RetType() == CAMERA_ONBOARD )
+ {
+ bOnBoard = TRUE;
+ }
+
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)*1.5f;
+ a = Abs(m_physics->RetCirMotionY(MO_MOTSPEED)*2.0f);
+
+ if ( s == 0.0f && a != 0.0f ) a *= 1.5f;
+
+ m_armTimeAbs += event.rTime;
+ m_armMember += (s+a)*event.rTime*0.15f;
+
+ bStop = ( a == 0.0f && s == 0.0f ); // à l'arrêt ?
+
+ action = 0; // marche
+ if ( s == 0.0f && a == 0.0f )
+ {
+ action = 3; // stop
+ }
+
+ if ( bStop )
+ {
+ prog = Mod(m_armTimeAbs, 2.0f)/10.0f;
+ a = Mod(m_armMember, 1.0f);
+ a = (prog-a)*event.rTime*2.0f; // vient gentiment à position stop
+ m_armMember += a;
+ }
+
+ if ( m_object->RetRuin() ) // brûle ou explose ?
+ {
+ action = 3;
+ }
+
+ for ( i=0 ; i<6 ; i++ ) // les 6 pattes
+ {
+ if ( action != 0 ) // action spéciale en cours ?
+ {
+ st = 3*3*3*action + (i%3)*3;
+ nd = st;
+ time = event.rTime*5.0f;
+ }
+ else
+ {
+ if ( i < 3 ) prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.0f, 1.0f);
+ else prog = Mod(m_armMember+(2.0f-(i%3))*0.33f+0.3f, 1.0f);
+ if ( prog < 0.33f ) // t0..t1 ?
+ {
+ prog = prog/0.33f; // 0..1
+ st = 0; // index start
+ nd = 1; // index end
+ }
+ else if ( prog < 0.67f ) // t1..t2 ?
+ {
+ prog = (prog-0.33f)/0.33f; // 0..1
+ st = 1; // index start
+ nd = 2; // index end
+ }
+ else // t2..t0 ?
+ {
+ prog = (prog-0.67f)/0.33f; // 0..1
+ st = 2; // index start
+ nd = 0; // index end
+ }
+ st = 3*3*3*action + st*3*3*3 + (i%3)*3;
+ nd = 3*3*3*action + nd*3*3*3 + (i%3)*3;
+
+ // De moins en moins mou ...
+ time = event.rTime*20.0f;
+ }
+
+ if ( i < 3 ) // patte droite (1..3) ?
+ {
+ m_object->SetAngleX(6+3*i+0, Smooth(m_object->RetAngleX(6+3*i+0), Prop(table[st+ 0], table[nd+ 0], prog), time));
+ m_object->SetAngleY(6+3*i+0, Smooth(m_object->RetAngleY(6+3*i+0), Prop(table[st+ 1], table[nd+ 1], prog), time));
+ m_object->SetAngleZ(6+3*i+0, Smooth(m_object->RetAngleZ(6+3*i+0), Prop(table[st+ 2], table[nd+ 2], prog), time));
+ m_object->SetAngleX(6+3*i+1, Smooth(m_object->RetAngleX(6+3*i+1), Prop(table[st+ 9], table[nd+ 9], prog), time));
+ m_object->SetAngleY(6+3*i+1, Smooth(m_object->RetAngleY(6+3*i+1), Prop(table[st+10], table[nd+10], prog), time));
+ m_object->SetAngleZ(6+3*i+1, Smooth(m_object->RetAngleZ(6+3*i+1), Prop(table[st+11], table[nd+11], prog), time));
+ m_object->SetAngleX(6+3*i+2, Smooth(m_object->RetAngleX(6+3*i+2), Prop(table[st+18], table[nd+18], prog), time));
+ m_object->SetAngleY(6+3*i+2, Smooth(m_object->RetAngleY(6+3*i+2), Prop(table[st+19], table[nd+19], prog), time));
+ m_object->SetAngleZ(6+3*i+2, Smooth(m_object->RetAngleZ(6+3*i+2), Prop(table[st+20], table[nd+20], prog), time));
+ }
+ else // patte gauche (4..6) ?
+ {
+ m_object->SetAngleX(6+3*i+0, Smooth(m_object->RetAngleX(6+3*i+0), Prop(-table[st+ 0], -table[nd+ 0], prog), time));
+ m_object->SetAngleY(6+3*i+0, Smooth(m_object->RetAngleY(6+3*i+0), Prop(-table[st+ 1], -table[nd+ 1], prog), time));
+ m_object->SetAngleZ(6+3*i+0, Smooth(m_object->RetAngleZ(6+3*i+0), Prop( table[st+ 2], table[nd+ 2], prog), time));
+ m_object->SetAngleX(6+3*i+1, Smooth(m_object->RetAngleX(6+3*i+1), Prop(-table[st+ 9], -table[nd+ 9], prog), time));
+ m_object->SetAngleY(6+3*i+1, Smooth(m_object->RetAngleY(6+3*i+1), Prop(-table[st+10], -table[nd+10], prog), time));
+ m_object->SetAngleZ(6+3*i+1, Smooth(m_object->RetAngleZ(6+3*i+1), Prop( table[st+11], table[nd+11], prog), time));
+ m_object->SetAngleX(6+3*i+2, Smooth(m_object->RetAngleX(6+3*i+2), Prop(-table[st+18], -table[nd+18], prog), time));
+ m_object->SetAngleY(6+3*i+2, Smooth(m_object->RetAngleY(6+3*i+2), Prop(-table[st+19], -table[nd+19], prog), time));
+ m_object->SetAngleZ(6+3*i+2, Smooth(m_object->RetAngleZ(6+3*i+2), Prop( table[st+20], table[nd+20], prog), time));
+ }
+ }
+
+ if ( bStop )
+ {
+ }
+ else
+ {
+ a = Mod(m_armMember, 1.0f);
+ if ( a < 0.5f ) a = -1.0f+4.0f*a; // -1..1
+ else a = 3.0f-4.0f*a; // 1..-1
+ dir.x = sinf(a)*0.05f;
+
+ s = Mod(m_armMember/2.0f, 1.0f);
+ if ( s < 0.5f ) s = -1.0f+4.0f*s; // -1..1
+ else s = 3.0f-4.0f*s; // 1..-1
+ dir.z = sinf(s)*0.1f;
+
+ dir.y = 0.0f;
+
+ if ( bOnBoard ) dir *= 0.6f;
+ SetInclinaison(dir);
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement pour un canon-insecte.
+
+BOOL CMotionVehicle::EventFrameCanoni(const Event &event)
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float zoom, angle, energy, factor;
+ BOOL bOnBoard = FALSE;
+
+ m_canonTime += event.rTime;
+
+ if ( m_object->RetSelect() &&
+ m_camera->RetType() == CAMERA_ONBOARD )
+ {
+ bOnBoard = TRUE;
+ }
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ energy = 0.0f;
+ }
+ else
+ {
+ energy = power->RetEnergy();
+ }
+ if ( energy == 0.0f ) return TRUE;
+
+ factor = 0.5f+energy*0.5f;
+ if ( bOnBoard ) factor *= 0.8f;
+
+ zoom = 1.3f+
+ sinf(m_canonTime*PI*0.31f)*0.10f+
+ sinf(m_canonTime*PI*0.52f)*0.08f+
+ sinf(m_canonTime*PI*1.53f)*0.05f;
+ zoom *= factor;
+ m_object->SetZoomY(2, zoom);
+
+ zoom = 1.0f+
+ sinf(m_canonTime*PI*0.27f)*0.07f+
+ sinf(m_canonTime*PI*0.62f)*0.06f+
+ sinf(m_canonTime*PI*1.73f)*0.03f;
+ zoom *= factor;
+ m_object->SetZoomZ(2, zoom);
+
+ angle = sinf(m_canonTime*1.0f)*0.10f+
+ sinf(m_canonTime*1.3f)*0.15f+
+ sinf(m_canonTime*2.7f)*0.05f;
+ m_object->SetAngleX(2, angle);
+
+#if 0
+ m_lastTimeCanon -= event.rTime;
+ if ( m_lastTimeCanon <= 0.0f )
+ {
+ m_lastTimeCanon = m_engine->ParticuleAdapt(0.5f+Rand()*0.5f);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 8.0f;
+ speed.y = 7.0f+Rand()*3.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = 2.0f+Rand()*2.0f;
+ if ( Rand() < 0.5f ) speed.z = -speed.z;
+ mat = m_object->RetRotateMatrix(0);
+ speed = Transform(*mat, speed);
+ dim.x = Rand()*0.1f+0.1f;
+ if ( bOnBoard ) dim.x *= 0.4f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIORGANIC2, 2.0f, 10.0f);
+ }
+#endif
+
+ return TRUE;
+}
+
+
+// Met à jour le mapping de la texture des chenilles.
+
+void CMotionVehicle::UpdateTrackMapping(float left, float right, ObjectType type)
+{
+ D3DMATERIAL7 mat;
+ float limit[4];
+ int rRank, lRank, i;
+
+ ZeroMemory( &mat, sizeof(D3DMATERIAL7) );
+ mat.diffuse.r = 1.0f;
+ mat.diffuse.g = 1.0f;
+ mat.diffuse.b = 1.0f; // blanc
+ mat.ambient.r = 0.5f;
+ mat.ambient.g = 0.5f;
+ mat.ambient.b = 0.5f;
+
+ rRank = m_object->RetObjectRank(6);
+ lRank = m_object->RetObjectRank(7);
+
+
+ if ( type == OBJECT_MOBILEdr )
+ {
+ limit[0] = 0.0f;
+ limit[1] = 1000000.0f;
+ limit[2] = limit[1];
+ limit[3] = m_engine->RetLimitLOD(1);
+
+ m_engine->TrackTextureMapping(rRank, mat, D3DSTATEPART1, "drawer.tga", "",
+ limit[0], limit[1], D3DMAPPINGX,
+ right, 1.0f, 8.0f, 192.0f, 256.0f);
+
+ m_engine->TrackTextureMapping(lRank, mat, D3DSTATEPART2, "drawer.tga", "",
+ limit[0], limit[1], D3DMAPPINGX,
+ left, 1.0f, 8.0f, 192.0f, 256.0f);
+ }
+ else
+ {
+ limit[0] = 0.0f;
+ limit[1] = m_engine->RetLimitLOD(0);
+ limit[2] = limit[1];
+ limit[3] = m_engine->RetLimitLOD(1);
+
+ for ( i=0 ; i<2 ; i++ )
+ {
+ m_engine->TrackTextureMapping(rRank, mat, D3DSTATEPART1, "lemt.tga", "",
+ limit[i*2+0], limit[i*2+1], D3DMAPPINGX,
+ right, 1.0f, 8.0f, 192.0f, 256.0f);
+
+ m_engine->TrackTextureMapping(lRank, mat, D3DSTATEPART2, "lemt.tga", "",
+ limit[i*2+0], limit[i*2+1], D3DMAPPINGX,
+ left, 1.0f, 8.0f, 192.0f, 256.0f);
+ }
+ }
+
+}
+
+
+
+// Gestion de l'état du crayon du robot dessinateur.
+
+BOOL CMotionVehicle::RetTraceDown()
+{
+ return m_bTraceDown;
+}
+
+void CMotionVehicle::SetTraceDown(BOOL bDown)
+{
+ m_bTraceDown = bDown;
+}
+
+int CMotionVehicle::RetTraceColor()
+{
+ return m_traceColor;
+}
+
+void CMotionVehicle::SetTraceColor(int color)
+{
+ m_traceColor = color;
+}
+
+float CMotionVehicle::RetTraceWidth()
+{
+ return m_traceWidth;
+}
+
+void CMotionVehicle::SetTraceWidth(float width)
+{
+ m_traceWidth = width;
+}
+
+
diff --git a/src/motionvehicle.h b/src/motionvehicle.h
new file mode 100644
index 0000000..f7bbf0a
--- /dev/null
+++ b/src/motionvehicle.h
@@ -0,0 +1,63 @@
+// motionvehicle.h
+
+#ifndef _MOTIONVEHICLE_H_
+#define _MOTIONVEHICLE_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CMotionVehicle : public CMotion
+{
+public:
+ CMotionVehicle(CInstanceManager* iMan, CObject* object);
+ ~CMotionVehicle();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+
+ BOOL RetTraceDown();
+ void SetTraceDown(BOOL bDown);
+ int RetTraceColor();
+ void SetTraceColor(int color);
+ float RetTraceWidth();
+ void SetTraceWidth(float width);
+
+protected:
+ void CreatePhysics(ObjectType type);
+ BOOL EventFrame(const Event &event);
+ BOOL EventFrameFly(const Event &event);
+ BOOL EventFrameInsect(const Event &event);
+ BOOL EventFrameCanoni(const Event &event);
+ void UpdateTrackMapping(float left, float right, ObjectType type);
+
+protected:
+ float m_wheelTurn[4];
+ float m_flyPaw[3];
+ float m_posTrackLeft;
+ float m_posTrackRight;
+ int m_partiReactor;
+ float m_armTimeAbs;
+ float m_armMember;
+ float m_canonTime;
+ float m_lastTimeCanon;
+ D3DVECTOR m_wheelLastPos;
+ D3DVECTOR m_wheelLastAngle;
+ D3DVECTOR m_posKey;
+ BOOL m_bFlyFix;
+ BOOL m_bTraceDown;
+ int m_traceColor;
+ float m_traceWidth;
+};
+
+
+#endif //_MOTIONVEHICLE_H_
diff --git a/src/motionworm.cpp b/src/motionworm.cpp
new file mode 100644
index 0000000..aa575d9
--- /dev/null
+++ b/src/motionworm.cpp
@@ -0,0 +1,365 @@
+// motionworm.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "modfile.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionworm.h"
+
+
+
+#define START_TIME 1000.0f // début du temps relatif
+#define TIME_UPDOWN 2.0f // temps pour up/down
+#define DOWN_ALTITUDE 3.0f // distance sous terre
+#define WORM_PART 7 // nb de parties d'un ver
+
+
+
+// Constructeur de l'objet.
+
+CMotionWorm::CMotionWorm(CInstanceManager* iMan, CObject* object)
+ : CMotion(iMan, object)
+{
+ CMotion::CMotion(iMan, object);
+
+ m_timeUp = 18.0f;
+ m_timeDown = 18.0f;
+ m_armMember = START_TIME;
+ m_armTimeAbs = START_TIME;
+ m_armTimeMarch = START_TIME;
+ m_armTimeAction = START_TIME;
+ m_armTimeIndex = 0;
+ m_armPartIndex = 0;
+ m_armMemberIndex = 0;
+ m_armLinSpeed = 0.0f;
+ m_armCirSpeed = 0.0f;
+ m_armLastAction = -1;
+ m_specAction = -1;
+ m_lastParticule = 0.0f;
+ m_bArmStop = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CMotionWorm::~CMotionWorm()
+{
+}
+
+
+// Supprime un objet.
+
+void CMotionWorm::DeleteObject(BOOL bAll)
+{
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CMotionWorm::Create(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ int rank, i;
+ float px;
+
+ if ( m_engine->RetRestCreate() < 2+WORM_PART+1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ m_object->SetType(type);
+
+ // Crée la base principale.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEVEHICULE); // c'est un objet mobile
+ m_object->SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\worm0.mod"); // n'existe pas exprès !
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(0, pos);
+ m_object->SetAngleY(0, angle);
+
+ // Un véhicule doit avoir obligatoirement une sphère de
+ // collision avec un centre (0;y;0) (voir GetCrashSphere).
+ m_object->CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUM, 0.20f);
+ m_object->SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 5.0f);
+
+ px = 1.0f+WORM_PART/2;
+
+ // Crée la tête.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(1, rank);
+ m_object->SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\worm1.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(1, D3DVECTOR(px, 0.0f, 0.0f));
+ px -= 1.0f;
+
+ // Crée le corps.
+ for ( i=0 ; i<WORM_PART ; i++ )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2+i, rank);
+ m_object->SetObjectParent(2+i, 0);
+ pModFile->ReadModel("objects\\worm2.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2+i, D3DVECTOR(px, 0.0f, 0.0f));
+ px -= 1.0f;
+ }
+
+ // Crée la queue.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ m_object->SetObjectRank(2+WORM_PART, rank);
+ m_object->SetObjectParent(2+WORM_PART, 0);
+ pModFile->ReadModel("objects\\worm3.mod");
+ pModFile->CreateEngineObject(rank);
+ m_object->SetPosition(2+WORM_PART, D3DVECTOR(px, 0.0f, 0.0f));
+
+ m_object->CreateShadowCircle(0.0f, 1.0f, D3DSHADOWWORM);
+
+ CreatePhysics();
+ m_object->SetFloorHeight(0.0f);
+
+ pos = m_object->RetPosition(0);
+ m_object->SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée la physique de l'objet.
+
+void CMotionWorm::CreatePhysics()
+{
+ Character* character;
+
+ m_physics->SetType(TYPE_ROLLING);
+
+ character = m_object->RetCharacter();
+ character->wheelFront = 10.0f;
+ character->wheelBack = 10.0f;
+ character->wheelLeft = 2.0f;
+ character->wheelRight = 2.0f;
+ character->height = -0.2f;
+
+ m_physics->SetLinMotionX(MO_ADVSPEED, 3.0f);
+ m_physics->SetLinMotionX(MO_RECSPEED, 3.0f);
+ m_physics->SetLinMotionX(MO_ADVACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_RECACCEL, 10.0f);
+ m_physics->SetLinMotionX(MO_STOACCEL, 40.0f);
+ m_physics->SetLinMotionX(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERSLIDE, 5.0f);
+ m_physics->SetLinMotionX(MO_TERFORCE, 5.0f);
+ m_physics->SetLinMotionZ(MO_TERFORCE, 5.0f);
+ m_physics->SetLinMotionZ(MO_MOTACCEL, 40.0f);
+
+ m_physics->SetCirMotionY(MO_ADVSPEED, 0.2f*PI);
+ m_physics->SetCirMotionY(MO_RECSPEED, 0.2f*PI);
+ m_physics->SetCirMotionY(MO_ADVACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_RECACCEL, 10.0f);
+ m_physics->SetCirMotionY(MO_STOACCEL, 20.0f);
+}
+
+
+
+// Spécifie un paramètre spécial.
+
+BOOL CMotionWorm::SetParam(int rank, float value)
+{
+ if ( rank == 0 )
+ {
+ m_timeDown = value;
+ return TRUE;
+ }
+
+ if ( rank == 1 )
+ {
+ m_timeUp = value;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+float CMotionWorm::RetParam(int rank)
+{
+ if ( rank == 0 ) return m_timeDown;
+ if ( rank == 1 ) return m_timeUp;
+ return 0.0f;
+}
+
+
+
+// Gestion d'un événement.
+
+BOOL CMotionWorm::EventProcess(const Event &event)
+{
+ CMotion::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+ }
+
+ return TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CMotionWorm::EventFrame(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, p, angle, speed;
+ FPOINT center, pp, dim;
+ float height[WORM_PART+2];
+ float floor, a, s, px, curve, phase, h, zoom, radius;
+ int i, under;
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ s = m_physics->RetLinMotionX(MO_MOTSPEED)/m_physics->RetLinMotionX(MO_ADVSPEED);
+ a = m_physics->RetCirMotionY(MO_MOTSPEED)/m_physics->RetCirMotionY(MO_ADVSPEED);
+
+ if ( s == 0.0f && a != 0.0f ) s = a;
+
+ m_armLinSpeed += (s-m_armLinSpeed)*event.rTime*3.0f;
+ m_armCirSpeed += (a-m_armCirSpeed)*event.rTime*1.5f;
+
+ m_armTimeAbs += event.rTime;
+ m_armTimeMarch += event.rTime*m_armLinSpeed;
+
+ under = 0; // aucun morceau sous terre
+ for ( i=0 ; i<WORM_PART+2 ; i++ )
+ {
+ phase = Mod(m_armTimeMarch-START_TIME-i*0.3f, TIME_UPDOWN+m_timeDown+TIME_UPDOWN+m_timeUp);
+ if ( phase < TIME_UPDOWN ) // descend ?
+ {
+ h = -(phase/TIME_UPDOWN)*DOWN_ALTITUDE;
+ }
+ else if ( phase < TIME_UPDOWN+m_timeDown ) // avance sous terre ?
+ {
+ h = -DOWN_ALTITUDE;
+ under ++; // un morceau entièrement sous terre de plus
+ }
+ else if ( phase < TIME_UPDOWN+m_timeDown+TIME_UPDOWN ) // monte ?
+ {
+ h = -(1.0f-(phase-TIME_UPDOWN-m_timeDown)/TIME_UPDOWN)*DOWN_ALTITUDE;
+ }
+ else // avance sur terre ?
+ {
+ h = 0.0f;
+ }
+ if ( m_object->RetBurn() ) // brûle ?
+ {
+ h = 0.0f; // reste sur terre
+ }
+ h += 0.3f;
+ height[i] = h;
+ }
+ m_object->SetVisible(under!=WORM_PART+2);
+
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return TRUE;
+
+ pos = m_object->RetPosition(0);
+ floor = m_terrain->RetFloorLevel(pos, TRUE);
+
+ mat = m_object->RetWorldMatrix(0);
+
+ px = 1.0f+WORM_PART/2;
+ for ( i=0 ; i<WORM_PART+2 ; i++ )
+ {
+ radius = 1.0f+(height[i]-0.3f)/DOWN_ALTITUDE; // 0=sous terre, 1=surface
+ radius = radius*1.3f-0.3f;
+ if ( radius < 0.0f ) radius = 0.0f;
+ radius *= 5.0f;
+ m_engine->SetObjectShadowRadius(m_object->RetObjectRank(0), radius);
+
+ pos.x = px+ sinf(m_armTimeMarch*4.0f+0.5f*i)*0.6f;
+ pos.y = height[i]+sinf(m_armTimeMarch*4.0f+0.5f*i)*0.2f*m_armLinSpeed;
+ pos.y += sinf(m_armTimeAbs *1.3f+0.2f*i)*0.1f;
+ pos.z = sinf(m_armTimeAbs *2.0f+0.7f*i)*0.2f;
+
+ curve = ((float)i-(WORM_PART+2)/2)*m_armCirSpeed*0.1f;
+ center.x = 0.0f;
+ center.y = 0.0f;
+ pp.x = pos.x;
+ pp.y = pos.z;
+ pp = RotatePoint(center, curve, pp);
+ pos.x = pp.x;
+ pos.z = pp.y;
+
+ p = Transform(*mat, pos);
+ pos.y += m_terrain->RetFloorLevel(p, TRUE)-floor;
+ m_object->SetPosition(i+1, pos);
+
+ zoom = Mod(m_armTimeAbs*0.5f+100.0f-i*0.1f, 2.0f);
+ if ( zoom > 1.0f ) zoom = 2.0f-zoom;
+ zoom *= 1.6f;
+ if ( zoom < 1.0f ) zoom = 1.0f;
+ m_object->SetZoomY(i+1, 0.2f+zoom*0.8f);
+ m_object->SetZoomZ(i+1, zoom);
+
+ if ( height[i] >= -1.0f && height[i] < -0.2f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.2f) <= m_armTimeMarch )
+ {
+ m_lastParticule = m_armTimeMarch;
+
+ pos = p;
+ pos.y += -height[i];
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*2.0f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+
+ px -= 1.0f;
+ }
+
+ for ( i=0 ; i<WORM_PART+1 ; i++ )
+ {
+ pos = m_object->RetPosition(i+2);
+ pos -= m_object->RetPosition(i+1);
+
+ angle.z = -RotateAngle(Length(pos.x, pos.z), pos.y);
+ angle.y = PI-RotateAngle(pos.x, pos.z);
+ angle.x = 0.0f;
+ m_object->SetAngle(i+1, angle);
+
+ if ( i == WORM_PART )
+ {
+ m_object->SetAngle(i+2, angle);
+ }
+ }
+
+ return TRUE;
+}
+
+
diff --git a/src/motionworm.h b/src/motionworm.h
new file mode 100644
index 0000000..a464367
--- /dev/null
+++ b/src/motionworm.h
@@ -0,0 +1,56 @@
+// motionworm.h
+
+#ifndef _MOTIONWORM_H_
+#define _MOTIONWORM_H_
+
+
+class CInstanceManager;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CMotionWorm : public CMotion
+{
+public:
+ CMotionWorm(CInstanceManager* iMan, CObject* object);
+ ~CMotionWorm();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(D3DVECTOR pos, float angle, ObjectType type, float power);
+ BOOL EventProcess(const Event &event);
+
+ BOOL SetParam(int rank, float value);
+ float RetParam(int rank);
+
+protected:
+ void CreatePhysics();
+ BOOL EventFrame(const Event &event);
+
+protected:
+ float m_timeUp;
+ float m_timeDown;
+ float m_armMember;
+ float m_armTimeAbs;
+ float m_armTimeMarch;
+ float m_armTimeAction;
+ short m_armAngles[3*3*3*3*10];
+ int m_armTimeIndex;
+ int m_armPartIndex;
+ int m_armMemberIndex;
+ int m_armLastAction;
+ float m_armLinSpeed;
+ float m_armCirSpeed;
+ int m_specAction;
+ float m_specTime;
+ BOOL m_bArmStop;
+ float m_lastParticule;
+};
+
+
+#endif //_MOTIONWORM_H_
diff --git a/src/object.cpp b/src/object.cpp
new file mode 100644
index 0000000..6eda9f7
--- /dev/null
+++ b/src/object.cpp
@@ -0,0 +1,7599 @@
+// object.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "cbot/cbotdll.h"
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "mainmovie.h"
+#include "robotmain.h"
+#include "light.h"
+#include "terrain.h"
+#include "water.h"
+#include "blitz.h"
+#include "camera.h"
+#include "particule.h"
+#include "physics.h"
+#include "brain.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "motiontoto.h"
+#include "motionvehicle.h"
+#include "motionmother.h"
+#include "motionant.h"
+#include "motionspider.h"
+#include "motionbee.h"
+#include "motionworm.h"
+#include "modfile.h"
+#include "auto.h"
+#include "autobase.h"
+#include "autoportico.h"
+#include "autoderrick.h"
+#include "autofactory.h"
+#include "autorepair.h"
+#include "autodestroyer.h"
+#include "autostation.h"
+#include "autoenergy.h"
+#include "autoconvert.h"
+#include "autotower.h"
+#include "autoresearch.h"
+#include "autolabo.h"
+#include "autonuclear.h"
+#include "autoradar.h"
+#include "autoegg.h"
+#include "autonest.h"
+#include "autoroot.h"
+#include "autoflag.h"
+#include "autoinfo.h"
+#include "autojostle.h"
+#include "autopara.h"
+#include "autosafe.h"
+#include "autohuston.h"
+#include "automush.h"
+#include "autokid.h"
+#include "task.h"
+#include "pyro.h"
+#include "displaytext.h"
+#include "cmdtoken.h"
+#include "cbottoken.h"
+#include "sound.h"
+#include "object.h"
+
+
+
+#define ADJUST_ONBOARD FALSE // TRUE -> ajuste la caméra ONBOARD
+#define ADJUST_ARM FALSE // TRUE -> ajuste le bras manipulateur
+#define VIRUS_DELAY 60.0f // durée d'infection d'un virus
+#define LOSS_SHIELD 0.24f // perte du bouclier par coup
+#define LOSS_SHIELD_H 0.10f // perte du bouclier pour l'homme
+#define LOSS_SHIELD_M 0.02f // perte du bouclier pour la pondeuse
+
+#if ADJUST_ONBOARD
+static float debug_x = 0.0f;
+static float debug_y = 0.0f;
+static float debug_z = 0.0f;
+#endif
+
+#if ADJUST_ARM
+static float debug_arm1 = 0.0f;
+static float debug_arm2 = 0.0f;
+static float debug_arm3 = 0.0f;
+#endif
+
+
+
+
+// Met à jour la classe Object.
+
+void uObject(CBotVar* botThis, void* user)
+{
+ CObject* object = (CObject*)user;
+ CObject* power;
+ CObject* fret;
+ CPhysics* physics;
+ CBotVar *pVar, *pSub;
+ ObjectType type;
+ D3DVECTOR pos;
+ float value;
+ int iValue;
+
+ if ( object == 0 ) return;
+
+ physics = object->RetPhysics();
+
+ // Met à jour le type de l'objet.
+ pVar = botThis->GivItemList(); // "category"
+ type = object->RetType();
+ pVar->SetValInt(type, object->RetName());
+
+ // Met à jour la position de l'objet.
+ pVar = pVar->GivNext(); // "position"
+ if ( object->RetTruck() == 0 )
+ {
+ pos = object->RetPosition(0);
+ pos.y -= object->RetWaterLevel(); // relatif au niveau de la mer !
+ pSub = pVar->GivItemList(); // "x"
+ pSub->SetValFloat(pos.x/g_unit);
+ pSub = pSub->GivNext(); // "y"
+ pSub->SetValFloat(pos.z/g_unit);
+ pSub = pSub->GivNext(); // "z"
+ pSub->SetValFloat(pos.y/g_unit);
+ }
+ else // objet transporté ?
+ {
+ pSub = pVar->GivItemList(); // "x"
+ pSub->SetInit(IS_NAN);
+ pSub = pSub->GivNext(); // "y"
+ pSub->SetInit(IS_NAN);
+ pSub = pSub->GivNext(); // "z"
+ pSub->SetInit(IS_NAN);
+ }
+
+ // Met à jour l'angle.
+ pos = object->RetAngle(0);
+ pos += object->RetInclinaison();
+ pVar = pVar->GivNext(); // "orientation"
+ pVar->SetValFloat(360.0f-Mod(pos.y*180.0f/PI, 360.0f));
+ pVar = pVar->GivNext(); // "pitch"
+ pVar->SetValFloat(pos.z*180.0f/PI);
+ pVar = pVar->GivNext(); // "roll"
+ pVar->SetValFloat(pos.x*180.0f/PI);
+
+ // Met à jour le niveau d'énergie de l'objet.
+ pVar = pVar->GivNext(); // "energyLevel"
+ value = object->RetEnergy();
+ pVar->SetValFloat(value);
+
+ // Met à jour le niveau du bouclier de l'objet.
+ pVar = pVar->GivNext(); // "shieldLevel"
+ value = object->RetShield();
+ pVar->SetValFloat(value);
+
+ // Met à jour la température du bouclier.
+ pVar = pVar->GivNext(); // "temperature"
+ if ( physics == 0 ) value = 0.0f;
+ else value = 1.0f-physics->RetReactorRange();
+ pVar->SetValFloat(value);
+
+ // Met à jour la hauteur au-dessus du sol.
+ pVar = pVar->GivNext(); // "altitude"
+ if ( physics == 0 ) value = 0.0f;
+ else value = physics->RetFloorHeight();
+ pVar->SetValFloat(value/g_unit);
+
+ // Met à jour le temps de l'objet.
+ pVar = pVar->GivNext(); // "lifeTime"
+ value = object->RetAbsTime();
+ pVar->SetValFloat(value);
+
+ // Met à jour la matière de l'objet.
+ pVar = pVar->GivNext(); // "material"
+ iValue = object->RetMaterial();
+ pVar->SetValInt(iValue);
+
+ // Met à jour le type de la pile.
+ pVar = pVar->GivNext(); // "energyCell"
+ power = object->RetPower();
+ if ( power == 0 ) pVar->SetPointer(0);
+ else pVar->SetPointer(power->RetBotVar());
+
+ // Met à jour le type de l'objet transporté.
+ pVar = pVar->GivNext(); // "load"
+ fret = object->RetFret();
+ if ( fret == 0 ) pVar->SetPointer(0);
+ else pVar->SetPointer(fret->RetBotVar());
+}
+
+
+
+
+// Constructeur de l'objet.
+
+CObject::CObject(CInstanceManager* iMan)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_OBJECT, this, 500);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ m_physics = 0;
+ m_brain = 0;
+ m_motion = 0;
+ m_auto = 0;
+ m_runScript = 0;
+
+ m_type = OBJECT_FIX;
+ m_id = ++g_id;
+ m_option = 0;
+ m_name[0] = 0;
+ m_partiReactor = -1;
+ m_shadowLight = -1;
+ m_effectLight = -1;
+ m_linVibration = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_cirVibration = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_inclinaison = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_lastParticule = 0.0f;
+
+ m_power = 0;
+ m_fret = 0;
+ m_truck = 0;
+ m_truckLink = 0;
+ m_energy = 1.0f;
+ m_capacity = 1.0f;
+ m_shield = 1.0f;
+ m_range = 0.0f;
+ m_transparency = 0.0f;
+ m_lastEnergy = 999.9f;
+ m_bHilite = FALSE;
+ m_bSelect = FALSE;
+ m_bSelectable = TRUE;
+ m_bCheckToken = TRUE;
+ m_bVisible = TRUE;
+ m_bEnable = TRUE;
+ m_bGadget = FALSE;
+ m_bProxyActivate = FALSE;
+ m_bTrainer = FALSE;
+ m_bToy = FALSE;
+ m_bManual = FALSE;
+ m_bFixed = FALSE;
+ m_bClip = TRUE;
+ m_bShowLimit = FALSE;
+ m_showLimitRadius = 0.0f;
+ m_aTime = 0.0f;
+ m_shotTime = 0.0f;
+ m_bVirusMode = FALSE;
+ m_virusTime = 0.0f;
+ m_lastVirusParticule = 0.0f;
+ m_totalDesectList = 0;
+ m_bLock = FALSE;
+ m_bExplo = FALSE;
+ m_bCargo = FALSE;
+ m_bBurn = FALSE;
+ m_bDead = FALSE;
+ m_bFlat = FALSE;
+ m_gunGoalV = 0.0f;
+ m_gunGoalH = 0.0f;
+ m_shieldRadius = 0.0f;
+ m_defRank = -1;
+ m_magnifyDamage = 1.0f;
+ m_proxyDistance = 60.0f;
+ m_param = 0.0f;
+
+ ZeroMemory(&m_character, sizeof(Character));
+ m_character.wheelFront = 1.0f;
+ m_character.wheelBack = 1.0f;
+ m_character.wheelLeft = 1.0f;
+ m_character.wheelRight = 1.0f;
+
+ m_resetCap = RESET_NONE;
+ m_bResetBusy = FALSE;
+ m_resetPosition = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_resetAngle = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_resetRun = -1;
+
+ m_cameraType = CAMERA_BACK;
+ m_cameraDist = 50.0f;
+ m_bCameraLock = FALSE;
+
+ m_infoTotal = 0;
+ m_infoReturn = NAN;
+ m_bInfoUpdate = FALSE;
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ m_objectPart[i].bUsed = FALSE;
+ }
+ m_totalPart = 0;
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ m_partiSel[i] = -1;
+ }
+
+ for ( i=0 ; i<OBJECTMAXCMDLINE ; i++ )
+ {
+ m_cmdLine[i] = NAN;
+ }
+
+ FlushCrashShere();
+ m_globalSpherePos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_globalSphereRadius = 0.0f;
+ m_jotlerSpherePos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_jotlerSphereRadius = 0.0f;
+
+ CBotClass* bc = CBotClass::Find("object");
+ if ( bc != 0 )
+ {
+ bc->AddUpdateFunc(uObject);
+ }
+
+ m_botVar = CBotVar::Create("", CBotTypResult(CBotTypClass, "object"));
+ m_botVar->SetUserPtr(this);
+ m_botVar->SetIdent(m_id);
+}
+
+// Destructeur de l'objet.
+
+CObject::~CObject()
+{
+ if ( m_botVar != 0 )
+ {
+ m_botVar->SetUserPtr(OBJECTDELETED);
+ delete m_botVar;
+ }
+
+ delete m_physics;
+ delete m_brain;
+ delete m_motion;
+ delete m_auto;
+
+ m_iMan->DeleteInstance(CLASS_OBJECT, this);
+}
+
+
+// Supprime un objet.
+// Si bAll=TRUE, on n'arrange rien, car tous les objets de la
+// scène sont détruits rapidement !
+
+void CObject::DeleteObject(BOOL bAll)
+{
+ CObject* pObj;
+ CPyro* pPyro;
+ int i;
+
+ if ( m_botVar != 0 )
+ {
+ m_botVar->SetUserPtr(OBJECTDELETED);
+ }
+
+ if ( m_camera->RetObject() == this )
+ {
+ m_camera->SetObject(0);
+ }
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ pObj->DeleteDeselList(this);
+ }
+
+ if ( !bAll )
+ {
+#if 0
+ type = m_camera->RetType();
+ if ( (type == CAMERA_BACK ||
+ type == CAMERA_FIX ||
+ type == CAMERA_EXPLO ||
+ type == CAMERA_ONBOARD) &&
+ m_camera->RetObject() == this )
+ {
+ pObj = m_main->SearchNearest(RetPosition(0), this);
+ if ( pObj == 0 )
+ {
+ m_camera->SetObject(0);
+ m_camera->SetType(CAMERA_FREE);
+ }
+ else
+ {
+ m_camera->SetObject(pObj);
+ m_camera->SetType(CAMERA_BACK);
+ }
+ }
+#endif
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pPyro = (CPyro*)m_iMan->SearchInstance(CLASS_PYRO, i);
+ if ( pPyro == 0 ) break;
+
+ pPyro->CutObjectLink(this); // l'objet n'existe plus
+ }
+
+ if ( m_bSelect )
+ {
+ SetSelect(FALSE);
+ }
+
+ if ( m_type == OBJECT_BASE ||
+ m_type == OBJECT_FACTORY ||
+ m_type == OBJECT_REPAIR ||
+ m_type == OBJECT_DESTROYER||
+ m_type == OBJECT_DERRICK ||
+ m_type == OBJECT_STATION ||
+ m_type == OBJECT_CONVERT ||
+ m_type == OBJECT_TOWER ||
+ m_type == OBJECT_RESEARCH ||
+ m_type == OBJECT_RADAR ||
+ m_type == OBJECT_INFO ||
+ m_type == OBJECT_ENERGY ||
+ m_type == OBJECT_LABO ||
+ m_type == OBJECT_NUCLEAR ||
+ m_type == OBJECT_PARA ||
+ m_type == OBJECT_SAFE ||
+ m_type == OBJECT_HUSTON ||
+ m_type == OBJECT_START ||
+ m_type == OBJECT_END ) // batiment?
+ {
+ m_terrain->DeleteBuildingLevel(RetPosition(0)); // applanit le terrain
+ }
+ }
+
+ m_type = OBJECT_NULL; // objet invalide jusqu'à destruction complète
+
+ if ( m_partiReactor != -1 )
+ {
+ m_particule->DeleteParticule(m_partiReactor);
+ m_partiReactor = -1;
+ }
+
+ if ( m_shadowLight != -1 )
+ {
+ m_light->DeleteLight(m_shadowLight);
+ m_shadowLight = -1;
+ }
+
+ if ( m_effectLight != -1 )
+ {
+ m_light->DeleteLight(m_effectLight);
+ m_effectLight = -1;
+ }
+
+ if ( m_physics != 0 )
+ {
+ m_physics->DeleteObject(bAll);
+ }
+
+ if ( m_brain != 0 )
+ {
+ m_brain->DeleteObject(bAll);
+ }
+
+ if ( m_motion != 0 )
+ {
+ m_motion->DeleteObject(bAll);
+ }
+
+ if ( m_auto != 0 )
+ {
+ m_auto->DeleteObject(bAll);
+ }
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( m_objectPart[i].bUsed )
+ {
+ m_objectPart[i].bUsed = FALSE;
+ m_engine->DeleteObject(m_objectPart[i].object);
+
+ if ( m_objectPart[i].masterParti != -1 )
+ {
+ m_particule->DeleteParticule(m_objectPart[i].masterParti);
+ m_objectPart[i].masterParti = -1;
+ }
+ }
+ }
+
+ if ( m_bShowLimit )
+ {
+ m_main->FlushShowLimit(0);
+ m_bShowLimit = FALSE;
+ }
+
+ if ( !bAll ) m_main->CreateShortcuts();
+}
+
+// Simplifie un objet (on lui ôte le cerveau, entre autres).
+
+void CObject::Simplify()
+{
+ if ( m_brain != 0 )
+ {
+ m_brain->StopProgram();
+ }
+ m_main->SaveOneScript(this);
+
+ if ( m_physics != 0 )
+ {
+ m_physics->DeleteObject();
+ delete m_physics;
+ m_physics = 0;
+ }
+
+ if ( m_brain != 0 )
+ {
+ m_brain->DeleteObject();
+ delete m_brain;
+ m_brain = 0;
+ }
+
+ if ( m_motion != 0 )
+ {
+ m_motion->DeleteObject();
+ delete m_motion;
+ m_motion = 0;
+ }
+
+ if ( m_auto != 0 )
+ {
+ m_auto->DeleteObject();
+ delete m_auto;
+ m_auto = 0;
+ }
+
+ m_main->CreateShortcuts();
+}
+
+
+// Fait exploser un objet, lorsqu'il est touché par un projectile.
+// Si FALSE est retourné, l'objet n'est pas encore foutu.
+// Si TRUE est retourné, l'objet est détruit.
+
+BOOL CObject::ExploObject(ExploType type, float force, float decay)
+{
+ PyroType pyroType;
+ CPyro* pyro;
+ float loss, shield;
+
+ if ( type == EXPLO_BURN )
+ {
+ if ( m_type == OBJECT_MOBILEtg ||
+ m_type == OBJECT_TEEN28 || // bouteille ?
+ m_type == OBJECT_METAL ||
+ m_type == OBJECT_POWER ||
+ m_type == OBJECT_ATOMIC ||
+ m_type == OBJECT_TNT ||
+ m_type == OBJECT_SCRAP1 ||
+ m_type == OBJECT_SCRAP2 ||
+ m_type == OBJECT_SCRAP3 ||
+ m_type == OBJECT_SCRAP4 ||
+ m_type == OBJECT_SCRAP5 ||
+ m_type == OBJECT_BULLET ||
+ m_type == OBJECT_EGG ) // objet qui ne brûle pas ?
+ {
+ type = EXPLO_BOUM;
+ force = 1.0f;
+ decay = 1.0f;
+ }
+ }
+
+ if ( EXPLO_BOUM )
+ {
+ if ( m_shotTime < 0.5f ) return FALSE;
+ m_shotTime = 0.0f;
+ }
+
+ if ( m_type == OBJECT_HUMAN && m_bDead ) return FALSE;
+
+ // Calcule la puissance perdue par l'explosion.
+ if ( force == 0.0f )
+ {
+ if ( m_type == OBJECT_HUMAN )
+ {
+ loss = LOSS_SHIELD_H;
+ }
+ else if ( m_type == OBJECT_MOTHER )
+ {
+ loss = LOSS_SHIELD_M;
+ }
+ else
+ {
+ loss = LOSS_SHIELD;
+ }
+ }
+ else
+ {
+ loss = force;
+ }
+ loss *= m_magnifyDamage;
+ loss *= decay;
+
+ // Diminue la puissance du bouclier.
+ shield = RetShield();
+ shield -= loss;
+ if ( shield < 0.0f ) shield = 0.0f;
+ SetShield(shield);
+
+ if ( shield > 0.0f ) // pas encore mort ?
+ {
+ if ( type == EXPLO_WATER )
+ {
+ if ( m_type == OBJECT_HUMAN )
+ {
+ pyroType = PT_SHOTH;
+ }
+ else
+ {
+ pyroType = PT_SHOTW;
+ }
+ }
+ else
+ {
+ if ( m_type == OBJECT_HUMAN )
+ {
+ pyroType = PT_SHOTH;
+ }
+ else if ( m_type == OBJECT_MOTHER )
+ {
+ pyroType = PT_SHOTM;
+ }
+ else
+ {
+ pyroType = PT_SHOTT;
+ }
+ }
+ }
+ else // complètement mort ?
+ {
+ if ( type == EXPLO_BURN ) // brûle ?
+ {
+ if ( m_type == OBJECT_MOTHER ||
+ m_type == OBJECT_ANT ||
+ m_type == OBJECT_SPIDER ||
+ m_type == OBJECT_BEE ||
+ m_type == OBJECT_WORM ||
+ m_type == OBJECT_BULLET )
+ {
+ pyroType = PT_BURNO;
+ SetBurn(TRUE);
+ }
+ else if ( m_type == OBJECT_HUMAN )
+ {
+ pyroType = PT_DEADG;
+ }
+ else
+ {
+ pyroType = PT_BURNT;
+ SetBurn(TRUE);
+ }
+ SetVirusMode(FALSE);
+ }
+ else if ( type == EXPLO_WATER )
+ {
+ if ( m_type == OBJECT_HUMAN )
+ {
+ pyroType = PT_DEADW;
+ }
+ else
+ {
+ pyroType = PT_FRAGW;
+ }
+ }
+ else // explosion ?
+ {
+ if ( m_type == OBJECT_ANT ||
+ m_type == OBJECT_SPIDER ||
+ m_type == OBJECT_BEE ||
+ m_type == OBJECT_WORM )
+ {
+ pyroType = PT_EXPLOO;
+ }
+ else if ( m_type == OBJECT_MOTHER ||
+ m_type == OBJECT_NEST ||
+ m_type == OBJECT_BULLET )
+ {
+ pyroType = PT_FRAGO;
+ }
+ else if ( m_type == OBJECT_HUMAN )
+ {
+ pyroType = PT_DEADG;
+ }
+ else if ( m_type == OBJECT_BASE ||
+ m_type == OBJECT_DERRICK ||
+ m_type == OBJECT_FACTORY ||
+ m_type == OBJECT_STATION ||
+ m_type == OBJECT_CONVERT ||
+ m_type == OBJECT_REPAIR ||
+ m_type == OBJECT_DESTROYER||
+ m_type == OBJECT_TOWER ||
+ m_type == OBJECT_NEST ||
+ m_type == OBJECT_RESEARCH ||
+ m_type == OBJECT_RADAR ||
+ m_type == OBJECT_INFO ||
+ m_type == OBJECT_ENERGY ||
+ m_type == OBJECT_LABO ||
+ m_type == OBJECT_NUCLEAR ||
+ m_type == OBJECT_PARA ||
+ m_type == OBJECT_SAFE ||
+ m_type == OBJECT_HUSTON ||
+ m_type == OBJECT_START ||
+ m_type == OBJECT_END ) // batiment ?
+ {
+ pyroType = PT_FRAGT;
+ }
+ else if ( m_type == OBJECT_MOBILEtg ||
+ m_type == OBJECT_TEEN28 || // bouteille ?
+ m_type == OBJECT_TEEN31 ) // basket ?
+ {
+ pyroType = PT_FRAGT;
+ }
+ else
+ {
+ pyroType = PT_EXPLOT;
+ }
+ }
+
+ loss = 1.0f;
+ }
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(pyroType, this, loss);
+
+ if ( shield == 0.0f ) // mort ?
+ {
+ if ( m_brain != 0 )
+ {
+ m_brain->StopProgram();
+ }
+ m_main->SaveOneScript(this);
+ }
+
+ if ( shield > 0.0f ) return FALSE; // pas encore mort
+
+ if ( RetSelect() )
+ {
+ SetSelect(FALSE); // désélectionne l'objet
+ m_camera->SetType(CAMERA_EXPLO);
+ m_main->DeselectAll();
+ }
+ DeleteDeselList(this);
+
+ if ( m_botVar != 0 )
+ {
+ if ( m_type == OBJECT_STONE ||
+ m_type == OBJECT_URANIUM ||
+ m_type == OBJECT_METAL ||
+ m_type == OBJECT_POWER ||
+ m_type == OBJECT_ATOMIC ||
+ m_type == OBJECT_BULLET ||
+ m_type == OBJECT_BBOX ||
+ m_type == OBJECT_TNT ||
+ m_type == OBJECT_SCRAP1 ||
+ m_type == OBJECT_SCRAP2 ||
+ m_type == OBJECT_SCRAP3 ||
+ m_type == OBJECT_SCRAP4 ||
+ m_type == OBJECT_SCRAP5 ) // (*)
+ {
+ m_botVar->SetUserPtr(OBJECTDELETED);
+ }
+ }
+
+ return TRUE;
+}
+
+// (*) Si un robot ou le cosmonaute meurt, l'objet doit continuer
+// d'exister, pour que les programmes des fourmis continuent
+// de fonctionner comme si de rien était !
+
+
+// Initialise une nouvelle partie.
+
+void CObject::InitPart(int part)
+{
+ m_objectPart[part].bUsed = TRUE;
+ m_objectPart[part].object = -1;
+ m_objectPart[part].parentPart = -1;
+
+ m_objectPart[part].position = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_objectPart[part].angle.y = 0.0f;
+ m_objectPart[part].angle.x = 0.0f;
+ m_objectPart[part].angle.z = 0.0f;
+ m_objectPart[part].zoom = D3DVECTOR(1.0f, 1.0f, 1.0f);
+
+ m_objectPart[part].bTranslate = TRUE;
+ m_objectPart[part].bRotate = TRUE;
+ m_objectPart[part].bZoom = FALSE;
+
+ D3DUtil_SetIdentityMatrix(m_objectPart[part].matTranslate);
+ D3DUtil_SetIdentityMatrix(m_objectPart[part].matRotate);
+ D3DUtil_SetIdentityMatrix(m_objectPart[part].matTransform);
+ D3DUtil_SetIdentityMatrix(m_objectPart[part].matWorld);
+
+ m_objectPart[part].masterParti = -1;
+}
+
+// Crée une nouvelle partie, et retourne son numéro.
+// Retourne -1 en cas d'erreur.
+
+int CObject::CreatePart()
+{
+ int i;
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( m_objectPart[i].bUsed ) continue;
+
+ InitPart(i);
+ UpdateTotalPart();
+ return i;
+ }
+ return -1;
+}
+
+// Supprime une partie.
+
+void CObject::DeletePart(int part)
+{
+ if ( !m_objectPart[part].bUsed ) return;
+
+ if ( m_objectPart[part].masterParti != -1 )
+ {
+ m_particule->DeleteParticule(m_objectPart[part].masterParti);
+ m_objectPart[part].masterParti = -1;
+ }
+
+ m_objectPart[part].bUsed = FALSE;
+ m_engine->DeleteObject(m_objectPart[part].object);
+ UpdateTotalPart();
+}
+
+void CObject::UpdateTotalPart()
+{
+ int i;
+
+ m_totalPart = 0;
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( m_objectPart[i].bUsed )
+ {
+ m_totalPart = i+1;
+ }
+ }
+}
+
+
+// Spécifie le numéro de l'objet d'une partie.
+
+void CObject::SetObjectRank(int part, int objRank)
+{
+ if ( !m_objectPart[part].bUsed ) // objet pas créé ?
+ {
+ InitPart(part);
+ UpdateTotalPart();
+ }
+ m_objectPart[part].object = objRank;
+}
+
+// Retourne le numéro d'une partie.
+
+int CObject::RetObjectRank(int part)
+{
+ if ( !m_objectPart[part].bUsed ) return -1;
+ return m_objectPart[part].object;
+}
+
+// Spécifie quel est le parent d'ue partie.
+// Rappel: la partie 0 est toujours le père de tous et donc la
+// partie principale (par exemple le chassis d'une voiture).
+
+void CObject::SetObjectParent(int part, int parent)
+{
+ m_objectPart[part].parentPart = parent;
+}
+
+
+// Spécifie le type de l'objet.
+
+void CObject::SetType(ObjectType type)
+{
+ m_type = type;
+ strcpy(m_name, RetObjectName(m_type));
+
+ if ( m_type == OBJECT_MOBILErs )
+ {
+ m_param = 1.0f; // bouclier au maximum par défaut
+ }
+
+ if ( m_type == OBJECT_ATOMIC )
+ {
+ m_capacity = 10.0f;
+ }
+ else
+ {
+ m_capacity = 1.0f;
+ }
+
+ if ( m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEic ||
+ m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEii ||
+ m_type == OBJECT_MOBILErc ) // véhicule canon ?
+ {
+ m_cameraType = CAMERA_ONBOARD;
+ }
+}
+
+ObjectType CObject::RetType()
+{
+ return m_type;
+}
+
+char* CObject::RetName()
+{
+ return m_name;
+}
+
+
+// Choix de l'option à utiliser.
+
+void CObject::SetOption(int option)
+{
+ m_option = option;
+}
+
+int CObject::RetOption()
+{
+ return m_option;
+}
+
+
+// Gestion de l'identificateur unique d'un objet.
+
+void CObject::SetID(int id)
+{
+ m_id = id;
+
+ if ( m_botVar != 0 )
+ {
+ m_botVar->SetIdent(m_id);
+ }
+}
+
+int CObject::RetID()
+{
+ return m_id;
+}
+
+
+// Sauve tous les paramètres de l'objet.
+
+BOOL CObject::Write(char *line)
+{
+ D3DVECTOR pos;
+ Info info;
+ char name[100];
+ float value;
+ int i;
+
+ sprintf(name, " camera=%s", GetCamera(RetCameraType()));
+ strcat(line, name);
+
+ if ( RetCameraLock() != 0 )
+ {
+ sprintf(name, " cameraLock=%d", RetCameraLock());
+ strcat(line, name);
+ }
+
+ if ( RetEnergy() != 0.0f )
+ {
+ sprintf(name, " energy=%.2f", RetEnergy());
+ strcat(line, name);
+ }
+
+ if ( RetCapacity() != 1.0f )
+ {
+ sprintf(name, " capacity=%.2f", RetCapacity());
+ strcat(line, name);
+ }
+
+ if ( RetShield() != 1.0f )
+ {
+ sprintf(name, " shield=%.2f", RetShield());
+ strcat(line, name);
+ }
+
+ if ( RetRange() != 1.0f )
+ {
+ sprintf(name, " range=%.2f", RetRange());
+ strcat(line, name);
+ }
+
+ if ( RetSelectable() != 1 )
+ {
+ sprintf(name, " selectable=%d", RetSelectable());
+ strcat(line, name);
+ }
+
+ if ( RetEnable() != 1 )
+ {
+ sprintf(name, " enable=%d", RetEnable());
+ strcat(line, name);
+ }
+
+ if ( RetFixed() != 0 )
+ {
+ sprintf(name, " fixed=%d", RetFixed());
+ strcat(line, name);
+ }
+
+ if ( RetClip() != 1 )
+ {
+ sprintf(name, " clip=%d", RetClip());
+ strcat(line, name);
+ }
+
+ if ( RetLock() != 0 )
+ {
+ sprintf(name, " lock=%d", RetLock());
+ strcat(line, name);
+ }
+
+ if ( RetProxyActivate() != 0 )
+ {
+ sprintf(name, " proxyActivate=%d", RetProxyActivate());
+ strcat(line, name);
+
+ sprintf(name, " proxyDistance=%.2f", RetProxyDistance()/g_unit);
+ strcat(line, name);
+ }
+
+ if ( RetMagnifyDamage() != 1.0f )
+ {
+ sprintf(name, " magnifyDamage=%.2f", RetMagnifyDamage());
+ strcat(line, name);
+ }
+
+ if ( RetGunGoalV() != 0.0f )
+ {
+ sprintf(name, " aimV=%.2f", RetGunGoalV());
+ strcat(line, name);
+ }
+ if ( RetGunGoalH() != 0.0f )
+ {
+ sprintf(name, " aimH=%.2f", RetGunGoalH());
+ strcat(line, name);
+ }
+
+ if ( RetParam() != 0.0f )
+ {
+ sprintf(name, " param=%.2f", RetParam());
+ strcat(line, name);
+ }
+
+ if ( RetResetCap() != 0 )
+ {
+ sprintf(name, " resetCap=%d", RetResetCap());
+ strcat(line, name);
+
+ pos = RetResetPosition()/g_unit;
+ sprintf(name, " resetPos=%.2f;%.2f;%.2f", pos.x, pos.y, pos.z);
+ strcat(line, name);
+
+ pos = RetResetAngle()/(PI/180.0f);
+ sprintf(name, " resetAngle=%.2f;%.2f;%.2f", pos.x, pos.y, pos.z);
+ strcat(line, name);
+
+ sprintf(name, " resetRun=%d", RetResetRun());
+ strcat(line, name);
+ }
+
+ if ( m_bVirusMode != 0 )
+ {
+ sprintf(name, " virusMode=%d", m_bVirusMode);
+ strcat(line, name);
+ }
+
+ if ( m_virusTime != 0.0f )
+ {
+ sprintf(name, " virusTime=%.2f", m_virusTime);
+ strcat(line, name);
+ }
+
+ // Met les infos dans borne (OBJECT_INFO).
+ for ( i=0 ; i<m_infoTotal ; i++ )
+ {
+ info = RetInfo(i);
+ if ( info.name[0] == 0 ) break;
+
+ sprintf(name, " info%d=\"%s=%.2f\"", i+1, info.name, info.value);
+ strcat(line, name);
+ }
+
+ // Met les paramètres de la ligne de commande.
+ for ( i=0 ; i<OBJECTMAXCMDLINE ; i++ )
+ {
+ value = RetCmdLine(i);
+ if ( value == NAN ) break;
+
+ if ( i == 0 ) sprintf(name, " cmdline=%.2f", value);
+ else sprintf(name, ";%.2f", value);
+ strcat(line, name);
+ }
+
+ if ( m_motion != 0 )
+ {
+ m_motion->Write(line);
+ }
+
+ if ( m_brain != 0 )
+ {
+ m_brain->Write(line);
+ }
+
+ if ( m_physics != 0 )
+ {
+ m_physics->Write(line);
+ }
+
+ if ( m_auto != 0 )
+ {
+ m_auto->Write(line);
+ }
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'objet.
+
+BOOL CObject::Read(char *line)
+{
+ D3DVECTOR pos, dir;
+ Info info;
+ CameraType cType;
+ char op[20];
+ char text[100];
+ char* p;
+ float value;
+ int i;
+
+ cType = OpCamera(line, "camera");
+ if ( cType != CAMERA_NULL )
+ {
+ SetCameraType(cType);
+ }
+
+ SetCameraLock(OpInt(line, "cameraLock", 0));
+ SetEnergy(OpFloat(line, "energy", 0.0f));
+ SetCapacity(OpFloat(line, "capacity", 1.0f));
+ SetShield(OpFloat(line, "shield", 1.0f));
+ SetRange(OpFloat(line, "range", 1.0f));
+ SetSelectable(OpInt(line, "selectable", 1));
+ SetEnable(OpInt(line, "enable", 1));
+ SetFixed(OpInt(line, "fixed", 0));
+ SetClip(OpInt(line, "clip", 1));
+ SetLock(OpInt(line, "lock", 0));
+ SetProxyActivate(OpInt(line, "proxyActivate", 0));
+ SetProxyDistance(OpFloat(line, "proxyDistance", 15.0f)*g_unit);
+ SetRange(OpFloat(line, "range", 30.0f));
+ SetMagnifyDamage(OpFloat(line, "magnifyDamage", 1.0f));
+ SetGunGoalV(OpFloat(line, "aimV", 0.0f));
+ SetGunGoalH(OpFloat(line, "aimH", 0.0f));
+ SetParam(OpFloat(line, "param", 0.0f));
+ SetResetCap((ResetCap)OpInt(line, "resetCap", 0));
+ SetResetPosition(OpDir(line, "resetPos")*g_unit);
+ SetResetAngle(OpDir(line, "resetAngle")*(PI/180.0f));
+ SetResetRun(OpInt(line, "resetRun", 0));
+ m_bBurn = OpInt(line, "burnMode", 0);
+ m_bVirusMode = OpInt(line, "virusMode", 0);
+ m_virusTime = OpFloat(line, "virusTime", 0.0f);
+
+ // Met les infos dans borne (OBJECT_INFO).
+ for ( i=0 ; i<OBJECTMAXINFO ; i++ )
+ {
+ sprintf(op, "info%d", i+1);
+ OpString(line, op, text);
+ if ( text[0] == 0 ) break;
+ p = strchr(text, '=');
+ if ( p == 0 ) break;
+ *p = 0;
+ strcpy(info.name, text);
+ sscanf(p+1, "%f", &info.value);
+ SetInfo(i, info);
+ }
+
+ // Met les paramètres de la ligne de commande.
+ p = SearchOp(line, "cmdline");
+ for ( i=0 ; i<OBJECTMAXCMDLINE ; i++ )
+ {
+ value = GetFloat(p, i, NAN);
+ if ( value == NAN ) break;
+ SetCmdLine(i, value);
+ }
+
+ if ( m_motion != 0 )
+ {
+ m_motion->Read(line);
+ }
+
+ if ( m_brain != 0 )
+ {
+ m_brain->Read(line);
+ }
+
+ if ( m_physics != 0 )
+ {
+ m_physics->Read(line);
+ }
+
+ if ( m_auto != 0 )
+ {
+ m_auto->Read(line);
+ }
+
+ return TRUE;
+}
+
+
+
+// Cherche le nième fils d'un père.
+
+int CObject::SearchDescendant(int parent, int n)
+{
+ int i;
+
+ for ( i=0 ; i<m_totalPart ; i++ )
+ {
+ if ( !m_objectPart[i].bUsed ) continue;
+
+ if ( parent == m_objectPart[i].parentPart )
+ {
+ if ( n-- == 0 ) return i;
+ }
+ }
+ return -1;
+}
+
+
+// Supprime toutes les sphères utilisées pour les collisions.
+
+void CObject::FlushCrashShere()
+{
+ m_crashSphereUsed = 0;
+}
+
+// Ajoute une nouvelle sphère.
+
+int CObject::CreateCrashSphere(D3DVECTOR pos, float radius, Sound sound,
+ float hardness)
+{
+ float zoom;
+
+ if ( m_crashSphereUsed >= MAXCRASHSPHERE ) return -1;
+
+ zoom = RetZoomX(0);
+ m_crashSpherePos[m_crashSphereUsed] = pos;
+ m_crashSphereRadius[m_crashSphereUsed] = radius*zoom;
+ m_crashSphereHardness[m_crashSphereUsed] = hardness;
+ m_crashSphereSound[m_crashSphereUsed] = sound;
+ return m_crashSphereUsed++;
+}
+
+// Retourne le nombre de sphères.
+
+int CObject::RetCrashSphereTotal()
+{
+ return m_crashSphereUsed;
+}
+
+// Retourne une sphère pour les collisions.
+// La position est absolue dans le monde.
+
+BOOL CObject::GetCrashSphere(int rank, D3DVECTOR &pos, float &radius)
+{
+ if ( rank < 0 || rank >= m_crashSphereUsed )
+ {
+ pos = m_objectPart[0].position;
+ radius = 0.0f;
+ return FALSE;
+ }
+
+ // Retourne la sphère pour les collisions, qui ne tient pas
+ // compte de l'inclinaison du véhicule. Ceci est nécessaire
+ // pour les collisions avec les véhicules, afin de ne pas tenir
+ // compte de SetInclinaison, par exemple.
+ // La sphère doit avoir obligatoirement un centre (0;y;0).
+ if ( rank == 0 && m_crashSphereUsed == 1 &&
+ m_crashSpherePos[0].x == 0.0f &&
+ m_crashSpherePos[0].z == 0.0f )
+ {
+ pos = m_objectPart[0].position + m_crashSpherePos[0];
+ radius = m_crashSphereRadius[0];
+ return TRUE;
+ }
+
+ if ( m_objectPart[0].bTranslate ||
+ m_objectPart[0].bRotate )
+ {
+ UpdateTransformObject();
+ }
+ pos = Transform(m_objectPart[0].matWorld, m_crashSpherePos[rank]);
+ radius = m_crashSphereRadius[rank];
+ return TRUE;
+}
+
+// Retourne la dureté d'une sphère.
+
+Sound CObject::RetCrashSphereSound(int rank)
+{
+ return m_crashSphereSound[rank];
+}
+
+// Retourne la dureté d'une sphère.
+
+float CObject::RetCrashSphereHardness(int rank)
+{
+ return m_crashSphereHardness[rank];
+}
+
+// Supprime une sphère.
+
+void CObject::DeleteCrashSphere(int rank)
+{
+ int i;
+
+ if ( rank < 0 || rank >= m_crashSphereUsed ) return;
+
+ for ( i=rank+1 ; i<MAXCRASHSPHERE ; i++ )
+ {
+ m_crashSpherePos[i-1] = m_crashSpherePos[i];
+ m_crashSphereRadius[i-1] = m_crashSphereRadius[i];
+ }
+ m_crashSphereUsed --;
+}
+
+// Spécifie la sphère globale, relative à l'objet.
+
+void CObject::SetGlobalSphere(D3DVECTOR pos, float radius)
+{
+ float zoom;
+
+ zoom = RetZoomX(0);
+ m_globalSpherePos = pos;
+ m_globalSphereRadius = radius*zoom;
+}
+
+// Retourne la sphère globale, dans l'univers.
+
+void CObject::GetGlobalSphere(D3DVECTOR &pos, float &radius)
+{
+ pos = Transform(m_objectPart[0].matWorld, m_globalSpherePos);
+ radius = m_globalSphereRadius;
+}
+
+
+// Spécifie la sphère de bousculade, relative à l'objet.
+
+void CObject::SetJotlerSphere(D3DVECTOR pos, float radius)
+{
+ m_jotlerSpherePos = pos;
+ m_jotlerSphereRadius = radius;
+}
+
+// Retourne la sphère de bousculade, dans l'univers.
+
+void CObject::GetJotlerSphere(D3DVECTOR &pos, float &radius)
+{
+ pos = Transform(m_objectPart[0].matWorld, m_jotlerSpherePos);
+ radius = m_jotlerSphereRadius;
+}
+
+
+// Spécifie le rayon du bouclier.
+
+void CObject::SetShieldRadius(float radius)
+{
+ m_shieldRadius = radius;
+}
+
+// Retourne le rayon du bouclier.
+
+float CObject::RetShieldRadius()
+{
+ return m_shieldRadius;
+}
+
+
+// Positionne un objet à une certaine hauteur par-rapport au sol.
+
+void CObject::SetFloorHeight(float height)
+{
+ D3DVECTOR pos;
+
+ pos = m_objectPart[0].position;
+ m_terrain->MoveOnFloor(pos);
+
+ if ( m_physics != 0 )
+ {
+ m_physics->SetLand(height == 0.0f);
+ m_physics->SetMotor(height != 0.0f);
+ }
+
+ m_objectPart[0].position.y = pos.y+height+m_character.height;
+ m_objectPart[0].bTranslate = TRUE; // il faudra recalculer les matrices
+}
+
+// Ajuste l'inclinaison d'un objet posé sur le sol.
+
+void CObject::FloorAdjust()
+{
+ D3DVECTOR pos, n;
+ FPOINT nn;
+ float a;
+
+ pos = RetPosition(0);
+ if ( m_terrain->GetNormal(n, pos) )
+ {
+#if 0
+ SetAngleX(0, sinf(n.z));
+ SetAngleZ(0, -sinf(n.x));
+ SetAngleY(0, 0.0f);
+#else
+ a = RetAngleY(0);
+ nn = RotatePoint(-a, FPOINT(n.z, n.x));
+ SetAngleX(0, sinf(nn.x));
+ SetAngleZ(0, -sinf(nn.y));
+#endif
+ }
+}
+
+
+// Donne la vibration linéaire.
+
+void CObject::SetLinVibration(D3DVECTOR dir)
+{
+ if ( m_linVibration.x != dir.x ||
+ m_linVibration.y != dir.y ||
+ m_linVibration.z != dir.z )
+ {
+ m_linVibration = dir;
+ m_objectPart[0].bTranslate = TRUE;
+ }
+}
+
+D3DVECTOR CObject::RetLinVibration()
+{
+ return m_linVibration;
+}
+
+// Donne la vibration circulaire.
+
+void CObject::SetCirVibration(D3DVECTOR dir)
+{
+ if ( m_cirVibration.x != dir.x ||
+ m_cirVibration.y != dir.y ||
+ m_cirVibration.z != dir.z )
+ {
+ m_cirVibration = dir;
+ m_objectPart[0].bRotate = TRUE;
+ }
+}
+
+D3DVECTOR CObject::RetCirVibration()
+{
+ return m_cirVibration;
+}
+
+// Donne l'inclinaison.
+
+void CObject::SetInclinaison(D3DVECTOR dir)
+{
+ if ( m_inclinaison.x != dir.x ||
+ m_inclinaison.y != dir.y ||
+ m_inclinaison.z != dir.z )
+ {
+ m_inclinaison = dir;
+ m_objectPart[0].bRotate = TRUE;
+ }
+}
+
+D3DVECTOR CObject::RetInclinaison()
+{
+ return m_inclinaison;
+}
+
+
+// Donne la position du centre de l'objet.
+
+void CObject::SetPosition(int part, const D3DVECTOR &pos)
+{
+ D3DVECTOR shPos, n[20], norm;
+ float height, radius;
+ int rank, i, j;
+
+ m_objectPart[part].position = pos;
+ m_objectPart[part].bTranslate = TRUE; // il faudra recalculer les matrices
+
+ if ( part == 0 && !m_bFlat ) // partie principale ?
+ {
+ rank = m_objectPart[0].object;
+
+ shPos = pos;
+ m_terrain->MoveOnFloor(shPos, TRUE);
+ m_engine->SetObjectShadowPos(rank, shPos);
+
+ if ( m_physics != 0 && m_physics->RetType() == TYPE_FLYING )
+ {
+ height = pos.y-shPos.y;
+ }
+ else
+ {
+ height = 0.0f;
+ }
+ m_engine->SetObjectShadowHeight(rank, height);
+
+ // Calcul la normale au terrain en 9 points stratégiques,
+ // puis effectue une moyenne pondérée (les points au centre
+ // ont plus d'importance).
+ radius = m_engine->RetObjectShadowRadius(rank);
+ i = 0;
+
+ m_terrain->GetNormal(norm, pos);
+ n[i++] = norm;
+ n[i++] = norm;
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x += radius*0.6f;
+ shPos.z += radius*0.6f;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x -= radius*0.6f;
+ shPos.z += radius*0.6f;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x += radius*0.6f;
+ shPos.z -= radius*0.6f;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x -= radius*0.6f;
+ shPos.z -= radius*0.6f;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x += radius;
+ shPos.z += radius;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x -= radius;
+ shPos.z += radius;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x += radius;
+ shPos.z -= radius;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+
+ shPos = pos;
+ shPos.x -= radius;
+ shPos.z -= radius;
+ m_terrain->GetNormal(norm, shPos);
+ n[i++] = norm;
+
+ norm = 0.0f;
+ for ( j=0 ; j<i ; j++ )
+ {
+ norm += n[j];
+ }
+ norm /= (float)i; // moyenne vectorielle
+
+ m_engine->SetObjectShadowNormal(rank, norm);
+
+ if ( m_shadowLight != -1 )
+ {
+ shPos = pos;
+ shPos.y += m_shadowHeight;
+ m_light->SetLightPos(m_shadowLight, shPos);
+ }
+
+ if ( m_effectLight != -1 )
+ {
+ shPos = pos;
+ shPos.y += m_effectHeight;
+ m_light->SetLightPos(m_effectLight, shPos);
+ }
+
+ if ( m_bShowLimit )
+ {
+ m_main->AdjustShowLimit(0, pos);
+ }
+ }
+}
+
+D3DVECTOR CObject::RetPosition(int part)
+{
+ return m_objectPart[part].position;
+}
+
+// Donne la rotation autour des 3 axes.
+
+void CObject::SetAngle(int part, const D3DVECTOR &angle)
+{
+ m_objectPart[part].angle = angle;
+ m_objectPart[part].bRotate = TRUE; // il faudra recalculer les matrices
+
+ if ( part == 0 && !m_bFlat ) // partie principale ?
+ {
+ m_engine->SetObjectShadowAngle(m_objectPart[0].object, m_objectPart[0].angle.y);
+ }
+}
+
+D3DVECTOR CObject::RetAngle(int part)
+{
+ return m_objectPart[part].angle;
+}
+
+// Donne la rotation autour de l'axe Y.
+
+void CObject::SetAngleY(int part, float angle)
+{
+ m_objectPart[part].angle.y = angle;
+ m_objectPart[part].bRotate = TRUE; // il faudra recalculer les matrices
+
+ if ( part == 0 && !m_bFlat ) // partie principale ?
+ {
+ m_engine->SetObjectShadowAngle(m_objectPart[0].object, m_objectPart[0].angle.y);
+ }
+}
+
+// Donne la rotation autour de l'axe X.
+
+void CObject::SetAngleX(int part, float angle)
+{
+ m_objectPart[part].angle.x = angle;
+ m_objectPart[part].bRotate = TRUE; // il faudra recalculer les matrices
+}
+
+// Donne la rotation autour de l'axe Z.
+
+void CObject::SetAngleZ(int part, float angle)
+{
+ m_objectPart[part].angle.z = angle;
+ m_objectPart[part].bRotate = TRUE; // il faudra recalculer les matrices
+}
+
+float CObject::RetAngleY(int part)
+{
+ return m_objectPart[part].angle.y;
+}
+
+float CObject::RetAngleX(int part)
+{
+ return m_objectPart[part].angle.x;
+}
+
+float CObject::RetAngleZ(int part)
+{
+ return m_objectPart[part].angle.z;
+}
+
+
+// Donne le zoom lobal.
+
+void CObject::SetZoom(int part, float zoom)
+{
+ m_objectPart[part].bTranslate = TRUE; // il faudra recalculer les matrices
+ m_objectPart[part].zoom.x = zoom;
+ m_objectPart[part].zoom.y = zoom;
+ m_objectPart[part].zoom.z = zoom;
+
+ m_objectPart[part].bZoom = ( m_objectPart[part].zoom.x != 1.0f ||
+ m_objectPart[part].zoom.y != 1.0f ||
+ m_objectPart[part].zoom.z != 1.0f );
+}
+
+void CObject::SetZoom(int part, D3DVECTOR zoom)
+{
+ m_objectPart[part].bTranslate = TRUE; // il faudra recalculer les matrices
+ m_objectPart[part].zoom = zoom;
+
+ m_objectPart[part].bZoom = ( m_objectPart[part].zoom.x != 1.0f ||
+ m_objectPart[part].zoom.y != 1.0f ||
+ m_objectPart[part].zoom.z != 1.0f );
+}
+
+D3DVECTOR CObject::RetZoom(int part)
+{
+ return m_objectPart[part].zoom;
+}
+
+void CObject::SetZoomX(int part, float zoom)
+{
+ m_objectPart[part].bTranslate = TRUE; // il faudra recalculer les matrices
+ m_objectPart[part].zoom.x = zoom;
+
+ m_objectPart[part].bZoom = ( m_objectPart[part].zoom.x != 1.0f ||
+ m_objectPart[part].zoom.y != 1.0f ||
+ m_objectPart[part].zoom.z != 1.0f );
+}
+
+void CObject::SetZoomY(int part, float zoom)
+{
+ m_objectPart[part].bTranslate = TRUE; // il faudra recalculer les matrices
+ m_objectPart[part].zoom.y = zoom;
+
+ m_objectPart[part].bZoom = ( m_objectPart[part].zoom.x != 1.0f ||
+ m_objectPart[part].zoom.y != 1.0f ||
+ m_objectPart[part].zoom.z != 1.0f );
+}
+
+void CObject::SetZoomZ(int part, float zoom)
+{
+ m_objectPart[part].bTranslate = TRUE; // il faudra recalculer les matrices
+ m_objectPart[part].zoom.z = zoom;
+
+ m_objectPart[part].bZoom = ( m_objectPart[part].zoom.x != 1.0f ||
+ m_objectPart[part].zoom.y != 1.0f ||
+ m_objectPart[part].zoom.z != 1.0f );
+}
+
+float CObject::RetZoomX(int part)
+{
+ return m_objectPart[part].zoom.x;
+}
+
+float CObject::RetZoomY(int part)
+{
+ return m_objectPart[part].zoom.y;
+}
+
+float CObject::RetZoomZ(int part)
+{
+ return m_objectPart[part].zoom.z;
+}
+
+
+// Retourne le niveau de l'eau.
+
+float CObject::RetWaterLevel()
+{
+ return m_water->RetLevel();
+}
+
+
+void CObject::SetTrainer(BOOL bEnable)
+{
+ m_bTrainer = bEnable;
+
+ if ( m_bTrainer ) // entraînement ?
+ {
+ m_cameraType = CAMERA_FIX;
+ }
+}
+
+BOOL CObject::RetTrainer()
+{
+ return m_bTrainer;
+}
+
+void CObject::SetToy(BOOL bEnable)
+{
+ m_bToy = bEnable;
+}
+
+BOOL CObject::RetToy()
+{
+ return m_bToy;
+}
+
+void CObject::SetManual(BOOL bManual)
+{
+ m_bManual = bManual;
+}
+
+BOOL CObject::RetManual()
+{
+ return m_bManual;
+}
+
+void CObject::SetResetCap(ResetCap cap)
+{
+ m_resetCap = cap;
+}
+
+ResetCap CObject::RetResetCap()
+{
+ return m_resetCap;
+}
+
+void CObject::SetResetBusy(BOOL bBusy)
+{
+ m_bResetBusy = bBusy;
+}
+
+BOOL CObject::RetResetBusy()
+{
+ return m_bResetBusy;
+}
+
+void CObject::SetResetPosition(const D3DVECTOR &pos)
+{
+ m_resetPosition = pos;
+}
+
+D3DVECTOR CObject::RetResetPosition()
+{
+ return m_resetPosition;
+}
+
+void CObject::SetResetAngle(const D3DVECTOR &angle)
+{
+ m_resetAngle = angle;
+}
+
+D3DVECTOR CObject::RetResetAngle()
+{
+ return m_resetAngle;
+}
+
+int CObject::RetResetRun()
+{
+ return m_resetRun;
+}
+
+void CObject::SetResetRun(int run)
+{
+ m_resetRun = run;
+}
+
+
+// Gestion de la particule maîtresse.
+
+void CObject::SetMasterParticule(int part, int parti)
+{
+ m_objectPart[part].masterParti = parti;
+}
+
+int CObject::RetMasterParticule(int part)
+{
+ return m_objectPart[part].masterParti;
+}
+
+
+// Gestion de la pile transportée.
+
+void CObject::SetPower(CObject* power)
+{
+ m_power = power;
+}
+
+CObject* CObject::RetPower()
+{
+ return m_power;
+}
+
+// Gestion de l'objet transporté.
+
+void CObject::SetFret(CObject* fret)
+{
+ m_fret = fret;
+}
+
+CObject* CObject::RetFret()
+{
+ return m_fret;
+}
+
+// Gestion de l'objet "camion" qui transporte celui-ci.
+
+void CObject::SetTruck(CObject* truck)
+{
+ m_truck = truck;
+
+ // Ombre invisible si l'objet est transporté.
+ m_engine->SetObjectShadowHide(m_objectPart[0].object, (m_truck != 0));
+}
+
+CObject* CObject::RetTruck()
+{
+ return m_truck;
+}
+
+// Gestion de la partie transporteuse.
+
+void CObject::SetTruckPart(int part)
+{
+ m_truckLink = part;
+}
+
+int CObject::RetTruckPart()
+{
+ return m_truckLink;
+}
+
+
+// Gestion des informations utilisateur.
+
+void CObject::InfoFlush()
+{
+ m_infoTotal = 0;
+ m_bInfoUpdate = TRUE;
+}
+
+void CObject::DeleteInfo(int rank)
+{
+ int i;
+
+ if ( rank < 0 || rank >= m_infoTotal ) return;
+
+ for ( i=rank ; i<m_infoTotal-1 ; i++ )
+ {
+ m_info[i] = m_info[i+1];
+ }
+ m_infoTotal --;
+ m_bInfoUpdate = TRUE;
+}
+
+void CObject::SetInfo(int rank, Info info)
+{
+ if ( rank < 0 || rank >= OBJECTMAXINFO ) return;
+ m_info[rank] = info;
+
+ if ( rank+1 > m_infoTotal ) m_infoTotal = rank+1;
+ m_bInfoUpdate = TRUE;
+}
+
+Info CObject::RetInfo(int rank)
+{
+ if ( rank < 0 || rank >= OBJECTMAXINFO ) rank = 0;
+ return m_info[rank];
+}
+
+int CObject::RetInfoTotal()
+{
+ return m_infoTotal;
+}
+
+void CObject::SetInfoReturn(float value)
+{
+ m_infoReturn = value;
+}
+
+float CObject::RetInfoReturn()
+{
+ return m_infoReturn;
+}
+
+void CObject::SetInfoUpdate(BOOL bUpdate)
+{
+ m_bInfoUpdate = bUpdate;
+}
+
+BOOL CObject::RetInfoUpdate()
+{
+ return m_bInfoUpdate;
+}
+
+
+BOOL CObject::SetCmdLine(int rank, float value)
+{
+ if ( rank < 0 || rank >= OBJECTMAXCMDLINE ) return FALSE;
+ m_cmdLine[rank] = value;
+ return TRUE;
+}
+
+float CObject::RetCmdLine(int rank)
+{
+ if ( rank < 0 || rank >= OBJECTMAXCMDLINE ) return 0.0f;
+ return m_cmdLine[rank];
+}
+
+
+// Retourne les matrices d'une partie d'objet.
+
+D3DMATRIX* CObject::RetRotateMatrix(int part)
+{
+ return &m_objectPart[part].matRotate;
+}
+
+D3DMATRIX* CObject::RetTranslateMatrix(int part)
+{
+ return &m_objectPart[part].matTranslate;
+}
+
+D3DMATRIX* CObject::RetTransformMatrix(int part)
+{
+ return &m_objectPart[part].matTransform;
+}
+
+D3DMATRIX* CObject::RetWorldMatrix(int part)
+{
+ if ( m_objectPart[0].bTranslate ||
+ m_objectPart[0].bRotate )
+ {
+ UpdateTransformObject();
+ }
+
+ return &m_objectPart[part].matWorld;
+}
+
+
+// Indique si l'objet doit être dessiné par dessous l'interface.
+
+void CObject::SetDrawWorld(BOOL bDraw)
+{
+ int i;
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( m_objectPart[i].bUsed )
+ {
+ m_engine->SetDrawWorld(m_objectPart[i].object, bDraw);
+ }
+ }
+}
+
+// Indique si l'objet doit être dessiné par dessus l'interface.
+
+void CObject::SetDrawFront(BOOL bDraw)
+{
+ int i;
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( m_objectPart[i].bUsed )
+ {
+ m_engine->SetDrawFront(m_objectPart[i].object, bDraw);
+ }
+ }
+}
+
+
+// Crée un véhicule roulant quelconque posé sur le sol.
+
+BOOL CObject::CreateVehicle(D3DVECTOR pos, float angle, ObjectType type,
+ float power, BOOL bTrainer, BOOL bToy)
+{
+ m_type = type;
+
+ if ( type == OBJECT_TOTO )
+ {
+ m_motion = new CMotionToto(m_iMan, this);
+ m_motion->Create(pos, angle, type, 1.0f);
+ return TRUE;
+ }
+
+ SetTrainer(bTrainer);
+ SetToy(bToy);
+
+ m_physics = new CPhysics(m_iMan, this);
+ m_brain = new CBrain(m_iMan, this);
+
+ m_physics->SetBrain(m_brain);
+ m_brain->SetPhysics(m_physics);
+
+#if 0
+ if ( type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ) // canon fireball ?
+ {
+ m_showLimitRadius = 160.0f;
+ }
+ if ( type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ) // canon orgaball ?
+ {
+ m_showLimitRadius = 160.0f;
+ }
+ if ( type == OBJECT_MOBILErc ) // canon phazer ?
+ {
+ m_showLimitRadius = 160.0f;
+ }
+ if ( type == OBJECT_MOBILErs ) // robot bouclier ?
+ {
+ m_showLimitRadius = 50.0f;
+ }
+#endif
+ if ( type == OBJECT_MOBILErt ) // robot secoueur ?
+ {
+ m_showLimitRadius = 400.0f;
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ m_motion = new CMotionHuman(m_iMan, this);
+ }
+ else
+ {
+ m_motion = new CMotionVehicle(m_iMan, this);
+ }
+ if ( m_motion == 0 ) return FALSE;
+
+ m_physics->SetMotion(m_motion);
+ m_brain->SetMotion(m_motion);
+ m_motion->SetPhysics(m_physics);
+ m_motion->SetBrain(m_brain);
+ if ( !m_motion->Create(pos, angle, type, power) )
+ {
+ if ( m_physics != 0 )
+ {
+ m_physics->DeleteObject();
+ delete m_physics;
+ m_physics = 0;
+ }
+ if ( m_brain != 0 )
+ {
+ m_brain->DeleteObject();
+ delete m_brain;
+ m_brain = 0;
+ }
+ if ( m_motion != 0 )
+ {
+ m_motion->DeleteObject();
+ delete m_motion;
+ m_motion = 0;
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Crée un insecte quelconque posé sur le sol.
+
+BOOL CObject::CreateInsect(D3DVECTOR pos, float angle, ObjectType type)
+{
+ m_type = type;
+
+ m_physics = new CPhysics(m_iMan, this);
+ m_brain = new CBrain(m_iMan, this);
+
+ m_physics->SetBrain(m_brain);
+ m_brain->SetPhysics(m_physics);
+
+ if ( type == OBJECT_MOTHER )
+ {
+ m_motion = new CMotionMother(m_iMan, this);
+ }
+ if ( type == OBJECT_ANT )
+ {
+ m_motion = new CMotionAnt(m_iMan, this);
+ }
+ if ( type == OBJECT_SPIDER )
+ {
+ m_motion = new CMotionSpider(m_iMan, this);
+ }
+ if ( type == OBJECT_BEE )
+ {
+ m_motion = new CMotionBee(m_iMan, this);
+ }
+ if ( type == OBJECT_WORM )
+ {
+ m_motion = new CMotionWorm(m_iMan, this);
+ }
+ if ( m_motion == 0 ) return FALSE;
+
+ m_physics->SetMotion(m_motion);
+ m_brain->SetMotion(m_motion);
+ m_motion->SetPhysics(m_physics);
+ m_motion->SetBrain(m_brain);
+ if ( !m_motion->Create(pos, angle, type, 0.0f) )
+ {
+ if ( m_physics != 0 )
+ {
+ m_physics->DeleteObject();
+ delete m_physics;
+ m_physics = 0;
+ }
+ if ( m_brain != 0 )
+ {
+ m_brain->DeleteObject();
+ delete m_brain;
+ m_brain = 0;
+ }
+ if ( m_motion != 0 )
+ {
+ m_motion->DeleteObject();
+ delete m_motion;
+ m_motion = 0;
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Crée l'ombre sous un véhicule sous forme d'une lumière
+// négative.
+
+BOOL CObject::CreateShadowLight(float height, D3DCOLORVALUE color)
+{
+ D3DLIGHT7 light;
+ D3DVECTOR pos;
+
+ if ( !m_engine->RetLightMode() ) return TRUE;
+
+ pos = RetPosition(0);
+ m_shadowHeight = height;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = color.r;
+ light.dcvDiffuse.g = color.g;
+ light.dcvDiffuse.b = color.b;
+ light.dvPosition.x = pos.x;
+ light.dvPosition.y = pos.y+height;
+ light.dvPosition.z = pos.z;
+ light.dvDirection.x = 0.0f;
+ light.dvDirection.y = -1.0f; // contre en bas
+ light.dvDirection.z = 0.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+
+ m_shadowLight = m_light->CreateLight();
+ if ( m_shadowLight == -1 ) return FALSE;
+
+ m_light->SetLight(m_shadowLight, light);
+
+ // N'éclaire que les objets du terrain.
+ m_light->SetLightIncluType(m_shadowLight, TYPETERRAIN);
+
+ return TRUE;
+}
+
+// Retourne le numéro de la lumière d'ombre négative.
+
+int CObject::RetShadowLight()
+{
+ return m_shadowLight;
+}
+
+// Crée la lumière pour les effects d'un véhicule.
+
+BOOL CObject::CreateEffectLight(float height, D3DCOLORVALUE color)
+{
+ D3DLIGHT7 light;
+
+ if ( !m_engine->RetLightMode() ) return TRUE;
+
+ m_effectHeight = height;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = color.r;
+ light.dcvDiffuse.g = color.g;
+ light.dcvDiffuse.b = color.b;
+ light.dvPosition.x = 0.0f;
+ light.dvPosition.y = 0.0f+height;
+ light.dvPosition.z = 0.0f;
+ light.dvDirection.x = 0.0f;
+ light.dvDirection.y = -1.0f; // contre en bas
+ light.dvDirection.z = 0.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+
+ m_effectLight = m_light->CreateLight();
+ if ( m_effectLight == -1 ) return FALSE;
+
+ m_light->SetLight(m_effectLight, light);
+ m_light->SetLightIntensity(m_effectLight, 0.0f);
+
+ return TRUE;
+}
+
+// Retourne le numéro de la lumière des effets.
+
+int CObject::RetEffectLight()
+{
+ return m_effectLight;
+}
+
+// Crée l'ombre circulaire sous un véhicule.
+
+BOOL CObject::CreateShadowCircle(float radius, float intensity,
+ D3DShadowType type)
+{
+ float zoom;
+
+ if ( intensity == 0.0f ) return TRUE;
+
+ zoom = RetZoomX(0);
+
+ m_engine->ShadowCreate(m_objectPart[0].object);
+
+ m_engine->SetObjectShadowRadius(m_objectPart[0].object, radius*zoom);
+ m_engine->SetObjectShadowIntensity(m_objectPart[0].object, intensity);
+ m_engine->SetObjectShadowHeight(m_objectPart[0].object, 0.0f);
+ m_engine->SetObjectShadowAngle(m_objectPart[0].object, m_objectPart[0].angle.y);
+ m_engine->SetObjectShadowType(m_objectPart[0].object, type);
+
+ return TRUE;
+}
+
+// Crée un batiment quelconque posé sur le sol.
+
+BOOL CObject::CreateBuilding(D3DVECTOR pos, float angle, float height,
+ ObjectType type, float power)
+{
+ CModFile* pModFile;
+ FPOINT p;
+ int rank, i;
+
+ if ( m_engine->RetRestCreate() < 20 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+
+ if ( m_type == OBJECT_PORTICO )
+ {
+ pModFile->ReadModel("objects\\portico1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\portico2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 67.0f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\portico3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(0.0f, 0.0f, -33.0f));
+ SetAngleY(2, 45.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(3, rank);
+ SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\portico4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(3, D3DVECTOR(50.0f, 0.0f, 0.0f));
+ SetAngleY(3, -60.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(4, rank);
+ SetObjectParent(4, 3);
+ pModFile->ReadModel("objects\\portico5.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(4, D3DVECTOR(35.0f, 0.0f, 0.0f));
+ SetAngleY(4, -55.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(5, rank);
+ SetObjectParent(5, 1);
+ pModFile->ReadModel("objects\\portico3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(5, D3DVECTOR(0.0f, 0.0f, 33.0f));
+ SetAngleY(5, -45.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(6, rank);
+ SetObjectParent(6, 5);
+ pModFile->ReadModel("objects\\portico4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(6, D3DVECTOR(50.0f, 0.0f, 0.0f));
+ SetAngleY(6, 60.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(7, rank);
+ SetObjectParent(7, 6);
+ pModFile->ReadModel("objects\\portico5.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(7, D3DVECTOR(35.0f, 0.0f, 0.0f));
+ SetAngleY(7, 55.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(8, rank);
+ SetObjectParent(8, 0);
+ pModFile->ReadModel("objects\\portico6.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(8, D3DVECTOR(-35.0f, 50.0f, -35.0f));
+ SetAngleY(8, -PI/2.0f);
+ SetZoom(8, 2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(9, rank);
+ SetObjectParent(9, 8);
+ pModFile->ReadModel("objects\\portico7.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(9, D3DVECTOR(0.0f, 4.5f, 1.9f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(10, rank);
+ SetObjectParent(10, 0);
+ pModFile->ReadModel("objects\\portico6.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(10, D3DVECTOR(-35.0f, 50.0f, 35.0f));
+ SetAngleY(10, -PI/2.0f);
+ SetZoom(10, 2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(11, rank);
+ SetObjectParent(11, 10);
+ pModFile->ReadModel("objects\\portico7.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(11, D3DVECTOR(0.0f, 4.5f, 1.9f));
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 28.0f, 0.0f), 45.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 27.0f, 10.0f, -42.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 10.0f, -42.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-27.0f, 10.0f, -42.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 27.0f, 10.0f, 42.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 10.0f, 42.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-27.0f, 10.0f, 42.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-32.0f, 45.0f, -32.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-32.0f, 45.0f, 32.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 32.0f, 45.0f, -32.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 32.0f, 45.0f, 32.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 35.0f, 0.0f), 50.0f);
+
+ CreateShadowCircle(50.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_BASE )
+ {
+ pModFile->ReadModel("objects\\base1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ for ( i=0 ; i<8 ; i++ )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1+i, rank);
+ SetObjectParent(1+i, 0);
+ pModFile->ReadModel("objects\\base2.mod");
+ pModFile->CreateEngineObject(rank);
+ p = RotatePoint(-PI/4.0f*i, 27.8f);
+ SetPosition(1+i, D3DVECTOR(p.x, 30.0f, p.y));
+ SetAngleY(1+i, PI/4.0f*i);
+ SetAngleZ(1+i, PI/2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(10+i, rank);
+ SetObjectParent(10+i, 1+i);
+ pModFile->ReadModel("objects\\base4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(10+i, D3DVECTOR(23.5f, 0.0f, 7.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(18+i, rank);
+ SetObjectParent(18+i, 1+i);
+ pModFile->ReadModel("objects\\base4.mod");
+ pModFile->Mirror();
+ pModFile->CreateEngineObject(rank);
+ SetPosition(18+i, D3DVECTOR(23.5f, 0.0f, -7.0f));
+ }
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(9, rank);
+ SetObjectParent(9, 0);
+ pModFile->ReadModel("objects\\base3.mod"); // pilier central
+ pModFile->CreateEngineObject(rank);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 33.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 39.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 45.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 51.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 57.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 63.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 69.0f, 0.0f), 2.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 82.0f, 0.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 18.0f, 94.0f, 0.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-18.0f, 94.0f, 0.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 94.0f, 18.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 94.0f, -18.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 13.0f, 94.0f, 13.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-13.0f, 94.0f, 13.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 13.0f, 94.0f, -13.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-13.0f, 94.0f, -13.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f,104.0f, 0.0f), 14.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 45.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(60.0f, 1.0f);
+ m_showLimitRadius = 200.0f;
+
+ m_terrain->AddBuildingLevel(pos, 28.6f, 73.4f, 30.0f, 0.4f);
+ }
+
+ if ( m_type == OBJECT_DERRICK )
+ {
+ pModFile->ReadModel("objects\\derrick1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\derrick2.mod");
+ pModFile->CreateEngineObject(rank);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 17.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 26.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(7.0f, 17.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(10.0f, 0.4f);
+ }
+
+ if ( m_type == OBJECT_RESEARCH )
+ {
+ pModFile->ReadModel("objects\\search1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\search2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 13.0f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\search3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(0.0f, 4.0f, 0.0f));
+ SetAngleZ(2, 35.0f*PI/180.0f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 9.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 9.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 14.0f, 0.0f), 7.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 8.0f, 0.0f), 12.0f);
+
+ m_character.posPower = D3DVECTOR(7.5f, 3.0f, 0.0f);
+
+ CreateShadowCircle(12.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_RADAR )
+ {
+ pModFile->ReadModel("objects\\radar1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\radar2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 5.0f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\radar3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(0.0f, 11.0f, 0.0f));
+ SetAngleY(2, -PI/2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(3, rank);
+ SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\radar4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(3, D3DVECTOR(0.0f, 4.5f, 1.9f));
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 11.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 7.0f, 0.0f), 7.0f);
+
+ CreateShadowCircle(8.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_INFO )
+ {
+ pModFile->ReadModel("objects\\info1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\info2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 5.0f, 0.0f));
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2+i*2, rank);
+ SetObjectParent(2+i*2, 1);
+ pModFile->ReadModel("objects\\info3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2+i*2, D3DVECTOR(0.0f, 4.5f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(3+i*2, rank);
+ SetObjectParent(3+i*2, 2+i*2);
+ pModFile->ReadModel("objects\\radar4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(3+i*2, D3DVECTOR(0.0f, 0.0f, -4.0f));
+
+ SetAngleY(2+i*2, 2.0f*PI/3.0f*i);
+ }
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 11.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 6.0f);
+
+ CreateShadowCircle(8.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_ENERGY )
+ {
+ pModFile->ReadModel("objects\\energy.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ CreateCrashSphere(D3DVECTOR(-2.0f, 13.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-7.0f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 0.0f), 1.5f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(-7.0f, 5.0f, 0.0f), 5.0f);
+
+ m_character.posPower = D3DVECTOR(0.0f, 3.0f, 0.0f);
+ m_energy = power; // initialise le niveau d'énergie
+
+ CreateShadowCircle(6.0f, 0.5f);
+ }
+
+ if ( m_type == OBJECT_LABO )
+ {
+ pModFile->ReadModel("objects\\labo1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\labo2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(-9.0f, 3.0f, 0.0f));
+ SetAngleZ(1, PI/2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\labo3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(9.0f, -1.0f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(3, rank);
+ SetObjectParent(3, 2);
+ pModFile->ReadModel("objects\\labo4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(3, D3DVECTOR(0.0f, 0.0f, 0.0f));
+ SetAngleZ(3, 80.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(4, rank);
+ SetObjectParent(4, 2);
+ pModFile->ReadModel("objects\\labo4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(4, D3DVECTOR(0.0f, 0.0f, 0.0f));
+ SetAngleZ(4, 80.0f*PI/180.0f);
+ SetAngleY(4, PI*2.0f/3.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(5, rank);
+ SetObjectParent(5, 2);
+ pModFile->ReadModel("objects\\labo4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(5, D3DVECTOR(0.0f, 0.0f, 0.0f));
+ SetAngleZ(5, 80.0f*PI/180.0f);
+ SetAngleY(5, -PI*2.0f/3.0f);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 0.0f), 1.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 11.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 10.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 3.0f, 3.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 3.0f, -3.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(-10.0f, 5.0f, 0.0f), 7.0f);
+
+ m_character.posPower = D3DVECTOR(0.0f, 3.0f, 0.0f);
+
+ CreateShadowCircle(7.0f, 0.5f);
+ }
+
+ if ( m_type == OBJECT_FACTORY )
+ {
+ pModFile->ReadModel("objects\\factory1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ for ( i=0 ; i<9 ; i++ )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1+i, rank);
+ SetObjectParent(1+i, 0);
+ pModFile->ReadModel("objects\\factory2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1+i, D3DVECTOR(10.0f, 2.0f*i, 10.0f));
+ SetAngleZ(1+i, PI/2.0f);
+ SetZoomZ(1+i, 0.30f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(10+i, rank);
+ SetObjectParent(10+i, 0);
+ pModFile->ReadModel("objects\\factory2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(10+i, D3DVECTOR(10.0f, 2.0f*i, -10.0f));
+ SetAngleZ(10+i, -PI/2.0f);
+ SetAngleY(10+i, PI);
+ SetZoomZ(10+i, 0.30f);
+ }
+
+ for ( i=0 ; i<2 ; i++ )
+ {
+ float s = (float)(i*2-1);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 2.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 2.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 2.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 2.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 9.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 9.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 9.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 9.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 16.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 16.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 16.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 16.0f, 11.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 16.0f, 4.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 16.0f, 4.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 16.0f, 4.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 16.0f, 4.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 2.0f, 4.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 9.0f, 4.0f*s), 4.0f, SOUND_BOUMm, 0.45f);
+ }
+ CreateCrashSphere(D3DVECTOR(-10.0f, 21.0f, -4.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 18.0f);
+
+ CreateShadowCircle(24.0f, 0.3f);
+ }
+
+ if ( m_type == OBJECT_REPAIR )
+ {
+ pModFile->ReadModel("objects\\repair1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\repair2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(-11.0f, 13.5f, 0.0f));
+ SetAngleZ(1, PI/2.0f);
+
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR(-11.0f, 0.0f, 4.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 0.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 0.0f, -4.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 10.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(-11.0f, 13.0f, 0.0f), 15.0f);
+ }
+
+ if ( m_type == OBJECT_DESTROYER )
+ {
+ pModFile->ReadModel("objects\\destroy1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\destroy2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR(-3.5f, 0.0f, -13.5f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.5f, 0.0f, -13.5f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.5f, 0.0f, 13.5f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.5f, 0.0f, 13.5f), 4.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(19.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_STATION )
+ {
+ pModFile->ReadModel("objects\\station.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR(-15.0f, 2.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 6.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(-15.0f, 5.0f, 0.0f), 6.0f);
+
+ m_energy = power; // initialise le niveau d'énergie
+ }
+
+ if ( m_type == OBJECT_CONVERT )
+ {
+ pModFile->ReadModel("objects\\convert1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\convert2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 14.0f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\convert3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(0.0f, 11.5f, 0.0f));
+ SetAngleX(2, -PI*0.35f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(3, rank);
+ SetObjectParent(3, 0);
+ pModFile->ReadModel("objects\\convert3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(3, D3DVECTOR(0.0f, 11.5f, 0.0f));
+ SetAngleY(3, PI);
+ SetAngleX(3, -PI*0.35f);
+
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR(-10.0f, 2.0f, 4.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 2.0f, -4.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 9.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 14.0f, 0.0f), 1.5f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(-3.0f, 8.0f, 0.0f), 14.0f);
+ }
+
+ if ( m_type == OBJECT_TOWER )
+ {
+ pModFile->ReadModel("objects\\tower.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\roller2c.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 20.0f, 0.0f));
+ SetAngleZ(1, PI/2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\roller3c.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(4.5f, 0.0f, 0.0f));
+ SetAngleZ(2, 0.0f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 6.5f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 8.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 15.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 24.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 7.0f);
+
+ m_character.posPower = D3DVECTOR(5.0f, 3.0f, 0.0f);
+
+ CreateShadowCircle(6.0f, 1.0f);
+ m_showLimitRadius = BLITZPARA;
+ }
+
+ if ( m_type == OBJECT_NUCLEAR )
+ {
+ pModFile->ReadModel("objects\\nuclear1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\nuclear2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(20.0f, 10.0f, 0.0f));
+ SetAngleZ(1, 135.0f*PI/180.0f);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 0.0f, 0.0f), 19.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 24.0f, 0.0f), 15.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(22.0f, 1.0f, 0.0f), 1.5f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 17.0f, 0.0f), 26.0f);
+
+ m_character.posPower = D3DVECTOR(22.0f, 3.0f, 0.0f);
+
+ CreateShadowCircle(21.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_PARA )
+ {
+ pModFile->ReadModel("objects\\para.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ m_terrain->AddBuildingLevel(pos, 16.0f, 18.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR( 13.0f, 3.0f, 13.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 11.0f, 15.0f, 11.0f), 2.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-13.0f, 3.0f, 13.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 15.0f, -11.0f), 2.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 13.0f, 3.0f, -13.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 11.0f, 15.0f, -11.0f), 2.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-13.0f, 3.0f, -13.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 15.0f, -11.0f), 2.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 26.0f, 0.0f), 9.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 54.0f, 0.0f), 14.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 20.0f);
+
+ CreateShadowCircle(21.0f, 1.0f);
+ m_showLimitRadius = BLITZPARA;
+ }
+
+ if ( m_type == OBJECT_SAFE )
+ {
+ pModFile->ReadModel("objects\\safe1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\safe2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetZoom(1, 1.05f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\safe3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetZoom(2, 1.05f);
+
+ m_terrain->AddBuildingLevel(pos, 18.0f, 20.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 13.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 13.0f);
+
+ CreateShadowCircle(23.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_HUSTON )
+ {
+ pModFile->ReadModel("objects\\huston1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\huston2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 39.0f, 30.0f));
+ SetAngleY(1, -PI/2.0f);
+ SetZoom(1, 3.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\huston3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(0.0f, 4.5f, 1.9f));
+
+ CreateCrashSphere(D3DVECTOR( 15.0f, 6.0f, -53.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 6.0f, -53.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 15.0f, 6.0f, -26.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 6.0f, -26.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 15.0f, 6.0f, 0.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 6.0f, 0.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 15.0f, 6.0f, 26.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 6.0f, 26.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 15.0f, 6.0f, 53.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 6.0f, 53.0f), 16.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 27.0f, 30.0f), 12.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 45.0f, 30.0f), 14.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 26.0f, 4.0f, -61.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-26.0f, 4.0f, -61.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 26.0f, 4.0f, 61.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-26.0f, 4.0f, 61.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ }
+
+ if ( m_type == OBJECT_TARGET1 )
+ {
+ pModFile->ReadModel("objects\\target1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 1.5f);
+ SetFloorHeight(0.0f);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 50.0f+14.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -7.0f, 50.0f+12.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 7.0f, 50.0f+12.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 50.0f+ 7.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 12.0f, 50.0f+ 7.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-14.0f, 50.0f+ 0.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 14.0f, 50.0f+ 0.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 50.0f- 7.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 12.0f, 50.0f- 7.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -7.0f, 50.0f-12.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 7.0f, 50.0f-12.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 50.0f-14.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 30.0f, 0.0f), 2.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 24.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 16.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 8.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(15.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_TARGET2 )
+ {
+ pModFile->ReadModel("objects\\target2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ height += 50.0f*1.5f;
+ }
+
+ if ( m_type == OBJECT_NEST )
+ {
+ pModFile->ReadModel("objects\\nest.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ m_terrain->AddBuildingLevel(pos, 3.0f, 5.0f, 1.0f, 0.5f);
+
+ CreateShadowCircle(4.0f, 1.0f);
+ }
+
+ if ( m_type == OBJECT_START )
+ {
+ pModFile->ReadModel("objects\\start.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+ }
+
+ if ( m_type == OBJECT_END )
+ {
+ pModFile->ReadModel("objects\\end.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+ }
+
+#if 0
+ if ( power > 0.0f ) // crée une pile ?
+ {
+ CObject* pPower;
+
+ pPower = new CObject(m_iMan);
+ pPower->SetType(power<=1.0f?OBJECT_POWER:OBJECT_ATOMIC);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ pPower->SetObjectRank(0, rank);
+
+ if ( power <= 1.0f ) pModFile->ReadModel("objects\\power.mod");
+ else pModFile->ReadModel("objects\\atomic.mod");
+ pModFile->CreateEngineObject(rank);
+
+ pPower->SetPosition(0, RetCharacter()->posPower);
+ pPower->CreateCrashSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ pPower->SetGlobalSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 1.5f);
+
+ pPower->SetTruck(this);
+ SetPower(pPower);
+
+ if ( power <= 1.0f ) pPower->SetEnergy(power);
+ else pPower->SetEnergy(power/100.0f);
+ }
+#endif
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ CreateOtherObject(type);
+ m_engine->LoadAllTexture();
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée une petite ressource posée sur le sol.
+
+BOOL CObject::CreateResource(D3DVECTOR pos, float angle, ObjectType type,
+ float power)
+{
+ CModFile* pModFile;
+ char name[50];
+ int rank;
+ float radius, height;
+
+ if ( type != OBJECT_SHOW )
+ {
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+ }
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ SetEnergy(power);
+
+ name[0] = 0;
+ if ( type == OBJECT_STONE ) strcpy(name, "objects\\stone.mod");
+ if ( type == OBJECT_URANIUM ) strcpy(name, "objects\\uranium.mod");
+ if ( type == OBJECT_METAL ) strcpy(name, "objects\\metal.mod");
+ if ( type == OBJECT_POWER ) strcpy(name, "objects\\power.mod");
+ if ( type == OBJECT_ATOMIC ) strcpy(name, "objects\\atomic.mod");
+ if ( type == OBJECT_BULLET ) strcpy(name, "objects\\bullet.mod");
+ if ( type == OBJECT_BBOX ) strcpy(name, "objects\\bbox.mod");
+ if ( type == OBJECT_KEYa ) strcpy(name, "objects\\keya.mod");
+ if ( type == OBJECT_KEYb ) strcpy(name, "objects\\keyb.mod");
+ if ( type == OBJECT_KEYc ) strcpy(name, "objects\\keyc.mod");
+ if ( type == OBJECT_KEYd ) strcpy(name, "objects\\keyd.mod");
+ if ( type == OBJECT_TNT ) strcpy(name, "objects\\tnt.mod");
+ if ( type == OBJECT_SCRAP1 ) strcpy(name, "objects\\scrap1.mod");
+ if ( type == OBJECT_SCRAP2 ) strcpy(name, "objects\\scrap2.mod");
+ if ( type == OBJECT_SCRAP3 ) strcpy(name, "objects\\scrap3.mod");
+ if ( type == OBJECT_SCRAP4 ) strcpy(name, "objects\\scrap4.mod");
+ if ( type == OBJECT_SCRAP5 ) strcpy(name, "objects\\scrap5.mod");
+ if ( type == OBJECT_BOMB ) strcpy(name, "objects\\bomb.mod");
+ if ( type == OBJECT_WAYPOINT ) strcpy(name, "objects\\waypoint.mod");
+ if ( type == OBJECT_SHOW ) strcpy(name, "objects\\show.mod");
+ if ( type == OBJECT_WINFIRE ) strcpy(name, "objects\\winfire.mod");
+ if ( type == OBJECT_BAG ) strcpy(name, "objects\\bag.mod");
+ if ( type == OBJECT_MARKSTONE ) strcpy(name, "objects\\cross1.mod");
+ if ( type == OBJECT_MARKURANIUM ) strcpy(name, "objects\\cross3.mod");
+ if ( type == OBJECT_MARKPOWER ) strcpy(name, "objects\\cross2.mod");
+ if ( type == OBJECT_MARKKEYa ) strcpy(name, "objects\\crossa.mod");
+ if ( type == OBJECT_MARKKEYb ) strcpy(name, "objects\\crossb.mod");
+ if ( type == OBJECT_MARKKEYc ) strcpy(name, "objects\\crossc.mod");
+ if ( type == OBJECT_MARKKEYd ) strcpy(name, "objects\\crossd.mod");
+ if ( type == OBJECT_EGG ) strcpy(name, "objects\\egg.mod");
+
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ if ( type == OBJECT_SHOW ) // reste en l'air ?
+ {
+ delete pModFile;
+ return TRUE;
+ }
+
+ radius = 1.5f;
+ height = 0.0f;
+
+ if ( type == OBJECT_MARKSTONE ||
+ type == OBJECT_MARKURANIUM ||
+ type == OBJECT_MARKKEYa ||
+ type == OBJECT_MARKKEYb ||
+ type == OBJECT_MARKKEYc ||
+ type == OBJECT_MARKKEYd ||
+ type == OBJECT_MARKPOWER ||
+ type == OBJECT_WAYPOINT )
+ {
+ }
+ else if ( type == OBJECT_EGG )
+ {
+ CreateCrashSphere(D3DVECTOR(-1.0f, 2.8f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 10.0f);
+ radius = 3.0f;
+ }
+ else if ( type == OBJECT_BOMB )
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 3.0f);
+ radius = 3.0f;
+ }
+ else if ( type == OBJECT_BAG )
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f);
+ SetZoom(0, 1.5f);
+ radius = 5.0f;
+ height = -1.4f;
+ }
+ else
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 1.5f);
+ }
+ CreateShadowCircle(radius, 1.0f);
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+ m_engine->LoadAllTexture();
+ FloorAdjust();
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée un drapeau posé sur le sol.
+
+BOOL CObject::CreateFlag(D3DVECTOR pos, float angle, ObjectType type)
+{
+ CModFile* pModFile;
+ char name[50];
+ int rank, i;
+
+ if ( m_engine->RetRestCreate() < 1+4 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ name[0] = 0;
+ if ( type == OBJECT_FLAGb ) strcpy(name, "objects\\flag1b.mod");
+ if ( type == OBJECT_FLAGr ) strcpy(name, "objects\\flag1r.mod");
+ if ( type == OBJECT_FLAGg ) strcpy(name, "objects\\flag1g.mod");
+ if ( type == OBJECT_FLAGy ) strcpy(name, "objects\\flag1y.mod");
+ if ( type == OBJECT_FLAGv ) strcpy(name, "objects\\flag1v.mod");
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ name[0] = 0;
+ if ( type == OBJECT_FLAGb ) strcpy(name, "objects\\flag2b.mod");
+ if ( type == OBJECT_FLAGr ) strcpy(name, "objects\\flag2r.mod");
+ if ( type == OBJECT_FLAGg ) strcpy(name, "objects\\flag2g.mod");
+ if ( type == OBJECT_FLAGy ) strcpy(name, "objects\\flag2y.mod");
+ if ( type == OBJECT_FLAGv ) strcpy(name, "objects\\flag2v.mod");
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1+i, rank);
+ SetObjectParent(1+i, i);
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+ if ( i == 0 ) SetPosition(1+i, D3DVECTOR(0.15f, 5.0f, 0.0f));
+ else SetPosition(1+i, D3DVECTOR(0.79f, 0.0f, 0.0f));
+ }
+
+ SetJotlerSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 1.0f);
+ CreateShadowCircle(2.0f, 0.3f);
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+ m_engine->LoadAllTexture();
+ FloorAdjust();
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée une barrière posée sur le sol.
+
+BOOL CObject::CreateBarrier(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_BARRIER0 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\barrier0.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(6.0f, 0.5f, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_BARRIER1 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\barrier1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(12.0f, 0.5f, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_BARRIER2 ) // en carton ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\barrier2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(12.0f, 0.8f, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_BARRIER3 ) // allumettes + paille ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\barrier3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-8.5f, 3.0f, 0.0f), 0.7f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(10.0f, 0.5f, D3DSHADOWWORM);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+ FloorAdjust();
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée une plante posée sur le sol.
+
+BOOL CObject::CreatePlant(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_PLANT0 ||
+ type == OBJECT_PLANT1 ||
+ type == OBJECT_PLANT2 ||
+ type == OBJECT_PLANT3 ||
+ type == OBJECT_PLANT4 ) // standard ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ if ( type == OBJECT_PLANT0 ) pModFile->ReadModel("objects\\plant0.mod");
+ if ( type == OBJECT_PLANT1 ) pModFile->ReadModel("objects\\plant1.mod");
+ if ( type == OBJECT_PLANT2 ) pModFile->ReadModel("objects\\plant2.mod");
+ if ( type == OBJECT_PLANT3 ) pModFile->ReadModel("objects\\plant3.mod");
+ if ( type == OBJECT_PLANT4 ) pModFile->ReadModel("objects\\plant4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ height -= 2.0f;
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 6.0f);
+ SetJotlerSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 8.0f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_PLANT5 ||
+ type == OBJECT_PLANT6 ||
+ type == OBJECT_PLANT7 ) // trèfle ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ if ( type == OBJECT_PLANT5 ) pModFile->ReadModel("objects\\plant5.mod");
+ if ( type == OBJECT_PLANT6 ) pModFile->ReadModel("objects\\plant6.mod");
+ if ( type == OBJECT_PLANT7 ) pModFile->ReadModel("objects\\plant7.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+//? CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 3.0f, SOUND_BOUM, 0.10f);
+ SetJotlerSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f);
+
+ CreateShadowCircle(5.0f, 0.3f);
+ }
+
+ if ( type == OBJECT_PLANT8 ||
+ type == OBJECT_PLANT9 ) // courgette ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ if ( type == OBJECT_PLANT8 ) pModFile->ReadModel("objects\\plant8.mod");
+ if ( type == OBJECT_PLANT9 ) pModFile->ReadModel("objects\\plant9.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+
+ CreateShadowCircle(10.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_PLANT10 ||
+ type == OBJECT_PLANT11 ||
+ type == OBJECT_PLANT12 ||
+ type == OBJECT_PLANT13 ||
+ type == OBJECT_PLANT14 ) // plante grasse ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ if ( type == OBJECT_PLANT10 ) pModFile->ReadModel("objects\\plant10.mod");
+ if ( type == OBJECT_PLANT11 ) pModFile->ReadModel("objects\\plant11.mod");
+ if ( type == OBJECT_PLANT12 ) pModFile->ReadModel("objects\\plant12.mod");
+ if ( type == OBJECT_PLANT13 ) pModFile->ReadModel("objects\\plant13.mod");
+ if ( type == OBJECT_PLANT14 ) pModFile->ReadModel("objects\\plant14.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 12.0f, 0.0f), 5.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 6.0f);
+ SetJotlerSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 8.0f);
+
+ CreateShadowCircle(8.0f, 0.3f);
+ }
+
+ if ( type == OBJECT_PLANT15 ||
+ type == OBJECT_PLANT16 ||
+ type == OBJECT_PLANT17 ||
+ type == OBJECT_PLANT18 ||
+ type == OBJECT_PLANT19 ) // fougère ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ if ( type == OBJECT_PLANT15 ) pModFile->ReadModel("objects\\plant15.mod");
+ if ( type == OBJECT_PLANT16 ) pModFile->ReadModel("objects\\plant16.mod");
+ if ( type == OBJECT_PLANT17 ) pModFile->ReadModel("objects\\plant17.mod");
+ if ( type == OBJECT_PLANT18 ) pModFile->ReadModel("objects\\plant18.mod");
+ if ( type == OBJECT_PLANT19 ) pModFile->ReadModel("objects\\plant19.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ if ( type != OBJECT_PLANT19 )
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 6.0f);
+ }
+ SetJotlerSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 8.0f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TREE0 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\tree0.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 2.0f), 3.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-1.0f, 10.0f, 1.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 17.0f, 0.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 1.0f, 27.0f, 0.0f), 2.0f, SOUND_BOUMs, 0.20f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TREE1 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\tree1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 2.0f), 3.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 11.0f, 1.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 19.0f, 2.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 2.0f, 26.0f, 0.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 2.0f, 34.0f,-2.0f), 2.0f, SOUND_BOUMs, 0.20f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TREE2 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\tree2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 3.0f, 1.0f), 3.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 10.0f, 1.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 19.0f, 2.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 2.0f, 25.0f, 0.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 32.0f,-2.0f), 2.0f, SOUND_BOUMs, 0.20f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TREE3 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\tree3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(-2.0f, 3.0f, 2.0f), 3.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-3.0f, 9.0f, 1.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 18.0f, 0.0f), 2.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 27.0f, 7.0f), 2.0f, SOUND_BOUMs, 0.20f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TREE4 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\tree4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 10.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 21.0f, 0.0f), 8.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(0.0f, 32.0f, 0.0f), 7.0f, SOUND_BOUMs, 0.20f);
+
+ CreateShadowCircle(8.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TREE5 ) // arbre géant (pour monde "teen")
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\tree5.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 5.0f,-10.0f), 25.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR(-65.0f, 5.0f, 65.0f), 20.0f, SOUND_BOUMs, 0.20f);
+ CreateCrashSphere(D3DVECTOR( 38.0f, 5.0f, 21.0f), 18.0f, SOUND_BOUMs, 0.20f);
+
+ CreateShadowCircle(50.0f, 0.5f);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée un champignon posé sur le sol.
+
+BOOL CObject::CreateMushroom(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_MUSHROOM1 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\mush1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 3.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 5.5f);
+ SetJotlerSphere(D3DVECTOR(0.0f, 3.0f, 0.0f), 5.5f);
+
+ CreateShadowCircle(6.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_MUSHROOM2 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\mush2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 3.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 5.5f);
+ SetJotlerSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 5.5f);
+
+ CreateShadowCircle(5.0f, 0.5f);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée un jouet posé sur le sol.
+
+BOOL CObject::CreateTeen(D3DVECTOR pos, float angle, float zoom, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ D3DMATRIX* mat;
+ D3DCOLORVALUE color;
+ int rank;
+ float fShadow;
+ BOOL bFloorAdjust = TRUE;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ fShadow = Norm(1.0f-height/10.0f);
+
+ if ( type == OBJECT_TEEN0 ) // crayon orange lg=10
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen0.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 5.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 2.5f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-2.5f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(5.0f, 0.8f*fShadow, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_TEEN1 ) // crayon bleu lg=14
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 6.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 2.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-4.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-6.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(6.0f, 0.8f*fShadow, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_TEEN2 ) // crayon rouge lg=16
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 7.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.7f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 2.3f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-2.3f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-4.7f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-7.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(6.0f, 0.8f*fShadow, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_TEEN3 ) // bocal avec crayon
+ {
+ rank = m_engine->CreateObject();
+//? m_engine->SetObjectType(rank, TYPEFIX);
+ m_engine->SetObjectType(rank, TYPEMETAL);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 4.0f);
+ CreateShadowCircle(6.0f, 0.5f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN4 ) // ciseaux
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-9.0f, 1.0f, 0.0f), 1.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-6.0f, 1.0f, 0.0f), 1.1f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.0f, 1.0f, 0.0f), 1.2f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 0.0f), 1.3f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 5.1f, 1.0f,-1.3f), 2.6f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 8.0f, 1.0f, 2.2f), 2.3f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 9.4f, 1.0f,-2.0f), 2.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(10.0f, 0.5f*fShadow, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_TEEN5 ) // CD
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen5.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ SetFloorHeight(0.0f);
+ bFloorAdjust = FALSE;
+
+ m_terrain->AddBuildingLevel(pos, 5.9f, 6.1f, 0.2f, 0.5f);
+ CreateShadowCircle(8.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN6 ) // livre 1
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen6.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(20.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN7 ) // livre 2
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen7.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(20.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN8 ) // pile de livres 1
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen8.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 12.0f);
+ CreateShadowCircle(20.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN9 ) // pile de livres 2
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen9.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-5.0f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 4.5f, 3.0f,-7.5f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 12.0f);
+ CreateShadowCircle(20.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN10 ) // bibliothèque
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen10.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-26.0f, 3.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 3.0f,-4.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-15.0f, 3.0f, 5.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -4.0f, 3.0f,-4.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -4.0f, 3.0f, 5.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 6.0f, 3.0f,-4.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 6.0f, 3.0f, 4.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 14.0f, 3.0f,-3.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 14.0f, 3.0f, 2.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 24.0f, 3.0f, 5.0f), 6.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 20.0f);
+ CreateShadowCircle(40.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN11 ) // lampe
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen11.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+ SetZoom(0, zoom);
+
+ mat = RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(-56.0f, 22.0f, 0.0f));
+ m_particule->CreateParticule(pos, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(20.0f, 20.0f), PARTISELY, 1.0f, 0.0f, 0.0f);
+
+ pos = Transform(*mat, D3DVECTOR(-65.0f, 40.0f, 0.0f));
+ color.r = 4.0f;
+ color.g = 2.0f;
+ color.b = 0.0f; // jaune-orange
+ color.a = 0.0f;
+ m_main->CreateSpot(pos, color);
+ }
+
+ if ( type == OBJECT_TEEN12 ) // coca
+ {
+ rank = m_engine->CreateObject();
+//? m_engine->SetObjectType(rank, TYPEFIX);
+ m_engine->SetObjectType(rank, TYPEMETAL);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen12.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 0.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 9.0f, 0.0f), 5.0f);
+ CreateShadowCircle(4.5f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN13 ) // carton fermé
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen13.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 15.0f);
+ CreateShadowCircle(20.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN14 ) // carton ouvert
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen14.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 15.0f);
+ CreateShadowCircle(20.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN15 ) // pile de cartons
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen15.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f,-7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 4.0f, 7.0f), 5.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 15.0f);
+ CreateShadowCircle(20.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN16 ) // arrosoir
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen16.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-8.0f, 4.0f, 0.0f), 12.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 8.0f, 4.0f, 0.0f), 12.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 13.0f, 0.0f), 20.0f);
+ CreateShadowCircle(18.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN17 ) // roue |
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen17.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 31.0f, 0.0f), 31.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 31.0f, 0.0f), 31.0f);
+ CreateShadowCircle(24.0f, 0.5f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN18 ) // roue /
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen18.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 31.0f, 0.0f), 31.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 31.0f, 0.0f), 31.0f);
+ CreateShadowCircle(24.0f, 0.5f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN19 ) // roue =
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen19.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 10.0f, 0.0f), 32.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 32.0f);
+ CreateShadowCircle(33.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN20 ) // mur avec étagère
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen20.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-175.0f, 0.0f, -5.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-175.0f, 0.0f, -35.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -55.0f, 0.0f, -5.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -55.0f, 0.0f, -35.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -37.0f, 0.0f, -5.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -37.0f, 0.0f, -35.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 83.0f, 0.0f, -5.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 83.0f, 0.0f, -35.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ }
+
+ if ( type == OBJECT_TEEN21 ) // mur avec fenêtre
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen21.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ }
+
+ if ( type == OBJECT_TEEN22 ) // mur avec porte et étagère
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen22.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-135.0f, 0.0f, -5.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-135.0f, 0.0f, -35.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -15.0f, 0.0f, -5.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -15.0f, 0.0f, -35.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ }
+
+ if ( type == OBJECT_TEEN23 ) // skate sur ses roues
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen23.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ if ( m_option == 1 ) // passage sous le skate interdit ?
+ {
+ CreateCrashSphere(D3DVECTOR(-10.0f, 2.0f, 0.0f), 11.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 10.0f, 2.0f, 0.0f), 11.0f, SOUND_BOUMm, 0.45f);
+ }
+
+ CreateCrashSphere(D3DVECTOR(-23.0f, 2.0f, 7.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-23.0f, 2.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-23.0f, 2.0f,-7.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 23.0f, 2.0f, 7.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 23.0f, 2.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 23.0f, 2.0f,-7.0f), 3.0f, SOUND_BOUMm, 0.45f);
+
+ CreateShadowCircle(35.0f, 0.8f*fShadow, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_TEEN24 ) // skate /
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen24.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-12.0f, 0.0f, -3.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 0.0f, 3.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateShadowCircle(20.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN25 ) // skate /
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen25.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-12.0f, 0.0f, -3.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 0.0f, 3.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateShadowCircle(20.0f, 0.2f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN26 ) // lampe au plafond
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen26.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ SetFloorHeight(0.0f);
+
+ mat = RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(0.0f, 50.0f, 0.0f));
+ m_particule->CreateParticule(pos, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(100.0f, 100.0f), PARTISELY, 1.0f, 0.0f, 0.0f);
+
+ pos = Transform(*mat, D3DVECTOR(0.0f, 50.0f, 0.0f));
+ color.r = 4.0f;
+ color.g = 2.0f;
+ color.b = 0.0f; // jaune-orange
+ color.a = 0.0f;
+ m_main->CreateSpot(pos, color);
+ }
+
+ if ( type == OBJECT_TEEN27 ) // grande plante ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen27.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(40.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_TEEN28 ) // bouteille ?
+ {
+ rank = m_engine->CreateObject();
+//? m_engine->SetObjectType(rank, TYPEFIX);
+ m_engine->SetObjectType(rank, TYPEMETAL);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen28.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 5.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(7.0f, 0.6f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN29 ) // pont ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen29.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ bFloorAdjust = FALSE;
+ }
+
+ if ( type == OBJECT_TEEN30 ) // saut ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen30.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 15.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 15.0f, 0.0f), 17.0f);
+ CreateShadowCircle(20.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN31 ) // basket ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen31.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-10.0f, 2.0f, 0.0f), 5.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 2.0f, 0.0f), 6.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR( 9.0f, 4.0f, 1.0f), 6.0f, SOUND_BOUM, 0.10f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 10.0f);
+ CreateShadowCircle(16.0f, 0.6f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN32 ) // chaise ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen32.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR( 17.5f, 1.0f, 17.5f), 3.5f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR( 17.5f, 1.0f, -17.5f), 3.5f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR(-17.5f, 1.0f, 17.5f), 3.5f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR(-17.5f, 1.0f, -17.5f), 3.5f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 26.0f);
+ CreateShadowCircle(35.0f, 0.3f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN33 ) // panneau ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen33.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(10.0f, 0.3f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN34 ) // caillou ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen34.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 4.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(3.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN35 ) // tuyau ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen35.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(-40.0f, 5.0f, 0.0f), 10.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR(-20.0f, 5.0f, 0.0f), 10.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 5.0f, 0.0f), 10.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR( 20.0f, 5.0f, 0.0f), 10.0f, SOUND_BOUM, 0.10f);
+ CreateCrashSphere(D3DVECTOR( 40.0f, 5.0f, 0.0f), 10.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(40.0f, 0.8f*fShadow, D3DSHADOWWORM);
+ }
+
+ if ( type == OBJECT_TEEN36 ) // tronc ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen36.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ bFloorAdjust = FALSE;
+ }
+
+ if ( type == OBJECT_TEEN37 ) // bateau ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen37.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ bFloorAdjust = FALSE;
+ }
+
+ if ( type == OBJECT_TEEN38 ) // ventillateur ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen38a.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\teen38b.mod"); // moteur
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 30.0f, 0.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 1);
+ pModFile->ReadModel("objects\\teen38c.mod"); // hélice
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 10.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 10.0f);
+ CreateShadowCircle(15.0f, 0.5f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN39 ) // plante en pot ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen39.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 8.5f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 8.5f);
+ CreateShadowCircle(10.0f, 1.0f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN40 ) // ballon ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen40.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 11.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 14.0f, 0.0f), 15.0f);
+ CreateShadowCircle(15.0f, 0.7f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN41 ) // clôture ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen41.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+ }
+
+ if ( type == OBJECT_TEEN42 ) // trèfle ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen42.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 2.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(15.0f, 0.4f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN43 ) // trèfle ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen43.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 2.0f, SOUND_BOUM, 0.10f);
+ CreateShadowCircle(15.0f, 0.4f*fShadow);
+ }
+
+ if ( type == OBJECT_TEEN44 ) // caisse ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\teen44.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, zoom);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 55.0f, SOUND_BOUM, 0.10f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 55.0f);
+ CreateShadowCircle(55.0f, 1.0f*fShadow);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ if ( bFloorAdjust )
+ {
+ SetFloorHeight(0.0f);
+ FloorAdjust();
+ }
+
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée un quartz posé sur le sol.
+
+BOOL CObject::CreateQuartz(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ float radius;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_QUARTZ0 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEQUARTZ);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\quartz0.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 3.5f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 3.5f);
+
+ CreateShadowCircle(4.0f, 0.5f);
+ }
+ if ( type == OBJECT_QUARTZ1 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEQUARTZ);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\quartz1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 5.0f);
+
+ CreateShadowCircle(5.0f, 0.5f);
+ }
+ if ( type == OBJECT_QUARTZ2 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEQUARTZ);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\quartz2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 6.0f);
+
+ CreateShadowCircle(6.0f, 0.5f);
+ }
+ if ( type == OBJECT_QUARTZ3 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEQUARTZ);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\quartz3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 10.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(10.0f, 0.5f);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ if ( type == OBJECT_QUARTZ0 )
+ {
+ pos.y += 4.0f;
+ radius = 2.0f;
+ }
+ if ( type == OBJECT_QUARTZ1 )
+ {
+ pos.y += 6.0f;
+ radius = 4.0f;
+ }
+ if ( type == OBJECT_QUARTZ2 )
+ {
+ pos.y += 10.0f;
+ radius = 5.0f;
+ }
+ if ( type == OBJECT_QUARTZ3 )
+ {
+ pos.y += 16.0f;
+ radius = 8.0f;
+ }
+ m_particule->CreateParticule(pos, pos, FPOINT(2.0f, 2.0f), PARTIQUARTZ, 0.7f+Rand()*0.7f, radius, 0.0f);
+ m_particule->CreateParticule(pos, pos, FPOINT(2.0f, 2.0f), PARTIQUARTZ, 0.7f+Rand()*0.7f, radius, 0.0f);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée une racine posée sur le sol.
+
+BOOL CObject::CreateRoot(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_ROOT0 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\root0.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 2.0f);
+
+ CreateCrashSphere(D3DVECTOR(-5.0f, 1.0f, 0.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 4.0f, 1.0f, 2.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 4.0f, 1.0f, -3.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 2.0f, 5.0f, -1.0f), 1.5f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-4.0f, 5.0f, -1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 8.0f, -0.5f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 10.0f, -0.5f), 1.0f, SOUND_BOUMv, 0.15f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 11.0f);
+
+ CreateShadowCircle(16.0f, 0.5f);
+ }
+ if ( type == OBJECT_ROOT1 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\root1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 2.0f);
+
+ CreateCrashSphere(D3DVECTOR(-4.0f, 1.0f, 1.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 1.0f, 2.0f), 1.5f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 1.0f, -2.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-2.0f, 5.0f, 1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 2.0f, 5.0f, 0.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 8.0f, 1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 12.0f, 1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 12.0f);
+
+ CreateShadowCircle(16.0f, 0.5f);
+ }
+ if ( type == OBJECT_ROOT2 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\root2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 2.0f);
+
+ CreateCrashSphere(D3DVECTOR(-3.0f, 1.0f, 0.5f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 1.0f, -1.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-1.0f, 4.5f, 0.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 7.0f, 1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 7.0f, -1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 4.0f, 11.0f, 1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(16.0f, 0.5f);
+ }
+ if ( type == OBJECT_ROOT3 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\root3.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 2.0f);
+
+ CreateCrashSphere(D3DVECTOR(-4.0f, 1.0f, 1.0f), 3.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 4.0f, 1.0f, -3.0f), 3.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 6.0f, 1.0f, 4.0f), 3.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-2.5f, 7.0f, 2.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 4.0f, 7.0f, 2.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 6.0f, -1.0f), 1.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 12.0f, 0.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 1.0f, 16.0f, 0.0f), 1.0f, SOUND_BOUMv, 0.15f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 10.0f, 0.0f), 14.0f);
+
+ CreateShadowCircle(22.0f, 0.5f);
+ }
+ if ( type == OBJECT_ROOT4 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\root4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 2.0f);
+
+ CreateCrashSphere(D3DVECTOR( -7.0f, 2.0f, 3.0f), 4.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 5.0f, 2.0f, -6.0f), 4.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 6.0f, 2.0f, 6.0f), 3.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 1.0f, -2.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 1.0f, 1.0f, -7.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( -4.0f, 10.0f, 3.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 1.0f, 11.0f, 7.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 11.0f, -3.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 17.0f, 1.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 23.0f, -1.0f), 2.0f, SOUND_BOUMv, 0.15f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 12.0f, 0.0f), 20.0f);
+
+ CreateShadowCircle(30.0f, 0.5f);
+ }
+ if ( type == OBJECT_ROOT5 ) // gravity root ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\root4.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 2.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\root5.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(-5.0f, 28.0f, -4.0f));
+ SetAngleX(1, -30.0f*PI/180.0f);
+ SetAngleZ(1, 20.0f*PI/180.0f);
+
+ CreateCrashSphere(D3DVECTOR( -7.0f, 2.0f, 3.0f), 4.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 5.0f, 2.0f, -6.0f), 4.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 6.0f, 2.0f, 6.0f), 3.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 1.0f, -2.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 1.0f, 1.0f, -7.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( -4.0f, 10.0f, 3.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 1.0f, 11.0f, 7.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( 3.0f, 11.0f, -3.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 17.0f, 1.0f), 2.0f, SOUND_BOUMv, 0.15f);
+ CreateCrashSphere(D3DVECTOR( -3.0f, 23.0f, -1.0f), 2.0f, SOUND_BOUMv, 0.15f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 12.0f, 0.0f), 20.0f);
+
+ CreateShadowCircle(30.0f, 0.5f);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée une petite maison.
+
+BOOL CObject::CreateHome(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_HOME1 )
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX);
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\home1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 1.3f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 10.0f, SOUND_BOUMs, 0.25f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 6.0f, 0.0f), 11.0f);
+ CreateShadowCircle(16.0f, 0.5f);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos);
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée une ruine posée sur le sol.
+
+BOOL CObject::CreateRuin(D3DVECTOR pos, float angle, float height,
+ ObjectType type)
+{
+ CModFile* pModFile;
+ char name[50];
+ int rank;
+
+ if ( m_engine->RetRestCreate() < 1+4 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+
+ name[0] = 0;
+ if ( type == OBJECT_RUINmobilew1 ) strcpy(name, "objects\\ruin1.mod");
+ if ( type == OBJECT_RUINmobilew2 ) strcpy(name, "objects\\ruin1.mod");
+ if ( type == OBJECT_RUINmobilet1 ) strcpy(name, "objects\\ruin2.mod");
+ if ( type == OBJECT_RUINmobilet2 ) strcpy(name, "objects\\ruin2.mod");
+ if ( type == OBJECT_RUINmobiler1 ) strcpy(name, "objects\\ruin3.mod");
+ if ( type == OBJECT_RUINmobiler2 ) strcpy(name, "objects\\ruin3.mod");
+ if ( type == OBJECT_RUINfactory ) strcpy(name, "objects\\ruin4.mod");
+ if ( type == OBJECT_RUINdoor ) strcpy(name, "objects\\ruin5.mod");
+ if ( type == OBJECT_RUINsupport ) strcpy(name, "objects\\ruin6.mod");
+ if ( type == OBJECT_RUINradar ) strcpy(name, "objects\\ruin7.mod");
+ if ( type == OBJECT_RUINconvert ) strcpy(name, "objects\\ruin8.mod");
+ if ( type == OBJECT_RUINbase ) strcpy(name, "objects\\ruin9.mod");
+ if ( type == OBJECT_RUINhead ) strcpy(name, "objects\\ruin10.mod");
+
+ pModFile->ReadModel(name);
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+
+ if ( type == OBJECT_RUINmobilew1 ) // véhicule à roues ?
+ {
+ // Crée la roue arrière-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(6, rank);
+ SetObjectParent(6, 0);
+
+ pModFile->ReadModel("objects\\ruin1w.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(6, D3DVECTOR(-3.0f, 1.8f, -4.0f));
+ SetAngleX(6, -PI/2.0f);
+
+ // Crée la roue arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(7, rank);
+ SetObjectParent(7, 0);
+
+ pModFile->ReadModel("objects\\ruin1w.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(7, D3DVECTOR(-3.0f, 1.0f, 3.0f));
+ SetAngleY(7, PI-0.3f);
+ SetAngleX(7, -0.3f);
+
+ // Crée la roue avant-droite.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(8, rank);
+ SetObjectParent(8, 0);
+
+ pModFile->ReadModel("objects\\ruin1w.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(8, D3DVECTOR(2.0f, 1.6f, -3.0f));
+ SetAngleY(8, 0.3f);
+
+ // Crée la roue avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(9, rank);
+ SetObjectParent(9, 0);
+
+ pModFile->ReadModel("objects\\ruin1w.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(9, D3DVECTOR(2.0f, 1.0f, 3.0f));
+ SetAngleY(9, PI-0.2f);
+ SetAngleX(9, 0.2f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.8f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(4.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINmobilew2 ) // véhicule à roues ?
+ {
+ // Crée la roue arrière-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(7, rank);
+ SetObjectParent(7, 0);
+
+ pModFile->ReadModel("objects\\ruin1w.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(7, D3DVECTOR(-3.0f, 1.0f, 3.0f));
+ SetAngleY(7, PI+0.3f);
+ SetAngleX(7, 0.4f);
+
+ // Crée la roue avant-gauche.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(9, rank);
+ SetObjectParent(9, 0);
+
+ pModFile->ReadModel("objects\\ruin1w.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(9, D3DVECTOR(2.0f, 1.0f, 3.0f));
+ SetAngleY(9, PI+0.3f);
+ SetAngleX(9, -0.3f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.8f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(4.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINmobilet1 ) // véhicule à chenilles ?
+ {
+ // Crée le canon.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+
+ pModFile->ReadModel("objects\\ruin2c.mod");
+ pModFile->CreateEngineObject(rank);
+
+ SetPosition(1, D3DVECTOR(3.0f, 5.0f, -2.5f));
+ SetAngleX(1, -PI*0.85f);
+ SetAngleY(1, -0.4f);
+ SetAngleZ(1, -0.1f);
+
+ CreateCrashSphere(D3DVECTOR(1.0f, 2.8f, -1.0f), 5.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(1.0f, 5.0f, -1.0f), 10.0f);
+
+ CreateShadowCircle(5.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINmobilet2 ) // véhicule à chenilles ?
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.8f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(5.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINmobiler1 ) // véhicule roller ?
+ {
+ CreateCrashSphere(D3DVECTOR(1.0f, 2.8f, -1.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(1.0f, 5.0f, -1.0f), 10.0f);
+
+ CreateShadowCircle(5.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINmobiler2 ) // véhicule roller ?
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 1.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 5.0f, 0.0f), 10.0f);
+
+ CreateShadowCircle(6.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINfactory ) // factory ?
+ {
+ CreateCrashSphere(D3DVECTOR( 9.0f, 1.0f, -11.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 2.0f, -11.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, -10.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-12.0f, 11.0f, -4.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 4.0f, -2.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 8.0f, 3.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 2.0f, 4.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 2.0f, 10.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -4.0f, 0.0f, 10.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 18.0f);
+
+ CreateShadowCircle(20.0f, 0.7f);
+ }
+
+ if ( type == OBJECT_RUINdoor ) // porte convert ?
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 6.0f);
+
+ CreateShadowCircle(6.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINsupport ) // porte radar ?
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 4.0f);
+
+ CreateShadowCircle(3.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINradar ) // base radar ?
+ {
+ CreateCrashSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 6.0f);
+
+ CreateShadowCircle(6.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINconvert ) // convert ?
+ {
+ m_terrain->AddBuildingLevel(pos, 7.0f, 9.0f, 1.0f, 0.5f);
+
+ CreateCrashSphere(D3DVECTOR(-10.0f, 0.0f, 4.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-10.0f, 0.0f, -4.0f), 5.0f, SOUND_BOUMm, 0.45f);
+//? SetGlobalSphere(D3DVECTOR(-3.0f, 0.0f, 0.0f), 14.0f);
+ }
+
+ if ( type == OBJECT_RUINbase ) // base ?
+ {
+ CreateCrashSphere(D3DVECTOR( 0.0f, 15.0f, 0.0f),28.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 17.0f, 6.0f, 42.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 17.0f, 17.0f, 42.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-17.0f, 6.0f, 42.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-17.0f, 17.0f, 42.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-42.0f, 6.0f, 17.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-42.0f, 17.0f, 17.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-42.0f, 6.0f, -17.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-42.0f, 17.0f, -17.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-17.0f, 6.0f, -42.0f), 6.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-17.0f, 10.0f, -42.0f), 4.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 15.0f, 13.0f, -34.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 31.0f, 15.0f, -13.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 21.0f, 8.0f, -39.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 26.0f, 8.0f, -33.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 48.0f);
+
+ CreateShadowCircle(40.0f, 1.0f);
+ }
+
+ if ( type == OBJECT_RUINhead ) // coiffe base ?
+ {
+ CreateCrashSphere(D3DVECTOR( 0.0f, 13.0f, 0.0f),20.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, -8.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f,-16.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f,-22.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-21.0f, 7.0f, 9.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -9.0f, 7.0f, 21.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 21.0f, 7.0f, 9.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 9.0f, 7.0f, 21.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-21.0f, 7.0f, -9.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( -9.0f, 7.0f, -21.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 21.0f, 7.0f, -9.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 9.0f, 7.0f, -21.0f), 8.0f, SOUND_BOUMm, 0.45f);
+ SetGlobalSphere(D3DVECTOR(0.0f, 0.0f, 0.0f), 35.0f);
+
+ CreateShadowCircle(30.0f, 1.0f);
+ }
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ SetFloorHeight(0.0f);
+ CreateOtherObject(type);
+
+ if ( type != OBJECT_RUINfactory &&
+ type != OBJECT_RUINconvert &&
+ type != OBJECT_RUINbase )
+ {
+ FloorAdjust();
+ }
+
+ pos = RetPosition(0);
+ pos.y += height;
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ if ( type == OBJECT_RUINmobilew1 )
+ {
+ pos = RetPosition(0);
+ pos.y -= 0.5f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)-0.1f;
+ SetAngleX(0, angle);
+ }
+
+ if ( type == OBJECT_RUINmobilew2 )
+ {
+ pos = RetPosition(0);
+ pos.y -= 1.5f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)-0.9f;
+ SetAngleX(0, angle);
+
+ angle = RetAngleZ(0)-0.1f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINmobilet1 )
+ {
+ pos = RetPosition(0);
+ pos.y -= 0.9f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)-0.3f;
+ SetAngleX(0, angle);
+ }
+
+ if ( type == OBJECT_RUINmobilet2 )
+ {
+ pos = RetPosition(0);
+ pos.y -= 1.5f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)-0.3f;
+ SetAngleX(0, angle);
+
+ angle = RetAngleZ(0)+0.8f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINmobiler1 )
+ {
+ pos = RetPosition(0);
+ pos.y += 4.0f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)-PI*0.6f;
+ SetAngleX(0, angle);
+
+ angle = RetAngleZ(0)-0.2f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINmobiler2 )
+ {
+ pos = RetPosition(0);
+ pos.y += 2.0f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)-0.1f;
+ SetAngleX(0, angle);
+
+ angle = RetAngleZ(0)-0.3f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINdoor )
+ {
+ pos = RetPosition(0);
+ pos.y -= 0.5f;
+ SetPosition(0, pos);
+
+ angle = RetAngleZ(0)-0.1f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINsupport )
+ {
+ pos = RetPosition(0);
+ pos.y += 0.5f;
+ SetPosition(0, pos);
+
+//? angle = RetAngleY(0)+0.1f;
+//? SetAngleY(0, angle);
+
+ angle = RetAngleX(0)+0.1f;
+ SetAngleX(0, angle);
+
+ angle = RetAngleZ(0)+0.1f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINradar )
+ {
+ pos = RetPosition(0);
+ pos.y -= 0.5f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)+0.15f;
+ SetAngleX(0, angle);
+
+ angle = RetAngleZ(0)+0.1f;
+ SetAngleZ(0, angle);
+ }
+
+ if ( type == OBJECT_RUINconvert )
+ {
+ pos = RetPosition(0);
+ pos.y -= 1.0f;
+ SetPosition(0, pos);
+ }
+
+ if ( type == OBJECT_RUINbase )
+ {
+ pos = RetPosition(0);
+ pos.y -= 1.0f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)+0.15f;
+ SetAngleX(0, angle);
+ }
+
+ if ( type == OBJECT_RUINhead )
+ {
+ pos = RetPosition(0);
+ pos.y += 8.0f;
+ SetPosition(0, pos);
+
+ angle = RetAngleX(0)+PI*0.4f;
+ SetAngleX(0, angle);
+ }
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée un gadget apollo.
+
+BOOL CObject::CreateApollo(D3DVECTOR pos, float angle, ObjectType type)
+{
+ CModFile* pModFile;
+ int rank, i;
+
+ if ( m_engine->RetRestCreate() < 6 ) return FALSE;
+
+ pModFile = new CModFile(m_iMan);
+
+ SetType(type);
+
+ if ( type == OBJECT_APOLLO1 ) // LEM ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\apollol1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetZoom(0, 1.2f);
+ SetFloorHeight(0.0f);
+
+ for ( i=0 ; i<4 ; i++ ) // crée les pieds
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(i+1, rank);
+ SetObjectParent(i+1, 0);
+ pModFile->ReadModel("objects\\apollol2.mod");
+ pModFile->CreateEngineObject(rank);
+ SetAngleY(i+1, PI/2.0f*i);
+ }
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(5, rank);
+ SetObjectParent(5, 0);
+ pModFile->ReadModel("objects\\apollol3.mod"); // échelle
+ pModFile->CreateEngineObject(rank);
+
+//? m_terrain->AddBuildingLevel(pos, 10.0f, 13.0f, 12.0f, 0.0f);
+
+ CreateCrashSphere(D3DVECTOR( 0.0f, 4.0f, 0.0f), 9.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 11.0f, 5.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-11.0f, 5.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 5.0f, -11.0f), 3.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 0.0f, 5.0f, 11.0f), 3.0f, SOUND_BOUMm, 0.45f);
+
+ SetGlobalSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 9.0f);
+
+ CreateShadowCircle(16.0f, 0.5f);
+ }
+
+ if ( type == OBJECT_APOLLO2 ) // jeep ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\apolloj1.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ // Roues.
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(-5.75f, 1.65f, -5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(2, rank);
+ SetObjectParent(2, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ SetPosition(2, D3DVECTOR(-5.75f, 1.65f, 5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(3, rank);
+ SetObjectParent(3, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ SetPosition(3, D3DVECTOR(5.75f, 1.65f, -5.0f));
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(4, rank);
+ SetObjectParent(4, 0);
+ pModFile->ReadModel("objects\\apolloj4.mod"); // roue
+ pModFile->CreateEngineObject(rank);
+ SetPosition(4, D3DVECTOR(5.75f, 1.65f, 5.0f));
+
+ // Accessoirs :
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(5, rank);
+ SetObjectParent(5, 0);
+ pModFile->ReadModel("objects\\apolloj2.mod"); // antenne
+ pModFile->CreateEngineObject(rank);
+ SetPosition(5, D3DVECTOR(5.5f, 8.8f, 2.0f));
+ SetAngleY(5, -120.0f*PI/180.0f);
+ SetAngleZ(5, 45.0f*PI/180.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(6, rank);
+ SetObjectParent(6, 0);
+ pModFile->ReadModel("objects\\apolloj3.mod"); // caméra
+ pModFile->CreateEngineObject(rank);
+ SetPosition(6, D3DVECTOR(5.5f, 2.8f, -2.0f));
+ SetAngleY(6, 30.0f*PI/180.0f);
+
+ CreateCrashSphere(D3DVECTOR( 3.0f, 2.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR(-3.0f, 2.0f, 0.0f), 5.0f, SOUND_BOUMm, 0.45f);
+ CreateCrashSphere(D3DVECTOR( 7.0f, 9.0f, 2.0f), 2.0f, SOUND_BOUMm, 0.20f);
+
+ CreateShadowCircle(7.0f, 0.8f);
+
+ FloorAdjust();
+ }
+
+ if ( type == OBJECT_APOLLO3 ) // flag ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\apollof.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ SetJotlerSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 1.0f);
+ CreateShadowCircle(2.0f, 0.3f);
+ }
+
+ if ( type == OBJECT_APOLLO4 ) // module ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\apollom.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 2.0f, 0.0f), 2.0f, SOUND_BOUMm, 0.45f);
+ CreateShadowCircle(5.0f, 0.8f);
+
+ FloorAdjust();
+ }
+
+ if ( type == OBJECT_APOLLO5 ) // antenna ?
+ {
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEFIX); // c'est un objet fixe
+ SetObjectRank(0, rank);
+ pModFile->ReadModel("objects\\apolloa.mod");
+ pModFile->CreateEngineObject(rank);
+ SetPosition(0, pos);
+ SetAngleY(0, angle);
+ SetFloorHeight(0.0f);
+
+ rank = m_engine->CreateObject();
+ m_engine->SetObjectType(rank, TYPEDESCENDANT);
+ SetObjectRank(1, rank);
+ SetObjectParent(1, 0);
+ pModFile->ReadModel("objects\\apolloj2.mod"); // antenne
+ pModFile->CreateEngineObject(rank);
+ SetPosition(1, D3DVECTOR(0.0f, 5.0f, 0.0f));
+ SetAngleY(1, -120.0f*PI/180.0f);
+ SetAngleZ(1, 45.0f*PI/180.0f);
+
+ CreateCrashSphere(D3DVECTOR(0.0f, 4.0f, 0.0f), 3.0f, SOUND_BOUMm, 0.35f);
+ CreateShadowCircle(3.0f, 0.7f);
+ }
+
+ CreateOtherObject(type);
+
+ pos = RetPosition(0);
+ SetPosition(0, pos); // pour afficher les ombres tout de suite
+
+ delete pModFile;
+ return TRUE;
+}
+
+// Crée tous les sous-objets permettant de gérer cet objet.
+
+void CObject::CreateOtherObject(ObjectType type)
+{
+ if ( type == OBJECT_BASE )
+ {
+ m_auto = new CAutoBase(m_iMan, this);
+ }
+ if ( type == OBJECT_PORTICO )
+ {
+ m_auto = new CAutoPortico(m_iMan, this);
+ }
+ if ( type == OBJECT_DERRICK )
+ {
+ m_auto = new CAutoDerrick(m_iMan, this);
+ }
+ if ( type == OBJECT_FACTORY )
+ {
+ m_auto = new CAutoFactory(m_iMan, this);
+ }
+ if ( type == OBJECT_REPAIR )
+ {
+ m_auto = new CAutoRepair(m_iMan, this);
+ }
+ if ( type == OBJECT_DESTROYER )
+ {
+ m_auto = new CAutoDestroyer(m_iMan, this);
+ }
+ if ( type == OBJECT_STATION )
+ {
+ m_auto = new CAutoStation(m_iMan, this);
+ }
+ if ( type == OBJECT_CONVERT )
+ {
+ m_auto = new CAutoConvert(m_iMan, this);
+ }
+ if ( type == OBJECT_TOWER )
+ {
+ m_auto = new CAutoTower(m_iMan, this);
+ }
+ if ( type == OBJECT_RESEARCH )
+ {
+ m_auto = new CAutoResearch(m_iMan, this);
+ }
+ if ( type == OBJECT_RADAR )
+ {
+ m_auto = new CAutoRadar(m_iMan, this);
+ }
+ if ( type == OBJECT_INFO )
+ {
+ m_auto = new CAutoInfo(m_iMan, this);
+ }
+ if ( type == OBJECT_ENERGY )
+ {
+ m_auto = new CAutoEnergy(m_iMan, this);
+ }
+ if ( type == OBJECT_LABO )
+ {
+ m_auto = new CAutoLabo(m_iMan, this);
+ }
+ if ( type == OBJECT_NUCLEAR )
+ {
+ m_auto = new CAutoNuclear(m_iMan, this);
+ }
+ if ( type == OBJECT_PARA )
+ {
+ m_auto = new CAutoPara(m_iMan, this);
+ }
+ if ( type == OBJECT_SAFE )
+ {
+ m_auto = new CAutoSafe(m_iMan, this);
+ }
+ if ( type == OBJECT_HUSTON )
+ {
+ m_auto = new CAutoHuston(m_iMan, this);
+ }
+ if ( type == OBJECT_EGG )
+ {
+ m_auto = new CAutoEgg(m_iMan, this);
+ }
+ if ( type == OBJECT_NEST )
+ {
+ m_auto = new CAutoNest(m_iMan, this);
+ }
+ if ( type == OBJECT_ROOT5 )
+ {
+ m_auto = new CAutoRoot(m_iMan, this);
+ }
+ if ( type == OBJECT_MUSHROOM2 )
+ {
+ m_auto = new CAutoMush(m_iMan, this);
+ }
+ if ( type == OBJECT_FLAGb ||
+ type == OBJECT_FLAGr ||
+ type == OBJECT_FLAGg ||
+ type == OBJECT_FLAGy ||
+ type == OBJECT_FLAGv )
+ {
+ m_auto = new CAutoFlag(m_iMan, this);
+ }
+ if ( type == OBJECT_TEEN36 || // tronc ?
+ type == OBJECT_TEEN37 || // bateau ?
+ type == OBJECT_TEEN38 ) // ventillateur ?
+ {
+ m_auto = new CAutoKid(m_iMan, this);
+ }
+}
+
+
+// Lit un programme.
+
+BOOL CObject::ReadProgram(int rank, char* filename)
+{
+ if ( m_brain != 0 )
+ {
+ return m_brain->ReadProgram(rank, filename);
+ }
+ return FALSE;
+}
+
+// Ecrit un programme.
+
+BOOL CObject::WriteProgram(int rank, char* filename)
+{
+ if ( m_brain != 0 )
+ {
+ return m_brain->WriteProgram(rank, filename);
+ }
+ return FALSE;
+}
+
+// Démarre un programme.
+
+BOOL CObject::RunProgram(int rank)
+{
+ if ( m_brain != 0 )
+ {
+ m_brain->RunProgram(rank);
+ return TRUE;
+ }
+ if ( m_auto != 0 )
+ {
+ m_auto->Start(rank);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+
+// Calcule la matrice permettant de transformer l'objet.
+// Retourne TRUE si la matrice a changé.
+// Les rotations ont lieu dans l'ordre Y, Z et X.
+
+BOOL CObject::UpdateTransformObject(int part, BOOL bForceUpdate)
+{
+ D3DVECTOR position, angle, eye;
+ BOOL bModif = FALSE;
+ int parent;
+
+ if ( m_truck != 0 ) // transporté par camion ?
+ {
+ m_objectPart[part].bTranslate = TRUE;
+ m_objectPart[part].bRotate = TRUE;
+ }
+
+ if ( !bForceUpdate &&
+ !m_objectPart[part].bTranslate &&
+ !m_objectPart[part].bRotate ) return FALSE;
+
+ position = m_objectPart[part].position;
+ angle = m_objectPart[part].angle;
+
+ if ( part == 0 ) // partie principale ?
+ {
+ position += m_linVibration;
+ angle += m_cirVibration+m_inclinaison;
+ }
+
+ if ( m_objectPart[part].bTranslate ||
+ m_objectPart[part].bRotate )
+ {
+ if ( m_objectPart[part].bTranslate )
+ {
+ D3DUtil_SetIdentityMatrix(m_objectPart[part].matTranslate);
+ m_objectPart[part].matTranslate._41 = position.x;
+ m_objectPart[part].matTranslate._42 = position.y;
+ m_objectPart[part].matTranslate._43 = position.z;
+ }
+
+ if ( m_objectPart[part].bRotate )
+ {
+ MatRotateZXY(m_objectPart[part].matRotate, angle);
+ }
+
+ if ( m_objectPart[part].bZoom )
+ {
+ D3DMATRIX mz;
+ D3DUtil_SetIdentityMatrix(mz);
+ mz._11 = m_objectPart[part].zoom.x;
+ mz._22 = m_objectPart[part].zoom.y;
+ mz._33 = m_objectPart[part].zoom.z;
+ m_objectPart[part].matTransform = mz *
+ m_objectPart[part].matRotate *
+ m_objectPart[part].matTranslate;
+ }
+ else
+ {
+ m_objectPart[part].matTransform = m_objectPart[part].matRotate *
+ m_objectPart[part].matTranslate;
+ }
+ bModif = TRUE;
+ }
+
+ if ( bForceUpdate ||
+ m_objectPart[part].bTranslate ||
+ m_objectPart[part].bRotate )
+ {
+ parent = m_objectPart[part].parentPart;
+
+ if ( part == 0 && m_truck != 0 ) // transporté par un camion ?
+ {
+ D3DMATRIX* matWorldTruck;
+ matWorldTruck = m_truck->RetWorldMatrix(m_truckLink);
+ m_objectPart[part].matWorld = m_objectPart[part].matTransform *
+ *matWorldTruck;
+ }
+ else
+ {
+ if ( parent == -1 ) // pas de parent ?
+ {
+ m_objectPart[part].matWorld = m_objectPart[part].matTransform;
+ }
+ else
+ {
+ m_objectPart[part].matWorld = m_objectPart[part].matTransform *
+ m_objectPart[parent].matWorld;
+ }
+ }
+ bModif = TRUE;
+ }
+
+ if ( bModif )
+ {
+ m_engine->SetObjectTransform(m_objectPart[part].object,
+ m_objectPart[part].matWorld);
+ }
+
+ m_objectPart[part].bTranslate = FALSE;
+ m_objectPart[part].bRotate = FALSE;
+
+ return bModif;
+}
+
+// Met à jour toutes les matrices pour transformer l'objet père
+// et tous ses fils.
+// On suppose un maximum de 4 degrés de liberté. Cela convient,
+// par exemple, pour un corps, un bras, un avant-bras, une main
+// et des doigts.
+
+BOOL CObject::UpdateTransformObject()
+{
+ BOOL bUpdate1, bUpdate2, bUpdate3, bUpdate4;
+ int level1, level2, level3, level4, rank;
+ int parent1, parent2, parent3, parent4;
+
+ if ( m_bFlat )
+ {
+ for ( level1=0 ; level1<m_totalPart ; level1++ )
+ {
+ if ( !m_objectPart[level1].bUsed ) continue;
+ UpdateTransformObject(level1, FALSE);
+ }
+ }
+ else
+ {
+ parent1 = 0;
+ bUpdate1 = UpdateTransformObject(parent1, FALSE);
+
+ for ( level1=0 ; level1<m_totalPart ; level1++ )
+ {
+ rank = SearchDescendant(parent1, level1);
+ if ( rank == -1 ) break;
+
+ parent2 = rank;
+ bUpdate2 = UpdateTransformObject(rank, bUpdate1);
+
+ for ( level2=0 ; level2<m_totalPart ; level2++ )
+ {
+ rank = SearchDescendant(parent2, level2);
+ if ( rank == -1 ) break;
+
+ parent3 = rank;
+ bUpdate3 = UpdateTransformObject(rank, bUpdate2);
+
+ for ( level3=0 ; level3<m_totalPart ; level3++ )
+ {
+ rank = SearchDescendant(parent3, level3);
+ if ( rank == -1 ) break;
+
+ parent4 = rank;
+ bUpdate4 = UpdateTransformObject(rank, bUpdate3);
+
+ for ( level4=0 ; level4<m_totalPart ; level4++ )
+ {
+ rank = SearchDescendant(parent4, level4);
+ if ( rank == -1 ) break;
+
+ UpdateTransformObject(rank, bUpdate4);
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Met toute la descendance à plat (il n'y a plus que des pères).
+// Ceci permet de faire partir les débris indépendamment les uns
+// des autres dans tous les sens.
+
+void CObject::FlatParent()
+{
+ int i;
+
+ for ( i=0 ; i<m_totalPart ; i++ )
+ {
+ m_objectPart[i].position.x = m_objectPart[i].matWorld._41;
+ m_objectPart[i].position.y = m_objectPart[i].matWorld._42;
+ m_objectPart[i].position.z = m_objectPart[i].matWorld._43;
+
+ m_objectPart[i].matWorld._41 = 0.0f;
+ m_objectPart[i].matWorld._42 = 0.0f;
+ m_objectPart[i].matWorld._43 = 0.0f;
+
+ m_objectPart[i].matTranslate._41 = 0.0f;
+ m_objectPart[i].matTranslate._42 = 0.0f;
+ m_objectPart[i].matTranslate._43 = 0.0f;
+
+ m_objectPart[i].parentPart = -1; // plus de parent
+ }
+
+ m_bFlat = TRUE;
+}
+
+
+
+// Met à jour la mapping de la texture de la pile.
+
+void CObject::UpdateEnergyMapping()
+{
+ D3DMATERIAL7 mat;
+ float a, b, i, s, au, bu;
+ float limit[6];
+ int j;
+
+ if ( Abs(m_energy-m_lastEnergy) < 0.01f ) return;
+ m_lastEnergy = m_energy;
+
+ ZeroMemory( &mat, sizeof(D3DMATERIAL7) );
+ mat.diffuse.r = 1.0f;
+ mat.diffuse.g = 1.0f;
+ mat.diffuse.b = 1.0f; // blanc
+ mat.ambient.r = 0.5f;
+ mat.ambient.g = 0.5f;
+ mat.ambient.b = 0.5f;
+
+ if ( m_type == OBJECT_POWER ||
+ m_type == OBJECT_ATOMIC )
+ {
+ a = 2.0f;
+ b = 0.0f; // dimensions de la pile (selon y)
+ }
+ if ( m_type == OBJECT_STATION )
+ {
+ a = 10.0f;
+ b = 4.0f; // dimensions de la pile (selon y)
+ }
+ if ( m_type == OBJECT_ENERGY )
+ {
+ a = 9.0f;
+ b = 3.0f; // dimensions de la pile (selon y)
+ }
+
+ i = 0.50f+0.25f*m_energy; // origine
+ s = i+0.25f; // largeur
+
+ au = (s-i)/(b-a);
+ bu = s-b*(s-i)/(b-a);
+
+ limit[0] = 0.0f;
+ limit[1] = m_engine->RetLimitLOD(0);
+ limit[2] = limit[1];
+ limit[3] = m_engine->RetLimitLOD(1);
+ limit[4] = limit[3];
+ limit[5] = 1000000.0f;
+
+ for ( j=0 ; j<3 ; j++ )
+ {
+ m_engine->ChangeTextureMapping(m_objectPart[0].object,
+ mat, D3DSTATEPART3, "lemt.tga", "",
+ limit[j*2+0], limit[j*2+1], D3DMAPPING1Y,
+ au, bu, 1.0f, 0.0f);
+ }
+}
+
+
+// Action manuelle.
+
+BOOL CObject::EventProcess(const Event &event)
+{
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if ADJUST_ONBOARD
+ if ( m_bSelect )
+ {
+ if ( event.param == 'E' ) debug_x += 0.1f;
+ if ( event.param == 'D' ) debug_x -= 0.1f;
+ if ( event.param == 'R' ) debug_y += 0.1f;
+ if ( event.param == 'F' ) debug_y -= 0.1f;
+ if ( event.param == 'T' ) debug_z += 0.1f;
+ if ( event.param == 'G' ) debug_z -= 0.1f;
+ }
+#endif
+#if ADJUST_ARM
+ if ( m_bSelect )
+ {
+ if ( event.param == 'X' ) debug_arm1 += 5.0f*PI/180.0f;
+ if ( event.param == 'C' ) debug_arm1 -= 5.0f*PI/180.0f;
+ if ( event.param == 'V' ) debug_arm2 += 5.0f*PI/180.0f;
+ if ( event.param == 'B' ) debug_arm2 -= 5.0f*PI/180.0f;
+ if ( event.param == 'N' ) debug_arm3 += 5.0f*PI/180.0f;
+ if ( event.param == 'M' ) debug_arm3 -= 5.0f*PI/180.0f;
+ if ( event.param == 'X' ||
+ event.param == 'C' ||
+ event.param == 'V' ||
+ event.param == 'B' ||
+ event.param == 'N' ||
+ event.param == 'M' )
+ {
+ SetAngleZ(1, debug_arm1);
+ SetAngleZ(2, debug_arm2);
+ SetAngleZ(3, debug_arm3);
+ char s[100];
+ sprintf(s, "a=%.2f b=%.2f c=%.2f", debug_arm1*180.0f/PI, debug_arm2*180.0f/PI, debug_arm3*180.0f/PI);
+ m_engine->SetInfoText(5, s);
+ }
+ }
+#endif
+ }
+
+ if ( m_physics != 0 )
+ {
+ if ( !m_physics->EventProcess(event) ) // objet détruit ?
+ {
+ if ( RetSelect() &&
+ m_type != OBJECT_ANT &&
+ m_type != OBJECT_SPIDER &&
+ m_type != OBJECT_BEE )
+ {
+ if ( !m_bDead ) m_camera->SetType(CAMERA_EXPLO);
+ m_main->DeselectAll();
+ }
+ return FALSE;
+ }
+ }
+
+ if ( m_auto != 0 )
+ {
+ m_auto->EventProcess(event);
+
+ if ( event.event == EVENT_FRAME &&
+ m_auto->IsEnded() != ERR_CONTINUE )
+ {
+ m_auto->DeleteObject();
+ delete m_auto;
+ m_auto = 0;
+ }
+ }
+
+ if ( m_motion != 0 )
+ {
+ m_motion->EventProcess(event);
+ }
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ return TRUE;
+}
+
+
+// Anime l'objet.
+
+BOOL CObject::EventFrame(const Event &event)
+{
+ if ( m_type == OBJECT_HUMAN && m_main->RetMainMovie() == MM_SATCOMopen )
+ {
+ UpdateTransformObject();
+ return TRUE;
+ }
+
+ if ( m_type != OBJECT_SHOW && m_engine->RetPause() ) return TRUE;
+
+ m_aTime += event.rTime;
+ m_shotTime += event.rTime;
+
+ VirusFrame(event.rTime);
+ PartiFrame(event.rTime);
+
+ UpdateMapping();
+ UpdateTransformObject();
+ UpdateSelectParticule();
+
+ if ( m_bProxyActivate ) // active si on est proche ?
+ {
+ CPyro* pyro;
+ D3DVECTOR eye;
+ float dist;
+
+ eye = m_engine->RetLookatPt();
+ dist = Length(eye, RetPosition(0));
+ if ( dist < m_proxyDistance )
+ {
+ m_bProxyActivate = FALSE;
+ m_main->CreateShortcuts();
+ m_sound->Play(SOUND_FINDING);
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FINDING, this, 0.0f);
+ m_displayText->DisplayError(INFO_FINDING, this);
+ }
+ }
+
+ return TRUE;
+}
+
+// Met à jour le mapping de l'objet.
+
+void CObject::UpdateMapping()
+{
+ if ( m_type == OBJECT_POWER ||
+ m_type == OBJECT_ATOMIC ||
+ m_type == OBJECT_STATION ||
+ m_type == OBJECT_ENERGY )
+ {
+ UpdateEnergyMapping();
+ }
+}
+
+
+// Gestion d'un virus.
+
+void CObject::VirusFrame(float rTime)
+{
+ ParticuleType type;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int r;
+
+ if ( !m_bVirusMode ) return; // object sain ?
+
+ m_virusTime += rTime;
+ if ( m_virusTime >= VIRUS_DELAY )
+ {
+ m_bVirusMode = FALSE; // le virus n'est plus actif
+ }
+
+ if ( m_lastVirusParticule+m_engine->ParticuleAdapt(0.2f) <= m_aTime )
+ {
+ m_lastVirusParticule = m_aTime;
+
+ r = rand()%10;
+ if ( r == 0 ) type = PARTIVIRUS1;
+ if ( r == 1 ) type = PARTIVIRUS2;
+ if ( r == 2 ) type = PARTIVIRUS3;
+ if ( r == 3 ) type = PARTIVIRUS4;
+ if ( r == 4 ) type = PARTIVIRUS5;
+ if ( r == 5 ) type = PARTIVIRUS6;
+ if ( r == 6 ) type = PARTIVIRUS7;
+ if ( r == 7 ) type = PARTIVIRUS8;
+ if ( r == 8 ) type = PARTIVIRUS9;
+ if ( r == 9 ) type = PARTIVIRUS10;
+
+ pos = RetPosition(0);
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = Rand()*4.0f+4.0f;
+ dim.x = Rand()*0.3f+0.3f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, type, 3.0f);
+ }
+}
+
+// Gestion des particules maîtresses.
+
+void CObject::PartiFrame(float rTime)
+{
+ D3DVECTOR pos, angle, factor;
+ int i, channel;
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( !m_objectPart[i].bUsed ) continue;
+
+ channel = m_objectPart[i].masterParti;
+ if ( channel == -1 ) continue;
+
+ if ( !m_particule->GetPosition(channel, pos) )
+ {
+ m_objectPart[i].masterParti = -1; // particule n'existe plus !
+ continue;
+ }
+
+ SetPosition(i, pos);
+
+ // Chaque morceau tournoie différemment.
+ switch( i%5 )
+ {
+ case 0: factor = D3DVECTOR( 0.5f, 0.3f, 0.6f); break;
+ case 1: factor = D3DVECTOR(-0.3f, 0.4f,-0.2f); break;
+ case 2: factor = D3DVECTOR( 0.4f,-0.6f,-0.3f); break;
+ case 3: factor = D3DVECTOR(-0.6f,-0.2f, 0.0f); break;
+ case 4: factor = D3DVECTOR( 0.4f, 0.1f,-0.7f); break;
+ }
+
+ angle = RetAngle(i);
+ angle += rTime*PI*factor;
+ SetAngle(i, angle);
+ }
+}
+
+
+// Modifie le point de vue pour voir comme si on était
+// dans le véhicule, ou derrière le véhicule.
+
+void CObject::SetViewFromHere(D3DVECTOR &eye, float &dirH, float &dirV,
+ D3DVECTOR &lookat, D3DVECTOR &upVec,
+ CameraType type)
+{
+ float speed;
+ int part;
+
+ UpdateTransformObject();
+
+ part = 0;
+ if ( m_type == OBJECT_HUMAN ||
+ m_type == OBJECT_TECH )
+ {
+ eye.x = -0.2f;
+ eye.y = 3.3f;
+ eye.z = 0.0f;
+//? eye.x = 1.0f;
+//? eye.y = 3.3f;
+//? eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs )
+ {
+ eye.x = -1.1f; // sur le capot
+ eye.y = 7.9f;
+ eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEic ) // fireball ?
+ {
+//? eye.x = -0.9f; // sur le canon
+//? eye.y = 3.0f;
+//? eye.z = 0.0f;
+//? part = 1;
+ eye.x = -0.9f; // sur le canon
+ eye.y = 8.3f;
+ eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEii ) // orgaball ?
+ {
+//? eye.x = -3.5f; // sur le canon
+//? eye.y = 5.1f;
+//? eye.z = 0.0f;
+//? part = 1;
+ eye.x = -2.5f; // sur le canon
+ eye.y = 10.4f;
+ eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_MOBILErc )
+ {
+//? eye.x = 2.0f; // dans le canon
+//? eye.y = 0.0f;
+//? eye.z = 0.0f;
+//? part = 2;
+ eye.x = 4.0f; // sur le canon
+ eye.y = 11.0f;
+ eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_MOBILEsa )
+ {
+ eye.x = 3.0f;
+ eye.y = 4.5f;
+ eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_MOBILEdr )
+ {
+ eye.x = 1.0f;
+ eye.y = 6.5f;
+ eye.z = 0.0f;
+ }
+ else if ( m_type == OBJECT_APOLLO2 )
+ {
+ eye.x = -3.0f;
+ eye.y = 6.0f;
+ eye.z = -2.0f;
+ }
+ else
+ {
+ eye.x = 0.7f; // entre les supports
+ eye.y = 4.8f;
+ eye.z = 0.0f;
+ }
+#if ADJUST_ONBOARD
+ eye.x += debug_x;
+ eye.y += debug_y;
+ eye.z += debug_z;
+ char s[100];
+ sprintf(s, "x=%.2f y=%.2f z=%.2f", eye.x, eye.y, eye.z);
+ m_engine->SetInfoText(4, s);
+#endif
+
+ if ( type == CAMERA_BACK )
+ {
+ eye.x -= 20.0f;
+ eye.y += 1.0f;
+ }
+
+ lookat.x = eye.x+1.0f;
+ lookat.y = eye.y+0.0f;
+ lookat.z = eye.z+0.0f;
+
+ eye = Transform(m_objectPart[part].matWorld, eye);
+ lookat = Transform(m_objectPart[part].matWorld, lookat);
+
+ // Penche la caméra dans les virages.
+ upVec = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ if ( m_physics != 0 )
+ {
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ speed = m_physics->RetLinMotionX(MO_REASPEED);
+ lookat.y -= speed*0.002f;
+
+ speed = m_physics->RetCirMotionY(MO_REASPEED);
+ upVec.z -= speed*0.04f;
+ }
+ else // en vol ?
+ {
+ speed = m_physics->RetLinMotionX(MO_REASPEED);
+ lookat.y += speed*0.002f;
+
+ speed = m_physics->RetCirMotionY(MO_REASPEED);
+ upVec.z += speed*0.08f;
+ }
+ }
+ upVec = Transform(m_objectPart[0].matRotate, upVec);
+
+ dirH = -(m_objectPart[part].angle.y+PI/2.0f);
+ dirV = 0.0f;
+
+}
+
+
+// Gestion des caractéristiques.
+
+void CObject::SetCharacter(Character* character)
+{
+ CopyMemory(&m_character, character, sizeof(Character));
+}
+
+void CObject::GetCharacter(Character* character)
+{
+ CopyMemory(character, &m_character, sizeof(Character));
+}
+
+Character* CObject::RetCharacter()
+{
+ return &m_character;
+}
+
+
+// Retourne le temps absolu.
+
+float CObject::RetAbsTime()
+{
+ return m_aTime;
+}
+
+
+// Gestion de l'énergie contenue dans une pile.
+// Seul l'objet pile possède de l'énergie, mais pas le véhicule
+// qui transporte la pile !
+
+void CObject::SetEnergy(float level)
+{
+ if ( level < 0.0f ) level = 0.0f;
+ if ( level > 1.0f ) level = 1.0f;
+ m_energy = level;
+}
+
+float CObject::RetEnergy()
+{
+ if ( m_type != OBJECT_POWER &&
+ m_type != OBJECT_ATOMIC &&
+ m_type != OBJECT_STATION &&
+ m_type != OBJECT_ENERGY ) return 0.0f;
+ return m_energy;
+}
+
+
+// Gestion de la capacité d'une pile.
+// Seul l'objet pile possède une capacité, mais pas le véhicule
+// qui transporte la pile !
+
+void CObject::SetCapacity(float capacity)
+{
+ m_capacity = capacity;
+}
+
+float CObject::RetCapacity()
+{
+ return m_capacity;
+}
+
+
+// Gestion du bouclier.
+
+void CObject::SetShield(float level)
+{
+ m_shield = level;
+}
+
+float CObject::RetShield()
+{
+ if ( m_type == OBJECT_FRET ||
+ m_type == OBJECT_STONE ||
+ m_type == OBJECT_URANIUM ||
+ m_type == OBJECT_BULLET ||
+ m_type == OBJECT_METAL ||
+ m_type == OBJECT_BBOX ||
+ m_type == OBJECT_KEYa ||
+ m_type == OBJECT_KEYb ||
+ m_type == OBJECT_KEYc ||
+ m_type == OBJECT_KEYd ||
+ m_type == OBJECT_TNT ||
+ m_type == OBJECT_TEEN31 || // basket ?
+ m_type == OBJECT_SCRAP1 ||
+ m_type == OBJECT_SCRAP2 ||
+ m_type == OBJECT_SCRAP3 ||
+ m_type == OBJECT_SCRAP4 ||
+ m_type == OBJECT_SCRAP5 ||
+ m_type == OBJECT_BOMB ||
+ m_type == OBJECT_WAYPOINT ||
+ m_type == OBJECT_FLAGb ||
+ m_type == OBJECT_FLAGr ||
+ m_type == OBJECT_FLAGg ||
+ m_type == OBJECT_FLAGy ||
+ m_type == OBJECT_FLAGv ||
+ m_type == OBJECT_POWER ||
+ m_type == OBJECT_ATOMIC ||
+ m_type == OBJECT_ANT ||
+ m_type == OBJECT_SPIDER ||
+ m_type == OBJECT_BEE ||
+ m_type == OBJECT_WORM ) return 0.0f;
+ return m_shield;
+}
+
+
+// Gestion de l'autonomie de vol (zéro = infini).
+
+void CObject::SetRange(float delay)
+{
+ m_range = delay;
+}
+
+float CObject::RetRange()
+{
+ return m_range;
+}
+
+
+// Gestion du facteur de transparence de l'objet.
+
+void CObject::SetTransparency(float value)
+{
+ int i;
+
+ m_transparency = value;
+
+ for ( i=0 ; i<m_totalPart ; i++ )
+ {
+ if ( m_objectPart[i].bUsed )
+ {
+ if ( m_type == OBJECT_BASE )
+ {
+ if ( i != 9 ) continue; // pas pilier central ?
+ }
+
+ m_engine->SetObjectTransparency(m_objectPart[i].object, value);
+ }
+ }
+}
+
+float CObject::RetTransparency()
+{
+ return m_transparency;
+}
+
+
+// Gestion de la matière de l'objet.
+
+ObjectMaterial CObject::RetMaterial()
+{
+ if ( m_type == OBJECT_HUMAN )
+ {
+ return OM_HUMAN;
+ }
+
+ if ( m_type == OBJECT_SCRAP4 ||
+ m_type == OBJECT_SCRAP5 )
+ {
+ return OM_HUMAN;
+ }
+
+ return OM_METAL;
+}
+
+
+// Indique si l'objet est un gadget non indispensable.
+
+void CObject::SetGadget(BOOL bMode)
+{
+ m_bGadget = bMode;
+}
+
+BOOL CObject::RetGadget()
+{
+ return m_bGadget;
+}
+
+
+// Indique si un objet est immobile (fourmi sur le dos).
+
+void CObject::SetFixed(BOOL bFixed)
+{
+ m_bFixed = bFixed;
+}
+
+BOOL CObject::RetFixed()
+{
+ return m_bFixed;
+}
+
+
+// Indique si un objet est soumis au clipping (obstacles).
+
+void CObject::SetClip(BOOL bClip)
+{
+ m_bClip = bClip;
+}
+
+BOOL CObject::RetClip()
+{
+ return m_bClip;
+}
+
+
+
+// Bouscule un objet.
+
+BOOL CObject::JostleObject(float force)
+{
+ CAutoJostle* pa;
+
+ if ( m_type == OBJECT_FLAGb ||
+ m_type == OBJECT_FLAGr ||
+ m_type == OBJECT_FLAGg ||
+ m_type == OBJECT_FLAGy ||
+ m_type == OBJECT_FLAGv ) // drapeau ?
+ {
+ if ( m_auto == 0 ) return FALSE;
+
+ m_auto->Start(1);
+ }
+ else
+ {
+ if ( m_auto != 0 ) return FALSE;
+
+ m_auto = new CAutoJostle(m_iMan, this);
+ pa = (CAutoJostle*)m_auto;
+ pa->Start(0, force);
+ }
+
+ return TRUE;
+}
+
+
+// Début de l'effet lorsque l'instruction "detect" est utilisée.
+
+void CObject::StartDetectEffect(CObject *target, BOOL bFound)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, goal;
+ FPOINT dim;
+
+ mat = RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(2.0f, 3.0f, 0.0f));
+
+ if ( target == 0 )
+ {
+ goal = Transform(*mat, D3DVECTOR(50.0f, 3.0f, 0.0f));
+ }
+ else
+ {
+ goal = target->RetPosition(0);
+ goal.y += 3.0f;
+ goal = SegmentDist(pos, goal, Length(pos, goal)-3.0f);
+ }
+
+ dim.x = 3.0f;
+ dim.y = dim.x;
+ m_particule->CreateRay(pos, goal, PARTIRAY2, dim, 0.2f);
+
+ if ( target != 0 )
+ {
+ goal = target->RetPosition(0);
+ goal.y += 3.0f;
+ goal = SegmentDist(pos, goal, Length(pos, goal)-1.0f);
+ dim.x = 6.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(goal, D3DVECTOR(0.0f, 0.0f, 0.0f), dim,
+ bFound?PARTIGLINT:PARTIGLINTr, 0.5f);
+ }
+
+ m_sound->Play(bFound?SOUND_BUILD:SOUND_RECOVER);
+}
+
+
+// Gestion du temps depuis lequel un virus est actif.
+
+void CObject::SetVirusMode(BOOL bEnable)
+{
+ m_bVirusMode = bEnable;
+ m_virusTime = 0.0f;
+
+ if ( m_bVirusMode && m_brain != 0 )
+ {
+ if ( !m_brain->IntroduceVirus() ) // essaye de contaminer
+ {
+ m_bVirusMode = FALSE; // pas de programme à contaminer !
+ }
+ }
+}
+
+BOOL CObject::RetVirusMode()
+{
+ return m_bVirusMode;
+}
+
+float CObject::RetVirusTime()
+{
+ return m_virusTime;
+}
+
+
+// Gestion du mode de la caméra.
+
+void CObject::SetCameraType(CameraType type)
+{
+ m_cameraType = type;
+}
+
+CameraType CObject::RetCameraType()
+{
+ return m_cameraType;
+}
+
+void CObject::SetCameraDist(float dist)
+{
+ m_cameraDist = dist;
+}
+
+float CObject::RetCameraDist()
+{
+ return m_cameraDist;
+}
+
+void CObject::SetCameraLock(BOOL bLock)
+{
+ m_bCameraLock = bLock;
+}
+
+BOOL CObject::RetCameraLock()
+{
+ return m_bCameraLock;
+}
+
+
+
+// Gestion de la mise en évidence de l'objet.
+
+void CObject::SetHilite(BOOL bMode)
+{
+ int list[OBJECTMAXPART+1];
+ int i, j;
+
+ m_bHilite = bMode;
+
+ if ( m_bHilite )
+ {
+ j = 0;
+ for ( i=0 ; i<m_totalPart ; i++ )
+ {
+ if ( m_objectPart[i].bUsed )
+ {
+ list[j++] = m_objectPart[i].object;
+ }
+ }
+ list[j] = -1; // terminateur
+
+ m_engine->SetHiliteRank(list); // donne la liste des parties sélectionnées
+ }
+}
+
+BOOL CObject::RetHilite()
+{
+ return m_bHilite;
+}
+
+
+// Indique si l'objet est sélecionné ou non.
+
+void CObject::SetSelect(BOOL bMode, BOOL bDisplayError)
+{
+ Error err;
+
+ m_bSelect = bMode;
+
+ if ( m_physics != 0 )
+ {
+ m_physics->CreateInterface(m_bSelect);
+ }
+
+ if ( m_auto != 0 )
+ {
+ m_auto->CreateInterface(m_bSelect);
+ }
+
+ CreateSelectParticule(); // crée/supprime les particules
+
+ if ( !m_bSelect )
+ {
+ SetGunGoalH(0.0f); // met le canon droit
+ return; // fini si pas sélectionné
+ }
+
+ err = ERR_OK;
+ if ( m_physics != 0 )
+ {
+ err = m_physics->RetError();
+ }
+ if ( m_auto != 0 )
+ {
+ err = m_auto->RetError();
+ }
+ if ( err != ERR_OK && bDisplayError )
+ {
+ m_displayText->DisplayError(err, this);
+ }
+}
+
+// Indique si l'objet est sélectionné ou non.
+
+BOOL CObject::RetSelect(BOOL bReal)
+{
+ if ( !bReal && m_main->RetFixScene() ) return FALSE;
+ return m_bSelect;
+}
+
+
+// Indique si l'objet est sélecionnable ou non.
+
+void CObject::SetSelectable(BOOL bMode)
+{
+ m_bSelectable = bMode;
+}
+
+// Indique si l'objet est sélecionnable ou non.
+
+BOOL CObject::RetSelectable()
+{
+ return m_bSelectable;
+}
+
+
+// Gestion de l'activité d'un objet.
+
+void CObject::SetActivity(BOOL bMode)
+{
+ if ( m_brain != 0 )
+ {
+ m_brain->SetActivity(bMode);
+ }
+}
+
+BOOL CObject::RetActivity()
+{
+ if ( m_brain != 0 )
+ {
+ return m_brain->RetActivity();
+ }
+ return FALSE;
+}
+
+
+// Indique si faut vérifier les tokens de l'objet.
+
+void CObject::SetCheckToken(BOOL bMode)
+{
+ m_bCheckToken = bMode;
+}
+
+// Indique si faut vérifier les tokens de l'objet.
+
+BOOL CObject::RetCheckToken()
+{
+ return m_bCheckToken;
+}
+
+
+// Gestion de la visibilité d'un objet.
+// L'objet n'est pas caché visuellement ni inactif, mais ignoré
+// des détections ! Par exemple: ver sous terre.
+
+void CObject::SetVisible(BOOL bVisible)
+{
+ m_bVisible = bVisible;
+}
+
+BOOL CObject::RetVisible()
+{
+ return m_bVisible;
+}
+
+
+// Gestion du mode de fonctionnement d'un objet. Un objet
+// inactif est identique à un objet détruit, inexistant.
+// Ce mode est utilisé pour les objets "resetables" lors
+// d'entraînement, pour simuler une destruction.
+
+void CObject::SetEnable(BOOL bEnable)
+{
+ m_bEnable = bEnable;
+}
+
+BOOL CObject::RetEnable()
+{
+ return m_bEnable;
+}
+
+
+// Gestion du mode où un objet n'est activé que lorsqu'on
+// est proche.
+
+void CObject::SetProxyActivate(BOOL bActivate)
+{
+ m_bProxyActivate = bActivate;
+}
+
+BOOL CObject::RetProxyActivate()
+{
+ return m_bProxyActivate;
+}
+
+void CObject::SetProxyDistance(float distance)
+{
+ m_proxyDistance = distance;
+}
+
+float CObject::RetProxyDistance()
+{
+ return m_proxyDistance;
+}
+
+
+// Gestion du mode d'augmentation des dommages.
+
+void CObject::SetMagnifyDamage(float factor)
+{
+ m_magnifyDamage = factor;
+}
+
+float CObject::RetMagnifyDamage()
+{
+ return m_magnifyDamage;
+}
+
+
+// Gestion du paramètre libre.
+
+void CObject::SetParam(float value)
+{
+ m_param = value;
+}
+
+float CObject::RetParam()
+{
+ return m_param;
+}
+
+
+// Gestion du mode "bloqué" d'un objet.
+// Par exemple, un cube de titanium est bloqué pendant qu'il est utilisé
+// pour fabriquer qq chose, ou un véhicule est bloqué tant que sa
+// construction n'est pas terminée.
+
+void CObject::SetLock(BOOL bLock)
+{
+ m_bLock = bLock;
+}
+
+BOOL CObject::RetLock()
+{
+ return m_bLock;
+}
+
+// Gestion du mode "en cours d'explosion" d'un objet.
+// Un objet dans ce mode n'est pas sauvegardé.
+
+void CObject::SetExplo(BOOL bExplo)
+{
+ m_bExplo = bExplo;
+}
+
+BOOL CObject::RetExplo()
+{
+ return m_bExplo;
+}
+
+
+// Gestion du mode "cargaison du vaisseau" pendant les films.
+
+void CObject::SetCargo(BOOL bCargo)
+{
+ m_bCargo = bCargo;
+}
+
+BOOL CObject::RetCargo()
+{
+ return m_bCargo;
+}
+
+
+// Gestion du mode HS d'un objet.
+
+void CObject::SetBurn(BOOL bBurn)
+{
+ m_bBurn = bBurn;
+
+//? if ( m_botVar != 0 )
+//? {
+//? if ( m_bBurn ) m_botVar->SetUserPtr(OBJECTDELETED);
+//? else m_botVar->SetUserPtr(this);
+//? }
+}
+
+BOOL CObject::RetBurn()
+{
+ return m_bBurn;
+}
+
+void CObject::SetDead(BOOL bDead)
+{
+ m_bDead = bDead;
+
+ if ( bDead && m_brain != 0 )
+ {
+ m_brain->StopProgram(); // stoppe la tâche en cours
+ }
+
+//? if ( m_botVar != 0 )
+//? {
+//? if ( m_bDead ) m_botVar->SetUserPtr(OBJECTDELETED);
+//? else m_botVar->SetUserPtr(this);
+//? }
+}
+
+BOOL CObject::RetDead()
+{
+ return m_bDead;
+}
+
+BOOL CObject::RetRuin()
+{
+ return m_bBurn|m_bFlat;
+}
+
+BOOL CObject::RetActif()
+{
+ return !m_bLock && !m_bBurn && !m_bFlat && m_bVisible && m_bEnable;
+}
+
+
+// Gestion du point de visée.
+
+void CObject::SetGunGoalV(float gunGoal)
+{
+ if ( m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEic ) // fireball ?
+ {
+ if ( gunGoal > 10.0f*PI/180.0f ) gunGoal = 10.0f*PI/180.0f;
+ if ( gunGoal < -20.0f*PI/180.0f ) gunGoal = -20.0f*PI/180.0f;
+ SetAngleZ(1, gunGoal);
+ }
+ else if ( m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEii ) // orgaball ?
+ {
+ if ( gunGoal > 20.0f*PI/180.0f ) gunGoal = 20.0f*PI/180.0f;
+ if ( gunGoal < -20.0f*PI/180.0f ) gunGoal = -20.0f*PI/180.0f;
+ SetAngleZ(1, gunGoal);
+ }
+ else if ( m_type == OBJECT_MOBILErc ) // phazer ?
+ {
+ if ( gunGoal > 45.0f*PI/180.0f ) gunGoal = 45.0f*PI/180.0f;
+ if ( gunGoal < -20.0f*PI/180.0f ) gunGoal = -20.0f*PI/180.0f;
+ SetAngleZ(2, gunGoal);
+ }
+ else
+ {
+ gunGoal = 0.0f;
+ }
+
+ m_gunGoalV = gunGoal;
+}
+
+void CObject::SetGunGoalH(float gunGoal)
+{
+ if ( m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEic ) // fireball ?
+ {
+ if ( gunGoal > 40.0f*PI/180.0f ) gunGoal = 40.0f*PI/180.0f;
+ if ( gunGoal < -40.0f*PI/180.0f ) gunGoal = -40.0f*PI/180.0f;
+ SetAngleY(1, gunGoal);
+ }
+ else if ( m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEii ) // orgaball ?
+ {
+ if ( gunGoal > 40.0f*PI/180.0f ) gunGoal = 40.0f*PI/180.0f;
+ if ( gunGoal < -40.0f*PI/180.0f ) gunGoal = -40.0f*PI/180.0f;
+ SetAngleY(1, gunGoal);
+ }
+ else if ( m_type == OBJECT_MOBILErc ) // phazer ?
+ {
+ if ( gunGoal > 40.0f*PI/180.0f ) gunGoal = 40.0f*PI/180.0f;
+ if ( gunGoal < -40.0f*PI/180.0f ) gunGoal = -40.0f*PI/180.0f;
+ SetAngleY(2, gunGoal);
+ }
+ else
+ {
+ gunGoal = 0.0f;
+ }
+
+ m_gunGoalH = gunGoal;
+}
+
+float CObject::RetGunGoalV()
+{
+ return m_gunGoalV;
+}
+
+float CObject::RetGunGoalH()
+{
+ return m_gunGoalH;
+}
+
+
+
+// Montre les limites de l'objet.
+
+BOOL CObject::StartShowLimit()
+{
+ if ( m_showLimitRadius == 0.0f ) return FALSE;
+
+ m_main->SetShowLimit(0, PARTILIMIT1, this, RetPosition(0), m_showLimitRadius);
+ m_bShowLimit = TRUE;
+ return TRUE;
+}
+
+void CObject::StopShowLimit()
+{
+ m_bShowLimit = FALSE;
+}
+
+
+
+// Indique si un programme est en cours d'exécution.
+
+BOOL CObject::IsProgram()
+{
+ if ( m_brain == 0 ) return FALSE;
+ return m_brain->IsProgram();
+}
+
+
+// Crée ou supprime les particules associées à l'objet.
+
+void CObject::CreateSelectParticule()
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i;
+
+ // Supprime les particules précédentes.
+ for ( i=0 ; i<4 ; i++ )
+ {
+ if ( m_partiSel[i] != -1 )
+ {
+ m_particule->DeleteParticule(m_partiSel[i]);
+ m_partiSel[i] = -1;
+ }
+ }
+
+ if ( m_bSelect || IsProgram() )
+ {
+ // Crée les particules lens pour les phares.
+ if ( m_type == OBJECT_MOBILEfa ||
+ m_type == OBJECT_MOBILEta ||
+ m_type == OBJECT_MOBILEwa ||
+ m_type == OBJECT_MOBILEia ||
+ m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEic ||
+ m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEii ||
+ m_type == OBJECT_MOBILEfs ||
+ m_type == OBJECT_MOBILEts ||
+ m_type == OBJECT_MOBILEws ||
+ m_type == OBJECT_MOBILEis ||
+ m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErc ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs ||
+ m_type == OBJECT_MOBILEsa ||
+ m_type == OBJECT_MOBILEtg ||
+ m_type == OBJECT_MOBILEft ||
+ m_type == OBJECT_MOBILEtt ||
+ m_type == OBJECT_MOBILEwt ||
+ m_type == OBJECT_MOBILEit ||
+ m_type == OBJECT_MOBILEdr ) // véhicule ?
+ {
+ pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 0.0f;
+ dim.y = 0.0f;
+ m_partiSel[0] = m_particule->CreateParticule(pos, speed, dim, PARTISELY, 1.0f, 0.0f, 0.0f);
+ m_partiSel[1] = m_particule->CreateParticule(pos, speed, dim, PARTISELY, 1.0f, 0.0f, 0.0f);
+ m_partiSel[2] = m_particule->CreateParticule(pos, speed, dim, PARTISELR, 1.0f, 0.0f, 0.0f);
+ m_partiSel[3] = m_particule->CreateParticule(pos, speed, dim, PARTISELR, 1.0f, 0.0f, 0.0f);
+ UpdateSelectParticule();
+ }
+ }
+}
+
+// Met à jour les particules associées à l'objet.
+
+void CObject::UpdateSelectParticule()
+{
+ D3DVECTOR pos[4];
+ FPOINT dim[4];
+ float zoom[4];
+ float angle;
+ int i;
+
+ if ( !m_bSelect && !IsProgram() ) return;
+
+ dim[0].x = 1.0f;
+ dim[1].x = 1.0f;
+ dim[2].x = 1.2f;
+ dim[3].x = 1.2f;
+
+ // Lens avants jaunes.
+ if ( m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErc ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ pos[0] = D3DVECTOR(4.2f, 2.8f, 1.5f);
+ pos[1] = D3DVECTOR(4.2f, 2.8f, -1.5f);
+ dim[0].x = 1.5f;
+ dim[1].x = 1.5f;
+ }
+ else if ( m_type == OBJECT_MOBILEwt ||
+ m_type == OBJECT_MOBILEtt ||
+ m_type == OBJECT_MOBILEft ||
+ m_type == OBJECT_MOBILEit ) // trainer ?
+ {
+ pos[0] = D3DVECTOR(4.2f, 2.5f, 1.2f);
+ pos[1] = D3DVECTOR(4.2f, 2.5f, -1.2f);
+ dim[0].x = 1.5f;
+ dim[1].x = 1.5f;
+ }
+ else if ( m_type == OBJECT_MOBILEsa ) // sous-marin ?
+ {
+ pos[0] = D3DVECTOR(3.6f, 4.0f, 2.0f);
+ pos[1] = D3DVECTOR(3.6f, 4.0f, -2.0f);
+ }
+ else if ( m_type == OBJECT_MOBILEtg ) // cible ?
+ {
+ pos[0] = D3DVECTOR(3.4f, 6.5f, 2.0f);
+ pos[1] = D3DVECTOR(3.4f, 6.5f, -2.0f);
+ }
+ else if ( m_type == OBJECT_MOBILEdr ) // dessinateur ?
+ {
+ pos[0] = D3DVECTOR(4.9f, 3.5f, 2.5f);
+ pos[1] = D3DVECTOR(4.9f, 3.5f, -2.5f);
+ }
+ else
+ {
+ pos[0] = D3DVECTOR(4.2f, 2.5f, 1.5f);
+ pos[1] = D3DVECTOR(4.2f, 2.5f, -1.5f);
+ }
+
+ // Lens arrières rouges.
+ if ( m_type == OBJECT_MOBILEfa ||
+ m_type == OBJECT_MOBILEfc ||
+ m_type == OBJECT_MOBILEfi ||
+ m_type == OBJECT_MOBILEfs ||
+ m_type == OBJECT_MOBILEft ) // volant ?
+ {
+ pos[2] = D3DVECTOR(-4.0f, 3.1f, 4.5f);
+ pos[3] = D3DVECTOR(-4.0f, 3.1f, -4.5f);
+ dim[2].x = 0.6f;
+ dim[3].x = 0.6f;
+ }
+ if ( m_type == OBJECT_MOBILEwa ||
+ m_type == OBJECT_MOBILEwc ||
+ m_type == OBJECT_MOBILEwi ||
+ m_type == OBJECT_MOBILEws ) // roues ?
+ {
+ pos[2] = D3DVECTOR(-4.5f, 2.7f, 2.8f);
+ pos[3] = D3DVECTOR(-4.5f, 2.7f, -2.8f);
+ }
+ if ( m_type == OBJECT_MOBILEwt ) // roues ?
+ {
+ pos[2] = D3DVECTOR(-4.0f, 2.5f, 2.2f);
+ pos[3] = D3DVECTOR(-4.0f, 2.5f, -2.2f);
+ }
+ if ( m_type == OBJECT_MOBILEia ||
+ m_type == OBJECT_MOBILEic ||
+ m_type == OBJECT_MOBILEii ||
+ m_type == OBJECT_MOBILEis ||
+ m_type == OBJECT_MOBILEit ) // pattes ?
+ {
+ pos[2] = D3DVECTOR(-4.5f, 2.7f, 2.8f);
+ pos[3] = D3DVECTOR(-4.5f, 2.7f, -2.8f);
+ }
+ if ( m_type == OBJECT_MOBILEta ||
+ m_type == OBJECT_MOBILEtc ||
+ m_type == OBJECT_MOBILEti ||
+ m_type == OBJECT_MOBILEts ||
+ m_type == OBJECT_MOBILEtt ) // chenilles ?
+ {
+ pos[2] = D3DVECTOR(-3.6f, 4.2f, 3.0f);
+ pos[3] = D3DVECTOR(-3.6f, 4.2f, -3.0f);
+ }
+ if ( m_type == OBJECT_MOBILErt ||
+ m_type == OBJECT_MOBILErc ||
+ m_type == OBJECT_MOBILErr ||
+ m_type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ pos[2] = D3DVECTOR(-5.0f, 5.2f, 2.5f);
+ pos[3] = D3DVECTOR(-5.0f, 5.2f, -2.5f);
+ }
+ if ( m_type == OBJECT_MOBILEsa ) // sous-marin ?
+ {
+ pos[2] = D3DVECTOR(-3.6f, 4.0f, 2.0f);
+ pos[3] = D3DVECTOR(-3.6f, 4.0f, -2.0f);
+ }
+ if ( m_type == OBJECT_MOBILEtg ) // cible ?
+ {
+ pos[2] = D3DVECTOR(-2.4f, 6.5f, 2.0f);
+ pos[3] = D3DVECTOR(-2.4f, 6.5f, -2.0f);
+ }
+ if ( m_type == OBJECT_MOBILEdr ) // dessinateur ?
+ {
+ pos[2] = D3DVECTOR(-5.3f, 2.7f, 1.8f);
+ pos[3] = D3DVECTOR(-5.3f, 2.7f, -1.8f);
+ }
+
+ angle = RetAngleY(0)/PI;
+
+ zoom[0] = 1.0f;
+ zoom[1] = 1.0f;
+ zoom[2] = 1.0f;
+ zoom[3] = 1.0f;
+
+ if ( IsProgram() && // programme en cours ?
+ Mod(m_aTime, 0.7f) < 0.3f )
+ {
+ zoom[0] = 0.0f; // clignotte
+ zoom[1] = 0.0f;
+ zoom[2] = 0.0f;
+ zoom[3] = 0.0f;
+ }
+
+ // Met à jour tous les lens.
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos[i] = Transform(m_objectPart[0].matWorld, pos[i]);
+ dim[i].y = dim[i].x;
+ m_particule->SetParam(m_partiSel[i], pos[i], dim[i], zoom[i], angle, 1.0f);
+ }
+}
+
+
+// Donne le pointeur au script en cours d'exécution.
+
+void CObject::SetRunScript(CScript* script)
+{
+ m_runScript = script;
+}
+
+CScript* CObject::RetRunScript()
+{
+ return m_runScript;
+}
+
+// Retourne les variables du "this" pour CBOT.
+
+CBotVar* CObject::RetBotVar()
+{
+ return m_botVar;
+}
+
+// Retourne la physique associée à l'objet.
+
+CPhysics* CObject::RetPhysics()
+{
+ return m_physics;
+}
+
+// Retourne le cerveau associé à l'objet.
+
+CBrain* CObject::RetBrain()
+{
+ return m_brain;
+}
+
+// Retourne le mouvement associé à l'objet.
+
+CMotion* CObject::RetMotion()
+{
+ return m_motion;
+}
+
+// Retourne l'automate associé à l'objet.
+
+CAuto* CObject::RetAuto()
+{
+ return m_auto;
+}
+
+void CObject::SetAuto(CAuto* automat)
+{
+ m_auto = automat;
+}
+
+
+
+// Gestion du rang dans le fichier de définition.
+
+void CObject::SetDefRank(int rank)
+{
+ m_defRank = rank;
+}
+
+int CObject::RetDefRank()
+{
+ return m_defRank;
+}
+
+
+// Donne le nom de l'objet pour le tooltip.
+
+BOOL CObject::GetTooltipName(char* name)
+{
+ GetResource(RES_OBJECT, m_type, name);
+ return ( name[0] != 0 );
+}
+
+
+// Ajoute l'objet précédemment sélectionné dans la liste.
+
+void CObject::AddDeselList(CObject* pObj)
+{
+ int i;
+
+ if ( m_totalDesectList >= OBJECTMAXDESELLIST )
+ {
+ for ( i=0 ; i<OBJECTMAXDESELLIST-1 ; i++ )
+ {
+ m_objectDeselectList[i] = m_objectDeselectList[i+1];
+ }
+ m_totalDesectList --;
+ }
+
+ m_objectDeselectList[m_totalDesectList++] = pObj;
+}
+
+// Enlève l'objet précédemment sélectionné dans la liste.
+
+CObject* CObject::SubDeselList()
+{
+ if ( m_totalDesectList == 0 ) return 0;
+
+ return m_objectDeselectList[--m_totalDesectList];
+}
+
+// Supprime un objet s'il est référencé dans la liste.
+
+void CObject::DeleteDeselList(CObject* pObj)
+{
+ int i, j;
+
+ j = 0;
+ for ( i=0 ; i<m_totalDesectList ; i++ )
+ {
+ if ( m_objectDeselectList[i] != pObj )
+ {
+ m_objectDeselectList[j++] = m_objectDeselectList[i];
+ }
+ }
+ m_totalDesectList = j;
+}
+
+
+
+// Gestion de l'état du crayon du robot dessinateur.
+
+BOOL CObject::RetTraceDown()
+{
+ CMotionVehicle* mv;
+ if ( m_motion == 0 ) return FALSE;
+ mv = (CMotionVehicle*)m_motion;
+ return mv->RetTraceDown();
+}
+
+void CObject::SetTraceDown(BOOL bDown)
+{
+ CMotionVehicle* mv;
+ if ( m_motion == 0 ) return;
+ mv = (CMotionVehicle*)m_motion;
+ mv->SetTraceDown(bDown);
+}
+
+int CObject::RetTraceColor()
+{
+ CMotionVehicle* mv;
+ if ( m_motion == 0 ) return 0;
+ mv = (CMotionVehicle*)m_motion;
+ return mv->RetTraceColor();
+}
+
+void CObject::SetTraceColor(int color)
+{
+ CMotionVehicle* mv;
+ if ( m_motion == 0 ) return;
+ mv = (CMotionVehicle*)m_motion;
+ mv->SetTraceColor(color);
+}
+
+float CObject::RetTraceWidth()
+{
+ CMotionVehicle* mv;
+ if ( m_motion == 0 ) return 0.0f;
+ mv = (CMotionVehicle*)m_motion;
+ return mv->RetTraceWidth();
+}
+
+void CObject::SetTraceWidth(float width)
+{
+ CMotionVehicle* mv;
+ if ( m_motion == 0 ) return;
+ mv = (CMotionVehicle*)m_motion;
+ mv->SetTraceWidth(width);
+}
+
+
diff --git a/src/object.h b/src/object.h
new file mode 100644
index 0000000..785c6db
--- /dev/null
+++ b/src/object.h
@@ -0,0 +1,767 @@
+// object.h
+
+#ifndef _OBJECT_H_
+#define _OBJECT_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CLight;
+class CTerrain;
+class CWater;
+class CCamera;
+class CParticule;
+class CPhysics;
+class CBrain;
+class CMotion;
+class CAuto;
+class CDisplayText;
+class CRobotMain;
+class CBotVar;
+class CScript;
+
+enum CameraType;
+enum Sound;
+enum D3DShadowType;
+
+
+
+// Le père de toutes les parties doit toujours être la partie
+// numéro zéro !
+
+#define OBJECTMAXPART 40
+#define MAXCRASHSPHERE 40
+#define OBJECTMAXDESELLIST 10
+#define OBJECTMAXINFO 10
+#define OBJECTMAXCMDLINE 20
+
+enum ObjectType
+{
+ OBJECT_NULL = 0, // objet détruit
+ OBJECT_FIX = 1, // décor fixe
+ OBJECT_PORTICO = 2, // portique
+ OBJECT_BASE = 3, // grande base principale
+ OBJECT_DERRICK = 4, // derrick fixe
+ OBJECT_FACTORY = 5, // usine fixe
+ OBJECT_STATION = 6, // station de recharge
+ OBJECT_CONVERT = 7, // station de transformation
+ OBJECT_REPAIR = 8, // réparation
+ OBJECT_TOWER = 9, // tour de défense
+ OBJECT_NEST = 10, // nid
+ OBJECT_RESEARCH = 11, // centre de recherches
+ OBJECT_RADAR = 12, // radar
+ OBJECT_ENERGY = 13, // centrale d'énergie
+ OBJECT_LABO = 14, // laboratoire d'analyse pour insectes
+ OBJECT_NUCLEAR = 15, // centrale nucléaire
+ OBJECT_START = 16, // départ
+ OBJECT_END = 17, // arrivée
+ OBJECT_INFO = 18, // borne d'information
+ OBJECT_PARA = 19, // paratonnerre
+ OBJECT_TARGET1 = 20, // portique cible
+ OBJECT_TARGET2 = 21, // centre cible
+ OBJECT_SAFE = 22, // coffre fort
+ OBJECT_HUSTON = 23, // centre de contrôle
+ OBJECT_DESTROYER = 24, // destructeur
+ OBJECT_FRET = 30, // transportable
+ OBJECT_STONE = 31, // pierre
+ OBJECT_URANIUM = 32, // uranium
+ OBJECT_METAL = 33, // métal
+ OBJECT_POWER = 34, // pile normale
+ OBJECT_ATOMIC = 35, // pile atomique
+ OBJECT_BULLET = 36, // boulet
+ OBJECT_BBOX = 37, // black-box
+ OBJECT_TNT = 38, // caisse de TNT
+ OBJECT_SCRAP1 = 40, // déchet métallique
+ OBJECT_SCRAP2 = 41, // déchet métallique
+ OBJECT_SCRAP3 = 42, // déchet métallique
+ OBJECT_SCRAP4 = 43, // déchet plastique
+ OBJECT_SCRAP5 = 44, // déchet plastique
+ OBJECT_MARKPOWER = 50, // marque pile en sous-sol
+ OBJECT_MARKSTONE = 51, // marque minerai en sous-sol
+ OBJECT_MARKURANIUM = 52, // marque uranium en sous-sol
+ OBJECT_MARKKEYa = 53, // marque clé en sous-sol
+ OBJECT_MARKKEYb = 54, // marque clé en sous-sol
+ OBJECT_MARKKEYc = 55, // marque clé en sous-sol
+ OBJECT_MARKKEYd = 56, // marque clé en sous-sol
+ OBJECT_BOMB = 60, // bombe
+ OBJECT_WINFIRE = 61, // feu d'artifice
+ OBJECT_SHOW = 62, // montre un lieu
+ OBJECT_BAG = 63, // sac de survie
+ OBJECT_PLANT0 = 70, // plante 0
+ OBJECT_PLANT1 = 71, // plante 1
+ OBJECT_PLANT2 = 72, // plante 2
+ OBJECT_PLANT3 = 73, // plante 3
+ OBJECT_PLANT4 = 74, // plante 4
+ OBJECT_PLANT5 = 75, // plante 5
+ OBJECT_PLANT6 = 76, // plante 6
+ OBJECT_PLANT7 = 77, // plante 7
+ OBJECT_PLANT8 = 78, // plante 8
+ OBJECT_PLANT9 = 79, // plante 9
+ OBJECT_PLANT10 = 80, // plante 10
+ OBJECT_PLANT11 = 81, // plante 11
+ OBJECT_PLANT12 = 82, // plante 12
+ OBJECT_PLANT13 = 83, // plante 13
+ OBJECT_PLANT14 = 84, // plante 14
+ OBJECT_PLANT15 = 85, // plante 15
+ OBJECT_PLANT16 = 86, // plante 16
+ OBJECT_PLANT17 = 87, // plante 17
+ OBJECT_PLANT18 = 88, // plante 18
+ OBJECT_PLANT19 = 89, // plante 19
+ OBJECT_TREE0 = 90, // arbre 0
+ OBJECT_TREE1 = 91, // arbre 1
+ OBJECT_TREE2 = 92, // arbre 2
+ OBJECT_TREE3 = 93, // arbre 3
+ OBJECT_TREE4 = 94, // arbre 4
+ OBJECT_TREE5 = 95, // arbre 5
+ OBJECT_TREE6 = 96, // arbre 6
+ OBJECT_TREE7 = 97, // arbre 7
+ OBJECT_TREE8 = 98, // arbre 8
+ OBJECT_TREE9 = 99, // arbre 9
+ OBJECT_MOBILEwt = 100, // wheel-trainer
+ OBJECT_MOBILEtt = 101, // track-trainer
+ OBJECT_MOBILEft = 102, // fly-trainer
+ OBJECT_MOBILEit = 103, // insect-trainer
+ OBJECT_MOBILEwa = 110, // wheel-arm
+ OBJECT_MOBILEta = 111, // track-arm
+ OBJECT_MOBILEfa = 112, // fly-arm
+ OBJECT_MOBILEia = 113, // insect-arm
+ OBJECT_MOBILEwc = 120, // wheel-cannon
+ OBJECT_MOBILEtc = 121, // track-cannon
+ OBJECT_MOBILEfc = 122, // fly-cannon
+ OBJECT_MOBILEic = 123, // insect-cannon
+ OBJECT_MOBILEwi = 130, // wheel-insect-cannon
+ OBJECT_MOBILEti = 131, // track-insect-cannon
+ OBJECT_MOBILEfi = 132, // fly-insect-cannon
+ OBJECT_MOBILEii = 133, // insect-insect-cannon
+ OBJECT_MOBILEws = 140, // wheel-search
+ OBJECT_MOBILEts = 141, // track-search
+ OBJECT_MOBILEfs = 142, // fly-search
+ OBJECT_MOBILEis = 143, // insect-search
+ OBJECT_MOBILErt = 200, // roller-terraform
+ OBJECT_MOBILErc = 201, // roller-canon
+ OBJECT_MOBILErr = 202, // roller-recover
+ OBJECT_MOBILErs = 203, // roller-shield
+ OBJECT_MOBILEsa = 210, // sous-marin
+ OBJECT_MOBILEtg = 211, // cible d'exercice
+ OBJECT_MOBILEdr = 212, // robot de dessin
+ OBJECT_WAYPOINT = 250, // chemin
+ OBJECT_FLAGb = 260, // drapeau bleu
+ OBJECT_FLAGr = 261, // drapeau rouge
+ OBJECT_FLAGg = 262, // drapeau vert
+ OBJECT_FLAGy = 263, // drapeau jaune
+ OBJECT_FLAGv = 264, // drapeau violet
+ OBJECT_KEYa = 270, // clé a
+ OBJECT_KEYb = 271, // clé b
+ OBJECT_KEYc = 272, // clé c
+ OBJECT_KEYd = 273, // clé d
+ OBJECT_HUMAN = 300, // homme
+ OBJECT_TOTO = 301, // toto
+ OBJECT_TECH = 302, // technicien
+ OBJECT_BARRIER0 = 400, // barrière
+ OBJECT_BARRIER1 = 401, // barrière
+ OBJECT_BARRIER2 = 402, // barrière
+ OBJECT_BARRIER3 = 403, // barrière
+ OBJECT_BARRIER4 = 404, // barrière
+ OBJECT_MOTHER = 500, // mère pondeuse
+ OBJECT_EGG = 501, // oeuf
+ OBJECT_ANT = 502, // fourmi
+ OBJECT_SPIDER = 503, // araignée
+ OBJECT_BEE = 504, // abeille
+ OBJECT_WORM = 505, // ver
+ OBJECT_RUINmobilew1 = 600, // ruine 1
+ OBJECT_RUINmobilew2 = 601, // ruine 1
+ OBJECT_RUINmobilet1 = 602, // ruine 2
+ OBJECT_RUINmobilet2 = 603, // ruine 2
+ OBJECT_RUINmobiler1 = 604, // ruine 3
+ OBJECT_RUINmobiler2 = 605, // ruine 3
+ OBJECT_RUINfactory = 606, // ruine 4
+ OBJECT_RUINdoor = 607, // ruine 5
+ OBJECT_RUINsupport = 608, // ruine 6
+ OBJECT_RUINradar = 609, // ruine 7
+ OBJECT_RUINconvert = 610, // ruine 8
+ OBJECT_RUINbase = 611, // ruine 9
+ OBJECT_RUINhead = 612, // ruine 10
+ OBJECT_TEEN0 = 620, // jouet
+ OBJECT_TEEN1 = 621, // jouet
+ OBJECT_TEEN2 = 622, // jouet
+ OBJECT_TEEN3 = 623, // jouet
+ OBJECT_TEEN4 = 624, // jouet
+ OBJECT_TEEN5 = 625, // jouet
+ OBJECT_TEEN6 = 626, // jouet
+ OBJECT_TEEN7 = 627, // jouet
+ OBJECT_TEEN8 = 628, // jouet
+ OBJECT_TEEN9 = 629, // jouet
+ OBJECT_TEEN10 = 630, // jouet
+ OBJECT_TEEN11 = 631, // jouet
+ OBJECT_TEEN12 = 632, // jouet
+ OBJECT_TEEN13 = 633, // jouet
+ OBJECT_TEEN14 = 634, // jouet
+ OBJECT_TEEN15 = 635, // jouet
+ OBJECT_TEEN16 = 636, // jouet
+ OBJECT_TEEN17 = 637, // jouet
+ OBJECT_TEEN18 = 638, // jouet
+ OBJECT_TEEN19 = 639, // jouet
+ OBJECT_TEEN20 = 640, // jouet
+ OBJECT_TEEN21 = 641, // jouet
+ OBJECT_TEEN22 = 642, // jouet
+ OBJECT_TEEN23 = 643, // jouet
+ OBJECT_TEEN24 = 644, // jouet
+ OBJECT_TEEN25 = 645, // jouet
+ OBJECT_TEEN26 = 646, // jouet
+ OBJECT_TEEN27 = 647, // jouet
+ OBJECT_TEEN28 = 648, // jouet
+ OBJECT_TEEN29 = 649, // jouet
+ OBJECT_TEEN30 = 650, // jouet
+ OBJECT_TEEN31 = 651, // jouet
+ OBJECT_TEEN32 = 652, // jouet
+ OBJECT_TEEN33 = 653, // jouet
+ OBJECT_TEEN34 = 654, // jouet
+ OBJECT_TEEN35 = 655, // jouet
+ OBJECT_TEEN36 = 656, // jouet
+ OBJECT_TEEN37 = 657, // jouet
+ OBJECT_TEEN38 = 658, // jouet
+ OBJECT_TEEN39 = 659, // jouet
+ OBJECT_TEEN40 = 660, // jouet
+ OBJECT_TEEN41 = 661, // jouet
+ OBJECT_TEEN42 = 662, // jouet
+ OBJECT_TEEN43 = 663, // jouet
+ OBJECT_TEEN44 = 664, // jouet
+ OBJECT_TEEN45 = 665, // jouet
+ OBJECT_TEEN46 = 666, // jouet
+ OBJECT_TEEN47 = 667, // jouet
+ OBJECT_TEEN48 = 668, // jouet
+ OBJECT_TEEN49 = 669, // jouet
+ OBJECT_QUARTZ0 = 700, // quartz 0
+ OBJECT_QUARTZ1 = 701, // quartz 1
+ OBJECT_QUARTZ2 = 702, // quartz 2
+ OBJECT_QUARTZ3 = 703, // quartz 3
+ OBJECT_QUARTZ4 = 704, // quartz 4
+ OBJECT_QUARTZ5 = 705, // quartz 5
+ OBJECT_QUARTZ6 = 706, // quartz 6
+ OBJECT_QUARTZ7 = 707, // quartz 7
+ OBJECT_QUARTZ8 = 708, // quartz 8
+ OBJECT_QUARTZ9 = 709, // quartz 9
+ OBJECT_ROOT0 = 710, // racine 0
+ OBJECT_ROOT1 = 711, // racine 1
+ OBJECT_ROOT2 = 712, // racine 2
+ OBJECT_ROOT3 = 713, // racine 3
+ OBJECT_ROOT4 = 714, // racine 4
+ OBJECT_ROOT5 = 715, // racine 5
+ OBJECT_ROOT6 = 716, // racine 6
+ OBJECT_ROOT7 = 717, // racine 7
+ OBJECT_ROOT8 = 718, // racine 8
+ OBJECT_ROOT9 = 719, // racine 9
+ OBJECT_SEAWEED0 = 720, // algue 0
+ OBJECT_SEAWEED1 = 721, // algue 1
+ OBJECT_SEAWEED2 = 722, // algue 2
+ OBJECT_SEAWEED3 = 723, // algue 3
+ OBJECT_SEAWEED4 = 724, // algue 4
+ OBJECT_SEAWEED5 = 725, // algue 5
+ OBJECT_SEAWEED6 = 726, // algue 6
+ OBJECT_SEAWEED7 = 727, // algue 7
+ OBJECT_SEAWEED8 = 728, // algue 8
+ OBJECT_SEAWEED9 = 729, // algue 9
+ OBJECT_MUSHROOM0 = 730, // champignon 0
+ OBJECT_MUSHROOM1 = 731, // champignon 1
+ OBJECT_MUSHROOM2 = 732, // champignon 2
+ OBJECT_MUSHROOM3 = 733, // champignon 3
+ OBJECT_MUSHROOM4 = 734, // champignon 4
+ OBJECT_MUSHROOM5 = 735, // champignon 5
+ OBJECT_MUSHROOM6 = 736, // champignon 6
+ OBJECT_MUSHROOM7 = 737, // champignon 7
+ OBJECT_MUSHROOM8 = 738, // champignon 8
+ OBJECT_MUSHROOM9 = 739, // champignon 9
+ OBJECT_APOLLO1 = 900, // apollo lem
+ OBJECT_APOLLO2 = 901, // apollo jeep
+ OBJECT_APOLLO3 = 902, // apollo flag
+ OBJECT_APOLLO4 = 903, // apollo module
+ OBJECT_APOLLO5 = 904, // apollo antenna
+ OBJECT_HOME1 = 910, // maison 1
+ OBJECT_MAX = 1000,
+};
+
+enum ObjectMaterial
+{
+ OM_METAL = 0, // métal
+ OM_PLASTIC = 1, // plastique
+ OM_HUMAN = 2, // cosmonaute
+ OM_ANIMAL = 3, // insecte
+ OM_VEGETAL = 4, // plante
+ OM_MINERAL = 5, // pierre
+};
+
+typedef struct
+{
+ char bUsed;
+ int object; // numéro de l'objet dans CD3DEngine
+ int parentPart; // numéro de la partie père
+ int masterParti; // canal de la particule maître
+ D3DVECTOR position;
+ D3DVECTOR angle;
+ D3DVECTOR zoom;
+ char bTranslate;
+ char bRotate;
+ char bZoom;
+ D3DMATRIX matTranslate;
+ D3DMATRIX matRotate;
+ D3DMATRIX matTransform;
+ D3DMATRIX matWorld;
+}
+ObjectPart;
+
+typedef struct
+{
+ float wheelFront; // position X des roues avant
+ float wheelBack; // position X des roues arrières
+ float wheelLeft; // position Z des roues gauches
+ float wheelRight; // position Z des roues droites
+ float height; // hauteur normale au-dessus du sol
+ D3DVECTOR posPower; // position de la pile
+}
+Character;
+
+typedef struct
+{
+ char name[20]; // nom de l'information
+ float value; // valeur de l'information
+}
+Info;
+
+enum ExploType
+{
+ EXPLO_BOUM = 1,
+ EXPLO_BURN = 2,
+ EXPLO_WATER = 3,
+};
+
+enum ResetCap
+{
+ RESET_NONE = 0,
+ RESET_MOVE = 1,
+ RESET_DELETE = 2,
+};
+
+enum RadarFilter
+{
+ FILTER_NONE = 0,
+ FILTER_ONLYLANDING = 1,
+ FILTER_ONLYFLYING = 2,
+};
+
+
+
+
+class CObject
+{
+public:
+ CObject(CInstanceManager* iMan);
+ ~CObject();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ void Simplify();
+ BOOL ExploObject(ExploType type, float force, float decay=1.0f);
+
+ BOOL EventProcess(const Event &event);
+ void UpdateMapping();
+
+ int CreatePart();
+ void DeletePart(int part);
+ void SetObjectRank(int part, int objRank);
+ int RetObjectRank(int part);
+ void SetObjectParent(int part, int parent);
+ void SetType(ObjectType type);
+ ObjectType RetType();
+ char* RetName();
+ void SetOption(int option);
+ int RetOption();
+
+ void SetID(int id);
+ int RetID();
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+ void SetDrawWorld(BOOL bDraw);
+ void SetDrawFront(BOOL bDraw);
+
+ BOOL CreateVehicle(D3DVECTOR pos, float angle, ObjectType type, float power, BOOL bTrainer, BOOL bToy);
+ BOOL CreateInsect(D3DVECTOR pos, float angle, ObjectType type);
+ BOOL CreateBuilding(D3DVECTOR pos, float angle, float height, ObjectType type, float power=1.0f);
+ BOOL CreateResource(D3DVECTOR pos, float angle, ObjectType type, float power=1.0f);
+ BOOL CreateFlag(D3DVECTOR pos, float angle, ObjectType type);
+ BOOL CreateBarrier(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreatePlant(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreateMushroom(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreateTeen(D3DVECTOR pos, float angle, float zoom, float height, ObjectType type);
+ BOOL CreateQuartz(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreateRoot(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreateHome(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreateRuin(D3DVECTOR pos, float angle, float height, ObjectType type);
+ BOOL CreateApollo(D3DVECTOR pos, float angle, ObjectType type);
+
+ BOOL ReadProgram(int rank, char* filename);
+ BOOL WriteProgram(int rank, char* filename);
+ BOOL RunProgram(int rank);
+
+ int RetShadowLight();
+ int RetEffectLight();
+
+ void FlushCrashShere();
+ int CreateCrashSphere(D3DVECTOR pos, float radius, Sound sound, float hardness=0.45f);
+ int RetCrashSphereTotal();
+ BOOL GetCrashSphere(int rank, D3DVECTOR &pos, float &radius);
+ float RetCrashSphereHardness(int rank);
+ Sound RetCrashSphereSound(int rank);
+ void DeleteCrashSphere(int rank);
+ void SetGlobalSphere(D3DVECTOR pos, float radius);
+ void GetGlobalSphere(D3DVECTOR &pos, float &radius);
+ void SetJotlerSphere(D3DVECTOR pos, float radius);
+ void GetJotlerSphere(D3DVECTOR &pos, float &radius);
+ void SetShieldRadius(float radius);
+ float RetShieldRadius();
+
+ void SetFloorHeight(float height);
+ void FloorAdjust();
+
+ void SetLinVibration(D3DVECTOR dir);
+ D3DVECTOR RetLinVibration();
+ void SetCirVibration(D3DVECTOR dir);
+ D3DVECTOR RetCirVibration();
+ void SetInclinaison(D3DVECTOR dir);
+ D3DVECTOR RetInclinaison();
+
+ void SetPosition(int part, const D3DVECTOR &pos);
+ D3DVECTOR RetPosition(int part);
+ void SetAngle(int part, const D3DVECTOR &angle);
+ D3DVECTOR RetAngle(int part);
+ void SetAngleY(int part, float angle);
+ void SetAngleX(int part, float angle);
+ void SetAngleZ(int part, float angle);
+ float RetAngleY(int part);
+ float RetAngleX(int part);
+ float RetAngleZ(int part);
+ void SetZoom(int part, float zoom);
+ void SetZoom(int part, D3DVECTOR zoom);
+ D3DVECTOR RetZoom(int part);
+ void SetZoomX(int part, float zoom);
+ float RetZoomX(int part);
+ void SetZoomY(int part, float zoom);
+ float RetZoomY(int part);
+ void SetZoomZ(int part, float zoom);
+ float RetZoomZ(int part);
+
+ float RetWaterLevel();
+
+ void SetTrainer(BOOL bEnable);
+ BOOL RetTrainer();
+
+ void SetToy(BOOL bEnable);
+ BOOL RetToy();
+
+ void SetManual(BOOL bManual);
+ BOOL RetManual();
+
+ void SetResetCap(ResetCap cap);
+ ResetCap RetResetCap();
+ void SetResetBusy(BOOL bBusy);
+ BOOL RetResetBusy();
+ void SetResetPosition(const D3DVECTOR &pos);
+ D3DVECTOR RetResetPosition();
+ void SetResetAngle(const D3DVECTOR &angle);
+ D3DVECTOR RetResetAngle();
+ void SetResetRun(int run);
+ int RetResetRun();
+
+ void SetMasterParticule(int part, int parti);
+ int RetMasterParticule(int part);
+
+ void SetPower(CObject* power);
+ CObject* RetPower();
+ void SetFret(CObject* fret);
+ CObject* RetFret();
+ void SetTruck(CObject* truck);
+ CObject* RetTruck();
+ void SetTruckPart(int part);
+ int RetTruckPart();
+
+ void InfoFlush();
+ void DeleteInfo(int rank);
+ void SetInfo(int rank, Info info);
+ Info RetInfo(int rank);
+ int RetInfoTotal();
+ void SetInfoReturn(float value);
+ float RetInfoReturn();
+ void SetInfoUpdate(BOOL bUpdate);
+ BOOL RetInfoUpdate();
+
+ BOOL SetCmdLine(int rank, float value);
+ float RetCmdLine(int rank);
+
+ D3DMATRIX* RetRotateMatrix(int part);
+ D3DMATRIX* RetTranslateMatrix(int part);
+ D3DMATRIX* RetTransformMatrix(int part);
+ D3DMATRIX* RetWorldMatrix(int part);
+
+ void SetViewFromHere(D3DVECTOR &eye, float &dirH, float &dirV, D3DVECTOR &lookat, D3DVECTOR &upVec, CameraType type);
+
+ void SetCharacter(Character* character);
+ void GetCharacter(Character* character);
+ Character* RetCharacter();
+
+ float RetAbsTime();
+
+ void SetEnergy(float level);
+ float RetEnergy();
+
+ void SetCapacity(float capacity);
+ float RetCapacity();
+
+ void SetShield(float level);
+ float RetShield();
+
+ void SetRange(float delay);
+ float RetRange();
+
+ void SetTransparency(float value);
+ float RetTransparency();
+
+ ObjectMaterial RetMaterial();
+
+ void SetGadget(BOOL bMode);
+ BOOL RetGadget();
+
+ void SetFixed(BOOL bFixed);
+ BOOL RetFixed();
+
+ void SetClip(BOOL bClip);
+ BOOL RetClip();
+
+ BOOL JostleObject(float force);
+
+ void StartDetectEffect(CObject *target, BOOL bFound);
+
+ void SetVirusMode(BOOL bEnable);
+ BOOL RetVirusMode();
+ float RetVirusTime();
+
+ void SetCameraType(CameraType type);
+ CameraType RetCameraType();
+ void SetCameraDist(float dist);
+ float RetCameraDist();
+ void SetCameraLock(BOOL bLock);
+ BOOL RetCameraLock();
+
+ void SetHilite(BOOL bMode);
+ BOOL RetHilite();
+
+ void SetSelect(BOOL bMode, BOOL bDisplayError=TRUE);
+ BOOL RetSelect(BOOL bReal=FALSE);
+
+ void SetSelectable(BOOL bMode);
+ BOOL RetSelectable();
+
+ void SetActivity(BOOL bMode);
+ BOOL RetActivity();
+
+ void SetVisible(BOOL bVisible);
+ BOOL RetVisible();
+
+ void SetEnable(BOOL bEnable);
+ BOOL RetEnable();
+
+ void SetCheckToken(BOOL bMode);
+ BOOL RetCheckToken();
+
+ void SetProxyActivate(BOOL bActivate);
+ BOOL RetProxyActivate();
+ void SetProxyDistance(float distance);
+ float RetProxyDistance();
+
+ void SetMagnifyDamage(float factor);
+ float RetMagnifyDamage();
+
+ void SetParam(float value);
+ float RetParam();
+
+ void SetExplo(BOOL bExplo);
+ BOOL RetExplo();
+ void SetLock(BOOL bLock);
+ BOOL RetLock();
+ void SetCargo(BOOL bCargo);
+ BOOL RetCargo();
+ void SetBurn(BOOL bBurn);
+ BOOL RetBurn();
+ void SetDead(BOOL bDead);
+ BOOL RetDead();
+ BOOL RetRuin();
+ BOOL RetActif();
+
+ void SetGunGoalV(float gunGoal);
+ void SetGunGoalH(float gunGoal);
+ float RetGunGoalV();
+ float RetGunGoalH();
+
+ BOOL StartShowLimit();
+ void StopShowLimit();
+
+ BOOL IsProgram();
+ void CreateSelectParticule();
+
+ void SetRunScript(CScript* script);
+ CScript* RetRunScript();
+ CBotVar* RetBotVar();
+ CPhysics* RetPhysics();
+ CBrain* RetBrain();
+ CMotion* RetMotion();
+ CAuto* RetAuto();
+ void SetAuto(CAuto* automat);
+
+ void SetDefRank(int rank);
+ int RetDefRank();
+
+ BOOL GetTooltipName(char* name);
+
+ void AddDeselList(CObject* pObj);
+ CObject* SubDeselList();
+ void DeleteDeselList(CObject* pObj);
+
+ BOOL CreateShadowCircle(float radius, float intensity, D3DShadowType type=D3DSHADOWNORM);
+ BOOL CreateShadowLight(float height, D3DCOLORVALUE color);
+ BOOL CreateEffectLight(float height, D3DCOLORVALUE color);
+
+ void FlatParent();
+
+ BOOL RetTraceDown();
+ void SetTraceDown(BOOL bDown);
+ int RetTraceColor();
+ void SetTraceColor(int color);
+ float RetTraceWidth();
+ void SetTraceWidth(float width);
+
+protected:
+ BOOL EventFrame(const Event &event);
+ void VirusFrame(float rTime);
+ void PartiFrame(float rTime);
+ void CreateOtherObject(ObjectType type);
+ void InitPart(int part);
+ void UpdateTotalPart();
+ int SearchDescendant(int parent, int n);
+ void UpdateEnergyMapping();
+ BOOL UpdateTransformObject(int part, BOOL bForceUpdate);
+ BOOL UpdateTransformObject();
+ void UpdateSelectParticule();
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CLight* m_light;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCamera* m_camera;
+ CParticule* m_particule;
+ CPhysics* m_physics;
+ CBrain* m_brain;
+ CMotion* m_motion;
+ CAuto* m_auto;
+ CDisplayText* m_displayText;
+ CRobotMain* m_main;
+ CSound* m_sound;
+ CBotVar* m_botVar;
+ CScript* m_runScript;
+
+ ObjectType m_type; // OBJECT_*
+ int m_id; // identificateur unique
+ char m_name[50]; // nom de l'objet
+ Character m_character; // caractéristiques
+ int m_option; // option
+ int m_partiReactor; // numéro de la particule du réacteur
+ int m_shadowLight; // numéro de la lumière de l'ombre
+ float m_shadowHeight; // hauteur de la lumière de l'ombre
+ int m_effectLight; // numéro de la lumière des effets
+ float m_effectHeight; // hauteur de la lumière des effets
+ D3DVECTOR m_linVibration; // vibration linéaire
+ D3DVECTOR m_cirVibration; // vibration circulaire
+ D3DVECTOR m_inclinaison; // inclinaison
+ CObject* m_power; // pile utilisée par le véhicule
+ CObject* m_fret; // objet transporté
+ CObject* m_truck; // objet portant celui-ci
+ int m_truckLink; // partie
+ float m_energy; // énergie contenue (si pile)
+ float m_lastEnergy;
+ float m_capacity; // capacité (si pile)
+ float m_shield; // bouclier
+ float m_range; // autonomie de vol
+ float m_transparency; // transparence (0..1)
+ int m_material; // matière (0..n)
+ float m_aTime;
+ float m_shotTime; // temps depuis dernier coup
+ BOOL m_bVirusMode; // virus enclanché/déclanché
+ float m_virusTime; // temps de vie du virus
+ float m_lastVirusParticule;
+ float m_lastParticule;
+ BOOL m_bHilite;
+ BOOL m_bSelect; // objet sélectionné
+ BOOL m_bSelectable; // objet sélectionnable
+ BOOL m_bCheckToken; // objet avec tokens vérifiés
+ BOOL m_bVisible; // objet actif mais indétectable
+ BOOL m_bEnable; // objet mort
+ BOOL m_bProxyActivate; // objet activé si proche
+ BOOL m_bGadget; // objet non indispensable
+ BOOL m_bLock;
+ BOOL m_bExplo;
+ BOOL m_bCargo;
+ BOOL m_bBurn;
+ BOOL m_bDead;
+ BOOL m_bFlat;
+ BOOL m_bTrainer; // véhicule d'entraînement (sans télécommande)
+ BOOL m_bToy; // jouet à clé
+ BOOL m_bManual; // commandes manuelles (Scribbler)
+ BOOL m_bFixed;
+ BOOL m_bClip;
+ BOOL m_bShowLimit;
+ float m_showLimitRadius;
+ float m_gunGoalV;
+ float m_gunGoalH;
+ CameraType m_cameraType;
+ float m_cameraDist;
+ BOOL m_bCameraLock;
+ int m_defRank;
+ float m_magnifyDamage;
+ float m_proxyDistance;
+ float m_param;
+
+ int m_crashSphereUsed; // nb de sphères utilisées
+ D3DVECTOR m_crashSpherePos[MAXCRASHSPHERE];
+ float m_crashSphereRadius[MAXCRASHSPHERE];
+ float m_crashSphereHardness[MAXCRASHSPHERE];
+ Sound m_crashSphereSound[MAXCRASHSPHERE];
+ D3DVECTOR m_globalSpherePos;
+ float m_globalSphereRadius;
+ D3DVECTOR m_jotlerSpherePos;
+ float m_jotlerSphereRadius;
+ float m_shieldRadius;
+
+ int m_totalPart;
+ ObjectPart m_objectPart[OBJECTMAXPART];
+
+ int m_totalDesectList;
+ CObject* m_objectDeselectList[OBJECTMAXDESELLIST];
+
+ int m_partiSel[4];
+
+ ResetCap m_resetCap;
+ BOOL m_bResetBusy;
+ D3DVECTOR m_resetPosition;
+ D3DVECTOR m_resetAngle;
+ int m_resetRun;
+
+ int m_infoTotal;
+ Info m_info[OBJECTMAXINFO];
+ float m_infoReturn;
+ BOOL m_bInfoUpdate;
+
+ float m_cmdLine[OBJECTMAXCMDLINE];
+};
+
+
+#endif //_OBJECT_H_
diff --git a/src/particule.cpp b/src/particule.cpp
new file mode 100644
index 0000000..e98f249
--- /dev/null
+++ b/src/particule.cpp
@@ -0,0 +1,4357 @@
+// particule.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DMath.h"
+#include "D3DTextr.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "iman.h"
+#include "math3d.h"
+#include "event.h"
+#include "object.h"
+#include "physics.h"
+#include "auto.h"
+#include "robotmain.h"
+#include "terrain.h"
+#include "sound.h"
+#include "water.h"
+#include "particule.h"
+
+
+
+#define FOG_HSUP 10.0f
+#define FOG_HINF 100.0f
+
+
+
+
+// Vérifie si un objet est destructible, mais pas un ennemi.
+
+BOOL IsSoft(ObjectType type)
+{
+ return ( type == OBJECT_HUMAN ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr || // robot ?
+ type == OBJECT_METAL ||
+ type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC || // fret ?
+ type == OBJECT_DERRICK ||
+ type == OBJECT_STATION ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER||
+ 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 ); // bâtiment ?
+}
+
+// Vérifie si un objet est un ennemi destructible.
+
+BOOL IsAlien(ObjectType type)
+{
+ return ( type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_NEST ||
+ type == OBJECT_BULLET ||
+ type == OBJECT_EGG ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_TEEN28 ||
+ type == OBJECT_TEEN31 );
+}
+
+// Retourne le facteur d'aténumation pour les tirs amis.
+
+float RetDecay(ObjectType type)
+{
+ if ( IsSoft(type) ) return 0.2f;
+ return 1.0f;
+}
+
+
+
+// Application constructor.
+
+CParticule::CParticule(CInstanceManager *iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_PARTICULE, this);
+
+ m_pD3DDevice = 0;
+ m_engine = engine;
+ m_main = 0;
+ m_terrain = 0;
+ m_water = 0;
+ m_sound = 0;
+ m_uniqueStamp = 0;
+ m_exploGunCounter = 0;
+ m_lastTimeGunDel = 0.0f;
+ m_absTime = 0.0f;
+
+ FlushParticule();
+}
+
+// Application destructor. Free memory.
+
+CParticule::~CParticule()
+{
+ m_iMan->DeleteInstance(CLASS_PARTICULE, this);
+}
+
+
+void CParticule::SetD3DDevice(LPDIRECT3DDEVICE7 device)
+{
+ m_pD3DDevice = device;
+}
+
+
+// Supprime toutes les particules.
+
+void CParticule::FlushParticule()
+{
+ int i, j;
+
+ for ( i=0 ; i<MAXPARTICULE*MAXPARTITYPE ; i++ )
+ {
+ m_particule[i].bUsed = FALSE;
+ }
+
+ for ( i=0 ; i<MAXPARTITYPE ; i++ )
+ {
+ for ( j=0 ; j<SH_MAX ; j++ )
+ {
+ m_totalInterface[i][j] = 0;
+ }
+ }
+
+ for ( i=0 ; i<MAXTRACK ; i++ )
+ {
+ m_track[i].bUsed = FALSE;
+ }
+
+ m_wheelTraceTotal = 0;
+ m_wheelTraceIndex = 0;
+
+ for ( i=0 ; i<SH_MAX ; i++ )
+ {
+ m_bFrameUpdate[i] = TRUE;
+ }
+
+ m_fogTotal = 0;
+ m_exploGunCounter = 0;
+}
+
+// Supprime toutes les particules d'une feuille.
+
+void CParticule::FlushParticule(int sheet)
+{
+ int i;
+
+ for ( i=0 ; i<MAXPARTICULE*MAXPARTITYPE ; i++ )
+ {
+ if ( !m_particule[i].bUsed ) continue;
+ if ( m_particule[i].sheet != sheet ) continue;
+
+ m_particule[i].bUsed = FALSE;
+ }
+
+ for ( i=0 ; i<MAXPARTITYPE ; i++ )
+ {
+ m_totalInterface[i][sheet] = 0;
+ }
+
+ for ( i=0 ; i<MAXTRACK ; i++ )
+ {
+ m_track[i].bUsed = FALSE;
+ }
+
+ if ( sheet == SH_WORLD )
+ {
+ m_wheelTraceTotal = 0;
+ m_wheelTraceIndex = 0;
+ }
+}
+
+
+// Construit le nom de fichier de l'effet.
+// effectNN.tga, avec NN = numéro
+
+void NameParticule(char *buffer, int num)
+{
+ if ( num == 1 ) strcpy(buffer, "effect00.tga");
+ else if ( num == 2 ) strcpy(buffer, "effect01.tga");
+ else if ( num == 3 ) strcpy(buffer, "effect02.tga");
+#if _POLISH
+ else if ( num == 4 ) strcpy(buffer, "textp.tga");
+#else
+ else if ( num == 4 ) strcpy(buffer, "text.tga");
+#endif
+ else strcpy(buffer, "xxx.tga");
+}
+
+
+// Créé une nouvelle particule.
+// Retourne le canal de la particule crée ou -1 en cas d'erreur.
+
+int CParticule::CreateParticule(D3DVECTOR pos, D3DVECTOR speed, FPOINT dim,
+ ParticuleType type,
+ float duration, float mass,
+ float windSensitivity, int sheet)
+{
+//? float dist;
+ int i, j, t;
+
+ if ( m_main == 0 )
+ {
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ }
+
+#if 0
+ if ( sheet == SH_WORLD &&
+ type != PARTISELY &&
+ type != PARTISELR &&
+ type != PARTIGUN1 &&
+ type != PARTIGUN2 &&
+ type != PARTIGUN3 &&
+ type != PARTIGUN4 &&
+ type != PARTIQUARTZ &&
+ !m_main->RetMovieLock() )
+ {
+ dist = Length(pos, m_engine->RetEyePt());
+ if ( dist > 300.0f ) return -1;
+ }
+#endif
+
+ t = -1;
+ if ( type == PARTIEXPLOT ||
+ type == PARTIEXPLOO ||
+ type == PARTIMOTOR ||
+ type == PARTIBLITZ ||
+ type == PARTICRASH ||
+ type == PARTIVAPOR ||
+ type == PARTIGAS ||
+ type == PARTIBASE ||
+ type == PARTIFIRE ||
+ type == PARTIFIREZ ||
+ type == PARTIBLUE ||
+ type == PARTIROOT ||
+ type == PARTIRECOVER ||
+ type == PARTIEJECT ||
+ type == PARTISCRAPS ||
+ type == PARTIGUN2 ||
+ type == PARTIGUN3 ||
+ type == PARTIGUN4 ||
+ type == PARTIQUEUE ||
+ type == PARTIORGANIC1 ||
+ type == PARTIORGANIC2 ||
+ type == PARTIFLAME ||
+ type == PARTIBUBBLE ||
+ type == PARTIERROR ||
+ type == PARTIWARNING ||
+ type == PARTIINFO ||
+ type == PARTISPHERE1 ||
+ type == PARTISPHERE2 ||
+ type == PARTISPHERE4 ||
+ type == PARTISPHERE5 ||
+ type == PARTISPHERE6 ||
+ type == PARTIPLOUF0 ||
+ type == PARTITRACK1 ||
+ type == PARTITRACK2 ||
+ type == PARTITRACK3 ||
+ type == PARTITRACK4 ||
+ type == PARTITRACK5 ||
+ type == PARTITRACK6 ||
+ type == PARTITRACK7 ||
+ type == PARTITRACK8 ||
+ type == PARTITRACK9 ||
+ type == PARTITRACK10 ||
+ type == PARTITRACK11 ||
+ type == PARTITRACK12 ||
+ type == PARTILENS1 ||
+ type == PARTILENS2 ||
+ type == PARTILENS3 ||
+ type == PARTILENS4 ||
+ type == PARTIGFLAT ||
+ type == PARTIDROP ||
+ type == PARTIWATER ||
+ type == PARTILIMIT1 ||
+ type == PARTILIMIT2 ||
+ type == PARTILIMIT3 ||
+ type == PARTILIMIT4 ||
+ type == PARTIEXPLOG1 ||
+ type == PARTIEXPLOG2 )
+ {
+ t = 1; // effect00
+ }
+ if ( type == PARTIGLINT ||
+ type == PARTIGLINTb ||
+ type == PARTIGLINTr ||
+ type == PARTITOTO ||
+ type == PARTISELY ||
+ type == PARTISELR ||
+ type == PARTIQUARTZ ||
+ type == PARTIGUNDEL ||
+ type == PARTICONTROL ||
+ type == PARTISHOW ||
+ type == PARTICHOC ||
+ type == PARTIFOG4 ||
+ type == PARTIFOG5 ||
+ type == PARTIFOG6 ||
+ type == PARTIFOG7 )
+ {
+ t = 2; // effect01
+ }
+ if ( type == PARTIGUN1 ||
+ type == PARTIFLIC ||
+ type == PARTISPHERE0 ||
+ type == PARTISPHERE3 ||
+ type == PARTIFOG0 ||
+ type == PARTIFOG1 ||
+ type == PARTIFOG2 ||
+ type == PARTIFOG3 )
+ {
+ t = 3; // effect02
+ }
+ if ( type == PARTISMOKE1 ||
+ type == PARTISMOKE2 ||
+ type == PARTISMOKE3 ||
+ type == PARTIBLOOD ||
+ type == PARTIBLOODM ||
+ type == PARTIVIRUS1 ||
+ type == PARTIVIRUS2 ||
+ type == PARTIVIRUS3 ||
+ type == PARTIVIRUS4 ||
+ type == PARTIVIRUS5 ||
+ type == PARTIVIRUS6 ||
+ type == PARTIVIRUS7 ||
+ type == PARTIVIRUS8 ||
+ type == PARTIVIRUS9 ||
+ type == PARTIVIRUS10 )
+ {
+ t = 4; // text (D3DSTATETTw)
+ }
+ if ( t >= MAXPARTITYPE ) return -1;
+ if ( t == -1 ) return -1;
+
+ for ( j=0 ; j<MAXPARTICULE ; j++ )
+ {
+ i = MAXPARTICULE*t+j;
+
+ if ( !m_particule[i].bUsed )
+ {
+ ZeroMemory(&m_particule[i], sizeof(Particule));
+ m_particule[i].bUsed = TRUE;
+ m_particule[i].bRay = FALSE;
+ m_particule[i].uniqueStamp = m_uniqueStamp++;
+ m_particule[i].sheet = sheet;
+ m_particule[i].mass = mass;
+ m_particule[i].duration = duration;
+ m_particule[i].pos = pos;
+ m_particule[i].goal = pos;
+ m_particule[i].speed = speed;
+ m_particule[i].windSensitivity = windSensitivity;
+ m_particule[i].dim = dim;
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].angle = 0.0f;
+ m_particule[i].intensity = 1.0f;
+ m_particule[i].type = type;
+ m_particule[i].phase = PARPHSTART;
+ m_particule[i].texSup.x = 0.0f;
+ m_particule[i].texSup.y = 0.0f;
+ m_particule[i].texInf.x = 0.0f;
+ m_particule[i].texInf.y = 0.0f;
+ m_particule[i].time = 0.0f;
+ m_particule[i].phaseTime = 0.0f;
+ m_particule[i].testTime = 0.0f;
+ m_particule[i].objLink = 0;
+ m_particule[i].objFather = 0;
+ m_particule[i].trackRank = -1;
+
+ m_totalInterface[t][sheet] ++;
+
+ if ( type == PARTIEXPLOT ||
+ type == PARTIEXPLOO )
+ {
+ m_particule[i].angle = Rand()*PI*2.0f;
+ }
+
+ if ( type == PARTIGUN1 ||
+ type == PARTIGUN4 )
+ {
+ m_particule[i].testTime = 1.0f; // impact tout de suite
+ }
+
+ if ( type >= PARTIFOG0 &&
+ type <= PARTIFOG9 )
+ {
+ if ( m_fogTotal < MAXPARTIFOG )
+ m_fog[m_fogTotal++] = i;
+ }
+
+ return i | ((m_particule[i].uniqueStamp&0xffff)<<16);
+ }
+ }
+
+ return -1;
+}
+
+// Créé une nouvelle particule triangulaire (débris).
+// Retourne le canal de la particule crée ou -1 en cas d'erreur.
+
+int CParticule::CreateFrag(D3DVECTOR pos, D3DVECTOR speed,
+ D3DTriangle *triangle,
+ ParticuleType type,
+ float duration, float mass,
+ float windSensitivity, int sheet)
+{
+ D3DVECTOR p1, p2, p3, n;
+ float l1, l2, l3, dx, dy;
+ int i, j, t;
+
+ t = 0;
+ for ( j=0 ; j<MAXPARTICULE ; j++ )
+ {
+ i = MAXPARTICULE*t+j;
+
+ if ( !m_particule[i].bUsed )
+ {
+ ZeroMemory(&m_particule[i], sizeof(Particule));
+ m_particule[i].bUsed = TRUE;
+ m_particule[i].bRay = FALSE;
+ m_particule[i].uniqueStamp = m_uniqueStamp++;
+ m_particule[i].sheet = sheet;
+ m_particule[i].mass = mass;
+ m_particule[i].duration = duration;
+ m_particule[i].pos = pos;
+ m_particule[i].goal = pos;
+ m_particule[i].speed = speed;
+ m_particule[i].windSensitivity = windSensitivity;
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].angle = 0.0f;
+ m_particule[i].intensity = 1.0f;
+ m_particule[i].type = type;
+ m_particule[i].phase = PARPHSTART;
+ m_particule[i].texSup.x = 0.0f;
+ m_particule[i].texSup.y = 0.0f;
+ m_particule[i].texInf.x = 0.0f;
+ m_particule[i].texInf.y = 0.0f;
+ m_particule[i].time = 0.0f;
+ m_particule[i].phaseTime = 0.0f;
+ m_particule[i].testTime = 0.0f;
+ m_particule[i].objLink = 0;
+ m_particule[i].objFather = 0;
+ m_particule[i].trackRank = -1;
+ m_triangle[i] = *triangle;
+
+ m_totalInterface[t][sheet] ++;
+
+ p1.x = m_triangle[i].triangle[0].x;
+ p1.y = m_triangle[i].triangle[0].y;
+ p1.z = m_triangle[i].triangle[0].z;
+
+ p2.x = m_triangle[i].triangle[1].x;
+ p2.y = m_triangle[i].triangle[1].y;
+ p2.z = m_triangle[i].triangle[1].z;
+
+ p3.x = m_triangle[i].triangle[2].x;
+ p3.y = m_triangle[i].triangle[2].y;
+ p3.z = m_triangle[i].triangle[2].z;
+
+ l1 = Length(p1, p2);
+ l2 = Length(p2, p3);
+ l3 = Length(p3, p1);
+ dx = Abs(Min(l1, l2, l3))*0.5f;
+ dy = Abs(Max(l1, l2, l3))*0.5f;
+ p1 = D3DVECTOR(-dx, dy, 0.0f);
+ p2 = D3DVECTOR( dx, dy, 0.0f);
+ p3 = D3DVECTOR(-dx, -dy, 0.0f);
+
+ m_triangle[i].triangle[0].x = p1.x;
+ m_triangle[i].triangle[0].y = p1.y;
+ m_triangle[i].triangle[0].z = p1.z;
+
+ m_triangle[i].triangle[1].x = p2.x;
+ m_triangle[i].triangle[1].y = p2.y;
+ m_triangle[i].triangle[1].z = p2.z;
+
+ m_triangle[i].triangle[2].x = p3.x;
+ m_triangle[i].triangle[2].y = p3.y;
+ m_triangle[i].triangle[2].z = p3.z;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f);
+
+ m_triangle[i].triangle[0].nx = n.x;
+ m_triangle[i].triangle[0].ny = n.y;
+ m_triangle[i].triangle[0].nz = n.z;
+
+ m_triangle[i].triangle[1].nx = n.x;
+ m_triangle[i].triangle[1].ny = n.y;
+ m_triangle[i].triangle[1].nz = n.z;
+
+ m_triangle[i].triangle[2].nx = n.x;
+ m_triangle[i].triangle[2].ny = n.y;
+ m_triangle[i].triangle[2].nz = n.z;
+
+ if ( type == PARTIFRAG )
+ {
+ m_particule[i].angle = Rand()*PI*2.0f;
+ }
+ return i | ((m_particule[i].uniqueStamp&0xffff)<<16);
+ }
+ }
+
+ return -1;
+}
+
+// Créé une nouvelle particule étant une partie d'objet.
+// Retourne le canal de la particule crée ou -1 en cas d'erreur.
+
+int CParticule::CreatePart(D3DVECTOR pos, D3DVECTOR speed,
+ ParticuleType type,
+ float duration, float mass, float weight,
+ float windSensitivity, int sheet)
+{
+ int i, j, t;
+
+ t = 0;
+ for ( j=0 ; j<MAXPARTICULE ; j++ )
+ {
+ i = MAXPARTICULE*t+j;
+
+ if ( !m_particule[i].bUsed )
+ {
+ ZeroMemory(&m_particule[i], sizeof(Particule));
+ m_particule[i].bUsed = TRUE;
+ m_particule[i].bRay = FALSE;
+ m_particule[i].uniqueStamp = m_uniqueStamp++;
+ m_particule[i].sheet = sheet;
+ m_particule[i].mass = mass;
+ m_particule[i].weight = weight;
+ m_particule[i].duration = duration;
+ m_particule[i].pos = pos;
+ m_particule[i].goal = pos;
+ m_particule[i].speed = speed;
+ m_particule[i].windSensitivity = windSensitivity;
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].angle = 0.0f;
+ m_particule[i].intensity = 1.0f;
+ m_particule[i].type = type;
+ m_particule[i].phase = PARPHSTART;
+ m_particule[i].texSup.x = 0.0f;
+ m_particule[i].texSup.y = 0.0f;
+ m_particule[i].texInf.x = 0.0f;
+ m_particule[i].texInf.y = 0.0f;
+ m_particule[i].time = 0.0f;
+ m_particule[i].phaseTime = 0.0f;
+ m_particule[i].testTime = 0.0f;
+ m_particule[i].trackRank = -1;
+
+ m_totalInterface[t][sheet] ++;
+
+ return i | ((m_particule[i].uniqueStamp&0xffff)<<16);
+ }
+ }
+
+ return -1;
+}
+
+// Créé une nouvelle particule linéaire (rayon).
+// Retourne le canal de la particule crée ou -1 en cas d'erreur.
+
+int CParticule::CreateRay(D3DVECTOR pos, D3DVECTOR goal,
+ ParticuleType type, FPOINT dim,
+ float duration, int sheet)
+{
+ int i, j, t;
+
+ t = -1;
+ if ( type == PARTIRAY1 ||
+ type == PARTIRAY2 ||
+ type == PARTIRAY3 ||
+ type == PARTIRAY4 )
+ {
+ t = 3; // effect02
+ }
+ if ( t >= MAXPARTITYPE ) return -1;
+ if ( t == -1 ) return -1;
+
+ for ( j=0 ; j<MAXPARTICULE ; j++ )
+ {
+ i = MAXPARTICULE*t+j;
+
+ if ( !m_particule[i].bUsed )
+ {
+ ZeroMemory(&m_particule[i], sizeof(Particule));
+ m_particule[i].bUsed = TRUE;
+ m_particule[i].bRay = TRUE;
+ m_particule[i].uniqueStamp = m_uniqueStamp++;
+ m_particule[i].sheet = sheet;
+ m_particule[i].mass = 0.0f;
+ m_particule[i].duration = duration;
+ m_particule[i].pos = pos;
+ m_particule[i].goal = goal;
+ m_particule[i].speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_particule[i].windSensitivity = 0.0f;
+ m_particule[i].dim = dim;
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].angle = 0.0f;
+ m_particule[i].intensity = 1.0f;
+ m_particule[i].type = type;
+ m_particule[i].phase = PARPHSTART;
+ m_particule[i].texSup.x = 0.0f;
+ m_particule[i].texSup.y = 0.0f;
+ m_particule[i].texInf.x = 0.0f;
+ m_particule[i].texInf.y = 0.0f;
+ m_particule[i].time = 0.0f;
+ m_particule[i].phaseTime = 0.0f;
+ m_particule[i].testTime = 0.0f;
+ m_particule[i].objLink = 0;
+ m_particule[i].objFather = 0;
+ m_particule[i].trackRank = -1;
+
+ m_totalInterface[t][sheet] ++;
+
+ return i | ((m_particule[i].uniqueStamp&0xffff)<<16);
+ }
+ }
+
+ return -1;
+}
+
+// Crée une particule avec une traînée.
+// "length" est la durée de la queue de la traînée (en secondes) !
+
+int CParticule::CreateTrack(D3DVECTOR pos, D3DVECTOR speed, FPOINT dim,
+ ParticuleType type, float duration, float mass,
+ float length, float width)
+{
+ int channel, rank, i;
+
+ // Crée la particule normale.
+ channel = CreateParticule(pos, speed, dim, type, duration, mass, 0.0f, 0);
+ if ( channel == -1 ) return -1;
+
+ // Cherche une traînée libre.
+ for ( i=0 ; i<MAXTRACK ; i++ )
+ {
+ if ( !m_track[i].bUsed ) // libre ?
+ {
+ rank = channel;
+ if ( !CheckChannel(rank) ) return -1;
+ m_particule[rank].trackRank = i;
+
+ m_track[i].bUsed = TRUE;
+ m_track[i].step = (length/duration)/MAXTRACKLEN;
+ m_track[i].last = 0.0f;
+ m_track[i].intensity = 1.0f;
+ m_track[i].width = width;
+ m_track[i].used = 1;
+ m_track[i].head = 0;
+ m_track[i].pos[0] = pos;
+ break;
+ }
+ }
+
+ return channel;
+}
+
+// Crée une trace de pneu.
+
+void CParticule::CreateWheelTrace(const D3DVECTOR &p1, const D3DVECTOR &p2,
+ const D3DVECTOR &p3, const D3DVECTOR &p4,
+ ParticuleType type)
+{
+ int i, max;
+
+//? max = (int)(m_engine->RetWheelTraceQuantity()*MAXWHEELTRACE);
+ max = MAXWHEELTRACE;
+ i = m_wheelTraceIndex++;
+ if ( m_wheelTraceIndex > max ) m_wheelTraceIndex = 0;
+
+ m_wheelTrace[i].type = type;
+ m_wheelTrace[i].pos[0] = p1; // ul
+ m_wheelTrace[i].pos[1] = p2; // dl
+ m_wheelTrace[i].pos[2] = p3; // ur
+ m_wheelTrace[i].pos[3] = p4; // dr
+ m_wheelTrace[i].startTime = m_absTime;
+
+ if ( m_terrain == 0 )
+ {
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ }
+
+ m_terrain->MoveOnFloor(m_wheelTrace[i].pos[0]);
+ m_wheelTrace[i].pos[0].y += 0.2f; // juste en dessus du sol
+
+ m_terrain->MoveOnFloor(m_wheelTrace[i].pos[1]);
+ m_wheelTrace[i].pos[1].y += 0.2f; // juste en dessus du sol
+
+ m_terrain->MoveOnFloor(m_wheelTrace[i].pos[2]);
+ m_wheelTrace[i].pos[2].y += 0.2f; // juste en dessus du sol
+
+ m_terrain->MoveOnFloor(m_wheelTrace[i].pos[3]);
+ m_wheelTrace[i].pos[3].y += 0.2f; // juste en dessus du sol
+
+ if ( m_wheelTraceTotal < max )
+ {
+ m_wheelTraceTotal ++;
+ }
+ else
+ {
+ m_wheelTraceTotal = max;
+ }
+}
+
+
+// Check un numéro de canal.
+// Adapte le canal pour qu'il puisse être utilisé comme offset
+// dans m_particule.
+
+BOOL CParticule::CheckChannel(int &channel)
+{
+ int uniqueStamp;
+
+ uniqueStamp = (channel>>16)&0xffff;
+ channel &= 0xffff;
+
+ if ( channel < 0 ) return FALSE;
+ if ( channel >= MAXPARTICULE*MAXPARTITYPE ) return FALSE;
+#if 0
+ if ( !m_particule[channel].bUsed ) return FALSE;
+
+ if ( m_particule[channel].uniqueStamp != uniqueStamp ) return FALSE;
+#else
+ if ( !m_particule[channel].bUsed )
+ {
+ OutputDebugString("CheckChannel bUsed=FALSE !\n");
+ return FALSE;
+ }
+
+ if ( m_particule[channel].uniqueStamp != uniqueStamp )
+ {
+ OutputDebugString("CheckChannel uniqueStamp !\n");
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+// Supprime une particule d'après son rang.
+
+void CParticule::DeleteRank(int rank)
+{
+ int i;
+
+ if ( m_totalInterface[rank/MAXPARTICULE][m_particule[rank].sheet] > 0 )
+ {
+ m_totalInterface[rank/MAXPARTICULE][m_particule[rank].sheet] --;
+ }
+
+ i = m_particule[rank].trackRank;
+ if ( i != -1 ) // traînée associée ?
+ {
+ m_track[i].bUsed = FALSE; // libère la traînée
+ }
+
+ m_particule[rank].bUsed = FALSE;
+}
+
+// Supprime toutes les particules d'un type donné.
+
+void CParticule::DeleteParticule(ParticuleType type)
+{
+ int i;
+
+ for ( i=0 ; i<MAXPARTICULE*MAXPARTITYPE ; i++ )
+ {
+ if ( !m_particule[i].bUsed ) continue;
+ if ( m_particule[i].type != type ) continue;
+
+ DeleteRank(i);
+ }
+}
+
+// Supprime une particule d'après son canal.
+
+void CParticule::DeleteParticule(int channel)
+{
+ int i;
+
+ if ( !CheckChannel(channel) ) return;
+
+ if ( m_totalInterface[channel/MAXPARTICULE][m_particule[channel].sheet] > 0 )
+ {
+ m_totalInterface[channel/MAXPARTICULE][m_particule[channel].sheet] --;
+ }
+
+ i = m_particule[channel].trackRank;
+ if ( i != -1 ) // traînée associée ?
+ {
+ m_track[i].bUsed = FALSE; // libère la traînée
+ }
+
+ m_particule[channel].bUsed = FALSE;
+}
+
+
+// Spécifie l'objet auquel la particule est liée.
+
+void CParticule::SetObjectLink(int channel, CObject *object)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].objLink = object;
+}
+
+// Spécifie l'objet père qui a créé la particule.
+
+void CParticule::SetObjectFather(int channel, CObject *object)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].objFather = object;
+}
+
+void CParticule::SetPosition(int channel, D3DVECTOR pos)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].pos = pos;
+}
+
+void CParticule::SetDimension(int channel, FPOINT dim)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].dim = dim;
+}
+
+void CParticule::SetZoom(int channel, float zoom)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].zoom = zoom;
+}
+
+void CParticule::SetAngle(int channel, float angle)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].angle = angle;
+}
+
+void CParticule::SetIntensity(int channel, float intensity)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].intensity = intensity;
+}
+
+void CParticule::SetParam(int channel, D3DVECTOR pos, FPOINT dim, float zoom,
+ float angle, float intensity)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].pos = pos;
+ m_particule[channel].dim = dim;
+ m_particule[channel].zoom = zoom;
+ m_particule[channel].angle = angle;
+ m_particule[channel].intensity = intensity;
+}
+
+void CParticule::SetPhase(int channel, ParticulePhase phase, float duration)
+{
+ if ( !CheckChannel(channel) ) return;
+ m_particule[channel].phase = phase;
+ m_particule[channel].duration = duration;
+ m_particule[channel].phaseTime = m_particule[channel].time;
+}
+
+// Retourne la position de la particule.
+
+BOOL CParticule::GetPosition(int channel, D3DVECTOR &pos)
+{
+ if ( !CheckChannel(channel) ) return FALSE;
+ pos = m_particule[channel].pos;
+ return TRUE;
+}
+
+
+// Indique si une feuille évolue ou non.
+
+void CParticule::SetFrameUpdate(int sheet, BOOL bUpdate)
+{
+ m_bFrameUpdate[sheet] = bUpdate;
+}
+
+// Fait évoluer toutes les particules.
+
+void CParticule::FrameParticule(float rTime)
+{
+ CObject* object;
+ D3DVECTOR eye, pos, speed, wind;
+ FPOINT ts, ti, dim;
+ BOOL bPause;
+ float progress, dp, h, duration, mass, amplitude;
+ int i, j, r, total;
+
+ if ( m_main == 0 )
+ {
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ }
+
+ bPause = ( m_engine->RetPause() && !m_main->RetInfoLock() );
+
+ if ( m_terrain == 0 )
+ {
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ }
+ if ( m_water == 0 )
+ {
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ }
+
+ if ( !bPause )
+ {
+ m_lastTimeGunDel += rTime;
+ m_absTime += rTime;
+ }
+
+ wind = m_terrain->RetWind();
+ eye = m_engine->RetEyePt();
+
+ for ( i=0 ; i<MAXPARTICULE*MAXPARTITYPE ; i++ )
+ {
+ if ( !m_particule[i].bUsed ) continue;
+ if ( !m_bFrameUpdate[m_particule[i].sheet] ) continue;
+
+ if ( m_particule[i].type != PARTISHOW )
+ {
+ if ( bPause && m_particule[i].sheet != SH_INTERFACE ) continue;
+ }
+
+ if ( m_particule[i].type != PARTIQUARTZ )
+ {
+ m_particule[i].pos += m_particule[i].speed*rTime;
+ }
+
+ if ( m_particule[i].sheet == SH_WORLD )
+ {
+ h = rTime*m_particule[i].windSensitivity*Rand()*2.0f;
+ m_particule[i].pos += wind*h;
+ }
+
+ progress = (m_particule[i].time-m_particule[i].phaseTime)/m_particule[i].duration;
+
+ // Gère les particules avec masse qui rebondissent.
+ if ( m_particule[i].mass != 0.0f &&
+ m_particule[i].type != PARTIQUARTZ )
+ {
+ m_particule[i].speed.y -= m_particule[i].mass*rTime;
+
+ if ( m_particule[i].sheet == SH_INTERFACE )
+ {
+ h = 0.0f;
+ }
+ else
+ {
+ h = m_terrain->RetFloorLevel(m_particule[i].pos, TRUE);
+ }
+ h += m_particule[i].dim.y*0.75f;
+ if ( m_particule[i].pos.y < h ) // choc avec le sol ?
+ {
+ if ( m_particule[i].type == PARTIPART &&
+ m_particule[i].weight > 3.0f && // assez lourd ?
+ m_particule[i].bounce < 3 )
+ {
+ amplitude = m_particule[i].weight*0.1f;
+ amplitude *= 1.0f-0.3f*m_particule[i].bounce;
+ if ( amplitude > 1.0f ) amplitude = 1.0f;
+ if ( amplitude > 0.0f )
+ {
+ Play(SOUND_BOUM, m_particule[i].pos, amplitude);
+ }
+ }
+
+ if ( m_particule[i].bounce < 3 )
+ {
+ m_particule[i].pos.y = h;
+ m_particule[i].speed.y *= -0.4f;
+ m_particule[i].speed.x *= 0.4f;
+ m_particule[i].speed.z *= 0.4f;
+ m_particule[i].bounce ++; // un choc de plus
+ }
+ else // disparaît après 3 rebonds ?
+ {
+ if ( m_particule[i].pos.y < h-10.0f ||
+ m_particule[i].time >= 20.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+ }
+ }
+ }
+
+ // Gère la traînée associée.
+ r = m_particule[i].trackRank;
+ if ( r != -1 ) // traînée existe ?
+ {
+ if ( TrackMove(r, m_particule[i].pos, progress) )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_track[r].bDrawParticule = (progress < 1.0f);
+ }
+
+ if ( m_particule[i].type == PARTITRACK1 ) // explosion technique ?
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.375f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK2 ) // jet bleu ?
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.500f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK3 ) // araignée ?
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.500f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK4 ) // explosion insecte ?
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.625f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK5 ) // derrick ?
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.750f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK6 ) // reset in/out ?
+ {
+ ts.x = 0.0f;
+ ts.y = 0.0f;
+ ti.x = 0.0f;
+ ti.y = 0.0f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK7 || // win-1 ?
+ m_particule[i].type == PARTITRACK8 || // win-2 ?
+ m_particule[i].type == PARTITRACK9 || // win-3 ?
+ m_particule[i].type == PARTITRACK10 ) // win-4 ?
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.25f*(m_particule[i].type-PARTITRACK7);
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK11 ) // tir phazer ?
+ {
+ object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather);
+ m_particule[i].goal = m_particule[i].pos;
+ if ( object != 0 )
+ {
+ if ( object->RetType() == OBJECT_MOTHER )
+ {
+ object->ExploObject(EXPLO_BOUM, 0.1f);
+ }
+ else
+ {
+ object->ExploObject(EXPLO_BOUM, 0.0f, RetDecay(object->RetType()));
+ }
+ }
+
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.375f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTITRACK12 ) // traînée réacteur ?
+ {
+ m_particule[i].zoom = 1.0f;
+
+ ts.x = 0.375f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIMOTOR )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.000f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIBLITZ )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+ m_particule[i].angle = Rand()*PI*2.0f;
+
+ ts.x = 0.125f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTICRASH )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+//? m_particule[i].intensity = 1.0f-progress;
+ if ( progress < 0.25f )
+ {
+ m_particule[i].zoom = progress/0.25f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f;
+ }
+
+//? ts.x = 0.250f;
+ ts.x = 0.000f;
+//? ts.x = 0.375f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIVAPOR )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].intensity = 1.0f-progress;
+ m_particule[i].zoom = 1.0f+progress*3.0f;
+
+ ts.x = 0.000f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIGAS )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+
+ ts.x = 0.375f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIBASE )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f+progress*7.0f;
+ m_particule[i].intensity = powf(1.0f-progress, 3.0f);
+
+ ts.x = 0.375f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIFIRE ||
+ m_particule[i].type == PARTIFIREZ )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].type == PARTIFIRE )
+ {
+ m_particule[i].zoom = 1.0f-progress;
+ }
+ else
+ {
+ m_particule[i].zoom = progress;
+ }
+
+ ts.x = 0.500f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIGUN1 ) // tir fireball ?
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].testTime >= 0.1f )
+ {
+ m_particule[i].testTime = 0.0f;
+
+ if ( m_terrain->RetFloorHeight(m_particule[i].pos, TRUE) < -2.0f )
+ {
+ m_exploGunCounter ++;
+
+ if ( m_exploGunCounter%2 == 0 )
+ {
+ pos = m_particule[i].goal;
+ m_terrain->MoveOnFloor(pos, TRUE);
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*6.0f+6.0f;
+ dim.y = dim.x;
+ duration = Rand()*1.0f+1.0f;
+ mass = 0.0f;
+ CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f);
+
+ pos.y += 1.0f;
+ total = (int)(2.0f*m_engine->RetParticuleDensity());
+ for ( j=0 ; j<total ; j++ )
+ {
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*20.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ duration = Rand()*1.0f+1.0f;
+ mass = Rand()*10.0f+15.0f;
+ CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f);
+ }
+ }
+
+ if ( m_exploGunCounter%4 == 0 )
+ {
+ Play(SOUND_EXPLOg1, pos, 0.5f);
+ }
+
+ DeleteRank(i);
+ continue;
+ }
+
+ object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather);
+ m_particule[i].goal = m_particule[i].pos;
+ if ( object != 0 )
+ {
+ object->ExploObject(EXPLO_BURN, 0.0f, RetDecay(object->RetType()));
+
+ m_exploGunCounter ++;
+
+ if ( m_exploGunCounter%2 == 0 )
+ {
+ pos = m_particule[i].pos;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*6.0f+6.0f;
+ dim.y = dim.x;
+ duration = Rand()*1.0f+1.0f;
+ mass = 0.0f;
+ CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f);
+
+ pos.y += 1.0f;
+ total = (int)(2.0f*m_engine->RetParticuleDensity());
+ for ( j=0 ; j<total ; j++ )
+ {
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*20.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ duration = Rand()*1.0f+1.0f;
+ mass = Rand()*10.0f+15.0f;
+ CreateParticule(pos, speed, dim, PARTIEXPLOG1, duration, mass, 1.0f);
+ }
+ }
+
+ if ( m_exploGunCounter%4 == 0 )
+ {
+ Play(SOUND_EXPLOg1, pos, 0.5f);
+ }
+
+ DeleteRank(i);
+ continue;
+ }
+ }
+
+ m_particule[i].angle -= rTime*PI*8.0f;
+ m_particule[i].zoom = 1.0f-progress;
+
+ ts.x = 0.00f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIGUN2 ) // tir fourmi ?
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].testTime >= 0.2f )
+ {
+ m_particule[i].testTime = 0.0f;
+ object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather);
+ m_particule[i].goal = m_particule[i].pos;
+ if ( object != 0 )
+ {
+ if ( object->RetShieldRadius() > 0.0f ) // protégé par bouclier ?
+ {
+ CreateParticule(m_particule[i].pos, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(6.0f, 6.0f), PARTIGUNDEL, 2.0f);
+ if ( m_lastTimeGunDel > 0.2f )
+ {
+ m_lastTimeGunDel = 0.0f;
+ Play(SOUND_GUNDEL, m_particule[i].pos, 1.0f);
+ }
+ DeleteRank(i);
+ continue;
+ }
+ else
+ {
+ if ( object->RetType() != OBJECT_HUMAN )
+ {
+ Play(SOUND_TOUCH, m_particule[i].pos, 1.0f);
+ }
+ object->ExploObject(EXPLO_BOUM, 0.0f); // démarre explosion
+ }
+ }
+ }
+
+ m_particule[i].angle = Rand()*PI*2.0f;
+ m_particule[i].zoom = 1.0f-progress;
+
+ ts.x = 0.125f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIGUN3 ) // suicide araignée ?
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].testTime >= 0.2f )
+ {
+ m_particule[i].testTime = 0.0f;
+ object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather);
+ m_particule[i].goal = m_particule[i].pos;
+ if ( object != 0 )
+ {
+ if ( object->RetShieldRadius() > 0.0f )
+ {
+ CreateParticule(m_particule[i].pos, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(6.0f, 6.0f), PARTIGUNDEL, 2.0f);
+ if ( m_lastTimeGunDel > 0.2f )
+ {
+ m_lastTimeGunDel = 0.0f;
+ Play(SOUND_GUNDEL, m_particule[i].pos, 1.0f);
+ }
+ DeleteRank(i);
+ continue;
+ }
+ else
+ {
+ object->ExploObject(EXPLO_BURN, 1.0f); // démarre explosion
+ }
+ }
+ }
+
+//? ts.x = 0.875f;
+//? ts.y = 0.750f;
+ ts.x = 0.500f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIGUN4 ) // tir orgaball ?
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].testTime >= 0.1f )
+ {
+ m_particule[i].testTime = 0.0f;
+
+ if ( m_terrain->RetFloorHeight(m_particule[i].pos, TRUE) < -2.0f )
+ {
+ m_exploGunCounter ++;
+
+ if ( m_exploGunCounter%2 == 0 )
+ {
+ pos = m_particule[i].goal;
+ m_terrain->MoveOnFloor(pos, TRUE);
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*4.0f+2.0f;
+ dim.y = dim.x;
+ duration = Rand()*0.7f+0.7f;
+ mass = 0.0f;
+ CreateParticule(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f);
+ }
+
+ if ( m_exploGunCounter%4 == 0 )
+ {
+ Play(SOUND_EXPLOg2, pos, 0.5f);
+ }
+
+ DeleteRank(i);
+ continue;
+ }
+
+ object = SearchObjectGun(m_particule[i].goal, m_particule[i].pos, m_particule[i].type, m_particule[i].objFather);
+ m_particule[i].goal = m_particule[i].pos;
+ if ( object != 0 )
+ {
+ object->ExploObject(EXPLO_BOUM, 0.0f, RetDecay(object->RetType()));
+
+ m_exploGunCounter ++;
+
+ if ( m_exploGunCounter%2 == 0 )
+ {
+ pos = m_particule[i].pos;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*4.0f+2.0f;
+ dim.y = dim.x;
+ duration = Rand()*0.7f+0.7f;
+ mass = 0.0f;
+ CreateParticule(pos, speed, dim, PARTIEXPLOG2, duration, mass, 1.0f);
+ }
+
+ if ( m_exploGunCounter%4 == 0 )
+ {
+ Play(SOUND_EXPLOg2, pos, 0.5f);
+ }
+
+ DeleteRank(i);
+ continue;
+ }
+ }
+
+ m_particule[i].angle = Rand()*PI*2.0f;
+ m_particule[i].zoom = 1.0f-progress;
+
+ ts.x = 0.125f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIFLIC )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 0.1f+progress;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.00f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTISHOW )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.5f ) m_particule[i].intensity = progress/0.5f;
+ else m_particule[i].intensity = 2.0f-progress/0.5f;
+ m_particule[i].zoom = 1.0f-progress*0.8f;
+ m_particule[i].angle -= rTime*PI*0.5f;
+
+ ts.x = 0.50f;
+ ts.y = 0.00f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTICHOC )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 0.1f+progress;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.50f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIGFLAT )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 0.1f+progress;
+ m_particule[i].intensity = 1.0f-progress;
+ m_particule[i].angle -= rTime*PI*2.0f;
+
+ ts.x = 0.00f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTILIMIT1 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].intensity = 1.0f;
+
+ ts.x = 0.000f;
+ ts.y = 0.125f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+ if ( m_particule[i].type == PARTILIMIT2 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].intensity = 1.0f;
+
+ ts.x = 0.375f;
+ ts.y = 0.125f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+ if ( m_particule[i].type == PARTILIMIT3 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].intensity = 1.0f;
+
+ ts.x = 0.500f;
+ ts.y = 0.125f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIFOG0 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.3f+sinf(progress)*0.15f;
+ m_particule[i].angle += rTime*0.05f;
+
+ ts.x = 0.25f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+ if ( m_particule[i].type == PARTIFOG1 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.3f+sinf(progress)*0.15f;
+ m_particule[i].angle -= rTime*0.07f;
+
+ ts.x = 0.25f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIFOG2 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.6f+sinf(progress)*0.15f;
+ m_particule[i].angle += rTime*0.05f;
+
+ ts.x = 0.75f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+ if ( m_particule[i].type == PARTIFOG3 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.6f+sinf(progress)*0.15f;
+ m_particule[i].angle -= rTime*0.07f;
+
+ ts.x = 0.75f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIFOG4 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.5f+sinf(progress)*0.2f;
+ m_particule[i].angle += rTime*0.05f;
+
+ ts.x = 0.00f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+ if ( m_particule[i].type == PARTIFOG5 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.5f+sinf(progress)*0.2f;
+ m_particule[i].angle -= rTime*0.07f;
+
+ ts.x = 0.00f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIFOG6 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.5f+sinf(progress)*0.2f;
+ m_particule[i].angle += rTime*0.05f;
+
+ ts.x = 0.50f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+ if ( m_particule[i].type == PARTIFOG7 )
+ {
+ m_particule[i].zoom = progress;
+ m_particule[i].intensity = 0.5f+sinf(progress)*0.2f;
+ m_particule[i].angle -= rTime*0.07f;
+
+ ts.x = 0.50f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ // Diminue l'intensité si la caméra est presque à la même
+ // hauteur (nappe de brouillard à hauteur des yeux).
+ if ( m_particule[i].type >= PARTIFOG0 &&
+ m_particule[i].type <= PARTIFOG9 )
+ {
+ h = 10.0f;
+
+ if ( m_particule[i].pos.y >= eye.y &&
+ m_particule[i].pos.y < eye.y+h )
+ {
+ m_particule[i].intensity *= (m_particule[i].pos.y-eye.y)/h;
+ }
+ if ( m_particule[i].pos.y > eye.y-h &&
+ m_particule[i].pos.y < eye.y )
+ {
+ m_particule[i].intensity *= (eye.y-m_particule[i].pos.y)/h;
+ }
+ }
+
+ if ( m_particule[i].type == PARTIEXPLOT ||
+ m_particule[i].type == PARTIEXPLOO )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress/2.0f;
+ m_particule[i].intensity = 1.0f-progress;
+
+ if ( m_particule[i].type == PARTIEXPLOT ) ts.x = 0.750f;
+ else ts.x = 0.875f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIEXPLOG1 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.375f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+ if ( m_particule[i].type == PARTIEXPLOG2 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.625f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIFLAME )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress/2.0f;
+ if ( progress < 0.5f )
+ {
+ m_particule[i].intensity = progress/0.5f;
+ }
+ else
+ {
+ m_particule[i].intensity = 2.0f-progress/0.5f;
+ }
+
+ ts.x = 0.750f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIBUBBLE )
+ {
+ if ( progress >= 1.0f ||
+ m_particule[i].pos.y >= m_water->RetLevel() )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress/2.0f;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.250f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTISMOKE1 ||
+ m_particule[i].type == PARTISMOKE2 ||
+ m_particule[i].type == PARTISMOKE3 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.25f )
+ {
+ m_particule[i].zoom = progress/0.25f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f;
+ }
+
+ ts.x = 0.500f+0.125f*(m_particule[i].type-PARTISMOKE1);
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIBLOOD )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.750f+(rand()%2)*0.125f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIBLOODM )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.875f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIVIRUS1 ||
+ m_particule[i].type == PARTIVIRUS2 ||
+ m_particule[i].type == PARTIVIRUS3 ||
+ m_particule[i].type == PARTIVIRUS4 ||
+ m_particule[i].type == PARTIVIRUS5 ||
+ m_particule[i].type == PARTIVIRUS6 ||
+ m_particule[i].type == PARTIVIRUS7 ||
+ m_particule[i].type == PARTIVIRUS8 ||
+ m_particule[i].type == PARTIVIRUS9 ||
+ m_particule[i].type == PARTIVIRUS10 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.25f )
+ {
+ m_particule[i].zoom = progress/0.25f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f;
+ }
+ m_particule[i].angle += rTime*PI*1.0f;
+
+ if ( m_particule[i].type == PARTIVIRUS1 ) // A ?
+ {
+ ts.x = 0.0f/256.0f; ts.y = 19.0f/256.0f;
+ ti.x = 10.0f/256.0f; ti.y = 30.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS2 ) // C ?
+ {
+ ts.x = 19.0f/256.0f; ts.y = 19.0f/256.0f;
+ ti.x = 28.0f/256.0f; ti.y = 30.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS3 ) // E ?
+ {
+ ts.x = 36.0f/256.0f; ts.y = 19.0f/256.0f;
+ ti.x = 45.0f/256.0f; ti.y = 30.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS4 ) // N ?
+ {
+ ts.x = 110.0f/256.0f; ts.y = 19.0f/256.0f;
+ ti.x = 120.0f/256.0f; ti.y = 30.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS5 ) // R ?
+ {
+ ts.x = 148.0f/256.0f; ts.y = 19.0f/256.0f;
+ ti.x = 158.0f/256.0f; ti.y = 30.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS6 ) // T ?
+ {
+ ts.x = 166.0f/256.0f; ts.y = 19.0f/256.0f;
+ ti.x = 175.0f/256.0f; ti.y = 30.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS7 ) // 0 ?
+ {
+ ts.x = 90.0f/256.0f; ts.y = 2.0f/256.0f;
+ ti.x = 98.0f/256.0f; ti.y = 13.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS8 ) // 2 ?
+ {
+ ts.x = 103.0f/256.0f; ts.y = 2.0f/256.0f;
+ ti.x = 111.0f/256.0f; ti.y = 13.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS9 ) // 5 ?
+ {
+ ts.x = 125.0f/256.0f; ts.y = 2.0f/256.0f;
+ ti.x = 132.0f/256.0f; ti.y = 13.0f/256.0f;
+ }
+ if ( m_particule[i].type == PARTIVIRUS10 ) // 9 ?
+ {
+ ts.x = 153.0f/256.0f; ts.y = 2.0f/256.0f;
+ ti.x = 161.0f/256.0f; ti.y = 13.0f/256.0f;
+ }
+ }
+
+ if ( m_particule[i].type == PARTIBLUE )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+
+ ts.x = 0.625f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIROOT )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.25f )
+ {
+ m_particule[i].zoom = progress/0.25f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f;
+ }
+
+ ts.x = 0.000f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIRECOVER )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.25f )
+ {
+ m_particule[i].zoom = progress/0.25f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.25f)/0.75f;
+ }
+
+ ts.x = 0.875f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIEJECT )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f+powf(progress, 2.0f)*5.0f;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.625f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTISCRAPS )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+
+ ts.x = 0.625f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIFRAG )
+ {
+ m_particule[i].angle += rTime*PI*0.5f;
+
+ ts.x = 0.0f;
+ ts.y = 0.0f;
+ ti.x = 0.0f;
+ ti.y = 0.0f;
+ }
+
+ if ( m_particule[i].type == PARTIPART )
+ {
+ ts.x = 0.0f;
+ ts.y = 0.0f;
+ ti.x = 0.0f;
+ ti.y = 0.0f;
+ }
+
+ if ( m_particule[i].type == PARTIQUEUE )
+ {
+ if ( m_particule[i].testTime >= 0.05f )
+ {
+ m_particule[i].testTime = 0.0f;
+
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+
+ pos = m_particule[i].pos;
+//? speed = -m_particule[i].speed*0.5f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 1.0f*(Rand()*0.8f+0.6f);
+ dim.y = dim.x;
+ CreateParticule(pos, speed, dim, PARTIGAS, 0.5f);
+ }
+
+ ts.x = 0.375f;
+ ts.y = 0.750f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIORGANIC1 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+
+ pos = m_particule[i].pos;
+ dim.x = m_particule[i].dim.x/4.0f;
+ dim.y = dim.x;
+ duration = m_particule[i].duration;
+ mass = m_particule[i].mass;
+ total = (int)(10.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<total ; i++ )
+ {
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.y = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ CreateParticule(pos, speed, dim, PARTIORGANIC2, duration, mass);
+ }
+ total = (int)(5.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<total ; i++ )
+ {
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.y = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ duration *= Rand()+0.8f;
+ CreateTrack(pos, speed, dim, PARTITRACK4, duration, mass, duration*0.2f, dim.x*2.0f);
+ }
+ continue;
+ }
+
+ m_particule[i].zoom = (m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.125f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIORGANIC2 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration);
+
+ ts.x = 0.125f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIGLINT )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress > 0.5f )
+ {
+//? m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration/2.0f);
+ m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f;
+ }
+ m_particule[i].angle = m_particule[i].time*PI;
+
+ ts.x = 0.75f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIGLINTb )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress > 0.5f )
+ {
+ m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f;
+ }
+ m_particule[i].angle = m_particule[i].time*PI;
+
+ ts.x = 0.75f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIGLINTr )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress > 0.5f )
+ {
+ m_particule[i].zoom = 1.0f-(progress-0.5f)*2.0f;
+ }
+ m_particule[i].angle = m_particule[i].time*PI;
+
+ ts.x = 0.75f;
+ ts.y = 0.00f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type >= PARTILENS1 &&
+ m_particule[i].type <= PARTILENS4 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.5f )
+ {
+ m_particule[i].zoom = progress*2.0f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.5f)*2.0f;
+ }
+//? m_particule[i].angle = m_particule[i].time*PI;
+
+ ts.x = 0.25f*(m_particule[i].type-PARTILENS1);
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTICONTROL )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.3f )
+ {
+ m_particule[i].zoom = progress/0.3f;
+ }
+ else
+ {
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].intensity = 1.0f-(progress-0.3f)/0.7f;
+ }
+
+ ts.x = 0.00f;
+ ts.y = 0.00f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIGUNDEL )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress > 0.5f )
+ {
+ m_particule[i].zoom = 1.0f-(m_particule[i].time-m_particule[i].duration/2.0f);
+ }
+ m_particule[i].angle = m_particule[i].time*PI;
+
+ ts.x = 0.75f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIQUARTZ )
+ {
+ if ( progress >= 1.0f )
+ {
+ m_particule[i].time = 0.0f;
+ m_particule[i].duration = 0.5f+Rand()*2.0f;
+ m_particule[i].pos.x = m_particule[i].speed.x + (Rand()-0.5f)*m_particule[i].mass;
+ m_particule[i].pos.y = m_particule[i].speed.y + (Rand()-0.5f)*m_particule[i].mass;
+ m_particule[i].pos.z = m_particule[i].speed.z + (Rand()-0.5f)*m_particule[i].mass;
+ m_particule[i].dim.x = 0.5f+Rand()*1.5f;
+ m_particule[i].dim.y = m_particule[i].dim.x;
+ progress = 0.0f;
+ }
+
+ if ( progress < 0.2f )
+ {
+ m_particule[i].zoom = progress/0.2f;
+ m_particule[i].intensity = 1.0f;
+ }
+ else
+ {
+ m_particule[i].zoom = 1.0f;
+ m_particule[i].intensity = 1.0f-(progress-0.2f)/0.8f;
+ }
+
+ ts.x = 0.25f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTITOTO )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+ if ( progress < 0.15f )
+ {
+ m_particule[i].intensity = progress/0.15f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.15f)/0.85f;
+ }
+ m_particule[i].intensity *= 0.5f;
+
+ ts.x = 0.25f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIERROR )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = progress*1.0f;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.500f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIWARNING )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = progress*1.0f;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.875f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIINFO )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = progress*1.0f;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.750f;
+ ts.y = 0.875f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTISELY )
+ {
+ ts.x = 0.75f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+ if ( m_particule[i].type == PARTISELR )
+ {
+ ts.x = 0.75f;
+ ts.y = 0.00f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE0 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = progress*m_particule[i].dim.x;
+//? m_particule[i].intensity = 1.0f-progress;
+ if ( progress < 0.65f )
+ {
+ m_particule[i].intensity = progress/0.65f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.65f)/0.35f;
+ }
+ m_particule[i].intensity *= 0.5f;
+
+ ts.x = 0.50f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE1 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.30f )
+ {
+ m_particule[i].intensity = progress/0.30f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.30f)/0.70f;
+ }
+ m_particule[i].zoom = progress*m_particule[i].dim.x;
+ m_particule[i].angle = m_particule[i].time*PI*2.0f;
+
+ ts.x = 0.000f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE2 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( progress < 0.20f )
+ {
+ m_particule[i].intensity = 1.0f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.20f)/0.80f;
+ }
+ m_particule[i].zoom = progress*m_particule[i].dim.x;
+ m_particule[i].angle = m_particule[i].time*PI*2.0f;
+
+ ts.x = 0.125f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE3 )
+ {
+ if ( m_particule[i].phase == PARPHEND &&
+ progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].phase == PARPHSTART )
+ {
+ m_particule[i].intensity = progress;
+ if ( m_particule[i].intensity > 1.0f )
+ {
+ m_particule[i].intensity = 1.0f;
+ }
+ }
+
+ if ( m_particule[i].phase == PARPHEND )
+ {
+ m_particule[i].intensity = 1.0f-progress;
+ }
+
+ m_particule[i].zoom = m_particule[i].dim.x;
+ m_particule[i].angle = m_particule[i].time*PI*0.2f;
+
+ ts.x = 0.25f;
+ ts.y = 0.75f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE4 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = progress*m_particule[i].dim.x;
+ if ( progress < 0.65f )
+ {
+ m_particule[i].intensity = progress/0.65f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.65f)/0.35f;
+ }
+ m_particule[i].intensity *= 0.5f;
+
+ ts.x = 0.125f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE5 )
+ {
+ m_particule[i].intensity = 0.7f+sinf(progress)*0.3f;
+ m_particule[i].zoom = m_particule[i].dim.x*(1.0f+sinf(progress*0.7f)*0.01f);
+ m_particule[i].angle = m_particule[i].time*PI*0.2f;
+
+ ts.x = 0.25f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTISPHERE6 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = (1.0f-progress)*m_particule[i].dim.x;
+ m_particule[i].intensity = progress*0.5f;
+
+ ts.x = 0.125f;
+ ts.y = 0.000f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIPLOUF0 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = progress;
+#if 0
+ if ( progress <= 0.5f )
+ {
+ m_particule[i].intensity = 1.0f;
+ }
+ else
+ {
+ m_particule[i].intensity = 1.0f-(progress-0.5f)/0.5f;
+ }
+#else
+//? m_particule[i].intensity = 1.0f;
+ m_particule[i].intensity = 1.0f-progress;
+#endif
+
+ ts.x = 0.50f;
+ ts.y = 0.50f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIDROP )
+ {
+ if ( progress >= 1.0f ||
+ m_particule[i].pos.y < m_water->RetLevel() )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].zoom = 1.0f-progress;
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.750f;
+ ts.y = 0.500f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIWATER )
+ {
+ if ( progress >= 1.0f ||
+ m_particule[i].pos.y < m_water->RetLevel() )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ m_particule[i].intensity = 1.0f-progress;
+
+ ts.x = 0.125f;
+ ts.y = 0.125f;
+ ti.x = ts.x+0.125f;
+ ti.y = ts.y+0.125f;
+ }
+
+ if ( m_particule[i].type == PARTIRAY1 ) // rayon tour ?
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ if ( m_particule[i].testTime >= 0.2f )
+ {
+ m_particule[i].testTime = 0.0f;
+ object = SearchObjectRay(m_particule[i].pos, m_particule[i].goal,
+ m_particule[i].type, m_particule[i].objFather);
+ if ( object != 0 )
+ {
+ object->ExploObject(EXPLO_BOUM, 0.0f);
+ }
+ }
+
+ ts.x = 0.00f;
+ ts.y = 0.00f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ if ( m_particule[i].type == PARTIRAY2 ||
+ m_particule[i].type == PARTIRAY3 )
+ {
+ if ( progress >= 1.0f )
+ {
+ DeleteRank(i);
+ continue;
+ }
+
+ ts.x = 0.00f;
+ ts.y = 0.25f;
+ ti.x = ts.x+0.25f;
+ ti.y = ts.y+0.25f;
+ }
+
+ dp = (1.0f/256.0f)/2.0f;
+ m_particule[i].texSup.x = ts.x+dp;
+ m_particule[i].texSup.y = ts.y+dp;
+ m_particule[i].texInf.x = ti.x-dp;
+ m_particule[i].texInf.y = ti.y-dp;
+ m_particule[i].time += rTime;
+ m_particule[i].testTime += rTime;
+ }
+}
+
+
+// Déplace une traînée.
+// Retourne TRUE lorsque la traînée est terminée.
+
+BOOL CParticule::TrackMove(int i, D3DVECTOR pos, float progress)
+{
+ D3DVECTOR last;
+ int h, hh;
+
+ if ( i < 0 || i >= MAXTRACK ) return TRUE;
+ if ( m_track[i].bUsed == FALSE ) return TRUE;
+
+ if ( progress < 1.0f ) // particule existe ?
+ {
+ h = m_track[i].head;
+
+ if ( m_track[i].used == 1 ||
+ m_track[i].last+m_track[i].step <= progress )
+ {
+ m_track[i].last = progress;
+ last = m_track[i].pos[h];
+ h ++;
+ if ( h == MAXTRACKLEN ) h = 0;
+ if ( m_track[i].used < MAXTRACKLEN ) m_track[i].used ++;
+ }
+ else
+ {
+ hh = h-1;
+ if ( hh < 0 ) hh = MAXTRACKLEN-1;
+ last = m_track[i].pos[hh];
+ }
+ m_track[i].pos[h] = pos;
+ m_track[i].len[h] = Length(pos, last);
+
+ m_track[i].head = h;
+
+//? m_track[i].intensity = 1.0f;
+ m_track[i].intensity = 1.0f-progress;
+ }
+ else // mort lente de la traînée ?
+ {
+//? m_track[i].intensity = 1.0f-(progress-1.0f)/(m_track[i].step*MAXTRACKLEN);
+ m_track[i].intensity = 0.0f;
+ }
+
+ return (m_track[i].intensity <= 0.0f);
+}
+
+// Dessine une traînée.
+
+void CParticule::TrackDraw(int i, ParticuleType type)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR corner[4], p1, p2, p, n, eye;
+ D3DMATRIX matrix;
+ FPOINT texInf, texSup, rot;
+ float lTotal, f1, f2, a;
+ int counter, h;
+
+ // Calcule la longueur totale mémorisée.
+ lTotal = 0.0f;
+ h = m_track[i].head;
+ for ( counter=0 ; counter<m_track[i].used-1 ; counter++ )
+ {
+ lTotal += m_track[i].len[h];
+ h --; if ( h < 0 ) h = MAXTRACKLEN-1;
+ }
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ if ( type == PARTITRACK1 ) // explosion technique ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 21.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 22.0f/256.0f; // orange
+ }
+ if ( type == PARTITRACK2 ) // jet bleu ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 13.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 14.0f/256.0f; // bleu
+ }
+ if ( type == PARTITRACK3 ) // araignée ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 5.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 6.0f/256.0f; // brun
+ }
+ if ( type == PARTITRACK4 ) // explosion insecte ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 9.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 10.0f/256.0f; // vert foncé
+ }
+ if ( type == PARTITRACK5 ) // derrick ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 29.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 30.0f/256.0f; // brun foncé
+ }
+ if ( type == PARTITRACK6 ) // reset in/out ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 17.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 18.0f/256.0f; // cyan
+ }
+ if ( type == PARTITRACK7 ) // win-1 ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 41.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 42.0f/256.0f; // orange
+ }
+ if ( type == PARTITRACK8 ) // win-2 ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 45.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 46.0f/256.0f; // jaune
+ }
+ if ( type == PARTITRACK9 ) // win-3 ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 49.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 50.0f/256.0f; // rouge
+ }
+ if ( type == PARTITRACK10 ) // win-4 ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 53.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 54.0f/256.0f; // violet
+ }
+ if ( type == PARTITRACK11 ) // tir phazer ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 21.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 22.0f/256.0f; // orange
+ }
+ if ( type == PARTITRACK12 ) // traînée réacteur ?
+ {
+ texInf.x = 64.5f/256.0f;
+ texInf.y = 21.0f/256.0f;
+ texSup.x = 95.5f/256.0f;
+ texSup.y = 22.0f/256.0f; // orange
+ }
+
+ h = m_track[i].head;
+ p1 = m_track[i].pos[h];
+ f1 = m_track[i].intensity;
+
+ eye = m_engine->RetEyePt();
+ a = RotateAngle(eye.x-p1.x, eye.z-p1.z);
+
+ for ( counter=0 ; counter<m_track[i].used-1 ; counter++ )
+ {
+ f2 = f1-(m_track[i].len[h]/lTotal);
+ if ( f2 < 0.0f ) f2 = 0.0f;
+ h --; if ( h < 0 ) h = MAXTRACKLEN-1;
+ p2 = m_track[i].pos[h];
+
+ n = Normalize(p1-eye);
+
+ p = p1;
+ p.x += f1*m_track[i].width;
+ rot = RotatePoint(FPOINT(p1.x, p1.z), a+PI/2.0f, FPOINT(p.x, p.z));
+ corner[0].x = rot.x;
+ corner[0].y = p1.y;
+ corner[0].z = rot.y;
+ rot = RotatePoint(FPOINT(p1.x, p1.z), a-PI/2.0f, FPOINT(p.x, p.z));
+ corner[1].x = rot.x;
+ corner[1].y = p1.y;
+ corner[1].z = rot.y;
+
+ p = p2;
+ p.x += f2*m_track[i].width;
+ rot = RotatePoint(FPOINT(p2.x, p2.z), a+PI/2.0f, FPOINT(p.x, p.z));
+ corner[2].x = rot.x;
+ corner[2].y = p2.y;
+ corner[2].z = rot.y;
+ rot = RotatePoint(FPOINT(p2.x, p2.z), a-PI/2.0f, FPOINT(p.x, p.z));
+ corner[3].x = rot.x;
+ corner[3].y = p2.y;
+ corner[3].z = rot.y;
+
+ if ( p2.y < p1.y )
+ {
+ vertex[0] = D3DVERTEX2(corner[1], n, texSup.x, texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, texInf.x, texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, texSup.x, texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, texInf.x, texInf.y);
+ }
+ else
+ {
+ vertex[0] = D3DVERTEX2(corner[0], n, texSup.x, texSup.y);
+ vertex[1] = D3DVERTEX2(corner[1], n, texInf.x, texSup.y);
+ vertex[2] = D3DVERTEX2(corner[2], n, texSup.x, texInf.y);
+ vertex[3] = D3DVERTEX2(corner[3], n, texInf.x, texInf.y);
+ }
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+ if ( f2 < 0.0f ) break;
+ f1 = f2;
+ p1 = p2;
+ }
+}
+
+// Dessine une particule triangulaire.
+
+void CParticule::DrawParticuleTriangle(int i)
+{
+ CObject* object;
+ D3DMATRIX matrix;
+ D3DVECTOR eye, pos, angle;
+
+ if ( m_particule[i].zoom == 0.0f ) return;
+
+ eye = m_engine->RetEyePt();
+ pos = m_particule[i].pos;
+
+ object = m_particule[i].objLink;
+ if ( object != 0 )
+ {
+ pos += object->RetPosition(0);
+ }
+
+ angle.x = -RotateAngle(Length2d(pos, eye), pos.y-eye.y);
+ angle.y = RotateAngle(pos.z-eye.z, pos.x-eye.x);
+ angle.z = m_particule[i].angle;
+
+ MatRotateXZY(matrix, angle);
+ matrix._41 = pos.x;
+ matrix._42 = pos.y;
+ matrix._43 = pos.z;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, D3DFVF_VERTEX2,
+ m_triangle[i].triangle, 3, NULL);
+ m_engine->AddStatisticTriangle(1);
+}
+
+// Dessine une particule normale.
+
+void CParticule::DrawParticuleNorm(int i)
+{
+ CObject* object;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DMATRIX matrix;
+ D3DVECTOR corner[4], eye, pos, n, angle;
+ FPOINT dim;
+ float zoom;
+
+ zoom = m_particule[i].zoom;
+ if ( !m_engine->RetStateColor() && m_particule[i].intensity < 0.5f )
+ {
+ zoom *= m_particule[i].intensity/0.5f;
+ }
+
+ if ( zoom == 0.0f ) return;
+ if ( m_particule[i].intensity == 0.0f ) return;
+
+ if ( m_particule[i].sheet == SH_INTERFACE )
+ {
+ pos = m_particule[i].pos;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f);
+
+ dim.x = m_particule[i].dim.x * zoom;
+ dim.y = m_particule[i].dim.y * zoom;
+
+ corner[0].x = pos.x+dim.x;
+ corner[0].y = pos.y+dim.y;
+ corner[0].z = 0.0f;
+
+ corner[1].x = pos.x-dim.x;
+ corner[1].y = pos.y+dim.y;
+ corner[1].z = 0.0f;
+
+ corner[2].x = pos.x+dim.x;
+ corner[2].y = pos.y-dim.y;
+ corner[2].z = 0.0f;
+
+ corner[3].x = pos.x-dim.x;
+ corner[3].y = pos.y-dim.y;
+ corner[3].z = 0.0f;
+
+ vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+ }
+ else
+ {
+ eye = m_engine->RetEyePt();
+ pos = m_particule[i].pos;
+
+ object = m_particule[i].objLink;
+ if ( object != 0 )
+ {
+ pos += object->RetPosition(0);
+ }
+
+ angle.x = -RotateAngle(Length2d(pos, eye), pos.y-eye.y);
+ angle.y = RotateAngle(pos.z-eye.z, pos.x-eye.x);
+ angle.z = m_particule[i].angle;
+
+ MatRotateXZY(matrix, angle);
+ matrix._41 = pos.x;
+ matrix._42 = pos.y;
+ matrix._43 = pos.z;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f);
+
+ dim.x = m_particule[i].dim.x * zoom;
+ dim.y = m_particule[i].dim.y * zoom;
+
+ corner[0].x = dim.x;
+ corner[0].y = dim.y;
+ corner[0].z = 0.0f;
+
+ corner[1].x = -dim.x;
+ corner[1].y = dim.y;
+ corner[1].z = 0.0f;
+
+ corner[2].x = dim.x;
+ corner[2].y = -dim.y;
+ corner[2].z = 0.0f;
+
+ corner[3].x = -dim.x;
+ corner[3].y = -dim.y;
+ corner[3].z = 0.0f;
+
+ vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+ }
+}
+
+// Dessine une particule plate (horizontale).
+
+void CParticule::DrawParticuleFlat(int i)
+{
+ CObject* object;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DMATRIX matrix;
+ D3DVECTOR corner[4], pos, n, angle, eye;
+ FPOINT dim;
+
+ if ( m_particule[i].zoom == 0.0f ) return;
+ if ( m_particule[i].intensity == 0.0f ) return;
+
+ pos = m_particule[i].pos;
+
+ object = m_particule[i].objLink;
+ if ( object != 0 )
+ {
+ pos += object->RetPosition(0);
+ }
+
+ angle.x = PI/2.0f;
+ angle.y = 0.0f;
+ angle.z = m_particule[i].angle;
+
+#if 0
+ if ( m_engine->RetRankView() == 1 ) // sous l'eau ?
+ {
+ angle.x = -PI/2.0f;
+ pos.y -= 1.0f;
+ }
+#else
+ if ( m_engine->RetRankView() == 1 ) // sous l'eau ?
+ {
+ pos.y -= 1.0f;
+ }
+
+ eye = m_engine->RetEyePt();
+ if ( pos.y > eye.y ) // vu par en-dessous ?
+ {
+ angle.x = -PI/2.0f;
+ }
+#endif
+
+ MatRotateXZY(matrix, angle);
+ matrix._41 = pos.x;
+ matrix._42 = pos.y;
+ matrix._43 = pos.z;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f);
+
+ dim.x = m_particule[i].dim.x * m_particule[i].zoom;
+ dim.y = m_particule[i].dim.y * m_particule[i].zoom;
+
+ corner[0].x = dim.x;
+ corner[0].y = dim.y;
+ corner[0].z = 0.0f;
+
+ corner[1].x = -dim.x;
+ corner[1].y = dim.y;
+ corner[1].z = 0.0f;
+
+ corner[2].x = dim.x;
+ corner[2].y = -dim.y;
+ corner[2].z = 0.0f;
+
+ corner[3].x = -dim.x;
+ corner[3].y = -dim.y;
+ corner[3].z = 0.0f;
+
+ vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+}
+
+// Dessine une particule plate pour faire une nappe de brouillard.
+
+void CParticule::DrawParticuleFog(int i)
+{
+ CObject* object;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DMATRIX matrix;
+ D3DVECTOR corner[4], pos, n, angle, eye;
+ FPOINT dim, zoom;
+
+ if ( !m_engine->RetFog() ) return;
+ if ( m_particule[i].intensity == 0.0f ) return;
+
+ pos = m_particule[i].pos;
+
+ dim.x = m_particule[i].dim.x;
+ dim.y = m_particule[i].dim.y;
+
+ if ( m_particule[i].type == PARTIFOG0 ||
+ m_particule[i].type == PARTIFOG2 ||
+ m_particule[i].type == PARTIFOG4 ||
+ m_particule[i].type == PARTIFOG6 )
+ {
+//? pos.x += sinf(m_particule[i].zoom*1.2f)*dim.x*0.1f;
+//? pos.y += cosf(m_particule[i].zoom*1.5f)*dim.y*0.1f;
+ zoom.x = 1.0f+sinf(m_particule[i].zoom*2.0f)/6.0f;
+ zoom.y = 1.0f+cosf(m_particule[i].zoom*2.7f)/6.0f;
+ }
+ if ( m_particule[i].type == PARTIFOG1 ||
+ m_particule[i].type == PARTIFOG3 ||
+ m_particule[i].type == PARTIFOG5 ||
+ m_particule[i].type == PARTIFOG7 )
+ {
+//? pos.x += sinf(m_particule[i].zoom*1.0f)*dim.x*0.1f;
+//? pos.y += cosf(m_particule[i].zoom*1.3f)*dim.y*0.1f;
+ zoom.x = 1.0f+sinf(m_particule[i].zoom*3.0f)/6.0f;
+ zoom.y = 1.0f+cosf(m_particule[i].zoom*3.7f)/6.0f;
+ }
+
+ dim.x *= zoom.x;
+ dim.y *= zoom.y;
+
+ object = m_particule[i].objLink;
+ if ( object != 0 )
+ {
+ pos += object->RetPosition(0);
+ }
+
+ angle.x = PI/2.0f;
+ angle.y = 0.0f;
+ angle.z = m_particule[i].angle;
+
+ if ( m_engine->RetRankView() == 1 ) // sous l'eau ?
+ {
+ pos.y -= 1.0f;
+ }
+
+ eye = m_engine->RetEyePt();
+ if ( pos.y > eye.y ) // vu par en-dessous ?
+ {
+ angle.x = -PI/2.0f;
+ }
+
+ MatRotateXZY(matrix, angle);
+ matrix._41 = pos.x;
+ matrix._42 = pos.y;
+ matrix._43 = pos.z;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f);
+
+ corner[0].x = dim.x;
+ corner[0].y = dim.y;
+ corner[0].z = 0.0f;
+
+ corner[1].x = -dim.x;
+ corner[1].y = dim.y;
+ corner[1].z = 0.0f;
+
+ corner[2].x = dim.x;
+ corner[2].y = -dim.y;
+ corner[2].z = 0.0f;
+
+ corner[3].x = -dim.x;
+ corner[3].y = -dim.y;
+ corner[3].z = 0.0f;
+
+ vertex[0] = D3DVERTEX2(corner[1], n, m_particule[i].texSup.x, m_particule[i].texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, m_particule[i].texInf.x, m_particule[i].texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, m_particule[i].texSup.x, m_particule[i].texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, m_particule[i].texInf.x, m_particule[i].texInf.y);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+}
+
+// Dessine une particule sous forme de rayon.
+
+void CParticule::DrawParticuleRay(int i)
+{
+ CObject* object;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DMATRIX matrix;
+ D3DVECTOR corner[4], eye, pos, goal, n, angle, proj;
+ FPOINT dim, texInf, texSup;
+ BOOL bLeft;
+ float a, len, adv, prop, vario1, vario2;
+ int r, rank, step, first, last;
+
+ if ( m_particule[i].zoom == 0.0f ) return;
+ if ( m_particule[i].intensity == 0.0f ) return;
+
+ eye = m_engine->RetEyePt();
+ pos = m_particule[i].pos;
+ goal = m_particule[i].goal;
+
+ object = m_particule[i].objLink;
+ if ( object != 0 )
+ {
+ pos += object->RetPosition(0);
+ }
+
+ a = RotateAngle(FPOINT(pos.x,pos.z), FPOINT(goal.x,goal.z), FPOINT(eye.x,eye.z));
+ bLeft = (a < PI);
+
+ proj = Projection(pos, goal, eye);
+ angle.x = -RotateAngle(Length2d(proj, eye), proj.y-eye.y);
+ angle.y = RotateAngle(pos.z-goal.z, pos.x-goal.x)+PI/2.0f;
+ angle.z = -RotateAngle(Length2d(pos, goal), pos.y-goal.y);
+ if ( bLeft ) angle.x = -angle.x;
+
+ MatRotateZXY(matrix, angle);
+ matrix._41 = pos.x;
+ matrix._42 = pos.y;
+ matrix._43 = pos.z;
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ n = D3DVECTOR(0.0f, 0.0f, bLeft?1.0f:-1.0f);
+
+ dim.x = m_particule[i].dim.x * m_particule[i].zoom;
+ dim.y = m_particule[i].dim.y * m_particule[i].zoom;
+
+ if ( bLeft ) dim.y = -dim.y;
+
+ len = Length(pos, goal);
+ adv = 0.0f;
+
+ step = (int)(len/(dim.x*2.0f))+1;
+
+ if ( step == 1 )
+ {
+ vario1 = 1.0f;
+ vario2 = 1.0f;
+ }
+ else
+ {
+ vario1 = 0.0f;
+ vario2 = 2.0f;
+ }
+
+ if ( m_particule[i].type == PARTIRAY2 )
+ {
+ first = 0;
+ last = step;
+ vario1 = 0.0f;
+ vario2 = 0.0f;
+ }
+ else if ( m_particule[i].type == PARTIRAY3 )
+ {
+ if ( m_particule[i].time < m_particule[i].duration*0.40f )
+ {
+ prop = m_particule[i].time / (m_particule[i].duration*0.40f);
+ first = 0;
+ last = (int)(prop*step);
+ }
+ else if ( m_particule[i].time < m_particule[i].duration*0.60f )
+ {
+ first = 0;
+ last = step;
+ }
+ else
+ {
+ prop = (m_particule[i].time-m_particule[i].duration*0.60f) / (m_particule[i].duration*0.40f);
+ first = (int)(prop*step);
+ last = step;
+ }
+ }
+ else
+ {
+ if ( m_particule[i].time < m_particule[i].duration*0.50f )
+ {
+ prop = m_particule[i].time / (m_particule[i].duration*0.50f);
+ first = 0;
+ last = (int)(prop*step);
+ }
+ else if ( m_particule[i].time < m_particule[i].duration*0.75f )
+ {
+ first = 0;
+ last = step;
+ }
+ else
+ {
+ prop = (m_particule[i].time-m_particule[i].duration*0.75f) / (m_particule[i].duration*0.25f);
+ first = (int)(prop*step);
+ last = step;
+ }
+ }
+
+ corner[0].x = adv;
+ corner[2].x = adv;
+ corner[0].y = dim.y;
+ corner[2].y = -dim.y;
+ corner[0].z = (Rand()-0.5f)*vario1;
+ corner[1].z = (Rand()-0.5f)*vario1;
+ corner[2].z = (Rand()-0.5f)*vario1;
+ corner[3].z = (Rand()-0.5f)*vario1;
+
+ for ( rank=0 ; rank<step ; rank++ )
+ {
+ corner[1].x = corner[0].x;
+ corner[3].x = corner[2].x;
+ corner[0].x = adv+dim.x*2.0f+(Rand()-0.5f)*vario2;
+ corner[2].x = adv+dim.x*2.0f+(Rand()-0.5f)*vario2;
+
+ corner[1].y = corner[0].y;
+ corner[3].y = corner[2].y;
+ corner[0].y = dim.y+(Rand()-0.5f)*vario2;
+ corner[2].y = -dim.y+(Rand()-0.5f)*vario2;
+
+ if ( rank >= first && rank <= last )
+ {
+#if 1
+ texInf = m_particule[i].texInf;
+ texSup = m_particule[i].texSup;
+
+ r = rand()%16;
+ texInf.x += 0.25f*(r/4);
+ texSup.x += 0.25f*(r/4);
+ if ( r%2 < 1 && adv > 0.0f && m_particule[i].type != PARTIRAY1 )
+ {
+ Swap(texInf.x, texSup.x);
+ }
+ if ( r%4 < 2 )
+ {
+ Swap(texInf.y, texSup.y);
+ }
+#else
+ texInf.x = Mod(texInf.x+0.25f, 1.0f);
+ texSup.x = Mod(texSup.x+0.25f, 1.0f);
+#endif
+
+ vertex[0] = D3DVERTEX2(corner[1], n, texSup.x, texSup.y);
+ vertex[1] = D3DVERTEX2(corner[0], n, texInf.x, texSup.y);
+ vertex[2] = D3DVERTEX2(corner[3], n, texSup.x, texInf.y);
+ vertex[3] = D3DVERTEX2(corner[2], n, texInf.x, texInf.y);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+ }
+ adv += dim.x*2.0f;
+ }
+}
+
+// Dessine une particule sphérique.
+
+void CParticule::DrawParticuleSphere(int i)
+{
+ D3DVERTEX2 vertex[2*16*(16+1)]; // triangles
+ D3DMATRIX matrix, rot;
+ D3DVECTOR angle, v0, v1;
+ FPOINT ts, ti;
+ float zoom, deltaRingAngle, deltaSegAngle;
+ float r0,r1, tu0,tv0, tu1,tv1;
+ int j, ring, seg, numRings, numSegments;
+
+ zoom = m_particule[i].zoom;
+#if 0
+ if ( !m_engine->RetStateColor() && m_particule[i].intensity < 0.5f )
+ {
+ zoom *= m_particule[i].intensity/0.5f;
+ }
+#endif
+
+ if ( zoom == 0.0f ) return;
+
+ m_engine->SetState(D3DSTATETTb|D3DSTATE2FACE|D3DSTATEWRAP, RetColor(m_particule[i].intensity));
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ matrix._11 = zoom;
+ matrix._22 = zoom;
+ matrix._33 = zoom;
+ matrix._41 = m_particule[i].pos.x;
+ matrix._42 = m_particule[i].pos.y;
+ matrix._43 = m_particule[i].pos.z;
+
+ if ( m_particule[i].angle != 0.0f )
+ {
+ angle.x = m_particule[i].angle*0.4f;
+ angle.y = m_particule[i].angle*1.0f;
+ angle.z = m_particule[i].angle*0.7f;
+ MatRotateZXY(rot, angle);
+ matrix = rot*matrix;
+ }
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ ts.x = m_particule[i].texSup.x;
+ ts.y = m_particule[i].texSup.y;
+ ti.x = m_particule[i].texInf.x;
+ ti.y = m_particule[i].texInf.y;
+
+ // Choose a tesselation level.
+ if ( m_particule[i].type == PARTISPHERE3 ||
+ m_particule[i].type == PARTISPHERE5 )
+ {
+ numRings = 16;
+ numSegments = 16;
+ }
+ else
+ {
+ numRings = 8;
+ numSegments = 10;
+ }
+
+ // Establish constants used in sphere generation.
+ deltaRingAngle = PI/numRings;
+ deltaSegAngle = 2.0f*PI/numSegments;
+
+ // Generate the group of rings for the sphere.
+ j = 0;
+ for ( ring=0 ; ring<numRings ; ring++ )
+ {
+ r0 = sinf((ring+0)*deltaRingAngle);
+ r1 = sinf((ring+1)*deltaRingAngle);
+ v0.y = cosf((ring+0)*deltaRingAngle);
+ v1.y = cosf((ring+1)*deltaRingAngle);
+
+ tv0 = (ring+0)/(float)numRings;
+ tv1 = (ring+1)/(float)numRings;
+ tv0 = ts.y+(ti.y-ts.y)*tv0;
+ tv1 = ts.y+(ti.y-ts.y)*tv1;
+
+ // Generate the group of segments for the current ring.
+ for ( seg=0 ; seg<numSegments+1 ; seg++ )
+ {
+ v0.x = r0*sinf(seg*deltaSegAngle);
+ v0.z = r0*cosf(seg*deltaSegAngle);
+ v1.x = r1*sinf(seg*deltaSegAngle);
+ v1.z = r1*cosf(seg*deltaSegAngle);
+
+ // Add two vertices to the strip which makes up the sphere.
+ tu0 = ((float)seg)/numSegments;
+ tu0 = ts.x+(ti.x-ts.x)*tu0;
+ tu1 = tu0;
+
+ vertex[j++] = D3DVERTEX2(v0,v0, tu0,tv0);
+ vertex[j++] = D3DVERTEX2(v1,v1, tu1,tv1);
+ }
+ }
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, j, NULL);
+ m_engine->AddStatisticTriangle(j);
+
+ m_engine->SetState(D3DSTATETTb, RetColor(m_particule[i].intensity));
+}
+
+// Retourne la hauteur en fonction de la progression.
+
+float ProgressCylinder(float progress)
+{
+ if ( progress < 0.5f )
+ {
+ return 1.0f - (powf(1.0f-progress*2.0f, 2.0f));
+ }
+ else
+ {
+ return 1.0f - (powf(progress*2.0f-1.0f, 2.0f));
+ }
+}
+
+// Dessine une particule cylindrique.
+
+void CParticule::DrawParticuleCylinder(int i)
+{
+ D3DVERTEX2 vertex[2*5*(10+1)]; // triangles
+ D3DMATRIX matrix, rot;
+ D3DVECTOR angle, v0, v1;
+ FPOINT ts, ti;
+ float progress, zoom, diam, deltaSegAngle, h[6], d[6];
+ float r0,r1, tu0,tv0, tu1,tv1, p1, p2, pp;
+ int j, ring, seg, numRings, numSegments;
+
+ progress = m_particule[i].zoom;
+ zoom = m_particule[i].dim.x;
+ diam = m_particule[i].dim.y;
+ if ( progress >= 1.0f || zoom == 0.0f ) return;
+
+ m_engine->SetState(D3DSTATETTb|D3DSTATE2FACE|D3DSTATEWRAP, RetColor(m_particule[i].intensity));
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ matrix._11 = zoom;
+ matrix._22 = zoom;
+ matrix._33 = zoom;
+ matrix._41 = m_particule[i].pos.x;
+ matrix._42 = m_particule[i].pos.y;
+ matrix._43 = m_particule[i].pos.z;
+
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ ts.x = m_particule[i].texSup.x;
+ ts.y = m_particule[i].texSup.y;
+ ti.x = m_particule[i].texInf.x;
+ ti.y = m_particule[i].texInf.y;
+
+ numRings = 5;
+ numSegments = 10;
+ deltaSegAngle = 2.0f*PI/numSegments;
+
+ if ( m_particule[i].type == PARTIPLOUF0 )
+ {
+#if 0
+ if ( progress <= 0.5f )
+ {
+ p1 = progress/0.5f; // avant
+ p2 = 0.0f; // arrière
+ }
+ else
+ {
+ p1 = 1.0f; // avant
+ p2 = (progress-0.5f)/0.5f; // arrière
+ ts.y += (ti.y-ts.y)*p2;
+ }
+#else
+ p1 = progress; // avant
+ p2 = powf(progress, 5.0f); // arrière
+#endif
+
+ for ( ring=0 ; ring<=numRings ; ring++ )
+ {
+ pp = p2+(p1-p2)*((float)ring/numRings);
+ d[ring] = diam/zoom+pp*2.0f;
+ h[ring] = ProgressCylinder(pp);
+ }
+ }
+
+ j = 0;
+ for ( ring=0 ; ring<numRings ; ring++ )
+ {
+ r0 = 1.0f*d[ring+0]; // rayon à la base
+ r1 = 1.0f*d[ring+1]; // rayon en haut
+ v0.y = 1.0f*h[ring+0]; // bas
+ v1.y = 1.0f*h[ring+1]; // haut
+
+ tv0 = 1.0f-(ring+0)*(1.0f/numRings);
+ tv1 = 1.0f-(ring+1)*(1.0f/numRings);
+ tv0 = ts.y+(ti.y-ts.y)*tv0;
+ tv1 = ts.y+(ti.y-ts.y)*tv1;
+
+ for ( seg=0 ; seg<numSegments+1 ; seg++ )
+ {
+ v0.x = r0*sinf(seg*deltaSegAngle);
+ v0.z = r0*cosf(seg*deltaSegAngle);
+ v1.x = r1*sinf(seg*deltaSegAngle);
+ v1.z = r1*cosf(seg*deltaSegAngle);
+
+//? tu0 = ((float)seg)/numSegments;
+ tu0 = (seg%2)?0.0f:1.0f;
+ tu0 = ts.x+(ti.x-ts.x)*tu0;
+ tu1 = tu0;
+
+ vertex[j++] = D3DVERTEX2(v0,v0, tu0,tv0);
+ vertex[j++] = D3DVERTEX2(v1,v1, tu1,tv1);
+ }
+ }
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, j, NULL);
+ m_engine->AddStatisticTriangle(j);
+
+ m_engine->SetState(D3DSTATETTb, RetColor(m_particule[i].intensity));
+}
+
+// Dessine une trace de pneu.
+
+void CParticule::DrawParticuleWheel(int i)
+{
+ D3DVECTOR pos[4], center;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR n;
+ FPOINT ts, ti;
+ float dist, dp;
+
+ dist = Length2d(m_engine->RetEyePt(), m_wheelTrace[i].pos[0]);
+ if ( dist > 300.0f ) return;
+
+ pos[0] = m_wheelTrace[i].pos[0];
+ pos[1] = m_wheelTrace[i].pos[1];
+ pos[2] = m_wheelTrace[i].pos[2];
+ pos[3] = m_wheelTrace[i].pos[3];
+
+ if ( m_wheelTrace[i].type == PARTITRACE0 ) // trace au sol blanche ?
+ {
+ ts.x = 8.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE1 ) // trace au sol noire ?
+ {
+ ts.x = 0.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE2 ) // trace au sol grise ?
+ {
+ ts.x = 0.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE3 ) // trace au sol gris clair ?
+ {
+ ts.x = 8.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE4 ) // trace au sol rouge ?
+ {
+ ts.x = 32.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE5 ) // trace au sol rose ?
+ {
+ ts.x = 40.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE6 ) // trace au sol violette ?
+ {
+ ts.x = 32.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE7 ) // trace au sol orange ?
+ {
+ ts.x = 40.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE8 ) // trace au sol jaune ?
+ {
+ ts.x = 16.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE9 ) // trace au sol beige ?
+ {
+ ts.x = 24.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE10 ) // trace au sol brun ?
+ {
+ ts.x = 16.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE11 ) // trace au sol peau ?
+ {
+ ts.x = 24.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE12 ) // trace au sol vert ?
+ {
+ ts.x = 48.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE13 ) // trace au sol vert clair ?
+ {
+ ts.x = 56.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE14 ) // trace au sol bleu ?
+ {
+ ts.x = 48.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE15 ) // trace au sol bleu clair ?
+ {
+ ts.x = 56.0f/256.0f;
+ ts.y = 232.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE16 ) // trace au sol flèche noire ?
+ {
+ ts.x = 160.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE17 ) // trace au sol flèche rouge ?
+ {
+ ts.x = 176.0f/256.0f;
+ ts.y = 224.0f/256.0f;
+ }
+ else
+ {
+ return;
+ }
+
+ if ( m_wheelTrace[i].type == PARTITRACE16 ||
+ m_wheelTrace[i].type == PARTITRACE17 )
+ {
+ ti.x = ts.x+16.0f/256.0f;
+ ti.y = ts.y+16.0f/256.0f;
+ }
+ else
+ {
+ ti.x = ts.x+8.0f/256.0f;
+ ti.y = ts.y+8.0f/256.0f;
+ }
+
+ dp = (1.0f/256.0f)/2.0f;
+ ts.x = ts.x+dp;
+ ts.y = ts.y+dp;
+ ti.x = ti.x-dp;
+ ti.y = ti.y-dp;
+
+ n = D3DVECTOR(0.0f, 1.0f, 0.0f);
+
+ vertex[0] = D3DVERTEX2(pos[0], n, ts.x, ts.y);
+ vertex[1] = D3DVERTEX2(pos[1], n, ti.x, ts.y);
+ vertex[2] = D3DVERTEX2(pos[2], n, ts.x, ti.y);
+ vertex[3] = D3DVERTEX2(pos[3], n, ti.x, ti.y);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+}
+
+// Dessine toutes les particules.
+
+void CParticule::DrawParticule(int sheet)
+{
+ D3DMATERIAL7 mat;
+ D3DMATRIX matrix;
+ BOOL bLoadTexture;
+ char name[20];
+ int state, t, i, j, r;
+
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+
+ // Dessine les particules à base de triangles.
+ if ( m_totalInterface[0][sheet] > 0 )
+ {
+ for ( i=0 ; i<MAXPARTICULE ; i++ )
+ {
+ if ( !m_particule[i].bUsed ) continue;
+ if ( m_particule[i].sheet != sheet ) continue;
+ if ( m_particule[i].type == PARTIPART ) continue;
+
+ m_engine->SetTexture(m_triangle[i].texName1);
+ m_engine->SetMaterial(m_triangle[i].material);
+ m_engine->SetState(m_triangle[i].state);
+ DrawParticuleTriangle(i);
+ }
+ }
+
+ // Dessines les particules à base de carrés calculés.
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+
+ ZeroMemory( &mat, sizeof(D3DMATERIAL7) );
+ mat.diffuse.r = 1.0f;
+ mat.diffuse.g = 1.0f;
+ mat.diffuse.b = 1.0f; // blanc
+ mat.ambient.r = 0.5f;
+ mat.ambient.g = 0.5f;
+ mat.ambient.b = 0.5f;
+ m_engine->SetMaterial(mat);
+
+ // Dessine les traces de pneu.
+ if ( m_wheelTraceTotal > 0 && sheet == SH_WORLD )
+ {
+#if _POLISH
+ m_engine->SetTexture("textp.tga");
+#else
+ m_engine->SetTexture("text.tga");
+#endif
+ m_engine->SetState(D3DSTATETTw);
+//? m_engine->SetState(D3DSTATENORMAL);
+ D3DUtil_SetIdentityMatrix(matrix);
+ m_pD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+ for ( i=0 ; i<m_wheelTraceTotal ; i++ )
+ {
+ DrawParticuleWheel(i);
+ }
+ }
+
+//? for ( t=1 ; t<MAXPARTITYPE ; t++ )
+ for ( t=MAXPARTITYPE-1 ; t>=1 ; t-- ) // noir derrière !
+ {
+ if ( m_totalInterface[t][sheet] == 0 ) continue;
+
+ bLoadTexture = FALSE;
+
+ if ( t == 4 ) state = D3DSTATETTw; // text.tga
+ else state = D3DSTATETTb; // effect[00..02].tga
+ m_engine->SetState(state);
+
+ for ( j=0 ; j<MAXPARTICULE ; j++ )
+ {
+ i = MAXPARTICULE*t+j;
+ if ( !m_particule[i].bUsed ) continue;
+ if ( m_particule[i].sheet != sheet ) continue;
+
+ if ( !bLoadTexture )
+ {
+ NameParticule(name, t);
+ m_engine->SetTexture(name);
+ bLoadTexture = TRUE;
+ }
+
+ r = m_particule[i].trackRank;
+ if ( r != -1 )
+ {
+ m_engine->SetState(state);
+ TrackDraw(r, m_particule[i].type); // dessine la traînée
+ if ( !m_track[r].bDrawParticule ) continue;
+ }
+
+ m_engine->SetState(state, RetColor(m_particule[i].intensity));
+
+ if ( m_particule[i].bRay ) // rayon ?
+ {
+ DrawParticuleRay(i);
+ }
+ else if ( m_particule[i].type == PARTIFLIC || // rond dans l'eau ?
+ m_particule[i].type == PARTISHOW ||
+ m_particule[i].type == PARTICHOC ||
+ m_particule[i].type == PARTIGFLAT )
+ {
+ DrawParticuleFlat(i);
+ }
+ else if ( m_particule[i].type >= PARTIFOG0 &&
+ m_particule[i].type <= PARTIFOG9 )
+ {
+ DrawParticuleFog(i);
+ }
+ else if ( m_particule[i].type >= PARTISPHERE0 &&
+ m_particule[i].type <= PARTISPHERE9 ) // sphère ?
+ {
+ DrawParticuleSphere(i);
+ }
+ else if ( m_particule[i].type >= PARTIPLOUF0 &&
+ m_particule[i].type <= PARTIPLOUF4 ) // cylindre ?
+ {
+ DrawParticuleCylinder(i);
+ }
+ else // normal ?
+ {
+ DrawParticuleNorm(i);
+ }
+ }
+ }
+
+//? m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
+ m_pD3DDevice->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE);
+}
+
+
+// Cherche si un objet fait collision avec une balle.
+
+CObject* CParticule::SearchObjectGun(D3DVECTOR old, D3DVECTOR pos,
+ ParticuleType type, CObject *father)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR box1, box2, oPos, p;
+ ObjectType oType;
+ BOOL bShield;
+ float min, oRadius, dist, shieldRadius;
+ int i, j;
+ BOOL bHimself;
+
+ if ( m_main->RetMovieLock() ) return 0; // film en cours ?
+
+ bHimself = m_main->RetHimselfDamage();
+
+ min = 5.0f;
+ if ( type == PARTIGUN2 ) min = 2.0f; // tir insecte ?
+ if ( type == PARTIGUN3 ) min = 3.0f; // suicide araignée ?
+
+ box1 = old;
+ box2 = pos;
+ if ( box1.x > box2.x ) Swap(box1.x, box2.x); // box1 < box2
+ if ( box1.y > box2.y ) Swap(box1.y, box2.y);
+ if ( box1.z > box2.z ) Swap(box1.z, box2.z);
+ box1.x -= min;
+ box1.y -= min;
+ box1.z -= min;
+ box2.x += min;
+ box2.y += min;
+ box2.z += min;
+
+ pBest = 0;
+ bShield = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj == father ) continue;
+
+ oType = pObj->RetType();
+
+ if ( oType == OBJECT_TOTO ) continue;
+
+ if ( type == PARTIGUN1 ) // tir fireball ?
+ {
+ if ( oType == OBJECT_MOTHER ) continue;
+ if ( bHimself ) // dégâts à soi-même ?
+ {
+ if ( !IsAlien(oType) &&
+ !IsSoft(oType) ) continue;
+ }
+ else // dégats seulement aux ennemis ?
+ {
+ if ( !IsAlien(oType) ) continue;
+ }
+ }
+ else if ( type == PARTIGUN2 ) // tir insecte ?
+ {
+ if ( !IsSoft(oType) ) continue;
+ }
+ else if ( type == PARTIGUN3 ) // suicide araignée ?
+ {
+ if ( !IsSoft(oType) ) continue;
+ }
+ else if ( type == PARTIGUN4 ) // tir orgaball ?
+ {
+ if ( oType == OBJECT_MOTHER ) continue;
+ if ( bHimself ) // dégâts à soi-même ?
+ {
+ if ( !IsAlien(oType) &&
+ !IsSoft(oType) ) continue;
+ }
+ else // dégats seulement aux ennemis ?
+ {
+ if ( !IsAlien(oType) ) continue;
+ }
+ }
+ else if ( type == PARTITRACK11 ) // tir phazer ?
+ {
+ if ( bHimself ) // dégâts à soi-même ?
+ {
+ if ( !IsAlien(oType) &&
+ !IsSoft(oType) ) continue;
+ }
+ else // dégats seulement aux ennemis ?
+ {
+ if ( !IsAlien(oType) ) continue;
+ }
+ }
+ else
+ {
+ continue;
+ }
+
+ oPos = pObj->RetPosition(0);
+
+ if ( type == PARTIGUN2 || // tir insecte ?
+ type == PARTIGUN3 ) // suicide araignée ?
+ {
+ // Test si la balle est entrée dans la sphère d'un bouclier.
+ shieldRadius = pObj->RetShieldRadius();
+ if ( shieldRadius > 0.0f )
+ {
+ dist = Length(oPos, pos);
+ if ( dist <= shieldRadius )
+ {
+ pBest = pObj;
+ bShield = TRUE;
+ }
+ }
+ }
+ if ( bShield ) continue;
+
+ // Test au centre de l'objet, ce qui est nécessaire pour
+ // les objets qui n'ont pas de sphère au centre (station).
+ dist = Length(oPos, pos)-4.0f;
+ if ( dist < min )
+ {
+ pBest = pObj;
+ }
+
+ // Test avec toutes les sphères de l'objet.
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( oPos.x+oRadius < box1.x || oPos.x-oRadius > box2.x || // hors de la boîte ?
+ oPos.y+oRadius < box1.y || oPos.y-oRadius > box2.y ||
+ oPos.z+oRadius < box1.z || oPos.z-oRadius > box2.z ) continue;
+
+ p = Projection(old, pos, oPos);
+ dist = Length(p, oPos)-oRadius;
+ if ( dist < min )
+ {
+ pBest = pObj;
+ }
+ }
+ }
+
+ return pBest;
+}
+
+// Cherche si un objet fait collision avec un rayon.
+
+CObject* CParticule::SearchObjectRay(D3DVECTOR pos, D3DVECTOR goal,
+ ParticuleType type, CObject *father)
+{
+ CObject* pObj;
+ D3DVECTOR box1, box2, oPos, p;
+ ObjectType oType;
+ float min, dist;
+ int i;
+
+ if ( m_main->RetMovieLock() ) return 0; // film en cours ?
+
+ min = 10.0f;
+
+ box1 = pos;
+ box2 = goal;
+ if ( box1.x > box2.x ) Swap(box1.x, box2.x); // box1 < box2
+ if ( box1.y > box2.y ) Swap(box1.y, box2.y);
+ if ( box1.z > box2.z ) Swap(box1.z, box2.z);
+ box1.x -= min;
+ box1.y -= min;
+ box1.z -= min;
+ box2.x += min;
+ box2.y += min;
+ box2.z += min;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj == father ) continue;
+
+ oType = pObj->RetType();
+
+ if ( oType == OBJECT_TOTO ) continue;
+
+ if ( type == PARTIRAY1 &&
+ oType != OBJECT_MOBILEtg &&
+ oType != OBJECT_TEEN28 &&
+ oType != OBJECT_TEEN31 &&
+ oType != OBJECT_ANT &&
+ oType != OBJECT_SPIDER &&
+ oType != OBJECT_BEE &&
+ oType != OBJECT_WORM &&
+ oType != OBJECT_MOTHER &&
+ oType != OBJECT_NEST ) continue;
+
+ oPos = pObj->RetPosition(0);
+
+ if ( oPos.x < box1.x || oPos.x > box2.x || // hors de la boîte ?
+ oPos.y < box1.y || oPos.y > box2.y ||
+ oPos.z < box1.z || oPos.z > box2.z ) continue;
+
+ p = Projection(pos, goal, oPos);
+ dist = Length(p, oPos);
+ if ( dist < min ) return pObj;
+ }
+
+ return 0;
+}
+
+
+// Fait entendre un son.
+
+void CParticule::Play(Sound sound, D3DVECTOR pos, float amplitude)
+{
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+
+ m_sound->Play(sound, pos, amplitude);
+}
+
+
+
+// Cherche la couleur si on est dans le brouillard.
+// Retourne noir si on est pas dans le brouillard.
+
+D3DCOLORVALUE CParticule::RetFogColor(D3DVECTOR pos)
+{
+ D3DCOLORVALUE result, color;
+ float dist, factor;
+ int fog, i;
+
+ result.r = 0.0f;
+ result.g = 0.0f;
+ result.b = 0.0f;
+ result.a = 0.0f;
+
+ for ( fog=0 ; fog<m_fogTotal ; fog++ )
+ {
+ i = m_fog[fog]; // i = rang de la particule
+
+ if ( pos.y >= m_particule[i].pos.y+FOG_HSUP ) continue;
+ if ( pos.y <= m_particule[i].pos.y-FOG_HINF ) continue;
+
+ dist = Length2d(pos, m_particule[i].pos);
+ if ( dist >= m_particule[i].dim.x*1.5f ) continue;
+
+ // Calcule le facteur horizontal.
+ factor = 1.0f-powf(dist/(m_particule[i].dim.x*1.5f), 4.0f);
+
+ // Calcule le facteur vertical.
+ if ( pos.y > m_particule[i].pos.y )
+ {
+ factor *= 1.0f-(pos.y-m_particule[i].pos.y)/FOG_HSUP;
+ }
+ else
+ {
+ factor *= 1.0f-(m_particule[i].pos.y-pos.y)/FOG_HINF;
+ }
+
+ factor *= 0.3f;
+
+ if ( m_particule[i].type == PARTIFOG0 ||
+ m_particule[i].type == PARTIFOG1 ) // bleu ?
+ {
+ color.r = 0.0f;
+ color.g = 0.5f;
+ color.b = 1.0f;
+ }
+ else if ( m_particule[i].type == PARTIFOG2 ||
+ m_particule[i].type == PARTIFOG3 ) // rouge ?
+ {
+ color.r = 2.0f;
+ color.g = 1.0f;
+ color.b = 0.0f;
+ }
+ else if ( m_particule[i].type == PARTIFOG4 ||
+ m_particule[i].type == PARTIFOG5 ) // blanc ?
+ {
+ color.r = 1.0f;
+ color.g = 1.0f;
+ color.b = 1.0f;
+ }
+ else if ( m_particule[i].type == PARTIFOG6 ||
+ m_particule[i].type == PARTIFOG7 ) // jaune ?
+ {
+ color.r = 0.8f;
+ color.g = 1.0f;
+ color.b = 0.4f;
+ }
+ else
+ {
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ }
+
+ result.r += color.r*factor;
+ result.g += color.g*factor;
+ result.b += color.b*factor;
+ }
+
+ if ( result.r > 0.6f ) result.r = 0.6f;
+ if ( result.g > 0.6f ) result.g = 0.6f;
+ if ( result.b > 0.6f ) result.b = 0.6f;
+
+ return result;
+}
+
+
+// Ecrit un fichier .BMP contenant toutes les traces de pneu.
+
+BOOL CParticule::WriteWheelTrace(char *filename, int width, int height,
+ D3DVECTOR dl, D3DVECTOR ur)
+{
+ HDC hDC;
+ HDC hDCImage;
+ HBITMAP hb;
+ PBITMAPINFO info;
+ HBRUSH hBrush;
+ HPEN hPen;
+ HGDIOBJ old;
+ RECT rect;
+ COLORREF color;
+ FPOINT pos[4];
+ POINT list[4];
+ int i;
+
+ if ( !m_engine->GetRenderDC(hDC) ) return FALSE;
+
+ hDCImage = CreateCompatibleDC(hDC);
+ if ( hDCImage == 0 )
+ {
+ m_engine->ReleaseRenderDC(hDC);
+ return FALSE;
+ }
+
+ hb = CreateCompatibleBitmap(hDC, width, height);
+ if ( hb == 0 )
+ {
+ DeleteDC(hDCImage);
+ m_engine->ReleaseRenderDC(hDC);
+ return FALSE;
+ }
+
+ SelectObject(hDCImage, hb);
+
+ rect.left = 0;
+ rect.right = width;
+ rect.top = 0;
+ rect.bottom = height;
+ FillRect(hDCImage, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+
+ hPen = CreatePen(PS_NULL, 1, 0);
+ SelectObject(hDCImage, hPen);
+
+ for ( i=0 ; i<m_wheelTraceTotal ; i++ )
+ {
+ if ( m_wheelTrace[i].type == PARTITRACE0 ) // trace au sol noire ?
+ {
+ color = RGB(0,0,0);
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE1 ) // trace au sol rouge ?
+ {
+ color = RGB(255,0,0);
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE2 ) // trace au sol verte ?
+ {
+ color = RGB(0,255,0);
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE3 ) // trace au sol bleue ?
+ {
+ color = RGB(0,0,255);
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE4 ) // trace au sol cyan ?
+ {
+ color = RGB(0,255,255);
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE5 ) // trace au sol magenta ?
+ {
+ color = RGB(255,0,255);
+ }
+ else if ( m_wheelTrace[i].type == PARTITRACE6 ) // trace au sol jaune ?
+ {
+ color = RGB(255,255,0);
+ }
+ else
+ {
+ color = RGB(0,0,0);
+ }
+ hBrush = CreateSolidBrush(color);
+ old = SelectObject(hDCImage, hBrush);
+
+ pos[0].x = ((m_wheelTrace[i].pos[0].x-dl.x)*width)/(ur.x-dl.x);
+ pos[0].y = ((m_wheelTrace[i].pos[0].z-dl.z)*width)/(ur.z-dl.z);
+ pos[1].x = ((m_wheelTrace[i].pos[1].x-dl.x)*width)/(ur.x-dl.x);
+ pos[1].y = ((m_wheelTrace[i].pos[1].z-dl.z)*width)/(ur.z-dl.z);
+ pos[2].x = ((m_wheelTrace[i].pos[2].x-dl.x)*width)/(ur.x-dl.x);
+ pos[2].y = ((m_wheelTrace[i].pos[2].z-dl.z)*width)/(ur.z-dl.z);
+ pos[3].x = ((m_wheelTrace[i].pos[3].x-dl.x)*width)/(ur.x-dl.x);
+ pos[3].y = ((m_wheelTrace[i].pos[3].z-dl.z)*width)/(ur.z-dl.z);
+
+ list[0].x = (int)pos[0].x;
+ list[0].y = (int)pos[0].y;
+ list[1].x = (int)pos[1].x;
+ list[1].y = (int)pos[1].y;
+ list[2].x = (int)pos[3].x;
+ list[2].y = (int)pos[3].y;
+ list[3].x = (int)pos[2].x;
+ list[3].y = (int)pos[2].y;
+ Polygon(hDCImage, list, 4);
+
+ if ( old != 0 ) SelectObject(hDCImage, old);
+ DeleteObject(hBrush);
+ }
+
+ info = m_engine->CreateBitmapInfoStruct(hb);
+ if ( info == 0 )
+ {
+ DeleteObject(hb);
+ DeleteDC(hDCImage);
+ m_engine->ReleaseRenderDC(hDC);
+ return FALSE;
+ }
+
+ m_engine->CreateBMPFile(filename, info, hb, hDCImage);
+
+ DeleteObject(hb);
+ DeleteDC(hDCImage);
+ m_engine->ReleaseRenderDC(hDC);
+ return TRUE;
+}
+
diff --git a/src/particule.h b/src/particule.h
new file mode 100644
index 0000000..34916e5
--- /dev/null
+++ b/src/particule.h
@@ -0,0 +1,326 @@
+// particule.h
+
+#ifndef _PARTICULE_H_
+#define _PARTICULE_H_
+
+
+#include "D3DEngine.h"
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CRobotMain;
+class CTerrain;
+class CWater;
+class CObject;
+class CSound;
+
+enum Sound;
+
+
+#define MAXPARTICULE 500
+#define MAXPARTITYPE 5
+#define MAXTRACK 100
+#define MAXTRACKLEN 10
+#define MAXPARTIFOG 100
+#define MAXWHEELTRACE 1000
+
+#define SH_WORLD 0 // particule dans le monde sous l'interface
+#define SH_FRONT 1 // particule dans le monde sur l'interface
+#define SH_INTERFACE 2 // particule dans l'interface
+#define SH_MAX 3
+
+// type == 0 -> triangles
+// type == 1 -> effect00 (fond noir)
+// type == 2 -> effect01 (fond noir)
+// type == 3 -> effect02 (fond noir)
+// type == 4 -> text (fond blanc)
+
+
+enum ParticuleType
+{
+ PARTIEXPLOT = 1, // explosion technique
+ PARTIEXPLOO = 2, // explosion organique
+ PARTIMOTOR = 3, // gaz d'échappement du moteur
+ PARTIGLINT = 4, // reflet
+ PARTIBLITZ = 5, // éclair recharge batterie
+ PARTICRASH = 6, // poussière après chute
+ PARTIGAS = 7, // gaz du réacteur
+ PARTIFIRE = 9, // boule de feu qui rétricit
+ PARTIFIREZ = 10, // boule de feu qui grandit
+ PARTIBLUE = 11, // boule bleu
+ PARTISELY = 12, // sélection jaune
+ PARTISELR = 13, // sélection rouge
+ PARTIGUN1 = 18, // balle 1 (fireball)
+ PARTIGUN2 = 19, // balle 2 (fourmi)
+ PARTIGUN3 = 20, // balle 3 (araignée)
+ PARTIGUN4 = 21, // balle 4 (orgaball)
+ PARTIFRAG = 22, // fragment triangulaire
+ PARTIQUEUE = 23, // queue enflammée
+ PARTIORGANIC1 = 24, // boule organique mère
+ PARTIORGANIC2 = 25, // boule organique fille
+ PARTISMOKE1 = 26, // fumée noire
+ PARTISMOKE2 = 27, // fumée noire
+ PARTISMOKE3 = 28, // fumée noire
+ PARTISMOKE4 = 29, // fumée noire
+ PARTIBLOOD = 30, // sang homme
+ PARTIBLOODM = 31, // sang pondeuse
+ PARTIVAPOR = 32, // vapeur
+ PARTIVIRUS1 = 33, // virus 1
+ PARTIVIRUS2 = 34, // virus 2
+ PARTIVIRUS3 = 35, // virus 3
+ PARTIVIRUS4 = 36, // virus 4
+ PARTIVIRUS5 = 37, // virus 5
+ PARTIVIRUS6 = 38, // virus 6
+ PARTIVIRUS7 = 39, // virus 7
+ PARTIVIRUS8 = 40, // virus 8
+ PARTIVIRUS9 = 41, // virus 9
+ PARTIVIRUS10 = 42, // virus 10
+ PARTIRAY1 = 43, // rayon 1 (tour)
+ PARTIRAY2 = 44, // rayon 2 (electric arc)
+ PARTIRAY3 = 45, // rayon 3
+ PARTIRAY4 = 46, // rayon 4
+ PARTIFLAME = 47, // flamme
+ PARTIBUBBLE = 48, // bubble
+ PARTIFLIC = 49, // rond dans l'eau
+ PARTIEJECT = 50, // éjection du réacteur
+ PARTISCRAPS = 51, // déchets du réacteur
+ PARTITOTO = 52, // réacteur de toto
+ PARTIERROR = 53, // toto dit non
+ PARTIWARNING = 54, // toto dit bof
+ PARTIINFO = 54, // toto dit oui
+ PARTIQUARTZ = 55, // reflet quartz
+ PARTISPHERE0 = 56, // sphère d'explosion
+ PARTISPHERE1 = 57, // sphère d'énergie
+ PARTISPHERE2 = 58, // sphère d'analyse
+ PARTISPHERE3 = 59, // sphère de bouclier
+ PARTISPHERE4 = 60, // sphère d'information (emette)
+ PARTISPHERE5 = 61, // sphère végétale (gravity root)
+ PARTISPHERE6 = 62, // sphère d'information (receive)
+ PARTISPHERE7 = 63, // sphère
+ PARTISPHERE8 = 64, // sphère
+ PARTISPHERE9 = 65, // sphère
+ PARTIGUNDEL = 66, // destruction balle par bouclier
+ PARTIPART = 67, // partie d'objet
+ PARTITRACK1 = 68, // traînée 1
+ PARTITRACK2 = 69, // traînée 2
+ PARTITRACK3 = 70, // traînée 3
+ PARTITRACK4 = 71, // traînée 4
+ PARTITRACK5 = 72, // traînée 5
+ PARTITRACK6 = 73, // traînée 6
+ PARTITRACK7 = 74, // traînée 7
+ PARTITRACK8 = 75, // traînée 8
+ PARTITRACK9 = 76, // traînée 9
+ PARTITRACK10 = 77, // traînée 10
+ PARTITRACK11 = 78, // traînée 11
+ PARTITRACK12 = 79, // traînée 12
+ PARTITRACK13 = 80, // traînée 13
+ PARTITRACK14 = 81, // traînée 14
+ PARTITRACK15 = 82, // traînée 15
+ PARTITRACK16 = 83, // traînée 16
+ PARTITRACK17 = 84, // traînée 17
+ PARTITRACK18 = 85, // traînée 18
+ PARTITRACK19 = 86, // traînée 19
+ PARTITRACK20 = 87, // traînée 20
+ PARTIGLINTb = 88, // reflet bleu
+ PARTIGLINTr = 89, // reflet rouge
+ PARTILENS1 = 90, // éclat 1 (orange)
+ PARTILENS2 = 91, // éclat 2 (jaune)
+ PARTILENS3 = 92, // éclat 3 (rouge)
+ PARTILENS4 = 93, // éclat 4 (violet)
+ PARTICONTROL = 94, // reflet sur bouton
+ PARTISHOW = 95, // montre un lieu
+ PARTICHOC = 96, // onde de choc
+ PARTIGFLAT = 97, // montre si le sol est plat
+ PARTIRECOVER = 98, // boule bleu pour recycleur
+ PARTIROOT = 100, // fumée gravity root
+ PARTIPLOUF0 = 101, // plouf
+ PARTIPLOUF1 = 102, // plouf
+ PARTIPLOUF2 = 103, // plouf
+ PARTIPLOUF3 = 104, // plouf
+ PARTIPLOUF4 = 105, // plouf
+ PARTIDROP = 106, // goutte
+ PARTIFOG0 = 107, // brouillard 0
+ PARTIFOG1 = 108, // brouillard 1
+ PARTIFOG2 = 109, // brouillard 2
+ PARTIFOG3 = 110, // brouillard 3
+ PARTIFOG4 = 111, // brouillard 4
+ PARTIFOG5 = 112, // brouillard 5
+ PARTIFOG6 = 113, // brouillard 6
+ PARTIFOG7 = 114, // brouillard 7
+ PARTIFOG8 = 115, // brouillard 8
+ PARTIFOG9 = 116, // brouillard 9
+ PARTILIMIT1 = 117, // montre les limites 1
+ PARTILIMIT2 = 118, // montre les limites 2
+ PARTILIMIT3 = 119, // montre les limites 3
+ PARTILIMIT4 = 120, // montre les limites 4
+ PARTIWATER = 121, // goutte d'eau
+ PARTIEXPLOG1 = 122, // explosion balle 1
+ PARTIEXPLOG2 = 123, // explosion balle 2
+ PARTIBASE = 124, // gaz du vaisseau spatial
+ PARTITRACE0 = 140, // trace
+ PARTITRACE1 = 141, // trace
+ PARTITRACE2 = 142, // trace
+ PARTITRACE3 = 143, // trace
+ PARTITRACE4 = 144, // trace
+ PARTITRACE5 = 145, // trace
+ PARTITRACE6 = 146, // trace
+ PARTITRACE7 = 147, // trace
+ PARTITRACE8 = 148, // trace
+ PARTITRACE9 = 149, // trace
+ PARTITRACE10 = 150, // trace
+ PARTITRACE11 = 151, // trace
+ PARTITRACE12 = 152, // trace
+ PARTITRACE13 = 153, // trace
+ PARTITRACE14 = 154, // trace
+ PARTITRACE15 = 155, // trace
+ PARTITRACE16 = 156, // trace
+ PARTITRACE17 = 157, // trace
+ PARTITRACE18 = 158, // trace
+ PARTITRACE19 = 159, // trace
+};
+
+enum ParticulePhase
+{
+ PARPHSTART = 0,
+ PARPHEND = 1,
+};
+
+typedef struct
+{
+ char bUsed; // TRUE -> particule utilisée
+ char bRay; // TRUE -> rayon avec but
+ unsigned short uniqueStamp;// marque unique
+ short sheet; // feuille (0..n)
+ ParticuleType type; // type PARTI*
+ ParticulePhase phase; // phase PARPH*
+ float mass; // masse de la particule (pour les rebonds)
+ float weight; // poids de la particule (pour le bruit)
+ float duration; // durée de vie
+ D3DVECTOR pos; // position absolue (relative si objet lié)
+ D3DVECTOR goal; // position but (si bRay)
+ D3DVECTOR speed; // vitesses de déplacement
+ float windSensitivity;
+ short bounce; // nb de rebonds
+ FPOINT dim; // dimensions du rectangle
+ float zoom; // zoom (0..1)
+ float angle; // angle de rotation
+ float intensity; // intensité
+ FPOINT texSup; // coordonnée texture supérieure
+ FPOINT texInf; // cooddonnée texture inférieure
+ float time; // âge de la particule (0..n)
+ float phaseTime; // âge au début de la phase
+ float testTime; // temps depuis dernier test
+ CObject* objLink; // objet père (pour réacteur par exemple)
+ CObject* objFather; // objet père (pour réacteur par exemple)
+ short objRank; // rang de l'objet, ou -1
+ short trackRank; // rang de la traînée
+}
+Particule;
+
+typedef struct
+{
+ char bUsed; // TRUE -> traînée utilisée
+ char bDrawParticule;
+ float step; // durée d'un pas
+ float last; // progression dernier pas mémorisé
+ float intensity; // intensité au départ (0..1)
+ float width; // largeur queue
+ int used; // nb de positions dans "pos"
+ int head; // index tête d'écriture
+ D3DVECTOR pos[MAXTRACKLEN];
+ float len[MAXTRACKLEN];
+}
+Track;
+
+typedef struct
+{
+ ParticuleType type; // type PARTI*
+ D3DVECTOR pos[4]; // positions rectangle
+ float startTime; // début de vie
+}
+WheelTrace;
+
+
+
+class CParticule
+{
+public:
+ CParticule(CInstanceManager* iMan, CD3DEngine* engine);
+ ~CParticule();
+
+ void SetD3DDevice(LPDIRECT3DDEVICE7 device);
+
+ void FlushParticule();
+ void FlushParticule(int sheet);
+ int CreateParticule(D3DVECTOR pos, D3DVECTOR speed, FPOINT dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
+ int CreateFrag(D3DVECTOR pos, D3DVECTOR speed, D3DTriangle *triangle, ParticuleType type, float duration=1.0f, float mass=0.0f, float windSensitivity=1.0f, int sheet=0);
+ int CreatePart(D3DVECTOR pos, D3DVECTOR speed, ParticuleType type, float duration=1.0f, float mass=0.0f, float weight=0.0f, float windSensitivity=1.0f, int sheet=0);
+ int CreateRay(D3DVECTOR pos, D3DVECTOR goal, ParticuleType type, FPOINT dim, float duration=1.0f, int sheet=0);
+ int CreateTrack(D3DVECTOR pos, D3DVECTOR speed, FPOINT dim, ParticuleType type, float duration=1.0f, float mass=0.0f, float length=10.0f, float width=1.0f);
+ void CreateWheelTrace(const D3DVECTOR &p1, const D3DVECTOR &p2, const D3DVECTOR &p3, const D3DVECTOR &p4, ParticuleType type);
+ void DeleteParticule(ParticuleType type);
+ void DeleteParticule(int channel);
+ void SetObjectLink(int channel, CObject *object);
+ void SetObjectFather(int channel, CObject *object);
+ void SetPosition(int channel, D3DVECTOR pos);
+ void SetDimension(int channel, FPOINT dim);
+ void SetZoom(int channel, float zoom);
+ void SetAngle(int channel, float angle);
+ void SetIntensity(int channel, float intensity);
+ void SetParam(int channel, D3DVECTOR pos, FPOINT dim, float zoom, float angle, float intensity);
+ void SetPhase(int channel, ParticulePhase phase, float duration);
+ BOOL GetPosition(int channel, D3DVECTOR &pos);
+
+ D3DCOLORVALUE RetFogColor(D3DVECTOR pos);
+
+ void SetFrameUpdate(int sheet, BOOL bUpdate);
+ void FrameParticule(float rTime);
+ void DrawParticule(int sheet);
+
+ BOOL WriteWheelTrace(char *filename, int width, int height, D3DVECTOR dl, D3DVECTOR 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(D3DVECTOR old, D3DVECTOR pos, ParticuleType type, CObject *father);
+ CObject* SearchObjectRay(D3DVECTOR pos, D3DVECTOR goal, ParticuleType type, CObject *father);
+ void Play(Sound sound, D3DVECTOR pos, float amplitude);
+ BOOL TrackMove(int i, D3DVECTOR pos, float progress);
+ void TrackDraw(int i, ParticuleType type);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+ CRobotMain* m_main;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CSound* m_sound;
+
+ Particule m_particule[MAXPARTICULE*MAXPARTITYPE];
+ D3DTriangle m_triangle[MAXPARTICULE]; // triangle si 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;
+};
+
+
+#endif //_PARTICULE_H_
diff --git a/src/patch16.txt b/src/patch16.txt
new file mode 100644
index 0000000..cfd3982
--- /dev/null
+++ b/src/patch16.txt
@@ -0,0 +1,10 @@
+Liste des fichiers pour le patch 1.6
+
+help\cbot.txt (/f)
+help\cbot\object.txt
+help\cbot\grab.txt
+help\cbot\drop.txt
+help\cbot\category.txt
+help\cbot\extern.txt (/f)
+help\object\goal.txt
+help\object\atomic.txt
diff --git a/src/physics.cpp b/src/physics.cpp
new file mode 100644
index 0000000..ad28b65
--- /dev/null
+++ b/src/physics.cpp
@@ -0,0 +1,3873 @@
+// physics.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "camera.h"
+#include "object.h"
+#include "pyro.h"
+#include "brain.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "sound.h"
+#include "task.h"
+#include "cmdtoken.h"
+#include "physics.h"
+
+
+
+#define LANDING_SPEED 3.0f
+#define LANDING_ACCEL 5.0f
+#define LANDING_ACCELh 1.5f
+
+
+
+
+// Constructeur de l'objet.
+
+CPhysics::CPhysics(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_PHYSICS, this, 100);
+
+ m_object = object;
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ m_brain = 0;
+ m_motion = 0;
+
+ m_type = TYPE_ROLLING;
+ m_gravity = 9.81f; // gravité terrestre par défaut
+ m_time = 0.0f;
+ m_timeUnderWater = 0.0f;
+ m_motorSpeed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_bMotor = FALSE;
+ m_bLand = TRUE; // au sol
+ m_bSwim = FALSE; // dans l'air
+ m_bCollision = FALSE;
+ m_bObstacle = FALSE;
+ m_repeatCollision = 0;
+ m_linVibrationFactor = 1.0f;
+ m_cirVibrationFactor = 1.0f;
+ m_inclinaisonFactor = 1.0f;
+ m_lastPowerParticule = 0.0f;
+ m_lastSlideParticule = 0.0f;
+ m_lastMotorParticule = 0.0f;
+ m_lastWaterParticule = 0.0f;
+ m_lastUnderParticule = 0.0f;
+ m_lastPloufParticule = 0.0f;
+ m_lastFlameParticule = 0.0f;
+ m_bWheelParticuleBrake = FALSE;
+ m_absorbWater = 0.0f;
+ m_reactorTemperature = 0.0f;
+ m_reactorRange = 1.0f;
+ m_timeReactorFail = 0.0f;
+ m_lastEnergy = 0.0f;
+ m_lastSoundWater = 0.0f;
+ m_lastSoundInsect = 0.0f;
+ m_restBreakParticule = 0.0f;
+ m_floorHeight = 0.0f;
+ m_soundChannel = -1;
+ m_soundChannelSlide = -1;
+ m_soundTimePshhh = 0.0f;
+ m_soundTimeJostle = 0.0f;
+ m_soundTimeBoum = 0.0f;
+ m_bSoundSlow = TRUE;
+ m_bFreeze = FALSE;
+ m_bForceUpdate = TRUE;
+ m_bLowLevel = FALSE;
+
+ ZeroMemory(&m_linMotion, sizeof(Motion));
+ ZeroMemory(&m_cirMotion, sizeof(Motion));
+}
+
+// Destructeur de l'objet.
+
+CPhysics::~CPhysics()
+{
+ m_iMan->DeleteInstance(CLASS_PHYSICS, this);
+}
+
+
+// Détruit l'objet.
+
+void CPhysics::DeleteObject(BOOL bAll)
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+ if ( m_soundChannelSlide != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannelSlide);
+ m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannelSlide = -1;
+ }
+}
+
+
+
+void CPhysics::SetBrain(CBrain* brain)
+{
+ m_brain = brain;
+}
+
+void CPhysics::SetMotion(CMotion* motion)
+{
+ m_motion = motion;
+}
+
+// Gestion du type.
+
+void CPhysics::SetType(PhysicsType type)
+{
+ m_type = type;
+}
+
+PhysicsType CPhysics::RetType()
+{
+ return m_type;
+}
+
+
+
+// Sauve tous les paramètres de l'objet.
+
+BOOL CPhysics::Write(char *line)
+{
+ char name[100];
+
+ sprintf(name, " motor=%.2f;%.2f;%.2f", m_motorSpeed.x, m_motorSpeed.y, m_motorSpeed.z);
+ strcat(line, name);
+
+ if ( m_type == TYPE_FLYING )
+ {
+ sprintf(name, " reactorRange=%.2f", RetReactorRange());
+ strcat(line, name);
+
+ sprintf(name, " land=%d", RetLand());
+ strcat(line, name);
+ }
+
+ return TRUE;
+}
+
+// Restitue tous les paramètres de l'objet.
+
+BOOL CPhysics::Read(char *line)
+{
+ m_motorSpeed = OpDir(line, "motor");
+
+ if ( m_type == TYPE_FLYING )
+ {
+ SetReactorRange(OpFloat(line, "reactorRange", 0.0f));
+ SetLand(OpInt(line, "land", 0));
+ }
+
+ return TRUE;
+}
+
+
+
+// Gestion de la force de gravité.
+
+void CPhysics::SetGravity(float value)
+{
+ m_gravity = value;
+}
+
+float CPhysics::RetGravity()
+{
+ return m_gravity;
+}
+
+
+// Retourne la hauteur au-dessus du sol.
+
+float CPhysics::RetFloorHeight()
+{
+ return m_floorHeight;
+}
+
+
+// Gestion de l'état du moteur.
+
+void CPhysics::SetMotor(BOOL bState)
+{
+ int light;
+
+ m_bMotor = bState;
+
+ light = m_object->RetShadowLight();
+ if ( light != -1 )
+ {
+ m_light->SetLightIntensity(light, m_bMotor?1.0f:0.0f);
+ m_light->SetLightIntensitySpeed(light, 3.0f);
+ }
+}
+
+BOOL CPhysics::RetMotor()
+{
+ return m_bMotor;
+}
+
+
+// Gestion de l'état en vol/au sol.
+
+void CPhysics::SetLand(BOOL bState)
+{
+ m_bLand = bState;
+ SetMotor(!bState); // allume le réacteur si on part en vol
+}
+
+BOOL CPhysics::RetLand()
+{
+ return m_bLand;
+}
+
+
+// Gestion de l'état dans l'air/l'eau.
+
+void CPhysics::SetSwim(BOOL bState)
+{
+ if ( !m_bSwim && bState ) // entre dans l'eau ?
+ {
+ m_timeUnderWater = 0.0f;
+ }
+ m_bSwim = bState;
+}
+
+BOOL CPhysics::RetSwim()
+{
+ return m_bSwim;
+}
+
+
+// Indique s une collision a eu lieu.
+
+void CPhysics::SetCollision(BOOL bCollision)
+{
+ m_bCollision = bCollision;
+}
+
+BOOL CPhysics::RetCollision()
+{
+ return m_bCollision;
+}
+
+
+// Indique si l'influence du sol est activée ou non.
+
+void CPhysics::SetFreeze(BOOL bFreeze)
+{
+ m_bFreeze = bFreeze;
+}
+
+BOOL CPhysics::RetFreeze()
+{
+ return m_bFreeze;
+}
+
+
+// Retourne le niveau d'automie du réacteur.
+
+void CPhysics::SetReactorRange(float range)
+{
+ m_reactorRange = range;
+}
+
+float CPhysics::RetReactorRange()
+{
+ return m_reactorRange;
+}
+
+
+// Spécifie la vitesse du moteur.
+// x = avancer/reculer
+// y = monter/descendre
+// z = tourner
+
+void CPhysics::SetMotorSpeed(D3DVECTOR speed)
+{
+ m_motorSpeed = speed;
+}
+
+// Spécifie la vitesse du moteur pour avancer/reculer.
+// +1 = avancer
+// -1 = reculer
+
+void CPhysics::SetMotorSpeedX(float speed)
+{
+ m_motorSpeed.x = speed;
+}
+
+// Spécifie la vitesse du moteur pour monter/descendre.
+// +1 = monter
+// -1 = descendre
+
+void CPhysics::SetMotorSpeedY(float speed)
+{
+ m_motorSpeed.y = speed;
+}
+
+// Spécifie la vitesse du moteur pour tourner.
+// +1 = tourner à droite (CW)
+// -1 = tourner à gauche (CCW)
+
+void CPhysics::SetMotorSpeedZ(float speed)
+{
+ m_motorSpeed.z = speed;
+}
+
+D3DVECTOR CPhysics::RetMotorSpeed()
+{
+ return m_motorSpeed;
+}
+
+float CPhysics::RetMotorSpeedX()
+{
+ return m_motorSpeed.x;
+}
+
+float CPhysics::RetMotorSpeedY()
+{
+ return m_motorSpeed.y;
+}
+
+float CPhysics::RetMotorSpeedZ()
+{
+ return m_motorSpeed.z;
+}
+
+
+// Gestion des vitesses linéaires et angulaires.
+// Spécifie la vitesse parallèle au sens de marche.
+
+void CPhysics::SetLinMotion(PhysicsMode mode, D3DVECTOR value)
+{
+ if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel = value;
+ if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel = value;
+ if ( mode == MO_STOACCEL ) m_linMotion.stopAccel = value;
+ if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed = value;
+ if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide = value;
+ if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel = value;
+ if ( mode == MO_TERFORCE ) m_linMotion.terrainForce = value;
+ if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed = value;
+ if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed = value;
+ if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed = value;
+ if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed = value;
+ if ( mode == MO_REASPEED ) m_linMotion.realSpeed = value;
+}
+
+D3DVECTOR CPhysics::RetLinMotion(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel;
+ if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel;
+ if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel;
+ if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed;
+ if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide;
+ if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel;
+ if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce;
+ if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed;
+ if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed;
+ if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed;
+ if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed;
+ if ( mode == MO_REASPEED ) return m_linMotion.realSpeed;
+ return D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+void CPhysics::SetLinMotionX(PhysicsMode mode, float value)
+{
+ if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel.x = value;
+ if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel.x = value;
+ if ( mode == MO_STOACCEL ) m_linMotion.stopAccel.x = value;
+ if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed.x = value;
+ if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide.x = value;
+ if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel.x = value;
+ if ( mode == MO_TERFORCE ) m_linMotion.terrainForce.x = value;
+ if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed.x = value;
+ if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed.x = value;
+ if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed.x = value;
+ if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed.x = value;
+ if ( mode == MO_REASPEED ) m_linMotion.realSpeed.x = value;
+}
+
+float CPhysics::RetLinMotionX(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel.x;
+ if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel.x;
+ if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel.x;
+ if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed.x;
+ if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide.x;
+ if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel.x;
+ if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce.x;
+ if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed.x;
+ if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed.x;
+ if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed.x;
+ if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed.x;
+ if ( mode == MO_REASPEED ) return m_linMotion.realSpeed.x;
+ return 0.0f;
+}
+
+// Spécifie la vitesse d'élévation.
+
+void CPhysics::SetLinMotionY(PhysicsMode mode, float value)
+{
+ if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel.y = value;
+ if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel.y = value;
+ if ( mode == MO_STOACCEL ) m_linMotion.stopAccel.y = value;
+ if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed.y = value;
+ if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide.y = value;
+ if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel.y = value;
+ if ( mode == MO_TERFORCE ) m_linMotion.terrainForce.y = value;
+ if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed.y = value;
+ if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed.y = value;
+ if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed.y = value;
+ if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed.y = value;
+ if ( mode == MO_REASPEED ) m_linMotion.realSpeed.y = value;
+}
+
+float CPhysics::RetLinMotionY(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel.y;
+ if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel.y;
+ if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel.y;
+ if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed.y;
+ if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide.y;
+ if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel.y;
+ if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce.y;
+ if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed.y;
+ if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed.y;
+ if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed.y;
+ if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed.y;
+ if ( mode == MO_REASPEED ) return m_linMotion.realSpeed.y;
+ return 0.0f;
+}
+
+// Spécifie la vitesse perpendiculaire au sens de marche.
+
+void CPhysics::SetLinMotionZ(PhysicsMode mode, float value)
+{
+ if ( mode == MO_ADVACCEL ) m_linMotion.advanceAccel.z = value;
+ if ( mode == MO_RECACCEL ) m_linMotion.recedeAccel.z = value;
+ if ( mode == MO_STOACCEL ) m_linMotion.stopAccel.z = value;
+ if ( mode == MO_TERSPEED ) m_linMotion.terrainSpeed.z = value;
+ if ( mode == MO_TERSLIDE ) m_linMotion.terrainSlide.z = value;
+ if ( mode == MO_MOTACCEL ) m_linMotion.motorAccel.z = value;
+ if ( mode == MO_TERFORCE ) m_linMotion.terrainForce.z = value;
+ if ( mode == MO_ADVSPEED ) m_linMotion.advanceSpeed.z = value;
+ if ( mode == MO_RECSPEED ) m_linMotion.recedeSpeed.z = value;
+ if ( mode == MO_MOTSPEED ) m_linMotion.motorSpeed.z = value;
+ if ( mode == MO_CURSPEED ) m_linMotion.currentSpeed.z = value;
+ if ( mode == MO_REASPEED ) m_linMotion.realSpeed.z = value;
+}
+
+float CPhysics::RetLinMotionZ(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_linMotion.advanceAccel.z;
+ if ( mode == MO_RECACCEL ) return m_linMotion.recedeAccel.z;
+ if ( mode == MO_STOACCEL ) return m_linMotion.stopAccel.z;
+ if ( mode == MO_TERSPEED ) return m_linMotion.terrainSpeed.z;
+ if ( mode == MO_TERSLIDE ) return m_linMotion.terrainSlide.z;
+ if ( mode == MO_MOTACCEL ) return m_linMotion.motorAccel.z;
+ if ( mode == MO_TERFORCE ) return m_linMotion.terrainForce.z;
+ if ( mode == MO_ADVSPEED ) return m_linMotion.advanceSpeed.z;
+ if ( mode == MO_RECSPEED ) return m_linMotion.recedeSpeed.z;
+ if ( mode == MO_MOTSPEED ) return m_linMotion.motorSpeed.z;
+ if ( mode == MO_CURSPEED ) return m_linMotion.currentSpeed.z;
+ if ( mode == MO_REASPEED ) return m_linMotion.realSpeed.z;
+ return 0.0f;
+}
+
+// Spécifie la rotation autour de l'axe de marche.
+
+void CPhysics::SetCirMotion(PhysicsMode mode, D3DVECTOR value)
+{
+ if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel = value;
+ if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel = value;
+ if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel = value;
+ if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed = value;
+ if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide = value;
+ if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel = value;
+ if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce = value;
+ if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed = value;
+ if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed = value;
+ if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed = value;
+ if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed = value;
+ if ( mode == MO_REASPEED ) m_cirMotion.realSpeed = value;
+}
+
+D3DVECTOR CPhysics::RetCirMotion(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel;
+ if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel;
+ if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel;
+ if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed;
+ if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide;
+ if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel;
+ if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce;
+ if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed;
+ if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed;
+ if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed;
+ if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed;
+ if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed;
+ return D3DVECTOR(0.0f, 0.0f, 0.0f);
+}
+
+void CPhysics::SetCirMotionX(PhysicsMode mode, float value)
+{
+ if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel.x = value;
+ if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel.x = value;
+ if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel.x = value;
+ if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed.x = value;
+ if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide.x = value;
+ if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel.x = value;
+ if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce.x = value;
+ if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed.x = value;
+ if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed.x = value;
+ if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed.x = value;
+ if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed.x = value;
+ if ( mode == MO_REASPEED ) m_cirMotion.realSpeed.x = value;
+}
+
+float CPhysics::RetCirMotionX(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel.x;
+ if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel.x;
+ if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel.x;
+ if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed.x;
+ if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide.x;
+ if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel.x;
+ if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce.x;
+ if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed.x;
+ if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed.x;
+ if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed.x;
+ if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed.x;
+ if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed.x;
+ return 0.0f;
+}
+
+// Spécifie la rotation de direction.
+
+void CPhysics::SetCirMotionY(PhysicsMode mode, float value)
+{
+ if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel.y = value;
+ if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel.y = value;
+ if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel.y = value;
+ if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed.y = value;
+ if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide.y = value;
+ if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel.y = value;
+ if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce.y = value;
+ if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed.y = value;
+ if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed.y = value;
+ if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed.y = value;
+ if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed.y = value;
+ if ( mode == MO_REASPEED ) m_cirMotion.realSpeed.y = value;
+}
+
+float CPhysics::RetCirMotionY(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel.y;
+ if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel.y;
+ if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel.y;
+ if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed.y;
+ if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide.y;
+ if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel.y;
+ if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce.y;
+ if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed.y;
+ if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed.y;
+ if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed.y;
+ if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed.y;
+ if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed.y;
+ return 0.0f;
+}
+
+// Spécifie la rotation de montée/descente.
+
+void CPhysics::SetCirMotionZ(PhysicsMode mode, float value)
+{
+ if ( mode == MO_ADVACCEL ) m_cirMotion.advanceAccel.z = value;
+ if ( mode == MO_RECACCEL ) m_cirMotion.recedeAccel.z = value;
+ if ( mode == MO_STOACCEL ) m_cirMotion.stopAccel.z = value;
+ if ( mode == MO_TERSPEED ) m_cirMotion.terrainSpeed.z = value;
+ if ( mode == MO_TERSLIDE ) m_cirMotion.terrainSlide.z = value;
+ if ( mode == MO_MOTACCEL ) m_cirMotion.motorAccel.z = value;
+ if ( mode == MO_TERFORCE ) m_cirMotion.terrainForce.z = value;
+ if ( mode == MO_ADVSPEED ) m_cirMotion.advanceSpeed.z = value;
+ if ( mode == MO_RECSPEED ) m_cirMotion.recedeSpeed.z = value;
+ if ( mode == MO_MOTSPEED ) m_cirMotion.motorSpeed.z = value;
+ if ( mode == MO_CURSPEED ) m_cirMotion.currentSpeed.z = value;
+ if ( mode == MO_REASPEED ) m_cirMotion.realSpeed.z = value;
+}
+
+float CPhysics::RetCirMotionZ(PhysicsMode mode)
+{
+ if ( mode == MO_ADVACCEL ) return m_cirMotion.advanceAccel.z;
+ if ( mode == MO_RECACCEL ) return m_cirMotion.recedeAccel.z;
+ if ( mode == MO_STOACCEL ) return m_cirMotion.stopAccel.z;
+ if ( mode == MO_TERSPEED ) return m_cirMotion.terrainSpeed.z;
+ if ( mode == MO_TERSLIDE ) return m_cirMotion.terrainSlide.z;
+ if ( mode == MO_MOTACCEL ) return m_cirMotion.motorAccel.z;
+ if ( mode == MO_TERFORCE ) return m_cirMotion.terrainForce.z;
+ if ( mode == MO_ADVSPEED ) return m_cirMotion.advanceSpeed.z;
+ if ( mode == MO_RECSPEED ) return m_cirMotion.recedeSpeed.z;
+ if ( mode == MO_MOTSPEED ) return m_cirMotion.motorSpeed.z;
+ if ( mode == MO_CURSPEED ) return m_cirMotion.currentSpeed.z;
+ if ( mode == MO_REASPEED ) return m_cirMotion.realSpeed.z;
+ return 0.0f;
+}
+
+
+// Retourne la distance linéaire de freinage.
+//
+// v*v
+// d = -----
+// 2a
+
+float CPhysics::RetLinStopLength(PhysicsMode sMode, PhysicsMode aMode)
+{
+ float speed, accel;
+
+ speed = RetLinMotionX(sMode); // MO_ADVSPEED/MO_RECSPEED
+ accel = RetLinMotionX(aMode); // MO_ADVACCEL/MO_RECACCEL/MO_STOACCEL
+
+ if ( m_type == TYPE_FLYING && m_bLand ) // volant au sol ?
+ {
+ speed /= LANDING_SPEED;
+ accel *= LANDING_ACCEL;
+ }
+
+ return (speed*speed) / (accel*2.0f);
+}
+
+// Retourne l'angle circulaire de freinage.
+
+float CPhysics::RetCirStopLength()
+{
+ return m_cirMotion.advanceSpeed.y * m_cirMotion.advanceSpeed.y /
+ m_cirMotion.stopAccel.y / 2.0f;
+}
+
+// Retourne la longueur avancée en une seconde, au sol, à vitesse maximale.
+
+float CPhysics::RetLinMaxLength(float dir)
+{
+ float dist;
+
+ if ( dir > 0.0f ) dist = m_linMotion.advanceSpeed.x;
+ else dist = m_linMotion.recedeSpeed.x;
+
+ if ( m_type == TYPE_FLYING )
+ {
+ dist /= 5.0f;
+ }
+
+ return dist;
+}
+
+// Retourne le temps nécessaire pour parcourir une certaine distance.
+
+float CPhysics::RetLinTimeLength(float dist, float dir)
+{
+ float accel, decel, dps;
+
+ if ( dir > 0.0f )
+ {
+ accel = RetLinStopLength(MO_ADVSPEED, MO_ADVACCEL);
+ decel = RetLinStopLength(MO_ADVSPEED, MO_STOACCEL);
+ }
+ else
+ {
+ accel = RetLinStopLength(MO_RECSPEED, MO_RECACCEL);
+ decel = RetLinStopLength(MO_RECSPEED, MO_STOACCEL);
+ }
+
+ dps = RetLinMaxLength(dir);
+
+ return (dist+accel+decel)/dps;
+}
+
+// Retourne la longueur à avancer pour parcourir une certaine
+// distance, en tenant compte des accélérations/décélérations.
+
+float CPhysics::RetLinLength(float dist)
+{
+ float accDist, desDist;
+
+ if ( dist > 0.0f )
+ {
+ accDist = RetLinStopLength(MO_ADVSPEED, MO_ADVACCEL);
+ desDist = RetLinStopLength(MO_ADVSPEED, MO_STOACCEL);
+
+ if ( dist > accDist+desDist )
+ {
+ return dist-desDist;
+ }
+
+ return dist*m_linMotion.stopAccel.x /
+ (m_linMotion.advanceAccel.x+m_linMotion.stopAccel.x);
+ }
+ else
+ {
+ dist = -dist;
+ accDist = RetLinStopLength(MO_RECSPEED, MO_RECACCEL);
+ desDist = RetLinStopLength(MO_RECSPEED, MO_STOACCEL);
+
+ if ( dist > accDist+desDist )
+ {
+ return dist-desDist;
+ }
+
+ return dist*m_linMotion.stopAccel.x /
+ (m_linMotion.recedeAccel.x+m_linMotion.stopAccel.x);
+ }
+}
+
+
+// Gestion d'un événement.
+// Retourne FALSE si l'objet est détruit.
+
+BOOL CPhysics::EventProcess(const Event &event)
+{
+ if ( !m_object->RetEnable() ) return TRUE;
+
+ if ( m_brain != 0 )
+ {
+ m_brain->EventProcess(event);
+ }
+
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+ return TRUE;
+}
+
+
+// Met à jour les consignes de vitesse du moteur.
+
+void CPhysics::MotorUpdate(float aTime, float rTime)
+{
+ ObjectType type;
+ CObject* power;
+ D3DVECTOR pos, motorSpeed;
+ float energy, speed, factor, h;
+
+ type = m_object->RetType();
+
+ motorSpeed = m_motorSpeed;
+
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_APOLLO2 ||
+ type == OBJECT_MOBILEdr )
+ {
+ power = 0;
+ }
+ else if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ power = 0;
+ if ( m_object->RetFret() != 0 && // porte qq chose ?
+ !m_object->RetCargo() )
+ {
+ motorSpeed.x *= 0.7f; // avance plus lentement
+ motorSpeed.z *= 0.5f;
+ motorSpeed.y = -1.0f; // tombe
+ }
+ if ( m_bSwim )
+ {
+ if ( m_bLand ) // au fond de l'eau ?
+ {
+ motorSpeed.x *= 0.4f; // avance plus lentement
+ motorSpeed.z *= 0.5f;
+ motorSpeed.y *= 0.5f;
+
+ if ( m_object->RetFret() != 0 ) // porte qq chose ?
+ {
+ motorSpeed.x *= 0.2f;
+ motorSpeed.z *= 0.9f;
+ motorSpeed.y *= 0.2f;
+ }
+ }
+ else // nage ?
+ {
+ motorSpeed.x *= 0.2f; // avance plus lentement
+ motorSpeed.z *= 0.5f;
+ motorSpeed.y *= 0.2f;
+ }
+ }
+ }
+ else
+ {
+ power = m_object->RetPower(); // cherche l'objet pile utilisé
+ if ( power == 0 || power->RetEnergy() == 0.0f ) // pas de pile ou plate ?
+ {
+ motorSpeed.x = 0.0f;
+ motorSpeed.z = 0.0f;
+ if ( m_bFreeze || m_bLand )
+ {
+ motorSpeed.y = 0.0f; // immobile
+ }
+ else
+ {
+ motorSpeed.y = -1.0f; // tombe
+ }
+ SetMotor(FALSE);
+ }
+ }
+
+ if ( m_object->RetDead() ) // homme mort ?
+ {
+ motorSpeed.x = 0.0f;
+ motorSpeed.z = 0.0f;
+ if ( m_motion->RetAction() == MHS_DEADw ) // mort noyé ?
+ {
+ motorSpeed.y = 0.0f; // c'est MHS_DEADw qui remonte
+ }
+ else
+ {
+ motorSpeed.y = -1.0f; // tombe
+ }
+ SetMotor(FALSE);
+ }
+
+ if ( m_type == TYPE_FLYING && !m_bLand && motorSpeed.y > 0.0f )
+ {
+ pos = m_object->RetPosition(0);
+ h = m_terrain->RetFlyingLimit(pos, type==OBJECT_BEE);
+ h += m_object->RetCharacter()->height;
+ if ( pos.y > h-40.0f ) // presque tout en haut ?
+ {
+ factor = 1.0f-(pos.y-(h-40.0f))/40.0f;
+ if ( factor < -1.0f ) factor = -1.0f;
+ if ( factor > 1.0f ) factor = 1.0f;
+ motorSpeed.y *= factor; // limite la vitesse de montée
+ }
+ }
+
+ if ( type != OBJECT_BEE &&
+ m_object->RetRange() > 0.0f ) // autonomie de vol limitée ?
+ {
+ if ( m_bLand || m_bSwim || m_bObstacle ) // au sol ou dans l'eau ?
+ {
+ factor = 1.0f;
+ if ( m_bObstacle ) factor = 3.0f; // pour pouvoir repartir !
+ if ( m_bSwim ) factor = 3.0f; // refroidit plus vite dans l'eau
+ m_reactorRange += rTime*(1.0f/5.0f)*factor;
+ if ( m_reactorRange > 1.0f )
+ {
+ m_reactorRange = 1.0f;
+ if ( m_bLowLevel && m_object->RetSelect() ) // bip froid ?
+ {
+ m_sound->Play(SOUND_INFO, m_object->RetPosition(0), 1.0f, 2.0f);
+ m_bLowLevel = FALSE;
+ }
+ }
+ m_bObstacle = FALSE;
+ }
+ else // en vol ?
+ {
+ m_reactorRange -= rTime*(1.0f/m_object->RetRange());
+ if ( m_reactorRange < 0.0f ) m_reactorRange = 0.0f;
+ if ( m_reactorRange < 0.5f ) m_bLowLevel = TRUE;
+ }
+
+ if ( m_reactorRange == 0.0f ) // réacteur tilté ?
+ {
+ motorSpeed.y = -1.0f; // tombe ...
+ }
+ }
+
+//? MotorParticule(aTime);
+
+ // Avancer/reculer.
+ if ( motorSpeed.x > 0.0f )
+ {
+ m_linMotion.motorAccel.x = m_linMotion.advanceAccel.x;
+ m_linMotion.motorSpeed.x = m_linMotion.advanceSpeed.x * motorSpeed.x;
+ }
+ if ( motorSpeed.x < 0.0f )
+ {
+ m_linMotion.motorAccel.x = m_linMotion.recedeAccel.x;
+ m_linMotion.motorSpeed.x = m_linMotion.recedeSpeed.x * motorSpeed.x;
+ }
+ if ( motorSpeed.x == 0.0f )
+ {
+ m_linMotion.motorAccel.x = m_linMotion.stopAccel.x;
+ m_linMotion.motorSpeed.x = 0.0f;
+ }
+
+ // Monter/descendre.
+ if ( motorSpeed.y > 0.0f )
+ {
+ m_linMotion.motorAccel.y = m_linMotion.advanceAccel.y;
+ m_linMotion.motorSpeed.y = m_linMotion.advanceSpeed.y * motorSpeed.y;
+ }
+ if ( motorSpeed.y < 0.0f )
+ {
+ m_linMotion.motorAccel.y = m_linMotion.recedeAccel.y;
+ m_linMotion.motorSpeed.y = m_linMotion.recedeSpeed.y * motorSpeed.y;
+ }
+ if ( motorSpeed.y == 0.0f )
+ {
+ m_linMotion.motorAccel.y = m_linMotion.stopAccel.y;
+ m_linMotion.motorSpeed.y = 0.0f;
+ }
+
+ // Tourner à gauche/droite.
+ speed = motorSpeed.z;
+//? if ( motorSpeed.x < 0.0f ) speed = -speed; // inverse tourne si recule
+
+ if ( motorSpeed.z > 0.0f )
+ {
+ m_cirMotion.motorAccel.y = m_cirMotion.advanceAccel.y;
+ m_cirMotion.motorSpeed.y = m_cirMotion.advanceSpeed.y * speed;
+ }
+ if ( motorSpeed.z < 0.0f )
+ {
+ m_cirMotion.motorAccel.y = m_cirMotion.recedeAccel.y;
+ m_cirMotion.motorSpeed.y = m_cirMotion.recedeSpeed.y * speed;
+ }
+ if ( motorSpeed.z == 0.0f )
+ {
+ m_cirMotion.motorAccel.y = m_cirMotion.stopAccel.y;
+ m_cirMotion.motorSpeed.y = 0.0f;
+ }
+
+ if ( m_type == TYPE_FLYING && m_bLand ) // volant au sol ?
+ {
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ factor = LANDING_ACCELh;
+ }
+ else
+ {
+ factor = LANDING_ACCEL;
+ }
+ m_linMotion.motorAccel.x = m_linMotion.stopAccel.x*factor;
+ m_cirMotion.motorAccel.y = m_cirMotion.stopAccel.y*factor;
+
+ pos = m_object->RetPosition(0);
+ h = m_terrain->RetFlyingLimit(pos, type==OBJECT_BEE);
+ h += m_object->RetCharacter()->height;
+ if ( motorSpeed.y > 0.0f && m_reactorRange > 0.1f && pos.y < h )
+ {
+ m_bLand = FALSE; // décolle
+ SetMotor(TRUE);
+ pos.y += 0.05f; // petite hauteur initiale (startup)
+ m_object->SetPosition(0, pos);
+ }
+ }
+
+ if ( m_type == TYPE_ROLLING )
+ {
+ if ( motorSpeed.x == 0.0f &&
+ motorSpeed.z == 0.0f )
+ {
+ SetMotor(FALSE);
+ }
+ else
+ {
+ SetMotor(TRUE);
+ }
+ }
+
+ if ( power != 0 ) // pile transportée ?
+ {
+ factor = 1.0f;
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ) factor = 0.5f;
+
+ factor /= power->RetCapacity();
+
+ energy = power->RetEnergy();
+ energy -= Abs(motorSpeed.x)*rTime*factor*0.005f;
+ energy -= Abs(motorSpeed.z)*rTime*factor*0.005f;
+
+ if ( m_type == TYPE_FLYING && motorSpeed.y > 0.0f )
+ {
+ energy -= motorSpeed.y*rTime*factor*0.01f;
+ }
+ if ( energy < 0.0f ) energy = 0.0f;
+ power->SetEnergy(energy);
+ }
+}
+
+
+// Met à jour les effets de vibration et d'inclinaison.
+
+void CPhysics::EffectUpdate(float aTime, float rTime)
+{
+ Character* character;
+ D3DVECTOR vibLin, vibCir, incl;
+ float speedLin, speedCir, accel;
+ ObjectType type;
+ BOOL bOnBoard;
+
+ if ( !m_engine->IsVisiblePoint(m_object->RetPosition(0)) ) return;
+
+ type = m_object->RetType();
+ character = m_object->RetCharacter();
+
+ bOnBoard = FALSE;
+ if ( m_object->RetSelect() &&
+ m_camera->RetType() == CAMERA_ONBOARD )
+ {
+ bOnBoard = TRUE;
+ }
+
+ vibLin = m_motion->RetLinVibration();
+ vibCir = m_motion->RetCirVibration();
+ incl = m_motion->RetInclinaison();
+
+ if ( type == OBJECT_HUMAN || // homme ?
+ type == OBJECT_TECH )
+ {
+ if ( !m_bLand && !m_bSwim ) // en vol ?
+ {
+ vibLin.y = sinf(aTime*2.00f)*0.5f+
+ sinf(aTime*2.11f)*0.3f;
+
+ vibCir.z = sinf(aTime*PI* 2.01f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.51f)*(PI/200.0f)+
+ sinf(aTime*PI*19.01f)*(PI/400.0f);
+
+ vibCir.x = sinf(aTime*PI* 2.03f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.52f)*(PI/200.0f)+
+ sinf(aTime*PI*19.53f)*(PI/400.0f);
+
+ speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x;
+ speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y;
+ incl.x = -speedLin*speedCir*0.5f; // penche si virage
+
+//? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f;
+ speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f;
+ speedLin /= m_linMotion.advanceSpeed.x;
+ m_linMotion.finalInclin.z = speedLin*1.4f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z += rTime*0.4f;
+ if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+ else if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z -= rTime*0.4f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+
+ vibLin *= m_linVibrationFactor;
+ vibCir *= m_cirVibrationFactor;
+ incl *= m_inclinaisonFactor;
+
+ m_motion->SetLinVibration(vibLin);
+ m_motion->SetCirVibration(vibCir);
+ m_motion->SetInclinaison(incl);
+ }
+ else if ( m_bSwim ) // nage ?
+ {
+ vibLin.y = sinf(aTime*2.00f)*0.5f+
+ sinf(aTime*2.11f)*0.3f;
+
+ vibCir.z = sinf(aTime*PI* 2.01f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.51f)*(PI/200.0f)+
+//? sinf(aTime*PI*19.01f)*(PI/400.0f)-PI/2.0f;
+ sinf(aTime*PI*19.01f)*(PI/400.0f);
+
+ vibCir.x = sinf(aTime*PI* 2.03f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.52f)*(PI/200.0f)+
+ sinf(aTime*PI*19.53f)*(PI/400.0f);
+
+ speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x;
+ speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y;
+ incl.x = -speedLin*speedCir*5.0f; // penche si virage
+
+//? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f;
+ speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f;
+ speedLin /= m_linMotion.advanceSpeed.x;
+ m_linMotion.finalInclin.z = speedLin*1.4f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z += rTime*0.4f;
+ if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+ else if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z -= rTime*0.4f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+
+ if ( m_linMotion.realSpeed.y > 0.0f ) // monte ?
+ {
+ vibCir.z += m_linMotion.realSpeed.y*0.05f;
+ }
+ else // descend ?
+ {
+ vibCir.z += m_linMotion.realSpeed.y*0.12f;
+ }
+ vibCir.z -= PI*0.4f;
+
+ vibLin *= m_linVibrationFactor;
+ vibCir *= m_cirVibrationFactor;
+ incl *= m_inclinaisonFactor;
+
+ m_motion->SetLinVibration(vibLin);
+ m_motion->SetCirVibration(vibCir);
+ m_motion->SetInclinaison(incl);
+ }
+ else
+ {
+ m_motion->SetLinVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+//? m_motion->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+//? m_motion->SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ }
+ }
+
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_APOLLO2 ) // roues ?
+ {
+ speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x;
+ speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y;
+ incl.x = speedLin*speedCir*0.20f; // penche si virage
+ if ( type == OBJECT_APOLLO2 ) incl.x *= 0.25f;
+
+ speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x;
+ speedLin /= m_linMotion.advanceSpeed.x;
+ if ( speedLin > 1.0f ) speedLin = 1.0f;
+ m_linMotion.finalInclin.z = -speedLin*0.30f;
+ accel = (0.40f-Abs(incl.z))*4.0f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z += rTime*accel;
+ if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+ else if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z -= rTime*accel;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+ if ( bOnBoard ) incl.z *= 0.1f;
+ if ( type == OBJECT_APOLLO2 ) incl.z *= 0.25f;
+ m_object->SetInclinaison(incl);
+
+ vibLin.x = 0.0f;
+ vibLin.z = 0.0f;
+ vibLin.y = Abs(character->wheelFront*sinf(incl.z))*0.8f +
+ Abs(character->wheelRight*sinf(incl.x))*0.5f;
+ m_motion->SetLinVibration(vibLin);
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+ if ( m_bLand ) // au sol ?
+ {
+ m_motion->SetLinVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_motion->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_motion->SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ }
+ else // en vol ?
+ {
+ vibLin.y = sinf(aTime*2.00f)*0.5f+
+ sinf(aTime*2.11f)*0.3f;
+
+ vibCir.z = sinf(aTime*PI* 2.01f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.51f)*(PI/200.0f)+
+ sinf(aTime*PI*19.01f)*(PI/400.0f);
+
+ vibCir.x = sinf(aTime*PI* 2.03f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.52f)*(PI/200.0f)+
+ sinf(aTime*PI*19.53f)*(PI/400.0f);
+
+ if ( bOnBoard ) vibCir *= 0.4f;
+
+ speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x;
+ speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y;
+ incl.x = -speedLin*speedCir*0.5f; // penche si virage
+
+//? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f;
+ speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f;
+ speedLin /= m_linMotion.advanceSpeed.x;
+ m_linMotion.finalInclin.z = speedLin*0.8f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z += rTime*0.4f;
+ if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+ else if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z -= rTime*0.4f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+//? if ( bOnBoard ) incl.z *= 0.5f;
+
+ vibLin *= m_linVibrationFactor;
+ vibCir *= m_cirVibrationFactor;
+ incl *= m_inclinaisonFactor;
+
+ m_motion->SetLinVibration(vibLin);
+ m_motion->SetCirVibration(vibCir);
+ m_motion->SetInclinaison(incl);
+ }
+ }
+
+ if ( type == OBJECT_BEE ) // abeille ?
+ {
+ if ( !m_bLand ) // en vol ?
+ {
+ vibLin.y = sinf(aTime*2.00f)*0.5f+
+ sinf(aTime*2.11f)*0.3f;
+
+ vibCir.z = (Rand()-0.5f)*0.1f+
+ sinf(aTime*PI* 2.01f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.51f)*(PI/200.0f)+
+ sinf(aTime*PI*19.01f)*(PI/400.0f);
+
+ vibCir.x = (Rand()-0.5f)*0.1f+
+ sinf(aTime*PI* 2.03f)*(PI/150.0f)+
+ sinf(aTime*PI* 2.52f)*(PI/200.0f)+
+ sinf(aTime*PI*19.53f)*(PI/400.0f);
+
+ speedLin = m_linMotion.realSpeed.x / m_linMotion.advanceSpeed.x;
+ speedCir = m_cirMotion.realSpeed.y / m_cirMotion.advanceSpeed.y;
+ incl.x = -speedLin*speedCir*1.5f; // penche si virage
+
+//? speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.5f;
+ speedLin = m_linMotion.currentSpeed.x - m_linMotion.motorSpeed.x*1.2f;
+ speedLin /= m_linMotion.advanceSpeed.x;
+ m_linMotion.finalInclin.z = speedLin*1.4f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z += rTime*1.6f;
+ if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+ else if ( incl.z > m_linMotion.finalInclin.z )
+ {
+ incl.z -= rTime*1.6f;
+ if ( incl.z < m_linMotion.finalInclin.z )
+ {
+ incl.z = m_linMotion.finalInclin.z;
+ }
+ }
+
+ vibLin *= m_linVibrationFactor;
+ vibCir *= m_cirVibrationFactor;
+ incl *= m_inclinaisonFactor;
+
+ m_motion->SetLinVibration(vibLin);
+ m_motion->SetCirVibration(vibCir);
+ m_motion->SetInclinaison(incl);
+ }
+ }
+}
+
+
+// Met à jour une structure Motion.
+
+void CPhysics::UpdateMotionStruct(float rTime, Motion &motion)
+{
+ float speed, motor;
+
+ // Gestion de la coordonnée x.
+ speed = motion.currentSpeed.x;
+ motor = motion.motorSpeed.x * m_inclinaisonFactor;
+ if ( speed < motor )
+ {
+ speed += rTime*motion.motorAccel.x; // accélère
+ if ( speed > motor )
+ {
+ speed = motor; // ne dépasse pas la vitesse
+ }
+ }
+ if ( speed > motor )
+ {
+ speed -= rTime*motion.motorAccel.x; // déccélère
+ if ( speed < motor )
+ {
+ speed = motor; // ne dépasse pas la vitesse
+ }
+ }
+ motion.currentSpeed.x = speed;
+ motion.realSpeed.x = speed;
+
+ if ( Abs(motion.terrainSpeed.x) > motion.terrainSlide.x )
+ {
+ if ( motion.terrainSpeed.x > 0 )
+ {
+ speed = motion.terrainSpeed.x - motion.terrainSlide.x;
+ }
+ else
+ {
+ speed = motion.terrainSpeed.x + motion.terrainSlide.x;
+ }
+ motion.realSpeed.x += speed;
+ }
+
+ // Gestion de la coordonnée y.
+ speed = motion.currentSpeed.y;
+ motor = motion.motorSpeed.y; // vitesse non limitée !
+ if ( speed < motor )
+ {
+ speed += rTime*motion.motorAccel.y; // accélère
+ if ( speed > motor )
+ {
+ speed = motor; // ne dépasse pas la vitesse
+ }
+ }
+ if ( speed > motor )
+ {
+ speed -= rTime*motion.motorAccel.y; // déccélère
+ if ( speed < motor )
+ {
+ speed = motor; // ne dépasse pas la vitesse
+ }
+ }
+ motion.currentSpeed.y = speed;
+ motion.realSpeed.y = speed;
+
+ if ( Abs(motion.terrainSpeed.y) > motion.terrainSlide.y )
+ {
+ if ( motion.terrainSpeed.y > 0 )
+ {
+ speed = motion.terrainSpeed.y - motion.terrainSlide.y;
+ }
+ else
+ {
+ speed = motion.terrainSpeed.y + motion.terrainSlide.y;
+ }
+ motion.realSpeed.y += speed;
+ }
+
+ // Gestion de la coordonnée z.
+ speed = motion.currentSpeed.z;
+ motor = motion.motorSpeed.z * m_inclinaisonFactor;
+ if ( speed < motor )
+ {
+ speed += rTime*motion.motorAccel.z; // accélère
+ if ( speed > motor )
+ {
+ speed = motor; // ne dépasse pas la vitesse
+ }
+ }
+ if ( speed > motor )
+ {
+ speed -= rTime*motion.motorAccel.z; // déccélère
+ if ( speed < motor )
+ {
+ speed = motor; // ne dépasse pas la vitesse
+ }
+ }
+ motion.currentSpeed.z = speed;
+ motion.realSpeed.z = speed;
+
+ if ( Abs(motion.terrainSpeed.z) > motion.terrainSlide.z )
+ {
+ if ( motion.terrainSpeed.z > 0 )
+ {
+ speed = motion.terrainSpeed.z - motion.terrainSlide.z;
+ }
+ else
+ {
+ speed = motion.terrainSpeed.z + motion.terrainSlide.z;
+ }
+ motion.realSpeed.z += speed;
+ }
+}
+
+
+// Fait évoluer la physique selon le temps écoulé.
+// Retourne FALSE si l'objet est détruit.
+//
+// a: accélération
+// v1: vitesse au temps t1
+// v2: vitesse au temps t2
+// dt: temps écoulé depuis t1, donc: dt=t2-t1
+// dd: différence de distance (avance)
+//
+// v2 = v1 + a*dt
+// dd = v2*dt
+
+BOOL CPhysics::EventFrame(const Event &event)
+{
+ ObjectType type;
+ D3DMATRIX objRotate, matRotate;
+ D3DVECTOR iPos, iAngle, tAngle, pos, newpos, angle, newangle, n;
+ float h, w;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ m_time += event.rTime;
+ m_timeUnderWater += event.rTime;
+ m_soundTimeJostle += event.rTime;
+
+ type = m_object->RetType();
+
+ FrameParticule(m_time, event.rTime);
+ MotorUpdate(m_time, event.rTime);
+ EffectUpdate(m_time, event.rTime);
+ WaterFrame(m_time, event.rTime);
+
+ iPos = pos = m_object->RetPosition(0);
+ iAngle = angle = m_object->RetAngle(0);
+
+ // Accélère à la descente, freine à la montée.
+ if ( m_bFreeze || m_object->RetDead() )
+ {
+ m_linMotion.terrainSpeed.x = 0.0f;
+ m_linMotion.terrainSpeed.z = 0.0f;
+ m_linMotion.terrainSpeed.y = 0.0f;
+ }
+ else
+ {
+ tAngle = angle;
+ h = m_terrain->RetBuildingFactor(pos);
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ if ( m_linMotion.currentSpeed.x == 0.0f )
+ {
+ h *= 0.5f; // homme immobile -> glisse moins
+ }
+ FloorAngle(pos, tAngle); // calcule l'angle avec le terrain
+ }
+#if 1
+ if ( pos.y < m_water->RetLevel(m_object) ) // sous l'eau ?
+ {
+ h *= 0.5f;
+ }
+#endif
+//? m_linMotion.terrainSpeed.x = -tAngle.z*m_linMotion.terrainForce.x*h;
+//? m_linMotion.terrainSpeed.z = tAngle.x*m_linMotion.terrainForce.z*h;
+//? m_linMotion.terrainSpeed.x = -sinf(tAngle.z)*PI*0.5f*m_linMotion.terrainForce.x*h;
+//? m_linMotion.terrainSpeed.z = sinf(tAngle.x)*PI*0.5f*m_linMotion.terrainForce.z*h;
+ m_linMotion.terrainSpeed.x = -tanf(tAngle.z)*0.9f*m_linMotion.terrainForce.x*h;
+ m_linMotion.terrainSpeed.z = tanf(tAngle.x)*0.9f*m_linMotion.terrainForce.z*h;
+ m_linMotion.terrainSpeed.y = 0.0f;
+
+ // Si le terrain est très pentu, n'exagère pas !
+ if ( m_linMotion.terrainSpeed.x > 50.0f ) m_linMotion.terrainSpeed.x = 20.0f;
+ if ( m_linMotion.terrainSpeed.x < -50.0f ) m_linMotion.terrainSpeed.x = -20.0f;
+ if ( m_linMotion.terrainSpeed.z > 50.0f ) m_linMotion.terrainSpeed.z = 20.0f;
+ if ( m_linMotion.terrainSpeed.z < -50.0f ) m_linMotion.terrainSpeed.z = -20.0f;
+ }
+
+ if ( type == OBJECT_BEE && !m_bLand )
+ {
+ h = m_floorLevel; // niveau du sol
+ w = m_water->RetLevel(m_object);
+ if ( h < w ) h = w;
+ h = pos.y-h-10.0f; // hauteur maximale (*)
+ if ( h < 0.0f ) h = 0.0f;
+ m_linMotion.terrainSpeed.y = -h*2.5f; // ne va pas plus haut
+ }
+
+ // (*) Assez haut pour passer par-dessus la tour de défence
+ // (OBJECT_TOWER), mais pas trop pour passer sous la coiffe
+ // du vaisseau (OBJECT_BASE) !
+
+ UpdateMotionStruct(event.rTime, m_linMotion);
+ UpdateMotionStruct(event.rTime, m_cirMotion);
+
+ newangle = angle + event.rTime*m_cirMotion.realSpeed;
+ MatRotateZXY(matRotate, newangle);
+ newpos = event.rTime*m_linMotion.realSpeed;
+ newpos = Transform(matRotate, newpos);
+ newpos += pos;
+
+ m_terrain->LimitPos(newpos);
+
+ if ( m_type == TYPE_FLYING && !m_bLand )
+ {
+ h = m_terrain->RetFlyingLimit(newpos, type==OBJECT_BEE);
+ h += m_object->RetCharacter()->height;
+ if ( newpos.y > h ) newpos.y = h;
+ }
+
+ if ( m_bForceUpdate ||
+ newpos.x != pos.x ||
+ newpos.y != pos.y ||
+ newpos.z != pos.z ||
+ newangle.x != angle.x ||
+ newangle.y != angle.y ||
+ newangle.z != angle.z )
+ {
+ FloorAdapt(m_time, event.rTime, newpos, newangle);
+ }
+
+ if ( m_bForceUpdate ||
+ newpos.x != pos.x ||
+ newpos.y != pos.y ||
+ newpos.z != pos.z )
+ {
+ i = ObjectAdapt(newpos, newangle);
+ if ( i == 2 ) // objet détruit ?
+ {
+ return FALSE;
+ }
+ if ( i == 1 ) // objet immobile ?
+ {
+ newpos = iPos; // garde la position initiale, mais accepte la rotation
+ }
+ }
+
+ if ( newangle.x != angle.x ||
+ newangle.y != angle.y ||
+ newangle.z != angle.z )
+ {
+ m_object->SetAngle(0, newangle);
+ }
+
+ if ( newpos.x != pos.x ||
+ newpos.y != pos.y ||
+ newpos.z != pos.z )
+ {
+ m_object->SetPosition(0, newpos);
+ }
+
+ MotorParticule(m_time, event.rTime);
+ SoundMotor(event.rTime);
+
+ m_bForceUpdate = FALSE;
+
+ return TRUE;
+}
+
+// Démarre ou stoppe les bruits de moteur.
+
+void CPhysics::SoundMotor(float rTime)
+{
+ CObject* power;
+ ObjectType type;
+ float energy;
+
+ m_lastSoundInsect -= rTime;
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOTHER )
+ {
+ if ( m_lastSoundInsect <= 0.0f && m_object->RetActif() )
+ {
+ m_sound->Play(SOUND_INSECTm, m_object->RetPosition(0));
+ if ( m_bMotor ) m_lastSoundInsect = 0.4f+Rand()*2.5f;
+ else m_lastSoundInsect = 1.5f+Rand()*4.0f;
+ }
+ }
+ else if ( type == OBJECT_ANT )
+ {
+ if ( m_object->RetBurn() ||
+ m_object->RetFixed() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTa, m_object->RetPosition(0), 1.0f, 1.5f+Rand()*0.5f);
+ m_lastSoundInsect = 0.4f+Rand()*0.6f;
+ }
+ }
+ else if ( m_object->RetActif() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTa, m_object->RetPosition(0));
+ if ( m_bMotor ) m_lastSoundInsect = 0.4f+Rand()*2.5f;
+ else m_lastSoundInsect = 1.5f+Rand()*4.0f;
+ }
+ }
+ }
+ else if ( type == OBJECT_BEE )
+ {
+ if ( m_object->RetActif() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTb, m_object->RetPosition(0));
+ if ( m_bMotor ) m_lastSoundInsect = 0.4f+Rand()*2.5f;
+ else m_lastSoundInsect = 1.5f+Rand()*4.0f;
+ }
+ }
+ else if ( m_object->RetBurn() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTb, m_object->RetPosition(0), 1.0f, 1.5f+Rand()*0.5f);
+ m_lastSoundInsect = 0.3f+Rand()*0.5f;
+ }
+ }
+ }
+ else if ( type == OBJECT_WORM )
+ {
+ if ( m_object->RetActif() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTw, m_object->RetPosition(0));
+ if ( m_bMotor ) m_lastSoundInsect = 0.4f+Rand()*2.5f;
+ else m_lastSoundInsect = 1.5f+Rand()*4.0f;
+ }
+ }
+ else if ( m_object->RetBurn() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTw, m_object->RetPosition(0), 1.0f, 1.5f+Rand()*0.5f);
+ m_lastSoundInsect = 0.2f+Rand()*0.2f;
+ }
+ }
+ }
+ else if ( type == OBJECT_SPIDER )
+ {
+ if ( m_object->RetBurn() ||
+ m_object->RetFixed() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTs, m_object->RetPosition(0), 1.0f, 1.5f+Rand()*0.5f);
+ m_lastSoundInsect = 0.4f+Rand()*0.6f;
+ }
+ }
+ else if ( m_object->RetActif() )
+ {
+ if ( m_lastSoundInsect <= 0.0f )
+ {
+ m_sound->Play(SOUND_INSECTs, m_object->RetPosition(0));
+ if ( m_bMotor ) m_lastSoundInsect = 0.4f+Rand()*2.5f;
+ else m_lastSoundInsect = 1.5f+Rand()*4.0f;
+ }
+ }
+ }
+ else // véhicule ?
+ {
+ if ( m_type == TYPE_ROLLING )
+ {
+ if ( m_bMotor && m_object->RetActif() )
+ {
+ SoundMotorFull(rTime, type); // plein régime
+ }
+ else
+ {
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( m_object->RetSelect() &&
+ energy != 0.0f )
+ {
+ SoundMotorSlow(rTime, type); // au ralenti
+ }
+ else
+ {
+ SoundMotorStop(rTime, type); // à l'arrêt
+ }
+ }
+ }
+
+ if ( m_type == TYPE_FLYING )
+ {
+ if ( m_bMotor && !m_bSwim &&
+ m_object->RetActif() && !m_object->RetDead() )
+ {
+ SoundReactorFull(rTime, type); // plein régime
+ }
+ else
+ {
+ SoundReactorStop(rTime, type); // à l'arrêt
+ }
+ }
+ }
+}
+
+// Fait exploser l'objet s'il est sous l'eau.
+
+void CPhysics::WaterFrame(float aTime, float rTime)
+{
+ ObjectType type;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float level;
+
+ level = m_water->RetLevel();
+ if ( level == 0.0f ) return; // pas d'eau ?
+ if ( m_object->RetTruck() != 0 ) return; // objet transporté ?
+
+ // Gestion des flammes dans la lave.
+ pos = m_object->RetPosition(0);
+ if ( m_water->RetLava() &&
+ pos.y-m_object->RetCharacter()->height <= level )
+ {
+ if ( m_lastFlameParticule+m_engine->ParticuleAdapt(0.05f) <= aTime )
+ {
+ m_lastFlameParticule = aTime;
+
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = Rand()*5.0f+3.0f;
+ dim.x = Rand()*2.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
+
+ pos = m_object->RetPosition(0);
+ pos.y -= 2.0f;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 6.0f+Rand()*6.0f+6.0f;
+ dim.x = Rand()*1.5f+1.0f+3.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+ }
+
+ pos = m_object->RetPosition(0);
+ if ( pos.y >= m_water->RetLevel(m_object) ) return; // hors de l'eau ?
+
+ type = m_object->RetType();
+ if ( type == OBJECT_TOTO ) return;
+ if ( type == OBJECT_NULL ) return;
+
+ if ( !m_object->RetActif() ) return;
+ if ( m_object->RetResetBusy() ) return; // reset en cours ?
+
+ if ( m_water->RetLava() ||
+ (type == OBJECT_HUMAN &&
+ m_object->RetOption() != 0 ) || // homme sans casque ?
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_APOLLO2 ) // véhicule non sous-marin ?
+ {
+ m_object->ExploObject(EXPLO_WATER, 1.0f); // démarre explosion
+ }
+}
+
+// Fait entendre le moteur à plein régime.
+
+void CPhysics::SoundMotorFull(float rTime, ObjectType type)
+{
+ Sound sound;
+ float amplitude, time, freq;
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis )
+ {
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_MOTORi, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 0.2f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_LOOP);
+ }
+ else
+ {
+ m_sound->Position(m_soundChannel, m_object->RetPosition(0));
+ }
+
+ freq = 1.0f+m_linMotion.terrainSpeed.x/50.0f;
+ if ( m_linMotion.realSpeed.x == 0.0f )
+ {
+ freq -= Abs(m_cirMotion.realSpeed.y/3.0f);
+ }
+ else
+ {
+ freq -= Abs(m_cirMotion.realSpeed.y/4.0f);
+ }
+ m_sound->Frequency(m_soundChannel, freq);
+
+ return;
+ }
+
+ if ( type == OBJECT_MOBILEsa )
+ {
+ sound = SOUND_MOTORs;
+ amplitude = 0.6f;
+ time = 0.5f;
+ }
+ else if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ sound = SOUND_MOTORr;
+ amplitude = 1.0f;
+ time = 0.7f;
+ }
+ else if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts )
+ {
+ sound = SOUND_MOTORt;
+ amplitude = 1.0f;
+ time = 0.5f;
+ }
+ else if ( type == OBJECT_APOLLO2 )
+ {
+ sound = SOUND_MANIP;
+ amplitude = 1.0f;
+ time = 0.5f;
+ }
+ else
+ {
+ sound = SOUND_MOTORw;
+ amplitude = 0.7f;
+ time = 0.3f;
+ }
+
+ if ( m_object->RetToy() )
+ {
+ sound = SOUND_MOTORd;
+ amplitude = 1.0f;
+ time = 0.1f;
+ }
+
+ freq = 0.75f+(Abs(m_motorSpeed.x)+Abs(m_motorSpeed.z))*0.25f;
+ if ( freq > 1.0f ) freq = 1.0f;
+ if ( m_object->RetToy() ) freq = 1.0f;
+
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(sound, m_object->RetPosition(0), 0.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, freq, time, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, freq, 1.0f, SOPER_LOOP);
+ }
+ else
+ {
+ m_sound->Position(m_soundChannel, m_object->RetPosition(0));
+
+ if ( m_bSoundSlow ) // au ralenti ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, freq, time, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, freq, 1.0f, SOPER_LOOP);
+ m_bSoundSlow = FALSE;
+ }
+ }
+
+ freq *= 1.0f + m_linMotion.terrainSpeed.x/100.0f;
+ freq *= 1.0f + Abs(m_cirMotion.realSpeed.y/20.0f);
+ m_sound->Frequency(m_soundChannel, freq);
+
+ m_soundTimePshhh -= rTime*2.0f;
+}
+
+// Fait entendre le moteur au ralenti.
+
+void CPhysics::SoundMotorSlow(float rTime, ObjectType type)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ Sound sound;
+ float amplitude;
+ int i, max;
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis )
+ {
+ if ( m_soundChannel != -1 ) // moteur tourne ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+ return;
+ }
+
+ if ( type == OBJECT_MOBILEsa )
+ {
+ sound = SOUND_MOTORs;
+ amplitude = 0.4f;
+ }
+ else if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ sound = SOUND_MOTORr;
+ amplitude = 0.9f;
+ }
+ else if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts )
+ {
+ sound = SOUND_MOTORt;
+ amplitude = 0.7f;
+ }
+ else if ( type == OBJECT_APOLLO2 )
+ {
+ if ( m_soundChannel != -1 ) // moteur tourne ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+ return;
+ }
+ else
+ {
+ sound = SOUND_MOTORw;
+ amplitude = 0.3f;
+ }
+
+ if ( m_object->RetToy() )
+ {
+ sound = SOUND_MOTORd;
+ amplitude = 0.0f;
+ }
+
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(sound, m_object->RetPosition(0), 0.0f, 0.25f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 0.2f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 1.0f, SOPER_LOOP);
+ }
+ else
+ {
+ m_sound->Position(m_soundChannel, m_object->RetPosition(0));
+
+ if ( !m_bSoundSlow ) // plein régime ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 0.3f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, amplitude, 0.5f, 1.0f, SOPER_LOOP);
+ m_bSoundSlow = TRUE;
+ }
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ m_soundTimePshhh -= rTime;
+
+ if ( m_soundTimePshhh <= 0.0f )
+ {
+ amplitude = 0.5f-m_soundTimePshhh*0.08f;
+ if ( amplitude > 1.0f ) amplitude = 1.0f;
+//? m_sound->Play(SOUND_PSHHH, m_object->RetPosition(0), amplitude);
+ m_sound->Play(SOUND_PSHHH, m_object->RetPosition(0), 1.0f);
+
+ m_soundTimePshhh = 4.0f+4.0f*Rand();
+
+ max = (int)(10.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ pos = D3DVECTOR(-5.0f, 2.0f, 0.0f);
+ pos.x += Rand()*4.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+
+ speed = pos;
+ speed.x -= Rand()*4.0f;
+ speed.y -= Rand()*3.0f;
+ speed.z += (Rand()-0.5f)*6.0f;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed = Transform(*mat, speed)-pos;
+
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIMOTOR, 2.0f);
+ }
+ }
+ }
+}
+
+// Fait entendre le moteur à l'arrêt.
+
+void CPhysics::SoundMotorStop(float rTime, ObjectType type)
+{
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis )
+ {
+ if ( m_soundChannel != -1 ) // moteur tourne ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+ return;
+ }
+
+ if ( m_soundChannel != -1 ) // moteur tourne ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_soundTimePshhh -= rTime*2.0f;
+}
+
+// Fait entendre le réacteur à plein régime.
+
+void CPhysics::SoundReactorFull(float rTime, ObjectType type)
+{
+ Sound sound;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float freq;
+ int i;
+
+ if ( m_soundChannelSlide != -1 ) // glisse ?
+ {
+ m_sound->FlushEnvelope(m_soundChannelSlide);
+ m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannelSlide = -1;
+ }
+
+ if ( m_reactorRange > 0.0f )
+ {
+ if ( m_soundChannel == -1 )
+ {
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ sound = SOUND_FLYh;
+ }
+ else
+ {
+ sound = SOUND_FLY;
+ }
+
+ m_soundChannel = m_sound->Play(sound, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 0.6f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_LOOP);
+ }
+ else
+ {
+ m_sound->Position(m_soundChannel, m_object->RetPosition(0));
+ }
+
+ freq = 1.0f + m_linMotion.realSpeed.y/100.0f;
+ freq *= 1.0f + Abs(m_cirMotion.realSpeed.y/5.0f);
+ m_sound->Frequency(m_soundChannel, freq);
+ }
+ else
+ {
+ if ( m_soundChannel != -1 ) // moteur tourne ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ if ( m_timeReactorFail <= m_time )
+ {
+ freq = 1.0f+Rand()*0.5f;
+ m_sound->Play(SOUND_FLYf, m_object->RetPosition(0), 1.0f, freq);
+ m_camera->StartEffect(CE_PET, m_object->RetPosition(0), 1.0f);
+
+ for ( i=0 ; i<5 ; i++ )
+ {
+ if ( m_object->RetType() == OBJECT_HUMAN ||
+ m_object->RetType() == OBJECT_TECH )
+ {
+ pos = D3DVECTOR(-1.6f, -0.5f, 0.0f);
+ }
+ else
+ {
+ pos = D3DVECTOR(0.0f, -1.0f, 0.0f);
+ }
+ pos.x += (Rand()-0.5f)*2.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed.x = (Rand()-0.5f)*5.0f;
+ speed.z = (Rand()-0.5f)*5.0f;
+ speed.y = -(4.0f+Rand()*4.0f);
+ dim.x = (2.0f+Rand()*1.0f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 2.0f, 0.0f, 0.1f);
+ }
+
+ m_timeReactorFail = m_time+0.10f+Rand()*0.30f;
+ }
+ else
+ {
+ if ( m_object->RetType() == OBJECT_HUMAN ||
+ m_object->RetType() == OBJECT_TECH )
+ {
+ pos = D3DVECTOR(-1.6f, -0.5f, 0.0f);
+ }
+ else
+ {
+ pos = D3DVECTOR(0.0f, -1.0f, 0.0f);
+ }
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = -(4.0f+Rand()*4.0f);
+ dim.x = (0.7f+Rand()*0.4f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 2.0f, 0.0f, 0.1f);
+ }
+ }
+
+}
+
+// Fait entendre le réacteur à l'arrêt.
+
+void CPhysics::SoundReactorStop(float rTime, ObjectType type)
+{
+ CObject* power;
+ float energy;
+
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( m_soundChannel != -1 ) // moteur tourne ?
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ if ( m_soundChannelSlide != -1 ) // glisse ?
+ {
+ m_sound->FlushEnvelope(m_soundChannelSlide);
+ m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannelSlide = -1;
+ }
+ }
+ else
+ {
+ if ( energy != 0.0f &&
+ (m_motorSpeed.x != 0.0f || // glisse avec petits réacteurs dans patins ?
+ m_cirMotion.realSpeed.y != 0.0f) )
+ {
+ if ( m_soundChannelSlide == -1 )
+ {
+ m_soundChannelSlide = m_sound->Play(SOUND_SLIDE, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannelSlide, 0.5f, 1.0f, 0.3f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannelSlide, 0.5f, 1.0f, 1.0f, SOPER_LOOP);
+ }
+ m_sound->Position(m_soundChannelSlide, m_object->RetPosition(0));
+ }
+ else
+ {
+ if ( m_soundChannelSlide != -1 ) // glisse ?
+ {
+ m_sound->FlushEnvelope(m_soundChannelSlide);
+ m_sound->AddEnvelope(m_soundChannelSlide, 0.0f, 1.0f, 0.3f, SOPER_STOP);
+ m_soundChannelSlide = -1;
+ }
+ }
+ }
+}
+
+
+// Adapte la physique de l'objet en fonction du terrain.
+
+void CPhysics::FloorAdapt(float aTime, float rTime,
+ D3DVECTOR &pos, D3DVECTOR &angle)
+{
+ Character* character;
+ ObjectType type;
+ D3DVECTOR norm;
+ D3DMATRIX matRotate;
+ float level, h, f, a1, volume, freq, force;
+ BOOL bOldSwim, bSlopingTerrain;
+
+ type = m_object->RetType();
+ character = m_object->RetCharacter();
+
+ level = m_water->RetLevel(m_object);
+ bOldSwim = m_bSwim;
+ SetSwim( pos.y < level );
+
+ m_floorLevel = m_terrain->RetFloorLevel(pos); // hauteur au-dessus du sol
+ h = pos.y-m_floorLevel;
+ h -= character->height;
+ m_floorHeight = h;
+
+ WaterParticule(aTime, pos, type, m_floorLevel,
+ Abs(m_linMotion.realSpeed.x),
+ Abs(m_cirMotion.realSpeed.y*15.0f));
+
+ if ( m_type == TYPE_ROLLING )
+ {
+ pos.y -= h; // plaque immédiatement au sol
+ pos.y += character->height;
+ m_floorHeight = 0.0f;
+ }
+
+ if ( m_type == TYPE_FLYING )
+ {
+ bSlopingTerrain = FALSE; // terrain possible pour atterrir
+
+ if ( !m_bLand ) // en vol ?
+ {
+ m_terrain->GetNormal(norm, pos);
+ a1 = Abs(RotateAngle(Length(norm.x, norm.z), norm.y));
+ if ( a1 < (90.0f-55.0f)*PI/180.0f ) // pente dépasse 55 degrés ?
+ {
+ bSlopingTerrain = TRUE; // terrain très pentu
+
+ if ( h < 4.0f ) // choc avec le terrain ?
+ {
+ force = 5.0f+Abs(m_linMotion.realSpeed.x*0.3f)+
+ Abs(m_linMotion.realSpeed.y*0.3f);
+ m_linMotion.currentSpeed = norm*force;
+ MatRotateXZY(matRotate, -angle);
+ m_linMotion.currentSpeed = Transform(matRotate, m_linMotion.currentSpeed);
+
+ if ( aTime-m_soundTimeBoum > 0.5f )
+ {
+ volume = Abs(m_linMotion.realSpeed.x*0.02f)+
+ Abs(m_linMotion.realSpeed.y*0.02f);
+ freq = 0.5f+m_terrain->RetHardness(pos)*2.5f;
+ m_sound->Play(SOUND_BOUM, pos, volume, freq);
+
+ m_soundTimeBoum = aTime;
+ }
+
+//? pos = m_object->RetPosition(0); // remet pos avant collision
+ }
+ }
+ }
+
+ if ( (h <= 0.0f || m_bLand) && !bSlopingTerrain ) // au sol ?
+ {
+ if ( !m_bLand ) // en vol ?
+ {
+ volume = Abs(m_linMotion.realSpeed.y*0.02f);
+ freq = 0.5f+m_terrain->RetHardness(pos)*2.5f;
+ m_sound->Play(SOUND_BOUM, pos, volume, freq);
+ }
+
+ m_bLand = TRUE; // au sol
+ SetMotor(FALSE);
+ pos.y -= h; // plaque immédiatement au sol
+ m_floorHeight = 0.0f;
+
+ if ( h < 0.0f )
+ {
+ f = Abs(m_linMotion.currentSpeed.y/m_linMotion.advanceSpeed.y);
+ CrashParticule(f);
+ }
+ m_linMotion.currentSpeed.y = 0.0f;
+ m_inclinaisonFactor = 1.0f/LANDING_SPEED; // glisse un peu au sol
+ m_linVibrationFactor = 0.0f;
+ m_cirVibrationFactor = 0.0f;
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ) return; // toujours droit
+ }
+
+ if ( h > 4.0f || bSlopingTerrain ) // très au-dessus du sol ?
+ {
+ if ( m_bSwim )
+ {
+ m_linVibrationFactor = 1.0f; // vibre un max
+ m_cirVibrationFactor = 1.0f;
+ }
+ else
+ {
+ m_linVibrationFactor = 2.0f; // vibre un gros max
+ m_cirVibrationFactor = 2.0f;
+ }
+ m_inclinaisonFactor = 1.0f;
+
+ // Remet gentiment à l'horizontale.
+ if ( angle.x > 0.0f )
+ {
+ angle.x -= rTime*0.5f;
+ if ( angle.x < 0.0f ) angle.x = 0.0f;
+ }
+ if ( angle.x < 0.0f )
+ {
+ angle.x += rTime*0.5f;
+ if ( angle.x > 0.0f ) angle.x = 0.0f;
+ }
+ if ( angle.z > 0.0f )
+ {
+ angle.z -= rTime*0.5f;
+ if ( angle.z < 0.0f ) angle.z = 0.0f;
+ }
+ if ( angle.z < 0.0f )
+ {
+ angle.z += rTime*0.5f;
+ if ( angle.z > 0.0f ) angle.z = 0.0f;
+ }
+ return;
+ }
+ }
+
+ if ( m_floorHeight == 0.0f ) // plaqué au sol ?
+ {
+ if ( m_object->RetTraceDown() )
+ {
+ WheelParticule(m_object->RetTraceColor(), m_object->RetTraceWidth()*g_unit);
+ }
+ else
+ {
+ WheelParticule(-1, 0.0f);
+ }
+ }
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_WORM ) return; // toujours droit
+
+ FloorAngle(pos, angle); // adapte l'angle au terrain
+
+ if ( m_type == TYPE_FLYING && !m_bLand ) // volant en l'air ?
+ {
+ f = h/1.0f;
+ if ( f < 0.0f ) f = 0.0f;
+ if ( f > 1.0f ) f = 1.0f;
+ m_linVibrationFactor = f;
+ m_cirVibrationFactor = f;
+ angle.z *= 1.0f-f;
+ angle.x *= 1.0f-f;
+
+ f = h/1.0f;
+ if ( f < 0.0f ) f = 0.0f;
+ if ( f > 1.0f ) f = 1.0f;
+ m_inclinaisonFactor = f;
+ }
+}
+
+// Calcule l'angle d'un objet avec le terrain.
+
+void CPhysics::FloorAngle(const D3DVECTOR &pos, D3DVECTOR &angle)
+{
+ Character* character;
+ D3DVECTOR pw, norm;
+ float a1, a2;
+
+ character = m_object->RetCharacter();
+
+ pw.x = pos.x+character->wheelFront*cosf(angle.y+PI*0.0f);
+ pw.y = pos.y;
+ pw.z = pos.z-character->wheelFront*sinf(angle.y+PI*0.0f);
+ a1 = atanf(m_terrain->RetFloorHeight(pw)/character->wheelFront);
+
+ pw.x = pos.x+character->wheelBack*cosf(angle.y+PI*1.0f);
+ pw.y = pos.y;
+ pw.z = pos.z-character->wheelBack*sinf(angle.y+PI*1.0f);
+ a2 = atanf(m_terrain->RetFloorHeight(pw)/character->wheelBack);
+
+ angle.z = (a2-a1)/2.0f;
+
+ pw.x = pos.x+character->wheelLeft*cosf(angle.y+PI*0.5f)*cosf(angle.z);
+ pw.y = pos.y;
+ pw.z = pos.z-character->wheelLeft*sinf(angle.y+PI*0.5f)*cosf(angle.z);
+ a1 = atanf(m_terrain->RetFloorHeight(pw)/character->wheelLeft);
+
+ pw.x = pos.x+character->wheelRight*cosf(angle.y+PI*1.5f)*cosf(angle.z);
+ pw.y = pos.y;
+ pw.z = pos.z-character->wheelRight*sinf(angle.y+PI*1.5f)*cosf(angle.z);
+ a2 = atanf(m_terrain->RetFloorHeight(pw)/character->wheelRight);
+
+ angle.x = (a2-a1)/2.0f;
+}
+
+
+// Adapte la physique de l'objet en fonction des autres objets.
+// Retourne 0 -> objet mobile
+// Retourne 1 -> objet immobile (à cause collision)
+// Retourne 2 -> objet détruit
+
+int CPhysics::ObjectAdapt(const D3DVECTOR &pos, const D3DVECTOR &angle)
+{
+ CObject* pObj;
+ CPyro* pyro;
+ CPhysics* ph;
+ D3DMATRIX matRotate;
+ D3DVECTOR iPos, oPos, iiPos, oAngle, oSpeed;
+ Sound sound;
+ float iRad, oRad, distance, force, volume;
+ int i, j, colType;
+ ObjectType iType, oType;
+
+ if ( m_object->RetRuin() ) return 0; // brûle ou explose ?
+ if ( !m_object->RetClip() ) return 0;
+
+ // iiPos = centre sphère à l'ancienne position.
+ // iPos = centre sphère à la nouvelle position.
+ m_object->GetCrashSphere(0, iiPos, iRad);
+ iPos = iiPos + (pos - m_object->RetPosition(0));
+ iType = m_object->RetType();
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue; // soi-même ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( !pObj->RetEnable() ) continue; // inactif ?
+ if ( pObj->RetRuin() ) continue; // brûle ou explose ?
+ if ( pObj->RetDead() ) continue; // homme mort ?
+
+ oType = pObj->RetType();
+ if ( oType == OBJECT_NULL ) continue;
+ if ( oType == OBJECT_TOTO ) continue;
+//? if ( iType == OBJECT_BEE && oType == OBJECT_BEE ) continue;
+ if ( iType == OBJECT_WORM && oType != OBJECT_WORM ) continue;
+ if ( iType != OBJECT_WORM && oType == OBJECT_WORM ) continue;
+ if ( iType == OBJECT_MOTHER && oType == OBJECT_ANT ) continue;
+ if ( iType == OBJECT_ANT && oType == OBJECT_MOTHER ) continue;
+ if ( iType == OBJECT_MOTHER && oType == OBJECT_SPIDER ) continue;
+ if ( iType == OBJECT_SPIDER && oType == OBJECT_MOTHER ) continue;
+ if ( iType == OBJECT_MOTHER && oType == OBJECT_EGG ) continue;
+ if ( iType == OBJECT_EGG && oType == OBJECT_MOTHER ) continue;
+
+ pObj->GetJotlerSphere(oPos, oRad);
+ if ( oRad > 0.0f )
+ {
+ JostleObject(pObj, iPos, iRad, oPos, oRad);
+ }
+
+ if ( iType == OBJECT_MOTHER ||
+ iType == OBJECT_ANT ||
+ iType == OBJECT_SPIDER ||
+ iType == OBJECT_WORM ||
+ iType == OBJECT_BEE ) // insecte ?
+ {
+ if ( oType == OBJECT_STONE ||
+ oType == OBJECT_URANIUM ||
+ oType == OBJECT_METAL ||
+ oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_BULLET ||
+ oType == OBJECT_BBOX ||
+ oType == OBJECT_KEYa ||
+ oType == OBJECT_KEYb ||
+ oType == OBJECT_KEYc ||
+ oType == OBJECT_KEYd ||
+ oType == OBJECT_TNT ||
+ (oType >= OBJECT_PLANT0 && oType <= OBJECT_PLANT19 ) ||
+ (oType >= OBJECT_MUSHROOM0 && oType <= OBJECT_MUSHROOM9) ) continue;
+ }
+
+#if _TEEN
+ if ( oType == OBJECT_WAYPOINT &&
+ pObj->RetEnable() &&
+ !m_object->RetResetBusy() ) // véhicule d'entraînement ?
+#else
+ if ( oType == OBJECT_WAYPOINT &&
+ pObj->RetEnable() &&
+ !m_object->RetResetBusy() &&
+ m_object->RetTrainer() ) // véhicule d'entraînement ?
+#endif
+ {
+ oPos = pObj->RetPosition(0);
+ distance = Length2d(oPos, iPos);
+ if ( distance < 4.0f )
+ {
+ m_sound->Play(SOUND_WAYPOINT, m_object->RetPosition(0));
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_WPCHECK, pObj);
+ }
+ }
+
+ if ( oType == OBJECT_TARGET2 )
+ {
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ if ( distance < 10.0f*1.5f )
+ {
+ m_sound->Play(SOUND_WAYPOINT, m_object->RetPosition(0));
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_WPCHECK, pObj);
+ }
+ }
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRad) )
+ {
+ if ( iType == OBJECT_MOTHER && oRad <= 1.2f ) continue;
+ if ( iType == OBJECT_ANT && oRad <= 1.2f ) continue;
+ if ( iType == OBJECT_SPIDER && oRad <= 1.2f ) continue;
+ if ( iType == OBJECT_BEE && oRad <= 1.2f ) continue;
+ if ( iType == OBJECT_WORM && oRad <= 1.2f ) continue;
+
+ distance = Length(oPos, iPos);
+ if ( distance < iRad+oRad ) // collision ?
+ {
+ distance = Length(oPos, iiPos);
+ if ( distance >= iRad+oRad ) // voir (*)
+ {
+ m_bCollision = TRUE;
+ m_bObstacle = TRUE;
+
+ sound = pObj->RetCrashSphereSound(j-1);
+ if ( sound != SOUND_CLICK )
+ {
+ force = Abs(m_linMotion.realSpeed.x);
+ force *= pObj->RetCrashSphereHardness(j-1)*2.0f;
+ if ( ExploOther(iType, pObj, oType, force) ) continue;
+ colType = ExploHimself(iType, oType, force);
+ if ( colType == 2 ) return 2; // détruit ?
+ if ( colType == 0 ) continue; // passe outre ?
+ }
+
+ force = Length(m_linMotion.realSpeed);
+ force *= pObj->RetCrashSphereHardness(j-1);
+ volume = Abs(force*0.05f);
+ if ( volume > 1.0f ) volume = 1.0f;
+ if ( sound != SOUND_CLICK )
+ {
+ m_sound->Play(sound, m_object->RetPosition(0), volume);
+ }
+ if ( iType == OBJECT_HUMAN && volume > 0.5f )
+ {
+ m_sound->Play(SOUND_AIE, m_object->RetPosition(0), volume);
+ }
+
+ if ( m_repeatCollision > 0 )
+ {
+ force *= 0.5f*m_repeatCollision;
+ if ( force > 20.0f ) force = 20.0f;
+ }
+ m_repeatCollision += 2;
+ if ( m_repeatCollision > 10 )
+ {
+ m_repeatCollision = 10;
+ }
+
+ m_linMotion.currentSpeed = Normalize(iPos-oPos)*force;
+ MatRotateXZY(matRotate, -angle);
+ m_linMotion.currentSpeed = Transform(matRotate, m_linMotion.currentSpeed);
+ if ( m_type == TYPE_ROLLING )
+ {
+ m_linMotion.currentSpeed.y = 0.0f;
+ }
+
+ ph = pObj->RetPhysics();
+ if ( ph != 0 )
+ {
+ oAngle = pObj->RetAngle(0);
+ oSpeed = Normalize(oPos-iPos)*force;
+ MatRotateXZY(matRotate, -oAngle);
+ oSpeed = Transform(matRotate, oSpeed);
+ if ( ph->RetType() == TYPE_ROLLING )
+ {
+ oSpeed.y = 0.0f;
+ }
+ ph->SetLinMotion(MO_CURSPEED, oSpeed);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ if ( m_repeatCollision > 0 )
+ {
+ m_repeatCollision --;
+ }
+ return 0;
+}
+
+// (*) En cas de collision à la position initiale (iiPos) et à la
+// nouvelle position (iPos), l'obstacle est ignoré. On peut
+// donc passer à travers. Ceci est nécessaire lorsqu'un obstacle
+// se retrouve "dans" un véhicule, pour ne pas le bloquer
+// définitivement !
+
+
+// Bouscule un objet.
+
+BOOL CPhysics::JostleObject(CObject* pObj, D3DVECTOR iPos, float iRad,
+ D3DVECTOR oPos, float oRad)
+{
+ D3DVECTOR speed;
+ float distance, force, d, f;
+
+ distance = Length(oPos, iPos);
+ if ( distance >= iRad+oRad ) return FALSE;
+
+ d = (iRad+oRad)/2.0f;
+ f = (distance-d)/d; // 0=loin, 1=proche
+ if ( f < 0.0f ) f = 0.0f;
+ if ( f > 1.0f ) f = 1.0f;
+
+ speed = m_linMotion.realSpeed;
+ speed.y = 0.0f;
+ force = Length(speed)*f*0.05f;
+ if ( force > 1.0f ) force = 1.0f;
+
+ if ( m_soundTimeJostle >= 0.20f )
+ {
+ m_soundTimeJostle = 0.0f;
+ m_sound->Play(SOUND_JOSTLE, iPos, force);
+ }
+
+ return pObj->JostleObject(force);
+}
+
+// Bouscule forcément un objet.
+
+BOOL CPhysics::JostleObject(CObject* pObj, float force)
+{
+ D3DVECTOR oPos;
+ float oRad;
+
+ pObj->GetJotlerSphere(oPos, oRad);
+ if ( oRad <= 0.0f ) return FALSE;
+
+ if ( m_soundTimeJostle >= 0.20f )
+ {
+ m_soundTimeJostle = 0.0f;
+ m_sound->Play(SOUND_JOSTLE, pObj->RetPosition(0), force);
+ }
+
+ return pObj->JostleObject(force);
+}
+
+// Action de l'explosion sur l'objet tamponné.
+// Retourne TRUE s'il faut ignorer cet obstacle.
+
+BOOL CPhysics::ExploOther(ObjectType iType,
+ CObject *pObj, ObjectType oType, float force)
+{
+ CPyro* pyro;
+
+ if ( !pObj->RetEnable() ) return TRUE;
+
+ JostleObject(pObj, 1.0f); // bouscule l'objet
+
+ if ( force > 50.0f &&
+ (oType == OBJECT_FRET ||
+ oType == OBJECT_METAL ) )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_EXPLOT, pObj); // destruction totale
+ }
+
+ if ( force > 50.0f &&
+ (oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ) )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj); // destruction totale
+ }
+
+ if ( force > 25.0f &&
+ (oType == OBJECT_STONE ||
+ oType == OBJECT_URANIUM ) )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj); // destruction totale
+ }
+
+ if ( force > 25.0f &&
+ (oType == OBJECT_DERRICK ||
+ oType == OBJECT_FACTORY ||
+ oType == OBJECT_STATION ||
+ oType == OBJECT_CONVERT ||
+ oType == OBJECT_REPAIR ||
+ oType == OBJECT_DESTROYER||
+ oType == OBJECT_TOWER ||
+ oType == OBJECT_RESEARCH ||
+ oType == OBJECT_RADAR ||
+ oType == OBJECT_INFO ||
+ oType == OBJECT_ENERGY ||
+ oType == OBJECT_LABO ||
+ oType == OBJECT_NUCLEAR ||
+ oType == OBJECT_PARA ||
+ oType == OBJECT_SAFE ||
+ oType == OBJECT_HUSTON ) ) // bâtiment ?
+ {
+ pObj->ExploObject(EXPLO_BOUM, force/400.0f);
+ }
+
+ if ( force > 25.0f &&
+ (oType == OBJECT_MOBILEwa ||
+ oType == OBJECT_MOBILEta ||
+ oType == OBJECT_MOBILEfa ||
+ oType == OBJECT_MOBILEia ||
+ oType == OBJECT_MOBILEwc ||
+ oType == OBJECT_MOBILEtc ||
+ oType == OBJECT_MOBILEfc ||
+ oType == OBJECT_MOBILEic ||
+ oType == OBJECT_MOBILEwi ||
+ oType == OBJECT_MOBILEti ||
+ oType == OBJECT_MOBILEfi ||
+ oType == OBJECT_MOBILEii ||
+ oType == OBJECT_MOBILEws ||
+ oType == OBJECT_MOBILEts ||
+ oType == OBJECT_MOBILEfs ||
+ oType == OBJECT_MOBILEis ||
+ oType == OBJECT_MOBILErt ||
+ oType == OBJECT_MOBILErc ||
+ oType == OBJECT_MOBILErr ||
+ oType == OBJECT_MOBILErs ||
+ oType == OBJECT_MOBILEsa ||
+ oType == OBJECT_MOBILEwt ||
+ oType == OBJECT_MOBILEtt ||
+ oType == OBJECT_MOBILEft ||
+ oType == OBJECT_MOBILEit ||
+ oType == OBJECT_MOBILEdr ||
+ oType == OBJECT_APOLLO2 ) ) // véhicule ?
+ {
+ pObj->ExploObject(EXPLO_BOUM, force/200.0f);
+ }
+
+ if ( force > 10.0f &&
+ (oType == OBJECT_MOBILEtg ||
+ oType == OBJECT_TNT ) )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj); // destruction totale
+ }
+
+ if ( force > 0.0f &&
+ oType == OBJECT_BOMB )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj); // destruction totale
+ }
+
+ return FALSE;
+}
+
+// Action de l'explosion sur l'objet lui-même.
+// Retourne 0 -> objet mobile
+// Retourne 1 -> objet immobile
+// Retourne 2 -> objet détruit
+
+int CPhysics::ExploHimself(ObjectType iType, ObjectType oType, float force)
+{
+ PyroType type;
+ CPyro* pyro;
+
+ if ( force > 10.0f &&
+ (oType == OBJECT_TNT ||
+ oType == OBJECT_MOBILEtg ) )
+ {
+ if ( iType == OBJECT_HUMAN ) type = PT_DEADG;
+ else type = PT_EXPLOT;
+ pyro = new CPyro(m_iMan);
+ pyro->Create(type, m_object); // destruction totale
+ return 2;
+ }
+
+ if ( force > 0.0f &&
+ oType == OBJECT_BOMB )
+ {
+ if ( iType == OBJECT_HUMAN )
+ {
+ type = PT_DEADG;
+ }
+ else if ( iType == OBJECT_ANT ||
+ iType == OBJECT_SPIDER ||
+ iType == OBJECT_BEE )
+ {
+ type = PT_EXPLOO;
+ }
+ else
+ {
+ type = PT_EXPLOT;
+ }
+ pyro = new CPyro(m_iMan);
+ pyro->Create(type, m_object); // destruction totale
+ return 2;
+ }
+
+ if ( force > 25.0f &&
+ (iType == OBJECT_HUMAN ||
+ iType == OBJECT_MOBILEwa ||
+ iType == OBJECT_MOBILEta ||
+ iType == OBJECT_MOBILEfa ||
+ iType == OBJECT_MOBILEia ||
+ iType == OBJECT_MOBILEwc ||
+ iType == OBJECT_MOBILEtc ||
+ iType == OBJECT_MOBILEfc ||
+ iType == OBJECT_MOBILEic ||
+ iType == OBJECT_MOBILEwi ||
+ iType == OBJECT_MOBILEti ||
+ iType == OBJECT_MOBILEfi ||
+ iType == OBJECT_MOBILEii ||
+ iType == OBJECT_MOBILEws ||
+ iType == OBJECT_MOBILEts ||
+ iType == OBJECT_MOBILEfs ||
+ iType == OBJECT_MOBILEis ||
+ iType == OBJECT_MOBILErt ||
+ iType == OBJECT_MOBILErc ||
+ iType == OBJECT_MOBILErr ||
+ iType == OBJECT_MOBILErs ||
+ iType == OBJECT_MOBILEsa ||
+ iType == OBJECT_MOBILEwt ||
+ iType == OBJECT_MOBILEtt ||
+ iType == OBJECT_MOBILEft ||
+ iType == OBJECT_MOBILEit ||
+ iType == OBJECT_MOBILEdr ||
+ iType == OBJECT_APOLLO2 ) ) // véhicule ?
+ {
+ if ( oType == OBJECT_DERRICK ||
+ oType == OBJECT_FACTORY ||
+ oType == OBJECT_STATION ||
+ oType == OBJECT_CONVERT ||
+ oType == OBJECT_REPAIR ||
+ oType == OBJECT_DESTROYER||
+ oType == OBJECT_TOWER ||
+ oType == OBJECT_RESEARCH ||
+ oType == OBJECT_RADAR ||
+ oType == OBJECT_INFO ||
+ oType == OBJECT_ENERGY ||
+ oType == OBJECT_LABO ||
+ oType == OBJECT_NUCLEAR ||
+ oType == OBJECT_PARA ||
+ oType == OBJECT_SAFE ||
+ oType == OBJECT_HUSTON ) // bâtiment ?
+ {
+ force /= 200.0f;
+ }
+ else
+ if ( oType == OBJECT_MOTHER ||
+ oType == OBJECT_ANT ||
+ oType == OBJECT_SPIDER ||
+ oType == OBJECT_BEE ||
+ oType == OBJECT_WORM ) // insecte ?
+ {
+ force /= 400.0f;
+ }
+ else
+ if ( oType == OBJECT_FRET ||
+ oType == OBJECT_STONE ||
+ oType == OBJECT_METAL )
+ {
+ force /= 500.0f;
+ }
+ else
+ if ( oType == OBJECT_URANIUM ||
+ oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC )
+ {
+ force /= 100.0f;
+ }
+ else
+ {
+ force /= 200.0f;
+ }
+
+ if ( m_object->ExploObject(EXPLO_BOUM, force) ) return 2;
+ }
+
+ return 1;
+}
+
+
+
+// Fait évoluer les particules.
+
+void CPhysics::FrameParticule(float aTime, float rTime)
+{
+ D3DVECTOR pos;
+ CObject* power;
+ float energy, intensity;
+ int effectLight;
+ BOOL bFlash;
+
+ m_restBreakParticule -= rTime;
+ if ( aTime-m_lastPowerParticule < m_engine->ParticuleAdapt(0.05f) ) return;
+ m_lastPowerParticule = aTime;
+
+ bFlash = FALSE;
+
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( energy != m_lastEnergy ) // changement du niveau d'énergie ?
+ {
+ if ( energy > m_lastEnergy ) // recharge ?
+ {
+ PowerParticule(1.0f, FALSE);
+ bFlash = TRUE;
+ }
+
+ if ( energy == 0.0f || m_lastEnergy == 0.0f )
+ {
+ m_restBreakParticule = 2.5f; // particules pendant 2.5s
+ }
+
+ m_lastEnergy = energy;
+ }
+
+ if ( m_restBreakParticule > 0.0f )
+ {
+ PowerParticule(m_restBreakParticule/2.5f, (energy == 0));
+ bFlash = TRUE;
+ }
+
+ effectLight = m_object->RetEffectLight();
+ if ( effectLight != -1 )
+ {
+ if ( bFlash )
+ {
+ intensity = 0.0f;
+ if ( Rand() < 0.5f ) intensity = 1.0f;
+ m_light->SetLightIntensity(effectLight, intensity);
+ m_light->SetLightIntensitySpeed(effectLight, 10000.0f);
+ }
+ else
+ {
+ m_light->SetLightIntensity(effectLight, 0.0f);
+ }
+ }
+}
+
+// Génère qq particules suite à une recharge.
+
+void CPhysics::PowerParticule(float factor, BOOL bBreak)
+{
+ Character* character;
+ CObject* fret;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, ppos, eye, speed;
+ FPOINT dim;
+ BOOL bCarryPower;
+
+ bCarryPower = FALSE;
+ fret = m_object->RetFret();
+ if ( fret != 0 && fret->RetType() == OBJECT_POWER &&
+ m_object->RetAngleZ(1) == ARM_STOCK_ANGLE1 )
+ {
+ bCarryPower = TRUE; // porte une batterie
+ }
+
+ mat = m_object->RetWorldMatrix(0);
+ character = m_object->RetCharacter();
+
+ pos = character->posPower;
+ pos.x -= 0.3f;
+ pos.y += 1.0f; // position centre batterie
+ pos = Transform(*mat, pos);
+
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.y = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+
+ ppos.x = pos.x;
+ ppos.y = pos.y+(Rand()-0.5f)*2.0f;
+ ppos.z = pos.z;
+
+ dim.x = 1.0f*factor;
+ dim.y = 1.0f*factor;
+
+ m_particule->CreateParticule(ppos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
+
+ if ( bCarryPower ) // porte une batterie ?
+ {
+ pos = D3DVECTOR(3.0f, 5.6f, 0.0f); // position batterie portée
+ pos = Transform(*mat, pos);
+
+ speed.x = (Rand()-0.5f)*12.0f;
+ speed.y = (Rand()-0.5f)*12.0f;
+ speed.z = (Rand()-0.5f)*12.0f;
+
+ ppos.x = pos.x;
+ ppos.y = pos.y;
+ ppos.z = pos.z+(Rand()-0.5f)*2.0f;
+
+ dim.x = 1.0f*factor;
+ dim.y = 1.0f*factor;
+
+ m_particule->CreateParticule(ppos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
+ }
+}
+
+// Génère qq particules suite à une chute.
+// crash: 0=super soft, 1=big crash
+
+void CPhysics::CrashParticule(float crash)
+{
+ D3DVECTOR pos, ppos, speed;
+ FPOINT dim;
+ float len;
+ int i, max;
+
+ if ( crash < 0.2f ) return;
+
+ pos = m_object->RetPosition(0);
+ m_camera->StartEffect(CE_CRASH, pos, crash);
+
+//? max = (int)(crash*50.0f);
+ max = (int)(crash*10.0f*m_engine->RetParticuleDensity());
+
+ for ( i=0 ; i<max ; i++ )
+ {
+ ppos.x = pos.x + (Rand()-0.5f)*15.0f*crash;
+ ppos.z = pos.z + (Rand()-0.5f)*15.0f*crash;
+ ppos.y = pos.y + Rand()*4.0f;
+ len = 1.0f-(Length(ppos, pos)/(15.0f+5.0f));
+ if ( len <= 0.0f ) continue;
+ speed.x = (ppos.x-pos.x)*0.1f;
+ speed.z = (ppos.z-pos.z)*0.1f;
+ speed.y = -2.0f;
+ dim.x = 2.0f+crash*5.0f*len;
+ dim.y = dim.x;
+ m_particule->CreateParticule(ppos, speed, dim, PARTICRASH, 2.0f);
+ }
+}
+
+// Génère qq particules de gaz d'échappement.
+
+void CPhysics::MotorParticule(float aTime, float rTime)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ ObjectType type;
+ FPOINT c, p;
+ float h, a, delay, level;
+ int r, i, nb;
+
+ if ( m_object->RetToy() ) return;
+
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEis || // pattes ?
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_APOLLO2 ) return;
+
+ if ( type == OBJECT_HUMAN ) delay = 3.0f;
+ else delay = 8.0f;
+ if ( m_bSwim && m_timeUnderWater < delay ) // bulles en entrant dans l'eau ?
+ {
+ if ( aTime-m_lastUnderParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ m_lastUnderParticule = aTime;
+
+ nb = (int)(20.0f-(20.0f/delay)*m_timeUnderWater);
+ for ( i=0 ; i<nb ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.y += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ speed.y = (Rand()-0.5f)*8.0f+8.0f;
+ speed.x = (Rand()-0.5f)*0.2f;
+ speed.z = (Rand()-0.5f)*0.2f;
+ dim.x = 0.06f+Rand()*0.10f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBUBBLE, 3.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ level = m_water->RetLevel();
+ pos = m_object->RetPosition(0);
+ if ( type == OBJECT_HUMAN ) pos.y -= 2.0f;
+ if ( pos.y < level ) // sous l'eau ?
+ {
+ m_absorbWater += rTime*(1.0f/2.0f); // se mouille
+ if ( m_absorbWater > 1.0f ) m_absorbWater = 1.0f;
+ }
+ else // hors de l'eau ?
+ {
+ m_absorbWater -= rTime*(1.0f/3.0f); // se sèche
+ if ( m_absorbWater < 0.0f ) m_absorbWater = 0.0f;
+ }
+
+ if ( pos.y >= level &&
+ m_absorbWater > 0.0f &&
+ !m_water->RetLava() ) // gouttes en sortant de l'eau ?
+ {
+ if ( aTime-m_lastUnderParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ m_lastUnderParticule = aTime;
+
+ nb = (int)(8.0f*m_absorbWater);
+ for ( i=0 ; i<nb ; i++ )
+ {
+ pos = m_object->RetPosition(0);
+ if ( type == OBJECT_HUMAN ) pos.y -= Rand()*2.0f;
+ else pos.y += Rand()*2.0f;
+ pos.x += (Rand()-0.5f)*2.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+ speed.y = -((Rand()-0.5f)*8.0f+8.0f);
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = 0.2f;
+ dim.y = 0.2f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIWATER, 2.0f, 0.0f, 1.0f);
+ }
+ }
+ }
+
+ if ( type == OBJECT_HUMAN || // homme ?
+ type == OBJECT_TECH )
+ {
+ if ( m_bLand &&
+ aTime-m_lastSlideParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ h = Max(Abs(m_linMotion.terrainSpeed.x),
+ Abs(m_linMotion.terrainSpeed.z));
+ if ( h > m_linMotion.terrainSlide.x+0.5f &&
+ m_linMotion.motorSpeed.x == 0.0f ) // glisse à l'arrêt ?
+ {
+ m_lastSlideParticule = aTime;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos.x = (Rand()-0.5f)*1.0f;
+ pos.y = -m_object->RetCharacter()->height;
+ pos.z = Rand()*0.4f+1.0f;
+ if ( rand()%2 == 0 ) pos.z = -pos.z;
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ dim.x = Rand()*(h-5.0f)/2.0f+1.0f;
+ if ( dim.x > 2.5f ) dim.x = 2.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.2f);
+ }
+ }
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ) // chenilles ?
+ {
+ if ( aTime-m_lastSlideParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ h = Abs(m_linMotion.motorSpeed.x-m_linMotion.realSpeed.x);
+ if ( h > 5.0f )
+ {
+ m_lastSlideParticule = aTime;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos.x = (Rand()-0.5f)*8.0f;
+ pos.y = 0.0f;
+ pos.z = Rand()*2.0f+3.0f;
+ if ( rand()%2 == 0 ) pos.z = -pos.z;
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*(h-5.0f)/2.0f+1.0f;
+ if ( dim.x > 3.0f ) dim.x = 3.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.2f);
+ }
+ }
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ if ( aTime-m_lastSlideParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ h = Abs(m_linMotion.motorSpeed.x-m_linMotion.realSpeed.x);
+ if ( h > 5.0f )
+ {
+ m_lastSlideParticule = aTime;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos.x = (Rand()-0.5f)*9.0f;
+ pos.y = 0.0f;
+ pos.z = Rand()*3.0f+3.0f;
+ if ( rand()%2 == 0 ) pos.z = -pos.z;
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*(h-5.0f)/2.0f+1.0f;
+ if ( dim.x > 3.0f ) dim.x = 3.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.2f);
+ }
+ }
+ }
+
+ if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && !m_bSwim )
+ {
+ if ( m_bLand ) // au sol ?
+ {
+ if ( m_reactorTemperature > 0.0f )
+ {
+ m_reactorTemperature -= rTime*(1.0f/10.0f); // ça refroidi
+ if ( m_reactorTemperature < 0.0f )
+ {
+ m_reactorTemperature = 0.0f;
+ }
+ }
+
+ if ( m_reactorTemperature == 0.0f ||
+ aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.05f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(-1.6f, -0.5f, 0.0f);
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+
+ speed.x = (Rand()-0.5f)*0.6f;
+ speed.z = (Rand()-0.5f)*0.6f;
+ speed.y = -(0.5f+Rand()*0.3f)*(1.0f-m_reactorTemperature);
+
+ dim.x = (1.0f+Rand()*0.5f)*(0.2f+m_reactorTemperature*0.8f);
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE2, 3.0f, 0.0f, 0.1f);
+ }
+ else // en vol ?
+ {
+ if ( !m_bMotor || m_reactorRange == 0.0f ) return;
+
+ if ( m_reactorTemperature < 1.0f ) // pas trop chaud ?
+ {
+ m_reactorTemperature += rTime*(1.0f/4.0f); // ça chauffe
+ if ( m_reactorTemperature > 1.0f )
+ {
+ m_reactorTemperature = 1.0f; // mais pas trop
+ }
+ }
+
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.02f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(-1.6f, -1.0f, 0.0f);
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.y += (Rand()-0.5f)*1.5f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+
+ h = m_floorHeight;
+ if ( h > 10.0f ) // assez haut ?
+ {
+ speed = D3DVECTOR(0.0f, -10.0f, 0.0f); // contre le bas
+ }
+ else
+ {
+ speed.y = 10.0f-2.0f*h - Rand()*(10.0f-h); // contre le haut
+ speed.x = (Rand()-0.5f)*(5.0f-h)*1.0f; // horizontal (xz)
+ speed.z = (Rand()-0.5f)*(5.0f-h)*1.0f;
+ }
+
+ dim.x = 0.12f;
+ dim.y = 0.12f;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTISCRAPS, 2.0f, 10.0f);
+
+#if 1
+ pos = D3DVECTOR(-1.6f, -0.5f, 0.0f);
+ pos = Transform(*mat, pos);
+
+ speed.x = (Rand()-0.5f)*1.0f;
+ speed.z = (Rand()-0.5f)*1.0f;
+ speed.y = -(4.0f+Rand()*3.0f);
+ speed.x += m_linMotion.realSpeed.x*0.8f;
+ speed.z -= m_linMotion.realSpeed.x*m_cirMotion.realSpeed.y*0.05f;
+ if ( m_linMotion.realSpeed.y > 0.0f )
+ {
+ speed.y += m_linMotion.realSpeed.y*0.5f;
+ }
+ else
+ {
+ speed.y += m_linMotion.realSpeed.y*1.2f;
+ }
+ a = m_object->RetAngleY(0);
+ p.x = speed.x;
+ p.y = speed.z;
+ p = RotatePoint(-a, p);
+ speed.x = p.x;
+ speed.z = p.y;
+
+ dim.x = 0.4f+Rand()*0.2f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIEJECT, 0.3f, 10.0f);
+#endif
+ }
+ }
+
+ if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim )
+ {
+ m_reactorTemperature = 0.0f; // réacteur froid
+ }
+
+ if ( m_type == TYPE_FLYING &&
+ type != OBJECT_HUMAN &&
+ type != OBJECT_TECH &&
+ !m_bSwim )
+ {
+ if ( m_bLand ) // au sol ?
+ {
+ if ( m_motorSpeed.x == 0.0f && // glisse à cause pente terrain ?
+ m_cirMotion.realSpeed.y == 0.0f )
+ {
+ h = Max(Abs(m_linMotion.realSpeed.x),
+ Abs(m_linMotion.realSpeed.z));
+
+ if ( h < 3.0f ) return;
+
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.2f) ) return;
+ m_lastMotorParticule = aTime;
+
+ r = rand()%3;
+ if ( r == 0 ) pos = D3DVECTOR(-3.0f, 0.0f, -4.0f);
+ if ( r == 1 ) pos = D3DVECTOR(-3.0f, 0.0f, 4.0f);
+ if ( r == 2 ) pos = D3DVECTOR( 4.0f, 0.0f, 0.0f);
+
+ pos.x += (Rand()-0.5f)*2.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = Rand()*h/5.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+ }
+ else // glisse avec petits réacteurs dans patins ?
+ {
+ if ( m_linMotion.realSpeed.x == 0.0f &&
+ m_cirMotion.realSpeed.y == 0.0f ) return;
+
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.02f) ) return;
+ m_lastMotorParticule = aTime;
+
+ r = rand()%3;
+ if ( r == 0 ) pos = D3DVECTOR(-3.0f, 0.0f, -4.0f);
+ if ( r == 1 ) pos = D3DVECTOR(-3.0f, 0.0f, 4.0f);
+ if ( r == 2 ) pos = D3DVECTOR( 4.0f, 0.0f, 0.0f);
+
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIEJECT);
+ }
+ }
+ else // en vol ?
+ {
+ if ( !m_bMotor || m_reactorRange == 0.0f ) return;
+
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.02f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(0.0f, -1.0f, 0.0f);
+ pos.x += (Rand()-0.5f)*6.0f;
+ pos.y += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*6.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+
+ h = m_floorHeight;
+ if ( h > 10.0f ) // assez haut ?
+ {
+ speed = D3DVECTOR(0.0f, -10.0f, 0.0f); // contre le bas
+ }
+ else
+ {
+ speed.y = 10.0f-2.0f*h - Rand()*(10.0f-h); // contre le haut
+ speed.x = (Rand()-0.5f)*(10.0f-h)*2.0f; // horizontal (xz)
+ speed.z = (Rand()-0.5f)*(10.0f-h)*2.0f;
+ }
+
+ dim.x = 0.2f;
+ dim.y = 0.2f;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTISCRAPS, 2.0f, 10.0f);
+
+#if 1
+ pos = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ pos = Transform(*mat, pos);
+
+ speed.x = (Rand()-0.5f)*1.0f;
+ speed.z = (Rand()-0.5f)*1.0f;
+ speed.y = -(6.0f+Rand()*4.5f);
+ speed.x += m_linMotion.realSpeed.x*0.8f;
+ speed.z -= m_linMotion.realSpeed.x*m_cirMotion.realSpeed.y*0.05f;
+ if ( m_linMotion.realSpeed.y > 0.0f )
+ {
+ speed.y += m_linMotion.realSpeed.y*0.5f;
+ }
+ else
+ {
+ speed.y += m_linMotion.realSpeed.y*1.2f;
+ }
+ a = m_object->RetAngleY(0);
+ p.x = speed.x;
+ p.y = speed.z;
+ p = RotatePoint(-a, p);
+ speed.x = p.x;
+ speed.z = p.y;
+
+ dim.x = 0.7f+Rand()*0.6f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIEJECT, 0.5f, 10.0f);
+#endif
+ }
+ }
+
+ if ( (type == OBJECT_HUMAN || type == OBJECT_TECH) && m_bSwim )
+ {
+ if ( !m_object->RetDead() )
+ {
+ h = Mod(aTime, 5.0f);
+ if ( h < 3.5f && ( h < 1.5f || h > 1.6f ) ) return;
+ }
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.06f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(0.0f, 3.0f, 0.0f);
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ speed.y = (Rand()-0.5f)*8.0f+8.0f;
+ speed.x = (Rand()-0.5f)*0.2f;
+ speed.z = (Rand()-0.5f)*0.2f;
+ dim.x = 0.2f;
+ dim.y = 0.2f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBUBBLE, 3.0f, 0.0f, 0.0f);
+
+ if ( aTime-m_lastSoundWater > 1.5f )
+ {
+ m_lastSoundWater = aTime;
+ m_sound->Play(SOUND_BLUP, m_object->RetPosition(0), 0.5f+Rand()*0.5f);
+ }
+ }
+
+ if ( type == OBJECT_MOBILEsa && m_bSwim )
+ {
+ h = Mod(aTime, 3.0f);
+ if ( h < 1.5f && ( h < 0.5f || h > 0.9f ) ) return;
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.06f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(0.0f, 3.0f, 0.0f);
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ speed.y = (Rand()-0.5f)*8.0f+8.0f;
+ speed.x = (Rand()-0.5f)*0.2f;
+ speed.z = (Rand()-0.5f)*0.2f;
+ dim.x = 0.2f;
+ dim.y = 0.2f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBUBBLE, 3.0f, 0.0f, 0.0f);
+
+ if ( aTime-m_lastSoundWater > 1.5f )
+ {
+ m_lastSoundWater = aTime;
+ m_sound->Play(SOUND_BLUP, m_object->RetPosition(0), 0.5f+Rand()*0.5f);
+ }
+ }
+
+ if ( m_type == TYPE_ROLLING )
+ {
+ if ( type == OBJECT_APOLLO2 ) return; // moteurs électriques !
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ if ( !m_bMotor ) return;
+
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.1f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(-2.5f, 10.3f, -1.3f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 1.5f+Rand()*1.0f;
+
+ dim.x = Rand()*0.6f+0.4f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIMOTOR, 2.0f);
+ }
+ else
+ {
+ if ( !m_bMotor ) return;
+
+ if ( aTime-m_lastMotorParticule < m_engine->ParticuleAdapt(0.05f) ) return;
+ m_lastMotorParticule = aTime;
+
+ pos = D3DVECTOR(-3.4f, 1.8f, 0.5f);
+
+ speed = pos;
+ if ( m_linMotion.currentSpeed.x < 0.0f )
+ {
+ speed.x += m_linMotion.currentSpeed.x*1.2f;
+ }
+ else if ( m_linMotion.currentSpeed.x > 0.0f )
+ {
+ speed.x += 0.0f;
+ }
+ else
+ {
+ speed.x -= 3.0f;
+ }
+ speed.y -= 0.5f+Rand()*2.0f;
+ speed.z += (Rand()-0.5f)*3.0f;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ speed = Transform(*mat, speed)-pos;
+
+ dim.x = Rand()*0.4f+0.3f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIMOTOR, 2.0f);
+ }
+ }
+}
+
+// Génère qq particules suite à une chute dans l'eau.
+
+void CPhysics::WaterParticule(float aTime, D3DVECTOR pos, ObjectType type,
+ float floor, float advance, float turn)
+{
+ D3DVECTOR ppos, speed;
+ FPOINT dim;
+ float delay, level, min, max, force, volume, diam;
+ int i, nb;
+
+ level = m_water->RetLevel();
+ if ( floor >= level ) return;
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ min = 3.0f;
+ max = 3.0f;
+ }
+ else
+ {
+ min = 0.0f;
+ max = 9.0f;
+ }
+
+ if ( pos.y+max < level || pos.y-min > level ) return;
+
+ // Gestion de la particule "plouf".
+ if ( m_linMotion.realSpeed.y < -10.0f &&
+ aTime-m_lastPloufParticule >= 1.0f )
+ {
+ m_lastPloufParticule = aTime;
+
+ force = -m_linMotion.realSpeed.y/20.0f; // force selon vitesse chute
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ diam = 2.5f;
+ }
+ else
+ {
+ diam = 5.0f;
+ force *= 1.3f; // un robot est plus lourd
+ }
+
+ pos = m_object->RetPosition(0);
+ pos.y = m_water->RetLevel()-1.0f;
+ dim.x = 2.0f*force; // hauteur
+ dim.y = diam; // diamètre
+ m_particule->CreateParticule(pos, D3DVECTOR(0.0f, 0.0f, 0.0f), dim, PARTIPLOUF0, 1.4f, 0.0f, 0.0f);
+
+ force = (0.5f+force*0.5f);
+ nb = (int)(force*50.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<nb ; i++ )
+ {
+ ppos = pos;
+ ppos.x += (Rand()-0.5f)*4.0f;
+ ppos.z += (Rand()-0.5f)*4.0f;
+ ppos.y += 0.6f;
+ speed.x = (Rand()-0.5f)*12.0f*force;
+ speed.z = (Rand()-0.5f)*12.0f*force;
+ speed.y = 6.0f+Rand()*6.0f*force;
+ dim.x = 0.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(ppos, speed, dim, PARTIDROP, 2.0f, 20.0f, 0.2f);
+ }
+
+ volume = Abs(m_linMotion.realSpeed.y*0.02f);
+ if ( volume > 1.0f ) volume = 1.0f;
+ m_sound->Play(SOUND_PLOUF, pos, volume);
+ }
+
+ // Gestion des particules "flic".
+ if ( m_water->RetLava() ) return;
+
+ if ( advance == 0.0f && turn == 0.0f )
+ {
+ turn = 10.0f;
+ delay = 0.50f;
+ }
+ else if ( advance == 0.0f )
+ {
+ delay = 0.24f;
+ }
+ else
+ {
+ delay = 0.06f;
+ }
+ m_engine->ParticuleAdapt(delay);
+
+ if ( aTime-m_lastWaterParticule < delay ) return;
+ m_lastWaterParticule = aTime;
+
+ force = (advance+turn)*0.16f;
+ if ( force < 0.001f ) return;
+
+ pos = m_object->RetPosition(0);
+ pos.y = level+0.1f;
+ if ( advance == 0 )
+ {
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ }
+ else
+ {
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ }
+ speed.y = 0.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ dim.x = Min(Rand()*force+force+1.0f, 10.0f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLIC, 3.0f, 0.0f, 0.0f);
+}
+
+// Crée la trace sous le robot.
+
+void CPhysics::WheelParticule(int color, float width)
+{
+ Character* character;
+ D3DMATRIX* mat;
+ D3DVECTOR goal1, goal2, wheel1, wheel2;
+ ParticuleType parti;
+ float dist1, dist2, step;
+
+ character = m_object->RetCharacter();
+ mat = m_object->RetWorldMatrix(0);
+
+ // Dessine une trace sur le sol.
+ if ( color >= 0 && color <= 17 )
+ {
+ parti = (ParticuleType)(PARTITRACE0+color);
+ step = 2.0f;
+ if ( color >= 16 ) step = 4.0f; // flèche ?
+ step /= m_engine->RetTracePrecision();
+
+ goal1.x = step/2.0f;
+ goal1.y = 0.0f;
+ goal1.z = -width/2.0f;
+ goal1 = Transform(*mat, goal1);
+
+ goal2.x = step/2.0f;
+ goal2.y = 0.0f;
+ goal2.z = width/2.0f;
+ goal2 = Transform(*mat, goal2);
+
+ if ( !m_bWheelParticuleBrake )
+ {
+ m_wheelParticulePos[0] = goal1;
+ m_wheelParticulePos[1] = goal2;
+ }
+
+ while ( TRUE )
+ {
+ dist1 = Length(m_wheelParticulePos[0], goal1);
+ if ( dist1 < step ) break;
+ dist2 = Length(m_wheelParticulePos[1], goal2);
+ wheel1 = SegmentDist(m_wheelParticulePos[0], goal1, step);
+ wheel2 = SegmentDist(m_wheelParticulePos[1], goal2, step*dist2/dist1);
+ if ( m_linMotion.realSpeed.x >= 0.0f )
+ {
+ m_particule->CreateWheelTrace(m_wheelParticulePos[0], m_wheelParticulePos[1], wheel1, wheel2, parti);
+ }
+ else
+ {
+ m_particule->CreateWheelTrace(m_wheelParticulePos[1], m_wheelParticulePos[0], wheel2, wheel1, parti);
+ }
+ m_wheelParticulePos[0] = wheel1;
+ m_wheelParticulePos[1] = wheel2;
+ }
+
+ m_bWheelParticuleBrake = TRUE;
+ }
+ else
+ {
+ m_bWheelParticuleBrake = FALSE;
+ }
+}
+
+
+// Crée l'interface.
+
+void CPhysics::CreateInterface(BOOL bSelect)
+{
+ if ( m_brain != 0 )
+ {
+ m_brain->CreateInterface(bSelect);
+ }
+}
+
+
+// Retourne une erreur liée à l'état général.
+
+Error CPhysics::RetError()
+{
+ ObjectType type;
+ CObject* power;
+
+ type = m_object->RetType();
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_APOLLO2 ||
+ type == OBJECT_MOBILEdr ) return ERR_OK;
+
+ if ( m_brain != 0 && m_brain->RetActiveVirus() )
+ {
+ return ERR_VEH_VIRUS;
+ }
+
+ power = m_object->RetPower(); // cherche l'objet pile utilisé
+ if ( power == 0 )
+ {
+ return ERR_VEH_POWER;
+ }
+ else
+ {
+ if ( power->RetEnergy() == 0.0f ) return ERR_VEH_ENERGY;
+ }
+
+ return ERR_OK;
+}
+
diff --git a/src/physics.h b/src/physics.h
new file mode 100644
index 0000000..3eb83f5
--- /dev/null
+++ b/src/physics.h
@@ -0,0 +1,228 @@
+// physics.h
+
+#ifndef _PHYSICS_H_
+#define _PHYSICS_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CWater;
+class CCamera;
+class CObject;
+class CBrain;
+class CMotion;
+class CSound;
+
+
+enum PhysicsType
+{
+ TYPE_ROLLING = 1,
+ TYPE_FLYING = 2,
+};
+
+enum PhysicsMode
+{
+ MO_ADVACCEL = 0,
+ MO_RECACCEL = 1,
+ MO_STOACCEL = 2,
+ MO_MOTACCEL = 3,
+ MO_ADVSPEED = 4,
+ MO_RECSPEED = 5,
+ MO_MOTSPEED = 6,
+ MO_CURSPEED = 7,
+ MO_TERFORCE = 8,
+ MO_TERSPEED = 9,
+ MO_TERSLIDE = 10,
+ MO_REASPEED = 11,
+};
+
+
+typedef struct
+{
+ D3DVECTOR advanceAccel; // accélération de départ (+)
+ D3DVECTOR recedeAccel; // accélération de départ (+)
+ D3DVECTOR stopAccel; // accélération d'arrêt (+)
+ D3DVECTOR motorAccel; // accélération actuelle (+/-)
+
+ D3DVECTOR advanceSpeed; // vitesse en marche avant (+)
+ D3DVECTOR recedeSpeed; // vitesse en marche arrière (+)
+ D3DVECTOR motorSpeed; // vitesse souhaitée (+/-)
+ D3DVECTOR currentSpeed; // vitesse actuelle (+/-)
+
+ D3DVECTOR terrainForce; // force de résistance du terrain (+)
+ D3DVECTOR terrainSpeed; // vitesse du terrain (+/-)
+ D3DVECTOR terrainSlide; // limite vitesse de glissement (+)
+
+ D3DVECTOR realSpeed; // vitesse réelle (+/-)
+
+ D3DVECTOR finalInclin; // inclinaison finale
+}
+Motion;
+
+
+
+
+class CPhysics
+{
+public:
+ CPhysics(CInstanceManager* iMan, CObject* object);
+ ~CPhysics();
+
+ void DeleteObject(BOOL bAll=FALSE);
+
+ BOOL EventProcess(const Event &event);
+
+ void SetBrain(CBrain* brain);
+ void SetMotion(CMotion* motion);
+
+ void SetType(PhysicsType type);
+ PhysicsType RetType();
+
+ BOOL Write(char *line);
+ BOOL Read(char *line);
+
+ void SetGravity(float value);
+ float RetGravity();
+
+ float RetFloorHeight();
+
+ void SetLinMotion(PhysicsMode mode, D3DVECTOR value);
+ D3DVECTOR RetLinMotion(PhysicsMode mode);
+ void SetLinMotionX(PhysicsMode mode, float value);
+ void SetLinMotionY(PhysicsMode mode, float value);
+ void SetLinMotionZ(PhysicsMode mode, float value);
+ float RetLinMotionX(PhysicsMode mode);
+ float RetLinMotionY(PhysicsMode mode);
+ float RetLinMotionZ(PhysicsMode mode);
+
+ void SetCirMotion(PhysicsMode mode, D3DVECTOR value);
+ D3DVECTOR RetCirMotion(PhysicsMode mode);
+ void SetCirMotionX(PhysicsMode mode, float value);
+ void SetCirMotionY(PhysicsMode mode, float value);
+ void SetCirMotionZ(PhysicsMode mode, float value);
+ float RetCirMotionX(PhysicsMode mode);
+ float RetCirMotionY(PhysicsMode mode);
+ float RetCirMotionZ(PhysicsMode mode);
+
+ float RetLinStopLength(PhysicsMode sMode=MO_ADVSPEED, PhysicsMode aMode=MO_STOACCEL);
+ float RetCirStopLength();
+ float RetLinMaxLength(float dir);
+ float RetLinTimeLength(float dist, float dir=1.0f);
+ float RetLinLength(float dist);
+
+ void SetMotor(BOOL bState);
+ BOOL RetMotor();
+ void SetLand(BOOL bState);
+ BOOL RetLand();
+ void SetSwim(BOOL bState);
+ BOOL RetSwim();
+ void SetCollision(BOOL bCollision);
+ BOOL RetCollision();
+ void SetFreeze(BOOL bFreeze);
+ BOOL RetFreeze();
+ void SetReactorRange(float range);
+ float RetReactorRange();
+
+ void SetMotorSpeed(D3DVECTOR speed);
+ void SetMotorSpeedX(float speed);
+ void SetMotorSpeedY(float speed);
+ void SetMotorSpeedZ(float speed);
+ D3DVECTOR RetMotorSpeed();
+ float RetMotorSpeedX();
+ float RetMotorSpeedY();
+ float RetMotorSpeedZ();
+
+ void CreateInterface(BOOL bSelect);
+ Error RetError();
+
+protected:
+ BOOL EventFrame(const Event &event);
+ void WaterFrame(float aTime, float rTime);
+ void SoundMotor(float rTime);
+ void SoundMotorFull(float rTime, ObjectType type);
+ void SoundMotorSlow(float rTime, ObjectType type);
+ void SoundMotorStop(float rTime, ObjectType type);
+ void SoundReactorFull(float rTime, ObjectType type);
+ void SoundReactorStop(float rTime, ObjectType type);
+ void FrameParticule(float aTime, float rTime);
+ void MotorUpdate(float aTime, float rTime);
+ void EffectUpdate(float aTime, float rTime);
+ void UpdateMotionStruct(float rTime, Motion &motion);
+ void FloorAdapt(float aTime, float rTime, D3DVECTOR &pos, D3DVECTOR &angle);
+ void FloorAngle(const D3DVECTOR &pos, D3DVECTOR &angle);
+ int ObjectAdapt(const D3DVECTOR &pos, const D3DVECTOR &angle);
+ BOOL JostleObject(CObject* pObj, D3DVECTOR iPos, float iRad, D3DVECTOR oPos, float oRad);
+ BOOL JostleObject(CObject* pObj, float force);
+ BOOL ExploOther(ObjectType iType, CObject *pObj, ObjectType oType, float force);
+ int ExploHimself(ObjectType iType, ObjectType oType, float force);
+
+ void PowerParticule(float factor, BOOL bBreak);
+ void CrashParticule(float crash);
+ void MotorParticule(float aTime, float rTime);
+ void WaterParticule(float aTime, D3DVECTOR pos, ObjectType type, float floor, float advance, float turn);
+ void WheelParticule(int color, float width);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CLight* m_light;
+ CParticule* m_particule;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCamera* m_camera;
+ CObject* m_object;
+ CBrain* m_brain;
+ CMotion* m_motion;
+ CSound* m_sound;
+
+ PhysicsType m_type; // TYPE_*
+ float m_gravity; // force de gravitation
+ float m_time; // temps absolu
+ D3DVECTOR m_motorSpeed; // vitesse du moteur (-1..1)
+ Motion m_linMotion; // mouvement linéaire
+ Motion m_cirMotion; // mouvement circulaire
+ BOOL m_bMotor;
+ BOOL m_bLand;
+ BOOL m_bSwim;
+ BOOL m_bCollision;
+ BOOL m_bObstacle;
+ BOOL m_bFreeze;
+ int m_repeatCollision;
+ float m_linVibrationFactor;
+ float m_cirVibrationFactor;
+ float m_inclinaisonFactor;
+ float m_lastPowerParticule;
+ float m_lastSlideParticule;
+ float m_lastMotorParticule;
+ float m_lastWaterParticule;
+ float m_lastUnderParticule;
+ float m_lastPloufParticule;
+ float m_lastFlameParticule;
+ BOOL m_bWheelParticuleBrake;
+ D3DVECTOR m_wheelParticulePos[2];
+ float m_absorbWater;
+ float m_reactorTemperature;
+ float m_reactorRange;
+ float m_timeReactorFail;
+ float m_timeUnderWater;
+ float m_lastEnergy;
+ float m_lastSoundWater;
+ float m_lastSoundInsect;
+ float m_restBreakParticule;
+ float m_floorLevel; // niveau du sol
+ float m_floorHeight; // hauteur au-dessus du sol
+ int m_soundChannel;
+ int m_soundChannelSlide;
+ float m_soundTimePshhh;
+ float m_soundTimeJostle;
+ float m_soundTimeBoum;
+ BOOL m_bSoundSlow;
+ BOOL m_bForceUpdate;
+ BOOL m_bLowLevel;
+};
+
+
+#endif //_PHYSICS_H_
diff --git a/src/planet.cpp b/src/planet.cpp
new file mode 100644
index 0000000..c479b1f
--- /dev/null
+++ b/src/planet.cpp
@@ -0,0 +1,232 @@
+// planet.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "planet.h"
+
+
+
+
+// Constructeur du terrain.
+
+CPlanet::CPlanet(CInstanceManager* iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_PLANET, this);
+
+ m_engine = engine;
+ Flush();
+
+}
+
+// Destructeur du terrain.
+
+CPlanet::~CPlanet()
+{
+}
+
+
+// Supprime toutes les planètes.
+
+void CPlanet::Flush()
+{
+ int i, j;
+
+ for ( j=0 ; j<2 ; j++ )
+ {
+ for ( i=0 ; i<MAXPLANET ; i++ )
+ {
+ m_planet[j][i].bUsed = FALSE;
+ }
+ }
+
+ m_bPlanetExist = FALSE;
+ m_mode = 0;
+ m_time = 0.0f;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CPlanet::EventProcess(const Event &event)
+{
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+ return TRUE;
+}
+
+// Fait évoluer les planètes.
+
+BOOL CPlanet::EventFrame(const Event &event)
+{
+ float a;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+
+ m_time += event.rTime;
+
+ for ( i=0 ; i<MAXPLANET ; i++ )
+ {
+ if ( !m_planet[m_mode][i].bUsed ) continue;
+
+ a = m_time*m_planet[m_mode][i].speed;
+ if ( a < 0.0f )
+ {
+ a += PI*1000.0f;
+ }
+ m_planet[m_mode][i].angle.x = a+m_planet[m_mode][i].start.x;
+ m_planet[m_mode][i].angle.y = sinf(a)*sinf(m_planet[m_mode][i].dir)+m_planet[m_mode][i].start.y;
+ }
+
+ return TRUE;
+}
+
+
+// Charge toutes les textures pour les planètes.
+
+void CPlanet::LoadTexture()
+{
+ int i, j;
+
+ for ( j=0 ; j<2 ; j++ )
+ {
+ for ( i=0 ; i<MAXPLANET ; i++ )
+ {
+ if ( !m_planet[j][i].bUsed ) continue;
+
+ m_engine->LoadTexture(m_planet[j][i].name);
+ }
+ }
+}
+
+// Dessine toutes les planètes.
+
+void CPlanet::Draw()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DVECTOR n;
+ FPOINT p1, p2;
+ float eyeDirH, eyeDirV, dp, u1, u2, v1, v2, a;
+ int i;
+
+ device = m_engine->RetD3DDevice();
+ eyeDirH = m_engine->RetEyeDirH();
+ eyeDirV = m_engine->RetEyeDirV();
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+ dp = 0.5f/256.0f;
+
+ for ( i=0 ; i<MAXPLANET ; i++ )
+ {
+ if ( !m_planet[m_mode][i].bUsed ) continue;
+
+ m_engine->SetTexture(m_planet[m_mode][i].name);
+
+ if ( m_planet[m_mode][i].bTGA )
+ {
+ m_engine->SetState(D3DSTATEWRAP|D3DSTATEALPHA);
+ }
+ else
+ {
+ m_engine->SetState(D3DSTATEWRAP|D3DSTATETTb);
+ }
+
+ a = eyeDirH + m_planet[m_mode][i].angle.x;
+ p1.x = Mod(a, PI*2.0f)-0.5f;
+
+ a = eyeDirV + m_planet[m_mode][i].angle.y;
+ p1.y = 0.4f+(Mod(a+PI, PI*2.0f)-PI)*(2.0f/PI);
+
+ p1.x -= m_planet[m_mode][i].dim/2.0f*0.75f;
+ p1.y -= m_planet[m_mode][i].dim/2.0f;
+ p2.x = p1.x+m_planet[m_mode][i].dim*0.75f;
+ p2.y = p1.y+m_planet[m_mode][i].dim;
+
+ u1 = m_planet[m_mode][i].uv1.x + dp;
+ v1 = m_planet[m_mode][i].uv1.y + dp;
+ u2 = m_planet[m_mode][i].uv2.x - dp;
+ v2 = m_planet[m_mode][i].uv2.y - dp;
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+ }
+}
+
+
+// Crée une nouvelle planète.
+
+BOOL CPlanet::Create(int mode, FPOINT start, float dim, float speed,
+ float dir, char *name, FPOINT uv1, FPOINT uv2)
+{
+ int i;
+
+ if ( mode < 0 ) mode = 0;
+ if ( mode > 1 ) mode = 1;
+
+ for ( i=0 ; i<MAXPLANET ; i++ )
+ {
+ if ( m_planet[mode][i].bUsed ) continue;
+
+ m_planet[mode][i].bUsed = TRUE;
+ m_planet[mode][i].start = start;
+ m_planet[mode][i].angle = start;
+ m_planet[mode][i].dim = dim;
+ m_planet[mode][i].speed = speed;
+ m_planet[mode][i].dir = dir;
+
+ strcpy(m_planet[mode][i].name, name);
+ m_planet[mode][i].uv1 = uv1;
+ m_planet[mode][i].uv2 = uv2;
+
+ m_planet[mode][i].bTGA = ( strstr(m_planet[mode][i].name, "planet") != 0 );
+
+ m_bPlanetExist = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Indique s'il existe au moins une planète.
+
+BOOL CPlanet::PlanetExist()
+{
+ return m_bPlanetExist;
+}
+
+
+// Choix du mode.
+
+void CPlanet::SetMode(int mode)
+{
+ if ( mode < 0 ) mode = 0;
+ if ( mode > 1 ) mode = 1;
+ m_mode = mode;
+}
+
+int CPlanet::RetMode()
+{
+ return m_mode;
+}
+
diff --git a/src/planet.h b/src/planet.h
new file mode 100644
index 0000000..263926f
--- /dev/null
+++ b/src/planet.h
@@ -0,0 +1,60 @@
+// planet.h
+
+#ifndef _PLANET_H_
+#define _PLANET_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+
+
+
+#define MAXPLANET 10
+
+typedef struct
+{
+ char bUsed; // TRUE -> planète existe
+ FPOINT start; // position initiale en degrés
+ FPOINT angle; // position actuelle en degrés
+ float dim; // dimensions (0..1)
+ float speed; // vitesse
+ float dir; // direction dans le ciel
+ char name[20]; // nom de la texture
+ FPOINT uv1, uv2; // mapping de la texture
+ char bTGA; // texture .TGA
+}
+Planet;
+
+
+
+
+class CPlanet
+{
+public:
+ CPlanet(CInstanceManager* iMan, CD3DEngine* engine);
+ ~CPlanet();
+
+ void Flush();
+ BOOL EventProcess(const Event &event);
+ BOOL Create(int mode, FPOINT start, float dim, float speed, float dir, char *name, FPOINT uv1, FPOINT uv2);
+ BOOL PlanetExist();
+ void LoadTexture();
+ void Draw();
+ void SetMode(int mode);
+ int RetMode();
+
+protected:
+ BOOL EventFrame(const Event &event);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+
+ float m_time;
+ int m_mode;
+ Planet m_planet[2][MAXPLANET];
+ BOOL m_bPlanetExist;
+};
+
+
+#endif //_PLANET_H_
diff --git a/src/profile.cpp b/src/profile.cpp
new file mode 100644
index 0000000..b869bc2
--- /dev/null
+++ b/src/profile.cpp
@@ -0,0 +1,100 @@
+// profile.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <stdio.h>
+#include <d3d.h>
+#include <stdlib.h>
+
+#include "language.h"
+#include "struct.h"
+#include "profile.h"
+
+
+
+static char g_filename[100];
+
+
+
+BOOL InitCurrentDirectory()
+{
+#if _SCHOOL
+ _fullpath(g_filename, "ceebot.ini", 100);
+#else
+ _fullpath(g_filename, "colobot.ini", 100);
+#endif
+ return TRUE;
+}
+
+
+BOOL SetProfileString(char* section, char* key, char* string)
+{
+ WritePrivateProfileString(section, key, string, g_filename);
+ return TRUE;
+}
+
+BOOL GetProfileString(char* section, char* key, char* buffer, int max)
+{
+ int nb;
+
+ nb = GetPrivateProfileString(section, key, "", buffer, max, g_filename);
+ if ( nb == 0 )
+ {
+ buffer[0] = 0;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+BOOL SetProfileInt(char* section, char* key, int value)
+{
+ char s[20];
+
+ sprintf(s, "%d", value);
+ WritePrivateProfileString(section, key, s, g_filename);
+ return TRUE;
+}
+
+BOOL GetProfileInt(char* section, char* key, int &value)
+{
+ char s[20];
+ int nb;
+
+ nb = GetPrivateProfileString(section, key, "", s, 20, g_filename);
+ if ( nb == 0 )
+ {
+ value = 0;
+ return FALSE;
+ }
+ sscanf(s, "%d", &value);
+ return TRUE;
+}
+
+
+BOOL SetProfileFloat(char* section, char* key, float value)
+{
+ char s[20];
+
+ sprintf(s, "%.2f", value);
+ WritePrivateProfileString(section, key, s, g_filename);
+ return TRUE;
+}
+
+BOOL GetProfileFloat(char* section, char* key, float &value)
+{
+ char s[20];
+ int nb;
+
+ nb = GetPrivateProfileString(section, key, "", s, 20, g_filename);
+ if ( nb == 0 )
+ {
+ value = 0.0f;
+ return FALSE;
+ }
+ sscanf(s, "%f", &value);
+ return TRUE;
+}
+
+
diff --git a/src/profile.h b/src/profile.h
new file mode 100644
index 0000000..e328ce1
--- /dev/null
+++ b/src/profile.h
@@ -0,0 +1,20 @@
+// profile.h
+
+#ifndef _PROFILE_H_
+#define _PROFILE_H_
+
+
+#define STRICT
+#define D3D_OVERLOADS
+
+
+extern BOOL InitCurrentDirectory();
+extern BOOL SetProfileString(char* section, char* key, char* string);
+extern BOOL GetProfileString(char* section, char* key, char* buffer, int max);
+extern BOOL SetProfileInt(char* section, char* key, int value);
+extern BOOL GetProfileInt(char* section, char* key, int &value);
+extern BOOL SetProfileFloat(char* section, char* key, float value);
+extern BOOL GetProfileFloat(char* section, char* key, float &value);
+
+
+#endif //_PROFILE_H_
diff --git a/src/projet1.dsp b/src/projet1.dsp
new file mode 100644
index 0000000..a72113c
--- /dev/null
+++ b/src/projet1.dsp
@@ -0,0 +1,608 @@
+# Microsoft Developer Studio Project File - Name="projet1" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=projet1 - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "projet1.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "projet1.mak" CFG="projet1 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "projet1 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "projet1 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x100c /d "NDEBUG"
+# ADD RSC /l 0x100c /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib c:\dx7sdk\lib\ddraw.lib c:\dx7sdk\lib\dinput.lib c:\dx7sdk\lib\dxguid.lib c:\dx7sdk\lib\d3dx.lib c:\dx7sdk\lib\dsound.lib cbot\cbot.lib /nologo /subsystem:windows /machine:I386
+# SUBTRACT LINK32 /debug
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+# ADD BASE RSC /l 0x100c /d "_DEBUG"
+# ADD RSC /l 0x100c /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib c:\dx7sdk\lib\ddraw.lib c:\dx7sdk\lib\dinput.lib c:\dx7sdk\lib\dxguid.lib c:\dx7sdk\lib\d3dx.lib c:\dx7sdk\lib\dsound.lib cbot\cbot.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# SUBTRACT LINK32 /map
+
+!ENDIF
+
+# Begin Target
+
+# Name "projet1 - Win32 Release"
+# Name "projet1 - Win32 Debug"
+# Begin Source File
+
+SOURCE=.\auto.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autobase.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoconvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoderrick.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autodestroyer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoegg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoenergy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autofactory.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoflag.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autohuston.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoinfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autojostle.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autokid.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autolabo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\automush.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autonest.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autonuclear.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autopara.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoportico.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoradar.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autorepair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoresearch.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autoroot.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autosafe.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autostation.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\autotower.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\blitz.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\brain.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\button.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\camera.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\cbottoken.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\check.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\cloud.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\cmdtoken.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\color.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\compass.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\control.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\cur00001.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\cur00002.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\cur00003.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\cursor1.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\cursorha.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\cursorsc.cur
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3dapp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3dengine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3denum.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3dframe.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3dmath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3dtextr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\d3dutil.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\directx.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\displayinfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\displaytext.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\edit.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\editvalue.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\event.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\gauge.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\group.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\image.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\iman.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\interface.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\joystick.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\key.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\label.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\language.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\light.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\list.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\maindialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mainmap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mainmovie.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\mainshort.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\map.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\math3d.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\metafile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\misc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\model.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modfile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motion.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionbee.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionhuman.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionmother.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionspider.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motiontoto.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionvehicle.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\motionworm.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\object.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\particule.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\physics.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\planet.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\profile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\pyro.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\restext.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\robotmain.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\script.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\scroll.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\shortcut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\slider.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\sound.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\studio.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\target.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\task.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskadvance.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskbuild.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskfire.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskfireant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskflag.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskgoto.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskgungoal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskinfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskmanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskmanip.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskrecover.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskreset.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\tasksearch.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskshield.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskspiderexplo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\tasktake.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskterraform.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskturn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\taskwait.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\terrain.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\text.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\water.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\winmain.rc
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
diff --git a/src/projet1.dsw b/src/projet1.dsw
new file mode 100644
index 0000000..dec6482
--- /dev/null
+++ b/src/projet1.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 5.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "projet1"=.\projet1.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/src/projet1.mak b/src/projet1.mak
new file mode 100644
index 0000000..619bb49
--- /dev/null
+++ b/src/projet1.mak
@@ -0,0 +1,8659 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on projet1.dsp
+!IF "$(CFG)" == ""
+CFG=projet1 - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to projet1 - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "projet1 - Win32 Release" && "$(CFG)" !=\
+ "projet1 - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "projet1.mak" CFG="projet1 - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "projet1 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "projet1 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\projet1.exe"
+
+!ELSE
+
+ALL : "$(OUTDIR)\projet1.exe"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\auto.obj"
+ -@erase "$(INTDIR)\autobase.obj"
+ -@erase "$(INTDIR)\autoconvert.obj"
+ -@erase "$(INTDIR)\autoderrick.obj"
+ -@erase "$(INTDIR)\autodestroyer.obj"
+ -@erase "$(INTDIR)\autoegg.obj"
+ -@erase "$(INTDIR)\autoenergy.obj"
+ -@erase "$(INTDIR)\autofactory.obj"
+ -@erase "$(INTDIR)\autoflag.obj"
+ -@erase "$(INTDIR)\autohuston.obj"
+ -@erase "$(INTDIR)\autoinfo.obj"
+ -@erase "$(INTDIR)\autojostle.obj"
+ -@erase "$(INTDIR)\autokid.obj"
+ -@erase "$(INTDIR)\autolabo.obj"
+ -@erase "$(INTDIR)\automush.obj"
+ -@erase "$(INTDIR)\autonest.obj"
+ -@erase "$(INTDIR)\autonuclear.obj"
+ -@erase "$(INTDIR)\autopara.obj"
+ -@erase "$(INTDIR)\autoportico.obj"
+ -@erase "$(INTDIR)\autoradar.obj"
+ -@erase "$(INTDIR)\autorepair.obj"
+ -@erase "$(INTDIR)\autoresearch.obj"
+ -@erase "$(INTDIR)\autoroot.obj"
+ -@erase "$(INTDIR)\autosafe.obj"
+ -@erase "$(INTDIR)\autostation.obj"
+ -@erase "$(INTDIR)\autotower.obj"
+ -@erase "$(INTDIR)\blitz.obj"
+ -@erase "$(INTDIR)\brain.obj"
+ -@erase "$(INTDIR)\button.obj"
+ -@erase "$(INTDIR)\camera.obj"
+ -@erase "$(INTDIR)\cbottoken.obj"
+ -@erase "$(INTDIR)\check.obj"
+ -@erase "$(INTDIR)\cloud.obj"
+ -@erase "$(INTDIR)\cmdtoken.obj"
+ -@erase "$(INTDIR)\color.obj"
+ -@erase "$(INTDIR)\compass.obj"
+ -@erase "$(INTDIR)\control.obj"
+ -@erase "$(INTDIR)\d3dapp.obj"
+ -@erase "$(INTDIR)\d3dengine.obj"
+ -@erase "$(INTDIR)\d3denum.obj"
+ -@erase "$(INTDIR)\d3dframe.obj"
+ -@erase "$(INTDIR)\d3dmath.obj"
+ -@erase "$(INTDIR)\d3dtextr.obj"
+ -@erase "$(INTDIR)\d3dutil.obj"
+ -@erase "$(INTDIR)\displayinfo.obj"
+ -@erase "$(INTDIR)\displaytext.obj"
+ -@erase "$(INTDIR)\edit.obj"
+ -@erase "$(INTDIR)\editvalue.obj"
+ -@erase "$(INTDIR)\event.obj"
+ -@erase "$(INTDIR)\gauge.obj"
+ -@erase "$(INTDIR)\group.obj"
+ -@erase "$(INTDIR)\image.obj"
+ -@erase "$(INTDIR)\iman.obj"
+ -@erase "$(INTDIR)\interface.obj"
+ -@erase "$(INTDIR)\joystick.obj"
+ -@erase "$(INTDIR)\key.obj"
+ -@erase "$(INTDIR)\label.obj"
+ -@erase "$(INTDIR)\light.obj"
+ -@erase "$(INTDIR)\list.obj"
+ -@erase "$(INTDIR)\maindialog.obj"
+ -@erase "$(INTDIR)\mainmap.obj"
+ -@erase "$(INTDIR)\mainmovie.obj"
+ -@erase "$(INTDIR)\mainshort.obj"
+ -@erase "$(INTDIR)\map.obj"
+ -@erase "$(INTDIR)\math3d.obj"
+ -@erase "$(INTDIR)\metafile.obj"
+ -@erase "$(INTDIR)\misc.obj"
+ -@erase "$(INTDIR)\model.obj"
+ -@erase "$(INTDIR)\modfile.obj"
+ -@erase "$(INTDIR)\motion.obj"
+ -@erase "$(INTDIR)\motionant.obj"
+ -@erase "$(INTDIR)\motionbee.obj"
+ -@erase "$(INTDIR)\motionhuman.obj"
+ -@erase "$(INTDIR)\motionmother.obj"
+ -@erase "$(INTDIR)\motionspider.obj"
+ -@erase "$(INTDIR)\motiontoto.obj"
+ -@erase "$(INTDIR)\motionvehicle.obj"
+ -@erase "$(INTDIR)\motionworm.obj"
+ -@erase "$(INTDIR)\object.obj"
+ -@erase "$(INTDIR)\particule.obj"
+ -@erase "$(INTDIR)\physics.obj"
+ -@erase "$(INTDIR)\planet.obj"
+ -@erase "$(INTDIR)\profile.obj"
+ -@erase "$(INTDIR)\pyro.obj"
+ -@erase "$(INTDIR)\restext.obj"
+ -@erase "$(INTDIR)\robotmain.obj"
+ -@erase "$(INTDIR)\script.obj"
+ -@erase "$(INTDIR)\scroll.obj"
+ -@erase "$(INTDIR)\shortcut.obj"
+ -@erase "$(INTDIR)\slider.obj"
+ -@erase "$(INTDIR)\sound.obj"
+ -@erase "$(INTDIR)\studio.obj"
+ -@erase "$(INTDIR)\target.obj"
+ -@erase "$(INTDIR)\task.obj"
+ -@erase "$(INTDIR)\taskadvance.obj"
+ -@erase "$(INTDIR)\taskbuild.obj"
+ -@erase "$(INTDIR)\taskfire.obj"
+ -@erase "$(INTDIR)\taskfireant.obj"
+ -@erase "$(INTDIR)\taskflag.obj"
+ -@erase "$(INTDIR)\taskgoto.obj"
+ -@erase "$(INTDIR)\taskgungoal.obj"
+ -@erase "$(INTDIR)\taskinfo.obj"
+ -@erase "$(INTDIR)\taskmanager.obj"
+ -@erase "$(INTDIR)\taskmanip.obj"
+ -@erase "$(INTDIR)\taskpen.obj"
+ -@erase "$(INTDIR)\taskrecover.obj"
+ -@erase "$(INTDIR)\taskreset.obj"
+ -@erase "$(INTDIR)\tasksearch.obj"
+ -@erase "$(INTDIR)\taskshield.obj"
+ -@erase "$(INTDIR)\taskspiderexplo.obj"
+ -@erase "$(INTDIR)\tasktake.obj"
+ -@erase "$(INTDIR)\taskterraform.obj"
+ -@erase "$(INTDIR)\taskturn.obj"
+ -@erase "$(INTDIR)\taskwait.obj"
+ -@erase "$(INTDIR)\terrain.obj"
+ -@erase "$(INTDIR)\text.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(INTDIR)\vc50.pdb"
+ -@erase "$(INTDIR)\water.obj"
+ -@erase "$(INTDIR)\window.obj"
+ -@erase "$(INTDIR)\winmain.res"
+ -@erase "$(OUTDIR)\projet1.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /ML /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)\projet1.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.
+
+.c{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x100c /fo"$(INTDIR)\winmain.res" /d "NDEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\projet1.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib winmm.lib c:\dx7sdk\lib\ddraw.lib c:\dx7sdk\lib\dinput.lib\
+ c:\dx7sdk\lib\dxguid.lib c:\dx7sdk\lib\d3dx.lib c:\dx7sdk\lib\dsound.lib\
+ cbot\cbot.lib /nologo /subsystem:windows /incremental:no\
+ /pdb:"$(OUTDIR)\projet1.pdb" /machine:I386 /out:"$(OUTDIR)\projet1.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\auto.obj" \
+ "$(INTDIR)\autobase.obj" \
+ "$(INTDIR)\autoconvert.obj" \
+ "$(INTDIR)\autoderrick.obj" \
+ "$(INTDIR)\autodestroyer.obj" \
+ "$(INTDIR)\autoegg.obj" \
+ "$(INTDIR)\autoenergy.obj" \
+ "$(INTDIR)\autofactory.obj" \
+ "$(INTDIR)\autoflag.obj" \
+ "$(INTDIR)\autohuston.obj" \
+ "$(INTDIR)\autoinfo.obj" \
+ "$(INTDIR)\autojostle.obj" \
+ "$(INTDIR)\autokid.obj" \
+ "$(INTDIR)\autolabo.obj" \
+ "$(INTDIR)\automush.obj" \
+ "$(INTDIR)\autonest.obj" \
+ "$(INTDIR)\autonuclear.obj" \
+ "$(INTDIR)\autopara.obj" \
+ "$(INTDIR)\autoportico.obj" \
+ "$(INTDIR)\autoradar.obj" \
+ "$(INTDIR)\autorepair.obj" \
+ "$(INTDIR)\autoresearch.obj" \
+ "$(INTDIR)\autoroot.obj" \
+ "$(INTDIR)\autosafe.obj" \
+ "$(INTDIR)\autostation.obj" \
+ "$(INTDIR)\autotower.obj" \
+ "$(INTDIR)\blitz.obj" \
+ "$(INTDIR)\brain.obj" \
+ "$(INTDIR)\button.obj" \
+ "$(INTDIR)\camera.obj" \
+ "$(INTDIR)\cbottoken.obj" \
+ "$(INTDIR)\check.obj" \
+ "$(INTDIR)\cloud.obj" \
+ "$(INTDIR)\cmdtoken.obj" \
+ "$(INTDIR)\color.obj" \
+ "$(INTDIR)\compass.obj" \
+ "$(INTDIR)\control.obj" \
+ "$(INTDIR)\d3dapp.obj" \
+ "$(INTDIR)\d3dengine.obj" \
+ "$(INTDIR)\d3denum.obj" \
+ "$(INTDIR)\d3dframe.obj" \
+ "$(INTDIR)\d3dmath.obj" \
+ "$(INTDIR)\d3dtextr.obj" \
+ "$(INTDIR)\d3dutil.obj" \
+ "$(INTDIR)\displayinfo.obj" \
+ "$(INTDIR)\displaytext.obj" \
+ "$(INTDIR)\edit.obj" \
+ "$(INTDIR)\editvalue.obj" \
+ "$(INTDIR)\event.obj" \
+ "$(INTDIR)\gauge.obj" \
+ "$(INTDIR)\group.obj" \
+ "$(INTDIR)\image.obj" \
+ "$(INTDIR)\iman.obj" \
+ "$(INTDIR)\interface.obj" \
+ "$(INTDIR)\joystick.obj" \
+ "$(INTDIR)\key.obj" \
+ "$(INTDIR)\label.obj" \
+ "$(INTDIR)\light.obj" \
+ "$(INTDIR)\list.obj" \
+ "$(INTDIR)\maindialog.obj" \
+ "$(INTDIR)\mainmap.obj" \
+ "$(INTDIR)\mainmovie.obj" \
+ "$(INTDIR)\mainshort.obj" \
+ "$(INTDIR)\map.obj" \
+ "$(INTDIR)\math3d.obj" \
+ "$(INTDIR)\metafile.obj" \
+ "$(INTDIR)\misc.obj" \
+ "$(INTDIR)\model.obj" \
+ "$(INTDIR)\modfile.obj" \
+ "$(INTDIR)\motion.obj" \
+ "$(INTDIR)\motionant.obj" \
+ "$(INTDIR)\motionbee.obj" \
+ "$(INTDIR)\motionhuman.obj" \
+ "$(INTDIR)\motionmother.obj" \
+ "$(INTDIR)\motionspider.obj" \
+ "$(INTDIR)\motiontoto.obj" \
+ "$(INTDIR)\motionvehicle.obj" \
+ "$(INTDIR)\motionworm.obj" \
+ "$(INTDIR)\object.obj" \
+ "$(INTDIR)\particule.obj" \
+ "$(INTDIR)\physics.obj" \
+ "$(INTDIR)\planet.obj" \
+ "$(INTDIR)\profile.obj" \
+ "$(INTDIR)\pyro.obj" \
+ "$(INTDIR)\restext.obj" \
+ "$(INTDIR)\robotmain.obj" \
+ "$(INTDIR)\script.obj" \
+ "$(INTDIR)\scroll.obj" \
+ "$(INTDIR)\shortcut.obj" \
+ "$(INTDIR)\slider.obj" \
+ "$(INTDIR)\sound.obj" \
+ "$(INTDIR)\studio.obj" \
+ "$(INTDIR)\target.obj" \
+ "$(INTDIR)\task.obj" \
+ "$(INTDIR)\taskadvance.obj" \
+ "$(INTDIR)\taskbuild.obj" \
+ "$(INTDIR)\taskfire.obj" \
+ "$(INTDIR)\taskfireant.obj" \
+ "$(INTDIR)\taskflag.obj" \
+ "$(INTDIR)\taskgoto.obj" \
+ "$(INTDIR)\taskgungoal.obj" \
+ "$(INTDIR)\taskinfo.obj" \
+ "$(INTDIR)\taskmanager.obj" \
+ "$(INTDIR)\taskmanip.obj" \
+ "$(INTDIR)\taskpen.obj" \
+ "$(INTDIR)\taskrecover.obj" \
+ "$(INTDIR)\taskreset.obj" \
+ "$(INTDIR)\tasksearch.obj" \
+ "$(INTDIR)\taskshield.obj" \
+ "$(INTDIR)\taskspiderexplo.obj" \
+ "$(INTDIR)\tasktake.obj" \
+ "$(INTDIR)\taskterraform.obj" \
+ "$(INTDIR)\taskturn.obj" \
+ "$(INTDIR)\taskwait.obj" \
+ "$(INTDIR)\terrain.obj" \
+ "$(INTDIR)\text.obj" \
+ "$(INTDIR)\water.obj" \
+ "$(INTDIR)\window.obj" \
+ "$(INTDIR)\winmain.res"
+
+"$(OUTDIR)\projet1.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\projet1.exe" "$(OUTDIR)\projet1.bsc"
+
+!ELSE
+
+ALL : "$(OUTDIR)\projet1.exe" "$(OUTDIR)\projet1.bsc"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\auto.obj"
+ -@erase "$(INTDIR)\auto.sbr"
+ -@erase "$(INTDIR)\autobase.obj"
+ -@erase "$(INTDIR)\autobase.sbr"
+ -@erase "$(INTDIR)\autoconvert.obj"
+ -@erase "$(INTDIR)\autoconvert.sbr"
+ -@erase "$(INTDIR)\autoderrick.obj"
+ -@erase "$(INTDIR)\autoderrick.sbr"
+ -@erase "$(INTDIR)\autodestroyer.obj"
+ -@erase "$(INTDIR)\autodestroyer.sbr"
+ -@erase "$(INTDIR)\autoegg.obj"
+ -@erase "$(INTDIR)\autoegg.sbr"
+ -@erase "$(INTDIR)\autoenergy.obj"
+ -@erase "$(INTDIR)\autoenergy.sbr"
+ -@erase "$(INTDIR)\autofactory.obj"
+ -@erase "$(INTDIR)\autofactory.sbr"
+ -@erase "$(INTDIR)\autoflag.obj"
+ -@erase "$(INTDIR)\autoflag.sbr"
+ -@erase "$(INTDIR)\autohuston.obj"
+ -@erase "$(INTDIR)\autohuston.sbr"
+ -@erase "$(INTDIR)\autoinfo.obj"
+ -@erase "$(INTDIR)\autoinfo.sbr"
+ -@erase "$(INTDIR)\autojostle.obj"
+ -@erase "$(INTDIR)\autojostle.sbr"
+ -@erase "$(INTDIR)\autokid.obj"
+ -@erase "$(INTDIR)\autokid.sbr"
+ -@erase "$(INTDIR)\autolabo.obj"
+ -@erase "$(INTDIR)\autolabo.sbr"
+ -@erase "$(INTDIR)\automush.obj"
+ -@erase "$(INTDIR)\automush.sbr"
+ -@erase "$(INTDIR)\autonest.obj"
+ -@erase "$(INTDIR)\autonest.sbr"
+ -@erase "$(INTDIR)\autonuclear.obj"
+ -@erase "$(INTDIR)\autonuclear.sbr"
+ -@erase "$(INTDIR)\autopara.obj"
+ -@erase "$(INTDIR)\autopara.sbr"
+ -@erase "$(INTDIR)\autoportico.obj"
+ -@erase "$(INTDIR)\autoportico.sbr"
+ -@erase "$(INTDIR)\autoradar.obj"
+ -@erase "$(INTDIR)\autoradar.sbr"
+ -@erase "$(INTDIR)\autorepair.obj"
+ -@erase "$(INTDIR)\autorepair.sbr"
+ -@erase "$(INTDIR)\autoresearch.obj"
+ -@erase "$(INTDIR)\autoresearch.sbr"
+ -@erase "$(INTDIR)\autoroot.obj"
+ -@erase "$(INTDIR)\autoroot.sbr"
+ -@erase "$(INTDIR)\autosafe.obj"
+ -@erase "$(INTDIR)\autosafe.sbr"
+ -@erase "$(INTDIR)\autostation.obj"
+ -@erase "$(INTDIR)\autostation.sbr"
+ -@erase "$(INTDIR)\autotower.obj"
+ -@erase "$(INTDIR)\autotower.sbr"
+ -@erase "$(INTDIR)\blitz.obj"
+ -@erase "$(INTDIR)\blitz.sbr"
+ -@erase "$(INTDIR)\brain.obj"
+ -@erase "$(INTDIR)\brain.sbr"
+ -@erase "$(INTDIR)\button.obj"
+ -@erase "$(INTDIR)\button.sbr"
+ -@erase "$(INTDIR)\camera.obj"
+ -@erase "$(INTDIR)\camera.sbr"
+ -@erase "$(INTDIR)\cbottoken.obj"
+ -@erase "$(INTDIR)\cbottoken.sbr"
+ -@erase "$(INTDIR)\check.obj"
+ -@erase "$(INTDIR)\check.sbr"
+ -@erase "$(INTDIR)\cloud.obj"
+ -@erase "$(INTDIR)\cloud.sbr"
+ -@erase "$(INTDIR)\cmdtoken.obj"
+ -@erase "$(INTDIR)\cmdtoken.sbr"
+ -@erase "$(INTDIR)\color.obj"
+ -@erase "$(INTDIR)\color.sbr"
+ -@erase "$(INTDIR)\compass.obj"
+ -@erase "$(INTDIR)\compass.sbr"
+ -@erase "$(INTDIR)\control.obj"
+ -@erase "$(INTDIR)\control.sbr"
+ -@erase "$(INTDIR)\d3dapp.obj"
+ -@erase "$(INTDIR)\d3dapp.sbr"
+ -@erase "$(INTDIR)\d3dengine.obj"
+ -@erase "$(INTDIR)\d3dengine.sbr"
+ -@erase "$(INTDIR)\d3denum.obj"
+ -@erase "$(INTDIR)\d3denum.sbr"
+ -@erase "$(INTDIR)\d3dframe.obj"
+ -@erase "$(INTDIR)\d3dframe.sbr"
+ -@erase "$(INTDIR)\d3dmath.obj"
+ -@erase "$(INTDIR)\d3dmath.sbr"
+ -@erase "$(INTDIR)\d3dtextr.obj"
+ -@erase "$(INTDIR)\d3dtextr.sbr"
+ -@erase "$(INTDIR)\d3dutil.obj"
+ -@erase "$(INTDIR)\d3dutil.sbr"
+ -@erase "$(INTDIR)\displayinfo.obj"
+ -@erase "$(INTDIR)\displayinfo.sbr"
+ -@erase "$(INTDIR)\displaytext.obj"
+ -@erase "$(INTDIR)\displaytext.sbr"
+ -@erase "$(INTDIR)\edit.obj"
+ -@erase "$(INTDIR)\edit.sbr"
+ -@erase "$(INTDIR)\editvalue.obj"
+ -@erase "$(INTDIR)\editvalue.sbr"
+ -@erase "$(INTDIR)\event.obj"
+ -@erase "$(INTDIR)\event.sbr"
+ -@erase "$(INTDIR)\gauge.obj"
+ -@erase "$(INTDIR)\gauge.sbr"
+ -@erase "$(INTDIR)\group.obj"
+ -@erase "$(INTDIR)\group.sbr"
+ -@erase "$(INTDIR)\image.obj"
+ -@erase "$(INTDIR)\image.sbr"
+ -@erase "$(INTDIR)\iman.obj"
+ -@erase "$(INTDIR)\iman.sbr"
+ -@erase "$(INTDIR)\interface.obj"
+ -@erase "$(INTDIR)\interface.sbr"
+ -@erase "$(INTDIR)\joystick.obj"
+ -@erase "$(INTDIR)\joystick.sbr"
+ -@erase "$(INTDIR)\key.obj"
+ -@erase "$(INTDIR)\key.sbr"
+ -@erase "$(INTDIR)\label.obj"
+ -@erase "$(INTDIR)\label.sbr"
+ -@erase "$(INTDIR)\light.obj"
+ -@erase "$(INTDIR)\light.sbr"
+ -@erase "$(INTDIR)\list.obj"
+ -@erase "$(INTDIR)\list.sbr"
+ -@erase "$(INTDIR)\maindialog.obj"
+ -@erase "$(INTDIR)\maindialog.sbr"
+ -@erase "$(INTDIR)\mainmap.obj"
+ -@erase "$(INTDIR)\mainmap.sbr"
+ -@erase "$(INTDIR)\mainmovie.obj"
+ -@erase "$(INTDIR)\mainmovie.sbr"
+ -@erase "$(INTDIR)\mainshort.obj"
+ -@erase "$(INTDIR)\mainshort.sbr"
+ -@erase "$(INTDIR)\map.obj"
+ -@erase "$(INTDIR)\map.sbr"
+ -@erase "$(INTDIR)\math3d.obj"
+ -@erase "$(INTDIR)\math3d.sbr"
+ -@erase "$(INTDIR)\metafile.obj"
+ -@erase "$(INTDIR)\metafile.sbr"
+ -@erase "$(INTDIR)\misc.obj"
+ -@erase "$(INTDIR)\misc.sbr"
+ -@erase "$(INTDIR)\model.obj"
+ -@erase "$(INTDIR)\model.sbr"
+ -@erase "$(INTDIR)\modfile.obj"
+ -@erase "$(INTDIR)\modfile.sbr"
+ -@erase "$(INTDIR)\motion.obj"
+ -@erase "$(INTDIR)\motion.sbr"
+ -@erase "$(INTDIR)\motionant.obj"
+ -@erase "$(INTDIR)\motionant.sbr"
+ -@erase "$(INTDIR)\motionbee.obj"
+ -@erase "$(INTDIR)\motionbee.sbr"
+ -@erase "$(INTDIR)\motionhuman.obj"
+ -@erase "$(INTDIR)\motionhuman.sbr"
+ -@erase "$(INTDIR)\motionmother.obj"
+ -@erase "$(INTDIR)\motionmother.sbr"
+ -@erase "$(INTDIR)\motionspider.obj"
+ -@erase "$(INTDIR)\motionspider.sbr"
+ -@erase "$(INTDIR)\motiontoto.obj"
+ -@erase "$(INTDIR)\motiontoto.sbr"
+ -@erase "$(INTDIR)\motionvehicle.obj"
+ -@erase "$(INTDIR)\motionvehicle.sbr"
+ -@erase "$(INTDIR)\motionworm.obj"
+ -@erase "$(INTDIR)\motionworm.sbr"
+ -@erase "$(INTDIR)\object.obj"
+ -@erase "$(INTDIR)\object.sbr"
+ -@erase "$(INTDIR)\particule.obj"
+ -@erase "$(INTDIR)\particule.sbr"
+ -@erase "$(INTDIR)\physics.obj"
+ -@erase "$(INTDIR)\physics.sbr"
+ -@erase "$(INTDIR)\planet.obj"
+ -@erase "$(INTDIR)\planet.sbr"
+ -@erase "$(INTDIR)\profile.obj"
+ -@erase "$(INTDIR)\profile.sbr"
+ -@erase "$(INTDIR)\pyro.obj"
+ -@erase "$(INTDIR)\pyro.sbr"
+ -@erase "$(INTDIR)\restext.obj"
+ -@erase "$(INTDIR)\restext.sbr"
+ -@erase "$(INTDIR)\robotmain.obj"
+ -@erase "$(INTDIR)\robotmain.sbr"
+ -@erase "$(INTDIR)\script.obj"
+ -@erase "$(INTDIR)\script.sbr"
+ -@erase "$(INTDIR)\scroll.obj"
+ -@erase "$(INTDIR)\scroll.sbr"
+ -@erase "$(INTDIR)\shortcut.obj"
+ -@erase "$(INTDIR)\shortcut.sbr"
+ -@erase "$(INTDIR)\slider.obj"
+ -@erase "$(INTDIR)\slider.sbr"
+ -@erase "$(INTDIR)\sound.obj"
+ -@erase "$(INTDIR)\sound.sbr"
+ -@erase "$(INTDIR)\studio.obj"
+ -@erase "$(INTDIR)\studio.sbr"
+ -@erase "$(INTDIR)\target.obj"
+ -@erase "$(INTDIR)\target.sbr"
+ -@erase "$(INTDIR)\task.obj"
+ -@erase "$(INTDIR)\task.sbr"
+ -@erase "$(INTDIR)\taskadvance.obj"
+ -@erase "$(INTDIR)\taskadvance.sbr"
+ -@erase "$(INTDIR)\taskbuild.obj"
+ -@erase "$(INTDIR)\taskbuild.sbr"
+ -@erase "$(INTDIR)\taskfire.obj"
+ -@erase "$(INTDIR)\taskfire.sbr"
+ -@erase "$(INTDIR)\taskfireant.obj"
+ -@erase "$(INTDIR)\taskfireant.sbr"
+ -@erase "$(INTDIR)\taskflag.obj"
+ -@erase "$(INTDIR)\taskflag.sbr"
+ -@erase "$(INTDIR)\taskgoto.obj"
+ -@erase "$(INTDIR)\taskgoto.sbr"
+ -@erase "$(INTDIR)\taskgungoal.obj"
+ -@erase "$(INTDIR)\taskgungoal.sbr"
+ -@erase "$(INTDIR)\taskinfo.obj"
+ -@erase "$(INTDIR)\taskinfo.sbr"
+ -@erase "$(INTDIR)\taskmanager.obj"
+ -@erase "$(INTDIR)\taskmanager.sbr"
+ -@erase "$(INTDIR)\taskmanip.obj"
+ -@erase "$(INTDIR)\taskmanip.sbr"
+ -@erase "$(INTDIR)\taskpen.obj"
+ -@erase "$(INTDIR)\taskpen.sbr"
+ -@erase "$(INTDIR)\taskrecover.obj"
+ -@erase "$(INTDIR)\taskrecover.sbr"
+ -@erase "$(INTDIR)\taskreset.obj"
+ -@erase "$(INTDIR)\taskreset.sbr"
+ -@erase "$(INTDIR)\tasksearch.obj"
+ -@erase "$(INTDIR)\tasksearch.sbr"
+ -@erase "$(INTDIR)\taskshield.obj"
+ -@erase "$(INTDIR)\taskshield.sbr"
+ -@erase "$(INTDIR)\taskspiderexplo.obj"
+ -@erase "$(INTDIR)\taskspiderexplo.sbr"
+ -@erase "$(INTDIR)\tasktake.obj"
+ -@erase "$(INTDIR)\tasktake.sbr"
+ -@erase "$(INTDIR)\taskterraform.obj"
+ -@erase "$(INTDIR)\taskterraform.sbr"
+ -@erase "$(INTDIR)\taskturn.obj"
+ -@erase "$(INTDIR)\taskturn.sbr"
+ -@erase "$(INTDIR)\taskwait.obj"
+ -@erase "$(INTDIR)\taskwait.sbr"
+ -@erase "$(INTDIR)\terrain.obj"
+ -@erase "$(INTDIR)\terrain.sbr"
+ -@erase "$(INTDIR)\text.obj"
+ -@erase "$(INTDIR)\text.sbr"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(INTDIR)\vc50.pdb"
+ -@erase "$(INTDIR)\water.obj"
+ -@erase "$(INTDIR)\water.sbr"
+ -@erase "$(INTDIR)\window.obj"
+ -@erase "$(INTDIR)\window.sbr"
+ -@erase "$(INTDIR)\winmain.res"
+ -@erase "$(OUTDIR)\projet1.bsc"
+ -@erase "$(OUTDIR)\projet1.exe"
+ -@erase "$(OUTDIR)\projet1.ilk"
+ -@erase "$(OUTDIR)\projet1.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /FR"$(INTDIR)\\" /Fp"$(INTDIR)\projet1.pch" /YX /Fo"$(INTDIR)\\"\
+ /Fd"$(INTDIR)\\" /FD /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\Debug/
+
+.c{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o NUL /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x100c /fo"$(INTDIR)\winmain.res" /d "_DEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\projet1.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\auto.sbr" \
+ "$(INTDIR)\autobase.sbr" \
+ "$(INTDIR)\autoconvert.sbr" \
+ "$(INTDIR)\autoderrick.sbr" \
+ "$(INTDIR)\autodestroyer.sbr" \
+ "$(INTDIR)\autoegg.sbr" \
+ "$(INTDIR)\autoenergy.sbr" \
+ "$(INTDIR)\autofactory.sbr" \
+ "$(INTDIR)\autoflag.sbr" \
+ "$(INTDIR)\autohuston.sbr" \
+ "$(INTDIR)\autoinfo.sbr" \
+ "$(INTDIR)\autojostle.sbr" \
+ "$(INTDIR)\autokid.sbr" \
+ "$(INTDIR)\autolabo.sbr" \
+ "$(INTDIR)\automush.sbr" \
+ "$(INTDIR)\autonest.sbr" \
+ "$(INTDIR)\autonuclear.sbr" \
+ "$(INTDIR)\autopara.sbr" \
+ "$(INTDIR)\autoportico.sbr" \
+ "$(INTDIR)\autoradar.sbr" \
+ "$(INTDIR)\autorepair.sbr" \
+ "$(INTDIR)\autoresearch.sbr" \
+ "$(INTDIR)\autoroot.sbr" \
+ "$(INTDIR)\autosafe.sbr" \
+ "$(INTDIR)\autostation.sbr" \
+ "$(INTDIR)\autotower.sbr" \
+ "$(INTDIR)\blitz.sbr" \
+ "$(INTDIR)\brain.sbr" \
+ "$(INTDIR)\button.sbr" \
+ "$(INTDIR)\camera.sbr" \
+ "$(INTDIR)\cbottoken.sbr" \
+ "$(INTDIR)\check.sbr" \
+ "$(INTDIR)\cloud.sbr" \
+ "$(INTDIR)\cmdtoken.sbr" \
+ "$(INTDIR)\color.sbr" \
+ "$(INTDIR)\compass.sbr" \
+ "$(INTDIR)\control.sbr" \
+ "$(INTDIR)\d3dapp.sbr" \
+ "$(INTDIR)\d3dengine.sbr" \
+ "$(INTDIR)\d3denum.sbr" \
+ "$(INTDIR)\d3dframe.sbr" \
+ "$(INTDIR)\d3dmath.sbr" \
+ "$(INTDIR)\d3dtextr.sbr" \
+ "$(INTDIR)\d3dutil.sbr" \
+ "$(INTDIR)\displayinfo.sbr" \
+ "$(INTDIR)\displaytext.sbr" \
+ "$(INTDIR)\edit.sbr" \
+ "$(INTDIR)\editvalue.sbr" \
+ "$(INTDIR)\event.sbr" \
+ "$(INTDIR)\gauge.sbr" \
+ "$(INTDIR)\group.sbr" \
+ "$(INTDIR)\image.sbr" \
+ "$(INTDIR)\iman.sbr" \
+ "$(INTDIR)\interface.sbr" \
+ "$(INTDIR)\joystick.sbr" \
+ "$(INTDIR)\key.sbr" \
+ "$(INTDIR)\label.sbr" \
+ "$(INTDIR)\light.sbr" \
+ "$(INTDIR)\list.sbr" \
+ "$(INTDIR)\maindialog.sbr" \
+ "$(INTDIR)\mainmap.sbr" \
+ "$(INTDIR)\mainmovie.sbr" \
+ "$(INTDIR)\mainshort.sbr" \
+ "$(INTDIR)\map.sbr" \
+ "$(INTDIR)\math3d.sbr" \
+ "$(INTDIR)\metafile.sbr" \
+ "$(INTDIR)\misc.sbr" \
+ "$(INTDIR)\model.sbr" \
+ "$(INTDIR)\modfile.sbr" \
+ "$(INTDIR)\motion.sbr" \
+ "$(INTDIR)\motionant.sbr" \
+ "$(INTDIR)\motionbee.sbr" \
+ "$(INTDIR)\motionhuman.sbr" \
+ "$(INTDIR)\motionmother.sbr" \
+ "$(INTDIR)\motionspider.sbr" \
+ "$(INTDIR)\motiontoto.sbr" \
+ "$(INTDIR)\motionvehicle.sbr" \
+ "$(INTDIR)\motionworm.sbr" \
+ "$(INTDIR)\object.sbr" \
+ "$(INTDIR)\particule.sbr" \
+ "$(INTDIR)\physics.sbr" \
+ "$(INTDIR)\planet.sbr" \
+ "$(INTDIR)\profile.sbr" \
+ "$(INTDIR)\pyro.sbr" \
+ "$(INTDIR)\restext.sbr" \
+ "$(INTDIR)\robotmain.sbr" \
+ "$(INTDIR)\script.sbr" \
+ "$(INTDIR)\scroll.sbr" \
+ "$(INTDIR)\shortcut.sbr" \
+ "$(INTDIR)\slider.sbr" \
+ "$(INTDIR)\sound.sbr" \
+ "$(INTDIR)\studio.sbr" \
+ "$(INTDIR)\target.sbr" \
+ "$(INTDIR)\task.sbr" \
+ "$(INTDIR)\taskadvance.sbr" \
+ "$(INTDIR)\taskbuild.sbr" \
+ "$(INTDIR)\taskfire.sbr" \
+ "$(INTDIR)\taskfireant.sbr" \
+ "$(INTDIR)\taskflag.sbr" \
+ "$(INTDIR)\taskgoto.sbr" \
+ "$(INTDIR)\taskgungoal.sbr" \
+ "$(INTDIR)\taskinfo.sbr" \
+ "$(INTDIR)\taskmanager.sbr" \
+ "$(INTDIR)\taskmanip.sbr" \
+ "$(INTDIR)\taskpen.sbr" \
+ "$(INTDIR)\taskrecover.sbr" \
+ "$(INTDIR)\taskreset.sbr" \
+ "$(INTDIR)\tasksearch.sbr" \
+ "$(INTDIR)\taskshield.sbr" \
+ "$(INTDIR)\taskspiderexplo.sbr" \
+ "$(INTDIR)\tasktake.sbr" \
+ "$(INTDIR)\taskterraform.sbr" \
+ "$(INTDIR)\taskturn.sbr" \
+ "$(INTDIR)\taskwait.sbr" \
+ "$(INTDIR)\terrain.sbr" \
+ "$(INTDIR)\text.sbr" \
+ "$(INTDIR)\water.sbr" \
+ "$(INTDIR)\window.sbr"
+
+"$(OUTDIR)\projet1.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib winmm.lib c:\dx7sdk\lib\ddraw.lib c:\dx7sdk\lib\dinput.lib\
+ c:\dx7sdk\lib\dxguid.lib c:\dx7sdk\lib\d3dx.lib c:\dx7sdk\lib\dsound.lib\
+ cbot\cbot.lib /nologo /subsystem:windows /incremental:yes\
+ /pdb:"$(OUTDIR)\projet1.pdb" /debug /machine:I386 /out:"$(OUTDIR)\projet1.exe"\
+ /pdbtype:sept
+LINK32_OBJS= \
+ "$(INTDIR)\auto.obj" \
+ "$(INTDIR)\autobase.obj" \
+ "$(INTDIR)\autoconvert.obj" \
+ "$(INTDIR)\autoderrick.obj" \
+ "$(INTDIR)\autodestroyer.obj" \
+ "$(INTDIR)\autoegg.obj" \
+ "$(INTDIR)\autoenergy.obj" \
+ "$(INTDIR)\autofactory.obj" \
+ "$(INTDIR)\autoflag.obj" \
+ "$(INTDIR)\autohuston.obj" \
+ "$(INTDIR)\autoinfo.obj" \
+ "$(INTDIR)\autojostle.obj" \
+ "$(INTDIR)\autokid.obj" \
+ "$(INTDIR)\autolabo.obj" \
+ "$(INTDIR)\automush.obj" \
+ "$(INTDIR)\autonest.obj" \
+ "$(INTDIR)\autonuclear.obj" \
+ "$(INTDIR)\autopara.obj" \
+ "$(INTDIR)\autoportico.obj" \
+ "$(INTDIR)\autoradar.obj" \
+ "$(INTDIR)\autorepair.obj" \
+ "$(INTDIR)\autoresearch.obj" \
+ "$(INTDIR)\autoroot.obj" \
+ "$(INTDIR)\autosafe.obj" \
+ "$(INTDIR)\autostation.obj" \
+ "$(INTDIR)\autotower.obj" \
+ "$(INTDIR)\blitz.obj" \
+ "$(INTDIR)\brain.obj" \
+ "$(INTDIR)\button.obj" \
+ "$(INTDIR)\camera.obj" \
+ "$(INTDIR)\cbottoken.obj" \
+ "$(INTDIR)\check.obj" \
+ "$(INTDIR)\cloud.obj" \
+ "$(INTDIR)\cmdtoken.obj" \
+ "$(INTDIR)\color.obj" \
+ "$(INTDIR)\compass.obj" \
+ "$(INTDIR)\control.obj" \
+ "$(INTDIR)\d3dapp.obj" \
+ "$(INTDIR)\d3dengine.obj" \
+ "$(INTDIR)\d3denum.obj" \
+ "$(INTDIR)\d3dframe.obj" \
+ "$(INTDIR)\d3dmath.obj" \
+ "$(INTDIR)\d3dtextr.obj" \
+ "$(INTDIR)\d3dutil.obj" \
+ "$(INTDIR)\displayinfo.obj" \
+ "$(INTDIR)\displaytext.obj" \
+ "$(INTDIR)\edit.obj" \
+ "$(INTDIR)\editvalue.obj" \
+ "$(INTDIR)\event.obj" \
+ "$(INTDIR)\gauge.obj" \
+ "$(INTDIR)\group.obj" \
+ "$(INTDIR)\image.obj" \
+ "$(INTDIR)\iman.obj" \
+ "$(INTDIR)\interface.obj" \
+ "$(INTDIR)\joystick.obj" \
+ "$(INTDIR)\key.obj" \
+ "$(INTDIR)\label.obj" \
+ "$(INTDIR)\light.obj" \
+ "$(INTDIR)\list.obj" \
+ "$(INTDIR)\maindialog.obj" \
+ "$(INTDIR)\mainmap.obj" \
+ "$(INTDIR)\mainmovie.obj" \
+ "$(INTDIR)\mainshort.obj" \
+ "$(INTDIR)\map.obj" \
+ "$(INTDIR)\math3d.obj" \
+ "$(INTDIR)\metafile.obj" \
+ "$(INTDIR)\misc.obj" \
+ "$(INTDIR)\model.obj" \
+ "$(INTDIR)\modfile.obj" \
+ "$(INTDIR)\motion.obj" \
+ "$(INTDIR)\motionant.obj" \
+ "$(INTDIR)\motionbee.obj" \
+ "$(INTDIR)\motionhuman.obj" \
+ "$(INTDIR)\motionmother.obj" \
+ "$(INTDIR)\motionspider.obj" \
+ "$(INTDIR)\motiontoto.obj" \
+ "$(INTDIR)\motionvehicle.obj" \
+ "$(INTDIR)\motionworm.obj" \
+ "$(INTDIR)\object.obj" \
+ "$(INTDIR)\particule.obj" \
+ "$(INTDIR)\physics.obj" \
+ "$(INTDIR)\planet.obj" \
+ "$(INTDIR)\profile.obj" \
+ "$(INTDIR)\pyro.obj" \
+ "$(INTDIR)\restext.obj" \
+ "$(INTDIR)\robotmain.obj" \
+ "$(INTDIR)\script.obj" \
+ "$(INTDIR)\scroll.obj" \
+ "$(INTDIR)\shortcut.obj" \
+ "$(INTDIR)\slider.obj" \
+ "$(INTDIR)\sound.obj" \
+ "$(INTDIR)\studio.obj" \
+ "$(INTDIR)\target.obj" \
+ "$(INTDIR)\task.obj" \
+ "$(INTDIR)\taskadvance.obj" \
+ "$(INTDIR)\taskbuild.obj" \
+ "$(INTDIR)\taskfire.obj" \
+ "$(INTDIR)\taskfireant.obj" \
+ "$(INTDIR)\taskflag.obj" \
+ "$(INTDIR)\taskgoto.obj" \
+ "$(INTDIR)\taskgungoal.obj" \
+ "$(INTDIR)\taskinfo.obj" \
+ "$(INTDIR)\taskmanager.obj" \
+ "$(INTDIR)\taskmanip.obj" \
+ "$(INTDIR)\taskpen.obj" \
+ "$(INTDIR)\taskrecover.obj" \
+ "$(INTDIR)\taskreset.obj" \
+ "$(INTDIR)\tasksearch.obj" \
+ "$(INTDIR)\taskshield.obj" \
+ "$(INTDIR)\taskspiderexplo.obj" \
+ "$(INTDIR)\tasktake.obj" \
+ "$(INTDIR)\taskterraform.obj" \
+ "$(INTDIR)\taskturn.obj" \
+ "$(INTDIR)\taskwait.obj" \
+ "$(INTDIR)\terrain.obj" \
+ "$(INTDIR)\text.obj" \
+ "$(INTDIR)\water.obj" \
+ "$(INTDIR)\window.obj" \
+ "$(INTDIR)\winmain.res"
+
+"$(OUTDIR)\projet1.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(CFG)" == "projet1 - Win32 Release" || "$(CFG)" ==\
+ "projet1 - Win32 Debug"
+SOURCE=.\auto.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTO_=\
+ ".\auto.h"\
+ ".\blitz.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cloud.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\light.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\planet.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\auto.obj" : $(SOURCE) $(DEP_CPP_AUTO_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTO_=\
+ ".\auto.h"\
+ ".\blitz.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cloud.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\light.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\planet.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\auto.obj" "$(INTDIR)\auto.sbr" : $(SOURCE) $(DEP_CPP_AUTO_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autobase.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOB=\
+ ".\auto.h"\
+ ".\autobase.h"\
+ ".\blitz.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cloud.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\planet.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autobase.obj" : $(SOURCE) $(DEP_CPP_AUTOB) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOB=\
+ ".\auto.h"\
+ ".\autobase.h"\
+ ".\blitz.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cloud.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\planet.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autobase.obj" "$(INTDIR)\autobase.sbr" : $(SOURCE) $(DEP_CPP_AUTOB)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoconvert.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOC=\
+ ".\auto.h"\
+ ".\autoconvert.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoconvert.obj" : $(SOURCE) $(DEP_CPP_AUTOC) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOC=\
+ ".\auto.h"\
+ ".\autoconvert.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoconvert.obj" "$(INTDIR)\autoconvert.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOC) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoderrick.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOD=\
+ ".\auto.h"\
+ ".\autoderrick.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoderrick.obj" : $(SOURCE) $(DEP_CPP_AUTOD) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOD=\
+ ".\auto.h"\
+ ".\autoderrick.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoderrick.obj" "$(INTDIR)\autoderrick.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOD) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autodestroyer.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTODE=\
+ ".\auto.h"\
+ ".\autodestroyer.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autodestroyer.obj" : $(SOURCE) $(DEP_CPP_AUTODE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTODE=\
+ ".\auto.h"\
+ ".\autodestroyer.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autodestroyer.obj" "$(INTDIR)\autodestroyer.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTODE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoegg.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOE=\
+ ".\auto.h"\
+ ".\autoegg.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\pyro.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoegg.obj" : $(SOURCE) $(DEP_CPP_AUTOE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOE=\
+ ".\auto.h"\
+ ".\autoegg.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\pyro.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoegg.obj" "$(INTDIR)\autoegg.sbr" : $(SOURCE) $(DEP_CPP_AUTOE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoenergy.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOEN=\
+ ".\auto.h"\
+ ".\autoenergy.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoenergy.obj" : $(SOURCE) $(DEP_CPP_AUTOEN) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOEN=\
+ ".\auto.h"\
+ ".\autoenergy.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoenergy.obj" "$(INTDIR)\autoenergy.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOEN) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autofactory.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOF=\
+ ".\auto.h"\
+ ".\autofactory.h"\
+ ".\brain.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autofactory.obj" : $(SOURCE) $(DEP_CPP_AUTOF) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOF=\
+ ".\auto.h"\
+ ".\autofactory.h"\
+ ".\brain.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autofactory.obj" "$(INTDIR)\autofactory.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOF) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoflag.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOFL=\
+ ".\auto.h"\
+ ".\autoflag.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoflag.obj" : $(SOURCE) $(DEP_CPP_AUTOFL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOFL=\
+ ".\auto.h"\
+ ".\autoflag.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoflag.obj" "$(INTDIR)\autoflag.sbr" : $(SOURCE) $(DEP_CPP_AUTOFL)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autohuston.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOH=\
+ ".\auto.h"\
+ ".\autohuston.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autohuston.obj" : $(SOURCE) $(DEP_CPP_AUTOH) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOH=\
+ ".\auto.h"\
+ ".\autohuston.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autohuston.obj" "$(INTDIR)\autohuston.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOH) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoinfo.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOI=\
+ ".\auto.h"\
+ ".\autoinfo.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoinfo.obj" : $(SOURCE) $(DEP_CPP_AUTOI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOI=\
+ ".\auto.h"\
+ ".\autoinfo.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoinfo.obj" "$(INTDIR)\autoinfo.sbr" : $(SOURCE) $(DEP_CPP_AUTOI)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autojostle.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOJ=\
+ ".\auto.h"\
+ ".\autojostle.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autojostle.obj" : $(SOURCE) $(DEP_CPP_AUTOJ) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOJ=\
+ ".\auto.h"\
+ ".\autojostle.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autojostle.obj" "$(INTDIR)\autojostle.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOJ) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autokid.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOK=\
+ ".\auto.h"\
+ ".\autokid.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autokid.obj" : $(SOURCE) $(DEP_CPP_AUTOK) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOK=\
+ ".\auto.h"\
+ ".\autokid.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autokid.obj" "$(INTDIR)\autokid.sbr" : $(SOURCE) $(DEP_CPP_AUTOK)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autolabo.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOL=\
+ ".\auto.h"\
+ ".\autolabo.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autolabo.obj" : $(SOURCE) $(DEP_CPP_AUTOL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOL=\
+ ".\auto.h"\
+ ".\autolabo.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autolabo.obj" "$(INTDIR)\autolabo.sbr" : $(SOURCE) $(DEP_CPP_AUTOL)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\automush.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOM=\
+ ".\auto.h"\
+ ".\automush.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\automush.obj" : $(SOURCE) $(DEP_CPP_AUTOM) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOM=\
+ ".\auto.h"\
+ ".\automush.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\automush.obj" "$(INTDIR)\automush.sbr" : $(SOURCE) $(DEP_CPP_AUTOM)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autonest.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTON=\
+ ".\auto.h"\
+ ".\autonest.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autonest.obj" : $(SOURCE) $(DEP_CPP_AUTON) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTON=\
+ ".\auto.h"\
+ ".\autonest.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autonest.obj" "$(INTDIR)\autonest.sbr" : $(SOURCE) $(DEP_CPP_AUTON)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autonuclear.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTONU=\
+ ".\auto.h"\
+ ".\autonuclear.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autonuclear.obj" : $(SOURCE) $(DEP_CPP_AUTONU) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTONU=\
+ ".\auto.h"\
+ ".\autonuclear.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autonuclear.obj" "$(INTDIR)\autonuclear.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTONU) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autopara.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOP=\
+ ".\auto.h"\
+ ".\autopara.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autopara.obj" : $(SOURCE) $(DEP_CPP_AUTOP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOP=\
+ ".\auto.h"\
+ ".\autopara.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autopara.obj" "$(INTDIR)\autopara.sbr" : $(SOURCE) $(DEP_CPP_AUTOP)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoportico.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOPO=\
+ ".\auto.h"\
+ ".\autoportico.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoportico.obj" : $(SOURCE) $(DEP_CPP_AUTOPO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOPO=\
+ ".\auto.h"\
+ ".\autoportico.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoportico.obj" "$(INTDIR)\autoportico.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOPO) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoradar.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOR=\
+ ".\auto.h"\
+ ".\autoradar.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoradar.obj" : $(SOURCE) $(DEP_CPP_AUTOR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOR=\
+ ".\auto.h"\
+ ".\autoradar.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoradar.obj" "$(INTDIR)\autoradar.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOR) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autorepair.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTORE=\
+ ".\auto.h"\
+ ".\autorepair.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autorepair.obj" : $(SOURCE) $(DEP_CPP_AUTORE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTORE=\
+ ".\auto.h"\
+ ".\autorepair.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autorepair.obj" "$(INTDIR)\autorepair.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTORE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoresearch.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTORES=\
+ ".\auto.h"\
+ ".\autoresearch.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoresearch.obj" : $(SOURCE) $(DEP_CPP_AUTORES) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTORES=\
+ ".\auto.h"\
+ ".\autoresearch.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoresearch.obj" "$(INTDIR)\autoresearch.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTORES) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autoroot.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTORO=\
+ ".\auto.h"\
+ ".\autoroot.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoroot.obj" : $(SOURCE) $(DEP_CPP_AUTORO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTORO=\
+ ".\auto.h"\
+ ".\autoroot.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autoroot.obj" "$(INTDIR)\autoroot.sbr" : $(SOURCE) $(DEP_CPP_AUTORO)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autosafe.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOS=\
+ ".\auto.h"\
+ ".\autosafe.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autosafe.obj" : $(SOURCE) $(DEP_CPP_AUTOS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOS=\
+ ".\auto.h"\
+ ".\autosafe.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autosafe.obj" "$(INTDIR)\autosafe.sbr" : $(SOURCE) $(DEP_CPP_AUTOS)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autostation.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOST=\
+ ".\auto.h"\
+ ".\autostation.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autostation.obj" : $(SOURCE) $(DEP_CPP_AUTOST) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOST=\
+ ".\auto.h"\
+ ".\autostation.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autostation.obj" "$(INTDIR)\autostation.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOST) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\autotower.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_AUTOT=\
+ ".\auto.h"\
+ ".\autotower.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autotower.obj" : $(SOURCE) $(DEP_CPP_AUTOT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_AUTOT=\
+ ".\auto.h"\
+ ".\autotower.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\autotower.obj" "$(INTDIR)\autotower.sbr" : $(SOURCE)\
+ $(DEP_CPP_AUTOT) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\blitz.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_BLITZ=\
+ ".\auto.h"\
+ ".\autopara.h"\
+ ".\blitz.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\blitz.obj" : $(SOURCE) $(DEP_CPP_BLITZ) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_BLITZ=\
+ ".\auto.h"\
+ ".\autopara.h"\
+ ".\blitz.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\blitz.obj" "$(INTDIR)\blitz.sbr" : $(SOURCE) $(DEP_CPP_BLITZ)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\brain.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_BRAIN=\
+ ".\brain.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbot\cbotdll.h"\
+ ".\cmdtoken.h"\
+ ".\color.h"\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\global.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\studio.h"\
+ ".\target.h"\
+ ".\task.h"\
+ ".\taskflag.h"\
+ ".\taskmanager.h"\
+ ".\taskmanip.h"\
+ ".\taskshield.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\brain.obj" : $(SOURCE) $(DEP_CPP_BRAIN) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_BRAIN=\
+ ".\brain.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbot\cbotdll.h"\
+ ".\cmdtoken.h"\
+ ".\color.h"\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\global.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\studio.h"\
+ ".\target.h"\
+ ".\task.h"\
+ ".\taskflag.h"\
+ ".\taskmanager.h"\
+ ".\taskmanip.h"\
+ ".\taskshield.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\brain.obj" "$(INTDIR)\brain.sbr" : $(SOURCE) $(DEP_CPP_BRAIN)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\button.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_BUTTO=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\button.obj" : $(SOURCE) $(DEP_CPP_BUTTO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_BUTTO=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\button.obj" "$(INTDIR)\button.sbr" : $(SOURCE) $(DEP_CPP_BUTTO)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\camera.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_CAMER=\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\camera.obj" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_CAMER=\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\camera.obj" "$(INTDIR)\camera.sbr" : $(SOURCE) $(DEP_CPP_CAMER)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\cbottoken.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_CBOTT=\
+ ".\cbottoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\language.h"\
+ ".\object.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\cbottoken.obj" : $(SOURCE) $(DEP_CPP_CBOTT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_CBOTT=\
+ ".\cbottoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\language.h"\
+ ".\object.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\cbottoken.obj" "$(INTDIR)\cbottoken.sbr" : $(SOURCE)\
+ $(DEP_CPP_CBOTT) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\check.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_CHECK=\
+ ".\check.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\check.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_CHECK=\
+ ".\check.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\check.obj" "$(INTDIR)\check.sbr" : $(SOURCE) $(DEP_CPP_CHECK)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\cloud.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_CLOUD=\
+ ".\cloud.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\cloud.obj" : $(SOURCE) $(DEP_CPP_CLOUD) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_CLOUD=\
+ ".\cloud.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\cloud.obj" "$(INTDIR)\cloud.sbr" : $(SOURCE) $(DEP_CPP_CLOUD)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\cmdtoken.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_CMDTO=\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\language.h"\
+ ".\object.h"\
+ ".\pyro.h"\
+ ".\struct.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\cmdtoken.obj" : $(SOURCE) $(DEP_CPP_CMDTO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_CMDTO=\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\language.h"\
+ ".\object.h"\
+ ".\pyro.h"\
+ ".\struct.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\cmdtoken.obj" "$(INTDIR)\cmdtoken.sbr" : $(SOURCE) $(DEP_CPP_CMDTO)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\color.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_COLOR=\
+ ".\color.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\color.obj" : $(SOURCE) $(DEP_CPP_COLOR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_COLOR=\
+ ".\color.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\color.obj" "$(INTDIR)\color.sbr" : $(SOURCE) $(DEP_CPP_COLOR)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\compass.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_COMPA=\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\compass.obj" : $(SOURCE) $(DEP_CPP_COMPA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_COMPA=\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\compass.obj" "$(INTDIR)\compass.sbr" : $(SOURCE) $(DEP_CPP_COMPA)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\control.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_CONTR=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\particule.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\control.obj" : $(SOURCE) $(DEP_CPP_CONTR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_CONTR=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\particule.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\control.obj" "$(INTDIR)\control.sbr" : $(SOURCE) $(DEP_CPP_CONTR)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3dapp.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_D3DAP=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\joystick.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\profile.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+ "c:\dx7sdk\include\dinput.h"\
+
+
+"$(INTDIR)\d3dapp.obj" : $(SOURCE) $(DEP_CPP_D3DAP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_D3DAP=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\joystick.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\profile.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+ "c:\dx7sdk\include\dinput.h"\
+
+
+"$(INTDIR)\d3dapp.obj" "$(INTDIR)\d3dapp.sbr" : $(SOURCE) $(DEP_CPP_D3DAP)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3dengine.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_D3DEN=\
+ ".\blitz.h"\
+ ".\cloud.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\planet.h"\
+ ".\profile.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\d3dengine.obj" : $(SOURCE) $(DEP_CPP_D3DEN) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_D3DEN=\
+ ".\blitz.h"\
+ ".\cloud.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\planet.h"\
+ ".\profile.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\d3dengine.obj" "$(INTDIR)\d3dengine.sbr" : $(SOURCE)\
+ $(DEP_CPP_D3DEN) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3denum.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_D3DENU=\
+ ".\d3denum.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+
+
+"$(INTDIR)\d3denum.obj" : $(SOURCE) $(DEP_CPP_D3DENU) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_D3DENU=\
+ ".\d3denum.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+
+
+"$(INTDIR)\d3denum.obj" "$(INTDIR)\d3denum.sbr" : $(SOURCE) $(DEP_CPP_D3DENU)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3dframe.cpp
+DEP_CPP_D3DFR=\
+ ".\d3dframe.h"\
+ ".\d3dutil.h"\
+
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+
+"$(INTDIR)\d3dframe.obj" : $(SOURCE) $(DEP_CPP_D3DFR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+
+"$(INTDIR)\d3dframe.obj" "$(INTDIR)\d3dframe.sbr" : $(SOURCE) $(DEP_CPP_D3DFR)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3dmath.cpp
+DEP_CPP_D3DMA=\
+ ".\d3dmath.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+
+"$(INTDIR)\d3dmath.obj" : $(SOURCE) $(DEP_CPP_D3DMA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+
+"$(INTDIR)\d3dmath.obj" "$(INTDIR)\d3dmath.sbr" : $(SOURCE) $(DEP_CPP_D3DMA)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3dtextr.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_D3DTE=\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\language.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+
+
+"$(INTDIR)\d3dtextr.obj" : $(SOURCE) $(DEP_CPP_D3DTE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_D3DTE=\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\language.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+
+
+"$(INTDIR)\d3dtextr.obj" "$(INTDIR)\d3dtextr.sbr" : $(SOURCE) $(DEP_CPP_D3DTE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\d3dutil.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_D3DUT=\
+ ".\d3dutil.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\d3dutil.obj" : $(SOURCE) $(DEP_CPP_D3DUT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_D3DUT=\
+ ".\d3dutil.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\d3dutil.obj" "$(INTDIR)\d3dutil.sbr" : $(SOURCE) $(DEP_CPP_D3DUT)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\displayinfo.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_DISPL=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbottoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displayinfo.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\displayinfo.obj" : $(SOURCE) $(DEP_CPP_DISPL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_DISPL=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbottoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displayinfo.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\displayinfo.obj" "$(INTDIR)\displayinfo.sbr" : $(SOURCE)\
+ $(DEP_CPP_DISPL) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\displaytext.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_DISPLA=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\displaytext.obj" : $(SOURCE) $(DEP_CPP_DISPLA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_DISPLA=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\displaytext.obj" "$(INTDIR)\displaytext.sbr" : $(SOURCE)\
+ $(DEP_CPP_DISPLA) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\edit.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_EDIT_=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\scroll.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\edit.obj" : $(SOURCE) $(DEP_CPP_EDIT_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_EDIT_=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\scroll.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\edit.obj" "$(INTDIR)\edit.sbr" : $(SOURCE) $(DEP_CPP_EDIT_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\editvalue.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_EDITV=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\editvalue.obj" : $(SOURCE) $(DEP_CPP_EDITV) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_EDITV=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\editvalue.obj" "$(INTDIR)\editvalue.sbr" : $(SOURCE)\
+ $(DEP_CPP_EDITV) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\event.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_EVENT=\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\event.obj" : $(SOURCE) $(DEP_CPP_EVENT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_EVENT=\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\event.obj" "$(INTDIR)\event.sbr" : $(SOURCE) $(DEP_CPP_EVENT)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\gauge.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_GAUGE=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\gauge.obj" : $(SOURCE) $(DEP_CPP_GAUGE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_GAUGE=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\gauge.obj" "$(INTDIR)\gauge.sbr" : $(SOURCE) $(DEP_CPP_GAUGE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\group.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_GROUP=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\group.obj" : $(SOURCE) $(DEP_CPP_GROUP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_GROUP=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\group.obj" "$(INTDIR)\group.sbr" : $(SOURCE) $(DEP_CPP_GROUP)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\image.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_IMAGE=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\image.obj" : $(SOURCE) $(DEP_CPP_IMAGE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_IMAGE=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\image.obj" "$(INTDIR)\image.sbr" : $(SOURCE) $(DEP_CPP_IMAGE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\iman.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_IMAN_=\
+ ".\iman.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\iman.obj" : $(SOURCE) $(DEP_CPP_IMAN_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_IMAN_=\
+ ".\iman.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\iman.obj" "$(INTDIR)\iman.sbr" : $(SOURCE) $(DEP_CPP_IMAN_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\interface.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_INTER=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\check.h"\
+ ".\color.h"\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\key.h"\
+ ".\label.h"\
+ ".\list.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\shortcut.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\target.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\interface.obj" : $(SOURCE) $(DEP_CPP_INTER) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_INTER=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\check.h"\
+ ".\color.h"\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\key.h"\
+ ".\label.h"\
+ ".\list.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\shortcut.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\target.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\interface.obj" "$(INTDIR)\interface.sbr" : $(SOURCE)\
+ $(DEP_CPP_INTER) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\joystick.cpp
+DEP_CPP_JOYST=\
+ ".\joystick.h"\
+ "c:\dx7sdk\include\dinput.h"\
+
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+
+"$(INTDIR)\joystick.obj" : $(SOURCE) $(DEP_CPP_JOYST) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+
+"$(INTDIR)\joystick.obj" "$(INTDIR)\joystick.sbr" : $(SOURCE) $(DEP_CPP_JOYST)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\key.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_KEY_C=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\key.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\key.obj" : $(SOURCE) $(DEP_CPP_KEY_C) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_KEY_C=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\key.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\key.obj" "$(INTDIR)\key.sbr" : $(SOURCE) $(DEP_CPP_KEY_C)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\label.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_LABEL=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\label.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\label.obj" : $(SOURCE) $(DEP_CPP_LABEL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_LABEL=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\label.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\label.obj" "$(INTDIR)\label.sbr" : $(SOURCE) $(DEP_CPP_LABEL)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\light.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_LIGHT=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\light.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_LIGHT=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\light.obj" "$(INTDIR)\light.sbr" : $(SOURCE) $(DEP_CPP_LIGHT)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\list.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_LIST_=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\list.obj" : $(SOURCE) $(DEP_CPP_LIST_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_LIST_=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\list.obj" "$(INTDIR)\list.sbr" : $(SOURCE) $(DEP_CPP_LIST_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\maindialog.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MAIND=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\check.h"\
+ ".\cmdtoken.h"\
+ ".\color.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\key.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\maindialog.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\particule.h"\
+ ".\profile.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\scroll.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\maindialog.obj" : $(SOURCE) $(DEP_CPP_MAIND) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MAIND=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\check.h"\
+ ".\cmdtoken.h"\
+ ".\color.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\key.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\maindialog.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\particule.h"\
+ ".\profile.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\scroll.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\maindialog.obj" "$(INTDIR)\maindialog.sbr" : $(SOURCE)\
+ $(DEP_CPP_MAIND) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\mainmap.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MAINM=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\mainmap.h"\
+ ".\map.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\mainmap.obj" : $(SOURCE) $(DEP_CPP_MAINM) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MAINM=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\mainmap.h"\
+ ".\map.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\mainmap.obj" "$(INTDIR)\mainmap.sbr" : $(SOURCE) $(DEP_CPP_MAINM)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\mainmovie.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MAINMO=\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\mainmovie.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\mainmovie.obj" : $(SOURCE) $(DEP_CPP_MAINMO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MAINMO=\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\mainmovie.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\mainmovie.obj" "$(INTDIR)\mainmovie.sbr" : $(SOURCE)\
+ $(DEP_CPP_MAINMO) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\mainshort.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MAINS=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\mainshort.h"\
+ ".\map.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\mainshort.obj" : $(SOURCE) $(DEP_CPP_MAINS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MAINS=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\mainshort.h"\
+ ".\map.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\mainshort.obj" "$(INTDIR)\mainshort.sbr" : $(SOURCE)\
+ $(DEP_CPP_MAINS) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\map.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MAP_C=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MAP_C=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\map.obj" "$(INTDIR)\map.sbr" : $(SOURCE) $(DEP_CPP_MAP_C)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\math3d.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MATH3=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\math3d.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\math3d.obj" : $(SOURCE) $(DEP_CPP_MATH3) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MATH3=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\math3d.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\math3d.obj" "$(INTDIR)\math3d.sbr" : $(SOURCE) $(DEP_CPP_MATH3)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\metafile.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_METAF=\
+ ".\language.h"\
+ ".\metafile.h"\
+
+
+"$(INTDIR)\metafile.obj" : $(SOURCE) $(DEP_CPP_METAF) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_METAF=\
+ ".\language.h"\
+ ".\metafile.h"\
+
+
+"$(INTDIR)\metafile.obj" "$(INTDIR)\metafile.sbr" : $(SOURCE) $(DEP_CPP_METAF)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\misc.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MISC_=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\language.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MISC_=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\language.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\misc.obj" "$(INTDIR)\misc.sbr" : $(SOURCE) $(DEP_CPP_MISC_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\model.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MODEL=\
+ ".\button.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\model.h"\
+ ".\modfile.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\model.obj" : $(SOURCE) $(DEP_CPP_MODEL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MODEL=\
+ ".\button.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\model.h"\
+ ".\modfile.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\model.obj" "$(INTDIR)\model.sbr" : $(SOURCE) $(DEP_CPP_MODEL)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\modfile.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MODFI=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\modfile.obj" : $(SOURCE) $(DEP_CPP_MODFI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MODFI=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\modfile.obj" "$(INTDIR)\modfile.sbr" : $(SOURCE) $(DEP_CPP_MODFI)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motion.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIO=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motion.obj" : $(SOURCE) $(DEP_CPP_MOTIO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIO=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motion.obj" "$(INTDIR)\motion.sbr" : $(SOURCE) $(DEP_CPP_MOTIO)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionant.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTION=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionant.obj" : $(SOURCE) $(DEP_CPP_MOTION) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTION=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionant.obj" "$(INTDIR)\motionant.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTION) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionbee.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONB=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionbee.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionbee.obj" : $(SOURCE) $(DEP_CPP_MOTIONB) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONB=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionbee.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionbee.obj" "$(INTDIR)\motionbee.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONB) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionhuman.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONH=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionhuman.obj" : $(SOURCE) $(DEP_CPP_MOTIONH) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONH=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionhuman.obj" "$(INTDIR)\motionhuman.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONH) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionmother.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONM=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionmother.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionmother.obj" : $(SOURCE) $(DEP_CPP_MOTIONM) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONM=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionmother.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionmother.obj" "$(INTDIR)\motionmother.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONM) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionspider.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONS=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionspider.obj" : $(SOURCE) $(DEP_CPP_MOTIONS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONS=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionspider.obj" "$(INTDIR)\motionspider.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONS) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motiontoto.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONT=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motiontoto.obj" : $(SOURCE) $(DEP_CPP_MOTIONT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONT=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motiontoto.obj" "$(INTDIR)\motiontoto.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONT) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionvehicle.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONV=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionvehicle.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionvehicle.obj" : $(SOURCE) $(DEP_CPP_MOTIONV) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONV=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionvehicle.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionvehicle.obj" "$(INTDIR)\motionvehicle.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONV) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\motionworm.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_MOTIONW=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionworm.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionworm.obj" : $(SOURCE) $(DEP_CPP_MOTIONW) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_MOTIONW=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionworm.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\motionworm.obj" "$(INTDIR)\motionworm.sbr" : $(SOURCE)\
+ $(DEP_CPP_MOTIONW) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\object.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_OBJEC=\
+ ".\auto.h"\
+ ".\autobase.h"\
+ ".\autoconvert.h"\
+ ".\autoderrick.h"\
+ ".\autodestroyer.h"\
+ ".\autoegg.h"\
+ ".\autoenergy.h"\
+ ".\autofactory.h"\
+ ".\autoflag.h"\
+ ".\autohuston.h"\
+ ".\autoinfo.h"\
+ ".\autojostle.h"\
+ ".\autokid.h"\
+ ".\autolabo.h"\
+ ".\automush.h"\
+ ".\autonest.h"\
+ ".\autonuclear.h"\
+ ".\autopara.h"\
+ ".\autoportico.h"\
+ ".\autoradar.h"\
+ ".\autorepair.h"\
+ ".\autoresearch.h"\
+ ".\autoroot.h"\
+ ".\autosafe.h"\
+ ".\autostation.h"\
+ ".\autotower.h"\
+ ".\blitz.h"\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\cbot\cbotdll.h"\
+ ".\cbottoken.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\mainmovie.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\motionbee.h"\
+ ".\motionhuman.h"\
+ ".\motionmother.h"\
+ ".\motionspider.h"\
+ ".\motiontoto.h"\
+ ".\motionvehicle.h"\
+ ".\motionworm.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\object.obj" : $(SOURCE) $(DEP_CPP_OBJEC) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_OBJEC=\
+ ".\auto.h"\
+ ".\autobase.h"\
+ ".\autoconvert.h"\
+ ".\autoderrick.h"\
+ ".\autodestroyer.h"\
+ ".\autoegg.h"\
+ ".\autoenergy.h"\
+ ".\autofactory.h"\
+ ".\autoflag.h"\
+ ".\autohuston.h"\
+ ".\autoinfo.h"\
+ ".\autojostle.h"\
+ ".\autokid.h"\
+ ".\autolabo.h"\
+ ".\automush.h"\
+ ".\autonest.h"\
+ ".\autonuclear.h"\
+ ".\autopara.h"\
+ ".\autoportico.h"\
+ ".\autoradar.h"\
+ ".\autorepair.h"\
+ ".\autoresearch.h"\
+ ".\autoroot.h"\
+ ".\autosafe.h"\
+ ".\autostation.h"\
+ ".\autotower.h"\
+ ".\blitz.h"\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\cbot\cbotdll.h"\
+ ".\cbottoken.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\mainmovie.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\motionbee.h"\
+ ".\motionhuman.h"\
+ ".\motionmother.h"\
+ ".\motionspider.h"\
+ ".\motiontoto.h"\
+ ".\motionvehicle.h"\
+ ".\motionworm.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\object.obj" "$(INTDIR)\object.sbr" : $(SOURCE) $(DEP_CPP_OBJEC)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\particule.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_PARTI=\
+ ".\auto.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\particule.obj" : $(SOURCE) $(DEP_CPP_PARTI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_PARTI=\
+ ".\auto.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dtextr.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\particule.obj" "$(INTDIR)\particule.sbr" : $(SOURCE)\
+ $(DEP_CPP_PARTI) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\physics.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_PHYSI=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\physics.obj" : $(SOURCE) $(DEP_CPP_PHYSI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_PHYSI=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\cmdtoken.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\physics.obj" "$(INTDIR)\physics.sbr" : $(SOURCE) $(DEP_CPP_PHYSI)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\planet.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_PLANE=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\planet.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\planet.obj" : $(SOURCE) $(DEP_CPP_PLANE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_PLANE=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\planet.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\planet.obj" "$(INTDIR)\planet.sbr" : $(SOURCE) $(DEP_CPP_PLANE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\profile.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_PROFI=\
+ ".\language.h"\
+ ".\profile.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\profile.obj" : $(SOURCE) $(DEP_CPP_PROFI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_PROFI=\
+ ".\language.h"\
+ ".\profile.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\profile.obj" "$(INTDIR)\profile.sbr" : $(SOURCE) $(DEP_CPP_PROFI)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\pyro.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_PYRO_=\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\pyro.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\pyro.obj" : $(SOURCE) $(DEP_CPP_PYRO_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_PYRO_=\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\pyro.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\pyro.obj" "$(INTDIR)\pyro.sbr" : $(SOURCE) $(DEP_CPP_PYRO_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\restext.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_RESTE=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\language.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\restext.obj" : $(SOURCE) $(DEP_CPP_RESTE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_RESTE=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\language.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\restext.obj" "$(INTDIR)\restext.sbr" : $(SOURCE) $(DEP_CPP_RESTE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\robotmain.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_ROBOT=\
+ ".\auto.h"\
+ ".\autobase.h"\
+ ".\blitz.h"\
+ ".\brain.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbot\cbotdll.h"\
+ ".\cbottoken.h"\
+ ".\classfile.cpp"\
+ ".\cloud.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displayinfo.h"\
+ ".\displaytext.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\maindialog.h"\
+ ".\mainmap.h"\
+ ".\mainmovie.h"\
+ ".\mainshort.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\model.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\planet.h"\
+ ".\profile.h"\
+ ".\pyro.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\shortcut.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskbuild.h"\
+ ".\taskmanip.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\robotmain.obj" : $(SOURCE) $(DEP_CPP_ROBOT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_ROBOT=\
+ ".\auto.h"\
+ ".\autobase.h"\
+ ".\blitz.h"\
+ ".\brain.h"\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbot\cbotdll.h"\
+ ".\cbottoken.h"\
+ ".\classfile.cpp"\
+ ".\cloud.h"\
+ ".\cmdtoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displayinfo.h"\
+ ".\displaytext.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\light.h"\
+ ".\maindialog.h"\
+ ".\mainmap.h"\
+ ".\mainmovie.h"\
+ ".\mainshort.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\model.h"\
+ ".\modfile.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\motiontoto.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\planet.h"\
+ ".\profile.h"\
+ ".\pyro.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\shortcut.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskbuild.h"\
+ ".\taskmanip.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\robotmain.obj" "$(INTDIR)\robotmain.sbr" : $(SOURCE)\
+ $(DEP_CPP_ROBOT) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\script.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_SCRIP=\
+ ".\cbot\cbotdll.h"\
+ ".\cbottoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskgoto.h"\
+ ".\taskmanager.h"\
+ ".\taskmanip.h"\
+ ".\taskshield.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\script.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_SCRIP=\
+ ".\cbot\cbotdll.h"\
+ ".\cbottoken.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\global.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskgoto.h"\
+ ".\taskmanager.h"\
+ ".\taskmanip.h"\
+ ".\taskshield.h"\
+ ".\terrain.h"\
+ ".\text.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\script.obj" "$(INTDIR)\script.sbr" : $(SOURCE) $(DEP_CPP_SCRIP)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\scroll.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_SCROL=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\scroll.obj" : $(SOURCE) $(DEP_CPP_SCROL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_SCROL=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\scroll.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\scroll.obj" "$(INTDIR)\scroll.sbr" : $(SOURCE) $(DEP_CPP_SCROL)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\shortcut.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_SHORT=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\shortcut.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\shortcut.obj" : $(SOURCE) $(DEP_CPP_SHORT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_SHORT=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\shortcut.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\shortcut.obj" "$(INTDIR)\shortcut.sbr" : $(SOURCE) $(DEP_CPP_SHORT)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\slider.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_SLIDE=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\slider.obj" : $(SOURCE) $(DEP_CPP_SLIDE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_SLIDE=\
+ ".\button.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\slider.obj" "$(INTDIR)\slider.sbr" : $(SOURCE) $(DEP_CPP_SLIDE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\sound.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_SOUND=\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\sound.obj" : $(SOURCE) $(DEP_CPP_SOUND) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_SOUND=\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\sound.obj" "$(INTDIR)\sound.sbr" : $(SOURCE) $(DEP_CPP_SOUND)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\studio.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_STUDI=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbottoken.h"\
+ ".\check.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\studio.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\studio.obj" : $(SOURCE) $(DEP_CPP_STUDI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_STUDI=\
+ ".\button.h"\
+ ".\camera.h"\
+ ".\cbottoken.h"\
+ ".\check.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\event.h"\
+ ".\group.h"\
+ ".\iman.h"\
+ ".\interface.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\script.h"\
+ ".\slider.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\studio.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\studio.obj" "$(INTDIR)\studio.sbr" : $(SOURCE) $(DEP_CPP_STUDI)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\target.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TARGE=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ ".\target.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\target.obj" : $(SOURCE) $(DEP_CPP_TARGE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TARGE=\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\restext.h"\
+ ".\robotmain.h"\
+ ".\struct.h"\
+ ".\target.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\target.obj" "$(INTDIR)\target.sbr" : $(SOURCE) $(DEP_CPP_TARGE)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\task.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASK_=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\task.obj" : $(SOURCE) $(DEP_CPP_TASK_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASK_=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\task.obj" "$(INTDIR)\task.sbr" : $(SOURCE) $(DEP_CPP_TASK_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskadvance.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKA=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskadvance.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskadvance.obj" : $(SOURCE) $(DEP_CPP_TASKA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKA=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskadvance.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskadvance.obj" "$(INTDIR)\taskadvance.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKA) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskbuild.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKB=\
+ ".\auto.h"\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskbuild.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskbuild.obj" : $(SOURCE) $(DEP_CPP_TASKB) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKB=\
+ ".\auto.h"\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskbuild.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskbuild.obj" "$(INTDIR)\taskbuild.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKB) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskfire.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKF=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskfire.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskfire.obj" : $(SOURCE) $(DEP_CPP_TASKF) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKF=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskfire.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskfire.obj" "$(INTDIR)\taskfire.sbr" : $(SOURCE) $(DEP_CPP_TASKF)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskfireant.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKFI=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskfireant.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskfireant.obj" : $(SOURCE) $(DEP_CPP_TASKFI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKFI=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskfireant.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskfireant.obj" "$(INTDIR)\taskfireant.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKFI) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskflag.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKFL=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskflag.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskflag.obj" : $(SOURCE) $(DEP_CPP_TASKFL) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKFL=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskflag.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskflag.obj" "$(INTDIR)\taskflag.sbr" : $(SOURCE) $(DEP_CPP_TASKFL)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskgoto.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKG=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskgoto.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskgoto.obj" : $(SOURCE) $(DEP_CPP_TASKG) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKG=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskgoto.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskgoto.obj" "$(INTDIR)\taskgoto.sbr" : $(SOURCE) $(DEP_CPP_TASKG)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskgungoal.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKGU=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskgungoal.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskgungoal.obj" : $(SOURCE) $(DEP_CPP_TASKGU) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKGU=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskgungoal.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskgungoal.obj" "$(INTDIR)\taskgungoal.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKGU) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskinfo.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKI=\
+ ".\auto.h"\
+ ".\autoinfo.h"\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskinfo.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskinfo.obj" : $(SOURCE) $(DEP_CPP_TASKI) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKI=\
+ ".\auto.h"\
+ ".\autoinfo.h"\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskinfo.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskinfo.obj" "$(INTDIR)\taskinfo.sbr" : $(SOURCE) $(DEP_CPP_TASKI)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskmanager.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKM=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskadvance.h"\
+ ".\taskbuild.h"\
+ ".\taskfire.h"\
+ ".\taskfireant.h"\
+ ".\taskflag.h"\
+ ".\taskgoto.h"\
+ ".\taskgungoal.h"\
+ ".\taskinfo.h"\
+ ".\taskmanager.h"\
+ ".\taskmanip.h"\
+ ".\taskpen.h"\
+ ".\taskrecover.h"\
+ ".\taskreset.h"\
+ ".\tasksearch.h"\
+ ".\taskshield.h"\
+ ".\taskspiderexplo.h"\
+ ".\tasktake.h"\
+ ".\taskterraform.h"\
+ ".\taskturn.h"\
+ ".\taskwait.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskmanager.obj" : $(SOURCE) $(DEP_CPP_TASKM) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKM=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskadvance.h"\
+ ".\taskbuild.h"\
+ ".\taskfire.h"\
+ ".\taskfireant.h"\
+ ".\taskflag.h"\
+ ".\taskgoto.h"\
+ ".\taskgungoal.h"\
+ ".\taskinfo.h"\
+ ".\taskmanager.h"\
+ ".\taskmanip.h"\
+ ".\taskpen.h"\
+ ".\taskrecover.h"\
+ ".\taskreset.h"\
+ ".\tasksearch.h"\
+ ".\taskshield.h"\
+ ".\taskspiderexplo.h"\
+ ".\tasktake.h"\
+ ".\taskterraform.h"\
+ ".\taskturn.h"\
+ ".\taskwait.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskmanager.obj" "$(INTDIR)\taskmanager.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKM) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskmanip.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKMA=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskmanip.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskmanip.obj" : $(SOURCE) $(DEP_CPP_TASKMA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKMA=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskmanip.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskmanip.obj" "$(INTDIR)\taskmanip.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKMA) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskpen.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKP=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskpen.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskpen.obj" : $(SOURCE) $(DEP_CPP_TASKP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKP=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskpen.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskpen.obj" "$(INTDIR)\taskpen.sbr" : $(SOURCE) $(DEP_CPP_TASKP)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskrecover.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKR=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskrecover.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskrecover.obj" : $(SOURCE) $(DEP_CPP_TASKR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKR=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskrecover.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskrecover.obj" "$(INTDIR)\taskrecover.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKR) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskreset.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKRE=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskreset.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskreset.obj" : $(SOURCE) $(DEP_CPP_TASKRE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKRE=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskreset.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskreset.obj" "$(INTDIR)\taskreset.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKRE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\tasksearch.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKS=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\tasksearch.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\tasksearch.obj" : $(SOURCE) $(DEP_CPP_TASKS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKS=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\displaytext.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\tasksearch.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\tasksearch.obj" "$(INTDIR)\tasksearch.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKS) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskshield.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKSH=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskshield.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskshield.obj" : $(SOURCE) $(DEP_CPP_TASKSH) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKSH=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\light.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskshield.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskshield.obj" "$(INTDIR)\taskshield.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKSH) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskspiderexplo.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKSP=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskspiderexplo.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskspiderexplo.obj" : $(SOURCE) $(DEP_CPP_TASKSP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKSP=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskspiderexplo.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskspiderexplo.obj" "$(INTDIR)\taskspiderexplo.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKSP) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\tasktake.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKT=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\tasktake.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\tasktake.obj" : $(SOURCE) $(DEP_CPP_TASKT) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKT=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionhuman.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\robotmain.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\tasktake.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\tasktake.obj" "$(INTDIR)\tasktake.sbr" : $(SOURCE) $(DEP_CPP_TASKT)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskterraform.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKTE=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskterraform.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskterraform.obj" : $(SOURCE) $(DEP_CPP_TASKTE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKTE=\
+ ".\brain.h"\
+ ".\camera.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\motion.h"\
+ ".\motionant.h"\
+ ".\motionspider.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\physics.h"\
+ ".\pyro.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskterraform.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskterraform.obj" "$(INTDIR)\taskterraform.sbr" : $(SOURCE)\
+ $(DEP_CPP_TASKTE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskturn.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKTU=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskturn.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskturn.obj" : $(SOURCE) $(DEP_CPP_TASKTU) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKTU=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskturn.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskturn.obj" "$(INTDIR)\taskturn.sbr" : $(SOURCE) $(DEP_CPP_TASKTU)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\taskwait.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TASKW=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskwait.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskwait.obj" : $(SOURCE) $(DEP_CPP_TASKW) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TASKW=\
+ ".\brain.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\physics.h"\
+ ".\struct.h"\
+ ".\task.h"\
+ ".\taskwait.h"\
+ ".\terrain.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\taskwait.obj" "$(INTDIR)\taskwait.sbr" : $(SOURCE) $(DEP_CPP_TASKW)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\terrain.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TERRA=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\terrain.obj" : $(SOURCE) $(DEP_CPP_TERRA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TERRA=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\modfile.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\terrain.obj" "$(INTDIR)\terrain.sbr" : $(SOURCE) $(DEP_CPP_TERRA)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\text.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_TEXT_=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\text.obj" : $(SOURCE) $(DEP_CPP_TEXT_) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_TEXT_=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\language.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\struct.h"\
+ ".\text.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\text.obj" "$(INTDIR)\text.sbr" : $(SOURCE) $(DEP_CPP_TEXT_)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\water.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_WATER=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\water.obj" : $(SOURCE) $(DEP_CPP_WATER) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_WATER=\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dmath.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\event.h"\
+ ".\iman.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\object.h"\
+ ".\particule.h"\
+ ".\sound.h"\
+ ".\struct.h"\
+ ".\terrain.h"\
+ ".\water.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\water.obj" "$(INTDIR)\water.sbr" : $(SOURCE) $(DEP_CPP_WATER)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\window.cpp
+
+!IF "$(CFG)" == "projet1 - Win32 Release"
+
+DEP_CPP_WINDO=\
+ ".\button.h"\
+ ".\check.h"\
+ ".\color.h"\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\key.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\scroll.h"\
+ ".\shortcut.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\target.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\window.obj" : $(SOURCE) $(DEP_CPP_WINDO) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "projet1 - Win32 Debug"
+
+DEP_CPP_WINDO=\
+ ".\button.h"\
+ ".\check.h"\
+ ".\color.h"\
+ ".\compass.h"\
+ ".\control.h"\
+ ".\d3dapp.h"\
+ ".\d3dengine.h"\
+ ".\d3denum.h"\
+ ".\d3dframe.h"\
+ ".\d3dres.h"\
+ ".\d3dutil.h"\
+ ".\edit.h"\
+ ".\editvalue.h"\
+ ".\event.h"\
+ ".\gauge.h"\
+ ".\group.h"\
+ ".\image.h"\
+ ".\iman.h"\
+ ".\key.h"\
+ ".\label.h"\
+ ".\language.h"\
+ ".\list.h"\
+ ".\map.h"\
+ ".\math3d.h"\
+ ".\metafile.h"\
+ ".\misc.h"\
+ ".\restext.h"\
+ ".\scroll.h"\
+ ".\shortcut.h"\
+ ".\slider.h"\
+ ".\struct.h"\
+ ".\target.h"\
+ ".\text.h"\
+ ".\window.h"\
+ "c:\dx7sdk\include\d3dvec.inl"\
+
+
+"$(INTDIR)\window.obj" "$(INTDIR)\window.sbr" : $(SOURCE) $(DEP_CPP_WINDO)\
+ "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\winmain.rc
+DEP_RSC_WINMA=\
+ ".\cur00001.cur"\
+ ".\cur00002.cur"\
+ ".\cur00003.cur"\
+ ".\cursor1.cur"\
+ ".\cursorha.cur"\
+ ".\cursorsc.cur"\
+ ".\directx.ico"\
+
+
+"$(INTDIR)\winmain.res" : $(SOURCE) $(DEP_RSC_WINMA) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+
+!ENDIF
+
diff --git a/src/projet1.opt b/src/projet1.opt
new file mode 100644
index 0000000..46bb4db
--- /dev/null
+++ b/src/projet1.opt
Binary files differ
diff --git a/src/projet1.plg b/src/projet1.plg
new file mode 100644
index 0000000..7f5f7d2
--- /dev/null
+++ b/src/projet1.plg
@@ -0,0 +1,199 @@
+--------------------Configuration: projet1 - Win32 Release--------------------
+Begining build with project "D:\Robot\projet1\projet1.dsp", at root.
+Active configuration is Win32 (x86) Application (based on Win32 (x86) Application)
+
+Project's tools are:
+ "32-bit C/C++ Compiler for 80x86" with flags "/nologo /ML /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/projet1.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c "
+ "OLE Type Library Maker" with flags "/nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 "
+ "Win32 Resource Compiler" with flags "/l 0x100c /fo"Release/winmain.res" /d "NDEBUG" "
+ "Browser Database Maker" with flags "/nologo /o"Release/projet1.bsc" "
+ "COFF Linker for 80x86" with flags "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib c:\dx7sdk\lib\ddraw.lib c:\dx7sdk\lib\dinput.lib c:\dx7sdk\lib\dxguid.lib c:\dx7sdk\lib\d3dx.lib c:\dx7sdk\lib\dsound.lib cbot\cbot.lib /nologo /subsystem:windows /incremental:no /pdb:"Release/projet1.pdb" /machine:I386 /out:"Release/projet1.exe" "
+ "Custom Build" with flags ""
+ "<Component 0xa>" with flags ""
+
+Creating temp file "C:\Users\DANIEL~1\AppData\Local\Temp\RSPCDA8.tmp" with contents </nologo /ML /W3 /GX /Zi /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/projet1.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
+"D:\Robot\projet1\autobase.cpp"
+"D:\Robot\projet1\brain.cpp"
+"D:\Robot\projet1\button.cpp"
+"D:\Robot\projet1\camera.cpp"
+"D:\Robot\projet1\cbottoken.cpp"
+"D:\Robot\projet1\cmdtoken.cpp"
+"D:\Robot\projet1\color.cpp"
+"D:\Robot\projet1\control.cpp"
+"D:\Robot\projet1\d3dapp.cpp"
+"D:\Robot\projet1\d3dengine.cpp"
+"D:\Robot\projet1\d3dtextr.cpp"
+"D:\Robot\projet1\displayinfo.cpp"
+"D:\Robot\projet1\edit.cpp"
+"D:\Robot\projet1\maindialog.cpp"
+"D:\Robot\projet1\metafile.cpp"
+"D:\Robot\projet1\misc.cpp"
+"D:\Robot\projet1\modfile.cpp"
+"D:\Robot\projet1\particule.cpp"
+"D:\Robot\projet1\physics.cpp"
+"D:\Robot\projet1\profile.cpp"
+"D:\Robot\projet1\restext.cpp"
+"D:\Robot\projet1\robotmain.cpp"
+"D:\Robot\projet1\sound.cpp"
+"D:\Robot\projet1\studio.cpp"
+"D:\Robot\projet1\taskterraform.cpp"
+"D:\Robot\projet1\terrain.cpp"
+"D:\Robot\projet1\text.cpp"
+"D:\Robot\projet1\window.cpp"
+>
+Creating command line "cl.exe @C:\Users\DANIEL~1\AppData\Local\Temp\RSPCDA8.tmp"
+Creating temp file "C:\Users\DANIEL~1\AppData\Local\Temp\RSPCDA9.tmp" with contents <kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib c:\dx7sdk\lib\ddraw.lib c:\dx7sdk\lib\dinput.lib c:\dx7sdk\lib\dxguid.lib c:\dx7sdk\lib\d3dx.lib c:\dx7sdk\lib\dsound.lib cbot\cbot.lib /nologo /subsystem:windows /incremental:no /pdb:"Release/projet1.pdb" /machine:I386 /out:"Release/projet1.exe"
+.\Release\auto.obj
+.\Release\autobase.obj
+.\Release\autoconvert.obj
+.\Release\autoderrick.obj
+.\Release\autodestroyer.obj
+.\Release\autoegg.obj
+.\Release\autoenergy.obj
+.\Release\autofactory.obj
+.\Release\autoflag.obj
+.\Release\autohuston.obj
+.\Release\autoinfo.obj
+.\Release\autojostle.obj
+.\Release\autokid.obj
+.\Release\autolabo.obj
+.\Release\automush.obj
+.\Release\autonest.obj
+.\Release\autonuclear.obj
+.\Release\autopara.obj
+.\Release\autoportico.obj
+.\Release\autoradar.obj
+.\Release\autorepair.obj
+.\Release\autoresearch.obj
+.\Release\autoroot.obj
+.\Release\autosafe.obj
+.\Release\autostation.obj
+.\Release\autotower.obj
+.\Release\blitz.obj
+.\Release\brain.obj
+.\Release\button.obj
+.\Release\camera.obj
+.\Release\cbottoken.obj
+.\Release\check.obj
+.\Release\cloud.obj
+.\Release\cmdtoken.obj
+.\Release\color.obj
+.\Release\compass.obj
+.\Release\control.obj
+.\Release\d3dapp.obj
+.\Release\d3dengine.obj
+.\Release\d3denum.obj
+.\Release\d3dframe.obj
+.\Release\d3dmath.obj
+.\Release\d3dtextr.obj
+.\Release\d3dutil.obj
+.\Release\displayinfo.obj
+.\Release\displaytext.obj
+.\Release\edit.obj
+.\Release\editvalue.obj
+.\Release\event.obj
+.\Release\gauge.obj
+.\Release\group.obj
+.\Release\image.obj
+.\Release\iman.obj
+.\Release\interface.obj
+.\Release\joystick.obj
+.\Release\key.obj
+.\Release\label.obj
+.\Release\light.obj
+.\Release\list.obj
+.\Release\maindialog.obj
+.\Release\mainmap.obj
+.\Release\mainmovie.obj
+.\Release\mainshort.obj
+.\Release\map.obj
+.\Release\math3d.obj
+.\Release\metafile.obj
+.\Release\misc.obj
+.\Release\model.obj
+.\Release\modfile.obj
+.\Release\motion.obj
+.\Release\motionant.obj
+.\Release\motionbee.obj
+.\Release\motionhuman.obj
+.\Release\motionmother.obj
+.\Release\motionspider.obj
+.\Release\motiontoto.obj
+.\Release\motionvehicle.obj
+.\Release\motionworm.obj
+.\Release\object.obj
+.\Release\particule.obj
+.\Release\physics.obj
+.\Release\planet.obj
+.\Release\profile.obj
+.\Release\pyro.obj
+.\Release\restext.obj
+.\Release\robotmain.obj
+.\Release\script.obj
+.\Release\scroll.obj
+.\Release\shortcut.obj
+.\Release\slider.obj
+.\Release\sound.obj
+.\Release\studio.obj
+.\Release\target.obj
+.\Release\task.obj
+.\Release\taskadvance.obj
+.\Release\taskbuild.obj
+.\Release\taskfire.obj
+.\Release\taskfireant.obj
+.\Release\taskflag.obj
+.\Release\taskgoto.obj
+.\Release\taskgungoal.obj
+.\Release\taskinfo.obj
+.\Release\taskmanager.obj
+.\Release\taskmanip.obj
+.\Release\taskpen.obj
+.\Release\taskrecover.obj
+.\Release\taskreset.obj
+.\Release\tasksearch.obj
+.\Release\taskshield.obj
+.\Release\taskspiderexplo.obj
+.\Release\tasktake.obj
+.\Release\taskterraform.obj
+.\Release\taskturn.obj
+.\Release\taskwait.obj
+.\Release\terrain.obj
+.\Release\text.obj
+.\Release\water.obj
+.\Release\window.obj
+.\Release\winmain.res>
+Creating command line "link.exe @C:\Users\DANIEL~1\AppData\Local\Temp\RSPCDA9.tmp"
+Compiling...
+autobase.cpp
+brain.cpp
+button.cpp
+camera.cpp
+cbottoken.cpp
+cmdtoken.cpp
+color.cpp
+control.cpp
+d3dapp.cpp
+d3dengine.cpp
+d3dtextr.cpp
+displayinfo.cpp
+edit.cpp
+maindialog.cpp
+metafile.cpp
+misc.cpp
+modfile.cpp
+particule.cpp
+physics.cpp
+profile.cpp
+restext.cpp
+robotmain.cpp
+sound.cpp
+studio.cpp
+taskterraform.cpp
+terrain.cpp
+text.cpp
+window.cpp
+Linking...
+
+
+
+projet1.exe - 0 error(s), 0 warning(s)
diff --git a/src/pyro.cpp b/src/pyro.cpp
new file mode 100644
index 0000000..9ef4eac
--- /dev/null
+++ b/src/pyro.cpp
@@ -0,0 +1,2470 @@
+// pyro.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "robotmain.h"
+#include "terrain.h"
+#include "camera.h"
+#include "particule.h"
+#include "light.h"
+#include "object.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "displaytext.h"
+#include "sound.h"
+#include "pyro.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CPyro::CPyro(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_PYRO, this, 100);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ m_object = 0;
+
+ m_progress = 0.0f;
+ m_speed = 0.0f;
+ m_lightRank = -1;
+ m_soundChannel = -1;
+ LightOperFlush();
+}
+
+// Destructeur de l'objet.
+
+CPyro::~CPyro()
+{
+ m_iMan->DeleteInstance(CLASS_PYRO, this);
+}
+
+
+// Détruit l'objet.
+
+void CPyro::DeleteObject(BOOL bAll)
+{
+ if ( m_lightRank != -1 )
+ {
+ m_light->DeleteLight(m_lightRank);
+ m_lightRank = -1;
+ }
+}
+
+
+// Crée un effet pyrotechnique.
+
+BOOL CPyro::Create(PyroType type, CObject* pObj, float force)
+{
+ D3DMATRIX* mat;
+ CObject* power;
+ CMotion* motion;
+ D3DVECTOR min, max, pos, speed;
+ FPOINT dim;
+ ObjectType oType;
+ Sound sound;
+ float duration, mass, h, limit;
+ int part, objRank, total, i, channel;
+
+ m_object = pObj;
+ m_force = force;
+
+ oType = pObj->RetType();
+ objRank = pObj->RetObjectRank(0);
+ if ( objRank == -1 ) return FALSE;
+ m_engine->GetBBox(objRank, min, max);
+ pos = pObj->RetPosition(0);
+
+ DisplayError(type, pObj); // affiche message éventuel
+
+ // Copie toutes les sphères de l'objet.
+ for ( i=0 ; i<50 ; i++ )
+ {
+ if ( !pObj->GetCrashSphere(i, m_crashSpherePos[i], m_crashSphereRadius[i]) ) break;
+ }
+ m_crashSphereUsed = i;
+
+ // Calcule la dimension de l'effet.
+ if ( oType == OBJECT_ANT ||
+ oType == OBJECT_BEE ||
+ oType == OBJECT_WORM ||
+ oType == OBJECT_SPIDER )
+ {
+ m_size = 40.0f;
+ }
+ else
+ {
+ m_size = Length(min, max)*2.0f;
+ if ( m_size < 4.0f ) m_size = 4.0f;
+ if ( m_size > 80.0f ) m_size = 80.0f;
+ }
+ if ( oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB )
+ {
+ m_size *= 2.0f;
+ }
+
+ m_pos = pos+(min+max)/2.0f;
+ m_type = type;
+ m_progress = 0.0f;
+ m_speed = 1.0f/20.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_lastParticuleSmoke = 0.0f;
+ m_lightRank = -1;
+
+ if ( oType == OBJECT_TEEN28 ||
+ oType == OBJECT_TEEN31 )
+ {
+ m_pos.y = pos.y+1.0f;
+ }
+
+ // Cherche la position de la pile.
+ power = pObj->RetPower();
+ if ( power == 0 )
+ {
+ m_bPower = FALSE;
+ }
+ else
+ {
+ m_bPower = TRUE;
+ pos = power->RetPosition(0);
+ pos.y += 1.0f;
+ mat = pObj->RetWorldMatrix(0);
+ m_posPower = Transform(*mat, pos);
+ }
+ if ( oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_URANIUM ||
+ oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB )
+ {
+ m_bPower = TRUE;
+ m_posPower = m_pos;
+ m_posPower.y += 1.0f;
+ m_pos = m_posPower;
+ }
+ if ( oType == OBJECT_STATION )
+ {
+ m_bPower = TRUE;
+ mat = pObj->RetWorldMatrix(0);
+ m_posPower = Transform(*mat, D3DVECTOR(-15.0f, 7.0f, 0.0f));
+ m_pos = m_posPower;
+ }
+ if ( oType == OBJECT_ENERGY )
+ {
+ m_bPower = TRUE;
+ mat = pObj->RetWorldMatrix(0);
+ m_posPower = Transform(*mat, D3DVECTOR(-7.0f, 6.0f, 0.0f));
+ m_pos = m_posPower;
+ }
+ if ( oType == OBJECT_NUCLEAR )
+ {
+ m_bPower = TRUE;
+ m_posPower = m_pos;
+ }
+ if ( oType == OBJECT_PARA )
+ {
+ m_bPower = TRUE;
+ m_posPower = m_pos;
+ }
+ if ( oType == OBJECT_SCRAP4 ||
+ oType == OBJECT_SCRAP5 ) // matière plastique ?
+ {
+ m_bPower = TRUE;
+ m_posPower = m_pos;
+ }
+
+ // Fait entendre le bruit de l'effet pyrotechnique.
+ if ( type == PT_FRAGT ||
+ type == PT_FRAGW ||
+ type == PT_EXPLOT ||
+ type == PT_EXPLOW )
+ {
+ if ( m_bPower )
+ {
+ sound = SOUND_EXPLOp;
+ }
+ else
+ {
+ sound = SOUND_EXPLO;
+ }
+ if ( oType == OBJECT_STONE ||
+ oType == OBJECT_METAL ||
+ oType == OBJECT_BULLET ||
+ oType == OBJECT_BBOX ||
+ oType == OBJECT_KEYa ||
+ oType == OBJECT_KEYb ||
+ oType == OBJECT_KEYc ||
+ oType == OBJECT_KEYd )
+ {
+ sound = SOUND_EXPLOl;
+ }
+ if ( oType == OBJECT_URANIUM ||
+ oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB )
+ {
+ sound = SOUND_EXPLOlp;
+ }
+ m_sound->Play(sound, m_pos);
+ }
+ if ( type == PT_FRAGO ||
+ type == PT_EXPLOO ||
+ type == PT_SPIDER ||
+ type == PT_SHOTM )
+ {
+ m_sound->Play(SOUND_EXPLOi, m_pos);
+ }
+ if ( type == PT_BURNT ||
+ type == PT_BURNO )
+ {
+ m_soundChannel = m_sound->Play(SOUND_BURN, m_pos, 1.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 12.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 5.0f, SOPER_STOP);
+ }
+ if ( type == PT_BURNO )
+ {
+ m_sound->Play(SOUND_DEADi, m_pos);
+ m_sound->Play(SOUND_DEADi, m_engine->RetEyePt());
+ }
+ if ( type == PT_EGG )
+ {
+ m_sound->Play(SOUND_EGG, m_pos);
+ }
+ if ( type == PT_WPCHECK ||
+ type == PT_FLCREATE ||
+ type == PT_FLDELETE )
+ {
+ m_sound->Play(SOUND_WAYPOINT, m_pos);
+ }
+ if ( oType == OBJECT_HUMAN )
+ {
+ if ( type == PT_DEADG )
+ {
+ m_sound->Play(SOUND_DEADg, m_pos);
+ }
+ if ( type == PT_DEADW )
+ {
+ m_sound->Play(SOUND_DEADw, m_pos);
+ }
+ if ( type == PT_SHOTH && m_object->RetSelect() )
+ {
+ m_sound->Play(SOUND_AIE, m_pos);
+ m_sound->Play(SOUND_AIE, m_engine->RetEyePt());
+ }
+ }
+
+ if ( m_type == PT_FRAGT ||
+ m_type == PT_FRAGO ||
+ m_type == PT_FRAGW )
+ {
+ m_engine->ShadowDelete(m_object->RetObjectRank(0));
+ }
+
+ if ( m_type == PT_DEADG )
+ {
+ m_object->SetDead(TRUE);
+
+ motion = m_object->RetMotion();
+ if ( motion != 0 )
+ {
+ motion->SetAction(MHS_DEADg, 1.0f);
+ }
+ m_camera->StartCentering(m_object, PI*0.5f, 99.9f, 0.0f, 1.5f);
+ m_camera->StartOver(OE_FADEOUTw, m_pos, 1.0f);
+ m_speed = 1.0f/10.0f;
+ return TRUE;
+ }
+ if ( m_type == PT_DEADW )
+ {
+ m_object->SetDead(TRUE);
+
+ motion = m_object->RetMotion();
+ if ( motion != 0 )
+ {
+ motion->SetAction(MHS_DEADw, 4.0f);
+ }
+ m_camera->StartCentering(m_object, PI*0.5f, 99.9f, 0.0f, 3.0f);
+ m_camera->StartOver(OE_FADEOUTb, m_pos, 1.0f);
+ m_speed = 1.0f/10.0f;
+ return TRUE;
+ }
+
+ if ( m_type == PT_SHOTT ||
+ m_type == PT_SHOTM )
+ {
+ m_camera->StartEffect(CE_SHOT, m_pos, force);
+ m_speed = 1.0f/1.0f;
+ return TRUE;
+ }
+ if ( m_type == PT_SHOTH )
+ {
+ if ( m_object->RetSelect() )
+ {
+ m_camera->StartOver(OE_BLOOD, m_pos, force);
+ }
+ m_speed = 1.0f/0.2f;
+ return TRUE;
+ }
+
+ if ( m_type == PT_SHOTW )
+ {
+ m_speed = 1.0f/1.0f;
+ }
+
+ if ( m_type == PT_BURNT )
+ {
+ BurnStart();
+ }
+
+ if ( m_type == PT_WPCHECK )
+ {
+ m_speed = 1.0f/8.0f;
+ m_object->SetEnable(FALSE); // objet plus fonctionnel
+ }
+ if ( m_type == PT_FLCREATE )
+ {
+ m_speed = 1.0f/2.0f;
+ }
+ if ( m_type == PT_FLDELETE )
+ {
+ m_speed = 1.0f/2.0f;
+ m_object->SetEnable(FALSE); // objet plus fonctionnel
+ }
+ if ( m_type == PT_RESET )
+ {
+ m_speed = 1.0f/2.0f;
+ m_object->SetPosition(0, m_object->RetResetPosition());
+ m_object->SetAngle(0, m_object->RetResetAngle());
+ m_object->SetZoom(0, 0.0f);
+ }
+ if ( m_type == PT_FINDING )
+ {
+ limit = (m_size-1.0f)/4.0f;
+ if ( limit > 8.0f ) limit = 8.0f;
+ if ( oType == OBJECT_APOLLO2 ) limit = 2.0f;
+ m_speed = 1.0f/limit;
+ }
+
+ if ( m_type == PT_EXPLOT ||
+ m_type == PT_EXPLOO ||
+ m_type == PT_EXPLOW )
+ {
+ CreateTriangle(pObj, oType, 0);
+ m_engine->ShadowDelete(m_object->RetObjectRank(0));
+ ExploStart();
+ }
+
+ if ( m_type == PT_FALL )
+ {
+ FallStart();
+ return TRUE;
+ }
+
+ if ( m_type == PT_BURNT ||
+ m_type == PT_BURNO )
+ {
+ m_speed = 1.0f/15.0f;
+
+ LightOperAdd(0.00f, 0.0f, 2.0f, 1.0f, 0.0f); // rouge-orange
+ LightOperAdd(0.30f, 1.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ LightOperAdd(0.80f, 1.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ CreateLight(m_pos, 40.0f);
+ return TRUE;
+ }
+
+ if ( m_type == PT_SPIDER )
+ {
+ m_speed = 1.0f/15.0f;
+
+ pos = D3DVECTOR(-3.0f, 2.0f, 0.0f);
+ mat = pObj->RetWorldMatrix(0);
+ m_pos = Transform(*mat, pos);
+
+ m_engine->ShadowDelete(m_object->RetObjectRank(0));
+ }
+
+ if ( m_type != PT_EGG &&
+ m_type != PT_WIN &&
+ m_type != PT_LOST )
+ {
+ h = 40.0f;
+ if ( m_type == PT_FRAGO ||
+ m_type == PT_EXPLOO )
+ {
+ LightOperAdd(0.00f, 0.0f, -1.0f, -0.5f, -1.0f); // vert foncé
+ LightOperAdd(0.05f, 1.0f, -1.0f, -0.5f, -1.0f); // vert foncé
+ LightOperAdd(1.00f, 0.0f, -1.0f, -0.5f, -1.0f); // vert foncé
+ }
+ else if ( m_type == PT_FRAGT ||
+ m_type == PT_EXPLOT )
+ {
+ LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // jaune
+ LightOperAdd(0.02f, 1.0f, 4.0f, 2.0f, 0.0f); // rouge-orange
+ LightOperAdd(0.16f, 1.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ h = m_size*2.0f;
+ }
+ else if ( m_type == PT_SPIDER )
+ {
+ LightOperAdd(0.00f, 0.0f, -0.5f, -1.0f, -1.0f); // rouge foncé
+ LightOperAdd(0.05f, 1.0f, -0.5f, -1.0f, -1.0f); // rouge foncé
+ LightOperAdd(1.00f, 0.0f, -0.5f, -1.0f, -1.0f); // rouge foncé
+ }
+ else if ( m_type == PT_FRAGW ||
+ m_type == PT_EXPLOW ||
+ m_type == PT_SHOTW )
+ {
+ LightOperAdd(0.00f, 0.0f, -0.5f, -0.5f, -1.0f); // jaune foncé
+ LightOperAdd(0.05f, 1.0f, -0.5f, -0.5f, -1.0f); // jaune foncé
+ LightOperAdd(1.00f, 0.0f, -0.5f, -0.5f, -1.0f); // jaune foncé
+ }
+ else if ( m_type == PT_WPCHECK ||
+ m_type == PT_FLCREATE ||
+ m_type == PT_FLDELETE ||
+ m_type == PT_RESET ||
+ m_type == PT_FINDING )
+ {
+ LightOperAdd(0.00f, 1.0f, 4.0f, 4.0f, 2.0f); // jaune
+ LightOperAdd(1.00f, 0.0f, 4.0f, 4.0f, 2.0f); // jaune
+ }
+ else
+ {
+ LightOperAdd(0.00f, 0.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ LightOperAdd(0.05f, 1.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ LightOperAdd(1.00f, 0.0f, -0.8f, -0.8f, -0.8f); // gris foncé
+ }
+ CreateLight(m_pos, h);
+
+ if ( m_type != PT_SHOTW &&
+ m_type != PT_WPCHECK &&
+ m_type != PT_FLCREATE &&
+ m_type != PT_FLDELETE &&
+ m_type != PT_RESET &&
+ m_type != PT_FINDING )
+ {
+ m_camera->StartEffect(CE_EXPLO, m_pos, force);
+ }
+ }
+
+ if ( m_type == PT_SHOTW ) return TRUE;
+
+ // Génère les triangles de l'explosion.
+ if ( m_type == PT_FRAGT ||
+ m_type == PT_FRAGO ||
+ m_type == PT_FRAGW ||
+ m_type == PT_SPIDER ||
+ m_type == PT_EGG ||
+ (m_type == PT_EXPLOT && oType == OBJECT_MOBILEtg) ||
+ (m_type == PT_EXPLOT && oType == OBJECT_TEEN28 ) ||
+ (m_type == PT_EXPLOT && oType == OBJECT_TEEN31 ) )
+ {
+ for ( part=0 ; part<OBJECTMAXPART ; part++ )
+ {
+ CreateTriangle(pObj, oType, part);
+ }
+ }
+
+ if ( m_type == PT_FRAGT ||
+ m_type == PT_EXPLOT )
+ {
+ if ( m_bPower )
+ {
+ total = (int)(10.0f*m_engine->RetParticuleDensity());
+ if ( oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB ) total *= 3;
+ for ( i=0 ; i<total ; i++ )
+ {
+ pos = m_posPower;
+ speed.x = (Rand()-0.5f)*30.0f;
+ speed.z = (Rand()-0.5f)*30.0f;
+ speed.y = Rand()*30.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ duration = Rand()*3.0f+2.0f;
+ mass = Rand()*10.0f+15.0f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK1,
+ duration, mass, Rand()+0.7f, 1.0f);
+ }
+ }
+
+ if ( m_size > 10.0f ) // assez grand (fret exclu) ?
+ {
+ if ( m_bPower )
+ {
+ pos = m_posPower;
+ }
+ else
+ {
+ pos = m_pos;
+ m_terrain->MoveOnFloor(pos);
+ pos.y += 1.0f;
+ }
+ dim.x = m_size*0.4f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, D3DVECTOR(0.0f,0.0f,0.0f), dim, PARTISPHERE0, 2.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_type == PT_FRAGO ||
+ m_type == PT_EXPLOO )
+ {
+ total = (int)(10.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<total ; i++ )
+ {
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*30.0f;
+ speed.z = (Rand()-0.5f)*30.0f;
+ speed.y = Rand()*50.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ duration = Rand()*1.0f+0.8f;
+ mass = Rand()*10.0f+15.0f;
+ m_particule->CreateParticule(pos, speed, dim, PARTIORGANIC1,
+ duration, mass);
+ }
+ total = (int)(5.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<total ; i++ )
+ {
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*30.0f;
+ speed.z = (Rand()-0.5f)*30.0f;
+ speed.y = Rand()*50.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ duration = Rand()*2.0f+1.4f;
+ mass = Rand()*10.0f+15.0f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK4,
+ duration, mass, duration*0.5f, dim.x*2.0f);
+ }
+ }
+
+ if ( m_type == PT_SPIDER )
+ {
+ for ( i=0 ; i<50 ; i++ )
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ pos.y += (Rand()-0.5f)*2.0f;
+ speed.x = (Rand()-0.5f)*24.0f;
+ speed.z = (Rand()-0.5f)*24.0f;
+ speed.y = 10.0f+Rand()*10.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN3, 2.0f+Rand()*2.0f, 10.0f);
+ m_particule->SetObjectFather(channel, pObj);
+ }
+ total = (int)(10.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<total ; i++ )
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ pos.y += (Rand()-0.5f)*2.0f;
+ speed.x = (Rand()-0.5f)*24.0f;
+ speed.z = (Rand()-0.5f)*24.0f;
+ speed.y = 7.0f+Rand()*7.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK3,
+ 2.0f+Rand()*2.0f, 10.0f, 2.0f, 0.6f);
+ }
+ }
+
+ if ( type == PT_FRAGT ||
+ type == PT_FRAGW ||
+ type == PT_EXPLOT ||
+ type == PT_EXPLOW )
+ {
+ if ( m_size > 10.0f || m_bPower )
+ {
+ pos = m_pos;
+//? m_terrain->MoveOnFloor(pos);
+//? pos.y += 2.0f;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = m_size;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICHOC, 2.0f);
+ }
+ }
+
+ return TRUE;
+}
+
+// Crée une explosion sous forme de particules triangulaires.
+
+void CPyro::CreateTriangle(CObject* pObj, ObjectType oType, int part)
+{
+ D3DTriangle buffer[100];
+ D3DMATRIX* mat;
+ D3DVECTOR offset, pos, speed;
+ float percent, min, max, h, duration, mass;
+ int objRank, total, i;
+
+ objRank = pObj->RetObjectRank(part);
+ if ( objRank == -1 ) return;
+
+ min = 0.0f;
+ max = m_engine->RetLimitLOD(0);
+ total = m_engine->RetTotalTriangles(objRank);
+ percent = 0.10f;
+ if ( total < 50 ) percent = 0.25f;
+ if ( total < 20 ) percent = 0.50f;
+ if ( m_type == PT_EGG ) percent = 0.30f;
+ if ( oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_URANIUM ||
+ oType == OBJECT_TNT ||
+ oType == OBJECT_BOMB ) percent = 0.75f;
+ if ( oType == OBJECT_MOBILEtg ) percent = 0.50f;
+ if ( oType == OBJECT_TEEN28 ) percent = 0.75f;
+ if ( oType == OBJECT_MOTHER ) max = 1000000.0f;
+ if ( oType == OBJECT_TEEN28 ) max = 1000000.0f;
+ if ( oType == OBJECT_TEEN31 ) max = 1000000.0f;
+ total = m_engine->GetTriangles(objRank, min, max, buffer, 100, percent);
+
+ for ( i=0 ; i<total ; i++ )
+ {
+ D3DVECTOR p1, p2, p3;
+
+ p1.x = buffer[i].triangle[0].x;
+ p1.y = buffer[i].triangle[0].y;
+ p1.z = buffer[i].triangle[0].z;
+ p2.x = buffer[i].triangle[1].x;
+ p2.y = buffer[i].triangle[1].y;
+ p2.z = buffer[i].triangle[1].z;
+ p3.x = buffer[i].triangle[2].x;
+ p3.y = buffer[i].triangle[2].y;
+ p3.z = buffer[i].triangle[2].z;
+
+ h = Length(p1, p2);
+ if ( h > 5.0f )
+ {
+ p2.x = p1.x+((p2.x-p1.x)*5.0f/h);
+ p2.y = p1.y+((p2.y-p1.y)*5.0f/h);
+ p2.z = p1.z+((p2.z-p1.z)*5.0f/h);
+ }
+
+ h = Length(p2, p3);
+ if ( h > 5.0f )
+ {
+ p3.x = p2.x+((p3.x-p2.x)*5.0f/h);
+ p3.y = p2.y+((p3.y-p2.y)*5.0f/h);
+ p3.z = p2.z+((p3.z-p2.z)*5.0f/h);
+ }
+
+ h = Length(p3, p1);
+ if ( h > 5.0f )
+ {
+ p1.x = p3.x+((p1.x-p3.x)*5.0f/h);
+ p1.y = p3.y+((p1.y-p3.y)*5.0f/h);
+ p1.z = p3.z+((p1.z-p3.z)*5.0f/h);
+ }
+
+ buffer[i].triangle[0].x = p1.x;
+ buffer[i].triangle[0].y = p1.y;
+ buffer[i].triangle[0].z = p1.z;
+ buffer[i].triangle[1].x = p2.x;
+ buffer[i].triangle[1].y = p2.y;
+ buffer[i].triangle[1].z = p2.z;
+ buffer[i].triangle[2].x = p3.x;
+ buffer[i].triangle[2].y = p3.y;
+ buffer[i].triangle[2].z = p3.z;
+
+ offset.x = (buffer[i].triangle[0].x+buffer[i].triangle[1].x+buffer[i].triangle[2].x)/3.0f;
+ offset.y = (buffer[i].triangle[0].y+buffer[i].triangle[1].y+buffer[i].triangle[2].y)/3.0f;
+ offset.z = (buffer[i].triangle[0].z+buffer[i].triangle[1].z+buffer[i].triangle[2].z)/3.0f;
+
+ buffer[i].triangle[0].x -= offset.x;
+ buffer[i].triangle[1].x -= offset.x;
+ buffer[i].triangle[2].x -= offset.x;
+
+ buffer[i].triangle[0].y -= offset.y;
+ buffer[i].triangle[1].y -= offset.y;
+ buffer[i].triangle[2].y -= offset.y;
+
+ buffer[i].triangle[0].z -= offset.z;
+ buffer[i].triangle[1].z -= offset.z;
+ buffer[i].triangle[2].z -= offset.z;
+
+ mat = pObj->RetWorldMatrix(part);
+ pos = Transform(*mat, offset);
+ if ( m_type == PT_EGG )
+ {
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*15.0f;
+ mass = Rand()*20.0f+20.0f;
+ }
+ else if ( m_type == PT_SPIDER )
+ {
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = Rand()*20.0f;
+ mass = Rand()*10.0f+15.0f;
+ }
+ else
+ {
+ speed.x = (Rand()-0.5f)*30.0f;
+ speed.z = (Rand()-0.5f)*30.0f;
+ speed.y = Rand()*30.0f;
+ mass = Rand()*10.0f+15.0f;
+ }
+ if ( oType == OBJECT_STONE ) speed *= 0.5f;
+ if ( oType == OBJECT_URANIUM ) speed *= 0.4f;
+ duration = Rand()*3.0f+3.0f;
+ m_particule->CreateFrag(pos, speed, &buffer[i], PARTIFRAG,
+ duration, mass, 0.5f);
+ }
+}
+
+// Affiche l'erreur ou l'information éventuelle, liée à la destruction
+// d'un insecte, d'un véhicule ou d'un batiment.
+
+void CPyro::DisplayError(PyroType type, CObject* pObj)
+{
+ ObjectType oType;
+ Error err;
+
+ oType = pObj->RetType();
+
+ if ( type == PT_FRAGT ||
+ type == PT_FRAGO ||
+ type == PT_FRAGW ||
+ type == PT_EXPLOT ||
+ type == PT_EXPLOO ||
+ type == PT_EXPLOW ||
+ type == PT_BURNT ||
+ type == PT_BURNO )
+ {
+ err = ERR_OK;
+ if ( oType == OBJECT_MOTHER ) err = INFO_DELETEMOTHER;
+ if ( oType == OBJECT_ANT ) err = INFO_DELETEANT;
+ if ( oType == OBJECT_BEE ) err = INFO_DELETEBEE;
+ if ( oType == OBJECT_WORM ) err = INFO_DELETEWORM;
+ if ( oType == OBJECT_SPIDER ) err = INFO_DELETESPIDER;
+
+ if ( oType == OBJECT_MOBILEwa ||
+ oType == OBJECT_MOBILEta ||
+ oType == OBJECT_MOBILEfa ||
+ oType == OBJECT_MOBILEia ||
+ oType == OBJECT_MOBILEwc ||
+ oType == OBJECT_MOBILEtc ||
+ oType == OBJECT_MOBILEfc ||
+ oType == OBJECT_MOBILEic ||
+ oType == OBJECT_MOBILEwi ||
+ oType == OBJECT_MOBILEti ||
+ oType == OBJECT_MOBILEfi ||
+ oType == OBJECT_MOBILEii ||
+ oType == OBJECT_MOBILEws ||
+ oType == OBJECT_MOBILEts ||
+ oType == OBJECT_MOBILEfs ||
+ oType == OBJECT_MOBILEis ||
+ oType == OBJECT_MOBILErt ||
+ oType == OBJECT_MOBILErc ||
+ oType == OBJECT_MOBILErr ||
+ oType == OBJECT_MOBILErs ||
+ oType == OBJECT_MOBILEsa ||
+ oType == OBJECT_MOBILEwt ||
+ oType == OBJECT_MOBILEtt ||
+ oType == OBJECT_MOBILEft ||
+ oType == OBJECT_MOBILEit ||
+ oType == OBJECT_MOBILEdr )
+ {
+ err = ERR_DELETEMOBILE;
+ }
+
+ if ( oType == OBJECT_DERRICK ||
+ oType == OBJECT_FACTORY ||
+ oType == OBJECT_STATION ||
+ oType == OBJECT_CONVERT ||
+ oType == OBJECT_REPAIR ||
+ oType == OBJECT_DESTROYER||
+ oType == OBJECT_TOWER ||
+ oType == OBJECT_RESEARCH ||
+ oType == OBJECT_RADAR ||
+ oType == OBJECT_INFO ||
+ oType == OBJECT_ENERGY ||
+ oType == OBJECT_LABO ||
+ oType == OBJECT_NUCLEAR ||
+ oType == OBJECT_PARA ||
+ oType == OBJECT_SAFE ||
+ oType == OBJECT_HUSTON ||
+ oType == OBJECT_START ||
+ oType == OBJECT_END )
+ {
+ err = ERR_DELETEBUILDING;
+ m_displayText->DisplayError(err, pObj->RetPosition(0), 5.0f);
+ return;
+ }
+
+ if ( err != ERR_OK )
+ {
+ m_displayText->DisplayError(err, pObj);
+ }
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CPyro::EventProcess(const Event &event)
+{
+ ParticuleType type;
+ D3DVECTOR pos, speed, angle;
+ FPOINT dim;
+ float prog, factor, duration;
+ int i, r;
+
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_engine->RetPause() ) return TRUE;
+
+ m_time += event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ if ( m_soundChannel != -1 && m_object != 0 )
+ {
+ pos = m_object->RetPosition(0);
+ m_sound->Position(m_soundChannel, pos);
+
+ if ( m_lightRank != -1 )
+ {
+ pos.y += m_lightHeight;
+ m_light->SetLightPos(m_lightRank, pos);
+ }
+ }
+
+ if ( m_type == PT_SHOTT &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ if ( m_crashSphereUsed > 0 )
+ {
+ i = rand()%m_crashSphereUsed;
+ pos = m_crashSpherePos[i];
+ pos.x += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f;
+ pos.z += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f;
+ speed.x = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f;
+ speed.z = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f;
+ speed.y = Rand()*m_crashSphereRadius[i]*1.0f;
+ dim.x = Rand()*m_crashSphereRadius[i]*0.5f+m_crashSphereRadius[i]*0.75f*m_force;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f);
+ }
+ else
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*m_size*0.3f;
+ pos.z += (Rand()-0.5f)*m_size*0.3f;
+ speed.x = (Rand()-0.5f)*m_size*0.1f;
+ speed.z = (Rand()-0.5f)*m_size*0.1f;
+ speed.y = Rand()*m_size*0.2f;
+ dim.x = Rand()*m_size/10.0f+m_size/10.0f*m_force;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f);
+ }
+ }
+
+ if ( m_type == PT_SHOTH &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ for ( i=0 ; i<10 ; i++ )
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*m_size*0.2f;
+ pos.z += (Rand()-0.5f)*m_size*0.2f;
+ pos.y += (Rand()-0.5f)*m_size*0.5f;
+ speed.x = (Rand()-0.5f)*5.0f;
+ speed.z = (Rand()-0.5f)*5.0f;
+ speed.y = Rand()*1.0f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLOOD, Rand()*3.0f+3.0f, Rand()*10.0f+15.0f, 0.5f);
+ }
+ }
+
+ if ( m_type == PT_SHOTM &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ r = (int)(10.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<r ; i++ )
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*20.0f;
+ pos.z += (Rand()-0.5f)*20.0f;
+ pos.y += 8.0f;
+ speed.x = (Rand()-0.5f)*40.0f;
+ speed.z = (Rand()-0.5f)*40.0f;
+ speed.y = Rand()*40.0f;
+ dim.x = Rand()*8.0f+8.0f*m_force;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLOODM, 2.0f, 50.0f, 0.0f);
+ }
+ }
+
+ if ( m_type == PT_SHOTW &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ if ( m_crashSphereUsed > 0 )
+ {
+ i = rand()%m_crashSphereUsed;
+ pos = m_crashSpherePos[i];
+ pos.x += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f;
+ pos.z += (Rand()-0.5f)*m_crashSphereRadius[i]*2.0f;
+ speed.x = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f;
+ speed.z = (Rand()-0.5f)*m_crashSphereRadius[i]*0.5f;
+ speed.y = Rand()*m_crashSphereRadius[i]*1.0f;
+ dim.x = 1.0f*m_force;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
+ }
+ else
+ {
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*m_size*0.3f;
+ pos.z += (Rand()-0.5f)*m_size*0.3f;
+ speed.x = (Rand()-0.5f)*m_size*0.1f;
+ speed.z = (Rand()-0.5f)*m_size*0.1f;
+ speed.y = Rand()*m_size*0.2f;
+ dim.x = 1.0f*m_force;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_type == PT_SHOTW &&
+ m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticuleSmoke = m_time;
+
+ pos = m_pos;
+ pos.y -= 2.0f;
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 10.0f+Rand()*10.0f;
+ dim.x = Rand()*2.5f+2.0f*m_force;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 4.0f);
+ }
+
+ if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) &&
+ m_progress < 0.05f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*m_size*1.0f;
+ speed.z = (Rand()-0.5f)*m_size*1.0f;
+ speed.y = Rand()*m_size*0.50f;
+ dim.x = Rand()*m_size/5.0f+m_size/5.0f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIEXPLOT);
+ }
+
+ if ( (m_type == PT_FRAGT || m_type == PT_EXPLOT) &&
+ m_progress < 0.10f &&
+ m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticuleSmoke = m_time;
+
+ dim.x = Rand()*m_size/3.0f+m_size/3.0f;
+ dim.y = dim.x;
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*m_size*0.5f;
+ pos.z += (Rand()-0.5f)*m_size*0.5f;
+ m_terrain->MoveOnFloor(pos);
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = -dim.x/2.0f/4.0f;
+ pos.y += dim.x/2.0f;
+
+ r = rand()%2;
+ if ( r == 0 ) type = PARTISMOKE1;
+ if ( r == 1 ) type = PARTISMOKE2;
+ m_particule->CreateParticule(pos, speed, dim, type, 6.0f);
+ }
+
+ if ( (m_type == PT_FRAGO || m_type == PT_EXPLOO) &&
+ m_progress < 0.03f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.1f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*m_size*2.0f;
+ speed.z = (Rand()-0.5f)*m_size*2.0f;
+ speed.y = Rand()*m_size*1.0f;
+ dim.x = Rand()*m_size/2.0f+m_size/2.0f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIEXPLOO);
+ }
+
+ if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) &&
+ m_progress < 0.05f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*m_size*1.0f;
+ speed.z = (Rand()-0.5f)*m_size*1.0f;
+ speed.y = Rand()*m_size*0.50f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 0.5f, 0.0f, 0.0f);
+ }
+
+ if ( (m_type == PT_FRAGW || m_type == PT_EXPLOW) &&
+ m_progress < 0.25f &&
+ m_lastParticuleSmoke+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticuleSmoke = m_time;
+
+ pos = m_pos;
+ pos.y -= 2.0f;
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 4.0f+Rand()*4.0f;
+ dim.x = Rand()*2.5f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 4.0f);
+ }
+
+ if ( m_type == PT_WPCHECK )
+ {
+ if ( m_progress < 0.25f )
+ {
+ factor = 0.0f;
+ }
+ else
+ {
+ factor = powf((m_progress-0.25f)/0.75f, 2.0f)*30.0f;
+ }
+
+ if ( m_progress < 0.85f &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ pos.y += factor;
+ pos.x += (Rand()-0.5f)*3.0f;
+ pos.z += (Rand()-0.5f)*3.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = Rand()*1.5f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f);
+//? m_particule->CreateParticule(pos, speed, dim, (ParticuleType)(PARTILENS1+rand()%4), 2.0f);
+ }
+
+ angle = m_object->RetAngle(0);
+ angle.y = m_progress*20.0f;
+ angle.x = sinf(m_progress*49.0f)*0.3f;
+ angle.z = sinf(m_progress*47.0f)*0.2f;
+ m_object->SetAngle(0, angle);
+
+ pos = m_pos;
+ pos.y += factor;
+ m_object->SetPosition(0, pos);
+
+ if ( m_progress > 0.85f )
+ {
+ m_object->SetZoom(0, 1.0f-(m_progress-0.85f)/0.15f);
+ }
+ }
+
+ if ( m_type == PT_FLCREATE )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ m_terrain->MoveOnFloor(pos);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 2.0f+Rand()*2.0f;
+ dim.x = (Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.0f);
+ }
+
+ angle = m_object->RetAngle(0);
+//? angle.y = powf(m_progress, 0.2f)*20.0f;
+ angle.x = sinf(m_progress*49.0f)*0.3f*(1.0f-m_progress);
+ angle.z = sinf(m_progress*47.0f)*0.2f*(1.0f-m_progress);
+ m_object->SetAngle(0, angle);
+
+ m_object->SetZoom(0, m_progress);
+ }
+
+ if ( m_type == PT_FLDELETE )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ m_terrain->MoveOnFloor(pos);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 2.0f+Rand()*2.0f;
+ dim.x = (Rand()*1.0f+1.0f)*(0.2f+m_progress*0.8f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f);
+ }
+
+ angle = m_object->RetAngle(0);
+ angle.y = m_progress*20.0f;
+ angle.x = sinf(m_progress*49.0f)*0.3f;
+ angle.z = sinf(m_progress*47.0f)*0.2f;
+ m_object->SetAngle(0, angle);
+
+ m_object->SetZoom(0, 1.0f-m_progress);
+ }
+
+ if ( m_type == PT_RESET )
+ {
+#if 0
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*6.0f;
+ speed.z = (Rand()-0.5f)*6.0f;
+ speed.y = Rand()*12.0f;
+ dim.x = (Rand()*2.5f+2.5f)*(1.0f-m_progress*0.9f);
+ dim.y = dim.x;
+ pos.y += dim.y;
+ m_particule->CreateParticule(pos, speed, dim,
+ (ParticuleType)(PARTILENS1+rand()%4),
+ Rand()*2.5f+2.5f,
+ Rand()*5.0f+5.0f, 0.0f);
+ }
+#else
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_pos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+
+ pos = m_pos;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ speed *= 0.5f+m_progress*0.5f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*1.5f+1.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+#endif
+
+ angle = m_object->RetResetAngle();
+ m_object->SetAngleY(0, angle.y-powf((1.0f-m_progress)*5.0f, 2.0f));
+ m_object->SetZoom(0, m_progress);
+ }
+
+ if ( m_type == PT_FINDING )
+ {
+ if ( m_object != 0 &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ factor = m_size*0.3f;
+ if ( m_object->RetType() == OBJECT_SAFE ) factor *= 1.3f;
+ if ( factor > 40.0f ) factor = 40.0f;
+ pos = m_pos;
+ m_terrain->MoveOnFloor(pos);
+ pos.x += (Rand()-0.5f)*factor;
+ pos.z += (Rand()-0.5f)*factor;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 4.0f+Rand()*4.0f;
+ dim.x = (Rand()*3.0f+3.0f)*(1.0f-m_progress*0.9f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINT, 2.0f, 0.0f, 0.5f);
+ }
+ }
+
+ if ( (m_type == PT_BURNT || m_type == PT_BURNO) &&
+ m_object != 0 )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ factor = m_size/25.0f; // 1 = taille standard
+
+ pos = m_object->RetPosition(0);
+ pos.y -= m_object->RetCharacter()->height;
+ pos.x += (Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor;
+ pos.z += (Rand()-0.5f)*(4.0f+8.0f*m_progress)*factor;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 0.0f;
+ dim.x = (Rand()*2.5f+1.0f)*factor;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
+
+ pos = m_object->RetPosition(0);
+ pos.y -= m_object->RetCharacter()->height;
+ pos.x += (Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor;
+ pos.z += (Rand()-0.5f)*(2.0f+4.0f*m_progress)*factor;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = (Rand()*5.0f*m_progress+3.0f)*factor;
+ dim.x = (Rand()*2.0f+1.0f)*factor;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLAME, 2.0f, 0.0f, 0.2f);
+
+ pos = m_object->RetPosition(0);
+ pos.y -= 2.0f;
+ pos.x += (Rand()-0.5f)*5.0f*factor;
+ pos.z += (Rand()-0.5f)*5.0f*factor;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = (6.0f+Rand()*6.0f+m_progress*6.0f)*factor;
+ dim.x = (Rand()*1.5f+1.0f+m_progress*3.0f)*factor;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+
+ if ( m_type == PT_BURNT )
+ {
+ BurnProgress();
+ }
+ else
+ {
+ speed.y = 0.0f;
+ speed.x = (Rand()-0.5f)*m_progress*1.0f;
+ speed.z = (Rand()-0.5f)*m_progress*1.0f;
+ if ( m_progress > 0.8f )
+ {
+ prog = (m_progress-0.8f)/0.2f; // 0..1
+ speed.y = -prog*6.0f; // s'enfonce dans le sol
+ m_object->SetZoom(0, 1.0f-prog*0.5f);
+ }
+ m_object->SetLinVibration(speed);
+ }
+ }
+
+ if ( m_type == PT_WIN )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y += 1.5f;
+ speed.x = (Rand()-0.5f)*10.0f;
+ speed.z = (Rand()-0.5f)*10.0f;
+ speed.y = 8.0f+Rand()*8.0f;
+ dim.x = Rand()*0.2f+0.2f;
+ dim.y = dim.x;
+ m_particule->CreateTrack(pos, speed, dim,
+ (ParticuleType)(PARTITRACK7+rand()%4),
+ 3.0f, 20.0f, 1.0f, 0.4f);
+ }
+ }
+
+ if ( m_type == PT_LOST )
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.10f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_object->RetPosition(0);
+ pos.y -= 2.0f;
+ pos.x += (Rand()-0.5f)*10.0f;
+ pos.z += (Rand()-0.5f)*10.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 1.0f+Rand()*1.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 8.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_type == PT_FALL )
+ {
+ FallProgress(event.rTime);
+ }
+
+ if ( m_lightRank != -1 )
+ {
+ LightOperFrame(event.rTime);
+ }
+
+ return TRUE;
+}
+
+// Indique que l'objet lié à l'effet n'existe plus, sans le détruire.
+
+void CPyro::CutObjectLink(CObject* pObj)
+{
+ if ( m_object == pObj )
+ {
+ m_object = 0;
+ }
+}
+
+// Indique si l'effet pyrotechnique est terminé.
+
+Error CPyro::IsEnded()
+{
+ // Détruit l'objet qui explose. Il ne doit pas être détruit à la fin
+ // du Create, car c'est parfois l'objet lui-même qui fait le Create :
+ // pyro->Create(PT_FRAGT, this);
+ if ( m_type == PT_FRAGT ||
+ m_type == PT_FRAGO ||
+ m_type == PT_FRAGW ||
+ m_type == PT_SPIDER ||
+ m_type == PT_EGG )
+ {
+ DeleteObject(TRUE, TRUE);
+ }
+
+ if ( m_type == PT_FALL ) // fret qui tombe ?
+ {
+ return FallIsEnded();
+ }
+
+ if ( m_type == PT_WIN ||
+ m_type == PT_LOST )
+ {
+ return ERR_CONTINUE;
+ }
+
+ // Fin de l'effet pyrotechnique ?
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ if ( m_type == PT_EXPLOT ||
+ m_type == PT_EXPLOO ||
+ m_type == PT_EXPLOW ) // explosion ?
+ {
+ ExploTerminate();
+ }
+
+ if ( m_type == PT_BURNT ||
+ m_type == PT_BURNO ) // brûle ?
+ {
+ BurnTerminate();
+ }
+
+ if ( m_type == PT_WPCHECK ||
+ m_type == PT_FLDELETE )
+ {
+ DeleteObject(TRUE, TRUE);
+ }
+
+ if ( m_type == PT_FLCREATE )
+ {
+ m_object->SetAngleX(0, 0.0f);
+ m_object->SetAngleZ(0, 0.0f);
+ m_object->SetZoom(0, 1.0f);
+ }
+
+ if ( m_type == PT_RESET )
+ {
+ m_object->SetPosition(0, m_object->RetResetPosition());
+ m_object->SetAngle(0, m_object->RetResetAngle());
+ m_object->SetZoom(0, 1.0f);
+ }
+
+ if ( m_lightRank != -1 )
+ {
+ m_light->DeleteLight(m_lightRank);
+ m_lightRank = -1;
+ }
+
+ return ERR_STOP;
+}
+
+// Supprime l'objet lié à l'effet pyrotechnique.
+
+void CPyro::DeleteObject(BOOL bPrimary, BOOL bSecondary)
+{
+ CObject *sub, *truck;
+ D3DVECTOR pos;
+ ObjectType type;
+
+ if ( m_object == 0 ) return;
+
+ if ( m_object->RetResetCap() == RESET_MOVE ) // objet resetable ?
+ {
+ m_object->SetEnable(FALSE); // objet caché et inactif
+ pos = m_object->RetPosition(0);
+ pos.y = -100.0f;
+ m_object->SetPosition(0, pos);
+ return;
+ }
+
+ type = m_object->RetType();
+ if ( bSecondary &&
+ type != OBJECT_FACTORY &&
+ type != OBJECT_NUCLEAR &&
+ type != OBJECT_ENERGY )
+ {
+ sub = m_object->RetPower();
+ if ( sub != 0 )
+ {
+ sub->DeleteObject(); // supprime la pile
+ delete sub;
+ m_object->SetPower(0);
+ }
+
+ sub = m_object->RetFret();
+ if ( sub != 0 )
+ {
+ sub->DeleteObject(); // supprime l'objet transporté
+ delete sub;
+ m_object->SetFret(0);
+ }
+ }
+
+ if ( bPrimary )
+ {
+ truck = m_object->RetTruck();
+ if ( truck != 0 ) // objet porté ?
+ {
+ if ( truck->RetPower() == m_object )
+ {
+ truck->SetPower(0);
+ }
+ if ( truck->RetFret() == m_object )
+ {
+ truck->SetFret(0);
+ }
+ }
+
+ sub = m_object;
+ sub->DeleteObject(); // supprime l'objet (*)
+ delete sub;
+ m_object = 0;
+ }
+}
+
+// (*) CObject::DeleteObject peut remettre à zéro m_object
+// par le biais de CPyro::CutObjectLink !
+
+
+// Vide la table des opérations d'animation de la lumière.
+
+void CPyro::LightOperFlush()
+{
+ m_lightOperTotal = 0;
+}
+
+// Ajoute une opération d'animation de la lumière.
+
+void CPyro::LightOperAdd(float progress, float intensity,
+ float r, float g, float b)
+{
+ int i;
+
+ i = m_lightOperTotal;
+
+ m_lightOper[i].progress = progress;
+ m_lightOper[i].intensity = intensity;
+ m_lightOper[i].color.r = r;
+ m_lightOper[i].color.g = g;
+ m_lightOper[i].color.b = b;
+
+ m_lightOperTotal ++;
+}
+
+// Fait évoluer la lumière associée.
+
+void CPyro::LightOperFrame(float rTime)
+{
+ D3DCOLORVALUE color;
+ float progress, intensity;
+ int i;
+
+ for ( i=0 ; i<m_lightOperTotal ; i++ )
+ {
+ if ( m_progress < m_lightOper[i].progress )
+ {
+ progress = (m_progress-m_lightOper[i-1].progress) / (m_lightOper[i].progress-m_lightOper[i-1].progress);
+
+ intensity = m_lightOper[i-1].intensity + (m_lightOper[i].intensity-m_lightOper[i-1].intensity)*progress;
+ color.r = m_lightOper[i-1].color.r + (m_lightOper[i].color.r-m_lightOper[i-1].color.r)*progress;
+ color.g = m_lightOper[i-1].color.g + (m_lightOper[i].color.g-m_lightOper[i-1].color.g)*progress;
+ color.b = m_lightOper[i-1].color.b + (m_lightOper[i].color.b-m_lightOper[i-1].color.b)*progress;
+
+ m_light->SetLightIntensity(m_lightRank, intensity);
+ m_light->SetLightColor(m_lightRank, color);
+ break;
+ }
+ }
+}
+
+
+// Crée la lumière pour accompagner un effet pyrotechnique.
+
+BOOL CPyro::CreateLight(D3DVECTOR pos, float height)
+{
+ D3DLIGHT7 light;
+
+ if ( !m_engine->RetLightMode() ) return TRUE;
+
+ m_lightHeight = height;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dvPosition.x = pos.x;
+ light.dvPosition.y = pos.y+height;
+ light.dvPosition.z = pos.z;
+ light.dvDirection.x = 0.0f;
+ light.dvDirection.y = -1.0f; // contre en bas
+ light.dvDirection.z = 0.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+
+ m_lightRank = m_light->CreateLight();
+ if ( m_lightRank == -1 ) return FALSE;
+
+ m_light->SetLight(m_lightRank, light);
+ m_light->SetLightIntensity(m_lightRank, 0.0f);
+
+ // N'éclaire que les objets du terrain.
+ m_light->SetLightIncluType(m_lightRank, TYPETERRAIN);
+
+ return TRUE;
+}
+
+
+// Démarre l'explosion d'un véhicule.
+
+void CPyro::ExploStart()
+{
+ D3DVECTOR pos, angle, speed, min, max;
+ float weight;
+ int i, objRank, channel;
+
+ m_burnType = m_object->RetType();
+
+ pos = m_object->RetPosition(0);
+ m_burnFall = m_terrain->RetFloorHeight(pos, TRUE);
+
+ m_object->Simplify();
+ m_object->SetLock(TRUE); // ruine pas encore utilisable
+ m_object->SetExplo(TRUE); // en cours de destruction
+ m_object->FlatParent();
+
+ if ( m_object->RetSelect() )
+ {
+ m_object->SetSelect(FALSE); // désélectionne l'objet
+ m_camera->SetType(CAMERA_EXPLO);
+ m_main->DeselectAll();
+ }
+ m_object->DeleteDeselList(m_object);
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ objRank = m_object->RetObjectRank(i);
+ if ( objRank == -1 ) continue;
+ m_engine->ChangeSecondTexture(objRank, "dirty04.tga");
+
+ pos = m_object->RetPosition(i);
+
+ if ( i == 0 ) // partie principale ?
+ {
+ weight = 0.0f;
+
+ speed.y = -1.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ }
+ else
+ {
+ m_engine->GetBBox(objRank, min, max);
+ weight = Length(min, max); // poids selon dimensions !
+
+ speed.y = 10.0f+Rand()*20.0f;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ }
+
+ channel = m_particule->CreatePart(pos, speed, PARTIPART, 10.0f, 20.0f, weight, 0.5f);
+ if ( channel != -1 )
+ {
+ m_object->SetMasterParticule(i, channel);
+ }
+ }
+ m_engine->LoadTexture("dirty04.tga", 1);
+
+ DeleteObject(FALSE, TRUE); // détruit l'objet transporté + la pile
+}
+
+// Termine l'explosion d'un véhicule.
+
+void CPyro::ExploTerminate()
+{
+ DeleteObject(TRUE, FALSE); // supprime l'objet principal
+}
+
+
+// Démarre le feu d'un véhicule.
+
+void CPyro::BurnStart()
+{
+ D3DVECTOR pos, angle;
+ int i, objRank;
+
+ m_burnType = m_object->RetType();
+
+ pos = m_object->RetPosition(0);
+ m_burnFall = m_terrain->RetFloorHeight(pos, TRUE);
+
+ m_object->Simplify();
+ m_object->SetLock(TRUE); // ruine pas encore utilisable
+
+ if ( m_object->RetSelect() )
+ {
+ m_object->SetSelect(FALSE); // désélectionne l'objet
+ m_camera->SetType(CAMERA_EXPLO);
+ m_main->DeselectAll();
+ }
+ m_object->DeleteDeselList(m_object);
+
+ for ( i=0 ; i<OBJECTMAXPART ; i++ )
+ {
+ objRank = m_object->RetObjectRank(i);
+ if ( objRank == -1 ) continue;
+ m_engine->ChangeSecondTexture(objRank, "dirty04.tga");
+ }
+ m_engine->LoadTexture("dirty04.tga", 1);
+
+ m_burnPartTotal = 0;
+
+ if ( m_burnType == OBJECT_DERRICK ||
+ m_burnType == OBJECT_FACTORY ||
+ m_burnType == OBJECT_REPAIR ||
+ m_burnType == OBJECT_DESTROYER||
+ m_burnType == OBJECT_CONVERT ||
+ m_burnType == OBJECT_TOWER ||
+ m_burnType == OBJECT_RESEARCH ||
+ m_burnType == OBJECT_ENERGY ||
+ m_burnType == OBJECT_LABO )
+ {
+ pos.x = 0.0f;
+ pos.y = -(4.0f+Rand()*4.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.4f;
+ }
+ else if ( m_burnType == OBJECT_STATION ||
+ m_burnType == OBJECT_RADAR ||
+ m_burnType == OBJECT_INFO )
+ {
+ pos.x = 0.0f;
+ pos.y = -(1.0f+Rand()*1.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.2f;
+ }
+ else if ( m_burnType == OBJECT_NUCLEAR )
+ {
+ pos.x = 0.0f;
+ pos.y = -(10.0f+Rand()*10.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.4f;
+ }
+ else if ( m_burnType == OBJECT_PARA )
+ {
+ pos.x = 0.0f;
+ pos.y = -(10.0f+Rand()*10.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.4f;
+ }
+ else if ( m_burnType == OBJECT_SAFE )
+ {
+ pos.x = 0.0f;
+ pos.y = -(10.0f+Rand()*10.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.4f;
+ }
+ else if ( m_burnType == OBJECT_HUSTON )
+ {
+ pos.x = 0.0f;
+ pos.y = -(10.0f+Rand()*10.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.4f;
+ }
+ else if ( m_burnType == OBJECT_MOBILEwa ||
+ m_burnType == OBJECT_MOBILEwc ||
+ m_burnType == OBJECT_MOBILEwi ||
+ m_burnType == OBJECT_MOBILEws ||
+ m_burnType == OBJECT_MOBILEwt )
+ {
+ pos.x = 0.0f;
+ pos.y = -(0.5f+Rand()*1.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.8f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.4f;
+ }
+ else if ( m_burnType == OBJECT_TEEN31 ) // basket ?
+ {
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.8f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.2f;
+ }
+ else
+ {
+ pos.x = 0.0f;
+ pos.y = -(2.0f+Rand()*2.0f);
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.8f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*0.8f;
+ }
+ BurnAddPart(0, pos, angle); // mouvement de la partie principale
+
+ m_burnKeepPart[0] = -1; // rien à garder
+
+ if ( m_burnType == OBJECT_DERRICK )
+ {
+ pos.x = 0.0f;
+ pos.y = -40.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le foret
+ }
+
+ if ( m_burnType == OBJECT_REPAIR )
+ {
+ pos.x = 0.0f;
+ pos.y = -12.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = -90.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le capteur
+ }
+
+ if ( m_burnType == OBJECT_DESTROYER )
+ {
+ pos.x = 0.0f;
+ pos.y = -12.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = -90.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le capteur
+ }
+
+ if ( m_burnType == OBJECT_CONVERT )
+ {
+ pos.x = 0.0f;
+ pos.y = -200.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.5f;
+ angle.y = (Rand()-0.5f)*0.5f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le couvercle
+ BurnAddPart(2, pos, angle);
+ BurnAddPart(3, pos, angle);
+ }
+
+ if ( m_burnType == OBJECT_TOWER )
+ {
+ pos.x = 0.0f;
+ pos.y = -7.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = (Rand()-0.5f)*0.4f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le canon
+ }
+
+ if ( m_burnType == OBJECT_RESEARCH )
+ {
+ pos.x = 0.0f;
+ pos.y = -7.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend l'anémomètre
+ }
+
+ if ( m_burnType == OBJECT_RADAR )
+ {
+ pos.x = 0.0f;
+ pos.y = -14.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = (Rand()-0.5f)*0.4f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le radar
+ BurnAddPart(2, pos, angle);
+ }
+
+ if ( m_burnType == OBJECT_INFO )
+ {
+ pos.x = 0.0f;
+ pos.y = -14.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.4f;
+ angle.y = (Rand()-0.5f)*0.4f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend la borne d'information
+ BurnAddPart(2, pos, angle);
+ }
+
+ if ( m_burnType == OBJECT_LABO )
+ {
+ pos.x = 0.0f;
+ pos.y = -12.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le bras
+ }
+
+ if ( m_burnType == OBJECT_NUCLEAR )
+ {
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = -135.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le couvercle
+ }
+
+ if ( m_burnType == OBJECT_MOBILEfa ||
+ m_burnType == OBJECT_MOBILEta ||
+ m_burnType == OBJECT_MOBILEwa ||
+ m_burnType == OBJECT_MOBILEia )
+ {
+ pos.x = 2.0f;
+ pos.y = -5.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = 40.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le bras
+ }
+
+ if ( m_burnType == OBJECT_MOBILEfs ||
+ m_burnType == OBJECT_MOBILEts ||
+ m_burnType == OBJECT_MOBILEws ||
+ m_burnType == OBJECT_MOBILEis )
+ {
+ pos.x = 0.0f;
+ pos.y = -7.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = 50.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le capteur
+ }
+
+ if ( m_burnType == OBJECT_MOBILEfc ||
+ m_burnType == OBJECT_MOBILEtc ||
+ m_burnType == OBJECT_MOBILEwc ||
+ m_burnType == OBJECT_MOBILEic )
+ {
+ pos.x = -1.5f;
+ pos.y = -5.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = -25.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le canon
+ }
+
+ if ( m_burnType == OBJECT_MOBILEfi ||
+ m_burnType == OBJECT_MOBILEti ||
+ m_burnType == OBJECT_MOBILEwi ||
+ m_burnType == OBJECT_MOBILEii )
+ {
+ pos.x = -1.5f;
+ pos.y = -5.0f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*0.2f;
+ angle.y = (Rand()-0.5f)*0.2f;
+ angle.z = -25.0f*PI/180.0f;
+ BurnAddPart(1, pos, angle); // descend le canon-insecte
+ }
+
+ if ( m_burnType == OBJECT_MOBILErt ||
+ m_burnType == OBJECT_MOBILErc )
+ {
+ pos.x = 0.0f;
+ pos.y = -10.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le support
+
+ pos.x = 0.0f;
+ pos.y = -10.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(2, pos, angle); // descend le pilon/canon
+ }
+
+ if ( m_burnType == OBJECT_MOBILErr )
+ {
+ pos.x = 0.0f;
+ pos.y = -10.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le support
+
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = -PI/2.0f;
+ BurnAddPart(4, pos, angle);
+
+ pos.x = 0.0f;
+ pos.y = 0.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = PI/2.5f;
+ BurnAddPart(2, pos, angle);
+ }
+
+ if ( m_burnType == OBJECT_MOBILErs )
+ {
+ pos.x = 0.0f;
+ pos.y = -10.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le support
+
+ pos.x = 0.0f;
+ pos.y = -5.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(2, pos, angle);
+
+ pos.x = 0.0f;
+ pos.y = -5.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(3, pos, angle);
+ }
+
+ if ( m_burnType == OBJECT_MOBILEsa )
+ {
+ pos.x = 0.0f;
+ pos.y = -10.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = 0.0f;
+ BurnAddPart(1, pos, angle); // descend le support
+ }
+
+ if ( m_burnType == OBJECT_MOBILEwa ||
+ m_burnType == OBJECT_MOBILEwc ||
+ m_burnType == OBJECT_MOBILEwi ||
+ m_burnType == OBJECT_MOBILEws ||
+ m_burnType == OBJECT_MOBILEwt ) // roues ?
+ {
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos.x = 0.0f;
+ pos.y = Rand()*0.5f;
+ pos.z = 0.0f;
+ angle.x = (Rand()-0.5f)*PI/2.0f;
+ angle.y = (Rand()-0.5f)*PI/2.0f;
+ angle.z = 0.0f;
+ BurnAddPart(6+i, pos, angle); // roue
+
+ m_burnKeepPart[i] = 6+i; // on garde les roues
+ }
+ m_burnKeepPart[i] = -1;
+ }
+
+ if ( m_burnType == OBJECT_MOBILEta ||
+ m_burnType == OBJECT_MOBILEtc ||
+ m_burnType == OBJECT_MOBILEti ||
+ m_burnType == OBJECT_MOBILEts ||
+ m_burnType == OBJECT_MOBILErt ||
+ m_burnType == OBJECT_MOBILErc ||
+ m_burnType == OBJECT_MOBILErr ||
+ m_burnType == OBJECT_MOBILErs ||
+ m_burnType == OBJECT_MOBILEsa ||
+ m_burnType == OBJECT_MOBILEdr ) // chenilles ?
+ {
+ pos.x = 0.0f;
+ pos.y = -4.0f;
+ pos.z = 2.0f;
+ angle.x = (Rand()-0.5f)*20.0f*PI/180.0f;
+ angle.y = (Rand()-0.5f)*10.0f*PI/180.0f;
+ angle.z = (Rand()-0.5f)*30.0f*PI/180.0f;
+ BurnAddPart(6, pos, angle); // descend la chenille droite
+
+ pos.x = 0.0f;
+ pos.y = -4.0f;
+ pos.z = -2.0f;
+ angle.x = (Rand()-0.5f)*20.0f*PI/180.0f;
+ angle.y = (Rand()-0.5f)*10.0f*PI/180.0f;
+ angle.z = (Rand()-0.5f)*30.0f*PI/180.0f;
+ BurnAddPart(7, pos, angle); // descend la chenille gauche
+ }
+
+ if ( m_burnType == OBJECT_MOBILEfa ||
+ m_burnType == OBJECT_MOBILEfc ||
+ m_burnType == OBJECT_MOBILEfi ||
+ m_burnType == OBJECT_MOBILEfs ||
+ m_burnType == OBJECT_MOBILEft ) // volant ?
+ {
+ for ( i=0 ; i<3 ; i++ )
+ {
+ pos.x = 0.0f;
+ pos.y = -3.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*PI/2.0f;
+ BurnAddPart(6+i, pos, angle); // pied
+ }
+ m_burnKeepPart[i] = -1;
+ }
+
+ if ( m_burnType == OBJECT_MOBILEia ||
+ m_burnType == OBJECT_MOBILEic ||
+ m_burnType == OBJECT_MOBILEii ||
+ m_burnType == OBJECT_MOBILEis ) // pattes ?
+ {
+ for ( i=0 ; i<6; i++ )
+ {
+ pos.x = 0.0f;
+ pos.y = -3.0f;
+ pos.z = 0.0f;
+ angle.x = 0.0f;
+ angle.y = (Rand()-0.5f)*PI/4.0f;
+ angle.z = (Rand()-0.5f)*PI/4.0f;
+ BurnAddPart(6+i, pos, angle); // patte
+ }
+ }
+}
+
+// Ajoute une partie à bouger.
+
+void CPyro::BurnAddPart(int part, D3DVECTOR pos, D3DVECTOR angle)
+{
+ int i;
+
+ i = m_burnPartTotal;
+ m_burnPart[i].part = part;
+ m_burnPart[i].initialPos = m_object->RetPosition(part);
+ m_burnPart[i].finalPos = m_burnPart[i].initialPos+pos;
+ m_burnPart[i].initialAngle = m_object->RetAngle(part);
+ m_burnPart[i].finalAngle = m_burnPart[i].initialAngle+angle;
+
+ m_burnPartTotal ++;
+}
+
+// Fait progresser le feu d'un véhicule.
+
+void CPyro::BurnProgress()
+{
+ CObject* sub;
+ D3DVECTOR pos;
+ float h;
+ int i;
+
+ if ( m_burnType == OBJECT_TEEN31 ) // basket ?
+ {
+ m_object->SetZoomY(0, 1.0f-m_progress*0.5f); // léger applatissement
+ }
+
+ for ( i=0 ; i<m_burnPartTotal ; i++ )
+ {
+ pos = m_burnPart[i].initialPos + m_progress*(m_burnPart[i].finalPos-m_burnPart[i].initialPos);
+ if ( i == 0 && m_burnFall > 0.0f )
+ {
+ h = powf(m_progress, 2.0f)*1000.0f;
+ if ( h > m_burnFall ) h = m_burnFall;
+ pos.y -= h;
+ }
+ m_object->SetPosition(m_burnPart[i].part, pos);
+
+ pos = m_burnPart[i].initialAngle + m_progress*(m_burnPart[i].finalAngle-m_burnPart[i].initialAngle);
+ m_object->SetAngle(m_burnPart[i].part, pos);
+ }
+
+ sub = m_object->RetPower();
+ if ( sub != 0 ) // y a-t-il une pile ?
+ {
+ sub->SetZoomY(0, 1.0f-m_progress); // aplatissement complet
+ }
+}
+
+// Indique si une partie doit être conservée.
+
+BOOL CPyro::BurnIsKeepPart(int part)
+{
+ int i;
+
+ i = 0;
+ while ( m_burnKeepPart[i] != -1 )
+ {
+ if ( part == m_burnKeepPart[i++] ) return TRUE; // faut garder
+ }
+ return FALSE; // faut détruire
+}
+
+// Termine le feu d'un insecte ou d'un véhicule.
+
+void CPyro::BurnTerminate()
+{
+ int i, objRank;
+
+ if ( m_type == PT_BURNO ) // brûle objet organique ?
+ {
+ DeleteObject(TRUE, TRUE); // supprime l'insecte
+ return;
+ }
+
+ for ( i=1 ; i<OBJECTMAXPART ; i++ )
+ {
+ objRank = m_object->RetObjectRank(i);
+ if ( objRank == -1 ) continue;
+ if ( BurnIsKeepPart(i) ) continue;
+
+ m_object->DeletePart(i);
+ }
+
+ DeleteObject(FALSE, TRUE); // détruit l'objet transporté + la pile
+
+ if ( m_burnType == OBJECT_DERRICK ||
+ m_burnType == OBJECT_STATION ||
+ m_burnType == OBJECT_FACTORY ||
+ m_burnType == OBJECT_REPAIR ||
+ m_burnType == OBJECT_DESTROYER||
+ m_burnType == OBJECT_CONVERT ||
+ m_burnType == OBJECT_TOWER ||
+ m_burnType == OBJECT_RESEARCH ||
+ m_burnType == OBJECT_RADAR ||
+ m_burnType == OBJECT_INFO ||
+ m_burnType == OBJECT_ENERGY ||
+ m_burnType == OBJECT_LABO ||
+ m_burnType == OBJECT_NUCLEAR ||
+ m_burnType == OBJECT_PARA ||
+ m_burnType == OBJECT_SAFE ||
+ m_burnType == OBJECT_HUSTON ||
+ m_burnType == OBJECT_START ||
+ m_burnType == OBJECT_END )
+ {
+ m_object->SetType(OBJECT_RUINfactory); // ça devient une ruine
+ m_object->SetLock(FALSE);
+ }
+ else
+ {
+ m_object->SetType(OBJECT_RUINmobilew1); // ça devient une ruine
+ m_object->SetLock(FALSE);
+ }
+
+ m_object->SetBurn(FALSE); // ruine utilisable (c-à-d. récupérable)
+}
+
+
+// Début d'un objet fret qui tombe.
+
+void CPyro::FallStart()
+{
+ D3DVECTOR pos;
+
+ m_object->SetBurn(TRUE); // plus utilisable
+
+ pos = m_object->RetPosition(0);
+ m_fallFloor = m_terrain->RetFloorLevel(pos);
+ m_fallSpeed = 0.0f;
+ m_fallBulletTime = 0.0f;
+ m_bFallEnding = FALSE;
+}
+
+// Cherche un objet à exploser par le boulet de l'abeille qui tombe.
+
+CObject* CPyro::FallSearchBeeExplo()
+{
+ CObject* pObj;
+ D3DVECTOR iPos, oPos;
+ ObjectType oType;
+ float iRadius, oRadius, distance, shieldRadius;
+ int i, j;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( oType != OBJECT_HUMAN &&
+ oType != OBJECT_MOBILEfa &&
+ oType != OBJECT_MOBILEta &&
+ oType != OBJECT_MOBILEwa &&
+ oType != OBJECT_MOBILEia &&
+ oType != OBJECT_MOBILEfc &&
+ oType != OBJECT_MOBILEtc &&
+ oType != OBJECT_MOBILEwc &&
+ oType != OBJECT_MOBILEic &&
+ oType != OBJECT_MOBILEfi &&
+ oType != OBJECT_MOBILEti &&
+ oType != OBJECT_MOBILEwi &&
+ oType != OBJECT_MOBILEii &&
+ oType != OBJECT_MOBILEfs &&
+ oType != OBJECT_MOBILEts &&
+ oType != OBJECT_MOBILEws &&
+ oType != OBJECT_MOBILEis &&
+ oType != OBJECT_MOBILErt &&
+ oType != OBJECT_MOBILErc &&
+ oType != OBJECT_MOBILErr &&
+ oType != OBJECT_MOBILErs &&
+ oType != OBJECT_MOBILEsa &&
+ oType != OBJECT_MOBILEtg &&
+ oType != OBJECT_MOBILEft &&
+ oType != OBJECT_MOBILEtt &&
+ oType != OBJECT_MOBILEwt &&
+ oType != OBJECT_MOBILEit &&
+ oType != OBJECT_MOBILEdr &&
+ oType != OBJECT_BASE &&
+ oType != OBJECT_DERRICK &&
+ oType != OBJECT_STATION &&
+ oType != OBJECT_FACTORY &&
+ oType != OBJECT_REPAIR &&
+ oType != OBJECT_DESTROYER&&
+ oType != OBJECT_CONVERT &&
+ oType != OBJECT_TOWER &&
+ oType != OBJECT_RESEARCH &&
+ oType != OBJECT_RADAR &&
+ oType != OBJECT_INFO &&
+ oType != OBJECT_ENERGY &&
+ oType != OBJECT_LABO &&
+ oType != OBJECT_NUCLEAR &&
+ oType != OBJECT_PARA &&
+ oType != OBJECT_SAFE &&
+ oType != OBJECT_HUSTON &&
+ oType != OBJECT_METAL &&
+ oType != OBJECT_POWER &&
+ oType != OBJECT_ATOMIC ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+
+ oPos = pObj->RetPosition(0);
+
+ shieldRadius = pObj->RetShieldRadius();
+ if ( shieldRadius > 0.0f )
+ {
+ distance = Length(oPos, iPos);
+ if ( distance <= shieldRadius ) return pObj;
+ }
+
+ if ( oType == OBJECT_BASE )
+ {
+ distance = Length(oPos, iPos);
+ if ( distance < 25.0f ) return pObj;
+ }
+
+ // Test au centre de l'objet, ce qui est nécessaire pour
+ // les objets qui n'ont pas de sphère au centre (station).
+ distance = Length(oPos, iPos)-4.0f;
+ if ( distance < 5.0f ) return pObj;
+
+ // Test avec toutes les sphères de l'objet.
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ distance = Length(oPos, iPos);
+ if ( distance <= iRadius+oRadius )
+ {
+ return pObj;
+ }
+ }
+ }
+ return 0;
+}
+
+// Chute d'un objet fret.
+
+void CPyro::FallProgress(float rTime)
+{
+ CObject* pObj;
+ D3DVECTOR pos;
+ BOOL bFloor = FALSE;
+
+ if ( m_object == 0 ) return;
+
+ m_fallSpeed += rTime*50.0f; // v2 = v1 + a*dt
+ pos = m_object->RetPosition(0);
+ pos.y -= m_fallSpeed*rTime; // dd -= v2*dt
+
+ if ( pos.y <= m_fallFloor ) // sous le niveau du sol ?
+ {
+ pos.y = m_fallFloor;
+ bFloor = TRUE;
+ }
+ m_object->SetPosition(0, pos);
+
+ if ( m_object->RetType() == OBJECT_BULLET )
+ {
+ m_fallBulletTime += rTime;
+
+ if ( m_fallBulletTime > 0.2f || bFloor )
+ {
+ m_fallBulletTime = 0.0f;
+
+ pObj = FallSearchBeeExplo();
+ if ( pObj == 0 )
+ {
+ if ( bFloor ) // arrivé au niveau du sol ?
+ {
+ m_object->ExploObject(EXPLO_BOUM, 0.0f); // démarre explosion
+ }
+ }
+ else
+ {
+ if ( pObj->RetShieldRadius() > 0.0f ) // protégé par bouclier ?
+ {
+ m_particule->CreateParticule(pos, D3DVECTOR(0.0f, 0.0f, 0.0f), FPOINT(6.0f, 6.0f), PARTIGUNDEL, 2.0f, 0.0f, 0.0f);
+ m_sound->Play(SOUND_GUNDEL);
+
+ DeleteObject(TRUE, TRUE); // supprime le boulet
+ }
+ else
+ {
+ if ( pObj->ExploObject(EXPLO_BOUM, 1.0f) ) // démarre explosion
+ {
+ DeleteObject(TRUE, TRUE); // supprime le boulet
+ }
+ else
+ {
+ m_object->ExploObject(EXPLO_BOUM, 0.0f); // démarre explosion
+ }
+ }
+ }
+
+ if ( bFloor || pObj != 0 )
+ {
+ m_bFallEnding = TRUE;
+ }
+ }
+ }
+}
+
+// Indique si la chute est terminée.
+
+Error CPyro::FallIsEnded()
+{
+ D3DVECTOR pos;
+
+ if ( m_bFallEnding || m_object == 0 ) return ERR_STOP;
+
+ pos = m_object->RetPosition(0);
+ if ( pos.y > m_fallFloor ) return ERR_CONTINUE;
+
+ m_sound->Play(SOUND_BOUM, pos);
+ m_object->SetBurn(FALSE); // de nouveau utilisable
+
+ return ERR_STOP;
+}
+
diff --git a/src/pyro.h b/src/pyro.h
new file mode 100644
index 0000000..cfab33a
--- /dev/null
+++ b/src/pyro.h
@@ -0,0 +1,158 @@
+// pyro.h
+
+#ifndef _PYRO_H_
+#define _PYRO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CTerrain;
+class CCamera;
+class CParticule;
+class CLight;
+class CObject;
+class CDisplayText;
+class CRobotMain;
+class CSound;
+
+
+
+enum PyroType
+{
+ PT_NULL = 0,
+ PT_FRAGT = 1, // fragmentation objet technique
+ PT_FRAGO = 2, // fragmentation objet organique
+ PT_FRAGW = 4, // fragmentation objet sous l'eau
+ PT_EXPLOT = 5, // explosion objet technique
+ PT_EXPLOO = 6, // explosion objet organique
+ PT_EXPLOW = 8, // explosion objet sous l'eau
+ PT_SHOTT = 9, // coup objet technique
+ PT_SHOTH = 10, // coup homme
+ PT_SHOTM = 11, // coup pondeuse
+ PT_SHOTW = 12, // coup sous l'eau
+ PT_EGG = 13, // casse l'oeuf
+ PT_BURNT = 14, // brûle objet technique
+ PT_BURNO = 15, // brûle objet organique
+ PT_SPIDER = 16, // explosion araignée
+ PT_FALL = 17, // fret qui tombe
+ PT_WPCHECK = 18, // indicateur atteint
+ PT_FLCREATE = 19, // drapeau créé
+ PT_FLDELETE = 20, // drapeau détruit
+ PT_RESET = 21, // reset position de l'objet
+ PT_WIN = 22, // feu d'artifice
+ PT_LOST = 23, // fumée noire
+ PT_DEADG = 24, // mort par balle
+ PT_DEADW = 25, // mort noyé
+ PT_FINDING = 26, // objet découvert
+};
+
+
+enum ObjectType;
+enum Error;
+
+
+typedef struct
+{
+ int part;
+ D3DVECTOR initialPos;
+ D3DVECTOR finalPos;
+ D3DVECTOR initialAngle;
+ D3DVECTOR finalAngle;
+}
+PyroBurnPart;
+
+typedef struct
+{
+ float progress;
+ float intensity;
+ D3DCOLORVALUE color;
+}
+PyroLightOper;
+
+
+
+class CPyro
+{
+public:
+ CPyro(CInstanceManager* iMan);
+ ~CPyro();
+
+ void DeleteObject(BOOL bAll=FALSE);
+ BOOL Create(PyroType type, CObject* pObj, float force=1.0f);
+ BOOL EventProcess(const Event &event);
+ Error IsEnded();
+ void CutObjectLink(CObject* pObj);
+
+protected:
+ void DisplayError(PyroType type, CObject* pObj);
+ BOOL CreateLight(D3DVECTOR pos, float height);
+ void DeleteObject(BOOL bPrimary, BOOL bSecondary);
+
+ void CreateTriangle(CObject* pObj, ObjectType oType, int part);
+
+ void ExploStart();
+ void ExploTerminate();
+
+ void BurnStart();
+ void BurnAddPart(int part, D3DVECTOR pos, D3DVECTOR angle);
+ void BurnProgress();
+ BOOL BurnIsKeepPart(int part);
+ void BurnTerminate();
+
+ void FallStart();
+ CObject* FallSearchBeeExplo();
+ void FallProgress(float rTime);
+ Error FallIsEnded();
+
+ void LightOperFlush();
+ void LightOperAdd(float progress, float intensity, float r, float g, float b);
+ void LightOperFrame(float rTime);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CTerrain* m_terrain;
+ CCamera* m_camera;
+ CParticule* m_particule;
+ CLight* m_light;
+ CObject* m_object;
+ CDisplayText* m_displayText;
+ CRobotMain* m_main;
+ CSound* m_sound;
+
+ D3DVECTOR m_pos; // centre de l'effet
+ D3DVECTOR m_posPower; // centre de la pile
+ BOOL m_bPower; // pile existe ?
+ PyroType m_type;
+ float m_force;
+ float m_size;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_lastParticule;
+ float m_lastParticuleSmoke;
+ int m_soundChannel;
+
+ int m_lightRank;
+ int m_lightOperTotal;
+ PyroLightOper m_lightOper[10];
+ float m_lightHeight;
+
+ ObjectType m_burnType;
+ int m_burnPartTotal;
+ PyroBurnPart m_burnPart[10];
+ int m_burnKeepPart[10];
+ float m_burnFall;
+
+ float m_fallFloor;
+ float m_fallSpeed;
+ float m_fallBulletTime;
+ BOOL m_bFallEnding;
+
+ int m_crashSphereUsed; // nb de sphères utilisées
+ D3DVECTOR m_crashSpherePos[50];
+ float m_crashSphereRadius[50];
+};
+
+
+#endif //_PYRO_H_
diff --git a/src/readme.txt b/src/readme.txt
new file mode 100644
index 0000000..55bdeeb
--- /dev/null
+++ b/src/readme.txt
@@ -0,0 +1,872 @@
+COLOBOT version 1.4 /f
+----------------------
+
+COLOBOT est un mélange d'un jeu de stratégie en temps réel et
+d'une initiation à la programmation. Le scénario vous place à
+la tête d'une expédition spatiale, composée d'un seul humain
+(vous) et de quelques robots. Vous devrez explorer et coloniser
+différentes planètes, tout en cherchant des matières premières
+nécessaires à votre survie.
+
+Petit à petit, vous pourrez construire et programmer de nouveaux
+robots, qui vous aideront dans vos tâches. Certaines planètes
+sont habitées par des créatures primitives et hostiles qu'il
+vous faudra combattre.
+
+
+Configuration minimale
+----------------------
+
+Processeur 300 MHz
+64 Mb RAM
+Carte graphique 3D avec 16 Mb RAM
+100 Mb d'espace libre sur le disque dur
+
+Si ce n'est pas déjà fait, DirectX 8a est installé.
+La présence du CD est nécessaire pour jouer.
+
+
+Missions
+--------
+
+Les missions contiennent la partie "aventure" de COLOBOT. Elles
+sont au nombre de 36, réparties sur 9 planètes différentes.
+Elles doivent être faites dans l'ordre imposé.
+
+Jeu libre
+---------
+
+Le mode "jeu libre" vous permet d'agir librement sur une
+planète, sans but déterminé. Seuls les planètes déjà visitées et
+les recherches effectuées sont disponibles.
+
+Programmation
+-------------
+
+Cette partie de COLOBOT permet d'apprendre à programmer, même si
+vous n'avez aucune notion dans ce domaine. Différents chapitres
+présentent des sujets de plus en plus compliqués. Vous pouvez
+effectuer n'importe quel exercice, bien qu'il soit conseillé de
+commencer par les plus simples.
+
+Défis
+-----
+
+Les défis vous demandent une bonne connaissance de la
+programmation. Ils permettent de vérifier si les notions
+apprises sous "programmation" sont effectivement comprises.
+
+
+Autre joueur
+------------
+
+Après avoir installé COLOBOT sur un ordinateur, plusieurs
+personnes peuvent y jouer. Pour chaque joueur, COLOBOT
+enregistre automatiquement la progression dans les missions,
+les programmes écrits, etc.
+
+
+Options
+-------
+
+Réglages du jeu, répartis dans 5 pages.
+
+
+Options - Affichage
+-------------------
+
+- Pilotes
+Il faut choisir un pilote qui porte la mention HAL (Hardware
+Abstraction Layer). Evitez les pilotes ayant la mention
+"Emulation" ou "T&L". Il arrive fréquemment que des pilotes
+avec des noms différents aient des comportements identiques.
+
+- Résolutions
+Les premier et deuxième chiffres indiquent le nombre de pixels
+en largeur et en hauteur dans l'écran. Le troisième chiffre
+indique le nombre de couleurs affichables (16 pour 65'000
+couleurs et 32 pour 4 millions de couleurs).
+Plus la résolution est grande et plus le jeu est beau.
+Mais il risque de devenir lent. Commencez par mettre
+640 x 480 x 16. La plupart des cartes graphiques modernes
+supportent 1024 x 768 x 16. A vous d'essayer le meilleur
+compromis.
+
+- Plein écran
+Normalement, COLOBOT occupe tout l'écran, quelle que soit la
+résolution. Si vous enlevez la coche, COLOBOT tournera dans
+une fenêtre fixe ayant approximativement 640 x 480 pixels.
+
+- Appliquer les changements
+Il faut cliquer ce bouton pour que les changements effectués
+dans cette page prennent effet.
+
+
+Options - Graphique
+-------------------
+
+- Ombres
+Normalement, tous les objets (robots, bâtiments, titanium,
+etc.) projettent une ombre sur le sol. Avec certaines cartes
+graphiques anciennes, un carré gris peut apparaître, en plus
+de l'ombre. Si cela vous semble inesthétique, supprimez cette
+option.
+
+- Marques sur le sol
+Les marques accentuent les berges. Elles donnent aussi des
+teintes différentes à certains endroits du terrain. Si cette
+option est déclenchée, il n'est pas possible de montrer les
+zones plates avec le cosmonaute.
+
+- Salissures
+Les salissures donnent un effet vieux et sale aux robots et aux
+bâtiments.
+
+- Ciel
+Avec cette option, le ciel de certaines planètes contient des
+nuages poussés par le vent. Sans cela, le ciel est généralement
+rempli par un simple dégradé de couleurs.
+
+- Rayons du soleil
+Lorsque vous vous tournez en direction du soleil, un reflet
+apparaît.
+
+- Planètes et étoiles
+Sur certaines planètes, vous voyez dans le ciel des planètes
+proches qui bougent lentement.
+
+- Brouillard
+Cette option correspond aux nappes de brouillard horizontales
+qui sont généralement très proches du sol.
+
+- Lumières dynamiques
+Les lumières dynamiques apparaissent lors d'explosions, ou
+lorsqu'un robot refait le plein d'énergie.
+
+- Quantité de particules (0% à 200%)
+Les particules servent à simuler la poussière, la fumée, les
+éclats, les bulles sous l'eau, etc.
+
+- Profondeur de champ (50% à 200%)
+La profondeur de champ détermine jusqu'où porte votre regard.
+Cette profondeur est de toute façon très différente selon
+l'atmosphère de la planète. Une grande valeur (par exemple
+200%) permet de voir loin, mais nécessite une bonne carte
+graphique 3D.
+
+- Détails des objets (0% à 200%)
+Lorsqu'un objet est au loin, il est représenté avec moins de
+détails. Une grande valeur éloigne la distance à laquelle le
+changement est effectué.
+
+- Nombre d'objets décoratifs (0% à 100%)
+Ce nombre détermine la quantité d'objets décoratifs présents,
+tels que les plantes, les arbres, les cristaux, etc.
+
+
+Options - Jeu
+-------------
+
+- Séquences cinématiques
+Certaines missions commencent ou finissent par un petit film
+montrant l'atterrissage ou le décollage du vaisseau. La touche
+Esc permet toujours de stopper ces séquences. Si cette option
+est supprimée, ces films sont complètement sautés.
+
+- Défilement dans les bords
+Lorsque la caméra est derrière le cosmonaute ou derrière un
+robot, une rotation est effectuée si la souris s'approche du
+bord de l'écran.
+
+- Inversion souris X
+Inverse le sens de la rotation lorsque la souris touche le bord
+gauche ou le bord droite de l'écran.
+
+- Inversion souris Y
+Inverse le sens du mouvement lorsque la souris touche le bord
+supérieur ou le bord inférieur de l'écran, dans l'éditeur de
+programmes.
+
+- Secousses lors d'explosions
+Lors d'une explosion, ou lorsque vous effectuez un atterrissage
+brusque, la caméra subit un choc qui se manifeste par une
+secousse plus on moins prononcée. Supprimez cette option pour
+que la caméra soit toujours parfaitement stable.
+
+- Retour animé
+Indique comment la situation est réinitialisée dans les exercices
+de programmation et dans les défis.
+
+- Bulles d'aide
+Les bulles d'aide vous donnent un petit texte explicatif lorsque
+la souris s'arrête sur un bouton ou un objet.
+
+- Reflets sur les boutons
+Les reflets sont visibles lorsque la souris survole un bouton.
+
+- Particules dans l'interface
+Pluie de particules lorsque la souris bouge dans les écrans
+d'interface.
+
+- Souris ombrée
+La souris ombrée est gérée par COLOBOT. La souris normale est
+dessinée par Windows. Lorsque COLOBOT ne fonctionne pas en mode
+"plein écran", la souris est forcément normale.
+
+- Indentation automatique
+L'indentation déplace automatiquement le curseur vers la droite
+lors de l'édition d'un programme, en fonction des accolades
+{ et }.
+
+- Grande indentation
+Une grande indentation décale vers la droite d'une distance
+égale à 4 espaces. Sinon, le décalage est de 2 espaces.
+
+
+Options - Commandes
+-------------------
+
+- Flèches gauche, droite, haut et bas
+Pour faire tourner, avancer ou reculer le cosmonaute ou un
+robot. Dans les exercices de programmation, notez que les robots
+ne peuvent pas être déplacés ainsi.
+
+- Shirt et Ctrl
+Pour faire monter ou descendre le cosmonaute ou un robot volant.
+Sur certaines planètes, le vol est impossible.
+
+- Entrée
+Cette touche effectue l'action principale du robot sélectionné,
+qui correspond au bouton avec un cadre rouge.
+
+- Espace
+Change le point de vue de la caméra. Pour la plupart des robots,
+la caméra passe alternativement d'une vue arrière à une vue
+intérieure.
+
+- . (pavé numérique)
+Met le jeu en pause et montre l'endroit correspondant au dernier
+message affiché en haut de l'écran. Si plusieurs messages sont
+affichés, une nouvelle pression montre le message précédent,
+chronologiquement parlant. Esc enlève la pause et le jeu reprend
+son cours.
+
+- Tab
+Sélectionne l'objet suivant, selon l'ordre des petites icônes
+tout en haut de l'écran.
+
+- Home
+Sélectionne toujours rapidement le cosmonaute.
+
+- 0 (pavé numérique)
+Sélectionne le robot ou le bâtiment qui était sélectionné
+précédemment.
+
+- + et - (pavé numérique)
+Approche ou éloigne la caméra de l'objet sélectionné.
+
+- F1
+Affiche les instructions sur la mission ou l'exercice à l'aide
+du SatCom.
+
+- F2
+Affiche le glossaire sur la programmation à l'aide du SatCom.
+
+- F3
+Pendant l'édition d'un programme, cette touche affiche des
+informations complémentaires sur l'instruction en cours de
+frappe.
+
+- F4, F5 et F6
+Choix de la vitesse du jeu. Le mode normal x1 correspond à la
+touche F4. Les modes rapides x1.5 et x2 doivent être utilisés
+avec prudence, car les ennemis vont également plus vite !
+
+- Esc
+Quitte la mission en cours.
+
+
+Options - Son
+-------------
+
+- Bruitages
+Les bruitages sont générés par l'action en cours. Il s'agit de
+bruits de moteur, de pas, d'explosions, etc.
+
+- Fond sonore
+Le fond sonore dépend de la planète. Il donne une ambiance
+générale, indépendamment de l'action en cours. Chaque fond
+sonore correspond à une piste audio sur le CD. Dans les
+exercices, les défis ainsi que sur la lune, il n'y a pas de
+fond sonore.
+
+- Bruitages 3D
+Certaines cartes son permettent de localiser un son dans
+l'espace à l'aide de 4 haut-parleurs. Le réalisme est alors
+superbe. Si votre carte son ne le permet pas, le bouton est
+grisé.
+
+
+Créér des exercices
+-------------------
+
+Tous les exercices sont dans le sous-dossier \scene\ :
+
+ \scene\trainxyy.txt -> exercices
+ \scene\defixyy.txt -> défis
+ \scene\scenexyy.txt -> missions
+ \scene\freexyy.txt -> jeux libres
+
+Le numéro de 3 chiffres est composé de :
+
+ x -> numéro du chapitre (1..9)
+ yy -> rang dans le chapitre (01..99)
+
+Par exemple, train102.txt est le deuxième exercice du premier
+chapitre.
+Lorsque le rang dans le chapitre est 00, c'est qu'il s'agit de
+la description du chapitre.
+Les fichiers doivent avoir des numéros sucessifs. Supposons par
+exemple que les fichiers suivants existent :
+
+ train600.txt
+ train601.txt
+ train602.txt
+ train605.txt
+
+Le chapitre 6 ne contiendra dans ce cas que 2 exercices, les
+numéros 01 et 02. Le numéro 05 n'apparaît pas dans la liste,
+car il manque les numéros 03 et 04.
+
+Description
+-----------
+
+Un fichier de description d'exercice détermine le relief du
+terrain, les textures utilisées, la position initiale des
+différents robots, matières premières, plantes, etc.
+
+
+
+Couleur
+-------
+
+Les couleurs sont spécifiées à l'aide de 4 composantes
+rouge/vert/bleu/alpha. Les valeurs sont comprises entre
+0 (noir) et 255 (blanc). La composante alpha est généralement
+nulle. Par exemple :
+
+ color=175;209;215;0 // bleu-sable
+
+
+
+
+Title.E text="Power Cell 1"
+Nom court de l'exercice, tel qu'il apparaît dans la liste de
+gauche.
+
+Resume.E text="Instruct a bot to change the power cell of a nearby winged shooter."
+Résumé de l'exercice, tel qu'il apparaît en dessous des deux
+listes.
+
+ScriptName.E text="Spider2"
+Nom par défaut donné à un nouveau programme créé.
+
+Instructions name="tcell1.txt"
+Nom du fichier qui contient les instructions de l'exercice,
+qui seront affichées dans le SatCom.
+Le fichier ttit1.txt doit être placé dans le dossier help\.
+
+HelpFile name="cbot.txt"
+Non du fichier qui contient les instructions sur la program-
+mation, affichées lorsque l'on presse sur F2.
+Le fichier cbot.txt doit être placé dans le dossier help\.
+Normalement, tous les exercices font référence aux mêmes
+instructions générales contenues dans cbot.txt.
+
+EndingFile win=2 lost=0
+Scène à utiliser lorsque l'exercice est réussi ou raté.
+win=2 signifie qu'il faut utiliser scene\win002.txt.
+lost=0 signifie qu'il faut utiliser scene\lost000.txt.
+
+Audio track=0
+Numéro de la piste audio du CD à jouer pendant l'exercice.
+Normalement, les exercices restent silencieux, en donnant le
+numéro de piste 0. Si nécessaire, il est possible de donner
+les numéros suivants :
+ 2: Terre
+ 3: Tropica
+ 4: Crystalium
+ 5: Saari
+ 6: Volcano
+ 7: Centaury
+ 8: Orphéon
+ 9: Terranova
+
+AmbiantColor air=102;102;102;102 water=20;20;20;20
+Couleur ambiante utilisée lorsqu'on est à l'air libre ou
+sous l'eau.
+
+FogColor air=180;222;255;0 water=10;20;100;0
+Couleur que prennent les objets lorsqu'ils sont au loin.
+
+VehicleColor color=175;209;215;0
+Couleur des robots et des bâtiments.
+
+DeepView air=100.00 water=25.00
+Distance en mètres jusqu'où porte la vue. Au delà de cette
+distance, plus rien n'est affiché.
+
+FogStart air=0.1 water=0.1
+Plus on s'approche de la distance maximale de vue (DeepView)
+et plus la couleur des objets fusionne avec la couleur du
+brouillard (FogColor), ce qui simule du brouillard. Une valeur
+de 0.1 indique un brouillard qui commence proche du point de
+vue, donc un brouillard dense. Une valeur de 0.9 indique un
+brouillard très peu dense.
+
+Par exemple :
+ DeepView air=100.00
+ FogStart air=0.2
+
+Distances à partir de l'observateur :
+0 à 20 mètres -> affichage normal
+20 à 100 mètres -> affichage de plus en plus brouillardeux
+100 mètres et plus -> plus rien n'est affiché
+
+SecondTexture rank=3
+Texture utilisée pour salir les robots et les bâtiments. Vous
+pouvez utiliser une valeur comprise entre 1 et 8.
+
+Background up=76;105;226;0 down=192;250;255;0
+Couleurs du fond d'écran, si aucune texture n'est utilisée.
+Un dégradé de couleur passe de "up" tout en haut de l'écran
+progressivement jusqu'à "down" en milieu d'écran. La moitié
+inférieure de l'écran prend la couleur unie "down". Cette
+moitié inférieure n'est en principe jamais visible, puisqu'il
+y a toujours une partie de terrain qui la recouvre.
+
+FrontsizeName image="lens5.tga"
+Nom de la texture d'avant-plan, qui contient un effet de
+"lens flare", plus ou moins visible selon l'orientation.
+
+
+TerrainRelief image="textures\relief41.bmp" factor=1.0
+Le relief du terrain est décrit dans une image BMP à 256
+niveaux de gris mesurant exactement 161 x 161 pixels.
+La couleur blanche correspond à l'altitude la plus basse.
+La couleur noire correspond à l'altitude la plus haute.
+Normalement, on utilise "factor=1.0". Dans ce cas, les 256
+niveaux permettent de s'élever de 64 mètres. Une différence
+d'intensité de gris de 1 correspond donc à une différence
+d'altitude de 0.25 mètres.
+
+La coordonnée du pixel central 80;80 de l'image correspond
+à la coordonnée 0;0 dans CoLoBoT.
+La coordonnée 0;0 du pixel en haut à gauche dans l'image
+correspond au point à l'extrème nord-ouest -400;400 dans CoLoBoT.
+Un pixel dans l'image correspond à un carré au sol de 5x5
+mètres dans CoLoBoT.
+
+Vous pouvez dessiner de nouveaux reliefs avec un logiciel tel
+que PaintShop, ou réutiliser les nombreux fichiers reliefxx.bmp
+placés dans le dossier textures\.
+
+TerrainResource image="textures\res00.bmp"
+Cette image détermine la présence des ressources dans le
+sous-sol. Il s'agit d'une image BMP en 256 couleurs de
+161 x 161 pixels.
+
+Rouge = 255;0;0 (index=5) -> titanium
+Vert = 0;255;0 (index=30) -> énergie
+Jaune = 255;255;0 (index=35) -> uranium
+
+Toutes les autres couleurs ou niveaux de gris sont ignorés.
+
+Généralement, un bon truc pour placer les zones de couleur au
+bon endroit est de partir de l'image à niveaux de gris du
+relief et de la convertir en 256 couleurs.
+
+TerrainWater level=7.5 ...
+Cette commande contient plusieurs paramètres, dont seul "level"
+nous intéresse ici. "level" indique donc le niveau de l'eau ou
+de la lave, par-rapport au niveau zéro qui correspond à la
+couleur blanche dans l'image du relief (TerrainResource).
+L'altitude des robots est par la suite toujours calculée par-
+rapport au niveau de la mer (level). Une altitude négative
+indiquera donc que le robot est sous l'eau.
+
+BeginObject
+Cette commande doit précéder le premier CreateObject.
+
+CreateObject pos=7;-10 dir=1.5 type=Me
+Création d'un objet dans l'exercice. Il peut s'agir d'un robot,
+d'un bâtiment, d'une matière première, d'une plante, etc.
+
+Pour déterminer la position d'un objet, un bon moyen consiste
+à déplacer le cosmonaute à l'endroit souhaité, puis de taper
+les commandes :
+
+ Ctrl+Pause showstat Entrée
+ Ctrl+Pause showpos Entrée
+
+La partie inférieure de l'écran indique alors les coordonnées
+de l'objet sélectionné, qu'il n'y a plus qu'à reporter dans le
+fichier de description de l'exercice.
+
+La direction est un nombre compris entre 0 et 2.
+ 0.0 -> est
+ 0.5 -> sud
+ 1.0 -> ouest
+ 1.5 -> nord
+Le sens de rotation est donc horaire.
+
+Les différents types possibles pour les objets sont :
+
+Base :
+ type=Me // cosmonaute
+ type=SpaceShip
+
+Robots :
+ type=PracticeBot // robot d'entraînement
+ type=TargetBot // robot cible
+
+ type=WheeledGrabber
+ type=TrackedGrabber
+ type=WingedGrabber
+ type=LeggedGrabber
+
+ type=WheeledShooter
+ type=TrackedShooter
+ type=WingedShooter
+ type=LeggedShooter
+
+ type=WheeledOrgaShooter
+ type=TrackedOrgaShooter
+ type=WingedOrgaShooter
+ type=LeggedOrgaShooter
+
+ type=WheeledSniffer
+ type=TrackedSniffer
+ type=WingedSniffer
+ type=LeggedSniffer
+
+ type=Thumper
+ type=PhazerShooter
+ type=Recycler
+ type=Shielder
+ type=Subber
+
+Bâtiments :
+ type=Derrick
+ type=BotFactory
+ type=PowerStation
+ type=Converter
+ type=RepairCenter
+ type=DefenseTower
+ type=AlienNest
+ type=ResearchCenter
+ type=RadarStation
+ type=ExchangePost
+ type=PowerPlant
+ type=AutoLab
+ type=NuclearPlant
+ type=PowerCaptor
+ type=Vault
+ type=StartArea
+ type=GoalArea
+ type=Target1 // pour l'entraînement au vol
+ type=Target2
+ type=Houston // centre de contrôle
+
+Objets transportables :
+ type=TitaniumOre
+ type=UraniumOre
+ type=Titanium
+ type=PowerCell
+ type=NuclearCell
+ type=OrgaMatter
+ type=BlackBox // boîte noire
+ type=KeyA..D
+ type=TNT // caisse d'explosif
+
+Plantes et décors :
+ type=Greenery0..4 // plante standard basse
+ type=Greenery5..7 // petit trèfle bas
+ type=Greenery10..14 // plante grasse montante
+ type=Greenery15..19 // fougère
+ type=Tree0..3 // arbre haut
+ type=Mushroom1 // champignon inoffensif
+ type=Mushroom2 // champignon corrosif
+ type=MegaStalk0..5 // plante étrange
+
+ type=Quartz0..3 // quartz petit..grand
+ type=Barrier0 // barrière courte
+ type=Barrier1 // barrière longue
+ type=ApolloLEM // sur la lune uniquement :
+ type=ApolloJeep
+ type=ApolloFlag
+ type=ApolloModule
+ type=ApolloAntenna
+
+Epaves de robots recyclables :
+ type=WreckBotw1..2 // robot à roues
+ type=WreckBott1..2 // robot à petites chenilles
+ type=WreckBotr1..2 // robot à grosses chenilles
+
+Bâtiments en ruine :
+ type=RuinBotFactory
+ type=RuinDoor // porte de convertisseur
+ type=RuinSupport // support de radar
+ type=RuinRadar // socle de radar
+ type=RuinConvert
+ type=RuinBaseCamp // socle du vaisseau spatial
+ type=RuinHeadCamp // coiffe du vaisseau spatial
+
+Ennemis :
+ type=AlienQueen
+ type=AlienEgg
+ type=AlienAnt
+ type=AlienSpider
+ type=AlienWasp
+ type=AlienWorm
+
+Indicateurs :
+ type=PowerSpot // indique la présence d'énergie en sous-sol
+ type=TitaniumSpot // indique la présence de titanium en sous-sol
+ type=UraniumSpot // indique la présence d'uranium en sous-sol
+ type=KeyA..DSpot // indique la présence de clé en sous-sol
+ type=WayPoint // croix pour les exercices
+ type=BlueFlag
+ type=RedFlag
+ type=GreenFlag
+ type=YellowFlag
+ type=VioletFlag
+
+Divers :
+ type=Mine // bombe fixe à éviter
+ type=Portico // portique géant (sur la terre)
+ type=Bag // sac de survie
+ type=Home // petite maison sympa (sur terranova)
+ type=Tech // technicien de Houston
+ type=Firework // feu d'artifice
+
+La commande CreateObject peut contenir des paramètres
+supplémentaires :
+
+CreateObject ... script1="ttit1.txt"
+Nom du programme CBOT à charger à la position 1 dans le robot
+ou l'insecte. Il est possible de charger jusqu'à 10 programmes
+en utilisant les commandes script1 à script10.
+Les fichiers .txt des programmes doivent être placés dans le
+dossier script\.
+
+CreateObject ... run=1
+Numéro du programme à exécuter directement lorsque l'exercice
+démarre. Cela peut être utile, par exemple, pour un robot
+TargetBot que l'élève devra suivre.
+Si plusieurs programmes sont chargés (avec script1, script2,
+etc.), un seul pourra être exécuté, bien entendu.
+
+EnableResearch type=WINGER
+Liste des recherches déjà effectuées.
+
+DoneResearch type=WINGER
+Liste des recherches qu'il est autorisé de faire, en construisant
+un centre de recherche (ResearchCenter) ou un laboratoire (AutoLab).
+
+
+ TRACKER Robots Tracked*
+ WINGER Robots Winged*
+ THUMPER Robots Thumper
+ SHOOTER Robots *Shooter
+ TOWER Bâtiment DefenseTower
+ PHAZER Robots PhazerShooter
+ SHIELDER Robots Shielder
+ ATOMIC Bâtiment NuclearPlant
+
+ iPAW Robots Legged*
+ iGUN Robots *OrgaShooter
+
+ RECYCLER Robots recycleurs
+ SUBBER Robots Subber
+ SNIFFER Robots *Sniffer
+
+
+EndMissionTake pos=0.00;0.00 dist=25000.00 type=Me lost=0
+EndMissionTake pos=0.00;0.00 dist=25000.00 type=WheeledGrabber lost=0
+EndMissionTake pos=0.00;0.00 dist=1000.00 type=Titanium min=1 max=1
+Critères pour déterminer à quel moment l'exercice est terminé.
+
+
+
+
+Dossiers et réseau
+------------------
+
+Dans une utilisation en réseau, COLOBOT doit être installé
+sur chaque machine individuellement. Après cette opération,
+les exercices et les missions sont chargés localement,
+généralement dans le dossier :
+
+ C:\Program Files\Colobot\scene\
+
+Si vous avez créé des exercices spécifiques, il peut être
+utile de les charger à partir d'un dossier central commun à
+tous les ordinateurs. Pour cela, il faut modifier le fichier
+
+ C:\Program Files\Colobot\colobot.ini
+
+sur chaque machine. La section suivante permet de donner le
+chemin d'accès :
+
+ [Directory]
+ scene=scene
+
+Ici, il s'agit d'un chemin d'accès relatif. Vous pouvez par
+exemple le changer en un chemin absolu sur un serveur :
+
+ [Directory]
+ scene=\\Serveur\c\colobot\scene\
+
+De la même façon, vous pouvez changer le dossier dans lequel
+sont placés les programmes lorsque vous utilisez la commande
+ouvrir/enregistrer avec le mode "public", dans l'éditeur de
+programmes :
+
+ [Directory]
+ public=program
+
+En donnant un chemin d'accès commun à tous les ordinateurs, il
+sera possible d'échanger des programmes :
+
+ [Directory]
+ public=\\Serveur\c\colobot\program\
+
+
+
+Réglages
+--------
+
+Pour afficher le nombre d'images par seconde, il faut appuyer
+sur Ctrl+Pause puis taper la commande "showstat" et valider
+avec la touche Entrée :
+
+ Ctrl+Pause showstat Entrée
+
+La partie supérieure de l'écran affiche alors, par exemple :
+
+ 32.46 fps T=11558 (640x480x16)
+
+Le premier chiffre correspond au nombre d'images par seconde
+(fps = frame per second).
+Le deuxième chiffre indique le nombre de triangles affiché dans
+la scène.
+Les 3 derniers chiffres entre parenthèses sont la résolution
+(largeur x hauteur) et le nombre de bits pour les couleurs.
+
+Tous les réglages sont mémorisés dans le fichier colobot.ini,
+présent dans le dossier principal où COLOBOT a été installé.
+Ce fichier peut être modifié (avec prudence et après en avoir
+fait une copie) avec un éditeur de texte, comme par exemple le
+bloc-notes de Windows.
+
+
+Problèmes
+---------
+
+Pour résoudre certains problèmes, il est possible de modifier
+le fichier colobot.ini avec un éditeur de texte (par exemple
+avec le bloc-notes de Windows). N'ajoutez pas de nouvelles
+lignes, mais modifiez simplement les valeurs existantes.
+Attention à ne pas insérer d'espace. Il faut quitter COLOBOT
+avant de modifier le fichier.
+
+Si la végétation s'affiche mal, ou même pas du tout, vous
+avez peut-être mis à zéro le nombre d'objets décoratifs dans
+les options. Pour remettre 100% :
+ [Setup]
+ GadgetQuantity=1.00
+Si la végétation ne s'affiche toujours pas, essayez :
+ [Engine]
+ AlphaMode=0
+ou
+ [Engine]
+ AlphaMode=2
+
+Si un carré apparaît autour des ombres, essayez :
+ [Engine]
+ WhiteSrcBlend=9
+ WhiteDestBlend=6
+ou
+ [Engine]
+ WhiteSrcBlend=6
+ WhiteDestBlend=3
+Si cela ne fonctionne pas, il faut supprimer les ombres :
+ [Engine]
+ WhiteSrcBlend=0
+ WhiteDestBlend=0
+ [Setup]
+ GroundShadow=0
+
+Lorsque un objet s'interpose entre l'objet sélectionné et la
+caméra, il devient transparent. Si l'objet n'est pas assez
+transparent, essayez :
+ [Engine]
+ StateColor=0
+ou
+ [Engine]
+ StateColor=1
+
+
+Equipe de développement
+-----------------------
+
+- Daniel Roux
+- Denis Dumoulin
+- Otto Kölbl
+- Michael Walz
+- Didier Gertsch
+
+Beta testeurs
+-------------
+
+- Adrien Roux
+- Didier Raboud
+- Nicolas Beuchat
+- Joël Roux
+- Michael Jubin
+- Daniel Sauthier
+- Nicolas Stubi
+- Patrick Thévoz
+
+Copyright
+---------
+
+La photo de la nébuleuse NGC3603 servant de fond pour la planète
+Orphéon a été prise avec le télescope spatial Hubble. Elle est
+utilisée avec l'autorisation des auteurs Wolfgang Brandner
+(JPL/IPAC), Eva K. Grebel (Université de Washington), You-Hua Chu
+(Université d'Illinois Urbana-Champaign) et de la NASA.
+
+Le son de tonnerre de la planète Orphéon est utilisé avec
+l'autorisation limitée de CREATIVE moyennant la mention :
+Material from products are used by limited permission from CREATIVE.
+
+Développeur
+-----------
+
+EPSITEC SA
+Mouette 5
+CH-1092 Belmont
+
+colobot@epsitec.ch
+www.colobot.com
+
+Editeur de la version française
+-------------------------------
+
+ALSYD
+43, Ch. du vieux Chêne
+F-38240 Meylan
+
+www.alsyd.com
diff --git a/src/resource.h b/src/resource.h
new file mode 100644
index 0000000..0daaca6
--- /dev/null
+++ b/src/resource.h
@@ -0,0 +1,39 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by winmain.rc
+//
+#define IDI_MAIN_ICON 101
+#define IDR_MAIN_ACCEL 113
+#define IDR_MENU 141
+#define IDR_POPUP 142
+#define IDD_ABOUT 143
+#define IDD_CHANGEDEVICE 144
+#define IDC_CURSORHAND 149
+#define IDC_CURSORSCROLLL 150
+#define IDC_CURSORSCROLLR 151
+#define IDC_CURSORSCROLLU 152
+#define IDC_CURSORSCROLLD 153
+#define IDC_CURSORTARGET 154
+#define IDC_DEVICE_COMBO 1000
+#define IDC_MODE_COMBO 1001
+#define IDC_WINDOWED_CHECKBOX 1012
+#define IDC_STEREO_CHECKBOX 1013
+#define IDC_FULLSCREEN_TEXT 1014
+#define IDM_ABOUT 40001
+#define IDM_CHANGEDEVICE 40002
+#define IDM_TOGGLEFULLSCREEN 40003
+#define IDM_TOGGLESTART 40004
+#define IDM_SINGLESTEP 40005
+#define IDM_EXIT 40006
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_3D_CONTROLS 1
+#define _APS_NEXT_RESOURCE_VALUE 159
+#define _APS_NEXT_COMMAND_VALUE 40011
+#define _APS_NEXT_CONTROL_VALUE 1015
+#define _APS_NEXT_SYMED_VALUE 102
+#endif
+#endif
diff --git a/src/restext-old.cpp b/src/restext-old.cpp
new file mode 100644
index 0000000..073692d
--- /dev/null
+++ b/src/restext-old.cpp
@@ -0,0 +1,2527 @@
+// restext.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <stdio.h>
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "misc.h"
+#include "event.h"
+#include "object.h"
+#include "cbot\resource.h"
+#include "restext.h"
+
+
+
+
+// Donne le pointeur au moteur.
+
+void SetEngine(CD3DEngine *engine)
+{
+ g_engine = engine;
+}
+
+// Donne le nom du joueur.
+
+void SetGlobalGamerName(char *name)
+{
+ strcpy(g_gamerName, name);
+}
+
+
+
+typedef struct
+{
+ KeyRank key;
+ char name[20];
+}
+KeyDesc;
+
+static KeyDesc keyTable[22] =
+{
+ { KEYRANK_LEFT, "left;" },
+ { KEYRANK_RIGHT, "right;" },
+ { KEYRANK_UP, "up;" },
+ { KEYRANK_DOWN, "down;" },
+ { KEYRANK_GUP, "gup;" },
+ { KEYRANK_GDOWN, "gdown;" },
+ { KEYRANK_CAMERA, "camera;" },
+ { KEYRANK_DESEL, "desel;" },
+ { KEYRANK_ACTION, "action;" },
+ { KEYRANK_NEAR, "near;" },
+ { KEYRANK_AWAY, "away;" },
+ { KEYRANK_NEXT, "next;" },
+ { KEYRANK_HUMAN, "human;" },
+ { KEYRANK_QUIT, "quit;" },
+ { KEYRANK_HELP, "help;" },
+ { KEYRANK_PROG, "prog;" },
+ { KEYRANK_CBOT, "cbot;" },
+ { KEYRANK_VISIT, "visit;" },
+ { KEYRANK_SPEED10, "speed10;" },
+ { KEYRANK_SPEED15, "speed15;" },
+ { KEYRANK_SPEED20, "speed20;" },
+ { KEYRANK_SPEED30, "speed30;" },
+};
+
+// Cherche une touche.
+
+BOOL SearchKey(char *cmd, KeyRank &key)
+{
+ int i;
+
+ for ( i=0 ; i<22 ; i++ )
+ {
+ if ( strstr(cmd, keyTable[i].name) == cmd )
+ {
+ key = keyTable[i].key;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Remplace les commandes "\key name;" dans un texte.
+
+void PutKeyName(char* dst, char* src)
+{
+ KeyRank key;
+ char name[50];
+ int s, d, n, res;
+
+ s = d = 0;
+ while ( src[s] != 0 )
+ {
+ if ( src[s+0] == '\\' &&
+ src[s+1] == 'k' &&
+ src[s+2] == 'e' &&
+ src[s+3] == 'y' &&
+ src[s+4] == ' ' )
+ {
+ if ( SearchKey(src+s+5, key) )
+ {
+ res = g_engine->RetKey(key, 0);
+ if ( res != 0 )
+ {
+ if ( GetResource(RES_KEY, res, name) )
+ {
+ n = 0;
+ while ( name[n] != 0 )
+ {
+ dst[d++] = name[n++];
+ }
+ while ( src[s++] != ';' );
+ continue;
+ }
+ }
+ }
+ }
+
+ dst[d++] = src[s++];
+ }
+ dst[d++] = 0;
+}
+
+
+// Retourne le texte d'une ressource.
+
+BOOL GetResource(ResType type, int num, char* text)
+{
+ char buffer[100];
+
+ if ( !GetResourceBase(type, num, buffer) )
+ {
+ text[0] = 0;
+ return FALSE;
+ }
+
+ PutKeyName(text, buffer);
+ return TRUE;
+}
+
+
+// Retourne le texte d'une ressource.
+
+BOOL GetResourceBase(ResType type, int num, char* text)
+{
+ text[0] = 0;
+
+#if _ENGLISH
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "Version 1.8 /e");
+ #endif
+ #if _NET | _SCHOOL
+ if ( num == RT_VERSION_ID ) strcpy(text, "School 1.8 /e");
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.8 /e");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Maximize");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Minimize");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Normal size");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Close");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Program editor");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "New");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Player");
+ if ( num == RT_IO_NEW ) strcpy(text, "New ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " or ");
+
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Programming exercises");
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Challenges");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Missions");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Free game");
+ if ( num == RT_TITLE_USER ) strcpy(text, "User levels");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypes");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Options");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Player name");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Customize your appearance");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Save the current mission");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Load a saved mission");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Chapters:");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Chapters:");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Planets:");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Planets:");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " User levels:");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Planets:");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Exercises in the chapter:");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Challenges in the chapter:");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Missions on this planet:");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Free game on this planet:");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Missions on this level:");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Prototypes on this planet:");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Summary:");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Drivers:");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " Resolution:");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) First click on the key you want to redefine.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Then push the key you want to use instead.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Face type:");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Eyeglasses:");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Hair color:");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Suit color:");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Strip color:");
+
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Quit the mission?");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Do you want to quit COLOBOT ?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Abort\\Abort the current mission");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Continue\\Continue the current mission");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Quit\\Quit COLOBOT");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Continue\\Continue the game");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Do you really want to destroy the selected building?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Do you want to delete %s's saved games? ");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Delete");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Cancel");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "LOADING");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Keyword help(\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Compilation ok (0 errors)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Program finished");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;List of objects\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Robots\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Buildings\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Moveable objects\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Aliens\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (none)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;Error\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "The list is only available if a \\l;radar station\\u object\\radar; is working.\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Open");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Save");
+ if ( num == RT_IO_LIST ) strcpy(text, "Folder: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Name:");
+ if ( num == RT_IO_DIR ) strcpy(text, "Folder:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Private\\Private folder");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Public\\Common folder");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Developed by :");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+//? if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "English version published by:");
+//? if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.?.com");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "OK");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Cancel");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Next");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Previous");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menu (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "OK");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Cancel");
+
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Exercises\\Programming exercises");
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Challenges\\Programming challenges");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Missions\\Select mission");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Free game\\Free game without precise goal");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "User\\User levels");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Proto\\Prototypes under development");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "New player\\Choose player name");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Options\\Preferences");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Restart\\Restart the mission from the beginning");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Save\\Save the current mission ");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Load\\Load a saved mission");
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Return to COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Quit\\Quit COLOBOT");
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Back \\Back to the previous screen");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Play\\Start mission!");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Device\\Driver and resolution settings");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Graphics\\Graphics settings");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Game\\Game settings");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Controls\\Keyboard, joystick and mouse settings");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "Sound\\Music and game sound volume");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Unit");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "Resolution");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Full screen\\Full screen or window mode");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Apply changes\\Activates the changed settings");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robbie\\Your assistant");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Shadows\\Shadows on the ground");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Marks on the ground\\Marks on the ground");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Dust\\Dust and dirt on bots and buildings");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Fog\\Fog");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Sunbeams\\Sunbeams in the sky");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Sky\\Clouds and nebulae");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planets and stars\\Astronomical objects in the sky");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Dynamic lighting\\Mobile light sources");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Number of particles\\Explosions, dust, reflections, etc.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "Depth of field\\Maximum visibility");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Details\\Visual quality of 3D objects");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Textures\\Quality of textures ");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Number of decorative objects \\Number of purely ornamental objects");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Particles in the interface\\Steam clouds and sparks in the interface");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Reflections on the buttons \\Shiny buttons");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Help balloons\\Explain the function of the buttons");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Film sequences\\Films before and after the missions");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Exit film\\Film at the exit of exercises");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Friendly fire\\Your shooting can damage your own objects ");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Scrolling\\Scrolling when the mouse touches right or left border");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Mouse inversion X\\Inversion of the scrolling direction on the X axis");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Quake at explosions\\The screen shakes at explosions");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Mouse shadow\\Gives the mouse a shadow");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Automatic indent\\When program editing");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Big indent\\Indent 2 or 4 spaces per level defined by braces");
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Standard controls\\Standard key functions");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Turn left\\turns the bot to the left");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Turn right\\turns the bot to the right");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Forward\\Moves forward");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Backward\\Moves backward");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "Climb\\Increases the power of the jet");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "Descend\\Reduces the power of the jet");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Change camera\\Switches between onboard camera and following camera");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Previous object\\Selects the previous object");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Camera closer\\Moves the camera forward");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Camera back\\Moves the camera backward");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Next object\\Selects the next object");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Select the astronaut\\Selects the astronaut");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Quit\\Quit the current mission or exercise");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Instructions\\Shows the instructions for the current mission");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Programming help\\Gives more detailed help with programming");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Key word help\\More detailed help about key words");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Origin of last message\\Shows where the last message was sent from");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Speed 1.0x\\Normal speed");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Speed 1.5x\\1.5 times faster");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Speed 2.0x\\Double speed");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Speed 3.0x\\Three times faster");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Sound effects:\\Volume of engines, voice, shooting, etc.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Background sound :\\Volume of audio tracks on the CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "3D sound\\3D positioning of the sound");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Lowest\\Minimum graphic quality (highest frame rate)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normal\\Normal graphic quality");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Highest\\Highest graphic quality (lowest frame rate)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Silent\\No sound");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normal\\Normal sound volume");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "Use a joystick\\Joystick or keyboard");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Access to solution\\Shows the solution (detailed instructions for missions)");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\New player name");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "OK\\Choose the selected player");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Cancel\\Keep current player name");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Delete player\\Deletes the player from the list");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Player name");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Save\\Saves the current mission");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Load\\Loads the selected mission");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "List of saved missions");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Filename:");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Mission name");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Photography");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Delete\\Deletes the selected file");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Appearance\\Choose your appearance");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "OK");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Cancel");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standard\\Standard appearance settings");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "Head\\Face and hair");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Suit\\Astronaut suit");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Turn left");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Turn right");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Red");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Green");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Blue");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Red");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Green");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Blue");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Face 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Face 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Face 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Face 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\No eyeglasses");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Eyeglasses 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Eyeglasses 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Eyeglasses 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Eyeglasses 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Eyeglasses 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Previous selection (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Turn left (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Turn right (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Forward (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Backward (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Up (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Down (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Grab or drop (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Grab or drop (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..in front");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..behind");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..power cell");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Instructions for the mission (\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Take off to finish the mission");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Build a derrick");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Build a power station");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Build a bot factory");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Build a repair center");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Build a converter");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Build a defense tower");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Build a research center");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Build a radar station");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Build a power cell factory");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Build an autolab");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Build a nuclear power plant");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Build a lightning conductor");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Build a exchange post");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Show if the ground is flat");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Plant a flag");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Remove a flag");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Blue flags");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Red flags");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Green flags");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\Yellow flags");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Violet flags");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Build a winged grabber");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Build a tracked grabber");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Build a wheeled grabber");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Build a legged grabber");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Build a winged shooter");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Build a tracked shooter");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Build a wheeled shooter");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Build a legged shooter");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Build a winged orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Build a tracked orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Build a wheeled orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Build a legged orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Build a winged sniffer");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Build a tracked sniffer");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Build a wheeled sniffer");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Build a legged sniffer");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Build a thumper");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Build a phazer shooter");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Build a recycler");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Build a shielder");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Build a subber");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Run research program for tracked bots");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Run research program for winged bots");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Run research program for thumper");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Run research program for shooter");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Run research program for defense tower");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Run research program for phazer shooter");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Run research program for shielder");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Run research program for nuclear power");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Run research program for legged bots");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Run research program for orga shooter");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Return to start");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Sniff (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Thump (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Shoot (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Recycle (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Extend shield (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Withdraw shield (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Shield radius");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Execute the selected program");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Edit the selected program");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\SatCom on standby");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Destroy the building");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Energy level");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Shield level");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Jet temperature");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Still working ...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Number of insects detected");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Transmitted information");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Compass");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Mini-map");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Zoom mini-map");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Camera (\\key camera;)");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Help about selected object");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Show the solution");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Switch bots <-> buildings");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Show the range");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Show the place");
+ if ( num == EVENT_DT_END ) strcpy(text, "Continue");
+ if ( num == EVENT_CMD ) strcpy(text, "Command line");
+ if ( num == EVENT_SPEED ) strcpy(text, "Game speed");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Back");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Forward");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Home");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Copy");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "Size 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "Size 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "Size 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "Size 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "Size 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Instructions from Houston");
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Satellite report");
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Programs dispatched by Houston");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "List of objects");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Programming help");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Solution");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "OK\\Close program editor and return to game");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Cancel\\Cancel all changes");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "New");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Open (Ctrl+o)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Save (Ctrl+s)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Undo (Ctrl+z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Cut (Ctrl+x)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Copy (Ctrl+c)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Paste (Ctrl+v)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "Font size");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Instructions (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Programming help (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Compile");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Execute/stop");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pause/continue");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "One step");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "Gantry crane");
+ if ( num == OBJECT_BASE ) strcpy(text, "Spaceship");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Derrick");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Bot factory");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Repair center");
+ if ( num == OBJECT_STATION ) strcpy(text, "Power station");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Converts ore to titanium");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Defense tower");
+ if ( num == OBJECT_NEST ) strcpy(text, "Nest");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Research center");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Radar station");
+ if ( num == OBJECT_INFO ) strcpy(text, "Information exchange post");
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Power cell factory");
+ if ( num == OBJECT_LABO ) strcpy(text, "Autolab");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Nuclear power station");
+ if ( num == OBJECT_PARA ) strcpy(text, "Lightning conductor");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Vault");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Houston Mission Control");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Target");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Target");
+ if ( num == OBJECT_START ) strcpy(text, "Start");
+ if ( num == OBJECT_END ) strcpy(text, "Finish");
+ if ( num == OBJECT_STONE ) strcpy(text, "Titanium ore");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Uranium ore");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Organic matter");
+ if ( num == OBJECT_METAL ) strcpy(text, "Titanium");
+ if ( num == OBJECT_POWER ) strcpy(text, "Power cell");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Nuclear power cell");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Black box");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Key A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Key B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Key C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Key D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Explosive");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Fixed mine");
+ if ( num == OBJECT_BAG ) strcpy(text, "Survival kit");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Checkpoint");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Blue flag");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Red flag");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Green flag");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "Yellow flag");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Violet flag");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "Energy deposit (site for power station)");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Uranium deposit (site for derrick)");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Found key A (site for derrick)");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Found key B (site for derrick)");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Found key C (site for derrick)");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Found key D (site for derrick)");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Titanium deposit (site for derrick)");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Winged grabber");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Tracked grabber");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Wheeled grabber");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Legged grabber");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Winged shooter");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Tracked shooter");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Wheeled shooter");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Legged shooter");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "Winged orga shooter");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "Tracked orga shooter");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "Wheeled orga shooter");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "Legged orga shooter");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Winged sniffer");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Tracked sniffer");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Wheeled sniffer");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Legged sniffer");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Thumper");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Phazer shooter");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Recycler");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Shielder");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Subber");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Target bot");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "Engineer");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robbie");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Alien Queen");
+ if ( num == OBJECT_ANT ) strcpy(text, "Ant");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Spider");
+ if ( num == OBJECT_BEE ) strcpy(text, "Wasp");
+ if ( num == OBJECT_WORM ) strcpy(text, "Worm");
+ if ( num == OBJECT_EGG ) strcpy(text, "Egg");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Waste");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Spaceship ruin");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Spaceship ruin");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Derelict of Apollo mission");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Lunar Roving Vehicle");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "Error");
+ if ( num == ERR_CMD ) strcpy(text, "Unknown command");
+ if ( num == ERR_INSTALL ) strcpy(text, "COLOBOT not installed.");
+ if ( num == ERR_NOCD ) strcpy(text, "Please insert the COLOBOT CD\nand re-run the game.");
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Already carrying something");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Nothing to grab");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Place occupied");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "No other robot");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "You can not carry a radioactive object");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "You can not carry an object under water");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Nothing to drop");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Impossible under water");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Titanium too far away");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Titanium too close");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "No titanium around");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Ground not flat enough");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Flat ground not large enough");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Place occupied");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Too close to space ship");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Too close to a building");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Bot inappropriate");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Bot inappropriate");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Ground inappropriate");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Building too close");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Object too close");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Bot inappropriate");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Nothing to recycle");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Bot inappropriate");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "No more energy");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "Error in instruction move");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Goto: destination inaccessible");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Goto: destination inaccessible");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Goto: destination occupied");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Bot inappropriate");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "No titanium ore to convert");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "No ore in the subsoil");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "No energy in the subsoil");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "No power cell");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "No more energy");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "No power cell");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Cell type inappropriate");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Research program already performed");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "No energy in the subsoil");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Not yet enough energy");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "No titanium to transform");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Transforms only titanium");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Doors blocked by a robot or another object ");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "You must get on the spaceship to take off ");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Nothing to analyze");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "Analyzes only organic matter");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analysis already performed");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "No energy in the subsoil");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Not yet enough energy");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "No uranium to transform");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Transforms only uranium");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "No titanium");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Object too close");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Place occupied");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "No information exchange post within range");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Program infected by a virus");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Infected by a virus, temporarily out of order");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "No power cell");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "No more energy");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Impossible when swimming");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Impossible when carrying an object");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Too many flags of this color (maximum 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Too close to an existing flag");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "No flag nearby");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "The mission is not accomplished yet (push \\key help; for more details)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Bot destroyed");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Building destroyed");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Can not create this, there are too many objects");
+
+ if ( num == INFO_BUILD ) strcpy(text, "Building completed");
+ if ( num == INFO_CONVERT ) strcpy(text, "Titanium available");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Research program completed");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Plans for tracked robots available ");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "You can fly with the keys (\\key gup;) and (\\key gdown;)");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Plans for thumper available");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Plans for shooter available");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Plans for defense tower available");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Plans for phazer shooter available");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Plans for shielder available");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Plans for nuclear power plant available");
+ if ( num == INFO_FACTORY ) strcpy(text, "New bot available");
+ if ( num == INFO_LABO ) strcpy(text, "Analysis performed");
+ if ( num == INFO_ENERGY ) strcpy(text, "Power cell available");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Nuclear power cell available");
+ if ( num == INFO_FINDING ) strcpy(text, "You found a usable object");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Found a site for power station");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Well done, mission accomplished >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Sorry, mission failed >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Sorry, mission failed >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Current mission saved");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Checkpoint crossed");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Alien Queen killed");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Ant fatally wounded");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Wasp fatally wounded");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Worm fatally wounded");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Spider fatally wounded");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Push \\key help; to get instructions on your SatCom");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "Error");
+ if ( num == TX_OPENPAR ) strcpy(text, "Opening bracket missing");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Closing bracket missing ");
+ if ( num == TX_NOTBOOL ) strcpy(text, "The expression must return a boolean value");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Variable not declared");
+ if ( num == TX_BADLEFT ) strcpy(text, "Assignment impossible");
+ if ( num == TX_ENDOF ) strcpy(text, "Semicolon terminator missing");
+ if ( num == TX_OUTCASE ) strcpy(text, "Instruction ""case"" outside a block ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Instructions after the final closing brace");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "End of block missing");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Instruction ""else"" without corresponding ""if"" ");
+ if ( num == TX_OPENBLK ) strcpy(text, "Opening brace missing ");//début d'un bloc attendu?
+ if ( num == TX_BADTYPE ) strcpy(text, "Wrong type for the assignment");
+ if ( num == TX_REDEFVAR ) strcpy(text, "A variable can not be declared twice");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "The types of the two operands are incompatible ");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Unknown function");
+ if ( num == TX_MISDOTS ) strcpy(text, "Sign "" : "" missing");
+ if ( num == TX_WHILE ) strcpy(text, "Keyword ""while"" missing");
+ if ( num == TX_BREAK ) strcpy(text, "Instruction ""break"" outside a loop");
+ if ( num == TX_LABEL ) strcpy(text, "A label must be followed by ""for"", ""while"", ""do"" or ""switch""");
+ if ( num == TX_NOLABEL ) strcpy(text, "This label does not exist");// Cette étiquette n'existe pas
+ if ( num == TX_NOCASE ) strcpy(text, "Instruction ""case"" missing");
+ if ( num == TX_BADNUM ) strcpy(text, "Number missing");
+ if ( num == TX_VOID ) strcpy(text, "Void parameter");
+ if ( num == TX_NOTYP ) strcpy(text, "Type declaration missing");
+ if ( num == TX_NOVAR ) strcpy(text, "Variable name missing");
+ if ( num == TX_NOFONC ) strcpy(text, "Function name missing");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Too many parameters");
+ if ( num == TX_REDEF ) strcpy(text, "Function already exists");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Parameters missing ");
+ if ( num == TX_BADPARAM ) strcpy(text, "No function of this name accepts this kind of parameter");
+ if ( num == TX_NUMPARAM ) strcpy(text, "No function of this name accepts this number of parameters");
+ if ( num == TX_NOITEM ) strcpy(text, "This is not a member of this class");
+ if ( num == TX_DOT ) strcpy(text, "This object is not a member of a class");
+ if ( num == TX_NOCONST ) strcpy(text, "Appropriate constructor missing");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "This class already exists");
+ if ( num == TX_CLBRK ) strcpy(text, """ ] "" missing");
+ if ( num == TX_RESERVED ) strcpy(text, "Reserved keyword of CBOT language");
+ if ( num == TX_BADNEW ) strcpy(text, "Bad argument for ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, """ [ "" expected");
+ if ( num == TX_BADSTRING ) strcpy(text, "String missing");
+ if ( num == TX_BADINDEX ) strcpy(text, "Incorrect index type");
+ if ( num == TX_PRIVATE ) strcpy(text, "Private element");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Public required");
+ if ( num == TX_DIVZERO ) strcpy(text, "Dividing through zero");
+ if ( num == TX_NOTINIT ) strcpy(text, "Variable not initialized");
+ if ( num == TX_BADTHROW ) strcpy(text, "Negative value rejected by ""throw""");//C'est quoi, ça?
+ if ( num == TX_NORETVAL ) strcpy(text, "The function returned no value ");
+ if ( num == TX_NORUN ) strcpy(text, "No function running");
+ if ( num == TX_NOCALL ) strcpy(text, "Calling an unknown function");
+ if ( num == TX_NOCLASS ) strcpy(text, "This class does not exist");
+ if ( num == TX_NULLPT ) strcpy(text, "Unknown Object");
+ if ( num == TX_OPNAN ) strcpy(text, "Operation impossible with value ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Access beyond array limit");
+ if ( num == TX_STACKOVER ) strcpy(text, "Stack overflow");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Illegal object");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Can't open file");
+ if ( num == TX_NOTOPEN ) strcpy(text, "File not open");
+ if ( num == TX_ERRREAD ) strcpy(text, "Read error");
+ if ( num == TX_ERRWRITE ) strcpy(text, "Write error");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< none >");
+ if ( num == VK_LEFT ) strcpy(text, "Arrow left");
+ if ( num == VK_RIGHT ) strcpy(text, "Arrow right");
+ if ( num == VK_UP ) strcpy(text, "Arrow up");
+ if ( num == VK_DOWN ) strcpy(text, "Arrow down");
+ if ( num == VK_CANCEL ) strcpy(text, "Control-break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_RETURN ) strcpy(text, "Enter");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Space");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Select");
+ if ( num == VK_EXECUTE ) strcpy(text, "Execute");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Help");
+ if ( num == VK_LWIN ) strcpy(text, "Left Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Right Windows");
+ if ( num == VK_APPS ) strcpy(text, "Application key");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "NumPad 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "NumPad 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "NumPad 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "NumPad 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "NumPad 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "NumPad 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "NumPad 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "NumPad 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "NumPad 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "NumPad 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "NumPad *");
+ if ( num == VK_ADD ) strcpy(text, "NumPad +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "NumPad sep");
+ if ( num == VK_SUBTRACT ) strcpy(text, "NumPad -");
+ if ( num == VK_DECIMAL ) strcpy(text, "NumPad .");
+ if ( num == VK_DIVIDE ) strcpy(text, "NumPad /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Play");
+ if ( num == VK_ZOOM ) strcpy(text, "Zoom");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Button 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Button 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Button 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Button 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Button 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Button 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Button 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Button 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Button 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Button 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Button 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Button 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Button 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Button 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Button 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Button 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Button 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Button 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Button 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Button 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Button 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Button 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Button 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Button 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Button 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Button 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Button 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Button 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Button 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Button 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Button 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Button 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Wheel up");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Wheel down");
+ }
+#endif
+
+#if _FRENCH
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "Version 1.8 /f");
+ #endif
+ #if _NET | _SCHOOL
+ if ( num == RT_VERSION_ID ) strcpy(text, "Ecole 1.8 /f");
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.8 /f");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Taille maximale");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Taille réduite");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Taille normale");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Fermer");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Edition du programme");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "Nouveau");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Joueur");
+ if ( num == RT_IO_NEW ) strcpy(text, "Nouveau ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " ou ");
+
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Programmation");
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Défis");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Missions");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Jeu libre");
+ if ( num == RT_TITLE_USER ) strcpy(text, "Niveaux supplémentaires");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypes");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Options");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Nom du joueur");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Personnalisation de votre apparence");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Enregistrement de la mission en cours");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Chargement d'une mission enregistrée");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Liste des chapitres :");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Liste des chapitres :");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Liste des planètes :");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Liste des planètes :");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " Niveaux supplémentaires :");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Liste des planètes :");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Liste des exercices du chapitre :");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Liste des défis du chapitre :");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Liste des missions du chapitre :");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Liste des jeux libres du chapitre :");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Missions du niveau :");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Liste des prototypes du chapitre :");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Résumé :");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Pilotes :");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " Résolutions :");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) Cliquez d'abord sur la touche à redéfinir.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Appuyez ensuite sur la nouvelle touche souhaitée.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Type de visage :");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Lunettes :");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Couleur des cheveux :");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Couleur de la combinaison :");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Couleur des bandes :");
+
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Quitter la mission ?");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Voulez-vous quitter COLOBOT ?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Abandonner\\Abandonner la mission en cours");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Continuer\\Continuer la mission en cours");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Quitter\\Quitter COLOBOT");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Continuer\\Continuer de jouer");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Voulez-vous vraiment détruire le bâtiment sélectionné ?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Voulez-vous détruire les sauvegardes de %s ?");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Détruire");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Annuler");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "CHARGEMENT");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Aide sur le mot-clé (\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Compilation ok (0 erreur)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Programme terminé");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;Listes des objets\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Listes des robots\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Listes des bâtiments\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Listes des objets transportables\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Listes des ennemis\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (aucun)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;Erreur\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "Liste non disponible sans \\l;radar\\u object\\radar; !\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Ouvrir");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Enregistrer");
+ if ( num == RT_IO_LIST ) strcpy(text, "Dossier: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Nom:");
+ if ( num == RT_IO_DIR ) strcpy(text, "Dans:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Privé\\Dossier privé");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Public\\Dossier commun à tous les joueurs");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Développé par :");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "Version française éditée par :");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.alsyd.com");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "D'accord");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Annuler");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Suivant");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Précédent");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menu (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "D'accord");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Annuler");
+
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Programmation\\Exercices de programmation");
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Défis\\Défis de programmation");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Missions\\La grande aventure");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Jeu libre\\Jeu libre sans but précis");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "Suppl.\\Niveaux supplémentaires");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Proto\\Prototypes en cours d'élaboration");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "Autre joueur\\Choix du nom du joueur");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Options\\Réglages");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Recommencer\\Recommencer la mission au début");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Enregistrer\\Enregistrer la mission en cours");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Charger\\Charger une mission enregistrée");
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Retourner dans COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Quitter\\Quitter COLOBOT");
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Retour \\Retour au niveau précédent");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Jouer ...\\Démarrer l'action");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Affichage\\Pilote et résolution d'affichage");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Graphique\\Options graphiques");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Jeu\\Options de jouabilité");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Commandes\\Touches du clavier");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "Son\\Volumes bruitages & musiques");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Unité");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "Résolution");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Plein écran\\Plein écran ou fenêtré");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Appliquer les changements\\Active les changements effectués");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robbie\\Votre assistant");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Ombres\\Ombres projetées au sol");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Marques sur le sol\\Marques dessinées sur le sol");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Salissures\\Salissures des robots et bâtiments");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Brouillard\\Nappes de brouillard");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Rayons du soleil\\Rayons selon l'orientation");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Ciel\\Ciel et nuages");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planètes et étoiles\\Motifs mobiles dans le ciel");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Lumières dynamiques\\Eclairages mobiles");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Quantité de particules\\Explosions, poussières, reflets, etc.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "Profondeur de champ\\Distance de vue maximale");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Détails des objets\\Qualité des objets en 3D");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Qualité des textures\\Qualité des images");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Nombre d'objets décoratifs\\Qualité d'objets non indispensables");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Particules dans l'interface\\Pluie de particules");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Reflets sur les boutons\\Boutons brillants");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Bulles d'aide\\Bulles explicatives");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Séquences cinématiques\\Films avant ou après une mission");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Retour animé\\Retour animé dans les exercices");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Dégâts à soi-même\\Vos tirs infligent des dommages à vos unités");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Défilement dans les bords\\Défilement lorsque la souris touches les bords gauche ou droite");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Inversion souris Y\\Inversion de la rotation lorsque la souris touche un bord");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Secousses lors d'explosions\\L'écran vibre lors d'une explosion");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Souris ombrée\\Jolie souris avec une ombre");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Indentation automatique\\Pendant l'édition d'un programme");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Grande indentation\\Indente avec 2 ou 4 espaces");
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Tout réinitialiser\\Remet toutes les touches standards");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Tourner à gauche\\Moteur à gauche");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Tourner à droite\\Moteur à droite");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Avancer\\Moteur en avant");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Reculer\\Moteur en arrière");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "Monter\\Augmenter la puissance du réacteur");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "Descendre\\Diminuer la puissance du réacteur");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Changement de caméra\\Autre de point de vue");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Sélection précédente\\Sélectionne l'objet précédent");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Action standard\\Action du bouton avec le cadre rouge");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Caméra plus proche\\Avance la caméra");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Caméra plus loin\\Recule la caméra");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Sélectionner l'objet suivant\\Sélectionner l'objet suivant");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Sélectionner le cosmonaute\\Sélectionner le cosmonaute");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Quitter la mission en cours\\Terminer un exercice ou une mssion");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Instructions mission\\Marche à suivre");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Instructions programmation\\Explication sur la programmation");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Instructions mot-clé\\Explication sur le mot-clé");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Montrer le lieu d'un message\\Montrer le lieu du dernier message");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Vitesse 1.0x\\Vitesse normale");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Vitesse 1.5x\\Une fois et demi plus rapide");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Vitesse 2.0x\\Deux fois plus rapide");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Vitesse 3.0x\\Trois fois plus rapide");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Bruitages :\\Volume des moteurs, voix, etc.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Fond sonore :\\Volume des pistes audio du CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "Bruitages 3D\\Positionnement sonore dans l'espace");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Mini\\Qualité minimale (+ rapide)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normal\\Qualité standard");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Maxi\\Haute qualité (+ lent)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Silencieux\\Totalement silencieux");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normal\\Niveaux normaux");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "Utilise un joystick\\Joystick ou clavier");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Accès à la solution\\Donne la solution");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\Nom du joueur à créer");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "D'accord\\Choisir le joueur");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Annuler\\Conserver le joueur actuel");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Supprimer le joueur\\Supprimer le joueur de la liste");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Nom du joueur");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Enregistrer\\Enregistrer la mission en cours");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Charger\\Charger la mission sélectionnée");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "Liste des missions enregistrées");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Nom du fichier :");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Nom de la mission");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Vue de la mission");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Supprimer\\Supprime l'enregistrement sélectionné");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Aspect\\Choisir votre aspect");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "D'accord");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Annuler");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standard\\Remet les couleurs standards");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "Tête\\Visage et cheveux");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Corps\\Combinaison");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Rotation à gauche");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Rotation à droite");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Rouge");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Vert");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Bleu");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Rouge");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Vert");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Bleu");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Visage 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Visage 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Visage 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Visage 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\Pas de lunettes");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Lunettes 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Lunettes 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Lunettes 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Lunettes 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Lunettes 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Sélection précédente (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Tourne à gauche (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Tourne à droite (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Avance (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Recule (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Monte (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Descend (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Prend ou dépose (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Prend ou dépose (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..devant");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..derrière");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..pile");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Instructions sur la mission (\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Décolle pour terminer la mission");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Construit un derrick");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Construit une station");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Construit une fabrique de robots");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Construit un centre de réparation");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Construit un convertisseur");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Construit une tour");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Construit un centre de recherches");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Construit un radar");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Construit une fabrique de piles");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Construit un laboratoire");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Construit une centrale nucléaire");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Construit un paratonnerre");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Construit une borne d'information");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Montre si le sol est plat");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Pose un drapeau de couleur");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Enlève un drapeau");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Drapeaux bleus");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Drapeaux rouges");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Drapeaux verts");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\Drapeaux jaunes");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Drapeaux violets");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Fabrique un déménageur volant");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Fabrique un déménageur à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Fabrique un déménageur à roues");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Fabrique un déménageur à pattes");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Fabrique un shooter volant");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Fabrique un shooter à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Fabrique un shooter à roues");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Fabrique un shooter à pattes");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Fabrique un orgaShooter volant");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Fabrique un orgaShooter à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Fabrique un orgaShooter à roues");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Fabrique un orgaShooter à pattes");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Fabrique un renifleur volant");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Fabrique un renifleur à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Fabrique un renifleur à roues");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Fabrique un renifleur à pattes");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Fabrique un robot secoueur");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Fabrique un robot phazer");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Fabrique un robot recycleur");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Fabrique un robot bouclier");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Fabrique un robot sous-marin");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Recherche les chenilles");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Recherche les robots volants");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Recherche le secoueur");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Recherche le canon shooter");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Recherche la tour de défense");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Recherche le canon phazer");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Recherche le bouclier");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Recherche le nucléaire");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Recherche les pattes");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Recherche le canon orgaShooter");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Remet au départ");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Cherche (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Secoue (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Tir (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Recycle (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Déploie le bouclier (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Stoppe le bouclier (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Rayon du bouclier");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Exécute le programme sélectionné");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Edite le programme sélectionné");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\Mettre le SatCom en veille");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Démolit le bâtiment");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Niveau d'énergie");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Niveau du bouclier");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Température du réacteur");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Travail en cours ...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Nombre d'insectes détectés");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Informations diffusées");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Boussole");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Mini-carte");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Zoom mini-carte");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Caméra (\\key camera;)");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Instructions sur la sélection");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Donne la solution");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Permute robots <-> bâtiments");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Montre le rayon d'action");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Montre l'endroit");
+ if ( num == EVENT_DT_END ) strcpy(text, "Continuer");
+ if ( num == EVENT_CMD ) strcpy(text, "Console de commande");
+ if ( num == EVENT_SPEED ) strcpy(text, "Vitesse du jeu");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Page précédente");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Page suivante");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Page initiale");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Copier");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "Taille 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "Taille 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "Taille 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "Taille 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "Taille 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Instructions de Houston");
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Rapport du satellite");
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Programmes envoyés par Houston");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "Liste des objets");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Aide à la programmation");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Solution");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "D'accord\\Compiler le programme");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Annuler\\Annuler toutes les modifications");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "Nouveau");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Ouvrir (Ctrl+o)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Enregistrer (Ctrl+s)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Annuler (Ctrl+z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Couper (Ctrl+x)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Copier (Ctrl+c)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Coller (Ctrl+v)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "Taille des caractères");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Instructions (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Aide à la programmation (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Compiler");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Démarrer/stopper");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pause/continuer");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "Un pas");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "Portique");
+ if ( num == OBJECT_BASE ) strcpy(text, "Vaisseau spatial");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Derrick");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Fabrique de robots");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Centre de réparation");
+ if ( num == OBJECT_STATION ) strcpy(text, "Station de recharge");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Conversion minerai en titanium");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Tour de défense");
+ if ( num == OBJECT_NEST ) strcpy(text, "Nid");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Centre de recherches");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Radar");
+ if ( num == OBJECT_INFO ) strcpy(text, "Borne d'information");
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Fabrique de piles");
+ if ( num == OBJECT_LABO ) strcpy(text, "Laboratoire de matières organiques");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Centrale nucléaire");
+ if ( num == OBJECT_PARA ) strcpy(text, "Paratonnerre");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Coffre-fort");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Centre de contrôle");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Cible");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Cible");
+ if ( num == OBJECT_START ) strcpy(text, "Départ");
+ if ( num == OBJECT_END ) strcpy(text, "But");
+ if ( num == OBJECT_STONE ) strcpy(text, "Minerai de titanium");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Minerai d'uranium");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Matière organique");
+ if ( num == OBJECT_METAL ) strcpy(text, "Titanium");
+ if ( num == OBJECT_POWER ) strcpy(text, "Pile normale");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Pile nucléaire");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Boîte noire");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Clé A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Clé B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Clé C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Clé D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Explosif");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Mine fixe");
+ if ( num == OBJECT_BAG ) strcpy(text, "Sac de survie");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Indicateur");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Drapeau bleu");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Drapeau rouge");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Drapeau vert");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "Drapeau jaune");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Drapeau violet");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "Emplacement pour station");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Emplacement pour derrick (uranium)");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Emplacement pour derrick (clé A)");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Emplacement pour derrick (clé B)");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Emplacement pour derrick (clé C)");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Emplacement pour derrick (clé D)");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Emplacement pour derrick (titanium)");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Robot secoueur");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Robot phazer");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Robot recycleur");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Robot bouclier");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Robot sous-marin");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Cible d'entraînement");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "Technicien");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robbie");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Pondeuse");
+ if ( num == OBJECT_ANT ) strcpy(text, "Fourmi");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Araignée");
+ if ( num == OBJECT_BEE ) strcpy(text, "Guêpe");
+ if ( num == OBJECT_WORM ) strcpy(text, "Ver");
+ if ( num == OBJECT_EGG ) strcpy(text, "Oeuf");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Déchet");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Epave de vaisseau spatial");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Epave de vaisseau spatial");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Vestige d'une mission Apollo");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Lunar Roving Vehicle");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "Erreur");
+ if ( num == ERR_CMD ) strcpy(text, "Commande inconnue");
+ if ( num == ERR_INSTALL ) strcpy(text, "COLOBOT n'est pas installé.");
+ if ( num == ERR_NOCD ) strcpy(text, "Veuillez mettre le CD de COLOBOT\net relancer le jeu.");
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Porte déjà quelque chose");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Rien à prendre");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Emplacement occupé");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "Pas d'autre robot");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "Vous ne pouvez pas transporter un objet radioactif");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "Vous ne pouvez pas transporter un objet sous l'eau");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Rien à déposer");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Impossible sous l'eau");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Titanium trop loin");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Titanium trop proche");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "Titanium inexistant");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Sol pas assez plat");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Sol plat pas assez grand");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Emplacement occupé");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Trop proche du vaisseau spatial");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Trop proche d'un bâtiment");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Terrain inadapté");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Bâtiment trop proche");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Objet trop proche");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Rien à recycler");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "Plus d'énergie");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "Déplacement impossible");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Chemin introuvable");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Position inaccessible");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Destination occupée");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "Pas de minerai de titanium à convertir");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "Pas de minerai en sous-sol");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "Pas d'énergie en sous-sol");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "Pas de pile");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "Plus d'énergie");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "Pas de pile");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Plus assez d'énergie");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Pas le bon type de pile");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Recherche déjà effectuée");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "Pas d'énergie en sous-sol");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Pas encore assez d'énergie");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "Pas de titanium à transformer");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Ne transforme que le titanium");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Portes bloquées par un robot ou un objet");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "Vous devez embarquer pour pouvoir décoller");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Rien à analyser");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "N'analyse que la matière organique");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analyse déjà effectuée");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "Pas d'énergie en sous-sol");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Pas encore assez d'énergie");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "Pas d'uranium à transformer");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Ne transforme que l'uranium");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "Pas de titanium");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Quelque chose est trop proche");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Emplacement occupé");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "Pas trouvé de borne d'information");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Un programme est infecté par un virus");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Infecté par un virus, ne fonctionne plus temporairement");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "Pas de pile");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "Plus d'énergie");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Impossible en nageant");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Impossible en portant un objet");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Trop de drapeaux de cette couleur (maximum 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Trop proche d'un drapeau existant");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "Aucun drapeau à proximité");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "La misssion n'est pas terminée (appuyez sur \\key help; pour plus de détails)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Robot détruit");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Bâtiment détruit");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Création impossible, il y a trop d'objets");
+
+ if ( num == INFO_BUILD ) strcpy(text, "Bâtiment terminé");
+ if ( num == INFO_CONVERT ) strcpy(text, "Titanium disponible");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Recherche terminée");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Fabrication d'un robot à chenilles possible");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "Il est possible de voler avec les touches (\\key gup;) et (\\key gdown;)");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Fabrication d'un robot secoueur possible");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Fabrication de robots shooter possible");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Construction d'une tour de défense possible");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Fabrication d'un robot phazer possible");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Fabrication d'un robot bouclier possible");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Construction d'une centrale nucléaire possible");
+ if ( num == INFO_FACTORY ) strcpy(text, "Nouveau robot disponible");
+ if ( num == INFO_LABO ) strcpy(text, "Analyse terminée");
+ if ( num == INFO_ENERGY ) strcpy(text, "Pile disponible");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Pile nucléaire disponible");
+ if ( num == INFO_FINDING ) strcpy(text, "Vous avez trouvé un objet utilisable");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Emplacement pour station trouvé");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Bravo, mission terminée >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Désolé, mission échouée >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Désolé, mission échouée >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Enregistrement effectué");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Indicateur atteint");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Pondeuse mortellement touchée");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Fourmi mortellement touchée");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Guêpe mortellement touchée");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Ver mortellement touché");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Araignée mortellement touchée");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Consultez votre SatCom en appuyant sur \\key help;");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "Erreur");
+ if ( num == TX_OPENPAR ) strcpy(text, "Il manque une parenthèse ouvrante");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Il manque une parenthèse fermante");
+ if ( num == TX_NOTBOOL ) strcpy(text, "L'expression doit être un boolean");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Variable non déclarée");
+ if ( num == TX_BADLEFT ) strcpy(text, "Assignation impossible");
+ if ( num == TX_ENDOF ) strcpy(text, "Terminateur point-virgule non trouvé");
+ if ( num == TX_OUTCASE ) strcpy(text, "Instruction ""case"" hors d'un bloc ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Instructions après la fin");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "Il manque la fin du bloc");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Instruction ""else"" sans ""if"" correspondant");
+ if ( num == TX_OPENBLK ) strcpy(text, "Début d'un bloc attendu");
+ if ( num == TX_BADTYPE ) strcpy(text, "Mauvais type de résultat pour l'assignation");
+ if ( num == TX_REDEFVAR ) strcpy(text, "Redéfinition d'une variable");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "Les deux opérandes ne sont pas de types compatibles");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Routine inconnue");
+ if ( num == TX_MISDOTS ) strcpy(text, "Séparateur "" : "" attendu");
+ if ( num == TX_WHILE ) strcpy(text, "Manque le mot ""while""");
+ if ( num == TX_BREAK ) strcpy(text, "Instruction ""break"" en dehors d'une boucle");
+ if ( num == TX_LABEL ) strcpy(text, "Un label ne peut se placer que devant un ""for"", un ""while"", un ""do"" ou un ""switch""");
+ if ( num == TX_NOLABEL ) strcpy(text, "Cette étiquette n'existe pas");
+ if ( num == TX_NOCASE ) strcpy(text, "Manque une instruction ""case""");
+ if ( num == TX_BADNUM ) strcpy(text, "Un nombre est attendu");
+ if ( num == TX_VOID ) strcpy(text, "Paramètre void");
+ if ( num == TX_NOTYP ) strcpy(text, "Déclaration de type attendu");
+ if ( num == TX_NOVAR ) strcpy(text, "Nom d'une variable attendu");
+ if ( num == TX_NOFONC ) strcpy(text, "Nom de la fonction attendu");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Trop de paramètres");
+ if ( num == TX_REDEF ) strcpy(text, "Cette fonction existe déjà");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Pas assez de paramètres");
+ if ( num == TX_BADPARAM ) strcpy(text, "Aucune fonction de ce nom n'accepte ce(s) type(s) de paramètre(s)");
+ if ( num == TX_NUMPARAM ) strcpy(text, "Aucune fonction de ce nom n'accepte ce nombre de paramètres");
+ if ( num == TX_NOITEM ) strcpy(text, "Cet élément n'existe pas dans cette classe");
+ if ( num == TX_DOT ) strcpy(text, "L'objet n'est pas une instance d'une classe");
+ if ( num == TX_NOCONST ) strcpy(text, "Il n'y a pas de constructeur approprié");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "Cette classe existe déjà");
+ if ( num == TX_CLBRK ) strcpy(text, """ ] "" attendu");
+ if ( num == TX_RESERVED ) strcpy(text, "Ce mot est réservé");
+ if ( num == TX_BADNEW ) strcpy(text, "Mauvais argument pour ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, """ [ "" attendu");
+ if ( num == TX_BADSTRING ) strcpy(text, "Une chaîne de caractère est attendue");
+ if ( num == TX_BADINDEX ) strcpy(text, "Mauvais type d'index");
+ if ( num == TX_PRIVATE ) strcpy(text, "Elément protégé");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Public requis");
+ if ( num == TX_DIVZERO ) strcpy(text, "Division par zéro");
+ if ( num == TX_NOTINIT ) strcpy(text, "Variable non initialisée");
+ if ( num == TX_BADTHROW ) strcpy(text, "Valeur négative refusée pour ""throw""");
+ if ( num == TX_NORETVAL ) strcpy(text, "La fonction n'a pas retourné de résultat");
+ if ( num == TX_NORUN ) strcpy(text, "Pas de fonction en exécution");
+ if ( num == TX_NOCALL ) strcpy(text, "Appel d'une fonction inexistante");
+ if ( num == TX_NOCLASS ) strcpy(text, "Cette classe n'existe pas");
+ if ( num == TX_NULLPT ) strcpy(text, "Objet n'existe pas");
+ if ( num == TX_OPNAN ) strcpy(text, "Opération sur un ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Accès hors du tableau");
+ if ( num == TX_STACKOVER ) strcpy(text, "Débordement de la pile");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Objet inaccessible");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Ouverture du fichier impossible");
+ if ( num == TX_NOTOPEN ) strcpy(text, "Le fichier n'est pas ouvert");
+ if ( num == TX_ERRREAD ) strcpy(text, "Erreur à la lecture");
+ if ( num == TX_ERRWRITE ) strcpy(text, "Erreur à l'écriture");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< aucune >");
+ if ( num == VK_LEFT ) strcpy(text, "Flèche Gauche");
+ if ( num == VK_RIGHT ) strcpy(text, "Flèche Droite");
+ if ( num == VK_UP ) strcpy(text, "Flèche Haut");
+ if ( num == VK_DOWN ) strcpy(text, "Flèche Bas");
+ if ( num == VK_CANCEL ) strcpy(text, "Control-break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_RETURN ) strcpy(text, "Entrée");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Espace");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Select");
+ if ( num == VK_EXECUTE ) strcpy(text, "Execute");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Help");
+ if ( num == VK_LWIN ) strcpy(text, "Left Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Right Windows");
+ if ( num == VK_APPS ) strcpy(text, "Application key");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "NumPad 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "NumPad 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "NumPad 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "NumPad 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "NumPad 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "NumPad 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "NumPad 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "NumPad 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "NumPad 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "NumPad 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "NumPad *");
+ if ( num == VK_ADD ) strcpy(text, "NumPad +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "NumPad sep");
+ if ( num == VK_SUBTRACT ) strcpy(text, "NumPad -");
+ if ( num == VK_DECIMAL ) strcpy(text, "NumPad .");
+ if ( num == VK_DIVIDE ) strcpy(text, "NumPad /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Play");
+ if ( num == VK_ZOOM ) strcpy(text, "Zoom");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Bouton 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Bouton 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Bouton 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Bouton 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Bouton 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Bouton 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Bouton 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Bouton 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Bouton 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Bouton 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Bouton 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Bouton 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Bouton 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Bouton 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Bouton 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Bouton 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Bouton 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Bouton 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Bouton 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Bouton 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Bouton 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Bouton 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Bouton 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Bouton 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Bouton 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Bouton 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Bouton 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Bouton 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Bouton 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Bouton 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Bouton 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Bouton 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Molette haut");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Molette bas");
+ }
+#endif
+
+#if _POLISH
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "Wersja 1.9 /pl");
+ #endif
+ #if _NET | _SCHOOL
+ if ( num == RT_VERSION_ID ) strcpy(text, "Szko³a 1.9 /pl");
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.9 /pl");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Powiêksz");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Pomniejsz");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Normalna wielkoϾ");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Zamknij");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Edytor programu");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "Nowy");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Gracz");
+ if ( num == RT_IO_NEW ) strcpy(text, "Nowy ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " lub ");
+
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Æwiczenia programistyczne");
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Wyzwania");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Misje");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Swobodna gra");
+ if ( num == RT_TITLE_USER ) strcpy(text, "Poziom u¿ytkownika");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypy");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Opcje");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Imiê gracza");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Dostosuj wygl¹d");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Zapisz bie¿¹c¹ misjê");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Wczytaj zapisan¹ misjê");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Rozdzia³y:");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Rozdzia³y:");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " Poziom u¿ytkownika:");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Æwiczenia w tym rozdziale:");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Wyzwania w tym rozdziale:");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Misje na tej planecie:");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Swobodna gra na tej planecie:");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Misje na tym poziomie:");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Prototypy na tej planecie:");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Streszczenie:");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Sterowniki:");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " RozdzielczoϾ:");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) Najpierw kliknij klawisz, który chcesz przedefiniowaæ.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Nastêpnie naciœnij klawisz, którego chcesz u¿ywaæ.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Rodzaj twarzy:");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Okulary:");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Kolor w³osów:");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Kolor skafandra:");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Kolor pasków:");
+
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Opuœciæ misjê?");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Czy na pewno chcesz opuœciæ grê COLOBOT?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Przerwij\\Przerywa bie¿¹c¹ misjê");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Kontynuuj\\Kontynuuje bie¿¹c¹ misjê");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Zakoñcz\\Koñczy grê COLOTOT");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Kontynuuj\\Kontynuuje grê");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Czy na pewno chcesz zniszczyæ zaznaczony budynek?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Czy na pewno chcesz skasowaæ grê gracza %s? ");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Usuñ");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Anuluj");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "WCZYTYWANIE");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Skróty klawiszowe (\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Program skompilowany (0 b³êdów)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Program zakoñczony");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;Lista obiektów\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Roboty\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Budynki\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Obiekty ruchome\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Obcy\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (brak)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;B³¹d\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "Lista jest dostêpna jedynie gdy dzia³a \\l;stacja radarowa\\u object\\radar;.\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Otwórz");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Zapisz");
+ if ( num == RT_IO_LIST ) strcpy(text, "Folder: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Nazwa:");
+ if ( num == RT_IO_DIR ) strcpy(text, "Folder:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Prywatny\\Folder prywatny");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Publiczny\\Folder ogólnodostêpny");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Twórcy:");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+//? if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "Wersja angielska wydana przez:");
+//? if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.?.com");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "OK");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Anuluj");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Nastêpny");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Poprzedni");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menu (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "OK");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Anuluj");
+
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Æwiczenia\\Æwiczenia programistyczne");
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Wyzwania\\Wyzwania programistyczne");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Misje\\Wybierz misjê");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Swobodna gra\\Swobodna gra bez konkretnych celów");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "Poziom\\Poziomy u¿ytkownika");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Prototypy\\Prototypy w trakcie rozwijania");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "Nowy gracz\\Wybierz imiê gracza");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Opcje\\Preferencje");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Uruchom ponownie\\Uruchamia ponownie misjê od pocz¹tku");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Zapisz\\Zapisuje bie¿¹c¹ misjê");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Wczytaj\\Wczytuje zapisan¹ misjê");
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Powróæ do gry COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Zakoñcz\\Koñczy grê COLOTOT");
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Wstecz \\Wraca do poprzedniego ekranu");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Graj\\Rozpoczyna misjê!");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Urz¹dzenie\\Ustawienia sterownika i rozdzielczoœci");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Grafika\\Ustawienia grafiki");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Gra\\Ustawienia gry");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Sterowanie\\Ustawienia klawiatury, joysticka i myszy");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "DŸwiêk\\G³oœnoœæ muzyki i dŸwiêków gry");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Jednostka");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "RozdzielczoϾ");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Pe³ny ekran\\Pe³ny ekran lub tryb okna");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Zastosuj zmiany\\Aktywuje zmienione ustawienia");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robbie\\Twój asystent");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Cienie\\Cienie na ziemi");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Znaki na ziemi\\Znaki na ziemi");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Kurz\\Kurz i bród na robotach i budynkach");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Mg³a\\Mg³a");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Promienie s³oneczne\\Promienie s³oneczne na niebie");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Niebo\\Chmury i mg³awice");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planety i gwiazdy\\Obiekty astronomiczne na niebie");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Dynamiczne oœwietlenie\\Ruchome Ÿród³a œwiat³a");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Liczba cz¹stek\\Wybuchy, kurz, odbicia, itp.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "G³êbokoœæ pola\\Maksymalna widocznoœæ");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Szczegó³y\\Jakoœæ wizualna obiektów 3D");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Tekstury\\JakoϾ tekstur ");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Iloœæ elementów dekoracyjnych \\Iloœæ elementów czysto dekoracyjnych");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Cz¹stki w interfejsie\\Para i iskry z silników w interfejsie");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Odbicia na przyciskach \\Œwiec¹ce przyciski");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Dymki pomocy\\Wyjaœnia funkcje przycisków");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Sekwencje filmowe\\Filmy przed rozpoczêciem i na zakoñczenie misji");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Koñcowy film\\Film na zakoñczenie æwiczeñ");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Przyjacielski ogieñ\\W³asne strza³y uszkadzaj¹ Twoje obiekty");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Przewijanie\\Ekran jest przewijany gdy mysz dotknie prawej lub lewej jego krawêdzi");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Odwrócenie myszy X\\Odwrócenie kierunków przewijania na w poziomie");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Odwrócenie myszy Y\\Odwrócenie kierunków przewijania na w pionie");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Wstrz¹sy przy wybuchach\\Ekran trzêsie siê podczas wybuchów");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Cieñ myszy\\Dodaje cieñ kursorowi myszy");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Automatyczne wciêcia\\Podczas edycji programu");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Du¿e wciêcie\\2 lub 4 spacje wciêcia na ka¿dy poziom zdefiniowany przez klamry");
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Standardowa kontrola\\Standardowe klawisze funkcyjne");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Skrêæ w lewo\\obraca robota w lewo");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Obróæ w prawo\\obraca robota w prawo");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Naprzód\\Porusza do przodu");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Wstecz\\Porusza do ty³u");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "W górê\\Zwiêksza moc silnika'");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "W dó³\\Zmniejsza moc silnika");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Zmieñ kamerê\\Prze³¹cza pomiêdzy kamer¹ pok³adow¹ i œledz¹c¹");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Poprzedni obiekt\\Zaznacz poprzedni obiekt");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Standardowa akcja\\Standardowa akcja robota (podnieœ/upuœæ, strzelaj, szukaj, itp.)");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Kamera bli¿ej\\Przybli¿a kamerê");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Kamera dalej\\Oddala kamerê");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Nastêpny obiekt\\Zaznacza nastêpny obiekt");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Zaznacz astronautê\\Zaznacza astronautê");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Zakoñcz\\Koñczy bie¿¹c¹ misjê lub æwiczenie");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Rozkazy\\Pokazuje rozkazy dotycz¹ce bie¿¹cej misji");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Podrêcznik programowania");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Pomoc dot. s³ów kluczowych\\Dok³adniejsza pomoc na temat s³ów kluczowych");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Miejsce nadania wiadomoœci\\Pokazuje sk¹d zosta³a wys³ana ostatnia wiadomoœæ");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Prêdkoœæ 1,0x\\Prêdkoœæ normalna");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Prêdkoœæ 1,5x\\1,5 raza szybciej");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Prêdkoœæ 2,0x\\Dwa razy szybciej");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Prêdkoœæ 3,0x\\Trzy razy szybciej");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Efekty dŸwiêkowe:\\G³oœnoœæ silników, g³osów, strza³ów, itp.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Muzyka w tle :\\G³oœnoœæ œcie¿ek dŸwiêkowych z p³yty CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "DŸwiêk 3D\\Przestrzenne pozycjonowanie dŸwiêków");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Najni¿sza\\Minimalna jakoœæ grafiki (najwy¿sza czêstotliwoœæ odœwie¿ania)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normalna\\Normalna jakoϾ grafiki");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Najwy¿sza\\Maksymalna jakoœæ grafiki (najni¿sza czêstotliwoœæ odœwie¿ania)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Cisza\\Bez dŸwiêków");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normalne\\Normalna g³oœnoœæ dŸwiêków");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "U¿ywaj joysticka\\Joystick lub klawiatura");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Dostêp do rozwi¹zania\\Pokazuje rozwi¹zanie (szczegó³owe instrukcje dotycz¹ce misji)");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\Nowe imiê gracza");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "OK\\Wybiera zaznaczonego gracza");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Anuluj\\Zachowuje bie¿¹ce imiê gracza");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Usuñ gracza\\Usuwa gracza z listy");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Imiê gracza");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Zapisz\\Zapisuje bie¿¹c¹ misjê");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Wczytaj\\Wczytuje zaznaczon¹ misjê");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "Lista zapisanych misji");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Nazwa pliku:");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Nazwa misji");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Fotografia");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Usuñ\\Usuwa zaznaczony plik");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Wygl¹d\\Wybierz swoj¹ postaæ");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "OK");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Anuluj");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standardowe\\Standardowe ustawienia wygl¹du");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "G³owa\\Twarz i w³osy");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Skafander\\Skafander astronauty");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Obróæ w lewo");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Obróæ w prawo");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Czerwony");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Zielony");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Niebieski");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Czerwony");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Zielony");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Niebieski");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Twarz 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Twarz 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Twarz 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Twarz 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\Bez okularów");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Okulary 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Okulary 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Okulary 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Okulary 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Okulary 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Poprzednie zaznaczenie (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Skrêæ w lewo (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Skrêæ w prawo (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Naprzód (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Cofnij (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Góra (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Dó³ (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Podnieœ lub upuœæ (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Podnieœ lub upuœæ (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..przed");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..za");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..ogniwo elektryczne");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Rozkazy dotycz¹ce misji (\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Odleæ, aby zakoñczyæ misjê");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Zbuduj kopalniê");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Zbuduj elektrowniê");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Zbuduj fabrykê robotów");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Zbuduj warsztat");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Zbuduj hutê");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Zbuduj wie¿ê obronn¹");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Zbuduj centrum badawcze");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Zbuduj stacjê radarow¹");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Zbuduj fabrykê ogniw elektrycznych");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Zbuduj laboratorium");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Zbuduj elektrowniê atomow¹");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Zbuduj odgromnik");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Zbuduj stacjê przekaŸnikow¹");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Poka¿ czy teren jest p³aski");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Postaw flagê");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Usuñ flagê");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Niebieskie flagi");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Czerwone flagi");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Zielone flagi");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\¯ó³te flagi");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Fioletowe flagi");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Zbuduj transporter lataj¹cy");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Zbuduj transporter na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Zbuduj transporter na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Zbuduj transporter na nogach");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Zbuduj dzia³o lataj¹ce");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Zbuduj dzia³o na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Zbuduj dzia³o na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Zbuduj dzia³o na nogach");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Zbuduj lataj¹ce dzia³o organiczne");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Zbuduj dzia³o organiczne na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Zbuduj dzia³o organiczne na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Zbuduj dzia³o organiczne na nogach");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Zbuduj szperacz lataj¹cy");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Zbuduj szperacz na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Zbuduj szperacz na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Zbuduj szperacz na nogach");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Zbuduj robota uderzacza");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Zbuduj dzia³o fazowe");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Zbuduj robota recyklera");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Zbuduj robota os³aniajacza");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Zbuduj robota nurka");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Rozpocznij prace badawcze robotów na g¹sienicach");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Rozpocznij prace badawcze robotów lataj¹cych");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Rozpocznij prace badawcze robota uderzacza");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Rozpocznij prace badawcze dzia³a");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Rozpocznij prace badawcze wie¿y obronnej");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Rozpocznij prace badawcze dzia³a fazowego");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Rozpocznij prace badawcze robota os³aniacza");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Rozpocznij prace badawcze energii atomowej");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Rozpocznij prace badawcze robotów na nogach");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Rozpocznij prace badawcze dzia³a organicznego");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Powrót do pocz¹tku");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Szukaj (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Uderz (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Strzelaj (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Odzyskaj (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Rozszerz os³onê (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Wy³¹cz os³onê (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Zasiêg os³ony");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Wykonaj zaznaczony program");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Edytuj zaznaczony program");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\Prze³¹cz przekaŸnik SatCom w stan gotowoœci");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Zniszcz budynek");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Poziom energii");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Poziom os³ony");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Temperatura silnika");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Wci¹¿ pracuje...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Liczba wykrytych insektów");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Przes³ane informacje");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Kompas");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Mapka");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Powiêkszenie mapki");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Kamera (\\key camera;)");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Pomoc na temat zaznaczonego obiektu");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Poka¿ rozwi¹zanie");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Prze³¹cz roboty <-> budynki");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Poka¿ zasiêg");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Poka¿ miejsce");
+ if ( num == EVENT_DT_END ) strcpy(text, "Kontynuuj");
+ if ( num == EVENT_CMD ) strcpy(text, "Linia polecenia");
+ if ( num == EVENT_SPEED ) strcpy(text, "Prêdkoœæ gry");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Wstecz");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Naprzód");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Home");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Kopiuj");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "WielkoϾ 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "WielkoϾ 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "WielkoϾ 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "WielkoϾ 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "WielkoϾ 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Rozkazy z Houston");
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Raport z satelity");
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Program dostarczony z Houston");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "Lista obiektów");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Podrêcznik programowania");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Rozwi¹zanie");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "OK\\Zamyka edytor programu i powraca do gry");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Anuluj\\Pomija wszystkie zmiany");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "Nowy");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Otwórz (Ctrl+o)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Zapisz (Ctrl+s)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Cofnij (Ctrl+z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Wytnij (Ctrl+x)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Kopiuj (Ctrl+c)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Wklej (Ctrl+v)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "WielkoϾ czcionki");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Rozkazy (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Podrêcznik programowania (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Kompiluj");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Wykonaj/zatrzymaj");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pauza/kontynuuj");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "Jeden krok");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "¯uraw przesuwalny");
+ if ( num == OBJECT_BASE ) strcpy(text, "Statek kosmiczny");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Kopalnia");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Fabryka robotów");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Warsztat");
+ if ( num == OBJECT_STATION ) strcpy(text, "Stacja energetyczna");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Przetop rudê na tytan");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Wie¿a obronna");
+ if ( num == OBJECT_NEST ) strcpy(text, "Gniazdo");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Centrum badawcze");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Stacja radarowa");
+ if ( num == OBJECT_INFO ) strcpy(text, "Stacja przekaŸnikowa informacji");
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Fabryka ogniw elektrycznych");
+ if ( num == OBJECT_LABO ) strcpy(text, "Laboratorium");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Elektrownia atomowa");
+ if ( num == OBJECT_PARA ) strcpy(text, "Odgromnik");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Skrytka");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Centrum Kontroli Misji w Houston");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Cel");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Cel");
+ if ( num == OBJECT_START ) strcpy(text, "Pocz¹tek");
+ if ( num == OBJECT_END ) strcpy(text, "Koniec");
+ if ( num == OBJECT_STONE ) strcpy(text, "Ruda tytanu");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Ruda uranu");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Materia organiczna");
+ if ( num == OBJECT_METAL ) strcpy(text, "Tytan");
+ if ( num == OBJECT_POWER ) strcpy(text, "Ogniwo elektryczne");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Atomowe ogniwa elektryczne");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Czarna skrzynka");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Klucz A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Klucz B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Klucz C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Klucz D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Materia³y wybuchowe");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Mina");
+ if ( num == OBJECT_BAG ) strcpy(text, "Zestaw przetrwania");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Punkt kontrolny");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Niebieska flaga");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Czerwona flaga");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Zielona flaga");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "¯ó³ta flaga");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Fioletowa flaga");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "ród³o energii (miejsce na elektrowniê)");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Z³o¿e uranu (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Znaleziono klucz A (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Znaleziono klucz B (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Znaleziono klucz C (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Znaleziono klucz D (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Z³o¿e tytanu (miejsce na kopalniê)");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Transporter lataj¹cy");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Transporter na g¹sienicach");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Transporter na ko³ach");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Transporter na nogach");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Dzia³o lataj¹ce");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Dzia³o na g¹sienicach");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Dzia³o na ko³ach");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Dzia³o na nogach");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "Lataj¹ce dzia³o organiczne");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "Dzia³o organiczne na g¹sienicach");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "Dzia³o organiczne na ko³ach");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "Dzia³o organiczne na nogach");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Szperacz lataj¹cy");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Szperacz na g¹sienicach");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Szperacz na ko³ach");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Szperacz na nogach");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Uderzacz");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Dzia³o fazowe");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Recykler");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Os³aniacz");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Robot nurek");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Robot cel");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "In¿ynier");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robbie");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Królowa Obcych");
+ if ( num == OBJECT_ANT ) strcpy(text, "Mrówka");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Paj¹k");
+ if ( num == OBJECT_BEE ) strcpy(text, "Osa");
+ if ( num == OBJECT_WORM ) strcpy(text, "Robal");
+ if ( num == OBJECT_EGG ) strcpy(text, "Jajo");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Odpady");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Ruiny statku kosmicznego");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Ruiny statku kosmicznego");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Pozosta³oœci z misji Apollo");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Pojazd Ksiê¿ycowy");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "B³¹d");
+ if ( num == ERR_CMD ) strcpy(text, "Nieznane polecenie");
+ if ( num == ERR_INSTALL ) strcpy(text, "Gra COLOBOT nie jest zainstalowana.");
+ if ( num == ERR_NOCD ) strcpy(text, "W³ó¿ dysk CD z gr¹ COLOBOT\ni uruchom grê jeszcze raz.");
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Nie mo¿na nieœæ wiêcej przedmiotów");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Nie ma nic do podniesienia");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Miejsce zajête");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "Brak innego robota");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "Nie mo¿esz przenosiæ przedmiotów radioaktywnych");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "Nie mo¿esz przenosiæ przedmiotów pod wod¹");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Nie ma nic do upuszczenia");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Niemo¿liwe pod wod¹");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Tytan za daleko");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Tytan za blisko");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "Brak tytanu w pobli¿u");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Powierzchnia nie jest wystarczaj¹co p³aska");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Za ma³o p³askiego terenu");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Miejsce zajête");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Za blisko statku kosmicznego");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Za blisko budynku");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Nieodpowiedni teren");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Budynek za blisko");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Obiekt za blisko");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Nie ma niczego do odzysku");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "Nie ma wiêcej energii");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "B³¹d w poleceniu ruchu");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Goto: miejsce docelowe niedostêpne");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Goto: miejsce docelowe niedostêpne");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Goto: miejsce docelowe zajête");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "Brak rudy tytanu do przetopienia");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "W ziemi nie ma ¿adnej rudy");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "Brak energii w ziemi");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "Brak ogniwa elektrycznego");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "Nie ma wiêcej energii");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "Brak ogniwa elektrycznego");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Nieodpowiedni rodzaj ogniw");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Program badawczy zosta³ ju¿ wykonany");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "Brak energii w ziemi");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Wci¹¿ za ma³o energii");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "Brak tytanu do przetworzenia");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Przetwarza jedynie tytan");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Drzwi zablokowane przez robota lub inny obiekt ");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "Musisz byæ na statku kosmicznym aby nim odlecieæ");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Nie ma niczego do zanalizowania");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "Analizuje jedynie materiê organiczn¹");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analiza zosta³a ju¿ wykonana");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "Brak energii w ziemi");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Wci¹¿ za ma³o energii");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "Brak uranu do przetworzenia");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Przetwarza jedynie uran");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "Brak tytanu");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Obiekt za blisko");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Miejsce zajête");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "Nie ma ¿adnej stacji przekaŸnikowej w zasiêgu");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Program zawirusowany");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Zainfekowane wirusem, chwilowo niesprawne");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "Brak ogniwa elektrycznego");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "Nie ma wiêcej energii");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Niemo¿liwe podczas p³ywania");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Niemo¿liwe podczas przenoszenia przedmiotu");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Za du¿o flag w tym kolorze (maksymalnie 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Za blisko istniej¹cej flagi");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "Nie ma flagi w pobli¿u");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "Misja nie jest wype³niona (naciœnij \\key help; aby uzyskaæ szczegó³y)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Robot zniszczony");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Budynek zniszczony");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Nie mo¿na tego utworzyæ, za du¿o obiektów");
+
+ if ( num == INFO_BUILD ) strcpy(text, "Budowa zakoñczona");
+ if ( num == INFO_CONVERT ) strcpy(text, "Tytan dostêpny");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Program badawczy zakoñczony");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Dostêpne plany robotów na g¹sienicach");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "Mo¿esz lataæ u¿ywaj¹c klawiszy (\\key gup;) oraz (\\key gdown;)");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Dostêpne plany robota uderzacza");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Dostêpne plany dzia³a");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Dostêpne plany wie¿y obronnej");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Dostêpne plany dzia³a fazowego");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Dostêpne plany robota os³aniacza");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Dostêpne plany elektrowni atomowej");
+ if ( num == INFO_FACTORY ) strcpy(text, "Dostêpny nowy robot");
+ if ( num == INFO_LABO ) strcpy(text, "Analiza wykonana");
+ if ( num == INFO_ENERGY ) strcpy(text, "Wytworzono ogniwo elektryczne");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Wytworzono atomowe ogniwo elektryczne");
+ if ( num == INFO_FINDING ) strcpy(text, "Znaleziono u¿yteczny przedmiot");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Znaleziono miejsce na elektrowniê");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Dobra robota, misja wype³niona >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Niestety, misja nie powiod³a siê >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Niestety, misja nie powiod³a siê >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Bie¿¹ca misja zapisana");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Przekroczono punkt kontrolny");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Królowa Obcych zosta³a zabita");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Mrówka œmiertelnie ranna");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Osa œmiertelnie ranna");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Robal œmiertelnie ranny");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Paj¹k œmiertelnie ranny");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Naciœnij klawisz \\key help; aby wyœwietliæ rozkazy na przekaŸniku SatCom");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "B³¹d");
+ if ( num == TX_OPENPAR ) strcpy(text, "Brak nawiasu otwieraj¹cego");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Brak nawiasu zamykaj¹cego");
+ if ( num == TX_NOTBOOL ) strcpy(text, "Wyra¿enie musi zwróciæ wartoœæ logiczn¹");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Zmienna nie zosta³a zadeklarowana");
+ if ( num == TX_BADLEFT ) strcpy(text, "Przypisanie niemo¿liwe");
+ if ( num == TX_ENDOF ) strcpy(text, "Brak œrednika na koñcu wiersza");
+ if ( num == TX_OUTCASE ) strcpy(text, "Polecenie ""case"" outside a block ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Polecenie po koñcowej klamrze zamykaj¹cej");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "Brak koñca bloku");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Polecenie ""else"" without corresponding ""if"" ");
+ if ( num == TX_OPENBLK ) strcpy(text, "Brak klamry otwieraj¹cej");//début d'un bloc attendu?
+ if ( num == TX_BADTYPE ) strcpy(text, "Z³y typ dla przypisania");
+ if ( num == TX_REDEFVAR ) strcpy(text, "Zmienna nie mo¿e byæ zadeklarowana dwukrotnie");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "Niezgodne typy operatorów");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Funkcja nieznana");
+ if ( num == TX_MISDOTS ) strcpy(text, "Znak "" : "" missing");
+ if ( num == TX_WHILE ) strcpy(text, "Skrót klawiszowy ""while"" missing");
+ if ( num == TX_BREAK ) strcpy(text, "Polecenie ""break"" outside a loop");
+ if ( num == TX_LABEL ) strcpy(text, "Po etykiecie musi wyst¹piæ ""for"", ""while"", ""do"" or ""switch""");
+ if ( num == TX_NOLABEL ) strcpy(text, "Taka etykieta nie istnieje");// Cette étiquette n'existe pas
+ if ( num == TX_NOCASE ) strcpy(text, "Polecenie ""case"" missing");
+ if ( num == TX_BADNUM ) strcpy(text, "Brak liczby");
+ if ( num == TX_VOID ) strcpy(text, "Pusty parametr");
+ if ( num == TX_NOTYP ) strcpy(text, "Brak deklaracji typu");
+ if ( num == TX_NOVAR ) strcpy(text, "Brak nazwy zmiennej");
+ if ( num == TX_NOFONC ) strcpy(text, "Brakuj¹ca nazwa funkcji");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Za du¿o parametrów");
+ if ( num == TX_REDEF ) strcpy(text, "Funkcja ju¿ istnieje");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Brak wymaganego parametru");
+ if ( num == TX_BADPARAM ) strcpy(text, "Funkcja o tej nazwie nie akceptuje parametrów tego typu");
+ if ( num == TX_NUMPARAM ) strcpy(text, "Funkcja o tej nazwie nie akceptuje takiej liczby parametrów");
+ if ( num == TX_NOITEM ) strcpy(text, "To nie jest obiekt tej klasy");
+ if ( num == TX_DOT ) strcpy(text, "Ten obiekt nie jest cz³onkiem klasy");
+ if ( num == TX_NOCONST ) strcpy(text, "Brak odpowiedniego konstruktora");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "Taka klasa ju¿ istnieje");
+ if ( num == TX_CLBRK ) strcpy(text, """ ] "" missing");
+ if ( num == TX_RESERVED ) strcpy(text, "S³owo zarezerwowane jêzyka CBOT");
+ if ( num == TX_BADNEW ) strcpy(text, "Z³y argument dla funkcji ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, """ [ "" expected");
+ if ( num == TX_BADSTRING ) strcpy(text, "Brak ³añcucha");
+ if ( num == TX_BADINDEX ) strcpy(text, "Nieprawid³owy typ indeksu");
+ if ( num == TX_PRIVATE ) strcpy(text, "Element prywatny");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Wymagany publiczny");
+ if ( num == TX_DIVZERO ) strcpy(text, "Dzielenie przez zero");
+ if ( num == TX_NOTINIT ) strcpy(text, "Zmienna nie zosta³a zainicjalizowana");
+ if ( num == TX_BADTHROW ) strcpy(text, "Wartoœæ ujemna odrzucona przez ""throw""");//C'est quoi, ça?
+ if ( num == TX_NORETVAL ) strcpy(text, "Funkcja nie zwróci³a ¿adnej wartoœci ");
+ if ( num == TX_NORUN ) strcpy(text, "¯adna funkcja nie dzia³a");
+ if ( num == TX_NOCALL ) strcpy(text, "Odwo³anie do nieznanej funkcji");
+ if ( num == TX_NOCLASS ) strcpy(text, "Taka klasa nie istnieje");
+ if ( num == TX_NULLPT ) strcpy(text, "Obiekt nieznany");
+ if ( num == TX_OPNAN ) strcpy(text, "Dzia³anie niemo¿liwe z wartoœci¹ ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Dostêp poza tablicê");
+ if ( num == TX_STACKOVER ) strcpy(text, "Przepe³nienie stosu");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Nieprawid³owy obiekt");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Nie mo¿na otworzyæ pliku");
+ if ( num == TX_NOTOPEN ) strcpy(text, "Plik nie jest otwarty");
+ if ( num == TX_ERRREAD ) strcpy(text, "B³¹d odczytu");
+ if ( num == TX_ERRWRITE ) strcpy(text, "B³¹d zapisu");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< brak >");
+ if ( num == VK_LEFT ) strcpy(text, "Strza³ka w lewo");
+ if ( num == VK_RIGHT ) strcpy(text, "Strza³ka w prawo");
+ if ( num == VK_UP ) strcpy(text, "Strza³ka w górê");
+ if ( num == VK_DOWN ) strcpy(text, "Strza³ka w dó³");
+ if ( num == VK_CANCEL ) strcpy(text, "Ctrl-break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "WyczyϾ");
+ if ( num == VK_RETURN ) strcpy(text, "Enter");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Spacja");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Zaznacz");
+ if ( num == VK_EXECUTE ) strcpy(text, "Wykonaj");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Pomoc");
+ if ( num == VK_LWIN ) strcpy(text, "Lewy klawisz Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Prawy klawisz Windows");
+ if ( num == VK_APPS ) strcpy(text, "Klawisz menu kontekstowego");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "Szary 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "Szary 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "Szary 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "Szary 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "Szary 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "Szary 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "Szary 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "Szary 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "Szary 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "Szary 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "Szary *");
+ if ( num == VK_ADD ) strcpy(text, "Szary +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "Szary separator");
+ if ( num == VK_SUBTRACT ) strcpy(text, "Szary -");
+ if ( num == VK_DECIMAL ) strcpy(text, "Szary .");
+ if ( num == VK_DIVIDE ) strcpy(text, "Szary /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll Lock");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Graj");
+ if ( num == VK_ZOOM ) strcpy(text, "Powiêkszenie");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "WyczyϾ");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Przycisk 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Przycisk 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Przycisk 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Przycisk 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Przycisk 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Przycisk 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Przycisk 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Przycisk 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Przycisk 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Przycisk 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Przycisk 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Przycisk 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Przycisk 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Przycisk 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Przycisk 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Przycisk 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Przycisk 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Przycisk 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Przycisk 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Przycisk 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Przycisk 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Przycisk 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Przycisk 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Przycisk 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Przycisk 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Przycisk 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Przycisk 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Przycisk 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Przycisk 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Przycisk 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Przycisk 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Przycisk 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Kó³ko w górê");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Kó³ko w dó³");
+ }
+#endif
+
+ return ( text[0] != 0 );
+}
+
+
diff --git a/src/restext.cpp b/src/restext.cpp
new file mode 100644
index 0000000..8c25f01
--- /dev/null
+++ b/src/restext.cpp
@@ -0,0 +1,3649 @@
+// restext.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <stdio.h>
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "misc.h"
+#include "event.h"
+#include "object.h"
+#include "cbot\resource.h"
+#include "restext.h"
+
+
+
+//** -> texte à traduire !!!
+
+
+
+// Donne le pointeur au moteur.
+
+void SetEngine(CD3DEngine *engine)
+{
+ g_engine = engine;
+}
+
+// Donne le nom du joueur.
+
+void SetGlobalGamerName(char *name)
+{
+ strcpy(g_gamerName, name);
+}
+
+
+
+typedef struct
+{
+ KeyRank key;
+ char name[20];
+}
+KeyDesc;
+
+static KeyDesc keyTable[22] =
+{
+ { KEYRANK_LEFT, "left;" },
+ { KEYRANK_RIGHT, "right;" },
+ { KEYRANK_UP, "up;" },
+ { KEYRANK_DOWN, "down;" },
+ { KEYRANK_GUP, "gup;" },
+ { KEYRANK_GDOWN, "gdown;" },
+ { KEYRANK_CAMERA, "camera;" },
+ { KEYRANK_DESEL, "desel;" },
+ { KEYRANK_ACTION, "action;" },
+ { KEYRANK_NEAR, "near;" },
+ { KEYRANK_AWAY, "away;" },
+ { KEYRANK_NEXT, "next;" },
+ { KEYRANK_HUMAN, "human;" },
+ { KEYRANK_QUIT, "quit;" },
+ { KEYRANK_HELP, "help;" },
+ { KEYRANK_PROG, "prog;" },
+ { KEYRANK_CBOT, "cbot;" },
+ { KEYRANK_VISIT, "visit;" },
+ { KEYRANK_SPEED10, "speed10;" },
+ { KEYRANK_SPEED15, "speed15;" },
+ { KEYRANK_SPEED20, "speed20;" },
+ { KEYRANK_SPEED30, "speed30;" },
+};
+
+// Cherche une touche.
+
+BOOL SearchKey(char *cmd, KeyRank &key)
+{
+ int i;
+
+ for ( i=0 ; i<22 ; i++ )
+ {
+ if ( strstr(cmd, keyTable[i].name) == cmd )
+ {
+ key = keyTable[i].key;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Remplace les commandes "\key name;" dans un texte.
+
+void PutKeyName(char* dst, char* src)
+{
+ KeyRank key;
+ char name[50];
+ int s, d, n, res;
+
+ s = d = 0;
+ while ( src[s] != 0 )
+ {
+ if ( src[s+0] == '\\' &&
+ src[s+1] == 'k' &&
+ src[s+2] == 'e' &&
+ src[s+3] == 'y' &&
+ src[s+4] == ' ' )
+ {
+ if ( SearchKey(src+s+5, key) )
+ {
+ res = g_engine->RetKey(key, 0);
+ if ( res != 0 )
+ {
+ if ( GetResource(RES_KEY, res, name) )
+ {
+ n = 0;
+ while ( name[n] != 0 )
+ {
+ dst[d++] = name[n++];
+ }
+ while ( src[s++] != ';' );
+ continue;
+ }
+ }
+ }
+ }
+
+ dst[d++] = src[s++];
+ }
+ dst[d++] = 0;
+}
+
+
+// Retourne le texte d'une ressource.
+
+BOOL GetResource(ResType type, int num, char* text)
+{
+ char buffer[100];
+
+ if ( !GetResourceBase(type, num, buffer) )
+ {
+ text[0] = 0;
+ return FALSE;
+ }
+
+ PutKeyName(text, buffer);
+ return TRUE;
+}
+
+
+// Retourne le texte d'une ressource.
+
+BOOL GetResourceBase(ResType type, int num, char* text)
+{
+ text[0] = 0;
+
+#if _ENGLISH
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "1.18 /e");
+ #endif
+ #if _NET
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A 1.18");
+ #endif
+ #if _SCHOOL & _EDU
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen EDU 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A EDU 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _PERSO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen PERSO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A PERSO 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _CEEBOTDEMO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen DEMO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A DEMO 1.18");
+ #endif
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.18 /e");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Maximize");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Minimize");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Normal size");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Close");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Program editor");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "New");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Player");
+ if ( num == RT_IO_NEW ) strcpy(text, "New ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " or ");
+
+#if _NEWLOOK
+ if ( num == RT_TITLE_BASE ) strcpy(text, "CeeBot");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "CeeBot");
+#else
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+#endif
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Programming exercises");
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Challenges");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Missions");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Free game");
+ if ( num == RT_TITLE_TEEN ) strcpy(text, "Free game");
+ if ( num == RT_TITLE_USER ) strcpy(text, "User levels");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypes");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Options");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Player's name");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Customize your appearance");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Save the current mission");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Load a saved mission");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Chapters:");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Chapters:");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Planets:");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Planets:");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " User levels:");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Planets:");
+ if ( num == RT_PLAY_CHAPte ) strcpy(text, " Chapters:");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Exercises in the chapter:");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Challenges in the chapter:");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Missions on this planet:");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Free game on this planet:");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Missions on this level:");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Prototypes on this planet:");
+ if ( num == RT_PLAY_LISTk ) strcpy(text, " Free game on this chapter:");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Summary:");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Drivers:");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " Resolution:");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) First click on the key you want to redefine.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Then press the key you want to use instead.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Face type:");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Eyeglasses:");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Hair color:");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Suit color:");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Strip color:");
+
+#if _NEWLOOK
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Do you want to quit CeeBot ?");
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "CeeBot");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Quit\\Quit CeeBot");
+#else
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Do you want to quit COLOBOT ?");
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Quit\\Quit COLOBOT");
+#endif
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Quit the mission?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Abort\\Abort the current mission");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Continue\\Continue the current mission");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Continue\\Continue the game");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Do you really want to destroy the selected building?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Do you want to delete %s's saved games? ");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Delete");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Cancel");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "LOADING");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Keyword help(\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Compilation ok (0 errors)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Program finished");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;List of objects\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Robots\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Buildings\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Moveable objects\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Aliens\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (none)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;Error\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "The list is only available if a \\l;radar station\\u object\\radar; is working.\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Open");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Save");
+ if ( num == RT_IO_LIST ) strcpy(text, "Folder: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Name:");
+ if ( num == RT_IO_DIR ) strcpy(text, "Folder:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Private\\Private folder");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Public\\Common folder");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Developed by :");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+//? if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "English version published by:");
+//? if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.?.com");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+
+ if ( num == RT_INTERFACE_REC ) strcpy(text, "Recorder");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "OK");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Cancel");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Next");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Previous");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menu (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "OK");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Cancel");
+
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Exercises\\Programming exercises");
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Challenges\\Programming challenges");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Missions\\Select mission");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Free game\\Free game without a specific goal");
+ if ( num == EVENT_INTERFACE_TEEN ) strcpy(text, "Free game\\Free game without a specific goal");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "User\\User levels");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Proto\\Prototypes under development");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "New player\\Choose player's name");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Options\\Preferences");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Restart\\Restart the mission from the beginning");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Save\\Save the current mission ");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Load\\Load a saved mission");
+#if _NEWLOOK
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Return to CeeBot");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Quit\\Quit CeeBot");
+#else
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Return to COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Quit\\Quit COLOBOT");
+#endif
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Back \\Back to the previous screen");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Play\\Start mission!");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Device\\Driver and resolution settings");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Graphics\\Graphics settings");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Game\\Game settings");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Controls\\Keyboard, joystick and mouse settings");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "Sound\\Music and game sound volume");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Unit");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "Resolution");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Full screen\\Full screen or window mode");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Apply changes\\Activates the changed settings");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robbie\\Your assistant");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Shadows\\Shadows on the ground");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Marks on the ground\\Marks on the ground");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Dust\\Dust and dirt on bots and buildings");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Fog\\Fog");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Sunbeams\\Sunbeams in the sky");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Sky\\Clouds and nebulae");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planets and stars\\Astronomical objects in the sky");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Dynamic lighting\\Mobile light sources");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Number of particles\\Explosions, dust, reflections, etc.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "Depth of field\\Maximum visibility");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Details\\Visual quality of 3D objects");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Textures\\Quality of textures ");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Num of decorative objects\\Number of purely ornamental objects");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Particles in the interface\\Steam clouds and sparks in the interface");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Reflections on the buttons \\Shiny buttons");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Help balloons\\Explain the function of the buttons");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Film sequences\\Films before and after the missions");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Exit film\\Film at the exit of exercises");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Friendly fire\\Your shooting can damage your own objects ");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Scrolling\\Scrolling when the mouse touches right or left border");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Mouse inversion X\\Inversion of the scrolling direction on the X axis");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Mouse inversion Y\\Inversion of the scrolling direction on the Y axis");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Quake at explosions\\The screen shakes at explosions");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Mouse shadow\\Gives the mouse a shadow");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Automatic indent\\When program editing");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Big indent\\Indent 2 or 4 spaces per level defined by braces");
+ if ( num == EVENT_INTERFACE_SOLUCE4) strcpy(text, "Access to solutions\\Show program \"4: Solution\" in the exercises"); //**
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Standard controls\\Standard key functions");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Turn left\\turns the bot to the left");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Turn right\\turns the bot to the right");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Forward\\Moves forward");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Backward\\Moves backward");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "Climb\\Increases the power of the jet");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "Descend\\Reduces the power of the jet");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Change camera\\Switches between onboard camera and following camera");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Previous object\\Selects the previous object");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Standard action\\Standard action of the bot (take/grab, shoot, sniff, etc)");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Camera closer\\Moves the camera forward");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Camera back\\Moves the camera backward");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Next object\\Selects the next object");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Select the astronaut\\Selects the astronaut");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Quit\\Quit the current mission or exercise");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Instructions\\Shows the instructions for the current mission");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Programming help\\Gives more detailed help with programming");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Key word help\\More detailed help about key words");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Origin of last message\\Shows where the last message was sent from");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Speed 1.0x\\Normal speed");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Speed 1.5x\\1.5 times faster");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Speed 2.0x\\Double speed");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Speed 3.0x\\Three times faster");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Sound effects:\\Volume of engines, voice, shooting, etc.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Background sound :\\Volume of audio tracks on the CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "3D sound\\3D positioning of the sound");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Lowest\\Minimum graphic quality (highest frame rate)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normal\\Normal graphic quality");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Highest\\Highest graphic quality (lowest frame rate)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Mute\\No sound");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normal\\Normal sound volume");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "Use a joystick\\Joystick or keyboard");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Access to solution\\Shows the solution (detailed instructions for missions)");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\New player name");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "OK\\Choose the selected player");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Cancel\\Keep current player name");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Delete player\\Deletes the player from the list");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Player name");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Save\\Saves the current mission");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Load\\Loads the selected mission");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "List of saved missions");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Filename:");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Mission name");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Photography");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Delete\\Deletes the selected file");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Appearance\\Choose your appearance");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "OK");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Cancel");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standard\\Standard appearance settings");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "Head\\Face and hair");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Suit\\Astronaut suit");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Turn left");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Turn right");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Red");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Green");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Blue");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Red");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Green");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Blue");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Face 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Face 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Face 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Face 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\No eyeglasses");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Eyeglasses 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Eyeglasses 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Eyeglasses 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Eyeglasses 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Eyeglasses 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Previous selection (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Turn left (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Turn right (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Forward (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Backward (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Up (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Down (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Grab or drop (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Grab or drop (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..in front");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..behind");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..power cell");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Instructions for the mission (\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Take off to finish the mission");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Build a derrick");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Build a power station");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Build a bot factory");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Build a repair center");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Build a converter");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Build a defense tower");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Build a research center");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Build a radar station");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Build a power cell factory");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Build an autolab");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Build a nuclear power plant");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Build a lightning conductor");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Build a exchange post");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Show if the ground is flat");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Plant a flag");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Remove a flag");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Blue flags");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Red flags");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Green flags");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\Yellow flags");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Violet flags");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Build a winged grabber");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Build a tracked grabber");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Build a wheeled grabber");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Build a legged grabber");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Build a winged shooter");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Build a tracked shooter");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Build a wheeled shooter");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Build a legged shooter");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Build a winged orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Build a tracked orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Build a wheeled orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Build a legged orga shooter");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Build a winged sniffer");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Build a tracked sniffer");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Build a wheeled sniffer");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Build a legged sniffer");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Build a thumper");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Build a phazer shooter");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Build a recycler");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Build a shielder");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Build a subber");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Run research program for tracked bots");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Run research program for winged bots");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Run research program for thumper");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Run research program for shooter");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Run research program for defense tower");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Run research program for phazer shooter");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Run research program for shielder");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Run research program for nuclear power");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Run research program for legged bots");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Run research program for orga shooter");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Return to start");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Sniff (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Thump (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Shoot (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Recycle (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Extend shield (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Withdraw shield (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Shield radius");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Execute the selected program");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Edit the selected program");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\SatCom on standby");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Destroy the building");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Energy level");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Shield level");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Jet temperature");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Still working ...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Number of insects detected");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Transmitted information");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Compass");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Mini-map");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Zoom mini-map");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Camera (\\key camera;)");
+ if ( num == EVENT_OBJECT_CAMERAleft) strcpy(text, "Camera to left");
+ if ( num == EVENT_OBJECT_CAMERAright) strcpy(text, "Camera to right");
+ if ( num == EVENT_OBJECT_CAMERAnear) strcpy(text, "Camera nearest");
+ if ( num == EVENT_OBJECT_CAMERAaway) strcpy(text, "Camera awayest");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Help about selected object");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Show the solution");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Switch bots <-> buildings");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Show the range");
+ if ( num == EVENT_OBJECT_PEN0 ) strcpy(text, "\\Raise the pencil");
+ if ( num == EVENT_OBJECT_PEN1 ) strcpy(text, "\\Use the black pencil");
+ if ( num == EVENT_OBJECT_PEN2 ) strcpy(text, "\\Use the yellow pencil");
+ if ( num == EVENT_OBJECT_PEN3 ) strcpy(text, "\\Use the orange pencil");
+ if ( num == EVENT_OBJECT_PEN4 ) strcpy(text, "\\Use the red pencil");
+ if ( num == EVENT_OBJECT_PEN5 ) strcpy(text, "\\Use the purple pencil");
+ if ( num == EVENT_OBJECT_PEN6 ) strcpy(text, "\\Use the blue pencil");
+ if ( num == EVENT_OBJECT_PEN7 ) strcpy(text, "\\Use the green pencil");
+ if ( num == EVENT_OBJECT_PEN8 ) strcpy(text, "\\Use the brown pencil");
+ if ( num == EVENT_OBJECT_REC ) strcpy(text, "\\Start recording");
+ if ( num == EVENT_OBJECT_STOP ) strcpy(text, "\\Stop recording");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Show the place");
+ if ( num == EVENT_DT_END ) strcpy(text, "Continue");
+ if ( num == EVENT_CMD ) strcpy(text, "Command line");
+ if ( num == EVENT_SPEED ) strcpy(text, "Game speed");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Back");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Forward");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Home");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Copy");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "Size 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "Size 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "Size 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "Size 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "Size 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Instructions from Houston");
+#if _TEEN
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Dictionnary");
+#else
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Satellite report");
+#endif
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Programs dispatched by Houston");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "List of objects");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Programming help");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Solution");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "OK\\Close program editor and return to game");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Cancel\\Cancel all changes");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "New");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Open (Ctrl+o)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Save (Ctrl+s)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Undo (Ctrl+z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Cut (Ctrl+x)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Copy (Ctrl+c)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Paste (Ctrl+v)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "Font size");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Instructions (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Programming help (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Compile");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Execute/stop");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pause/continue");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "One step");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "Gantry crane");
+ if ( num == OBJECT_BASE ) strcpy(text, "Spaceship");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Derrick");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Bot factory");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Repair center");
+ if ( num == OBJECT_DESTROYER ) strcpy(text, "Destroyer");
+ if ( num == OBJECT_STATION ) strcpy(text, "Power station");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Converts ore to titanium");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Defense tower");
+ if ( num == OBJECT_NEST ) strcpy(text, "Nest");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Research center");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Radar station");
+ if ( num == OBJECT_INFO ) strcpy(text, "Information exchange post");
+#if _TEEN
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Power cell factory");
+#else
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Power cell factory");
+#endif
+ if ( num == OBJECT_LABO ) strcpy(text, "Autolab");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Nuclear power station");
+ if ( num == OBJECT_PARA ) strcpy(text, "Lightning conductor");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Vault");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Houston Mission Control");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Target");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Target");
+ if ( num == OBJECT_START ) strcpy(text, "Start");
+ if ( num == OBJECT_END ) strcpy(text, "Finish");
+ if ( num == OBJECT_STONE ) strcpy(text, "Titanium ore");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Uranium ore");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Organic matter");
+ if ( num == OBJECT_METAL ) strcpy(text, "Titanium");
+ if ( num == OBJECT_POWER ) strcpy(text, "Power cell");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Nuclear power cell");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Black box");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Key A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Key B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Key C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Key D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Explosive");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Fixed mine");
+ if ( num == OBJECT_BAG ) strcpy(text, "Survival kit");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Checkpoint");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Blue flag");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Red flag");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Green flag");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "Yellow flag");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Violet flag");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "Energy deposit (site for power station)");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Uranium deposit (site for derrick)");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Found key A (site for derrick)");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Found key B (site for derrick)");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Found key C (site for derrick)");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Found key D (site for derrick)");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Titanium deposit (site for derrick)");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Practice bot");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Winged grabber");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Tracked grabber");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Wheeled grabber");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Legged grabber");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Winged shooter");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Tracked shooter");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Wheeled shooter");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Legged shooter");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "Winged orga shooter");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "Tracked orga shooter");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "Wheeled orga shooter");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "Legged orga shooter");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Winged sniffer");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Tracked sniffer");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Wheeled sniffer");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Legged sniffer");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Thumper");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Phazer shooter");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Recycler");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Shielder");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Subber");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Target bot");
+ if ( num == OBJECT_MOBILEdr ) strcpy(text, "Drawer bot");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "Engineer");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robbie");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Alien Queen");
+ if ( num == OBJECT_ANT ) strcpy(text, "Ant");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Spider");
+ if ( num == OBJECT_BEE ) strcpy(text, "Wasp");
+ if ( num == OBJECT_WORM ) strcpy(text, "Worm");
+ if ( num == OBJECT_EGG ) strcpy(text, "Egg");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Wreckage");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Waste");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Ruin");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Spaceship ruin");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Spaceship ruin");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Remains of Apollo mission");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Lunar Roving Vehicle");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "Error");
+ if ( num == ERR_CMD ) strcpy(text, "Unknown command");
+#if _NEWLOOK
+ if ( num == ERR_INSTALL ) strcpy(text, "CeeBot not installed.");
+ if ( num == ERR_NOCD ) strcpy(text, "Please insert the CeeBot CD\nand re-run the game.");
+#else
+ if ( num == ERR_INSTALL ) strcpy(text, "COLOBOT not installed.");
+ if ( num == ERR_NOCD ) strcpy(text, "Please insert the COLOBOT CD\nand re-run the game.");
+#endif
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Already carrying something");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Nothing to grab");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Place occupied");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "No other robot");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "You can not carry a radioactive object");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "You can not carry an object under water");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Nothing to drop");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Impossible under water");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Titanium too far away");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Titanium too close");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "No titanium around");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Ground not flat enough");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Flat ground not large enough");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Place occupied");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Too close to space ship");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Too close to a building");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Ground inappropriate");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Building too close");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Object too close");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Nothing to recycle");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "No more energy");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "Error in instruction move");
+ if ( num == ERR_FIND_IMPOSSIBLE ) strcpy(text, "Object not found");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Goto: inaccessible destination");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Goto: inaccessible destination");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Goto: destination occupied");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Inappropriate bot");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "No titanium ore to convert");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "No ore in the subsoil");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "No energy in the subsoil");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "No power cell");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "No more energy");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "No power cell");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Not enough energy");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Inappropriate cell type");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Research program already performed");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "No energy in the subsoil");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Not enough energy yet");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "No titanium to transform");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Transforms only titanium");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Doors blocked by a robot or another object ");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "You must get on the spaceship to take off ");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Nothing to analyze");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "Analyzes only organic matter");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analysis already performed");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "No energy in the subsoil");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Not yet enough energy");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "No uranium to transform");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Transforms only uranium");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "No titanium");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Object too close");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Place occupied");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "No information exchange post within range");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Program infected by a virus");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Infected by a virus, temporarily out of order");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "No power cell");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "No more energy");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Impossible when flying");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Impossible when swimming");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Impossible when moving");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Impossible when carrying an object");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Too many flags of this color (maximum 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Too close to an existing flag");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "No flag nearby");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "The mission is not accomplished yet (press \\key help; for more details)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Bot destroyed");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Building destroyed");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Can not create this, there are too many objects");
+ if ( num == ERR_OBLIGATORYTOKEN ) strcpy(text, "\"%s\" missing in this exercise"); //**
+ if ( num == ERR_PROHIBITEDTOKEN ) strcpy(text, "Do not use in this exercise"); //**
+
+ if ( num == INFO_BUILD ) strcpy(text, "Building completed");
+ if ( num == INFO_CONVERT ) strcpy(text, "Titanium available");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Research program completed");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Plans for tracked robots available ");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "You can fly with the keys (\\key gup;) and (\\key gdown;)");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Plans for thumper available");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Plans for shooter available");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Plans for defense tower available");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Plans for phazer shooter available");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Plans for shielder available");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Plans for nuclear power plant available");
+ if ( num == INFO_FACTORY ) strcpy(text, "New bot available");
+ if ( num == INFO_LABO ) strcpy(text, "Analysis performed");
+ if ( num == INFO_ENERGY ) strcpy(text, "Power cell available");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Nuclear power cell available");
+ if ( num == INFO_FINDING ) strcpy(text, "You found a usable object");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Found a site for power station");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Found a site for a derrick");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Well done, mission accomplished >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Sorry, mission failed >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Sorry, mission failed >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Current mission saved");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Checkpoint crossed");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Alien Queen killed");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Ant fatally wounded");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Wasp fatally wounded");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Worm fatally wounded");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Spider fatally wounded");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Press \\key help; to read instructions on your SatCom");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "Error");
+ if ( num == TX_OPENPAR ) strcpy(text, "Opening bracket missing");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Closing bracket missing ");
+ if ( num == TX_NOTBOOL ) strcpy(text, "The expression must return a boolean value");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Variable not declared");
+ if ( num == TX_BADLEFT ) strcpy(text, "Assignment impossible");
+ if ( num == TX_ENDOF ) strcpy(text, "Semicolon terminator missing");
+ if ( num == TX_OUTCASE ) strcpy(text, "Instruction ""case"" outside a block ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Instructions after the final closing brace");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "End of block missing");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Instruction ""else"" without corresponding ""if"" ");
+ if ( num == TX_OPENBLK ) strcpy(text, "Opening brace missing ");//début d'un bloc attendu?
+ if ( num == TX_BADTYPE ) strcpy(text, "Wrong type for the assignment");
+ if ( num == TX_REDEFVAR ) strcpy(text, "A variable can not be declared twice");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "The types of the two operands are incompatible ");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Unknown function");
+ if ( num == TX_MISDOTS ) strcpy(text, "Sign "" : "" missing");
+ if ( num == TX_WHILE ) strcpy(text, "Keyword ""while"" missing");
+ if ( num == TX_BREAK ) strcpy(text, "Instruction ""break"" outside a loop");
+ if ( num == TX_LABEL ) strcpy(text, "A label must be followed by ""for"", ""while"", ""do"" or ""switch""");
+ if ( num == TX_NOLABEL ) strcpy(text, "This label does not exist");// Cette étiquette n'existe pas
+ if ( num == TX_NOCASE ) strcpy(text, "Instruction ""case"" missing");
+ if ( num == TX_BADNUM ) strcpy(text, "Number missing");
+ if ( num == TX_VOID ) strcpy(text, "Void parameter");
+ if ( num == TX_NOTYP ) strcpy(text, "Type declaration missing");
+ if ( num == TX_NOVAR ) strcpy(text, "Variable name missing");
+ if ( num == TX_NOFONC ) strcpy(text, "Function name missing");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Too many parameters");
+ if ( num == TX_REDEF ) strcpy(text, "Function already exists");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Parameters missing ");
+ if ( num == TX_BADPARAM ) strcpy(text, "No function with this name accepts this kind of parameter");
+ if ( num == TX_NUMPARAM ) strcpy(text, "No function with this name accepts this number of parameters");
+ if ( num == TX_NOITEM ) strcpy(text, "This is not a member of this class");
+ if ( num == TX_DOT ) strcpy(text, "This object is not a member of a class");
+ if ( num == TX_NOCONST ) strcpy(text, "Appropriate constructor missing");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "This class already exists");
+ if ( num == TX_CLBRK ) strcpy(text, """ ] "" missing");
+ if ( num == TX_RESERVED ) strcpy(text, "Reserved keyword of CBOT language");
+ if ( num == TX_BADNEW ) strcpy(text, "Bad argument for ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, """ [ "" expected");
+ if ( num == TX_BADSTRING ) strcpy(text, "String missing");
+ if ( num == TX_BADINDEX ) strcpy(text, "Incorrect index type");
+ if ( num == TX_PRIVATE ) strcpy(text, "Private element");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Public required");
+ if ( num == TX_DIVZERO ) strcpy(text, "Dividing by zero");
+ if ( num == TX_NOTINIT ) strcpy(text, "Variable not initialized");
+ if ( num == TX_BADTHROW ) strcpy(text, "Negative value rejected by ""throw""");//C'est quoi, ça?
+ if ( num == TX_NORETVAL ) strcpy(text, "The function returned no value ");
+ if ( num == TX_NORUN ) strcpy(text, "No function running");
+ if ( num == TX_NOCALL ) strcpy(text, "Calling an unknown function");
+ if ( num == TX_NOCLASS ) strcpy(text, "This class does not exist");
+ if ( num == TX_NULLPT ) strcpy(text, "Unknown Object");
+ if ( num == TX_OPNAN ) strcpy(text, "Operation impossible with value ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Access beyond array limit");
+ if ( num == TX_STACKOVER ) strcpy(text, "Stack overflow");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Illegal object");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Can't open file");
+ if ( num == TX_NOTOPEN ) strcpy(text, "File not open");
+ if ( num == TX_ERRREAD ) strcpy(text, "Read error");
+ if ( num == TX_ERRWRITE ) strcpy(text, "Write error");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< none >");
+ if ( num == VK_LEFT ) strcpy(text, "Arrow left");
+ if ( num == VK_RIGHT ) strcpy(text, "Arrow right");
+ if ( num == VK_UP ) strcpy(text, "Arrow up");
+ if ( num == VK_DOWN ) strcpy(text, "Arrow down");
+ if ( num == VK_CANCEL ) strcpy(text, "Control-break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_RETURN ) strcpy(text, "Enter");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Space");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Select");
+ if ( num == VK_EXECUTE ) strcpy(text, "Execute");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Help");
+ if ( num == VK_LWIN ) strcpy(text, "Left Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Right Windows");
+ if ( num == VK_APPS ) strcpy(text, "Application key");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "NumPad 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "NumPad 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "NumPad 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "NumPad 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "NumPad 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "NumPad 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "NumPad 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "NumPad 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "NumPad 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "NumPad 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "NumPad *");
+ if ( num == VK_ADD ) strcpy(text, "NumPad +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "NumPad sep");
+ if ( num == VK_SUBTRACT ) strcpy(text, "NumPad -");
+ if ( num == VK_DECIMAL ) strcpy(text, "NumPad .");
+ if ( num == VK_DIVIDE ) strcpy(text, "NumPad /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Play");
+ if ( num == VK_ZOOM ) strcpy(text, "Zoom");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Button 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Button 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Button 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Button 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Button 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Button 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Button 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Button 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Button 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Button 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Button 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Button 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Button 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Button 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Button 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Button 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Button 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Button 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Button 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Button 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Button 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Button 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Button 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Button 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Button 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Button 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Button 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Button 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Button 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Button 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Button 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Button 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Wheel up");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Wheel down");
+ }
+#endif
+
+#if _FRENCH
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "1.18 /f");
+ #endif
+ #if _NET
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A 1.18");
+ #endif
+ #if _SCHOOL & _EDU
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen EDU 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A EDU 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _PERSO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen PERSO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A PERSO 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _CEEBOTDEMO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen DEMO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A DEMO 1.18");
+ #endif
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.18 /f");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Taille maximale");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Taille réduite");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Taille normale");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Fermer");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Edition du programme");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "Nouveau");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Joueur");
+ if ( num == RT_IO_NEW ) strcpy(text, "Nouveau ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " ou ");
+
+#if _NEWLOOK
+ if ( num == RT_TITLE_BASE ) strcpy(text, "CeeBot");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "CeeBot");
+#else
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+#endif
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Programmation");
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Défis");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Missions");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Jeu libre");
+ if ( num == RT_TITLE_TEEN ) strcpy(text, "Jeu libre");
+ if ( num == RT_TITLE_USER ) strcpy(text, "Niveaux supplémentaires");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypes");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Options");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Nom du joueur");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Personnalisation de votre apparence");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Enregistrement de la mission en cours");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Chargement d'une mission enregistrée");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Liste des chapitres :");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Liste des chapitres :");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Liste des planètes :");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Liste des planètes :");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " Niveaux supplémentaires :");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Liste des planètes :");
+ if ( num == RT_PLAY_CHAPte ) strcpy(text, " Liste des chapitres :");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Liste des exercices du chapitre :");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Liste des défis du chapitre :");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Liste des missions du chapitre :");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Liste des jeux libres du chapitre :");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Missions du niveau :");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Liste des prototypes du chapitre :");
+ if ( num == RT_PLAY_LISTk ) strcpy(text, " Liste des jeux libres du chapitre :");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Résumé :");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Pilotes :");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " Résolutions :");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) Cliquez d'abord sur la touche à redéfinir.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Appuyez ensuite sur la nouvelle touche souhaitée.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Type de visage :");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Lunettes :");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Couleur des cheveux :");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Couleur de la combinaison :");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Couleur des bandes :");
+
+#if _NEWLOOK
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "CeeBot");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Voulez-vous quitter CeeBot ?");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Quitter\\Quitter CeeBot");
+#else
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Voulez-vous quitter COLOBOT ?");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Quitter\\Quitter COLOBOT");
+#endif
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Quitter la mission ?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Abandonner\\Abandonner la mission en cours");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Continuer\\Continuer la mission en cours");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Continuer\\Continuer de jouer");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Voulez-vous vraiment détruire le bâtiment sélectionné ?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Voulez-vous détruire les sauvegardes de %s ?");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Détruire");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Annuler");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "CHARGEMENT");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Aide sur le mot-clé (\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Compilation ok (0 erreur)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Programme terminé");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;Listes des objets\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Listes des robots\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Listes des bâtiments\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Listes des objets transportables\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Listes des ennemis\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (aucun)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;Erreur\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "Liste non disponible sans \\l;radar\\u object\\radar; !\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Ouvrir");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Enregistrer");
+ if ( num == RT_IO_LIST ) strcpy(text, "Dossier: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Nom:");
+ if ( num == RT_IO_DIR ) strcpy(text, "Dans:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Privé\\Dossier privé");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Public\\Dossier commun à tous les joueurs");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Développé par :");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+#if _SCHOOL
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+#else
+ //?if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "Version française éditée par :");
+ //?if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.alsyd.com");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+#endif
+
+ if ( num == RT_INTERFACE_REC ) strcpy(text, "Enregistreur");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "D'accord");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Annuler");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Suivant");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Précédent");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menu (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "D'accord");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Annuler");
+
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Programmation\\Exercices de programmation");
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Défis\\Défis de programmation");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Missions\\La grande aventure");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Jeu libre\\Jeu libre sans but précis");
+ if ( num == EVENT_INTERFACE_TEEN ) strcpy(text, "Jeu libre\\Jeu libre sans but précis");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "Suppl.\\Niveaux supplémentaires");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Proto\\Prototypes en cours d'élaboration");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "Autre joueur\\Choix du nom du joueur");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Options\\Réglages");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Recommencer\\Recommencer la mission au début");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Enregistrer\\Enregistrer la mission en cours");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Charger\\Charger une mission enregistrée");
+#if _NEWLOOK
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Retourner dans CeeBot");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Quitter\\Quitter CeeBot");
+#else
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Retourner dans COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Quitter\\Quitter COLOBOT");
+#endif
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Retour \\Retour au niveau précédent");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Jouer ...\\Démarrer l'action");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Affichage\\Pilote et résolution d'affichage");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Graphique\\Options graphiques");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Jeu\\Options de jouabilité");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Commandes\\Touches du clavier");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "Son\\Volumes bruitages & musiques");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Unité");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "Résolution");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Plein écran\\Plein écran ou fenêtré");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Appliquer les changements\\Active les changements effectués");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robbie\\Votre assistant");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Ombres\\Ombres projetées au sol");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Marques sur le sol\\Marques dessinées sur le sol");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Salissures\\Salissures des robots et bâtiments");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Brouillard\\Nappes de brouillard");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Rayons du soleil\\Rayons selon l'orientation");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Ciel\\Ciel et nuages");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planètes et étoiles\\Motifs mobiles dans le ciel");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Lumières dynamiques\\Eclairages mobiles");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Quantité de particules\\Explosions, poussières, reflets, etc.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "Profondeur de champ\\Distance de vue maximale");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Détails des objets\\Qualité des objets en 3D");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Qualité des textures\\Qualité des images");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Nb d'objets décoratifs\\Qualité d'objets non indispensables");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Particules dans l'interface\\Pluie de particules");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Reflets sur les boutons\\Boutons brillants");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Bulles d'aide\\Bulles explicatives");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Séquences cinématiques\\Films avant ou après une mission");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Retour animé\\Retour animé dans les exercices");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Dégâts à soi-même\\Vos tirs infligent des dommages à vos unités");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Défilement dans les bords\\Défilement lorsque la souris touches les bords gauche ou droite");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Inversion souris X\\Inversion de la rotation lorsque la souris touche un bord");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Inversion souris Y\\Inversion de la rotation lorsque la souris touche un bord");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Secousses lors d'explosions\\L'écran vibre lors d'une explosion");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Souris ombrée\\Jolie souris avec une ombre");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Indentation automatique\\Pendant l'édition d'un programme");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Grande indentation\\Indente avec 2 ou 4 espaces");
+ if ( num == EVENT_INTERFACE_SOLUCE4) strcpy(text, "Accès aux solutions\\Programme \"4: Solution\" dans les exercices");
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Tout réinitialiser\\Remet toutes les touches standards");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Tourner à gauche\\Moteur à gauche");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Tourner à droite\\Moteur à droite");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Avancer\\Moteur en avant");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Reculer\\Moteur en arrière");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "Monter\\Augmenter la puissance du réacteur");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "Descendre\\Diminuer la puissance du réacteur");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Changement de caméra\\Autre de point de vue");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Sélection précédente\\Sélectionne l'objet précédent");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Action standard\\Action du bouton avec le cadre rouge");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Caméra plus proche\\Avance la caméra");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Caméra plus loin\\Recule la caméra");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Sélectionner l'objet suivant\\Sélectionner l'objet suivant");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Sélectionner le cosmonaute\\Sélectionner le cosmonaute");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Quitter la mission en cours\\Terminer un exercice ou une mssion");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Instructions mission\\Marche à suivre");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Instructions programmation\\Explication sur la programmation");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Instructions mot-clé\\Explication sur le mot-clé");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Montrer le lieu d'un message\\Montrer le lieu du dernier message");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Vitesse 1.0x\\Vitesse normale");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Vitesse 1.5x\\Une fois et demi plus rapide");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Vitesse 2.0x\\Deux fois plus rapide");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Vitesse 3.0x\\Trois fois plus rapide");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Bruitages :\\Volume des moteurs, voix, etc.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Fond sonore :\\Volume des pistes audio du CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "Bruitages 3D\\Positionnement sonore dans l'espace");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Mini\\Qualité minimale (+ rapide)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normal\\Qualité standard");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Maxi\\Haute qualité (+ lent)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Silencieux\\Totalement silencieux");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normal\\Niveaux normaux");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "Utilise un joystick\\Joystick ou clavier");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Accès à la solution\\Donne la solution");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\Nom du joueur à créer");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "D'accord\\Choisir le joueur");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Annuler\\Conserver le joueur actuel");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Supprimer le joueur\\Supprimer le joueur de la liste");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Nom du joueur");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Enregistrer\\Enregistrer la mission en cours");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Charger\\Charger la mission sélectionnée");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "Liste des missions enregistrées");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Nom du fichier :");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Nom de la mission");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Vue de la mission");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Supprimer\\Supprime l'enregistrement sélectionné");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Aspect\\Choisir votre aspect");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "D'accord");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Annuler");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standard\\Remet les couleurs standards");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "Tête\\Visage et cheveux");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Corps\\Combinaison");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Rotation à gauche");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Rotation à droite");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Rouge");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Vert");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Bleu");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Rouge");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Vert");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Bleu");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Visage 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Visage 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Visage 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Visage 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\Pas de lunettes");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Lunettes 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Lunettes 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Lunettes 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Lunettes 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Lunettes 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Sélection précédente (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Tourne à gauche (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Tourne à droite (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Avance (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Recule (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Monte (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Descend (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Prend ou dépose (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Prend ou dépose (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..devant");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..derrière");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..pile");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Instructions sur la mission (\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Décolle pour terminer la mission");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Construit un derrick");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Construit une station");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Construit une fabrique de robots");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Construit un centre de réparation");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Construit un convertisseur");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Construit une tour");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Construit un centre de recherches");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Construit un radar");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Construit une fabrique de piles");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Construit un laboratoire");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Construit une centrale nucléaire");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Construit un paratonnerre");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Construit une borne d'information");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Montre si le sol est plat");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Pose un drapeau de couleur");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Enlève un drapeau");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Drapeaux bleus");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Drapeaux rouges");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Drapeaux verts");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\Drapeaux jaunes");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Drapeaux violets");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Fabrique un déménageur volant");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Fabrique un déménageur à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Fabrique un déménageur à roues");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Fabrique un déménageur à pattes");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Fabrique un shooter volant");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Fabrique un shooter à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Fabrique un shooter à roues");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Fabrique un shooter à pattes");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Fabrique un orgaShooter volant");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Fabrique un orgaShooter à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Fabrique un orgaShooter à roues");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Fabrique un orgaShooter à pattes");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Fabrique un renifleur volant");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Fabrique un renifleur à chenilles");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Fabrique un renifleur à roues");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Fabrique un renifleur à pattes");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Fabrique un robot secoueur");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Fabrique un robot phazer");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Fabrique un robot recycleur");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Fabrique un robot bouclier");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Fabrique un robot sous-marin");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Recherche les chenilles");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Recherche les robots volants");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Recherche le secoueur");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Recherche le canon shooter");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Recherche la tour de défense");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Recherche le canon phazer");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Recherche le bouclier");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Recherche le nucléaire");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Recherche les pattes");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Recherche le canon orgaShooter");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Remet au départ");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Cherche (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Secoue (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Tir (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Recycle (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Déploie le bouclier (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Stoppe le bouclier (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Rayon du bouclier");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Exécute le programme sélectionné");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Edite le programme sélectionné");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\Mettre le SatCom en veille");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Démolit le bâtiment");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Niveau d'énergie");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Niveau du bouclier");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Température du réacteur");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Travail en cours ...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Nombre d'insectes détectés");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Informations diffusées");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Boussole");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Mini-carte");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Zoom mini-carte");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Caméra (\\key camera;)");
+ if ( num == EVENT_OBJECT_CAMERAleft) strcpy(text, "Caméra à gauche");
+ if ( num == EVENT_OBJECT_CAMERAright) strcpy(text, "Caméra à droite");
+ if ( num == EVENT_OBJECT_CAMERAnear) strcpy(text, "Caméra plus proche");
+ if ( num == EVENT_OBJECT_CAMERAaway) strcpy(text, "Caméra plus loin");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Instructions sur la sélection");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Donne la solution");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Permute robots <-> bâtiments");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Montre le rayon d'action");
+ if ( num == EVENT_OBJECT_PEN0 ) strcpy(text, "\\Relève le crayon");
+ if ( num == EVENT_OBJECT_PEN1 ) strcpy(text, "\\Abaisse le crayon noir");
+ if ( num == EVENT_OBJECT_PEN2 ) strcpy(text, "\\Abaisse le crayon jaune");
+ if ( num == EVENT_OBJECT_PEN3 ) strcpy(text, "\\Abaisse le crayon orange");
+ if ( num == EVENT_OBJECT_PEN4 ) strcpy(text, "\\Abaisse le crayon rouge");
+ if ( num == EVENT_OBJECT_PEN5 ) strcpy(text, "\\Abaisse le crayon violet");
+ if ( num == EVENT_OBJECT_PEN6 ) strcpy(text, "\\Abaisse le crayon bleu");
+ if ( num == EVENT_OBJECT_PEN7 ) strcpy(text, "\\Abaisse le crayon vert");
+ if ( num == EVENT_OBJECT_PEN8 ) strcpy(text, "\\Abaisse le crayon brun");
+ if ( num == EVENT_OBJECT_REC ) strcpy(text, "\\Démarre l'enregistrement");
+ if ( num == EVENT_OBJECT_STOP ) strcpy(text, "\\Stoppe l'enregistrement");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Montre l'endroit");
+ if ( num == EVENT_DT_END ) strcpy(text, "Continuer");
+ if ( num == EVENT_CMD ) strcpy(text, "Console de commande");
+ if ( num == EVENT_SPEED ) strcpy(text, "Vitesse du jeu");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Page précédente");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Page suivante");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Page initiale");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Copier");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "Taille 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "Taille 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "Taille 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "Taille 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "Taille 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Instructions de Houston");
+#if _TEEN
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Dictionnaire anglais-français");
+#else
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Rapport du satellite");
+#endif
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Programmes envoyés par Houston");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "Liste des objets");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Aide à la programmation");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Solution");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "D'accord\\Compiler le programme");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Annuler\\Annuler toutes les modifications");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "Nouveau");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Ouvrir (Ctrl+o)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Enregistrer (Ctrl+s)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Annuler (Ctrl+z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Couper (Ctrl+x)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Copier (Ctrl+c)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Coller (Ctrl+v)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "Taille des caractères");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Instructions (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Aide à la programmation (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Compiler");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Démarrer/stopper");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pause/continuer");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "Un pas");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "Portique");
+ if ( num == OBJECT_BASE ) strcpy(text, "Vaisseau spatial");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Derrick");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Fabrique de robots");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Centre de réparation");
+ if ( num == OBJECT_DESTROYER ) strcpy(text, "Destructeur");
+ if ( num == OBJECT_STATION ) strcpy(text, "Station de recharge");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Conversion minerai en titanium");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Tour de défense");
+ if ( num == OBJECT_NEST ) strcpy(text, "Nid");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Centre de recherches");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Radar");
+ if ( num == OBJECT_INFO ) strcpy(text, "Borne d'information");
+#if _TEEN
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Désintégrateur");
+#else
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Fabrique de piles");
+#endif
+ if ( num == OBJECT_LABO ) strcpy(text, "Laboratoire de matières organiques");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Centrale nucléaire");
+ if ( num == OBJECT_PARA ) strcpy(text, "Paratonnerre");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Coffre-fort");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Centre de contrôle");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Cible");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Cible");
+ if ( num == OBJECT_START ) strcpy(text, "Départ");
+ if ( num == OBJECT_END ) strcpy(text, "But");
+ if ( num == OBJECT_STONE ) strcpy(text, "Minerai de titanium");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Minerai d'uranium");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Matière organique");
+ if ( num == OBJECT_METAL ) strcpy(text, "Titanium");
+ if ( num == OBJECT_POWER ) strcpy(text, "Pile normale");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Pile nucléaire");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Boîte noire");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Clé A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Clé B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Clé C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Clé D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Explosif");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Mine fixe");
+ if ( num == OBJECT_BAG ) strcpy(text, "Sac de survie");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Indicateur");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Drapeau bleu");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Drapeau rouge");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Drapeau vert");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "Drapeau jaune");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Drapeau violet");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "Emplacement pour station");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Emplacement pour derrick (uranium)");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Emplacement pour derrick (clé A)");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Emplacement pour derrick (clé B)");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Emplacement pour derrick (clé C)");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Emplacement pour derrick (clé D)");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Emplacement pour derrick (titanium)");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Robot d'entraînement");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Robot déménageur");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Robot shooter");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "Robot orgaShooter");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Robot renifleur");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Robot secoueur");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Robot phazer");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Robot recycleur");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Robot bouclier");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Robot sous-marin");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Cible d'entraînement");
+ if ( num == OBJECT_MOBILEdr ) strcpy(text, "Robot dessinateur");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "Technicien");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robbie");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Pondeuse");
+ if ( num == OBJECT_ANT ) strcpy(text, "Fourmi");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Araignée");
+ if ( num == OBJECT_BEE ) strcpy(text, "Guêpe");
+ if ( num == OBJECT_WORM ) strcpy(text, "Ver");
+ if ( num == OBJECT_EGG ) strcpy(text, "Oeuf");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Epave de robot");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Déchet");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Bâtiment en ruine");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Epave de vaisseau spatial");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Epave de vaisseau spatial");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Vestige d'une mission Apollo");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Lunar Roving Vehicle");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "Erreur");
+ if ( num == ERR_CMD ) strcpy(text, "Commande inconnue");
+#if _NEWLOOK
+ if ( num == ERR_INSTALL ) strcpy(text, "CeeBot n'est pas installé.");
+ if ( num == ERR_NOCD ) strcpy(text, "Veuillez mettre le CD de CeeBot\net relancer le jeu.");
+#else
+ if ( num == ERR_INSTALL ) strcpy(text, "COLOBOT n'est pas installé.");
+ if ( num == ERR_NOCD ) strcpy(text, "Veuillez mettre le CD de COLOBOT\net relancer le jeu.");
+#endif
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Porte déjà quelque chose");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Rien à prendre");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Emplacement occupé");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "Pas d'autre robot");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "Vous ne pouvez pas transporter un objet radioactif");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "Vous ne pouvez pas transporter un objet sous l'eau");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Rien à déposer");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Impossible sous l'eau");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Titanium trop loin");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Titanium trop proche");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "Titanium inexistant");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Sol pas assez plat");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Sol plat pas assez grand");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Emplacement occupé");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Trop proche du vaisseau spatial");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Trop proche d'un bâtiment");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Terrain inadapté");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Bâtiment trop proche");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Objet trop proche");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Rien à recycler");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "Plus d'énergie");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "Déplacement impossible");
+ if ( num == ERR_FIND_IMPOSSIBLE ) strcpy(text, "Objet n'existe pas");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Chemin introuvable");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Position inaccessible");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Destination occupée");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Robot inadapté");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Pas assez d'énergie");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "Pas de minerai de titanium à convertir");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "Pas de minerai en sous-sol");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "Pas d'énergie en sous-sol");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "Pas de pile");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "Plus d'énergie");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "Pas de pile");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Plus assez d'énergie");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Pas le bon type de pile");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Recherche déjà effectuée");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "Pas d'énergie en sous-sol");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Pas encore assez d'énergie");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "Pas de titanium à transformer");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Ne transforme que le titanium");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Portes bloquées par un robot ou un objet");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "Vous devez embarquer pour pouvoir décoller");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Rien à analyser");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "N'analyse que la matière organique");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analyse déjà effectuée");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "Pas d'énergie en sous-sol");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Pas encore assez d'énergie");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "Pas d'uranium à transformer");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Ne transforme que l'uranium");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "Pas de titanium");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Quelque chose est trop proche");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Emplacement occupé");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "Pas trouvé de borne d'information");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Un programme est infecté par un virus");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Infecté par un virus, ne fonctionne plus temporairement");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "Pas de pile");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "Plus d'énergie");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Impossible en vol");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Impossible en nageant");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Impossible en mouvement");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Impossible en portant un objet");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Trop de drapeaux de cette couleur (maximum 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Trop proche d'un drapeau existant");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "Aucun drapeau à proximité");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "La misssion n'est pas terminée (appuyez sur \\key help; pour plus de détails)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Robot détruit");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Bâtiment détruit");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Création impossible, il y a trop d'objets");
+ if ( num == ERR_OBLIGATORYTOKEN ) strcpy(text, "Il manque \"%s\" dans le programme");
+ if ( num == ERR_PROHIBITEDTOKEN ) strcpy(text, "Interdit dans cet exercice");
+
+ if ( num == INFO_BUILD ) strcpy(text, "Bâtiment terminé");
+ if ( num == INFO_CONVERT ) strcpy(text, "Titanium disponible");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Recherche terminée");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Fabrication d'un robot à chenilles possible");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "Il est possible de voler avec les touches (\\key gup;) et (\\key gdown;)");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Fabrication d'un robot secoueur possible");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Fabrication de robots shooter possible");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Construction d'une tour de défense possible");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Fabrication d'un robot phazer possible");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Fabrication d'un robot bouclier possible");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Construction d'une centrale nucléaire possible");
+ if ( num == INFO_FACTORY ) strcpy(text, "Nouveau robot disponible");
+ if ( num == INFO_LABO ) strcpy(text, "Analyse terminée");
+ if ( num == INFO_ENERGY ) strcpy(text, "Pile disponible");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Pile nucléaire disponible");
+ if ( num == INFO_FINDING ) strcpy(text, "Vous avez trouvé un objet utilisable");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Emplacement pour station trouvé");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Emplacement pour derrick trouvé");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Bravo, mission terminée >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Désolé, mission échouée >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Désolé, mission échouée >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Enregistrement effectué");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Indicateur atteint");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Pondeuse mortellement touchée");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Fourmi mortellement touchée");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Guêpe mortellement touchée");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Ver mortellement touché");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Araignée mortellement touchée");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Consultez votre SatCom en appuyant sur \\key help;");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "Erreur");
+ if ( num == TX_OPENPAR ) strcpy(text, "Il manque une parenthèse ouvrante");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Il manque une parenthèse fermante");
+ if ( num == TX_NOTBOOL ) strcpy(text, "L'expression doit être un boolean");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Variable non déclarée");
+ if ( num == TX_BADLEFT ) strcpy(text, "Assignation impossible");
+ if ( num == TX_ENDOF ) strcpy(text, "Terminateur point-virgule non trouvé");
+ if ( num == TX_OUTCASE ) strcpy(text, "Instruction ""case"" hors d'un bloc ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Instructions après la fin");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "Il manque la fin du bloc");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Instruction ""else"" sans ""if"" correspondant");
+ if ( num == TX_OPENBLK ) strcpy(text, "Début d'un bloc attendu");
+ if ( num == TX_BADTYPE ) strcpy(text, "Mauvais type de résultat pour l'assignation");
+ if ( num == TX_REDEFVAR ) strcpy(text, "Redéfinition d'une variable");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "Les deux opérandes ne sont pas de types compatibles");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Routine inconnue");
+ if ( num == TX_MISDOTS ) strcpy(text, "Séparateur "" : "" attendu");
+ if ( num == TX_WHILE ) strcpy(text, "Manque le mot ""while""");
+ if ( num == TX_BREAK ) strcpy(text, "Instruction ""break"" en dehors d'une boucle");
+ if ( num == TX_LABEL ) strcpy(text, "Un label ne peut se placer que devant un ""for"", un ""while"", un ""do"" ou un ""switch""");
+ if ( num == TX_NOLABEL ) strcpy(text, "Cette étiquette n'existe pas");
+ if ( num == TX_NOCASE ) strcpy(text, "Manque une instruction ""case""");
+ if ( num == TX_BADNUM ) strcpy(text, "Un nombre est attendu");
+ if ( num == TX_VOID ) strcpy(text, "Paramètre void");
+ if ( num == TX_NOTYP ) strcpy(text, "Déclaration de type attendu");
+ if ( num == TX_NOVAR ) strcpy(text, "Nom d'une variable attendu");
+ if ( num == TX_NOFONC ) strcpy(text, "Nom de la fonction attendu");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Trop de paramètres");
+ if ( num == TX_REDEF ) strcpy(text, "Cette fonction existe déjà");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Pas assez de paramètres");
+ if ( num == TX_BADPARAM ) strcpy(text, "Aucune fonction de ce nom n'accepte ce(s) type(s) de paramètre(s)");
+ if ( num == TX_NUMPARAM ) strcpy(text, "Aucune fonction de ce nom n'accepte ce nombre de paramètres");
+ if ( num == TX_NOITEM ) strcpy(text, "Cet élément n'existe pas dans cette classe");
+ if ( num == TX_DOT ) strcpy(text, "L'objet n'est pas une instance d'une classe");
+ if ( num == TX_NOCONST ) strcpy(text, "Il n'y a pas de constructeur approprié");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "Cette classe existe déjà");
+ if ( num == TX_CLBRK ) strcpy(text, """ ] "" attendu");
+ if ( num == TX_RESERVED ) strcpy(text, "Ce mot est réservé");
+ if ( num == TX_BADNEW ) strcpy(text, "Mauvais argument pour ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, """ [ "" attendu");
+ if ( num == TX_BADSTRING ) strcpy(text, "Une chaîne de caractère est attendue");
+ if ( num == TX_BADINDEX ) strcpy(text, "Mauvais type d'index");
+ if ( num == TX_PRIVATE ) strcpy(text, "Elément protégé");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Public requis");
+ if ( num == TX_DIVZERO ) strcpy(text, "Division par zéro");
+ if ( num == TX_NOTINIT ) strcpy(text, "Variable non initialisée");
+ if ( num == TX_BADTHROW ) strcpy(text, "Valeur négative refusée pour ""throw""");
+ if ( num == TX_NORETVAL ) strcpy(text, "La fonction n'a pas retourné de résultat");
+ if ( num == TX_NORUN ) strcpy(text, "Pas de fonction en exécution");
+ if ( num == TX_NOCALL ) strcpy(text, "Appel d'une fonction inexistante");
+ if ( num == TX_NOCLASS ) strcpy(text, "Cette classe n'existe pas");
+ if ( num == TX_NULLPT ) strcpy(text, "Objet n'existe pas");
+ if ( num == TX_OPNAN ) strcpy(text, "Opération sur un ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Accès hors du tableau");
+ if ( num == TX_STACKOVER ) strcpy(text, "Débordement de la pile");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Objet inaccessible");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Ouverture du fichier impossible");
+ if ( num == TX_NOTOPEN ) strcpy(text, "Le fichier n'est pas ouvert");
+ if ( num == TX_ERRREAD ) strcpy(text, "Erreur à la lecture");
+ if ( num == TX_ERRWRITE ) strcpy(text, "Erreur à l'écriture");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< aucune >");
+ if ( num == VK_LEFT ) strcpy(text, "Flèche Gauche");
+ if ( num == VK_RIGHT ) strcpy(text, "Flèche Droite");
+ if ( num == VK_UP ) strcpy(text, "Flèche Haut");
+ if ( num == VK_DOWN ) strcpy(text, "Flèche Bas");
+ if ( num == VK_CANCEL ) strcpy(text, "Control-break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_RETURN ) strcpy(text, "Entrée");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Espace");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Select");
+ if ( num == VK_EXECUTE ) strcpy(text, "Execute");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Help");
+ if ( num == VK_LWIN ) strcpy(text, "Left Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Right Windows");
+ if ( num == VK_APPS ) strcpy(text, "Application key");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "NumPad 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "NumPad 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "NumPad 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "NumPad 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "NumPad 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "NumPad 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "NumPad 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "NumPad 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "NumPad 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "NumPad 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "NumPad *");
+ if ( num == VK_ADD ) strcpy(text, "NumPad +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "NumPad sep");
+ if ( num == VK_SUBTRACT ) strcpy(text, "NumPad -");
+ if ( num == VK_DECIMAL ) strcpy(text, "NumPad .");
+ if ( num == VK_DIVIDE ) strcpy(text, "NumPad /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Play");
+ if ( num == VK_ZOOM ) strcpy(text, "Zoom");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Bouton 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Bouton 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Bouton 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Bouton 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Bouton 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Bouton 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Bouton 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Bouton 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Bouton 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Bouton 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Bouton 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Bouton 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Bouton 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Bouton 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Bouton 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Bouton 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Bouton 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Bouton 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Bouton 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Bouton 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Bouton 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Bouton 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Bouton 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Bouton 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Bouton 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Bouton 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Bouton 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Bouton 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Bouton 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Bouton 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Bouton 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Bouton 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Molette haut");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Molette bas");
+ }
+#endif
+
+#if _GERMAN | _WG
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "1.18 /d");
+ #endif
+ #if _NET
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A 1.18");
+ #endif
+ #if _SCHOOL & _EDU
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen EDU 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A EDU 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _PERSO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen PERSO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A PERSO 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _CEEBOTDEMO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen DEMO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A DEMO 1.18");
+ #endif
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.18 /d");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Großes Fenster");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Reduzieren");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Normale Größe");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Schließen");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Programmeditor");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "Neu");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Spieler");
+ if ( num == RT_IO_NEW ) strcpy(text, "Neu ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " oder ");
+
+#if _NEWLOOK
+ if ( num == RT_TITLE_BASE ) strcpy(text, "CeeBot");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "CeeBot");
+#else
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+#endif
+#if _SCHOOL
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Übungen");
+#else
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Programmieren");
+#endif
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Challenges");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Missionen");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Freestyle");
+ if ( num == RT_TITLE_TEEN ) strcpy(text, "Freestyle");
+ if ( num == RT_TITLE_USER ) strcpy(text, "Userlevels");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypen");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Einstellungen");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Name ");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Aussehen einstellen");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Aktuelle Mission speichern");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Gespeicherte Mission laden");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Liste der Kapitel:");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Liste der Kapitel:");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Liste der Planeten:");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Liste der Planeten:");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " Userlevels:");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Liste der Planeten:");
+ if ( num == RT_PLAY_CHAPte ) strcpy(text, " Liste der Kapitel:");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Liste der Übungen des Kapitels:");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Liste der Challenges des Kapitels:");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Liste der Missionen des Planeten:");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Liste der freien Levels des Planeten:");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Missionen des Userlevels:");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Liste der Prototypen des Planeten:");
+ if ( num == RT_PLAY_LISTk ) strcpy(text, " Liste der freien Levels des Kapitel:");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Zusammenfassung:");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Driver:");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " Auflösung:");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) Klicken Sie auf die neu zu definierende Taste.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Drücken Sie auf die neue Taste.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Kopf:");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Brille:");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Haarfarbe:");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Farbe des Anzugs:");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Farbe der Streifen:");
+
+#if _NEWLOOK
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "CeeBot");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Wollen Sie CeeBot schließen ?");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Schließen\\CeeBot schließen");
+#else
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Wollen Sie COLOBOT schließen ?");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Schließen\\COLOBOT schließen");
+#endif
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Mission abbrechen ?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Abbrechen\\Mission abbrechen");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Weitermachen\\Mission weitermachen");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Weitermachen\\Weitermachen");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Wollen Sie das angewählte Gebäude wirklich zerstören ?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Wollen Sie die gespeicherten Missionen von %s löschen ?");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Zerstören");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Abbrechen");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "Laden");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Hilfe über den Begriff (\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Kompilieren OK (0 Fehler)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Programm beendet");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;Liste der Objekte\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Liste der Roboter\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Listes der Gebäude\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Listes der tragbaren Gegenstände\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Listes der Feinde\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (keine)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;Fehler\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "Die Liste ist ohne \\l;Radar\\u object\\radar; nicht verfügbar !\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Öffnen");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Speichern");
+ if ( num == RT_IO_LIST ) strcpy(text, "Ordner: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Name:");
+ if ( num == RT_IO_DIR ) strcpy(text, "In:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Privat\\Privater Ordner");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Öffentlich\\Gemeinsamer Ordner für alle Spieler");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Entwickelt von:");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+#if _WG
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "Herausgegeben von:");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.wg-verlag.ch");
+#else
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+#endif
+
+ if ( num == RT_INTERFACE_REC ) strcpy(text, "Recorder");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "OK");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Abbrechen");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Nächster");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Vorherg.");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menü (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "OK");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Abbrechen");
+
+#if _SCHOOL
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Übungen\\Programmierübungen");
+#else
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Programmieren\\Programmierübungen");
+#endif
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Challenges\\Herausforderungen");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Missionen\\Aufbruch ins Weltall");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Freestyle\\Freies Spielen ohne vorgegebenes Ziel");
+ if ( num == EVENT_INTERFACE_TEEN ) strcpy(text, "Freestyle\\Freies Spielen ohne vorgegebenes Ziel");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "User\\Userlevels");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Proto\\In Entwicklung befindliche Prototypen");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "Anderer Spieler\\Spielername ändern");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Einstellungen\\Einstellungen");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Neu anfangen\\Die Mission von vorne anfangen");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Speichern\\Aktuelle Mission speichern");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Laden\\Eine gespeicherte Mission öffnen");
+#if _NEWLOOK
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Zurück zu CeeBot");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Schließen\\CeeBot schließen");
+#else
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Zurück zu COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Schließen\\COLOBOT schließen");
+#endif
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Zurück \\Zurück zum Hauptmenü");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Spielen ...\\Los geht's");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Bildschirm\\Driver und Bildschirmauflösung");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Grafik\\Grafische Einstellungen");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Spiel\\Gameplay Einstellungen");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Steuerung\\Auswahl der Tasten");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "Geräusche\\Lautstärke Geräusche und Musik");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Einheit");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "Auflösung");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Vollbildschirm\\Vollbildschirm oder Fenster");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Änderungen ausführen\\Getätigte Einstellungen ausführen");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robby\\Ihr Assistent");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Schatten\\Schlagschatten auf dem Boden");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Markierungen\\Markierungen auf dem Boden");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Schmutz\\Schmutz auf Robotern und Bauten");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Nebel\\Nebelschwaden");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Sonnenstrahlen\\Sonnenstrahlen");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Himmel\\Himmel und Wolken");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planeten und Sterne\\Kreisende Planeten und Sterne");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Dynamische Beleuchtung\\Dynamische Beleuchtung");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Anzahl Partikel\\Explosionen, Staub, usw.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "Sichtweite\\Maximale Sichtweite");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Details\\Detailliertheit der Objekte in 3D");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Qualität der Texturen\\Qualität der Anzeige");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Anzahl Ziergegenstände\\Anzahl Gegenstände ohne Funktion");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Partikel in den Menüs\\Funken und Sterne in den Menüs");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Glänzende Tasten\\Glänzende Tasten in den Menüs");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Hilfsblasen\\Hilfsblasen");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Filme\\Filme vor und nach den Missionen");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Zurücksetzen \\Kleine Show beim Zurücksetzen in den Übungen");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Eigenbeschuss\\Ihre Einheiten werden von Ihren Waffen beschädigt.");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Kameradrehung mit der Maus\\Die Kamera dreht wenn die Maus den Rand erreicht");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Umkehr X\\Umkehr der Kameradrehung X-Achse");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Umkehr Y\\Umkehr der Kameradrehung Y-Achse");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Beben bei Explosionen\\Die Kamera bebt bei Explosionen");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Schatten unter der Maus\\Ein Schatten erscheint unter der Maus");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Automatisches Einrücken\\Beim Bearbeiten der Programme");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Einrücken mit 4 Leerstellen\\Einrücken mit 2 oder 4 Leerstellen");
+ if ( num == EVENT_INTERFACE_SOLUCE4) strcpy(text, "Lösung zugänglich\\Die Lösung ist im Programmslot \"4: Lösung\" zugänglich");
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Alles zurücksetzen\\Standarddefinition aller Tasten");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Drehung nach links\\Steuer links");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Drehung nach rechts\\Steuer rechts");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Vorwärts\\Bewegung nach vorne");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Rückwärts\\Bewegung nach hinten");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "Steigen\\Leistung des Triebwerks steigern");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "Sinken\\Leistung des Triebwerks drosseln");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Andere Kamera\\Sichtpunkt einstellen");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Vorherg. Auswahl\\Das vorhergehende Objekt auswählen");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Standardhandlung\\Führt die Standardhandlung des Roboters aus.");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Kamera näher\\Bewegung der Kamera vorwärts");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Kamera weiter\\Bewegung der Kamera rückwärts");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Nächstes auswählen\\Nächstes Objekt auswählen");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Astronauten auswählen\\Astronauten auswählen");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Mission verlassen\\Eine Mission oder Übung verlassen");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Anweisungen\\Anweisungen für die Mission oder Übung");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Hilfe CBOT-Sprache\\Hilfe über die Programmiersprache CBOT");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Hilfe über Begriff\\Hilfe über einen Begriff");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Ort der Meldung\\Zeigt den Ort, von dem die letzte Meldung stammt");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Geschwindigkeit 1.0x\\Normale Spielgeschwindigkeit");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Geschwindigkeit 1.5x\\Spielgeschwindigkeit anderthalb Mal schneller");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Geschwindigkeit 2.0x\\Spielgeschwindigkeit doppelt so schnell");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Geschwindigkeit 3.0x\\Spielgeschwindigkeit drei Mal schneller");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Geräusche:\\Lautstärke Motoren, Stimmen, usw.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Geräuschkulisse:\\Lautstärke der Soundtracks der CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "3D-Geräusche\\Orten der Geräusche im Raum");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Min.\\Minimale Qualität (großes Framerate)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normal\\Standardqualität");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Max.\\Beste Qualität (niedriges Framerate)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Kein Ton\\Keine Geräusche und Geräuschkulisse");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normal\\Normale Lautstärke");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "Joystick\\Joystick oder Tastatur");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Zeigt die Lösung\\Zeigt nach 3mal Scheitern die Lösung");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\Name des Spielers");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "OK\\Spieler auswählen");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Abbrechen\\Behält den bisherigen Spieler bei");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Spieler löschen\\Löscht den Spieler aus der Liste");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Name ");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Speichern\\Speichert die Mission");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Laden\\Öffnet eine gespeicherte Mission");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "Liste der gespeicherten Missionen");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Dateiname:");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Name der Mission");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Ansicht der Mission");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Löschen\\Löscht die gespeicherte Mission");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Aussehen\\Erscheinungsbild des Astronauten einstellen");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "OK");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Abbrechen");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standard\\Standardfarben einsetzen");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "Kopf\\Gesicht und Haare");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Anzug\\Raumfahrtanzug");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Drehung links");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Drehung rechts");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Rot");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Grün");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Blau");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Rot");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Grün");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Blau");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Kopf 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Kopf 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Kopf 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Kopf 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\Keine Brille");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Brille 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Brille 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Brille 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Brille 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Brille 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Vorherg. Auwahl (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Drehung links (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Drehung rechts (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Vorwärts (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Rückwärts (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Steigt (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Sinkt (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Nehmen oder hinlegen (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Nehmen oder hinlegen (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..vorne");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..hinten");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..Batterie");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Anweisungen über die Mission(\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Abheben nach vollbrachter Mission");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Baut einen Bohrturm");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Baut ein Kraftwerk");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Baut eine Roboterfabrik");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Baut ein Reparaturzentrum");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Baut einen Konverter");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Baut einen Geschützturm");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Baut ein Forschungszentrum");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Baut ein Radar");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Baut eine Batteriefabrik");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Baut ein automatisches Labor");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Baut eine Brennstoffzellenfabrik");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Baut einen Blitzableiter");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Baut einen Infoserver");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Zeigt ob der Boden eben ist");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Setzt eine Fahne");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Sammelt die Fahne ein");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Blaue Fahne");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Rote Fahne");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Grüne Fahne");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\Gelbe Fahne");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Violette Fahne");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Baut einen Jettransporter");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Baut einen Kettentransporter");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Baut einen Radtransporter");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Baut einen Krabbeltransporter");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Baut einen Jetshooter");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Baut einen Kettenshooter");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Baut einen Radshooter");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Baut einen Krabbelshooter");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Baut einen Jetorgashooter");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Baut einen Kettenorgashooter");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Baut einen Radorgashooter");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Baut einen Krabbelorgashooter");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Baut einen Jetschnüffler");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Baut einen Kettenschnüffler");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Baut einen Radschnüffler");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Baut einen Krabbelschnüffler");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Baut einen Stampfer");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Baut einen Phazershooter");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Baut einen Recycler");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Baut einen Schutzschild");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Baut einen Kettentaucher");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Forschungsprogramm Kettenantrieb");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Forschungsprogramm Jetantrieb");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Forschungsprogramm Stampfer");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Forschungsprogramm Shooterkanone");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Forschungsprogramm Geschützturm");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Forschungsprogramm Phazerkanone");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Forschungsprogramm Schutzschild");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Forschungsprogramm Brennstoffzelle");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Forschungsprogramm Krabbelantrieb");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Forschungsprogramm Orgashooterkanone");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Alles zurücksetzen");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Schnüffeln (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Stampfen (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Feuer (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Recyceln (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Schutzschild ausfahren (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Schutzschild einholen (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Reichweite Schutzschild");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Gewähltes Programm ausführen");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Gewähltes Programm bearbeiten");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\SatCom in Standby");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Gebäude sprengen");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Energievorrat");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Schäden");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Triebwerktemperatur");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Prozess im Gang ...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Anzahl erfasster Insekten");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Gesendete Informationen");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Kompass");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Minikarte");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Zoom Minikarte");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Kamera (\\key camera;)");
+ if ( num == EVENT_OBJECT_CAMERAleft) strcpy(text, "Kamera links");
+ if ( num == EVENT_OBJECT_CAMERAright) strcpy(text, "Kamera rechts");
+ if ( num == EVENT_OBJECT_CAMERAnear) strcpy(text, "Kamera näher");
+ if ( num == EVENT_OBJECT_CAMERAaway) strcpy(text, "Kamera weiter weg");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Anweisungen über das ausgewählte Objekt");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Zeigt die Lösung");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Anzeige Roboter <-> Bauten");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Zeigt die Reichweite");
+ if ( num == EVENT_OBJECT_PEN0 ) strcpy(text, "\\Bleistift abheben");
+ if ( num == EVENT_OBJECT_PEN1 ) strcpy(text, "\\Schwarzen Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN2 ) strcpy(text, "\\Gelben Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN3 ) strcpy(text, "\\Orangefarbenen Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN4 ) strcpy(text, "\\Roten Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN5 ) strcpy(text, "\\Violetten Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN6 ) strcpy(text, "\\Blauen Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN7 ) strcpy(text, "\\Grünen Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_PEN8 ) strcpy(text, "\\Braunen Bleistift hinunterlassen");
+ if ( num == EVENT_OBJECT_REC ) strcpy(text, "\\Aufnahme starten");
+ if ( num == EVENT_OBJECT_STOP ) strcpy(text, "\\Aufnahme stoppen");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Zeigt den Ort");
+ if ( num == EVENT_DT_END ) strcpy(text, "Weitermachen");
+ if ( num == EVENT_CMD ) strcpy(text, "Befehleingabe");
+ if ( num == EVENT_SPEED ) strcpy(text, "Spielgeschwindigkeit");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Vorherg. Seite");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Nächste Seite");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Home");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Kopieren");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "Größe 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "Größe 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "Größe 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "Größe 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "Größe 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Anweisungen von Houston");
+#if _TEEN
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Wörterbuch Englisch-Deutsch");
+#else
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Satellitenbericht");
+#endif
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Von Houston übermittelte Programme");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "Liste der Objekte");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Hilfe über Programmieren");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Lösung");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "OK\\Programm kompilieren");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Abbrechen\\Editor schließen");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "Neu");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Öffnen (Ctrl+o)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Speichern (Ctrl+s)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Widerrufen (Ctrl+z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Ausschneiden (Ctrl+x)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Kopieren (Ctrl+c)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Einfügen (Ctrl+v)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "Zeichengröße");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Anweisungen (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Hilfe über Programmieren (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Kompilieren");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Start/Stop");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pause/Weitermachen");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "Ein Schritt");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "Träger");
+ if ( num == OBJECT_BASE ) strcpy(text, "Raumschiff");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Bohrturm");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Roboterfabrik");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Reparaturzentrum");
+ if ( num == OBJECT_DESTROYER ) strcpy(text, "Einstampfer");
+ if ( num == OBJECT_STATION ) strcpy(text, "Kraftwerk");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Konverter Erz-Titan");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Geschützturm");
+ if ( num == OBJECT_NEST ) strcpy(text, "Orgastoffquelle");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Forschungszentrum");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Radar");
+ if ( num == OBJECT_INFO ) strcpy(text, "Infoserver");
+#if _TEEN
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Auflöser");
+#else
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Batteriefabrik");
+#endif
+ if ( num == OBJECT_LABO ) strcpy(text, "Automatisches Labor");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Brennstoffzellenfabrik");
+ if ( num == OBJECT_PARA ) strcpy(text, "Blitzableiter");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Bunker");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Kontrollzentrum");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Zielscheibe");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Zielscheibe");
+ if ( num == OBJECT_START ) strcpy(text, "Startfläche");
+ if ( num == OBJECT_END ) strcpy(text, "Zielfläche");
+ if ( num == OBJECT_STONE ) strcpy(text, "Titanerz");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Platinerz");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Orgastoff");
+ if ( num == OBJECT_METAL ) strcpy(text, "Titan");
+ if ( num == OBJECT_POWER ) strcpy(text, "Elektrolytische Batterie");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Brennstoffzelle");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Flugschreiber");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Schlüssel A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Schlüssel B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Schlüssel C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Schlüssel D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Sprengstoff");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Landmine");
+ if ( num == OBJECT_BAG ) strcpy(text, "Überlebenskit");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Checkpoint");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Blaue Fahne");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Rote Fahne");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Grüne Fahne");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "Gelbe Fahne");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Violette Fahne");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "Markierung für unterirdische Energiequelle");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Markierung für unterirdisches Platinvorkommen");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Markierung für vergrabenen Schlüssel A");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Markierung für vergrabenen Schlüssel B");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Markierung für vergrabenen Schlüssel C");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Markierung für vergrabenen Schlüssel D");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Markierung für unterirdisches Titanvorkommen");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Übungsroboter");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Übungsroboter");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Übungsroboter");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Übungsroboter");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Transporter");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Transporter");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Transporter");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Transporter");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Shooter");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Shooter");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Shooter");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Shooter");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "OrgaShooter");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "OrgaShooter");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "OrgaShooter");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "OrgaShooter");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Schnüffler");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Schnüffler");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Schnüffler");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Schnüffler");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Stampfer");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Phazershooter");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Recycler");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Schutzschild");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Kettentaucher");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Mobile Zielscheibe");
+ if ( num == OBJECT_MOBILEdr ) strcpy(text, "Zeichner");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "Techniker");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robby");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Insektenkönigin");
+ if ( num == OBJECT_ANT ) strcpy(text, "Ameise");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Spinne");
+ if ( num == OBJECT_BEE ) strcpy(text, "Wespe");
+ if ( num == OBJECT_WORM ) strcpy(text, "Wurm");
+ if ( num == OBJECT_EGG ) strcpy(text, "Ei");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Roboterwrack");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Roboterwrack");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Roboterwrack");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Roboterwrack");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Roboterwrack");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Roboterwrack");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Gebäuderuine");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Gebäuderuine");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Abfall");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Gebäuderuine");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Gebäuderuine");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Raumschiffruine");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Raumschiffruine");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Überreste einer Apollo-Mission");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Lunar Roving Vehicle");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "Fehler");
+ if ( num == ERR_CMD ) strcpy(text, "Befehl unbekannt");
+#if _NEWLOOK
+ if ( num == ERR_INSTALL ) strcpy(text, "CeeBot wurde nicht installiert.");
+ if ( num == ERR_NOCD ) strcpy(text, "Legen Sie die CeeBot-CD ein\nund starten Sie das Spiel neu.");
+#else
+ if ( num == ERR_INSTALL ) strcpy(text, "COLOBOT wurde nicht installiert.");
+ if ( num == ERR_NOCD ) strcpy(text, "Legen Sie die COLOBOT-CD ein\nund starten Sie das Spiel neu.");
+#endif
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Roboter ungeeignet");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Im Flug unmöglich");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Trägt schon etwas");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Nichts zu ergreifen");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "In Fahrt unmöglich");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Stelle schon besetzt");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "Kein anderer Roboter");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "Sie können keinen radioaktiven Gegenstand tragen");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "Sie können unter Wasser nichts tragen");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Nichts abzulegen");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Im Flug unmöglich");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Unter Wasser unmöglich");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Nicht genug Energie");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Titan zu weit weg");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Titan zu nahe");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "Kein Titan vorhanden");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Boden nicht eben genug");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Ebener Boden nicht groß genug");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Stelle schon besetzt");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Zu nahe am Raumschiff");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Zu nahe an einem Gebäude");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "In Fahrt unmöglich");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Im Flug unmöglich");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Roboter ungeeignet");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "In Fahrt unmöglich");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Roboter ungeeignet");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Nicht genug Energie");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Boden ungeeignet");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Gebäude zu nahe");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Gegenstand zu nahe");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Roboter ungeeignet");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Nicht genug Energie");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Nichts zu recyceln");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Roboter ungeeignet");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "Keine Energie mehr");
+//? if ( num == ERR_COM ) strcpy(text, "Kommunikationsproblem mit dem Roboter");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "Ziel kann nicht erreicht werden");
+ if ( num == ERR_FIND_IMPOSSIBLE ) strcpy(text, "Das Objekt existiert nicht");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Ziel kann nicht erreicht werden");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Ziel kann nicht erreicht werden");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Ziel ist schon besetzt");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Roboter ungeeignet");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Nicht genug Energie");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Im Flug unmöglich");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "Kein konvertierbares Titanerz vorhanden");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "Keine unterirdische Erzlagerstätte");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "Kein unterirdisches Energievorkommen");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "Keine Batterie");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "Keine Energie mehr");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "Keine Batterie");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Nicht mehr genug Energie");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Falscher Batterietyp");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Forschungsprogramm schon ausgeführt");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "Kein unterirdisches Energievorkommen");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Noch nicht genug Energie");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "Kein konvertierbares Titanerz vorhanden");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Wandelt nur Titanerz um");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Die Türen werden von einem Gegenstand blockiert");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "Gehen Sie an Bord, bevor Sie abheben");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Nichts zu analysieren");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "Analysiert nur Orgastoff");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analyse schon durchgeführt");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "Kein unterirdisches Energievorkommen");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Noch nicht genug Energie");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "Kein konvertierbares Platin");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Wandelt nur Platin um");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "Kein Titan vorhanden");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Ein Gegenstand ist zu nahe");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Stelle schon besetzt");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "Kein Infoserver in Reichweite");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Ein Programm wurde von einem Virus infiziert");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Von Virus infiziert, zeitweise außer Betrieb");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "Keine Batterie");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "Keine Energie mehr");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Im Flug unmöglich");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Im Wasser unmöglich");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Beim Gehen unmöglich");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Unmöglich wenn Sie etwas tragen");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Zu viele Fahnen dieser Farbe (Maximum 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Zu nahe an einer anderen Fahne");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "Keine Fahne in Reichweite");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "Mission noch nicht beendet (Drücken Sie auf \\key help; für weitere Informationen)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Roboter zerstört");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Gebäude zerstört");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Kein neues Objekt kann erstellt werden (zu viele vorhanden)");
+ if ( num == ERR_OBLIGATORYTOKEN ) strcpy(text, "Es fehlt \"%s\" in Ihrem Programm");
+ if ( num == ERR_PROHIBITEDTOKEN ) strcpy(text, "In dieser Übung verboten");
+
+ if ( num == INFO_BUILD ) strcpy(text, "Gebäude fertiggestellt");
+ if ( num == INFO_CONVERT ) strcpy(text, "Titan verfügbar");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Forschungsprogramm abgeschlossen");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Herstellung eines Roboters mit Kettenantrieb möglich");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "Sie können jetzt mit den Tasten \\key gup; und \\key gdown; fliegen");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Herstellung eines Stampfers möglich");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Herstellung eines Shooters möglich");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Errichtung eines Geschützturms möglich");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Herstellung eines Phazershooters möglich");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Herstellung eines Schutzschildes möglich");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Errichtung einer Brennstoffzellenfabrik möglich");
+ if ( num == INFO_FACTORY ) strcpy(text, "Neuer Roboter verfügbar");
+ if ( num == INFO_LABO ) strcpy(text, "Analyse vollendet");
+ if ( num == INFO_ENERGY ) strcpy(text, "Batterie verfügbar");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Brennstoffzelle verfügbar");
+ if ( num == INFO_FINDING ) strcpy(text, "Sie haben ein brauchbares Objekt gefunden");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Geeignete Stelle für Kraftwerk gefunden");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Geeignete Stelle für Bohrturm gefunden");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Geeignete Stelle für Bohrturm gefunden");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Geeignete Stelle für Bohrturm gefunden");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Geeignete Stelle für Bohrturm gefunden");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Geeignete Stelle für Bohrturm gefunden");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Geeignete Stelle für Bohrturm gefunden");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Bravo, Mission vollendet >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Mission gescheitert >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Mission gescheitert >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Mission gespeichert");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Checkpoint erreicht");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Insektenkönigin tödlich verwundet");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Ameise tödlich verwundet");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Wespe tödlich verwundet");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Wurm tödlich verwundet");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Spinne tödlich verwundet");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Beziehen Sie sich auf Ihren SatCom, indem Sie auf \\key help; drücken");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "Fehler");
+ if ( num == TX_OPENPAR ) strcpy(text, "Es fehlt eine offene Klammer ""(""");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Es fehlt eine geschlossene Klammer "")""");
+ if ( num == TX_NOTBOOL ) strcpy(text, "Der Ausdruck muss einen boolschen Wert ergeben");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Variable nicht deklariert");
+ if ( num == TX_BADLEFT ) strcpy(text, "Zuweisung unmöglich");
+ if ( num == TX_ENDOF ) strcpy(text, "Es fehlt ein Strichpunkt "";"" am Ende der Anweisung");
+ if ( num == TX_OUTCASE ) strcpy(text, "Anweisung ""case"" ohne vorhergehende Anweisung ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Hier ist eine Anweisung nach dem Ende des Programms");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "Es fehlt eine geschlossene geschweifte Klammer ""}"" (Ende des Blocks)");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Anweisung ""else"" ohne vorhergehende Anweisung ""if""");
+ if ( num == TX_OPENBLK ) strcpy(text, "Es fehlt eine offene geschweifte Klammer""{""");
+ if ( num == TX_BADTYPE ) strcpy(text, "Der Ausdruck ergibt einen falschen Typ für die Zuweisung");
+ if ( num == TX_REDEFVAR ) strcpy(text, "Eine Variable wird zum zweiten Mal deklariert");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "Die zwei Operanden sind nicht kompatibel");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Unbekannte Funktion");
+ if ( num == TX_MISDOTS ) strcpy(text, "Es fehlt ein Doppelpunkt "" : """);
+ if ( num == TX_WHILE ) strcpy(text, "Es fehlt das Wort ""while""");
+ if ( num == TX_BREAK ) strcpy(text, "Anweisung ""break"" außerhalb einer Schleife");
+ if ( num == TX_LABEL ) strcpy(text, "Ein Label kann nur vor den Anweisungen ""for"", ""while"", ""do"" oder ""switch"" vorkommen");
+ if ( num == TX_NOLABEL ) strcpy(text, "Dieses Label existiert nicht");
+ if ( num == TX_NOCASE ) strcpy(text, "Es fehlt eine Anweisung ""case""");
+ if ( num == TX_BADNUM ) strcpy(text, "Es fehlt eine Zahl");
+ if ( num == TX_VOID ) strcpy(text, "Parameter void");
+ if ( num == TX_NOTYP ) strcpy(text, "Hier muss ein Variablentyp stehen");
+ if ( num == TX_NOVAR ) strcpy(text, "Es fehlt der Name einer Variable");
+ if ( num == TX_NOFONC ) strcpy(text, "Hier muss der Name der Funktion stehen");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Zu viele Parameter");
+ if ( num == TX_REDEF ) strcpy(text, "Diese Funktion gibt es schon");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Nicht genug Parameter");
+ if ( num == TX_BADPARAM ) strcpy(text, "Keine Funktion mit diesem Namen verträgt Parameter diesen Typs");
+ if ( num == TX_NUMPARAM ) strcpy(text, "Keine Funktion mit diesem Namen verträgt diese Anzahl Parameter");
+ if ( num == TX_NOITEM ) strcpy(text, "Dieses Element gibt es nicht in dieser Klasse");
+ if ( num == TX_DOT ) strcpy(text, "Das Objekt ist nicht eine Instanz einer Klasse");
+ if ( num == TX_NOCONST ) strcpy(text, "Es gibt keinen geeigneten Konstruktor");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "Diese Klasse gibt es schon");
+ if ( num == TX_CLBRK ) strcpy(text, "Es fehlt eine geschlossene eckige Klammer "" ] """);
+ if ( num == TX_RESERVED ) strcpy(text, "Dieses Wort ist reserviert");
+ if ( num == TX_BADNEW ) strcpy(text, "Falsche Argumente für ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, "Es fehlt eine offene eckige Klammer "" [ """);
+ if ( num == TX_BADSTRING ) strcpy(text, "Hier wird eine Zeichenkette erwartet");
+ if ( num == TX_BADINDEX ) strcpy(text, "Falscher Typ für einen Index");
+ if ( num == TX_PRIVATE ) strcpy(text, "Geschütztes Element (private)");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Hier muss das Wort ""public"" stehen");
+ if ( num == TX_DIVZERO ) strcpy(text, "Teilung durch Null");
+ if ( num == TX_NOTINIT ) strcpy(text, "Der Wert dieser Variable wurde nicht definiert");
+ if ( num == TX_BADTHROW ) strcpy(text, "Negativer Wert ungeeignet für Anweisung ""throw""");
+ if ( num == TX_NORETVAL ) strcpy(text, "Die Funktion hat kein Ergebnis zurückgegeben");
+ if ( num == TX_NORUN ) strcpy(text, "Keine Funktion wird ausgeführt");
+ if ( num == TX_NOCALL ) strcpy(text, "Die aufgerufene Funktion existiert nicht");
+ if ( num == TX_NOCLASS ) strcpy(text, "Diese Klasse existiert nicht");
+ if ( num == TX_NULLPT ) strcpy(text, "Das Objekt existiert nicht");
+ if ( num == TX_OPNAN ) strcpy(text, "Operation mit dem Wert ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Zugriff im Array außerhalb der Grenzen");
+ if ( num == TX_STACKOVER ) strcpy(text, "Stack overflow");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Objekt nicht verfügbar");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Die Datei kann nicht geöffnet werden");
+ if ( num == TX_NOTOPEN ) strcpy(text, "Die Datei wurde nicht geöffnet");
+ if ( num == TX_ERRREAD ) strcpy(text, "Fehler beim Lesezugriff");
+ if ( num == TX_ERRWRITE ) strcpy(text, "Fehler beim Schreibzugriff");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< keine >");
+ if ( num == VK_LEFT ) strcpy(text, "Pfeiltaste links");
+ if ( num == VK_RIGHT ) strcpy(text, "Pfeiltaste rechts");
+ if ( num == VK_UP ) strcpy(text, "Pfeil nach oben");
+ if ( num == VK_DOWN ) strcpy(text, "Pfeil nach unten");
+ if ( num == VK_CANCEL ) strcpy(text, "Ctrl-Break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_RETURN ) strcpy(text, "Eingabe");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Leertaste");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Select");
+ if ( num == VK_EXECUTE ) strcpy(text, "Execute");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Help");
+ if ( num == VK_LWIN ) strcpy(text, "Left Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Right Windows");
+ if ( num == VK_APPS ) strcpy(text, "Application key");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "NumPad 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "NumPad 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "NumPad 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "NumPad 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "NumPad 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "NumPad 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "NumPad 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "NumPad 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "NumPad 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "NumPad 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "NumPad *");
+ if ( num == VK_ADD ) strcpy(text, "NumPad +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "NumPad sep");
+ if ( num == VK_SUBTRACT ) strcpy(text, "NumPad -");
+ if ( num == VK_DECIMAL ) strcpy(text, "NumPad .");
+ if ( num == VK_DIVIDE ) strcpy(text, "NumPad /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Play");
+ if ( num == VK_ZOOM ) strcpy(text, "Zoom");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "Clear");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Knopf 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Knopf 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Knopf 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Knopf 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Knopf 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Knopf 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Knopf 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Knopf 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Knopf 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Knopf 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Knopf 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Knopf 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Knopf 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Knopf 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Knopf 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Knopf 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Knopf 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Knopf 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Knopf 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Knopf 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Knopf 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Knopf 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Knopf 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Knopf 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Knopf 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Knopf 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Knopf 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Knopf 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Knopf 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Knopf 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Knopf 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Knopf 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Mausrad nach vorne");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Mausrad zurück");
+ }
+#endif
+
+#if _POLISH
+ if ( type == RES_TEXT )
+ {
+ #if _FULL
+ if ( num == RT_VERSION_ID ) strcpy(text, "Wersja 1.18 /pl");
+ #endif
+ #if _NET
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A 1.18");
+ #endif
+ #if _SCHOOL & _EDU
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen EDU 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A EDU 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _PERSO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen PERSO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A PERSO 1.18");
+ #endif
+ #endif
+ #if _SCHOOL & _CEEBOTDEMO
+ #if _TEEN
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-Teen DEMO 1.18");
+ #else
+ if ( num == RT_VERSION_ID ) strcpy(text, "CeeBot-A DEMO 1.18");
+ #endif
+ #endif
+ #if _DEMO
+ if ( num == RT_VERSION_ID ) strcpy(text, "Demo 1.18 /pl");
+ #endif
+ if ( num == RT_DISINFO_TITLE ) strcpy(text, "SatCom");
+ if ( num == RT_WINDOW_MAXIMIZED ) strcpy(text, "Powiêksz");
+ if ( num == RT_WINDOW_MINIMIZED ) strcpy(text, "Pomniejsz");
+ if ( num == RT_WINDOW_STANDARD ) strcpy(text, "Normalna wielkoϾ");
+ if ( num == RT_WINDOW_CLOSE ) strcpy(text, "Zamknij");
+
+ if ( num == RT_STUDIO_TITLE ) strcpy(text, "Edytor programu");
+ if ( num == RT_SCRIPT_NEW ) strcpy(text, "Nowy");
+ if ( num == RT_NAME_DEFAULT ) strcpy(text, "Gracz");
+ if ( num == RT_IO_NEW ) strcpy(text, "Nowy ...");
+ if ( num == RT_KEY_OR ) strcpy(text, " lub ");
+
+#if _NEWLOOK
+ if ( num == RT_TITLE_BASE ) strcpy(text, "CeeBot");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "CeeBot");
+#else
+ if ( num == RT_TITLE_BASE ) strcpy(text, "COLOBOT");
+ if ( num == RT_TITLE_INIT ) strcpy(text, "COLOBOT");
+#endif
+ if ( num == RT_TITLE_TRAINER ) strcpy(text, "Æwiczenia programistyczne");
+ if ( num == RT_TITLE_DEFI ) strcpy(text, "Wyzwania");
+ if ( num == RT_TITLE_MISSION ) strcpy(text, "Misje");
+ if ( num == RT_TITLE_FREE ) strcpy(text, "Swobodna gra");
+ if ( num == RT_TITLE_TEEN ) strcpy(text, "Swobodna gra");
+ if ( num == RT_TITLE_USER ) strcpy(text, "Poziomy u¿ytkownika");
+ if ( num == RT_TITLE_PROTO ) strcpy(text, "Prototypy");
+ if ( num == RT_TITLE_SETUP ) strcpy(text, "Opcje");
+ if ( num == RT_TITLE_NAME ) strcpy(text, "Imiê gracza");
+ if ( num == RT_TITLE_PERSO ) strcpy(text, "Dostosuj wygl¹d");
+ if ( num == RT_TITLE_WRITE ) strcpy(text, "Zapisz bie¿¹c¹ misjê");
+ if ( num == RT_TITLE_READ ) strcpy(text, "Wczytaj zapisan¹ misjê");
+
+ if ( num == RT_PLAY_CHAPt ) strcpy(text, " Rozdzia³y:");
+ if ( num == RT_PLAY_CHAPd ) strcpy(text, " Rozdzia³y:");
+ if ( num == RT_PLAY_CHAPm ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_CHAPf ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_CHAPu ) strcpy(text, " Poziomy u¿ytkownika:");
+ if ( num == RT_PLAY_CHAPp ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_CHAPte ) strcpy(text, " Planety:");
+ if ( num == RT_PLAY_LISTt ) strcpy(text, " Æwiczenia w tym rozdziale:");
+ if ( num == RT_PLAY_LISTd ) strcpy(text, " Wyzwania w tym rozdziale:");
+ if ( num == RT_PLAY_LISTm ) strcpy(text, " Misje na tej planecie:");
+ if ( num == RT_PLAY_LISTf ) strcpy(text, " Swobodna gra na tej planecie:");
+ if ( num == RT_PLAY_LISTu ) strcpy(text, " Misje na tym poziomie:");
+ if ( num == RT_PLAY_LISTp ) strcpy(text, " Prototypy na tej planecie:");
+ if ( num == RT_PLAY_LISTk ) strcpy(text, " Prototypy na tej planecie:");
+ if ( num == RT_PLAY_RESUME ) strcpy(text, " Streszczenie:");
+
+ if ( num == RT_SETUP_DEVICE ) strcpy(text, " Sterowniki:");
+ if ( num == RT_SETUP_MODE ) strcpy(text, " RozdzielczoϾ:");
+ if ( num == RT_SETUP_KEY1 ) strcpy(text, "1) Najpierw kliknij klawisz, który chcesz przedefiniowaæ.");
+ if ( num == RT_SETUP_KEY2 ) strcpy(text, "2) Nastêpnie naciœnij klawisz, którego chcesz u¿ywaæ.");
+
+ if ( num == RT_PERSO_FACE ) strcpy(text, "Rodzaj twarzy:");
+ if ( num == RT_PERSO_GLASSES ) strcpy(text, "Okulary:");
+ if ( num == RT_PERSO_HAIR ) strcpy(text, "Kolor w³osów:");
+ if ( num == RT_PERSO_COMBI ) strcpy(text, "Kolor skafandra:");
+ if ( num == RT_PERSO_BAND ) strcpy(text, "Kolor pasków:");
+
+#if _NEWLOOK
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "CeeBot");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Czy na pewno chcesz opuœciæ grê CeeBot?");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Zakoñcz\\Koñczy grê CeeBot");
+#else
+ if ( num == RT_DIALOG_TITLE ) strcpy(text, "COLOBOT");
+ if ( num == RT_DIALOG_QUIT ) strcpy(text, "Czy na pewno chcesz opuœciæ grê COLOBOT?");
+ if ( num == RT_DIALOG_YESQUIT ) strcpy(text, "Zakoñcz\\Koñczy grê COLOBOT");
+#endif
+ if ( num == RT_DIALOG_ABORT ) strcpy(text, "Opuœciæ misjê?");
+ if ( num == RT_DIALOG_YES ) strcpy(text, "Przerwij\\Przerywa bie¿¹c¹ misjê");
+ if ( num == RT_DIALOG_NO ) strcpy(text, "Kontynuuj\\Kontynuuje bie¿¹c¹ misjê");
+ if ( num == RT_DIALOG_NOQUIT ) strcpy(text, "Kontynuuj\\Kontynuuje grê");
+ if ( num == RT_DIALOG_DELOBJ ) strcpy(text, "Czy na pewno chcesz zniszczyæ zaznaczony budynek?");
+ if ( num == RT_DIALOG_DELGAME ) strcpy(text, "Czy na pewno chcesz skasowaæ zapisane gry gracza %s? ");
+ if ( num == RT_DIALOG_YESDEL ) strcpy(text, "Usuñ");
+ if ( num == RT_DIALOG_NODEL ) strcpy(text, "Anuluj");
+ if ( num == RT_DIALOG_LOADING ) strcpy(text, "WCZYTYWANIE");
+
+ if ( num == RT_STUDIO_LISTTT ) strcpy(text, "Skróty klawiszowe (\\key cbot;)");
+ if ( num == RT_STUDIO_COMPOK ) strcpy(text, "Program skompilowany (0 b³êdów)");
+ if ( num == RT_STUDIO_PROGSTOP ) strcpy(text, "Program zakoñczony");
+
+ if ( num == RT_SATCOM_LIST ) strcpy(text, "\\b;Lista obiektów\n");
+ if ( num == RT_SATCOM_BOT ) strcpy(text, "\\b;Roboty\n");
+ if ( num == RT_SATCOM_BUILDING ) strcpy(text, "\\b;Budynki\n");
+ if ( num == RT_SATCOM_FRET ) strcpy(text, "\\b;Obiekty ruchome\n");
+ if ( num == RT_SATCOM_ALIEN ) strcpy(text, "\\b;Obcy\n");
+ if ( num == RT_SATCOM_NULL ) strcpy(text, "\\c; (brak)\\n;\n");
+ if ( num == RT_SATCOM_ERROR1 ) strcpy(text, "\\b;B³¹d\n");
+ if ( num == RT_SATCOM_ERROR2 ) strcpy(text, "Lista jest dostêpna jedynie gdy dzia³a \\l;stacja radarowa\\u object\\radar;.\n");
+
+ if ( num == RT_IO_OPEN ) strcpy(text, "Otwórz");
+ if ( num == RT_IO_SAVE ) strcpy(text, "Zapisz");
+ if ( num == RT_IO_LIST ) strcpy(text, "Folder: %s");
+ if ( num == RT_IO_NAME ) strcpy(text, "Nazwa:");
+ if ( num == RT_IO_DIR ) strcpy(text, "Folder:");
+ if ( num == RT_IO_PRIVATE ) strcpy(text, "Prywatny\\Folder prywatny");
+ if ( num == RT_IO_PUBLIC ) strcpy(text, "Publiczny\\Folder ogólnodostêpny");
+
+ if ( num == RT_GENERIC_DEV1 ) strcpy(text, "Twórcy:");
+ if ( num == RT_GENERIC_DEV2 ) strcpy(text, "www.epsitec.com");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, "Wersja polska wydana przez:");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, "www.manta.com.pl");
+ if ( num == RT_GENERIC_EDIT1 ) strcpy(text, " ");
+ if ( num == RT_GENERIC_EDIT2 ) strcpy(text, " ");
+
+ if ( num == RT_INTERFACE_REC ) strcpy(text, "Recorder");
+ }
+
+ if ( type == RES_EVENT )
+ {
+ if ( num == EVENT_BUTTON_OK ) strcpy(text, "OK");
+ if ( num == EVENT_BUTTON_CANCEL ) strcpy(text, "Anuluj");
+ if ( num == EVENT_BUTTON_NEXT ) strcpy(text, "Nastêpny");
+ if ( num == EVENT_BUTTON_PREV ) strcpy(text, "Poprzedni");
+ if ( num == EVENT_BUTTON_QUIT ) strcpy(text, "Menu (\\key quit;)");
+
+ if ( num == EVENT_DIALOG_OK ) strcpy(text, "OK");
+ if ( num == EVENT_DIALOG_CANCEL ) strcpy(text, "Anuluj");
+
+ if ( num == EVENT_INTERFACE_TRAINER) strcpy(text, "Æwiczenia\\Æwiczenia programistyczne");
+ if ( num == EVENT_INTERFACE_DEFI ) strcpy(text, "Wyzwania\\Wyzwania programistyczne");
+ if ( num == EVENT_INTERFACE_MISSION) strcpy(text, "Misje\\Wybierz misjê");
+ if ( num == EVENT_INTERFACE_FREE ) strcpy(text, "Swobodna gra\\Swobodna gra bez konkretnych celów");
+ if ( num == EVENT_INTERFACE_TEEN ) strcpy(text, "Swobodna gra\\Swobodna gra bez konkretnych celów");
+ if ( num == EVENT_INTERFACE_USER ) strcpy(text, "Poziomy\\Poziomy u¿ytkownika");
+ if ( num == EVENT_INTERFACE_PROTO ) strcpy(text, "Prototypy\\Prototypy w trakcie rozwijania");
+ if ( num == EVENT_INTERFACE_NAME ) strcpy(text, "Nowy gracz\\Wybierz imiê gracza");
+ if ( num == EVENT_INTERFACE_SETUP ) strcpy(text, "Opcje\\Preferencje");
+ if ( num == EVENT_INTERFACE_AGAIN ) strcpy(text, "Uruchom ponownie\\Uruchamia ponownie misjê od pocz¹tku");
+ if ( num == EVENT_INTERFACE_WRITE ) strcpy(text, "Zapisz\\Zapisuje bie¿¹c¹ misjê");
+ if ( num == EVENT_INTERFACE_READ ) strcpy(text, "Wczytaj\\Wczytuje zapisan¹ misjê");
+#if _NEWLOOK
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Powróæ do gry CeeBot");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Zakoñcz\\Koñczy grê CeeBot");
+#else
+ if ( num == EVENT_INTERFACE_ABORT ) strcpy(text, "\\Powróæ do gry COLOBOT");
+ if ( num == EVENT_INTERFACE_QUIT ) strcpy(text, "Zakoñcz\\Koñczy grê COLOBOT");
+#endif
+ if ( num == EVENT_INTERFACE_BACK ) strcpy(text, "<< Wstecz \\Wraca do poprzedniego ekranu");
+ if ( num == EVENT_INTERFACE_PLAY ) strcpy(text, "Graj\\Rozpoczyna misjê!");
+ if ( num == EVENT_INTERFACE_SETUPd ) strcpy(text, "Urz¹dzenie\\Ustawienia sterownika i rozdzielczoœci");
+ if ( num == EVENT_INTERFACE_SETUPg ) strcpy(text, "Grafika\\Ustawienia grafiki");
+ if ( num == EVENT_INTERFACE_SETUPp ) strcpy(text, "Gra\\Ustawienia gry");
+ if ( num == EVENT_INTERFACE_SETUPc ) strcpy(text, "Sterowanie\\Ustawienia klawiatury, joysticka i myszy");
+ if ( num == EVENT_INTERFACE_SETUPs ) strcpy(text, "DŸwiêk\\G³oœnoœæ muzyki i dŸwiêków gry");
+ if ( num == EVENT_INTERFACE_DEVICE ) strcpy(text, "Jednostka");
+ if ( num == EVENT_INTERFACE_RESOL ) strcpy(text, "RozdzielczoϾ");
+ if ( num == EVENT_INTERFACE_FULL ) strcpy(text, "Pe³ny ekran\\Pe³ny ekran lub tryb okna");
+ if ( num == EVENT_INTERFACE_APPLY ) strcpy(text, "Zastosuj zmiany\\Aktywuje zmienione ustawienia");
+
+ if ( num == EVENT_INTERFACE_TOTO ) strcpy(text, "Robbie\\Twój asystent");
+ if ( num == EVENT_INTERFACE_SHADOW ) strcpy(text, "Cienie\\Cienie na ziemi");
+ if ( num == EVENT_INTERFACE_GROUND ) strcpy(text, "Znaki na ziemi\\Znaki na ziemi");
+ if ( num == EVENT_INTERFACE_DIRTY ) strcpy(text, "Kurz\\Kurz i bród na robotach i budynkach");
+ if ( num == EVENT_INTERFACE_FOG ) strcpy(text, "Mg³a\\Mg³a");
+ if ( num == EVENT_INTERFACE_LENS ) strcpy(text, "Promienie s³oneczne\\Promienie s³oneczne na niebie");
+ if ( num == EVENT_INTERFACE_SKY ) strcpy(text, "Niebo\\Chmury i mg³awice");
+ if ( num == EVENT_INTERFACE_PLANET ) strcpy(text, "Planety i gwiazdy\\Obiekty astronomiczne na niebie");
+ if ( num == EVENT_INTERFACE_LIGHT ) strcpy(text, "Dynamiczne oœwietlenie\\Ruchome Ÿród³a œwiat³a");
+ if ( num == EVENT_INTERFACE_PARTI ) strcpy(text, "Liczba cz¹stek\\Wybuchy, kurz, odbicia, itp.");
+ if ( num == EVENT_INTERFACE_CLIP ) strcpy(text, "G³êbokoœæ pola\\Maksymalna widocznoœæ");
+ if ( num == EVENT_INTERFACE_DETAIL ) strcpy(text, "Szczegó³y\\Jakoœæ wizualna obiektów 3D");
+ if ( num == EVENT_INTERFACE_TEXTURE) strcpy(text, "Tekstury\\JakoϾ tekstur ");
+ if ( num == EVENT_INTERFACE_GADGET ) strcpy(text, "Iloœæ elementów dekoracyjnych \\Iloœæ elementów czysto dekoracyjnych");
+ if ( num == EVENT_INTERFACE_RAIN ) strcpy(text, "Cz¹stki w interfejsie\\Para i iskry z silników w interfejsie");
+ if ( num == EVENT_INTERFACE_GLINT ) strcpy(text, "Odbicia na przyciskach \\Œwiec¹ce przyciski");
+ if ( num == EVENT_INTERFACE_TOOLTIP) strcpy(text, "Dymki pomocy\\Wyjaœnia funkcje przycisków");
+ if ( num == EVENT_INTERFACE_MOVIES ) strcpy(text, "Sekwencje filmowe\\Filmy przed rozpoczêciem i na zakoñczenie misji");
+ if ( num == EVENT_INTERFACE_NICERST) strcpy(text, "Koñcowy film\\Film na zakoñczenie æwiczeñ");
+ if ( num == EVENT_INTERFACE_HIMSELF) strcpy(text, "Przyjacielski ogieñ\\W³asne strza³y uszkadzaj¹ Twoje obiekty");
+ if ( num == EVENT_INTERFACE_SCROLL ) strcpy(text, "Przewijanie\\Ekran jest przewijany gdy mysz dotknie prawej lub lewej jego krawêdzi");
+ if ( num == EVENT_INTERFACE_INVERTX) strcpy(text, "Odwrócenie myszy X\\Odwrócenie kierunków przewijania w poziomie");
+ if ( num == EVENT_INTERFACE_INVERTY) strcpy(text, "Odwrócenie myszy Y\\Odwrócenie kierunków przewijania w pionie");
+ if ( num == EVENT_INTERFACE_EFFECT ) strcpy(text, "Wstrz¹sy przy wybuchach\\Ekran trzêsie siê podczas wybuchów");
+ if ( num == EVENT_INTERFACE_MOUSE ) strcpy(text, "Cieñ kursora myszy\\Dodaje cieñ kursorowi myszy");
+ if ( num == EVENT_INTERFACE_EDITMODE) strcpy(text, "Automatyczne wciêcia\\Automatyczne wciêcia podczas edycji programu");
+ if ( num == EVENT_INTERFACE_EDITVALUE)strcpy(text, "Du¿e wciêcie\\2 lub 4 spacje wciêcia na ka¿dy poziom zdefiniowany przez klamry");
+ if ( num == EVENT_INTERFACE_SOLUCE4) strcpy(text, "Accès aux solutions\\Programme \"4: Solution\" dans les exercices");
+
+ if ( num == EVENT_INTERFACE_KDEF ) strcpy(text, "Standardowa kontrola\\Standardowe klawisze funkcyjne");
+ if ( num == EVENT_INTERFACE_KLEFT ) strcpy(text, "Skrêæ w lewo\\Obraca robota w lewo");
+ if ( num == EVENT_INTERFACE_KRIGHT ) strcpy(text, "Obróæ w prawo\\Obraca robota w prawo");
+ if ( num == EVENT_INTERFACE_KUP ) strcpy(text, "Naprzód\\Porusza do przodu");
+ if ( num == EVENT_INTERFACE_KDOWN ) strcpy(text, "Wstecz\\Porusza do ty³u");
+ if ( num == EVENT_INTERFACE_KGUP ) strcpy(text, "W górê\\Zwiêksza moc silnika");
+ if ( num == EVENT_INTERFACE_KGDOWN ) strcpy(text, "W dó³\\Zmniejsza moc silnika");
+ if ( num == EVENT_INTERFACE_KCAMERA) strcpy(text, "Zmieñ kamerê\\Prze³¹cza pomiêdzy kamer¹ pok³adow¹ i œledz¹c¹");
+ if ( num == EVENT_INTERFACE_KDESEL ) strcpy(text, "Poprzedni obiekt\\Zaznacz poprzedni obiekt");
+ if ( num == EVENT_INTERFACE_KACTION) strcpy(text, "Standardowa akcja\\Standardowa akcja robota (podnieœ/upuœæ, strzelaj, szukaj, itp.)");
+ if ( num == EVENT_INTERFACE_KNEAR ) strcpy(text, "Kamera bli¿ej\\Przybli¿a kamerê");
+ if ( num == EVENT_INTERFACE_KAWAY ) strcpy(text, "Kamera dalej\\Oddala kamerê");
+ if ( num == EVENT_INTERFACE_KNEXT ) strcpy(text, "Nastêpny obiekt\\Zaznacza nastêpny obiekt");
+ if ( num == EVENT_INTERFACE_KHUMAN ) strcpy(text, "Zaznacz astronautê\\Zaznacza astronautê");
+ if ( num == EVENT_INTERFACE_KQUIT ) strcpy(text, "Zakoñcz\\Koñczy bie¿¹c¹ misjê lub æwiczenie");
+ if ( num == EVENT_INTERFACE_KHELP ) strcpy(text, "Rozkazy\\Pokazuje rozkazy dotycz¹ce bie¿¹cej misji");
+ if ( num == EVENT_INTERFACE_KPROG ) strcpy(text, "Podrêcznik programowania\\Dostarcza szczegó³ow¹ pomoc w programowaniu");
+ if ( num == EVENT_INTERFACE_KCBOT ) strcpy(text, "Pomoc dot. s³ów kluczowych\\Dok³adniejsza pomoc na temat s³ów kluczowych");
+ if ( num == EVENT_INTERFACE_KVISIT ) strcpy(text, "Miejsce nadania wiadomoœci\\Pokazuje sk¹d zosta³a wys³ana ostatnia wiadomoœæ");
+ if ( num == EVENT_INTERFACE_KSPEED10) strcpy(text, "Prêdkoœæ 1,0x\\Prêdkoœæ normalna");
+ if ( num == EVENT_INTERFACE_KSPEED15) strcpy(text, "Prêdkoœæ 1,5x\\1,5 raza szybciej");
+ if ( num == EVENT_INTERFACE_KSPEED20) strcpy(text, "Prêdkoœæ 2,0x\\Dwa razy szybciej");
+ if ( num == EVENT_INTERFACE_KSPEED30) strcpy(text, "Prêdkoœæ 3,0x\\Trzy razy szybciej");
+
+ if ( num == EVENT_INTERFACE_VOLSOUND) strcpy(text, "Efekty dŸwiêkowe:\\G³oœnoœæ silników, g³osów, strza³ów, itp.");
+ if ( num == EVENT_INTERFACE_VOLMUSIC) strcpy(text, "Muzyka w tle :\\G³oœnoœæ œcie¿ek dŸwiêkowych z p³yty CD");
+ if ( num == EVENT_INTERFACE_SOUND3D) strcpy(text, "DŸwiêk 3D\\Przestrzenne pozycjonowanie dŸwiêków");
+
+ if ( num == EVENT_INTERFACE_MIN ) strcpy(text, "Najni¿sza\\Minimalna jakoœæ grafiki (najwy¿sza czêstotliwoœæ odœwie¿ania)");
+ if ( num == EVENT_INTERFACE_NORM ) strcpy(text, "Normalna\\Normalna jakoϾ grafiki");
+ if ( num == EVENT_INTERFACE_MAX ) strcpy(text, "Najwy¿sza\\Maksymalna jakoœæ grafiki (najni¿sza czêstotliwoœæ odœwie¿ania)");
+
+ if ( num == EVENT_INTERFACE_SILENT ) strcpy(text, "Cisza\\Brak dŸwiêków");
+ if ( num == EVENT_INTERFACE_NOISY ) strcpy(text, "Normalne\\Normalna g³oœnoœæ dŸwiêków");
+
+ if ( num == EVENT_INTERFACE_JOYSTICK) strcpy(text, "U¿ywaj joysticka\\Joystick lub klawiatura");
+ if ( num == EVENT_INTERFACE_SOLUCE ) strcpy(text, "Dostêp do rozwi¹zania\\Pokazuje rozwi¹zanie (szczegó³owe instrukcje dotycz¹ce misji)");
+
+ if ( num == EVENT_INTERFACE_NEDIT ) strcpy(text, "\\Nowe imiê gracza");
+ if ( num == EVENT_INTERFACE_NOK ) strcpy(text, "OK\\Wybiera zaznaczonego gracza");
+ if ( num == EVENT_INTERFACE_NCANCEL) strcpy(text, "Anuluj\\Zachowuje bie¿¹ce imiê gracza");
+ if ( num == EVENT_INTERFACE_NDELETE) strcpy(text, "Usuñ gracza\\Usuwa gracza z listy");
+ if ( num == EVENT_INTERFACE_NLABEL ) strcpy(text, "Imiê gracza");
+
+ if ( num == EVENT_INTERFACE_IOWRITE) strcpy(text, "Zapisz\\Zapisuje bie¿¹c¹ misjê");
+ if ( num == EVENT_INTERFACE_IOREAD ) strcpy(text, "Wczytaj\\Wczytuje zaznaczon¹ misjê");
+ if ( num == EVENT_INTERFACE_IOLIST ) strcpy(text, "Lista zapisanych misji");
+ if ( num == EVENT_INTERFACE_IOLABEL) strcpy(text, "Nazwa pliku:");
+ if ( num == EVENT_INTERFACE_IONAME ) strcpy(text, "Nazwa misji");
+ if ( num == EVENT_INTERFACE_IOIMAGE) strcpy(text, "Fotografia");
+ if ( num == EVENT_INTERFACE_IODELETE) strcpy(text, "Usuñ\\Usuwa zaznaczony plik");
+
+ if ( num == EVENT_INTERFACE_PERSO ) strcpy(text, "Wygl¹d\\Wybierz swoj¹ postaæ");
+ if ( num == EVENT_INTERFACE_POK ) strcpy(text, "OK");
+ if ( num == EVENT_INTERFACE_PCANCEL) strcpy(text, "Anuluj");
+ if ( num == EVENT_INTERFACE_PDEF ) strcpy(text, "Standardowe\\Standardowe ustawienia wygl¹du");
+ if ( num == EVENT_INTERFACE_PHEAD ) strcpy(text, "G³owa\\Twarz i w³osy");
+ if ( num == EVENT_INTERFACE_PBODY ) strcpy(text, "Skafander\\Skafander astronauty");
+ if ( num == EVENT_INTERFACE_PLROT ) strcpy(text, "\\Obróæ w lewo");
+ if ( num == EVENT_INTERFACE_PRROT ) strcpy(text, "\\Obróæ w prawo");
+ if ( num == EVENT_INTERFACE_PCRa ) strcpy(text, "Czerwony");
+ if ( num == EVENT_INTERFACE_PCGa ) strcpy(text, "Zielony");
+ if ( num == EVENT_INTERFACE_PCBa ) strcpy(text, "Niebieski");
+ if ( num == EVENT_INTERFACE_PCRb ) strcpy(text, "Czerwony");
+ if ( num == EVENT_INTERFACE_PCGb ) strcpy(text, "Zielony");
+ if ( num == EVENT_INTERFACE_PCBb ) strcpy(text, "Niebieski");
+ if ( num == EVENT_INTERFACE_PFACE1 ) strcpy(text, "\\Twarz 1");
+ if ( num == EVENT_INTERFACE_PFACE2 ) strcpy(text, "\\Twarz 4");
+ if ( num == EVENT_INTERFACE_PFACE3 ) strcpy(text, "\\Twarz 3");
+ if ( num == EVENT_INTERFACE_PFACE4 ) strcpy(text, "\\Twarz 2");
+ if ( num == EVENT_INTERFACE_PGLASS0) strcpy(text, "\\Bez okularów");
+ if ( num == EVENT_INTERFACE_PGLASS1) strcpy(text, "\\Okulary 1");
+ if ( num == EVENT_INTERFACE_PGLASS2) strcpy(text, "\\Okulary 2");
+ if ( num == EVENT_INTERFACE_PGLASS3) strcpy(text, "\\Okulary 3");
+ if ( num == EVENT_INTERFACE_PGLASS4) strcpy(text, "\\Okulary 4");
+ if ( num == EVENT_INTERFACE_PGLASS5) strcpy(text, "\\Okulary 5");
+
+ if ( num == EVENT_OBJECT_DESELECT ) strcpy(text, "Poprzednie zaznaczenie (\\key desel;)");
+ if ( num == EVENT_OBJECT_LEFT ) strcpy(text, "Skrêæ w lewo (\\key left;)");
+ if ( num == EVENT_OBJECT_RIGHT ) strcpy(text, "Skrêæ w prawo (\\key right;)");
+ if ( num == EVENT_OBJECT_UP ) strcpy(text, "Naprzód (\\key up;)");
+ if ( num == EVENT_OBJECT_DOWN ) strcpy(text, "Cofnij (\\key down;)");
+ if ( num == EVENT_OBJECT_GASUP ) strcpy(text, "Góra (\\key gup;)");
+ if ( num == EVENT_OBJECT_GASDOWN ) strcpy(text, "Dó³ (\\key gdown;)");
+ if ( num == EVENT_OBJECT_HTAKE ) strcpy(text, "Podnieœ lub upuœæ (\\key action;)");
+ if ( num == EVENT_OBJECT_MTAKE ) strcpy(text, "Podnieœ lub upuœæ (\\key action;)");
+ if ( num == EVENT_OBJECT_MFRONT ) strcpy(text, "..przed");
+ if ( num == EVENT_OBJECT_MBACK ) strcpy(text, "..za");
+ if ( num == EVENT_OBJECT_MPOWER ) strcpy(text, "..ogniwo elektryczne");
+ if ( num == EVENT_OBJECT_BHELP ) strcpy(text, "Rozkazy dotycz¹ce misji (\\key help;)");
+ if ( num == EVENT_OBJECT_BTAKEOFF ) strcpy(text, "Odleæ, aby zakoñczyæ misjê");
+ if ( num == EVENT_OBJECT_BDERRICK ) strcpy(text, "Zbuduj kopalniê");
+ if ( num == EVENT_OBJECT_BSTATION ) strcpy(text, "Zbuduj elektrowniê");
+ if ( num == EVENT_OBJECT_BFACTORY ) strcpy(text, "Zbuduj fabrykê robotów");
+ if ( num == EVENT_OBJECT_BREPAIR ) strcpy(text, "Zbuduj warsztat");
+ if ( num == EVENT_OBJECT_BCONVERT ) strcpy(text, "Zbuduj hutê");
+ if ( num == EVENT_OBJECT_BTOWER ) strcpy(text, "Zbuduj wie¿ê obronn¹");
+ if ( num == EVENT_OBJECT_BRESEARCH ) strcpy(text, "Zbuduj centrum badawcze");
+ if ( num == EVENT_OBJECT_BRADAR ) strcpy(text, "Zbuduj stacjê radarow¹");
+ if ( num == EVENT_OBJECT_BENERGY ) strcpy(text, "Zbuduj fabrykê ogniw elektrycznych");
+ if ( num == EVENT_OBJECT_BLABO ) strcpy(text, "Zbuduj laboratorium");
+ if ( num == EVENT_OBJECT_BNUCLEAR ) strcpy(text, "Zbuduj elektrowniê atomow¹");
+ if ( num == EVENT_OBJECT_BPARA ) strcpy(text, "Zbuduj odgromnik");
+ if ( num == EVENT_OBJECT_BINFO ) strcpy(text, "Zbuduj stacjê przekaŸnikow¹");
+ if ( num == EVENT_OBJECT_GFLAT ) strcpy(text, "Poka¿ czy teren jest p³aski");
+ if ( num == EVENT_OBJECT_FCREATE ) strcpy(text, "Postaw flagê");
+ if ( num == EVENT_OBJECT_FDELETE ) strcpy(text, "Usuñ flagê");
+ if ( num == EVENT_OBJECT_FCOLORb ) strcpy(text, "\\Niebieskie flagi");
+ if ( num == EVENT_OBJECT_FCOLORr ) strcpy(text, "\\Czerwone flagi");
+ if ( num == EVENT_OBJECT_FCOLORg ) strcpy(text, "\\Zielone flagi");
+ if ( num == EVENT_OBJECT_FCOLORy ) strcpy(text, "\\¯ó³te flagi");
+ if ( num == EVENT_OBJECT_FCOLORv ) strcpy(text, "\\Fioletowe flagi");
+ if ( num == EVENT_OBJECT_FACTORYfa ) strcpy(text, "Zbuduj transporter lataj¹cy");
+ if ( num == EVENT_OBJECT_FACTORYta ) strcpy(text, "Zbuduj transporter na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYwa ) strcpy(text, "Zbuduj transporter na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYia ) strcpy(text, "Zbuduj transporter na nogach");
+ if ( num == EVENT_OBJECT_FACTORYfc ) strcpy(text, "Zbuduj dzia³o lataj¹ce");
+ if ( num == EVENT_OBJECT_FACTORYtc ) strcpy(text, "Zbuduj dzia³o na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYwc ) strcpy(text, "Zbuduj dzia³o na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYic ) strcpy(text, "Zbuduj dzia³o na nogach");
+ if ( num == EVENT_OBJECT_FACTORYfi ) strcpy(text, "Zbuduj lataj¹ce dzia³o organiczne");
+ if ( num == EVENT_OBJECT_FACTORYti ) strcpy(text, "Zbuduj dzia³o organiczne na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYwi ) strcpy(text, "Zbuduj dzia³o organiczne na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYii ) strcpy(text, "Zbuduj dzia³o organiczne na nogach");
+ if ( num == EVENT_OBJECT_FACTORYfs ) strcpy(text, "Zbuduj szperacz lataj¹cy");
+ if ( num == EVENT_OBJECT_FACTORYts ) strcpy(text, "Zbuduj szperacz na g¹sienicach");
+ if ( num == EVENT_OBJECT_FACTORYws ) strcpy(text, "Zbuduj szperacz na ko³ach");
+ if ( num == EVENT_OBJECT_FACTORYis ) strcpy(text, "Zbuduj szperacz na nogach");
+ if ( num == EVENT_OBJECT_FACTORYrt ) strcpy(text, "Zbuduj robota uderzacza");
+ if ( num == EVENT_OBJECT_FACTORYrc ) strcpy(text, "Zbuduj dzia³o fazowe");
+ if ( num == EVENT_OBJECT_FACTORYrr ) strcpy(text, "Zbuduj robota recyklera");
+ if ( num == EVENT_OBJECT_FACTORYrs ) strcpy(text, "Zbuduj robota os³aniajacza");
+ if ( num == EVENT_OBJECT_FACTORYsa ) strcpy(text, "Zbuduj robota nurka");
+ if ( num == EVENT_OBJECT_RTANK ) strcpy(text, "Rozpocznij prace badawcze nad transporterem na g¹sienicach");
+ if ( num == EVENT_OBJECT_RFLY ) strcpy(text, "Rozpocznij prace badawcze nad transporterem lataj¹cym");
+ if ( num == EVENT_OBJECT_RTHUMP ) strcpy(text, "Rozpocznij prace badawcze nad robotem uderzaczem");
+ if ( num == EVENT_OBJECT_RCANON ) strcpy(text, "Rozpocznij prace badawcze nad dzia³em");
+ if ( num == EVENT_OBJECT_RTOWER ) strcpy(text, "Rozpocznij prace badawcze nad wie¿¹ obronn¹");
+ if ( num == EVENT_OBJECT_RPHAZER ) strcpy(text, "Rozpocznij prace badawcze nad dzia³em fazowym");
+ if ( num == EVENT_OBJECT_RSHIELD ) strcpy(text, "Rozpocznij prace badawcze nad robotem os³aniaczem");
+ if ( num == EVENT_OBJECT_RATOMIC ) strcpy(text, "Rozpocznij prace badawcze nad energi¹ atomow¹");
+ if ( num == EVENT_OBJECT_RiPAW ) strcpy(text, "Rozpocznij prace badawcze nad transporterem na nogach");
+ if ( num == EVENT_OBJECT_RiGUN ) strcpy(text, "Rozpocznij prace badawcze nad dzia³em organicznym");
+ if ( num == EVENT_OBJECT_RESET ) strcpy(text, "Powrót do pocz¹tku");
+ if ( num == EVENT_OBJECT_SEARCH ) strcpy(text, "Szukaj (\\key action;)");
+ if ( num == EVENT_OBJECT_TERRAFORM ) strcpy(text, "Uderz (\\key action;)");
+ if ( num == EVENT_OBJECT_FIRE ) strcpy(text, "Strzelaj (\\key action;)");
+ if ( num == EVENT_OBJECT_RECOVER ) strcpy(text, "Odzyskaj (\\key action;)");
+ if ( num == EVENT_OBJECT_BEGSHIELD ) strcpy(text, "Rozszerz os³onê (\\key action;)");
+ if ( num == EVENT_OBJECT_ENDSHIELD ) strcpy(text, "Wy³¹cz os³onê (\\key action;)");
+ if ( num == EVENT_OBJECT_DIMSHIELD ) strcpy(text, "Zasiêg os³ony");
+ if ( num == EVENT_OBJECT_PROGRUN ) strcpy(text, "Wykonaj zaznaczony program");
+ if ( num == EVENT_OBJECT_PROGEDIT ) strcpy(text, "Edytuj zaznaczony program");
+ if ( num == EVENT_OBJECT_INFOOK ) strcpy(text, "\\Prze³¹cz przekaŸnik SatCom w stan gotowoœci");
+ if ( num == EVENT_OBJECT_DELETE ) strcpy(text, "Zniszcz budynek");
+ if ( num == EVENT_OBJECT_GENERGY ) strcpy(text, "Poziom energii");
+ if ( num == EVENT_OBJECT_GSHIELD ) strcpy(text, "Poziom os³ony");
+ if ( num == EVENT_OBJECT_GRANGE ) strcpy(text, "Temperatura silnika");
+ if ( num == EVENT_OBJECT_GPROGRESS ) strcpy(text, "Wci¹¿ pracuje...");
+ if ( num == EVENT_OBJECT_GRADAR ) strcpy(text, "Liczba wykrytych insektów");
+ if ( num == EVENT_OBJECT_GINFO ) strcpy(text, "Przes³ane informacje");
+ if ( num == EVENT_OBJECT_COMPASS ) strcpy(text, "Kompas");
+//? if ( num == EVENT_OBJECT_MAP ) strcpy(text, "Mapka");
+ if ( num == EVENT_OBJECT_MAPZOOM ) strcpy(text, "Powiêkszenie mapki");
+ if ( num == EVENT_OBJECT_CAMERA ) strcpy(text, "Kamera (\\key camera;)");
+ if ( num == EVENT_OBJECT_CAMERAleft) strcpy(text, "Camera to left");
+ if ( num == EVENT_OBJECT_CAMERAright) strcpy(text, "Camera to right");
+ if ( num == EVENT_OBJECT_CAMERAnear) strcpy(text, "Camera nearest");
+ if ( num == EVENT_OBJECT_CAMERAaway) strcpy(text, "Camera awayest");
+ if ( num == EVENT_OBJECT_HELP ) strcpy(text, "Pomoc na temat zaznaczonego obiektu");
+ if ( num == EVENT_OBJECT_SOLUCE ) strcpy(text, "Poka¿ rozwi¹zanie");
+ if ( num == EVENT_OBJECT_SHORTCUT00) strcpy(text, "Prze³¹cz roboty <-> budynki");
+ if ( num == EVENT_OBJECT_LIMIT ) strcpy(text, "Poka¿ zasiêg");
+ if ( num == EVENT_OBJECT_PEN0 ) strcpy(text, "\\Relève le crayon");
+ if ( num == EVENT_OBJECT_PEN1 ) strcpy(text, "\\Abaisse le crayon noir");
+ if ( num == EVENT_OBJECT_PEN2 ) strcpy(text, "\\Abaisse le crayon jaune");
+ if ( num == EVENT_OBJECT_PEN3 ) strcpy(text, "\\Abaisse le crayon orange");
+ if ( num == EVENT_OBJECT_PEN4 ) strcpy(text, "\\Abaisse le crayon rouge");
+ if ( num == EVENT_OBJECT_PEN5 ) strcpy(text, "\\Abaisse le crayon violet");
+ if ( num == EVENT_OBJECT_PEN6 ) strcpy(text, "\\Abaisse le crayon bleu");
+ if ( num == EVENT_OBJECT_PEN7 ) strcpy(text, "\\Abaisse le crayon vert");
+ if ( num == EVENT_OBJECT_PEN8 ) strcpy(text, "\\Abaisse le crayon brun");
+ if ( num == EVENT_OBJECT_REC ) strcpy(text, "\\Démarre l'enregistrement");
+ if ( num == EVENT_OBJECT_STOP ) strcpy(text, "\\Stoppe l'enregistrement");
+ if ( num == EVENT_DT_VISIT0 ||
+ num == EVENT_DT_VISIT1 ||
+ num == EVENT_DT_VISIT2 ||
+ num == EVENT_DT_VISIT3 ||
+ num == EVENT_DT_VISIT4 ) strcpy(text, "Poka¿ miejsce");
+ if ( num == EVENT_DT_END ) strcpy(text, "Kontynuuj");
+ if ( num == EVENT_CMD ) strcpy(text, "Linia polecenia");
+ if ( num == EVENT_SPEED ) strcpy(text, "Prêdkoœæ gry");
+
+ if ( num == EVENT_HYPER_PREV ) strcpy(text, "Wstecz");
+ if ( num == EVENT_HYPER_NEXT ) strcpy(text, "Naprzód");
+ if ( num == EVENT_HYPER_HOME ) strcpy(text, "Pocz¹tek");
+ if ( num == EVENT_HYPER_COPY ) strcpy(text, "Kopiuj");
+ if ( num == EVENT_HYPER_SIZE1 ) strcpy(text, "WielkoϾ 1");
+ if ( num == EVENT_HYPER_SIZE2 ) strcpy(text, "WielkoϾ 2");
+ if ( num == EVENT_HYPER_SIZE3 ) strcpy(text, "WielkoϾ 3");
+ if ( num == EVENT_HYPER_SIZE4 ) strcpy(text, "WielkoϾ 4");
+ if ( num == EVENT_HYPER_SIZE5 ) strcpy(text, "WielkoϾ 5");
+ if ( num == EVENT_SATCOM_HUSTON ) strcpy(text, "Rozkazy z Houston");
+#if _TEEN
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Raport z satelity");
+#else
+ if ( num == EVENT_SATCOM_SAT ) strcpy(text, "Raport z satelity");
+#endif
+ if ( num == EVENT_SATCOM_LOADING ) strcpy(text, "Program dostarczony z Houston");
+ if ( num == EVENT_SATCOM_OBJECT ) strcpy(text, "Lista obiektów");
+ if ( num == EVENT_SATCOM_PROG ) strcpy(text, "Podrêcznik programowania");
+ if ( num == EVENT_SATCOM_SOLUCE ) strcpy(text, "Rozwi¹zanie");
+
+ if ( num == EVENT_STUDIO_OK ) strcpy(text, "OK\\Zamyka edytor programu i powraca do gry");
+ if ( num == EVENT_STUDIO_CANCEL ) strcpy(text, "Anuluj\\Pomija wszystkie zmiany");
+ if ( num == EVENT_STUDIO_NEW ) strcpy(text, "Nowy");
+ if ( num == EVENT_STUDIO_OPEN ) strcpy(text, "Otwórz (Ctrl+O)");
+ if ( num == EVENT_STUDIO_SAVE ) strcpy(text, "Zapisz (Ctrl+S)");
+ if ( num == EVENT_STUDIO_UNDO ) strcpy(text, "Cofnij (Ctrl+Z)");
+ if ( num == EVENT_STUDIO_CUT ) strcpy(text, "Wytnij (Ctrl+X)");
+ if ( num == EVENT_STUDIO_COPY ) strcpy(text, "Kopiuj (Ctrl+C)");
+ if ( num == EVENT_STUDIO_PASTE ) strcpy(text, "Wklej (Ctrl+V)");
+ if ( num == EVENT_STUDIO_SIZE ) strcpy(text, "WielkoϾ czcionki");
+ if ( num == EVENT_STUDIO_TOOL ) strcpy(text, "Rozkazy (\\key help;)");
+ if ( num == EVENT_STUDIO_HELP ) strcpy(text, "Podrêcznik programowania (\\key prog;)");
+ if ( num == EVENT_STUDIO_COMPILE ) strcpy(text, "Kompiluj");
+ if ( num == EVENT_STUDIO_RUN ) strcpy(text, "Wykonaj/Zatrzymaj");
+ if ( num == EVENT_STUDIO_REALTIME ) strcpy(text, "Pauza/Kontynuuj");
+ if ( num == EVENT_STUDIO_STEP ) strcpy(text, "Jeden krok");
+ }
+
+ if ( type == RES_OBJECT )
+ {
+ if ( num == OBJECT_PORTICO ) strcpy(text, "¯uraw przesuwalny");
+ if ( num == OBJECT_BASE ) strcpy(text, "Statek kosmiczny");
+ if ( num == OBJECT_DERRICK ) strcpy(text, "Kopalnia");
+ if ( num == OBJECT_FACTORY ) strcpy(text, "Fabryka robotów");
+ if ( num == OBJECT_REPAIR ) strcpy(text, "Warsztat");
+ if ( num == OBJECT_DESTROYER ) strcpy(text, "Destroyer");
+ if ( num == OBJECT_STATION ) strcpy(text, "Stacja energetyczna");
+ if ( num == OBJECT_CONVERT ) strcpy(text, "Przetop rudê na tytan");
+ if ( num == OBJECT_TOWER ) strcpy(text, "Wie¿a obronna");
+ if ( num == OBJECT_NEST ) strcpy(text, "Gniazdo");
+ if ( num == OBJECT_RESEARCH ) strcpy(text, "Centrum badawcze");
+ if ( num == OBJECT_RADAR ) strcpy(text, "Stacja radarowa");
+ if ( num == OBJECT_INFO ) strcpy(text, "Stacja przekaŸnikowa informacji");
+#if _TEEN
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Fabryka ogniw elektrycznych");
+#else
+ if ( num == OBJECT_ENERGY ) strcpy(text, "Fabryka ogniw elektrycznych");
+#endif
+ if ( num == OBJECT_LABO ) strcpy(text, "Laboratorium");
+ if ( num == OBJECT_NUCLEAR ) strcpy(text, "Elektrownia atomowa");
+ if ( num == OBJECT_PARA ) strcpy(text, "Odgromnik");
+ if ( num == OBJECT_SAFE ) strcpy(text, "Skrytka");
+ if ( num == OBJECT_HUSTON ) strcpy(text, "Centrum Kontroli Misji w Houston");
+ if ( num == OBJECT_TARGET1 ) strcpy(text, "Cel");
+ if ( num == OBJECT_TARGET2 ) strcpy(text, "Cel");
+ if ( num == OBJECT_START ) strcpy(text, "Pocz¹tek");
+ if ( num == OBJECT_END ) strcpy(text, "Koniec");
+ if ( num == OBJECT_STONE ) strcpy(text, "Ruda tytanu");
+ if ( num == OBJECT_URANIUM ) strcpy(text, "Ruda uranu");
+ if ( num == OBJECT_BULLET ) strcpy(text, "Materia organiczna");
+ if ( num == OBJECT_METAL ) strcpy(text, "Tytan");
+ if ( num == OBJECT_POWER ) strcpy(text, "Ogniwo elektryczne");
+ if ( num == OBJECT_ATOMIC ) strcpy(text, "Atomowe ogniwa elektryczne");
+ if ( num == OBJECT_BBOX ) strcpy(text, "Czarna skrzynka");
+ if ( num == OBJECT_KEYa ) strcpy(text, "Klucz A");
+ if ( num == OBJECT_KEYb ) strcpy(text, "Klucz B");
+ if ( num == OBJECT_KEYc ) strcpy(text, "Klucz C");
+ if ( num == OBJECT_KEYd ) strcpy(text, "Klucz D");
+ if ( num == OBJECT_TNT ) strcpy(text, "Materia³y wybuchowe");
+ if ( num == OBJECT_BOMB ) strcpy(text, "Mina");
+ if ( num == OBJECT_BAG ) strcpy(text, "Zestaw przetrwania");
+ if ( num == OBJECT_WAYPOINT ) strcpy(text, "Punkt kontrolny");
+ if ( num == OBJECT_FLAGb ) strcpy(text, "Niebieska flaga");
+ if ( num == OBJECT_FLAGr ) strcpy(text, "Czerwona flaga");
+ if ( num == OBJECT_FLAGg ) strcpy(text, "Zielona flaga");
+ if ( num == OBJECT_FLAGy ) strcpy(text, "¯ó³ta flaga");
+ if ( num == OBJECT_FLAGv ) strcpy(text, "Fioletowa flaga");
+ if ( num == OBJECT_MARKPOWER ) strcpy(text, "ród³o energii (miejsce na elektrowniê)");
+ if ( num == OBJECT_MARKURANIUM ) strcpy(text, "Z³o¿e uranu (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYa ) strcpy(text, "Znaleziono klucz A (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYb ) strcpy(text, "Znaleziono klucz B (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYc ) strcpy(text, "Znaleziono klucz C (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKKEYd ) strcpy(text, "Znaleziono klucz D (miejsce na kopalniê)");
+ if ( num == OBJECT_MARKSTONE ) strcpy(text, "Z³o¿e tytanu (miejsce na kopalniê)");
+ if ( num == OBJECT_MOBILEft ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEtt ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEwt ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEit ) strcpy(text, "Robot treningowy");
+ if ( num == OBJECT_MOBILEfa ) strcpy(text, "Transporter lataj¹cy");
+ if ( num == OBJECT_MOBILEta ) strcpy(text, "Transporter na g¹sienicach");
+ if ( num == OBJECT_MOBILEwa ) strcpy(text, "Transporter na ko³ach");
+ if ( num == OBJECT_MOBILEia ) strcpy(text, "Transporter na nogach");
+ if ( num == OBJECT_MOBILEfc ) strcpy(text, "Dzia³o lataj¹ce");
+ if ( num == OBJECT_MOBILEtc ) strcpy(text, "Dzia³o na g¹sienicach");
+ if ( num == OBJECT_MOBILEwc ) strcpy(text, "Dzia³o na ko³ach");
+ if ( num == OBJECT_MOBILEic ) strcpy(text, "Dzia³o na nogach");
+ if ( num == OBJECT_MOBILEfi ) strcpy(text, "Lataj¹ce dzia³o organiczne");
+ if ( num == OBJECT_MOBILEti ) strcpy(text, "Dzia³o organiczne na g¹sienicach");
+ if ( num == OBJECT_MOBILEwi ) strcpy(text, "Dzia³o organiczne na ko³ach");
+ if ( num == OBJECT_MOBILEii ) strcpy(text, "Dzia³o organiczne na nogach");
+ if ( num == OBJECT_MOBILEfs ) strcpy(text, "Szperacz lataj¹cy");
+ if ( num == OBJECT_MOBILEts ) strcpy(text, "Szperacz na g¹sienicach");
+ if ( num == OBJECT_MOBILEws ) strcpy(text, "Szperacz na ko³ach");
+ if ( num == OBJECT_MOBILEis ) strcpy(text, "Szperacz na nogach");
+ if ( num == OBJECT_MOBILErt ) strcpy(text, "Uderzacz");
+ if ( num == OBJECT_MOBILErc ) strcpy(text, "Dzia³o fazowe");
+ if ( num == OBJECT_MOBILErr ) strcpy(text, "Recykler");
+ if ( num == OBJECT_MOBILErs ) strcpy(text, "Os³aniacz");
+ if ( num == OBJECT_MOBILEsa ) strcpy(text, "Robot nurek");
+ if ( num == OBJECT_MOBILEtg ) strcpy(text, "Robot cel");
+ if ( num == OBJECT_MOBILEdr ) strcpy(text, "Drawer bot");
+ if ( num == OBJECT_HUMAN ) strcpy(text, g_gamerName);
+ if ( num == OBJECT_TECH ) strcpy(text, "In¿ynier");
+ if ( num == OBJECT_TOTO ) strcpy(text, "Robbie");
+ if ( num == OBJECT_MOTHER ) strcpy(text, "Królowa Obcych");
+ if ( num == OBJECT_ANT ) strcpy(text, "Mrówka");
+ if ( num == OBJECT_SPIDER ) strcpy(text, "Paj¹k");
+ if ( num == OBJECT_BEE ) strcpy(text, "Osa");
+ if ( num == OBJECT_WORM ) strcpy(text, "Robal");
+ if ( num == OBJECT_EGG ) strcpy(text, "Jajo");
+ if ( num == OBJECT_RUINmobilew1 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobilew2 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobilet1 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobilet2 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobiler1 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINmobiler2 ) strcpy(text, "Wrak");
+ if ( num == OBJECT_RUINfactory ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINdoor ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINsupport ) strcpy(text, "Odpady");
+ if ( num == OBJECT_RUINradar ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINconvert ) strcpy(text, "Ruiny");
+ if ( num == OBJECT_RUINbase ) strcpy(text, "Ruiny statku kosmicznego");
+ if ( num == OBJECT_RUINhead ) strcpy(text, "Ruiny statku kosmicznego");
+ if ( num == OBJECT_APOLLO1 ||
+ num == OBJECT_APOLLO3 ||
+ num == OBJECT_APOLLO4 ||
+ num == OBJECT_APOLLO5 ) strcpy(text, "Pozosta³oœci z misji Apollo");
+ if ( num == OBJECT_APOLLO2 ) strcpy(text, "Pojazd Ksiê¿ycowy");
+ }
+
+ if ( type == RES_ERR )
+ {
+ strcpy(text, "B³¹d");
+ if ( num == ERR_CMD ) strcpy(text, "Nieznane polecenie");
+#if _NEWLOOK
+ if ( num == ERR_INSTALL ) strcpy(text, "Gra CeeBot nie jest zainstalowana.");
+ if ( num == ERR_NOCD ) strcpy(text, "W³ó¿ dysk CD z gr¹ CeeBot\ni uruchom grê jeszcze raz.");
+#else
+ if ( num == ERR_INSTALL ) strcpy(text, "Gra COLOBOT nie jest zainstalowana.");
+ if ( num == ERR_NOCD ) strcpy(text, "W³ó¿ dysk CD z gr¹ COLOBOT\ni uruchom grê jeszcze raz.");
+#endif
+ if ( num == ERR_MANIP_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_MANIP_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_MANIP_BUSY ) strcpy(text, "Nie mo¿na nieœæ wiêcej przedmiotów");
+ if ( num == ERR_MANIP_NIL ) strcpy(text, "Nie ma nic do podniesienia");
+ if ( num == ERR_MANIP_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_MANIP_OCC ) strcpy(text, "Miejsce zajête");
+ if ( num == ERR_MANIP_FRIEND ) strcpy(text, "Brak innego robota");
+ if ( num == ERR_MANIP_RADIO ) strcpy(text, "Nie mo¿esz przenosiæ przedmiotów radioaktywnych");
+ if ( num == ERR_MANIP_WATER ) strcpy(text, "Nie mo¿esz przenosiæ przedmiotów pod wod¹");
+ if ( num == ERR_MANIP_EMPTY ) strcpy(text, "Nie ma nic do upuszczenia");
+ if ( num == ERR_BUILD_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_BUILD_WATER ) strcpy(text, "Niemo¿liwe pod wod¹");
+ if ( num == ERR_BUILD_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_BUILD_METALAWAY ) strcpy(text, "Tytan za daleko");
+ if ( num == ERR_BUILD_METALNEAR ) strcpy(text, "Tytan za blisko");
+ if ( num == ERR_BUILD_METALINEX ) strcpy(text, "Brak tytanu w pobli¿u");
+ if ( num == ERR_BUILD_FLAT ) strcpy(text, "Powierzchnia nie jest wystarczaj¹co p³aska");
+ if ( num == ERR_BUILD_FLATLIT ) strcpy(text, "Za ma³o p³askiego terenu");
+ if ( num == ERR_BUILD_BUSY ) strcpy(text, "Miejsce zajête");
+ if ( num == ERR_BUILD_BASE ) strcpy(text, "Za blisko statku kosmicznego");
+ if ( num == ERR_BUILD_NARROW ) strcpy(text, "Za blisko budynku");
+ if ( num == ERR_BUILD_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_SEARCH_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_SEARCH_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_SEARCH_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_TERRA_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_TERRA_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_TERRA_FLOOR ) strcpy(text, "Nieodpowiedni teren");
+ if ( num == ERR_TERRA_BUILDING ) strcpy(text, "Budynek za blisko");
+ if ( num == ERR_TERRA_OBJECT ) strcpy(text, "Obiekt za blisko");
+ if ( num == ERR_RECOVER_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_RECOVER_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_RECOVER_NULL ) strcpy(text, "Nie ma niczego do odzysku");
+ if ( num == ERR_SHIELD_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_SHIELD_ENERGY ) strcpy(text, "Nie ma wiêcej energii");
+ if ( num == ERR_MOVE_IMPOSSIBLE ) strcpy(text, "B³¹d w poleceniu ruchu");
+ if ( num == ERR_FIND_IMPOSSIBLE ) strcpy(text, "Obiekt nieznany");
+ if ( num == ERR_GOTO_IMPOSSIBLE ) strcpy(text, "Goto: miejsce docelowe niedostêpne");
+ if ( num == ERR_GOTO_ITER ) strcpy(text, "Goto: miejsce docelowe niedostêpne");
+ if ( num == ERR_GOTO_BUSY ) strcpy(text, "Goto: miejsce docelowe zajête");
+ if ( num == ERR_FIRE_VEH ) strcpy(text, "Nieodpowiedni robot");
+ if ( num == ERR_FIRE_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_FIRE_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_CONVERT_EMPTY ) strcpy(text, "Brak rudy tytanu do przetopienia");
+ if ( num == ERR_DERRICK_NULL ) strcpy(text, "W ziemi nie ma ¿adnej rudy");
+ if ( num == ERR_STATION_NULL ) strcpy(text, "Brak energii w ziemi");
+ if ( num == ERR_TOWER_POWER ) strcpy(text, "Brak ogniwa elektrycznego");
+ if ( num == ERR_TOWER_ENERGY ) strcpy(text, "Nie ma wiêcej energii");
+ if ( num == ERR_RESEARCH_POWER ) strcpy(text, "Brak ogniwa elektrycznego");
+ if ( num == ERR_RESEARCH_ENERGY ) strcpy(text, "Za ma³o energii");
+ if ( num == ERR_RESEARCH_TYPE ) strcpy(text, "Nieodpowiedni rodzaj ogniw");
+ if ( num == ERR_RESEARCH_ALREADY) strcpy(text, "Program badawczy zosta³ ju¿ wykonany");
+ if ( num == ERR_ENERGY_NULL ) strcpy(text, "Brak energii w ziemi");
+ if ( num == ERR_ENERGY_LOW ) strcpy(text, "Wci¹¿ za ma³o energii");
+ if ( num == ERR_ENERGY_EMPTY ) strcpy(text, "Brak tytanu do przetworzenia");
+ if ( num == ERR_ENERGY_BAD ) strcpy(text, "Przetwarza jedynie tytan");
+ if ( num == ERR_BASE_DLOCK ) strcpy(text, "Drzwi zablokowane przez robota lub inny obiekt ");
+ if ( num == ERR_BASE_DHUMAN ) strcpy(text, "Musisz byæ na statku kosmicznym aby nim odlecieæ");
+ if ( num == ERR_LABO_NULL ) strcpy(text, "Nie ma niczego do zanalizowania");
+ if ( num == ERR_LABO_BAD ) strcpy(text, "Analizuje jedynie materiê organiczn¹");
+ if ( num == ERR_LABO_ALREADY ) strcpy(text, "Analiza zosta³a ju¿ wykonana");
+ if ( num == ERR_NUCLEAR_NULL ) strcpy(text, "Brak energii w ziemi");
+ if ( num == ERR_NUCLEAR_LOW ) strcpy(text, "Wci¹¿ za ma³o energii");
+ if ( num == ERR_NUCLEAR_EMPTY ) strcpy(text, "Brak uranu do przetworzenia");
+ if ( num == ERR_NUCLEAR_BAD ) strcpy(text, "Przetwarza jedynie uran");
+ if ( num == ERR_FACTORY_NULL ) strcpy(text, "Brak tytanu");
+ if ( num == ERR_FACTORY_NEAR ) strcpy(text, "Obiekt za blisko");
+ if ( num == ERR_RESET_NEAR ) strcpy(text, "Miejsce zajête");
+ if ( num == ERR_INFO_NULL ) strcpy(text, "Nie ma ¿adnej stacji przekaŸnikowej w zasiêgu");
+ if ( num == ERR_VEH_VIRUS ) strcpy(text, "Program zawirusowany");
+ if ( num == ERR_BAT_VIRUS ) strcpy(text, "Zainfekowane wirusem, chwilowo niesprawne");
+ if ( num == ERR_VEH_POWER ) strcpy(text, "Brak ogniwa elektrycznego");
+ if ( num == ERR_VEH_ENERGY ) strcpy(text, "Nie ma wiêcej energii");
+ if ( num == ERR_FLAG_FLY ) strcpy(text, "Niemo¿liwe podczas lotu");
+ if ( num == ERR_FLAG_WATER ) strcpy(text, "Niemo¿liwe podczas p³ywania");
+ if ( num == ERR_FLAG_MOTOR ) strcpy(text, "Niemo¿liwe podczas ruchu");
+ if ( num == ERR_FLAG_BUSY ) strcpy(text, "Niemo¿liwe podczas przenoszenia przedmiotu");
+ if ( num == ERR_FLAG_CREATE ) strcpy(text, "Za du¿o flag w tym kolorze (maksymalnie 5)");
+ if ( num == ERR_FLAG_PROXY ) strcpy(text, "Za blisko istniej¹cej flagi");
+ if ( num == ERR_FLAG_DELETE ) strcpy(text, "Nie ma flagi w pobli¿u");
+ if ( num == ERR_MISSION_NOTERM ) strcpy(text, "Misja nie jest wype³niona (naciœnij \\key help; aby uzyskaæ szczegó³y)");
+ if ( num == ERR_DELETEMOBILE ) strcpy(text, "Robot zniszczony");
+ if ( num == ERR_DELETEBUILDING ) strcpy(text, "Budynek zniszczony");
+ if ( num == ERR_TOOMANY ) strcpy(text, "Nie mo¿na tego utworzyæ, za du¿o obiektów");
+ if ( num == ERR_OBLIGATORYTOKEN ) strcpy(text, "It misses \"%s\" in this exercise");
+ if ( num == ERR_PROHIBITEDTOKEN ) strcpy(text, "Do not use in this exercise");
+
+ if ( num == INFO_BUILD ) strcpy(text, "Budowa zakoñczona");
+ if ( num == INFO_CONVERT ) strcpy(text, "Tytan dostêpny");
+ if ( num == INFO_RESEARCH ) strcpy(text, "Program badawczy zakoñczony");
+ if ( num == INFO_RESEARCHTANK ) strcpy(text, "Dostêpne plany tranporterów na g¹sienicach");
+ if ( num == INFO_RESEARCHFLY ) strcpy(text, "Mo¿esz lataæ u¿ywaj¹c klawiszy (\\key gup;) oraz (\\key gdown;)");
+ if ( num == INFO_RESEARCHTHUMP ) strcpy(text, "Dostêpne plany robota uderzacza");
+ if ( num == INFO_RESEARCHCANON ) strcpy(text, "Dostêpne plany dzia³a");
+ if ( num == INFO_RESEARCHTOWER ) strcpy(text, "Dostêpne plany wie¿y obronnej");
+ if ( num == INFO_RESEARCHPHAZER ) strcpy(text, "Dostêpne plany dzia³a fazowego");
+ if ( num == INFO_RESEARCHSHIELD ) strcpy(text, "Dostêpne plany robota os³aniacza");
+ if ( num == INFO_RESEARCHATOMIC ) strcpy(text, "Dostêpne plany elektrowni atomowej");
+ if ( num == INFO_FACTORY ) strcpy(text, "Dostêpny nowy robot");
+ if ( num == INFO_LABO ) strcpy(text, "Analiza wykonana");
+ if ( num == INFO_ENERGY ) strcpy(text, "Wytworzono ogniwo elektryczne");
+ if ( num == INFO_NUCLEAR ) strcpy(text, "Wytworzono atomowe ogniwo elektryczne");
+ if ( num == INFO_FINDING ) strcpy(text, "Znaleziono u¿yteczny przedmiot");
+ if ( num == INFO_MARKPOWER ) strcpy(text, "Znaleziono miejsce na elektrowniê");
+ if ( num == INFO_MARKURANIUM ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKSTONE ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYa ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYb ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYc ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_MARKKEYd ) strcpy(text, "Znaleziono miejsce na kopalniê");
+ if ( num == INFO_WIN ) strcpy(text, "<<< Dobra robota, misja wype³niona >>>");
+ if ( num == INFO_LOST ) strcpy(text, "<<< Niestety, misja nie powiod³a siê >>>");
+ if ( num == INFO_LOSTq ) strcpy(text, "<<< Niestety, misja nie powiod³a siê >>>");
+ if ( num == INFO_WRITEOK ) strcpy(text, "Bie¿¹ca misja zapisana");
+ if ( num == INFO_DELETEPATH ) strcpy(text, "Przekroczono punkt kontrolny");
+ if ( num == INFO_DELETEMOTHER ) strcpy(text, "Królowa Obcych zosta³a zabita");
+ if ( num == INFO_DELETEANT ) strcpy(text, "Mrówka œmiertelnie raniona");
+ if ( num == INFO_DELETEBEE ) strcpy(text, "Osa œmiertelnie raniona");
+ if ( num == INFO_DELETEWORM ) strcpy(text, "Robal œmiertelnie raniony");
+ if ( num == INFO_DELETESPIDER ) strcpy(text, "Paj¹k œmiertelnie raniony");
+ if ( num == INFO_BEGINSATCOM ) strcpy(text, "Naciœnij klawisz \\key help; aby wyœwietliæ rozkazy na przekaŸniku SatCom");
+ }
+
+ if ( type == RES_CBOT )
+ {
+ strcpy(text, "B³¹d");
+ if ( num == TX_OPENPAR ) strcpy(text, "Brak nawiasu otwieraj¹cego");
+ if ( num == TX_CLOSEPAR ) strcpy(text, "Brak nawiasu zamykaj¹cego");
+ if ( num == TX_NOTBOOL ) strcpy(text, "Wyra¿enie musi zwróciæ wartoœæ logiczn¹");
+ if ( num == TX_UNDEFVAR ) strcpy(text, "Zmienna nie zosta³a zadeklarowana");
+ if ( num == TX_BADLEFT ) strcpy(text, "Przypisanie niemo¿liwe");
+ if ( num == TX_ENDOF ) strcpy(text, "Brak œrednika na koñcu wiersza");
+ if ( num == TX_OUTCASE ) strcpy(text, "Polecenie ""case"" na zewn¹trz bloku ""switch""");
+ if ( num == TX_NOTERM ) strcpy(text, "Polecenie po koñcowej klamrze zamykaj¹cej");
+ if ( num == TX_CLOSEBLK ) strcpy(text, "Brak koñca bloku");
+ if ( num == TX_ELSEWITHOUTIF ) strcpy(text, "Polecenie ""else"" bez wyst¹pienia ""if"" ");
+ if ( num == TX_OPENBLK ) strcpy(text, "Brak klamry otwieraj¹cej");//début d'un bloc attendu?
+ if ( num == TX_BADTYPE ) strcpy(text, "Z³y typ dla przypisania");
+ if ( num == TX_REDEFVAR ) strcpy(text, "Zmienna nie mo¿e byæ zadeklarowana dwukrotnie");
+ if ( num == TX_BAD2TYPE ) strcpy(text, "Niezgodne typy operatorów");
+ if ( num == TX_UNDEFCALL ) strcpy(text, "Funkcja nieznana");
+ if ( num == TX_MISDOTS ) strcpy(text, "Brak znaku "" : ");
+ if ( num == TX_WHILE ) strcpy(text, "Brak kluczowego s³owa ""while");
+ if ( num == TX_BREAK ) strcpy(text, "Polecenie ""break"" na zewn¹trz pêtli");
+ if ( num == TX_LABEL ) strcpy(text, "Po etykiecie musi wyst¹piæ ""for"", ""while"", ""do"" lub ""switch""");
+ if ( num == TX_NOLABEL ) strcpy(text, "Taka etykieta nie istnieje");// Cette étiquette n'existe pas
+ if ( num == TX_NOCASE ) strcpy(text, "Brak polecenia ""case");
+ if ( num == TX_BADNUM ) strcpy(text, "Brak liczby");
+ if ( num == TX_VOID ) strcpy(text, "Pusty parametr");
+ if ( num == TX_NOTYP ) strcpy(text, "Brak deklaracji typu");
+ if ( num == TX_NOVAR ) strcpy(text, "Brak nazwy zmiennej");
+ if ( num == TX_NOFONC ) strcpy(text, "Brakuj¹ca nazwa funkcji");
+ if ( num == TX_OVERPARAM ) strcpy(text, "Za du¿o parametrów");
+ if ( num == TX_REDEF ) strcpy(text, "Funkcja ju¿ istnieje");
+ if ( num == TX_LOWPARAM ) strcpy(text, "Brak wymaganego parametru");
+ if ( num == TX_BADPARAM ) strcpy(text, "Funkcja o tej nazwie nie akceptuje parametrów tego typu");
+ if ( num == TX_NUMPARAM ) strcpy(text, "Funkcja o tej nazwie nie akceptuje takiej liczby parametrów");
+ if ( num == TX_NOITEM ) strcpy(text, "To nie jest obiekt tej klasy");
+ if ( num == TX_DOT ) strcpy(text, "Ten obiekt nie jest cz³onkiem klasy");
+ if ( num == TX_NOCONST ) strcpy(text, "Brak odpowiedniego konstruktora");
+ if ( num == TX_REDEFCLASS ) strcpy(text, "Taka klasa ju¿ istnieje");
+ if ( num == TX_CLBRK ) strcpy(text, "Brak "" ] """);
+ if ( num == TX_RESERVED ) strcpy(text, "S³owo zarezerwowane jêzyka CBOT");
+ if ( num == TX_BADNEW ) strcpy(text, "Z³y argument dla funkcji ""new""");
+ if ( num == TX_OPBRK ) strcpy(text, "Oczekiwane "" [ """);
+ if ( num == TX_BADSTRING ) strcpy(text, "Brak ³añcucha");
+ if ( num == TX_BADINDEX ) strcpy(text, "Nieprawid³owy typ indeksu");
+ if ( num == TX_PRIVATE ) strcpy(text, "Element prywatny");
+ if ( num == TX_NOPUBLIC ) strcpy(text, "Wymagany publiczny");
+ if ( num == TX_DIVZERO ) strcpy(text, "Dzielenie przez zero");
+ if ( num == TX_NOTINIT ) strcpy(text, "Zmienna nie zosta³a zainicjalizowana");
+ if ( num == TX_BADTHROW ) strcpy(text, "Wartoœæ ujemna odrzucona przez ""throw""");//C'est quoi, ça?
+ if ( num == TX_NORETVAL ) strcpy(text, "Funkcja nie zwróci³a ¿adnej wartoœci ");
+ if ( num == TX_NORUN ) strcpy(text, "¯adna funkcja nie dzia³a");
+ if ( num == TX_NOCALL ) strcpy(text, "Odwo³anie do nieznanej funkcji");
+ if ( num == TX_NOCLASS ) strcpy(text, "Taka klasa nie istnieje");
+ if ( num == TX_NULLPT ) strcpy(text, "Obiekt nieznany");
+ if ( num == TX_OPNAN ) strcpy(text, "Dzia³anie niemo¿liwe z wartoœci¹ ""nan""");
+ if ( num == TX_OUTARRAY ) strcpy(text, "Dostêp poza tablicê");
+ if ( num == TX_STACKOVER ) strcpy(text, "Przepe³nienie stosu");
+ if ( num == TX_DELETEDPT ) strcpy(text, "Nieprawid³owy obiekt");
+ if ( num == TX_FILEOPEN ) strcpy(text, "Nie mo¿na otworzyæ pliku");
+ if ( num == TX_NOTOPEN ) strcpy(text, "Plik nie jest otwarty");
+ if ( num == TX_ERRREAD ) strcpy(text, "B³¹d odczytu");
+ if ( num == TX_ERRWRITE ) strcpy(text, "B³¹d zapisu");
+ }
+
+ if ( type == RES_KEY )
+ {
+ if ( num == 0 ) strcpy(text, "< brak >");
+ if ( num == VK_LEFT ) strcpy(text, "Strza³ka w lewo");
+ if ( num == VK_RIGHT ) strcpy(text, "Strza³ka w prawo");
+ if ( num == VK_UP ) strcpy(text, "Strza³ka w górê");
+ if ( num == VK_DOWN ) strcpy(text, "Strza³ka w dó³");
+ if ( num == VK_CANCEL ) strcpy(text, "Ctrl-break");
+ if ( num == VK_BACK ) strcpy(text, "<--");
+ if ( num == VK_TAB ) strcpy(text, "Tab");
+ if ( num == VK_CLEAR ) strcpy(text, "Delete");
+ if ( num == VK_RETURN ) strcpy(text, "Enter");
+ if ( num == VK_SHIFT ) strcpy(text, "Shift");
+ if ( num == VK_CONTROL ) strcpy(text, "Ctrl");
+ if ( num == VK_MENU ) strcpy(text, "Alt");
+ if ( num == VK_PAUSE ) strcpy(text, "Pause");
+ if ( num == VK_CAPITAL ) strcpy(text, "Caps Lock");
+ if ( num == VK_ESCAPE ) strcpy(text, "Esc");
+ if ( num == VK_SPACE ) strcpy(text, "Spacja");
+ if ( num == VK_PRIOR ) strcpy(text, "Page Up");
+ if ( num == VK_NEXT ) strcpy(text, "Page Down");
+ if ( num == VK_END ) strcpy(text, "End");
+ if ( num == VK_HOME ) strcpy(text, "Home");
+ if ( num == VK_SELECT ) strcpy(text, "Zaznacz");
+ if ( num == VK_EXECUTE ) strcpy(text, "Wykonaj");
+ if ( num == VK_SNAPSHOT ) strcpy(text, "Print Scrn");
+ if ( num == VK_INSERT ) strcpy(text, "Insert");
+ if ( num == VK_DELETE ) strcpy(text, "Delete");
+ if ( num == VK_HELP ) strcpy(text, "Pomoc");
+ if ( num == VK_LWIN ) strcpy(text, "Lewy klawisz Windows");
+ if ( num == VK_RWIN ) strcpy(text, "Prawy klawisz Windows");
+ if ( num == VK_APPS ) strcpy(text, "Klawisz menu kontekstowego");
+ if ( num == VK_NUMPAD0 ) strcpy(text, "Klaw. Num. 0");
+ if ( num == VK_NUMPAD1 ) strcpy(text, "Klaw. Num. 1");
+ if ( num == VK_NUMPAD2 ) strcpy(text, "Klaw. Num. 2");
+ if ( num == VK_NUMPAD3 ) strcpy(text, "Klaw. Num. 3");
+ if ( num == VK_NUMPAD4 ) strcpy(text, "Klaw. Num. 4");
+ if ( num == VK_NUMPAD5 ) strcpy(text, "Klaw. Num. 5");
+ if ( num == VK_NUMPAD6 ) strcpy(text, "Klaw. Num. 6");
+ if ( num == VK_NUMPAD7 ) strcpy(text, "Klaw. Num. 7");
+ if ( num == VK_NUMPAD8 ) strcpy(text, "Klaw. Num. 8");
+ if ( num == VK_NUMPAD9 ) strcpy(text, "Klaw. Num. 9");
+ if ( num == VK_MULTIPLY ) strcpy(text, "Klaw. Num. *");
+ if ( num == VK_ADD ) strcpy(text, "Klaw. Num. +");
+ if ( num == VK_SEPARATOR ) strcpy(text, "Klaw. Num. separator");
+ if ( num == VK_SUBTRACT ) strcpy(text, "Klaw. Num. -");
+ if ( num == VK_DECIMAL ) strcpy(text, "Klaw. Num. .");
+ if ( num == VK_DIVIDE ) strcpy(text, "Klaw. Num. /");
+ if ( num == VK_F1 ) strcpy(text, "F1");
+ if ( num == VK_F2 ) strcpy(text, "F2");
+ if ( num == VK_F3 ) strcpy(text, "F3");
+ if ( num == VK_F4 ) strcpy(text, "F4");
+ if ( num == VK_F5 ) strcpy(text, "F5");
+ if ( num == VK_F6 ) strcpy(text, "F6");
+ if ( num == VK_F7 ) strcpy(text, "F7");
+ if ( num == VK_F8 ) strcpy(text, "F8");
+ if ( num == VK_F9 ) strcpy(text, "F9");
+ if ( num == VK_F10 ) strcpy(text, "F10");
+ if ( num == VK_F11 ) strcpy(text, "F11");
+ if ( num == VK_F12 ) strcpy(text, "F12");
+ if ( num == VK_F13 ) strcpy(text, "F13");
+ if ( num == VK_F14 ) strcpy(text, "F14");
+ if ( num == VK_F15 ) strcpy(text, "F15");
+ if ( num == VK_F16 ) strcpy(text, "F16");
+ if ( num == VK_F17 ) strcpy(text, "F17");
+ if ( num == VK_F18 ) strcpy(text, "F18");
+ if ( num == VK_F19 ) strcpy(text, "F19");
+ if ( num == VK_F20 ) strcpy(text, "F20");
+ if ( num == VK_NUMLOCK ) strcpy(text, "Num Lock");
+ if ( num == VK_SCROLL ) strcpy(text, "Scroll Lock");
+ if ( num == VK_ATTN ) strcpy(text, "Attn");
+ if ( num == VK_CRSEL ) strcpy(text, "CrSel");
+ if ( num == VK_EXSEL ) strcpy(text, "ExSel");
+ if ( num == VK_EREOF ) strcpy(text, "Erase EOF");
+ if ( num == VK_PLAY ) strcpy(text, "Graj");
+ if ( num == VK_ZOOM ) strcpy(text, "Powiêkszenie");
+ if ( num == VK_PA1 ) strcpy(text, "PA1");
+ if ( num == VK_OEM_CLEAR ) strcpy(text, "WyczyϾ");
+ if ( num == VK_BUTTON1 ) strcpy(text, "Przycisk 1");
+ if ( num == VK_BUTTON2 ) strcpy(text, "Przycisk 2");
+ if ( num == VK_BUTTON3 ) strcpy(text, "Przycisk 3");
+ if ( num == VK_BUTTON4 ) strcpy(text, "Przycisk 4");
+ if ( num == VK_BUTTON5 ) strcpy(text, "Przycisk 5");
+ if ( num == VK_BUTTON6 ) strcpy(text, "Przycisk 6");
+ if ( num == VK_BUTTON7 ) strcpy(text, "Przycisk 7");
+ if ( num == VK_BUTTON8 ) strcpy(text, "Przycisk 8");
+ if ( num == VK_BUTTON9 ) strcpy(text, "Przycisk 9");
+ if ( num == VK_BUTTON10 ) strcpy(text, "Przycisk 10");
+ if ( num == VK_BUTTON11 ) strcpy(text, "Przycisk 11");
+ if ( num == VK_BUTTON12 ) strcpy(text, "Przycisk 12");
+ if ( num == VK_BUTTON13 ) strcpy(text, "Przycisk 13");
+ if ( num == VK_BUTTON14 ) strcpy(text, "Przycisk 14");
+ if ( num == VK_BUTTON15 ) strcpy(text, "Przycisk 15");
+ if ( num == VK_BUTTON16 ) strcpy(text, "Przycisk 16");
+ if ( num == VK_BUTTON17 ) strcpy(text, "Przycisk 17");
+ if ( num == VK_BUTTON18 ) strcpy(text, "Przycisk 18");
+ if ( num == VK_BUTTON19 ) strcpy(text, "Przycisk 19");
+ if ( num == VK_BUTTON20 ) strcpy(text, "Przycisk 20");
+ if ( num == VK_BUTTON21 ) strcpy(text, "Przycisk 21");
+ if ( num == VK_BUTTON22 ) strcpy(text, "Przycisk 22");
+ if ( num == VK_BUTTON23 ) strcpy(text, "Przycisk 23");
+ if ( num == VK_BUTTON24 ) strcpy(text, "Przycisk 24");
+ if ( num == VK_BUTTON25 ) strcpy(text, "Przycisk 25");
+ if ( num == VK_BUTTON26 ) strcpy(text, "Przycisk 26");
+ if ( num == VK_BUTTON27 ) strcpy(text, "Przycisk 27");
+ if ( num == VK_BUTTON28 ) strcpy(text, "Przycisk 28");
+ if ( num == VK_BUTTON29 ) strcpy(text, "Przycisk 29");
+ if ( num == VK_BUTTON30 ) strcpy(text, "Przycisk 30");
+ if ( num == VK_BUTTON31 ) strcpy(text, "Przycisk 31");
+ if ( num == VK_BUTTON32 ) strcpy(text, "Przycisk 32");
+ if ( num == VK_WHEELUP ) strcpy(text, "Kó³ko w górê");
+ if ( num == VK_WHEELDOWN ) strcpy(text, "Kó³ko w dó³");
+ }
+#endif
+
+ return ( text[0] != 0 );
+}
+
+
diff --git a/src/restext.h b/src/restext.h
new file mode 100644
index 0000000..619e74a
--- /dev/null
+++ b/src/restext.h
@@ -0,0 +1,141 @@
+// restext.h
+
+#ifndef _RESTEXT_H_
+#define _RESTEXT_H_
+
+
+#define STRICT
+#define D3D_OVERLOADS
+
+
+
+enum KeyRank;
+
+
+// Types possibles pour les ressources texte.
+
+enum ResType
+{
+ RES_TEXT = 0, // RT_*
+ RES_EVENT = 1, // EVENT_* (EventMsg)
+ RES_OBJECT = 2, // OBJECT_* (ObjectType)
+ RES_ERR = 3, // ERR_* (Error)
+ RES_KEY = 4, // VK_* (touches)
+ RES_CBOT = 5, // TX_* (cbot.dll)
+};
+
+
+// Ressources de type RES_TEXT.
+
+#define RT_VERSION_ID 1
+#define RT_DISINFO_TITLE 2
+#define RT_WINDOW_MAXIMIZED 3
+#define RT_WINDOW_MINIMIZED 4
+#define RT_WINDOW_STANDARD 5
+#define RT_WINDOW_CLOSE 6
+
+#define RT_STUDIO_TITLE 10
+#define RT_SCRIPT_NEW 20
+#define RT_NAME_DEFAULT 21
+#define RT_IO_NEW 22
+#define RT_KEY_OR 23
+
+#define RT_TITLE_BASE 40
+#define RT_TITLE_INIT 41
+#define RT_TITLE_TRAINER 42
+#define RT_TITLE_DEFI 43
+#define RT_TITLE_MISSION 44
+#define RT_TITLE_FREE 45
+#define RT_TITLE_PROTO 46
+#define RT_TITLE_SETUP 47
+#define RT_TITLE_NAME 48
+#define RT_TITLE_PERSO 49
+#define RT_TITLE_WRITE 50
+#define RT_TITLE_READ 51
+#define RT_TITLE_USER 52
+#define RT_TITLE_TEEN 53
+
+#define RT_PLAY_CHAPt 60
+#define RT_PLAY_CHAPd 61
+#define RT_PLAY_CHAPm 62
+#define RT_PLAY_CHAPf 63
+#define RT_PLAY_CHAPp 64
+#define RT_PLAY_LISTt 65
+#define RT_PLAY_LISTd 66
+#define RT_PLAY_LISTm 67
+#define RT_PLAY_LISTf 68
+#define RT_PLAY_LISTp 69
+#define RT_PLAY_RESUME 70
+#define RT_PLAY_CHAPu 71
+#define RT_PLAY_LISTu 72
+#define RT_PLAY_CHAPte 73
+#define RT_PLAY_LISTk 74
+
+#define RT_SETUP_DEVICE 80
+#define RT_SETUP_MODE 81
+#define RT_SETUP_KEY1 82
+#define RT_SETUP_KEY2 83
+
+#define RT_PERSO_FACE 90
+#define RT_PERSO_GLASSES 91
+#define RT_PERSO_HAIR 92
+#define RT_PERSO_COMBI 93
+#define RT_PERSO_BAND 94
+
+#define RT_DIALOG_TITLE 100
+#define RT_DIALOG_ABORT 101
+#define RT_DIALOG_QUIT 102
+#define RT_DIALOG_YES 103
+#define RT_DIALOG_NO 104
+#define RT_DIALOG_DELOBJ 105
+#define RT_DIALOG_DELGAME 106
+#define RT_DIALOG_YESDEL 107
+#define RT_DIALOG_NODEL 108
+#define RT_DIALOG_LOADING 109
+#define RT_DIALOG_YESQUIT 110
+#define RT_DIALOG_NOQUIT 111
+
+#define RT_STUDIO_LISTTT 120
+#define RT_STUDIO_COMPOK 121
+#define RT_STUDIO_PROGSTOP 122
+
+#define RT_SATCOM_LIST 140
+#define RT_SATCOM_BOT 141
+#define RT_SATCOM_BUILDING 142
+#define RT_SATCOM_FRET 143
+#define RT_SATCOM_ALIEN 144
+#define RT_SATCOM_NULL 145
+#define RT_SATCOM_ERROR1 146
+#define RT_SATCOM_ERROR2 147
+
+#define RT_IO_OPEN 150
+#define RT_IO_SAVE 151
+#define RT_IO_LIST 152
+#define RT_IO_NAME 153
+#define RT_IO_DIR 154
+#define RT_IO_PRIVATE 155
+#define RT_IO_PUBLIC 156
+
+#define RT_GENERIC_DEV1 170
+#define RT_GENERIC_DEV2 171
+#define RT_GENERIC_EDIT1 172
+#define RT_GENERIC_EDIT2 173
+
+#define RT_INTERFACE_REC 180
+
+#define RT_MESSAGE_WIN 200
+#define RT_MESSAGE_LOST 201
+
+
+static CD3DEngine* g_engine = 0;
+static char g_gamerName[100];
+
+extern void SetEngine(CD3DEngine *engine);
+extern void SetGlobalGamerName(char *name);
+extern BOOL SearchKey(char *cmd, KeyRank &key);
+extern void PutKeyName(char* dst, char* src);
+extern BOOL GetResource(ResType type, int num, char* text);
+extern BOOL GetResourceBase(ResType type, int num, char* text);
+
+
+#endif //_RESTEXT_H_
diff --git a/src/robotmain.cpp b/src/robotmain.cpp
new file mode 100644
index 0000000..1f6a7a9
--- /dev/null
+++ b/src/robotmain.cpp
@@ -0,0 +1,7018 @@
+// robotmain.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "cbot/cbotdll.h"
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "profile.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "cloud.h"
+#include "blitz.h"
+#include "planet.h"
+#include "object.h"
+#include "motion.h"
+#include "motiontoto.h"
+#include "motionhuman.h"
+#include "physics.h"
+#include "brain.h"
+#include "pyro.h"
+#include "modfile.h"
+#include "model.h"
+#include "camera.h"
+#include "task.h"
+#include "taskmanip.h"
+#include "taskbuild.h"
+#include "auto.h"
+#include "autobase.h"
+#include "displayinfo.h"
+#include "interface.h"
+#include "shortcut.h"
+#include "map.h"
+#include "label.h"
+#include "button.h"
+#include "slider.h"
+#include "window.h"
+#include "edit.h"
+#include "displaytext.h"
+#include "text.h"
+#include "sound.h"
+#include "cbottoken.h"
+#include "cmdtoken.h"
+#include "mainmovie.h"
+#include "maindialog.h"
+#include "mainshort.h"
+#include "mainmap.h"
+#include "script.h"
+#include "robotmain.h"
+
+
+
+#define CBOT_STACK TRUE // enregistre le stack des programmes CBOT
+#define UNIT 4.0f
+
+
+
+// Variables globales.
+
+long g_id; // identificateur unique
+long g_build; // bâtiments constructibles
+long g_researchDone; // recherches effectuées
+long g_researchEnable; // recherches accessibles
+float g_unit; // facteur de conversion
+
+
+
+#include "classfile.cpp"
+
+
+
+// Compilation de la classe "point".
+
+CBotTypResult cPoint(CBotVar* pThis, CBotVar* &var)
+{
+ if ( !pThis->IsElemOfClass("point") ) return CBotTypResult(CBotErrBadNum);
+
+ if ( var == NULL ) return CBotTypResult(0); // ok si aucun paramètre
+
+ // Premier paramètre (x) :
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ // Deuxième paramètre (y) :
+ if ( var == NULL ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ // Troisième paramètre (z) :
+ if ( var == NULL ) // seulement 2 paramètres ?
+ {
+ return CBotTypResult(0); // cette fonction retourne void
+ }
+
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != NULL ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(0); // cette fonction retourne void
+}
+
+// Exécution de la classe "point".
+
+BOOL rPoint(CBotVar* pThis, CBotVar* var, CBotVar* pResult, int& Exception)
+{
+ CBotVar *pX, *pY, *pZ;
+
+ if ( var == NULL ) return TRUE; // constructeur sans paramètres est ok
+
+ if ( var->GivType() > CBotTypDouble )
+ {
+ Exception = CBotErrBadNum; return FALSE;
+ }
+
+ pX = pThis->GivItem("x");
+ if ( pX == NULL )
+ {
+ Exception = CBotErrUndefItem; return FALSE;
+ }
+ pX->SetValFloat( var->GivValFloat() );
+ var = var->GivNext();
+
+ if ( var == NULL )
+ {
+ Exception = CBotErrLowParam; return FALSE;
+ }
+
+ if ( var->GivType() > CBotTypDouble )
+ {
+ Exception = CBotErrBadNum; return FALSE;
+ }
+
+ pY = pThis->GivItem("y");
+ if ( pY == NULL )
+ {
+ Exception = CBotErrUndefItem; return FALSE;
+ }
+ pY->SetValFloat( var->GivValFloat() );
+ var = var->GivNext();
+
+ if ( var == NULL )
+ {
+ return TRUE; // ok avec seulement 2 paramètres
+ }
+
+ pZ = pThis->GivItem("z");
+ if ( pZ == NULL )
+ {
+ Exception = CBotErrUndefItem; return FALSE;
+ }
+ pZ->SetValFloat( var->GivValFloat() );
+ var = var->GivNext();
+
+ if ( var != NULL )
+ {
+ Exception = CBotErrOverParam; return FALSE;
+ }
+
+ return TRUE; // pas d'interruption
+}
+
+
+
+
+// Constructeur de l'application robot.
+
+CRobotMain::CRobotMain(CInstanceManager* iMan)
+{
+ ObjectType type;
+ float fValue;
+ int iValue, i;
+ char* token;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_MAIN, this);
+
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_cloud = (CCloud*)m_iMan->SearchInstance(CLASS_CLOUD);
+ m_blitz = (CBlitz*)m_iMan->SearchInstance(CLASS_BLITZ);
+ m_planet = (CPlanet*)m_iMan->SearchInstance(CLASS_PLANET);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_interface = new CInterface(m_iMan);
+ m_terrain = new CTerrain(m_iMan);
+ m_model = new CModel(m_iMan);
+ m_camera = new CCamera(m_iMan);
+ m_displayText = new CDisplayText(m_iMan);
+ m_movie = new CMainMovie(m_iMan);
+ m_dialog = new CMainDialog(m_iMan);
+ m_short = new CMainShort(m_iMan);
+ m_map = new CMainMap(m_iMan);
+ m_displayInfo = 0;
+
+ m_engine->SetTerrain(m_terrain);
+ m_filesDir = m_dialog->RetFilesDir();
+
+ m_time = 0.0f;
+ m_gameTime = 0.0f;
+ m_checkEndTime = 0.0f;
+
+ m_phase = PHASE_NAME;
+ m_cameraRank = -1;
+ m_visitLast = EVENT_NULL;
+ m_visitObject = 0;
+ m_visitArrow = 0;
+ m_audioTrack = 0;
+ m_bAudioRepeat = TRUE;
+ m_delayWriteMessage = 0;
+ m_selectObject = 0;
+ m_infoUsed = 0;
+
+ m_bBeginSatCom = FALSE;
+ m_bMovieLock = FALSE;
+ m_bSatComLock = FALSE;
+ m_bEditLock = FALSE;
+ m_bEditFull = FALSE;
+ m_bPause = FALSE;
+ m_bHilite = FALSE;
+ m_bFreePhoto = FALSE;
+ m_bShowPos = FALSE;
+ m_bSelectInsect = FALSE;
+ m_bShowSoluce = FALSE;
+ m_bShowAll = FALSE;
+ m_bCheatRadar = FALSE;
+ m_bFixScene = FALSE;
+ m_bTrainerPilot = FALSE;
+ m_bSuspend = FALSE;
+ m_bFriendAim = FALSE;
+ m_bResetCreate = FALSE;
+ m_bShortCut = TRUE;
+
+ m_engine->SetMovieLock(m_bMovieLock);
+
+ m_movie->Flush();
+ m_movieInfoIndex = -1;
+
+ m_tooltipPos = FPOINT(0.0f, 0.0f);
+ m_tooltipName[0] = 0;
+ m_tooltipTime = 0.0f;
+
+ m_endingWinRank = 0;
+ m_endingLostRank = 0;
+ m_bWinTerminate = FALSE;
+
+ FlushDisplayInfo();
+
+ m_fontSize = 9.0f;
+ m_windowPos = FPOINT(0.15f, 0.17f);
+ m_windowDim = FPOINT(0.70f, 0.66f);
+
+ if ( GetProfileFloat("Edit", "FontSize", fValue) ) m_fontSize = fValue;
+ if ( GetProfileFloat("Edit", "WindowPos.x", fValue) ) m_windowPos.x = fValue;
+ if ( GetProfileFloat("Edit", "WindowPos.y", fValue) ) m_windowPos.y = fValue;
+ if ( GetProfileFloat("Edit", "WindowDim.x", fValue) ) m_windowDim.x = fValue;
+ if ( GetProfileFloat("Edit", "WindowDim.y", fValue) ) m_windowDim.y = fValue;
+
+ m_IOPublic = FALSE;
+ m_IODim = FPOINT(320.0f/640.0f, (121.0f+18.0f*8)/480.0f);
+ m_IOPos.x = (1.0f-m_IODim.x)/2.0f; // au milieu
+ m_IOPos.y = (1.0f-m_IODim.y)/2.0f;
+
+ if ( GetProfileInt ("Edit", "IOPublic", iValue) ) m_IOPublic = iValue;
+ if ( GetProfileFloat("Edit", "IOPos.x", fValue) ) m_IOPos.x = fValue;
+ if ( GetProfileFloat("Edit", "IOPos.y", fValue) ) m_IOPos.y = fValue;
+ if ( GetProfileFloat("Edit", "IODim.x", fValue) ) m_IODim.x = fValue;
+ if ( GetProfileFloat("Edit", "IODim.y", fValue) ) m_IODim.y = fValue;
+
+ m_short->FlushShortcuts();
+ InitEye();
+
+ m_engine->SetTracePrecision(1.0f);
+
+ m_cameraPan = 0.0f;
+ m_cameraZoom = 0.0f;
+
+ g_id = 0;
+ g_build = 0;
+ g_researchDone = 0; // aucune recherche effectuée
+ g_researchEnable = 0;
+ g_unit = 4.0f;
+
+ m_gamerName[0] = 0;
+ GetProfileString("Gamer", "LastName", m_gamerName, 100);
+ SetGlobalGamerName(m_gamerName);
+ ReadFreeParam();
+ m_dialog->SetupRecall();
+
+ for ( i=0 ; i<MAXSHOWLIMIT ; i++ )
+ {
+ m_showLimit[i].bUsed = FALSE;
+ m_showLimit[i].total = 0;
+ m_showLimit[i].link = 0;
+ }
+
+ CBotProgram::SetTimer(100);
+ CBotProgram::Init();
+
+ for ( i=0 ; i<OBJECT_MAX ; i++ )
+ {
+ type = (ObjectType)i;
+ token = RetObjectName(type);
+ if ( token[0] != 0 )
+ {
+ CBotProgram::DefineNum(token, type);
+ }
+ token = RetObjectAlias(type);
+ if ( token[0] != 0 )
+ {
+ CBotProgram::DefineNum(token, type);
+ }
+ }
+
+ CBotProgram::DefineNum("White", 0);
+ CBotProgram::DefineNum("Black", 1);
+ CBotProgram::DefineNum("Gray", 2);
+ CBotProgram::DefineNum("LightGray", 3);
+ CBotProgram::DefineNum("Red", 4);
+ CBotProgram::DefineNum("Pink", 5);
+ CBotProgram::DefineNum("Purple", 6);
+ CBotProgram::DefineNum("Orange", 7);
+ CBotProgram::DefineNum("Yellow", 8);
+ CBotProgram::DefineNum("Beige", 9);
+ CBotProgram::DefineNum("Brown", 10);
+ CBotProgram::DefineNum("Skin", 11);
+ CBotProgram::DefineNum("Green", 12);
+ CBotProgram::DefineNum("LightGreen", 13);
+ CBotProgram::DefineNum("Blue", 14);
+ CBotProgram::DefineNum("LightBlue", 15);
+ CBotProgram::DefineNum("BlackArrow", 16);
+ CBotProgram::DefineNum("RedArrow", 17);
+
+ CBotProgram::DefineNum("Metal", OM_METAL);
+ CBotProgram::DefineNum("Plastic", OM_PLASTIC);
+
+ CBotProgram::DefineNum("InFront", TMA_FFRONT);
+ CBotProgram::DefineNum("Behind", TMA_FBACK);
+ CBotProgram::DefineNum("EnergyCell", TMA_POWER);
+
+ CBotProgram::DefineNum("DisplayError", TT_ERROR);
+ CBotProgram::DefineNum("DisplayWarning", TT_WARNING);
+ CBotProgram::DefineNum("DisplayInfo", TT_INFO);
+ CBotProgram::DefineNum("DisplayMessage", TT_MESSAGE);
+
+ CBotProgram::DefineNum("FilterNone", FILTER_NONE);
+ CBotProgram::DefineNum("FilterOnlyLanding", FILTER_ONLYLANDING);
+ CBotProgram::DefineNum("FilterOnlyFliying", FILTER_ONLYFLYING);
+
+ // Ajoute la classe Point.
+ CBotClass* bc;
+ bc = new CBotClass("point", NULL, TRUE); // classe intrinsèque
+ bc->AddItem("x", CBotTypFloat);
+ bc->AddItem("y", CBotTypFloat);
+ bc->AddItem("z", CBotTypFloat);
+ bc->AddFunction("point", rPoint, cPoint);
+
+ // Ajoute la classe Object.
+ bc = new CBotClass("object", NULL);
+ bc->AddItem("category", CBotTypResult(CBotTypInt), PR_READ);
+ bc->AddItem("position", CBotTypResult(CBotTypClass, "point"), PR_READ);
+ bc->AddItem("orientation", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("pitch", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("roll", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("energyLevel", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("shieldLevel", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("temperature", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("altitude", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("lifeTime", CBotTypResult(CBotTypFloat), PR_READ);
+ bc->AddItem("material", CBotTypResult(CBotTypInt), PR_READ);
+ bc->AddItem("energyCell", CBotTypResult(CBotTypPointer, "object"), PR_READ);
+ bc->AddItem("load", CBotTypResult(CBotTypPointer, "object"), PR_READ);
+
+ // Initialise la classe FILE.
+ InitClassFILE();
+
+ CScript::InitFonctions();
+}
+
+// Destructeur de l'application robot.
+
+CRobotMain::~CRobotMain()
+{
+ delete m_movie;
+ delete m_dialog;
+ delete m_short;
+ delete m_map;
+ delete m_terrain;
+ delete m_model;
+}
+
+
+// Crée le fichier colobot.ini la première fois.
+
+void CRobotMain::CreateIni()
+{
+ int iValue;
+
+ // colobot.ini inexistant ?
+ if ( !GetProfileInt("Setup", "TotoMode", iValue) )
+ {
+ m_dialog->SetupMemorize();
+ }
+}
+
+
+// Change de phase.
+
+void CRobotMain::ChangePhase(Phase phase)
+{
+ CEdit* pe;
+ CButton* pb;
+ D3DCOLORVALUE color;
+ FPOINT pos, dim, ddim;
+ float ox, oy, sx, sy;
+ char* read;
+ int rank, numTry;
+ BOOL bLoading;
+
+ if ( m_phase == PHASE_SIMUL ) // termine une simulation ?
+ {
+ SaveAllScript();
+ m_sound->StopMusic();
+ m_camera->SetObject(0);
+
+#if _SCHOOL
+ if ( TRUE )
+#else
+ if ( m_gameTime > 10.0f ) // a-t-on joué au moins 10 secondes ?
+#endif
+ {
+ rank = m_dialog->RetSceneRank();
+ numTry = m_dialog->RetGamerInfoTry(rank);
+ m_dialog->SetGamerInfoTry(rank, numTry+1);
+ m_dialog->WriteGamerInfo();
+ }
+ }
+
+ if ( phase == PHASE_WIN ) // gagné une simulation ?
+ {
+ rank = m_dialog->RetSceneRank();
+ m_dialog->SetGamerInfoPassed(rank, TRUE);
+ m_dialog->NextMission(); // passe à la mission suivante
+ m_dialog->WriteGamerInfo();
+ }
+
+ DeleteAllObjects(); // supprime toute la scène 3D actuelle
+
+ m_phase = phase;
+ m_winDelay = 0.0f;
+ m_lostDelay = 0.0f;
+ m_bBeginSatCom = FALSE;
+ m_bMovieLock = FALSE;
+ m_bSatComLock = FALSE;
+ m_bEditLock = FALSE;
+ m_bFreePhoto = FALSE;
+ m_bResetCreate = FALSE;
+
+ m_engine->SetMovieLock(m_bMovieLock);
+ ChangePause(FALSE);
+ FlushDisplayInfo();
+ m_engine->SetRankView(0);
+ m_engine->FlushObject();
+ color.r = color.g = color.b = color.a = 0.0f;
+ m_engine->SetWaterAddColor(color);
+ m_engine->SetBackground("");
+ m_engine->SetBackForce(FALSE);
+ m_engine->SetFrontsizeName("");
+ m_engine->SetOverColor();
+ m_engine->GroundMarkDelete(0);
+ SetSpeed(1.0f);
+ m_terrain->SetWind(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_terrain->FlushBuildingLevel();
+ m_terrain->FlushFlyingLimit();
+ m_light->FlushLight();
+ m_particule->FlushParticule();
+ m_water->Flush();
+ m_cloud->Flush();
+ m_blitz->Flush();
+ m_planet->Flush();
+ m_iMan->Flush(CLASS_OBJECT);
+ m_iMan->Flush(CLASS_PHYSICS);
+ m_iMan->Flush(CLASS_BRAIN);
+ m_iMan->Flush(CLASS_PYRO);
+ m_model->StopUserAction();
+ m_interface->Flush();
+ ClearInterface();
+ FlushNewScriptName();
+ m_sound->SetListener(D3DVECTOR(0.0f, 0.0f, 0.0f), D3DVECTOR(0.0f, 0.0f, 1.0f));
+ m_camera->SetType(CAMERA_DIALOG);
+ m_movie->Flush();
+ m_movieInfoIndex = -1;
+ m_cameraPan = 0.0f;
+ m_cameraZoom = 0.0f;
+ m_bShortCut = TRUE;
+
+ // Crée et cache la console de commande.
+ dim.x = 200.0f/640.0f;
+ dim.y = 18.0f/480.0f;
+ pos.x = 50.0f/640.0f;
+ pos.y = 452.0f/480.0f;
+ pe = m_interface->CreateEdit(pos, dim, 0, EVENT_CMD);
+ if ( pe == 0 ) return;
+ pe->ClearState(STATE_VISIBLE);
+ m_bCmdEdit = FALSE; // caché pour l'instant
+
+ // Crée l'indicateur de vitesse.
+#if _TEEN
+ dim.x = 30.0f/640.0f;
+ dim.y = 20.0f/480.0f;
+ pos.x = 4.0f/640.0f;
+ pos.y = 454.0f/480.0f;
+#else
+ dim.x = 30.0f/640.0f;
+ dim.y = 20.0f/480.0f;
+ pos.x = 4.0f/640.0f;
+ pos.y = 426.0f/480.0f;
+#endif
+ pb = m_interface->CreateButton(pos, dim, 0, EVENT_SPEED);
+ if ( pb == 0 ) return;
+ pb->SetState(STATE_SIMPLY);
+ pb->ClearState(STATE_VISIBLE);
+
+ m_dialog->ChangePhase(m_phase);
+
+ dim.x = 32.0f/640.0f;
+ dim.y = 32.0f/480.0f;
+ ox = 3.0f/640.0f;
+ oy = 3.0f/480.0f;
+ sx = (32.0f+2.0f)/640.0f;
+ sy = (32.0f+2.0f)/480.0f;
+
+ if ( m_phase != PHASE_PERSO )
+ {
+ m_engine->SetDrawWorld(TRUE);
+ m_engine->SetDrawFront(FALSE);
+ m_bFixScene = FALSE;
+ }
+
+ if ( m_phase == PHASE_INIT )
+ {
+#if _NEWLOOK
+ m_engine->FreeTexture("generna.tga");
+ m_engine->FreeTexture("genernb.tga");
+ m_engine->FreeTexture("genernc.tga");
+ m_engine->FreeTexture("genernd.tga");
+#else
+#if _FRENCH
+#if _DEMO
+ m_engine->FreeTexture("genedfa.tga");
+ m_engine->FreeTexture("genedfb.tga");
+ m_engine->FreeTexture("genedfc.tga");
+ m_engine->FreeTexture("genedfd.tga");
+#else
+ m_engine->FreeTexture("generfa.tga");
+ m_engine->FreeTexture("generfb.tga");
+ m_engine->FreeTexture("generfc.tga");
+ m_engine->FreeTexture("generfd.tga");
+#endif
+#endif
+#if _ENGLISH
+#if _DEMO
+ m_engine->FreeTexture("genedea.tga");
+ m_engine->FreeTexture("genedeb.tga");
+ m_engine->FreeTexture("genedec.tga");
+ m_engine->FreeTexture("geneded.tga");
+#else
+ m_engine->FreeTexture("generea.tga");
+ m_engine->FreeTexture("genereb.tga");
+ m_engine->FreeTexture("generec.tga");
+ m_engine->FreeTexture("genered.tga");
+#endif
+#endif
+#if _GERMAN
+#if _DEMO
+ m_engine->FreeTexture("genedda.tga");
+ m_engine->FreeTexture("geneddb.tga");
+ m_engine->FreeTexture("geneddc.tga");
+ m_engine->FreeTexture("geneddd.tga");
+#else
+ m_engine->FreeTexture("generea.tga");
+ m_engine->FreeTexture("genereb.tga");
+ m_engine->FreeTexture("generec.tga");
+ m_engine->FreeTexture("genered.tga");
+#endif
+#endif
+#if _WG
+#if _DEMO
+ m_engine->FreeTexture("genedda.tga");
+ m_engine->FreeTexture("geneddb.tga");
+ m_engine->FreeTexture("geneddc.tga");
+ m_engine->FreeTexture("geneddd.tga");
+#else
+ m_engine->FreeTexture("generda.tga");
+ m_engine->FreeTexture("generdb.tga");
+ m_engine->FreeTexture("generdc.tga");
+ m_engine->FreeTexture("generdd.tga");
+#endif
+#endif
+#if _POLISH
+#if _DEMO
+ m_engine->FreeTexture("genedpa.tga");
+ m_engine->FreeTexture("genedpb.tga");
+ m_engine->FreeTexture("genedpc.tga");
+ m_engine->FreeTexture("genedpd.tga");
+#else
+ m_engine->FreeTexture("generpa.tga");
+ m_engine->FreeTexture("generpb.tga");
+ m_engine->FreeTexture("generpc.tga");
+ m_engine->FreeTexture("generpd.tga");
+#endif
+#endif
+#endif
+ }
+
+ if ( m_phase == PHASE_SIMUL )
+ {
+ m_engine->FreeTexture("inter01a.tga");
+ m_engine->FreeTexture("inter01b.tga");
+ m_engine->FreeTexture("inter01c.tga");
+ m_engine->FreeTexture("inter01d.tga");
+
+ read = m_dialog->RetSceneRead();
+ bLoading = (read[0] != 0);
+
+ m_map->CreateMap();
+ CreateScene(m_dialog->RetSceneSoluce(), FALSE, FALSE); // scène interractive
+ if ( m_bMapImage )
+ {
+ m_map->SetFixImage(m_mapFilename);
+ }
+
+ pos.x = 620.0f/640.0f;
+ pos.y = 460.0f/480.0f;
+ ddim.x = 20.0f/640.0f;
+ ddim.y = 20.0f/480.0f;
+ m_interface->CreateButton(pos, ddim, 11, EVENT_BUTTON_QUIT);
+
+ if ( m_bImmediatSatCom && !bLoading &&
+ m_infoFilename[SATCOM_HUSTON][0] != 0 )
+ {
+ StartDisplayInfo(SATCOM_HUSTON, FALSE); // affiche les instructions
+ }
+
+ m_sound->StopMusic();
+ if ( !m_bBase || bLoading ) StartMusic();
+ }
+
+ if ( m_phase == PHASE_WIN )
+ {
+ if ( m_endingWinRank == -1 )
+ {
+ ChangePhase(PHASE_TERM);
+ }
+ else
+ {
+#if _TEEN
+ m_bWinTerminate = (m_endingWinRank == 900);
+ m_dialog->SetSceneName("teenw");
+#else
+ m_bWinTerminate = (m_endingWinRank == 904);
+ m_dialog->SetSceneName("win");
+#endif
+ m_dialog->SetSceneRank(m_endingWinRank);
+ CreateScene(FALSE, TRUE, FALSE); // scène fixe
+
+ pos.x = ox+sx*1; pos.y = oy+sy*1;
+ ddim.x = dim.x*2; ddim.y = dim.y*2;
+ m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK);
+
+ if ( m_bWinTerminate )
+ {
+#if _TEEN
+ pos.x = ox+sx*3; pos.y = oy+sy*1;
+ ddim.x = dim.x*15; ddim.y = dim.y*2;
+ pe = m_interface->CreateEdit(pos, ddim, 0, EVENT_EDIT0);
+ pe->SetFontType(FONT_COLOBOT);
+ pe->SetEditCap(FALSE);
+ pe->SetHiliteCap(FALSE);
+ pe->ReadText("help\\teenw.txt");
+#else
+ pos.x = ox+sx*3; pos.y = oy+sy*0.2f;
+ ddim.x = dim.x*15; ddim.y = dim.y*3.0f;
+ pe = m_interface->CreateEdit(pos, ddim, 0, EVENT_EDIT0);
+ pe->SetGenericMode(TRUE);
+ pe->SetFontType(FONT_COLOBOT);
+ pe->SetEditCap(FALSE);
+ pe->SetHiliteCap(FALSE);
+ pe->ReadText("help\\win.txt");
+#endif
+ }
+ else
+ {
+ m_displayText->DisplayError(INFO_WIN, D3DVECTOR(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f);
+ }
+ }
+ m_sound->StopAll();
+ StartMusic();
+ }
+
+ if ( m_phase == PHASE_LOST )
+ {
+ if ( m_endingLostRank == -1 )
+ {
+ ChangePhase(PHASE_TERM);
+ }
+ else
+ {
+ m_bWinTerminate = FALSE;
+ m_dialog->SetSceneName("lost");
+ m_dialog->SetSceneRank(m_endingLostRank);
+ CreateScene(FALSE, TRUE, FALSE); // scène fixe
+
+ pos.x = ox+sx*1; pos.y = oy+sy*1;
+ ddim.x = dim.x*2; ddim.y = dim.y*2;
+ m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK);
+ m_displayText->DisplayError(INFO_LOST, D3DVECTOR(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f);
+ }
+ m_sound->StopAll();
+ StartMusic();
+ }
+
+ if ( m_phase == PHASE_MODEL )
+ {
+ pos.x = ox+sx*0; pos.y = oy+sy*0;
+ m_interface->CreateButton(pos, dim, 11, EVENT_BUTTON_CANCEL);
+
+ CreateModel();
+ }
+
+ if ( m_phase == PHASE_LOADING )
+ {
+ m_engine->SetMouseHide(TRUE);
+ }
+ else
+ {
+ m_engine->SetMouseHide(FALSE);
+ }
+
+ m_engine->LoadAllTexture();
+}
+
+
+// Traite un événement.
+
+BOOL CRobotMain::EventProcess(const Event &event)
+{
+ CEdit* pe;
+ CObject* pObj;
+ Event newEvent;
+ MainMovieType type;
+ int i;
+
+ if ( event.event == EVENT_FRAME )
+ {
+ if ( !m_movie->EventProcess(event) ) // fin du film ?
+ {
+ type = m_movie->RetStopType();
+ if ( type == MM_SATCOMopen )
+ {
+ ChangePause(FALSE);
+ SelectObject(m_infoObject, FALSE); // remet les boutons de commande
+ m_map->ShowMap(m_bMapShow);
+ m_displayText->HideText(FALSE);
+ i = m_movieInfoIndex;
+ StartDisplayInfo(m_movieInfoIndex, FALSE);
+ m_movieInfoIndex = i;
+ }
+ }
+
+ m_dialog->EventProcess(event);
+ m_displayText->EventProcess(event);
+ RemoteCamera(m_cameraPan, m_cameraZoom, event.rTime);
+
+ m_interface->EventProcess(event);
+ if ( m_displayInfo != 0 ) // édition en cours ?
+ {
+ m_displayInfo->EventProcess(event);
+ }
+ return EventFrame(event);
+ }
+
+ // Gestion de la console de commande.
+#if 0
+ if ( m_phase != PHASE_NAME &&
+ !m_movie->IsExist() &&
+ event.event == EVENT_KEYDOWN &&
+ event.param == VK_PAUSE &&
+ (event.keyState&KS_CONTROL) != 0 )
+#else
+ if ( m_phase != PHASE_NAME &&
+ !m_movie->IsExist() &&
+ event.event == EVENT_KEYDOWN &&
+ event.param == VK_CANCEL ) // Ctrl+Pause ?
+#endif
+ {
+ pe = (CEdit*)m_interface->SearchControl(EVENT_CMD);
+ if ( pe == 0 ) return FALSE;
+ pe->SetState(STATE_VISIBLE);
+ pe->SetFocus(TRUE);
+ if ( m_phase == PHASE_SIMUL ) ChangePause(TRUE);
+ m_bCmdEdit = TRUE;
+ return FALSE;
+ }
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_RETURN && m_bCmdEdit )
+ {
+ char cmd[50];
+ pe = (CEdit*)m_interface->SearchControl(EVENT_CMD);
+ if ( pe == 0 ) return FALSE;
+ pe->GetText(cmd, 50);
+ pe->SetText("");
+ pe->ClearState(STATE_VISIBLE);
+ if ( m_phase == PHASE_SIMUL ) ChangePause(FALSE);
+ ExecuteCmd(cmd);
+ m_bCmdEdit = FALSE;
+ return FALSE;
+ }
+
+ // Gestion du changement de vitesse.
+ if ( event.event == EVENT_SPEED )
+ {
+ SetSpeed(1.0f);
+ }
+
+ if ( !m_dialog->EventProcess(event) )
+ {
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ m_lastMousePos = event.pos;
+ HiliteObject(event.pos);
+ }
+ return FALSE;
+ }
+
+ if ( !m_displayText->EventProcess(event) )
+ {
+ return FALSE;
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ m_lastMousePos = event.pos;
+ HiliteObject(event.pos);
+ }
+
+ if ( m_displayInfo != 0 ) // info en cours ?
+ {
+ m_displayInfo->EventProcess(event);
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+ if ( event.param == m_engine->RetKey(KEYRANK_HELP, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_HELP, 1) ||
+ event.param == m_engine->RetKey(KEYRANK_PROG, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_PROG, 1) ||
+ event.param == VK_ESCAPE )
+ {
+ StopDisplayInfo();
+ }
+ }
+ if ( event.event == EVENT_OBJECT_INFOOK )
+ {
+ StopDisplayInfo();
+ }
+ return FALSE;
+ }
+
+ // Phase de simulation du jeu.
+ if ( m_phase == PHASE_SIMUL )
+ {
+ UpdateInfoText();
+
+ if ( !m_bEditFull )
+ {
+ m_camera->EventProcess(event);
+ }
+
+ switch( event.event )
+ {
+ case EVENT_KEYDOWN:
+ KeyCamera(event.event, event.param);
+ HiliteClear();
+ if ( event.param == VK_F11 )
+ {
+ m_particule->WriteWheelTrace("Savegame\\t.bmp", 256, 256, D3DVECTOR(16.0f, 0.0f, -368.0f), D3DVECTOR(140.0f, 0.0f, -248.0f));
+ return FALSE;
+ }
+ if ( m_bEditLock ) // édition en cours ?
+ {
+ if ( event.param == m_engine->RetKey(KEYRANK_HELP, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_HELP, 1) )
+ {
+ StartDisplayInfo(SATCOM_HUSTON, FALSE);
+ return FALSE;
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_PROG, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_PROG, 1) )
+ {
+ StartDisplayInfo(SATCOM_PROG, FALSE);
+ return FALSE;
+ }
+ break;
+ }
+ if ( m_bMovieLock ) // film en cours ?
+ {
+ if ( event.param == m_engine->RetKey(KEYRANK_QUIT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_QUIT, 1) ||
+ event.param == VK_ESCAPE )
+ {
+ AbortMovie();
+ }
+ return FALSE;
+ }
+ if ( m_camera->RetType() == CAMERA_VISIT )
+ {
+ if ( event.param == m_engine->RetKey(KEYRANK_VISIT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_VISIT, 1) )
+ {
+ StartDisplayVisit(EVENT_NULL);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_QUIT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_QUIT, 1) ||
+ event.param == VK_ESCAPE )
+ {
+ StopDisplayVisit();
+ }
+ return FALSE;
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_QUIT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_QUIT, 1) )
+ {
+ if ( m_movie->IsExist() )
+ {
+ StartDisplayInfo(SATCOM_HUSTON, FALSE);
+ }
+ else if ( m_winDelay > 0.0f )
+ {
+ ChangePhase(PHASE_WIN);
+ }
+ else if ( m_lostDelay > 0.0f )
+ {
+ ChangePhase(PHASE_LOST);
+ }
+ else
+ {
+ m_dialog->StartAbort(); // voulez-vous quitter ?
+ }
+ }
+ if ( event.param == VK_PAUSE )
+ {
+ if ( !m_bMovieLock && !m_bEditLock && !m_bCmdEdit &&
+ m_camera->RetType() != CAMERA_VISIT &&
+ !m_movie->IsExist() )
+ {
+ ChangePause(!m_engine->RetPause());
+ }
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_CAMERA, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_CAMERA, 1) )
+ {
+ ChangeCamera();
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_DESEL, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_DESEL, 1) )
+ {
+ if ( m_bShortCut )
+ {
+ DeselectObject();
+ }
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_HUMAN, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_HUMAN, 1) )
+ {
+ SelectHuman();
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_NEXT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_NEXT, 1) )
+ {
+ if ( m_bShortCut )
+ {
+ m_short->SelectNext();
+ }
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_HELP, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_HELP, 1) )
+ {
+ StartDisplayInfo(SATCOM_HUSTON, TRUE);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_PROG, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_PROG, 1) )
+ {
+ StartDisplayInfo(SATCOM_PROG, TRUE);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_VISIT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_VISIT, 1) )
+ {
+ StartDisplayVisit(EVENT_NULL);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_SPEED10, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_SPEED10, 1) )
+ {
+ SetSpeed(1.0f);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_SPEED15, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_SPEED15, 1) )
+ {
+ SetSpeed(1.5f);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_SPEED20, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_SPEED20, 1) )
+ {
+ SetSpeed(2.0f);
+ }
+ if ( event.param == m_engine->RetKey(KEYRANK_SPEED30, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_SPEED30, 1) )
+ {
+ SetSpeed(3.0f);
+ }
+ break;
+
+ case EVENT_KEYUP:
+ KeyCamera(event.event, event.param);
+ break;
+
+ case EVENT_LBUTTONDOWN:
+ pObj = DetectObject(event.pos);
+ if ( !m_bShortCut ) pObj = 0;
+ if ( pObj != 0 && pObj->RetType() == OBJECT_TOTO )
+ {
+ if ( m_displayInfo != 0 ) // info en cours ?
+ {
+ StopDisplayInfo();
+ }
+ else
+ {
+ if ( !m_bEditLock )
+ {
+ StartDisplayInfo(SATCOM_HUSTON, TRUE);
+ }
+ }
+ }
+ else
+ {
+ SelectObject(pObj);
+ }
+ break;
+
+ case EVENT_LBUTTONUP:
+ m_cameraPan = 0.0f;
+ m_cameraZoom = 0.0f;
+ break;
+
+ case EVENT_BUTTON_QUIT:
+ if ( m_movie->IsExist() )
+ {
+ StartDisplayInfo(SATCOM_HUSTON, FALSE);
+ }
+ else if ( m_winDelay > 0.0f )
+ {
+ ChangePhase(PHASE_WIN);
+ }
+ else if ( m_lostDelay > 0.0f )
+ {
+ ChangePhase(PHASE_LOST);
+ }
+ else
+ {
+ m_dialog->StartAbort(); // voulez-vous quitter ?
+ }
+ break;
+
+ case EVENT_OBJECT_LIMIT:
+ StartShowLimit();
+ break;
+
+ case EVENT_OBJECT_DESELECT:
+ if ( m_bShortCut )
+ {
+ DeselectObject();
+ }
+ break;
+
+ case EVENT_OBJECT_HELP:
+ HelpObject();
+ break;
+
+ case EVENT_OBJECT_CAMERA:
+ ChangeCamera();
+ break;
+
+ case EVENT_OBJECT_CAMERAleft:
+ m_cameraPan = -1.0f;
+ break;
+ case EVENT_OBJECT_CAMERAright:
+ m_cameraPan = 1.0f;
+ break;
+ case EVENT_OBJECT_CAMERAnear:
+ m_cameraZoom = -1.0f;
+ break;
+ case EVENT_OBJECT_CAMERAaway:
+ m_cameraZoom = 1.0f;
+ break;
+
+ case EVENT_OBJECT_DELETE:
+ m_dialog->StartDeleteObject(); // voulez-vous détruire ?
+ break;
+
+ case EVENT_OBJECT_BHELP:
+ StartDisplayInfo(SATCOM_HUSTON, TRUE);
+ break;
+
+ case EVENT_OBJECT_SOLUCE:
+ StartDisplayInfo(SATCOM_SOLUCE, TRUE);
+ break;
+
+ case EVENT_OBJECT_MAPZOOM:
+ m_map->ZoomMap();
+ break;
+
+ case EVENT_DT_VISIT0:
+ case EVENT_DT_VISIT1:
+ case EVENT_DT_VISIT2:
+ case EVENT_DT_VISIT3:
+ case EVENT_DT_VISIT4:
+ StartDisplayVisit(event.event);
+ break;
+
+ case EVENT_DT_END:
+ StopDisplayVisit();
+ break;
+
+ case EVENT_OBJECT_SHORTCUT00:
+ case EVENT_OBJECT_SHORTCUT01:
+ case EVENT_OBJECT_SHORTCUT02:
+ case EVENT_OBJECT_SHORTCUT03:
+ case EVENT_OBJECT_SHORTCUT04:
+ case EVENT_OBJECT_SHORTCUT05:
+ case EVENT_OBJECT_SHORTCUT06:
+ case EVENT_OBJECT_SHORTCUT07:
+ case EVENT_OBJECT_SHORTCUT08:
+ case EVENT_OBJECT_SHORTCUT09:
+ case EVENT_OBJECT_SHORTCUT10:
+ case EVENT_OBJECT_SHORTCUT11:
+ case EVENT_OBJECT_SHORTCUT12:
+ case EVENT_OBJECT_SHORTCUT13:
+ case EVENT_OBJECT_SHORTCUT14:
+ case EVENT_OBJECT_SHORTCUT15:
+ case EVENT_OBJECT_SHORTCUT16:
+ case EVENT_OBJECT_SHORTCUT17:
+ case EVENT_OBJECT_SHORTCUT18:
+ case EVENT_OBJECT_SHORTCUT19:
+ m_short->SelectShortcut(event.event);
+ break;
+
+ case EVENT_OBJECT_MOVIELOCK:
+ AbortMovie();
+ break;
+
+ case EVENT_WIN:
+ ChangePhase(PHASE_WIN);
+ break;
+
+ case EVENT_LOST:
+ ChangePhase(PHASE_LOST);
+ break;
+ }
+
+ EventObject(event);
+ return FALSE;
+ }
+
+ if ( m_phase == PHASE_PERSO )
+ {
+ EventObject(event);
+ }
+
+ if ( m_phase == PHASE_WIN ||
+ m_phase == PHASE_LOST )
+ {
+ EventObject(event);
+
+ switch( event.event )
+ {
+ case EVENT_KEYDOWN:
+ if ( event.param == VK_ESCAPE ||
+ event.param == VK_RETURN )
+ {
+ if ( m_bWinTerminate )
+ {
+ ChangePhase(PHASE_INIT);
+ }
+ else
+ {
+ ChangePhase(PHASE_TERM);
+ }
+ }
+ break;
+
+ case EVENT_BUTTON_OK:
+ if ( m_bWinTerminate )
+ {
+ ChangePhase(PHASE_INIT);
+ }
+ else
+ {
+ ChangePhase(PHASE_TERM);
+ }
+ break;
+ }
+ }
+
+ if ( m_phase == PHASE_MODEL )
+ {
+ switch( event.event )
+ {
+ case EVENT_KEYDOWN:
+ if ( event.param == VK_ESCAPE )
+ {
+ ChangePhase(PHASE_INIT);
+ }
+ if ( event.param == VK_HOME )
+ {
+ InitEye();
+ }
+ break;
+
+ case EVENT_BUTTON_CANCEL:
+ ChangePhase(PHASE_INIT);
+ break;
+ }
+
+ m_model->EventProcess(event);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+// Exécute une commande.
+
+void CRobotMain::ExecuteCmd(char *cmd)
+{
+ if ( cmd[0] == 0 ) return;
+
+ if ( m_phase == PHASE_SIMUL )
+ {
+ if ( strcmp(cmd, "winmission") == 0 )
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, EVENT_WIN);
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( strcmp(cmd, "lostmission") == 0 )
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, EVENT_LOST);
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( strcmp(cmd, "trainerpilot") == 0 )
+ {
+ m_bTrainerPilot = !m_bTrainerPilot;
+ return;
+ }
+
+ if ( strcmp(cmd, "fly") == 0 )
+ {
+ Event newEvent;
+
+ g_researchDone |= RESEARCH_FLY;
+
+ m_event->MakeEvent(newEvent, EVENT_UPDINTERFACE);
+ m_event->AddEvent(newEvent);
+ return;
+ }
+
+ if ( strcmp(cmd, "allresearch") == 0 )
+ {
+ Event newEvent;
+
+ g_researchDone = -1; // toutes les recherches sont effectuées
+
+ m_event->MakeEvent(newEvent, EVENT_UPDINTERFACE);
+ m_event->AddEvent(newEvent);
+ return;
+ }
+
+ if ( strcmp(cmd, "nolimit") == 0 )
+ {
+ m_terrain->SetFlyingMaxHeight(280.0f);
+ return;
+ }
+
+ if ( strcmp(cmd, "photo1") == 0 )
+ {
+ m_bFreePhoto = !m_bFreePhoto;
+ if ( m_bFreePhoto )
+ {
+ m_camera->SetType(CAMERA_FREE);
+ ChangePause(TRUE);
+ }
+ else
+ {
+ m_camera->SetType(CAMERA_BACK);
+ ChangePause(FALSE);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "photo2") == 0 )
+ {
+ m_bFreePhoto = !m_bFreePhoto;
+ if ( m_bFreePhoto )
+ {
+ m_camera->SetType(CAMERA_FREE);
+ ChangePause(TRUE);
+ DeselectAll(); // enlève les boutons de commande
+ m_map->ShowMap(FALSE);
+ m_displayText->HideText(TRUE);
+ }
+ else
+ {
+ m_camera->SetType(CAMERA_BACK);
+ ChangePause(FALSE);
+ m_map->ShowMap(m_bMapShow);
+ m_displayText->HideText(FALSE);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "noclip") == 0 )
+ {
+ CObject* object;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ object->SetClip(FALSE);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "clip") == 0 )
+ {
+ CObject* object;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ object->SetClip(TRUE);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "addhusky") == 0 )
+ {
+ CObject* object;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ object->SetMagnifyDamage(object->RetMagnifyDamage()*0.1f);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "addfreezer") == 0 )
+ {
+ CObject* object;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ object->SetRange(object->RetRange()*10.0f);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "fullpower") == 0 )
+ {
+ CObject* object;
+ CObject* power;
+ CPhysics* physics;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ power = object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetEnergy(1.0f);
+ }
+ object->SetShield(1.0f);
+ physics = object->RetPhysics();
+ if ( physics != 0 )
+ {
+ physics->SetReactorRange(1.0f);
+ }
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "fullenergy") == 0 )
+ {
+ CObject* object;
+ CObject* power;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ power = object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetEnergy(1.0f);
+ }
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "fullshield") == 0 )
+ {
+ CObject* object;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ object->SetShield(1.0f);
+ }
+ return;
+ }
+
+ if ( strcmp(cmd, "fullrange") == 0 )
+ {
+ CObject* object;
+ CPhysics* physics;
+
+ object = RetSelect();
+ if ( object != 0 )
+ {
+ physics = object->RetPhysics();
+ if ( physics != 0 )
+ {
+ physics->SetReactorRange(1.0f);
+ }
+ }
+ return;
+ }
+ }
+
+ if ( strcmp(cmd, "debugmode") == 0 )
+ {
+ m_engine->SetDebugMode(!m_engine->RetDebugMode());
+ return;
+ }
+
+ if ( strcmp(cmd, "showstat") == 0 )
+ {
+ m_engine->SetShowStat(!m_engine->RetShowStat());
+ return;
+ }
+
+ if ( strcmp(cmd, "invshadow") == 0 )
+ {
+ m_engine->SetShadow(!m_engine->RetShadow());
+ return;
+ }
+
+ if ( strcmp(cmd, "invdirty") == 0 )
+ {
+ m_engine->SetDirty(!m_engine->RetDirty());
+ return;
+ }
+
+ if ( strcmp(cmd, "invfog") == 0 )
+ {
+ m_engine->SetFog(!m_engine->RetFog());
+ return;
+ }
+
+ if ( strcmp(cmd, "invlens") == 0 )
+ {
+ m_engine->SetLensMode(!m_engine->RetLensMode());
+ return;
+ }
+
+ if ( strcmp(cmd, "invwater") == 0 )
+ {
+ m_engine->SetWaterMode(!m_engine->RetWaterMode());
+ return;
+ }
+
+ if ( strcmp(cmd, "invsky") == 0 )
+ {
+ m_engine->SetSkyMode(!m_engine->RetSkyMode());
+ return;
+ }
+
+ if ( strcmp(cmd, "invplanet") == 0 )
+ {
+ m_engine->SetPlanetMode(!m_engine->RetPlanetMode());
+ return;
+ }
+
+ if ( strcmp(cmd, "showpos") == 0 )
+ {
+ m_bShowPos = !m_bShowPos;
+ return;
+ }
+
+ if ( strcmp(cmd, "selectinsect") == 0 )
+ {
+ m_bSelectInsect = !m_bSelectInsect;
+ return;
+ }
+
+ if ( strcmp(cmd, "showsoluce") == 0 )
+ {
+ m_bShowSoluce = !m_bShowSoluce;
+ m_dialog->ShowSoluceUpdate();
+ return;
+ }
+
+#if _TEEN
+ if ( strcmp(cmd, "allteens") == 0 )
+#else
+ if ( strcmp(cmd, "allmission") == 0 )
+#endif
+ {
+ m_bShowAll = !m_bShowAll;
+ m_dialog->AllMissionUpdate();
+ return;
+ }
+
+ if ( strcmp(cmd, "invradar") == 0 )
+ {
+ m_bCheatRadar = !m_bCheatRadar;
+ return;
+ }
+
+ if ( m_phase == PHASE_SIMUL )
+ {
+ m_displayText->DisplayError(ERR_CMD, D3DVECTOR(0.0f,0.0f,0.0f));
+ }
+}
+
+
+
+// Retourne le type de film en cours.
+
+MainMovieType CRobotMain::RetMainMovie()
+{
+ return m_movie->RetType();
+}
+
+
+// Efface l'affichage d'instructions.
+
+void CRobotMain::FlushDisplayInfo()
+{
+ int i;
+
+ for ( i=0 ; i<SATCOM_MAX ; i++ )
+ {
+ m_infoFilename[i][0] = 0;
+ m_infoPos[i] = 0;
+ }
+ strcpy(m_infoFilename[SATCOM_OBJECT], "help\\objects.txt");
+ m_infoIndex = 0;
+}
+
+// Début de l'affichage d'instructions.
+// index: SATCOM_*
+
+void CRobotMain::StartDisplayInfo(int index, BOOL bMovie)
+{
+ CObject* pObj;
+ CMotion* motion;
+ BOOL bHuman;
+
+ if ( m_bCmdEdit || m_bSatComLock ) return;
+
+ pObj = RetSelect();
+ bHuman = ( pObj != 0 && pObj->RetType() == OBJECT_HUMAN );
+
+ if ( !m_bEditLock && bMovie && !m_movie->IsExist() && bHuman )
+ {
+ motion = pObj->RetMotion();
+ if ( motion != 0 && motion->RetAction() == -1 )
+ {
+ m_movieInfoIndex = index;
+ m_movie->Start(MM_SATCOMopen, 2.5f);
+ ChangePause(TRUE);
+//? m_map->ShowMap(FALSE);
+ m_infoObject = DeselectAll(); // enlève les boutons de commande
+ m_displayText->HideText(TRUE);
+ return;
+ }
+ }
+
+ if ( m_movie->IsExist() )
+ {
+ m_movie->Stop();
+ ChangePause(FALSE);
+ SelectObject(m_infoObject, FALSE); // remet les boutons de commande
+//? m_map->ShowMap(m_bMapShow);
+ m_displayText->HideText(FALSE);
+ }
+
+ StartDisplayInfo(m_infoFilename[index], index);
+}
+
+// Début de l'affichage d'instructions.
+
+void CRobotMain::StartDisplayInfo(char *filename, int index)
+{
+ CButton* pb;
+ BOOL bSoluce;
+
+ if ( m_bCmdEdit ) return;
+
+ m_movieInfoIndex = -1;
+ ClearInterface(); // enlève mise en évidence et tooltip
+
+ if ( !m_bEditLock )
+ {
+//? m_map->ShowMap(FALSE);
+ m_infoObject = DeselectAll(); // enlève les boutons de commande
+ m_displayText->HideText(TRUE);
+ m_sound->MuteAll(TRUE);
+ }
+
+ pb = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( pb != 0 )
+ {
+ pb->ClearState(STATE_VISIBLE);
+ }
+
+ bSoluce = m_dialog->RetSceneSoluce();
+
+ m_displayInfo = new CDisplayInfo(m_iMan);
+ m_displayInfo->StartDisplayInfo(filename, index, bSoluce);
+
+ m_infoIndex = index;
+ if ( index != -1 )
+ {
+ m_displayInfo->SetPosition(m_infoPos[index]);
+ }
+}
+
+// Fin de l'affichage d'instructions.
+
+void CRobotMain::StopDisplayInfo()
+{
+ CButton* pb;
+
+ if ( m_movieInfoIndex != -1 ) // film pour lire le SatCom ?
+ {
+ m_movie->Start(MM_SATCOMclose, 2.0f);
+ }
+
+ if ( m_infoIndex != -1 )
+ {
+ m_infoPos[m_infoIndex] = m_displayInfo->RetPosition();
+ }
+ m_displayInfo->StopDisplayInfo();
+
+ delete m_displayInfo;
+ m_displayInfo = 0;
+
+ if ( !m_bEditLock )
+ {
+ pb = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_VISIBLE);
+ }
+
+ SelectObject(m_infoObject, FALSE); // remet les boutons de commande
+//? m_map->ShowMap(m_bMapShow);
+ m_displayText->HideText(FALSE);
+
+ m_sound->MuteAll(FALSE);
+ }
+
+ if ( m_infoUsed == 0 )
+ {
+ m_displayText->ClearText(); // enlève message "voir SatCom ..."
+ }
+ m_infoUsed ++;
+}
+
+// Retourne le nom du texte à afficher.
+
+char* CRobotMain::RetDisplayInfoName(int index)
+{
+ return m_infoFilename[index];
+}
+
+// Retourne le nom du texte à afficher.
+
+int CRobotMain::RetDisplayInfoPosition(int index)
+{
+ return m_infoPos[index];
+}
+
+// Retourne le nom du texte à afficher.
+
+void CRobotMain::SetDisplayInfoPosition(int index, int pos)
+{
+ m_infoPos[index] = pos;
+}
+
+
+// Début d'un dialogue pendant le jeu,
+
+void CRobotMain::StartSuspend()
+{
+ CButton* pb;
+
+ m_map->ShowMap(FALSE);
+ m_infoObject = DeselectAll(); // enlève les boutons de commande
+ m_displayText->HideText(TRUE);
+
+ pb = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( pb != 0 )
+ {
+ pb->ClearState(STATE_VISIBLE);
+ }
+
+ m_bSuspend = TRUE;
+}
+
+// Fin d'un dialogue pendant le jeu,
+
+void CRobotMain::StopSuspend()
+{
+ CButton* pb;
+
+ pb = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( pb != 0 )
+ {
+ pb->SetState(STATE_VISIBLE);
+ }
+
+ SelectObject(m_infoObject, FALSE); // remet les boutons de commande
+ m_map->ShowMap(m_bMapShow);
+ m_displayText->HideText(FALSE);
+
+ m_bSuspend = FALSE;
+}
+
+
+// Retourne le temps absoul du jeu.
+
+float CRobotMain::RetGameTime()
+{
+ return m_gameTime;
+}
+
+
+
+// Gestion de la taille des caractères par défaut.
+
+void CRobotMain::SetFontSize(float size)
+{
+ m_fontSize = size;
+ SetProfileFloat("Edit", "FontSize", m_fontSize);
+}
+
+float CRobotMain::RetFontSize()
+{
+ return m_fontSize;
+}
+
+// Gestion de la taille de la fenêtre par défaut.
+
+void CRobotMain::SetWindowPos(FPOINT pos)
+{
+ m_windowPos = pos;
+ SetProfileFloat("Edit", "WindowPos.x", m_windowPos.x);
+ SetProfileFloat("Edit", "WindowPos.y", m_windowPos.y);
+}
+
+FPOINT CRobotMain::RetWindowPos()
+{
+ return m_windowPos;
+}
+
+void CRobotMain::SetWindowDim(FPOINT dim)
+{
+ m_windowDim = dim;
+ SetProfileFloat("Edit", "WindowDim.x", m_windowDim.x);
+ SetProfileFloat("Edit", "WindowDim.y", m_windowDim.y);
+}
+
+FPOINT CRobotMain::RetWindowDim()
+{
+ return m_windowDim;
+}
+
+
+// Gestion des fenêtres ouvrir/enregistrer.
+
+void CRobotMain::SetIOPublic(BOOL bMode)
+{
+ m_IOPublic = bMode;
+ SetProfileInt("Edit", "IOPublic", m_IOPublic);
+}
+
+BOOL CRobotMain::RetIOPublic()
+{
+ return m_IOPublic;
+}
+
+void CRobotMain::SetIOPos(FPOINT pos)
+{
+ m_IOPos = pos;
+ SetProfileFloat("Edit", "IOPos.x", m_IOPos.x);
+ SetProfileFloat("Edit", "IOPos.y", m_IOPos.y);
+}
+
+FPOINT CRobotMain::RetIOPos()
+{
+ return m_IOPos;
+}
+
+void CRobotMain::SetIODim(FPOINT dim)
+{
+ m_IODim = dim;
+ SetProfileFloat("Edit", "IODim.x", m_IODim.x);
+ SetProfileFloat("Edit", "IODim.y", m_IODim.y);
+}
+
+FPOINT CRobotMain::RetIODim()
+{
+ return m_IODim;
+}
+
+
+
+// Début de la visite du lieu d'une erreur.
+
+void CRobotMain::StartDisplayVisit(EventMsg event)
+{
+ CWindow* pw;
+ CButton* button;
+ CGroup* group;
+ D3DVECTOR goal;
+ FPOINT pos, dim;
+ int i, j;
+
+ if ( m_bEditLock ) return;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW2);
+ if ( pw == 0 ) return;
+
+ if ( event == EVENT_NULL ) // visite par raccourci clavier ?
+ {
+ if ( m_visitLast != EVENT_NULL ) // déjà une visite en cours ?
+ {
+ i = m_visitLast-EVENT_DT_VISIT0;
+ }
+ else
+ {
+ i = MAXDTLINE;
+ }
+
+ // Cherche la précédente.
+ for ( j=0 ; j<MAXDTLINE ; j++ )
+ {
+ i --;
+ if ( i < 0 ) i = MAXDTLINE-1;
+
+ button = (CButton*)pw->SearchControl(EventMsg(EVENT_DT_VISIT0+i));
+ if ( button == 0 || !button->TestState(STATE_ENABLE) ) continue;
+
+ group = (CGroup*)pw->SearchControl(EventMsg(EVENT_DT_GROUP0+i));
+ if ( group != 0 )
+ {
+ event = EventMsg(EVENT_DT_VISIT0+i);
+ break;
+ }
+ }
+ }
+ if ( event == EVENT_NULL )
+ {
+ m_sound->Play(SOUND_TZOING); // rien à voir !
+ return;
+ }
+
+ m_visitLast = event;
+
+ ClearInterface(); // enlève mise en évidence et tooltip
+
+ if ( m_camera->RetType() == CAMERA_VISIT ) // déjà une visite en cours ?
+ {
+ m_camera->StopVisit();
+ m_displayText->ClearVisit();
+ }
+ else
+ {
+ m_visitObject = DeselectAll(); // enlève les boutons de commande
+ }
+
+ // Crée le bouton "continuer".
+ if ( m_interface->SearchControl(EVENT_DT_END) == 0 )
+ {
+ pos.x = 10.0f/640.0f;
+ pos.y = 10.0f/480.0f;
+ dim.x = 50.0f/640.0f;
+ dim.y = 50.0f/480.0f;
+ m_interface->CreateButton(pos, dim, 16, EVENT_DT_END);
+ }
+
+ // Crée la flèche pour montrer l'endroit.
+ if ( m_visitArrow != 0 )
+ {
+ m_visitArrow->DeleteObject();
+ delete m_visitArrow;
+ m_visitArrow = 0;
+ }
+ goal = m_displayText->RetVisitGoal(event);
+ m_visitArrow = CreateObject(goal, 0.0f, 1.0f, 10.0f, OBJECT_SHOW, FALSE, FALSE, 0);
+
+ m_visitPos = m_visitArrow->RetPosition(0);
+ m_visitPosArrow = m_visitPos;
+ m_visitPosArrow.y += m_displayText->RetVisitHeight(event);
+ m_visitArrow->SetPosition(0, m_visitPosArrow);
+
+ m_visitTime = 0.0;
+ m_visitParticule = 0.0f;
+
+ m_particule->DeleteParticule(PARTISHOW);
+
+ m_camera->StartVisit(m_displayText->RetVisitGoal(event),
+ m_displayText->RetVisitDist(event));
+ m_displayText->SetVisit(event);
+ ChangePause(TRUE);
+}
+
+// Bouge la flèche de visite.
+
+void CRobotMain::FrameVisit(float rTime)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float level;
+
+ if ( m_visitArrow == 0 ) return;
+
+ // Bouge la flèche.
+ m_visitTime += rTime;
+
+ pos = m_visitPosArrow;
+ pos.y += 1.5f+sinf(m_visitTime*4.0f)*4.0f;
+ m_visitArrow->SetPosition(0, pos);
+ m_visitArrow->SetAngleY(0, m_visitTime*2.0f);
+
+ // Gère les particules "flèches".
+ m_visitParticule -= rTime;
+ if ( m_visitParticule <= 0.0f )
+ {
+ m_visitParticule = 1.5f;
+
+ pos = m_visitPos;
+ level = m_terrain->RetFloorLevel(pos)+2.0f;
+ if ( pos.y < level ) pos.y = level; // pas en-dessous du sol
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 30.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISHOW, 2.0f);
+ }
+}
+
+// Fin de la visite du lieu d'une erreur.
+
+void CRobotMain::StopDisplayVisit()
+{
+ m_visitLast = EVENT_NULL;
+
+ // Supprime le bouton.
+ m_interface->DeleteControl(EVENT_DT_END);
+
+ // Supprime la flèche.
+ if ( m_visitArrow != 0 )
+ {
+ m_visitArrow->DeleteObject();
+ delete m_visitArrow;
+ m_visitArrow = 0;
+ }
+
+ // Supprime les particules "flèches".
+ m_particule->DeleteParticule(PARTISHOW);
+
+ m_camera->StopVisit();
+ m_displayText->ClearVisit();
+ ChangePause(FALSE);
+ if ( m_visitObject != 0 )
+ {
+ SelectObject(m_visitObject, FALSE); // remet les boutons de commande
+ m_visitObject = 0;
+ }
+}
+
+
+
+// Met à jour tous les raccourcis.
+
+void CRobotMain::UpdateShortcuts()
+{
+ m_short->UpdateShortcuts();
+}
+
+// Retourne l'objet par défaut à sélectionner après la création d'une scène.
+
+CObject* CRobotMain::RetSelectObject()
+{
+ if ( m_selectObject != 0 ) return m_selectObject;
+ return SearchHuman();
+}
+
+// Désélectionne tout, et retourne l'objet qui était sélectionné.
+
+CObject* CRobotMain::DeselectAll()
+{
+ CObject* pObj;
+ CObject* pPrev;
+ int i;
+
+ pPrev = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetSelect() ) pPrev = pObj;
+ pObj->SetSelect(FALSE);
+ }
+ return pPrev;
+}
+
+// Sélectionne un objet, sans s'occuper de désélectionner le reste.
+
+void CRobotMain::SelectOneObject(CObject* pObj, BOOL bDisplayError)
+{
+ ObjectType type;
+ CObject* toto;
+ CMotionToto* mt;
+
+ pObj->SetSelect(TRUE, bDisplayError);
+ m_camera->SetObject(pObj);
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_APOLLO2 )
+ {
+ m_camera->SetType(pObj->RetCameraType());
+ m_camera->SetDist(pObj->RetCameraDist());
+ }
+ else
+ {
+ m_camera->SetType(CAMERA_BACK);
+ }
+
+ toto = SearchToto();
+ if ( toto != 0 )
+ {
+ mt = (CMotionToto*)toto->RetMotion();
+ if ( mt != 0 )
+ {
+ mt->SetLinkType(type);
+ }
+ }
+}
+
+// Sélectionne l'objet visé par la souris.
+
+BOOL CRobotMain::SelectObject(CObject* pObj, BOOL bDisplayError)
+{
+ CObject* pPrev;
+
+ if ( m_camera->RetType() == CAMERA_VISIT )
+ {
+ StopDisplayVisit();
+ }
+
+ if ( m_bMovieLock || m_bEditLock || m_bPause ) return FALSE;
+ if ( m_movie->IsExist() ) return FALSE;
+ if ( pObj == 0 || !IsSelectable(pObj) ) return FALSE;
+
+ pPrev = DeselectAll();
+
+ if ( pPrev != 0 && pPrev != pObj )
+ {
+ pObj->AddDeselList(pPrev);
+ }
+
+ SelectOneObject(pObj, bDisplayError);
+ m_short->UpdateShortcuts();
+ return TRUE;
+}
+
+// Désélectionne l'objet sélectionné.
+
+BOOL CRobotMain::DeselectObject()
+{
+ CObject* pObj;
+ CObject* pPrev;
+
+ pPrev = DeselectAll();
+
+ if ( pPrev == 0 )
+ {
+ pObj = SearchHuman();
+ }
+ else
+ {
+ pObj = pPrev->SubDeselList();
+ }
+ if ( pObj == 0 )
+ {
+ pObj = SearchHuman();
+ }
+
+ if ( pObj != 0 )
+ {
+ SelectOneObject(pObj);
+ }
+ else
+ {
+ m_camera->SetType(CAMERA_FREE);
+ }
+
+ m_short->UpdateShortcuts();
+ return TRUE;
+}
+
+// Supprime rapidement tous les objets.
+
+void CRobotMain::DeleteAllObjects()
+{
+ CPyro* pyro;
+ CObject* pObj;
+ int i;
+
+ // Supprime tous les effets pyrotechniques en cours.
+ while ( TRUE )
+ {
+ pyro = (CPyro*)m_iMan->SearchInstance(CLASS_PYRO, 0);
+ if ( pyro == 0 ) break;
+
+ pyro->DeleteObject();
+ delete pyro;
+ }
+
+ // Supprime la flèche.
+ if ( m_visitArrow != 0 )
+ {
+ m_visitArrow->DeleteObject();
+ delete m_visitArrow;
+ m_visitArrow = 0;
+ }
+
+ for ( i=0 ; i<MAXSHOWLIMIT ; i++ )
+ {
+ FlushShowLimit(i);
+ }
+
+ while ( TRUE )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, 0);
+ if ( pObj == 0 ) break;
+
+ pObj->DeleteObject(TRUE); // détruit rapidement
+ delete pObj;
+ }
+}
+
+// Sélectionne l'homme.
+
+void CRobotMain::SelectHuman()
+{
+ SelectObject(SearchHuman());
+}
+
+// Retourne l'objet de l'homme.
+
+CObject* CRobotMain::SearchHuman()
+{
+ ObjectType type;
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN )
+ {
+ return pObj;
+ }
+ }
+ return 0;
+}
+
+// Retourne l'objet de toto.
+
+CObject* CRobotMain::SearchToto()
+{
+ ObjectType type;
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_TOTO )
+ {
+ return pObj;
+ }
+ }
+ return 0;
+}
+
+// Retourne l'objet sélectionnable le plus proche d'une position donnée.
+
+CObject* CRobotMain::SearchNearest(D3DVECTOR pos, CObject* pExclu)
+{
+ ObjectType type;
+ CObject *pObj, *pBest;
+ D3DVECTOR oPos;
+ float min, dist;
+ int i;
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == pExclu ) continue;
+ if ( !IsSelectable(pObj) ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_TOTO ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, pos);
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+ return pBest;
+}
+
+// Retourne l'objet sélectionné.
+
+CObject* CRobotMain::RetSelect()
+{
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetSelect() )
+ {
+ return pObj;
+ }
+ }
+ return 0;
+}
+
+CObject* CRobotMain::SearchObject(ObjectType type)
+{
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetType() == type )
+ {
+ return pObj;
+ }
+ }
+ return 0;
+}
+
+// Détecte l'objet visé par la souris.
+
+CObject* CRobotMain::DetectObject(FPOINT pos)
+{
+ ObjectType type;
+ CObject *pObj, *pTarget;
+ int objRank, i, j, rank;
+
+ objRank = m_engine->DetectObject(pos);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+
+ pTarget = 0;
+ type = pObj->RetType();
+ if ( type == OBJECT_PORTICO ||
+ type == OBJECT_BASE ||
+ 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_TARGET1 ||
+ type == OBJECT_TARGET2 ||
+ type == OBJECT_START ||
+ type == OBJECT_END ||
+ type == OBJECT_STONE ||
+ type == OBJECT_URANIUM ||
+ type == OBJECT_BULLET ||
+ type == OBJECT_METAL ||
+ type == OBJECT_BBOX ||
+ type == OBJECT_KEYa ||
+ type == OBJECT_KEYb ||
+ type == OBJECT_KEYc ||
+ type == OBJECT_KEYd ||
+ type == OBJECT_TNT ||
+ type == OBJECT_SCRAP1 ||
+ type == OBJECT_SCRAP2 ||
+ type == OBJECT_SCRAP3 ||
+ type == OBJECT_SCRAP4 ||
+ type == OBJECT_SCRAP5 ||
+ type == OBJECT_BOMB ||
+ type == OBJECT_BAG ||
+ type == OBJECT_WAYPOINT ||
+ type == OBJECT_FLAGb ||
+ type == OBJECT_FLAGr ||
+ type == OBJECT_FLAGg ||
+ type == OBJECT_FLAGy ||
+ type == OBJECT_FLAGv ||
+ type == OBJECT_MARKPOWER ||
+ type == OBJECT_MARKSTONE ||
+ type == OBJECT_MARKURANIUM ||
+ type == OBJECT_MARKKEYa ||
+ type == OBJECT_MARKKEYb ||
+ type == OBJECT_MARKKEYc ||
+ type == OBJECT_MARKKEYd ||
+ type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_TOTO ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_EGG ||
+ type == OBJECT_RUINmobilew1 ||
+ type == OBJECT_RUINmobilew2 ||
+ type == OBJECT_RUINmobilet1 ||
+ type == OBJECT_RUINmobilet2 ||
+ type == OBJECT_RUINmobiler1 ||
+ type == OBJECT_RUINmobiler2 ||
+ type == OBJECT_RUINfactory ||
+ type == OBJECT_RUINdoor ||
+ type == OBJECT_RUINsupport ||
+ type == OBJECT_RUINradar ||
+ type == OBJECT_RUINconvert ||
+ type == OBJECT_RUINbase ||
+ type == OBJECT_RUINhead ||
+ type == OBJECT_APOLLO1 ||
+ type == OBJECT_APOLLO2 ||
+ type == OBJECT_APOLLO3 ||
+ type == OBJECT_APOLLO4 ||
+ type == OBJECT_APOLLO5 )
+ {
+ pTarget = pObj;
+ }
+ else if ( (type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC ) &&
+ pObj->RetTruck() != 0 ) // pile utilisée ?
+ {
+ pTarget = pObj->RetTruck();
+ }
+ else if ( type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC )
+ {
+ pTarget = pObj;
+ }
+
+ for ( j=0 ; j<OBJECTMAXPART ; j++ )
+ {
+ rank = pObj->RetObjectRank(j);
+ if ( rank == -1 ) continue;
+ if ( rank != objRank ) continue;
+ return pTarget;
+ }
+ }
+ return 0;
+}
+
+// Indique si un objet est sélectionnable.
+
+BOOL CRobotMain::IsSelectable(CObject* pObj)
+{
+ ObjectType type;
+
+ if ( !pObj->RetSelectable() ) return FALSE;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TOTO ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_APOLLO2 ||
+ type == OBJECT_BASE ||
+ 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 )
+ {
+ return TRUE;
+ }
+
+ if ( m_bSelectInsect )
+ {
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_MOBILEtg )
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+// Supprime l'objet sélectionné.
+
+BOOL CRobotMain::DeleteObject()
+{
+ CObject* pObj;
+ CPyro* pyro;
+
+ pObj = RetSelect();
+ if ( pObj == 0 ) return FALSE;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj);
+
+ pObj->SetSelect(FALSE); // désélectionne l'objet
+ m_camera->SetType(CAMERA_EXPLO);
+ DeselectAll();
+ pObj->DeleteDeselList(pObj);
+
+ return TRUE;
+}
+
+
+// Enlève la mise en évidence de l'objet survolé par la souris.
+
+void CRobotMain::HiliteClear()
+{
+ CObject* pObj;
+ int i;
+
+ ClearTooltip();
+ m_tooltipName[0] = 0; // enlève vraiment le tooltip
+
+ if ( !m_bHilite ) return;
+
+ i = -1;
+ m_engine->SetHiliteRank(&i); // plus rien de sélectionné
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ pObj->SetHilite(FALSE);
+ m_map->SetHilite(0);
+ m_short->SetHilite(0);
+ }
+
+ m_bHilite = FALSE;
+}
+
+// Met en évidence l'objet survolé par la souris.
+
+void CRobotMain::HiliteObject(FPOINT pos)
+{
+ CObject* pObj;
+ char name[100];
+ BOOL bInMap;
+
+ if ( m_bFixScene && m_phase != PHASE_PERSO ) return;
+ if ( m_bMovieLock ) return;
+ if ( m_movie->IsExist() ) return;
+ if ( m_engine->RetMouseHide() ) return;
+
+ ClearInterface(); // enlève mise en évidence et tooltip
+
+ pObj = m_short->DetectShort(pos);
+
+ if ( m_dialog->RetTooltip() && m_interface->GetTooltip(pos, name) )
+ {
+ m_tooltipPos = pos;
+ strcpy(m_tooltipName, name);
+ m_tooltipTime = 0.0f;
+ if ( pObj == 0 ) return;
+ }
+
+ if ( m_bSuspend ) return;
+
+ if ( pObj == 0 )
+ {
+ pObj = m_map->DetectMap(pos, bInMap);
+ if ( pObj == 0 )
+ {
+ if ( bInMap ) return;
+
+ pObj = DetectObject(pos);
+
+ if ( m_camera->RetType() == CAMERA_ONBOARD &&
+ m_camera->RetObject() == pObj )
+ {
+ return;
+ }
+ }
+ }
+
+ if ( pObj != 0 )
+ {
+ if ( m_dialog->RetTooltip() && pObj->GetTooltipName(name) )
+ {
+ m_tooltipPos = pos;
+ strcpy(m_tooltipName, name);
+ m_tooltipTime = 0.0f;
+ }
+
+ if ( IsSelectable(pObj) )
+ {
+ pObj->SetHilite(TRUE);
+ m_map->SetHilite(pObj);
+ m_short->SetHilite(pObj);
+ m_bHilite = TRUE;
+ }
+ }
+}
+
+// Met en évidence l'objet survolé par la souris.
+
+void CRobotMain::HiliteFrame(float rTime)
+{
+ if ( m_bFixScene && m_phase != PHASE_PERSO ) return;
+ if ( m_bMovieLock ) return;
+ if ( m_movie->IsExist() ) return;
+
+ m_tooltipTime += rTime;
+
+ ClearTooltip();
+
+ if ( m_tooltipTime >= 0.2f &&
+ m_tooltipName[0] != 0 )
+ {
+ CreateTooltip(m_tooltipPos, m_tooltipName);
+ }
+}
+
+// Crée un tooltip.
+
+void CRobotMain::CreateTooltip(FPOINT pos, char* text)
+{
+ CWindow* pw;
+ FPOINT start, end, dim, offset, corner;
+
+ corner.x = pos.x+0.022f;
+ corner.y = pos.y-0.052f;
+
+ m_engine->RetText()->DimText(text, corner, 1,
+ SMALLFONT, NORMSTRETCH, FONT_COLOBOT,
+ start, end);
+ start.x -= 0.010f;
+ start.y -= 0.002f;
+ end.x += 0.010f;
+ end.y += 0.004f; // ch'tite marge
+
+ pos.x = start.x;
+ pos.y = start.y;
+ dim.x = end.x-start.x;
+ dim.y = end.y-start.y;
+
+ offset.x = 0.0f;
+ offset.y = 0.0f;
+ if ( pos.x+dim.x > 1.0f ) offset.x = 1.0f-(pos.x+dim.x);
+ if ( pos.y < 0.0f ) offset.y = -pos.y;
+
+ corner.x += offset.x;
+ corner.y += offset.y;
+ pos.x += offset.x;
+ pos.y += offset.y;
+
+ m_interface->CreateWindows(pos, dim, 1, EVENT_TOOLTIP);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_TOOLTIP);
+ if ( pw != 0 )
+ {
+ pw->SetState(STATE_SHADOW);
+ pw->SetTrashEvent(FALSE);
+
+ pos.y -= m_engine->RetText()->RetHeight(SMALLFONT, FONT_COLOBOT)/2.0f;
+ pw->CreateLabel(pos, dim, -1, EVENT_LABEL2, text);
+ }
+}
+
+// Efface le tooltip précédent.
+
+void CRobotMain::ClearTooltip()
+{
+ m_interface->DeleteControl(EVENT_TOOLTIP);
+}
+
+
+// Affiche l'aide pour un objet.
+
+void CRobotMain::HelpObject()
+{
+ CObject* pObj;
+ char* filename;
+
+ pObj = RetSelect();
+ if ( pObj == 0 ) return;
+
+ filename = RetHelpFilename(pObj->RetType());
+ if ( filename[0] == 0 ) return;
+
+ StartDisplayInfo(filename, -1);
+}
+
+
+// Change le mode de la caméra.
+
+void CRobotMain::ChangeCamera()
+{
+ CObject* pObj;
+ ObjectType oType;
+ CameraType type;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetSelect() )
+ {
+ if ( pObj->RetCameraLock() ) return;
+
+ oType = pObj->RetType();
+ type = pObj->RetCameraType();
+
+ if ( oType != OBJECT_MOBILEfa &&
+ oType != OBJECT_MOBILEta &&
+ oType != OBJECT_MOBILEwa &&
+ oType != OBJECT_MOBILEia &&
+ oType != OBJECT_MOBILEfc &&
+ oType != OBJECT_MOBILEtc &&
+ oType != OBJECT_MOBILEwc &&
+ oType != OBJECT_MOBILEic &&
+ oType != OBJECT_MOBILEfi &&
+ oType != OBJECT_MOBILEti &&
+ oType != OBJECT_MOBILEwi &&
+ oType != OBJECT_MOBILEii &&
+ oType != OBJECT_MOBILEfs &&
+ oType != OBJECT_MOBILEts &&
+ oType != OBJECT_MOBILEws &&
+ oType != OBJECT_MOBILEis &&
+ oType != OBJECT_MOBILErt &&
+ oType != OBJECT_MOBILErc &&
+ oType != OBJECT_MOBILErr &&
+ oType != OBJECT_MOBILErs &&
+ oType != OBJECT_MOBILEsa &&
+ oType != OBJECT_MOBILEtg &&
+ oType != OBJECT_MOBILEft &&
+ oType != OBJECT_MOBILEtt &&
+ oType != OBJECT_MOBILEwt &&
+ oType != OBJECT_MOBILEit &&
+ oType != OBJECT_MOBILEdr &&
+ oType != OBJECT_APOLLO2 ) return;
+
+ if ( oType == OBJECT_MOBILEdr ) // dessinateur ?
+ {
+ if ( type == CAMERA_PLANE ) type = CAMERA_BACK;
+ else if ( type == CAMERA_BACK ) type = CAMERA_PLANE;
+ }
+ else if ( pObj->RetTrainer() ) // entraînement ?
+ {
+ if ( type == CAMERA_ONBOARD ) type = CAMERA_FIX;
+ else if ( type == CAMERA_FIX ) type = CAMERA_PLANE;
+ else if ( type == CAMERA_PLANE ) type = CAMERA_BACK;
+ else if ( type == CAMERA_BACK ) type = CAMERA_ONBOARD;
+ }
+ else
+ {
+ if ( type == CAMERA_ONBOARD ) type = CAMERA_BACK;
+ else if ( type == CAMERA_BACK ) type = CAMERA_ONBOARD;
+ }
+
+ pObj->SetCameraType(type);
+ m_camera->SetType(type);
+ }
+ }
+}
+
+// Télécommande la caméra avec les touches flèches.
+
+void CRobotMain::KeyCamera(EventMsg event, long param)
+{
+ CObject* pObj;
+
+ if ( event == EVENT_KEYUP )
+ {
+ if ( param == m_engine->RetKey(KEYRANK_LEFT, 0) ||
+ param == m_engine->RetKey(KEYRANK_LEFT, 1) )
+ {
+ m_cameraPan = 0.0f;
+ }
+
+ if ( param == m_engine->RetKey(KEYRANK_RIGHT, 0) ||
+ param == m_engine->RetKey(KEYRANK_RIGHT, 1) )
+ {
+ m_cameraPan = 0.0f;
+ }
+
+ if ( param == m_engine->RetKey(KEYRANK_UP, 0) ||
+ param == m_engine->RetKey(KEYRANK_UP, 1) )
+ {
+ m_cameraZoom = 0.0f;
+ }
+
+ if ( param == m_engine->RetKey(KEYRANK_DOWN, 0) ||
+ param == m_engine->RetKey(KEYRANK_DOWN, 1) )
+ {
+ m_cameraZoom = 0.0f;
+ }
+ }
+
+ if ( m_phase != PHASE_SIMUL ) return;
+ if ( m_bEditLock ) return; // édition en cours ?
+ if ( m_bTrainerPilot ) return;
+
+ pObj = RetSelect();
+ if ( pObj == 0 ) return;
+ if ( !pObj->RetTrainer() ) return;
+
+ if ( event == EVENT_KEYDOWN )
+ {
+ if ( param == m_engine->RetKey(KEYRANK_LEFT, 0) ||
+ param == m_engine->RetKey(KEYRANK_LEFT, 1) )
+ {
+ m_cameraPan = -1.0f;
+ }
+
+ if ( param == m_engine->RetKey(KEYRANK_RIGHT, 0) ||
+ param == m_engine->RetKey(KEYRANK_RIGHT, 1) )
+ {
+ m_cameraPan = 1.0f;
+ }
+
+ if ( param == m_engine->RetKey(KEYRANK_UP, 0) ||
+ param == m_engine->RetKey(KEYRANK_UP, 1) )
+ {
+ m_cameraZoom = -1.0f;
+ }
+
+ if ( param == m_engine->RetKey(KEYRANK_DOWN, 0) ||
+ param == m_engine->RetKey(KEYRANK_DOWN, 1) )
+ {
+ m_cameraZoom = 1.0f;
+ }
+ }
+}
+
+// Effectue un panoramique avec la caméra si un bouton est enfoncé.
+
+void CRobotMain::RemoteCamera(float pan, float zoom, float rTime)
+{
+ float value;
+
+ if ( pan != 0.0f )
+ {
+ value = m_camera->RetRemotePan();
+ value += pan*rTime*1.5f;
+ m_camera->SetRemotePan(value);
+ }
+
+ if ( zoom != 0.0f )
+ {
+ value = m_camera->RetRemoteZoom();
+ value += zoom*rTime*0.3f;
+ m_camera->SetRemoteZoom(value);
+ }
+}
+
+
+
+// Annule le film en cours.
+
+void CRobotMain::AbortMovie()
+{
+ CObject* pObj;
+ CAuto* automat;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ automat = pObj->RetAuto();
+ if ( automat != 0 )
+ {
+ automat->Abort();
+ }
+ }
+
+ m_engine->SetMouseHide(FALSE);
+}
+
+
+
+// Met à jour le texte d'informations.
+
+void CRobotMain::UpdateInfoText()
+{
+ CObject* pObj;
+ D3DVECTOR pos;
+ char info[100];
+
+ if ( m_bShowPos )
+ {
+ pObj = RetSelect();
+ if ( pObj != 0 )
+ {
+ pos = pObj->RetPosition(0);
+ sprintf(info, "Pos = %.2f ; %.2f", pos.x/g_unit, pos.z/g_unit);
+ m_engine->SetInfoText(4, info);
+ }
+ }
+}
+
+
+// Initialise le point de vue.
+
+void CRobotMain::InitEye()
+{
+ if ( m_phase == PHASE_SIMUL )
+ {
+ m_camera->Init(D3DVECTOR( 0.0f, 10.0f, 0.0f),
+ D3DVECTOR(10.0f, 5.0f, 0.0f), 0.0f);
+ }
+
+ if ( m_phase == PHASE_MODEL )
+ {
+ m_model->InitView();
+ }
+}
+
+// Fait progresser toute la scène.
+
+BOOL CRobotMain::EventFrame(const Event &event)
+{
+ ObjectType type;
+ CObject *pObj, *toto;
+ CPyro* pPyro;
+ CWindow* pw;
+ CMap* pm;
+ int i;
+
+ m_time += event.rTime;
+ if ( !m_bMovieLock ) m_gameTime += event.rTime;
+
+ if ( !m_bImmediatSatCom && !m_bBeginSatCom &&
+ m_gameTime > 0.1f && m_phase == PHASE_SIMUL )
+ {
+ m_displayText->DisplayError(INFO_BEGINSATCOM, D3DVECTOR(0.0f,0.0f,0.0f));
+ m_bBeginSatCom = TRUE; // message affiché
+ }
+
+ m_water->EventProcess(event);
+ m_cloud->EventProcess(event);
+ m_blitz->EventProcess(event);
+ m_planet->EventProcess(event);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw == 0 )
+ {
+ pm = 0;
+ }
+ else
+ {
+ pm = (CMap*)pw->SearchControl(EVENT_OBJECT_MAP);
+ if ( pm != 0 ) pm->FlushObject();
+ }
+
+ toto = 0;
+ if ( !m_bFreePhoto )
+ {
+ // Fait progresser tous les robots, mais pas toto.
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pm != 0 ) pm->UpdateObject(pObj);
+ if ( pObj->RetTruck() != 0 ) continue;
+ type = pObj->RetType();
+ if ( type == OBJECT_TOTO )
+ {
+ toto = pObj;
+ }
+ else
+ {
+ pObj->EventProcess(event);
+ }
+ }
+ // Fait progresser tous les objets transportés par les robots.
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj->RetTruck() == 0 ) continue;
+ pObj->EventProcess(event);
+ }
+
+ // Fait progresser les effets pyrotechniques.
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pPyro = (CPyro*)m_iMan->SearchInstance(CLASS_PYRO, i);
+ if ( pPyro == 0 ) break;
+
+ pPyro->EventProcess(event);
+ if ( pPyro->IsEnded() != ERR_CONTINUE )
+ {
+ pPyro->DeleteObject();
+ delete pPyro;
+ }
+ }
+ }
+
+ // Fait bouger la caméra après les objets, car sa position peut
+ // dépendre de l'objet sélectionné (CAMERA_ONBOARD ou CAMERA_BACK).
+ if ( m_phase == PHASE_SIMUL && !m_bEditFull )
+ {
+ m_camera->EventProcess(event);
+
+ if ( m_engine->RetFog() )
+ {
+ m_camera->SetOverBaseColor(m_particule->RetFogColor(m_engine->RetEyePt()));
+ }
+ }
+ if ( m_phase == PHASE_PERSO ||
+ m_phase == PHASE_WIN ||
+ m_phase == PHASE_LOST )
+ {
+ m_camera->EventProcess(event);
+ }
+
+ // Fait progresser toto après la caméra, car sa position dépend
+ // de la caméra.
+ if ( toto != 0 )
+ {
+ toto->EventProcess(event);
+ }
+
+ // Fait progresser le modèle.
+ if ( m_phase == PHASE_MODEL )
+ {
+ m_model->ViewMove(event, 2.0f);
+ m_model->UpdateView();
+ m_model->EventProcess(event);
+ }
+
+ HiliteFrame(event.rTime);
+
+ // Fait bouger l'indicateur de film.
+ if ( m_bMovieLock && !m_bEditLock ) // film en cours ?
+ {
+ CControl* pc;
+ FPOINT pos, dim;
+ float zoom;
+
+ pc = m_interface->SearchControl(EVENT_OBJECT_MOVIELOCK);
+ if ( pc != 0 )
+ {
+ dim.x = 32.0f/640.0f;
+ dim.y = 32.0f/480.0f;
+ pos.x = 20.0f/640.0f;
+ pos.y = (480.0f-24.0f)/480.0f;
+
+ zoom = 1.0f+sinf(m_time*6.0f)*0.1f; // 0.9 .. 1.1
+ dim.x *= zoom;
+ dim.y *= zoom;
+ pos.x -= dim.x/2.0f;
+ pos.y -= dim.y/2.0f;
+
+ pc->SetPos(pos);
+ pc->SetDim(dim);
+ }
+ }
+
+ // Fait bouger l'indicateur d'édition.
+ if ( m_bEditLock || m_bPause ) // édition en cours ?
+ {
+ CControl* pc;
+ FPOINT pos, dim;
+ float zoom;
+
+ pc = m_interface->SearchControl(EVENT_OBJECT_EDITLOCK);
+ if ( pc != 0 )
+ {
+ if ( m_bEditFull || m_bEditLock )
+ {
+ dim.x = 10.0f/640.0f;
+ dim.y = 10.0f/480.0f;
+ pos.x = -20.0f/640.0f;
+ pos.y = -20.0f/480.0f; // invisible !
+ }
+ else
+ {
+ dim.x = 32.0f/640.0f;
+ dim.y = 32.0f/480.0f;
+ pos.x = 20.0f/640.0f;
+ pos.y = (480.0f-24.0f)/480.0f;
+
+ zoom = 1.0f+sinf(m_time*6.0f)*0.1f; // 0.9 .. 1.1
+ dim.x *= zoom;
+ dim.y *= zoom;
+ pos.x -= dim.x/2.0f;
+ pos.y -= dim.y/2.0f;
+ }
+ pc->SetPos(pos);
+ pc->SetDim(dim);
+ }
+ }
+
+ // Fait bouger la flèche de visite.
+ if ( m_camera->RetType() == CAMERA_VISIT )
+ {
+ FrameVisit(event.rTime);
+ }
+
+ // Fait bouger les limites.
+ FrameShowLimit(event.rTime);
+
+ if ( m_phase == PHASE_SIMUL )
+ {
+ if ( !m_bEditLock && m_checkEndTime+1.0f < m_time )
+ {
+ m_checkEndTime = m_time;
+ CheckEndMission(TRUE);
+ }
+
+ if ( m_winDelay > 0.0f && !m_bEditLock )
+ {
+ m_winDelay -= event.rTime;
+ if ( m_winDelay <= 0.0f )
+ {
+ if ( m_bMovieLock )
+ {
+ m_winDelay = 1.0f;
+ }
+ else
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, EVENT_WIN);
+ m_event->AddEvent(newEvent);
+ }
+ }
+ }
+
+ if ( m_lostDelay > 0.0f && !m_bEditLock )
+ {
+ m_lostDelay -= event.rTime;
+ if ( m_lostDelay <= 0.0f )
+ {
+ if ( m_bMovieLock )
+ {
+ m_winDelay = 1.0f;
+ }
+ else
+ {
+ Event newEvent;
+ m_event->MakeEvent(newEvent, EVENT_LOST);
+ m_event->AddEvent(newEvent);
+ }
+ }
+ }
+ }
+
+ if ( m_delayWriteMessage > 0 )
+ {
+ m_delayWriteMessage --;
+ if ( m_delayWriteMessage == 0 )
+ {
+ m_displayText->DisplayError(INFO_WRITEOK, D3DVECTOR(0.0f,0.0f,0.0f));
+ }
+ }
+
+ return S_OK;
+}
+
+// Donne l'événement à tous les robots.
+
+BOOL CRobotMain::EventObject(const Event &event)
+{
+ CObject* pObj;
+ int i;
+
+ if ( m_bFreePhoto ) return S_OK;
+
+ m_bResetCreate = FALSE;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ pObj->EventProcess(event);
+ }
+
+ if ( m_bResetCreate )
+ {
+ ResetCreate();
+ }
+
+ return S_OK;
+}
+
+
+// Calcule le point d'arrivée de la caméra.
+
+D3DVECTOR CRobotMain::LookatPoint(D3DVECTOR eye, float angleH, float angleV,
+ float length)
+{
+ D3DVECTOR lookat;
+
+ lookat = eye;
+ lookat.z += length;
+
+ RotatePoint(eye, angleH, angleV, lookat);
+ return lookat;
+}
+
+
+
+char* SkipNum(char *p)
+{
+ while ( *p == ' ' || *p == '.' || *p == '-' || (*p >= '0' && *p <= '9') )
+ {
+ p++;
+ }
+ return p;
+}
+
+// Conversion des unités.
+
+void CRobotMain::Convert()
+{
+ FILE* file = NULL;
+ FILE* fileNew = NULL;
+ char line[500];
+ char lineNew[500];
+ char s[200];
+ char* base;
+ char* p;
+ int rank;
+ D3DVECTOR pos;
+ float value;
+
+ base = m_dialog->RetSceneName();
+ rank = m_dialog->RetSceneRank();
+
+ m_dialog->BuildSceneName(line, base, rank);
+ file = fopen(line, "r");
+ if ( file == NULL ) return;
+
+ strcpy(line+strlen(line)-4, ".new");
+ fileNew = fopen(line, "w");
+ if ( fileNew == NULL ) return;
+
+ while ( fgets(line, 500, file) != NULL )
+ {
+ strcpy(lineNew, line);
+
+ if ( Cmd(line, "DeepView") )
+ {
+ p = strstr(line, "air=");
+ if ( p != 0 )
+ {
+ value = OpFloat(line, "air", 500.0f);
+ value /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+4);
+ strcpy(lineNew, line);
+ strcat(lineNew, "air=");
+ sprintf(s, "%.2f", value);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ strcpy(line, lineNew);
+
+ p = strstr(line, "water=");
+ if ( p != 0 )
+ {
+ value = OpFloat(line, "water", 100.0f);
+ value /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+6);
+ strcpy(lineNew, line);
+ strcat(lineNew, "water=");
+ sprintf(s, "%.2f", value);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ strcpy(line, lineNew);
+ }
+
+ if ( Cmd(line, "TerrainGenerate") )
+ {
+ p = strstr(line, "vision=");
+ if ( p != 0 )
+ {
+ value = OpFloat(line, "vision", 500.0f);
+ value /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+7);
+ strcpy(lineNew, line);
+ strcat(lineNew, "vision=");
+ sprintf(s, "%.2f", value);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ }
+
+ if ( Cmd(line, "CreateObject") ||
+ Cmd(line, "CreateSpot") )
+ {
+ p = strstr(line, "pos=");
+ if ( p != 0 )
+ {
+ pos = OpPos(line, "pos");
+ pos.x /= g_unit;
+ pos.y /= g_unit;
+ pos.z /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+4);
+ p = SkipNum(p+1);
+ strcpy(lineNew, line);
+ strcat(lineNew, "pos=");
+ sprintf(s, "%.2f", pos.x);
+ strcat(lineNew, s);
+ strcat(lineNew, ";");
+ sprintf(s, "%.2f", pos.z);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ }
+
+ if ( Cmd(line, "EndMissionTake") )
+ {
+ p = strstr(line, "pos=");
+ if ( p != 0 )
+ {
+ pos = OpPos(line, "pos");
+ pos.x /= g_unit;
+ pos.y /= g_unit;
+ pos.z /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+4);
+ p = SkipNum(p+1);
+ strcpy(lineNew, line);
+ strcat(lineNew, "pos=");
+ sprintf(s, "%.2f", pos.x);
+ strcat(lineNew, s);
+ strcat(lineNew, ";");
+ sprintf(s, "%.2f", pos.z);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ strcpy(line, lineNew);
+
+ p = strstr(line, "dist=");
+ if ( p != 0 )
+ {
+ value = OpFloat(line, "dist", 32.0f);
+ value /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+5);
+ strcpy(lineNew, line);
+ strcat(lineNew, "dist=");
+ sprintf(s, "%.2f", value);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ strcpy(line, lineNew);
+ }
+
+ if ( Cmd(line, "Camera") )
+ {
+ p = strstr(line, "pos=");
+ if ( p != 0 )
+ {
+ pos = OpPos(line, "pos");
+ pos.x /= g_unit;
+ pos.y /= g_unit;
+ pos.z /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+4);
+ p = SkipNum(p+1);
+ strcpy(lineNew, line);
+ strcat(lineNew, "pos=");
+ sprintf(s, "%.2f", pos.x);
+ strcat(lineNew, s);
+ strcat(lineNew, ";");
+ sprintf(s, "%.2f", pos.z);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ strcpy(line, lineNew);
+
+ p = strstr(line, "h=");
+ if ( p != 0 )
+ {
+ value = OpFloat(line, "h", 32.0f);
+ value /= g_unit;
+ p[0] = 0;
+ p = SkipNum(p+2);
+ strcpy(lineNew, line);
+ strcat(lineNew, "h=");
+ sprintf(s, "%.2f", value);
+ strcat(lineNew, s);
+ strcat(lineNew, " ");
+ strcat(lineNew, p);
+ }
+ strcpy(line, lineNew);
+ }
+
+ fputs(lineNew, fileNew);
+ }
+
+ fclose(fileNew);
+ fclose(file);
+}
+
+// Charge la scène pour le personnage.
+
+void CRobotMain::ScenePerso()
+{
+ CObject* pObj;
+
+ DeleteAllObjects(); // supprime toute la scène 3D actuelle
+ m_engine->FlushObject();
+ m_terrain->FlushRelief(); // tout plat
+ m_terrain->FlushBuildingLevel();
+ m_terrain->FlushFlyingLimit();
+ m_light->FlushLight();
+ m_particule->FlushParticule();
+ m_iMan->Flush(CLASS_OBJECT);
+ m_iMan->Flush(CLASS_PHYSICS);
+ m_iMan->Flush(CLASS_BRAIN);
+ m_iMan->Flush(CLASS_PYRO);
+
+ m_dialog->SetSceneName("perso");
+ m_dialog->SetSceneRank(0);
+ CreateScene(FALSE, TRUE, FALSE); // scène fixe
+
+ m_engine->SetDrawWorld(FALSE); // ne dessine rien sous l'interface
+ m_engine->SetDrawFront(TRUE); // dessine human sur l'interface
+ pObj = SearchHuman();
+ if ( pObj != 0 )
+ {
+ CMotionHuman* mh;
+
+ pObj->SetDrawFront(TRUE); // dessine sur l'interface
+
+ mh = (CMotionHuman*)pObj->RetMotion();
+ if ( mh != 0 )
+ {
+ mh->StartDisplayPerso();
+ }
+ }
+}
+
+// Crée toute la scène.
+
+void CRobotMain::CreateScene(BOOL bSoluce, BOOL bFixScene, BOOL bResetObject)
+{
+ CObject* pObj;
+ CObject* pSel;
+ CMotion* motion;
+ FILE* file = NULL;
+ char line[500];
+ char name[200];
+ char dir[100];
+ char op[100];
+ char* read;
+ char* stack;
+ char* base;
+ D3DCOLORVALUE color;
+ D3DVECTOR pos;
+ int rank, obj, i, rankObj, rankGadget;
+
+//? Convert();
+
+ base = m_dialog->RetSceneName();
+ rank = m_dialog->RetSceneRank();
+ read = m_dialog->RetSceneRead();
+ stack = m_dialog->RetStackRead();
+ m_dialog->SetUserDir(base, rank);
+
+ m_bFixScene = bFixScene;
+
+ g_id = 0;
+ m_bBase = FALSE;
+
+ if ( !bResetObject )
+ {
+ g_build = 0;
+ g_researchDone = 0; // aucune recherche effectuée
+ g_researchEnable = 0;
+
+ FlushDisplayInfo();
+ m_terrain->LevelFlush();
+ m_audioTrack = 0;
+ m_bAudioRepeat = TRUE;
+ m_displayText->SetDelay(1.0f);
+ m_displayText->SetEnable(TRUE);
+ m_bImmediatSatCom = FALSE;
+ m_endingWinRank = 0;
+ m_endingLostRank = 0;
+ m_endTakeTotal = 0;
+ m_endTakeResearch = 0;
+ m_endTakeWinDelay = 2.0f;
+ m_endTakeLostDelay = 2.0f;
+ m_obligatoryTotal = 0;
+ m_prohibitedTotal = 0;
+ m_bMapShow = TRUE;
+ m_bMapImage = FALSE;
+ m_mapFilename[0] = 0;
+
+ m_colorRefBot.r = 10.0f/256.0f;
+ m_colorRefBot.g = 166.0f/256.0f;
+ m_colorRefBot.b = 254.0f/256.0f; // bleu
+ m_colorRefBot.a = 0.0f;
+ m_colorNewBot = m_colorRefBot;
+
+ m_colorRefAlien.r = 135.0f/256.0f;
+ m_colorRefAlien.g = 170.0f/256.0f;
+ m_colorRefAlien.b = 13.0f/256.0f; // vert
+ m_colorRefAlien.a = 0.0f;
+ m_colorNewAlien = m_colorRefAlien;
+
+ m_colorRefGreen.r = 135.0f/256.0f;
+ m_colorRefGreen.g = 170.0f/256.0f;
+ m_colorRefGreen.b = 13.0f/256.0f; // vert
+ m_colorRefGreen.a = 0.0f;
+ m_colorNewGreen = m_colorRefGreen;
+
+ m_colorRefWater.r = 25.0f/256.0f;
+ m_colorRefWater.g = 255.0f/256.0f;
+ m_colorRefWater.b = 240.0f/256.0f; // cyan
+ m_colorRefWater.a = 0.0f;
+ m_colorNewWater = m_colorRefWater;
+
+ m_dialog->BuildResumeName(m_title, base, rank);
+ m_dialog->BuildResumeName(m_resume, base, rank);
+ GetResource(RES_TEXT, RT_SCRIPT_NEW, m_scriptName);
+ m_scriptFile[0] = 0;
+ }
+
+ m_dialog->BuildSceneName(line, base, rank);
+ file = fopen(line, "r");
+ if ( file == NULL ) return;
+
+ rankObj = 0;
+ rankGadget = 0;
+ pSel = 0;
+
+ while ( fgets(line, 500, file) != NULL )
+ {
+ for ( i=0 ; i<500 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ sprintf(op, "Title.%c", RetLanguageLetter());
+ if ( Cmd(line, op) && !bResetObject )
+ {
+ OpString(line, "text", m_title);
+ }
+
+ sprintf(op, "Resume.%c", RetLanguageLetter());
+ if ( Cmd(line, op) && !bResetObject )
+ {
+ OpString(line, "text", m_resume);
+ }
+
+ sprintf(op, "ScriptName.%c", RetLanguageLetter());
+ if ( Cmd(line, op) && !bResetObject )
+ {
+ OpString(line, "text", m_scriptName);
+ }
+
+ if ( Cmd(line, "ScriptFile") && !bResetObject )
+ {
+ OpString(line, "name", m_scriptFile);
+ }
+
+ if ( Cmd(line, "Instructions") && !bResetObject )
+ {
+ OpString(line, "name", name);
+//? sprintf(m_infoFilename[SATCOM_HUSTON], "help\\%s", name);
+ UserDir(m_infoFilename[SATCOM_HUSTON], name, "help");
+
+ m_bImmediatSatCom = OpInt(line, "immediat", 0);
+ }
+
+ if ( Cmd(line, "Satellite") && !bResetObject )
+ {
+ OpString(line, "name", name);
+//? sprintf(m_infoFilename[SATCOM_SAT], "help\\%s", name);
+ UserDir(m_infoFilename[SATCOM_SAT], name, "help");
+ }
+
+ if ( Cmd(line, "Loading") && !bResetObject )
+ {
+ OpString(line, "name", name);
+//? sprintf(m_infoFilename[SATCOM_LOADING], "help\\%s", name);
+ UserDir(m_infoFilename[SATCOM_LOADING], name, "help");
+ }
+
+ if ( Cmd(line, "HelpFile") && !bResetObject )
+ {
+ OpString(line, "name", name);
+//? sprintf(m_infoFilename[SATCOM_PROG], "help\\%s", name);
+ UserDir(m_infoFilename[SATCOM_PROG], name, "help");
+ }
+ if ( Cmd(line, "SoluceFile") && !bResetObject )
+ {
+ OpString(line, "name", name);
+//? sprintf(m_infoFilename[SATCOM_SOLUCE], "help\\%s", name);
+ UserDir(m_infoFilename[SATCOM_SOLUCE], name, "help");
+ }
+
+ if ( Cmd(line, "EndingFile") && !bResetObject )
+ {
+ m_endingWinRank = OpInt(line, "win", 0);
+ m_endingLostRank = OpInt(line, "lost", 0);
+ }
+
+ if ( Cmd(line, "MessageDelay") && !bResetObject )
+ {
+ m_displayText->SetDelay(OpFloat(line, "factor", 1.0f));
+ }
+
+ if ( Cmd(line, "Audio") && !bResetObject )
+ {
+ m_audioTrack = OpInt(line, "track", 0);
+ m_bAudioRepeat = OpInt(line, "repeat", 1);
+ }
+
+ if ( Cmd(line, "AmbiantColor") && !bResetObject )
+ {
+ m_engine->SetAmbiantColor(OpColor(line, "air", 0x88888888), 0);
+ m_engine->SetAmbiantColor(OpColor(line, "water", 0x88888888), 1);
+ }
+
+ if ( Cmd(line, "FogColor") && !bResetObject )
+ {
+ m_engine->SetFogColor(OpColor(line, "air", 0x88888888), 0);
+ m_engine->SetFogColor(OpColor(line, "water", 0x88888888), 1);
+ }
+
+ if ( Cmd(line, "VehicleColor") && !bResetObject )
+ {
+ m_colorNewBot = RetColor(OpColor(line, "color", 0x88888888));
+ }
+
+ if ( Cmd(line, "InsectColor") && !bResetObject )
+ {
+ m_colorNewAlien = RetColor(OpColor(line, "color", 0x88888888));
+ }
+
+ if ( Cmd(line, "GreeneryColor") && !bResetObject )
+ {
+ m_colorNewGreen = RetColor(OpColor(line, "color", 0x88888888));
+ }
+
+ if ( Cmd(line, "DeepView") && !bResetObject )
+ {
+ m_engine->SetDeepView(OpFloat(line, "air", 500.0f)*UNIT, 0, TRUE);
+ m_engine->SetDeepView(OpFloat(line, "water", 100.0f)*UNIT, 1, TRUE);
+ }
+
+ if ( Cmd(line, "FogStart") && !bResetObject )
+ {
+ m_engine->SetFogStart(OpFloat(line, "air", 0.5f), 0);
+ m_engine->SetFogStart(OpFloat(line, "water", 0.5f), 1);
+ }
+
+ if ( Cmd(line, "SecondTexture") && !bResetObject )
+ {
+ m_engine->SetSecondTexture(OpInt(line, "rank", 1));
+ }
+
+ if ( Cmd(line, "Background") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "");
+ m_engine->SetBackground(dir,
+ OpColor(line, "up", 0x00000000),
+ OpColor(line, "down", 0x00000000),
+ OpColor(line, "cloudUp", 0x00000000),
+ OpColor(line, "cloudDown", 0x00000000),
+ OpInt(line, "full", 0));
+ }
+
+ if ( Cmd(line, "Planet") && !bResetObject )
+ {
+ D3DVECTOR ppos, uv1, uv2;
+
+ ppos = OpPos(line, "pos");
+ uv1 = OpPos(line, "uv1");
+ uv2 = OpPos(line, "uv2");
+ OpString(line, "image", name);
+ UserDir(dir, name, "");
+ m_planet->Create(OpInt(line, "mode", 0),
+ FPOINT(ppos.x, ppos.z),
+ OpFloat(line, "dim", 0.2f),
+ OpFloat(line, "speed", 0.0f),
+ OpFloat(line, "dir", 0.0f),
+ dir,
+ FPOINT(uv1.x, uv1.z),
+ FPOINT(uv2.x, uv2.z));
+ }
+
+ if ( Cmd(line, "FrontsizeName") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "");
+ m_engine->SetFrontsizeName(dir);
+ }
+
+ if ( Cmd(line, "Global") && !bResetObject )
+ {
+ g_unit = OpFloat(line, "unitScale", 4.0f);
+ m_engine->SetTracePrecision(OpFloat(line, "traceQuality", 1.0f));
+ m_bShortCut = OpInt(line, "shortcut", 1);
+ }
+
+ if ( Cmd(line, "TerrainGenerate") && !bResetObject )
+ {
+ m_terrain->Generate(OpInt(line, "mosaic", 20),
+ OpInt(line, "brick", 3),
+ OpFloat(line, "size", 20.0f),
+ OpFloat(line, "vision", 500.0f)*UNIT,
+ OpInt(line, "depth", 2),
+ OpFloat(line, "hard", 0.5f));
+ }
+
+ if ( Cmd(line, "TerrainWind") && !bResetObject )
+ {
+ m_terrain->SetWind(OpPos(line, "speed"));
+ }
+
+ if ( Cmd(line, "TerrainRelief") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "textures");
+ m_terrain->ReliefFromBMP(dir, OpFloat(line, "factor", 1.0f), OpInt(line, "border", 1));
+ }
+
+ if ( Cmd(line, "TerrainReliefDXF") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "textures");
+ m_terrain->ReliefFromDXF(dir, OpFloat(line, "factor", 1.0f));
+ }
+
+ if ( Cmd(line, "TerrainResource") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "textures");
+ m_terrain->ResFromBMP(dir);
+ }
+
+ if ( Cmd(line, "TerrainWater") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "");
+ pos.x = OpFloat(line, "moveX", 0.0f);
+ pos.y = OpFloat(line, "moveY", 0.0f);
+ pos.z = pos.x;
+ m_water->Create(OpTypeWater(line, "air", WATER_TT),
+ OpTypeWater(line, "water", WATER_TT),
+ dir,
+ RetColor(OpColor(line, "diffuse", 0xffffffff)),
+ RetColor(OpColor(line, "ambiant", 0xffffffff)),
+ OpFloat(line, "level", 100.0f)*UNIT,
+ OpFloat(line, "glint", 1.0f),
+ pos);
+ m_colorNewWater = RetColor(OpColor(line, "color", RetColor(m_colorRefWater)));
+ m_colorShiftWater = OpFloat(line, "brightness", 0.0f);
+ }
+
+ if ( Cmd(line, "TerrainLava") && !bResetObject )
+ {
+ m_water->SetLava(OpInt(line, "mode", 0));
+ }
+
+ if ( Cmd(line, "TerrainCloud") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ UserDir(dir, name, "");
+ m_cloud->Create(dir,
+ RetColor(OpColor(line, "diffuse", 0xffffffff)),
+ RetColor(OpColor(line, "ambiant", 0xffffffff)),
+ OpFloat(line, "level", 500.0f)*UNIT);
+ }
+
+ if ( Cmd(line, "TerrainBlitz") && !bResetObject )
+ {
+ m_blitz->Create(OpFloat(line, "sleep", 0.0f),
+ OpFloat(line, "delay", 3.0f),
+ OpFloat(line, "magnetic", 50.0f)*UNIT);
+ }
+
+ if ( Cmd(line, "TerrainInitTextures") && !bResetObject )
+ {
+ int dx, dy, tt[100];
+ char* op;
+
+ OpString(line, "image", name);
+ AddExt(name, ".tga");
+ dx = OpInt(line, "dx", 1);
+ dy = OpInt(line, "dy", 1);
+ op = SearchOp(line, "table");
+ for ( i=0 ; i<dx*dy ; i++ )
+ {
+ tt[i] = GetInt(op, i, 0);
+ }
+
+ if ( strstr(name, "%user%") != 0 )
+ {
+ CopyFileListToTemp(name, tt, dx*dy);
+ }
+
+ m_terrain->InitTextures(name, tt, dx, dy);
+ }
+
+ if ( Cmd(line, "TerrainInit") && !bResetObject )
+ {
+ m_terrain->LevelInit(OpInt(line, "id", 1));
+ }
+
+ if ( Cmd(line, "TerrainMaterial") && !bResetObject )
+ {
+ OpString(line, "image", name);
+ AddExt(name, ".tga");
+ if ( strstr(name, "%user%") != 0 )
+ {
+ CopyFileToTemp(name);
+ }
+
+ m_terrain->LevelMaterial(OpInt(line, "id", 0),
+ name,
+ OpFloat(line, "u", 0.0f),
+ OpFloat(line, "v", 0.0f),
+ OpInt(line, "up", 1),
+ OpInt(line, "right", 1),
+ OpInt(line, "down", 1),
+ OpInt(line, "left", 1),
+ OpFloat(line, "hard", 0.5f));
+ }
+
+ if ( Cmd(line, "TerrainLevel") && !bResetObject )
+ {
+ int id[50];
+ char* op;
+
+ op = SearchOp(line, "id");
+ i = 0;
+ while ( TRUE )
+ {
+ id[i] = GetInt(op, i, 0);
+ if ( id[i++] == 0 ) break;
+ }
+
+ m_terrain->LevelGenerate(id,
+ OpFloat(line, "min", 0.0f)*UNIT,
+ OpFloat(line, "max", 100.0f)*UNIT,
+ OpFloat(line, "slope", 5.0f),
+ OpFloat(line, "freq", 100.0f),
+ OpPos(line, "center")*g_unit,
+ OpFloat(line, "radius", 0.0f)*g_unit);
+ }
+
+ if ( Cmd(line, "TerrainCreate") && !bResetObject )
+ {
+ m_terrain->CreateObjects(TRUE);
+ }
+
+ if ( Cmd(line, "BeginObject") )
+ {
+ InitEye();
+ SetMovieLock(FALSE);
+ if ( !m_bFixScene )
+ {
+//? CreateObject(D3DVECTOR(0.0f, 0.0f, 0.0f), 0.0f, 0.0f, OBJECT_TOTO);
+ }
+
+ if ( read[0] != 0 ) // loading file ?
+ {
+ pSel = IOReadScene(read, stack);
+ }
+ }
+
+ if ( Cmd(line, "CreateObject") && read[0] == 0 )
+ {
+ CObject* pObj;
+ CBrain* pBrain;
+ CAuto* pAuto;
+ CPyro* pyro;
+ ObjectType type;
+ PyroType pType;
+ CameraType cType;
+ Info info;
+ float dir;
+ char op[20];
+ char text[100];
+ char* p;
+ int run, gadget;
+
+ type = OpTypeObject(line, "type", OBJECT_NULL);
+
+ gadget = OpInt(line, "gadget", -1);
+ if ( gadget == -1 )
+ {
+ gadget = 0;
+ if ( type == OBJECT_TECH ||
+ (type >= OBJECT_PLANT0 &&
+ type <= OBJECT_PLANT19 ) ||
+ (type >= OBJECT_TREE0 &&
+ type <= OBJECT_TREE9 ) ||
+ (type >= OBJECT_TEEN0 &&
+ type <= OBJECT_TEEN49 ) ||
+ (type >= OBJECT_QUARTZ0 &&
+ type <= OBJECT_QUARTZ9 ) ||
+ (type >= OBJECT_ROOT0 &&
+ type <= OBJECT_ROOT4 ) ) // pas ROOT5 !
+ {
+ if ( type != OBJECT_TEEN11 && // lampe ?
+ type != OBJECT_TEEN12 && // coke ?
+ type != OBJECT_TEEN20 && // mur ?
+ type != OBJECT_TEEN21 && // mur ?
+ type != OBJECT_TEEN22 && // mur ?
+ type != OBJECT_TEEN26 && // lampe ?
+ type != OBJECT_TEEN28 && // bouteille ?
+ type != OBJECT_TEEN34 ) // pierre ?
+ {
+ gadget = 1;
+ }
+ }
+ }
+ if ( gadget != 0 ) // est-ce un gadget ?
+ {
+ if ( !TestGadgetQuantity(rankGadget++) ) continue;
+ }
+
+ pos = OpPos(line, "pos")*g_unit;
+ dir = OpFloat(line, "dir", 0.0f)*PI;
+ pObj = CreateObject(pos, dir,
+ OpFloat(line, "z", 1.0f),
+ OpFloat(line, "h", 0.0f),
+ type,
+ OpFloat(line, "power", 1.0f),
+ OpInt(line, "trainer", 0),
+ OpInt(line, "toy", 0),
+ OpInt(line, "option", 0));
+
+ if ( pObj != 0 )
+ {
+ pObj->SetDefRank(rankObj);
+
+ if ( type == OBJECT_BASE ) m_bBase = TRUE;
+
+ cType = OpCamera(line, "camera");
+ if ( cType != CAMERA_NULL )
+ {
+ pObj->SetCameraType(cType);
+ }
+ pObj->SetCameraDist(OpFloat(line, "cameraDist", 50.0f));
+ pObj->SetCameraLock(OpInt(line, "cameraLock", 0));
+
+ pType = OpPyro(line, "pyro");
+ if ( pType != PT_NULL )
+ {
+ pyro = new CPyro(m_iMan);
+ pyro->Create(pType, pObj);
+ }
+
+ // Met les infos dans borne (OBJECT_INFO).
+ for ( i=0 ; i<OBJECTMAXINFO ; i++ )
+ {
+ sprintf(op, "info%d", i+1);
+ OpString(line, op, text);
+ if ( text[0] == 0 ) break;
+ p = strchr(text, '=');
+ if ( p == 0 ) break;
+ *p = 0;
+ strcpy(info.name, text);
+ sscanf(p+1, "%f", &info.value);
+ pObj->SetInfo(i, info);
+ }
+
+ // Met les paramètres de la ligne de commande.
+ p = SearchOp(line, "cmdline");
+ for ( i=0 ; i<OBJECTMAXCMDLINE ; i++ )
+ {
+ float value;
+ value = GetFloat(p, i, NAN);
+ if ( value == NAN ) break;
+ pObj->SetCmdLine(i, value);
+ }
+
+ if ( OpInt(line, "select", 0) == 1 )
+ {
+ pSel = pObj;
+ }
+
+ pObj->SetSelectable(OpInt(line, "selectable", 1));
+ pObj->SetEnable(OpInt(line, "enable", 1));
+ pObj->SetProxyActivate(OpInt(line, "proxyActivate", 0));
+ pObj->SetProxyDistance(OpFloat(line, "proxyDistance", 15.0f)*g_unit);
+ pObj->SetRange(OpFloat(line, "range", 30.0f));
+ pObj->SetShield(OpFloat(line, "shield", 1.0f));
+ pObj->SetMagnifyDamage(OpFloat(line, "magnifyDamage", 1.0f));
+ pObj->SetClip(OpInt(line, "clip", 1));
+ pObj->SetCheckToken(OpInt(line, "checkToken", 1));
+ pObj->SetManual(OpInt(line, "manual", 0));
+
+ motion = pObj->RetMotion();
+ if ( motion != 0 )
+ {
+ p = SearchOp(line, "param");
+ for ( i=0 ; i<10 ; i++ )
+ {
+ float value;
+ value = GetFloat(p, i, NAN);
+ if ( value == NAN ) break;
+ motion->SetParam(i, value);
+ }
+ }
+
+ run = -1;
+ pBrain = pObj->RetBrain();
+ if ( pBrain != 0 )
+ {
+ for ( i=0 ; i<10 ; i++ )
+ {
+ sprintf(op, "script%d", i+1); // script1..script10
+ OpString(line, op, name);
+#if _SCHOOL
+ if ( !m_dialog->RetSoluce4() && i == 3 ) continue;
+#endif
+ if ( name[0] != 0 )
+ {
+ pBrain->SetScriptName(i, name);
+ }
+ }
+
+ i = OpInt(line, "run", 0);
+ if ( i != 0 )
+ {
+ run = i-1;
+ pBrain->SetScriptRun(run);
+ }
+ }
+ pAuto = pObj->RetAuto();
+ if ( pAuto != 0 )
+ {
+ type = OpTypeObject(line, "autoType", OBJECT_NULL);
+ pAuto->SetType(type);
+ for ( i=0 ; i<5 ; i++ )
+ {
+ sprintf(op, "autoValue%d", i+1); // autoValue1..autoValue5
+ pAuto->SetValue(i, OpFloat(line, op, 0.0f));
+ }
+ OpString(line, "autoString", name);
+ pAuto->SetString(name);
+
+ i = OpInt(line, "run", -1);
+ if ( i != -1 )
+ {
+ if ( i != PARAM_FIXSCENE &&
+ !m_dialog->RetMovies() ) i = 0;
+ pAuto->Start(i); // démarre le film
+ }
+ }
+
+ OpString(line, "soluce", name);
+ if ( bSoluce && pBrain != 0 && name[0] != 0 )
+ {
+ pBrain->SetSoluceName(name);
+ }
+
+ pObj->SetResetPosition(pObj->RetPosition(0));
+ pObj->SetResetAngle(pObj->RetAngle(0));
+ pObj->SetResetRun(run);
+
+ if ( OpInt(line, "reset", 0) == 1 )
+ {
+ pObj->SetResetCap(RESET_MOVE);
+ }
+ }
+
+ rankObj ++;
+ }
+
+ if ( Cmd(line, "CreateFog") && !bResetObject )
+ {
+ ParticuleType type;
+ FPOINT dim;
+ float height, ddim, delay;
+
+ type = (ParticuleType)(PARTIFOG0+OpInt(line, "type", 0));
+ pos = OpPos(line, "pos")*g_unit;
+ height = OpFloat(line, "height", 1.0f)*g_unit;
+ ddim = OpFloat(line, "dim", 50.0f)*g_unit;
+ delay = OpFloat(line, "delay", 2.0f);
+ m_terrain->MoveOnFloor(pos);
+ pos.y += height;
+ dim.x = ddim;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, D3DVECTOR(0.0f, 0.0f, 0.0f), dim, type, delay, 0.0f, 0.0f);
+ }
+
+ if ( Cmd(line, "CreateLight") && !bResetObject )
+ {
+ D3DTypeObj type;
+
+ color.r = 0.5f;
+ color.g = 0.5f;
+ color.b = 0.5f;
+ color.a = 1.0f;
+ obj = CreateLight(OpDir(line, "dir"),
+ OpColorValue(line, "color", color));
+
+ type = OpTypeTerrain(line, "type", TYPENULL);
+ if ( type == TYPETERRAIN )
+ {
+ m_light->SetLightIncluType(obj, TYPETERRAIN);
+ }
+ if ( type == TYPEQUARTZ )
+ {
+ m_light->SetLightIncluType(obj, TYPEQUARTZ);
+ }
+ if ( type == TYPEMETAL )
+ {
+ m_light->SetLightIncluType(obj, TYPEMETAL);
+ }
+ if ( type == TYPEFIX )
+ {
+ m_light->SetLightExcluType(obj, TYPETERRAIN);
+ }
+ }
+ if ( Cmd(line, "CreateSpot") && !bResetObject )
+ {
+ D3DTypeObj type;
+
+ color.r = 0.5f;
+ color.g = 0.5f;
+ color.b = 0.5f;
+ color.a = 1.0f;
+ obj = CreateSpot(OpDir(line, "pos")*g_unit,
+ OpColorValue(line, "color", color));
+
+ type = OpTypeTerrain(line, "type", TYPENULL);
+ if ( type == TYPETERRAIN )
+ {
+ m_light->SetLightIncluType(obj, TYPETERRAIN);
+ }
+ if ( type == TYPEQUARTZ )
+ {
+ m_light->SetLightIncluType(obj, TYPEQUARTZ);
+ }
+ if ( type == TYPEMETAL )
+ {
+ m_light->SetLightIncluType(obj, TYPEMETAL);
+ }
+ if ( type == TYPEFIX )
+ {
+ m_light->SetLightExcluType(obj, TYPETERRAIN);
+ }
+ }
+
+ if ( Cmd(line, "GroundSpot") && !bResetObject )
+ {
+ rank = m_engine->GroundSpotCreate();
+ if ( rank != -1 )
+ {
+ m_engine->SetObjectGroundSpotPos(rank, OpPos(line, "pos")*g_unit);
+ m_engine->SetObjectGroundSpotRadius(rank, OpFloat(line, "radius", 10.0f)*g_unit);
+ m_engine->SetObjectGroundSpotColor(rank, RetColor(OpColor(line, "color", 0x88888888)));
+ m_engine->SetObjectGroundSpotSmooth(rank, OpFloat(line, "smooth", 1.0f));
+ m_engine->SetObjectGroundSpotMinMax(rank, OpFloat(line, "min", 0.0f)*g_unit,
+ OpFloat(line, "max", 0.0f)*g_unit);
+ }
+ }
+
+ if ( Cmd(line, "WaterColor") && !bResetObject )
+ {
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ color.a = 1.0f;
+ m_engine->SetWaterAddColor(OpColorValue(line, "color", color));
+ }
+
+ if ( Cmd(line, "MapColor") && !bResetObject )
+ {
+ m_map->FloorColorMap(RetColor(OpColor(line, "floor", 0x88888888)),
+ RetColor(OpColor(line, "water", 0x88888888)));
+ m_bMapShow = OpInt(line, "show", 1);
+ m_map->ShowMap(m_bMapShow);
+ m_map->SetToy(OpInt(line, "toyIcon", 0));
+ m_bMapImage = OpInt(line, "image", 0);
+ if ( m_bMapImage )
+ {
+ D3DVECTOR offset;
+ OpString(line, "filename", m_mapFilename);
+ offset = OpPos(line, "offset");
+ m_map->SetFixParam(OpFloat(line, "zoom", 1.0f),
+ offset.x, offset.z,
+ OpFloat(line, "angle", 0.0f)*PI/180.0f,
+ OpInt(line, "mode", 0),
+ OpInt(line, "debug", 0));
+ }
+ }
+ if ( Cmd(line, "MapZoom") && !bResetObject )
+ {
+ m_map->ZoomMap(OpFloat(line, "factor", 2.0f));
+ m_map->MapEnable(OpInt(line, "enable", 1));
+ }
+
+ if ( Cmd(line, "MaxFlyingHeight") && !bResetObject )
+ {
+ m_terrain->SetFlyingMaxHeight(OpFloat(line, "max", 280.0f)*g_unit);
+ }
+ if ( Cmd(line, "AddFlyingHeight") && !bResetObject )
+ {
+ m_terrain->AddFlyingLimit(OpPos(line, "center")*g_unit,
+ OpFloat(line, "extRadius", 20.0f)*g_unit,
+ OpFloat(line, "intRadius", 10.0f)*g_unit,
+ OpFloat(line, "maxHeight", 200.0f));
+ }
+
+ if ( Cmd(line, "Camera") )
+ {
+ m_camera->Init(OpDir(line, "eye")*g_unit,
+ OpDir(line, "lookat")*g_unit,
+ bResetObject?0.0f:OpFloat(line, "delay", 0.0f));
+
+ if ( OpInt(line, "fadeIn", 0) == 1 )
+ {
+ m_camera->StartOver(OE_FADEINw, D3DVECTOR(0.0f, 0.0f, 0.0f), 1.0f);
+ }
+ m_camera->SetFixDirection(OpFloat(line, "fixDirection", 0.25f)*PI);
+ }
+
+ if ( Cmd(line, "EndMissionTake") && !bResetObject )
+ {
+ i = m_endTakeTotal;
+ if ( i < 10 )
+ {
+ m_endTake[i].pos = OpPos(line, "pos")*g_unit;
+ m_endTake[i].dist = OpFloat(line, "dist", 8.0f)*g_unit;
+ m_endTake[i].type = OpTypeObject(line, "type", OBJECT_NULL);
+ m_endTake[i].min = OpInt(line, "min", 1);
+ m_endTake[i].max = OpInt(line, "max", 9999);
+ m_endTake[i].lost = OpInt(line, "lost", -1);
+ m_endTake[i].bImmediat = OpInt(line, "immediat", 0);
+ OpString(line, "message", m_endTake[i].message);
+ m_endTakeTotal ++;
+ }
+ }
+ if ( Cmd(line, "EndMissionDelay") && !bResetObject )
+ {
+ m_endTakeWinDelay = OpFloat(line, "win", 2.0f);
+ m_endTakeLostDelay = OpFloat(line, "lost", 2.0f);
+ }
+ if ( Cmd(line, "EndMissionResearch") && !bResetObject )
+ {
+ m_endTakeResearch |= OpResearch(line, "type");
+ }
+
+ if ( Cmd(line, "ObligatoryToken") && !bResetObject )
+ {
+ i = m_obligatoryTotal;
+ if ( i < 100 )
+ {
+ OpString(line, "text", m_obligatoryToken[i]);
+ m_obligatoryTotal ++;
+ }
+ }
+
+ if ( Cmd(line, "ProhibitedToken") && !bResetObject )
+ {
+ i = m_prohibitedTotal;
+ if ( i < 100 )
+ {
+ OpString(line, "text", m_prohibitedToken[i]);
+ m_prohibitedTotal ++;
+ }
+ }
+
+ if ( Cmd(line, "EnableBuild") && !bResetObject )
+ {
+ g_build |= OpBuild(line, "type");
+ }
+
+ if ( Cmd(line, "EnableResearch") && !bResetObject )
+ {
+ g_researchEnable |= OpResearch(line, "type");
+ }
+ if ( Cmd(line, "DoneResearch") && read[0] == 0 && !bResetObject ) // pas loading file ?
+ {
+ g_researchDone |= OpResearch(line, "type");
+ }
+
+ if ( Cmd(line, "NewScript") && !bResetObject )
+ {
+ OpString(line, "name", name);
+ AddNewScriptName(OpTypeObject(line, "type", OBJECT_NULL), name);
+ }
+ }
+
+ fclose(file);
+
+ if ( read[0] == 0 )
+ {
+ CompileScript(bSoluce); // compile tous les scripts
+ }
+
+ if ( strcmp(base, "scene") == 0 && !bResetObject ) // mission ?
+ {
+ WriteFreeParam();
+ }
+ if ( strcmp(base, "free") == 0 && !bResetObject ) // jeu libre ?
+ {
+ g_researchDone = m_freeResearch;
+
+ g_build = m_freeBuild;
+ g_build &= ~BUILD_RESEARCH;
+ g_build &= ~BUILD_LABO;
+ g_build |= BUILD_FACTORY;
+ g_build |= BUILD_GFLAT;
+ g_build |= BUILD_FLAG;
+ }
+
+ if ( !bResetObject )
+ {
+ ChangeColor(); // change les couleurs des textures
+ m_short->SetMode(FALSE); // véhicules
+ }
+
+ CreateShortcuts();
+ m_map->UpdateMap();
+ m_engine->TimeInit();
+ m_engine->FlushPressKey();
+ m_time = 0.0f;
+ m_gameTime = 0.0f;
+ m_checkEndTime = 0.0f;
+ m_infoUsed = 0;
+
+ m_selectObject = pSel;
+
+ if ( !m_bBase && // pas de base principale ?
+ !m_bFixScene ) // scène interractive ?
+ {
+ if ( pSel == 0 )
+ {
+ pObj = SearchHuman();
+ }
+ else
+ {
+ pObj = pSel;
+ }
+ if ( pObj != 0 )
+ {
+ SelectObject(pObj);
+ m_camera->SetObject(pObj);
+//? m_camera->SetType(CAMERA_BACK);
+ m_camera->SetType(pObj->RetCameraType());
+ }
+ }
+ if ( m_bFixScene )
+ {
+ m_camera->SetType(CAMERA_SCRIPT);
+ }
+
+ if ( read[0] != 0 && pSel != 0 ) // loading file ?
+ {
+ pos = pSel->RetPosition(0);
+ m_camera->Init(pos, pos, 0.0f);
+ m_camera->FixCamera();
+
+ SelectObject(pSel);
+ m_camera->SetObject(pSel);
+
+ m_bBeginSatCom = TRUE; // message déjà affiché
+ }
+ m_dialog->SetSceneRead("");
+ m_dialog->SetStackRead("");
+}
+
+// Crée un objet du décor mobile ou fixe.
+
+CObject* CRobotMain::CreateObject(D3DVECTOR pos, float angle, float zoom, float height,
+ ObjectType type, float power,
+ BOOL bTrainer, BOOL bToy,
+ int option)
+{
+ CObject* pObject = 0;
+ CAuto* automat;
+
+ if ( type == OBJECT_NULL ) return 0;
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ bTrainer = FALSE; // forcément
+ }
+
+ if ( type == OBJECT_PORTICO ||
+ type == OBJECT_BASE ||
+ type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER||
+ type == OBJECT_TOWER ||
+ type == OBJECT_NEST ||
+ 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_TARGET1 ||
+ type == OBJECT_TARGET2 ||
+ type == OBJECT_START ||
+ type == OBJECT_END )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateBuilding(pos, angle, height, type, power);
+
+ automat = pObject->RetAuto();
+ if ( automat != 0 )
+ {
+ automat->Init();
+ }
+ }
+ else
+ if ( 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_TNT ||
+ type == OBJECT_SCRAP1 ||
+ type == OBJECT_SCRAP2 ||
+ type == OBJECT_SCRAP3 ||
+ type == OBJECT_SCRAP4 ||
+ type == OBJECT_SCRAP5 ||
+ type == OBJECT_BOMB ||
+ type == OBJECT_WAYPOINT ||
+ type == OBJECT_SHOW ||
+ type == OBJECT_WINFIRE ||
+ type == OBJECT_BAG ||
+ type == OBJECT_MARKPOWER ||
+ type == OBJECT_MARKSTONE ||
+ type == OBJECT_MARKURANIUM ||
+ type == OBJECT_MARKKEYa ||
+ type == OBJECT_MARKKEYb ||
+ type == OBJECT_MARKKEYc ||
+ type == OBJECT_MARKKEYd ||
+ type == OBJECT_EGG )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateResource(pos, angle, type, power);
+ }
+ else
+ if ( type == OBJECT_FLAGb ||
+ type == OBJECT_FLAGr ||
+ type == OBJECT_FLAGg ||
+ type == OBJECT_FLAGy ||
+ type == OBJECT_FLAGv )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateFlag(pos, angle, type);
+ }
+ else
+ if ( type == OBJECT_BARRIER0 ||
+ type == OBJECT_BARRIER1 ||
+ type == OBJECT_BARRIER2 ||
+ type == OBJECT_BARRIER3 ||
+ type == OBJECT_BARRIER4 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateBarrier(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_PLANT0 ||
+ type == OBJECT_PLANT1 ||
+ type == OBJECT_PLANT2 ||
+ type == OBJECT_PLANT3 ||
+ type == OBJECT_PLANT4 ||
+ type == OBJECT_PLANT5 ||
+ type == OBJECT_PLANT6 ||
+ type == OBJECT_PLANT7 ||
+ type == OBJECT_PLANT8 ||
+ type == OBJECT_PLANT9 ||
+ type == OBJECT_PLANT10 ||
+ type == OBJECT_PLANT11 ||
+ type == OBJECT_PLANT12 ||
+ type == OBJECT_PLANT13 ||
+ type == OBJECT_PLANT14 ||
+ type == OBJECT_PLANT15 ||
+ type == OBJECT_PLANT16 ||
+ type == OBJECT_PLANT17 ||
+ type == OBJECT_PLANT18 ||
+ type == OBJECT_PLANT19 ||
+ type == OBJECT_TREE0 ||
+ type == OBJECT_TREE1 ||
+ type == OBJECT_TREE2 ||
+ type == OBJECT_TREE3 ||
+ type == OBJECT_TREE4 ||
+ type == OBJECT_TREE5 ||
+ type == OBJECT_TREE6 ||
+ type == OBJECT_TREE7 ||
+ type == OBJECT_TREE8 ||
+ type == OBJECT_TREE9 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreatePlant(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_MUSHROOM0 ||
+ type == OBJECT_MUSHROOM1 ||
+ type == OBJECT_MUSHROOM2 ||
+ type == OBJECT_MUSHROOM3 ||
+ type == OBJECT_MUSHROOM4 ||
+ type == OBJECT_MUSHROOM5 ||
+ type == OBJECT_MUSHROOM6 ||
+ type == OBJECT_MUSHROOM7 ||
+ type == OBJECT_MUSHROOM8 ||
+ type == OBJECT_MUSHROOM9 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateMushroom(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_TEEN0 ||
+ type == OBJECT_TEEN1 ||
+ type == OBJECT_TEEN2 ||
+ type == OBJECT_TEEN3 ||
+ type == OBJECT_TEEN4 ||
+ type == OBJECT_TEEN5 ||
+ type == OBJECT_TEEN6 ||
+ type == OBJECT_TEEN7 ||
+ type == OBJECT_TEEN8 ||
+ type == OBJECT_TEEN9 ||
+ type == OBJECT_TEEN10 ||
+ type == OBJECT_TEEN11 ||
+ type == OBJECT_TEEN12 ||
+ type == OBJECT_TEEN13 ||
+ type == OBJECT_TEEN14 ||
+ type == OBJECT_TEEN15 ||
+ type == OBJECT_TEEN16 ||
+ type == OBJECT_TEEN17 ||
+ type == OBJECT_TEEN18 ||
+ type == OBJECT_TEEN19 ||
+ type == OBJECT_TEEN20 ||
+ type == OBJECT_TEEN21 ||
+ type == OBJECT_TEEN22 ||
+ type == OBJECT_TEEN23 ||
+ type == OBJECT_TEEN24 ||
+ type == OBJECT_TEEN25 ||
+ type == OBJECT_TEEN26 ||
+ type == OBJECT_TEEN27 ||
+ type == OBJECT_TEEN28 ||
+ type == OBJECT_TEEN29 ||
+ type == OBJECT_TEEN30 ||
+ type == OBJECT_TEEN31 ||
+ type == OBJECT_TEEN32 ||
+ type == OBJECT_TEEN33 ||
+ type == OBJECT_TEEN34 ||
+ type == OBJECT_TEEN35 ||
+ type == OBJECT_TEEN36 ||
+ type == OBJECT_TEEN37 ||
+ type == OBJECT_TEEN38 ||
+ type == OBJECT_TEEN39 ||
+ type == OBJECT_TEEN40 ||
+ type == OBJECT_TEEN41 ||
+ type == OBJECT_TEEN42 ||
+ type == OBJECT_TEEN43 ||
+ type == OBJECT_TEEN44 ||
+ type == OBJECT_TEEN45 ||
+ type == OBJECT_TEEN46 ||
+ type == OBJECT_TEEN47 ||
+ type == OBJECT_TEEN48 ||
+ type == OBJECT_TEEN49 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->SetOption(option);
+ pObject->CreateTeen(pos, angle, zoom, height, type);
+ }
+ else
+ if ( type == OBJECT_QUARTZ0 ||
+ type == OBJECT_QUARTZ1 ||
+ type == OBJECT_QUARTZ2 ||
+ type == OBJECT_QUARTZ3 ||
+ type == OBJECT_QUARTZ4 ||
+ type == OBJECT_QUARTZ5 ||
+ type == OBJECT_QUARTZ6 ||
+ type == OBJECT_QUARTZ7 ||
+ type == OBJECT_QUARTZ8 ||
+ type == OBJECT_QUARTZ9 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateQuartz(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_ROOT0 ||
+ type == OBJECT_ROOT1 ||
+ type == OBJECT_ROOT2 ||
+ type == OBJECT_ROOT3 ||
+ type == OBJECT_ROOT4 ||
+ type == OBJECT_ROOT5 ||
+ type == OBJECT_ROOT6 ||
+ type == OBJECT_ROOT7 ||
+ type == OBJECT_ROOT8 ||
+ type == OBJECT_ROOT9 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateRoot(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_HOME1 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateHome(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_RUINmobilew1 ||
+ type == OBJECT_RUINmobilew2 ||
+ type == OBJECT_RUINmobilet1 ||
+ type == OBJECT_RUINmobilet2 ||
+ type == OBJECT_RUINmobiler1 ||
+ type == OBJECT_RUINmobiler2 ||
+ type == OBJECT_RUINfactory ||
+ type == OBJECT_RUINdoor ||
+ type == OBJECT_RUINsupport ||
+ type == OBJECT_RUINradar ||
+ type == OBJECT_RUINconvert ||
+ type == OBJECT_RUINbase ||
+ type == OBJECT_RUINhead )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateRuin(pos, angle, height, type);
+ }
+ else
+ if ( type == OBJECT_APOLLO1 ||
+ type == OBJECT_APOLLO3 ||
+ type == OBJECT_APOLLO4 ||
+ type == OBJECT_APOLLO5 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateApollo(pos, angle, type);
+ }
+ else
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->CreateInsect(pos, angle, type); // sans oeuf
+ }
+ else
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_TOTO ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr ||
+ type == OBJECT_APOLLO2 )
+ {
+ pObject = new CObject(m_iMan);
+ pObject->SetOption(option);
+ pObject->CreateVehicle(pos, angle, type, power, bTrainer, bToy);
+ }
+
+ if ( m_bFixScene && type == OBJECT_HUMAN )
+ {
+ CMotion* motion;
+
+ motion = pObject->RetMotion();
+ if ( m_phase == PHASE_WIN ) motion->SetAction(MHS_WIN, 0.4f);
+ if ( m_phase == PHASE_LOST ) motion->SetAction(MHS_LOST, 0.5f);
+ }
+
+ return pObject;
+}
+
+
+// Crée le modèle éditable.
+
+void CRobotMain::CreateModel()
+{
+ D3DVECTOR direction;
+ D3DCOLORVALUE color;
+
+ m_engine->SetAmbiantColor(0xC0C0C0C0); // gris
+ m_engine->SetBackground("", 0x80808080, 0x80808080, 0x80808080, 0x80808080);
+ m_engine->SetFogColor(0x80808080);
+ m_engine->SetDeepView(500.0f, 0);
+ m_engine->SetDeepView(100.0f, 1);
+ m_engine->SetFogStart(0.5f);
+
+ m_model->StartUserAction();
+
+ direction = D3DVECTOR(1.0f, -1.0f, 1.0f);
+ color.r = 0.7f;
+ color.g = 0.7f;
+ color.b = 0.7f; // blanc
+ CreateLight(direction, color);
+
+ direction = D3DVECTOR(-1.0f, -1.0f, 1.0f);
+ color.r = 0.7f;
+ color.g = 0.7f;
+ color.b = 0.7f; // blanc
+ CreateLight(direction, color);
+
+ direction = D3DVECTOR(1.0f, -1.0f, -1.0f);
+ color.r = 0.7f;
+ color.g = 0.7f;
+ color.b = 0.7f; // blanc
+ CreateLight(direction, color);
+
+ direction = D3DVECTOR(-1.0f, -1.0f, -1.0f);
+ color.r = 0.7f;
+ color.g = 0.7f;
+ color.b = 0.7f; // blanc
+ CreateLight(direction, color);
+
+ direction = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ color.r = 0.7f;
+ color.g = 0.7f;
+ color.b = 0.7f; // blanc
+ CreateLight(direction, color);
+
+ InitEye();
+
+ m_engine->TimeInit();
+ m_time = 0.0f;
+ m_gameTime = 0.0f;
+ m_checkEndTime = 0.0f;
+}
+
+
+// Crée une lumière directionnelle.
+
+int CRobotMain::CreateLight(D3DVECTOR direction, D3DCOLORVALUE color)
+{
+ D3DLIGHT7 light;
+ int obj;
+
+ if ( direction.x == 0.0f &&
+ direction.y == 0.0f &&
+ direction.z == 0.0f )
+ {
+ direction.y = -1.0f;
+ }
+
+ ZeroMemory(&light, sizeof(D3DLIGHT7));
+ light.dltType = D3DLIGHT_DIRECTIONAL;
+ light.dcvDiffuse.r = color.r;
+ light.dcvDiffuse.g = color.g;
+ light.dcvDiffuse.b = color.b;
+ light.dvDirection = direction;
+ obj = m_light->CreateLight();
+ m_light->SetLight(obj, light);
+
+ return obj;
+}
+
+// Crée une lumière spot.
+
+int CRobotMain::CreateSpot(D3DVECTOR pos, D3DCOLORVALUE color)
+{
+ D3DLIGHT7 light;
+ int obj;
+
+ if ( !m_engine->RetLightMode() ) return -1;
+
+ pos.y += m_terrain->RetFloorLevel(pos);
+
+ ZeroMemory(&light, sizeof(D3DLIGHT7));
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = color.r;
+ light.dcvDiffuse.g = color.g;
+ light.dcvDiffuse.b = color.b;
+ light.dvPosition = pos;
+ light.dvDirection = D3DVECTOR(0.0f, -1.0f, 0.0f);
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvTheta = 10.0f*PI/180.0f;
+ light.dvPhi = 90.0f*PI/180.0f;
+ light.dvAttenuation0 = 2.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ obj = m_light->CreateLight();
+ m_light->SetLight(obj, light);
+
+ return obj;
+}
+
+
+// Change les couleurs des textures.
+
+void CRobotMain::ChangeColor()
+{
+ D3DCOLORVALUE colorRef1, colorNew1, colorRef2, colorNew2;
+ FPOINT ts, ti;
+ FPOINT exclu[6];
+ char name[100];
+ int face;
+ float tolerance;
+
+ ts = FPOINT(0.0f, 0.0f);
+ ti = FPOINT(1.0f, 1.0f); // toute l'image
+
+ colorRef1.a = 0.0f;
+ colorRef2.a = 0.0f;
+
+ colorRef1.r = 206.0f/256.0f;
+ colorRef1.g = 206.0f/256.0f;
+ colorRef1.b = 204.0f/256.0f; // ~blanc
+ colorNew1 = m_dialog->RetGamerColorCombi();
+ colorRef2.r = 255.0f/256.0f;
+ colorRef2.g = 132.0f/256.0f;
+ colorRef2.b = 1.0f/256.0f; // orange
+ colorNew2 = m_dialog->RetGamerColorBand();
+ exclu[0] = FPOINT(192.0f/256.0f, 0.0f/256.0f);
+ exclu[1] = FPOINT(256.0f/256.0f, 64.0f/256.0f); // crystaux + bombonnes
+ exclu[2] = FPOINT(208.0f/256.0f, 224.0f/256.0f);
+ exclu[3] = FPOINT(256.0f/256.0f, 256.0f/256.0f); // écran SatCom
+ exclu[4] = FPOINT(0.0f, 0.0f);
+ exclu[5] = FPOINT(0.0f, 0.0f); // terminateur
+ m_engine->ChangeColor("human.tga", colorRef1, colorNew1, colorRef2, colorNew2, 0.30f, 0.01f, ts, ti, exclu);
+
+ face = RetGamerFace();
+ if ( face == 0 ) // normal ?
+ {
+ colorRef1.r = 90.0f/256.0f;
+ colorRef1.g = 95.0f/256.0f;
+ colorRef1.b = 85.0f/256.0f; // noir
+ tolerance = 0.15f;
+ }
+ if ( face == 1 ) // chauve ?
+ {
+ colorRef1.r = 74.0f/256.0f;
+ colorRef1.g = 58.0f/256.0f;
+ colorRef1.b = 46.0f/256.0f; // brun
+ tolerance = 0.20f;
+ }
+ if ( face == 2 ) // carlos ?
+ {
+ colorRef1.r = 70.0f/256.0f;
+ colorRef1.g = 40.0f/256.0f;
+ colorRef1.b = 8.0f/256.0f; // brun
+ tolerance = 0.30f;
+ }
+ if ( face == 3 ) // blond ?
+ {
+ colorRef1.r = 74.0f/256.0f;
+ colorRef1.g = 16.0f/256.0f;
+ colorRef1.b = 0.0f/256.0f; // jaune
+ tolerance = 0.20f;
+ }
+ colorNew1 = m_dialog->RetGamerColorHair();
+ colorRef2.r = 0.0f;
+ colorRef2.g = 0.0f;
+ colorRef2.b = 0.0f;
+ colorNew2.r = 0.0f;
+ colorNew2.g = 0.0f;
+ colorNew2.b = 0.0f;
+ sprintf(name, "face%.2d.tga", face+1);
+ exclu[0] = FPOINT(105.0f/256.0f, 47.0f/166.0f);
+ exclu[1] = FPOINT(153.0f/256.0f, 79.0f/166.0f); // bombonne bleu
+ exclu[2] = FPOINT(0.0f, 0.0f);
+ exclu[3] = FPOINT(0.0f, 0.0f); // terminateur
+ m_engine->ChangeColor(name, colorRef1, colorNew1, colorRef2, colorNew2, tolerance, 0.00f, ts, ti, exclu);
+
+ colorRef2.r = 0.0f;
+ colorRef2.g = 0.0f;
+ colorRef2.b = 0.0f;
+ colorNew2.r = 0.0f;
+ colorNew2.g = 0.0f;
+ colorNew2.b = 0.0f;
+
+ m_engine->ChangeColor("base1.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+ m_engine->ChangeColor("convert.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+ m_engine->ChangeColor("derrick.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+ m_engine->ChangeColor("factory.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+ m_engine->ChangeColor("lemt.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+ m_engine->ChangeColor("roller.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+ m_engine->ChangeColor("search.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, TRUE);
+
+ exclu[0] = FPOINT( 0.0f/256.0f, 160.0f/256.0f);
+ exclu[1] = FPOINT(256.0f/256.0f, 256.0f/256.0f); // crayons
+ exclu[2] = FPOINT(0.0f, 0.0f);
+ exclu[3] = FPOINT(0.0f, 0.0f); // terminateur
+ m_engine->ChangeColor("drawer.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, TRUE);
+
+ exclu[0] = FPOINT(237.0f/256.0f, 176.0f/256.0f);
+ exclu[1] = FPOINT(256.0f/256.0f, 220.0f/256.0f); // bombonne bleu
+ exclu[2] = FPOINT(106.0f/256.0f, 150.0f/256.0f);
+ exclu[3] = FPOINT(130.0f/256.0f, 214.0f/256.0f); // emplacement safe
+ exclu[4] = FPOINT(0.0f, 0.0f);
+ exclu[5] = FPOINT(0.0f, 0.0f); // terminateur
+ m_engine->ChangeColor("subm.tga", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, TRUE);
+
+ exclu[0] = FPOINT(128.0f/256.0f, 160.0f/256.0f);
+ exclu[1] = FPOINT(256.0f/256.0f, 256.0f/256.0f); // SatCom
+ exclu[2] = FPOINT(0.0f, 0.0f);
+ exclu[3] = FPOINT(0.0f, 0.0f); // terminateur
+ m_engine->ChangeColor("ant.tga", m_colorRefAlien, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti, exclu);
+ m_engine->ChangeColor("mother.tga", m_colorRefAlien, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti);
+
+ m_engine->ChangeColor("plant.tga", m_colorRefGreen, m_colorNewGreen, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti);
+
+ // PARTIPLOUF0 et PARTIDROP :
+ ts = FPOINT(0.500f, 0.500f);
+ ti = FPOINT(0.875f, 0.750f);
+ m_engine->ChangeColor("effect00.tga", m_colorRefWater, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, 0, m_colorShiftWater, TRUE);
+
+ // PARTIFLIC :
+ ts = FPOINT(0.00f, 0.75f);
+ ti = FPOINT(0.25f, 1.00f);
+ m_engine->ChangeColor("effect02.tga", m_colorRefWater, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, 0, m_colorShiftWater, TRUE);
+}
+
+// Met à jour le nombre d'objets non indispansables.
+
+BOOL CRobotMain::TestGadgetQuantity(int rank)
+{
+ float percent;
+ int *table;
+
+ static int table10[10] = {0,1,0,0,0,0,0,0,0,0};
+ static int table20[10] = {0,1,0,0,0,1,0,0,0,0};
+ static int table30[10] = {0,1,0,1,0,1,0,0,0,0};
+ static int table40[10] = {0,1,0,1,0,1,0,1,0,0};
+ static int table50[10] = {0,1,0,1,0,1,0,1,0,1};
+ static int table60[10] = {0,1,0,1,1,1,0,1,0,1};
+ static int table70[10] = {0,1,0,1,1,1,0,1,1,1};
+ static int table80[10] = {0,1,1,1,1,1,0,1,1,1};
+ static int table90[10] = {0,1,1,1,1,1,1,1,1,1};
+
+ percent = m_engine->RetGadgetQuantity();
+ if ( percent == 0.0f ) return FALSE;
+ if ( percent == 1.0f ) return TRUE;
+
+ if ( percent <= 0.15f ) table = table10;
+ else if ( percent <= 0.25f ) table = table20;
+ else if ( percent <= 0.35f ) table = table30;
+ else if ( percent <= 0.45f ) table = table40;
+ else if ( percent <= 0.55f ) table = table50;
+ else if ( percent <= 0.65f ) table = table60;
+ else if ( percent <= 0.75f ) table = table70;
+ else if ( percent <= 0.85f ) table = table80;
+ else table = table90;
+
+ return table[rank%10];
+}
+
+
+
+// Calcule la distance jusqu'à l'objet le plus proche.
+
+float CRobotMain::SearchNearestObject(D3DVECTOR center, CObject *exclu)
+{
+ CObject* pObj;
+ ObjectType type;
+ D3DVECTOR oPos;
+ float min, dist, oRadius;
+ int i, j;
+
+ min = 100000.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+ if ( pObj == exclu ) continue;
+
+ type = pObj->RetType();
+
+ if ( type == OBJECT_BASE )
+ {
+ oPos = pObj->RetPosition(0);
+ if ( oPos.x != center.x ||
+ oPos.z != center.z )
+ {
+ dist = Length(center, oPos)-80.0f;
+ if ( dist < 0.0f ) dist = 0.0f;
+ min = Min(min, dist);
+ continue;
+ }
+ }
+
+ if ( type == OBJECT_STATION ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER )
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length(center, oPos)-8.0f;
+ if ( dist < 0.0f ) dist = 0.0f;
+ min = Min(min, dist);
+ }
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius;
+ if ( dist < 0.0f ) dist = 0.0f;
+ min = Min(min, dist);
+ }
+ }
+ return min;
+}
+
+// Calcule un emplacement libre.
+
+BOOL CRobotMain::FreeSpace(D3DVECTOR &center, float minRadius, float maxRadius,
+ float space, CObject *exclu)
+{
+ D3DVECTOR pos;
+ FPOINT p;
+ float radius, ia, angle, dist, flat;
+
+ if ( minRadius < maxRadius ) // de l'intérieur vers l'extérieur ?
+ {
+ for ( radius=minRadius ; radius<=maxRadius ; radius+=space )
+ {
+ ia = space/radius;
+ for ( angle=0.0f ; angle<PI*2.0f ; angle+=ia )
+ {
+ p.x = center.x+radius;
+ p.y = center.z;
+ p = RotatePoint(FPOINT(center.x, center.z), angle, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ pos.y = 0.0f;
+ m_terrain->MoveOnFloor(pos, TRUE);
+ dist = SearchNearestObject(pos, exclu);
+ if ( dist >= space )
+ {
+ flat = m_terrain->RetFlatZoneRadius(pos, dist/2.0f);
+ if ( flat >= dist/2.0f )
+ {
+ center = pos;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ else // de l'extérieur vers l'intérieur ?
+ {
+ for ( radius=maxRadius ; radius>=minRadius ; radius-=space )
+ {
+ ia = space/radius;
+ for ( angle=0.0f ; angle<PI*2.0f ; angle+=ia )
+ {
+ p.x = center.x+radius;
+ p.y = center.z;
+ p = RotatePoint(FPOINT(center.x, center.z), angle, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ pos.y = 0.0f;
+ m_terrain->MoveOnFloor(pos, TRUE);
+ dist = SearchNearestObject(pos, exclu);
+ if ( dist >= space )
+ {
+ flat = m_terrain->RetFlatZoneRadius(pos, dist/2.0f);
+ if ( flat >= dist/2.0f )
+ {
+ center = pos;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+// Calcule le rayon maximal d'un emplacement libre.
+
+float CRobotMain::RetFlatZoneRadius(D3DVECTOR center, float maxRadius,
+ CObject *exclu)
+{
+ float dist;
+
+ dist = SearchNearestObject(center, exclu);
+ if ( dist == 0.0f ) return 0.0f;
+ if ( dist < maxRadius )
+ {
+ maxRadius = dist;
+ }
+ return m_terrain->RetFlatZoneRadius(center, maxRadius);
+}
+
+
+// Cache la zone constructible lorsqu'un cube de métal est repris.
+
+void CRobotMain::HideDropZone(CObject* metal)
+{
+ if ( m_showLimit[1].bUsed &&
+ m_showLimit[1].link == metal )
+ {
+ FlushShowLimit(1);
+ }
+
+ if ( m_showLimit[2].bUsed &&
+ m_showLimit[2].link == metal )
+ {
+ FlushShowLimit(2);
+ }
+}
+
+// Montre la zone constructible lorsqu'un cube de métal est déposé.
+
+void CRobotMain::ShowDropZone(CObject* metal, CObject* truck)
+{
+ CObject* pObj;
+ ObjectType type;
+ D3DVECTOR center, oPos;
+ float oMax, tMax, dist, oRadius, radius;
+ int i, j;
+
+ if ( metal == 0 ) return;
+
+ center = metal->RetPosition(0);
+
+ // Calcule le rayon maximal possible en fonction des autres objets.
+ oMax = 30.0f; // rayon permettant de construire le plus grand bâtiment
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+ if ( pObj == metal ) continue;
+ if ( pObj == truck ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_BASE )
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length(center, oPos)-80.0f;
+ oMax = Min(oMax, dist);
+ }
+ else
+ {
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius;
+ oMax = Min(oMax, dist);
+ }
+ }
+
+ if ( type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_DESTROYER||
+ type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH ||
+ type == OBJECT_RADAR ||
+ type == OBJECT_ENERGY ||
+ type == OBJECT_LABO ||
+ type == OBJECT_NUCLEAR ||
+ type == OBJECT_START ||
+ type == OBJECT_END ||
+ type == OBJECT_INFO ||
+ type == OBJECT_PARA ||
+ type == OBJECT_SAFE ||
+ type == OBJECT_HUSTON ) // bâtiment ?
+ {
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius-BUILDMARGIN;
+ oMax = Min(oMax, dist);
+ }
+ }
+ }
+
+ // Calcule le rayon maximal possible en fonction du terrain.
+ if ( oMax >= 2.0f )
+ {
+ tMax = m_terrain->RetFlatZoneRadius(center, 30.0f);
+ }
+ else
+ {
+ tMax = 0.0f;
+ }
+
+ radius = Min(oMax, tMax);
+ if ( radius >= 2.0f )
+ {
+ SetShowLimit(1, PARTILIMIT2, metal, center, radius, 10.0f);
+ }
+}
+
+// Efface les limites montrées.
+
+void CRobotMain::FlushShowLimit(int i)
+{
+ int j;
+
+ if ( m_showLimit[i].link != 0 )
+ {
+ m_showLimit[i].link->StopShowLimit();
+ }
+
+ for ( j=0 ; j<m_showLimit[i].total ; j++ )
+ {
+ if ( m_showLimit[i].parti[j] == 0 ) continue;
+
+ m_particule->DeleteParticule(m_showLimit[i].parti[j]);
+ m_showLimit[i].parti[j] = 0;
+ }
+
+ m_showLimit[i].total = 0;
+ m_showLimit[i].link = 0;
+ m_showLimit[i].bUsed = FALSE;
+}
+
+// Spécifie les limites à montrer.
+
+void CRobotMain::SetShowLimit(int i, ParticuleType parti, CObject *pObj,
+ D3DVECTOR pos, float radius, float duration)
+{
+ FPOINT dim;
+ float dist;
+ int j;
+
+ FlushShowLimit(i); // efface les limites actuelles
+
+ if ( radius <= 0.0f ) return;
+
+ if ( radius <= 50.0f )
+ {
+ dim = FPOINT(0.3f, 0.3f);
+ dist = 2.5f;
+ }
+ else
+ {
+ dim = FPOINT(1.5f, 1.5f);
+ dist = 10.0f;
+ }
+
+ m_showLimit[i].bUsed = TRUE;
+ m_showLimit[i].link = pObj;
+ m_showLimit[i].pos = pos;
+ m_showLimit[i].radius = radius;
+ m_showLimit[i].duration = duration;
+ m_showLimit[i].total = (int)((radius*2.0f*PI)/dist);
+ if ( m_showLimit[i].total > MAXSHOWPARTI ) m_showLimit[i].total = MAXSHOWPARTI;
+ m_showLimit[i].time = 0.0f;
+
+ for ( j=0 ; j<m_showLimit[i].total ; j++ )
+ {
+ m_showLimit[i].parti[j] = m_particule->CreateParticule(pos, D3DVECTOR(0.0f, 0.0f, 0.0f), dim, parti, duration);
+ }
+}
+
+// Ajuste les limites à montrer.
+
+void CRobotMain::AdjustShowLimit(int i, D3DVECTOR pos)
+{
+ m_showLimit[i].pos = pos;
+}
+
+// Monter les limites de l'objet sélectionné.
+
+void CRobotMain::StartShowLimit()
+{
+ CObject* pObj;
+
+ pObj = RetSelect();
+ if ( pObj == 0 ) return;
+
+ pObj->StartShowLimit();
+}
+
+// Fait avancer les limites montrées.
+
+void CRobotMain::FrameShowLimit(float rTime)
+{
+ D3DVECTOR pos;
+ FPOINT center, rotate;
+ float angle, factor, speed;
+ int i, j;
+
+ if ( m_engine->RetPause() ) return;
+
+ for ( i=0 ; i<MAXSHOWLIMIT ; i++ )
+ {
+ if ( !m_showLimit[i].bUsed ) continue;
+
+ m_showLimit[i].time += rTime;
+
+ if ( m_showLimit[i].time >= m_showLimit[i].duration )
+ {
+ FlushShowLimit(i);
+ continue;
+ }
+
+ if ( m_showLimit[i].time < 1.0f )
+ {
+ factor = m_showLimit[i].time;
+ }
+ else if ( m_showLimit[i].time > m_showLimit[i].duration-1.0f )
+ {
+ factor = m_showLimit[i].duration-m_showLimit[i].time;
+ }
+ else
+ {
+ factor = 1.0f;
+ }
+
+ speed = 0.4f-m_showLimit[i].radius*0.001f;
+ if ( speed < 0.1f ) speed = 0.1f;
+ angle = m_showLimit[i].time*speed;
+
+ for ( j=0 ; j<m_showLimit[i].total ; j++ )
+ {
+ if ( m_showLimit[i].parti[j] == 0 ) continue;
+
+ center.x = m_showLimit[i].pos.x;
+ center.y = m_showLimit[i].pos.z;
+ rotate.x = center.x+m_showLimit[i].radius*factor;
+ rotate.y = center.y;
+ rotate = RotatePoint(center, angle, rotate);
+
+ pos.x = rotate.x;
+ pos.z = rotate.y;
+ pos.y = 0.0f;
+ m_terrain->MoveOnFloor(pos, TRUE);
+ if ( m_showLimit[i].radius <= 50.0f ) pos.y += 0.5f;
+ else pos.y += 2.0f;
+ m_particule->SetPosition(m_showLimit[i].parti[j], pos);
+//? m_particule->SetAngle(m_showLimit[i].parti[j], angle-PI/2.0f);
+
+ angle += (2.0f*PI)/m_showLimit[i].total;
+ }
+ }
+}
+
+
+
+// Retourne un pointeur sur le dernier backslash d'un nom de fichier.
+
+char* SearchLastDir(char *filename)
+{
+ char* p = filename;
+
+ while ( *p++ != 0 );
+ p --; // ^sur le zéro terminateur
+
+ while ( p != filename )
+ {
+ if ( *(--p) == '\\' ) return p;
+ }
+ return 0;
+}
+
+
+// Compile tous les scripts des robots.
+
+void CRobotMain::CompileScript(BOOL bSoluce)
+{
+ CObject* pObj;
+ CBrain* brain;
+ int i, j, nbError, lastError, run;
+ char* name;
+
+ nbError = 0;
+ do
+ {
+ lastError = nbError;
+ nbError = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) continue;
+
+ for ( j=0 ; j<10 ; j++ )
+ {
+ if ( brain->RetCompile(j) ) continue;
+
+ name = brain->RetScriptName(j);
+ if ( name[0] != 0 )
+ {
+ brain->ReadProgram(j, name);
+ if ( !brain->RetCompile(j) ) nbError++;
+ }
+ }
+
+ LoadOneScript(pObj, nbError);
+ }
+ }
+ while ( nbError > 0 && nbError != lastError );
+
+ // Charge toutes les solutions.
+ if ( bSoluce )
+ {
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) continue;
+
+ name = brain->RetSoluceName();
+ if ( name[0] != 0 )
+ {
+ brain->ReadSoluce(name); // charge solution
+ }
+ }
+ }
+
+ // Démarre tous les programmes selon la commande "run".
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) continue;
+
+ run = brain->RetScriptRun();
+ if ( run != -1 )
+ {
+ brain->RunProgram(run); // démarre le programme
+ }
+ }
+}
+
+// Charge tous les programmes d'un robot.
+
+void CRobotMain::LoadOneScript(CObject *pObj, int &nbError)
+{
+ ObjectType type;
+ CBrain* brain;
+ char filename[_MAX_FNAME];
+ char* name;
+ int rank, i, objRank;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) return;
+
+ if ( !IsSelectable(pObj) ) return;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ) return;
+
+ objRank = pObj->RetDefRank();
+ if ( objRank == -1 ) return;
+
+ name = m_dialog->RetSceneName();
+ rank = m_dialog->RetSceneRank();
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ if ( brain->RetCompile(i) ) continue;
+//? if ( brain->ProgramExist(i) ) continue;
+
+ sprintf(filename, "%s\\%s\\%c%.3d%.3d%.1d.txt",
+ RetSavegameDir(), m_gamerName, name[0], rank, objRank, i);
+ brain->ReadProgram(i, filename);
+ if ( !brain->RetCompile(i) ) nbError++;
+ }
+}
+
+// Charge tous les programmes d'un robot.
+
+void CRobotMain::LoadFileScript(CObject *pObj, char* filename, int objRank,
+ int &nbError)
+{
+ ObjectType type;
+ CBrain* brain;
+ char fn[_MAX_FNAME];
+ char* ldir;
+ char* name;
+ int rank, i;
+
+ if ( objRank == -1 ) return;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) return;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ) return;
+
+ name = m_dialog->RetSceneName();
+ rank = m_dialog->RetSceneRank();
+
+ strcpy(fn, filename);
+ ldir = SearchLastDir(fn);
+ if ( ldir == 0 ) return;
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ if ( brain->RetCompile(i) ) continue;
+//? if ( brain->ProgramExist(i) ) continue;
+
+ sprintf(ldir, "\\prog%.3d%.1d.txt", objRank, i);
+ brain->ReadProgram(i, fn);
+ if ( !brain->RetCompile(i) ) nbError++;
+ }
+}
+
+// Sauve tous les programmes de tous les robots.
+
+void CRobotMain::SaveAllScript()
+{
+ CObject* pObj;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ SaveOneScript(pObj);
+ }
+}
+
+// Sauve tous les programmes d'un robot.
+// Si un programme n'existe pas, le fichier correspondant est détruit.
+
+void CRobotMain::SaveOneScript(CObject *pObj)
+{
+ ObjectType type;
+ CBrain* brain;
+ char filename[_MAX_FNAME];
+ char* name;
+ int rank, i, objRank;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) return;
+
+ if ( !IsSelectable(pObj) ) return;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ) return;
+
+ objRank = pObj->RetDefRank();
+ if ( objRank == -1 ) return;
+
+ name = m_dialog->RetSceneName();
+ rank = m_dialog->RetSceneRank();
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ sprintf(filename, "%s\\%s\\%c%.3d%.3d%.1d.txt",
+ RetSavegameDir(), m_gamerName, name[0], rank, objRank, i);
+ brain->WriteProgram(i, filename);
+ }
+}
+
+// Sauve tous les programmes d'un robot.
+// Si un programme n'existe pas, le fichier correspondant est détruit.
+
+void CRobotMain::SaveFileScript(CObject *pObj, char* filename, int objRank)
+{
+ ObjectType type;
+ CBrain* brain;
+ char fn[_MAX_FNAME];
+ char* ldir;
+ char* name;
+ int rank, i;
+
+ if ( objRank == -1 ) return;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) return;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ) return;
+
+ name = m_dialog->RetSceneName();
+ rank = m_dialog->RetSceneRank();
+
+ strcpy(fn, filename);
+ ldir = SearchLastDir(fn);
+ if ( ldir == 0 ) return;
+
+ for ( i=0 ; i<BRAINMAXSCRIPT ; i++ )
+ {
+ sprintf(ldir, "\\prog%.3d%.1d.txt", objRank, i);
+ brain->WriteProgram(i, fn);
+ }
+}
+
+// Sauve le stack du programme en exécution d'un robot.
+
+BOOL CRobotMain::SaveFileStack(CObject *pObj, FILE *file, int objRank)
+{
+ ObjectType type;
+ CBrain* brain;
+
+ if ( objRank == -1 ) return TRUE;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) return TRUE;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ) return TRUE;
+
+ return brain->WriteStack(file);
+}
+
+// Reprend le stack du programme en exécution d'un robot.
+
+BOOL CRobotMain::ReadFileStack(CObject *pObj, FILE *file, int objRank)
+{
+ ObjectType type;
+ CBrain* brain;
+
+ if ( objRank == -1 ) return TRUE;
+
+ brain = pObj->RetBrain();
+ if ( brain == 0 ) return TRUE;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_HUMAN ) return TRUE;
+
+ return brain->ReadStack(file);
+}
+
+
+// Vide la liste.
+
+BOOL CRobotMain::FlushNewScriptName()
+{
+ int i;
+
+ for ( i=0 ; i<MAXNEWSCRIPTNAME ; i++ )
+ {
+ m_newScriptName[i].bUsed = FALSE;
+ }
+ return TRUE;
+}
+
+// Ajoute un nom de script.
+
+BOOL CRobotMain::AddNewScriptName(ObjectType type, char *name)
+{
+ int i;
+
+ for ( i=0 ; i<MAXNEWSCRIPTNAME ; i++ )
+ {
+ if ( !m_newScriptName[i].bUsed )
+ {
+ m_newScriptName[i].bUsed = TRUE;
+ m_newScriptName[i].type = type;
+ strcpy(m_newScriptName[i].name, name);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Cherche un nom de script pour un type donné.
+
+char* CRobotMain::RetNewScriptName(ObjectType type, int rank)
+{
+ int i;
+
+ for ( i=0 ; i<MAXNEWSCRIPTNAME ; i++ )
+ {
+ if ( m_newScriptName[i].bUsed &&
+ (m_newScriptName[i].type == type ||
+ m_newScriptName[i].type == OBJECT_NULL ) )
+ {
+ if ( rank == 0 ) return m_newScriptName[i].name;
+ else rank --;
+ }
+ }
+
+ return 0;
+}
+
+
+// Cherche si un objet est occupé dans une tâche, pour interdire
+// une sauvegarde de la partie.
+
+BOOL CRobotMain::IsBusy()
+{
+ CObject* pObj;
+ CBrain* pBrain;
+//? CAuto* pAuto;
+ int i;
+
+ if ( m_CompteurFileOpen > 0 ) return TRUE;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ pBrain = pObj->RetBrain();
+ if ( pBrain != 0 )
+ {
+ if ( pBrain->IsBusy() ) return TRUE;
+ }
+
+//? pAuto = pObj->RetAuto();
+//? if ( pAuto != 0 )
+//? {
+//? if ( pAuto->RetBusy() ) return TRUE;
+//? }
+ }
+ return FALSE;
+}
+
+// Ecrit un objet dans le fichier de sauvegarde.
+
+void CRobotMain::IOWriteObject(FILE *file, CObject* pObj, char *cmd)
+{
+ D3DVECTOR pos;
+ CBrain* pBrain;
+ char line[3000];
+ char name[100];
+ int run, i;
+
+ if ( pObj->RetType() == OBJECT_FIX ) return;
+
+ strcpy(line, cmd);
+
+ sprintf(name, " type=%s", GetTypeObject(pObj->RetType()));
+ strcat(line, name);
+
+ sprintf(name, " id=%d", pObj->RetID());
+ strcat(line, name);
+
+ pos = pObj->RetPosition(0)/g_unit;
+ sprintf(name, " pos=%.2f;%.2f;%.2f", pos.x, pos.y, pos.z);
+ strcat(line, name);
+
+ pos = pObj->RetAngle(0)/(PI/180.0f);
+ sprintf(name, " angle=%.2f;%.2f;%.2f", pos.x, pos.y, pos.z);
+ strcat(line, name);
+
+ pos = pObj->RetZoom(0);
+ sprintf(name, " zoom=%.2f;%.2f;%.2f", pos.x, pos.y, pos.z);
+ strcat(line, name);
+
+ for ( i=1 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( pObj->RetObjectRank(i) == -1 ) continue;
+
+ pos = pObj->RetPosition(i);
+ if ( pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f )
+ {
+ pos /= g_unit;
+ sprintf(name, " p%d=%.2f;%.2f;%.2f", i, pos.x, pos.y, pos.z);
+ strcat(line, name);
+ }
+
+ pos = pObj->RetAngle(i);
+ if ( pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f )
+ {
+ pos /= (PI/180.0f);
+ sprintf(name, " a%d=%.2f;%.2f;%.2f", i, pos.x, pos.y, pos.z);
+ strcat(line, name);
+ }
+
+ pos = pObj->RetZoom(i);
+ if ( pos.x != 1.0f || pos.y != 1.0f || pos.z != 1.0f )
+ {
+ sprintf(name, " z%d=%.2f;%.2f;%.2f", i, pos.x, pos.y, pos.z);
+ strcat(line, name);
+ }
+ }
+
+ sprintf(name, " trainer=%d", pObj->RetTrainer());
+ strcat(line, name);
+
+ sprintf(name, " option=%d", pObj->RetOption());
+ strcat(line, name);
+
+ if ( pObj == m_infoObject ) // objet sélectionné ?
+ {
+ sprintf(name, " select=1");
+ strcat(line, name);
+ }
+
+ pObj->Write(line);
+
+ if ( pObj->RetType() == OBJECT_BASE )
+ {
+ sprintf(name, " run=3"); // stoppé et ouvert (PARAM_FIXSCENE)
+ strcat(line, name);
+ }
+
+ pBrain = pObj->RetBrain();
+ if ( pBrain != 0 )
+ {
+ run = pBrain->RetProgram();
+ if ( run != -1 )
+ {
+ sprintf(name, " run=%d", run+1);
+ strcat(line, name);
+ }
+ }
+
+ strcat(line, "\n");
+ fputs(line, file);
+}
+
+// Enregistre la partie en cours.
+
+BOOL CRobotMain::IOWriteScene(char *filename, char *filecbot, char *info)
+{
+ FILE* file;
+ char line[500];
+ char* name;
+ CObject *pObj, *pPower, *pFret;
+ float sleep, delay, magnetic, progress;
+ int i, objRank;
+ long version;
+
+ file = fopen(filename, "w");
+ if ( file == NULL ) return FALSE;
+
+ sprintf(line, "Title text=\"%s\"\n", info);
+ fputs(line, file);
+
+ sprintf(line, "Version maj=%d min=%d\n", 0, 1);
+ fputs(line, file);
+
+ name = m_dialog->RetSceneName();
+ if ( strcmp(name, "user") == 0 )
+ {
+ sprintf(line, "Mission base=\"%s\" rank=%.3d dir=\"%s\"\n", name, m_dialog->RetSceneRank(), m_dialog->RetSceneDir());
+ }
+ else
+ {
+ sprintf(line, "Mission base=\"%s\" rank=%.3d\n", name, m_dialog->RetSceneRank());
+ }
+ fputs(line, file);
+
+ sprintf(line, "Map zoom=%.2f\n", m_map->RetZoomMap());
+ fputs(line, file);
+
+ sprintf(line, "DoneResearch bits=%d\n", g_researchDone);
+ fputs(line, file);
+
+ if ( m_blitz->GetStatus(sleep, delay, magnetic, progress) )
+ {
+ sprintf(line, "BlitzMode sleep=%.2f delay=%.2f magnetic=%.2f progress=%.2f\n", sleep, delay, magnetic/g_unit, progress);
+ fputs(line, file);
+ }
+
+ objRank = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetType() == OBJECT_TOTO ) continue;
+ if ( pObj->RetType() == OBJECT_FIX ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+ if ( pObj->RetBurn() ) continue;
+ if ( pObj->RetDead() ) continue;
+ if ( pObj->RetExplo() ) continue;
+
+ pPower = pObj->RetPower();
+ pFret = pObj->RetFret();
+
+ if ( pFret != 0 ) // objet transporté ?
+ {
+ IOWriteObject(file, pFret, "CreateFret");
+ }
+
+ if ( pPower != 0 ) // pile transportée ?
+ {
+ IOWriteObject(file, pPower, "CreatePower");
+ }
+
+ IOWriteObject(file, pObj, "CreateObject");
+
+ SaveFileScript(pObj, filename, objRank++);
+ }
+ fclose(file);
+
+#if CBOT_STACK
+ // Ecrit le fichier des stacks d'exécution.
+ file = fOpen(filecbot, "wb");
+ if ( file == NULL ) return FALSE;
+
+ version = 1;
+ fWrite(&version, sizeof(long), 1, file); // version de COLOBOT
+ version = CBotProgram::GivVersion();
+ fWrite(&version, sizeof(long), 1, file); // version de CBOT
+
+ objRank = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetType() == OBJECT_TOTO ) continue;
+ if ( pObj->RetType() == OBJECT_FIX ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+ if ( pObj->RetBurn() ) continue;
+ if ( pObj->RetDead() ) continue;
+
+ if ( !SaveFileStack(pObj, file, objRank++) ) break;
+ }
+ CBotClass::SaveStaticState(file);
+ fClose(file);
+#endif
+
+ m_delayWriteMessage = 4; // affiche message dans 3 frames
+ return TRUE;
+}
+
+// Reprend un objet enregistré.
+
+CObject* CRobotMain::IOReadObject(char *line, char* filename, int objRank)
+{
+ CObject* pObj;
+//? CBrain* pBrain;
+ CAuto* pAuto;
+ D3DVECTOR pos, dir, zoom;
+ ObjectType type;
+ int id, run, trainer, toy, option, i;
+ char op[10];
+
+ pos = OpDir(line, "pos")*g_unit;
+ dir = OpDir(line, "angle")*(PI/180.0f);
+ zoom = OpDir(line, "zoom");
+ type = OpTypeObject(line, "type", OBJECT_NULL);
+ id = OpInt(line, "id", 0);
+ if ( type == OBJECT_NULL ) return 0;
+ trainer = OpInt(line, "trainer", 0);
+ toy = OpInt(line, "toy", 0);
+ option = OpInt(line, "option", 0);
+ pObj = CreateObject(pos, dir.y, 1.0f, 0.0f, type, 0.0f, trainer, toy, option);
+ pObj->SetDefRank(objRank);
+ pObj->SetPosition(0, pos);
+ pObj->SetAngle(0, dir);
+ pObj->SetID(id);
+ if ( g_id < id ) g_id = id;
+
+ if ( zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f )
+ {
+ pObj->SetZoom(0, zoom);
+ }
+
+ for ( i=1 ; i<OBJECTMAXPART ; i++ )
+ {
+ if ( pObj->RetObjectRank(i) == -1 ) continue;
+
+ sprintf(op, "p%d", i);
+ pos = OpDir(line, op);
+ if ( pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f )
+ {
+ pObj->SetPosition(i, pos*g_unit);
+ }
+
+ sprintf(op, "a%d", i);
+ dir = OpDir(line, op);
+ if ( dir.x != 0.0f || dir.y != 0.0f || dir.z != 0.0f )
+ {
+ pObj->SetAngle(i, dir*(PI/180.0f));
+ }
+
+ sprintf(op, "z%d", i);
+ zoom = OpDir(line, op);
+ if ( zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f )
+ {
+ pObj->SetZoom(i, zoom);
+ }
+ }
+
+ if ( type == OBJECT_BASE ) m_bBase = TRUE;
+
+ pObj->Read(line);
+
+#if CBOT_STACK
+#else
+ LoadFileScript(pObj, filename, objRank, i);
+#endif
+
+ run = OpInt(line, "run", -1);
+ if ( run != -1 )
+ {
+#if CBOT_STACK
+#else
+ pBrain = pObj->RetBrain();
+ if ( pBrain != 0 )
+ {
+ pBrain->RunProgram(run-1); // démarre le programme
+ }
+#endif
+
+ pAuto = pObj->RetAuto();
+ if ( pAuto != 0 )
+ {
+ pAuto->Start(run); // démarre le film
+ }
+ }
+
+ return pObj;
+}
+
+// Reprend une partie enregistrée.
+
+CObject* CRobotMain::IOReadScene(char *filename, char *filecbot)
+{
+ FILE* file;
+ CObject *pObj, *pPower, *pFret, *pSel;
+ char line[3000];
+ float sleep, delay, progress, magnetic;
+ int i, objRank, nbError, lastError;
+ long version;
+
+ m_bBase = FALSE;
+
+ file = fopen(filename, "r");
+ if ( file == NULL ) return 0;
+
+ pFret = 0;
+ pPower = 0;
+ pSel = 0;
+ objRank = 0;
+ while ( fgets(line, 3000, file) != NULL )
+ {
+ for ( i=0 ; i<3000 ; i++ )
+ {
+ if ( line[i] == '\t' ) line[i] = ' '; // remplace tab par space
+ if ( line[i] == '/' && line[i+1] == '/' )
+ {
+ line[i] = 0;
+ break;
+ }
+ }
+
+ if ( Cmd(line, "Map") )
+ {
+ m_map->ZoomMap(OpFloat(line, "zoom", 1.0f));
+ }
+
+ if ( Cmd(line, "DoneResearch") )
+ {
+ g_researchDone = OpInt(line, "bits", 0);
+ }
+
+ if ( Cmd(line, "BlitzMode") )
+ {
+ sleep = OpFloat(line, "sleep", 0.0f);
+ delay = OpFloat(line, "delay", 3.0f);
+ magnetic = OpFloat(line, "magnetic", 50.0f)*g_unit;
+ progress = OpFloat(line, "progress", 0.0f);
+ m_blitz->SetStatus(sleep, delay, magnetic, progress);
+ }
+
+ if ( Cmd(line, "CreateFret") )
+ {
+ pFret = IOReadObject(line, filename, -1);
+ }
+
+ if ( Cmd(line, "CreatePower") )
+ {
+ pPower = IOReadObject(line, filename, -1);
+ }
+
+ if ( Cmd(line, "CreateObject") )
+ {
+ pObj = IOReadObject(line, filename, objRank++);
+
+ if ( OpInt(line, "select", 0) )
+ {
+ pSel = pObj;
+ }
+
+ if ( pFret != 0 )
+ {
+ CTaskManip* task;
+
+ pObj->SetFret(pFret);
+ task = new CTaskManip(m_iMan, pObj);
+ task->Start(TMO_AUTO, TMA_GRAB); // tient l'objet !
+ delete task;
+ }
+
+ if ( pPower != 0 )
+ {
+ pObj->SetPower(pPower);
+ pPower->SetTruck(pObj);
+ }
+
+ pFret = 0;
+ pPower = 0;
+ }
+ }
+ fclose(file);
+
+#if CBOT_STACK
+ // Compile les scripts.
+ nbError = 0;
+ do
+ {
+ lastError = nbError;
+ nbError = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ objRank = pObj->RetDefRank();
+ if ( objRank == -1 ) continue;
+
+ LoadFileScript(pObj, filename, objRank, nbError);
+ }
+ }
+ while ( nbError > 0 && nbError != lastError );
+
+ // Lit le fichier des stacks d'exécution.
+ file = fOpen(filecbot, "rb");
+ if ( file != NULL )
+ {
+ fRead(&version, sizeof(long), 1, file); // version de COLOBOT
+ if ( version == 1 )
+ {
+ fRead(&version, sizeof(long), 1, file); // version de CBOT
+ if ( version == CBotProgram::GivVersion() )
+ {
+ objRank = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetType() == OBJECT_TOTO ) continue;
+ if ( pObj->RetType() == OBJECT_FIX ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+ if ( pObj->RetBurn() ) continue;
+ if ( pObj->RetDead() ) continue;
+
+ if ( !ReadFileStack(pObj, file, objRank++) ) break;
+ }
+ }
+ }
+ CBotClass::RestoreStaticState(file);
+ fClose(file);
+ }
+#endif
+
+ return pSel;
+}
+
+
+// Ecrit les paramètres globaux pour le jeu libre.
+
+void CRobotMain::WriteFreeParam()
+{
+ FILE* file;
+ char filename[_MAX_FNAME];
+ char line[100];
+
+ m_freeResearch |= g_researchDone;
+ m_freeBuild |= g_build;
+
+ if ( m_gamerName[0] == 0 ) return;
+
+ sprintf(filename, "%s\\%s\\research.gam", RetSavegameDir(), m_gamerName);
+ file = fopen(filename, "w");
+ if ( file == NULL ) return;
+
+ sprintf(line, "research=%d build=%d\n", m_freeResearch, m_freeBuild);
+ fputs(line, file);
+ fclose(file);
+}
+
+// Lit les paramètres globaux pour le jeu libre.
+
+void CRobotMain::ReadFreeParam()
+{
+ FILE* file;
+ char filename[_MAX_FNAME];
+ char line[100];
+
+ m_freeResearch = 0;
+ m_freeBuild = 0;
+
+ if ( m_gamerName[0] == 0 ) return;
+
+ sprintf(filename, "%s\\%s\\research.gam", RetSavegameDir(), m_gamerName);
+ file = fopen(filename, "r");
+ if ( file == NULL ) return;
+
+ if ( fgets(line, 100, file) != NULL )
+ {
+ sscanf(line, "research=%d build=%d\n", &m_freeResearch, &m_freeBuild);
+ }
+
+ fclose(file);
+}
+
+
+// Remet tous les objets à leur place initiale.
+
+void CRobotMain::ResetObject()
+{
+#if 0
+ CObject* pObj;
+ CObject* pTruck;
+ CAuto* pAuto;
+ CBrain* brain;
+ CPyro* pyro;
+ ResetCap cap;
+ D3DVECTOR pos, angle;
+ int i;
+
+ // Supprime tous les effets pyrotechniques en cours.
+ while ( TRUE )
+ {
+ pyro = (CPyro*)m_iMan->SearchInstance(CLASS_PYRO, 0);
+ if ( pyro == 0 ) break;
+
+ pyro->DeleteObject();
+ delete pyro;
+ }
+
+ // Supprime toutes les balles en cours.
+ m_particule->DeleteParticule(PARTIGUN1);
+ m_particule->DeleteParticule(PARTIGUN2);
+ m_particule->DeleteParticule(PARTIGUN3);
+ m_particule->DeleteParticule(PARTIGUN4);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ cap = pObj->RetResetCap();
+ if ( cap == RESET_NONE ) continue;
+
+ if ( cap == RESET_DELETE )
+ {
+ pTruck = pObj->RetTruck();
+ if ( pTruck != 0 )
+ {
+ pTruck->SetFret(0);
+ pObj->SetTruck(0);
+ }
+ pObj->DeleteObject();
+ delete pObj;
+ i --;
+ continue;
+ }
+
+ pAuto = pObj->RetAuto();
+ if ( pAuto != 0 )
+ {
+ pAuto->Abort();
+ }
+
+ if ( pObj->RetEnable() ) // objet toujours actif ?
+ {
+ brain = pObj->RetBrain();
+ if ( brain != 0 )
+ {
+ pos = pObj->RetResetPosition();
+ angle = pObj->RetResetAngle();
+
+ if ( pos == pObj->RetPosition(0) &&
+ angle == pObj->RetAngle(0) ) continue;
+ brain->StartTaskReset(pos, angle);
+ continue;
+ }
+ }
+
+ pObj->SetEnable(TRUE); // de nouveau actif
+
+ pos = pObj->RetResetPosition();
+ angle = pObj->RetResetAngle();
+
+ if ( pos == pObj->RetPosition(0) &&
+ angle == pObj->RetAngle(0) ) continue;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_RESET, pObj);
+
+ brain = pObj->RetBrain();
+ if ( brain != 0 )
+ {
+ brain->RunProgram(pObj->RetResetRun());
+ }
+ }
+#else
+ m_bResetCreate = TRUE;
+#endif
+}
+
+// Remet tous les objets à leur place initiale.
+
+void CRobotMain::ResetCreate()
+{
+ CObject* pObj;
+ CPyro* pyro;
+ ResetCap cap;
+ int i;
+
+ SaveAllScript();
+
+ // Supprime toutes les balles en cours.
+ m_particule->DeleteParticule(PARTIGUN1);
+ m_particule->DeleteParticule(PARTIGUN2);
+ m_particule->DeleteParticule(PARTIGUN3);
+ m_particule->DeleteParticule(PARTIGUN4);
+
+ DeselectAll(); // enlève les boutons de commande
+ DeleteAllObjects(); // supprime toute la scène 3D actuelle
+
+ m_particule->FlushParticule();
+ m_terrain->FlushBuildingLevel();
+ m_iMan->Flush(CLASS_OBJECT);
+ m_iMan->Flush(CLASS_PHYSICS);
+ m_iMan->Flush(CLASS_BRAIN);
+ m_iMan->Flush(CLASS_PYRO);
+ m_camera->SetType(CAMERA_DIALOG);
+
+ CreateScene(m_dialog->RetSceneSoluce(), FALSE, TRUE);
+
+ if ( !RetNiceReset() ) return;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ cap = pObj->RetResetCap();
+ if ( cap == RESET_NONE ) continue;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_RESET, pObj);
+ }
+}
+
+// Vérifie si la mission est terminée.
+
+Error CRobotMain::CheckEndMission(BOOL bFrame)
+{
+ CObject* pObj;
+ D3DVECTOR bPos, oPos;
+ ObjectType type;
+ int t, i, nb;
+
+ for ( t=0 ; t<m_endTakeTotal ; t++ )
+ {
+ if ( m_endTake[t].message[0] != 0 ) continue;
+
+ bPos = m_endTake[t].pos;
+ bPos.y = 0.0f;
+
+ nb = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ // Ne pas utiliser RetActif(), car un ver invisible (sous terre)
+ // doit être considéré comme existant ici !
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetRuin() ) continue;
+ if ( !pObj->RetEnable() ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_SCRAP2 ||
+ type == OBJECT_SCRAP3 ||
+ type == OBJECT_SCRAP4 ||
+ type == OBJECT_SCRAP5 ) // déchet ?
+ {
+ type = OBJECT_SCRAP1;
+ }
+ if ( type != m_endTake[t].type ) continue;
+
+ if ( pObj->RetTruck() == 0 )
+ {
+ oPos = pObj->RetPosition(0);
+ }
+ else
+ {
+ oPos = pObj->RetTruck()->RetPosition(0);
+ }
+ oPos.y = 0.0f;
+ if ( Length2d(oPos, bPos) <= m_endTake[t].dist )
+ {
+ nb ++;
+ }
+ }
+
+ if ( nb <= m_endTake[t].lost )
+ {
+ if ( m_endTake[t].type == OBJECT_HUMAN )
+ {
+ if ( m_lostDelay == 0.0f )
+ {
+ m_lostDelay = 0.1f; // perdu immédiatement
+ m_winDelay = 0.0f;
+ }
+ m_displayText->SetEnable(FALSE);
+ return INFO_LOSTq;
+ }
+ else
+ {
+ if ( m_lostDelay == 0.0f )
+ {
+ m_displayText->DisplayError(INFO_LOST, D3DVECTOR(0.0f,0.0f,0.0f));
+ m_lostDelay = m_endTakeLostDelay; // perdu dans 6 secondes
+ m_winDelay = 0.0f;
+ }
+ m_displayText->SetEnable(FALSE);
+ return INFO_LOST;
+ }
+ }
+ if ( nb < m_endTake[t].min ||
+ nb > m_endTake[t].max )
+ {
+ m_displayText->SetEnable(TRUE);
+ return ERR_MISSION_NOTERM;
+ }
+ if ( m_endTake[t].bImmediat )
+ {
+ if ( m_winDelay == 0.0f )
+ {
+ m_winDelay = m_endTakeWinDelay; // gagné dans x seconde
+ m_lostDelay = 0.0f;
+ }
+ m_displayText->SetEnable(FALSE);
+ return ERR_OK; // mission terminée
+ }
+ }
+
+ if ( m_endTakeResearch != 0 )
+ {
+ if ( m_endTakeResearch != (m_endTakeResearch&g_researchDone) )
+ {
+ m_displayText->SetEnable(TRUE);
+ return ERR_MISSION_NOTERM;
+ }
+ }
+
+ if ( m_endTakeWinDelay == -1.0f )
+ {
+ m_winDelay = 1.0f; // gagné dans 1 seconde
+ m_lostDelay = 0.0f;
+ m_displayText->SetEnable(FALSE);
+ return ERR_OK; // mission terminée
+ }
+
+ if ( bFrame && m_bBase ) return ERR_MISSION_NOTERM;
+
+ if ( m_winDelay == 0.0f )
+ {
+ m_displayText->DisplayError(INFO_WIN, D3DVECTOR(0.0f,0.0f,0.0f));
+ m_winDelay = m_endTakeWinDelay; // gagné dans 2 secondes
+ m_lostDelay = 0.0f;
+ }
+ m_displayText->SetEnable(FALSE);
+ return ERR_OK; // mission terminée
+}
+
+// Vérifie si la mission est terminée suite à l'affichage d'un message.
+
+void CRobotMain::CheckEndMessage(char *message)
+{
+ int t;
+
+ for ( t=0 ; t<m_endTakeTotal ; t++ )
+ {
+ if ( m_endTake[t].message[0] == 0 ) continue;
+
+ if ( strcmp(m_endTake[t].message, message) == 0 )
+ {
+ m_displayText->DisplayError(INFO_WIN, D3DVECTOR(0.0f,0.0f,0.0f));
+ m_winDelay = m_endTakeWinDelay; // gagné dans 2 secondes
+ m_lostDelay = 0.0f;
+ }
+ }
+}
+
+
+// Retourne le nombre d'instructions obligatoires.
+
+int CRobotMain::RetObligatoryToken()
+{
+ return m_obligatoryTotal;
+}
+
+// Retourne le nom d'une instruction obligatoire.
+
+char* CRobotMain::RetObligatoryToken(int i)
+{
+ return m_obligatoryToken[i];
+}
+
+// Vérifie si une instruction fait partie de la liste obligatoire.
+
+int CRobotMain::IsObligatoryToken(char *token)
+{
+ int i;
+
+ for ( i=0 ; i<m_obligatoryTotal ; i++ )
+ {
+ if ( strcmp(token, m_obligatoryToken[i]) == 0 )
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+// Vérifie si une instruction ne fait pas partie de la liste interdite.
+
+BOOL CRobotMain::IsProhibitedToken(char *token)
+{
+ int i;
+
+ for ( i=0 ; i<m_prohibitedTotal ; i++ )
+ {
+ if ( strcmp(token, m_prohibitedToken[i]) == 0 )
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+// Indique s'il est possible de télécommander un robot d'entraînement.
+
+BOOL CRobotMain::RetTrainerPilot()
+{
+ return m_bTrainerPilot;
+}
+
+// Indique si la scène est fixe, sans interraction.
+
+BOOL CRobotMain::RetFixScene()
+{
+ return m_bFixScene;
+}
+
+
+char* CRobotMain::RetTitle()
+{
+ return m_title;
+}
+
+char* CRobotMain::RetResume()
+{
+ return m_resume;
+}
+
+char* CRobotMain::RetScriptName()
+{
+ return m_scriptName;
+}
+
+char* CRobotMain::RetScriptFile()
+{
+ return m_scriptFile;
+}
+
+
+BOOL CRobotMain::RetGlint()
+{
+ return m_dialog->RetGlint();
+}
+
+BOOL CRobotMain::RetSoluce4()
+{
+ return m_dialog->RetSoluce4();
+}
+
+BOOL CRobotMain::RetMovies()
+{
+ return m_dialog->RetMovies();
+}
+
+BOOL CRobotMain::RetNiceReset()
+{
+ return m_dialog->RetNiceReset();
+}
+
+BOOL CRobotMain::RetHimselfDamage()
+{
+ return m_dialog->RetHimselfDamage();
+}
+
+BOOL CRobotMain::RetShowSoluce()
+{
+ return m_bShowSoluce;
+}
+
+BOOL CRobotMain::RetSceneSoluce()
+{
+ if ( m_infoFilename[SATCOM_SOLUCE][0] == 0 ) return FALSE;
+ return m_dialog->RetSceneSoluce();
+}
+
+BOOL CRobotMain::RetShowAll()
+{
+ return m_bShowAll;
+}
+
+BOOL CRobotMain::RetCheatRadar()
+{
+ return m_bCheatRadar;
+}
+
+char* CRobotMain::RetSavegameDir()
+{
+ return m_dialog->RetSavegameDir();
+}
+
+char* CRobotMain::RetPublicDir()
+{
+ return m_dialog->RetPublicDir();
+}
+
+char* CRobotMain::RetFilesDir()
+{
+ return m_dialog->RetFilesDir();
+}
+
+
+// Change le nom du joueur.
+
+void CRobotMain::SetGamerName(char *name)
+{
+ strcpy(m_gamerName, name);
+ SetGlobalGamerName(m_gamerName);
+ ReadFreeParam();
+}
+
+// Donne le nom du joueur.
+
+char* CRobotMain::RetGamerName()
+{
+ return m_gamerName;
+}
+
+
+// Retourne la représentation à utiliser pour le joueur.
+
+int CRobotMain::RetGamerFace()
+{
+ return m_dialog->RetGamerFace();
+}
+
+// Retourne la représentation à utiliser pour le joueur.
+
+int CRobotMain::RetGamerGlasses()
+{
+ return m_dialog->RetGamerGlasses();
+}
+
+// Retourne le mode avec seulement la tête.
+
+BOOL CRobotMain::RetGamerOnlyHead()
+{
+ return m_dialog->RetGamerOnlyHead();
+}
+
+// Retourne l'angle de présentation.
+
+float CRobotMain::RetPersoAngle()
+{
+ return m_dialog->RetPersoAngle();
+}
+
+
+// Change le mode de pause.
+
+void CRobotMain::ChangePause(BOOL bPause)
+{
+ m_bPause = bPause;
+ m_engine->SetPause(m_bPause);
+
+ m_sound->MuteAll(m_bPause);
+ CreateShortcuts();
+ if ( m_bPause ) HiliteClear();
+}
+
+
+// Change la vitesse du jeu.
+
+void CRobotMain::SetSpeed(float speed)
+{
+ CButton* pb;
+ char text[10];
+
+ m_engine->SetSpeed(speed);
+
+ pb = (CButton*)m_interface->SearchControl(EVENT_SPEED);
+ if ( pb != 0 )
+ {
+ if ( speed == 1.0f )
+ {
+ pb->ClearState(STATE_VISIBLE);
+ }
+ else
+ {
+ sprintf(text, "x%.1f", speed);
+ pb->SetName(text);
+ pb->SetState(STATE_VISIBLE);
+ }
+ }
+}
+
+float CRobotMain::RetSpeed()
+{
+ return m_engine->RetSpeed();
+}
+
+
+// Crée l'interface des raccourcis aux unités.
+
+BOOL CRobotMain::CreateShortcuts()
+{
+ if ( m_phase != PHASE_SIMUL ) return FALSE;
+ if ( !m_bShortCut ) return FALSE;
+ return m_short->CreateShortcuts();
+}
+
+// Met à jour la carte.
+
+void CRobotMain::UpdateMap()
+{
+ m_map->UpdateMap();
+}
+
+// Indique si la mini-carte est visible.
+
+BOOL CRobotMain::RetShowMap()
+{
+ return m_map->RetShowMap() && m_bMapShow;
+}
+
+
+// Gestion du mode de blocage pendant les films.
+
+void CRobotMain::SetMovieLock(BOOL bLock)
+{
+ m_bMovieLock = bLock;
+ m_engine->SetMovieLock(m_bMovieLock);
+
+ CreateShortcuts();
+ m_map->ShowMap(!m_bMovieLock && m_bMapShow);
+ if ( m_bMovieLock ) HiliteClear();
+ m_engine->SetMouseHide(m_bMovieLock);
+}
+
+BOOL CRobotMain::RetMovieLock()
+{
+ return m_bMovieLock;
+}
+
+BOOL CRobotMain::RetInfoLock()
+{
+ return ( m_displayInfo != 0 ); // info en cours ?
+}
+
+// Gestion du blocage de l'appel du SatCom.
+
+void CRobotMain::SetSatComLock(BOOL bLock)
+{
+ m_bSatComLock = bLock;
+}
+
+BOOL CRobotMain::RetSatComLock()
+{
+ return m_bSatComLock;
+}
+
+// Gestion du mode de blocage pendant l'édition.
+
+void CRobotMain::SetEditLock(BOOL bLock, BOOL bEdit)
+{
+ m_bEditLock = bLock;
+
+ CreateShortcuts();
+
+ // N'enlève pas la carte si elle contient une image fixe.
+ if ( !bLock || !m_map->RetFixImage() )
+ {
+ m_map->ShowMap(!m_bEditLock && m_bMapShow);
+ }
+
+ m_displayText->HideText(bLock);
+ m_engine->FlushPressKey();
+
+ if ( m_bEditLock )
+ {
+ HiliteClear();
+ }
+ else
+ {
+ m_bEditFull = FALSE;
+ }
+}
+
+BOOL CRobotMain::RetEditLock()
+{
+ return m_bEditLock;
+}
+
+// Gestion du mode plein écran pendant l'édition.
+
+void CRobotMain::SetEditFull(BOOL bFull)
+{
+ m_bEditFull = bFull;
+}
+
+BOOL CRobotMain::RetEditFull()
+{
+ return m_bEditFull;
+}
+
+
+BOOL CRobotMain::RetFreePhoto()
+{
+ return m_bFreePhoto;
+}
+
+
+// Indique si la souris vise un objet ami, sur lequel il ne faut
+// pas tirer.
+
+void CRobotMain::SetFriendAim(BOOL bFriend)
+{
+ m_bFriendAim = bFriend;
+}
+
+BOOL CRobotMain::RetFriendAim()
+{
+ return m_bFriendAim;
+}
+
+
+// Gestion de la précision du dessin au sol.
+
+void CRobotMain::SetTracePrecision(float factor)
+{
+ m_engine->SetTracePrecision(factor);
+}
+
+float CRobotMain::RetTracePrecision()
+{
+ return m_engine->RetTracePrecision();
+}
+
+
+// Débute la musique d'une mission.
+
+void CRobotMain::StartMusic()
+{
+ if ( m_audioTrack != 0 )
+ {
+ m_sound->StopMusic();
+ m_sound->PlayMusic(m_audioTrack, m_bAudioRepeat);
+ }
+}
+
+// Enlève hilite et tooltip.
+
+void CRobotMain::ClearInterface()
+{
+ HiliteClear(); // enlève la mise en évidence
+ m_tooltipName[0] = 0; // enlève vraiment le tooltip
+}
+
+
diff --git a/src/robotmain.h b/src/robotmain.h
new file mode 100644
index 0000000..799a0b7
--- /dev/null
+++ b/src/robotmain.h
@@ -0,0 +1,449 @@
+// robotmain.h
+
+#ifndef _ROBOTMAIN_H_
+#define _ROBOTMAIN_H_
+
+
+
+enum Phase
+{
+ PHASE_INIT,
+ PHASE_TERM,
+ PHASE_NAME,
+ PHASE_PERSO,
+ PHASE_TRAINER,
+ PHASE_DEFI,
+ PHASE_MISSION,
+ PHASE_FREE,
+ PHASE_TEEN,
+ PHASE_USER,
+ PHASE_PROTO,
+ PHASE_LOADING,
+ PHASE_SIMUL,
+ PHASE_MODEL,
+ PHASE_SETUPd,
+ PHASE_SETUPg,
+ PHASE_SETUPp,
+ PHASE_SETUPc,
+ PHASE_SETUPs,
+ PHASE_SETUPds,
+ PHASE_SETUPgs,
+ PHASE_SETUPps,
+ PHASE_SETUPcs,
+ PHASE_SETUPss,
+ PHASE_WRITE,
+ PHASE_READ,
+ PHASE_WRITEs,
+ PHASE_READs,
+ PHASE_WIN,
+ PHASE_LOST,
+ PHASE_WELCOME1,
+ PHASE_WELCOME2,
+ PHASE_WELCOME3,
+ PHASE_GENERIC,
+};
+
+
+class CInstanceManager;
+class CMainMovie;
+class CMainDialog;
+class CMainShort;
+class CMainMap;
+class CEvent;
+class CD3DEngine;
+class CLight;
+class CParticule;
+class CWater;
+class CCloud;
+class CBlitz;
+class CPlanet;
+class CTerrain;
+class CObject;
+class CModel;
+class CCamera;
+class CInterface;
+class CWindow;
+class CControl;
+class CDisplayText;
+class CDisplayInfo;
+class CSound;
+
+enum ObjectType;
+enum CameraType;
+enum MainMovieType;
+enum ParticuleType;
+
+
+typedef struct
+{
+ D3DVECTOR pos;
+ float dist;
+ ObjectType type;
+ int min; // gagné si >
+ int max; // gagné si <
+ int lost; // perdu si <=
+ BOOL bImmediat;
+ char message[100];
+}
+EndTake;
+
+
+#define MAXNEWSCRIPTNAME 20
+
+typedef struct
+{
+ BOOL bUsed;
+ ObjectType type;
+ char name[40];
+}
+NewScriptName;
+
+
+#define MAXSHOWLIMIT 5
+#define MAXSHOWPARTI 200
+#define SHOWLIMITTIME 20.0f
+
+typedef struct
+{
+ BOOL bUsed;
+ D3DVECTOR pos;
+ float radius;
+ int total;
+ int parti[MAXSHOWPARTI];
+ CObject* link;
+ float duration;
+ float time;
+}
+ShowLimit;
+
+
+#define SATCOM_HUSTON 0
+#define SATCOM_SAT 1
+#define SATCOM_OBJECT 2
+#define SATCOM_LOADING 3
+#define SATCOM_PROG 4
+#define SATCOM_SOLUCE 5
+#define SATCOM_MAX 6
+
+
+
+class CRobotMain
+{
+public:
+ CRobotMain(CInstanceManager* iMan);
+ ~CRobotMain();
+
+ void CreateIni();
+
+ void ChangePhase(Phase phase);
+ BOOL EventProcess(const Event &event);
+
+ BOOL CreateShortcuts();
+ void ScenePerso();
+
+ void SetMovieLock(BOOL bLock);
+ BOOL RetMovieLock();
+ BOOL RetInfoLock();
+ void SetSatComLock(BOOL bLock);
+ BOOL RetSatComLock();
+ void SetEditLock(BOOL bLock, BOOL bEdit);
+ BOOL RetEditLock();
+ void SetEditFull(BOOL bFull);
+ BOOL RetEditFull();
+ BOOL RetFreePhoto();
+ void SetFriendAim(BOOL bFriend);
+ BOOL RetFriendAim();
+
+ void SetTracePrecision(float factor);
+ float RetTracePrecision();
+
+ void ChangePause(BOOL bPause);
+
+ void SetSpeed(float speed);
+ float RetSpeed();
+
+ void UpdateShortcuts();
+ void SelectHuman();
+ CObject* SearchHuman();
+ CObject* SearchToto();
+ CObject* SearchNearest(D3DVECTOR pos, CObject* pExclu);
+ BOOL SelectObject(CObject* pObj, BOOL bDisplayError=TRUE);
+ CObject* RetSelectObject();
+ CObject* DeselectAll();
+ BOOL DeleteObject();
+
+ void ResetObject();
+ void ResetCreate();
+ Error CheckEndMission(BOOL bFrame);
+ void CheckEndMessage(char *message);
+ int RetObligatoryToken();
+ char* RetObligatoryToken(int i);
+ int IsObligatoryToken(char *token);
+ BOOL IsProhibitedToken(char *token);
+ void UpdateMap();
+ BOOL RetShowMap();
+
+ MainMovieType RetMainMovie();
+
+ void FlushDisplayInfo();
+ void StartDisplayInfo(int index, BOOL bMovie);
+ void StartDisplayInfo(char *filename, int index);
+ void StopDisplayInfo();
+ char* RetDisplayInfoName(int index);
+ int RetDisplayInfoPosition(int index);
+ void SetDisplayInfoPosition(int index, int pos);
+
+ void StartSuspend();
+ void StopSuspend();
+
+ float RetGameTime();
+
+ void SetFontSize(float size);
+ float RetFontSize();
+ void SetWindowPos(FPOINT pos);
+ FPOINT RetWindowPos();
+ void SetWindowDim(FPOINT dim);
+ FPOINT RetWindowDim();
+
+ void SetIOPublic(BOOL bMode);
+ BOOL RetIOPublic();
+ void SetIOPos(FPOINT pos);
+ FPOINT RetIOPos();
+ void SetIODim(FPOINT dim);
+ FPOINT RetIODim();
+
+ char* RetTitle();
+ char* RetResume();
+ char* RetScriptName();
+ char* RetScriptFile();
+ BOOL RetTrainerPilot();
+ BOOL RetFixScene();
+ BOOL RetGlint();
+ BOOL RetSoluce4();
+ BOOL RetMovies();
+ BOOL RetNiceReset();
+ BOOL RetHimselfDamage();
+ BOOL RetShowSoluce();
+ BOOL RetSceneSoluce();
+ BOOL RetShowAll();
+ BOOL RetCheatRadar();
+ char* RetSavegameDir();
+ char* RetPublicDir();
+ char* RetFilesDir();
+
+ void SetGamerName(char *name);
+ char* RetGamerName();
+ int RetGamerFace();
+ int RetGamerGlasses();
+ BOOL RetGamerOnlyHead();
+ float RetPersoAngle();
+
+ void StartMusic();
+ void ClearInterface();
+ void ChangeColor();
+
+ float SearchNearestObject(D3DVECTOR center, CObject *exclu);
+ BOOL FreeSpace(D3DVECTOR &center, float minRadius, float maxRadius, float space, CObject *exclu);
+ float RetFlatZoneRadius(D3DVECTOR center, float maxRadius, CObject *exclu);
+ void HideDropZone(CObject* metal);
+ void ShowDropZone(CObject* metal, CObject* truck);
+ void FlushShowLimit(int i);
+ void SetShowLimit(int i, ParticuleType parti, CObject *pObj, D3DVECTOR pos, float radius, float duration=SHOWLIMITTIME);
+ void AdjustShowLimit(int i, D3DVECTOR pos);
+ void StartShowLimit();
+ void FrameShowLimit(float rTime);
+
+ void CompileScript(BOOL bSoluce);
+ void LoadOneScript(CObject *pObj, int &nbError);
+ void LoadFileScript(CObject *pObj, char* filename, int objRank, int &nbError);
+ void SaveAllScript();
+ void SaveOneScript(CObject *pObj);
+ void SaveFileScript(CObject *pObj, char* filename, int objRank);
+ BOOL SaveFileStack(CObject *pObj, FILE *file, int objRank);
+ BOOL ReadFileStack(CObject *pObj, FILE *file, int objRank);
+
+ BOOL FlushNewScriptName();
+ BOOL AddNewScriptName(ObjectType type, char *name);
+ char* RetNewScriptName(ObjectType type, int rank);
+
+ void WriteFreeParam();
+ void ReadFreeParam();
+
+ BOOL IsBusy();
+ BOOL IOWriteScene(char *filename, char *filecbot, char *info);
+ CObject* IOReadScene(char *filename, char *filecbot);
+ void IOWriteObject(FILE *file, CObject* pObj, char *cmd);
+ CObject* IOReadObject(char *line, char* filename, int objRank);
+
+ int CreateSpot(D3DVECTOR pos, D3DCOLORVALUE color);
+
+protected:
+ BOOL EventFrame(const Event &event);
+ BOOL EventObject(const Event &event);
+ void InitEye();
+
+ void Convert();
+ void CreateScene(BOOL bSoluce, BOOL bFixScene, BOOL bResetObject);
+
+ void CreateModel();
+ D3DVECTOR LookatPoint( D3DVECTOR eye, float angleH, float angleV, float length );
+ CObject* CreateObject(D3DVECTOR pos, float angle, float zoom, float height, ObjectType type, float power=1.0f, BOOL bTrainer=FALSE, BOOL bToy=FALSE, int option=0);
+ int CreateLight(D3DVECTOR direction, D3DCOLORVALUE color);
+ void HiliteClear();
+ void HiliteObject(FPOINT pos);
+ void HiliteFrame(float rTime);
+ void CreateTooltip(FPOINT pos, char* text);
+ void ClearTooltip();
+ CObject* DetectObject(FPOINT pos);
+ void ChangeCamera();
+ void RemoteCamera(float pan, float zoom, float rTime);
+ void KeyCamera(EventMsg event, long param);
+ void AbortMovie();
+ BOOL IsSelectable(CObject* pObj);
+ void SelectOneObject(CObject* pObj, BOOL bDisplayError=TRUE);
+ void HelpObject();
+ BOOL DeselectObject();
+ void DeleteAllObjects();
+ void UpdateInfoText();
+ CObject* SearchObject(ObjectType type);
+ CObject* RetSelect();
+ void StartDisplayVisit(EventMsg event);
+ void FrameVisit(float rTime);
+ void StopDisplayVisit();
+ void ExecuteCmd(char *cmd);
+ BOOL TestGadgetQuantity(int rank);
+
+protected:
+ CInstanceManager* m_iMan;
+ CMainMovie* m_movie;
+ CMainDialog* m_dialog;
+ CMainShort* m_short;
+ CMainMap* m_map;
+ CEvent* m_event;
+ CD3DEngine* m_engine;
+ CParticule* m_particule;
+ CWater* m_water;
+ CCloud* m_cloud;
+ CBlitz* m_blitz;
+ CPlanet* m_planet;
+ CLight* m_light;
+ CTerrain* m_terrain;
+ CModel* m_model;
+ CInterface* m_interface;
+ CCamera* m_camera;
+ CDisplayText* m_displayText;
+ CDisplayInfo* m_displayInfo;
+ CSound* m_sound;
+
+ float m_time;
+ float m_gameTime;
+ float m_checkEndTime;
+ float m_winDelay;
+ float m_lostDelay;
+ BOOL m_bFixScene; // scène fixe, sans interraction
+ BOOL m_bBase; // OBJECT_BASE existe dans mission
+ FPOINT m_lastMousePos;
+ CObject* m_selectObject;
+
+ Phase m_phase;
+ int m_cameraRank;
+ D3DCOLORVALUE m_color;
+ BOOL m_bFreePhoto;
+ BOOL m_bCmdEdit;
+ BOOL m_bShowPos;
+ BOOL m_bSelectInsect;
+ BOOL m_bShowSoluce;
+ BOOL m_bShowAll;
+ BOOL m_bCheatRadar;
+ BOOL m_bAudioRepeat;
+ BOOL m_bShortCut;
+ int m_audioTrack;
+ int m_delayWriteMessage;
+ int m_movieInfoIndex;
+
+ BOOL m_bImmediatSatCom; // SatCom tout de suite ?
+ BOOL m_bBeginSatCom; // message SatCom affiché ?
+ BOOL m_bMovieLock; // film en cours ?
+ BOOL m_bSatComLock; // appel du SatCom possible ?
+ BOOL m_bEditLock; // édition en cours ?
+ BOOL m_bEditFull; // édition en plein écran ?
+ BOOL m_bPause; // simulation en pause
+ BOOL m_bHilite;
+ BOOL m_bTrainerPilot; // télécommande trainer ?
+ BOOL m_bSuspend;
+ BOOL m_bFriendAim;
+ BOOL m_bResetCreate;
+ BOOL m_bMapShow;
+ BOOL m_bMapImage;
+ char m_mapFilename[100];
+
+ FPOINT m_tooltipPos;
+ char m_tooltipName[100];
+ float m_tooltipTime;
+
+ char m_infoFilename[SATCOM_MAX][100]; // noms des fichiers texte
+ CObject* m_infoObject;
+ int m_infoIndex;
+ int m_infoPos[SATCOM_MAX];
+ int m_infoUsed;
+
+ char m_title[100];
+ char m_resume[500];
+ char m_scriptName[100];
+ char m_scriptFile[100];
+ int m_endingWinRank;
+ int m_endingLostRank;
+ BOOL m_bWinTerminate;
+
+ float m_fontSize;
+ FPOINT m_windowPos;
+ FPOINT m_windowDim;
+
+ BOOL m_IOPublic;
+ FPOINT m_IOPos;
+ FPOINT m_IODim;
+
+ NewScriptName m_newScriptName[MAXNEWSCRIPTNAME];
+
+ float m_cameraPan;
+ float m_cameraZoom;
+
+ EventMsg m_visitLast;
+ CObject* m_visitObject;
+ CObject* m_visitArrow;
+ float m_visitTime;
+ float m_visitParticule;
+ D3DVECTOR m_visitPos;
+ D3DVECTOR m_visitPosArrow;
+
+ int m_endTakeTotal;
+ EndTake m_endTake[10];
+ long m_endTakeResearch;
+ float m_endTakeWinDelay;
+ float m_endTakeLostDelay;
+
+ int m_obligatoryTotal;
+ char m_obligatoryToken[100][20];
+ int m_prohibitedTotal;
+ char m_prohibitedToken[100][20];
+
+ char m_gamerName[100];
+
+ long m_freeBuild; // bâtiments constructibles
+ long m_freeResearch; // recherches effectuées
+
+ ShowLimit m_showLimit[MAXSHOWLIMIT];
+
+ D3DCOLORVALUE m_colorRefBot;
+ D3DCOLORVALUE m_colorNewBot;
+ D3DCOLORVALUE m_colorRefAlien;
+ D3DCOLORVALUE m_colorNewAlien;
+ D3DCOLORVALUE m_colorRefGreen;
+ D3DCOLORVALUE m_colorNewGreen;
+ D3DCOLORVALUE m_colorRefWater;
+ D3DCOLORVALUE m_colorNewWater;
+ float m_colorShiftWater;
+};
+
+
+#endif //_ROBOTMAIN_H_
diff --git a/src/script.cpp b/src/script.cpp
new file mode 100644
index 0000000..16ff612
--- /dev/null
+++ b/src/script.cpp
@@ -0,0 +1,3762 @@
+// script.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "cbot/cbotdll.h"
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "global.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "robotmain.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "interface.h"
+#include "edit.h"
+#include "list.h"
+#include "text.h"
+#include "displaytext.h"
+#include "taskmanager.h"
+#include "task.h"
+#include "taskmanip.h"
+#include "taskgoto.h"
+#include "taskshield.h"
+#include "cbottoken.h"
+#include "script.h"
+
+
+
+#define CBOT_IPF 100 // CBOT: number of instructions / frame
+
+#define ERM_CONT 0 // si erreur -> continue
+#define ERM_STOP 1 // si erreur -> stoppe
+
+
+
+
+// Compilation d'une procédure sans ancun paramètre.
+
+CBotTypResult cNull(CBotVar* &var, void* user)
+{
+ if ( var != 0 ) return CBotErrOverParam;
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Compilation d'une procédure avec un seul nombre réel.
+
+CBotTypResult cOneFloat(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Compilation d'une procédure avec deux nombres réels.
+
+CBotTypResult cTwoFloat(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Compilation d'une procédure avec un "point".
+
+CBotTypResult cPoint(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+
+ if ( var->GivType() <= CBotTypDouble )
+ {
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+//? if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+//? if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+//? var = var->GivNext();
+ return CBotTypResult(0);
+ }
+
+ if ( var->GivType() == CBotTypClass )
+ {
+ if ( !var->IsElemOfClass("point") ) return CBotTypResult(CBotErrBadParam);
+ var = var->GivNext();
+ return CBotTypResult(0);
+ }
+
+ return CBotTypResult(CBotErrBadParam);
+}
+
+// Compilation d'une procédure avec un seul "point".
+
+CBotTypResult cOnePoint(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Compilation d'une procédure avec une seule chaîne.
+
+CBotTypResult cString(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString &&
+ var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+
+// Cherche une valeur dans un tableau d'entiers.
+
+BOOL FindList(CBotVar* array, int type)
+{
+ while ( array != 0 )
+ {
+ if ( type == array->GivValInt() ) return TRUE;
+ array = array->GivNext();
+ }
+ return FALSE;
+}
+
+
+// Donne un paramètre de type "point".
+
+BOOL GetPoint(CBotVar* &var, int& exception, D3DVECTOR& pos)
+{
+ CBotVar *pX, *pY, *pZ;
+
+ if ( var->GivType() <= CBotTypDouble )
+ {
+ pos.x = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+
+ pos.z = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+
+ pos.y = 0.0f;
+ }
+ else
+ {
+ pX = var->GivItem("x");
+ if ( pX == NULL )
+ {
+ exception = CBotErrUndefItem; return TRUE;
+ }
+ pos.x = pX->GivValFloat()*g_unit;
+
+ pY = var->GivItem("y");
+ if ( pY == NULL )
+ {
+ exception = CBotErrUndefItem; return TRUE;
+ }
+ pos.z = pY->GivValFloat()*g_unit; // attention y -> z !
+
+ pZ = var->GivItem("z");
+ if ( pZ == NULL )
+ {
+ exception = CBotErrUndefItem; return TRUE;
+ }
+ pos.y = pZ->GivValFloat()*g_unit; // attention z -> y !
+
+ var = var->GivNext();
+ }
+ return TRUE;
+}
+
+
+// Instruction "sin(degrés)".
+
+BOOL rSin(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(sinf(value*PI/180.0f));
+ return TRUE;
+}
+
+// Instruction "cos(degrés)".
+
+BOOL rCos(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(cosf(value*PI/180.0f));
+ return TRUE;
+}
+
+// Instruction "tan(degrés)".
+
+BOOL rTan(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(tanf(value*PI/180.0f));
+ return TRUE;
+}
+
+// Instruction "asin(valeur)".
+
+BOOL raSin(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(asinf(value)*180.0f/PI);
+ return TRUE;
+}
+
+// Instruction "acos(valeur)".
+
+BOOL raCos(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(acosf(value)*180.0f/PI);
+ return TRUE;
+}
+
+// Instruction "atan(valeur)".
+
+BOOL raTan(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(atanf(value)*180.0f/PI);
+ return TRUE;
+}
+
+// Instruction "sqrt(valeur)".
+
+BOOL rSqrt(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(sqrtf(value));
+ return TRUE;
+}
+
+// Instruction "pow(x, y)".
+
+BOOL rPow(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float x, y;
+
+ x = var->GivValFloat();
+ var = var->GivNext();
+ y = var->GivValFloat();
+ result->SetValFloat(powf(x, y));
+ return TRUE;
+}
+
+// Instruction "rand()".
+
+BOOL rRand(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ result->SetValFloat(Rand());
+ return TRUE;
+}
+
+// Instruction "abs()".
+
+BOOL rAbs(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ float value;
+
+ value = var->GivValFloat();
+ result->SetValFloat(Abs(value));
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "retobject(rank)".
+
+CBotTypResult cRetObject(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypPointer, "object");
+}
+
+// Instruction "retobject(rank)".
+
+BOOL rRetObject(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pObj;
+ int rank;
+
+ rank = var->GivValInt();
+
+ pObj = (CObject*)script->m_iMan->SearchInstance(CLASS_OBJECT, rank);
+ if ( pObj == 0 )
+ {
+ result->SetPointer(0);
+ }
+ else
+ {
+ result->SetPointer(pObj->RetBotVar());
+ }
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "search(type, pos)".
+
+CBotTypResult cSearch(CBotVar* &var, void* user)
+{
+ CBotVar* array;
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() == CBotTypArrayPointer )
+ {
+ array = var->GivItemList();
+ if ( array == 0 ) return CBotTypResult(CBotTypPointer);
+ if ( array->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ }
+ else if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ }
+
+ return CBotTypResult(CBotTypPointer, "object");
+}
+
+// Instruction "search(type, pos)".
+
+BOOL rSearch(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject *pObj, *pBest;
+ CBotVar* array;
+ D3DVECTOR pos, oPos;
+ BOOL bNearest = FALSE;
+ BOOL bArray;
+ float min, dist;
+ int type, oType, i;
+
+ if ( var->GivType() == CBotTypArrayPointer )
+ {
+ array = var->GivItemList();
+ bArray = TRUE;
+ }
+ else
+ {
+ type = var->GivValInt();
+ bArray = FALSE;
+ }
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ if ( !GetPoint(var, exception, pos) ) return TRUE;
+ bNearest = TRUE;
+ }
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)script->m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( !pObj->RetActif() ) continue;
+
+ oType = pObj->RetType();
+ if ( oType == OBJECT_TOTO ) continue;
+
+ if ( oType == OBJECT_RUINmobilew2 ||
+ oType == OBJECT_RUINmobilet1 ||
+ oType == OBJECT_RUINmobilet2 ||
+ oType == OBJECT_RUINmobiler1 ||
+ oType == OBJECT_RUINmobiler2 )
+ {
+ oType = OBJECT_RUINmobilew1; // n'importe quelle ruine
+ }
+
+ if ( oType == OBJECT_SCRAP2 ||
+ oType == OBJECT_SCRAP3 ||
+ oType == OBJECT_SCRAP4 ||
+ oType == OBJECT_SCRAP5 ) // déchet ?
+ {
+ oType = OBJECT_SCRAP1; // n'importe quel déchet
+ }
+
+ if ( oType == OBJECT_BARRIER2 ||
+ oType == OBJECT_BARRIER3 ) // barrière ?
+ {
+ oType = OBJECT_BARRIER1; // n'importe quelle barrière
+ }
+
+ if ( bArray )
+ {
+ if ( !FindList(array, oType) ) continue;
+ }
+ else
+ {
+ if ( type != oType && type != OBJECT_NULL ) continue;
+ }
+
+ if ( bNearest )
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(pos, oPos);
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+ else
+ {
+ pBest = pObj;
+ break;
+ }
+ }
+
+ if ( pBest == 0 )
+ {
+ result->SetPointer(0);
+ }
+ else
+ {
+ result->SetPointer(pBest->RetBotVar());
+ }
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "radar(type, angle, focus, min, max, sens)".
+
+CBotTypResult cRadar(CBotVar* &var, void* user)
+{
+ CBotVar* array;
+
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() == CBotTypArrayPointer )
+ {
+ array = var->GivItemList();
+ if ( array == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( array->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // type
+ }
+ else if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // type
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // angle
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // focus
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // min
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // max
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // sens
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); // filtre
+ var = var->GivNext();
+ if ( var == 0 ) return CBotTypResult(CBotTypPointer, "object");
+ return CBotTypResult(CBotErrOverParam);
+}
+
+// Instruction "radar(type, angle, focus, min, max, sens, filter)".
+
+BOOL rRadar(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CObject *pObj, *pBest;
+ CPhysics* physics;
+ CBotVar* array;
+ D3DVECTOR iPos, oPos;
+ RadarFilter filter;
+ float best, minDist, maxDist, sens, iAngle, angle, focus, d, a;
+ int type, oType, i;
+ BOOL bArray;
+
+ type = OBJECT_NULL;
+ angle = 0.0f;
+ focus = PI*2.0f;
+ minDist = 0.0f*g_unit;
+ maxDist = 1000.0f*g_unit;
+ sens = 1.0f;
+ filter = FILTER_NONE;
+
+ if ( var != 0 )
+ {
+ if ( var->GivType() == CBotTypArrayPointer )
+ {
+ array = var->GivItemList();
+ bArray = TRUE;
+ }
+ else
+ {
+ type = var->GivValInt();
+ bArray = FALSE;
+ }
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ angle = -var->GivValFloat()*PI/180.0f;
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ focus = var->GivValFloat()*PI/180.0f;
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ minDist = var->GivValFloat()*g_unit;
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ maxDist = var->GivValFloat()*g_unit;
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ sens = var->GivValFloat();
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ filter = (RadarFilter)var->GivValInt();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ iPos = pThis->RetPosition(0);
+ iAngle = pThis->RetAngleY(0)+angle;
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( sens >= 0.0f ) best = 100000.0f;
+ else best = 0.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)script->m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj == pThis ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+
+ oType = pObj->RetType();
+ if ( oType == OBJECT_TOTO ) continue;
+
+ if ( oType == OBJECT_RUINmobilew2 ||
+ oType == OBJECT_RUINmobilet1 ||
+ oType == OBJECT_RUINmobilet2 ||
+ oType == OBJECT_RUINmobiler1 ||
+ oType == OBJECT_RUINmobiler2 )
+ {
+ oType = OBJECT_RUINmobilew1; // n'importe quelle ruine
+ }
+
+ if ( oType == OBJECT_SCRAP2 ||
+ oType == OBJECT_SCRAP3 ||
+ oType == OBJECT_SCRAP4 ||
+ oType == OBJECT_SCRAP5 ) // déchet ?
+ {
+ oType = OBJECT_SCRAP1; // n'importe quel déchet
+ }
+
+ if ( oType == OBJECT_BARRIER2 ||
+ oType == OBJECT_BARRIER3 ) // barrière ?
+ {
+ oType = OBJECT_BARRIER1; // n'importe quelle barrière
+ }
+
+ if ( filter == FILTER_ONLYLANDING )
+ {
+ physics = pObj->RetPhysics();
+ if ( physics != 0 && !physics->RetLand() ) continue;
+ }
+ if ( filter == FILTER_ONLYFLYING )
+ {
+ physics = pObj->RetPhysics();
+ if ( physics != 0 && physics->RetLand() ) continue;
+ }
+
+ if ( bArray )
+ {
+ if ( !FindList(array, oType) ) continue;
+ }
+ else
+ {
+ if ( type != oType && type != OBJECT_NULL ) continue;
+ }
+
+ oPos = pObj->RetPosition(0);
+ d = Length2d(iPos, oPos);
+ if ( d < minDist || d > maxDist ) continue; // trop proche ou trop loin ?
+
+ if ( focus >= PI*2.0f )
+ {
+ if ( (sens >= 0.0f && d < best) ||
+ (sens < 0.0f && d > best) )
+ {
+ best = d;
+ pBest = pObj;
+ }
+ continue;
+ }
+
+ a = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(a, iAngle-focus/2.0f, iAngle+focus/2.0f) )
+ {
+ if ( (sens >= 0.0f && d < best) ||
+ (sens < 0.0f && d > best) )
+ {
+ best = d;
+ pBest = pObj;
+ }
+ }
+ }
+
+ if ( pBest == 0 )
+ {
+ result->SetPointer(0);
+ }
+ else
+ {
+ result->SetPointer(pBest->RetBotVar());
+ }
+ return TRUE;
+}
+
+
+// Suivi d'une tâche.
+
+BOOL Process(CScript* script, CBotVar* result, int &exception)
+{
+ Error err;
+
+ err = script->m_primaryTask->IsEnded();
+ if ( err != ERR_CONTINUE ) // tâche terminée ?
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+
+ script->m_bContinue = FALSE;
+
+ if ( err == ERR_STOP ) err = ERR_OK;
+ result->SetValInt(err); // indique l'erreur ou ok
+ if ( err != ERR_OK && script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE; // c'est fini
+ }
+
+ script->m_primaryTask->EventProcess(script->m_event);
+ script->m_bContinue = TRUE;
+ return FALSE; // pas fini
+}
+
+
+// Compilation de l'instruction "detect(type)".
+
+CBotTypResult cDetect(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypBoolean);
+}
+
+// Instruction "detect(type)".
+
+BOOL rDetect(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CObject *pObj, *pGoal, *pBest;
+ CPhysics* physics;
+ CBotVar* array;
+ D3DVECTOR iPos, oPos;
+ RadarFilter filter;
+ float bGoal, best, minDist, maxDist, sens, iAngle, angle, focus, d, a;
+ int type, oType, i;
+ BOOL bArray;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ type = OBJECT_NULL;
+ angle = 0.0f;
+ focus = 45.0f*PI/180.0f;
+ minDist = 0.0f*g_unit;
+ maxDist = 20.0f*g_unit;
+ sens = 1.0f;
+ filter = FILTER_NONE;
+
+ if ( var != 0 )
+ {
+ if ( var->GivType() == CBotTypArrayPointer )
+ {
+ array = var->GivItemList();
+ bArray = TRUE;
+ }
+ else
+ {
+ type = var->GivValInt();
+ bArray = FALSE;
+ }
+ }
+
+ iPos = pThis->RetPosition(0);
+ iAngle = pThis->RetAngleY(0)+angle;
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ bGoal = 100000.0f;
+ pGoal = 0;
+ if ( sens >= 0.0f ) best = 100000.0f;
+ else best = 0.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)script->m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj == pThis ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+
+ oType = pObj->RetType();
+ if ( oType == OBJECT_TOTO ) continue;
+
+ if ( oType == OBJECT_RUINmobilew2 ||
+ oType == OBJECT_RUINmobilet1 ||
+ oType == OBJECT_RUINmobilet2 ||
+ oType == OBJECT_RUINmobiler1 ||
+ oType == OBJECT_RUINmobiler2 )
+ {
+ oType = OBJECT_RUINmobilew1; // n'importe quelle ruine
+ }
+
+ if ( oType == OBJECT_SCRAP2 ||
+ oType == OBJECT_SCRAP3 ||
+ oType == OBJECT_SCRAP4 ||
+ oType == OBJECT_SCRAP5 ) // déchet ?
+ {
+ oType = OBJECT_SCRAP1; // n'importe quel déchet
+ }
+
+ if ( oType == OBJECT_BARRIER2 ||
+ oType == OBJECT_BARRIER3 ) // barrière ?
+ {
+ oType = OBJECT_BARRIER1; // n'importe quelle barrière
+ }
+
+ if ( filter == FILTER_ONLYLANDING )
+ {
+ physics = pObj->RetPhysics();
+ if ( physics != 0 && !physics->RetLand() ) continue;
+ }
+ if ( filter == FILTER_ONLYFLYING )
+ {
+ physics = pObj->RetPhysics();
+ if ( physics != 0 && physics->RetLand() ) continue;
+ }
+
+ if ( bArray )
+ {
+ if ( !FindList(array, oType) ) continue;
+ }
+ else
+ {
+ if ( type != oType && type != OBJECT_NULL ) continue;
+ }
+
+ oPos = pObj->RetPosition(0);
+ d = Length2d(iPos, oPos);
+ a = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+
+ if ( d < bGoal &&
+ TestAngle(a, iAngle-(5.0f*PI/180.0f)/2.0f, iAngle+(5.0f*PI/180.0f)/2.0f) )
+ {
+ bGoal = d;
+ pGoal = pObj;
+ }
+
+ if ( d < minDist || d > maxDist ) continue; // trop proche ou trop loin ?
+
+ if ( focus >= PI*2.0f )
+ {
+ if ( (sens >= 0.0f && d < best) ||
+ (sens < 0.0f && d > best) )
+ {
+ best = d;
+ pBest = pObj;
+ }
+ continue;
+ }
+
+ if ( TestAngle(a, iAngle-focus/2.0f, iAngle+focus/2.0f) )
+ {
+ if ( (sens >= 0.0f && d < best) ||
+ (sens < 0.0f && d > best) )
+ {
+ best = d;
+ pBest = pObj;
+ }
+ }
+ }
+
+ pThis->StartDetectEffect(pGoal, pBest!=0);
+
+ if ( pBest == 0 )
+ {
+ script->m_returnValue = 0.0f;
+ }
+ else
+ {
+ script->m_returnValue = 1.0f;
+ }
+
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskWait(0.3f);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ if ( !Process(script, result, exception) ) return FALSE; // pas terminé
+ result->SetValFloat(script->m_returnValue);
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "direction(pos)".
+
+CBotTypResult cDirection(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "direction(pos)".
+
+BOOL rDirection(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ D3DVECTOR iPos, oPos;
+ float a, g;
+
+ if ( !GetPoint(var, exception, oPos) ) return TRUE;
+
+ iPos = pThis->RetPosition(0);
+
+ a = pThis->RetAngleY(0);
+ g = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+
+ result->SetValFloat(-Direction(a, g)*180.0f/PI);
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "produce(pos, angle, type, scriptName)".
+
+CBotTypResult cProduce(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString ) return CBotTypResult(CBotErrBadString);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "produce(pos, angle, type, scriptName)".
+
+BOOL rProduce(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* object;
+ CBotString cbs;
+ const char* name;
+ D3DVECTOR pos;
+ float angle;
+ ObjectType type;
+
+ if ( !GetPoint(var, exception, pos) ) return TRUE;
+
+ angle = var->GivValFloat()*PI/180.0f;
+ var = var->GivNext();
+
+ type = (ObjectType)var->GivValInt();
+ var = var->GivNext();
+
+ cbs = var->GivValString();
+ name = cbs;
+
+ if ( 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_TNT ||
+ type == OBJECT_SCRAP1 ||
+ type == OBJECT_SCRAP2 ||
+ type == OBJECT_SCRAP3 ||
+ type == OBJECT_SCRAP4 ||
+ type == OBJECT_SCRAP5 ||
+ type == OBJECT_BOMB ||
+ type == OBJECT_WAYPOINT ||
+ type == OBJECT_SHOW ||
+ type == OBJECT_WINFIRE )
+ {
+ object = new CObject(script->m_iMan);
+ if ( !object->CreateResource(pos, angle, type) )
+ {
+ delete object;
+ result->SetValInt(1); // erreur
+ return TRUE;
+ }
+ }
+ else
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM )
+ {
+ CObject* egg;
+
+ object = new CObject(script->m_iMan);
+ if ( !object->CreateInsect(pos, angle, type) )
+ {
+ delete object;
+ result->SetValInt(1); // erreur
+ return TRUE;
+ }
+
+ egg = new CObject(script->m_iMan);
+ if ( !egg->CreateResource(pos, angle, OBJECT_EGG, 0.0f) )
+ {
+ delete egg;
+ }
+ }
+ else
+ {
+ result->SetValInt(1); // impossible
+ return TRUE;
+ }
+ object->SetActivity(FALSE);
+ object->ReadProgram(0, (char*)name);
+ object->RunProgram(0);
+
+ result->SetValInt(0); // pas d'erreur
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "distance(p1, p2)".
+
+CBotTypResult cDistance(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "distance(p1, p2)".
+
+BOOL rDistance(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ D3DVECTOR p1, p2;
+ float value;
+
+ if ( !GetPoint(var, exception, p1) ) return TRUE;
+ if ( !GetPoint(var, exception, p2) ) return TRUE;
+
+ value = Length(p1, p2);
+ result->SetValFloat(value/g_unit);
+ return TRUE;
+}
+
+// Instruction "distance2d(p1, p2)".
+
+BOOL rDistance2d(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ D3DVECTOR p1, p2;
+ float value;
+
+ if ( !GetPoint(var, exception, p1) ) return TRUE;
+ if ( !GetPoint(var, exception, p2) ) return TRUE;
+
+ value = Length2d(p1, p2);
+ result->SetValFloat(value/g_unit);
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "space(center, rMin, rMax, dist)".
+
+CBotTypResult cSpace(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotTypIntrinsic, "point");
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotTypIntrinsic, "point");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypIntrinsic, "point");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypIntrinsic, "point");
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypIntrinsic, "point");
+}
+
+// Instruction "space(center, rMin, rMax, dist)".
+
+BOOL rSpace(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CBotVar* pSub;
+ D3DVECTOR center;
+ float rMin, rMax, dist;
+
+ rMin = 10.0f*g_unit;
+ rMax = 50.0f*g_unit;
+ dist = 4.0f*g_unit;
+
+ if ( var == 0 )
+ {
+ center = pThis->RetPosition(0);
+ }
+ else
+ {
+ if ( !GetPoint(var, exception, center) ) return TRUE;
+
+ if ( var != 0 )
+ {
+ rMin = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+
+ if ( var != 0 )
+ {
+ rMax = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+
+ if ( var != 0 )
+ {
+ dist = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+ }
+ }
+ }
+ }
+ script->m_main->FreeSpace(center, rMin, rMax, dist, pThis);
+
+ if ( result != 0 )
+ {
+ pSub = result->GivItemList();
+ if ( pSub != 0 )
+ {
+ pSub->SetValFloat(center.x/g_unit);
+ pSub = pSub->GivNext(); // "y"
+ pSub->SetValFloat(center.z/g_unit);
+ pSub = pSub->GivNext(); // "z"
+ pSub->SetValFloat(center.y/g_unit);
+ }
+ }
+ return TRUE;
+}
+
+
+// Compilation de l'instruction "flatground(center, rMax)".
+
+CBotTypResult cFlatGround(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "flatground(center, rMax)".
+
+BOOL rFlatGround(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ D3DVECTOR center;
+ float rMax, dist;
+
+ if ( !GetPoint(var, exception, center) ) return TRUE;
+ rMax = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+
+ dist = script->m_main->RetFlatZoneRadius(center, rMax, pThis);
+ result->SetValFloat(dist/g_unit);
+
+ return TRUE;
+}
+
+
+// Instruction "wait(t)".
+
+BOOL rWait(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ float value;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ value = var->GivValFloat();
+ err = script->m_primaryTask->StartTaskWait(value);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "move(dist)".
+
+BOOL rMove(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ float value;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ value = var->GivValFloat();
+ err = script->m_primaryTask->StartTaskAdvance(value*g_unit);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "turn(angle)".
+
+BOOL rTurn(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ float value;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ value = var->GivValFloat();
+ err = script->m_primaryTask->StartTaskTurn(-value*PI/180.0f);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Compilation de l'instruction "goto(pos, altitude, crash, goal)".
+
+CBotTypResult cGoto(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ return CBotTypResult(CBotErrOverParam);
+}
+
+// Instruction "goto(pos, altitude, mode)".
+
+BOOL rGoto(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ D3DVECTOR pos;
+ TaskGotoGoal goal;
+ TaskGotoCrash crash;
+ float altitude;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ if ( !GetPoint(var, exception, pos) ) return TRUE;
+
+ goal = TGG_DEFAULT;
+ crash = TGC_DEFAULT;
+ altitude = 0.0f*g_unit;
+
+ if ( var != 0 )
+ {
+ altitude = var->GivValFloat()*g_unit;
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ goal = (TaskGotoGoal)var->GivValInt();
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ crash = (TaskGotoCrash)var->GivValInt();
+ }
+ }
+ }
+
+ err = script->m_primaryTask->StartTaskGoto(pos, altitude, goal, crash);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "find(type)".
+
+BOOL rFind(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ D3DVECTOR pos;
+ TaskGotoGoal goal;
+ TaskGotoCrash crash;
+ float altitude;
+ Error err;
+ CObject* pThis = (CObject*)user;
+ CObject *pObj, *pBest;
+ CBotVar* array;
+ D3DVECTOR iPos, oPos;
+ float best, minDist, maxDist, sens, iAngle, angle, focus, d, a;
+ int type, oType, i;
+ BOOL bArray;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ type = OBJECT_NULL;
+ angle = 0.0f;
+ focus = PI*2.0f;
+ minDist = 0.0f*g_unit;
+ maxDist = 1000.0f*g_unit;
+ sens = 1.0f;
+
+ if ( var->GivType() == CBotTypArrayPointer )
+ {
+ array = var->GivItemList();
+ bArray = TRUE;
+ }
+ else
+ {
+ type = var->GivValInt();
+ bArray = FALSE;
+ }
+
+ best = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)script->m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+ if ( pObj == pThis ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+
+ oType = pObj->RetType();
+ if ( oType == OBJECT_TOTO ) continue;
+
+ if ( oType == OBJECT_RUINmobilew2 ||
+ oType == OBJECT_RUINmobilet1 ||
+ oType == OBJECT_RUINmobilet2 ||
+ oType == OBJECT_RUINmobiler1 ||
+ oType == OBJECT_RUINmobiler2 )
+ {
+ oType = OBJECT_RUINmobilew1; // n'importe quelle ruine
+ }
+
+ if ( oType == OBJECT_SCRAP2 ||
+ oType == OBJECT_SCRAP3 ||
+ oType == OBJECT_SCRAP4 ||
+ oType == OBJECT_SCRAP5 ) // déchet ?
+ {
+ oType = OBJECT_SCRAP1; // n'importe quel déchet
+ }
+
+ if ( oType == OBJECT_BARRIER2 ||
+ oType == OBJECT_BARRIER3 ) // barrière ?
+ {
+ oType = OBJECT_BARRIER1; // n'importe quelle barrière
+ }
+
+ if ( bArray )
+ {
+ if ( !FindList(array, oType) ) continue;
+ }
+ else
+ {
+ if ( type != oType && type != OBJECT_NULL ) continue;
+ }
+
+ oPos = pObj->RetPosition(0);
+ d = Length2d(iPos, oPos);
+ if ( d < minDist || d > maxDist ) continue; // trop proche ou trop loin ?
+
+ if ( focus >= PI*2.0f )
+ {
+ if ( d < best )
+ {
+ best = d;
+ pBest = pObj;
+ }
+ continue;
+ }
+
+ a = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(a, iAngle-focus/2.0f, iAngle+focus/2.0f) )
+ {
+ if ( d < best )
+ {
+ best = d;
+ pBest = pObj;
+ }
+ }
+ }
+
+ if ( pBest == 0 )
+ {
+ exception = ERR_FIND_IMPOSSIBLE;
+ return FALSE;
+ }
+
+ pos = pBest->RetPosition(0);
+ goal = TGG_DEFAULT;
+ crash = TGC_DEFAULT;
+ altitude = 0.0f*g_unit;
+
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskGoto(pos, altitude, goal, crash);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Compilation "grab/drop(oper)".
+
+CBotTypResult cGrabDrop(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "grab(oper)".
+
+BOOL rGrab(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ ObjectType oType;
+ TaskManipArm type;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ if ( var == 0 ) type = TMA_FFRONT;
+ else type = (TaskManipArm)var->GivValInt();
+
+ oType = pThis->RetType();
+ if ( oType == OBJECT_HUMAN ||
+ oType == OBJECT_TECH )
+ {
+ err = script->m_primaryTask->StartTaskTake();
+ }
+ else
+ {
+ err = script->m_primaryTask->StartTaskManip(TMO_GRAB, type);
+ }
+
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "drop(oper)".
+
+BOOL rDrop(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ ObjectType oType;
+ TaskManipArm type;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ if ( var == 0 ) type = TMA_FFRONT;
+ else type = (TaskManipArm)var->GivValInt();
+
+ oType = pThis->RetType();
+ if ( oType == OBJECT_HUMAN ||
+ oType == OBJECT_TECH )
+ {
+ err = script->m_primaryTask->StartTaskTake();
+ }
+ else
+ {
+ err = script->m_primaryTask->StartTaskManip(TMO_DROP, type);
+ }
+
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "sniff()".
+
+BOOL rSniff(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskSearch();
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Compilation de l'instruction "receive(nom, power)".
+
+CBotTypResult cReceive(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString ) return CBotTypResult(CBotErrBadString);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "receive(nom, power)".
+
+BOOL rReceive(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CBotString cbs;
+ Error err;
+ const char* p;
+ float value, power;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+
+ cbs = var->GivValString();
+ p = cbs;
+ var = var->GivNext();
+
+ power = 10.0f*g_unit;
+ if ( var != 0 )
+ {
+ power = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+ }
+
+ err = script->m_primaryTask->StartTaskInfo((char*)p, 0.0f, power, FALSE);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetInit(IS_NAN);
+ return TRUE;
+ }
+ }
+ if ( !Process(script, result, exception) ) return FALSE; // pas terminé
+
+ value = pThis->RetInfoReturn();
+ if ( value == NAN )
+ {
+ result->SetInit(IS_NAN);
+ }
+ else
+ {
+ result->SetValFloat(value);
+ }
+ return TRUE;
+}
+
+// Compilation de l'instruction "send(nom, value, power)".
+
+CBotTypResult cSend(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString ) return CBotTypResult(CBotErrBadString);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "send(nom, value, power)".
+
+BOOL rSend(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CBotString cbs;
+ Error err;
+ const char* p;
+ float value, power;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+
+ cbs = var->GivValString();
+ p = cbs;
+ var = var->GivNext();
+
+ value = var->GivValFloat();
+ var = var->GivNext();
+
+ power = 10.0f*g_unit;
+ if ( var != 0 )
+ {
+ power = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+ }
+
+ err = script->m_primaryTask->StartTaskInfo((char*)p, value, power, TRUE);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Cherche la borne d'information la plus proche.
+
+CObject* SearchInfo(CScript* script, CObject* object, float power)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float dist, min;
+ int i;
+
+ iPos = object->RetPosition(0);
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)script->m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_INFO ) continue;
+
+ if ( !pObj->RetActif() ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, iPos);
+ if ( dist > power ) continue; // trop loin ?
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+
+ return pBest;
+}
+
+// Compilation de l'instruction "deleteinfo(nom, power)".
+
+CBotTypResult cDeleteInfo(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString ) return CBotTypResult(CBotErrBadString);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "deleteinfo(nom, power)".
+
+BOOL rDeleteInfo(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CObject* pInfo;
+ CBotString cbs;
+ Info info;
+ const char* p;
+ float power;
+ int i, total;
+
+ exception = 0;
+
+ cbs = var->GivValString();
+ p = cbs;
+ var = var->GivNext();
+
+ power = 10.0f*g_unit;
+ if ( var != 0 )
+ {
+ power = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+ }
+
+ pInfo = SearchInfo(script, pThis, power);
+ if ( pInfo == 0 )
+ {
+ result->SetValFloat(0.0f); // false
+ return TRUE;
+ }
+
+ total = pInfo->RetInfoTotal();
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = pInfo->RetInfo(i);
+ if ( strcmp(info.name, p) == 0 )
+ {
+ pInfo->DeleteInfo(i);
+ result->SetValFloat(1.0f); // true
+ return TRUE;
+ }
+ }
+ result->SetValFloat(0.0f); // false
+ return TRUE;
+}
+
+// Compilation de l'instruction "testinfo(nom, power)".
+
+CBotTypResult cTestInfo(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString ) return CBotTypResult(CBotErrBadString);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypBoolean);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypBoolean);
+}
+
+// Instruction "testinfo(nom, power)".
+
+BOOL rTestInfo(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ CObject* pInfo;
+ CBotString cbs;
+ Info info;
+ const char* p;
+ float power;
+ int i, total;
+
+ exception = 0;
+
+ cbs = var->GivValString();
+ p = cbs;
+ var = var->GivNext();
+
+ power = 10.0f*g_unit;
+ if ( var != 0 )
+ {
+ power = var->GivValFloat()*g_unit;
+ var = var->GivNext();
+ }
+
+ pInfo = SearchInfo(script, pThis, power);
+ if ( pInfo == 0 )
+ {
+ result->SetValInt(FALSE);
+ return TRUE;
+ }
+
+ total = pInfo->RetInfoTotal();
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = pInfo->RetInfo(i);
+ if ( strcmp(info.name, p) == 0 )
+ {
+ result->SetValInt(TRUE);
+ return TRUE;
+ }
+ }
+ result->SetValInt(FALSE);
+ return TRUE;
+}
+
+// Instruction "thump()".
+
+BOOL rThump(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskTerraform();
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "recycle()".
+
+BOOL rRecycle(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskRecover();
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Compilation "shield(oper, radius)".
+
+CBotTypResult cShield(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "shield(oper, radius)".
+
+BOOL rShield(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ float oper, radius;
+ Error err;
+
+ oper = var->GivValFloat(); // 0=down, 1=up
+ var = var->GivNext();
+
+ radius = var->GivValFloat();
+ if ( radius < 10.0f ) radius = 10.0f;
+ if ( radius > 25.0f ) radius = 25.0f;
+ radius = (radius-10.0f)/15.0f;
+
+ if ( *script->m_secondaryTask == 0 ) // bouclier replié ?
+ {
+ if ( oper == 0.0f ) // down ?
+ {
+ result->SetValInt(1); // indique une erreur
+ }
+ else // up ?
+ {
+ pThis->SetParam(radius);
+
+ *script->m_secondaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = (*script->m_secondaryTask)->StartTaskShield(TSM_UP, 1000.0f);
+ if ( err != ERR_OK )
+ {
+ delete *script->m_secondaryTask;
+ *script->m_secondaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ }
+ }
+ }
+ else // bouclier deployé ?
+ {
+ if ( oper == 0.0f ) // down ?
+ {
+ (*script->m_secondaryTask)->StartTaskShield(TSM_DOWN, 0.0f);
+ }
+ else // up ?
+ {
+//? result->SetValInt(1); // indique une erreur
+ pThis->SetParam(radius);
+ (*script->m_secondaryTask)->StartTaskShield(TSM_UPDATE, 0.0f);
+ }
+ }
+
+ return TRUE;
+}
+
+// Compilation "fire(delay)".
+
+CBotTypResult cFire(CBotVar* &var, void* user)
+{
+#if 0
+ CObject* pThis = (CObject*)user;
+ ObjectType type;
+
+ type = pThis->RetType();
+
+ if ( type == OBJECT_ANT )
+ {
+ return cOnePoint(var, user);
+ }
+ else if ( type == OBJECT_SPIDER )
+ {
+ return cNull(var, user);
+ }
+ else
+ {
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+ return CBotTypResult(CBotTypFloat);
+ }
+#else
+ return CBotTypResult(CBotTypFloat);
+#endif
+}
+
+// Instruction "fire(delay)".
+
+BOOL rFire(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ float delay;
+ D3DVECTOR impact;
+ Error err;
+ ObjectType type;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+
+ type = pThis->RetType();
+
+ if ( type == OBJECT_ANT )
+ {
+ if ( !GetPoint(var, exception, impact) ) return TRUE;
+ impact.y += pThis->RetWaterLevel();
+ err = script->m_primaryTask->StartTaskFireAnt(impact);
+ }
+ else if ( type == OBJECT_SPIDER )
+ {
+ err = script->m_primaryTask->StartTaskSpiderExplo();
+ }
+ else
+ {
+ if ( var == 0 ) delay = 0.0f;
+ else delay = var->GivValFloat();
+ err = script->m_primaryTask->StartTaskFire(delay);
+ }
+
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Instruction "aim(dir)".
+
+BOOL rAim(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ float value;
+ Error err;
+
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ value = var->GivValFloat();
+ err = script->m_primaryTask->StartTaskGunGoal(value*PI/180.0f, 0.0f);
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+}
+
+// Compilation de l'instruction "motor(left, right)".
+
+CBotTypResult cMotor(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var != 0 ) return CBotTypResult(CBotErrOverParam);
+
+ return CBotTypResult(CBotTypFloat);
+}
+
+// Instruction "motor(left, right)".
+
+BOOL rMotor(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CObject* pThis = (CObject*)user;
+ CPhysics* physics = ((CObject*)user)->RetPhysics();
+ float left, right, speed, turn;
+
+ left = var->GivValFloat();
+ var = var->GivNext();
+ right = var->GivValFloat();
+
+ speed = (left+right)/2.0f;
+ if ( speed < -1.0f ) speed = -1.0f;
+ if ( speed > 1.0f ) speed = 1.0f;
+
+ turn = left-right;
+ if ( turn < -1.0f ) turn = -1.0f;
+ if ( turn > 1.0f ) turn = 1.0f;
+
+ if ( pThis->RetFixed() ) // fourmi sur le dos ?
+ {
+ speed = 0.0f;
+ turn = 0.0f;
+ }
+
+ physics->SetMotorSpeedX(speed); // avance/recule
+ physics->SetMotorSpeedZ(turn); // tourne
+
+ return TRUE;
+}
+
+// Instruction "jet(power)".
+
+BOOL rJet(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CPhysics* physics = ((CObject*)user)->RetPhysics();
+ float value;
+
+ value = var->GivValFloat();
+ physics->SetMotorSpeedY(value);
+
+ return TRUE;
+}
+
+// Compilation de l'instruction "topo(pos)".
+
+CBotTypResult cTopo(CBotVar* &var, void* user)
+{
+ CBotTypResult ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ ret = cPoint(var, user);
+ if ( ret.GivType() != 0 ) return ret;
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ return CBotTypResult(CBotErrOverParam);
+}
+
+// Instruction "topo(pos)".
+
+BOOL rTopo(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ D3DVECTOR pos;
+ float level;
+
+ exception = 0;
+
+ if ( !GetPoint(var, exception, pos) ) return TRUE;
+
+ level = script->m_terrain->RetFloorLevel(pos);
+ level -= script->m_water->RetLevel();
+ result->SetValFloat(level/g_unit);
+ return TRUE;
+}
+
+// Compilation de l'instruction "message(string, type)".
+
+CBotTypResult cMessage(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotErrLowParam);
+ if ( var->GivType() != CBotTypString &&
+ var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ return CBotTypResult(CBotErrOverParam);
+}
+
+// Instruction "message(string, type)".
+
+BOOL rMessage(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CBotString cbs;
+ const char* p;
+ TextType type;
+
+ cbs = var->GivValString();
+ p = cbs;
+
+ type = TT_MESSAGE;
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ type = (TextType)var->GivValInt();
+ }
+
+ script->m_displayText->DisplayText((char*)p, script->m_object, 10.0f, type);
+ script->m_main->CheckEndMessage((char*)p);
+
+ return TRUE;
+}
+
+// Instruction "cmdline(rank)".
+
+BOOL rCmdline(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ float value;
+ int rank;
+
+ rank = var->GivValInt();
+ value = pThis->RetCmdLine(rank);
+ result->SetValFloat(value);
+
+ return TRUE;
+}
+
+// Instruction "ismovie()".
+
+BOOL rIsMovie(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ float value;
+
+ value = script->m_main->RetMovieLock()?1.0f:0.0f;
+ result->SetValFloat(value);
+
+ return TRUE;
+}
+
+// Instruction "errmode(mode)".
+
+BOOL rErrMode(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ int value;
+
+ value = var->GivValInt();
+ if ( value < 0 ) value = 0;
+ if ( value > 1 ) value = 1;
+ script->m_errMode = value;
+
+ return TRUE;
+}
+
+// Instruction "ipf(num)".
+
+BOOL rIPF(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ int value;
+
+ value = var->GivValInt();
+ if ( value < 1 ) value = 1;
+ if ( value > 10000 ) value = 10000;
+ script->m_ipf = value;
+
+ return TRUE;
+}
+
+// Instruction "abstime()".
+
+BOOL rAbsTime(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ float value;
+
+ value = script->m_main->RetGameTime();
+ result->SetValFloat(value);
+ return TRUE;
+}
+
+
+// Prépare un nom de fichier.
+
+void PrepareFilename(CBotString &filename, char *dir)
+{
+ 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(dir) + CBotString("\\") + filename;
+}
+
+// Instruction "deletefile(filename)".
+
+BOOL rDeleteFile(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CBotString cbs;
+ const char* p;
+ char* dir;
+
+ cbs = var->GivValString();
+ dir = script->m_main->RetFilesDir();
+ PrepareFilename(cbs, dir);
+ p = cbs;
+ DeleteFile(p);
+
+ return TRUE;
+}
+
+// Compilation de l'instruction "pendown(color, width)".
+
+CBotTypResult cPenDown(CBotVar* &var, void* user)
+{
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ if ( var->GivType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
+ var = var->GivNext();
+
+ if ( var == 0 ) return CBotTypResult(CBotTypFloat);
+ return CBotTypResult(CBotErrOverParam);
+}
+
+// Instruction "pendown(color, width)".
+
+BOOL rPenDown(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ int color;
+ float width;
+ Error err;
+
+ if ( pThis->RetType() == OBJECT_MOBILEdr )
+ {
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ if ( var != 0 )
+ {
+ color = var->GivValInt();
+ if ( color < 0 ) color = 0;
+ if ( color > 17 ) color = 17;
+ pThis->SetTraceColor(color);
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ width = var->GivValFloat();
+ if ( width < 0.1f ) width = 0.1f;
+ if ( width > 1.0f ) width = 1.0f;
+ pThis->SetTraceWidth(width);
+ }
+ }
+ pThis->SetTraceDown(TRUE);
+
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskPen(pThis->RetTraceDown(), pThis->RetTraceColor());
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+ }
+ else
+ {
+ if ( var != 0 )
+ {
+ color = var->GivValInt();
+ if ( color < 0 ) color = 0;
+ if ( color > 17 ) color = 17;
+ pThis->SetTraceColor(color);
+
+ var = var->GivNext();
+ if ( var != 0 )
+ {
+ width = var->GivValFloat();
+ if ( width < 0.1f ) width = 0.1f;
+ if ( width > 1.0f ) width = 1.0f;
+ pThis->SetTraceWidth(width);
+ }
+ }
+ pThis->SetTraceDown(TRUE);
+
+ return TRUE;
+ }
+}
+
+// Instruction "penup()".
+
+BOOL rPenUp(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CObject* pThis = (CObject*)user;
+ Error err;
+
+ if ( pThis->RetType() == OBJECT_MOBILEdr )
+ {
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ pThis->SetTraceDown(FALSE);
+
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskPen(pThis->RetTraceDown(), pThis->RetTraceColor());
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+ }
+ else
+ {
+ pThis->SetTraceDown(FALSE);
+ return TRUE;
+ }
+}
+
+// Instruction "pencolor()".
+
+BOOL rPenColor(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CScript* script = ((CObject*)user)->RetRunScript();
+ CPhysics* physics = ((CObject*)user)->RetPhysics();
+ CObject* pThis = (CObject*)user;
+ int color;
+ Error err;
+
+ if ( pThis->RetType() == OBJECT_MOBILEdr )
+ {
+ exception = 0;
+
+ if ( script->m_primaryTask == 0 ) // pas de tâche en cours ?
+ {
+ color = var->GivValInt();
+ if ( color < 0 ) color = 0;
+ if ( color > 17 ) color = 17;
+ pThis->SetTraceColor(color);
+
+ script->m_primaryTask = new CTaskManager(script->m_iMan, script->m_object);
+ err = script->m_primaryTask->StartTaskPen(pThis->RetTraceDown(), pThis->RetTraceColor());
+ if ( err != ERR_OK )
+ {
+ delete script->m_primaryTask;
+ script->m_primaryTask = 0;
+ result->SetValInt(err); // indique l'erreur
+ if ( script->m_errMode == ERM_STOP )
+ {
+ exception = err;
+ return FALSE;
+ }
+ return TRUE;
+ }
+ }
+ return Process(script, result, exception);
+ }
+ else
+ {
+ color = var->GivValInt();
+ if ( color < 0 ) color = 0;
+ if ( color > 17 ) color = 17;
+ pThis->SetTraceColor(color);
+
+ return TRUE;
+ }
+}
+
+// Instruction "penwidth()".
+
+BOOL rPenWidth(CBotVar* var, CBotVar* result, int& exception, void* user)
+{
+ CObject* pThis = (CObject*)user;
+ float width;
+
+ width = var->GivValFloat();
+ if ( width < 0.1f ) width = 0.1f;
+ if ( width > 1.0f ) width = 1.0f;
+ pThis->SetTraceWidth(width);
+ return TRUE;
+}
+
+
+
+// Constructeur de l'objet.
+
+CScript::CScript(CInstanceManager* iMan, CObject* object, CTaskManager** secondaryTask)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_SCRIPT, this, 100);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_botProg = 0;
+ m_object = object;
+ m_primaryTask = 0;
+ m_secondaryTask = secondaryTask;
+
+ m_ipf = CBOT_IPF;
+ m_errMode = ERM_STOP;
+ m_len = 0;
+ m_script = 0;
+ m_bRun = FALSE;
+ m_bStepMode = FALSE;
+ m_bCompile = FALSE;
+ m_title[0] = 0;
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ m_filename[0] = 0;
+}
+
+// Initialise toutes les fonctions pour le module CBOT.
+
+void CScript::InitFonctions()
+{
+ CBotProgram::AddFunction("sin", rSin, cOneFloat);
+ CBotProgram::AddFunction("cos", rCos, cOneFloat);
+ CBotProgram::AddFunction("tan", rTan, cOneFloat);
+ CBotProgram::AddFunction("asin", raSin, cOneFloat);
+ CBotProgram::AddFunction("acos", raCos, cOneFloat);
+ CBotProgram::AddFunction("atan", raTan, cOneFloat);
+ CBotProgram::AddFunction("sqrt", rSqrt, cOneFloat);
+ CBotProgram::AddFunction("pow", rPow, cTwoFloat);
+ CBotProgram::AddFunction("rand", rRand, cNull);
+ CBotProgram::AddFunction("abs", rAbs, cOneFloat);
+
+ CBotProgram::AddFunction("retobject", rRetObject, cRetObject);
+ CBotProgram::AddFunction("search", rSearch, cSearch);
+ CBotProgram::AddFunction("radar", rRadar, cRadar);
+ CBotProgram::AddFunction("detect", rDetect, cDetect);
+ CBotProgram::AddFunction("direction", rDirection, cDirection);
+ CBotProgram::AddFunction("produce", rProduce, cProduce);
+ CBotProgram::AddFunction("distance", rDistance, cDistance);
+ CBotProgram::AddFunction("distance2d",rDistance2d,cDistance);
+ CBotProgram::AddFunction("space", rSpace, cSpace);
+ CBotProgram::AddFunction("flatground",rFlatGround,cFlatGround);
+ CBotProgram::AddFunction("wait", rWait, cOneFloat);
+ CBotProgram::AddFunction("move", rMove, cOneFloat);
+ CBotProgram::AddFunction("turn", rTurn, cOneFloat);
+ CBotProgram::AddFunction("goto", rGoto, cGoto);
+ CBotProgram::AddFunction("find", rFind, cOneFloat);
+ CBotProgram::AddFunction("grab", rGrab, cGrabDrop);
+ CBotProgram::AddFunction("drop", rDrop, cGrabDrop);
+ CBotProgram::AddFunction("sniff", rSniff, cNull);
+ CBotProgram::AddFunction("receive", rReceive, cReceive);
+ CBotProgram::AddFunction("send", rSend, cSend);
+ CBotProgram::AddFunction("deleteinfo",rDeleteInfo,cDeleteInfo);
+ CBotProgram::AddFunction("testinfo", rTestInfo, cTestInfo);
+ CBotProgram::AddFunction("thump", rThump, cNull);
+ CBotProgram::AddFunction("recycle", rRecycle, cNull);
+ CBotProgram::AddFunction("shield", rShield, cShield);
+ CBotProgram::AddFunction("fire", rFire, cFire);
+ CBotProgram::AddFunction("aim", rAim, cOneFloat);
+ CBotProgram::AddFunction("motor", rMotor, cMotor);
+ CBotProgram::AddFunction("jet", rJet, cOneFloat);
+ CBotProgram::AddFunction("topo", rTopo, cTopo);
+ CBotProgram::AddFunction("message", rMessage, cMessage);
+ CBotProgram::AddFunction("cmdline", rCmdline, cOneFloat);
+ CBotProgram::AddFunction("ismovie", rIsMovie, cNull);
+ CBotProgram::AddFunction("errmode", rErrMode, cOneFloat);
+ CBotProgram::AddFunction("ipf", rIPF, cOneFloat);
+ CBotProgram::AddFunction("abstime", rAbsTime, cNull);
+ CBotProgram::AddFunction("deletefile",rDeleteFile,cString);
+ CBotProgram::AddFunction("pendown", rPenDown, cPenDown);
+ CBotProgram::AddFunction("penup", rPenUp, cNull);
+ CBotProgram::AddFunction("pencolor", rPenColor, cOneFloat);
+ CBotProgram::AddFunction("penwidth", rPenWidth, cOneFloat);
+}
+
+// Destructeur de l'objet.
+
+CScript::~CScript()
+{
+ delete m_botProg;
+ delete m_primaryTask;
+ delete m_script;
+ m_script = 0;
+ m_len = 0;
+
+ m_iMan->DeleteInstance(CLASS_SCRIPT, this);
+}
+
+
+// Donne le script éditable à un pavé de texte.
+
+void CScript::PutScript(CEdit* edit, char* name)
+{
+ if ( m_script == 0 )
+ {
+ New(edit, name);
+ }
+ else
+ {
+ edit->SetText(m_script);
+ edit->SetCursor(m_cursor2, m_cursor1);
+ edit->ShowSelect();
+ }
+ edit->SetFocus(TRUE);
+}
+
+// Reprend le script d'un pavé de texte.
+
+BOOL CScript::GetScript(CEdit* edit)
+{
+ int len;
+
+ delete m_script;
+ m_script = 0;
+
+ len = edit->RetTextLength();
+ m_script = (char*)malloc(sizeof(char)*(len+1));
+
+ edit->GetText(m_script, len+1);
+ edit->GetCursor(m_cursor2, m_cursor1);
+ m_len = strlen(m_script);
+
+ if ( !CheckToken() )
+ {
+ edit->SetCursor(m_cursor2, m_cursor1);
+ edit->ShowSelect();
+ edit->SetFocus(TRUE);
+ return FALSE;
+ }
+
+ if ( !Compile() )
+ {
+ edit->SetCursor(m_cursor2, m_cursor1);
+ edit->ShowSelect();
+ edit->SetFocus(TRUE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Indique si un programme est correctement compilé.
+
+BOOL CScript::RetCompile()
+{
+ return m_bCompile;
+}
+
+// Indique si le programme est vide.
+
+BOOL CScript::IsEmpty()
+{
+ int i;
+
+ for ( i=0 ; i<m_len ; i++ )
+ {
+ if ( m_script[i] != ' ' &&
+ m_script[i] != '\n' ) return FALSE;
+ }
+ return TRUE;
+}
+
+// Vérifie si un programme ne contient pas les instructions interdites
+// et s'il contient bien au moins une fois toutes les instructions
+// obligatoires.
+
+BOOL CScript::CheckToken()
+{
+ CBotToken* bt;
+ CBotString bs;
+ const char* token;
+ int error, type, cursor1, cursor2, i;
+ char used[100];
+
+ if ( !m_object->RetCheckToken() ) return TRUE;
+
+ m_error = 0;
+ m_title[0] = 0;
+ m_token[0] = 0;
+ m_bCompile = FALSE;
+
+ for ( i=0 ; i<m_main->RetObligatoryToken() ; i++ )
+ {
+ used[i] = 0; // token pas utilisé
+ }
+
+ bt = CBotToken::CompileTokens(m_script, error);
+ while ( bt != 0 )
+ {
+ bs = bt->GivString();
+ token = bs;
+ type = bt->GivType();
+
+ cursor1 = bt->GivStart();
+ cursor2 = bt->GivEnd();
+
+ i = m_main->IsObligatoryToken((char*)token);
+ if ( i != -1 )
+ {
+ used[i] = 1; // token utilisé
+ }
+
+ if ( !m_main->IsProhibitedToken((char*)token) )
+ {
+ m_error = ERR_PROHIBITEDTOKEN;
+ m_cursor1 = cursor1;
+ m_cursor2 = cursor2;
+ strcpy(m_title, "<erreur>");
+ CBotToken::Delete(bt);
+ return FALSE;
+ }
+
+ bt = bt->GivNext();
+ }
+
+ // Au moins une fois chaque instruction obligatoire ?
+ for ( i=0 ; i<m_main->RetObligatoryToken() ; i++ )
+ {
+ if ( used[i] == 0 ) // token pas utilisé ?
+ {
+ strcpy(m_token, m_main->RetObligatoryToken(i));
+ m_error = ERR_OBLIGATORYTOKEN;
+ strcpy(m_title, "<erreur>");
+ CBotToken::Delete(bt);
+ return FALSE;
+ }
+ }
+
+ CBotToken::Delete(bt);
+ return TRUE;
+}
+
+// Compile le script d'un pavé de texte.
+
+BOOL CScript::Compile()
+{
+ CBotStringArray liste;
+ int i;
+ const char* p;
+
+ m_error = 0;
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ m_title[0] = 0;
+ m_bCompile = FALSE;
+
+ if ( IsEmpty() ) // programme inexistant ?
+ {
+ delete m_botProg;
+ m_botProg = 0;
+ return TRUE;
+ }
+
+ if ( m_botProg == 0 )
+ {
+ m_botProg = new CBotProgram(m_object->RetBotVar());
+ }
+
+ if ( m_botProg->Compile(m_script, liste, this) )
+ {
+ if ( liste.GivSize() == 0 )
+ {
+ strcpy(m_title, "<sans nom>");
+ }
+ else
+ {
+ p = liste[0];
+ i = 0;
+ while ( TRUE )
+ {
+ if ( p[i] == 0 || p[i] == '(' ) break;
+ if ( i >= 20 )
+ {
+ m_title[i++] = '.';
+ m_title[i++] = '.';
+ m_title[i++] = '.';
+ break;
+ }
+ m_title[i] = p[i];
+ i ++;
+ }
+ m_title[i] = 0;
+ }
+ m_bCompile = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ m_botProg->GetError(m_error, m_cursor1, m_cursor2);
+ if ( m_cursor1 < 0 || m_cursor1 > m_len ||
+ m_cursor2 < 0 || m_cursor2 > m_len )
+ {
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ }
+ if ( m_error == 0 )
+ {
+ m_cursor1 = m_cursor2 = 0;
+ }
+ strcpy(m_title, "<erreur>");
+ return FALSE;
+ }
+}
+
+
+// Retourne le titre du script.
+
+void CScript::GetTitle(char* buffer)
+{
+ strcpy(buffer, m_title);
+}
+
+
+// Choix du mode d'exécution.
+
+void CScript::SetStepMode(BOOL bStep)
+{
+ m_bStepMode = bStep;
+}
+
+
+// Lance le programme depuis le début.
+
+BOOL CScript::Run()
+{
+ if( m_botProg == 0 ) return FALSE;
+ if ( m_script == 0 || m_len == 0 ) return FALSE;
+
+ if ( !m_botProg->Start(m_title) ) return FALSE;
+
+ m_object->SetRunScript(this);
+ m_bRun = TRUE;
+ m_bContinue = FALSE;
+ m_ipf = CBOT_IPF;
+ m_errMode = ERM_STOP;
+
+ if ( m_bStepMode ) // mode step by step ?
+ {
+ Event newEvent;
+ ZeroMemory(&newEvent, sizeof(Event));
+ Step(newEvent);
+ }
+
+ return TRUE;
+}
+
+// Continue le programme en cours d'exécution.
+// Retourne TRUE lorsque l'exécution est terminée.
+
+BOOL CScript::Continue(const Event &event)
+{
+ if( m_botProg == 0 ) return TRUE;
+ if ( !m_bRun ) return TRUE;
+
+ m_event = event;
+
+ if ( m_bStepMode ) // mode step by step ?
+ {
+ if ( m_bContinue ) // instuction "move", "goto", etc. ?
+ {
+ if ( m_botProg->Run(m_object, 0) )
+ {
+ m_botProg->GetError(m_error, m_cursor1, m_cursor2);
+ if ( m_cursor1 < 0 || m_cursor1 > m_len ||
+ m_cursor2 < 0 || m_cursor2 > m_len )
+ {
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ }
+ if ( m_error == 0 )
+ {
+ m_cursor1 = m_cursor2 = 0;
+ }
+ m_bRun = FALSE;
+
+ if ( m_error != 0 && m_errMode == ERM_STOP )
+ {
+ char s[100];
+ GetError(s);
+ m_displayText->DisplayText(s, m_object, 10.0f, TT_ERROR);
+ }
+ m_engine->SetPause(TRUE); // remet la pause
+ return TRUE;
+ }
+ if ( !m_bContinue )
+ {
+ m_engine->SetPause(TRUE); // remet la pause
+ }
+ }
+
+ return FALSE;
+ }
+
+ if ( m_botProg->Run(m_object, m_ipf) )
+ {
+ m_botProg->GetError(m_error, m_cursor1, m_cursor2);
+ if ( m_cursor1 < 0 || m_cursor1 > m_len ||
+ m_cursor2 < 0 || m_cursor2 > m_len )
+ {
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ }
+ if ( m_error == 0 )
+ {
+ m_cursor1 = m_cursor2 = 0;
+ }
+ m_bRun = FALSE;
+
+ if ( m_error != 0 && m_errMode == ERM_STOP )
+ {
+ char s[100];
+ GetError(s);
+ m_displayText->DisplayText(s, m_object, 10.0f, TT_ERROR);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Continue le programme en cours d'exécution.
+// Retourne TRUE lorsque l'exécution est terminée.
+
+BOOL CScript::Step(const Event &event)
+{
+ if( m_botProg == 0 ) return TRUE;
+ if ( !m_bRun ) return TRUE;
+ if ( !m_bStepMode ) return FALSE;
+
+ m_engine->SetPause(FALSE);
+ m_engine->StepSimul(0.01f); // avance de 10ms
+ m_engine->SetPause(TRUE);
+
+ m_event = event;
+
+ if ( m_botProg->Run(m_object, 0) ) // en mode step
+ {
+ m_botProg->GetError(m_error, m_cursor1, m_cursor2);
+ if ( m_cursor1 < 0 || m_cursor1 > m_len ||
+ m_cursor2 < 0 || m_cursor2 > m_len )
+ {
+ m_cursor1 = 0;
+ m_cursor2 = 0;
+ }
+ if ( m_error == 0 )
+ {
+ m_cursor1 = m_cursor2 = 0;
+ }
+ m_bRun = FALSE;
+
+ if ( m_error != 0 && m_errMode == ERM_STOP )
+ {
+ char s[100];
+ GetError(s);
+ m_displayText->DisplayText(s, m_object, 10.0f, TT_ERROR);
+ }
+ return TRUE;
+ }
+
+ if ( m_bContinue ) // instuction "move", "goto", etc. ?
+ {
+ m_engine->SetPause(FALSE); // enlève la pause
+ }
+ return FALSE;
+}
+
+// Stoppe le programme.
+
+void CScript::Stop()
+{
+ if ( !m_bRun ) return;
+
+ if( m_botProg != 0 )
+ {
+ m_botProg->Stop();
+ }
+
+ if ( m_primaryTask != 0 )
+ {
+ m_primaryTask->Abort();
+ delete m_primaryTask;
+ m_primaryTask = 0;
+ }
+
+ m_bRun = FALSE;
+}
+
+// Indique si le programme tourne.
+
+BOOL CScript::IsRunning()
+{
+ return m_bRun;
+}
+
+// Indique si le programme continue un step.
+
+BOOL CScript::IsContinue()
+{
+ return m_bContinue;
+}
+
+
+// Donne la position des curseurs pendant l'exécution.
+
+BOOL CScript::GetCursor(int &cursor1, int &cursor2)
+{
+ const char* funcName;
+
+ cursor1 = cursor2 = 0;
+
+ if( m_botProg == 0 ) return FALSE;
+ if ( !m_bRun ) return FALSE;
+
+ m_botProg->GetRunPos(funcName, cursor1, cursor2);
+ if ( cursor1 < 0 || cursor1 > m_len ||
+ cursor2 < 0 || cursor2 > m_len )
+ {
+ cursor1 = 0;
+ cursor2 = 0;
+ }
+ return TRUE;
+}
+
+
+// Met des variables dans une liste.
+
+void PutList(char *baseName, BOOL bArray, CBotVar *var, CList *list, int &rankList)
+{
+ CBotString bs;
+ CBotVar *svar, *pStatic;
+ char varName[100];
+ char buffer[100];
+ const char *p;
+ int index, type;
+
+ if ( var == 0 && baseName[0] != 0 )
+ {
+ sprintf(buffer, "%s = null;", baseName);
+ list->SetName(rankList++, buffer);
+ return;
+ }
+
+ index = 0;
+ while ( var != 0 )
+ {
+ var->Maj(NULL, FALSE);
+ pStatic = var->GivStaticVar(); // retrouve l'élément static
+
+ bs = pStatic->GivName(); // nom de la variable
+ p = bs;
+//? if ( strcmp(p, "this") == 0 )
+//? {
+//? var = var->GivNext();
+//? continue;
+//? }
+
+ if ( baseName[0] == 0 )
+ {
+ sprintf(varName, "%s", p);
+ }
+ else
+ {
+ if ( bArray )
+ {
+ sprintf(varName, "%s[%d]", baseName, index);
+ }
+ else
+ {
+ sprintf(varName, "%s.%s", baseName, p);
+ }
+ }
+
+ type = pStatic->GivType();
+
+ if ( type < CBotTypBoolean )
+ {
+ CBotString value;
+ value = pStatic->GivValString();
+ p = value;
+ sprintf(buffer, "%s = %s;", varName, p);
+ list->SetName(rankList++, buffer);
+ }
+ else if ( type == CBotTypString )
+ {
+ CBotString value;
+ value = pStatic->GivValString();
+ p = value;
+ sprintf(buffer, "%s = \"%s\";", varName, p);
+ list->SetName(rankList++, buffer);
+ }
+ else if ( type == CBotTypArrayPointer )
+ {
+ svar = pStatic->GivItemList();
+ PutList(varName, TRUE, svar, list, rankList);
+ }
+ else if ( type == CBotTypClass ||
+ type == CBotTypPointer )
+ {
+ svar = pStatic->GivItemList();
+ PutList(varName, FALSE, svar, list, rankList);
+ }
+ else
+ {
+ sprintf(buffer, "%s = ?;", varName);
+ list->SetName(rankList++, buffer);
+ }
+
+ index ++;
+ var = var->GivNext();
+ }
+}
+
+// Rempli une liste avec les variables.
+
+void CScript::UpdateList(CList* list)
+{
+ CBotVar *var;
+ const char *progName, *funcName;
+ int total, select, level, cursor1, cursor2, rank;
+
+ if( m_botProg == 0 ) return;
+
+ total = list->RetTotal();
+ select = list->RetSelect();
+
+ list->Flush(); // vide la liste
+ m_botProg->GetRunPos(progName, cursor1, cursor2);
+ if ( progName == 0 ) return;
+
+ level = 0;
+ rank = 0;
+ while ( TRUE )
+ {
+ var = m_botProg->GivStackVars(funcName, level--);
+ if ( funcName != progName ) break;
+
+ PutList("", FALSE, var, list, rank);
+ }
+
+ if ( total == list->RetTotal() ) // même total ?
+ {
+ list->SetSelect(select);
+ }
+
+ list->SetTooltip("");
+ list->SetState(STATE_ENABLE);
+}
+
+
+// Colorise le texte selon la syntaxe.
+
+void CScript::ColorizeScript(CEdit* edit)
+{
+ CBotToken* bt;
+ CBotString bs;
+ const char* token;
+ int error, type, cursor1, cursor2, color;
+
+ edit->ClearFormat();
+
+ bt = CBotToken::CompileTokens(edit->RetText(), error);
+ while ( bt != 0 )
+ {
+ bs = bt->GivString();
+ token = bs;
+ type = bt->GivType();
+
+ cursor1 = bt->GivStart();
+ cursor2 = bt->GivEnd();
+
+ color = 0;
+ if ( type >= TokenKeyWord && type < TokenKeyWord+100 )
+ {
+ color = COLOR_TOKEN;
+ }
+ if ( type >= TokenKeyDeclare && type < TokenKeyDeclare+100 )
+ {
+ color = COLOR_TYPE;
+ }
+ if ( type >= TokenKeyVal && type < TokenKeyVal+100 )
+ {
+ color = COLOR_CONST;
+ }
+ if ( type == TokenTypVar )
+ {
+ if ( IsType(token) )
+ {
+ color = COLOR_TYPE;
+ }
+ else if ( IsFunction(token) )
+ {
+ color = COLOR_TOKEN;
+ }
+ }
+ if ( type == TokenTypDef )
+ {
+ color = COLOR_CONST;
+ }
+
+ if ( cursor1 < cursor2 && color != 0 )
+ {
+ edit->SetFormat(cursor1, cursor2, color);
+ }
+
+ bt = bt->GivNext();
+ }
+
+ CBotToken::Delete(bt);
+}
+
+
+// Cherche un token au hazard dans un script.
+// Retourne l'index du début du token trouvé, ou -1.
+
+int SearchToken(char* script, char* token)
+{
+ int lScript, lToken, i, iFound;
+ int found[100];
+ char* p;
+
+ lScript = strlen(script);
+ lToken = strlen(token);
+ iFound = 0;
+ for ( i=0 ; i<lScript-lToken ; i++ )
+ {
+ p = strstr(script+i, token);
+ if ( p != 0 )
+ {
+ found[iFound++] = p-script;
+ if ( iFound >= 100 ) break;
+ }
+ }
+
+ if ( iFound == 0 ) return -1;
+ return found[rand()%iFound];
+}
+
+// Supprime un token dans un script.
+
+void DeleteToken(char* script, int pos, int len)
+{
+ while ( TRUE )
+ {
+ script[pos] = script[pos+len];
+ if ( script[pos++] == 0 ) break;
+ }
+}
+
+// Insère un token dans un script.
+
+void InsertToken(char* script, int pos, char* token)
+{
+ int lScript, lToken, i;
+
+ lScript = strlen(script);
+ lToken = strlen(token);
+ for ( i=lScript ; i>=pos ; i-- )
+ {
+ script[i+lToken] = script[i];
+ }
+ memcpy(script+pos, token, lToken);
+}
+
+// Introduit un virus dans un programme.
+
+BOOL CScript::IntroduceVirus()
+{
+ int i, start, iFound;
+ int found[11*2];
+ char* newScript;
+
+ char* names[11*2] =
+ {
+ "==", "!=",
+ "!=", "==",
+ ">", "<",
+ "<", ">",
+ "true", "false",
+ "false", "true",
+ "grab", "drop",
+ "drop", "grab",
+ "InFront", "Behind",
+ "Behind", "EnergyCell",
+ "EnergyCell", "InFront",
+ };
+
+ iFound = 0;
+ for ( i=0 ; i<11 ; i++ )
+ {
+ start = SearchToken(m_script, names[i*2]);
+ if ( start != -1 )
+ {
+ found[iFound++] = i*2;
+ found[iFound++] = start;
+ }
+ }
+ if ( iFound == 0 ) return FALSE;
+
+ i = (rand()%(iFound/2))*2;
+ start = found[i+1];
+ i = found[i+0];
+
+ newScript = (char*)malloc(sizeof(char)*(m_len+strlen(names[i+1])+1));
+ strcpy(newScript, m_script);
+ delete m_script;
+ m_script = newScript;
+
+ DeleteToken(m_script, start, strlen(names[i]));
+ InsertToken(m_script, start, names[i+1]);
+ m_len = strlen(m_script);
+ Compile(); // recompile avec le virus
+
+ return TRUE;
+}
+
+
+// Retourne le numéro de l'erreur.
+
+int CScript::RetError()
+{
+ return m_error;
+}
+
+// Retourne le texte de l'erreur.
+
+void CScript::GetError(char* buffer)
+{
+ if ( m_error == 0 )
+ {
+ buffer[0] = 0;
+ }
+ else
+ {
+ if ( m_error == ERR_OBLIGATORYTOKEN )
+ {
+ char s[100];
+ GetResource(RES_ERR, m_error, s);
+ sprintf(buffer, s, m_token);
+ }
+ else if ( m_error < 1000 )
+ {
+ GetResource(RES_ERR, m_error, buffer);
+ }
+ else
+ {
+ GetResource(RES_CBOT, m_error, buffer);
+ }
+ }
+}
+
+
+// Nouveau programme.
+
+void CScript::New(CEdit* edit, char* name)
+{
+ FILE *file = NULL;
+ char res[100];
+ char text[100];
+ char filename[100];
+ char script[500];
+ char buffer[500];
+ char *sf;
+ int cursor1, cursor2, len, i, j;
+
+ GetResource(RES_TEXT, RT_SCRIPT_NEW, res);
+ if ( name[0] == 0 ) strcpy(text, res);
+ else strcpy(text, name);
+
+ sprintf(script, "extern void object::%s()\n{\n\t\n\t\n\t\n}\n", text);
+ edit->SetText(script, FALSE);
+
+ if ( strcmp(text, res) == 0 )
+ {
+ cursor1 = 20;
+ cursor2 = 20+strlen(text); // màj "Nouveau"
+ }
+ else
+ {
+ if ( edit->RetAutoIndent() )
+ {
+ cursor1 = 20+strlen(text)+6;
+ cursor2 = cursor1; // curseur dans { }
+ }
+ else
+ {
+ cursor1 = 20+strlen(text)+8;
+ cursor2 = cursor1; // curseur dans { }
+ }
+ }
+
+ edit->SetCursor(cursor2, cursor1);
+ edit->ShowSelect();
+ edit->SetFocus(TRUE);
+
+ sf = m_main->RetScriptFile();
+ if ( sf[0] != 0 ) // charge un programme vide spécifique ?
+ {
+ strcpy(filename, "script\\");
+ strcat(filename, sf);
+ file = fopen(filename, "rb");
+ if ( file != NULL )
+ {
+ fseek(file, 0, SEEK_END);
+ len = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ if ( len > 500-1 ) len = 500-1;
+ fread(buffer, 1, len, file);
+ buffer[len] = 0;
+ fclose(file);
+
+ cursor1 = 0;
+ i = 0;
+ j = 0;
+ while ( TRUE )
+ {
+ if ( buffer[i] == 0 ) break;
+
+ if ( buffer[i] == '\r' )
+ {
+ i ++;
+ continue;
+ }
+
+ if ( buffer[i] == '\t' && edit->RetAutoIndent() )
+ {
+ i ++;
+ continue;
+ }
+
+ if ( buffer[i+0] == '%' &&
+ buffer[i+1] == 's' )
+ {
+ strcpy(script+j, text);
+ j += strlen(text);
+ i += 2;
+ continue;
+ }
+
+ if ( buffer[i] == '#' )
+ {
+ cursor1 = j;
+ i ++;
+ continue;
+ }
+
+ script[j++] = buffer[i++];
+ }
+ script[j] = 0;
+ edit->SetText(script, FALSE);
+
+ cursor2 = cursor1;
+ edit->SetCursor(cursor2, cursor1);
+ edit->ShowSelect();
+ edit->SetFocus(TRUE);
+ }
+ }
+
+ ColorizeScript(edit);
+}
+
+
+// Fourni un script de toutes pièces.
+
+BOOL CScript::SendScript(char* text)
+{
+ m_len = strlen(text);
+ m_script = (char*)malloc(sizeof(char)*(m_len+1));
+ strcpy(m_script, text);
+ if ( !CheckToken() ) return FALSE;
+ if ( !Compile() ) return FALSE;
+
+ return TRUE;
+}
+
+// Lit un script sous la forme d'un fichier texte.
+
+BOOL CScript::ReadScript(char* filename)
+{
+ FILE* file;
+ CEdit* edit;
+ char name[100];
+
+ if ( strchr(filename, '\\') == 0 )
+ {
+ strcpy(name, "script\\");
+ strcat(name, filename);
+ }
+ else
+ {
+//? strcpy(name, filename);
+ UserDir(name, filename, "");
+ }
+
+ file = fopen(name, "rb");
+ if ( file == NULL ) return FALSE;
+ fclose(file);
+
+ delete m_script;
+ m_script = 0;
+
+ edit = m_interface->CreateEdit(FPOINT(0.0f, 0.0f), FPOINT(0.0f, 0.0f), 0, EVENT_EDIT9);
+ edit->SetMaxChar(EDITSTUDIOMAX);
+ edit->SetAutoIndent(m_engine->RetEditIndentMode());
+ edit->ReadText(name);
+ GetScript(edit);
+ m_interface->DeleteControl(EVENT_EDIT9);
+ return TRUE;
+}
+
+// Ecrit un script sous la forme d'un fichier texte.
+
+BOOL CScript::WriteScript(char* filename)
+{
+ CEdit* edit;
+ char name[100];
+
+ if ( strchr(filename, '\\') == 0 )
+ {
+ strcpy(name, "script\\");
+ strcat(name, filename);
+ }
+ else
+ {
+ strcpy(name, filename);
+ }
+
+ if ( m_script == 0 )
+ {
+ remove(filename);
+ return FALSE;
+ }
+
+ edit = m_interface->CreateEdit(FPOINT(0.0f, 0.0f), FPOINT(0.0f, 0.0f), 0, EVENT_EDIT9);
+ edit->SetMaxChar(EDITSTUDIOMAX);
+ edit->SetAutoIndent(m_engine->RetEditIndentMode());
+ edit->SetText(m_script);
+ edit->WriteText(name);
+ m_interface->DeleteControl(EVENT_EDIT9);
+ return TRUE;
+}
+
+
+// Lit un stack de script en exécution sous la forme d'un fichier.
+
+BOOL CScript::ReadStack(FILE *file)
+{
+ int nb;
+
+ fRead(&nb, sizeof(int), 1, file);
+ fRead(&m_ipf, sizeof(int), 1, file);
+ fRead(&m_errMode, sizeof(int), 1, file);
+
+ if ( m_botProg == 0 ) return FALSE;
+ if ( !m_botProg->RestoreState(file) ) return FALSE;
+
+ m_object->SetRunScript(this);
+ m_bRun = TRUE;
+ m_bContinue = FALSE;
+ return TRUE;
+}
+
+// Ecrit un stack de script en exécution sous la forme d'un fichier.
+
+BOOL CScript::WriteStack(FILE *file)
+{
+ int nb;
+
+ nb = 2;
+ fWrite(&nb, sizeof(int), 1, file);
+ fWrite(&m_ipf, sizeof(int), 1, file);
+ fWrite(&m_errMode, sizeof(int), 1, file);
+
+ return m_botProg->SaveState(file);
+}
+
+
+// Compare deux scripts.
+
+BOOL CScript::Compare(CScript* other)
+{
+ if ( m_len != other->m_len ) return FALSE;
+
+ return ( strcmp(m_script, other->m_script) == 0 );
+}
+
+
+// Gestion du nom de fichier lorsque le script est sauvegardé.
+
+void CScript::SetFilename(char *filename)
+{
+ strcpy(m_filename, filename);
+}
+
+char* CScript::RetFilename()
+{
+ return m_filename;
+}
+
diff --git a/src/script.h b/src/script.h
new file mode 100644
index 0000000..8078715
--- /dev/null
+++ b/src/script.h
@@ -0,0 +1,99 @@
+// script.h
+
+#ifndef _SCRIPT_H_
+#define _SCRIPT_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CInterface;
+class CDisplayText;
+class CEdit;
+class CList;
+class CObject;
+class CTaskManager;
+class CBotProgram;
+class CRobotMain;
+class CTerrain;
+class CWater;
+
+
+
+class CScript
+{
+public:
+ CScript(CInstanceManager* iMan, CObject* object, CTaskManager** secondaryTask);
+ ~CScript();
+
+ static void InitFonctions();
+
+ void PutScript(CEdit* edit, char* name);
+ BOOL GetScript(CEdit* edit);
+ BOOL RetCompile();
+
+ void GetTitle(char* buffer);
+
+ void SetStepMode(BOOL bStep);
+ BOOL Run();
+ BOOL Continue(const Event &event);
+ BOOL Step(const Event &event);
+ void Stop();
+ BOOL IsRunning();
+ BOOL IsContinue();
+ BOOL GetCursor(int &cursor1, int &cursor2);
+ void UpdateList(CList* list);
+ void ColorizeScript(CEdit* edit);
+ BOOL IntroduceVirus();
+
+ int RetError();
+ void GetError(char* buffer);
+
+ void New(CEdit* edit, char* name);
+ BOOL SendScript(char* text);
+ BOOL ReadScript(char* filename);
+ BOOL WriteScript(char* filename);
+ BOOL ReadStack(FILE *file);
+ BOOL WriteStack(FILE *file);
+ BOOL Compare(CScript* other);
+
+ void SetFilename(char *filename);
+ char* RetFilename();
+
+protected:
+ BOOL IsEmpty();
+ BOOL CheckToken();
+ BOOL Compile();
+
+public:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CInterface* m_interface;
+ CDisplayText* m_displayText;
+ CBotProgram* m_botProg;
+ CRobotMain* m_main;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CTaskManager* m_primaryTask;
+ CTaskManager** m_secondaryTask;
+ CObject* m_object;
+
+ int m_ipf; // nb d'instructions / seconde
+ int m_errMode; // que faire en cas d'erreur
+ int m_len; // longueur du script (sans le <0>)
+ char* m_script; // script terminé par <0>
+ BOOL m_bRun; // programme en cours d'exécution ?
+ BOOL m_bStepMode; // step by step
+ BOOL m_bContinue; // fonction externe à continuer
+ BOOL m_bCompile; // compilation ok ?
+ char m_title[50]; // titre du script
+ char m_filename[50]; // nom du fichier
+ char m_token[50]; // instruction manquante
+ int m_error; // erreur (0=ok)
+ int m_cursor1;
+ int m_cursor2;
+ Event m_event;
+ float m_returnValue;
+};
+
+
+#endif //_SCRIPT_H_
diff --git a/src/scroll.cpp b/src/scroll.cpp
new file mode 100644
index 0000000..c5a7afc
--- /dev/null
+++ b/src/scroll.cpp
@@ -0,0 +1,459 @@
+// scroll.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "button.h"
+#include "scroll.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CScroll::CScroll(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_buttonUp = 0;
+ m_buttonDown = 0;
+
+ m_visibleValue = 0.0f;
+ m_visibleRatio = 1.0f;
+ m_step = 0.0f;
+
+ m_eventUp = EVENT_NULL;
+ m_eventDown = EVENT_NULL;
+
+ m_bCapture = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CScroll::~CScroll()
+{
+ delete m_buttonUp;
+ delete m_buttonDown;
+
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CScroll::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ MoveAdjust();
+ return TRUE;
+}
+
+
+void CScroll::SetPos(FPOINT pos)
+{
+ CControl::SetPos(pos);
+ MoveAdjust();
+}
+
+void CScroll::SetDim(FPOINT dim)
+{
+ CControl::SetDim(dim);
+ MoveAdjust();
+}
+
+// Ajuste les deux boutons.
+
+void CScroll::MoveAdjust()
+{
+ CButton* pc;
+ FPOINT pos, dim;
+
+ if ( m_dim.y < m_dim.x*2.0f ) // ascenseur très court ?
+ {
+ delete m_buttonUp;
+ m_buttonUp = 0;
+
+ delete m_buttonDown;
+ m_buttonDown = 0;
+ }
+ else
+ {
+ if ( m_buttonUp == 0 )
+ {
+ m_buttonUp = new CButton(m_iMan);
+ pc = (CButton*)m_buttonUp;
+ pc->Create(FPOINT(0.0f, 0.0f), FPOINT(0.0f, 0.0f), 49, EVENT_NULL);
+ pc->SetRepeat(TRUE);
+ m_eventUp = pc->RetEventMsg();
+ }
+
+ if ( m_buttonDown == 0 )
+ {
+ m_buttonDown = new CButton(m_iMan);
+ pc = (CButton*)m_buttonDown;
+ pc->Create(FPOINT(0.0f, 0.0f), FPOINT(0.0f, 0.0f), 50, EVENT_NULL);
+ pc->SetRepeat(TRUE);
+ m_eventDown = pc->RetEventMsg();
+ }
+ }
+
+ if ( m_buttonUp != 0 )
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+m_dim.y-m_dim.x/0.75f;
+ dim.x = m_dim.x;
+ dim.y = m_dim.x/0.75f;
+ m_buttonUp->SetPos(pos);
+ m_buttonUp->SetDim(dim);
+ }
+
+ if ( m_buttonDown != 0 )
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y;
+ dim.x = m_dim.x;
+ dim.y = m_dim.x/0.75f;
+ m_buttonDown->SetPos(pos);
+ m_buttonDown->SetDim(dim);
+ }
+
+ AdjustGlint();
+}
+
+// Ajuste la position du reflet.
+
+void CScroll::AdjustGlint()
+{
+ FPOINT ref;
+ float hButton, h;
+
+ hButton = m_buttonUp?m_dim.x/0.75f:0.0f;
+ h = m_dim.y-hButton*2.0f;
+
+ ref.x = m_pos.x;
+ ref.y = m_pos.y+hButton+h*m_visibleRatio+0.003f;
+ ref.y += h*(1.0f-m_visibleRatio)*(1.0f-m_visibleValue);
+
+ GlintCreate(ref);
+}
+
+
+
+BOOL CScroll::SetState(int state, BOOL bState)
+{
+ if ( state & STATE_ENABLE )
+ {
+ if ( m_buttonUp != 0 ) m_buttonUp->SetState(state, bState);
+ if ( m_buttonDown != 0 ) m_buttonDown->SetState(state, bState);
+ }
+
+ return CControl::SetState(state, bState);
+}
+
+BOOL CScroll::SetState(int state)
+{
+ if ( state & STATE_ENABLE )
+ {
+ if ( m_buttonUp != 0 ) m_buttonUp->SetState(state);
+ if ( m_buttonDown != 0 ) m_buttonDown->SetState(state);
+ }
+
+ return CControl::SetState(state);
+}
+
+BOOL CScroll::ClearState(int state)
+{
+ if ( state & STATE_ENABLE )
+ {
+ if ( m_buttonUp != 0 ) m_buttonUp->ClearState(state);
+ if ( m_buttonDown != 0 ) m_buttonDown->ClearState(state);
+ }
+
+ return CControl::ClearState(state);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CScroll::EventProcess(const Event &event)
+{
+ FPOINT pos, dim;
+ float hButton, h, value;
+
+ CControl::EventProcess(event);
+
+ if ( m_buttonUp != 0 && !m_bCapture )
+ {
+ if ( !m_buttonUp->EventProcess(event) ) return FALSE;
+ }
+ if ( m_buttonDown != 0 && !m_bCapture )
+ {
+ if ( !m_buttonDown->EventProcess(event) ) return FALSE;
+ }
+
+ if ( event.event == m_eventUp && m_step > 0.0f )
+ {
+ m_visibleValue -= m_step;
+ if ( m_visibleValue < 0.0f ) m_visibleValue = 0.0f;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.event == m_eventDown && m_step > 0.0f )
+ {
+ m_visibleValue += m_step;
+ if ( m_visibleValue > 1.0f ) m_visibleValue = 1.0f;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+
+ hButton = m_buttonUp?m_dim.x/0.75f:0.0f;
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ pos.y = m_pos.y+hButton;
+ dim.y = m_dim.y-hButton*2.0f;
+ pos.y += dim.y*(1.0f-m_visibleRatio)*(1.0f-m_visibleValue);
+ dim.y *= m_visibleRatio;
+ if ( event.pos.y < pos.y ||
+ event.pos.y > pos.y+dim.y ) // clic hors cabine ?
+ {
+ h = (m_dim.y-hButton*2.0f)*(1.0f-m_visibleRatio);
+ value = 1.0f-(event.pos.y-(m_pos.y+hButton+dim.y*0.5f))/h;
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+ m_visibleValue = value;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+ m_bCapture = TRUE;
+ m_pressPos = event.pos;
+ m_pressValue = m_visibleValue;
+ }
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && m_bCapture )
+ {
+ h = (m_dim.y-hButton*2.0f)*(1.0f-m_visibleRatio);
+ if ( h != 0 )
+ {
+ value = m_pressValue - (event.pos.y-m_pressPos.y)/h;
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+
+ if ( value != m_visibleValue )
+ {
+ m_visibleValue = value;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONUP && m_bCapture )
+ {
+ m_bCapture = FALSE;
+ }
+
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELUP &&
+ Detect(event.pos) &&
+ m_buttonUp != 0 )
+ {
+ Event newEvent = event;
+ newEvent.event = m_buttonUp->RetEventMsg();
+ m_event->AddEvent(newEvent);
+ }
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELDOWN &&
+ Detect(event.pos) &&
+ m_buttonDown != 0 )
+ {
+ Event newEvent = event;
+ newEvent.event = m_buttonDown->RetEventMsg();
+ m_event->AddEvent(newEvent);
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CScroll::Draw()
+{
+ FPOINT pos, dim, ppos, ddim;
+ float hButton;
+ int icon, n, i;
+
+ hButton = m_buttonUp?m_dim.x/0.75f:0.0f;
+
+ // Dessine le fond.
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+hButton;
+ dim.x = m_dim.x;
+ dim.y = m_dim.y-hButton*2.0f;
+ if ( m_state & STATE_ENABLE ) icon = 0;
+ else icon = 1;
+ DrawVertex(pos, dim, icon);
+
+ // Dessine la cabine.
+ if ( m_visibleRatio < 1.0f && (m_state & STATE_ENABLE) )
+ {
+ pos.x += 0.003f; // ch'tite marge
+ pos.y += 0.003f;
+ dim.x -= 0.006f;
+ dim.y -= 0.006f;
+ pos.y += dim.y*(1.0f-m_visibleRatio)*(1.0f-m_visibleValue);
+ dim.y *= m_visibleRatio;
+ DrawVertex(pos, dim, 2);
+
+ n = (int)(dim.y*0.8f/0.012f);
+ if ( n < 1 ) n = 1;
+ if ( n > 5 ) n = 5;
+
+ ppos.x = pos.x+0.003f;
+ ppos.y = pos.y+(dim.y-(n-1)*0.012f-0.008f)/2.0f;
+ ddim.x = dim.x-0.006f;
+ ddim.y = 0.008f;
+ for ( i=0 ; i<n ; i++ )
+ {
+ DrawVertex(ppos, ddim, 3); // barre horizontale
+ ppos.y += 0.012f;
+ }
+ }
+
+ if ( m_buttonUp != 0 )
+ {
+ m_buttonUp->Draw();
+ }
+ if ( m_buttonDown != 0 )
+ {
+ m_buttonDown->Draw();
+ }
+}
+
+// Dessine un rectangle.
+
+void CScroll::DrawVertex(FPOINT pos, FPOINT dim, int icon)
+{
+ FPOINT uv1, uv2;
+ float ex, dp;
+
+ if ( icon == 0 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 0.0f/256.0f; // rectangle jaune
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 32.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ ex = 8.0f/256.0f;
+ }
+ else if ( icon == 1 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 128.0f/256.0f; // rectangle gris
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ ex = 8.0f/256.0f;
+ }
+ else if ( icon == 2 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f; // rectangle bleu
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ ex = 8.0f/256.0f;
+ }
+ else
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 104.0f/256.0f; // ligne bleu -
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 128.0f/256.0f;
+ uv2.y = 40.0f/256.0f;
+ ex = 0.0f;
+ }
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(pos, dim, uv1, uv2, ex);
+}
+
+
+void CScroll::SetVisibleValue(float value)
+{
+ if ( value < 0.0 ) value = 0.0f;
+ if ( value > 1.0 ) value = 1.0f;
+ m_visibleValue = value;
+ AdjustGlint();
+}
+
+float CScroll::RetVisibleValue()
+{
+ return m_visibleValue;
+}
+
+
+void CScroll::SetVisibleRatio(float value)
+{
+ if ( value < 0.1 ) value = 0.1f;
+ if ( value > 1.0 ) value = 1.0f;
+ m_visibleRatio = value;
+ AdjustGlint();
+}
+
+float CScroll::RetVisibleRatio()
+{
+ return m_visibleRatio;
+}
+
+
+void CScroll::SetArrowStep(float step)
+{
+ m_step = step;
+}
+
+float CScroll::RetArrowStep()
+{
+ return m_step;
+}
+
diff --git a/src/scroll.h b/src/scroll.h
new file mode 100644
index 0000000..f8cbc7b
--- /dev/null
+++ b/src/scroll.h
@@ -0,0 +1,67 @@
+// scroll.h
+
+#ifndef _SCROLL_H_
+#define _SCROLL_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CButton;
+
+
+#define SCROLL_WIDTH (15.0f/640.0f)
+
+
+
+class CScroll : public CControl
+{
+public:
+ CScroll(CInstanceManager* iMan);
+ ~CScroll();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ void SetPos(FPOINT pos);
+ void SetDim(FPOINT dim);
+
+ BOOL SetState(int state, BOOL bState);
+ BOOL SetState(int state);
+ BOOL ClearState(int state);
+
+ BOOL EventProcess(const Event &event);
+ void Draw();
+
+ void SetVisibleValue(float value);
+ float RetVisibleValue();
+
+ void SetVisibleRatio(float value);
+ float RetVisibleRatio();
+
+ void SetArrowStep(float step);
+ float RetArrowStep();
+
+protected:
+ void MoveAdjust();
+ void AdjustGlint();
+ void DrawVertex(FPOINT pos, FPOINT dim, int icon);
+
+protected:
+ CButton* m_buttonUp;
+ CButton* m_buttonDown;
+
+ float m_visibleValue;
+ float m_visibleRatio;
+ float m_step;
+
+ BOOL m_bCapture;
+ FPOINT m_pressPos;
+ float m_pressValue;
+
+ EventMsg m_eventUp;
+ EventMsg m_eventDown;
+};
+
+
+#endif //_SCROLL_H_
diff --git a/src/shortcut.cpp b/src/shortcut.cpp
new file mode 100644
index 0000000..f17b58b
--- /dev/null
+++ b/src/shortcut.cpp
@@ -0,0 +1,229 @@
+// shortcut.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "shortcut.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CShortcut::CShortcut(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+ m_time = 0.0f;
+}
+
+// Destructeur de l'objet.
+
+CShortcut::~CShortcut()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CShortcut::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CShortcut::EventProcess(const Event &event)
+{
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_FRAME )
+ {
+ m_time += event.rTime;
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CShortcut::Draw()
+{
+ float zoom;
+ int icon, mode;
+
+ icon = 0;
+ zoom = 0.8f;
+ mode = D3DSTATETTw;
+ if ( m_state & STATE_HILIGHT )
+ {
+ icon = 4;
+ zoom = 0.9f;
+ mode = D3DSTATENORMAL;
+ }
+ if ( m_state & STATE_CHECK )
+ {
+ icon = 1;
+ zoom = 0.8f;
+ mode = D3DSTATENORMAL;
+ }
+ if ( m_state & STATE_PRESS )
+ {
+ icon = 1;
+ zoom = 1.0f;
+ mode = D3DSTATENORMAL;
+ }
+ if ( m_icon == 6 || m_icon == 7 ) // pause ou film ?
+ {
+ icon = -1; // pas de fond
+ zoom = 1.0f;
+ }
+
+ m_engine->SetTexture("button3.tga");
+
+ if ( icon != -1 )
+ {
+ m_engine->SetState(mode);
+ DrawVertex(icon, 0.95f);
+ }
+
+ m_engine->SetState(D3DSTATETTb);
+ DrawVertex(m_icon, zoom);
+
+ if ( m_state & STATE_FRAME )
+ {
+ FPOINT p1, p2, c, uv1, uv2;
+ float zoom, dp;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+
+ zoom = 0.9f+sinf(m_time*8.0f)*0.1f;
+
+ p1.x = m_pos.x;
+ p1.y = m_pos.y;
+ p2.x = m_pos.x + m_dim.x;
+ p2.y = m_pos.y + m_dim.y;
+
+ c.x = (p1.x+p2.x)/2.0f;
+ c.y = (p1.y+p2.y)/2.0f; // centre
+
+ p1.x = (p1.x-c.x)*zoom + c.x;
+ p1.y = (p1.y-c.y)*zoom + c.y;
+ p2.x = (p2.x-c.x)*zoom + c.x;
+ p2.y = (p2.y-c.y)*zoom + c.y;
+
+ p2.x -= p1.x;
+ p2.y -= p1.y;
+
+ uv1.x = 176.0f/256.0f;
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 240.0f/256.0f;
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(p1, p2, uv1, uv2);
+ }
+
+ if ( (m_state & STATE_RUN) && Mod(m_time, 0.7f) >= 0.3f )
+ {
+ FPOINT uv1, uv2;
+ float dp;
+
+ m_engine->SetTexture("button3.tga");
+ m_engine->SetState(D3DSTATETTw);
+
+ uv1.x = 160.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(m_pos, m_dim, uv1, uv2);
+ }
+}
+
+// Dessine le tableau des vertex.
+
+void CShortcut::DrawVertex(int icon, float zoom)
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2, c;
+ D3DVECTOR n;
+ float u1, u2, v1, v2, dp;
+
+ device = m_engine->RetD3DDevice();
+
+ p1.x = m_pos.x;
+ p1.y = m_pos.y;
+ p2.x = m_pos.x + m_dim.x;
+ p2.y = m_pos.y + m_dim.y;
+
+ c.x = (p1.x+p2.x)/2.0f;
+ c.y = (p1.y+p2.y)/2.0f; // centre
+
+ p1.x = (p1.x-c.x)*zoom + c.x;
+ p1.y = (p1.y-c.y)*zoom + c.y;
+
+ p2.x = (p2.x-c.x)*zoom + c.x;
+ p2.y = (p2.y-c.y)*zoom + c.y;
+
+ u1 = (32.0f/256.0f)*(icon%8);
+ v1 = (32.0f/256.0f)*(icon/8); // u-v texture
+ u2 = (32.0f/256.0f)+u1;
+ v2 = (32.0f/256.0f)+v1;
+
+ dp = 0.5f/256.0f;
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+}
+
diff --git a/src/shortcut.h b/src/shortcut.h
new file mode 100644
index 0000000..bce6ee0
--- /dev/null
+++ b/src/shortcut.h
@@ -0,0 +1,34 @@
+// shortcut.h
+
+#ifndef _SHORTCUT_H_
+#define _SHORTCUT_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+
+
+
+class CShortcut : public CControl
+{
+public:
+ CShortcut(CInstanceManager* iMan);
+ ~CShortcut();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+protected:
+ void DrawVertex(int icon, float zoom);
+
+protected:
+ float m_time;
+};
+
+
+#endif //_SHORTCUT_H_
diff --git a/src/slider.cpp b/src/slider.cpp
new file mode 100644
index 0000000..6fbda72
--- /dev/null
+++ b/src/slider.cpp
@@ -0,0 +1,570 @@
+// slider.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "text.h"
+#include "button.h"
+#include "slider.h"
+
+
+
+#define CURSOR_WIDTH (10.0f/640.0f)
+#define HOLE_WIDTH (5.0f/480.0f)
+
+
+
+
+// Constructeur de l'objet.
+
+CSlider::CSlider(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+
+ m_buttonLeft = 0;
+ m_buttonRight = 0;
+
+ m_min = 0.0f;
+ m_max = 1.0f;
+ m_visibleValue = 0.0f;
+ m_step = 0.0f;
+
+ m_marginButton = 0.0f;
+ m_bHoriz = FALSE;
+
+ m_eventUp = EVENT_NULL;
+ m_eventDown = EVENT_NULL;
+
+ m_bCapture = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CSlider::~CSlider()
+{
+ delete m_buttonLeft;
+ delete m_buttonRight;
+
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CSlider::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ MoveAdjust();
+ return TRUE;
+}
+
+
+void CSlider::SetPos(FPOINT pos)
+{
+ CControl::SetPos(pos);
+ MoveAdjust();
+}
+
+void CSlider::SetDim(FPOINT dim)
+{
+ CControl::SetDim(dim);
+ MoveAdjust();
+}
+
+void CSlider::MoveAdjust()
+{
+ FPOINT pos, dim;
+
+ m_bHoriz = ( m_dim.x > m_dim.y );
+
+ if ( ( m_bHoriz && m_dim.x < m_dim.y*4.0f) ||
+ (!m_bHoriz && m_dim.y < m_dim.x*4.0f) ) // slider très court ?
+ {
+ delete m_buttonLeft;
+ m_buttonLeft = 0;
+
+ delete m_buttonRight;
+ m_buttonRight = 0;
+
+ m_marginButton = 0.0f;
+ }
+ else
+ {
+#if 1
+ if ( m_buttonLeft == 0 )
+ {
+ m_buttonLeft = new CButton(m_iMan);
+ m_buttonLeft->Create(FPOINT(0.0f, 0.0f), FPOINT(0.0f, 0.0f), m_bHoriz?55:49, EVENT_NULL); // </^
+ m_buttonLeft->SetRepeat(TRUE);
+ if ( m_state & STATE_SHADOW ) m_buttonLeft->SetState(STATE_SHADOW);
+ m_eventUp = m_buttonLeft->RetEventMsg();
+ }
+
+ if ( m_buttonRight == 0 )
+ {
+ m_buttonRight = new CButton(m_iMan);
+ m_buttonRight->Create(FPOINT(0.0f, 0.0f), FPOINT(0.0f, 0.0f), m_bHoriz?48:50, EVENT_NULL); // >/v
+ m_buttonRight->SetRepeat(TRUE);
+ if ( m_state & STATE_SHADOW ) m_buttonRight->SetState(STATE_SHADOW);
+ m_eventDown = m_buttonRight->RetEventMsg();
+ }
+
+ m_marginButton = m_bHoriz?(m_dim.y*0.75f):(m_dim.x/0.75f);
+#endif
+ }
+
+ if ( m_buttonLeft != 0 )
+ {
+ if ( m_bHoriz )
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y;
+ dim.x = m_dim.y*0.75f;
+ dim.y = m_dim.y;
+ }
+ else
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+m_dim.y-m_dim.x/0.75f;
+ dim.x = m_dim.x;
+ dim.y = m_dim.x/0.75f;
+ }
+ m_buttonLeft->SetPos(pos);
+ m_buttonLeft->SetDim(dim);
+ }
+
+ if ( m_buttonRight != 0 )
+ {
+ if ( m_bHoriz )
+ {
+ pos.x = m_pos.x+m_dim.x-m_dim.y*0.75f;
+ pos.y = m_pos.y;
+ dim.x = m_dim.y*0.75f;
+ dim.y = m_dim.y;
+ }
+ else
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y;
+ dim.x = m_dim.x;
+ dim.y = m_dim.x/0.75f;
+ }
+ m_buttonRight->SetPos(pos);
+ m_buttonRight->SetDim(dim);
+ }
+
+ AdjustGlint();
+}
+
+// Ajuste la position du reflet.
+
+void CSlider::AdjustGlint()
+{
+ FPOINT ref;
+ float w;
+
+ if ( m_bHoriz )
+ {
+ w = m_dim.x-m_marginButton*0.75f;
+ ref.x = m_pos.x+m_marginButton;
+ ref.x += (w-CURSOR_WIDTH)*m_visibleValue;
+ ref.y = m_pos.y+m_dim.y;
+ }
+ else
+ {
+ w = m_dim.y-m_marginButton*2.0f;
+ ref.y = m_pos.y+m_marginButton+CURSOR_WIDTH;
+ ref.y += (w-CURSOR_WIDTH)*m_visibleValue;
+ ref.x = m_pos.x;
+ }
+
+ GlintCreate(ref);
+}
+
+
+BOOL CSlider::SetState(int state, BOOL bState)
+{
+ if ( (state & STATE_ENABLE) ||
+ (state & STATE_SHADOW) )
+ {
+ if ( m_buttonLeft != 0 ) m_buttonLeft->SetState(state, bState);
+ if ( m_buttonRight != 0 ) m_buttonRight->SetState(state, bState);
+ }
+
+ return CControl::SetState(state, bState);
+}
+
+BOOL CSlider::SetState(int state)
+{
+ if ( (state & STATE_ENABLE) ||
+ (state & STATE_SHADOW) )
+ {
+ if ( m_buttonLeft != 0 ) m_buttonLeft->SetState(state);
+ if ( m_buttonRight != 0 ) m_buttonRight->SetState(state);
+ }
+
+ return CControl::SetState(state);
+}
+
+BOOL CSlider::ClearState(int state)
+{
+ if ( (state & STATE_ENABLE) ||
+ (state & STATE_SHADOW) )
+ {
+ if ( m_buttonLeft != 0 ) m_buttonLeft->ClearState(state);
+ if ( m_buttonRight != 0 ) m_buttonRight->ClearState(state);
+ }
+
+ return CControl::ClearState(state);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CSlider::EventProcess(const Event &event)
+{
+ FPOINT pos, dim;
+ float value;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( m_buttonLeft != 0 && !m_bCapture )
+ {
+ if ( !m_buttonLeft->EventProcess(event) ) return FALSE;
+ }
+ if ( m_buttonRight != 0 && !m_bCapture )
+ {
+ if ( !m_buttonRight->EventProcess(event) ) return FALSE;
+ }
+
+ if ( event.event == m_eventUp && m_step > 0.0f )
+ {
+ m_visibleValue -= m_bHoriz?m_step:-m_step;
+ if ( m_visibleValue < 0.0f ) m_visibleValue = 0.0f;
+ if ( m_visibleValue > 1.0f ) m_visibleValue = 1.0f;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.event == m_eventDown && m_step > 0.0f )
+ {
+ m_visibleValue += m_bHoriz?m_step:-m_step;
+ if ( m_visibleValue < 0.0f ) m_visibleValue = 0.0f;
+ if ( m_visibleValue > 1.0f ) m_visibleValue = 1.0f;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ if ( m_bHoriz )
+ {
+ pos.x = m_pos.x+m_marginButton;
+ dim.x = m_dim.x-m_marginButton*2.0f;
+ value = (event.pos.x-pos.x-CURSOR_WIDTH/2.0f);
+ value /= (dim.x-CURSOR_WIDTH);
+ }
+ else
+ {
+ pos.y = m_pos.y+m_marginButton;
+ dim.y = m_dim.y-m_marginButton*2.0f;
+ value = (event.pos.y-pos.y-CURSOR_WIDTH/2.0f);
+ value /= (dim.y-CURSOR_WIDTH);
+ }
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+ m_visibleValue = value;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+
+ m_bCapture = TRUE;
+ m_pressPos = event.pos;
+ m_pressValue = m_visibleValue;
+ }
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && m_bCapture )
+ {
+ if ( m_bHoriz )
+ {
+ pos.x = m_pos.x+m_marginButton;
+ dim.x = m_dim.x-m_marginButton*2.0f;
+ value = (event.pos.x-pos.x-CURSOR_WIDTH/2.0f);
+ value /= (dim.x-CURSOR_WIDTH);
+ }
+ else
+ {
+ pos.y = m_pos.y+m_marginButton;
+ dim.y = m_dim.y-m_marginButton*2.0f;
+ value = (event.pos.y-pos.y-CURSOR_WIDTH/2.0f);
+ value /= (dim.y-CURSOR_WIDTH);
+ }
+ if ( value < 0.0f ) value = 0.0f;
+ if ( value > 1.0f ) value = 1.0f;
+
+ if ( value != m_visibleValue )
+ {
+ m_visibleValue = value;
+ AdjustGlint();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONUP && m_bCapture )
+ {
+ m_bCapture = FALSE;
+ }
+
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELUP &&
+ Detect(event.pos) &&
+ m_buttonLeft != 0 )
+ {
+ Event newEvent = event;
+ newEvent.event = m_buttonLeft->RetEventMsg();
+ m_event->AddEvent(newEvent);
+ }
+ if ( event.event == EVENT_KEYDOWN &&
+ event.param == VK_WHEELDOWN &&
+ Detect(event.pos) &&
+ m_buttonRight != 0 )
+ {
+ Event newEvent = event;
+ newEvent.event = m_buttonRight->RetEventMsg();
+ m_event->AddEvent(newEvent);
+ }
+
+ return TRUE;
+}
+
+
+// Dessine le bouton.
+
+void CSlider::Draw()
+{
+ FPOINT pos, dim, ppos, ddim, spos;
+ int icon;
+ float h;
+ char text[100];
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_buttonLeft != 0 )
+ {
+ m_buttonLeft->Draw();
+ }
+
+ if ( m_bHoriz )
+ {
+ pos.x = m_pos.x+m_marginButton;
+ pos.y = m_pos.y;
+ dim.x = m_dim.x-m_marginButton*2.0f;
+ dim.y = m_dim.y;
+ }
+ else
+ {
+ pos.x = m_pos.x;
+ pos.y = m_pos.y+m_marginButton;
+ dim.x = m_dim.x;
+ dim.y = m_dim.y-m_marginButton*2.0f;
+ }
+
+ // Dessine le fond.
+ if ( m_bHoriz )
+ {
+ ppos.x = pos.x + CURSOR_WIDTH/2.0f;
+ ppos.y = pos.y + (dim.y-HOLE_WIDTH)/2.0f;
+ ddim.x = dim.x - CURSOR_WIDTH;
+ ddim.y = HOLE_WIDTH;
+ }
+ else
+ {
+ ppos.x = pos.x + (dim.x-HOLE_WIDTH*0.75f)/2.0f;
+ ppos.y = pos.y + CURSOR_WIDTH/2.0f;
+ ddim.x = HOLE_WIDTH*0.75f;
+ ddim.y = dim.y - CURSOR_WIDTH;
+ }
+
+ if ( m_state & STATE_SHADOW )
+ {
+ spos = ppos;
+ spos.x -= 0.005f*0.75f;
+ spos.y += 0.005f;
+ DrawShadow(spos, ddim);
+ }
+
+ if ( m_state & STATE_ENABLE ) icon = 0;
+ else icon = 1;
+ DrawVertex(ppos, ddim, icon);
+
+ // Dessine la cabine.
+ if ( m_state & STATE_ENABLE )
+ {
+ if ( m_bHoriz )
+ {
+ ppos.x = pos.x + (dim.x-CURSOR_WIDTH)*m_visibleValue;
+ ppos.y = pos.y;
+ ddim.x = CURSOR_WIDTH;
+ ddim.y = dim.y;
+ }
+ else
+ {
+ ppos.x = pos.x;
+ ppos.y = pos.y + (dim.y-CURSOR_WIDTH)*m_visibleValue;
+ ddim.x = dim.x;
+ ddim.y = CURSOR_WIDTH;
+ }
+ DrawShadow(ppos, ddim, 0.7f);
+ DrawVertex(ppos, ddim, 2);
+ }
+
+ if ( m_buttonRight != 0 )
+ {
+ m_buttonRight->Draw();
+ }
+
+ if ( m_bHoriz )
+ {
+ sprintf(text, "%d", (int)(m_min+m_visibleValue*(m_max-m_min)));
+ h = m_engine->RetText()->RetHeight(m_fontSize, m_fontType);
+ pos.x = m_pos.x+m_dim.x+(10.0f/640.0f);
+ pos.y = m_pos.y+(m_dim.y-h)/2.0f;
+ m_engine->RetText()->DrawText(text, pos, m_dim.x, 1, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ else
+ {
+ if ( m_state & STATE_VALUE )
+ {
+ pos.x = m_pos.x+m_dim.x+4.0f/640.0f;
+ h = m_dim.y-m_marginButton*2.0f;
+ pos.y = m_pos.y+m_marginButton-4.0f/480.0f;
+ pos.y += (h-CURSOR_WIDTH)*m_visibleValue;
+ dim.x = 50.0f/640.0f;
+ dim.y = 16.0f/480.0f;
+ sprintf(text, "%d", (int)(m_min+(m_visibleValue*(m_max-m_min))));
+ m_engine->RetText()->DrawText(text, pos, dim.x, 1, m_fontSize, m_fontStretch, m_fontType, 0);
+ }
+ }
+}
+
+// Dessine un rectangle.
+
+void CSlider::DrawVertex(FPOINT pos, FPOINT dim, int icon)
+{
+ FPOINT uv1, uv2, corner;
+ float ex, dp;
+
+ if ( icon == 0 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 0.0f/256.0f; // rectangle jaune
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 32.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ corner.x = 2.0f/640.0f;
+ corner.y = 2.0f/480.0f;
+ ex = 4.0f/256.0f;
+ }
+ else if ( icon == 1 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 128.0f/256.0f; // rectangle gris
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ corner.x = 2.0f/640.0f;
+ corner.y = 2.0f/480.0f;
+ ex = 4.0f/256.0f;
+ }
+ else
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 224.0f/256.0f; // curseur
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 256.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ if ( !m_bHoriz )
+ {
+ uv1.y += 64.0f/256.0f;
+ uv2.y += 64.0f/256.0f;
+ }
+ corner.x = 2.0f/640.0f;
+ corner.y = 2.0f/480.0f;
+ ex = 4.0f/256.0f;
+ }
+
+ dp = 0.5f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ DrawIcon(pos, dim, uv1, uv2, corner, ex);
+}
+
+
+void CSlider::SetLimit(float min, float max)
+{
+ m_min = min;
+ m_max = max;
+}
+
+void CSlider::SetVisibleValue(float value)
+{
+ value = (value-m_min)/(m_max-m_min);
+ if ( value < 0.0 ) value = 0.0f;
+ if ( value > 1.0 ) value = 1.0f;
+ m_visibleValue = value;
+ AdjustGlint();
+}
+
+float CSlider::RetVisibleValue()
+{
+ return m_min+m_visibleValue*(m_max-m_min);
+}
+
+
+void CSlider::SetArrowStep(float step)
+{
+ m_step = step/(m_max-m_min);
+}
+
+float CSlider::RetArrowStep()
+{
+ return m_step*(m_max-m_min);
+}
+
+
diff --git a/src/slider.h b/src/slider.h
new file mode 100644
index 0000000..eea3070
--- /dev/null
+++ b/src/slider.h
@@ -0,0 +1,67 @@
+// slider.h
+
+#ifndef _SLIDER_H_
+#define _SLIDER_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CButton;
+
+
+
+class CSlider : public CControl
+{
+public:
+ CSlider(CInstanceManager* iMan);
+ ~CSlider();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ void SetPos(FPOINT pos);
+ void SetDim(FPOINT dim);
+
+ BOOL SetState(int state, BOOL bState);
+ BOOL SetState(int state);
+ BOOL ClearState(int state);
+
+ BOOL EventProcess(const Event &event);
+ void Draw();
+
+ void SetLimit(float min, float max);
+
+ void SetVisibleValue(float value);
+ float RetVisibleValue();
+
+ void SetArrowStep(float step);
+ float RetArrowStep();
+
+protected:
+ void MoveAdjust();
+ void AdjustGlint();
+ void DrawVertex(FPOINT pos, FPOINT dim, int icon);
+
+protected:
+ CButton* m_buttonLeft;
+ CButton* m_buttonRight;
+
+ float m_min;
+ float m_max;
+ float m_visibleValue;
+ float m_step;
+
+ BOOL m_bHoriz;
+ float m_marginButton;
+
+ BOOL m_bCapture;
+ FPOINT m_pressPos;
+ float m_pressValue;
+
+ EventMsg m_eventUp;
+ EventMsg m_eventDown;
+};
+
+
+#endif //_SLIDER_H_
diff --git a/src/sound.cpp b/src/sound.cpp
new file mode 100644
index 0000000..ac06e14
--- /dev/null
+++ b/src/sound.cpp
@@ -0,0 +1,1640 @@
+// sound.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <dsound.h>
+#include <stdio.h>
+#include "language.h"
+#include "struct.h"
+#include "iman.h"
+#include "math3d.h"
+#include "sound.h"
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+#define LXIMAGE 640
+#define LYIMAGE 480
+
+
+
+// Header .WAV file.
+
+struct WaveHeader
+{
+ BYTE RIFF[4]; // "RIFF"
+ DWORD dwSize; // size of data to follow
+ BYTE WAVE[4]; // "WAVE"
+ BYTE fmt_[4]; // "fmt "
+ DWORD dw16; // 16
+ WORD wOne_0; // 1
+ WORD wChnls; // number of Channels
+ DWORD dwSRate; // sample Rate
+ DWORD BytesPerSec; // sample Rate
+ WORD wBlkAlign; // 1
+ WORD BitsPerSample; // sample size
+ BYTE DATA[4]; // "DATA"
+ DWORD dwDSize; // number of Samples
+};
+
+
+
+
+// Affiche une erreur DirectSound.
+
+void DisplayError(char *name, Sound sound, HRESULT err)
+{
+ char s[100];
+ unsigned int i = err;
+ if ( err == DS_OK ) return;
+ sprintf(s, "SoundError in %s, sound=%d err=%d\n", name, sound, i);
+ OutputDebugString(s);
+
+ if ( err == DSERR_ALLOCATED ) OutputDebugString("DSERR_ALLOCATED\n");
+ if ( err == DSERR_CONTROLUNAVAIL ) OutputDebugString("DSERR_CONTROLUNAVAIL\n");
+ if ( err == DSERR_INVALIDPARAM ) OutputDebugString("DSERR_INVALIDPARAM\n");
+ if ( err == DSERR_INVALIDCALL ) OutputDebugString("DSERR_INVALIDCALL\n");
+ if ( err == DSERR_GENERIC ) OutputDebugString("DSERR_GENERIC\n");
+ if ( err == DSERR_PRIOLEVELNEEDED ) OutputDebugString("DSERR_PRIOLEVELNEEDED\n");
+ if ( err == DSERR_OUTOFMEMORY ) OutputDebugString("DSERR_OUTOFMEMORY\n");
+ if ( err == DSERR_BADFORMAT ) OutputDebugString("DSERR_BADFORMAT\n");
+ if ( err == DSERR_UNSUPPORTED ) OutputDebugString("DSERR_UNSUPPORTED\n");
+ if ( err == DSERR_NODRIVER ) OutputDebugString("DSERR_NODRIVER\n");
+ if ( err == DSERR_ALREADYINITIALIZED ) OutputDebugString("DSERR_ALREADYINITIALIZED\n");
+ if ( err == DSERR_NOAGGREGATION ) OutputDebugString("DSERR_NOAGGREGATION\n");
+ if ( err == DSERR_BUFFERLOST ) OutputDebugString("DSERR_BUFFERLOST\n");
+ if ( err == DSERR_OTHERAPPHASPRIO ) OutputDebugString("DSERR_OTHERAPPHASPRIO\n");
+ if ( err == DSERR_UNINITIALIZED ) OutputDebugString("DSERR_UNINITIALIZED\n");
+ if ( err == DSERR_NOINTERFACE ) OutputDebugString("DSERR_NOINTERFACE\n");
+ if ( err == DSERR_ACCESSDENIED ) OutputDebugString("DSERR_ACCESSDENIED\n");
+}
+
+// Retourne le nom de dossier en cours.
+
+void GetCurrentDir(char *pName, int lg)
+{
+ int i;
+
+ strncpy(pName, _pgmptr, lg-1);
+ pName[lg-1] = 0;
+
+ lg = strlen(pName);
+ if ( lg == 0 ) return;
+
+ for ( i=0 ; i<lg ; i++ )
+ {
+ pName[i] = tolower(pName[i]);
+ }
+
+ while ( lg > 0 )
+ {
+ lg --;
+ if ( pName[lg] == '\\' )
+ {
+ pName[lg+1] = 0;
+ break;
+ }
+ }
+
+ if ( lg > 6 && strcmp(pName+lg-6, "\\debug\\") == 0 )
+ {
+ pName[lg-5] = 0; // ignore le dossier \debug !
+ }
+
+ if ( lg > 6 && strcmp(pName+lg-6, "\\release\\") == 0 )
+ {
+ pName[lg-7] = 0; // ignore le dossier \release !
+ }
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+// Modifie le volume midi.
+// Le volume est compris entre 0 et 20 !
+
+void InitMidiVolume(int volume)
+{
+ int nb, i, n;
+ MMRESULT result;
+ HMIDIOUT hmo = 0;
+
+ static int table[21] =
+ {
+ 0x00000000,
+ 0x11111111,
+ 0x22222222,
+ 0x33333333,
+ 0x44444444,
+ 0x55555555,
+ 0x66666666,
+ 0x77777777,
+ 0x88888888,
+ 0x99999999,
+ 0xAAAAAAAA,
+ 0xBBBBBBBB,
+ 0xCCCCCCCC,
+ 0xDDDDDDDD,
+ 0xEEEEEEEE,
+ 0xF222F222,
+ 0xF555F555,
+ 0xF777F777,
+ 0xFAAAFAAA,
+ 0xFDDDFDDD,
+ 0xFFFFFFFF,
+ };
+
+ if ( volume < 0 ) volume = 0;
+ if ( volume > MAXVOLUME ) volume = MAXVOLUME;
+
+ nb = midiOutGetNumDevs();
+ for ( i=0 ; i<nb ; i++ )
+ {
+ result = midiOutOpen((LPHMIDIOUT)&hmo, i, 0L, 0L, 0L);
+ if ( result != MMSYSERR_NOERROR )
+ {
+ continue;
+ }
+
+ result = midiOutSetVolume(hmo, table[volume]);
+ if ( result != MMSYSERR_NOERROR )
+ {
+ n = 1;
+ }
+ midiOutClose(hmo);
+ hmo = 0;
+ }
+}
+
+// Modifie le volume CD audio.
+// Le volume est compris entre 0 et 20 !
+// Plantait sous Vista. Le bricolage actuel (si _SOUNDTRACKS = TRUE) ne plante
+// plus, mais ce n'est pas le bon volume qui est modifié !
+
+BOOL InitAudioTrackVolume(int volume)
+{
+#if _SOUNDTRACKS
+ MMRESULT rc; // Return code.
+ HMIXER hMixer; // Mixer handle used in mixer API calls.
+ MIXERCONTROL mxc; // Holds the mixer control data.
+ MIXERLINE mxl; // Holds the mixer line data.
+ MIXERLINECONTROLS mxlc; // Obtains the mixer control.
+
+ if ( volume < 0 ) volume = 0;
+ if ( volume > MAXVOLUME ) volume = MAXVOLUME;
+
+ // Open the mixer. This opens the mixer with a deviceID of 0. If you
+ // have a single sound card/mixer, then this will open it. If you have
+ // multiple sound cards/mixers, the deviceIDs will be 0, 1, 2, and
+ // so on.
+ rc = mixerOpen(&hMixer, 0,0,0,0);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return FALSE; // Couldn't open the mixer.
+ }
+
+ // Initialize MIXERLINE structure.
+ ZeroMemory(&mxl,sizeof(mxl));
+ mxl.cbStruct = sizeof(mxl);
+
+ // Specify the line you want to get. You are getting the input line
+ // here. If you want to get the output line, you need to use
+ // MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT.
+ mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
+
+ rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl,
+ MIXER_GETLINEINFOF_COMPONENTTYPE);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return FALSE; // Couldn't get the mixer line.
+ }
+
+ // Get the control.
+ ZeroMemory(&mxlc, sizeof(mxlc));
+ mxlc.cbStruct = sizeof(mxlc);
+ mxlc.dwLineID = mxl.dwLineID;
+//? mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER;
+//? mxlc.dwControlType = MIXERCONTROL_CONTROLF_UNIFORM;
+ mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
+ mxlc.cControls = 1;
+ mxlc.cbmxctrl = sizeof(mxc);
+ mxlc.pamxctrl = &mxc;
+ ZeroMemory(&mxc, sizeof(mxc));
+ mxc.cbStruct = sizeof(mxc);
+ rc = mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc,
+ MIXER_GETLINECONTROLSF_ONEBYTYPE);
+//? MIXER_GETLINECONTROLSF_ALL);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return FALSE; // Couldn't get the control.
+ }
+
+ // After successfully getting the peakmeter control, the volume range
+ // will be specified by mxc.Bounds.lMinimum to mxc.Bounds.lMaximum.
+
+ MIXERCONTROLDETAILS mxcd; // Gets the control values.
+ MIXERCONTROLDETAILS_SIGNED volStruct; // Gets the control values.
+
+ volStruct.lValue = volume*(mxc.Bounds.lMaximum-mxc.Bounds.lMinimum);
+ volStruct.lValue /= MAXVOLUME;
+ volStruct.lValue += mxc.Bounds.lMinimum;
+
+ // Initialize the MIXERCONTROLDETAILS structure
+ ZeroMemory(&mxcd, sizeof(mxcd));
+ mxcd.cbStruct = sizeof(mxcd);
+ mxcd.cbDetails = sizeof(volStruct);
+ mxcd.dwControlID = mxc.dwControlID;
+ mxcd.paDetails = &volStruct;
+ mxcd.cChannels = 1;
+
+ // Get the current value of the peakmeter control. Typically, you
+ // would set a timer in your program to query the volume every 10th
+ // of a second or so.
+ rc = mixerSetControlDetails((HMIXEROBJ)hMixer, &mxcd,
+ MIXER_SETCONTROLDETAILSF_VALUE);
+ if ( rc != MMSYSERR_NOERROR )
+ {
+ return FALSE; // Couldn't get the current volume.
+ }
+#endif
+
+ return TRUE;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+// Constructeur.
+
+CSound::CSound(CInstanceManager* iMan)
+{
+ int i;
+
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_SOUND, this);
+
+ m_bEnable = FALSE;
+ m_bState = FALSE;
+ m_bAudioTrack = TRUE;
+ m_ctrl3D = TRUE;
+ m_bDebugMode = FALSE;
+ m_MidiDeviceID = 0;
+ m_MIDIMusic = 0;
+ m_audioVolume = 20;
+ m_midiVolume = 15;
+ m_lastMidiVolume = 0;
+ m_listener = 0;
+ m_lastTime = 0.0f;
+ m_playTime = 0.0f;
+ m_uniqueStamp = 0;
+ m_maxSound = MAXSOUND;
+ m_eye = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_hWnd = 0;
+
+ m_lpDS = NULL;
+
+ ZeroMemory(m_channel, sizeof(SoundChannel)*MAXSOUND);
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ m_channel[i].bUsed = FALSE;
+ }
+
+ for ( i=0 ; i<MAXFILES ; i++ )
+ {
+ m_files[i] = 0;
+ }
+}
+
+// Destructeur.
+
+CSound::~CSound()
+{
+ int i;
+
+ if ( m_bEnable )
+ {
+ InitMidiVolume(15); // remet un volume moyen !
+ InitAudioTrackVolume(15); // remet un volume moyen !
+ }
+
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ if ( m_channel[i].bUsed )
+ {
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].bUsed = FALSE;
+ }
+ }
+
+ if ( m_listener != NULL )
+ {
+ m_listener->Release();
+ m_listener = NULL;
+ }
+
+ if ( m_lpDS != NULL )
+ {
+ m_lpDS->Release();
+ m_lpDS = NULL;
+ }
+}
+
+
+// Spécifie si on est en mode debug.
+
+void CSound::SetDebugMode(BOOL bMode)
+{
+ m_bDebugMode = bMode;
+}
+
+
+// Initialisation de DirectSound.
+
+BOOL CSound::Create(HWND hWnd, BOOL b3D)
+{
+ LPDIRECTSOUNDBUFFER primary;
+ DSBUFFERDESC dsbdesc;
+ DSCAPS dscaps;
+ WAVEFORMATEX wfx;
+ HRESULT hr;
+
+ if ( !DirectSoundCreate(NULL, &m_lpDS, NULL) == DS_OK )
+ {
+ OutputDebugString("Fatal error: DirectSoundCreate\n");
+ m_bEnable = FALSE;
+ return FALSE;
+ }
+
+//? m_lpDS->SetCooperativeLevel(hWnd, DSSCL_NORMAL);
+ m_lpDS->SetCooperativeLevel(hWnd, DSSCL_PRIORITY);
+
+ if ( !RetSound3DCap() ) b3D = FALSE;
+
+ m_ctrl3D = FALSE;
+ if ( b3D )
+ {
+ // Obtain primary buffer, asking it for 3D control.
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
+ hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL );
+ if ( hr == S_OK )
+ {
+ m_ctrl3D = TRUE;
+ }
+ }
+
+ if ( !m_ctrl3D )
+ {
+ // Obtain primary buffer, without 3D control.
+ ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
+ hr = m_lpDS->CreateSoundBuffer( &dsbdesc, &primary, NULL );
+ if ( hr != S_OK )
+ {
+ return FALSE;
+ }
+ m_ctrl3D = FALSE;
+ }
+
+ if ( m_ctrl3D )
+ {
+ hr = primary->QueryInterface( IID_IDirectSound3DListener,
+ (VOID**)&m_listener );
+ if ( hr != S_OK )
+ {
+ primary->Release();
+ return FALSE;
+ }
+ }
+
+ // Set primary buffer format to 44kHz and 16-bit output.
+ ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nChannels = 2;
+ wfx.nSamplesPerSec = 22050;
+//? wfx.nSamplesPerSec = 44100;
+ wfx.wBitsPerSample = 16;
+ wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
+ hr = primary->SetFormat(&wfx);
+ if ( hr != S_OK )
+ {
+ DisplayError("SetFormat", SOUND_CLICK, hr);
+ }
+
+ // Release the primary buffer, since it is not need anymore.
+ primary->Release();
+
+ // Search the maximum possible voices.
+ if ( m_ctrl3D )
+ {
+ ZeroMemory( &dscaps, sizeof(DSCAPS) );
+ dscaps.dwSize = sizeof(DSCAPS);
+ hr = m_lpDS->GetCaps(&dscaps);
+ if ( hr == DS_OK )
+ {
+ m_maxSound = dscaps.dwMaxHwMixingAllBuffers;
+ if ( dscaps.dwMaxHw3DAllBuffers > 0 &&
+ m_maxSound > (int)dscaps.dwMaxHw3DAllBuffers )
+ {
+ m_maxSound = dscaps.dwMaxHw3DAllBuffers;
+ }
+ if ( m_maxSound > MAXSOUND ) m_maxSound = MAXSOUND;
+ }
+ }
+
+ m_bEnable = TRUE;
+ m_hWnd = hWnd;
+ return TRUE;
+}
+
+
+// Indique s'il faut jouer les sons en 3D ou pas.
+
+void CSound::SetSound3D(BOOL bMode)
+{
+ StopAll();
+
+ if ( m_listener != NULL )
+ {
+ m_listener->Release();
+ m_listener = NULL;
+ }
+
+ if ( m_lpDS != NULL )
+ {
+ m_lpDS->Release();
+ m_lpDS = NULL;
+ }
+
+ Create(m_hWnd, bMode);
+}
+
+BOOL CSound::RetSound3D()
+{
+ return m_ctrl3D;
+}
+
+// Indique s'il est possible de jouer les sons en 3D.
+
+BOOL CSound::RetSound3DCap()
+{
+ DSCAPS dscaps;
+ HRESULT hr;
+
+ ZeroMemory( &dscaps, sizeof(DSCAPS) );
+ dscaps.dwSize = sizeof(DSCAPS);
+ hr = m_lpDS->GetCaps(&dscaps);
+ if ( hr != DS_OK ) return FALSE;
+
+ return ( dscaps.dwMaxHw3DAllBuffers > 0 );
+}
+
+
+
+// Retourne l'état de DirectSound.
+
+BOOL CSound::RetEnable()
+{
+ return m_bEnable;
+}
+
+
+// Enclenche ou déclenche le son.
+
+void CSound::SetState(BOOL bState)
+{
+ m_bState = bState;
+}
+
+// Spécifie le chamin d'accès au CD.
+
+void CSound::SetCDpath(char *path)
+{
+ strcpy(m_CDpath, path);
+}
+
+// Enclenche ou déclenche les musiques CD-audio.
+
+void CSound::SetAudioTrack(BOOL bAudio)
+{
+ m_bAudioTrack = bAudio;
+}
+
+
+// Gestion des volumes audio (.wav) et midi (.mid).
+
+void CSound::SetAudioVolume(int volume)
+{
+ m_audioVolume = volume;
+}
+
+int CSound::RetAudioVolume()
+{
+ if ( !m_bEnable ) return 0;
+ return m_audioVolume;
+}
+
+void CSound::SetMidiVolume(int volume)
+{
+ m_midiVolume = volume;
+
+ if ( m_bAudioTrack )
+ {
+ InitAudioTrackVolume(m_midiVolume);
+ }
+}
+
+int CSound::RetMidiVolume()
+{
+ if ( !m_bEnable ) return 0;
+ return m_midiVolume;
+}
+
+
+// Lit un fichier.
+
+BOOL CSound::ReadFile(Sound sound, char *metaname, char *filename)
+{
+ WaveHeader wavHdr;
+ DWORD size;
+ int err;
+
+ // Open the wave file.
+ err = g_metafile.Open(metaname, filename);
+ if ( err != 0 ) return FALSE;
+
+ // Read in the wave header.
+ g_metafile.Read(&wavHdr, sizeof(wavHdr));
+
+ // Figure out the size of the data region.
+ size = wavHdr.dwDSize;
+
+ if ( m_files[sound] != 0 )
+ {
+ free(m_files[sound]);
+ }
+ m_files[sound] = (char*)malloc(sizeof(WaveHeader)+size);
+
+ memcpy(m_files[sound], &wavHdr, sizeof(WaveHeader));
+ g_metafile.Read(m_files[sound]+sizeof(WaveHeader), size);
+
+ // Close out the wave file.
+ g_metafile.Close();
+ return TRUE;
+}
+
+// Cache tous les ficheirs son (.wav).
+
+void CSound::CacheAll()
+{
+ int i;
+ char meta[50];
+ char name[50];
+
+ if ( !m_bEnable ) return;
+
+ if ( m_bDebugMode )
+ {
+ strcpy(meta, "");
+ }
+ else
+ {
+#if _SCHOOL
+ strcpy(meta, "ceebot3.dat");
+#else
+ strcpy(meta, "colobot3.dat");
+#endif
+ }
+
+ for ( i=0 ; i<MAXFILES ; i++ )
+ {
+ if ( m_bDebugMode )
+ {
+ sprintf(name, "sound\\sound%.3d.wav", i);
+ }
+ else
+ {
+ sprintf(name, "sound%.3d.wav", i);
+ }
+ if ( !ReadFile((Sound)i, meta, name) ) break;
+ }
+}
+
+
+// Retourne la priorité d'un son.
+// Plus la valeur est grande et plus le son est important.
+
+int CSound::RetPriority(Sound sound)
+{
+ if ( sound == SOUND_FLYh ||
+ sound == SOUND_FLY ||
+ sound == SOUND_MOTORw ||
+ sound == SOUND_MOTORt ||
+ sound == SOUND_MOTORr ||
+ sound == SOUND_MOTORs ||
+ sound == SOUND_SLIDE ||
+ sound == SOUND_ERROR )
+ {
+ return 30;
+ }
+
+ if ( sound == SOUND_CONVERT ||
+ sound == SOUND_ENERGY ||
+ sound == SOUND_DERRICK ||
+ sound == SOUND_STATION ||
+ sound == SOUND_REPAIR ||
+ sound == SOUND_RESEARCH ||
+ sound == SOUND_BURN ||
+ sound == SOUND_BUILD ||
+ sound == SOUND_TREMBLE ||
+ sound == SOUND_NUCLEAR ||
+ sound == SOUND_EXPLO ||
+ sound == SOUND_EXPLOl ||
+ sound == SOUND_EXPLOlp ||
+ sound == SOUND_EXPLOp ||
+ sound == SOUND_EXPLOi )
+ {
+ return 20;
+ }
+
+ if ( sound == SOUND_BLUP ||
+ sound == SOUND_INSECTs ||
+ sound == SOUND_INSECTa ||
+ sound == SOUND_INSECTb ||
+ sound == SOUND_INSECTw ||
+ sound == SOUND_INSECTm ||
+ sound == SOUND_PSHHH ||
+ sound == SOUND_EGG )
+ {
+ return 0;
+ }
+
+ return 10;
+}
+
+// Cherche un buffer libre.
+
+BOOL CSound::SearchFreeBuffer(Sound sound, int &channel, BOOL &bAlreadyLoaded)
+{
+ DWORD status;
+ int i, priority;
+
+ priority = RetPriority(sound);
+
+#if 1
+ // Cherche un canal utilisé dont le son est stoppé.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( m_channel[i].type != sound ) continue;
+
+ m_channel[i].soundBuffer->GetStatus(&status);
+ if ( (status&DSBSTATUS_PLAYING) == 0 )
+ {
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+ channel = i;
+ bAlreadyLoaded = TRUE;
+ return TRUE;
+ }
+ }
+#endif
+
+ // Cherche un canal complètement libre.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed )
+ {
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+ channel = i;
+ bAlreadyLoaded = FALSE;
+ return TRUE;
+ }
+ }
+
+ // Cherche un canal utilisé dont le son est stoppé.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ m_channel[i].soundBuffer->GetStatus(&status);
+ if ( (status&DSBSTATUS_PLAYING) == 0 )
+ {
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+
+ channel = i;
+ bAlreadyLoaded = FALSE;
+ return TRUE;
+ }
+ }
+
+ // Cherche un canal utilisé moins prioritaire.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( m_channel[i].priority >= priority ) continue;
+
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+
+ channel = i;
+ bAlreadyLoaded = FALSE;
+ return TRUE;
+ }
+
+ // Cherche un canal utilisé moins prioritaire ou identique.
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( m_channel[i].priority > priority ) continue;
+
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+ m_channel[i].priority = priority;
+ m_channel[i].uniqueStamp = m_uniqueStamp++;
+
+ channel = i;
+ bAlreadyLoaded = FALSE;
+ return TRUE;
+ }
+
+ char s[100];
+ sprintf(s, "Sound %d forget (priority=%d)\n", sound, priority);
+ OutputDebugString(s);
+
+ return FALSE;
+}
+
+// Reads in data from a wave file.
+
+BOOL CSound::ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size)
+{
+ LPVOID pData1;
+ DWORD dwData1Size;
+ LPVOID pData2;
+ DWORD dwData2Size;
+ HRESULT hr;
+
+ // Lock data in buffer for writing.
+ hr = lpDSB->Lock(0, size, &pData1, &dwData1Size, &pData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR);
+ if ( hr != DS_OK )
+ {
+ return FALSE;
+ }
+
+ // Read in first chunk of data.
+ if ( dwData1Size > 0 )
+ {
+ memcpy(pData1, m_files[sound]+sizeof(WaveHeader), dwData1Size);
+ }
+
+ // Read in second chunk if necessary.
+ if ( dwData2Size > 0 )
+ {
+ memcpy(pData2, m_files[sound]+sizeof(WaveHeader)+dwData1Size, dwData2Size);
+ }
+
+ // Unlock data in buffer.
+ hr = lpDSB->Unlock(pData1, dwData1Size, pData2, dwData2Size);
+ if ( hr != DS_OK )
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Creates a DirectSound buffer.
+
+BOOL CSound::CreateSoundBuffer(int channel, DWORD size, DWORD freq,
+ DWORD bitsPerSample, DWORD blkAlign,
+ BOOL bStereo)
+{
+ PCMWAVEFORMAT pcmwf;
+ DSBUFFERDESC dsbdesc;
+ DS3DBUFFER bufferParams; // 3D buffer properties
+ HRESULT hr;
+
+ // Set up wave format structure.
+ memset( &pcmwf, 0, sizeof(PCMWAVEFORMAT) );
+ pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM;
+ pcmwf.wf.nChannels = bStereo ? 2 : 1;
+ pcmwf.wf.nSamplesPerSec = freq;
+ pcmwf.wf.nBlockAlign = (WORD)blkAlign;
+ pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
+ pcmwf.wBitsPerSample = (WORD)bitsPerSample;
+
+ // Set up DSBUFFERDESC structure.
+ memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
+ dsbdesc.dwSize = sizeof(DSBUFFERDESC);
+ if ( m_ctrl3D )
+ {
+ dsbdesc.dwFlags = DSBCAPS_CTRL3D|DSBCAPS_MUTE3DATMAXDISTANCE|
+ DSBCAPS_LOCDEFER|
+ DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY;
+ }
+ else
+ {
+ dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLPAN|DSBCAPS_CTRLFREQUENCY;
+ }
+ dsbdesc.dwBufferBytes = size;
+ dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
+
+ hr = m_lpDS->CreateSoundBuffer(&dsbdesc, &m_channel[channel].soundBuffer, NULL);
+ if ( hr != DS_OK ) return FALSE;
+
+ if ( m_ctrl3D )
+ {
+ hr = m_channel[channel].soundBuffer->QueryInterface
+ (
+ IID_IDirectSound3DBuffer,
+ (VOID**)&m_channel[channel].soundBuffer3D
+ );
+ if ( hr != DS_OK ) return FALSE;
+ }
+
+ m_channel[channel].bUsed = TRUE;
+ m_channel[channel].bMute = FALSE;
+ return TRUE;
+}
+
+// Creates a DirectSound buffer from a wave file.
+
+BOOL CSound::CreateBuffer(int channel, Sound sound)
+{
+ WaveHeader* wavHdr;
+ DWORD size;
+ BOOL bStereo;
+
+ if ( m_files[sound] == 0 ) return FALSE;
+
+ wavHdr = (WaveHeader*)m_files[sound];
+ size = wavHdr->dwDSize;
+ bStereo = wavHdr->wChnls > 1 ? TRUE : FALSE;
+
+ // Create the sound buffer for the wave file.
+ if ( !CreateSoundBuffer(channel, size, wavHdr->dwSRate,
+ wavHdr->BitsPerSample, wavHdr->wBlkAlign, bStereo) )
+ {
+ return FALSE;
+ }
+
+ // Read the data for the wave file into the sound buffer.
+ if ( !ReadData(m_channel[channel].soundBuffer, sound, size) )
+ {
+ return FALSE;
+ }
+
+ m_channel[channel].type = sound;
+
+ // Close out the wave file.
+ return TRUE;
+}
+
+// Calcule le volume et le panoramique d'un son, en mode non 3D.
+
+void CSound::ComputeVolumePan2D(int channel, const D3DVECTOR &pos)
+{
+ float dist, a, g;
+
+ if ( pos.x == m_eye.x &&
+ pos.y == m_eye.y &&
+ pos.z == m_eye.z )
+ {
+ m_channel[channel].volume = 1.0f; // volume maximal
+ m_channel[channel].pan = 0.0f; // au centre
+ return;
+ }
+
+#if _TEEN
+ dist = Length(pos, m_eye);
+ if ( dist >= 210.0f ) // très loin ?
+ {
+ m_channel[channel].volume = 0.0f; // silence
+ m_channel[channel].pan = 0.0f; // au centre
+ return;
+ }
+ if ( dist <= 10.0f ) // très proche ?
+ {
+ m_channel[channel].volume = 1.0f; // volume maximal
+ m_channel[channel].pan = 0.0f; // au centre
+ return;
+ }
+ m_channel[channel].volume = 1.0f-((dist-10.0f)/200.0f);
+#else
+ dist = Length(pos, m_eye);
+ if ( dist >= 110.0f ) // très loin ?
+ {
+ m_channel[channel].volume = 0.0f; // silence
+ m_channel[channel].pan = 0.0f; // au centre
+ return;
+ }
+ if ( dist <= 10.0f ) // très proche ?
+ {
+ m_channel[channel].volume = 1.0f; // volume maximal
+ m_channel[channel].pan = 0.0f; // au centre
+ return;
+ }
+ m_channel[channel].volume = 1.0f-((dist-10.0f)/100.0f);
+#endif
+
+ a = RotateAngle(m_lookat.x-m_eye.x, m_eye.z-m_lookat.z);
+ g = RotateAngle(pos.x-m_eye.x, m_eye.z-pos.z);
+ m_channel[channel].pan = sinf(Direction(a, g));
+}
+
+// Fait entendre un son au milieu.
+// Retourne le canal associé ou -1.
+
+int CSound::Play(Sound sound, float amplitude, float frequency, BOOL bLoop)
+{
+ return Play(sound, m_lookat, amplitude, frequency, bLoop);
+}
+
+// Fait entendre un son à une position donnée.
+// Retourne le canal associé ou -1.
+
+int CSound::Play(Sound sound, D3DVECTOR pos,
+ float amplitude, float frequency, BOOL bLoop)
+{
+ DS3DBUFFER sb;
+ int channel, iVolume, iPan, iFreq, uniqueStamp;
+ BOOL bAlreadyLoaded;
+ DWORD flag, freq;
+ HRESULT err;
+
+ if ( !m_bEnable ) return -1;
+ if ( !m_bState || m_audioVolume == 0 ) return -1;
+
+//? if ( Length(pos, m_eye) > 100.0f ) return -1;
+
+ if ( !SearchFreeBuffer(sound, channel, bAlreadyLoaded) ) return -1;
+
+ if ( !bAlreadyLoaded )
+ {
+ if ( !CreateBuffer(channel, sound) )
+ {
+ if ( m_channel[channel].bUsed &&
+ m_channel[channel].soundBuffer != 0 )
+ {
+ m_channel[channel].soundBuffer->Release();
+ m_channel[channel].soundBuffer = 0;
+ }
+ m_channel[channel].bUsed = FALSE;
+ return -1;
+ }
+ }
+
+ m_channel[channel].pos = pos;
+
+ if ( m_ctrl3D )
+ {
+ m_channel[channel].volume = 1.0f;
+ m_channel[channel].pan = 0.0f;
+ }
+ else
+ {
+ ComputeVolumePan2D(channel, pos);
+ }
+
+#if 0
+ DWORD status;
+ m_channel[channel].soundBuffer->GetStatus(&status);
+ char s[100];
+ sprintf(s, "Play sound=%d status=%d channel=%d flag=%d\n", sound, status, channel, bAlreadyLoaded);
+ OutputDebugString(s);
+#endif
+
+ m_channel[channel].oper[0].bUsed = FALSE;
+ m_channel[channel].startAmplitude = amplitude;
+ m_channel[channel].startFrequency = frequency;
+ m_channel[channel].changeFrequency = 1.0f;
+
+ if ( m_ctrl3D )
+ {
+ sb.dwSize = sizeof(DS3DBUFFER);
+ err = m_channel[channel].soundBuffer3D->GetAllParameters(&sb);
+ DisplayError("GetAllParameters", sound, err);
+
+ sb.vPosition = pos;
+//? sb.dwInsideConeAngle = 90;
+//? sb.dwOutsideConeAngle = 180;
+//? sb.vConeOrientation = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ sb.lConeOutsideVolume = DSBVOLUME_MIN;
+#if _TEEN
+ sb.flMinDistance = 50.0f;
+#else
+ sb.flMinDistance = 20.0f;
+#endif
+ sb.flMaxDistance = DS3D_DEFAULTMAXDISTANCE;
+
+ err = m_channel[channel].soundBuffer3D->SetAllParameters(&sb, DS3D_IMMEDIATE);
+ DisplayError("SetAllParameters", sound, err);
+ }
+
+ amplitude *= m_channel[channel].volume;
+ amplitude *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ err = m_channel[channel].soundBuffer->SetVolume(iVolume);
+ DisplayError("SetVolume", sound, err);
+
+ if ( !m_ctrl3D )
+ {
+ iPan = (int)(m_channel[channel].pan*10000.0f);
+ err = m_channel[channel].soundBuffer->SetPan(iPan);
+ DisplayError("SetPan", sound, err);
+ }
+
+ if ( !bAlreadyLoaded )
+ {
+ err = m_channel[channel].soundBuffer->GetFrequency(&freq);
+ DisplayError("GetFrequency", sound, err);
+ m_channel[channel].initFrequency = freq;
+ }
+ iFreq = (int)(frequency*m_channel[channel].initFrequency);
+ err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
+ DisplayError("SetFrequency", sound, err);
+
+ err = m_channel[channel].soundBuffer->SetCurrentPosition(0);
+ DisplayError("SetCurrentPosition", sound, err);
+
+ flag = bLoop?DSBPLAY_LOOPING:0;
+//? flag |= DSBPLAY_LOCHARDWARE|DSBPLAY_TERMINATEBY_DISTANCE;
+//? flag |= DSBPLAY_TERMINATEBY_DISTANCE;
+ err = m_channel[channel].soundBuffer->Play(0, 0, flag);
+ DisplayError("Play", sound, err);
+ if ( err == DSERR_BADFORMAT )
+ {
+ iFreq = m_channel[channel].initFrequency;
+ err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
+ DisplayError("SetFrequency (repeat)", sound, err);
+
+ err = m_channel[channel].soundBuffer->Play(0, 0, flag);
+ DisplayError("Play (repeat)", sound, err);
+ }
+
+ uniqueStamp = m_channel[channel].uniqueStamp;
+ return channel | ((uniqueStamp&0xffff)<<16);
+}
+
+// Check un numéro de canal.
+// Adapte le canal pour qu'il puisse être utilisé comme offset
+// dans m_channel.
+
+BOOL CSound::CheckChannel(int &channel)
+{
+ int uniqueStamp;
+
+ uniqueStamp = (channel>>16)&0xffff;
+ channel &= 0xffff;
+
+ if ( !m_bEnable ) return FALSE;
+ if ( !m_bState || m_audioVolume == 0 ) return FALSE;
+
+ if ( channel < 0 || channel >= m_maxSound ) return FALSE;
+ if ( !m_channel[channel].bUsed ) return FALSE;
+
+ if ( m_channel[channel].uniqueStamp != uniqueStamp ) return FALSE;
+
+ return TRUE;
+}
+
+// Supprime toutes les enveloppes.
+
+BOOL CSound::FlushEnvelope(int channel)
+{
+ if ( !CheckChannel(channel) ) return FALSE;
+
+ m_channel[channel].oper[0].bUsed = FALSE;
+ return TRUE;
+}
+
+// Ajoute une opération d'enveloppe.
+
+BOOL CSound::AddEnvelope(int channel, float amplitude, float frequency,
+ float time, SoundNext oper)
+{
+ int i;
+
+ if ( !CheckChannel(channel) ) return FALSE;
+
+ for ( i=0 ; i<MAXOPER ; i++ )
+ {
+ if ( m_channel[channel].oper[i].bUsed ) continue;
+
+ m_channel[channel].oper[i].bUsed = TRUE;
+ m_channel[channel].oper[i].finalAmplitude = amplitude;
+ m_channel[channel].oper[i].finalFrequency = frequency;
+ m_channel[channel].oper[i].totalTime = time;
+ m_channel[channel].oper[i].currentTime = 0;
+ m_channel[channel].oper[i].nextOper = oper;
+
+ if ( i < MAXOPER-1 )
+ {
+ m_channel[channel].oper[i+1].bUsed = FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Modifie la posiion d'un son.
+
+BOOL CSound::Position(int channel, D3DVECTOR pos)
+{
+ float amplitude, pan;
+ int iVolume, iPan;
+ HRESULT err;
+
+ if ( !CheckChannel(channel) ) return FALSE;
+
+ m_channel[channel].pos = pos;
+
+ if ( m_ctrl3D )
+ {
+ m_channel[channel].soundBuffer3D->SetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED);
+ }
+ else
+ {
+ ComputeVolumePan2D(channel, pos);
+
+ if ( !m_channel[channel].oper[0].bUsed )
+ {
+ amplitude = m_channel[channel].startAmplitude;
+ amplitude *= m_channel[channel].volume;
+ amplitude *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ err = m_channel[channel].soundBuffer->SetVolume(iVolume);
+ DisplayError("SetVolume", m_channel[channel].type, err);
+ }
+
+ pan = m_channel[channel].pan;
+ iPan = (int)(pan*10000.0f);
+ err = m_channel[channel].soundBuffer->SetPan(iPan);
+ DisplayError("SetPan", m_channel[channel].type, err);
+ }
+ return TRUE;
+}
+
+// Modifie la fréquence d'un son.
+// 0.5 descend d'une octave et 2.0 monte d'une octave.
+
+BOOL CSound::Frequency(int channel, float frequency)
+{
+ HRESULT err;
+ int iFreq;
+
+ if ( !CheckChannel(channel) ) return FALSE;
+
+ m_channel[channel].changeFrequency = frequency;
+
+ if ( !m_channel[channel].oper[0].bUsed )
+ {
+ iFreq = (int)(frequency*m_channel[channel].initFrequency);
+ err = m_channel[channel].soundBuffer->SetFrequency(iFreq);
+ DisplayError("Frequency", m_channel[channel].type, err);
+ }
+
+ return TRUE;
+}
+
+// Stoppe un son.
+
+BOOL CSound::Stop(int channel)
+{
+ if ( !CheckChannel(channel) ) return FALSE;
+
+ m_channel[channel].soundBuffer->Stop();
+ return TRUE;
+}
+
+// Stops all sounds.
+
+BOOL CSound::StopAll()
+{
+ DWORD status;
+ int i;
+
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ m_channel[i].soundBuffer->GetStatus(&status);
+ if ( (status&DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING )
+ {
+ m_channel[i].soundBuffer->Stop();
+ }
+ m_channel[i].soundBuffer->Stop();
+ m_channel[i].soundBuffer->Release();
+ m_channel[i].soundBuffer = 0;
+
+ m_channel[i].bUsed = FALSE;
+ }
+ return TRUE;
+}
+
+// Silent all sounds.
+
+BOOL CSound::MuteAll(BOOL bMute)
+{
+ int i;
+
+ for ( i=0 ; i<MAXSOUND ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ m_channel[i].bMute = bMute;
+ }
+ return TRUE;
+}
+
+
+// Passe à l'opération suivante pour un canal.
+
+void CSound::OperNext(int channel)
+{
+ int i;
+
+ m_channel[channel].startAmplitude = m_channel[channel].oper[0].finalAmplitude;
+ m_channel[channel].startFrequency = m_channel[channel].oper[0].finalFrequency;
+
+ for ( i=0 ; i<MAXOPER-1 ; i++ )
+ {
+ if ( !m_channel[channel].oper[i+1].bUsed ) break;
+
+ m_channel[channel].oper[i] = m_channel[channel].oper[i+1];
+ }
+
+ m_channel[channel].oper[i].bUsed = FALSE;
+}
+
+// Met à jour les buffers des sons.
+
+void CSound::FrameMove(float rTime)
+{
+ HRESULT err;
+ SoundNext next;
+ float progress, volume, freq;
+ int i, iVolume, iFreq;
+
+ m_playTime += rTime;
+
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+ if ( !m_channel[i].oper[0].bUsed ) continue;
+
+ if ( m_channel[i].bMute )
+ {
+ m_channel[i].soundBuffer->SetVolume(-10000); // silence
+ continue;
+ }
+
+ m_channel[i].oper[0].currentTime += rTime;
+
+ progress = m_channel[i].oper[0].currentTime / m_channel[i].oper[0].totalTime;
+ if ( progress > 1.0f ) progress = 1.0f;
+
+ volume = progress;
+ volume *= m_channel[i].oper[0].finalAmplitude-m_channel[i].startAmplitude;
+ volume += m_channel[i].startAmplitude;
+ volume *= m_channel[i].volume;
+ volume *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(volume, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ m_channel[i].soundBuffer->SetVolume(iVolume);
+
+ freq = progress;
+ freq *= m_channel[i].oper[0].finalFrequency-m_channel[i].startFrequency;
+ freq += m_channel[i].startFrequency;
+ freq *= m_channel[i].changeFrequency;
+ iFreq = (int)(freq*m_channel[i].initFrequency);
+ err = m_channel[i].soundBuffer->SetFrequency(iFreq);
+ DisplayError("FrameMove::Frequency", m_channel[i].type, err);
+
+ if ( m_channel[i].oper[0].currentTime >=
+ m_channel[i].oper[0].totalTime )
+ {
+ next = m_channel[i].oper[0].nextOper;
+
+ if ( next == SOPER_LOOP )
+ {
+ m_channel[i].oper[0].currentTime = 0.0f;
+ }
+ else
+ {
+ OperNext(i);
+
+ if ( next == SOPER_STOP )
+ {
+ m_channel[i].soundBuffer->Stop();
+ }
+ }
+ }
+ }
+
+ m_lastTime += rTime;
+ if ( m_lastTime >= 0.05f && m_listener != 0 )
+ {
+ m_lastTime = 0.0f;
+ m_listener->CommitDeferredSettings();
+ }
+}
+
+// Spécifie la position de l'auditeur.
+// Doit être appelé chaque fois que la caméra se déplace.
+
+void CSound::SetListener(D3DVECTOR eye, D3DVECTOR lookat)
+{
+ DS3DLISTENER listenerParams;
+ HRESULT err;
+ float amplitude, pan;
+ int i, iVolume, iPan;
+
+ m_eye = eye;
+ m_lookat = lookat;
+
+ if ( m_listener == 0 )
+ {
+ if ( m_ctrl3D ) return;
+
+ for ( i=0 ; i<m_maxSound ; i++ )
+ {
+ if ( !m_channel[i].bUsed ) continue;
+
+ ComputeVolumePan2D(i, m_channel[i].pos);
+
+ if ( !m_channel[i].oper[0].bUsed )
+ {
+ amplitude = m_channel[i].startAmplitude;
+ amplitude *= m_channel[i].volume;
+ amplitude *= (float)m_audioVolume/MAXVOLUME;
+ iVolume = (int)((powf(amplitude, 0.2f)-1.0f)*10000.0f);
+ if ( iVolume > 0 ) iVolume = 0;
+ err = m_channel[i].soundBuffer->SetVolume(iVolume);
+ DisplayError("SetVolume", m_channel[i].type, err);
+ }
+
+ pan = m_channel[i].pan;
+ iPan = (int)(pan*10000.0f);
+ err = m_channel[i].soundBuffer->SetPan(iPan);
+ DisplayError("SetPan", m_channel[i].type, err);
+ }
+ return;
+ }
+
+ // Get listener parameters.
+ listenerParams.dwSize = sizeof(DS3DLISTENER);
+ m_listener->GetAllParameters(&listenerParams);
+
+ listenerParams.vPosition = eye;
+ listenerParams.vOrientFront = lookat-eye;
+ listenerParams.vOrientTop = D3DVECTOR(0.0f, 1.0f, 0.0f);
+ listenerParams.flDistanceFactor = 10.0f;
+ listenerParams.flRolloffFactor = 1.0f;
+
+ m_listener->SetAllParameters(&listenerParams, DS3D_DEFERRED);
+}
+
+
+
+
+// Uses MCI to play a MIDI file. The window procedure
+// is notified when playback is complete.
+
+BOOL CSound::PlayMusic(int rank, BOOL bRepeat)
+{
+ MCI_OPEN_PARMS mciOpenParms;
+ MCI_PLAY_PARMS mciPlayParms;
+ DWORD dwReturn;
+ char filename[MAX_PATH];
+
+ m_bRepeatMusic = bRepeat;
+ m_playTime = 0.0f;
+
+ if ( m_midiVolume == 0 ) return TRUE;
+
+ if ( m_bAudioTrack )
+ {
+ return PlayAudioTrack(rank);
+ }
+
+ if ( !m_bEnable ) return TRUE;
+ InitMidiVolume(m_midiVolume);
+ m_lastMidiVolume = m_midiVolume;
+
+ GetCurrentDir(filename, MAX_PATH-30);
+ sprintf(filename+strlen(filename), "sound\\music%.3d.blp", rank-1);
+
+ // Open the device by specifying the device and filename.
+ // MCI will attempt to choose the MIDI mapper as the output port.
+ mciOpenParms.lpstrDeviceType = "sequencer";
+ mciOpenParms.lpstrElementName = filename;
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,
+ (DWORD)(LPVOID)&mciOpenParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ // Failed to open device. Don't close it; just return error.
+ return FALSE;
+ }
+
+ // The device opened successfully; get the device ID.
+ m_MidiDeviceID = mciOpenParms.wDeviceID;
+
+ // Begin playback.
+ mciPlayParms.dwCallback = (DWORD)m_hWnd;
+ dwReturn = mciSendCommand(m_MidiDeviceID,
+ MCI_PLAY,
+ MCI_NOTIFY,
+ (DWORD)(LPVOID)&mciPlayParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ StopMusic();
+ return FALSE;
+ }
+
+ m_MIDIMusic = rank;
+ return TRUE;
+}
+
+// Uses MCI to play a CD-audio track. The window procedure
+// is notified when playback is complete.
+// The rank parameter is in space [1..n] !
+// For CD mix (data/audio), it will be [2..n] !
+
+BOOL CSound::PlayAudioTrack(int rank)
+{
+#if _SOUNDTRACKS
+ MCI_OPEN_PARMS mciOpenParms;
+ MCI_PLAY_PARMS mciPlayParms;
+ MCI_SET_PARMS mciSetParms;
+ DWORD dwReturn;
+ char filename[MAX_PATH];
+ char device[10];
+
+ if ( !m_bEnable ) return TRUE;
+//? if ( m_midiVolume == 0 ) return TRUE;
+ InitAudioTrackVolume(m_midiVolume);
+ m_lastMidiVolume = m_midiVolume;
+
+ // Open the device by specifying the device and filename.
+ // MCI will attempt to choose the MIDI mapper as the output port.
+ memset(&mciOpenParms, 0, sizeof(MCI_OPEN_PARMS));
+//? mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
+//? dwReturn = mciSendCommand(NULL,
+//? MCI_OPEN,
+//? MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
+//? (DWORD)(LPVOID)&mciOpenParms);
+ mciOpenParms.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO;
+ if ( m_CDpath[0] == 0 )
+ {
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,
+ (DWORD)(LPVOID)&mciOpenParms);
+ }
+ else
+ {
+ device[0] = m_CDpath[0];
+ device[1] = ':';
+ device[2] = 0;
+ mciOpenParms.lpstrElementName = device;
+ dwReturn = mciSendCommand(NULL,
+ MCI_OPEN,
+ MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_OPEN_ELEMENT,
+ (DWORD)(LPVOID)&mciOpenParms);
+ }
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ // Failed to open device. Don't close it; just return error.
+ return FALSE;
+ }
+
+ // The device opened successfully; get the device ID.
+ m_MidiDeviceID = mciOpenParms.wDeviceID;
+
+ // Set the time format to track/minute/second/frame (TMSF).
+ memset(&mciSetParms, 0, sizeof(MCI_SET_PARMS));
+ mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
+ dwReturn = mciSendCommand(m_MidiDeviceID,
+ MCI_SET,
+ MCI_SET_TIME_FORMAT,
+ (DWORD)&mciSetParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ StopMusic();
+ return FALSE;
+ }
+
+ // Begin playback.
+ memset(&mciPlayParms, 0, sizeof(MCI_PLAY_PARMS));
+ mciPlayParms.dwCallback = (DWORD)m_hWnd;
+ mciPlayParms.dwFrom = MCI_MAKE_TMSF(rank+0, 0, 0, 0);
+ mciPlayParms.dwTo = MCI_MAKE_TMSF(rank+1, 0, 0, 0);
+ dwReturn = mciSendCommand(m_MidiDeviceID,
+ MCI_PLAY,
+ MCI_NOTIFY|MCI_FROM|MCI_TO,
+ (DWORD)(LPVOID)&mciPlayParms);
+ if ( dwReturn != 0 )
+ {
+ mciGetErrorString(dwReturn, filename, 128);
+ StopMusic();
+ return FALSE;
+ }
+
+ m_MIDIMusic = rank;
+#endif
+ return TRUE;
+}
+
+// Restart the MIDI player.
+
+BOOL CSound::RestartMusic()
+{
+ if ( !m_bRepeatMusic ) return FALSE;
+
+ OutputDebugString("RestartMusic\n");
+ if ( !m_bEnable ) return TRUE;
+//? if ( m_midiVolume == 0 ) return TRUE;
+ if ( m_MIDIMusic == 0 ) return FALSE;
+ if ( m_playTime < 5.0f ) return FALSE;
+
+ return PlayMusic(m_MIDIMusic, TRUE);
+}
+
+// Shuts down the MIDI player.
+
+void CSound::SuspendMusic()
+{
+ if ( !m_bEnable ) return;
+
+//? if ( m_MidiDeviceID && m_midiVolume != 0 )
+ if ( m_MidiDeviceID )
+ {
+ if ( m_bAudioTrack ) mciSendCommand(m_MidiDeviceID, MCI_STOP, 0, NULL);
+ mciSendCommand(m_MidiDeviceID, MCI_CLOSE, 0, NULL);
+ }
+ m_MidiDeviceID = 0;
+}
+
+// Shuts down the MIDI player.
+
+void CSound::StopMusic()
+{
+ SuspendMusic();
+ m_MIDIMusic = 0;
+}
+
+// Retourne TRUE si une musique est en cours.
+
+BOOL CSound::IsPlayingMusic()
+{
+ return (m_MIDIMusic != 0);
+}
+
+// Adapte le volume de la musique en cours, si nécessaire.
+
+void CSound::AdaptVolumeMusic()
+{
+ if ( m_midiVolume != m_lastMidiVolume )
+ {
+ if ( m_bAudioTrack )
+ {
+ InitAudioTrackVolume(m_midiVolume);
+ }
+ else
+ {
+ InitMidiVolume(m_midiVolume);
+ }
+ m_lastMidiVolume = m_midiVolume;
+ RestartMusic();
+ }
+}
+
diff --git a/src/sound.h b/src/sound.h
new file mode 100644
index 0000000..1f42562
--- /dev/null
+++ b/src/sound.h
@@ -0,0 +1,225 @@
+// sound.h
+
+
+#include <dsound.h>
+
+
+#define MAXFILES 200
+#define MAXSOUND 32
+#define MAXVOLUME 20
+#define MAXOPER 4
+
+class CInstanceManager;
+
+
+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, // tir avec fireball
+ SOUND_HUMAN1 = 26, // respiration
+ SOUND_STEPw = 27, // water
+ SOUND_SWIM = 28,
+ SOUND_RADAR = 29,
+ SOUND_BUILD = 30,
+ SOUND_ALARM = 31, // alarme énergie
+ 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 (pattes)
+ SOUND_SHIELD = 48,
+ SOUND_FIREi = 49, // tir avec orgaball (insect)
+ SOUND_GUNDEL = 50,
+ SOUND_PSHHH2 = 51, // shield
+ SOUND_MESSAGE = 52,
+ SOUND_BOUMm = 53, // metal
+ SOUND_BOUMv = 54, // vegetal
+ 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, // mort par balle
+ SOUND_DEADw = 70, // mort noyé
+ SOUND_FLYf = 71, // reactor fail
+ SOUND_ALARMt = 72, // alarme température
+ SOUND_FINDING = 73, // trouvé un objet caché
+ SOUND_THUMP = 74,
+ SOUND_TOUCH = 75,
+ SOUND_BLITZ = 76,
+ SOUND_MUSHROOM = 77,
+ SOUND_FIREp = 78, // tir avec phazer
+ SOUND_EXPLOg1 = 79, // impact gun 1
+ SOUND_EXPLOg2 = 80, // impact gun 2
+ SOUND_MOTORd = 81, // moteur à friction
+};
+
+enum SoundNext
+{
+ SOPER_CONTINUE = 1,
+ SOPER_STOP = 2,
+ SOPER_LOOP = 3,
+};
+
+typedef struct
+{
+ char bUsed;
+ float finalAmplitude;
+ float finalFrequency;
+ float totalTime;
+ float currentTime;
+ SoundNext nextOper;
+}
+SoundOper;
+
+typedef struct
+{
+ char bUsed; // buffer utilisé ?
+ char bMute; // silence ?
+ Sound type; // SOUND_*
+ int priority; // si grand -> important
+ D3DVECTOR pos; // position dans l'espace
+ unsigned short uniqueStamp; // marqueur unique
+ LPDIRECTSOUNDBUFFER soundBuffer;
+ LPDIRECTSOUND3DBUFFER soundBuffer3D;
+ float startAmplitude;
+ float startFrequency;
+ float changeFrequency;
+ int initFrequency;
+ float volume; // 2D: volume 1..0 selon position
+ float pan; // 2D: pan -1..+1 selon position
+ SoundOper oper[MAXOPER];
+}
+SoundChannel;
+
+
+
+class CSound
+{
+public:
+ CSound(CInstanceManager* iMan);
+ ~CSound();
+
+ void SetDebugMode(BOOL bMode);
+ BOOL Create(HWND hWnd, BOOL b3D);
+ void CacheAll();
+
+ void SetState(BOOL bState);
+ BOOL RetEnable();
+
+ void SetCDpath(char *path);
+ void SetAudioTrack(BOOL bAudio);
+
+ void SetSound3D(BOOL bMode);
+ BOOL RetSound3D();
+ BOOL RetSound3DCap();
+
+ void SetAudioVolume(int volume);
+ int RetAudioVolume();
+ void SetMidiVolume(int volume);
+ int RetMidiVolume();
+
+ void SetListener(D3DVECTOR eye, D3DVECTOR lookat);
+ void FrameMove(float rTime);
+
+ int Play(Sound sound, float amplitude=1.0f, float frequency=1.0f, BOOL bLoop=FALSE);
+ int Play(Sound sound, D3DVECTOR pos, float amplitude=1.0f, float frequency=1.0f, BOOL bLoop=FALSE);
+ BOOL FlushEnvelope(int channel);
+ BOOL AddEnvelope(int channel, float amplitude, float frequency, float time, SoundNext oper);
+ BOOL Position(int channel, D3DVECTOR pos);
+ BOOL Frequency(int channel, float frequency);
+ BOOL Stop(int channel);
+ BOOL StopAll();
+ BOOL MuteAll(BOOL bMute);
+
+ BOOL PlayMusic(int rank, BOOL bRepeat);
+ BOOL RestartMusic();
+ void SuspendMusic();
+ void StopMusic();
+ BOOL IsPlayingMusic();
+ void AdaptVolumeMusic();
+
+protected:
+ BOOL CheckChannel(int &channel);
+ BOOL CreateSoundBuffer(int channel, DWORD size, DWORD freq, DWORD bitsPerSample, DWORD blkAlign, BOOL bStereo);
+ BOOL ReadData(LPDIRECTSOUNDBUFFER lpDSB, Sound sound, DWORD size);
+ BOOL CreateBuffer(int channel, Sound sound);
+ void ComputeVolumePan2D(int channel, const D3DVECTOR &pos);
+ BOOL ReadFile(Sound sound, char *metaname, char *filename);
+ int RetPriority(Sound sound);
+ BOOL SearchFreeBuffer(Sound sound, int &channel, BOOL &bAlreadyLoaded);
+ void OperNext(int channel);
+ BOOL PlayAudioTrack(int rank);
+
+protected:
+ CInstanceManager* m_iMan;
+
+ HWND m_hWnd;
+ BOOL m_bEnable;
+ BOOL m_bState;
+ BOOL m_bAudioTrack;
+ BOOL m_ctrl3D;
+ BOOL m_bDebugMode;
+ LPDIRECTSOUND m_lpDS;
+ LPDIRECTSOUND3DLISTENER m_listener;
+ SoundChannel m_channel[MAXSOUND];
+ char* m_files[MAXFILES];
+ UINT m_MidiDeviceID;
+ int m_MIDIMusic;
+ BOOL m_bRepeatMusic;
+ int m_audioVolume;
+ int m_midiVolume;
+ int m_lastMidiVolume;
+ D3DVECTOR m_eye;
+ D3DVECTOR m_lookat;
+ float m_lastTime;
+ float m_playTime;
+ int m_uniqueStamp;
+ int m_maxSound;
+ char m_CDpath[100];
+};
+
diff --git a/src/struct.h b/src/struct.h
new file mode 100644
index 0000000..d81b30f
--- /dev/null
+++ b/src/struct.h
@@ -0,0 +1,57 @@
+// struct.h
+
+#ifndef _STRUCT_H_
+#define _STRUCT_H_
+
+#include <d3d.h>
+
+
+#define NAN 999999
+
+#define D3DFVF_VERTEX2 (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2)
+
+struct D3DVERTEX2
+{
+ float x,y,z;
+ float nx,ny,nz;
+ float tu, tv;
+ float tu2, tv2;
+
+ D3DVERTEX2() { }
+ D3DVERTEX2(const D3DVECTOR& _v, const D3DVECTOR& _n, float _tu=0.0f, float _tv=0.0f, float _tu2=0.0f, float _tv2=0.0f)
+ {
+ x = _v.x;
+ y = _v.y;
+ z = _v.z;
+ nx = _n.x;
+ ny = _n.y;
+ nz = _n.z;
+ tu = _tu;
+ tv = _tv;
+ tu2 = _tu2;
+ tv2 = _tv2;
+ }
+};
+
+
+struct FPOINT
+{
+ float x;
+ float y;
+
+ FPOINT() { }
+ FPOINT(float _x, float _y)
+ {
+ x = _x;
+ y = _y;
+ }
+};
+
+
+struct ColorHSV
+{
+ float h,s,v;
+};
+
+
+#endif //_STRUCT_H_
diff --git a/src/studio.cpp b/src/studio.cpp
new file mode 100644
index 0000000..aa6907d
--- /dev/null
+++ b/src/studio.cpp
@@ -0,0 +1,1649 @@
+// studio.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <direct.h>
+#include <io.h>
+#include <time.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "restext.h"
+#include "math3d.h"
+#include "robotmain.h"
+#include "object.h"
+#include "camera.h"
+#include "sound.h"
+#include "script.h"
+#include "interface.h"
+#include "button.h"
+#include "check.h"
+#include "slider.h"
+#include "edit.h"
+#include "list.h"
+#include "label.h"
+#include "group.h"
+#include "window.h"
+#include "text.h"
+#include "cbottoken.h"
+#include "studio.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CStudio::CStudio(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_STUDIO, this);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_event = (CEvent*)m_iMan->SearchInstance(CLASS_EVENT);
+ m_interface = (CInterface*)m_iMan->SearchInstance(CLASS_INTERFACE);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_bEditMaximized = FALSE;
+ m_bEditMinimized = FALSE;
+
+ m_time = 0.0f;
+ m_bRealTime = TRUE;
+ m_bRunning = FALSE;
+ m_fixInfoTextTime = 0.0f;
+ m_helpFilename[0] = 0;
+ m_dialog = SD_NULL;
+}
+
+// Destructeur de l'objet.
+
+CStudio::~CStudio()
+{
+ m_iMan->DeleteInstance(CLASS_STUDIO, this);
+}
+
+
+// Gestion d'un événement.
+
+BOOL CStudio::EventProcess(const Event &event)
+{
+ CWindow* pw;
+ CEdit* edit;
+ CSlider* slider;
+ char res[100];
+
+ if ( m_dialog != SD_NULL ) // dialogue existe ?
+ {
+ return EventDialog(event);
+ }
+
+ if ( event.event == EVENT_FRAME )
+ {
+ EventFrame(event);
+ }
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return FALSE;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( edit == 0 ) return FALSE;
+
+ if ( event.event == pw->RetEventMsgClose() )
+ {
+ Event newEvent = event;
+ newEvent.event = EVENT_STUDIO_OK;
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.event == EVENT_STUDIO_EDIT ) // texte modifié ?
+ {
+ ColorizeScript(edit);
+ }
+
+ if ( event.event == EVENT_STUDIO_LIST ) // liste cliquée ?
+ {
+ m_main->StartDisplayInfo(m_helpFilename, -1);
+ }
+
+ if ( event.event == EVENT_STUDIO_NEW ) // nouveau ?
+ {
+ m_script->New(edit, "");
+ }
+
+ if ( event.event == EVENT_STUDIO_OPEN ) // ouvrir ?
+ {
+ StartDialog(SD_OPEN);
+ }
+ if ( event.event == EVENT_STUDIO_SAVE ) // enregistrer ?
+ {
+ StartDialog(SD_SAVE);
+ }
+
+ if ( event.event == EVENT_STUDIO_UNDO ) // annuler ?
+ {
+ edit->Undo();
+ }
+ if ( event.event == EVENT_STUDIO_CUT ) // couper ?
+ {
+ edit->Cut();
+ }
+ if ( event.event == EVENT_STUDIO_COPY ) // copier ?
+ {
+ edit->Copy();
+ }
+ if ( event.event == EVENT_STUDIO_PASTE ) // coller ?
+ {
+ edit->Paste();
+ }
+
+ if ( event.event == EVENT_STUDIO_SIZE ) // taille ?
+ {
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider == 0 ) return FALSE;
+ m_main->SetFontSize(9.0f+slider->RetVisibleValue()*6.0f);
+ ViewEditScript();
+ }
+
+ if ( event.event == EVENT_STUDIO_TOOL && // instructions ?
+ m_dialog == SD_NULL )
+ {
+ m_main->StartDisplayInfo(SATCOM_HUSTON, FALSE);
+ }
+ if ( event.event == EVENT_STUDIO_HELP && // aide ?
+ m_dialog == SD_NULL )
+ {
+ m_main->StartDisplayInfo(SATCOM_PROG, FALSE);
+ }
+
+ if ( event.event == EVENT_STUDIO_COMPILE ) // compile ?
+ {
+ char buffer[100];
+
+ if ( m_script->GetScript(edit) ) // compile
+ {
+ GetResource(RES_TEXT, RT_STUDIO_COMPOK, res);
+ SetInfoText(res, FALSE);
+ }
+ else
+ {
+ m_script->GetError(buffer);
+ SetInfoText(buffer, FALSE);
+ }
+ }
+
+ if ( event.event == EVENT_STUDIO_RUN ) // run/stop ?
+ {
+ if ( m_script->IsRunning() )
+ {
+ Event newEvent = event;
+ newEvent.event = EVENT_OBJECT_PROGSTOP;
+ m_event->AddEvent(newEvent); // stoppe
+ }
+ else
+ {
+ if ( m_script->GetScript(edit) ) // compile
+ {
+ SetInfoText("", FALSE);
+
+ Event newEvent = event;
+ newEvent.event = EVENT_OBJECT_PROGSTART;
+ m_event->AddEvent(newEvent); // start
+ }
+ else
+ {
+ char buffer[100];
+ m_script->GetError(buffer);
+ SetInfoText(buffer, FALSE);
+ }
+ }
+ }
+
+ if ( event.event == EVENT_STUDIO_REALTIME ) // temps réel ?
+ {
+ m_bRealTime = !m_bRealTime;
+ m_script->SetStepMode(!m_bRealTime);
+ UpdateFlux();
+ UpdateButtons();
+ }
+
+ if ( event.event == EVENT_STUDIO_STEP ) // step ?
+ {
+ m_script->Step(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+ if ( event.param == m_engine->RetKey(KEYRANK_CBOT, 0) ||
+ event.param == m_engine->RetKey(KEYRANK_CBOT, 1) )
+ {
+ if ( m_helpFilename[0] != 0 )
+ {
+ m_main->StartDisplayInfo(m_helpFilename, -1);
+ }
+ }
+ }
+
+ if ( event.event == EVENT_WINDOW3 ) // fenêtre déplacée ?
+ {
+ m_editActualPos = m_editFinalPos = pw->RetPos();
+ m_editActualDim = m_editFinalDim = pw->RetDim();
+ m_main->SetWindowPos(m_editActualPos);
+ m_main->SetWindowDim(m_editActualDim);
+ AdjustEditScript();
+ }
+ if ( event.event == pw->RetEventMsgReduce() )
+ {
+ if ( m_bEditMinimized )
+ {
+ m_editFinalPos = m_main->RetWindowPos();
+ m_editFinalDim = m_main->RetWindowDim();
+ m_bEditMinimized = FALSE;
+ m_bEditMaximized = FALSE;
+ }
+ else
+ {
+ m_editFinalPos.x = 0.00f;
+ m_editFinalPos.y = -0.44f;
+ m_editFinalDim.x = 1.00f;
+ m_editFinalDim.y = 0.50f;
+ m_bEditMinimized = TRUE;
+ m_bEditMaximized = FALSE;
+ }
+ m_main->SetEditFull(m_bEditMaximized);
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 )
+ {
+ pw->SetMaximized(m_bEditMaximized);
+ pw->SetMinimized(m_bEditMinimized);
+ }
+ }
+ if ( event.event == pw->RetEventMsgFull() )
+ {
+ if ( m_bEditMaximized )
+ {
+ m_editFinalPos = m_main->RetWindowPos();
+ m_editFinalDim = m_main->RetWindowDim();
+ m_bEditMinimized = FALSE;
+ m_bEditMaximized = FALSE;
+ }
+ else
+ {
+ m_editFinalPos.x = 0.00f;
+ m_editFinalPos.y = 0.00f;
+ m_editFinalDim.x = 1.00f;
+ m_editFinalDim.y = 1.00f;
+ m_bEditMinimized = FALSE;
+ m_bEditMaximized = TRUE;
+ }
+ m_main->SetEditFull(m_bEditMaximized);
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 )
+ {
+ pw->SetMaximized(m_bEditMaximized);
+ pw->SetMinimized(m_bEditMinimized);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Fait évoluer une valeur en fonction du temps écoulé.
+
+float Evolution(float final, float actual, float time)
+{
+ float value;
+
+ value = actual + (final-actual)*time;
+
+ if ( final > actual )
+ {
+ if ( value > final ) value = final; // ne dépasse pas
+ }
+ else
+ {
+ if ( value < final ) value = final; // ne dépasse pas
+ }
+
+ return value;
+}
+
+// Fait évoluer le studio selon le temps écoulé.
+
+BOOL CStudio::EventFrame(const Event &event)
+{
+ CWindow* pw;
+ CEdit* edit;
+ CList* list;
+ float time;
+ int cursor1, cursor2, iCursor1, iCursor2;
+ char res[100];
+
+ m_time += event.rTime;
+ m_fixInfoTextTime -= event.rTime;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return FALSE;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( edit == 0 ) return FALSE;
+
+ list = (CList*)pw->SearchControl(EVENT_STUDIO_LIST);
+ if ( list == 0 ) return FALSE;
+
+ if ( !m_script->IsRunning() && m_bRunning ) // arrêt ?
+ {
+ m_bRunning = FALSE;
+ UpdateFlux(); // stop
+ AdjustEditScript();
+ GetResource(RES_TEXT, RT_STUDIO_PROGSTOP, res);
+ SetInfoText(res, FALSE);
+
+ Event newEvent = event;
+ newEvent.event = EVENT_OBJECT_PROGSTOP;
+ m_event->AddEvent(newEvent); // stoppe
+ }
+
+ if ( m_script->IsRunning() && !m_bRunning ) // départ ?
+ {
+ m_bRunning = TRUE;
+ UpdateFlux(); // run
+ AdjustEditScript();
+ }
+ UpdateButtons();
+
+ if ( m_bRunning )
+ {
+ m_script->GetCursor(cursor1, cursor2);
+ edit->GetCursor(iCursor1, iCursor2);
+ if ( cursor1 != iCursor1 ||
+ cursor2 != iCursor2 ) // curseurs changés ?
+ {
+ edit->SetCursor(cursor1, cursor2); // montre où en est l'exécution
+ edit->ShowSelect();
+ }
+
+ m_script->UpdateList(list); // met à jour la liste des variables
+ }
+ else
+ {
+ SearchToken(edit);
+ }
+
+ if ( m_editFinalPos.x != m_editActualPos.x ||
+ m_editFinalPos.y != m_editActualPos.y ||
+ m_editFinalDim.x != m_editActualDim.x ||
+ m_editFinalDim.y != m_editActualDim.y )
+ {
+ time = event.rTime*20.0f;
+ m_editActualPos.x = Evolution(m_editFinalPos.x, m_editActualPos.x, time);
+ m_editActualPos.y = Evolution(m_editFinalPos.y, m_editActualPos.y, time);
+ m_editActualDim.x = Evolution(m_editFinalDim.x, m_editActualDim.x, time);
+ m_editActualDim.y = Evolution(m_editFinalDim.y, m_editActualDim.y, time);
+ AdjustEditScript();
+ }
+
+ return TRUE;
+}
+
+
+// Indique si un caractère fait partie d'un mot.
+
+BOOL IsToken(int character)
+{
+ char c;
+
+ c = tolower(RetNoAccent(character));
+
+ return ( (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' );
+}
+
+// Cherche si le curseur est sur un mot-clé.
+
+void CStudio::SearchToken(CEdit* edit)
+{
+ ObjectType type;
+ int len, cursor1, cursor2, i, character, level;
+ char* text;
+ char token[100];
+
+ text = edit->RetText();
+ len = edit->RetTextLength();
+ edit->GetCursor(cursor1, cursor2);
+
+ i = cursor1;
+ if ( i > 0 )
+ {
+ character = (unsigned char)text[i-1];
+ if ( !IsToken(character) )
+ {
+ level = 1;
+ while ( i > 0 )
+ {
+ character = (unsigned char)text[i-1];
+ if ( character == ')' )
+ {
+ level ++;
+ }
+ else if ( character == '(' )
+ {
+ level --;
+ if ( level == 0 ) break;
+ }
+ i --;
+ }
+ if ( level > 0 )
+ {
+ m_helpFilename[0] = 0;
+ SetInfoText("", TRUE);
+ return;
+ }
+ while ( i > 0 )
+ {
+ character = (unsigned char)text[i-1];
+ if ( IsToken(character) ) break;
+ i --;
+ }
+ }
+ }
+
+ while ( i > 0 )
+ {
+ character = (unsigned char)text[i-1];
+ if ( !IsToken(character) ) break;
+ i --;
+ }
+ cursor2 = i;
+
+ while ( i < len )
+ {
+ character = (unsigned char)text[i];
+ if ( !IsToken(character) ) break;
+ i ++;
+ }
+ cursor1 = i;
+ len = cursor1-cursor2;
+
+ if ( len > 100-1 ) len = 100-1;
+ for ( i=0 ; i<len ; i++ )
+ {
+ token[i] = text[cursor2+i];
+ }
+ token[i] = 0;
+
+ strcpy(m_helpFilename, RetHelpFilename(token));
+ if ( m_helpFilename[0] == 0 )
+ {
+ for ( i=0 ; i<OBJECT_MAX ; i++ )
+ {
+ type = (ObjectType)i;
+ text = RetObjectName(type);
+ if ( text[0] != 0 )
+ {
+ if ( strcmp(token, text) == 0 )
+ {
+ strcpy(m_helpFilename, RetHelpFilename(type));
+ SetInfoText(token, TRUE);
+ return;
+ }
+ }
+ text = RetObjectAlias(type);
+ if ( text[0] != 0 )
+ {
+ if ( strcmp(token, text) == 0 )
+ {
+ strcpy(m_helpFilename, RetHelpFilename(type));
+ SetInfoText(token, TRUE);
+ return;
+ }
+ }
+ }
+ }
+
+ text = RetHelpText(token);
+ if ( text[0] == 0 && m_helpFilename[0] != 0 )
+ {
+ SetInfoText(token, TRUE);
+ }
+ else
+ {
+ SetInfoText(text, TRUE);
+ }
+}
+
+// Colore le texte selon la syntaxe.
+
+void CStudio::ColorizeScript(CEdit* edit)
+{
+ m_script->ColorizeScript(edit);
+}
+
+
+// Début de l'édition d'un programme.
+
+void CStudio::StartEditScript(CScript *script, char* name, int rank)
+{
+ FPOINT pos, dim;
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+ CSlider* slider;
+ CList* list;
+ char res[100];
+
+ m_script = script;
+ m_rank = rank;
+
+ m_main->SetEditLock(TRUE, TRUE);
+ m_main->SetEditFull(FALSE);
+ m_bInitPause = m_engine->RetPause();
+ m_main->SetSpeed(1.0f);
+ m_editCamera = m_camera->RetType();
+ m_camera->SetType(CAMERA_EDIT);
+
+ m_bRunning = m_script->IsRunning();
+ m_bRealTime = m_bRunning;
+ m_script->SetStepMode(!m_bRealTime);
+
+ button = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( button != 0 )
+ {
+ button->ClearState(STATE_VISIBLE);
+ }
+
+ pos = m_editFinalPos = m_editActualPos = m_main->RetWindowPos();
+ dim = m_editFinalDim = m_editActualDim = m_main->RetWindowDim();
+ pw = m_interface->CreateWindows(pos, dim, 8, EVENT_WINDOW3);
+ if ( pw == 0 ) return;
+ pw->SetState(STATE_SHADOW);
+ pw->SetRedim(TRUE); // avant SetName !
+ pw->SetMovable(TRUE);
+ pw->SetClosable(TRUE);
+ GetResource(RES_TEXT, RT_STUDIO_TITLE, res);
+ pw->SetName(res);
+ pw->SetMinDim(FPOINT(0.49f, 0.50f));
+ pw->SetMaximized(m_bEditMaximized);
+ pw->SetMinimized(m_bEditMinimized);
+ m_main->SetEditFull(m_bEditMaximized);
+
+ edit = pw->CreateEdit(pos, dim, 0, EVENT_STUDIO_EDIT);
+ if ( edit == 0 ) return;
+ edit->SetState(STATE_SHADOW);
+ edit->SetInsideScroll(FALSE);
+//? if ( m_bRunning ) edit->SetEdit(FALSE);
+ edit->SetMaxChar(EDITSTUDIOMAX);
+ edit->SetFontType(FONT_COURIER);
+ edit->SetFontStretch(0.7f);
+ edit->SetDisplaySpec(TRUE);
+ edit->SetAutoIndent(m_engine->RetEditIndentMode());
+ m_script->PutScript(edit, name);
+ ColorizeScript(edit);
+
+ ViewEditScript();
+
+ list = pw->CreateList(pos, dim, 1, EVENT_STUDIO_LIST, 1.2f);
+ list->SetState(STATE_SHADOW);
+ list->SetFontType(FONT_COURIER);
+ list->SetSelectCap(FALSE);
+ list->SetFontSize(SMALLFONT*0.85f);
+//? list->SetFontStretch(1.0f);
+
+ button = pw->CreateButton(pos, dim, 56, EVENT_STUDIO_NEW);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 57, EVENT_STUDIO_OPEN);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 58, EVENT_STUDIO_SAVE);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 59, EVENT_STUDIO_UNDO);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 60, EVENT_STUDIO_CUT);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 61, EVENT_STUDIO_COPY);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 62, EVENT_STUDIO_PASTE);
+ button->SetState(STATE_SHADOW);
+ slider = pw->CreateSlider(pos, dim, 0, EVENT_STUDIO_SIZE);
+ slider->SetState(STATE_SHADOW);
+ slider->SetVisibleValue((m_main->RetFontSize()-9.0f)/6.0f);
+ pw->CreateGroup(pos, dim, 19, EVENT_LABEL1); // logo SatCom
+ button = pw->CreateButton(pos, dim, 128+57, EVENT_STUDIO_TOOL);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 128+60, EVENT_STUDIO_HELP);
+ button->SetState(STATE_SHADOW);
+
+ button = pw->CreateButton(pos, dim, -1, EVENT_STUDIO_OK);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, -1, EVENT_STUDIO_CANCEL);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 64+23, EVENT_STUDIO_COMPILE);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 21, EVENT_STUDIO_RUN);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 64+22, EVENT_STUDIO_REALTIME);
+ button->SetState(STATE_SHADOW);
+ button = pw->CreateButton(pos, dim, 64+29, EVENT_STUDIO_STEP);
+ button->SetState(STATE_SHADOW);
+
+ UpdateFlux();
+ UpdateButtons();
+ AdjustEditScript();
+}
+
+// Repositionne tous les contrôles d'édition.
+
+void CStudio::AdjustEditScript()
+{
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+ CGroup* group;
+ CSlider* slider;
+ CList* list;
+ FPOINT wpos, wdim, pos, dim, ppos, ddim;
+ float hList;
+
+ wpos = m_editActualPos;
+ wdim = m_editActualDim;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 )
+ {
+ pw->SetPos(wpos);
+ pw->SetDim(wdim);
+ wdim = pw->RetDim();
+ }
+
+ if ( m_bRunning ) hList = 80.0f/480.0f;
+ else hList = 20.0f/480.0f;
+
+ pos.x = wpos.x+0.01f;
+ pos.y = wpos.y+0.09f+hList;
+ dim.x = wdim.x-0.02f;
+ dim.y = wdim.y-0.22f-hList;
+ edit = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( edit != 0 )
+ {
+ edit->SetPos(pos);
+ edit->SetDim(dim);
+ }
+
+ pos.x = wpos.x+0.01f;
+ pos.y = wpos.y+0.09f;
+ dim.x = wdim.x-0.02f;
+ dim.y = hList;
+ list = (CList*)pw->SearchControl(EVENT_STUDIO_LIST);
+ if ( list != 0 )
+ {
+ list->SetPos(pos);
+ list->SetDim(dim);
+ }
+
+ dim.x = 0.04f;
+ dim.y = 0.04f*1.5f;
+ dim.y = 25.0f/480.0f;
+
+ pos.y = wpos.y+wdim.y-dim.y-0.06f;
+ pos.x = wpos.x+0.01f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_NEW);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.05f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_OPEN);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.09f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_SAVE);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.14f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_UNDO);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.19f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_CUT);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.23f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_COPY);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.27f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_PASTE);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.32f;
+ slider = (CSlider*)pw->SearchControl(EVENT_STUDIO_SIZE);
+ if ( slider != 0 )
+ {
+ ppos = pos;
+ ddim.x = dim.x*0.7f;
+ ddim.y = dim.y;
+ ppos.y -= 3.0f/480.0f;
+ ddim.y += 6.0f/480.0f;
+ slider->SetPos(ppos);
+ slider->SetDim(ddim);
+ }
+ pos.x = wpos.x+0.36f;
+ group = (CGroup*)pw->SearchControl(EVENT_LABEL1);
+ if ( group != 0 )
+ {
+ group->SetPos(pos);
+ group->SetDim(dim);
+ }
+ pos.x = wpos.x+0.40f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_TOOL);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.44f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_HELP);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+
+ pos.y = wpos.y+0.02f;
+ pos.x = wpos.x+0.01f;
+ dim.x = 80.0f/640.0f;
+ dim.y = 25.0f/480.0f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_OK);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.14f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_CANCEL);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.28f;
+ dim.x = dim.y*0.75f;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_COMPILE);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.28f+dim.x*1;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_RUN);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.28f+dim.x*2;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_REALTIME);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+ pos.x = wpos.x+0.28f+dim.x*3;
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_STEP);
+ if ( button != 0 )
+ {
+ button->SetPos(pos);
+ button->SetDim(dim);
+ }
+}
+
+// Fin de l'édition d'un programme.
+
+BOOL CStudio::StopEditScript(BOOL bCancel)
+{
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+ char buffer[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return FALSE;
+
+ if ( !bCancel && !m_script->IsRunning() )
+ {
+ edit = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( edit != 0 )
+ {
+ if ( !m_script->GetScript(edit) ) // compile
+ {
+ m_script->GetError(buffer);
+ SetInfoText(buffer, FALSE);
+ return FALSE;
+ }
+ }
+ }
+ m_script->SetStepMode(FALSE);
+
+ m_interface->DeleteControl(EVENT_WINDOW3);
+
+ button = (CButton*)m_interface->SearchControl(EVENT_BUTTON_QUIT);
+ if ( button != 0 )
+ {
+ button->SetState(STATE_VISIBLE);
+ }
+
+ if ( !m_bInitPause ) m_engine->SetPause(FALSE);
+ m_sound->MuteAll(FALSE);
+ m_main->SetEditLock(FALSE, TRUE);
+ m_camera->SetType(m_editCamera);
+ return TRUE;
+}
+
+// Spécifie le message à afficher.
+// Les messages non cliquables restent 8 secondes, même si un
+// message cliquable est affiché avant.
+
+void CStudio::SetInfoText(char *text, BOOL bClickable)
+{
+ CWindow* pw;
+ CList* list;
+ char res[100];
+
+ if ( bClickable && m_fixInfoTextTime > 0.0f ) return;
+ if ( !bClickable ) m_fixInfoTextTime = 8.0f;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return;
+
+ list = (CList*)pw->SearchControl(EVENT_STUDIO_LIST);
+ if ( list == 0 ) return;
+
+ list->Flush(); // juste le texte
+ list->SetName(0, text);
+
+ if ( text[0] == 0 ) bClickable = FALSE;
+ list->SetSelectCap(bClickable);
+
+ if ( bClickable )
+ {
+ GetResource(RES_TEXT, RT_STUDIO_LISTTT, res);
+ list->SetTooltip(res);
+ list->SetState(STATE_ENABLE);
+ }
+ else
+ {
+ list->SetTooltip("");
+//? list->ClearState(STATE_ENABLE);
+ list->SetState(STATE_ENABLE, text[0] != 0);
+ }
+}
+
+
+// Changement de la taille l'édition d'un programme.
+
+void CStudio::ViewEditScript()
+{
+ CWindow* pw;
+ CEdit* edit;
+ POINT dim;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( edit == 0 ) return;
+
+ dim = m_engine->RetDim();
+ edit->SetFontSize(m_main->RetFontSize()/(dim.x/640.0f));
+}
+
+
+// Met à jour le mode de fonctionnement.
+
+void CStudio::UpdateFlux()
+{
+ if ( m_bRunning )
+ {
+#if 1
+ if ( m_bRealTime ) // run ?
+ {
+ m_engine->SetPause(FALSE);
+ m_sound->MuteAll(FALSE);
+ }
+ else // step by step ?
+ {
+ m_engine->SetPause(TRUE);
+ m_sound->MuteAll(TRUE);
+ }
+#else
+ m_engine->SetPause(FALSE);
+ m_sound->MuteAll(FALSE);
+#endif
+ }
+ else // stop ?
+ {
+ m_engine->SetPause(TRUE);
+ m_sound->MuteAll(TRUE);
+ }
+}
+
+// Met à jour les boutons.
+
+void CStudio::UpdateButtons()
+{
+ CWindow* pw;
+ CEdit* edit;
+ CButton* button;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return;
+
+ edit = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( edit == 0 ) return;
+
+ if ( m_bRunning )
+ {
+ edit->SetIcon(1); // fond rouge
+ edit->SetEditCap(FALSE); // juste pour voir
+ edit->SetHiliteCap(TRUE);
+ }
+ else
+ {
+ edit->SetIcon(0); // fond standard
+ edit->SetEditCap(TRUE);
+ edit->SetHiliteCap(TRUE);
+ }
+
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_COMPILE);
+ if ( button == 0 ) return;
+ button->SetState(STATE_ENABLE, !m_bRunning);
+
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_RUN);
+ if ( button == 0 ) return;
+ button->SetIcon(m_bRunning?8:21); // stop/run
+
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_REALTIME);
+ if ( button == 0 ) return;
+ button->SetIcon(m_bRealTime?64+22:64+21);
+ button->SetState(STATE_ENABLE, (!m_bRunning || !m_script->IsContinue()));
+
+ button = (CButton*)pw->SearchControl(EVENT_STUDIO_STEP);
+ if ( button == 0 ) return;
+ button->SetState(STATE_ENABLE, (m_bRunning && !m_bRealTime && !m_script->IsContinue()));
+}
+
+
+// Début de l'affichage d'un dialogue.
+
+void CStudio::StartDialog(StudioDialog type)
+{
+ CWindow* pw;
+ CButton* pb;
+ CCheck* pc;
+ CLabel* pla;
+ CList* pli;
+ CEdit* pe;
+ FPOINT pos, dim;
+ char name[100];
+
+ m_dialog = type;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW6);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW7);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW8);
+ if ( pw != 0 ) pw->ClearState(STATE_ENABLE);
+
+ if ( m_dialog == SD_OPEN ||
+ m_dialog == SD_SAVE )
+ {
+ pos = m_main->RetIOPos();
+ dim = m_main->RetIODim();
+ }
+//? pw = m_interface->CreateWindows(pos, dim, 8, EVENT_WINDOW9);
+ pw = m_interface->CreateWindows(pos, dim, m_dialog==SD_OPEN?14:13, EVENT_WINDOW9);
+ pw->SetState(STATE_SHADOW);
+ pw->SetMovable(TRUE);
+ pw->SetClosable(TRUE);
+ pw->SetMinDim(FPOINT(320.0f/640.0f, (121.0f+18.0f*4)/480.0f));
+ if ( m_dialog == SD_OPEN ) GetResource(RES_TEXT, RT_IO_OPEN, name);
+ if ( m_dialog == SD_SAVE ) GetResource(RES_TEXT, RT_IO_SAVE, name);
+ pw->SetName(name);
+
+ pos = FPOINT(0.0f, 0.0f);
+ dim = FPOINT(0.0f, 0.0f);
+
+ if ( m_dialog == SD_OPEN ||
+ m_dialog == SD_SAVE )
+ {
+ GetResource(RES_TEXT, RT_IO_LIST, name);
+ pla = pw->CreateLabel(pos, dim, 0, EVENT_DIALOG_LABEL1, name);
+ pla->SetJustif(1);
+
+ pli = pw->CreateList(pos, dim, 0, EVENT_DIALOG_LIST);
+ pli->SetState(STATE_SHADOW);
+
+ GetResource(RES_TEXT, RT_IO_NAME, name);
+ pla = pw->CreateLabel(pos, dim, 0, EVENT_DIALOG_LABEL2, name);
+ pla->SetJustif(1);
+
+ pe = pw->CreateEdit(pos, dim, 0, EVENT_DIALOG_EDIT);
+ pe->SetState(STATE_SHADOW);
+ if ( m_dialog == SD_SAVE )
+ {
+ pe->SetText(m_script->RetFilename());
+ }
+
+ GetResource(RES_TEXT, RT_IO_DIR, name);
+ pla = pw->CreateLabel(pos, dim, 0, EVENT_DIALOG_LABEL3, name);
+ pla->SetJustif(1);
+
+ pc = pw->CreateCheck(pos, dim, 0, EVENT_DIALOG_CHECK1);
+ GetResource(RES_TEXT, RT_IO_PRIVATE, name);
+ pc->SetName(name);
+ pc->SetState(STATE_SHADOW);
+#if _POLISH
+ pc->SetFontSize(8.0f);
+#endif
+
+ pc = pw->CreateCheck(pos, dim, 0, EVENT_DIALOG_CHECK2);
+ GetResource(RES_TEXT, RT_IO_PUBLIC, name);
+ pc->SetName(name);
+ pc->SetState(STATE_SHADOW);
+#if _POLISH
+ pc->SetFontSize(8.0f);
+#endif
+
+ pb = pw->CreateButton(pos, dim, -1, EVENT_DIALOG_OK);
+ pb->SetState(STATE_SHADOW);
+ if ( m_dialog == SD_OPEN ) GetResource(RES_TEXT, RT_IO_OPEN, name);
+ if ( m_dialog == SD_SAVE ) GetResource(RES_TEXT, RT_IO_SAVE, name);
+ pb->SetName(name);
+
+ pb = pw->CreateButton(pos, dim, -1, EVENT_DIALOG_CANCEL);
+ pb->SetState(STATE_SHADOW);
+ GetResource(RES_EVENT, EVENT_DIALOG_CANCEL, name);
+ pb->SetName(name);
+
+ AdjustDialog();
+ UpdateDialogList();
+ UpdateDialogPublic();
+ UpdateDialogAction();
+
+ pe->SetCursor(999, 0); // sélectionne tout
+ pe->SetFocus(TRUE);
+ }
+
+ m_main->SetSatComLock(TRUE); // impossible d'utiliser le SatCom
+}
+
+// Fin de l'affichage d'un dialogue.
+
+void CStudio::StopDialog()
+{
+ CWindow* pw;
+
+ if ( m_dialog == SD_NULL ) return;
+ m_dialog = SD_NULL;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW0);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW1);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW4);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW5);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW6);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW7);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW8);
+ if ( pw != 0 ) pw->SetState(STATE_ENABLE);
+
+ m_interface->DeleteControl(EVENT_WINDOW9);
+ m_main->SetSatComLock(FALSE); // possible d'utiliser le SatCom
+}
+
+// Ajuste tous les contrôles de dialogue suite à un changement de géométrie.
+
+void CStudio::AdjustDialog()
+{
+ CWindow* pw;
+ CButton* pb;
+ CCheck* pc;
+ CLabel* pla;
+ CList* pli;
+ CEdit* pe;
+ FPOINT wpos, wdim, ppos, ddim;
+ int nli, nch;
+ char name[100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+
+ wpos = pw->RetPos();
+ wdim = pw->RetDim();
+ pw->SetPos(wpos); // pour déplacer les boutons de la barre de titre
+
+ if ( m_dialog == SD_OPEN ||
+ m_dialog == SD_SAVE )
+ {
+ ppos.x = wpos.x+10.0f/640.0f;
+ ppos.y = wpos.y+wdim.y-55.0f/480.0f;
+ ddim.x = wdim.x-20.0f/640.0f;
+ ddim.y = 20.0f/480.0f;
+ pla = (CLabel*)pw->SearchControl(EVENT_DIALOG_LABEL1);
+ if ( pla != 0 )
+ {
+ pla->SetPos(ppos);
+ pla->SetDim(ddim);
+ }
+
+ nli = (int)((wdim.y-120.0f/480.0f)/(18.0f/480.0f));
+ ddim.y = nli*18.0f/480.0f+9.0f/480.0f;
+ ppos.y = wpos.y+wdim.y-48.0f/480.0f-ddim.y;
+ pli = (CList*)pw->SearchControl(EVENT_DIALOG_LIST);
+ if ( pli != 0 )
+ {
+ pli->SetPos(ppos);
+ pli->SetDim(ddim);
+ pli->SetTabs(0, ddim.x-(50.0f+130.0f+16.0f)/640.0f);
+ pli->SetTabs(1, 50.0f/640.0f, -1);
+ pli->SetTabs(2, 130.0f/640.0f);
+//? pli->ShowSelect();
+ }
+
+ ppos.y = wpos.y+30.0f/480.0f;
+ ddim.x = 50.0f/640.0f;
+ ddim.y = 20.0f/480.0f;
+ pla = (CLabel*)pw->SearchControl(EVENT_DIALOG_LABEL2);
+ if ( pla != 0 )
+ {
+ pla->SetPos(ppos);
+ pla->SetDim(ddim);
+ }
+
+ ppos.x += 50.0f/640.0f;
+ ppos.y = wpos.y+36.0f/480.0f;
+ ddim.x = wdim.x-170.0f/640.0f;
+ pe = (CEdit*)pw->SearchControl(EVENT_DIALOG_EDIT);
+ if ( pe != 0 )
+ {
+ pe->SetPos(ppos);
+ pe->SetDim(ddim);
+
+ nch = (int)((ddim.x*640.0f-22.0f)/8.0f);
+ pe->GetText(name, 100);
+ pe->SetMaxChar(nch);
+ name[nch] = 0; // tronque le texte selon max
+ pe->SetText(name);
+ }
+
+ ppos.x = wpos.x+10.0f/640.0f;
+ ppos.y = wpos.y+5.0f/480.0f;
+ ddim.x = 50.0f/640.0f;
+ ddim.y = 16.0f/480.0f;
+ pla = (CLabel*)pw->SearchControl(EVENT_DIALOG_LABEL3);
+ if ( pla != 0 )
+ {
+ pla->SetPos(ppos);
+ pla->SetDim(ddim);
+ }
+
+ ppos.x += 50.0f/640.0f;
+ ppos.y = wpos.y+12.0f/480.0f;
+ ddim.x = 70.0f/640.0f;
+ pc = (CCheck*)pw->SearchControl(EVENT_DIALOG_CHECK1);
+ if ( pc != 0 )
+ {
+ pc->SetPos(ppos);
+ pc->SetDim(ddim);
+ }
+
+ ppos.x += 80.0f/640.0f;
+ pc = (CCheck*)pw->SearchControl(EVENT_DIALOG_CHECK2);
+ if ( pc != 0 )
+ {
+ pc->SetPos(ppos);
+ pc->SetDim(ddim);
+ }
+
+ ppos.x = wpos.x+wdim.x-100.0f/640.0f;
+ ppos.y = wpos.y+34.0f/480.0f;
+ ddim.x = 90.0f/640.0f;
+ ddim.y = 23.0f/480.0f;
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_OK);
+ if ( pb != 0 )
+ {
+ pb->SetPos(ppos);
+ pb->SetDim(ddim);
+ }
+
+ ppos.y -= 26.0f/480.0f;
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_CANCEL);
+ if ( pb != 0 )
+ {
+ pb->SetPos(ppos);
+ pb->SetDim(ddim);
+ }
+ }
+}
+
+// Gestion de l'événement d'un dialogue.
+
+BOOL CStudio::EventDialog(const Event &event)
+{
+ CWindow* pw;
+ FPOINT wpos, wdim;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return FALSE;
+
+ if ( event.event == EVENT_WINDOW9 ) // fenêtre déplacée ?
+ {
+ wpos = pw->RetPos();
+ wdim = pw->RetDim();
+ m_main->SetIOPos(wpos);
+ m_main->SetIODim(wdim);
+ AdjustDialog();
+ }
+
+ if ( m_dialog == SD_OPEN ||
+ m_dialog == SD_SAVE )
+ {
+ if ( event.event == EVENT_DIALOG_LIST )
+ {
+ UpdateChangeList();
+ }
+ if ( event.event == EVENT_DIALOG_EDIT )
+ {
+ UpdateChangeEdit();
+ }
+
+ if ( event.event == EVENT_DIALOG_CHECK1 ) // private ?
+ {
+ m_main->SetIOPublic(FALSE);
+ UpdateDialogPublic();
+ UpdateDialogList();
+ }
+ if ( event.event == EVENT_DIALOG_CHECK2 ) // public ?
+ {
+ m_main->SetIOPublic(TRUE);
+ UpdateDialogPublic();
+ UpdateDialogList();
+ }
+ }
+
+ if ( event.event == EVENT_DIALOG_OK ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_RETURN) )
+ {
+ if ( m_dialog == SD_OPEN )
+ {
+ if ( !ReadProgram() ) return TRUE;
+ }
+ if ( m_dialog == SD_SAVE )
+ {
+ if ( !WriteProgram() ) return TRUE;
+ }
+
+ StopDialog();
+ return TRUE;
+ }
+
+ if ( event.event == EVENT_DIALOG_CANCEL ||
+ (event.event == EVENT_KEYDOWN && event.param == VK_ESCAPE) ||
+ event.event == pw->RetEventMsgClose() )
+ {
+ StopDialog();
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+// Met à jour le nom suite à un clic dans la liste.
+
+void CStudio::UpdateChangeList()
+{
+ CWindow* pw;
+ CList* pl;
+ CEdit* pe;
+ char name[100];
+ char* p;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_DIALOG_LIST);
+ if ( pl == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_DIALOG_EDIT);
+ if ( pe == 0 ) return;
+
+ strcpy(name, pl->RetName(pl->RetSelect()));
+ name[pe->RetMaxChar()] = 0; // tronque selon lg max éditable
+ p = strchr(name, '\t'); // cherche 1er tabulateur
+ if ( p != 0 ) *p = 0;
+ pe->SetText(name);
+ pe->SetCursor(999, 0); // sélectionne tout
+ pe->SetFocus(TRUE);
+
+ UpdateDialogAction();
+}
+
+// Met à jour la liste suite à un changement dans le nom.
+
+void CStudio::UpdateChangeEdit()
+{
+ CWindow* pw;
+ CList* pl;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_DIALOG_LIST);
+ if ( pl == 0 ) return;
+
+ pl->SetSelect(-1);
+
+ UpdateDialogAction();
+}
+
+// Met à jour le bouton d'action.
+
+void CStudio::UpdateDialogAction()
+{
+ CWindow* pw;
+ CEdit* pe;
+ CButton* pb;
+ char name[100];
+ int len, i;
+ BOOL bError;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+ pe = (CEdit*)pw->SearchControl(EVENT_DIALOG_EDIT);
+ if ( pe == 0 ) return;
+ pb = (CButton*)pw->SearchControl(EVENT_DIALOG_OK);
+ if ( pb == 0 ) return;
+
+ pe->GetText(name, 100);
+ len = strlen(name);
+ if ( len == 0 )
+ {
+ bError = TRUE;
+ }
+ else
+ {
+ bError = FALSE;
+ for ( i=0 ; i<len ; i++ )
+ {
+ if ( name[i] == '*' ||
+ name[i] == '?' ||
+ name[i] == ':' ||
+ name[i] == '<' ||
+ name[i] == '>' ||
+ name[i] == '"' ||
+ name[i] == '|' ||
+ name[i] == '/' ||
+ name[i] == '\\' ) bError = TRUE;
+ }
+ }
+
+ pb->SetState(STATE_ENABLE, !bError);
+}
+
+// Met à jour les boutons private/public.
+
+void CStudio::UpdateDialogPublic()
+{
+ CWindow* pw;
+ CCheck* pc;
+ CLabel* pl;
+ char name[100];
+ char dir[_MAX_FNAME];
+ char text[_MAX_FNAME+100];
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+
+ pc = (CCheck*)pw->SearchControl(EVENT_DIALOG_CHECK1);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, !m_main->RetIOPublic());
+ }
+
+ pc = (CCheck*)pw->SearchControl(EVENT_DIALOG_CHECK2);
+ if ( pc != 0 )
+ {
+ pc->SetState(STATE_CHECK, m_main->RetIOPublic());
+ }
+
+ pl = (CLabel*)pw->SearchControl(EVENT_DIALOG_LABEL1);
+ if ( pl != 0 )
+ {
+ GetResource(RES_TEXT, RT_IO_LIST, name);
+ SearchDirectory(dir, FALSE);
+ sprintf(text, name, dir);
+ pl->SetName(text, FALSE);
+ }
+}
+
+// Remplit la liste avec tous les programmes sauvés.
+
+void CStudio::UpdateDialogList()
+{
+ CWindow* pw;
+ CList* pl;
+ long hFile;
+ struct _finddata_t fileBuffer;
+ struct _finddata_t* listBuffer;
+ BOOL bDo;
+ char dir[_MAX_FNAME];
+ char temp[_MAX_FNAME];
+ int nbFilenames, i;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return;
+ pl = (CList*)pw->SearchControl(EVENT_DIALOG_LIST);
+ if ( pl == 0 ) return;
+ pl->Flush();
+
+ nbFilenames = 0;
+ listBuffer = (_finddata_t*)malloc(sizeof(_finddata_t)*1000);
+
+ SearchDirectory(dir, FALSE);
+ strcat(dir, "*"); // liste tout
+ hFile = _findfirst(dir, &fileBuffer);
+ if ( hFile != -1 )
+ {
+ do
+ {
+ if ( (fileBuffer.attrib & _A_SUBDIR) == 0 )
+ {
+ listBuffer[nbFilenames++] = fileBuffer;
+ }
+ }
+ while ( _findnext(hFile, &fileBuffer) == 0 && nbFilenames < 1000 );
+ }
+ do // trie tous les noms :
+ {
+ bDo = FALSE;
+ for ( i=0 ; i<nbFilenames-1 ; i++ )
+ {
+ if ( strcmp(listBuffer[i].name, listBuffer[i+1].name) > 0 )
+ {
+ fileBuffer = listBuffer[i]; // échange i et i+1
+ listBuffer[i] = listBuffer[i+1];
+ listBuffer[i+1] = fileBuffer;
+ bDo = TRUE;
+ }
+ }
+ }
+ while ( bDo );
+
+ for ( i=0 ; i<nbFilenames ; i++ )
+ {
+ TimeToAscii(listBuffer[i].time_write, dir);
+ sprintf(temp, "%s\t%d \t%s", listBuffer[i].name, listBuffer[i].size, dir);
+ pl->SetName(i, temp);
+ }
+
+ free(listBuffer);
+}
+
+// Construit le nom du dossier où ouvrir/enregistrer.
+// Si le dossier n'existe pas, il est éventuellement créé.
+
+void CStudio::SearchDirectory(char *dir, BOOL bCreate)
+{
+ if ( m_main->RetIOPublic() )
+ {
+ sprintf(dir, "%s\\", m_main->RetPublicDir());
+ }
+ else
+ {
+ sprintf(dir, "%s\\%s\\Program\\", m_main->RetSavegameDir(), m_main->RetGamerName());
+ }
+
+ if ( bCreate )
+ {
+ _mkdir(dir); // si n'existe pas encore !
+ }
+}
+
+// Lit un nouveau programme.
+
+BOOL CStudio::ReadProgram()
+{
+ CWindow* pw;
+ CEdit* pe;
+ char filename[100];
+ char dir[100];
+ char* p;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return FALSE;
+
+ pe = (CEdit*)pw->SearchControl(EVENT_DIALOG_EDIT);
+ if ( pe == 0 ) return FALSE;
+ pe->GetText(filename, 100);
+ if ( filename[0] == 0 ) return FALSE;
+
+ p = strstr(filename, ".txt");
+ if ( p == 0 || p != filename+strlen(filename)-4 )
+ {
+ strcat(filename, ".txt");
+ }
+ SearchDirectory(dir, TRUE);
+ strcat(dir, filename);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return FALSE;
+ pe = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( pe == 0 ) return FALSE;
+
+ if ( !pe->ReadText(dir) ) return FALSE;
+
+ m_script->SetFilename(filename);
+ ColorizeScript(pe);
+ return TRUE;
+}
+
+// Ecrit le programme actuel.
+
+BOOL CStudio::WriteProgram()
+{
+ CWindow* pw;
+ CEdit* pe;
+ char filename[100];
+ char dir[100];
+ char* p;
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW9);
+ if ( pw == 0 ) return FALSE;
+
+ pe = (CEdit*)pw->SearchControl(EVENT_DIALOG_EDIT);
+ if ( pe == 0 ) return FALSE;
+ pe->GetText(filename, 100);
+ if ( filename[0] == 0 ) return FALSE;
+
+ p = strstr(filename, ".txt");
+ if ( p == 0 || p != filename+strlen(filename)-4 )
+ {
+ strcat(filename, ".txt");
+ }
+ SearchDirectory(dir, TRUE);
+ strcat(dir, filename);
+
+ pw = (CWindow*)m_interface->SearchControl(EVENT_WINDOW3);
+ if ( pw == 0 ) return FALSE;
+ pe = (CEdit*)pw->SearchControl(EVENT_STUDIO_EDIT);
+ if ( pe == 0 ) return FALSE;
+
+ if ( !pe->WriteText(dir) ) return FALSE;
+
+ m_script->SetFilename(filename);
+ return TRUE;
+}
+
diff --git a/src/studio.h b/src/studio.h
new file mode 100644
index 0000000..1da9e10
--- /dev/null
+++ b/src/studio.h
@@ -0,0 +1,97 @@
+// studio.h
+
+#ifndef _STUDIO_H_
+#define _STUDIO_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CEvent;
+class CRobotMain;
+class CCamera;
+class CSound;
+class CInterface;
+class CScript;
+class CList;
+class CEdit;
+
+
+
+enum StudioDialog
+{
+ SD_NULL,
+ SD_OPEN,
+ SD_SAVE,
+ SD_FIND,
+ SD_REPLACE,
+};
+
+
+
+class CStudio
+{
+public:
+ CStudio(CInstanceManager* iMan);
+ ~CStudio();
+
+ BOOL EventProcess(const Event &event);
+
+ void StartEditScript(CScript *script, char* name, int rank);
+ BOOL StopEditScript(BOOL bCancel);
+
+protected:
+ BOOL EventFrame(const Event &event);
+ void SearchToken(CEdit* edit);
+ void ColorizeScript(CEdit* edit);
+ void AdjustEditScript();
+ void SetInfoText(char *text, BOOL bClickable);
+ void ViewEditScript();
+ void UpdateFlux();
+ void UpdateButtons();
+
+ void StartDialog(StudioDialog type);
+ void StopDialog();
+ void AdjustDialog();
+ BOOL EventDialog(const Event &event);
+ void UpdateChangeList();
+ void UpdateChangeEdit();
+ void UpdateDialogAction();
+ void UpdateDialogPublic();
+ void UpdateDialogList();
+ void SearchDirectory(char *dir, BOOL bCreate);
+ BOOL ReadProgram();
+ BOOL WriteProgram();
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CEvent* m_event;
+ CRobotMain* m_main;
+ CCamera* m_camera;
+ CSound* m_sound;
+ CInterface* m_interface;
+
+ int m_rank;
+ CScript* m_script;
+
+ BOOL m_bEditMaximized;
+ BOOL m_bEditMinimized;
+
+ CameraType m_editCamera;
+ FPOINT m_editActualPos;
+ FPOINT m_editActualDim;
+ FPOINT m_editFinalPos;
+ FPOINT m_editFinalDim;
+
+ float m_time;
+ float m_fixInfoTextTime;
+ BOOL m_bRunning;
+ BOOL m_bRealTime;
+ BOOL m_bInitPause;
+ char m_helpFilename[100];
+
+ StudioDialog m_dialog;
+};
+
+
+#endif //_STUDIO_H_
diff --git a/src/t.txt b/src/t.txt
new file mode 100644
index 0000000..9dd81fb
--- /dev/null
+++ b/src/t.txt
@@ -0,0 +1,11 @@
+extern void object::Go()
+{
+//float a = energyLevel;
+//message(a);
+
+//object item=energyCell;
+//float i = item.energyLevel;
+//message(i);
+float i = energyCell.energyLevel;
+
+}
diff --git a/src/target.cpp b/src/target.cpp
new file mode 100644
index 0000000..b0b64c2
--- /dev/null
+++ b/src/target.cpp
@@ -0,0 +1,271 @@
+// target.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "robotmain.h"
+#include "object.h"
+#include "restext.h"
+#include "target.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTarget::CTarget(CInstanceManager* iMan) : CControl(iMan)
+{
+ CControl::CControl(iMan);
+}
+
+// Destructeur de l'objet.
+
+CTarget::~CTarget()
+{
+ CControl::~CControl();
+}
+
+
+// Crée un nouveau bouton.
+
+BOOL CTarget::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+
+ return TRUE;
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTarget::EventProcess(const Event &event)
+{
+#if 0
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ m_engine->SetMouseType(D3DMOUSETARGET);
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ Event newEvent = event;
+ newEvent.event = EVENT_OBJECT_FIRE;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+#else
+ CObject* pObj;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return TRUE;
+ if ( m_state & STATE_DEAD ) return TRUE;
+
+ CControl::EventProcess(event);
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ m_main->SetFriendAim(FALSE);
+
+ if ( CControl::Detect(event.pos) )
+ {
+ pObj = DetectFriendObject(event.pos);
+ if ( pObj == 0 )
+ {
+ m_engine->SetMouseType(D3DMOUSETARGET);
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ else
+ {
+ m_main->SetFriendAim(TRUE);
+ m_engine->SetMouseType(D3DMOUSENORM);
+ }
+ }
+ }
+
+ if ( event.event == EVENT_LBUTTONDOWN &&
+ (m_state & STATE_VISIBLE) &&
+ (m_state & STATE_ENABLE) )
+ {
+ if ( CControl::Detect(event.pos) )
+ {
+ if ( !m_main->RetFriendAim() )
+ {
+ Event newEvent = event;
+ newEvent.event = EVENT_OBJECT_FIRE;
+ m_event->AddEvent(newEvent);
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+#endif
+}
+
+
+// Dessine le bouton.
+
+void CTarget::Draw()
+{
+ // C'est totalement invisible !
+}
+
+
+// Retourne le tooltip.
+
+BOOL CTarget::GetTooltip(FPOINT pos, char* name)
+{
+#if 0
+ if ( (m_state&STATE_VISIBLE) && Detect(pos) ) // dans la fenêtre ?
+ {
+ strcpy(name, m_tooltip);
+ return TRUE; // ne détecte pas les objets dessous !
+ }
+
+ return FALSE;
+#else
+//? CObject* pObj;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return FALSE;
+
+ if ( (m_state&STATE_VISIBLE) && Detect(pos) ) // dans la fenêtre ?
+ {
+//? pObj = DetectFriendObject(pos);
+//? if ( pObj == 0 )
+ if ( !m_main->RetFriendAim() )
+ {
+ strcpy(name, m_tooltip);
+ return TRUE; // ne détecte pas les objets dessous !
+ }
+ }
+
+ return FALSE;
+#endif
+}
+
+
+// Détecte l'objet visé par la souris.
+
+CObject* CTarget::DetectFriendObject(FPOINT pos)
+{
+ ObjectType type;
+ CObject *pObj, *pTarget;
+ int objRank, i, j, rank;
+
+ objRank = m_engine->DetectObject(pos);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetProxyActivate() ) continue;
+ if ( pObj->RetSelect() ) continue;
+
+ pTarget = 0;
+ type = pObj->RetType();
+ 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_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_TOTO ||
+ type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr )
+ {
+ pTarget = pObj;
+ }
+ else if ( (type == OBJECT_POWER ||
+ type == OBJECT_ATOMIC ) &&
+ pObj->RetTruck() != 0 ) // pile utilisée ?
+ {
+ pTarget = pObj->RetTruck();
+ if ( pTarget->RetType() == OBJECT_MOBILEtg )
+ {
+ pTarget = 0;
+ }
+ }
+
+ for ( j=0 ; j<OBJECTMAXPART ; j++ )
+ {
+ rank = pObj->RetObjectRank(j);
+ if ( rank == -1 ) continue;
+ if ( rank != objRank ) continue;
+ return pTarget;
+ }
+ }
+ return 0;
+}
+
diff --git a/src/target.h b/src/target.h
new file mode 100644
index 0000000..2f479dc
--- /dev/null
+++ b/src/target.h
@@ -0,0 +1,34 @@
+// target.h
+
+#ifndef _TARGET_H_
+#define _TARGET_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CObject;
+
+
+
+class CTarget : public CControl
+{
+public:
+ CTarget(CInstanceManager* iMan);
+ ~CTarget();
+
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+
+ BOOL EventProcess(const Event &event);
+ void Draw();
+ BOOL GetTooltip(FPOINT pos, char* name);
+
+protected:
+ CObject* DetectFriendObject(FPOINT pos);
+
+protected:
+};
+
+
+#endif //_TARGET_H_
diff --git a/src/task.cpp b/src/task.cpp
new file mode 100644
index 0000000..7b3dd84
--- /dev/null
+++ b/src/task.cpp
@@ -0,0 +1,93 @@
+// task.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "motion.h"
+#include "camera.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "displaytext.h"
+#include "task.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTask::CTask(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_light = (CLight*)m_iMan->SearchInstance(CLASS_LIGHT);
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+ m_camera = (CCamera*)m_iMan->SearchInstance(CLASS_CAMERA);
+ m_main = (CRobotMain*)m_iMan->SearchInstance(CLASS_MAIN);
+ m_displayText = (CDisplayText*)m_iMan->SearchInstance(CLASS_DISPLAYTEXT);
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+
+ m_object = object;
+ m_physics = m_object->RetPhysics();
+ m_brain = m_object->RetBrain();
+ m_motion = m_object->RetMotion();
+}
+
+// Destructeur de l'objet.
+
+CTask::~CTask()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTask::EventProcess(const Event &event)
+{
+ return TRUE;
+}
+
+
+// Indique si l'action est terminée.
+
+Error CTask::IsEnded()
+{
+ return ERR_STOP;
+}
+
+
+// Indique si l'action est en cours.
+
+BOOL CTask::IsBusy()
+{
+ return TRUE;
+}
+
+
+// Termine brutalement l'action en cours.
+
+BOOL CTask::Abort()
+{
+ return TRUE;
+}
+
+
diff --git a/src/task.h b/src/task.h
new file mode 100644
index 0000000..5b6041d
--- /dev/null
+++ b/src/task.h
@@ -0,0 +1,70 @@
+// task.h
+
+#ifndef _TASK_H_
+#define _TASK_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CEngine;
+class CLight;
+class CParticule;
+class CTerrain;
+class CWater;
+class CCamera;
+class CBrain;
+class CPhysics;
+class CMotion;
+class CObject;
+class CRobotMain;
+class CDisplayText;
+class CSound;
+
+
+#define TAKE_DIST 6.0f // distance d'un objet pour le prendre
+#define TAKE_DIST_OTHER 1.5f // distance supplémentaire si sur ami
+
+//?#define ARM_NEUTRAL_ANGLE1 155.0f*PI/180.0f
+//?#define ARM_NEUTRAL_ANGLE2 -125.0f*PI/180.0f
+//?#define ARM_NEUTRAL_ANGLE3 -45.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE1 110.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE2 -130.0f*PI/180.0f
+#define ARM_NEUTRAL_ANGLE3 -50.0f*PI/180.0f
+
+#define ARM_STOCK_ANGLE1 110.0f*PI/180.0f
+#define ARM_STOCK_ANGLE2 -100.0f*PI/180.0f
+#define ARM_STOCK_ANGLE3 -70.0f*PI/180.0f
+
+
+class CTask
+{
+public:
+ CTask(CInstanceManager* iMan, CObject* object);
+ virtual ~CTask();
+
+ virtual BOOL EventProcess(const Event &event);
+ virtual Error IsEnded();
+ virtual BOOL IsBusy();
+ virtual BOOL Abort();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CLight* m_light;
+ CParticule* m_particule;
+ CTerrain* m_terrain;
+ CWater* m_water;
+ CCamera* m_camera;
+ CMotion* m_motion;
+ CBrain* m_brain;
+ CPhysics* m_physics;
+ CObject* m_object;
+ CRobotMain* m_main;
+ CDisplayText* m_displayText;
+ CSound* m_sound;
+};
+
+
+#endif //_TASK_H_
diff --git a/src/taskadvance.cpp b/src/taskadvance.cpp
new file mode 100644
index 0000000..365562f
--- /dev/null
+++ b/src/taskadvance.cpp
@@ -0,0 +1,143 @@
+// taskadvance.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskadvance.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskAdvance::CTaskAdvance(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskAdvance::~CTaskAdvance()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskAdvance::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_fixTime += event.rTime;
+
+ // Objet momentanément immobile (fourmi sur le dos) ?
+ if ( m_object->RetFixed() )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_bError = TRUE;
+ return TRUE;
+ }
+
+ m_timeLimit -= event.rTime;
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskAdvance::Start(float length)
+{
+ m_direction = (length>=0.0f)?1.0f:-1.0f;
+ m_totalLength = Abs(length);
+ m_advanceLength = m_physics->RetLinLength(length);
+ m_startPos = m_object->RetPosition(0);
+ m_lastDist = 0.0f;
+ m_fixTime = 0.0f;
+
+ m_timeLimit = m_physics->RetLinTimeLength(m_totalLength, m_direction)*3.0f;
+ if ( m_timeLimit < 2.0f ) m_timeLimit = 2.0f;
+
+ m_physics->SetMotorSpeedX(m_direction*1.0f); // avance/recule
+ m_physics->SetMotorSpeedY(0.0f);
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskAdvance::IsEnded()
+{
+ D3DVECTOR pos;
+ float length;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError )
+ {
+ return ERR_STOP;
+ }
+
+ if ( m_timeLimit < 0.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ return ERR_MOVE_IMPOSSIBLE;
+ }
+
+ pos = m_object->RetPosition(0);
+ length = Length2d(pos, m_startPos);
+
+ if ( length > m_lastDist ) // avance ?
+ {
+ m_fixTime = 0.0f;
+ }
+ else // n'avance plus ?
+ {
+ if ( m_fixTime > 1.0f ) // depuis plus d'une seconde ?
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ return ERR_MOVE_IMPOSSIBLE;
+ }
+ }
+ m_lastDist = length;
+
+ if ( length >= m_totalLength )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ m_physics->SetLinMotionX(MO_CURSPEED, 0.0f);
+
+ if ( length != 0.0f )
+ {
+ pos = m_startPos+((pos-m_startPos)*m_totalLength/length);
+ m_object->SetPosition(0, pos);
+ }
+ return ERR_STOP;
+ }
+
+ if ( length >= m_advanceLength )
+ {
+ m_physics->SetMotorSpeedX(m_direction*0.1f);
+ }
+ return ERR_CONTINUE;
+}
+
+
diff --git a/src/taskadvance.h b/src/taskadvance.h
new file mode 100644
index 0000000..9ff20ce
--- /dev/null
+++ b/src/taskadvance.h
@@ -0,0 +1,39 @@
+// taskadvance.h
+
+#ifndef _TASKADVANCE_H_
+#define _TASKADVANCE_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskAdvance : public CTask
+{
+public:
+ CTaskAdvance(CInstanceManager* iMan, CObject* object);
+ ~CTaskAdvance();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float length);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_totalLength;
+ float m_advanceLength;
+ float m_direction;
+ float m_timeLimit;
+ D3DVECTOR m_startPos;
+ float m_lastDist;
+ float m_fixTime;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKADVANCE_H_
diff --git a/src/taskbuild.cpp b/src/taskbuild.cpp
new file mode 100644
index 0000000..d4b7d10
--- /dev/null
+++ b/src/taskbuild.cpp
@@ -0,0 +1,806 @@
+// taskbuild.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "light.h"
+#include "particule.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "auto.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "robotmain.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "task.h"
+#include "taskbuild.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskBuild::CTaskBuild(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ int i;
+
+ CTask::CTask(iMan, object);
+
+ m_type = OBJECT_DERRICK;
+ m_time = 0.0f;
+ m_soundChannel = -1;
+
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ m_lightRank[i] = -1;
+ }
+}
+
+// Destructeur de l'objet.
+
+CTaskBuild::~CTaskBuild()
+{
+ int i;
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ if ( m_lightRank[i] == -1 ) continue;
+ m_light->DeleteLight(m_lightRank[i]);
+ }
+}
+
+
+// Crée un batiment.
+
+BOOL CTaskBuild::CreateBuilding(D3DVECTOR pos, float angle)
+{
+ m_building = new CObject(m_iMan);
+ if ( !m_building->CreateBuilding(pos, angle, 0.0f, m_type, 0.0f) )
+ {
+ delete m_building;
+ m_building = 0;
+ return FALSE;
+ }
+ m_building->UpdateMapping();
+ m_building->SetLock(TRUE); // pas encore utilisable
+
+ if ( m_type == OBJECT_DERRICK ) m_buildingHeight = 35.0f;
+ if ( m_type == OBJECT_FACTORY ) m_buildingHeight = 28.0f;
+ if ( m_type == OBJECT_REPAIR ) m_buildingHeight = 30.0f;
+ if ( m_type == OBJECT_STATION ) m_buildingHeight = 13.0f;
+ if ( m_type == OBJECT_CONVERT ) m_buildingHeight = 20.0f;
+ if ( m_type == OBJECT_TOWER ) m_buildingHeight = 30.0f;
+ if ( m_type == OBJECT_RESEARCH ) m_buildingHeight = 22.0f;
+ if ( m_type == OBJECT_RADAR ) m_buildingHeight = 19.0f;
+ if ( m_type == OBJECT_ENERGY ) m_buildingHeight = 20.0f;
+ if ( m_type == OBJECT_LABO ) m_buildingHeight = 16.0f;
+ if ( m_type == OBJECT_NUCLEAR ) m_buildingHeight = 40.0f;
+ if ( m_type == OBJECT_PARA ) m_buildingHeight = 68.0f;
+ if ( m_type == OBJECT_INFO ) m_buildingHeight = 19.0f;
+ m_buildingHeight *= 0.25f;
+
+ m_buildingPos = m_building->RetPosition(0);
+ m_buildingPos.y -= m_buildingHeight;
+ m_building->SetPosition(0, m_buildingPos);
+ return TRUE;
+}
+
+// Crée les lumières pour les effets.
+
+void CTaskBuild::CreateLight()
+{
+ D3DLIGHT7 light;
+ D3DCOLORVALUE color;
+ D3DVECTOR center, pos, dir;
+ FPOINT c, p;
+ float angle;
+ int i;
+
+ if ( !m_engine->RetLightMode() ) return;
+
+ center = m_metal->RetPosition(0);
+
+ angle = 0;
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ m_lightRank[i] = m_light->CreateLight();
+ if ( m_lightRank[i] == -1 ) continue;
+
+ c.x = center.x;
+ c.y = center.z;
+ p.x = center.x+40.0f;
+ p.y = center.z;
+ p = RotatePoint(c, angle, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ pos.y = center.y+40.0f;
+ dir = center-pos;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = 0.0f;
+ light.dcvDiffuse.g = 0.0f;
+ light.dcvDiffuse.b = 0.0f; // blanc (invisible)
+ light.dvPosition.x = pos.x;
+ light.dvPosition.y = pos.y;
+ light.dvPosition.z = pos.z;
+ light.dvDirection.x = dir.x;
+ light.dvDirection.y = dir.y;
+ light.dvDirection.z = dir.z;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+ m_light->SetLight(m_lightRank[i], light);
+
+ color.r = -1.0f;
+ color.g = -1.0f;
+ color.b = -0.5f; // violet
+ color.a = 0.0f;
+ m_light->SetLightColor(m_lightRank[i], color);
+ m_light->SetLightColorSpeed(m_lightRank[i], 1.0f/((1.0f/m_speed)*0.25f));
+
+ angle += (PI*2.0f)/TBMAXLIGHT;
+ }
+
+ m_bBlack = FALSE;
+}
+
+// Fait passer les lumières du noir au blanc.
+
+void CTaskBuild::BlackLight()
+{
+ D3DCOLORVALUE color;
+ int i;
+
+ for ( i=0 ; i<TBMAXLIGHT ; i++ )
+ {
+ if ( m_lightRank[i] == -1 ) continue;
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 0.0f; // blanc (invisible)
+ color.a = 0.0f;
+ m_light->SetLightColor(m_lightRank[i], color);
+ m_light->SetLightColorSpeed(m_lightRank[i], 1.0f/((1.0f/m_speed)*0.75f));
+ }
+
+ m_bBlack = TRUE;
+}
+
+// Gestion d'un événement.
+
+BOOL CTaskBuild::EventProcess(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, dir, speed;
+ FPOINT dim;
+ float a, g, cirSpeed, dist, linSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_time += event.rTime;
+
+ m_progress += event.rTime*m_speed; // ça avance
+
+ if ( m_phase == TBP_TURN ) // rotation préliminaire ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angleY;
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_MOVE ) // avance/recule préliminaire ?
+ {
+ dist = Length(m_object->RetPosition(0), m_metal->RetPosition(0));
+ linSpeed = 0.0f;
+ if ( dist > 30.0f ) linSpeed = 1.0f;
+ if ( dist < 30.0f ) linSpeed = -1.0f;
+ m_physics->SetMotorSpeedX(linSpeed); // avance/recule
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_RECEDE ) // recule terminal ?
+ {
+ m_physics->SetMotorSpeedX(-1.0f); // recule
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_TAKE ) // prend arme ?
+ {
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_PREP ) // prépare ?
+ {
+ return TRUE;
+ }
+
+ if ( m_phase == TBP_TERM ) // termine ?
+ {
+ return TRUE;
+ }
+
+ if ( !m_bBuild ) // batiment à construire ?
+ {
+ m_bBuild = TRUE;
+
+ pos = m_metal->RetPosition(0);
+ a = m_object->RetAngleY(0);
+ if ( !CreateBuilding(pos, a+PI) )
+ {
+ m_metal->SetLock(FALSE); // de nouveau utilisable
+ m_motion->SetAction(-1);
+ m_object->SetObjectParent(14, 0);
+ m_object->SetPosition(14, D3DVECTOR(-1.5f, 0.3f, -1.35f));
+ m_object->SetAngleZ(14, PI);
+ m_camera->FlushEffect();
+ Abort();
+ m_bError = TRUE;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object->RetPosition(0));
+ return FALSE;
+ }
+ CreateLight();
+ }
+
+ pos = m_buildingPos;
+ pos.y += m_buildingHeight*m_progress;
+ m_building->SetPosition(0, pos); // le batiment monte
+
+ m_building->SetZoom(0, m_progress*0.75f+0.25f);
+ m_metal->SetZoom(0, 1.0f-m_progress);
+
+ a = (2.0f-2.0f*m_progress);
+ if ( a > 1.0f ) a = 1.0f;
+ dir.x = (Rand()-0.5f)*a*0.1f;
+ dir.z = (Rand()-0.5f)*a*0.1f;
+ dir.y = (Rand()-0.5f)*a*0.1f;
+ m_building->SetCirVibration(dir);
+
+ if ( !m_bBlack && m_progress >= 0.25f )
+ {
+ BlackLight();
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_metal->RetPosition(0);
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIRE);
+
+ pos = D3DVECTOR(0.0f, 0.5f, 0.0f);
+ mat = m_object->RetWorldMatrix(14);
+ pos = Transform(*mat, pos);
+ speed = m_metal->RetPosition(0);
+ speed.x += (Rand()-0.5f)*5.0f;
+ speed.z += (Rand()-0.5f)*5.0f;
+ speed -= pos;
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFIREZ);
+
+ if ( Rand() < 0.3f )
+ {
+ m_sound->Play(SOUND_BUILD, m_object->RetPosition(0), 0.5f, 1.0f*Rand()*1.5f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskBuild::Start(ObjectType type)
+{
+ D3DVECTOR pos, speed, pv, pm;
+ Error err;
+ float iAngle, oAngle;
+
+ m_type = type;
+ m_lastParticule = 0.0f;
+ m_progress = 0.0f;
+
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+ oAngle = iAngle;
+
+ m_bError = TRUE; // opération impossible
+
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel() ) return ERR_BUILD_WATER;
+
+ if ( !m_physics->RetLand() ) return ERR_BUILD_FLY;
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_BUILD_MOTOR;
+
+ if ( m_object->RetFret() != 0 ) return ERR_MANIP_BUSY;
+
+ m_metal = SearchMetalObject(oAngle, 2.0f, 100.0f, PI*0.25f, err);
+ if ( err == ERR_BUILD_METALNEAR && m_metal != 0 )
+ {
+ err = FlatFloor();
+ if ( err != ERR_OK ) return err;
+ return ERR_BUILD_METALNEAR;
+ }
+ if ( err != ERR_OK ) return err;
+
+ err = FlatFloor();
+ if ( err != ERR_OK ) return err;
+
+ m_metal->SetLock(TRUE); // plus utilisable
+ m_camera->StartCentering(m_object, PI*0.15f, 99.9f, 0.0f, 1.0f);
+
+ m_phase = TBP_TURN; // rotation préliminaire nécessaire
+ m_angleY = oAngle; // angle à atteindre
+
+ pv = m_object->RetPosition(0);
+ pv.y += 8.3f;
+ pm = m_metal->RetPosition(0);
+ m_angleZ = RotateAngle(Length2d(pv, pm), Abs(pv.y-pm.y));
+
+ m_physics->SetFreeze(TRUE); // on ne bouge plus
+
+ m_bBuild = FALSE; // pas encore construit
+ m_bError = FALSE; // ok
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskBuild::IsEnded()
+{
+ CAuto* automat;
+ float angle, dist, time;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_phase == TBP_TURN ) // rotation préliminaire ?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angleY-PI*0.01f, m_angleY+PI*0.01f) )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ dist = Length(m_object->RetPosition(0), m_metal->RetPosition(0));
+ if ( dist > 30.0f )
+ {
+ time = m_physics->RetLinTimeLength(dist-30.0f, 1.0f);
+ m_speed = 1.0f/time;
+ }
+ else
+ {
+ time = m_physics->RetLinTimeLength(30.0f-dist, -1.0f);
+ m_speed = 1.0f/time;
+ }
+ m_phase = TBP_MOVE;
+ m_progress = 0.0f;
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TBP_MOVE ) // avance/recule préliminaire ?
+ {
+ dist = Length(m_object->RetPosition(0), m_metal->RetPosition(0));
+
+ if ( dist >= 25.0f && dist <= 35.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+ m_motion->SetAction(MHS_GUN); // prend arme
+
+ m_phase = TBP_TAKE;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+ else
+ {
+ if ( m_progress > 1.0f ) // timeout ?
+ {
+ m_metal->SetLock(FALSE); // de nouveau utilisable
+ if ( dist < 30.0f ) return ERR_BUILD_METALNEAR;
+ else return ERR_BUILD_METALAWAY;
+ }
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TBP_TAKE ) // prend arme ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_motion->SetAction(MHS_FIRE); // position de tir
+ m_object->SetObjectParent(14, 4);
+ m_object->SetPosition(14, D3DVECTOR(0.6f, 0.1f, 0.3f));
+ m_object->SetAngleZ(14, 0.0f);
+
+ m_phase = TBP_PREP;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+
+ if ( m_phase == TBP_PREP ) // prépare ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_soundChannel = m_sound->Play(SOUND_TREMBLE, m_object->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.7f, 1.0f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.7f, 1.5f, 7.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.5f, 2.0f, SOPER_STOP);
+
+ m_camera->StartEffect(CE_VIBRATION, m_metal->RetPosition(0), 1.0f);
+
+ m_phase = TBP_BUILD;
+ m_speed = 1.0f/10.f; // durée de 10s
+ m_progress = 0.0f;
+ }
+
+ if ( m_phase == TBP_BUILD ) // construction ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ DeleteMark(m_metal->RetPosition(0), 20.0f);
+
+ m_metal->DeleteObject(); // supprime le métal
+ delete m_metal;
+ m_metal = 0;
+
+ m_building->SetZoom(0, 1.0f);
+ m_building->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_building->SetLock(FALSE); // batiment utilisable
+ m_main->CreateShortcuts();
+ m_displayText->DisplayError(INFO_BUILD, m_buildingPos, 10.0f, 50.0f);
+
+ automat = m_building->RetAuto();
+ if ( automat != 0 )
+ {
+ automat->Init();
+ }
+
+ m_motion->SetAction(MHS_GUN); // remet arme
+ m_phase = TBP_TERM;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+
+ if ( m_phase == TBP_TERM ) // rotation terminale ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_motion->SetAction(-1);
+ m_object->SetObjectParent(14, 0);
+ m_object->SetPosition(14, D3DVECTOR(-1.5f, 0.3f, -1.35f));
+ m_object->SetAngleZ(14, PI);
+
+ if ( m_type == OBJECT_FACTORY ||
+ m_type == OBJECT_RESEARCH ||
+ m_type == OBJECT_NUCLEAR )
+ {
+
+ m_phase = TBP_RECEDE;
+ m_speed = 1.0f/1.5f;
+ m_progress = 0.0f;
+ }
+ }
+
+ if ( m_phase == TBP_RECEDE ) // recule ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_physics->SetMotorSpeedX(0.0f);
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskBuild::Abort()
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ m_physics->SetFreeze(FALSE); // on bouge de nouveau
+ return TRUE;
+}
+
+
+// Vérifie si le terrain est assez plat et s'il n'y a pas
+// un autre objet trop proche.
+
+Error CTaskBuild::FlatFloor()
+{
+ CObject *pObj;
+ ObjectType type;
+ D3DVECTOR center, pos, oPos, bPos;
+ FPOINT c, p;
+ float radius, max, oRadius, bRadius, angle, dist;
+ int i, j;
+ BOOL bLittleFlat, bBase;
+
+ radius = 0.0f;
+ if ( m_type == OBJECT_DERRICK ) radius = 5.0f;
+ if ( m_type == OBJECT_FACTORY ) radius = 15.0f;
+ if ( m_type == OBJECT_REPAIR ) radius = 12.0f;
+ if ( m_type == OBJECT_STATION ) radius = 12.0f;
+ if ( m_type == OBJECT_CONVERT ) radius = 12.0f;
+ if ( m_type == OBJECT_TOWER ) radius = 7.0f;
+ if ( m_type == OBJECT_RESEARCH ) radius = 10.0f;
+ if ( m_type == OBJECT_RADAR ) radius = 5.0f;
+ if ( m_type == OBJECT_ENERGY ) radius = 8.0f;
+ if ( m_type == OBJECT_LABO ) radius = 12.0f;
+ if ( m_type == OBJECT_NUCLEAR ) radius = 20.0f;
+ if ( m_type == OBJECT_PARA ) radius = 20.0f;
+ if ( m_type == OBJECT_INFO ) radius = 5.0f;
+ if ( radius == 0.0f ) return ERR_GENERIC;
+
+ center = m_metal->RetPosition(0);
+ angle = m_terrain->RetFineSlope(center);
+ bLittleFlat = ( angle < FLATLIMIT );
+
+ max = m_terrain->RetFlatZoneRadius(center, radius);
+ if ( max < radius ) // zone trop petite ?
+ {
+ if ( bLittleFlat )
+ {
+ m_main->SetShowLimit(1, PARTILIMIT3, m_metal, center, max, 10.0f);
+ }
+ return bLittleFlat?ERR_BUILD_FLATLIT:ERR_BUILD_FLAT;
+ }
+
+ max = 100000.0f;
+ bBase = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( pObj == m_metal ) continue;
+ if ( pObj == m_object ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_BASE )
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length(center, oPos)-80.0f;
+ if ( dist < max )
+ {
+ max = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ bBase = TRUE;
+ }
+ }
+ else
+ {
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius;
+ if ( dist < max )
+ {
+ max = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ bBase = FALSE;
+ }
+ }
+ }
+ }
+ if ( max < radius )
+ {
+ m_main->SetShowLimit(1, PARTILIMIT2, m_metal, center, max, 10.0f);
+ if ( bRadius < 2.0f ) bRadius = 2.0f;
+ m_main->SetShowLimit(2, PARTILIMIT3, m_metal, bPos, bRadius, 10.0f);
+ return bBase?ERR_BUILD_BASE:ERR_BUILD_BUSY;
+ }
+
+ max = 100000.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( pObj == m_metal ) continue;
+ if ( pObj == m_object ) continue;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_DERRICK ||
+ type == OBJECT_FACTORY ||
+ type == OBJECT_STATION ||
+ type == OBJECT_CONVERT ||
+ type == OBJECT_REPAIR ||
+ type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH ||
+ type == OBJECT_RADAR ||
+ type == OBJECT_ENERGY ||
+ type == OBJECT_LABO ||
+ type == OBJECT_NUCLEAR ||
+ type == OBJECT_START ||
+ type == OBJECT_END ||
+ type == OBJECT_INFO ||
+ type == OBJECT_PARA ||
+ type == OBJECT_SAFE ||
+ type == OBJECT_HUSTON ) // bâtiment ?
+ {
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length(center, oPos)-oRadius;
+ if ( dist < max )
+ {
+ max = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ }
+ }
+ }
+ }
+ if ( max-BUILDMARGIN < radius )
+ {
+ m_main->SetShowLimit(1, PARTILIMIT2, m_metal, center, max-BUILDMARGIN, 10.0f);
+ m_main->SetShowLimit(2, PARTILIMIT3, m_metal, bPos, bRadius+BUILDMARGIN, 10.0f);
+ return bBase?ERR_BUILD_BASE:ERR_BUILD_NARROW;
+ }
+
+ return ERR_OK;
+}
+
+// Cherche l'objet métal le plus proche.
+
+CObject* CTaskBuild::SearchMetalObject(float &angle, float dMin, float dMax,
+ float aLimit, Error &err)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, a, aa, aBest, distance, magic;
+ int i;
+ BOOL bMetal;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ min = 1000000.0f;
+ pBest = 0;
+ bMetal = FALSE;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue; // objet inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+
+ type = pObj->RetType();
+ if ( type != OBJECT_METAL ) continue;
+
+ bMetal = TRUE; // métal existe
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ a = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+
+ if ( distance > dMax ) continue;
+ if ( !TestAngle(a, iAngle-aLimit, iAngle+aLimit) ) continue;
+
+ if ( distance < dMin )
+ {
+ err = ERR_BUILD_METALNEAR; // trop proche
+ return pObj;
+ }
+
+ aa = Abs(a-iAngle);
+ if ( aa > PI ) aa = PI*2.0f-aa;
+ magic = distance*aa;
+
+ if ( magic < min )
+ {
+ min = magic;
+ aBest = a;
+ pBest = pObj;
+ }
+ }
+
+ if ( pBest == 0 )
+ {
+ if ( bMetal ) err = ERR_BUILD_METALAWAY; // trop loin
+ else err = ERR_BUILD_METALINEX; // inexistant
+ }
+ else
+ {
+ angle = aBest;
+ err = ERR_OK;
+ }
+ return pBest;
+}
+
+// Détruit toutes les marques proches.
+
+void CTaskBuild::DeleteMark(D3DVECTOR pos, float radius)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float distance;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MARKSTONE &&
+ type != OBJECT_MARKURANIUM &&
+ type != OBJECT_MARKKEYa &&
+ type != OBJECT_MARKKEYb &&
+ type != OBJECT_MARKKEYc &&
+ type != OBJECT_MARKKEYd &&
+ type != OBJECT_MARKPOWER ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, pos);
+ if ( distance <= radius )
+ {
+ pObj->DeleteObject(); // supprime la marque
+ delete pObj;
+ i --;
+ }
+ }
+}
+
diff --git a/src/taskbuild.h b/src/taskbuild.h
new file mode 100644
index 0000000..6d8a234
--- /dev/null
+++ b/src/taskbuild.h
@@ -0,0 +1,74 @@
+// taskbuild.h
+
+#ifndef _TASKBUILD_H_
+#define _TASKBUILD_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+#define BUILDMARGIN 16.0f
+#define TBMAXLIGHT 4
+
+
+enum TaskBuildPhase
+{
+ TBP_TURN = 1, // tourne
+ TBP_MOVE = 2, // avance/recule
+ TBP_TAKE = 3, // prend arme
+ TBP_PREP = 4, // prépare
+ TBP_BUILD = 5, // construit
+ TBP_TERM = 6, // termine
+ TBP_RECEDE = 7, // recule terminal
+};
+
+
+
+class CTaskBuild : public CTask
+{
+public:
+ CTaskBuild(CInstanceManager* iMan, CObject* object);
+ ~CTaskBuild();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(ObjectType type);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ Error FlatFloor();
+ BOOL CreateBuilding(D3DVECTOR pos, float angle);
+ void CreateLight();
+ void BlackLight();
+ CObject* SearchMetalObject(float &angle, float dMin, float dMax, float aLimit, Error &err);
+ void DeleteMark(D3DVECTOR pos, float radius);
+
+protected:
+ ObjectType m_type; // type de construction
+ CObject* m_metal; // objet metal transformé
+ CObject* m_power; // pile du véhicule
+ CObject* m_building; // batiment construit
+ TaskBuildPhase m_phase; // phase de l'opération
+ BOOL m_bError; // TRUE -> opération impossible
+ BOOL m_bBuild; // TRUE -> batiment construit
+ BOOL m_bBlack; // TRUE -> lumières noir -> blanc
+ float m_time; // temps absolu
+ float m_lastParticule;// temps génération dernière particule
+ float m_progress; // progression (0..1)
+ float m_speed; // vitesse de la progression
+ float m_angleY; // angle de rotation du véhicule
+ float m_angleZ; // angle de rotation du canon
+ D3DVECTOR m_buildingPos; // position initiale du batiment
+ float m_buildingHeight;// hauteur du building
+ int m_lightRank[TBMAXLIGHT];// lumières pour les effets
+ int m_soundChannel;
+};
+
+
+#endif //_TASKBUILD_H_
diff --git a/src/taskfire.cpp b/src/taskfire.cpp
new file mode 100644
index 0000000..5347ad6
--- /dev/null
+++ b/src/taskfire.cpp
@@ -0,0 +1,382 @@
+// taskfire.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "task.h"
+#include "taskfire.h"
+
+
+
+#define ENERGY_FIRE (0.25f/2.5f) // énergie consommée /s de tir
+#define ENERGY_FIREr (0.25f/1.5f) // énergie consommée /s de rayon
+#define ENERGY_FIREi (0.10f/2.5f) // énergie consommée /s d'organique
+
+
+// Constructeur de l'objet.
+
+CTaskFire::CTaskFire(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CTaskFire::~CTaskFire()
+{
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskFire::EventProcess(const Event &event)
+{
+ CObject* power;
+ CPhysics* physics;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed, dir, vib;
+ ObjectType type;
+ FPOINT dim;
+ float energy, fire;
+ int i, channel;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_time += event.rTime;
+ m_lastSound -= event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ if ( m_bOrganic ) fire = ENERGY_FIREi;
+ else if ( m_bRay ) fire = ENERGY_FIREr;
+ else fire = ENERGY_FIRE;
+ energy -= event.rTime*fire/power->RetCapacity();
+ power->SetEnergy(energy);
+ }
+
+ if ( m_lastParticule+0.05f <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ if ( m_bOrganic )
+ {
+ mat = m_object->RetWorldMatrix(1); // canon-insecte
+
+ for ( i=0 ; i<6 ; i++ )
+ {
+ pos = D3DVECTOR(0.0f, 2.5f, 0.0f);
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(200.0f, 0.0f, 0.0f);
+
+ physics = m_object->RetPhysics();
+ if ( physics != 0 )
+ {
+ speed += physics->RetLinMotion(MO_REASPEED);
+ }
+
+ speed.x += (Rand()-0.5f)*10.0f;
+ speed.y += (Rand()-0.5f)*20.0f;
+ speed.z += (Rand()-0.5f)*30.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = Rand()*0.5f+0.5f;
+ dim.y = dim.x;
+
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN4, 0.8f, 0.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+ }
+ else if ( m_bRay )
+ {
+ mat = m_object->RetWorldMatrix(2); // canon
+
+ for ( i=0 ; i<4 ; i++ )
+ {
+ pos = D3DVECTOR(4.0f, 0.0f, 0.0f);
+ pos.y += (rand()%3-1)*1.5f;
+ pos.z += (rand()%3-1)*1.5f;
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(200.0f, 0.0f, 0.0f);
+ speed.x += (Rand()-0.5f)*6.0f;
+ speed.y += (Rand()-0.5f)*12.0f;
+ speed.z += (Rand()-0.5f)*12.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ channel = m_particule->CreateTrack(pos, speed, dim, PARTITRACK11,
+ 2.0f, 200.0f, 0.5f, 1.0f);
+ m_particule->SetObjectFather(channel, m_object);
+
+ speed = D3DVECTOR(5.0f, 0.0f, 0.0f);
+ speed.x += (Rand()-0.5f)*1.0f;
+ speed.y += (Rand()-0.5f)*2.0f;
+ speed.z += (Rand()-0.5f)*2.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+ speed.y += 5.0f;
+
+ dim.x = 2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE2, 2.0f, 0.0f, 0.5f);
+ }
+ }
+ else
+ {
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILErc )
+ {
+ mat = m_object->RetWorldMatrix(2); // canon
+ }
+ else
+ {
+ mat = m_object->RetWorldMatrix(1); // canon
+ }
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ if ( type == OBJECT_MOBILErc )
+ {
+ pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ }
+ else
+ {
+ pos = D3DVECTOR(3.0f, 1.0f, 0.0f);
+ }
+ pos.y += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(200.0f, 0.0f, 0.0f);
+
+ physics = m_object->RetPhysics();
+ if ( physics != 0 )
+ {
+ speed += physics->RetLinMotion(MO_REASPEED);
+ }
+
+ speed.x += (Rand()-0.5f)*3.0f;
+ speed.y += (Rand()-0.5f)*6.0f;
+ speed.z += (Rand()-0.5f)*6.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = Rand()*0.7f+0.7f;
+ dim.y = dim.x;
+
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN1, 0.8f, 0.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+
+ if ( type != OBJECT_MOBILErc &&
+ m_progress > 0.3f )
+ {
+ pos = D3DVECTOR(-1.0f, 1.0f, 0.0f);
+ pos.y += (Rand()-0.5f)*0.4f;
+ pos.z += (Rand()-0.5f)*0.4f;
+ pos = Transform(*mat, pos);
+
+ speed = D3DVECTOR(-4.0f, 0.0f, 0.0f);
+ speed.x += (Rand()-0.5f)*2.0f;
+ speed.y += (Rand()-0.2f)*4.0f;
+ speed.z += (Rand()-0.5f)*4.0f;
+ speed = Transform(*mat, speed);
+ speed -= pos;
+
+ dim.x = Rand()*1.2f+1.2f;
+ dim.y = dim.x;
+
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f, 0.0f, 0.0f);
+//? m_particule->CreateParticule(pos, speed, dim, PARTISMOKE2, 4.0f, 0.0f, 0.0f);
+ }
+ }
+
+ dir = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ if ( m_progress < 0.1f )
+ {
+ dir.z = (PI*0.04f)*(m_progress*10.0f);
+ }
+ else if ( m_progress < 0.9f )
+ {
+ dir.z = (PI*0.04f);
+ }
+ else
+ {
+ dir.z = (PI*0.04f)*(1.0f-(m_progress-0.9f)*10.0f);
+ }
+ m_object->SetInclinaison(dir);
+
+ vib.x = (Rand()-0.5f)*0.01f;
+ vib.y = (Rand()-0.5f)*0.02f;
+ vib.z = (Rand()-0.5f)*0.02f;
+ m_object->SetCirVibration(vib);
+
+ vib.x = (Rand()-0.5f)*0.20f;
+ vib.y = (Rand()-0.5f)*0.05f;
+ vib.z = (Rand()-0.5f)*0.20f;
+ m_object->SetLinVibration(vib);
+ }
+
+ if ( m_bRay && m_lastSound <= 0.0f )
+ {
+ m_lastSound = Rand()*0.4f+0.4f;
+ m_sound->Play(SOUND_FIREp, m_object->RetPosition(0));
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskFire::Start(float delay)
+{
+ CObject* power;
+ D3DVECTOR pos, goal, speed;
+ float energy, fire;
+ ObjectType type;
+
+ m_bError = TRUE; // opération impossible
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILErc ) return ERR_FIRE_VEH;
+
+//? if ( !m_physics->RetLand() ) return ERR_FIRE_FLY;
+
+ speed = m_physics->RetMotorSpeed();
+//? if ( speed.x != 0.0f ||
+//? speed.z != 0.0f ) return ERR_FIRE_MOTOR;
+
+ m_bRay = (type == OBJECT_MOBILErc);
+
+ m_bOrganic = FALSE;
+ if ( type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii )
+ {
+ m_bOrganic = TRUE;
+ }
+
+ if ( delay == 0.0f )
+ {
+ if ( m_bRay ) delay = 1.2f;
+ else delay = 2.0f;
+ }
+ m_delay = delay;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_FIRE_ENERGY;
+ energy = power->RetEnergy();
+ if ( m_bOrganic ) fire = m_delay*ENERGY_FIREi;
+ else if ( m_bRay ) fire = m_delay*ENERGY_FIREr;
+ else fire = m_delay*ENERGY_FIRE;
+ if ( energy < fire/power->RetCapacity()+0.05f ) return ERR_FIRE_ENERGY;
+
+ m_speed = 1.0f/m_delay;
+ m_progress = 0.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_lastSound = 0.0f;
+ m_bError = FALSE; // ok
+
+//? m_camera->StartCentering(m_object, PI*0.15f, 99.9f, 0.0f, 1.0f);
+
+ if ( m_bOrganic )
+ {
+ m_soundChannel = m_sound->Play(SOUND_FIREi, m_object->RetPosition(0), 1.0f, 1.0f, TRUE);
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, m_delay, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.5f, SOPER_STOP);
+ }
+ }
+ else if ( m_bRay )
+ {
+ }
+ else
+ {
+ m_soundChannel = m_sound->Play(SOUND_FIRE, m_object->RetPosition(0), 1.0f, 1.0f, TRUE);
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, m_delay, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 0.5f, SOPER_STOP);
+ }
+ }
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskFire::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskFire::Abort()
+{
+ m_object->SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetLinVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+//? m_camera->StopCentering(m_object, 1.0f);
+ return TRUE;
+}
+
diff --git a/src/taskfire.h b/src/taskfire.h
new file mode 100644
index 0000000..9ce1c9b
--- /dev/null
+++ b/src/taskfire.h
@@ -0,0 +1,42 @@
+// taskfire.h
+
+#ifndef _TASKFIRE_H_
+#define _TASKTIRE_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskFire : public CTask
+{
+public:
+ CTaskFire(CInstanceManager* iMan, CObject* object);
+ ~CTaskFire();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float delay);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ float m_delay;
+ float m_progress;
+ BOOL m_bError;
+ BOOL m_bRay;
+ BOOL m_bOrganic;
+ float m_time;
+ float m_speed;
+ float m_lastParticule;
+ float m_lastSound;
+ int m_soundChannel;
+};
+
+
+#endif //_TASKFIRE_H_
diff --git a/src/taskfireant.cpp b/src/taskfireant.cpp
new file mode 100644
index 0000000..d82ec32
--- /dev/null
+++ b/src/taskfireant.cpp
@@ -0,0 +1,211 @@
+// taskfireant.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionant.h"
+#include "task.h"
+#include "taskfireant.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskFireAnt::CTaskFireAnt(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_phase = TFA_NULL;
+}
+
+// Destructeur de l'objet.
+
+CTaskFireAnt::~CTaskFireAnt()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskFireAnt::EventProcess(const Event &event)
+{
+ D3DVECTOR dir, vib;
+ float a, g, cirSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_object->RetFixed() ) // insecte sur le dos ?
+ {
+ m_bError = TRUE;
+ return FALSE;
+ }
+
+ m_time += event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == TFA_TURN ) // rotation préliminaire ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*2.0f;
+ if ( cirSpeed > 2.0f ) cirSpeed = 2.0f;
+ if ( cirSpeed < -2.0f ) cirSpeed = -2.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskFireAnt::Start(D3DVECTOR impact)
+{
+ D3DVECTOR pos;
+ ObjectType type;
+
+ m_impact = impact;
+
+ m_bError = TRUE; // opération impossible
+ if ( !m_physics->RetLand() ) return ERR_FIRE_VEH;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_ANT ) return ERR_FIRE_VEH;
+
+ // Insecte sur le dos ?
+ if ( m_object->RetFixed() ) return ERR_FIRE_VEH;
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ pos = m_object->RetPosition(0);
+ m_angle = RotateAngle(m_impact.x-pos.x, pos.z-m_impact.z); // CW !
+
+ m_phase = TFA_TURN;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ m_bError = FALSE; // ok
+ m_bFire = FALSE; // un seul coup !
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskFireAnt::IsEnded()
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle, dist;
+ int i, channel;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+ if ( m_object->RetFixed() ) return ERR_STOP; // insecte sur le dos ?
+
+ if ( m_phase == TFA_TURN ) // rotation ?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+ if ( !TestAngle(angle, m_angle-PI*0.05f, m_angle+PI*0.05f) ) return ERR_CONTINUE;
+
+ m_physics->SetMotorSpeedZ(0.0f); // rotation terminée
+
+ m_phase = TFA_PREPARE;
+//? m_speed = 1.0f/1.5f;
+ m_speed = 1.0f/0.4f;
+ m_progress = 0.0f;
+//? m_motion->SetAction(MAS_PREPARE, 1.5f);
+ m_motion->SetAction(MAS_PREPARE, 0.4f);
+ }
+
+ if ( m_phase == TFA_PREPARE ) // préparation ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = TFA_FIRE;
+//? m_speed = 1.0f/2.0f;
+ m_speed = 1.0f/0.5f;
+ m_progress = 0.0f;
+//? m_motion->SetAction(MAS_FIRE, 2.0f);
+ m_motion->SetAction(MAS_FIRE, 0.5f);
+ }
+
+ if ( m_phase == TFA_FIRE ) // tir ?
+ {
+ if ( m_progress > 0.75f && !m_bFire )
+ {
+ m_bFire = TRUE; // un seul coup
+
+ for ( i=0 ; i<20 ; i++ )
+ {
+ pos = D3DVECTOR(-2.5f, -0.7f, 0.0f);
+ mat = m_object->RetWorldMatrix(2);
+ pos = Transform(*mat, pos);
+ dist = Length(pos, m_impact);
+ speed = m_impact-pos;
+ speed.x += (Rand()-0.5f)*dist*1.2f;
+ speed.y += (Rand()-0.5f)*dist*0.4f+50.0f;
+ speed.z += (Rand()-0.5f)*dist*1.2f;
+ dim.x = 1.0f;
+ dim.y = dim.x;
+ channel = m_particule->CreateParticule(pos, speed, dim, PARTIGUN2, 2.0f, 100.0f, 0.0f);
+ m_particule->SetObjectFather(channel, m_object);
+ }
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = TFA_TERMINATE;
+//? m_speed = 1.0f/0.9f;
+ m_speed = 1.0f/0.4f;
+ m_progress = 0.0f;
+//? m_motion->SetAction(MAS_TERMINATE, 0.9f);
+ m_motion->SetAction(MAS_TERMINATE, 0.4f);
+ }
+
+ if ( m_phase == TFA_TERMINATE ) // termine ?
+ {
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_phase = TFA_NULL;
+ m_speed = 1.0f/1.0f;
+ m_progress = 0.0f;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskFireAnt::Abort()
+{
+ m_motion->SetAction(-1);
+ return TRUE;
+}
+
diff --git a/src/taskfireant.h b/src/taskfireant.h
new file mode 100644
index 0000000..d251b9b
--- /dev/null
+++ b/src/taskfireant.h
@@ -0,0 +1,53 @@
+// taskfireant.h
+
+#ifndef _TASKFIREANT_H_
+#define _TASKTIREANT_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskFireAnt
+{
+ TFA_NULL = 0, // rien à faire
+ TFA_TURN = 1, // tourne
+ TFA_PREPARE = 2, // prépare position de tir
+ TFA_FIRE = 3, // tir
+ TFA_TERMINATE = 4, // termine position de tir
+};
+
+
+
+class CTaskFireAnt : public CTask
+{
+public:
+ CTaskFireAnt(CInstanceManager* iMan, CObject* object);
+ ~CTaskFireAnt();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(D3DVECTOR impact);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ D3DVECTOR m_impact;
+ TaskFireAnt m_phase;
+ float m_progress;
+ float m_speed;
+ float m_angle;
+ BOOL m_bError;
+ BOOL m_bFire;
+ float m_time;
+ float m_lastParticule;
+};
+
+
+#endif //_TASKFIREANT_H_
diff --git a/src/taskflag.cpp b/src/taskflag.cpp
new file mode 100644
index 0000000..a475e67
--- /dev/null
+++ b/src/taskflag.cpp
@@ -0,0 +1,305 @@
+// taskflag.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "pyro.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "sound.h"
+#include "task.h"
+#include "taskflag.h"
+
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskFlag::CTaskFlag(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskFlag::~CTaskFlag()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskFlag::EventProcess(const Event &event)
+{
+ if ( m_bError ) return TRUE;
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_time += event.rTime;
+
+ return TRUE;
+}
+
+
+
+// Assigne le but à atteindre.
+
+Error CTaskFlag::Start(TaskFlagOrder order, int rank)
+{
+ D3DVECTOR pos, speed;
+ Error err;
+
+ m_order = order;
+ m_time = 0.0f;
+
+ m_bError = TRUE; // opération impossible
+ if ( !m_physics->RetLand() )
+ {
+ pos = m_object->RetPosition(0);
+ if ( pos.y < m_water->RetLevel() ) return ERR_FLAG_WATER;
+ return ERR_FLAG_FLY;
+ }
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_FLAG_MOTOR;
+
+ if ( m_object->RetFret() != 0 ) return ERR_FLAG_BUSY;
+
+ if ( order == TFL_CREATE )
+ {
+ err = CreateFlag(rank);
+ if ( err != ERR_OK ) return err;
+ }
+
+ if ( order == TFL_DELETE )
+ {
+ err = DeleteFlag();
+ if ( err != ERR_OK ) return err;
+ }
+
+ m_bError = FALSE;
+
+ m_motion->SetAction(MHS_FLAG); // met/enlève drapeau
+ m_camera->StartCentering(m_object, PI*0.3f, 99.9f, 0.0f, 0.5f);
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskFlag::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError ) return ERR_STOP;
+ if ( m_time < 2.0f ) return ERR_CONTINUE;
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskFlag::Abort()
+{
+ m_motion->SetAction(-1);
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+
+// Retourne l'objet le plus proche d'une position donnée.
+
+CObject* CTaskFlag::SearchNearest(D3DVECTOR pos, ObjectType type)
+{
+ ObjectType oType;
+ CObject *pObj, *pBest;
+ D3DVECTOR oPos;
+ float min, dist;
+ int i;
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetEnable() ) continue;
+
+ oType = pObj->RetType();
+ if ( type == OBJECT_NULL )
+ {
+ if ( oType != OBJECT_FLAGb &&
+ oType != OBJECT_FLAGr &&
+ oType != OBJECT_FLAGg &&
+ oType != OBJECT_FLAGy &&
+ oType != OBJECT_FLAGv ) continue;
+ }
+ else
+ {
+ if ( oType != type ) continue;
+ }
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(oPos, pos);
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+ return pBest;
+}
+
+// Compte le nombre d'objets existants.
+
+int CTaskFlag::CountObject(ObjectType type)
+{
+ ObjectType oType;
+ CObject *pObj;
+ D3DVECTOR oPos;
+ int i, count;
+
+ count = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetEnable() ) continue;
+
+ oType = pObj->RetType();
+ if ( type == OBJECT_NULL )
+ {
+ if ( oType != OBJECT_FLAGb &&
+ oType != OBJECT_FLAGr &&
+ oType != OBJECT_FLAGg &&
+ oType != OBJECT_FLAGy &&
+ oType != OBJECT_FLAGv ) continue;
+ }
+ else
+ {
+ if ( oType != type ) continue;
+ }
+
+ count ++;
+ }
+ return count;
+}
+
+// Crée un indicateur de couleur.
+
+Error CTaskFlag::CreateFlag(int rank)
+{
+ CObject* pObj;
+ CObject* pNew;
+ CPyro* pyro;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ float dist;
+ int i;
+
+ ObjectType table[5] =
+ {
+ OBJECT_FLAGb,
+ OBJECT_FLAGr,
+ OBJECT_FLAGg,
+ OBJECT_FLAGy,
+ OBJECT_FLAGv,
+ };
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(4.0f, 0.0f, 0.0f));
+
+ pObj = SearchNearest(pos, OBJECT_NULL);
+ if ( pObj != 0 )
+ {
+ dist = Length(pos, pObj->RetPosition(0));
+ if ( dist < 10.0f )
+ {
+ return ERR_FLAG_PROXY;
+ }
+ }
+
+ i = rank;
+ if ( CountObject(table[i]) >= 5 )
+ {
+ return ERR_FLAG_CREATE;
+ }
+
+ pNew = new CObject(m_iMan);
+ if ( !pNew->CreateFlag(pos, 0.0f, table[i]) )
+ {
+ delete pNew;
+ return ERR_TOOMANY;
+ }
+ pNew->SetZoom(0, 0.0f);
+
+ m_sound->Play(SOUND_WAYPOINT, pos);
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FLCREATE, pNew);
+
+ return ERR_OK;
+}
+
+// Supprime un indicateur de couleur.
+
+Error CTaskFlag::DeleteFlag()
+{
+ CObject* pObj;
+ CPyro* pyro;
+ D3DVECTOR iPos, oPos;
+ float iAngle, angle, aLimit, dist;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ pObj = SearchNearest(iPos, OBJECT_NULL);
+ if ( pObj == 0 )
+ {
+ return ERR_FLAG_DELETE;
+ }
+ dist = Length(iPos, pObj->RetPosition(0));
+ if ( dist > 10.0f )
+ {
+ return ERR_FLAG_DELETE;
+ }
+
+ oPos = pObj->RetPosition(0);
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ aLimit = 45.0f*PI/180.0f;
+ if ( !TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ return ERR_FLAG_DELETE;
+ }
+
+ m_sound->Play(SOUND_WAYPOINT, iPos);
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FLDELETE, pObj);
+
+ return ERR_OK;
+}
+
diff --git a/src/taskflag.h b/src/taskflag.h
new file mode 100644
index 0000000..af940aa
--- /dev/null
+++ b/src/taskflag.h
@@ -0,0 +1,48 @@
+// taskflag.h
+
+#ifndef _TASKFLAG_H_
+#define _TASKFLAG_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskFlagOrder
+{
+ TFL_CREATE = 0, // met
+ TFL_DELETE = 1, // enlève
+};
+
+
+
+class CTaskFlag : public CTask
+{
+public:
+ CTaskFlag(CInstanceManager* iMan, CObject* object);
+ ~CTaskFlag();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(TaskFlagOrder order, int rank);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ Error CreateFlag(int rank);
+ Error DeleteFlag();
+ CObject* SearchNearest(D3DVECTOR pos, ObjectType type);
+ int CountObject(ObjectType type);
+
+protected:
+ TaskFlagOrder m_order;
+ float m_time;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKFLAG_H_
diff --git a/src/taskgoto.cpp b/src/taskgoto.cpp
new file mode 100644
index 0000000..cd9575b
--- /dev/null
+++ b/src/taskgoto.cpp
@@ -0,0 +1,2340 @@
+// taskgoto.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "water.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskgoto.h"
+
+
+
+#define FLY_DIST_GROUND 80.0f // distance minimale pour rester au sol
+#define FLY_DEF_HEIGHT 50.0f // hauteur de vol par défaut
+#define BM_DIM_STEP 5.0f
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskGoto::CTaskGoto(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_bmArray = 0;
+}
+
+// Destructeur de l'objet.
+
+CTaskGoto::~CTaskGoto()
+{
+ BitmapClose();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskGoto::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, goal;
+ FPOINT rot, repulse;
+ float a, g, dist, linSpeed, cirSpeed, h, hh, factor, dir;
+ Error ret;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ // Objet momentanément immobile (fourmi sur le dos) ?
+ if ( m_object->RetFixed() )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ return TRUE;
+ }
+
+ if ( m_error != ERR_OK ) return FALSE;
+
+ if ( m_bWorm )
+ {
+ WormFrame(event.rTime);
+ }
+
+ if ( m_phase == TGP_BEAMLEAK ) // fuite ?
+ {
+ m_leakTime += event.rTime;
+
+ pos = m_object->RetPosition(0);
+
+ rot.x = m_leakPos.x-pos.x;
+ rot.y = m_leakPos.z-pos.z;
+ dist = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ a = Direction(a, g)*1.0f;
+ cirSpeed = a;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ a = NormAngle(a);
+ if ( a > PI*0.5f && a < PI*1.5f )
+ {
+ linSpeed = 1.0f; // obstacle derrière -> avance
+ cirSpeed = -cirSpeed;
+ }
+ else
+ {
+ linSpeed = -1.0f; // obstacle devant -> recule
+ }
+
+ if ( m_bLeakRecede )
+ {
+ linSpeed = -1.0f;
+ cirSpeed = 0.0f;
+ }
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(linSpeed); // avance
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMSEARCH ) // recherche chemin ?
+ {
+ if ( m_bmStep == 0 )
+ {
+ // Libère la zone autour du départ.
+ BitmapClearCircle(m_object->RetPosition(0), BM_DIM_STEP*1.8f);
+ }
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_bmFretObject == 0 )
+ {
+ goal = m_goal;
+ dist = 0.0f;
+ }
+ else
+ {
+ goal = m_goalObject;
+ dist = TAKE_DIST+2.0f;
+ if ( m_bmFretObject->RetType() == OBJECT_BASE ) dist = 12.0f;
+ }
+
+ ret = BeamSearch(pos, goal, dist);
+ if ( ret == ERR_OK )
+ {
+#if 0
+ D3DVECTOR min, max;
+ min = pos;
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 50.0f;
+ min.z -= 50.0f;
+ max.x += 50.0f;
+ max.z += 50.0f;
+ BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
+#endif
+ if ( m_physics->RetLand() ) m_phase = TGP_BEAMWCOLD;
+ else m_phase = TGP_BEAMGOTO;
+ m_bmIndex = 0;
+ m_bmWatchDogPos = m_object->RetPosition(0);
+ m_bmWatchDogTime = 0.0f;
+ }
+ if ( ret == ERR_GOTO_IMPOSSIBLE || ret == ERR_GOTO_ITER )
+ {
+#if 0
+ D3DVECTOR min, max;
+ min = pos;
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 50.0f;
+ min.z -= 50.0f;
+ max.x += 50.0f;
+ max.z += 50.0f;
+ BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
+#endif
+ m_error = ret;
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMWCOLD ) // attend refroidissement réacteur ?
+ {
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMUP ) // décolle ?
+ {
+ m_physics->SetMotorSpeedY(1.0f); // monte
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMGOTO ) // goto dot list ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ }
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f )
+ {
+ if ( m_physics->RetLand() )
+ {
+ m_physics->SetMotorSpeedY(0.0f);
+ }
+ else
+ {
+ m_physics->SetMotorSpeedY(-1.0f);
+ }
+ }
+
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ goal = m_bmPoints[m_bmIndex];
+ goal.y = pos.y;
+ h = m_terrain->RetFloorHeight(goal, TRUE, TRUE);
+ dist = Length2d(pos, goal);
+ if ( dist != 0.0f ) // anticipe ?
+ {
+ linSpeed = m_physics->RetLinMotionX(MO_REASPEED);
+ linSpeed /= m_physics->RetLinMotionX(MO_ADVSPEED);
+ goal.x = pos.x + (goal.x-pos.x)*linSpeed*20.0f/dist;
+ goal.z = pos.z + (goal.z-pos.z)*linSpeed*20.0f/dist;
+ }
+ goal.y = pos.y;
+ hh = m_terrain->RetFloorHeight(goal, TRUE, TRUE);
+ h = Min(h, hh);
+ linSpeed = 0.0f;
+ if ( h < m_altitude-1.0f )
+ {
+ linSpeed = 0.2f+((m_altitude-1.0f)-h)*0.1f; // monte
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+ }
+ if ( h > m_altitude+1.0f )
+ {
+ linSpeed = -0.2f; // descend
+ }
+ m_physics->SetMotorSpeedY(linSpeed);
+ }
+
+ rot.x = m_bmPoints[m_bmIndex].x-pos.x;
+ rot.y = m_bmPoints[m_bmIndex].z-pos.z;
+ dist = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = Direction(a, g)*2.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+ if ( dist < 4.0f ) cirSpeed *= dist/4.0f; // si proche -> tourne moins
+
+ if ( m_bmIndex == m_bmTotal ) // dernier point ?
+ {
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+ }
+ else
+ {
+ linSpeed = 1.0f; // fonce sans s'arrêter
+ }
+
+ linSpeed *= 1.0f-(1.0f-0.3f)*Abs(cirSpeed);
+
+//? if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ if ( Abs(cirSpeed) >= 0.2f )
+ {
+ linSpeed = 0.0f; // tourne d'abord, puis avance
+ }
+
+ dist = Length2d(pos, m_bmWatchDogPos);
+ if ( dist < 1.0f && linSpeed != 0.0f )
+ {
+ m_bmWatchDogTime += event.rTime;
+ }
+ else
+ {
+ m_bmWatchDogTime = 0.0f;
+ m_bmWatchDogPos = pos;
+ }
+
+ if ( m_bmWatchDogTime >= 1.0f ) // immobile depuis longtemps ?
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ BeamStart(); // on recommence tout
+ return TRUE;
+ }
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(linSpeed); // avance
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_BEAMDOWN ) // atterri ?
+ {
+ m_physics->SetMotorSpeedY(-0.5f); // tombe
+ return TRUE;
+ }
+
+ if ( m_phase == TGP_LAND ) // atterri ?
+ {
+ m_physics->SetMotorSpeedY(-0.5f); // tombe
+ return TRUE;
+ }
+
+ if ( m_goalMode == TGG_EXPRESS )
+ {
+ if ( m_crashMode == TGC_HALT )
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_error = ERR_STOP;
+ return TRUE;
+ }
+ }
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_altitude > 0.0f )
+ {
+ h = m_terrain->RetFloorHeight(pos, TRUE, TRUE);
+ linSpeed = 0.0f;
+ if ( h < m_altitude )
+ {
+ linSpeed = 0.1f; // monte
+ }
+ if ( h > m_altitude )
+ {
+ linSpeed = -0.2f; // descend
+ }
+ m_physics->SetMotorSpeedY(linSpeed);
+ }
+
+ rot.x = m_goal.x-pos.x;
+ rot.y = m_goal.z-pos.z;
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(1.0f); // avance
+ return TRUE;
+ }
+
+ if ( m_phase != TGP_TURN &&
+ m_physics->RetType() == TYPE_FLYING &&
+ m_altitude > 0.0f )
+ {
+ pos = m_object->RetPosition(0);
+ dist = Length2d(m_goal, pos);
+ factor = (dist-20.0f)/20.0f;
+ if ( factor < 0.0f ) factor = 0.0f;
+ if ( factor > 1.0f ) factor = 1.0f;
+
+ h = m_terrain->RetFloorHeight(m_object->RetPosition(0), TRUE, TRUE);
+ linSpeed = 0.0f;
+ if ( h < (m_altitude-0.5f)*factor && factor == 1.0f )
+ {
+ linSpeed = 0.1f; // monte
+ }
+ if ( h > m_altitude*factor )
+ {
+ linSpeed = -0.2f; // descend
+ }
+ ComputeFlyingRepulse(dir);
+ linSpeed += dir*0.2f;
+
+ m_physics->SetMotorSpeedY(linSpeed);
+ }
+
+ if ( m_phase == TGP_ADVANCE ) // va vers l'objectif ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_time = 0.0f;
+ m_phase = TGP_CRWAIT;
+ return TRUE;
+ }
+
+#if 0
+ pos = m_object->RetPosition(0);
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(m_goal.x-pos.x, pos.z-m_goal.z); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ dist = Length2d(m_goal, pos);
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+
+ if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ {
+ linSpeed = 0.0f; // tourne d'abord, puis avance
+ }
+#else
+ pos = m_object->RetPosition(0);
+
+ rot.x = m_goal.x-pos.x;
+ rot.y = m_goal.z-pos.z;
+ dist = Length(rot.x, rot.y);
+ rot.x /= dist;
+ rot.y /= dist;
+
+ ComputeRepulse(repulse);
+ rot.x += repulse.x*2.0f;
+ rot.y += repulse.y*2.0f;
+
+ a = m_object->RetAngleY(0);
+ g = RotateAngle(rot.x, -rot.y); // CW !
+ cirSpeed = Direction(a, g)*1.0f;
+//? if ( m_physics->RetType() == TYPE_FLYING &&
+//? m_physics->RetLand() ) // volant au sol ?
+//? {
+//? cirSpeed *= 4.0f; // plus de pèche
+//? }
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ dist = Length2d(m_goal, pos);
+ linSpeed = dist/(m_physics->RetLinStopLength()*1.5f);
+//? if ( m_physics->RetType() == TYPE_FLYING &&
+//? m_physics->RetLand() ) // volant au sol ?
+//? {
+//? linSpeed *= 8.0f; // plus de pèche
+//? }
+ if ( linSpeed > 1.0f ) linSpeed = 1.0f;
+
+ linSpeed *= 1.0f-(1.0f-0.3f)*Abs(cirSpeed);
+
+ if ( dist < 20.0f && Abs(cirSpeed) >= 0.5f )
+ {
+ linSpeed = 0.0f; // tourne d'abord, puis avance
+ }
+#endif
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ m_physics->SetMotorSpeedX(linSpeed); // avance
+ }
+
+ if ( m_phase == TGP_TURN || // tourne vers l'objet ?
+ m_phase == TGP_CRTURN || // tourne après collision ?
+ m_phase == TGP_CLTURN ) // tourne après collision ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ }
+
+ if ( m_phase == TGP_CRWAIT || // attend après collision ?
+ m_phase == TGP_CLWAIT ) // attend après collision ?
+ {
+ m_time += event.rTime;
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ }
+
+ if ( m_phase == TGP_CRADVANCE ) // avance après collision ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_time = 0.0f;
+ m_phase = TGP_CLWAIT;
+ return TRUE;
+ }
+ m_physics->SetMotorSpeedX(0.5f); // avance mollo
+ }
+
+ if ( m_phase == TGP_CLADVANCE ) // avance après collision ?
+ {
+ if ( m_physics->RetCollision() ) // collision ?
+ {
+ m_physics->SetCollision(FALSE); // y'a plus
+ m_time = 0.0f;
+ m_phase = TGP_CRWAIT;
+ return TRUE;
+ }
+ m_physics->SetMotorSpeedX(0.5f); // avance mollo
+ }
+
+ if ( m_phase == TGP_MOVE ) // avance finale ?
+ {
+ m_bmTimeLimit -= event.rTime;
+ m_physics->SetMotorSpeedX(1.0f);
+ }
+
+ return TRUE;
+}
+
+
+// Cherche une cible pour le ver.
+
+CObject* CTaskGoto::WormSearch(D3DVECTOR &impact)
+{
+ CObject* pObj;
+ CObject* pBest = 0;
+ D3DVECTOR iPos, oPos;
+ ObjectType oType;
+ float distance, min, radius;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ min = 1000000.0f;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ oType = pObj->RetType();
+ if ( oType != OBJECT_MOBILEfa &&
+ oType != OBJECT_MOBILEta &&
+ oType != OBJECT_MOBILEwa &&
+ oType != OBJECT_MOBILEia &&
+ oType != OBJECT_MOBILEfc &&
+ oType != OBJECT_MOBILEtc &&
+ oType != OBJECT_MOBILEwc &&
+ oType != OBJECT_MOBILEic &&
+ oType != OBJECT_MOBILEfi &&
+ oType != OBJECT_MOBILEti &&
+ oType != OBJECT_MOBILEwi &&
+ oType != OBJECT_MOBILEii &&
+ oType != OBJECT_MOBILEfs &&
+ oType != OBJECT_MOBILEts &&
+ oType != OBJECT_MOBILEws &&
+ oType != OBJECT_MOBILEis &&
+ oType != OBJECT_MOBILErt &&
+ oType != OBJECT_MOBILErc &&
+ oType != OBJECT_MOBILErr &&
+ oType != OBJECT_MOBILErs &&
+ oType != OBJECT_MOBILEsa &&
+ oType != OBJECT_MOBILEtg &&
+ oType != OBJECT_MOBILEft &&
+ oType != OBJECT_MOBILEtt &&
+ oType != OBJECT_MOBILEwt &&
+ oType != OBJECT_MOBILEit &&
+ oType != OBJECT_MOBILEdr &&
+ oType != OBJECT_DERRICK &&
+ oType != OBJECT_STATION &&
+ oType != OBJECT_FACTORY &&
+ oType != OBJECT_REPAIR &&
+ oType != OBJECT_DESTROYER &&
+ oType != OBJECT_CONVERT &&
+ oType != OBJECT_TOWER &&
+ oType != OBJECT_RESEARCH &&
+ oType != OBJECT_RADAR &&
+ oType != OBJECT_INFO &&
+ oType != OBJECT_ENERGY &&
+ oType != OBJECT_LABO &&
+ oType != OBJECT_NUCLEAR &&
+ oType != OBJECT_PARA &&
+ oType != OBJECT_SAFE &&
+ oType != OBJECT_HUSTON ) continue;
+
+ if ( pObj->RetVirusMode() ) continue; // objet infecté ?
+
+ if ( !pObj->GetCrashSphere(0, oPos, radius) ) continue;
+ distance = Length2d(oPos, iPos);
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ }
+ }
+ if ( pBest == 0 ) return 0;
+
+ impact = pBest->RetPosition(0);
+ return pBest;
+}
+
+// Contamine les objets proches du ver.
+
+void CTaskGoto::WormFrame(float rTime)
+{
+ CObject* pObj;
+ D3DVECTOR impact, pos;
+ float dist;
+
+ m_wormLastTime += rTime;
+
+ if ( m_wormLastTime >= 0.5f )
+ {
+ m_wormLastTime = 0.0f;
+
+ pObj = WormSearch(impact);
+ if ( pObj != 0 )
+ {
+ pos = m_object->RetPosition(0);
+ dist = Length(pos, impact);
+ if ( dist <= 15.0f )
+ {
+ pObj->SetVirusMode(TRUE); // paf, infecté !
+ }
+ }
+ }
+}
+
+
+
+// Assigne le but à atteindre.
+// "dist" est la distance de laquelle il faut s'éloigner pour
+// prendre ou déposer un objet.
+
+Error CTaskGoto::Start(D3DVECTOR goal, float altitude,
+ TaskGotoGoal goalMode, TaskGotoCrash crashMode)
+{
+ D3DVECTOR pos;
+ CObject* target;
+ ObjectType type;
+ float dist;
+ int x, y;
+
+ type = m_object->RetType();
+
+ if ( goalMode == TGG_DEFAULT )
+ {
+ goalMode = TGG_STOP;
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_WORM )
+ {
+ goalMode = TGG_EXPRESS;
+ }
+ }
+
+ if ( crashMode == TGC_DEFAULT )
+ {
+//? crashMode = TGC_RIGHTLEFT;
+ crashMode = TGC_BEAM;
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_WORM ||
+ type == OBJECT_BEE )
+ {
+ crashMode = TGC_HALT;
+ }
+ }
+
+ m_altitude = altitude;
+ m_goalMode = goalMode;
+ m_crashMode = crashMode;
+ m_goalObject = goal;
+ m_goal = goal;
+
+ m_bTake = FALSE;
+ m_phase = TGP_ADVANCE;
+ m_error = ERR_OK;
+ m_try = 0;
+ m_bmFretObject = 0;
+ m_bmFinalMove = 0.0f;
+
+ pos = m_object->RetPosition(0);
+ dist = Length2d(pos, m_goal);
+ if ( dist < 10.0f && m_crashMode == TGC_BEAM )
+ {
+ m_crashMode = TGC_RIGHTLEFT;
+ }
+
+ m_bWorm = FALSE;
+ if ( type == OBJECT_WORM )
+ {
+ m_bWorm = TRUE;
+ m_wormLastTime = 0.0f;
+ }
+
+ m_bApprox = FALSE;
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH ||
+ type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs )
+ {
+ m_bApprox = TRUE;
+ }
+
+ if ( !m_bApprox && m_crashMode != TGC_BEAM )
+ {
+ target = SearchTarget(goal, 1.0f);
+ if ( target != 0 )
+ {
+ m_goal = target->RetPosition(0);
+ dist = 0.0f;
+ if ( !AdjustBuilding(m_goal, 1.0f, dist) )
+ {
+ dist = 0.0f;
+ AdjustTarget(target, m_goal, dist);
+ }
+ m_bTake = TRUE; // objet à prendre à l'arrivée (rotation finale)
+ }
+ }
+
+ m_lastDistance = 1000.0f;
+ m_physics->SetCollision(FALSE);
+
+ if ( m_crashMode == TGC_BEAM ) // avec l'algorithme des rayons ?
+ {
+ target = SearchTarget(goal, 1.0f);
+ if ( target != 0 )
+ {
+ m_goal = target->RetPosition(0);
+ dist = 4.0f;
+ if ( AdjustBuilding(m_goal, 1.0f, dist) )
+ {
+ m_bmFinalMove = dist;
+ }
+ else
+ {
+ dist = 4.0f;
+ if ( AdjustTarget(target, m_goal, dist) )
+ {
+ m_bmFretObject = target; // fret posé au sol
+ }
+ else
+ {
+ m_bmFinalMove = dist;
+ }
+ }
+ m_bTake = TRUE; // objet à prendre à l'arrivée (rotation finale)
+ }
+
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude == 0.0f )
+ {
+ pos = m_object->RetPosition(0);
+ dist = Length2d(pos, m_goal);
+ if ( dist > FLY_DIST_GROUND ) // plus de 20 mètres ?
+ {
+ m_altitude = FLY_DEF_HEIGHT; // altitude par défaut
+ }
+ }
+
+ BeamStart();
+
+ if ( m_bmFretObject == 0 )
+ {
+ x = (int)((m_goal.x+1600.0f)/BM_DIM_STEP);
+ y = (int)((m_goal.z+1600.0f)/BM_DIM_STEP);
+ if ( BitmapTestDot(0, x, y) ) // arrivée occupée ?
+ {
+#if 0
+ D3DVECTOR min, max;
+ min = m_object->RetPosition(0);
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 50.0f;
+ min.z -= 50.0f;
+ max.x += 50.0f;
+ max.z += 50.0f;
+ BitmapDebug(min, max, m_object->RetPosition(0), m_goal);
+#endif
+ m_error = ERR_GOTO_BUSY;
+ return m_error;
+ }
+ }
+ }
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskGoto::IsEnded()
+{
+ D3DVECTOR pos;
+ float limit, angle, dist, h, level;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_error != ERR_OK ) return m_error;
+
+ pos = m_object->RetPosition(0);
+
+ if ( m_phase == TGP_BEAMLEAK ) // fuite ?
+ {
+ if ( m_leakTime >= m_leakDelay )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ BeamInit();
+ m_phase = TGP_BEAMSEARCH; // faudra chercher le chemin
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TGP_BEAMSEARCH ) // recherche du chemin ?
+ {
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TGP_BEAMWCOLD ) // attend refroidissement réacteur ?
+ {
+ if ( m_altitude != 0.0f &&
+ m_physics->RetReactorRange() < 1.0f ) return ERR_CONTINUE;
+ m_phase = TGP_BEAMUP;
+ }
+
+ if ( m_phase == TGP_BEAMUP ) // décolle ?
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ level = m_terrain->RetFloorLevel(pos, TRUE, TRUE);
+ h = level+m_altitude-20.0f;
+ limit = m_terrain->RetFlyingMaxHeight();
+ if ( h > limit ) h = limit;
+ if ( pos.y < h-1.0f ) return ERR_CONTINUE;
+
+ m_physics->SetMotorSpeedY(0.0f); // stoppe la montée
+ }
+ m_phase = TGP_BEAMGOTO;
+ }
+
+ if ( m_phase == TGP_BEAMGOTO ) // goto dot list ?
+ {
+ if ( m_altitude != 0.0f &&
+ m_physics->RetReactorRange() < 0.1f ) // surchauffe ?
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_physics->SetMotorSpeedY(-1.0f); // tombe
+ m_phase = TGP_BEAMWCOLD;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_physics->RetLand() ) // au sol ?
+ {
+ limit = 1.0f;
+ }
+ else // en vol ?
+ {
+ limit = 2.0f;
+ if ( m_bmIndex < m_bmTotal ) limit *= 2.0f; // point intermédiaire
+ }
+ if ( m_bApprox ) limit = 2.0f;
+
+ if ( Abs(pos.x - m_bmPoints[m_bmIndex].x) < limit &&
+ Abs(pos.z - m_bmPoints[m_bmIndex].z) < limit )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+
+ m_bmIndex = BeamShortcut();
+
+ if ( m_bmIndex > m_bmTotal )
+ {
+ m_phase = TGP_BEAMDOWN;
+ }
+ }
+ }
+
+ if ( m_phase == TGP_BEAMDOWN ) // atteri ?
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ if ( !m_physics->RetLand() ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedY(0.0f); // stoppe la descente
+
+ m_altitude = 0.0f;
+ m_phase = TGP_BEAMGOTO; // avance finement au sol pour finir
+ m_bmIndex = m_bmTotal;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_bTake )
+ {
+ m_angle = RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z);
+ m_phase = TGP_TURN;
+ }
+ else
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ return ERR_STOP;
+ }
+ }
+
+ if ( m_goalMode == TGG_EXPRESS )
+ {
+ dist = Length2d(m_goal, pos);
+ if ( dist < 10.0f && dist > m_lastDistance )
+ {
+ return ERR_STOP;
+ }
+ m_lastDistance = dist;
+ }
+
+ if ( m_phase == TGP_ADVANCE ) // va vers l'objectif ?
+ {
+ if ( m_physics->RetLand() ) limit = 0.1f; // au sol
+ else limit = 1.0f; // en vol
+ if ( m_bApprox ) limit = 2.0f;
+
+ if ( Abs(pos.x - m_goal.x) < limit &&
+ Abs(pos.z - m_goal.z) < limit )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_phase = TGP_LAND;
+ }
+ }
+
+ if ( m_phase == TGP_LAND ) // atterri ?
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ if ( !m_physics->RetLand() ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedY(0.0f);
+ }
+
+ if ( m_bTake )
+ {
+ m_angle = RotateAngle(m_goalObject.x-pos.x, pos.z-m_goalObject.z);
+ m_phase = TGP_TURN;
+ }
+ else
+ {
+ return ERR_STOP;
+ }
+ }
+
+ if ( m_phase == TGP_TURN ) // tourne vers l'objet ?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.02f;
+ if ( m_bApprox ) limit = 0.10f;
+ if ( Abs(angle-m_angle) < limit )
+ {
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ if ( m_bmFinalMove == 0.0f ) return ERR_STOP;
+
+ m_bmFinalPos = m_object->RetPosition(0);
+ m_bmFinalDist = m_physics->RetLinLength(m_bmFinalMove);
+ m_bmTimeLimit = m_physics->RetLinTimeLength(Abs(m_bmFinalMove))*1.5f;
+ if ( m_bmTimeLimit < 0.5f ) m_bmTimeLimit = 0.5f;
+ m_phase = TGP_MOVE;
+ }
+ }
+
+ if ( m_phase == TGP_CRWAIT ) // attend après collision ?
+ {
+ if ( m_crashMode == TGC_HALT )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_error = ERR_GENERIC;
+ return m_error;
+ }
+ if ( m_time >= 1.0f )
+ {
+ if ( m_crashMode == TGC_RIGHTLEFT ||
+ m_crashMode == TGC_RIGHT ) angle = PI/2.0f; // 90 à droite
+ else angle = -PI/2.0f; // 90 à gauche
+ m_angle = NormAngle(m_object->RetAngleY(0)+angle);
+ m_phase = TGP_CRTURN;
+//? m_phase = TGP_ADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CRTURN ) // tourne après collision ?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.1f;
+ if ( Abs(angle-m_angle) < limit )
+ {
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_pos = pos;
+ m_phase = TGP_CRADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CRADVANCE ) // avance après collision ?
+ {
+ if ( Length(pos, m_pos) >= 5.0f )
+ {
+ m_phase = TGP_ADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CLWAIT ) // attend après collision ?
+ {
+ if ( m_time >= 1.0f )
+ {
+ if ( m_crashMode == TGC_RIGHTLEFT ) angle = -PI;
+ if ( m_crashMode == TGC_LEFTRIGHT ) angle = PI;
+ if ( m_crashMode == TGC_RIGHT ) angle = PI/2.0f;
+ if ( m_crashMode == TGC_LEFT ) angle = -PI/2.0f;
+ m_angle = NormAngle(m_object->RetAngleY(0)+angle);
+ m_phase = TGP_CLTURN;
+ }
+ }
+
+ if ( m_phase == TGP_CLTURN ) // tourne après collision ?
+ {
+ angle = NormAngle(m_object->RetAngleY(0));
+ limit = 0.1f;
+ if ( Abs(angle-m_angle) < limit )
+ {
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_pos = pos;
+ m_phase = TGP_CLADVANCE;
+ }
+ }
+
+ if ( m_phase == TGP_CLADVANCE ) // avance après collision ?
+ {
+ if ( Length(pos, m_pos) >= 10.0f )
+ {
+ m_phase = TGP_ADVANCE;
+ m_try ++;
+ }
+ }
+
+ if ( m_phase == TGP_MOVE ) // avance finale ?
+ {
+ if ( m_bmTimeLimit <= 0.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe
+ Abort();
+ return ERR_STOP;
+ }
+
+ dist = Length(m_bmFinalPos, m_object->RetPosition(0));
+ if ( dist < m_bmFinalDist ) return ERR_CONTINUE;
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ return ERR_STOP;
+ }
+
+ return ERR_CONTINUE;
+}
+
+
+// Cherche l'objet à la position cible.
+
+CObject* CTaskGoto::SearchTarget(D3DVECTOR pos, float margin)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR oPos;
+ float dist, min;
+ int i;
+
+ pBest = 0;
+ min = 1000000.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+
+ oPos = pObj->RetPosition(0);
+ dist = Length2d(pos, oPos);
+
+ if ( dist <= margin && dist <= min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+
+ return pBest;
+}
+
+// Ajuste la cible en fonction de l'objet.
+// Retourne TRUE s'il s'agit de fret posé au sol, dont on peut
+// s'approcher par n'importe quel côté.
+
+BOOL CTaskGoto::AdjustTarget(CObject* pObj, D3DVECTOR &pos, float &distance)
+{
+ ObjectType type;
+ Character* character;
+ D3DMATRIX* mat;
+ D3DVECTOR goal;
+ float dist, suppl;
+
+ type = m_object->RetType();
+ if ( type == OBJECT_BEE ||
+ type == OBJECT_WORM )
+ {
+ pos = pObj->RetPosition(0);
+ return FALSE; // approche unique
+ }
+
+ type = pObj->RetType();
+
+ if ( 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_TNT ||
+ type == OBJECT_SCRAP1 ||
+ type == OBJECT_SCRAP2 ||
+ type == OBJECT_SCRAP3 ||
+ type == OBJECT_SCRAP4 ||
+ type == OBJECT_SCRAP5 ||
+ type == OBJECT_BOMB ||
+ type == OBJECT_RUINmobilew1 ||
+ type == OBJECT_RUINmobilew2 ||
+ type == OBJECT_RUINmobilet1 ||
+ type == OBJECT_RUINmobilet2 ||
+ type == OBJECT_RUINmobiler1 ||
+ type == OBJECT_RUINmobiler2 )
+ {
+ pos = m_object->RetPosition(0);
+ goal = pObj->RetPosition(0);
+ dist = Length(goal, pos);
+ pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal;
+ return TRUE; // approche par tous les côtés
+ }
+
+ if ( type == OBJECT_BASE )
+ {
+ pos = m_object->RetPosition(0);
+ goal = pObj->RetPosition(0);
+ dist = Length(goal, pos);
+ pos = (pos-goal)*(TAKE_DIST+distance)/dist + goal;
+ return TRUE; // approche par tous les côtés
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr )
+ {
+ character = pObj->RetCharacter();
+ pos = character->posPower;
+ pos.x -= TAKE_DIST+TAKE_DIST_OTHER+distance;
+ mat = pObj->RetWorldMatrix(0);
+ pos = Transform(*mat, pos);
+ return FALSE; // approche unique
+ }
+
+ if ( GetHotPoint(pObj, goal, TRUE, distance, suppl) )
+ {
+ pos = goal;
+ distance += suppl;
+ return FALSE; // approche unique
+ }
+
+ pos = pObj->RetPosition(0);
+ distance = 0.0f;
+ return FALSE; // approche unique
+}
+
+// S'il on est sur un objet produit par un bâtiment (minerai produit
+// par derrick), modifie la position par-rapport au bâtiment.
+
+BOOL CTaskGoto::AdjustBuilding(D3DVECTOR &pos, float margin, float &distance)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ float dist, suppl;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+
+ if ( !GetHotPoint(pObj, oPos, FALSE, 0.0f, suppl) ) continue;
+ dist = Length2d(pos, oPos);
+ if ( dist <= margin )
+ {
+ GetHotPoint(pObj, pos, TRUE, distance, suppl);
+ distance += suppl;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Retourne le point où est produit ou posé qq chose sur un bâtiment.
+
+BOOL CTaskGoto::GetHotPoint(CObject *pObj, D3DVECTOR &pos,
+ BOOL bTake, float distance, float &suppl)
+{
+ ObjectType type;
+ D3DMATRIX* mat;
+
+ pos = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ suppl = 0.0f;
+ type = pObj->RetType();
+
+ if ( type == OBJECT_DERRICK )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 8.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_CONVERT )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 0.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_RESEARCH )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 10.0f;
+ if ( bTake && distance != 0.0f ) suppl = 2.5f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_ENERGY )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 6.0f;
+ if ( bTake && distance != 0.0f ) suppl = 6.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_TOWER )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 5.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_LABO )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 6.0f;
+ if ( bTake && distance != 0.0f ) suppl = 6.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_NUCLEAR )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 22.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+TAKE_DIST_OTHER+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_FACTORY )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 4.0f;
+ if ( bTake && distance != 0.0f ) suppl = 6.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_STATION )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 4.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_REPAIR )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 4.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += distance;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_DESTROYER )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ pos.x += 0.0f;
+ if ( bTake && distance != 0.0f ) suppl = 4.0f;
+ if ( bTake ) pos.x += TAKE_DIST+distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ if ( type == OBJECT_PARA && m_physics->RetType() == TYPE_FLYING )
+ {
+ mat = pObj->RetWorldMatrix(0);
+ if ( bTake && distance != 0.0f ) suppl = 20.0f;
+ if ( bTake ) pos.x += distance+suppl;
+ pos = Transform(*mat, pos);
+ return TRUE;
+ }
+
+ suppl = 0.0f;
+ return FALSE;
+}
+
+
+// Cherche un objet trop proche qu'il faut fuire.
+
+BOOL CTaskGoto::LeakSearch(D3DVECTOR &pos, float &delay)
+{
+ CObject *pObj, *pObstacle;
+ D3DVECTOR iPos, oPos, bPos;
+ float iRadius, oRadius, bRadius, dist, min, dir;
+ int i, j;
+
+ if ( !m_physics->RetLand() ) return FALSE; // en vol ?
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ min = 100000.0f;
+ bRadius = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( !pObj->RetActif() ) continue;
+ if ( pObj->RetTruck() != 0 ) continue; // objet porté ?
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ dist = Length2d(oPos, iPos);
+ if ( dist < min )
+ {
+ min = dist;
+ bPos = oPos;
+ bRadius = oRadius;
+ pObstacle = pObj;
+ }
+ }
+ }
+ if ( min > iRadius+bRadius+4.0f ) return FALSE;
+
+ m_bLeakRecede = FALSE;
+
+ dist = 4.0f;
+ dir = 1.0f;
+ if ( pObstacle->RetType() == OBJECT_FACTORY )
+ {
+ dist = 16.0f;
+ dir = -1.0f;
+ m_bLeakRecede = TRUE; // recule simplement
+ }
+
+ pos = bPos;
+ delay = m_physics->RetLinTimeLength(dist, dir);
+ return TRUE;
+}
+
+
+// Calcule la force de répulsion en fonction des obstacles.
+// La longueur du vecteur rendu est comprise entre 0 et 1.
+
+void CTaskGoto::ComputeRepulse(FPOINT &dir)
+{
+#if 0
+ D3DVECTOR iPos, oPos;
+ FPOINT repulse;
+ CObject *pObj;
+ float dist, iRadius, oRadius;
+ int i;
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_goalObject);
+ if ( dist <= 1.0f ) continue;
+
+ pObj->GetGlobalSphere(oPos, oRadius);
+ oRadius += iRadius+m_physics->RetLinStopLength()*1.1f;
+ dist = Length2d(oPos, iPos);
+ if ( dist <= oRadius )
+ {
+ repulse.x = iPos.x-oPos.x;
+ repulse.y = iPos.z-oPos.z;
+
+//? dist = 0.2f-(0.2f*dist/oRadius);
+ dist = powf(dist/oRadius, 2.0f);
+ dist = 0.2f-0.2f*dist;
+ repulse.x *= dist;
+ repulse.y *= dist;
+//? repulse.x /= dist;
+//? repulse.y /= dist;
+
+ dir.x += repulse.x;
+ dir.y += repulse.y;
+ }
+ }
+#else
+ ObjectType iType, oType;
+ D3DVECTOR iPos, oPos;
+ FPOINT repulse;
+ CObject *pObj;
+ float gDist, add, addi, fac, dist, iRadius, oRadius;
+ int i, j;
+ BOOL bAlien;
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+
+ // Le ver passe partout et à travers tout !
+ iType = m_object->RetType();
+ if ( iType == OBJECT_WORM ) return;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+ gDist = Length(iPos, m_goal);
+
+ add = m_physics->RetLinStopLength()*1.1f; // distance de freinage
+ fac = 2.0f;
+
+ if ( iType == OBJECT_MOBILEwa ||
+ iType == OBJECT_MOBILEwc ||
+ iType == OBJECT_MOBILEwi ||
+ iType == OBJECT_MOBILEws ||
+ iType == OBJECT_MOBILEwt ) // roues ?
+ {
+ add = 5.0f;
+ fac = 1.5f;
+ }
+ if ( iType == OBJECT_MOBILEta ||
+ iType == OBJECT_MOBILEtc ||
+ iType == OBJECT_MOBILEti ||
+ iType == OBJECT_MOBILEts ||
+ iType == OBJECT_MOBILEtt ||
+ iType == OBJECT_MOBILEdr ) // chenilles ?
+ {
+ add = 4.0f;
+ fac = 1.5f;
+ }
+ if ( iType == OBJECT_MOBILEfa ||
+ iType == OBJECT_MOBILEfc ||
+ iType == OBJECT_MOBILEfi ||
+ iType == OBJECT_MOBILEfs ||
+ iType == OBJECT_MOBILEft ) // volant ?
+ {
+ if ( m_physics->RetLand() )
+ {
+ add = 5.0f;
+ fac = 1.5f;
+ }
+ else
+ {
+ add = 10.0f;
+ fac = 1.5f;
+ }
+ }
+ if ( iType == OBJECT_MOBILEia ||
+ iType == OBJECT_MOBILEic ||
+ iType == OBJECT_MOBILEii ||
+ iType == OBJECT_MOBILEis ||
+ iType == OBJECT_MOBILEit ) // pattes ?
+ {
+ add = 4.0f;
+ fac = 1.5f;
+ }
+ if ( iType == OBJECT_BEE ) // guêpe ?
+ {
+ if ( m_physics->RetLand() )
+ {
+ add = 3.0f;
+ fac = 1.5f;
+ }
+ else
+ {
+ add = 5.0f;
+ fac = 1.5f;
+ }
+ }
+
+ bAlien = FALSE;
+ if ( iType == OBJECT_MOTHER ||
+ iType == OBJECT_ANT ||
+ iType == OBJECT_SPIDER ||
+ iType == OBJECT_BEE ||
+ iType == OBJECT_WORM )
+ {
+ bAlien = TRUE;
+ }
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oType = pObj->RetType();
+
+ if ( oType == OBJECT_WORM ) continue;
+
+ if ( bAlien )
+ {
+ if ( oType == OBJECT_STONE ||
+ oType == OBJECT_URANIUM ||
+ oType == OBJECT_METAL ||
+ oType == OBJECT_POWER ||
+ oType == OBJECT_ATOMIC ||
+ oType == OBJECT_BULLET ||
+ oType == OBJECT_BBOX ||
+ oType == OBJECT_KEYa ||
+ oType == OBJECT_KEYb ||
+ oType == OBJECT_KEYc ||
+ oType == OBJECT_KEYd ||
+ oType == OBJECT_TNT ||
+ oType == OBJECT_SCRAP1 ||
+ oType == OBJECT_SCRAP2 ||
+ oType == OBJECT_SCRAP3 ||
+ oType == OBJECT_SCRAP4 ||
+ oType == OBJECT_SCRAP5 ||
+ oType == OBJECT_BOMB ||
+ (oType >= OBJECT_PLANT0 &&
+ oType <= OBJECT_PLANT19 ) ||
+ (oType >= OBJECT_MUSHROOM0 &&
+ oType <= OBJECT_MUSHROOM9 ) ) continue;
+ }
+
+ addi = add;
+ if ( iType == OBJECT_BEE &&
+ oType == OBJECT_BEE )
+ {
+ addi = 2.0f; // entre guèpes, faut pas trop s'embêter
+ }
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( oPos.y-oRadius > iPos.y+iRadius ) continue;
+ if ( oPos.y+oRadius < iPos.y-iRadius ) continue;
+
+ dist = Length(oPos, m_goal);
+ if ( dist <= 1.0f ) continue; // sur le but ?
+
+ oRadius += iRadius+addi;
+ dist = Length2d(oPos, iPos);
+ if ( dist > gDist ) continue; // plus loin que le but ?
+ if ( dist <= oRadius )
+ {
+ repulse.x = iPos.x-oPos.x;
+ repulse.y = iPos.z-oPos.z;
+
+ dist = powf(dist/oRadius, fac);
+ dist = 0.2f-0.2f*dist;
+ repulse.x *= dist;
+ repulse.y *= dist;
+
+ dir.x += repulse.x;
+ dir.y += repulse.y;
+ }
+ }
+ }
+#endif
+}
+
+// Calcule la force de répulsion verticale en fonction des obstacles.
+// La longueur du vecteur rendu est comprise entre -1 et 1.
+
+void CTaskGoto::ComputeFlyingRepulse(float &dir)
+{
+ ObjectType oType;
+ D3DVECTOR iPos, oPos;
+ CObject *pObj;
+ float add, fac, dist, iRadius, oRadius, repulse;
+ int i, j;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ add = 0.0f;
+ fac = 1.5f;
+ dir = 0.0f;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ oType = pObj->RetType();
+
+ if ( oType == OBJECT_WORM ) continue;
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ oRadius += iRadius+add;
+ dist = Length2d(oPos, iPos);
+ if ( dist <= oRadius )
+ {
+ repulse = iPos.y-oPos.y;
+
+ dist = powf(dist/oRadius, fac);
+ dist = 0.2f-0.2f*dist;
+ repulse *= dist;
+
+ dir += repulse;
+ }
+ }
+ }
+
+ if ( dir < -1.0f ) dir = -1.0f;
+ if ( dir > 1.0f ) dir = 1.0f;
+}
+
+
+
+// Parmi tous les points suivants, cherche s'il en existe un qui
+// permet d'y aller directement à vol d'oiseau. Si oui, saute tous
+// les points intermédiaires inutiles.
+
+int CTaskGoto::BeamShortcut()
+{
+ int i;
+
+ for ( i=m_bmTotal ; i>=m_bmIndex+2 ; i-- ) // cherche depuis le dernier
+ {
+ if ( BitmapTestLine(m_bmPoints[m_bmIndex], m_bmPoints[i], 0.0f, FALSE) )
+ {
+ return i; // bingo, trouvé
+ }
+ }
+
+ return m_bmIndex+1; // va simplement au point suivant
+}
+
+// C'est le grand départ.
+
+void CTaskGoto::BeamStart()
+{
+ D3DVECTOR min, max;
+
+ BitmapOpen();
+ BitmapObject();
+
+ min = m_object->RetPosition(0);
+ max = m_goal;
+ if ( min.x > max.x ) Swap(min.x, max.x);
+ if ( min.z > max.z ) Swap(min.z, max.z);
+ min.x -= 10.0f*BM_DIM_STEP;
+ min.z -= 10.0f*BM_DIM_STEP;
+ max.x += 10.0f*BM_DIM_STEP;
+ max.z += 10.0f*BM_DIM_STEP;
+ BitmapTerrain(min, max);
+
+ if ( LeakSearch(m_leakPos, m_leakDelay) )
+ {
+ m_phase = TGP_BEAMLEAK; // il faut d'abord fuire
+ m_leakTime = 0.0f;
+ }
+ else
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ BeamInit();
+ m_phase = TGP_BEAMSEARCH; // faudra chercher le chemin
+ }
+}
+
+// Initialisation avant le premier BeamSearch.
+
+void CTaskGoto::BeamInit()
+{
+ int i;
+
+ for ( i=0 ; i<MAXPOINTS ; i++ )
+ {
+ m_bmIter[i] = -1;
+ }
+ m_bmStep = 0;
+}
+
+// Calcule les points par où passer pour aller de start à goal.
+// Retourne :
+// ERR_OK si c'est bon
+// ERR_GOTO_IMPOSSIBLE si impossible
+// ERR_GOTO_ITER si avorté car trop de récursions
+// ERR_CONTINUE si pas encore fini
+// goalRadius: distance à laquelle il faut s'approcher du but
+
+Error CTaskGoto::BeamSearch(const D3DVECTOR &start, const D3DVECTOR &goal,
+ float goalRadius)
+{
+ float step, len;
+ int nbIter;
+
+ m_bmStep ++;
+
+ len = Length2d(start, goal);
+ step = len/5.0f;
+ if ( step < BM_DIM_STEP*2.1f ) step = BM_DIM_STEP*2.1f;
+ if ( step > 20.0f ) step = 20.0f;
+ nbIter = 200; // pour ne pas trop baisser le framerate
+ m_bmIterCounter = 0;
+ return BeamExplore(start, start, goal, goalRadius, 165.0f*PI/180.0f, 22, step, 0, nbIter);
+}
+
+// prevPos: position précédente
+// curPos: position courante
+// goalPos: position qu'on cherche à atteindre
+// angle: angle par rapport au but qu'on explore
+// nbDiv: nombre du sous-divisions qu'on fait avec angle
+// step longuer d'un pas
+// i nombre de récursions effectuées
+// nbIter nombre max. d'iterations qu'on a le droit de faire avant d'interrompre provisoirement
+
+Error CTaskGoto::BeamExplore(const D3DVECTOR &prevPos, const D3DVECTOR &curPos,
+ const D3DVECTOR &goalPos, float goalRadius,
+ float angle, int nbDiv, float step,
+ int i, int nbIter)
+{
+ D3DVECTOR newPos;
+ Error ret;
+ int iDiv, iClear, iLar;
+
+ iLar = 0;
+ if ( i >= MAXPOINTS ) return ERR_GOTO_ITER; // trop de récursion
+
+ if ( m_bmIter[i] == -1 )
+ {
+ m_bmIter[i] = 0;
+
+ if ( i == 0 )
+ {
+ m_bmPoints[i] = curPos;
+ }
+ else
+ {
+ if ( !BitmapTestLine(prevPos, curPos, angle/nbDiv, TRUE) ) return ERR_GOTO_IMPOSSIBLE;
+
+ m_bmPoints[i] = curPos;
+
+ if ( Length2d(curPos, goalPos)-goalRadius <= step )
+ {
+ if ( goalRadius == 0.0f )
+ {
+ newPos = goalPos;
+ }
+ else
+ {
+ newPos = BeamPoint(curPos, goalPos, 0, Length2d(curPos, goalPos)-goalRadius);
+ }
+ if ( BitmapTestLine(curPos, newPos, angle/nbDiv, FALSE) )
+ {
+ m_bmPoints[i+1] = newPos;
+ m_bmTotal = i+1;
+ return ERR_OK;
+ }
+ }
+ }
+ }
+
+ if ( iLar >= m_bmIter[i] )
+ {
+ newPos = BeamPoint(curPos, goalPos, 0, step);
+ ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
+ if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
+ m_bmIter[i] = iLar+1;
+ for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
+ m_bmIterCounter ++;
+ if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
+ }
+ iLar ++;
+
+ for ( iDiv=1 ; iDiv<=nbDiv ; iDiv++ )
+ {
+ if ( iLar >= m_bmIter[i] )
+ {
+ newPos = BeamPoint(curPos, goalPos, angle*iDiv/nbDiv, step);
+ ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
+ if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
+ m_bmIter[i] = iLar+1;
+ for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
+ m_bmIterCounter ++;
+ if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
+ }
+ iLar ++;
+
+ if ( iLar >= m_bmIter[i] )
+ {
+ newPos = BeamPoint(curPos, goalPos, -angle*iDiv/nbDiv, step);
+ ret = BeamExplore(curPos, newPos, goalPos, goalRadius, angle, nbDiv, step, i+1, nbIter);
+ if ( ret != ERR_GOTO_IMPOSSIBLE ) return ret;
+ m_bmIter[i] = iLar+1;
+ for ( iClear=i+1 ; iClear<=MAXPOINTS ; iClear++ ) m_bmIter[iClear] = -1;
+ m_bmIterCounter ++;
+ if ( m_bmIterCounter >= nbIter ) return ERR_CONTINUE;
+ }
+ iLar ++;
+ }
+
+ return ERR_GOTO_IMPOSSIBLE;
+}
+
+// Soit une droite "start-goal". Calcule le point situé à la distance
+// "step" du point "start" et faisant un angle "angle" avec la droite.
+
+D3DVECTOR CTaskGoto::BeamPoint(const D3DVECTOR &startPoint,
+ const D3DVECTOR &goalPoint,
+ float angle, float step)
+{
+ D3DVECTOR resPoint;
+ float goalAngle;
+
+ goalAngle = RotateAngle(goalPoint.x-startPoint.x, goalPoint.z-startPoint.z);
+
+ resPoint.x = startPoint.x + cosf(goalAngle+angle)*step;
+ resPoint.z = startPoint.z + sinf(goalAngle+angle)*step;
+ resPoint.y = 0.0f;
+
+ return resPoint;
+}
+
+// Affiche une partion de bitmap.
+
+void CTaskGoto::BitmapDebug(const D3DVECTOR &min, const D3DVECTOR &max,
+ const D3DVECTOR &start, const D3DVECTOR &goal)
+{
+ int minx, miny, maxx, maxy, x, y, i ,n;
+ char s[2000];
+
+ minx = (int)((min.x+1600.0f)/BM_DIM_STEP);
+ miny = (int)((min.z+1600.0f)/BM_DIM_STEP);
+ maxx = (int)((max.x+1600.0f)/BM_DIM_STEP);
+ maxy = (int)((max.z+1600.0f)/BM_DIM_STEP);
+
+ if ( minx > maxx ) Swap(minx, maxx);
+ if ( miny > maxy ) Swap(miny, maxy);
+
+ OutputDebugString("Bitmap :\n");
+ for ( y=miny ; y<=maxy ; y++ )
+ {
+ s[0] = 0;
+ for ( x=minx ; x<=maxx ; x++ )
+ {
+ n = -1;
+ for ( i=0 ; i<=m_bmTotal ; i++ )
+ {
+ if ( x == (int)((m_bmPoints[i].x+1600.0f)/BM_DIM_STEP) &&
+ y == (int)((m_bmPoints[i].z+1600.0f)/BM_DIM_STEP) )
+ {
+ n = i;
+ break;
+ }
+ }
+
+ if ( BitmapTestDot(0, x,y) )
+ {
+ strcat(s, "o");
+ }
+ else
+ {
+ if ( BitmapTestDot(1, x,y) )
+ {
+ strcat(s, "-");
+ }
+ else
+ {
+ strcat(s, ".");
+ }
+ }
+
+ if ( x == (int)((start.x+1600.0f)/BM_DIM_STEP) &&
+ y == (int)((start.z+1600.0f)/BM_DIM_STEP) )
+ {
+ strcat(s, "s");
+ }
+ else
+ if ( x == (int)((goal.x+1600.0f)/BM_DIM_STEP) &&
+ y == (int)((goal.z+1600.0f)/BM_DIM_STEP) )
+ {
+ strcat(s, "g");
+ }
+ else
+ if ( n != -1 )
+ {
+ char ss[2];
+ ss[0] = 'A'+n;
+ ss[1] = 0;
+ strcat(s, ss);
+ }
+ else
+ {
+ strcat(s, " ");
+ }
+ }
+ strcat(s, "\n");
+ OutputDebugString(s);
+ }
+}
+
+// Teste si un chemin le long d'une droite est possible.
+
+BOOL CTaskGoto::BitmapTestLine(const D3DVECTOR &start, const D3DVECTOR &goal,
+ float stepAngle, BOOL bSecond)
+{
+ D3DVECTOR pos, inc;
+ float dist, step;
+ float distNoB2;
+ int i, max, x, y;
+
+ if ( m_bmArray == 0 ) return TRUE;
+
+ dist = Length2d(start, goal);
+ if ( dist == 0.0f ) return TRUE;
+ step = BM_DIM_STEP*0.5f;
+
+ inc.x = (goal.x-start.x)*step/dist;
+ inc.z = (goal.z-start.z)*step/dist;
+
+ pos = start;
+
+ if ( bSecond )
+ {
+ x = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ y = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+ BitmapSetDot(1, x, y); // met le flag du point de départ
+ }
+
+ max = (int)(dist/step);
+ if ( max == 0 ) max = 1;
+ distNoB2 = BM_DIM_STEP*sqrtf(2.0f)/sinf(stepAngle);
+ for ( i=0 ; i<max ; i++ )
+ {
+ if ( i == max-1 )
+ {
+ pos = goal; // teste le point d'arrivée
+ }
+ else
+ {
+ pos.x += inc.x;
+ pos.z += inc.z;
+ }
+
+ x = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ y = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+
+ if ( bSecond )
+ {
+ if ( i > 2 && BitmapTestDot(1, x, y) ) return FALSE;
+
+ if ( step*(i+1) > distNoB2 && i < max-2 )
+ {
+ BitmapSetDot(1, x, y);
+ }
+ }
+
+ if ( BitmapTestDot(0, x, y) ) return FALSE;
+ }
+ return TRUE;
+}
+
+// Ajoute les objets dans le bitmap.
+
+void CTaskGoto::BitmapObject()
+{
+ CObject *pObj;
+ ObjectType type;
+ D3DVECTOR iPos, oPos;
+ float iRadius, oRadius, h;
+ int i, j;
+
+ m_object->GetCrashSphere(0, iPos, iRadius);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( pObj == m_object ) continue;
+ if ( pObj == m_bmFretObject ) continue;
+ if ( pObj->RetTruck() != 0 ) continue;
+
+ h = m_terrain->RetFloorLevel(pObj->RetPosition(0), FALSE);
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f )
+ {
+ h += m_altitude;
+ }
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( m_physics->RetType() == TYPE_FLYING && m_altitude > 0.0f ) // volant ?
+ {
+ if ( oPos.y-oRadius > h+8.0f ||
+ oPos.y+oRadius < h-8.0f ) continue;
+ }
+ else // rampant ?
+ {
+ if ( oPos.y-oRadius > h+8.0f ) continue;
+ }
+
+ if ( type == OBJECT_PARA ) oRadius -= 2.0f;
+ BitmapSetCircle(oPos, oRadius+iRadius+4.0f);
+ }
+ }
+}
+
+// Ajoute une portion de terrain dans le bitmap.
+
+void CTaskGoto::BitmapTerrain(const D3DVECTOR &min, const D3DVECTOR &max)
+{
+ int minx, miny, maxx, maxy;
+
+ minx = (int)((min.x+1600.0f)/BM_DIM_STEP);
+ miny = (int)((min.z+1600.0f)/BM_DIM_STEP);
+ maxx = (int)((max.x+1600.0f)/BM_DIM_STEP);
+ maxy = (int)((max.z+1600.0f)/BM_DIM_STEP);
+
+ BitmapTerrain(minx, miny, maxx, maxy);
+}
+
+// Ajoute une portion de terrain dans le bitmap.
+
+void CTaskGoto::BitmapTerrain(int minx, int miny, int maxx, int maxy)
+{
+ ObjectType type;
+ D3DVECTOR p;
+ float aLimit, angle, h;
+ int x, y;
+ BOOL bAcceptWater, bFly;
+
+ if ( minx > maxx ) Swap(minx, maxx);
+ if ( miny > maxy ) Swap(miny, maxy);
+
+ if ( minx < 0 ) minx = 0;
+ if ( miny < 0 ) miny = 0;
+ if ( maxx > m_bmSize-1 ) maxx = m_bmSize-1;
+ if ( maxy > m_bmSize-1 ) maxy = m_bmSize-1;
+
+ if ( minx > m_bmMinX ) minx = m_bmMinX;
+ if ( miny > m_bmMinY ) miny = m_bmMinY;
+ if ( maxx < m_bmMaxX ) maxx = m_bmMaxX;
+ if ( maxy < m_bmMaxY ) maxy = m_bmMaxY;
+
+ if ( minx >= m_bmMinX && maxx <= m_bmMaxX &&
+ miny >= m_bmMinY && maxy <= m_bmMaxY ) return;
+
+ aLimit = 20.0f*PI/180.0f;
+ bAcceptWater = FALSE;
+ bFly = FALSE;
+
+ type = m_object->RetType();
+
+ if ( type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEtg ) // roues ?
+ {
+ aLimit = 20.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEts ) // chenilles ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ) // grosses chenilles ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEsa ) // chenilles sous-marin ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ bAcceptWater = TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEdr ) // chenilles dessinateur ?
+ {
+ aLimit = 35.0f*PI/180.0f;
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEft ) // volant ?
+ {
+ aLimit = 15.0f*PI/180.0f;
+ bFly = TRUE;
+ }
+
+ if ( type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILEii ) // pattes d'insecte ?
+ {
+ aLimit = 60.0f*PI/180.0f;
+ }
+
+ for ( y=miny ; y<=maxy ; y++ )
+ {
+ for ( x=minx ; x<=maxx ; x++ )
+ {
+ if ( x >= m_bmMinX && x <= m_bmMaxX &&
+ y >= m_bmMinY && y <= m_bmMaxY ) continue;
+
+ p.x = x*BM_DIM_STEP-1600.0f;
+ p.z = y*BM_DIM_STEP-1600.0f;
+
+ if ( bFly ) // robot volant ?
+ {
+ h = m_terrain->RetFloorLevel(p, TRUE);
+ if ( h >= m_terrain->RetFlyingMaxHeight()-5.0f )
+ {
+ BitmapSetDot(0, x, y);
+ }
+ continue;
+ }
+
+ if ( !bAcceptWater ) // ne va pas sous l'eau ?
+ {
+ h = m_terrain->RetFloorLevel(p, TRUE);
+ if ( h < m_water->RetLevel()-2.0f ) // sous l'eau (*) ?
+ {
+//? BitmapSetDot(0, x, y);
+ BitmapSetCircle(p, BM_DIM_STEP*1.0f);
+ continue;
+ }
+ }
+
+ angle = m_terrain->RetFineSlope(p);
+ if ( angle > aLimit )
+ {
+ BitmapSetDot(0, x, y);
+ }
+ }
+ }
+
+ m_bmMinX = minx;
+ m_bmMinY = miny;
+ m_bmMaxX = maxx;
+ m_bmMaxY = maxy; // agrandi la zone rectangulaire
+}
+
+// (*) Accepte qu'un robot soit 50cm sous l'eau, par exemple
+// sur Tropica 3 !
+
+// Ouvre un bitmap vide.
+
+BOOL CTaskGoto::BitmapOpen()
+{
+ BitmapClose();
+
+ m_bmSize = (int)(3200.0f/BM_DIM_STEP);
+ m_bmArray = (unsigned char*)malloc(m_bmSize*m_bmSize/8*2);
+ ZeroMemory(m_bmArray, m_bmSize*m_bmSize/8*2);
+
+ m_bmOffset = m_bmSize/2;
+ m_bmLine = m_bmSize/8;
+
+ m_bmMinX = m_bmSize; // zone rectangulaire inexistante
+ m_bmMinY = m_bmSize;
+ m_bmMaxX = 0;
+ m_bmMaxY = 0;
+
+ return TRUE;
+}
+
+// Ferme le bitmap.
+
+BOOL CTaskGoto::BitmapClose()
+{
+ free(m_bmArray);
+ m_bmArray = 0;
+ return TRUE;
+}
+
+// Met un cercle dans le bitmap.
+
+void CTaskGoto::BitmapSetCircle(const D3DVECTOR &pos, float radius)
+{
+ float d, r;
+ int cx, cy, ix, iy;
+
+ cx = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ cy = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+ r = radius/BM_DIM_STEP;
+
+ for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ )
+ {
+ for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ )
+ {
+ d = Length((float)(ix-cx), (float)(iy-cy));
+ if ( d > r ) continue;
+ BitmapSetDot(0, ix, iy);
+ }
+ }
+}
+
+// Enlève un cercle dans le bitmap.
+
+void CTaskGoto::BitmapClearCircle(const D3DVECTOR &pos, float radius)
+{
+ float d, r;
+ int cx, cy, ix, iy;
+
+ cx = (int)((pos.x+1600.0f)/BM_DIM_STEP);
+ cy = (int)((pos.z+1600.0f)/BM_DIM_STEP);
+ r = radius/BM_DIM_STEP;
+
+ for ( iy=cy-(int)r ; iy<=cy+(int)r ; iy++ )
+ {
+ for ( ix=cx-(int)r ; ix<=cx+(int)r ; ix++ )
+ {
+ d = Length((float)(ix-cx), (float)(iy-cy));
+ if ( d > r ) continue;
+ BitmapClearDot(0, ix, iy);
+ }
+ }
+}
+
+// Met un point dans le bitmap.
+// x:y: 0..m_bmSize-1
+
+void CTaskGoto::BitmapSetDot(int rank, int x, int y)
+{
+ if ( x < 0 || x >= m_bmSize ||
+ y < 0 || y >= m_bmSize ) return;
+
+ m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] |= (1<<x%8);
+}
+
+// Enlève un point dans le bitmap.
+// x:y: 0..m_bmSize-1
+
+void CTaskGoto::BitmapClearDot(int rank, int x, int y)
+{
+ if ( x < 0 || x >= m_bmSize ||
+ y < 0 || y >= m_bmSize ) return;
+
+ m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] &= ~(1<<x%8);
+}
+
+// Teste un point dans le bitmap.
+// x:y: 0..m_bmSize-1
+
+BOOL CTaskGoto::BitmapTestDot(int rank, int x, int y)
+{
+ if ( x < 0 || x >= m_bmSize ||
+ y < 0 || y >= m_bmSize ) return FALSE;
+
+ if ( x < m_bmMinX || x > m_bmMaxX ||
+ y < m_bmMinY || y > m_bmMaxY )
+ {
+ BitmapTerrain(x-10,y-10, x+10,y+10); // refait une couche
+ }
+
+ return m_bmArray[rank*m_bmLine*m_bmSize + m_bmLine*y + x/8] & (1<<x%8);
+}
+
+
diff --git a/src/taskgoto.h b/src/taskgoto.h
new file mode 100644
index 0000000..094cd6b
--- /dev/null
+++ b/src/taskgoto.h
@@ -0,0 +1,147 @@
+// taskgoto.h
+
+#ifndef _TASKGOTO_H_
+#define _TASKGOTO_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+#define MAXPOINTS 500
+
+
+
+enum TaskGotoGoal
+{
+ TGG_DEFAULT = -1, // mode par défaut
+ TGG_STOP = 0, // va à destination en s'arrêtant avec précision
+ TGG_EXPRESS = 1, // va à destination sans s'arrêter
+};
+
+enum TaskGotoCrash
+{
+ TGC_DEFAULT = -1, // mode par défaut
+ TGC_HALT = 0, // stoppe si collision
+ TGC_RIGHTLEFT = 1, // droite-gauche
+ TGC_LEFTRIGHT = 2, // gauche-droite
+ TGC_LEFT = 3, // gauche
+ TGC_RIGHT = 4, // droite
+ TGC_BEAM = 5, // algorithme "rayons de soleil"
+};
+
+
+enum TaskGotoPhase
+{
+ TGP_ADVANCE = 1, // avance
+ TGP_LAND = 2, // atterri
+ TGP_TURN = 3, // tourne pour finir
+ TGP_MOVE = 4, // avance pour finir
+ TGP_CRWAIT = 5, // attend après collision
+ TGP_CRTURN = 6, // tourne à droite après collision
+ TGP_CRADVANCE = 7, // avance à droite après collision
+ TGP_CLWAIT = 8, // attend après collision
+ TGP_CLTURN = 9, // tourne à gauche après collision
+ TGP_CLADVANCE = 10, // avance à gauche après collision
+ TGP_BEAMLEAK = 11, // beam: leak (fuite)
+ TGP_BEAMSEARCH = 12, // beam: search
+ TGP_BEAMWCOLD = 13, // beam: attend refroidissement réacteur
+ TGP_BEAMUP = 14, // beam: décolle
+ TGP_BEAMGOTO = 15, // beam: goto dot list
+ TGP_BEAMDOWN = 16, // beam: atterri
+};
+
+
+
+class CTaskGoto : public CTask
+{
+public:
+ CTaskGoto(CInstanceManager* iMan, CObject* object);
+ ~CTaskGoto();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(D3DVECTOR goal, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode);
+ Error IsEnded();
+
+protected:
+ CObject* WormSearch(D3DVECTOR &impact);
+ void WormFrame(float rTime);
+ CObject* SearchTarget(D3DVECTOR pos, float margin);
+ BOOL AdjustTarget(CObject* pObj, D3DVECTOR &pos, float &distance);
+ BOOL AdjustBuilding(D3DVECTOR &pos, float margin, float &distance);
+ BOOL GetHotPoint(CObject *pObj, D3DVECTOR &pos, BOOL bTake, float distance, float &suppl);
+ BOOL LeakSearch(D3DVECTOR &pos, float &delay);
+ void ComputeRepulse(FPOINT &dir);
+ void ComputeFlyingRepulse(float &dir);
+
+ int BeamShortcut();
+ void BeamStart();
+ void BeamInit();
+ Error BeamSearch(const D3DVECTOR &start, const D3DVECTOR &goal, float goalRadius);
+ Error BeamExplore(const D3DVECTOR &prevPos, const D3DVECTOR &curPos, const D3DVECTOR &goalPos, float goalRadius, float angle, int nbDiv, float step, int i, int nbIter);
+ D3DVECTOR BeamPoint(const D3DVECTOR &startPoint, const D3DVECTOR &goalPoint, float angle, float step);
+
+ void BitmapDebug(const D3DVECTOR &min, const D3DVECTOR &max, const D3DVECTOR &start, const D3DVECTOR &goal);
+ BOOL BitmapTestLine(const D3DVECTOR &start, const D3DVECTOR &goal, float stepAngle, BOOL bSecond);
+ void BitmapObject();
+ void BitmapTerrain(const D3DVECTOR &min, const D3DVECTOR &max);
+ void BitmapTerrain(int minx, int miny, int maxx, int maxy);
+ BOOL BitmapOpen();
+ BOOL BitmapClose();
+ void BitmapSetCircle(const D3DVECTOR &pos, float radius);
+ void BitmapClearCircle(const D3DVECTOR &pos, float radius);
+ void BitmapSetDot(int rank, int x, int y);
+ void BitmapClearDot(int rank, int x, int y);
+ BOOL BitmapTestDot(int rank, int x, int y);
+
+protected:
+ D3DVECTOR m_goal;
+ D3DVECTOR m_goalObject;
+ float m_angle;
+ float m_altitude;
+ TaskGotoCrash m_crashMode;
+ TaskGotoGoal m_goalMode;
+ TaskGotoPhase m_phase;
+ int m_try;
+ Error m_error;
+ BOOL m_bTake;
+ float m_stopLength; // distance de freinage
+ float m_time;
+ D3DVECTOR m_pos;
+ BOOL m_bWorm;
+ BOOL m_bApprox;
+ float m_wormLastTime;
+ float m_lastDistance;
+
+ int m_bmSize; // largeur ou hauteur du tableau
+ int m_bmOffset; // m_bmSize/2
+ int m_bmLine; // incrément ligne m_bmSize/8
+ unsigned char* m_bmArray; // tableau de bits
+ int m_bmMinX, m_bmMinY;
+ int m_bmMaxX, m_bmMaxY;
+ int m_bmTotal; // nb de points dans m_bmPoints
+ int m_bmIndex; // index dans m_bmPoints
+ D3DVECTOR m_bmPoints[MAXPOINTS+2];
+ char m_bmIter[MAXPOINTS+2];
+ int m_bmIterCounter;
+ CObject* m_bmFretObject;
+ float m_bmFinalMove; // distance finale à avancer
+ float m_bmFinalDist; // distance effective à avancer
+ D3DVECTOR m_bmFinalPos; // position initiale avant avance
+ float m_bmTimeLimit;
+ int m_bmStep;
+ D3DVECTOR m_bmWatchDogPos;
+ float m_bmWatchDogTime;
+ D3DVECTOR m_leakPos; // position initiale à fuire
+ float m_leakDelay;
+ float m_leakTime;
+ BOOL m_bLeakRecede;
+};
+
+
+#endif //_TASKGOTO_H_
diff --git a/src/taskgungoal.cpp b/src/taskgungoal.cpp
new file mode 100644
index 0000000..9066c5a
--- /dev/null
+++ b/src/taskgungoal.cpp
@@ -0,0 +1,145 @@
+// taskgungoal.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "object.h"
+#include "sound.h"
+#include "task.h"
+#include "taskgungoal.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskGunGoal::CTaskGunGoal(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskGunGoal::~CTaskGunGoal()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskGunGoal::EventProcess(const Event &event)
+{
+ float dir;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_progress += event.rTime*m_speed;
+
+ if ( m_progress < 1.0f )
+ {
+ dir = m_initialDirV + (m_finalDirV-m_initialDirV)*m_progress;
+ }
+ else
+ {
+ dir = m_finalDirV;
+ }
+ m_object->SetGunGoalV(dir);
+
+ if ( m_progress < 1.0f )
+ {
+ dir = m_initialDirH + (m_finalDirH-m_initialDirH)*m_progress;
+ }
+ else
+ {
+ dir = m_finalDirH;
+ }
+ m_object->SetGunGoalH(dir);
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskGunGoal::Start(float dirV, float dirH)
+{
+ float speedV, speedH;
+ int i;
+
+ m_initialDirV = m_object->RetGunGoalV();
+ m_object->SetGunGoalV(dirV);
+ m_finalDirV = m_object->RetGunGoalV(); // direction possible
+ m_object->SetGunGoalV(m_initialDirV); // remet direction initiale
+
+ if ( m_finalDirV == m_initialDirV )
+ {
+ speedV = 100.0f;
+ }
+ else
+ {
+ speedV = 1.0f/(Abs(m_finalDirV-m_initialDirV)*1.0f);
+ }
+
+ m_initialDirH = m_object->RetGunGoalH();
+ m_object->SetGunGoalH(dirH);
+ m_finalDirH = m_object->RetGunGoalH(); // direction possible
+ m_object->SetGunGoalH(m_initialDirH); // remet direction initiale
+
+ if ( m_finalDirH == m_initialDirH )
+ {
+ speedH = 100.0f;
+ }
+ else
+ {
+ speedH = 1.0f/(Abs(m_finalDirH-m_initialDirH)*1.0f);
+ }
+
+ m_speed = Min(speedV, speedH);
+
+ if ( m_finalDirV != m_initialDirV ||
+ m_finalDirH != m_initialDirH )
+ {
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.3f, 1.5f, TRUE);
+ m_sound->AddEnvelope(i, 0.3f, 1.5f, 1.0f/m_speed, SOPER_STOP);
+ }
+
+ m_progress = 0.0f;
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskGunGoal::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_initialDirV == m_finalDirV &&
+ m_initialDirH == m_finalDirH ) return ERR_STOP;
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ m_object->SetGunGoalV(m_finalDirV);
+ m_object->SetGunGoalH(m_finalDirH);
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskGunGoal::Abort()
+{
+ return TRUE;
+}
+
diff --git a/src/taskgungoal.h b/src/taskgungoal.h
new file mode 100644
index 0000000..63630a0
--- /dev/null
+++ b/src/taskgungoal.h
@@ -0,0 +1,38 @@
+// taskgungoal.h
+
+#ifndef _TASKGUNGOAL_H_
+#define _TASKGUNGOAL_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskGunGoal : public CTask
+{
+public:
+ CTaskGunGoal(CInstanceManager* iMan, CObject* object);
+ ~CTaskGunGoal();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float dirV, float dirH);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ float m_progress;
+ float m_speed;
+ float m_initialDirV; // direction initiale
+ float m_finalDirV; // direction à atteindre
+ float m_initialDirH; // direction initiale
+ float m_finalDirH; // direction à atteindre
+};
+
+
+#endif //_TASKGUNGOAL_H_
diff --git a/src/taskinfo.cpp b/src/taskinfo.cpp
new file mode 100644
index 0000000..7789732
--- /dev/null
+++ b/src/taskinfo.cpp
@@ -0,0 +1,217 @@
+// taskinfo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "sound.h"
+#include "auto.h"
+#include "autoinfo.h"
+#include "task.h"
+#include "taskinfo.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskInfo::CTaskInfo(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskInfo::~CTaskInfo()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskInfo::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // ça avance
+ m_time += event.rTime;
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskInfo::Start(char *name, float value, float power, BOOL bSend)
+{
+ CObject* pInfo;
+ CAutoInfo* pAuto;
+ D3DVECTOR pos, goal;
+ Info info;
+ int i, total, op;
+
+ m_bError = TRUE;
+ m_object->SetInfoReturn(NAN);
+
+ pInfo = SearchInfo(power); // cherche borne
+ if ( pInfo == 0 )
+ {
+ return ERR_INFO_NULL;
+ }
+
+ pAuto = (CAutoInfo*)pInfo->RetAuto();
+ if ( pAuto == 0 )
+ {
+ return ERR_INFO_NULL;
+ }
+
+ op = 1; // émission impossible
+ if ( bSend ) // send ?
+ {
+ total = pInfo->RetInfoTotal();
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = pInfo->RetInfo(i);
+ if ( strcmp(info.name, name) == 0 )
+ {
+ info.value = value;
+ pInfo->SetInfo(i, info);
+ break;
+ }
+ }
+ if ( i == total )
+ {
+ if ( total < OBJECTMAXINFO )
+ {
+ strcpy(info.name, name);
+ info.value = value;
+ pInfo->SetInfo(total, info);
+ op = 2; // début de réception (pour la borne)
+ }
+ }
+ else
+ {
+ op = 2; // début de réception (pour la borne)
+ }
+ }
+ else // receive ?
+ {
+ total = pInfo->RetInfoTotal();
+ for ( i=0 ; i<total ; i++ )
+ {
+ info = pInfo->RetInfo(i);
+ if ( strcmp(info.name, name) == 0 )
+ {
+ m_object->SetInfoReturn(info.value);
+ break;
+ }
+ }
+ if ( i < total )
+ {
+ op = 0; // début d'émission (pour la borne)
+ }
+ }
+
+ pAuto->Start(op);
+
+ if ( op == 0 ) // émission ?
+ {
+ pos = pInfo->RetPosition(0);
+ pos.y += 9.5f;
+ goal = m_object->RetPosition(0);
+ goal.y += 4.0f;
+ m_particule->CreateRay(pos, goal, PARTIRAY3, FPOINT(2.0f, 2.0f), 1.0f);
+ }
+ if ( op == 2 ) // réception ?
+ {
+ goal = pInfo->RetPosition(0);
+ goal.y += 9.5f;
+ pos = m_object->RetPosition(0);
+ pos.y += 4.0f;
+ m_particule->CreateRay(pos, goal, PARTIRAY3, FPOINT(2.0f, 2.0f), 1.0f);
+ }
+
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskInfo::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskInfo::Abort()
+{
+ return TRUE;
+}
+
+
+// Cherche la borne d'information la plus proche.
+
+CObject* CTaskInfo::SearchInfo(float power)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float dist, min;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+
+ min = 100000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_INFO ) continue;
+
+ if ( !pObj->RetActif() ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, iPos);
+ if ( dist > power ) continue; // trop loin ?
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+
+ return pBest;
+}
+
diff --git a/src/taskinfo.h b/src/taskinfo.h
new file mode 100644
index 0000000..c2d6147
--- /dev/null
+++ b/src/taskinfo.h
@@ -0,0 +1,38 @@
+// taskinfo.h
+
+#ifndef _TASKINFO_H_
+#define _TASKINFO_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+class CTaskInfo : public CTask
+{
+public:
+ CTaskInfo(CInstanceManager* iMan, CObject* object);
+ ~CTaskInfo();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(char *name, float value, float power, BOOL bSend);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ CObject* SearchInfo(float power);
+
+protected:
+ float m_progress;
+ float m_speed;
+ float m_time;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKINFO_H_
diff --git a/src/taskmanager.cpp b/src/taskmanager.cpp
new file mode 100644
index 0000000..0a61c93
--- /dev/null
+++ b/src/taskmanager.cpp
@@ -0,0 +1,275 @@
+// taskmanager.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "misc.h"
+#include "iman.h"
+#include "event.h"
+#include "object.h"
+#include "task.h"
+#include "taskwait.h"
+#include "taskadvance.h"
+#include "taskturn.h"
+#include "taskgoto.h"
+#include "tasktake.h"
+#include "taskmanip.h"
+#include "taskflag.h"
+#include "taskbuild.h"
+#include "tasksearch.h"
+#include "taskterraform.h"
+#include "taskpen.h"
+#include "taskrecover.h"
+#include "taskshield.h"
+#include "taskinfo.h"
+#include "taskfire.h"
+#include "taskfireant.h"
+#include "taskgungoal.h"
+#include "taskspiderexplo.h"
+#include "taskreset.h"
+#include "taskmanager.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskManager::CTaskManager(CInstanceManager* iMan, CObject* object)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_TASKMANAGER, this, 100);
+
+ m_task = 0;
+ m_object = object;
+ m_bPilot = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CTaskManager::~CTaskManager()
+{
+ delete m_task;
+}
+
+
+
+// Attend un certain temps.
+
+Error CTaskManager::StartTaskWait(float time)
+{
+ m_task = new CTaskWait(m_iMan, m_object);
+ return ((CTaskWait*)m_task)->Start(time);
+}
+
+// Avance droit devant d'une certaine distance.
+
+Error CTaskManager::StartTaskAdvance(float length)
+{
+ m_task = new CTaskAdvance(m_iMan, m_object);
+ return ((CTaskAdvance*)m_task)->Start(length);
+}
+
+// Tourne d'un certain angle.
+
+Error CTaskManager::StartTaskTurn(float angle)
+{
+ m_task = new CTaskTurn(m_iMan, m_object);
+ return ((CTaskTurn*)m_task)->Start(angle);
+}
+
+// Atteint une position donnée.
+
+Error CTaskManager::StartTaskGoto(D3DVECTOR pos, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode)
+{
+ m_task = new CTaskGoto(m_iMan, m_object);
+ return ((CTaskGoto*)m_task)->Start(pos, altitude, goalMode, crashMode);
+}
+
+// Bouge le bras manipulateur.
+
+Error CTaskManager::StartTaskTake()
+{
+ m_task = new CTaskTake(m_iMan, m_object);
+ return ((CTaskTake*)m_task)->Start();
+}
+
+// Bouge le bras manipulateur.
+
+Error CTaskManager::StartTaskManip(TaskManipOrder order, TaskManipArm arm)
+{
+ m_task = new CTaskManip(m_iMan, m_object);
+ return ((CTaskManip*)m_task)->Start(order, arm);
+}
+
+// Met ou enlève un drapeau.
+
+Error CTaskManager::StartTaskFlag(TaskFlagOrder order, int rank)
+{
+ m_task = new CTaskFlag(m_iMan, m_object);
+ return ((CTaskFlag*)m_task)->Start(order, rank);
+}
+
+// Construit un batiment.
+
+Error CTaskManager::StartTaskBuild(ObjectType type)
+{
+ m_task = new CTaskBuild(m_iMan, m_object);
+ return ((CTaskBuild*)m_task)->Start(type);
+}
+
+// Sonde le sol.
+
+Error CTaskManager::StartTaskSearch()
+{
+ m_task = new CTaskSearch(m_iMan, m_object);
+ return ((CTaskSearch*)m_task)->Start();
+}
+
+// Lit une borne d'information.
+
+Error CTaskManager::StartTaskInfo(char *name, float value, float power, BOOL bSend)
+{
+ m_task = new CTaskInfo(m_iMan, m_object);
+ return ((CTaskInfo*)m_task)->Start(name, value, power, bSend);
+}
+
+// Terraforme le sol.
+
+Error CTaskManager::StartTaskTerraform()
+{
+ m_task = new CTaskTerraform(m_iMan, m_object);
+ return ((CTaskTerraform*)m_task)->Start();
+}
+
+// Change de crayon.
+
+Error CTaskManager::StartTaskPen(BOOL bDown, int color)
+{
+ m_task = new CTaskPen(m_iMan, m_object);
+ return ((CTaskPen*)m_task)->Start(bDown, color);
+}
+
+// Récupère une ruine.
+
+Error CTaskManager::StartTaskRecover()
+{
+ m_task = new CTaskRecover(m_iMan, m_object);
+ return ((CTaskRecover*)m_task)->Start();
+}
+
+// Déploie le bouclier.
+
+Error CTaskManager::StartTaskShield(TaskShieldMode mode, float delay)
+{
+ if ( mode == TSM_UP )
+ {
+ m_task = new CTaskShield(m_iMan, m_object);
+ return ((CTaskShield*)m_task)->Start(mode, delay);
+ }
+ if ( mode == TSM_DOWN && m_task != 0 )
+ {
+ return ((CTaskShield*)m_task)->Start(mode, delay);
+ }
+ if ( mode == TSM_UPDATE && m_task != 0 )
+ {
+ return ((CTaskShield*)m_task)->Start(mode, delay);
+ }
+ return ERR_GENERIC;
+}
+
+// Tire.
+
+Error CTaskManager::StartTaskFire(float delay)
+{
+ m_bPilot = TRUE;
+ m_task = new CTaskFire(m_iMan, m_object);
+ return ((CTaskFire*)m_task)->Start(delay);
+}
+
+// Tire avec la fourmi.
+
+Error CTaskManager::StartTaskFireAnt(D3DVECTOR impact)
+{
+ m_task = new CTaskFireAnt(m_iMan, m_object);
+ return ((CTaskFireAnt*)m_task)->Start(impact);
+}
+
+// Ajuste la hausse.
+
+Error CTaskManager::StartTaskGunGoal(float dirV, float dirH)
+{
+ m_task = new CTaskGunGoal(m_iMan, m_object);
+ return ((CTaskGunGoal*)m_task)->Start(dirV, dirH);
+}
+
+// Suicide de l'araignée.
+
+Error CTaskManager::StartTaskSpiderExplo()
+{
+ m_task = new CTaskSpiderExplo(m_iMan, m_object);
+ return ((CTaskSpiderExplo*)m_task)->Start();
+}
+
+// Reset.
+
+Error CTaskManager::StartTaskReset(D3DVECTOR goal, D3DVECTOR angle)
+{
+ m_task = new CTaskReset(m_iMan, m_object);
+ return ((CTaskReset*)m_task)->Start(goal, angle);
+}
+
+
+
+
+
+// Gestion d'un événement.
+
+BOOL CTaskManager::EventProcess(const Event &event)
+{
+ if ( m_task == 0 ) return FALSE;
+ return m_task->EventProcess(event);
+}
+
+
+// Indique si l'action est terminée.
+
+Error CTaskManager::IsEnded()
+{
+ if ( m_task == 0 ) return ERR_GENERIC;
+ return m_task->IsEnded();
+}
+
+
+// Indique si l'action est en cours.
+
+BOOL CTaskManager::IsBusy()
+{
+ if ( m_task == 0 ) return FALSE;
+ return m_task->IsBusy();
+}
+
+
+// Indique s'il est possible de piloter le robot pendant l'exécution
+// de la tâche en cours.
+
+BOOL CTaskManager::IsPilot()
+{
+ return m_bPilot;
+}
+
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskManager::Abort()
+{
+ if ( m_task == 0 ) return FALSE;
+ return m_task->Abort();
+}
+
+
diff --git a/src/taskmanager.h b/src/taskmanager.h
new file mode 100644
index 0000000..4384f15
--- /dev/null
+++ b/src/taskmanager.h
@@ -0,0 +1,62 @@
+// taskmanager.h
+
+#ifndef _TASKMANAGER_H_
+#define _TASKMANAGER_H_
+
+
+class CInstanceManager;
+class CTask;
+
+enum TaskManipOrder;
+enum TaskManipArm;
+enum TaskFlagOrder;
+enum TaskGotoGoal;
+enum TaskGotoCrash;
+enum TaskShieldMode;
+enum ObjectType;
+
+
+
+class CTaskManager
+{
+public:
+ CTaskManager(CInstanceManager* iMan, CObject* object);
+ ~CTaskManager();
+
+ Error StartTaskWait(float time);
+ Error StartTaskAdvance(float length);
+ Error StartTaskTurn(float angle);
+ Error StartTaskGoto(D3DVECTOR pos, float altitude, TaskGotoGoal goalMode, TaskGotoCrash crashMode);
+ Error StartTaskTake();
+ Error StartTaskManip(TaskManipOrder order, TaskManipArm arm);
+ Error StartTaskFlag(TaskFlagOrder order, int rank);
+ Error StartTaskBuild(ObjectType type);
+ Error StartTaskSearch();
+ Error StartTaskInfo(char *name, float value, float power, BOOL bSend);
+ Error StartTaskTerraform();
+ Error StartTaskPen(BOOL bDown, int color);
+ Error StartTaskRecover();
+ Error StartTaskShield(TaskShieldMode mode, float delay);
+ Error StartTaskFire(float delay);
+ Error StartTaskFireAnt(D3DVECTOR impact);
+ Error StartTaskGunGoal(float dirV, float dirH);
+ Error StartTaskSpiderExplo();
+ Error StartTaskReset(D3DVECTOR goal, D3DVECTOR angle);
+
+ BOOL EventProcess(const Event &event);
+ Error IsEnded();
+ BOOL IsBusy();
+ BOOL IsPilot();
+ BOOL Abort();
+
+protected:
+
+protected:
+ CInstanceManager* m_iMan;
+ CTask* m_task;
+ CObject* m_object;
+ BOOL m_bPilot;
+};
+
+
+#endif //_TASKMANAGER_H_
diff --git a/src/taskmanip.cpp b/src/taskmanip.cpp
new file mode 100644
index 0000000..2ccc27f
--- /dev/null
+++ b/src/taskmanip.cpp
@@ -0,0 +1,1383 @@
+// taskmanip.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "pyro.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "task.h"
+#include "taskmanip.h"
+
+
+//?#define MARGIN_FRONT 2.0f
+//?#define MARGIN_BACK 2.0f
+//?#define MARGIN_FRIEND 2.0f
+//?#define MARGIN_BEE 5.0f
+#define MARGIN_FRONT 4.0f //OK 1.9
+#define MARGIN_BACK 4.0f //OK 1.9
+#define MARGIN_FRIEND 4.0f //OK 1.9
+#define MARGIN_BEE 5.0f //OK 1.9
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskManip::CTaskManip(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_arm = TMA_NEUTRAL;
+ m_hand = TMH_OPEN;
+}
+
+// Destructeur de l'objet.
+
+CTaskManip::~CTaskManip()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskManip::EventProcess(const Event &event)
+{
+ D3DVECTOR pos;
+ float angle, a, g, cirSpeed, progress;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_bBee ) // abeille ?
+ {
+ return TRUE;
+ }
+
+ if ( m_bTurn ) // rotation préliminaire ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( m_physics->RetType() == TYPE_FLYING ) // volant au sol ?
+ {
+ cirSpeed *= 4.0f; // plus de pèche
+ }
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ return TRUE;
+ }
+
+ if ( m_move != 0 ) // avance préliminaire ?
+ {
+ m_timeLimit -= event.rTime;
+ m_physics->SetMotorSpeedX(m_move); // avance/recule
+ return TRUE;
+ }
+
+ m_progress += event.rTime*m_speed; // ça avance
+ progress = m_progress;
+ if ( progress > 1.0f ) progress = 1.0f;
+
+ if ( m_bSubm ) // sous-marin ?
+ {
+ if ( m_order == TMO_GRAB )
+ {
+ if ( m_step == 0 ) // descend ?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-progress*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ if ( m_step == 1 ) // ferme ?
+ {
+ pos = m_object->RetPosition(2);
+ pos.z = -1.5f+progress*0.5f;
+ m_object->SetPosition(2, pos);
+
+ pos = m_object->RetPosition(3);
+ pos.z = 1.5f-progress*0.5f;
+ m_object->SetPosition(3, pos);
+ }
+ if ( m_step == 2 ) // monte ?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-(1.0f-progress)*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ }
+ else
+ {
+ if ( m_step == 0 ) // descend ?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-progress*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ if ( m_step == 1 ) // ferme ?
+ {
+ pos = m_object->RetPosition(2);
+ pos.z = -1.5f+(1.0f-progress)*0.5f;
+ m_object->SetPosition(2, pos);
+
+ pos = m_object->RetPosition(3);
+ pos.z = 1.5f-(1.0f-progress)*0.5f;
+ m_object->SetPosition(3, pos);
+ }
+ if ( m_step == 2 ) // monte ?
+ {
+ pos = m_object->RetPosition(1);
+ pos.y = 3.0f-(1.0f-progress)*2.0f;
+ m_object->SetPosition(1, pos);
+ }
+ }
+ }
+ else
+ {
+ for ( i=0 ; i<5 ; i++ )
+ {
+ angle = (m_finalAngle[i]-m_initialAngle[i])*progress;
+ angle += m_initialAngle[i];
+ m_object->SetAngleZ(i+1, angle);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Initialise les angles finaux et initiaux.
+
+void CTaskManip::InitAngle()
+{
+ CObject* power;
+ float max, energy;
+ int i;
+
+ if ( m_bSubm || m_bBee ) return;
+
+ if ( m_arm == TMA_NEUTRAL ||
+ m_arm == TMA_GRAB )
+ {
+ m_finalAngle[0] = ARM_NEUTRAL_ANGLE1; // bras
+ m_finalAngle[1] = ARM_NEUTRAL_ANGLE2; // avant-bras
+ m_finalAngle[2] = ARM_NEUTRAL_ANGLE3; // main
+ }
+ if ( m_arm == TMA_STOCK )
+ {
+ m_finalAngle[0] = ARM_STOCK_ANGLE1; // bras
+ m_finalAngle[1] = ARM_STOCK_ANGLE2; // avant-bras
+ m_finalAngle[2] = ARM_STOCK_ANGLE3; // main
+ }
+ if ( m_arm == TMA_FFRONT )
+ {
+ m_finalAngle[0] = 35.0f*PI/180.0f; // bras
+ m_finalAngle[1] = -95.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = -27.0f*PI/180.0f; // main
+ }
+ if ( m_arm == TMA_FBACK )
+ {
+ m_finalAngle[0] = 145.0f*PI/180.0f; // bras
+ m_finalAngle[1] = 95.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = 27.0f*PI/180.0f; // main
+ }
+ if ( m_arm == TMA_POWER )
+ {
+ m_finalAngle[0] = 95.0f*PI/180.0f; // bras
+ m_finalAngle[1] = 125.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = 50.0f*PI/180.0f; // main
+ }
+ if ( m_arm == TMA_OTHER )
+ {
+ if ( m_height <= 3.0f )
+ {
+ m_finalAngle[0] = 55.0f*PI/180.0f; // bras
+ m_finalAngle[1] = -90.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = -35.0f*PI/180.0f; // main
+ }
+ else
+ {
+ m_finalAngle[0] = 70.0f*PI/180.0f; // bras
+ m_finalAngle[1] = -90.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = -50.0f*PI/180.0f; // main
+ }
+ }
+
+ if ( m_hand == TMH_OPEN ) // pince ouverte ?
+ {
+ m_finalAngle[3] = -PI*0.10f; // pince proche
+ m_finalAngle[4] = PI*0.10f; // pince éloignée
+ }
+ if ( m_hand == TMH_CLOSE ) // pince fermée ?
+ {
+ m_finalAngle[3] = PI*0.05f; // pince proche
+ m_finalAngle[4] = -PI*0.05f; // pince éloignée
+ }
+
+ for ( i=0 ; i<5 ; i++ )
+ {
+ m_initialAngle[i] = m_object->RetAngleZ(i+1);
+ }
+
+ max = 0.0f;
+ for ( i=0 ; i<5 ; i++ )
+ {
+ max = Max(max, Abs(m_initialAngle[i] - m_finalAngle[i]));
+ }
+ m_speed = (PI*1.0f)/max;
+ if ( m_speed > 3.0f ) m_speed = 3.0f; // piano, ma non troppo
+
+ energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( energy == 0.0f )
+ {
+ m_speed *= 0.7f; // plus lent si plus d'énergie !
+ }
+}
+
+
+// Teste si un objet est compatible avec l'opération TMA_OTHER.
+
+BOOL TestFriend(ObjectType oType, ObjectType fType)
+{
+ if ( oType == OBJECT_ENERGY )
+ {
+ return ( fType == OBJECT_METAL );
+ }
+ if ( oType == OBJECT_LABO )
+ {
+ return ( fType == OBJECT_BULLET );
+ }
+ if ( oType == OBJECT_NUCLEAR )
+ {
+ return ( fType == OBJECT_URANIUM );
+ }
+
+ return ( fType == OBJECT_POWER ||
+ fType == OBJECT_ATOMIC );
+}
+
+// Assigne le but à atteindre.
+
+Error CTaskManip::Start(TaskManipOrder order, TaskManipArm arm)
+{
+ ObjectType type;
+ CObject *front, *other, *power;
+ CPyro *pyro;
+ float iAngle, dist, len;
+ float fDist, fAngle, oDist, oAngle, oHeight;
+ D3DVECTOR pos, fPos, oPos;
+
+ m_arm = arm;
+ m_height = 0.0f;
+ m_step = 0;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+ oAngle = iAngle;
+
+ m_bError = TRUE; // opération impossible
+
+ if ( m_arm != TMA_FFRONT &&
+ m_arm != TMA_FBACK &&
+ m_arm != TMA_POWER &&
+ m_arm != TMA_GRAB ) return ERR_MANIP_VEH;
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ type = m_object->RetType();
+ if ( type == OBJECT_BEE ) // abeille ?
+ {
+ if ( m_object->RetFret() == 0 )
+ {
+ if ( !m_physics->RetLand() ) return ERR_MANIP_FLY;
+
+ other = SearchTakeUnderObject(m_targetPos, MARGIN_BEE);
+ if ( other == 0 ) return ERR_MANIP_NIL;
+ m_object->SetFret(other); // prend le boulet
+ other->SetTruck(m_object);
+ other->SetTruckPart(0); // prend avec la base
+ other->SetPosition(0, D3DVECTOR(0.0f, -3.0f, 0.0f));
+ }
+ else
+ {
+ other = m_object->RetFret(); // other = boulet
+ m_object->SetFret(0); // lâche le boulet
+ other->SetTruck(0);
+ pos = m_object->RetPosition(0);
+ pos.y -= 3.0f;
+ other->SetPosition(0, pos);
+
+ pos = m_object->RetPosition(0);
+ pos.y += 2.0f;
+ m_object->SetPosition(0, pos); // bond contre le haut
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FALL, other); // le boulet tombe
+ }
+
+ m_bBee = TRUE;
+ m_bError = FALSE; // ok
+ return ERR_OK;
+ }
+ m_bBee = FALSE;
+
+ m_bSubm = ( type == OBJECT_MOBILEsa ); // sous-marin ?
+
+ if ( m_arm == TMA_GRAB ) // prend immédiatement ?
+ {
+ TruckTakeObject();
+ Abort();
+ return ERR_OK;
+ }
+
+ m_energy = 0.0f;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ m_energy = power->RetEnergy();
+ }
+
+ if ( !m_physics->RetLand() ) return ERR_MANIP_FLY;
+
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEsa ) return ERR_MANIP_VEH;
+
+ if ( m_bSubm ) // sous-marin ?
+ {
+ m_arm = TMA_FFRONT; // possible seulement devant !
+ }
+
+ m_move = 0.0f; // avance pas nécessaire
+ m_angle = iAngle;
+
+ if ( order == TMO_AUTO )
+ {
+ if ( m_object->RetFret() == 0 )
+ {
+ m_order = TMO_GRAB;
+ }
+ else
+ {
+ m_order = TMO_DROP;
+ }
+ }
+ else
+ {
+ m_order = order;
+ }
+
+ if ( m_order == TMO_GRAB && m_object->RetFret() != 0 )
+ {
+ return ERR_MANIP_BUSY;
+ }
+ if ( m_order == TMO_DROP && m_object->RetFret() == 0 )
+ {
+ return ERR_MANIP_EMPTY;
+ }
+
+//? speed = m_physics->RetMotorSpeed();
+//? if ( speed.x != 0.0f ||
+//? speed.z != 0.0f ) return ERR_MANIP_MOTOR;
+
+ if ( m_order == TMO_GRAB )
+ {
+ if ( m_arm == TMA_FFRONT )
+ {
+ front = SearchTakeFrontObject(TRUE, fPos, fDist, fAngle);
+ other = SearchOtherObject(TRUE, oPos, oDist, oAngle, oHeight);
+
+ if ( front != 0 && fDist < oDist )
+ {
+ m_targetPos = fPos;
+ m_angle = fAngle;
+ m_move = 1.0f; // avance nécessaire
+ }
+ else if ( other != 0 && oDist < fDist )
+ {
+ if ( other->RetPower() == 0 ) return ERR_MANIP_NIL;
+ m_targetPos = oPos;
+ m_angle = oAngle;
+ m_height = oHeight;
+ m_move = 1.0f; // avance nécessaire
+ m_arm = TMA_OTHER;
+ }
+ else
+ {
+ return ERR_MANIP_NIL;
+ }
+ m_main->HideDropZone(front); // cache zone constructible
+ }
+ if ( m_arm == TMA_FBACK )
+ {
+ if ( SearchTakeBackObject(TRUE, m_targetPos, fDist, m_angle) == 0 )
+ {
+ return ERR_MANIP_NIL;
+ }
+ m_angle += PI;
+ m_move = -1.0f; // recule nécessaire
+ }
+ if ( m_arm == TMA_POWER )
+ {
+ if ( m_object->RetPower() == 0 ) return ERR_MANIP_NIL;
+ }
+ }
+
+ if ( m_order == TMO_DROP )
+ {
+ if ( m_arm == TMA_FFRONT )
+ {
+ other = SearchOtherObject(TRUE, oPos, oDist, oAngle, oHeight);
+ if ( other != 0 && other->RetPower() == 0 )
+ {
+ m_targetPos = oPos;
+ m_angle = oAngle;
+ m_height = oHeight;
+ m_move = 1.0f; // avance nécessaire
+ m_arm = TMA_OTHER;
+ }
+ else
+ {
+ if ( !IsFreeDeposeObject(D3DVECTOR(TAKE_DIST, 0.0f, 0.0f)) ) return ERR_MANIP_OCC;
+ }
+ }
+ if ( m_arm == TMA_FBACK )
+ {
+ if ( !IsFreeDeposeObject(D3DVECTOR(-TAKE_DIST, 0.0f, 0.0f)) ) return ERR_MANIP_OCC;
+ }
+ if ( m_arm == TMA_POWER )
+ {
+ if ( m_object->RetPower() != 0 ) return ERR_MANIP_OCC;
+ }
+ }
+
+ dist = Length(m_object->RetPosition(0), m_targetPos);
+ len = dist-TAKE_DIST;
+ if ( m_arm == TMA_OTHER ) len -= TAKE_DIST_OTHER;
+ if ( len < 0.0f ) len = 0.0f;
+ if ( m_arm == TMA_FBACK ) len = -len;
+ m_advanceLength = dist-m_physics->RetLinLength(len);
+ if ( dist <= m_advanceLength+0.2f ) m_move = 0.0f; // pas nécessaire d'avancer
+
+ if ( m_energy == 0.0f ) m_move = 0.0f;
+
+ if ( m_move != 0.0f ) // avance ou recule ?
+ {
+ m_timeLimit = m_physics->RetLinTimeLength(Abs(len))*1.5f;
+ if ( m_timeLimit < 0.5f ) m_timeLimit = 0.5f;
+ }
+
+ if ( m_object->RetFret() == 0 ) // ne transporte rien ?
+ {
+ m_hand = TMH_OPEN; // pince ouverte
+ }
+ else
+ {
+ m_hand = TMH_CLOSE; // pince fermée
+ }
+
+ InitAngle();
+
+ if ( iAngle == m_angle || m_energy == 0.0f )
+ {
+ m_bTurn = FALSE; // rotation préliminaire inutile
+ SoundManip(1.0f/m_speed);
+ }
+ else
+ {
+ m_bTurn = TRUE; // rotation préliminaire nécessaire
+ }
+
+ if ( m_bSubm )
+ {
+ m_camera->StartCentering(m_object, PI*0.8f, 99.9f, 0.0f, 0.5f);
+ }
+
+ m_physics->SetFreeze(TRUE); // on ne bouge plus
+
+ m_bError = FALSE; // ok
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskManip::IsEnded()
+{
+ CObject* fret;
+ D3DVECTOR pos;
+ float angle, dist;
+ int i;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_bBee ) // abeille ?
+ {
+ return ERR_STOP;
+ }
+
+ if ( m_bTurn ) // rotation préliminaire ?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angle-PI*0.01f, m_angle+PI*0.01f) )
+ {
+ m_bTurn = FALSE; // rotation terminée
+ m_physics->SetMotorSpeedZ(0.0f);
+ if ( m_move == 0.0f )
+ {
+ SoundManip(1.0f/m_speed);
+ }
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_move != 0.0f ) // avance préliminaire ?
+ {
+ if ( m_timeLimit <= 0.0f )
+ {
+//OK 1.9
+ dist = Length(m_object->RetPosition(0), m_targetPos);
+ if ( dist <= m_advanceLength + 2.0f )
+ {
+ m_move = 0.0f; // avance terminée
+ m_physics->SetMotorSpeedX(0.0f);
+ SoundManip(1.0f/m_speed);
+ return ERR_CONTINUE;
+ }
+ else
+ {
+//EOK 1.9
+ m_move = 0.0f; // avance terminée
+ m_physics->SetMotorSpeedX(0.0f); // stoppe
+ Abort();
+ return ERR_STOP;
+ }
+ }
+
+ dist = Length(m_object->RetPosition(0), m_targetPos);
+ if ( dist <= m_advanceLength )
+ {
+ m_move = 0.0f; // avance terminée
+ m_physics->SetMotorSpeedX(0.0f);
+ SoundManip(1.0f/m_speed);
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( !m_bSubm )
+ {
+ for ( i=0 ; i<5 ; i++ )
+ {
+ m_object->SetAngleZ(i+1, m_finalAngle[i]);
+ }
+ }
+ m_step ++;
+
+ if ( m_order == TMO_GRAB )
+ {
+ if ( m_step == 1 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/0.7f;
+ m_hand = TMH_CLOSE; // ferme la pince pour prendre
+ InitAngle();
+ SoundManip(1.0f/m_speed, 0.8f, 1.5f);
+ return ERR_CONTINUE;
+ }
+ if ( m_step == 2 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/1.5f;
+ if ( !TruckTakeObject() &&
+ m_object->RetFret() == 0 )
+ {
+ m_hand = TMH_OPEN; // réouvre la pince
+ m_arm = TMA_NEUTRAL;
+ InitAngle();
+ SoundManip(1.0f/m_speed, 0.8f, 1.5f);
+ }
+ else
+ {
+ if ( (m_arm == TMA_OTHER ||
+ m_arm == TMA_POWER ) &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWEROFF, m_object->RetPosition(0));
+ }
+ m_arm = TMA_STOCK;
+ InitAngle();
+ SoundManip(1.0f/m_speed);
+ }
+ return ERR_CONTINUE;
+ }
+ }
+
+ if ( m_order == TMO_DROP )
+ {
+ if ( m_step == 1 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/0.7f;
+ fret = m_object->RetFret();
+ if ( TruckDeposeObject() )
+ {
+ if ( (m_arm == TMA_OTHER ||
+ m_arm == TMA_POWER ) &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWERON, m_object->RetPosition(0));
+ }
+ if ( fret != 0 && m_fretType == OBJECT_METAL && m_arm == TMA_FFRONT )
+ {
+ m_main->ShowDropZone(fret, m_object); // montre zone constructible
+ }
+ m_hand = TMH_OPEN; // ouvre la pince pour déposer
+ SoundManip(1.0f/m_speed, 0.8f, 1.5f);
+ }
+ InitAngle();
+ return ERR_CONTINUE;
+ }
+ if ( m_step == 2 )
+ {
+ if ( m_bSubm ) m_speed = 1.0f/1.5f;
+ m_arm = TMA_NEUTRAL;
+ InitAngle();
+ SoundManip(1.0f/m_speed);
+ return ERR_CONTINUE;
+ }
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskManip::Abort()
+{
+ int i;
+
+ if ( m_object->RetFret() == 0 ) // ne transporte rien ?
+ {
+ m_hand = TMH_OPEN; // pince ouverte
+ m_arm = TMA_NEUTRAL;
+ }
+ else
+ {
+ m_hand = TMH_CLOSE; // pince fermée
+ m_arm = TMA_STOCK;
+ }
+ InitAngle();
+
+ if ( !m_bSubm )
+ {
+ for ( i=0 ; i<5 ; i++ )
+ {
+ m_object->SetAngleZ(i+1, m_finalAngle[i]);
+ }
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ m_physics->SetFreeze(FALSE); // on bouge de nouveau
+ return TRUE;
+}
+
+
+// Cherche l'objet à prendre dessous (pour l'abeille).
+
+CObject* CTaskManip::SearchTakeUnderObject(D3DVECTOR &pos, float dLimit)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, distance;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+
+ min = 1000000.0f;
+ pBest = 0;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ if ( distance <= dLimit &&
+ distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ }
+ }
+ if ( pBest != 0 )
+ {
+ pos = pBest->RetPosition(0);
+ }
+ return pBest;
+}
+
+// Cherche l'objet à prendre devant.
+
+CObject* CTaskManip::SearchTakeFrontObject(BOOL bAdvance, D3DVECTOR &pos,
+ float &distance, float &angle)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, bAngle, aLimit, dLimit, f;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( bAdvance && m_energy > 0.0f )
+ {
+ aLimit = 60.0f*PI/180.0f;
+ dLimit = MARGIN_FRONT+10.0f;
+ }
+ else
+ {
+//? aLimit = 7.0f*PI/180.0f;
+ aLimit = 15.0f*PI/180.0f; //OK 1.9
+ dLimit = MARGIN_FRONT;
+ }
+
+ min = 1000000.0f;
+ pBest = 0;
+ bAngle = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT &&
+ type != OBJECT_SCRAP1 &&
+ type != OBJECT_SCRAP2 &&
+ type != OBJECT_SCRAP3 &&
+ type != OBJECT_SCRAP4 &&
+ type != OBJECT_SCRAP5 ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Abs(Length(oPos, iPos)-TAKE_DIST);
+ f = 1.0f-distance/50.0f;
+ if ( f < 0.5f ) f = 0.5f;
+
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( !TestAngle(angle, iAngle-aLimit*f, iAngle+aLimit*f) ) continue;
+
+ if ( distance < -dLimit ||
+ distance > dLimit ) continue;
+
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ bAngle = angle;
+ }
+ }
+ if ( pBest == 0 )
+ {
+ distance = 1000000.0f;
+ angle = 0.0f;
+ }
+ else
+ {
+ pos = pBest->RetPosition(0);
+ distance = min;
+ angle = bAngle;
+ }
+ return pBest;
+}
+
+// Cherche l'objet à prendre derrière.
+
+CObject* CTaskManip::SearchTakeBackObject(BOOL bAdvance, D3DVECTOR &pos,
+ float &distance, float &angle)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, bAngle, aLimit, dLimit, f;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0)+PI;
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( bAdvance && m_energy > 0.0f )
+ {
+ aLimit = 60.0f*PI/180.0f;
+ dLimit = MARGIN_BACK+5.0f;
+ }
+ else
+ {
+ aLimit = 7.0f*PI/180.0f;
+ dLimit = MARGIN_BACK;
+ }
+
+ min = 1000000.0f;
+ pBest = 0;
+ bAngle = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT &&
+ type != OBJECT_SCRAP1 &&
+ type != OBJECT_SCRAP2 &&
+ type != OBJECT_SCRAP3 &&
+ type != OBJECT_SCRAP4 &&
+ type != OBJECT_SCRAP5 ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Abs(Length(oPos, iPos)-TAKE_DIST);
+ f = 1.0f-distance/50.0f;
+ if ( f < 0.5f ) f = 0.5f;
+
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( !TestAngle(angle, iAngle-aLimit*f, iAngle+aLimit*f) ) continue;
+
+ if ( distance < -dLimit ||
+ distance > dLimit ) continue;
+
+ if ( distance < min )
+ {
+ min = distance;
+ pBest = pObj;
+ bAngle = angle;
+ }
+ }
+ if ( pBest == 0 )
+ {
+ distance = 1000000.0f;
+ angle = 0.0f;
+ }
+ else
+ {
+ pos = pBest->RetPosition(0);
+ distance = min;
+ angle = bAngle;
+ }
+ return pBest;
+}
+
+// Cherche le robot ou le bâtiment sur lequel on veut prendre ou poser
+// une pile ou un autre objet.
+
+CObject* CTaskManip::SearchOtherObject(BOOL bAdvance, D3DVECTOR &pos,
+ float &distance, float &angle,
+ float &height)
+{
+ Character* character;
+ CObject* pObj;
+ CObject* pPower;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ ObjectType type, powerType;
+ float iAngle, iRad, oAngle, oLimit, aLimit, dLimit;
+ int i;
+
+ distance = 1000000.0f;
+ angle = 0.0f;
+
+ if ( m_bSubm ) return 0; // impossible avec le sous-marin
+
+ if ( !m_object->GetCrashSphere(0, iPos, iRad) ) return 0;
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ if ( bAdvance && m_energy > 0.0f )
+ {
+ aLimit = 60.0f*PI/180.0f;
+ dLimit = MARGIN_FRIEND+10.0f;
+ }
+ else
+ {
+ aLimit = 7.0f*PI/180.0f;
+ dLimit = MARGIN_FRIEND;
+ }
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue; // soi-même ?
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_TOWER &&
+ type != OBJECT_RESEARCH &&
+ type != OBJECT_ENERGY &&
+ type != OBJECT_LABO &&
+ type != OBJECT_NUCLEAR ) continue;
+
+ pPower = pObj->RetPower();
+ if ( pPower != 0 )
+ {
+ if ( pPower->RetLock() ) continue;
+ if ( pPower->RetZoomY(0) != 1.0f ) continue;
+
+ powerType = pPower->RetType();
+ if ( powerType == OBJECT_NULL ||
+ powerType == OBJECT_FIX ) continue;
+ }
+
+ mat = pObj->RetWorldMatrix(0);
+ character = pObj->RetCharacter();
+ oPos = Transform(*mat, character->posPower);
+
+ oAngle = pObj->RetAngleY(0);
+ if ( type == OBJECT_TOWER ||
+ type == OBJECT_RESEARCH )
+ {
+ oLimit = 45.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_ENERGY )
+ {
+ oLimit = 90.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_LABO )
+ {
+ oLimit = 120.0f*PI/180.0f;
+ }
+ else if ( type == OBJECT_NUCLEAR )
+ {
+ oLimit = 45.0f*PI/180.0f;
+ }
+ else
+ {
+ oLimit = 45.0f*PI/180.0f;
+ oAngle += PI; // c'est derrière
+ }
+ oAngle = NormAngle(oAngle); // 0..2*PI
+ angle = RotateAngle(iPos.x-oPos.x, oPos.z-iPos.z); // CW !
+ if ( !TestAngle(angle, oAngle-oLimit, oAngle+oLimit) ) continue;
+
+ distance = Abs(Length(oPos, iPos)-TAKE_DIST);
+ if ( distance <= dLimit )
+ {
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ character = pObj->RetCharacter();
+ height = character->posPower.y;
+ pos = oPos;
+ return pObj;
+ }
+ }
+ }
+
+ distance = 1000000.0f;
+ angle = 0.0f;
+ return 0;
+}
+
+// Prend l'objet placé devant.
+
+BOOL CTaskManip::TruckTakeObject()
+{
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX matRotate;
+ D3DVECTOR pos;
+ float angle, dist;
+
+ if ( m_arm == TMA_GRAB ) // prend immédiatement ?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // rien à prendre ?
+ m_fretType = fret->RetType();
+
+ if ( m_object->RetType() == OBJECT_HUMAN ||
+ m_object->RetType() == OBJECT_TECH )
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(4); // prend avec la main
+
+ fret->SetPosition(0, D3DVECTOR(1.7f, -0.5f, 1.1f));
+ fret->SetAngleY(0, 0.1f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.8f);
+ }
+ else if ( m_bSubm )
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(2); // prend avec la pince droite
+
+ pos = D3DVECTOR(1.1f, -1.0f, 1.0f); // relatif
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ }
+ else
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // prend avec la main
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relatif à la main (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+ }
+
+ m_object->SetFret(fret); // prend
+ }
+
+ if ( m_arm == TMA_FFRONT ) // prend au sol devant ?
+ {
+ fret = SearchTakeFrontObject(FALSE, pos, dist, angle);
+ if ( fret == 0 ) return FALSE; // rien à prendre ?
+ m_fretType = fret->RetType();
+
+ if ( m_bSubm )
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(2); // prend avec la pince droite
+
+ pos = D3DVECTOR(1.1f, -1.0f, 1.0f); // relatif
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ }
+ else
+ {
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // prend avec la main
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relatif à la main (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+ }
+
+ m_object->SetFret(fret); // prend
+ }
+
+ if ( m_arm == TMA_FBACK ) // prend au sol derrière ?
+ {
+ fret = SearchTakeBackObject(FALSE, pos, dist, angle);
+ if ( fret == 0 ) return FALSE; // rien à prendre ?
+ m_fretType = fret->RetType();
+
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // prend avec la main
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relatif à la main (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+
+ m_object->SetFret(fret); // prend
+ }
+
+ if ( m_arm == TMA_POWER ) // prend pile à l'arrière ?
+ {
+ fret = m_object->RetPower();
+ if ( fret == 0 ) return FALSE; // pas de pile ?
+ m_fretType = fret->RetType();
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relatif à la main (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetTruckPart(3); // prend avec la main
+
+ m_object->SetPower(0);
+ m_object->SetFret(fret); // prend
+ }
+
+ if ( m_arm == TMA_OTHER ) // prend pile sur amis ?
+ {
+ other = SearchOtherObject(FALSE, pos, dist, angle, m_height);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret == 0 ) return FALSE; // l'autre n'a pas de pile ?
+ m_fretType = fret->RetType();
+
+ other->SetPower(0);
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(3); // prend avec la main
+
+ pos = D3DVECTOR(4.7f, 0.0f, 0.0f); // relatif à la main (lem4)
+ fret->SetPosition(0, pos);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, PI/2.0f);
+ fret->SetAngleY(0, 0.0f);
+
+ m_object->SetFret(fret); // prend
+ }
+
+ return TRUE;
+}
+
+// Dépose l'objet pris.
+
+BOOL CTaskManip::TruckDeposeObject()
+{
+ Character* character;
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ float angle, dist;
+
+ if ( m_arm == TMA_FFRONT ) // dépose au sol devant ?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // ne porte rien ?
+ m_fretType = fret->RetType();
+
+ mat = fret->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(0.0f, 1.0f, 0.0f));
+ m_terrain->MoveOnFloor(pos);
+ fret->SetPosition(0, pos);
+ fret->SetAngleY(0, m_object->RetAngleY(0)+PI/2.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->FloorAdjust(); // plaque bien au sol
+
+ fret->SetTruck(0);
+ m_object->SetFret(0); // dépose
+ }
+
+ if ( m_arm == TMA_FBACK ) // dépose au sol derrière ?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // ne porte rien ?
+ m_fretType = fret->RetType();
+
+ mat = fret->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(0.0f, 1.0f, 0.0f));
+ m_terrain->MoveOnFloor(pos);
+ fret->SetPosition(0, pos);
+ fret->SetAngleY(0, m_object->RetAngleY(0)+PI/2.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+
+ fret->SetTruck(0);
+ m_object->SetFret(0); // dépose
+ }
+
+ if ( m_arm == TMA_POWER ) // dépose pile à l'arrière ?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // ne porte rien ?
+ m_fretType = fret->RetType();
+
+ if ( m_object->RetPower() != 0 ) return FALSE;
+
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(0); // porté par la base
+
+ character = m_object->RetCharacter();
+ fret->SetPosition(0, character->posPower);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+
+ m_object->SetPower(fret); // utilise
+ m_object->SetFret(0);
+ }
+
+ if ( m_arm == TMA_OTHER ) // dépose pile sur amis ?
+ {
+ other = SearchOtherObject(FALSE, pos, dist, angle, m_height);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret != 0 ) return FALSE; // l'autre a déjà une pile ?
+
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE;
+ m_fretType = fret->RetType();
+
+ other->SetPower(fret);
+ fret->SetTruck(other);
+
+ character = other->RetCharacter();
+ fret->SetPosition(0, character->posPower);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->SetTruckPart(0); // porté par la base
+
+ m_object->SetFret(0); // dépose
+ }
+
+ return TRUE;
+}
+
+// Cherche si un emplacement permet de déposer un objet.
+
+BOOL CTaskManip::IsFreeDeposeObject(D3DVECTOR pos)
+{
+ CObject* pObj;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ float oRadius;
+ int i, j;
+
+ mat = m_object->RetWorldMatrix(0);
+ iPos = Transform(*mat, pos);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( Length(iPos, oPos)-(oRadius+1.0f) < 2.0f )
+ {
+ return FALSE; // emplacement occupé
+ }
+ }
+ }
+ return TRUE; // emplacement libre
+}
+
+// Fait entendre le son du bras manipulateur.
+
+void CTaskManip::SoundManip(float time, float amplitude, float frequency)
+{
+ int i;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f*frequency, TRUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
+}
+
diff --git a/src/taskmanip.h b/src/taskmanip.h
new file mode 100644
index 0000000..9067235
--- /dev/null
+++ b/src/taskmanip.h
@@ -0,0 +1,88 @@
+// taskmanip.h
+
+#ifndef _TASKMANIP_H_
+#define _TASKMANIP_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskManipOrder
+{
+ TMO_AUTO = 0, // prend ou dépose automatique
+ TMO_GRAB = 1, // prend un objet
+ TMO_DROP = 2, // dépose l'objet
+};
+
+enum TaskManipArm
+{
+ TMA_NEUTRAL = 1, // bras vide au repos
+ TMA_STOCK = 2, // bras plein au repos
+ TMA_FFRONT = 3, // bras au sol
+ TMA_FBACK = 4, // bras derrière le robot
+ TMA_POWER = 5, // bras derrière le robot
+ TMA_OTHER = 6, // bras derrière un robot amis
+ TMA_GRAB = 7, // prend immédiatement
+};
+
+enum TaskManipHand
+{
+ TMH_OPEN = 1, // pince ouverte
+ TMH_CLOSE = 2, // pince fermée
+};
+
+
+
+class CTaskManip : public CTask
+{
+public:
+ CTaskManip(CInstanceManager* iMan, CObject* object);
+ ~CTaskManip();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(TaskManipOrder order, TaskManipArm arm);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ void InitAngle();
+ CObject* SearchTakeUnderObject(D3DVECTOR &pos, float dLimit);
+ CObject* SearchTakeFrontObject(BOOL bAdvance, D3DVECTOR &pos, float &distance, float &angle);
+ CObject* SearchTakeBackObject(BOOL bAdvance, D3DVECTOR &pos, float &distance, float &angle);
+ CObject* SearchOtherObject(BOOL bAdvance, D3DVECTOR &pos, float &distance, float &angle, float &height);
+ BOOL TruckTakeObject();
+ BOOL TruckDeposeObject();
+ BOOL IsFreeDeposeObject(D3DVECTOR pos);
+ void SoundManip(float time, float amplitude=1.0f, float frequency=1.0f);
+
+protected:
+ TaskManipOrder m_order;
+ TaskManipArm m_arm;
+ TaskManipHand m_hand;
+ int m_step;
+ float m_speed;
+ float m_progress;
+ float m_initialAngle[5];
+ float m_finalAngle[5];
+ float m_height;
+ float m_advanceLength;
+ float m_energy;
+ BOOL m_bError;
+ BOOL m_bTurn;
+ BOOL m_bSubm;
+ BOOL m_bBee;
+ float m_angle;
+ float m_move;
+ D3DVECTOR m_targetPos;
+ float m_timeLimit;
+ ObjectType m_fretType;
+};
+
+
+#endif //_TASKMANIP_H_
diff --git a/src/taskpen.cpp b/src/taskpen.cpp
new file mode 100644
index 0000000..49f2faf
--- /dev/null
+++ b/src/taskpen.cpp
@@ -0,0 +1,288 @@
+// taskpen.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionant.h"
+#include "motionspider.h"
+#include "task.h"
+#include "taskpen.h"
+
+
+
+// Constructeur de l'objet.
+
+CTaskPen::CTaskPen(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskPen::~CTaskPen()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskPen::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_delay == 0.0f )
+ {
+ m_progress = 1.0f;
+ }
+ else
+ {
+ m_progress += event.rTime*(1.0f/m_delay); // ça avance
+ if ( m_progress > 1.0f ) m_progress = 1.0f;
+ }
+
+ m_time += event.rTime;
+
+ if ( m_phase == TPP_UP ) // remonte le crayon ?
+ {
+ i = AngleToRank(m_object->RetAngleY(1));
+ pos = m_object->RetPosition(10+i);
+ pos.y = -3.2f*(1.0f-m_progress);
+ m_object->SetPosition(10+i, pos);
+ }
+
+ if ( m_phase == TPP_TURN ) // tourne le carrousel ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_supportPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*3.0f;
+ speed.z = (Rand()-0.5f)*3.0f;
+ speed.y = Rand()*2.0f;
+ dim.x = Rand()*1.5f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+
+ m_object->SetAngleY(1, m_oldAngle+(m_newAngle-m_oldAngle)*m_progress);
+ }
+
+ if ( m_phase == TPP_DOWN ) // descend le crayon ?
+ {
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_supportPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*3.0f;
+ speed.z = (Rand()-0.5f)*3.0f;
+ speed.y = Rand()*5.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR, 4.0f);
+ }
+
+ i = AngleToRank(m_object->RetAngleY(1));
+ pos = m_object->RetPosition(10+i);
+ if ( m_timeDown == 0.0f )
+ {
+ pos.y = 0.0f;
+ }
+ else
+ {
+ pos.y = -3.2f*Bounce(Min(m_progress*1.8f, 1.0f));
+ }
+ m_object->SetPosition(10+i, pos);
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskPen::Start(BOOL bDown, int color)
+{
+ D3DVECTOR pos;
+ D3DMATRIX* mat;
+ ObjectType type;
+ int i;
+
+ m_bError = TRUE; // opération impossible
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILEdr ) return ERR_FIRE_VEH;
+
+ m_bError = FALSE; // ok
+
+ m_oldAngle = m_object->RetAngleY(1);
+ m_newAngle = ColorToAngle(color);
+
+ i = AngleToRank(m_oldAngle);
+ pos = m_object->RetPosition(10+i);
+
+ if ( pos.y == 0.0f ) // crayon en haut ?
+ {
+ m_timeUp = 0.0f;
+ }
+ else // crayon en bas ?
+ {
+ m_timeUp = 1.0f; // faut le remonter
+ }
+
+ if ( bDown ) // faudra-t-il le descendre en dernier ?
+ {
+ m_timeDown = 0.7f;
+ }
+ else
+ {
+ m_timeDown = 0.0f;
+ }
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(-3.0f, 7.0f, 0.0f);
+ pos = Transform(*mat, pos); // position carrousel
+ m_supportPos = pos;
+
+ m_phase = TPP_UP;
+ m_progress = 0.0f;
+ m_delay = m_timeUp;
+ m_time = 0.0f;
+
+ if ( m_timeUp > 0.0f )
+ {
+ SoundManip(m_timeUp, 1.0f, 0.5f);
+ }
+
+ m_lastParticule = 0.0f;
+
+//? m_camera->StartCentering(m_object, PI*0.60f, 99.9f, 5.0f, 0.5f);
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskPen::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TPP_UP )
+ {
+ m_phase = TPP_TURN;
+ m_progress = 0.0f;
+ m_delay = Abs(m_oldAngle-m_newAngle)/PI;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ if ( m_delay > 0.0f )
+ {
+ SoundManip(m_delay, 1.0f, 1.0f);
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TPP_TURN )
+ {
+ m_sound->Play(SOUND_PSHHH2, m_supportPos, 1.0f, 1.4f);
+ m_phase = TPP_DOWN;
+ m_progress = 0.0f;
+ m_delay = m_timeDown;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskPen::Abort()
+{
+//? m_camera->StopCentering(m_object, 0.5f);
+ return TRUE;
+}
+
+
+// Fait entendre le son du bras manipulateur.
+
+void CTaskPen::SoundManip(float time, float amplitude, float frequency)
+{
+ int i;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f*frequency, TRUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f*amplitude, 1.0f*frequency, time-0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f*frequency, 0.1f, SOPER_STOP);
+}
+
+
+// Conversion d'un angle en numéro de crayon.
+
+int CTaskPen::AngleToRank(float angle)
+{
+//? return (int)(angle/(-45.0f*PI/180.0f));
+ angle = -angle;
+ angle += (45.0f*PI/180.0f)/2.0f;
+ return (int)(angle/(45.0f*PI/180.0f));
+}
+
+// Conversion d'une couleur en angle pour le carrousel de crayons.
+
+float CTaskPen::ColorToAngle(int color)
+{
+ return -45.0f*PI/180.0f*ColorToRank(color);
+}
+
+// Conversion d'une couleur en numéro de crayon (0..7).
+
+int CTaskPen::ColorToRank(int color)
+{
+ if ( color == 8 ) return 1; // yellow
+ if ( color == 7 ) return 2; // orange
+ if ( color == 5 ) return 2; // pink
+ if ( color == 4 ) return 3; // red
+ if ( color == 6 ) return 4; // purple
+ if ( color == 14 ) return 5; // blue
+ if ( color == 15 ) return 5; // light blue
+ if ( color == 12 ) return 6; // green
+ if ( color == 13 ) return 6; // light green
+ if ( color == 10 ) return 7; // brown
+ if ( color == 9 ) return 7; // beige
+ return 0; // black
+}
+
diff --git a/src/taskpen.h b/src/taskpen.h
new file mode 100644
index 0000000..35740a6
--- /dev/null
+++ b/src/taskpen.h
@@ -0,0 +1,58 @@
+// taskpen.h
+
+#ifndef _TASKSPEN_H_
+#define _TASKSPEN_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskPenPhase
+{
+ TPP_UP = 1, // monte le crayon
+ TPP_TURN = 2, // tourne le carrousel
+ TPP_DOWN = 3, // descend le crayon
+};
+
+
+
+class CTaskPen : public CTask
+{
+public:
+ CTaskPen(CInstanceManager* iMan, CObject* object);
+ ~CTaskPen();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(BOOL bDown, int color);
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ void SoundManip(float time, float amplitude, float frequency);
+ int AngleToRank(float angle);
+ float ColorToAngle(int color);
+ int ColorToRank(int color);
+
+protected:
+ BOOL m_bError;
+ TaskPenPhase m_phase;
+ float m_progress;
+ float m_delay;
+ float m_time;
+ float m_lastParticule;
+ D3DVECTOR m_supportPos;
+
+ float m_timeUp;
+ float m_oldAngle;
+ float m_newAngle;
+ float m_timeDown;
+};
+
+
+#endif //_TASKSPEN_H_
diff --git a/src/taskrecover.cpp b/src/taskrecover.cpp
new file mode 100644
index 0000000..ce06669
--- /dev/null
+++ b/src/taskrecover.cpp
@@ -0,0 +1,415 @@
+// taskrecover.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "task.h"
+#include "taskrecover.h"
+
+
+#define ENERGY_RECOVER 0.25f // énergie consommée par récupération
+#define RECOVER_DIST 11.8f
+
+
+
+// Constructeur de l'objet.
+
+CTaskRecover::CTaskRecover(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_ruin = 0;
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CTaskRecover::~CTaskRecover()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskRecover::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float a, g, cirSpeed, angle, energy, dist, linSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_phase == TRP_TURN ) // rotation préliminaire ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*1.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ return TRUE;
+ }
+
+ m_progress += event.rTime*m_speed; // ça avance
+ m_time += event.rTime;
+
+ if ( m_phase == TRP_DOWN )
+ {
+ angle = Prop(126, -10, m_progress);
+ m_object->SetAngleZ(2, angle);
+ m_object->SetAngleZ(4, angle);
+
+ angle = Prop(-144, 0, m_progress);
+ m_object->SetAngleZ(3, angle);
+ m_object->SetAngleZ(5, angle);
+ }
+
+ if ( m_phase == TRP_MOVE ) // avance/recule préliminaire ?
+ {
+ dist = Length(m_object->RetPosition(0), m_ruin->RetPosition(0));
+ linSpeed = 0.0f;
+ if ( dist > RECOVER_DIST ) linSpeed = 1.0f;
+ if ( dist < RECOVER_DIST ) linSpeed = -1.0f;
+ m_physics->SetMotorSpeedX(linSpeed); // avance/recule
+ return TRUE;
+ }
+
+ if ( m_phase == TRP_OPER )
+ {
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ energy = power->RetEnergy();
+ power->SetEnergy(energy-ENERGY_RECOVER*event.rTime*m_speed);
+ }
+
+ speed.x = (Rand()-0.5f)*0.1f*m_progress;
+ speed.y = (Rand()-0.5f)*0.1f*m_progress;
+ speed.z = (Rand()-0.5f)*0.1f*m_progress;
+ m_ruin->SetCirVibration(speed);
+
+ if ( m_progress >= 0.75f )
+ {
+ m_ruin->SetZoom(0, 1.0f-(m_progress-0.75f)/0.25f);
+ }
+
+ if ( m_progress > 0.5f && m_progress < 0.8f )
+ {
+ m_metal->SetZoom(0, (m_progress-0.5f)/0.3f);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.02f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_recoverPos;
+ pos.x += (Rand()-0.5f)*8.0f*(1.0f-m_progress);
+ pos.z += (Rand()-0.5f)*8.0f*(1.0f-m_progress);
+ pos.y -= 4.0f;
+ speed.x = (Rand()-0.5f)*0.0f;
+ speed.z = (Rand()-0.5f)*0.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*2.0f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIRECOVER, 1.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if ( m_phase == TRP_UP )
+ {
+ angle = Prop(-10, 126, m_progress);
+ m_object->SetAngleZ(2, angle);
+ m_object->SetAngleZ(4, angle);
+
+ angle = Prop(0, -144, m_progress);
+ m_object->SetAngleZ(3, angle);
+ m_object->SetAngleZ(5, angle);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.02f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_recoverPos;
+ pos.y -= 4.0f;
+ speed.x = (Rand()-0.5f)*0.0f;
+ speed.z = (Rand()-0.5f)*0.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*2.0f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIRECOVER, 1.0f, 0.0f, 0.0f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskRecover::Start()
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, iPos, oPos;
+ float energy;
+
+ ObjectType type;
+
+ m_bError = TRUE; // opération impossible
+ if ( !m_physics->RetLand() ) return ERR_RECOVER_VEH;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILErr ) return ERR_RECOVER_VEH;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_RECOVER_ENERGY;
+ energy = power->RetEnergy();
+ if ( energy < ENERGY_RECOVER/power->RetCapacity()+0.05f ) return ERR_RECOVER_ENERGY;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(RECOVER_DIST, 3.3f, 0.0f);
+ pos = Transform(*mat, pos); // position devant
+ m_recoverPos = pos;
+
+ m_ruin = SearchRuin();
+ if ( m_ruin == 0 ) return ERR_RECOVER_NULL;
+ m_ruin->SetLock(TRUE); // ruine plus utilisable
+
+ iPos = m_object->RetPosition(0);
+ oPos = m_ruin->RetPosition(0);
+ m_angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+
+ m_metal = 0;
+
+ m_phase = TRP_TURN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ m_camera->StartCentering(m_object, PI*0.85f, 99.9f, 10.0f, 3.0f);
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskRecover::IsEnded()
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed, goal;
+ FPOINT dim;
+ float angle, dist, time;
+ int i;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_phase == TRP_TURN ) // rotation préliminaire ?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angle-PI*0.01f, m_angle+PI*0.01f) )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ dist = Length(m_object->RetPosition(0), m_ruin->RetPosition(0));
+ if ( dist > RECOVER_DIST )
+ {
+ time = m_physics->RetLinTimeLength(dist-RECOVER_DIST, 1.0f);
+ m_speed = 1.0f/time;
+ }
+ else
+ {
+ time = m_physics->RetLinTimeLength(RECOVER_DIST-dist, -1.0f);
+ m_speed = 1.0f/time;
+ }
+ m_phase = TRP_MOVE;
+ m_progress = 0.0f;
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TRP_MOVE ) // avance préliminaire ?
+ {
+ dist = Length(m_object->RetPosition(0), m_ruin->RetPosition(0));
+
+ if ( dist >= RECOVER_DIST-1.0f &&
+ dist <= RECOVER_DIST+1.0f )
+ {
+ m_physics->SetMotorSpeedX(0.0f);
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(RECOVER_DIST, 3.3f, 0.0f);
+ pos = Transform(*mat, pos); // position devant
+ m_recoverPos = pos;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.9f, TRUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 0.3f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.9f, 0.3f, SOPER_STOP);
+
+ m_phase = TRP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.5f;
+ m_time = 0.0f;
+ }
+ else
+ {
+ if ( m_progress > 1.0f ) // timeout ?
+ {
+ m_ruin->SetLock(FALSE); // de nouveau utilisable
+ m_camera->StopCentering(m_object, 2.0f);
+ return ERR_RECOVER_NULL;
+ }
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TRP_DOWN )
+ {
+ m_metal = new CObject(m_iMan);
+ if ( !m_metal->CreateResource(m_recoverPos, 0.0f, OBJECT_METAL) )
+ {
+ delete m_metal;
+ m_metal = 0;
+ Abort();
+ m_bError = TRUE;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return ERR_STOP;
+ }
+ m_metal->SetLock(TRUE); // métal pas encore utilisable
+ m_metal->SetZoom(0, 0.0f);
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(RECOVER_DIST, 3.1f, 3.9f);
+ pos = Transform(*mat, pos);
+ goal = D3DVECTOR(RECOVER_DIST, 3.1f, -3.9f);
+ goal = Transform(*mat, goal);
+ m_particule->CreateRay(pos, goal, PARTIRAY2,
+ FPOINT(2.0f, 2.0f), 8.0f);
+
+ m_soundChannel = m_sound->Play(SOUND_RECOVER, m_ruin->RetPosition(0), 0.0f, 1.0f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.6f, 1.0f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.6f, 1.0f, 4.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.7f, 2.0f, SOPER_STOP);
+
+ m_phase = TRP_OPER;
+ m_speed = 1.0f/8.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TRP_OPER )
+ {
+ m_metal->SetZoom(0, 1.0f);
+
+ m_ruin->DeleteObject(); // détruit la ruine
+ delete m_ruin;
+ m_ruin = 0;
+
+ m_soundChannel = -1;
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.9f, TRUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 0.3f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 1.0f, 1.5f, 1.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.9f, 0.3f, SOPER_STOP);
+
+ m_phase = TRP_UP;
+ m_speed = 1.0f/1.5f;
+ return ERR_CONTINUE;
+ }
+
+ m_metal->SetLock(FALSE); // métal utilisable
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskRecover::Abort()
+{
+ m_object->SetAngleZ(2, 126.0f*PI/180.0f);
+ m_object->SetAngleZ(4, 126.0f*PI/180.0f);
+ m_object->SetAngleZ(3, -144.0f*PI/180.0f);
+ m_object->SetAngleZ(5, -144.0f*PI/180.0f); // repos
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+// Cherche si un ruine est devant le véhicule.
+
+CObject* CTaskRecover::SearchRuin()
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float dist, min;
+ int i;
+
+ pBest = 0;
+ min = 100000.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_RUINmobilew1 ||
+ type == OBJECT_RUINmobilew2 ||
+ type == OBJECT_RUINmobilet1 ||
+ type == OBJECT_RUINmobilet2 ||
+ type == OBJECT_RUINmobiler1 ||
+ type == OBJECT_RUINmobiler2 ) // véhicule en ruine ?
+ {
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_recoverPos);
+ if ( dist > 40.0f ) continue;
+
+ if ( dist < min )
+ {
+ min = dist;
+ pBest = pObj;
+ }
+ }
+
+ }
+ return pBest;
+}
+
diff --git a/src/taskrecover.h b/src/taskrecover.h
new file mode 100644
index 0000000..bc14d00
--- /dev/null
+++ b/src/taskrecover.h
@@ -0,0 +1,56 @@
+// taskrecover.h
+
+#ifndef _TASKSRECOVER_H_
+#define _TASKSRECOVER_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskRecoverPhase
+{
+ TRP_TURN = 1, // tourne
+ TRP_MOVE = 2, // avance
+ TRP_DOWN = 3, // descend
+ TRP_OPER = 4, // opère
+ TRP_UP = 5, // remonte
+};
+
+
+
+class CTaskRecover : public CTask
+{
+public:
+ CTaskRecover(CInstanceManager* iMan, CObject* object);
+ ~CTaskRecover();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ CObject* SearchRuin();
+
+protected:
+ TaskRecoverPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_angle;
+ float m_lastParticule;
+ BOOL m_bError;
+ CObject* m_ruin;
+ CObject* m_metal;
+ D3DVECTOR m_recoverPos;
+ int m_soundChannel;
+};
+
+
+#endif //_TASKSRECOVER_H_
diff --git a/src/taskreset.cpp b/src/taskreset.cpp
new file mode 100644
index 0000000..0d4aa28
--- /dev/null
+++ b/src/taskreset.cpp
@@ -0,0 +1,329 @@
+// taskreset.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "task.h"
+#include "taskreset.h"
+
+
+
+#define RESET_DELAY_ZOOM 0.7f
+#define RESET_DELAY_MOVE 0.7f
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskReset::CTaskReset(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskReset::~CTaskReset()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskReset::EventProcess(const Event &event)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle, duration;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_time += event.rTime;
+ m_progress += event.rTime*m_speed;
+
+ if ( m_phase == TRSP_ZOUT )
+ {
+ angle = m_iAngle;
+ angle += powf(m_progress*5.0f, 2.0f); // accélère
+ m_object->SetAngleY(0, angle);
+ m_object->SetZoom(0, 1.0f-m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_begin;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+
+ pos = m_begin;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ speed *= 1.0f-m_progress*0.5f;
+ pos += speed*1.5f;
+ speed = -speed;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*1.5f+1.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+ }
+
+ if ( m_phase == TRSP_MOVE )
+ {
+ pos = m_begin+(m_goal-m_begin)*m_progress;
+ m_object->SetPosition(0, pos);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 2.0f+Rand()*2.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+ }
+ }
+
+ if ( m_phase == TRSP_ZIN )
+ {
+ angle = m_angle.y;
+ angle += -powf((1.0f-m_progress)*5.0f, 2.0f); // freine
+ m_object->SetAngleY(0, angle);
+ m_object->SetZoom(0, m_progress);
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_goal;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = 0.0f;
+ speed.z = 0.0f;
+ speed.y = 5.0f+Rand()*5.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGLINTb, 2.0f);
+
+ pos = m_goal;
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = Rand()*10.0f;
+ speed *= 0.5f+m_progress*0.5f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*1.5f+1.5f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK6,
+ duration, 0.0f,
+ duration*0.9f, 0.7f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+// Un angle positif effectue un virage à droite.
+
+Error CTaskReset::Start(D3DVECTOR goal, D3DVECTOR angle)
+{
+ CObject* fret;
+ int i;
+
+ fret = m_object->RetFret();
+ if ( fret != 0 && fret->RetResetCap() == RESET_MOVE )
+ {
+ fret->SetTruck(0);
+ m_object->SetFret(0); // ne porte plus rien
+ }
+
+ if ( !m_main->RetNiceReset() ) // retour rapide ?
+ {
+ m_object->SetPosition(0, goal);
+ m_object->SetAngle(0, angle);
+ m_brain->RunProgram(m_object->RetResetRun());
+
+ m_bError = FALSE;
+ return ERR_OK;
+ }
+
+ m_begin = m_object->RetPosition(0);
+ m_goal = goal;
+ m_angle = angle;
+
+ if ( SearchVehicle() ) // emplacement de départ occupé ?
+ {
+ m_bError = TRUE;
+ return ERR_RESET_NEAR;
+ }
+
+ m_iAngle = m_object->RetAngleY(0);
+ m_time = 0.0f;
+ m_phase = TRSP_ZOUT;
+ m_speed = 1.0f/RESET_DELAY_ZOOM;
+ m_progress = 0.0f;
+ m_lastParticule = 0.0f;
+
+ m_object->SetResetBusy(TRUE);
+
+ i = m_sound->Play(SOUND_GGG, m_begin, 1.0f, 2.0f, TRUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.5f, RESET_DELAY_ZOOM, SOPER_STOP);
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskReset::IsEnded()
+{
+ CObject* power;
+ float dist;
+ int i;
+
+ if ( !m_main->RetNiceReset() ) // retour rapide ?
+ {
+ return ERR_STOP;
+ }
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+
+ if ( m_phase == TRSP_ZOUT )
+ {
+ dist = Length(m_begin, m_goal);
+ m_phase = TRSP_MOVE;
+ m_speed = 1.0f/(dist*RESET_DELAY_MOVE/100.0f);
+ m_progress = 0.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TRSP_MOVE )
+ {
+ m_object->SetPosition(0, m_goal);
+ m_object->SetAngle(0, m_angle);
+
+ i = m_sound->Play(SOUND_GGG, m_goal, 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(i, 0.0f, 2.0f, RESET_DELAY_ZOOM, SOPER_STOP);
+
+ m_phase = TRSP_ZIN;
+ m_speed = 1.0f/RESET_DELAY_ZOOM;
+ m_progress = 0.0f;
+ return ERR_CONTINUE;
+ }
+
+ m_object->SetAngle(0, m_angle);
+ m_object->SetZoom(0, 1.0f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetEnergy(power->RetCapacity()); // refait le plein
+ }
+
+ m_brain->RunProgram(m_object->RetResetRun());
+ m_object->SetResetBusy(FALSE);
+ return ERR_STOP;
+}
+
+
+// Cherche si un véhicule est trop proche.
+
+BOOL CTaskReset::SearchVehicle()
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ ObjectType type;
+ float oRadius, dist;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+
+ type = pObj->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_TECH &&
+ type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_MOBILEdr &&
+ type != OBJECT_MOTHER &&
+ type != OBJECT_ANT &&
+ type != OBJECT_SPIDER &&
+ type != OBJECT_BEE &&
+ type != OBJECT_WORM ) continue;
+
+ if ( !pObj->GetCrashSphere(0, oPos, oRadius) ) continue;
+ dist = Length(oPos, m_goal)-oRadius;
+
+ if ( dist < 5.0f ) return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/src/taskreset.h b/src/taskreset.h
new file mode 100644
index 0000000..fa80a40
--- /dev/null
+++ b/src/taskreset.h
@@ -0,0 +1,53 @@
+// taskreset.h
+
+#ifndef _TASKRESET_H_
+#define _TASKRESET_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskResetPhase
+{
+ TRSP_ZOUT = 1, // disparaît
+ TRSP_MOVE = 2, // déplace
+ TRSP_ZIN = 3, // réapparaît
+};
+
+
+
+class CTaskReset : public CTask
+{
+public:
+ CTaskReset(CInstanceManager* iMan, CObject* object);
+ ~CTaskReset();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(D3DVECTOR goal, D3DVECTOR angle);
+ Error IsEnded();
+
+protected:
+ BOOL SearchVehicle();
+
+protected:
+ D3DVECTOR m_begin;
+ D3DVECTOR m_goal;
+ D3DVECTOR m_angle;
+
+ TaskResetPhase m_phase;
+ BOOL m_bError;
+ float m_time;
+ float m_speed;
+ float m_progress;
+ float m_lastParticule; // temps génération dernière particule
+ float m_iAngle;
+};
+
+
+#endif //_TASKRESET_H_
diff --git a/src/tasksearch.cpp b/src/tasksearch.cpp
new file mode 100644
index 0000000..f4b65b5
--- /dev/null
+++ b/src/tasksearch.cpp
@@ -0,0 +1,318 @@
+// tasksearch.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "displaytext.h"
+#include "task.h"
+#include "tasksearch.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskSearch::CTaskSearch(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_hand = TSH_UP;
+}
+
+// Destructeur de l'objet.
+
+CTaskSearch::~CTaskSearch()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskSearch::EventProcess(const Event &event)
+{
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float angle;
+ int i;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // ça avance
+ m_time += event.rTime;
+
+ if ( m_phase == TSP_DOWN ||
+ m_phase == TSP_UP )
+ {
+ for ( i=0 ; i<3 ; i++ )
+ {
+ angle = (m_finalAngle[i]-m_initialAngle[i])*m_progress;
+ angle += m_initialAngle[i];
+ m_object->SetAngleZ(i+1, angle);
+ }
+ }
+
+ if ( m_phase == TSP_SEARCH &&
+ m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(6.5f, 0.2f, 0.0f);
+ pos = Transform(*mat, pos); // position capteur
+
+ speed.x = (Rand()-0.5f)*20.0f;
+ speed.z = (Rand()-0.5f)*20.0f;
+ speed.y = 0.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIGAS);
+ }
+
+ return TRUE;
+}
+
+
+// Initialise les angles finaux et initiaux.
+
+void CTaskSearch::InitAngle()
+{
+ int i;
+
+ if ( m_hand == TSH_UP )
+ {
+ m_finalAngle[0] = 110.0f*PI/180.0f; // bras
+ m_finalAngle[1] = -110.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = -65.0f*PI/180.0f; // capteur
+ }
+ if ( m_hand == TSH_DOWN )
+ {
+ m_finalAngle[0] = 25.0f*PI/180.0f; // bras
+ m_finalAngle[1] = -70.0f*PI/180.0f; // avant-bras
+ m_finalAngle[2] = -45.0f*PI/180.0f; // capteur
+ }
+
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_initialAngle[i] = m_object->RetAngleZ(i+1);
+ }
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskSearch::Start()
+{
+ ObjectType type;
+ D3DVECTOR speed;
+ int i;
+
+ m_bError = TRUE;
+ if ( !m_physics->RetLand() ) return ERR_SEARCH_FLY;
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_SEARCH_MOTOR;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis ) return ERR_SEARCH_VEH;
+
+ m_hand = TSH_DOWN;
+ m_phase = TSP_DOWN;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+ m_lastParticule = 0.0f;
+
+ InitAngle();
+ m_bError = FALSE; // ok
+
+ m_camera->StartCentering(m_object, PI*0.50f, 99.9f, 0.0f, 1.0f);
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.9f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f, 0.1f, SOPER_STOP);
+
+ m_physics->SetFreeze(TRUE); // on ne bouge plus
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskSearch::IsEnded()
+{
+ int i;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TSP_DOWN ||
+ m_phase == TSP_UP )
+ {
+ for ( i=0 ; i<3 ; i++ )
+ {
+ m_object->SetAngleZ(i+1, m_finalAngle[i]);
+ }
+ }
+
+ if ( m_phase == TSP_DOWN )
+ {
+ m_sound->Play(SOUND_REPAIR, m_object->RetPosition(0));
+
+ m_phase = TSP_SEARCH;
+ m_speed = 1.0f/4.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TSP_SEARCH )
+ {
+ CreateMark();
+
+ m_hand = TSH_UP;
+ InitAngle();
+
+ i = m_sound->Play(SOUND_MANIP, m_object->RetPosition(0), 0.0f, 0.3f, TRUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.1f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.5f, 1.0f, 0.9f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(i, 0.0f, 0.3f, 0.1f, SOPER_STOP);
+
+ m_phase = TSP_UP;
+ m_speed = 1.0f/1.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskSearch::Abort()
+{
+ m_camera->StopCentering(m_object, 2.0f);
+ m_physics->SetFreeze(FALSE); // on bouge de nouveau
+ return TRUE;
+}
+
+
+// Crée une marque si c'est possible.
+
+BOOL CTaskSearch::CreateMark()
+{
+ CObject* fret;
+ ObjectType type;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ TerrainRes res;
+ Error info;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(7.5f, 0.0f, 0.0f);
+ pos = Transform(*mat, pos); // position capteur
+
+ res = m_terrain->RetResource(pos);
+ if ( res == TR_NULL ) return FALSE;
+
+ type = OBJECT_NULL;
+ if ( res == TR_STONE )
+ {
+ type = OBJECT_MARKSTONE;
+ info = INFO_MARKSTONE;
+ }
+ if ( res == TR_URANIUM )
+ {
+ type = OBJECT_MARKURANIUM;
+ info = INFO_MARKURANIUM;
+ }
+ if ( res == TR_POWER )
+ {
+ type = OBJECT_MARKPOWER;
+ info = INFO_MARKPOWER;
+ }
+ if ( res == TR_KEYa )
+ {
+ type = OBJECT_MARKKEYa;
+ info = INFO_MARKKEYa;
+ }
+ if ( res == TR_KEYb )
+ {
+ type = OBJECT_MARKKEYb;
+ info = INFO_MARKKEYb;
+ }
+ if ( res == TR_KEYc )
+ {
+ type = OBJECT_MARKKEYc;
+ info = INFO_MARKKEYc;
+ }
+ if ( res == TR_KEYd )
+ {
+ type = OBJECT_MARKKEYd;
+ info = INFO_MARKKEYd;
+ }
+ if ( type == OBJECT_NULL ) return FALSE;
+
+//? DeleteMark(type);
+
+ fret = new CObject(m_iMan);
+ if ( !fret->CreateResource(pos, 0.0f, type) )
+ {
+ delete fret;
+ m_displayText->DisplayError(ERR_TOOMANY, m_object);
+ return FALSE;
+ }
+
+ m_displayText->DisplayError(info, pos, 5.0f, 50.0f); // affiche le message
+
+ return TRUE;
+}
+
+// Détruit les marques d'un type donné..
+
+void CTaskSearch::DeleteMark(ObjectType type)
+{
+ CObject* pObj;
+ D3DVECTOR oPos;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( type == pObj->RetType() )
+ {
+ pObj->DeleteObject(); // supprime la marque
+ delete pObj;
+ break;
+ }
+ }
+}
+
+
diff --git a/src/tasksearch.h b/src/tasksearch.h
new file mode 100644
index 0000000..3d6cca5
--- /dev/null
+++ b/src/tasksearch.h
@@ -0,0 +1,60 @@
+// tasksearch.h
+
+#ifndef _TASKSEARCH_H_
+#define _TASKSEARCH_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskSearchHand
+{
+ TSH_UP = 1, // capteur en haut
+ TSH_DOWN = 2, // capteur en bas
+};
+
+enum TaskSearchPhase
+{
+ TSP_DOWN = 1, // descend
+ TSP_SEARCH = 2, // cherche
+ TSP_UP = 3, // remonte
+};
+
+
+
+class CTaskSearch : public CTask
+{
+public:
+ CTaskSearch(CInstanceManager* iMan, CObject* object);
+ ~CTaskSearch();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ void InitAngle();
+ BOOL CreateMark();
+ void DeleteMark(ObjectType type);
+
+protected:
+ TaskSearchHand m_hand;
+ TaskSearchPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_lastParticule;
+ float m_initialAngle[3];
+ float m_finalAngle[3];
+ BOOL m_bError;
+};
+
+
+#endif //_TASKSEARCH_H_
diff --git a/src/taskshield.cpp b/src/taskshield.cpp
new file mode 100644
index 0000000..3ae44c8
--- /dev/null
+++ b/src/taskshield.cpp
@@ -0,0 +1,557 @@
+// taskshield.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "camera.h"
+#include "light.h"
+#include "sound.h"
+#include "task.h"
+#include "taskshield.h"
+
+
+#define ENERGY_TIME 20.0f // durée maximale si pile pleine
+
+
+
+// Constructeur de l'objet.
+
+CTaskShield::CTaskShield(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_rankSphere = -1;
+ m_soundChannel = -1;
+ m_effectLight = -1;
+}
+
+// Destructeur de l'objet.
+
+CTaskShield::~CTaskShield()
+{
+ Abort();
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskShield::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DMATRIX matrix;
+ D3DVECTOR pos, speed, goal, angle;
+ D3DCOLORVALUE color;
+ FPOINT dim;
+ float energy;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // ça avance
+ m_time += event.rTime;
+ m_delay -= event.rTime;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(7.0f, 15.0f, 0.0f);
+ pos = Transform(*mat, pos); // position sphère
+ m_shieldPos = pos;
+
+ if ( m_rankSphere != -1 )
+ {
+ m_particule->SetPosition(m_rankSphere, m_shieldPos);
+ dim.x = RetRadius();
+ dim.y = dim.x;
+ m_particule->SetDimension(m_rankSphere, dim);
+ }
+
+ if ( m_phase == TS_UP1 )
+ {
+ pos.x = 7.0f;
+ pos.y = 4.5f+Bounce(m_progress)*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ if ( m_phase == TS_UP2 )
+ {
+ pos.x = 0.0f;
+ pos.y = 1.0f+Bounce(m_progress)*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+ }
+
+ if ( m_phase == TS_SHIELD )
+ {
+ energy = (1.0f/ENERGY_TIME)*event.rTime;
+ energy *= RetRadius()/RADIUS_SHIELD_MAX;
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetEnergy(power->RetEnergy()-energy/power->RetCapacity());
+ }
+ m_energyUsed += energy;
+
+ if ( m_soundChannel == -1 )
+ {
+ m_soundChannel = m_sound->Play(SOUND_SHIELD, m_shieldPos, 0.5f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 2.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 1.0f, 1.0f, SOPER_LOOP);
+ }
+ else
+ {
+ m_sound->Position(m_soundChannel, m_shieldPos);
+ }
+
+ pos = m_shieldPos;
+ pos.y += RetRadius()*(2.0f+sinf(m_time*9.0f)*0.2f);
+ if ( m_effectLight == -1 )
+ {
+ CreateLight(pos);
+ }
+ else
+ {
+ m_light->SetLightPos(m_effectLight, pos);
+
+ color.r = 0.0f+sinf(m_time*33.2f)*0.2f;
+ color.g = 0.5f+sinf(m_time*20.0f)*0.5f;
+ color.b = 0.5f+sinf(m_time*21.3f)*1.0f;
+ color.a = 0.0f;
+ m_light->SetLightColor(m_effectLight, color);
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_shieldPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*0.0f;
+ speed.z = (Rand()-0.5f)*0.0f;
+ speed.y = Rand()*15.0f;
+ dim.x = Rand()*6.0f+4.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLUE, 1.0f, 0.0f, 0.0f);
+ }
+
+ if ( m_lastRay+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastRay = m_time;
+
+ pos = m_shieldPos;
+ dim.x = RetRadius()/20.0f;
+ dim.y = dim.x;
+ angle.x = (Rand()-0.5f)*PI*1.2f;
+ angle.y = 0.0f;
+ angle.z = (Rand()-0.5f)*PI*1.2f;
+ MatRotateXZY(matrix, angle);
+ goal = Transform(matrix, D3DVECTOR(0.0f, RetRadius()-dim.x, 0.0f));
+ goal += pos;
+ m_particule->CreateRay(pos, goal, PARTIRAY2, dim, 0.3f);
+ }
+
+ if ( m_lastIncrease+0.2f <= m_time )
+ {
+ m_lastIncrease = m_time;
+ IncreaseShield();
+ }
+ }
+
+ if ( m_phase == TS_SMOKE )
+ {
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.5f, 2.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ if ( m_lastParticule+m_engine->ParticuleAdapt(0.05f) <= m_time )
+ {
+ m_lastParticule = m_time;
+
+ pos = m_shieldPos;
+ pos.x += (Rand()-0.5f)*5.0f;
+ pos.z += (Rand()-0.5f)*5.0f;
+ speed.x = (Rand()-0.5f)*3.0f;
+ speed.z = (Rand()-0.5f)*3.0f;
+ speed.y = (Rand()-0.5f)*3.0f;
+ dim.x = Rand()*1.5f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE3, 4.0f);
+ }
+ }
+
+ if ( m_phase == TS_DOWN1 )
+ {
+ pos.x = 0.0f;
+ pos.y = 1.0f+(1.0f-Bounce(m_progress))*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+ }
+
+ if ( m_phase == TS_DOWN2 )
+ {
+ pos.x = 7.0f;
+ pos.y = 4.5f+(1.0f-Bounce(m_progress))*3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ return TRUE;
+}
+
+
+// Déploie le bouclier.
+// Le délai n'est utile qu'avec TSM_UP !
+
+Error CTaskShield::Start(TaskShieldMode mode, float delay)
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, iPos, oPos, speed;
+ ObjectType type;
+ float energy;
+
+ if ( mode == TSM_DOWN )
+ {
+ return Stop();
+ }
+
+ if ( mode == TSM_UPDATE )
+ {
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+ return ERR_OK;
+ }
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILErs ) return ERR_SHIELD_VEH;
+
+ m_bError = TRUE; // opération impossible
+ if ( !m_physics->RetLand() ) return ERR_SHIELD_VEH;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_SHIELD_ENERGY;
+ energy = power->RetEnergy();
+ if ( energy == 0.0f ) return ERR_SHIELD_ENERGY;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(7.0f, 15.0f, 0.0f);
+ pos = Transform(*mat, pos); // position sphère
+ m_shieldPos = pos;
+
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 0.7f);
+
+ m_phase = TS_UP1;
+ m_progress = 0.0f;
+ m_speed = 1.0f/1.0f;
+ m_time = 0.0f;
+ m_delay = delay;
+ m_lastParticule = 0.0f;
+ m_lastRay = 0.0f;
+ m_lastIncrease = 0.0f;
+ m_energyUsed = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+//? m_camera->StartCentering(m_object, PI*0.85f, -PI*0.15f, RetRadius()+40.0f, 3.0f);
+ return ERR_OK;
+}
+
+// Rentre le bouclier.
+
+Error CTaskShield::Stop()
+{
+ float time;
+
+ if ( m_phase == TS_SHIELD )
+ {
+ m_object->SetShieldRadius(0.0f);
+
+ if ( m_rankSphere != -1 )
+ {
+ m_particule->SetPhase(m_rankSphere, PARPHEND, 3.0f);
+ m_rankSphere = -1;
+ }
+
+ if ( m_effectLight != -1 )
+ {
+ m_light->DeleteLight(m_effectLight);
+ m_effectLight = -1;
+ }
+
+ time = m_energyUsed*4.0f;
+ if ( time < 1.0f ) time = 1.0f;
+ if ( time > 4.0f ) time = 4.0f;
+
+ m_phase = TS_SMOKE;
+ m_speed = 1.0f/time;
+
+ m_camera->StopCentering(m_object, 4.0f);
+
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+ return ERR_CONTINUE;
+ }
+
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskShield::IsEnded()
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float energy;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_phase == TS_SHIELD )
+ {
+ m_object->SetShieldRadius(RetRadius());
+
+ power = m_object->RetPower();
+ if ( power == 0 )
+ {
+ energy = 0.0f;
+ }
+ else
+ {
+ energy = power->RetEnergy();
+ }
+
+ if ( energy == 0.0f || m_delay <= 0.0f )
+ {
+ Stop();
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TS_UP1 )
+ {
+ pos.x = 7.0f;
+ pos.y = 4.5f+3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 1.0f);
+
+ m_phase = TS_UP2;
+ m_speed = 1.0f/0.8f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TS_UP2 )
+ {
+ pos.x = 0.0f;
+ pos.y = 1.0f+3.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+
+ m_object->SetShieldRadius(RetRadius());
+
+ pos = m_shieldPos;
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = RetRadius();
+ dim.y = dim.x;
+ m_rankSphere = m_particule->CreateParticule(pos, speed, dim, PARTISPHERE3, 2.0f, 0.0f, 0.0f);
+
+ m_phase = TS_SHIELD;
+ m_speed = 1.0f/999.9f;
+
+ if ( m_object->RetSelect() )
+ {
+ m_brain->UpdateInterface();
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TS_SMOKE )
+ {
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 1.0f);
+
+ m_phase = TS_DOWN1;
+ m_speed = 1.0f/0.8f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TS_DOWN1 )
+ {
+ m_sound->Play(SOUND_PSHHH2, m_shieldPos, 1.0f, 0.7f);
+
+ m_phase = TS_DOWN2;
+ m_speed = 1.0f/1.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Indique si l'action est en cours.
+
+BOOL CTaskShield::IsBusy()
+{
+ if ( m_phase == TS_SHIELD )
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskShield::Abort()
+{
+ D3DVECTOR pos;
+
+ m_object->SetShieldRadius(0.0f);
+
+ pos.x = 7.0f;
+ pos.y = 4.5f;
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+
+ pos.x = 0.0f;
+ pos.y = 1.0f;
+ pos.z = 0.0f;
+ m_object->SetPosition(3, pos);
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.5f, 0.5f, 2.0f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ if ( m_rankSphere != -1 )
+ {
+ m_particule->SetPhase(m_rankSphere, PARPHEND, 3.0f);
+ m_rankSphere = -1;
+ }
+
+ if ( m_effectLight != -1 )
+ {
+ m_light->DeleteLight(m_effectLight);
+ m_effectLight = -1;
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+// Crée la lumière pour accompagner un effet pyrotechnique.
+
+BOOL CTaskShield::CreateLight(D3DVECTOR pos)
+{
+ D3DLIGHT7 light;
+
+ if ( !m_engine->RetLightMode() ) return TRUE;
+
+ ZeroMemory( &light, sizeof(light) );
+ light.dltType = D3DLIGHT_SPOT;
+ light.dcvDiffuse.r = 0.0f;
+ light.dcvDiffuse.g = 1.0f;
+ light.dcvDiffuse.b = 2.0f;
+ light.dvPosition.x = pos.x;
+ light.dvPosition.y = pos.y;
+ light.dvPosition.z = pos.z;
+ light.dvDirection.x = 0.0f;
+ light.dvDirection.y = -1.0f; // contre en bas
+ light.dvDirection.z = 0.0f;
+ light.dvRange = D3DLIGHT_RANGE_MAX;
+ light.dvFalloff = 1.0f;
+ light.dvAttenuation0 = 1.0f;
+ light.dvAttenuation1 = 0.0f;
+ light.dvAttenuation2 = 0.0f;
+ light.dvTheta = 0.0f;
+ light.dvPhi = PI/4.0f;
+
+ m_effectLight = m_light->CreateLight();
+ if ( m_effectLight == -1 ) return FALSE;
+
+ m_light->SetLight(m_effectLight, light);
+ m_light->SetLightIntensity(m_effectLight, 1.0f);
+
+ return TRUE;
+}
+
+
+// Répare le bouclier des objets dans la sphère du bouclier.
+
+void CTaskShield::IncreaseShield()
+{
+ ObjectType type;
+ CObject* pObj;
+ D3DVECTOR oPos;
+ float dist, shield;
+ int i;
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_MOTHER ||
+ type == OBJECT_ANT ||
+ type == OBJECT_SPIDER ||
+ type == OBJECT_BEE ||
+ type == OBJECT_WORM ) continue;
+
+ oPos = pObj->RetPosition(0);
+ dist = Length(oPos, m_shieldPos);
+ if ( dist <= RetRadius()+10.0f )
+ {
+ shield = pObj->RetShield();
+ shield += 0.1f;
+ if ( shield > 1.0f ) shield = 1.0f;
+ pObj->SetShield(shield);
+ }
+ }
+}
+
+
+// Retourne le rayon du bouclier.
+
+float CTaskShield::RetRadius()
+{
+ return RADIUS_SHIELD_MIN + (RADIUS_SHIELD_MAX-RADIUS_SHIELD_MIN)*m_object->RetParam();
+}
+
+
+
diff --git a/src/taskshield.h b/src/taskshield.h
new file mode 100644
index 0000000..e6bfd0c
--- /dev/null
+++ b/src/taskshield.h
@@ -0,0 +1,74 @@
+// taskshield.h
+
+#ifndef _TASKSHIELD_H_
+#define _TASKSHIELD_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+#define RADIUS_SHIELD_MIN 40.0f // rayon min de la zone protégée
+#define RADIUS_SHIELD_MAX 100.0f // rayon max de la zone protégée
+
+
+enum TaskShieldPhase
+{
+ TS_UP1 = 1, // monte
+ TS_UP2 = 2, // monte
+ TS_SHIELD = 3, // bouclier déployé
+ TS_SMOKE = 4, // fume
+ TS_DOWN1 = 5, // descend
+ TS_DOWN2 = 6, // descend
+};
+
+enum TaskShieldMode
+{
+ TSM_UP = 1, // déploie le bouclier
+ TSM_DOWN = 2, // rentre le bouclier
+ TSM_UPDATE = 3, // changement de rayon
+};
+
+
+
+class CTaskShield : public CTask
+{
+public:
+ CTaskShield(CInstanceManager* iMan, CObject* object);
+ ~CTaskShield();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(TaskShieldMode mode, float delay);
+ Error IsEnded();
+ BOOL IsBusy();
+ BOOL Abort();
+
+protected:
+ Error Stop();
+ BOOL CreateLight(D3DVECTOR pos);
+ void IncreaseShield();
+ float RetRadius();
+
+protected:
+ TaskShieldPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_delay;
+ float m_lastParticule;
+ float m_lastRay;
+ float m_lastIncrease;
+ float m_energyUsed;
+ BOOL m_bError;
+ D3DVECTOR m_shieldPos;
+ int m_rankSphere;
+ int m_soundChannel;
+ int m_effectLight;
+};
+
+
+#endif //_TASKSHIELD_H_
diff --git a/src/taskspiderexplo.cpp b/src/taskspiderexplo.cpp
new file mode 100644
index 0000000..6a2a322
--- /dev/null
+++ b/src/taskspiderexplo.cpp
@@ -0,0 +1,108 @@
+// taskspiderexplo.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "object.h"
+#include "physics.h"
+#include "pyro.h"
+#include "motion.h"
+#include "motionspider.h"
+#include "task.h"
+#include "taskspiderexplo.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskSpiderExplo::CTaskSpiderExplo(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_time = 0.0f;
+ m_bError = FALSE;
+}
+
+// Destructeur de l'objet.
+
+CTaskSpiderExplo::~CTaskSpiderExplo()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskSpiderExplo::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ // Objet momentanément immobile (fourmi sur le dos) ?
+ if ( m_object->RetFixed() )
+ {
+ m_bError = TRUE;
+ return TRUE;
+ }
+
+ m_time += event.rTime;
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskSpiderExplo::Start()
+{
+ m_motion->SetAction(MSS_EXPLO, 1.0f); // l'abdomen gonfle
+ m_time = 0.0f;
+
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskSpiderExplo::IsEnded()
+{
+ CPyro* pyro;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError )
+ {
+ Abort();
+ return ERR_STOP;
+ }
+
+ if ( m_time < 1.0f ) return ERR_CONTINUE;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_SPIDER, m_object); // l'araignée explose (suicide)
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskSpiderExplo::Abort()
+{
+ return TRUE;
+}
+
diff --git a/src/taskspiderexplo.h b/src/taskspiderexplo.h
new file mode 100644
index 0000000..a934b83
--- /dev/null
+++ b/src/taskspiderexplo.h
@@ -0,0 +1,34 @@
+// taskspiderexplo.h
+
+#ifndef _TASKSPIDEREXPLO_H_
+#define _TASKSPIDEREXPLO_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskSpiderExplo : public CTask
+{
+public:
+ CTaskSpiderExplo(CInstanceManager* iMan, CObject* object);
+ ~CTaskSpiderExplo();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+
+protected:
+ float m_time;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKSPIDEREXPLO_H_
diff --git a/src/tasktake.cpp b/src/tasktake.cpp
new file mode 100644
index 0000000..a979a3e
--- /dev/null
+++ b/src/tasktake.cpp
@@ -0,0 +1,596 @@
+// tasktake.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "water.h"
+#include "camera.h"
+#include "motion.h"
+#include "motionhuman.h"
+#include "sound.h"
+#include "robotmain.h"
+#include "task.h"
+#include "tasktake.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskTake::CTaskTake(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+
+ m_arm = TTA_NEUTRAL;
+}
+
+// Destructeur de l'objet.
+
+CTaskTake::~CTaskTake()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskTake::EventProcess(const Event &event)
+{
+ float a, g, cirSpeed;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ if ( m_bTurn ) // rotation préliminaire ?
+ {
+ a = m_object->RetAngleY(0);
+ g = m_angle;
+ cirSpeed = Direction(a, g)*2.0f;
+ if ( cirSpeed > 1.0f ) cirSpeed = 1.0f;
+ if ( cirSpeed < -1.0f ) cirSpeed = -1.0f;
+
+ m_physics->SetMotorSpeedZ(cirSpeed); // tourne à gauche/droite
+ return TRUE;
+ }
+
+ m_progress += event.rTime*m_speed; // ça avance
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f)); // immobile !
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskTake::Start()
+{
+ ObjectType type;
+ CObject* other;
+ float iAngle, oAngle, h;
+ D3DVECTOR pos;
+
+ m_height = 0.0f;
+ m_step = 0;
+ m_progress = 0.0f;
+
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+ oAngle = iAngle;
+
+ m_bError = TRUE; // opération impossible
+ if ( !m_physics->RetLand() )
+ {
+ pos = m_object->RetPosition(0);
+ h = m_water->RetLevel(m_object);
+ if ( pos.y < h ) return ERR_MANIP_WATER; // impossible sous l'eau
+ return ERR_MANIP_FLY;
+ }
+
+ type = m_object->RetType();
+ if ( type != OBJECT_HUMAN &&
+ type != OBJECT_TECH ) return ERR_MANIP_VEH;
+
+ m_physics->SetMotorSpeed(D3DVECTOR(0.0f, 0.0f, 0.0f));
+
+ if ( m_object->RetFret() == 0 )
+ {
+ m_order = TTO_TAKE;
+ }
+ else
+ {
+ m_order = TTO_DEPOSE;
+ }
+
+ if ( m_order == TTO_TAKE )
+ {
+ pos = m_object->RetPosition(0);
+ h = m_water->RetLevel(m_object);
+ if ( pos.y < h ) return ERR_MANIP_WATER; // impossible sous l'eau
+
+ other = SearchFriendObject(oAngle, 1.5f, PI*0.50f);
+ if ( other != 0 && other->RetPower() != 0 )
+ {
+ type = other->RetPower()->RetType();
+ if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO;
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT ) return ERR_MANIP_FRIEND;
+//? m_camera->StartCentering(m_object, PI*0.3f, -PI*0.1f, 0.0f, 0.8f);
+ m_arm = TTA_FRIEND;
+ }
+ else
+ {
+ other = SearchTakeObject(oAngle, 1.5f, PI*0.45f);
+ if ( other == 0 ) return ERR_MANIP_NIL;
+ type = other->RetType();
+ if ( type == OBJECT_URANIUM ) return ERR_MANIP_RADIO;
+//? m_camera->StartCentering(m_object, PI*0.3f, 99.9f, 0.0f, 0.8f);
+ m_arm = TTA_FFRONT;
+ m_main->HideDropZone(other); // cache zone constructible
+ }
+ }
+
+ if ( m_order == TTO_DEPOSE )
+ {
+//? speed = m_physics->RetMotorSpeed();
+//? if ( speed.x != 0.0f ||
+//? speed.z != 0.0f ) return ERR_MANIP_MOTOR;
+
+ other = SearchFriendObject(oAngle, 1.5f, PI*0.50f);
+ if ( other != 0 && other->RetPower() == 0 )
+ {
+//? m_camera->StartCentering(m_object, PI*0.3f, -PI*0.1f, 0.0f, 0.8f);
+ m_arm = TTA_FRIEND;
+ }
+ else
+ {
+ if ( !IsFreeDeposeObject(D3DVECTOR(2.5f, 0.0f, 0.0f)) ) return ERR_MANIP_OCC;
+//? m_camera->StartCentering(m_object, PI*0.3f, 99.9f, 0.0f, 0.8f);
+ m_arm = TTA_FFRONT;
+ }
+ }
+
+ m_bTurn = TRUE; // rotation préliminaire nécessaire
+ m_angle = oAngle; // angle à atteindre
+
+ m_physics->SetFreeze(TRUE); // on ne bouge plus
+
+ m_bError = FALSE; // ok
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskTake::IsEnded()
+{
+ CObject* fret;
+ float angle;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_bTurn ) // rotation préliminaire ?
+ {
+ angle = m_object->RetAngleY(0);
+ angle = NormAngle(angle); // 0..2*PI
+
+ if ( TestAngle(angle, m_angle-PI*0.01f, m_angle+PI*0.01f) )
+ {
+ m_bTurn = FALSE; // rotation terminée
+ m_physics->SetMotorSpeedZ(0.0f);
+
+ if ( m_arm == TTA_FFRONT )
+ {
+ m_motion->SetAction(MHS_TAKE, 0.2f); // se baisse
+ }
+ if ( m_arm == TTA_FRIEND )
+ {
+ if ( m_height <= 3.0f )
+ {
+ m_motion->SetAction(MHS_TAKEOTHER, 0.2f); // se baisse
+ }
+ else
+ {
+ m_motion->SetAction(MHS_TAKEHIGH, 0.2f); // se baisse
+ }
+ }
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.6f;
+ }
+ return ERR_CONTINUE;
+ }
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ m_step ++;
+
+ if ( m_order == TTO_TAKE )
+ {
+ if ( m_step == 1 )
+ {
+ if ( TruckTakeObject() )
+ {
+ if ( m_arm == TTA_FRIEND &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWEROFF, m_object->RetPosition(0));
+ }
+ }
+ m_motion->SetAction(MHS_UPRIGHT, 0.4f); // se relève
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.8f;
+ m_camera->StopCentering(m_object, 0.8f);
+ return ERR_CONTINUE;
+ }
+ }
+
+ if ( m_order == TTO_DEPOSE )
+ {
+ if ( m_step == 1 )
+ {
+ fret = m_object->RetFret();
+ TruckDeposeObject();
+ if ( m_arm == TTA_FRIEND &&
+ (m_fretType == OBJECT_POWER ||
+ m_fretType == OBJECT_ATOMIC ) )
+ {
+ m_sound->Play(SOUND_POWERON, m_object->RetPosition(0));
+ }
+ if ( fret != 0 && m_fretType == OBJECT_METAL && m_arm == TTA_FFRONT )
+ {
+ m_main->ShowDropZone(fret, m_object); // montre zone constructible
+ }
+ m_motion->SetAction(-1); // se relève
+ m_progress = 0.0f;
+ m_speed = 1.0f/0.4f;
+ m_camera->StopCentering(m_object, 0.8f);
+ return ERR_CONTINUE;
+ }
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskTake::Abort()
+{
+ m_motion->SetAction(-1);
+ m_camera->StopCentering(m_object, 0.8f);
+ m_physics->SetFreeze(FALSE); // on bouge de nouveau
+ return TRUE;
+}
+
+
+// Cherche l'objet à prendre devant.
+
+CObject* CTaskTake::SearchTakeObject(float &angle,
+ float dLimit, float aLimit)
+{
+ CObject *pObj, *pBest;
+ D3DVECTOR iPos, oPos;
+ ObjectType type;
+ float min, iAngle, bAngle, a, distance;
+ int i;
+
+ iPos = m_object->RetPosition(0);
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ min = 1000000.0f;
+ pBest = 0;
+ bAngle = 0.0f;
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+
+ if ( type != OBJECT_FRET &&
+ type != OBJECT_STONE &&
+ type != OBJECT_URANIUM &&
+ type != OBJECT_BULLET &&
+ type != OBJECT_METAL &&
+ type != OBJECT_POWER &&
+ type != OBJECT_ATOMIC &&
+ type != OBJECT_BBOX &&
+ type != OBJECT_KEYa &&
+ type != OBJECT_KEYb &&
+ type != OBJECT_KEYc &&
+ type != OBJECT_KEYd &&
+ type != OBJECT_TNT ) continue;
+
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+ if ( pObj->RetLock() ) continue;
+ if ( pObj->RetZoomY(0) != 1.0f ) continue;
+
+ oPos = pObj->RetPosition(0);
+ distance = Length(oPos, iPos);
+ if ( distance >= 4.0f-dLimit &&
+ distance <= 4.0f+dLimit )
+ {
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ a = Abs(angle-iAngle);
+ if ( a > PI ) a = PI*2.0f-a;
+ if ( a < min )
+ {
+ min = a;
+ pBest = pObj;
+ bAngle = angle;
+ }
+ }
+ }
+ }
+ angle = bAngle;
+ return pBest;
+}
+
+// Cherche le robot sur lequel on veut prendre ou poser une pile.
+
+CObject* CTaskTake::SearchFriendObject(float &angle,
+ float dLimit, float aLimit)
+{
+ Character* character;
+ CObject* pObj;
+ CObject* pPower;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ ObjectType type, powerType;
+ float iAngle, iRad, distance;
+ int i;
+
+ if ( !m_object->GetCrashSphere(0, iPos, iRad) ) return 0;
+ iAngle = m_object->RetAngleY(0);
+ iAngle = NormAngle(iAngle); // 0..2*PI
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue; // soi-même ?
+
+ type = pObj->RetType();
+ if ( type != OBJECT_MOBILEfa &&
+ type != OBJECT_MOBILEta &&
+ type != OBJECT_MOBILEwa &&
+ type != OBJECT_MOBILEia &&
+ type != OBJECT_MOBILEfc &&
+ type != OBJECT_MOBILEtc &&
+ type != OBJECT_MOBILEwc &&
+ type != OBJECT_MOBILEic &&
+ type != OBJECT_MOBILEfi &&
+ type != OBJECT_MOBILEti &&
+ type != OBJECT_MOBILEwi &&
+ type != OBJECT_MOBILEii &&
+ type != OBJECT_MOBILEfs &&
+ type != OBJECT_MOBILEts &&
+ type != OBJECT_MOBILEws &&
+ type != OBJECT_MOBILEis &&
+ type != OBJECT_MOBILErt &&
+ type != OBJECT_MOBILErc &&
+ type != OBJECT_MOBILErr &&
+ type != OBJECT_MOBILErs &&
+ type != OBJECT_MOBILEsa &&
+ type != OBJECT_MOBILEtg &&
+ type != OBJECT_MOBILEft &&
+ type != OBJECT_MOBILEtt &&
+ type != OBJECT_MOBILEwt &&
+ type != OBJECT_MOBILEit &&
+ type != OBJECT_TOWER &&
+ type != OBJECT_RESEARCH &&
+ type != OBJECT_ENERGY &&
+ type != OBJECT_LABO &&
+ type != OBJECT_NUCLEAR ) continue;
+
+ pPower = pObj->RetPower();
+ if ( pPower != 0 )
+ {
+ if ( pPower->RetLock() ) continue;
+ if ( pPower->RetZoomY(0) != 1.0f ) continue;
+
+ powerType = pPower->RetType();
+ if ( powerType == OBJECT_NULL ||
+ powerType == OBJECT_FIX ) continue;
+ }
+
+ mat = pObj->RetWorldMatrix(0);
+ character = pObj->RetCharacter();
+ oPos = Transform(*mat, character->posPower);
+
+ distance = Abs(Length(oPos, iPos) - (iRad+1.0f));
+ if ( distance <= dLimit )
+ {
+ angle = RotateAngle(oPos.x-iPos.x, iPos.z-oPos.z); // CW !
+ if ( TestAngle(angle, iAngle-aLimit, iAngle+aLimit) )
+ {
+ character = pObj->RetCharacter();
+ m_height = character->posPower.y;
+ return pObj;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// Prend l'objet placé devant.
+
+BOOL CTaskTake::TruckTakeObject()
+{
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX matRotate;
+ float angle;
+
+ if ( m_arm == TTA_FFRONT ) // prend au sol devant ?
+ {
+//? fret = SearchTakeObject(angle, 1.5f, PI*0.04f);
+ fret = SearchTakeObject(angle, 1.5f, PI*0.15f); //OK 1.9
+ if ( fret == 0 ) return FALSE; // rien à prendre ?
+ m_fretType = fret->RetType();
+
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(4); // prend avec la main
+
+//? fret->SetPosition(0, D3DVECTOR(2.2f, -1.0f, 1.1f));
+ fret->SetPosition(0, D3DVECTOR(1.7f, -0.5f, 1.1f));
+ fret->SetAngleY(0, 0.1f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.8f);
+
+ m_object->SetFret(fret); // prend
+ }
+
+ if ( m_arm == TTA_FRIEND ) // prend pile sur amis ?
+ {
+ other = SearchFriendObject(angle, 1.5f, PI*0.04f);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret == 0 ) return FALSE; // l'autre n'a pas de pile ?
+ m_fretType = fret->RetType();
+
+ other->SetPower(0);
+ fret->SetTruck(m_object);
+ fret->SetTruckPart(4); // prend avec la main
+
+//? fret->SetPosition(0, D3DVECTOR(2.2f, -1.0f, 1.1f));
+ fret->SetPosition(0, D3DVECTOR(1.7f, -0.5f, 1.1f));
+ fret->SetAngleY(0, 0.1f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.8f);
+
+ m_object->SetFret(fret); // prend
+ }
+
+ return TRUE;
+}
+
+// Dépose l'objet pris.
+
+BOOL CTaskTake::TruckDeposeObject()
+{
+ Character* character;
+ CObject* fret;
+ CObject* other;
+ D3DMATRIX* mat;
+ D3DVECTOR pos;
+ float angle;
+
+ if ( m_arm == TTA_FFRONT ) // dépose au sol devant ?
+ {
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE; // ne porte rien ?
+ m_fretType = fret->RetType();
+
+ mat = fret->RetWorldMatrix(0);
+ pos = Transform(*mat, D3DVECTOR(-0.5f, 1.0f, 0.0f));
+ m_terrain->MoveOnFloor(pos);
+ fret->SetPosition(0, pos);
+ fret->SetAngleY(0, m_object->RetAngleY(0)+PI/2.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->FloorAdjust(); // plaque bien au sol
+
+ fret->SetTruck(0);
+ m_object->SetFret(0); // dépose
+ }
+
+ if ( m_arm == TTA_FRIEND ) // dépose pile sur amis ?
+ {
+ other = SearchFriendObject(angle, 1.5f, PI*0.04f);
+ if ( other == 0 ) return FALSE;
+
+ fret = other->RetPower();
+ if ( fret != 0 ) return FALSE; // l'autre a déjà une pile ?
+
+ fret = m_object->RetFret();
+ if ( fret == 0 ) return FALSE;
+ m_fretType = fret->RetType();
+
+ other->SetPower(fret);
+ fret->SetTruck(other);
+
+ character = other->RetCharacter();
+ fret->SetPosition(0, character->posPower);
+ fret->SetAngleY(0, 0.0f);
+ fret->SetAngleX(0, 0.0f);
+ fret->SetAngleZ(0, 0.0f);
+ fret->SetTruckPart(0); // porté par la base
+
+ m_object->SetFret(0); // dépose
+ }
+
+ return TRUE;
+}
+
+// Cherche si un emplacement permet de déposer un objet.
+
+BOOL CTaskTake::IsFreeDeposeObject(D3DVECTOR pos)
+{
+ CObject* pObj;
+ D3DMATRIX* mat;
+ D3DVECTOR iPos, oPos;
+ float oRadius;
+ int i, j;
+
+ mat = m_object->RetWorldMatrix(0);
+ iPos = Transform(*mat, pos);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ if ( pObj == m_object ) continue;
+ if ( !pObj->RetActif() ) continue; // inactif ?
+ if ( pObj->RetTruck() != 0 ) continue; // objet transporté ?
+
+ j = 0;
+ while ( pObj->GetCrashSphere(j++, oPos, oRadius) )
+ {
+ if ( Length(iPos, oPos)-(oRadius+1.0f) < 1.0f )
+ {
+ return FALSE; // emplacement occupé
+ }
+ }
+ }
+ return TRUE; // emplacement libre
+}
+
+
diff --git a/src/tasktake.h b/src/tasktake.h
new file mode 100644
index 0000000..a721022
--- /dev/null
+++ b/src/tasktake.h
@@ -0,0 +1,65 @@
+// tasktake.h
+
+#ifndef _TASKTAKE_H_
+#define _TASKTAKE_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskTakeOrder
+{
+ TTO_TAKE = 1, // prend un objet
+ TTO_DEPOSE = 2, // dépose l'objet
+};
+
+enum TaskTakeArm
+{
+ TTA_NEUTRAL = 1, // bras vide au repos
+ TTA_FFRONT = 2, // bras au sol
+ TTA_FRIEND = 3, // bras derrière un robot amis
+};
+
+
+
+class CTaskTake : public CTask
+{
+public:
+ CTaskTake(CInstanceManager* iMan, CObject* object);
+ ~CTaskTake();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ CObject* SearchTakeObject(float &angle, float dLimit, float aLimit);
+ CObject* SearchFriendObject(float &angle, float dLimit, float aLimit);
+ BOOL TruckTakeObject();
+ BOOL TruckDeposeObject();
+ BOOL IsFreeDeposeObject(D3DVECTOR pos);
+
+protected:
+ CTerrain* m_terrain;
+
+ TaskTakeOrder m_order;
+ TaskTakeArm m_arm;
+ int m_step;
+ float m_speed;
+ float m_progress;
+ float m_height;
+ BOOL m_bError;
+ BOOL m_bTurn;
+ float m_angle;
+ ObjectType m_fretType;
+};
+
+
+#endif //_TASKTAKE_H_
diff --git a/src/taskterraform.cpp b/src/taskterraform.cpp
new file mode 100644
index 0000000..835da53
--- /dev/null
+++ b/src/taskterraform.cpp
@@ -0,0 +1,413 @@
+// taskterraform.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "language.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "pyro.h"
+#include "brain.h"
+#include "camera.h"
+#include "sound.h"
+#include "motion.h"
+#include "motionant.h"
+#include "motionspider.h"
+#include "task.h"
+#include "taskterraform.h"
+
+
+#define ENERGY_TERRA 0.40f // énergie consommée par coup
+#define ACTION_RADIUS 400.0f
+
+
+
+// Constructeur de l'objet.
+
+CTaskTerraform::CTaskTerraform(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+ m_lastParticule = 0.0f;
+ m_soundChannel = -1;
+}
+
+// Destructeur de l'objet.
+
+CTaskTerraform::~CTaskTerraform()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskTerraform::EventProcess(const Event &event)
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, dir, speed;
+ FPOINT dim;
+ float energy;
+
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+ if ( m_bError ) return FALSE;
+
+ m_progress += event.rTime*m_speed; // ça avance
+ m_time += event.rTime;
+
+ if ( m_phase == TTP_CHARGE )
+ {
+ if ( m_soundChannel == -1 )
+ {
+#if _TEEN
+ m_soundChannel = m_sound->Play(SOUND_GGG, m_object->RetPosition(0), 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 2.0f, 1.5f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.5f, SOPER_STOP);
+#else
+ m_soundChannel = m_sound->Play(SOUND_GGG, m_object->RetPosition(0), 1.0f, 0.5f, TRUE);
+ m_sound->AddEnvelope(m_soundChannel, 1.0f, 2.0f, 4.0f, SOPER_CONTINUE);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.5f, SOPER_STOP);
+#endif
+ }
+
+ dir.x = 0.0f;
+ dir.y = (Rand()-0.5f)*0.2f*m_progress;
+ dir.z = 0.0f;
+ m_object->SetCirVibration(dir);
+
+ m_object->SetZoom(0, 1.0f+m_progress*0.2f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f+m_progress*1.0f);
+
+ energy = power->RetEnergy();
+ energy -= event.rTime*ENERGY_TERRA/power->RetCapacity()/4.0f;
+ if ( energy < 0.0f ) energy = 0.0f;
+ power->SetEnergy(energy);
+ }
+ }
+
+ if ( m_phase == TTP_DOWN )
+ {
+ pos.x = 9.0f;
+#if _TEEN
+ pos.y = 4.0f-m_progress*4.0f;
+#else
+ pos.y = 4.0f-m_progress*5.8f;
+#endif
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ if ( m_phase == TTP_UP )
+ {
+ pos.x = 9.0f;
+#if _TEEN
+ pos.y = 4.0f-(1.0f-m_progress)*4.0f;
+#else
+ pos.y = 4.0f-(1.0f-m_progress)*5.8f;
+#endif
+ pos.z = 0.0f;
+ m_object->SetPosition(2, pos);
+ }
+
+ dir.x = 0.0f;
+ dir.y = 0.0f;
+ dir.z = 0.0f;
+ pos = m_object->RetPosition(2);
+ if ( pos.y < 0.0f )
+ {
+ dir.z = -atanf((pos.y/2.0f)/9.0f);
+ }
+ m_object->SetInclinaison(dir);
+
+ if ( m_time-m_lastParticule >= m_engine->ParticuleAdapt(0.05f) )
+ {
+ m_lastParticule = m_time;
+
+ mat = m_object->RetWorldMatrix(0);
+
+ if ( m_phase == TTP_CHARGE )
+ {
+ // Pile.
+ pos = D3DVECTOR(-6.0f, 5.5f+2.0f*m_progress, 0.0f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = (Rand()-0.5f)*6.0f*(1.0f+m_progress*4.0f);
+ speed.z = (Rand()-0.5f)*6.0f*(1.0f+m_progress*4.0f);
+ speed.y = 6.0f+Rand()*4.0f*(1.0f+m_progress*2.0f);
+ dim.x = 0.5f+1.5f*m_progress;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIBLITZ, 2.0f, 20.0f);
+ }
+
+ if ( m_phase != TTP_CHARGE )
+ {
+ // Grille gauche.
+ pos = D3DVECTOR(-1.0f, 5.8f, 3.5f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = Rand()*4.0f;
+ speed.z = Rand()*2.0f;
+ speed.y = 2.5f+Rand()*1.0f;
+ speed = Transform(*mat, speed);
+ speed -= m_object->RetPosition(0);
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f);
+
+ // Grille droite.
+ pos = D3DVECTOR(-1.0f, 5.8f, -3.5f);
+ pos.x += (Rand()-0.5f)*1.0f;
+ pos.z += (Rand()-0.5f)*1.0f;
+ pos = Transform(*mat, pos);
+ speed.x = Rand()*4.0f;
+ speed.z = -Rand()*2.0f;
+ speed.y = 2.5f+Rand()*1.0f;
+ speed = Transform(*mat, speed);
+ speed -= m_object->RetPosition(0);
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTISMOKE1, 3.0f);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskTerraform::Start()
+{
+ CObject* power;
+ D3DMATRIX* mat;
+ D3DVECTOR pos, speed;
+ float energy;
+
+ ObjectType type;
+
+ m_bError = TRUE; // opération impossible
+ if ( !m_physics->RetLand() ) return ERR_TERRA_VEH;
+
+ type = m_object->RetType();
+ if ( type != OBJECT_MOBILErt ) return ERR_TERRA_VEH;
+
+ power = m_object->RetPower();
+ if ( power == 0 ) return ERR_TERRA_ENERGY;
+ energy = power->RetEnergy();
+ if ( energy < ENERGY_TERRA/power->RetCapacity()+0.05f ) return ERR_TERRA_ENERGY;
+
+ speed = m_physics->RetMotorSpeed();
+ if ( speed.x != 0.0f ||
+ speed.z != 0.0f ) return ERR_MANIP_MOTOR;
+
+ mat = m_object->RetWorldMatrix(0);
+ pos = D3DVECTOR(9.0f, 0.0f, 0.0f);
+ pos = Transform(*mat, pos); // position pillon
+ m_terraPos = pos;
+
+ m_phase = TTP_CHARGE;
+ m_progress = 0.0f;
+#if _TEEN
+ m_speed = 1.0f/1.5f;
+#else
+ m_speed = 1.0f/4.0f;
+#endif
+ m_time = 0.0f;
+
+ m_bError = FALSE; // ok
+
+ m_camera->StartCentering(m_object, PI*0.35f, 99.9f, 20.0f, 2.0f);
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskTerraform::IsEnded()
+{
+ CObject* power;
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ float dist, duration;
+ int i, max;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bError ) return ERR_STOP;
+
+ if ( m_progress < 1.0f ) return ERR_CONTINUE;
+ m_progress = 0.0f;
+
+ if ( m_phase == TTP_CHARGE )
+ {
+#if _TEEN
+ Terraform(); // modifie le terrain.
+#endif
+
+ m_phase = TTP_DOWN;
+ m_speed = 1.0f/0.2f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TTP_DOWN )
+ {
+#if !_TEEN
+ Terraform(); // modifie le terrain.
+#endif
+
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetZoom(0, 1.0f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f);
+ }
+
+ max= (int)(50.0f*m_engine->RetParticuleDensity());
+ for ( i=0 ; i<max ; i++ )
+ {
+ pos.x = m_terraPos.x+(Rand()-0.5f)*80.0f;
+ pos.z = m_terraPos.z+(Rand()-0.5f)*80.0f;
+ pos.y = m_terraPos.y;
+ m_terrain->MoveOnFloor(pos);
+ dist = Length(pos, m_terraPos);
+ speed = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ dim.x = 2.0f+(40.0f-dist)/(1.0f+Rand()*4.0f);
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTICRASH, 2.0f);
+
+ pos = m_terraPos;
+ speed.x = (Rand()-0.5f)*40.0f;
+ speed.z = (Rand()-0.5f)*40.0f;
+ speed.y = Rand()*15.0f+15.0f;
+ dim.x = 0.6f;
+ dim.y = dim.x;
+ pos.y += dim.y;
+ duration = Rand()*3.0f+3.0f;
+ m_particule->CreateTrack(pos, speed, dim, PARTITRACK5,
+ duration, Rand()*10.0f+15.0f,
+ duration*0.2f, 1.0f);
+ }
+
+ m_phase = TTP_TERRA;
+ m_speed = 1.0f/2.0f;
+ return ERR_CONTINUE;
+ }
+
+ if ( m_phase == TTP_TERRA )
+ {
+ m_phase = TTP_UP;
+ m_speed = 1.0f/1.0f;
+ return ERR_CONTINUE;
+ }
+
+ Abort();
+ return ERR_STOP;
+}
+
+// Termine brutalement l'action en cours.
+
+BOOL CTaskTerraform::Abort()
+{
+ CObject* power;
+
+ if ( m_soundChannel != -1 )
+ {
+ m_sound->FlushEnvelope(m_soundChannel);
+ m_sound->AddEnvelope(m_soundChannel, 0.0f, 0.5f, 0.3f, SOPER_STOP);
+ m_soundChannel = -1;
+ }
+
+ m_object->SetPosition(2, D3DVECTOR(9.0f, 4.0f, 0.0f));
+ m_object->SetInclinaison(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetCirVibration(D3DVECTOR(0.0f, 0.0f, 0.0f));
+ m_object->SetZoom(0, 1.0f);
+
+ power = m_object->RetPower();
+ if ( power != 0 )
+ {
+ power->SetZoom(0, 1.0f);
+ }
+
+ m_camera->StopCentering(m_object, 2.0f);
+ return TRUE;
+}
+
+
+// Retourne toutes les fourmis et les araignées proches.
+
+BOOL CTaskTerraform::Terraform()
+{
+ CObject* pObj;
+ CBrain* brain;
+ CMotion* motion;
+ CPyro* pyro;
+ ObjectType type;
+ float dist;
+ int i;
+
+ m_camera->StartEffect(CE_TERRAFORM, m_terraPos, 1.0f);
+
+ m_sound->Play(SOUND_THUMP, m_terraPos);
+
+ for ( i=0 ; i<1000000 ; i++ )
+ {
+ pObj = (CObject*)m_iMan->SearchInstance(CLASS_OBJECT, i);
+ if ( pObj == 0 ) break;
+
+ type = pObj->RetType();
+ if ( type == OBJECT_NULL ) continue;
+
+ if ( type == OBJECT_TEEN34 ) // caillou ?
+ {
+ dist = Length(m_terraPos, pObj->RetPosition(0));
+ if ( dist > 20.0f ) continue;
+
+ pyro = new CPyro(m_iMan);
+ pyro->Create(PT_FRAGT, pObj);
+ }
+ else
+ {
+ motion = pObj->RetMotion();
+ if ( motion == 0 ) continue;
+
+ dist = Length(m_terraPos, pObj->RetPosition(0));
+ if ( dist > ACTION_RADIUS ) continue;
+
+ if ( type == OBJECT_ANT )
+ {
+ brain = pObj->RetBrain();
+ if ( brain != 0 ) brain->StopTask();
+ motion->SetAction(MAS_BACK1, 0.8f+Rand()*0.3f);
+ pObj->SetFixed(TRUE); // ne bouge plus
+ }
+ if ( type == OBJECT_SPIDER )
+ {
+ brain = pObj->RetBrain();
+ if ( brain != 0 ) brain->StopTask();
+ motion->SetAction(MSS_BACK1, 0.8f+Rand()*0.3f);
+ pObj->SetFixed(TRUE); // ne bouge plus
+ }
+ }
+ }
+
+ return TRUE;
+}
+
diff --git a/src/taskterraform.h b/src/taskterraform.h
new file mode 100644
index 0000000..5da6bb7
--- /dev/null
+++ b/src/taskterraform.h
@@ -0,0 +1,52 @@
+// taskterraform.h
+
+#ifndef _TASKSTERRAFORM_H_
+#define _TASKSTERRAFORM_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+
+enum TaskTerraPhase
+{
+ TTP_CHARGE = 1, // charge d'énergie
+ TTP_DOWN = 2, // descend
+ TTP_TERRA = 3, // frappe
+ TTP_UP = 4, // remonte
+};
+
+
+
+class CTaskTerraform : public CTask
+{
+public:
+ CTaskTerraform(CInstanceManager* iMan, CObject* object);
+ ~CTaskTerraform();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start();
+ Error IsEnded();
+ BOOL Abort();
+
+protected:
+ BOOL Terraform();
+
+protected:
+ TaskTerraPhase m_phase;
+ float m_progress;
+ float m_speed;
+ float m_time;
+ float m_lastParticule;
+ int m_soundChannel;
+ BOOL m_bError;
+ D3DVECTOR m_terraPos;
+};
+
+
+#endif //_TASKSTERRAFORM_H_
diff --git a/src/taskturn.cpp b/src/taskturn.cpp
new file mode 100644
index 0000000..1086b8a
--- /dev/null
+++ b/src/taskturn.cpp
@@ -0,0 +1,131 @@
+// taskturn.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskturn.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskTurn::CTaskTurn(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskTurn::~CTaskTurn()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskTurn::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ // Objet momentanément immobile (fourmi sur le dos) ?
+ if ( m_object->RetFixed() )
+ {
+ m_physics->SetMotorSpeedX(0.0f); // stoppe l'avance
+ m_physics->SetMotorSpeedZ(0.0f); // stoppe la rotation
+ m_bError = TRUE;
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+// Un angle positif effectue un virage à droite.
+
+Error CTaskTurn::Start(float angle)
+{
+ m_startAngle = m_object->RetAngleY(0);
+ m_finalAngle = m_startAngle+angle;
+
+ if ( angle < 0.0f )
+ {
+ m_angle = angle+m_physics->RetCirStopLength();
+ m_physics->SetMotorSpeedZ(-1.0f); // tourne à gauche
+ m_bLeft = TRUE;
+ }
+ else
+ {
+ m_angle = angle-m_physics->RetCirStopLength();
+ m_physics->SetMotorSpeedZ(1.0f); // tourne à droite
+ m_bLeft = FALSE;
+ }
+ m_physics->SetMotorSpeedX(0.0f);
+ m_physics->SetMotorSpeedY(0.0f);
+
+ m_bError = FALSE;
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskTurn::IsEnded()
+{
+ float angle;
+
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+
+ if ( m_bError )
+ {
+ return ERR_STOP;
+ }
+
+ angle = m_object->RetAngleY(0);
+
+ if ( m_bLeft )
+ {
+ if ( angle <= m_startAngle+m_angle )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
+ m_physics->SetCirMotionY(MO_CURSPEED, 0.0f);
+//? m_physics->SetCirMotionY(MO_REASPEED, 0.0f);
+ m_object->SetAngleY(0, m_finalAngle);
+ return ERR_STOP;
+ }
+ }
+ else
+ {
+ if ( angle >= m_startAngle+m_angle )
+ {
+ m_physics->SetMotorSpeedZ(0.0f);
+//? m_physics->SetCirMotionY(MO_MOTSPEED, 0.0f);
+ m_physics->SetCirMotionY(MO_CURSPEED, 0.0f);
+//? m_physics->SetCirMotionY(MO_REASPEED, 0.0f);
+ m_object->SetAngleY(0, m_finalAngle);
+ return ERR_STOP;
+ }
+ }
+
+ return ERR_CONTINUE;
+}
+
+
diff --git a/src/taskturn.h b/src/taskturn.h
new file mode 100644
index 0000000..73ea3ea
--- /dev/null
+++ b/src/taskturn.h
@@ -0,0 +1,36 @@
+// taskturn.h
+
+#ifndef _TASKTURN_H_
+#define _TASKTURN_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskTurn : public CTask
+{
+public:
+ CTaskTurn(CInstanceManager* iMan, CObject* object);
+ ~CTaskTurn();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float angle);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_angle;
+ float m_startAngle;
+ float m_finalAngle;
+ BOOL m_bLeft;
+ BOOL m_bError;
+};
+
+
+#endif //_TASKTURN_H_
diff --git a/src/taskwait.cpp b/src/taskwait.cpp
new file mode 100644
index 0000000..d884e3c
--- /dev/null
+++ b/src/taskwait.cpp
@@ -0,0 +1,73 @@
+// taskwait.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "terrain.h"
+#include "object.h"
+#include "physics.h"
+#include "brain.h"
+#include "task.h"
+#include "taskwait.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CTaskWait::CTaskWait(CInstanceManager* iMan, CObject* object)
+ : CTask(iMan, object)
+{
+ CTask::CTask(iMan, object);
+}
+
+// Destructeur de l'objet.
+
+CTaskWait::~CTaskWait()
+{
+}
+
+
+// Gestion d'un événement.
+
+BOOL CTaskWait::EventProcess(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+ if ( event.event != EVENT_FRAME ) return TRUE;
+
+ m_passTime += event.rTime;
+ m_bEnded = (m_passTime >= m_waitTime);
+ return TRUE;
+}
+
+
+// Assigne le but à atteindre.
+
+Error CTaskWait::Start(float time)
+{
+ m_waitTime = time; // durée à attendre
+ m_passTime = 0.0f; // durée écoulée
+ m_bEnded = FALSE;
+ return ERR_OK;
+}
+
+// Indique si l'action est terminée.
+
+Error CTaskWait::IsEnded()
+{
+ if ( m_engine->RetPause() ) return ERR_CONTINUE;
+ if ( m_bEnded ) return ERR_STOP;
+ return ERR_CONTINUE;
+}
+
+
diff --git a/src/taskwait.h b/src/taskwait.h
new file mode 100644
index 0000000..7a1f782
--- /dev/null
+++ b/src/taskwait.h
@@ -0,0 +1,34 @@
+// taskwait.h
+
+#ifndef _TASKWAIT_H_
+#define _TASKWAIT_H_
+
+
+class CInstanceManager;
+class CTerrain;
+class CBrain;
+class CPhysics;
+class CObject;
+
+
+class CTaskWait : public CTask
+{
+public:
+ CTaskWait(CInstanceManager* iMan, CObject* object);
+ ~CTaskWait();
+
+ BOOL EventProcess(const Event &event);
+
+ Error Start(float time);
+ Error IsEnded();
+
+protected:
+
+protected:
+ float m_waitTime;
+ float m_passTime;
+ BOOL m_bEnded;
+};
+
+
+#endif //_TASKWAIT_H_
diff --git a/src/terrain.cpp b/src/terrain.cpp
new file mode 100644
index 0000000..3d19cac
--- /dev/null
+++ b/src/terrain.cpp
@@ -0,0 +1,2263 @@
+// terrain.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "modfile.h"
+#include "water.h"
+#include "terrain.h"
+
+
+#define BMPHEAD 1078
+
+
+
+// Constructeur du terrain.
+
+CTerrain::CTerrain(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_TERRAIN, this);
+
+ m_engine = (CD3DEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+ m_water = (CWater*)m_iMan->SearchInstance(CLASS_WATER);
+
+ m_mosaic = 20;
+ m_brick = 1<<4;
+ m_size = 10.0f;
+ m_vision = 200.0f;
+ m_relief = 0;
+ m_texture = 0;
+ m_objRank = 0;
+ m_scaleMapping = 0.01f;
+ m_scaleRelief = 1.0f;
+ m_subdivMapping = 1;
+ m_depth = 2;
+ m_texBaseName[0]= 0;
+ m_texBaseExt[0] = 0;
+ m_bMultiText = TRUE;
+ m_bLevelText = FALSE;
+ m_resources = 0;
+ m_levelMatTotal = 0;
+ m_levelMatMax = 0;
+ m_levelDot = 0;
+ m_wind = D3DVECTOR(0.0f, 0.0f, 0.0f);
+ m_defHardness = 0.5f;
+
+ FlushBuildingLevel();
+ FlushFlyingLimit();
+}
+
+// Destructeur du terrain.
+
+CTerrain::~CTerrain()
+{
+ free(m_relief);
+ free(m_texture);
+ free(m_objRank);
+ free(m_resources);
+}
+
+
+// Génère un nouveau terrain plat.
+// Le terrain est composé de mosaïques, elles-mêmes composées
+// de briques. Chaque brique est composée de 2 triangles.
+// mosaic: nombre de mosaïques selon les axes X et Z
+// brick: nombre de briques (puissance de 2)
+// size: taille d'une brique selon les axes X et Z
+// vision: vision avant un changement de résolution
+// scaleMapping: échelle pour mapper les textures
+//
+// ^ z
+// | <---> brick*size
+// +---+---+---+---+
+// | | | |_|_| mosaic = 4
+// | | | | | | brick = 2 (brickP2=1)
+// +---+---+---+---+
+// |\ \| | | |
+// |\ \| | | |
+// +---+---o---+---+---> x
+// | | | | |
+// | | | | |
+// +---+---+---+---+ Le terrain est ici
+// | | | | | vu de dessus.
+// | | | | |
+// +---+---+---+---+
+// <---------------> mosaic*brick*size
+
+BOOL CTerrain::Generate(int mosaic, int brickP2, float size, float vision,
+ int depth, float hardness)
+{
+ int dim;
+
+ m_mosaic = mosaic;
+ m_brick = 1<<brickP2;
+ m_size = size;
+ m_vision = vision;
+ m_depth = depth;
+ m_defHardness = hardness;
+
+ m_engine->SetTerrainVision(vision);
+
+ m_bMultiText = TRUE;
+ m_bLevelText = FALSE;
+ m_scaleMapping = 1.0f/(m_brick*m_size);
+ m_subdivMapping = 1;
+
+ dim = (m_mosaic*m_brick+1)*(m_mosaic*m_brick+1);
+ m_relief = (float*)malloc(sizeof(float)*dim);
+ ZeroMemory(m_relief, sizeof(float)*dim);
+
+ dim = m_mosaic*m_subdivMapping*m_mosaic*m_subdivMapping;
+ m_texture = (int*)malloc(sizeof(int)*dim);
+ ZeroMemory(m_texture, sizeof(int)*dim);
+
+ dim = m_mosaic*m_mosaic;
+ m_objRank = (int*)malloc(sizeof(int)*dim);
+ ZeroMemory(m_objRank, sizeof(int)*dim);
+
+ return TRUE;
+}
+
+
+int CTerrain::RetMosaic()
+{
+ return m_mosaic;
+}
+
+int CTerrain::RetBrick()
+{
+ return m_brick;
+}
+
+float CTerrain::RetSize()
+{
+ return m_size;
+}
+
+float CTerrain::RetScaleRelief()
+{
+ return m_scaleRelief;
+}
+
+
+// Initialise les noms des textures à utiliser pour le terrain.
+
+BOOL CTerrain::InitTextures(char* baseName, int* table, int dx, int dy)
+{
+ int x, y;
+ char* p;
+
+ m_bLevelText = FALSE;
+
+ strcpy(m_texBaseName, baseName);
+ p = strchr(m_texBaseName, '.'); // p <- ^début de l'extension
+ if ( p == 0 )
+ {
+ strcpy(m_texBaseExt, ".tga");
+ }
+ else
+ {
+ strcpy(m_texBaseExt, p); // m_texBaseExt <- ".tga" ou ".bmp"
+ *p = 0; // m_texBaseName <- nom sans extension
+ }
+
+ for ( y=0 ; y<m_mosaic*m_subdivMapping ; y++ )
+ {
+ for ( x=0 ; x<m_mosaic*m_subdivMapping ; x++ )
+ {
+ m_texture[x+y*m_mosaic] = table[(x%dx)+(y%dy)*dx];
+ }
+ }
+ return TRUE;
+}
+
+
+// Vide les niveaux.
+
+void CTerrain::LevelFlush()
+{
+ m_levelMatTotal = 0;
+ m_levelMatMax = 0;
+ m_levelID = 1000;
+ LevelCloseTable();
+}
+
+// Initialise les noms des textures à utiliser pour le terrain.
+
+BOOL CTerrain::LevelMaterial(int id, char* baseName, float u, float v,
+ int up, int right, int down, int left,
+ float hardness)
+{
+ int i;
+
+ i = m_levelMatTotal;
+ if ( i >= MAXMATTERRAIN-1 ) return FALSE;
+
+ LevelOpenTable();
+
+ if ( id == 0 )
+ {
+ id = m_levelID++; // met un id interne standard
+ }
+
+ strcpy(m_levelMat[i].texName, baseName);
+ m_levelMat[i].id = id;
+ m_levelMat[i].u = u;
+ m_levelMat[i].v = v;
+ m_levelMat[i].mat[0] = up;
+ m_levelMat[i].mat[1] = right;
+ m_levelMat[i].mat[2] = down;
+ m_levelMat[i].mat[3] = left;
+ m_levelMat[i].hardness = hardness;
+
+ if ( m_levelMatMax < up+1 ) m_levelMatMax = up+1;
+ if ( m_levelMatMax < right+1 ) m_levelMatMax = right+1;
+ if ( m_levelMatMax < down+1 ) m_levelMatMax = down+1;
+ if ( m_levelMatMax < left+1 ) m_levelMatMax = left+1;
+
+ m_bLevelText = TRUE;
+ m_subdivMapping = 4;
+
+ m_levelMatTotal ++;
+ return TRUE;
+}
+
+
+// Charge le relief dans un fichier BMP.
+// La taille de l'image doit être de dimension dx et dy,
+// avec dx=dy=(mosaic*brick)+1.
+// L'image doit avoir 8 bits/pixels, 256 couleurs avec
+// une palette standard.
+
+// Conversion coordonnée image (x;y) -> world (x;-;z) :
+// Wx = 5*Ix-400
+// Wz = -(5*Iy-400)
+
+// Conversion coordonnée world (x;-;z) -> image (x;y) :
+// Ix = (400+Wx)/5
+// Iy = (400-Wz)/5
+
+BOOL CTerrain::ResFromBMP(const char* filename)
+{
+ FILE* file;
+ int size, sizem;
+
+ file = fopen(filename, "rb");
+ if ( file == NULL ) return FALSE;
+
+ size = (m_mosaic*m_brick)+1;
+ sizem = ((size+4-1)/4)*4; // taille multiple de 4 supérieur
+
+ if ( m_resources != 0 )
+ {
+ free(m_resources);
+ }
+
+ m_resources = (unsigned char*)malloc(BMPHEAD+sizem*size);
+ fread(m_resources, BMPHEAD+sizem*size, 1, file);
+
+ if ( m_resources[18] != (size&0xff) || m_resources[19] != (size>>8) ||
+ m_resources[22] != (size&0xff) || m_resources[23] != (size>>8) )
+ {
+ free(m_resources);
+ m_resources = 0;
+ fclose(file);
+ return FALSE;
+ }
+
+ fclose(file);
+ return TRUE;
+}
+
+// Retourne le type de ressource disponible en sous-sol.
+
+TerrainRes CTerrain::RetResource(const D3DVECTOR &p)
+{
+ int x, y, size, sizem, ress;
+
+ if ( m_resources == 0 ) return TR_NULL;
+
+ x = (int)((p.x + (m_mosaic*m_brick*m_size)/2.0f)/m_size);
+ y = (int)((p.z + (m_mosaic*m_brick*m_size)/2.0f)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return TR_NULL;
+
+ size = (m_mosaic*m_brick)+1;
+ sizem = ((size+4-1)/4)*4; // taille multiple de 4 supérieur
+
+ ress = m_resources[BMPHEAD+x+sizem*y];
+ if ( ress == 5 ) return TR_STONE; // rouge ?
+ if ( ress == 35 ) return TR_URANIUM; // jaune ?
+ if ( ress == 30 ) return TR_POWER; // vert ?
+ if ( ress == 24 ) return TR_KEYa; // ~vert ?
+ if ( ress == 25 ) return TR_KEYb; // ~vert ?
+ if ( ress == 26 ) return TR_KEYc; // ~vert ?
+ if ( ress == 27 ) return TR_KEYd; // ~vert ?
+
+ return TR_NULL;
+}
+
+
+// Initialise un relief tout plat.
+
+void CTerrain::FlushRelief()
+{
+ free(m_relief);
+ m_relief = 0;
+}
+
+// Charge le relief dans un fichier BMP.
+// La taille de l'image doit être de dimension dx et dy,
+// avec dx=dy=(mosaic*brick)+1.
+// L'image doit avoir 8 bits/pixels, 256 niveaux de gris :
+// blanc = sol (y=0)
+// noir = montagne (y=255*scaleRelief)
+
+// Conversion coordonnée image (x;y) -> world (x;-;z) :
+// Wx = 5*Ix-400
+// Wz = -(5*Iy-400)
+
+// Conversion coordonnée world (x;-;z) -> image (x;y) :
+// Ix = (400+Wx)/5
+// Iy = (400-Wz)/5
+
+BOOL CTerrain::ReliefFromBMP(const char* filename, float scaleRelief,
+ BOOL adjustBorder)
+{
+ FILE* file;
+ unsigned char* buffer;
+ int size, sizem, x, y;
+ float level, limit, dist, border;
+
+ m_scaleRelief = scaleRelief;
+
+ file = fopen(filename, "rb");
+ if ( file == NULL ) return FALSE;
+
+ size = (m_mosaic*m_brick)+1;
+ sizem = ((size+4-1)/4)*4; // taille multiple de 4 supérieur
+
+ buffer = (unsigned char*)malloc(BMPHEAD+sizem*size);
+ fread(buffer, BMPHEAD+sizem*size, 1, file);
+
+ if ( buffer[18] != (size&0xff) || buffer[19] != (size>>8) ||
+ buffer[22] != (size&0xff) || buffer[23] != (size>>8) )
+ {
+ free(buffer);
+ fclose(file);
+ return FALSE;
+ }
+
+ limit = 0.9f;
+ for ( y=0 ; y<size ; y++ )
+ {
+ for ( x=0 ; x<size ; x++ )
+ {
+ level = (255-buffer[BMPHEAD+x+sizem*y])*scaleRelief;
+
+//? dist = Length((float)(x-size/2), (float)(y-size/2));
+ dist = Max(Abs((float)(x-size/2)), Abs((float)(y-size/2)));
+ dist = dist/(float)(size/2);
+ if ( dist > limit && adjustBorder )
+ {
+ dist = (dist-limit)/(1.0f-limit); // 0..1
+ if ( dist > 1.0f ) dist = 1.0f;
+ border = 300.0f+Rand()*20.0f;
+ level = level+dist*(border-level);
+ }
+
+ m_relief[x+y*size] = level;
+ }
+ }
+
+ free(buffer);
+ fclose(file);
+ return TRUE;
+}
+
+// Ajoute un point d'élévation dans le buffer du relief.
+
+BOOL CTerrain::ReliefAddDot(D3DVECTOR pos, float scaleRelief)
+{
+ float dim;
+ int size, x, y;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+ size = (m_mosaic*m_brick)+1;
+
+ pos.x = (pos.x+dim)/m_size;
+ pos.z = (pos.z+dim)/m_size;
+
+ x = (int)pos.x;
+ y = (int)pos.z;
+
+ if ( x < 0 || x >= size ||
+ y < 0 || y >= size ) return FALSE;
+
+ if ( m_relief[x+y*size] < pos.y*scaleRelief )
+ {
+ m_relief[x+y*size] = pos.y*scaleRelief;
+ }
+ return TRUE;
+}
+
+// Charge le relief dans un fichier DXF.
+
+BOOL CTerrain::ReliefFromDXF(const char* filename, float scaleRelief)
+{
+ FILE* file = NULL;
+ char line[100];
+ int command, rankSommet, nbSommet, nbFace, size;
+ D3DVECTOR* table;
+ BOOL bWaitNbSommet;
+ BOOL bWaitNbFace;
+ BOOL bWaitSommetX;
+ BOOL bWaitSommetY;
+ BOOL bWaitSommetZ;
+ BOOL bWaitFaceX;
+ BOOL bWaitFaceY;
+ BOOL bWaitFaceZ;
+ float x,y,z;
+ int p1,p2,p3;
+
+ ZeroMemory(m_relief, sizeof(float)*(m_mosaic*m_brick+1)*(m_mosaic*m_brick+1));
+
+ file = fopen(filename, "r");
+ if ( file == NULL ) return FALSE;
+
+ size = (m_mosaic*m_brick)+1;
+ table = (D3DVECTOR*)malloc(sizeof(D3DVECTOR)*size*size);
+
+ 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 > size*size ) nbSommet = size*size;
+ rankSommet = 0;
+ bWaitNbFace = TRUE;
+ }
+
+ if ( command == 72 && bWaitNbFace )
+ {
+ bWaitNbFace = FALSE;
+ sscanf(line, "%d", &nbFace);
+ bWaitSommetX = TRUE;
+ }
+
+ 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 )
+ {
+ D3DVECTOR p(x,z,y); // permutation de Y et Z !
+ table[rankSommet++] = p;
+ bWaitSommetX = TRUE;
+ }
+ 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 )
+ {
+ ReliefAddDot(table[p3-1], scaleRelief);
+ ReliefAddDot(table[p2-1], scaleRelief);
+ ReliefAddDot(table[p1-1], scaleRelief);
+ bWaitFaceX = TRUE;
+ }
+ }
+
+ }
+
+ free(table);
+ fclose(file);
+ return TRUE;
+}
+
+
+// Ajuste une position pour qu'elle ne dépasse pas les limites.
+
+void CTerrain::LimitPos(D3DVECTOR &pos)
+{
+ float dim;
+
+#if _TEEN
+ dim = (m_mosaic*m_brick*m_size)/2.0f*0.98f;
+#else
+ dim = (m_mosaic*m_brick*m_size)/2.0f*0.92f;
+#endif
+
+ if ( pos.x < -dim ) pos.x = -dim;
+ if ( pos.x > dim ) pos.x = dim;
+ if ( pos.z < -dim ) pos.z = -dim;
+ if ( pos.z > dim ) pos.z = dim;
+}
+
+
+// Ajuste les bords de chaque mosaïque pour être compatible
+// avec toutes les résolutions inférieures.
+
+void CTerrain::AdjustRelief()
+{
+ int x, y, xx, yy, ii, b;
+ float level1, level2;
+
+ if ( m_depth == 1 ) return;
+
+ ii = m_mosaic*m_brick+1;
+ b = 1<<(m_depth-1);
+
+ for ( y=0 ; y<m_mosaic*m_brick ; y+=b )
+ {
+ for ( x=0 ; x<m_mosaic*m_brick ; x+=b )
+ {
+ yy = 0;
+ if ( (y+yy)%m_brick == 0 )
+ {
+ level1 = m_relief[(x+0)+(y+yy)*ii];
+ level2 = m_relief[(x+b)+(y+yy)*ii];
+ for ( xx=1 ; xx<b ; xx++ )
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*xx+level1;
+ }
+ }
+
+ yy = b;
+ if ( (y+yy)%m_brick == 0 )
+ {
+ level1 = m_relief[(x+0)+(y+yy)*ii];
+ level2 = m_relief[(x+b)+(y+yy)*ii];
+ for ( xx=1 ; xx<b ; xx++ )
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*xx+level1;
+ }
+ }
+
+ xx = 0;
+ if ( (x+xx)%m_brick == 0 )
+ {
+ level1 = m_relief[(x+xx)+(y+0)*ii];
+ level2 = m_relief[(x+xx)+(y+b)*ii];
+ for ( yy=1 ; yy<b ; yy++ )
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*yy+level1;
+ }
+ }
+
+ xx = b;
+ if ( (x+xx)%m_brick == 0 )
+ {
+ level1 = m_relief[(x+xx)+(y+0)*ii];
+ level2 = m_relief[(x+xx)+(y+b)*ii];
+ for ( yy=1 ; yy<b ; yy++ )
+ {
+ m_relief[(x+xx)+(y+yy)*ii] = ((level2-level1)/b)*yy+level1;
+ }
+ }
+ }
+ }
+}
+
+
+// Calcule un vecteur du terrain.
+
+D3DVECTOR CTerrain::RetVector(int x, int y)
+{
+ D3DVECTOR p;
+
+ p.x = x*m_size - (m_mosaic*m_brick*m_size)/2;
+ p.z = y*m_size - (m_mosaic*m_brick*m_size)/2;
+
+ if ( m_relief != 0 &&
+ x >= 0 && x <= m_mosaic*m_brick &&
+ y >= 0 && y <= m_mosaic*m_brick )
+ {
+ p.y = m_relief[x+y*(m_mosaic*m_brick+1)];
+ }
+ else
+ {
+ p.y = 0.0f;
+ }
+
+ return p;
+}
+
+// Calcule un vertex du terrain.
+// Calcule une normale adoucie, en tenant compte des 6 triangles
+// adjacents :
+//
+// ^ y
+// |
+// b---c---+
+// |\ |\ |
+// | \| \|
+// a---o---d
+// |\ |\ |
+// | \| \|
+// +---f---e--> x
+
+D3DVERTEX2 CTerrain::RetVertex(int x, int y, int step)
+{
+ D3DVERTEX2 v;
+ D3DVECTOR o, oo, a,b,c,d,e,f, n, s;
+ int brick;
+
+ o = RetVector(x, y);
+ v.x = o.x;
+ v.y = o.y;
+ v.z = o.z;
+
+ a = RetVector(x-step, y );
+ b = RetVector(x-step, y+step);
+ c = RetVector(x, y+step);
+ d = RetVector(x+step, y );
+ e = RetVector(x+step, y-step);
+ f = RetVector(x, y-step);
+
+ s = D3DVECTOR(0.0f, 0.0f, 0.0f);
+
+ if ( x-step >= 0 && y+step <= m_mosaic*m_brick+1 )
+ {
+ s += ComputeNormal(b,a,o);
+ s += ComputeNormal(c,b,o);
+ }
+
+ if ( x+step <= m_mosaic*m_brick+1 && y+step <= m_mosaic*m_brick+1 )
+ {
+ s += ComputeNormal(d,c,o);
+ }
+
+ if ( x+step <= m_mosaic*m_brick+1 && y-step >= 0 )
+ {
+ s += ComputeNormal(e,d,o);
+ s += ComputeNormal(f,e,o);
+ }
+
+ if ( x-step >= 0 && y-step >= 0 )
+ {
+ s += ComputeNormal(a,f,o);
+ }
+
+ s = Normalize(s);
+ v.nx = s.x;
+ v.ny = s.y;
+ v.nz = s.z;
+
+ if ( m_bMultiText )
+ {
+ brick = m_brick/m_subdivMapping;
+ oo = RetVector((x/brick)*brick, (y/brick)*brick);
+ o = RetVector(x, y);
+ v.tu = (o.x-oo.x)*m_scaleMapping*m_subdivMapping;
+ v.tv = 1.0f - (o.z-oo.z)*m_scaleMapping*m_subdivMapping;
+ }
+ else
+ {
+ v.tu = o.x*m_scaleMapping;
+ v.tv = o.z*m_scaleMapping;
+ }
+
+ return v;
+}
+
+// Crée tous les objets d'une mosaïque.
+// L'origine d'une mosaïque est son centre.
+//
+// ^ z
+// |
+// | 2---4---6--
+// | |\ |\ |\
+// | | \| \|
+// | 1---3---5--- ...
+// |
+// +-------------------> x
+
+BOOL CTerrain::CreateMosaic(int ox, int oy, int step, int objRank,
+ const D3DMATERIAL7 &mat,
+ float min, float max)
+{
+ D3DMATRIX transform;
+ D3DVERTEX2 o, p1, p2;
+ D3DObjLevel6* buffer;
+ FPOINT uv;
+ int brick, total, size, mx, my, x, y, xx, yy, i;
+ char texName1[20];
+ char texName2[20];
+ float pixel, dp;
+
+ if ( step == 1 && m_engine->RetGroundSpot() )
+ {
+ i = (ox/5) + (oy/5)*(m_mosaic/5);
+ sprintf(texName2, "shadow%.2d.tga", i);
+ }
+ else
+ {
+ texName2[0] = 0;
+ }
+
+ brick = m_brick/m_subdivMapping;
+
+ o = RetVertex(ox*m_brick+m_brick/2, oy*m_brick+m_brick/2, step);
+ total = ((brick/step)+1)*2;
+ size = sizeof(D3DObjLevel6)+sizeof(D3DVERTEX2)*(total-1);
+
+ pixel = 1.0f/256.0f; // 1 pixel de recouvrement (*)
+//? dp = 0.5f/512.0f;
+ dp = 1.0f/512.0f;
+
+ for ( my=0 ; my<m_subdivMapping ; my++ )
+ {
+ for ( mx=0 ; mx<m_subdivMapping ; mx++ )
+ {
+ if ( m_bLevelText )
+ {
+ xx = ox*m_brick + mx*(m_brick/m_subdivMapping);
+ yy = oy*m_brick + my*(m_brick/m_subdivMapping);
+ LevelTextureName(xx, yy, texName1, uv);
+ }
+ else
+ {
+ i = (ox*m_subdivMapping+mx)+(oy*m_subdivMapping+my)*m_mosaic;
+ sprintf(texName1, "%s%.3d%s", m_texBaseName, m_texture[i], m_texBaseExt);
+ }
+
+ for ( y=0 ; y<brick ; y+=step )
+ {
+ buffer = (D3DObjLevel6*)malloc(size);
+ ZeroMemory(buffer, sizeof(D3DObjLevel6));
+ buffer->totalPossible = total;
+ buffer->totalUsed = total;
+ buffer->type = D3DTYPE6S;
+ buffer->material = mat;
+ if ( m_bMultiText )
+ {
+//? buffer->state = D3DSTATENORMAL;
+ buffer->state = D3DSTATEWRAP;
+ }
+ else
+ {
+ buffer->state = D3DSTATEWRAP;
+ }
+ buffer->state |= D3DSTATESECOND;
+ if ( step == 1 )
+ {
+ buffer->state |= D3DSTATEDUALb;
+ }
+ i = 0;
+ for ( x=0 ; x<=brick ; x+=step )
+ {
+ p1 = RetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+0 , step);
+ p2 = RetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+step, step);
+ p1.x -= o.x; p1.z -= o.z;
+ p2.x -= o.x; p2.z -= o.z;
+
+ if ( m_bMultiText )
+ {
+ if ( x == 0 )
+ {
+ p1.tu = 0.0f+(0.5f/256.0f);
+ p2.tu = 0.0f+(0.5f/256.0f);
+ }
+ if ( x == brick )
+ {
+ p1.tu = 1.0f-(0.5f/256.0f);
+ p2.tu = 1.0f-(0.5f/256.0f);
+ }
+ if ( y == 0 )
+ {
+ p1.tv = 1.0f-(0.5f/256.0f);
+ }
+ if ( y == brick-step )
+ {
+ p2.tv = 0.0f+(0.5f/256.0f);
+ }
+ }
+
+ if ( m_bLevelText )
+ {
+ p1.tu /= m_subdivMapping; // 0..1 -> 0..0.25
+ p1.tv /= m_subdivMapping;
+ p2.tu /= m_subdivMapping;
+ p2.tv /= m_subdivMapping;
+
+ if ( x == 0 )
+ {
+ p1.tu = 0.0f+dp;
+ p2.tu = 0.0f+dp;
+ }
+ if ( x == brick )
+ {
+ p1.tu = (1.0f/m_subdivMapping)-dp;
+ p2.tu = (1.0f/m_subdivMapping)-dp;
+ }
+ if ( y == 0 )
+ {
+ p1.tv = (1.0f/m_subdivMapping)-dp;
+ }
+ if ( y == brick-step )
+ {
+ p2.tv = 0.0f+dp;
+ }
+
+ p1.tu += uv.x;
+ p1.tv += uv.y;
+ p2.tu += uv.x;
+ p2.tv += uv.y;
+ }
+
+#if 1
+ xx = mx*(m_brick/m_subdivMapping) + x;
+ yy = my*(m_brick/m_subdivMapping) + y;
+ p1.tu2 = ((float)(ox%5)*m_brick+xx+0.0f)/(m_brick*5);
+ p1.tv2 = ((float)(oy%5)*m_brick+yy+0.0f)/(m_brick*5);
+ p2.tu2 = ((float)(ox%5)*m_brick+xx+0.0f)/(m_brick*5);
+ p2.tv2 = ((float)(oy%5)*m_brick+yy+1.0f)/(m_brick*5);
+
+ // Correction pour 1 pixel de recouvrement (*).
+ p1.tu2 = (p1.tu2+pixel)*(1.0f-pixel)/(1.0f+pixel);
+ p1.tv2 = (p1.tv2+pixel)*(1.0f-pixel)/(1.0f+pixel);
+ p2.tu2 = (p2.tu2+pixel)*(1.0f-pixel)/(1.0f+pixel);
+ p2.tv2 = (p2.tv2+pixel)*(1.0f-pixel)/(1.0f+pixel);
+#endif
+
+ buffer->vertex[i++] = p1;
+ buffer->vertex[i++] = p2;
+ }
+ m_engine->AddQuick(objRank, buffer, texName1, texName2, min, max, TRUE);
+ }
+ }
+ }
+
+ D3DUtil_SetIdentityMatrix(transform);
+ transform._41 = o.x;
+ transform._43 = o.z;
+ m_engine->SetObjectTransform(objRank, transform);
+
+ return TRUE;
+}
+
+// (*) Il y a 1 pixel de recouvrement autour de chacune des 16 surfaces :
+//
+// |<--------------256-------------->|
+// | |<----------254---------->| |
+// |---|---|---|-- ... --|---|---|---|
+// | 0.0 1.0 |
+// | | | |
+// 0.0 min max 1.0
+//
+// Les coordonnées u-v utilisées pour le texturage sont comprises
+// entre min et max (au lieu de 0 et 1). Ceci permet d'exclure les
+// pixels situés dans une marge d'un pixel tout autour de la surface.
+
+
+// Cherche un matériaux d'après son identificateur.
+
+TerrainMaterial* CTerrain::LevelSearchMat(int id)
+{
+ int i;
+
+ for ( i=0 ; i<m_levelMatTotal ; i++ )
+ {
+ if ( id == m_levelMat[i].id )
+ {
+ return &m_levelMat[i];
+ }
+ }
+
+ return 0;
+}
+
+// Choix de la texture à utiliser pour un carré donné.
+
+void CTerrain::LevelTextureName(int x, int y, char *name, FPOINT &uv)
+{
+ TerrainMaterial* tm;
+
+ x /= m_brick/m_subdivMapping;
+ y /= m_brick/m_subdivMapping;
+
+ tm = LevelSearchMat(m_levelDot[x+y*m_levelDotSize].id);
+ if ( tm == 0 )
+ {
+ strcpy(name, "xxx.tga");
+ uv.x = 0.0f;
+ uv.y = 0.0f;
+ }
+ else
+ {
+//? sprintf(name, "%s.tga", tm->texName);
+ strcpy(name, tm->texName);
+ uv.x = tm->u;
+ uv.y = tm->v;
+ }
+}
+
+// Retourne la hauteur du terrain.
+
+float CTerrain::LevelRetHeight(int x, int y)
+{
+ int size;
+
+ size = (m_mosaic*m_brick+1);
+
+ if ( x < 0 ) x = 0;
+ if ( x >= size ) x = size-1;
+ if ( y < 0 ) y = 0;
+ if ( y >= size ) y = size-1;
+
+ return m_relief[x+y*size];
+}
+
+// Décide si un point utilise le matériaux.
+
+BOOL CTerrain::LevelGetDot(int x, int y, float min, float max, float slope)
+{
+ float hc, h[4];
+ int i;
+
+ hc = LevelRetHeight(x, y);
+ h[0] = LevelRetHeight(x+0, y+1);
+ h[1] = LevelRetHeight(x+1, y+0);
+ h[2] = LevelRetHeight(x+0, y-1);
+ h[3] = LevelRetHeight(x-1, y+0);
+
+ if ( hc < min ||
+ hc > max ) return FALSE;
+
+ if ( slope == 0.0f )
+ {
+ return TRUE;
+ }
+
+ if ( slope > 0.0f )
+ {
+ for ( i=0 ; i<4 ; i++ )
+ {
+ if ( Abs(hc-h[i]) >= slope )
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ if ( slope < 0.0f )
+ {
+ for ( i=0 ; i<4 ; i++ )
+ {
+ if ( Abs(hc-h[i]) < -slope )
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+// Cherche si un matériau existe.
+// Retourne l'index dans m_levelMat ou -1 s'il n'existe pas.
+// m_levelMat[i].id donne l'identificateur.
+
+int CTerrain::LevelTestMat(char *mat)
+{
+ int i;
+
+ for ( i=0 ; i<m_levelMatTotal ; i++ )
+ {
+ if ( m_levelMat[i].mat[0] == mat[0] &&
+ m_levelMat[i].mat[1] == mat[1] &&
+ m_levelMat[i].mat[2] == mat[2] &&
+ m_levelMat[i].mat[3] == mat[3] ) return i;
+ }
+
+ return -1;
+}
+
+// Modifie l'état d'un point et de ses 4 voisins, sans tester si
+// c'est possible.
+
+void CTerrain::LevelSetDot(int x, int y, int id, char *mat)
+{
+ TerrainMaterial* tm;
+ int i, ii;
+
+ tm = LevelSearchMat(id);
+ if ( tm == 0 ) return;
+
+ if ( tm->mat[0] != mat[0] ||
+ tm->mat[1] != mat[1] ||
+ tm->mat[2] != mat[2] ||
+ tm->mat[3] != mat[3] ) // id incompatible avec mat ?
+ {
+ ii = LevelTestMat(mat);
+ if ( ii == -1 ) return;
+ id = m_levelMat[ii].id; // cherche un id compatible avec mat
+ }
+
+ // Modifie le point.
+ m_levelDot[x+y*m_levelDotSize].id = id;
+ m_levelDot[x+y*m_levelDotSize].mat[0] = mat[0];
+ m_levelDot[x+y*m_levelDotSize].mat[1] = mat[1];
+ m_levelDot[x+y*m_levelDotSize].mat[2] = mat[2];
+ m_levelDot[x+y*m_levelDotSize].mat[3] = mat[3];
+
+ // Modifie le voisin inférieur.
+ if ( (x+0) >= 0 && (x+0) < m_levelDotSize &&
+ (y-1) >= 0 && (y-1) < m_levelDotSize )
+ {
+ i = (x+0)+(y-1)*m_levelDotSize;
+ if ( m_levelDot[i].mat[0] != mat[2] )
+ {
+ m_levelDot[i].mat[0] = mat[2];
+ ii = LevelTestMat(m_levelDot[i].mat);
+ if ( ii != -1 )
+ {
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+ }
+
+ // Modifie le voisin gauche.
+ if ( (x-1) >= 0 && (x-1) < m_levelDotSize &&
+ (y+0) >= 0 && (y+0) < m_levelDotSize )
+ {
+ i = (x-1)+(y+0)*m_levelDotSize;
+ if ( m_levelDot[i].mat[1] != mat[3] )
+ {
+ m_levelDot[i].mat[1] = mat[3];
+ ii = LevelTestMat(m_levelDot[i].mat);
+ if ( ii != -1 )
+ {
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+ }
+
+ // Modifie le voisin supérieur.
+ if ( (x+0) >= 0 && (x+0) < m_levelDotSize &&
+ (y+1) >= 0 && (y+1) < m_levelDotSize )
+ {
+ i = (x+0)+(y+1)*m_levelDotSize;
+ if ( m_levelDot[i].mat[2] != mat[0] )
+ {
+ m_levelDot[i].mat[2] = mat[0];
+ ii = LevelTestMat(m_levelDot[i].mat);
+ if ( ii != -1 )
+ {
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+ }
+
+ // Modifie le voisin droite.
+ if ( (x+1) >= 0 && (x+1) < m_levelDotSize &&
+ (y+0) >= 0 && (y+0) < m_levelDotSize )
+ {
+ i = (x+1)+(y+0)*m_levelDotSize;
+ if ( m_levelDot[i].mat[3] != mat[1] )
+ {
+ m_levelDot[i].mat[3] = mat[1];
+ ii = LevelTestMat(m_levelDot[i].mat);
+ if ( ii != -1 )
+ {
+ m_levelDot[i].id = m_levelMat[ii].id;
+ }
+ }
+ }
+}
+
+// Teste si un matériau est possible à un endroit donné, en fonction
+// de ses 4 voisins. Si oui, met le point.
+
+BOOL CTerrain::LevelIfDot(int x, int y, int id, char *mat)
+{
+ char test[4];
+
+ // Compatible avec voisin inférieur ?
+ if ( x+0 >= 0 && x+0 < m_levelDotSize &&
+ y-1 >= 0 && y-1 < m_levelDotSize )
+ {
+ test[0] = mat[2];
+ test[1] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[1];
+ test[2] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[2];
+ test[3] = m_levelDot[(x+0)+(y-1)*m_levelDotSize].mat[3];
+
+ if ( LevelTestMat(test) == -1 ) return FALSE;
+ }
+
+ // Compatible avec voisin gauche ?
+ if ( x-1 >= 0 && x-1 < m_levelDotSize &&
+ y+0 >= 0 && y+0 < m_levelDotSize )
+ {
+ test[0] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[0];
+ test[1] = mat[3];
+ test[2] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[2];
+ test[3] = m_levelDot[(x-1)+(y+0)*m_levelDotSize].mat[3];
+
+ if ( LevelTestMat(test) == -1 ) return FALSE;
+ }
+
+ // Compatible avec voisin supérieur ?
+ if ( x+0 >= 0 && x+0 < m_levelDotSize &&
+ y+1 >= 0 && y+1 < m_levelDotSize )
+ {
+ test[0] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[0];
+ test[1] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[1];
+ test[2] = mat[0];
+ test[3] = m_levelDot[(x+0)+(y+1)*m_levelDotSize].mat[3];
+
+ if ( LevelTestMat(test) == -1 ) return FALSE;
+ }
+
+ // Compatible avec voisin droite ?
+ if ( x+1 >= 0 && x+1 < m_levelDotSize &&
+ y+0 >= 0 && y+0 < m_levelDotSize )
+ {
+ test[0] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[0];
+ test[1] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[1];
+ test[2] = m_levelDot[(x+1)+(y+0)*m_levelDotSize].mat[2];
+ test[3] = mat[1];
+
+ if ( LevelTestMat(test) == -1 ) return FALSE;
+ }
+
+ LevelSetDot(x, y, id, mat); // met le point
+ return TRUE;
+}
+
+// Modifie l'état d'un point.
+
+BOOL CTerrain::LevelPutDot(int x, int y, int id)
+{
+ TerrainMaterial *tm;
+ char mat[4];
+ int up, right, down, left;
+
+ x /= m_brick/m_subdivMapping;
+ y /= m_brick/m_subdivMapping;
+
+ if ( x < 0 || x >= m_levelDotSize ||
+ y < 0 || y >= m_levelDotSize ) return FALSE;
+
+ tm = LevelSearchMat(id);
+ if ( tm == 0 ) return FALSE;
+
+ // Essaye sans modifier les voisins.
+ if ( LevelIfDot(x, y, id, tm->mat) ) return TRUE;
+
+ // Essaye en modifiant un seul voisin (4x).
+ for ( up=0 ; up<m_levelMatMax ; up++ )
+ {
+ mat[0] = up;
+ mat[1] = tm->mat[1];
+ mat[2] = tm->mat[2];
+ mat[3] = tm->mat[3];
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+
+ for ( right=0 ; right<m_levelMatMax ; right++ )
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = right;
+ mat[2] = tm->mat[2];
+ mat[3] = tm->mat[3];
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+
+ for ( down=0 ; down<m_levelMatMax ; down++ )
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = tm->mat[1];
+ mat[2] = down;
+ mat[3] = tm->mat[3];
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+
+ for ( left=0 ; left<m_levelMatMax ; left++ )
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = tm->mat[1];
+ mat[2] = tm->mat[2];
+ mat[3] = left;
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+
+ // Essaye en modifiant deux voisins (6x).
+ for ( up=0 ; up<m_levelMatMax ; up++ )
+ {
+ for ( down=0 ; down<m_levelMatMax ; down++ )
+ {
+ mat[0] = up;
+ mat[1] = tm->mat[1];
+ mat[2] = down;
+ mat[3] = tm->mat[3];
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+
+ for ( right=0 ; right<m_levelMatMax ; right++ )
+ {
+ for ( left=0 ; left<m_levelMatMax ; left++ )
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = right;
+ mat[2] = tm->mat[2];
+ mat[3] = left;
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+
+ for ( up=0 ; up<m_levelMatMax ; up++ )
+ {
+ for ( right=0 ; right<m_levelMatMax ; right++ )
+ {
+ mat[0] = up;
+ mat[1] = right;
+ mat[2] = tm->mat[2];
+ mat[3] = tm->mat[3];
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+
+ for ( right=0 ; right<m_levelMatMax ; right++ )
+ {
+ for ( down=0 ; down<m_levelMatMax ; down++ )
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = right;
+ mat[2] = down;
+ mat[3] = tm->mat[3];
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+
+ for ( down=0 ; down<m_levelMatMax ; down++ )
+ {
+ for ( left=0 ; left<m_levelMatMax ; left++ )
+ {
+ mat[0] = tm->mat[0];
+ mat[1] = tm->mat[1];
+ mat[2] = down;
+ mat[3] = left;
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+
+ for ( up=0 ; up<m_levelMatMax ; up++ )
+ {
+ for ( left=0 ; left<m_levelMatMax ; left++ )
+ {
+ mat[0] = up;
+ mat[1] = tm->mat[1];
+ mat[2] = tm->mat[2];
+ mat[3] = left;
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+
+ // Essaye en modifiant tous les voisins.
+ for ( up=0 ; up<m_levelMatMax ; up++ )
+ {
+ for ( right=0 ; right<m_levelMatMax ; right++ )
+ {
+ for ( down=0 ; down<m_levelMatMax ; down++ )
+ {
+ for ( left=0 ; left<m_levelMatMax ; left++ )
+ {
+ mat[0] = up;
+ mat[1] = right;
+ mat[2] = down;
+ mat[3] = left;
+
+ if ( LevelIfDot(x, y, id, mat) ) return TRUE;
+ }
+ }
+ }
+ }
+
+ OutputDebugString("LevelPutDot error\n");
+ return FALSE;
+}
+
+// Initialise tout le terrain avec un matériau.
+
+BOOL CTerrain::LevelInit(int id)
+{
+ TerrainMaterial* tm;
+ int i, j;
+
+ tm = LevelSearchMat(id);
+ if ( tm == 0 ) return FALSE;
+
+ for ( i=0 ; i<m_levelDotSize*m_levelDotSize ; i++ )
+ {
+ m_levelDot[i].id = id;
+
+ for ( j=0 ; j<4 ; j++ )
+ {
+ m_levelDot[i].mat[j] = tm->mat[j];
+ }
+ }
+
+ return TRUE;
+}
+
+// Génère un niveau dans le terrain.
+
+BOOL CTerrain::LevelGenerate(int *id, float min, float max,
+ float slope, float freq,
+ D3DVECTOR center, float radius)
+{
+ TerrainMaterial *tm;
+ D3DVECTOR pos;
+ int i, numID, x, y, xx, yy, group, rnd;
+ float dim;
+
+ static char random[100] =
+ {
+ 84,25,12, 6,34,52,85,38,97,16,
+ 21,31,65,19,62,40,72,22,48,61,
+ 56,47, 8,53,73,77, 4,91,26,88,
+ 76, 1,44,93,39,11,71,17,98,95,
+ 88,83,18,30, 3,57,28,49,74, 9,
+ 32,13,96,66,15,70,36,10,59,94,
+ 45,86, 2,29,63,42,51, 0,79,27,
+ 54, 7,20,69,89,23,64,43,81,92,
+ 90,33,46,14,67,35,50, 5,87,60,
+ 68,55,24,78,41,75,58,80,37,82,
+ };
+
+ i = 0;
+ while ( id[i] != 0 )
+ {
+ tm = LevelSearchMat(id[i++]);
+ if ( tm == 0 ) return FALSE;
+ }
+ numID = i;
+
+ group = m_brick/m_subdivMapping;
+
+ if ( radius > 0.0f && radius < 5.0f ) // juste un carré ?
+ {
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ xx = (int)((center.x+dim)/m_size);
+ yy = (int)((center.z+dim)/m_size);
+
+ x = xx/group;
+ y = yy/group;
+
+ tm = LevelSearchMat(id[0]);
+ if ( tm != 0 )
+ {
+ LevelSetDot(x, y, id[0], tm->mat); // met le point
+ }
+//? LevelPutDot(xx,yy, id[0]);
+ }
+ else
+ {
+ for ( y=0 ; y<m_levelDotSize ; y++ )
+ {
+ for ( x=0 ; x<m_levelDotSize ; x++ )
+ {
+ if ( radius != 0.0f )
+ {
+ pos.x = ((float)x-m_levelDotSize/2.0f)*group*m_size;
+ pos.z = ((float)y-m_levelDotSize/2.0f)*group*m_size;
+ if ( Length2d(pos, center) > radius ) continue;
+ }
+
+ if ( freq < 100.0f )
+ {
+ rnd = random[(x%10)+(y%10)*10];
+ if ( (float)rnd > freq ) continue;
+ }
+
+ xx = x*group + group/2;
+ yy = y*group + group/2;
+
+ if ( LevelGetDot(xx,yy, min, max, slope) )
+ {
+ rnd = random[(x%10)+(y%10)*10];
+ i = rnd%numID;
+ LevelPutDot(xx,yy, id[i]);
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+// Initialise une table des niveaux vide.
+
+void CTerrain::LevelOpenTable()
+{
+ int i, j;
+
+ if ( !m_bLevelText ) return;
+ if ( m_levelDot != 0 ) return; // déjà alloué
+
+ m_levelDotSize = (m_mosaic*m_brick)/(m_brick/m_subdivMapping)+1;
+ m_levelDot = (DotLevel*)malloc(m_levelDotSize*m_levelDotSize*sizeof(DotLevel));
+
+ for ( i=0 ; i<m_levelDotSize*m_levelDotSize ; i++ )
+ {
+ for ( j=0 ; j<4 ; j++ )
+ {
+ m_levelDot[i].mat[j] = 0;
+ }
+ }
+}
+
+// Ferme la table des niveaux.
+
+void CTerrain::LevelCloseTable()
+{
+ free(m_levelDot);
+ m_levelDot = 0;
+}
+
+
+
+// Crée tous les objets pour une maille carrée du terrain.
+
+BOOL CTerrain::CreateSquare(BOOL bMultiRes, int x, int y)
+{
+ D3DMATERIAL7 mat;
+ float min, max;
+ int step, objRank;
+
+ ZeroMemory( &mat, sizeof(D3DMATERIAL7) );
+ mat.diffuse.r = 1.0f;
+ mat.diffuse.g = 1.0f;
+ mat.diffuse.b = 1.0f;
+ mat.ambient.r = 0.0f;
+ mat.ambient.g = 0.0f;
+ mat.ambient.b = 0.0f;
+
+ objRank = m_engine->CreateObject();
+ m_engine->SetObjectType(objRank, TYPETERRAIN); // c'est un terrain
+
+ m_objRank[x+y*m_mosaic] = objRank;
+
+ if ( bMultiRes )
+ {
+ min = 0.0f;
+ max = m_vision;
+ max *= m_engine->RetClippingDistance();
+ for ( step=0 ; step<m_depth ; step++ )
+ {
+ CreateMosaic(x, y, 1<<step, objRank, mat, min, max);
+ min = max;
+ max *= 2;
+ if ( step == m_depth-1 ) max = g_HUGE;
+ }
+ }
+ else
+ {
+ CreateMosaic(x, y, 1, objRank, mat, 0.0f, g_HUGE);
+ }
+
+ return TRUE;
+}
+
+// Crée tous les objets du terrain dans le moteur 3D.
+
+BOOL CTerrain::CreateObjects(BOOL bMultiRes)
+{
+ int x, y;
+
+ AdjustRelief();
+
+ for ( y=0 ; y<m_mosaic ; y++ )
+ {
+ for ( x=0 ; x<m_mosaic ; x++ )
+ {
+ CreateSquare(bMultiRes, x, y);
+ }
+ }
+
+ return TRUE;
+}
+
+
+// Modifie le relief du terrain.
+// ATTENTION: ok seulement avec m_depth = 2 !
+
+BOOL CTerrain::Terraform(const D3DVECTOR &p1, const D3DVECTOR &p2, float height)
+{
+ POINT tp1, tp2, pp1, pp2;
+ float dim, avg;
+ int x, y, size, nb;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+ tp1.x = (int)((p1.x+dim+m_size/2.0f)/m_size);
+ tp1.y = (int)((p1.z+dim+m_size/2.0f)/m_size);
+ tp2.x = (int)((p2.x+dim+m_size/2.0f)/m_size);
+ tp2.y = (int)((p2.z+dim+m_size/2.0f)/m_size);
+
+ if ( tp1.x > tp2.x )
+ {
+ x = tp1.x;
+ tp1.x = tp2.x;
+ tp2.x = x;
+ }
+
+ if ( tp1.y > tp2.y )
+ {
+ y = tp1.y;
+ tp1.y = tp2.y;
+ tp2.y = y;
+ }
+
+ size = (m_mosaic*m_brick)+1;
+
+ // Calcule la hauteur moyenne actuelle.
+ avg = 0.0f;
+ nb = 0;
+ for ( y=tp1.y ; y<=tp2.y ; y++ )
+ {
+ for ( x=tp1.x ; x<=tp2.x ; x++ )
+ {
+ avg += m_relief[x+y*size];
+ nb ++;
+ }
+ }
+ avg /= (float)nb;
+
+ // Modifie la description du relief.
+ for ( y=tp1.y ; y<=tp2.y ; y++ )
+ {
+ for ( x=tp1.x ; x<=tp2.x ; x++ )
+ {
+ m_relief[x+y*size] = avg+height;
+
+ if ( x%m_brick == 0 && y%m_depth != 0 )
+ {
+ m_relief[(x+0)+(y-1)*size] = avg+height;
+ m_relief[(x+0)+(y+1)*size] = avg+height;
+ }
+
+ if ( y%m_brick == 0 && x%m_depth != 0 )
+ {
+ m_relief[(x-1)+(y+0)*size] = avg+height;
+ m_relief[(x+1)+(y+0)*size] = avg+height;
+ }
+ }
+ }
+ AdjustRelief();
+
+ pp1.x = (tp1.x-2)/m_brick;
+ pp1.y = (tp1.y-2)/m_brick;
+ pp2.x = (tp2.x+1)/m_brick;
+ pp2.y = (tp2.y+1)/m_brick;
+
+ if ( pp1.x < 0 ) pp1.x = 0;
+ if ( pp1.x >= m_mosaic ) pp1.x = m_mosaic-1;
+ if ( pp1.y < 0 ) pp1.y = 0;
+ if ( pp1.y >= m_mosaic ) pp1.y = m_mosaic-1;
+
+ for ( y=pp1.y ; y<=pp2.y ; y++ )
+ {
+ for ( x=pp1.x ; x<=pp2.x ; x++ )
+ {
+ m_engine->DeleteObject(m_objRank[x+y*m_mosaic]);
+ CreateSquare(m_bMultiText, x, y); // recrée le carré
+ }
+ }
+ m_engine->Update();
+
+ return TRUE;
+}
+
+
+// Gestion du vent.
+
+void CTerrain::SetWind(D3DVECTOR speed)
+{
+ m_wind = speed;
+}
+
+D3DVECTOR CTerrain::RetWind()
+{
+ return m_wind;
+}
+
+
+// Donne la pente exacte du terrain à un endroit donné.
+
+float CTerrain::RetFineSlope(const D3DVECTOR &pos)
+{
+ D3DVECTOR n;
+
+ if ( !GetNormal(n, pos) ) return 0.0f;
+ return Abs(RotateAngle(Length(n.x, n.z), n.y)-PI/2.0f);
+}
+
+// Donne la pente approximative du terrain à un endroit donné.
+
+float CTerrain::RetCoarseSlope(const D3DVECTOR &pos)
+{
+ float dim, level[4], min, max;
+ int x, y;
+
+ if ( m_relief == 0 ) return 0.0f;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ x = (int)((pos.x+dim)/m_size);
+ y = (int)((pos.z+dim)/m_size);
+
+ if ( x < 0 || x >= m_mosaic*m_brick ||
+ y < 0 || y >= m_mosaic*m_brick ) return 0.0f;
+
+ level[0] = m_relief[(x+0)+(y+0)*(m_mosaic*m_brick+1)];
+ level[1] = m_relief[(x+1)+(y+0)*(m_mosaic*m_brick+1)];
+ level[2] = m_relief[(x+0)+(y+1)*(m_mosaic*m_brick+1)];
+ level[3] = m_relief[(x+1)+(y+1)*(m_mosaic*m_brick+1)];
+
+ min = Min(level[0], level[1], level[2], level[3]);
+ max = Max(level[0], level[1], level[2], level[3]);
+
+ return atanf((max-min)/m_size);
+}
+
+// Donne le vecteur normal à la position p(x,-,z) du terrain.
+
+BOOL CTerrain::GetNormal(D3DVECTOR &n, const D3DVECTOR &p)
+{
+ D3DVECTOR p1, p2, p3, p4;
+ float dim;
+ int x, y;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ x = (int)((p.x+dim)/m_size);
+ y = (int)((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return FALSE;
+
+ p1 = RetVector(x+0, y+0);
+ p2 = RetVector(x+1, y+0);
+ p3 = RetVector(x+0, y+1);
+ p4 = RetVector(x+1, y+1);
+
+ if ( Abs(p.z-p2.z) < Abs(p.x-p2.x) )
+ {
+ n = ComputeNormal(p1,p2,p3);
+ }
+ else
+ {
+ n = ComputeNormal(p2,p4,p3);
+ }
+ return TRUE;
+}
+
+// Retourne la hauteur du sol.
+
+float CTerrain::RetFloorLevel(const D3DVECTOR &p, BOOL bBrut, BOOL bWater)
+{
+ D3DVECTOR p1, p2, p3, p4, ps;
+ float dim, level;
+ int x, y;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ x = (int)((p.x+dim)/m_size);
+ y = (int)((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return FALSE;
+
+ p1 = RetVector(x+0, y+0);
+ p2 = RetVector(x+1, y+0);
+ p3 = RetVector(x+0, y+1);
+ p4 = RetVector(x+1, y+1);
+
+ ps = p;
+ if ( Abs(p.z-p2.z) < Abs(p.x-p2.x) )
+ {
+ if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f;
+ }
+ else
+ {
+ if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f;
+ }
+
+ if ( !bBrut ) AdjustBuildingLevel(ps);
+
+ if ( bWater ) // ne va pas sous l'eau ?
+ {
+ level = m_water->RetLevel();
+ if ( ps.y < level ) ps.y = level; // pas sous l'eau
+ }
+
+ return ps.y;
+}
+
+// Retourne la hauteur jusqu'au sol. Cette hauteur est positive
+// lorsqu'on est au-dessus du sol.
+
+float CTerrain::RetFloorHeight(const D3DVECTOR &p, BOOL bBrut, BOOL bWater)
+{
+ D3DVECTOR p1, p2, p3, p4, ps;
+ float dim, level;
+ int x, y;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ x = (int)((p.x+dim)/m_size);
+ y = (int)((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return FALSE;
+
+ p1 = RetVector(x+0, y+0);
+ p2 = RetVector(x+1, y+0);
+ p3 = RetVector(x+0, y+1);
+ p4 = RetVector(x+1, y+1);
+
+ ps = p;
+ if ( Abs(p.z-p2.z) < Abs(p.x-p2.x) )
+ {
+ if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f;
+ }
+ else
+ {
+ if ( !IntersectY(p2, p4, p3, ps) ) return 0.0f;
+ }
+
+ if ( !bBrut ) AdjustBuildingLevel(ps);
+
+ if ( bWater ) // ne va pas sous l'eau ?
+ {
+ level = m_water->RetLevel();
+ if ( ps.y < level ) ps.y = level; // pas sous l'eau
+ }
+
+ return p.y-ps.y;
+}
+
+// Modifie la coordonnée "y" du point "p" pour qu'il repose
+// sur le sol du terrain.
+
+BOOL CTerrain::MoveOnFloor(D3DVECTOR &p, BOOL bBrut, BOOL bWater)
+{
+ D3DVECTOR p1, p2, p3, p4;
+ float dim, level;
+ int x, y;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ x = (int)((p.x+dim)/m_size);
+ y = (int)((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return FALSE;
+
+ p1 = RetVector(x+0, y+0);
+ p2 = RetVector(x+1, y+0);
+ p3 = RetVector(x+0, y+1);
+ p4 = RetVector(x+1, y+1);
+
+ if ( Abs(p.z-p2.z) < Abs(p.x-p2.x) )
+ {
+ if ( !IntersectY(p1, p2, p3, p) ) return FALSE;
+ }
+ else
+ {
+ if ( !IntersectY(p2, p4, p3, p) ) return FALSE;
+ }
+
+ if ( !bBrut ) AdjustBuildingLevel(p);
+
+ if ( bWater ) // ne va pas sous l'eau ?
+ {
+ level = m_water->RetLevel();
+ if ( p.y < level ) p.y = level; // pas sous l'eau
+ }
+
+ return TRUE;
+}
+
+// Modifie une coordonnée pour qu'elle soit sur le terrain.
+// Retourne FALSE si la coordonnée initiale était trop loin.
+
+BOOL CTerrain::ValidPosition(D3DVECTOR &p, float marging)
+{
+ BOOL bOK = TRUE;
+ float limit;
+
+ limit = m_mosaic*m_brick*m_size/2.0f - marging;
+
+ if ( p.x < -limit )
+ {
+ p.x = -limit;
+ bOK = FALSE;
+ }
+
+ if ( p.z < -limit )
+ {
+ p.z = -limit;
+ bOK = FALSE;
+ }
+
+ if ( p.x > limit )
+ {
+ p.x = limit;
+ bOK = FALSE;
+ }
+
+ if ( p.z > limit )
+ {
+ p.z = limit;
+ bOK = FALSE;
+ }
+
+ return bOK;
+}
+
+
+
+// Vide la table des élévations.
+
+void CTerrain::FlushBuildingLevel()
+{
+ m_buildingUsed = 0;
+}
+
+// Ajoute une nouvelle élévation pour un batiment.
+
+BOOL CTerrain::AddBuildingLevel(D3DVECTOR center, float min, float max,
+ float height, float factor)
+{
+ int i;
+
+ for ( i=0 ; i<m_buildingUsed ; i++ )
+ {
+ if ( center.x == m_buildingTable[i].center.x &&
+ center.z == m_buildingTable[i].center.z )
+ {
+ goto update;
+ }
+ }
+
+ if ( m_buildingUsed >= MAXBUILDINGLEVEL ) return FALSE;
+ i = m_buildingUsed++;
+
+ update:
+ m_buildingTable[i].center = center;
+ m_buildingTable[i].min = min;
+ m_buildingTable[i].max = max;
+ m_buildingTable[i].level = RetFloorLevel(center, TRUE);
+ m_buildingTable[i].height = height;
+ m_buildingTable[i].factor = factor;
+ m_buildingTable[i].bboxMinX = center.x-max;
+ m_buildingTable[i].bboxMaxX = center.x+max;
+ m_buildingTable[i].bboxMinZ = center.z-max;
+ m_buildingTable[i].bboxMaxZ = center.z+max;
+
+ return TRUE;
+}
+
+// Met à jour l'élévation pour un batiment lorsqu'il a été déplacé
+// en hauteur (suite à un terraformage).
+
+BOOL CTerrain::UpdateBuildingLevel(D3DVECTOR center)
+{
+ int i;
+
+ for ( i=0 ; i<m_buildingUsed ; i++ )
+ {
+ if ( center.x == m_buildingTable[i].center.x &&
+ center.z == m_buildingTable[i].center.z )
+ {
+ m_buildingTable[i].center = center;
+ m_buildingTable[i].level = RetFloorLevel(center, TRUE);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Supprime l'élévation pour un batiment lorsqu'il a été détruit.
+
+BOOL CTerrain::DeleteBuildingLevel(D3DVECTOR center)
+{
+ int i, j;
+
+ for ( i=0 ; i<m_buildingUsed ; i++ )
+ {
+ if ( center.x == m_buildingTable[i].center.x &&
+ center.z == m_buildingTable[i].center.z )
+ {
+ for ( j=i+1 ; j<m_buildingUsed ; j++ )
+ {
+ m_buildingTable[j-1] = m_buildingTable[j];
+ }
+ m_buildingUsed --;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Retourne le facteur d'influence si une position est sur une
+// élévation éventuelle.
+
+float CTerrain::RetBuildingFactor(const D3DVECTOR &p)
+{
+ float dist;
+ int i;
+
+ for ( i=0 ; i<m_buildingUsed ; i++ )
+ {
+ if ( p.x < m_buildingTable[i].bboxMinX ||
+ p.x > m_buildingTable[i].bboxMaxX ||
+ p.z < m_buildingTable[i].bboxMinZ ||
+ p.z > m_buildingTable[i].bboxMaxZ ) continue;
+
+ dist = Length2d(p, m_buildingTable[i].center);
+
+ if ( dist <= m_buildingTable[i].max )
+ {
+ return m_buildingTable[i].factor;
+ }
+ }
+ return 1.0f; // on est sur le sol normnal
+}
+
+// Ajuste une position en fonction d'une élévation éventuelle.
+
+void CTerrain::AdjustBuildingLevel(D3DVECTOR &p)
+{
+ D3DVECTOR border;
+ float dist, base;
+ int i;
+
+ for ( i=0 ; i<m_buildingUsed ; i++ )
+ {
+ if ( p.x < m_buildingTable[i].bboxMinX ||
+ p.x > m_buildingTable[i].bboxMaxX ||
+ p.z < m_buildingTable[i].bboxMinZ ||
+ p.z > m_buildingTable[i].bboxMaxZ ) continue;
+
+ dist = Length2d(p, m_buildingTable[i].center);
+
+ if ( dist > m_buildingTable[i].max ) continue;
+
+ if ( dist < m_buildingTable[i].min )
+ {
+ p.y = m_buildingTable[i].level+m_buildingTable[i].height;
+ return;
+ }
+
+#if 0
+ p.y = m_buildingTable[i].level;
+ p.y += (m_buildingTable[i].max-dist)/
+ (m_buildingTable[i].max-m_buildingTable[i].min)*
+ m_buildingTable[i].height;
+
+ base = RetFloorLevel(p, TRUE);
+ if ( p.y < base ) p.y = base;
+#else
+ border.x = ((p.x-m_buildingTable[i].center.x)*m_buildingTable[i].max)/
+ dist+m_buildingTable[i].center.x;
+ border.z = ((p.z-m_buildingTable[i].center.z)*m_buildingTable[i].max)/
+ dist+m_buildingTable[i].center.z;
+
+ base = RetFloorLevel(border, TRUE);
+
+ p.y = (m_buildingTable[i].max-dist)/
+ (m_buildingTable[i].max-m_buildingTable[i].min)*
+ (m_buildingTable[i].level+m_buildingTable[i].height-base)+
+ base;
+#endif
+ return;
+ }
+}
+
+
+// Retourne la dureté du terrain à un endroit donné.
+// La dureté détermine le bruit (SOUND_STEP et SOUND_BOUM).
+
+float CTerrain::RetHardness(const D3DVECTOR &p)
+{
+ TerrainMaterial* tm;
+ float factor, dim;
+ int x, y, id;
+
+ factor = RetBuildingFactor(p);
+ if ( factor != 1.0f ) return 1.0f; // sur bâtiment
+
+ if ( m_levelDot == 0 ) return m_defHardness;
+
+ dim = (m_mosaic*m_brick*m_size)/2.0f;
+
+ x = (int)((p.x+dim)/m_size);
+ y = (int)((p.z+dim)/m_size);
+
+ if ( x < 0 || x > m_mosaic*m_brick ||
+ y < 0 || y > m_mosaic*m_brick ) return m_defHardness;
+
+ x /= m_brick/m_subdivMapping;
+ y /= m_brick/m_subdivMapping;
+
+ if ( x < 0 || x >= m_levelDotSize ||
+ y < 0 || y >= m_levelDotSize ) return m_defHardness;
+
+ id = m_levelDot[x+y*m_levelDotSize].id;
+ tm = LevelSearchMat(id);
+ if ( tm == 0 ) return m_defHardness;
+
+ return tm->hardness;
+}
+
+
+// Montre les zones plates sur le terrain.
+
+void CTerrain::GroundFlat(D3DVECTOR pos)
+{
+ D3DVECTOR p;
+ float rapport, angle;
+ int x, y, i;
+ static char table[41*41];
+
+
+ rapport = 3200.0f/1024.0f;
+
+ for ( y=0 ; y<=40 ; y++ )
+ {
+ for ( x=0 ; x<=40 ; x++ )
+ {
+ i = x + y*41;
+ table[i] = 0;
+
+ p.x = (x-20)*rapport;
+ p.z = (y-20)*rapport;
+ p.y = 0.0f;
+ if ( Length(p.x, p.y) > 20.0f*rapport ) continue;
+
+ angle = RetFineSlope(pos+p);
+
+ if ( angle < FLATLIMIT )
+ {
+ table[i] = 1;
+ }
+ else
+ {
+ table[i] = 2;
+ }
+ }
+ }
+
+ m_engine->GroundMarkCreate(pos, 40.0f, 0.001f, 15.0f, 0.001f, 41, 41, table);
+}
+
+
+// Calcule le rayon de la plus grande zone platte disponible.
+// Ce calcul n'est pas optimisé !
+
+float CTerrain::RetFlatZoneRadius(D3DVECTOR center, float max)
+{
+ D3DVECTOR pos;
+ FPOINT c, p;
+ float ref, radius, angle, h;
+ int i, nb;
+
+ angle = RetFineSlope(center);
+ if ( angle >= FLATLIMIT ) return 0.0f;
+
+ ref = RetFloorLevel(center, TRUE);
+
+ radius = 1.0f;
+ while ( radius <= max )
+ {
+ angle = 0.0f;
+ nb = (int)(2.0f*PI*radius);
+ if ( nb < 8 ) nb = 8;
+ for ( i=0 ; i<nb ; i++ )
+ {
+ c.x = center.x;
+ c.y = center.z;
+ p.x = center.x+radius;
+ p.y = center.z;
+ p = RotatePoint(c, angle, p);
+ pos.x = p.x;
+ pos.z = p.y;
+ h = RetFloorLevel(pos, TRUE);
+ if ( Abs(h-ref) > 1.0f ) return radius;
+
+ angle += PI*2.0f/8.0f;
+ }
+ radius += 1.0f;
+ }
+ return max;
+}
+
+
+
+// Spécifie la hauteur maximale de vol.
+
+void CTerrain::SetFlyingMaxHeight(float height)
+{
+ m_flyingMaxHeight = height;
+}
+
+// Retourne la hauteur maximale de vol.
+
+float CTerrain::RetFlyingMaxHeight()
+{
+ return m_flyingMaxHeight;
+}
+
+
+// Vide la table des limites de vol.
+
+void CTerrain::FlushFlyingLimit()
+{
+ m_flyingMaxHeight = 280.0f;
+ m_flyingLimitTotal = 0;
+}
+
+// Vide la table des limites de vol.
+
+BOOL CTerrain::AddFlyingLimit(D3DVECTOR center,
+ float extRadius, float intRadius,
+ float maxHeight)
+{
+ int i;
+
+ if ( m_flyingLimitTotal >= MAXFLYINGLIMIT ) return FALSE;
+
+ i = m_flyingLimitTotal;
+ m_flyingLimit[i].center = center;
+ m_flyingLimit[i].extRadius = extRadius;
+ m_flyingLimit[i].intRadius = intRadius;
+ m_flyingLimit[i].maxHeight = maxHeight;
+ m_flyingLimitTotal = i+1;
+
+ return TRUE;
+}
+
+// Retourne la hauteur maximale de vol.
+
+float CTerrain::RetFlyingLimit(D3DVECTOR pos, BOOL bNoLimit)
+{
+ float dist, h;
+ int i;
+
+ if ( bNoLimit ) return 280.0f;
+ if ( m_flyingLimitTotal == 0 ) return m_flyingMaxHeight;
+
+ for ( i=0 ; i<m_flyingLimitTotal ; i++ )
+ {
+ dist = Length2d(pos, m_flyingLimit[i].center);
+
+ if ( dist >= m_flyingLimit[i].extRadius ) continue;
+
+ if ( dist <= m_flyingLimit[i].intRadius )
+ {
+ return m_flyingLimit[i].maxHeight;
+ }
+
+ dist -= m_flyingLimit[i].intRadius;
+
+ h = dist*(m_flyingMaxHeight-m_flyingLimit[i].maxHeight)/
+ (m_flyingLimit[i].extRadius-m_flyingLimit[i].intRadius);
+
+ return h + m_flyingLimit[i].maxHeight;
+ }
+
+ return m_flyingMaxHeight;
+}
+
diff --git a/src/terrain.h b/src/terrain.h
new file mode 100644
index 0000000..f8f7435
--- /dev/null
+++ b/src/terrain.h
@@ -0,0 +1,195 @@
+// terrain.h
+
+#ifndef _TERRAIN_H_
+#define _TERRAIN_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CWater;
+
+
+
+#define FLATLIMIT (5.0f*PI/180.0f)
+
+
+enum TerrainRes
+{
+ TR_NULL = 0,
+ TR_STONE = 1,
+ TR_URANIUM = 2,
+ TR_POWER = 3,
+ TR_KEYa = 4,
+ TR_KEYb = 5,
+ TR_KEYc = 6,
+ TR_KEYd = 7,
+};
+
+
+#define MAXBUILDINGLEVEL 100
+
+typedef struct
+{
+ D3DVECTOR center;
+ float factor;
+ float min;
+ float max;
+ float level;
+ float height;
+ float bboxMinX;
+ float bboxMaxX;
+ float bboxMinZ;
+ float bboxMaxZ;
+}
+BuildingLevel;
+
+
+#define MAXMATTERRAIN 100
+
+typedef struct
+{
+ short id;
+ char texName[20];
+ float u,v;
+ float hardness;
+ char mat[4]; // up, right, down, left
+}
+TerrainMaterial;
+
+typedef struct
+{
+ short id;
+ char mat[4]; // up, right, down, left
+}
+DotLevel;
+
+
+#define MAXFLYINGLIMIT 10
+
+typedef struct
+{
+ D3DVECTOR center;
+ float extRadius;
+ float intRadius;
+ float maxHeight;
+}
+FlyingLimit;
+
+
+
+class CTerrain
+{
+public:
+ CTerrain(CInstanceManager* iMan);
+ ~CTerrain();
+
+ BOOL Generate(int mosaic, int brickP2, float size, float vision, int depth, float hardness);
+ BOOL InitTextures(char* baseName, int* table, int dx, int dy);
+ void LevelFlush();
+ BOOL LevelMaterial(int id, char* baseName, float u, float v, int up, int right, int down, int left, float hardness);
+ BOOL LevelInit(int id);
+ BOOL LevelGenerate(int *id, float min, float max, float slope, float freq, D3DVECTOR center, float radius);
+ void FlushRelief();
+ BOOL ReliefFromBMP(const char* filename, float scaleRelief, BOOL adjustBorder);
+ BOOL ReliefFromDXF(const char* filename, float scaleRelief);
+ BOOL ResFromBMP(const char* filename);
+ BOOL CreateObjects(BOOL bMultiRes);
+ BOOL Terraform(const D3DVECTOR &p1, const D3DVECTOR &p2, float height);
+
+ void SetWind(D3DVECTOR speed);
+ D3DVECTOR RetWind();
+
+ float RetFineSlope(const D3DVECTOR &pos);
+ float RetCoarseSlope(const D3DVECTOR &pos);
+ BOOL GetNormal(D3DVECTOR &n, const D3DVECTOR &p);
+ float RetFloorLevel(const D3DVECTOR &p, BOOL bBrut=FALSE, BOOL bWater=FALSE);
+ float RetFloorHeight(const D3DVECTOR &p, BOOL bBrut=FALSE, BOOL bWater=FALSE);
+ BOOL MoveOnFloor(D3DVECTOR &p, BOOL bBrut=FALSE, BOOL bWater=FALSE);
+ BOOL ValidPosition(D3DVECTOR &p, float marging);
+ TerrainRes RetResource(const D3DVECTOR &p);
+ void LimitPos(D3DVECTOR &pos);
+
+ void FlushBuildingLevel();
+ BOOL AddBuildingLevel(D3DVECTOR center, float min, float max, float height, float factor);
+ BOOL UpdateBuildingLevel(D3DVECTOR center);
+ BOOL DeleteBuildingLevel(D3DVECTOR center);
+ float RetBuildingFactor(const D3DVECTOR &p);
+ float RetHardness(const D3DVECTOR &p);
+
+ int RetMosaic();
+ int RetBrick();
+ float RetSize();
+ float RetScaleRelief();
+
+ void GroundFlat(D3DVECTOR pos);
+ float RetFlatZoneRadius(D3DVECTOR center, float max);
+
+ void SetFlyingMaxHeight(float height);
+ float RetFlyingMaxHeight();
+ void FlushFlyingLimit();
+ BOOL AddFlyingLimit(D3DVECTOR center, float extRadius, float intRadius, float maxHeight);
+ float RetFlyingLimit(D3DVECTOR pos, BOOL bNoLimit);
+
+protected:
+ BOOL ReliefAddDot(D3DVECTOR pos, float scaleRelief);
+ void AdjustRelief();
+ D3DVECTOR RetVector(int x, int y);
+ D3DVERTEX2 RetVertex(int x, int y, int step);
+ BOOL CreateMosaic(int ox, int oy, int step, int objRank, const D3DMATERIAL7 &mat, float min, float max);
+ BOOL CreateSquare(BOOL bMultiRes, int x, int y);
+
+ TerrainMaterial* LevelSearchMat(int id);
+ void LevelTextureName(int x, int y, char *name, FPOINT &uv);
+ float LevelRetHeight(int x, int y);
+ BOOL LevelGetDot(int x, int y, float min, float max, float slope);
+ int LevelTestMat(char *mat);
+ void LevelSetDot(int x, int y, int id, char *mat);
+ BOOL LevelIfDot(int x, int y, int id, char *mat);
+ BOOL LevelPutDot(int x, int y, int id);
+ void LevelOpenTable();
+ void LevelCloseTable();
+
+ void AdjustBuildingLevel(D3DVECTOR &p);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ CWater* m_water;
+
+ int m_mosaic; // nb de mosaïque
+ int m_brick; // nb de briques par mosaïque
+ float m_size; // taille d'un élément dans une brique
+ float m_vision; // vision avant un changement de résolution
+ float* m_relief; // table du relief
+ int* m_texture; // table des textures
+ int* m_objRank; // table des rangs des objets
+ BOOL m_bMultiText;
+ BOOL m_bLevelText;
+ float m_scaleMapping; // échelle du mapping
+ float m_scaleRelief;
+ int m_subdivMapping;
+ int m_depth; // nb de résolutions différentes (1,2,3,4)
+ char m_texBaseName[20];
+ char m_texBaseExt[10];
+ float m_defHardness;
+
+ TerrainMaterial m_levelMat[MAXMATTERRAIN+1];
+ int m_levelMatTotal;
+ int m_levelMatMax;
+ int m_levelDotSize;
+ DotLevel* m_levelDot;
+ int m_levelID;
+
+ int m_buildingUsed;
+ BuildingLevel m_buildingTable[MAXBUILDINGLEVEL];
+
+ unsigned char* m_resources;
+ D3DVECTOR m_wind; // vitesse du vent
+
+ float m_flyingMaxHeight;
+ int m_flyingLimitTotal;
+ FlyingLimit m_flyingLimit[MAXFLYINGLIMIT];
+};
+
+
+#endif //_TERRAIN_H_
diff --git a/src/text.cpp b/src/text.cpp
new file mode 100644
index 0000000..12c6c37
--- /dev/null
+++ b/src/text.cpp
@@ -0,0 +1,1865 @@
+// text.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "text.h"
+
+
+
+static short table_text_colobot[] =
+{
+// x1, y1, x2, y2
+ 219,34, 225,50, // 0
+ 1,188, 9,203, // .
+ 51,188,59,203, // carré
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 11,188,19,203, // \t
+ 21,188,29,203, // \n
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50, // \r
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 41,188,49,203, // >
+ 31,188,39,203, // <
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+#if _NEWLOOK
+ 0, 0, 4, 16, // 32
+ 7, 0, 9, 16, // !
+ 9, 0, 13, 16, // "
+ 13, 0, 24, 16, // #
+ 24, 0, 31, 16, // $
+ 31, 0, 43, 16, // %
+ 43, 0, 54, 16, // &
+ 54, 0, 56, 16, // '
+ 56, 0, 61, 16, // (
+ 61, 0, 67, 16, // )
+ 67, 0, 73, 16, // *
+ 73, 0, 83, 16, // +
+ 83, 0, 87, 16, // ,
+ 87, 0, 92, 16, // -
+ 92, 0, 94, 16, // .
+ 94, 0, 101,16, // /
+ 101,0, 109,16, // 0
+ 109,0, 114,16, // 1
+ 114,0, 122,16, // 2
+ 122,0, 129,16, // 3
+ 129,0, 138,16, // 4
+ 138,0, 146,16, // 5
+ 146,0, 154,16, // 6
+ 154,0, 161,16, // 7
+ 161,0, 169,16, // 8
+ 169,0, 177,16, // 9
+ 177,0, 179,16, // :
+ 179,0, 183,16, // ;
+ 183,0, 193,16, // <
+ 193,0, 203,16, // =
+ 203,0, 213,16, // >
+ 213,0, 219,16, // ?
+
+ 0, 17, 14, 33, // @ 64
+ 14, 17, 26, 33, // A
+ 26, 17, 33, 33, // B
+ 33, 17, 42, 33, // C
+ 42, 17, 51, 33, // D
+ 51, 17, 58, 33, // E
+ 58, 17, 63, 33, // F
+ 63, 17, 73, 33, // G
+ 73, 17, 82, 33, // H
+ 82, 17, 84, 33, // I
+ 84, 17, 90, 33, // J
+ 90, 17, 98, 33, // K
+ 98, 17, 103,33, // L
+ 103,17, 115,33, // M
+ 115,17, 124,33, // N
+ 124,17, 136,33, // O
+ 136,17, 142,33, // P
+ 142,17, 154,33, // Q
+ 154,17, 160,33, // R
+ 160,17, 167,33, // S
+ 167,17, 175,33, // T
+ 175,17, 183,33, // U
+ 183,17, 194,33, // V
+ 194,17, 208,33, // W
+ 208,17, 218,33, // X
+ 218,17, 227,33, // Y
+ 227,17, 236,33, // Z
+ 236,17, 241,33, // [
+ 241,17, 248,33, // \
+ 248,17, 252,33, // ]
+ 219,0, 229,16, // ^
+ 0, 34, 9, 50, // _
+
+ 54, 0, 56, 16, // ` 96
+ 9, 34, 16, 50, // a
+ 16, 34, 25, 50, // b
+ 25, 34, 33, 50, // c
+ 33, 34, 42, 50, // d
+ 42, 34, 50, 50, // e
+ 50, 34, 55, 50, // f
+ 55, 34, 62, 50, // g
+ 62, 34, 69, 50, // h
+ 69, 34, 71, 50, // i
+ 71, 34, 75, 50, // j
+ 75, 34, 81, 50, // k
+ 81, 34, 83, 50, // l
+ 83, 34, 93, 50, // m
+ 93, 34, 100,50, // n
+ 100,34, 109,50, // o
+ 109,34, 118,50, // p
+ 118,34, 127,50, // q
+ 127,34, 132,50, // r
+ 132,34, 138,50, // s
+ 138,34, 143,50, // t
+ 143,34, 150,50, // u
+ 150,34, 158,50, // v
+ 158,34, 171,50, // w
+ 171,34, 179,50, // x
+ 179,34, 187,50, // y
+ 187,34, 195,50, // z
+ 195,34, 201,50, // {
+ 201,34, 203,50, // |
+ 203,34, 209,50, // }
+ 209,34, 219,50, // ~
+ 219,34, 228,50, //
+
+ 219,34, 225,50, // 128
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 144
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 160
+ 219,34, 225,50, // 161 A1 ! inversé
+ 219,34, 225,50,
+ 219,34, 225,50, // 163 A3 £
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 0, 0, 4, 16, // 166 A6 ¦ (cadratin)
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 176
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50, // 191 BF ? inversé
+
+ 12, 51, 24, 67, // 192 C0 à maj
+ 0, 51, 12, 67, // 193 C1 á maj
+ 24, 51, 36, 67, // 194 C2 â maj
+ 48, 51, 60, 67, // 195 C3 ã maj
+ 36, 51, 48, 67, // 196 C4 ä maj
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 60, 51, 69, 67, // 199 C7 ç maj
+ 77, 51, 84, 67, // 200 C8 è maj
+ 70, 51, 77, 67, // 201 C9 é maj
+ 85, 51, 92, 67, // 202 CA ê maj
+ 93, 51, 100,67, // 203 CB ë maj
+ 219,34, 225,50,
+ 100,51, 104,67, // 205 CD í maj
+ 108,51, 113,67, // 206 CE î maj
+ 113,51, 117,67, // 207 CF ï maj
+
+ 219,34, 225,50, // 208
+ 117,51, 126,67, // 209 D1 ñ maj
+ 219,34, 225,50,
+ 126,51, 138,67, // 211 D3 ó maj
+ 150,51, 162,67, // 212 D4 ô maj
+ 219,34, 225,50,
+ 162,51, 174,67, // 214 D6 ö maj
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 194,51, 202,67, // 217 D9 ù maj
+ 186,51, 194,67, // 218 DA ú maj
+ 202,51, 210,67, // 219 DB û maj
+ 210,51, 218,67, // 220 DC ü maj
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 218,51, 227,67, // 223 DF ss allemand
+
+ 7, 68, 14, 84, // 224 E0 à min
+ 0, 68, 7, 84, // 225 E1 á min
+ 14, 68, 21, 84, // 226 E2 â min
+ 28, 68, 35, 84, // 227 E3 ã min
+ 21, 68, 28, 84, // 228 E4 ä min
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 35, 68, 43, 84, // 231 E7 ç min
+ 51, 68, 59, 84, // 232 E8 è min
+ 43, 68, 51, 84, // 233 E9 é min
+ 59, 68, 67, 84, // 234 EA ê min
+ 67, 68, 75, 84, // 235 EB ë min
+ 219,34, 225,50,
+ 75, 68, 79, 84, // 237 ED í min
+ 83, 68, 88, 84, // 238 EE î min
+ 88, 68, 92, 84, // 239 EF ï min
+
+ 219,34, 225,50, // 240
+ 92, 68, 99, 84, // 241 F1 ñ min
+ 219,34, 225,50,
+ 99, 68, 108,84, // 243 F3 ó min
+ 117,68, 126,84, // 244 F4 ô min
+ 219,34, 225,50,
+ 126,68, 135,84, // 246 F6 ö min
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 151,68, 158,84, // 249 F9 ù min
+ 144,68, 151,84, // 250 FA ú min
+ 158,68, 165,84, // 251 FB û min
+ 165,68, 172,84, // 252 FC ü min
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+#else
+ 0, 0, 4, 16, // 32
+ 4, 0, 7, 16, // !
+ 7, 0, 13, 16,
+ 14, 0, 21, 16,
+ 22, 0, 28, 16,
+ 29, 0, 38, 16,
+ 39, 0, 48, 16,
+ 48, 0, 51, 16,
+ 51, 0, 55, 16,
+ 55, 0, 59, 16,
+ 59, 0, 65, 16,
+ 66, 0, 72, 16,
+ 73, 0, 76, 16,
+ 76, 0, 82, 16,
+ 82, 0, 85, 16,
+ 85, 0, 90, 16,
+ 90, 0, 97, 16,
+ 98, 0, 103,16,
+ 104,0, 111,16,
+ 111,0, 118,16,
+ 118,0, 125,16,
+ 125,0, 132,16,
+ 132,0, 139,16,
+ 139,0, 146,16,
+ 146,0, 153,16,
+ 153,0, 160,16,
+ 160,0, 165,16, // :
+ 164,0, 169,16, // ;
+ 169,0, 177,16, // <
+ 177,0, 185,16, // =
+ 185,0, 193,16, // >
+ 193,0, 201,16, // ?
+
+ 201,0, 215,16, // 64
+ 0, 17, 10, 33, // A
+ 10, 17, 18, 33,
+ 19, 17, 28, 33,
+ 28, 17, 36, 33,
+ 37, 17, 44, 33,
+ 45, 17, 52, 33,
+ 53, 17, 62, 33,
+ 63, 17, 71, 33,
+ 72, 17, 75, 33,
+ 75, 17, 82, 33,
+ 83, 17, 91, 33,
+ 92, 17, 99, 33,
+ 100,17, 110,33,
+ 111,17, 119,33,
+//? 120,17, 129,33, // O
+ 216,0, 227,16, // O
+ 130,17, 138,33,
+ 139,17, 148,33,
+ 149,17, 158,33,
+ 158,17, 166,33,
+ 166,17, 175,33,
+ 175,17, 183,33,
+ 183,17, 193,33,
+ 193,17, 207,33,
+ 207,17, 215,33,
+ 215,17, 224,33,
+ 224,17, 232,33, // Z
+ 232,17, 236,33,
+ 236,17, 241,33,
+ 241,17, 245,33,
+ 245,17, 252,33, // ^
+ 0, 34, 8, 50, // _
+
+ 45, 17, 52, 33, // 96
+ 8, 34, 15, 50, // a
+ 16, 34, 23, 50,
+ 24, 34, 31, 50,
+ 31, 34, 38, 50,
+ 39, 34, 46, 50,
+ 46, 34, 52, 50,
+ 52, 34, 59, 50,
+ 60, 34, 67, 50,
+ 68, 34, 71, 50,
+ 71, 34, 76, 50,
+ 77, 34, 84, 50,
+ 84, 34, 87, 50,
+ 88, 34, 99, 50,
+ 100,34, 107,50,
+//? 108,34, 115,50, // o
+ 238,0, 246,16, // o
+ 116,34, 123,50,
+ 124,34, 131,50,
+ 132,34, 137,50,
+ 137,34, 144,50,
+ 144,34, 149,50,
+ 149,34, 156,50,
+ 156,34, 164,50,
+ 164,34, 176,50,
+ 176,34, 183,50,
+ 183,34, 191,50,
+ 191,34, 197,50, // z
+ 197,34, 203,50,
+ 203,34, 205,50,
+ 205,34, 211,50,
+ 211,34, 219,50,
+ 219,34, 225,50,
+
+#if _POLISH
+ 219,34, 225,50, // 128
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 0, 51, 8, 67, // 140 S´
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 9, 51, 17, 67, // 143 Z´
+
+ 219,34, 225,50, // 144
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 0, 68, 7, 84, // 156 s´
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 8, 68, 14, 84, // 159 z´
+
+ 219,34, 225,50, // 160
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 18, 51, 27, 67, // 163 L/
+ 219,34, 225,50,
+ 28, 51, 39, 67, // 165 A,
+ 0, 0, 4, 16, // 166 A6 ¦ (cadratin)
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 40, 51, 48, 67, // 175 Zo
+
+ 219,34, 225,50, // 176
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 16, 68, 21, 84, // 179 l/
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 23, 68, 31, 84, // 185 a,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 32, 68, 38, 84, // 191 zo
+
+ 219,34, 225,50, // 192
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 49, 51, 58, 67, // 198 C´
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 59, 51, 66, 67, // 202 E,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 208
+ 67, 51, 75, 67, // 209 N´
+ 219,34, 225,50,
+//? 76, 51, 85, 67, // 211 O´
+ 86, 51, 97, 67, // 211 O´
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 224
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 39, 68, 46, 84, // 230 c´
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 47, 68, 54, 84, // 234 e,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 240
+ 55, 68, 62, 84, // 241 n´
+ 219,34, 225,50,
+//? 63, 68, 70, 84, // 243 o´
+ 71, 68, 79, 84, // 243 o´
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+#else
+ 219,34, 225,50, // 128
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 144
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 160
+ 219,34, 225,50, // 161 A1 ! inversé
+ 219,34, 225,50,
+ 219,34, 225,50, // 163 A3 £
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 0, 0, 4, 16, // 166 A6 ¦ (cadratin)
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+
+ 219,34, 225,50, // 176
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50, // 191 BF ? inversé
+
+ 10, 51, 20, 67, // 192 C0 à maj
+ 0, 51, 10, 67, // 193 C1 á maj
+ 20, 51, 30, 67, // 194 C2 â maj
+ 40, 51, 50, 67, // 195 C3 ã maj
+ 30, 51, 40, 67, // 196 C4 ä maj
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 50, 51, 59, 67, // 199 C7 ç maj
+ 67, 51, 74, 67, // 200 C8 è maj
+ 59, 51, 66, 67, // 201 C9 é maj
+ 75, 51, 82, 67, // 202 CA ê maj
+ 83, 51, 90, 67, // 203 CB ë maj
+ 219,34, 225,50,
+ 91, 51, 95, 67, // 205 CD í maj
+ 100,51, 103,67, // 206 CE î maj
+ 104,51, 109,67, // 207 CF ï maj
+
+ 219,34, 225,50, // 208
+ 109,51, 117,67, // 209 D1 ñ maj
+ 219,34, 225,50,
+ 118,51, 127,67, // 211 D3 ó maj
+ 138,51, 147,67, // 212 D4 ô maj
+ 219,34, 225,50,
+ 148,51, 157,67, // 214 D6 ö maj
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 177,51, 185,67, // 217 D9 ù maj
+ 168,51, 176,67, // 218 DA ú maj
+ 186,51, 194,67, // 219 DB û maj
+ 195,51, 203,67, // 220 DC ü maj
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 211,51, 220,67, // 223 DF ss allemand
+
+ 8, 68, 15, 84, // 224 E0 à min
+ 0, 68, 7, 84, // 225 E1 á min
+ 16, 68, 23, 84, // 226 E2 â min
+ 32, 68, 39, 84, // 227 E3 ã min
+ 24, 68, 31, 84, // 228 E4 ä min
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 40, 68, 47, 84, // 231 E7 ç min
+ 55, 68, 62, 84, // 232 E8 è min
+ 47, 68, 54, 84, // 233 E9 é min
+ 63, 68, 70, 84, // 234 EA ê min
+ 71, 68, 78, 84, // 235 EB ë min
+ 219,34, 225,50,
+ 79, 68, 83, 84, // 237 ED í min
+ 88, 68, 92, 84, // 238 EE î min
+ 92, 68, 97, 84, // 239 EF ï min
+
+ 219,34, 225,50, // 240
+ 97, 68, 104,84, // 241 F1 ñ min
+ 219,34, 225,50,
+ 105,68, 112,84, // 243 F3 ó min
+ 121,68, 128,84, // 244 F4 ô min
+ 219,34, 225,50,
+ 129,68, 136,84, // 246 F6 ö min
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 153,68, 160,84, // 249 F9 ù min
+ 145,68, 152,84, // 250 FA ú min
+ 161,68, 168,84, // 251 FB û min
+ 169,68, 176,84, // 252 FC ü min
+ 219,34, 225,50,
+ 219,34, 225,50,
+ 219,34, 225,50,
+#endif
+#endif
+};
+
+
+static short table_text_courier[] =
+{
+// x1, y1, x2, y2
+ 231,137,239,153, // 0
+ 1,188, 9,204, // .
+ 51,188,59,204, // carré
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 11,188,19,204, // \t
+ 21,188,29,204, // \n
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153, // \r
+ 231,137,239,153,
+ 231,137,239,153,
+ 41,188,49,204, // >
+ 31,188,39,204, // <
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 1, 86, 9,102, // 32
+ 11, 86, 19,102,
+ 21, 86, 29,102,
+ 31, 86, 39,102,
+ 41, 86, 49,102,
+ 51, 86, 59,102,
+ 61, 86, 69,102,
+ 71, 86, 79,102,
+ 81, 86, 89,102,
+ 91, 86, 99,102,
+ 101, 86,109,102,
+ 111, 86,119,102,
+ 121, 86,129,102,
+ 131, 86,139,102,
+ 141, 86,149,102,
+ 151, 86,159,102,
+ 161, 86,169,102,
+ 171, 86,179,102,
+ 181, 86,189,102,
+ 191, 86,199,102,
+ 201, 86,209,102,
+ 211, 86,219,102,
+ 221, 86,229,102,
+ 231, 86,239,102,
+ 1,103, 9,119, // 56
+ 11,103, 19,119,
+ 21,103, 29,119,
+ 31,103, 39,119,
+ 41,103, 49,119,
+ 51,103, 59,119,
+ 61,103, 69,119,
+ 71,103, 79,119,
+
+ 81,103, 89,119, // @
+ 91,103, 99,119,
+ 101,103,109,119,
+ 111,103,119,119,
+ 121,103,129,119,
+ 131,103,139,119,
+ 141,103,149,119,
+ 151,103,159,119,
+ 161,103,169,119,
+ 171,103,179,119,
+ 181,103,189,119,
+ 191,103,199,119,
+ 201,103,209,119,
+ 211,103,219,119,
+ 221,103,229,119,
+ 231,103,239,119,
+ 1,120, 9,136, // P
+ 11,120, 19,136,
+ 21,120, 29,136,
+ 31,120, 39,136,
+ 41,120, 49,136,
+ 51,120, 59,136,
+ 61,120, 69,136,
+ 71,120, 79,136,
+ 81,120, 89,136,
+ 91,120, 99,136,
+ 101,120,109,136,
+ 111,120,119,136, // [
+ 121,120,129,136,
+ 131,120,139,136,
+ 141,120,149,136,
+ 151,120,159,136, // _
+
+ 161,120,169,136,
+ 171,120,179,136, // a
+ 181,120,189,136,
+ 191,120,199,136,
+ 201,120,209,136,
+ 211,120,219,136,
+ 221,120,229,136,
+ 231,120,239,136,
+ 1,137, 9,153,
+ 11,137, 19,153,
+ 21,137, 29,153,
+ 31,137, 39,153,
+ 41,137, 49,153,
+ 51,137, 59,153,
+ 61,137, 69,153,
+ 71,137, 79,153, // o
+ 81,137, 89,153,
+ 91,137, 99,153,
+ 101,137,109,153,
+ 111,137,119,153,
+ 121,137,129,153,
+ 131,137,139,153,
+ 141,137,149,153,
+ 151,137,159,153,
+ 161,137,169,153,
+ 171,137,179,153,
+ 181,137,189,153,
+ 191,137,199,153,
+ 201,137,209,153,
+ 211,137,219,153,
+ 221,137,229,153, // ~
+ 231,137,239,153,
+
+#if _POLISH
+ 231,137,239,153, // 128
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 1,154, 9,170, // 140 S´
+ 231,137,239,153,
+ 231,137,239,153,
+ 11,154, 19,170, // 143 Z´
+
+ 231,137,239,153, // 144
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 1,171, 9,187, // 156 s´
+ 231,137,239,153,
+ 231,137,239,153,
+ 11,171, 19,187, // 159 z´
+
+ 231,137,239,153, // 160
+ 231,137,239,153,
+ 231,137,239,153,
+ 21,154, 29,170, // 163 L/
+ 231,137,239,153,
+ 31,154, 39,170, // 165 A,
+ 1, 86, 9,102, // 166 A6 ¦ (cadratin)
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 41,154, 49,170, // 175 Zo
+
+ 231,137,239,153, // 176
+ 231,137,239,153,
+ 231,137,239,153,
+ 21,171, 29,187, // 179 l/
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 31,171, 39,187, // 185 a,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 41,171, 49,187, // 191 zo
+
+ 231,137,239,153, // 192
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 51,154, 59,170, // 198 C´
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 61,154, 69,170, // 202 E,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 231,137,239,153, // 208
+ 71,154, 79,170, // 209 N´
+ 231,137,239,153,
+ 81,171, 89,187, // 211 O´
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 231,137,239,153, // 224
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 51,171, 59,187, // 230 c´
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 61,171, 69,187, // 234 e,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 231,137,239,153, // 240
+ 71,171, 79,187, // 241 n´
+ 231,137,239,153,
+ 81,171, 89,187, // 243 ó min
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+#else
+ 231,137,239,153, // 128
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 231,137,239,153, // 144
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 231,137,239,153, // 160
+ 231,137,239,153, // 161 A1 ! inversé
+ 231,137,239,153,
+ 231,137,239,153, // 163 A3 £
+ 231,137,239,153,
+ 231,137,239,153,
+ 1, 86, 9,102, // 166 A6 ¦ (cadratin)
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+
+ 231,137,239,153, // 176
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153, // 191 BF ? inversé
+
+ 11,154, 19,170, // à maj
+ 1,154, 9,170, // á maj
+ 21,154, 29,170, // â maj
+ 41,154, 49,170, // ã maj
+ 31,154, 39,170, // ä maj
+ 231,137,239,153,
+ 231,137,239,153,
+ 51,154, 59,170, // ç maj
+ 71,154, 79,170, // è maj
+ 61,154, 69,170, // é maj
+ 81,154, 89,170, // ê maj
+ 91,154, 99,170, // ë maj
+ 231,137,239,153,
+ 101,154,109,170, // í maj
+ 121,154,129,170, // î maj
+ 131,154,139,170, // ï maj
+ 231,137,239,153,
+ 141,154,149,170, // ñ maj
+ 231,137,239,153,
+ 151,154,159,170, // ó maj
+ 171,154,179,170, // ô maj
+ 231,137,239,153,
+ 181,154,189,170, // ö maj
+ 231,137,239,153,
+ 231,137,239,153,
+ 211,154,219,170, // ù maj
+ 201,154,209,170, // ú maj
+ 221,154,229,170, // û maj
+ 231,154,239,170, // ü maj
+ 231,137,239,153,
+ 231,137,239,153,
+ 241,154,249,170, // 223 DF ss allemand
+
+ 11,171, 19,187, // à min
+ 1,171, 9,187, // á min
+ 21,171, 29,187, // â min
+ 41,171, 49,187, // ã min
+ 31,171, 39,187, // ä min
+ 231,137,239,153,
+ 231,137,239,153,
+ 51,171, 59,187, // ç min
+ 71,171, 79,187, // è min
+ 61,171, 69,187, // é min
+ 81,171, 89,187, // ê min
+ 91,171, 99,187, // ë min
+ 231,137,239,153,
+ 111,171,119,187, // ì min
+ 121,171,129,187, // î min
+ 131,171,139,187, // ï min
+ 231,137,239,153,
+ 141,171,149,187, // ñ min
+ 231,137,239,153,
+ 151,171,159,187, // ó min
+ 171,171,179,187, // ô min
+ 231,137,239,153,
+ 181,171,189,187, // ö min
+ 231,137,239,153,
+ 231,137,239,153,
+ 211,171,219,187, // ù min
+ 201,171,209,187, // ú min
+ 221,171,229,187, // û min
+ 231,171,239,187, // ü min
+ 231,137,239,153,
+ 231,137,239,153,
+ 231,137,239,153,
+#endif
+};
+
+
+// Retourne le pointeur à la table selon la fonte.
+
+short* RetTable(FontType font)
+{
+ if ( font == FONT_COLOBOT ) return table_text_colobot;
+ else return table_text_courier;
+}
+
+
+
+// Constructeur de l'objet.
+
+CText::CText(CInstanceManager* iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_TEXT, this);
+
+ m_pD3DDevice = 0;
+ m_engine = engine;
+}
+
+// Destructeur de l'objet.
+
+CText::~CText()
+{
+ m_iMan->DeleteInstance(CLASS_TEXT, this);
+}
+
+
+void CText::SetD3DDevice(LPDIRECT3DDEVICE7 device)
+{
+ m_pD3DDevice = device;
+}
+
+
+// Affiche un texte multi-fonte.
+// La position verticale est en bas de la boîte du caractère.
+
+void CText::DrawText(char *string, char *format, int len, FPOINT pos,
+ float width, int justif, float size, float stretch,
+ int eol)
+{
+ float sw;
+
+ if ( justif == 0 ) // centré ?
+ {
+ sw = RetStringWidth(string, format, len, size, stretch);
+ if ( sw > width ) sw = width;
+ pos.x -= sw/2.0f;
+ }
+ if ( justif < 0 ) // drapeau à gauche ?
+ {
+ sw = RetStringWidth(string, format, len, size, stretch);
+ if ( sw > width ) sw = width;
+ pos.x -= sw;
+ }
+ DrawString(string, format, len, pos, width, size, stretch, eol);
+}
+
+// Affiche un texte multi-fonte.
+// La position verticale est en bas de la boîte du caractère.
+
+void CText::DrawText(char *string, char *format, FPOINT pos, float width,
+ int justif, float size, float stretch,
+ int eol)
+{
+ DrawText(string, format, strlen(string), pos, width, justif, size, stretch, eol);
+}
+
+// Affiche un texte.
+// La position verticale est en bas de la boîte du caractère.
+
+void CText::DrawText(char *string, int len, FPOINT pos, float width,
+ int justif, float size, float stretch, FontType font,
+ int eol)
+{
+ float sw;
+
+ if ( justif == 0 ) // centré ?
+ {
+ sw = RetStringWidth(string, len, size, stretch, font);
+ if ( sw > width ) sw = width;
+ pos.x -= sw/2.0f;
+ }
+ if ( justif < 0 ) // drapeau à gauche ?
+ {
+ sw = RetStringWidth(string, len, size, stretch, font);
+ if ( sw > width ) sw = width;
+ pos.x -= sw;
+ }
+ DrawString(string, len, pos, width, size, stretch, font, eol);
+}
+
+// Affiche un texte.
+// La position verticale est en bas de la boîte du caractère.
+
+void CText::DrawText(char *string, FPOINT pos, float width,
+ int justif, float size, float stretch, FontType font,
+ int eol)
+{
+ DrawText(string, strlen(string), pos, width, justif, size, stretch, font, eol);
+}
+
+
+// Retourne les dimensions d'un texte multi-fonte.
+
+void CText::DimText(char *string, char *format, int len, FPOINT pos,
+ int justif, float size, float stretch,
+ FPOINT &start, FPOINT &end)
+{
+ float sw;
+
+ start = end = pos;
+
+ sw = RetStringWidth(string, format, len, size, stretch);
+ end.x += sw;
+ if ( justif == 0 ) // centré ?
+ {
+ start.x -= sw/2.0f;
+ end.x -= sw/2.0f;
+ }
+ if ( justif < 0 ) // drapeau à gauche ?
+ {
+ start.x -= sw;
+ end.x -= sw;
+ }
+
+ start.y -= RetDescent(size, FONT_COLOBOT);
+ end.y += RetAscent(size, FONT_COLOBOT);
+}
+
+// Retourne les dimensions d'un texte multi-fonte.
+
+void CText::DimText(char *string, char *format, FPOINT pos, int justif,
+ float size, float stretch,
+ FPOINT &start, FPOINT &end)
+{
+ DimText(string, format, strlen(string), pos, justif, size, stretch, start, end);
+}
+
+// Retourne les dimensions d'un texte.
+
+void CText::DimText(char *string, int len, FPOINT pos, int justif,
+ float size, float stretch, FontType font,
+ FPOINT &start, FPOINT &end)
+{
+ float sw;
+
+ start = end = pos;
+
+ sw = RetStringWidth(string, len, size, stretch, font);
+ end.x += sw;
+ if ( justif == 0 ) // centré ?
+ {
+ start.x -= sw/2.0f;
+ end.x -= sw/2.0f;
+ }
+ if ( justif < 0 ) // drapeau à gauche ?
+ {
+ start.x -= sw;
+ end.x -= sw;
+ }
+
+ start.y -= RetDescent(size, font);
+ end.y += RetAscent(size, font);
+}
+
+// Retourne les dimensions d'un texte.
+
+void CText::DimText(char *string, FPOINT pos, int justif,
+ float size, float stretch, FontType font,
+ FPOINT &start, FPOINT &end)
+{
+ DimText(string, strlen(string), pos, justif, size, stretch, font, start, end);
+}
+
+
+// Retourne la hauteur au-dessus de la ligne de base.
+
+float CText::RetAscent(float size, FontType font)
+{
+ return (13.0f/256.0f)*(size/20.0f);
+}
+
+// Retourne la hauteur au-dessous de la ligne de base.
+
+float CText::RetDescent(float size, FontType font)
+{
+ return (3.0f/256.0f)*(size/20.0f);
+}
+
+// Retourne la hauteur totale du caractère.
+
+float CText::RetHeight(float size, FontType font)
+{
+ return (16.0f/256.0f)*(size/20.0f);
+}
+
+
+// Retourne la largeur d'une chaîne de caractères multi-fonte.
+
+float CText::RetStringWidth(char *string, char *format, int len,
+ float size, float stretch)
+{
+ FontType font;
+ float st, tab, w, width = 0.0f;
+ short *table, *pt;
+ int i, c;
+
+ for ( i=0 ; i<len ; i++ )
+ {
+ font = (FontType)(format[i]&FONT_MASK);
+ if ( font == FONT_BUTTON )
+ {
+ width += (12.0f/256.0f)*(size/20.0f);
+ }
+ else
+ {
+ table = RetTable(font);
+ c = (unsigned char)string[i];
+
+ if ( c == '\t' )
+ {
+ pt = table+' '*4;
+ tab = (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*stretch*m_engine->RetEditIndentValue();
+ w = tab-Mod(width, tab);
+ if ( w < tab*0.1f ) w += tab;
+ width += w;
+ continue;
+ }
+
+ if ( c > 255 ) continue;
+
+ pt = table+c*4;
+ st = stretch;
+ if ( font == FONT_COLOBOT && (c == 'O' || c == 'o') ) st = 0.8f;
+ width += (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st;
+ }
+ }
+
+ return width;
+}
+
+// Retourne la largeur d'une chaîne de caractères.
+
+float CText::RetStringWidth(char *string, int len,
+ float size, float stretch, FontType font)
+{
+ float st, tab, w, width = 0.0f;
+ short *table, *pt;
+ int i, c;
+
+ table = RetTable(font);
+ for ( i=0 ; i<len ; i++ )
+ {
+ c = (unsigned char)string[i];
+
+ if ( c == '\t' )
+ {
+ pt = table+' '*4;
+ tab = (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*stretch*m_engine->RetEditIndentValue();
+ w = tab-Mod(width, tab);
+ if ( w < tab*0.1f ) w += tab;
+ width += w;
+ continue;
+ }
+
+ if ( c > 255 ) continue;
+
+ pt = table+c*4;
+ st = stretch;
+ if ( font == FONT_COLOBOT && (c == 'O' || c == 'o') ) st = 0.8f;
+ width += (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st;
+ }
+
+ return width;
+}
+
+// Retourne la largeur d'un caractère.
+// 'offset' est la position actuelle dans la ligne.
+
+float CText::RetCharWidth(int character, float offset,
+ float size, float stretch, FontType font)
+{
+ float st, tab, w;
+ short* pt;
+
+ if ( font == FONT_BUTTON ) return (12.0f/256.0f)*(size/20.0f);
+
+ if ( character == '\t' )
+ {
+ pt = RetTable(font)+' '*4;
+ tab = (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*stretch*m_engine->RetEditIndentValue();
+ w = tab-Mod(offset, tab);
+ if ( w < tab*0.1f ) w += tab;
+ return w;
+ }
+
+ if ( character > 255 ) return 0.0f;
+
+ pt = RetTable(font)+character*4;
+ st = stretch;
+#if !_NEWLOOK
+ if ( font == FONT_COLOBOT && (character == 'O' || character == 'o') ) st = 0.8f;
+#endif
+ return (float)(pt[2]-pt[0])/256.0f*(size/20.0f)*st;
+}
+
+
+// Justifie une ligne de texte multi-fonte. Retourne l'offset de la coupure.
+
+int CText::Justif(char *string, char *format, int len, float width,
+ float size, float stretch)
+{
+ FontType font;
+ float pos;
+ int i, character, cut;
+
+ pos = 0.0f;
+ cut = 0;
+ for ( i=0 ; i<len ; i++ )
+ {
+ font = (FontType)(format[i]&FONT_MASK);
+ character = (unsigned char)string[i];
+
+ if ( character == 0 )
+ {
+ return i;
+ }
+ if ( font != FONT_BUTTON )
+ {
+ if ( character == '\n' )
+ {
+ return i+1;
+ }
+ if ( character == ' ' )
+ {
+ cut = i+1;
+ }
+ }
+
+ pos += RetCharWidth(character, pos, size, stretch, font);
+ if ( pos > width )
+ {
+ if ( cut == 0 ) return i;
+ else return cut;
+ }
+ }
+ return i;
+}
+
+// Justifie une ligne de texte. Retourne l'offset de la coupure.
+
+int CText::Justif(char *string, int len, float width,
+ float size, float stretch, FontType font)
+{
+ float pos;
+ int i, character, cut;
+
+ pos = 0.0f;
+ cut = 0;
+ for ( i=0 ; i<len ; i++ )
+ {
+ character = (unsigned char)string[i];
+
+ if ( character == 0 )
+ {
+ return i;
+ }
+ if ( character == '\n' )
+ {
+ return i+1;
+ }
+ if ( character == ' ' )
+ {
+ cut = i+1;
+ }
+
+ pos += RetCharWidth(character, pos, size, stretch, font);
+ if ( pos > width )
+ {
+ if ( cut == 0 ) return i;
+ else return cut;
+ }
+ }
+ return i;
+}
+
+// Retourne la position convenant le mieux à une offset donnée (multi-fonte).
+
+int CText::Detect(char *string, char *format, int len, float offset,
+ float size, float stretch)
+{
+ FontType font;
+ float pos, width;
+ int i, character, cut;
+
+ pos = 0.0f;
+ cut = 0;
+ for ( i=0 ; i<len ; i++ )
+ {
+ font = (FontType)(format[i]&FONT_MASK);
+ character = (unsigned char)string[i];
+
+ if ( character == 0 )
+ {
+ return i;
+ }
+ if ( font != FONT_BUTTON )
+ {
+ if ( character == '\n' )
+ {
+ return i;
+ }
+ }
+
+ width = RetCharWidth(character, pos, size, stretch, font);
+ if ( offset <= pos+width/2.0f )
+ {
+ return i;
+ }
+ pos += width;
+ }
+ return i;
+}
+
+// Retourne la position convenant le mieux à une offset donnée.
+
+int CText::Detect(char *string, int len, float offset,
+ float size, float stretch, FontType font)
+{
+ float pos, width;
+ int i, character, cut;
+
+ pos = 0.0f;
+ cut = 0;
+ for ( i=0 ; i<len ; i++ )
+ {
+ character = (unsigned char)string[i];
+
+ if ( character == 0 ||
+ character == '\n' )
+ {
+ return i;
+ }
+
+ width = RetCharWidth(character, pos, size, stretch, font);
+ if ( offset <= pos+width/2.0f )
+ {
+ return i;
+ }
+ pos += width;
+ }
+ return i;
+}
+
+
+// Affiche un texte multi-fonte.
+
+void CText::DrawString(char *string, char *format, int len, FPOINT pos,
+ float width, float size, float stretch, int eol)
+{
+ FontType font;
+ float start, offset, cw;
+ int i, c;
+
+#if _POLISH
+ m_engine->SetTexture("textp.tga");
+#else
+ m_engine->SetTexture("text.tga");
+#endif
+ m_engine->SetState(D3DSTATETTw);
+
+ font = FONT_COLOBOT;
+
+ start = pos.x;
+ offset = 0.0f;
+ for ( i=0 ; i<len ; i++ )
+ {
+ font = (FontType)(format[i]&FONT_MASK);
+ c = (unsigned char)string[i];
+ cw = RetCharWidth(c, offset, size, stretch, font);
+
+ if ( offset+cw > width ) // dépasse la largeur maximale ?
+ {
+ cw = RetCharWidth(16, offset, size, stretch, font);
+ pos.x = start+width-cw;
+ DrawChar(16, pos, size, stretch, font); // >
+ break;
+ }
+
+ if ( (format[i]&COLOR_MASK) != 0 )
+ {
+ DrawColor(pos, size, cw, format[i]&COLOR_MASK);
+ }
+ DrawChar(c, pos, size, stretch, font);
+ offset += cw;
+ pos.x += cw;
+ }
+
+ if ( eol != 0 )
+ {
+ DrawChar(eol, pos, size, stretch, font);
+ }
+}
+
+// Affiche un texte.
+
+void CText::DrawString(char *string, int len, FPOINT pos, float width,
+ float size, float stretch, FontType font,
+ int eol)
+{
+ float start, offset, cw;
+ int i, c;
+
+#if _POLISH
+ m_engine->SetTexture("textp.tga");
+#else
+ m_engine->SetTexture("text.tga");
+#endif
+ m_engine->SetState(D3DSTATETTw);
+
+ start = pos.x;
+ offset = 0.0f;
+ for ( i=0 ; i<len ; i++ )
+ {
+ c = (unsigned char)string[i];
+ cw = RetCharWidth(c, offset, size, stretch, font);
+
+ if ( offset+cw > width ) // dépasse la largeur maximale ?
+ {
+ cw = RetCharWidth(16, offset, size, stretch, font);
+ pos.x = start+width-cw;
+ DrawChar(16, pos, size, stretch, font); // >
+ break;
+ }
+
+ DrawChar(c, pos, size, stretch, font);
+ offset += cw;
+ pos.x += cw;
+ }
+
+ if ( eol != 0 )
+ {
+ DrawChar(eol, pos, size, stretch, font);
+ }
+}
+
+// Affiche le lien d'un caractère.
+
+void CText::DrawColor(FPOINT pos, float size, float width, int color)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2;
+ POINT dim;
+ D3DVECTOR n;
+ float h, u1, u2, v1, v2, dp;
+ int icon;
+
+ icon = -1;
+ if ( color == COLOR_LINK ) icon = 9; // bleu
+ if ( color == COLOR_TOKEN ) icon = 4; // orange
+ if ( color == COLOR_TYPE ) icon = 5; // vert
+ if ( color == COLOR_CONST ) icon = 8; // rouge
+ if ( color == COLOR_REM ) icon = 6; // magenta
+ if ( color == COLOR_KEY ) icon = 10; // gris
+ if ( icon == -1 ) return;
+
+ if ( color == COLOR_LINK )
+ {
+ m_engine->SetState(D3DSTATENORMAL);
+ }
+
+ dim = m_engine->RetDim();
+ if ( dim.y <= 768.0f ) // 1024x768 ou moins ?
+ {
+ h = 1.01f/dim.y; // 1 pixel
+ }
+ else // plus que 1024x768 ?
+ {
+ h = 2.0f/dim.y; // 2 pixels
+ }
+
+ p1.x = pos.x;
+ p2.x = pos.x + width;
+
+ if ( color == COLOR_LINK )
+ {
+ p1.y = pos.y;
+ p2.y = pos.y + h; // juste souligné
+ }
+ else
+ {
+#if 1
+ p1.y = pos.y;
+ p2.y = pos.y + (16.0f/256.0f)*(size/20.0f);
+//? p2.y = pos.y + h*4.0f; // juste souligné épais
+#else
+ p1.y = pos.y;
+ p2.y = pos.y + (16.0f/256.0f)*(size/20.0f)/4.0f;
+#endif
+ }
+
+ u1 = (16.0f/256.0f)*(icon%16);
+ v1 = (240.0f/256.0f);
+ u2 = (16.0f/256.0f)+u1;
+ v2 = (16.0f/256.0f)+v1;
+
+ dp = 0.5f/256.0f;
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+ if ( color == COLOR_LINK )
+ {
+ m_engine->SetState(D3DSTATETTw);
+ }
+}
+
+// Affiche un caractère.
+
+void CText::DrawChar(int character, FPOINT pos, float size,
+ float stretch, FontType font)
+{
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ FPOINT p1, p2;
+ D3DVECTOR n;
+ float width, height, u1, u2, v1, v2, dp;
+ short* pt;
+
+ dp = 0.5f/256.0f;
+ n = D3DVECTOR(0.0f, 0.0f, -1.0f); // normale
+
+ if ( font == FONT_BUTTON )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + (12.0f/256.0f)*(size/20.0f);
+ p2.y = pos.y + (16.0f/256.0f)*(size/20.0f);
+
+ if ( character <= 64 || character >= 128+56 )
+ {
+ u1 = 66.0f/256.0f;
+ v1 = 2.0f/256.0f;
+ u2 = 94.0f/256.0f;
+ v2 = 30.0f/256.0f;
+ }
+ else
+ {
+ u1 = 224.0f/256.0f;
+ v1 = 32.0f/256.0f;
+ u2 = 256.0f/256.0f;
+ v2 = 64.0f/256.0f;
+ }
+
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+//? p1.x += (12.0f/256.0f)*(size/20.0f)*0.1f;
+//? p1.y += (16.0f/256.0f)*(size/20.0f)*0.1f;
+//? p2.x -= (12.0f/256.0f)*(size/20.0f)*0.1f;
+//? p2.y -= (16.0f/256.0f)*(size/20.0f)*0.1f;
+
+ if ( character >= 64 && character < 64+64 )
+ {
+ character -= 64;
+ m_engine->SetTexture("button2.tga");
+ }
+ if ( character >= 128 && character < 128+64 )
+ {
+ character -= 128;
+ m_engine->SetTexture("button3.tga");
+ }
+
+ m_engine->SetState(D3DSTATETTw);
+
+ u1 = (32.0f/256.0f)*(character%8);
+ v1 = (32.0f/256.0f)*(character/8); // uv texture
+ u2 = (32.0f/256.0f)+u1;
+ v2 = (32.0f/256.0f)+v1;
+
+ u1 += dp;
+ v1 += dp;
+ u2 -= dp;
+ v2 -= dp;
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+
+#if _POLISH
+ m_engine->SetTexture("textp.tga");
+#else
+ m_engine->SetTexture("text.tga");
+#endif
+ return;
+ }
+
+ if ( character > 255 ) return;
+
+//? if ( character == '\t' ) character = ' '; // si tab, n'affiche pas ->
+
+#if !_NEWLOOK
+ if ( font == FONT_COLOBOT && (character == 'O' || character == 'o') )
+ {
+ stretch = 0.8f;
+ }
+#endif
+ if ( font == FONT_COURIER )
+ {
+ stretch *= 1.2f;
+ }
+
+ pt = RetTable(font)+character*4;
+ width = (float)(pt[2]-pt[0])/256.0f*stretch*0.9f;
+//? width = (float)(pt[2]-pt[0])/256.0f*stretch;
+ height = (float)(pt[3]-pt[1])/256.0f;
+
+#if _NEWLOOK
+ pos.y += height*(size/20.0f)/17.0f;
+#endif
+ p1.x = pos.x;
+ p1.y = pos.y;
+ p2.x = pos.x + width*(size/20.0f);
+ p2.y = pos.y + height*(size/20.0f);
+
+ u1 = (float)pt[0]/256.0f;
+ v1 = (float)pt[1]/256.0f;
+ u2 = (float)pt[2]/256.0f;
+ v2 = (float)pt[3]/256.0f;
+
+ if ( font == FONT_COLOBOT )
+ {
+ u1 += dp;
+ u2 += dp;
+#if _NEWLOOK
+ v2 += dp;
+#endif
+ }
+ if ( font == FONT_COURIER )
+ {
+ u1 -= dp;
+ u2 += dp*2.0f;
+ }
+
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, 0.0f), n, u1,v2);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, 0.0f), n, u1,v1);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, 0.0f), n, u2,v2);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, 0.0f), n, u2,v1);
+
+ m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+}
+
diff --git a/src/text.h b/src/text.h
new file mode 100644
index 0000000..0ae1ac2
--- /dev/null
+++ b/src/text.h
@@ -0,0 +1,96 @@
+// text.h
+
+#ifndef _TEXT_H_
+#define _TEXT_H_
+
+
+
+class CInstanceManager;
+class CD3DEngine;
+
+
+
+#define SMALLFONT 10.0f
+#define BIGFONT 15.0f
+
+#define NORMSTRETCH 0.8f
+
+
+
+enum FontType
+{
+ FONT_COLOBOT = 0,
+ FONT_COURIER = 1,
+ FONT_BUTTON = 2,
+};
+
+enum FontTitle
+{
+ TITLE_BIG = 0x04,
+ TITLE_NORM = 0x08,
+ TITLE_LITTLE = 0x0c,
+};
+
+enum FontColor
+{
+ COLOR_LINK = 0x10,
+ COLOR_TOKEN = 0x20,
+ COLOR_TYPE = 0x30,
+ COLOR_CONST = 0x40,
+ COLOR_REM = 0x50,
+ COLOR_KEY = 0x60,
+ COLOR_TABLE = 0x70,
+};
+
+#define FONT_MASK 0x03
+#define TITLE_MASK 0x0c
+#define COLOR_MASK 0x70
+#define IMAGE_MASK 0x80
+
+
+
+class CText
+{
+public:
+ CText(CInstanceManager *iMan, CD3DEngine* engine);
+ ~CText();
+
+ void SetD3DDevice(LPDIRECT3DDEVICE7 device);
+
+ void DrawText(char *string, char *format, int len, FPOINT pos, float width, int justif, float size, float stretch, int eol);
+ void DrawText(char *string, char *format, FPOINT pos, float width, int justif, float size, float stretch, int eol);
+ void DrawText(char *string, int len, FPOINT pos, float width, int justif, float size, float stretch, FontType font, int eol);
+ void DrawText(char *string, FPOINT pos, float width, int justif, float size, float stretch, FontType font, int eol);
+ void DimText(char *string, char *format, int len, FPOINT pos, int justif, float size, float stretch, FPOINT &start, FPOINT &end);
+ void DimText(char *string, char *format, FPOINT pos, int justif, float size, float stretch, FPOINT &start, FPOINT &end);
+ void DimText(char *string, int len, FPOINT pos, int justif, float size, float stretch, FontType font, FPOINT &start, FPOINT &end);
+ void DimText(char *string, FPOINT pos, int justif, float size, float stretch, FontType font, FPOINT &start, FPOINT &end);
+
+ float RetAscent(float size, FontType font);
+ float RetDescent(float size, FontType font);
+ float RetHeight(float size, FontType font);
+
+ float RetStringWidth(char *string, char *format, int len, float size, float stretch);
+ float RetStringWidth(char *string, int len, float size, float stretch, FontType font);
+ float RetCharWidth(int character, float offset, float size, float stretch, FontType font);
+
+ int Justif(char *string, char *format, int len, float width, float size, float stretch);
+ int Justif(char *string, int len, float width, float size, float stretch, FontType font);
+ int Detect(char *string, char *format, int len, float offset, float size, float stretch);
+ int Detect(char *string, int len, float offset, float size, float stretch, FontType font);
+
+protected:
+ void DrawString(char *string, char *format, int len, FPOINT pos, float width, float size, float stretch, int eol);
+ void DrawString(char *string, int len, FPOINT pos, float width, float size, float stretch, FontType font, int eol);
+ void DrawColor(FPOINT pos, float size, float width, int color);
+ void DrawChar(int character, FPOINT pos, float size, float stretch, FontType font);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+
+};
+
+
+#endif //_TEXT_H_
diff --git a/src/tracks.txt b/src/tracks.txt
new file mode 100644
index 0000000..8d80872
--- /dev/null
+++ b/src/tracks.txt
@@ -0,0 +1,17 @@
+Utilisation des tracks
+
+ 1: data
+ 2: terre Terre
+ 3: tropica Tropica
+ 4: crystalium Crystalium
+ 5: saari Saari
+ 6: volcano Volcano
+ 7: centaury Centaury
+ 8: orpheon Orphéon
+ 9: terranova Terranova
+10: lost perdu
+11: win gagné
+12: fox fin du jeu
+13: shuffle -
+
+DR 12.06.01
diff --git a/src/traduc.txt b/src/traduc.txt
new file mode 100644
index 0000000..73bbf55
--- /dev/null
+++ b/src/traduc.txt
@@ -0,0 +1,151 @@
+Types des objets COLOBOT
+------------------------
+
+
+ ... // sac de survie
+
+ BaseCamp // fusée principale
+ Derrick // derrick
+ BotFactory // fabrique de véhicules
+ PowerStation // station de recharge
+ Converter // conversion minerai en titanium
+ RepairCenter // centre de réparation
+ DefenceTower // tour de défense
+ AlienNest // nid
+ ResearchCenter // centre de recherches
+ RadarStation // radar
+ PowerPlant // fabrique de piles
+ AutoLab // analyseur de matières organiques
+ NuclearPlant // centrale nucléaire
+ StartArea // départ
+ GoalArea // arrivée
+ ExchangePost // borne d'information
+
+ TitaniumOre // minerai de titanium
+ UraniumOre // minerai d'uranium
+ Titanium // titanium
+ PowerPack // pile normale
+ NuclearPack // pile nucléaire
+ OrgaStuff // matière organique
+ BlackBox // boîte noire
+ TNT // explosif
+
+ PowerSpot // énergie en sous-sol
+ TitaniumSpot // titanium en sous-sol
+ UraniumSpot // uranium en sous-sol
+ PathSpot // chemin
+
+ TrainingRollerBot // véhicule d'entraînement :
+ TrainingCrawlerBot
+ TrainingJetBot
+ TrainingSpiderBot
+
+ GrabberRollerBot // véhicule manipulateur :
+ GrabberCrawlerBot
+ GrabberJetBot
+ GrabberSpiderBot
+
+ FireballRollerBot // véhicule de défense :
+ FireballCrawlerBot
+ FireballJetBot
+ FireballSpiderBot
+
+ OrgaballRollerBot // véhicule de défense :
+ OrgaballCrawlerBot
+ OrgaballJetBot
+ OrgaballSpiderBot
+
+ SnifferRollerBot // véhicule sondeur :
+ SnifferCrawlerBot
+ SnifferJetBot
+ SnifferSpiderBot
+
+ ThumperBot // véhicule de terrassement
+ FazerBot // véhicule de défense
+ RecyclerBot // véhicule de récupération
+ ShieldBot // véhicule de protection
+ SubBot // sous-marin
+ TargetBot // cible d'entraînement
+
+ Me // homme
+ Wiz // toto
+
+ AlienBigLady // mère pondeuse
+ AlienEgg // oeuf
+ AlienAnt // fourmi
+ AlienSpider // araignée
+ AlienWasp // guèpe
+ AlienWorm // ver
+
+ Wreck // épave de véhicule
+ Ruin // bâtiment en ruine
+ Firework // feu d'artifice
+ Mine // mine
+ Barrier // barrière
+ Greenery // plante
+ Tree // arbre
+ Quartz // quartz
+ MegaStalk // racine
+ ... // gravi-plante
+
+
+Fonction du langage CBOT :
+
+ Move // avance d'une certaine distance
+ Turn // tourne d'un certain angle
+ Goto // va à une coordonnée donnée
+ Motor // commande directe des moteurs gauche & droite
+ Jet // commande directe du réacteur
+
+ Radar // détecte un objet
+ Direction // calcule une direction
+ Distance // calcule la distance entre deux points
+ Wait // attend
+ Produce // crée un objet
+ Message // affiche un message
+
+ Grab // prend un objet avec le bras manipulateur
+ Drop // dépose un objet avec le bras manipulateur
+ Sniff // sonde le sous-sol
+ Receive // reçoit une information
+ Send // envoie une information
+ Thump // terraforme le terrain
+ Recycle // récupère une épave
+ Shield // actionne le bouclier de protection
+ Fire // tir avec un canon
+ Aim // hausse du canon
+
+
+Classes :
+
+ point // point avec coordonnées x,y,z
+ object // descriptif d'un objet
+
+
+Descripteur d'un objet :
+
+ category // catégorie de l'objet
+ energyPack // object pile
+ load // objet transporté
+ position // position x,y,z
+ direction // orientation
+ energyLevel // niveau d'énergie
+ shieldLevel // niveau du bouclier
+ altitude // hauteur par rapport au sol
+
+
+Argument de la commande Manip( ) :
+
+ InFront // prend ou dépose devant
+ Behind // prend ou dépose derrière
+ EnergyPack // prend ou dépose sa propre pile
+
+
+Filtre pour la commande Radar( ) ;
+
+ FilterNone // pas de filtre
+ FilterOnlyLanding // seulement les robots qui roulent
+ FilterOnlyFliying // seulement les robots qui volent
+
+
+DR 14.03.01
diff --git a/src/version.txt b/src/version.txt
new file mode 100644
index 0000000..da31287
--- /dev/null
+++ b/src/version.txt
@@ -0,0 +1,108 @@
+1.18 (24.01.08)
+- Ne vérifie plus la présence des pistes audio.
+
+1.17 (08.01.08)
+- Sound.cpp:InitAudioTrackVolume:mixerGetLineControls ne devrait plus planter
+ sous Vista, grace à l'abandon de MIXER_GETLINECONTROLSF_ALL.
+- CoLoBoT ne joue plus les pistes audio, et le réglage du volume a disparu
+- CoLoBoT n'affiche plus Alsyd
+- Texte "www.colobot.com" remplacé par "www.ceebot.com"
+
+1.16 (10.11.03)
+- Options: si "accès aux solutions" décoché -> Lancer défi,
+ éditer programme, Esc, Abandonner: plus de bouton "accès à la solution"
+
+1.15 (02.09.03)
+- EVENT_INTERFACE_KGUP: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KGDOWN: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KACTION: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KVISIT: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KNEXT: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KHUMAN: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KDESEL: plus si CeeBot-Teen !
+- EVENT_INTERFACE_KCBOT: plus si CeeBot-Teen !
+
+1.14 (28.07.03)
+- Switch -nosetup -> plus de bouton "Options" pendant jeu
+
+1.8 ()
+- instruction shield(1, radius) ok avec radius 10..25
+- instruction shield(1, radius) possible si bouclier déjà déployé
+
+1.8 BETA (05.10.01)
+- CBOT: public, static, synchronized, private, protected
+- CBOT: strlen, strleft, strright, strmid, strval, strfind, strupper, strlower
+- CBOT: file, open, close, writeln, readln, eof, deletefile
+- extern/public: aide en cliquant dans la ligne d'info de l'éditeur
+- ExchangePost: UpdateList si infos reçues
+- ok si lien d'un seul caractère: \l;x\u file;
+- colobot.ini: [Setup] DeleteGamer=1
+- colobot.ini: [Directory] files=files
+- studio: nb max de caractères: 10000 -> 20000
+- script antt41 (scene904): AlienMother -> AlienQueen
+- load: recompilation ok si procédures "public" dans d'autres robots
+- si le volume CD est nul, la piste n'est pas du tout jouée
+- goto ResearchCenter toujours possible
+- meilleure gestion des touches Ctrl et Shift dans l'éditeur
+- object.temperature=12 impossible (PR_READ)
+- studio: ne plante plus si on tape plus de 100 car. sans espace
+- studio: "enregistrer" se rappelle du nom de fichier dans la mission
+- studio: Ctrl+A sélectionne tout
+- studio: run: si liste < 5 variables -> fond gris
+
+1.7 (13.09.01)
+- object.lifeTime
+- object.range Winged* idem si camera OnBoard/Back
+- float flatground(center, rmax);
+- float abstime();
+- float receive(name, power);
+- void send(name, value, power);
+- void deleteinfo(name, power);
+- bool testinfo(name, power);
+- Le cosmonaute peut construire une borne d'information
+
+1.6 (06.09.01)
+- niveaux supplémentaires avec %user%
+- fonction "send" plus coloriée
+- english help: EnergyPack -> EnergyCell
+- english help: energyPack -> energyCell
+- english help: FinishArea -> GoalArea
+
+1.5 (24.08.01)
+- first execute: prefered first non-T&L, second T&L
+- fondus welcome: D3DSTATETTb/w -> D3DSTATETCb/w
+
+1.4 (02.08.01)
+- n'importe quelle touche/clic passe les écrans welcome1, 2 et 3
+- icône associée au CD dans autorun.inf
+- SatCom: icône "Aide à la programmation" présente dans exercices
+- welcome: phase "Alsyd" plus longue (8s)
+- SaveOneScript quand on quitte le studio par ok, cancel ou run
+
+1.3 (27.07.01)
+- goto BotFactory toujours possible
+- documentation errmode(0)
+- petites corrections anglaises par MW
+- enlever pile pendant recherche ne bloque plus
+- si human porte qq chose et vaisseau décole -> ne reste plus sur place
+- robot sur vaisseau puis sauvegarder-reprendre -> impossible gravir pentes
+
+GoldMaster 1.3 /e envoyé à CD PRESS pour 1000x
+
+1.2
+- bouton de fermeture (en haut à droite) supprimé en mode fenêtré
+- suppression du réglage "nice reset"
+
+1.1 (20.07.01)
+- volume du son non nul après installation
+- images logo au démarrage du jeu
+- image generic != si français ou anglais
+- install: nouvelle clé pour uninstall depuis autorun
+
+GoldMaster 1.1 /f envoyé à Alsyd
+
+1.0
+- commande "reset" (exercices) tjrs ok (fichier rechargé)
+- nom sauvegarde avec date/heure au format anglais
+- ScriptName.F et .E
+
diff --git a/src/water.cpp b/src/water.cpp
new file mode 100644
index 0000000..f3e4dc8
--- /dev/null
+++ b/src/water.cpp
@@ -0,0 +1,819 @@
+// water.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "D3DMath.h"
+#include "event.h"
+#include "misc.h"
+#include "iman.h"
+#include "math3d.h"
+#include "particule.h"
+#include "terrain.h"
+#include "object.h"
+#include "sound.h"
+#include "water.h"
+
+
+
+
+// Constructeur du terrain.
+
+CWater::CWater(CInstanceManager* iMan, CD3DEngine* engine)
+{
+ m_iMan = iMan;
+ m_iMan->AddInstance(CLASS_WATER, this);
+
+ m_engine = engine;
+ m_terrain = 0;
+ m_particule = 0;
+ m_sound = 0;
+
+ m_type[0] = WATER_NULL;
+ m_type[1] = WATER_NULL;
+ m_level = 0.0f;
+ m_bDraw = TRUE;
+ m_bLava = FALSE;
+ m_color = 0xffffffff;
+ m_subdiv = 4;
+ m_filename[0] = 0;
+}
+
+// Destructeur du terrain.
+
+CWater::~CWater()
+{
+}
+
+
+BOOL CWater::EventProcess(const Event &event)
+{
+ if ( event.event == EVENT_FRAME )
+ {
+ return EventFrame(event);
+ }
+
+ if ( event.event == EVENT_KEYDOWN )
+ {
+#if 0
+ if ( event.param == 'S' )
+ {
+ if ( m_subdiv == 1 ) m_subdiv = 2;
+ else if ( m_subdiv == 2 ) m_subdiv = 4;
+ else if ( m_subdiv == 4 ) m_subdiv = 8;
+ else if ( m_subdiv == 8 ) m_subdiv = 1;
+ SetLevel(m_level);
+ }
+ if ( event.param == 'M' )
+ {
+ SetLevel(m_level+1.0f);
+ }
+ if ( event.param == 'D' )
+ {
+ SetLevel(m_level-1.0f);
+ }
+ if ( event.param == 'H' )
+ {
+ m_bDraw = !m_bDraw;
+ }
+ if ( event.param == 'C' )
+ {
+ if ( m_color == 0xffffffff ) m_color = 0xcccccccc;
+ else if ( m_color == 0xcccccccc ) m_color = 0x88888888;
+ else if ( m_color == 0x88888888 ) m_color = 0x44444444;
+ else if ( m_color == 0x44444444 ) m_color = 0x00000000;
+ else if ( m_color == 0x00000000 ) m_color = 0xffffffff;
+ }
+ if ( event.param == 'Q' )
+ {
+ int i;
+ i = (m_color>>24);
+ i += 0x44;
+ i &= 0xff;
+ i = (i<<24);
+ m_color &= 0x00ffffff;
+ m_color |= i;
+ }
+ if ( event.param == 'W' )
+ {
+ int i;
+ i = (m_color>>16);
+ i += 0x44;
+ i &= 0xff;
+ i = (i<<16);
+ m_color &= 0xff00ffff;
+ m_color |= i;
+ }
+ if ( event.param == 'E' )
+ {
+ int i;
+ i = (m_color>>8);
+ i += 0x44;
+ i &= 0xff;
+ i = (i<<8);
+ m_color &= 0xffff00ff;
+ m_color |= i;
+ }
+ if ( event.param == 'R' )
+ {
+ int i;
+ i = m_color;
+ i += 0x44;
+ i &= 0xff;
+ m_color &= 0xffffff00;
+ m_color |= i;
+ }
+#endif
+ }
+ return TRUE;
+}
+
+// Fait évoluer l'eau.
+
+BOOL CWater::EventFrame(const Event &event)
+{
+ if ( m_engine->RetPause() ) return TRUE;
+
+ m_time += event.rTime;
+
+ if ( m_type[0] == WATER_NULL ) return TRUE;
+
+ if ( m_bLava )
+ {
+ LavaFrame(event.rTime);
+ }
+ return TRUE;
+}
+
+// Fait évoluer les jets de vapeur sur la lave.
+
+void CWater::LavaFrame(float rTime)
+{
+ D3DVECTOR eye, lookat, dir, perp, pos;
+ float distance, shift, level;
+ int i;
+
+ if ( m_particule == 0 )
+ {
+ m_particule = (CParticule*)m_iMan->SearchInstance(CLASS_PARTICULE);
+ }
+
+ for ( i=0 ; i<MAXWATVAPOR ; i++ )
+ {
+ VaporFrame(i, rTime);
+ }
+
+ if ( m_time-m_lastLava >= 0.1f )
+ {
+ eye = m_engine->RetEyePt();
+ lookat = m_engine->RetLookatPt();
+
+ distance = Rand()*200.0f;
+ shift = (Rand()-0.5f)*200.0f;
+
+ dir = Normalize(lookat-eye);
+ pos = eye + dir*distance;
+
+ perp.x = -dir.z;
+ perp.y = dir.y;
+ perp.z = dir.x;
+ pos = pos + perp*shift;
+
+ level = m_terrain->RetFloorLevel(pos, TRUE);
+ if ( level < m_level )
+ {
+ pos.y = m_level;
+
+ level = Rand();
+ if ( level < 0.8f )
+ {
+ if ( VaporCreate(PARTIFIRE, pos, 0.02f+Rand()*0.06f) )
+ {
+ m_lastLava = m_time;
+ }
+ }
+ else if ( level < 0.9f )
+ {
+ if ( VaporCreate(PARTIFLAME, pos, 0.5f+Rand()*3.0f) )
+ {
+ m_lastLava = m_time;
+ }
+ }
+ else
+ {
+ if ( VaporCreate(PARTIVAPOR, pos, 0.2f+Rand()*2.0f) )
+ {
+ m_lastLava = m_time;
+ }
+ }
+ }
+ }
+}
+
+// Supprime tous les jets de vapeur.
+
+void CWater::VaporFlush()
+{
+ int i;
+
+ for ( i=0 ; i<MAXWATVAPOR ; i++ )
+ {
+ m_vapor[i].bUsed = FALSE;
+ }
+}
+
+// Crée un nouveau jet de vapeur.
+
+BOOL CWater::VaporCreate(ParticuleType type, D3DVECTOR pos, float delay)
+{
+ int i;
+
+ for ( i=0 ; i<MAXWATVAPOR ; i++ )
+ {
+ if ( !m_vapor[i].bUsed )
+ {
+ m_vapor[i].bUsed = TRUE;
+ m_vapor[i].type = type;
+ m_vapor[i].pos = pos;
+ m_vapor[i].delay = delay;
+ m_vapor[i].time = 0.0f;
+ m_vapor[i].last = 0.0f;
+
+ if ( m_vapor[i].type == PARTIFIRE )
+ {
+ m_sound->Play(SOUND_BLUP, pos, 1.0f, 1.0f-Rand()*0.5f);
+ }
+ if ( m_vapor[i].type == PARTIFLAME )
+ {
+//? m_sound->Play(SOUND_SWIM, pos, 1.0f, 1.0f-Rand()*0.5f);
+ }
+ if ( m_vapor[i].type == PARTIVAPOR )
+ {
+ m_sound->Play(SOUND_PSHHH, pos, 0.3f, 2.0f);
+ }
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Fait évoluer un jet de vapeur,
+
+void CWater::VaporFrame(int i, float rTime)
+{
+ D3DVECTOR pos, speed;
+ FPOINT dim;
+ int j;
+
+ m_vapor[i].time += rTime;
+
+ if ( m_sound == 0 )
+ {
+ m_sound = (CSound*)m_iMan->SearchInstance(CLASS_SOUND);
+ }
+
+ if ( m_vapor[i].time <= m_vapor[i].delay )
+ {
+ if ( m_time-m_vapor[i].last >= m_engine->ParticuleAdapt(0.02f) )
+ {
+ m_vapor[i].last = m_time;
+
+ if ( m_vapor[i].type == PARTIFIRE )
+ {
+ for ( j=0 ; j<10 ; j++ )
+ {
+ pos = m_vapor[i].pos;
+ pos.x += (Rand()-0.5f)*2.0f;
+ pos.z += (Rand()-0.5f)*2.0f;
+ pos.y -= 1.0f;
+ speed.x = (Rand()-0.5f)*6.0f;
+ speed.z = (Rand()-0.5f)*6.0f;
+ speed.y = 8.0f+Rand()*5.0f;
+ dim.x = Rand()*1.5f+1.5f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIERROR, 2.0f, 10.0f);
+ }
+ }
+ else if ( m_vapor[i].type == PARTIFLAME )
+ {
+ pos = m_vapor[i].pos;
+ pos.x += (Rand()-0.5f)*8.0f;
+ pos.z += (Rand()-0.5f)*8.0f;
+ pos.y -= 2.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 4.0f+Rand()*4.0f;
+ dim.x = Rand()*2.0f+2.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIFLAME);
+ }
+ else
+ {
+ pos = m_vapor[i].pos;
+ pos.x += (Rand()-0.5f)*4.0f;
+ pos.z += (Rand()-0.5f)*4.0f;
+ pos.y -= 2.0f;
+ speed.x = (Rand()-0.5f)*2.0f;
+ speed.z = (Rand()-0.5f)*2.0f;
+ speed.y = 8.0f+Rand()*8.0f;
+ dim.x = Rand()*1.0f+1.0f;
+ dim.y = dim.x;
+ m_particule->CreateParticule(pos, speed, dim, PARTIVAPOR);
+ }
+ }
+ }
+ else
+ {
+ m_vapor[i].bUsed = FALSE;
+ }
+}
+
+
+// Ajuste la position et la normale, pour imiter des reflets
+// sur une étendue d'eau au repos.
+
+void CWater::AdjustLevel(D3DVECTOR &pos, D3DVECTOR &norm,
+ FPOINT &uv1, FPOINT &uv2)
+{
+#if 0
+ float t1, t2;
+
+ uv1.x = (pos.x+10000.0f)/40.0f;
+ uv1.y = (pos.z+10000.0f)/40.0f;
+
+ t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f;
+ pos.y += sinf(t1)*m_eddy.y;
+
+ t1 = m_time*0.6f + pos.x*0.1f * pos.z*0.2f;
+ t2 = m_time*0.7f + pos.x*0.3f * pos.z*0.4f;
+ pos.x += sinf(t1)*m_eddy.x;
+ pos.z += sinf(t2)*m_eddy.z;
+
+//? uv2.x = (pos.x+10000.0f)/40.0f+0.3f;
+//? uv2.y = (pos.z+10000.0f)/40.0f+0.4f;
+ uv2.x = (pos.x+10000.0f)/20.0f;
+ uv2.y = (pos.z+10000.0f)/20.0f;
+
+ t1 = m_time*0.7f + pos.x*5.5f + pos.z*5.6f;
+ t2 = m_time*0.8f + pos.x*5.7f + pos.z*5.8f;
+ norm = D3DVECTOR(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint);
+#else
+ float t1, t2;
+
+ t1 = m_time*1.5f + pos.x*0.1f * pos.z*0.2f;
+ pos.y += sinf(t1)*m_eddy.y;
+
+ t1 = m_time*1.5f;
+ uv1.x = (pos.x+10000.0f)/40.0f+sinf(t1)*m_eddy.x*0.02f;
+ uv1.y = (pos.z+10000.0f)/40.0f-cosf(t1)*m_eddy.z*0.02f;
+ uv2.x = (pos.x+10010.0f)/20.0f+cosf(-t1)*m_eddy.x*0.02f;
+ uv2.y = (pos.z+10010.0f)/20.0f-sinf(-t1)*m_eddy.z*0.02f;
+
+ t1 = m_time*0.50f + pos.x*2.1f + pos.z*1.1f;
+ t2 = m_time*0.75f + pos.x*2.0f + pos.z*1.0f;
+ norm = D3DVECTOR(sinf(t1)*m_glint, 1.0f, sinf(t2)*m_glint);
+#endif
+}
+
+// Dessine la surface arrière de l'eau.
+// Cette surface empèche de voir le ciel (background) sous l'eau !
+
+void CWater::DrawBack()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2 vertex[4]; // 2 triangles
+ D3DMATERIAL7 material;
+ D3DMATRIX matrix;
+ D3DVECTOR eye, lookat, n, p, p1, p2;
+ FPOINT uv1, uv2;
+ float deep, dist;
+
+ if ( !m_bDraw ) return;
+ if ( m_type[0] == WATER_NULL ) return;
+ if ( m_lineUsed == 0 ) return;
+
+ eye = m_engine->RetEyePt();
+ lookat = m_engine->RetLookatPt();
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse = m_diffuse;
+ material.ambient = m_ambient;
+ m_engine->SetMaterial(material);
+
+ m_engine->SetTexture("", 0);
+
+ device = m_engine->RetD3DDevice();
+ device->SetRenderState(D3DRENDERSTATE_LIGHTING, FALSE);
+ device->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+ m_engine->SetState(D3DSTATENORMAL);
+
+ deep = m_engine->RetDeepView(0);
+ m_engine->SetDeepView(deep*2.0f, 0);
+ m_engine->SetFocus(m_engine->RetFocus());
+ m_engine->UpdateMatProj(); // double la profondeur de vue
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ p.x = eye.x;
+ p.z = eye.z;
+ dist = Length2d(eye, lookat);
+ p.x = (lookat.x-eye.x)*deep*1.0f/dist + eye.x;
+ p.z = (lookat.z-eye.z)*deep*1.0f/dist + eye.z;
+
+ p1.x = (lookat.z-eye.z)*deep*2.0f/dist + p.x;
+ p1.z = -(lookat.x-eye.x)*deep*2.0f/dist + p.z;
+ p2.x = -(lookat.z-eye.z)*deep*2.0f/dist + p.x;
+ p2.z = (lookat.x-eye.x)*deep*2.0f/dist + p.z;
+
+ p1.y = -50.0f;
+ p2.y = m_level;
+
+ n.x = (lookat.x-eye.x)/dist;
+ n.z = (lookat.z-eye.z)/dist;
+ n.y = 0.0f;
+
+ uv1.x = uv1.y = 0.0f;
+ uv2.x = uv2.y = 0.0f;
+
+ vertex[0] = D3DVERTEX2(D3DVECTOR(p1.x, p2.y, p1.z), n, uv1.x,uv2.y);
+ vertex[1] = D3DVERTEX2(D3DVECTOR(p1.x, p1.y, p1.z), n, uv1.x,uv1.y);
+ vertex[2] = D3DVERTEX2(D3DVECTOR(p2.x, p2.y, p2.z), n, uv2.x,uv2.y);
+ vertex[3] = D3DVERTEX2(D3DVECTOR(p2.x, p1.y, p2.z), n, uv2.x,uv1.y);
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, 4, NULL);
+ m_engine->AddStatisticTriangle(2);
+
+ m_engine->SetDeepView(deep, 0);
+ m_engine->SetFocus(m_engine->RetFocus());
+ m_engine->UpdateMatProj(); // remet profondeur de vue initiale
+
+ device->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+ device->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+}
+
+// Dessine la surface plane de l'eau.
+
+void CWater::DrawSurf()
+{
+ LPDIRECT3DDEVICE7 device;
+ D3DVERTEX2* vertex; // triangles
+ D3DMATERIAL7 material;
+ D3DMATRIX matrix;
+ D3DVECTOR eye, lookat, n, pos, p;
+ FPOINT uv1, uv2;
+ BOOL bUnder;
+ DWORD flags;
+ float deep, size, sizez, radius;
+ int rankview, i, j, u;
+
+ if ( !m_bDraw ) return;
+ if ( m_type[0] == WATER_NULL ) return;
+ if ( m_lineUsed == 0 ) return;
+
+ vertex = (D3DVERTEX2*)malloc(sizeof(D3DVERTEX2)*(m_brick+2)*2);
+
+ eye = m_engine->RetEyePt();
+ lookat = m_engine->RetLookatPt();
+
+ rankview = m_engine->RetRankView();
+ bUnder = ( rankview == 1);
+
+ device = m_engine->RetD3DDevice();
+//? device->SetRenderState(D3DRENDERSTATE_AMBIENT, 0xffffffff);
+//? device->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
+//? device->SetRenderState(D3DRENDERSTATE_ZENABLE, FALSE);
+ device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE);
+
+ D3DUtil_SetIdentityMatrix(matrix);
+ device->SetTransform(D3DTRANSFORMSTATE_WORLD, &matrix);
+
+ ZeroMemory( &material, sizeof(D3DMATERIAL7) );
+ material.diffuse = m_diffuse;
+ material.ambient = m_ambient;
+ m_engine->SetMaterial(material);
+
+ m_engine->SetTexture(m_filename, 0);
+ m_engine->SetTexture(m_filename, 1);
+
+ if ( m_type[rankview] == WATER_TT )
+ {
+ m_engine->SetState(D3DSTATETTb|D3DSTATEDUALw|D3DSTATEWRAP, m_color);
+ }
+ if ( m_type[rankview] == WATER_TO )
+ {
+ m_engine->SetState(D3DSTATENORMAL|D3DSTATEDUALw|D3DSTATEWRAP);
+ }
+ if ( m_type[rankview] == WATER_CT )
+ {
+ m_engine->SetState(D3DSTATETTb);
+ }
+ if ( m_type[rankview] == WATER_CO )
+ {
+ m_engine->SetState(D3DSTATENORMAL);
+ }
+ device->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
+
+ size = m_size/2.0f;
+ if ( bUnder ) sizez = -size;
+ else sizez = size;
+
+ // Dessine toutes les lignes.
+ deep = m_engine->RetDeepView(0)*1.5f;
+
+ for ( i=0 ; i<m_lineUsed ; i++ )
+ {
+ pos.y = m_level;
+ pos.z = m_line[i].pz;
+ pos.x = m_line[i].px1;
+
+ // Ligne visible ?
+ p = pos;
+ p.x += size*(m_line[i].len-1);
+ radius = sqrtf(powf(size, 2.0f)+powf(size*m_line[i].len, 2.0f));
+ if ( Length(p, eye) > deep+radius ) continue;
+ device->ComputeSphereVisibility(&p, &radius, 1, 0, &flags);
+ if ( flags & D3DSTATUS_CLIPINTERSECTIONALL ) continue;
+
+ u = 0;
+ p.x = pos.x-size;
+ p.z = pos.z-sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x-size;
+ p.z = pos.z+sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ for ( j=0 ; j<m_line[i].len ; j++ )
+ {
+ p.x = pos.x+size;
+ p.z = pos.z-sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ p.x = pos.x+size;
+ p.z = pos.z+sizez;
+ p.y = pos.y;
+ AdjustLevel(p, n, uv1, uv2);
+ if ( bUnder ) n.y = -n.y;
+ vertex[u++] = D3DVERTEX2(p, n, uv1.x,uv1.y, uv2.x,uv2.y);
+
+ pos.x += size*2.0f;
+ }
+
+ device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_VERTEX2, vertex, u, NULL);
+ m_engine->AddStatisticTriangle(u-2);
+ }
+
+ free(vertex);
+}
+
+
+// Indique s'il y a de l'eau à une position donnée.
+
+BOOL CWater::RetWater(int x, int y)
+{
+ D3DVECTOR pos;
+ float size, offset, level;
+ int dx, dy;
+
+ x *= m_subdiv;
+ y *= m_subdiv;
+
+ size = m_size/m_subdiv;
+ offset = m_brick*m_size/2.0f;
+
+ for ( dy=0 ; dy<=m_subdiv ; dy++ )
+ {
+ for ( dx=0 ; dx<=m_subdiv ; dx++ )
+ {
+ pos.x = (x+dx)*size - offset;
+ pos.z = (y+dy)*size - offset;
+ pos.y = 0.0f;
+ level = m_terrain->RetFloorLevel(pos, TRUE);
+ if ( level < m_level+m_eddy.y ) return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// Met à jour les positions par-rapport au terrain.
+
+BOOL CWater::CreateLine(int x, int y, int len)
+{
+ float offset;
+
+ m_line[m_lineUsed].x = x;
+ m_line[m_lineUsed].y = y;
+ m_line[m_lineUsed].len = len;
+
+ offset = m_brick*m_size/2.0f - m_size/2.0f;
+
+ m_line[m_lineUsed].px1 = m_size* m_line[m_lineUsed].x - offset;
+ m_line[m_lineUsed].px2 = m_size*(m_line[m_lineUsed].x+m_line[m_lineUsed].len) - offset;
+ m_line[m_lineUsed].pz = m_size* m_line[m_lineUsed].y - offset;
+
+ m_lineUsed ++;
+
+ return ( m_lineUsed < MAXWATERLINE );
+}
+
+// Crée toutes les étendues d'eau.
+
+BOOL CWater::Create(WaterType type1, WaterType type2, const char *filename,
+ D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient,
+ float level, float glint, D3DVECTOR eddy)
+{
+ int x, y, len;
+
+ m_type[0] = type1;
+ m_type[1] = type2;
+ m_diffuse = diffuse;
+ m_ambient = ambient;
+ m_level = level;
+ m_glint = glint;
+ m_eddy = eddy;
+ m_time = 0.0f;
+ m_lastLava = 0.0f;
+ strcpy(m_filename, filename);
+
+ VaporFlush();
+
+ if ( m_filename[0] != 0 )
+ {
+ m_engine->LoadTexture(m_filename, 0);
+ m_engine->LoadTexture(m_filename, 1);
+ }
+
+ if ( m_terrain == 0 )
+ {
+ m_terrain = (CTerrain*)m_iMan->SearchInstance(CLASS_TERRAIN);
+ }
+ m_brick = m_terrain->RetBrick()*m_terrain->RetMosaic();
+ m_size = m_terrain->RetSize();
+
+ m_brick /= m_subdiv;
+ m_size *= m_subdiv;
+
+ if ( m_type[0] == WATER_NULL ) return TRUE;
+
+ m_lineUsed = 0;
+ for ( y=0 ; y<m_brick ; y++ )
+ {
+ len = 0;
+ for ( x=0 ; x<m_brick ; x++ )
+ {
+ if ( RetWater(x,y) ) // eau ici ?
+ {
+ len ++;
+ if ( len >= 5 )
+ {
+ if ( !CreateLine(x-len+1, y, len) ) return FALSE;
+ len = 0;
+ }
+ }
+ else // sec ?
+ {
+ if ( len != 0 )
+ {
+ if ( !CreateLine(x-len, y, len) ) return FALSE;
+ len = 0;
+ }
+ }
+ }
+ if ( len != 0 )
+ {
+ if ( !CreateLine(x-len, y, len) ) return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+// Supprime toute l'eau.
+
+void CWater::Flush()
+{
+ m_type[0] = WATER_NULL;
+ m_type[1] = WATER_NULL;
+ m_level = 0.0f;
+ m_bLava = FALSE;
+}
+
+
+// Modifie le niveau de l'eau.
+
+BOOL CWater::SetLevel(float level)
+{
+ m_level = level;
+
+ return Create(m_type[0], m_type[1], m_filename, m_diffuse, m_ambient,
+ m_level, m_glint, m_eddy);
+}
+
+// Retourne le niveau actuel de l'eau.
+
+float CWater::RetLevel()
+{
+ return m_level;
+}
+
+// Retourne le niveau actuel de l'eau pour un objet donné.
+
+float CWater::RetLevel(CObject* object)
+{
+ ObjectType type;
+
+ type = object->RetType();
+
+ if ( type == OBJECT_HUMAN ||
+ type == OBJECT_TECH )
+ {
+ return m_level-3.0f;
+ }
+
+ if ( type == OBJECT_MOBILEfa ||
+ type == OBJECT_MOBILEta ||
+ type == OBJECT_MOBILEwa ||
+ type == OBJECT_MOBILEia ||
+ type == OBJECT_MOBILEfc ||
+ type == OBJECT_MOBILEtc ||
+ type == OBJECT_MOBILEwc ||
+ type == OBJECT_MOBILEic ||
+ type == OBJECT_MOBILEfi ||
+ type == OBJECT_MOBILEti ||
+ type == OBJECT_MOBILEwi ||
+ type == OBJECT_MOBILEii ||
+ type == OBJECT_MOBILEfs ||
+ type == OBJECT_MOBILEts ||
+ type == OBJECT_MOBILEws ||
+ type == OBJECT_MOBILEis ||
+ type == OBJECT_MOBILErt ||
+ type == OBJECT_MOBILErc ||
+ type == OBJECT_MOBILErr ||
+ type == OBJECT_MOBILErs ||
+ type == OBJECT_MOBILEsa ||
+ type == OBJECT_MOBILEtg ||
+ type == OBJECT_MOBILEft ||
+ type == OBJECT_MOBILEtt ||
+ type == OBJECT_MOBILEwt ||
+ type == OBJECT_MOBILEit ||
+ type == OBJECT_MOBILEdr )
+ {
+ return m_level-2.0f;
+ }
+
+ return m_level;
+}
+
+
+// Gestion du mode lave/eau.
+
+void CWater::SetLava(BOOL bLava)
+{
+ m_bLava = bLava;
+}
+
+BOOL CWater::RetLava()
+{
+ return m_bLava;
+}
+
+
+// Ajuste l'oeil de la caméra, pour ne pas être entre deux eaux.
+
+void CWater::AdjustEye(D3DVECTOR &eye)
+{
+ if ( m_bLava )
+ {
+ if ( eye.y < m_level+2.0f )
+ {
+ eye.y = m_level+2.0f; // jamais sous la lave
+ }
+ }
+ else
+ {
+ if ( eye.y >= m_level-2.0f &&
+ eye.y <= m_level+2.0f ) // proche de la surface ?
+ {
+ eye.y = m_level+2.0f; // paf, bien dessus
+ }
+ }
+}
+
diff --git a/src/water.h b/src/water.h
new file mode 100644
index 0000000..f5751ae
--- /dev/null
+++ b/src/water.h
@@ -0,0 +1,118 @@
+// water.h
+
+#ifndef _WATER_H_
+#define _WATER_H_
+
+
+class CInstanceManager;
+class CD3DEngine;
+class CTerrain;
+class CParticule;
+class CSound;
+
+enum ParticuleType;
+
+
+
+#define MAXWATERLINE 500
+
+typedef struct
+{
+ short x, y; // début
+ short len; // longueur en x
+ float px1, px2, pz;
+}
+WaterLine;
+
+
+#define MAXWATVAPOR 10
+
+typedef struct
+{
+ BOOL bUsed;
+ ParticuleType type;
+ D3DVECTOR pos;
+ float delay;
+ float time;
+ float last;
+}
+WaterVapor;
+
+
+enum WaterType
+{
+ WATER_NULL = 0, // pas d'eau
+ WATER_TT = 1, // texture transparente
+ WATER_TO = 2, // texture opaque
+ WATER_CT = 3, // couleur transparente
+ WATER_CO = 4, // couleur opaque
+};
+
+
+class CWater
+{
+public:
+ CWater(CInstanceManager* iMan, CD3DEngine* engine);
+ ~CWater();
+
+ void SetD3DDevice(LPDIRECT3DDEVICE7 device);
+ BOOL EventProcess(const Event &event);
+ void Flush();
+ BOOL Create(WaterType type1, WaterType type2, const char *filename, D3DCOLORVALUE diffuse, D3DCOLORVALUE ambient, float level, float glint, D3DVECTOR eddy);
+ void DrawBack();
+ void DrawSurf();
+
+ BOOL SetLevel(float level);
+ float RetLevel();
+ float RetLevel(CObject* object);
+
+ void SetLava(BOOL bLava);
+ BOOL RetLava();
+
+ void AdjustEye(D3DVECTOR &eye);
+
+protected:
+ BOOL EventFrame(const Event &event);
+ void LavaFrame(float rTime);
+ void AdjustLevel(D3DVECTOR &pos, D3DVECTOR &norm, FPOINT &uv1, FPOINT &uv2);
+ BOOL RetWater(int x, int y);
+ BOOL CreateLine(int x, int y, int len);
+
+ void VaporFlush();
+ BOOL VaporCreate(ParticuleType type, D3DVECTOR pos, float delay);
+ void VaporFrame(int i, float rTime);
+
+protected:
+ CInstanceManager* m_iMan;
+ CD3DEngine* m_engine;
+ LPDIRECT3DDEVICE7 m_pD3DDevice;
+ CTerrain* m_terrain;
+ CParticule* m_particule;
+ CSound* m_sound;
+
+ WaterType m_type[2];
+ char m_filename[100];
+ float m_level; // niveau global
+ float m_glint; // amplitude des reflets
+ D3DVECTOR m_eddy; // amplitude des remous
+ D3DCOLORVALUE m_diffuse; // couleur diffuse
+ D3DCOLORVALUE m_ambient; // couleur ambiante
+ float m_time;
+ float m_lastLava;
+ int m_subdiv;
+
+ int m_brick; // nb de briques*mosaïque
+ float m_size; // taille d'un élément dans une brique
+
+ int m_lineUsed;
+ WaterLine m_line[MAXWATERLINE];
+
+ WaterVapor m_vapor[MAXWATVAPOR];
+
+ BOOL m_bDraw;
+ BOOL m_bLava;
+ D3DCOLOR m_color;
+};
+
+
+#endif //_WATER_H_
diff --git a/src/window.cpp b/src/window.cpp
new file mode 100644
index 0000000..1740919
--- /dev/null
+++ b/src/window.cpp
@@ -0,0 +1,1610 @@
+// window.cpp
+
+#define STRICT
+#define D3D_OVERLOADS
+
+#include <windows.h>
+#include <stdio.h>
+#include <d3d.h>
+
+#include "struct.h"
+#include "D3DEngine.h"
+#include "language.h"
+#include "math3d.h"
+#include "event.h"
+#include "misc.h"
+#include "restext.h"
+#include "iman.h"
+#include "button.h"
+#include "color.h"
+#include "check.h"
+#include "key.h"
+#include "group.h"
+#include "image.h"
+#include "label.h"
+#include "edit.h"
+#include "editvalue.h"
+#include "scroll.h"
+#include "slider.h"
+#include "list.h"
+#include "shortcut.h"
+#include "map.h"
+#include "gauge.h"
+#include "compass.h"
+#include "target.h"
+#include "text.h"
+#include "window.h"
+
+
+
+
+// Constructeur de l'objet.
+
+CWindow::CWindow(CInstanceManager* iMan) : CControl(iMan)
+{
+ int i;
+
+ CControl::CControl(iMan);
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ m_table[i] = 0;
+ }
+
+ m_bTrashEvent = TRUE;
+ m_bMaximized = FALSE;
+ m_bMinimized = FALSE;
+ m_bFixed = FALSE;
+
+ m_minDim = FPOINT(0.0f, 0.0f);
+ m_maxDim = FPOINT(1.0f, 1.0f);
+
+ m_buttonReduce = 0;
+ m_buttonFull = 0;
+ m_buttonClose = 0;
+
+ m_bMovable = FALSE;
+ m_bRedim = FALSE;
+ m_bClosable = FALSE;
+ m_bCapture = FALSE;
+
+ m_fontStretch = NORMSTRETCH*1.2f;
+}
+
+// Destructeur de l'objet.
+
+CWindow::~CWindow()
+{
+ Flush();
+ CControl::~CControl();
+}
+
+
+// Purge tous les contrôles.
+
+void CWindow::Flush()
+{
+ int i;
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ delete m_table[i];
+ m_table[i] = 0;
+ }
+ }
+
+ if ( m_buttonReduce != 0 )
+ {
+ delete m_buttonReduce;
+ m_buttonReduce = 0;
+ }
+
+ if ( m_buttonFull != 0 )
+ {
+ delete m_buttonFull;
+ m_buttonFull = 0;
+ }
+
+ if ( m_buttonClose != 0 )
+ {
+ delete m_buttonClose;
+ m_buttonClose = 0;
+ }
+}
+
+
+// Crée une nouvelle fenêtre.
+
+BOOL CWindow::Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ CControl::Create(pos, dim, icon, eventMsg);
+ return TRUE;
+}
+
+
+// Crée un nouveau bouton.
+
+CButton* CWindow::CreateButton(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CButton* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CButton(m_iMan);
+ pc = (CButton*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CColor* CWindow::CreateColor(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CColor* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CColor(m_iMan);
+ pc = (CColor*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CCheck* CWindow::CreateCheck(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CCheck* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CCheck(m_iMan);
+ pc = (CCheck*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CKey* CWindow::CreateKey(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CKey* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CKey(m_iMan);
+ pc = (CKey*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CGroup* CWindow::CreateGroup(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CGroup* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CGroup(m_iMan);
+ pc = (CGroup*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau bouton.
+
+CImage* CWindow::CreateImage(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CImage* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CImage(m_iMan);
+ pc = (CImage*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau label.
+
+CLabel* CWindow::CreateLabel(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg,
+ char *name)
+{
+ CLabel* pc;
+ char* p;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CLabel(m_iMan);
+ pc = (CLabel*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+
+ p = strchr(name, '\\');
+ if ( p == 0 )
+ {
+ pc->SetName(name);
+ }
+ else
+ {
+ char text[100];
+ strncpy(text, name, 100);
+ text[100-1] = 0;
+ if ( p-name < 100 )
+ {
+ text[p-name] = 0; // supprime texte après "\\" (tooltip)
+ }
+ pc->SetName(text);
+ }
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau pavé éditable.
+
+CEdit* CWindow::CreateEdit(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CEdit* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CEdit(m_iMan);
+ pc = (CEdit*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau pavé éditable.
+
+CEditValue* CWindow::CreateEditValue(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CEditValue* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CEditValue(m_iMan);
+ pc = (CEditValue*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouvel ascenseur.
+
+CScroll* CWindow::CreateScroll(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CScroll* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CScroll(m_iMan);
+ pc = (CScroll*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau curseur.
+
+CSlider* CWindow::CreateSlider(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CSlider* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CSlider(m_iMan);
+ pc = (CSlider*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle liste.
+
+CList* CWindow::CreateList(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg,
+ float expand)
+{
+ CList* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CList(m_iMan);
+ pc = (CList*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg, expand);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée un nouveau raccourci.
+
+CShortcut* CWindow::CreateShortcut(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CShortcut* ps;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CShortcut(m_iMan);
+ ps = (CShortcut*)m_table[i];
+ ps->Create(pos, dim, icon, eventMsg);
+ return ps;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle carte.
+
+CMap* CWindow::CreateMap(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CMap* pm;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CMap(m_iMan);
+ pm = (CMap*)m_table[i];
+ pm->Create(pos, dim, icon, eventMsg);
+ return pm;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle jauge.
+
+CGauge* CWindow::CreateGauge(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CGauge* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CGauge(m_iMan);
+ pc = (CGauge*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle boussole.
+
+CCompass* CWindow::CreateCompass(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CCompass* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CCompass(m_iMan);
+ pc = (CCompass*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Crée une nouvelle cible.
+
+CTarget* CWindow::CreateTarget(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg)
+{
+ CTarget* pc;
+ int i;
+
+ if ( eventMsg == EVENT_NULL ) eventMsg = GetUniqueEventMsg();
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] == 0 )
+ {
+ m_table[i] = new CTarget(m_iMan);
+ pc = (CTarget*)m_table[i];
+ pc->Create(pos, dim, icon, eventMsg);
+ return pc;
+ }
+ }
+ return 0;
+}
+
+// Supprime un contrôle.
+
+BOOL CWindow::DeleteControl(EventMsg eventMsg)
+{
+ int i;
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( eventMsg == m_table[i]->RetEventMsg() )
+ {
+ delete m_table[i];
+ m_table[i] = 0;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+// Donne un contrôle.
+
+CControl* CWindow::SearchControl(EventMsg eventMsg)
+{
+ int i;
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( eventMsg == m_table[i]->RetEventMsg() )
+ {
+ return m_table[i];
+ }
+ }
+ }
+ return 0;
+}
+
+
+// Donne le tooltip lié à la fenêtre.
+
+BOOL CWindow::GetTooltip(FPOINT pos, char* name)
+{
+ int i;
+
+ for ( i=MAXWINDOW-1 ; i>=0 ; i-- )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( m_table[i]->GetTooltip(pos, name) )
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ if ( m_buttonClose != 0 &&
+ m_buttonClose->GetTooltip(pos, name) )
+ {
+ return TRUE;
+ }
+ if ( m_buttonFull != 0 &&
+ m_buttonFull->GetTooltip(pos, name) )
+ {
+ return TRUE;
+ }
+ if ( m_buttonReduce != 0 &&
+ m_buttonReduce->GetTooltip(pos, name) )
+ {
+ return TRUE;
+ }
+
+ if ( Detect(pos) ) // dans la fenêtre ?
+ {
+ strcpy(name, m_tooltip);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+// Spécifie le nom pour la barre de titre.
+
+void CWindow::SetName(char* name)
+{
+ CButton* pc;
+ BOOL bAdjust;
+
+ CControl::SetName(name);
+
+ if ( m_buttonReduce != 0 )
+ {
+ delete m_buttonReduce;
+ m_buttonReduce = 0;
+ }
+
+ if ( m_buttonFull != 0 )
+ {
+ delete m_buttonFull;
+ m_buttonFull = 0;
+ }
+
+ if ( m_buttonClose != 0 )
+ {
+ delete m_buttonClose;
+ m_buttonClose = 0;
+ }
+
+ bAdjust = FALSE;
+
+ if ( m_name[0] != 0 && m_bRedim ) // barre de titre existe ?
+ {
+ m_buttonReduce = new CButton(m_iMan);
+ pc = (CButton*)m_buttonReduce;
+ pc->Create(m_pos, m_dim, 0, EVENT_NULL);
+
+ m_buttonFull = new CButton(m_iMan);
+ pc = (CButton*)m_buttonFull;
+ pc->Create(m_pos, m_dim, 0, EVENT_NULL);
+
+ bAdjust = TRUE;
+ }
+
+ if ( m_name[0] != 0 && m_bClosable ) // barre de titre existe ?
+ {
+ m_buttonClose = new CButton(m_iMan);
+ pc = (CButton*)m_buttonClose;
+ pc->Create(m_pos, m_dim, 0, EVENT_NULL);
+
+ bAdjust = TRUE;
+ }
+
+ if ( bAdjust )
+ {
+ AdjustButtons();
+ }
+
+ MoveAdjust();
+}
+
+
+void CWindow::SetPos(FPOINT pos)
+{
+ CControl::SetPos(pos);
+ MoveAdjust();
+}
+
+void CWindow::SetDim(FPOINT dim)
+{
+ if ( dim.x < m_minDim.x ) dim.x = m_minDim.x;
+ if ( dim.x > m_maxDim.x ) dim.x = m_maxDim.x;
+ if ( dim.y < m_minDim.y ) dim.y = m_minDim.y;
+ if ( dim.y > m_maxDim.y ) dim.y = m_maxDim.y;
+
+ CControl::SetDim(dim);
+ MoveAdjust();
+}
+
+void CWindow::MoveAdjust()
+{
+ FPOINT pos, dim;
+ float h, offset;
+
+ h = m_engine->RetText()->RetHeight(m_fontSize, m_fontType);
+ dim.y = h*1.2f;
+ dim.x = dim.y*0.75f;
+
+ if ( m_buttonClose != 0 )
+ {
+ pos.x = m_pos.x+m_dim.x-0.01f-dim.x;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
+ m_buttonClose->SetPos(pos);
+ m_buttonClose->SetDim(dim);
+ offset = dim.x*1.0f;
+ }
+ else
+ {
+ offset = 0.0f;
+ }
+
+ if ( m_buttonFull != 0 )
+ {
+ pos.x = m_pos.x+m_dim.x-0.01f-dim.x-offset;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
+ m_buttonFull->SetPos(pos);
+ m_buttonFull->SetDim(dim);
+ }
+
+ if ( m_buttonReduce != 0 )
+ {
+ pos.x = m_pos.x+m_dim.x-0.01f-dim.x*2.0f-offset;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
+ m_buttonReduce->SetPos(pos);
+ m_buttonReduce->SetDim(dim);
+ }
+}
+
+
+void CWindow::SetMinDim(FPOINT dim)
+{
+ m_minDim = dim;
+}
+
+void CWindow::SetMaxDim(FPOINT dim)
+{
+ m_maxDim = dim;
+}
+
+FPOINT CWindow::RetMinDim()
+{
+ return m_minDim;
+}
+
+FPOINT CWindow::RetMaxDim()
+{
+ return m_maxDim;
+}
+
+
+// Indique si la fenêtre est déplaçable.
+
+void CWindow::SetMovable(BOOL bMode)
+{
+ m_bMovable = bMode;
+}
+
+BOOL CWindow::RetMovable()
+{
+ return m_bMovable;
+}
+
+
+// Gestion de la présence des boutons minimise/maximise.
+
+void CWindow::SetRedim(BOOL bMode)
+{
+ m_bRedim = bMode;
+}
+
+BOOL CWindow::RetRedim()
+{
+ return m_bRedim;
+}
+
+
+// Gestion de la présence du bouton de fermeture.
+
+void CWindow::SetClosable(BOOL bMode)
+{
+ m_bClosable = bMode;
+}
+
+BOOL CWindow::RetClosable()
+{
+ return m_bClosable;
+}
+
+
+void CWindow::SetMaximized(BOOL bMaxi)
+{
+ m_bMaximized = bMaxi;
+ AdjustButtons();
+}
+
+BOOL CWindow::RetMaximized()
+{
+ return m_bMaximized;
+}
+
+void CWindow::SetMinimized(BOOL bMini)
+{
+ m_bMinimized = bMini;
+ AdjustButtons();
+}
+
+BOOL CWindow::RetMinimized()
+{
+ return m_bMinimized;
+}
+
+void CWindow::SetFixed(BOOL bFix)
+{
+ m_bFixed = bFix;
+}
+
+BOOL CWindow::RetFixed()
+{
+ return m_bFixed;
+}
+
+
+// Ajuste les boutons dans la barre de titre.
+
+void CWindow::AdjustButtons()
+{
+ char res[100];
+
+ if ( m_buttonFull != 0 )
+ {
+ if ( m_bMaximized )
+ {
+ m_buttonFull->SetIcon(54);
+ GetResource(RES_TEXT, RT_WINDOW_STANDARD, res);
+ m_buttonFull->SetTooltip(res);
+ }
+ else
+ {
+ m_buttonFull->SetIcon(52);
+ GetResource(RES_TEXT, RT_WINDOW_MAXIMIZED, res);
+ m_buttonFull->SetTooltip(res);
+ }
+ }
+
+ if ( m_buttonReduce != 0 )
+ {
+ if ( m_bMinimized )
+ {
+ m_buttonReduce->SetIcon(54);
+ GetResource(RES_TEXT, RT_WINDOW_STANDARD, res);
+ m_buttonReduce->SetTooltip(res);
+ }
+ else
+ {
+ m_buttonReduce->SetIcon(51);
+ GetResource(RES_TEXT, RT_WINDOW_MINIMIZED, res);
+ m_buttonReduce->SetTooltip(res);
+ }
+ }
+
+ if ( m_buttonClose != 0 )
+ {
+ m_buttonClose->SetIcon(11); // x
+ GetResource(RES_TEXT, RT_WINDOW_CLOSE, res);
+ m_buttonClose->SetTooltip(res);
+ }
+}
+
+
+void CWindow::SetTrashEvent(BOOL bTrash)
+{
+ m_bTrashEvent = bTrash;
+}
+
+BOOL CWindow::RetTrashEvent()
+{
+ return m_bTrashEvent;
+}
+
+
+// Retourne le message du bouton "reduce".
+
+EventMsg CWindow::RetEventMsgReduce()
+{
+ if ( m_buttonReduce == 0 ) return EVENT_NULL;
+ return m_buttonReduce->RetEventMsg();
+}
+
+// Retourne le message du bouton "full".
+
+EventMsg CWindow::RetEventMsgFull()
+{
+ if ( m_buttonFull == 0 ) return EVENT_NULL;
+ return m_buttonFull->RetEventMsg();
+}
+
+// Retourne le message du bouton "close".
+
+EventMsg CWindow::RetEventMsgClose()
+{
+ if ( m_buttonClose == 0 ) return EVENT_NULL;
+ return m_buttonClose->RetEventMsg();
+}
+
+
+// Détecte si la souris est dans un bord de la fenêtre, pour
+// la redimensionner.
+// Bits retournée: 0=gauche, 1=bas, 2=droite, 3=haut, -1=tout.
+
+int CWindow::BorderDetect(FPOINT pos)
+{
+ FPOINT dim;
+ float h;
+ int flags;
+
+ if ( m_bMaximized || m_bMinimized || m_bFixed ) return 0;
+
+ flags = 0;
+ if ( pos.x < m_pos.x+0.030f )
+ {
+ flags |= (1<<0);
+ }
+ if ( pos.y < m_pos.y+0.020f )
+ {
+ flags |= (1<<1);
+ }
+ if ( pos.x > m_pos.x+m_dim.x-0.030f )
+ {
+ flags |= (1<<2);
+ }
+ if ( pos.y > m_pos.y+m_dim.y-0.020f )
+ {
+ flags |= (1<<3);
+ }
+
+ if ( pos.x > m_pos.x+ 0.015f &&
+ pos.x < m_pos.x+m_dim.x-0.015f &&
+ pos.y > m_pos.y+ 0.010f &&
+ pos.y < m_pos.y+m_dim.y-0.010f )
+ {
+ flags = 0;
+ }
+
+ if ( flags == 0 )
+ {
+ h = m_engine->RetText()->RetHeight(m_fontSize, m_fontType);
+ dim.y = h*1.2f;
+ dim.x = dim.y*0.75f;
+ if ( pos.x < m_pos.x+m_dim.x-0.01f-dim.x*3.0f &&
+ pos.y >= m_pos.y+m_dim.y-0.01f-h*1.2f )
+ {
+ flags = -1;
+ }
+ }
+
+ return flags;
+}
+
+// Gestion d'un événement.
+
+BOOL CWindow::EventProcess(const Event &event)
+{
+ FPOINT pos;
+ int i, flags;
+
+ if ( event.event == EVENT_MOUSEMOVE )
+ {
+ if ( m_bCapture )
+ {
+ m_engine->SetMouseType(m_pressMouse);
+ }
+ else
+ {
+ m_pressMouse = D3DMOUSENORM;
+
+ if ( m_name[0] != 0 && m_bMovable && // barre de titre ?
+ Detect(event.pos) )
+ {
+ flags = BorderDetect(event.pos);
+ if ( flags == -1 )
+ {
+ m_pressMouse = D3DMOUSEMOVE; // +
+ }
+ else if ( ((flags & (1<<0)) && (flags & (1<<3))) ||
+ ((flags & (1<<1)) && (flags & (1<<2))) )
+ {
+ m_pressMouse = D3DMOUSEMOVEI; // \
+ }
+ else if ( ((flags & (1<<0)) && (flags & (1<<1))) ||
+ ((flags & (1<<2)) && (flags & (1<<3))) )
+ {
+ m_pressMouse = D3DMOUSEMOVED; // /
+ }
+ else if ( (flags & (1<<0)) || (flags & (1<<2)) )
+ {
+ m_pressMouse = D3DMOUSEMOVEH; // -
+ }
+ else if ( (flags & (1<<1)) || (flags & (1<<3)) )
+ {
+ m_pressMouse = D3DMOUSEMOVEV; // |
+ }
+ }
+
+ if ( m_pressMouse != D3DMOUSENORM )
+ {
+ m_engine->SetMouseType(m_pressMouse);
+ }
+ }
+ }
+
+ if ( !m_bCapture )
+ {
+ for ( i=MAXWINDOW-1 ; i>=0 ; i-- )
+ {
+ if ( m_table[i] != 0 )
+ {
+ if ( !m_table[i]->EventProcess(event) )
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ if ( m_buttonReduce != 0 )
+ {
+ m_buttonReduce->EventProcess(event);
+ }
+ if ( m_buttonFull != 0 )
+ {
+ m_buttonFull->EventProcess(event);
+ }
+ if ( m_buttonClose != 0 )
+ {
+ m_buttonClose->EventProcess(event);
+ }
+ }
+
+ if ( m_bTrashEvent && event.event == EVENT_LBUTTONDOWN )
+ {
+ if ( Detect(event.pos) )
+ {
+ if ( m_name[0] != 0 && m_bMovable ) // barre de titre ?
+ {
+ m_pressFlags = BorderDetect(event.pos);
+ if ( m_pressFlags != 0 )
+ {
+ m_bCapture = TRUE;
+ m_pressPos = event.pos;
+ }
+ }
+ return FALSE;
+ }
+ }
+
+ if ( event.event == EVENT_MOUSEMOVE && m_bCapture )
+ {
+ pos = event.pos;
+ if ( m_pressFlags == -1 ) // déplace tout ?
+ {
+ m_pos.x += pos.x-m_pressPos.x;
+ m_pos.y += pos.y-m_pressPos.y;
+ }
+ else
+ {
+ if ( m_pressFlags & (1<<0) ) // bord gauche ?
+ {
+ if ( pos.x > m_pressPos.x+m_dim.x-m_minDim.x )
+ {
+ pos.x = m_pressPos.x+m_dim.x-m_minDim.x;
+ }
+ m_pos.x += pos.x-m_pressPos.x;
+ m_dim.x -= pos.x-m_pressPos.x;
+ }
+ if ( m_pressFlags & (1<<1) ) // bord inf ?
+ {
+ if ( pos.y > m_pressPos.y+m_dim.y-m_minDim.y )
+ {
+ pos.y = m_pressPos.y+m_dim.y-m_minDim.y;
+ }
+ m_pos.y += pos.y-m_pressPos.y;
+ m_dim.y -= pos.y-m_pressPos.y;
+ }
+ if ( m_pressFlags & (1<<2) ) // bord droite ?
+ {
+ if ( pos.x < m_pressPos.x-m_dim.x+m_minDim.x )
+ {
+ pos.x = m_pressPos.x-m_dim.x+m_minDim.x;
+ }
+ m_dim.x += pos.x-m_pressPos.x;
+ }
+ if ( m_pressFlags & (1<<3) ) // bord sup ?
+ {
+ if ( pos.y < m_pressPos.y-m_dim.y+m_minDim.y )
+ {
+ pos.y = m_pressPos.y-m_dim.y+m_minDim.y;
+ }
+ m_dim.y += pos.y-m_pressPos.y;
+ }
+ }
+ m_pressPos = pos;
+ AdjustButtons();
+
+ Event newEvent = event;
+ newEvent.event = m_eventMsg;
+ m_event->AddEvent(newEvent);
+ }
+
+ if ( event.event == EVENT_LBUTTONUP && m_bCapture )
+ {
+ m_bCapture = FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// Dessine la fenêtre.
+
+void CWindow::Draw()
+{
+ FPOINT pos, dim;
+ float width, h, sw;
+ int i;
+
+ if ( (m_state & STATE_VISIBLE) == 0 ) return;
+
+ if ( m_state & STATE_SHADOW )
+ {
+ DrawShadow(m_pos, m_dim);
+ }
+
+ DrawVertex(m_pos, m_dim, m_icon); // dessine le fond
+
+ if ( m_name[0] != 0 ) // barre de titre ?
+ {
+ h = m_engine->RetText()->RetHeight(m_fontSize, m_fontType);
+
+ // Dessine l'ombre sous la barre de titre.
+ {
+ FPOINT sPos, sDim;
+
+ pos.x = m_pos.x+0.01f;
+ dim.x = m_dim.x-0.02f;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
+ dim.y = h*1.2f;
+ DrawShadow(pos, dim);
+ }
+
+ width = m_dim.x;
+ if ( m_bRedim ) width -= h*1.2f*0.75f*2.0f;
+ if ( m_bClosable ) width -= h*1.2f*0.75f;
+
+ pos.x = m_pos.x+0.01f;
+ dim.x = width-0.02f;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.2f;
+ dim.y = h*1.2f;
+ DrawVertex(pos, dim, (m_state&STATE_ENABLE)?2:9);
+
+ sw = m_engine->RetText()->RetStringWidth(m_name, strlen(m_name), m_fontSize, m_fontStretch, m_fontType);
+
+ if ( m_state&STATE_ENABLE )
+ {
+ pos.x = m_pos.x+0.015f;
+ dim.x = (width-sw-0.06f)/2.0f;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.0f;
+ dim.y = h*0.8f;
+ DrawHach(pos, dim); // hachures gauches
+ pos.x = m_pos.x+width-dim.x-0.015f;
+ DrawHach(pos, dim); // hachures droites
+ }
+
+ pos.x = m_pos.x+width/2.0f;
+ pos.y = m_pos.y+m_dim.y-0.01f-h*1.10f;
+ m_engine->RetText()->DrawText(m_name, pos, width, 0, m_fontSize, m_fontStretch, m_fontType, 0);
+
+ if ( m_buttonReduce != 0 )
+ {
+ m_buttonReduce->Draw();
+ }
+
+ if ( m_buttonFull != 0 )
+ {
+ m_buttonFull->Draw();
+ }
+
+ if ( m_buttonClose != 0 )
+ {
+ m_buttonClose->Draw();
+ }
+ }
+
+ for ( i=0 ; i<MAXWINDOW ; i++ )
+ {
+ if ( m_table[i] != 0 )
+ {
+ m_table[i]->Draw();
+ }
+ }
+}
+
+// Dessine un rectangle.
+
+void CWindow::DrawVertex(FPOINT pos, FPOINT dim, int icon)
+{
+ FPOINT p1, p2, uv1, uv2, corner;
+ float dp;
+ int i;
+
+ dp = 0.5f/256.0f;
+
+ if ( icon == 0 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 64.0f/256.0f; // bleu foncé transparent
+ uv1.y = 64.0f/256.0f;
+ uv2.x = 128.0f/256.0f;
+ uv2.y = 128.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 14.0f/640.0f;
+ corner.y = 14.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+ else if ( icon == 1 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 128.0f/256.0f; // jaune tooltip
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 16.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 2 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 128.0f/256.0f; // jaune
+ uv1.y = 16.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 3 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 0.0f/256.0f; // bleu transparent avec barre jaune supérieure
+ uv1.y = 64.0f/256.0f;
+ uv2.x = 64.0f/256.0f;
+ uv2.y = 128.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 4 ) // SatCom ?
+ {
+ pos.x -= 50.0f/640.0f;
+ pos.y -= 30.0f/480.0f;
+ dim.x += 100.0f/640.0f;
+ dim.y += 60.0f/480.0f;
+
+ m_engine->SetTexture("human.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 140.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 182.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // vêtement
+
+ pos.x += 20.0f/640.0f;
+ pos.y -= 10.0f/480.0f;
+ dim.x -= 20.0f/640.0f;
+ dim.y += 0.0f/480.0f;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTw);
+ uv1.x = 192.0f/256.0f;
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 30.0f/640.0f;
+ corner.y = 30.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f); // ombre
+
+ pos.x += 0.0f/640.0f;
+ pos.y += 20.0f/480.0f;
+ dim.x -= 20.0f/640.0f;
+ dim.y -= 20.0f/480.0f;
+
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 96.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 14.0f/640.0f;
+ corner.y = 14.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f); // ext. bleu
+
+ pos.x += 20.0f/640.0f;
+ pos.y += 10.0f/480.0f;
+ dim.x -= 40.0f/640.0f;
+ dim.y -= 20.0f/480.0f;
+
+ uv1.x = 96.0f/256.0f;
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 128.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 14.0f/640.0f;
+ corner.y = 14.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f); // int. bleu
+
+ pos.x += 10.0f/640.0f;
+ pos.y += 10.0f/480.0f;
+ dim.x -= 20.0f/640.0f;
+ dim.y -= 20.0f/480.0f;
+
+ m_engine->SetTexture("button3.tga");
+ uv1.x = 0.0f/256.0f;
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 32.0f/256.0f;
+ uv2.y = 256.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2); // fond bleu foncé
+
+ m_engine->SetTexture("button2.tga");
+ uv1.x = 224.0f/256.0f;
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 249.0f/256.0f;
+ uv2.y = 235.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ pos.x = 20.0f/640.0f;
+ pos.y = 70.0f/480.0f;
+ dim.x = 25.0f/640.0f;
+ dim.y = 11.0f/480.0f;
+ for ( i=0 ; i<5 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // = inf/gauche
+ pos.y += 15.0f/480.0f;
+ }
+ pos.y = (480.0f-70.0f-11.0f)/480.0f;
+ for ( i=0 ; i<5 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // = sup/gauche
+ pos.y -= 15.0f/480.0f;
+ }
+ pos.x = (640.0f-25.0f-20.0f)/640.0f;
+ pos.y = 70.0f/480.0f;
+ for ( i=0 ; i<5 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // = inf/droite
+ pos.y += 15.0f/480.0f;
+ }
+ pos.y = (480.0f-70.0f-11.0f)/480.0f;
+ for ( i=0 ; i<5 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // = sup/droite
+ pos.y -= 15.0f/480.0f;
+ }
+
+ uv1.x = 208.0f/256.0f;
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 240.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ dim.x = 10.0f/640.0f;
+ dim.y = 10.0f/480.0f;
+ pos.x = 534.0f/640.0f;
+ pos.y = 430.0f/480.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // micro
+ pos.x += 12.0f/640.0f;
+ }
+ pos.x = 528.0f/640.0f;
+ pos.y -= 12.0f/480.0f;
+ for ( i=0 ; i<4 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // micro
+ pos.x += 12.0f/640.0f;
+ }
+ pos.x = 534.0f/640.0f;
+ pos.y -= 12.0f/480.0f;
+ for ( i=0 ; i<3 ; i++ )
+ {
+ DrawIcon(pos, dim, uv1, uv2); // micro
+ pos.x += 12.0f/640.0f;
+ }
+ }
+ else if ( icon == 5 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // vert transparent
+ uv1.y = 160.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 176.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 6 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // rouge transparent
+ uv1.y = 176.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 192.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 7 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // bleu transparent
+ uv1.y = 192.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 208.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 8 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 0.0f/256.0f; // orange opaque
+ uv1.y = 0.0f/256.0f;
+ uv2.x = 32.0f/256.0f;
+ uv2.y = 32.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 14.0f/640.0f;
+ corner.y = 14.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+ else if ( icon == 9 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 32.0f/256.0f; // gris opaque
+ uv1.y = 32.0f/256.0f;
+ uv2.x = 64.0f/256.0f;
+ uv2.y = 64.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 14.0f/640.0f;
+ corner.y = 14.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 8.0f/256.0f);
+ }
+ else if ( icon == 10 )
+ {
+ // rien (dans l'image de fond) !
+ }
+ else if ( icon == 11 )
+ {
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATETTb);
+ uv1.x = 64.0f/256.0f; // jaune transparent
+ uv1.y = 224.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 240.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ DrawIcon(pos, dim, uv1, uv2, 8.0f/256.0f);
+ }
+ else if ( icon == 12 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 128.0f/256.0f; // gris sale opaque
+ uv1.y = 128.0f/256.0f;
+ uv2.x = 160.0f/256.0f;
+ uv2.y = 160.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 6.0f/640.0f;
+ corner.y = 6.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f);
+ }
+ else if ( icon == 13 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 192.0f/256.0f; // bleu sale opaque
+ uv1.y = 128.0f/256.0f;
+ uv2.x = 224.0f/256.0f;
+ uv2.y = 160.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 6.0f/640.0f;
+ corner.y = 6.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f);
+ }
+ else if ( icon == 14 )
+ {
+ m_engine->SetTexture("button1.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 160.0f/256.0f; // rouge sale opaque
+ uv1.y = 128.0f/256.0f;
+ uv2.x = 192.0f/256.0f;
+ uv2.y = 160.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+ corner.x = 6.0f/640.0f;
+ corner.y = 6.0f/480.0f;
+ DrawIcon(pos, dim, uv1, uv2, corner, 5.0f/256.0f);
+ }
+}
+
+// Dessine des hachures.
+
+void CWindow::DrawHach(FPOINT pos, FPOINT dim)
+{
+#if _NEWLOOK
+#else
+ FPOINT ppos, ddim, uv1, uv2;
+ float dp, max, ndim;
+ BOOL bStop;
+
+ dp = 0.5f/256.0f;
+
+ m_engine->SetTexture("button2.tga");
+ m_engine->SetState(D3DSTATENORMAL);
+ uv1.x = 64.0f/256.0f; // hachures
+ uv1.y = 208.0f/256.0f;
+ uv2.x = 145.0f/256.0f;
+ uv2.y = 224.0f/256.0f;
+ uv1.x += dp;
+ uv1.y += dp;
+ uv2.x -= dp;
+ uv2.y -= dp;
+
+ max = dim.y*(uv2.x-uv1.x)/(uv2.y-uv1.y);
+
+ ppos = pos;
+ ddim = dim;
+ bStop = FALSE;
+ do
+ {
+ ddim.x = max;
+ if ( ppos.x+ddim.x > pos.x+dim.x )
+ {
+ ndim = pos.x+dim.x-ppos.x;
+ uv2.x = uv1.x+(uv2.x-uv1.x)*(ndim/ddim.x);
+ ddim.x = ndim;
+ bStop = TRUE;
+ }
+ DrawIcon(ppos, ddim, uv1, uv2);
+
+ ppos.x += ddim.x;
+ }
+ while ( !bStop );
+#endif
+}
+
diff --git a/src/window.h b/src/window.h
new file mode 100644
index 0000000..dfccfbd
--- /dev/null
+++ b/src/window.h
@@ -0,0 +1,132 @@
+// window.h
+
+#ifndef _WINDOW_H_
+#define _WINDOW_H_
+
+
+#include "control.h"
+
+
+class CD3DEngine;
+class CButton;
+class CColor;
+class CCheck;
+class CKey;
+class CGroup;
+class CImage;
+class CLabel;
+class CEdit;
+class CEditValue;
+class CScroll;
+class CSlider;
+class CList;
+class CShortcut;
+class CMap;
+class CGauge;
+class CCompass;
+class CTarget;
+
+
+#define MAXWINDOW 100
+
+
+class CWindow : public CControl
+{
+public:
+ CWindow(CInstanceManager* iMan);
+ ~CWindow();
+
+ void Flush();
+ BOOL Create(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CButton* CreateButton(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CColor* CreateColor(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CCheck* CreateCheck(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CKey* CreateKey(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CGroup* CreateGroup(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CImage* CreateImage(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CLabel* CreateLabel(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg, char *name);
+ CEdit* CreateEdit(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CEditValue* CreateEditValue(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CScroll* CreateScroll(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CSlider* CreateSlider(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CList* CreateList(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg, float expand=1.2f);
+ CShortcut* CreateShortcut(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CMap* CreateMap(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CGauge* CreateGauge(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CCompass* CreateCompass(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ CTarget* CreateTarget(FPOINT pos, FPOINT dim, int icon, EventMsg eventMsg);
+ BOOL DeleteControl(EventMsg eventMsg);
+ CControl* SearchControl(EventMsg eventMsg);
+
+ EventMsg RetEventMsgReduce();
+ EventMsg RetEventMsgFull();
+ EventMsg RetEventMsgClose();
+
+ void SetName(char* name);
+
+ void SetTrashEvent(BOOL bTrash);
+ BOOL RetTrashEvent();
+
+ void SetPos(FPOINT pos);
+ void SetDim(FPOINT dim);
+
+ void SetMinDim(FPOINT dim);
+ void SetMaxDim(FPOINT dim);
+ FPOINT RetMinDim();
+ FPOINT RetMaxDim();
+
+ void SetMovable(BOOL bMode);
+ BOOL RetMovable();
+
+ void SetRedim(BOOL bMode);
+ BOOL RetRedim();
+
+ void SetClosable(BOOL bMode);
+ BOOL RetClosable();
+
+ void SetMaximized(BOOL bMaxi);
+ BOOL RetMaximized();
+ void SetMinimized(BOOL bMini);
+ BOOL RetMinimized();
+ void SetFixed(BOOL bFix);
+ BOOL RetFixed();
+
+ BOOL GetTooltip(FPOINT pos, char* name);
+
+ BOOL EventProcess(const Event &event);
+
+ void Draw();
+
+protected:
+ int BorderDetect(FPOINT pos);
+ void AdjustButtons();
+ void MoveAdjust();
+ void DrawVertex(FPOINT pos, FPOINT dim, int icon);
+ void DrawHach(FPOINT pos, FPOINT dim);
+
+protected:
+ CControl* m_table[MAXWINDOW];
+
+ BOOL m_bTrashEvent;
+ BOOL m_bMaximized;
+ BOOL m_bMinimized;
+ BOOL m_bFixed;
+
+ FPOINT m_minDim;
+ FPOINT m_maxDim;
+
+ CButton* m_buttonReduce;
+ CButton* m_buttonFull;
+ CButton* m_buttonClose;
+
+ BOOL m_bMovable;
+ BOOL m_bRedim;
+ BOOL m_bClosable;
+ BOOL m_bCapture;
+ FPOINT m_pressPos;
+ int m_pressFlags;
+ D3DMouse m_pressMouse;
+};
+
+
+#endif //_WINDOW_H_
diff --git a/src/winmain.aps b/src/winmain.aps
new file mode 100644
index 0000000..6a1e0df
--- /dev/null
+++ b/src/winmain.aps
Binary files differ
diff --git a/src/winmain.cpp b/src/winmain.cpp
new file mode 100644
index 0000000..c4b6f5a
--- /dev/null
+++ b/src/winmain.cpp
@@ -0,0 +1,24 @@
+// winmain.cpp
+//
+
+#define STRICT
+#include <windows.h>
+#include "D3DApp.h"
+
+
+//-----------------------------------------------------------------------------
+// Name: WinMain()
+// Desc: Entry point to the program. Initializes everything, and goes into a
+// message-processing loop. Idle time is used to render the scene.
+//-----------------------------------------------------------------------------
+INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
+{
+ CD3DApplication d3dApp;
+
+ if( FAILED( d3dApp.Create( hInst, strCmdLine ) ) )
+ return 0;
+
+ return d3dApp.Run();
+}
+
+
diff --git a/src/winmain.rc b/src/winmain.rc
new file mode 100644
index 0000000..547d4c2
--- /dev/null
+++ b/src/winmain.rc
@@ -0,0 +1,265 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define IDC_STATIC -1
+#include <windows.h>
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MAIN_ICON ICON DISCARDABLE "DirectX.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define IDC_STATIC -1\r\n"
+ "#include <windows.h>\r\n"
+ "\r\n"
+ "\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_MAIN_ACCEL ACCELERATORS DISCARDABLE
+BEGIN
+ VK_F12, IDM_CHANGEDEVICE, VIRTKEY, SHIFT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 165
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 117
+ END
+
+ IDD_CHANGEDEVICE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 174
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 83
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUT DIALOG DISCARDABLE 0, 0, 172, 124
+STYLE DS_SYSMODAL | DS_MODALFRAME | DS_NOIDLEMSG | DS_SETFOREGROUND |
+ DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "About"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,115,103,50,14
+ ICON IDI_MAIN_ICON,IDC_STATIC,5,5,20,20
+ LTEXT "Robot Sample",IDC_STATIC,35,5,46,8
+ LTEXT "Copyright (c) 1999-2000 EPSITEC SA",IDC_STATIC,35,15,
+ 120,8
+ LTEXT "About",IDC_STATIC,62,52,20,8
+ LTEXT "Select Driver / Device / Mode",IDC_STATIC,62,62,97,8
+ CTEXT "<Alt+Enter>",IDC_STATIC,12,72,45,8
+ LTEXT "Toggle Fullscreen / Windowed",IDC_STATIC,62,72,98,8
+ LTEXT "Exit",IDC_STATIC,62,82,12,8
+ CTEXT "<F1>",IDC_STATIC,12,52,45,8
+ CTEXT "<F2>",IDC_STATIC,12,62,45,8
+ CTEXT "<ESC>",IDC_STATIC,12,82,45,8
+ GROUPBOX "Usage",IDC_STATIC,7,42,160,55
+ LTEXT "Daniel Roux, version 0.1 Janvier 2000",IDC_STATIC,35,26,
+ 121,8
+END
+
+IDD_CHANGEDEVICE DIALOG DISCARDABLE 0, 0, 182, 90
+STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Change device"
+FONT 8, "MS Sans Serif"
+BEGIN
+ GROUPBOX "&Device selection",-1,5,5,115,40
+ COMBOBOX IDC_DEVICE_COMBO,10,15,105,100,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "Use desktop &window",IDC_WINDOWED_CHECKBOX,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,30,85,10
+ GROUPBOX "Fullscreen &modes",IDC_FULLSCREEN_TEXT,5,45,115,40
+ COMBOBOX IDC_MODE_COMBO,10,55,105,100,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ CONTROL "&Stereoscopic viewing",IDC_STEREO_CHECKBOX,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,10,70,85,9
+ DEFPUSHBUTTON "OK",IDOK,125,5,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,125,25,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MENU MENU DISCARDABLE
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Go/stop\tEnter", IDM_TOGGLESTART
+ MENUITEM "&Single step\tSpace", IDM_SINGLESTEP
+ MENUITEM SEPARATOR
+ MENUITEM "&About...\tF1", IDM_ABOUT
+ MENUITEM "&Change device...\tF2", IDM_CHANGEDEVICE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit\tESC", IDM_EXIT
+ END
+END
+
+IDR_POPUP MENU DISCARDABLE
+BEGIN
+ POPUP "Popup"
+ BEGIN
+ MENUITEM "&Go/stop", IDM_TOGGLESTART
+ MENUITEM "&Single step", IDM_SINGLESTEP
+ MENUITEM SEPARATOR
+ MENUITEM "&About...", IDM_ABOUT
+ MENUITEM "&Change device...", IDM_CHANGEDEVICE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// French (Switzerland) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRS)
+#ifdef _WIN32
+LANGUAGE LANG_FRENCH, SUBLANG_FRENCH_SWISS
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "100c04b0"
+ BEGIN
+ VALUE "CompanyName", "www.epsitec.com\0"
+ VALUE "FileDescription", "CeeBot\0"
+ VALUE "FileVersion", "Version 1.0\0"
+ VALUE "InternalName", "CeeBot\0"
+ VALUE "LegalCopyright", "Copyright © 2001 by EPSITEC SA\0"
+ VALUE "OriginalFilename", "ceebot.exe\0"
+ VALUE "ProductName", "EPSITEC CeeBot\0"
+ VALUE "ProductVersion", "Version 1.0\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x100c, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_CURSORHAND CURSOR DISCARDABLE "cursor1.cur"
+IDC_CURSORSCROLLL CURSOR DISCARDABLE "cursorha.cur"
+IDC_CURSORSCROLLR CURSOR DISCARDABLE "cursorsc.cur"
+IDC_CURSORSCROLLU CURSOR DISCARDABLE "cur00001.cur"
+IDC_CURSORSCROLLD CURSOR DISCARDABLE "cur00002.cur"
+IDC_CURSORTARGET CURSOR DISCARDABLE "cur00003.cur"
+#endif // French (Switzerland) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+