+ incr lno
+ errexpect-setline $lno $l
+ set l [string trim $l]
+ if {![string length $l]} continue
+ if {[regexp {^\#} $l]} continue
+ if {![regexp -expanded \
+ {^ (\d+) (?: \s+([^=]*?) )? \s* =
+ (?: \s* (\S+)
+ (?: \s+ (\S+) )?)? $} \
+ $l dummy vid vname owner note]} {
+ errexpect-error "badly formatted"
+ }
+ set vname [string trim $vname]
+ if {[info exists notes($vid)]} {
+ errexpect-error "duplicate vesselid $vid"
+ }
+ set notes($vid) [list $lno $vname $owner $note]
+ }
+}
+
+proc note-info {lno vid name island description} {
+ global note_infos
+ lappend note_infos [list $lno $vid $name $island $description]
+}
+
+proc display-note-infos {} {
+ global note_infos note_missings notes
+
+ set nmissing [llength $note_missings]
+ debug "display-note-infos $nmissing [array size notes]"
+
+ if {[llength $note_infos]} {
+ set tiny "[llength $note_infos] warning(s)"
+ } elseif {$nmissing && [array size notes]} {
+ set tiny "$nmissing missing"
+ } else {
+ return
+ }
+
+ set infodata {}
+
+ foreach info $note_infos {
+ manyset $info lno vid name island description
+ append infodata "vessel"
+ append infodata " $vid"
+ if {[string length $name]} { append infodata " $name" }
+ if {[string length $island]} { append infodata " ($island)" }
+ append infodata ": " $description "\n"
+ }
+
+ if {$nmissing} {
+ if {[string length $infodata]} { append infodata "\n" }
+ append infodata "$nmissing vessel(s) not mentioned in notes:\n"
+ set last_island {}
+ foreach info [lsort $note_missings] {
+ manyset $info island name vid
+ if {[string compare $island $last_island]} {
+ append infodata "# $island:\n"
+ set last_island $island
+ }
+ append infodata [format "%-9d %-29s =\n" $vid $name]
+ }
+ }
+
+ parser-control-failed-core .cp.ctrl.notes notes \
+ white blue 0 \
+ $tiny \
+ "[llength $note_infos] warning(s);\
+ $nmissing vessel(s) missing" \
+ "Full description of warnings and missing vessels:" \
+ $infodata
+}
+
+#---------- vessel properties ----------
+
+proc info-cache-update {} {
+ global info_source info_cache
+ file mkdir $info_cache
+ exec sh -c "cp -u icons/* $info_cache/."
+
+ if {[string length $info_source]} {
+ set cmdl [list \
+ rsync -udLKtOzm \
+ --exclude=*~ --exclude=*.bak --exclude=.* --exclude=*.tmp \
+ $info_source/ $info_cache 2>@ stderr]
+ debug "INFO-CACHE $cmdl"
+ eval exec $cmdl
+ }
+
+ set f [open $info_cache/vessel-info]
+ glset vessel_class_data [read $f]
+ close $f
+}
+
+proc vesselclasses-init {} {
+ global vc_game2code vc_code2abbrev vc_code2full vc_codes
+
+ global vessel_class_data
+ manyset $vessel_class_data classinfos subclassinfos
+
+ set vc_codes {}
+ foreach {game code abbrev full} $classinfos {
+ if {![regexp {^[a-z][a-z]$} $code code]} { error "bad code" }
+ if {![regexp {^[a-z][a-z]$} $abbrev abbrev]} { error "bad abbrev" }
+ lappend vc_codes $code
+ set vc_game2code($game) $code
+ set vc_code2abbrev($code) $abbrev
+ set vc_code2full($code) $full
+ load-icon $abbrev
+ }
+
+ global vsc_code2report
+ global vsc_game2code
+ set vsc_game2code(null) {}
+ set vsc_code2report() Ordinary
+ foreach {game code full} $subclassinfos {
+ if {![regexp {^[A-Z]$} $code code]} { error "bad code" }
+ set vsc_game2code($game) $code
+ set vsc_code2report($code) $full
+ }
+
+ load-icon atsea
+ foreach a {battle borrow dot} {
+ foreach b {ours dot query} {
+ load-icon-combine $a $b
+ }
+ }
+}
+
+proc load-icon {icon} {
+ global info_cache
+ image create bitmap icon/$icon -file $info_cache/$icon.xbm
+}
+
+proc load-icon-combine {args} {
+ global info_cache
+ set cmd {}
+ set delim "pnmcat -lr "
+ foreach icon $args {
+ append cmd $delim " <(xbmtopbm $info_cache/$icon.xbm)"
+ set delim " <(pbmmake -white 1 1)"
+ }
+ append cmd " | pbmtoxbm"
+ debug "load-icon-combine $cmd"
+ image create bitmap icon/[join $args +] -data [exec bash -c $cmd]
+}
+
+proc code-lockown2icon {lockown} {
+ manyset [split $lockown ""] lock notown
+ return icon/[
+ lindex {battle borrow dot} $lock
+ ]+[
+ lindex {ours dot query} $notown
+ ]
+}
+
+proc canvas-horiz-stack {xvar xoff y bind type args} {
+ upvar 1 $xvar x
+ upvar 1 canvas canvas
+ set id [eval $canvas create $type [expr {$x+$xoff}] $y $args]
+ set bbox [$canvas bbox $id]
+ set x [lindex $bbox 2]
+ $canvas bind $id <ButtonPress> $bind
+ return $id
+}
+
+proc code2canvas {code canvas x yvar qty qtylen bind} {
+ global vc_code2abbrev
+ upvar 1 $yvar y
+
+ manyset [split $code _] inport class subclass lockown xabbrev
+
+ set stackx $x
+ incr stackx 2
+ set imy [expr {$y+2}]
+
+ if {!$inport} { incr qtylen -1 }
+ if {$qtylen<=0} { set qtylen {} }
+ set qty [format "%${qtylen}s" $qty]
+
+ set qtyid [canvas-horiz-stack stackx 0 $y $bind \
+ text -anchor nw -font fixed -text $qty]
+
+ if {!$inport} {
+ canvas-horiz-stack stackx 0 $imy $bind \
+ image -anchor nw -image icon/atsea
+ incr stackx
+ }
+
+ upvar #0 vc_code2abbrev($class) vcabb
+ if {![info exists vcabb]} {
+ set vcabb vc-$class
+ image create bitmap icon/$vcabb -data \
+ [exec pbmtext -builtin fixed $class | pnminvert | pnmcrop >t.pnm]
+ }
+ canvas-horiz-stack stackx -1 $imy $bind \
+ image -anchor nw -image icon/$vcabb
+
+ if {[string length $subclass]} {
+ canvas-horiz-stack stackx 0 $y $bind \
+ text -anchor nw -font fixed -text \
+ $subclass
+ }
+
+ incr stackx
+ canvas-horiz-stack stackx 0 $imy $bind \
+ image -anchor nw -image [code-lockown2icon $lockown]
+ incr stackx
+
+ if {[string length $xabbrev]} {
+ canvas-horiz-stack stackx 0 $y $bind \
+ text -anchor nw -font fixed -text \
+ $xabbrev
+ }
+
+ set bbox [$canvas bbox $qtyid]
+ set ny [lindex $bbox 3]
+ set bid [$canvas create rectangle \
+ $x $y $stackx $ny \
+ -fill white]
+
+ set y $ny
+ $canvas lower $bid $qtyid
+
+ $canvas bind $bid <ButtonPress> $bind
+}
+
+proc show-report-decode {code} {
+ global vc_code2full
+
+ manyset [split $code _] inport classcode subclass lockown xabbrev
+ manyset [split $lockown ""] lock notown
+
+ report-set inport [lindex {{At Sea} {In port}} $inport]
+ report-set class $vc_code2full($classcode)
+
+ upvar #0 vsc_code2report($subclass) subclass_report
+ if {[info exists subclass_report]} {
+ report-set subclass $subclass_report
+ } else {
+ report-set subclass "Subclass \"$subclass\""
+ }
+
+ report-set lock [lindex {
+ {Battle ready} {Unlocked} {Locked}
+ } $lock]
+
+ switch -exact $notown {
+ 0 { report-set own "Yours" }
+ 1 { report-set own "Other pirate's" }
+ 2 { report-set own "Owner unknown" }
+ default { report-set own "?? $notown" }
+ }
+
+ if {[string length $xabbrev]} {
+ report-set xabbrev "Notes flags: $xabbrev"
+ } else {
+ report-set xabbrev "No flags in notes"