code wiki / _hdl_build / nx_swap.nx

nx_swap.nx source

↩ module page · 389 lines · 20115 B

1// nx_swap.nx -- LIB: the GAMIFIED COMMUNITY PLANT/HERB SWAP (operator: "a community swap that's like a gamified 2// fun exchange like Pokemon GO but for gardening without the licensing and other issues but allows a person to 3// ask and give say basil or rosemary instead of buying at a store"). Pokemon-GO-style FUN, but our OWN IP: the 4// "collection" is REAL PLANTS (a garden-dex), the mechanics are ours (no third-party IP/licensing). A GIFT 5// economy -- ask + give, NO money -- so you get basil/rosemary by swapping with neighbours instead of buying. 6// 7// Gamification: a garden DEX (species you grow/swapped), XP for giving + collecting, LEVELS, SETS + BADGES 8// ("gotta grow 'em all"), rarity. Area-based local discovery (privacy-first: an AREA, not GPS). Ties to the 9// seed-to-feed lineage (a swapped seed records origin=swapped). Sovereign seg-store (knowledge/store/swap-*, NO 10// TSV), integer-only. Composes nx_ads for a sovereign in-board ad slot. license_tier: ORIGINAL 11import "nx_ads.nx" 12import "nx_food_science.nx" 13import "nx_seg_store.nx" 14import "nx_syscalls.nx" 15 16func sw_put(prefix: *u8, key: *u8, val: *u8) -> i64 { 17 let vl: i64 = as_len(val) 18 if fd_streq_store(prefix, key, val, vl) == 1 { return 0 } 19 let w: *i64 = ss_begin() 20 ss_add(w, 1, key, val, vl) 21 let seg: i64 = fd_seg_next(prefix) 22 ss_commit(prefix, w, seg) 23 return 1 24} 25func sw_split(buf: *u8, len: i64, out: *i64) -> i64 { 26 var c: i64 = 0 27 var i: i64 = 0 28 var ls: i64 = 0 29 while i <= len { 30 var sep: i64 = 0 31 if i == len { sep = 1 } else { if buf[i] == (9 as u8) { sep = 1 } } 32 if sep == 1 { 33 let tl: i64 = i - ls 34 if tl > 0 { 35 let tok: *u8 = sys_mmap(48) 36 var t: i64 = 0 37 while t < tl { tok[t] = buf[ls + t]; t = t + 1 } tok[tl] = 0 as u8 38 out[c] = tok as i64; c = c + 1 39 } 40 ls = i + 1 41 } 42 i = i + 1 43 } 44 return c 45} 46// idempotent append of token to the TAB list at key 47func sw_list_append(prefix: *u8, key: *u8, token: *u8) -> i64 { 48 let pq: *i64 = sys_mmap(16) as *i64 49 let lq: *i64 = sys_mmap(16) as *i64 50 let cur: *u8 = sys_mmap(4096) 51 var o: i64 = 0 52 if ss_get(prefix, key, pq, lq) == 1 { 53 let b: *u8 = pq[0] as *u8; let n: i64 = lq[0] 54 let toks: *i64 = sys_mmap(8 * 256) as *i64 55 let nt: i64 = sw_split(b, n, toks) 56 var i: i64 = 0 57 while i < nt { if fd_streq(toks[i] as *u8, token) == 1 { return 0 } i = i + 1 } 58 var u: i64 = 0; while u < n { cur[u] = b[u]; u = u + 1 } o = n 59 cur[o] = 9 as u8; o = o + 1 60 } 61 o = as_append(cur, o, token); cur[o] = 0 as u8 62 return sw_put(prefix, key, cur) 63} 64 65// ---- config ---- 66func sw_seed_config(prefix: *u8) -> i64 { return sw_put(prefix, "swap:xpconfig" as *u8, "10\t10\t25\t100\t50" as *u8) } // give,receive,newspecies,setcomplete,per_level 67func sw_cfg(prefix: *u8, f: i64) -> i64 { 68 let pq: *i64 = sys_mmap(16) as *i64 69 let lq: *i64 = sys_mmap(16) as *i64 70 if ss_get(prefix, "swap:xpconfig" as *u8, pq, lq) != 1 { return 0 } 71 let fb: *u8 = sys_mmap(16) 72 let fl: i64 = fd_field(pq[0] as *u8, lq[0], f, fb) 73 return fd_atoi(fb, fl) 74} 75 76// ---- species catalog (the "creatures" = real plants) ---- 77func sw_add_species(prefix: *u8, sid: *u8, name: *u8, category: *u8, rarity: *u8) -> i64 { 78 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "swap:species:" as *u8); o = as_append(key, o, sid); key[o] = 0 as u8 79 let val: *u8 = sys_mmap(160); var v: i64 = 0 80 v = as_append(val, v, name); val[v] = 9 as u8; v = v + 1 81 v = as_append(val, v, category); val[v] = 9 as u8; v = v + 1 82 v = as_append(val, v, rarity); val[v] = 0 as u8 83 return sw_put(prefix, key, val) 84} 85func sw_species_field(prefix: *u8, sid: *u8, f: i64, out: *u8) -> i64 { 86 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "swap:species:" as *u8); o = as_append(key, o, sid); key[o] = 0 as u8 87 let pq: *i64 = sys_mmap(16) as *i64 88 let lq: *i64 = sys_mmap(16) as *i64 89 if ss_get(prefix, key, pq, lq) != 1 { out[0] = 0 as u8; return 0 } 90 return fd_field(pq[0] as *u8, lq[0], f, out) 91} 92 93// ---- gardeners + XP + levels ---- 94func sw_g_key(gid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:gardener:" as *u8); o = as_append(out, o, gid); out[o] = 0 as u8; return o } 95func sw_xp_key(gid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:xp:" as *u8); o = as_append(out, o, gid); out[o] = 0 as u8; return o } 96func sw_add_gardener(prefix: *u8, gid: *u8, name: *u8, area: *u8) -> i64 { 97 let key: *u8 = sys_mmap(96); sw_g_key(gid, key) 98 let val: *u8 = sys_mmap(160); var v: i64 = 0 99 v = as_append(val, v, name); val[v] = 9 as u8; v = v + 1 100 v = as_append(val, v, area); val[v] = 0 as u8 101 let w: i64 = sw_put(prefix, key, val) 102 let xk: *u8 = sys_mmap(96); sw_xp_key(gid, xk) 103 let pq: *i64 = sys_mmap(16) as *i64 104 let lq: *i64 = sys_mmap(16) as *i64 105 if ss_get(prefix, xk, pq, lq) != 1 { sw_put(prefix, xk, "0" as *u8) } 106 return w 107} 108func sw_g_field(prefix: *u8, gid: *u8, f: i64, out: *u8) -> i64 { 109 let key: *u8 = sys_mmap(96); sw_g_key(gid, key) 110 let pq: *i64 = sys_mmap(16) as *i64 111 let lq: *i64 = sys_mmap(16) as *i64 112 if ss_get(prefix, key, pq, lq) != 1 { out[0] = 0 as u8; return 0 } 113 return fd_field(pq[0] as *u8, lq[0], f, out) 114} 115func sw_xp(prefix: *u8, gid: *u8) -> i64 { 116 let xk: *u8 = sys_mmap(96); sw_xp_key(gid, xk) 117 let pq: *i64 = sys_mmap(16) as *i64 118 let lq: *i64 = sys_mmap(16) as *i64 119 if ss_get(prefix, xk, pq, lq) != 1 { return 0 } 120 return fd_atoi(pq[0] as *u8, lq[0]) 121} 122func sw_add_xp(prefix: *u8, gid: *u8, amt: i64) -> i64 { 123 let cur: i64 = sw_xp(prefix, gid) 124 let xk: *u8 = sys_mmap(96); sw_xp_key(gid, xk) 125 let nv: *u8 = sys_mmap(24); var no: i64 = fd_apnum(nv, 0, cur + amt); nv[no] = 0 as u8 126 sw_put(prefix, xk, nv) 127 return cur + amt 128} 129func sw_level(prefix: *u8, gid: *u8) -> i64 { 130 let per: i64 = sw_cfg(prefix, 4) 131 if per <= 0 { return 1 } 132 return 1 + sw_xp(prefix, gid) / per 133} 134 135// ---- garden dex (collection) ---- 136func sw_dex_key(gid: *u8, species: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:dex:" as *u8); o = as_append(out, o, gid); out[o] = 58 as u8; o = o + 1; o = as_append(out, o, species); out[o] = 0 as u8; return o } 137func sw_dexn_key(gid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:dexn:" as *u8); o = as_append(out, o, gid); out[o] = 0 as u8; return o } 138func sw_dex_has(prefix: *u8, gid: *u8, species: *u8) -> i64 { 139 let key: *u8 = sys_mmap(96); sw_dex_key(gid, species, key) 140 let pq: *i64 = sys_mmap(16) as *i64 141 let lq: *i64 = sys_mmap(16) as *i64 142 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 143 return 1 144} 145func sw_dex_count(prefix: *u8, gid: *u8) -> i64 { 146 let key: *u8 = sys_mmap(96); sw_dexn_key(gid, key) 147 let pq: *i64 = sys_mmap(16) as *i64 148 let lq: *i64 = sys_mmap(16) as *i64 149 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 150 return fd_atoi(pq[0] as *u8, lq[0]) 151} 152func sw_dex_add(prefix: *u8, gid: *u8, species: *u8) -> i64 { 153 if sw_dex_has(prefix, gid, species) == 1 { return 0 } 154 let key: *u8 = sys_mmap(96); sw_dex_key(gid, species, key) 155 sw_put(prefix, key, "1" as *u8) 156 let cnt: i64 = sw_dex_count(prefix, gid) 157 let nk: *u8 = sys_mmap(96); sw_dexn_key(gid, nk) 158 let nv: *u8 = sys_mmap(24); var no: i64 = fd_apnum(nv, 0, cnt + 1); nv[no] = 0 as u8 159 sw_put(prefix, nk, nv) 160 return 1 161} 162 163// ---- offers (give) + requests (ask) ---- 164func sw_offer_key(oid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:offer:" as *u8); o = as_append(out, o, oid); out[o] = 0 as u8; return o } 165func sw_ostatus_key(oid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:ostatus:" as *u8); o = as_append(out, o, oid); out[o] = 0 as u8; return o } 166// post an offer (I HAVE X to give). Implies you grow it -> adds X to your dex. status=open. 167func sw_post_offer(prefix: *u8, oid: *u8, gid: *u8, species: *u8, form: *u8, qty: i64, area: *u8, note: *u8) -> i64 { 168 let key: *u8 = sys_mmap(96); sw_offer_key(oid, key) 169 let val: *u8 = sys_mmap(384); var v: i64 = 0 170 v = as_append(val, v, gid); val[v] = 9 as u8; v = v + 1 171 v = as_append(val, v, species); val[v] = 9 as u8; v = v + 1 172 v = as_append(val, v, form); val[v] = 9 as u8; v = v + 1 173 v = fd_apnum(val, v, qty); val[v] = 9 as u8; v = v + 1 174 v = as_append(val, v, area); val[v] = 9 as u8; v = v + 1 175 v = as_append(val, v, note); val[v] = 0 as u8 176 sw_put(prefix, key, val) 177 let sk: *u8 = sys_mmap(96); sw_ostatus_key(oid, sk) 178 let pq: *i64 = sys_mmap(16) as *i64 179 let lq: *i64 = sys_mmap(16) as *i64 180 if ss_get(prefix, sk, pq, lq) != 1 { sw_put(prefix, sk, "open" as *u8) } 181 sw_list_append(prefix, "swap:offerids" as *u8, oid) 182 sw_dex_add(prefix, gid, species) 183 return 1 184} 185func sw_offer_field(prefix: *u8, oid: *u8, f: i64, out: *u8) -> i64 { 186 let key: *u8 = sys_mmap(96); sw_offer_key(oid, key) 187 let pq: *i64 = sys_mmap(16) as *i64 188 let lq: *i64 = sys_mmap(16) as *i64 189 if ss_get(prefix, key, pq, lq) != 1 { out[0] = 0 as u8; return 0 } 190 return fd_field(pq[0] as *u8, lq[0], f, out) 191} 192func sw_offer_open(prefix: *u8, oid: *u8) -> i64 { 193 let sk: *u8 = sys_mmap(96); sw_ostatus_key(oid, sk) 194 let pq: *i64 = sys_mmap(16) as *i64 195 let lq: *i64 = sys_mmap(16) as *i64 196 if ss_get(prefix, sk, pq, lq) != 1 { return 0 } 197 return fd_streq(pq[0] as *u8, "open" as *u8) 198} 199func sw_post_request(prefix: *u8, rid: *u8, gid: *u8, species: *u8, area: *u8) -> i64 { 200 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "swap:request:" as *u8); o = as_append(key, o, rid); key[o] = 0 as u8 201 let val: *u8 = sys_mmap(160); var v: i64 = 0 202 v = as_append(val, v, gid); val[v] = 9 as u8; v = v + 1 203 v = as_append(val, v, species); val[v] = 9 as u8; v = v + 1 204 v = as_append(val, v, area); val[v] = 0 as u8 205 sw_put(prefix, key, val) 206 sw_list_append(prefix, "swap:requestids" as *u8, rid) 207 return 1 208} 209 210// find OPEN offers of `species` in `area` (the local match: who near me can give me basil). Returns count. 211func sw_find_offers(prefix: *u8, species: *u8, area: *u8, outoids: *i64) -> i64 { 212 let pq: *i64 = sys_mmap(16) as *i64 213 let lq: *i64 = sys_mmap(16) as *i64 214 if ss_get(prefix, "swap:offerids" as *u8, pq, lq) != 1 { return 0 } 215 let ids: *i64 = sys_mmap(8 * 512) as *i64 216 let n: i64 = sw_split(pq[0] as *u8, lq[0], ids) 217 var c: i64 = 0 218 var i: i64 = 0 219 while i < n { 220 let oid: *u8 = ids[i] as *u8 221 let sp: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 1, sp) 222 let ar: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 4, ar) 223 if fd_streq(sp, species) == 1 { 224 if fd_streq(ar, area) == 1 { 225 if sw_offer_open(prefix, oid) == 1 { outoids[c] = oid as i64; c = c + 1 } 226 } 227 } 228 i = i + 1 229 } 230 return c 231} 232 233// THE SWAP: a taker claims an open offer = the gamified exchange. Marks claimed, adds the species to the taker's 234// dex (if new), awards XP to giver (gave) + taker (received, +bonus if new species). Returns 1 on success. 235func sw_claim_offer(prefix: *u8, oid: *u8, taker_gid: *u8) -> i64 { 236 if sw_offer_open(prefix, oid) == 0 { return 0 } 237 let giver: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 0, giver) 238 let species: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 1, species) 239 let sk: *u8 = sys_mmap(96); sw_ostatus_key(oid, sk) 240 sw_put(prefix, sk, "claimed" as *u8) 241 var newsp: i64 = 0 242 if sw_dex_has(prefix, taker_gid, species) == 0 { newsp = 1; sw_dex_add(prefix, taker_gid, species) } 243 sw_add_xp(prefix, giver, sw_cfg(prefix, 0)) // give 244 var recv: i64 = sw_cfg(prefix, 1) // receive 245 if newsp == 1 { recv = recv + sw_cfg(prefix, 2) } // + new-species bonus 246 sw_add_xp(prefix, taker_gid, recv) 247 return 1 248} 249 250// ---- sets + badges ("gotta grow 'em all") ---- 251// set record: swap:set:<setid> -> name <t> species1 <t> species2 ... 252func sw_add_set(prefix: *u8, setid: *u8, record: *u8) -> i64 { 253 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "swap:set:" as *u8); o = as_append(key, o, setid); key[o] = 0 as u8 254 return sw_put(prefix, key, record) 255} 256// 1 if the gardener's dex covers every species in the set. 257func sw_set_complete(prefix: *u8, gid: *u8, setid: *u8) -> i64 { 258 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "swap:set:" as *u8); o = as_append(key, o, setid); key[o] = 0 as u8 259 let pq: *i64 = sys_mmap(16) as *i64 260 let lq: *i64 = sys_mmap(16) as *i64 261 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 262 let rec: *u8 = pq[0] as *u8 263 let rl: i64 = lq[0] 264 var f: i64 = 1 265 var checked: i64 = 0 266 var go: i64 = 1 267 while go == 1 { 268 let fb: *u8 = sys_mmap(48) 269 let fl: i64 = fd_field(rec, rl, f, fb) 270 if fl == 0 { go = 0 } else { 271 if sw_dex_has(prefix, gid, fb) == 0 { return 0 } 272 checked = checked + 1 273 f = f + 1 274 } 275 } 276 if checked == 0 { return 0 } 277 return 1 278} 279func sw_badge_key(gid: *u8, setid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "swap:badge:" as *u8); o = as_append(out, o, gid); out[o] = 58 as u8; o = o + 1; o = as_append(out, o, setid); out[o] = 0 as u8; return o } 280func sw_has_badge(prefix: *u8, gid: *u8, setid: *u8) -> i64 { 281 let key: *u8 = sys_mmap(96); sw_badge_key(gid, setid, key) 282 let pq: *i64 = sys_mmap(16) as *i64 283 let lq: *i64 = sys_mmap(16) as *i64 284 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 285 return 1 286} 287// award the set badge if complete + not already held (gives the set-complete XP bonus). Returns 1 if newly awarded. 288func sw_award_badge(prefix: *u8, gid: *u8, setid: *u8) -> i64 { 289 if sw_set_complete(prefix, gid, setid) == 0 { return 0 } 290 if sw_has_badge(prefix, gid, setid) == 1 { return 0 } 291 let key: *u8 = sys_mmap(96); sw_badge_key(gid, setid, key) 292 sw_put(prefix, key, "1" as *u8) 293 sw_add_xp(prefix, gid, sw_cfg(prefix, 3)) 294 return 1 295} 296 297// count how many of a set's species the gardener has (for progress display). 298func sw_set_progress(prefix: *u8, gid: *u8, setid: *u8, total_out: *i64) -> i64 { 299 let key: *u8 = sys_mmap(96); var o: i64 = 0; o = as_append(key, o, "swap:set:" as *u8); o = as_append(key, o, setid); key[o] = 0 as u8 300 let pq: *i64 = sys_mmap(16) as *i64 301 let lq: *i64 = sys_mmap(16) as *i64 302 total_out[0] = 0 303 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 304 let rec: *u8 = pq[0] as *u8 305 let rl: i64 = lq[0] 306 var f: i64 = 1 307 var have: i64 = 0 308 var tot: i64 = 0 309 var go: i64 = 1 310 while go == 1 { 311 let fb: *u8 = sys_mmap(48) 312 let fl: i64 = fd_field(rec, rl, f, fb) 313 if fl == 0 { go = 0 } else { 314 tot = tot + 1 315 if sw_dex_has(prefix, gid, fb) == 1 { have = have + 1 } 316 f = f + 1 317 } 318 } 319 total_out[0] = tot 320 return have 321} 322 323// ---- the sovereign gamified BOARD (with an in-board contextual ad slot) ---- 324func sw_render_board(prefix: *u8, ads_prefix: *u8, area: *u8, gid: *u8, setid: *u8, out: *u8) -> i64 { 325 let nm: *u8 = sys_mmap(96); sw_g_field(prefix, gid, 0, nm) 326 var o: i64 = 0 327 o = as_append(out, o, "<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Nishi Garden Swap</title><style>body{margin:0;font-family:system-ui,sans-serif;color:#15301c;background:#eef6ea;line-height:1.5}header{background:#2f7d3a;color:#fff;padding:20px}header h1{margin:0;font-size:1.4rem}header p{margin:4px 0 0;color:#d7efce}main{max-width:680px;margin:0 auto;padding:16px}section{background:#fff;border-radius:14px;padding:16px 18px;margin-top:16px;box-shadow:0 1px 0 #dcebd3}h2{font-size:1.1rem;margin:0 0 10px;color:#2f7d3a}.lvl{display:inline-block;background:#2f7d3a;color:#fff;border-radius:20px;padding:3px 12px;font-weight:800}.bar{height:12px;background:#e3eedd;border-radius:6px;overflow:hidden;margin-top:6px}.bar > i{display:block;height:100%;background:#7cc15a}ul{list-style:none;padding:0;margin:0}li{padding:8px 0;border-bottom:1px solid #eef3ea}.give{color:#2f7d3a;font-weight:700}.adslot{background:#fbfdf8;border:1px dashed #b9d6a6;border-radius:10px;padding:12px 14px;margin-top:16px}.adlabel{display:inline-block;background:#e3eedd;color:#496b3a;font-size:.72rem;text-transform:uppercase;letter-spacing:.05em;padding:2px 8px;border-radius:6px;margin-bottom:6px}.adslot b{display:block}.adslot small{color:#5b6a52}.muted{color:#5b6a52;font-size:.88rem}</style></head><body><header><h1>Nishi Garden Swap</h1><p>Ask &amp; give plants with neighbours &mdash; grow your collection instead of buying.</p></header><main>" as *u8) 328 329 // player card 330 o = as_append(out, o, "<section><h2>Your garden</h2><p><span class='lvl'>Level " as *u8) 331 o = fd_apnum(out, o, sw_level(prefix, gid)) 332 o = as_append(out, o, "</span> &mdash; " as *u8) 333 o = as_append_escaped(out, o, nm, as_len(nm)) 334 o = as_append(out, o, "</p><p>" as *u8) 335 o = fd_apnum(out, o, sw_xp(prefix, gid)) 336 o = as_append(out, o, " XP &middot; " as *u8) 337 o = fd_apnum(out, o, sw_dex_count(prefix, gid)) 338 o = as_append(out, o, " species collected</p>" as *u8) 339 // set progress 340 let tot: *i64 = sys_mmap(16) as *i64 341 let have: i64 = sw_set_progress(prefix, gid, setid, tot) 342 o = as_append(out, o, "<p class='muted'>Set progress: " as *u8); o = fd_apnum(out, o, have); o = as_append(out, o, " / " as *u8); o = fd_apnum(out, o, tot[0]) 343 if sw_has_badge(prefix, gid, setid) == 1 { o = as_append(out, o, " &mdash; badge earned!" as *u8) } 344 o = as_append(out, o, "</p><div class='bar'><i style='width:" as *u8) 345 var pct: i64 = 0 346 if tot[0] > 0 { pct = have * 100 / tot[0] } 347 o = fd_apnum(out, o, pct) 348 o = as_append(out, o, "%'></i></div></section>" as *u8) 349 350 // swaps near you 351 o = as_append(out, o, "<section><h2>Swaps near you (" as *u8) 352 o = as_append_escaped(out, o, area, as_len(area)) 353 o = as_append(out, o, ")</h2><ul>" as *u8) 354 let pq: *i64 = sys_mmap(16) as *i64 355 let lq: *i64 = sys_mmap(16) as *i64 356 if ss_get(prefix, "swap:offerids" as *u8, pq, lq) == 1 { 357 let ids: *i64 = sys_mmap(8 * 512) as *i64 358 let n: i64 = sw_split(pq[0] as *u8, lq[0], ids) 359 var i: i64 = 0 360 while i < n { 361 let oid: *u8 = ids[i] as *u8 362 let ar: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 4, ar) 363 if fd_streq(ar, area) == 1 { 364 if sw_offer_open(prefix, oid) == 1 { 365 let og: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 0, og) 366 let sp: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 1, sp) 367 let fm: *u8 = sys_mmap(48); sw_offer_field(prefix, oid, 2, fm) 368 let ognm: *u8 = sys_mmap(96); sw_g_field(prefix, og, 0, ognm) 369 o = as_append(out, o, "<li><span class='give'>" as *u8) 370 o = as_append_escaped(out, o, sp, as_len(sp)) 371 o = as_append(out, o, "</span> (" as *u8) 372 o = as_append_escaped(out, o, fm, as_len(fm)) 373 o = as_append(out, o, ") &mdash; from " as *u8) 374 o = as_append_escaped(out, o, ognm, as_len(ognm)) 375 o = as_append(out, o, "</li>" as *u8) 376 } 377 } 378 i = i + 1 379 } 380 } 381 o = as_append(out, o, "</ul></section>" as *u8) 382 383 // sovereign contextual ad slot (context = herbs; selected by topic, not by viewer) 384 o = ads_render_slot(ads_prefix, "herbs" as *u8, out, o) 385 386 o = as_append(out, o, "<p class='muted'>A gift economy &mdash; no money, just neighbours sharing. Our own game, our own plants; no third-party characters or licensing.</p></main></body></html>" as *u8) 387 out[o] = 0 as u8 388 return o 389}