bliss.bas 282 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668
  1. ' Bliss (track editor for Stunts)
  2. ' Copyright (C) 2016-2023 Lucas Pedrosa
  3. ' This program is free software: you can redistribute it and/or modify
  4. ' it under the terms of the GNU General Public License as published by
  5. ' the Free Software Foundation, version 3 of the License.
  6. ' This program is distributed in the hope that it will be useful,
  7. ' but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. ' GNU General Public License for more details.
  10. ' You should have received a copy of the GNU General Public License
  11. ' along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. ' COMPILATION:
  13. ' Bliss has been compiled with FreeBasic 1.09.0 for GNU/Linux,
  14. ' DOS and Windows. It should compile well with any newer version
  15. ' and likely, with some older versions. You can get FreeBasic at:
  16. ' - http://www.freebasic.net
  17. ' For FreeDOS (or any other DOS), compile with:
  18. ' - fbc bliss.bas
  19. ' For GNU/Linux, compile with:
  20. ' - fbc bliss.bas bliss.xpm
  21. ' For Windows, compile with:
  22. ' - fbc -s gui bliss.bas bliss.rc
  23. #include "file.bi"
  24. #ifndef __FB_DOS__
  25. #include "http.bi"
  26. #undef GetParent
  27. #else
  28. Dim Shared use_curl As Byte = -1
  29. #endif
  30. #ifdef __FB_LINUX__
  31. #include once "fbgfx.bi"
  32. #include once "X11/Xlib.bi"
  33. #include once "X11/Xutil.bi"
  34. #include once "X11/keysymdef.bi"
  35. Declare Function Linkey As String
  36. Dim Shared LKdisp As Display Ptr, LKwindow As Window
  37. Dim Shared LKevent As XEvent, LKsym As KeySym
  38. Dim Shared LKstring As ZString * 26, LKinitialised As Byte = 0
  39. #define DIR_DIVISOR "/"
  40. #else
  41. #define DIR_DIVISOR "\"
  42. #endif
  43. #include "vbcompat.bi"
  44. #include "targalib.bi"
  45. #include "dir.bi"
  46. #define UNDOLEVEL 30
  47. #define MAXPATHS 1000
  48. #define THISVERSION "2.6.1"
  49. #define THISVERSION_NOPERIOD 20601
  50. #define LENGTHOF4AM 1895
  51. #define MAXCARS 20
  52. #define FORMAT_RAW 1
  53. #define FORMAT_COMBINED 2
  54. #define FORMAT_BINARY_SPLIT 3
  55. #define FORMAT_TEXT_SPLIT 4
  56. 'For DOS, there's no point in sacrificing performance, since Bliss would
  57. 'be the only primary process running
  58. #ifndef __FB_DOS__
  59. 'Set this to 0 to disable delays if performance is not good
  60. #define STRONG_ANTI_HOG -1
  61. #else
  62. #define STRONG_ANTI_HOG 0
  63. #endif
  64. 'If uncommented, font rendering in the TrackInfo menu will be done
  65. 'with Draw String and CP437 will be used. Otherwise, PutString will
  66. 'be used with Latin-1-Plus.
  67. '#define RENDER_TO_CP437
  68. #ifdef __FB_DOS__
  69. #undef ScreenLock
  70. #define ScreenLock DoNothing
  71. '#define ScreenLock FakeScreenLock
  72. #undef ScreenUnlock
  73. #define ScreenUnlock DoNothing
  74. '#define ScreenUnlock FakeScreenUnlock
  75. #undef WindowTitle
  76. #define WindowTitle DOSScreenTitle
  77. Declare Sub DoNothing
  78. Declare Sub DOSScreenTitle(title As String)
  79. Declare Sub FakeScreenLock
  80. Declare Sub FakeScreenUnlock
  81. #endif
  82. Type EncX 'Encoding translation
  83. utf32 As Long
  84. o As UByte 'Output
  85. End Type
  86. Type SGrid
  87. track As UByte
  88. land As UByte
  89. bgc As ULong 'Background colour
  90. border As ULong 'Border colour
  91. End Type
  92. Type TransType Field = 1 'To locate an icon for a track code
  93. x As UByte
  94. y As UByte
  95. w As UByte
  96. h As UByte
  97. id As ZString * 20
  98. hflip As UByte
  99. vflip As UByte
  100. cr As UByte 'Clockwise rotation
  101. ccr As UByte 'Counter-clockwise rotation
  102. xsmall As UByte 'Coordinates to small icon
  103. ysmall As UByte
  104. ctype(0 To 3) As UByte 'Connector types
  105. cto(0 To 3) As UByte 'Connector "to" (possible destinations)
  106. cisalt(0 To 3) As Byte 'Connector is alternative
  107. length As UByte 'Weighed length
  108. material As Byte
  109. entity As UByte 'What the tile does
  110. reserved(0 To 18) As UByte
  111. End Type
  112. Type ButtonType
  113. x1 As Short
  114. y1 As Short
  115. x2 As Short
  116. y2 As Short
  117. value As Short
  118. title As String
  119. End Type
  120. Type SelectorType
  121. opt(1 To 20) As String
  122. options As Byte
  123. current As Byte
  124. redraw As Byte
  125. wasinlasttime As Byte
  126. x1 As Short
  127. y1 As Short
  128. x2 As Short
  129. y2 As Short
  130. End Type
  131. Type FilerType
  132. x1 As Short
  133. y1 As Short
  134. x2 As Short
  135. y2 As Short
  136. reread As Byte
  137. mask As String
  138. End Type
  139. Type DirLink
  140. text As String
  141. directory As String
  142. End Type
  143. Type StringerType
  144. maxlength As Short
  145. x As Short
  146. y As Short
  147. s32 As String 'String in UTF-32 encoding
  148. sr As String 'String in CP437 (for rendering)
  149. 'last As String 'To keep the last edited string
  150. cursor_pos As Short
  151. t As Double
  152. fileonly As Byte
  153. cursor As Byte
  154. redraw As Byte
  155. init As Byte
  156. background As ULong
  157. End Type
  158. Type MetaData
  159. title As String
  160. author As String
  161. cyear As Short
  162. cmonth As Byte
  163. cday As Byte
  164. tool As String
  165. toolversion As ULong 'Example: 21305 for 2.13.5
  166. comment As String
  167. championship As String
  168. editing_time As Long 'In seconds
  169. End Type
  170. Type TrackVector
  171. Union
  172. coors As UShort 'Packed coordinates
  173. Type
  174. x As Byte
  175. y As Byte
  176. End Type
  177. End Union
  178. bearing As Byte 'Where it's going
  179. origin As Byte 'Where it came from
  180. e As Byte 'Error
  181. End Type
  182. Type TrackSection
  183. Union 'Starting node coordinates
  184. initial As UShort
  185. Type
  186. xo As Byte
  187. yo As Byte
  188. End Type
  189. End Union
  190. Union 'Ending node coordinates
  191. final As UShort
  192. Type
  193. xf As Byte
  194. yf As Byte
  195. End Type
  196. End Union
  197. solving As Byte 'Flag for this section being solved
  198. origin As Byte 'Direction from which the section was entered
  199. bearing As Byte 'Starting bearing
  200. parent(2) As Short 'Parent sections
  201. child(2) As Short 'Child sections
  202. finishes As Byte 'Leads to the finish line
  203. cycle As Byte 'Leads to a cycle
  204. wrongway As Byte 'Leads to wrong way
  205. errors As Byte 'Contains local errors
  206. e As Byte 'Error code
  207. End Type
  208. Type TrackError
  209. e As Byte 'Error type/code
  210. Union 'Error coordinates if applicable
  211. coors As UShort
  212. Type
  213. x As Byte
  214. y As Byte
  215. End Type
  216. End Union
  217. section As Short
  218. End Type
  219. Type TrackPath
  220. p As String 'The path itself
  221. e As Byte 'The error status
  222. finishes As Byte
  223. End Type
  224. Type Scoreboard
  225. racer As String
  226. handicap As Byte
  227. realtime As String
  228. hctime As String 'Handicapped time or effective points
  229. car As String
  230. style As String
  231. verified As Byte
  232. End Type
  233. Type Car
  234. id As String * 4
  235. cname As String
  236. handicap As Single
  237. End Type
  238. Declare Function Enc_UTF32_to_CP437 (s As String) As String
  239. Declare Function Enc_UTF32_to_Latin1 (s As String) As String
  240. Declare Function Enc_UTF32_to_UTF8 (s As String) As String
  241. Declare Function Enc_UTF8_to_UTF32 (s As String) As String
  242. Declare Function ConvertColour(c As String) As String
  243. Declare Sub DrawPanel
  244. Declare Sub DrawSpot(x As UByte, y As UByte, inked As Byte = 0)
  245. Declare Sub DrawTrack
  246. Declare Sub DrawBox(x1 As Short, y1 As Short, x2 As Short, y2 As Short)
  247. Declare Sub MenuBox(boxwidth As Short, boxheight As Short, title As String)
  248. Declare Sub SelectBackground
  249. Declare Sub LoadFont (fontfile As String)
  250. Declare Sub PutString (x As Short, y As Short, s As String, col As ULong, col2 As ULong = RGB(&HFF, 0, &HFF))
  251. Declare Sub TCentre(y As Short = -1, text As String = "", colour As ULong = RGB(255, 255, 255))
  252. Declare Sub TCont(text As String, eol As Byte = 0)
  253. Declare Sub AddButton(x As Short = -1, y As Short = -1, title As String, value As Short)
  254. Declare Sub StackButton(title As String, value As Short = -1, direction As Byte = 0, separation As UShort = 16)
  255. Declare Sub EndOfButtonStack
  256. Declare Function ManageButtons As Short
  257. Declare Sub ManageIcons
  258. Declare Function ManageString(ByRef s As String) As String
  259. Declare Function ManageSelector(sel As SelectorType) As Byte
  260. Declare Sub Error_Message(text As String, title As String = "Error!")
  261. Declare Sub Menu_License
  262. Declare Sub Menu_StartNewTrack
  263. Declare Sub Menu_LoadTrack
  264. Declare Sub Menu_SaveTrack
  265. Declare Sub Menu_TrackInfo
  266. Declare Sub Menu_Help
  267. Declare Sub Menu_Analysis
  268. Declare Sub Menu_Scenery
  269. Declare Sub Menu_Settings
  270. Declare Sub Menu_Tournaments
  271. Declare Sub Menu_TrackShot
  272. Declare Sub Menu_Colouring
  273. Declare Sub LoadConfiguration
  274. Declare Sub LoadGraphics
  275. Declare Sub LoadTrack(trk As String)
  276. Declare Sub SaveTrack(trk As String)
  277. Declare Sub SaveTrackImage(trk As String)
  278. Declare Sub LoadMetaData(filenumber As Short = 0, content As String = "")
  279. Declare Sub SaveMetaData(filenumber As Short)
  280. Declare Function GetMetaDataFromRegistry As Byte
  281. Declare Sub InitFiles(mask As String, x1 As Short, y1 As Short, x2 As Short, y2 As Short)
  282. Declare Sub DetectDrives
  283. Declare Sub SortFiles
  284. Declare Function ManageFiles(akey As String = "") As String
  285. Declare Sub ChangeTrackDirectory(d As String)
  286. Declare Sub LoadTransformations
  287. Declare Sub SaveTransformations
  288. Declare Function FindStart As TrackVector
  289. Declare Sub CheckTrack
  290. Declare Function GetNext(slot As TrackVector, detour As Byte = 0) As TrackVector
  291. Declare Sub GenerateSections
  292. Declare Sub SolveSection(sn As Short)
  293. Declare Sub SolvePath(pn As Short)
  294. Declare Function PathToError(te As Short) As String
  295. Declare Function PathToFinishLine(which As Byte = 0) As String
  296. Declare Sub FollowPath(s As String, e As Byte = 0)
  297. Declare Sub TrackErrorMessage(e As UByte)
  298. Declare Sub DetectTerrainErrors(ByRef e As UByte, ByRef x As Byte, ByRef y As Byte)
  299. Declare Function PathLength(n As Short, weighed As Byte = 0) As Long
  300. Declare Function Timey(t As Long) As String
  301. Declare Function AntiTimey(t As String) As Long
  302. Declare Sub SelectByTyping
  303. Declare Sub SmartSelect(etype As String, direction As Byte = 1)
  304. Declare Sub CreatePath
  305. Declare Sub PutIcon(u As UByte, v As UByte, x As UShort, y As UShort)
  306. Declare Sub PutSmallIcon(u As UByte, v As UByte, x As UShort, y As UShort)
  307. Declare Sub StartUp
  308. Declare Sub QuitProgram
  309. Declare Sub Editor
  310. Declare Sub UpdateTitleBar
  311. Declare Sub ClearTrack(x As UByte, y As UByte)
  312. Declare Sub PickTrack(x As UByte, y As UByte)
  313. Declare Sub SetTrack(x As UByte, y As UByte, code As UByte)
  314. Declare Function GetParent(x As UByte, y As UByte) As UByte
  315. Declare Sub BuildClosedCircuit
  316. Declare Sub LinkTiles
  317. Declare Sub RaiseTerrain(x As UByte, y As UByte)
  318. Declare Sub LowerTerrain(x As UByte, y As UByte)
  319. Declare Sub Flood(x As UByte, y As UByte)
  320. Declare Sub Dry(x As UByte, y As UByte)
  321. Declare Sub CopyOrCut(cut As Byte = 0)
  322. Declare Sub Paste
  323. Declare Sub CheckClipboardImport
  324. Declare Function GetTrack(x As UByte, y As UByte, x2 As UByte, y2 As UByte) As String
  325. Declare Sub PutTrack(x As UByte, y As UByte, t As String, forcefull As Byte = 0)
  326. Declare Function HFlipTrack(t As String) As String
  327. Declare Function VFlipTrack(t As String) As String
  328. Declare Function CRotate(t As String) As String
  329. Declare Function CCRotate(t As String) As String
  330. Declare Sub NotASquare
  331. Declare Sub PushUndo
  332. Declare Sub Undo
  333. Declare Sub Redo
  334. Declare Function Hash32 Overload (content As String) As ULong
  335. Declare Function Hash32 Overload As ULong
  336. Declare Function PackedClip(m() As SGrid, wi As Byte = -1, he As Byte = -1) As String
  337. Declare Sub DetectNotStunts(ByRef x As Byte, ByRef y As Byte, ByRef what As Byte)
  338. Declare Sub UnRLETerrain(s As String)
  339. Declare Function TMT_GetCurrentTrack(taddress As String) As Byte
  340. Declare Function TMT_GetMain(taddress As String, ByRef curtrack As String, ByRef deadline As String) As Byte
  341. Declare Function TMT_GetScoreboard(taddress As String, item() As Scoreboard, ByRef items As Byte) As Byte
  342. Const ptitle = "Bliss " + THISVERSION '+ " beta"
  343. '============================== Track structure variables
  344. Dim Shared grid(1 To 31, 1 To 31) As SGrid
  345. 'Grid is 30x30, but an extra row and column are added to prevent
  346. 'segmentation fault in calculations involving path following and
  347. 'track element shortcut keys when a large element has been placed
  348. 'across the "fence".
  349. Dim Shared clipboard As String, pasting As Byte = 0
  350. Dim Shared last_cb_file_length As Long = 0
  351. Dim Shared As Byte xselect, yselect, x2select, y2select, selecting = 0
  352. Dim Shared As Byte xcursor = 1, ycursor = 1, drawkeyboardcursor 'Keyboard cursor
  353. Dim Shared vlast As TrackVector
  354. Dim Shared tr(0 To 255) As TransType, itr(0 To 5, 0 To 5, 0 To 11) As UByte
  355. Dim Shared ttr(0 To 18) As TransType
  356. Dim Shared section(1 To 255) As TrackSection, sections As Short
  357. Dim Shared terror(1 To 100) As TrackError, terrors As Short
  358. Dim Shared path(1 To MAXPATHS) As TrackPath, paths As Short
  359. Dim Shared As UByte landscape = 4, format_byte = 152
  360. Dim Shared meta As MetaData, started_editing As Double
  361. Dim Shared default_format As UByte = FORMAT_COMBINED, thisfileformat As UByte = FORMAT_COMBINED
  362. Dim Shared default_author As String, racer_weigh As Double = 7.2955
  363. 'Other objects
  364. Dim Shared cars As Short, car(1 To MAXCARS) As Car, activecar As Byte
  365. 'Panel and graphics
  366. Dim Shared graphic_size As UByte = 16, bigwidth As UByte = 22
  367. Dim Shared As Short xoffs = 352, yoffs = 22 'Where to draw the track
  368. Dim Shared As Short xpanel = 0, ypanel = 0 'Where to draw the panel
  369. Dim Shared As Short xpalette = 198, ypalette = 484
  370. Dim Shared As Short xpicons = 80, ypicons = 74
  371. Dim Shared As Short xswitches = 70, yswitches = 380
  372. Dim Shared current_page As UByte = 0, current_brush As UByte = 1
  373. Dim Shared current_bgc As ULong = 0
  374. Dim Shared current_border As ULong = RGB(220, 200, 0)
  375. Dim Shared current_terrain_brush As UByte = 0
  376. Dim Shared bigicons As Any Pointer, track_image_buffer As Any Pointer = 0
  377. Dim Shared imageformat As String
  378. 'Undo-Redo
  379. Dim Shared undobuffer(0 To UNDOLEVEL - 1) As String
  380. Dim Shared As Short undohead = 0, undotail = UNDOLEVEL -1, undopointer = 0
  381. 'Switches
  382. Dim Shared As Byte show_errors = -1, allow_errors = 0
  383. Dim Shared As Byte data_codes = 0, smart_editing = 0
  384. Dim Shared As Byte show_grid = -1, colouring_mode = 0
  385. Dim Shared As Byte affect_terrain = 0, affect_track = -1
  386. 'Toolkit-related variables
  387. Dim Shared button(1 To 8) As ButtonType, buttons As Byte = 0
  388. Dim Shared cenx As Short, ceny As Short, lefx As Short
  389. Dim Shared conx As Short, cony As Short, concolour As ULong = RGB(200, 200, 200)
  390. 'File-related variables
  391. Dim Shared As String program_path, track_path, track_file
  392. Dim Shared big_graphics_file As String
  393. Dim Shared modified As Byte = 0
  394. Dim Shared filey(1 To 512) As String, fileys As Short = 0
  395. Dim Shared filer As FilerType, stringer As StringerType
  396. Dim Shared dirlinks As Byte = 0, dirlink(1 To 10) As DirLink
  397. 'Latin-1 font pointers
  398. Dim Shared As Any Ptr font, mask
  399. Dim Shared changing_title As Byte 'Flag for window title updates
  400. 'Encoding translation arrays
  401. Dim Shared toCP437(100) As EncX = _
  402. {(&HC1, 65), (&HC9, 144), (&HCD, 73), (&HD3, 79), (&HDA, 85), _
  403. (&HE1, 160), (&HE9, 130), (&HED, 161), (&HF3, 162), (&HFA, 163), _
  404. (&HD1, 165), (&HF1, 164), _
  405. (&HC4, 142), (&HCB, 69), (&HCF, 73), (&HD6, 153), (&HDC, 154), _
  406. (&HE4, 132), (&HEB, 137), (&HEF, 139), (&HF6, 148), (&HFC, 129), _
  407. (&HC7, 128), (&HE7, 135), _
  408. (&HC0, 65), (&HC8, 69), (&HCC, 73), (&HD2, 79), (&HD9, 85), _
  409. (&HE0, 133), (&HE8, 138), (&HEC, 141), (&HF2, 149), (&HF9, 151), _
  410. (&HC3, 65), (&HE3, 97), (&HD5, 79), (&HF5, 111), _
  411. (&HC2, 65), (&HCA, 69), (&HCE, 73), (&HD4, 79), (&HDB, 85), _
  412. (&HE2, 131), (&HEA, 136), (&HEE, 140), (&HF4, 147), (&HFB, 150), _
  413. (&HA1, 173), (&HBF, 168), (&HAB, 174), (&HBB, 175), _
  414. (&H150, 153), (&H151, 148), (&H170, 154), (&H171, 129)}
  415. 'CP437 to Unicode code points
  416. Dim Shared fromCP437(128) As Long = _
  417. {&HC7, &HFC, &HE9, &HE2, &HE4, &HE0, &HE5, &HE7, &HEA, &HEB, &HE8, &HEF, &HEE, &HEC, &HC4, &HC5, _
  418. &HC9, &HE6, &HC6, &HF4, &HF6, &HF2, &HFB, &HF9, &HFF, &HD6, &HDC, &HA2, &HA3, &HA5, &H20A7, &H192, _
  419. &HE1, &HED, &HF3, &HFA, &HF1, &HD1, &HAA, &HBA, &HBF, &H2310, &HAC, &HBD, &HBC, &HA1, &HAB, &HBB, _
  420. &H2591, &H2592, &H2593, &H2502, &H2524, &H2561, &H2562, &H2556, &H2555, &H2563, &H2551, &H2557, &H255D, &H255C, &H255B, &H2510, _
  421. &H2514, &H2534, &H252C, &H251C, &H2500, &H253C, &H255E, &H255F, &H255A, &H2554, &H2569, &H2566, &H2560, &H2550, &H256C, &H2567, _
  422. &H2568, &H2564, &H2565, &H2559, &H2558, &H2552, &H2553, &H256B, &H256A, &H2518, &H250C, &H2588, &H2584, &H258C, &H2590, &H2580, _
  423. &H321, &HDF, &H393, &H3C0, &H3A3, &H3C3, &HB4, &H3C4, &H3A6, &H398, &H3A9, &H3B4, &H221E, &H3C6, &H3B5, &H2229, _
  424. &H2261, &HB1, &H2265, &H2264, &H2320, &H2321, &HF7, &H2248, &HB0, &H2219, &HB7, &H221A, &H207F, &HB2, &H25A0, &HA0}
  425. 'Colouring palette
  426. Dim Shared cpal(0 To 23) As ULong = _
  427. {0, &HFFE0E000, &HFF5050FF, &HFFE02000, &HFF20E000, &HFFF08000, _
  428. &HFFA020FF, &HFFE0E0E0, &HFF808080, &HFF404040, &HFF000000, &HFFA0E000, _
  429. &HFF804020, &HFFE010F0, &HFF20E0A0, &HFFE04040, &HFF4040E0, &HFF00E0E0, _
  430. &HFFF020B0, &HFFFED000, &HFFE080FF, &HFF806010, &HFFA7E189, &HFF495827 }
  431. 'DOSBox flag
  432. Dim Shared dosbox As Byte = 0
  433. StartUp
  434. #ifdef __FB_DOS__
  435. Dim Shared fake_screenlock_level As Short = 0
  436. dosbox = ScreenRes(1024, 768, 32, 2)
  437. If dosbox Then ScreenRes 1024, 768, 16, 2
  438. Width 128, 48
  439. Line (0, 0)-(1023, 767), RGB(30, 30, 50), BF
  440. yoffs += 64
  441. ypanel += 64
  442. #else
  443. ScreenRes 1024, 704, 32
  444. Width 128, 44
  445. Line (0, 0)-(1023, 703), RGB(30, 30, 50), BF
  446. HTTP_Start
  447. #endif
  448. big_graphics_file = "biggfx"
  449. LoadConfiguration
  450. LoadGraphics
  451. LoadTransformations
  452. #ifndef RENDER_TO_CP437
  453. LoadFont "latin1p"
  454. #endif
  455. Dim today As Double
  456. today = Now
  457. meta.cyear = DatePart("yyyy", today)
  458. meta.cmonth = DatePart("m", today)
  459. meta.cday = DatePart("d", today)
  460. meta.tool = "Bliss"
  461. meta.toolversion = THISVERSION_NOPERIOD
  462. meta.author = default_author
  463. started_editing = Timer
  464. thisfileformat = default_format
  465. If bigwidth = 16 Then xoffs += 180
  466. If Len(Command) Then
  467. Dim afile As String
  468. afile = Trim(Command)
  469. If FileExists(afile) Or FileExists(afile + ".trk") Then
  470. LoadTrack afile
  471. 'This makes the file menus default to the directory
  472. 'that the track was loaded from
  473. Dim n As Short
  474. #ifdef __FB_LINUX__
  475. n = InStrRev(afile, "/")
  476. #else
  477. n = InStrRev(afile, "\")
  478. #endif
  479. If n Then
  480. track_path = Left(afile, n)
  481. Else
  482. track_path = ""
  483. End If
  484. End If
  485. End If
  486. UpdateTitleBar
  487. DrawTrack
  488. DrawPanel
  489. Menu_License
  490. Editor
  491. ImageDestroy bigicons
  492. #ifndef RENDER_TO_CP437
  493. ImageDestroy font
  494. ImageDestroy mask
  495. #endif
  496. #ifndef __FB_DOS__
  497. HTTP_End
  498. #endif
  499. End
  500. Function PackedClip(m() As SGrid, wi As Byte = -1, he As Byte = -1) As String
  501. Dim As Byte w, h, c, i, j
  502. Dim t As String, r As String
  503. If wi = -1 Then w = UBound(m, 1) Else w = wi
  504. If he = -1 Then h = UBound(m, 2) Else h = he
  505. t = Chr(w, h)
  506. For j = 1 To h
  507. For i = 1 to w
  508. c = 0 : r = ""
  509. If m(i, j).track Then
  510. c Or= 1
  511. r &= Chr(m(i, j).track)
  512. End If
  513. If m(i, j).land Then
  514. c Or= 2
  515. r &= Chr(m(i, j).land)
  516. End If
  517. If m(i, j).border Then
  518. c Or= 4
  519. r &= MkL(m(i, j).border)
  520. End If
  521. If m(i, j).bgc Then
  522. c Or= 8
  523. r &= MkL(m(i, j).bgc)
  524. End If
  525. t &= Chr(c) & r
  526. Next i
  527. Next j
  528. Return t
  529. End Function
  530. Sub DrawPanel
  531. Dim As Short sourcex, sourcey, i
  532. Dim s As String
  533. Dim indicator(0 To 8) As Short
  534. indicator(0) = Len(clipboard) <> 0
  535. indicator(1) = show_errors
  536. indicator(2) = allow_errors
  537. indicator(3) = data_codes
  538. indicator(4) = show_grid
  539. indicator(5) = affect_track
  540. indicator(6) = affect_terrain
  541. indicator(7) = colouring_mode
  542. indicator(8) = 0
  543. ScreenLock
  544. Line (xpanel, ypanel)-(xoffs - 1, ypanel + 704), RGB(30, 30, 50), BF
  545. 'Draw border around menu icons
  546. Line (xpanel + xpicons - 32, ypanel + ypicons - 32)- STEP (239, 315), RGB(55, 65, 110), B
  547. Line (xpanel + xpicons - 31, ypanel + ypicons - 33)- STEP (239, 315), RGB(20, 20, 20), B
  548. If dosbox Then
  549. Put (xpanel + xpicons, ypanel + ypicons), bigicons, (13 * bigwidth, 12 * 22)- STEP (8 * bigwidth - 1, 219), Trans
  550. Else
  551. Put (xpanel + xpicons, ypanel + ypicons), bigicons, (13 * bigwidth, 12 * 22)- STEP (8 * bigwidth - 1, 219), Alpha
  552. End If
  553. 'Draw switch indicator icons
  554. For i = 0 To 8
  555. PutIcon 21 + i, 12 - 2 * indicator(i), xpanel + xswitches + bigwidth * i, ypanel + yswitches
  556. Next i
  557. Select Case landscape
  558. Case 0 : s = "Desert"
  559. Case 1 : s = "Tropical"
  560. Case 2 : s = "Alpine"
  561. Case 3 : s = "City"
  562. Case 4 : s = "Country"
  563. Case Else : s = "Background #" + Trim(Str(landscape))
  564. End Select
  565. Draw String (100 - Len(s) * 4, 640 + ypanel), s, RGB(70, 200, 240)
  566. If landscape < 5 Then
  567. For i = 0 To 9
  568. PutSmallIcon i + 31, landscape + 21, xpanel + i * graphic_size + 20, ypanel + 664
  569. Next i
  570. Else
  571. Draw String (72, 664), "Chaotic", RGB(240, 160, 50)
  572. End If
  573. 'Display border for coordinates and pointed element
  574. 'and colouring options if activated
  575. If colouring_mode Then
  576. Line (xpanel + 16, ypanel + 420)- STEP (165, 47), RGB(55, 65, 110), B
  577. Line (xpanel + 17, ypanel + 419)- STEP (165, 47), RGB(20, 20, 20), B
  578. Line (xpanel + xpalette, ypanel + 420)- STEP (132, 47), RGB(55, 65, 110), B
  579. Line (xpanel + xpalette + 1, ypanel + 419)- STEP (132, 47), RGB(20, 20, 20), B
  580. If current_bgc Then
  581. Line (xpanel + xpalette + 16, ypanel + 434)- STEP (21, 21), current_bgc, BF
  582. Else
  583. Line (xpanel + xpalette + 16, ypanel + 434)- STEP (21, 21), RGB(100, 100, 100), B
  584. End If
  585. If current_border Then
  586. Line (xpanel + xpalette + 48, ypanel + 434)- STEP (21, 21), current_border, B
  587. Line (xpanel + xpalette + 49, ypanel + 435)- STEP (19, 19), current_border, B
  588. Else
  589. Line (xpanel + xpalette + 48, ypanel + 434)- STEP (21, 21), RGB(100, 100, 100), B, &H5555
  590. End If
  591. Else
  592. Line (xpanel + 16, ypanel + 420)- STEP (314, 47), RGB(55, 65, 110), B
  593. Line (xpanel + 17, ypanel + 419)- STEP (314, 47), RGB(20, 20, 20), B
  594. End If
  595. 'Display current brush
  596. Line (xpanel + 16, ypanel + ypalette + 1)-(xpanel + 181, ypanel + ypalette + 131), RGB(55, 65, 110), B
  597. Line (xpanel + 17, ypanel + ypalette)-(xpanel + 182, ypanel + ypalette + 130), RGB(20, 20, 20), B
  598. If current_page >= 10 Then
  599. If current_terrain_brush <= 18 Then _
  600. PutIcon ttr(current_terrain_brush).x + 2, ttr(current_terrain_brush).y + 1, xpanel + 88, ypanel + ypalette + 44
  601. Select Case current_terrain_brush
  602. Case 0 : s = "Grass"
  603. Case 1 To 5 : s = "Water"
  604. Case 6 To 18 : s = "Mountain"
  605. Case Else : s = "Invalid"
  606. End Select
  607. Draw String (xpanel + 99 - Len(s) * 4, ypanel + ypalette + 82), s, RGB(255, 255, 255)
  608. Else
  609. If tr(current_brush).h = 1 And tr(current_brush).w = 1 Then
  610. PutIcon tr(current_brush).x, tr(current_brush).y, xpanel + 88, ypanel + ypalette + 44
  611. ElseIf tr(current_brush).h = 2 And tr(current_brush).w = 2 Then
  612. PutIcon tr(current_brush).x, tr(current_brush).y, xpanel + 77, ypanel + ypalette + 33
  613. PutIcon tr(current_brush).x + 1, tr(current_brush).y, xpanel + 99, ypanel + ypalette + 33
  614. PutIcon tr(current_brush).x, tr(current_brush).y + 1, xpanel + 77, ypanel + ypalette + 55
  615. PutIcon tr(current_brush).x + 1, tr(current_brush).y + 1, xpanel + 99, ypanel + ypalette + 55
  616. ElseIf tr(current_brush).h = 2 And tr(current_brush).w = 1 Then
  617. PutIcon tr(current_brush).x, tr(current_brush).y, xpanel + 88, ypanel + ypalette + 33
  618. PutIcon tr(current_brush).x, tr(current_brush).y + 1, xpanel + 88, ypanel + ypalette + 55
  619. ElseIf tr(current_brush).h = 1 And tr(current_brush).w = 2 Then
  620. PutIcon tr(current_brush).x, tr(current_brush).y, xpanel + 77, ypanel + ypalette + 44
  621. PutIcon tr(current_brush).x + 1, tr(current_brush).y, xpanel + 99, ypanel + ypalette + 44
  622. End If
  623. Draw String (xpanel + 99 - Len(Trim(tr(current_brush).id)) * 4, ypanel + ypalette + 82), Trim(tr(current_brush).id), RGB(255, 255, 255)
  624. End If
  625. 'Draw palette
  626. If current_page = 10 Then
  627. Put (xpanel + xpalette, ypanel + ypalette), bigicons, (0, 12 * 22)- STEP (6 * bigwidth - 1, 6 * 22 - 1), PSet
  628. 'Draw palette grid
  629. For i = 0 To 6
  630. Line (xpanel + xpalette, ypanel + ypalette + 22 * i)- STEP (6 * bigwidth - 1, 0), 0
  631. Line (xpanel + xpalette + bigwidth * i, ypanel + ypalette)- STEP (0, 6 * 22 - 1), 0
  632. Next i
  633. ElseIf current_page >= 11 Then
  634. Line (xpanel + xpalette, ypanel + ypalette)- STEP(6 * bigwidth - 1, 6 * 22 - 1), RGB(&H0B, &H64, &H1B), BF
  635. Line (xpanel + xpalette, ypanel + ypalette)- STEP(6 * bigwidth, 6 * 22), 0, B
  636. Put (xpanel + xpalette + bigwidth, ypanel + ypalette + 2 * 22), bigicons, (2 * bigwidth, 14 * 22)- STEP (2 * bigwidth - 1, 2 * 22 - 1), PSet
  637. Put (xpanel + xpalette + 3 * bigwidth, ypanel + ypalette + 2 * 22), bigicons, (2 * bigwidth, 16 * 22)- STEP (2 * bigwidth - 1, 2 * 22 - 1), PSet
  638. Else
  639. sourcex = 6 * bigwidth * (current_page Mod 5)
  640. sourcey = 6 * 22 * (current_page \ 5)
  641. 'Draw palette grid
  642. Line (xpanel + xpalette, ypanel + ypalette)- STEP(6 * bigwidth - 1, 6 * 22 - 1), RGB(&H0B, &H64, &H1B), BF
  643. For i = 0 To 6
  644. Line (xpanel + xpalette, ypanel + ypalette + 22 * i)- STEP (6 * bigwidth - 1, 0), 0
  645. Line (xpanel + xpalette + bigwidth * i, ypanel + ypalette)- STEP (0, 6 * 22 - 1), 0
  646. Next i
  647. 'Draw palette icons
  648. If dosbox Then
  649. Put (xpanel + xpalette, ypanel + ypalette), bigicons, (sourcex, sourcey)- STEP (6 * bigwidth - 1, 6 * 22 - 1), Trans
  650. Else
  651. Put (xpanel + xpalette, ypanel + ypalette), bigicons, (sourcex, sourcey)- STEP (6 * bigwidth - 1, 6 * 22 - 1), Alpha
  652. End If
  653. End If
  654. Line (xpanel + xpalette, ypanel + ypalette + 22 * 7)- STEP (6 * bigwidth - 1, 2 * 22 - 1), RGB(30, 30, 50), BF
  655. If current_page < 10 Then
  656. Line (xpanel + xpalette + (current_page Mod 5) * bigwidth, ypanel + ypalette + (current_page \ 5 + 7) * 22)- STEP (21, 21), RGB(40, 160, 160), BF
  657. Else
  658. Line (xpanel + xpalette + 5 * bigwidth, ypanel + ypalette + (current_page - 3) * 22)- STEP (21, 21), RGB(40, 160, 160), BF
  659. End If
  660. 'Draw palette page list buttons
  661. If dosbox Then
  662. Put (xpanel + xpalette, ypanel + ypalette + 22 * 7), bigicons, (7 * bigwidth, 12 * 22)- STEP (6 * bigwidth - 1, 2 * 22 - 1), Trans
  663. Else
  664. Put (xpanel + xpalette, ypanel + ypalette + 22 * 7), bigicons, (7 * bigwidth, 12 * 22)- STEP (6 * bigwidth - 1, 2 * 22 - 1), Alpha
  665. End If
  666. ScreenUnlock
  667. End Sub
  668. Sub DrawSpot(x As UByte, y As UByte, inked As Byte = 0)
  669. 'Draw the full contents of a square in the map (both track and terrain)
  670. Dim As UByte c, t
  671. Dim As ULong bgc, border
  672. Dim As Short xg, yg
  673. Dim conflict As Byte
  674. c = grid(x, y).land
  675. t = grid(x, y).track
  676. bgc = grid(x, y).bgc
  677. border = grid(x, y).border
  678. xg = (x - 1) * bigwidth
  679. yg = (y - 1) * 22
  680. If track_image_buffer = 0 Then
  681. xg += xoffs
  682. yg += yoffs
  683. End If
  684. 'First, draw the terrain
  685. If c > 18 Then
  686. If show_errors Then
  687. PutIcon 6, 12, xg, yg
  688. If data_codes <> 0 AndAlso t = 0 Then
  689. Draw String (xg + 4, yg + 4), Hex(c, 2), RGB(0, 0, 0)
  690. End If
  691. Else
  692. PutIcon 0, 12, xg, yg
  693. End If
  694. Else
  695. If show_errors Then
  696. Select Case c
  697. Case 0, 6
  698. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  699. Case 7
  700. If t = 0 Or t = 4 Or t = 14 Or t = 24 Or t = 39 Or t = 59 Or t = 98 Then
  701. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  702. Else
  703. PutIcon 6, 13, xg, yg
  704. End If
  705. Case 8
  706. If t = 0 Or t = 5 Or t = 15 Or t = 25 Or t = 36 Or t = 56 Or t = 95 Then
  707. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  708. Else
  709. PutIcon 6, 13, xg, yg
  710. End If
  711. Case 9
  712. If t = 0 Or t = 4 Or t = 14 Or t = 24 Or t = 38 Or t = 58 Or t = 97 Then
  713. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  714. Else
  715. PutIcon 6, 13, xg, yg
  716. End If
  717. Case 10
  718. If t = 0 Or t = 5 Or t = 15 Or t = 25 Or t = 37 Or t = 57 Or t = 96 Then
  719. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  720. Else
  721. PutIcon 6, 13, xg, yg
  722. End If
  723. Case 11 To 18
  724. If t = 0 Then
  725. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  726. Else
  727. PutIcon 6, 13, xg, yg
  728. End If
  729. Case Else 'The ones that have water
  730. If (tr(t).w > 1 Or tr(t).h > 1) And (t < 105 Or t > 108) Then
  731. PutIcon 6, 16, xg, yg
  732. Else
  733. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  734. End If
  735. End Select
  736. Else
  737. PutIcon ttr(c).x + 2, ttr(c).y + 1, xg, yg
  738. End If
  739. End If
  740. 'Paint background colour if any
  741. If bgc Then
  742. Line track_image_buffer, (xg, yg)- Step (bigwidth - 1, 21), bgc, BF
  743. End If
  744. 'If grid view is active, show grid between terrain and track
  745. 'If show_grid Then Line (xg, yg)- Step (bigwidth, 22), 0, B
  746. If show_grid Then
  747. If track_image_buffer = 0 Then
  748. Line (xg + bigwidth - 1, yg)-(xg, yg), 0
  749. Line -(xg, yg + 21), 0
  750. Else
  751. Line track_image_buffer, (xg + bigwidth - 1, yg)-(xg, yg), RGB(0, 0, 0)
  752. Line track_image_buffer, -(xg, yg + 21), RGB(0, 0, 0)
  753. End If
  754. End If
  755. 'Second, if it's a slope, draw the guides
  756. If (c = 7 Or c = 9) And (t = 4 Or t = 14 Or t = 24) Then 'North and South
  757. PutIcon 6, 15, xg, yg
  758. ElseIf (c = 8 Or c = 10) And (t = 5 Or t = 15 Or t = 25) Then 'East and West
  759. PutIcon 7, 15, xg, yg
  760. End If
  761. 'Then draw the track
  762. If t >= 182 And t <= 252 Then
  763. If show_errors Then
  764. If data_codes Then
  765. Draw String (xg + 4, yg + 4), Hex(t, 2), RGB(200, 180, 0)
  766. Else
  767. PutIcon 6, 14, xg, yg
  768. End If
  769. End If
  770. ElseIf t < 182 Then
  771. If t = &H42 Then 'Vertical tunnel
  772. If (y = 1 OrElse grid(x, y - 1).track <> &H42) And (y = 30 OrElse grid(x, y + 1).track <> &H42) then
  773. PutIcon tr(t).x, tr(t).y, xg, yg
  774. ElseIf y > 1 And y < 30 AndAlso grid(x, y - 1).track = &H42 AndAlso grid(x, y + 1).track = &H42 Then
  775. PutIcon 8, 17, xg, yg
  776. ElseIf y > 1 AndAlso grid(x, y - 1).track = &H42 Then
  777. PutIcon 9, 17, xg, yg
  778. Else
  779. PutIcon 7, 17, xg, yg
  780. End If
  781. ElseIf t = &H43 Then 'Horizontal tunnel
  782. If (x = 1 OrElse grid(x - 1, y).track <> &H43) And (x = 30 OrElse grid(x + 1, y).track <> &H43) then
  783. PutIcon tr(t).x, tr(t).y, xg, yg
  784. ElseIf x > 1 And x < 30 AndAlso grid(x - 1, y).track = &H43 AndAlso grid(x + 1, y).track = &H43 Then
  785. PutIcon 8, 16, xg, yg
  786. ElseIf x > 1 AndAlso grid(x - 1, y).track = &H43 Then
  787. PutIcon 9, 16, xg, yg
  788. Else
  789. PutIcon 7, 16, xg, yg
  790. End If
  791. ElseIf data_codes <> 0 AndAlso (tr(t).w > 1 Or tr(t).h > 1) Then
  792. PutIcon tr(t).xsmall, tr(t).ysmall, xg, yg
  793. Else
  794. PutIcon tr(t).x, tr(t).y, xg, yg
  795. End If
  796. conflict = 0
  797. If x > 1 AndAlso tr(grid(x - 1, y).track).w = 2 Then conflict = -1
  798. If y > 1 AndAlso tr(grid(x, y - 1).track).h = 2 Then conflict = -1
  799. If (x > 1 And y > 1) AndAlso (tr(grid(x - 1, y - 1).track).h = 2 And tr(grid(x - 1, y - 1).track).w = 2) Then conflict = -1
  800. If conflict <> 0 And show_errors <> 0 Then
  801. If track_image_buffer = 0 Then
  802. Line (xg, yg)-(xg + bigwidth - 1, yg + 21), RGB(&HF0, &HD0, 0), B
  803. Else
  804. Line track_image_buffer, (xg, yg)-(xg + bigwidth - 1, yg + 21), RGB(&HF0, &HD0, 0), B
  805. End If
  806. End If
  807. ElseIf t = 253 Then
  808. If data_codes Then
  809. PutIcon 7, 14, xg, yg
  810. Else
  811. If x = 1 Or y = 1 OrElse tr(grid(x - 1, y - 1).track).w < 2 OrElse tr(grid(x - 1, y - 1).track).h < 2 Then
  812. If show_errors Then PutIcon 6, 14, xg, yg
  813. Else
  814. PutIcon tr(grid(x - 1, y - 1).track).x + 1, tr(grid(x - 1, y - 1).track).y + 1, xg, yg
  815. End If
  816. End If
  817. ElseIf t = 254 Then
  818. If data_codes Then
  819. PutIcon 8, 14, xg, yg
  820. Else
  821. If y = 1 OrElse tr(grid(x, y - 1).track).h < 2 Then
  822. If show_errors Then PutIcon 6, 14, xg, yg
  823. Else
  824. PutIcon tr(grid(x, y - 1).track).x, tr(grid(x, y - 1).track).y + 1, xg, yg
  825. End If
  826. End If
  827. ElseIf t = 255 Then
  828. If data_codes Then
  829. PutIcon 9, 14, xg, yg
  830. Else
  831. If x = 1 OrElse tr(grid(x - 1, y).track).w < 2 Then
  832. If show_errors Then PutIcon 6, 14, xg, yg
  833. Else
  834. PutIcon tr(grid(x - 1, y).track).x + 1, tr(grid(x - 1, y).track).y, xg, yg
  835. End If
  836. End If
  837. End If
  838. 'Draw border if any
  839. If border Then
  840. If y < 1 OrElse grid(x, y - 1).border <> border Then _
  841. Line track_image_buffer, (xg, yg)- Step (bigwidth - 1, 1), border, B
  842. If x < 1 OrElse grid(x - 1, y).border <> border Then _
  843. Line track_image_buffer, (xg, yg)- Step (1, 21), border, B
  844. If y > 29 OrElse grid(x, y + 1).border <> border Then _
  845. Line track_image_buffer, (xg, yg + 21)- Step (bigwidth - 1, -1), border, B
  846. If x > 29 OrElse grid(x + 1, y).border <> border Then _
  847. Line track_image_buffer, (xg + bigwidth - 1, yg)- Step (-1, 21), border, B
  848. End If
  849. 'Mark as selected if it is
  850. If xselect Then
  851. Dim As Short xs1, xs2, ys1, ys2
  852. If xselect <= x2select Then xs1 = xselect : xs2 = x2select Else xs1 = x2select : xs2 = xselect
  853. If yselect <= y2select Then ys1 = yselect : ys2 = y2select Else ys1 = y2select : ys2 = yselect
  854. If x >= xs1 And x <= xs2 And _
  855. y >= ys1 And y <= ys2 Then
  856. If dosbox Then
  857. PutIcon 9, 15, xg, yg
  858. Else
  859. PutIcon 8, 15, xg, yg
  860. End If
  861. End If
  862. End If
  863. 'Also mark it if just requested
  864. If inked Then PutIcon 8, 15, xg, yg
  865. End Sub
  866. Sub DrawTrack
  867. Dim As Short x, y
  868. ScreenLock
  869. If track_image_buffer = 0 Then
  870. If show_grid Then
  871. Line (xoffs, yoffs)-(xoffs + 30 * bigwidth, yoffs + 30 * 22), 0, B
  872. Else
  873. Line (xoffs, yoffs)-(xoffs + 30 * bigwidth, yoffs + 30 * 22), RGB(30, 30, 50), B
  874. End If
  875. Else
  876. If show_grid Then
  877. Line track_image_buffer, (0, 0)-(30 * bigwidth, 30 * 22), RGB(0, 0, 0), B
  878. Else
  879. Line track_image_buffer, (0, 0)-(30 * bigwidth, 30 * 22), RGB(30, 30, 50), B
  880. End If
  881. End If
  882. For y = 1 To 30
  883. For x = 1 To 30
  884. DrawSpot x, y
  885. Next x
  886. Next y
  887. ScreenUnlock
  888. End Sub
  889. 'Detect whether something exists on the grid that could not have
  890. 'been created by Stunts built-in editor
  891. Sub DetectNotStunts(ByRef x As Byte, ByRef y As Byte, ByRef what As Byte)
  892. Dim As Byte i, j
  893. what = 0
  894. 'Non-standard terrain elements
  895. For j = 1 To 30
  896. For i = 1 To 30
  897. If grid(i, j).land > 18 Then
  898. what = 1
  899. x = i : y = j
  900. Exit Sub
  901. End If
  902. Next i
  903. Next j
  904. 'Non-standard track elements
  905. For j = 1 To 30
  906. For i = 1 To 30
  907. If grid(i, j).track >= &HB6 And grid(i, j).track <= &HFC Then
  908. what = 2
  909. x = i : y = j
  910. Exit Sub
  911. ElseIf grid(i, j).track = 2 Or grid(i, j).track = 3 Then
  912. what = 3 'Player's or Opponent's car
  913. x = i : y = j
  914. Exit Sub
  915. End If
  916. Next i
  917. Next j
  918. 'Big track element without its corresponding fillers
  919. For j = 1 To 30
  920. For i = 1 To 30
  921. If tr(grid(i, j).track).w = 2 Then
  922. If i = 30 OrElse grid(i + 1, j).track <> 255 Then _
  923. what = 4
  924. End If
  925. If tr(grid(i, j).track).h = 2 Then
  926. If j = 30 OrElse grid(i, j + 1).track <> 254 Then
  927. what = 4
  928. ElseIf tr(grid(i, j).track).w = 2 Then
  929. If i = 30 OrElse grid(i + 1, j + 1).track <> 253 Then _
  930. what = 4
  931. End If
  932. End If
  933. If what Then
  934. x = i : y = j
  935. Exit Sub
  936. End If
  937. Next i
  938. Next j
  939. 'Filler without a parent track element
  940. For j = 1 To 30
  941. For i = 1 To 30
  942. Select Case grid(i, j).track
  943. Case 253
  944. If i = 1 Or j = 1 OrElse _
  945. (tr(grid(i - 1, j - 1).track).h < 2 Or _
  946. tr(grid(i - 1, j - 1).track).w < 2) Then what = 5
  947. Case 254
  948. If j = 1 OrElse tr(grid(i, j - 1).track).h < 2 Then what = 5
  949. Case 255
  950. If i = 1 OrElse tr(grid(i - 1, j).track).w < 2 Then what = 5
  951. End Select
  952. If what Then
  953. x = i : y = j
  954. Exit Sub
  955. End If
  956. Next i
  957. Next j
  958. 'Mountain corner with something on top
  959. For j = 1 To 30
  960. For i = 1 To 30
  961. If grid(i, j).land >= 11 And grid(i, j).track <> 0 Then
  962. what = 6
  963. x = i : y = j
  964. Exit Sub
  965. End If
  966. Next i
  967. Next j
  968. 'Mountain side with illegal element on top
  969. For j = 1 To 30
  970. For i = 1 To 30
  971. Select Case grid(i, j).land
  972. Case 7
  973. If InStr(Chr(0, 4, 14, &H18, &H3B, &H27, &H62), Chr(grid(i, j).track)) = 0 Then _
  974. what = 7
  975. Case 8
  976. If InStr(Chr(0, 5, 15, &H19, &H38, &H24, &H5F), Chr(grid(i, j).track)) = 0 Then _
  977. what = 7
  978. Case 9
  979. If InStr(Chr(0, 4, 14, &H18, &H3A, &H26, &H61), Chr(grid(i, j).track)) = 0 Then _
  980. what = 7
  981. Case 10
  982. If InStr(Chr(0, 5, 15, &H19, &H39, &H25, &H60), Chr(grid(i, j).track)) = 0 Then _
  983. what = 7
  984. End Select
  985. If what Then
  986. x = i : y = j
  987. Exit Sub
  988. End If
  989. Next i
  990. Next j
  991. 'Water with illegal element on top
  992. For j = 1 To 30
  993. For i = 1 To 30
  994. If grid(i, j).land >= 1 And grid(i, j).land <= 5 Then
  995. If InStr(Chr(0, &H68, &H23, &H67, &H22, &H69, &H6A, _
  996. &H6B, &H6C, &HAB, &HAE, &HAC, &HAD, &HFD, &HFE, _
  997. &HFF), Chr(grid(i, j).track)) = 0 Then
  998. what = 8
  999. x = i : y = j
  1000. Exit Sub
  1001. End If
  1002. End If
  1003. Next i
  1004. Next j
  1005. 'It is still possible to draw a part of a big element, not
  1006. 'including the parent block, on water and go undetected!
  1007. End Sub
  1008. Sub DetectTerrainErrors(ByRef e As UByte, ByRef x As Byte, ByRef y As Byte)
  1009. Dim As Byte i, j
  1010. e = 0
  1011. 'Non-standard terrain elements - Error 40
  1012. For j = 1 To 30
  1013. For i = 1 To 30
  1014. If grid(i, j).land > 18 Then
  1015. e = 40
  1016. x = i : y = j
  1017. Exit Sub
  1018. End If
  1019. Next i
  1020. Next j
  1021. 'Mountain borders mismatch - Error 41
  1022. Dim tvert(0 To 18, 0 To 1, 0 To 1) As Byte
  1023. 'First create terrain element descriptors
  1024. tvert(6, 0, 0) = 1 : tvert(6, 0, 1) = 1
  1025. tvert(6, 1, 0) = 1 : tvert(6, 1, 1) = 1
  1026. tvert(7, 0, 0) = 1 : tvert(7, 0, 1) = 1
  1027. tvert(7, 1, 0) = 0 : tvert(7, 1, 1) = 0
  1028. tvert(8, 0, 0) = 1 : tvert(8, 0, 1) = 0
  1029. tvert(8, 1, 0) = 1 : tvert(8, 1, 1) = 0
  1030. tvert(9, 0, 0) = 0 : tvert(9, 0, 1) = 0
  1031. tvert(9, 1, 0) = 1 : tvert(9, 1, 1) = 1
  1032. tvert(10, 0, 0) = 0 : tvert(10, 0, 1) = 1
  1033. tvert(10, 1, 0) = 0 : tvert(10, 1, 1) = 1
  1034. tvert(11, 0, 0) = 1 : tvert(11, 0, 1) = 0
  1035. tvert(11, 1, 0) = 0 : tvert(11, 1, 1) = 0
  1036. tvert(12, 0, 0) = 0 : tvert(12, 0, 1) = 0
  1037. tvert(12, 1, 0) = 1 : tvert(12, 1, 1) = 0
  1038. tvert(13, 0, 0) = 0 : tvert(13, 0, 1) = 0
  1039. tvert(13, 1, 0) = 0 : tvert(13, 1, 1) = 1
  1040. tvert(14, 0, 0) = 0 : tvert(14, 0, 1) = 1
  1041. tvert(14, 1, 0) = 0 : tvert(14, 1, 1) = 0
  1042. tvert(15, 0, 0) = 1 : tvert(15, 0, 1) = 1
  1043. tvert(15, 1, 0) = 1 : tvert(15, 1, 1) = 0
  1044. tvert(16, 0, 0) = 1 : tvert(16, 0, 1) = 0
  1045. tvert(16, 1, 0) = 1 : tvert(16, 1, 1) = 1
  1046. tvert(17, 0, 0) = 0 : tvert(17, 0, 1) = 1
  1047. tvert(17, 1, 0) = 1 : tvert(17, 1, 1) = 1
  1048. tvert(18, 0, 0) = 1 : tvert(18, 0, 1) = 1
  1049. tvert(18, 1, 0) = 0 : tvert(18, 1, 1) = 1
  1050. 'Now check to the right and below
  1051. For j = 1 To 30
  1052. For i = 1 To 30
  1053. If i < 30 Then
  1054. If tvert(grid(i, j).land, 0, 1) <> tvert(grid(i + 1, j).land, 0, 0) _
  1055. Or tvert(grid(i, j).land, 1, 1) <> tvert(grid(i + 1, j).land, 1, 0) Then
  1056. e = 41
  1057. x = i + 1 : y = j
  1058. Exit Sub
  1059. End If
  1060. End If
  1061. If j < 30 Then
  1062. If tvert(grid(i, j).land, 1, 0) <> tvert(grid(i, j + 1).land, 0, 0) _
  1063. Or tvert(grid(i, j).land, 1, 1) <> tvert(grid(i, j + 1).land, 0, 1) Then
  1064. e = 41
  1065. x = i : y = j + 1
  1066. Exit Sub
  1067. End If
  1068. End If
  1069. Next i
  1070. Next j
  1071. 'Mountain corner with something on top - Error 50
  1072. For j = 1 To 30
  1073. For i = 1 To 30
  1074. If grid(i, j).land >= 11 And grid(i, j).track <> 0 Then
  1075. e = 50
  1076. x = i : y = j
  1077. Exit Sub
  1078. End If
  1079. Next i
  1080. Next j
  1081. 'Mountain side with illegal element on top - Error 51
  1082. For j = 1 To 30
  1083. For i = 1 To 30
  1084. Select Case grid(i, j).land
  1085. Case 7
  1086. If InStr(Chr(0, 4, 14, &H18, &H3B, &H27, &H62), Chr(grid(i, j).track)) = 0 Then _
  1087. e = 51
  1088. Case 8
  1089. If InStr(Chr(0, 5, 15, &H19, &H38, &H24, &H5F), Chr(grid(i, j).track)) = 0 Then _
  1090. e = 51
  1091. Case 9
  1092. If InStr(Chr(0, 4, 14, &H18, &H3A, &H26, &H61), Chr(grid(i, j).track)) = 0 Then _
  1093. e = 51
  1094. Case 10
  1095. If InStr(Chr(0, 5, 15, &H19, &H39, &H25, &H60), Chr(grid(i, j).track)) = 0 Then _
  1096. e = 51
  1097. End Select
  1098. If e Then
  1099. x = i : y = j
  1100. Exit Sub
  1101. End If
  1102. Next i
  1103. Next j
  1104. End Sub
  1105. Sub DoNothing
  1106. End Sub
  1107. Sub DOSScreenTitle(title As String)
  1108. Line (0, 0)-(1023, 31), RGB(60, 60, 100), BF
  1109. Draw String (512 - Len(title) * 4, 8), title, RGB(255, 255, 255)
  1110. PutIcon 24, 6, 16, 4
  1111. End Sub
  1112. Sub DrawBox(x1 As Short, y1 As Short, x2 As Short, y2 As Short)
  1113. Line (x1, y1)-(x2, y2), RGB(30, 30, 50), BF
  1114. Line (x1 + 2, y1 + 2)-(x2 - 2, y2 - 2), RGB(200, 200, 200), B
  1115. Line (x1 + 3, y1 + 3)-(x2 - 3, y2 - 3), RGB(200, 200, 200), B
  1116. End Sub
  1117. Sub MenuBox(boxwidth As Short, boxheight As Short, title As String)
  1118. Dim xcentre As Short, ycentre As Short
  1119. xcentre = xoffs + 15 * bigwidth
  1120. ycentre = yoffs + 15 * 22
  1121. DrawBox xcentre - boxwidth * 8, _
  1122. ycentre - boxheight * 8, _
  1123. xcentre + boxwidth * 8, _
  1124. ycentre + boxheight * 8
  1125. If Len(title) Then
  1126. Draw String (xcentre - Len(title) * 4, _
  1127. ycentre - (boxheight - 1) * 8 + 2), _
  1128. title, RGB(255, 255, 255)
  1129. Line (xcentre - (boxwidth - 6) * 8, _
  1130. ycentre - (boxheight - 4) * 8)- _
  1131. (xcentre + (boxwidth - 6) * 8, _
  1132. ycentre - (boxheight - 4) * 8 + 1), _
  1133. RGB(200, 200, 200), B
  1134. ceny = ycentre - (boxheight - 4) * 8 + 12
  1135. Else
  1136. ceny = ycentre - boxheight * 8 + 8
  1137. End If
  1138. cenx = xcentre
  1139. lefx = xcentre - boxwidth * 8 + 16
  1140. End Sub
  1141. Sub SelectBackground
  1142. Dim As Short i, j, centre
  1143. Dim s As String, akey As String
  1144. Dim As Integer xm, ym, wm, bm
  1145. Dim As Byte current, previous = -1
  1146. Dim custom_background As UByte = 5, update_custom As Byte = 0
  1147. Dim text(0 To 5) As String
  1148. text(0) = "Desert"
  1149. text(1) = "Tropical"
  1150. text(2) = "Alpine"
  1151. text(3) = "City"
  1152. text(4) = "Country"
  1153. text(5) = "Custom/Chaotic"
  1154. MenuBox 25, 25 - 3 * (allow_errors <> 0), "Select Background"
  1155. centre = xoffs + 15 * bigwidth
  1156. For i = 0 To 4 - (allow_errors <> 0)
  1157. s = text(i)
  1158. Draw String (centre - Len(s) * 4, i * 50 + ceny + 16), s, RGB(70, 200, 240)
  1159. If i = 5 Then
  1160. Draw String (centre - 56, ceny + 286), "Background #" + Hex(custom_background, 2), RGB(240, 160, 50)
  1161. Else
  1162. For j = 0 To 9
  1163. PutIcon j, i + 22, centre + (j - 5) * bigwidth, i * 50 + ceny + 32
  1164. Next j
  1165. End If
  1166. Next i
  1167. buttons = 0 : ceny += (292 - 50 * (allow_errors <> 0))
  1168. StackButton " Cancel ", 1
  1169. EndOfButtonStack
  1170. ceny -= (292 - 50 * (allow_errors <> 0))
  1171. Do
  1172. GetMouse xm, ym, wm, bm
  1173. If xm >= centre - 5 * bigwidth - 16 And xm < centre + 5 * bigwidth + 16 _
  1174. AndAlso ym >= ceny + 8 And ym < ceny + 256 - (50 * (allow_errors <> 0)) Then
  1175. current = (ym - ceny - 8) \ 50
  1176. Else
  1177. current = -1
  1178. End If
  1179. If current <> previous Then
  1180. If previous >= 0 Then
  1181. ScreenLock
  1182. Line (centre - 5 * bigwidth - 16, 50 * previous + ceny + 8)- _
  1183. Step (10 * bigwidth + 31, 49), RGB(30, 30, 50), BF
  1184. s = text(previous)
  1185. Draw String (centre - Len(s) * 4, previous * 50 + ceny + 16), s, RGB(70, 200, 240)
  1186. If previous = 5 Then
  1187. Draw String (centre - 56, ceny + 286), "Background #" + Hex(custom_background, 2), RGB(240, 160, 50)
  1188. Else
  1189. For j = 0 To 9
  1190. PutIcon j, previous + 22, centre + (j - 5) * bigwidth, previous * 50 + ceny + 32
  1191. Next j
  1192. End If
  1193. ScreenUnlock
  1194. End If
  1195. If current >= 0 Then
  1196. ScreenLock
  1197. Line (centre - 5 * bigwidth - 16, 50 * current + ceny + 8)- _
  1198. Step (10 * bigwidth + 31, 49), RGB(10, 10, 10), BF
  1199. s = text(current)
  1200. Draw String (centre - Len(s) * 4, current * 50 + ceny + 16), s, RGB(70, 200, 240)
  1201. If current = 5 Then
  1202. Draw String (centre - 56, ceny + 286), "Background #" + Hex(custom_background, 2), RGB(240, 160, 50)
  1203. Else
  1204. For j = 0 To 9
  1205. PutIcon j, current + 22, centre + (j - 5) * bigwidth, current * 50 + ceny + 32
  1206. Next j
  1207. End If
  1208. ScreenUnlock
  1209. End If
  1210. previous = current
  1211. End If
  1212. If bm = 1 Then
  1213. If current >= 0 Then
  1214. landscape = current
  1215. If landscape = 5 Then landscape = custom_background
  1216. Exit Do
  1217. End If
  1218. ElseIf bm = 2 Then
  1219. Exit Do
  1220. End If
  1221. If ManageButtons Then Exit Do
  1222. akey = InKey
  1223. Select Case akey
  1224. Case "=", "+"
  1225. custom_background += 1
  1226. update_custom = -1
  1227. Case "-"
  1228. custom_background -= 1
  1229. update_custom = -1
  1230. Case "0" To "9"
  1231. custom_background ShL= 4
  1232. custom_background Or= ValInt(akey)
  1233. update_custom = -1
  1234. Case "A" To "F", "a" To "f"
  1235. custom_background ShL= 4
  1236. custom_background Or= (ASC(UCase(akey)) - 55)
  1237. update_custom = -1
  1238. Case Chr(27) : Exit Do
  1239. End Select
  1240. If update_custom Then
  1241. If allow_errors Then
  1242. If current = 5 Then
  1243. Line (centre - 56, ceny + 286)- Step (111, 15), RGB(10, 10, 10), BF
  1244. Else
  1245. Line (centre - 56, ceny + 286)- Step (111, 15), RGB(30, 30, 50), BF
  1246. End If
  1247. Draw String (centre - 56, ceny + 286), "Background #" + Hex(custom_background, 2), RGB(240, 160, 50)
  1248. End If
  1249. update_custom = 0
  1250. End If
  1251. Loop
  1252. buttons = 0
  1253. Do
  1254. GetMouse xm, ym, wm, bm
  1255. Loop Until bm = 0
  1256. Do : Loop Until Len(InKey) = 0
  1257. End Sub
  1258. Sub TCentre(y As Short = -1, text As String = "", colour As ULong = RGB(255, 255, 255))
  1259. If y >= 0 Then ceny = y
  1260. cenx = xoffs + 15 * bigwidth - 4 * Len(text)
  1261. If Len(text) Then Draw String (cenx, ceny), text, colour
  1262. cenx = xoffs + 15 * bigwidth
  1263. ceny += 16
  1264. conx = lefx : cony = ceny
  1265. End Sub
  1266. Sub TCont(text As String, eol As Byte = 0)
  1267. Draw String (conx, cony), text, concolour
  1268. If eol Then
  1269. cony += 16
  1270. conx = lefx
  1271. Else
  1272. conx += 8 * Len(text)
  1273. End If
  1274. End Sub
  1275. Function Timey(t As Long) As String
  1276. Dim As Byte c, s, m, h
  1277. Dim As String r, result
  1278. c = t Mod 100 : t \= 100
  1279. s = t Mod 60 : t \= 60
  1280. m = t Mod 60 : t \= 60
  1281. h = t
  1282. r = Str(c) : r = String(2 - Len(r), "0") + r
  1283. result = r
  1284. r = Str(s) : r = String(2 - Len(r), "0") + r
  1285. result = r + "." + result
  1286. r = Str(m)
  1287. If h Then r = String(2 - Len(r), "0") + r
  1288. result = r + ":" + result
  1289. If h Then
  1290. result = Str(h) + ":" + result
  1291. End If
  1292. Return result
  1293. End Function
  1294. Sub TLeft(y As Short = -1, text As String = "", colour As ULong = RGB(255, 255, 255))
  1295. If y >= 0 Then ceny = y
  1296. If Len(text) Then
  1297. #ifdef RENDER_TO_CP437
  1298. Draw String (lefx, ceny), text, colour
  1299. #else
  1300. PutString lefx, ceny, text, colour
  1301. #endif
  1302. End If
  1303. cenx = xoffs + 15 * bigwidth
  1304. ceny += 16
  1305. conx = lefx : cony = ceny
  1306. End Sub
  1307. Sub AddButton(x As Short = -1, y As Short = -1, title As String, value As Short)
  1308. buttons += 1
  1309. If x >= 0 Then button(buttons).x1 = x Else button(buttons).x1 = cenx
  1310. If y >= 0 Then button(buttons).y1 = y Else button(buttons).y1 = ceny
  1311. button(buttons).x2 = button(buttons).x1 + 8 * Len(title) + 16
  1312. button(buttons).y2 = button(buttons).y1 + 31
  1313. button(buttons).title = title
  1314. button(buttons).value = value
  1315. Line (button(buttons).x1, button(buttons).y1)-(button(buttons).x2, button(buttons).y1 + 31), RGB(200, 200, 200), B
  1316. Line (button(buttons).x1 + 1, button(buttons).y1 + 1)-(button(buttons).x2 - 1, button(buttons).y1 + 30), RGB(200, 200, 200), B
  1317. Line (button(buttons).x1 + 2, button(buttons).y1 + 2)-(button(buttons).x2 - 2, button(buttons).y1 + 29), RGB(30, 30, 50), BF
  1318. Draw String (button(buttons).x1 + 8, button(buttons).y1 + 8), title, RGB(200, 200, 200)
  1319. ceny = button(buttons).y1
  1320. cenx = button(buttons).x2 + 8
  1321. End Sub
  1322. Sub StackButton(title As String, value As Short = -1, direction As Byte = 0, separation As UShort = 16)
  1323. Static lastvalue As Short = 0, first As Short = 0
  1324. Dim i As Short
  1325. If Len(title) = 0 Then
  1326. first = 0
  1327. Exit Sub
  1328. End If
  1329. buttons += 1
  1330. If first = 0 Then first = buttons : lastvalue = 0
  1331. If value Then
  1332. button(buttons).value = value
  1333. lastvalue = value
  1334. Else
  1335. lastvalue += 1
  1336. button(buttons).value = lastvalue
  1337. End If
  1338. button(buttons).title = title
  1339. button(buttons).y1 = ceny : button(buttons).y2 = ceny + 31
  1340. If direction > 0 Then 'Stack to the right
  1341. If buttons = first Then
  1342. button(buttons).x1 = cenx
  1343. Else
  1344. button(buttons).x1 = button(buttons - 1).x2 + separation
  1345. End If
  1346. button(buttons).x2 = button(buttons).x1 + 8 * Len(title) + 16
  1347. ElseIf direction < 0 Then 'Stack to the left
  1348. If buttons = first Then
  1349. button(buttons).x2 = cenx
  1350. Else
  1351. button(buttons).x2 = button(buttons - 1).x1 - separation
  1352. End If
  1353. button(buttons).x1 = button(buttons).x2 - 8 * Len(title) - 16
  1354. Else 'Stack around a centre
  1355. If buttons = first Then
  1356. button(buttons).x1 = cenx - Len(title) * 4 - 8
  1357. button(buttons).x2 = cenx + Len(title) * 4 + 8
  1358. Else
  1359. For i = first To buttons - 1
  1360. button(i).x1 -= (Len(title) * 4 + 8 + separation \ 2)
  1361. button(i).x2 -= (Len(title) * 4 + 8 + separation \ 2)
  1362. Next i
  1363. button(buttons).x1 = button(buttons - 1).x2 + separation
  1364. button(buttons).x2 = button(buttons).x1 + Len(title) * 8 + 16
  1365. End If
  1366. End If
  1367. End Sub
  1368. Sub EndOfButtonStack
  1369. Dim i As Short
  1370. StackButton ""
  1371. For i = 1 To buttons
  1372. Line (button(i).x1, button(i).y1)-(button(i).x2, button(i).y1 + 31), RGB(200, 200, 200), B
  1373. Line (button(i).x1 + 1, button(i).y1 + 1)-(button(i).x2 - 1, button(i).y1 + 30), RGB(200, 200, 200), B
  1374. Line (button(i).x1 + 2, button(i).y1 + 2)-(button(i).x2 - 2, button(i).y1 + 29), RGB(30, 30, 50), BF
  1375. Draw String (button(i).x1 + 8, button(i).y1 + 8), button(i).title, RGB(200, 200, 200)
  1376. Next i
  1377. End Sub
  1378. Function ManageButtons As Short
  1379. Static ex As Byte = 0
  1380. Dim As Integer xm, ym, wm, bm
  1381. Dim i As Byte, active As Byte = 0
  1382. GetMouse xm, ym, wm, bm
  1383. For i = 1 To buttons
  1384. If xm >= button(i).x1 And xm <= button(i).x2 And ym >= button(i).y1 And ym <= button(i).y2 Then
  1385. active = i
  1386. Exit For
  1387. End If
  1388. Next i
  1389. If active <> ex Then
  1390. If ex <> 0 And ex <= buttons Then
  1391. Line (button(ex).x1, button(ex).y1)-(button(ex).x2, button(ex).y2), RGB(200, 200, 200), B
  1392. Line (button(ex).x1 + 1, button(ex).y1 + 1)-(button(ex).x2 - 1, button(ex).y2 - 1), RGB(200, 200, 200), B
  1393. Line (button(ex).x1 + 2, button(ex).y1 + 2)-(button(ex).x2 - 2, button(ex).y2 - 2), RGB(30, 30, 50), BF
  1394. Draw String (button(ex).x1 + 8, button(ex).y1 + 8), button(ex).title, RGB(200, 200, 200)
  1395. End If
  1396. If active <> 0 And active <= buttons Then
  1397. Line (button(active).x1, button(active).y1)-(button(active).x2, button(active).y2), RGB(200, 200, 200), BF
  1398. Draw String (button(active).x1 + 8, button(active).y1 + 8), button(active).title, RGB(30, 30, 50)
  1399. End If
  1400. ex = active
  1401. End If
  1402. If bm = 1 And active <> 0 And active <= buttons Then
  1403. Return button(active).value
  1404. Else
  1405. Return 0
  1406. End If
  1407. End Function
  1408. Sub ManageIcons
  1409. Dim As Integer xm, ym, wm, bm
  1410. Dim As Short xi, yi
  1411. Dim and_now As Byte
  1412. Dim tempboard As String
  1413. Static highlit As Byte = -1, exwm As Integer
  1414. Static internal_bgc As Byte = 0
  1415. Dim oname(0 To 19) As String
  1416. oname(0) = "New Track"
  1417. oname(1) = "Save Track"
  1418. oname(2) = "Load Track"
  1419. oname(3) = "Exit Bliss"
  1420. oname(4) = "Select"
  1421. oname(5) = "Copy"
  1422. oname(6) = "Cut"
  1423. oname(7) = "Paste"
  1424. oname(8) = "Flip Horizontally"
  1425. oname(9) = "Flip Vertically"
  1426. oname(10) = "Rotate Clockwise"
  1427. oname(11) = "Rotate Ctr-clockwise"
  1428. oname(12) = "Track Information"
  1429. oname(13) = "Undo"
  1430. oname(14) = "Redo"
  1431. oname(15) = "Help"
  1432. oname(16) = "Generate Scenery"
  1433. oname(17) = "Track Analysis"
  1434. oname(18) = "Tournaments"
  1435. oname(19) = "Settings"
  1436. GetMouse xm, ym, wm, bm
  1437. 'Calculate menu item position
  1438. If xm < xpanel + xpicons Or xm >= xpanel + xpicons + 176 Or _
  1439. ym < ypanel + ypicons Or ym >= ypanel + ypicons + 220 Then
  1440. and_now = -1
  1441. Else
  1442. xi = (xm - xpanel - xpicons) \ 44
  1443. yi = (ym - ypanel - ypicons) \ 44
  1444. and_now = yi * 4 + xi
  1445. End If
  1446. If highlit <> and_now Then
  1447. ScreenLock
  1448. If highlit <> -1 Then
  1449. Line ((highlit Mod 4) * 44 + xpanel + xpicons, (highlit \ 4) * 44 + ypanel + ypicons)- STEP (43, 43), RGB(30, 30, 50), BF
  1450. If dosbox Then
  1451. Put ((highlit Mod 4) * 44 + xpanel + xpicons, (highlit \ 4) * 44 + ypanel + ypicons), bigicons, (13 * bigwidth + (highlit Mod 4) * 44, 12 * 22 + (highlit \ 4) * 44)- STEP(bigwidth * 2 - 1, 43), Trans
  1452. Else
  1453. Put ((highlit Mod 4) * 44 + xpanel + xpicons, (highlit \ 4) * 44 + ypanel + ypicons), bigicons, (13 * bigwidth + (highlit Mod 4) * 44, 12 * 22 + (highlit \ 4) * 44)- STEP(bigwidth * 2 - 1, 43), Alpha
  1454. End If
  1455. End If
  1456. Line (xpanel + xpicons, ypanel + ypicons + 236)- Step (175, 15), RGB(30, 30, 50), BF
  1457. If and_now <> -1 Then
  1458. Line (xi * 44 + xpanel + xpicons, yi * 44 + ypanel + ypicons)- STEP (43, 43), RGB(30, &HF2, &HF3), BF
  1459. If dosbox Then
  1460. Put (xi * 44 + xpanel + xpicons, yi * 44 + ypanel + ypicons), bigicons, (13 * bigwidth + (and_now Mod 4) * 44, 12 * 22 + (and_now \ 4) * 44)- STEP(bigwidth * 2 - 1, 43), Trans
  1461. Else
  1462. Put (xi * 44 + xpanel + xpicons, yi * 44 + ypanel + ypicons), bigicons, (13 * bigwidth + (and_now Mod 4) * 44, 12 * 22 + (and_now \ 4) * 44)- STEP(bigwidth * 2 - 1, 43), Alpha
  1463. End If
  1464. Draw String (xpanel + xpicons + 4 * bigwidth - Len(oname(and_now)) * 4, ypanel + ypicons + 236), oname(and_now), RGB(200, 200, 200)
  1465. End If
  1466. ScreenUnlock
  1467. highlit = and_now
  1468. End If
  1469. 'Activate menu icon option
  1470. If highlit <> -1 And bm = 1 Then
  1471. Select Case highlit
  1472. Case 0 : Menu_StartNewTrack
  1473. Case 1 : Menu_SaveTrack
  1474. Case 2 : Menu_LoadTrack
  1475. Case 3 : QuitProgram
  1476. Case 4
  1477. selecting = -1 : xselect = 0 : DrawTrack
  1478. Do
  1479. GetMouse xm, ym, wm, bm
  1480. Loop Until bm <> 1
  1481. Case 5, 6
  1482. CopyOrCut highlit = 6
  1483. If highlit = 6 Then PushUndo
  1484. DrawPanel
  1485. Do
  1486. GetMouse xm, ym, wm, bm
  1487. Loop Until bm <> 1
  1488. Case 7
  1489. Paste
  1490. Do
  1491. GetMouse xm, ym, wm, bm
  1492. Loop Until bm <> 1
  1493. Case 8 'Flip horizontally
  1494. If pasting Then
  1495. clipboard = HFlipTrack(clipboard)
  1496. Do
  1497. GetMouse xm, ym, wm, bm
  1498. Loop Until bm <> 1
  1499. ElseIf xselect Then
  1500. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  1501. tempboard = HFlipTrack(tempboard)
  1502. PutTrack xselect, yselect, tempboard, -1
  1503. DrawTrack
  1504. PushUndo
  1505. Do
  1506. GetMouse xm, ym, wm, bm
  1507. Loop Until bm <> 1
  1508. Else
  1509. tempboard = GetTrack(1, 1, 30, 30)
  1510. tempboard = HFlipTrack(tempboard)
  1511. PutTrack 1, 1, tempboard, -1
  1512. DrawTrack
  1513. PushUndo
  1514. Do
  1515. GetMouse xm, ym, wm, bm
  1516. Loop Until bm <> 1
  1517. End If
  1518. Case 9 'Flip vertically
  1519. If pasting Then
  1520. clipboard = VFlipTrack(clipboard)
  1521. Do
  1522. GetMouse xm, ym, wm, bm
  1523. Loop Until bm <> 1
  1524. ElseIf xselect Then
  1525. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  1526. tempboard = VFlipTrack(tempboard)
  1527. PutTrack xselect, yselect, tempboard, -1
  1528. DrawTrack
  1529. PushUndo
  1530. Do
  1531. GetMouse xm, ym, wm, bm
  1532. Loop Until bm <> 1
  1533. Else
  1534. tempboard = GetTrack(1, 1, 30, 30)
  1535. tempboard = VFlipTrack(tempboard)
  1536. PutTrack 1, 1, tempboard, -1
  1537. DrawTrack
  1538. PushUndo
  1539. Do
  1540. GetMouse xm, ym, wm, bm
  1541. Loop Until bm <> 1
  1542. End If
  1543. Case 10 'Rotate clockwise
  1544. If pasting Then
  1545. clipboard = CRotate(clipboard)
  1546. Do
  1547. GetMouse xm, ym, wm, bm
  1548. Loop Until bm <> 1
  1549. ElseIf xselect Then
  1550. If x2select - xselect = y2select - yselect Then
  1551. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  1552. tempboard = CRotate(tempboard)
  1553. PutTrack xselect, yselect, tempboard, -1
  1554. DrawTrack
  1555. PushUndo
  1556. Do
  1557. GetMouse xm, ym, wm, bm
  1558. Loop Until bm <> 1
  1559. Else
  1560. NotASquare
  1561. End If
  1562. Else
  1563. tempboard = GetTrack(1, 1, 30, 30)
  1564. tempboard = CRotate(tempboard)
  1565. PutTrack 1, 1, tempboard, -1
  1566. DrawTrack
  1567. PushUndo
  1568. Do
  1569. GetMouse xm, ym, wm, bm
  1570. Loop Until bm <> 1
  1571. End If
  1572. Case 11 'Rotate counter-clockwise
  1573. If pasting Then
  1574. clipboard = CCRotate(clipboard)
  1575. Do
  1576. GetMouse xm, ym, wm, bm
  1577. Loop Until bm <> 1
  1578. ElseIf xselect Then
  1579. If x2select - xselect = y2select - yselect Then
  1580. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  1581. tempboard = CCRotate(tempboard)
  1582. PutTrack xselect, yselect, tempboard, -1
  1583. DrawTrack
  1584. PushUndo
  1585. Do
  1586. GetMouse xm, ym, wm, bm
  1587. Loop Until bm <> 1
  1588. Else
  1589. NotASquare
  1590. End If
  1591. Else
  1592. tempboard = GetTrack(1, 1, 30, 30)
  1593. tempboard = CCRotate(tempboard)
  1594. PutTrack 1, 1, tempboard, -1
  1595. DrawTrack
  1596. PushUndo
  1597. Do
  1598. GetMouse xm, ym, wm, bm
  1599. Loop Until bm <> 1
  1600. End If
  1601. Case 12 : Menu_TrackInfo
  1602. Case 13 'Undo
  1603. If Not pasting Then
  1604. Undo
  1605. DrawTrack
  1606. Do
  1607. GetMouse xm, ym, wm, bm
  1608. Loop Until bm <> 1
  1609. End If
  1610. Case 14 'Redo
  1611. If Not pasting Then
  1612. Redo
  1613. DrawTrack
  1614. Do
  1615. GetMouse xm, ym, wm, bm
  1616. Loop Until bm <> 1
  1617. End If
  1618. Case 15 : Menu_Help
  1619. Case 16 : Menu_Scenery
  1620. Case 17 : Menu_Analysis
  1621. Case 18 : Menu_Tournaments
  1622. Case 19 : Menu_Settings
  1623. End Select
  1624. End If
  1625. 'Check to update switch indicators
  1626. If xm >= xpanel + xswitches AndAlso _
  1627. xm < xpanel + xswitches + 9 * 22 AndAlso _
  1628. ym >= ypanel + yswitches AndAlso _
  1629. ym < ypanel + yswitches + 22 Then
  1630. If bm = 1 Then
  1631. xi = (xm - xswitches - xpanel) \ 22
  1632. PutIcon 21 + xi, 13, xpanel + xswitches + bigwidth * xi, ypanel + yswitches
  1633. Select Case xi
  1634. Case 0 : clipboard = ""
  1635. Case 1 : show_errors = Not show_errors
  1636. Case 2 : allow_errors = Not allow_errors
  1637. Case 3 : data_codes = Not data_codes
  1638. Case 4 : show_grid = Not show_grid
  1639. Case 5 : affect_track = Not affect_track
  1640. Case 6 : affect_terrain = Not affect_terrain
  1641. Case 7 : colouring_mode = Not colouring_mode
  1642. Case 8 : Menu_TrackShot
  1643. End Select
  1644. Do
  1645. GetMouse xm, ym, wm, bm
  1646. Loop Until bm <> 1
  1647. DrawTrack
  1648. DrawPanel
  1649. End If
  1650. End If
  1651. If colouring_mode Then
  1652. 'Colouration - Background colour
  1653. If xm >= xpanel + xpalette + 16 AndAlso ym >= ypanel + 434 AndAlso _
  1654. xm < xpanel + xpalette + 38 AndAlso ym < ypanel + 456 Then
  1655. Dim As ULong r, g, b
  1656. If wm > exwm Then
  1657. internal_bgc = (internal_bgc + 1) Mod 24
  1658. current_bgc = cpal(internal_bgc)
  1659. If internal_bgc Then
  1660. r = .7 * ((current_bgc ShR 16) And 255)
  1661. g = .7 * ((current_bgc ShR 8) And 255)
  1662. b = .7 * (current_bgc And 255)
  1663. current_bgc = RGB(r, g, b)
  1664. Else
  1665. current_bgc = 0
  1666. End If
  1667. DrawPanel
  1668. ElseIf wm < exwm Then
  1669. internal_bgc = (internal_bgc + 23) Mod 24
  1670. current_bgc = cpal(internal_bgc)
  1671. If internal_bgc Then
  1672. r = .7 * ((current_bgc ShR 16) And 255)
  1673. g = .7 * ((current_bgc ShR 8) And 255)
  1674. b = .7 * (current_bgc And 255)
  1675. current_bgc = RGB(r, g, b)
  1676. Else
  1677. current_bgc = 0
  1678. End If
  1679. DrawPanel
  1680. ElseIf bm = 2 Then
  1681. current_bgc = 0
  1682. internal_bgc = 0
  1683. DrawPanel
  1684. Do
  1685. GetMouse xm, ym, wm, bm
  1686. Loop Until bm <> 2
  1687. ElseIf bm = 1 Then
  1688. Menu_Colouring
  1689. End If
  1690. 'Colouration - Border colour
  1691. ElseIf xm >= xpanel + xpalette + 48 AndAlso ym >= ypanel + 434 AndAlso _
  1692. xm < xpanel + xpalette + 70 AndAlso ym < ypanel + 456 Then
  1693. Dim q As Byte
  1694. If wm > exwm Then
  1695. For i As Byte = 0 To 23
  1696. If cpal(i) = current_border Then q = i
  1697. Next i
  1698. q = (q + 1) Mod 24
  1699. current_border = cpal(q)
  1700. DrawPanel
  1701. ElseIf wm < exwm Then
  1702. For i As Byte = 0 To 23
  1703. If cpal(i) = current_border Then q = i
  1704. Next i
  1705. q = (q + 23) Mod 24
  1706. current_border = cpal(q)
  1707. DrawPanel
  1708. ElseIf bm = 2 Then
  1709. current_border = 0
  1710. DrawPanel
  1711. Do
  1712. GetMouse xm, ym, wm, bm
  1713. Loop Until bm <> 2
  1714. ElseIf bm = 1 Then
  1715. Menu_Colouring
  1716. End If
  1717. End If
  1718. End If
  1719. exwm = wm
  1720. End Sub
  1721. Sub ManageKeyboardCursor(forceupdate As Byte = 0)
  1722. Static As Byte oldx = 1, oldy = 1
  1723. Dim As Integer xm, ym, wm, bm
  1724. If forceupdate OrElse oldx <> xcursor Or oldy <> ycursor Then
  1725. drawkeyboardcursor = -1
  1726. For j As Byte = oldy - 1 To oldy + 1
  1727. For i As Byte = oldx - 1 To oldx + 1
  1728. If i >= 1 AndAlso i <= 30 AndAlso j >= 1 AndAlso j <= 30 _
  1729. Then DrawSpot i, j
  1730. Next i
  1731. Next j
  1732. Dim As Short xx, yy
  1733. xx = xoffs + 22 * (xcursor - 1)
  1734. yy = yoffs + 22 * (ycursor - 1)
  1735. If current_page = 10 Or allow_errors <> 0 Then
  1736. Line (xx, yy)- Step (21, 21), RGB(250, 250, 250), B
  1737. Line (xx + 1, yy + 1)- Step (19, 19), RGB(250, 250, 250), B
  1738. ElseIf current_page < 10 Then
  1739. Dim As Byte w, h
  1740. Dim v As UByte
  1741. Dim As Byte ex, ey
  1742. Select Case grid(xcursor, ycursor).track
  1743. Case 255 : ex = xcursor - 1 : ey = ycursor
  1744. Case 254 : ex = xcursor : ey = ycursor - 1
  1745. Case 253 : ex = xcursor - 1 : ey = ycursor - 1
  1746. Case Else : ex = xcursor : ey = ycursor
  1747. End Select
  1748. If ex < 1 Then ex = 1
  1749. If ey < 1 Then ey = 1
  1750. v = grid(ex, ey).track
  1751. If v Then
  1752. DrawSpot ex, ey, -1
  1753. If tr(v).w = 2 And ex < 30 Then
  1754. DrawSpot ex + 1, ey, -1
  1755. If tr(v).h = 2 And ey < 30 Then DrawSpot ex + 1, ey + 1, -1
  1756. End If
  1757. If tr(v).h = 2 And ey < 30 Then DrawSpot ex, ey + 1, -1
  1758. End If
  1759. If xcursor < 30 Then w = tr(current_brush).w Else w = 1
  1760. If ycursor < 30 Then h = tr(current_brush).h Else h = 1
  1761. Line (xx, yy)- Step (22 * w - 1, 22 * h - 1), RGB(200, 200, 200), B
  1762. Line (xx, yy)- Step (21, 21), RGB(250, 250, 250), B
  1763. Line (xx + 1, yy + 1)- Step (19, 19), RGB(250, 250, 250), B
  1764. End If
  1765. Dim s As String, coorpos As Short
  1766. coorpos = xpanel + 170
  1767. If colouring_mode Then coorpos -= 72
  1768. ScreenLock
  1769. Line (coorpos - 74, ypanel + 432)- STEP (155, 31), RGB(30, 30, 50), BF
  1770. s = "[" + Trim(Str(xcursor)) + ", " + Trim(Str(ycursor)) + "]"
  1771. If selecting = -3 Then s = "[" + Trim(Str(xselect)) + ", " + Trim(Str(yselect)) + "]-" + s
  1772. Draw String (coorpos - Len(s) * 4, ypanel + 430), s, RGB(200, 200, 200)
  1773. If data_codes Then
  1774. s = "Ter[" + Hex(grid(xcursor, ycursor).land) + "h] Trk[" + Hex(grid(xcursor, ycursor).track) + "h]"
  1775. Else
  1776. s = Trim(tr(GetParent(xcursor, ycursor)).id)
  1777. End If
  1778. Draw String (coorpos - Len(s) * 4, ypanel + 446), s, RGB(200, 200, 200)
  1779. ScreenUnlock
  1780. oldx = xcursor : oldy = ycursor
  1781. End If
  1782. If drawkeyboardcursor Then
  1783. GetMouse xm, ym, wm, bm
  1784. If bm <> 0 Then
  1785. drawkeyboardcursor = 0
  1786. For j As Byte = ycursor - 1 To ycursor + 1
  1787. For i As Byte = xcursor - 1 To xcursor + 1
  1788. If i >= 1 AndAlso i <= 30 AndAlso j >= 1 AndAlso j <= 30 _
  1789. Then DrawSpot i, j
  1790. Next i
  1791. Next j
  1792. End If
  1793. End If
  1794. End Sub
  1795. Function ManageSelector(sel As SelectorType) As Byte
  1796. Dim isin As Byte
  1797. Dim As Integer xm, ym, wm, bm
  1798. If sel.current = 0 Then sel.current = 1
  1799. GetMouse xm, ym, wm, bm
  1800. If xm >= sel.x1 And xm <= sel.x2 And ym >= sel.y1 And ym <= sel.y2 Then
  1801. isin = -1
  1802. Else
  1803. isin = 0
  1804. End If
  1805. 'Redraw
  1806. If sel.redraw <> 0 Or isin <> sel.wasinlasttime Then
  1807. ScreenLock
  1808. With sel
  1809. If isin Then
  1810. Line (.x1, .y1)-(.x2, .y2), RGB(200, 200, 200), BF
  1811. Draw String (.x1 + 8, (.y1 + .y2) \ 2 - 8), .opt(.current), RGB(30, 30, 50)
  1812. Draw String (.x2 - 16, (.y1 + .y2) \ 2 - 8), Chr(25), RGB(30, 30, 50)
  1813. Else
  1814. Line (.x1, .y1)-(.x2, .y2), RGB(200, 200, 200), B
  1815. Line (.x1 + 1, .y1 + 1)-(.x2 - 1, .y2 - 1), RGB(200, 200, 200), B
  1816. LIne (.x1 + 2, .y1 + 2)-(.x2 - 2, .y2 - 2), RGB(30, 30, 50), BF
  1817. Draw String (.x1 + 8, (.y1 + .y2) \ 2 - 8), .opt(.current), RGB(200, 200, 200)
  1818. Draw String (.x2 - 16, (.y1 + .y2) \ 2 - 8), Chr(25), RGB(200, 200, 200)
  1819. End If
  1820. End With
  1821. ScreenUnlock
  1822. sel.redraw = 0
  1823. If isin Then sel.wasinlasttime = -1 Else sel.wasinlasttime = 0
  1824. End If
  1825. 'Clicked on the pull-down selector
  1826. If bm = 1 And isin Then
  1827. Dim bgcopy As UByte Ptr, newy1 As Short, newy2 As Short
  1828. Dim thisone As Byte, thelastone As Byte
  1829. With sel
  1830. newy1 = .y1
  1831. newy2 = .y1 + 32 * .options + 3
  1832. If newy2 > 700 Then
  1833. newy1 = newy1 - newy2 + 700
  1834. newy2 = 700
  1835. End If
  1836. bgcopy = ImageCreate(.x2 - .x1 + 1, 32 * .options + 4)
  1837. Get (.x1, newy1)-(.x2, newy2), bgcopy
  1838. ScreenLock
  1839. Line (.x1, newy1)-(.x2, newy2), RGB(200, 200, 200), B
  1840. Line (.x1 + 1, newy1 + 1)-(.x2 - 1, newy2 - 1), RGB(200, 200, 200), B
  1841. Line (.x1 + 2, newy1 + 2)-(.x2 - 2, newy2 - 2), RGB(30, 30, 50), BF
  1842. For i As Byte = 1 To .options
  1843. Draw String (.x1 + 8, newy1 + 32 * i - 24), .opt(i), RGB(200, 200, 200)
  1844. Next i
  1845. ScreenUnlock
  1846. Do
  1847. GetMouse xm, ym, wm, bm
  1848. Loop Until bm = 0
  1849. thelastone = -1
  1850. Do
  1851. GetMouse xm, ym, wm, bm
  1852. If xm < .x1 Or xm > .x2 Or ym < newy1 + 2 Or ym > newy2 - 2 Then Exit Do
  1853. thisone = (ym - newy1) \ 32 + 1
  1854. If thisone <> thelastone Then
  1855. If thelastone >= 1 And thelastone <= .options Then
  1856. Line (.x1 + 2, newy1 + 32 * (thelastone - 1) + 2)-(.x2 - 2, newy1 + 32 * thelastone + 1), RGB(30, 30, 50), BF
  1857. Draw String (.x1 + 8, newy1 + 32 * thelastone - 24), .opt(thelastone), RGB(200, 200, 200)
  1858. End If
  1859. If thisone >= 1 And thisone <= .options Then
  1860. Line (.x1 + 2, newy1 + 32 * (thisone - 1) + 2)-(.x2 - 2, newy1 + 32 * thisone + 1), RGB(200, 200, 200), BF
  1861. Draw String (.x1 + 8, newy1 + 32 * thisone - 24), .opt(thisone), RGB(30, 30, 50)
  1862. End If
  1863. thelastone = thisone
  1864. End If
  1865. If bm = 1 And thisone >= 1 And thisone <= .options Then
  1866. sel.current = thisone
  1867. Exit Do
  1868. End If
  1869. Loop
  1870. Do
  1871. GetMouse xm, ym, wm, bm
  1872. Loop Until bm = 0
  1873. Put (.x1, newy1), bgcopy, PSet
  1874. ImageDestroy bgcopy
  1875. End With
  1876. sel.redraw = -1
  1877. Return sel.current
  1878. End If
  1879. Return 0
  1880. End Function
  1881. Function ManageString(ByRef s As String) As String
  1882. Dim akey As String
  1883. If stringer.init <> 0 Or stringer.sr <> s Then
  1884. stringer.t = Timer
  1885. stringer.cursor = -1
  1886. stringer.redraw = -1
  1887. stringer.init = 0
  1888. stringer.s32 = Enc_UTF8_to_UTF32(s)
  1889. #ifdef RENDER_TO_CP437
  1890. stringer.sr = Enc_UTF32_to_CP437(stringer.s32)
  1891. #else
  1892. stringer.sr = Enc_UTF32_to_Latin1(stringer.s32)
  1893. #endif
  1894. stringer.cursor_pos = Len(stringer.sr)
  1895. 'stringer.last = s
  1896. End If
  1897. #ifdef __FB_LINUX__
  1898. akey = LinKey
  1899. #else
  1900. akey = InKey
  1901. #endif
  1902. Select Case akey
  1903. Case "A" To "Z", "a" To "z", "0" To "9", "_", "."
  1904. If Len(stringer.sr) < stringer.maxlength Then
  1905. stringer.sr = Left(stringer.sr, stringer.cursor_pos) + akey + Mid(stringer.sr, stringer.cursor_pos + 1)
  1906. stringer.s32 = Left(stringer.s32, 4 * stringer.cursor_pos) + akey + String(3, 0) + Mid(stringer.s32, 4 * stringer.cursor_pos + 1)
  1907. stringer.cursor_pos += 1
  1908. stringer.redraw = -1
  1909. End If
  1910. Case " " To Chr(126)
  1911. If Len(stringer.sr) < stringer.maxlength And stringer.fileonly = 0 Then
  1912. stringer.sr = Left(stringer.sr, stringer.cursor_pos) + akey + Mid(stringer.sr, stringer.cursor_pos + 1)
  1913. stringer.s32 = Left(stringer.s32, 4 * stringer.cursor_pos) + akey + String(3, 0) + Mid(stringer.s32, 4 * stringer.cursor_pos + 1)
  1914. stringer.cursor_pos += 1
  1915. stringer.redraw = -1
  1916. End If
  1917. Case Chr(8)
  1918. If stringer.cursor_pos > 0 Then
  1919. stringer.sr = Left(stringer.sr, stringer.cursor_pos - 1) + Mid(stringer.sr, stringer.cursor_pos + 1)
  1920. stringer.s32 = Left(stringer.s32, 4 * stringer.cursor_pos - 4) + Mid(stringer.s32, 4 * stringer.cursor_pos + 1)
  1921. stringer.cursor_pos -= 1
  1922. stringer.redraw = -1
  1923. End If
  1924. Case Chr(13), Chr(27)
  1925. Return akey
  1926. Case Chr(255) + Chr(77), Chr(0, &H53, &HFF, 0, 0)
  1927. If stringer.cursor_pos < Len(stringer.sr) Then
  1928. stringer.cursor_pos += 1
  1929. stringer.redraw = -1
  1930. End If
  1931. Case Chr(255) + Chr(75), Chr(0, &H51, &HFF, 0, 0)
  1932. If stringer.cursor_pos > 0 Then
  1933. stringer.cursor_pos -= 1
  1934. stringer.redraw = -1
  1935. End If
  1936. Case Chr(255) + Chr(83), Chr(127)
  1937. If Len(stringer.sr) >= stringer.cursor_pos Then
  1938. stringer.sr = Left(stringer.sr, stringer.cursor_pos) + Mid(stringer.sr, stringer.cursor_pos + 2)
  1939. stringer.s32 = Left(stringer.s32, 4 * stringer.cursor_pos) + Mid(stringer.s32, 4 * stringer.cursor_pos + 5)
  1940. stringer.redraw = -1
  1941. End If
  1942. Case Chr(255) + Chr(71), Chr(0, &H50, &HFF, 0, 0)
  1943. stringer.cursor_pos = 0
  1944. stringer.redraw = -1
  1945. Case Chr(255) + Chr(79), Chr(0, &H57, &HFF, 0, 0)
  1946. stringer.cursor_pos = Len(stringer.sr)
  1947. stringer.redraw = -1
  1948. Case Else
  1949. If Len(akey) > 1 Then
  1950. Dim akey32 As Long
  1951. If Left(akey, 1) = Chr(0) Then Return akey
  1952. akey32 = CvL(Enc_UTF8_to_UTF32(akey))
  1953. If akey32 >= 128 And stringer.fileonly = 0 Then
  1954. If Len(stringer.sr) < stringer.maxlength Then
  1955. #ifdef RENDER_TO_CP437
  1956. 'Use CP437 as target codepage (to render with Draw String)
  1957. stringer.sr = Left(stringer.sr, stringer.cursor_pos) + Enc_UTF32_to_CP437(MkL(akey32)) + Mid(stringer.sr, stringer.cursor_pos + 1)
  1958. #else
  1959. 'Use Latin-1 as target codepage (to render with PutString)
  1960. stringer.sr = Left(stringer.sr, stringer.cursor_pos) + Enc_UTF32_to_Latin1(MkL(akey32)) + Mid(stringer.sr, stringer.cursor_pos + 1)
  1961. #endif
  1962. stringer.s32 = Left(stringer.s32, 4 * stringer.cursor_pos) + MkL(akey32) + Mid(stringer.s32, 4 * stringer.cursor_pos + 1)
  1963. stringer.cursor_pos += 1
  1964. stringer.redraw = -1
  1965. End If
  1966. End If
  1967. 'This line was here, but looks terribly wrong!!!
  1968. 'Return akey
  1969. ElseIf Len(akey) = 1 And stringer.fileonly = 0 Then 'DOS extended CP437
  1970. Dim akey32 As Long
  1971. akey32 = fromCP437(Asc(akey) - 128)
  1972. If Len(stringer.sr) < stringer.maxlength Then
  1973. stringer.sr = Left(stringer.sr, stringer.cursor_pos) + Enc_UTF32_to_CP437(MkL(akey32)) + Mid(stringer.sr, stringer.cursor_pos + 1)
  1974. stringer.s32 = Left(stringer.s32, 4 * stringer.cursor_pos) + MkL(akey32) + Mid(stringer.s32, 4 * stringer.cursor_pos + 1)
  1975. stringer.cursor_pos += 1
  1976. stringer.redraw = -1
  1977. End If
  1978. End If
  1979. End Select
  1980. If Timer - stringer.t > .2 Then
  1981. stringer.cursor = Not stringer.cursor
  1982. stringer.t = Timer
  1983. stringer.redraw = -1
  1984. End If
  1985. If stringer.redraw <> 0 Or Len(akey) <> 0 Then _
  1986. s = Enc_UTF32_to_UTF8(stringer.s32)
  1987. If stringer.redraw Then
  1988. ScreenLock
  1989. Line(stringer.x, stringer.y)- STEP (8 * stringer.maxlength + 7, 15), stringer.background, BF
  1990. #ifdef RENDER_TO_CP437
  1991. Draw String (stringer.x, stringer.y), stringer.sr, RGB(160, 160, 240)
  1992. #else
  1993. PutString stringer.x, stringer.y, stringer.sr, RGB(160, 160, 240)
  1994. #endif
  1995. If stringer.cursor Then
  1996. Line (stringer.x + 8 * stringer.cursor_pos, stringer.y)- STEP (7, 15), RGB(200, 200, 200), BF
  1997. End If
  1998. ScreenUnlock
  1999. stringer.redraw = 0
  2000. End If
  2001. Return akey
  2002. End Function
  2003. Sub Error_Message(text As String, title As String = "Error!")
  2004. Dim v As Short
  2005. Dim As Integer xm, ym, wm, bm
  2006. MenuBox 28, 10, title
  2007. ceny += 16
  2008. TCentre , text, RGB(200, 200, 240)
  2009. ceny += 24
  2010. buttons = 0
  2011. StackButton " OK "
  2012. EndOfButtonStack
  2013. Do
  2014. v = ManageButtons
  2015. If STRONG_ANTI_HOG Then Sleep 1
  2016. Loop Until v <> 0 Or Len(InKey) <> 0
  2017. buttons = 0
  2018. Do
  2019. GetMouse xm, ym, wm, bm
  2020. Loop Until bm = 0
  2021. Do : Loop Until Len(InKey) = 0
  2022. DrawTrack
  2023. End Sub
  2024. Sub Menu_Scenery
  2025. Dim update As Byte = -1, i As Short, j As Short
  2026. Dim As Integer xm, ym, wm, bm
  2027. Dim bar(0 To 9) As UByte, sel(0 To 9) As SelectorType
  2028. Dim thing(0 To 9) As UByte
  2029. Dim tempy As Short, v As Short, scratch As SelectorType
  2030. Dim akey As String, lastchanged As Byte
  2031. 'Define what tile each bar represents
  2032. thing(0) = &H99 : thing(1) = &H98 : thing(2) = &H97
  2033. thing(3) = &H9A : thing(4) = &HA3 : thing(5) = &H9F
  2034. thing(6) = &H9B : thing(7) = &HA7 : thing(8) = &HAF : thing(9) = &HAB
  2035. Select Case landscape
  2036. Case 0 'Desert
  2037. bar(1) = 20 : bar(6) = 5
  2038. Case 1 'Tropical
  2039. bar(2) = 20 : bar(4) = 7 : bar(6) = 6
  2040. bar(8) = 3 : bar(9) = 10
  2041. Case 2 'Alpine
  2042. bar(0) = 20 : bar(4) = 5 : bar(5) = 8
  2043. Case 3 'City
  2044. bar(0) = 15 : bar(4) = 15 : bar(6) = 7
  2045. bar(8) = 9 : bar(9) = 10 : bar(3) = 2
  2046. Case 4 'Country
  2047. bar(0) = 15 : bar(3) = 5 : bar(5) = 7
  2048. bar(6) = 3 : bar(7) = 8 : bar(9) = 5
  2049. End Select
  2050. MenuBox 35, 28, "Generate Scenery"
  2051. lefx += 16 : ceny += 16
  2052. PutIcon 24, 6, lefx, ceny
  2053. PutIcon 24, 7, lefx, ceny + 32
  2054. PutIcon 24, 8, lefx, ceny + 64
  2055. PutIcon 24, 9, lefx, ceny + 96
  2056. PutIcon 26, 6, lefx, ceny + 128
  2057. PutIcon 26, 7, lefx, ceny + 160
  2058. PutIcon 26, 8, lefx, ceny + 192
  2059. PutIcon 26, 9, lefx, ceny + 224
  2060. PutIcon 26, 11, lefx, ceny + 256
  2061. PutIcon 26, 10, lefx, ceny + 288
  2062. For i = 0 To 9
  2063. sel(i).redraw = -1
  2064. If i < 3 Then
  2065. sel(i).current = 1
  2066. Else
  2067. sel(i).current = 2
  2068. End If
  2069. sel(i).options = 2
  2070. sel(i).opt(1) = "Everywhere"
  2071. If i = 9 Then
  2072. sel(i).opt(2) = "On water"
  2073. Else
  2074. sel(i).opt(2) = "By the road"
  2075. End If
  2076. sel(i).x1 = lefx + 360
  2077. sel(i).y1 = ceny + 32 * i
  2078. sel(i).x2 = lefx + 487
  2079. sel(i).y2 = ceny + 32 * i + 19
  2080. Next i
  2081. buttons = 0
  2082. tempy = ceny
  2083. ceny += 330 : cenx += 240
  2084. StackButton "Generate", 1, -1
  2085. StackButton " Cancel ", 2, -1
  2086. EndOfButtonStack
  2087. scratch.redraw = -1
  2088. scratch.x1 = lefx
  2089. scratch.y1 = ceny
  2090. scratch.x2 = lefx + 199
  2091. scratch.y2 = ceny + 31
  2092. scratch.current = 1
  2093. scratch.options = 2
  2094. scratch.opt(1) = "Use free space"
  2095. scratch.opt(2) = "Remove old scenery"
  2096. ceny = tempy
  2097. Do
  2098. If update Then
  2099. ScreenLock
  2100. For i = 0 To 9
  2101. Dim p As String
  2102. p = Str(bar(i)) + "%"
  2103. Line (lefx + 30, 32 * i + ceny)- Step(304, 19), RGB(160, 160, 160), B
  2104. Line (lefx + 31, 32 * i + ceny + 1)- Step(302, 17), RGB(160, 160, 160), B
  2105. Line (lefx + 32, 32 * i + ceny + 2)- Step(300, 15), RGB(30, 30, 50), BF
  2106. Line (lefx + 32, 32 * i + ceny + 2)- Step(3 * bar(i), 15), RGB(0, 160, 160), BF
  2107. Draw String (lefx + 192 - 4 * Len(p), 32 * i + ceny + 3), p, RGB(250, 250, 250)
  2108. Next i
  2109. ScreenUnlock
  2110. update = 0
  2111. End If
  2112. GetMouse xm, ym, wm, bm
  2113. akey = InKey
  2114. If STRONG_ANTI_HOG Then Sleep 1
  2115. If bm = 1 Then
  2116. If xm >= lefx + 32 And xm <= lefx + 332 AndAlso _
  2117. ym >= ceny + 2 And (ym - ceny - 2) Mod 32 < 22 AndAlso _
  2118. (ym - ceny - 2) \ 32 <= 9 Then
  2119. Dim n As Short
  2120. lastchanged = (ym - ceny - 2) \ 32
  2121. n = bar(lastchanged)
  2122. bar(lastchanged) = (xm - lefx - 32) \ 3
  2123. If bar(lastchanged) <> n Then update = -1
  2124. End If
  2125. End If
  2126. Select Case akey
  2127. Case Chr(13) : v = 1 : Exit Do
  2128. Case Chr(27) : v = 2 : Exit Do
  2129. End Select
  2130. For i = 0 To 9
  2131. Dim test As Short
  2132. test = sel(i).current
  2133. ManageSelector sel(i)
  2134. If sel(i).current <> test Then update = -1
  2135. Next i
  2136. ManageSelector scratch
  2137. v = ManageButtons
  2138. 'Ensure values don't add up greater than 100%
  2139. If update Then
  2140. Dim total As Short, howmany As Short
  2141. Dim factor As Double, topvalue As Byte
  2142. If sel(9).current = 2 Then topvalue = 8 Else topvalue = 9
  2143. For j = 1 To 2
  2144. total = 0 : howmany = 0
  2145. For i = 0 To topvalue
  2146. If sel(i).current = j Then
  2147. total += bar(i)
  2148. If i <> lastchanged Then howmany += 1
  2149. End If
  2150. Next i
  2151. If total > 100 Then
  2152. If sel(lastchanged).current = j Then
  2153. factor = (100 - bar(lastchanged)) / (total - bar(lastchanged))
  2154. Else
  2155. factor = 100 / total
  2156. End If
  2157. For i = 0 To topvalue
  2158. If sel(i).current = j And i <> lastchanged Then
  2159. bar(i) *= factor
  2160. End If
  2161. Next i
  2162. End If
  2163. Next j
  2164. End If
  2165. Loop Until v <> 0
  2166. buttons = 0
  2167. 'Generate the requested scenery
  2168. If v = 1 Then
  2169. Dim As Short openfield, water, bytheroad
  2170. Dim map(1 To 30, 1 To 30) As Byte, s As String
  2171. 'First remove old scenery if requested
  2172. If scratch.current = 2 Then
  2173. For j = 1 To 30
  2174. For i = 1 To 30
  2175. If grid(i, j).track >= &H97 And grid(i, j).track <= &HB2 Then _
  2176. grid(i, j).track = 0
  2177. Next i
  2178. Next j
  2179. End If
  2180. 'Calculate how many tiles of each type are available
  2181. For j = 1 To 30
  2182. For i = 1 To 30
  2183. Select Case grid(i, j).land
  2184. Case 1 To 5 'Water
  2185. If grid(i, j).track Then
  2186. map(i, j) = -1 'Cannot be used
  2187. Else
  2188. map(i, j) = 2 'Water
  2189. water += 1
  2190. End If
  2191. Case Is >= 7 'Mountain borders
  2192. map(i, j) = -1 'Cannot be used
  2193. Case Else 'Grass or mountain top
  2194. If grid(i, j).track Then
  2195. map(i, j) = -1 'Cannot be used
  2196. Else
  2197. Dim isbytheroad As Byte
  2198. s = ""
  2199. If j < 30 Then s &= Chr(grid(i, j + 1).track) Else s &= Chr(0)
  2200. If j > 1 Then s &= Chr(grid(i, j - 1).track) Else s &= Chr(0)
  2201. If i < 30 Then s &= Chr(grid(i + 1, j).track) Else s &= Chr(0)
  2202. If i > 1 Then s &= Chr(grid(i - 1, j).track) Else s &= Chr(0)
  2203. For n As Byte = 1 To 4
  2204. Dim k As UByte
  2205. k = ASC(Mid(s, n, 1))
  2206. If (k > 0 And k < &H97) Or k >= &HFD Then
  2207. isbytheroad = -1
  2208. map(i, j) = 10 + n - 1 'By the road (with direction)
  2209. bytheroad += 1
  2210. Exit For
  2211. End If
  2212. Next n
  2213. If Not isbytheroad Then
  2214. map(i, j) = 1 'Open field
  2215. openfield += 1
  2216. End If
  2217. End If
  2218. End Select
  2219. Next i
  2220. Next j
  2221. 'Fill with scenery
  2222. For round As Byte = 1 To 2
  2223. For i = 0 To 9
  2224. Dim amount As Short, whichfrom As Byte, whichto As Byte
  2225. 'Calculate how many of each type to place
  2226. If sel(i).current = 1 Then 'Everywhere (open field)
  2227. whichfrom = 1 : whichto = 1
  2228. amount = openfield * bar(i) / 100 - 1
  2229. ElseIf i = 9 Then 'Water
  2230. whichfrom = 2 : whichto = 2
  2231. amount = water * bar(i) / 100 - 1
  2232. Else 'By the road
  2233. whichfrom = 10 : whichto = 13
  2234. amount = bytheroad * bar(i) / 100 - 1
  2235. End If
  2236. 'Place the scenery (open field goes last)
  2237. If (whichfrom = 1 And round = 2) Or _
  2238. (whichfrom <> 1 And round = 1) Then
  2239. For j = 1 To amount
  2240. Dim As Byte x, y
  2241. Do
  2242. x = Int(Rnd * 30) + 1
  2243. y = Int(Rnd * 30) + 1
  2244. If map(x, y) >= whichfrom And map(x, y) <= whichto Then
  2245. If i < 4 Then
  2246. grid(x, y).track = thing(i)
  2247. ElseIf i = 9 Then
  2248. grid(x, y).track = thing(i) + Int(Rnd * 4)
  2249. ElseIf whichfrom = 10 Then
  2250. grid(x, y).track = thing(i) + map(x, y) - 10
  2251. Else
  2252. grid(x, y).track = thing(i) + Int(Rnd * 4)
  2253. End If
  2254. map(x, y) = -1
  2255. Exit Do
  2256. ElseIf whichfrom = 1 And map(x, y) >= 10 Then
  2257. If i < 4 Then
  2258. grid(x, y).track = thing(i)
  2259. Else
  2260. grid(x, y).track = thing(i) + Int(Rnd * 4)
  2261. End If
  2262. ElseIf i = 9 And whichfrom = 1 And map(x, y) = 2 Then
  2263. grid(x, y).track = thing(i) + Int(Rnd * 4)
  2264. End If
  2265. Loop
  2266. Next j
  2267. End If
  2268. Next i
  2269. Next round
  2270. 'We've done changes so push to the undo buffer
  2271. PushUndo
  2272. modified = -1
  2273. End If
  2274. DrawTrack
  2275. Do
  2276. GetMouse xm, ym, wm, bm
  2277. Loop Until bm = 0
  2278. Do : Loop Until Len(InKey) = 0
  2279. End Sub
  2280. Sub Menu_Settings
  2281. Dim top As Short, v As Short, akey As String, i As Short
  2282. Dim As SelectorType theformat, thegrid, theconfview, theconfgen
  2283. Dim As Integer xm, ym, wm, bm
  2284. Dim content(1 To 4, 0 To 1) As String
  2285. Dim pointed As Byte, previous As Byte, update As Byte
  2286. Dim validtrack As Byte = -1, briefestwinning As Long
  2287. Dim e As Byte, s As String, t As Double
  2288. Dim switched_to_raw As Byte = 0
  2289. GenerateSections
  2290. If sections > 254 Or paths >= MAXPATHS Then
  2291. validtrack = 0
  2292. ElseIf paths = 0 Then
  2293. validtrack = 0
  2294. End If
  2295. DetectTerrainErrors e, 0, 0
  2296. If e >= 40 And e <= 49 Then validtrack = 0
  2297. briefestwinning = 100000
  2298. For i = 1 To paths
  2299. If path(i).finishes Then
  2300. Dim m As Long
  2301. m = PathLength(i, 1)
  2302. If m < briefestwinning Then briefestwinning = m
  2303. End If
  2304. Next i
  2305. If briefestwinning = 100000 Then validtrack = 0
  2306. MenuBox 37, 27, "Settings"
  2307. lefx += 8 : ceny += 16
  2308. top = ceny
  2309. theformat.x1 = lefx
  2310. theformat.x2 = lefx + 239
  2311. theformat.y1 = top + 208
  2312. theformat.y2 = top + 239
  2313. theformat.options = 4
  2314. theformat.opt(1) = "Def. format: One file"
  2315. theformat.opt(2) = "Def. format: Split binary"
  2316. theformat.opt(3) = "Def. format: Split text"
  2317. theformat.opt(4) = "Def. format: Raw"
  2318. Select Case default_format
  2319. Case FORMAT_BINARY_SPLIT : theformat.current = 2
  2320. Case FORMAT_TEXT_SPLIT : theformat.current = 3
  2321. Case FORMAT_RAW : theformat.current = 4
  2322. Case Else : theformat.current = 1
  2323. End Select
  2324. theformat.redraw = -1
  2325. thegrid.x1 = lefx
  2326. thegrid.x2 = lefx + 239
  2327. thegrid.y1 = top + 256
  2328. thegrid.y2 = top + 287
  2329. thegrid.options = 2
  2330. thegrid.opt(1) = "Grid ON at start up"
  2331. thegrid.opt(2) = "Grid OFF at start up"
  2332. If show_grid Then
  2333. thegrid.current = 1
  2334. Else
  2335. thegrid.current = 2
  2336. End If
  2337. thegrid.redraw = -1
  2338. theconfview.x1 = lefx + 304
  2339. theconfview.x2 = lefx + 543
  2340. theconfview.y1 = top + 208
  2341. theconfview.y2 = top + 239
  2342. theconfview.options = 2
  2343. theconfview.opt(1) = "Show track tile conflicts"
  2344. theconfview.opt(2) = "Hide track tile conflicts"
  2345. If show_errors Then
  2346. theconfview.current = 1
  2347. Else
  2348. theconfview.current = 2
  2349. End If
  2350. theconfview.redraw = -1
  2351. theconfgen.x1 = lefx + 304
  2352. theconfgen.x2 = lefx + 543
  2353. theconfgen.y1 = top + 256
  2354. theconfgen.y2 = top + 287
  2355. theconfgen.options = 2
  2356. theconfgen.opt(1) = "Allow producing conflicts"
  2357. theconfgen.opt(2) = "Prevent tile conflicts"
  2358. If allow_errors Then
  2359. theconfgen.current = 1
  2360. Else
  2361. theconfgen.current = 2
  2362. End If
  2363. theconfgen.redraw = -1
  2364. content(1, 0) = "Track path:"
  2365. For i = 1 To dirlinks
  2366. If Trim(LCase(dirlink(i).text)) = "tracks" Then
  2367. content(1, 1) = Trim(dirlink(i).directory)
  2368. Exit For
  2369. End If
  2370. Next i
  2371. If content(1, 1) = "" Then content(1, 1) = track_path
  2372. content(2, 0) = "Stunts path:"
  2373. For i = 1 To dirlinks
  2374. If Trim(LCase(dirlink(i).text)) = "stunts" Then
  2375. content(2, 1) = Trim(dirlink(i).directory)
  2376. Exit For
  2377. End If
  2378. Next i
  2379. content(3, 0) = "Default author:"
  2380. content(3, 1) = default_author
  2381. If validtrack Then
  2382. content(4, 0) = "Racer calibration time with THIS track (OWOOT, Porsche March Indy)"
  2383. content(4, 1) = Timey(briefestwinning * racer_weigh)
  2384. Else
  2385. content(4, 0) = "Racer calibration time (race 4am.trk in OWOOT, Porsche March Indy):"
  2386. content(4, 1) = Timey(LENGTHOF4AM * racer_weigh)
  2387. End If
  2388. For i = 1 To 4
  2389. s = content(i, 1)
  2390. TLeft , content(i, 0), RGB(200, 200, 200)
  2391. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  2392. TLeft
  2393. Next i
  2394. ceny += 128
  2395. buttons = 0
  2396. StackButton " Cancel ", 2
  2397. StackButton " Save ", 1
  2398. EndOfButtonStack
  2399. previous = -1
  2400. Do
  2401. GetMouse xm, ym, wm, bm
  2402. If xm >= lefx - 4 And xm < lefx + 547 And ym >= top - 8 And ym < top + 184 Then
  2403. pointed = (ym - top + 8) \ 48
  2404. Else
  2405. pointed = -1
  2406. End If
  2407. If pointed <> previous Or update <> 0 Then
  2408. ScreenLock
  2409. If previous <> -1 Then
  2410. Line (lefx - 4, 48 * previous + top - 8)- Step (551, 47), RGB(30, 30, 50), BF
  2411. ceny = 48 * previous + top
  2412. s = content(previous + 1, 1)
  2413. TLeft , content(previous + 1, 0), RGB(200, 200, 200)
  2414. #ifdef RENDER_TO_CP437
  2415. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  2416. #else
  2417. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  2418. #endif
  2419. End If
  2420. If pointed <> -1 Then
  2421. Line (lefx - 4, 48 * pointed + top - 8)- Step (551, 47), RGB(10, 10, 10), BF
  2422. ceny = 48 * pointed + top
  2423. s = content(pointed + 1, 1)
  2424. TLeft , content(pointed + 1, 0), RGB(200, 200, 200)
  2425. #ifdef RENDER_TO_CP437
  2426. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  2427. #else
  2428. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  2429. #endif
  2430. End If
  2431. ScreenUnlock
  2432. previous = pointed
  2433. End If
  2434. If bm = 1 And pointed <> -1 Then
  2435. stringer.init = -1
  2436. stringer.maxlength = 64
  2437. stringer.fileonly = 0
  2438. stringer.x = lefx
  2439. stringer.y = 48 * pointed + top + 16
  2440. stringer.background = RGB(10, 10, 10)
  2441. Do
  2442. akey = ManageString(content(pointed + 1, 1))
  2443. v = ManageButtons
  2444. If STRONG_ANTI_HOG Then Sleep 1
  2445. Loop Until akey = Chr(13) Or akey = Chr(27) Or v <> 0
  2446. t = Timer
  2447. Do : Loop Until Timer >= t + .3
  2448. Do : Loop Until Len(InKey) = 0
  2449. content(pointed + 1, 1) = Trim(content(pointed + 1, 1))
  2450. If pointed = 0 And content(1, 1) = "" Then content(1, 1) = ExePath
  2451. If pointed = 3 Then
  2452. Dim cents As Long
  2453. cents = AntiTimey(content(4, 1))
  2454. If cents < 6000 Then cents = 6000
  2455. If cents > 60000 Then cents = 60000
  2456. content(4, 1) = Timey(cents)
  2457. End If
  2458. update = -1
  2459. End If
  2460. ManageSelector theformat
  2461. ManageSelector thegrid
  2462. ManageSelector theconfview
  2463. ManageSelector theconfgen
  2464. v = ManageButtons
  2465. akey = InKey
  2466. If STRONG_ANTI_HOG Then Sleep 1
  2467. Select Case akey
  2468. Case Chr(13) : v = 1 : Exit Do
  2469. Case Chr(27) : v = 2 : Exit DO
  2470. End Select
  2471. Loop Until v
  2472. buttons = 0
  2473. DrawTrack
  2474. 'Update configuration
  2475. If v = 1 Then
  2476. 'Update track directory
  2477. content(1, 1) = Trim(content(1, 1))
  2478. If Len(content(1, 1)) <> 0 And Right(content(1, 1), 1) <> DIR_DIVISOR Then content(1, 1) &= DIR_DIVISOR
  2479. For i = 1 To dirlinks
  2480. If Trim(LCase(dirlink(i).text)) = "tracks" Then
  2481. dirlink(i).directory = content(1, 1)
  2482. Exit For
  2483. End If
  2484. Next i
  2485. If i > dirlinks Then
  2486. dirlinks += 1
  2487. dirlink(dirlinks).text = "Tracks"
  2488. dirlink(dirlinks).directory = content(1, 1)
  2489. End If
  2490. 'Update Stunts directory
  2491. If Len(content(1, 1)) <> 0 And Right(content(2, 1), 1) <> DIR_DIVISOR Then content(2, 1) &= DIR_DIVISOR
  2492. For i = 1 To dirlinks
  2493. If Trim(LCase(dirlink(i).text)) = "stunts" Then
  2494. dirlink(i).directory = content(2, 1)
  2495. Exit For
  2496. End If
  2497. Next i
  2498. If i > dirlinks Then
  2499. dirlinks += 1
  2500. dirlink(dirlinks).text = "Stunts"
  2501. dirlink(dirlinks).directory = content(2, 1)
  2502. End If
  2503. 'Update author
  2504. default_author = Trim(content(3, 1))
  2505. Dim ff As Integer
  2506. ff = FreeFile
  2507. Open program_path + "bliss.cfg" For Output As ff
  2508. Print #ff, "; Bliss configuration file"
  2509. Print #ff,
  2510. Print #ff, "; Starting track directory. Bliss home directory by default"
  2511. Print #ff, "tracks=" + content(1, 1)
  2512. Print #ff,
  2513. If dirlinks Then
  2514. If dirlinks > 1 Or LCase(dirlink(1).text) <> "tracks" Then
  2515. Print #ff, "; Other directories"
  2516. For i = 1 To dirlinks
  2517. Select Case Trim(LCase(dirlink(i).text))
  2518. Case "tracks"
  2519. Case "stunts" : Print #ff, "stunts=" + Trim(dirlink(i).directory)
  2520. Case Else
  2521. Print #ff, "dirlink=" + Trim(dirlink(i).text) + ":" + Trim(dirlink(i).directory)
  2522. End Select
  2523. Next i
  2524. Print #ff,
  2525. End If
  2526. End If
  2527. Print #ff, "; Default author name"
  2528. If Len(content(3, 1)) = 0 Then
  2529. Print #ff, "; author=Your Name"
  2530. Else
  2531. Print #ff, "author=" + content(3, 1)
  2532. End If
  2533. Print #ff,
  2534. Print #ff, "; Racer speed calibration quotient"
  2535. If validtrack Then
  2536. racer_weigh = AntiTimey(content(4, 1)) / briefestwinning
  2537. Else
  2538. racer_weigh = AntiTimey(content(4, 1)) / LENGTHOF4AM
  2539. End If
  2540. Print #ff, "calibration="; racer_weigh
  2541. Print #ff,
  2542. Print #ff, "; Default format for new tracks"
  2543. If theformat.current = 4 And default_format <> FORMAT_RAW Then switched_to_raw = -1
  2544. Select Case theformat.current
  2545. Case 1 : Print #ff, "format=bliss" : default_format = FORMAT_COMBINED
  2546. Case 2 : Print #ff, "format=split" : default_format = FORMAT_BINARY_SPLIT
  2547. Case 3 : Print #ff, "format=text" : default_format = FORMAT_TEXT_SPLIT
  2548. Case 4 : Print #ff, "format=none" : default_format = FORMAT_RAW
  2549. End Select
  2550. Print #ff,
  2551. Print #ff, "; Show grid at start time"
  2552. If thegrid.current = 1 Then
  2553. Print #ff, "grid=yes"
  2554. Else
  2555. Print #ff, "grid=no"
  2556. End If
  2557. Print #ff,
  2558. Print #ff, "; Enable generating track conflicts (superpositions)"
  2559. If theconfgen.current = 1 Then
  2560. Print #ff, "superpositions=yes"
  2561. Else
  2562. Print #ff, "superpositions=no"
  2563. End If
  2564. Print #ff,
  2565. Print #ff, "; Show terrain conflict warnings"
  2566. If theconfview.current = 1 Then
  2567. Print #ff, "warnings=yes"
  2568. Else
  2569. Print #ff, "warnings=no"
  2570. End If
  2571. Print #ff,
  2572. Print #ff, "; Image format when saving a track-shot"
  2573. Print #ff, "imageformat=" + imageformat
  2574. Print #ff,
  2575. Print #ff, "; Use curl in order to support https"
  2576. If use_curl Then
  2577. Print #ff, "curl=yes"
  2578. Else
  2579. Print #ff, "curl=no"
  2580. End If
  2581. Close ff
  2582. End If
  2583. Do
  2584. GetMouse xm, ym, wm, bm
  2585. Loop Until bm = 0
  2586. Do : Loop Until Len(InKey) = 0
  2587. If switched_to_raw Then
  2588. MenuBox 28, 14, "Warning!"
  2589. ceny += 16
  2590. TCentre , "You are setting default format to RAW", RGB(200, 200, 240)
  2591. ceny += 16
  2592. TCentre , "Track title and author's name as well as", RGB(200, 200, 240)
  2593. TCentre , "other metadata will be LOST if you save", RGB(200, 200, 240)
  2594. TCentre , "your track in this format!", RGB(200, 200, 240)
  2595. ceny += 24
  2596. buttons = 0
  2597. StackButton " OK "
  2598. EndOfButtonStack
  2599. Do
  2600. v = ManageButtons
  2601. Loop Until v <> 0 Or Len(InKey) <> 0
  2602. buttons = 0
  2603. Do
  2604. GetMouse xm, ym, wm, bm
  2605. Loop Until bm = 0
  2606. Do : Loop Until Len(InKey) = 0
  2607. DrawTrack
  2608. End If
  2609. End Sub
  2610. Sub Menu_StartNewTrack
  2611. Dim v As Short, akey As String
  2612. Dim As Short x, y, i, top
  2613. Dim As Integer xm, ym, wm, bm
  2614. Dim ttitle(1 To 100) As String, terrain(1 To 100) As String
  2615. Dim terrains As Short, first_terrain As Short
  2616. MenuBox 28, 10, "Start New Track"
  2617. ceny += 16
  2618. TCentre , "Current track data will be lost!", RGB(200, 200, 240)
  2619. TCentre , "Are you sure you want to clear the map?", RGB(200, 200, 240)
  2620. ceny += 16
  2621. StackButton " OK ", 1
  2622. StackButton " Cancel ", 2, , 50
  2623. EndOfButtonStack
  2624. Do
  2625. v = ManageButtons
  2626. akey = InKey
  2627. If STRONG_ANTI_HOG Then Sleep 1
  2628. Loop Until v <> 0 Or akey <> ""
  2629. buttons = 0
  2630. Do
  2631. GetMouse xm, ym, wm, bm
  2632. Loop Until bm = 0
  2633. DrawTrack
  2634. DrawPanel
  2635. If v <> 1 Then Exit Sub 'User cancelled
  2636. '---------- Terrain selection
  2637. MenuBox 35, 37, "Select Terrain"
  2638. 'Load terrains
  2639. Open program_path + "terrains.dat" For Binary Access Read As 100
  2640. Get #100, 5, terrains
  2641. For i = 1 To terrains
  2642. Get #100, 2 * i + 5, v
  2643. Seek #100, v
  2644. Get #100, , v
  2645. ttitle(i) = Space(v)
  2646. Get #100, , ttitle(i)
  2647. Get #100, , v
  2648. terrain(i) = Space(v)
  2649. Get #100, , terrain(i)
  2650. Next i
  2651. Close 100
  2652. 'Clear grid
  2653. For y = 1 To 30
  2654. For x = 1 To 30
  2655. grid(x, y).land = 0
  2656. grid(x, y).track = 0
  2657. grid(x, y).bgc = 0
  2658. grid(x, y).border = 0
  2659. Next x
  2660. Next y
  2661. Dim As Short selected_t, pointed_t, old_t
  2662. ceny += 16
  2663. top = ceny
  2664. lefx += 240
  2665. first_terrain = 1
  2666. For i = first_terrain To first_terrain + 27
  2667. TLeft , ttitle(i), RGB(160, 160, 240)
  2668. Next i
  2669. TLeft
  2670. StackButton " Create Track ", 1
  2671. EndOfButtonStack
  2672. ScreenLock
  2673. DrawBox lefx - 184, top, lefx - 184 + 135, top + 135
  2674. Line (lefx - 176, top + 8)- Step (119, 119), RGB(0, 100, 0), BF
  2675. ScreenUnlock
  2676. old_t = 1
  2677. selected_t = 1
  2678. Do
  2679. GetMouse xm, ym, wm, bm
  2680. If xm >= lefx - 8 And xm < lefx + 272 And ym >= top And ym < top + 16 * terrains Then
  2681. pointed_t = (ym - top) \ 16 + 1
  2682. Else
  2683. pointed_t = -1
  2684. End If
  2685. If pointed_t <> old_t Then
  2686. ScreenLock
  2687. If old_t <> -1 Then
  2688. If old_t = selected_t Then Color RGB(160, 160, 240) Else Color RGB(30, 30, 50)
  2689. Line (lefx - 8, top + 16 * (old_t - 1))- Step (271, 15), , BF
  2690. If old_t = selected_t Then Color RGB(10, 10, 10) Else Color RGB(160, 160, 240)
  2691. Draw String (lefx, top + 16 * (old_t - 1)), ttitle(old_t)
  2692. End If
  2693. If pointed_t <> -1 Then
  2694. If pointed_t = selected_t Then Color RGB(160, 160, 240) Else Color RGB(30, 30, 50)
  2695. Line (lefx - 8, top + 16 * (pointed_t - 1))- Step (271, 15), , BF
  2696. If pointed_t = selected_t Then Color RGB(250, 250, 250) Else Color RGB(200, 200, 250)
  2697. Draw String (lefx, top + 16 * (pointed_t - 1)), ttitle(pointed_t)
  2698. End If
  2699. ScreenUnlock
  2700. old_t = pointed_t
  2701. End If
  2702. If bm = 1 And pointed_t <> -1 Then
  2703. old_t = selected_t
  2704. selected_t = pointed_t
  2705. UnRLETerrain terrain(selected_t)
  2706. ScreenLock
  2707. For y = 1 To 30
  2708. For x = 1 To 30
  2709. Dim As ULong c1, c2
  2710. Dim style As Byte
  2711. Select Case grid(x, y).land
  2712. Case 0 : style = 0 : c1 = RGB(0, 100, 0)
  2713. Case 1 : style = 0 : c1 = RGB(0, 0, 100)
  2714. Case 2 : style = 1 : c1 = RGB(0, 0, 100) : c2 = RGB(0, 100, 0)
  2715. Case 3 : style = 2 : c1 = RGB(0, 100, 0) : c2 = RGB(0, 0, 100)
  2716. Case 4 : style = 1 : c1 = RGB(0, 100, 0) : c2 = RGB(0, 0, 100)
  2717. Case 5 : style = 2 : c1 = RGB(0, 0, 100) : c2 = RGB(0, 100, 0)
  2718. Case 6 : style = 0 : c1 = RGB(0, 200, 0)
  2719. Case 7, 10 : style = 0 : c1 = RGB(0, 160, 0)
  2720. Case 8, 9 : style = 0 : c1 = RGB(0, 240, 0)
  2721. Case 11 : style = 2 : c1 = RGB(0, 200, 0) : c2 = RGB(0, 100, 0)
  2722. Case 12 : style = 1 : c1 = RGB(50, 255, 50) : c2 = RGB(0, 100, 0)
  2723. Case 13 : style = 2 : c1 = RGB(0, 100, 0) : c2 = RGB(0, 200, 0)
  2724. Case 14 : style = 1 : c1 = RGB(0, 100, 0) : c2 = RGB(0, 130, 0)
  2725. Case 15 : style = 2 : c1 = RGB(0, 200, 0) : c2 = RGB(0, 220, 0)
  2726. Case 16 : style = 1 : c1 = RGB(0, 200, 0) : c2 = RGB(50, 255, 50)
  2727. Case 17 : style = 2 : c1 = RGB(0, 220, 0) : c2 = RGB(0, 200, 0)
  2728. Case 18 : style = 1 : c1 = RGB(0, 130, 0) : c2 = RGB(0, 200, 0)
  2729. Case Else : style = 0 : c1 = RGB(100, 0, 0)
  2730. End Select
  2731. Select Case style
  2732. Case 0 : Line (lefx - 180 + 4 * x, top + 4 * y + 4)- Step (3, 3), c1, BF
  2733. Case 1
  2734. Line (lefx - 180 + 4 * x, top + 4 * y + 4)- Step (0, 3), c1
  2735. Line - Step (3, 0), c1
  2736. Line - Step (-3, -3), c1
  2737. Paint Step (1, 2), c1
  2738. Line (lefx - 180 + 4 * x, top + 4 * y + 4)- Step (3, 0), c2
  2739. Line - Step (0, 3), c2
  2740. Line - Step (-3, -3), c2
  2741. Paint Step (2, 1), c2
  2742. Case Else
  2743. Line (lefx - 180 + 4 * x, top + 4 * y + 4)- Step (0, 3), c1
  2744. Line - Step (3, -3), c1
  2745. Line - Step (-3, 0), c1
  2746. Paint Step (1, 1), c1
  2747. Line (lefx - 180 + 4 * x + 3, top + 4 * y + 4)- Step (0, 3), c2
  2748. Line - Step (-3, 0), c2
  2749. Line - Step (3, -3), c2
  2750. Paint Step (-1, 2), c2
  2751. End Select
  2752. Next x
  2753. Next y
  2754. ScreenUnlock
  2755. End If
  2756. v = ManageButtons
  2757. If STRONG_ANTI_HOG Then Sleep 1
  2758. Loop Until v <> 0 Or InKey = Chr(13)
  2759. buttons = 0
  2760. modified = 0
  2761. track_file = ""
  2762. landscape = 4
  2763. thisfileformat = default_format
  2764. format_byte = 152 'Fixed for Bliss
  2765. Dim today As Double
  2766. today = Now
  2767. meta.title = ""
  2768. meta.author = default_author
  2769. meta.cyear = DatePart("yyyy", today)
  2770. meta.cmonth = DatePart("m", today)
  2771. meta.cday = DatePart("d", today)
  2772. meta.tool = "Bliss"
  2773. meta.toolversion = THISVERSION_NOPERIOD
  2774. meta.comment = ""
  2775. meta.championship = ""
  2776. meta.editing_time = 0
  2777. track_file = ""
  2778. UpdateTitleBar
  2779. started_editing = Timer
  2780. PushUndo
  2781. Do
  2782. GetMouse xm, ym, wm, bm
  2783. Loop Until bm = 0
  2784. Do : Loop Until Len(InKey) = 0
  2785. DrawTrack
  2786. DrawPanel
  2787. End Sub
  2788. Sub Menu_LoadTrack
  2789. Dim v As Short
  2790. Dim As Integer xm, ym, wm, bm
  2791. Dim As Short bx1, bx2, by1, by2
  2792. Dim s As String, selected_track As String, akey As String
  2793. Dim olds As String
  2794. buttons = 0
  2795. MenuBox 28, 28, "Load Track"
  2796. bx1 = lefx + 8 : by1 = ceny : bx2 = lefx + 407 : by2 = ceny + 31
  2797. DrawBox bx1, by1, bx2, by2
  2798. InitFiles "trk;rpl", lefx + 8, ceny + 40, lefx + 407, ceny + 351
  2799. cenx -= 16 : ceny += 40
  2800. StackButton " Load ", 1, -1
  2801. StackButton " Cancel ", 2, -1
  2802. EndOfButtonStack
  2803. selected_track = ""
  2804. stringer.init = -1
  2805. stringer.maxlength = 40
  2806. stringer.fileonly = -1
  2807. stringer.x = bx1 + 16
  2808. stringer.y = by1 + 8
  2809. stringer.background = RGB(30, 30, 50)
  2810. #ifdef __FB_LINUX__ 'Empty keyboard buffer
  2811. For i As Byte = 1 To 32
  2812. akey = LinKey
  2813. Next i
  2814. #endif
  2815. olds = ""
  2816. Do
  2817. v = ManageButtons
  2818. s = selected_track
  2819. akey = ManageString(selected_track)
  2820. If s <> selected_track And Len(selected_track) <> 0 Then akey = Chr(1) + selected_track
  2821. s = ManageFiles(akey)
  2822. If STRONG_ANTI_HOG Then Sleep 1
  2823. Select Case akey
  2824. Case Chr(13)
  2825. Do : Loop Until MultiKey(&H1C) = 0
  2826. v = 1
  2827. Case Chr(27)
  2828. Do : Loop Until MultiKey(1) = 0
  2829. v = 2
  2830. End Select
  2831. If Len(s) <> 0 And olds <> s Then
  2832. selected_track = s
  2833. stringer.cursor_pos = Len(s)
  2834. ScreenLock
  2835. DrawBox bx1, by1, bx2, by2
  2836. Draw String (bx1 + 16, by1 + 8), s + Space(30 - Len(s)), RGB(160, 160, 240)
  2837. ScreenUnlock
  2838. olds = s
  2839. End If
  2840. Loop Until v = 1 Or v = 2
  2841. buttons = 0
  2842. #ifdef __FB_LINUX__
  2843. Do : Loop Until LinKey = ""
  2844. #endif
  2845. Do : Loop Until InKey = ""
  2846. Do
  2847. GetMouse xm, ym, wm, bm
  2848. Loop Until bm = 0
  2849. If v = 1 And Len(selected_track) <> 0 Then
  2850. If InStr(selected_track, ".") = 0 Then selected_track = selected_track + ".trk"
  2851. If FileExists(track_path + selected_track) Then
  2852. LoadTrack track_path + selected_track
  2853. track_file = selected_track
  2854. DrawTrack
  2855. PushUndo
  2856. Else
  2857. DrawTrack
  2858. buttons = 0
  2859. Error_Message "File not found or wrong name"
  2860. End If
  2861. Else
  2862. DrawTrack
  2863. End If
  2864. DrawPanel
  2865. End Sub
  2866. Sub Menu_Analysis
  2867. Dim As Integer xm, ym, wm, bm
  2868. Dim As Short i, v
  2869. Dim As Byte x, y, page
  2870. Dim e As UByte
  2871. Dim As Short winning, safe, cycles
  2872. Dim As Short shortestsafe, shortestwinning, n
  2873. Dim As Long briefestsafe, briefestwinning, m
  2874. Dim As Byte flow_fatal, wrong_way
  2875. Dim As Byte terrain_crash, terrain_fatal, terrain_warning
  2876. Dim As ULong normal = RGB(160, 160, 240), bright = RGB(180, 180, 80)
  2877. Dim As SelectorType current_car
  2878. GenerateSections
  2879. If sections > 254 Or paths >= MAXPATHS Then
  2880. Error_Message "Track is too complex. Too many splits!"
  2881. Exit Sub
  2882. ElseIf paths = 0 Then
  2883. Error_Message "Track has no valid path", "Track Analysis"
  2884. Exit Sub
  2885. End If
  2886. DetectTerrainErrors e, x, y
  2887. Select Case e
  2888. Case 40 : terrain_crash = -1
  2889. Case 41 To 49 : terrain_fatal = -1
  2890. Case 50 To 59 : terrain_warning = -1
  2891. End Select
  2892. DetectNotStunts x, y, e
  2893. shortestsafe = 10000
  2894. shortestwinning = 10000
  2895. briefestsafe = 1000000
  2896. briefestwinning = 100000
  2897. For i = 1 To paths
  2898. If path(i).finishes Then
  2899. winning += 1
  2900. n = PathLength(i)
  2901. m = PathLength(i, 1)
  2902. If n < shortestwinning Then shortestwinning = n
  2903. If m < briefestwinning Then briefestwinning = m
  2904. If path(i).e = 0 Then
  2905. safe += 1
  2906. If n < shortestsafe Then shortestsafe = n
  2907. If m < briefestsafe Then briefestsafe = m
  2908. End If
  2909. End If
  2910. If path(i).e = 82 Then
  2911. cycles += 1
  2912. ElseIf path(i).e >= 70 And path(i).e <= 79 Then
  2913. flow_fatal = -1
  2914. End If
  2915. Next i
  2916. 'Load car selector
  2917. current_car.options = cars
  2918. current_car.current = activecar
  2919. For i = 1 To UBound(current_car.opt)
  2920. If i > cars Then Exit For
  2921. current_car.opt(i) = car(i).cname
  2922. Next i
  2923. current_car.redraw = -1
  2924. current_car.x1 = 512
  2925. current_car.x2 = 719
  2926. current_car.y1 = 200
  2927. current_car.y2 = 223
  2928. Do
  2929. Select Case page
  2930. Case 0 '----------------------------------------------
  2931. Dim As Short xrecalc, yrecalc, sxrecalc, syrecalc
  2932. MenuBox 30, 23, "Track Analysis"
  2933. lefx += 8
  2934. TLeft
  2935. concolour = normal : TCont "Total paths: "
  2936. concolour = bright : TCont Str(paths), -1
  2937. concolour = normal : TCont "Winning paths: "
  2938. concolour = bright : TCont Str(winning), -1
  2939. If winning Then
  2940. concolour = normal : TCont "Shortest winning path: "
  2941. concolour = bright : TCont Str(shortestwinning) + " tiles", -1
  2942. concolour = normal : TCont "Estimated winning time: "
  2943. xrecalc = conx : yrecalc = cony
  2944. concolour = bright : TCont Timey(briefestwinning * racer_weigh * car(activecar).handicap) + " (" + Trim(Str(briefestwinning)) + " tokens)", -1
  2945. End If
  2946. concolour = normal : TCont "Safe paths: "
  2947. concolour = bright : TCont Str(safe), -1
  2948. If safe Then
  2949. concolour = normal : TCont "Shortest safe path: "
  2950. concolour = bright : TCont Str(shortestsafe) + " tiles", -1
  2951. concolour = normal : TCont "Estimated winning time on a safe path: "
  2952. sxrecalc = conx : syrecalc = cony
  2953. concolour = bright : TCont Timey(briefestsafe * racer_weigh * car(activecar).handicap), -1
  2954. End If
  2955. concolour = normal : TCont "Cycles: "
  2956. concolour = bright : TCont Str(cycles), -1
  2957. TCont "", -1
  2958. concolour = normal : TCont "Prognosis:", -1
  2959. concolour = bright
  2960. If terrain_crash Then
  2961. TCont "Stunts will crash because of terrain errors", -1
  2962. ElseIf terrain_fatal Then
  2963. TCont "Track will not run, due to terrain errors", -1
  2964. ElseIf winning Then
  2965. If flow_fatal Then
  2966. TCont "Track will fail because of path flow error", -1
  2967. ElseIf terrain_warning Then
  2968. TCont "Track will run, but terrain problems may occur", -1
  2969. ElseIf e Then
  2970. TCont "Stunts will run the track. Using the internal", -1
  2971. TCont "editor will corrupt it, though", -1
  2972. Else
  2973. TCont "Track will run fine", -1
  2974. End If
  2975. Else
  2976. TCont "Track will fail because there's no winning path", -1
  2977. End If
  2978. concolour = normal : cony += 16
  2979. current_car.y1 = cony - 3
  2980. If winning Then TCont "Times estimated based on:"
  2981. ceny += 248
  2982. buttons = 0
  2983. StackButton "See paths", 1
  2984. If winning Then StackButton "See times", 2
  2985. StackButton " OK ", 3
  2986. EndOfButtonStack
  2987. Do
  2988. GetMouse xm, ym, wm, bm
  2989. Loop Until bm = 0
  2990. current_car.redraw = -1
  2991. current_car.x1 = 680
  2992. current_car.x2 = current_car.x1 + 219
  2993. current_car.y2 = current_car.y1 + 23
  2994. Do
  2995. If winning Then ManageSelector current_car
  2996. If current_car.current <> activecar Then
  2997. conx = xrecalc : cony = yrecalc
  2998. Line (conx, cony)- Step (200, 15), RGB(30, 30, 50), BF
  2999. concolour = bright
  3000. activecar = current_car.current
  3001. TCont Timey(briefestwinning * racer_weigh * car(activecar).handicap) + " (" + Trim(Str(briefestwinning)) + " tokens)", -1
  3002. If sxrecalc Then
  3003. conx = sxrecalc : cony = syrecalc
  3004. Line (conx, cony)- Step (100, 15), RGB(30, 30, 50), BF
  3005. TCont Timey(briefestsafe * racer_weigh * car(activecar).handicap), -1
  3006. End If
  3007. End If
  3008. v = ManageButtons
  3009. If STRONG_ANTI_HOG Then Sleep 1
  3010. Loop Until v <> 0 Or Len(InKey) <> 0
  3011. buttons = 0
  3012. DrawTrack
  3013. If v = 3 Or v = 0 Then Exit Do
  3014. page = v
  3015. Case 1 '------------------------------------------------
  3016. Dim As Short first = 1, current = 1, top, ex, exfirst
  3017. Dim pathdata(1 To paths, 2) As String
  3018. Dim paintcol As ULong, update As Byte = -1
  3019. Dim akey As String, exw As Integer
  3020. Dim knob As Double, plen1 As Long, plen2 As Long
  3021. For i = 1 To paths
  3022. plen1 = PathLength(i)
  3023. plen2 = PathLength(i, 1)
  3024. pathdata(i, 0) = "Path " + Str(i) + ": " + Str(plen1) + " tiles - " + Timey(plen2 * racer_weigh * car(activecar).handicap)
  3025. If path(i).finishes Then
  3026. pathdata(i, 1) = "Complete"
  3027. If path(i).e Then
  3028. pathdata(i, 1) &= ", with warnings"
  3029. Else
  3030. pathdata(i, 1) &= ", safe"
  3031. End If
  3032. If plen1 = shortestwinning Then pathdata(i, 1) &= " (opp's path)"
  3033. If plen2 = briefestwinning Then pathdata(i, 1) &= " - Fastest"
  3034. Else
  3035. pathdata(i, 1) = "Incomplete"
  3036. If path(i).e = 72 Then
  3037. pathdata(i, 1) &= ", wrong way"
  3038. ElseIf section(ASC(Right(path(i).p, 1))).cycle Then
  3039. pathdata(i, 1) &= ", cyclic"
  3040. End If
  3041. End If
  3042. Next i
  3043. MenuBox 30, 32, "Track Analysis"
  3044. ceny += 16 : top = ceny
  3045. lefx += 8
  3046. ceny += 392
  3047. buttons = 0
  3048. StackButton "Follow path", 1
  3049. If winning Then StackButton "See times", 2
  3050. StackButton "Main page", 3
  3051. StackButton " OK ", 4
  3052. EndOfButtonStack
  3053. Do
  3054. GetMouse xm, ym, exw, bm
  3055. Loop Until bm = 0
  3056. Do
  3057. If update Then
  3058. ceny = top
  3059. ScreenLock
  3060. Line (lefx + 416, top)- Step (15, 359), RGB(30, 30, 50), BF
  3061. Line (lefx + 423, top)- Step (1, 359), RGB(200, 200, 200), B
  3062. If paths > 1 Then knob = (current - 1) / (paths - 1) Else knob = 0
  3063. Line (lefx + 416, top + 344 * knob)- Step (15, 15), RGB(200, 200, 200), BF
  3064. For i = first To first + 7
  3065. If i > paths Then Exit For
  3066. If i = current Then
  3067. paintcol = RGB(10, 10, 10)
  3068. Else
  3069. paintcol = RGB(30, 30, 50)
  3070. End If
  3071. Line (lefx - 4, top + 48 * (i - first) - 4)- Step (379, 39), paintcol, BF
  3072. TLeft , pathdata(i, 0), normal
  3073. TLeft , pathdata(i, 1), bright
  3074. TLeft
  3075. Next i
  3076. ScreenUnlock
  3077. update = 0
  3078. End If
  3079. akey = InKey
  3080. GetMouse xm, ym, wm, bm
  3081. If STRONG_ANTI_HOG Then Sleep 1
  3082. If bm = 1 Then
  3083. ex = current : exfirst = first
  3084. If xm >= lefx - 4 And xm < lefx + 376 And _
  3085. ym >= top And ym < top + 380 Then
  3086. current = first + (ym - top + 4) \ 48
  3087. If current > paths Then current = paths
  3088. If current > first + 7 Then current = first + 7
  3089. End If
  3090. If xm >= lefx + 416 And xm < lefx + 432 And _
  3091. ym >= top And ym < top + 360 Then
  3092. current = (ym - top) * paths / 360 + 1
  3093. If current > paths Then current = paths
  3094. If first > current Then
  3095. first = current
  3096. ElseIf current > first + 7 Then
  3097. first = current - 7
  3098. End If
  3099. End If
  3100. If current <> ex Or first <> exfirst Then update = -1
  3101. End If
  3102. If wm <> exw Then
  3103. If wm > exw Then
  3104. If first > 1 Then
  3105. first -= 1
  3106. If current > first + 7 Then current -= 1
  3107. update = -1
  3108. End If
  3109. Else
  3110. If first + 7 < paths Then
  3111. first += 1
  3112. If current < first Then current = first
  3113. update = -1
  3114. End If
  3115. End If
  3116. exw = wm
  3117. End If
  3118. Select Case akey
  3119. Case Chr(255, 72)
  3120. If current > 1 Then
  3121. current -= 1
  3122. If first > current Then first = current
  3123. update = -1
  3124. End If
  3125. Case Chr(255, 80)
  3126. If current < paths Then
  3127. current += 1
  3128. If first + 7 < current Then first += 1
  3129. update = -1
  3130. End If
  3131. Case Chr(27) : v = 0 : Exit Do
  3132. Case Chr(13) : v = 1 : Exit Do
  3133. End Select
  3134. v = ManageButtons
  3135. If v <> 0 Then Exit Do
  3136. Loop
  3137. buttons = 0
  3138. DrawTrack
  3139. Select Case v
  3140. Case 1
  3141. FollowPath path(current).p
  3142. drawkeyboardcursor = -1
  3143. ManageKeyboardCursor -1
  3144. Exit Do
  3145. Case 2 : page = 2
  3146. Case 3 : page = 0
  3147. Case Else : Exit Do
  3148. End Select
  3149. Case 2 '----------------------------------------------
  3150. Dim As Short xtimes, ytimes, ynorh
  3151. Dim As String rhname(1 To 8), norhname(1 To 3)
  3152. Dim As Single rhratio(1 To 8), norhratio(1 To 3)
  3153. Dim i As Byte
  3154. rhname(1) = "Duplode" : rhratio(1) = 6.8815
  3155. rhname(2) = "Marco" : rhratio(2) = 6.8863
  3156. rhname(3) = "FinRok" : rhratio(3) = 7.0758
  3157. rhname(4) = "Zak McKracken" : rhratio(4) = 7.6161
  3158. rhname(5) = "Cas" : rhratio(5) = 7.6255
  3159. rhname(6) = "Nach" : rhratio(6) = 7.6588
  3160. rhname(7) = "AbuRaf70" : rhratio(7) = 7.9953
  3161. rhname(8) = "Shoegazing Leo" : rhratio(8) = 9.2796
  3162. norhname(1) = "Marco" : norhratio(1) = 7.4313
  3163. norhname(2) = "Duplode" : norhratio(2) = 7.6066
  3164. norhname(3) = "Cas" : norhratio(3) = 8.3744
  3165. MenuBox 30, 31, "Track Analysis"
  3166. lefx += 112
  3167. TLeft
  3168. TCentre , "Estimated OWOOT times for famous racers", RGB(200, 200, 200)
  3169. TLeft
  3170. ytimes = cony : xtimes = conx + 160
  3171. For i = 1 To 8
  3172. concolour = normal
  3173. TCont rhname(i)
  3174. conx = xtimes
  3175. concolour = bright
  3176. TCont Timey(briefestwinning * rhratio(i) * car(activecar).handicap), 1
  3177. Next i
  3178. ceny += 144
  3179. TLeft
  3180. TCentre , "Estimated OWOOT NoRH times for famous racers", RGB(200, 200, 200)
  3181. TLeft
  3182. ynorh = cony
  3183. For i = 1 To 3
  3184. concolour = normal
  3185. TCont norhname(i)
  3186. conx = xtimes
  3187. concolour = bright
  3188. TCont Timey(briefestwinning * norhratio(i) * car(activecar).handicap), 1
  3189. Next i
  3190. ceny += 64
  3191. TLeft
  3192. TCentre , "Estimations based on selected car", RGB(200, 200, 200)
  3193. TLeft
  3194. current_car.options = cars
  3195. For i = 1 To cars
  3196. current_car.opt(i) = car(i).cname
  3197. Next i
  3198. current_car.redraw = -1
  3199. current_car.x1 = cenx - 100
  3200. current_car.x2 = current_car.x1 + 199
  3201. current_car.y1 = ceny
  3202. current_car.y2 = current_car.y1 + 23
  3203. ceny += 48
  3204. buttons = 0
  3205. StackButton "Main page", 1
  3206. StackButton "See paths", 2
  3207. StackButton " OK ", 3
  3208. EndOfButtonStack
  3209. Do
  3210. GetMouse xm, ym, wm, bm
  3211. Loop Until bm = 0
  3212. Do
  3213. ManageSelector current_car
  3214. If current_car.current <> activecar Then
  3215. activecar = current_car.current
  3216. concolour = bright
  3217. cony = ytimes
  3218. lefx = xtimes : conx = xtimes
  3219. Line (xtimes, ytimes)- Step(79, 127), RGB(30, 30, 50), BF
  3220. For i = 1 To 8
  3221. TCont Timey(briefestwinning * rhratio(i) * car(activecar).handicap), 1
  3222. Next i
  3223. cony = ynorh
  3224. Line (xtimes, ynorh)- Step(79, 47), RGB(30, 30, 50), BF
  3225. For i = 1 To 3
  3226. TCont Timey(briefestwinning * norhratio(i) * car(activecar).handicap), 1
  3227. Next i
  3228. End If
  3229. v = ManageButtons
  3230. If STRONG_ANTI_HOG Then Sleep 1
  3231. Loop Until Len(InKey) <> 0 Or v <> 0
  3232. buttons = 0
  3233. DrawTrack
  3234. Select Case v
  3235. Case 1 : page = 0
  3236. Case 2 : page = 1
  3237. Case Else : Exit Do
  3238. End Select
  3239. End Select
  3240. Loop
  3241. Do
  3242. GetMouse xm, ym, wm, bm
  3243. Loop Until bm = 0
  3244. Do : Loop Until Len(InKey) = 0
  3245. End Sub
  3246. Sub Menu_Colouring
  3247. Dim updatecols As Byte, bluish As ULong
  3248. Dim tempcol(0 To 23, 0 To 1) As ULong
  3249. Dim As ULong r, g, b
  3250. Dim As ULong temp_bgc, temp_border
  3251. Dim As Integer xm, ym, bm, wm
  3252. Dim As Byte kx, ky, usekeyboard
  3253. Dim v As Short, akey As String, dy As Short
  3254. temp_bgc = current_bgc
  3255. temp_border = current_border
  3256. For i As Short = 0 To 23
  3257. tempcol(i, 0) = cpal(i)
  3258. r = (cpal(i) ShR 16) And 255
  3259. g = (cpal(i) ShR 8) And 255
  3260. b = cpal(i) And 255
  3261. tempcol(i, 1) = RGB(Int(.7 * r), Int(.7 * g), Int(.7 * b))
  3262. Next i
  3263. tempcol(0, 1) = 0
  3264. bluish = RGB(160, 160, 240)
  3265. MenuBox 36, 24, "Colouring"
  3266. dy = ceny
  3267. TLeft
  3268. TLeft , " Border colour"
  3269. TLeft
  3270. TLeft , " Red", bluish
  3271. TLeft , " Green", bluish
  3272. TLeft , " Blue", bluish
  3273. TLeft
  3274. TLeft
  3275. TLeft , " Background colour"
  3276. TLeft
  3277. TLeft , " Red", bluish
  3278. TLeft , " Green", bluish
  3279. TLeft , " Blue", bluish
  3280. TLeft
  3281. TLeft
  3282. TLeft , " Preview"
  3283. TLeft
  3284. TLeft
  3285. buttons = 0
  3286. StackButton " Set colours ", 1
  3287. StackButton " Clear ", 2
  3288. StackButton " Uncolour map ", 3
  3289. StackButton " Cancel ", 4
  3290. EndOfButtonStack
  3291. updatecols = -1
  3292. Do
  3293. If updatecols <> 0 Then
  3294. ScreenLock
  3295. For i As Short = 0 To 1
  3296. Dim c As ULong
  3297. If i Then c = temp_bgc Else c = temp_border
  3298. For j As Short = 0 To 2
  3299. Dim reg As UByte
  3300. Line (494, 112 * i + 20 * j + 46 + dy)- Step (266, 10), RGB(30, 30, 50), BF
  3301. Line (500, 112 * i + 20 * j + 50 + dy)- Step (255, 2), RGB(128, 128, 128), BF
  3302. Select Case j
  3303. Case 0 : reg = (c And &HFF0000) ShR 16
  3304. Case 1 : reg = (c And &HFF00) ShR 8
  3305. Case Else : reg = c And 255
  3306. End Select
  3307. Circle (500 + reg, 112 * i + 20 * j + 51 + dy), 4, RGB(200, 200, 200), , , , F
  3308. Next j
  3309. For j As Short = 0 To 3
  3310. For k As Short = 0 To 5
  3311. If j + k = 0 Then
  3312. Line (24 * k + 790, 112 * i + 24 * j + 16 + dy)- Step (22, 22), RGB(128, 128, 128), B
  3313. Line (24 * k + 791, 112 * i + 24 * j + 17 + dy)- Step (20, 20), RGB(30, 30, 50), BF
  3314. Else
  3315. Line (24 * k + 790, 112 * i + 24 * j + 16 + dy)- Step (22, 22), tempcol(6 * j + k, i), BF
  3316. End If
  3317. If usekeyboard AndAlso kx = k And ky = 4 * i + j Then
  3318. Line (24 * k + 795, 112 * i + 24 * j + 21 + dy)- Step (12, 12), RGB(200, 200, 200), B
  3319. Line (24 * k + 796, 112 * i + 24 * j + 22 + dy)- Step (10, 10), RGB(0, 0, 0), B
  3320. End If
  3321. Next k
  3322. Next j
  3323. Next i
  3324. If temp_bgc Then
  3325. Line (510, 238 + dy)- Step (21, 21), temp_bgc, BF
  3326. If temp_border Then
  3327. Line (510, 238 + dy)- Step (21, 21), temp_border, B
  3328. Line (511, 239 + dy)- Step (19, 19), temp_border, B
  3329. End If
  3330. Else
  3331. Line (510, 238 + dy)- Step (21, 21), RGB(30, 30, 50), BF
  3332. If temp_border = 0 Then
  3333. Line (510, 238 + dy)- Step (21, 21), RGB(128, 128, 128), B, &H5555
  3334. Else
  3335. Line (510, 238 + dy)- Step (21, 21), temp_border, B
  3336. Line (511, 239 + dy)- Step (19, 19), temp_border, B
  3337. End If
  3338. End If
  3339. ScreenUnlock
  3340. updatecols = 0
  3341. End If
  3342. GetMouse xm, ym, wm, bm
  3343. akey = InKey
  3344. If STRONG_ANTI_HOG Then Sleep 1
  3345. If bm = 1 Then
  3346. If xm >= 500 And xm <= 755 Then
  3347. Select Case ym
  3348. Case 46 + dy To 65 + dy 'Update border red
  3349. temp_border And= &HFF00FFFF
  3350. r = (xm - 500) ShL 16
  3351. temp_border Or= r
  3352. updatecols = -1
  3353. Case 66 + dy To 85 + dy 'Update border green
  3354. temp_border And= &HFFFF00FF
  3355. g = (xm - 500) ShL 8
  3356. temp_border Or= g
  3357. updatecols = -1
  3358. Case 86 + dy To 105 + dy 'Update border blue
  3359. temp_border And= &HFFFFFF00
  3360. b = (xm - 500)
  3361. temp_border Or= b
  3362. updatecols = -1
  3363. Case 158 + dy To 177 + dy 'Update background red
  3364. temp_bgc And= &HFF00FFFF
  3365. r = (xm - 500) ShL 16
  3366. temp_bgc Or= r
  3367. updatecols = -1
  3368. Case 178 + dy To 197 + dy 'Update background green
  3369. temp_bgc And= &HFFFF00FF
  3370. g = (xm - 500) ShL 8
  3371. temp_bgc Or= g
  3372. updatecols = -1
  3373. Case 198 + dy To 217 + dy 'Update background blue
  3374. temp_bgc And= &HFFFFFF00
  3375. b = (xm - 500)
  3376. temp_bgc Or= b
  3377. updatecols = -1
  3378. End Select
  3379. Elseif xm >= 790 And ym >= 16 + dy And xm < 934 And ym < 112 + dy Then
  3380. temp_border = tempcol((xm - 790) \ 24 + 6 * ((ym - 16 - dy) \ 24), 0)
  3381. updatecols = -1
  3382. ElseIf xm >= 790 And ym >= 332 And xm < 934 And ym < 224 + dy Then
  3383. temp_bgc = tempcol((xm - 790) \ 24 + 6 * ((ym - 128 - dy) \ 24), 1)
  3384. updatecols = -1
  3385. End If
  3386. End If
  3387. v = ManageButtons
  3388. Select Case akey
  3389. Case Chr(255, 72)
  3390. If ky > 0 Then ky -= 1 : updatecols = -1
  3391. usekeyboard = -1
  3392. Case Chr(255, 80)
  3393. If ky < 7 Then ky += 1 : updatecols = -1
  3394. usekeyboard = -1
  3395. Case Chr(255, 77)
  3396. If kx < 5 Then kx += 1 : updatecols = -1
  3397. usekeyboard = -1
  3398. Case Chr(255, 75)
  3399. If kx > 0 Then kx -= 1 : updatecols = -1
  3400. usekeyboard = -1
  3401. Case Chr(13)
  3402. Dim tb As ULong
  3403. If ky >= 4 Then
  3404. tb = tempcol(6 * (ky - 4) + kx, 1)
  3405. If temp_bgc = tb Then
  3406. v = 1
  3407. Else
  3408. temp_bgc = tb
  3409. End If
  3410. Else
  3411. tb = tempcol(6 * ky + kx, 0)
  3412. If temp_border = tb Then
  3413. v = 1
  3414. Else
  3415. temp_border = tb
  3416. End If
  3417. End If
  3418. updatecols = -1
  3419. usekeyboard = -1
  3420. Case "C", "c", Chr(3) : v = 2
  3421. Case Chr(0, 83), Chr(8) : v = 3
  3422. Case Chr(27) : v = 4
  3423. End Select
  3424. If v Then
  3425. Select Case v
  3426. Case 1 'Set colours
  3427. current_bgc = temp_bgc
  3428. current_border = temp_border
  3429. Exit Do
  3430. Case 2 'Clear
  3431. temp_bgc = 0
  3432. temp_border = 0
  3433. updatecols = -1
  3434. Case 3 'Uncolour map
  3435. For j As Byte = 1 To 30
  3436. For i As Byte = 1 To 30
  3437. grid(i, j).border = 0
  3438. grid(i, j).bgc = 0
  3439. Next i
  3440. Next j
  3441. PushUndo
  3442. Exit Do
  3443. Case 4 'Cancel
  3444. Exit Do
  3445. End Select
  3446. End If
  3447. Loop
  3448. buttons = 0
  3449. Do
  3450. GetMouse 0, 0, 0, bm
  3451. Loop Until bm = 0
  3452. DrawTrack
  3453. DrawPanel
  3454. Do : Loop Until Len(InKey) = 0
  3455. End Sub
  3456. Sub Menu_Help
  3457. Dim top As Short, page As Byte = 3
  3458. Dim v As Short, f AS Integer, fline As Short = 1
  3459. Dim maline(1 To 1500) As String, malines As Short = 0
  3460. If FileExists(program_path & "manual.txt") Then
  3461. f = FreeFile
  3462. Open program_path & "manual.txt" For Input As f
  3463. Do Until EoF(f)
  3464. malines += 1
  3465. Line Input #f, maline(malines)
  3466. maline(malines) = Left(maline(malines), 72)
  3467. Loop
  3468. Close f
  3469. End If
  3470. Dim akey As String, idletimer As Double
  3471. idletimer = Timer
  3472. Do
  3473. Select Case page
  3474. Case 1
  3475. MenuBox 30, 38, "Help - Option keys"
  3476. TLeft
  3477. top = ceny
  3478. lefx += 8
  3479. TLeft , "F1 - F12", RGB(180, 180, 80)
  3480. TLeft , " Ctrl-Q", RGB(180, 180, 80)
  3481. TLeft , " Ctrl-E", RGB(180, 180, 80)
  3482. TLeft , " Ctrl-D", RGB(180, 180, 80)
  3483. TLeft , " Ctrl-G", RGB(180, 180, 80)
  3484. TLeft , " Ctrl-R", RGB(180, 180, 80)
  3485. TLeft , " Ctrl-S", RGB(180, 180, 80)
  3486. TLeft , " Ctrl-T", RGB(180, 180, 80)
  3487. TLeft , " Ctrk-K", RGB(180, 180, 80)
  3488. TLeft , " Ctrl-O", RGB(180, 180, 80)
  3489. TLeft , " Ctrl", RGB(180, 180, 80)
  3490. TLeft , " Ctrl-W", RGB(180, 180, 80)
  3491. TLeft , " Ctrl-C", RGB(180, 180, 80)
  3492. TLeft , " Ctrl-X", RGB(180, 180, 80)
  3493. TLeft , " Ctrl-V", RGB(180, 180, 80)
  3494. TLeft , " F", RGB(180, 180, 80)
  3495. TLeft , " Shift-F", RGB(180, 180, 80)
  3496. TLeft , " R", RGB(180, 180, 80)
  3497. TLeft , " Shift-R", RGB(180, 180, 80)
  3498. TLeft , " Ctrl-Z", RGB(180, 180, 80)
  3499. TLeft , " Ctrl-Y", RGB(180, 180, 80)
  3500. TLeft , " U", RGB(180, 180, 80)
  3501. TLeft , " C", RGB(180, 180, 80)
  3502. TLeft , " Arrows", RGB(180, 180, 80)
  3503. TLeft , " Tab", RGB(180, 180, 80)
  3504. TLeft , " Enter", RGB(180, 180, 80)
  3505. TLeft , " Del", RGB(180, 180, 80)
  3506. TLeft , " P", RGB(180, 180, 80)
  3507. TLeft , " \", RGB(180, 180, 80)
  3508. ceny = top
  3509. lefx += 80
  3510. TLeft , "Select palette page (2xF1 for help)", RGB(160, 160, 240)
  3511. TLeft , "Toggle debug mode", RGB(160, 160, 240)
  3512. TLeft , "Allow/disallow conflict generation", RGB(160, 160, 240)
  3513. TLeft , "Toggle conflict-warning display", RGB(160, 160, 240)
  3514. TLeft , "Display/hide grid", RGB(160, 160, 240)
  3515. TLeft , "Redraw track", RGB(160, 160, 240)
  3516. TLeft , "Take a track-shot", RGB(160, 160, 240)
  3517. TLeft , "Toggle terrain affected by paste", RGB(160, 160, 240)
  3518. TLeft , "Toggle track affected by paste", RGB(160, 160, 240)
  3519. TLeft , "Toggle colouring mode", RGB(160, 160, 240)
  3520. TLeft , "Select by dragging with left mouse button", RGB(160, 160, 240)
  3521. TLeft , "Select/Deselect the whole grid", RGB(160, 160, 240)
  3522. TLeft , "Copy selection", RGB(160, 160, 240)
  3523. TLeft , "Cut selection", RGB(160, 160, 240)
  3524. TLeft , "Paste clipboard", RGB(160, 160, 240)
  3525. TLeft , "Flip horizontally", RGB(160, 160, 240)
  3526. TLeft , "Flip vertically", RGB(160, 160, 240)
  3527. TLeft , "Rotate clockwise", RGB(160, 160, 240)
  3528. TLeft , "Rotate counter-clockwise", RGB(160, 160, 240)
  3529. TLeft , "Undo", RGB(160, 160, 240)
  3530. TLeft , "Redo", RGB(160, 160, 240)
  3531. TLeft , "Link tiles at pointer/keyboard cursor", RGB(160, 160, 240)
  3532. TLeft , "Check track for errors", RGB(160, 160, 240)
  3533. TLeft , "Move keyboard cursor", RGB(160, 160, 240)
  3534. TLeft , "Switch between the grid and the palette", RGB(160, 160, 240)
  3535. TLeft , "Paste current element/Create closed-circuit", RGB(160, 160, 240)
  3536. TLeft , "Delete at keyboard cursor or selection", RGB(160, 160, 240)
  3537. TLeft , "Pick element at keyboard cursor position", RGB(160, 160, 240)
  3538. TLeft , "In manual mode, select element by hex typing", RGB(160, 160, 240)
  3539. TLeft
  3540. TLeft
  3541. buttons = 0
  3542. StackButton " User Manual ", 3
  3543. StackButton " Tile Shorcuts ", 2
  3544. StackButton " Back ", 1
  3545. EndOfButtonStack
  3546. Dim As Integer xm, ym, wm, bm
  3547. Do
  3548. v = ManageButtons
  3549. GetMouse xm, ym, wm, bm
  3550. akey = InKey
  3551. 'This is to prevent the program from hogging the CPU
  3552. If xm <> -1 Or Len(akey) <> 0 Then idletimer = Timer
  3553. If Timer > idletimer + 1 Then Sleep 500
  3554. Select Case akey
  3555. Case Chr(27) : v = 1 : Exit Do
  3556. Case Chr(13) : v = 2 : Exit Do
  3557. End Select
  3558. Loop Until v <> 0
  3559. buttons = 0
  3560. If v = 1 Then page = -1 Else page = v
  3561. Case 2
  3562. MenuBox 30, 29, "Help - Tile shortcuts"
  3563. TLeft
  3564. top = ceny
  3565. lefx += 8
  3566. TLeft , " Space", RGB(180, 180, 80)
  3567. TLeft , " A", RGB(180, 180, 80)
  3568. TLeft , " B", RGB(180, 180, 80)
  3569. TLeft , " D", RGB(180, 180, 80)
  3570. TLeft , " E", RGB(180, 180, 80)
  3571. TLeft , " G", RGB(180, 180, 80)
  3572. TLeft , " H", RGB(180, 180, 80)
  3573. TLeft , " I", RGB(180, 180, 80)
  3574. TLeft , " J", RGB(180, 180, 80)
  3575. TLeft , " K", RGB(180, 180, 80)
  3576. TLeft , " L", RGB(180, 180, 80)
  3577. TLeft , " M", RGB(180, 180, 80)
  3578. TLeft , " N", RGB(180, 180, 80)
  3579. TLeft , " O", RGB(180, 180, 80)
  3580. TLeft , " Q", RGB(180, 180, 80)
  3581. TLeft , " S", RGB(180, 180, 80)
  3582. TLeft , " T", RGB(180, 180, 80)
  3583. TLeft , " V", RGB(180, 180, 80)
  3584. TLeft , " W", RGB(180, 180, 80)
  3585. TLeft , " X, Y, Z", RGB(180, 180, 80)
  3586. ceny = top
  3587. lefx += 80
  3588. TLeft , "Find element by name", RGB(160, 160, 240)
  3589. TLeft , "Banked road", RGB(160, 160, 240)
  3590. TLeft , "Boulevard (highway)", RGB(160, 160, 240)
  3591. TLeft , "Split (detour)", RGB(160, 160, 240)
  3592. TLeft , "Elevated road", RGB(160, 160, 240)
  3593. TLeft , "Spin (cork up/down)", RGB(160, 160, 240)
  3594. TLeft , "Chicane", RGB(160, 160, 240)
  3595. TLeft , "Pipe", RGB(160, 160, 240)
  3596. TLeft , "Ramp (jump)", RGB(160, 160, 240)
  3597. TLeft , "Crossroad", RGB(160, 160, 240)
  3598. TLeft , "Loop", RGB(160, 160, 240)
  3599. TLeft , "Change material", RGB(160, 160, 240)
  3600. TLeft , "Scenery", RGB(160, 160, 240)
  3601. TLeft , "Start/Finish line", RGB(160, 160, 240)
  3602. TLeft , "Corner", RGB(160, 160, 240)
  3603. TLeft , "Straightway", RGB(160, 160, 240)
  3604. TLeft , "Tunnel and slalom", RGB(160, 160, 240)
  3605. TLeft , "Transitions", RGB(160, 160, 240)
  3606. TLeft , "Corkscrew", RGB(160, 160, 240)
  3607. TLeft , "Side, bottom and corner fillers", RGB(160, 160, 240)
  3608. TLeft
  3609. TLeft
  3610. buttons = 0
  3611. StackButton " User Manual ", 3
  3612. StackButton " Option Keys ", 2
  3613. StackButton " Back ", 1
  3614. EndOfButtonStack
  3615. Dim As Integer xm, ym, wm, bm
  3616. Do
  3617. v = ManageButtons
  3618. GetMouse xm, ym, wm, bm
  3619. akey = InKey
  3620. 'This is to prevent the program from hogging the CPU
  3621. If xm <> -1 Or Len(akey) <> 0 Then idletimer = Timer
  3622. If Timer > idletimer + 1 Then Sleep 500
  3623. Select Case akey
  3624. Case Chr(27) : v = 1 : Exit Do
  3625. Case Chr(13) : v = 3 : Exit Do
  3626. End Select
  3627. Loop Until v <> 0
  3628. buttons = 0
  3629. If v = 1 Then
  3630. page = -1
  3631. ElseIf v = 2 Then
  3632. page = 1
  3633. Else
  3634. page = 3
  3635. End If
  3636. Case 3
  3637. Dim As Integer w, exw, x, y, b
  3638. Dim drlines As Short = 33
  3639. Dim exfline As Short = 0, s As String, n As Short
  3640. MenuBox 38, 40, "Help - User Manual"
  3641. top = ceny
  3642. ceny += 512
  3643. TLeft
  3644. TLeft
  3645. buttons = 0
  3646. StackButton " Tile Shortcuts ", 2
  3647. StackButton " Option Keys ", 1
  3648. StackButton " Back ", 3
  3649. EndOfButtonStack
  3650. GetMouse x, y, w
  3651. exw = w
  3652. Do
  3653. If fline <> exfline Then
  3654. ceny = top
  3655. Line (xoffs + 40, top)- Step (73 * 8, 33 * 16), RGB(30, 30, 50), BF
  3656. For i As Short = 0 To drlines - 1
  3657. s = Trim(maline(fline + i))
  3658. n = InStr(s, ".")
  3659. If n > 1 And n <= 4 And ValInt(s) > 0 Then
  3660. TLeft , maline(fline + i), RGB(180, 180, 80)
  3661. Else
  3662. TLeft , maline(fline + i), RGB(160, 160, 240)
  3663. End If
  3664. Next i
  3665. exfline = fline
  3666. End If
  3667. v = ManageButtons
  3668. GetMouse x, y, w, b
  3669. akey = InKey
  3670. If w <> - 1 AndAlso w <> exw Then
  3671. If w < exw Then akey = Chr(255, 80) Else akey = Chr(255, 72)
  3672. exw = w
  3673. End If
  3674. If b = 1 AndAlso x > xoffs + 330 - 80 _
  3675. AndAlso x < xoffs + 300 + 80 AndAlso y >= top Then
  3676. Dim m As Short
  3677. m = (y - top) \ 16 + fline
  3678. If m <= malines Then
  3679. s = Trim(maline(m))
  3680. n = InStr(s, ".")
  3681. If n > 0 And n <= 3 And ValInt(s) Then
  3682. For i As Short = 1 To malines
  3683. If Trim(maline(i)) = "." & ValInt(s) & "." Then
  3684. fline = i
  3685. Exit For
  3686. End If
  3687. Next i
  3688. If fline + drlines - 1 > malines Then fline = malines - drlines + 1
  3689. End If
  3690. End If
  3691. End If
  3692. 'This is to prevent the program from hogging the CPU
  3693. If x <> -1 Or Len(akey) <> 0 Then idletimer = Timer
  3694. If Timer > idletimer + 1 Then Sleep 500
  3695. Select Case akey
  3696. Case Chr(255, 72)
  3697. If fline > 1 Then fline -= 1
  3698. Case Chr(255, 80)
  3699. If fline + drlines - 1 < malines Then fline += 1
  3700. Case Chr(255, 73)
  3701. fline -= 30
  3702. If fline < 1 Then fline = 1
  3703. Case Chr(255, 81)
  3704. fline += 30
  3705. If fline + drlines - 1 > malines Then fline = malines - drlines + 1
  3706. Case Chr(255, 71)
  3707. fline = 1
  3708. Case Chr(255, 79)
  3709. fline = malines - drlines + 1
  3710. Case Chr(27) : v = 3 : Exit Do
  3711. Case Chr(13) : v = 1 : Exit Do
  3712. End Select
  3713. Loop Until v <> 0
  3714. buttons = 0
  3715. If v = 3 Then page = -1 Else page = v
  3716. End Select
  3717. Dim bm As Integer
  3718. Do
  3719. GetMouse 0, 0, 0, bm
  3720. Loop Until bm = 0
  3721. Do : Loop Until Len(InKey) = 0
  3722. DrawTrack
  3723. Loop Until page = -1
  3724. End Sub
  3725. Sub Menu_License
  3726. Dim As Integer xm, ym, wm, bm
  3727. Dim v As Short
  3728. MenuBox 27, 32, "Bliss " + THISVERSION '+ Chr(225)
  3729. TCentre , "Track editor for Stunts v1.0 and v1.1", RGB(160, 160, 240)
  3730. TCentre , "Copyright (c) 2016-" & Left(__DATE_ISO__, 4) & " - Lucas Pedrosa", RGB(160, 160, 240)
  3731. TCentre
  3732. TCentre , "This program comes with ABSOLUTELY NO WARRANTY.", RGB(160, 160, 240)
  3733. TCentre , "This is free software and you are welcome", RGB(160, 160, 240)
  3734. TCentre , "to redistribute it under the conditions of the", RGB(160, 160, 240)
  3735. TCentre , "GNU GPLv3 license. For more information on this", RGB(160, 160, 240)
  3736. TCentre , "license, read the file license.txt that comes", RGB(160, 160, 240)
  3737. TCentre , "included or visit http://www.gnu.org/licenses/", RGB(160, 160, 240)
  3738. TCentre
  3739. TCentre , "Thank you for using my editor!!", RGB(160, 160, 240)
  3740. TCentre , "Bliss is dedicated especially to the", RGB(160, 160, 240)
  3741. TCentre , "Stunts racing community, to the tournament", RGB(160, 160, 240)
  3742. TCentre , "organisers and to the people of DSI, creators", RGB(160, 160, 240)
  3743. TCentre , "of Stunts, a magnificent game.", RGB(160, 160, 240)
  3744. TCentre , "Special thanks go to Duplode, for the amazing", RGB(160, 160, 240)
  3745. TCentre , "feedback and effort in beta-testing during the", RGB(160, 160, 240)
  3746. TCentre , "different stages of development.", RGB(160, 160, 240)
  3747. TCentre
  3748. TCentre
  3749. TCentre , "Contact:", RGB(160, 160, 240)
  3750. TCentre , "xlucas@mailo.com", RGB(50, 200, 240)
  3751. TCentre
  3752. TCentre , "Website:", RGB(160, 160, 240)
  3753. TCentre , "http://www.raceforkicks.com/bliss", RGB(50, 200, 240)
  3754. TCentre
  3755. buttons = 0
  3756. StackButton " Continue ", 1
  3757. EndOfButtonStack
  3758. Dim idletimer as Double, akey As String
  3759. idletimer = Timer
  3760. Do
  3761. v = ManageButtons
  3762. akey = InKey
  3763. 'This is to prevent the program from hogging the CPU
  3764. If xm <> -1 Or Len(akey) <> 0 Then idletimer = Timer
  3765. If Timer > idletimer + 1 Then Sleep 500
  3766. Loop Until v = 1 Or akey <> ""
  3767. buttons = 0
  3768. Do
  3769. GetMouse xm, ym, wm, bm
  3770. Loop Until bm = 0
  3771. DrawTrack
  3772. End Sub
  3773. Sub Menu_SaveTrack
  3774. Dim v As Short
  3775. Dim As Integer xm, ym, wm, bm
  3776. Dim As Short bx1, bx2, by1, by2
  3777. Dim s As String, selected_track As String, akey As String
  3778. Dim olds As String
  3779. Dim sel As SelectorType
  3780. buttons = 0
  3781. MenuBox 28, 28, "Save Track"
  3782. bx1 = lefx + 8 : by1 = ceny : bx2 = lefx + 407 : by2 = ceny + 31
  3783. DrawBox bx1, by1, bx2, by2
  3784. InitFiles "trk;rpl", lefx + 8, ceny + 40, lefx + 407, ceny + 351
  3785. cenx -= 16 : ceny += 40
  3786. sel.redraw = -1
  3787. Select Case thisfileformat
  3788. Case FORMAT_RAW : sel.current = 4 'On request by Dreadnaut
  3789. Case FORMAT_COMBINED : sel.current = 1
  3790. Case FORMAT_BINARY_SPLIT : sel.current = 2
  3791. Case FORMAT_TEXT_SPLIT : sel.current = 3
  3792. Case Else 'Just in case I add a format or something
  3793. sel.current = 1
  3794. End Select
  3795. sel.opt(1) = "One file"
  3796. sel.opt(2) = "Binary split"
  3797. sel.opt(3) = "Text split"
  3798. sel.opt(4) = "Raw (no metadata)"
  3799. sel.options = 4
  3800. sel.y1 = ceny
  3801. sel.y2 = sel.y1 + 31
  3802. sel.x1 = cenx - 24 * 16
  3803. sel.x2 = sel.x1 + 160
  3804. StackButton " Save ", 1, -1
  3805. StackButton " Cancel ", 2, -1
  3806. EndOfButtonStack
  3807. selected_track = track_file
  3808. stringer.init = -1
  3809. stringer.maxlength = 40
  3810. stringer.fileonly = -1
  3811. stringer.x = bx1 + 16
  3812. stringer.y = by1 + 8
  3813. stringer.background = RGB(30, 30, 50)
  3814. #ifdef __FB_LINUX__ 'Empty keyboard buffer
  3815. For i As Byte = 1 To 32
  3816. akey = LinKey
  3817. Next i
  3818. #endif
  3819. olds = ""
  3820. Do
  3821. v = ManageButtons
  3822. ManageSelector sel
  3823. s = selected_track
  3824. akey = ManageString(selected_track)
  3825. If s <> selected_track And Len(selected_track) <> 0 Then akey = Chr(1) + selected_track
  3826. s = ManageFiles(akey)
  3827. If STRONG_ANTI_HOG Then Sleep 1
  3828. Select Case akey
  3829. Case Chr(13)
  3830. v = 1
  3831. Do : Loop Until MultiKey(&H1D) = 0
  3832. Case Chr(27)
  3833. v = 2
  3834. Do : Loop Until MultiKey(1) = 0
  3835. End Select
  3836. If Len(s) <> 0 And olds <> s Then
  3837. selected_track = s
  3838. stringer.cursor_pos = Len(s)
  3839. ScreenLock
  3840. DrawBox bx1, by1, bx2, by2
  3841. Draw String (bx1 + 16, by1 + 8), s + Space(30 - Len(s)), RGB(160, 160, 240)
  3842. ScreenUnlock
  3843. olds = s
  3844. End If
  3845. Loop Until (v = 1 And Len(selected_track) <> 0) Or v = 2
  3846. buttons = 0
  3847. #ifdef __FB_LINUX__
  3848. Do : Loop Until LinKey = ""
  3849. #endif
  3850. Do : Loop Until InKey = ""
  3851. Do
  3852. GetMouse xm, ym, wm, bm
  3853. Loop Until bm = 0
  3854. If v = 1 And Len(selected_track) <> 0 Then
  3855. If InStr(selected_track, ".") = 0 Then selected_track = selected_track + ".trk"
  3856. If FileExists(track_path + selected_track) Then
  3857. DrawTrack
  3858. MenuBox 28, 10, "Warning!"
  3859. ceny += 16
  3860. If sel.current = 4 Then
  3861. TCentre , "An image with that name already exists.", RGB(200, 200, 240)
  3862. Else
  3863. TCentre , "A track with that name already exists.", RGB(200, 200, 240)
  3864. End If
  3865. TCentre , "Are you sure you want to OVERWRITE it?", RGB(200, 200, 240)
  3866. ceny += 16
  3867. buttons = 0
  3868. StackButton " SAVE ", 1, , 50
  3869. StackButton " Cancel ", 2, , 50
  3870. EndOfButtonStack
  3871. Do
  3872. v = ManageButtons
  3873. akey = InKey
  3874. If STRONG_ANTI_HOG Then Sleep 1
  3875. Loop Until v <> 0 Or akey <> ""
  3876. buttons = 0
  3877. Do
  3878. GetMouse xm, ym, wm, bm
  3879. Loop Until bm = 0
  3880. If v = 1 Then
  3881. If sel.current = 1 Then
  3882. thisfileformat = FORMAT_COMBINED
  3883. ElseIf sel.current = 2 Then
  3884. thisfileformat = FORMAT_BINARY_SPLIT
  3885. ElseIf sel.current = 3 Then
  3886. thisfileformat = FORMAT_TEXT_SPLIT
  3887. Else
  3888. thisfileformat = FORMAT_RAW 'Do not save meta-data
  3889. End If
  3890. SaveTrack track_path + selected_track
  3891. track_file = selected_track
  3892. End If
  3893. Else
  3894. If Open(track_path + selected_track For Output As 101) Then
  3895. DrawTrack
  3896. buttons = 0
  3897. Error_Message "Invalid track file name"
  3898. Else
  3899. Close 101
  3900. If Right(LCase(selected_track), 4) = ".rpl" Then
  3901. DrawTrack
  3902. buttons = 0
  3903. Error_Message "Can't write to replay if it doesn't exist"
  3904. Else
  3905. If sel.current = 1 Then
  3906. thisfileformat = FORMAT_COMBINED
  3907. ElseIf sel.current = 2 Then
  3908. thisfileformat = FORMAT_BINARY_SPLIT
  3909. ElseIf sel.current = 3 Then
  3910. thisfileformat = FORMAT_TEXT_SPLIT
  3911. Else
  3912. thisfileformat = FORMAT_RAW 'Do not save meta-data
  3913. End If
  3914. SaveTrack track_path + selected_track
  3915. track_file = selected_track
  3916. End If
  3917. End If
  3918. End If
  3919. End If
  3920. DrawTrack
  3921. DrawPanel
  3922. End Sub
  3923. Sub LinkTiles
  3924. Dim As Short xr, yr, i, j, n, v
  3925. Dim As Integer xm, ym, wm, bm
  3926. Dim connector(0 To 3) As Byte, connectors As Byte
  3927. GetMouse xm, ym, wm, bm
  3928. If drawkeyboardcursor Then
  3929. xr = xcursor
  3930. yr = ycursor
  3931. ElseIf xm >= xoffs And ym >= yoffs Then
  3932. xr = (xm - xoffs) \ bigwidth + 1
  3933. yr = (ym - yoffs) \ 22 + 1
  3934. If xr > 30 Or yr > 30 Then Exit Sub
  3935. End If
  3936. v = GetParent(xr, yr)
  3937. 'First try to find a 1x1 tile
  3938. If yr > 1 Then
  3939. connector(0) = tr(GetParent(xr, yr - 1)).ctype(2)
  3940. If connector(0) Then connectors += 1
  3941. End If
  3942. If xr < 30 Then
  3943. connector(1) = tr(GetParent(xr + 1, yr)).ctype(3)
  3944. If connector(1) Then connectors += 1
  3945. End If
  3946. If yr < 30 Then
  3947. connector(2) = tr(GetParent(xr, yr + 1)).ctype(0)
  3948. If connector(2) Then connectors += 1
  3949. End If
  3950. If xr > 1 Then
  3951. connector(3) = tr(GetParent(xr - 1, yr)).ctype(1)
  3952. If connector(3) Then connectors += 1
  3953. End If
  3954. If connectors >= 2 Then
  3955. For i = v + 1 To v + 256
  3956. n = i Mod 256
  3957. If tr(n).w = 1 And tr(n).h = 1 Then
  3958. If tr(n).ctype(0) = connector(0) And tr(n).ctype(1) = connector(1) _
  3959. And tr(n).ctype(2) = connector(2) And tr(n).ctype(3) = connector(3) Then
  3960. PushUndo
  3961. SetTrack xr, yr, n
  3962. Exit Sub
  3963. End If
  3964. End If
  3965. Next i
  3966. End If
  3967. End Sub
  3968. #ifdef __FB_LINUX__
  3969. Sub LKinitialise
  3970. ScreenControl FB.GET_WINDOW_HANDLE, LKwindow
  3971. LKdisp = XOpenDisplay(0)
  3972. XSelectInput LKdisp, LKwindow, KeyPressMask Or KeyReleaseMask
  3973. End Sub
  3974. Function Linkey As String
  3975. Dim tempkey As Long 'KeySym type seems to be a Long
  3976. If Not LKinitialised Then
  3977. LKinitialise
  3978. LKinitialised = -1
  3979. End If
  3980. If XPending(LKdisp) Then
  3981. XNextEvent LKdisp, @LKevent
  3982. If LKevent.type = KeyPress Then
  3983. 'XLookupString fills only as many bytes as necessary, so
  3984. 'the string has to be zeroed to prevent trailing bytes from
  3985. 'the last query to populate in the next if shorter
  3986. LKstring = String(25, 0)
  3987. XLookupString @LKevent.xkey, @LKstring, 25, @LKsym, 0
  3988. tempkey = XLookupKeysym(@LKevent.xkey, 0)
  3989. 'If tempkey = XK_Alt_L Or tempkey = XK_Alt_R Then LKaltpressed = -1
  3990. If Len(LKstring) Then
  3991. Return LKstring
  3992. Else
  3993. Return Chr(0) & MkL(tempkey)
  3994. End If
  3995. End If
  3996. Else
  3997. Return ""
  3998. End If
  3999. End Function
  4000. #endif
  4001. Sub LoadConfiguration
  4002. Dim s As String, n As UShort
  4003. Dim As String param, value
  4004. default_author = "Anonymous"
  4005. imageformat = "tga"
  4006. Open program_path + "bliss.cfg" For Input As 100
  4007. Do While Not EOF(100)
  4008. Line Input #100, s
  4009. s = Trim(s)
  4010. n = InStr(s, ";")
  4011. If n Then s = Left(s, n - 1)
  4012. n = InStr(s, "=")
  4013. If n Then
  4014. param = LCase(Trim(Left(s, n - 1)))
  4015. value = Trim(Mid(s, n + 1))
  4016. Select Case param
  4017. Case "track", "tracks"
  4018. track_path = value
  4019. If Right(track_path, 1) <> "/" And Right(track_path, 1) <> "\" Then
  4020. #ifdef __FB_LINUX__
  4021. track_path = track_path + "/"
  4022. #else
  4023. track_path = track_path + "\"
  4024. #endif
  4025. End If
  4026. If dirlinks < 10 Then
  4027. dirlinks += 1
  4028. dirlink(dirlinks).text = "Tracks"
  4029. dirlink(dirlinks).directory = track_path
  4030. End If
  4031. Case "dirlink"
  4032. Dim mysplit As UByte
  4033. If dirlinks < 10 Then
  4034. dirlinks += 1
  4035. mysplit = InStr(value, ":")
  4036. If mysplit Then
  4037. dirlink(dirlinks).text = Trim(Left(value, mysplit - 1))
  4038. dirlink(dirlinks).directory = Trim(Mid(value, mysplit + 1))
  4039. Else
  4040. dirlink(dirlinks).text = Trim(value)
  4041. dirlink(dirlinks).directory = Trim(value)
  4042. End If
  4043. If Right(dirlink(dirlinks).directory, 1) <> "/" And Right(dirlink(dirlinks).directory, 1) <> "\" Then
  4044. #ifdef __FB_LINUX__
  4045. dirlink(dirlinks).directory &= "/"
  4046. #else
  4047. dirlink(dirlinks).directory &= "\"
  4048. #endif
  4049. End If
  4050. End If
  4051. Case "stunts"
  4052. If dirlinks < 10 Then
  4053. dirlinks += 1
  4054. dirlink(dirlinks).text = "Stunts"
  4055. dirlink(dirlinks).directory = Trim(value)
  4056. End If
  4057. If Right(dirlink(dirlinks).directory, 1) <> "/" And Right(dirlink(dirlinks).directory, 1) <> "\" Then
  4058. #ifdef __FB_LINUX__
  4059. dirlink(dirlinks).directory &= "/"
  4060. #else
  4061. dirlink(dirlinks).directory &= "\"
  4062. #endif
  4063. End If
  4064. Case "superposition", "superpositions"
  4065. If LCase(value) = "true" Or LCase(value) = "yes" Or LCase(value) = "on" Then
  4066. allow_errors = -1
  4067. Else
  4068. allow_errors = 0
  4069. End If
  4070. Case "warning", "warnings"
  4071. If LCase(value) = "true" Or LCase(value) = "yes" Or LCase(value) = "on" Then
  4072. show_errors = -1
  4073. Else
  4074. show_errors = 0
  4075. End If
  4076. Case "grid"
  4077. If LCase(value) = "true" Or LCase(value) = "yes" Or LCase(value) = "on" Then
  4078. show_grid = -1
  4079. Else
  4080. show_grid = 0
  4081. End If
  4082. Case "format"
  4083. Select Case LCase(Trim(value))
  4084. Case "stunts", "none" : default_format = FORMAT_RAW
  4085. Case "tb", "trackblaster" : default_format = FORMAT_RAW
  4086. Case "bliss", "overlay", "combined"
  4087. default_format = FORMAT_COMBINED
  4088. Case "companion", "split", "binary"
  4089. default_format = FORMAT_BINARY_SPLIT
  4090. Case "text", "text-split", "human", "human-readable"
  4091. default_format = FORMAT_TEXT_SPLIT
  4092. End Select
  4093. Case "author"
  4094. default_author = Trim(value)
  4095. Case "calibration", "speed" 'Racer speed weigh value
  4096. racer_weigh = Val(value)
  4097. If racer_weigh < 4 Then racer_weigh = 4
  4098. If racer_weigh > 20 Then racer_weigh = 20
  4099. Case "imageformat"
  4100. value = LCase(Trim(value))
  4101. If Left(value, 1) = "." Then value = Mid(value, 2)
  4102. Select Case value
  4103. Case "bmp", "gif", "pcx", "jpg", "png"
  4104. imageformat = value
  4105. Case "jpeg"
  4106. imageformat = "jpg"
  4107. Case Else
  4108. imageformat = "tga"
  4109. End Select
  4110. Case "curl"
  4111. If LCase(value) = "true" Or LCase(value) = "yes" Or LCase(value) = "on" Then
  4112. use_curl = -1
  4113. Else
  4114. use_curl = 0
  4115. End If
  4116. End Select
  4117. End If
  4118. Loop
  4119. Close 100
  4120. If FileExists(program_path + "handicap.cfg") Then
  4121. Open program_path + "handicap.cfg" For Input As 100
  4122. Do While Not EOF(100)
  4123. Line Input #100, s
  4124. s = Trim(s)
  4125. If Len(s) <> 0 And Left(s, 1) <> ";" Then
  4126. cars += 1
  4127. If Mid(s, 5, 1) = ";" Then
  4128. car(cars).id = Left(s, 4)
  4129. s = Mid(s, 6)
  4130. Else
  4131. car(cars).id = "****"
  4132. End If
  4133. n = InStr(s, ";")
  4134. If n = 0 Then
  4135. cars -= 1
  4136. Else
  4137. car(cars).cname = Trim(Left(s, n - 1))
  4138. If Len(car(cars).cname) = 0 Then car(cars).cname = "Unknown"
  4139. car(cars).handicap = Val(Mid(s, n + 1))
  4140. If car(cars).handicap < 0.005 Or car(cars).handicap > 5 Then _
  4141. car(cars).handicap = 1.5
  4142. End If
  4143. End If
  4144. If car(cars).handicap = 1 Then activecar = cars
  4145. If cars = MAXCARS Then Exit Do
  4146. Loop
  4147. Close 100
  4148. If activecar = 0 Then activecar = 1
  4149. Else
  4150. 'No handicap file. Only one car: Porsche March Indy
  4151. cars = 1 : activecar = 1
  4152. car(1).id = "PMIN" : car(1).cname = "Porsche March Indy"
  4153. car(1).handicap = 1
  4154. End If
  4155. End Sub
  4156. Sub LoadFont (fontfile As String)
  4157. Dim As Byte x, y
  4158. Dim f As String, b As UByte, i As Short
  4159. Dim ff As String
  4160. ff = fontfile
  4161. If InStr(ff, ".") = 0 Then ff &= ".fnt"
  4162. Open program_path + ff For Binary Access Read As 1
  4163. f = Space(Lof(1))
  4164. Get #1, , f
  4165. Close 1
  4166. font = ImageCreate(8, 16 * 256)
  4167. mask = ImageCreate(8, 16 * 256)
  4168. Line font, (0, 0)-(15, 16 * 256 -1), RGB(0, 0, 0), BF
  4169. Line mask, (0, 0)-(15, 16 * 256 -1), RGB(255, 0, 255), BF
  4170. For i = 0 To 255
  4171. For y = 0 To 15
  4172. b = Asc(Mid(f, 16 * i + y, 1))
  4173. For x = 0 To 7
  4174. If b And 2 ^ x Then
  4175. PSet font, (x, 16 * i + y), RGB(255, 255, 255)
  4176. PSet mask, (x, 16 * i + y), RGB(0, 0, 0)
  4177. End If
  4178. Next x
  4179. Next y
  4180. Next i
  4181. End Sub
  4182. Sub LoadGraphics
  4183. Dim gf As String
  4184. Dim f As Integer
  4185. Dim As UShort gwidth, gheight, x, y, i
  4186. Dim As UByte r, g, b, a, count
  4187. Dim rle As Byte
  4188. Dim col As ULong
  4189. Dim buffer As UByte Ptr, fp As ULong
  4190. f = FreeFile
  4191. gf = big_graphics_file
  4192. If InStr(gf, ".") = 0 Then gf = gf + ".tga"
  4193. Open program_path + gf For Binary Access Read As f
  4194. Get #f, 13, gwidth
  4195. Get #f, , gheight
  4196. bigicons = ImageCreate(gwidth, gheight)
  4197. buffer = Allocate(LOF(f) + 1024)
  4198. Get #f, 1, *buffer, LOF(f)
  4199. If dosbox Then
  4200. fp = 18
  4201. x = 0 : y = 0
  4202. Do
  4203. count = buffer[fp]
  4204. rle = count And 128
  4205. count = count And 127
  4206. fp += 1
  4207. If rle Then
  4208. b = buffer[fp]
  4209. g = buffer[fp + 1]
  4210. r = buffer[fp + 2]
  4211. a = buffer[fp + 3]
  4212. fp += 4
  4213. For i = 0 To count
  4214. If a >= 128 Then
  4215. PSet bigicons, (x, y), RGB(r, g, b)
  4216. Else
  4217. PSet bigicons, (x, y), RGB(255, 0, 255)
  4218. End If
  4219. x += 1
  4220. If x = gwidth Then x = 0 : y += 1
  4221. Next i
  4222. Else
  4223. For i = 0 To count
  4224. b = buffer[fp]
  4225. g = buffer[fp + 1]
  4226. r = buffer[fp + 2]
  4227. a = buffer[fp + 3]
  4228. fp += 4
  4229. If a >= 128 Then
  4230. PSet bigicons, (x, y), RGB(r, g, b)
  4231. Else
  4232. PSet bigicons, (x, y), RGB(255, 0, 255)
  4233. End If
  4234. x += 1
  4235. If x = gwidth Then x = 0 : y += 1
  4236. Next i
  4237. End If
  4238. Loop Until y >= gheight
  4239. Else
  4240. fp = 18
  4241. x = 0 : y = 0
  4242. Do
  4243. count = buffer[fp]
  4244. rle = count And 128
  4245. count = count And 127
  4246. fp += 1
  4247. If rle Then
  4248. b = buffer[fp]
  4249. g = buffer[fp + 1]
  4250. r = buffer[fp + 2]
  4251. a = buffer[fp + 3]
  4252. fp += 4
  4253. For i = 0 To count
  4254. PSet bigicons, (x, y), RGBA(r, g, b, a)
  4255. x += 1
  4256. If x = gwidth Then x = 0 : y += 1
  4257. Next i
  4258. Else
  4259. For i = 0 To count
  4260. b = buffer[fp]
  4261. g = buffer[fp + 1]
  4262. r = buffer[fp + 2]
  4263. a = buffer[fp + 3]
  4264. fp += 4
  4265. PSet bigicons, (x, y), RGBA(r, g, b, a)
  4266. x += 1
  4267. If x = gwidth Then x = 0 : y += 1
  4268. Next i
  4269. End If
  4270. Loop Until y >= gheight
  4271. End If
  4272. Close f
  4273. Deallocate buffer
  4274. End Sub
  4275. Sub LoadMetaData(filenumber As Short = 0, content As String = "")
  4276. Dim s As String, l As Short
  4277. Dim c As String
  4278. If Len(content) Then
  4279. c = content
  4280. Else
  4281. l = LOF(filenumber) - Seek(filenumber) + 1
  4282. c = Space(l)
  4283. Get #filenumber, , c
  4284. End If
  4285. 'Initialise meta-data
  4286. meta.title = ""
  4287. meta.author = ""
  4288. meta.comment = ""
  4289. meta.championship = ""
  4290. meta.cyear = 0
  4291. meta.cmonth = 0
  4292. meta.cday = 0
  4293. meta.editing_time = -1
  4294. started_editing = Timer
  4295. 'Read meta-data
  4296. s = Left(c, 8)
  4297. If Left(s, 4) = "smdf" Then
  4298. thisfileformat = FORMAT_BINARY_SPLIT
  4299. c = Mid(c, 9) 'Skip obsolete track hash
  4300. Do While Len(c)
  4301. s = Left(c, 4) : l = CvShort(Mid(c, 5, 2))
  4302. c = Mid(c, 7)
  4303. 'Field length has to be positive
  4304. If l <= 0 Then Exit Do
  4305. Select Case s
  4306. Case "Titl"
  4307. meta.title = Left(c, l)
  4308. c = Mid(c, l + 1)
  4309. Case "Autr"
  4310. meta.author = Left(c, l)
  4311. c = Mid(c, l + 1)
  4312. Case "Comm"
  4313. meta.comment = Left(c, l)
  4314. c = Mid(c, l + 1)
  4315. Case "Chmp"
  4316. meta.championship = Left(c, l)
  4317. c = Mid(c, l + 1)
  4318. Case "Date"
  4319. If l <> 4 Then Exit Do
  4320. meta.cyear = CvShort(Left(c, 2))
  4321. meta.cmonth = ASC(Mid(c, 3, 1))
  4322. meta.cday = ASC(Mid(c, 4, 1))
  4323. c = Mid(c, 5)
  4324. Case "Tool"
  4325. l -= 4
  4326. If l <= 0 Then Exit Do
  4327. meta.tool = Left(c, l) : c = Mid(c, l + 1)
  4328. meta.toolversion = CvL(Left(c, 4))
  4329. c = Mid(c, 5)
  4330. Case "Etim"
  4331. If l <> 4 Then Exit Do
  4332. meta.editing_time = CvL(Left(c, 4))
  4333. c = Mid(c, 5)
  4334. Case "Colr"
  4335. Dim t As String, last_bgc As ULong, last_border As ULong
  4336. Dim As UByte i, j
  4337. Dim pending As UByte
  4338. t = Left(c, l)
  4339. c = Mid(c, l + 1)
  4340. i = 1 : j = 1 : pending = 0
  4341. Do While Len(t) <> 0 Or pending
  4342. If pending = 0 Then
  4343. pending = ASC(Left(t, 1))
  4344. last_border = CvL(ConvertColour(Mid(t, 2, 2)))
  4345. last_bgc = CvL(ConvertColour(Mid(t, 4, 2)))
  4346. t = Mid(t, 6)
  4347. End If
  4348. grid(i, j).border = last_border
  4349. grid(i, j).bgc = last_bgc
  4350. pending -= 1
  4351. i += 1
  4352. If i = 31 Then i = 1 : j += 1
  4353. If j = 31 Then Exit Do
  4354. Loop
  4355. Case Else
  4356. c = Mid(c, l + 1)
  4357. End Select
  4358. Loop
  4359. ElseIf Left(s, 7) = "[smdf]" + Chr(13) Or Left(s, 7) = "[smdf]" + Chr(10) Then
  4360. thisfileformat = FORMAT_TEXT_SPLIT
  4361. If Right(s, 1) = Chr(10) Or Right(s, 1) = Chr(13) Then
  4362. 'Using CRLF or LFCR for end of line. Skip both characters
  4363. c = Mid(c, 9)
  4364. Else
  4365. 'Using either CR or LF for end of line. Skip it
  4366. c = Mid(c, 8)
  4367. End If
  4368. 'Make sure the string ends with an end-of-line character
  4369. If Right(c, 1) <> Chr(13) And Right(c, 1) <> Chr(10) Then c &= Chr(10)
  4370. Dim titi As Double
  4371. s = ""
  4372. Do While Len(c)
  4373. If Left(c, 1) = Chr(13) Or Left(c, 1) = Chr(10) Then
  4374. 'EOL character. Process the accumulated string if any
  4375. Dim n As Short, id As String, vval As String
  4376. s = Trim(s)
  4377. n = InStr(s, "=")
  4378. If n Then 'Ignore lines that don't contain a "="
  4379. id = LCase(RTrim(Left(s, n - 1)))
  4380. vval = LTrim(Mid(s, n + 1))
  4381. Select Case id
  4382. Case "title", "titl" : meta.title = Left(vval, 64)
  4383. Case "author", "autr" : meta.author = Left(vval, 64)
  4384. Case "comment", "comm" : meta.comment = Left(vval, 64)
  4385. Case "tour_info", "chmp" : meta.championship = Left(vval, 64)
  4386. Case "creation_date", "date"
  4387. meta.cyear = ValInt(vval)
  4388. meta.cmonth = 0 : meta.cday = 0
  4389. If meta.cyear < 1900 Then meta.cyear = 1900
  4390. If meta.cyear > 3000 Then meta.cyear = 3000
  4391. n = InStr(vval, "-")
  4392. If n Then
  4393. vval = Mid(vval, n + 1)
  4394. meta.cmonth = ValInt(vval)
  4395. If meta.cmonth < 0 Or meta.cmonth > 12 Then meta.cmonth = 0
  4396. n = InStr(vval, "-")
  4397. If n Then
  4398. vval = Mid(vval, n + 1)
  4399. meta.cday = ValInt(vval)
  4400. If meta.cday < 0 Or meta.cday > 31 Then meta.cday = 0
  4401. End If
  4402. End If
  4403. Case "tool" : meta.tool = Left(vval, 64)
  4404. Case "tool_version"
  4405. n = InStr(vval, ".")
  4406. If n Then
  4407. meta.toolversion = ValInt(Left(vval, n - 1))
  4408. meta.toolversion *= 10000
  4409. vval = Mid(vval, n + 1)
  4410. n = InStr(vval, ".")
  4411. If n Then
  4412. meta.toolversion += 100 * ValInt(Left(vval, n - 1))
  4413. meta.toolversion += ValInt(Mid(vval, n + 1))
  4414. Else
  4415. meta.toolversion += 100 * ValInt(vval)
  4416. End If
  4417. Else
  4418. meta.toolversion = ValInt(vval)
  4419. meta.toolversion *= 10000
  4420. End If
  4421. Case "editing_time", "etim" : meta.editing_time = ValInt(vval)
  4422. End Select
  4423. End If
  4424. s = ""
  4425. Else
  4426. 'Not and EOL character, add the character to the line
  4427. s &= Left(c, 1)
  4428. End If
  4429. c = Mid(c, 2)
  4430. Loop
  4431. Else
  4432. Exit Sub 'No valid metadata found
  4433. 'Notice that the metadata file has to be UTF-8 or ASCII with
  4434. 'no BOM. Otherwise, we'll get here and no metadata will be loaded.
  4435. End If
  4436. End Sub
  4437. Sub LoadTrack(trk As String)
  4438. Dim As Short x, y, n, i
  4439. Dim ticks As UShort, s As String
  4440. Dim mytrack As String
  4441. Dim pathtofile As String
  4442. Dim isrpl As Byte = 0
  4443. #ifdef __FB_LINUX__
  4444. n = InStrRev(trk, "/")
  4445. #else
  4446. n = InStrRev(trk, "\")
  4447. #endif
  4448. pathtofile = Left(trk, n)
  4449. mytrack = trk
  4450. If InStr(mytrack, ".") = 0 Then mytrack = mytrack + ".trk"
  4451. Open mytrack For Binary Access Read As 100
  4452. If Right(LCase(mytrack), 4) = ".rpl" Then
  4453. isrpl = -1
  4454. track_file = Space(9)
  4455. Get #100, 14, track_file
  4456. n = InStr(track_file, Chr(0))
  4457. track_file = LCase(Left(track_file, n - 1)) + ".trk"
  4458. Get #100, 25, ticks
  4459. If ticks + 1828 = LOF(100) Then 'v1.1 replay file
  4460. Seek #100, 27
  4461. Else
  4462. Get #100, 23, ticks
  4463. If ticks + 1826 = LOF(100) Then 'v1.0 replay file
  4464. Seek #100, 25
  4465. Else 'Track file renamed as replay? Or corrupt?
  4466. Seek #100, 1
  4467. End If
  4468. End If
  4469. Else
  4470. track_file = ""
  4471. For i = Len(mytrack) To 1 Step -1
  4472. If Mid(mytrack, i, 1) = "/" Or Mid(mytrack, i, 1) = "\" Then
  4473. track_file = Mid(mytrack, i + 1)
  4474. Exit For
  4475. End If
  4476. Next i
  4477. If Len(track_file) = 0 Then track_file = mytrack
  4478. End If
  4479. 'Load track contents
  4480. For y = 30 To 1 Step -1
  4481. For x = 1 To 30
  4482. Get #100, , grid(x, y).track
  4483. Next x
  4484. Next y
  4485. Get #100, , landscape
  4486. For y = 1 To 30
  4487. For x = 1 To 30
  4488. Get #100, , grid(x, y).land
  4489. grid(x, y).bgc = 0
  4490. grid(x, y).border = 0
  4491. Next x
  4492. Next y
  4493. Get #100, , format_byte
  4494. 'Initialise meta-data
  4495. meta.title = ""
  4496. meta.author = ""
  4497. meta.comment = ""
  4498. meta.championship = ""
  4499. meta.cyear = 0
  4500. meta.cmonth = 0
  4501. meta.cday = 0
  4502. meta.editing_time = -1
  4503. started_editing = Timer
  4504. 'Load meta-data
  4505. s = pathtofile + Left(track_file, InStr(track_file, ".")) + "smd"
  4506. If isrpl = 0 And LOF(100) > 1802 Then
  4507. Seek #100, 1803
  4508. LoadMetaData 100
  4509. thisfileformat = FORMAT_COMBINED 'Overlay
  4510. ElseIf FileExists(s) Then
  4511. Close 100
  4512. Open s For Binary Access Read As 100
  4513. 'We know this is a split format, but still don't know if
  4514. 'it's text or binary. We'll assume binary and if it isn't,
  4515. 'LoadMetaData will change the global variable thisfileformat
  4516. 'accordingly.
  4517. thisfileformat = FORMAT_BINARY_SPLIT 'Split
  4518. LoadMetaData 100
  4519. ElseIf GetMetaDataFromRegistry Then
  4520. Select Case format_byte
  4521. Case 150
  4522. 'Format 150 was used in earlier versions of Bliss,
  4523. 'before metadata were introduced
  4524. meta.tool = "Bliss"
  4525. meta.toolversion = 20100
  4526. thisfileformat = FORMAT_COMBINED 'Use overlay if modified
  4527. Case 151, 152, 2
  4528. 'Format 151 was used previously for tracks including
  4529. 'their metadata in the same file. It was discontinued
  4530. 'after version 2.3.3
  4531. 'Format 152 corresponded originally to tracks whose
  4532. 'metadata was being stored separately. Currently, all
  4533. 'Bliss tracks are generated with format code 152
  4534. 'Format 2 was being issued as a bug on new tracks
  4535. 'made with versions prior to 2.5.4, maybe even several
  4536. 'versions before. This was fixed, but tracks still
  4537. 'exist carrying this value
  4538. meta.tool = "Probably, Bliss"
  4539. meta.toolversion = 20303
  4540. thisfileformat = FORMAT_COMBINED 'Bliss, so also use overlay
  4541. Case 0
  4542. 'Stunts produces files with format 0 and so does
  4543. 'Track Blaster. Other tools might issue this same
  4544. 'format code, but I can't tell if that's the case.
  4545. Dim mywhat As Byte
  4546. 'Here verify the elements on the track to see if
  4547. 'it was made with Track Blaster
  4548. DetectNotStunts 0, 0, mywhat
  4549. If mywhat Then
  4550. meta.tool = "Track Blaster Pro"
  4551. meta.toolversion = 50300
  4552. Else
  4553. meta.tool = "Stunts"
  4554. meta.toolversion = 10100
  4555. End If
  4556. thisfileformat = FORMAT_BINARY_SPLIT 'Prefer split for these files
  4557. Case Else
  4558. meta.tool = "Unknown"
  4559. meta.toolversion = 0
  4560. thisfileformat = FORMAT_BINARY_SPLIT 'Unknown format - prefer split
  4561. End Select
  4562. End If
  4563. Close 100
  4564. UpdateTitleBar
  4565. modified = 0
  4566. End Sub
  4567. Sub Redo
  4568. 'If already at the head, then there's nothing to redo
  4569. If undopointer = undohead Then Exit Sub
  4570. 'Increment the pointer
  4571. undopointer = (undopointer + 1) Mod UNDOLEVEL
  4572. 'Recover the grid
  4573. If Len(undobuffer(undopointer)) = 0 Then _
  4574. undobuffer(undopointer) = Chr(30, 30) + String(1800, 0)
  4575. PutTrack 1, 1, undobuffer(undopointer), -1
  4576. DrawTrack
  4577. End Sub
  4578. Sub SaveMetaData(filenumber As Short)
  4579. Dim l As Short
  4580. If thisfileformat = FORMAT_BINARY_SPLIT Or _
  4581. thisfileformat = FORMAT_COMBINED Then
  4582. 'Stunts Meta-Data Format
  4583. Put #filenumber, , "smdf" 'Magic word
  4584. Put #filenumber, , MKL(0) 'Skip obsolete track hash
  4585. l = Len(meta.title)
  4586. If l Then
  4587. Put #filenumber, , "Titl"
  4588. Put #filenumber, , l : Put #filenumber, , meta.title
  4589. End If
  4590. l = Len(meta.author)
  4591. If l Then
  4592. Put #filenumber, , "Autr"
  4593. Put #filenumber, , l : Put #filenumber, , meta.author
  4594. End If
  4595. l = Len(meta.comment)
  4596. If l Then
  4597. Put #filenumber, , "Comm"
  4598. Put #filenumber, , l : Put #filenumber, , meta.comment
  4599. End If
  4600. l = Len(meta.championship)
  4601. If l Then
  4602. Put #filenumber, , "Chmp"
  4603. Put #filenumber, , l : Put #filenumber, , meta.championship
  4604. End If
  4605. If meta.cyear Then
  4606. Put #filenumber, , "Date" : l = 4
  4607. Put #filenumber, , l
  4608. Put #filenumber, , meta.cyear
  4609. Put #filenumber, , meta.cmonth
  4610. Put #filenumber, , meta.cday
  4611. End If
  4612. l = Len(meta.tool)
  4613. If l = 0 Then
  4614. meta.tool = "Bliss"
  4615. meta.toolversion = THISVERSION_NOPERIOD
  4616. l = 10
  4617. End If
  4618. l += 4
  4619. Put #filenumber, , "Tool"
  4620. Put #filenumber, , l
  4621. Put #filenumber, , meta.tool
  4622. Put #filenumber, , meta.toolversion
  4623. If meta.editing_time >= 0 Then
  4624. If started_editing < Timer Then _
  4625. meta.editing_time += (Timer - started_editing)
  4626. started_editing = Timer
  4627. Put #filenumber, , "Etim"
  4628. l = 4
  4629. Put #filenumber, , l
  4630. Put #filenumber, , meta.editing_time
  4631. End If
  4632. 'Save colouration if any
  4633. Dim As Byte i, j, q = 0
  4634. Dim p As String, last_bgc As ULong, last_border As ULong
  4635. Dim count As Short
  4636. last_bgc = grid(1, 1).bgc
  4637. last_border = grid(1, 1).border
  4638. For j = 1 To 30
  4639. For i = 1 To 30
  4640. If grid(i, j).border <> 0 OrElse grid(i, j).bgc <> 0 Then q = -1
  4641. If grid(i, j).border <> last_border OrElse _
  4642. grid(i, j).bgc <> last_bgc OrElse count = 255 Then
  4643. p &= Chr(count) & ConvertColour(MkL(last_border)) & ConvertColour(MkL(last_bgc))
  4644. last_bgc = grid(i, j).bgc
  4645. last_border = grid(i, j).border
  4646. count = 1
  4647. Else
  4648. count += 1
  4649. End If
  4650. Next i
  4651. Next j
  4652. p &= Chr(count) & ConvertColour(MkL(last_border)) & ConvertColour(MkL(last_bgc))
  4653. If q Then
  4654. Put #filenumber, , "Colr"
  4655. Put #filenumber, , MkShort(Len(p))
  4656. Put #filenumber, , p
  4657. End If
  4658. ElseIf thisfileformat = FORMAT_TEXT_SPLIT Then
  4659. 'Stunts text meta-data format
  4660. Put #filenumber, , "[smdf]" + Chr(13, 10)
  4661. If Len(meta.title) Then
  4662. Put #filenumber, , "title="
  4663. Put #filenumber, , meta.title + Chr(13, 10)
  4664. End If
  4665. If Len(meta.author) Then
  4666. Put #filenumber, , "author="
  4667. Put #filenumber, , meta.author + Chr(13, 10)
  4668. End If
  4669. If Len(meta.comment) Then
  4670. Put #filenumber, , "comment="
  4671. Put #filenumber, , meta.comment + Chr(13, 10)
  4672. End If
  4673. If Len(meta.championship) Then
  4674. Put #filenumber, , "tour_info="
  4675. Put #filenumber, , meta.championship + Chr(13, 10)
  4676. End If
  4677. If meta.cyear Then
  4678. Dim s As String
  4679. s = "creation_date="
  4680. s &= Trim(Str(meta.cyear)) & "-" & Trim(Str(meta.cmonth))
  4681. s &= "-" & Trim(Str(meta.cday))
  4682. Put #filenumber, , s + Chr(13, 10)
  4683. End If
  4684. l = Len(meta.tool)
  4685. If l = 0 Then
  4686. meta.tool = "Bliss"
  4687. meta.toolversion = THISVERSION_NOPERIOD
  4688. End If
  4689. Put #filenumber, , "tool="
  4690. Put #filenumber, , meta.tool + Chr(13, 10)
  4691. Put #filenumber, , "tool_version="
  4692. Dim As UByte v1, v2, v3
  4693. v1 = meta.toolversion \ 10000
  4694. v2 = (meta.toolversion Mod 10000) \ 100
  4695. v3 = meta.toolversion Mod 100
  4696. Put #filenumber, , Trim(Str(v1))
  4697. If v2 Or v3 Then Put #filenumber, , "." & Trim(Str(v2))
  4698. If v3 Then Put #filenumber, , "." & Trim(Str(v3))
  4699. Put #filenumber, , Chr(13, 10)
  4700. If meta.editing_time >= 0 Then
  4701. If started_editing < Timer Then _
  4702. meta.editing_time += (Timer - started_editing)
  4703. started_editing = Timer
  4704. Put #filenumber, , "editing_time="
  4705. Put #filenumber, , Trim(Str(meta.editing_time)) + Chr(13, 10)
  4706. End If
  4707. End If
  4708. End Sub
  4709. Sub SaveTrack(trk As String)
  4710. Dim mytrack As String, otherfile As String
  4711. Dim ticks As Short, isrpl As Byte = 0
  4712. Dim As Short x, y, i
  4713. Dim hashvalue As ULong
  4714. mytrack = trk
  4715. If InStr(mytrack, ".") = 0 Then mytrack = mytrack + ".trk"
  4716. otherfile = Left(mytrack, InStr(mytrack, ".")) + "smd"
  4717. If Right(LCase(mytrack), 4) = ".rpl" Then
  4718. isrpl = -1
  4719. Open mytrack For Binary As 100
  4720. Get #100, 25, ticks
  4721. If ticks + 1828 = LOF(100) Then 'v1.1 replay file
  4722. Seek #100, 27
  4723. Else
  4724. Get #100, 23, ticks
  4725. If ticks + 1826 = LOF(100) Then 'v1.0 replay file
  4726. Seek #100, 25
  4727. Else 'Track file renamed as replay? Or corrupt?
  4728. Seek #100, 1
  4729. End If
  4730. End If
  4731. Else
  4732. Open mytrack For Output As 100 : Close 100
  4733. Open mytrack For Binary As 100
  4734. track_file = ""
  4735. For i = Len(mytrack) To 1 Step -1
  4736. If Mid(mytrack, i, 1) = "/" Or Mid(mytrack, i, 1) = "\" Then
  4737. track_file = Mid(mytrack, i + 1)
  4738. Exit For
  4739. End If
  4740. Next i
  4741. If Len(track_file) = 0 Then track_file = mytrack
  4742. End If
  4743. For y = 30 To 1 Step -1
  4744. For x = 1 To 30
  4745. Put #100, , grid(x, y).track
  4746. Next x
  4747. Next y
  4748. Put #100, , landscape
  4749. For y = 1 To 30
  4750. For x = 1 To 30
  4751. Put #100, , grid(x, y).land
  4752. Next x
  4753. Next y
  4754. Put #100, , format_byte
  4755. 'Write meta-data
  4756. If Not isrpl AndAlso (thisfileformat <> FORMAT_RAW) Then
  4757. If thisfileformat = FORMAT_BINARY_SPLIT Or _
  4758. thisfileformat = FORMAT_TEXT_SPLIT Then
  4759. Close 100 : Open otherfile For Output As 100
  4760. Close 100 : Open otherfile For Binary As 100
  4761. End If
  4762. SaveMetaData 100
  4763. End If
  4764. Close 100
  4765. 'Delete SMD file if saved in a format other than split
  4766. If thisfileformat <> FORMAT_BINARY_SPLIT And _
  4767. thisfileformat <> FORMAT_TEXT_SPLIT And _
  4768. FileExists(otherfile) Then Kill otherfile
  4769. UpdateTitleBar
  4770. modified = 0
  4771. End Sub
  4772. Sub SaveTrackImage(trk As String)
  4773. Dim n As Short, extension As String, tfile As String
  4774. Dim As Short iwidth, iheight, ixstart, iystart
  4775. Dim finalbuffer As ULong Ptr
  4776. Dim tempxselect As Byte
  4777. 'If there's a selection, save selection, otherwise, whole track
  4778. If xselect Then
  4779. If xselect <= x2select Then
  4780. ixstart = bigwidth * (xselect - 1)
  4781. Else
  4782. ixstart = bigwidth * (x2select - 1)
  4783. End If
  4784. If yselect <= y2select Then
  4785. iystart = bigwidth * (yselect - 1)
  4786. Else
  4787. iystart = bigwidth * (y2select - 1)
  4788. End If
  4789. iwidth = bigwidth * (Abs(x2select - xselect) + 1)
  4790. iheight = bigwidth * (Abs(y2select - yselect) + 1)
  4791. Else
  4792. iwidth = 660 : iheight = 660
  4793. ixstart = 0 : iystart = 0
  4794. End If
  4795. If show_grid Then
  4796. track_image_buffer = ImageCreate(661, 661, 32)
  4797. iwidth += 1 : iheight += 1
  4798. Else
  4799. track_image_buffer = ImageCreate(660, 660, 32)
  4800. End If
  4801. finalbuffer = ImageCreate(iwidth, iheight, 32)
  4802. tempxselect = xselect
  4803. xselect = 0
  4804. DrawTrack
  4805. xselect = tempxselect
  4806. 'Kill alpha channel
  4807. Dim pvalue As ULong
  4808. For j As Short = 0 To 659
  4809. For i As Short = 0 To 659
  4810. pvalue = Point(i, j, track_image_buffer)
  4811. PSet track_image_buffer, (i, j), pvalue Or &HFF000000ul
  4812. Next i
  4813. Next j
  4814. 'Get the part that's being saved
  4815. Get track_image_buffer, (ixstart, iystart)-_
  4816. (ixstart + iwidth - 1, iystart + iheight - 1), finalbuffer
  4817. n = InStrRev(trk, ".")
  4818. If n Then
  4819. extension = LCase(Mid(trk, n))
  4820. tfile = trk
  4821. Else
  4822. extension = ".tga"
  4823. tfile = trk + extension
  4824. End If
  4825. Select Case extension
  4826. Case ".bmp" : BSave tfile, finalbuffer
  4827. Case ".tga" : TargaSave tfile, finalbuffer
  4828. Case ".jpg", ".png", ".pcx", ".gif"
  4829. BSave track_path + "temp.bmp", finalbuffer
  4830. Shell "convert " + track_path + "temp.bmp " + tfile
  4831. Kill track_path + "temp.bmp"
  4832. End Select
  4833. ImageDestroy track_image_buffer
  4834. ImageDestroy finalbuffer
  4835. track_image_buffer = 0
  4836. End Sub
  4837. Sub FollowPath(s As String, e As Byte = 0)
  4838. Dim As TrackVector slot, oldslot
  4839. Dim As Byte w, h, juststarted = -1, gofast = 0
  4840. Dim As Short n, pointed = 0
  4841. 'Null tracks are not to be followed
  4842. If section(1).final = section(1).initial And section(1).finishes = 0 Then Exit Sub
  4843. Do
  4844. pointed += 1
  4845. n = ASC(Mid(s, pointed, 1))
  4846. slot.coors = section(n).initial
  4847. slot.bearing = section(n).bearing
  4848. Do
  4849. If slot.coors = section(n).final And juststarted = 0 Then
  4850. xcursor = slot.x
  4851. ycursor = slot.y
  4852. Exit Do
  4853. End If
  4854. 'This part may cause artifacts when big items are used
  4855. 'across the border of the grid
  4856. If gofast = 0 Then
  4857. w = tr(grid(slot.x, slot.y).track).w
  4858. h = tr(grid(slot.x, slot.y).track).h
  4859. Line (xoffs + (slot.x - 1) * 22, yoffs + (slot.y - 1) * 22)- _
  4860. Step(bigwidth * w - 1, 22 * h - 1), RGB(100, 240, 240), BF
  4861. For j As Byte = 1 To h
  4862. For i As Byte = 1 To w
  4863. PutIcon tr(grid(slot.x, slot.y).track).x + i - 1, tr(grid(slot.x, slot.y).track).y + j - 1, _
  4864. xoffs + bigwidth * (slot.x + i - 2), yoffs + 22 * (slot.y + j - 2)
  4865. Next i
  4866. Next j
  4867. Sleep 100
  4868. End If
  4869. DrawSpot slot.x, slot.y
  4870. If w = 2 And slot.x < 30 Then
  4871. DrawSpot slot.x + 1, slot.y
  4872. If h = 2 And slot.y < 30 Then DrawSpot slot.x + 1, slot.y + 1
  4873. End If
  4874. If h = 2 And slot.y < 30 Then DrawSpot slot.x, slot.y + 1
  4875. oldslot = slot
  4876. slot = GetNext(slot)
  4877. If e Then 'e <> 0 means follow to error
  4878. If slot.e = e Then
  4879. xcursor = oldslot.x
  4880. ycursor = oldslot.y
  4881. Exit Do, Do
  4882. End If
  4883. End If
  4884. juststarted = 0
  4885. If Len(InKey) Then gofast = -1
  4886. Loop
  4887. Loop Until pointed = Len(s)
  4888. DrawTrack
  4889. ManageKeyboardCursor -1
  4890. End Sub
  4891. Sub GenerateSections
  4892. Dim vector As TrackVector
  4893. Dim lastchecked As Short = 0
  4894. vector = FindStart
  4895. If vector.e Then
  4896. sections = 0
  4897. paths = 0
  4898. terrors = 0
  4899. Exit Sub
  4900. End If
  4901. terrors = 0
  4902. sections = 1
  4903. section(1).initial = vector.coors
  4904. section(1).bearing = vector.bearing
  4905. section(1).origin = vector.bearing XOr 2
  4906. SolveSection 1
  4907. paths = 1
  4908. path(1).p = Chr(1)
  4909. path(1).e = 0
  4910. path(1).finishes = 0
  4911. SolvePath 1
  4912. End Sub
  4913. Function GetMetaDataFromRegistry As Byte
  4914. Dim s As String, h As ULong
  4915. Dim As Byte original
  4916. h = Hash32
  4917. Select Case h
  4918. Case &H57F9D21A : meta.title = "Default" : original = -1
  4919. Case &H9F88F8DB : meta.title = "Bernie's" : original = -1
  4920. Case &H142A0681 : meta.title = "Cherry's" : original = -1
  4921. Case &HC3477BBF : meta.title = "Helen's" : original = -1
  4922. Case &H843C5C7F : meta.title = "Joe's" : original = -1
  4923. Case &H2C1625C5 : meta.title = "Skid's" : original = -1
  4924. Case &HF8680B47
  4925. meta.title = "4:00am"
  4926. meta.author = "Cas"
  4927. meta.cyear = 2006 : meta.cmonth = 2 : meta.cday = 28
  4928. meta.tool = "Cas-Stunts" : meta.toolversion = 10000
  4929. meta.editing_time = -1
  4930. meta.comment = "Always raced with Porsche March Indy"
  4931. meta.championship = "Paleke's WSC - March 2006; ZakStunts - May 2015"
  4932. Case &H136836E9
  4933. meta.title = "Napalm"
  4934. meta.author = "Cas"
  4935. meta.cyear = 0
  4936. meta.tool = "Bliss" : meta.toolversion = 20100
  4937. meta.editing_time = -1
  4938. meta.comment = ""
  4939. meta.championship = "ZakStunts ZCT183 - September 2016"
  4940. Case &HA6460C26
  4941. meta.title = "Bliss"
  4942. meta.author = "Cas"
  4943. meta.cyear = 2016 : meta.cmonth = 10 : meta.cday = 17
  4944. meta.tool = "Bliss" : meta.toolversion = 20500
  4945. meta.editing_time = 1066
  4946. meta.comment = "Race this track to measure your relative lap"
  4947. meta.championship = "Race for Immortality - October/November 2016"
  4948. Case Else 'Use external registry
  4949. Dim found As Short = -1
  4950. If FileExists("bliss.reg") Then
  4951. Dim f As Integer, n As Short, s As String, rs As Short
  4952. Dim shash As String, fpointer As Long
  4953. f = FreeFile
  4954. Open "bliss.reg" For Binary Access Read As f
  4955. 'First four bytes are magic number (not checked now)
  4956. Get #f, 5, rs 'Get registry size (max number of tracks)
  4957. Get #f, , n 'Get number of registry entries
  4958. s = Space(4 * n)
  4959. Get #f, , s 'Read hash table
  4960. shash = MkL(h) : found = -1
  4961. For i As Short = 0 To n - 1
  4962. If Mid(s, 4 * i + 1, 4) = shash Then
  4963. found = i
  4964. Exit For
  4965. End If
  4966. Next i
  4967. If found >= 0 Then
  4968. Get #f, 5 + 4 * rs + 4 * found, fpointer
  4969. Get #f, fpointer + 1, n 'Get metadata length
  4970. s = Space(n)
  4971. Get #f, , s
  4972. LoadMetadata , s
  4973. End If
  4974. Close f
  4975. End If
  4976. #ifndef __FB_DOS__
  4977. 'If it looks like a ZakStunts track, try to retrieve
  4978. 'the metadata from the site
  4979. If found = -1 AndAlso UCase(Left(track_file, 3)) = "ZCT" Then
  4980. Dim length As Long, trackaddr As String
  4981. Dim content As ZString Ptr, s As String
  4982. Dim dif As Boolean = False
  4983. DrawTrack
  4984. MenuBox 25, 9, "Identifying Track"
  4985. lefx += 8
  4986. TLeft , "Identifying ZakStunts champ track...", RGB(160, 160, 240)
  4987. TLeft , "Verifying track content...", RGB(160, 160, 240)
  4988. trackaddr = "zak.stunts.hu/tracks/" & UCase(Left(track_file, Len(track_file) - 4)) & ".trk"
  4989. length = HTTP_Download(trackaddr, content)
  4990. If length > 0 Then
  4991. Dim As Byte x, y
  4992. Dim u As Short = 0
  4993. For y = 30 To 1 Step -1
  4994. For x = 1 To 30
  4995. If content[u] <> grid(x, y).track Then
  4996. dif = True
  4997. Exit For, For
  4998. End If
  4999. u += 1
  5000. Next x
  5001. Next y
  5002. If content[u] <> landscape Then dif = True
  5003. u += 1
  5004. For y = 1 To 30
  5005. For x = 1 To 30
  5006. If content[u] <> grid(x, y).land Then
  5007. dif = True
  5008. Exit For, For
  5009. End If
  5010. u += 1
  5011. Next x
  5012. Next y
  5013. If Not dif Then
  5014. TLeft , "Verified.", RGB(160, 160, 240)
  5015. Else
  5016. TLeft , "Couldn't verify!", RGB(160, 160, 240)
  5017. Sleep 300
  5018. End If
  5019. If content <> 0 Then Deallocate content : content = 0
  5020. End If
  5021. If Not dif Then
  5022. TLeft , "Retrieving metadata from ZakStunts...", RGB(160, 160, 240)
  5023. trackaddr = UCase(Left(track_file, Len(track_file) - 4))
  5024. trackaddr = "zak.stunts.hu/tracks/" & trackaddr
  5025. length = HTTP_Download(trackaddr, content)
  5026. If length > 0 Then
  5027. Dim n As Long
  5028. 'Get the track name in form "Cxxx"
  5029. s = Left(track_file, Len(track_file) - 4)
  5030. s = "C" + Mid(s, 4) + " - "
  5031. n = InStr(*content, s)
  5032. If n Then
  5033. s = Mid(*content, n + Len(s), 255)
  5034. n = InStr(s, "<")
  5035. If n Then s = Left(s, n - 1)
  5036. n = InStr(s, "(by ")
  5037. If n Then
  5038. 'Title and author
  5039. meta.title = Trim(Left(s, n - 1))
  5040. s = Mid(s, n + 4)
  5041. n = InStr(s, ")")
  5042. If n Then s = Left(s, n - 1)
  5043. meta.author = Trim(s)
  5044. Else
  5045. 'Title only
  5046. meta.title = Trim(s)
  5047. meta.author = ""
  5048. End If
  5049. meta.championship = "ZakStunts " & UCase(Left(track_file, Len(track_file) - 4))
  5050. End If
  5051. Deallocate content
  5052. End If
  5053. End If
  5054. End If
  5055. #endif
  5056. End Select
  5057. If original Then
  5058. meta.author = "DSI"
  5059. meta.comment = "Original track"
  5060. meta.championship = ""
  5061. meta.tool = "Stunts"
  5062. meta.toolversion = 10000
  5063. meta.editing_time = -1
  5064. meta.cyear = 1990
  5065. meta.cmonth = 10
  5066. meta.cday = 0
  5067. Return 0
  5068. Else
  5069. Return -1
  5070. End If
  5071. End Function
  5072. Function GetNext(slot As TrackVector, detour As Byte = 0) As TrackVector
  5073. Dim newslot As TrackVector
  5074. Dim As UByte curel, newel, isaramp = 0, isabridge = 0
  5075. 'Current element is the nature of the element at current slot
  5076. curel = grid(slot.x, slot.y).track
  5077. newslot.origin = slot.bearing XOr 2
  5078. Select Case slot.bearing
  5079. Case 0 'North
  5080. If tr(curel).cisalt(slot.bearing) Then
  5081. newslot.x = slot.x + 1
  5082. Else
  5083. newslot.x = slot.x
  5084. End If
  5085. newslot.y = slot.y - 1
  5086. 'See if this is a ramp or bridge
  5087. If tr(curel).ctype(0) = 2 Then
  5088. If tr(curel).w = 1 And tr(curel).h = 1 AndAlso _
  5089. tr(curel).ctype(2) = 1 Then
  5090. isaramp = -1
  5091. Else
  5092. isabridge = -1
  5093. End If
  5094. If detour Then newslot.y -= 1 'Skip one slot (jump)
  5095. End If
  5096. If newslot.x > 30 Or newslot.y < 1 Then _
  5097. newslot.e = 80 : Return newslot 'Grid border reached
  5098. newel = grid(newslot.x, newslot.y).track
  5099. Select Case newel
  5100. Case 255 : newslot.x -= 1
  5101. Case 254 : newslot.y -= 1
  5102. Case 253 : newslot.x -= 1 : newslot.y -= 1
  5103. End Select
  5104. If newslot.x < 1 Or newslot.y < 1 Then _
  5105. newslot.e = 80 : Return newslot 'Grid border reached
  5106. newel = grid(newslot.x, newslot.y).track
  5107. If tr(newel).ctype(2) = 0 Then 'New tile does not accept
  5108. If (isaramp <> 0 Or isabridge <> 0) And detour = 0 Then
  5109. newslot = GetNext(slot, -1)
  5110. Return newslot
  5111. ElseIf isaramp Then
  5112. newslot.e = 73 'Jump distance is too long
  5113. Return newslot
  5114. ElseIf tr(curel).ctype(slot.bearing) = 2 Then
  5115. newslot.e = 74 'Stunts won't allow interrupting this bridge
  5116. Return newslot
  5117. Else
  5118. newslot.e = 81 'End of track, interrupted
  5119. Return newslot
  5120. End If
  5121. ElseIf tr(newel).ctype(2) <> tr(curel).ctype(0) Then
  5122. newslot.e = 70 'Track types mismatch
  5123. End If
  5124. 'Accepted, but... is the jump feasible?
  5125. If isaramp And detour Then
  5126. If grid(slot.x, slot.y).land = 9 Then
  5127. newslot.e = 21 'Jump is not feasible
  5128. ElseIf grid(slot.x, slot.y).land = 0 And grid(newslot.x, newslot.y).land = 6 Then
  5129. newslot.e = 21 'Jump is not feasible
  5130. End If
  5131. ElseIf isabridge And detour Then
  5132. If grid(slot.x, slot.y).land <> 6 Or grid(newslot.x, newslot.y).land = 6 Then
  5133. newslot.e = 21 'Jump is not feasible
  5134. End If
  5135. End If
  5136. If newslot.x - (tr(newel).cisalt(2) <> 0) _
  5137. <> slot.x - (tr(curel).cisalt(0) <> 0) Then
  5138. newslot.e = 81 'Track not properly connected
  5139. End If
  5140. 'Straightway before jump is too short?
  5141. If slot.origin <> (slot.bearing XOr 2) _
  5142. Or tr(curel).entity = ASC("t") _
  5143. Or tr(curel).entity = ASC("h") Then 'Turn, tunnel or chicane?
  5144. 'Yes, it's one of those. Ramp ahead?
  5145. If tr(newel).w = 1 And tr(newel).h = 1 AndAlso _
  5146. tr(newel).ctype(2) = 1 And tr(newel).ctype(0) = 2 Then
  5147. 'Yes. Is it a jump?
  5148. If newslot.y - 1 >= 1 AndAlso _
  5149. tr(GetParent(newslot.x, newslot.y - 1)).ctype(2) <> 2 Then
  5150. newslot.e = 71 'Straightway before jump is too short
  5151. End If
  5152. End If
  5153. End If
  5154. Select Case tr(newel).cto(2)
  5155. Case 0 : newslot.e = 4 'No exit!
  5156. Case 1 : newslot.bearing = 0 'North
  5157. Case 2 : newslot.bearing = 1 'East
  5158. Case 4 : newslot.bearing = 2 'South
  5159. Case 8 : newslot.bearing = 3 'West
  5160. Case 3 'Split: North or East
  5161. If detour Then
  5162. newslot.bearing = 1
  5163. Else
  5164. newslot.bearing = 0
  5165. End If
  5166. Case 9 'Split: North or West
  5167. If detour Then
  5168. newslot.bearing = 3
  5169. Else
  5170. newslot.bearing = 0
  5171. End If
  5172. Case Else : newslot.bearing = 0 'This should never happen
  5173. End Select
  5174. Case 1 'East
  5175. If tr(curel).cisalt(slot.bearing) Then
  5176. newslot.y = slot.y + 1
  5177. Else
  5178. newslot.y = slot.y
  5179. End If
  5180. newslot.x = slot.x + tr(curel).w
  5181. 'See if this is a ramp or bridge
  5182. If tr(curel).ctype(1) = 2 Then
  5183. If tr(curel).w = 1 And tr(curel).h = 1 AndAlso _
  5184. tr(curel).ctype(3) = 1 Then
  5185. isaramp = -1
  5186. Else
  5187. isabridge = -1
  5188. End If
  5189. If detour Then newslot.x += 1 'Skip one slot (jump)
  5190. End If
  5191. If newslot.x > 30 Or newslot.y > 30 Then _
  5192. newslot.e = 80 : Return newslot 'Grid border reached
  5193. newel = grid(newslot.x, newslot.y).track
  5194. Select Case newel
  5195. Case 255 : newslot.x -= 1
  5196. Case 254 : newslot.y -= 1
  5197. Case 253 : newslot.x -= 1 : newslot.y -= 1
  5198. End Select
  5199. If newslot.x < 1 Or newslot.y < 1 Then _
  5200. newslot.e = 80 : Return newslot 'Grid border reached
  5201. newel = grid(newslot.x, newslot.y).track
  5202. If tr(newel).ctype(3) = 0 Then 'New tile does not accept
  5203. If (isaramp <> 0 Or isabridge <> 0) And detour = 0 Then
  5204. newslot = GetNext(slot, -1)
  5205. Return newslot
  5206. ElseIf isaramp Then
  5207. newslot.e = 73 'Jump distance is too long
  5208. Return newslot
  5209. ElseIf tr(curel).ctype(slot.bearing) = 2 Then
  5210. newslot.e = 74 'Stunts won't allow interrupting this bridge
  5211. Return newslot
  5212. Else
  5213. newslot.e = 81 'End of track, interrupted
  5214. Return newslot
  5215. End If
  5216. ElseIf tr(newel).ctype(3) <> tr(curel).ctype(1) Then
  5217. newslot.e = 70 'Track types mismatch
  5218. End If
  5219. 'Accepted, but... is the jump feasible?
  5220. If isaramp And detour Then
  5221. If grid(slot.x, slot.y).land = 8 Then
  5222. newslot.e = 21 'Jump is not feasible
  5223. ElseIf grid(slot.x, slot.y).land = 0 And grid(newslot.x, newslot.y).land = 6 Then
  5224. newslot.e = 21 'Jump is not feasible
  5225. End If
  5226. ElseIf isabridge And detour Then
  5227. If grid(slot.x, slot.y).land <> 6 Or grid(newslot.x, newslot.y).land = 6 Then
  5228. newslot.e = 21 'Jump is not feasible
  5229. End If
  5230. End If
  5231. If newslot.y - (tr(newel).cisalt(3) <> 0) _
  5232. <> slot.y - (tr(curel).cisalt(1) <> 0) Then
  5233. newslot.e = 81 'Track not properly connected
  5234. End If
  5235. 'Straightway before jump is too short?
  5236. If slot.origin <> (slot.bearing XOr 2) _
  5237. Or tr(curel).entity = ASC("t") _
  5238. Or tr(curel).entity = ASC("h") Then 'Turn, tunnel or chicane?
  5239. 'Yes, it's one of those. Ramp ahead?
  5240. If tr(newel).w = 1 And tr(newel).h = 1 AndAlso _
  5241. tr(newel).ctype(3) = 1 And tr(newel).ctype(1) = 2 Then
  5242. 'Yes. Is it a jump?
  5243. If newslot.x + 1 <= 30 AndAlso _
  5244. tr(GetParent(newslot.x + 1, newslot.y)).ctype(3) <> 2 Then
  5245. newslot.e = 71 'Straightway before jump is too short
  5246. End If
  5247. End If
  5248. End If
  5249. Select Case tr(newel).cto(3)
  5250. Case 0 : newslot.e = 4 'No exit!
  5251. Case 1 : newslot.bearing = 0 'North
  5252. Case 2 : newslot.bearing = 1 'East
  5253. Case 4 : newslot.bearing = 2 'South
  5254. Case 8 : newslot.bearing = 3 'West
  5255. Case 3 'Split: East or North
  5256. If detour Then
  5257. newslot.bearing = 0
  5258. Else
  5259. newslot.bearing = 1
  5260. End If
  5261. Case 6 'Split: East or South
  5262. If detour Then
  5263. newslot.bearing = 2
  5264. Else
  5265. newslot.bearing = 1
  5266. End If
  5267. Case Else : newslot.bearing = 1 'This should never happen
  5268. End Select
  5269. Case 2 'South
  5270. If tr(curel).cisalt(slot.bearing) Then
  5271. newslot.x = slot.x + 1
  5272. Else
  5273. newslot.x = slot.x
  5274. End If
  5275. newslot.y = slot.y + tr(curel).h
  5276. 'See if this is a ramp or bridge
  5277. If tr(curel).ctype(2) = 2 Then
  5278. If tr(curel).w = 1 And tr(curel).h = 1 AndAlso _
  5279. tr(curel).ctype(0) = 1 Then
  5280. isaramp = -1
  5281. Else
  5282. isabridge = -1
  5283. End If
  5284. If detour Then newslot.y += 1 'Skip one slot (jump)
  5285. End If
  5286. If newslot.x > 30 Or newslot.y > 30 Then _
  5287. newslot.e = 80 : Return newslot 'Grid border reached
  5288. newel = grid(newslot.x, newslot.y).track
  5289. Select Case newel
  5290. Case 255 : newslot.x -= 1
  5291. Case 254 : newslot.y -= 1
  5292. Case 253 : newslot.x -= 1 : newslot.y -= 1
  5293. End Select
  5294. If newslot.x < 1 Or newslot.y < 1 Then _
  5295. newslot.e = 80 : Return newslot 'Grid border reached
  5296. newel = grid(newslot.x, newslot.y).track
  5297. If tr(newel).ctype(0) = 0 Then 'New tile does not accept
  5298. If (isaramp <> 0 Or isabridge <> 0) And detour = 0 Then
  5299. newslot = GetNext(slot, -1)
  5300. Return newslot
  5301. ElseIf isaramp Then
  5302. newslot.e = 73 'Jump distance is too long
  5303. Return newslot
  5304. ElseIf tr(curel).ctype(slot.bearing) = 2 Then
  5305. newslot.e = 74 'Stunts won't allow interrupting this bridge
  5306. Return newslot
  5307. Else
  5308. newslot.e = 81 'End of track, interrupted
  5309. Return newslot
  5310. End If
  5311. ElseIf tr(newel).ctype(0) <> tr(curel).ctype(2) Then
  5312. newslot.e = 70 'Track types mismatch
  5313. End If
  5314. 'Accepted, but... is the jump feasible?
  5315. If isaramp And detour Then
  5316. If grid(slot.x, slot.y).land = 7 Then
  5317. newslot.e = 21 'Jump is not feasible
  5318. ElseIf grid(slot.x, slot.y).land = 0 And grid(newslot.x, newslot.y).land = 6 Then
  5319. newslot.e = 21 'Jump is not feasible
  5320. End If
  5321. ElseIf isabridge And detour Then
  5322. If grid(slot.x, slot.y).land <> 6 Or grid(newslot.x, newslot.y).land = 6 Then
  5323. newslot.e = 21 'Jump is not feasible
  5324. End If
  5325. End If
  5326. If newslot.x - (tr(newel).cisalt(0) <> 0) _
  5327. <> slot.x - (tr(curel).cisalt(2) <> 0) Then
  5328. newslot.e = 81 'Track not properly connected
  5329. End If
  5330. 'Straightway before jump is too short?
  5331. If slot.origin <> (slot.bearing XOr 2) _
  5332. Or tr(curel).entity = ASC("t") _
  5333. Or tr(curel).entity = ASC("h") Then 'Turn, tunnel or chicane?
  5334. 'Yes, it's one of those. Ramp ahead?
  5335. If tr(newel).w = 1 And tr(newel).h = 1 AndAlso _
  5336. tr(newel).ctype(0) = 1 And tr(newel).ctype(2) = 2 Then
  5337. 'Yes. Is it a jump?
  5338. If newslot.y + 1 <= 30 AndAlso _
  5339. tr(GetParent(newslot.x, newslot.y + 1)).ctype(0) <> 2 Then
  5340. newslot.e = 71 'Straightway before jump is too short
  5341. End If
  5342. End If
  5343. End If
  5344. Select Case tr(newel).cto(0)
  5345. Case 0 : newslot.e = 4 'No exit!
  5346. Case 1 : newslot.bearing = 0 'North
  5347. Case 2 : newslot.bearing = 1 'East
  5348. Case 4 : newslot.bearing = 2 'South
  5349. Case 8 : newslot.bearing = 3 'West
  5350. Case 6 'Split: South or East
  5351. If detour Then
  5352. newslot.bearing = 1
  5353. Else
  5354. newslot.bearing = 2
  5355. End If
  5356. Case 12 'Split: South or West
  5357. If detour Then
  5358. newslot.bearing = 3
  5359. Else
  5360. newslot.bearing = 2
  5361. End If
  5362. Case Else : newslot.bearing = 2 'This should never happen
  5363. End Select
  5364. Case 3 'West
  5365. If tr(curel).cisalt(slot.bearing) Then
  5366. newslot.y = slot.y + 1
  5367. Else
  5368. newslot.y = slot.y
  5369. End If
  5370. newslot.x = slot.x - 1
  5371. 'See if this is a ramp or bridge
  5372. If tr(curel).ctype(3) = 2 Then
  5373. If tr(curel).w = 1 And tr(curel).h = 1 AndAlso _
  5374. tr(curel).ctype(1) = 1 Then
  5375. isaramp = -1
  5376. Else
  5377. isabridge = -1
  5378. End If
  5379. If detour Then newslot.x -= 1 'Skip one slot (jump)
  5380. End If
  5381. If newslot.x < 1 Or newslot.y > 30 Then _
  5382. newslot.e = 80 : Return newslot 'Grid border reached
  5383. newel = grid(newslot.x, newslot.y).track
  5384. Select Case newel
  5385. Case 255 : newslot.x -= 1
  5386. Case 254 : newslot.y -= 1
  5387. Case 253 : newslot.x -= 1 : newslot.y -= 1
  5388. End Select
  5389. If newslot.x < 1 Or newslot.y < 1 Then _
  5390. newslot.e = 80 : Return newslot 'Grid border reached
  5391. newel = grid(newslot.x, newslot.y).track
  5392. If tr(newel).ctype(1) = 0 Then 'New tile does not accept
  5393. If (isaramp <> 0 Or isabridge <> 0) And detour = 0 Then
  5394. newslot = GetNext(slot, -1)
  5395. Return newslot
  5396. ElseIf isaramp Then
  5397. newslot.e = 73 'Jump distance is too long
  5398. Return newslot
  5399. ElseIf tr(curel).ctype(slot.bearing) = 2 Then
  5400. newslot.e = 74 'Stunts won't allow interrupting this bridge
  5401. Return newslot
  5402. Else
  5403. newslot.e = 81 'End of track, interrupted
  5404. Return newslot
  5405. End If
  5406. ElseIf tr(newel).ctype(1) <> tr(curel).ctype(3) Then
  5407. newslot.e = 70 'Track types mismatch
  5408. End If
  5409. 'Accepted, but... is the jump feasible?
  5410. If isaramp And detour Then
  5411. If grid(slot.x, slot.y).land = 10 Then
  5412. newslot.e = 21 'Jump is not feasible
  5413. ElseIf grid(slot.x, slot.y).land = 0 And grid(newslot.x, newslot.y).land = 6 Then
  5414. newslot.e = 21 'Jump is not feasible
  5415. End If
  5416. ElseIf isabridge And detour Then
  5417. If grid(slot.x, slot.y).land <> 6 Or grid(newslot.x, newslot.y).land = 6 Then
  5418. newslot.e = 21 'Jump is not feasible
  5419. End If
  5420. End If
  5421. If newslot.y - (tr(newel).cisalt(1) <> 0) _
  5422. <> slot.y - (tr(curel).cisalt(3) <> 0) Then
  5423. newslot.e = 81 'Track not properly connected
  5424. End If
  5425. 'Straightway before jump is too short?
  5426. If slot.origin <> (slot.bearing XOr 2) _
  5427. Or tr(curel).entity = ASC("t") _
  5428. Or tr(curel).entity = ASC("h") Then 'Turn, tunnel or chicane?
  5429. 'Yes, it's one of those. Ramp ahead?
  5430. If tr(newel).w = 1 And tr(newel).h = 1 AndAlso _
  5431. tr(newel).ctype(1) = 1 And tr(newel).ctype(3) = 2 Then
  5432. 'Yes. Is it a jump?
  5433. If newslot.x - 1 >= 1 AndAlso _
  5434. tr(GetParent(newslot.x - 1, newslot.y)).ctype(1) <> 2 Then
  5435. newslot.e = 71 'Straightway before jump is too short
  5436. End If
  5437. End If
  5438. End If
  5439. Select Case tr(newel).cto(1)
  5440. Case 0 : newslot.e = 4 'No exit!
  5441. Case 1 : newslot.bearing = 0 'North
  5442. Case 2 : newslot.bearing = 1 'East
  5443. Case 4 : newslot.bearing = 2 'South
  5444. Case 8 : newslot.bearing = 3 'West
  5445. Case 9 'Split: West or North
  5446. If detour Then
  5447. newslot.bearing = 0
  5448. Else
  5449. newslot.bearing = 3
  5450. End If
  5451. Case 12 'Split: West or South
  5452. If detour Then
  5453. newslot.bearing = 2
  5454. Else
  5455. newslot.bearing = 3
  5456. End If
  5457. Case Else : newslot.bearing = 3 'This should never happen
  5458. End Select
  5459. End Select
  5460. Return newslot
  5461. End Function
  5462. 'Get the code of the parent element
  5463. Function GetParent(x As UByte, y As UByte) As UByte
  5464. Select Case grid(x, y).track
  5465. Case 255
  5466. If x > 1 Then
  5467. If tr(grid(x - 1, y).track).w = 2 Then
  5468. Return grid(x - 1, y).track
  5469. End If
  5470. End If
  5471. Case 254
  5472. If y > 1 Then
  5473. If tr(grid(x, y - 1).track).h = 2 Then
  5474. Return grid(x, y - 1).track
  5475. End If
  5476. End If
  5477. Case 253
  5478. If x > 1 And y > 1 Then
  5479. If tr(grid(x - 1, y - 1).track).w = 2 And tr(grid(x - 1, y - 1).track).h = 2 Then
  5480. Return grid(x - 1, y - 1).track
  5481. End If
  5482. End If
  5483. End Select
  5484. Return grid(x, y).track
  5485. End Function
  5486. 'Read a rectangle from the grid into a string
  5487. Function GetTrack(x As UByte, y As UByte, x2 As UByte, y2 As UByte) As String
  5488. Dim As Byte i, j, c
  5489. Dim s As String, t As String
  5490. s = Chr(x2 - x + 1, y2 - y + 1)
  5491. For j = y To y2
  5492. For i = x To x2
  5493. c = 0 : t = ""
  5494. If grid(i, j).track Then
  5495. c Or= 1
  5496. t &= Chr(grid(i, j).track)
  5497. End If
  5498. If grid(i, j).land Then
  5499. c Or= 2
  5500. t &= Chr(grid(i, j).land)
  5501. End If
  5502. If grid(i, j).border Then
  5503. c Or= 4
  5504. t &= MkL(grid(i, j).border)
  5505. End If
  5506. If grid(i, j).bgc Then
  5507. c Or= 8
  5508. t &= MkL(grid(i, j).bgc)
  5509. End If
  5510. s &= Chr(c) & t
  5511. Next i
  5512. Next j
  5513. Return s
  5514. End Function
  5515. 'Generate a 32bit hash value out of the given string
  5516. Function Hash32 Overload (content As String) As ULong
  5517. Dim i As Short, hash As ULong
  5518. Dim u As UByte
  5519. For i = 1 To Len(content)
  5520. u = ASC(Mid(content, i, 1))
  5521. If u Then
  5522. hash XOr= (u + 11)
  5523. hash XOr= (121 * i)
  5524. Else
  5525. hash *= 31
  5526. hash += 3
  5527. End If
  5528. Next i
  5529. Return hash
  5530. End Function
  5531. Function Hash32 Overload As ULong
  5532. Dim trackstring As String, h As ULong
  5533. For j As Byte = 30 To 1 Step - 1
  5534. For i As Byte = 1 To 30
  5535. trackstring &= Chr(grid(i, j).track)
  5536. Next i
  5537. Next j
  5538. trackstring &= Chr(landscape)
  5539. For j As Byte = 1 To 30
  5540. For i As Byte = 1 To 30
  5541. trackstring &= Chr(grid(i, j).land)
  5542. Next i
  5543. Next j
  5544. Return Hash32(trackstring)
  5545. End Function
  5546. 'Flip buffer rectangle horizontally
  5547. Function HFlipTrack(t As String) As String
  5548. Dim As Byte w, h, c
  5549. w = ASC(Left(t, 1))
  5550. h = ASC(Mid(t, 2, 1))
  5551. Dim temp(1 To w, 1 To h) As SGrid
  5552. Dim s As String, i As Byte, j As Byte, n As Short
  5553. 'Read and flip
  5554. n = 3 : i = w : j = 1
  5555. Do While n <= Len(t)
  5556. c = ASC(Mid(t, n, 1))
  5557. n += 1
  5558. If c And 1 Then 'Track is non-zero
  5559. temp(i, j).track = tr(ASC(Mid(t, n, 1))).hflip
  5560. n += 1
  5561. End If
  5562. If c And 2 Then 'Terrain is non-zero
  5563. temp(i, j).land = ttr(ASC(Mid(t, n, 1))).hflip
  5564. n += 1
  5565. End If
  5566. If c And 4 Then 'Border colour is non-zero
  5567. temp(i, j).border = CvL(Mid(t, n, 4))
  5568. n += 4
  5569. End If
  5570. If c And 8 Then 'Background colour is non-zero
  5571. temp(i, j).bgc = CvL(Mid(t, n, 4))
  5572. n += 4
  5573. End If
  5574. i -= 1
  5575. If i = 0 Then i = w : j += 1
  5576. Loop
  5577. 'Fix
  5578. For j = 1 To h
  5579. For i = 1 To w - 1
  5580. If temp(i, j).track = 255 Or temp(i, j).track = 253 Then
  5581. Swap temp(i, j).track, temp(i + 1, j).track
  5582. i += 1
  5583. End If
  5584. Next i
  5585. Next j
  5586. 'Put back into the string
  5587. s = PackedClip(temp())
  5588. Return s
  5589. End Function
  5590. Sub InitFiles(mask As String, x1 As Short, y1 As Short, x2 As Short, y2 As Short)
  5591. Dim As String s, t
  5592. Dim attr As Integer
  5593. Dim i As Short
  5594. Dim justreloading As Byte
  5595. filer.mask = mask
  5596. If x1 Then
  5597. filer.x1 = x1
  5598. filer.y1 = y1
  5599. filer.x2 = x2
  5600. filer.y2 = y2
  5601. justreloading = 0
  5602. DrawBox x1, y1, x2, y2
  5603. Else
  5604. x1 = filer.x1
  5605. y1 = filer.y1
  5606. x2 = filer.x2
  5607. y2 = filer.y2
  5608. justreloading = -1
  5609. Line (x1 + 4, y1 + 4)-(x2 - 32, y2 - 4), RGB(30, 30, 50), BF
  5610. End If
  5611. filer.reread = -1
  5612. fileys = 0
  5613. #ifdef __FB_LINUX__
  5614. If track_path <> "/" And track_path <> "\" Then
  5615. fileys = 1
  5616. filey(1) = "*.."
  5617. End If
  5618. #else
  5619. DetectDrives
  5620. #endif
  5621. For i As UByte = 1 To dirlinks
  5622. If track_path <> dirlink(i).directory Then
  5623. fileys += 1
  5624. filey(fileys) = "* - " + dirlink(i).text + " - "
  5625. End If
  5626. Next i
  5627. s = Dir(track_path + "*.*", 49, attr)
  5628. Do
  5629. If Len(s) Then
  5630. If attr And 16 Then
  5631. If s <> "." Then
  5632. fileys += 1
  5633. filey(fileys) = "*" + s
  5634. End If
  5635. Else
  5636. i = 1
  5637. Do
  5638. t = LCase(Mid(mask, i))
  5639. i = InStr(t, ";")
  5640. If i Then t = Left(t, i - 1)
  5641. t = Trim(t)
  5642. If Len(t) = 0 Then Exit Do
  5643. If Right(LCase(s), Len(t) + 1) = "." + t Then
  5644. fileys += 1
  5645. filey(fileys) = s
  5646. Exit Do
  5647. End If
  5648. If i = 0 Then Exit Do Else i += 1
  5649. Loop
  5650. End If
  5651. s = Dir(attr)
  5652. Else
  5653. Exit Do
  5654. End If
  5655. Loop Until fileys = 512
  5656. SortFiles
  5657. If Not justreloading Then
  5658. AddButton x2 - 24, y1, Chr(24), 101
  5659. AddButton x2 - 24, y2 - 32, Chr(25), 102
  5660. End If
  5661. End Sub
  5662. Function ManageFiles(akey As String = "") As String
  5663. Static first As Short, exfirst As Short = -1
  5664. Static lit As Short, exlit As Short
  5665. Static wheel As Integer
  5666. Dim i As Short, v As Short
  5667. Dim As Integer xm, ym, wm, bm
  5668. If filer.reread Then
  5669. first = 1 : exfirst = -1
  5670. lit = -1 : exlit = -1
  5671. filer.reread = 0
  5672. Do
  5673. GetMouse xm, ym, wm, bm
  5674. Loop Until bm = 0
  5675. wheel = wm
  5676. End If
  5677. GetMouse xm, ym, wm, bm
  5678. v = ManageButtons
  5679. If v = 101 Or wm > wheel Then
  5680. If first > 1 Then first -= 1 Else v = 0
  5681. wheel = wm
  5682. ElseIf v = 102 Or wm < wheel Then
  5683. If first + 17 < fileys Then first += 1 Else v = 0
  5684. wheel = wm
  5685. End If
  5686. If Len(akey) Then
  5687. If ASC(akey) = 1 Then 'Search for file name in list
  5688. For i = 1 To fileys
  5689. If Left(LCase(filey(i)), Len(akey) - 1) = LCase(Mid(akey, 2)) Then
  5690. first = i
  5691. If first + 17 > fileys Then first = fileys - 17
  5692. If first < 1 Then first = 1
  5693. Exit For
  5694. End If
  5695. Next i
  5696. Else
  5697. Select Case akey
  5698. Case Chr(255) + Chr(73)
  5699. If first > 18 Then first -= 18 Else first = 1
  5700. Case Chr(255) + Chr(81)
  5701. If first + 35 < fileys Then first += 18 Else first = fileys - 17
  5702. End Select
  5703. End If
  5704. End If
  5705. If first <> exfirst Then
  5706. ScreenLock
  5707. Line (filer.x1 + 4, filer.y1 + 4)-(filer.x2 - 32, filer.y2 - 4), RGB(30, 30, 50), BF
  5708. For i = 0 To 17
  5709. If first + i > fileys Then Exit For
  5710. If Left(filey(first + i), 1) = "*" Then
  5711. Draw String (filer.x1 + 16, filer.y1 + 12 + i * 16), "[" + Mid(filey(first + i), 2) + "]", RGB(160, 240, 160)
  5712. Else
  5713. Draw String (filer.x1 + 16, filer.y1 + 12 + i * 16), filey(first + i), RGB(160, 160, 240)
  5714. End If
  5715. Next i
  5716. ScreenUnlock
  5717. exfirst = first
  5718. End If
  5719. If xm >= filer.x1 + 16 And xm <= filer.x2 - 32 And ym >= filer.y1 + 12 And ym <= filer.y2 - 12 Then
  5720. lit = (ym - filer.y1 - 12) \ 16
  5721. Else
  5722. lit = -1
  5723. End If
  5724. If lit <> exlit Then
  5725. If exlit <> -1 And first + exlit <= fileys Then
  5726. If Left(filey(first + exlit), 1) = "*" Then
  5727. Draw String (filer.x1 + 16, filer.y1 + 12 + exlit * 16), "[" + Mid(filey(first + exlit), 2) + "]", RGB(160, 240, 160)
  5728. Else
  5729. Draw String (filer.x1 + 16, filer.y1 + 12 + exlit * 16), filey(first + exlit), RGB(160, 160, 240)
  5730. End If
  5731. End If
  5732. If lit <> -1 And first + lit <= fileys Then
  5733. If Left(filey(first + lit), 1) = "*" Then
  5734. Draw String (filer.x1 + 16, filer.y1 + 12 + lit * 16), "[" + Mid(filey(first + lit), 2) + "]", RGB(255, 255, 255)
  5735. Else
  5736. Draw String (filer.x1 + 16, filer.y1 + 12 + lit * 16), filey(first + lit), RGB(255, 255, 255)
  5737. End If
  5738. End If
  5739. exlit = lit
  5740. End If
  5741. If bm = 1 And lit <> -1 And first + lit <= fileys Then
  5742. If Left(filey(first + lit), 1) = "*" Then
  5743. If Mid(filey(first + lit), 2, 1) = " " Then
  5744. For i As UByte = 1 To dirlinks
  5745. If Mid(filey(first + lit), 5, Len(dirlink(i).text)) = dirlink(i).text Then
  5746. track_path = dirlink(i).directory
  5747. Exit For
  5748. End If
  5749. Next i
  5750. Else
  5751. ChangeTrackDirectory Mid(filey(first + lit), 2)
  5752. End If
  5753. InitFiles filer.mask, 0, 0, 0, 0
  5754. Else
  5755. Return filey(first + lit)
  5756. End If
  5757. End If
  5758. If v = 101 Or v = 102 Then Sleep 30, 1
  5759. Return ""
  5760. End Function
  5761. Sub CreatePath
  5762. Dim As Byte firstx, firsty, bearing, material = 1
  5763. Dim As UByte addthing
  5764. Dim As String buffer, akey
  5765. Dim As Integer bm
  5766. Do
  5767. GetMouse 0, 0, 0, bm
  5768. Loop Until bm = 0
  5769. firstx = xcursor
  5770. firsty = ycursor
  5771. PushUndo
  5772. Do
  5773. GetMouse 0, 0, 0, bm
  5774. If bm Then Exit Do
  5775. akey = InKey
  5776. Select Case akey
  5777. Case Chr(255, 72)
  5778. Case Chr(27) : Undo : Exit Do
  5779. Case Chr(13)
  5780. If Len(buffer) = 0 Then Undo
  5781. Exit Do
  5782. End Select
  5783. If addthing Then
  5784. addthing = 0
  5785. End If
  5786. Loop
  5787. Do
  5788. GetMouse 0, 0, 0, bm
  5789. Loop Until bm = 0
  5790. End Sub
  5791. Sub ChangeTrackDirectory(d As String)
  5792. Dim i As Short
  5793. #ifndef __FB_LINUX__
  5794. If Len(d) = 2 And Right(d, 1) = ":" Then
  5795. track_path = UCase(d) + "\"
  5796. Exit Sub
  5797. End If
  5798. #endif
  5799. If d <> ".." Then
  5800. #ifdef __FB_LINUX__
  5801. track_path = track_path + d + "/"
  5802. #else
  5803. track_path = track_path + d + "\"
  5804. #endif
  5805. Exit Sub
  5806. End If
  5807. For i = Len(track_path) - 1 To 1 Step -1
  5808. #ifdef __FB_LINUX__
  5809. If Mid(track_path, i, 1) = "/" Then
  5810. #else
  5811. If Mid(track_path, i, 1) = "\" Then
  5812. #endif
  5813. track_path = Left(track_path, i)
  5814. Exit Sub
  5815. End If
  5816. Next i
  5817. track_path = CurDir
  5818. #ifdef __FB_LINUX__
  5819. If Right(track_path, 1) <> "/" Then track_path = track_path + "/"
  5820. #else
  5821. If Right(track_path, 1) <> "\" Then track_path = track_path + "\"
  5822. #endif
  5823. End Sub
  5824. 'Convert 32bit to 16bit colour or vice-versa in string form
  5825. Function ConvertColour(c As String) As String
  5826. Dim As UByte r, g, b
  5827. Dim s As UShort, l As ULong
  5828. Dim t As String
  5829. If Len(c) = 2 Then
  5830. s = CvShort(c)
  5831. If s = &B1111100000011111 Then
  5832. 'Transparent colour translates to no colouration
  5833. t = MkL(0)
  5834. Else
  5835. r = (s ShR 8) And &B11111000
  5836. g = (s ShR 3) And &B11111100
  5837. b = (s ShL 3) And &B11111000
  5838. t = MkL(RGB(r, g, b))
  5839. End If
  5840. ElseIf Len(c) = 4 Then
  5841. l = CvL(c)
  5842. If l Then
  5843. r = (l ShR 19) And &B11111
  5844. g = (l ShR 10) And &B111111
  5845. b = (l ShR 3) And &B11111
  5846. s = r
  5847. s = (s ShL 6) Or g
  5848. s = (s ShL 5) Or b
  5849. t = MkShort(s)
  5850. Else
  5851. 'No colouration translates as transparent colour
  5852. t = MkShort(&B1111100000011111)
  5853. End If
  5854. End If
  5855. Return t
  5856. End Function
  5857. Sub CopyOrCut(cut As Byte = 0)
  5858. If xselect Then
  5859. If xselect > x2select Then Swap xselect, x2select
  5860. If yselect > y2select Then Swap yselect, y2select
  5861. clipboard = GetTrack(xselect, yselect, x2select, y2select)
  5862. 'Update temporary file so as to export clipboard --------
  5863. Dim cllen As Short, f As Integer
  5864. f = FreeFile
  5865. If FileExists(program_path & "clip.tmp") Then
  5866. cllen = FileLen(program_path & "clip.tmp")
  5867. Else
  5868. cllen = 0
  5869. End If
  5870. 'Make sure new length is different from previous one
  5871. 'This will allow Bliss instances to realise the clipboard
  5872. 'was changed without having to open the file
  5873. Open program_path & "clip.tmp" For Output As f : Close f
  5874. Open program_path & "clip.tmp" For Binary Access Write As f
  5875. If cllen <> Len(clipboard) + 1 Then
  5876. Dim b As Byte = 0
  5877. Put #f, , b
  5878. Else
  5879. Dim b As Byte = 1
  5880. Put #f, , b
  5881. b = 0
  5882. Put #f, , b
  5883. End If
  5884. Put #f, , clipboard
  5885. last_cb_file_length = LOF(f)
  5886. Close f
  5887. '------------------------------
  5888. 'xclip = xselect : x2clip = x2select
  5889. 'yclip = yselect : y2clip = y2select
  5890. If cut Then
  5891. For j As Byte = yselect To y2select
  5892. For i As Byte = xselect To x2select
  5893. If affect_terrain Then grid(i, j).land = 0
  5894. If affect_track Then
  5895. If allow_errors Then
  5896. ClearTrack i, j
  5897. Else
  5898. grid(i, j).track = 0
  5899. End If
  5900. End If
  5901. Next i
  5902. Next j
  5903. modified = -1
  5904. End If
  5905. xselect = 0 : DrawTrack
  5906. End If
  5907. End Sub
  5908. Function AntiTimey(t As String) As Long
  5909. Dim n As Short, cents As Long
  5910. Dim s As String
  5911. s = t
  5912. n = InStr(s, ":")
  5913. If n = 0 Then
  5914. cents = 100 * Val(s)
  5915. Return cents
  5916. End If
  5917. cents = ValInt(s) * 6000
  5918. s = Mid(s, n + 1)
  5919. n = InStr(s, ":")
  5920. If n = 0 Then
  5921. cents += 100 * Val(s)
  5922. Return cents
  5923. End If
  5924. cents *= 24
  5925. cents += 6000 * ValInt(s)
  5926. s = Mid(s, n + 1)
  5927. cents += 100 * Val(s)
  5928. Return cents
  5929. End Function
  5930. Sub BuildClosedCircuit
  5931. Dim As UByte corner, straightway, tile
  5932. Dim material As Byte, i As Short, j As Short
  5933. If xselect = 0 Then
  5934. Error_Message "First select a region to build a closed-circuit"
  5935. DrawTrack
  5936. Exit Sub
  5937. End If
  5938. If xselect > x2select Then Swap xselect, x2select
  5939. If yselect > y2select Then Swap yselect, y2select
  5940. If tr(current_brush).material >= 1 And tr(current_brush).material <= 3 Then
  5941. material = tr(current_brush).material
  5942. tile = grid(xselect, yselect).track
  5943. If x2select - xselect > 1 And y2select - yselect > 1 _
  5944. And tr(tile).ctype(0) = 0 And tr(tile).ctype(1) <> 0 _
  5945. And tr(tile).ctype(2) <> 0 And tr(tile).ctype(3) = 0 Then
  5946. 'It's a North-West corner. Find big or small corner of the
  5947. 'same material. If the selection is too narrow, always use
  5948. 'small corners
  5949. For i = 1 To 190
  5950. If tr(i).h = 3 - tr(tile).h And tr(i).ctype(0) = 0 And tr(i).ctype(1) <> 0 _
  5951. And tr(i).ctype(2) <> 0 And tr(i).ctype(3) = 0 _
  5952. And tr(i).material = material Then Exit For
  5953. Next i
  5954. corner = i
  5955. Else
  5956. 'If still not drawn, use small corners
  5957. For i = 1 To 190
  5958. If tr(i).h = 1 And tr(i).ctype(0) = 0 And tr(i).ctype(1) <> 0 _
  5959. And tr(i).ctype(2) <> 0 And tr(i).ctype(3) = 0 _
  5960. And tr(i).material = material Then Exit For
  5961. Next i
  5962. corner = i
  5963. End If
  5964. 'Find a straightway
  5965. For i = 1 To 190
  5966. If Chr(tr(i).entity) = "s" And tr(i).material = material And tr(i).ctype(0) <> 0 Then _
  5967. Exit For
  5968. Next i
  5969. straightway = i
  5970. ElseIf tr(current_brush).entity = ASC("e") Then
  5971. 'It's going to be an elevated circuit
  5972. straightway = current_brush
  5973. If tr(straightway).ctype(0) = 0 Then straightway = tr(straightway).cr
  5974. corner = &H69
  5975. ElseIf tr(current_brush).entity = ASC("a") Then
  5976. 'It's going to be a banked circuit
  5977. straightway = &H30
  5978. corner = &H34
  5979. ElseIf tr(current_brush).entity = ASC("Q") Then
  5980. If tr(current_brush).ctype(0) = 2 OrElse tr(current_brush).ctype(1) = 2 _
  5981. OrElse tr(current_brush).ctype(2) = 2 Then
  5982. straightway = &H67 'It's elevated
  5983. corner = &H69
  5984. Else
  5985. straightway = &H30 'It's banked
  5986. corner = &H34
  5987. End If
  5988. ElseIf tr(current_brush).entity = ASC("b") Then
  5989. straightway = &H6D 'Boulevard (no corners)
  5990. corner = 0
  5991. ElseIf current_brush >= &H97 And current_brush <= &HB2 Then
  5992. ScreenLock 'Scenery - fill with it
  5993. For j = yselect To y2select
  5994. For i = xselect To x2select
  5995. SetTrack i, j, current_brush
  5996. Next i
  5997. Next j
  5998. ScreenUnlock
  5999. Exit Sub
  6000. Else
  6001. Exit Sub 'Can't do anything with this item
  6002. End If
  6003. 'Push to undo buffer
  6004. PushUndo
  6005. If xselect = x2select Then
  6006. 'Draw vertical straightway
  6007. For i = yselect To y2select
  6008. SetTrack xselect, i, straightway
  6009. Next i
  6010. ElseIf yselect = y2select Then
  6011. 'Draw horizontal straightway
  6012. straightway = tr(straightway).cr
  6013. For i = xselect To x2select
  6014. SetTrack i, yselect, straightway
  6015. Next i
  6016. Else
  6017. 'Draw corners
  6018. SetTrack xselect, yselect, corner : corner = tr(corner).cr
  6019. SetTrack x2select - tr(corner).w + 1, yselect, corner : corner = tr(corner).cr
  6020. SetTrack x2select - tr(corner).w + 1, y2select - tr(corner).h + 1, corner : corner = tr(corner).cr
  6021. SetTrack xselect, y2select - tr(corner).h + 1, corner
  6022. 'Draw straightways
  6023. For i = yselect + tr(corner).h To y2select - tr(corner).h
  6024. SetTrack xselect, i, straightway
  6025. Next i
  6026. straightway = tr(straightway).cr
  6027. For i = xselect + tr(corner).w To x2select - tr(corner).w
  6028. SetTrack i, yselect, straightway
  6029. Next i
  6030. straightway = tr(straightway).cr
  6031. For i = yselect + tr(corner).h To y2select - tr(corner).h
  6032. SetTrack x2select, i, straightway
  6033. Next i
  6034. straightway = tr(straightway).cr
  6035. For i = xselect + tr(corner).w To x2select - tr(corner).w
  6036. SetTrack i, y2select, straightway
  6037. Next i
  6038. End If
  6039. DrawTrack
  6040. End Sub
  6041. Function CCRotate(t As String) As String
  6042. Dim As Byte w, h, c
  6043. h = ASC(Left(t, 1))
  6044. w = ASC(Mid(t, 2, 1))
  6045. Dim temp(1 To w, 1 To h) As SGrid
  6046. Dim s As String, i As Byte, j As Byte, n As Short
  6047. 'Read and rotate
  6048. n = 3 : i = 1 : j = h
  6049. Do While n <= Len(t)
  6050. c = ASC(Mid(t, n, 1))
  6051. n += 1
  6052. If c And 1 Then 'Track is non-zero
  6053. temp(i, j).track = tr(ASC(Mid(t, n, 1))).ccr
  6054. n += 1
  6055. End If
  6056. If c And 2 Then 'Terrain is non-zero
  6057. temp(i, j).land = ttr(ASC(Mid(t, n, 1))).ccr
  6058. n += 1
  6059. End If
  6060. If c And 4 Then 'Border colour is non-zero
  6061. temp(i, j).border = CvL(Mid(t, n, 4))
  6062. n += 4
  6063. End If
  6064. If c And 8 Then 'Background colour is non-zero
  6065. temp(i, j).bgc = CvL(Mid(t, n, 4))
  6066. n += 4
  6067. End If
  6068. j -= 1
  6069. If j = 0 Then i += 1 : j = h
  6070. Loop
  6071. 'Fix
  6072. For j = 1 To h
  6073. For i = 1 To w
  6074. If tr(temp(i, j).track).w = 2 And tr(temp(i, j).track).h = 2 Then
  6075. If j > 1 Then
  6076. temp(i, j - 1).track = temp(i, j).track
  6077. If i < w then temp(i + 1, j - 1).track = 255
  6078. End If
  6079. If i < w Then temp(i + 1, j).track = 253
  6080. temp(i, j).track = 254
  6081. ElseIf tr(temp(i, j).track).w = 2 Then
  6082. If i < w Then temp(i + 1, j).track = 255
  6083. ElseIf tr(temp(i, j).track).h = 2 Then
  6084. If j > 1 Then temp(i, j - 1).track = temp(i, j).track
  6085. temp(i, j).track = 254
  6086. End If
  6087. Next i
  6088. Next j
  6089. 'Put back into the string
  6090. s = PackedClip(temp())
  6091. Return s
  6092. End Function
  6093. Function CRotate(t As String) As String
  6094. Dim As Byte w, h, c
  6095. h = ASC(Left(t, 1))
  6096. w = ASC(Mid(t, 2, 1))
  6097. Dim temp(1 To w, 1 To h) As SGrid
  6098. Dim s As String, i As Byte, j As Byte, n As Short
  6099. 'Read and rotate
  6100. n = 3 : i = w : j = 1
  6101. Do While n <= Len(t)
  6102. c = ASC(Mid(t, n, 1))
  6103. n += 1
  6104. If c And 1 Then 'Track is non-zero
  6105. temp(i, j).track = tr(ASC(Mid(t, n, 1))).cr
  6106. n += 1
  6107. End If
  6108. If c And 2 Then 'Terrain is non-zero
  6109. temp(i, j).land = ttr(ASC(Mid(t, n, 1))).cr
  6110. n += 1
  6111. End If
  6112. If c And 4 Then 'Border colour is non-zero
  6113. temp(i, j).border = CvL(Mid(t, n, 4))
  6114. n += 4
  6115. End If
  6116. If c And 8 Then 'Background colour is non-zero
  6117. temp(i, j).bgc = CvL(Mid(t, n, 4))
  6118. n += 4
  6119. End If
  6120. j += 1
  6121. If j > h Then i -= 1 : j = 1
  6122. Loop
  6123. 'Fix
  6124. For j = 1 To h
  6125. For i = 1 To w
  6126. If tr(temp(i, j).track).w = 2 And tr(temp(i, j).track).h = 2 Then
  6127. If i > 1 Then
  6128. temp(i - 1, j).track = temp(i, j).track
  6129. If j < h then Temp(i - 1, j + 1).track = 254
  6130. End If
  6131. If j < h Then temp(i, j + 1).track = 253
  6132. temp(i, j).track = 255
  6133. ElseIf tr(temp(i, j).track).w = 2 Then
  6134. If i > 1 Then temp(i - 1, j).track = temp(i, j).track
  6135. temp(i, j).track = 255
  6136. ElseIf tr(temp(i, j).track).h = 2 Then
  6137. If j < h Then temp(i, j + 1).track = 254
  6138. End If
  6139. Next i
  6140. Next j
  6141. 'Put back into the string
  6142. s = PackedClip(temp())
  6143. Return s
  6144. End Function
  6145. Sub DetectDrives
  6146. Dim i As Byte
  6147. For i = 3 To 26
  6148. Open Chr(64 + i) + ":\NUL" For Input As 101
  6149. If Err = 0 Then
  6150. fileys += 1
  6151. filey(fileys) = "*" + Chr(64 + i) + ":"
  6152. Close 101
  6153. End If
  6154. Next i
  6155. End Sub
  6156. Sub SmartSelect(etype As String, direction As Byte = 1)
  6157. Dim As Byte checkconnections = -1, checkmaterial = -1
  6158. Dim As Byte connector(0 To 3), material
  6159. Dim i As Short
  6160. 'Check to see if there are open connectors
  6161. If vlast.x = 0 Or vlast.y = 0 OrElse grid(vlast.x, vlast.y).track = 0 Then
  6162. 'Nothing has yet been placed or there's an empty space there
  6163. checkconnections = 0
  6164. material = tr(current_brush).material
  6165. If material = 0 Then checkmaterial = 0
  6166. Else
  6167. Dim n As UByte = GetParent(vlast.x, vlast.y)
  6168. material = tr(n).material
  6169. If material = 0 Then checkmaterial = 0
  6170. 'Check North
  6171. If vlast.y > 1 AndAlso grid(vlast.x + tr(n).cisalt(0), vlast.y - 1).track = 0 Then _
  6172. connector(2) = tr(n).ctype(0)
  6173. 'Check East
  6174. If vlast.x <= 30 - tr(n).w AndAlso grid(vlast.x + tr(n).w, vlast.y + tr(n).cisalt(1)).track = 0 Then _
  6175. connector(3) = tr(n).ctype(1)
  6176. 'Check South
  6177. If vlast.y <= 30 - tr(n).h AndAlso grid(vlast.x + tr(n).cisalt(2), vlast.y + tr(n).h).track = 0 Then _
  6178. connector(0) = tr(n).ctype(2)
  6179. 'Check West
  6180. If vlast.x > 1 AndAlso grid(vlast.x - 1, vlast.y + tr(n).cisalt(3)).track = 0 Then _
  6181. connector(1) = tr(n).ctype(3)
  6182. 'If no connector, then don't check
  6183. If connector(0) + connector(1) + connector(2) + connector(3) = 0 Then checkconnections = 0
  6184. End If
  6185. Dim As Short searchstart, searchend
  6186. Dim q As Byte
  6187. 'Prepare to search left or right
  6188. If direction > 0 Then
  6189. searchstart = current_brush + 1
  6190. searchend = current_brush + 256
  6191. Else
  6192. searchstart = current_brush + 255
  6193. searchend = current_brush
  6194. End If
  6195. 'Try to find a coincidence. First for everything, then go
  6196. 'eliminating restrictions
  6197. Do
  6198. For i = searchstart To searchend Step direction
  6199. Dim n As UByte
  6200. n = i Mod 256
  6201. 'See if type matches
  6202. If UCase(Chr(tr(n).entity)) = UCase(etype) Then
  6203. q = 0
  6204. If checkconnections Then
  6205. For j As Byte = 0 To 3
  6206. If connector(j) <> 0 And tr(n).ctype(j) = connector(j) Then
  6207. q = -1 'At least one connector matches
  6208. Exit For
  6209. End If
  6210. Next j
  6211. Else
  6212. q = -1 'Not checking connections, so assume OK
  6213. End If
  6214. If checkmaterial Then
  6215. If tr(n).material <> material Then q = 0
  6216. End If
  6217. If q Then Exit For 'Everything matches
  6218. End If
  6219. Next i
  6220. If q Then Exit Do
  6221. 'See what we can give up to obtain a result
  6222. If checkmaterial Then
  6223. checkmaterial = 0 'Give up checking material
  6224. ElseIf checkconnections Then
  6225. checkconnections = 0 'Give up checking connections
  6226. Else
  6227. Exit Do 'Couldn't find anything
  6228. End If
  6229. Loop
  6230. If q Then
  6231. current_brush = i
  6232. DrawPanel
  6233. End If
  6234. End Sub
  6235. Sub SolvePath(pn As Short)
  6236. Dim As UByte thissection, c1, c2
  6237. thissection = ASC(Right(path(pn).p, 1))
  6238. 'Propagate errors
  6239. If section(thissection).errors Then
  6240. If section(thissection).e >= 40 Then
  6241. 'Path-fatal errors. Path ends here
  6242. path(pn).e = section(thissection).e
  6243. Exit Sub
  6244. Else
  6245. 'Prioritise early errors if not path-fatal (warnings)
  6246. If path(pn).e = 0 Then path(pn).e = section(thissection).e
  6247. End If
  6248. End If
  6249. 'See if it ends at the finish line
  6250. If section(thissection).final = section(1).initial Then
  6251. path(pn).finishes = -1
  6252. Exit Sub
  6253. End If
  6254. c1 = section(thissection).child(0)
  6255. c2 = section(thissection).child(1)
  6256. If c2 = 0 Then
  6257. If c1 = 0 Then 'No child (weird)
  6258. Exit Sub
  6259. Else 'Joint (one child)
  6260. If InStr(path(pn).p, Chr(c1)) Then 'It's a cycle!
  6261. path(pn).e = 82
  6262. Exit Sub
  6263. End If
  6264. path(pn).p &= Chr(c1)
  6265. SolvePath pn
  6266. End If
  6267. Else 'Split (two children)
  6268. If paths = MAXPATHS Then Exit Sub
  6269. paths += 1
  6270. path(paths).p = path(pn).p
  6271. path(paths).e = path(pn).e
  6272. path(paths).finishes = path(pn).finishes
  6273. path(pn).p &= Chr(c1)
  6274. path(paths).p &= Chr(c2)
  6275. SolvePath paths
  6276. SolvePath pn
  6277. End If
  6278. End Sub
  6279. 'Analyse a section of the track, finding errors and handling
  6280. 'split points recursively. Save information in the sections array
  6281. Sub SolveSection(sn As Short)
  6282. Dim As TrackVector v, oldv
  6283. Dim As Short i, n
  6284. v.coors = section(sn).initial
  6285. v.bearing = section(sn).bearing
  6286. v.origin = section(sn).origin
  6287. section(sn).e = 0
  6288. section(sn).errors = 0
  6289. section(sn).solving = -1
  6290. section(sn).finishes = 0
  6291. section(sn).cycle = 0
  6292. section(sn).final = 0
  6293. section(sn).wrongway = 0
  6294. Do
  6295. oldv = v
  6296. v = GetNext(v)
  6297. If v.e Then
  6298. terrors += 1
  6299. terror(terrors).coors = oldv.coors
  6300. terror(terrors).e = v.e
  6301. terror(terrors).section = sn
  6302. End If
  6303. Select Case v.e
  6304. Case 70 To 79 'Path flow fatal errors
  6305. If section(sn).e < 40 Then section(sn).e = v.e
  6306. section(sn).errors = -1
  6307. section(sn).solving = 0
  6308. section(sn).final = oldv.coors
  6309. section(sn).child(0) = 0
  6310. section(sn).child(1) = 0
  6311. Exit Do
  6312. Case 80 To 89 'Path flow non-fatal errors
  6313. If section(sn).e = 0 Then section(sn).e = v.e
  6314. section(sn).errors = -1
  6315. section(sn).solving = 0
  6316. section(sn).final = oldv.coors
  6317. section(sn).child(0) = 0
  6318. section(sn).child(1) = 0
  6319. Exit Do
  6320. Case 20 To 39 'Warnings
  6321. If section(sn).e = 0 Then section(sn).e = v.e
  6322. section(sn).errors = -1
  6323. End Select
  6324. 'Found finish line
  6325. If v.coors = section(1).initial Then
  6326. section(sn).final = v.coors
  6327. section(sn).child(0) = 0
  6328. section(sn).child(1) = 0
  6329. section(sn).finishes = -1
  6330. Exit Do
  6331. End If
  6332. 'Reached a split?
  6333. n = 0
  6334. For i = 0 To 3 'Count number of connectors
  6335. If tr(grid(v.x, v.y).track).ctype(i) Then n += 1
  6336. Next i
  6337. 'Yes. It's a split
  6338. If n = 3 Then
  6339. section(sn).final = v.coors
  6340. 'See if this is a previously solved node
  6341. For i = 1 To sections
  6342. If v.coors = section(i).initial Then
  6343. If 2 ^ section(i).bearing <> tr(grid(v.x, v.y).track).cto(v.bearing XOr 2) Then
  6344. 'Make sure it ends here
  6345. section(sn).child(0) = 0
  6346. section(sn).child(1) = 0
  6347. 'Wrong way!
  6348. section(sn).wrongway = -1
  6349. section(sn).errors = -1
  6350. If section(sn).e < 40 Then section(sn).e = 72
  6351. terrors += 1
  6352. terror(terrors).coors = v.coors
  6353. terror(terrors).e = 72
  6354. terror(terrors).section = sn
  6355. ElseIf section(i).solving Then
  6356. 'Make sure it ends here
  6357. section(sn).child(0) = 0
  6358. section(sn).child(1) = 0
  6359. 'This is a cycle!
  6360. section(sn).cycle = -1
  6361. If section(sn).e < 40 Then section(sn).e = 82
  6362. terrors += 1
  6363. terror(terrors).coors = v.coors
  6364. terror(terrors).e = 82
  6365. terror(terrors).section = sn
  6366. Else
  6367. 'Connect sections
  6368. section(sn).child(0) = i
  6369. section(sn).child(1) = 0
  6370. section(i).parent(1) = sn
  6371. 'Inherit child's errors and finish status
  6372. section(sn).finishes = section(i).finishes
  6373. section(sn).cycle = section(i).cycle
  6374. section(sn).wrongway = section(i).wrongway
  6375. If section(sn).e < 40 Then section(sn).e = section(i).e
  6376. End If
  6377. section(sn).solving = 0
  6378. Exit Do
  6379. End If
  6380. Next i
  6381. 'It's a new node
  6382. n = tr(grid(v.x, v.y).track).cto(v.bearing XOr 2)
  6383. Select Case n
  6384. Case 1, 2, 4, 8 'Only one direction
  6385. Dim daughter As Short
  6386. 'Create new section and solve it
  6387. sections += 1
  6388. section(sections).initial = v.coors
  6389. section(sections).bearing = Log(n) / Log(2)
  6390. section(sections).origin = v.origin
  6391. daughter = sections
  6392. SolveSection daughter
  6393. 'Inherit new section's status
  6394. section(sn).finishes = section(daughter).finishes
  6395. section(sn).cycle = section(daughter).cycle
  6396. section(sn).wrongway = section(daughter).wrongway
  6397. If section(sn).e = 0 Then section(sn).e = section(daughter).e
  6398. 'Create parental links
  6399. section(sn).child(0) = daughter
  6400. section(sn).child(1) = 0
  6401. section(sections).parent(0) = sn
  6402. section(sections).parent(1) = 0
  6403. Case Else 'Two directions
  6404. Dim As Short daughter(1 To 2), daughters = 0
  6405. 'Always solve the straight node first
  6406. For i = v.bearing To v.bearing + 3
  6407. Dim direction As Byte
  6408. direction = i Mod 4
  6409. If direction <> (v.bearing XOr 2) And _
  6410. tr(grid(v.x, v.y).track).ctype(direction) <> 0 Then
  6411. 'Create each node and solve it
  6412. sections += 1
  6413. If sections > 254 Then Exit Sub
  6414. section(sections).initial = v.coors
  6415. section(sections).bearing = direction
  6416. section(sections).origin = v.origin
  6417. daughters += 1
  6418. daughter(daughters) = sections
  6419. SolveSection sections
  6420. End If
  6421. Next i
  6422. 'Carefully inherit the status
  6423. If section(daughter(1)).finishes Or section(daughter(2)).finishes Then _
  6424. section(sn).finishes = -1
  6425. If section(daughter(1)).cycle And section(daughter(2)).cycle Then _
  6426. section(sn).cycle = -1
  6427. If section(sn).e = 0 Then
  6428. section(sn).e = section(daughter(1)).e
  6429. If section(sn).e = 0 Or section(daughter(2)).e = 4 Then section(sn).e = section(daughter(2)).e
  6430. End If
  6431. If section(daughter(1)).wrongway And section(daughter(2)).wrongway Then _
  6432. section(sn).wrongway = -1
  6433. 'Create parental links
  6434. section(sn).child(0) = daughter(1)
  6435. section(sn).child(1) = daughter(2)
  6436. section(daughter(1)).parent(0) = sn
  6437. section(daughter(1)).parent(1) = 0
  6438. section(daughter(2)).parent(0) = sn
  6439. section(daughter(2)).parent(1) = 0
  6440. End Select
  6441. Exit Do
  6442. End If
  6443. Loop
  6444. section(sn).solving = 0
  6445. End Sub
  6446. Sub SortFiles
  6447. Dim changes As Byte
  6448. Dim i As Short
  6449. 'For now, we use bubble sort
  6450. 'First sort by name
  6451. Do
  6452. changes = 0
  6453. For i = 1 To fileys - 1
  6454. If LCase(filey(i)) > LCase(filey(i + 1)) Then
  6455. Swap filey(i), filey(i + 1)
  6456. changes = -1
  6457. End If
  6458. Next i
  6459. Loop Until changes = 0
  6460. 'Then place directories first
  6461. Do
  6462. changes = 0
  6463. For i = 1 To fileys - 1
  6464. If Left(filey(i), 1) <> "*" And Left(filey(i + 1), 1) = "*" Then
  6465. Swap filey(i), filey(i + 1)
  6466. changes = -1
  6467. End If
  6468. Next i
  6469. Loop Until changes = 0
  6470. #ifndef __FB_LINUX__
  6471. 'Finally, place drives after directories
  6472. Do
  6473. changes = 0
  6474. For i = 1 To fileys - 1
  6475. If Left(filey(i), 1) = "*" And Left(filey(i + 1), 1) = "*" Then
  6476. If Right(filey(i), 1) = ":" And Right(filey(i + 1), 1) <> ":" Then
  6477. Swap filey(i), filey(i + 1)
  6478. changes = -1
  6479. End If
  6480. Else
  6481. Exit For
  6482. End If
  6483. Next i
  6484. Loop Until changes = 0
  6485. #endif
  6486. End Sub
  6487. Sub LoadTransformations
  6488. Dim As Short x, y, p
  6489. Open program_path + "xlation.dat" For Binary Access Read As 100
  6490. For x = 0 To 255
  6491. Get #100, , tr(x)
  6492. Next x
  6493. For x = 0 To 18
  6494. Get #100, , ttr(x)
  6495. Next x
  6496. For p = 0 To 11
  6497. For y = 0 To 5
  6498. For x = 0 To 5
  6499. Get #100, , itr(x, y, p)
  6500. Next x
  6501. Next y
  6502. Next p
  6503. Close 100
  6504. End Sub
  6505. Sub SaveTransformations
  6506. Dim As Short x, y, p
  6507. Open program_path + "xlation.dat" For Binary Access Write As 100
  6508. For x = 0 To 255
  6509. Put #100, , tr(x)
  6510. Next x
  6511. For x = 0 To 18
  6512. Put #100, , ttr(x)
  6513. Next x
  6514. For p = 0 To 11
  6515. For y = 0 To 5
  6516. For x = 0 To 5
  6517. Put #100, , itr(x, y, p)
  6518. Next x
  6519. Next y
  6520. Next p
  6521. Close 100
  6522. End Sub
  6523. #ifndef __FB_DOS__
  6524. Function TMT_GetCurrentTrack(taddress As String) As Byte
  6525. Dim mysite As ZString Ptr, length As Long
  6526. Dim baseaddr As String, descfile As ZString Ptr
  6527. Dim As Short n, m
  6528. Dim trackfn As String, tbinary As UByte Ptr
  6529. Dim As Byte i, j
  6530. Dim As String title, author
  6531. MenuBox 25, 10, "Getting current track"
  6532. lefx += 16
  6533. TLeft
  6534. If InStr(LCase(taddress), "stunts.hu") Then
  6535. TLeft , "Trying to connect to ZakStunts...", RGB(160, 160, 240)
  6536. length = HTTP_Download("zak.stunts.hu/track.json", mysite)
  6537. If length < 0 Then Return -1
  6538. n = InStr(*mysite, "file" & Chr(34))
  6539. Dim tempstring As String
  6540. tempstring = Mid(*mysite, n + 7, 200)
  6541. trackfn = ""
  6542. For i As Short = 1 To Len(tempstring)
  6543. Select Case Mid(tempstring, i, 1)
  6544. Case "\"
  6545. Case Chr(34) : Exit For
  6546. Case Else : trackfn &= Mid(tempstring, i, 1)
  6547. End Select
  6548. Next i
  6549. n = InStr(*mysite, Chr(34) + "track" + Chr(34))
  6550. m = InStr(n + 1, *mysite, Chr(34) + "name" + Chr(34))
  6551. If m Then
  6552. m += 6
  6553. m = InStr(m, *mysite, "-") + 1
  6554. n = InStr(m + 1, *mysite, Chr(34))
  6555. title = Mid(*mysite, m + 1, n - m - 1)
  6556. Else
  6557. title = ""
  6558. End If
  6559. n = InStr(*mysite, "author" + Chr(34))
  6560. If n Then
  6561. n += 9
  6562. m = InStr(n, *mysite, Chr(34))
  6563. author = Mid(*mysite, n, m - n)
  6564. End If
  6565. Deallocate mysite : mysite = 0
  6566. Else
  6567. TLeft , "Trying to connect to the server...", RGB(160, 160, 240)
  6568. If LCase(Left(taddress, 4)) = "btp:" Then
  6569. baseaddr = Mid(taddress, 5)
  6570. Else
  6571. baseaddr = taddress
  6572. End If
  6573. length = HTTP_Download(baseaddr + "/tour.cfg", descfile)
  6574. If length < 0 Then Return -1
  6575. If LCase(Left(*descfile, 4)) <> "tour" Then Return -1
  6576. n = InStr(*descfile, "tracktitle=")
  6577. If n Then
  6578. n += 11
  6579. m = InStr(n, *descfile, Chr(10))
  6580. If m Then
  6581. title = Mid(*descfile, n, m - n)
  6582. If Right(title, 1) = Chr(13) Then title = Left(title, Len(title) - 1)
  6583. End If
  6584. End If
  6585. n = InStr(*descfile, "trackauthor=")
  6586. If n Then
  6587. n += 12
  6588. m = InStr(n, *descfile, Chr(10))
  6589. If m Then
  6590. author = Mid(*descfile, n, m - n)
  6591. If Right(author, 1) = Chr(13) Then author = Left(author, Len(author) - 1)
  6592. End If
  6593. End If
  6594. n = InStr(*descfile, "trackfile=")
  6595. If n Then
  6596. n += 10
  6597. m = InStr(n, *descfile, Chr(10))
  6598. If m Then
  6599. trackfn = Mid(*descfile, n, m - n)
  6600. If Right(trackfn, 1) = Chr(13) Then trackfn = Left(trackfn, Len(trackfn) - 1)
  6601. End If
  6602. End If
  6603. If InStr(trackfn, ".") = 0 Then trackfn &= ".trk"
  6604. Deallocate descfile : descfile = 0
  6605. End If
  6606. Dim baretrackname As String, slashpos As Short
  6607. slashpos = InStrRev(trackfn, "/")
  6608. If slashpos Then baretrackname = Mid(trackfn, slashpos + 1) Else baretrackname = trackfn
  6609. TLeft , "Downloading '" + baretrackname + "'...", RGB(160, 160, 240)
  6610. If InStr(LCase(taddress), "stunts.hu") Then
  6611. length = HTTP_Download(trackfn, tbinary)
  6612. Else
  6613. length = HTTP_Download(baseaddr + "/" + trackfn, tbinary)
  6614. End If
  6615. If length < 0 OrElse (InStr(LCase(taddress), "stunts.hu") <> 0 And length <> 1802) Then
  6616. DrawTrack
  6617. Print length
  6618. Error_Message "Could not download the track " + trackfn
  6619. Return -1
  6620. End If
  6621. n = InStrRev(trackfn, "/")
  6622. If n Then trackfn = Mid(trackfn, n + 1)
  6623. n = InStrRev(trackfn, "\")
  6624. If n Then trackfn = Mid(trackfn, n + 1)
  6625. n = 0
  6626. For j = 30 To 1 Step -1
  6627. For i = 1 To 30
  6628. grid(i, j).track = tbinary[n]
  6629. n += 1
  6630. Next i
  6631. Next j
  6632. landscape = tbinary[n]
  6633. n += 1
  6634. For j = 1 To 30
  6635. For i = 1 To 30
  6636. grid(i, j).land = tbinary[n]
  6637. n += 1
  6638. Next i
  6639. Next j
  6640. format_byte = tbinary[n]
  6641. PushUndo
  6642. If length > 1802 Then
  6643. Dim s As String
  6644. For i = 1 To length - 1802
  6645. s &= Chr(tbinary[i + 1801])
  6646. Next i
  6647. LoadMetaData , s
  6648. Else
  6649. meta.title = title
  6650. meta.author = author
  6651. meta.cyear = 0
  6652. meta.cmonth = 0
  6653. meta.cday = 0
  6654. Select Case format_byte
  6655. Case 0
  6656. meta.tool = "Track Blaster"
  6657. meta.toolversion = 50300
  6658. Case 150
  6659. meta.tool = "Bliss"
  6660. meta.toolversion = 20100
  6661. Case 151, 152
  6662. meta.tool = "Bliss"
  6663. meta.toolversion = 20400
  6664. Case Else
  6665. meta.tool = "Unknown"
  6666. meta.toolversion = 0
  6667. End Select
  6668. meta.comment = ""
  6669. If LCase(Trim(taddress)) = "zak.stunts.hu" Then
  6670. meta.championship = "ZakStunts " + UCase(Left(trackfn, 6))
  6671. Else
  6672. meta.championship = ""
  6673. End If
  6674. meta.editing_time = -1
  6675. End If
  6676. Deallocate tbinary
  6677. modified = -1
  6678. track_file = LCase(trackfn)
  6679. UpdateTitleBar
  6680. DrawTrack
  6681. Return 0
  6682. End Function
  6683. Function TMT_GetMain(taddress As String, ByRef curtrack As String, ByRef deadline As String) As Byte
  6684. Dim zaksite As ZString Ptr, length As Long
  6685. Dim As String title, author
  6686. Dim As Short n, m
  6687. Dim trackfn As String
  6688. If LCase(Trim(taddress)) = "zak.stunts.hu" Then 'Use Zak's Protocol
  6689. ' length = HTTP_Download("zak.stunts.hu/", zaksite, -1)
  6690. '
  6691. ' If length < 0 Then Return -1
  6692. '
  6693. ' n = InStr(*zaksite, "zct")
  6694. ' trackfn = "ZCT" + Mid(*zaksite, n + 3, 3)
  6695. ' n = InStr(n + 1, *zaksite, "-")
  6696. ' m = InStr(n, *zaksite, "<")
  6697. ' If n <> 0 And m <> 0 And m > n Then
  6698. ' title = Mid(*zaksite, n + 2, m - n - 2)
  6699. ' title = Trim(title)
  6700. ' n = InStr(m, *zaksite, ">")
  6701. ' If n Then
  6702. ' m = InStr(n, *zaksite, ";")
  6703. ' If m Then
  6704. ' n = InStr(m, *zaksite, "<")
  6705. ' If n Then author = Trim(Mid(*zaksite, m + 1, n - m - 1))
  6706. ' End If
  6707. ' End If
  6708. ' End If
  6709. '
  6710. ' n = InStr(*zaksite, "deadline" + Chr(34) + ">")
  6711. ' If n = 0 Then
  6712. ' deadline = "Unknown"
  6713. ' Else
  6714. ' n += 10
  6715. ' m = InStr(n, *zaksite, "<")
  6716. ' deadline = Trim(Mid(*zaksite, n, m - n))
  6717. ' End If
  6718. length = HTTP_Download("zak.stunts.hu/track.json", zaksite)
  6719. If length < 0 Then Return -1
  6720. n = InStr(*zaksite, "ZCT")
  6721. trackfn = "ZCT" + Mid(*zaksite, n + 3, 3) + ".trk"
  6722. m = InStr(n + 1, *zaksite, "-")
  6723. If m Then
  6724. n = InStr(m + 1, *zaksite, Chr(34))
  6725. title = Mid(*zaksite, m + 2, n - m - 2)
  6726. End If
  6727. n = InStr(*zaksite, "author" + Chr(34))
  6728. If n Then
  6729. n += 9
  6730. m = InStr(n, *zaksite, Chr(34))
  6731. author = Mid(*zaksite, n, m - n)
  6732. End If
  6733. n = InStr(*zaksite, "deadline" + Chr(34))
  6734. If n Then
  6735. n += 11
  6736. m = InStr(n, *zaksite, Chr(34))
  6737. deadline = Mid(*zaksite, n, m - n)
  6738. End If
  6739. Deallocate zaksite : zaksite = 0
  6740. If Len(title) Then
  6741. curtrack = title
  6742. If Len(author) Then curtrack &= " (by " + author + ")"
  6743. Else
  6744. curtrack = trackfn
  6745. End If
  6746. Return 0
  6747. Else 'Use Bliss Tournament Protocol
  6748. Dim baseaddr As String, descfile As ZString Ptr
  6749. If LCase(Left(taddress, 4)) = "btp:" Then
  6750. baseaddr = Mid(taddress, 5)
  6751. Else
  6752. baseaddr = taddress
  6753. End If
  6754. length = HTTP_Download(baseaddr + "/tour.cfg", descfile)
  6755. If length < 0 Then Return -1
  6756. If LCase(Left(*descfile, 4)) <> "tour" Then Return -1
  6757. n = InStr(*descfile, "tracktitle=")
  6758. If n Then
  6759. n += 11
  6760. m = InStr(n, *descfile, Chr(10))
  6761. If m Then
  6762. title = Mid(*descfile, n, m - n)
  6763. If Right(title, 1) = Chr(13) Then title = Left(title, Len(title) - 1)
  6764. End If
  6765. End If
  6766. n = InStr(*descfile, "trackauthor=")
  6767. If n Then
  6768. n += 12
  6769. m = InStr(n, *descfile, Chr(10))
  6770. If m Then
  6771. author = Mid(*descfile, n, m - n)
  6772. If Right(author, 1) = Chr(13) Then author = Left(author, Len(author) - 1)
  6773. End If
  6774. End If
  6775. n = InStr(*descfile, "trackfile=")
  6776. If n Then
  6777. n += 10
  6778. m = InStr(n, *descfile, Chr(10))
  6779. If m Then
  6780. trackfn = Mid(*descfile, n, m - n)
  6781. If Right(trackfn, 1) = Chr(13) Then trackfn = Left(trackfn, Len(trackfn) - 1)
  6782. End If
  6783. End If
  6784. If InStr(trackfn, ".") = 0 Then trackfn &= ".trk"
  6785. n = InStr(*descfile, "deadline=")
  6786. If n Then
  6787. n += 9
  6788. m = InStr(n, *descfile, Chr(10))
  6789. If m Then
  6790. deadline = Mid(*descfile, n, m - n)
  6791. If Right(deadline, 1) = Chr(13) Then deadline = Left(deadline, Len(deadline) - 1)
  6792. End If
  6793. End If
  6794. Deallocate descfile : descfile = 0
  6795. If Len(title) Then
  6796. curtrack = title
  6797. If Len(author) Then curtrack &= " (by " + author + ")"
  6798. Else
  6799. curtrack = trackfn
  6800. End If
  6801. Return 0
  6802. End If
  6803. End Function
  6804. Function TMT_GetScoreboard(taddress As String, item() As Scoreboard, ByRef items As Byte) As Byte
  6805. If InStr(LCase(Trim(taddress)), "zak.stunts.hu") Then
  6806. 'New scoreboard found at:
  6807. 'zak.stunts.hu/api/races/ZCTxxx/scoreboard
  6808. Dim filestring As ZString Ptr, length As Long, s As String
  6809. Dim As Long n, m, t1, t2
  6810. items = 0
  6811. length = HTTP_Download("zak.stunts.hu/track.json", filestring)
  6812. If length < 0 Then Return -1
  6813. n = InStr(*filestring, "ZCT")
  6814. s = "ZCT" + Mid(*filestring, n + 3, 3)
  6815. length = HTTP_Download("zak.stunts.hu/api/races/" + s + "/scoreboard", filestring)
  6816. If length < 0 Then Return -1
  6817. m = 1
  6818. For i As Byte = 1 To 100
  6819. n = InStr(m, *filestring, Chr(34) + "racer" + Chr(34))
  6820. If n = 0 Then Exit For
  6821. n = InStr(n, *filestring, Chr(34) + "name" + Chr(34))
  6822. n = InStr(n + 6, *filestring, Chr(34))
  6823. m = InStr(n + 1, *filestring, Chr(34))
  6824. item(i).racer = Mid(*filestring, n + 1, m - n - 1)
  6825. n = InStr(m, *filestring, Chr(34) + "model" + Chr(34))
  6826. n = InStr(n + 7, *filestring, Chr(34))
  6827. m = InStr(n + 1, *filestring, Chr(34))
  6828. item(i).car = Mid(*filestring, n + 1, m - n - 1)
  6829. n = InStr(m, *filestring, Chr(34) + "lap_time" + Chr(34))
  6830. n = InStr(n + 10, *filestring, ":")
  6831. m = InStr(n + 1, *filestring, ",")
  6832. t1 = ValInt(Mid(*filestring, n + 1, m - n - 1))
  6833. item(i).realtime = Timey(t1)
  6834. n = InStr(m, *filestring, Chr(34) + "corrected_time" + Chr(34))
  6835. n = InStr(n + 16, *filestring, ":")
  6836. m = InStr(n + 1, *filestring, ",")
  6837. t2 = ValInt(Mid(*filestring, n + 1, m - n - 1))
  6838. item(i).hctime = Timey(t2)
  6839. item(i).handicap = (100 * t2) \ t1 - 100
  6840. items += 1
  6841. If i = UBound(item) Then Exit For
  6842. Next i
  6843. Deallocate filestring
  6844. '~ Dim zaksite As ZString Ptr, length As Long
  6845. '~ Dim trackfn As String
  6846. '~ Dim As Long n, m
  6847. '~ length = HTTP_Download("zak.stunts.hu/", zaksite, -1)
  6848. '~ If length < 0 Then Return -1
  6849. '~ n = InStr(*zaksite, "ZCT")
  6850. '~ trackfn = "ZCT" + Mid(*zaksite, n + 3, 3)
  6851. '~ length = HTTP_Download("zak.stunts.hu/tracks/" + trackfn, zaksite, -1)
  6852. '~ If length < 0 Then Return -1
  6853. '~ If InStr(*zaksite, "No results") Then
  6854. '~ items = 0
  6855. '~ Return 0
  6856. '~ End If
  6857. '~ m = 1
  6858. '~ For i As Byte = 1 To 100
  6859. '~ n = InStr(m, *zaksite, "rank" + Chr(34) + ">" + Trim(Str(i)) + "<")
  6860. '~ If n = 0 Then items = i - 1 : Exit For
  6861. '~ m = InStr(n, *zaksite, "racer" + Chr(34)) + 8
  6862. '~ n = InStr(m, *zaksite, ">") + 1
  6863. '~ m = InStr(n, *zaksite, "<")
  6864. '~ item(i).racer = Trim(Mid(*zaksite, n, m - n))
  6865. '~ n = InStr(m, *zaksite, "time" + Chr(34)) + 6
  6866. '~ m = InStr(n, *zaksite, "<")
  6867. '~ item(i).hctime = Trim(Mid(*zaksite, n, m - n))
  6868. '~ n = InStr(m, *zaksite, "car-image" + Chr(34)) + 16
  6869. '~ m = InStr(n, *zaksite, Chr(34))
  6870. '~ item(i).car = Trim(Mid(*zaksite, n, m - n))
  6871. '~ n = InStr(m, *zaksite, "(") + 1
  6872. '~ m = InStr(n, *zaksite, "%")
  6873. '~ item(i).handicap = ValInt(Mid(*zaksite, n, m - n))
  6874. '~ n = InStr(m, *zaksite, "original-time" + Chr(34)) + 15
  6875. '~ m = InStr(n, *zaksite, "<")
  6876. '~ item(i).realtime = Trim(Mid(*zaksite, n, m - n))
  6877. '~ n = m + 1
  6878. '~ If i = UBound(item) Then items = i : Exit For
  6879. '~ Next i
  6880. Else
  6881. Dim baseaddr As String, scfile As UByte Ptr, tourfile As ZString Ptr
  6882. Dim length As Long, i As Short, n As Short, s As String
  6883. Dim sbfname As String
  6884. If LCase(Left(taddress, 5)) = "btp:" Then
  6885. baseaddr = Mid(taddress, 6)
  6886. Else
  6887. baseaddr = taddress
  6888. End If
  6889. length = HTTP_Download(baseaddr + "/tour.cfg", tourfile)
  6890. If length < 0 Then Return -1
  6891. If LCase(Left(*tourfile, 4)) <> "tour" Then Return -1
  6892. Dim m As Long
  6893. n = InStr(*tourfile, "scoreboard=")
  6894. If n Then
  6895. n += 11
  6896. m = InStr(n, *tourfile, Chr(10))
  6897. If m Then
  6898. sbfname = Mid(*tourfile, n, m - n)
  6899. If Right(sbfname, 1) = Chr(13) Then sbfname = Left(sbfname, Len(sbfname) - 1)
  6900. End If
  6901. End If
  6902. Deallocate tourfile : tourfile = 0
  6903. length = HTTP_Download(baseaddr + "/" + sbfname, scfile)
  6904. If length = 0 Then
  6905. items = 0
  6906. Return 0
  6907. End if
  6908. 'Skip all control characters other than character 10
  6909. s = ""
  6910. For i = 0 To length - 1
  6911. If scfile[i] >= 32 Or scfile[i] = 10 Then s &= Chr(scfile[i])
  6912. Next i
  6913. Deallocate scfile : scfile = 0
  6914. Dim sbx As Scoreboard, l As String
  6915. Dim pass As Byte
  6916. items = 0
  6917. Do While Len(s)
  6918. n = InStr(s, Chr(10))
  6919. If n Then
  6920. l = Left(s, n - 1)
  6921. s = Mid(s, n + 1)
  6922. Else
  6923. l = s
  6924. s = ""
  6925. End If
  6926. l = Trim(l)
  6927. If Left(l, 1) = "[" And Right(l, 1) = "]" Then
  6928. If pass <> 0 Then
  6929. items += 1
  6930. item(items) = sbx
  6931. Else
  6932. sbx.racer = "Unknown"
  6933. sbx.car = "????"
  6934. sbx.realtime = ""
  6935. sbx.hctime = ""
  6936. sbx.style = ""
  6937. sbx.handicap = 0
  6938. sbx.verified = 0
  6939. pass = -1
  6940. End If
  6941. ElseIf InStr(l, "=") Then
  6942. Dim As String varid, v
  6943. varid = LCase(RTrim(Left(l, InStr(l, "=") - 1)))
  6944. v = LTrim(Mid(l, InStr(l, "=") + 1))
  6945. Select Case varid
  6946. Case "carid", "car" : sbx.car = v
  6947. Case "name" : sbx.racer = v
  6948. Case "lap" : sbx.realtime = Timey((ValInt(v) - 1828 - 20) * 5)
  6949. Case "laptime" : sbx.realtime = v
  6950. Case "style" : sbx.style = v
  6951. Case "handicap" : sbx.handicap = ValInt(v)
  6952. Case "competing"
  6953. If LCase(v) <> "yes" Then pass = 0
  6954. Case "status"
  6955. If LCase(v) = "verified" Then
  6956. sbx.verified = -1
  6957. ElseIf LCase(v) = "rejected" Then
  6958. pass = 0
  6959. End If
  6960. End Select
  6961. End If
  6962. Loop
  6963. If pass <> 0 Then
  6964. items += 1
  6965. item(items) = sbx
  6966. End If
  6967. End If
  6968. 'Make sure the values are valid
  6969. For i As Byte = 1 To items
  6970. item(i).racer = Left(item(i).racer, 20)
  6971. item(i).hctime = Left(item(i).hctime, 8)
  6972. item(i).car = Left(item(i).car, 10)
  6973. item(i).realtime = Left(item(i).realtime, 8)
  6974. If item(i).handicap < -100 Then
  6975. item(i).handicap = -100
  6976. ElseIf item(i).handicap > 100 Then
  6977. item(i).handicap = 100
  6978. End If
  6979. Next i
  6980. Return 0
  6981. End Function
  6982. #endif
  6983. Sub TrackErrorMessage(e As UByte)
  6984. Select Case e
  6985. Case 20 : Error_Message "Dangerous path on mountain border", "Warning!"
  6986. Case 21 : Error_Message "Jump is not feasible in OWOOT", "Warning!"
  6987. Case 22 : Error_Message "Inverted jump. Not feasible in OWOOT", "Warning!"
  6988. Case 23 : Error_Message "Water will display as grass", "Warning!"
  6989. Case 24 : Error_Message "Water will be solid here", "Warning!"
  6990. Case 40 : Error_Message "Non-standard terrain element", "Fatal Error!"
  6991. Case 41 : Error_Message "Mountain borders mismatch"
  6992. Case 50 : Error_Message "Objects on mountain corners will not display correctly", "Warning"
  6993. Case 51 : Error_Message "Only straightways and ramps will display on mountain borders", "Warning"
  6994. Case 60 : Error_Message "Start/Finish line not found"
  6995. Case 61 : Error_Message "Too many start/finish lines!"
  6996. Case 62 : Error_Message "Terrain at track start is inadequeate"
  6997. Case 70 : Error_Message "Track type mismatch"
  6998. Case 71 : Error_Message "Straightway before jump is too short"
  6999. Case 72 : Error_Message "Wrong way"
  7000. Case 73 : Error_Message "Jump distance is too long"
  7001. Case 74 : Error_Message "Stunts won't allow interrupting this bridge"
  7002. Case 80 : Error_Message "Grid border reached"
  7003. Case 81 : Error_Message "Path interrupted"
  7004. Case 82 : Error_Message "Cyclic path"
  7005. Case Else : Error_Message "Error #" + Str(e)
  7006. End Select
  7007. DrawTrack
  7008. End Sub
  7009. Sub Undo
  7010. 'If the pointer would be at the tail, then there's no undo.
  7011. If ((undotail + 1) Mod UNDOLEVEL) = undopointer Then Exit Sub
  7012. 'Decrement the pointer for the next undo
  7013. If undopointer Then undopointer -= 1 Else undopointer = UNDOLEVEL - 1
  7014. 'Restore grid
  7015. If Len(undobuffer(undopointer)) = 0 Then _
  7016. undobuffer(undopointer) = Chr(30, 30) + String(1800, 0)
  7017. PutTrack 1, 1, undobuffer(undopointer), -1
  7018. DrawTrack
  7019. End Sub
  7020. Sub UnRLETerrain(ter As String)
  7021. Dim As Short x = 1, y = 1, n = 0
  7022. Dim what As UByte, s As String
  7023. s = ter
  7024. Do
  7025. If n Then
  7026. grid(x, y).land = what
  7027. n -= 1
  7028. x += 1
  7029. If x = 31 Then x = 1 : y += 1
  7030. Else
  7031. what = ASC(Left(s, 1))
  7032. If what And 128 Then
  7033. n = what And 127
  7034. what = ASC(Mid(s, 2, 1))
  7035. s = Mid(s, 3)
  7036. Else
  7037. grid(x, y).land = what
  7038. s = Mid(s, 2)
  7039. x += 1
  7040. If x = 31 Then x = 1 : y += 1
  7041. End If
  7042. End If
  7043. Loop Until y = 31
  7044. End Sub
  7045. Sub UpdateTitleBar
  7046. Dim s As String
  7047. If Len(Trim(meta.title)) Then
  7048. s = Trim(meta.title)
  7049. If Len(Trim(meta.author)) Then _
  7050. s &= " (by " + Trim(meta.author) + ")"
  7051. ElseIf Len(Trim(track_file)) Then
  7052. s = Trim(track_file)
  7053. If Len(Trim(meta.author)) Then _
  7054. s &= " (by " + Trim(meta.author) + ")"
  7055. End If
  7056. If Len(s) Then
  7057. s = ptitle + " - " + s
  7058. Else
  7059. s = ptitle
  7060. End If
  7061. #ifdef __FB_DOS__
  7062. WindowTitle Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s))
  7063. #else
  7064. changing_title = -1
  7065. WindowTitle Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s))
  7066. changing_title = 0
  7067. #endif
  7068. End Sub
  7069. 'Flip buffer rectangle horizontally
  7070. Function VFlipTrack(t As String) As String
  7071. Dim As Byte w, h, c
  7072. w = ASC(Left(t, 1))
  7073. h = ASC(Mid(t, 2, 1))
  7074. Dim temp(1 To w, 1 To h) As SGrid
  7075. Dim s As String, i As Byte, j As Byte, n As Short
  7076. 'Read and flip
  7077. n = 3 : i = 1 : j = h
  7078. Do While n <= Len(t)
  7079. c = ASC(Mid(t, n, 1))
  7080. n += 1
  7081. If c And 1 Then 'Track is non-zero
  7082. temp(i, j).track = tr(ASC(Mid(t, n, 1))).vflip
  7083. n += 1
  7084. End If
  7085. If c And 2 Then 'Terrain is non-zero
  7086. temp(i, j).land = ttr(ASC(Mid(t, n, 1))).vflip
  7087. n += 1
  7088. End If
  7089. If c And 4 Then 'Border colour is non-zero
  7090. temp(i, j).border = CvL(Mid(t, n, 4))
  7091. n += 4
  7092. End If
  7093. If c And 8 Then 'Background colour is non-zero
  7094. temp(i, j).bgc = CvL(Mid(t, n, 4))
  7095. n += 4
  7096. End If
  7097. i += 1
  7098. If i > w Then i = 1 : j -= 1
  7099. Loop
  7100. 'Fix
  7101. For i = 1 To w
  7102. For j = 1 To h - 1
  7103. If temp(i, j).track = 254 Or temp(i, j).track = 253 Then
  7104. Swap temp(i, j).track, temp(i, j + 1).track
  7105. j += 1
  7106. End If
  7107. Next j
  7108. Next i
  7109. 'Put back into the string
  7110. s = PackedClip(temp())
  7111. Return s
  7112. End Function
  7113. 'Push the current grid into the undo buffer
  7114. Sub PushUndo
  7115. 'Advance the pointer
  7116. undopointer = (undopointer + 1) Mod UNDOLEVEL
  7117. 'If there were pending redos (the user has been undoing),
  7118. 'drop them, as they are now obsolete
  7119. If undohead <> undopointer Then undohead = undopointer
  7120. 'Store current grid
  7121. undobuffer(undohead) = GetTrack(1, 1, 30, 30)
  7122. 'If the head reaches the tail (there are already UNDOLEVEL undos
  7123. 'in the buffer), then drop the oldest undo by advancing the tail
  7124. If undohead = undotail Then undotail = (undotail + 1) Mod UNDOLEVEL
  7125. End Sub
  7126. Sub PutIcon(u As UByte, v As UByte, x As UShort, y As UShort)
  7127. If track_image_buffer = 0 Then
  7128. If dosbox Then
  7129. Put (x, y), bigicons, (u * bigwidth, v * 22)- STEP (bigwidth - 1, 21), Trans
  7130. Else
  7131. Put (x, y), bigicons, (u * bigwidth, v * 22)- STEP (bigwidth - 1, 21), Alpha
  7132. End If
  7133. Else
  7134. If dosbox Then
  7135. Put track_image_buffer, (x, y), bigicons, (u * bigwidth, v * 22)- STEP (bigwidth - 1, 21), Trans
  7136. Else
  7137. Put track_image_buffer, (x, y), bigicons, (u * bigwidth, v * 22)- STEP (bigwidth - 1, 21), Alpha
  7138. End If
  7139. End If
  7140. End Sub
  7141. Sub PutSmallIcon(u As UByte, v As UByte, x As UShort, y As UShort)
  7142. If dosbox Then
  7143. Put (x, y), bigicons, (u * graphic_size, v * graphic_size)- STEP (graphic_size - 1, graphic_size - 1), Trans
  7144. Else
  7145. Put (x, y), bigicons, (u * graphic_size, v * graphic_size)- STEP (graphic_size - 1, graphic_size - 1), Alpha
  7146. End If
  7147. End Sub
  7148. Sub CheckClipboardImport
  7149. 'Do not import clipboard if currently pasting (it would mess up)
  7150. If pasting Then Exit Sub
  7151. 'Do not delete the clipboard if nothing to import
  7152. If FileExists(program_path & "clip.tmp") AndAlso _
  7153. FileLen(program_path & "clip.tmp") <> last_cb_file_length Then
  7154. Dim f As Integer, b As Byte
  7155. f = FreeFile
  7156. Open program_path & "clip.tmp" For Binary Access Read As f
  7157. Get #f, , b
  7158. If b Then Get #f, , b
  7159. clipboard = Space(LOF(f) - Seek(f) + 1)
  7160. Get #f, , clipboard
  7161. last_cb_file_length = LOF(f)
  7162. Close f
  7163. DrawPanel
  7164. End If
  7165. End Sub
  7166. Sub CheckTrack
  7167. Dim v As TrackVector
  7168. Dim As Short i, j
  7169. Dim track_closed As Byte = 0
  7170. Dim e As UByte
  7171. Dim As Byte ex, ey
  7172. DetectTerrainErrors e, ex, ey
  7173. If e >= 40 And e <= 49 Then
  7174. TrackErrorMessage e
  7175. DrawTrack
  7176. xcursor = ex : ycursor = ey
  7177. ManageKeyboardCursor -1
  7178. Exit Sub
  7179. End If
  7180. v = FindStart
  7181. Select Case v.e
  7182. Case 60
  7183. Error_Message "Start/finish line not found"
  7184. DrawTrack
  7185. Exit Sub
  7186. Case 61
  7187. Error_Message "Too many start/finish lines!"
  7188. DrawTrack
  7189. Exit Sub
  7190. Case 62
  7191. Error_Message "Terrain at track start is inadequate"
  7192. DrawTrack
  7193. Exit Sub
  7194. End Select
  7195. GenerateSections
  7196. If sections > 254 Or paths >= MAXPATHS Then
  7197. Error_Message "Track is too complex. Too many splits!"
  7198. Exit Sub
  7199. End If
  7200. 'Find track-fatal errors
  7201. For i = 1 To paths
  7202. If path(i).e >= 70 And path(i).e <= 79 Then
  7203. TrackErrorMessage path(i).e
  7204. FollowPath path(i).p, path(i).e
  7205. Exit Sub
  7206. End If
  7207. Next i
  7208. 'So, track is OK, but is there any warning?
  7209. For i = 1 To paths
  7210. If path(i).e >= 20 And path(i).e <= 29 Then
  7211. TrackErrorMessage path(i).e
  7212. FollowPath path(i).p, path(i).e
  7213. Exit Sub
  7214. End If
  7215. Next i
  7216. 'See if there's a path to the finish-line with no errors
  7217. For i = 1 To paths
  7218. If path(i).finishes Then
  7219. Error_Message "Found winning path", "Track OK"
  7220. DrawTrack
  7221. FollowPath path(i).p
  7222. Exit Sub
  7223. End If
  7224. Next i
  7225. 'Reject tracks that are not closed
  7226. Error_Message "At least one path must be closed"
  7227. DrawTrack
  7228. For i = 1 To paths
  7229. FollowPath path(i).p
  7230. Next i
  7231. v.coors = section(ASC(Right(path(1).p, 1))).final
  7232. xcursor = v.x : ycursor = v.y
  7233. ManageKeyboardCursor -1
  7234. End Sub
  7235. Sub ClearTrack(x As UByte, y As UByte)
  7236. Dim As Short alterx, altery
  7237. Dim element As UByte
  7238. If allow_errors Then
  7239. alterx = x : altery = y
  7240. Else
  7241. Select Case grid(x, y).track
  7242. Case 255 : alterx = x - 1 : altery = y
  7243. Case 254 : alterx = x : altery = y - 1
  7244. Case 253 : alterx = x - 1 : altery = y - 1
  7245. Case Else : alterx = x : altery = y
  7246. End Select
  7247. End If
  7248. If alterx < 1 Then alterx = 1
  7249. If altery < 1 Then altery = 1
  7250. element = grid(alterx, altery).track
  7251. grid(alterx, altery).track = 0
  7252. DrawSpot alterx, altery
  7253. 'Tunnels
  7254. If element = &H42 Then
  7255. If y > 1 Then DrawSpot x, y - 1
  7256. If y < 30 Then DrawSpot x, y + 1
  7257. ElseIf element = &H43 Then
  7258. If x > 1 Then DrawSpot x - 1, y
  7259. If x < 30 Then DrawSpot x + 1, y
  7260. End If
  7261. If Not allow_errors Then
  7262. If tr(element).w > 1 Then
  7263. If alterx + 1 <= 30 Then grid(alterx + 1, altery).track = 0 : DrawSpot alterx + 1, altery
  7264. If tr(element).h > 1 Then
  7265. If alterx + 1 <= 30 And altery + 1 <= 30 Then grid(alterx + 1, altery + 1).track = 0 : DrawSpot alterx + 1, altery + 1
  7266. End if
  7267. End If
  7268. If tr(element).h > 1 Then
  7269. If altery + 1 <= 30 Then grid(alterx, altery + 1).track = 0 : DrawSpot alterx, altery + 1
  7270. End If
  7271. If grid(x, y).track <> 0 Then grid(x, y).track = 0 : DrawSpot x, y
  7272. End If
  7273. End Sub
  7274. Sub Menu_TrackInfo
  7275. Dim As Integer xm, ym, wm, bm
  7276. Dim v As Short, s As String
  7277. Dim et As Long, top As Short
  7278. Dim content(0 To 6, 1 To 2) As String
  7279. Dim As Byte current = -1, former = -1, update = -1
  7280. Dim akey As String
  7281. If thisfileformat = FORMAT_RAW Then
  7282. Error_Message "Format set to one-file to allow for metadata", "Warning!"
  7283. thisfileformat = FORMAT_COMBINED
  7284. DrawTrack
  7285. End If
  7286. MenuBox 36, 29, "Track Information"
  7287. top = ceny
  7288. lefx += 8
  7289. TLeft
  7290. content(0, 1) = "Track title:"
  7291. TLeft , content(0, 1), RGB(200, 200, 200)
  7292. If Len(meta.title) Then
  7293. s = Left(meta.title, 64)
  7294. ElseIf Len(track_file) Then
  7295. s = UCase(Left(track_file, 1)) + LCase(Mid(track_file, 2))
  7296. v = InStr(s, ".")
  7297. If v Then s = Left(s, v - 1)
  7298. Else
  7299. s = "Untitled"
  7300. End If
  7301. content(0, 2) = s
  7302. #ifdef RENDER_TO_CP437
  7303. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7304. #else
  7305. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7306. #endif
  7307. TLeft
  7308. content(1, 1) = "Author:"
  7309. TLeft , content(1, 1), RGB(200, 200, 200)
  7310. If Len(meta.author) Then
  7311. s = Left(meta.author, 64)
  7312. Else
  7313. s = "Anonymous"
  7314. End If
  7315. content(1, 2) = s
  7316. #ifdef RENDER_TO_CP437
  7317. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7318. #else
  7319. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7320. #endif
  7321. TLeft
  7322. TLeft , "Date created:", RGB(200, 200, 200)
  7323. If meta.cyear Then
  7324. s = Str(meta.cyear)
  7325. If meta.cmonth Then
  7326. s = Str(meta.cmonth) + "-" + s
  7327. If meta.cday Then s = Str(meta.cday) + "-" + s
  7328. End If
  7329. Else
  7330. s = "Unknown"
  7331. End If
  7332. TLeft , s, RGB(160, 160, 240)
  7333. TLeft
  7334. TLeft , "Created with:", RGB(200, 200, 200)
  7335. If meta.toolversion Then
  7336. s = Left(meta.tool, 32) + " " + Str(meta.toolversion \ 10000)
  7337. s &= "." + Str((meta.toolversion Mod 10000) \ 100)
  7338. If meta.toolversion Mod 100 Then s &= "." + Str(meta.toolversion Mod 100)
  7339. Else
  7340. s = Left(meta.tool, 32)
  7341. End If
  7342. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7343. TLeft
  7344. TLeft , "Editing time:", RGB(200, 200, 200)
  7345. If meta.editing_time >= 0 THen
  7346. et = meta.editing_time + Timer - started_editing
  7347. s = ""
  7348. If et >= 3600 Then s = Str(et \ 3600) + "h "
  7349. s &= Str((et Mod 3600) \ 60) + "' "
  7350. s &= Str(et Mod 60) + Chr(34)
  7351. Else
  7352. s = "Unknown"
  7353. End If
  7354. TLeft , s, RGB(160, 160, 240)
  7355. TLeft
  7356. content(5, 1) = "Comment:"
  7357. TLeft , content(5, 1), RGB(200, 200, 200)
  7358. If Len(meta.comment) Then
  7359. s = Left(meta.comment, 64)
  7360. Else
  7361. s = "No comment"
  7362. End If
  7363. content(5, 2) = s
  7364. #ifdef RENDER_TO_CP437
  7365. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7366. #else
  7367. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7368. #endif
  7369. TLeft
  7370. content(6, 1) = "Championship information:"
  7371. TLeft , content(6, 1), RGB(200, 200, 200)
  7372. If Len(meta.championship) Then
  7373. s = Left(meta.championship, 64)
  7374. Else
  7375. s = "No info"
  7376. End If
  7377. content(6, 2) = s
  7378. #ifdef RENDER_TO_CP437
  7379. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7380. #else
  7381. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7382. #endif
  7383. TLeft
  7384. TLeft
  7385. buttons = 0
  7386. StackButton " Cancel ", 2
  7387. StackButton " Update ", 1
  7388. EndOfButtonStack
  7389. Do
  7390. GetMouse xm, ym, wm, bm
  7391. If xm < lefx - 8 Or xm >= lefx + 8 * 67 Or ym < top + 8 Or ym >= top + 7 * 48 + 8 Then
  7392. current = -1
  7393. Else
  7394. current = (ym - top - 8) \ 48
  7395. End If
  7396. If current <> former Or update = -1 Then
  7397. ScreenLock
  7398. If former = 0 Or former = 1 Or former = 5 Or former = 6 Then
  7399. Line (lefx - 4, top + 8 + 48 * former)- Step (8 * 67 - 1, 47), RGB(30, 30, 50), BF
  7400. ceny = top + 16 + 48 * former
  7401. s = content(former, 2)
  7402. TLeft , content(former, 1), RGB(200, 200, 200)
  7403. #ifdef RENDER_TO_CP437
  7404. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7405. #else
  7406. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7407. #endif
  7408. End If
  7409. If current = 0 Or current = 1 Or current = 5 Or current = 6 Then
  7410. Line (lefx - 4, top + 8 + 48 * current)- Step (8 * 67 - 1, 47), RGB(10, 10, 10), BF
  7411. ceny = top + 16 + 48 * current
  7412. s = content(current, 2)
  7413. TLeft , content(current, 1), RGB(200, 200, 200)
  7414. #ifdef RENDER_TO_CP437
  7415. TLeft , Enc_UTF32_to_CP437(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7416. #else
  7417. TLeft , Enc_UTF32_to_Latin1(Enc_UTF8_to_UTF32(s)), RGB(160, 160, 240)
  7418. #endif
  7419. End If
  7420. ScreenUnlock
  7421. former = current
  7422. update = 0
  7423. End If
  7424. v = ManageButtons
  7425. If STRONG_ANTI_HOG Then Sleep 1
  7426. If bm = 1 And (current = 0 Or current = 1 Or current = 5 Or current = 6) Then
  7427. stringer.init = -1
  7428. stringer.maxlength = 64
  7429. stringer.fileonly = 0
  7430. stringer.x = lefx
  7431. stringer.y = 48 * current + top + 32
  7432. stringer.background = RGB(10, 10, 10)
  7433. If current = 0 And content(current, 2) = "Untitled" Then content(current, 2) = ""
  7434. If current = 1 And content(current, 2) = "Anonymous" Then content(current, 2) = ""
  7435. If current = 5 And content(current, 2) = "No comment" Then content(current, 2) = ""
  7436. If current = 6 And content(current, 2) = "No info" Then content(current, 2) = ""
  7437. Do
  7438. akey = ManageString(content(current, 2))
  7439. v = ManageButtons
  7440. Loop Until akey = Chr(13) Or akey = Chr(27) Or v <> 0
  7441. If current = 0 And Trim(content(current, 2)) = "" Then content(current, 2) = "Untitled"
  7442. If current = 1 And Trim(content(current, 2)) = "" Then content(current, 2) = "Anonymous"
  7443. If current = 5 And Trim(content(current, 2)) = "" Then content(current, 2) = "No comment"
  7444. If current = 6 And Trim(content(current, 2)) = "" Then content(current, 2) = "No info"
  7445. update = -1
  7446. Dim t As Double
  7447. t = Timer
  7448. Do : Loop Until Timer >= t + .3
  7449. Do : Loop Until Len(InKey) = 0
  7450. End If
  7451. akey = InKey
  7452. Loop Until v Or akey = Chr(13) Or akey = Chr(27)
  7453. buttons = 0
  7454. If v = 1 Or akey = Chr(13) Then
  7455. meta.title = Trim(content(0, 2))
  7456. If meta.title = "Untitled" Then meta.title = ""
  7457. meta.author = Trim(content(1, 2))
  7458. If meta.author = "Anonymous" Then meta.author = ""
  7459. meta.comment = Trim(content(5, 2))
  7460. If meta.comment = "No comment" Then meta.comment = ""
  7461. meta.championship = Trim(content(6,2))
  7462. If meta.championship = "No info" Then meta.championship = ""
  7463. End If
  7464. Do
  7465. GetMouse xm, ym, wm, bm
  7466. Loop Until bm = 0
  7467. Do : Loop Until Len(InKey) = 0
  7468. UpdateTitleBar
  7469. DrawTrack
  7470. End Sub
  7471. Sub Menu_Tournaments
  7472. #ifdef __FB_DOS__
  7473. Error_Message "Tournament option not available in DOS"
  7474. #else
  7475. Dim tmt(1 To 10) As String, addr(1 To 10) As String, tmts As Byte
  7476. Dim n As Short, v As Short, current_tournament As Byte, top As Short
  7477. Dim page As Byte, reload_tournament As Byte = -1
  7478. Dim As Integer xm, ym, wm, bm
  7479. Dim As String curtrack, deadline
  7480. If FileExists(program_path + "tours.dat") Then
  7481. Dim ff As Integer
  7482. ff = FreeFile
  7483. Open program_path + "tours.dat" For Binary Access Read As ff
  7484. While Not EOF(ff)
  7485. tmts += 1
  7486. Get #ff, , n
  7487. tmt(tmts) = Space(n)
  7488. Get #ff, , tmt(tmts)
  7489. Get #ff, , n
  7490. addr(tmts) = Space(n)
  7491. Get #ff, , addr(tmts)
  7492. WEnd
  7493. Close ff
  7494. End If
  7495. Do
  7496. Select Case page
  7497. Case 0 'Main page, list of tournaments
  7498. Dim update As Byte = -1
  7499. Do
  7500. If update Then
  7501. ScreenLock
  7502. DrawTrack
  7503. If tmts Then
  7504. MenuBox 30, 8 + 3 * tmts, "Tournaments"
  7505. If current_tournament = 0 Then current_tournament = 1
  7506. Line (lefx - 4, ceny + 48 * current_tournament - 40)- Step (455, 47), RGB(10, 10, 10), BF
  7507. Else
  7508. MenuBox 30, 11, "Tournaments"
  7509. End If
  7510. top = ceny : lefx += 8
  7511. TLeft
  7512. If tmts Then
  7513. For n = 1 To tmts
  7514. TLeft , tmt(n), RGB(200, 200, 200)
  7515. TLeft , addr(n), RGB(160, 160, 240)
  7516. TLeft
  7517. Next n
  7518. Else
  7519. TLeft
  7520. TCentre , "No tournaments found", RGB(160, 160, 240)
  7521. TLeft
  7522. End If
  7523. TLeft
  7524. buttons = 0
  7525. If tmts Then
  7526. StackButton " Connect ", 1
  7527. StackButton " Remove ", 2
  7528. End If
  7529. If tmts < 10 Then StackButton " Add New ", 3
  7530. StackButton " Done ", 10
  7531. EndOfButtonStack
  7532. ScreenUnlock
  7533. update = 0
  7534. End If
  7535. GetMouse xm, ym, wm, bm
  7536. If STRONG_ANTI_HOG Then Sleep 1
  7537. If bm = 1 And tmts <> 0 Then
  7538. If xm >= lefx - 4 And xm <= lefx + 459 And ym >= top + 8 Then
  7539. n = (ym - top - 8) \ 48 + 1
  7540. If n <= tmts And n <> current_tournament Then
  7541. current_tournament = n
  7542. update = -1
  7543. End If
  7544. End If
  7545. End If
  7546. v = ManageButtons
  7547. Loop Until v
  7548. buttons = 0
  7549. If v = 2 And tmts <> 0 Then 'Remove
  7550. For i As Byte = current_tournament To tmts - 1
  7551. tmt(i) = tmt(i + 1)
  7552. addr(i) = addr(i + 1)
  7553. Next i
  7554. tmts -= 1
  7555. If current_tournament > tmts Then current_tournament = tmts
  7556. ElseIf v = 3 Then
  7557. page = 1
  7558. ElseIf v = 1 Then
  7559. reload_tournament = -1
  7560. page = 2 'Connect
  7561. End If
  7562. DrawTrack
  7563. Do
  7564. GetMouse xm, ym, wm, bm
  7565. Loop Until bm = 0
  7566. Case 1 'Add tournament
  7567. Dim As String title, address, akey
  7568. Dim As Byte which = 0, old = 1
  7569. MenuBox 30, 14, "Add Tournament"
  7570. lefx += 8 : top = ceny
  7571. TLeft
  7572. TLeft , "Tournament name:", RGB(200, 200, 200)
  7573. TLeft
  7574. TLeft
  7575. TLeft , "Domain name (base address):", RGB(200, 200, 200)
  7576. TLeft
  7577. TLeft
  7578. TLeft
  7579. buttons = 0
  7580. StackButton " Cancel ", 2
  7581. StackButton " Create ", 1
  7582. EndOfButtonStack
  7583. stringer.x = lefx
  7584. stringer.fileonly = 0
  7585. stringer.maxlength = 40
  7586. stringer.background = RGB(30, 30, 50)
  7587. Do
  7588. If old <> which Then
  7589. Line (lefx, top + 48 * old + 32)- Step (449, 15), RGB(30, 30, 50), BF
  7590. If old Then
  7591. Draw String (lefx, top + 80), address + Space(40 - Len(address)), RGB(160, 160, 240)
  7592. stringer.y = top + 32
  7593. Else
  7594. Draw String (lefx, top + 32), title + Space(40 - Len(title)), RGB(160, 160, 240)
  7595. stringer.y = top + 80
  7596. End If
  7597. stringer.init = -1
  7598. old = which
  7599. End If
  7600. v = ManageButtons
  7601. If which Then
  7602. akey = ManageString(address)
  7603. Else
  7604. akey = ManageString(title)
  7605. End If
  7606. If STRONG_ANTI_HOG Then Sleep 1
  7607. Select Case akey
  7608. Case Chr(9) : which = 1 - which
  7609. Case Chr(13)
  7610. If which Then
  7611. v = 1 : Exit Do
  7612. Else
  7613. which = 1 - which
  7614. End If
  7615. Case Chr(27) : v = 2 : Exit DO
  7616. End Select
  7617. Loop Until v
  7618. Do : Loop Until Len(InKey) = 0
  7619. If v = 1 Then
  7620. tmts += 1
  7621. tmt(tmts) = Trim(title)
  7622. addr(tmts) = Trim(address)
  7623. End If
  7624. page = 0
  7625. DrawTrack
  7626. Do
  7627. GetMouse xm, ym, wm, bm
  7628. Loop Until bm = 0
  7629. Case 2 'Attempt connection to tournament
  7630. Dim result As Byte
  7631. If reload_tournament Then
  7632. MenuBox 20, 7, "Please wait"
  7633. TLeft
  7634. TCentre , "Attempting connection...", RGB(160, 160, 240)
  7635. result = TMT_GetMain(addr(current_tournament), curtrack, deadline)
  7636. DrawTrack
  7637. Else
  7638. result = 0
  7639. End If
  7640. If result Then
  7641. Error_Message "Failed to connect to " + tmt(current_tournament)
  7642. v = 3
  7643. Else
  7644. MenuBox 35, 14, tmt(current_tournament)
  7645. lefx += 8
  7646. TLeft
  7647. TLeft , "Current race:", RGB(200, 200, 200)
  7648. TLeft , curtrack, RGB(160, 160, 240)
  7649. TLeft
  7650. TLeft , "Deadline:", RGB(200, 200, 200)
  7651. TLeft , deadline, RGB(160, 160, 240)
  7652. TLeft
  7653. TLeft
  7654. buttons = 0
  7655. StackButton " Back ", 3
  7656. StackButton " Get Track ", 1
  7657. StackButton " Scoreboard ", 2
  7658. EndOfButtonStack
  7659. Do
  7660. v = ManageButtons
  7661. Loop Until v
  7662. If STRONG_ANTI_HOG Then Sleep 1
  7663. buttons = 0
  7664. reload_tournament = 0
  7665. End If
  7666. If v = 1 Then
  7667. DrawTrack
  7668. TMT_GetCurrentTrack addr(current_tournament)
  7669. ElseIf v = 2 Then
  7670. page = 3
  7671. ElseIf v = 3 Then
  7672. page = 0
  7673. End If
  7674. DrawTrack
  7675. Do
  7676. GetMouse xm, ym, wm, bm
  7677. Loop Until bm = 0
  7678. Case 3 'Scoreboard
  7679. Dim item(1 To 100) As Scoreboard, items As Byte
  7680. Dim result As Byte
  7681. MenuBox 20, 7, "Please wait"
  7682. TLeft
  7683. TCentre , "Loading scoreboard...", RGB(160, 160, 240)
  7684. result = TMT_GetScoreboard(addr(current_tournament), item(), items)
  7685. DrawTrack
  7686. If result Then
  7687. Error_Message "Failed to get the scoreboard"
  7688. ElseIf items = 0 Then
  7689. Error_Message "Scoreboard is empty", tmt(current_tournament) + " - Scoreboard"
  7690. Else
  7691. Dim top As Short
  7692. Dim As ULong normal = RGB(160, 160, 240), bright = RGB(180, 180, 80)
  7693. Do : Loop Until Len(InKey) = 0
  7694. ScreenLock
  7695. MenuBox 35, 9 + items, tmt(current_tournament) + " - Scoreboard"
  7696. lefx += 8
  7697. TLeft
  7698. top = ceny
  7699. For i As Byte = 1 To items
  7700. Dim s As String
  7701. s = Str(i) : If Len(s) = 1 Then s = " " + s
  7702. concolour = normal
  7703. TCont s + " - " + item(i).racer + " (" + item(i).car + ")"
  7704. concolour = bright : conx = lefx + 320
  7705. If Len(item(i).hctime) = 0 Then
  7706. TCont Space(8) + item(i).realtime
  7707. Else
  7708. TCont item(i).realtime + " " + item(i).hctime
  7709. End If
  7710. If item(i).handicap Then
  7711. s = "(" + Str(item(i).handicap) + "%)"
  7712. ElseIf Len(item(i).style) Then
  7713. s = "(" + item(i).style + ")"
  7714. Else
  7715. s = ""
  7716. End If
  7717. If item(i).verified Then s &= Chr(251)
  7718. concolour = normal
  7719. TCont s, -1
  7720. Next i
  7721. ScreenUnlock
  7722. buttons = 0
  7723. ceny = top + 16 * items + 32
  7724. StackButton " OK ", 1
  7725. EndOfButtonStack
  7726. Do
  7727. v = ManageButtons
  7728. If STRONG_ANTI_HOG Then Sleep 1
  7729. Loop Until v <> 0 Or Len(InKey) <> 0
  7730. DrawTrack
  7731. Do
  7732. GetMouse xm, ym, wm, bm
  7733. Loop Until bm = 0
  7734. End If
  7735. page = 2
  7736. End Select
  7737. Loop Until v = 10
  7738. Do : Loop Until Len(InKey) = 0
  7739. If tmts Then
  7740. Dim ff As Integer
  7741. ff = FreeFile
  7742. Open program_path + "tours.dat" For Output As ff : Close ff
  7743. Open program_path + "tours.dat" For Binary As ff
  7744. For i As Byte = 1 To tmts
  7745. n = Len(tmt(i))
  7746. Put #ff, , n
  7747. Put #ff, , tmt(i)
  7748. n = Len(addr(i))
  7749. Put #ff, , n
  7750. Put #ff, , addr(i)
  7751. Next i
  7752. Close ff
  7753. Else
  7754. If FileExists(program_path + "tours.dat") Then Kill program_path + "tours.dat"
  7755. End If
  7756. #endif
  7757. End Sub
  7758. Sub Menu_TrackShot
  7759. Dim tiname As String, tsformat As SelectorType
  7760. MenuBox 28, 12, "Track-shot"
  7761. TLeft ,
  7762. tsformat.redraw = -1
  7763. tsformat.options = 6
  7764. tsformat.opt(1) = "TGA"
  7765. tsformat.opt(2) = "BMP"
  7766. tsformat.opt(3) = "PCX"
  7767. tsformat.opt(4) = "GIF"
  7768. tsformat.opt(5) = "JPG"
  7769. tsformat.opt(6) = "PNG"
  7770. tsformat.current = 1
  7771. For i As Byte = 1 To 6
  7772. If LCase(tsformat.opt(i)) = LCase(imageformat) Then
  7773. tsformat.current = i
  7774. Exit For
  7775. End If
  7776. Next i
  7777. tsformat.x1 = cenx + 8
  7778. tsformat.x2 = cenx + 108
  7779. tsformat.y1 = ceny - 8
  7780. tsformat.y2 = ceny + 23
  7781. TCentre , "Image format: ", RGB(160, 160, 240)
  7782. TLeft ,
  7783. TCentre , "Only TGA and BMP are supported natively", RGB(160, 160, 240)
  7784. TCentre , "Other formats require ImageMagick", RGB(160, 160, 240)
  7785. TLeft ,
  7786. buttons = 0
  7787. StackButton " Cancel ", 1
  7788. StackButton " Save ", 2
  7789. EndOfButtonStack
  7790. Dim v As Short, akey As String
  7791. Do
  7792. v = ManageButtons
  7793. ManageSelector tsformat
  7794. akey = InKey
  7795. If STRONG_ANTI_HOG Then Sleep 1
  7796. Select Case akey
  7797. Case Chr(13) : v = 2 : Exit Do
  7798. Case Chr(27) : v = 1 : Exit Do
  7799. End Select
  7800. Loop Until v <> 0
  7801. buttons = 0
  7802. DrawTrack
  7803. If v = 2 Then
  7804. imageformat = LCase(tsformat.opt(tsformat.current))
  7805. If Len(Trim(track_file)) Then
  7806. If LCase(Right(track_file, 4)) = ".trk" Then
  7807. tiname = Left(track_file, Len(track_file) - 3) + imageformat
  7808. Else
  7809. tiname = track_file + "." + imageformat
  7810. End If
  7811. Else
  7812. tiname = "track." + imageformat
  7813. End If
  7814. SaveTrackImage program_path + tiname
  7815. If FileExists(program_path + tiname) Then
  7816. Error_Message "Track image saved as '" & tiname & "'", "Track-shot"
  7817. Else
  7818. Error_Message "Track image could not be saved!"
  7819. End If
  7820. End If
  7821. End Sub
  7822. Sub NotASquare
  7823. Dim v As Short
  7824. MenuBox 32, 10, "Cannot rotate!"
  7825. ceny += 8
  7826. TCentre , "The selected area has to be a square to rotate in-situ", RGB(200, 200, 240)
  7827. TCentre , "Adjust dimensions or copy the selection to the", RGB(200, 200, 240)
  7828. TCentre , "clipboard and then paste before rotating.", RGB(200, 200, 240)
  7829. TCentre
  7830. If xselect > x2select Then Swap xselect, x2select
  7831. If yselect > y2select Then Swap yselect, y2select
  7832. If xselect + y2select - yselect <= 30 Then _
  7833. StackButton " Adjust width ", 1
  7834. If yselect + x2select - xselect <= 30 Then _
  7835. StackButton " Adjust height ", 2
  7836. StackButton " Cancel ", 3
  7837. EndOfButtonStack
  7838. Do
  7839. v = ManageButtons
  7840. Loop Until v <> 0 Or InKey <> ""
  7841. buttons = 0
  7842. Select Case v
  7843. Case 1 : x2select = xselect + y2select - yselect
  7844. Case 2 : y2select = yselect + x2select - xselect
  7845. End Select
  7846. Dim As Integer xm, ym, wm, bm
  7847. Do
  7848. GetMouse xm, ym, wm, bm
  7849. Loop Until bm = 0
  7850. Do : Loop Until Len(InKey) = 0
  7851. DrawTrack
  7852. End Sub
  7853. Sub Paste
  7854. If Len(clipboard) Then pasting = -1
  7855. End Sub
  7856. Function PathLength(n As Short, weighed As Byte = 0) As Long
  7857. Dim l As Long = 0, i As Short
  7858. Dim v As TrackVector, s As Short
  7859. Dim juststarted As Byte
  7860. For i = 1 To Len(path(n).p)
  7861. s = ASC(Mid(path(n).p, i, 1))
  7862. v.coors = section(s).initial
  7863. v.bearing = section(s).bearing
  7864. If sections = 1 And section(1).finishes <> 0 Then juststarted = -1
  7865. While v.coors <> section(s).final Or juststarted
  7866. v = GetNext(v)
  7867. juststarted = 0
  7868. If weighed Then
  7869. l += tr(grid(v.x, v.y).track).length
  7870. Else
  7871. If tr(grid(v.x, v.y).track).w > 1 Or tr(grid(v.x, v.y).track).h > 1 Then
  7872. l += 2
  7873. Else
  7874. l += 1
  7875. End If
  7876. End If
  7877. WEnd
  7878. Next i
  7879. If weighed Then
  7880. l += 10
  7881. Else
  7882. l += 1
  7883. End If
  7884. Return l
  7885. End Function
  7886. Function PathToError(te As Short) As String
  7887. Dim s As String, i As Short, current As Short
  7888. 'I believe this function may hang when executed to find
  7889. 'a cycle that's made of more than one section if it happens
  7890. 'to choose the same two or more sections over and over.
  7891. current = terror(te).section
  7892. s = Chr(current)
  7893. While current <> 1
  7894. For i = 1 To sections
  7895. If i <> current And section(i).final = section(current).initial Then
  7896. current = i
  7897. s = Chr(i) + s
  7898. Exit For
  7899. End If
  7900. Next i
  7901. Wend
  7902. Return s
  7903. End Function
  7904. Function PathToFinishLine(which As Byte = 0) As String
  7905. Dim i As Short
  7906. Return ""
  7907. End Function
  7908. Sub PickTrack(x As UByte, y As UByte)
  7909. Dim As Short alterx, altery
  7910. Select Case grid(x, y).track
  7911. Case 255 : alterx = x - 1 : altery = y
  7912. Case 254 : alterx = x : altery = y - 1
  7913. Case 253 : alterx = x - 1 : altery = y - 1
  7914. Case Else : alterx = x : altery = y
  7915. End Select
  7916. If alterx < 1 Then alterx = 1
  7917. If altery < 1 Then altery = 1
  7918. current_brush = grid(alterx, altery).track
  7919. End Sub
  7920. Sub SelectByTyping
  7921. Dim As String akey, s
  7922. Dim As Integer xm, ym, wm, bm, xo, yo
  7923. Dim t As Double
  7924. GetMouse xo, yo, wm, bm
  7925. t = Timer
  7926. Do
  7927. akey = InKey
  7928. Select Case akey
  7929. Case ""
  7930. Case Chr(27) : s = "" : Exit Do
  7931. Case Chr(8)
  7932. If Len(s) > 1 Then s = Left(s, Len(s) - 1)
  7933. Case " " To Chr(126) : s = s + akey
  7934. Case Else : Exit Do
  7935. End Select
  7936. If Len(akey) And Len(s) Then
  7937. For i As Short = 1 To current_brush + 255
  7938. Dim n As Byte, namey As String
  7939. namey = Trim(tr(i).id)
  7940. n = InStr(LCase(namey), LCase(s))
  7941. If n Then
  7942. current_brush = i
  7943. ScreenLock
  7944. DrawPanel
  7945. Draw String (xpanel + 99 - Len(namey) * 4 + (n - 1) * 8, ypanel + ypalette + 82), Mid(namey, n, Len(s)), RGB(50, 200, 250)
  7946. ScreenUnlock
  7947. Exit For
  7948. End If
  7949. Next i
  7950. End If
  7951. GetMouse xm, ym, wm, bm
  7952. If bm <> 0 Then
  7953. Exit Do
  7954. ElseIf xo = -1 And xm <> -1 Then
  7955. Exit Do
  7956. ElseIf xo <> -1 And xm = -1 Then
  7957. Exit Do
  7958. ElseIf Sqr((xm - xo) ^ 2 + (ym - yo) ^ 2) > 10 Then
  7959. Exit Do
  7960. End If
  7961. Loop Until Timer > t + 5
  7962. DrawPanel
  7963. Do
  7964. GetMouse xm, ym, wm, bm
  7965. Loop Until bm = 0
  7966. End Sub
  7967. Sub SetTrack(x As UByte, y As UByte, code As UByte)
  7968. 'First, check that the new element can be placed
  7969. If Not allow_errors Then
  7970. If (x = 30 And tr(code).w > 1) Or (y = 30 And tr(code).h > 1) Then
  7971. Exit Sub
  7972. End If
  7973. End If
  7974. ScreenLock
  7975. 'Then make sure to leave no incomplete track elements
  7976. If Not allow_errors Then
  7977. ClearTrack x, y
  7978. If tr(code).w > 1 And x < 30 Then
  7979. ClearTrack x + 1, y
  7980. If tr(code).h > 1 And y < 30 Then ClearTrack x + 1, y + 1
  7981. End If
  7982. If tr(code).h > 1 And y < 30 Then ClearTrack x, y + 1
  7983. End If
  7984. 'Finally, place the new element
  7985. grid(x, y).track = code : DrawSpot x, y
  7986. 'If it's a tunnel, make it look good
  7987. If code = &H42 Then 'Vertical tunnel
  7988. If y > 1 Then DrawSpot x, y - 1
  7989. If y < 30 Then DrawSpot x, y + 1
  7990. ElseIf code = &H43 Then 'Horizontal tunnel
  7991. If x > 1 Then DrawSpot x - 1, y
  7992. If x < 30 Then DrawSpot x + 1, y
  7993. End If
  7994. '... and draw the complemental sub-elements, if any
  7995. If tr(code).w > 1 Then
  7996. If x + 1 <= 30 Then grid(x + 1, y).track = 255 : DrawSpot x + 1, y
  7997. If tr(code).h > 1 Then
  7998. If x + 1 <= 30 And y + 1 <= 30 Then
  7999. grid(x + 1, y + 1).track = 253
  8000. DrawSpot x + 1, y + 1
  8001. End If
  8002. End If
  8003. End If
  8004. If tr(code).h > 1 Then
  8005. If y + 1 <= 30 Then grid(x, y + 1).track = 254 : DrawSpot x, y + 1
  8006. End If
  8007. ScreenUnlock
  8008. End Sub
  8009. Sub RaiseTerrain(x As UByte, y As UByte)
  8010. ScreenLock
  8011. If x < 30 And y < 30 Then
  8012. Select Case grid(x + 1, y + 1).land
  8013. Case 0 To 5: grid(x + 1, y + 1).land = 11
  8014. Case 9 : grid(x + 1, y + 1).land = 16
  8015. Case 10 : grid(x + 1, y + 1).land = 18
  8016. Case 12 : grid(x + 1, y + 1).land = 8
  8017. Case 13
  8018. grid(x + 1, y + 1).land = 6
  8019. RaiseTerrain x + 1, y
  8020. RaiseTerrain x, y + 1
  8021. Case 14 : grid(x + 1, y + 1).land = 7
  8022. Case 17 : grid(x + 1, y + 1).land = 6
  8023. End Select
  8024. DrawSpot x + 1, y + 1
  8025. End If
  8026. If x > 0 And y > 0 Then
  8027. Select Case grid(x, y).land
  8028. Case 0 To 5 : grid(x, y).land = 13
  8029. Case 7 : grid(x, y).land = 18
  8030. Case 8 : grid(x, y).land = 16
  8031. Case 11
  8032. grid(x, y).land = 6
  8033. RaiseTerrain x - 1, y
  8034. RaiseTerrain x, y - 1
  8035. Case 12 : grid(x, y).land = 9
  8036. Case 14 : grid(x, y).land = 10
  8037. Case 15 : grid(x, y).land = 6
  8038. End Select
  8039. DrawSpot x, y
  8040. End If
  8041. If x > 0 And y < 30 Then
  8042. Select Case grid(x, y + 1).land
  8043. Case 0 To 5: grid(x, y + 1).land = 14
  8044. Case 8 : grid(x, y + 1).land = 15
  8045. Case 9 : grid(x, y + 1).land = 17
  8046. Case 11 : grid(x, y + 1).land = 7
  8047. Case 12
  8048. grid(x, y + 1).land = 6
  8049. RaiseTerrain x - 1, y
  8050. RaiseTerrain x, y + 1
  8051. Case 13 : grid(x, y + 1).land = 10
  8052. Case 16 : grid(x, y + 1).land = 6
  8053. End Select
  8054. DrawSpot x, y + 1
  8055. End If
  8056. If x < 30 And y > 0 Then
  8057. Select Case grid(x + 1, y).land
  8058. Case 0 To 5: grid(x + 1, y).land = 12
  8059. Case 7 : grid(x + 1, y).land = 15
  8060. Case 10 : grid(x + 1, y).land = 17
  8061. Case 11 : grid(x + 1, y).land = 8
  8062. Case 13 : grid(x + 1, y).land = 9
  8063. Case 14
  8064. grid(x + 1, y).land = 6
  8065. RaiseTerrain x, y - 1
  8066. RaiseTerrain x + 1, y
  8067. Case 18 : grid(x + 1, y).land = 6
  8068. End Select
  8069. DrawSpot x + 1, y
  8070. End If
  8071. ScreenUnlock
  8072. End Sub
  8073. Sub LowerTerrain(x As UByte, y As UByte)
  8074. ScreenLock
  8075. If x < 30 And y < 30 Then
  8076. Select Case grid(x + 1, y + 1).land
  8077. Case 6 : grid(x + 1, y + 1).land = 17
  8078. Case 7 : grid(x + 1, y + 1).land = 14
  8079. Case 8 : grid(x + 1, y + 1).land = 12
  8080. Case 11 : grid(x + 1, y + 1).land = 0
  8081. Case 15
  8082. grid(x + 1, y + 1).land = 0
  8083. LowerTerrain x + 1, y
  8084. LowerTerrain x, y + 1
  8085. Case 16 : grid(x + 1, y + 1).land = 9
  8086. Case 18 : grid(x + 1, y + 1).land = 10
  8087. End Select
  8088. DrawSpot x + 1, y + 1
  8089. End If
  8090. If x > 0 And y > 0 Then
  8091. Select Case grid(x, y).land
  8092. Case 6 : grid(x, y).land = 15
  8093. Case 9 : grid(x, y).land = 12
  8094. Case 10 : grid(x, y).land = 14
  8095. Case 13 : grid(x, y).land = 0
  8096. Case 16 : grid(x, y).land = 8
  8097. Case 17
  8098. grid(x, y).land = 0
  8099. LowerTerrain x, y - 1
  8100. LowerTerrain x - 1, y
  8101. Case 18 : grid(x, y).land = 7
  8102. End Select
  8103. DrawSpot x, y
  8104. End If
  8105. If x > 0 And y < 30 Then
  8106. Select Case grid(x, y + 1).land
  8107. Case 6 : grid(x, y + 1).land = 16
  8108. Case 7 : grid(x, y + 1).land = 11
  8109. Case 10 : grid(x, y + 1).land = 13
  8110. Case 14 : grid(x, y + 1).land = 0
  8111. Case 15 : grid(x, y + 1).land = 8
  8112. Case 17 : grid(x, y + 1).land = 9
  8113. Case 18
  8114. grid(x, y + 1).land = 0
  8115. LowerTerrain x - 1, y
  8116. LowerTerrain x, y + 1
  8117. End Select
  8118. DrawSpot x, y + 1
  8119. End If
  8120. If x < 30 And y > 0 Then
  8121. Select Case grid(x + 1, y).land
  8122. Case 6 : grid(x + 1, y).land = 18
  8123. Case 8 : grid(x + 1, y).land = 11
  8124. Case 9 : grid(x + 1, y).land = 13
  8125. Case 12 : grid(x + 1, y).land = 0
  8126. Case 15 : grid(x + 1, y).land = 7
  8127. Case 16
  8128. grid(x + 1, y).land = 0
  8129. LowerTerrain x + 1, y
  8130. LowerTerrain x, y - 1
  8131. Case 17 : grid(x + 1, y).land = 10
  8132. End Select
  8133. DrawSpot x + 1, y
  8134. End If
  8135. ScreenUnlock
  8136. End Sub
  8137. Function Enc_UTF8_to_UTF32 (s As String) As String
  8138. Dim s1 As String, s2 As String, w As Long
  8139. Dim As UByte v1, v2, v3, v4
  8140. If Len(s) = 0 Then Return ""
  8141. s1 = s
  8142. s2 = ""
  8143. Do
  8144. v1 = Asc(Left(s1, 1))
  8145. 'Note: This code does not check the validity of trailing bytes
  8146. 'for multi-byte codes, that is, it does not make sure that the
  8147. 'highest two bits are 1 and 0. It will work well as long as the
  8148. 'input code is well-behaved. Otherwise, it would be crap anyway.
  8149. 'The check is not performed to avoid making the code longer and
  8150. 'slower unnecessarily.
  8151. If v1 < 128 Then 'ASCII
  8152. w = v1
  8153. s1 = Mid(s1, 2)
  8154. s2 &= MkL(w)
  8155. ElseIf (v1 And 64) = 0 Then 'Invalid. Skip
  8156. s1 = Mid(s1, 2)
  8157. ElseIf (v1 And 32) = 0 Then 'Two-byte code
  8158. v2 = Asc(Mid(s1, 2, 1))
  8159. s1 = Mid(s1, 3)
  8160. w = (v2 And 63) Or ((v1 And 31) ShL 6)
  8161. s2 &= MkL(w)
  8162. ElseIf (v1 And 16) = 0 Then 'Three-byte code
  8163. v2 = Asc(Mid(s1, 2, 1))
  8164. v3 = Asc(Mid(s1, 3, 1))
  8165. s1 = Mid(s1, 4)
  8166. w = (v3 And 63) Or ((v2 And 63) ShL 6) Or ((v1 And 15) ShL 12)
  8167. s2 &= MkL(w)
  8168. ElseIf (v1 And 8) = 0 Then 'Four-byte code
  8169. v2 = Asc(Mid(s1, 2, 1))
  8170. v3 = Asc(Mid(s1, 3, 1))
  8171. v4 = Asc(Mid(s1, 4, 1))
  8172. s1 = Mid(s1, 5)
  8173. w = (v4 And 63) Or ((v3 And 63) ShL 6) Or ((v2 And 63) ShL 12) Or ((v1 And 7) ShL 18)
  8174. s2 &= MkL(w)
  8175. Else 'Invalid leading byte. Skip
  8176. s1 = Mid(s1, 2)
  8177. End If
  8178. Loop Until Len(s1) = 0
  8179. Return s2
  8180. End Function
  8181. Function Enc_UTF32_to_UTF8 (s As String) As String
  8182. Dim As UByte v1, v2, v3, v4
  8183. Dim w As Long, s1 As String, s2 As String
  8184. If Len(s) = 0 Then Return ""
  8185. s1 = s : s2 = ""
  8186. Do
  8187. w = CvL(Left(s1, 4))
  8188. s1 = Mid(s1, 5)
  8189. If w < 128 Then 'ASCII
  8190. v1 = w
  8191. s2 &= Chr(v1)
  8192. ElseIf w < 2 ^ 11 Then 'Two-byte code
  8193. v2 = (w And 63) Or 128
  8194. v1 = ((w ShR 6) And 31) Or &B11000000
  8195. s2 &= Chr(v1) & Chr(v2)
  8196. ElseIf w < 2 ^ 16 Then 'Three-byte code
  8197. v3 = (w And 63) Or 128
  8198. v2 = ((w ShR 6) And 63) Or 128
  8199. v1 = ((w ShR 12) And 15) Or &B11100000
  8200. s2 &= Chr(v1) & Chr(v2) & Chr(v3)
  8201. Else 'Four-byte code
  8202. v4 = (w And 63) Or 128
  8203. v3 = ((w ShR 6) And 63) Or 128
  8204. v2 = ((w ShR 12) And 63) Or 128
  8205. v1 = ((w ShR 18) And 7) Or &B11110000
  8206. s2 &= Chr(v1) & Chr(v2) & Chr(v3) & Chr(v4)
  8207. End If
  8208. Loop Until Len(s1) = 0
  8209. Return s2
  8210. End Function
  8211. Function Enc_UTF32_to_CP437 (s As String) As String
  8212. Dim s2 As String, w As Long, v As UByte
  8213. If Len(s) = 0 Then Return ""
  8214. For i As Short = 1 To Len(s) - 3 Step 4
  8215. w = CvL(Mid(s, i, 4))
  8216. If (w >= 32 And w <= 126) Then
  8217. v = w
  8218. Else
  8219. v = 0
  8220. For j As Short = 0 To UBound(toCP437)
  8221. If toCP437(j).utf32 = 0 Then Exit For
  8222. If w = toCP437(j).utf32 Then
  8223. v = toCP437(j).o
  8224. Exit For
  8225. End If
  8226. Next j
  8227. If v = 0 And w <> 0 Then v = 254
  8228. End If
  8229. s2 &= Chr(v)
  8230. Next i
  8231. Return s2
  8232. End Function
  8233. Function Enc_UTF32_to_Latin1 (s As String) As String
  8234. Dim s2 As String, w As Long, v As UByte
  8235. If Len(s) = 0 Then Return ""
  8236. For i As Short = 1 To Len(s) - 3 Step 4
  8237. w = CvL(Mid(s, i, 4))
  8238. If (w >= 32 And w <= 126) Or (w >= &HA0 And w <= &HFF) Then
  8239. v = w
  8240. ElseIf changing_title Then
  8241. 'We're chaning the window title, so Latin-2 codepoints
  8242. 'will be placed where Latin-2 usually puts them
  8243. Select Case w
  8244. 'The following code points correspond to Latin-2
  8245. 'actually and are mapped so that Hungarian language
  8246. 'is supported
  8247. Case &H150 : v = 213 'Capital O with double acute
  8248. Case &H170 : v = 219 'Capital U with double acute
  8249. Case &H151 : v = 245 'Lowercase o with double acute
  8250. Case &H171 : v = 251 'Lowercase u with double acute
  8251. 'Everything else is a question mark
  8252. Case Else : v = 63
  8253. End Select
  8254. Else
  8255. 'We're goint to map Latin-2 codepoints to special codes
  8256. 'in the font I designed, where I've located the corresponding
  8257. 'characters
  8258. Select Case w
  8259. 'The following code points correspond to Latin-2
  8260. 'actually and are mapped so that Hungarian language
  8261. 'is supported
  8262. Case &H150 : v = 133 'Capital O with double acute
  8263. Case &H170 : v = 139 'Capital U with double acute
  8264. Case &H151 : v = 149 'Lowercase o with double acute
  8265. Case &H171 : v = 155 'Lowercase u with double acute
  8266. 'The Euro sign is supported here
  8267. Case &H20AC: v = 132
  8268. 'Everything else is an empty rectangle
  8269. Case Else : v = 128
  8270. End Select
  8271. End If
  8272. s2 &= Chr(v)
  8273. Next i
  8274. Return s2
  8275. End Function
  8276. #ifdef __FB_DOS__
  8277. Sub FakeScreenLock
  8278. If fake_screenlock_level = 0 Then
  8279. ScreenCopy 0, 1
  8280. ScreenSet 1, 0
  8281. End If
  8282. fake_screenlock_level += 1
  8283. End Sub
  8284. Sub FakeScreenUnlock
  8285. fake_screenlock_level -= 1
  8286. If fake_screenlock_level = 0 Then
  8287. ScreenCopy 1, 0
  8288. ScreenSet 0, 0
  8289. ElseIf fake_screenlock_level = -1 Then
  8290. fake_screenlock_level = 0
  8291. End If
  8292. End Sub
  8293. #endif
  8294. Function FindStart As TrackVector
  8295. Dim As Byte i, j
  8296. Dim starts As String, n As Short
  8297. Dim slot As TrackVector
  8298. starts = Chr(1, &HB3, &HB4, &HB5, &H86, &H87, &H88, &H89, &H93, &H94, &H95, &H96)
  8299. For j = 1 To 30
  8300. For i = 1 To 30
  8301. If InStr(starts, Chr(grid(i, j).track)) Then
  8302. slot.x = i : slot.y = j
  8303. n += 1
  8304. End If
  8305. Next i
  8306. Next j
  8307. If n = 0 Then 'No start/finish line
  8308. slot.e = 60
  8309. Return slot
  8310. ElseIf n > 1 Then 'Too many start/finish lines
  8311. slot.e = 61
  8312. Return slot
  8313. Else
  8314. Select Case grid(slot.x, slot.y).track
  8315. Case 1, &H86, &H93 : slot.bearing = 0 'North
  8316. Case &HB5, &H89, &H96 : slot.bearing = 3 'West
  8317. Case &HB3, &H87, &H94 : slot.bearing = 2 'South
  8318. Case Else : slot.bearing = 1 'East
  8319. End Select
  8320. slot.origin = slot.bearing XOr 2
  8321. 'Terrain at track start is inadequate
  8322. If grid(slot.x, slot.y).land > 6 Then slot.e = 62
  8323. Return slot
  8324. End If
  8325. End Function
  8326. Sub Flood(x As UByte, y As UByte)
  8327. ScreenLock
  8328. If x < 30 And y < 30 Then
  8329. Select Case grid(x + 1, y + 1).land
  8330. Case 0 : grid(x + 1, y + 1).land = 5
  8331. Case 2 To 4 : grid(x + 1, y + 1).land = 1
  8332. End Select
  8333. DrawSpot x + 1, y + 1
  8334. End If
  8335. If x > 0 And y > 0 Then
  8336. Select Case grid(x, y).land
  8337. Case 0 : grid(x, y).land = 3
  8338. Case 2, 4, 5 : grid(x, y).land = 1
  8339. End Select
  8340. DrawSpot x, y
  8341. End If
  8342. If x > 0 And y < 30 Then
  8343. Select Case grid(x, y + 1).land
  8344. Case 0 : grid(x, y + 1).land = 4
  8345. Case 2, 3, 5 : grid(x, y + 1).land = 1
  8346. End Select
  8347. DrawSpot x, y + 1
  8348. End If
  8349. If x < 30 And y > 0 Then
  8350. Select Case grid(x + 1, y).land
  8351. Case 0 : grid(x + 1, y).land = 2
  8352. Case 3 To 5 : grid(x + 1, y).land = 1
  8353. End Select
  8354. DrawSpot x + 1, y
  8355. End If
  8356. ScreenUnlock
  8357. End Sub
  8358. Sub Dry(x As UByte, y As UByte)
  8359. ScreenLock
  8360. If x < 30 And y < 30 Then
  8361. Select Case grid(x + 1, y + 1).land
  8362. Case 1 : grid(x + 1, y + 1).land = 3
  8363. Case 2, 4, 5 : grid(x + 1, y + 1).land = 0
  8364. End Select
  8365. DrawSpot x + 1, y + 1
  8366. End If
  8367. If x > 0 And y > 0 Then
  8368. Select Case grid(x, y).land
  8369. Case 1 : grid(x, y).land = 5
  8370. Case 2 To 4 : grid(x, y).land = 0
  8371. End Select
  8372. DrawSpot x, y
  8373. End If
  8374. If x > 0 And y < 30 Then
  8375. Select Case grid(x, y + 1).land
  8376. Case 1 : grid(x, y + 1).land = 2
  8377. Case 3 To 5 : grid(x, y + 1).land = 0
  8378. End Select
  8379. DrawSpot x, y + 1
  8380. End If
  8381. If x < 30 And y > 0 Then
  8382. Select Case grid(x + 1, y).land
  8383. Case 1 : grid(x + 1, y).land = 4
  8384. Case 2, 3, 5 : grid(x + 1, y).land = 0
  8385. End Select
  8386. DrawSpot x + 1, y
  8387. End If
  8388. ScreenUnlock
  8389. End Sub
  8390. Sub StartUp
  8391. Dim s As String, n As Short
  8392. program_path = ""
  8393. #ifdef __FB_LINUX__
  8394. program_path = Environ("HOME") + "/.bliss/"
  8395. If Not FileExists(program_path + "bliss.cfg") Then
  8396. program_path = Environ("HOME") + "/bliss/"
  8397. If Not FileExists(program_path + "bliss.cfg") Then
  8398. program_path = ExePath
  8399. If Right(program_path, 1) <> "/" Then program_path &= "/"
  8400. End If
  8401. End If
  8402. #elseif defined (__FB_DOS__)
  8403. If FileExists("bliss.cfg") Then
  8404. program_path = ""
  8405. Else
  8406. s = Environ("PATH")
  8407. Do
  8408. s = Trim(s)
  8409. If Len(s) = 0 Then
  8410. Screen 0
  8411. Print
  8412. Print "Configuration file not found!"
  8413. Print "Create an empty one or reinstall Bliss."
  8414. Print
  8415. End 1
  8416. End If
  8417. n = InStr(s, ";")
  8418. If n Then
  8419. program_path = Left(s, n - 1)
  8420. s = Mid(s, n + 1)
  8421. Else
  8422. program_path = s
  8423. s = ""
  8424. End If
  8425. If Right(program_path, 1) <> "\" Then program_path = program_path + "\"
  8426. If FileExists(program_path + "bliss.cfg") Then Exit Do
  8427. Loop
  8428. End If
  8429. #elseif defined (__FB_WIN32__)
  8430. program_path = Environ("APPDATA") + "\bliss\"
  8431. If Not FileExists(program_path + "bliss.cfg") Then
  8432. program_path = ExePath
  8433. If Right(program_path, 1) <> "\" Then program_path &= "\"
  8434. End If
  8435. #endif
  8436. If Not FileExists(program_path + "bliss.cfg") Then
  8437. ScreenRes 640, 64, 32
  8438. Width 80, 4
  8439. Line (0, 0)-(639, 63), RGB(30, 30, 50), BF
  8440. Color RGB(200, 200, 200)
  8441. Draw String (204, 16), "Configuration file not found!"
  8442. Draw String (164, 32), "Create an empty one or reinstall Bliss."
  8443. WindowTitle "Bliss - Error"
  8444. Dim t As Double, k As String
  8445. Dim As Integer xm, ym, bm
  8446. t = Timer
  8447. Do
  8448. k = Inkey
  8449. If Len(k) Then Exit Do
  8450. GetMouse xm, ym, , bm
  8451. If bm > 0 Then Exit Do
  8452. Loop Until Timer > t + 10
  8453. End 1
  8454. End If
  8455. track_path = CurDir
  8456. #ifdef __FB_LINUX__
  8457. If Right(track_path, 1) <> "/" Then track_path = track_path + "/"
  8458. #else
  8459. If Right(track_path, 1) <> "\" Then track_path = track_path + "\"
  8460. #endif
  8461. End Sub
  8462. 'Draw string using the font loaded with LoadFont (used for Latin-1)
  8463. Sub PutString (x As Short, y As Short, s As String, col As ULong, col2 As ULong = RGB(&HFF, 0, &HFF))
  8464. Dim As Any Ptr mystring, mymask
  8465. Dim c As UByte
  8466. If Len(s) = 0 Then Exit Sub
  8467. mystring = ImageCreate(8 * Len(s), 16, col)
  8468. mymask = ImageCreate(8 * Len(s), 16, 0)
  8469. For i As Short = 1 To Len(s)
  8470. c = Asc(Mid(s, i, 1))
  8471. Put mymask, (8 * i - 8, 0), mask, (0, 16 * c)-(7, 16 * c + 15), PSet
  8472. Put mystring, (8 * i - 8, 0), font, (0, 16 * c)-(7, 16 * c + 15), And
  8473. Next i
  8474. If col2 <> RGB(&HFF, 0, &HFF) Then _
  8475. Line (x, y)-(x + 8 * Len(s) - 1, y + 15), col2, BF
  8476. Put mystring, (0, 0), mymask, Or
  8477. Put (x, y), mystring, Trans
  8478. ImageDestroy mystring
  8479. ImageDestroy mymask
  8480. End Sub
  8481. 'Paste a string based rectangular region on the grid
  8482. Sub PutTrack(x As UByte, y As UByte, t As String, forcefull As Byte = 0)
  8483. Dim As Byte i, j, c
  8484. Dim n As Short
  8485. n = 3
  8486. For j = y To y + ASC(Mid(t, 2, 1)) - 1
  8487. For i = x To x + ASC(Left(t, 1)) - 1
  8488. c = ASC(Mid(t, n, 1))
  8489. n += 1
  8490. If c And 1 Then
  8491. If affect_track Or forcefull Then _
  8492. grid(i, j).track = ASC(Mid(t, n, 1))
  8493. n += 1
  8494. Else
  8495. If affect_track Or forcefull Then _
  8496. grid(i, j).track = 0
  8497. End If
  8498. If c And 2 Then
  8499. If affect_terrain Or forcefull Then _
  8500. grid(i, j).land = ASC(Mid(t, n, 1))
  8501. n += 1
  8502. Else
  8503. If affect_terrain Or forcefull Then _
  8504. grid(i, j).land = 0
  8505. End If
  8506. If c And 4 Then
  8507. If colouring_mode Or forcefull Then _
  8508. grid(i, j).border = CvL(Mid(t, n, 4))
  8509. n += 4
  8510. Else
  8511. If colouring_mode Or forcefull Then _
  8512. grid(i, j).border = 0
  8513. End If
  8514. If c And 8 Then
  8515. If colouring_mode Or forcefull Then _
  8516. grid(i, j).bgc = CvL(Mid(t, n, 4))
  8517. n += 4
  8518. Else
  8519. If colouring_mode Or forcefull Then _
  8520. grid(i, j).bgc = 0
  8521. End If
  8522. Next i
  8523. Next j
  8524. End Sub
  8525. Sub QuitProgram
  8526. Dim v As Short, akey As String
  8527. Dim As Integer xm, ym, wm, bm
  8528. If modified Then
  8529. MenuBox 28, 10, "Quit Bliss"
  8530. ceny += 8
  8531. TCentre , "Current track data will be lost!", RGB(200, 200, 240)
  8532. TCentre , "Are you sure you want to leave the program?", RGB(200, 200, 240)
  8533. TCentre
  8534. buttons = 0
  8535. StackButton " Quit ", 1
  8536. StackButton " Stay ", 2, , 50
  8537. EndOfButtonStack
  8538. Do
  8539. v = ManageButtons
  8540. akey = InKey
  8541. Loop Until v <> 0 Or akey <> ""
  8542. buttons = 0
  8543. Else
  8544. v = 1
  8545. End If
  8546. If v = 1 Then
  8547. 'SaveTransformations '-- COMMENT TO PUBLISH
  8548. ImageDestroy bigicons
  8549. #ifndef __FB_DOS__
  8550. HTTP_End
  8551. #endif
  8552. End
  8553. End If
  8554. Do
  8555. GetMouse xm, ym, wm, bm
  8556. Loop Until bm = 0
  8557. DrawTrack
  8558. DrawPanel
  8559. End Sub
  8560. Sub Editor
  8561. Dim As Integer xm, ym, wm, bm
  8562. Dim akey As String, s As String
  8563. Dim As Short xgrid, ygrid 'Coors within a box
  8564. Dim As Short xcross, ycross 'Coors near a vertex
  8565. Dim As Short xbrush, ybrush 'Coors in the centre of current brush
  8566. Dim As Short exgrid, eygrid 'To check when it changes
  8567. Dim As Short stylex, styley 'Last styling coordinates
  8568. Dim As Byte exxcursor = 1, exycursor = 1
  8569. Dim As Byte xpcursor = 0, ypcursor = 0 'Palette cursor
  8570. Dim As Byte inpalette = 0, updatepalette = 0
  8571. Dim tempboard As String 'Temporal rectangle on the grid
  8572. Dim valuecopy As UByte, specialkeylock As Byte
  8573. Dim idletimer As Double, ctrltoselect As Byte
  8574. Dim updatepaste As Byte, stroking As Byte
  8575. Dim previous_page As Byte = 0 'For returning after 2xF1
  8576. idletimer = Timer
  8577. Do
  8578. 'Read input
  8579. akey = InKey
  8580. GetMouse xm, ym, wm, bm
  8581. 'This is to prevent the program from hogging the CPU
  8582. If xm <> -1 Or Len(akey) <> 0 Then idletimer = Timer
  8583. If Timer > idletimer + 1 Then Sleep 500
  8584. 'Check on clipboard import, but not too often
  8585. If Timer > idletimer + .1 Then CheckClipboardImport
  8586. 'CTRL key to select
  8587. If MultiKey(&H1D) Then
  8588. If selecting = 0 Then selecting = -1 : ctrltoselect = -1
  8589. Else
  8590. If (selecting = -1 Or selecting = -3) And ctrltoselect = -1 Then selecting = 0
  8591. ctrltoselect = 0
  8592. End If
  8593. 'Calculate coordinates
  8594. xgrid = (xm - xoffs) \ bigwidth + 1
  8595. ygrid = (ym - yoffs) \ 22 + 1
  8596. 'Invalidate border bogus
  8597. If xgrid = 1 And xm < xoffs Then xgrid = -100
  8598. If ygrid = 1 And ym < yoffs Then ygrid = -100
  8599. xcross = (xm - xoffs + (bigwidth ShR 1)) \ bigwidth
  8600. ycross = (ym - yoffs + 11) \ 22
  8601. If tr(current_brush).h = 2 Then
  8602. ybrush = ycross
  8603. Else
  8604. ybrush = ygrid
  8605. End If
  8606. If tr(current_brush).w = 2 Then
  8607. xbrush = xcross
  8608. Else
  8609. xbrush = xgrid
  8610. End If
  8611. If ybrush < 1 Then ybrush = 1
  8612. If ybrush > 30 Then ybrush = 30
  8613. If xbrush < 1 Then xbrush = 1
  8614. If xbrush > 30 Then xbrush = 30
  8615. 'Draw coordinates and content at the cursor
  8616. If xgrid <> exgrid Or ygrid <> eygrid Or updatepaste Then
  8617. If pasting Then
  8618. Dim As Byte dx, dy
  8619. 'Paste old contents if any
  8620. If Len(tempboard) <> 0 AndAlso exgrid >= 1 And exgrid <= 30 And eygrid >= 1 And eygrid <= 30 Then
  8621. dx = ASC(Left(tempboard, 1)) : dy = ASC(Mid(tempboard, 2, 1))
  8622. xselect = exgrid - dx \ 2
  8623. If xselect < 1 Then xselect = 1
  8624. If xselect + dx - 1 > 30 Then xselect = 30 - dx + 1
  8625. yselect = eygrid - dy \ 2
  8626. If yselect < 1 Then yselect = 1
  8627. If yselect + dy - 1 > 30 Then yselect = 30 - dy + 1
  8628. PutTrack xselect, yselect, tempboard, -1
  8629. End If
  8630. If xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  8631. 'Read new region into buffer
  8632. dx = ASC(Left(clipboard, 1)) : dy = ASC(Mid(clipboard, 2, 1))
  8633. xselect = xgrid - dx \ 2
  8634. If xselect < 1 Then xselect = 1
  8635. If xselect + dx - 1 > 30 Then xselect = 30 - dx + 1
  8636. yselect = ygrid - dy \ 2
  8637. If yselect < 1 Then yselect = 1
  8638. If yselect + dy - 1 > 30 Then yselect = 30 - dy + 1
  8639. x2select = xselect + dx - 1
  8640. y2select = yselect + dy - 1
  8641. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  8642. 'And place clipboard contents on it
  8643. PutTrack xselect, yselect, clipboard
  8644. Else
  8645. xselect = 0
  8646. End If
  8647. updatepaste = 0
  8648. End If
  8649. ScreenLock
  8650. If pasting Then DrawTrack
  8651. If xgrid >= 1 And ygrid >= 1 And xgrid <= 30 And ygrid <= 30 Then
  8652. Dim coorpos As Short
  8653. coorpos = xpanel + 170
  8654. If colouring_mode Then coorpos -= 72
  8655. Line (coorpos - 74, ypanel + 432)- STEP (152, 31), RGB(30, 30, 50), BF
  8656. s = "(" + Trim(Str(xgrid)) + ", " + Trim(Str(ygrid)) + ")"
  8657. If selecting = -2 Then s = "(" + Trim(Str(xselect)) + ", " + Trim(Str(yselect)) + ")-" + s
  8658. Draw String (coorpos - Len(s) * 4, ypanel + 430), s, RGB(200, 200, 200)
  8659. If data_codes Then
  8660. s = "Ter[" + Hex(grid(xgrid, ygrid).land) + "h] Trk[" + Hex(grid(xgrid, ygrid).track) + "h]"
  8661. Else
  8662. s = Trim(tr(GetParent(xgrid, ygrid)).id)
  8663. End If
  8664. Draw String (coorpos - Len(s) * 4, ypanel + 446), s, RGB(200, 200, 200)
  8665. End If
  8666. ScreenUnlock
  8667. exgrid = xgrid : eygrid = ygrid
  8668. End If
  8669. 'Keyboard cursor
  8670. ManageKeyboardCursor
  8671. If inpalette <> 0 And updatepalette <> 0 Then
  8672. ScreenLock
  8673. DrawPanel
  8674. Line (xpanel + xpalette + bigwidth * xpcursor, ypanel + ypalette + 22 * ypcursor) - Step (bigwidth - 1, 21), RGB(200, 200, 200), B
  8675. ScreenUnlock
  8676. updatepalette = 0
  8677. End If
  8678. 'Mouse button actions
  8679. If bm = 1 Then
  8680. If selecting <> 0 AndAlso xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  8681. selecting = -2 'Selecting with the mouse
  8682. If xselect = 0 Then
  8683. xselect = xgrid : yselect = ygrid
  8684. x2select = xgrid : y2select = ygrid
  8685. DrawTrack
  8686. ElseIf xgrid <> x2select Or ygrid <> y2select Then
  8687. x2select = xgrid : y2select = ygrid
  8688. DrawTrack
  8689. End If
  8690. ElseIf pasting <> 0 AndAlso xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  8691. tempboard = "" 'Accept paste
  8692. pasting = 0
  8693. xselect = 0
  8694. DrawTrack
  8695. PushUndo
  8696. Do
  8697. GetMouse xm, ym, wm, bm
  8698. Loop Until bm <> 1
  8699. modified = -1
  8700. Else
  8701. If xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  8702. If xselect Then
  8703. xselect = 0 : yselect = 0
  8704. x2select = 0 : y2select = 0
  8705. DrawTrack
  8706. Do
  8707. GetMouse xm, ym, wm, bm
  8708. Loop Until bm <> 1 Or xm < xoffs
  8709. ElseIf colouring_mode Then
  8710. stroking = -1
  8711. If stylex <> xgrid Or styley <> ygrid Then
  8712. Dim As ULong last_bgc, last_border
  8713. last_bgc = grid(xgrid, ygrid).bgc
  8714. last_border = grid(xgrid, ygrid).border
  8715. grid(xgrid, ygrid).bgc = current_bgc
  8716. grid(xgrid, ygrid).border = current_border
  8717. If last_border <> current_border Then
  8718. DrawTrack
  8719. ElseIf last_bgc <> current_bgc Then
  8720. DrawSpot xgrid, ygrid
  8721. End If
  8722. stylex = xgrid : styley = ygrid
  8723. End If
  8724. Else
  8725. stroking = -1
  8726. 'Update the track/terrain brush-like
  8727. ScreenLock
  8728. If current_page < 10 Then
  8729. SetTrack xbrush, ybrush, current_brush
  8730. vlast.x = xbrush : vlast.y = ybrush
  8731. ElseIf current_page = 10 Then
  8732. grid(xgrid, ygrid).land = current_terrain_brush
  8733. DrawSpot xgrid, ygrid
  8734. ElseIf current_page = 11 Then
  8735. If current_terrain_brush >= 1 And current_terrain_brush <= 5 Then
  8736. Flood xcross, ycross
  8737. Else
  8738. RaiseTerrain xcross, ycross
  8739. End If
  8740. End If
  8741. ScreenUnlock
  8742. modified = -1
  8743. End If
  8744. ElseIf xgrid >= -5 And xgrid <= -1 And ygrid >= 29 And ygrid <= 30 Then
  8745. current_page = (xgrid + 5) + 5 * (ygrid - 29)
  8746. DrawPanel
  8747. ElseIf xgrid = 0 And ygrid >= 29 And ygrid <= 30 Then
  8748. current_page = ygrid - 19
  8749. DrawPanel
  8750. ElseIf xgrid >= -5 And xgrid <= 0 And ygrid >= 22 And ygrid <= 27 Then
  8751. If current_page < 10 Then
  8752. current_brush = itr(xgrid + 5, ygrid - 22, current_page)
  8753. ElseIf current_page >= 10 Then
  8754. current_terrain_brush = itr(xgrid + 5, ygrid - 22, current_page)
  8755. End If
  8756. Sleep 200 'To avoid picking the wrong element
  8757. DrawPanel
  8758. ElseIf xgrid >= -13 And xgrid <= -7 And ygrid >= 29 And ygrid <= 30 Then
  8759. SelectBackground
  8760. DrawTrack
  8761. DrawPanel
  8762. modified = -1
  8763. End If
  8764. End If
  8765. ElseIf bm = 2 Then
  8766. If xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  8767. If pasting Then
  8768. Dim As Byte dx, dy
  8769. 'Cancel pasting
  8770. dx = ASC(Left(tempboard, 1)) : dy = ASC(Mid(tempboard, 2, 1))
  8771. xselect = xgrid - dx \ 2
  8772. If xselect < 1 Then xselect = 1
  8773. If xselect + dx - 1 > 30 Then xselect = 30 - dx + 1
  8774. yselect = ygrid - dy \ 2
  8775. If yselect < 1 Then yselect = 1
  8776. If yselect + dy - 1 > 30 Then yselect = 30 - dy + 1
  8777. PutTrack xselect, yselect, tempboard
  8778. tempboard = ""
  8779. pasting = 0
  8780. xselect = 0
  8781. DrawTrack
  8782. Do
  8783. GetMouse xm, ym, wm, bm
  8784. Loop Until bm <> 2
  8785. ElseIf xselect Then
  8786. xselect = 0 : yselect = 0
  8787. x2select = 0 : y2select = 0
  8788. DrawTrack
  8789. Do
  8790. GetMouse xm, ym, wm, bm
  8791. Loop Until bm <> 2 Or xm < xoffs
  8792. ElseIf colouring_mode Then
  8793. stroking = -1
  8794. If stylex <> xgrid Or styley <> ygrid Then
  8795. Dim As ULong last_bgc, last_border
  8796. last_bgc = grid(xgrid, ygrid).bgc
  8797. last_border = grid(xgrid, ygrid).border
  8798. grid(xgrid, ygrid).bgc = 0
  8799. grid(xgrid, ygrid).border = 0
  8800. If last_border <> 0 Then
  8801. DrawTrack
  8802. ElseIf last_bgc <> 0 Then
  8803. DrawSpot xgrid, ygrid
  8804. End If
  8805. stylex = xgrid : styley = ygrid
  8806. End If
  8807. Else
  8808. stroking = -1
  8809. ScreenLock
  8810. If current_page < 10 Then
  8811. ClearTrack xgrid, ygrid
  8812. ElseIf current_page = 10 Then
  8813. grid(xgrid, ygrid).land = 0
  8814. DrawSpot xgrid, ygrid
  8815. Else
  8816. If current_terrain_brush >= 1 And current_terrain_brush <= 5 Then
  8817. Dry xcross, ycross
  8818. Else
  8819. LowerTerrain xcross, ycross
  8820. End If
  8821. End If
  8822. ScreenUnlock
  8823. modified = -1
  8824. End If
  8825. End If
  8826. ElseIf bm = 4 Then
  8827. If xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  8828. If colouring_mode Then
  8829. current_bgc = grid(xgrid, ygrid).bgc
  8830. current_border = grid(xgrid, ygrid).border
  8831. Else
  8832. PickTrack xgrid, ygrid
  8833. End If
  8834. DrawPanel
  8835. End If
  8836. ElseIf bm = 0 Then
  8837. 'Button released -> end of stroke
  8838. If stroking Then
  8839. stroking = 0
  8840. PushUndo
  8841. End If
  8842. 'Any styling is interrupted
  8843. stylex = -1 : styley = -1
  8844. 'Final selection step
  8845. If selecting = -2 Then selecting = 0
  8846. End If
  8847. ManageIcons
  8848. 'Handle F11 and F12 for GNU/Linux
  8849. If specialkeylock = 0 Then
  8850. If MultiKey(&H57) Then
  8851. akey = Chr(255) + Chr(133)
  8852. specialkeylock = -1
  8853. ElseIf MultiKey(&H58) Then
  8854. akey = Chr(255) + Chr(134)
  8855. specialkeylock = -1
  8856. End If
  8857. ElseIf MultiKey(&H57) = 0 And MultiKey(&H58) = 0 Then
  8858. specialkeylock = 0
  8859. End If
  8860. Select Case akey
  8861. '--- Palette pages
  8862. Case Chr(255) + Chr(59) To Chr(255) + Chr(68)
  8863. 'This check is necessary in GNU/Linux because the
  8864. 'FreeBasic compiler does not support Shift+Functional
  8865. 'keys in InKey for this platform.
  8866. If MultiKey(&H2A) Or MultiKey(&H36) Then
  8867. If ASC(Right(akey, 1)) = 59 Then
  8868. current_page = 10
  8869. DrawPanel
  8870. ElseIf ASC(Right(akey, 1)) = 60 Then
  8871. current_page = 11
  8872. DrawPanel
  8873. End If
  8874. ElseIf current_page = 0 And akey = Chr(255, 59) Then
  8875. current_page = previous_page
  8876. DrawPanel
  8877. Menu_Help
  8878. Else
  8879. previous_page = current_page
  8880. current_page = ASC(Right(akey, 1)) - 59
  8881. DrawPanel
  8882. End If
  8883. Case Chr(255) + Chr(133), Chr(255) + Chr(84)
  8884. current_page = 10
  8885. DrawPanel
  8886. Case Chr(255) + Chr(134), Chr(255) + Chr(85)
  8887. current_page = 11
  8888. DrawPanel
  8889. Case " " 'Switch between mountain and water
  8890. If current_page = 11 Then
  8891. If current_terrain_brush = 0 Or current_terrain_brush > 5 Then
  8892. current_terrain_brush = 1
  8893. Else
  8894. current_terrain_brush = 6
  8895. End If
  8896. DrawPanel
  8897. ElseIf current_page <= 10 Then
  8898. SelectByTyping
  8899. End If
  8900. '---- Switches
  8901. Case Chr(5) 'CTRL+E - Allow mixing track elements
  8902. allow_errors = Not allow_errors
  8903. DrawPanel
  8904. Case Chr(4) 'CTRL+D - Display errors and warnings
  8905. show_errors = Not show_errors
  8906. DrawTrack : DrawPanel
  8907. Case Chr(7) 'CTRL+G - Show grid
  8908. show_grid = Not show_grid
  8909. DrawTrack : DrawPanel
  8910. Case Chr(17) 'CTRL+Q - Display codes instead of element names
  8911. data_codes = Not data_codes
  8912. DrawTrack : DrawPanel
  8913. Case Chr(20) 'CTRL+T - Switch terrain affected by paste
  8914. affect_terrain = Not affect_terrain
  8915. If pasting Then updatepaste = -1
  8916. DrawPanel
  8917. Case Chr(11) 'CTRL+K - Switch track affected by paste
  8918. affect_track = Not affect_track
  8919. If pasting Then updatepaste = -1
  8920. DrawPanel
  8921. Case Chr(18) 'CTRL+R - Redraw track
  8922. DrawTrack
  8923. '---- Copying, pasting & co.
  8924. Case Chr(3) 'CTRL+C - Copy
  8925. CopyOrCut : DrawPanel
  8926. Case Chr(24) 'CTRL+X - Cut
  8927. CopyOrCut -1 : PushUndo : DrawPanel : modified = -1
  8928. Case Chr(22) 'CTRL+V - Paste
  8929. Paste : modified = -1
  8930. Case Chr(26) 'CTRL+Z - Undo
  8931. If Not pasting Then Undo : modified = -1
  8932. Case Chr(25) 'CTRL+Y - Redo
  8933. If Not pasting Then Redo : modified = -1
  8934. Case Chr(23) 'CTRL+W - Whole-Track Selection / Deselection
  8935. If pasting = 0 And bm = 0 Then
  8936. If xselect Then
  8937. xselect = 0
  8938. Else
  8939. xselect = 1 : yselect = 1
  8940. x2select = 30 : y2select = 30
  8941. End If
  8942. DrawTrack
  8943. End If
  8944. '---- Check track
  8945. Case "c", "C" : CheckTrack
  8946. '---- Save track image
  8947. Case Chr(19) 'CTRL+S
  8948. Menu_TrackShot
  8949. Case Chr(8) 'CTRL+H - Provide hash value
  8950. Error_Message "Current track hash value is " + Hex(Hash32), "Information requested"
  8951. '---- Flipping and rotating
  8952. Case "f" 'Horizontal flipping
  8953. If pasting Then
  8954. clipboard = HFlipTrack(clipboard)
  8955. updatepaste = -1
  8956. ElseIf xselect Then
  8957. If selecting = 0 Then
  8958. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  8959. tempboard = HFlipTrack(tempboard)
  8960. PutTrack xselect, yselect, tempboard, -1
  8961. DrawTrack
  8962. PushUndo
  8963. End If
  8964. ElseIf current_page < 10 Then
  8965. current_brush = tr(current_brush).hflip
  8966. DrawPanel
  8967. ElseIf current_page = 10 Then
  8968. current_terrain_brush = ttr(current_terrain_brush).hflip
  8969. DrawPanel
  8970. End If
  8971. Case "F" 'Vertical flipping
  8972. If pasting Then
  8973. clipboard = VFlipTrack(clipboard)
  8974. updatepaste = -1
  8975. ElseIf xselect Then
  8976. If selecting = 0 Then
  8977. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  8978. tempboard = VFlipTrack(tempboard)
  8979. PutTrack xselect, yselect, tempboard, -1
  8980. DrawTrack
  8981. PushUndo
  8982. End If
  8983. ElseIf current_page < 10 Then
  8984. current_brush = tr(current_brush).vflip
  8985. DrawPanel
  8986. ElseIf current_page = 10 Then
  8987. current_terrain_brush = ttr(current_terrain_brush).vflip
  8988. DrawPanel
  8989. End If
  8990. Case "r" 'Clockwise rotation
  8991. If pasting Then
  8992. clipboard = CRotate(clipboard)
  8993. updatepaste = -1
  8994. ElseIf xselect Then
  8995. If selecting = 0 Then
  8996. If x2select - xselect = y2select - yselect Then
  8997. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  8998. tempboard = CRotate(tempboard)
  8999. PutTrack xselect, yselect, tempboard, -1
  9000. DrawTrack
  9001. PushUndo
  9002. Do
  9003. GetMouse xm, ym, wm, bm
  9004. Loop Until bm <> 1
  9005. Else
  9006. NotASquare
  9007. End If
  9008. End If
  9009. ElseIf current_page < 10 Then
  9010. current_brush = tr(current_brush).cr
  9011. DrawPanel
  9012. ElseIf current_page = 10 Then
  9013. current_terrain_brush = ttr(current_terrain_brush).cr
  9014. DrawPanel
  9015. End If
  9016. Case "R" 'Counter-clockwise rotation
  9017. If pasting Then
  9018. clipboard = CCRotate(clipboard)
  9019. updatepaste = -1
  9020. ElseIf xselect Then
  9021. If selecting = 0 Then
  9022. If x2select - xselect = y2select - yselect Then
  9023. tempboard = GetTrack(xselect, yselect, x2select, y2select)
  9024. tempboard = CCRotate(tempboard)
  9025. PutTrack xselect, yselect, tempboard, -1
  9026. DrawTrack
  9027. PushUndo
  9028. Do
  9029. GetMouse xm, ym, wm, bm
  9030. Loop Until bm <> 1
  9031. Else
  9032. NotASquare
  9033. End If
  9034. End If
  9035. ElseIf current_page < 10 Then
  9036. current_brush = tr(current_brush).ccr
  9037. DrawPanel
  9038. ElseIf current_page = 10 Then
  9039. current_terrain_brush = ttr(current_terrain_brush).ccr
  9040. DrawPanel
  9041. End If
  9042. '---- Track element selectors
  9043. Case "m", "M" 'Material (pavement, dirt, ice)
  9044. Select Case current_brush
  9045. Case 1 : current_brush = &H86
  9046. Case &HB3 To &HB5 : current_brush -= &H2C
  9047. Case &H86 To &H89 : current_brush += 13
  9048. Case &H93 : current_brush = 1
  9049. Case &H94 To &H96 : current_brush += &H1F
  9050. Case 4, 5, 14, 15 : current_brush += 10
  9051. Case 24, 25 : current_brush -= 20
  9052. Case &H4A : current_brush = &H7D
  9053. Case &H7D : current_brush = &H8A
  9054. Case &H8A : current_brush = &H4A
  9055. Case 6 To 9, &H10 To &H13 : current_brush += 10
  9056. Case &H1A To &H1D : current_brush -= 20
  9057. Case &HA To &HD, &H14 To &H17 : current_brush += 10
  9058. Case &H1E To &H21 : current_brush -= 20
  9059. Case &H4B To &H52 : current_brush += &H33
  9060. Case &H7E To &H85 : current_brush += 13
  9061. Case &H8B To &H92 : current_brush -= &H40
  9062. End Select
  9063. DrawPanel
  9064. Case "u", "U" : LinkTiles
  9065. Case "a" To "o", "q" To "w"
  9066. SmartSelect akey
  9067. Case "A" To "O", "Q" To "W"
  9068. SmartSelect akey, -1
  9069. '~ Case "s", "S" 'Street, straightway
  9070. '~ If tr(current_brush).entity = ASC("s") Then
  9071. '~ current_brush = tr(current_brush).cr
  9072. '~ Else
  9073. '~ Dim m As Byte
  9074. '~
  9075. '~ If tr(current_brush).material >= 1 And tr(current_brush).material <= 3 Then
  9076. '~ m = tr(current_brush).material
  9077. '~ Else
  9078. '~ m = 1
  9079. '~ End If
  9080. '~
  9081. '~ For i As UByte = 1 To 190
  9082. '~ If tr(i).material = m And tr(i).entity = ASC("s") Then
  9083. '~ current_brush = i
  9084. '~ Exit For
  9085. '~ End If
  9086. '~ Next i
  9087. '~ End If
  9088. '~ DrawPanel
  9089. Case "x", "X"
  9090. current_brush = 255
  9091. DrawPanel
  9092. Case "y", "Y"
  9093. current_brush = 254
  9094. DrawPanel
  9095. Case "z", "Z"
  9096. current_brush = 253
  9097. DrawPanel
  9098. Case "\"
  9099. If allow_errors Then
  9100. Dim temp_s As String, temp_t As Double
  9101. Dim temp_key As String
  9102. Line (xpanel + 77, ypanel + ypalette + 33)- Step (43, 43), RGB(30, 30, 50), BF
  9103. PutIcon 19, 18, xpanel + 77, ypanel + ypalette + 33
  9104. PutIcon 20, 18, xpanel + 99, ypanel + ypalette + 33
  9105. PutIcon 19, 19, xpanel + 77, ypanel + ypalette + 55
  9106. PutIcon 20, 19, xpanel + 99, ypanel + ypalette + 55
  9107. 'You have to type a hex value in three seconds
  9108. temp_t = Timer
  9109. temp_s = ""
  9110. Do
  9111. temp_key = InKey
  9112. Select Case temp_key
  9113. Case "0" To "9", "a" To "f", "A" To "F"
  9114. temp_s &= temp_key
  9115. If Len(temp_s) = 2 Then Exit Do
  9116. Case Chr(8), Chr(255, 83)
  9117. temp_s = ""
  9118. temp_t = Timer
  9119. Case ""
  9120. Case Else
  9121. temp_s = ""
  9122. Exit Do
  9123. End Select
  9124. Loop Until Timer >= temp_t + 3
  9125. If Len(temp_s) Then
  9126. If current_page = 10 Then
  9127. current_terrain_brush = Abs(ValInt("&H" + temp_s))
  9128. Else
  9129. current_brush = Abs(ValInt("&H" + temp_s))
  9130. End If
  9131. End If
  9132. End If
  9133. DrawPanel
  9134. '~ Case "a" To "o", "q" To "w"
  9135. '~ For i As Short = current_brush + 1 To current_brush + 256
  9136. '~ Dim ii As Short
  9137. '~
  9138. '~ ii = i Mod 256
  9139. '~ If tr(ii).entity = ASC(LCase(akey)) Or tr(ii).entity = ASC(UCase(akey)) Then
  9140. '~ current_brush = ii
  9141. '~ Exit For
  9142. '~ End If
  9143. '~ Next i
  9144. '~ DrawPanel
  9145. '~ Case "A" To "O", "Q" To "W"
  9146. '~ For i As Short = current_brush + 255 To current_brush Step -1
  9147. '~ Dim ii As Short
  9148. '~
  9149. '~ ii = i Mod 256
  9150. '~ If tr(ii).entity = ASC(LCase(akey)) Or tr(ii).entity = ASC(UCase(akey)) Then
  9151. '~ current_brush = ii
  9152. '~ Exit For
  9153. '~ End If
  9154. '~ Next i
  9155. '~ DrawPanel
  9156. '--- Move keyboard cursor
  9157. Case Chr(255, 72), Chr(255, 141)
  9158. If inpalette Then
  9159. If ypcursor > 0 Then ypcursor -= 1 : updatepalette = -1
  9160. Else
  9161. If selecting = -1 Then
  9162. xselect = xcursor : x2select = xcursor
  9163. yselect = ycursor : y2select = ycursor
  9164. selecting = -3 'Selecting with the keyboard
  9165. End If
  9166. If ycursor > 1 Then ycursor -= 1
  9167. If selecting = -3 Then
  9168. x2select = xcursor
  9169. y2select = ycursor
  9170. DrawTrack
  9171. End If
  9172. If pasting Then
  9173. SetMouse xoffs + (xcursor - 1) * bigwidth + 11, yoffs + (ycursor - 1) * 22 + 11
  9174. DrawTrack
  9175. End If
  9176. End If
  9177. Case Chr(255, 80), Chr(255, 145)
  9178. If inpalette Then
  9179. If ypcursor < 5 Then ypcursor += 1 : updatepalette = -1
  9180. Else
  9181. If selecting = -1 Then
  9182. xselect = xcursor : x2select = xcursor
  9183. yselect = ycursor : y2select = ycursor
  9184. selecting = -3 'Selecting with the keyboard
  9185. End If
  9186. If ycursor < 30 Then ycursor += 1
  9187. If selecting = -3 Then
  9188. x2select = xcursor
  9189. y2select = ycursor
  9190. DrawTrack
  9191. End If
  9192. If pasting Then
  9193. SetMouse xoffs + (xcursor - 1) * bigwidth + 11, yoffs + (ycursor - 1) * 22 + 11
  9194. DrawTrack
  9195. End If
  9196. End If
  9197. Case Chr(255, 75), Chr(255, 115)
  9198. If inpalette Then
  9199. If xpcursor > 0 Then xpcursor -= 1 : updatepalette = -1
  9200. Else
  9201. If selecting = -1 Then
  9202. xselect = xcursor : x2select = xcursor
  9203. yselect = ycursor : y2select = ycursor
  9204. selecting = -3 'Selecting with the keyboard
  9205. End If
  9206. If xcursor > 1 Then xcursor -= 1
  9207. If selecting = -3 Then
  9208. x2select = xcursor
  9209. y2select = ycursor
  9210. DrawTrack
  9211. End If
  9212. If pasting Then
  9213. SetMouse xoffs + (xcursor - 1) * bigwidth + 11, yoffs + (ycursor - 1) * 22 + 11
  9214. DrawTrack
  9215. End If
  9216. End If
  9217. Case Chr(255, 77), Chr(255, 116)
  9218. If inpalette Then
  9219. If xpcursor < 5 Then xpcursor += 1 : updatepalette = -1
  9220. Else
  9221. If selecting = -1 Then
  9222. xselect = xcursor : x2select = xcursor
  9223. yselect = ycursor : y2select = ycursor
  9224. selecting = -3 'Selecting with the keyboard
  9225. End If
  9226. If xcursor < 30 Then xcursor += 1
  9227. If selecting = -3 Then
  9228. x2select = xcursor
  9229. y2select = ycursor
  9230. DrawTrack
  9231. End If
  9232. If pasting Then
  9233. SetMouse xoffs + (xcursor - 1) * bigwidth + 11, yoffs + (ycursor - 1) * 22 + 11
  9234. DrawTrack
  9235. End If
  9236. End If
  9237. Case Chr(13) 'Insert element
  9238. If inpalette Then
  9239. If current_page < 10 Then
  9240. current_brush = itr(xpcursor, ypcursor, current_page)
  9241. ElseIf current_page = 10 Then
  9242. current_terrain_brush = itr(xpcursor, ypcursor, current_page)
  9243. End If
  9244. DrawPanel
  9245. ElseIf pasting Then
  9246. tempboard = "" 'Accept paste
  9247. pasting = 0 : xselect = 0
  9248. DrawTrack : PushUndo
  9249. modified = -1
  9250. ElseIf xselect Then
  9251. modified = -1
  9252. BuildClosedCircuit
  9253. Else
  9254. modified = -1
  9255. If colouring_mode Then
  9256. Dim As ULong last_bgc, last_border
  9257. last_bgc = grid(xcursor, ycursor).bgc
  9258. last_border = grid(xcursor, ycursor).border
  9259. grid(xcursor, ycursor).bgc = current_bgc
  9260. grid(xcursor, ycursor).border = current_border
  9261. If last_border <> current_border Then
  9262. DrawTrack
  9263. ElseIf last_bgc <> current_bgc Then
  9264. DrawSpot xcursor, ycursor
  9265. End If
  9266. ElseIf current_page < 10 Then
  9267. SetTrack xcursor, ycursor, current_brush
  9268. vlast.x = xcursor : vlast.y = ycursor
  9269. ElseIf current_page = 10 Then
  9270. grid(xcursor, ycursor).land = current_terrain_brush
  9271. DrawSpot xcursor, ycursor
  9272. End If
  9273. PushUndo
  9274. ManageKeyboardCursor -1
  9275. End If
  9276. Case Chr(255, 83) 'Delete element or block
  9277. modified = -1
  9278. If xselect Then
  9279. If selecting = 0 Then
  9280. For j As Byte = yselect To y2select
  9281. For i As Byte = xselect To x2select
  9282. If affect_track Then grid(i, j).track = 0
  9283. If affect_terrain Then grid(i, j).land = 0
  9284. If colouring_mode Then grid(i, j).border = 0 : grid(i, j).bgc = 0
  9285. Next i
  9286. Next j
  9287. xselect = 0
  9288. DrawTrack
  9289. End If
  9290. Else
  9291. If current_page < 10 Then
  9292. ClearTrack xcursor, ycursor
  9293. ElseIf current_page = 10 Then
  9294. grid(xcursor, ycursor).land = 0
  9295. DrawSpot xgrid, ygrid
  9296. End If
  9297. ManageKeyboardCursor -1
  9298. End If
  9299. PushUndo
  9300. Case "p", "P" 'Pick element
  9301. If drawkeyboardcursor Then
  9302. If colouring_mode Then
  9303. current_border = grid(xcursor, ycursor).border
  9304. current_bgc = grid(xcursor, ycursor).bgc
  9305. Else
  9306. PickTrack xcursor, ycursor
  9307. End If
  9308. DrawPanel
  9309. ElseIf xgrid >= 1 And xgrid <= 30 And ygrid >= 1 And ygrid <= 30 Then
  9310. If colouring_mode Then
  9311. current_border = grid(xgrid, ygrid).border
  9312. current_bgc = grid(xgrid, ygrid).bgc
  9313. Else
  9314. PickTrack xgrid, ygrid
  9315. End If
  9316. DrawPanel
  9317. End If
  9318. Case Chr(9) 'Switch between track and palette
  9319. If colouring_mode Then
  9320. Menu_Colouring
  9321. Else
  9322. inpalette = Not inpalette
  9323. updatepalette = -1
  9324. DrawPanel
  9325. ManageKeyboardCursor -1
  9326. End If
  9327. '~ Case Chr(255, 82) 'INSERT: Activate path creating tool
  9328. '~ If drawkeyboardcursor Then
  9329. '~ CreatePath
  9330. '~ DrawTrack
  9331. '~ End If
  9332. Case Chr(15) 'Switch colouration
  9333. colouring_mode = Not colouring_mode
  9334. DrawPanel
  9335. Case Chr(27), Chr(255) + "k" : QuitProgram
  9336. End Select
  9337. Loop
  9338. End Sub