wip(0.S2): migrate - a var nothing writes becomes a let; a state is keyed by its module, directory or program, so every program's plan agrees; paths normalized; program states named SceneDemoState / scene_demo_st; the LSP reads state, mut and entry/handler parameters

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 15:31:34 +03:00
parent 3eda72e8c2
commit 5ffe50ed02
463 changed files with 72045 additions and 67421 deletions

View file

@ -1,37 +1,37 @@
# frame.ludic - what the camera sees right now: the game offers each subject and tag, and the frame
# takes the best subject's grade - which is what a photographer would say about it
export function photo_frame_begin(photo_st: mut PhotoState) -> void {
photo_st.pht_pending_tags = ""
photo_st.pht_pending_mask = 0
photo_st.pht_pending_legend = 0
photo_st.pht_pending_grade = 0
photo_st.pht_pending_why = PHOTO_WHY_NONE
photo_st.pht_pending_sign = -1
photo_st.pht_pending_stars = false
export function photo_frame_begin() -> void {
pht_pending_tags = ""
pht_pending_mask = 0
pht_pending_legend = 0
pht_pending_grade = 0
pht_pending_why = PHOTO_WHY_NONE
pht_pending_sign = -1
pht_pending_stars = false
}
# A subject `sp` (0..31) named `name`, h metres tall, standing at (x, y, z) and doing something worth
# `moment`. True when the lens sees it within its range: it is tagged (once a kind, every legend) and
# scored, and the best score is the frame's.
export function photo_frame_subject(photo_st: mut PhotoState, sp: int, name: string, x: float, y: float, z: float, h: float, legend: bool, moment: int) -> bool {
export function photo_frame_subject(sp: int, name: string, x: float, y: float, z: float, h: float, legend: bool, moment: int) -> bool {
if not photo_in_view(x, y + 0.8, z, PhotoLens.range()) { return false }
if (photo_st.pht_pending_mask & (1 << sp)) == 0 or legend { photo_frame_tag(photo_st, name) }
photo_st.pht_pending_mask = photo_st.pht_pending_mask | (1 << sp)
if legend { photo_st.pht_pending_legend = photo_st.pht_pending_legend | (1 << sp) }
let g = photo_score(photo_st, x, y, z, h, moment)
if g > photo_st.pht_pending_grade {
photo_st.pht_pending_grade = g
photo_st.pht_pending_why = photo_why_of_comp(photo_st)
if (pht_pending_mask & (1 << sp)) == 0 or legend { photo_frame_tag(name) }
pht_pending_mask = pht_pending_mask | (1 << sp)
if legend { pht_pending_legend = pht_pending_legend | (1 << sp) }
let g = photo_score(x, y, z, h, moment)
if g > pht_pending_grade {
pht_pending_grade = g
pht_pending_why = photo_why_of_comp()
}
return true
}
# anything else in the picture worth naming: a landmark, the water, a sign
export function photo_frame_tag(photo_st: mut PhotoState, text: string) -> void {
export function photo_frame_tag(text: string) -> void {
if len(text) == 0 { return }
if len(photo_st.pht_pending_tags) > 0 { photo_st.pht_pending_tags = photo_st.pht_pending_tags + ", " }
photo_st.pht_pending_tags = photo_st.pht_pending_tags + text
if len(pht_pending_tags) > 0 { pht_pending_tags = pht_pending_tags + ", " }
pht_pending_tags = pht_pending_tags + text
}
export function photo_frame_sign(photo_st: mut PhotoState, sign: int) -> void { photo_st.pht_pending_sign = sign }
export function photo_frame_stars(photo_st: mut PhotoState) -> void { photo_st.pht_pending_stars = true }
export function photo_frame_sign(sign: int) -> void { pht_pending_sign = sign }
export function photo_frame_stars() -> void { pht_pending_stars = true }

View file

@ -37,39 +37,39 @@ export function photo_score_frame(sx: float, sy: float, frac: float) -> int {
# The whole score for a subject `h` metres tall standing at (x, y, z), doing something worth
# `moment` (0..20). Composition, light and behaviour are qualities OF a subject, so they are
# weighted by how much of one there is: a deer three pixels wide in perfect light is not a photograph.
export function photo_score(photo_st: mut PhotoState, x: float, y: float, z: float, h: float, moment: int) -> int {
export function photo_score(x: float, y: float, z: float, h: float, moment: int) -> int {
let dx = x - PhotoLens.x()
let dy = y + 0.6 - PhotoLens.y()
let dz = z - PhotoLens.z()
let d = Math.max(Math.sqrt(dx * dx + dy * dy + dz * dz), 0.01)
let frac = pht_size_frac(h, d)
if photo_st.pht_comp == null { pht_blank(photo_st) }
if pht_comp == null { pht_blank() }
var sx = 0.5
var sy = 0.5
if PhotoLens.project(x, y + h * 0.5, z) {
sx = PhotoLens.sx()
sy = PhotoLens.sy()
}
photo_st.pht_comp[0] = float(photo_score_size(frac))
photo_st.pht_comp[1] = float(photo_score_frame(sx, sy, frac))
if PhotoLens.steady() { photo_st.pht_comp[1] = Math.min(photo_st.pht_comp[1] + 5.0, 20.0) }
photo_st.pht_comp[2] = float(photo_score_light(x, z))
photo_st.pht_comp[3] = float(Math.clamp(moment, 0, 20))
photo_st.pht_comp_have = true
let presence = Math.clamp(photo_st.pht_comp[0] / 40.0 * 1.4, 0.0, 1.0)
pht_comp[0] = float(photo_score_size(frac))
pht_comp[1] = float(photo_score_frame(sx, sy, frac))
if PhotoLens.steady() { pht_comp[1] = Math.min(pht_comp[1] + 5.0, 20.0) }
pht_comp[2] = float(photo_score_light(x, z))
pht_comp[3] = float(Math.clamp(moment, 0, 20))
pht_comp_have = true
let presence = Math.clamp(pht_comp[0] / 40.0 * 1.4, 0.0, 1.0)
if PhotoRules.behaviour() {
photo_st.pht_comp[0] = photo_st.pht_comp[0] * 0.5
photo_st.pht_comp[3] = photo_st.pht_comp[3] * 2.0
pht_comp[0] = pht_comp[0] * 0.5
pht_comp[3] = pht_comp[3] * 2.0
}
return int(photo_st.pht_comp[0] + (photo_st.pht_comp[1] + photo_st.pht_comp[2] + photo_st.pht_comp[3]) * presence)
return int(pht_comp[0] + (pht_comp[1] + pht_comp[2] + pht_comp[3]) * presence)
}
# the one thing to do differently next time: the worst component, or nothing to fault
export function photo_why_of_comp(photo_st: PhotoState) -> int {
export function photo_why_of_comp() -> int {
var worst = PHOTO_WHY_SIZE
var least = photo_st.pht_comp[0] / 40.0
var least = pht_comp[0] / 40.0
for k in 1 .. 4 {
let f = photo_st.pht_comp[k] / 20.0
let f = pht_comp[k] / 20.0
if f < least {
least = f
worst = k

View file

@ -1,81 +1,81 @@
# keep.ludic - the frame onto the roll, and a frame off it
# The composed frame, kept as `file` on `day` at `hour`: the index, or -1 when the card is full.
# Every subject in it counts as photographed, and its best grade may rise.
export function photo_keep(base_st: mut BaseState, photo_st: mut PhotoState, file: string, day: int, hour: float) -> int {
if photo_st.pht_n >= photo_st.pht_max {
pht_fact(base_st, photo_st, PHOTO_FULL, -1)
export function photo_keep(file: string, day: int, hour: float) -> int {
if pht_n >= pht_max {
pht_fact(PHOTO_FULL, -1)
return -1
}
var firsts = 0
for sp in 0 .. 32 { if (photo_st.pht_pending_mask & (1 << sp)) != 0 and photo_st.pht_best[sp] == 0 { firsts = firsts | (1 << sp) } }
let i = photo_add(photo_st, day, hour, photo_st.pht_pending_mask, photo_st.pht_pending_legend, false, photo_st.pht_pending_tags, file, photo_st.pht_pending_grade, photo_st.pht_pending_why)
photo_st.pht_legend_shot = photo_st.pht_legend_shot | photo_st.pht_pending_legend
let f = pht_fact(base_st, photo_st, PHOTO_KEPT, i)
f.mask = photo_st.pht_pending_mask
f.legend = photo_st.pht_pending_legend
for sp in 0 .. 32 { if (pht_pending_mask & (1 << sp)) != 0 and pht_best[sp] == 0 { firsts = firsts | (1 << sp) } }
let i = photo_add(day, hour, pht_pending_mask, pht_pending_legend, false, pht_pending_tags, file, pht_pending_grade, pht_pending_why)
pht_legend_shot = pht_legend_shot | pht_pending_legend
let f = pht_fact(PHOTO_KEPT, i)
f.mask = pht_pending_mask
f.legend = pht_pending_legend
f.firsts = firsts
f.grade = photo_st.pht_pending_grade
f.sign = photo_st.pht_pending_sign
f.stars = photo_st.pht_pending_stars
f.grade = pht_pending_grade
f.sign = pht_pending_sign
f.stars = pht_pending_stars
f.file = file
f.tags = photo_st.pht_pending_tags
f.tags = pht_pending_tags
return i
}
# a frame onto the roll as it stands (a save, an older trip): the index, or -1 when full
export function photo_add(photo_st: mut PhotoState, day: int, hour: float, mask: int, legend: int, sold: bool, tags: string, file: string, grade: int, why: int) -> int {
if photo_st.pht_day == null { pht_blank(photo_st) }
if photo_st.pht_n >= photo_st.pht_max { return -1 }
let i = photo_st.pht_n
photo_st.pht_day[i] = day
photo_st.pht_hour[i] = hour
photo_st.pht_mask[i] = mask
photo_st.pht_legend[i] = legend
photo_st.pht_sold[i] = 0
if sold { photo_st.pht_sold[i] = 1 }
photo_st.pht_grade[i] = grade
photo_st.pht_why[i] = why
push(photo_st.pht_tags, tags)
push(photo_st.pht_file, file)
photo_st.pht_n += 1
photo_st.pht_species_shot = photo_st.pht_species_shot | mask
for sp in 0 .. 32 { if (mask & (1 << sp)) != 0 and grade > photo_st.pht_best[sp] { photo_st.pht_best[sp] = grade } }
export function photo_add(day: int, hour: float, mask: int, legend: int, sold: bool, tags: string, file: string, grade: int, why: int) -> int {
if pht_day == null { pht_blank() }
if pht_n >= pht_max { return -1 }
let i = pht_n
pht_day[i] = day
pht_hour[i] = hour
pht_mask[i] = mask
pht_legend[i] = legend
pht_sold[i] = 0
if sold { pht_sold[i] = 1 }
pht_grade[i] = grade
pht_why[i] = why
push(pht_tags, tags)
push(pht_file, file)
pht_n += 1
pht_species_shot = pht_species_shot | mask
for sp in 0 .. 32 { if (mask & (1 << sp)) != 0 and grade > pht_best[sp] { pht_best[sp] = grade } }
return i
}
# forgetting one: the record goes, the ones after it close up, and the game is told the file
export function photo_remove(base_st: mut BaseState, photo_st: mut PhotoState, i: int) -> void {
if i < 0 or i >= photo_st.pht_n { return }
let f = pht_fact(base_st, photo_st, PHOTO_DELETED, i)
f.file = photo_st.pht_file[i]
export function photo_remove(i: int) -> void {
if i < 0 or i >= pht_n { return }
let f = pht_fact(PHOTO_DELETED, i)
f.file = pht_file[i]
let tags = new []string
let files = new []string
for k in 0 .. photo_st.pht_n {
for k in 0 .. pht_n {
if k == i { continue }
push(tags, photo_st.pht_tags[k])
push(files, photo_st.pht_file[k])
push(tags, pht_tags[k])
push(files, pht_file[k])
}
for k in i .. photo_st.pht_n - 1 {
photo_st.pht_day[k] = photo_st.pht_day[k + 1]
photo_st.pht_hour[k] = photo_st.pht_hour[k + 1]
photo_st.pht_mask[k] = photo_st.pht_mask[k + 1]
photo_st.pht_legend[k] = photo_st.pht_legend[k + 1]
photo_st.pht_sold[k] = photo_st.pht_sold[k + 1]
photo_st.pht_grade[k] = photo_st.pht_grade[k + 1]
photo_st.pht_why[k] = photo_st.pht_why[k + 1]
for k in i .. pht_n - 1 {
pht_day[k] = pht_day[k + 1]
pht_hour[k] = pht_hour[k + 1]
pht_mask[k] = pht_mask[k + 1]
pht_legend[k] = pht_legend[k + 1]
pht_sold[k] = pht_sold[k + 1]
pht_grade[k] = pht_grade[k + 1]
pht_why[k] = pht_why[k + 1]
}
photo_st.pht_tags = tags
photo_st.pht_file = files
photo_st.pht_n -= 1
if photo_st.pht_cover == i { photo_st.pht_cover = -1 } else if photo_st.pht_cover > i { photo_st.pht_cover -= 1 }
pht_tags = tags
pht_file = files
pht_n -= 1
if pht_cover == i { pht_cover = -1 } else if pht_cover > i { pht_cover -= 1 }
}
export function photo_cover_set(photo_st: mut PhotoState, i: int) -> void { photo_st.pht_cover = i }
export function photo_cover_set(i: int) -> void { pht_cover = i }
# what has been photographed outright (a network's word, a staged trip)
export function photo_record_set(photo_st: mut PhotoState, species: int, legends: int) -> void {
photo_st.pht_species_shot = species
photo_st.pht_legend_shot = legends
export function photo_record_set(species: int, legends: int) -> void {
pht_species_shot = species
pht_legend_shot = legends
}
export function photo_best_set(photo_st: mut PhotoState, sp: int, grade: int) -> void { if sp >= 0 and sp < 32 { photo_st.pht_best[sp] = grade } }
export function photo_best_set(sp: int, grade: int) -> void { if sp >= 0 and sp < 32 { pht_best[sp] = grade } }

View file

@ -5,47 +5,50 @@ export const PHOTO_BEST: int = 1
export const PHOTO_BY_SUBJECT: int = 2
export const PHOTO_PAGE: int = 8
var pht_sort: int = 0
var pht_page: int = 0
var pht_order: []int = null
export function photo_sort(photo_st: PhotoState) -> int { return photo_st.pht_sort }
export function photo_sort_next(photo_st: mut PhotoState) -> void { photo_st.pht_sort = (photo_st.pht_sort + 1) % 3 }
export function photo_sort_set(photo_st: mut PhotoState, s: int) -> void { photo_st.pht_sort = Math.clamp(s, 0, 2) }
export function photo_sort() -> int { return pht_sort }
export function photo_sort_next() -> void { pht_sort = (pht_sort + 1) % 3 }
export function photo_sort_set(s: int) -> void { pht_sort = Math.clamp(s, 0, 2) }
# the roll in the chosen order: newest first, best first, or by subject
export function photo_order(photo_st: mut PhotoState) -> []int {
photo_st.pht_order = new []int
for i in 0 .. photo_st.pht_n { push(photo_st.pht_order, i) }
if photo_st.pht_sort == PHOTO_NEWEST {
for i in 0 .. photo_st.pht_n { photo_st.pht_order[i] = photo_st.pht_n - 1 - i }
return photo_st.pht_order
export function photo_order() -> []int {
pht_order = new []int
for i in 0 .. pht_n { push(pht_order, i) }
if pht_sort == PHOTO_NEWEST {
for i in 0 .. pht_n { pht_order[i] = pht_n - 1 - i }
return pht_order
}
for i in 0 .. photo_st.pht_n {
for i in 0 .. pht_n {
var best = i
for k in i + 1 .. photo_st.pht_n { if pht_before(photo_st, photo_st.pht_order[k], photo_st.pht_order[best]) { best = k } }
let t = photo_st.pht_order[i]
photo_st.pht_order[i] = photo_st.pht_order[best]
photo_st.pht_order[best] = t
for k in i + 1 .. pht_n { if pht_before(pht_order[k], pht_order[best]) { best = k } }
let t = pht_order[i]
pht_order[i] = pht_order[best]
pht_order[best] = t
}
return photo_st.pht_order
return pht_order
}
function pht_before(photo_st: PhotoState, a: int, b: int) -> bool {
if photo_st.pht_sort == PHOTO_BEST { return photo_st.pht_grade[a] > photo_st.pht_grade[b] }
return photo_st.pht_mask[a] < photo_st.pht_mask[b]
function pht_before(a: int, b: int) -> bool {
if pht_sort == PHOTO_BEST { return pht_grade[a] > pht_grade[b] }
return pht_mask[a] < pht_mask[b]
}
export function photo_pages(photo_st: PhotoState) -> int { return (photo_st.pht_n + PHOTO_PAGE - 1) / PHOTO_PAGE }
export function photo_page_now(photo_st: PhotoState) -> int { return photo_st.pht_page }
export function photo_page_step(photo_st: mut PhotoState, d: int) -> void { photo_st.pht_page = Math.clamp(photo_st.pht_page + d, 0, Math.max(photo_pages(photo_st) - 1, 0)) }
export function photo_pages() -> int { return (pht_n + PHOTO_PAGE - 1) / PHOTO_PAGE }
export function photo_page_now() -> int { return pht_page }
export function photo_page_step(d: int) -> void { pht_page = Math.clamp(pht_page + d, 0, Math.max(photo_pages() - 1, 0)) }
# a page of the roll, in its order; the page is held inside the roll
export function photo_page_list(photo_st: mut PhotoState) -> []int {
export function photo_page_list() -> []int {
let out = new []int
if photo_st.pht_n == 0 { return out }
let order = photo_order(photo_st)
if photo_st.pht_page >= photo_pages(photo_st) { photo_st.pht_page = photo_pages(photo_st) - 1 }
if pht_n == 0 { return out }
let order = photo_order()
if pht_page >= photo_pages() { pht_page = photo_pages() - 1 }
for k in 0 .. PHOTO_PAGE {
let oi = photo_st.pht_page * PHOTO_PAGE + k
if oi < photo_st.pht_n { push(out, order[oi]) }
let oi = pht_page * PHOTO_PAGE + k
if oi < pht_n { push(out, order[oi]) }
}
return out
}

View file

@ -1,38 +1,38 @@
# queries.ludic - what a game may ask of the roll and of the frame being composed
export function photo_count(photo_st: PhotoState) -> int { return photo_st.pht_n }
export function photo_max(photo_st: PhotoState) -> int { return photo_st.pht_max }
export function photo_full(photo_st: PhotoState) -> bool { return photo_st.pht_n >= photo_st.pht_max }
export function photo_day(photo_st: PhotoState, i: int) -> int { return photo_st.pht_day[i] }
export function photo_hour(photo_st: PhotoState, i: int) -> float { return photo_st.pht_hour[i] }
export function photo_mask(photo_st: PhotoState, i: int) -> int { return photo_st.pht_mask[i] }
export function photo_legend_mask(photo_st: PhotoState, i: int) -> int { return photo_st.pht_legend[i] }
export function photo_sold(photo_st: PhotoState, i: int) -> bool { return photo_st.pht_sold[i] != 0 }
export function photo_grade(photo_st: PhotoState, i: int) -> int { return photo_st.pht_grade[i] }
export function photo_why(photo_st: PhotoState, i: int) -> int { return photo_st.pht_why[i] }
export function photo_tags(photo_st: PhotoState, i: int) -> string { return photo_st.pht_tags[i] }
export function photo_file(photo_st: PhotoState, i: int) -> string { return photo_st.pht_file[i] }
export function photo_count() -> int { return pht_n }
export function photo_max() -> int { return pht_max }
export function photo_full() -> bool { return pht_n >= pht_max }
export function photo_day(i: int) -> int { return pht_day[i] }
export function photo_hour(i: int) -> float { return pht_hour[i] }
export function photo_mask(i: int) -> int { return pht_mask[i] }
export function photo_legend_mask(i: int) -> int { return pht_legend[i] }
export function photo_sold(i: int) -> bool { return pht_sold[i] != 0 }
export function photo_grade(i: int) -> int { return pht_grade[i] }
export function photo_why(i: int) -> int { return pht_why[i] }
export function photo_tags(i: int) -> string { return pht_tags[i] }
export function photo_file(i: int) -> string { return pht_file[i] }
# a frame with a subject in it was graded; a view is not
export function photo_graded(photo_st: PhotoState, i: int) -> bool { return photo_st.pht_mask[i] != 0 }
export function photo_cover(photo_st: PhotoState) -> int { return photo_st.pht_cover }
export function photo_graded(i: int) -> bool { return pht_mask[i] != 0 }
export function photo_cover() -> int { return pht_cover }
export function photo_species_shot(photo_st: PhotoState) -> int { return photo_st.pht_species_shot }
export function photo_legend_shot(photo_st: PhotoState) -> int { return photo_st.pht_legend_shot }
export function photo_best(photo_st: PhotoState, sp: int) -> int {
if sp < 0 or sp >= len(photo_st.pht_best) { return 0 }
return photo_st.pht_best[sp]
export function photo_species_shot() -> int { return pht_species_shot }
export function photo_legend_shot() -> int { return pht_legend_shot }
export function photo_best(sp: int) -> int {
if sp < 0 or sp >= len(pht_best) { return 0 }
return pht_best[sp]
}
export function photo_pending_tags(photo_st: PhotoState) -> string { return photo_st.pht_pending_tags }
export function photo_pending_mask(photo_st: PhotoState) -> int { return photo_st.pht_pending_mask }
export function photo_pending_legend(photo_st: PhotoState) -> int { return photo_st.pht_pending_legend }
export function photo_pending_grade(photo_st: PhotoState) -> int { return photo_st.pht_pending_grade }
export function photo_pending_why(photo_st: PhotoState) -> int { return photo_st.pht_pending_why }
export function photo_pending_sign(photo_st: PhotoState) -> int { return photo_st.pht_pending_sign }
export function photo_pending_stars(photo_st: PhotoState) -> bool { return photo_st.pht_pending_stars }
export function photo_pending_tags() -> string { return pht_pending_tags }
export function photo_pending_mask() -> int { return pht_pending_mask }
export function photo_pending_legend() -> int { return pht_pending_legend }
export function photo_pending_grade() -> int { return pht_pending_grade }
export function photo_pending_why() -> int { return pht_pending_why }
export function photo_pending_sign() -> int { return pht_pending_sign }
export function photo_pending_stars() -> bool { return pht_pending_stars }
# the last subject's four components (size of 40, framing, light and the moment of 20 each), for a meter
export function photo_comp(photo_st: PhotoState, k: int) -> float { return photo_st.pht_comp[k] }
export function photo_comp_have(photo_st: PhotoState) -> bool { return photo_st.pht_comp_have }
export function photo_comp(k: int) -> float { return pht_comp[k] }
export function photo_comp_have() -> bool { return pht_comp_have }
# the band a grade falls in: 0 a record shot, 1 fair, 2 good, 3 fine, 4 one for the wall
export function photo_band(g: int) -> int {

View file

@ -26,49 +26,44 @@ export property PhotoFact {
v: int = 0
}
export state PhotoState {
pht_sort: int = 0
pht_page: int = 0
pht_order: []int = null
pht_max: int = 40
pht_n: int = 0
pht_day: []int = null
pht_hour: []float = null
pht_mask: []int = null
pht_legend: []int = null
pht_sold: []int = null
pht_grade: []int = null
pht_why: []int = null
pht_tags: []string = null
pht_file: []string = null
pht_best: []int = null # the best grade yet, per subject
pht_species_shot: int = 0 # every subject ever photographed, sold or deleted
pht_legend_shot: int = 0
pht_cover: int = -1 # the one frame a game shows for the whole roll
pht_pending_tags: string = ""
pht_pending_mask: int = 0
pht_pending_legend: int = 0
pht_pending_grade: int = 0
pht_pending_why: int = -1
pht_pending_sign: int = -1
pht_pending_stars: bool = false
pht_comp: []float = null # size, framing, light, moment of the last subject scored
pht_comp_have: bool = false
pht_fact_q: Queue<PhotoFact> = null
var pht_max: int = 40
var pht_n: int = 0
var pht_day: []int = null
var pht_hour: []float = null
var pht_mask: []int = null
var pht_legend: []int = null
var pht_sold: []int = null
var pht_grade: []int = null
var pht_why: []int = null
var pht_tags: []string = null
var pht_file: []string = null
var pht_best: []int = null # the best grade yet, per subject
var pht_species_shot: int = 0 # every subject ever photographed, sold or deleted
var pht_legend_shot: int = 0
var pht_cover: int = -1 # the one frame a game shows for the whole roll
var pht_pending_tags: string = ""
var pht_pending_mask: int = 0
var pht_pending_legend: int = 0
var pht_pending_grade: int = 0
var pht_pending_why: int = -1
var pht_pending_sign: int = -1
var pht_pending_stars: bool = false
var pht_comp: []float = null # size, framing, light, moment of the last subject scored
var pht_comp_have: bool = false
var pht_fact_q: Queue<PhotoFact> = null
export function photo_facts() -> Queue<PhotoFact> {
if pht_fact_q == null { pht_fact_q = queue_new("photo.facts") }
return pht_fact_q
}
export function photo_facts(base_st: mut BaseState, photo_st: mut PhotoState) -> Queue<PhotoFact> {
if photo_st.pht_fact_q == null { photo_st.pht_fact_q = queue_new(base_st, "photo.facts") }
return photo_st.pht_fact_q
}
function pht_fact(base_st: mut BaseState, photo_st: mut PhotoState, what: int, i: int) -> PhotoFact {
function pht_fact(what: int, i: int) -> PhotoFact {
let f = new PhotoFact
f.what = what
f.index = i
q_push(base_st, photo_facts(base_st, photo_st), f)
q_push(photo_facts(), f)
return f
}
@ -85,18 +80,18 @@ function pht_floats(n: int) -> []float {
}
# an empty roll of `max` frames
function pht_blank(photo_st: mut PhotoState) -> void {
photo_st.pht_n = 0
photo_st.pht_day = pht_ints(photo_st.pht_max)
photo_st.pht_hour = pht_floats(photo_st.pht_max)
photo_st.pht_mask = pht_ints(photo_st.pht_max)
photo_st.pht_legend = pht_ints(photo_st.pht_max)
photo_st.pht_sold = pht_ints(photo_st.pht_max)
photo_st.pht_grade = pht_ints(photo_st.pht_max)
photo_st.pht_why = pht_ints(photo_st.pht_max)
photo_st.pht_tags = new []string
photo_st.pht_file = new []string
photo_st.pht_best = pht_ints(32)
photo_st.pht_comp = pht_floats(4)
photo_st.pht_comp_have = false
function pht_blank() -> void {
pht_n = 0
pht_day = pht_ints(pht_max)
pht_hour = pht_floats(pht_max)
pht_mask = pht_ints(pht_max)
pht_legend = pht_ints(pht_max)
pht_sold = pht_ints(pht_max)
pht_grade = pht_ints(pht_max)
pht_why = pht_ints(pht_max)
pht_tags = new []string
pht_file = new []string
pht_best = pht_ints(32)
pht_comp = pht_floats(4)
pht_comp_have = false
}

View file

@ -1,56 +1,56 @@
# system.ludic - the camera as a system: the roll and what has been photographed in its own save
# section, by key. The best per subject follows from the frames, as a buyer would judge them.
export function photo_config(base_st: mut BaseState, photo_st: mut PhotoState, max: int) -> void {
photo_st.pht_max = Math.max(max, 1)
photo_reset(base_st, photo_st)
export function photo_config(max: int) -> void {
pht_max = Math.max(max, 1)
photo_reset()
}
export function photo_reset(base_st: mut BaseState, photo_st: mut PhotoState) -> void {
pht_blank(photo_st)
photo_st.pht_species_shot = 0
photo_st.pht_legend_shot = 0
photo_st.pht_cover = -1
photo_st.pht_page = 0
photo_frame_begin(photo_st)
q_clear(base_st, photo_facts(base_st, photo_st))
export function photo_reset() -> void {
pht_blank()
pht_species_shot = 0
pht_legend_shot = 0
pht_cover = -1
pht_page = 0
photo_frame_begin()
q_clear(photo_facts())
}
export function photo_save(photo_st: PhotoState) -> Val {
export function photo_save() -> Val {
let v = Value.object()
let l = Value.list()
for i in 0 .. photo_st.pht_n {
for i in 0 .. pht_n {
let o = Value.object()
sv_put_int(o, "day", photo_st.pht_day[i])
sv_put_float(o, "hour", photo_st.pht_hour[i])
sv_put_int(o, "mask", photo_st.pht_mask[i])
sv_put_int(o, "legend", photo_st.pht_legend[i])
sv_put_bool(o, "sold", photo_st.pht_sold[i] != 0)
sv_put_str(o, "tags", photo_st.pht_tags[i])
sv_put_str(o, "file", photo_st.pht_file[i])
sv_put_int(o, "grade", photo_st.pht_grade[i])
sv_put_int(o, "why", photo_st.pht_why[i])
sv_put_int(o, "day", pht_day[i])
sv_put_float(o, "hour", pht_hour[i])
sv_put_int(o, "mask", pht_mask[i])
sv_put_int(o, "legend", pht_legend[i])
sv_put_bool(o, "sold", pht_sold[i] != 0)
sv_put_str(o, "tags", pht_tags[i])
sv_put_str(o, "file", pht_file[i])
sv_put_int(o, "grade", pht_grade[i])
sv_put_int(o, "why", pht_why[i])
Value.add(l, o)
}
Value.put(v, "frames", l)
sv_put_int(v, "shot", photo_st.pht_species_shot)
sv_put_int(v, "legend_shot", photo_st.pht_legend_shot)
sv_put_int(v, "cover", photo_st.pht_cover)
sv_put_int(v, "sort", photo_st.pht_sort)
sv_put_int(v, "shot", pht_species_shot)
sv_put_int(v, "legend_shot", pht_legend_shot)
sv_put_int(v, "cover", pht_cover)
sv_put_int(v, "sort", pht_sort)
return v
}
export function photo_load(base_st: mut BaseState, photo_st: mut PhotoState, v: Val, version: int) -> void {
photo_reset(base_st, photo_st)
export function photo_load(v: Val, version: int) -> void {
photo_reset()
if Value.has(v, "frames") != 0 {
let l = Value.get(v, "frames")
for i in 0 .. Value.count(l) {
let o = Value.at(l, i)
photo_add(photo_st, sv_int(o, "day", 1), sv_float(o, "hour", 0.0), sv_int(o, "mask", 0), sv_int(o, "legend", 0), sv_bool(o, "sold", false), sv_str(o, "tags", ""), sv_str(o, "file", ""), sv_int(o, "grade", 40), sv_int(o, "why", PHOTO_WHY_NONE))
photo_add(sv_int(o, "day", 1), sv_float(o, "hour", 0.0), sv_int(o, "mask", 0), sv_int(o, "legend", 0), sv_bool(o, "sold", false), sv_str(o, "tags", ""), sv_str(o, "file", ""), sv_int(o, "grade", 40), sv_int(o, "why", PHOTO_WHY_NONE))
}
}
photo_record_set(photo_st, photo_st.pht_species_shot | sv_int(v, "shot", 0), sv_int(v, "legend_shot", 0))
photo_st.pht_cover = sv_int(v, "cover", -1)
photo_sort_set(photo_st, sv_int(v, "sort", PHOTO_NEWEST))
photo_record_set(pht_species_shot | sv_int(v, "shot", 0), sv_int(v, "legend_shot", 0))
pht_cover = sv_int(v, "cover", -1)
photo_sort_set(sv_int(v, "sort", PHOTO_NEWEST))
}
export function photo_system() -> System {

View file

@ -7,78 +7,76 @@ import "ludic.base"
program PhotoTest {
numbers float
state PhototestState {
hour: float = 12.0
night: bool = false
moon: float = 0.0
dim: int = 0
sun_z: float = 0.0
behaviour: bool = false
sx: float = 0.5
sy: float = 0.5
}
var hour: float = 12.0
var night: bool = false
var moon: float = 0.0
var dim: int = 0
var sun_z: float = 0.0
var behaviour: bool = false
var sx: float = 0.5
var sy: float = 0.5
function fk_y() -> float { return 1.5 }
function fk_fz() -> float { return -1.0 }
function fk_fov() -> float { return 0.8 }
# a pinhole at the origin: across by x over the distance, down by the height over it
function fk_project(phototest_st: mut PhototestState, x: float, y: float, z: float) -> bool {
function fk_project(x: float, y: float, z: float) -> bool {
let d = Math.max(-z, 0.5)
phototest_st.sx = 0.5 + x / d
phototest_st.sy = 0.5 - (y - 1.5) / d
sx = 0.5 + x / d
sy = 0.5 - (y - 1.5) / d
return z < 0.0
}
function fk_sx(phototest_st: PhototestState) -> float { return phototest_st.sx }
function fk_sy(phototest_st: PhototestState) -> float { return phototest_st.sy }
function fk_sx() -> float { return sx }
function fk_sy() -> float { return sy }
function fk_ground(x: float, z: float) -> float {
if x < 0.0 and z < -45.0 and z > -50.0 { return 10.0 }
return 0.0
}
function fk_trunk(x: float, z: float, r: float) -> bool { return Math.abs(x - 3.75) < 1.6 and Math.abs(z + 30.0) < 1.6 }
function fk_range() -> float { return 80.0 }
function fk_hour(phototest_st: PhototestState) -> float { return phototest_st.hour }
function fk_night(phototest_st: PhototestState) -> bool { return phototest_st.night }
function fk_moon(phototest_st: PhototestState) -> float { return phototest_st.moon }
function fk_dim(phototest_st: PhototestState) -> int { return phototest_st.dim }
function fk_sun_z(phototest_st: PhototestState) -> float { return phototest_st.sun_z }
function fk_behaviour(phototest_st: PhototestState) -> bool { return phototest_st.behaviour }
function fk_hour() -> float { return hour }
function fk_night() -> bool { return night }
function fk_moon() -> float { return moon }
function fk_dim() -> int { return dim }
function fk_sun_z() -> float { return sun_z }
function fk_behaviour() -> bool { return behaviour }
function fk_value(sp: int) -> int { return 10 + sp }
bind PhotoLens { y: fn fk_y, fz: fn fk_fz, fov: fn fk_fov, project: fn fk_project, sx: fn fk_sx, sy: fn fk_sy, ground: fn fk_ground, trunk: fn fk_trunk, range: fn fk_range }
bind PhotoLight { hour: fn fk_hour, night: fn fk_night, moon: fn fk_moon, dim: fn fk_dim, sun_z: fn fk_sun_z }
bind PhotoRules { behaviour: fn fk_behaviour, subject_value: fn fk_value }
function fresh(base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) -> void {
photo_config(base_st, photo_st, 4)
phototest_st.hour = 12.0
phototest_st.night = false
phototest_st.dim = 0
phototest_st.sun_z = 0.0
phototest_st.behaviour = false
function fresh() -> void {
photo_config(4)
hour = 12.0
night = false
dim = 0
sun_z = 0.0
behaviour = false
}
function facts(base_st: mut BaseState, photo_st: mut PhotoState) -> []PhotoFact { return q_drain(base_st, photo_facts(base_st, photo_st)) }
function facts() -> []PhotoFact { return q_drain(photo_facts()) }
function count(fs: []PhotoFact, what: int) -> int {
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }
return n
}
# a deer-sized subject straight ahead at `d` metres, doing something worth `moment`
function shoot(photo_st: mut PhotoState, sp: int, x: float, d: float, h: float, moment: int) -> bool {
photo_frame_begin(photo_st)
return photo_frame_subject(photo_st, sp, "deer", x, 0.0, -d, h, false, moment)
function shoot(sp: int, x: float, d: float, h: float, moment: int) -> bool {
photo_frame_begin()
return photo_frame_subject(sp, "deer", x, 0.0, -d, h, false, moment)
}
test "a subject ahead and in reach is in the frame; behind, too far, over a ridge or a trunk it is not" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
expect(shoot(photo_st, 1, 0.0, 20.0, 1.1, 10))
expect_eq(photo_pending_mask(photo_st), 2)
expect(photo_pending_tags(photo_st) == "deer")
expect(photo_pending_grade(photo_st) > 0)
expect(not shoot(photo_st, 1, 0.0, -20.0, 1.1, 10))
expect(not shoot(photo_st, 1, 0.0, 90.0, 1.1, 10))
expect(not shoot(photo_st, 1, -2.0, 60.0, 1.1, 10))
expect(not shoot(photo_st, 1, 5.0, 40.0, 1.1, 10))
expect_eq(photo_pending_mask(photo_st), 0)
test "a subject ahead and in reach is in the frame; behind, too far, over a ridge or a trunk it is not" {
fresh()
expect(shoot(1, 0.0, 20.0, 1.1, 10))
expect_eq(photo_pending_mask(), 2)
expect(photo_pending_tags() == "deer")
expect(photo_pending_grade() > 0)
expect(not shoot(1, 0.0, -20.0, 1.1, 10))
expect(not shoot(1, 0.0, 90.0, 1.1, 10))
expect(not shoot(1, -2.0, 60.0, 1.1, 10))
expect(not shoot(1, 5.0, 40.0, 1.1, 10))
expect_eq(photo_pending_mask(), 0)
}
test "size: a record shot is a record shot, and the band that pays is a quarter to two thirds" {
@ -90,123 +88,123 @@ program PhotoTest {
expect_eq(photo_score_frame(1.4, 0.4, 0.1), 0)
}
test "the light: gold after dawn, flat at noon, the moon at night, the weather, and backlit" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
phototest_st.hour = 6.5
test "the light: gold after dawn, flat at noon, the moon at night, the weather, and backlit" {
fresh()
hour = 6.5
expect_eq(photo_score_light(0.0, -20.0), 20)
phototest_st.hour = 12.0
hour = 12.0
expect_eq(photo_score_light(0.0, -20.0), 9)
phototest_st.dim = 4
dim = 4
expect_eq(photo_score_light(0.0, -20.0), 5)
phototest_st.dim = 0
phototest_st.sun_z = -1.0
dim = 0
sun_z = -1.0
expect_eq(photo_score_light(0.0, -20.0), 2)
phototest_st.sun_z = 0.0
phototest_st.night = true
phototest_st.moon = 1.0
sun_z = 0.0
night = true
moon = 1.0
expect_eq(photo_score_light(0.0, -20.0), 9)
}
test "the moment counts by how much subject there is, and a judge of behaviour doubles it" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
shoot(photo_st, 1, 0.0, 70.0, 0.3, 20)
let tiny = photo_pending_grade(photo_st)
shoot(photo_st, 1, 0.0, 6.0, 1.1, 6)
let big = photo_pending_grade(photo_st)
test "the moment counts by how much subject there is, and a judge of behaviour doubles it" {
fresh()
shoot(1, 0.0, 70.0, 0.3, 20)
let tiny = photo_pending_grade()
shoot(1, 0.0, 6.0, 1.1, 6)
let big = photo_pending_grade()
expect(big > tiny)
expect(tiny < 20)
shoot(photo_st, 1, 0.0, 6.0, 1.1, 20)
let busy = photo_pending_grade(photo_st)
phototest_st.behaviour = true
shoot(photo_st, 1, 0.0, 6.0, 1.1, 20)
expect(photo_pending_grade(photo_st) > busy - 21)
expect_near(photo_comp(photo_st, 3), 40.0, 0.01)
shoot(1, 0.0, 6.0, 1.1, 20)
let busy = photo_pending_grade()
behaviour = true
shoot(1, 0.0, 6.0, 1.1, 20)
expect(photo_pending_grade() > busy - 21)
expect_near(photo_comp(3), 40.0, 0.01)
}
test "the frame takes its best subject, tags each kind once and every legend" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
photo_frame_begin(photo_st)
photo_frame_subject(photo_st, 2, "elk", 0.0, 0.0, -60.0, 1.9, false, 6)
let far = photo_pending_grade(photo_st)
photo_frame_subject(photo_st, 2, "elk", 1.0, 0.0, -8.0, 1.9, false, 17)
photo_frame_subject(photo_st, 4, "the Ghost Elk", -1.0, 0.0, -9.0, 2.2, true, 20)
photo_frame_tag(photo_st, "Maroon Lake")
expect(photo_pending_grade(photo_st) > far)
expect(photo_pending_tags(photo_st) == "elk, the Ghost Elk, Maroon Lake")
expect_eq(photo_pending_mask(photo_st), 4 + 16)
expect_eq(photo_pending_legend(photo_st), 16)
expect(photo_pending_why(photo_st) >= PHOTO_WHY_SIZE)
test "the frame takes its best subject, tags each kind once and every legend" {
fresh()
photo_frame_begin()
photo_frame_subject(2, "elk", 0.0, 0.0, -60.0, 1.9, false, 6)
let far = photo_pending_grade()
photo_frame_subject(2, "elk", 1.0, 0.0, -8.0, 1.9, false, 17)
photo_frame_subject(4, "the Ghost Elk", -1.0, 0.0, -9.0, 2.2, true, 20)
photo_frame_tag("Maroon Lake")
expect(photo_pending_grade() > far)
expect(photo_pending_tags() == "elk, the Ghost Elk, Maroon Lake")
expect_eq(photo_pending_mask(), 4 + 16)
expect_eq(photo_pending_legend(), 16)
expect(photo_pending_why() >= PHOTO_WHY_SIZE)
}
test "a kept frame is on the roll, its subjects are photographed for good, and a full card says so" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
shoot(photo_st, 3, 0.0, 10.0, 1.1, 15)
let g = photo_pending_grade(photo_st)
expect_eq(photo_keep(base_st, photo_st, "a.png", 2, 7.5), 0)
let fs = facts(base_st, photo_st)
test "a kept frame is on the roll, its subjects are photographed for good, and a full card says so" {
fresh()
shoot(3, 0.0, 10.0, 1.1, 15)
let g = photo_pending_grade()
expect_eq(photo_keep("a.png", 2, 7.5), 0)
let fs = facts()
expect_eq(count(fs, PHOTO_KEPT), 1)
expect_eq(fs[0].firsts, 8)
expect_eq(photo_species_shot(photo_st), 8)
expect_eq(photo_best(photo_st, 3), g)
expect_eq(photo_day(photo_st, 0), 2)
shoot(photo_st, 3, 0.0, 10.0, 1.1, 15)
photo_keep(base_st, photo_st, "b.png", 2, 8.0)
expect_eq(facts(base_st, photo_st)[0].firsts, 0)
photo_keep(base_st, photo_st, "c.png", 2, 8.0)
photo_keep(base_st, photo_st, "d.png", 2, 8.0)
expect(photo_full(photo_st))
expect_eq(photo_keep(base_st, photo_st, "e.png", 2, 8.0), -1)
expect_eq(count(facts(base_st, photo_st), PHOTO_FULL), 1)
expect_eq(photo_species_shot(), 8)
expect_eq(photo_best(3), g)
expect_eq(photo_day(0), 2)
shoot(3, 0.0, 10.0, 1.1, 15)
photo_keep("b.png", 2, 8.0)
expect_eq(facts()[0].firsts, 0)
photo_keep("c.png", 2, 8.0)
photo_keep("d.png", 2, 8.0)
expect(photo_full())
expect_eq(photo_keep("e.png", 2, 8.0), -1)
expect_eq(count(facts(), PHOTO_FULL), 1)
}
test "the first frame of a subject is worth its value on the grade's curve; sold is sold" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
photo_add(photo_st, 1, 9.0, 2, 0, false, "fox", "f.png", 60, PHOTO_WHY_NONE)
photo_add(photo_st, 1, 9.5, 2, 2, false, "fox", "g.png", 95, PHOTO_WHY_FINE)
photo_add(photo_st, 1, 9.5, 0, 0, false, "the valley", "h.png", 0, PHOTO_WHY_NONE)
expect_eq(photo_value(photo_st, 0), int(11.0 * 1.5))
expect_eq(photo_value(photo_st, 1), int(float(11 + 120) * 4.0))
expect_eq(photo_value(photo_st, 2), 0)
let total = photo_sell_all(base_st, photo_st)
test "the first frame of a subject is worth its value on the grade's curve; sold is sold" {
fresh()
photo_add(1, 9.0, 2, 0, false, "fox", "f.png", 60, PHOTO_WHY_NONE)
photo_add(1, 9.5, 2, 2, false, "fox", "g.png", 95, PHOTO_WHY_FINE)
photo_add(1, 9.5, 0, 0, false, "the valley", "h.png", 0, PHOTO_WHY_NONE)
expect_eq(photo_value(0), int(11.0 * 1.5))
expect_eq(photo_value(1), int(float(11 + 120) * 4.0))
expect_eq(photo_value(2), 0)
let total = photo_sell_all()
expect_eq(total, int(11.0 * 1.5) + int(120.0 * 4.0))
expect_eq(count(facts(base_st, photo_st), PHOTO_SOLD), 2)
expect(photo_sold(photo_st, 0))
expect_eq(photo_value(photo_st, 0), 0)
photo_add(photo_st, 1, 10.0, 2, 0, false, "fox", "i.png", 60, PHOTO_WHY_NONE)
expect_eq(photo_value(photo_st, 3), 0)
expect_eq(count(facts(), PHOTO_SOLD), 2)
expect(photo_sold(0))
expect_eq(photo_value(0), 0)
photo_add(1, 10.0, 2, 0, false, "fox", "i.png", 60, PHOTO_WHY_NONE)
expect_eq(photo_value(3), 0)
}
test "forgetting a frame closes the roll up, moves the cover, and names the file" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
photo_add(photo_st, 1, 9.0, 2, 0, false, "a", "a.png", 10, 0)
photo_add(photo_st, 1, 9.0, 4, 0, false, "b", "b.png", 20, 0)
photo_add(photo_st, 1, 9.0, 8, 0, false, "c", "c.png", 30, 0)
photo_cover_set(photo_st, 2)
photo_remove(base_st, photo_st, 0)
expect_eq(photo_count(photo_st), 2)
expect(photo_tags(photo_st, 0) == "b")
expect_eq(photo_grade(photo_st, 1), 30)
expect_eq(photo_cover(photo_st), 1)
let fs = facts(base_st, photo_st)
test "forgetting a frame closes the roll up, moves the cover, and names the file" {
fresh()
photo_add(1, 9.0, 2, 0, false, "a", "a.png", 10, 0)
photo_add(1, 9.0, 4, 0, false, "b", "b.png", 20, 0)
photo_add(1, 9.0, 8, 0, false, "c", "c.png", 30, 0)
photo_cover_set(2)
photo_remove(0)
expect_eq(photo_count(), 2)
expect(photo_tags(0) == "b")
expect_eq(photo_grade(1), 30)
expect_eq(photo_cover(), 1)
let fs = facts()
expect(fs[0].file == "a.png")
expect_eq(photo_species_shot(photo_st), 14)
expect_eq(photo_species_shot(), 14)
}
test "the roll in order: newest first, best first, by subject, and a page at a time" (base_st: mut BaseState, photo_st: mut PhotoState) {
photo_config(base_st, photo_st, 20)
for i in 0 .. 10 { photo_add(photo_st, 1, 9.0, 1 << (i % 3), 0, false, "x", "x.png", (i * 37) % 100, 0) }
expect_eq(photo_order(photo_st)[0], 9)
photo_sort_next(photo_st)
let best = photo_order(photo_st)
expect(photo_grade(photo_st, best[0]) >= photo_grade(photo_st, best[1]))
expect(photo_grade(photo_st, best[1]) >= photo_grade(photo_st, best[9]))
photo_sort_next(photo_st)
expect(photo_mask(photo_st, photo_order(photo_st)[0]) <= photo_mask(photo_st, photo_order(photo_st)[9]))
expect_eq(photo_pages(photo_st), 2)
expect_eq(len(photo_page_list(photo_st)), 8)
photo_page_step(photo_st, 5)
expect_eq(photo_page_now(photo_st), 1)
expect_eq(len(photo_page_list(photo_st)), 2)
test "the roll in order: newest first, best first, by subject, and a page at a time" {
photo_config(20)
for i in 0 .. 10 { photo_add(1, 9.0, 1 << (i % 3), 0, false, "x", "x.png", (i * 37) % 100, 0) }
expect_eq(photo_order()[0], 9)
photo_sort_next()
let best = photo_order()
expect(photo_grade(best[0]) >= photo_grade(best[1]))
expect(photo_grade(best[1]) >= photo_grade(best[9]))
photo_sort_next()
expect(photo_mask(photo_order()[0]) <= photo_mask(photo_order()[9]))
expect_eq(photo_pages(), 2)
expect_eq(len(photo_page_list()), 8)
photo_page_step(5)
expect_eq(photo_page_now(), 1)
expect_eq(len(photo_page_list()), 2)
}
test "a file name from the tags" {
@ -215,22 +213,22 @@ program PhotoTest {
expect(photo_slug("a very long list of names past twenty") == "a-very-long-list-of-name")
}
test "the roll and what was ever photographed come back from the save" (base_st: mut BaseState, photo_st: mut PhotoState, phototest_st: mut PhototestState) {
fresh(base_st, photo_st, phototest_st)
photo_add(photo_st, 3, 18.25, 2, 2, true, "fox", "f.png", 80, PHOTO_WHY_LIGHT)
photo_record_set(photo_st, 2 | 64, 2)
photo_cover_set(photo_st, 0)
let v = photo_save(photo_st)
photo_reset(base_st, photo_st)
expect_eq(photo_count(photo_st), 0)
photo_load(base_st, photo_st, v, 1)
expect_eq(photo_count(photo_st), 1)
expect_near(photo_hour(photo_st, 0), 18.25, 0.01)
expect(photo_sold(photo_st, 0))
expect_eq(photo_why(photo_st, 0), PHOTO_WHY_LIGHT)
expect_eq(photo_species_shot(photo_st), 66)
expect_eq(photo_legend_shot(photo_st), 2)
expect_eq(photo_best(photo_st, 1), 80)
expect_eq(photo_cover(photo_st), 0)
test "the roll and what was ever photographed come back from the save" {
fresh()
photo_add(3, 18.25, 2, 2, true, "fox", "f.png", 80, PHOTO_WHY_LIGHT)
photo_record_set(2 | 64, 2)
photo_cover_set(0)
let v = photo_save()
photo_reset()
expect_eq(photo_count(), 0)
photo_load(v, 1)
expect_eq(photo_count(), 1)
expect_near(photo_hour(0), 18.25, 0.01)
expect(photo_sold(0))
expect_eq(photo_why(0), PHOTO_WHY_LIGHT)
expect_eq(photo_species_shot(), 66)
expect_eq(photo_legend_shot(), 2)
expect_eq(photo_best(1), 80)
expect_eq(photo_cover(), 0)
}
}

View file

@ -1,38 +1,38 @@
# worth.ludic - what a buyer pays for a frame: the first frame of each subject and every legend,
# on the grade's curve and the lens's worth; sold is sold
export function photo_value(photo_st: PhotoState, i: int) -> int {
if i < 0 or i >= photo_st.pht_n or photo_st.pht_sold[i] != 0 { return 0 }
export function photo_value(i: int) -> int {
if i < 0 or i >= pht_n or pht_sold[i] != 0 { return 0 }
var v = 0
for sp in 0 .. 32 {
if (photo_st.pht_mask[i] & (1 << sp)) == 0 { continue }
if (pht_mask[i] & (1 << sp)) == 0 { continue }
var first = true
for k in 0 .. photo_st.pht_n { if k != i and photo_st.pht_sold[k] != 0 and (photo_st.pht_mask[k] & (1 << sp)) != 0 { first = false } }
for k in 0 .. pht_n { if k != i and pht_sold[k] != 0 and (pht_mask[k] & (1 << sp)) != 0 { first = false } }
if first { v += PhotoRules.subject_value(sp) }
if (photo_st.pht_legend[i] & (1 << sp)) != 0 { v += PhotoRules.legend_value(sp) }
if (pht_legend[i] & (1 << sp)) != 0 { v += PhotoRules.legend_value(sp) }
}
if v > 0 { v = int(float(v) * (PhotoRules.mult() * photo_grade_mult(photo_st.pht_grade[i]))) }
if v > 0 { v = int(float(v) * (PhotoRules.mult() * photo_grade_mult(pht_grade[i]))) }
return v
}
# every frame with a price, sold: the total, and a fact a frame
export function photo_sell_all(base_st: mut BaseState, photo_st: mut PhotoState) -> int {
export function photo_sell_all() -> int {
var total = 0
for i in 0 .. photo_st.pht_n {
let v = photo_value(photo_st, i)
for i in 0 .. pht_n {
let v = photo_value(i)
if v > 0 {
total += v
photo_st.pht_sold[i] = 1
let f = pht_fact(base_st, photo_st, PHOTO_SOLD, i)
pht_sold[i] = 1
let f = pht_fact(PHOTO_SOLD, i)
f.v = v
f.mask = photo_st.pht_mask[i]
f.mask = pht_mask[i]
}
}
return total
}
# what the roll would fetch now
export function photo_worth(photo_st: PhotoState) -> int {
export function photo_worth() -> int {
var total = 0
for i in 0 .. photo_st.pht_n { total += photo_value(photo_st, i) }
for i in 0 .. pht_n { total += photo_value(i) }
return total
}