diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..e69de29 diff --git a/BASENFK/models/Sarge/description.txt b/BASENFK/models/Sarge/description.txt new file mode 100644 index 0000000..d5d3dac --- /dev/null +++ b/BASENFK/models/Sarge/description.txt @@ -0,0 +1,5 @@ +Model: Sarge +Skins: red, blue, default, nuker +Author: Needle (mailto: eagla [at] yandex.ru) +This model is for NFK 075 or Tribes X +This model replaces previous sarge model. \ No newline at end of file diff --git a/BASENFK/nfksetup.ini b/BASENFK/nfksetup.ini new file mode 100644 index 0000000..a2f9f23 --- /dev/null +++ b/BASENFK/nfksetup.ini @@ -0,0 +1,14 @@ +[video] +fullscreen=1 +bitdepth=32 +vsync=0 + +[sound] +soundtype=2 +[DirectConnectHistory] +IP0=195.239.6.183 +IP1=169.254.244.174 +IP2=80.80.120.83 +IP3=217.74.40.6 +IP4=192.168.55.1 +IP5=195.209.236.15 diff --git a/BASENFK/system/icons/ico.lst b/BASENFK/system/icons/ico.lst new file mode 100644 index 0000000..f09821a --- /dev/null +++ b/BASENFK/system/icons/ico.lst @@ -0,0 +1,12 @@ +c:\!export\nfk_dev\basenfk\system\icons\iconw_gauntlet.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_machinegun.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_shotgun.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_grenade.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_rocket.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_lightning.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_railgun.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_plasma.tga +c:\!export\nfk_dev\basenfk\system\icons\iconw_bfg.tga +c:\!export\nfk_dev\basenfk\system\icons\noammo.tga +c:\!export\nfk_dev\basenfk\system\icons\iconh_red1.tga +c:\!export\nfk_dev\basenfk\system\icons\iconr_yellow.tga diff --git a/BOT.DPR b/BOT.DPR new file mode 100644 index 0000000..993fc21 --- /dev/null +++ b/BOT.DPR @@ -0,0 +1,240 @@ +{ + + BOT.DLL for Need For Kill + (c) 3d[Power] + http://www.3dpower.org + + unit: bot.dpr + purpose: system procedures. + + warning: do not modify this unit. +} + +library bot; + +uses + SysUtils, + Classes, + Windows, + bot_defs in 'bot_defs.pas', + bot_ai in 'bot_ai.pas', + bot_console in 'bot_console.pas', + bot_register in 'bot_register.pas', + bot_util in 'bot_util.pas'; + +// ========================================== + +// -------------------------------------------------------------- + +// DO NOT MODIFY. +procedure DLL_RegisterProc1(AProc : TCallProcWordWordFunc); +begin + SetAngle := AProc; +end; + +procedure DLL_RegisterProc2(AProc : TCallTextProc; ProcID:byte); +begin + case ProcID of + 1 : AddMessage := AProc; + 2 : RegisterConsoleCommand := AProc; + end; +end; + +// DO NOT MODIFY. +procedure DLL_RegisterProc3(AProc : TCallProcSTR; ProcID:byte); +begin + case ProcID of + 1 : GetSystemVariable := AProc; + end; +end; + +// DO NOT MODIFY. +procedure DLL_RegisterProc4(AProc : TCallProcCreatePlayer; ProcID:byte); +begin + sys_CreatePlayer := AProc; +end; + +// DO NOT MODIFY. +procedure DLL_RegisterProc5(AProc : TCallProcWordByteFunc; ProcID:byte); +begin + case ProcID of + 1 : SetKeys := AProc; + 3 : SetWeapon := AProc; + 4 : SetBalloon := AProc; + end; +end; + +// DO NOT MODIFY. +procedure DLL_RegisterProc6(AProc : TCallProcWordWord_Bool; ProcID:byte); +begin + case ProcID of + 1 : Test_Blocked := AProc; + end; +end; + +// DO NOT MODIFY. +procedure DLL_RegisterProc7(AProc : TCallProcWordWordString; ProcID:byte); +begin + case ProcID of + 1 : debug_textout := AProc; + 2 : debug_textoutc := AProc; + end; +end; + +// DO NOT MODIFY. +procedure DLL_RegisterProc8(AProc : TCallProcBrickStruct); begin GetBrickStruct := AProc; end; +procedure DLL_RegisterProc9(AProc : TCallProcObjectsStruct); begin GetObjStruct := AProc; end; +procedure DLL_RegisterProc10(AProc : TCallProcSpecailObjectsStruct); begin GetSpecObjStruct := AProc; end; +procedure DLL_RegisterProc11(AProc : TCallProcWord); begin RemoveBot := AProc; end; +procedure DLL_RegisterProc12(AProc : TCallProcChat); begin SendBotChat := AProc; end; +// ================================================ + + +// MainLoop. NFK.EXE calls this procedure 50 times per second. (in game) +procedure DLL_MainLoop(); +begin + MAIN_Loop; +end; + +// NFK loads a map. and begin game. It should be warmup time for now.. +procedure DLL_EVENT_BeginGame; +begin + CMD_Register; + EVENT_BeginGame; +end; + +// Game Reborn. It happends at game start, or at map restart. (it also called after DLL_EVENT_BeginGame (once)); +procedure DLL_EVENT_MapChanged; +begin + EVENT_MapChanged; +end; + +// Map changed by "map" command, or by callvote +procedure DLL_EVENT_ResetGame; +begin + EVENT_ResetGame; +end; + +// NFK.EXE query bot.dll version. +function DLL_QUERY_VERSION:shortstring; +begin + result := BotVersion; +end; + +// DO NOT MODIFY +procedure DLL_SYSTEM_AddPlayer(Player : TPlayerEx); +var i : byte; +begin + for i := 0 to 7 do if players[i] = nil then // free cell + begin + players[i] := Tplayer.Create; + players[i].DXID := Player.DXID; + players[i].netname := player.netname; + players[i].bot := player.bot; + exit; + end; +end; + +// DO NOT MODIFY +procedure DLL_SYSTEM_RemoveAllPlayers(); +var i : byte; +begin + for i := 0 to high(Players) do if players[i] <> nil then // free cell + players[i] := nil; +end; + +// DO NOT MODIFY +procedure DLL_SYSTEM_RemovePlayer(DXID:word); +begin + RemovePlayer(DXID); +end; + +// DO NOT MODIFY +procedure DLL_DMGReceived(TargetDXID, AttackerDXID:Word; dmg : word); +begin + EVENT_DMGReceived(TargetDXID, AttackerDXID, dmg); +end; + +procedure DLL_ChatReceived(DXID:Word; Text : shortstring); +begin + EVENT_ChatReceived(DXID, Text); +end; + +procedure DLL_AddModel(s : shortstring); +begin + ModelList.Add(s); +end; + +// DO NOT MODIFY +procedure DLL_SYSTEM_UpdatePlayer(Player : TPlayerEx); +var i : byte; +begin + // update all player info + for i := 0 to 7 do if players[i] <> nil then // free cell + if players[i].DXID = Player.DXID then + with players[i] do begin + dead := player.dead; + bot := player.bot; + refire := player.refire; + weapchg := player.weapchg; + weapon := player.weapon; + threadweapon := player.threadweapon; + dir := player.dir; + gantl_state := player.gantl_state; + air := player.air; + team := player.team; + health := player.health; + armor := player.armor; + frags := player.frags; + netname := player.netname; + nfkmodel := player.nfkmodel; + crouch := player.crouch; + balloon := player.balloon; + flagcarrier := player.flagcarrier; + Location := player.Location; + item_quad := player.item_quad; + item_regen := player.item_regen; + item_battle := player.item_battle; + item_flight := player.item_flight; + item_haste := player.item_haste; + item_invis := player.item_invis; + have_rl := player.have_rl; + have_gl := player.have_gl; + have_rg := player.have_rg; + have_bfg := player.have_bfg; + have_sg := player.have_sg; + have_sh := player.have_sh; + have_mg := player.have_mg; + have_pl := player.have_pl; + ammo_mg := player.ammo_mg; + ammo_sg := player.ammo_sg; + ammo_gl := player.ammo_gl; + ammo_rl := player.ammo_rl; + ammo_sh := player.ammo_sh; + ammo_rg := player.ammo_rg; + ammo_pl := player.ammo_pl; + ammo_bfg := player.ammo_bfg; + x := player.x; + y := player.y; + cx := player.cx; + cy := player.cy; + InertiaX := player.InertiaX; + InertiaY := player.InertiaY; + if not bot then fangle := player.fangle; + exit; + end; +end; + +exports DLL_RegisterProc1,DLL_RegisterProc2, DLL_RegisterProc3, + DLL_RegisterProc4, DLL_RegisterProc5,DLL_RegisterProc6, + DLL_RegisterProc7, DLL_RegisterProc8,DLL_RegisterProc9, + DLL_RegisterProc10,DLL_RegisterProc11,DLL_RegisterProc12, + DLL_EVENT_BeginGame, DLL_EVENT_ResetGame, DLL_EVENT_MapChanged, + DLL_MainLoop, DLL_SYSTEM_UpdatePlayer, DLL_SYSTEM_AddPlayer, + DLL_SYSTEM_RemoveAllPlayers, DLL_SYSTEM_RemovePlayer, DLL_AddModel, + DLL_DMGReceived, DLL_ChatReceived, DLL_CMD, DLL_QUERY_VERSION; + +begin + Randomize; + ModelList := TStringList.Create; +end. diff --git a/CLEAN.BAT b/CLEAN.BAT new file mode 100644 index 0000000..6dc5151 --- /dev/null +++ b/CLEAN.BAT @@ -0,0 +1,16 @@ +TITLE CLEANING... +REM CLEAN SCRIPT by NEOFF and BITNIK +@Echo off +cls +color 2 +Echo Cleaning Trash Files... +del /s *.~* +del /s *.dcu +del /s *.dsk +del /s *.dsm +del /s *.rsm +del /s *.cfg +del /s *.rar +del /s *.ddp +cls +Exit \ No newline at end of file diff --git a/COMPILE.txt b/COMPILE.txt new file mode 100644 index 0000000..2018deb --- /dev/null +++ b/COMPILE.txt @@ -0,0 +1,42 @@ +HOWTO COMPILE NFK !? + +Вобщем тут коротеничко опишу как инсталить и компилить сорсы НФК'и :) +Разобраться со всем этим мне помогал, а точнее описывал весь процесс exile, за что ему огромное спасибо ! + +Для начала требования: +1) Делфи 7 - самая обычная +2) Сами исходники +3) Пакет PowerDrow +4) Хренатень dclsockets70.bpl +5) Срань FastNet.v5.6.3.D5-7.FS +6) Мозг и куча свободного времени + +Вобщем полагаю Делфи 7 у вас уже стоит, самое время СКАЧАТЬ ИСХОДНИКИ НФК (NFK) :) +Качаем NFK.SDK.Lite 62B~64 облегчённый вариант отсюда: http://nfk.pro2d.ru/files/NFK-SDK-62B.rar, +либо ломимся ко мне в асю и просим 40 Мегабайтный оригинал Повера. +(Архив заблокирован паролем, пароль от архива могут получить далеко не все), вобщем +так или иначе предположим, что каким-то способом вы завладели паролем к архиву +и дико стремитесь закодить чёнить в НФК :) Но всему своё время, теперь качаем +пачку PowerДров, осюда http://nfk.pro2d.ru/files/PowerDrow.rar +Ну вот одну небольшую мечту мы уже осуществили, мы УЖЕ завладели исходниками +и почти готовы начать процесс программирования, но для начала скачаем ещё одну +хреновину для нашего мега брутального проекта (FastNet.v5.6.3.D5-7.FS): http://nfk.pro2d.ru/files/Hrenovina.rar +Теперь самое время покурить тем кто курит, а кто не курит, пьём чай с бубликами ;) + +Ну а теперь, когда мы раздобыли всё чё нам нужно по шурику всё инсталим: + +1) Открываем Делфи 7 Menu: Components -> Install Packages -> Кнопка ADD +-> C:\Program Files\Borland\Delphi7\Bin\dclsockets70.bpl + +2) Распаковываем ПоверДров, открываем PowerDraw24pwr\Source\PowerGrafixD6.dpk тыкаем Install, тыкаем Save ALL +теперь из этой папки PoweDraw24pwr копируем всё содержимое в: +C:\Program Files\Borland\Delphi7\Lib\ + +3) Теперь распаковываем ту хреновину Hrenovina.rar, открываем FastNet.v5.6.3.D5-7.FS\Fastnet\lib\DCLNMF70.dpk, +жмем Install, опять жмем Save ALL, теперь опять всё содержимое FastNet.v5.6.3.D5-7.FS\Fastnet\lib\ копируем: +C:\Program Files\Borland\Delphi7\Lib\ + +Терь всё путём, можно компилить :) + +И Кто уже всё замутил может попытать удачю в фиксе первого бага - правая кнопка мыши и кнопка колёсико +мыши нфк чёта не воспринимает в остальном всё путём... Эксперты говорят истина где-то в DXINPUT... \ No newline at end of file diff --git a/DOCS/040bugs!!!!!!!1.txt b/DOCS/040bugs!!!!!!!1.txt new file mode 100644 index 0000000..b1a9826 --- /dev/null +++ b/DOCS/040bugs!!!!!!!1.txt @@ -0,0 +1,3 @@ +-Пов, тебе ещё один баг - когда смотришь демки на 2 чела (хотсит, скорее всего) и CTF, то не показывается красно-синяя табличка со счётом флагов... + +- по окончании цтф (лимит флагов 5) в нижнем левом углу количество флагов у выигравшей команды остаётся 4 diff --git a/DOCS/CREDITS.TXT b/DOCS/CREDITS.TXT new file mode 100644 index 0000000..4f6df58 --- /dev/null +++ b/DOCS/CREDITS.TXT @@ -0,0 +1,131 @@ +Created by 3d[Power] + + + +=Programming + +3d[Power] + + + +=Sounds + +Id Software + + + +=Graphics + +3d[Power] +Deadlock +Eagla +[LD]:Surgeon +XeN +Dammer +YESMAD + + + +=Beta Testers + +ARMADoN +Barracuda +[DJ]_Bomberm@n +blade_kgb +c@tr1N +Dammer +D@$HA +Deadlock +DeaTh +[DJ]_Dimps +D*oo*M +Eagla +Eugen~3D +EXcEllent +.:FeniX:. +FuNTiK +G3x.Atom +GOD[WP] +Hellraiser +Horned Reaper +Hramovv +IMPULSE +Jackal +Kacnep +KAP^COH +Kesha +KoBa +[LD]:Shadow +[LD]:Surgeon +[NFK]-DJ_Web +[NFK]-HiT_mAn|G3x +[NFK]-PQR +[NFK]-RockY +Merlin[XP] +mkl +OverMind +Paul "Elf" Bulatov +PH@NT0M +Psibug +Snezzy +Sokoloff +Spike +Stens +the_ghost +VAMPiRE +Virus +WiCKed +XeN + + + +=Special Thanks to + +ID Software for great games. +MesiteL for hardcore beta testing :) +MadFrog for nfk planet masterserver code. +Drug-it for supporting nfk planet at q3.demos.su +Lifepower, u know for what :) + + + +=License agreement + +IF YOU DO NOT AGREE TO THE TERMS OF THIS +AGREEMENT, THEN DO NOT USE THIS SOFTWARE. + + +Limited Warranty. 3d[Power] expressly disclaims any warranty +for the Program, Editor and Manual(s). The Program, Editor +and Manual(s) are provided "as is" without warranty of any +kind, either express or implied, including, without +limitation, the implied warranties of merchantability, +fitness for a particular purpose, or noninfringement. + + +Responsibilities. you may not, in whole or in part, +reproduce, translate, reverse engineer, derive source +code, modify, disassemble, decompile, create derivative +works based on the Program, or remove any proprietary +notices or labels on the Program without the prior +consent, in writing from 3d[Power]. + + +You are entitled to use the Program for your own +use, but you are not be entitled to sell or to rent, +lease or license the Program to others without the +prior written consent from 3d[Power]. + + +Program Transfer. You may freely redistribute this software +provided the original installation package is unmodified. + + +This software is Freeware. +Quake III Arena (tm) copyright ID Software. + + + +=Need For Kill homepage: + +http://www.3dpower.org \ No newline at end of file diff --git a/DOCS/DONOW.txt b/DOCS/DONOW.txt new file mode 100644 index 0000000..1b18023 --- /dev/null +++ b/DOCS/DONOW.txt @@ -0,0 +1,6 @@ + в цтф тама када посылаешь мессаги тимные то последняя буква коряво отображается +- Редактор карт: при увеличении размера карты, вместо новых пустых клеток иногда появляются другие (например: блоки) +- map playlist. +- sv auto cfg exec +- area_brickillusion.. +- overtime? \ No newline at end of file diff --git a/DOCS/DONOW050.TXT b/DOCS/DONOW050.TXT new file mode 100644 index 0000000..7dcf1b2 --- /dev/null +++ b/DOCS/DONOW050.TXT @@ -0,0 +1,70 @@ +- пиши в лог вайле в статистике после имени бота через пробел идентификатор bot +- точнее так же работает, как и exec, выдаёт эхо всегда, мол конфиг такой-то ексекнут +- speeddemo 40 в конфиге (ну или может просто коммандой) даёт больше скорости чем "+" до 40 довести ;) +- но в nfk bot enemymodеl не пашет +- Dont connect if nfk alttabbed +- LCD +- check demo gibs +- сделай вот так, если чел конектится свыше sv_maxplayers, то его в спектры автоматом, тогда не понадобится делать tourney mod +- Overtime dont show in demo +- показывай во время смерти скорeбоaрд +- сделай чат в нфк поудобней +- add commands to Standart.cfg +- пов не красиво коды на больших картах твой ник с право :( нада нах чтоб он не отображался :( и команды для уменшения худа +- many video cards (icq:313492, чел LC) +- и где просмотр моделей чтоб можно было посмотреть как он бежит, приседает, и подыхает +- десятые в сенсе +- ты nfk.exe -map tourney4 сделал? +drawfps- + +2) Ну ентот баг незначительный.Короче, наводишь курсором на +окошко с мапами (ну, чтоб крестик появился) а потом мышкой +строго по вертикали, не отводя в бок доводишь до уровня +надписи "Гейм Тайп".А затем строго по горизонтали ведешь +на Гейм тайп.А терь поводи по надписи! + + +- когда мы оба с флагом умерли то я возрадился опять же с флагом +- мож сделаешь команду в 060 чтоб команда делал скрин всей карты без надписей + +7) возможность записывать дэмы в каталоги например autorecord (name demos) in (католог) а то их в другие +католаги перетаскивать влом + +12) во всех опциях типа тайм тимит и томуподобные где надо число вводить надо сделать так чтоб при +нажатии по крысе он просит изменитьа еще одним щелчком низя приходится искать клавиатуру =) + +- Встань на 253 брик, потом удерживая TAB нажми вправо. Потом жми влево, до +тех пор, пока не найдёшь 255 брик. Вот им можно рисовать непрозрачные +двери.... + +DRAWFPS +- (?) restore ALL gametypes in HOTSEAT. + +- binf F keys +- sv_allowvote_map +- sv_motd +- allow voting bugs. +- warmup 0 bug +- mapdiffers bug +- BARTRAX_autodetect. +- kill command does not work over multiplayer. +- повер сделай так чтобы время обозначалось не допусти 0.5 а 0.05 +- не забудь про powertimer nfk edition :) +- Пов, сделай, чтобы средней кнопкой можно было не только карты и демки выбирать, но и коннектиться к планете и т.д. В этой менюхе не пашет мидбуттон + +3. Иногда бывает такое: Я нахожусь на внизу уровня и меня убивают труп проваливается через +пол (нижнюю границу уровня). Это вроде случается на стыке блоков из которых состоит уровень. + +//dedic related. +- В дедике если в автоексек написать nfkplanet и дальше ещё команды, то первое - не грузятся остальные - второе - выдаёт ошибку. Исправь срочно - надо автоматизировать запуск дедика. +- integer overflow on stats end : dedic. + +<[DJ]_DimPs> CRC32: Could not find map RailArena\DJD_rail1.mapa +<[DJ]_DimPs> Пов, чё за фигня? +<_3d[Power]> х3 ;) +<[DJ]_DimPs> я написал nfkplanet +<[DJ]_DimPs> map djd_rail1 rail +<[DJ]_DimPs> он написал, что именно там, где она есть - её нет... +<_3d[Power]> в дедике? +<[DJ]_DimPs> да +<_3d[Power]> посмотрю diff --git a/DOCS/NOWtodo030.txt b/DOCS/NOWtodo030.txt new file mode 100644 index 0000000..e26f7a1 --- /dev/null +++ b/DOCS/NOWtodo030.txt @@ -0,0 +1,26 @@ +- AUTO_ENGLISH ENABLE +- MAYBE: Telefrags +- Pain sound stop when die +- Item respawn configurable. +- Mouse select in player2prop. +- screenshot. +- More clever TAB key at console. +- "warmup" command dont work in trix arena. +- NET: Sent gauntlet state packet to connected playerz. +- NET: ready command +- custom port +- MP_STEP gamma. +- 180*50 - bug warmup +- synchronize: net time. +- map playlist. +- rcon +- receive powerup states on GAMESTATE. + +-------------- 040 ---------- +- not limited size of area_waterillusion... +- improove modem play (client auto enter game). +- *.nmd valid model +- demo ammo bug. + +- в новой версии в кредитах исправь ники Rocky, PQR и G3x.HiT_mAn на: +[NFK]-Rocky, [NFK]-PQR, [NFK]-HiT_mAn|G3x \ No newline at end of file diff --git a/DOCS/TEST4.TXT b/DOCS/TEST4.TXT new file mode 100644 index 0000000..feea72f --- /dev/null +++ b/DOCS/TEST4.TXT @@ -0,0 +1,21 @@ +============================ +Need For Kill ver 040 +Version 39test4 +(c) 3d[Power] +2003 +http://www.3dpower.org +============================ + +Изменения относительно test3: +- Изменено: Значительно улучшена консольная команда "map": (1,2). +1) В нее встроен автоматический поиск, к примеру если вашу карту нфк не нашел в корневой папке maps, то он проводит сканирование всех вложенных подпапок в maps, и в итоге найдет вашу карту гдебы она не лежала :). Теперь достаточно писать просто "map mapname", без указывания поддиректорий. +2) Команда map теперь может менять GAMETYPE! (тип игры). Как сменить gametype: Команда "map dm2 deathmatch" загрузит карту dm2 в режиме DeathMatch. Чтобы получить help по смене gametype'ов (и все значения параметра gametype), введите (в нфк) "map dm2 help". +- изменено: дефалтные значения capturelimit=8 domlimit=400. +- Исправлено: нельзя было биндить ECHO в верхнем регистре. +- Исправлено: в полноэкранном режиме, нфк нельзя было alt+tab'нуть. +- Добавлено: команда writeconfig. "writeconfig myconfig", в файл myconfig.cfg будут записаны текущие настройки нфк. +- Исправлено: нельзя было биндить некоторые команды, содержащие пробелы +- Изменено: максимальное значение forcerespawn теперь равно 10ти. +- Добавлено: команды "nextwpn_skipempty", "p2nextwpn_skipempty", если включено, то при выборе оружия, через nextweapon и prevweapon, не будут выбираться оружия без патронов. +- Изменено: улучшена навигация по окну DEMOS (запоминание последней директории, home\end кнопки, итд) +- Изменено: теперь, если выпавшее оружие или флаг зажимается дверью, то оружие пропадает (флаг - возвращается на базу). \ No newline at end of file diff --git a/DOCS/botSDK.txt b/DOCS/botSDK.txt new file mode 100644 index 0000000..e61fc8b --- /dev/null +++ b/DOCS/botSDK.txt @@ -0,0 +1,321 @@ +NFK BOT DEVELOPMENT SDK +By 3d[Power] + +Встроенные в NFK.EXE процедуры и функции. Вызываются из bot.dll. + + +Function GetSystemVariable(text : string) : string; + +Возвращает значение системных переменных. + +Example: + Var RootDirectory : string; + begin + RootDirectory := GetSystemVariable('rootdir'); + End; + +Значения параметра text, задаются они в нижнем регистре: +rootdir - путь к рабочей папке нфк (c:\nfk\basenfk) +mapname - имя карты (tourney4), возвращается без расширения .mapa +mapfilename - полный путь к файлу карты (c:\nfk\basenfk\maps\tourney4.mapa). +mapinternalname - внутреннее имя карты (more frags & martini); +mapauthor - автор карты. +mapcrc32 - CRC32 карты. +playerscount - количество игроков. +playerscount_red - количество игроков которые в красной команде. +playerscount_blue - количество игроков которые в синей команде. +teamscore_red - количество очков красной команды. (team games only). +teamscore_blue - количество очков синей команды. (team games only). +gamesudden - идет ли сейчас sudden death. +timelimit - значение timelimit (в минутах). +fraglimit - значение fraglimit (в минутах). +capturelimit - значение capturelimit. +domlimit - значение domlimit. +overtime - значение overtime. +ctfflagstatus_red - статус красного флага (CTF). 0=base, 1=carried, 2=lost. +ctfflagstatus_blue - статус синего флага (CTF). 0=base, 1=carried, 2=lost. +time_min - текущее время. Минуты. (в партии). +time_sec - текущее время. Секунды. (в партии). +warmupleft - время до конца разыгровки. В секундах. (в партии). +gametype - возвращает режим игры (DM). +bricks_x - количество бриков по горизонтали. Отсчет начинается с 0, тоесть результат 29 - значит 30. +bricks_y - количество бриков по вертикали. Отсчет начинается с 0, тоесть результат 19 - значит 20. +nfkversion - версия NFK. +warmuparmor - значение консольной команды warmuparmor. +forcerespawn - значение консольной команды forcerespawn. +sv_maxplayers - значение консольной команды sv_maxplayers. +sv_teamdamage - значение консольной команды sv_teamdamage. +railarenainstagib - значение консольной команды railarenainstagib. + +Procedure AddMessage(text : string); + +Example: + AddMessage('Hi everybody'); + +Выводит text на консоль. (Тэги цвета - работают). + +Procedure sys_CreatePlayer(netname, nfkmodel : string; team : byte); + +Example + Sys_CreatePlayer('bot', 'sarge+red' ,0); + +Создает игрока, под управлением бота. +Netname - имя игрока. (player3). +Nfkmodel - модель игрока. (sarge+red). +Team - команда игрока. В не командных режимах игры, переменная игнорируется. + + Team. const +C_TEAMBLUE = 0; +C_TEAMRED = 1; +C_TEAMNON = 2; + +Вашему созданному боту назначается уникальный DXID. + +Procedure SetKeys(DXID: word; keys : byte); + +Нажатие кнопок у игрока, эта команда сработает только в случае если игрок - бот. + +DXID - уникальный DXID. +Keys - кнопки, они назначаются суммой. + + Keys. const +BKEY_MOVERIGHT = 1; +BKEY_MOVELEFT = 2; +BKEY_MOVEUP = 8; +BKEY_MOVEDOWN = 16; +BKEY_FIRE = 32; + +Example: + SetKeys(Players[I].DXID, BKEY_MOVERIGHT + BKEY_MOVEUP + BKEY_FIRE); + Нажаты кнопки вправо, вверх, выстрел. + +Чтобы проверить наличие кнопки: + + Var mykeys : byte; + Begin +Mykeys := BKEY_MOVERIGHT + BKEY_MOVEUP + BKEY_FIRE; +SetKeys(Players[I].DXID, Mykeys); +If mykeys and BKEY_MOVEUP = BKEY_MOVEUP then addmessage('I am jumping'); + End; + + +Procedure SetWeapon(DXID: word; weapon : byte); + +Выбрать оружие. + +DXID - уникальный DXID. +weapon - номер оружия. + + Weapon. const +C_WPN_GAUNTLET=0; +C_WPN_MACHINE=1; +C_WPN_SHOTGUN=2; +C_WPN_GRENADE=3; +C_WPN_ROCKET=4; +C_WPN_SHAFT=5; +C_WPN_RAIL=6; +C_WPN_PLASMA=7; +C_WPN_BFG=8; + +Example: + SetWeapon(players[I].DXID, C_WPN_ROCKET); + +Оружие включится в случае его наличия. + + + +Function Test_Blocked(X, Y : word) : Boolean; + +Проверяет проходим ли брик в позиции X, Y + +Example: + if Test_Blocked (trunc(players[i].x + 15),trunc(players[i].y)) then // + (проверяет есть ли стена справа от выбранного игрока) + + +Procedure debug_textout(x, y : word; text : string); + +Выводит текст в позиции X, Y. Используется для вывода дебаг информации, например пометка вэйпоинтов. + +Example: + debug_textout(100, 100, 'test1'); + + +Procedure RegisterConsoleCommand(s: string); + +Регистрирует наличие добавленной вами консольной команды, в nfk.exe +(Вызывается из bot_register.pas в процедуре CMD_Register) + + + +function GetBrickStruct(x, y : word):TBrick; + +Возвращает record с содержимым брика в позиции x, y; + +{ +type TBrick = record // do not modify + image : byte; // graphix index + block : boolean; // do this brick block player; + respawntime : integer; // respawn time + y : shortint; + dir : byte; + oy : real; + respawnable : boolean; // is this shit can respawn? + scale : byte; + end; +} + +Например: + +Var tmp : Tbrick; + + Tmp := GetBrickStruct(1,1); + + tmp.image - это картинка брика, константы под image указаны в bot_defs.pas (IT_ARMOR например) + tmp.block - Проверяет проходим ли брик (взятие этой переменной аналогично Test_Blocked()) + tmp.respawntime - если брик это предмет, то если respawntime = 0 значит предмет есть, иначе respawntime означает сколько времени осталось до респавна предмета (в условных единицах времени) + tmp.y - не используется (вродебы) + tmp.dir - если это CTF флаг и dir=0 то флаг стоит на месте, иначе нет. если это DOM флаг, то dir показывает его цвет. Во всех других случаях dir не используется. + tmp.oy - не используется (вродебы) + tmp.respawnable - например аптечка respawnable, джамппад нет + tmp.scale - не используется + + + +function GetObjStruct(ID : word):TObj; + +Доступ к массиву объектов. + +type TObj = record // do not modify + dead : byte; + speed,fallt,weapon,doublejump,refire : byte; + imageindex,dir,idd : byte; + clippixel : smallint; + spawnerDXID : word; + frame : byte; + health : smallint; + x,y,cx,cy,fangle,fspeed : real; + objname : string[30]; + DXID : word; + mass, InertiaX,InertiaY : real; + end; + + +Var tmp : Tbrick; + Tmp := GetObjStruct(0); + +Массив объектов objs: array [0..1000] of TObj; +Причем, если tmp.dead > 0 то данный объект не действителен. + +Допустим чтобы вам найти все запущенные ракеты на карте, нужно делать так: + for i := 0 to 1000 do + if GetObjStruct(i).dead=0 then + if GetObjStruct(i).objname='rocket' then ... + + +Данный тип был заведен достаточно давно, года 2 назад. Здесь большинство названий переменных не соотвествует действительности... +И массив не динамический (2 года назад я не умел делать другие). + +---------------------------- +Объект CTF FLAG +tmp.objname = 'flag' - уроненный CTF флаг. +tmp.x +tmp.y +tmp.imageindex - цвет +---------------------------- +Объект WEAPON +tmp.objname = 'weapon' - выпавшее оружие. +tmp.x +tmp.y +tmp.imageindex - ID оружия +---------------------------- +Объект GRENADE +tmp.objname = 'grenade' - запущенная граната. +tmp.x +tmp.y +tmp.spawnerDXID - DXID того кто ее запустил. +tmp.inertiax - velocity по X +tmp.inertiay - velocity по Y +tmp.clippixel - коробка вокруг гранаты, для зацепляния за брики +---------------------------- +Объект ROCKET +tmp.objname = 'rocket' - запущенная ракета. +tmp.x +tmp.y +tmp.spawnerDXID - DXID того кто ее запустил. +tmp.inertiax - velocity по X +tmp.inertiay - velocity по Y +tmp.clippixel - коробка вокруг ракеты, для зацепляния за брики +tmp.fallt - если 1 то это BFG снаряд +tmp.fangle - угол полета. Реальный угол полета angle = (fangle-90); + формула полета: + x := x + tmp.fspeed*CosTable[angle]; + y := y + tmp.fspeed*SinTable[angle]; +---------------------------- +Объект PLASMA +tmp.objname = 'plasma' - запущенная плазма. +tmp.x +tmp.y +tmp.spawnerDXID - DXID того кто ее запустил. +tmp.inertiax - velocity по X +tmp.inertiay - velocity по Y +tmp.clippixel - коробка вокруг плазмы, для зацепляния за брики +tmp.fangle - угол полета. Реальный угол полета angle = (fangle-90); + формула полета: + x := x + tmp.fspeed*CosTable[angle]; + y := y + tmp.fspeed*SinTable[angle]; +---------------------------- + +прочие objname: +shaft2, blood, smoke, shotgun, gauntlet, machine, rail, gib, shots, shots2, bubble, flash +(использовать их крайне не рекомендуется). + + + + +function GetSpecObjStruct(ID : byte):TSpecObj; + +Доступ к массиву спец объектов. Таких как двери, кнопки, итп. +Массив объектов objs: array [0..1000] of TObj; + +type TSpecObj = record // do not modify + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,orient,nowanim,special:word; + objtype : byte; + end; + +Причем, если active = false то данный спец объект не действителен. + +Данный тип был заведен достаточно давно, года 2 назад. Здесь большинство названий переменных не соотвествует действительности... +И массив не динамический (2 года назад я не умел делать другие). + + +ужно делать так: + for i := 0 to 255 do + if GetSpecObjStruct(i).active then ... + else break; // при первом появлении active=false можно прекращать сканирование. + +------------------------ +tmp.objtype = 1 - teleporter +tmp.x - position X +tmp.y - position Y +tmp.lenght - destination X +tmp.dir - destination Y +------------------------ +tmp.objtype = 2 - button +tmp.x - position X +tmp.y - position Y +tmp.targetname - статус зажатости кнопки (1=зажата) +tmp.lenght - время зажатости, переменная уменьшается, при достижении 0, targetname становится 0 +tmp.wait - при нажатии lenght присваивается wait. +tmp.target - TARGET_ID. ищет door или area_pain у которого targetname=tmp.target и активирует его +------------------------ +tmp.objtype = 3 - door +tmp.orient - ориентация двери. (0=closed, horizontal ||| 1=closed, vertical ||| 2=opened, horizontal ||| 3=opened, vertical) +tmp.targetname - TARGET_ID. активируется by button, trigger, area_push. + +Дальше вспомнить и разобрать что там написано не смог, скажу только что +tmp.target и +tmp.dir +учавствуют в статусе двери (открытая \ закрытая) \ No newline at end of file diff --git a/DOCS/bottesters.txt b/DOCS/bottesters.txt new file mode 100644 index 0000000..413e130 --- /dev/null +++ b/DOCS/bottesters.txt @@ -0,0 +1,4 @@ +agent007mail@list.ru, fsic_ms3@mail.ru, goorus@list.ru, xproger@list.ru, ranger_god@mail.ru, ubub@nm.ru, djdimps@yandex.ru, shtirlic5@mail.ru, tbutton@yandex.ru, boudaev-ddd@mail.ru, +psibug@inbox.ru, lagut-89@yandex.ru, whm@inbox.ru, surgeon_ld@mail.ru, _elven@mail.ru, pqr@mail.ru, booblikk@narod.ru, innochenti@rambler.ru, gibs@planetsky.com.ru, axxxe@yandex.ru, +hramovv@yandex.ru, shadow@3dg.ru, roma219@yandex.ru, markamer@mail.ru, sphynx_team@hotbox.ru, innochenti@rambler.ru, source90@mail.ru, dog1@rdgn.wsnet.ru +(last line 8 emails) \ No newline at end of file diff --git a/DOCS/bugReport.txt b/DOCS/bugReport.txt new file mode 100644 index 0000000..f25e552 --- /dev/null +++ b/DOCS/bugReport.txt @@ -0,0 +1,45 @@ +23:30 02.09.2003 +- r_fx_plasma - 2 раза выводит значение. +- Все NUM кнопки небиндят say и ещё какие-то комманды, которые появились в 040. +- Подложка статистики (зажатая в graph.d) не держит прозрачность. +- Перчатка в нфк (не в graph.d) перевернута по вертикали :) +- Отрисовка оружия неправильна, попробуй нарисовать ровный прямоугольник, место любого випона, + а потом глянь, на него в нфк, ещё когда смотришь влево, центровка неверна, а при прыжке + перерисовывается оружие неправильно (когда влево смотришь), от этого сильно дёргается. + Кстати, если ты исправишь этот глюк, то випоны можно будит увеличить в длину, без изменения + размеров текстуры, так как сейчас он из-за этого отображает лищние пиксели слева от прошлой + пушонки. +- В окне хотсита нельзя нажать f для начала матча, и ещё mousebutton'ами нельзя менять режим + игры. +- Пов, можешь сделать, чтобы строка execing .cfg, выводилась после чтения первой команды + конфига, а то писать скрипты неудобно, на экране постоянно выводится эта надпись, а так + в начале можно задать messagetime 0, а потом любое другое, на другие же конфиги это + никак не повлияет, посмотри, допустим, мой скрипт volume, всё поймешь, приходится для него + биндить лишнюю клавишу на messagetime 125. +- zoomwindow, после следующего alt+enter не сохраняется, а при alt+tab глючит сильно + (winXP pro bild 2600, ati radeon7000 32ram) +- Хотелось бы timescale, он же speeddemo, побольше, допустим до 100, с нынешним шагом. +- Нехватает кнопок на бинды, пора делать F1 - F12, нельзя биндить "<" , ">" , "[" , "]" ,"-", + "+" и иже с ними, а это уже больше 6 клавишь, непорядочек. +- Если забиндить что-то вроде bind 0 say ^#gg, (то есть цветной текст), то в консоли при + запросе bind 0 будет правая кавычка цвета ^#, а не ^7. +- Звук, должен непросто пропадать, по мере удаления от него, он должен постепенно + уменьшаться в громкости. +- Забиндиные say 's (и ещё что-то вроде) выводятся и если ты в меню ESC(мульт), + изврат bind downarrow say wtf? :) +- Зачем в демках проигровать НЕ ТВОИ exellent, impressive, etc. да ещё на таком расстоянии. +- Насколько я понимаю, комманда kill, должна делать суицид и в мультике (как в q3), ан нет. +- Когда ты успел убрать nfkitemspawn, ни в одном change файле этого нет :) +- Если поставить spectator 1, и создать teamplay сервер, то ты спавнишься там со скином + дефолт, и без всяких вопросов, сверху же будет гореть following xxx, имхо, нужно писать + no players to follow, и не спавнить игрока вовсе, аналогично и с остальными режимами. +- Если в имени игрока есть "|", то autorecord обваливается при записи на диск. +- basenfk/nfksetup.ini, мне кажется, лучше его переиминовать в nfkchat.ini, а то как-то + неясно. +- А ты можешь менять цвет тени от текста, если да, то можно сделать тег ^x (менять цвет тени, + в хексах), и ещё мона тег ^h, который цвет форграунда меняет. +- Было бы интерестно сделать что-то вроде CrosshairNames для тиммэйтов, в районе 8-10 бриков, + у них над головами отображаются хелса, а комманду надо делать не со значением, а как + cl_avidemo, то есть один раз нажал - включено, второй - выключено, чтобы удобнее биндить + было. +- хм, нафик было встраивать графон в nfkRadiant.exe, если в graph.d он весь есть? \ No newline at end of file diff --git a/DOCS/bugreport040.txt b/DOCS/bugreport040.txt new file mode 100644 index 0000000..7261d71 --- /dev/null +++ b/DOCS/bugreport040.txt @@ -0,0 +1,2 @@ +Баги +---- diff --git a/DOCS/changes040.txt b/DOCS/changes040.txt new file mode 100644 index 0000000..80317ad --- /dev/null +++ b/DOCS/changes040.txt @@ -0,0 +1,94 @@ +------------------------- +Need For Kill +version 040 +http://www.3dpower.org +olde http://powersite.narod.ru +------------------------- +Список изменений относительно nfk037. + +- Изменено: полностью переделан вывод звука, теперь он не будет пропадать на компах на которых это происходило. Это касается и отставания mp3 в nfkamp. +- Изменено: в NFK теперь новый shotgun (выглядит по другому). Прошу любить и жаловать :). +- Добавлено: в демках и в режиме спектатора, POV (за кого смотреть) можно менять кнопкой fire (по умолчанию mouse1). +- Добавлено: команда cl_avidemo. Во включенном режиме, последовательно сохраняет скриншоты в basenfk\. Поле чего эти скриншоты можно склеить в avi файл (например в adobe premier). +- Добавлен: коментатор текущего счета :), говорит "youre lost the lead" или "teams for tied". консольная команда "announcer"[0-1]. +- Добавлено: команда sv_testplayer2. Сервак создается с 2мя игроками (второй - на клаве). Терь на 2х компах можно поиграть в троем. +- Исправлено: глюки с вертикальной синхронизацией. Терь в полноэкранном режиме экран не будет "моргать". Возможность включения \ выключения вертикальной синхронизации у монитора. +- Добавлено: Теперь в NFK можно добавить свои брики. Делается это через "configure\brick palette" в NFKRadiant. +- Изменено: консоль теперь "выкатывается" а не просто появляется. +- Добавлено: возможность замены всех 8ми бэкграундов нфк. а также замена заднего фона консоли, и подложки под окно статистики. +- Добавлено: в каталоге maps можно создавать поддиректории. Они адекватно воспринимаются самим nfk. +- Добавлено: возможность использования скроллера. (можно биндить: mwheelup, mwheeldown). +- Добавлено: после смерти из игроков вываливается оружие. Этого не происходит в режимах игры TRIX, PRACTICE, RAILARENA. Выпавшее оружие лежит минуту, потом исчезает. +- Добавлено: Эффект света, применено на: ракеты, взрывы, плазму. А также чел с квадом теперь светится. Все это отключается командой "r_040fx 0". +- Изменено: дым от ракет и гранат теперь намного красивее. +- Добавлено: возможность командного чата. Команда "say_team RA Taken". +- Добавлено: возможность биндить ЛЮБУЮ команду. Например: bind space say just a business, nothing personal. (кавычки при этом использовать нельзя). +- Добавлено: новый сетевой режим игры CAPTURE THE FLAG. Захват флага. +- Добавлено: новый сетевой режим игры DOMINATION. Доминирование. +- Добавлено: Добавлен setup.exe. Это программа настройки некоторых параметров NFK. +- Добавлено: Возможность выбора hardware \ software звука. +- Исправлено: глобальное торможение NFK под некоторыми системами (например на некоторых Windows XP) +- Добавлено: teambar (Только в командных режимах игры). панель, отображающая статус игроков в вашей команде, показывает: ник, жизни, армор, оружие, локацию. +- Добавлено: настройки teambar. "ch_teambar_color"[0-13] - цвет панели. "ch_teambar_style"[0-3] - стиль панели. "ch_teambar_showmyself"[0-1] - не показывать себя в панели.. +- Изменено: Значительно улучшена консольная команда "map": (1,2). +1) В нее встроен автоматический поиск, к примеру если вашу карту нфк не нашел в корневой папке maps, то он проводит сканирование всех вложенных подпапок в maps, и в итоге найдет вашу карту гдебы она не лежала :). Теперь достаточно писать просто "map mapname", без указывания поддиректорий. +2) Команда map теперь может менять GAMETYPE! (тип игры). Как сменить gametype: Команда "map dm2 deathmatch" загрузит карту dm2 в режиме DeathMatch. Чтобы получить help по смене gametype'ов (и все значения параметра gametype), введите (в нфк) "map dm2 help". +- Добавлено: команды "nextwpn_skipempty", "p2nextwpn_skipempty", если включено, то при выборе оружия, через nextweapon и prevweapon, не будут выбираться оружия без патронов. +- Добавлено: команда writeconfig. "writeconfig myconfig", в файл myconfig.cfg будут записаны текущие настройки нфк. +- Исправлено: иногда скорость анимации модели после конца haste оставалась такойже быстрой как и при наличии haste. +- Добавлено: теперь если соединение сильно лагает, то появляется надпись "Connection Interrupted". +- Исправлено: area_waterillusion пропадал раньше времени при скроллинге на больших картах. +- Исправлено: иногда анимация лавы\воды сбивалась на больших картах +- Исправлено: в ffa демках fragbar показывал значение -9999. +- Исправлено: при выходе из нфк не запоминался параметр mouselook. +- Исправлено: брики, замененные командой brickreplace, сохранялись в демку. +- Исправлено: если в названии демы был знак "?", то при записи демы на винт, нфк умирал напрочь :) +- Изменено: команда autorecord. раньше имя игрока вставлялось в имя файла вместе с тэгами (^1^b), теперь тэги вырезаются. +- Исправлено: переписаны алгоритмы воспроизведения hit.wav. Раньше почему-то он проигрывался у того кого поранили, теперь он проигрывается у того чела который поранил. +- Исправлено: регуляторы громкости volume, mp3volume теперь корректно работают. и полностью не зависят друг от друга. +- Добавлено: NFKRadiant: операция CUT selecion (копирование+удаление (вырезание)). +- Исправлено: NFKRadiant: глюк: около doortrigger отрисовывался кусочек воды. +- Добавлено: теперь при повторном заходе в окно DEMOS, выбирается ранее выбранная дема. (запоминается типа). +- Добавлено: команда "r_displayrefresh". Изменяет частоту монитора в полноэкранном режиме. (пока особо не тестировалась). +- Добавлено: по окончанию демки у всех игроков выключается включенный gauntlet... +- Исправлено: теперь когда вы пытаетесь поиграть на карте где нет респавнов, вы не увидите нечеловеческих глюков, вас просто выкинут в меню, и скажут "кривая карта". +- Добавлено: команда "r_bgmotion". Бэкграунд движется не синхронно с картой (пространственный эффект). (только на больших картах). +- Добавлено: возвращена команда заливки цветом заднего фона. "fill_bgr", blue green red. (работает только с "drawbackground 0") +- Добавлено: команды настройки консоли: "ch_conspeed" "ch_conheight" "ch_conalpha". (скорость консоли, высота консоли, прозрачность). +- Изменено: команда "shownick 1" теперь применяется сразу, независимо то autoshownick. +- Исправлено: отклонение положения имени, наград от трупов в демке. +- Добавлено: NFKRadiant: кнопка F5 перемещает текуще-выбранный объект (или локацию) в положение курсора. +- Исправлено: теперь команда "enemymodel" работает правильно (не сбрасывается) +- Добавлено: консольная команда "teammodel", назначает вашим тиммэйтерам выбранную модель. +- Добавлено: конс команда "r_railstyle". Стиль луча рэилгана. [0 - 4] (5 видов). (thnx to Deadlock) +- Изменено: немного оптимизирован сетевой код, теперь должно меньше лагать на медленных коннектах. +- Добавлено: конс команда "clear". Очищает консоль. +- Изменено: теперь после подбирания оружия, которого у вас не было, зажигается weaponbar. +- Добавлено: конс команда "cmdlist" - выводит список всех возможных конс комманд. +- Исправлено: на клиентах игроки после смерти не откидывались (умирали на текущей позиции XY). +- Добавлено: раздел DEMOS теперь поддерживает вложенные каталоги. +- Добавлено: конс команда "randommodels". Всем игрокам ставит рандомные модели (из доступных). Полезно при просмотре демок, если все играют одинаковыми моделями. +- Исправлено: глюк тянувшийся с nfk035 - оружие криво отрисовывается, наконец-то исправлен. +- Добавлено: при включенном r_fx_quad. Чел (при наличии quad) из красной команды светится красным. +- Добавлено: скроллинг консоли скроллером (на мышке). +- Исправлено: чат сообщения ("say"), всегда отправлялись только в нижнем регистре. Теперь можно отправлять в любом. +- Добавлено: добавлена CTF карта ctf1.mapa +- Исправлено: Оружие теперь находится 100% ровно (и при центровке тоже). +- Добавлено: В редакторе карт можно экспортировать custom brick палитру. +- Исправлено: если в папке maps находился левый файл (например cfg) - вылетало в главное меню. +- Добавлено: Заходить в подкаталоги в списке карт, теперь можно кнопкой mbutton2, 3. +- Исправлено: раньше, если записать демку, а потом выйти в DEMOS, то записанная демка там не появлялась, теперь все ОК. +- Исправлено: командa autorecord: при записи дата и время не изменялись (в названии демки), тоесть запись происходила в один и тотже файл. +- Изменено: команда autorecord теперь записывает не internal map name, а map filename. +Дописывает какой был режим игры (dm,ctf..) +- Изменено: команда autorecord: если игроков слишком много то их имена обрезаются, (длина имен в названии = 30 - КолвоИгроков * 3). +- Добавлено: скроллинг скроллером (на мышке) демок в окне DEMOS, а также заход в папки кнопками mbutton2, 3. +- Исправлено: раньше у gauntlet'а, при повороте, иногда появлялся левый (ненужный) пиксель. +- Добавлено: редактирование значений domlimit, capturelimit теперь доступно в меню multiplayer\create server +- Изменено: теперь fraglimit не учитывается в режиме игры CAPTURE THE FLAG +- Изменено: теперь timelimit и fraglimit не учитываются в режиме игры DOMINATION +- Добавлено: новая конс команда "cl_avimode". [0] - cl_avidemo записывает в jpg. [1] - cl_avidemo записывает в bmp. +- Изменено: теперь, если написать "model sarge", то автоматически выберется модель sarge+default. (это распространяется на p2model, enemymodel, teammodel) +- Исправлено: Раньше, при использовании trixmasta, в имени демки не убирались тэги цвета от имени игрока +- изменено: дефалтные значения capturelimit=8 domlimit=400. +- Изменено: максимальное значение forcerespawn теперь равно 10ти. +- Изменено: улучшена навигация по окну DEMOS (запоминание последней директории, home\end кнопки, итд) diff --git a/DOCS/changes050.txt b/DOCS/changes050.txt new file mode 100644 index 0000000..1b505fe --- /dev/null +++ b/DOCS/changes050.txt @@ -0,0 +1,39 @@ +------------------------ + Need For Kill + by 3d[Power] + version 050 + http://www.3dpower.org +------------------------ +Список изменений относительно nfk040. +Изменения в NFK050 это в основном изменения касающиеся сетевой игры, и всего что с ней связано. + +- Новый, и сильно улучшенный и оптимизированный сетевой код. Также изменился протокол. Сетевая игра теперь по протоколу UDP (порт 29991). +- Добавлен NFK Master Server, который называется NFK PLANET. Это сервер в инете, где Вы можете увидеть список серверов, и\или занести туда свой. + +- Добавлено: Если нфксерв в фуллскрине, и альттабнут, то когда ктонибудь коннектится, нфк сама возвращается из альттаба. +- Добавлено: команда "sv_maxplayers" . Лимит игроков на сервере. +- Добавлена команда "ipinvite". Кидает приглашение в игру по указанному IP адресу. Полезно если соединение устанавливается только в одну сторону. +- Добавлена команда "net_showbandwidth". Показывает прокачку. bytes \ sec. +- Добавлена команда "minimize" - cворачивает нфк, (полезно когда alt+tab не помогает). + +- Добавлено: голосование (callvote). Можно выдвигать на голование выбранную консольную команду, по проценту проголосовавших ЗА, выбирается, будет ли применена команда. + Конс команды: sv_allowvote, sv_vote_percent, sv_allowvote_restart, sv_allowvote_fraglimit, sv_allowvote_timelimit, sv_allowvote_capturelimit, sv_allowvote_domlimit, sv_allowvote_ready, + sv_allowvote_map, sv_allowvote_warmup, sv_allowvote_warmuparmor, sv_allowvote_forcerespawn, sv_allowvote_sync, sv_allowvote_sv_teamdamage, sv_allowvote_net_predict, sv_allowvote_sv_maxplayers. + Возможно голосовать за команды: restart, ready, map, fraglimit, timelimit, capturelimit, domlimit, warmup,warmuparmor, forcerespawn, sync, sv_teamdamage, net_predict, sv_maxplayers. + Пример: "callvote restart", "callvote map tourney4" + Отключение команд sv_allowvote_XXX запрещают отключенный вид голосования. sv_allowvote 0 - запрещает голосование в целом. +Добавлен звук, который проигрывается при старте голосования. + +- Добавлено: нфк запоминает кол-во фрагов дропнутых игроков, если они вновь подсоединились, им восстанавливают их фраги. +- Исправлено: убраны разные глюки с демками, и глюки в окне DEMOS. +- Изменено: улучшена конс команда "ipaddress", она теперь показывает внутренний и внешний IP. +- Добавлено: новая система предугадывания позиции игроков, что дает более точную подгонку позиций игроков на больших пингах (net_predict 1) +- Улучшено: полностью переделан шафт, теперь им возможно стрелять в инет игре (не лагает). +- Улучшено: улучшена работа сервера, и decicated сервера, теперь если играет большее колво игроков, и у сервера быстрый коннект, то от этого лучше всем, раньше это не имело значения практически. +- Улучшено: возмножность чата dedicated сервера. +- Исправлено: иногда демки записанные по мультиплееру, не работали.. вылетали с ошибкой. +- Исправлено: иногда на сервер не пускали, говорили что карта отличается (хотя они одинаковые). +- Исправлено: иногда неправильно загружалась карта при серфинге по каталогам в списке карт. +- Исправлено: глюки с midi проигрывателем. +- Исправлено: окончательно прибиты все глюки функциональности окна DEMOS. +- Изменено: теперь слишком длинные имена демок и карт, обрезаются при отображении. +- Исправлено: баг в редакторе карт с удалением спец объектов. \ No newline at end of file diff --git a/DOCS/changes050_ENG.txt b/DOCS/changes050_ENG.txt new file mode 100644 index 0000000..0d53b2c --- /dev/null +++ b/DOCS/changes050_ENG.txt @@ -0,0 +1,36 @@ +------------------------ + Need For Kill + version 050 + by 3d[Power] + http://www.3dpower.org +------------------------ +Changes since NFK version 040. +Changes in NFK050 are mostly affecting network gaming and all regarding it + +- New, greatly improoved and optimized network code. Protocol also changed. Nfk uses UDP now.. (port 29991). +- Online NFK Master Server was added, which named "NFK PLANET". It is a place where nfk players can play with each other. + +- Added: if nfk server is in fullscreen mode, and minimized, then somebody connects, nfk popup it self. +- Added: command "sv_maxplayers", for limiting maximum amount of players. +- Added: command "ipinvite". invites specified ip address to your server. Useful then connection is available only to one direction +- Added: command "net_showbandwidth". shows channel current bandwidth, bytes/sec (network). +- Added: command "minimize". minimizes nfk window + +- Added: VOTING. You can toggle voting for some console command, and if number of positive (YES) votes will be enough to apply this command, it will be executed at server. + You can vote for: restart, ready, map, fraglimit, timelimit, capturelimit, domlimit, warmup,warmuparmor, forcerespawn, sync, sv_teamdamage, net_predict, sv_maxplayers. + Example: "callvote restart", "callvote map tourney4". + Server's voting console commands: sv_allowvote, sv_vote_percent, sv_allowvote_restart, sv_allowvote_fraglimit, sv_allowvote_timelimit, sv_allowvote_capturelimit, sv_allowvote_domlimit, sv_allowvote_ready, + sv_allowvote_map, sv_allowvote_warmup, sv_allowvote_warmuparmor, sv_allowvote_forcerespawn, sv_allowvote_sync, sv_allowvote_sv_teamdamage, sv_allowvote_net_predict, sv_allowvote_sv_maxplayers. + +- Added: nfk remembers frags count of dropped players, and restores it upon players reconnect. +- Fixed: several bugs in DEMOS screen. +- Changed: command "ipaddress" now improoved, now it show internal and external ip address. +- Added: nfk guesses player's position based on player's ping. Recommended to be enabled, expecially at dedicated servers. (command "net_predict 1"); +- Improoved: shaft was greatly improoved, it not laggy now :) +- Improoved: stability and efficiency of server, and dedicated server. Now it works more effectively then players count is more than 2. +- Added: dedicated server chat ability +- Fixed: sometimes multiplayer's demos, not work. +- Fixed: sometimes clients cannot join, because of modified map (but maps was equial) +- Fixed: bugs with midi music player. +- Changed: long map names now stripped by mapnames viewer. +- Fixed: bug in map editor with deleting objects \ No newline at end of file diff --git a/DOCS/changes055_b1.txt b/DOCS/changes055_b1.txt new file mode 100644 index 0000000..c79b89a --- /dev/null +++ b/DOCS/changes055_b1.txt @@ -0,0 +1,12 @@ +- Добавлено: поддержка bot.dll +- Исправлено: глюки в callvote. +- Исправлено: иногда чел на клиенте не мог респавниться. +- Исправлено: в режиме игры Trick Arena работал timelimit. +- Исправлено: если на сервере записывалась демка, а клиент сменил имя, то в демке это не отображалось. +- Добавлено: команда "reconnect". Переподсоединяет к последнему серверу. +- Добавлено: игроки теперь сортируются в SCOREBOARD в зависимости от кол-ва фрагов. +- Изменено: доботанно меню HOTSEAT, player1\2 properties. Теперь все пункты выбираются мышью, при наведении. И активируются при нажатии mouse1. +- Исправлено: раньше можно было из конфига ехеc'нуть сам конфиг. результат: dead loop. +- Исправлено: если прописать quit или halfquit в autoexec.cfg, то нфк умирал. +- Исправлено: если в имени игрока были символы < > то демка не записывалась. (autorecord) +- Исправлено: глюк со статус барами в клиентских дуэльных демках. \ No newline at end of file diff --git a/DOCS/changes055_b2.txt b/DOCS/changes055_b2.txt new file mode 100644 index 0000000..1d72bf0 --- /dev/null +++ b/DOCS/changes055_b2.txt @@ -0,0 +1,6 @@ +- Исправлено: раньше можно было читить на больших картах с помощью команды cameratype 0 +- Исправлено: можно было присоединяться к клиентам. +- Изменено: теперь при вводе команды "kickplayer" сразу показываются все . +- Исправлено: команда "mp3play" написанная в autoexec.cfg теперь работает. +- Добавлено: автоматический проигрыватель комментариев к демке. Если допустим вы проигрываете \demos\demo1.ndm, то сразу будет проигрываться \music\demo1.mp3 +- Изменено: теперь новая анимация лавы\воды. \ No newline at end of file diff --git a/DOCS/changes055_b3.txt b/DOCS/changes055_b3.txt new file mode 100644 index 0000000..7de2098 --- /dev/null +++ b/DOCS/changes055_b3.txt @@ -0,0 +1,34 @@ +- Добавлено: превью карты в меню теперь скроллируется если карта большая. +- Исправлено: неработал timelimit +- Исправлено: иногда в scoreboard не отображались игроки, которые на самом деле есть. +- Исправлено: аттрибут "read only" на нфк картах, вешал нфк. +- Исправлено: mp3-коммент не проигрывался, если демка находится в , а mp3 в +- Исправлено: mp3-коммент теперь не пересекается с NFKAMP (не вызывают в друг друге глюки). +- Исправлено: mp3-коммент при выходе из демки теперь прекращает воспроизведение. +- Исправлено: раньше если после загрузки карты сменить BG, то в демку запишется выбранный BG, а не тот который был в карте. +- Исправлено: при использовании команды sv_testplayer2 1, клиенты не видели серверного игрока2. +- Исправлено: возможно исправлено, то что не загружался файл graph.d под WINNT. изза действующих ограничений системы. +- Исправлено: раньше можно было выдвигать новое голосование (vote), пока еще не закончилось старое. +- Изменено: по окончанию партии, игроки останавливают свое движение (раньше бежали в стену). +- Улучшено: теперь можно проигрывать и записывать демки содержащие пробелы в названии файла (" "). +- Добавлено: новый внешний вид гранаты (опционально). Включается командой "r_altgrenades 1". thnx to [MWMD]-Spike. +- Добавлено: опция "disable player 2: yes\no" в окне HOTSEAT. Для игры с ботами. +- Добавлено: команду (team) теперь можно выбирать из InGameMenu (то которое по ESC). (В вармапе). +- Добавлено: улучшенное редактирование строки ввода в консоли. Можно использовать стрелки leftarrow, rightarrow для поцизионирования курсора. Работает del. +- Изменено: теперь неправильно введенный ai address, в окне Direct Join, не добавляется в хистори . +- Изменено: хистори введенных комманд на консоли, теперь не запоминает повторно введенные команды. +- Улучшено: команда "randommodels" теперь ведёт себя более разумно. +- Изменено: восстановлена работа биндов num- num+ num* +- Исправлено: нельзя было послать чат из одной буквы. +- botapi: добавлено EVENT_MapChanged +- botapi: добавлено EVENT_DMGReceived +- botapi: добавлено EVENT_ChatReceived +- botapi: исправлено: если вызывали игровое меню (ESC), то бот останавливался. +- botapi: исправлено: цвет луча railgun у бота был рандомным при каждом выстреле. +- botapi: изменено: теперь версию bot.dll нужно писать в BotVersion():bot_ai.pas +- botapi: исправлено: на гранату не распространялся SetAngle(); +- botapi: добавлено: нфк отсылает в bot.dll список загруженных моделей. +- botapi: изменено: нфк теперь автоматически корректирует угол оружия, в зависимости от того куда повернута модель. Теперь в bot.dll вам этим заниматься не нужно. +- botapi: добавлено: новые и улучшенные процедуры в bot_util.pas +- nfkchat: с 056 поставляется новый NFKChat v0.71. +- nfkchat: изменён дизайн проиграммы (в лучшую сторону). Более простой и понятный интерфейс. Убраный некоторые глюки, а также добавлена возможность приватного разговора. \ No newline at end of file diff --git a/DOCS/changes056.txt b/DOCS/changes056.txt new file mode 100644 index 0000000..41f23b0 --- /dev/null +++ b/DOCS/changes056.txt @@ -0,0 +1,48 @@ +------------------------ + Need For Kill + by 3d[Power] + version 056 + http://www.3dpower.org +------------------------ + +Список изменений относительно nfk050. + +- Добавлено: поддержка bot.dll +- Добавлены: две новых карты: DM0 и CTF2. +- Добавлено: автоматический проигрыватель комментариев к демке. Если допустим вы проигрываете \demos\demo1.ndm, то сразу будет проигрываться \music\demo1.mp3 +- Добавлено: игроки теперь сортируются в SCOREBOARD в зависимости от кол-ва фрагов. +- Добавлено: команда "reconnect". Пере подсоединяет к последнему серверу. +- Добавлено: превью карты в меню теперь скроллируется если карта большая. +- Изменено: доработано меню HOTSEAT, player1\2 properties. Теперь все пункты выбираются мышью, при наведении. И активируются при нажатии mouse1. +- Изменено: теперь новая анимация лавы\воды. +- Добавлено: новый внешний вид гранаты (опционально). Включается командой "r_altgrenades 1". thnx to [MWMD]-Spike. +- Добавлено: опция "disable player 2: yes\no" в окне HOTSEAT. Для игры с ботами. +- Добавлено: команду (team) теперь можно выбирать из InGameMenu (то которое по ESC). (В вармапе). +- Добавлено: улучшенное редактирование строки ввода в консоли. Можно использовать стрелки leftarrow, rightarrow для позиционирования курсора. Работает del. +- nfkchat: с 056 поставляется новый NFKChat v0.71. +- nfkchat: изменён дизайн программы (в лучшую сторону). Более простой и понятный интерфейс. Убраны некоторые глюки, а также добавлена возможность приватного разговора. +- Изменено: теперь при вводе команды "kickplayer" сразу показываются все . +- Изменено: по окончанию партии, игроки останавливают свое движение (раньше бежали в стену). +- Изменено: теперь неправильно введенный ip address, в окне Direct Join, не добавляется в хистори . +- Изменено: хистори введенных комманд на консоли, теперь не запоминает повторно введенные команды. +- Изменено: восстановлена работа биндов num- num+ num* +- Улучшено: команда "randommodels" теперь ведёт себя более разумно. +- Улучшено: теперь можно проигрывать и записывать демки содержащие пробелы в названии файла (" "). +- Исправлено: глюки в callvote. +- Исправлено: иногда чел на клиенте не мог респавниться. +- Исправлено: в режиме игры Trick Arena работал timelimit. +- Исправлено: если на сервере записывалась демка, а клиент сменил имя, то в демке это не отображалось. +- Исправлено: раньше можно было из конфига ехеc'нуть сам конфиг. результат: dead loop. +- Исправлено: если прописать quit или halfquit в autoexec.cfg, то нфк умирал. +- Исправлено: если в имени игрока были символы < > то демка не записывалась. (autorecord) +- Исправлено: глюк со статус барами в клиентских дуэльных демках. +- Исправлено: некоторые демки подвисали при проигрывании. +- Исправлено: раньше можно было читить на больших картах с помощью команды cameratype 0 +- Исправлено: можно было присоединяться к клиентам. +- Исправлено: атрибут "read only" на нфк картах, вешал нфк. +- Исправлено: команда "mp3play" написанная в autoexec.cfg теперь работает. +- Исправлено: раньше если после загрузки карты сменить BG, то в демку запишется выбранный BG, а не тот который был в карте. +- Исправлено: при использовании команды sv_testplayer2 1, клиенты не видели серверного игрока2. +- Исправлено: возможно исправлено, то что не загружался файл graph.d под WINNT. из-за действующих ограничений системы. +- Исправлено: раньше можно было выдвигать новое голосование (vote), пока еще не закончилось старое. +- Исправлено: нельзя было послать чат из одной буквы. \ No newline at end of file diff --git a/DOCS/changes057.txt b/DOCS/changes057.txt new file mode 100644 index 0000000..1787101 --- /dev/null +++ b/DOCS/changes057.txt @@ -0,0 +1,12 @@ +- Изменено: теперь при дропе таймаутных игроков, пишут "dropped by timeout". +- Исправлено: если удалить бота с флагом - флаг пропадал навсегда. +- Исправлено: команда "enemymodel" не работала на ботов. +- Добавлено: если кол-во игроков лимитированно командой sv_maxplayers, то при добавление бота, об этом пишут. +- Добавлено: теперь в меню по кнопке ESC, в демке, вместо Restart Level, опция Restart Demo - проигрывает демку заново. +- Добавлено: в имени (name) и sv_hostname теперь можно использовать пробелы. +- Исправлено: проблемы с коннектами по мультиплееру. Теперь коннектится даже если чел за шлюзом, или через GPRS. + +- Исправлено: +- Изменено: +- Улучшено: +- Добавлено: diff --git a/DOCS/changes058.txt b/DOCS/changes058.txt new file mode 100644 index 0000000..e88e969 --- /dev/null +++ b/DOCS/changes058.txt @@ -0,0 +1,5 @@ +- Добавлено: команда "spectator 1" теперь снова работает. Набрав ее на клиенте, можно присоединиться к серверу в качестве наблюдателя. +- Добавлено: команда "sv_allowspectator". Разрешает \ запрещает на сервере присоединение спектов. +- Добавлено: команда "sv_maxspectators". Максимальное колво спектов которые могу присоединиться к этому серверу. +- Добавлено: команда "sv_powerup". Разрешает \ запрещает на сервере powerups (появление предметов quad, haste итп). +- Добавлено: новая scoreboard. В стиле QuakeWorld, включается командой "ch_qwscoreboard" \ No newline at end of file diff --git a/DOCS/changes060.txt b/DOCS/changes060.txt new file mode 100644 index 0000000..3865de7 --- /dev/null +++ b/DOCS/changes060.txt @@ -0,0 +1,28 @@ +------------------------ + Need For Kill + by 3d[Power] + version 060 + http://www.3dpower.org +------------------------ + +- Добавлено: Поиск серверов по лану (LAN Broadcast), в меню MULTIPLAYER появился соответствующий пункт. +- Добавлено: Спектаторы. команда "spectator 1" теперь снова работает. Набрав ее на клиенте, можно присоединиться к серверу в качестве наблюдателя. +- Добавлено: команда "sv_allowspectator". Разрешает \ запрещает на сервере присоединение спектов. +- Добавлено: команда "sv_maxspectators". Максимальное колво спектов которые могу присоединиться к этому серверу. +- Добавлено: команда "sv_powerup". Разрешает \ запрещает на сервере powerups (появление предметов quad, haste итп). +- Добавлено: новая scoreboard. В стиле QuakeWorld, включается командой "ch_qwscoreboard 1" +- Исправлено: нфк подвисало после окончания проигрывания некоторых демок. +- Изменено: теперь боты в командных режимах игры сами выбирают себе команду, если она не была назначена игроком. +- Добавлено: оптимизация сетевого кода, если игроков > 2. Должно уменьшить кол-во траффика, и уменьшить лаги. +- Добавлено: новый внешний вид мяса. +- Исправлено: после окончания партии игрок продолжал стрелять из шафта, накручивалась статистика выстрелов. +- Исправлено: на клиенте в инет игре, могло появиться несколько CTF флагов. +- Добавлено: поддержка TGA 32 bit формата в моделях. Модели в bmp по прежнему работают. Но в случае если вместо bmp указаны TGA, модель грузится в 32 bit с альфа каналом. +- Исправлено: максимальный размер фрейма в модели теперь 96, во избежании читов с командой "enemymodel". +- Исправлено: пропадала последняя буква чата say_team, при сетевой игре на несколько человек. +- Исправлено: плазма пролетала сквозь игроков в демках. +- Исправлено: клиенту иногда писали "map not found", когда карта есть. Такое случалось если путь к nfk.exe был слишком длинный. +- Добавлено: выпадающие после смерти поверапы (квад, итп). +- Исправлено: решена основная проблема не коннекта в интернет играх, теперь можно присоединяться к сервакам до которых нету пинга, иными словами можно создавать игры будучи за шлюзом, который с блокированием входящего траффика. +- Исправлено: бота с невидимостью было видно. +- Исправлено: dedicated teamplay server просил выбрать команду. \ No newline at end of file diff --git a/DOCS/changes070.txt b/DOCS/changes070.txt new file mode 100644 index 0000000..601ddcb --- /dev/null +++ b/DOCS/changes070.txt @@ -0,0 +1,18 @@ +------------------------ + Need For Kill +------------------------ + +- Изменено: Переделан сетевой код. Теперь не тормозит при 5ти и более игроках в лан игре. Также улучшена игра по интернету. +- Добавлено: Трупы теперь разрываются на мясо от взрывов ракет и гранат. +- Изменено: Трупы теперь тают, а не просто исчезают. +- Добавлено: Вставка текста из буфера обмена в консоль (ctrl+v). Также возможна вставка IP адреса из буфера в поле ввода окна Direct Join. +- Исправлено: трупы проваливались сквозь кирпичи(?) +- Исправлено: неправильно показывались фраги у dedicated сервера. также исправлено что нажатием mouse1 не менялся pov (то за кем следить камерой). +- Исправлено: при "ch_qwscoreboard 1" слишком длинное имя игрока вызывало ошибку. +- Добавлено: команда "h_exec". работает также как и "exec", только не выводит на консоль надпись "execing *.cfg". +- Исправлено: если в имени игрока был символ "|" команда autorecord не работала. +- Добавлено: черный цвет в имени игрока. тэг ^0 +- Добавлено: новый HUD. На больших картах включается по умолчанию. HUD предназначен только для игрока 1. Команды настройки: ch_hudWidth, ch_hudHeight, ch_hudX, ch_hudY, ch_hudAlpha, ch_hudIcons, ch_hudshadow, ch_hudStretch, ch_hudVisible +- Изменено: панелька с фрагами (fragbar), теперь появляется и в Hotseat, если идет игра одного человека с ботами. +- Добавлено: Боты, при активном callvote, голосуют также как проголосовал сервер. +- Добавлено: rcon управление сервером с клиента. Команда "rconpassword" устанавливает пароль на "rcon" управление. Ввод команд серверу - через команду "rcon". Например "rcon restart". Консоль синхронизированна очень хорошо, создается ощущение что на клиенте серверная консоль :) \ No newline at end of file diff --git a/DOCS/dom.rules.txt b/DOCS/dom.rules.txt new file mode 100644 index 0000000..aab6df7 --- /dev/null +++ b/DOCS/dom.rules.txt @@ -0,0 +1,3 @@ +"Domination games: Есть несколько контрольных точек. Цель - получить контроль над этими точками (пройти через них, в результате чего их цвет поменяется на цвет вашей команды) и не потерять его. Очки зарабатываются за каждую секунду, когда ваша команда котролирует эти точки." + +While you have a control of a domination point, your team gains points. The first team to reach "dominationlimit" points wins the match \ No newline at end of file diff --git a/DOCS/logmatch.txt b/DOCS/logmatch.txt new file mode 100644 index 0000000..8a20f97 --- /dev/null +++ b/DOCS/logmatch.txt @@ -0,0 +1,21 @@ +[DJ]_DimPs vs 3d[Power] +Type: Railarena +Win: 2 (Это значит, что выиграл второй плеер) +или Win: [DJ]_DimPs +Kill: 100 +Death: 10 +Suicides: 3 +dmggiv: 100000 +dmgrec: 1000 +ex: 5 +imp: 10 +hum: 0 + +Kill: 100 +Death: 10 +Suicides: 3 +dmggiv: 100000 +dmgrec: 1000 +ex: 5 +imp: 10 +hum: 0 \ No newline at end of file diff --git a/DOCS/notes040.txt b/DOCS/notes040.txt new file mode 100644 index 0000000..3893f5f --- /dev/null +++ b/DOCS/notes040.txt @@ -0,0 +1,137 @@ +============================ +Need For Kill ver 040 +Заметки о NFK040 +(c) 3d[Power] +2003 +http://www.3dpower.org +============================ + + +CTF. +------------------------ +* В нфк 040 добавлен новый сетевой режим игры Capture The Flag. +Прошу заметить что в режиме CTF игроки появляются не на обычных +RESPAWN позициях, а на REDRESPAWN и BLUERESPAWN позициях, в +зависимости от команды игрока. В других режимах игры, red respawn +и respawn blue не используются. +* CTF Бонусы: За захват флага игрок получает бонус 5 фрагов. +За возвращение своего флага на базу - бонус 1 фраг. +* При старте сервера в режиме CTF. sv_teamdamage (ранение +своих по команде) автоматически становится 0 (не ранятся). +* Лимит захватов флага регулируется консольной командой +"capturelimit" +* NFK не запустит режим CTF на карте, где неправильное кол-во +флагов или red\blu respawn'ов. +* fraglimit не учитывается +* В режиме игры CTF доступен TEAMBAR + +DOMINATION +------------------------ +* В нфк 040 добавлен новый сетевой режим игры Domination. Смысл игры: +Ваша команда должна захватить как можно больше dompoints (флаги в DOM). +Каждый dompoint приносит 0.33 фрага в секунду своей команде, т.е. +за 3 секунды команда получает 1 фраг (+1 to domscore). Количество +dompoints на карте: только 3! +* При старте сервера в режиме DOMINATION. sv_teamdamage 0. (нельзя ранить) +* Лимит dom score регулируется консольной командой "domlimit" +* NFK не запустит режим DOM на карте, где если dompoins <> 3 +* fraglimit и timelimit не учитываются +* Dombar - панель, отображающая статус игры domination. Для настройки +dombar, есть 2 консольные команды "ch_dombarstyle", "ch_dombarpos" +* "ch_dombarstyle" [0-3] +0: Отключен +1: На панели 3 флага, каждый соответствует флагам в игре (с таким-же цветом). +2: Тоже что и "1", только флаги заменены на текст. +3: Один флаг, его цвет символизирует цвет доминирующей команды. +* "ch_dombarpos" [0-400]. Позиция панели по оси Y +* В режиме игры DOM доступен TEAMBAR + +DROPPABLE WEAPONS +------------------------ +* В нфк 040 из игроков (после смерти) вываливается оружие. +* При подбирании оружия, Вы получаете: во-первых само оружие :), +во-вторых, патроны (к текущему количеству патронов): +Shotgun +10 +Grenade +5 +Rocket +10 +Shaft +130 +Rail +10 +Plasma +50 +BFG +15 +* Оружие не вываливаеся в режимах игры: TRIX, RAILARENA, PRACTICE +* Выпавшее оружие лежит минуту, потом исчезает. + + +NEW FX EFFECTS +------------------------ +* В нфк 040 добавлены новые визуальные эффекты. Настройка этих +эффектов вынесена в консольные команды. По умолчанию все эффекты +включены. Команды: +r_fx_smoke - новый красивый дым (у ракет, гранат). +r_fx_rlbfg - свет от ракет, bfg. +r_fx_plasma - новая плазма. +r_fx_quad - свет от quad (player). +r_fx_explo - свет при взрывах (ракет, гранат, bfg). +* К новым эффектам можно отнести новые стили луча рэилгана. Которые +выбираются командой "r_railstyle" [0-4] + + +NEW CONSOLE COMMANDS +----------------------- +announcer [0-1]: комментатор текущего счета , говорит "youre lost the lead" или "teams for tied" итд. +teammodel [model+skin]: назначает вашим тиммэйтерам выбранную модель. +cl_avidemo (number): последовательно сохраняет скриншоты в basenfk\. с именем 0001.jpg. Если указан параметр (number) то файлы будут создаваться начиная с (number), например "cl_avidemo 1000", или "cl_avidemo" (с 0). +sv_testplayer2: мультиплеерная команда. На сервере создается второй игрок. Его управление от player2 в hotseat. +r_bgmotion [0-1]: Бэкграунд движется не синхронно с картой (пространственный эффект). Только на больших картах). +r_railstyle [0-4]: Стиль луча рэилгана. +fill_bgr [$AABBCC]: Заливка заднего фона, (при "drawbackground 0"). Где AA=синий. BB-зеленый. CC-красный. Например: "fill_bgr $0000FF" - заливка красным цветом. (значения в шестнадцатеричной системе) +ch_conspeed [1-480]: Cкорость выдвижения консоли. +ch_conheight [64-480]: высота консоли (максимальное расстояние на которое может выдвинуться консоль). +ch_conalpha [1-255]: Степень прозрачности консоли. +ch_constretch [0-1]: Растяжение бэкграунда консоли. (только при подключенной 040_CUSTOM_GRAFIX) +clear : Очищает консоль от всех надписей. +capturelimit : Лимит захватов флага (CTF Only) +domlimit : Лимит очков в режиме игры Domination. +hidep2statusbar : Убирает статусбар игрока2. +r_markemptydeath [0-1]: Делает death и empty брики видимыми. +r_fx_smoke [0-1]: Спец эффект: новый дым +r_fx_rlbfg [0-1]: Спец эффект: свет от ракет, bfg. +r_fx_plasma [0-1]: Спец эффект: новая плазма. +r_fx_quad [0-1]: Спец эффект: свет от quad (player). +r_fx_explo [0-1]: Спец эффект: свет при взрывах (ракет, гранат, bfg). +cmdlist : Выводит список всех консольных команд. +say_team [text]: отправить чат только своим по команде (multiplayer team game only) +ch_dombarpos: Позиция DOMBAR (панель отображающая статус игры Domination) по оси Y +ch_dombarstyle [0-3]: Внешний вид DOMBAR. +randommodels : Всем игрокам ставит рандомные модели (из доступных). +ch_teambar_showmyself [0-1] - показывать себя в TEAMBAR.. +ch_teambar_color [0-13] - цвет TEAMBAR +ch_teambar_style [0-3] - стиль TEAMBAR. +cl_avimode [0-1]: 0 - cl_avidemo записывает в jpg. 1 - cl_avidemo записывает в bmp. +writeconfig: "writeconfig myconfig", в файл myconfig.cfg будут записаны текущие настройки нфк. +nextwpn_skipempty [0-1]: при выборе оружия, через nextweapon и prevweapon, не будут выбираться оружия без патронов. +p2nextwpn_skipempty [0-1]: тоже самое, только для игрока2. +ch_showrecordinglabel [0-1]: (не) показывать вверху экрана надпись "recording xxxx.ndm", в случае записи демки. + +NFK CUSTOM GRAFIX +------------------- +* В нфк 040 некоторую графику можно заменять на свою. А конкретно: подложка под консоль, +бэкграунды, подложка под статистику. +* Чтобы установить свою графику вам нужно создать файл в формате jpg, и положить сюда: +basenfk\custom\console.jpg +basenfk\custom\bg_1.jpg +basenfk\custom\bg_2.jpg +basenfk\custom\bg_3.jpg +basenfk\custom\bg_4.jpg +basenfk\custom\bg_5.jpg +basenfk\custom\bg_6.jpg +basenfk\custom\bg_7.jpg +basenfk\custom\bg_8.jpg +basenfk\custom\stats.jpg +* Разрешения jpg файлов. В принципе любое, но вот рекомендованные разрешения: +console.jpg - 320x200 +bg_x.jpg - 256x256 +stats.jpg - 256x256 +(максимальный размер текстуры зависит от возможностей вашей видео карты) +* При использовании custom backgrounds рекомендую поставить "allowmapschangebg 0". +(запретить картам менять задний фон). \ No newline at end of file diff --git a/DOCS/rel2.txt b/DOCS/rel2.txt new file mode 100644 index 0000000..f043cdd --- /dev/null +++ b/DOCS/rel2.txt @@ -0,0 +1,9 @@ +IDNFK 120 90 400 290 NFK News & Updates Delivery System +PUSSY9 +w 140 120 ^3Welcome to NFK News & Updates Delivery +w 140 135 ^3System +w 140 165 ^7This internal service will bring the +w 140 180 ^7latest news about NFK updates, and +w 140 195 ^7any other major changes. +w 140 225 ^7For additional information visit +w 200 240 ^5www.3dpower.org \ No newline at end of file diff --git a/DOCS/scancodes.txt b/DOCS/scancodes.txt new file mode 100644 index 0000000..f33923c --- /dev/null +++ b/DOCS/scancodes.txt @@ -0,0 +1,165 @@ +(*--- Keyboard + Physical Keyboard Device ---*) + + DIKEYBOARD_ESCAPE = $81000401; + DIKEYBOARD_1 = $81000402; + DIKEYBOARD_2 = $81000403; + DIKEYBOARD_3 = $81000404; + DIKEYBOARD_4 = $81000405; + DIKEYBOARD_5 = $81000406; + DIKEYBOARD_6 = $81000407; + DIKEYBOARD_7 = $81000408; + DIKEYBOARD_8 = $81000409; + DIKEYBOARD_9 = $8100040A; + DIKEYBOARD_0 = $8100040B; + DIKEYBOARD_MINUS = $8100040C; (* - on main keyboard *) + DIKEYBOARD_EQUALS = $8100040D; + DIKEYBOARD_BACK = $8100040E; (* backspace *) + DIKEYBOARD_TAB = $8100040F; + DIKEYBOARD_Q = $81000410; + DIKEYBOARD_W = $81000411; + DIKEYBOARD_E = $81000412; + DIKEYBOARD_R = $81000413; + DIKEYBOARD_T = $81000414; + DIKEYBOARD_Y = $81000415; + DIKEYBOARD_U = $81000416; + DIKEYBOARD_I = $81000417; + DIKEYBOARD_O = $81000418; + DIKEYBOARD_P = $81000419; + DIKEYBOARD_LBRACKET = $8100041A; + DIKEYBOARD_RBRACKET = $8100041B; + DIKEYBOARD_RETURN = $8100041C; (* Enter on main keyboard *) + DIKEYBOARD_LCONTROL = $8100041D; + DIKEYBOARD_A = $8100041E; + DIKEYBOARD_S = $8100041F; + DIKEYBOARD_D = $81000420; + DIKEYBOARD_F = $81000421; + DIKEYBOARD_G = $81000422; + DIKEYBOARD_H = $81000423; + DIKEYBOARD_J = $81000424; + DIKEYBOARD_K = $81000425; + DIKEYBOARD_L = $81000426; + DIKEYBOARD_SEMICOLON = $81000427; + DIKEYBOARD_APOSTROPHE = $81000428; + DIKEYBOARD_GRAVE = $81000429; (* accent grave *) + DIKEYBOARD_LSHIFT = $8100042A; + DIKEYBOARD_BACKSLASH = $8100042B; + DIKEYBOARD_Z = $8100042C; + DIKEYBOARD_X = $8100042D; + DIKEYBOARD_C = $8100042E; + DIKEYBOARD_V = $8100042F; + DIKEYBOARD_B = $81000430; + DIKEYBOARD_N = $81000431; + DIKEYBOARD_M = $81000432; + DIKEYBOARD_COMMA = $81000433; + DIKEYBOARD_PERIOD = $81000434; (* . on main keyboard *) + DIKEYBOARD_SLASH = $81000435; (* / on main keyboard *) + DIKEYBOARD_RSHIFT = $81000436; + DIKEYBOARD_MULTIPLY = $81000437; (* * on numeric keypad *) + DIKEYBOARD_LMENU = $81000438; (* left Alt *) + DIKEYBOARD_SPACE = $81000439; + DIKEYBOARD_CAPITAL = $8100043A; + DIKEYBOARD_F1 = $8100043B; + DIKEYBOARD_F2 = $8100043C; + DIKEYBOARD_F3 = $8100043D; + DIKEYBOARD_F4 = $8100043E; + DIKEYBOARD_F5 = $8100043F; + DIKEYBOARD_F6 = $81000440; + DIKEYBOARD_F7 = $81000441; + DIKEYBOARD_F8 = $81000442; + DIKEYBOARD_F9 = $81000443; + DIKEYBOARD_F10 = $81000444; + DIKEYBOARD_NUMLOCK = $81000445; + DIKEYBOARD_SCROLL = $81000446; (* Scroll Lock *) + DIKEYBOARD_NUMPAD7 = $81000447; + DIKEYBOARD_NUMPAD8 = $81000448; + DIKEYBOARD_NUMPAD9 = $81000449; + DIKEYBOARD_SUBTRACT = $8100044A; (* - on numeric keypad *) + DIKEYBOARD_NUMPAD4 = $8100044B; + DIKEYBOARD_NUMPAD5 = $8100044C; + DIKEYBOARD_NUMPAD6 = $8100044D; + DIKEYBOARD_ADD = $8100044E; (* + on numeric keypad *) + DIKEYBOARD_NUMPAD1 = $8100044F; + DIKEYBOARD_NUMPAD2 = $81000450; + DIKEYBOARD_NUMPAD3 = $81000451; + DIKEYBOARD_NUMPAD0 = $81000452; + DIKEYBOARD_DECIMAL = $81000453; (* . on numeric keypad *) + DIKEYBOARD_OEM_102 = $81000456; (* <> or \| on RT 102-key keyboard (Non-U.S.) *) + DIKEYBOARD_F11 = $81000457; + DIKEYBOARD_F12 = $81000458; + DIKEYBOARD_F13 = $81000464; (* (NEC PC98) *) + DIKEYBOARD_F14 = $81000465; (* (NEC PC98) *) + DIKEYBOARD_F15 = $81000466; (* (NEC PC98) *) + DIKEYBOARD_KANA = $81000470; (* (Japanese keyboard) *) + DIKEYBOARD_ABNT_C1 = $81000473; (* /? on Brazilian keyboard *) + DIKEYBOARD_CONVERT = $81000479; (* (Japanese keyboard) *) + DIKEYBOARD_NOCONVERT = $8100047B; (* (Japanese keyboard) *) + DIKEYBOARD_YEN = $8100047D; (* (Japanese keyboard) *) + DIKEYBOARD_ABNT_C2 = $8100047E; (* Numpad . on Brazilian keyboard *) + DIKEYBOARD_NUMPADEQUALS = $8100048D; (* = on numeric keypad (NEC PC98) *) + DIKEYBOARD_PREVTRACK = $81000490; (* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) *) + DIKEYBOARD_AT = $81000491; (* (NEC PC98) *) + DIKEYBOARD_COLON = $81000492; (* (NEC PC98) *) + DIKEYBOARD_UNDERLINE = $81000493; (* (NEC PC98) *) + DIKEYBOARD_KANJI = $81000494; (* (Japanese keyboard) *) + DIKEYBOARD_STOP = $81000495; (* (NEC PC98) *) + DIKEYBOARD_AX = $81000496; (* (Japan AX) *) + DIKEYBOARD_UNLABELED = $81000497; (* (J3100) *) + DIKEYBOARD_NEXTTRACK = $81000499; (* Next Track *) + DIKEYBOARD_NUMPADENTER = $8100049C; (* Enter on numeric keypad *) + DIKEYBOARD_RCONTROL = $8100049D; + DIKEYBOARD_MUTE = $810004A0; (* Mute *) + DIKEYBOARD_CALCULATOR = $810004A1; (* Calculator *) + DIKEYBOARD_PLAYPAUSE = $810004A2; (* Play / Pause *) + DIKEYBOARD_MEDIASTOP = $810004A4; (* Media Stop *) + DIKEYBOARD_VOLUMEDOWN = $810004AE; (* Volume - *) + DIKEYBOARD_VOLUMEUP = $810004B0; (* Volume + *) + DIKEYBOARD_WEBHOME = $810004B2; (* Web home *) + DIKEYBOARD_NUMPADCOMMA = $810004B3; (* , on numeric keypad (NEC PC98) *) + DIKEYBOARD_DIVIDE = $810004B5; (* / on numeric keypad *) + DIKEYBOARD_SYSRQ = $810004B7; + DIKEYBOARD_RMENU = $810004B8; (* right Alt *) + DIKEYBOARD_PAUSE = $810004C5; (* Pause *) + DIKEYBOARD_HOME = $810004C7; (* Home on arrow keypad *) + DIKEYBOARD_UP = $810004C8; (* UpArrow on arrow keypad *) + DIKEYBOARD_PRIOR = $810004C9; (* PgUp on arrow keypad *) + DIKEYBOARD_LEFT = $810004CB; (* LeftArrow on arrow keypad *) + DIKEYBOARD_RIGHT = $810004CD; (* RightArrow on arrow keypad *) + DIKEYBOARD_END = $810004CF; (* End on arrow keypad *) + DIKEYBOARD_DOWN = $810004D0; (* DownArrow on arrow keypad *) + DIKEYBOARD_NEXT = $810004D1; (* PgDn on arrow keypad *) + DIKEYBOARD_INSERT = $810004D2; (* Insert on arrow keypad *) + DIKEYBOARD_DELETE = $810004D3; (* Delete on arrow keypad *) + DIKEYBOARD_LWIN = $810004DB; (* Left Windows key *) + DIKEYBOARD_RWIN = $810004DC; (* Right Windows key *) + DIKEYBOARD_APPS = $810004DD; (* AppMenu key *) + DIKEYBOARD_POWER = $810004DE; (* System Power *) + DIKEYBOARD_SLEEP = $810004DF; (* System Sleep *) + DIKEYBOARD_WAKE = $810004E3; (* System Wake *) + DIKEYBOARD_WEBSEARCH = $810004E5; (* Web Search *) + DIKEYBOARD_WEBFAVORITES = $810004E6; (* Web Favorites *) + DIKEYBOARD_WEBREFRESH = $810004E7; (* Web Refresh *) + DIKEYBOARD_WEBSTOP = $810004E8; (* Web Stop *) + DIKEYBOARD_WEBFORWARD = $810004E9; (* Web Forward *) + DIKEYBOARD_WEBBACK = $810004EA; (* Web Back *) + DIKEYBOARD_MYCOMPUTER = $810004EB; (* My Computer *) + DIKEYBOARD_MAIL = $810004EC; (* Mail *) + DIKEYBOARD_MEDIASELECT = $810004ED; (* Media Select *) + + +(*--- MOUSE + Physical Mouse Device ---*) + + DIMOUSE_XAXISAB = $82000200 or DIMOFS_X; (* X Axis-absolute: Some mice natively report absolute coordinates *) + DIMOUSE_YAXISAB = $82000200 or DIMOFS_Y; (* Y Axis-absolute: Some mice natively report absolute coordinates *) + DIMOUSE_XAXIS = $82000300 or DIMOFS_X; (* X Axis *) + DIMOUSE_YAXIS = $82000300 or DIMOFS_Y; (* Y Axis *) + DIMOUSE_WHEEL = $82000300 or DIMOFS_Z; (* Z Axis *) + DIMOUSE_BUTTON0 = $82000400 or DIMOFS_BUTTON0; (* Button 0 *) + DIMOUSE_BUTTON1 = $82000400 or DIMOFS_BUTTON1; (* Button 1 *) + DIMOUSE_BUTTON2 = $82000400 or DIMOFS_BUTTON2; (* Button 2 *) + DIMOUSE_BUTTON3 = $82000400 or DIMOFS_BUTTON3; (* Button 3 *) + DIMOUSE_BUTTON4 = $82000400 or DIMOFS_BUTTON4; (* Button 4 *) + DIMOUSE_BUTTON5 = $82000400 or DIMOFS_BUTTON5; (* Button 5 *) + DIMOUSE_BUTTON6 = $82000400 or DIMOFS_BUTTON6; (* Button 6 *) + DIMOUSE_BUTTON7 = $82000400 or DIMOFS_BUTTON7; (* Button 7 *) diff --git a/DOCS/test2.txt b/DOCS/test2.txt new file mode 100644 index 0000000..1ee8727 --- /dev/null +++ b/DOCS/test2.txt @@ -0,0 +1,26 @@ +============================ +Need For Kill ver 040 +Version 39test2 +(c) 3d[Power] +2003 +http://www.3dpower.org +============================ + +Изменения относительно test1: +- Изменено: Оружие теперь действительно находится ровно (вродебы :) +- Добавлено: Добавлен setup.exe. Это программа настройки некоторых параметров NFK. +- Добавлено: Возможность выбора hardware \ software звука. +- Добавлено: Возможность включения\выключения вертикальной синхронизации у монитора. +- Исправлено: не работал параметр "nosound" +- Исправлено: Если в окне multiplayer начать редактировать hostname, и нажать ESCAPE, то пропадал курсор.. +- Исправлено: Если у клиента карта лежала не в тойже папке что и у сервера, то при использовании сервером команды "map", клиента выкидывало. +- Исправлено: В списке карт неправильно работала кнопка PAGEDOWN. +- Исправлено: Если сначала поиграть в рейларену, а потом сыграть в dm (ctf, dom), то все предметы пропадут. +- Исправлено: скроллинг списка карт скроллером (на мышке) работал только в окне MULTIPLAYER (теперь работает и в окне HOTSEAT) +- Добавлено: скроллинг консоли скроллером (на мышке). +- Исправлено: чат сообщения ("say"), всегда отправлялись только в нижнем регистре. Теперь можно отправлять в любом. +- Исправлено: Редактор карт: при перемещении объекта кнопкой F5, в списке свойств объекта не обновлялось pos_x, pos_y +- Исправлено: Редактор карт: красный и синий флаги были перепутаны местами. +- Исправлено: после смены режима оконный\полноэкранный нфк неправильно отображал transparent custom brick'и +- Исправлено: Редактор карт неправильно считывал transparent custom brick'и из карт +- Добавлено: добавлена пробная CTF карта ctf1_test.mapa diff --git a/DOCS/test3.txt b/DOCS/test3.txt new file mode 100644 index 0000000..66fcdb9 --- /dev/null +++ b/DOCS/test3.txt @@ -0,0 +1,44 @@ +============================ +Need For Kill ver 040 +Version 39test3 +(c) 3d[Power] +2003 +http://www.3dpower.org +============================ + +Изменения относительно test2: +- !Исправлено: глобальное торможение NFK под некоторыми системами (например на некоторых Windows XP) +- Исправлено: Оружие теперь находится 100% ровно (и при центровке тоже). или? :) +- Исправлено: r_railstyle 1-4 глючил при отрисовке в правой стороне экрана. +- Исправлено: неправильно показывались цвета map locations в team чате. +- Исправлено: dompoints можно было захватывать в warmup режиме +- Добавлено: В редакторе карт теперь можно экспортировать custom brick палитру. +- Исправлено: если в папке maps находился левый файл (например cfg) - вылетало в главное меню. +- Исправлены: глюки со скроллингом сообщений в консоли. +- Изменено: команда r_markemptydeath, если включен режим игры TRIX ARENA, работает только в вармапе. +- Исправлено: если взять квад будучи в красной команде, и при этом иметь battlesuit, то были глюки с цветами. +- Добавлено: Заходить в подкаталоги в списке карт, теперь можно кнопкой mbutton2, 3. +- Исправлено: демки на картах где есть кастом брики не записывались вообще. +- Исправлено: раньше, если записать демку, а потом выйти в DEMOS, то записанная демка там не появлялась, теперь все ОК. +- Добавлено: teambar (Только в командных режимах игры). панель, отображающая статус игроков в вашей команде, показывает: ник, жизни, армор, оружие, локацию. +- Добавлено: настройки teambar. "ch_teambar_color"[0-13] - цвет панели. "ch_teambar_style"[0-3] - стиль панели. "ch_teambar_showmyself"[0-1] - не показывать себя в панели.. +- Исправлено: custom background отличающийся размером от 256х256 неправильно показывался. +- Исправлено: некоторые настройки в setup.exe применялись не сразу. +- Исправлено: система биндов: нельзя было биндить чат в верхнем регистре. +- Исправлено: система биндов: не работали команды состоящие из 1го слова (например stoprecord) +- Исправлено: система биндов: бинды не выводили сообщений, тоесть bind 1 currenttime (и аналогичные) не работали.. +- Исправлено: система биндов: исправлены глюки с биндами p2movedown.. +- Исправлено: командa autorecord: при записи дата и время не изменялись (в названии демки), тоесть запись происходила в один и тотже файл. +- Изменено: команда autorecord теперь записывает не internal map name, а map filename. +Дописывает какой был режим игры (dm,ctf..) +- Изменено: команда autorecord: если игроков слишком много то их имена обрезаются, (длина имен в названии = 30 - КолвоИгроков * 3). +- Добавлено: скроллинг скроллером (на мышке) демок в окне DEMOS, а также заход в папки кнопками mbutton2, 3. +- Исправлено: раньше у gauntlet'а, при повороте, иногда появлялся левый (ненужный) пиксель. +- Исправлено: В окне MULTIPLAYER небыло крадкого описания режима игры Domination. +- Добавлено: редактирование значений domlimit, capturelimit теперь доступно в меню multiplayer\create server +- Изменено: теперь fraglimit не учитывается в режиме игры CAPTURE THE FLAG +- Изменено: теперь timelimit и fraglimit не учитываются в режиме игры DOMINATION +- Добавлено: новая конс команда "cl_avimode". [0] - cl_avidemo записывает в jpg. [1] - cl_avidemo записывает в bmp. +- Возможно исправлено: трупы могли подбирать флаги и оружия.. +- Исправлено: неработала команда "brickreplace". +- Изменено: теперь, если написать "model sarge", то автоматически выберется модель sarge+default. +- Исправлено: Раньше, при использовании trixmasta, в имени демки не убирались тэги цвета от имени игрока diff --git a/DOCS/testers.txt b/DOCS/testers.txt new file mode 100644 index 0000000..ba514d0 --- /dev/null +++ b/DOCS/testers.txt @@ -0,0 +1 @@ +Kesha \ No newline at end of file diff --git a/EDITOR/RadiantPro/AddObjDialog.pas b/EDITOR/RadiantPro/AddObjDialog.pas new file mode 100644 index 0000000..e08ff87 --- /dev/null +++ b/EDITOR/RadiantPro/AddObjDialog.pas @@ -0,0 +1,44 @@ +unit AddObjdialog; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, ExtCtrls, StdCtrls, Buttons; + +type + TAddObjDlg = class(TForm) + RadioGroup1: TRadioGroup; + Panel1: TPanel; + RadioButton1: TRadioButton; + RadioButton2: TRadioButton; + RadioButton3: TRadioButton; + RadioButton4: TRadioButton; + RadioButton5: TRadioButton; + RadioButton6: TRadioButton; + RadioButton7: TRadioButton; + RadioButton8: TRadioButton; + RadioButton9: TRadioButton; + RadioButton10: TRadioButton; + BitBtn1: TBitBtn; + BitBtn2: TBitBtn; + procedure RadioButton1Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + AddObjDlg: TAddObjDlg; + +implementation + +{$R *.dfm} + +procedure TAddObjDlg.RadioButton1Click(Sender: TObject); +begin + Tag:=TRadioButton(Sender).Tag; +end; + +end. diff --git a/EDITOR/RadiantPro/Main.pas b/EDITOR/RadiantPro/Main.pas new file mode 100644 index 0000000..e25b9ba --- /dev/null +++ b/EDITOR/RadiantPro/Main.pas @@ -0,0 +1,1009 @@ +{ ------------------------------------------------------- + + NEED FOR KILL map editor. + for NFK v0.37. + + Created BY 3d[Power]. 2001-2002 + http://powersite.narod.ru + haz-3dpower@mail.ru + + SRC REQUIRES: + Delphi 5. + DelphiX (DelphiX2000_0717a). + + LICENSE: + You can modify or upgrade this source code only if you do it for Need For Kill. + Also u can use this source code for studies. + Any other use is not resolved. + + Народ, без вареза пожалуйста. И старайтесь не спрашивать меня что тут и как сделано, разбирайтесь сами. + +------------------------------------------------------- } + +unit Main; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + Grids, StdCtrls, Buttons, Menus, ComCtrls, + ImgList, ExtCtrls,shellapi, ToolWin, ActnList, StdActns, + Mask, ActnMan, ActnCtrls, XPStyleActnCtrls, + ActnMenus, CustomizeDlg, + + MyClasses, MyScroll, MyBuf; + +const + //длина буффера undo/redo + maxbuf= 20; + {Константы цвета, строки и.т.п.} + SelBrkColor = clRed; + BackBrkColor = clBlack; + BackBrkColor2 = clGray; + CW=1; + CH=1; + ScrX=20; + ScrY=20; + + CurColor = clWhite; + + BorderPenColor = clWhite; + BorderPenStyle : TPenStyle = psSolid; + + LocPenColor= clBlue; + LocPenStyle: TPenStyle = psDot; + LocBrushColor= clBlue; + LocBrushStyle: TBrushStyle = bsClear; + + TeleportPenStyle : TPenStyle = psSolid; + TeleportPenColor = clRed; + + TeleportPenStyle2 : TPenStyle = psDashDot; + TeleportPenColor2 = clPurple; + + ObjColors: array [TObjType] of TColor = + (clWhite, clWhite, clWhite, clWhite, clWhite, + clWhite, clWhite, clWhite, clWhite, clWhite); + ObjFontColor = clRed; + + SelObjColor = clAqua; + SelLocColor = clAqua; + + {Начальные зн-я св-в объектов} + DefObj : array [TObjType] of TMapObjV2 = + ((length:0; dir:0; objtype: 1), + (wait:100; target:0; orient:0; special:0;objtype: 2;), + (length:4;wait:100; targetname:0; orient:0; special:0; objtype: 3), + (length:2; dir:2; wait:10; target:0; objtype: 4), + (length:2; dir:2; wait:10; target:0; orient:0; nowanim:10; special:30;objtype: 5), + (length:50; dir:10; targetname:0; orient:2; nowanim:10; special:2; objtype: 6), + (orient:2; special:2; objtype: 7), + (dir:0; wait:0; orient:2; special:2; objtype: 8), + (length:4;wait:5; orient:0; objtype: 9), + (orient:2;special:2;objtype: 10)); + + { otTeleport: Result:='pos x|pos y|goto x|goto y'; + otButton: Result:='pos x|pos y|color|wait|target|shootable'; + otDoor: Result:='pos x|pos y|orientation|length|closed|wait|fastclose|target name'; + otTrigger: Result:='pos x|pos y|length x|length y|wait|target'; + otAreaPush: Result:='pos x|pos y|length x|length y|wait|target|direction|pushspeed'; + otAreaPain: Result:='pos x|pos y|length x|length y|dmginterval|wait|target name|dmg'; + otAreaTrickarena_end: Result:='pos x|pos y|length x|length y'; + otAreaTeleport: Result:='pos x|pos y|length x|length y|goto x|goto y'; + otDoorTrigger: Result:='pos x|pos y|length|orientation|closed|target'; + otAreaWaterIllusion: Result:='pos x|pos y|length x|length y'; +} + + +type + TEditorMode = (emPen, emLine, emBlock, emFloodBlock, emFloodFill, + emSelectBlock, emSelectObj, emSelectLoc, emNewObj, emNewLoc); + +type + TMainForm = class(TForm) + CmPalette: TImageList; + DefPalette: TImageList; + Status: TStatusBar; + TeleportList: TImageList; + ButtonList: TImageList; + BtnImages: TImageList; + RightPnl: TPanel; + BrickPnl: TPanel; + ScrollBrk: TScrollBox; + BrickPnl2: TPanel; + BrickLbl: TLabel; + LogoPnl: TPanel; + Image1: TImage; + ActionManager1: TActionManager; + ActionToolBar1: TActionToolBar; + FileOpen: TFileOpen; + FileSaveAs: TFileSaveAs; + FileNew: TAction; + PenAct: TAction; + SelObjAct: TAction; + SelLocAct: TAction; + FileSave: TAction; + ActionMainMenuBar1: TActionMainMenuBar; + CustomizeDlg: TCustomizeDlg; + CustomizeAct: TAction; + AddObj: TAction; + AddLoc: TAction; + EditAct: TAction; + ActionToolBar2: TActionToolBar; + PropGrid: TStringGrid; + Image: TPaintBox; + PopupMenu1: TPopupMenu; + NewObj: TMenuItem; + ELEPORT1: TMenuItem; + BUTTON1: TMenuItem; + DOOR1: TMenuItem; + RIGGER1: TMenuItem; + AREAPUSH1: TMenuItem; + AREAPAIN1: TMenuItem; + AREATRICKARENAEND1: TMenuItem; + AREATELEPORT1: TMenuItem; + AREADOORTRIGGER1: TMenuItem; + AREAWATERILLUSION1: TMenuItem; + AddAction1: TAction; + AddAction2: TAction; + AddAction3: TAction; + AddAction5: TAction; + AddAction6: TAction; + AddAction7: TAction; + AddAction8: TAction; + AddAction9: TAction; + AddAction10: TAction; + AddAction4: TAction; + NewLoc: TMenuItem; + NewLocAct: TAction; + DelObjAct: TAction; + EditUndo1: TEditUndo; + MapPropsAct: TAction; + MapPaletteAct: TAction; + Splitter1: TSplitter; + BrkImage: TPaintBox; + RunNFKAct: TAction; + + procedure FormCreate(Sender: TObject); + procedure BrkImageMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure ImageMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); + procedure ImageMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure FileOpenAccept(Sender: TObject); + procedure FileSaveAsAccept(Sender: TObject); + procedure FileSaveAsBeforeExecute(Sender: TObject); + procedure FileOpenBeforeExecute(Sender: TObject); + procedure ChangeEditMode(Sender: TObject); + procedure PropGridGetEditMask(Sender: TObject; ACol, ARow: Integer; + var Value: String); + procedure PropGridSetEditText(Sender: TObject; ACol, ARow: Integer; + const Value: String); + procedure PropGridEnter(Sender: TObject); + procedure FileNewExecute(Sender: TObject); + procedure CustomizeActExecute(Sender: TObject); + procedure FileSaveExecute(Sender: TObject); + procedure FormKeyPress(Sender: TObject; var Key: Char); + procedure EditActExecute(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure ImagePaint(Sender: TObject); + procedure AddAction(Sender: TObject); + procedure NewLocActExecute(Sender: TObject); + procedure DelObjActExecute(Sender: TObject); + procedure EditUndo1Execute(Sender: TObject); + procedure MapPropsActExecute(Sender: TObject); + procedure MapPaletteActExecute(Sender: TObject); + procedure BrkImagePaint(Sender: TObject); + procedure ScrollBrkResize(Sender: TObject); + procedure Splitter1Moved(Sender: TObject); + procedure RunNFKActExecute(Sender: TObject); + private + { Private declarations } + {Map and Coordinates} + Map: TMap; + Scroll: TMyScroll; + {буфер} + Buf: TMyBuffer; + {Выделенный тип брика, объект, локация} + SelBrk: integer; + Sel_Obj: TMyObj; + Sel_Loc: TLocation; + {Текущие положения мыши} + i_cur, j_cur, i_sel, j_sel: integer; + {флаги редактирования} + new, modified, Blocked: boolean; + loc_mod: boolean; + {кол-во x бриков и y бриков} + XBrkCount, YBrkCount : integer; + + {режимы редактирования} + Mode: TEditorMode; + + procedure SetScroll; + procedure SetBuf; + + public + { Public declarations } + + procedure SetSize; + + procedure DrawAll; + procedure DrawBrk; + procedure ShowStatusPanel; + procedure ShowCaption; + + procedure CheckProps; + procedure ShowProps; + end; + +CONST MAXBRUSH = 254; // всего brush'ей + MAX_BUF = 2048; // буфер + SHOWLINES : boolean = true; // показывать диагональные линии + SHOWOBJ : boolean = true; // показывать спец объекты + DOSELECT : boolean = false; // селекция + copysizex : byte = 0; // копирование + copysizey : byte = 0; // копирование + +var + MainForm: TMainForm; + +{procedure loadmapp (filename : string); +procedure Location_Modify(ID:byte);} + +implementation +uses + MyStrings, MyPalette, + AddObjDialog, MapPropsForm, MapPaletteForm; +{$R *.DFM} + +//Neoff procedures + +//CREATE!!!! + +procedure TMainForm.SetSize; +begin + PropGrid.ColWidths[0]:=60; + PropGrid.ColWidths[1]:=PropGrid.Width-60; + PropGrid.RowCount:=0; +end; + +procedure TMainForm.FormCreate(Sender: TObject); +begin + Map:=TMap.Create; + Scroll:=TMyScroll.Create; + Buf:=TMyBuffer.Create; + + FileOpen.Dialog.InitialDir := extractfilepath(paramstr(0)); + FileSaveAs.Dialog.InitialDir := extractfilepath(paramstr(0)); + + LoadPaletteFromFile('graph/040bricks.bmp', DefPalette, + clFuchsia, 1, 1); + if paramstr(1) <> '' then if fileexists(paramstr(1)) then begin + FileSaveAs.Dialog.filename := paramstr(1); + Map.Open037Map(paramstr(1)); + end; + SetScroll; + SetBuf; + + selbrk := 1;blocked:=false;modified:=false;new:=true; + Mode:=emSelectObj;loc_mod:=false; + + ScrollBrkResize(Self); + + DrawAll; +end; + +{преобразование координат} + +procedure TMainForm.SetScroll; +begin + with Scroll do + begin + ZoomX:=Brick_Width; + ZoomY:=Brick_Height; + MaxI:=Map.MaxX; + MaxJ:=Map.MaxY; + ScreenWidth:=Image.Width; + ScreenHeight:=Image.Height; + GX:=GX; + GY:=GY; + end; +end; + +//Обнуление буфера + +procedure TMainForm.SetBuf; +begin + Buf.Clear; + Buf.MaxBuf:=MaxBuf; + Buf.AddCopy(Map, 'current map'); +end; + +procedure TMainForm.Splitter1Moved(Sender: TObject); +begin + SetSize; +end; + +{прорисовка и все связанное с ней} + +procedure TMainForm.FormResize(Sender: TObject); +begin + SetScroll; +end; + +procedure TMainForm.ScrollBrkResize(Sender: TObject); +begin + XBrkCount:=(ScrollBrk.Width-22) div (Brick_Width+CW); + YBrkCount:=(254+XBrkCount) div XBrkCount; + DrawBrk; +end; + +procedure TMainForm.DrawAll; +begin + Image.Repaint; + DrawBrk; + CheckProps; + ShowProps; + ShowCaption; +end; + +procedure TMainForm.DrawBrk; +begin + BrkImage.RePaint; +end; + +procedure TMainForm.BrkImagePaint(Sender: TObject); +var + i, j, x, y, img: integer; + +begin + with BrkImage, Canvas do + begin + Width:=(Brick_Width+CW)*XBrkCount; + Height:=(Brick_Height+CH)*YBrkCount; + + Brush.Color:=BackBrkColor; + Pen.Color:=BackBrkColor; + Rectangle(0, 0, Width, Height); + for j:=0 to YBrkCount-1 do + for i:=0 to XBrkCount-1 do + with Map do + begin + x:=i*(Brick_Width+CW); + y:=j*(Brick_Height+CH); + img:=i+j*XBrkCount+1; + if img>255 then Break; + if img=selbrk then + begin + Brush.Color:=SelBrkColor; + Pen.Color:=SelBrkColor; + Rectangle( BrickRect(x, y, CW, CH) ); + end; + Brush.Color:=BackBrkColor2; + Pen.Color:=BackBrkColor2; + Rectangle( BrickRect(x, y, 0, 0) ); + + if CUSTOMPALETTE and (img >=54) and (img<=181) + then CmPalette.Draw(BrkImage.Canvas, x, y, img-54) + else DefPalette.Draw(BrkImage.Canvas, x, y, img); + end; + end; + BrickLbl.Caption:=GetBrushName(SelBrk); +end; + +procedure TMainForm.ImagePaint(Sender: TObject); +var + i, j, x, y, x1, y1: integer; + img: byte; + R: TRect; +begin + + with Image, Canvas, Map, Scroll do + begin + Brush.Color:=clBlack; + Pen.Color:=clBlack; + + // Draw Bricks + for j := GetJ(0) to GetJ(Height) do // отрисовка кирпичей + for i := GetI(0) to GetI(Width) do + begin + x:=GetX(i); + y:=GetY(j); + img:=Brk[i, j]; + if img>0 then + if CustomPalette and (img >=54) and (img <=181) + then CmPalette.Draw(Image.Canvas, x, y, img-54) + else DefPalette.Draw(Image.Canvas, x, y, img); + end; + // Draw Objects + Font.Color:=clRed; + for i:=0 to ObjCount-1 do + begin + R:=Obj[i].Rect; + R.Left:=GetX(R.Left); + R.Right:=GetX(R.Right+1); + R.Top:=GetY(R.Top); + R.Bottom:=GetY(R.Bottom+1); + X:=GetX(Obj[i].X); + Y:=GetY(Obj[i].Y); + + case Obj[i].ObjType of + otTeleport : begin + X1:=GetX(Obj[i].Prop['goto x']); + Y1:=GetY(Obj[i].Prop['goto y']-2); + Y:=Y-2*Brick_Height; + TeleportList.Draw(Canvas, R.Left, R.Top, 0); +{ TeleportList.Draw(Canvas, x1, y1, 0);} + Pen.Style:=TeleportPenStyle2; + Pen.Color:=TeleportPenColor2; + Brush.Style:=bsClear; + Rectangle(X1, Y1, X1+Brick_Width, Y1+3*Brick_Height); + Pen.Style:=TeleportPenStyle; + Pen.Color:=TeleportPenColor; + MoveTo(X+Brick_Width div 2, Y+Brick_Height); + LineTo(X1+Brick_Width div 2, Y1+Brick_Height); + end; + otButton : begin + ButtonList.Draw(Canvas, R.Left+4, R.Top+4, Obj[i].Prop['shootable']); + end; + otDoor, + otTrigger, + otAreaPush, + otAreaPain, + otAreaTrickarena_end, + otAreaTeleport, + otDoorTrigger, + otAreaWaterIllusion: + begin +{ Brush.Style:=bsClear;} + Brush.Style:=bsBDiagonal; + + Brush.Color:=ObjColors[Obj[i].ObjType]; + Pen.Style:=psSolid; + Pen.Color:=ObjColors[Obj[i].ObjType]; + Font.Color:=ObjFontColor; + Rectangle(R); + TextOut(X, Y, Obj[i].Name); + end; + end; +{ TextOut(X, Y, IntToStr(Ord(Obj[i].ObjType)));} + if (Mode=emSelectObj) and (sel_obj=Obj[i]) then + begin + Brush.Style:=bsClear; + Pen.Style:=psSolid; + Pen.Color:=SelObjColor; + Rectangle(R); + end; + end; + //Draw Locations + for i:=0 to LocCount-1 do + begin + x:=GetX(Locations[i].X); + y:=GetY(Locations[i].Y); + Pen.Color:=LocPenColor; + Pen.Style:=LocPenStyle; + Brush.Color:=LocBrushColor; + Brush.Style:=LocBrushStyle; + Ellipse(x, y, x+Brick_Width, y+Brick_Height); + + if (Mode=emSelectLoc) and (sel_loc=Locations[i]) then + begin + Brush.Style:=bsClear; + Pen.Style:=psSolid; + Pen.Color:=SelLocColor; + Rectangle(x, y, x+Brick_Width, y+Brick_Height); + end; + end; + // Главные Диагонали:) + Brush.Style:=bsClear; + Pen.Color:=BorderPenColor; + Pen.Style:=BorderPenStyle; + Rectangle(-GX, -GY, GetMaxX-GX+1, GetMaxY-GY+1); + MoveTo(-GX, -GY);LineTo(GetMaxX-GX+1, GetMaxY-GY+1); + MoveTo(-GX, GetMaxY-GY+1);LineTo(GetMaxX-GX+1, -GY); + // Наш курсор +// Brush.Style:=bsClear; +// Pen.Color:=CurColor; +// Rectangle(GetX(i_cur), GetY(j_cur), GetX(i_cur+1), GetY(j_cur+1)); + end; +end; + +//Заполнение StatusBar и.т.п. + +procedure TMainForm.ShowStatusPanel; +begin + Status.Panels[0].Text:=IntToStr(i_sel)+' '+IntToStr(j_sel); + Status.Panels[1].Text:=IntToStr(i_cur)+' '+IntToStr(j_cur); +end; + +procedure TMainForm.ShowCaption; +begin + if new then + Caption:='NFK Radiant Pro by Neoff - NEW' + else + Caption:='NFK Radiant Pro by Neoff - '+FileSaveAs.Dialog.FileName; +end; + +//Обработка мышиных событий:) на Image + +procedure TMainForm.BrkImageMouseDown(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +var + img : integer; +begin + img:=X div (Brick_Width+CW)+(Y div (Brick_Height+CH))*XBrkCount+1; + if img<=255 then + begin + PenAct.Execute; + selbrk:=img; + end; + DrawBrk; +end; + +procedure TMainForm.ImageMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +var + i: integer; +begin +{} + Loc_Mod:=false; + with Scroll do + if Clip(X, Y) then + with Map do + begin + case Mode of + emPen:if (ssLeft in Shift) then + begin + if ssShift in Shift then + Map[i_cur, j_cur]:=EmptyBrick.image + else + Map[i_cur, j_cur]:=SelBrk; + Loc_Mod:=true; + end; + emSelectObj: + begin +{ if ssShift in Shift then + begin + Sel_Obj:=Map.AddObj; + end;} + for i:=0 to ObjCount-1 do + with Obj[i].Rect do + if (Obj[i]<>Sel_Obj) and + (i_cur>=Left) and (i_cur<=Right) and + (j_cur>=Top) and (j_cur<=Bottom) then + Sel_Obj:=Obj[i]; + ShowProps; + end; + emSelectLoc: + begin + for i:=0 to LocCount-1 do + if (Locations[i]<>Sel_Loc) and + (i_cur=Locations[i].X) and (j_cur=Locations[i].Y) + then Sel_Loc:=Locations[i]; + ShowProps; + end; + emNewObj:begin + SelObjAct.Execute; + if AddObjDlg.ShowModal=mrOk then + begin + sel_obj:=AddObj; + sel_obj.Values:=DefObj[TObjType(AddObjDlg.Tag)]; + sel_obj.X:=i_cur; + sel_obj.Y:=j_cur; + end; + Buf.AddCopy(Map, 'Add Object'); + ShowProps; + end; + emNewLoc:begin + SelLocAct.Execute; + sel_loc:=AddLoc; + sel_loc.X:=i_cur; + sel_loc.Y:=j_cur; + sel_loc.Text:='Location'; + Buf.AddCopy(Map, 'Add Location'); + ShowProps; + end; + end; + Image.Repaint; + end; + {if ssLeft in Shift then + if Clip(X, Y) then + begin + Map.Brk[i_cur, j_cur]:=SelBrk; + DrawImage; + end;} +end; + +procedure TMainForm.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); +var + MustDrawImage: boolean; +{ i, j: integer;} +begin +{} +{ i:=Scroll.GetI(X); + j:=Scroll.GetJ(Y); + if (i<>i_cur) or (j<>j_cur) then + begin + i_cur:=i; + j_cur:=j; +// Прорисовка курсора + Image. + end;} + i_cur:=Scroll.GetI(X); + j_cur:=Scroll.GetJ(Y); + + ShowStatusPanel; + with Scroll do + if Clip(x, y) then + with Map do + begin + MustDrawImage:=true; + case Mode of + emPen:if (ssLeft in Shift) then + begin + if ssShift in Shift then + begin + Map[i_cur, j_cur]:=EmptyBrick.Image; + loc_mod:=true; + end + else + begin + if Map[i_cur, j_cur]<>SelBrk then + begin + Map[i_cur, j_cur]:=SelBrk; + loc_mod:=true; + end + else MustDrawImage:=false; + + end; + end else MustDrawImage:=false; + else MustDrawImage:=false; + end; + if MustDrawImage then Image.Repaint; + end; +end; + + +procedure TMainForm.ImageMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + if Loc_Mod then + Buf.AddCopy(Map, 'Brick Paint'); +end; + +// КЛАВА!!!!! + +procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char); +var + rp: boolean; +begin + rp:=true; + with Scroll do + if not EditAct.Checked then + case UpCase(Key) of + 'W':GY:=GY-ScrY; + 'S':GY:=GY+ScrY; + 'A':GX:=GX-ScrX; + 'D':GX:=GX+ScrX; + else rp:=false; + end; + if rp then + Image.Repaint; +end; + +//обработка show/edit свойств объекта. + +procedure TMainForm.CheckProps; +begin + PropGrid.Options:=PropGrid.Options-[goEditing]; + if EditAct.checked then + if (mode=emSelectObj) and (Sel_Obj<>nil) or + (mode=emSelectLoc) and (Sel_Loc<>nil) then + PropGrid.Options:=PropGrid.Options+[goEditing]; +end; + + +procedure TMainForm.ShowProps; +var + i, k: integer; + s, s1: string; +begin + EditAct.Enabled:=false; + PropGrid.Visible:=true; + with PropGrid do + case Mode of + emSelectObj: + if sel_obj<>nil then + begin + EditAct.Enabled:=true; + s:=sel_obj.Props; + i:=0; + while s<>'' do + begin + Inc(i); + k:=Pos('|', s); + if k<=0 then + begin + s1:=s; + s:=''; + end + else + begin + s1:=Copy(s, 1, k-1); + Delete(s, 1, k); + end; + Cells[0, i-1]:=S1; + Cells[1, i-1]:=IntToStr(sel_obj.Prop[S1]); + end; + RowCount:=i; + end; + + emSelectLoc: + if sel_loc<>nil then + begin + EditAct.Enabled:=true; + RowCount:=3; + Cells[0, 0]:='pos x'; + Cells[1, 0]:=IntToStr(sel_loc.X); + Cells[0, 1]:='pos y'; + Cells[1, 1]:=IntToStr(sel_loc.Y); + Cells[0, 2]:='text'; + Cells[1, 2]:=sel_loc.Text; + end; + else begin + PropGrid.Visible:=false; + RowCount:=1; + Cells[0, 0]:=''; + Cells[1, 0]:=''; + end; + end; + DelObjAct.Enabled:=EditAct.Enabled; +end; + +procedure TMainForm.PropGridGetEditMask(Sender: TObject; ACol, + ARow: Integer; var Value: String); +begin + with PropGrid do + case Mode of + emSelectObj: + begin + if Sel_Obj=nil then Exit; + Value:=Sel_Obj.Mask[Cells[0, ARow]]; + end; + emSelectLoc: + begin + if Sel_Loc=nil then Exit; + if Cells[0, ARow]='text' then Value:='' + else Value:='000;1;'; + end; + end; +end; + +procedure TMainForm.PropGridSetEditText(Sender: TObject; ACol, + ARow: Integer; const Value: String); +begin + {привет, кодер!!!} + with PropGrid do + begin + if (Trim(Value)<>'') and + ((Cells[0, ARow]='pos x') and (StrToInt(Trim(Value))>=Map.MaxX) or + (Cells[0, ARow]='pos y') and (StrToInt(Trim(Value))>=Map.MaxY)) + then Exit; + + case Mode of + emSelectObj: + if (Sel_Obj<>nil) and (Trim(Value)<>'') then + begin + sel_obj.Prop[Cells[0, ARow]]:=StrToInt(Trim(Value)); + Image.Repaint; + end; + emSelectLoc: + if (Sel_Loc<>nil) and ((Trim(Value)<>'') or (Cells[0, ARow]='text')) + then + begin + if Sel_Loc=nil then Exit; + if Cells[0, ARow]='text' then sel_loc.Text:=Value; + if Cells[0, ARow]='pos x' then sel_loc.X:=StrToInt(Trim(Value)); + if Cells[0, ARow]='pos y' then sel_loc.Y:=StrToInt(Trim(Value)); + Image.Repaint; + end; + end; + end; +end; + +procedure TMainForm.PropGridEnter(Sender: TObject); +begin + ShowProps; +end; + +//А здеся уже Action'ы пошли + +procedure TMainForm.FileNewExecute(Sender: TObject); +begin + Map.Clear; + SetBuf; + SetScroll; + new:=true; + Sel_Obj:=nil; + Sel_Loc:=nil; + DrawAll; +end; + +procedure TMainForm.FileOpenBeforeExecute(Sender: TObject); +begin +{ченить да напишем:)} + Mode:=emSelectObj; + SelObjAct.Checked:=true; +end; + +procedure TMainForm.FileOpenAccept(Sender: TObject); +begin + with Map do + case Open037map(FileOpen.Dialog.FileName) of + 0: + begin + if CustomPalette then + LoadPaletteFromBitmap(Palette, CmPalette, + CustomPaletteTransparentColor, 0, 0); + SetScroll; + DrawAll; + FileSaveAs.Dialog.InitialDir:=ExtractFilePath(FileOpen.Dialog.FileName); + FileSaveAs.Dialog.FileName:=FileOpen.Dialog.FileName; + end; + -1:ShowMessage('error'); + -2:ShowMessage('error'); + end; + + Sel_Obj:=nil; + Sel_Loc:=nil; + new:=false; + SetBuf; + SetScroll; + DrawAll; +end; + +procedure TMainForm.FileSaveExecute(Sender: TObject); +begin + if new or (FileSaveAs.dialog.Filename='') then + FileSaveAs.Execute + else FileSaveAsAccept(FileSave); +end; + +procedure TMainForm.FileSaveAsBeforeExecute(Sender: TObject); +begin + if new then + FileSaveAs.Dialog.FileName:='new.mapa'; +end; + +procedure TMainForm.FileSaveAsAccept(Sender: TObject); +begin + Map.SaveMap(FileSaveAs.Dialog.FileName); + FileOpen.Dialog.InitialDir:=ExtractFilePath(FileSaveAs.Dialog.FileName); + FileOpen.Dialog.FileName:=FileSaveAs.Dialog.FileName; + ShowCaption; + new:=false; +end; + +procedure TMainForm.CustomizeActExecute(Sender: TObject); +begin + CustomizeDlg.Show; +end; + +procedure TMainForm.EditActExecute(Sender: TObject); +begin + if not EditAct.Checked then + Buf.AddCopy(Map, 'Edit object'); + CheckProps; + ShowProps; +end; + +procedure TMainForm.AddAction(Sender: TObject); +var + obj_: TMyObj; +begin + obj_:=Map.AddObj; + obj_.Values:=DefObj[TObjType(TAction(Sender).Tag)]; + obj_.X:=i_cur; + obj_.Y:=j_cur; + sel_obj:=obj_; + SelObjAct.Execute; + Buf.AddCopy(Map, 'Add Object'); + Image.Repaint; +end; + +procedure TMainForm.NewLocActExecute(Sender: TObject); +begin + sel_loc:=Map.AddLoc; + sel_loc.X:=i_cur; + sel_loc.Y:=j_cur; + sel_loc.Text:='Location'; + SelLocAct.Execute; + Buf.AddCopy(Map, 'Add Location'); +end; + +procedure TMainForm.DelObjActExecute(Sender: TObject); +begin + if (Mode=emSelectObj) and (sel_obj<>nil) then + begin + Buf.AddCopy(Map, 'Delete object '+sel_obj.Name); + Map.DeleteObj(sel_obj); + sel_obj:=nil; + Image.Repaint; + ShowProps; + end; + if (Mode=emSelectLoc) and (sel_loc<>nil) then + begin + Buf.AddCopy(Map, 'Delete location '); + Map.DeleteLoc(sel_loc); + sel_loc:=nil; + Image.Repaint; + ShowProps; + end; +end; + +procedure TMainForm.EditUndo1Execute(Sender: TObject); +begin + if Buf.CurCopyIndex>1 then + Buf.SetCurCopy(Buf.CurCopyIndex-1).Assign(Map); + Image.Repaint; + sel_obj:=nil; + sel_loc:=nil; +end; + +procedure TMainForm.MapPropsActExecute(Sender: TObject); +begin + with MapPropsDlg do + begin + AuthorEd.Text:=Map.MapAuthor; + NameEd.Text:=Map.MapName; + BGEd.Text:=IntToStr(Map.BackGround); + MaxXEd.Text:=IntToStr(Map.MaxX); + MaxYEd.Text:=IntToStr(Map.MaxY); + if ShowModal=mrOk then + begin + Map.MapAuthor:=AuthorEd.Text; + Map.MapName:=NameEd.Text; + Map.BackGround:=StrToInt(Trim(BGEd.Text)); + Map.MaxX:=StrToInt(Trim(MaxXEd.Text)); + Map.MaxY:=StrToInt(Trim(MaxYEd.Text)); + SetScroll; + end; + end; +end; + + +procedure TMainForm.MapPaletteActExecute(Sender: TObject); +begin + MapPaletteDlg.Map:=Map; + MapPaletteDlg.ShowModal; + with MapPaletteDlg do + if PalFile<>'' then + begin + Map.CustomPalette:=true; + Map.Palette.LoadFromFile(PalFile); + LoadPaletteFromBitmap(Map.Palette, CmPalette, ColorDlg.Color, 0, 0); + DrawBrk; + end; +end; + +procedure TMainForm.RunNFKActExecute(Sender: TObject); +begin + if not new then + ShellExecute(Handle, 'open', 'd:\games\nfk\nfk.exe', + pchar('map '+ExtractFileName(FileSaveAs.Dialog.FileName)), '', SW_HIDE); +end; + +//УУУУ а вот это уже выбор режима редактирования + +procedure TMainForm.ChangeEditMode(Sender: TObject); +begin + Mode:=TEditorMode(TAction(Sender).Tag); + ShowProps; +end; + +end. + diff --git a/EDITOR/RadiantPro/MapPaletteForm.pas b/EDITOR/RadiantPro/MapPaletteForm.pas new file mode 100644 index 0000000..9aecd51 --- /dev/null +++ b/EDITOR/RadiantPro/MapPaletteForm.pas @@ -0,0 +1,127 @@ +unit MapPaletteForm; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, Buttons, ExtCtrls, + MyClasses, ImgList, ExtDlgs; + +type + TMapPaletteDlg = class(TForm) + Panel1: TPanel; + BitBtn1: TBitBtn; + BitBtn2: TBitBtn; + PaletteBox: TScrollBox; + Panel2: TPanel; + Image: TPaintBox; + MyPalette: TImageList; + Button1: TButton; + OpenDlg: TOpenPictureDialog; + ColorDlg: TColorDialog; + Label1: TLabel; + ColorPnl: TPanel; + procedure ImagePaint(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure ColorPnlClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure ImageMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + private + { Private declarations } + public + { Public declarations } + Map: TMap; + PalFile: string; + YBrkCount: integer; + end; + +var + MapPaletteDlg: TMapPaletteDlg; + +implementation + +uses MyPalette; + +{$R *.dfm} + +const + XBrkCount = 5; + CW=0;CH=0; + + BackBrkColor = clGray; + +procedure TMapPaletteDlg.ImagePaint(Sender: TObject); +var + i, j, x, y, img: integer; + +begin + with Image, Canvas do + begin + Width:=(Brick_Width+CW)*XBrkCount; + Height:=(Brick_Height+CH)*YBrkCount; + + Brush.Color:=BackBrkColor; + Pen.Color:=BackBrkColor; + Rectangle(0, 0, Width, Height); + for j:=0 to YBrkCount-1 do + for i:=0 to XBrkCount-1 do + with Map do + begin + x:=i*(Brick_Width+CW); + y:=j*(Brick_Height+CH); + img:=i+j*XBrkCount+1; + if img>=MyPalette.Count then Exit; + MyPalette.Draw(Canvas, x, y, img); + end; + end; +end; + +procedure TMapPaletteDlg.Button1Click(Sender: TObject); +begin + with OpenDlg do + if Execute then + try + LoadPaletteFromFile(FileName, MyPalette, ColorDlg.Color, 0, 0); + YBrkCount:=(MyPalette.Count+XBrkCount-1) div XBrkCount; + ImagePaint(Self); + PalFile:=FileName; + except + ShowMessage('I can''t load this bitmap!!!'); + PalFile:=''; + end; +end; + +procedure TMapPaletteDlg.ColorPnlClick(Sender: TObject); +begin + ColorDlg.Execute; + ColorPnl.Color:=ColorDlg.Color; + if PalFile<>'' then + begin + LoadPaletteFromFile(palFile, MyPalette, ColorDlg.Color, 0, 0); + ImagePaint(Self); + end; +end; + +procedure TMapPaletteDlg.ImageMouseDown(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + ColorDlg.Color:=Image.Canvas.Pixels[X, Y]; + ColorPnl.Color:=ColorDlg.Color; + if PalFile<>'' then + begin + LoadPaletteFromFile(palFile, MyPalette, ColorDlg.Color, 0, 0); + ImagePaint(Self); + end; +end; + +procedure TMapPaletteDlg.FormShow(Sender: TObject); +begin + if Map.CustomPalette then + LoadPaletteFromBitmap(Map.Palette, MyPalette, ColorDlg.Color, 0, 0) + else MyPalette.Clear; + YBrkCount:=(MyPalette.Count+XBrkCount-1) div XBrkCount; + ImagePaint(Self); +end; + +end. diff --git a/EDITOR/RadiantPro/MapPropsForm.pas b/EDITOR/RadiantPro/MapPropsForm.pas new file mode 100644 index 0000000..c3f57c6 --- /dev/null +++ b/EDITOR/RadiantPro/MapPropsForm.pas @@ -0,0 +1,37 @@ +unit MapPropsForm; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, Buttons, ExtCtrls, Mask; + +type + TMapPropsDlg = class(TForm) + Panel1: TPanel; + BitBtn1: TBitBtn; + BitBtn2: TBitBtn; + Label1: TLabel; + AuthorEd: TEdit; + NameEd: TEdit; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Label5: TLabel; + BGEd: TEdit; + MaxXEd: TEdit; + MaxYEd: TEdit; + private + { Private declarations } + public + { Public declarations } + end; + +var + MapPropsDlg: TMapPropsDlg; + +implementation + +{$R *.dfm} + +end. diff --git a/EDITOR/RadiantPro/Map_ed.dpr b/EDITOR/RadiantPro/Map_ed.dpr new file mode 100644 index 0000000..d25874c --- /dev/null +++ b/EDITOR/RadiantPro/Map_ed.dpr @@ -0,0 +1,28 @@ +program Map_ed; + +uses + Forms, + bzLib in 'bz\bzLib.pas', + PowerAcrModuleInfo in 'bz\PowerAcrModuleInfo.pas', + PowerArc in 'bz\PowerArc.pas', + MyStrings in 'MyStrings.pas', + MyPalette in 'MyPalette.pas', + Main in 'Main.pas' {MainForm}, + MyClasses in 'MyClasses.pas', + MyScroll in 'MyScroll.pas', + AddObjDialog in 'AddObjDialog.pas' {AddObjDlg}, + MyBuf in 'MyBuf.pas', + MapPropsForm in 'MapPropsForm.pas' {MapPropsDlg}, + MapPaletteForm in 'MapPaletteForm.pas' {MapPaletteDlg}; + +{$R *.RES} + +begin + Application.Initialize; + Application.Title := 'NFK Radiant'; + Application.CreateForm(TMainForm, MainForm); + Application.CreateForm(TAddObjDlg, AddObjDlg); + Application.CreateForm(TMapPropsDlg, MapPropsDlg); + Application.CreateForm(TMapPaletteDlg, MapPaletteDlg); + Application.Run; +end. diff --git a/EDITOR/RadiantPro/MyBuf.pas b/EDITOR/RadiantPro/MyBuf.pas new file mode 100644 index 0000000..2cf9803 --- /dev/null +++ b/EDITOR/RadiantPro/MyBuf.pas @@ -0,0 +1,123 @@ +unit MyBuf; + +interface + +uses Classes, Types, MyClasses; + +type + TMyBuffer = class + constructor Create; + destructor Destroy;override; + private + FCopies: TList; + FCopiesCount: integer; + FCurCopyIndex: integer; + FMaxBuf: integer; + function GetCopies(i: integer): TMap; + procedure SetCurCopyIndex(const Value: integer); + function GetCopiesCount: integer; + procedure SetCopiesCount(const Value: integer); + procedure SetMaxBuf(const Value: integer); + function GetCurCopy: TMap; + public + property Copies[i: integer]: TMap read GetCopies; + property CopiesCount: integer read GetCopiesCount; + property CurCopyIndex: integer read FCurCopyIndex write SetCurCopyIndex; + property CurCopy: TMap read GetCurCopy; + property MaxBuf: integer read FMaxBuf write SetMaxBuf; + function SetCurCopy(i: integer): TMap; + function AddCopy(Map: TMap; tagname: string): TMap; + + procedure Clear; + end; + +implementation + +{ TMyBuffer } + +function TMyBuffer.AddCopy(Map: TMap; tagName: string): TMap; +var + m: TMap; +begin + if CurCopyIndexMaxBuf then + begin + FCopies.Delete(0); + Dec(FCurCopyIndex); + end; +end; + +procedure TMyBuffer.Clear; +begin + FCurCopyIndex:=-1; + while FCopies.count>0 do + begin + Copies[0].Free; + FCopies.Delete(0); + end; +end; + +constructor TMyBuffer.Create; +begin + FCopies:=TList.Create; + FCurCopyIndex:=-1; +end; + +destructor TMyBuffer.Destroy; +begin + Clear; + FCopies.Free; + inherited; +end; + +function TMyBuffer.GetCopies(i: integer): TMap; +begin + Result:=TMap(FCopies[i]); +end; + +function TMyBuffer.GetCopiesCount: integer; +begin + Result:=FCopies.Count; +end; + +function TMyBuffer.GetCurCopy: TMap; +begin + Result:=Copies[FCurCopyIndex]; +end; + +procedure TMyBuffer.SetCopiesCount(const Value: integer); +begin + FCopiesCount := Value; +end; + +function TMyBuffer.SetCurCopy(i: integer): TMap; +begin + FCurCopyIndex:=i; + Result:=CurCopy; +end; + +procedure TMyBuffer.SetCurCopyIndex(const Value: integer); +begin + FCurCopyIndex := Value; +end; + +procedure TMyBuffer.SetMaxBuf(const Value: integer); +begin + FMaxBuf := Value; +end; + +end. diff --git a/EDITOR/RadiantPro/MyClasses.pas b/EDITOR/RadiantPro/MyClasses.pas new file mode 100644 index 0000000..820c77b --- /dev/null +++ b/EDITOR/RadiantPro/MyClasses.pas @@ -0,0 +1,883 @@ +unit MyClasses; + +interface + +uses Classes, Types, Graphics, BzLib; + +type TMapEntry = packed record + EntryType : string[3]; + DataSize : longint; + Reserved1 : byte; + Reserved2 : word; + Reserved3 : integer; + Reserved4 : longint; + Reserved5 : cardinal; + Reserved6 : boolean; + end; + +{type TWaypoint = packed record + x,y:byte; + number:byte; + zone:byte; + items:longword; + flags:word; + end; + + +type TMAPOBJ = record // специальный объект + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,objtype,orient,nowanim,special : byte; + end;} + +type TBrick = record + image : byte; // вот нафиг этот тип нужен??? + end; + +type TMAPOBJV2 = record // специальный объект + active : boolean; + x,y,length,dir,wait : word; + targetname,target,orient,nowanim,special:word; + objtype : byte; + end; + +//******************************************* +//А теперь... класс TMAP!!!!!!! +//******************************************* + +type + TBrickArray = array [0..254, 0..254] of TBrick; + String64 = string[64]; + String70 = string[70]; + Array4 = array [1..4] of char; + +type THeader = record // header карты + ID : Array4; + Version : byte; + MapName : string70; + Author : string70; + MapSizeX,MapSizeY,BG,GAMETYPE,numobj : byte; + numlights : word; + end; + + {1 - телерорт 2- переключатель 3- дверь 4- trigger + 5-area_push 6- area_pain 7- area_trickarena_end 8- area_teleport + 9- door_trigger 10-area_waterillusion} + + TObjType = (otTeleport=1, otButton=2, otDoor=3, otTrigger=4, + otAreaPush=5, otAreaPain=6, otAreaTrickarena_end=7, + otAreaTeleport=8, otDoorTrigger=9, otAreaWaterIllusion=10); + +const + EmptyBrick : TBrick = (image: 0); + DefHeader : THeader = (ID: ('N', 'M', 'A', 'P'); version: 3; + MapName: 'test map'; Author: 'unnamed'; + MapSizeX:20; MapSizeY:30;BG : 0;GAMETYPE: 0); + +type + TLocationText = Packed Record + Enabled : boolean; + X, Y : byte; + Text : String64; + end; + +type + TMyObj = class + private + Fx,Fy,Flength,Fdir,Fwait : word; + Ftargetname,Ftarget,Forient,Fnowanim,Fspecial:word; + Fobjtype : TObjType; + procedure SetValues(Obj : TMapOBJV2); + function GetValues: TMapObjV2; + procedure SetX(const Value: word); + procedure SetY(const Value: word); + function GetProps: string; + function GetProp(name: string): integer; + procedure SetProp(name: string; const Value: integer); + function GetName: string; + procedure SetObjType(const Value: TObjType); + function GetRect: TRect; + function GetMask(name: string): string; + function GetPropsCount: integer; + public + property Values: TMapObjV2 read GetValues write SetValues; + property X: word read FX write SetX; + property Y: word read FY write SetY; + property ObjType: TObjType read FObjType write SetObjType; + property Props : string read GetProps; + property Prop[name: string]: integer read GetProp write SetProp; + property Mask[name: string]: string read GetMask; + property PropsCount: integer read GetPropsCount; + property Name: string read GetName; + property Rect: TRect read GetRect; + end; +type + TLocation = class + private + FX, FY: byte; + FText: String64; + procedure SetValues(Loc : TLocationText); + function GetValues: TLocationText; + procedure SetX(const Value: byte); + procedure SetY(const Value: byte); + procedure SetText(const Value: String64); + public + property Values: TLocationText read GetValues write SetValues; + property X: byte read FX write SetX; + property Y: byte read FY write SetY; + property Text: String64 read FText write SetText; + end; + + TMap = class + constructor Create; + destructor Destroy;override; + private + {Брики, объекты, локации} + FMaxY: byte; + FMaxX: byte; + FBrk : TBrickArray; + FObj : TList; + FLocations : TList; + {Паллитра} + FCustomPaletteTransparent: boolean; + FCustomPalette: boolean; + FPalette: TBitmap; + FCustomPaletteTransparentColor: TColor; + {HEADER} + + {Автор и карта:)} + FMapAuthor: String70; + FMapName: String70; + {Фон} + FBackGround: byte; + {Фигня всякая} + FID: Array4; + FGameType: byte; + FVersion: byte; + FNumLights: integer; + +//TagName + FTagName: string; + + function GetBrick(i, j: integer): TBrick; + procedure SetBrick(i, j: integer; const Value: TBrick); + procedure SetMaxX(const Value: byte); + procedure SetMaxY(const Value: byte); + function GetObj(i: integer): TMyObj; + function GetObjCount: integer; + procedure SetCustomPaletteTransparent(const Value: boolean); + procedure SetCustomPaletteTransparentColor(const Value: TColor); + procedure SetPalette(const Value: TBitmap); + procedure SetCustomPalette(const Value: boolean); + procedure SetMapAuthor(const Value: String70); + procedure SetMapName(const Value: String70); + procedure SetBackGround(const Value: byte); + procedure SetGameType(const Value: byte); + procedure SetID(const Value: Array4); + procedure SetNumLights(const Value: integer); + procedure SetVersion(const Value: byte); + function GetHeader: THeader; + procedure SetHeader(const Value: THeader); + function GetLoc(i: integer): TLocation; + function GetLocCount: integer; + function GetBrk(i, j: integer): byte; + procedure SetBrk(i, j: integer; const Value: byte); + procedure SetTagName(const Value: string); + public + property Brick[i, j: integer]: TBrick read GetBrick write SetBrick; + property Brk[i, j: integer]: byte read GetBrk write SetBrk;default; + property MaxX: byte read FMaxX write SetMaxX; + property MaxY: byte read FMaxY write SetMaxY; + property Obj[i: integer]: TMyObj read GetObj; + property ObjCount: integer read GetObjCount; + property Locations[i: integer]: TLocation read GetLoc; + property LocCount: integer read GetLocCount; + + function AddObj: TMyObj; + procedure DeleteObj(i: integer);overload; + procedure DeleteObj(obj_: TMyObj);overload; + function AddLoc: TLocation; + procedure DeleteLoc(i: integer);overload; + procedure DeleteLoc(loc_: TLocation);overload; + + property Palette : TBitmap read FPalette write SetPalette; + property CustomPalette: boolean read FCustomPalette write SetCustomPalette; + property CustomPaletteTransparent: boolean read FCustomPaletteTransparent write SetCustomPaletteTransparent; + property CustomPaletteTransparentColor: TColor read FCustomPaletteTransparentColor write SetCustomPaletteTransparentColor; + {MapNAme, MapAuthor} + property ID: Array4 read FID write SetID; + property NumLights: integer read FNumLights write SetNumLights; + property MapName: String70 read FMapName write SetMapName; + property MapAuthor: String70 read FMapAuthor write SetMapAuthor; + property Version: byte read FVersion write SetVersion; + property GameType: byte read FGameType write SetGameType; + property BackGround: byte read FBackGround write SetBackGround; + + property Header : THeader read GetHeader write SetHeader; + {Открытие карты:) } + procedure Clear; + function Open037Map(FileName: string): integer; + procedure SaveMap(FileName: string); + {Копирование в другое место:)} + procedure Assign(Source: TMap); + procedure CopyRect(x1, y1, x2, y2: integer; var Map: TMap; copyObj, copyLoc: boolean); + {Св-во для Undo Redo} + property TagName: string read FTagName write SetTagName; + end; + +implementation + +{ TMyObj } + +function TMyObj.GetMask(name: string): string; +begin + if (name='shootable') or + (name='orientation') or + (name='closed') or + (name='fastclose') or + (name='direction') then Result:='0;1; ' + else + if (name='wait') then Result:='00000;1; ' + else Result:='000;1; '; +end; + +function TMyObj.GetName: string; +begin + case FObjType of + otTeleport: Result:='TELEPORT'; + otButton: Result:='BUTTON'; + otDoor: Result:='DOOR'; + otTrigger: Result:='TRIGGER'; + otAreaPush: Result:='AREA PUSH'; + otAreaPain: Result:='AREA PAIN'; + otAreaTrickarena_end: Result:='TRICKARENA END'; + otAreaTeleport: Result:='AREA TELEPORT'; + otDoorTrigger: Result:='AREA TRIGGER'; + otAreaWaterIllusion: Result:='AREA WATERILLUSION'; + end; +end; + +function TMyObj.GetProp(name: string): integer; +begin + if name='pos x' then Result:=FX; + if name='pos y' then Result:=FY; + if name='goto x' then Result:=FLength; + if name='goto y' then Result:=Fdir; + if name='color' then Result:=Forient; + if name='wait' then Result:=FWait; + if name='target' then Result:=FTarget; + if name='shootable' then Result:=FSpecial; + if name='length x' then + if Ord(ObjType)<=5 then Result:=FLength + else Result:=FSpecial; + if name='length y' then + if Ord(ObjType)<=5 then Result:=FDir + else Result:=FOrient; + if name='orientation' then Result:=FOrient and 1; + if name='closed' then Result:=1-((FOrient and 2) div 2); + if name='fastclose' then Result:=FSpecial; + if name='length' then Result:=FLength; + if name='target name' then Result:=FTargetName; + if name='direction' then Result:=FOrient; + if name='pushspeed' then Result:=FSpecial; + if name='dmginterval' then Result:=FNowanim; + if name='dmg' then Result:=FDir; +end; + +function TMyObj.GetProps : string; +begin + case FObjType of + otTeleport: Result:='pos x|pos y|goto x|goto y'; + otButton: Result:='pos x|pos y|color|wait|target|shootable'; + otDoor: Result:='pos x|pos y|orientation|length|closed|wait|fastclose|target name'; + otTrigger: Result:='pos x|pos y|length x|length y|wait|target'; + otAreaPush: Result:='pos x|pos y|length x|length y|wait|target|direction|pushspeed'; + otAreaPain: Result:='pos x|pos y|length x|length y|dmginterval|wait|target name|dmg'; + otAreaTrickarena_end: Result:='pos x|pos y|length x|length y'; + otAreaTeleport: Result:='pos x|pos y|length x|length y|goto x|goto y'; + otDoorTrigger: Result:='pos x|pos y|length|orientation|closed|target'; + otAreaWaterIllusion: Result:='pos x|pos y|length x|length y'; + end; +end; + +function TMyObj.GetPropsCount: integer; +begin + case FObjType of + otTeleport: Result:=4; + otButton: Result:=6; + otDoor: Result:=8; + otTrigger: Result:=6; + otAreaPush: Result:=8; + otAreaPain: Result:=8; + otAreaTrickarena_end: Result:=4; + otAreaTeleport: Result:=6; + otDoorTrigger: Result:=6; + otAreaWaterIllusion: Result:=4; + end; +end; + +function TMyObj.GetRect: TRect; +begin + case FObjType of + otTeleport: + begin + Result.Left:=X-1; + Result.Right:=X+1; + Result.Top:=Y-2; + Result.Bottom:=Y; + end; + otButton: + begin + Result.Left:=X; + Result.Right:=X; + Result.Top:=Y-1; + Result.Bottom:=Y; + end; + otTrigger, + otAreaPush: + begin + Result.Left:=X; + Result.Right:=X+FLength-1; + Result.Top:=Y; + Result.Bottom:=Y+FDir-1; + end; + + otAreaPain, + otAreaTrickarena_end, + otAreaTeleport, + otAreaWaterIllusion: + begin + Result.Left:=X; + Result.Right:=X+FSpecial-1; + Result.Top:=Y; + Result.Bottom:=Y+FOrient-1; + end; + + otDoor, + otDoorTrigger: + begin + Result.Left:=X; + Result.Right:=X+(1-FOrient and 1)*(FLength-1); + Result.Top:=Y; + Result.Bottom:=Y+(FOrient and 1)*(FLength-1); + end; + end; +end; + +function TMyObj.GetValues: TMapObjV2; +begin + Result.active:=true; + Result.x:=Fx;Result.y:=Fy; + Result.length:=FLength; + Result.Dir:=FDir; + Result.Wait:=Fwait; + Result.TargetName:=Ftargetname; + Result.target:=Ftarget; + Result.orient:=Forient; + Result.nowanim:=Fnowanim; + Result.Special:=Fspecial; + Result.objtype:=Ord(Fobjtype); +end; + +procedure TMyObj.SetObjType(const Value: TObjType); +begin + FObjType := Value; +end; + +procedure TMyObj.SetProp(name: string; const Value: integer); +begin + if name='pos x' then FX:=Value; + if name='pos y' then FY:=Value; + if name='goto x' then FLength:=Value; + if name='goto y' then Fdir:=Value; + if name='color' then Forient:=Value; + if name='wait' then FWait:=Value; + if name='target' then FTarget:=Value; + if name='shootable' then FSpecial:=Value; + if name='length x' then + if Ord(ObjType)<=5 then FLength:=Value + else FSpecial:=Value; + if name='length y' then + if Ord(ObjType)<=5 then FDir:=Value + else FOrient:=Value; + if name='orientation' then + if Value=0 then FOrient:=FOrient and not 1 + else FOrient:=FOrient or 1; + if name='closed' then + if Value>=1 then FOrient:=FOrient and not 2 + else FOrient:=FOrient or 2; + if name='fastclose' then FSpecial:=Value; + if name='length' then FLength:=Value; + if name='target name' then FTargetName:=Value; + if name='direction' then FOrient:=Value; + if name='pushspeed' then FSpecial:=Value; + if name='dmginterval' then FNowanim:=Value; + if name='dmg' then FDir:=Value; +end; + +procedure TMyObj.SetValues(Obj: TMapOBJV2); +begin + Fx:=Obj.x;Fy:=Obj.y; + Flength:=Obj.Length; + FDir:=Obj.Dir; + Fwait:=Obj.Wait; + Ftargetname:=Obj.TargetName; + Ftarget:=Obj.target; + Forient:=Obj.Orient; + Fnowanim:=Obj.nowanim; + Fspecial:=Obj.special; + Fobjtype:=TObjType(obj.ObjType); +end; + +procedure TMyObj.SetX(const Value: word); +begin + FX := Value; +end; + +procedure TMyObj.SetY(const Value: word); +begin + FY := Value; +end; + +{ TLocation } + +function TLocation.GetValues: TLocationText; +begin + Result.Enabled:=true; + Result.X:=FX; + Result.Y:=FY; + Result.Text:=FText; +end; + +procedure TLocation.SetText(const Value: String64); +begin + FText := Value; +end; + +procedure TLocation.SetValues(Loc: TLocationText); +begin + FX:=Loc.X; + FY:=Loc.Y; + FText:=Loc.Text; +end; + +procedure TLocation.SetX(const Value: byte); +begin + FX := Value; +end; + +procedure TLocation.SetY(const Value: byte); +begin + FY := Value; +end; + +{ TMap } + +function TMap.AddLoc: TLocation; +var + l: Tlocation; +begin + l:=TLocation.Create; + FLocations.Add(l); + Result:=l; +end; + +function TMap.AddObj: TMyObj; +var + b: TMyObj; +begin + b:=TMyObj.Create; + FObj.Add(b); + Result:=b; +end; + +procedure TMap.Assign(Source: TMap); +var + i: integer; +begin + Source.Clear; + Source.FMaxX:=FMaxX; + Source.FMaxY:=FMaxY; + Source.FBrk:=FBrk; + for i:=0 to ObjCount-1 do + Source.AddObj.Values:=Obj[i].Values; + for i:=0 to LocCount-1 do + Source.AddLoc.Values:=Locations[i].Values; + Source.Header:=Header; + Source.Palette.Assign(Palette); +end; + +procedure TMap.Clear; +begin + while ObjCount>0 do + DeleteObj(0); + while LocCount>0 do + DeleteLoc(0); + FillChar(FBrk, SizeOf(TBrickArray), EmptyBrick.image); + SetHeader(DefHeader); + CustomPalette:=false; +end; + +procedure TMap.CopyRect(x1, y1, x2, y2: integer; var Map: TMap; copyObj, + copyLoc: boolean); +var + i, j: integer; + obj_: TMyObj; +begin + Map.Clear; + Map.FMaxX:=x2-x1+1; + Map.FMaxY:=y2-y1+1; + for i:=x1 to x2 do + for j:=y1 to y2 do + Map[i-x1, j-y1]:=Brk[i, j]; + if copyObj then + for i:=0 to ObjCount-1 do + with Obj[i].Rect do + if (Left>=x1) and (Right<=x2) and + (Top>=y1) and (Bottom<=y2) then + begin + obj_:=Map.AddObj; + obj_.Values:=Obj[i].Values; + if (obj_.ObjType=otTeleport) or + (obj_.ObjType=otAreaTeleport) then + begin + obj_.Prop['goto x']:=obj_.Prop['goto x']-x1; + obj_.Prop['goto y']:=obj_.Prop['goto y']-y1; + end; + end; + if copyLoc then + for i:=0 to LocCount-1 do + if (Locations[i].X>=x1) and (Locations[i].X<=x2) and + (Locations[i].Y>=y1) and (Locations[i].Y<=y2) then + Map.AddLoc.Values:=Locations[i].Values; +end; + +constructor TMap.Create; +begin + FObj:=TList.Create; + FLocations:=TList.Create; + FPalette:=TBitmap.Create; + Clear; +end; + +procedure TMap.DeleteLoc(i: integer); +begin + TLocation(FLocations[i]).Free; + FLocations.Delete(i); +end; + +procedure TMap.DeleteLoc(loc_: TLocation); +begin + DeleteLoc(FLocations.IndexOf(loc_)); +end; + +procedure TMap.DeleteObj(i: integer); +begin + TMyObj(FObj[i]).Free; + FObj.Delete(i); +end; + +procedure TMap.DeleteObj(obj_: TMyObj); +begin + DeleteObj(FObj.IndexOf(obj_)); +end; + +destructor TMap.Destroy; +begin + FObj.Free; + FLocations.Free; + FPalette.Free; + inherited; +end; + +function TMap.GetBrick(i, j: integer): TBrick; +begin + if (i>=0) and (i=0) and (j 'NMAP') and (header.ID <> 'NDEM') then begin + f.free; + Result:=-1; + exit; + end; + if (header.Version <> 3) then begin + f.free; + Result:=-2; + exit; + end; + Clear; + SetHeader(Header); + for j := 0 to MaxY - 1 do begin + f.read(buf, MaxX); + for i := 0 to MaxX - 1 do + FBrk[i, j].image := buf[i]; + end; + for i := 0 to header.numobj-1 do + begin + f.Read(Obj,sizeof(Obj)); + AddObj.SetValues(Obj); + end; + + while F.Position < f.size do begin + f.read(entry,sizeof(entry)); + if entry.EntryType = 'pal' then + begin // reading pal + CustomPaletteTransparentColor := Entry.Reserved5; + CustomPaletteTransparent := Entry.Reserved6; + CustomPalette := TRUE; + + decompstr := TMemoryStream.Create; + PaletteStream:=TMemoryStream.Create; + decompstr.CopyFrom (F, Entry.Datasize); + decompstr.position := 0; + BZDecompress(decompstr,PaletteStream, nil); + PaletteStream.Position:=0; + + // apply to scene... + Palette.LoadFromStream(PaletteStream); + palettestream.free; + decompstr.free; + end + else if entry.EntryType = 'loc' then begin // reading location table. + for i := 1 to Entry.DataSize div Sizeof(TLocationText) do + begin + f.Read (Location, Sizeof(TLocationText)); + AddLoc.SetValues(Location); + end; + end + else f.position := f.position + Entry.DataSize; + end; + F.free; +end; + +// END OPEN037MAP + +//************************************************************** +// SAVEMAP!!! +//************************************************************** + + +procedure TMap.SaveMap(FileName: string); +var i, j : Integer; + buf : array [0..$FE] of byte; + Entry : TMapEntry; + PaletteStream, CompressedPaletteStream, MapFile :TMemoryStream; + Head: THeader; + obj_: TMapObjV2; + loc_: TLocationText; +begin + // Сохранение карте в формате nfkbeta031 + MapFile := TMemoryStream.Create; + MapFile.Position := 0; + MapFile.Size := 0; + Head:=GetHeader; + MapFile.Write(Head, Sizeof(THeader)); + for j:=0 to MaxY-1 do + begin + for i := 0 to MaxX-1 do + buf[i]:= Brk[i, j]; + MapFile.Write(buf, MaxX); + end; + + for i:=0 to ObjCount-1 do + begin + Obj_:=Obj[i].Values; + MapFile.Write(Obj_, SizeOf(TMapObjV2)); + end; + + if CUSTOMPALETTE then + begin + FillChar(Entry, SizeOf(Entry), 0); + Entry.EntryType := 'pal'; + Entry.Reserved5 := CUSTOMPALETTETRANSPARENTCOLOR; + Entry.Reserved6 := CUSTOMPALETTETRANSPARENT; + + // do compression... + CompressedPaletteStream := TMemoryStream.Create; + PaletteStream:=TMemoryStream.Create; + Palette.SaveToStream(PaletteStream); + PaletteStream.Position:=0; + BZCompress(PaletteStream, CompressedPaletteStream); + Entry.DataSize := CompressedPaletteStream.Size; + CompressedPaletteStream.Position := 0; + MapFile.Write(Entry,sizeof(Entry)); + MapFile.CopyFrom(CompressedPaletteStream,CompressedPaletteStream.size); + CompressedPaletteStream.Free; + PaletteStream.Free; + end; + + Fillchar(entry,sizeof(entry),0); + Entry.EntryType := 'loc'; + Entry.DataSize := sizeof(TLocationText)*LocCount; + MapFile.Write(Entry,sizeof(Entry)); + for i := 0 to LocCount-1 do + begin + loc_:=Locations[i].Values; + MapFile.Write(loc_, sizeof(TLocationText)); + end; + + MapFile.SaveToFile(FileName); + MapFile.Free; +end; + +// END SAVEMAP + +procedure TMap.SetBackGround(const Value: byte); +begin + FBackGround := Value; +end; + +procedure TMap.SetBrick(i, j: integer; const Value: TBrick); +begin + if (i>=0) and (i=0) and (j=0) and (i=0) and (j=MaxI then Result:=MaxI-1; +end; + +function TMyScroll.GetJ(y: integer): integer; +begin + Result:=(y+GY) div ZoomY; + if Result<0 then Result:=0; + if Result>=MaxJ then Result:=MaxJ-1; +end; + +function TMyScroll.GetMaxX: integer; +begin + Result:=FMaxI*ZoomX; +end; + +function TMyScroll.GetMaxY: integer; +begin + Result:=FMaxJ*ZoomY; +end; + +function TMyScroll.GetX(i: integer): integer; +begin + Result:=i*ZoomX-GX; +end; + +function TMyScroll.GetY(j: integer): integer; +begin + Result:=j*ZoomY-GY; +end; + +procedure TMyScroll.SetGX(const Value: integer); +begin + FGX := Value; + if FScreenWidthGetMaxX-FScreenWidth div 2 then + FGX:=GetMaxX-FScreenWidth div 2; + end else FGX:=(GetMaxX-FScreenWidth) div 2; +end; + +procedure TMyScroll.SetGY(const Value: integer); +begin + FGY:=Value; + if FScreenHeightGetMaxY-FScreenHeight div 2 then + FGY:=GetMaxY-FScreenHeight div 2; + end else FGY:=(GetMaxY-FScreenHeight) div 2; +end; + +procedure TMyScroll.SetMaxI(const Value: integer); +begin + FMaxI := Value; +end; + +procedure TMyScroll.SetMaxJ(const Value: integer); +begin + FMaxJ := Value; +end; + +procedure TMyScroll.SetScreenHeight(const Value: integer); +begin + FScreenHeight := Value; +end; + +procedure TMyScroll.SetScreenWidth(const Value: integer); +begin + FScreenWidth := Value; +end; + +procedure TMyScroll.SetZoomX(const Value: integer); +begin + FZoomX := Value; +end; + +procedure TMyScroll.SetZoomY(const Value: integer); +begin + FZoomY := Value; +end; + +end. diff --git a/EDITOR/RadiantPro/MyStrings.pas b/EDITOR/RadiantPro/MyStrings.pas new file mode 100644 index 0000000..a2938e1 --- /dev/null +++ b/EDITOR/RadiantPro/MyStrings.pas @@ -0,0 +1,72 @@ +unit MyStrings; + +interface + +const + Br_count = 42; + +const + BrushNames: array [-2..Br_Count] of String = + ( + {-2} 'Brush: unknown', + {-1} 'Brush: brick', + {0} 'Brush: none', + {1} 'Brush: shotgun', + {2} 'Brush: grenade launcher', + {3} 'Brush: rocket launcher', + {4} 'Brush: shaft', + {5} 'Brush: railgun', + {6} 'Brush: plasma', + {7} 'Brush: bfg', + {8} 'Brush: ammo for machinegun', + {9} 'Brush: ammo for shotgun', + {10} 'Brush: ammo for grenade launcher', + {11} 'Brush: ammo for rocket launcher', + {12} 'Brush: ammo for shaft', + {13} 'Brush: ammo for railgun', + {14} 'Brush: ammo for plasma', + {15} 'Brush: ammo for bfg', + {16} 'Brush: shard (+5)', + {17} 'Brush: yellow armor (+50)', + {18} 'Brush: red armor (+100)', + {19} 'Brush: health +5', + {20} 'Brush: health +25', + {21} 'Brush: health +50', + {22} 'Brush: megahealth +100', + {23} 'Brush: powerup regeneration', + {24} 'Brush: powerup battlesuit', + {25} 'Brush: powerup haste', + {26} 'Brush: powerup quaddamage', + {27} 'Brush: powerup flight', + {28} 'Brush: powerup invisibility', + {29} 'Brush: grenade launcher for trix', + {30} 'Brush: rocket launcher for trix', + {31} 'Brush: lava', + {32} 'Brush: water', + {33} 'Brush: death area. kills player.', + {34} 'Brush: respawn. neutral', + {35} 'Brush: respawn. red team (CTF ONLY)', + {36} 'Brush: respawn. blu team (CTF ONLY)', + {37} 'Brush: empty brick', + {38} 'Brush: jumppad', + {39} 'Brush: strong jumppad', + {40} 'Brush: red flag', + {41} 'Brush: blue flag', + {42} 'Brush: domination point' + ); + + +function GetBrushName(Brush: integer): string; + +implementation + +function GetBrushName(Brush: integer): string; +begin + case brush of + 0..42 : Result:=BrushNames[Brush]; + 54..255 : Result:=BrushNames[-1]; + else Result:=BrushNames[-2]; + end; +end; + +end. diff --git a/EDITOR/RadiantPro/bz/PowerAcrModuleInfo.pas b/EDITOR/RadiantPro/bz/PowerAcrModuleInfo.pas new file mode 100644 index 0000000..1b8b772 --- /dev/null +++ b/EDITOR/RadiantPro/bz/PowerAcrModuleInfo.pas @@ -0,0 +1,25 @@ +Unit PowerAcrModuleInfo; + +Interface + +Const + PowerArcModuleSignature = 'AA6F3C60-37D7-11D4-B4BF-D80DBEC04C01'; + +Type + TPowerArcModuleInfo = Packed Record + Signature: PChar; // must be eq to PowerArcModuleSignature + Name: PChar; // short name + Description: PChar; // full description + Options: PChar; // opt list delimited with #0 + // bit per char on calgary corpus *100 + DefaultBPC: integer; + MaxBPC: integer; + Case integer Of // unique + 0: (ModuleID: Packed Array[0..7] Of Char); + 1: (ModuleIDW: Packed Array[0..1] Of integer); + End; + PPowerArcModuleInfo = ^TPowerArcModuleInfo; + +Implementation + +End. diff --git a/EDITOR/RadiantPro/bz/PowerArc.pas b/EDITOR/RadiantPro/bz/PowerArc.pas new file mode 100644 index 0000000..88d35be --- /dev/null +++ b/EDITOR/RadiantPro/bz/PowerArc.pas @@ -0,0 +1,673 @@ +unit PowerArc; + +{| PowerArc 1.3.1 /5 Apr 2001/ + | Copyright (c) 2000,2001 SoftLab MIL-TEC Ltd + | Web http://www.softcomplete.com + | Email support@softcomplete.com + | Data compression library for Delphi and C++ Builder + |} + +{------------------------------------------------------------------------------- + What's new in ver.1.3.1 + + change interface proc names + RegisterPowerArcModule -> PowerArcRegisterModule + SetOptions -> PowerArcSetOptions + Compress -> PowerArcCompress + Decompress -> PowerArcDecompress + + change param order in PowerArcCompress + was: + function PowerArcCompress(ArcIdx: integer; InStream,OutStream: TStream; + const ArcOpt: string = ''; ProgressCallback: TProgressCallback = nil): Boolean; + now: + function PowerArcCompress(InStream,OutStream: TStream; + ArcIdx: integer = iPowerBZIP; const ArcOpt: string = ''; + ProgressCallback: TProgressCallback = nil): Boolean; +-------------------------------------------------------------------------------- + What's new in ver.1.3 + + full progress callback support + + TProgressCallback changed type definition + + update BZIP core to ver.1.0.1 + + implementation BZIP as default built-in method + + RegisterPowerArcModule now check for dups + + fix memory leak: free Options list + + fix bug in Read/Write methods in implementation of stream interface +-------------------------------------------------------------------------------} + +interface + +uses SysUtils, Windows, Classes, PowerAcrModuleInfo, bzLib; + +type + EPowerArcError = class(Exception); + TProgressCallback = procedure (Current: integer) of object; + +const // default compression method + iPowerBZIP = 0; +var // loadable compression engines + iPowerZIP: integer = 0; + iPowerRANK: integer = 0; + iPowerPPM: integer = 0; + +function PowerArcRegisterModule(const Name: string): integer; + +procedure PowerArcSetOptions(ArcIdx: integer; const ArcOpt: string); + +function PowerArcCompress(InStream,OutStream: TStream; + ArcIdx: integer = iPowerBZIP; const ArcOpt: string = ''; + ProgressCallback: TProgressCallback = nil): Boolean; overload; + +function PowerArcCompress(const Buffer; Size: integer; OutStream: TStream; + ArcIdx: integer = iPowerBZIP; const ArcOpt: string = ''; + ProgressCallback: TProgressCallback = nil): Boolean; overload; + +function PowerArcDecompress(InStream,OutStream: TStream; + ProgressCallback: TProgressCallback = nil): Boolean; + +//============================ Stream interface ================================ + +type + +{ TPowerArcCompressStream compresses data on the fly as data is written to it, + and stores the compressed data to another stream. + + TPowerArcCompressStream is write-only and strictly sequential. Reading from the + stream will raise an exception. Using Seek to move the stream pointer + will raise an exception. + + Output data is cached internally, written to the output stream only when + the internal output buffer is full. All pending output data is flushed + when the stream is destroyed. + + The Position property returns the number of uncompressed bytes of + data that have been written to the stream so far. + + The OnProgress event is called each time the output buffer is filled and + written to the output stream. This is useful for updating a progress + indicator when you are writing a large chunk of data to the compression + stream in a single call.} + + TPowerArcCompressStream = class(TStream) + private + Base: TStream; + ArcIdx: integer; + ArcOpt: string; + Thread: TThread; + hReadPipe, + hWritePipe: THandle; + TotalWrited: integer; + BZCompressionStream: TBZCompressionStream; + FOnProgress: TProgressCallback; + procedure DoProgress(Current: integer); + public + constructor Create(BaseStream: TStream; FArcIdx: integer = iPowerBZIP; + const FArcOpt: string = ''); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress: TProgressCallback read FOnProgress write FOnProgress; + end; + +{ TPowerArcDecompressStream decompresses data on the fly as data is read from it. + + Compressed data comes from a separate source stream. TPowerArcDecompressStream + is read-only and unidirectional; you can seek forward in the stream, but not + backwards. The special case of setting the stream position to zero is + allowed. Seeking forward decompresses data until the requested position in + the uncompressed data has been reached. Seeking backwards, seeking relative + to the end of the stream, requesting the size of the stream, and writing to + the stream will raise an exception. + + The Position property returns the number of bytes of uncompressed data that + have been read from the stream so far. + + The OnProgress event is called each time the internal input buffer of + compressed data is exhausted and the next block is read from the input stream. + This is useful for updating a progress indicator when you are reading a + large chunk of data from the decompression stream in a single call.} + + TPowerArcDecompressStream = class(TStream) + private + Base: TStream; + ArcIdx: integer; + Thread: TThread; + hReadPipe, + hWritePipe: THandle; + TotalReaded: integer; + BZDecompressionStream: TBZDecompressionStream; + FOnProgress: TProgressCallback; + procedure DoProgress(Current: integer); + public + constructor Create(BaseStream: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress: TProgressCallback read FOnProgress write FOnProgress; + end; + +//============================================================================== + +type + // callback's + TReadFunc = function (Data: Pointer; var Buffer; Size: integer): integer; stdcall; + TWriteFunc = function (Data: Pointer; const Buffer; Size: integer): integer; stdcall; + // dll entryes + TPowerArcSetOptions = procedure (Opt: PChar); stdcall; + TPowerArcCompress = procedure (Data: Pointer; Opt: PChar; ReadFunc: TReadFunc; + WriteFunc: TWriteFunc); stdcall; + TPowerArcCompressMem = procedure (Data: Pointer; Opt: PChar; Mem: Pointer; + MemSize: integer; WriteFunc: TWriteFunc); stdcall; + TPowerArcDecompress = function (Data: Pointer; ReadFunc: TReadFunc; + WriteFunc: TWriteFunc): Boolean; stdcall; + // dll registration info + TPowerArcModule = record + Name: string; + hLib: THandle; + Info: PPowerArcModuleInfo; + Options: TStringList; + SetOptions: TPowerArcSetOptions; + Compress: TPowerArcCompress; + CompressMem: TPowerArcCompressMem; + Decompress: TPowerArcDecompress; + end; + +var + PowerArcModules: array of TPowerArcModule; + +implementation + +const + PipeSize = 4*4096; + +type + TPowerArcData = record + InStream,OutStream: TStream; + Current: integer; + ProgressCallback: TProgressCallback; + end; + +function ReadFunc(Data: Pointer; var Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcData(Data^).InStream.Read(Buffer,Size); + if Assigned(TPowerArcData(Data^).ProgressCallback) then begin + Inc(TPowerArcData(Data^).Current,Result); + TPowerArcData(Data^).ProgressCallback(TPowerArcData(Data^).Current); + end; +end; + +function WriteFunc(Data: Pointer; const Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcData(Data^).OutStream.Write(Buffer,Size); +end; + +function ValidArcIdx(ArcIdx: integer): Boolean; +begin + Result:=(ArcIdx >= 0) and (ArcIdx < Length(PowerArcModules)); +end; + +procedure PowerArcSetOptions(ArcIdx: integer; const ArcOpt: string); +begin + // no opt for default method + if (ArcIdx <> iPowerBZIP) and ValidArcIdx(ArcIdx) then + PowerArcModules[ArcIdx].SetOptions(PChar(ArcOpt)); +end; + +function PowerArcCompress(InStream,OutStream: TStream; + ArcIdx: integer; const ArcOpt: string; + ProgressCallback: TProgressCallback): Boolean; +var Data: TPowerArcData; +begin + Result:=False; + if ArcIdx = iPowerBZIP then begin + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompress(InStream,OutStream,ProgressCallback); + Result:=True; + end else if ValidArcIdx(ArcIdx) then try + Data.InStream:=InStream; + Data.OutStream:=OutStream; + Data.ProgressCallback:=ProgressCallback; + Data.Current:=0; + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + PowerArcModules[ArcIdx].Compress(@Data,PChar(ArcOpt),ReadFunc,WriteFunc); + Result:=True; + except + end; +end; + +type + TMapMemoryStream = class (TCustomMemoryStream) + private + FReadOnly: Boolean; + public + constructor Create(Buf: Pointer; Size: integer; ReadOnly: Boolean); + function Write(const Buffer; Count: integer): integer; override; + end; + +constructor TMapMemoryStream.Create(Buf: Pointer; Size: integer; ReadOnly: Boolean); +begin + inherited Create; + SetPointer(Buf,Size); + FReadOnly:=ReadOnly; +end; + +function TMapMemoryStream.Write(const Buffer; Count: integer): integer; +begin + if FReadOnly then Result:=0 + else begin + if Position+Count > Size then Result:=Size-Position + else Result:=Count; + Move(Buffer, Pointer(integer(Memory) + Position)^, Result); + Seek(Result,1); + end; +end; + +function PowerArcCompress(const Buffer; Size: integer; OutStream: TStream; + ArcIdx: integer; const ArcOpt: string; + ProgressCallback: TProgressCallback): Boolean; +var Data: TPowerArcData; + MapMemoryStream: TMapMemoryStream; +begin + if Assigned(ProgressCallback) then begin + if ArcIdx = iPowerBZIP then begin + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompress(Buffer,Size,OutStream,ProgressCallback); + Result:=True; + end else begin + MapMemoryStream:=TMapMemoryStream.Create(@Buffer,Size,True); + try + Result:=PowerArcCompress(MapMemoryStream,OutStream,ArcIdx,ArcOpt,ProgressCallback); + finally + MapMemoryStream.Free; + end; + end; + end else begin + Result:=False; + if ArcIdx = iPowerBZIP then begin + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompress(Buffer,Size,OutStream); + Result:=True; + end else if ValidArcIdx(ArcIdx) then try + Data.OutStream:=OutStream; + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + PowerArcModules[ArcIdx].CompressMem(@Data,PChar(ArcOpt),@Buffer,Size,WriteFunc); + Result:=True; + except + end; + end; +end; + +function PowerArcDecompress(InStream,OutStream: TStream; + ProgressCallback: TProgressCallback): Boolean; +var ModuleID: packed array[0..7] of Char; + j: integer; + Data: TPowerArcData; +begin + Result:=False; + InStream.Read(ModuleID[0],8); + for j:=0 to Length(PowerArcModules)-1 do + if PowerArcModules[j].Info^.ModuleID = ModuleID then try + if j = iPowerBZIP then + BZDecompress(InStream,OutStream) + else begin + Data.InStream:=InStream; + Data.OutStream:=OutStream; + Data.ProgressCallback:=ProgressCallback; + Data.Current:=0; + PowerArcModules[j].Decompress(@Data,ReadFunc,WriteFunc); + end; + Result:=True; + Exit; + except + end; +end; + +function PowerArcRegisterModule(const Name: string): integer; +type TGetPowerArcModuleInfo = function: PPowerArcModuleInfo; +var PowerArcModule: TPowerArcModule; + GetPowerArcModuleInfo: TGetPowerArcModuleInfo; + POpt: PChar; + j: integer; +begin + Result:=-1; + PowerArcModule.hLib:=LoadLibrary(PChar(Name)); + if PowerArcModule.hLib <> 0 then begin + PowerArcModule.Name:=Name; + GetPowerArcModuleInfo:=TGetPowerArcModuleInfo(GetProcAddress(PowerArcModule.hLib, + 'GetPowerArcModuleInfo')); + PowerArcModule.Info:=GetPowerArcModuleInfo; + // check that module exists + for j:=0 to Length(PowerArcModules)-1 do + if PowerArcModules[j].Info^.ModuleID = PowerArcModule.Info.ModuleID then begin + Result:=j; + FreeLibrary(PowerArcModule.hLib); + Exit; + end; + // continue init + PowerArcModule.SetOptions:=TPowerArcSetOptions(GetProcAddress(PowerArcModule.hLib,'SetOptions')); + PowerArcModule.Compress:=TPowerArcCompress(GetProcAddress(PowerArcModule.hLib,'Compress')); + PowerArcModule.CompressMem:=TPowerArcCompressMem(GetProcAddress(PowerArcModule.hLib,'CompressMem')); + PowerArcModule.Decompress:=TPowerArcDecompress(GetProcAddress(PowerArcModule.hLib,'Decompress')); + if Assigned(GetPowerArcModuleInfo) and + (PowerArcModule.Info^.Signature = PowerArcModuleSignature) and + Assigned(PowerArcModule.SetOptions) and + Assigned(PowerArcModule.Compress) and + Assigned(PowerArcModule.CompressMem) and + Assigned(PowerArcModule.Decompress) then begin + PowerArcModule.Options:=TStringList.Create; + POpt:=PowerArcModule.Info^.Options; + while POpt^ <> #0 do begin + PowerArcModule.Options.Add(POpt); + POpt:=POpt+StrLen(POpt)+1; + end; + SetLength(PowerArcModules,Length(PowerArcModules)+1); + PowerArcModules[Length(PowerArcModules)-1]:=PowerArcModule; + Result:=Length(PowerArcModules)-1; + end else + FreeLibrary(PowerArcModule.hLib); + end; +end; + +procedure PowerArcUnregisterModules; +var j: integer; +begin + for j:=0 to Length(PowerArcModules)-1 do begin + if PowerArcModules[j].hLib <> 0 then + FreeLibrary(PowerArcModules[j].hLib); + PowerArcModules[j].Options.Free; + end; + PowerArcModules:=nil; +end; + +{ TCompressThread } + +type + TCompressThread = class(TThread) + private + Done: Boolean; + CompressStream: TPowerArcCompressStream; + protected + procedure Execute; override; + end; + +{ TCompressThread } + +function ReadCompressFunc(Data: Pointer; var Buffer; Size: integer): integer; stdcall; +begin + if not Windows.ReadFile(TPowerArcCompressStream(Data).hReadPipe,Buffer,Size,DWORD(Result),nil) then + Result:=-1; +end; + +function WriteCompressFunc(Data: Pointer; const Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcCompressStream(Data).Base.Write(Buffer,Size); +end; + +procedure TCompressThread.Execute; +begin + try + CompressStream.Base.Write(PowerArcModules[CompressStream.ArcIdx].Info^.ModuleID[0],8); + PowerArcModules[CompressStream.ArcIdx].Compress(CompressStream, + PChar(CompressStream.ArcOpt),ReadCompressFunc,WriteCompressFunc); + except + end; + CloseHandle(CompressStream.hReadPipe); + Done:=True; +end; + +{ TPowerArcCompressStream } + +constructor TPowerArcCompressStream.Create(BaseStream: TStream; + FArcIdx: integer; const FArcOpt: string); +begin + inherited Create; + Base:=BaseStream; + ArcIdx:=FArcIdx; + ArcOpt:=FArcOpt; + Thread:=nil; + FOnProgress:=nil; + TotalWrited:=0; + if not ValidArcIdx(ArcIdx) then + raise EPowerArcError.Create('Invalid acrhive index'); + if ArcIdx = iPowerBZIP then begin + Base.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompressionStream:=TBZCompressionStream.Create(Base); + BZCompressionStream.OnProgress:=DoProgress; + end else + BZCompressionStream:=nil; +end; + +destructor TPowerArcCompressStream.Destroy; +begin + if Thread <> nil then begin + CloseHandle(hWritePipe); + while not TCompressThread(Thread).Done do Sleep(0); + Thread.Free; + end; + if BZCompressionStream <> nil then + BZCompressionStream.Free; + inherited; +end; + +procedure TPowerArcCompressStream.DoProgress(Current: integer); +begin + if Assigned(FOnProgress) then FOnProgress(Current); +end; + +function TPowerArcCompressStream.Read(var Buffer; Count: Integer): Longint; +begin + raise EPowerArcError.Create('Invalid stream operation'); +end; + +function TPowerArcCompressStream.Seek(Offset: Integer; + Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := TotalWrited + else + raise EPowerArcError.Create('Invalid stream operation'); +end; + +function TPowerArcCompressStream.Write(const Buffer; + Count: Integer): Longint; +var Ret: Boolean; + ActualWrite: DWORD; + P: PChar; +begin + if ArcIdx = iPowerBZIP then + Result:=BZCompressionStream.Write(Buffer,Count) + else if Count > 0 then begin + if Thread = nil then begin + CreatePipe(hReadPipe,hWritePipe,nil,PipeSize); + Thread:=TCompressThread.Create(True); + TCompressThread(Thread).CompressStream:=Self; + TCompressThread(Thread).Done:=False; + Thread.FreeOnTerminate:=False; + Thread.Resume; + end; + //Windows.WriteFile(hWritePipe,Buffer,Count,DWORD(Result),nil); + Result:=0; + P:=PChar(@Buffer); + while Count > 0 do begin + Ret:=Windows.WriteFile(hWritePipe,P^,Count,ActualWrite,nil); + if not Ret or (Ret and (ActualWrite = 0)) then begin + if Result = 0 then Result:=-1; + Break; + end; + Dec(Count,ActualWrite); + Inc(Result,ActualWrite); + Inc(P,ActualWrite); + Sleep(0); + end; + end else + Result:=0; + if Result > 0 then begin + Inc(TotalWrited,Result); + if ArcIdx <> iPowerBZIP then + DoProgress(TotalWrited); + end; +end; + +{ TDecompressThread } + +type + TDecompressThread = class(TThread) + private + Done: Boolean; + DecompressStream: TPowerArcDecompressStream; + protected + procedure Execute; override; + end; + +{ TDecompressThread } + +function ReadDecompressFunc(Data: Pointer; var Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcDecompressStream(Data).Base.Read(Buffer,Size); +end; + +function WriteDecompressFunc(Data: Pointer; const Buffer; Size: integer): integer; stdcall; +begin + if not Windows.WriteFile(TPowerArcDecompressStream(Data).hWritePipe,Buffer,Size,DWORD(Result),nil) then + Result:=-1; +end; + +procedure TDecompressThread.Execute; +begin + try + PowerArcModules[DecompressStream.ArcIdx].Decompress(DecompressStream, + ReadDecompressFunc,WriteDecompressFunc); + except + end; + CloseHandle(DecompressStream.hWritePipe); + Done:=True; +end; + +{ TPowerArcDecompressStream } + +constructor TPowerArcDecompressStream.Create(BaseStream: TStream); +var ModuleID: packed array[0..7] of Char; + j: integer; +begin + inherited Create; + Base:=BaseStream; + Thread:=nil; + FOnProgress:=nil; + TotalReaded:=0; + if Base.Read(ModuleID[0],8) = 8 then + for j:=0 to Length(PowerArcModules)-1 do + if PowerArcModules[j].Info^.ModuleID = ModuleID then begin + if j = iPowerBZIP then begin + BZDecompressionStream:=TBZDecompressionStream.Create(Base); + BZDecompressionStream.OnProgress:=DoProgress; + end else + BZDecompressionStream:=nil; + ArcIdx:=j; + Exit; + end; + raise EPowerArcError.Create('Invalid acrhive index'); +end; + +destructor TPowerArcDecompressStream.Destroy; +begin + if Thread <> nil then begin + CloseHandle(hReadPipe); + while not TDecompressThread(Thread).Done do Sleep(0); + Thread.Free; + end; + if BZDecompressionStream <> nil then + BZDecompressionStream.Free; + inherited; +end; + +procedure TPowerArcDecompressStream.DoProgress(Current: integer); +begin + if Assigned(FOnProgress) then FOnProgress(Current); +end; + +function TPowerArcDecompressStream.Read(var Buffer; + Count: Integer): Longint; +var Ret: Boolean; + ActualRead: DWORD; + P: PChar; +begin + if ArcIdx = iPowerBZIP then + Result:=BZDecompressionStream.Read(Buffer,Count) + else if Count > 0 then begin + if Thread = nil then begin + CreatePipe(hReadPipe,hWritePipe,nil,PipeSize); + Thread:=TDecompressThread.Create(True); + TDecompressThread(Thread).DecompressStream:=Self; + TDecompressThread(Thread).Done:=False; + Thread.FreeOnTerminate:=False; + Thread.Resume; + end; + Result:=0; + P:=PChar(@Buffer); + while Count > 0 do begin + Ret:=Windows.ReadFile(hReadPipe,P^,Count,ActualRead,nil); + if not Ret or (Ret and (ActualRead = 0)) then begin + if Result = 0 then Result:=-1; + Break; + end; + Dec(Count,ActualRead); + Inc(Result,ActualRead); + Inc(P,ActualRead); + Sleep(0); + end; + end else + Result:=0; + if Result > 0 then begin + Inc(TotalReaded,Result); + if ArcIdx <> iPowerBZIP then + DoProgress(TotalReaded); + end; +end; + +function TPowerArcDecompressStream.Seek(Offset: Integer; + Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := TotalReaded + else + raise EPowerArcError.Create('Invalid stream operation'); +end; + +function TPowerArcDecompressStream.Write(const Buffer; + Count: Integer): Longint; +begin + raise EPowerArcError.Create('Invalid stream operation'); +end; + +// register default compression engine +procedure RegisterBZIP; +var POpt: PChar; +begin + SetLength(PowerArcModules,1); + with PowerArcModules[iPowerBZIP] do begin + Name:=''; + hLib:=0; + Info:=BZGetPowerArcModuleInfo; + Options:=TStringList.Create; + POpt:=Info^.Options; + while POpt^ <> #0 do begin + Options.Add(POpt); + POpt:=POpt+StrLen(POpt)+1; + end; + SetOptions:=nil; + Compress:=nil; + CompressMem:=nil; + Decompress:=nil; + end; +end; + +{ TCallbackObj } + +initialization + RegisterBZIP; + iPowerRANK:=PowerArcRegisterModule('PowerRANK.dll'); + iPowerZIP:=PowerArcRegisterModule('PowerZIP.dll'); + iPowerPPM:=PowerArcRegisterModule('PowerPPM.dll'); +finalization + PowerArcUnregisterModules; +end. diff --git a/EDITOR/RadiantPro/bz/bzLib.pas b/EDITOR/RadiantPro/bz/bzLib.pas new file mode 100644 index 0000000..f4c34a2 --- /dev/null +++ b/EDITOR/RadiantPro/bz/bzLib.pas @@ -0,0 +1,501 @@ +{*******************************************************} +{ } +{ BZIP2 1.0 Data Compression Interface Unit } +{ } +{*******************************************************} + +Unit bzLib; + +Interface + +Uses SysUtils, Classes, PowerAcrModuleInfo; + +Type + TAlloc = Function(opaque: Pointer; Items, size: integer): Pointer; cdecl; + TFree = Procedure(opaque, Block: Pointer); cdecl; + + // Internal structure. Ignore. + TBZStreamRec = Packed Record + next_in: PChar; // next input byte + avail_in: longword; // number of bytes available at next_in + total_in: int64; // total nb of input bytes read so far + + next_out: PChar; // next output byte should be put here + avail_out: longword; // remaining free space at next_out + total_out: int64; // total nb of bytes output so far + + state: Pointer; + + bzalloc: TAlloc; // used to allocate the internal state + bzfree: TFree; // used to free the internal state + opaque: Pointer; + End; + + TProgressEvent = Procedure(Current: integer) Of Object; + // Abstract ancestor class + TCustomBZip2Stream = Class(TStream) + Private + FStrm: TStream; + FStrmPos: integer; + FOnProgress: TProgressEvent; + FBZRec: TBZStreamRec; + FBuffer: Array[Word] Of Char; + Protected + Procedure Progress(Sender: TObject); Dynamic; + Public + Constructor Create(Strm: TStream); + Property OnProgress: TProgressEvent Read FOnProgress Write FOnProgress; + End; + + TBZCompressionStream = Class(TCustomBZip2Stream) + Public + Constructor Create(Dest: TStream); + Destructor Destroy; Override; + Function Read(Var Buffer; Count: LongInt): LongInt; Override; + Function write(Const Buffer; Count: LongInt): LongInt; Override; + Function Seek(Offset: LongInt; Origin: Word): LongInt; Override; + Property OnProgress; + End; + + TBZDecompressionStream = Class(TCustomBZip2Stream) + Public + Constructor Create(Source: TStream); + Destructor Destroy; Override; + Function Read(Var Buffer; Count: LongInt): LongInt; Override; + Function write(Const Buffer; Count: LongInt): LongInt; Override; + Function Seek(Offset: LongInt; Origin: Word): LongInt; Override; + Property OnProgress; + End; + + { CompressBuf compresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +Procedure BZCompressBuf(Const InBuf: Pointer; InBytes: integer; + Out OutBuf: Pointer; Out OutBytes: integer); + +{ DecompressBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + OutEstimate = zero, or est. size of the decompressed data + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +Procedure BZDecompressBuf(Const InBuf: Pointer; InBytes: integer; + OutEstimate: integer; Out OutBuf: Pointer; Out OutBytes: integer); + +Procedure BZCompress(Const Buffer; size: integer; OutStream: TStream; + ProgressCallback: TProgressEvent = Nil); overload; +Procedure BZCompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent = Nil); overload; +Procedure BZDecompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent = Nil); + +Type + EBZip2Error = Class(Exception); + EBZCompressionError = Class(EBZip2Error); + EBZDecompressionError = Class(EBZip2Error); + + // -------------------------- PowerArc specific -------------------------------- + +Function BZGetPowerArcModuleInfo: PPowerArcModuleInfo; + +Implementation + +{$L blocksort.obj} +{$L huffman.obj} +{$L compress.obj} +{$L decompress.obj} +{$L bzlib2.obj} +{$L crctable.obj} +{$L randtable.obj} + +Procedure _BZ2_hbMakeCodeLengths; External; +Procedure _BZ2_blockSort; External; +Procedure _BZ2_hbCreateDecodeTables; External; +Procedure _BZ2_hbAssignCodes; External; +Procedure _BZ2_compressBlock; External; +Procedure _BZ2_decompress; External; + +Const + BZ_RUN = 0; + BZ_FLUSH = 1; + BZ_FINISH = 2; + BZ_OK = 0; + BZ_RUN_OK = 1; + BZ_FLUSH_OK = 2; + BZ_FINISH_OK = 3; + BZ_STREAM_END = 4; + BZ_SEQUENCE_ERROR = (-1); + BZ_PARAM_ERROR = (-2); + BZ_MEM_ERROR = (-3); + BZ_DATA_ERROR = (-4); + BZ_DATA_ERROR_MAGIC = (-5); + BZ_IO_ERROR = (-6); + BZ_UNEXPECTED_EOF = (-7); + BZ_OUTBUFF_FULL = (-8); + + BZ_LEVEL = 9; + +Procedure _bz_internal_error(errcode: integer); Cdecl; +Begin + Raise EBZip2Error.CreateFmt('Compression Error %d', [errcode]); +End; + +Function _malloc(size: integer): Pointer; Cdecl; +Begin + GetMem(result, size); +End; + +Procedure _free(Block: Pointer); Cdecl; +Begin + FreeMem(Block); +End; + +// deflate compresses data + +Function BZ2_bzCompressInit(Var Strm: TBZStreamRec; BlockSize: integer; + verbosity: integer; workFactor: integer): integer; Stdcall; External; + +Function BZ2_bzCompress(Var Strm: TBZStreamRec; Action: integer): integer; + Stdcall; External; + +Function BZ2_bzCompressEnd(Var Strm: TBZStreamRec): integer; Stdcall; External; + +Function BZ2_bzBuffToBuffCompress(Dest: Pointer; Var destLen: integer; Source: + Pointer; + sourceLen, BlockSize, verbosity, workFactor: integer): integer; Stdcall; + External; + +// inflate decompresses data + +Function BZ2_bzDecompressInit(Var Strm: TBZStreamRec; verbosity: integer; + small: integer): integer; Stdcall; External; + +Function BZ2_bzDecompress(Var Strm: TBZStreamRec): integer; Stdcall; External; + +Function BZ2_bzDecompressEnd(Var Strm: TBZStreamRec): integer; Stdcall; + External; + +Function BZ2_bzBuffToBuffDecompress(Dest: Pointer; Var destLen: integer; Source: + Pointer; + sourceLen, small, verbosity: integer): integer; Stdcall; External; + +Function bzip2AllocMem(AppData: Pointer; Items, size: integer): Pointer; Cdecl; +Begin + GetMem(result, Items * size); +End; + +Procedure bzip2FreeMem(AppData, Block: Pointer); Cdecl; +Begin + FreeMem(Block); +End; + +Function CCheck(code: integer): integer; +Begin + result := code; + If code < 0 Then + Raise EBZCompressionError.CreateFmt('error %d', [code]); //!! +End; + +Function DCheck(code: integer): integer; +Begin + result := code; + If code < 0 Then + Raise EBZDecompressionError.CreateFmt('error %d', [code]); //!! +End; + +Procedure BZCompressBuf(Const InBuf: Pointer; InBytes: integer; + Out OutBuf: Pointer; Out OutBytes: integer); +Var + Strm : TBZStreamRec; + p : Pointer; +Begin + FillChar(Strm, Sizeof(Strm), 0); + Strm.bzalloc := bzip2AllocMem; + Strm.bzfree := bzip2FreeMem; + OutBytes := ((InBytes + (InBytes Div 10) + 12) + 255) And Not 255; + GetMem(OutBuf, OutBytes); + Try + Strm.next_in := InBuf; + Strm.avail_in := InBytes; + Strm.next_out := OutBuf; + Strm.avail_out := OutBytes; + CCheck(BZ2_bzCompressInit(Strm, BZ_LEVEL, 0, 0)); + Try + While CCheck(BZ2_bzCompress(Strm, BZ_FINISH)) <> BZ_STREAM_END Do + Begin + p := OutBuf; + Inc(OutBytes, 256); + ReallocMem(OutBuf, OutBytes); + Strm.next_out := PChar(integer(OutBuf) + (integer(Strm.next_out) - + integer(p))); + Strm.avail_out := 256; + End; + Finally + CCheck(BZ2_bzCompressEnd(Strm)); + End; + ReallocMem(OutBuf, Strm.total_out); + OutBytes := Strm.total_out; + Except + FreeMem(OutBuf); + Raise + End; +End; + +Procedure BZDecompressBuf(Const InBuf: Pointer; InBytes: integer; + OutEstimate: integer; Out OutBuf: Pointer; Out OutBytes: integer); +Var + Strm : TBZStreamRec; + p : Pointer; + BufInc : integer; +Begin + FillChar(Strm, Sizeof(Strm), 0); + Strm.bzalloc := bzip2AllocMem; + Strm.bzfree := bzip2FreeMem; + BufInc := (InBytes + 255) And Not 255; + If OutEstimate = 0 Then + OutBytes := BufInc + Else + OutBytes := OutEstimate; + GetMem(OutBuf, OutBytes); + Try + Strm.next_in := InBuf; + Strm.avail_in := InBytes; + Strm.next_out := OutBuf; + Strm.avail_out := OutBytes; + DCheck(BZ2_bzDecompressInit(Strm, 0, 0)); + Try + While DCheck(BZ2_bzDecompress(Strm)) <> BZ_STREAM_END Do + Begin + p := OutBuf; + Inc(OutBytes, BufInc); + ReallocMem(OutBuf, OutBytes); + Strm.next_out := PChar(integer(OutBuf) + (integer(Strm.next_out) - + integer(p))); + Strm.avail_out := BufInc; + End; + Finally + DCheck(BZ2_bzDecompressEnd(Strm)); + End; + ReallocMem(OutBuf, Strm.total_out); + OutBytes := Strm.total_out; + Except + FreeMem(OutBuf); + Raise + End; +End; + +// TCustomBZip2Stream + +Constructor TCustomBZip2Stream.Create(Strm: TStream); +Begin + Inherited Create; + FStrm := Strm; + FStrmPos := Strm.Position; + FBZRec.bzalloc := bzip2AllocMem; + FBZRec.bzfree := bzip2FreeMem; +End; + +Procedure TCustomBZip2Stream.Progress(Sender: TObject); +Begin + If Assigned(FOnProgress) Then FOnProgress(Position); +End; + +// TBZCompressionStream + +Constructor TBZCompressionStream.Create(Dest: TStream); +Begin + Inherited Create(Dest); + FBZRec.next_out := FBuffer; + FBZRec.avail_out := Sizeof(FBuffer); + CCheck(BZ2_bzCompressInit(FBZRec, BZ_LEVEL, 0, 0)); +End; + +Destructor TBZCompressionStream.Destroy; +Begin + FBZRec.next_in := Nil; + FBZRec.avail_in := 0; + Try + If FStrm.Position <> FStrmPos Then FStrm.Position := FStrmPos; + While (CCheck(BZ2_bzCompress(FBZRec, BZ_FINISH)) <> BZ_STREAM_END) + And (FBZRec.avail_out = 0) Do + Begin + FStrm.WriteBuffer(FBuffer, Sizeof(FBuffer)); + FBZRec.next_out := FBuffer; + FBZRec.avail_out := Sizeof(FBuffer); + End; + If FBZRec.avail_out < Sizeof(FBuffer) Then + FStrm.WriteBuffer(FBuffer, Sizeof(FBuffer) - FBZRec.avail_out); + Finally + BZ2_bzCompressEnd(FBZRec); + End; + Inherited Destroy; +End; + +Function TBZCompressionStream.Read(Var Buffer; Count: LongInt): LongInt; +Begin + Raise EBZCompressionError.Create('Invalid stream operation'); +End; + +Function TBZCompressionStream.write(Const Buffer; Count: LongInt): LongInt; +Begin + FBZRec.next_in := @Buffer; + FBZRec.avail_in := Count; + If FStrm.Position <> FStrmPos Then FStrm.Position := FStrmPos; + While (FBZRec.avail_in > 0) Do + Begin + CCheck(BZ2_bzCompress(FBZRec, BZ_RUN)); + If FBZRec.avail_out = 0 Then + Begin + FStrm.WriteBuffer(FBuffer, Sizeof(FBuffer)); + FBZRec.next_out := FBuffer; + FBZRec.avail_out := Sizeof(FBuffer); + FStrmPos := FStrm.Position; + End; + Progress(Self); + End; + result := Count; +End; + +Function TBZCompressionStream.Seek(Offset: LongInt; Origin: Word): LongInt; +Begin + If (Offset = 0) And (Origin = soFromCurrent) Then + result := FBZRec.total_in + Else + Raise EBZCompressionError.Create('Invalid stream operation'); +End; + +// TDecompressionStream + +Constructor TBZDecompressionStream.Create(Source: TStream); +Begin + Inherited Create(Source); + FBZRec.next_in := FBuffer; + FBZRec.avail_in := 0; + DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); +End; + +Destructor TBZDecompressionStream.Destroy; +Begin + BZ2_bzDecompressEnd(FBZRec); + Inherited Destroy; +End; + +Function TBZDecompressionStream.Read(Var Buffer; Count: LongInt): LongInt; +Begin + FBZRec.next_out := @Buffer; + FBZRec.avail_out := Count; + If FStrm.Position <> FStrmPos Then FStrm.Position := FStrmPos; + While (FBZRec.avail_out > 0) Do + Begin + If FBZRec.avail_in = 0 Then + Begin + FBZRec.avail_in := FStrm.Read(FBuffer, Sizeof(FBuffer)); + If FBZRec.avail_in = 0 Then + Begin + result := Count - FBZRec.avail_out; + exit; + End; + FBZRec.next_in := FBuffer; + FStrmPos := FStrm.Position; + End; + CCheck(BZ2_bzDecompress(FBZRec)); + Progress(Self); + End; + result := Count; +End; + +Function TBZDecompressionStream.write(Const Buffer; Count: LongInt): LongInt; +Begin + Raise EBZDecompressionError.Create('Invalid stream operation'); +End; + +Function TBZDecompressionStream.Seek(Offset: LongInt; Origin: Word): LongInt; +Begin + If (Offset >= 0) And (Origin = soFromCurrent) Then + result := FBZRec.total_out + Else + Raise EBZDecompressionError.Create('Invalid stream operation'); + +End; + +Procedure CopyStream(Src, Dst: TStream); +Const + BufSize = 4096; +Var + Buf : Array[0..BufSize - 1] Of byte; + readed : integer; +Begin + If (Src <> Nil) And (Dst <> Nil) Then + Begin + readed := Src.Read(Buf[0], BufSize); + While readed > 0 Do + Begin + Dst.write(Buf[0], readed); + readed := Src.Read(Buf[0], BufSize); + End; + End; +End; + +Procedure BZCompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent); +Var + CompressionStream: TBZCompressionStream; +Begin + CompressionStream := TBZCompressionStream.Create(OutStream); + Try + CompressionStream.OnProgress := ProgressCallback; + CopyStream(InStream, CompressionStream); + Finally + CompressionStream.free; + End; +End; + +Procedure BZDecompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent); +Var + DecompressionStream: TBZDecompressionStream; +Begin + DecompressionStream := TBZDecompressionStream.Create(InStream); + Try + DecompressionStream.OnProgress := ProgressCallback; + CopyStream(DecompressionStream, OutStream); + Finally + DecompressionStream.free; + End; +End; + +Procedure BZCompress(Const Buffer; size: integer; OutStream: TStream; + ProgressCallback: TProgressEvent); +Var + CompressionStream: TBZCompressionStream; +Begin + CompressionStream := TBZCompressionStream.Create(OutStream); + Try + CompressionStream.OnProgress := ProgressCallback; + CompressionStream.write(Buffer, size); + Finally + CompressionStream.free; + End; +End; + +// -------------------------- PowerArc specific -------------------------------- + +Const + BZIPModuleInfo: TPowerArcModuleInfo = ( + Signature: PowerArcModuleSignature; + Name: 'BZIP'; + Description: ''; + Options: #0#0; + DefaultBPC: 209; + MaxBPC: 209; + ModuleID: 'BZIP0001'; + ); + +Function BZGetPowerArcModuleInfo: PPowerArcModuleInfo; +Begin + result := @BZIPModuleInfo; +End; + +End. diff --git a/EDITOR/RadiantPro/palette_unit.pas b/EDITOR/RadiantPro/palette_unit.pas new file mode 100644 index 0000000..b1d7d4a --- /dev/null +++ b/EDITOR/RadiantPro/palette_unit.pas @@ -0,0 +1,156 @@ +unit palette_unit; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ExtCtrls, ExtDlgs, shellapi; + +type + Tpalette = class(TForm) + Bevel1: TBevel; + Label1: TLabel; + Button1: TButton; + Label2: TLabel; + Button2: TButton; + Button3: TButton; + Bevel2: TBevel; + Image1: TImage; + OPD1: TOpenPictureDialog; + CheckBox1: TCheckBox; + Panel1: TPanel; + Button4: TButton; + Button5: TButton; + SaveDialog1: TSaveDialog; + procedure FormShow(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure Button3Click(Sender: TObject); + procedure Panel1Click(Sender: TObject); + procedure CheckBox1Click(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Button4Click(Sender: TObject); + procedure Button5Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + palette: Tpalette; + +implementation +uses unit1; +{$R *.DFM} + +procedure Tpalette.FormShow(Sender: TObject); +begin +if CUSTOMPALITRE then label1.caption :='Current Brick Palette: CUSTOM' else +label1.caption :='Current Brick Palette: DEFAULT'; + +Image1.Picture.Bitmap.Assign(PaletteFile); +image1.Update; + +image1.visible := CUSTOMPALITRE; + +button1.visible := CUSTOMPALITRE; +button2.visible := not CUSTOMPALITRE; +button5.visible := CUSTOMPALITRE; +CheckBox1.visible := CUSTOMPALITRE; +Panel1.visible := CheckBox1.checked; + +end; + +procedure Tpalette.Button2Click(Sender: TObject); +begin +if not opd1.execute then exit; +PaletteFile.LoadFromFile(opd1.filename); + +PaletteStream.Clear; +PaletteStream.LoadFromFile(opd1.filename); + +if (PaletteFile.Width > 256) or + (PaletteFile.Height > 256) then begin + Showmessage('Can''t use this bitmap'+#13+'Width (Height) must me less or equal 256'); + exit; + end; + +CUSTOMPALITRE := TRUE; +form1.ImageList.Items[7].Picture.LoadFromFile(opd1.filename); +form1.ImageList.Items[7].Transparent := CheckBox1.checked; +form1.ImageList.Items[7].TransparentColor := CUSTOMPALITRETRANSPARENTCOLOR; +form1.ImageList.Items[7].restore; +CUSTOMPALITREFILENAME := opd1.filename; + +FormShow(sender); + +end; + +procedure Tpalette.Button3Click(Sender: TObject); +begin +close; +end; + +procedure Tpalette.Panel1Click(Sender: TObject); +var cdlg : TColorDialog; +begin + if not CheckBox1.checked then exit; + cdlg := TColorDialog.Create(self); + cdlg.Color := CUSTOMPALITRETRANSPARENTCOLOR; + if not cdlg.Execute then exit; + panel1.color := cdlg.Color; + + if CUSTOMPALITRE then begin + CUSTOMPALITRETRANSPARENTCOLOR := cdlg.Color; + CUSTOMPALITRETRANSPARENT := CheckBox1.checked; + form1.ImageList.Items[7].Transparent := CheckBox1.checked; + form1.ImageList.Items[7].TransparentColor := CUSTOMPALITRETRANSPARENTCOLOR; + form1.ImageList.Items[7].restore; + end; + + cdlg.free; +end; + +// assign transparent +procedure Tpalette.CheckBox1Click(Sender: TObject); +begin +panel1.visible := checkbox1.checked; + + if CUSTOMPALITRE then begin + form1.ImageList.Items[7].Transparent := CheckBox1.checked; + CUSTOMPALITRETRANSPARENT := CheckBox1.checked; + form1.ImageList.Items[7].restore; + end; +end; + +// destroy palette +procedure Tpalette.Button1Click(Sender: TObject); +begin + CUSTOMPALITRE := FALSE; + CUSTOMPALITREFILENAME := ''; + Checkbox1.checked := false; + Formshow(sender); +end; + +procedure Tpalette.Button4Click(Sender: TObject); +begin +// Загрузка help файла +showmessage('You can import you own brick pallette. '+#13#13+'Brick pallette it is a BMP file'+#13+'which contain bricks graphics.'+#13+'Please check sample_brickpalette.bmp'); +//ShellExecute(Application.Handle,'open',pchar(extractfilepath(application.exename)+'\palettes\palettehelp.htm'),nil,nil,0); +end; + +procedure Tpalette.Button5Click(Sender: TObject); +begin + if savedialog1.execute then try + image1.picture.savetofile(savedialog1.filename); + except showmessage('An error occured while exporting palette file'); end; +end; + +procedure Tpalette.FormCreate(Sender: TObject); +begin + palette.CheckBox1.checked := CUSTOMPALITRETRANSPARENT; + palette.Panel1.color := CUSTOMPALITRETRANSPARENTCOLOR; +end; + +end. diff --git a/EDITOR/map_ed/Map_ed.dpr b/EDITOR/map_ed/Map_ed.dpr new file mode 100644 index 0000000..b2f2f0e --- /dev/null +++ b/EDITOR/map_ed/Map_ed.dpr @@ -0,0 +1,24 @@ +program Map_ed; + +uses + Forms, + Unit1 in 'Unit1.pas' {Form1}, + teleport_dlg in 'teleport_dlg.pas' {Form3}, + Unit4 in 'Unit4.pas' {Form4}, + Unit5 in 'Unit5.pas' {Form5}, + Unit6 in 'Unit6.pas' {Form6}, + brshrepls in 'brshrepls.pas' {Form2_}; + +{$R *.RES} + +begin + Application.Initialize; + Application.Title := 'NFK Radiant'; + Application.CreateForm(TForm1, Form1); + Application.CreateForm(TForm3, Form3); + Application.CreateForm(TForm4, Form4); + Application.CreateForm(TForm5, Form5); + Application.CreateForm(TForm6, Form6); + Application.CreateForm(TForm2_, Form2_); + Application.Run; +end. diff --git a/EDITOR/map_ed/Unit1.pas b/EDITOR/map_ed/Unit1.pas new file mode 100644 index 0000000..728994c --- /dev/null +++ b/EDITOR/map_ed/Unit1.pas @@ -0,0 +1,2017 @@ +{ ------------------------------------------------------- + + NEED FOR KILL map editor. + for NFK v0.35. + + Created BY 3d[Power]. 2001-2002 + http://powersite.narod.ru + haz-3dpower@mail.ru + + SRC REQUIRES: + Delphi 5. + DelphiX (DelphiX2000_0717a). + + LICENSE: + You can modify or upgrade this source code only if you do it for Need For Kill. + Also u can use this source code for studies. + Any other use is not resolved. + + Короче, этот исходник написан "через жопу", в принципе как всегда :). Если кто его нормально проапгрейдит, + то вышлите мне апгрейженый исходник =). + + Народ, без вареза пожалуйста. И старайтесь не спрашивать меня что тут и как сделано, разбирайтесь сами. + +------------------------------------------------------- } + +unit Unit1; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + Grids, StdCtrls, Buttons, Menus, DXDraws, DXClass, DXInput, ComCtrls, + ImgList, ExtCtrls,shellapi; + +type + TForm1 = class(TForm) + SaveDialog: TSaveDialog; + OpenDlg: TOpenDialog; + ImageList: TDXImageList; + DXInput: TDXInput; + DXTimer1: TDXTimer; + DXDraw: TDXDraw; + PopupMenu1: TPopupMenu; + itisabrush1: TMenuItem; + MainMenu1: TMainMenu; + File1: TMenuItem; + new1: TMenuItem; + Open1: TMenuItem; + Save1: TMenuItem; + N1: TMenuItem; + Exit1: TMenuItem; + GroupBox1: TGroupBox; + SpeedButton5: TSpeedButton; + SpeedButton6: TSpeedButton; + SpeedButton7: TSpeedButton; + SpeedButton8: TSpeedButton; + ImageList1: TImageList; + Screen1: TMenuItem; + showcrosslines1: TMenuItem; + showspecialobjects1: TMenuItem; + Configure1: TMenuItem; + Mapproperities1: TMenuItem; + Operations1: TMenuItem; + Findmaperrors1: TMenuItem; + conventer1: TMenuItem; + N2: TMenuItem; + LoadoldNFKbeta025map1: TMenuItem; + Label4: TLabel; + Label5: TLabel; + SpeedButton9: TSpeedButton; + SpeedButton10: TSpeedButton; + SpeedButton11: TSpeedButton; + SpeedButton12: TSpeedButton; + Label6: TLabel; + Selectobject1: TMenuItem; + Panel1: TPanel; + Label2: TLabel; + SpeedButton1: TSpeedButton; + SpeedButton2: TSpeedButton; + Label8: TLabel; + Label3: TLabel; + SpeedButton3: TSpeedButton; + SpeedButton4: TSpeedButton; + ListView1: TListView; + N3: TMenuItem; + Help1: TMenuItem; + About1: TMenuItem; + Label1: TLabel; + Image1: TImage; + Brushreplace1: TMenuItem; + N4: TMenuItem; + Brushreplace2: TMenuItem; + NFKRadiantTutorial1: TMenuItem; + N5: TMenuItem; + Fillborder1: TMenuItem; + Startselection1: TMenuItem; + doselect_pop: TPopupMenu; + Fill1: TMenuItem; + Erase1: TMenuItem; + FlipX1: TMenuItem; + FlipY1: TMenuItem; + Copy1: TMenuItem; + N6: TMenuItem; + Cansel1: TMenuItem; + N7: TMenuItem; + Paste1: TMenuItem; + Cut1: TMenuItem; + procedure FormCreate(Sender: TObject); + procedure DXTimer1Timer(Sender: TObject; LagCount: Integer); + procedure DXDrawInitialize(Sender: TObject); + procedure PopupMenu1Popup(Sender: TObject); + procedure itisabrush1Click(Sender: TObject); + procedure FormActivate(Sender: TObject); + procedure FormDeactivate(Sender: TObject); + procedure saveclk(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure opnclk(Sender: TObject); + procedure ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); + procedure ListView1DblClick(Sender: TObject); + procedure SpeedButton3Click(Sender: TObject); + procedure SpeedButton1Click(Sender: TObject); + procedure SpeedButton2Click(Sender: TObject); + procedure SpeedButton4Click(Sender: TObject); + procedure showcrosslines1Click(Sender: TObject); + procedure showspecialobjects1Click(Sender: TObject); + procedure new1Click(Sender: TObject); + procedure Findmaperrors1Click(Sender: TObject); + procedure Mapproperities1Click(Sender: TObject); + procedure Exit1Click(Sender: TObject); + procedure LoadoldNFKbeta025map1Click(Sender: TObject); + procedure SpeedButton5Click(Sender: TObject); + procedure Selectobject1Click(Sender: TObject); + procedure ListView1KeyPress(Sender: TObject; var Key: Char); + procedure FormKeyUp(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure About1Click(Sender: TObject); + procedure Help1Click(Sender: TObject); + procedure Brushreplace1Click(Sender: TObject); + procedure Brushreplace2Click(Sender: TObject); + procedure Extractmapfromdemo1Click(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure NFKRadiantTutorial1Click(Sender: TObject); + procedure Fillborder1Click(Sender: TObject); + procedure Startselection1Click(Sender: TObject); + procedure SelectOpClick(Sender: TObject); + procedure Paste1Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +TYPE + TBrick = record + image : byte; // graphix index + +end; + +type TWaypoint = packed record + x,y:byte; + number:byte; + zone:byte; + items:longword; + flags:word; + end; + +procedure Open037map(filename : string); + +type THeader = record // header карты + ID : Array[1..4] of Char; + Version : byte; + MapName : string[70]; + Author : string[70]; + MapSizeX,MapSizeY,BG,GAMETYPE,numobj : byte; + numlights : word; + end; + +type TMAPOBJ = record // специальный объект + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,objtype,orient,nowanim,special : byte; + end; + +type TMAPOBJV2 = record // специальный объект + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,orient,nowanim,special:word; + objtype : byte; + end; + +var + Form1: TForm1; + GX, GY : integer; // позиция "камеры" + selx,sely, // выбранный брик по Х, У + selbrk, // выбранный браш из палитры брашей. + mode,alph,RRRA : integer; + bbb : array [0..254,0..254] of TBrick; // массив бриков (карта) + ddd : array[0..255] of TMAPOBJV2; // массив специальных объектов + SELECTEDOBJ : integer; // текуще выбранный спец объект + itmsel : TListItem; // для добавления свойств в список свойств спец объекта + + brCopy : array [0..254,0..254] of byte; + selbminx,selbminy , + selbmaxx,selbmaxy : word; + + + + +CONST MAXBRUSH = 254; // всего brush'ей + MAX_BUF = 2048; // буфер + BRICK_X : byte = 20; // 20 + BRICK_Y : byte = 30; // 30 + MAP_NAME : string[70] = 'test map'; + MAP_AUTHOR : string[70] = 'unnamed'; + MAP_BG : byte = 0; // задний фон карты + SHOWLINES : boolean = true; // показывать диагональные линии + SHOWOBJ : boolean = true; // показывать спец объекты + DOSELECT : boolean = false; // селекция + copysizex : byte = 0; // копирование + copysizey : byte = 0; // копирование + +procedure loadmapp (filename : string); + +implementation +uses unit2, teleport_dlg, Unit4, Unit5, Unit6, brshrepls; +{$R *.DFM} + +function ShiftKeyDown : boolean; begin result:=(Word(GetKeyState(VK_SHIFT)) and $8000)<>0; end; + +procedure TForm1.FormCreate(Sender: TObject); +var i : integer; +begin +form1.top := 0; +form1.left := 0; +form1.Width := 640; +form1.height := 480; +ImageList.Items.MakeColorTable; +selbrk := 1; +mode := 1; +alph := 255; +opendlg.initialdir := GetCurrentdir; +savedialog.InitialDir := GetCurrentdir; +for i := 0 to $ff do ddd[i].active := false; +if paramstr(1) <> '' then if fileexists(paramstr(1)) then Open037map(paramstr(1)); +// loadmapp('"'+paramstr(1)+'"'); +SELECTEDOBJ := -1; +GX := 32;GY := 32; +end; + +procedure BrushName; +begin +with form1 do + case selbrk of + 0 : label1.caption := 'Brush: none'; + 1 : label1.caption := 'Brush: shotgun'; + 2 : label1.caption := 'Brush: grenade launcher'; + 3 : label1.caption := 'Brush: rocket launcher'; + 4 : label1.caption := 'Brush: shaft'; + 5 : label1.caption := 'Brush: railgun'; + 6 : label1.caption := 'Brush: plasma'; + 7 : label1.caption := 'Brush: bfg'; + 8 : label1.caption := 'Brush: ammo for machinegun'; + 9 : label1.caption := 'Brush: ammo for shotgun'; + 10 : label1.caption := 'Brush: ammo for grenade launcher'; + 11 : label1.caption := 'Brush: ammo for rocket launcher'; + 12 : label1.caption := 'Brush: ammo for shaft'; + 13 : label1.caption := 'Brush: ammo for railgun'; + 14 : label1.caption := 'Brush: ammo for plasma'; + 15 : label1.caption := 'Brush: ammo for bfg'; + 16 : label1.caption := 'Brush: shard (+5)'; + 17 : label1.caption := 'Brush: yellow armor (+50)'; + 18 : label1.caption := 'Brush: red armor (+100)'; + 19 : label1.caption := 'Brush: health +5'; + 20 : label1.caption := 'Brush: health +25'; + 21 : label1.caption := 'Brush: health +50'; + 22 : label1.caption := 'Brush: megahealth +100'; + 23 : label1.caption := 'Brush: powerup regeneration'; + 24 : label1.caption := 'Brush: powerup battlesuit'; + 25 : label1.caption := 'Brush: powerup haste'; + 26 : label1.caption := 'Brush: powerup quaddamage'; + 27 : label1.caption := 'Brush: powerup flight'; + 28 : label1.caption := 'Brush: powerup invisibility'; + 29 : label1.caption := 'Brush: grenade launcher for trix'; + 30 : label1.caption := 'Brush: rocket launcher for trix'; + 31 : label1.caption := 'Brush: lava'; + 32 : label1.caption := 'Brush: water'; + 33 : label1.caption := 'Brush: death area. kills player.'; + 34 : label1.caption := 'Brush: respawn. neutral'; + 35 : label1.caption := 'Brush: respawn. red team'; + 36 : label1.caption := 'Brush: respawn. blu team'; + 37 : label1.caption := 'Brush: empty brick'; + 38 : label1.caption := 'Brush: jumppad'; + 39 : label1.caption := 'Brush: strong jumppad'; + 40 : label1.caption := 'Brush: red flag'; + 41 : label1.caption := 'Brush: blue flag'; + 42 : label1.caption := 'Brush: domination point'; + 43 : label1.caption := 'Brush: Soul Hunters Altar'; + 54..255 : label1.caption := 'Brush: brick'; + else label1.caption := 'Brush: unknown'; + end; +end; + +procedure Save1Click(Sender: TObject); +var i,b : byte; + s : string; + F : TFileStream; +begin +with form1 do begin +if(SaveDialog.execute) then begin +form2.showmodal; +if form2.ModalResult = mrCancel then begin showmessage('Save aborted :((('); exit; end; +if form2.mapname.text = '' then form2.mapname.text := 'noname'; +s := 'A1!'+#$FF+form2.mapname.text+#$FF+form2.desc.text+#$FF+form2.author.text+#$FF+'s1'+#$FF+'s2'+#$FF+'s3'+#$FF+'s4'+#$FF; +for i := 0 to 29 do begin +for b := 0 to 19 do begin + s := s + chr(bbb[b,i].image); + end; +end; +s := s+#$FF; +F := TFileStream.Create(savedialog.filename, fmCreate); +F.Write (s[1], Length(s)); +F.Free; +showmessage('Map "'+extractfilename(savedialog.filename)+'" saved'); +end; // SaveDialog +end; +end; + +// LOAD OLD NFKBETA025 MAP (Conventer). +procedure loadmapp (filename : string); +var tmpstr : string; + F : tfilestream; + buf : array [0..2048] of char; + i,a,stp,tx,ty : integer; +begin +stp := 0; tmpstr := ''; +tx := 0; ty := 0; +F := TFileStream.Create(filename, fmOpenRead); +F.Read (buf, MAX_BUF); // first read +for i := 0 to 250 do +for a := 0 to 250 do + bbb[i,a].image := 0; +for i := 0 to 255 do + ddd[i].active := false; +for i := 0 to MAX_BUF do begin + if stp = 10 then break; + if buf[i] = #$FF then begin inc(stp); end; + if buf[i] = #$FF then begin + if (stp = 1) then begin + tmpstr:=''; + continue; + end else + if (stp = 2) then begin + MAP_NAME := tmpstr; + tmpstr:=''; + continue; + end else + if (stp = 3) then begin + tmpstr:=''; + continue; + end else + if (stp = 4) then begin + MAP_AUTHOR := tmpstr; + tmpstr:=''; + continue; + end else + if (stp = 5) then begin + tmpstr:=''; + continue; + end else + if (stp = 6) then begin + tmpstr:=''; + continue; + end else + if (stp = 7) then begin + tmpstr:=''; + continue; + end else + if (stp = 8) then begin + tmpstr:=''; + continue; + tx := 0; ty := 0; + end else + end; + if (stp <= 7) and (i >= 3) then begin + if buf[i] <> #$FF then tmpstr := tmpstr + buf[i]; + end; + if (stp = 8) and (buf[i] <> #$FF) then begin + bbb[tx,ty].image := ord(buf[i]); + if(tx >= 19) then begin + tx := 0; + inc(ty); + end else + inc(tx); + end; +end; +BRICK_X := 20; +BRICK_Y := 30; +MAP_BG := 0; +form1.SaveDialog.filename := extractfilename(form1.OpenDlg.filename); +f.free; +end; // opendlg + + +procedure Open1Click(Sender: TObject); +begin +with form1 do begin +if(opendlg.execute) then begin + LOADMAPP (opendlg.filename); +end;end; + +end; // proc + + +procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer); +var i,a,z : byte; + xxx : TPoint; + rct : TREct; + s : string[$AA]; +begin + if not DXDraw.CanDraw then exit; + GetCursorPos(xxx); + xxx.x := xxx.x - form1.left-3; + xxx.y := xxx.y - form1.top-40; + rct := REct(0,0,181,78); + DXDraw.Surface.Fill(0); + + +if SHOWOBJ then + for i := 0 to $FF do if ddd[i].active = true then + + if ddd[i].objtype = 10 then + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, 8); + + // Draw Bricks + for i := 0 to BRICK_X-1 do begin // отрисовка кирпичей + for a := 0 to BRICK_Y-1 do begin + if bbb[i,a].image > 0 then begin + if bbb[i,a].image <= MAXBRUSH then + ImageList.Items[0].Draw(DXDraw.Surface, GX+i*32,GY+a*16, bbb[i,a].image) else + ImageList.Items[0].Draw(DXDraw.Surface, GX+i*32,GY+a*16, 0); + end; + + end; + end; + + + // Draw Map Border + with form1.DXDraw.surface.canvas do begin + Brush.Style := bsClear; + pen.color := rgb($FF,$0,$0); + Pen.Style := psSolid; + MoveTo(trunc(gx-1), trunc(gy-30)); + LineTo(trunc(gx-1), trunc(gy+16*brick_y+30)); + MoveTo(trunc(gx+32*BRICK_X+1), trunc(gy-30)); + LineTo(trunc(gx+32*BRICK_X+1), trunc(gy+16*brick_y+30)); + + MoveTo(trunc(gx-30), trunc(gy-1)); + LineTo(trunc(gx+32*BRICK_X+30), trunc(gy-1)); + + MoveTo(trunc(gx-30), trunc(gy+16*brick_y+1)); + LineTo(trunc(gx+32*BRICK_X+30), trunc(gy+16*brick_y+1)); + + + if SHOWLINES then begin + pen.color := rgb($ee,$cc,$cc); + MoveTo(trunc(gx), trunc(gy)); + LineTo(trunc(gx+32*BRICK_X), trunc(gy+16*brick_y)); + MoveTo(trunc(gx+32*BRICK_X), trunc(gy)); + LineTo(trunc(gx), trunc(gy+16*brick_y)); + end; + + release; + end; + +// ===================== +// Отрисовка спец объектов +if SHOWOBJ then begin + for i := 0 to $FF do if ddd[i].active = true then begin + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32,GY+ddd[i].y*16, ddd[i].objtype-1); + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Show Object Selection + if SELECTEDOBJ = i then begin + with form1.DXDraw.surface.canvas do begin + Brush.Style := bsClear; + pen.color := rgb($00,$FF,$FF); + Pen.Style := psDashDotDot; + + if ddd[i].objtype = 1 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY); + if ddd[i].objtype = 2 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY); + + if ddd[i].objtype = 3 then begin + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY) else + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY+16*ddd[i].lenght-16); + end; + if ddd[i].objtype = 4 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY+16*ddd[i].dir-16); + if ddd[i].objtype = 5 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY+16*ddd[i].dir-16); + if ddd[i].objtype = 6 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + if ddd[i].objtype = 7 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + if ddd[i].objtype = 8 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + if ddd[i].objtype = 9 then begin + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY) else + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY+16*ddd[i].lenght-16); + end; + if ddd[i].objtype = 10 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + release; + end; + end; + + + // ... в зависимости от типа объекта + if ddd[i].objtype = 3 then begin + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then begin + for z := 0 to ddd[i].lenght-1 do ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16, ddd[i].objtype-1); + end else + for z := 0 to ddd[i].lenght-1 do ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32,GY+ddd[i].y*16+16*z, ddd[i].objtype-1); + end; + + if ddd[i].objtype = 4 then begin + for z := 0 to ddd[i].lenght-1 do + for a := 0 to ddd[i].dir -1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 5 then begin + for z := 0 to ddd[i].lenght-1 do + for a := 0 to ddd[i].dir -1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 6 then begin + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 7 then begin + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 8 then begin + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 9 then begin // doortrigger draw + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then begin + for z := 0 to ddd[i].lenght-1 do ImageList.Items[5].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16, ddd[i].orient); + end else + for z := 0 to ddd[i].lenght-1 do ImageList.Items[5].Draw(DXDraw.Surface, GX+ddd[i].x*32,GY+ddd[i].y*16+16*z, ddd[i].orient); + end; + + with form1.DXDraw.surface.canvas do begin + // подписать спец объекты + case ddd[i].objtype of + 1 : s := 'teleport'; + 2 : s := 'button'; + 3 : s := 'door'; + 4 : s := 'trigger'; + 5 : s := 'area_push'; + 6 : s := 'area_pain'; + 7 : s := 'area_ta_end'; + 8 : s := 'area_teleport'; + 9 : s := 'doortrigger'; + 10 : s := 'area_waterillusion'; + else s := 'unknown'; + end; + s := s + '|#'+inttostr(i); + Font.Color := clYellow; + Font.Size := 8; + textout(GX+ddd[i].x*32,GY+ddd[i].y*16,s); + + // показать куда ведет телепорт если он выбран. + if (ddd[i].objtype = 1) and (SELECTEDOBJ = i) then begin + Brush.Style := bsClear; + pen.color := rgb($FF,$FF,$0); + Pen.Style := psSolid; + MoveTo(GX+ddd[i].x*32+16, GY+ddd[i].y*16+8); + LineTo(GX+ddd[i].lenght*32+16, GY+ddd[i].dir*16+8); + end; + + // показать куда ведет ареа_телепорт если он выбран. + if (ddd[i].objtype = 8) and (SELECTEDOBJ = i) then begin + Brush.Style := bsClear; + pen.color := rgb($FF,$FF,$0); + Pen.Style := psSolid; + MoveTo(GX+ddd[i].x*32+16, GY+ddd[i].y*16+8); + LineTo(GX+ddd[i].dir*32+16, GY+ddd[i].wait*16+8); + end; + + release; + end; + + end; + end; +// ===================== + + // плавная анимация палитры brush'ей + if (xxx.x < 200) and (xxx.y < 90) then begin + if alph > 3 then dec (alph,3); + mode := 2 + end + else begin + if alph < 252 then inc (alph,3); + mode :=1; + end; + + + ImageList.Items[2].DrawAlpha(DXDraw.Surface,rct, 0,alph); + + dxinput.update; + + // Отрисовать "кубик" вокруг текущего, выбранного брика. + selx := (xxx.x-GX) div 32; + sely := (xxx.y-GY) div 16; + if selx > BRICK_X-1 then selx := BRICK_X-1; + if selx < 0 then selx := 0; + if sely < 0 then sely := 0; + if sely > BRICK_Y-1 then sely := BRICK_Y-1; + ImageList.Items[3].Draw(DXDraw.Surface, GX+selx*32-2,GY+sely*16-2, 0); + + + if (isButton3 in dxinput.Mouse.States) or (DXInput.keyboard.keys[ord(27)]) then begin + GX := GX + dxinput.Mouse.X; + Gy := Gy + dxinput.Mouse.y; + end; + + // селекция. + if doselect then begin + + selbmaxx:=selx; + selbmaxy:=sely; + + if selbmaxx < selbminx then selbmaxx := selbminx; + if selx < selbminx then selx := selbminx; + if selbmaxy < selbminy then selbmaxy := selbminy; + if sely < selbminy then sely := selbminy; + + for i := selbminx to selbmaxx do + for a := selbminy to selbmaxy do + ImageList.Items[6].Draw(DXDraw.Surface, GX+i*32,GY+a*16, 0); + ImageList.Items[6].Draw(DXDraw.Surface, GX+selbminx*32,GY+selbminy*16, 2); + ImageList.Items[6].Draw(DXDraw.Surface, GX+selbmaxx*32,GY+selbmaxy*16, 1); + + if (isButton2 in dxinput.Mouse.States) or (DXInput.keyboard.keys[ord(27)]) then doselect := false; + + if isButton1 in dxinput.Mouse.States then begin + sleep(10); + doselect_pop.Popup (xxx.x,xxx.y); + sleep(10); + end; + + end; + + +// dxinput.keyboard.update; + // скроллинг карты по WSAD + if DXInput.keyboard.keys[ord(#65)] then inc (GX,6); + if DXInput.keyboard.keys[ord(#87)] then inc (GY,6); + if DXInput.keyboard.keys[ord(#68)] then dec (GX,6); + if DXInput.keyboard.keys[ord(#83)] then dec (GY,6); + if DXInput.keyboard.keys[ord(#27)] then begin gx := 0; gy := 0; end; + + if isButton1 in DXInput.keyboard.States then + begin + bbb[selx,sely].image := selbrk; + end; + + if isButton2 in DXInput.keyboard.States then + bbb[selx,sely].image := 0; + + + // скроллинг в палитре брашей + if RRRA = 0 then begin + if isLeft in DXInput.keyboard.States then begin + if isButton5 in DXInput.keyboard.States then begin + if selbrk > 10 then selbrk := selbrk - 10 else selbrk := 0; + end else + if selbrk > 0 then dec(selbrk); + RRRA := 5; + BrushName; + end; + + // скроллинг в палитре брашей + if isright in DXInput.keyboard.States then begin + if isButton5 in DXInput.keyboard.States then begin + if selbrk < MAXBRUSH then selbrk := selbrk + 10 else selbrk := MAXBRUSH; + end else + + if selbrk < MAXBRUSH then inc(selbrk); + RRRA := 5; + BrushName; + end; + end; + + // RRRA - это исключение слишком быстрого повторного нажатия кнопок. + if RRRA > 0 then dec(RRRA); + + // Отрисовать видимые браши в палитре брашей + for i := 0 to 3 do begin + if selbrk <= MAXBRUSH then + if mode = 1 then + ImageList.Items[0].Draw(DXDraw.Surface, 0+28+i*34,38, selbrk+i-3); + end; + + with DXDraw.Surface.Canvas do + begin + Brush.Style := bsClear; + font.name := 'verdana'; + font.style := [fsBold]; + Font.Color := clWhite; + Font.Size := 8; + if mode = 1 then + Textout(116, 9, inttostr(selbrk)); + Textout(5, 80, 'GX:'+inttostr(GX)); + Textout(5, 92, 'GY:'+inttostr(GY)); + Textout(5, 110, 'BRICKX:'+inttostr(selx)); + Textout(5, 122, 'BRICKY:'+inttostr(sely)); + Textout(5, 134, 'BRUSH:'+inttostr(bbb[selx,sely].image)); + + Release; { Indispensability } + end; + DXDraw.Flip; +end; + +procedure TForm1.DXDrawInitialize(Sender: TObject); +begin +DXTimer1.Enabled := True; +end; + +procedure TForm1.PopupMenu1Popup(Sender: TObject); +var i : byte; +begin +// Меню по правой кнопке мыши. +try +itisabrush1.caption := 'Select Brush: '+inttostr(bbb[selx,sely].image); +except itisabrush1.caption := 'unknown'; end; + Selectobject1.visible := false; + +if (copysizex=0) or (copysizey=0) then Paste1.visible := false else Paste1.visible := true; + + +for i := 0 to 255 do if ddd[i].active = true then begin + if (ddd[i].x = selx) and (ddd[i].y = sely) then + begin + Selectobject1.visible := true; + Selectobject1.caption := 'Select object #'+inttostr(i); + break; + end; + end; + +end; + +procedure TForm1.itisabrush1Click(Sender: TObject); +begin +try +selbrk := bbb[selx,sely].image; +except exit; end; +end; + +procedure TForm1.FormActivate(Sender: TObject); +begin +dxdraw.initialize; +dxtimer1.enabled := true; +end; + +procedure TForm1.FormDeactivate(Sender: TObject); +begin +dxdraw.finalize; +dxtimer1.enabled := false; +end; + + +procedure TForm1.saveclk(Sender: TObject); +var F : File; + i,a : Integer; + Header : THeader; + buf : array [0..$FE] of byte; +begin + // Сохранение карте в формате nfkbeta031 + if extractfilepath(SaveDialog.initialdir) <> '' then SaveDialog.initialdir := extractfilepath(SaveDialog.filename); + +if not (SaveDialog.execute) then exit; + AssignFile(F, SaveDialog.filename); + Rewrite(F,1); + header.ID := 'NMAP'; + header.Version := 3; + header.Author := MAP_AUTHOR; + header.mapname := MAP_NAME; + header.BG := MAP_BG; + header.MapSizeX := BRICK_X; + header.MapSizeY := BRICK_Y; + header.GAMETYPE := 0; + a:= 0; + for i := 0 to $FF do if ddd[i].active = true then inc(a); + header.numobj := a; + header.numlights := 0; + header.GAMETYPE := 0; + BlockWrite(F, Header, Sizeof(Header)); + for a := 0 to BRICK_Y-1 do begin + for i := 0 to BRICK_X do buf[i]:= bbb[i,a].image ; + BlockWrite(F, buf, BRICK_X); + end; + for i := 0 to $FF do + if ddd[i].active = true then + blockwrite(f,ddd[i],sizeof(ddd[i])); + CloseFile(F); +end; + +procedure Loadv031map(filename:string); +var tempobj : TMapOBJ; + f : file; + header : THeader; + i,a,z : word; + buf : array [0..$FE] of byte; + +begin + if not fileexists(filename) then begin showmessage(filename+' not found.');exit; end; + AssignFile(F, filename); + Reset(F,1); + BlockRead(F, Header, Sizeof(Header)); + if (header.ID <> 'NMAP') and (header.ID <> 'NDEM') then begin + closefile(f); + showmessage(filename + ' is not NFK map'); + exit; + end; + if (header.Version >= 3) then begin + closefile(F); + showmessage('incorrect map version ('+inttostr(header.version)+'). Im can load only earlier map.'); + exit; + end; + + form1.savedialog.FileName := filename; + form1.savedialog.InitialDir := extractfilepath(filename); + + + for i := 0 to 255 do + ddd[i].active := false; + MAP_AUTHOR := header.Author; + MAP_NAME := header.MapName ; + MAP_BG := header.BG; + BRICK_X := header.MapSizeX ; + BRICK_Y := header.MapSizeY; + for a := 0 to header.MapSizeY - 1 do begin + blockread(f,buf,header.MapSizeX); + for z := 0 to header.MapSizeX - 1 do begin + // convert it here! + bbb[z,a].image := buf[z]; + if buf[z]=9 then bbb[z,a].image := 8; + if buf[z]=10 then bbb[z,a].image := 9; + if buf[z]=11 then bbb[z,a].image := 10; + if buf[z]=12 then bbb[z,a].image := 11; + if buf[z]=13 then bbb[z,a].image := 12; + if buf[z]=14 then bbb[z,a].image := 13; + if buf[z]=15 then bbb[z,a].image := 14; + if buf[z]=16 then bbb[z,a].image := 15; + if buf[z]=17 then bbb[z,a].image := 16; + if buf[z]=18 then bbb[z,a].image := 17; + if buf[z]=19 then bbb[z,a].image := 18; + if buf[z]=20 then bbb[z,a].image := 20; + if buf[z]=21 then bbb[z,a].image := 21; + if buf[z]=22 then bbb[z,a].image := 22; + if buf[z]=23 then bbb[z,a].image := 19; + if buf[z]=24 then bbb[z,a].image := 23; + if buf[z]=25 then bbb[z,a].image := 24; + if buf[z]=26 then bbb[z,a].image := 25; + if buf[z]=27 then bbb[z,a].image := 26; + if buf[z]=8 then bbb[z,a].image := 27; + if buf[z]=28 then bbb[z,a].image := 29; + if buf[z]=29 then bbb[z,a].image := 30; + if buf[z]=30 then bbb[z,a].image := 37; + if buf[z]=31 then bbb[z,a].image := 39; + if buf[z]=32 then bbb[z,a].image := 33; + if buf[z]=33 then bbb[z,a].image := 38; + if buf[z]=34 then bbb[z,a].image := 31; + if buf[z]=35 then bbb[z,a].image := 34; + if buf[z]>=36 then bbb[z,a].image := 54 + buf[z]- 36; + end; + end; + + if header.numobj > 0 then + for a := 0 to header.numobj-1 do begin + blockread(f,tempobj,sizeof(tempobj)); + ddd[a].active := tempobj.active; + ddd[a].x := tempobj.x; + ddd[a].y := tempobj.y; + ddd[a].lenght := tempobj.lenght; + ddd[a].dir := tempobj.dir; + ddd[a].wait := tempobj.wait; + ddd[a].targetname := tempobj.targetname; + ddd[a].target := tempobj.target; + ddd[a].orient := tempobj.orient; + ddd[a].nowanim := tempobj.nowanim; + ddd[a].special:= tempobj.special; + ddd[a].objtype := tempobj.objtype; + end; + CloseFile(F); + +end; + + +procedure Open037map(filename : string); +var F : File; + i,a,z : Integer; + Header : THeader; + buf : array [0..$FE] of byte; +begin + + Form1.listview1.Items.Clear; + AssignFile(F, filename); + Reset(F,1); + BlockRead(F, Header, Sizeof(Header)); + if (header.ID <> 'NMAP') and (header.ID <> 'NDEM') then begin + closefile(f); + showmessage(filename + ' is not NFK map'); + exit; + end; + if (header.Version <> 3) then begin + closefile(F); + showmessage('incorrect map version ('+inttostr(header.version)+'). Only version 3 supported.'); + exit; + end; + + for i := 0 to 255 do + ddd[i].active := false; + form1.SaveDialog.filename := extractfilename(filename); + MAP_AUTHOR := header.Author; + MAP_NAME := header.MapName ; + MAP_BG := header.BG; + BRICK_X := header.MapSizeX ; + BRICK_Y := header.MapSizeY; + for a := 0 to header.MapSizeY - 1 do begin + blockread(f,buf,header.MapSizeX); + for z := 0 to header.MapSizeX - 1 do + bbb[z,a].image := buf[z]; + end; + for a := 0 to header.numobj-1 do + blockread(f,ddd[a],sizeof(ddd[a])); + CloseFile(F); +end; + +procedure TForm1.opnclk(Sender: TObject); +var F : File; + i,a,z : Integer; + Header : THeader; + buf : array [0..$FE] of byte; +begin + // Открытие карты nfkbeta030 или nfkbeta031. + if opendlg.filter = 'extractor' then opendlg.filter := 'Nfk demo (*.ndm)|*.ndm' else + opendlg.filter := 'Nfk maps (*.mapa)|*.mapa'; + if extractfilepath(opendlg.filename) <> '' then begin + opendlg.initialdir := extractfilepath(opendlg.filename); + savedialog.initialdir := extractfilepath(opendlg.filename); + end; +if not (opendlg.execute) then exit; + + Open037map( opendlg.filename); + +end; + + +procedure TForm1.FormResize(Sender: TObject); +begin +// Изменение размеров +form1.dxdraw.width := form1.width - 170; +form1.dxdraw.height := form1.height - 60; +groupbox1.left := form1.width - 165; +image1.left := form1.width - 135; +image1.top := 490; +panel1.left := form1.width - 165; +end; + + +procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); +begin +if item = nil then exit; +label2.caption := item.Caption; +itmsel := item; +end; + +procedure TForm1.ListView1DblClick(Sender: TObject); +// Редактирование свойств в списке спец объектов. +var n,s : string; +nn : integer; +begin +//showmessage(itmsel.Caption); +if ddd[SELECTEDOBJ].objtype = 1 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='goto_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='goto_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='goto_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='goto_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + +end; +if ddd[SELECTEDOBJ].objtype = 2 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='color' then s := 'value(0-5). (0=grn;1=red;2=blu;3=aqua;4=fuch;5=olive)'; + if itmsel.Caption ='shootable' then s := 'value(0-1). (0=no, 1=yes)'; + if itmsel.Caption ='wait' then s := 'value(10-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate. 0=no target.'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='color' then if (nn < 0) or (nn > 5) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='shootable' then if (nn < 0) or (nn > 1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 10) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + +end; + +if ddd[SELECTEDOBJ].objtype = 3 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='orientation' then begin s := 'value(0-3).'; + showmessage('value:'+#13+'0=closed, horizontal'+#13+'1=closed, vertical'+#13+'2=opened, horizontal'+#13+'3=opened, vertical'); + end; + if itmsel.Caption ='wait' then s := 'value(10-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='targetname' then s := 'value(0-255). targetname to be activated, 0=no targetname.'; + if itmsel.Caption ='lenght' then s := 'value(1-255). door lenght (bricks)'; + if itmsel.Caption ='fastclose' then s := 'value(0-1). 0=no. 1=yes'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='orientation' then if (nn < 0) or (nn > 3) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 10) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='targetname' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].targetname := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='fastclose' then if (nn < 0) or (nn > 1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; +end; + +if ddd[SELECTEDOBJ].objtype = 4 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='wait' then s := 'value(1-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate, 0=no target.'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 1) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 5 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='wait' then s := 'value(1-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate, 0=no target.'; + if itmsel.Caption ='pushspeed' then s := 'value(10-70). 10=very slow; 70=very fast.'; + if itmsel.Caption ='direction' then begin + showmessage('value:'+#13+'0=push left'+#13+'1=push up'+#13+'2=push right'+#13+'3=push down'); + s := 'value(0-3).'; + end; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='direction' then if (nn < 0) or (nn > 3) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 1) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pushspeed' then if (nn < 10) or (nn > 70) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; +end; + +if ddd[SELECTEDOBJ].objtype = 6 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='dmginterval' then s := 'value(1-255). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='wait' then s := 'value(1-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='targetname' then s := 'value(0-255). targetname to be actvtd, 0=no need to actvtd.'; + if itmsel.Caption ='dmg' then s := 'value(1-500). Makes the specified damage.'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='targetname' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].targetname := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='dmg' then if (nn < 1) or (nn > 500) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='dmginterval' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].nowanim := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 1) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 7 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 8 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='goto_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='goto_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + + if itmsel.Caption ='goto_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='goto_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 9 then begin // DOOR TRIGGED, Property edit. + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='orientation' then begin s := 'value(0-3).'; + showmessage('value:'+#13+'0=up'+#13+'1=left'+#13+'2=down'+#13+'3=right'); + end; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate, 0=no target'; + if itmsel.Caption ='lenght' then s := 'value(1-255). door lenght (bricks)'; + if itmsel.Caption ='fastclose' then s := 'value(0-1). 0=no. 1=yes'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='orientation' then if (nn < 0) or (nn > 3) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 10 then begin // AREA_WATERILLUSION, Property edit. + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-4).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-4).'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > 4) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > 4) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; +end; + +end; + + +procedure addprop (st1, st2 : string); +var item : TListItem; +begin +item := form1.listview1.items.add; +item.caption := st1; +item.SubItems.Add(st2); +end; + + +procedure ADDobjPROP(nn:integer;n : string); +begin +// Добавление свойств объекта в список свойств. +with Form1 do begin + +if ddd[nn].objtype = 1 then begin +label3.caption := 'TELEPORT | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('goto_x',inttostr(ddd[nn].lenght)); +addprop('goto_y',inttostr(ddd[nn].dir)); +end; + +if ddd[nn].objtype = 2 then begin +label3.caption := 'BUTTON | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('color',inttostr(ddd[nn].orient)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('target',inttostr(ddd[nn].target)); +addprop('shootable',inttostr(ddd[nn].special)); +end; + +if ddd[nn].objtype = 3 then begin +label3.caption := 'DOOR | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('orientation',inttostr(ddd[nn].orient)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('fastclose',inttostr(ddd[nn].special)); +addprop('targetname',inttostr(ddd[nn].targetname)); +addprop('lenght',inttostr(ddd[nn].lenght)); +end; + +if ddd[nn].objtype = 4 then begin +label3.caption := 'TRIGGER | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].lenght)); +addprop('lenght_y',inttostr(ddd[nn].dir)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('target',inttostr(ddd[nn].target)); +end; +if ddd[nn].objtype = 5 then begin +label3.caption := 'AREA_PUSH | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].lenght)); +addprop('lenght_y',inttostr(ddd[nn].dir)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('target',inttostr(ddd[nn].target)); +addprop('direction',inttostr(ddd[nn].orient)); +addprop('pushspeed',inttostr(ddd[nn].special)); +end; +if ddd[nn].objtype = 6 then begin +label3.caption := 'AREA_PAIN | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +addprop('dmginterval',inttostr(ddd[nn].nowanim)); +addprop('wait',inttostr(ddd[nn].lenght)); +addprop('targetname',inttostr(ddd[nn].targetname)); +addprop('dmg',inttostr(ddd[nn].dir)); +end; +if ddd[nn].objtype = 7 then begin +label3.caption := 'AREA_TA_END | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +end; +if ddd[nn].objtype = 8 then begin +label3.caption := 'AREA_TELEPORT | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +addprop('goto_x',inttostr(ddd[nn].dir)); +addprop('goto_y',inttostr(ddd[nn].wait)); +end; +if ddd[nn].objtype = 9 then begin +label3.caption := 'DOORTRIGGER | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('orientation',inttostr(ddd[nn].orient)); +addprop('target',inttostr(ddd[nn].target)); +addprop('lenght',inttostr(ddd[nn].lenght)); +end; +if ddd[nn].objtype = 10 then begin +label3.caption := 'AREA_WATERILLUSION | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +end; + +end; +end; + +procedure TForm1.SpeedButton3Click(Sender: TObject); +var +n : string; +nn : integer; +begin +showspecialobjects1.Checked := true; +SHOWOBJ := true; +form4.showmodal; +if SELECTEDOBJ < 0 then exit; +listview1.Items.Clear; +speedbutton1.enabled := true; +speedbutton2.enabled := true; +speedbutton3.enabled := false; +speedbutton4.enabled := false; +listview1.enabled := true; +nn := SELECTEDOBJ; +n := inttostr(nn); +AddOBJPROP(NN,n); +end; + +procedure TForm1.SpeedButton1Click(Sender: TObject); +begin +// Нажали на кнопку APPLY. Убирам редактирование текущего, выбранного объекта +if SELECTEDOBJ < 0 then begin + showmessage('no special object selected.'); + exit; + end; + +SELECTEDOBJ := -1; +listview1.Items.Clear; +label3.caption := 'not selected'; +label2.caption := ''; +speedbutton1.enabled := false; +speedbutton2.enabled := false; +speedbutton3.enabled := true; +speedbutton4.enabled := true; +listview1.enabled := false; +end; + +procedure TForm1.SpeedButton2Click(Sender: TObject); +// Удаление объекта +begin +if SELECTEDOBJ < 0 then begin + showmessage('no special object selected.'); + exit; + end; +case MessageDlg ('delete object #'+inttostr(SELECTEDOBJ)+' ?', mtConfirmation, [mbYes,mbNo], 0) of +IDNO : exit; +end; +ddd[SELECTEDOBJ].active := false; +SELECTEDOBJ := -1; +listview1.Items.Clear; +label3.caption := 'not selected'; +label2.caption := ''; +speedbutton1.enabled := false; +speedbutton2.enabled := false; +speedbutton3.enabled := true; +speedbutton4.enabled := true; +listview1.enabled := false; +end; + +procedure TForm1.SpeedButton4Click(Sender: TObject); +var i : byte; +begin + // Добавление нового спец объекта + + if SELECTEDOBJ >= 0 then begin + showmessage('finish editing current object'); + exit; + end; + + form3.showmodal; + if form3.ModalResult = mrOK then begin // add new obj + for i := 0 to $FF do if ddd[i].active = false then begin + if form3.RadioButton1.checked then begin // tele + ddd[i].active := true; + ddd[i].objtype := 1; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].lenght := 0; // goto_x + ddd[i].dir := 0; // goto_y + showmessage('teleport created at 0:0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton2.checked then begin // btn + ddd[i].active := true; + ddd[i].objtype := 2; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].target := 0; // target + ddd[i].wait := 100; // wait time; + ddd[i].orient := 0; // color + ddd[i].special := 0; // shoot + showmessage('button created at 0:0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton3.checked then begin // door + ddd[i].active := true; + ddd[i].objtype := 3; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].targetname := 0; // targetname + ddd[i].special := 0; // fastclose; + ddd[i].wait := 100; // wait time; + ddd[i].orient := 0; // orientation + ddd[i].lenght := 1; // door brick lenght + showmessage('door created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton4.checked then begin // trigger + ddd[i].active := true; + ddd[i].objtype := 4; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].target := 0; // target + ddd[i].lenght := 2; // lenght_x + ddd[i].dir := 2; // lenght_y + ddd[i].wait := 10; // retoggle time; + showmessage('trigger created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton5.checked then begin // area_push + ddd[i].active := true; + ddd[i].objtype := 5; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].target := 0; // target + ddd[i].lenght := 2; // lenght_x + ddd[i].dir := 2; // lenght_y + ddd[i].wait := 10; // retoggle time; + ddd[i].orient := 0; // push direction + ddd[i].special := 30; // push speed; + showmessage('area_push created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton6.checked then begin // area_dmg + ddd[i].active := true; + ddd[i].objtype := 6; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].targetname := 0; // targetname + ddd[i].special := 2; // lenght_x + ddd[i].orient := 2; // lenght_y + ddd[i].nowanim := 10; // DMGINTERVAL; + ddd[i].dir := 10; // DMG + ddd[i].lenght := 50; // wait. if targetname > 0 + showmessage('area_pain created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton7.checked then begin // area_dmg + ddd[i].active := true; + ddd[i].objtype := 7; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].special := 2; // lenght_x + ddd[i].orient := 2; // lenght_y + showmessage('area_trickarena_end created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton8.checked then begin // area_teleport + ddd[i].active := true; + ddd[i].objtype := 8; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].special := 2; // lenght_x + ddd[i].orient := 2; // lenght_y + ddd[i].dir := 0; // goto_x + ddd[i].wait := 0; // goto_y + showmessage('area_teleport created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton9.checked then begin // area_teleport + ddd[i].active := true; + ddd[i].objtype := 9; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].wait := 5; // wait time; + ddd[i].orient := 0; // orientation + ddd[i].lenght := 1; // doortrigger brick lenght + showmessage('doortrigger created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton10.checked then begin // area_waterillusion + ddd[i].active := true; + ddd[i].objtype := 10; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].special := 1; // lenght_x + ddd[i].orient := 1; // lenght_y + showmessage('area_waterillusion created at x0y0. with #'+inttostr(i)); + exit; + end; + + end; + end; +end; + +procedure TForm1.showcrosslines1Click(Sender: TObject); +begin +// диагональные линии +showcrosslines1.Checked := not showcrosslines1.Checked; +SHOWLINES := showcrosslines1.Checked; +end; + +procedure TForm1.showspecialobjects1Click(Sender: TObject); +begin +// [не]показывать спец объекты +showspecialobjects1.Checked := not showspecialobjects1.Checked; +SHOWOBJ := showspecialobjects1.Checked; +end; + +procedure TForm1.new1Click(Sender: TObject); +var i, a : word; +// Новая карта, удаление прежней информации. +begin + case MessageDlg ('Discard all map information?', mtConfirmation, [mbYes,mbNo], 0) of + IDNO : exit; + end; +listview1.Items.Clear; + +for i := 0 to 250 do +for a := 0 to 250 do + bbb[i,a].image := 0; +for i := 0 to 255 do + ddd[i].active := false; +BRICK_X := 20; +BRICK_Y := 30; +MAP_NAME := 'test map'; +MAP_AUTHOR := 'unnamed'; +SaveDialog.filename := 'unnamed.mapa'; +MAP_BG := 0; +SHOWLINES := true; +SHOWOBJ := true; +form5.showmodal; +end; + +procedure TForm1.Findmaperrors1Click(Sender: TObject); +begin + form6.showmodal; +end; + +procedure TForm1.Mapproperities1Click(Sender: TObject); +begin +form5.showmodal; +end; + +procedure TForm1.Exit1Click(Sender: TObject); +begin +close; +end; + +procedure TForm1.LoadoldNFKbeta025map1Click(Sender: TObject); +begin +// конвентер 025 карт. + opendlg.filter := 'Old nfk maps (*.mapa)|*.mapa'; + if extractfilepath(opendlg.filename) <> '' then opendlg.initialdir := extractfilepath(opendlg.filename); +if not (opendlg.execute) then exit; +listview1.Items.Clear; +// загрузка старой карты + Loadv031map(opendlg.FileName); +end; + +procedure TForm1.SpeedButton5Click(Sender: TObject); +begin +// Навигация +with sender as TSpeedButton do + case tag of + 1 : inc(gy,32); + 2 : inc(gx,32); + 3 : dec(gy,32); + 4 : dec(gx,32); + 5 : if selbrk > 0 then dec(selbrk); + 6 : if selbrk < MAXBRUSH then inc(selbrk); + 7 : if selbrk > 10 then selbrk := selbrk - 10 else selbrk := 0; + 8 : if selbrk < MAXBRUSH then selbrk := selbrk + 10 else selbrk := MAXBRUSH; + end; + BrushName; +end; + +procedure TForm1.Selectobject1Click(Sender: TObject); +var i,nn : byte; + n : string; +begin +// Выбор спец объекта +if selectedobj >= 0 then begin + showmessage('some object already selected'); + exit; + end; +for i := 0 to 255 do if ddd[i].active = true then + if (ddd[i].x = selx) and (ddd[i].y = sely) then + begin + SELECTEDOBJ := i; +listview1.Items.Clear; +speedbutton1.enabled := true; +speedbutton2.enabled := true; +speedbutton3.enabled := false; +speedbutton4.enabled := false; +listview1.enabled := true; +nn := SELECTEDOBJ; +n := inttostr(nn); + +AddOBJPROP(NN,n); + + break; + end; +end; + +procedure TForm1.ListView1KeyPress(Sender: TObject; var Key: Char); +begin +if key=#13 then ListView1DblClick(sender); +end; + +procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; + Shift: TShiftState); + var i,a : byte; +begin +// Рандомный генератор карт :))) +if (key=VK_F12) and (ShiftKeyDown) then begin + randomize; + for i := 0 to BRICK_X-1 do + for a := 0 to BRICK_y-1 do + if random(5) = 0 then + bbb[i,a].image := 36 else bbb[i,a].image := 0; + end; +end; + +procedure TForm1.About1Click(Sender: TObject); +begin +showmessage(form1.caption+#13+'created by 3d[Power]'+#13+'several upgrades by [LD]:Surgeon'+#13#13+'http://powersite.narod.ru'); +end; + +procedure TForm1.Help1Click(Sender: TObject); +begin +// Загрузка help файла +ShellExecute(Application.Handle,'open',pchar(extractfilepath(application.exename)+'\radiant_help.htm'),nil,nil,0); +end; + +procedure TForm1.Brushreplace1Click(Sender: TObject); +begin +form2_.showmodal; +end; + +procedure TForm1.Brushreplace2Click(Sender: TObject); +begin +form2_.SpinEdit1.value := bbb[selx,sely].image; +form2_.showmodal; +end; + +procedure TForm1.Extractmapfromdemo1Click(Sender: TObject); +begin +opendlg.filter := 'extractor'; +opnclk(sender); +end; + + +procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin +case MessageDlg ('quit?'+#13+'dont forget to save map', mtConfirmation, [mbYes,mbCancel], 0) of + mrCancel : canclose := false; +end; +end; + +procedure TForm1.NFKRadiantTutorial1Click(Sender: TObject); +begin +// Загрузка help файла +ShellExecute(Application.Handle,'open',pchar(extractfilepath(application.exename)+'\rocky_tutorial\help.htm'),nil,nil,0); + +end; + +// border filler. +procedure TForm1.Fillborder1Click(Sender: TObject); +var i: word; +begin + IF selbrk < 54 then selbrk := 54; + + for i := 0 to BRICK_X-1 do begin + bbb[i,0].image := selbrk; + bbb[i,BRICK_Y-1].image := selbrk; + end; + for i := 0 to BRICK_Y-1 do begin + bbb[0,I].image := selbrk; + bbb[BRICK_X-1,i].image := selbrk; + end; + +END; + +procedure TForm1.Startselection1Click(Sender: TObject); +begin + if not doselect then begin + doselect := true; + selbminx := selx; + selbminy := sely; + selbmaxx := selx; + selbmaxy := sely; + end; +end; + +// selection orepations +procedure TForm1.SelectOpClick(Sender: TObject); +var i,a:word; + t:byte; + + procedure local_copy; + var i,a:word; + begin + copysizex := selbmaxx - selbminx+1; + copysizey := selbmaxy - selbminy+1; + for i := 0 to copysizex-1 do + for a := 0 to copysizey-1 do + brCopy[i,a] := bbb[selbminx+i,selbminy+a].image; + end; + + procedure local_eraze; + var i,a:word; + begin + for i := selbminx to selbmaxx do for a := selbminy to selbmaxy do bbb[i,a].image := 0; // erase + end; + +begin + doselect:=false; + with sender as TMenuitem do + case tag of + 1: for i := selbminx to selbmaxx do for a := selbminy to selbmaxy do bbb[i,a].image := selbrk; // fill + 2: local_eraze; + 3: for i := selbminx to (selbminx + (selbmaxx - selbminx) div 2) do // flip_x + for a := selbminy to selbmaxy do begin + t := bbb[i,a].image; + bbb[i,a].image := bbb[selbminx+selbmaxx-i,a].image; + bbb[selbminx+selbmaxx-i,a].image := t; + end; + 4: for a := selbminy to (selbminy + (selbmaxy - selbminy) div 2) do // flip_y + for i := selbminx to selbmaxx do begin + t := bbb[i,a].image; + bbb[i,a].image := bbb[i,selbminy+selbmaxy-a].image; + bbb[i,selbminy+selbmaxy-a].image := t; + end; + 5: local_copy; // copy + 6: begin // cut. + local_copy; + local_eraze; + end; + + end; +end; + +procedure TForm1.Paste1Click(Sender: TObject); +var i,a:word; +begin +// showmessage(inttostr(copysizex)); + if (copysizex=0) or (copysizey=0) then exit; + for i:= 0 to copysizex-1 do + for a:= 0 to copysizey-1 do + bbb[selx+i,sely+a].image := brCopy[i,a]; + +end; + +end. + diff --git a/EDITOR/radiant040/Map_ed.dpr b/EDITOR/radiant040/Map_ed.dpr new file mode 100644 index 0000000..8de8a78 --- /dev/null +++ b/EDITOR/radiant040/Map_ed.dpr @@ -0,0 +1,30 @@ +program Map_ed; + +uses + Forms, + Unit1 in 'Unit1.pas' {Form1}, + teleport_dlg in 'teleport_dlg.pas' {Form3}, + Unit4 in 'Unit4.pas' {Form4}, + Unit5 in 'Unit5.pas' {Form5}, + Unit6 in 'Unit6.pas' {Form6}, + brshrepls in 'brshrepls.pas' {Form2_}, + bzLib in 'bz\bzLib.pas', + PowerAcrModuleInfo in 'bz\PowerAcrModuleInfo.pas', + PowerArc in 'bz\PowerArc.pas', + palette_unit in 'palette_unit.pas' {palette}, + Unit2_locsel in 'Unit2_locsel.pas' {loc_sel}; + +{$R *.RES} + +begin + Application.Initialize; + Application.Title := 'NFK Radiant'; + Application.CreateForm(TForm1, Form1); + Application.CreateForm(TForm3, Form3); + Application.CreateForm(TForm4, Form4); + Application.CreateForm(TForm5, Form5); + Application.CreateForm(TForm6, Form6); + Application.CreateForm(TForm2_, Form2_); + Application.CreateForm(Tpalette, palette); + Application.Run; +end. diff --git a/EDITOR/radiant040/Unit1.pas b/EDITOR/radiant040/Unit1.pas new file mode 100644 index 0000000..df58a9f --- /dev/null +++ b/EDITOR/radiant040/Unit1.pas @@ -0,0 +1,2451 @@ +{ ------------------------------------------------------- + + NEED FOR KILL map editor. + for NFK v0.37. + + Created BY 3d[Power]. 2001-2002 + http://powersite.narod.ru + haz-3dpower@mail.ru + + SRC REQUIRES: + Delphi 5. + DelphiX (DelphiX2000_0717a). + + LICENSE: + You can modify or upgrade this source code only if you do it for Need For Kill. + Also u can use this source code for studies. + Any other use is not resolved. + + Народ, без вареза пожалуйста. И старайтесь не спрашивать меня что тут и как сделано, разбирайтесь сами. + +------------------------------------------------------- } + +unit Unit1; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + Grids, StdCtrls, Buttons, Menus, DXDraws, DXClass, DXInput, ComCtrls, + ImgList, ExtCtrls,shellapi, bzlib, PowerTiming; + +type + TForm1 = class(TForm) + SaveDialog: TSaveDialog; + OpenDlg: TOpenDialog; + ImageList: TDXImageList; + DXInput: TDXInput; + DXDraw: TDXDraw; + PopupMenu1: TPopupMenu; + itisabrush1: TMenuItem; + MainMenu1: TMainMenu; + File1: TMenuItem; + new1: TMenuItem; + Open1: TMenuItem; + Save1: TMenuItem; + N1: TMenuItem; + Exit1: TMenuItem; + GroupBox1: TGroupBox; + SpeedButton5: TSpeedButton; + SpeedButton6: TSpeedButton; + SpeedButton7: TSpeedButton; + SpeedButton8: TSpeedButton; + ImageList1: TImageList; + Screen1: TMenuItem; + Showcrosslines1: TMenuItem; + showspecialobjects1: TMenuItem; + Configure1: TMenuItem; + Mapproperities1: TMenuItem; + Operations1: TMenuItem; + Findmaperrors1: TMenuItem; + conventer1: TMenuItem; + N2: TMenuItem; + LoadoldNFKbeta025map1: TMenuItem; + Label4: TLabel; + Label5: TLabel; + SpeedButton9: TSpeedButton; + SpeedButton10: TSpeedButton; + SpeedButton11: TSpeedButton; + SpeedButton12: TSpeedButton; + Label6: TLabel; + Selectobject1: TMenuItem; + N3: TMenuItem; + Help1: TMenuItem; + About1: TMenuItem; + Label1: TLabel; + Image1: TImage; + Brushreplace1: TMenuItem; + N4: TMenuItem; + Brushreplace2: TMenuItem; + NFKRadiantTutorial1: TMenuItem; + N5: TMenuItem; + Fillborder1: TMenuItem; + Startselection1: TMenuItem; + doselect_pop: TPopupMenu; + Fill1: TMenuItem; + Erase1: TMenuItem; + FlipX1: TMenuItem; + FlipY1: TMenuItem; + Copy1: TMenuItem; + N6: TMenuItem; + Cansel1: TMenuItem; + N7: TMenuItem; + Paste1: TMenuItem; + Buildnewbrickpalette1: TMenuItem; + Cut1: TMenuItem; + Showallteleportlinks1: TMenuItem; + PageControl1: TPageControl; + TabSheet1: TTabSheet; + TabSheet2: TTabSheet; + SpeedButton4: TSpeedButton; + SpeedButton2: TSpeedButton; + SpeedButton3: TSpeedButton; + SpeedButton1: TSpeedButton; + ListView1: TListView; + Label2: TLabel; + Label3: TLabel; + Label8: TLabel; + Label7: TLabel; + ListView2: TListView; + SpeedButton13: TSpeedButton; + SpeedButton14: TSpeedButton; + SpeedButton15: TSpeedButton; + SpeedButton16: TSpeedButton; + selectloc: TMenuItem; + Showloc1: TMenuItem; + TestLocations1: TMenuItem; + DXTimer1: TPowerTimer; + procedure FormCreate(Sender: TObject); + procedure DXTimer1Timer(Sender: TObject); + procedure DXDrawInitialize(Sender: TObject); + procedure PopupMenu1Popup(Sender: TObject); + procedure itisabrush1Click(Sender: TObject); + procedure FormActivate(Sender: TObject); + procedure FormDeactivate(Sender: TObject); + procedure saveclk(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure opnclk(Sender: TObject); + procedure ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); + procedure ListView1DblClick(Sender: TObject); + procedure SpeedButton3Click(Sender: TObject); + procedure SpeedButton1Click(Sender: TObject); + procedure SpeedButton2Click(Sender: TObject); + procedure SpeedButton4Click(Sender: TObject); + procedure Showcrosslines1Click(Sender: TObject); + procedure showspecialobjects1Click(Sender: TObject); + procedure new1Click(Sender: TObject); + procedure Findmaperrors1Click(Sender: TObject); + procedure Mapproperities1Click(Sender: TObject); + procedure Exit1Click(Sender: TObject); + procedure LoadoldNFKbeta025map1Click(Sender: TObject); + procedure SpeedButton5Click(Sender: TObject); + procedure Selectobject1Click(Sender: TObject); + procedure ListView1KeyPress(Sender: TObject; var Key: Char); + procedure FormKeyUp(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure About1Click(Sender: TObject); + procedure Help1Click(Sender: TObject); + procedure Brushreplace1Click(Sender: TObject); + procedure Brushreplace2Click(Sender: TObject); + procedure Extractmapfromdemo1Click(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure NFKRadiantTutorial1Click(Sender: TObject); + procedure Fillborder1Click(Sender: TObject); + procedure Startselection1Click(Sender: TObject); + procedure SelectOpClick(Sender: TObject); + procedure Paste1Click(Sender: TObject); + procedure Buildnewbrickpalette1Click(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure Showallteleportlinks1Click(Sender: TObject); + procedure SpeedButton16Click(Sender: TObject); + procedure ListView2DblClick(Sender: TObject); + procedure SpeedButton13Click(Sender: TObject); + procedure SpeedButton14Click(Sender: TObject); + procedure SpeedButton15Click(Sender: TObject); + procedure selectlocClick(Sender: TObject); + procedure Showloc1Click(Sender: TObject); + procedure TestLocations1Click(Sender: TObject); + procedure ListView2KeyPress(Sender: TObject; var Key: Char); + procedure PageControl1Change(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +TYPE + TBrick = record + image : byte; // graphix index + +end; + +type TWaypoint = packed record + x,y:byte; + number:byte; + zone:byte; + items:longword; + flags:word; + end; + +type TMapEntry = packed record + EntryType : string[3]; + DataSize : longint; + Reserved1 : byte; + Reserved2 : word; + Reserved3 : integer; + Reserved4 : longint; + Reserved5 : cardinal; + Reserved6 : boolean; + end; + +Type TLocationText = Packed Record + Enabled : boolean; + X, Y : byte; + Text : String [64]; +end; + +procedure Open037map(filename : string); + +type THeader = record // header карты + ID : Array[1..4] of Char; + Version : byte; + MapName : string[70]; + Author : string[70]; + MapSizeX,MapSizeY,BG,GAMETYPE,numobj : byte; + numlights : word; + end; + +type TMAPOBJ = record // специальный объект + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,objtype,orient,nowanim,special : byte; + end; + +type TMAPOBJV2 = record // специальный объект + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,orient,nowanim,special:word; + objtype : byte; + end; + +var + Form1: TForm1; + GX, GY : integer; // позиция "камеры" + selx,sely, // выбранный брик по Х, У + selbrk, // выбранный браш из палитры брашей. + mode,alph,RRRA : integer; + bbb : array [0..254,0..254] of TBrick; // массив бриков (карта) + ddd : array[0..255] of TMAPOBJV2; // массив специальных объектов + SELECTEDOBJ, SELECTEDLOC : integer; // текуще выбранный спец объект + itmsel : TListItem; // для добавления свойств в список свойств спец объекта + + brCopy : array [0..254,0..254] of byte; + LocationsArray : array [1..50] of TLocationText; + selbminx,selbminy , + selbmaxx,selbmaxy : word; + PaletteFile : TBitmap; + PaletteStream : TMemoryStream; + + +CONST MAXBRUSH = 254; // всего brush'ей + MAX_BUF = 2048; // буфер + BRICK_X : byte = 20; // 20 + BRICK_Y : byte = 30; // 30 + MAP_NAME : string[70] = 'test map'; + MAP_AUTHOR : string[70] = 'unnamed'; + MAP_BG : byte = 0; // задний фон карты + SHOWLINES : boolean = true; // показывать диагональные линии + SHOWOBJ : boolean = true; // показывать спец объекты + DOSELECT : boolean = false; // селекция + copysizex : byte = 0; // копирование + copysizey : byte = 0; // копирование + CUSTOMPALITRE : boolean=false; // своя палитра бриков. + CUSTOMPALITREFILENAME : string=''; + CUSTOMPALITRETRANSPARENT : boolean =false; + CUSTOMPALITRETRANSPARENTCOLOR : cardinal = $FFFFF; + + +procedure loadmapp (filename : string); +procedure BrushName; +procedure Location_Modify(ID:byte); + +implementation +uses unit2, teleport_dlg, Unit4, Unit5, Unit6, brshrepls, palette_unit, unit2_locsel; +{$R *.DFM} + +function ShiftKeyDown : boolean; begin result:=(Word(GetKeyState(VK_SHIFT)) and $8000)<>0; end; + +procedure CleanUpMap; +begin + if form1.speedbutton1.enabled then form1.speedbutton1.click; + if form1.speedbutton13.enabled then form1.speedbutton13.click; + + FillChar(LocationsArray, sizeof(LocationsArray),0); + SELECTEDOBJ := -1; + SELECTEDLOC := 0; + +end; + +procedure TForm1.FormCreate(Sender: TObject); +var i : integer; +begin +form1.top := 0; +form1.left := 0; +form1.Width := 640; +form1.height := 480; +ImageList.Items.MakeColorTable; +selbrk := 1; +mode := 1; +alph := 255; +opendlg.initialdir := GetCurrentdir; +savedialog.InitialDir := GetCurrentdir; +for i := 0 to $ff do ddd[i].active := false; +// loadmapp('"'+paramstr(1)+'"'); +SELECTEDOBJ := -1; +GX := 32;GY := 32; +PaletteFile := TBitmap.Create; +PaletteStream := TMemoryStream.Create; +CleanUpMap; +if paramstr(1) <> '' then if fileexists(paramstr(1)) then begin + OpenDlg.InitialDir := extractfilepath(paramstr(1)); +// SaveDialog.initialdir := extractfilepath(paramstr(1)); + SaveDialog.filename := paramstr(1); + Open037map(paramstr(1)); + end; + +end; + +procedure BrushName; +begin +with form1 do + case selbrk of + 0 : label1.caption := 'Brush: none'; + 1 : label1.caption := 'Brush: shotgun'; + 2 : label1.caption := 'Brush: grenade launcher'; + 3 : label1.caption := 'Brush: rocket launcher'; + 4 : label1.caption := 'Brush: shaft'; + 5 : label1.caption := 'Brush: railgun'; + 6 : label1.caption := 'Brush: plasma'; + 7 : label1.caption := 'Brush: bfg'; + 8 : label1.caption := 'Brush: ammo for machinegun'; + 9 : label1.caption := 'Brush: ammo for shotgun'; + 10 : label1.caption := 'Brush: ammo for grenade launcher'; + 11 : label1.caption := 'Brush: ammo for rocket launcher'; + 12 : label1.caption := 'Brush: ammo for shaft'; + 13 : label1.caption := 'Brush: ammo for railgun'; + 14 : label1.caption := 'Brush: ammo for plasma'; + 15 : label1.caption := 'Brush: ammo for bfg'; + 16 : label1.caption := 'Brush: shard (+5)'; + 17 : label1.caption := 'Brush: yellow armor (+50)'; + 18 : label1.caption := 'Brush: red armor (+100)'; + 19 : label1.caption := 'Brush: health +5'; + 20 : label1.caption := 'Brush: health +25'; + 21 : label1.caption := 'Brush: health +50'; + 22 : label1.caption := 'Brush: megahealth +100'; + 23 : label1.caption := 'Brush: powerup regeneration'; + 24 : label1.caption := 'Brush: powerup battlesuit'; + 25 : label1.caption := 'Brush: powerup haste'; + 26 : label1.caption := 'Brush: powerup quaddamage'; + 27 : label1.caption := 'Brush: powerup flight'; + 28 : label1.caption := 'Brush: powerup invisibility'; + 29 : label1.caption := 'Brush: grenade launcher for trix'; + 30 : label1.caption := 'Brush: rocket launcher for trix'; + 31 : label1.caption := 'Brush: lava'; + 32 : label1.caption := 'Brush: water'; + 33 : label1.caption := 'Brush: death area. kills player.'; + 34 : label1.caption := 'Brush: respawn. neutral'; + 35 : label1.caption := 'Brush: respawn. red team (CTF ONLY)'; + 36 : label1.caption := 'Brush: respawn. blu team (CTF ONLY)'; + 37 : label1.caption := 'Brush: empty brick'; + 38 : label1.caption := 'Brush: jumppad'; + 39 : label1.caption := 'Brush: strong jumppad'; + 40 : label1.caption := 'Brush: red flag'; + 41 : label1.caption := 'Brush: blue flag'; + 42 : label1.caption := 'Brush: domination point'; + 54..255 : label1.caption := 'Brush: brick'; + else label1.caption := 'Brush: unknown'; + end; +end; + +procedure Save1Click(Sender: TObject); // olde save 025 (or 031) map... +var i,b : byte; + s : string; + F : TFileStream; +begin +with form1 do begin +if(SaveDialog.execute) then begin +form2.showmodal; +if form2.ModalResult = mrCancel then begin showmessage('Save aborted :((('); exit; end; +if form2.mapname.text = '' then form2.mapname.text := 'noname'; +s := 'A1!'+#$FF+form2.mapname.text+#$FF+form2.desc.text+#$FF+form2.author.text+#$FF+'s1'+#$FF+'s2'+#$FF+'s3'+#$FF+'s4'+#$FF; +for i := 0 to 29 do begin +for b := 0 to 19 do begin + s := s + chr(bbb[b,i].image); + end; +end; +s := s+#$FF; +F := TFileStream.Create(savedialog.filename, fmCreate); +F.Write (s[1], Length(s)); +F.Free; +showmessage('Map "'+extractfilename(savedialog.filename)+'" saved'); +end; // SaveDialog +end; +end; + +// LOAD OLD NFKBETA025 MAP (Conventer). +procedure loadmapp (filename : string); +var tmpstr : string; + F : tfilestream; + buf : array [0..2048] of char; + i,a,stp,tx,ty : integer; +begin +stp := 0; tmpstr := ''; +tx := 0; ty := 0; +F := TFileStream.Create(filename, fmOpenRead); +F.Read (buf, MAX_BUF); // first read +for i := 0 to 250 do +for a := 0 to 250 do + bbb[i,a].image := 0; +for i := 0 to 255 do + ddd[i].active := false; +for i := 0 to MAX_BUF do begin + if stp = 10 then break; + if buf[i] = #$FF then begin inc(stp); end; + if buf[i] = #$FF then begin + if (stp = 1) then begin + tmpstr:=''; + continue; + end else + if (stp = 2) then begin + MAP_NAME := tmpstr; + tmpstr:=''; + continue; + end else + if (stp = 3) then begin + tmpstr:=''; + continue; + end else + if (stp = 4) then begin + MAP_AUTHOR := tmpstr; + tmpstr:=''; + continue; + end else + if (stp = 5) then begin + tmpstr:=''; + continue; + end else + if (stp = 6) then begin + tmpstr:=''; + continue; + end else + if (stp = 7) then begin + tmpstr:=''; + continue; + end else + if (stp = 8) then begin + tmpstr:=''; + continue; + tx := 0; ty := 0; + end else + end; + if (stp <= 7) and (i >= 3) then begin + if buf[i] <> #$FF then tmpstr := tmpstr + buf[i]; + end; + if (stp = 8) and (buf[i] <> #$FF) then begin + bbb[tx,ty].image := ord(buf[i]); + if(tx >= 19) then begin + tx := 0; + inc(ty); + end else + inc(tx); + end; +end; +BRICK_X := 20; +BRICK_Y := 30; +MAP_BG := 0; +form1.SaveDialog.filename := extractfilename(form1.OpenDlg.filename); +f.free; +end; // opendlg + +// ищет ближайший location к курсору. нужно для тестирования того как игрок будет реагировать на локации. +procedure TestLocations; +var MINDIST,Dist:word; + Selected, I:byte; +begin + Selected := 0; + MINDIST := $FFFF; + for i:=1 to 50 do if LocationsArray[i].enabled then begin + Dist := round(sqrt(sqr(LocationsArray[i].x*32 - selx*32)+sqr(LocationsArray[i].y*16 - sely*16))); + if dist < MINDIST then + begin + MINDIST := DIST; + SELECTED := I; + end; + end; + + if SELECTED > 0 then + with form1.DXDraw.Surface.Canvas do + begin + Brush.Style := bsClear; + font.name := 'verdana'; + font.style := [fsBold]; + Font.Color := clYellow; + Font.Size := 8; + Textout(5, 146, 'Zone: '+ LocationsARRAY[SELECTED].Text); + Release; { Indispensability } + end; +end; + +procedure Open1Click(Sender: TObject); +begin +with form1 do begin +if(opendlg.execute) then begin + LOADMAPP (opendlg.filename); +end;end; + +end; // proc + + +procedure TForm1.DXTimer1Timer(Sender: TObject); +var i,a,z : byte; + xxx : TPoint; + rct : TREct; + s : string[$AA]; +begin + if not DXDraw.CanDraw then exit; + GetCursorPos(xxx); + xxx.x := xxx.x - form1.left-3; + xxx.y := xxx.y - form1.top-40; + rct := REct(0,0,181,78); + DXDraw.Surface.Fill(0); + + +if SHOWOBJ then + for i := 0 to $FF do if ddd[i].active = true then + if ddd[i].objtype = 10 then // water pre draw.. + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, 8); + + // Draw Bricks + for i := 0 to BRICK_X-1 do begin // отрисовка кирпичей + for a := 0 to BRICK_Y-1 do begin + if bbb[i,a].image > 0 then + if (GX+i*32 < dxdraw.Width) and (GX+i*32 >= -32) and (GY+a*16 >= -16) and (GY+a*16 < dxdraw.Height) then + + begin + if (CUSTOMPALITRE=true) and (bbb[i,a].image <= 181) and (bbb[i,a].image >= 54) then + ImageList.Items[7].Draw(DXDraw.Surface,GX+i*32,GY+a*16, bbb[i,a].image-54) else // подргруженная юзером палитра бриков... + ImageList.Items[0].Draw(DXDraw.Surface, GX+i*32,GY+a*16, bbb[i,a].image); + end; + end; end; + + // Draw Map Border + with form1.DXDraw.surface.canvas do begin + Brush.Style := bsClear; + pen.color := rgb($FF,$0,$0); + Pen.Style := psSolid; + MoveTo(trunc(gx-1), trunc(gy-30)); + LineTo(trunc(gx-1), trunc(gy+16*brick_y+30)); + MoveTo(trunc(gx+32*BRICK_X+1), trunc(gy-30)); + LineTo(trunc(gx+32*BRICK_X+1), trunc(gy+16*brick_y+30)); + + MoveTo(trunc(gx-30), trunc(gy-1)); + LineTo(trunc(gx+32*BRICK_X+30), trunc(gy-1)); + + MoveTo(trunc(gx-30), trunc(gy+16*brick_y+1)); + LineTo(trunc(gx+32*BRICK_X+30), trunc(gy+16*brick_y+1)); + + + if SHOWLINES then begin + pen.color := rgb($ee,$cc,$cc); + MoveTo(trunc(gx), trunc(gy)); + LineTo(trunc(gx+32*BRICK_X), trunc(gy+16*brick_y)); + MoveTo(trunc(gx+32*BRICK_X), trunc(gy)); + LineTo(trunc(gx), trunc(gy+16*brick_y)); + end; + release; + end; + +// ======================= +// Отрисовка спец объектов +// ======================= +if SHOWOBJ then begin + for i := 0 to $FF do if ddd[i].active = true then begin + if ddd[i].objtype <> 9 then + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32,GY+ddd[i].y*16, ddd[i].objtype-1); + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Show Object Selection + if SELECTEDOBJ = i then begin + with form1.DXDraw.surface.canvas do begin + Brush.Style := bsClear; + pen.color := rgb($00,$FF,$FF); + Pen.Style := psDashDotDot; + + if ddd[i].objtype = 1 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY); + if ddd[i].objtype = 2 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY); + + if ddd[i].objtype = 3 then begin + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY) else + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY+16*ddd[i].lenght-16); + end; + if ddd[i].objtype = 4 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY+16*ddd[i].dir-16); + if ddd[i].objtype = 5 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY+16*ddd[i].dir-16); + if ddd[i].objtype = 6 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + if ddd[i].objtype = 7 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + if ddd[i].objtype = 8 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + if ddd[i].objtype = 9 then begin + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].lenght-32,ddd[i].y*16+20+GY) else + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX,ddd[i].y*16+20+GY+16*ddd[i].lenght-16); + end; + if ddd[i].objtype = 10 then + rectangle(ddd[i].x*32-4+GX,ddd[i].y*16-4+GY,ddd[i].x*32+36+GX+32*ddd[i].special-32,ddd[i].y*16+20+GY+16*ddd[i].orient-16); + release; + end; + end; + + + // ... в зависимости от типа объекта + if ddd[i].objtype = 3 then begin + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then begin + for z := 0 to ddd[i].lenght-1 do ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16, ddd[i].objtype-1); + end else + for z := 0 to ddd[i].lenght-1 do ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32,GY+ddd[i].y*16+16*z, ddd[i].objtype-1); + end; + + if ddd[i].objtype = 4 then begin + for z := 0 to ddd[i].lenght-1 do + for a := 0 to ddd[i].dir -1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 5 then begin + for z := 0 to ddd[i].lenght-1 do + for a := 0 to ddd[i].dir -1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 6 then begin + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 7 then begin + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 8 then begin + for z := 0 to ddd[i].special-1 do + for a := 0 to ddd[i].orient-1 do + ImageList.Items[4].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16+a*16, ddd[i].objtype-1); + end; + if ddd[i].objtype = 9 then begin // doortrigger draw + if (ddd[i].orient = 0) or (ddd[i].orient = 2) then begin + for z := 0 to ddd[i].lenght-1 do ImageList.Items[5].Draw(DXDraw.Surface, GX+ddd[i].x*32+32*z,GY+ddd[i].y*16, ddd[i].orient); + end else + for z := 0 to ddd[i].lenght-1 do ImageList.Items[5].Draw(DXDraw.Surface, GX+ddd[i].x*32,GY+ddd[i].y*16+16*z, ddd[i].orient); + end; + + + + with form1.DXDraw.surface.canvas do begin + // подписать спец объекты + case ddd[i].objtype of + 1 : s := 'teleport'; + 2 : s := 'button'; + 3 : s := 'door'; + 4 : s := 'trigger'; + 5 : s := 'area_push'; + 6 : s := 'area_pain'; + 7 : s := 'area_ta_end'; + 8 : s := 'area_teleport'; + 9 : s := 'doortrigger'; + 10 : s := 'area_waterillusion'; + else s := 'unknown'; + end; + s := s + '|#'+inttostr(i); + Font.Color := clYellow; + Font.Size := 8; + textout(GX+ddd[i].x*32,GY+ddd[i].y*16,s); + + // показать куда ведет телепорт если он выбран. + if (ddd[i].objtype = 1) and ((SELECTEDOBJ = i) or (Showallteleportlinks1.checked)) then begin + Brush.Style := bsClear; + pen.color := rgb($FF,$FF,$0); + Pen.Style := psSolid; + MoveTo(GX+ddd[i].x*32+16, GY+ddd[i].y*16+8); + LineTo(GX+ddd[i].lenght*32+16, GY+ddd[i].dir*16+8); + end; + + // показать куда ведет ареа_телепорт если он выбран. + if (ddd[i].objtype = 8) and ((SELECTEDOBJ = i) or (Showallteleportlinks1.checked)) then begin + Brush.Style := bsClear; + pen.color := rgb($FF,$FF,$0); + Pen.Style := psSolid; + MoveTo(GX+ddd[i].x*32+16, GY+ddd[i].y*16+8); + LineTo(GX+ddd[i].dir*32+16, GY+ddd[i].wait*16+8); + end; + + release; + end; + + end; + end; + + // Display Locations. + for i := 1 to 50 do if LocationsArray[i].Enabled = true then begin + if (showloc1.checked) or (i = SELECTEDLOC) then + ImageList.Items[3].Draw(DXDraw.Surface, GX+LocationsArray[i].x*32-2,GY+LocationsArray[i].y*16-2, 1); + with form1.DXDraw.surface.canvas do begin +// moveto(GX+LocationsArray[i].x*32 -, GY+LocationsArray[i].y*16); + if showloc1.checked then begin + + if (i <> SELECTEDLOC) then + Pen.Style := psDot + else Pen.Style := psSolid; + // if (i = SELECTEDLOC) then + pen.Color := clAqua; +// else pen.color := $00767600; + Brush.Style := bsclear; + Ellipse(GX+16+LocationsArray[i].x*32 - 20, + GY+8+LocationsArray[i].y*16 - 20, + GX+16+LocationsArray[i].x*32 + 20, + GY+8+LocationsArray[i].y*16 + 20); + Pen.Style := psSolid; + + moveto(GX+16+LocationsArray[i].x*32 - 20, + GY+8+LocationsArray[i].y*16 - 20); + lineto(GX+16+LocationsArray[i].x*32 + 20, + GY+8+LocationsArray[i].y*16 + 20); + + moveto(GX+16+LocationsArray[i].x*32 - 20, + GY+8+LocationsArray[i].y*16 + 20); + lineto(GX+16+LocationsArray[i].x*32 + 20, + GY+8+LocationsArray[i].y*16 - 20); + end; + + if (showloc1.checked) or (i = SELECTEDLOC) then begin + Brush.Style := bsClear; + font.name := 'verdana'; + font.style := [fsBold]; + if (i = SELECTEDLOC) then + Font.Color := clwhite + else Font.color := $eeeeee; + Font.Size := 8; + Textout(GX+25+LocationsArray[i].x*32 - textwidth(locationsarray[i].text) div 2 - 8, -12+GY+LocationsArray[i].y*16, LocationsArray[i].text); + end; + + release; + end; + end; + +// ===================== + + // плавная анимация палитры brush'ей + if (xxx.x < 200) and (xxx.y < 90) then begin + if alph > 3 then dec (alph,3); + mode := 2 + end + else begin + if alph < 252 then inc (alph,3); + mode :=1; + end; + + + ImageList.Items[2].DrawAlpha(DXDraw.Surface,rct, 0,alph); + + dxinput.update; + + // Отрисовать "кубик" вокруг текущего, выбранного брика. + selx := (xxx.x-GX) div 32; + sely := (xxx.y-GY) div 16; + if selx > BRICK_X-1 then selx := BRICK_X-1; + if selx < 0 then selx := 0; + if sely < 0 then sely := 0; + if sely > BRICK_Y-1 then sely := BRICK_Y-1; + ImageList.Items[3].Draw(DXDraw.Surface, GX+selx*32-2,GY+sely*16-2, 0); + + + if (isButton3 in dxinput.Mouse.States) or (DXInput.keyboard.keys[ord(27)]) then begin + GX := GX + dxinput.Mouse.X; + Gy := Gy + dxinput.Mouse.y; + end; + + // селекция. + if doselect then begin + + selbmaxx:=selx; + selbmaxy:=sely; + + if selbmaxx < selbminx then selbmaxx := selbminx; + if selx < selbminx then selx := selbminx; + if selbmaxy < selbminy then selbmaxy := selbminy; + if sely < selbminy then sely := selbminy; + + for i := selbminx to selbmaxx do + for a := selbminy to selbmaxy do + ImageList.Items[6].Draw(DXDraw.Surface, GX+i*32,GY+a*16, 0); + ImageList.Items[6].Draw(DXDraw.Surface, GX+selbminx*32,GY+selbminy*16, 2); + ImageList.Items[6].Draw(DXDraw.Surface, GX+selbmaxx*32,GY+selbmaxy*16, 1); + + if (isButton2 in dxinput.Mouse.States) or (DXInput.keyboard.keys[ord(27)]) then doselect := false; + + if isButton1 in dxinput.Mouse.States then begin + sleep(10); + doselect_pop.Popup (xxx.x,xxx.y); + sleep(10); + end; + + end; + + +// dxinput.keyboard.update; + // скроллинг карты по WSAD + if DXInput.keyboard.keys[ord(#65)] then inc (GX,6); + if DXInput.keyboard.keys[ord(#87)] then inc (GY,6); + if DXInput.keyboard.keys[ord(#68)] then dec (GX,6); + if DXInput.keyboard.keys[ord(#83)] then dec (GY,6); + if DXInput.keyboard.keys[ord(#27)] then begin gx := 0; gy := 0; end; + + if isButton1 in DXInput.keyboard.States then + begin + bbb[selx,sely].image := selbrk; + end; + + if isButton2 in DXInput.keyboard.States then + bbb[selx,sely].image := 0; + + + // скроллинг в палитре брашей + if RRRA = 0 then begin + if isLeft in DXInput.keyboard.States then begin + if isButton5 in DXInput.keyboard.States then begin + if selbrk > 10 then selbrk := selbrk - 10 else selbrk := 0; + end else + if selbrk > 0 then dec(selbrk); + RRRA := 5; + BrushName; + end; + + // скроллинг в палитре брашей + if isright in DXInput.keyboard.States then begin + if isButton5 in DXInput.keyboard.States then begin + if selbrk < MAXBRUSH then selbrk := selbrk + 10 else selbrk := MAXBRUSH; + end else + + if selbrk < MAXBRUSH then inc(selbrk); + RRRA := 5; + BrushName; + end; + end; + + // RRRA - это исключение слишком быстрого повторного нажатия кнопок. + if RRRA > 0 then dec(RRRA); + + // Отрисовать видимые браши в палитре брашей + for i := 0 to 3 do begin + if selbrk <= MAXBRUSH then + if mode = 1 then begin + if (CUSTOMPALITRE=true) and (selbrk+i-3 <= 181) and (selbrk+i-3 >= 54) then + ImageList.Items[7].Draw(DXDraw.Surface, 0+28+i*34,38, selbrk+i-3-54) else // подргруженная юзером палитра бриков... + ImageList.Items[0].Draw(DXDraw.Surface, 0+28+i*34,38, selbrk+i-3); + end; + end; + + with DXDraw.Surface.Canvas do + begin + Brush.Style := bsClear; + font.name := 'verdana'; + font.style := [fsBold]; + Font.Color := clWhite; + Font.Size := 8; + if mode = 1 then + Textout(116, 9, inttostr(selbrk)); + Textout(5, 80, 'GX:'+inttostr(GX)); + Textout(5, 92, 'GY:'+inttostr(GY)); + Textout(5, 110, 'BRICKX:'+inttostr(selx)); + Textout(5, 122, 'BRICKY:'+inttostr(sely)); + Textout(5, 134, 'BRUSH:'+inttostr(bbb[selx,sely].image)); + Release; { Indispensability } + end; + + if (TestLocations1.checked) then + TestLocations; + + + DXDraw.Flip; +end; + +procedure TForm1.DXDrawInitialize(Sender: TObject); +begin +DXTimer1.MayProcess := True; +end; + +procedure TForm1.PopupMenu1Popup(Sender: TObject); +var i : byte; +begin +// Меню по правой кнопке мыши. + try + itisabrush1.caption := 'Select Brush: '+inttostr(bbb[selx,sely].image); + except itisabrush1.caption := 'unknown'; end; + + Selectobject1.visible := false; + selectloc.visible := false; + + if (copysizex=0) or (copysizey=0) then Paste1.visible := false else Paste1.visible := true; + + for i := 0 to 255 do if ddd[i].active = true then begin + if (ddd[i].x = selx) and (ddd[i].y = sely) then + begin + Selectobject1.visible := true; + Selectobject1.caption := 'Select object: #'+inttostr(i); + break; + end; + end; + + for i := 1 to 50 do if LocationsArray[i].enabled = true then + if (LocationsArray[i].x = selx) and (LocationsArray[i].y = sely) then + begin + selectloc.visible := true; + selectloc.caption := 'Select location: #'+inttostr(i); + break; + end; + +end; + +procedure TForm1.itisabrush1Click(Sender: TObject); +begin +try +selbrk := bbb[selx,sely].image; +brushname; +except exit; end; +end; + +procedure TForm1.FormActivate(Sender: TObject); +begin +dxdraw.initialize; +dxtimer1.MayProcess := true; +end; + +procedure TForm1.FormDeactivate(Sender: TObject); +begin +dxdraw.finalize; +dxtimer1.MayProcess := false; +end; + +procedure TForm1.saveclk(Sender: TObject); +var F : File; + i,a : Integer; + Header : THeader; + buf : array [0..$FE] of byte; + Entry : TMapEntry; + CompressedPaletteStream, MapFile :TMemoryStream; + ProgressCallBack : TProgressEvent; +begin + // Сохранение карте в формате nfkbeta031 + if SaveDialog.filename <> '' then + SaveDialog.initialdir := extractfilepath(SaveDialog.filename); +// showmessage(SaveDialog.initialdir); +// end; + + if not (SaveDialog.execute) then exit; + + MapFile := TMemoryStream.Create; + MapFile.Position := 0; + MapFile.Size := 0; + + header.ID := 'NMAP'; + header.Version := 3; + header.Author := MAP_AUTHOR; + header.mapname := MAP_NAME; + header.BG := MAP_BG; + header.MapSizeX := BRICK_X; + header.MapSizeY := BRICK_Y; + header.GAMETYPE := 0; + a:= 0; + for i := 0 to $FF do if ddd[i].active = true then inc(a); + header.numobj := a; + header.numlights := 0; + header.GAMETYPE := 0; + MapFile.Write(Header, Sizeof(Header)); + for a := 0 to BRICK_Y-1 do begin + for i := 0 to BRICK_X do buf[i]:= bbb[i,a].image ; + MapFile.Write(buf, BRICK_X); + end; + for i := 0 to $FF do + if ddd[i].active = true then + MapFile.Write(ddd[i],sizeof(ddd[i])); + + if CUSTOMPALITRE then begin + Entry.EntryType := 'pal'; + Entry.Reserved1 := 0; + Entry.Reserved2 := 0; + Entry.Reserved3 := 0; + Entry.Reserved4 := 0; + Entry.Reserved5 := CUSTOMPALITRETRANSPARENTCOLOR; + Entry.Reserved6 := CUSTOMPALITRETRANSPARENT; + + try + // do compression... +// PaletteStream := TMemoryStream.Create; + // PaletteStream.Clear; + CompressedPaletteStream := TMemoryStream.Create; + CompressedPaletteStream.Clear; +// PaletteStream.LoadFromFile(CUSTOMPALITREFILENAME); + PaletteStream.Position := 0; + ProgressCallBack := nil; + BZCompress(PaletteStream, CompressedPaletteStream,ProgressCallBack); + Entry.DataSize := CompressedPaletteStream.Size; + CompressedPaletteStream.Position := 0; + MapFile.Write(Entry,sizeof(Entry)); + MapFile.CopyFrom(CompressedPaletteStream,CompressedPaletteStream.size); +// PaletteStream.Free; + CompressedPaletteStream.Free; + except showmessage('ERROR: Cannot compress palette file... may be source file does not exists...'); end; + + end; + + // save locations entry + a := 0; + for i := 1 to 50 do if LocationsArray[i].Enabled = true then inc(a); + if a > 0 then begin + fillchar(entry,sizeof(entry),0); + Entry.EntryType := 'loc'; + Entry.DataSize := sizeof(TLocationText)*a; + MapFile.Write(Entry,sizeof(Entry)); + for i := 1 to 50 do if LocationsArray[i].Enabled = true then + MapFile.Write(LocationsArray[i],sizeof(LocationsArray[i])); + end; + + MapFile.SaveToFile(SaveDialog.filename); + MapFile.Free; + +end; + +procedure Loadv031map(filename:string); +var tempobj : TMapOBJ; + f : file; + header : THeader; + i,a,z : word; + buf : array [0..$FE] of byte; + +begin + if not fileexists(filename) then begin showmessage(filename+' not found.');exit; end; + AssignFile(F, filename); + Reset(F,1); + BlockRead(F, Header, Sizeof(Header)); + if (header.ID <> 'NMAP') and (header.ID <> 'NDEM') then begin + closefile(f); + showmessage(filename + ' is not NFK map'); + exit; + end; + if (header.Version >= 3) then begin + closefile(F); + showmessage('incorrect map version ('+inttostr(header.version)+'). Im can load only earlier map.'); + exit; + end; + + form1.savedialog.FileName := filename; + form1.savedialog.InitialDir := extractfilepath(filename); + + + for i := 0 to 255 do + ddd[i].active := false; + MAP_AUTHOR := header.Author; + MAP_NAME := header.MapName ; + MAP_BG := header.BG; + BRICK_X := header.MapSizeX ; + BRICK_Y := header.MapSizeY; + for a := 0 to header.MapSizeY - 1 do begin + blockread(f,buf,header.MapSizeX); + for z := 0 to header.MapSizeX - 1 do begin + // convert it here! + bbb[z,a].image := buf[z]; + if buf[z]=9 then bbb[z,a].image := 8; + if buf[z]=10 then bbb[z,a].image := 9; + if buf[z]=11 then bbb[z,a].image := 10; + if buf[z]=12 then bbb[z,a].image := 11; + if buf[z]=13 then bbb[z,a].image := 12; + if buf[z]=14 then bbb[z,a].image := 13; + if buf[z]=15 then bbb[z,a].image := 14; + if buf[z]=16 then bbb[z,a].image := 15; + if buf[z]=17 then bbb[z,a].image := 16; + if buf[z]=18 then bbb[z,a].image := 17; + if buf[z]=19 then bbb[z,a].image := 18; + if buf[z]=20 then bbb[z,a].image := 20; + if buf[z]=21 then bbb[z,a].image := 21; + if buf[z]=22 then bbb[z,a].image := 22; + if buf[z]=23 then bbb[z,a].image := 19; + if buf[z]=24 then bbb[z,a].image := 23; + if buf[z]=25 then bbb[z,a].image := 24; + if buf[z]=26 then bbb[z,a].image := 25; + if buf[z]=27 then bbb[z,a].image := 26; + if buf[z]=8 then bbb[z,a].image := 27; + if buf[z]=28 then bbb[z,a].image := 29; + if buf[z]=29 then bbb[z,a].image := 30; + if buf[z]=30 then bbb[z,a].image := 37; + if buf[z]=31 then bbb[z,a].image := 39; + if buf[z]=32 then bbb[z,a].image := 33; + if buf[z]=33 then bbb[z,a].image := 38; + if buf[z]=34 then bbb[z,a].image := 31; + if buf[z]=35 then bbb[z,a].image := 34; + if buf[z]>=36 then bbb[z,a].image := 54 + buf[z]- 36; + end; + end; + + if header.numobj > 0 then + for a := 0 to header.numobj-1 do begin + blockread(f,tempobj,sizeof(tempobj)); + ddd[a].active := tempobj.active; + ddd[a].x := tempobj.x; + ddd[a].y := tempobj.y; + ddd[a].lenght := tempobj.lenght; + ddd[a].dir := tempobj.dir; + ddd[a].wait := tempobj.wait; + ddd[a].targetname := tempobj.targetname; + ddd[a].target := tempobj.target; + ddd[a].orient := tempobj.orient; + ddd[a].nowanim := tempobj.nowanim; + ddd[a].special:= tempobj.special; + ddd[a].objtype := tempobj.objtype; + end; + CloseFile(F); + +end; + + +procedure Open037map(filename : string); // open 040 map. +var F, decompstr : TMemoryStream; + i,a,z : Integer; + Header : THeader; + buf : array [0..$FE] of byte; + Entry : TMAPENTRY; + ProgressCallback : TProgressEvent; + tempbmp : TBitmap; +begin + + Form1.listview1.Items.Clear; + + F := TMemoryStream.create; + F.loadfromfile(filename); + F.Read(Header, Sizeof(Header)); + + if (header.ID <> 'NMAP') and (header.ID <> 'NDEM') then begin + f.free; + showmessage(filename + ' is not NFK map'); + exit; + end; + + if (header.Version <> 3) then begin + f.free; + showmessage('incorrect map version ('+inttostr(header.version)+'). Only version 3 supported.'); + exit; + end; + + for i := 0 to 255 do + ddd[i].active := false; + + CleanUpMap; + fillchar(LocationsArray, sizeof(LocationsArray),0); + + form1.SaveDialog.filename := filename; + MAP_AUTHOR := header.Author; + MAP_NAME := header.MapName ; + MAP_BG := header.BG; + BRICK_X := header.MapSizeX ; + BRICK_Y := header.MapSizeY; + for a := 0 to header.MapSizeY - 1 do begin + f.read(buf,header.MapSizeX); + for z := 0 to header.MapSizeX - 1 do + bbb[z,a].image := buf[z]; + end; + for a := 0 to header.numobj-1 do + f.read(ddd[a],sizeof(ddd[a])); + + if CUSTOMPALITRE then palette.button1.click; // clear old palette. + + + while F.Position < f.size do begin + f.read(entry,sizeof(entry)); + if entry.EntryType = 'pal' then begin // reading pal + CUSTOMPALITRETRANSPARENTCOLOR := Entry.Reserved5; + CUSTOMPALITRETRANSPARENT := Entry.Reserved6; + CUSTOMPALITRE := TRUE; + + decompstr := TMemoryStream.Create; + decompstr.clear; + PaletteStream.Clear; + decompstr.CopyFrom (F, Entry.Datasize); + decompstr.position := 0; + ProgressCallback := nil; + BZDecompress(decompstr,PaletteStream,ProgressCallback); + palettestream.Position := 0; + decompstr.free; + + // apply to scene... + PaletteFile.loadfromstream(PaletteStream); + form1.ImageList.Items[7].picture.assign(PaletteFile); + form1.ImageList.Items[7].Transparent := CUSTOMPALITRETRANSPARENT; + form1.ImageList.Items[7].TransparentColor := CUSTOMPALITRETRANSPARENTCOLOR; + form1.ImageList.Items[7].restore; + end + else if entry.EntryType = 'loc' then begin // reading location table. + For a := 1 to Entry.DataSize div Sizeof(TLocationText) do + f.Read (LocationsArray[a],sizeof(TLocationText)); + end + else f.position := f.position + Entry.DataSize; + end; + + F.free; +end; + +procedure TForm1.opnclk(Sender: TObject); +var F : File; + i,a,z : Integer; + Header : THeader; + buf : array [0..$FE] of byte; +begin + // Открытие карты nfkbeta030 или nfkbeta031. + if opendlg.filter = 'extractor' then opendlg.filter := 'Nfk demo (*.ndm)|*.ndm' else + opendlg.filter := 'Nfk maps (*.mapa)|*.mapa'; + if extractfilepath(opendlg.filename) <> '' then begin + opendlg.initialdir := extractfilepath(opendlg.filename); + savedialog.initialdir := extractfilepath(opendlg.filename); + end; +if not (opendlg.execute) then exit; + + Open037map( opendlg.filename); + +end; + + +procedure TForm1.FormResize(Sender: TObject); +begin +// Изменение размеров +form1.dxdraw.width := form1.width - 170; +form1.dxdraw.height := form1.height - 60; +groupbox1.left := form1.width - 165; +image1.left := form1.width - 135; +image1.top := 490; +pagecontrol1.left := form1.width - 165; +end; + + +procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); +begin +if item = nil then exit; +label2.caption := item.Caption; +itmsel := item; +end; + +procedure TForm1.ListView1DblClick(Sender: TObject); +// Редактирование свойств в списке спец объектов. +var n,s : string; +nn : integer; +begin +//showmessage(itmsel.Caption); +if ddd[SELECTEDOBJ].objtype = 1 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='goto_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='goto_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='goto_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='goto_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + +end; +if ddd[SELECTEDOBJ].objtype = 2 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='color' then s := 'value(0-5). (0=grn;1=red;2=blu;3=aqua;4=fuch;5=olive)'; + if itmsel.Caption ='shootable' then s := 'value(0-1). (0=no, 1=yes)'; + if itmsel.Caption ='wait' then s := 'value(10-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate. 0=no target.'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='color' then if (nn < 0) or (nn > 5) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='shootable' then if (nn < 0) or (nn > 1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 10) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + +end; + +if ddd[SELECTEDOBJ].objtype = 3 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='orientation' then begin s := 'value(0-3).'; + showmessage('value:'+#13+'0=closed, horizontal'+#13+'1=closed, vertical'+#13+'2=opened, horizontal'+#13+'3=opened, vertical'); + end; + if itmsel.Caption ='wait' then s := 'value(10-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='targetname' then s := 'value(0-255). targetname to be activated, 0=no targetname.'; + if itmsel.Caption ='lenght' then s := 'value(1-255). door lenght (bricks)'; + if itmsel.Caption ='fastclose' then s := 'value(0-1). 0=no. 1=yes'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='orientation' then if (nn < 0) or (nn > 3) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 10) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='targetname' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].targetname := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='fastclose' then if (nn < 0) or (nn > 1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; +end; + +if ddd[SELECTEDOBJ].objtype = 4 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='wait' then s := 'value(1-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate, 0=no target.'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 1) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 5 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='wait' then s := 'value(1-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate, 0=no target.'; + if itmsel.Caption ='pushspeed' then s := 'value(10-70). 10=very slow; 70=very fast.'; + if itmsel.Caption ='direction' then begin + showmessage('value:'+#13+'0=push left'+#13+'1=push up'+#13+'2=push right'+#13+'3=push down'); + s := 'value(0-3).'; + end; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='direction' then if (nn < 0) or (nn > 3) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 1) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pushspeed' then if (nn < 10) or (nn > 70) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; +end; + +if ddd[SELECTEDOBJ].objtype = 6 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='dmginterval' then s := 'value(1-255). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='wait' then s := 'value(1-65535). 50 - means 1 second. 100=2sec. etc'; + if itmsel.Caption ='targetname' then s := 'value(0-255). targetname to be actvtd, 0=no need to actvtd.'; + if itmsel.Caption ='dmg' then s := 'value(1-500). Makes the specified damage.'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='targetname' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].targetname := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='dmg' then if (nn < 1) or (nn > 500) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='dmginterval' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].nowanim := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='wait' then if (nn < 1) or (nn > $FFFF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 7 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 8 then begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-255).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-255).'; + if itmsel.Caption ='goto_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='goto_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + + if itmsel.Caption ='goto_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].dir := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='goto_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].wait := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 9 then begin // DOOR TRIGGED, Property edit. + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='orientation' then begin s := 'value(0-3).'; + showmessage('value:'+#13+'0=up'+#13+'1=left'+#13+'2=down'+#13+'3=right'); + end; + if itmsel.Caption ='target' then s := 'value(0-255). target to activate, 0=no target'; + if itmsel.Caption ='lenght' then s := 'value(1-255). door lenght (bricks)'; + if itmsel.Caption ='fastclose' then s := 'value(0-1). 0=no. 1=yes'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='orientation' then if (nn < 0) or (nn > 3) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='target' then if (nn < 0) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].target := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght' then if (nn < 1) or (nn > $FF) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].lenght := nn; + itmsel.SubItems.Text := n; + end; +end; +if ddd[SELECTEDOBJ].objtype = 10 then begin // AREA_WATERILLUSION, Property edit. + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='lenght_x' then s := 'value(1-4).'; + if itmsel.Caption ='lenght_y' then s := 'value(1-4).'; + + if not inputquery('edit object property "'+itmsel.Caption+'"',s,n) then exit; + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + + nn := strtoint(n); + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].x := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].y := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_x' then if (nn < 1) or (nn > 4) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].special := nn; + itmsel.SubItems.Text := n; + end; + if itmsel.Caption ='lenght_y' then if (nn < 0) or (nn > 4) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + ddd[SELECTEDOBJ].orient := nn; + itmsel.SubItems.Text := n; + end; +end; + +end; + + +procedure addprop (st1, st2 : string); +var item : TListItem; +begin +item := form1.listview1.items.add; +item.caption := st1; +item.SubItems.Add(st2); +end; + +procedure addprop_loc (st1, st2 : string); +var item : TListItem; +begin +item := form1.listview2.items.add; +item.caption := st1; +item.SubItems.Add(st2); +end; + + +procedure ADDobjPROP(nn:integer;n : string); +begin +// Добавление свойств объекта в список свойств. +with Form1 do begin + +if ddd[nn].objtype = 1 then begin +label3.caption := 'TELEPORT | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('goto_x',inttostr(ddd[nn].lenght)); +addprop('goto_y',inttostr(ddd[nn].dir)); +end; + +if ddd[nn].objtype = 2 then begin +label3.caption := 'BUTTON | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('color',inttostr(ddd[nn].orient)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('target',inttostr(ddd[nn].target)); +addprop('shootable',inttostr(ddd[nn].special)); +end; + +if ddd[nn].objtype = 3 then begin +label3.caption := 'DOOR | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('orientation',inttostr(ddd[nn].orient)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('fastclose',inttostr(ddd[nn].special)); +addprop('targetname',inttostr(ddd[nn].targetname)); +addprop('lenght',inttostr(ddd[nn].lenght)); +end; + +if ddd[nn].objtype = 4 then begin +label3.caption := 'TRIGGER | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].lenght)); +addprop('lenght_y',inttostr(ddd[nn].dir)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('target',inttostr(ddd[nn].target)); +end; +if ddd[nn].objtype = 5 then begin +label3.caption := 'AREA_PUSH | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].lenght)); +addprop('lenght_y',inttostr(ddd[nn].dir)); +addprop('wait',inttostr(ddd[nn].wait)); +addprop('target',inttostr(ddd[nn].target)); +addprop('direction',inttostr(ddd[nn].orient)); +addprop('pushspeed',inttostr(ddd[nn].special)); +end; +if ddd[nn].objtype = 6 then begin +label3.caption := 'AREA_PAIN | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +addprop('dmginterval',inttostr(ddd[nn].nowanim)); +addprop('wait',inttostr(ddd[nn].lenght)); +addprop('targetname',inttostr(ddd[nn].targetname)); +addprop('dmg',inttostr(ddd[nn].dir)); +end; +if ddd[nn].objtype = 7 then begin +label3.caption := 'AREA_TA_END | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +end; +if ddd[nn].objtype = 8 then begin +label3.caption := 'AREA_TELEPORT | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +addprop('goto_x',inttostr(ddd[nn].dir)); +addprop('goto_y',inttostr(ddd[nn].wait)); +end; +if ddd[nn].objtype = 9 then begin +label3.caption := 'DOORTRIGGER | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('orientation',inttostr(ddd[nn].orient)); +addprop('target',inttostr(ddd[nn].target)); +addprop('lenght',inttostr(ddd[nn].lenght)); +end; +if ddd[nn].objtype = 10 then begin +label3.caption := 'AREA_WATERILLUSION | #'+n; +addprop('pos_x',inttostr(ddd[nn].x)); +addprop('pos_y',inttostr(ddd[nn].y)); +addprop('lenght_x',inttostr(ddd[nn].special)); +addprop('lenght_y',inttostr(ddd[nn].orient)); +end; + +end; +end; + +procedure TForm1.SpeedButton3Click(Sender: TObject); +var +n : string; +nn : integer; +begin +showspecialobjects1.Checked := true; +SHOWOBJ := true; +form4.showmodal; +if SELECTEDOBJ < 0 then exit; +listview1.Items.Clear; +speedbutton1.enabled := true; +speedbutton2.enabled := true; +speedbutton3.enabled := false; +speedbutton4.enabled := false; +listview1.enabled := true; +nn := SELECTEDOBJ; +n := inttostr(nn); +ADDOBJPROP (nn,n); +end; + +procedure TForm1.SpeedButton1Click(Sender: TObject); +begin +// Нажали на кнопку APPLY. Убирам редактирование текущего, выбранного объекта +if SELECTEDOBJ < 0 then begin + showmessage('no special object selected.'); + exit; + end; + +SELECTEDOBJ := -1; +listview1.Items.Clear; +label3.caption := 'not selected'; +label2.caption := ''; +speedbutton1.enabled := false; +speedbutton2.enabled := false; +speedbutton3.enabled := true; +speedbutton4.enabled := true; +listview1.enabled := false; +end; + +procedure TForm1.SpeedButton2Click(Sender: TObject); +// Удаление объекта +begin +if SELECTEDOBJ < 0 then begin + showmessage('no special object selected.'); + exit; + end; +case MessageDlg ('delete object #'+inttostr(SELECTEDOBJ)+' ?', mtConfirmation, [mbYes,mbNo], 0) of +IDNO : exit; +end; +ddd[SELECTEDOBJ].active := false; +SELECTEDOBJ := -1; +listview1.Items.Clear; +label3.caption := 'not selected'; +label2.caption := ''; +speedbutton1.enabled := false; +speedbutton2.enabled := false; +speedbutton3.enabled := true; +speedbutton4.enabled := true; +listview1.enabled := false; +end; + +procedure TForm1.SpeedButton4Click(Sender: TObject); +var i : byte; +begin + // Добавление нового спец объекта + if SELECTEDOBJ >= 0 then begin + showmessage('finish editing current object'); + exit; + end; + + form3.showmodal; + if form3.ModalResult = mrOK then begin // add new obj + for i := 0 to $FF do if ddd[i].active = false then begin + if form3.RadioButton1.checked then begin // tele + ddd[i].active := true; + ddd[i].objtype := 1; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].lenght := 0; // goto_x + ddd[i].dir := 0; // goto_y + showmessage('teleport created at 0:0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton2.checked then begin // btn + ddd[i].active := true; + ddd[i].objtype := 2; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].target := 0; // target + ddd[i].wait := 100; // wait time; + ddd[i].orient := 0; // color + ddd[i].special := 0; // shoot + showmessage('button created at 0:0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton3.checked then begin // door + ddd[i].active := true; + ddd[i].objtype := 3; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].targetname := 0; // targetname + ddd[i].special := 0; // fastclose; + ddd[i].wait := 100; // wait time; + ddd[i].orient := 0; // orientation + ddd[i].lenght := 1; // door brick lenght + showmessage('door created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton4.checked then begin // trigger + ddd[i].active := true; + ddd[i].objtype := 4; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].target := 0; // target + ddd[i].lenght := 2; // lenght_x + ddd[i].dir := 2; // lenght_y + ddd[i].wait := 10; // retoggle time; + showmessage('trigger created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton5.checked then begin // area_push + ddd[i].active := true; + ddd[i].objtype := 5; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].target := 0; // target + ddd[i].lenght := 2; // lenght_x + ddd[i].dir := 2; // lenght_y + ddd[i].wait := 10; // retoggle time; + ddd[i].orient := 0; // push direction + ddd[i].special := 30; // push speed; + showmessage('area_push created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton6.checked then begin // area_dmg + ddd[i].active := true; + ddd[i].objtype := 6; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].targetname := 0; // targetname + ddd[i].special := 2; // lenght_x + ddd[i].orient := 2; // lenght_y + ddd[i].nowanim := 10; // DMGINTERVAL; + ddd[i].dir := 10; // DMG + ddd[i].lenght := 50; // wait. if targetname > 0 + showmessage('area_pain created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton7.checked then begin // area_dmg + ddd[i].active := true; + ddd[i].objtype := 7; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].special := 2; // lenght_x + ddd[i].orient := 2; // lenght_y + showmessage('area_trickarena_end created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton8.checked then begin // area_teleport + ddd[i].active := true; + ddd[i].objtype := 8; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].special := 2; // lenght_x + ddd[i].orient := 2; // lenght_y + ddd[i].dir := 0; // goto_x + ddd[i].wait := 0; // goto_y + showmessage('area_teleport created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton9.checked then begin // area_teleport + ddd[i].active := true; + ddd[i].objtype := 9; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].wait := 5; // wait time; + ddd[i].orient := 0; // orientation + ddd[i].lenght := 1; // doortrigger brick lenght + showmessage('doortrigger created at x0y0. with #'+inttostr(i)); + exit; + end; + if form3.RadioButton10.checked then begin // area_waterillusion + ddd[i].active := true; + ddd[i].objtype := 10; + ddd[i].x := 0; // pos_x + ddd[i].y := 0; // pos_y + ddd[i].special := 1; // lenght_x + ddd[i].orient := 1; // lenght_y + showmessage('area_waterillusion created at x0y0. with #'+inttostr(i)); + exit; + end; + end; + end; +end; + +procedure TForm1.Showcrosslines1Click(Sender: TObject); +begin +// диагональные линии +showcrosslines1.Checked := not showcrosslines1.Checked; +SHOWLINES := showcrosslines1.Checked; +end; + +procedure TForm1.showspecialobjects1Click(Sender: TObject); +begin +// [не]показывать спец объекты +showspecialobjects1.Checked := not showspecialobjects1.Checked; +SHOWOBJ := showspecialobjects1.Checked; +end; + +procedure TForm1.new1Click(Sender: TObject); +var i, a : word; +// Новая карта, удаление прежней информации. +begin + case MessageDlg ('Discard all map information?', mtConfirmation, [mbYes,mbNo], 0) of + IDNO : exit; + end; +listview1.Items.Clear; + +for i := 0 to 250 do +for a := 0 to 250 do + bbb[i,a].image := 0; +for i := 0 to 255 do + ddd[i].active := false; +BRICK_X := 20; +BRICK_Y := 30; +MAP_NAME := 'test map'; +MAP_AUTHOR := 'unnamed'; +SaveDialog.filename := 'unnamed.mapa'; +MAP_BG := 0; +SHOWLINES := true; +SHOWOBJ := true; +CleanUpMap; +if CUSTOMPALITRE then palette.Button1.Click; +form5.showmodal; +end; + +procedure TForm1.Findmaperrors1Click(Sender: TObject); +begin + form6.showmodal; +end; + +procedure TForm1.Mapproperities1Click(Sender: TObject); +begin +form5.showmodal; +end; + +procedure TForm1.Exit1Click(Sender: TObject); +begin +close; +end; + +procedure TForm1.LoadoldNFKbeta025map1Click(Sender: TObject); +begin +// конвентер 025 карт. + opendlg.filter := 'Old nfk maps (*.mapa)|*.mapa'; + if extractfilepath(opendlg.filename) <> '' then opendlg.initialdir := extractfilepath(opendlg.filename); + if not (opendlg.execute) then exit; + listview1.Items.Clear; +// загрузка старой карты + Loadv031map(opendlg.FileName); +end; + +procedure TForm1.SpeedButton5Click(Sender: TObject); +begin +// Навигация +with sender as TSpeedButton do + case tag of + 1 : inc(gy,32); + 2 : inc(gx,32); + 3 : dec(gy,32); + 4 : dec(gx,32); + 5 : if selbrk > 0 then dec(selbrk); + 6 : if selbrk < MAXBRUSH then inc(selbrk); + 7 : if selbrk > 10 then selbrk := selbrk - 10 else selbrk := 0; + 8 : if selbrk < MAXBRUSH then selbrk := selbrk + 10 else selbrk := MAXBRUSH; + end; + BrushName; +end; + +procedure TForm1.Selectobject1Click(Sender: TObject); +var i,nn : byte; + n : string; +begin +// Выбор спец объекта +if selectedobj >= 0 then begin + showmessage('some object already selected'); + exit; + end; +for i := 0 to 255 do if ddd[i].active = true then + if (ddd[i].x = selx) and (ddd[i].y = sely) then + begin + SELECTEDOBJ := i; +listview1.Items.Clear; +speedbutton1.enabled := true; +speedbutton2.enabled := true; +speedbutton3.enabled := false; +speedbutton4.enabled := false; +listview1.enabled := true; +Form1.PageControl1.ActivePageIndex := 0; +if form1.speedbutton13.enabled then form1.speedbutton13.click; +nn := SELECTEDOBJ; +n := inttostr(nn); + +AddOBJPROP(NN,n); + + break; + end; +end; + +procedure TForm1.ListView1KeyPress(Sender: TObject; var Key: Char); +begin +if key=#13 then ListView1DblClick(sender); +end; + +procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; + Shift: TShiftState); + var i,a : byte; +begin +// Рандомный генератор карт :))) +if (key=VK_F12) and (ShiftKeyDown) then begin + randomize; + for i := 0 to BRICK_X-1 do + for a := 0 to BRICK_y-1 do + if random(5) = 0 then + bbb[i,a].image := 54 else bbb[i,a].image := 0; + end; + + if (key=VK_F5) then begin + if SelectedLoc <> 0 then if LocationsArray[SELECTEDLOC].enabled then begin + LocationsArray[SELECTEDLOC].x := selx; + LocationsArray[SELECTEDLOC].y := sely; + if listview2.Items[0].Caption='pos_x' then listview2.Items[0].SubItems.Text := inttostr(selx); + if listview2.Items[1].Caption='pos_y' then listview2.Items[1].SubItems.Text := inttostr(sely); + end; + + if SELECTEDOBJ >= 0 then if ddd[SELECTEDOBJ].active then begin + ddd[SELECTEDOBJ].x := selx; + ddd[SELECTEDOBJ].y := sely; + if listview1.Items[0].Caption='pos_x' then listview1.Items[0].SubItems.Text := inttostr(selx); + if listview1.Items[1].Caption='pos_y' then listview1.Items[1].SubItems.Text := inttostr(sely); + end; + + end; +end; + +procedure TForm1.About1Click(Sender: TObject); +begin +showmessage(form1.caption+#13+'created by 3d[Power]'+#13+'several upgrades by [LD]:Surgeon'+#13#13+'http://www.3dpower.org'); +end; + +procedure TForm1.Help1Click(Sender: TObject); +begin +// Загрузка help файла +ShellExecute(Application.Handle,'open',pchar(extractfilepath(application.exename)+'\radiant_help.htm'),nil,nil,0); +end; + +procedure TForm1.Brushreplace1Click(Sender: TObject); +begin +form2_.showmodal; +end; + +procedure TForm1.Brushreplace2Click(Sender: TObject); +begin +form2_.SpinEdit1.value := bbb[selx,sely].image; +form2_.showmodal; +end; + +procedure TForm1.Extractmapfromdemo1Click(Sender: TObject); +begin +opendlg.filter := 'extractor'; +opnclk(sender); +end; + + +procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin +case MessageDlg ('quit?'+#13+'dont forget to save map', mtConfirmation, [mbYes,mbCancel], 0) of + mrCancel : canclose := false; +end; +end; + +procedure TForm1.NFKRadiantTutorial1Click(Sender: TObject); +begin +// Загрузка help файла +ShellExecute(Application.Handle,'open',pchar(extractfilepath(application.exename)+'\rocky_tutorial\help.htm'),nil,nil,0); + +end; + +// border filler. +procedure TForm1.Fillborder1Click(Sender: TObject); +var i: word; +begin + IF selbrk < 54 then selbrk := 54; + + for i := 0 to BRICK_X-1 do begin + bbb[i,0].image := selbrk; + bbb[i,BRICK_Y-1].image := selbrk; + end; + for i := 0 to BRICK_Y-1 do begin + bbb[0,I].image := selbrk; + bbb[BRICK_X-1,i].image := selbrk; + end; + +END; + +procedure TForm1.Startselection1Click(Sender: TObject); +begin + if not doselect then begin + doselect := true; + selbminx := selx; + selbminy := sely; + selbmaxx := selx; + selbmaxy := sely; + end; +end; + +// selection orepations +procedure TForm1.SelectOpClick(Sender: TObject); +var i,a:word; + t:byte; +begin + doselect:=false; + with sender as TMenuitem do + case tag of + 1: for i := selbminx to selbmaxx do for a := selbminy to selbmaxy do bbb[i,a].image := selbrk; // fill + 2: for i := selbminx to selbmaxx do for a := selbminy to selbmaxy do bbb[i,a].image := 0; // erase + 3: for i := selbminx to (selbminx + (selbmaxx - selbminx) div 2) do // flip_x + for a := selbminy to selbmaxy do begin + t := bbb[i,a].image; + bbb[i,a].image := bbb[selbminx+selbmaxx-i,a].image; + bbb[selbminx+selbmaxx-i,a].image := t; + end; + 4: for a := selbminy to (selbminy + (selbmaxy - selbminy) div 2) do // flip_y + for i := selbminx to selbmaxx do begin + t := bbb[i,a].image; + bbb[i,a].image := bbb[i,selbminy+selbmaxy-a].image; + bbb[i,selbminy+selbmaxy-a].image := t; + end; + 5: begin // copy + copysizex := selbmaxx - selbminx+1; + copysizey := selbmaxy - selbminy+1; + for i := 0 to copysizex-1 do + for a := 0 to copysizey-1 do + brCopy[i,a] := bbb[selbminx+i,selbminy+a].image; + end; + 6: begin // cut... + copysizex := selbmaxx - selbminx+1; + copysizey := selbmaxy - selbminy+1; + for i := 0 to copysizex-1 do for a := 0 to copysizey-1 do + brCopy[i,a] := bbb[selbminx+i,selbminy+a].image; + for i := selbminx to selbmaxx do for a := selbminy to selbmaxy do bbb[i,a].image := 0; // erase + end; + end; +end; + +procedure TForm1.Paste1Click(Sender: TObject); +var i,a:word; +begin +// showmessage(inttostr(copysizex)); + if (copysizex=0) or (copysizey=0) then exit; + for i:= 0 to copysizex-1 do + for a:= 0 to copysizey-1 do + bbb[selx+i,sely+a].image := brCopy[i,a]; + +end; + +procedure TForm1.Buildnewbrickpalette1Click(Sender: TObject); +begin +palette.showmodal; +end; + +procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); +begin +PaletteFile.Free; +end; + +procedure TForm1.Showallteleportlinks1Click(Sender: TObject); +begin +// [не]показывать телепорт линки +Showallteleportlinks1.Checked := not Showallteleportlinks1.Checked; +end; + +procedure Location_Apply(); +begin + form1.listview2.Items.Clear; + form1.SpeedButton16.enabled := true; + form1.SpeedButton13.enabled := false; + form1.SpeedButton14.enabled := true; + form1.SpeedButton15.enabled := false; + form1.listview2.enabled := false; + SELECTEDLOC := 0; + +end; + +procedure Location_Delete(ID:BYTE); +begin + LocationsArray[ID].Enabled := false; + LocationsArray[ID].Text := ''; + Location_Apply(); +end; + +procedure Location_Modify(ID:byte); +begin + if form1.speedbutton1.enabled then form1.speedbutton1.click; + form1.listview2.Items.Clear; + Addprop_loc('pos_x',inttostr(LocationsArray[ID].X)); + Addprop_loc('pos_y',inttostr(LocationsArray[ID].Y)); + Addprop_loc('text',LocationsArray[ID].Text); + SELECTEDLOC := ID; + Form1.PageControl1.ActivePageIndex := 1; + form1.SpeedButton16.enabled := false; + form1.SpeedButton13.enabled := true; + form1.SpeedButton15.enabled := true; + form1.SpeedButton14.enabled := false; + form1.listview2.enabled := true; +end; +// New locations... +procedure TForm1.SpeedButton16Click(Sender: TObject); +var i : byte; +begin + for i := 1 to 50 do if LocationsArray[i].Enabled = false then begin + LocationsArray[I].X := 0; + LocationsArray[I].Y := 0; + LocationsArray[I].Text := 'LocationName'; + LocationsArray[i].Enabled := TRUE; + Location_Modify(i); + break; + end; +end; + +procedure TForm1.ListView2DblClick(Sender: TObject); +var nn : integer; + s,n : string; +begin + if itmsel.Caption ='pos_x' then s := 'value(0-'+inttostr(BRICK_X-1)+').'; + if itmsel.Caption ='pos_y' then s := 'value(0-'+inttostr(BRICK_Y-1)+').'; + if itmsel.Caption ='text' then begin + s := 'value(64 chars max).'; + n := LocationsArray[SELECTEDLOC].Text; + end; + + if itmsel.Caption ='radius' then s := 'value(100-1000).'; + if not inputquery('edit object property "'+itmsel.Caption+'"',s, n) then exit; + + if itmsel.Caption <> 'text' then begin + try strtoint(n); + except showmessage('invalid value "'+n+'"'); exit; end; + nn := strtoint(n); + end; + + if itmsel.Caption ='pos_x' then if (nn < 0) or (nn > BRICK_X-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + LocationsArray[SELECTEDLOC].x := nn; + itmsel.SubItems.Text := n; + end; + + if itmsel.Caption ='pos_y' then if (nn < 0) or (nn > BRICK_Y-1) then begin + showmessage('out of range "'+n+'"'); exit; end else begin + LocationsArray[SELECTEDLOC].y := nn; + itmsel.SubItems.Text := n; + end; + + if itmsel.Caption ='text' then begin + LocationsArray[SELECTEDLOC].Text := n; + itmsel.SubItems.Text := n; + end; +end; + +procedure TForm1.SpeedButton13Click(Sender: TObject); +begin + Location_Apply(); +end; + +// loc select +procedure TForm1.SpeedButton14Click(Sender: TObject); +begin + application.CreateForm(Tloc_sel, loc_sel); + loc_sel.FormCreate(sender); + loc_sel.showmodal; + if loc_sel.ModalResult <> mrOk then Location_Apply(); + loc_sel.free; +end; + +procedure TForm1.SpeedButton15Click(Sender: TObject); +begin +case MessageDlg ('delete location #'+inttostr(SELECTEDLOC)+' ('+LocationsArray[SELECTEDLOC].text+') ?', mtConfirmation, [mbYes,mbNo], 0) of +IDNO : exit; +end; +Location_Delete(SELECTEDLOC); +end; + +procedure TForm1.selectlocClick(Sender: TObject); +var i :byte; +begin + for i := 1 to 50 do if LocationsArray[i].enabled then + if (LocationsArray[i].x = selx) and + (LocationsArray[i].y = sely) then begin + Location_Modify(i); + break; + end; +end; + +procedure TForm1.Showloc1Click(Sender: TObject); +begin +Showloc1.Checked := not Showloc1.Checked; +end; + +procedure TForm1.TestLocations1Click(Sender: TObject); +begin + TestLocations1.checked := not TestLocations1.checked; +end; + +procedure TForm1.ListView2KeyPress(Sender: TObject; var Key: Char); +begin +if key=#13 then ListView2DblClick(sender); +end; + +procedure TForm1.PageControl1Change(Sender: TObject); +begin +if speedbutton13.enabled then speedbutton13.click; +if speedbutton1.enabled then speedbutton1.click; +end; + +end. + diff --git a/EDITOR/radiant040/Unit2.pas b/EDITOR/radiant040/Unit2.pas new file mode 100644 index 0000000..075cf84 --- /dev/null +++ b/EDITOR/radiant040/Unit2.pas @@ -0,0 +1,35 @@ +unit Unit2; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, Buttons, ExtCtrls; + +type + TForm2 = class(TForm) + Label1: TLabel; + mapname: TEdit; + label2: TLabel; + desc: TEdit; + Label3: TLabel; + author: TEdit; + BitBtn1: TBitBtn; + BitBtn2: TBitBtn; + Bevel1: TBevel; + private + { Private declarations } + public + { Public declarations } + end; + +var + Form2: TForm2; + +implementation + +{$R *.DFM} + + + +end. diff --git a/EDITOR/radiant040/Unit2_loc.pas b/EDITOR/radiant040/Unit2_loc.pas new file mode 100644 index 0000000..cad09ed --- /dev/null +++ b/EDITOR/radiant040/Unit2_loc.pas @@ -0,0 +1,23 @@ +unit Unit2_loc; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; + +type + Tlocations = class(TForm) + private + { Private declarations } + public + { Public declarations } + end; + +var + locations: Tlocations; + +implementation + +{$R *.DFM} + +end. diff --git a/EDITOR/radiant040/Unit2_locsel.pas b/EDITOR/radiant040/Unit2_locsel.pas new file mode 100644 index 0000000..69edf0e --- /dev/null +++ b/EDITOR/radiant040/Unit2_locsel.pas @@ -0,0 +1,64 @@ +unit Unit2_locsel; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ComCtrls, ImgList; + +type + Tloc_sel = class(TForm) + ListView1: TListView; + Button1: TButton; + Button2: TButton; + ImageList1: TImageList; + procedure FormCreate(Sender: TObject); + procedure ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); + private + { Private declarations } + public + { Public declarations } + end; + +var + loc_sel: Tloc_sel; + itmsel_ : Tlistitem; + +implementation + +uses Unit4, unit1; + +{$R *.DFM} + +procedure addprop (st1,st2,st3,st4 : string); +var item : TListItem; +begin +Item := loc_sel.listview1.Items.add; +Item.caption := st1; +Item.SubItems.Add(st2); +Item.SubItems.Add(st3); +Item.SubItems.Add(st4); +end; + +procedure Tloc_sel.FormCreate(Sender: TObject); +var i: byte; +begin + listview1.items.Clear; + for i := 1 to 50 do + if LocationsArray[I].enabled then begin + addprop(inttostr(I), + inttostr(LocationsArray[I].x), + inttostr(LocationsArray[I].y), + LocationsArray[I].text); + end; +end; + +procedure Tloc_sel.ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); +begin + unit1.SELECTEDLOC := strtoint(Item.Caption); + Location_Modify(SELECTEDLOC); +end; + +end. diff --git a/EDITOR/radiant040/Unit4.pas b/EDITOR/radiant040/Unit4.pas new file mode 100644 index 0000000..af65005 --- /dev/null +++ b/EDITOR/radiant040/Unit4.pas @@ -0,0 +1,84 @@ +unit Unit4; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ImgList, ComCtrls; + +type + TForm4 = class(TForm) + ListView1: TListView; + ImageList1: TImageList; + Button1: TButton; + Button2: TButton; + procedure FormCreate(Sender: TObject); + procedure ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); + procedure Button1Click(Sender: TObject); + procedure Button2Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form4: TForm4; + +implementation +uses unit1; +{$R *.DFM} + +procedure addprop (st1,st2,st3,st4 : string); +var item : TListItem; +begin +item := form4.listview1.items.add; +item.caption := st1; +item.SubItems.Add(st2); +item.SubItems.Add(st3); +item.SubItems.Add(st4); +end; + + +procedure TForm4.FormCreate(Sender: TObject); +var s : shortstring; + i : byte; +begin +listview1.items.Clear; +unit1.SELECTEDOBJ := -1; +for i := 0 to $FF do if unit1.ddd[i].active = true then begin + case ddd[i].objtype of + 1 : s := 'teleport'; + 2 : s := 'button'; + 3 : s := 'door'; + 4 : s := 'trigger'; + 5 : s := 'area_push'; + 6 : s := 'area_pain'; + 7 : s := 'area_ta_end'; + 8 : s := 'area_teleport'; + 9 : s := 'doortrigger'; + 10 : s := 'area_waterillusion'; + end; + addprop(s,inttostr(i),inttostr(ddd[i].x),inttostr(ddd[i].y)); +end; +end; + +procedure TForm4.ListView1SelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); +begin +unit1.SELECTEDOBJ := strtoint(item.SubItems[0]); +end; + +procedure TForm4.Button1Click(Sender: TObject); +begin +close; +end; + +procedure TForm4.Button2Click(Sender: TObject); +begin +unit1.SELECTEDOBJ := -1; +close; +end; + +end. diff --git a/EDITOR/radiant040/Unit5.pas b/EDITOR/radiant040/Unit5.pas new file mode 100644 index 0000000..6cc4d2e --- /dev/null +++ b/EDITOR/radiant040/Unit5.pas @@ -0,0 +1,61 @@ +unit Unit5; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + Spin, StdCtrls, ExtCtrls; + +type + TForm5 = class(TForm) + Bevel1: TBevel; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + Label4: TLabel; + Edit1: TEdit; + Edit2: TEdit; + SpinEdit1: TSpinEdit; + SpinEdit2: TSpinEdit; + Label5: TLabel; + SpinEdit3: TSpinEdit; + Label6: TLabel; + Label7: TLabel; + Label8: TLabel; + Button1: TButton; + Label9: TLabel; + procedure FormCreate(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form5: TForm5; + +implementation +uses unit1; +{$R *.DFM} + +procedure TForm5.FormCreate(Sender: TObject); +begin +spinedit1.Value := unit1.BRICK_X; +spinedit2.Value := unit1.BRICK_Y; +spinedit3.Value := unit1.MAP_BG; +edit1.text := unit1.MAP_NAME; +edit2.text := unit1.MAP_AUTHOR; +end; + +procedure TForm5.Button1Click(Sender: TObject); +begin +unit1.BRICK_X := spinedit1.value; +unit1.BRICK_Y := spinedit2.value; +unit1.MAP_BG := spinedit3.value; +unit1.MAP_NAME := edit1.text; +unit1.MAP_AUTHOR := edit2.text; +close; +end; + +end. diff --git a/EDITOR/radiant040/Unit6.pas b/EDITOR/radiant040/Unit6.pas new file mode 100644 index 0000000..447b580 --- /dev/null +++ b/EDITOR/radiant040/Unit6.pas @@ -0,0 +1,61 @@ +unit Unit6; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls; + +type + TForm6 = class(TForm) + Memo1: TMemo; + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form6: TForm6; + +implementation +uses unit1; +{$R *.DFM} + + + +procedure TForm6.FormCreate(Sender: TObject); +var i,z : word; +r : boolean; +begin +memo1.clear; +for i := 0 to $FF do if ddd[i].active = true then begin + if ddd[i].objtype = 1 then begin + if bbb[ddd[i].x,ddd[i].y].image > 0 then + memo1.lines.add('>>> TELEPORT #'+inttostr(i)+' not stand on empty position.'); + if bbb[ddd[i].lenght ,ddd[i].dir ].image >= 36 then + memo1.lines.add('>>> TELEPORT #'+inttostr(i)+' teleport player to non empty position.'); + if ddd[i].y < 2 then + memo1.lines.add('>>> TELEPORT #'+inttostr(i)+' have incorrect "pos_y" value. it must be >= 2.'); + if ddd[i].dir < 2 then + memo1.lines.add('>>> TELEPORT #'+inttostr(i)+' have incorrect "goto_y" value. it must be >= 2.'); + end; + if ddd[i].objtype = 2 then begin + if bbb[ddd[i].x,ddd[i].y].image > 0 then + memo1.lines.add('>>> BUTTON #'+inttostr(i)+' not stand on empty position.'); + + if ddd[i].target = 0 then + memo1.lines.add('>>> BUTTON #'+inttostr(i)+' have not a target.'); + r := false; + if ddd[i].target > 0 then begin + for z := 0 to $FF do if ddd[z].active = true then + if (ddd[z].objtype = 2) and (ddd[z].targetname = ddd[i].target) then begin r := true; break; end; + if r = false then memo1.lines.add('>>> BUTTON #'+inttostr(i)+' have null target. door with same targetname does not exists.'); + end; + end; + end; +end; + + +end. diff --git a/EDITOR/radiant040/Unit7.pas b/EDITOR/radiant040/Unit7.pas new file mode 100644 index 0000000..a83370c --- /dev/null +++ b/EDITOR/radiant040/Unit7.pas @@ -0,0 +1,23 @@ +unit Unit7; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; + +type + TForm2 = class(TForm) + private + { Private declarations } + public + { Public declarations } + end; + +var + Form2: TForm2; + +implementation + +{$R *.DFM} + +end. diff --git a/EDITOR/radiant040/brshrepls.pas b/EDITOR/radiant040/brshrepls.pas new file mode 100644 index 0000000..5d92ee2 --- /dev/null +++ b/EDITOR/radiant040/brshrepls.pas @@ -0,0 +1,54 @@ +unit brshrepls; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ExtCtrls, Spin; + +type + TForm2_ = class(TForm) + SpinEdit1: TSpinEdit; + SpinEdit2: TSpinEdit; + Label1: TLabel; + Label2: TLabel; + Bevel1: TBevel; + Buttn1: TButton; + Button2: TButton; + procedure Buttn1Click(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure SpinEdit2KeyPress(Sender: TObject; var Key: Char); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form2_: TForm2_; + +implementation +uses unit1; +{$R *.DFM} + +procedure TForm2_.Buttn1Click(Sender: TObject); +var i, a: word; +begin +for i := 0 to BRICK_X - 1 do +for a := 0 to BRICK_Y - 1 do +if bbb[i,a].image = spinedit1.value then bbb[i,a].image := spinedit2.value; +BrushName; +close; +end; + +procedure TForm2_.Button2Click(Sender: TObject); +begin +close; +end; + +procedure TForm2_.SpinEdit2KeyPress(Sender: TObject; var Key: Char); +begin +//if key=#13 then Buttn1Click(sender); +end; + +end. diff --git a/EDITOR/radiant040/bz/PowerAcrModuleInfo.pas b/EDITOR/radiant040/bz/PowerAcrModuleInfo.pas new file mode 100644 index 0000000..1b8b772 --- /dev/null +++ b/EDITOR/radiant040/bz/PowerAcrModuleInfo.pas @@ -0,0 +1,25 @@ +Unit PowerAcrModuleInfo; + +Interface + +Const + PowerArcModuleSignature = 'AA6F3C60-37D7-11D4-B4BF-D80DBEC04C01'; + +Type + TPowerArcModuleInfo = Packed Record + Signature: PChar; // must be eq to PowerArcModuleSignature + Name: PChar; // short name + Description: PChar; // full description + Options: PChar; // opt list delimited with #0 + // bit per char on calgary corpus *100 + DefaultBPC: integer; + MaxBPC: integer; + Case integer Of // unique + 0: (ModuleID: Packed Array[0..7] Of Char); + 1: (ModuleIDW: Packed Array[0..1] Of integer); + End; + PPowerArcModuleInfo = ^TPowerArcModuleInfo; + +Implementation + +End. diff --git a/EDITOR/radiant040/bz/PowerArc.pas b/EDITOR/radiant040/bz/PowerArc.pas new file mode 100644 index 0000000..88d35be --- /dev/null +++ b/EDITOR/radiant040/bz/PowerArc.pas @@ -0,0 +1,673 @@ +unit PowerArc; + +{| PowerArc 1.3.1 /5 Apr 2001/ + | Copyright (c) 2000,2001 SoftLab MIL-TEC Ltd + | Web http://www.softcomplete.com + | Email support@softcomplete.com + | Data compression library for Delphi and C++ Builder + |} + +{------------------------------------------------------------------------------- + What's new in ver.1.3.1 + + change interface proc names + RegisterPowerArcModule -> PowerArcRegisterModule + SetOptions -> PowerArcSetOptions + Compress -> PowerArcCompress + Decompress -> PowerArcDecompress + + change param order in PowerArcCompress + was: + function PowerArcCompress(ArcIdx: integer; InStream,OutStream: TStream; + const ArcOpt: string = ''; ProgressCallback: TProgressCallback = nil): Boolean; + now: + function PowerArcCompress(InStream,OutStream: TStream; + ArcIdx: integer = iPowerBZIP; const ArcOpt: string = ''; + ProgressCallback: TProgressCallback = nil): Boolean; +-------------------------------------------------------------------------------- + What's new in ver.1.3 + + full progress callback support + + TProgressCallback changed type definition + + update BZIP core to ver.1.0.1 + + implementation BZIP as default built-in method + + RegisterPowerArcModule now check for dups + + fix memory leak: free Options list + + fix bug in Read/Write methods in implementation of stream interface +-------------------------------------------------------------------------------} + +interface + +uses SysUtils, Windows, Classes, PowerAcrModuleInfo, bzLib; + +type + EPowerArcError = class(Exception); + TProgressCallback = procedure (Current: integer) of object; + +const // default compression method + iPowerBZIP = 0; +var // loadable compression engines + iPowerZIP: integer = 0; + iPowerRANK: integer = 0; + iPowerPPM: integer = 0; + +function PowerArcRegisterModule(const Name: string): integer; + +procedure PowerArcSetOptions(ArcIdx: integer; const ArcOpt: string); + +function PowerArcCompress(InStream,OutStream: TStream; + ArcIdx: integer = iPowerBZIP; const ArcOpt: string = ''; + ProgressCallback: TProgressCallback = nil): Boolean; overload; + +function PowerArcCompress(const Buffer; Size: integer; OutStream: TStream; + ArcIdx: integer = iPowerBZIP; const ArcOpt: string = ''; + ProgressCallback: TProgressCallback = nil): Boolean; overload; + +function PowerArcDecompress(InStream,OutStream: TStream; + ProgressCallback: TProgressCallback = nil): Boolean; + +//============================ Stream interface ================================ + +type + +{ TPowerArcCompressStream compresses data on the fly as data is written to it, + and stores the compressed data to another stream. + + TPowerArcCompressStream is write-only and strictly sequential. Reading from the + stream will raise an exception. Using Seek to move the stream pointer + will raise an exception. + + Output data is cached internally, written to the output stream only when + the internal output buffer is full. All pending output data is flushed + when the stream is destroyed. + + The Position property returns the number of uncompressed bytes of + data that have been written to the stream so far. + + The OnProgress event is called each time the output buffer is filled and + written to the output stream. This is useful for updating a progress + indicator when you are writing a large chunk of data to the compression + stream in a single call.} + + TPowerArcCompressStream = class(TStream) + private + Base: TStream; + ArcIdx: integer; + ArcOpt: string; + Thread: TThread; + hReadPipe, + hWritePipe: THandle; + TotalWrited: integer; + BZCompressionStream: TBZCompressionStream; + FOnProgress: TProgressCallback; + procedure DoProgress(Current: integer); + public + constructor Create(BaseStream: TStream; FArcIdx: integer = iPowerBZIP; + const FArcOpt: string = ''); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress: TProgressCallback read FOnProgress write FOnProgress; + end; + +{ TPowerArcDecompressStream decompresses data on the fly as data is read from it. + + Compressed data comes from a separate source stream. TPowerArcDecompressStream + is read-only and unidirectional; you can seek forward in the stream, but not + backwards. The special case of setting the stream position to zero is + allowed. Seeking forward decompresses data until the requested position in + the uncompressed data has been reached. Seeking backwards, seeking relative + to the end of the stream, requesting the size of the stream, and writing to + the stream will raise an exception. + + The Position property returns the number of bytes of uncompressed data that + have been read from the stream so far. + + The OnProgress event is called each time the internal input buffer of + compressed data is exhausted and the next block is read from the input stream. + This is useful for updating a progress indicator when you are reading a + large chunk of data from the decompression stream in a single call.} + + TPowerArcDecompressStream = class(TStream) + private + Base: TStream; + ArcIdx: integer; + Thread: TThread; + hReadPipe, + hWritePipe: THandle; + TotalReaded: integer; + BZDecompressionStream: TBZDecompressionStream; + FOnProgress: TProgressCallback; + procedure DoProgress(Current: integer); + public + constructor Create(BaseStream: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress: TProgressCallback read FOnProgress write FOnProgress; + end; + +//============================================================================== + +type + // callback's + TReadFunc = function (Data: Pointer; var Buffer; Size: integer): integer; stdcall; + TWriteFunc = function (Data: Pointer; const Buffer; Size: integer): integer; stdcall; + // dll entryes + TPowerArcSetOptions = procedure (Opt: PChar); stdcall; + TPowerArcCompress = procedure (Data: Pointer; Opt: PChar; ReadFunc: TReadFunc; + WriteFunc: TWriteFunc); stdcall; + TPowerArcCompressMem = procedure (Data: Pointer; Opt: PChar; Mem: Pointer; + MemSize: integer; WriteFunc: TWriteFunc); stdcall; + TPowerArcDecompress = function (Data: Pointer; ReadFunc: TReadFunc; + WriteFunc: TWriteFunc): Boolean; stdcall; + // dll registration info + TPowerArcModule = record + Name: string; + hLib: THandle; + Info: PPowerArcModuleInfo; + Options: TStringList; + SetOptions: TPowerArcSetOptions; + Compress: TPowerArcCompress; + CompressMem: TPowerArcCompressMem; + Decompress: TPowerArcDecompress; + end; + +var + PowerArcModules: array of TPowerArcModule; + +implementation + +const + PipeSize = 4*4096; + +type + TPowerArcData = record + InStream,OutStream: TStream; + Current: integer; + ProgressCallback: TProgressCallback; + end; + +function ReadFunc(Data: Pointer; var Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcData(Data^).InStream.Read(Buffer,Size); + if Assigned(TPowerArcData(Data^).ProgressCallback) then begin + Inc(TPowerArcData(Data^).Current,Result); + TPowerArcData(Data^).ProgressCallback(TPowerArcData(Data^).Current); + end; +end; + +function WriteFunc(Data: Pointer; const Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcData(Data^).OutStream.Write(Buffer,Size); +end; + +function ValidArcIdx(ArcIdx: integer): Boolean; +begin + Result:=(ArcIdx >= 0) and (ArcIdx < Length(PowerArcModules)); +end; + +procedure PowerArcSetOptions(ArcIdx: integer; const ArcOpt: string); +begin + // no opt for default method + if (ArcIdx <> iPowerBZIP) and ValidArcIdx(ArcIdx) then + PowerArcModules[ArcIdx].SetOptions(PChar(ArcOpt)); +end; + +function PowerArcCompress(InStream,OutStream: TStream; + ArcIdx: integer; const ArcOpt: string; + ProgressCallback: TProgressCallback): Boolean; +var Data: TPowerArcData; +begin + Result:=False; + if ArcIdx = iPowerBZIP then begin + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompress(InStream,OutStream,ProgressCallback); + Result:=True; + end else if ValidArcIdx(ArcIdx) then try + Data.InStream:=InStream; + Data.OutStream:=OutStream; + Data.ProgressCallback:=ProgressCallback; + Data.Current:=0; + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + PowerArcModules[ArcIdx].Compress(@Data,PChar(ArcOpt),ReadFunc,WriteFunc); + Result:=True; + except + end; +end; + +type + TMapMemoryStream = class (TCustomMemoryStream) + private + FReadOnly: Boolean; + public + constructor Create(Buf: Pointer; Size: integer; ReadOnly: Boolean); + function Write(const Buffer; Count: integer): integer; override; + end; + +constructor TMapMemoryStream.Create(Buf: Pointer; Size: integer; ReadOnly: Boolean); +begin + inherited Create; + SetPointer(Buf,Size); + FReadOnly:=ReadOnly; +end; + +function TMapMemoryStream.Write(const Buffer; Count: integer): integer; +begin + if FReadOnly then Result:=0 + else begin + if Position+Count > Size then Result:=Size-Position + else Result:=Count; + Move(Buffer, Pointer(integer(Memory) + Position)^, Result); + Seek(Result,1); + end; +end; + +function PowerArcCompress(const Buffer; Size: integer; OutStream: TStream; + ArcIdx: integer; const ArcOpt: string; + ProgressCallback: TProgressCallback): Boolean; +var Data: TPowerArcData; + MapMemoryStream: TMapMemoryStream; +begin + if Assigned(ProgressCallback) then begin + if ArcIdx = iPowerBZIP then begin + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompress(Buffer,Size,OutStream,ProgressCallback); + Result:=True; + end else begin + MapMemoryStream:=TMapMemoryStream.Create(@Buffer,Size,True); + try + Result:=PowerArcCompress(MapMemoryStream,OutStream,ArcIdx,ArcOpt,ProgressCallback); + finally + MapMemoryStream.Free; + end; + end; + end else begin + Result:=False; + if ArcIdx = iPowerBZIP then begin + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompress(Buffer,Size,OutStream); + Result:=True; + end else if ValidArcIdx(ArcIdx) then try + Data.OutStream:=OutStream; + OutStream.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + PowerArcModules[ArcIdx].CompressMem(@Data,PChar(ArcOpt),@Buffer,Size,WriteFunc); + Result:=True; + except + end; + end; +end; + +function PowerArcDecompress(InStream,OutStream: TStream; + ProgressCallback: TProgressCallback): Boolean; +var ModuleID: packed array[0..7] of Char; + j: integer; + Data: TPowerArcData; +begin + Result:=False; + InStream.Read(ModuleID[0],8); + for j:=0 to Length(PowerArcModules)-1 do + if PowerArcModules[j].Info^.ModuleID = ModuleID then try + if j = iPowerBZIP then + BZDecompress(InStream,OutStream) + else begin + Data.InStream:=InStream; + Data.OutStream:=OutStream; + Data.ProgressCallback:=ProgressCallback; + Data.Current:=0; + PowerArcModules[j].Decompress(@Data,ReadFunc,WriteFunc); + end; + Result:=True; + Exit; + except + end; +end; + +function PowerArcRegisterModule(const Name: string): integer; +type TGetPowerArcModuleInfo = function: PPowerArcModuleInfo; +var PowerArcModule: TPowerArcModule; + GetPowerArcModuleInfo: TGetPowerArcModuleInfo; + POpt: PChar; + j: integer; +begin + Result:=-1; + PowerArcModule.hLib:=LoadLibrary(PChar(Name)); + if PowerArcModule.hLib <> 0 then begin + PowerArcModule.Name:=Name; + GetPowerArcModuleInfo:=TGetPowerArcModuleInfo(GetProcAddress(PowerArcModule.hLib, + 'GetPowerArcModuleInfo')); + PowerArcModule.Info:=GetPowerArcModuleInfo; + // check that module exists + for j:=0 to Length(PowerArcModules)-1 do + if PowerArcModules[j].Info^.ModuleID = PowerArcModule.Info.ModuleID then begin + Result:=j; + FreeLibrary(PowerArcModule.hLib); + Exit; + end; + // continue init + PowerArcModule.SetOptions:=TPowerArcSetOptions(GetProcAddress(PowerArcModule.hLib,'SetOptions')); + PowerArcModule.Compress:=TPowerArcCompress(GetProcAddress(PowerArcModule.hLib,'Compress')); + PowerArcModule.CompressMem:=TPowerArcCompressMem(GetProcAddress(PowerArcModule.hLib,'CompressMem')); + PowerArcModule.Decompress:=TPowerArcDecompress(GetProcAddress(PowerArcModule.hLib,'Decompress')); + if Assigned(GetPowerArcModuleInfo) and + (PowerArcModule.Info^.Signature = PowerArcModuleSignature) and + Assigned(PowerArcModule.SetOptions) and + Assigned(PowerArcModule.Compress) and + Assigned(PowerArcModule.CompressMem) and + Assigned(PowerArcModule.Decompress) then begin + PowerArcModule.Options:=TStringList.Create; + POpt:=PowerArcModule.Info^.Options; + while POpt^ <> #0 do begin + PowerArcModule.Options.Add(POpt); + POpt:=POpt+StrLen(POpt)+1; + end; + SetLength(PowerArcModules,Length(PowerArcModules)+1); + PowerArcModules[Length(PowerArcModules)-1]:=PowerArcModule; + Result:=Length(PowerArcModules)-1; + end else + FreeLibrary(PowerArcModule.hLib); + end; +end; + +procedure PowerArcUnregisterModules; +var j: integer; +begin + for j:=0 to Length(PowerArcModules)-1 do begin + if PowerArcModules[j].hLib <> 0 then + FreeLibrary(PowerArcModules[j].hLib); + PowerArcModules[j].Options.Free; + end; + PowerArcModules:=nil; +end; + +{ TCompressThread } + +type + TCompressThread = class(TThread) + private + Done: Boolean; + CompressStream: TPowerArcCompressStream; + protected + procedure Execute; override; + end; + +{ TCompressThread } + +function ReadCompressFunc(Data: Pointer; var Buffer; Size: integer): integer; stdcall; +begin + if not Windows.ReadFile(TPowerArcCompressStream(Data).hReadPipe,Buffer,Size,DWORD(Result),nil) then + Result:=-1; +end; + +function WriteCompressFunc(Data: Pointer; const Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcCompressStream(Data).Base.Write(Buffer,Size); +end; + +procedure TCompressThread.Execute; +begin + try + CompressStream.Base.Write(PowerArcModules[CompressStream.ArcIdx].Info^.ModuleID[0],8); + PowerArcModules[CompressStream.ArcIdx].Compress(CompressStream, + PChar(CompressStream.ArcOpt),ReadCompressFunc,WriteCompressFunc); + except + end; + CloseHandle(CompressStream.hReadPipe); + Done:=True; +end; + +{ TPowerArcCompressStream } + +constructor TPowerArcCompressStream.Create(BaseStream: TStream; + FArcIdx: integer; const FArcOpt: string); +begin + inherited Create; + Base:=BaseStream; + ArcIdx:=FArcIdx; + ArcOpt:=FArcOpt; + Thread:=nil; + FOnProgress:=nil; + TotalWrited:=0; + if not ValidArcIdx(ArcIdx) then + raise EPowerArcError.Create('Invalid acrhive index'); + if ArcIdx = iPowerBZIP then begin + Base.Write(PowerArcModules[ArcIdx].Info^.ModuleID[0],8); + BZCompressionStream:=TBZCompressionStream.Create(Base); + BZCompressionStream.OnProgress:=DoProgress; + end else + BZCompressionStream:=nil; +end; + +destructor TPowerArcCompressStream.Destroy; +begin + if Thread <> nil then begin + CloseHandle(hWritePipe); + while not TCompressThread(Thread).Done do Sleep(0); + Thread.Free; + end; + if BZCompressionStream <> nil then + BZCompressionStream.Free; + inherited; +end; + +procedure TPowerArcCompressStream.DoProgress(Current: integer); +begin + if Assigned(FOnProgress) then FOnProgress(Current); +end; + +function TPowerArcCompressStream.Read(var Buffer; Count: Integer): Longint; +begin + raise EPowerArcError.Create('Invalid stream operation'); +end; + +function TPowerArcCompressStream.Seek(Offset: Integer; + Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := TotalWrited + else + raise EPowerArcError.Create('Invalid stream operation'); +end; + +function TPowerArcCompressStream.Write(const Buffer; + Count: Integer): Longint; +var Ret: Boolean; + ActualWrite: DWORD; + P: PChar; +begin + if ArcIdx = iPowerBZIP then + Result:=BZCompressionStream.Write(Buffer,Count) + else if Count > 0 then begin + if Thread = nil then begin + CreatePipe(hReadPipe,hWritePipe,nil,PipeSize); + Thread:=TCompressThread.Create(True); + TCompressThread(Thread).CompressStream:=Self; + TCompressThread(Thread).Done:=False; + Thread.FreeOnTerminate:=False; + Thread.Resume; + end; + //Windows.WriteFile(hWritePipe,Buffer,Count,DWORD(Result),nil); + Result:=0; + P:=PChar(@Buffer); + while Count > 0 do begin + Ret:=Windows.WriteFile(hWritePipe,P^,Count,ActualWrite,nil); + if not Ret or (Ret and (ActualWrite = 0)) then begin + if Result = 0 then Result:=-1; + Break; + end; + Dec(Count,ActualWrite); + Inc(Result,ActualWrite); + Inc(P,ActualWrite); + Sleep(0); + end; + end else + Result:=0; + if Result > 0 then begin + Inc(TotalWrited,Result); + if ArcIdx <> iPowerBZIP then + DoProgress(TotalWrited); + end; +end; + +{ TDecompressThread } + +type + TDecompressThread = class(TThread) + private + Done: Boolean; + DecompressStream: TPowerArcDecompressStream; + protected + procedure Execute; override; + end; + +{ TDecompressThread } + +function ReadDecompressFunc(Data: Pointer; var Buffer; Size: integer): integer; stdcall; +begin + Result:=TPowerArcDecompressStream(Data).Base.Read(Buffer,Size); +end; + +function WriteDecompressFunc(Data: Pointer; const Buffer; Size: integer): integer; stdcall; +begin + if not Windows.WriteFile(TPowerArcDecompressStream(Data).hWritePipe,Buffer,Size,DWORD(Result),nil) then + Result:=-1; +end; + +procedure TDecompressThread.Execute; +begin + try + PowerArcModules[DecompressStream.ArcIdx].Decompress(DecompressStream, + ReadDecompressFunc,WriteDecompressFunc); + except + end; + CloseHandle(DecompressStream.hWritePipe); + Done:=True; +end; + +{ TPowerArcDecompressStream } + +constructor TPowerArcDecompressStream.Create(BaseStream: TStream); +var ModuleID: packed array[0..7] of Char; + j: integer; +begin + inherited Create; + Base:=BaseStream; + Thread:=nil; + FOnProgress:=nil; + TotalReaded:=0; + if Base.Read(ModuleID[0],8) = 8 then + for j:=0 to Length(PowerArcModules)-1 do + if PowerArcModules[j].Info^.ModuleID = ModuleID then begin + if j = iPowerBZIP then begin + BZDecompressionStream:=TBZDecompressionStream.Create(Base); + BZDecompressionStream.OnProgress:=DoProgress; + end else + BZDecompressionStream:=nil; + ArcIdx:=j; + Exit; + end; + raise EPowerArcError.Create('Invalid acrhive index'); +end; + +destructor TPowerArcDecompressStream.Destroy; +begin + if Thread <> nil then begin + CloseHandle(hReadPipe); + while not TDecompressThread(Thread).Done do Sleep(0); + Thread.Free; + end; + if BZDecompressionStream <> nil then + BZDecompressionStream.Free; + inherited; +end; + +procedure TPowerArcDecompressStream.DoProgress(Current: integer); +begin + if Assigned(FOnProgress) then FOnProgress(Current); +end; + +function TPowerArcDecompressStream.Read(var Buffer; + Count: Integer): Longint; +var Ret: Boolean; + ActualRead: DWORD; + P: PChar; +begin + if ArcIdx = iPowerBZIP then + Result:=BZDecompressionStream.Read(Buffer,Count) + else if Count > 0 then begin + if Thread = nil then begin + CreatePipe(hReadPipe,hWritePipe,nil,PipeSize); + Thread:=TDecompressThread.Create(True); + TDecompressThread(Thread).DecompressStream:=Self; + TDecompressThread(Thread).Done:=False; + Thread.FreeOnTerminate:=False; + Thread.Resume; + end; + Result:=0; + P:=PChar(@Buffer); + while Count > 0 do begin + Ret:=Windows.ReadFile(hReadPipe,P^,Count,ActualRead,nil); + if not Ret or (Ret and (ActualRead = 0)) then begin + if Result = 0 then Result:=-1; + Break; + end; + Dec(Count,ActualRead); + Inc(Result,ActualRead); + Inc(P,ActualRead); + Sleep(0); + end; + end else + Result:=0; + if Result > 0 then begin + Inc(TotalReaded,Result); + if ArcIdx <> iPowerBZIP then + DoProgress(TotalReaded); + end; +end; + +function TPowerArcDecompressStream.Seek(Offset: Integer; + Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := TotalReaded + else + raise EPowerArcError.Create('Invalid stream operation'); +end; + +function TPowerArcDecompressStream.Write(const Buffer; + Count: Integer): Longint; +begin + raise EPowerArcError.Create('Invalid stream operation'); +end; + +// register default compression engine +procedure RegisterBZIP; +var POpt: PChar; +begin + SetLength(PowerArcModules,1); + with PowerArcModules[iPowerBZIP] do begin + Name:=''; + hLib:=0; + Info:=BZGetPowerArcModuleInfo; + Options:=TStringList.Create; + POpt:=Info^.Options; + while POpt^ <> #0 do begin + Options.Add(POpt); + POpt:=POpt+StrLen(POpt)+1; + end; + SetOptions:=nil; + Compress:=nil; + CompressMem:=nil; + Decompress:=nil; + end; +end; + +{ TCallbackObj } + +initialization + RegisterBZIP; + iPowerRANK:=PowerArcRegisterModule('PowerRANK.dll'); + iPowerZIP:=PowerArcRegisterModule('PowerZIP.dll'); + iPowerPPM:=PowerArcRegisterModule('PowerPPM.dll'); +finalization + PowerArcUnregisterModules; +end. diff --git a/EDITOR/radiant040/bz/bzLib.pas b/EDITOR/radiant040/bz/bzLib.pas new file mode 100644 index 0000000..f4c34a2 --- /dev/null +++ b/EDITOR/radiant040/bz/bzLib.pas @@ -0,0 +1,501 @@ +{*******************************************************} +{ } +{ BZIP2 1.0 Data Compression Interface Unit } +{ } +{*******************************************************} + +Unit bzLib; + +Interface + +Uses SysUtils, Classes, PowerAcrModuleInfo; + +Type + TAlloc = Function(opaque: Pointer; Items, size: integer): Pointer; cdecl; + TFree = Procedure(opaque, Block: Pointer); cdecl; + + // Internal structure. Ignore. + TBZStreamRec = Packed Record + next_in: PChar; // next input byte + avail_in: longword; // number of bytes available at next_in + total_in: int64; // total nb of input bytes read so far + + next_out: PChar; // next output byte should be put here + avail_out: longword; // remaining free space at next_out + total_out: int64; // total nb of bytes output so far + + state: Pointer; + + bzalloc: TAlloc; // used to allocate the internal state + bzfree: TFree; // used to free the internal state + opaque: Pointer; + End; + + TProgressEvent = Procedure(Current: integer) Of Object; + // Abstract ancestor class + TCustomBZip2Stream = Class(TStream) + Private + FStrm: TStream; + FStrmPos: integer; + FOnProgress: TProgressEvent; + FBZRec: TBZStreamRec; + FBuffer: Array[Word] Of Char; + Protected + Procedure Progress(Sender: TObject); Dynamic; + Public + Constructor Create(Strm: TStream); + Property OnProgress: TProgressEvent Read FOnProgress Write FOnProgress; + End; + + TBZCompressionStream = Class(TCustomBZip2Stream) + Public + Constructor Create(Dest: TStream); + Destructor Destroy; Override; + Function Read(Var Buffer; Count: LongInt): LongInt; Override; + Function write(Const Buffer; Count: LongInt): LongInt; Override; + Function Seek(Offset: LongInt; Origin: Word): LongInt; Override; + Property OnProgress; + End; + + TBZDecompressionStream = Class(TCustomBZip2Stream) + Public + Constructor Create(Source: TStream); + Destructor Destroy; Override; + Function Read(Var Buffer; Count: LongInt): LongInt; Override; + Function write(Const Buffer; Count: LongInt): LongInt; Override; + Function Seek(Offset: LongInt; Origin: Word): LongInt; Override; + Property OnProgress; + End; + + { CompressBuf compresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +Procedure BZCompressBuf(Const InBuf: Pointer; InBytes: integer; + Out OutBuf: Pointer; Out OutBytes: integer); + +{ DecompressBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + OutEstimate = zero, or est. size of the decompressed data + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +Procedure BZDecompressBuf(Const InBuf: Pointer; InBytes: integer; + OutEstimate: integer; Out OutBuf: Pointer; Out OutBytes: integer); + +Procedure BZCompress(Const Buffer; size: integer; OutStream: TStream; + ProgressCallback: TProgressEvent = Nil); overload; +Procedure BZCompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent = Nil); overload; +Procedure BZDecompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent = Nil); + +Type + EBZip2Error = Class(Exception); + EBZCompressionError = Class(EBZip2Error); + EBZDecompressionError = Class(EBZip2Error); + + // -------------------------- PowerArc specific -------------------------------- + +Function BZGetPowerArcModuleInfo: PPowerArcModuleInfo; + +Implementation + +{$L blocksort.obj} +{$L huffman.obj} +{$L compress.obj} +{$L decompress.obj} +{$L bzlib2.obj} +{$L crctable.obj} +{$L randtable.obj} + +Procedure _BZ2_hbMakeCodeLengths; External; +Procedure _BZ2_blockSort; External; +Procedure _BZ2_hbCreateDecodeTables; External; +Procedure _BZ2_hbAssignCodes; External; +Procedure _BZ2_compressBlock; External; +Procedure _BZ2_decompress; External; + +Const + BZ_RUN = 0; + BZ_FLUSH = 1; + BZ_FINISH = 2; + BZ_OK = 0; + BZ_RUN_OK = 1; + BZ_FLUSH_OK = 2; + BZ_FINISH_OK = 3; + BZ_STREAM_END = 4; + BZ_SEQUENCE_ERROR = (-1); + BZ_PARAM_ERROR = (-2); + BZ_MEM_ERROR = (-3); + BZ_DATA_ERROR = (-4); + BZ_DATA_ERROR_MAGIC = (-5); + BZ_IO_ERROR = (-6); + BZ_UNEXPECTED_EOF = (-7); + BZ_OUTBUFF_FULL = (-8); + + BZ_LEVEL = 9; + +Procedure _bz_internal_error(errcode: integer); Cdecl; +Begin + Raise EBZip2Error.CreateFmt('Compression Error %d', [errcode]); +End; + +Function _malloc(size: integer): Pointer; Cdecl; +Begin + GetMem(result, size); +End; + +Procedure _free(Block: Pointer); Cdecl; +Begin + FreeMem(Block); +End; + +// deflate compresses data + +Function BZ2_bzCompressInit(Var Strm: TBZStreamRec; BlockSize: integer; + verbosity: integer; workFactor: integer): integer; Stdcall; External; + +Function BZ2_bzCompress(Var Strm: TBZStreamRec; Action: integer): integer; + Stdcall; External; + +Function BZ2_bzCompressEnd(Var Strm: TBZStreamRec): integer; Stdcall; External; + +Function BZ2_bzBuffToBuffCompress(Dest: Pointer; Var destLen: integer; Source: + Pointer; + sourceLen, BlockSize, verbosity, workFactor: integer): integer; Stdcall; + External; + +// inflate decompresses data + +Function BZ2_bzDecompressInit(Var Strm: TBZStreamRec; verbosity: integer; + small: integer): integer; Stdcall; External; + +Function BZ2_bzDecompress(Var Strm: TBZStreamRec): integer; Stdcall; External; + +Function BZ2_bzDecompressEnd(Var Strm: TBZStreamRec): integer; Stdcall; + External; + +Function BZ2_bzBuffToBuffDecompress(Dest: Pointer; Var destLen: integer; Source: + Pointer; + sourceLen, small, verbosity: integer): integer; Stdcall; External; + +Function bzip2AllocMem(AppData: Pointer; Items, size: integer): Pointer; Cdecl; +Begin + GetMem(result, Items * size); +End; + +Procedure bzip2FreeMem(AppData, Block: Pointer); Cdecl; +Begin + FreeMem(Block); +End; + +Function CCheck(code: integer): integer; +Begin + result := code; + If code < 0 Then + Raise EBZCompressionError.CreateFmt('error %d', [code]); //!! +End; + +Function DCheck(code: integer): integer; +Begin + result := code; + If code < 0 Then + Raise EBZDecompressionError.CreateFmt('error %d', [code]); //!! +End; + +Procedure BZCompressBuf(Const InBuf: Pointer; InBytes: integer; + Out OutBuf: Pointer; Out OutBytes: integer); +Var + Strm : TBZStreamRec; + p : Pointer; +Begin + FillChar(Strm, Sizeof(Strm), 0); + Strm.bzalloc := bzip2AllocMem; + Strm.bzfree := bzip2FreeMem; + OutBytes := ((InBytes + (InBytes Div 10) + 12) + 255) And Not 255; + GetMem(OutBuf, OutBytes); + Try + Strm.next_in := InBuf; + Strm.avail_in := InBytes; + Strm.next_out := OutBuf; + Strm.avail_out := OutBytes; + CCheck(BZ2_bzCompressInit(Strm, BZ_LEVEL, 0, 0)); + Try + While CCheck(BZ2_bzCompress(Strm, BZ_FINISH)) <> BZ_STREAM_END Do + Begin + p := OutBuf; + Inc(OutBytes, 256); + ReallocMem(OutBuf, OutBytes); + Strm.next_out := PChar(integer(OutBuf) + (integer(Strm.next_out) - + integer(p))); + Strm.avail_out := 256; + End; + Finally + CCheck(BZ2_bzCompressEnd(Strm)); + End; + ReallocMem(OutBuf, Strm.total_out); + OutBytes := Strm.total_out; + Except + FreeMem(OutBuf); + Raise + End; +End; + +Procedure BZDecompressBuf(Const InBuf: Pointer; InBytes: integer; + OutEstimate: integer; Out OutBuf: Pointer; Out OutBytes: integer); +Var + Strm : TBZStreamRec; + p : Pointer; + BufInc : integer; +Begin + FillChar(Strm, Sizeof(Strm), 0); + Strm.bzalloc := bzip2AllocMem; + Strm.bzfree := bzip2FreeMem; + BufInc := (InBytes + 255) And Not 255; + If OutEstimate = 0 Then + OutBytes := BufInc + Else + OutBytes := OutEstimate; + GetMem(OutBuf, OutBytes); + Try + Strm.next_in := InBuf; + Strm.avail_in := InBytes; + Strm.next_out := OutBuf; + Strm.avail_out := OutBytes; + DCheck(BZ2_bzDecompressInit(Strm, 0, 0)); + Try + While DCheck(BZ2_bzDecompress(Strm)) <> BZ_STREAM_END Do + Begin + p := OutBuf; + Inc(OutBytes, BufInc); + ReallocMem(OutBuf, OutBytes); + Strm.next_out := PChar(integer(OutBuf) + (integer(Strm.next_out) - + integer(p))); + Strm.avail_out := BufInc; + End; + Finally + DCheck(BZ2_bzDecompressEnd(Strm)); + End; + ReallocMem(OutBuf, Strm.total_out); + OutBytes := Strm.total_out; + Except + FreeMem(OutBuf); + Raise + End; +End; + +// TCustomBZip2Stream + +Constructor TCustomBZip2Stream.Create(Strm: TStream); +Begin + Inherited Create; + FStrm := Strm; + FStrmPos := Strm.Position; + FBZRec.bzalloc := bzip2AllocMem; + FBZRec.bzfree := bzip2FreeMem; +End; + +Procedure TCustomBZip2Stream.Progress(Sender: TObject); +Begin + If Assigned(FOnProgress) Then FOnProgress(Position); +End; + +// TBZCompressionStream + +Constructor TBZCompressionStream.Create(Dest: TStream); +Begin + Inherited Create(Dest); + FBZRec.next_out := FBuffer; + FBZRec.avail_out := Sizeof(FBuffer); + CCheck(BZ2_bzCompressInit(FBZRec, BZ_LEVEL, 0, 0)); +End; + +Destructor TBZCompressionStream.Destroy; +Begin + FBZRec.next_in := Nil; + FBZRec.avail_in := 0; + Try + If FStrm.Position <> FStrmPos Then FStrm.Position := FStrmPos; + While (CCheck(BZ2_bzCompress(FBZRec, BZ_FINISH)) <> BZ_STREAM_END) + And (FBZRec.avail_out = 0) Do + Begin + FStrm.WriteBuffer(FBuffer, Sizeof(FBuffer)); + FBZRec.next_out := FBuffer; + FBZRec.avail_out := Sizeof(FBuffer); + End; + If FBZRec.avail_out < Sizeof(FBuffer) Then + FStrm.WriteBuffer(FBuffer, Sizeof(FBuffer) - FBZRec.avail_out); + Finally + BZ2_bzCompressEnd(FBZRec); + End; + Inherited Destroy; +End; + +Function TBZCompressionStream.Read(Var Buffer; Count: LongInt): LongInt; +Begin + Raise EBZCompressionError.Create('Invalid stream operation'); +End; + +Function TBZCompressionStream.write(Const Buffer; Count: LongInt): LongInt; +Begin + FBZRec.next_in := @Buffer; + FBZRec.avail_in := Count; + If FStrm.Position <> FStrmPos Then FStrm.Position := FStrmPos; + While (FBZRec.avail_in > 0) Do + Begin + CCheck(BZ2_bzCompress(FBZRec, BZ_RUN)); + If FBZRec.avail_out = 0 Then + Begin + FStrm.WriteBuffer(FBuffer, Sizeof(FBuffer)); + FBZRec.next_out := FBuffer; + FBZRec.avail_out := Sizeof(FBuffer); + FStrmPos := FStrm.Position; + End; + Progress(Self); + End; + result := Count; +End; + +Function TBZCompressionStream.Seek(Offset: LongInt; Origin: Word): LongInt; +Begin + If (Offset = 0) And (Origin = soFromCurrent) Then + result := FBZRec.total_in + Else + Raise EBZCompressionError.Create('Invalid stream operation'); +End; + +// TDecompressionStream + +Constructor TBZDecompressionStream.Create(Source: TStream); +Begin + Inherited Create(Source); + FBZRec.next_in := FBuffer; + FBZRec.avail_in := 0; + DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); +End; + +Destructor TBZDecompressionStream.Destroy; +Begin + BZ2_bzDecompressEnd(FBZRec); + Inherited Destroy; +End; + +Function TBZDecompressionStream.Read(Var Buffer; Count: LongInt): LongInt; +Begin + FBZRec.next_out := @Buffer; + FBZRec.avail_out := Count; + If FStrm.Position <> FStrmPos Then FStrm.Position := FStrmPos; + While (FBZRec.avail_out > 0) Do + Begin + If FBZRec.avail_in = 0 Then + Begin + FBZRec.avail_in := FStrm.Read(FBuffer, Sizeof(FBuffer)); + If FBZRec.avail_in = 0 Then + Begin + result := Count - FBZRec.avail_out; + exit; + End; + FBZRec.next_in := FBuffer; + FStrmPos := FStrm.Position; + End; + CCheck(BZ2_bzDecompress(FBZRec)); + Progress(Self); + End; + result := Count; +End; + +Function TBZDecompressionStream.write(Const Buffer; Count: LongInt): LongInt; +Begin + Raise EBZDecompressionError.Create('Invalid stream operation'); +End; + +Function TBZDecompressionStream.Seek(Offset: LongInt; Origin: Word): LongInt; +Begin + If (Offset >= 0) And (Origin = soFromCurrent) Then + result := FBZRec.total_out + Else + Raise EBZDecompressionError.Create('Invalid stream operation'); + +End; + +Procedure CopyStream(Src, Dst: TStream); +Const + BufSize = 4096; +Var + Buf : Array[0..BufSize - 1] Of byte; + readed : integer; +Begin + If (Src <> Nil) And (Dst <> Nil) Then + Begin + readed := Src.Read(Buf[0], BufSize); + While readed > 0 Do + Begin + Dst.write(Buf[0], readed); + readed := Src.Read(Buf[0], BufSize); + End; + End; +End; + +Procedure BZCompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent); +Var + CompressionStream: TBZCompressionStream; +Begin + CompressionStream := TBZCompressionStream.Create(OutStream); + Try + CompressionStream.OnProgress := ProgressCallback; + CopyStream(InStream, CompressionStream); + Finally + CompressionStream.free; + End; +End; + +Procedure BZDecompress(InStream, OutStream: TStream; ProgressCallback: + TProgressEvent); +Var + DecompressionStream: TBZDecompressionStream; +Begin + DecompressionStream := TBZDecompressionStream.Create(InStream); + Try + DecompressionStream.OnProgress := ProgressCallback; + CopyStream(DecompressionStream, OutStream); + Finally + DecompressionStream.free; + End; +End; + +Procedure BZCompress(Const Buffer; size: integer; OutStream: TStream; + ProgressCallback: TProgressEvent); +Var + CompressionStream: TBZCompressionStream; +Begin + CompressionStream := TBZCompressionStream.Create(OutStream); + Try + CompressionStream.OnProgress := ProgressCallback; + CompressionStream.write(Buffer, size); + Finally + CompressionStream.free; + End; +End; + +// -------------------------- PowerArc specific -------------------------------- + +Const + BZIPModuleInfo: TPowerArcModuleInfo = ( + Signature: PowerArcModuleSignature; + Name: 'BZIP'; + Description: ''; + Options: #0#0; + DefaultBPC: 209; + MaxBPC: 209; + ModuleID: 'BZIP0001'; + ); + +Function BZGetPowerArcModuleInfo: PPowerArcModuleInfo; +Begin + result := @BZIPModuleInfo; +End; + +End. diff --git a/EDITOR/radiant040/palette_unit.pas b/EDITOR/radiant040/palette_unit.pas new file mode 100644 index 0000000..b1d7d4a --- /dev/null +++ b/EDITOR/radiant040/palette_unit.pas @@ -0,0 +1,156 @@ +unit palette_unit; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ExtCtrls, ExtDlgs, shellapi; + +type + Tpalette = class(TForm) + Bevel1: TBevel; + Label1: TLabel; + Button1: TButton; + Label2: TLabel; + Button2: TButton; + Button3: TButton; + Bevel2: TBevel; + Image1: TImage; + OPD1: TOpenPictureDialog; + CheckBox1: TCheckBox; + Panel1: TPanel; + Button4: TButton; + Button5: TButton; + SaveDialog1: TSaveDialog; + procedure FormShow(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure Button3Click(Sender: TObject); + procedure Panel1Click(Sender: TObject); + procedure CheckBox1Click(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Button4Click(Sender: TObject); + procedure Button5Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + palette: Tpalette; + +implementation +uses unit1; +{$R *.DFM} + +procedure Tpalette.FormShow(Sender: TObject); +begin +if CUSTOMPALITRE then label1.caption :='Current Brick Palette: CUSTOM' else +label1.caption :='Current Brick Palette: DEFAULT'; + +Image1.Picture.Bitmap.Assign(PaletteFile); +image1.Update; + +image1.visible := CUSTOMPALITRE; + +button1.visible := CUSTOMPALITRE; +button2.visible := not CUSTOMPALITRE; +button5.visible := CUSTOMPALITRE; +CheckBox1.visible := CUSTOMPALITRE; +Panel1.visible := CheckBox1.checked; + +end; + +procedure Tpalette.Button2Click(Sender: TObject); +begin +if not opd1.execute then exit; +PaletteFile.LoadFromFile(opd1.filename); + +PaletteStream.Clear; +PaletteStream.LoadFromFile(opd1.filename); + +if (PaletteFile.Width > 256) or + (PaletteFile.Height > 256) then begin + Showmessage('Can''t use this bitmap'+#13+'Width (Height) must me less or equal 256'); + exit; + end; + +CUSTOMPALITRE := TRUE; +form1.ImageList.Items[7].Picture.LoadFromFile(opd1.filename); +form1.ImageList.Items[7].Transparent := CheckBox1.checked; +form1.ImageList.Items[7].TransparentColor := CUSTOMPALITRETRANSPARENTCOLOR; +form1.ImageList.Items[7].restore; +CUSTOMPALITREFILENAME := opd1.filename; + +FormShow(sender); + +end; + +procedure Tpalette.Button3Click(Sender: TObject); +begin +close; +end; + +procedure Tpalette.Panel1Click(Sender: TObject); +var cdlg : TColorDialog; +begin + if not CheckBox1.checked then exit; + cdlg := TColorDialog.Create(self); + cdlg.Color := CUSTOMPALITRETRANSPARENTCOLOR; + if not cdlg.Execute then exit; + panel1.color := cdlg.Color; + + if CUSTOMPALITRE then begin + CUSTOMPALITRETRANSPARENTCOLOR := cdlg.Color; + CUSTOMPALITRETRANSPARENT := CheckBox1.checked; + form1.ImageList.Items[7].Transparent := CheckBox1.checked; + form1.ImageList.Items[7].TransparentColor := CUSTOMPALITRETRANSPARENTCOLOR; + form1.ImageList.Items[7].restore; + end; + + cdlg.free; +end; + +// assign transparent +procedure Tpalette.CheckBox1Click(Sender: TObject); +begin +panel1.visible := checkbox1.checked; + + if CUSTOMPALITRE then begin + form1.ImageList.Items[7].Transparent := CheckBox1.checked; + CUSTOMPALITRETRANSPARENT := CheckBox1.checked; + form1.ImageList.Items[7].restore; + end; +end; + +// destroy palette +procedure Tpalette.Button1Click(Sender: TObject); +begin + CUSTOMPALITRE := FALSE; + CUSTOMPALITREFILENAME := ''; + Checkbox1.checked := false; + Formshow(sender); +end; + +procedure Tpalette.Button4Click(Sender: TObject); +begin +// Загрузка help файла +showmessage('You can import you own brick pallette. '+#13#13+'Brick pallette it is a BMP file'+#13+'which contain bricks graphics.'+#13+'Please check sample_brickpalette.bmp'); +//ShellExecute(Application.Handle,'open',pchar(extractfilepath(application.exename)+'\palettes\palettehelp.htm'),nil,nil,0); +end; + +procedure Tpalette.Button5Click(Sender: TObject); +begin + if savedialog1.execute then try + image1.picture.savetofile(savedialog1.filename); + except showmessage('An error occured while exporting palette file'); end; +end; + +procedure Tpalette.FormCreate(Sender: TObject); +begin + palette.CheckBox1.checked := CUSTOMPALITRETRANSPARENT; + palette.Panel1.color := CUSTOMPALITRETRANSPARENTCOLOR; +end; + +end. diff --git a/EDITOR/radiant040/palettes/palettehelp.htm b/EDITOR/radiant040/palettes/palettehelp.htm new file mode 100644 index 0000000..f78b975 --- /dev/null +++ b/EDITOR/radiant040/palettes/palettehelp.htm @@ -0,0 +1,7 @@ + + +NFK RADIANT

+ +Help file about NFK brick palettes. + + diff --git a/EDITOR/radiant040/radiant_help.htm b/EDITOR/radiant040/radiant_help.htm new file mode 100644 index 0000000..e895e19 --- /dev/null +++ b/EDITOR/radiant040/radiant_help.htm @@ -0,0 +1,112 @@ + + NFK help file + +

NFK RADIANT

version 035a
need for kill map editor
+

+BASIC INFO
+

+Чтобы начать делать карту надo "menu+file+new map" выбрать. Вся карта делится на брики (кирпичи). Слева вверху висит ящик такой - это палитра brush (короче кирпичи и предметы здесь разные лежат). Чтобы поставить кирпич, надо его выбрать в палитре и нажать пробел, shift - удаление. И он установится в текущее положение курсора. Аналогично ставятся предметы.
Свойства карты вы можете указать в "menu+configure+map properties". При создании своей карты не забудьте края карты уложить каким-нибудь кирпичом (чтобы игрок не вылетал за пределы). На карте должно присутствовать минимум 2 респавна. +

+SPECIAL OBJECTS - BASIC INFO
+C версии 030 в нфк есть специальные объекты. Их всего 9. Справа снизу есть панель спец объектов, все действия с объектами производятся оттуда. Чтобы создать объект, нажмите кнопку "New Obj". И выберите нужный объект. Чтобы начать редактирование объекта нажмите кнопку "Select" и выберите нужный объект. Все объекты имеют порядковые номера, и обозначаются вот так "#". По этому номеру вы легко сможете найти нужный вам объект. Чтобы удалить его нужно объект сначала выбрать а потом нажать "Delete". После выбора объекта в таблицу будут занесены его свойства, там вы можете редактировать эти свойства. По завершению редактирования, нажмите "APPLY". +

+SPECIAL OBJECTS - PROPERTIES
+TELEPORT (Портал)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+goto_x - телепортировать в X=.
+goto_y - телепортировать в Y=.

+ +BUTTON (Кнопка)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+color - цвет кнопки в активированном состоянии. 0=зеленая, 1=красная.
+wait - столько ждать при активации. Время измеряется в условных единицах времени. wait 50 = 1 сек, wait 100 = 2 сек.
+target - цель кнопки. (какой объект нужно активировать). если target=1, то у объекта, который нужно активировать, targetname тоже должен быть 1.
+shootable - [0\1], запретить\разрешить активацию от выстрелов.

+ +DOOR (Дверь)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+orientation - расположение двери. 0=Закрытая, горизонтальная; 1=Закрытая, вертикальная; 2=Открытая, горизонтальная; 3=Открытая, вертикальная.
+wait - столько ждать при активации. Время измеряется в условных единицах времени. wait 50 = 1 сек, wait 100 = 2 сек.
+targetname - название собственной цели. У объекта, который собирается активировать эту дверь, должен target стоять такой же как у этой двери targetname.
+lenght - длина двери (в бриках).
+fastclose - если дверь хочет закрыться, но игрок блокирует пространство, то дверь ждет еще wait времени, при fastclose=1, дверь закрывается сразу же, как игрок ушел с занятого места.

+ +TRIGGER (Регион)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+lenght_x - длина по X (в бриках).
+lenght_y - длина по Y (в бриках)
+wait - время обновления тригерра (если сомневаетесь оставьте 10). Время измеряется в условных единицах времени. wait 50 = 1 сек, wait 100 = 2 сек.
+target - цель триггера. (какой объект нужно активировать). если target=1, то у объекта, который нужно активировать, targetname тоже должен быть 1.

+ +AREA_PUSH (Регион толкания)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+lenght_x - длина по X (в бриках).
+lenght_y - длина по Y (в бриках)
+wait - время обновления тригерра (если сомневаетесь оставьте 10). Время измеряется в условных единицах времени. wait 50 = 1 сек, wait 100 = 2 сек.
+target - цель. В данном случае area_push может быть совсем без target.
+direction - направление толкания. 0=влево, 1=вверх, 2=вправо, 3=вниз.
+pushspeed - каждое wait время area_push толкает игроков со скоростью pushspeed.

+ +AREA_PAIN (Регион боли)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+lenght_x - длина по X (в бриках).
+lenght_y - длина по Y (в бриках).
+dmginterval - интервал нанесения повреждения. Время измеряется в условных единицах времени. wait 50 = 1 сек, wait 100 = 2 сек.
+dmg - столько повреждения area_pain будет наносить каждое dmginterval время.
+Если у area_pain targetname=0 то area_pain работает в 1ом режиме, иначе он работает во 2ом режиме.
+1ый режим: наносит dmg повреждения каждое dmginterval время.
+2ый режим: не наносит никакого dmg, пока не будет активирован. После активации в течении wait времени наносит dmg повреждениe каждое dmginterval время.
+wait - время "работы" area_pain. Время измеряется в условных единицах времени. wait 50 = 1 сек, wait 100 = 2 сек.

+ +AREA_TRIXARENA_END (Регион конца уровня (в trix arene))
+pos_x - позиция по X.
+pos_y - позиция по Y.
+lenght_x - длина по X (в бриках).
+lenght_y - длина по Y (в бриках).
+Когда сюда заходит игрок, то заканчивается игра и останавливается демка. На консоль выводится время затраченное на уровень. +

+ +AREA_TELEPORT (Регион телепортирования)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+lenght_x - длина по X (в бриках).
+lenght_y - длина по Y (в бриках).
+goto_x - телепортировать в X=.
+goto_y - телепортировать в Y=.

+ +DOORTRIGGER (Регион для открывания двери выстрелом)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+orientation - направление триггера. ставится параллельно двери.
+target - цель
+lenght - длина (в бриках).
+При выстреле активируется объект с targetname равное target. Прикосновением doortrigger не активируется.
+Учтите что doortrigger НЕ может быть внутри двери! Как правильно установить doortrigger смотрите в "map_ed\tutorialmaps\doortrigger.mapa"

+ +AREA_WATERILLUSION (Заплатка для воды. Чтобы ложить предметы под водой)
+pos_x - позиция по X.
+pos_y - позиция по Y.
+lenght_x - длина по X (в бриках).
+lenght_y - длина по Y (в бриках).
+Как правильно установить area_waterillusion смотрите в "tutorialmaps\waterillusion.mapa"
+
+ +


+ +MISC
+* Уже нанесенный brush можно выбрать кликнув правой кнопкой
+* Выбрать объект можно кликнув правой кнопкой на левом верхнем углу объекта
+* Скроллировать карту можно кнопками WSAD.
+* Стрелки курсора скроллируют brush. TAB+Стрелки курсора быстро скроллируют brush.
+* Загрузить карту из nfkbeta025 можно через "menu+conventer+load old beta025 map".
+* Редактировать свойство объекта можно дабл кликом или enter'ом.
+* Карты сохранять и загружать надо из basenfk\maps\
+

+ + diff --git a/EDITOR/radiant040/radiant_tutorial.htm b/EDITOR/radiant040/radiant_tutorial.htm new file mode 100644 index 0000000..dba4500 --- /dev/null +++ b/EDITOR/radiant040/radiant_tutorial.htm @@ -0,0 +1,43 @@ + + NFK help file + +MAY BE SOMEONE WANTS TO MAKE THIS TUTORIAL FOR ME?

NFK RADIANT TUTORIAL

version 035a
need for kill map editor
+

+TUTORIALS
+Здесь будет изложен краткий курс обучения NFK Radiant'у.
+TUTORIAL#1 - Создание хорошо проходимой мапы.
+Некоторые места в нфк трудно пропрыгать, например 1бриковые подъемы. В мапе +tutorialmaps\tmap1.mapa слева поставлен подъем который сложен для закарабкивания, а справа стоит простой.

+TUTORIAL#2 - Создание дверей и триггеров итп.
+Карта tutorialmaps\tmap2.mapa демонстрирует основные принципы действия этих объектов.
+Карта tutorialmaps\doortrigger.mapa демонстрирует действие объекта doortrigger.
+Карта tutorialmaps\waterillusion.mapa демонстрирует действие объекта area_waterillusion.
+Остальное допишу потом.
+

+RECOMENDATIONS
+- Не забывайте прописывать "Map properties".
+- Не оставляйте карту без бордюра из бриков.
+- Не делайте чтобы двери зажимали предметы, или точки выхода из порталов.
+- Не делайте такую карту из-за которого NFK будет глючить.
+- Не делайте чтобы выход из телепорта заносил игрока в брики
+

+MAP CREATION TIPS
+ +1. Не надо делать, чтобы телепорт вел "в стенку", то есть чтобы надо было менять направление ходьбы. Еще не надо делать, чтобы goto был выше, чем на три блока, иначе игрок респаунится на блоке.
+2. Не надо делать симметричные карты. Надо ориентироваться на сбалансированность карты, а не на то, как она будет смотреться.
+3. Надо стараться избегать таких мест, из которых можно выйти только одним способом. Такие места надо делать только для значимых предметов (megahealth, armor, powerup).
+4. Надо избегать узких и длинных коридоров и очень открытых пространств.
+5. Респауны желательно надо делать возле какого-то предмета, оружия. Респауны также надо ставить только на земле (надпись "RESPAWN" - это расположение ног).
+6. Не надо располагать сразу несколько оружий в одном месте.
+7. Также не советую ставить death'ы на карте.
+8. Не надо ставить все виды оружия на карте - только те, что самые необходимые.
+9. На карте обязательно должны иметься shotgun и rocket. Как мне помнится, в Q3 нет ни одной карты без этих оружий. Разве что на dm0 нет рокета, на остальных же он есть.
+10. Не советую делать такие блоки, на которые можно запрыгнуть "с трудом". Дело в том, что не каждый игрок может сделать подобный трикс и может попросту не запрыгнуть. Хотя так можно сделать, если туда можно пройти еще каким-то путем, без напряга.
+11. Желательно респауны надо ставить так, чтобы с одного не было видно другого.
+12. Не надо нарушать бордюр карты, то есть не надо делать дырки, двери, телепорты и другие предметы в бордюре.
+13. Не следует делать очень много jumpad'ов. Карта от этого становится неиграбельной. К тому же, в некоторых случаях джампад можно заменить на блок.
+14. Не следует ставить оружие там, где оно имеет преимущество над другим - баланс карты от этого существенно понизится.
+15. Надо тщательно тестировать карты - можно ли допрыгнуть куда-то или нельзя; возможно ли успеть добежать до двери, прежде, чем она закроется; ведет ли телепорт туда, куда вы хотели или нет.
+

+map creation tips взят с сайта http://n-f-k.narod.ru.
+ diff --git a/EDITOR/radiant040/teleport_dlg.pas b/EDITOR/radiant040/teleport_dlg.pas new file mode 100644 index 0000000..6bc127a --- /dev/null +++ b/EDITOR/radiant040/teleport_dlg.pas @@ -0,0 +1,54 @@ +unit teleport_dlg; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, Spin, ExtCtrls; + +type + TForm3 = class(TForm) + Button1: TButton; + Button2: TButton; + RadioButton1: TRadioButton; + RadioButton2: TRadioButton; + RadioButton3: TRadioButton; + RadioButton4: TRadioButton; + Bevel1: TBevel; + RadioButton5: TRadioButton; + RadioButton6: TRadioButton; + RadioButton7: TRadioButton; + RadioButton8: TRadioButton; + RadioButton9: TRadioButton; + RadioButton10: TRadioButton; + procedure FormKeyPress(Sender: TObject; var Key: Char); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form3: TForm3; + +implementation + +{$R *.DFM} + +procedure TForm3.FormKeyPress(Sender: TObject; var Key: Char); +begin +if key='1' then RadioButton1.SetFocus; +if key='2' then RadioButton2.SetFocus; +if key='3' then RadioButton3.SetFocus; +if key='4' then RadioButton4.SetFocus; +if key='5' then RadioButton5.SetFocus; +if key='6' then RadioButton6.SetFocus; +if key='7' then RadioButton7.SetFocus; +if key='8' then RadioButton8.SetFocus; +if key='9' then RadioButton9.SetFocus; +if key='0' then RadioButton10.SetFocus; +if key=#13 then button1.Click; +if key=#27 then button2.Click; +end; + +end. diff --git a/HELP/BOTSDK.DOC b/HELP/BOTSDK.DOC new file mode 100644 index 0000000..a426b0b Binary files /dev/null and b/HELP/BOTSDK.DOC differ diff --git a/HELP/botsdk.htm b/HELP/botsdk.htm new file mode 100644 index 0000000..5785f0f --- /dev/null +++ b/HELP/botsdk.htm @@ -0,0 +1,338 @@ + +NFK BOT SDK + +
+
+
NFK BOT DEVELOPMENT SDK ver 0.1 +By 3d[Power]
+http://www.3dpower.org +mailto:haz-3dpower@mail.ru + +Встроенные в NFK.EXE процедуры и функции. Вызываются из bot.dll. + +
+Function GetSystemVariable(text : string) : string; + +Возвращает значение системных переменных. + +Example: + Var RootDirectory : string; + begin + RootDirectory := GetSystemVariable('rootdir'); + End; + +Значения параметра text, задаются они в нижнем регистре: +rootdir - путь к рабочей папке нфк (c:\nfk\basenfk) +mapname - имя карты (tourney4), возвращается без расширения .mapa +mapfilename - полный путь к файлу карты (c:\nfk\basenfk\maps\tourney4.mapa). +mapinternalname - внутреннее имя карты (more frags & martini); +mapauthor - автор карты. +mapcrc32 - CRC32 карты. +playerscount - количество игроков. +playerscount_red - количество игроков которые в красной команде. +playerscount_blue - количество игроков которые в синей команде. +teamscore_red - количество очков красной команды. (team games only). +teamscore_blue - количество очков синей команды. (team games only). +gamesudden - идет ли сейчас sudden death. +timelimit - значение timelimit (в минутах). +fraglimit - значение fraglimit (в минутах). +capturelimit - значение capturelimit. +domlimit - значение domlimit. +overtime - значение overtime. +ctfflagstatus_red - статус красного флага (CTF). 0=base, 1=carried, 2=lost. +ctfflagstatus_blue - статус синего флага (CTF). 0=base, 1=carried, 2=lost. +time_min - текущее время. Минуты. (в партии). +time_sec - текущее время. Секунды. (в партии). +warmupleft - время до конца разыгровки. В секундах. (в партии). +gametype - возвращает режим игры (DM). +bricks_x - количество бриков по горизонтали. Отсчет начинается с 0, тоесть результат 29 - значит 30. +bricks_y - количество бриков по вертикали. Отсчет начинается с 0, тоесть результат 19 - значит 20. +nfkversion - версия NFK. +warmuparmor - значение консольной команды warmuparmor. +forcerespawn - значение консольной команды forcerespawn. +sv_maxplayers - значение консольной команды sv_maxplayers. +sv_teamdamage - значение консольной команды sv_teamdamage. +railarenainstagib - значение консольной команды railarenainstagib. + +
+Procedure AddMessage(text : string); + +Example: + AddMessage('Hi everybody'); + +Выводит text на консоль. (Тэги цвета - работают). + +
+Procedure sys_CreatePlayer(netname, nfkmodel : string; team : byte); + +Example + Sys_CreatePlayer('bot', 'sarge+red' ,0); + +Создает игрока, под управлением бота. +Netname - имя игрока. (player3). +Nfkmodel - модель игрока. (sarge+red). +Team - команда игрока. В не командных режимах игры, переменная игнорируется. + + Team. const +C_TEAMBLUE = 0; +C_TEAMRED = 1; +C_TEAMNON = 2; + +Вашему созданному боту назначается уникальный DXID. + +
+Procedure SetKeys(DXID: word; keys : byte); + +Нажатие кнопок у игрока, эта команда сработает только в случае если игрок - бот. + +DXID - уникальный DXID. +Keys - кнопки, они назначаются суммой. + + Keys. const +BKEY_MOVERIGHT = 1; +BKEY_MOVELEFT = 2; +BKEY_MOVEUP = 8; +BKEY_MOVEDOWN = 16; +BKEY_FIRE = 32; + +Example: + SetKeys(Players[I].DXID, BKEY_MOVERIGHT + BKEY_MOVEUP + BKEY_FIRE); + Нажаты кнопки вправо, вверх, выстрел. + +Чтобы проверить наличие кнопки: + + Var mykeys : byte; + Begin +Mykeys := BKEY_MOVERIGHT + BKEY_MOVEUP + BKEY_FIRE; +SetKeys(Players[I].DXID, Mykeys); +If mykeys and BKEY_MOVEUP = BKEY_MOVEUP then addmessage('I am jumping'); + End; + + +
+Procedure SetWeapon(DXID: word; weapon : byte); + +Выбрать оружие. + +DXID - уникальный DXID. +weapon - номер оружия. + + Weapon. const +C_WPN_GAUNTLET=0; +C_WPN_MACHINE=1; +C_WPN_SHOTGUN=2; +C_WPN_GRENADE=3; +C_WPN_ROCKET=4; +C_WPN_SHAFT=5; +C_WPN_RAIL=6; +C_WPN_PLASMA=7; +C_WPN_BFG=8; + +Example: + SetWeapon(players[I].DXID, C_WPN_ROCKET); + +Оружие включится в случае его наличия. + + +
+Function Test_Blocked(X, Y : word) : Boolean; + +Проверяет проходим ли брик в позиции X, Y + +Example: + if Test_Blocked (trunc(players[i].x + 15),trunc(players[i].y)) then // + (проверяет есть ли стена справа от выбранного игрока) + +
+Procedure debug_textout(x, y : word; text : string); + +Выводит текст в позиции X, Y. Используется для вывода дебаг информации, например пометка вэйпоинтов. + +Example: + debug_textout(100, 100, 'test1'); + +
+Procedure RegisterConsoleCommand(s: string); + +Регистрирует наличие добавленной вами консольной команды, в nfk.exe +(Вызывается из bot_register.pas в процедуре CMD_Register) + +
+function GetBrickStruct(x, y : word):TBrick; + +Возвращает record с содержимым брика в позиции x, y; + +{ +type TBrick = record // do not modify + image : byte; // graphix index + block : boolean; // do this brick block player; + respawntime : integer; // respawn time + y : shortint; + dir : byte; + oy : real; + respawnable : boolean; // is this shit can respawn? + scale : byte; + end; +} + +Например: + +Var tmp : Tbrick; + + Tmp := GetBrickStruct(1,1); + + tmp.image - это картинка брика, константы под image указаны в bot_defs.pas (IT_ARMOR например) + tmp.block - Проверяет проходим ли брик (взятие этой переменной аналогично Test_Blocked()) + tmp.respawntime - если брик это предмет, то если respawntime = 0 значит предмет есть, иначе respawntime означает сколько времени осталось до респавна предмета (в условных единицах времени) + tmp.y - не используется (вродебы) + tmp.dir - если это CTF флаг и dir=0 то флаг стоит на месте, иначе нет. если это DOM флаг, то dir показывает его цвет. Во всех других случаях dir не используется. + tmp.oy - не используется (вродебы) + tmp.respawnable - например аптечка respawnable, джамппад нет + tmp.scale - не используется + + +
+function GetObjStruct(ID : word):TObj; + +Доступ к массиву объектов. + +type TObj = record // do not modify + dead : byte; + speed,fallt,weapon,doublejump,refire : byte; + imageindex,dir,idd : byte; + clippixel : smallint; + spawnerDXID : word; + frame : byte; + health : smallint; + x,y,cx,cy,fangle,fspeed : real; + objname : string[30]; + DXID : word; + mass, InertiaX,InertiaY : real; + end; + + +Var tmp : Tbrick; + Tmp := GetObjStruct(0); + +Массив объектов objs: array [0..1000] of TObj; +Причем, если tmp.dead > 0 то данный объект не действителен. + +Допустим чтобы вам найти все запущенные ракеты на карте, нужно делать так: + for i := 0 to 1000 do + if GetObjStruct(i).dead=0 then + if GetObjStruct(i).objname='rocket' then ... + + +Данный тип был заведен достаточно давно, года 2 назад. Здесь большинство названий переменных не соотвествует действительности... +И массив не динамический (2 года назад я не умел делать другие). + +---------------------------- +Объект CTF FLAG +tmp.objname = 'flag' - уроненный CTF флаг. +tmp.x +tmp.y +tmp.imageindex - цвет +---------------------------- +Объект WEAPON +tmp.objname = 'weapon' - выпавшее оружие. +tmp.x +tmp.y +tmp.imageindex - ID оружия +---------------------------- +Объект GRENADE +tmp.objname = 'grenade' - запущенная граната. +tmp.x +tmp.y +tmp.spawnerDXID - DXID того кто ее запустил. +tmp.inertiax - velocity по X +tmp.inertiay - velocity по Y +tmp.clippixel - коробка вокруг гранаты, для зацепляния за брики +---------------------------- +Объект ROCKET +tmp.objname = 'rocket' - запущенная ракета. +tmp.x +tmp.y +tmp.spawnerDXID - DXID того кто ее запустил. +tmp.inertiax - velocity по X +tmp.inertiay - velocity по Y +tmp.clippixel - коробка вокруг ракеты, для зацепляния за брики +tmp.fallt - если 1 то это BFG снаряд +tmp.fangle - угол полета. Реальный угол полета angle = (fangle-90); + формула полета: + x := x + tmp.fspeed*CosTable[angle]; + y := y + tmp.fspeed*SinTable[angle]; +---------------------------- +Объект PLASMA +tmp.objname = 'plasma' - запущенная плазма. +tmp.x +tmp.y +tmp.spawnerDXID - DXID того кто ее запустил. +tmp.inertiax - velocity по X +tmp.inertiay - velocity по Y +tmp.clippixel - коробка вокруг плазмы, для зацепляния за брики +tmp.fangle - угол полета. Реальный угол полета angle = (fangle-90); + формула полета: + x := x + tmp.fspeed*CosTable[angle]; + y := y + tmp.fspeed*SinTable[angle]; +---------------------------- + +прочие objname: +shaft2, blood, smoke, shotgun, gauntlet, machine, rail, gib, shots, shots2, bubble, flash +(использовать их крайне не рекомендуется). + + + +
+function GetSpecObjStruct(ID : byte):TSpecObj; + +Доступ к массиву спец объектов. Таких как двери, кнопки, итп. +Массив объектов objs: array [0..1000] of TObj; + +type TSpecObj = record // do not modify + active : boolean; + x,y,lenght,dir,wait : word; + targetname,target,orient,nowanim,special:word; + objtype : byte; + end; + +Причем, если active = false то данный спец объект не действителен. + +Данный тип был заведен достаточно давно, года 2 назад. Здесь большинство названий переменных не соотвествует действительности... +И массив не динамический (2 года назад я не умел делать другие). + + +ужно делать так: + for i := 0 to 255 do + if GetSpecObjStruct(i).active then ... + else break; // при первом появлении active=false можно прекращать сканирование. + +------------------------ +tmp.objtype = 1 - teleporter +tmp.x - position X +tmp.y - position Y +tmp.lenght - destination X +tmp.dir - destination Y +------------------------ +tmp.objtype = 2 - button +tmp.x - position X +tmp.y - position Y +tmp.targetname - статус зажатости кнопки (1=зажата) +tmp.lenght - время зажатости, переменная уменьшается, при достижении 0, targetname становится 0 +tmp.wait - при нажатии lenght присваивается wait. +tmp.target - TARGET_ID. ищет door или area_pain у которого targetname=tmp.target и активирует его +------------------------ +tmp.objtype = 3 - door +tmp.orient - ориентация двери. (0=closed, horizontal ||| 1=closed, vertical ||| 2=opened, horizontal ||| 3=opened, vertical) +tmp.targetname - TARGET_ID. активируется by button, trigger, area_push. + +Дальше вспомнить и разобрать что там написано не смог, скажу только что +tmp.target и +tmp.dir +учавствуют в статусе двери (открытая \ закрытая) + +
+// happy bot development! ^_^ + +
+ + \ No newline at end of file diff --git a/HELP/nfk_help030.htm b/HELP/nfk_help030.htm new file mode 100644 index 0000000..ce4c13d --- /dev/null +++ b/HELP/nfk_help030.htm @@ -0,0 +1,188 @@ + + NFK help file + +Хэлп небыло времени делать, так что пока это просто склад мусора. Но прочитать советую.

NEED FOR KILL

v0.30
Created by 3d[Power]
visit homepage

+HOW TO START
+Ну собсна пока начать мона только с Hotseat'a (мультиплеера пока нет). В общем "окно хотсит":
+Слева список карт(выбираются они курсором (стрелка вниз, стрелка вверх)). Справа вы видите настройки игры. Там можно изменить свойства игроков.
1ый игрок играет на мышке. 2ой игрок играет на клавиатуре. Клаву можно перебиндить, и кнопки мыши.
В настройки матча входят 3 параметра "warmup, fraglimit,timelimit". Warmup - время на подготовку перед матчем. Fraglimit - Ограничение по фрагам. Timelimit - Ограничение по времени.
+По-скольку мы обычно играем дуэль. Короче стандартные настройки для 1v1 это: warmup 180; fraglimit 0; timelimit 10. Кстати в NFK есть Sudden Death. По поводу физики читайте в разделе "Physics".
Когда загрузилась карта и начался отчет можно на консоли набрать команду "ready" (или нажать F10) которая начнет матч без разыгровки. +

+CONTROLS
+Управление игрока 1:
+Левая кнопка мыши - стрелять; Взмах мыши вверх - смотреть вверх.Взмах мыши ввниз - смотреть ввниз. Скорость мыши настраивается консольной командой "sensitivity". +Подефалту курсором можно ходить. Кнопка NUM0 менять оружие.
+Управление игрока 2:
+Влево - A;
+Вправо - D;
+Вверх - W;
+Стрелять - R;
+Cледущ.оружие - Q;
+Смотреть вверх - T;
+Смотреть вних - F;
+Это конечно не особо удобное расположение кнопок, но вы можете его перебиндить. Я заметил что если хождение биндить слева клавы, а смотрение биндить в центр клавы, то зажимание кнопок значительно уменьшается. Подробнее читайте раздел "BINDINGS". +

+MODELS
+В нфк можно играть разными моделями (внешний вид игрока). Дополнительные модели можно скачать с powersite.narod.ru
Выбирать модель можно через окно player properties
или через консольную команду "model enforcer+blue","p2model enforcer+blue".
Теоретически вы можете создавать свои модели. Создаются они с помощью программы NMDL которую можете тоже найти на powersite.narod.ru +

+ +DEMOS
+В игре можно демы писать\проигрывать. Чтобы начать запись надо сначала стартануть игру (на карте). и написать команду "record mydemo1" или "autorecord". Когда матч закончится демка остановиться сама, но если вы хотите завершить запись до конца матча, то надо набрать "stoprecord". Проиграть демку можно из главного меню, в разделе DEMOS или консольной командой "demo mydemo1". +

+ +TRIX ARENA
+Это пока единственное развлечение в сингл плеере. Суть данной фичи это прохождение уровня за наименьшее время. (карта TRIX1.MAPA и другие). На сайте powersite.narod.ru есть таблица рекордов trix arenы. Примите участие. Подробнее на powersite.narod.ru. +

+ +BINDINGS
+УЧТИТЕ: что нельзя биндить сериями команд (например bind space "fire; nextweapon; kill"). и вообще, можно биндить только те команды которые находятся в бинд листе расположенном далее.

+(С версии nfkbeta030 можно биндить мышь, и полностью перебиндить мышиное управление на клаву). +По скольку я еще не сделал окно настройки управления, придется биндить через консоль. Это делается так:
bind {key} {action}
Ниже описано каким может быть параметр {key} +
+A,B,C,D....Z
+1,2,3..0
+shift, ctrl, alt, tab, space, capslock, num0, num1, num2, num3, num4, num5, num6, num7, num8, num9, num0, +num/, num*, num-, num+, num., enter, insert, home, pgup, pgdown, delete, end, backspace, leftarrow, rightarrow, uparrow, downarrow,
+mbutton1,mbutton2,mbutton3
- кнопки мыши.

+Ниже описано каким может быть параметр {action}:
+moveleft, moveright, moveup, nextweapon, lookup, lookdown, fire, center, weapon1, weapon2, weapon3, weapon4, weapon5, weapon6, weapon7, weapon8, p2moveleft, p2moveright, p2moveup, p2fire, p2nextweapon, p2lookup, p2lookdown, p2center, p2weapon1, p2weapon2, p2weapon3, p2weapon4, p2weapon5, p2weapon6, p2weapon7, p2weapon8.

+Пример как биндить:
+bind leftarrow moveleft
+bind a p2moveleft

+приставка p2 значит для второго игрока. Ниже приложен пример полного набиндивания управления для игрока 2:
+bind 1 p2weapon2
+bind e p2weapon3
+bind r p2weapon4
+bind alt p2weapon5
+bind 4 p2weapon6
+bind capslock p2weapon7
+bind tab p2weapon1
+bind k p2lookup
+bind h p2lookdown
+bind j p2fire
+bind w p2moveup
+bind a p2moveleft
+bind d p2moveright
+NOTE: Чтобы забинденные значения lookup, lookdown работали то надо на консоли набрать "mouselook 0", и тогда смотрение игрока 1 будет на забинденных кнопках со значениями lookup, lookdown.

+Чтобы биндить мышь надо "bind mbutton1 fire" "bind mbutton2 moveup" итд.
Бинд "Center" центрует оружие.
+ +Я пока не сделал чтобы бинды сохранялись при выходе так что вам лучше записать их в отдельный конфиг и потом вызывать его в главном меню (на консоли набрать "exec yourfilename". Yourfilename.cfg должен лежать в каталоге BaseNFK).
+Если вас ломает каждый раз писать EXEC, то в каталоге basenfk создайте конфиг autoexec.cfg, а в нем напишите exec Yourfilename.cfg. И ваш конфиг будет грузиться автоматом.
+

+CONSOLE COMMANDS
+Консоль вызывается кнопкой "~"
+bg [1-?] - изменяет задний фон карты.
+crosscolor [1-7] - Цвет прицела игрока 1
+p2crosscolor [1-7] - Цвет прицела игрока 2
+crosstype [0-4] - Вид прицела игрока 1
+p2crosstype [0-4] - Вид прицела игрока 2
+fraglimit [0-999] - Ограничение по фрагам
+timelimit [0-999] - Ограничение по времени
+quit - выход.
+sensitivity [1-9] - cкорость мыши
+restart [0-1] - перезагружается карта. матч начинается сначала.
+drawfps [0-1] - показывает колво фреймов. Должно быть всегда 50. Это ограничение такое.
+ready - начать матч
+simplephysics [0-1] - физика нормальная/продвинутая
+map - Сменить карту. например "map dm1"
+keybsensitivity [1-9] - Скорость look'a с клавиатуры.
+keybaccelerate [0-9] - Акселлерация look'a с клавиатуры (игрока 1).
+p2keybaccelerate [0-9] - Акселлерация look'a с клавиатуры (игрока 2).
+warmup [1-999] - Время на подготовку.
+railcolor [1-7] - Цвет луча рэилгана игрока 1
+p2railcolor [1-7] - Цвет луча рэилгана игрока 2
+bind - Назначить клавишу
+exec - Выполнить конфиг
+unbindkeys - отбиндивает управление 1.
+p2unbindkeys - отбиндивает управление 2.
+railtrailtime [1-14] - время остывания луча рэила.
+hitsound [0-1] - при удачном попадании проигрывается звук hitsnd.wav.
+gibvelocity [0-1] - (эта команда глючит) мясо отлетает в противоположенную попаданию сторону
+gibblood [0-1] - кровь от мяса.
+disconnect - выгружает карту и возвращает в меню.
+stats - показывает статистику до конца партии.
+currenttime - показывает текущее время.
+halfquit - юзай если quitom не выходит.
+record - начинается запись демки
+stoprecord - заканчивается запись демки
+demo - проигрывает дему
+doorsounds [0-1] - звуки дверей
+cameratype [0-1] - тип камеры (неподвижная\за игроком).
+mousesmooth - ограничитель скорости мыши
+gofullscreen - на полный экран
+gowindow - оконный режим
+weaponswitch_on_end [0-2] - автосмена оружия игрока1.
+p2weaponswitch_on_end [0-2] - автосмена оружия игрока2.
+model - модель игрока 1
+p2model - модель игрока 2
+allowmapschangebg [0-1] - разрешить картам менять задний фон.
+leavearena - выгружает карту и возвращает в меню.
+warmuparmor - количество армора в разыгровке.
+shownick [0-1] - показывать ник над игроком.
+autoshownick [0-1] - показывать ник над игроком (автоматически).
+autorecord - начинается запись демки (имя демки придумывается за вас)
+mouselook [0-1] - 1=игрок 1 смотрит на мыше; 0=на клаве.
+paredrail [0-1] - 1=попадания рэила защитываются только в середину модели, голова и ноги не учитываются; 0=нормально.
+nfkitemspawn [0-1] - 1=время респавнов предметов как в NFK, 0=как в quake3.
+corpsetime [0-60] - кол-во сек трупа. после этого времени он убиратся.
+forcerespawn [2-60] - макс кол-во сек на лежание трупом.
+weapbartime [0-250] - время подсветки панели оружий игрока1.
+p2weapbartime [0-250] - время подсветки панели оружий игрока2.
+sndrestart - переинициализация звука.
+midiplay - начать проигрывать музыку. из basenfk\music\*.mid
+midinext - следующий трэк.
+midistop - остановить музыку.
+messagetime [0-500] - время на показ одного сообщения.
+log [0-1] - выключает\включает запись лог файла.
+noplayer [0-2] - (0=2 игрока) (1=нет игрока 1) (2=нет игрока 2). Команда работает только из главного меню.
+cachelist - Показывает список кэшированных моделей.
+transparentstats [0-1] - (не) прозрачная статистика.
+echo text - выводит сообщение text.
+Если ввести команду без значения, то будет показано ее текущее значение.
+

+BUGS
+Если у вас появляются подозрительные глюки то удалите файл nfkconfig.cfg в каталоге basenfk и запустите игру.
+- Помоему если алт+табнуть нфк на > 2 мин, то он виснет.
+- не подрубайте слишком много звуков, а то начнутся проблемы с памятью. (если конечно для вас память это проблема).
+- Гренады помоему отскакивают иногда неправильно
+- иногда можно прошафтить чувака через стену (если шафтить наискосяк через брики)
+- Не сохраняются бинды. но это только пока.
+- Если у вас ничего не пишется на консоли - переключитесь на английский шрифт.
+- Заметьте что при критической ошибке проигрывается звук (error.wav) и выдается сообщение об +ошибке на консоль. Пожалуйста если такое случится то сообщите.
+- иногда нфк не возвращается из альт+таба. Попробуйте подольше, покликайте на таскбар.
+
Если нфк не запускается:
+- Возможно у вас pentium-100.
+- Игра требует минимум DirectX7.
+- Отсутствуют некоторые файлы из оригинальной поставки.
+- Путь к каталогу где лежит нфк содержит русские буквы или пробелы.
+
Если нфк запустился, но не стартует карту.
+- Карта которую пытаетесь загрузить, является картой betanfk025. Ее надо конвертировать через nfkradiant.
+- Отсутствуют некоторые файлы из оригинальной поставки.
+
+ + +

+TECH INFO
+Броня предотвращает 66% дэмэйджа. Макс брони/хелса 200.
+В NFK пока очень много недоделанных опций, окон, графики. Это пока временно. Кстати вы наверное заметили аптечки из q1 - это просто потому что из ку3 аптечки смотрятся отвратительно (в нфк).
Повреждения оружий:
+Machine: 5
+Shotgun: 8-75 (в зависимости от расстояния)
+Grenade: 65
+Rocket: 100 (в голову или ноги где-то 85-100)
+Shaft: 2-3
+Rail: 75
+Plazma: 15
+BFG: 100 (в голову или ноги где-то 85-100)
+

+LICENSE
+Запрещено использовать графику из NFK для своих целей. Запрещено дизассемблирование итп. Распространение игры разрешено только в полном архиве, так как он поставляется в оригинале. Модификация архива, при распространении, запрещена. +Проект является Freeware. Но если вы хотите проспонсировать, то всегда пожалуйста :)). +

+POWERSITE.NAROD.RU
+:). Короче на этом сайте валяется много всякой доп фигни к нфк. Модели, карты, демы. Также на этом сайте много полезно интересного stuff'a.
+

+ps: this help suxx. +

+ + + \ No newline at end of file diff --git a/HELP/nfk_help031a.htm b/HELP/nfk_help031a.htm new file mode 100644 index 0000000..efa02ba --- /dev/null +++ b/HELP/nfk_help031a.htm @@ -0,0 +1,456 @@ + + + +Need For Kill v031a - help + + + + + +
+NEED FOR KILL
V0.31a
by 3d[Power]
+powersite.narod.ru
+
+ + + + + \ No newline at end of file diff --git a/HELP/nfk_help031a_eng.htm b/HELP/nfk_help031a_eng.htm new file mode 100644 index 0000000..5e0c2b6 --- /dev/null +++ b/HELP/nfk_help031a_eng.htm @@ -0,0 +1,462 @@ + + + +Need For Kill v031a - help + + + + + +
+NEED FOR KILL
V0.31a
by 3d[Power]
+powersite.narod.ru
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+ +
+ +
+HOW TO START
+На данный момент в игре есть только один режим игры, это Hotseat (игра вдвоем за одним компьютером). Собственно окно "hotseat":
+Слева-вверху список карт (выбираются курсором (стрелка вниз, стрелка вверх)). Справа вы видите настройки игры. Там же можно изменить свойства игроков.
1ый игрок играет на мышке. 2ой игрок играет на клавиатуре. Клаву можно перебиндить, и кнопки мыши тоже.
В настройки матча входят 4 параметра "warmup, fraglimit,timelimit,gametype". Warmup - время на подготовку перед матчем. Fraglimit - Ограничение по фрагам. Timelimit - Ограничение по времени. Gametype - тип игры (deathmatch, rail arena, practice).
+Рекомендуемые (стандартные) настройки для игры 1v1 это: warmup 180; fraglimit 0; timelimit 10.
Чтобы начать игру, нажмите "fight". +Когда загрузилась карта и начался отчет можно на консоли набрать команду "ready" (или нажать F10) которая начнет матч без разыгровки. +
+ + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help035.htm b/HELP/nfk_help035.htm new file mode 100644 index 0000000..c0d3559 --- /dev/null +++ b/HELP/nfk_help035.htm @@ -0,0 +1,510 @@ + + + +Need For Kill v035b - help + + + + + +
+NEED FOR KILL
V0.35b
by 3d[Power]
+powersite.narod.ru
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+
+ +
+HOW TO START
+There is only one method of playing, it is Hotseat Mode. (2 people at the same computer). +The "HotSeat" window consist of:
At the top-left - list of the maps. U can change maps, using up & down cursor keys. +At the right you can see game settings and player properties. There u can edit properties of both players. +1st player plays on the mouse, second on the keyboard. (u can redefine it). There is 4 parameters for +Game Settings: "warmup, fraglimit,timelimit, gametype". Warmup - time before match starts. +Fraglimit - Frag limitter. Timelimit - Time limitter. Gametype - a type of the game (DeathMatch, +RailArena and Practice). Recomended settings for 1v1 is: warmup 180; fraglimit 0; timelimit 10. +To begin the play press "Fight". When map loaded and the countdown began you can type console command +"ready" (or press F10) to begin the match without warmup. +
+ + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help035_eng.htm b/HELP/nfk_help035_eng.htm new file mode 100644 index 0000000..a8075a2 --- /dev/null +++ b/HELP/nfk_help035_eng.htm @@ -0,0 +1,524 @@ + + + +Need For Kill v035b - help + + + + + +
+NEED FOR KILL
V0.35b
by 3d[Power]
+powersite.narod.ru
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+ +
+ +
+HOTSEAT
+Режим HOTSEAT (игра вдвоем за одним компьютером).
+Слева вверху список карт. Справа, настройки игры. Там же можно изменить свойства игроков.
1ый игрок играет на мышке. 2ой игрок играет на клавиатуре. Управление можно переназначить.
В настройки матча входят 4 параметра "warmup, fraglimit,timelimit,gametype". Warmup - время на подготовку перед матчем. Fraglimit - Ограничение по фрагам. Timelimit - Ограничение по времени. Gametype - тип игры (deathmatch, rail arena, practice).
+Рекомендуемые (стандартные) настройки для игры 1v1 это: warmup 180; fraglimit 0; timelimit 10.
Чтобы начать игру, нажмите "fight". +Когда загрузилась карта и начался отчет, можно на консоли набрать команду "ready" (или нажать F10) которая начнет матч без разыгровки.
+
+ + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help037.htm b/HELP/nfk_help037.htm new file mode 100644 index 0000000..3342517 --- /dev/null +++ b/HELP/nfk_help037.htm @@ -0,0 +1,515 @@ + + + +Need For Kill v037 - help + + + + + +
+NEED FOR KILL
V0.37
by 3d[Power]
+powersite.narod.ru
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+
+ +
+HOTSEAT
+Hotseat Mode. (2 people at the same computer).
+The "HotSeat" window consist of:
At the top-left - list of the maps. U can change maps, using up & down cursor keys. +At the right you can see game settings and player properties. There u can edit properties of both players. +1st player plays on the mouse, second on the keyboard. (u can redefine it). There is 4 parameters for +Game Settings: "warmup, fraglimit,timelimit, gametype". Warmup - time before match starts. +Fraglimit - Frag limitter. Timelimit - Time limitter. Gametype - a type of the game (DeathMatch, +RailArena and Practice). Recomended settings for 1v1 is: warmup 180; fraglimit 0; timelimit 10. +To begin the play press "Fight". When map loaded and the countdown began you can type console command +"ready" (or press F10) to begin the match without warmup. +
+ + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help037_eng.htm b/HELP/nfk_help037_eng.htm new file mode 100644 index 0000000..0ade19d --- /dev/null +++ b/HELP/nfk_help037_eng.htm @@ -0,0 +1,531 @@ + + + +Need For Kill v037 - help + + + + + +
+NEED FOR KILL
V0.37
by 3d[Power]
+powersite.narod.ru
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+ +
+ +
+HOTSEAT
+Режим HOTSEAT (игра вдвоем за одним компьютером).
+Слева вверху список карт. Справа, настройки игры. Там же можно изменить свойства игроков.
1ый игрок играет на мышке. 2ой игрок играет на клавиатуре. Управление можно переназначить.
В настройки матча входят 4 параметра "warmup, fraglimit,timelimit,gametype". Warmup - время на подготовку перед матчем. Fraglimit - Ограничение по фрагам. Timelimit - Ограничение по времени. Gametype - тип игры (deathmatch, rail arena, practice).
+Рекомендуемые (стандартные) настройки для игры 1v1 это: warmup 180; fraglimit 0; timelimit 10.
Чтобы начать игру, нажмите "fight". +Когда загрузилась карта и начался отчет, можно на консоли набрать команду "ready" (или нажать F10) которая начнет матч без разыгровки.

+В HOTSEAT можно играть в типы игры: DeathMatch, Rail Arena, Practice
+
+ + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help040.htm b/HELP/nfk_help040.htm new file mode 100644 index 0000000..cd0f561 --- /dev/null +++ b/HELP/nfk_help040.htm @@ -0,0 +1,608 @@ + + + +Need For Kill v0.40 - help + + + + + +
+NEED FOR KILL
V0.40
by 3d[Power]
+www.3dpower.org
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+
+ +
+HOTSEAT
+Hotseat Mode. (2 people at the same computer).
+The "HotSeat" window consist of:
At the top-left - list of the maps. U can change maps, using up & down cursor keys. +At the right you can see game settings and player properties. There u can edit properties of both players. +1st player plays on the mouse, second on the keyboard. (u can redefine it). There is 4 parameters for +Game Settings: "warmup, fraglimit,timelimit, gametype". Warmup - time before match starts. +Fraglimit - Frag limitter. Timelimit - Time limitter. Gametype - a type of the game (DeathMatch, +RailArena and Practice). Recomended settings for 1v1 is: warmup 180; fraglimit 0; timelimit 10. +To begin the play press "Fight". When map loaded and the countdown began you can type console command +"ready" (or press F10) to begin the match without warmup. +

Available gametypes: DeathMatch, Rail Arena, Practice
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help040_eng.htm b/HELP/nfk_help040_eng.htm new file mode 100644 index 0000000..48db6dd --- /dev/null +++ b/HELP/nfk_help040_eng.htm @@ -0,0 +1,626 @@ + + + +Need For Kill v0.40 - help + + + + + +
+NEED FOR KILL
V0.40
by 3d[Power]
+www.3dpower.org
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+

+ +
+ +
+HOTSEAT
+Режим HOTSEAT (игра вдвоем за одним компьютером).
+Слева вверху список карт. Справа, настройки игры. Там же можно изменить свойства игроков.
1ый игрок играет на мышке. 2ой игрок играет на клавиатуре. Управление можно переназначить.
В настройки матча входят 4 параметра "warmup, fraglimit,timelimit,gametype". Warmup - время на подготовку перед матчем. Fraglimit - Ограничение по фрагам. Timelimit - Ограничение по времени. Gametype - тип игры (deathmatch, rail arena, practice).
+Рекомендуемые (стандартные) настройки для игры 1v1 это: warmup 180; fraglimit 0; timelimit 10.
Чтобы начать игру, нажмите "fight". +Когда загрузилась карта и начался отчет, можно на консоли набрать команду "ready" (или нажать F10) которая начнет матч без разыгровки.

+В HOTSEAT можно играть в типы игры: DeathMatch, Rail Arena, Practice
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help050.htm b/HELP/nfk_help050.htm new file mode 100644 index 0000000..0e4d1ee --- /dev/null +++ b/HELP/nfk_help050.htm @@ -0,0 +1,638 @@ + + + +Need For Kill v0.50 - help + + + + + +
+NEED FOR KILL
V0.50
by 3d[Power]
+www.3dpower.org
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+

+
+ +
+HOTSEAT
+Hotseat Mode. (2 people at the same computer).
+The "HotSeat" window consist of:
At the top-left - list of the maps. U can change maps, using up & down cursor keys. +At the right you can see game settings and player properties. There u can edit properties of both players. +1st player plays on the mouse, second on the keyboard. (u can redefine it). There is 4 parameters for +Game Settings: "warmup, fraglimit,timelimit, gametype". Warmup - time before match starts. +Fraglimit - Frag limitter. Timelimit - Time limitter. Gametype - a type of the game (DeathMatch, +RailArena and Practice). Recomended settings for 1v1 is: warmup 180; fraglimit 0; timelimit 10. +To begin the play press "Fight". When map loaded and the countdown began you can type console command +"ready" (or press F10) to begin the match without warmup. +

Available gametypes: DeathMatch, Rail Arena, Practice
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/nfk_help050_eng.htm b/HELP/nfk_help050_eng.htm new file mode 100644 index 0000000..381a51a --- /dev/null +++ b/HELP/nfk_help050_eng.htm @@ -0,0 +1,659 @@ + + + +Need For Kill v0.50 - help + + + + + +
+NEED FOR KILL
V0.50
by 3d[Power]
+www.3dpower.org
+
+ +
+ +





+
+

+

+

+

+

+

+

+

+

+

+

+ +
+ +
+HOTSEAT
+Режим HOTSEAT (игра вдвоем за одним компьютером).
+Слева вверху список карт. Справа, настройки игры. Там же можно изменить свойства игроков.
1ый игрок играет на мышке. 2ой игрок играет на клавиатуре. Управление можно переназначить.
В настройки матча входят 4 параметра "warmup, fraglimit,timelimit,gametype". Warmup - время на подготовку перед матчем. Fraglimit - Ограничение по фрагам. Timelimit - Ограничение по времени. Gametype - тип игры (deathmatch, rail arena, practice).
+Рекомендуемые (стандартные) настройки для игры 1v1 это: warmup 180; fraglimit 0; timelimit 10.
Чтобы начать игру, нажмите "fight". +Когда загрузилась карта и начался отчет, можно на консоли набрать команду "ready" (или нажать F10) которая начнет матч без разыгровки.

+В HOTSEAT можно играть в типы игры: DeathMatch, Rail Arena, Practice
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/HELP/q3-to-nfk-model-ripper/FILE_ID.DIZ b/HELP/q3-to-nfk-model-ripper/FILE_ID.DIZ new file mode 100644 index 0000000..58a288a --- /dev/null +++ b/HELP/q3-to-nfk-model-ripper/FILE_ID.DIZ @@ -0,0 +1,15 @@ + Quake 3 Model Loader +-------------------------------------------------------- + +Пример показывает как можно загрузить MD3 модель ( +формат файлов Quake III ) с поддержкой +текстурирования и анимации. В примере есть модуль +описывающий формат файла MD3. OpenGL. + +Проект компилировался на Delphi 3,5 + +-------------------------------------------------------- + +Delphi GFX - все о создании игр и графике на Delphi + +http://www.delphigfx.narod.ru diff --git a/HELP/q3-to-nfk-model-ripper/OpenGLApp.dpr b/HELP/q3-to-nfk-model-ripper/OpenGLApp.dpr new file mode 100644 index 0000000..b3012ae --- /dev/null +++ b/HELP/q3-to-nfk-model-ripper/OpenGLApp.dpr @@ -0,0 +1,791 @@ +//------------------------------------------------------------------------ +// +// Author : Jan Horn. Rest In Peace friend... +// Email : jhorn@global.co.za +// Website : http://home.global.co.za/~jhorn +// Date : 7 October 2001 +// Version : 1.0 +// Description : Quake 3 Model Loader (MD3 Loader) +// +//------------------------------------------------------------------------ +program OpenGLApp; + +uses + Windows, + Messages, + OpenGL, + model, + Textures, + SysUtils; + +const + WND_TITLE = 'RIPPA. original code by Jan Horn. adapted for NFK by 3d[Power]'; + FPS_TIMER = 1; // Timer to calculate FPS + FPS_INTERVAL = 1000; // Calculate FPS every 1000 ms + VAITKEY:boolean=true; + ANIMUP:boolean=true; // animate upper. + +var + h_Wnd : HWND; // Global window handle + h_DC : HDC; // Global device context + h_RC : HGLRC; // OpenGL rendering context + keys : Array[0..255] of Boolean; // Holds keystrokes + FPSCount : Integer = 0; // Counter for FPS + ElapsedTime : Integer; // Elapsed time between frames + clr:byte; + waitz: byte; + + // User vaiables + YRot, XRot : glFloat; // Y Rotation + Depth : glFloat; + Xcoord, Ycoord, Zcoord : Integer; + MouseButton : Integer; + + WireFrame : Boolean; + ShowFrames : Boolean; + fontBase : GLuint; // base to the font display lists + + Player : Q3Player; + Weapon : TMD3Model; + +{$R *.RES} + +procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32; + +{------------------------------------------------------------------} +{ Function to convert int to string. (No sysutils = smaller EXE) } +{------------------------------------------------------------------} +function IntToStr(Num : Integer) : String; // using SysUtils increase file size by 100K +begin + Str(Num, result); +end; + + +{----------------------------------------------------------------} +{ Procedures used to create and write text } +{----------------------------------------------------------------} +procedure BuildFont; +var font : HFONT; +begin + fontBase := glGenLists(96); // Generate enough display lists to hold + font := CreateFont(-16, // height of font + 0, // average character width + 0, // angle of escapement + 0, // base-line orientation angle + FW_BOLD, // font weight + 0, // italic + 0, // underline + 0, // strikeout + ANSI_CHARSET, // character set + OUT_TT_PRECIS, // output precision + CLIP_DEFAULT_PRECIS, // clipping precision + ANTIALIASED_QUALITY, // output quality + FF_DONTCARE or DEFAULT_PITCH, // pitch and family + 'Arial'); // font + SelectObject(h_DC, font); // Sets the new font as the current font in the device context + wglUseFontBitmaps(h_DC, 32, 96, fontBase); // Creates a set display lists containing the bitmap fonts +end; + +procedure KillFont; +begin + glDeleteLists(fontBase, 96); // Delete the font display lists, returning used memory +end; + +procedure glWrite(X, Y : GLUint; text : PChar); +var drawRect : TRect; +begin + glPushAttrib(GL_DEPTH_TEST); // Save the current Depth test settings (Used for blending ) + glDisable(GL_DEPTH_TEST); // Turn off depth testing (otherwise we get no FPS) + glDisable(GL_TEXTURE_2D); // Turn off textures, don't want our text textured + glMatrixMode(GL_PROJECTION); // Switch to the projection matrix + glPushMatrix(); // Save current projection matrix + glLoadIdentity(); + + GetWindowRect(GetDesktopWindow(), drawRect); // Get current window size + glOrtho(0, drawRect.right, 0, drawRect.bottom, -1, 1); // Change the projection matrix using an orthgraphic projection + glMatrixMode(GL_MODELVIEW); // Return to the modelview matrix + glPushMatrix(); // Save the current modelview matrix + glLoadIdentity(); + glColor3f(1.0, 1.0, 1.0); // Text color + + glRasterPos2i(X, Y); // Position the Text + glPushAttrib(GL_LIST_BIT); // Save's the current base list + glListBase(fontBase - 32); // Set the base list to our character list + glCallLists(length(text), GL_UNSIGNED_BYTE, PChar(text)); // Display the text + glPopAttrib(); // Restore the old base list + + glMatrixMode(GL_PROJECTION); // Switch to projection matrix + glPopMatrix(); // Restore the old projection matrix + glMatrixMode(GL_MODELVIEW); // Return to modelview matrix + glPopMatrix(); // Restore old modelview matrix + glEnable(GL_TEXTURE_2D); // Turn on textures, don't want our text textured + glPopAttrib(); // Restore depth testing +end; + + +{------------------------------------------------------------------} +{ Function used to write out the current upper and lower frames } +{------------------------------------------------------------------} +procedure DrawCurrentFrames; +begin + case Player.animLower of + BOTH_DEATH1 : glWrite(15, 500, 'Lower : Death 1'); + BOTH_DEAD1 : glWrite(15, 500, 'Lower : Dead 1'); + BOTH_DEATH2 : glWrite(15, 500, 'Lower : Death 2'); + BOTH_DEAD2 : glWrite(15, 500, 'Lower : Dead 2'); + BOTH_DEATH3 : glWrite(15, 500, 'Lower : Death 3'); + BOTH_DEAD3 : glWrite(15, 500, 'Lower : Dead 3'); + + LEGS_WALKCR : glWrite(15, 500, 'Lower : Walk Crouch'); + LEGS_WALK : glWrite(15, 500, 'Lower : Walk'); + LEGS_RUN : glWrite(15, 500, 'Lower : Run'); + LEGS_BACK : glWrite(15, 500, 'Lower : Backwarks'); + LEGS_SWIM : glWrite(15, 500, 'Lower : Swim'); + LEGS_JUMP : glWrite(15, 500, 'Lower : Jump'); + LEGS_LAND : glWrite(15, 500, 'Lower : Land'); + LEGS_JUMPB : glWrite(15, 500, 'Lower : Jump Backwards'); + LEGS_LANDB : glWrite(15, 500, 'Lower : Land Backwards'); + LEGS_IDLE : glWrite(15, 500, 'Lower : Idle'); + LEGS_IDLECR : glWrite(15, 500, 'Lower : Idel Crouch'); + LEGS_TURN : glWrite(15, 500, 'Lower : Turn'); + end; + + case Player.animUpper of + BOTH_DEATH1 : glWrite(600, 500, 'Upper : Death 1'); + BOTH_DEAD1 : glWrite(600, 500, 'Upper : Dead 1'); + BOTH_DEATH2 : glWrite(600, 500, 'Upper : Death 2'); + BOTH_DEAD2 : glWrite(600, 500, 'Upper : Dead 2'); + BOTH_DEATH3 : glWrite(600, 500, 'Upper : Death 3'); + BOTH_DEAD3 : glWrite(600, 500, 'Upper : Dead 3'); + + TORSO_GESTURE : glWrite(600, 500, 'Upper : Gesture'); + TORSO_ATTACK : glWrite(600, 500, 'Upper : Attack'); + TORSO_ATTACK2 : glWrite(600, 500, 'Upper : Attack2'); + TORSO_DROP : glWrite(600, 500, 'Upper : Drop'); + TORSO_RAISE : glWrite(600, 500, 'Upper : Raise'); + TORSO_STAND : glWrite(600, 500, 'Upper : Stand'); + LEGS_LAND : glWrite(600, 500, 'Upper : Land'); + TORSO_STAND2 : glWrite(600, 500, 'Upper : Stand2'); + end; +end; + + +{------------------------------------------------------------------} +{ Function used to load a railgin and join it to the player } +{------------------------------------------------------------------} +procedure LoadRailgun; + + procedure LoadMeshTexture(const imagename, meshname : String); + var I : Integer; + begin + // Find the right mesh item to assign the skin to + for I :=0 to Weapon.header.numMeshes-1 do + begin + // check it the two names are the same + if UpperCase(CharArrToStr(Weapon.meshes[i].MeshHeader.Name)) = Uppercase(meshname) then + begin + LoadTexture(ImageName, Weapon.meshes[i].Texture, FALSE); + Weapon.meshes[i].SetTexture :=TRUE; + end; + end; + end; + +begin +// Weapon.LoadModel('model\railgun\railgun.md3'); +// +{ LoadMeshTexture('model\railgun\railgun1.jpg', 'w_railgun1'); + LoadMeshTexture('model\railgun\railgun2.glow.jpg', 'w_railgun2'); + LoadMeshTexture('model\railgun\railgun4.jpg', 'w_railgun4'); + LoadMeshTexture('model\railgun\railgun3.glow.jpg', 'w_railgun3'); + LoadMeshTexture('model\railgun\railgun1.jpg', 'w_railgun05'); +} +// Player.Upper.LinkModel('tag_weapon', Weapon); +end; + + +{------------------------------------------------------------------} +{ Function to draw the actual scene } +{------------------------------------------------------------------} +procedure glDraw(); +begin + glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer + glLoadIdentity(); // Reset The View + + glTranslatef(0.0, -10.0, Depth); + + glRotatef(xRot, 1, 0, 0); + glRotatef(yRot, 0, 0, 1); + + glWrite(15, 430, pchar('yRot:'+inttostr(round(yrot)))); + + glWrite(15, 400, pchar('xRot:'+inttostr(round(xrot)))); + + glWrite(15, 460, pchar('Depth:'+inttostr(round(Depth)))); + + glWrite(15, 490, pchar('clr:'+inttostr(round(clr)))); + glWrite(15, 300, pchar('lowerframe:'+inttostr(player.Lower.frame))); + glWrite(15, 270, pchar('upperframe:'+inttostr(player.upper.frame))); + glWrite(15, 230, pchar('Headframe:'+inttostr(player.Head.frame))); + + if ANIMUP then + glWrite(15, 320, pchar('animup:y')) else + glWrite(15, 320, pchar('animup:n')); + + if waitz>0 then dec(waitz); + + +// if h_Wnd. + +// if VAITKEY=true then begin + Player.Draw(0); + // VAITKEY := false; + // end; + + if ShowFrames then + DrawCurrentFrames; +end; + + +{------------------------------------------------------------------} +{ Initialise OpenGL } +{------------------------------------------------------------------} +procedure glInit(); +var dir,skn :string; +begin +if clr=0 then + glClearColor(0, 0, 0, 0) else + glClearColor(1, 1, 1, 0); + + glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading + glClearDepth(1.0); // Depth Buffer Setup + glEnable(GL_DEPTH_TEST); // Enable Depth Buffer + glDepthFunc(GL_LESS); // The Type Of Depth Test To Do + + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //Realy Nice perspective calculations + + glEnable(GL_TEXTURE_2D); // Enable Texture Mapping + + xRot :=-90; + yRot :=0; + Depth :=-100; + + ShowFrames :=TRUE; + BuildFont(); + + dir := 'model\'; + skn := 'default'; + if paramstr(1) <> '' then dir := dir + paramstr(1)+'\' else dir := dir+'sarge\'; + if paramstr(2) <> '' then skn := paramstr(2); + if paramstr(3) <> '' then depth := strtoint(paramstr(3)); + +// Player.LoadPlayer(dir, skn); + Player.LoadPlayer(pchar(dir), pchar(skn)); + + LoadRailgun; +end; + + +{------------------------------------------------------------------} +{ Handle window resize } +{------------------------------------------------------------------} +procedure glResizeWnd(Width, Height : Integer); +begin + if (Height = 0) then // prevent divide by zero exception + Height := 1; + glViewport(0, 0, Width, Height); // Set the viewport for the OpenGL window + glMatrixMode(GL_PROJECTION); // Change Matrix Mode to Projection + glLoadIdentity(); // Reset View + gluPerspective(45.0, Width/Height, 1.0, 500.0); // Do the perspective calculations. Last value = max clipping depth + glMatrixMode(GL_MODELVIEW); // Return to the modelview matrix + glLoadIdentity(); // Reset View +end; + + +{------------------------------------------------------------------} +{ Processes all the keystrokes } +{------------------------------------------------------------------} +procedure ProcessKeys; +begin + if keys[Ord('F')] then // Show the current upper and lower frames + begin + ShowFrames :=Not(ShowFrames); + keys[Ord('F')] :=FALSE; + end; + + if keys[Ord('W')] then // Enable and Disable wireframe mode + begin + WireFrame :=Not(WireFrame); + if WireFrame then + begin + glDisable(GL_TEXTURE_2D); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + end + else + begin + glEnable(GL_TEXTURE_2D); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + end; + keys[Ord('W')] :=FALSE; + end; + + + if keys[Ord('Z')] then // Go to next leg movement + begin + Inc(Player.animLower); + if (Player.animLower > BOTH_DEAD3) AND (Player.animLower < LEGS_WALKCR) then + begin + Player.animLower := LEGS_WALKCR; + Player.animUpper := TORSO_STAND; + Player.SetAnim(Player.animUpper); + end; + if Player.animLower > LEGS_TURN then + Player.animLower :=BOTH_DEATH1; + Player.SetAnim(Player.animLower); + keys[Ord('Z')] :=FALSE; + end; + + if keys[Ord('X')] then // go to previous leg movement + begin + Dec(Player.animLower); + if (Player.animLower > BOTH_DEAD3) AND (Player.animLower < LEGS_WALKCR) then + Player.animLower := BOTH_DEAD3; + if Player.animLower < BOTH_DEATH1 then + Player.animLower :=LEGS_TURN; + Player.SetAnim(Player.animLower); + keys[Ord('X')] :=FALSE; + end; + + if keys[Ord('A')] then // go to next torso movement + begin + Inc(Player.animUpper); + if Player.animUpper > TORSO_STAND2 then + Player.animUpper :=TORSO_GESTURE; + Player.SetAnim(Player.animUpper); + keys[Ord('A')] :=FALSE; + end; + + if keys[Ord('I')] then depth:=depth+1; + if keys[Ord('K')] then depth:=depth-1; + + if (keys[VK_SPACE]) and (waitz=0) then // Reset Position to default + begin + waitz:=25; +// player.singleupdate(0); + player.Lower.UpdateFrame(time); + if ANIMUP then player.Upper.UpdateFrame(time); + player.Head.UpdateFrame(time); + + end; + + if keys[Ord('O')] then begin + if CLR=1 then CLR:=0 else CLR:=1; + if clr=0 then + glClearColor(0, 0, 0, 0) else + glClearColor(1, 1, 1, 0); + end; + + if keys[Ord('Y')] then glResizeWnd(400, 300); + + + if keys[Ord('S')] then // go to previous torso movement + begin + Dec(Player.animUpper); + if Player.animUpper < TORSO_GESTURE then + Player.animUpper :=TORSO_STAND2; + Player.SetAnim(Player.animUpper); + keys[Ord('S')] :=FALSE; + end; + + if keys[Ord('1')] then ANIMUP:=NOT ANIMUP; // go to previous torso movement + +end; + + +{------------------------------------------------------------------} +{ Determines the application’s response to the messages received } +{------------------------------------------------------------------} +function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; +begin + case (Msg) of + WM_CREATE: + begin + // Insert stuff you want executed when the program starts + end; + WM_CLOSE: + begin + PostQuitMessage(0); + Result := 0 + end; + WM_KEYDOWN: // Set the pressed key (wparam) to equal true so we can check if its pressed + begin + keys[wParam] := True; + Result := 0; + end; + WM_KEYUP: // Set the released key (wparam) to equal false so we can check if its pressed + begin + keys[wParam] := False; + Result := 0; + end; + WM_SIZE: // Resize the window with the new width and height + begin + glResizeWnd(LOWORD(lParam),HIWORD(lParam)); + Result := 0; + end; + + // Mouse buttons + WM_LBUTTONDOWN: + begin + ReleaseCapture(); // need them here, because if mouse moves off + SetCapture(h_Wnd); // window and returns, it needs to reset status + MouseButton := 1; + Xcoord := LOWORD(lParam); + Ycoord := HIWORD(lParam); + Result := 0; + end; + WM_LBUTTONUP: + begin + ReleaseCapture(); // above + MouseButton := 0; + XCoord := 0; + YCoord := 0; + Result := 0; + end; + WM_RBUTTONDOWN: + begin + ReleaseCapture(); // need them here, because if mouse moves off + SetCapture(h_Wnd); // window and returns, it needs to reset status + MouseButton := 2; + ZCoord :=HIWORD(lParam); + Result := 0; + end; + WM_RBUTTONUP: + begin + ReleaseCapture(); // above + MouseButton := 0; + Result := 0; + end; + WM_MOUSEMOVE: + begin + if MouseButton = 1 then + begin + xRot := xRot + (HIWORD(lParam) - Ycoord)/2; // moving up and down = rot around X-axis + yRot := yRot + (LOWORD(lParam) - Xcoord)/2; + Xcoord := LOWORD(lParam); + Ycoord := HIWORD(lParam); + end; + if MouseButton = 2 then + begin + Depth :=Depth - (HIWORD(lParam)-ZCoord)/10; + Zcoord := HIWORD(lParam); + end; + Result := 0; + end; + WM_TIMER : // Add code here for all timers to be used. + begin + if wParam = FPS_TIMER then + begin + FPSCount :=Round(FPSCount * 1000/FPS_INTERVAL); // calculate to get per Second incase intercal is less or greater than 1 second + SetWindowText(h_Wnd, PChar(WND_TITLE + ' [' + intToStr(FPSCount) + ' FPS]')); + FPSCount := 0; + Result := 0; + end; + end; + else + Result := DefWindowProc(hWnd, Msg, wParam, lParam); // Default result if nothing happens + end; +end; + + +{---------------------------------------------------------------------} +{ Properly destroys the window created at startup (no memory leaks) } +{---------------------------------------------------------------------} +procedure glKillWnd(Fullscreen : Boolean); +begin + if Fullscreen then // Change back to non fullscreen + begin + ChangeDisplaySettings(devmode(nil^), 0); + ShowCursor(True); + end; + + // Makes current rendering context not current, and releases the device + // context that is used by the rendering context. + if (not wglMakeCurrent(h_DC, 0)) then + MessageBox(0, 'Release of DC and RC failed!', 'Error', MB_OK or MB_ICONERROR); + + // Attempts to delete the rendering context + if (not wglDeleteContext(h_RC)) then + begin + MessageBox(0, 'Release of rendering context failed!', 'Error', MB_OK or MB_ICONERROR); + h_RC := 0; + end; + + // Attemps to release the device context + if ((h_DC = 1) and (ReleaseDC(h_Wnd, h_DC) <> 0)) then + begin + MessageBox(0, 'Release of device context failed!', 'Error', MB_OK or MB_ICONERROR); + h_DC := 0; + end; + + // Attempts to destroy the window + if ((h_Wnd <> 0) and (not DestroyWindow(h_Wnd))) then + begin + MessageBox(0, 'Unable to destroy window!', 'Error', MB_OK or MB_ICONERROR); + h_Wnd := 0; + end; + + // Attempts to unregister the window class + if (not UnRegisterClass('OpenGL', hInstance)) then + begin + MessageBox(0, 'Unable to unregister window class!', 'Error', MB_OK or MB_ICONERROR); + hInstance := 0; + end; +end; + + +{--------------------------------------------------------------------} +{ Creates the window and attaches a OpenGL rendering context to it } +{--------------------------------------------------------------------} +function glCreateWnd(Width, Height : Integer; Fullscreen : Boolean; PixelDepth : Integer) : Boolean; +var + wndClass : TWndClass; // Window class + dwStyle : DWORD; // Window styles + dwExStyle : DWORD; // Extended window styles + dmScreenSettings : DEVMODE; // Screen settings (fullscreen, etc...) + PixelFormat : GLuint; // Settings for the OpenGL rendering + h_Instance : HINST; // Current instance + pfd : TPIXELFORMATDESCRIPTOR; // Settings for the OpenGL window +begin + h_Instance := GetModuleHandle(nil); //Grab An Instance For Our Window + ZeroMemory(@wndClass, SizeOf(wndClass)); // Clear the window class structure + + with wndClass do // Set up the window class + begin + style := CS_HREDRAW or // Redraws entire window if length changes + CS_VREDRAW or // Redraws entire window if height changes + CS_OWNDC; // Unique device context for the window + lpfnWndProc := @WndProc; // Set the window procedure to our func WndProc + hInstance := h_Instance; + hCursor := LoadCursor(0, IDC_ARROW); + lpszClassName := 'OpenGL'; + end; + + if (RegisterClass(wndClass) = 0) then // Attemp to register the window class + begin + MessageBox(0, 'Failed to register the window class!', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit + end; + + // Change to fullscreen if so desired + if Fullscreen then + begin + ZeroMemory(@dmScreenSettings, SizeOf(dmScreenSettings)); + with dmScreenSettings do begin // Set parameters for the screen setting + dmSize := SizeOf(dmScreenSettings); + dmPelsWidth := Width; // Window width + dmPelsHeight := Height; // Window height + dmBitsPerPel := PixelDepth; // Window color depth + dmFields := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL; + end; + + // Try to change screen mode to fullscreen + if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) = DISP_CHANGE_FAILED) then + begin + MessageBox(0, 'Unable to switch to fullscreen!', 'Error', MB_OK or MB_ICONERROR); + Fullscreen := False; + end; + end; + + // If we are still in fullscreen then + if (Fullscreen) then + begin + dwStyle := WS_POPUP or // Creates a popup window + WS_CLIPCHILDREN // Doesn't draw within child windows + or WS_CLIPSIBLINGS; // Doesn't draw within sibling windows + dwExStyle := WS_EX_APPWINDOW; // Top level window + ShowCursor(False); // Turn of the cursor (gets in the way) + end + else + begin + dwStyle := WS_OVERLAPPEDWINDOW or // Creates an overlapping window + WS_CLIPCHILDREN or // Doesn't draw within child windows + WS_CLIPSIBLINGS; // Doesn't draw within sibling windows + dwExStyle := WS_EX_APPWINDOW or // Top level window + WS_EX_CLIENTEDGE ; // Border with a raised edge + end; + + // Attempt to create the actual window + h_Wnd := CreateWindowEx(dwExStyle, // Extended window styles + 'OpenGL', // Class name + WND_TITLE, // Window title (caption) + dwStyle, // Window styles + 0, 0, // Window position + Width, Height, // Size of window + 0, // No parent window + 0, // No menu + h_Instance, // Instance + nil); // Pass nothing to WM_CREATE + if h_Wnd = 0 then + begin + glKillWnd(Fullscreen); // Undo all the settings we've changed + MessageBox(0, 'Unable to create window!', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit; + end; + + // Try to get a device context + h_DC := GetDC(h_Wnd); + if (h_DC = 0) then + begin + glKillWnd(Fullscreen); + MessageBox(0, 'Unable to get a device context!', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit; + end; + + // Settings for the OpenGL window + with pfd do + begin + nSize := SizeOf(TPIXELFORMATDESCRIPTOR); // Size Of This Pixel Format Descriptor + nVersion := 1; // The version of this data structure + dwFlags := PFD_DRAW_TO_WINDOW // Buffer supports drawing to window + or PFD_SUPPORT_OPENGL // Buffer supports OpenGL drawing + or PFD_DOUBLEBUFFER; // Supports double buffering + iPixelType := PFD_TYPE_RGBA; // RGBA color format + cColorBits := PixelDepth; // OpenGL color depth + cRedBits := 0; // Number of red bitplanes + cRedShift := 0; // Shift count for red bitplanes + cGreenBits := 0; // Number of green bitplanes + cGreenShift := 0; // Shift count for green bitplanes + cBlueBits := 0; // Number of blue bitplanes + cBlueShift := 0; // Shift count for blue bitplanes + cAlphaBits := 0; // Not supported + cAlphaShift := 0; // Not supported + cAccumBits := 0; // No accumulation buffer + cAccumRedBits := 0; // Number of red bits in a-buffer + cAccumGreenBits := 0; // Number of green bits in a-buffer + cAccumBlueBits := 0; // Number of blue bits in a-buffer + cAccumAlphaBits := 0; // Number of alpha bits in a-buffer + cDepthBits := 16; // Specifies the depth of the depth buffer + cStencilBits := 0; // Turn off stencil buffer + cAuxBuffers := 0; // Not supported + iLayerType := PFD_MAIN_PLANE; // Ignored + bReserved := 0; // Number of overlay and underlay planes + dwLayerMask := 0; // Ignored + dwVisibleMask := 0; // Transparent color of underlay plane + dwDamageMask := 0; // Ignored + end; + + // Attempts to find the pixel format supported by a device context that is the best match to a given pixel format specification. + PixelFormat := ChoosePixelFormat(h_DC, @pfd); + if (PixelFormat = 0) then + begin + glKillWnd(Fullscreen); + MessageBox(0, 'Unable to find a suitable pixel format', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit; + end; + + // Sets the specified device context's pixel format to the format specified by the PixelFormat. + if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then + begin + glKillWnd(Fullscreen); + MessageBox(0, 'Unable to set the pixel format', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit; + end; + + // Create a OpenGL rendering context + h_RC := wglCreateContext(h_DC); + if (h_RC = 0) then + begin + glKillWnd(Fullscreen); + MessageBox(0, 'Unable to create an OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit; + end; + + // Makes the specified OpenGL rendering context the calling thread's current rendering context + if (not wglMakeCurrent(h_DC, h_RC)) then + begin + glKillWnd(Fullscreen); + MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error', MB_OK or MB_ICONERROR); + Result := False; + Exit; + end; + + // Initializes the timer used to calculate the FPS + SetTimer(h_Wnd, FPS_TIMER, FPS_INTERVAL, nil); + + // Settings to ensure that the window is the topmost window + ShowWindow(h_Wnd, SW_SHOW); + SetForegroundWindow(h_Wnd); + SetFocus(h_Wnd); + + // Ensure the OpenGL window is resized properly + glResizeWnd(Width, Height); + glInit(); + + Result := True; +end; + + +{--------------------------------------------------------------------} +{ Main message loop for the application } +{--------------------------------------------------------------------} +function WinMain(hInstance : HINST; hPrevInstance : HINST; + lpCmdLine : PChar; nCmdShow : Integer) : Integer; stdcall; +var + msg : TMsg; + finished : Boolean; + DemoStart, LastTime : DWord; +begin + finished := False; + + // Perform application initialization: + if not glCreateWnd(400, 300, FALSE, 32) then + begin + Result := 0; + Exit; + end; + + DemoStart := GetTickCount(); // Get Time when demo started + + // Main message loop: + while not finished do + begin + if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // Check if there is a message for this window + begin + if (msg.message = WM_QUIT) then // If WM_QUIT message received then we are done + finished := True + else + begin // Else translate and dispatch the message to this window + TranslateMessage(msg); + DispatchMessage(msg); + end; + end + else + begin + Inc(FPSCount); // Increment FPS Counter + + LastTime :=ElapsedTime; + ElapsedTime :=GetTickCount() - DemoStart; // Calculate Elapsed Time + ElapsedTime :=(LastTime + ElapsedTime) DIV 2; // Average it out for smoother movement + + glDraw(); // Draw the scene + SwapBuffers(h_DC); // Display the scene + + if (keys[VK_ESCAPE]) then // If user pressed ESC then set finised TRUE + finished := True + else + ProcessKeys; // Check for any other key Pressed + end; + end; + glKillWnd(FALSE); + Result := msg.wParam; +end; + + +begin + WinMain( hInstance, hPrevInst, CmdLine, CmdShow ); +end. diff --git a/HELP/q3-to-nfk-model-ripper/Quake 3 MD3 file format.htm b/HELP/q3-to-nfk-model-ripper/Quake 3 MD3 file format.htm new file mode 100644 index 0000000..c2889b3 --- /dev/null +++ b/HELP/q3-to-nfk-model-ripper/Quake 3 MD3 file format.htm @@ -0,0 +1,314 @@ + + +Mental Vortex + + + + +
+ +





+
+

+

+

+

+

+

+

+

+

+

+

+
+ +
+HOTSEAT
+Hotseat Mode. (2 people at the same computer).
+The "HotSeat" window consist of:
At the top-left - list of the maps. U can change maps, using up & down cursor keys. +At the right you can see game settings and player properties. There u can edit properties of both players. +1st player plays on the mouse, second on the keyboard. (u can redefine it). There is 4 parameters for +Game Settings: "warmup, fraglimit,timelimit, gametype". Warmup - time before match starts. +Fraglimit - Frag limitter. Timelimit - Time limitter. Gametype - a type of the game (DeathMatch, +RailArena and Practice). Recomended settings for 1v1 is: warmup 180; fraglimit 0; timelimit 10. +To begin the play press "Fight". When map loaded and the countdown began you can type console command +"ready" (or press F10) to begin the match without warmup. +

Available gametypes: DeathMatch, Rail Arena, Practice
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
MD3 + file format specs
+
+ + + + +
+
+
+


+ The file structure of the md3 files, as far as we know at this time:

+

Last + Updated October8 1999

+

!!Warning!! +
+ This document is very technical!
+ It is assumed that you, the reader, have knowledge of programming + C and have basic knowledge of 3d.

+
+ Please note that:

+
+
+
+

Char is a 8bit integer + variable type
+ Short is a 16bit integer variable type
+ Int is a 32bit integer variable type
+ Float is a 32bit floating point variable-type
+ Vec2 is float[2]
+ Vec3 is float[3]
+ Mat3x3 is float[3][3]
+
TexVec + is a texture vector or texture u/v coordinate

+
+
+
+

First start off with the + header of the md3 file.

+

MD3_HEADER:

+
+
+
+
char ID[4];         //id of file, always "IDP3" 
+int  Version;       //i suspect this is a version 
//number, always 15
char FileName[68]; //sometimes left Blank... + //65 chars, 32bit aligned ==
//68 chars +int BoneFrame_num; //number of BoneFrames +int Tag_num; //number of 'tags' per BoneFrame +int Mesh_num; //number of meshes/skins
int MaxSkin_num; //maximum number of unique skins
//used in md3 file +int HeaderLength; //always equal to the length of
//this header
int Tag_Start; //starting position of + //tag-structures
int Tag_End; //ending position of
//tag-structures/starting
//position of mesh-structures +int FileSize; //size of file
+
+
+
+

comments:
+ If Tag_Start is the same + as Tag_End then there are no tags.
+
+
+ Tag_Num is sometimes 0, this is alright it means that there are no + tags...
+ i'm not sure what Tags are used for, altough there is a clear connection +
+ with boneframe, together they're probably used for bone based animations
+ (where you rotate meshes around eachother to create animations)
.

+

 

+

After the header comes + a list of tags, if available.
+
The ammount of tags + is the header variable Tag_num + times the header variable BoneFrame_num.
+ So it is highly probably that tags have something to do with boneframes + and that objects
+ can have 0 to n tags 'attached' to them.
+ Note: We call them 'Tags' because the name in tag usually starts with + "tag_".

+

TAG:

+
+
+
+
char Name[64];    //name of 'tag' as it's usually 
//called in the md3 files try to
//see it as a sub-mesh/seperate
//mesh-part. + //sometimes this 64 string may
//contain some garbage, but
//i've been told this is because + //some tools leave garbage in
//those strings, but they ARE
//strings...
Vec3 Postition; //relative position of tag +Vec3x3 Rotation; //the direction the tag is facing relative to the rest of the model
+
+
+
+

comments:
+
fairly + obvious i think, the name is the name of the tag.
+ "position" is the relative position and "rotation" + is the relative rotation to the rest of the model.

+
+
+

After the tags come the + 'boneframes', frames in the bone animation.
+ The number of meshframes is usually identical to this number or simply + 1.
+
The header variable + BoneFrame_num + holds the ammount of BoneFrame..

+

BONEFRAME:

+
+
+
+
+
//unverified: 
+float  Mins[3];
+float  Maxs[3];
+float  Position[3];
+float  scale;
char Creator[16]; //i think this is the
//"creator" name.. + //but i'm only guessing. +
+
+
+
+
+

comments:
+
Mins, + Maxs, and position are very likely to be correct, scale is just a + guess.
+ If you divide the max
imum + and minimum xyz values of all the vertices from each meshframe you + get
+ the exact values as mins and maxs..
+ Position is the exact center of mins and maxs, most of the time anyway.

+

Creator + is very probably just the name of the program or file of which it + (the boneframe?) was created..
+ sometimes it's "(from ASE)" sometimes it's the name of a + .3ds file.
+

+

 

+

After the objects in the + file are the mesh-headers.
+ The header variable
Mesh_num + holds the ammount of Meshes..
+ Note that a mesh consists out of the mesh-header, the skins, the triangles, + the texture u/v coordinates and finally the vertices.
+ Each mesh contains that data, and the next mesh will only start after + the triangles, meshes etc. of the previous mesh.
+ To my suprise there are .md3 files that don't have any meshes in them! + This is something we need to look into.
+
+

+

MESH:

+
+
+
+
+
char ID[4];          //id, must be IDP3 
+char Name[68];       //name of mesh 
+                     //65 chars, 
//32 bit aligned == 68 chars +int MeshFrame_num; //number of meshframes + //in mesh +int Skin_num; //number of skins in mesh +int Vertex_num; //number of vertices +int Triangle_num; //number of Triangles +int Triangle_Start; //starting position of + //Triangle data, relative
//to start of Mesh_Header +int HeaderSize; //size of header +int TexVec_Start; //starting position of
//texvector data, relative
//to start of Mesh_Header +int Vertex_Start; //starting position of
//vertex data,relative
//to start of Mesh_Header +int MeshSize; //size of mesh +
+
+
+
+

comments:
+ Meshframe_num is the number + of quake1/quake2 type frames in the mesh.
+ (these frames work on a morph like way, the vertices are moved from + one position to another instead of rotated around eachother like in + bone-based-animations)
+ Skin_num is the number of skins in the md3 file..
+ These skins are animated.
+ Triangle_Start, TexVec_Start & Vertex_Start are the number of + bytes in the file from the start of the mesh header to the start of + the triangle, texvec and vertex data (in that order).
+

+

 

+

After the Mesh header come + the skin structures used by the mesh. +
+ The mesh header variable
Skin_num + holds the ammount of skins.. +

+

SKIN:

+
+
+
+
char Name[68]; //name of skin used by mesh
+               //65 chars, 
//32 bit aligned == 68 chars
+
+
+
+

comments:
+
Name + holds the name of the texture, relative to the baseq3 path.
+ Q3 has a peculiar way of handling textures..
+ The scripts in the /script directory in the baseq3 directory contain + scripts that hold information about how some surfaces are drawn and + animate (and out of how many layers it consist etc.)
+ Now the strange thing is, if you remove the ".tga" at the + end of the skin, and that name is used in the script files, than that + scripted surface is used.
+ If it isn't mentioned in the script files then the filename is used + to load the
+ tga file.

+


+ After the Skins come the + triangles.
+ The mesh header variable
Triangle_num + holds the ammount of triangles..

+
+
+

TRIANGLE

+
+
+
+
int  Triangle[3]; //vertex 1,2,3 of triangle
+              
+
+
+
+

comments:
+ This is the simplest of + structures.
+ A triangle has 3 points which make up the triangle, each point is + a vertex and the three ints that the triangle has point to those vertices.
+ So you have a list of vertices, for example you have a list of 28 + vertices and the triangle uses 3 of them: vertex 1, vertex 14 and + vertex 7.
+ Then the ints contain 1, 14 and 7.
+

+

 

+

After the triangle data + come the texture u/v coordinates of each vertex. The mesh header variable + Vertex_num + holds the ammount of u/v coordinates and vertices..
+ You have an U/V coordinate per vertex.

+
+
TEXTURE + U/V COORDINATES:
+
+
+
+
+
Vec2  TexVec; //Texture U/V coordinates of vertex 
+           
+
+
+
+
+

comments:
+ U/V coordinates are basically + the X/Y coordinates on the texture.
+ This is used by the triangles to know which part of the skin to display.
+

+

 

+

After the texture u/v coordinates + come the vertices.
+ The mesh header variable
Vertex_num + holds the ammount of vertices per frame, and the mesh header variable + MeshFrame_num + contains the ammount of frames in the mesh.
+ So you have
MeshFrame_num + times Vertex_num + vertices.
+

+
+
VERTICES: +
+
+
+
+
+             
+//!!!important!!! signed!
signed short Vec[3]; //vertex X/Y/Z coordinate +unsigned char EnvTex[2]; //enviromental mapping texture coordinates
+
+
+
comments:
+ Vec contains the 3d xyz coordinates + of the vertices that form the model.EnvTex + contains the texture coordinates for the enviromental mapping.
+ Why does md3 have a second set of texture coordinates?
+ Because:
+ 1.
these texture coordinates need to be interpolated when + the model changes shape,
+ 2. these texture coordinates are different from the normal texture coordinates + but still both need to be used (with shaders you can have multi-layered + surfaces, one could be an enviromental map, an other could be a transparent + texture)
+
+
+
+
+ + +