diff --git a/crystal.cpp b/crystal.cpp index b5d2908c..d4c1e737 100644 --- a/crystal.cpp +++ b/crystal.cpp @@ -281,7 +281,7 @@ coord add(coord c, int cname, int val) { return c; } -ld hypot2(crystal_structure& cs, ldcoord co1, ldcoord co2) { +ld sqhypot2(crystal_structure& cs, ldcoord co1, ldcoord co2) { int result = 0; for(int a=0; a> distmemo; map sgc; cell *camelot_center; + ldcoord camelot_coord; + ld camelot_mul; crystal_structure cs; east_structure east; @@ -321,6 +323,7 @@ struct hrmap_crystal : hrmap { hrmap_crystal() { cs.build(); + camelot_center = NULL; } ~hrmap_crystal() { @@ -536,7 +539,12 @@ ld space_distance(cell *c1, cell *c2) { auto m = crystal_map(); ldcoord co1 = m->get_coord(c1); ldcoord co2 = m->get_coord(c2); - return sqrt(hypot2(m->cs, co1, co2)); + return sqrt(sqhypot2(m->cs, co1, co2)); + } + +ld space_distance_camelot(cell *c) { + auto m = crystal_map(); + return m->camelot_mul * sqrt(sqhypot2(m->cs, m->get_coord(c), m->camelot_coord)); } int dist_relative(cell *c) { @@ -549,18 +557,23 @@ int dist_relative(cell *c) { cc = start; while(precise_distance(cc, start) < r + 5) cc = cc->cmove(hrand(cc->type)); + + m->camelot_coord = m->get_coord(m->camelot_center); + if(m->cs.dir % 2) + m->camelot_coord[m->cs.dim-1] = 2; + + m->camelot_mul = 1; + m->camelot_mul *= (r+5) / space_distance_camelot(start); } if(pure()) return precise_distance(c, cc) - r; - ld sdmul = (r+5) / space_distance(cc, start); - ld dis = space_distance(cc, c) * sdmul; - println(hlog, "dis = ", dis); + ld dis = space_distance_camelot(c); if(dis < r) return int(dis) - r; else { - forCellCM(c1, c) if(space_distance(cc, c1) * sdmul < r) + forCellCM(c1, c) if(space_distance_camelot(c1) < r) return 0; return int(dis) + 1 - r; } @@ -663,7 +676,7 @@ int dist_alt(cell *c) { if(pure()) return precise_distance(c, m->camelot_center); if(c == m->camelot_center) return 0; - return 1 + int(4 * space_distance(m->camelot_center, c)); + return 1 + int(2 * space_distance_camelot(c)); } else { m->prepare_east(); @@ -877,6 +890,110 @@ void show() { auto crystalhook = addHook(hooks_args, 100, readArgs) + addHook(hooks_drawcell, 100, crystal_cell); +map, bignum> volume_memo; + +bignum& compute_volume(int dim, int rad) { + auto p = make_pair(dim, rad); + int is = volume_memo.count(p); + auto& m = volume_memo[p]; + if(is) return m; + if(dim == 0) { m = 1; return m; } + m = compute_volume(dim-1, rad); + for(int r=0; r children; + map result; + + shift_data() { parent = NULL; } + + bignum& compute(ld rad2) { + if(result.count(rad2)) return result[rad2]; + // println(hlog, "compute ", format("%p", this), " [shift=", shift, "], r2 = ", rad2); + // indenter i(2); + auto& b = result[rad2]; + if(!parent) { + if(rad2 >= 0) b = 1; + } + else if(rad2 >= 0) { + for(int x = -2-sqrt(rad2); x <= sqrt(rad2)+2; x++) { + ld ax = x - shift; + if(ax*ax <= rad2) + b.addmul(parent->compute(rad2 - (ax*ax)), 1); + } + } + // println(hlog, "result = ", b.get_str(100)); + return b; + } + }; + +shift_data shift_data_zero; + +string get_table_volume() { + if(!pure()) { + auto m = crystal_map(); + m->prepare_east(); + bignum res; + manual_celllister cl; + cl.add(m->gamestart()); + ld rad2 = pow(roundTableRadius(NULL) / m->camelot_mul / 4, 2) + 1e-4; + for(int i=0; iget_coord(c); + for(int i=0; ics.dim; i++) { + if(co[i] < mincoord) mincoord = co[i]; + if(co[i] > maxcoord) maxcoord = co[i]; + } + static const ld eps = 1e-4; + if(mincoord >= 0-eps && maxcoord < 4-eps) { + auto cshift = (co - m->camelot_coord) / 4; + auto sd = &shift_data_zero; + for(int i=0; ics.dim; i++) { + ld val = cshift[i] - floor(cshift[i]); + if(!sd->children.count(val)) { + sd->children[val].parent = sd; + sd->children[val].shift = val; + } + sd = &sd->children[val]; + } + res.addmul(sd->compute(rad2), 1); + } + if(mincoord < -2 || maxcoord > 6) continue; + forCellCM(c2, c) cl.add(c2); + } + return res.get_str(100); + } + int s = ginf[gCrystal].sides; + int r = roundTableRadius(NULL); + if(s % 2 == 0) + return compute_volume(s/2, r-1).get_str(100); + else + return (compute_volume(s/2, r-1) + compute_volume(s/2, r-2)).get_str(100); + } + +string get_table_boundary() { + if(!pure()) return ""; + int r = roundTableRadius(NULL); + int s = ginf[gCrystal].sides; + if(s % 2 == 0) + return (compute_volume(s/2, r) - compute_volume(s/2, r-1)).get_str(100); + else + return (compute_volume(s/2, r) - compute_volume(s/2, r-2)).get_str(100); + } + } } diff --git a/game.cpp b/game.cpp index 9ea14b45..ccd08f0f 100644 --- a/game.cpp +++ b/game.cpp @@ -6936,6 +6936,15 @@ void roundTableMessage(cell *c2) { } } +bool in_full_game() { + if(chaosmode) return true; + if(geometry == gEuclid && isCrossroads(specialland)) return true; + if(weirdhyperbolic && specialland == laCrossroads4) return true; + if(geometry == gCrystal && specialland == laCrossroads) return true; + if(geometry == gNormal && !NONSTDVAR) return true; + return false; + } + void knightFlavorMessage(cell *c2) { if(!eubinary && !c2->master->alt) { @@ -6966,37 +6975,55 @@ void knightFlavorMessage(cell *c2) { else if(msgid == 2 && !tooeasy) { addMessage(XLAT("\"The Holy Grail is in the center of the Round Table.\"")); } - else if(msgid == 3 && !peace::on) { + else if(msgid == 3 && geometry == gCrystal) { + if(crystal::pure()) + addMessage(XLAT("\"Each piece of the Round Table is exactly %1 steps away from the Holy Grail.\"", its(roundTableRadius(c2)))); + else + addMessage(XLAT("\"According to Merlin, the Round Table is a perfect Euclidean sphere in %1 dimensions.\"", its(ginf[gCrystal].sides/2))); + } + else if(msgid == 3 && !peace::on && in_full_game()) { addMessage(XLAT("\"I enjoy watching the hyperbug battles.\"")); } - else if(msgid == 4) { + else if(msgid == 4 && in_full_game()) { addMessage(XLAT("\"Have you visited a temple in R'Lyeh?\"")); } - else if(msgid == 5) { + else if(msgid == 5 && in_full_game()) { addMessage(XLAT("\"Nice castle, eh?\"")); } - else if(msgid == 6 && items[itSpice] < 10 && !peace::on) { + else if(msgid == 6 && items[itSpice] < 10 && !peace::on && in_full_game()) { addMessage(XLAT("\"The Red Rock Valley is dangerous, but beautiful.\"")); } - else if(msgid == 7 && items[itSpice] < 10 && !peace::on) { + else if(msgid == 7 && items[itSpice] < 10 && !peace::on && in_full_game()) { addMessage(XLAT("\"Train in the Desert first!\"")); } else if(msgid == 8 && sizes_known() && !tactic::on) { - addMessage(XLAT("\"Our Table seats %1 Knights!\"", expansion.get_descendants(rad).get_str(100))); + string s = ""; + if(geometry == gCrystal) + s = crystal::get_table_boundary(); + else if(!quotient) + s = expansion.get_descendants(rad).get_str(100); + if(s == "") { msgid++; goto retry; } + addMessage(XLAT("\"Our Table seats %1 Knights!\"", s)); } else if(msgid == 9 && sizes_known() && !tactic::on) { - addMessage(XLAT("\"There are %1 floor tiles inside our Table!\"", expansion.get_descendants(rad-1, expansion.diskid).get_str(100))); + string s = ""; + if(geometry == gCrystal) + s = crystal::get_table_volume(); + else if(!quotient) + s = expansion.get_descendants(rad-1, expansion.diskid).get_str(100); + if(s == "") { msgid++; goto retry; } + addMessage(XLAT("\"There are %1 floor tiles inside our Table!\"", s)); } - else if(msgid == 10 && !items[itPirate] && !items[itWhirlpool] && !peace::on) { + else if(msgid == 10 && !items[itPirate] && !items[itWhirlpool] && !peace::on && in_full_game()) { addMessage(XLAT("\"Have you tried to take a boat and go into the Ocean? Try it!\"")); } - else if(msgid == 11 && !princess::saved) { + else if(msgid == 11 && !princess::saved && in_full_game()) { addMessage(XLAT("\"When I visited the Palace, a mouse wanted me to go somewhere.\"")); } - else if(msgid == 12 && !princess::saved) { + else if(msgid == 12 && !princess::saved && in_full_game()) { addMessage(XLAT("\"I wonder what was there...\"")); } - else if(msgid == 13 && !peace::on) { + else if(msgid == 13 && !peace::on && in_full_game()) { addMessage(XLAT("\"Be careful in the Rose Garden! It is beautiful, but very dangerous!\"")); } else if(msgid == 14) { diff --git a/hyper.h b/hyper.h index 5e81f48d..32464922 100644 --- a/hyper.h +++ b/hyper.h @@ -4156,6 +4156,9 @@ namespace crystal { int dist_relative(cell *c); void show(); void init_rotation(); + string get_table_volume(); + string get_table_boundary(); + bool pure(); } hyperpoint get_warp_corner(cell *c, int cid); @@ -4431,6 +4434,9 @@ struct bignum { if(isize(digits) == 1) return digits[0]; return digits[0] + digits[1] * (long long) BASE; } + + friend inline bignum operator +(bignum a, const bignum& b) { a.addmul(b, 1); return a; } + friend inline bignum operator -(bignum a, const bignum& b) { a.addmul(b, -1); return a; } }; struct expansion_analyzer {