/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /* * This code is based on the original source code of Lord Avalot d'Argent version 1.3. * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman. */ #include "graph.h" /*#include "Dos.h"*/ /*#include "Crt.h"*/ /*#include "Tommys.h"*/ #include "lucerna.h" /*$V-*/ namespace Avalanche { struct windowtype { integer x1,y1,x2,y2; varying_string<20> title; }; struct ednahead { /* Edna header */ /* This header starts at byte offset 177 in the .ASG file. */ array<1,9,char> id; /* signature */ word revision; /* EDNA revision, here 2 (1=dna256) */ varying_string<50> game; /* Long name, eg Lord Avalot D'Argent */ varying_string<15> shortname; /* Short name, eg Avalot */ word number; /* Game's code number, here 2 */ word ver; /* Version number as integer (eg 1.00 = 100) */ varying_string<5> verstr; /* Vernum as string (eg 1.00 = "1.00" */ varying_string<12> filename; /* Filename, eg AVALOT.EXE */ byte osbyte; /* Saving OS (here 1=DOS. See below for others.*/ varying_string<5> os; /* Saving OS (here 1=DOS. See below for others.*/ /* Info on this particular game */ varying_string<8> fn; /* Filename (not extension ('cos that's .ASG)) */ byte d,m; /* D, M, Y are the Day, Month & Year this game was... */ word y; /* ...saved on. */ varying_string<40> desc; /* Description of game (same as in Avaricius!) */ word len; /* Length of DNA (it's not going to be above 65535!) */ /* Quick reference & miscellaneous */ word saves; /* no. of times this game has been saved */ integer cash; /* contents of your wallet in numerical form */ varying_string<20> money; /* ditto in string form (eg 5/-, or 1 denarius)*/ word points; /* your score */ /* DNA values follow, then footer (which is ignored) */ }; const integer border = 1; /* size of border on shadowboxes */ const array<1,4,varying_string<7> > buttons = {{"Okay","Wipe","Cancel","Info..."}}; const integer files = 3; const integer dirs = 4; const integer drlen = 15; /* no. of drives on one line */ const array<1,4,windowtype> threewins = {{{155, 12, 630, 22, "Name"}, {15, 25, 410, 70, "Drives"}, {15, 83, 480, 179, "Files (*.ASG)"}, {490, 83, 630, 179, "Subdirectories"}}}; const integer name_win = 1; const integer drive_win = 2; const integer file_win = 3; const integer subdir_win = 4; matrix<3,4,1,77,varying_string<12> > lists; array<1,77,varying_string<40> > descs; array<3,4,byte> nums,where,top; searchrec s; boolean loading; varying_string<26> drives; pathstr current; byte nowwin; varying_string<17> doing; pathstr filename; boolean filefound; void shadow(integer x1,integer y1,integer x2,integer y2, byte hc,byte sc) { byte fv; ; for( fv=0; fv <= border; fv ++) {; setfillstyle(1,hc); bar(x1+fv,y1+fv,x1+fv,y2-fv); bar(x1+fv,y1+fv,x2-fv,y1+fv); setfillstyle(1,sc); bar(x2-fv,y1+fv,x2-fv,y2-fv); bar(x1+fv,y2-fv,x2-fv,y2-fv); } } void shbox(integer x1,integer y1,integer x2,integer y2, string t) { const integer fc = 7; ; shadow(x1,y1,x2,y2,15,8); setfillstyle(1,fc); bar(x1+border+1,y1+border+1,x2-border-1,y2-border-1); setcolor(1); x1=(x2-x1) / 2+x1; y1=(y2-y1) / 2+y1; outtextxy(x1,y1,t); if (length(t)>1) {; fillchar(t[2],length(t)-1,'\40'); t[1]='_'; outtextxy(x1-1,y1+1,t); } } void show_drives() { byte fv; ; settextjustify(1,1); for( fv=0; fv <= length(drives)-1; fv ++) shbox((fv % drlen)*25+25,(fv / drlen)*19+31, (fv % drlen)*25+40,45+(fv / drlen)*19,drives[fv+1]); setcolor(11); settextjustify(0,2); } void box(integer x1,integer y1,integer x2,integer y2, string z) {; rectangle(x1,y1,x2,y2); outtextxy(x1+1,y1-10,z+':'); outtextxy(x1,y1-9,"_"); } string lowstr(string x) { byte fv; string lowstr_result; ; for( fv=1; fv <= length(x); fv ++) if (set::of(range('A','Z'), eos).has(x[fv])) x[fv] += 32; lowstr_result=x; return lowstr_result; } char lowchar(char x) { char lowchar_result; if (set::of(range('A','Z'), eos).has(x)) x -= 32; lowchar_result=x; return lowchar_result; } void getcurrent() {; current=lowstr(fexpand("*.asg")); } void setup() { integer gd,gm; registers r; byte floppies; ; gd=3; gm=0; initgraph(gd,gm,"c:\\bp\\bgi"); dusk(); setfillstyle(1,1); bar(2,2,637,197); shadow(0,0,639,199,15,7); if (loading) doing="LOAD"; else doing="SAV"; doing=doing+"ING a file..."; /* Now... find all drives that exist. */ drives=""; intr(0x11,r); floppies=(((cardinal)r.ax >> 6) & 0x3)+1; /* useful bit of code! */ for( gm=1; gm <= floppies; gm ++) drives=drives+chr(64+gm); /* Winchesters, etc., can be found the easy way... */ for( gd=3; gd <= 26; gd ++) /* C: to Z: */ if (disksize(gd)>-1) drives=drives+chr(64+gd); fillchar(where,sizeof(where),'\1'); fillchar(top,sizeof(top),'\1'); settextstyle(0,0,0); settextjustify(1,1); for( gd=1; gd <= 2; gd ++) for( gm=0; gm <= 1; gm ++) shbox(420+gm*110,gd*25,520+gm*110,gd*25+20,buttons[gm*2+gd]); shbox(15,182,350,196,"Help... (press f1)"); settextjustify(0,2); setcolor(11); setcolor(15); outtextxy(15,5,"The Avvy Filer..."); setcolor(11); outtextxy(317,3,string('(')+doing+')'); outtextxy(357,185,"Copyright (c) 1993, Thomas Thurman."); /* Draw the boxes and names */ setcolor(3); for( gm=1; gm <= 4; gm ++) { windowtype& with = threewins[gm]; box(with.x1,with.y1,with.x2,with.y2,with.title);} nowwin=1; getcurrent(); } void quicksort(byte whichlist, integer lo, integer hi); static void sort(integer l, integer r, byte& whichlist) { integer i, j; varying_string<12> x, y; i = l; j = r; x = lists[whichlist][(l+r) / 2]; do { while (lists[whichlist][i] < x) i = i + 1; while (x < lists[whichlist][j]) j = j - 1; if (i <= j) { y = lists[whichlist][i]; lists[whichlist][i] = lists[whichlist][j]; lists[whichlist][j] = y; i = i + 1; j = j - 1; } } while (!(i > j)); if (l < j) sort(l, j, whichlist); if (i < r) sort(i, r, whichlist); } void quicksort(byte whichlist, integer lo, integer hi) { /*QuickSort*/; sort(lo,hi, whichlist); } void scandir() { pathstr nix; namestr name; untyped_file f; ednahead eh; array<1,4,char> dna_type; ; nums[files]=0; findfirst("*.asg",archive+hidden+readonly,s); while (doserror==0) {; fsplit(s.name,nix,name,nix); nums[files] += 1; lists[files][nums[files]]=lowstr(name); assign(f,s.name); reset(f,1); seek(f,11); blockread(f,dna_type,4); if (dna_type=="Avvy") {; /* A DNA256 file. */ descs[nums[files]]="* Saved by Avaricius!"; } else {; /* EDNA-based files. */ if (dna_type=="EDNA") {; seek(f,177); blockread(f,eh,sizeof(eh)); if (eh.revision!=2) descs[nums[files]]="* Unknown EDNA type!"; else {; if (eh.number!=2) descs[nums[files]]=string("* Saved by ")+eh.shortname+'!'; else {; /* Well... everything seems to have gone OK! */ descs[nums[files]]=eh.desc; } } } else descs[nums[files]]="* Not an Avvy saved game!"; } close(f); findnext(s); } nums[dirs]=0; findfirst("*.*",directory,s); while (doserror==0) {; if (((s.attr & directory)>0) && ((length(s.name))>1)) {; nums[dirs] += 1; lists[dirs][nums[dirs]]=lowstr(s.name); } findnext(s); } /* Now sort 'em! */ quicksort ( dirs,1,nums[ dirs]); quicksort (files,1,nums[files]); where[dirs]=1; where[files]=1; top[dirs]=1; top[files]=1; } void show_file(integer x,integer y, byte which) { varying_string<58> z; ; fillchar(z[1],13,'\40'); z=lists[files][which]+".asg"; z[0]='\15'; z=z+descs[which]; if (descs[which][1]=='*') /* Can't load these! */ setcolor(red); else setcolor(lightcyan); outtextxy(x,y,z); } void showfiles() { byte fv; ; if (loading) setcolor(11); else setcolor(3); if (nums[3]==0) {; outtextxy(22,86,"(None here!)"); return; } for( fv=0; fv <= 8; fv ++) if (where[3]+fv<=nums[3]) show_file(19,87+fv*10,where[3]+fv); } void showdirs() { byte fv; ; setcolor(11); for( fv=0; fv <= 8; fv ++) if (where[4]+fv<=nums[4]) outtextxy(497,87+fv*10,string('[')+lists[dirs][fv+where[4]]+']'); } void show() { byte fv; dirstr d; namestr n; extstr e; ; setfillstyle(1,1); for( fv=1; fv <= 4; fv ++) if (fv!=2) { windowtype& with = threewins[fv]; bar(with.x1+1,with.y1+1,with.x2-1,with.y2-1);} showfiles(); showdirs(); setcolor(7); outtextxy(159,14,current); } void blip() {; sound(177); delay(77); nosound; } void invert(integer x1,integer y1,integer x2,integer y2) { pointer p,restore; word s; ; s=imagesize(x1,y1,x2,y2); mark(restore); getmem(p,s); getimage(x1,y1,x2,y2,p); putimage(x1,y1,p,notput); release(restore); } void changedrive(char drive) { byte fv; ; fv=pos(drive,drives); if (fv==0) {; blip(); return; } fv -= 1; shadow((fv % drlen)*25+25,(fv / drlen)*19+31, (fv % drlen)*25+40,45+(fv / drlen)*19,8,7); chdir(string(drive)+':'); getcurrent(); scandir(); show(); shadow((fv % drlen)*25+25,(fv / drlen)*19+31, (fv % drlen)*25+40,45+(fv / drlen)*19,15,8); } void highlight(byte win,byte line) {; switch (win) { case 3: invert(16,75+line*10,479,85+line*10); break; case 4: invert(491,75+line*10,619,85+line*10); break; } } void repaint(byte whichwindow) { setfillstyle(1,1); { windowtype& with = threewins[whichwindow]; bar(with.x1+1,with.y1+1,with.x2-1,with.y2-1);} switch (whichwindow) { case file_win: showfiles(); break; case subdir_win: showdirs(); break; } highlight(whichwindow,1); top[whichwindow]=where[whichwindow]; } void fileblit(word xpos,word xlen,word y1,word y2, shortint dir, word ylen) { word fv; byte bit; ; for( bit=0; bit <= 3; bit ++) {; fv=0; while (fvnums[whichlist]) wherenow=1; } while (!((startedat==wherenow) || (lists[whichlist][wherenow][1]==whatfor))); repaint(whichlist); } void gotohome(byte whichlist) { where[whichlist]=1; repaint(whichlist); } void gotoend(byte whichlist) { where[whichlist]=nums[whichlist]; repaint(whichlist); } void pageup(byte whichlist) { if (where[whichlist]>9) { where[whichlist] -= 9; repaint(whichlist); } } void pagedown(byte whichlist) { if (where[whichlist]0) && ((where[which]+howmuch)<=(unsigned char)nums[4])) where[which]=where[which]+howmuch; highlight(4,where[4]-top[4]+1); } static void change_dir() {; dusk(); /*$I-*/ chdir(lists[4][where[4]]); /*$I+*/ if (ioresult!=0) {; dawn(); blip(); return; } where[4]=1; top[4]=1; getcurrent(); scandir(); show(); highlight(4,1); dawn(); } void subdirparse(string r) {; switch (r[1]) { case creturn: change_dir(); break; case '\0': switch (r[2]) { case cup: if (where[4]-top[4]>0) /* Up */ movehl(4,-1); /* Within range */ else if (top[4]>1) {; /* Outside range- must scroll */ highlight(4,1); top[4] -= 1; where[4] -= 1; fileblit(61,18,166,176,-1,80); setfillstyle(1,1); bar(490,85,630,95); setcolor(11); outtextxy(497,87,string('[')+lists[dirs][where[4]]+']'); highlight(4,1); } break; case cdown: if (where[4]-top[4]<8) /* Down */ movehl(4,1); else if (top[4]+8 os; char r; ; /* Firstly, we must check whether or not it's an Avalot file. This is easily done, since the descriptions of all others always begin with a star. */ if ((descs[which][1]=='*') || (descs[which][1]=='(')) {; /* it is. */ blip(); /* Naaaarghh! */ return; } /* Anyway... it wasn't. */ assign(f,lists[files][which]+".asg"); reset(f,1); seek(f,177); blockread(f,eh,sizeof(eh)); close(f); /* We now hold its EDNA record. */ setfillstyle(1,1); bar(2,2,637,197); /* Interesting information coming up! */ {; display(2,"Saved by:", eh.game); display(3,"version:", eh.verstr); /* display(4,'under', os);*/ display(6,"Saved on ",strf(eh.d)+'-'+strf(eh.m)+'-'+strf(eh.y)); display(9,"No. of times saved:",strf(eh.saves)); display(11,"Money:",eh.money); display(12,"Score:",strf(eh.points)); } shbox(500,177,650,200,"Press any key..."); r=readkey(); setfillstyle(1,1); bar(2,2,637,197); } void filer_help() /* This gives general help. */ { char r; ; outtextxy(100,100,"Just general help here."); shbox(500,177,650,200,"Press any key..."); r=readkey(); setfillstyle(1,1); bar(2,2,637,197); } void wipe() /* This allows you to delete files. */ { char r; ; outtextxy(100,100,"Are you sure you want to delete \"foo.bar\"?"); shbox(500,177,650,200,"[Y/N]"); r=readkey(); setfillstyle(1,1); bar(2,2,637,197); } void filesparse(string r); static void movehl1(byte which, shortint howmuch) {; highlight(3,where[3]-top[3]+1); if (((where[which]+howmuch)>0) && ((where[which]+howmuch)<=(unsigned char)nums[3])) where[which]=where[which]+howmuch; highlight(3,where[3]-top[3]+1); } static boolean selected_file() {boolean selected_file_result; ; if (descs[where[file_win]][1]=='*') { blip(); selected_file_result=false; } else { filename=lists[file_win][where[file_win]]; filefound=true; selected_file_result=true; } return selected_file_result; } void filesparse(string r) {; switch (r[1]) { case creturn: if (selected_file()) return; break; case '\0': switch (r[2]) { case cup: if (where[3]-top[3]>0) /* Up */ movehl1(3,-1); /* Within range */ else if (top[3]>1) {; /* Outside range- must scroll */ highlight(3,1); top[3] -= 1; where[3] -= 1; fileblit(1,59,166,176,-1,80); setfillstyle(1,1); bar( 15,85,480,95); show_file( 19,87,where[3]); highlight(3,1); } break; case cdown: if (where[3]-top[3]<8) /* Down */ movehl1(3,1); else if (top[3]+84) nowwin=1; switch (nowwin) { case 3:case 4: highlight(nowwin,where[nowwin]-top[nowwin]+1); break; } } string playaround() { char r,r2; string playaround_result; ; filefound=false; dawn(); do { setcolor(14); { windowtype& with = threewins[nowwin]; box(with.x1,with.y1,with.x2,with.y2,with.title);} r=readkey(); switch (r) { case ctab: changewin(nowwin+1); break; case cescape: {; playaround_result=""; return playaround_result; } break; case '\0': {; /* parse extd keystroke */ r2=readkey(); switch (r2) { case cs_tab: changewin(nowwin-1); break; case c_an: changewin(1); break; case c_ad: changewin(2); break; case c_af: changewin(3); break; case c_as: changewin(4); break; case c_ac: {; playaround_result=""; return playaround_result; } break; default: switch (nowwin) { case 3: filesparse(string('\0')+r2); break; case 4: subdirparse(string('\0')+r2); break; } } } break; default: {; /* Pass keystroke to current window */ switch (nowwin) { case 2: changedrive(upcase(r)); break; case 4: subdirparse(r); break; case 3: filesparse(r); break; default: blip(); } } } if (filefound) {; dusk(); playaround_result=filename; return playaround_result; } } while (!false); return playaround_result; } void do_filer() { pathstr p; void do_filer_result; ; loading=true; setup(); scandir(); show(); show_drives(); p=playaround(); if (p!="") p=fexpand(p+".ASG"); do_filer_result=p; return do_filer_result; } int main(int argc, const char* argv[]) {pio_initialize(argc, argv); ; filename=do_filer(); closegraph(); if (filename=="") output << "*** CANCELLED! ***" << NL; else output << "Selected: " << filename << NL; input >> NL; return EXIT_SUCCESS; } } // End of namespace Avalanche.