While it is capturing the screenshots, do not move the mouse or use
the keyboard. Keyboard focus must stay in the YPP client window.
+You will probably need to turn off `Use antialiased font' in the YPP
+client. This is in the Ye panel, Options, tab `General'.
Command-line options
--------------------
add UI option to dictionary-manager to make user specify which dictionary
to add multi-context entries to
install/test dictionary upload/approval
-onboard ship island name horizontal trim
write real uploader
test real uploader
-building island name extractor
-speed it up
+further speedups
our (%commodmap);
-our ($pctb) = $ENV{'YPPSC_PCTB_PCTB'}; die unless $pctb;
+our ($pctb) = $ENV{'YPPSC_PCTB_PCTB'};
our ($ua)= LWP::UserAgent->new;
}
sub refresh_commodmap() {
+ die unless $pctb;
my $resp= $ua->get("$pctb/commodmap.php?version=2");
die $resp->status_line unless $resp->is_success;
sub writeint { return pack 'v*', @_; }
+our (%stalltypetoabbrevmap)= qw(
+ Apothecary A
+ Distilling D
+ Furnishing F
+ Ironworking I
+ Shipbuilding S
+ Tailoring T
+ Weaving W
+ );
+
sub genmarketdata () {
our $version= '005b';
my $ot= sprintf("$version\n".
"%d\n",
scalar(@stallmap));
- foreach $stall (@stallmap) { $ot .= "$stall\n"; }
+ foreach $stall (@stallmap) {
+ my $st= $stall;
+ if ($st =~ m/^(\S+)\'s (\S+) Stall$/) {
+ my $stkind= $stalltypetoabbrevmap{$2};
+ if (defined $stkind) {
+ $st= "$1^$stkind";
+ } else {
+ warn "unknown stall type $2 in $st\n";
+ }
+ }
+ $ot .= "$st\n";
+ }
return $ot.$ob;
}
}
sub main__upload () {
+ die unless $pctb;
my $o= genmarketdata();
my $url= "$pctb/upload.php";
- $url= "http://www.chiark.greenend.org.uk/ucgi/~ijackson/check/upload.php";
my $content= {
'marketdata' => [ undef, "marketdata.gz",
Content_Type => 'application/gzip',
Content_Type => 'form-data');
die $resp->status_line unless $resp->is_success;
- print "[[ ",$resp->content," ]]\n";
+ my $resptxt= $resp->content();
+
+ my @filenames= $resptxt =~
+ m/input\s+type="hidden"\s+name="filename"\s+value=\"([_.0-9a-z]+)\"/i;
+ @filenames or die "$resptxt ?";
+
+ my @forcerls= $resptxt =~
+ m/input\s+type="hidden"\s+name="forcereload"\s+value=\"([1-9]\d+)\"/i;
+ @forcerls or die "$resptxt ?";
+
+ my $filename= $filenames[0];
+ my $forcerl= $forcerls[0];
+
+ die "$resptxt | @filenames ?" if grep { $_ ne $filename } @filenames;
+ die "$resptxt | @forcerls ?" if grep { $_ ne $forcerl } @forcerls;
+
+# my $setsland= {
+# 'action' => 'setisland'
+# 'filename' => $filename,
+# 'forcereload' => $forcerl,
+# my $url_setisland= "$url
+#
+#http://pctb.ilk.org/upload.php?topisland=560&ocean=2&island=48&action=setisland&forcereload=1244748679&filename=PFayDW' >v.html
+#
+ print ">$filename|$forcerl<\n";
+
+ system 'printenv|grep YPP|sort';
}
DF(struct) \
DF(ocr) \
DF(rsync) \
+ DF(structcolon) \
DF(callout)
enum {
/* Consequential changes to options */
if (o_mode & mf_analyse) {
- if (!o_outmode_kind)
- o_outmode_kind= (o_flags & ff_printisland) ? omk_none : omk_str;
+ if (!o_outmode_kind) {
+ if (o_flags & ff_printisland) {
+ o_outmode_kind= omk_none;
+ o_flags |= ff_singlepage;
+ } else {
+ o_outmode_kind= omk_upload;
+ }
+ }
if (o_outmode_kind==omk_upload) {
o_flags |= ffs_upload;
if (!ocean) ocean= o_ocean;
if (!pirate) pirate= o_pirate;
- if (o_flags & ff_needisland) {
+ if (o_flags & ff_needisland)
if (!ocean)
badusage("need --ocean option when replaying images"
" (consider supplying --pirate too)");
+ if (ocean)
sysassert(! setenv("YPPSC_OCEAN",ocean,1) );
- }
if (pirate && (o_flags & ff_dict_pirate))
sysassert(! setenv("YPPSC_PIRATE",pirate,1) );
open_screenshot_file("w");
if (o_flags & ff_singlepage) take_one_screenshot();
else take_screenshots();
+ progress_log("OK for you to move the mouse now.");
}
if (o_mode & mf_readscreenshot) {
open_screenshot_file("r");
}
if (o_mode & mf_analyse) {
if (o_flags & ff_needisland) {
- find_islandname();
+ find_islandname(page0_rgbimage);
if (o_flags & ff_printisland)
printf("%s, %s\n", archipelago, island);
+ sysassert(! setenv("YPPSC_ISLAND",island,1) );
}
switch (o_outmode_kind) {
case omk_upload: case omk_str: run_analysis(); break;
void identify_rgbimage(const RgbImage *base, Rect portion,
char result[MAXIMGIDENT], const char *what);
RgbImage *alloc_rgb_image(int w, int h);
+void fwrite_ppmraw(FILE *f, const RgbImage *ri);
#define RI_PIXEL(ri,x,y) ((ri)->data + ((y)*(ri)->w + (x)) * 3)
/*----- from structure.c -----*/
void find_structure(const CanonImage *im, int *max_relevant_y_r);
+Rect find_sunshine_widget(void);
-void find_islandname(void);
+void find_islandname(RgbImage *ri);
void check_correct_commodities(void);
void read_screenshots(void);
void read_one_screenshot(void);
startup_cursor
}
+proc approve_showentry_xinfo/char {w def} {
+ set unic [string2unicodenames $def]
+ label $w -text $unic
+}
+
#========== PIXMAPS ==========
#---------- pixmap database read and write ----------
}
}
+proc approve_showentry_xinfo/pixmap {w def} {
+ label $w -image image/empty
+}
+
#========== UPLOADS TO DICTIONARY SERVER ==========
proc upload_init {} {
set query [eval ::http::formatQuery $pl]
regsub -all {%0d} $query {} query
- debug "DB-UPDATE QUERY [string range $query 0 200]..."
+ debug "DB-UPDATE QUERY $query"
if {[regexp {^\.?/} $url]} {
set cmd [list $url $query]
focus .d.csr.csr.e
bind .d.csr.csr.e <Key-Return> {
set strq [.d.csr.csr.e get]
- if {[regexp -line {^(?:[!-[]|[]-~]|\\\\|\\x[0-9a-f]{2})+} $strq]} {
- RETURN_RESULT DEFINE "$cur_0 $cur_1 $strq"
+ if {[string length $strq]} {
+ RETURN_RESULT DEFINE [list $cur_0 $cur_1 $strq]
}
}
bind .d.csr.csr.e <Key-Escape> {
must_gets_exactly stdin confirmed
- if {![string compare pixmap $dict]} {
- set reqkind pixmap
- debug "DICT PIXMAP"
- } elseif {[regexp {^(char)([1-9]\d*)$} $dict dummy reqkind rows]} {
- debug "DICT CHAR rqk=$reqkind r=$rows."
- } else {
- error "$dict ?"
- }
+ manyset [dict2_reqkind_rows reqkind rows]
if {$yesno} {
read_database $dictdir/master-$dict.txt
}
}
+proc dict2_reqkind_rows {dict} {
+ if {![string compare pixmap $dict]} {
+ return {pixmap {}}
+ debug "DICT PIXMAP"
+ } elseif {[regexp {^(char)([1-9]\d*)$} $dict dummy reqkind rows]} {
+ debug "DICT CHAR rqk=$reqkind r=$rows."
+ return [list $reqkind rows]
+ } else {
+ error "$dict ?"
+ }
+}
+
proc chop_counted {var} {
upvar 1 $var val
global data
return [string compare $sv1 $sv2]
}
+proc string2unicodenames {str} {
+ return [exec perl -e {
+ use Unicode::CharName qw(uname);
+ $ARGV[0] =~ s/^ //;
+ foreach $_ (split //,$ARGV[0]) {
+ print uname(ord),"\n" or die $!
+ }
+ } " $str"]
+}
+
proc approve_showentry {ix file specdata} {
- global approve_ixes
+ global approve_ixes reqkind
approve_decompose_data $specdata
image create photo approve/$ix -data $ppm
label $wb-image -image approve/$ix -bd 2 -relief sunken
+ manyset [dict2_reqkind_rows $dict] reqkind
+ approve_showentry_xinfo/$reqkind $wb-xinfo $def
+
+ if {$ix} {
+ label $wb-div -bd 1 -relief sunken -image image/empty
+ grid configure $wb-div -columnspan 5 -sticky ew -padx 5
+ }
+
frame $wb-act
button $wb-act.rej -text Reject -command [list approve_reject $ix]
pack $wb-act.rej
- grid $wb-def $wb-image $wb-act $wb-inf -padx 3
+ grid $wb-def $wb-image $wb-xinfo $wb-act $wb-inf -padx 3
grid configure $wb-image -ipadx 3 -ipady 3 -sticky w
lappend approve_ixes $ix
pack .right -side right
pack .ok -side bottom
+ image create bitmap image/empty
+
set approve_page 0
approve_fetch_list
}
Booty Booty
Ahoy! Ahoy!
}
-Ship {On board a ship} {
+Vessel {On board a ship} {
Crew Crew
Vessel Vessel
Ye Ye
double begin= timestamp();
if (shmim) {
+ rtimestamp(&begin, "XShmGetImage before");
xassert( XShmGetImage(disp,id,shmim, 0,0, AllPlanes) );
rtimestamp(&begin, "XShmGetImage");
memcpy(im_free->data, shmim->data, dsz);
rtimestamp(&begin, "mmalloc/memcpy");
} else {
+ rtimestamp(&begin, "XGetImage before");
xassert( im_use= im_free=
XGetImage(disp,id, 0,0, wwidth,wheight, AllPlanes, ZPixmap) );
rtimestamp(&begin, "XGetImage");
return 0;
int compare_to= a->h;
- if (max_relevant_y && compare_to > max_relevant_y)
+ if (max_relevant_y>=0 && compare_to > max_relevant_y)
compare_to= max_relevant_y;
return !memcmp(a->data, b->data, a->w * 3 * compare_to);
va_start(al,fmt);
Snapshot *last=0;
+ int nidentical=0;
/* waits longer if we're going to return an image identical to previously
* if previously==0, all images are considered identical to it */
- debugf("PAGING wait_for_stability"
- " last_input=%f previously=%p\n",
- last_input, previously);
-
char *doing;
- sysassert( vasprintf(&doing,fmt,al) >=0);
+ sysassert( vasprintf(&doing,fmt,al) >=0 );
- progress("%s",doing);
+ debugf("PAGING wait_for_stability"
+ " last_input=%f previously=%p `%s'\n",
+ last_input, previously, doing);
+ double min_interval= 25000; /*us*/
for (;;) {
- double at_snapshot= timestamp();
- double need_sleep= min_update_allowance - (at_snapshot - last_input);
- if (need_sleep > 0) { delay(need_sleep); continue; }
+ progress_spinner("%s",doing);
+
+ double since_last_input= timestamp() - last_input;
+ double this_interval= min_interval - since_last_input;
- snapshot(output);
+ if (this_interval >= 0)
+ usleep(this_interval);
- if (!with_keypress &&
- !(previously && identical(*output,previously))) {
- debugf("PAGING wait_for_stability simple\n");
- break;
- }
+ snapshot(output);
- if (last && identical(*output,last)) {
- debugf("PAGING wait_for_stability stabilised\n");
- break;
+ if (!last) {
+ debugf("PAGING wait_for_stability first...\n");
+ last=*output; *output=0;
+ } else if (!identical(*output,last)) {
+ debugf("PAGING wait_for_stability changed...\n");
+ free(last); last=*output; *output=0;
+ nidentical=0;
+ if (!with_keypress) {
+ min_interval *= 3.0;
+ min_interval += 0.5;
+ }
+ } else {
+ nidentical++;
+ int threshold=
+ !previously ? 3 :
+ identical(*output,previously) ? 5
+ : 1;
+ debugf("PAGING wait_for_stability nidentical=%d threshold=%d\n",
+ nidentical, threshold);
+ if (nidentical >= threshold)
+ break;
+
+ min_interval += 0.5;
+ min_interval *= 2.0;
}
-
- progress_spinner("%s",doing);
-
- debugf("PAGING wait_for_stability retry\n");
-
- free_snapshot(&last); last=*output; *output=0;
if (with_keypress)
with_keypress();
-
- delay(0.5);
}
free_snapshot(&last);
check_client_window_all_on_screen();
- int shm= XShmQueryExtension(disp);
- shm=0;
+ Bool shmpixmaps=0;
+ int major=0,minor=0;
+ int shm= XShmQueryVersion(disp, &major,&minor,&shmpixmaps);
+ debugf("PAGING shm=%d %d.%d pixmaps=%d\n",shm,major,minor,shmpixmaps);
if (shm) {
xassert( shmim= XShmCreateImage(disp, attr.visual, attr.depth, ZPixmap,
0,&shminfo, wwidth,wheight) );
static CanonImage *convert_page(Snapshot *sn, RgbImage *ri) {
CanonImage *im;
- fprintf(screenshot_file,
- "P6\n"
- "%d %d\n"
- "255\n", sn->w, sn->h);
+ fwrite_ppmraw(screenshot_file, sn);
+ if (ri) memcpy(ri->data, sn->data, ri->h * ri->w * 3);
+ unsigned char *pixel= sn->data;
CANONICALISE_IMAGE(im, sn->w, sn->h, {
- int i;
- rgb= 0;
- for (i=0; i<3; i++) {
- rgb <<= 8;
- unsigned long sample= RI_PIXEL(sn,x,y)[i];
- rgb |= sample;
- fputc(sample, screenshot_file);
- }
- if (ri)
- CANONIMG_ALSO_STORERGB(ri);
+ rgb=
+ (pixel[0] << 16) |
+ (pixel[1] << 8) |
+ (pixel[2] );
+ pixel += 3;
});
-
+
sysassert(!ferror(screenshot_file));
sysassert(!fflush(screenshot_file));
raise_and_get_details();
wait_for_stability(¤t,0,0, "checking current YPP client screen...");
-#if 1
-timestamp();
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-snapshot(¤t);
-timestamp();
-#endif
-
test= convert_page(current, 0);
find_structure(test, &max_relevant_y);
check_correct_commodities();
+ Rect sunshine= find_sunshine_widget();
+
+ progress("poking client...");
+ mouse_1_updown((sunshine.tl.x + sunshine.br.x) / 2,
+ (sunshine.tl.y*9 + sunshine.br.y) / 10);
+
free(test);
- free_snapshot(¤t);
- progress("requesting status information...");
+ wait_for_stability(¤t,0,0, "checking basic YPP client screen...");
mouse_1_updown(250, wheight-10);
mouse_1_updown_here();
mouse_1_updown_here();
send_key(XK_w);
send_key(XK_Return);
sync_after_input();
+
+ Snapshot *status=0;
+ wait_for_stability(&status,current,0, "awaiting status information...");
+ free_snapshot(¤t);
+ free_snapshot(&status);
}
void take_screenshots(void) {
prepare_ypp_client();
wait_for_stability(¤t,0,0, "taking screenshot...");
page0_rgbimage= alloc_rgb_image(current->w, current->h);
- page_images[0]= convert_page(current, 0);
+ page_images[0]= convert_page(current, page0_rgbimage);
npages= 1;
progress_log("collected single screenshot.");
}
DEBUG_DEFINE_SOME_DEBUGF(findypp,debugfind)
+static int nfound;
+static Atom wm_name;
+static int screen;
+
+static void findypp_recurse(int depth, int targetdepth, Window w) {
+ unsigned int nchildren;
+ int i;
+ Window *children=0;
+ Window gotroot, gotparent;
+
+ static const char prefix[]= "Puzzle Pirates - ";
+ static const char onthe[]= " on the ";
+ static const char suffix[]= " ocean";
+#define S(x) (sizeof((x))-1)
+
+ debugfind("FINDYPP %d/%d screen %d %*s %lx",
+ depth,targetdepth,screen,
+ depth,"",(unsigned long)w);
+
+ if (depth!=targetdepth) {
+ xassert( XQueryTree(disp,w,
+ &gotroot,&gotparent,
+ &children,&nchildren) );
+ debugfind(" nchildren=%d\n",nchildren);
+
+ for (i=0; i<nchildren; i++) {
+ Window child= children[i];
+ findypp_recurse(depth+1, targetdepth, child);
+ }
+ XFree(children);
+ return;
+ }
+
+
+ int gotfmt;
+ Atom gottype;
+ unsigned long len, gotbytesafter;
+ char *title;
+ unsigned char *gottitle=0;
+ xassert( !XGetWindowProperty(disp,w, wm_name,0,512, False,
+ AnyPropertyType,&gottype, &gotfmt, &len,
+ &gotbytesafter, &gottitle) );
+ title= (char*)gottitle;
+
+ if (DEBUGP(findypp)) {
+ debugfind(" gf=%d len=%lu gba=%lu \"", gotfmt,len,gotbytesafter);
+ char *p;
+ for (p=title; p < title+len; p++) {
+ char c= *p;
+ if (c>=' ' && c<=126) fputc(c,debug);
+ else fprintf(debug,"\\x%02x",c & 0xff);
+ }
+ fputs("\": ",debug);
+ }
+
+#define REQUIRE(pred) \
+ if (!(pred)) { debugfind(" failed test %s\n", #pred); return; } \
+ else
+
+ REQUIRE( gottype!=None );
+ REQUIRE( len );
+ REQUIRE( gotfmt==8 );
+
+ REQUIRE( len >= S(prefix) + 1 + S(onthe) + 1 + S(suffix) );
+
+ char *spc1= strchr( title + S(prefix), ' '); REQUIRE(spc1);
+ char *spc2= strrchr((title + len) - S(suffix), ' '); REQUIRE(spc2);
+
+ REQUIRE( (title + len) - spc1 >= S(onthe) + S(suffix) );
+ REQUIRE( spc2 - title >= S(prefix) + S(onthe) );
+
+ REQUIRE( !memcmp(title, prefix, S(prefix)) );
+ REQUIRE( !memcmp(title + len - S(suffix), suffix, S(suffix)) );
+ REQUIRE( !memcmp(spc1, onthe, S(onthe)) );
+
+#define ASSIGN(what, start, end) \
+ what= masprintf("%.*s", (end)-(start), start); \
+ if (o_##what) REQUIRE( !strcasecmp(o_##what, what) ); \
+ else
+
+ ASSIGN(ocean, spc1 + S(onthe), (title + len) - S(suffix));
+ ASSIGN(pirate, title + S(prefix), spc1);
+
+ debugfind(" YES!\n");
+ id= w;
+ nfound++;
+ progress_log("found YPP client (0x%lx):"
+ " %s ocean - %s.",
+ (unsigned long)id, ocean, pirate);
+}
+
void find_yppclient_window(void) {
- Window root, gotroot, gotparent;
- int screen;
- int nfound=0;
+ int targetdepth;
+
+ nfound=0;
if (id) return;
progress("looking for YPP client window...");
- static const char prefix[]= "Puzzle Pirates - ";
- static const char onthe[]= " on the ";
- static const char suffix[]= " ocean";
-#define S(x) (sizeof((x))-1)
+ xassert( (wm_name= XInternAtom(disp,"WM_NAME",True)) != None);
- Atom wm_name= XInternAtom(disp,"WM_NAME",True);
- xassert(wm_name != None);
-
- for (screen=0; screen<ScreenCount(disp); screen++) {
- debugfind("FINDYPP screen %d\n", screen);
- root= RootWindow(disp,screen);
- unsigned int nchildren1;
- Window *children1=0;
-
- xassert( XQueryTree(disp,root,
- &gotroot,&gotparent,
- &children1,&nchildren1) );
- debugfind("FINDYPP screen %d nchildren1=%d\n", screen, nchildren1);
-
- int i;
- for (i=0; i<nchildren1; i++) {
- Window w1= children1[i];
- unsigned int nchildren2;
- Window *children2=0;
-
- xassert( XQueryTree(disp,w1,
- &gotroot,&gotparent,
- &children2,&nchildren2) );
- debugfind("FINDYPP screen %d c1[%2d]=0x%08lx nchildren2=%d\n",
- screen, i, (unsigned long)w1, nchildren2);
-
- int j;
- for (j=-1; j<(int)nchildren2; j++) {
- Window w2= j<0 ? w1 : children2[j];
- debugfind("FINDYPP screen %d c1[%2d]=0x%08lx c2[%2d]=0x%08lx",
- screen, i, (unsigned long)w1, j, (unsigned long)w2);
-
- int gotfmt;
- Atom gottype;
- unsigned long len, gotbytesafter;
- char *title;
- unsigned char *gottitle=0;
- xassert( !XGetWindowProperty(disp,w2, wm_name,0,512, False,
- AnyPropertyType,&gottype, &gotfmt, &len,
- &gotbytesafter, &gottitle) );
- title= (char*)gottitle;
-
- if (DEBUGP(findypp)) {
- debugfind(" gf=%d len=%lu gba=%lu \"", gotfmt,len,gotbytesafter);
- char *p;
- for (p=title; p < title+len; p++) {
- char c= *p;
- if (c>=' ' && c<=126) fputc(c,debug);
- else fprintf(debug,"\\x%02x",c & 0xff);
- }
- fputs("\": ",debug);
- }
-
-#define REQUIRE(pred) \
- if (!(pred)) { debugfind(" failed test %s\n", #pred); continue; } \
- else
-
- REQUIRE( gottype!=None );
- REQUIRE( len );
- REQUIRE( gotfmt==8 );
-
- REQUIRE( len >= S(prefix) + 1 + S(onthe) + 1 + S(suffix) );
-
- char *spc1= strchr( title + S(prefix), ' '); REQUIRE(spc1);
- char *spc2= strrchr((title + len) - S(suffix), ' '); REQUIRE(spc2);
-
- REQUIRE( (title + len) - spc1 >= S(onthe) + S(suffix) );
- REQUIRE( spc2 - title >= S(prefix) + S(onthe) );
-
- REQUIRE( !memcmp(title, prefix, S(prefix)) );
- REQUIRE( !memcmp(title + len - S(suffix), suffix, S(suffix)) );
- REQUIRE( !memcmp(spc1, onthe, S(onthe)) );
-
-#define ASSIGN(what, start, end) \
- what= masprintf("%.*s", (end)-(start), start); \
- if (o_##what) REQUIRE( !strcmp(o_##what, what) ); \
- else
-
- ASSIGN(ocean, spc1 + S(onthe), (title + len) - S(suffix));
- ASSIGN(pirate, title + S(prefix), spc1);
-
- debugfind(" YES!\n");
- id= w2;
- nfound++;
- progress_log("found YPP client (0x%lx):"
- " %s ocean - %s.",
- (unsigned long)id, ocean, pirate);
- }
- if (children2) XFree(children2);
+ for (targetdepth=1; targetdepth<4; targetdepth++) {
+ for (screen=0; screen<ScreenCount(disp); screen++) {
+ debugfind("FINDYPP screen %d\n", screen);
+ findypp_recurse(0,targetdepth, RootWindow(disp,screen));
}
- if (children1) XFree(children1);
+ if (nfound) break;
}
+
if (nfound>1)
- fatal("Found several possible YPP clients."
- " Close one, or specify the windowid with --window-id.\n");
+ fatal("Found several possible YPP clients. Close one,\n"
+ " disambiguate with --pirate or --ocean,"
+ " or specify --window-id.\n");
if (nfound<1)
fatal("Did not find %sYPP client."
" Use --window-id and/or report this as a fault.\n",
int c;
dbassert( dbfile_scanf("%d",&c) == 1);
dbassert(c>=0 && c<=255);
- diff |= (c != RI_PIXEL(base, portion.tl.x + x, portion.tl.y + y)[i]);
+ int px= portion.tl.x + x, py= portion.tl.y + y;
+ diff |= px > portion.br.x || py > portion.br.y ||
+ (c != RI_PIXEL(base,px,py)[i]);
}
}
}
identify1(base,portion,result,what, "local");
}
+void fwrite_ppmraw(FILE *f, const RgbImage *ri) {
+ fprintf(f,
+ "P6\n"
+ "%d %d\n"
+ "255\n", ri->w, ri->h);
+ int count= ri->w * ri->h * 3;
+ sysassert( fwrite(ri->data, 1, count, f) == count );
+ sysassert(!ferror(f));
+ sysassert(!fflush(f));
+}
+
static void fwrite_ppm(FILE *f, const RgbImage *base, Rect portion) {
int x,y,i;
fprintf(f,"P3\n%d %d\n255\n", RECT_W(portion), RECT_H(portion));
DEBUG_DEFINE_DEBUGF(struct)
-#define START_MAIN {200,100}
+#define START_MAIN {200,200}
#define MIN_COLUMNS 6
#define INTERESTING_COLUMNS 7
#define TEXT_COLUMNS 2
{ 0x6B828C, '*' }, /* background of ship status meter area */
{ 0x934405, '*' }, /* border of ship meter area */
{ 0x7D9094, '+' }, /* interbox */
+ { 0x022158, 'O' }, /* ahoy /w output foreground */
+ { 0xB5B686, 'H' }, /* ahoy /w output heading background */
{ 0xBDC5BF, ' ' }, /* background - pale Sugar cane, etc. */
{ 0xADB5AF, ' ' }, /* background - dark */
static void mustfail1(const char *file, int line, const char *what) {
fprintf(stderr,
- "\n\n"
- "Unable to figure out contents of YPP client display.\n"
- " Check that your client is logged in has the correct display.\n"
- " If that isn't the problem, please report this as a fault.\n\n"
+ "\n\n"
+ "Unable to figure out contents of YPP client display.\n"
+ "Please check the following:\n"
+ " * YPP client is showing commodity listing screen\n"
+ " * YPP client has antialiased text turned off (Ye / Options / General)\n"
+ " * YPP client window is on top (we try to raise it but your window\n"
+ " manager might have prevented that from succeeding)\n"
+ " * Your X display is 24bpp (NB some VNC servers use 16bpp by default)\n"
+ "\n"
+ "If all of these are true, please report this as a fault.\n\n"
"Technical details:"
" %s:%d: requirement failed:\n"
" %s\n",
debug_flush();
}
+static int commod_selector_matches(Rect search, const char *const *all,
+ int allh, int allw) {
+ int alloffy, alloffx;
+ for (alloffy=0; alloffy < search.br.y; alloffy++) {
+ if (alloffy+allh-1 < search.tl.y) continue;
+ for (alloffx=search.tl.x; alloffx+allw-1 <= search.br.x; alloffx++) {
+ int good=0, bad=0;
+ int x,y;
+ for (x=0; x<allw; x++)
+ for (y=0; y<allh; y++) {
+ int want= all[y][x];
+ if (want==' ') continue;
+ if (get(alloffx+x, alloffy+y) == want)
+ good++;
+ else
+ bad++;
+ }
+ debugf("CHECKCOMMOD alloff=%d,%d good=%d bad=%d\n",
+ alloffx,alloffy, good,bad);
+ if (good > 20*bad)
+ return 1;
+ }
+ }
+ return 0;
+}
+
#define WALK_UNTIL(point,coord,increm,last,edge) \
for (;;) { \
if ((point).coord == (last)+(increm)) break; \
debug_rect("commodselr",1, search);
- static const char *all[]= {
+ static const char *all_small[]= {
" ___________________________________ ",
" ________X____X__X____________________ ",
" ________ X___ X_ X_____XXXXXXXXXXX_____ ",
" ____X_____ _XX_ X______________________",
" __ _______ __ ______________________ ",
};
+ static const char *all_big[]= {
+ "???_______________________________________???",
+ "??_________________________________________??",
+ "?_________X______X___X______________________?",
+ "_________?X_____?X__?X______XXXXXXXXXXX______",
+ "_________X_X____?X__?X_______XXXXXXXXX_______",
+ "________?X?X____?X__?X________XXXXXXX________",
+ "________X_?_X___?X__?X_________XXXXX_________",
+ "_______?X__?X___?X__?X__________XXX__________",
+ "_______?XXXXX___?X__?X___________X___________",
+ "_______X????_X__?X__?X_______________________",
+ "?_____?X____?X__?X__?X_______________________",
+ "??____X_____?_X_?X__?X_______________________",
+ "???__?_______?__?___?_______________________?",
+ };
- static int allh= sizeof(all)/sizeof(all[0]);
- const int allw= strlen(all[0]);
+#define COMMOD_SELECTOR_MATCHES(all) \
+ commod_selector_matches(search, all, \
+ sizeof((all))/sizeof((all)[0]), \
+ strlen((all)[0]))
- int alloffy, alloffx;
- for (alloffy=0; alloffy < search.br.y; alloffy++) {
- if (alloffy+allh-1 < search.tl.y) continue;
- for (alloffx=search.tl.x; alloffx+allw-1 <= search.br.x; alloffx++) {
- int good=0, bad=0;
- int x,y;
- for (x=0; x<allw; x++)
- for (y=0; y<allh; y++) {
- int want= all[y][x];
- if (want==' ') continue;
- if (get(alloffx+x, alloffy+y) == want)
- good++;
- else
- bad++;
- }
- debugf("CHECKCOMMOD alloff=%d,%d good=%d bad=%d\n",
- alloffx,alloffy, good,bad);
- if (good > 20*bad)
- goto all_found;
- }
- }
- fatal("Commodities selector not set to `All'.");
-
- all_found:;
+ if (!(COMMOD_SELECTOR_MATCHES(all_small) ||
+ COMMOD_SELECTOR_MATCHES(all_big)))
+ fatal("Commodities selector not set to `All'.");
}
CanonImage *alloc_canon_image(int w, int h) {
//static Rect islandnamer;
-void find_islandname(void) {
- Rect sunshiner;
- char sunshine[MAXIMGIDENT], archisland[MAXIMGIDENT];
+DEBUG_DEFINE_SOME_DEBUGF(structcolon,colondebugf)
- RgbImage *ri= alloc_rgb_image(page0_rgbimage->w, page0_rgbimage->h);
- const unsigned char *srcp;
- unsigned char *destp, *endp;
- for (srcp=page0_rgbimage->data, destp=ri->data,
- endp= ri->data + 3 * ri->w * ri->h;
- destp < endp;
- srcp++, destp++) {
- unsigned char c= *srcp & 0xf0;
- *destp= c | (c>>4);
- }
+Rect find_sunshine_widget(void) {
+ Rect sunshiner;
- cim= page_images[0];
-
sunshiner.tl.x= cim->w - 1034 + 885;
sunshiner.br.x= cim->w - 1034 + 1020;
sunshiner.tl.y= 227;
ADJUST_BOX(sunshiner,"o",20, (cim->w - 1034 + 700), MUST, tl,x,-1);
ADJUST_BOX(sunshiner,"o",20, cim->w, MUST, br,x,+1);
debug_rect("sunshiner",1, sunshiner);
+ return sunshiner;
+}
+
+void find_islandname(RgbImage *ri) {
+ find_structure(page_images[0], 0);
+
+ Rect sunshiner= find_sunshine_widget();
+ char sunshine[MAXIMGIDENT], archisland[MAXIMGIDENT];
+
+ const unsigned char *srcp;
+ unsigned char *destp, *endp;
+ for (srcp=page0_rgbimage->data, destp=ri->data,
+ endp= ri->data + 3 * ri->w * ri->h;
+ destp < endp;
+ srcp++, destp++) {
+ unsigned char c= *srcp & 0xf0;
+ *destp= c | (c>>4);
+ }
identify_rgbimage(ri, sunshiner, sunshine, "sunshine widget");
- if (!memcmp(sunshine,"Ship ",5)) {
+ if (!memcmp(sunshine,"Vessel ",5)) {
Rect islandnamer;
islandnamer.tl.x= cim->w - 1034 + 885;
ADJUST_BOX(islandnamer,"o",5, 0, MUST, tl,y,+1);
ADJUST_BOX(islandnamer,"o",5, cim->h, MUST, br,y,-1);
+ ADJUST_BOX(islandnamer,"o",1, 0, MUST, tl,x,+1);
+ ADJUST_BOX(islandnamer,"o",1, cim->w, MUST, br,x,-1);
+
debug_rect("islandnamer",0, islandnamer);
// int larger_islandnamebry= islandnamer.tl.y + 25;
// MUST(islandnamer.br.y < larger_islandnamebry,
identify_rgbimage(ri, islandnamer, archisland, "island");
} else {
- assert(!"not vessel");
+ Rect islandnamer;
+
+ islandnamer.tl.x= (sunshiner.tl.x + sunshiner.br.x) / 2;
+ islandnamer.tl.y= sunshiner.tl.y + 100;
+ islandnamer.br= islandnamer.tl;
+ debug_rect("islandnamer",__LINE__, islandnamer);
+
+ WALK_UNTIL_MUST(islandnamer.tl,y, -1, sunshiner.br.y, 'H');
+ WALK_UNTIL_MUST(islandnamer.tl,x, -1, 0, 'o');
+ WALK_UNTIL_MUST(islandnamer.br,x, +1, cim->w, 'o');
+ debug_rect("islandnamer",__LINE__, islandnamer);
+
+ require_rectangle_r(islandnamer, "O*", __LINE__);
+
+ int rw= RECT_W(islandnamer);
+ ADJUST_BOX(islandnamer,"O",rw-4, cim->h, MUST,br,y,+1);
+ debug_rect("islandnamer",__LINE__, islandnamer);
+
+ islandnamer.br.y += 2;
+ ADJUST_BOX(islandnamer,"O",1, cim->h, MUST,br,y,+1);
+ debug_rect("islandnamer",__LINE__, islandnamer);
+
+ islandnamer.tl.y= islandnamer.br.y-1;
+ islandnamer.br.y= islandnamer.br.y+1;
+ ADJUST_BOX(islandnamer,"*",rw, cim->h, MUST,br,y,+1);
+ ADJUST_BOX(islandnamer,"O",1, cim->w, MUST,tl,x,+1);
+ debug_rect("islandnamer",__LINE__, islandnamer);
+
+ MUST( RECT_H(islandnamer) <= 31, MR(islandnamer));
+
+ Point p;
+ int nspaces=1, might_be_colon=0;
+ uint32_t colon_pattern= 0;
+ p.y=-1;
+
+ for (p.x=islandnamer.br.x; p.x>islandnamer.tl.x; p.x--) {
+ colondebugf("structcolon: x=%4d nsp=%2d mbc=%d cp=%08"PRIx32" ",
+ p.x, nspaces, might_be_colon, colon_pattern);
+
+ uint32_t pattern=0;
+ int runs[32], nruns=0;
+ runs[0]=0; runs[1]=0;
+
+ for (p.y=islandnamer.tl.y; p.y<=islandnamer.br.y; p.y++) {
+ pattern <<= 1;
+ switch (get_p(p)) {
+ case 'O': runs[nruns]++; pattern |= 1u; break;
+ case '*': if (runs[nruns]) { nruns++; runs[nruns]=0; } break;
+ default: abort();
+ }
+ }
+
+ colondebugf(" pat=%08"PRIx32" nruns=%d runs[]={%d,%d..} ",
+ pattern, nruns, runs[0],runs[1]);
+
+ if (!pattern) {
+ if (might_be_colon)
+ /* omg it _is_ a colon */
+ goto colon_found;
+ nspaces++;
+ might_be_colon=0;
+ } else {
+ if (nruns==2 && runs[1]==runs[0]) {
+ if (!nspaces) {
+ if (pattern==colon_pattern)
+ goto ok_might_be_colon;
+ } else if (nspaces>=2) {
+ colon_pattern= pattern;
+ might_be_colon=1;
+ goto ok_might_be_colon;
+ }
+ }
+ might_be_colon=0;
+ ok_might_be_colon:
+ nspaces= 0;
+ }
+ colondebugf(" nsp=%2d mbc=%d\n", nspaces, might_be_colon);
+ }
+ MUST(!"colon found", MP(p);MR(islandnamer) );
+
+ colon_found:
+ colondebugf(" found\n");
+ islandnamer.br.x= p.x;
+
+ identify_rgbimage(ri, islandnamer, archisland, "island");
}
char *delim= strstr(archisland," - ");
CanonImage *alloc_canon_image(int w, int h);
-#define CANONICALISE_IMAGE(im,w,h, COMPUTE_RGB) do{ \
- /* compute_rgb should be a number of statements, or \
- * a block, which assigns to \
- * unsigned long rgb; \
- * given the values of \
- * int x,y; \
- * all of which are anamorphic. Result is stored in im. \
- * The COMPUTE_RGB is executed exactly once for \
- * each pixel in reading order. \
- */ \
- (im)= alloc_canon_image((w), (h)); \
- \
- int x,y; \
- for (y=0; y<(h); y++) { \
- for (x=0; x<(w); x++) { \
- const CanonColourInfo *cci; \
- unsigned long rgb; \
- COMPUTE_RGB; \
- for (cci=canoncolourinfos; cci->c; cci++) { \
- if (cci->rgb == rgb) { \
- (im)->d[y*(w) + x]= cci->c; \
- break; \
- } \
- } \
- } \
- if (DEBUGP(rect)) { \
- fprintf(debug, "%4d ",y); \
- fwrite(im->d + y*w, 1,w, debug); \
- fputc('\n',debug); \
- } \
- } \
- debug_flush(); \
+#define CANONICALISE_IMAGE(im,w,h, COMPUTE_RGB) do{ \
+ /* compute_rgb should be a number of statements, or \
+ * a block, which assigns to \
+ * unsigned long rgb; \
+ * given the values of \
+ * int x,y; \
+ * all of which are anamorphic. Result is stored in im. \
+ * The COMPUTE_RGB is executed exactly once for \
+ * each pixel in reading order. \
+ */ \
+ (im)= alloc_canon_image((w), (h)); \
+ \
+ int x,y; \
+ unsigned long last_rgb= ~0UL; \
+ int last_c= -1; \
+ for (y=0; y<(h); y++) { \
+ for (x=0; x<(w); x++) { \
+ const CanonColourInfo *cci; \
+ unsigned long rgb; \
+ COMPUTE_RGB; \
+ if (rgb == last_rgb) { \
+ (im)->d[y*(w) + x]= last_c; \
+ } else { \
+ for (cci=canoncolourinfos; cci->c; cci++) { \
+ if (cci->rgb == rgb) { \
+ last_rgb= rgb; \
+ (im)->d[y*(w) + x]= last_c= cci->c; \
+ break; \
+ } \
+ } \
+ } \
+ } \
+ if (DEBUGP(rect)) { \
+ fprintf(debug, "%4d ",y); \
+ fwrite(im->d + y*w, 1,w, debug); \
+ fputc('\n',debug); \
+ } \
+ } \
+ debug_flush(); \
}while(0)
file ypp-commodities
-set confirm off
-set args -Dcallout --ocean midnight --pirate aristarchus --same --raw-tsv >raw.tsv
-break convert.c:260
+set args -Dpages --test-servers --find-island
+break pages.c:596
+
+#set args -Dcallout --ocean midnight --pirate aristarchus --same --raw-tsv >raw.tsv
+#break convert.c:260
+
run