mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-22 23:17:04 +00:00
merge
This commit is contained in:
commit
6c61162392
@ -26,7 +26,7 @@ language-data.cpp: langen
|
||||
./langen > language-data.cpp
|
||||
|
||||
autohdr.h: makeh language-data.cpp *.cpp
|
||||
./makeh classes.cpp locations.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp *.cpp > autohdr.h
|
||||
./makeh classes.cpp locations.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp util.cpp complex.cpp *.cpp > autohdr.h
|
||||
|
||||
#############################
|
||||
# Platform specific setup
|
||||
|
@ -159,7 +159,7 @@ makeh$(EXE_EXTENSION): makeh.cpp
|
||||
$(CXX) makeh.cpp -o $@
|
||||
|
||||
autohdr.h: makeh$(EXE_EXTENSION) *.cpp
|
||||
./makeh classes.cpp locations.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp complex.cpp *.cpp > autohdr.h
|
||||
./makeh classes.cpp locations.cpp hyperpoint.cpp geometry.cpp goldberg.cpp init.cpp floorshapes.cpp cell.cpp multi.cpp shmup.cpp pattern2.cpp mapeditor.cpp graph.cpp textures.cpp hprint.cpp language.cpp util.cpp complex.cpp *.cpp > autohdr.h
|
||||
|
||||
language-data.cpp: langen$(EXE_EXTENSION)
|
||||
./langen > language-data.cpp
|
||||
|
41
attack.cpp
41
attack.cpp
@ -216,7 +216,7 @@ EX void killIvy(cell *c, eMonster who) {
|
||||
c->monst = moIvyDead; // NEWYEARFIX
|
||||
for(int i=0; i<c->type; i++) if(c->move(i))
|
||||
if(isIvy(c->move(i)) && c->move(i)->mondir == c->c.spin(i))
|
||||
killIvy(c->move(i), who);
|
||||
killIvy(c->move(i), who), kills[moIvyDead]++;
|
||||
}
|
||||
|
||||
EX void prespill(cell* c, eWall t, int rad, cell *from) {
|
||||
@ -293,14 +293,14 @@ EX void prespill(cell* c, eWall t, int rad, cell *from) {
|
||||
// block spill
|
||||
if(t == waTemporary) return;
|
||||
// cwt.at->item = itNone;
|
||||
if(rad) for(int i=0; i<c->type; i++) if(c->move(i))
|
||||
prespill(c->move(i), t, rad-1, c);
|
||||
if(rad) for(cell *c2: adj_minefield_cells(c))
|
||||
prespill(c2, t, rad-1, c);
|
||||
}
|
||||
|
||||
EX void spillfix(cell* c, eWall t, int rad) {
|
||||
if(c->wall == waTemporary) c->wall = t;
|
||||
if(rad) for(int i=0; i<c->type; i++) if(c->move(i))
|
||||
spillfix(c->move(i), t, rad-1);
|
||||
if(rad) for(cell *c2: adj_minefield_cells(c))
|
||||
spillfix(c2, t, rad-1);
|
||||
}
|
||||
|
||||
EX void spill(cell* c, eWall t, int rad) {
|
||||
@ -391,7 +391,14 @@ EX void killMutantIvy(cell *c, eMonster who) {
|
||||
removeIvy(c);
|
||||
for(int i=0; i<c->type; i++)
|
||||
if(c->move(i)->mondir == c->c.spin(i) && (isMutantIvy(c->move(i)) || c->move(i)->monst == moFriendlyIvy))
|
||||
killMutantIvy(c->move(i), who);
|
||||
kills[c->move(i)->monst]++, killMutantIvy(c->move(i), who);
|
||||
if(c->land == laClearing) clearing::imput(c);
|
||||
}
|
||||
|
||||
EX bignum ivy_total() {
|
||||
return kills[moMutant] + kills[moFriendlyIvy] +
|
||||
kills[moIvyRoot] + kills[moIvyHead] + kills[moIvyBranch] + kills[moIvyWait] + kills[moIvyDead]
|
||||
+ clearing::imputed;
|
||||
}
|
||||
|
||||
EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
|
||||
@ -441,7 +448,7 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
|
||||
if(m == moHunterGuard) m = moHunterDog;
|
||||
if(m == moHunterChanging) m = moHunterDog;
|
||||
if(m == moWolfMoved) m = moWolf;
|
||||
if(!isBulletType(m)) kills[m]++;
|
||||
if(!isBulletType(m) && m != moIvyDead) kills[m]++;
|
||||
|
||||
if(saved_tortoise_on(c)) c->item = itNone;
|
||||
|
||||
@ -462,7 +469,12 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
|
||||
|
||||
if(isMutantIvy(m) || m == moFriendlyIvy) {
|
||||
pcount = 0;
|
||||
if(isMutantIvy(m)) clearing::direct++;
|
||||
bignum s = ivy_total() - 1;
|
||||
killMutantIvy(c, who);
|
||||
s = ivy_total() - s;
|
||||
if(vid.bubbles_special && s > bignum(1))
|
||||
drawBubble(c, 0xFFFF00, s.get_str(100), .5);
|
||||
}
|
||||
|
||||
if(m == moPrincess) {
|
||||
@ -680,12 +692,27 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
|
||||
}
|
||||
if(m == moLesser && !(kills[m] % 10))
|
||||
degradeDemons();
|
||||
if(m == moLesser) {
|
||||
if(kills[m] % 10) {
|
||||
if(vid.bubbles_special)
|
||||
drawBubble(c, 0xFF0000, its(kills[m]%10), 1);
|
||||
}
|
||||
else {
|
||||
if(vid.bubbles_special)
|
||||
drawBubble(c, 0xFF8000, "+1 XP", .8);
|
||||
degradeDemons();
|
||||
}
|
||||
}
|
||||
if(isIvy(c)) {
|
||||
pcount = 0;
|
||||
eMonster m = c->monst;
|
||||
bignum s = ivy_total() - 1;
|
||||
/*if((m == moIvyBranch || m == moIvyHead) && c->move(c->mondir)->monst == moIvyRoot)
|
||||
ivynext(c, moIvyNext); */
|
||||
killIvy(c, who);
|
||||
s = ivy_total() - s;
|
||||
if(s > bignum(1) && vid.bubbles_special)
|
||||
drawBubble(c, 0xFFFF00, s.get_str(100), .5);
|
||||
if(m == moIvyBranch || m == moIvyHead || m == moIvyNext) {
|
||||
int qty = 0;
|
||||
cell *c2 = c->move(c->mondir);
|
||||
|
@ -1782,7 +1782,7 @@ EX void moreBigStuff(cell *c) {
|
||||
c->land = laClearing, c->wall = waNone; // , c->monst = moNone, c->item = itNone;
|
||||
}
|
||||
else if(d == 1 && !tactic::on && !eubinary)
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone;
|
||||
c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2242,9 +2242,20 @@ void celldrawer::add_map_effects() {
|
||||
int tim = ticks - lightat;
|
||||
if(tim > 1000) tim = 800;
|
||||
if(elec::havecharge && tim > 400) tim = 400;
|
||||
for(int t=0; t<c->type; t++) if(c->move(t) && c->move(t)->ligon) {
|
||||
int lcol = darkena(gradient(iinf[itOrbLightning].color, 0, 0, tim, 1100), 0, 0xFF);
|
||||
queueline(V*chei(xspinpush(ticks * M_PI / cgi.S42, cgi.hexf/2), rand() % 1000, 1000) * C0, V*chei(currentmap->adj(c, t), rand() % 1000, 1000) * C0, lcol, 2 + vid.linequality);
|
||||
for(int t=0; t<c->type; t++) if(c->move(t)) {
|
||||
if(c->move(t)->ligon) {
|
||||
int lcol = darkena(gradient(iinf[itOrbLightning].color, 0, 0, tim, 1100), 0, 0xFF);
|
||||
queueline(V*chei(xspinpush(ticks * M_PI / cgi.S42, cgi.hexf/2), rand() % 1000, 1000) * C0, V*chei(currentmap->adj(c, t), rand() % 1000, 1000) * C0, lcol, 2 + vid.linequality);
|
||||
}
|
||||
for(int u: {-1, 1}) {
|
||||
cellwalker cw = cellwalker(c, t) + wstep + u;
|
||||
if(u == -1 && VALENCE == 4) continue;
|
||||
cell *c2 = cw.peek();
|
||||
if(c2 && c2->ligon) {
|
||||
int lcol = darkena(gradient(iinf[itOrbLightning].color, 0, 0, tim, 1100), 0, 0xFF);
|
||||
queueline(V*chei(xspinpush(ticks * M_PI / cgi.S42, cgi.hexf/2), rand() % 1000, 1000) * C0, V*chei(currentmap->adj(c, t)*currentmap->adj(cw.at, cw.spin), rand() % 1000, 1000) * C0, lcol, 2 + vid.linequality);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -722,7 +722,7 @@ enum eGeometry {
|
||||
gBinary4, gSol,
|
||||
gKiteDart2, gKiteDart3, gNil, gProduct, gRotSpace,
|
||||
gTernary, gNIH, gSolN, gInfOrder, gSpace336, gSpace344, gCrystal344,
|
||||
gArnoldCat, gArbitrary,
|
||||
gArnoldCat, gArbitrary, gInfOrder4,
|
||||
gGUARD};
|
||||
|
||||
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSolNIH, gcNil, gcProduct, gcSL2 };
|
||||
@ -887,6 +887,7 @@ EX vector<geometryinfo> ginf = {
|
||||
{"{3,4,4}","Crystal", "4D crystal in H3", "Cryst3" , 8, 4, qIDEAL | qANYQ | qCRYSTAL, giHyperb3, 0x52000, {{7, 3}}, eVariation::pure},
|
||||
{"cat", "cat", "Arnold's cat mapping torus", "cat", 12, 3, qBINARY | qSOL | qsBQ | qOPTQ, giSolNIH, 0x52200, {{6, 4}}, eVariation::pure},
|
||||
{"arb", "arb", "arbitrary", "arb", 7, 3, qEXPERIMENTAL, giEuclid2, 0, {{7, 5}}, eVariation::pure},
|
||||
{"{4,oo}", "none", "{4,∞} (infinite squares)", "oox4", 4, 100, qIDEAL, giHyperb2, 0x49400, {{5, 5}}, eVariation::pure},
|
||||
};
|
||||
// bits: 9, 10, 15, 16, (reserved for later) 17, 18
|
||||
|
||||
|
55
complex.cpp
55
complex.cpp
@ -306,9 +306,7 @@ EX namespace elec {
|
||||
if(from != 1) charges[id].lowlink = 1;
|
||||
}
|
||||
|
||||
for(int i=0; i<c->type; i++) {
|
||||
cell *c2 = c->move(i);
|
||||
if(!c2) continue;
|
||||
for(cell *c2: adj_minefield_cells(c)) {
|
||||
if(c2->listindex == from) continue;
|
||||
eCharge ct = getCharge(c2);
|
||||
if(conduct(chh, ct))
|
||||
@ -956,6 +954,46 @@ EX namespace clearing {
|
||||
steps--; ds++;
|
||||
}
|
||||
}
|
||||
|
||||
typedef tuple<int, int, int, int> celltype;
|
||||
|
||||
map<celltype, pair<bignum, int> > stats;
|
||||
|
||||
EX bignum imputed;
|
||||
EX int direct;
|
||||
|
||||
map<cell*, pair<bignum, int> > score;
|
||||
|
||||
celltype get_celltype(cell *c) {
|
||||
cell *c1 = c;
|
||||
if(c->mondir < c->type)
|
||||
c1 = c->move(c->mondir);
|
||||
return make_tuple(
|
||||
celldistAlt(c), type_in(expansion, c, celldistAlt),
|
||||
celldistAlt(c1), type_in(expansion, c1, celldistAlt)
|
||||
);
|
||||
}
|
||||
|
||||
EX void imput(cell *c) {
|
||||
if(bounded) return;
|
||||
if(score.count(c)) return;
|
||||
auto& is = score[c];
|
||||
celltype t = get_celltype(c);
|
||||
auto& stat = stats[t];
|
||||
is.second = c->mondir;
|
||||
if(c->mpdist <= 6) {
|
||||
is.first = 1;
|
||||
forCellEx(c2, c) if(score.count(c2) && c2->move(score[c2].second) == c)
|
||||
is.first += score[c2].first;
|
||||
stat.first += is.first;
|
||||
stat.second++;
|
||||
}
|
||||
else {
|
||||
is.first = stat.second ? stat.first.randomized_div(stat.second) : bignum(1);
|
||||
imputed += is.first;
|
||||
}
|
||||
}
|
||||
|
||||
EX }
|
||||
|
||||
EX namespace whirlpool {
|
||||
@ -2047,14 +2085,16 @@ EX namespace heat {
|
||||
if(isFire(c)) hmod += 4 * xrate;
|
||||
if(isPrincess(c->monst)) hmod += (markEmpathy(itOrbWinter) ? -1.2 : 1.2) * xrate;
|
||||
|
||||
forCellEx(ct, c) {
|
||||
auto ls = adj_minefield_cells(c);
|
||||
|
||||
for(cell* ct: ls) {
|
||||
if(!isIcyLand(ct) && isFire(ct))
|
||||
hmod += xrate*.1;
|
||||
if(ct->land == laVolcano)
|
||||
hmod += xrate * (ct->wall == waMagma ? .4 : .2);
|
||||
}
|
||||
|
||||
forCellEx(ct, c) {
|
||||
for(cell* ct: ls) {
|
||||
if(!isIcyLand(ct)) {
|
||||
// make sure that we can still enter Cocytus,
|
||||
// it won't heat up right away even without Orb of Winter or Orb of Speed
|
||||
@ -2139,7 +2179,8 @@ EX namespace heat {
|
||||
|
||||
cell *last = c->move(c->type-1);
|
||||
|
||||
forCellEx(c2, c) {
|
||||
auto ls = adj_minefield_cells(c);
|
||||
for(cell* c2: ls) {
|
||||
|
||||
if(c->wall == waPartialFire) {
|
||||
// two partial fires adjacent are necessary to spread
|
||||
@ -2260,7 +2301,7 @@ EX void livecaves() {
|
||||
hv = 0;
|
||||
if(c->monst == moDarkTroll) c->monst = moTroll;
|
||||
if(c->item || c->monst || c->cpdist == 0) continue;
|
||||
forCellEx(c2, c) {
|
||||
for(cell *c2: adj_minefield_cells(c)) {
|
||||
eWall w = c2->wall;
|
||||
if(w == waDeadfloor) hv++, bringlife.push_back(c2);
|
||||
else if(w == waDeadwall || (w == waDeadfloor2 && !c2->monst))
|
||||
|
25
config.cpp
25
config.cpp
@ -618,6 +618,10 @@ EX void initConfig() {
|
||||
|
||||
addsaver(s2xe::qrings, "s2xe-rings");
|
||||
addsaver(rots::underlying_scale, "rots-underlying-scale");
|
||||
|
||||
addsaver(vid.bubbles_special, "bubbles-special", 1);
|
||||
addsaver(vid.bubbles_threshold, "bubbles-special", 1);
|
||||
addsaver(vid.bubbles_all, "bubbles-special", 0);
|
||||
|
||||
#if CAP_SHMUP
|
||||
multi::initConfig();
|
||||
@ -996,6 +1000,22 @@ EX void menuitem_sightrange(char c IS('c')) {
|
||||
dialog::add_action(edit_sightrange);
|
||||
}
|
||||
|
||||
EX void showSpecialEffects() {
|
||||
cmode = vid.xres > vid.yres * 1.4 ? sm::SIDE : sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
dialog::init(XLAT("extra graphical effects"));
|
||||
|
||||
dialog::addBoolItem_action(XLAT("particles on attack"), (vid.particles), 'p');
|
||||
dialog::addBoolItem_action(XLAT("floating bubbles: special"), vid.bubbles_special, 's');
|
||||
dialog::addBoolItem_action(XLAT("floating bubbles: treasure thresholds"), vid.bubbles_threshold, 't');
|
||||
dialog::addBoolItem_action(XLAT("floating bubbles: all treasures"), vid.bubbles_all, 'a');
|
||||
dialog::addBoolItem_action(XLAT("background particle effects"), (vid.backeffects), 'b');
|
||||
|
||||
dialog::addBreak(50);
|
||||
dialog::addBack();
|
||||
dialog::display();
|
||||
}
|
||||
|
||||
EX void showGraphConfig() {
|
||||
cmode = vid.xres > vid.yres * 1.4 ? sm::SIDE : sm::MAYDARK;
|
||||
gamescreen(0);
|
||||
@ -1039,8 +1059,7 @@ EX void showGraphConfig() {
|
||||
|
||||
dialog::addSelItem(XLAT("movement animation speed"), fts(vid.mspeed), 'm');
|
||||
|
||||
dialog::addBoolItem(XLAT("extra graphical effects"), (vid.particles), 'u');
|
||||
dialog::addBoolItem(XLAT("background particle effects"), (vid.backeffects), 'p');
|
||||
dialog::addItem(XLAT("extra graphical effects"), 'u');
|
||||
|
||||
dialog::addBreak(50);
|
||||
dialog::addBack();
|
||||
@ -1055,7 +1074,7 @@ EX void showGraphConfig() {
|
||||
|
||||
if((uni >= 32 && uni < 64) || uni == 'L' || uni == 'C') xuni = uni;
|
||||
|
||||
if(xuni == 'u') vid.particles = !vid.particles;
|
||||
if(xuni == 'u') pushScreen(showSpecialEffects);
|
||||
|
||||
else if(xuni == 'a') dialog::editNumber(vid.sspeed, -5, 5, 1, 0,
|
||||
XLAT("scrolling speed"),
|
||||
|
18
control.cpp
18
control.cpp
@ -1027,7 +1027,23 @@ EX bool gmodekeys(int sym, int uni) {
|
||||
if(NUMBERKEY == '7') { vid.darkhepta = !vid.darkhepta; return true; }
|
||||
|
||||
if(GDIM == 2) {
|
||||
if(NUMBERKEY == '1' && !rug::rugged) { vid.alpha = 999; vid.scale = 998; vid.xposition = vid.yposition = 0; }
|
||||
if(among(NUMBERKEY, '1', '2', '3') && !rug::rugged && euclid && WDIM == 2) {
|
||||
vid.xposition = vid.yposition = 0;
|
||||
ld maxs = 0;
|
||||
auto& cd = current_display;
|
||||
for(auto& p: gmatrix) for(int i=0; i<p.first->type; i++) {
|
||||
hyperpoint h = tC0(p.second * currentmap->adj(p.first, i));
|
||||
hyperpoint onscreen;
|
||||
applymodel(h, onscreen);
|
||||
maxs = max(maxs, onscreen[0] / cd->xsize);
|
||||
maxs = max(maxs, onscreen[1] / cd->ysize);
|
||||
}
|
||||
vid.alpha = 1;
|
||||
vid.scale = vid.scale / 2 / maxs / cd->radius;
|
||||
if(NUMBERKEY == '3') vid.scale *= 2;
|
||||
if(NUMBERKEY == '1') vid.scale /= 2;
|
||||
}
|
||||
else if(NUMBERKEY == '1' && !rug::rugged) { vid.alpha = 999; vid.scale = 998; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '2' && !rug::rugged) { vid.alpha = 1; vid.scale = 0.4; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '3' && !rug::rugged) { vid.alpha = 1; vid.scale = 1; vid.xposition = vid.yposition = 0; }
|
||||
else if(NUMBERKEY == '4' && !rug::rugged) { vid.alpha = 0; vid.scale = 1; vid.xposition = vid.yposition = 0; }
|
||||
|
@ -348,6 +348,7 @@ EX void bfs() {
|
||||
if(c2->land == laWhirlwind) havewhat |= HF_WHIRLWIND;
|
||||
if(c2->land == laWestWall) havewhat |= HF_WESTWALL;
|
||||
if(c2->land == laPrairie) havewhat |= HF_RIVER;
|
||||
if(c2->land == laClearing) havewhat |= HF_MUTANT;
|
||||
|
||||
if(c2->wall == waRose) havewhat |= HF_ROSE;
|
||||
|
||||
|
158
expansion.cpp
158
expansion.cpp
@ -15,164 +15,6 @@ int subtype(cell *c) {
|
||||
return patterns::getpatterninfo(c, patterns::PAT_NONE, 0).id;
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct bignum {
|
||||
static const int BASE = 1000000000;
|
||||
static const long long BASE2 = BASE * (long long)BASE;
|
||||
vector<int> digits;
|
||||
bignum() {}
|
||||
bignum(int i) : digits() { digits.push_back(i); }
|
||||
void be(int i) { digits.resize(1); digits[0] = i; }
|
||||
bignum& operator +=(const bignum& b);
|
||||
void addmul(const bignum& b, int factor);
|
||||
string get_str(int max_length);
|
||||
|
||||
bool operator < (const bignum&) const;
|
||||
|
||||
ld leading() const {
|
||||
switch(isize(digits)) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return digits.back();
|
||||
default:
|
||||
return digits.back() + ld(digits[isize(digits)-2]) / BASE;
|
||||
}
|
||||
}
|
||||
|
||||
ld approx() const {
|
||||
return leading() * pow(BASE, isize(digits) - 1);
|
||||
}
|
||||
|
||||
ld log_approx() const {
|
||||
return log(leading()) * log(BASE) * (isize(digits) - 1);
|
||||
}
|
||||
|
||||
ld operator / (const bignum& b) const {
|
||||
return leading() / b.leading() * pow(BASE, isize(digits) - isize(b.digits));
|
||||
}
|
||||
|
||||
int approx_int() const {
|
||||
if(isize(digits) > 1) return BASE;
|
||||
if(digits.empty()) return 0;
|
||||
return digits[0];
|
||||
}
|
||||
|
||||
long long approx_ll() const {
|
||||
if(isize(digits) > 2) return BASE2;
|
||||
if(digits.empty()) return 0;
|
||||
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; }
|
||||
};
|
||||
#endif
|
||||
|
||||
bignum& bignum::operator +=(const bignum& b) {
|
||||
int K = isize(b.digits);
|
||||
if(K > isize(digits)) digits.resize(K);
|
||||
int carry = 0;
|
||||
for(int i=0; i<K || carry; i++) {
|
||||
if(i >= isize(digits)) digits.push_back(0);
|
||||
digits[i] += carry;
|
||||
if(i < K) digits[i] += b.digits[i];
|
||||
if(digits[i] >= BASE) {
|
||||
digits[i] -= BASE;
|
||||
carry = 1;
|
||||
}
|
||||
else carry = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool bignum::operator < (const bignum& b) const {
|
||||
if(isize(digits) != isize(b.digits))
|
||||
return isize(digits) < isize(b.digits);
|
||||
for(int i = isize(digits)-1; i>=0; i--)
|
||||
if(digits[i] != b.digits[i])
|
||||
return digits[i] < b.digits[i];
|
||||
return false;
|
||||
}
|
||||
|
||||
void bignum::addmul(const bignum& b, int factor) {
|
||||
int K = isize(b.digits);
|
||||
if(K > isize(digits)) digits.resize(K);
|
||||
int carry = 0;
|
||||
for(int i=0; i<K || (carry > 0 || carry < -1) || (carry == -1 && i < isize(digits)); i++) {
|
||||
if(i >= isize(digits)) digits.push_back(0);
|
||||
long long l = digits[i];
|
||||
l += carry;
|
||||
if(i < K) l += b.digits[i] * factor;
|
||||
carry = 0;
|
||||
if(l >= BASE) carry = l / BASE;
|
||||
if(l < 0) carry = -(BASE-1-l) / BASE;
|
||||
l -= carry * BASE;
|
||||
digits[i] = l;
|
||||
}
|
||||
if(carry < 0) digits.back() -= BASE;
|
||||
while(isize(digits) && digits.back() == 0) digits.pop_back();
|
||||
}
|
||||
|
||||
EX bignum hrand(bignum b) {
|
||||
bignum res;
|
||||
int d = isize(b.digits);
|
||||
while(true) {
|
||||
res.digits.resize(d);
|
||||
for(int i=0; i<d-1; i++) res.digits[i] = hrand(bignum::BASE);
|
||||
res.digits.back() = hrand(b.digits.back() + 1);
|
||||
if(res < b) return res;
|
||||
}
|
||||
}
|
||||
|
||||
EX void operator ++(bignum &b, int) {
|
||||
int i = 0;
|
||||
while(true) {
|
||||
if(isize(b.digits) == i) { b.digits.push_back(1); break; }
|
||||
else if(b.digits[i] == bignum::BASE-1) {
|
||||
b.digits[i] = 0;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
b.digits[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EX void operator --(bignum &b, int) {
|
||||
int i = 0;
|
||||
while(true) {
|
||||
if(isize(b.digits) == i) { b.digits.push_back(bignum::BASE-1); break; }
|
||||
else if(b.digits[i] == 0) {
|
||||
b.digits[i] = bignum::BASE-1;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
b.digits[i]--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string bignum::get_str(int max_length) {
|
||||
if(digits.empty()) return "0";
|
||||
string ret = its(digits.back());
|
||||
for(int i=isize(digits)-2; i>=0; i--) {
|
||||
if(isize(ret) > max_length && i) {
|
||||
ret += XLAT(" (%1 more digits)", its(9 * (i+1)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret += " ";
|
||||
string val = its(digits[i]);
|
||||
while(isize(val) < 9) val = "0" + val;
|
||||
ret += val;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void canonicize(vector<int>& t) {
|
||||
for(int i=2; i<isize(t); i++)
|
||||
if((t[i] & 3) == 1 && (t[i-1] & 3) != 1)
|
||||
|
@ -751,12 +751,13 @@ EX void showEuclideanMenu() {
|
||||
});
|
||||
}
|
||||
|
||||
if(among(specialland, laMinefield, laCA) && geometry_has_alt_mine_rule()) {
|
||||
dialog::addSelItem(XLAT("mine adjacency rule"), XLAT(mine_adjacency_rule ? "vertex" : WDIM == 3 ? "face" : "edge"), 'M');
|
||||
if(geometry_has_alt_mine_rule()) {
|
||||
dialog::addSelItem(XLAT("adjacency rule"), XLAT(mine_adjacency_rule ? "vertex" : WDIM == 3 ? "face" : "edge"), 'M');
|
||||
dialog::add_action([] {
|
||||
stop_game();
|
||||
mine_adjacency_rule = !mine_adjacency_rule;
|
||||
start_game();
|
||||
addMessage(XLAT("Note: adjacency rule affects environmental effects, but not movement."));
|
||||
});
|
||||
}
|
||||
|
||||
|
30
graph.cpp
30
graph.cpp
@ -3762,6 +3762,7 @@ struct flashdata {
|
||||
double angle2;
|
||||
int spd; // 0 for flashes, >0 for particles
|
||||
color_t color;
|
||||
string text;
|
||||
flashdata(int _t, int _s, cell *_w, color_t col, int sped) {
|
||||
t=_t; size=_s; where=_w; color = col;
|
||||
angle = rand() % 1000; spd = sped;
|
||||
@ -3771,6 +3772,13 @@ struct flashdata {
|
||||
|
||||
vector<flashdata> flashes;
|
||||
|
||||
EX void drawBubble(cell *c, color_t col, string s, ld size) {
|
||||
auto fd = flashdata(ticks, 1000, c, col, 0);
|
||||
fd.text = s;
|
||||
fd.angle = size;
|
||||
flashes.push_back(fd);
|
||||
}
|
||||
|
||||
EX void drawFlash(cell *c) {
|
||||
flashes.push_back(flashdata(ticks, 1000, c, iinf[itOrbFlash].color, 0));
|
||||
}
|
||||
@ -3990,8 +3998,8 @@ EX void drawMarkers() {
|
||||
queuecircleat(lmouseover, .8, darkena(lmouseover->cpdist > 1 ? 0x00FFFF : 0xFF0000, 0, 0xFF));
|
||||
}
|
||||
|
||||
if(pcm.mip.t && vid.drawmousecircle && ok && DEFAULTCONTROL && MOBON && WDIM == 2) {
|
||||
queuecircleat(pcm.mip.t, .6, darkena(0xFFD500, 0, 0xFF));
|
||||
if(global_pushto && vid.drawmousecircle && ok && DEFAULTCONTROL && MOBON && WDIM == 2) {
|
||||
queuecircleat(global_pushto, .6, darkena(0xFFD500, 0, 0xFF));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -4137,8 +4145,20 @@ EX void draw_flash(struct flashdata& f, const transmatrix& V, bool& kill) {
|
||||
int tim = ticks - f.t;
|
||||
|
||||
if(tim <= f.size && !f.spd) kill = false;
|
||||
|
||||
if(f.spd) {
|
||||
|
||||
if(f.text != "") {
|
||||
if(GDIM == 3 || sphere)
|
||||
queuestr(V, (1 - tim * 1. / f.size) * f.angle, f.text, f.color);
|
||||
else if(!kill) {
|
||||
hyperpoint h = tC0(V);
|
||||
if(hdist0(h) > .1) {
|
||||
transmatrix V2 = rspintox(h) * xpush(hdist0(h) * (1 / (1 - tim * 1. / f.size)));
|
||||
queuestr(V2, f.angle, f.text, f.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if(f.spd) {
|
||||
#if CAP_SHAPES
|
||||
if(tim <= 300) kill = false;
|
||||
int partcol = darkena(f.color, 0, GDIM == 3 ? 255 : max(255 - tim*255/300, 0));
|
||||
@ -4786,7 +4806,7 @@ EX bool nohelp;
|
||||
EX void normalscreen() {
|
||||
help = "@";
|
||||
|
||||
mouseovers = XLAT("Press F1 or right click for help");
|
||||
mouseovers = standard_help();
|
||||
|
||||
#if CAP_TOUR
|
||||
if(tour::on) mouseovers = tour::tourhelp;
|
||||
|
14
help.cpp
14
help.cpp
@ -178,6 +178,10 @@ void buildHelpText() {
|
||||
#endif
|
||||
}
|
||||
|
||||
EX string standard_help() {
|
||||
return XLAT("Press F1 or right click for help");
|
||||
}
|
||||
|
||||
EX void buildCredits() {
|
||||
help = "";
|
||||
help += XLAT("game design, programming, texts and graphics by Zeno Rogue <zeno@attnam.com>\n\n");
|
||||
@ -576,6 +580,16 @@ EX string generateHelpForMonster(eMonster m) {
|
||||
if(isGhost(m))
|
||||
s += XLAT("\n\nA Ghost never moves to a cell which is adjacent to another Ghost of the same kind.", m);
|
||||
|
||||
if(m == moMutant) {
|
||||
using namespace clearing;
|
||||
if(direct)
|
||||
s += XLAT("\n\nLeaves cut directly: %1", its(direct));
|
||||
if(kills[moMutant])
|
||||
s += XLAT("\n\nLeaves cut onscreen: %1", its(kills[moMutant]));
|
||||
if(imputed.nonzero())
|
||||
s += XLAT("\n\nLeaves cut offscreen (approximately): %1", imputed.get_str(10000));
|
||||
}
|
||||
|
||||
if(m == moBat || m == moEagle)
|
||||
s += XLAT("\n\nFast flying creatures may attack or go against gravity only in their first move.", m);
|
||||
|
||||
|
59
hud.cpp
59
hud.cpp
@ -253,8 +253,25 @@ bool displayglyph(int cx, int cy, int buttonsize, char glyph, color_t color, int
|
||||
(qty < 10 && (flags & (GLYPH_MARKTODO | GLYPH_RUNOUT))) ? buttonsize*3/4 :
|
||||
qty < 100 ? buttonsize / 2 :
|
||||
buttonsize / 3;
|
||||
if(str != "")
|
||||
displayfr(cx + buttonsize, cy + buttonsize/2 - bsize/2, 1, bsize, str, color, 16);
|
||||
|
||||
if(id == moMutant + ittypes && clearing::imputed.nonzero()) {
|
||||
ld d = qty + clearing::imputed.approx_ld();
|
||||
if(d < 100000) str = its(int(d));
|
||||
else {
|
||||
int digits = 0;
|
||||
while(d >= 10) digits++, d /= 10;
|
||||
str = its(int(d*100)) + "E" + its(digits);
|
||||
str.insert(1, ".");
|
||||
}
|
||||
bsize = buttonsize / 4;
|
||||
}
|
||||
|
||||
if(str != "") {
|
||||
if(textwidth(bsize, str) < buttonsize)
|
||||
displayfr(cx + buttonsize, cy + buttonsize/2 - bsize/2, 1, bsize, str, color, 16);
|
||||
else
|
||||
displayfr(cx, cy + buttonsize/2 - bsize/2, 1, bsize, str, color, 0);
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
@ -365,6 +382,8 @@ EX bool nofps = false;
|
||||
EX color_t crosshair_color = 0xFFFFFFC0;
|
||||
EX ld crosshair_size = 0;
|
||||
|
||||
EX bool long_kills;
|
||||
|
||||
EX void drawStats() {
|
||||
if(nohud || vid.stereo_mode == sLR) return;
|
||||
if(callhandlers(false, hooks_prestats)) return;
|
||||
@ -577,7 +596,8 @@ EX void drawStats() {
|
||||
#endif
|
||||
}
|
||||
else if(!peace::on) {
|
||||
if(displayButtonS(vid.xres - 8, vid.fsize, XLAT("score: %1", its(gold())), forecolor, 16, vid.fsize)) {
|
||||
string scoreline = XLAT("score: %1", its(gold()));
|
||||
if(displayButtonS(vid.xres - 8, vid.fsize, scoreline, forecolor, 16, vid.fsize)) {
|
||||
mouseovers = XLAT("Your total wealth"),
|
||||
instat = true,
|
||||
getcstat = SDLK_F1,
|
||||
@ -590,16 +610,29 @@ EX void drawStats() {
|
||||
"Orbs of Yendor are worth 50 $$$ each.\n\n"
|
||||
);
|
||||
}
|
||||
if(displayButtonS(8, vid.fsize, XLAT("kills: %1", its(tkills())), forecolor, 0, vid.fsize)) {
|
||||
instat = true,
|
||||
getcstat = SDLK_F1,
|
||||
mouseovers = XLAT("Your total kills")+": " + its(tkills()),
|
||||
help = helptitle(XLAT("Your total kills") + ": " + its(tkills()), 0x404040) +
|
||||
XLAT(
|
||||
"In most lands, more treasures are generated with each enemy native to this land you kill. "
|
||||
"Moreover, 100 kills is a requirement to enter the Graveyard and the Hive.\n\n"
|
||||
"Friendly creatures and parts of monsters (such as the Ivy) do appear in the list, "
|
||||
"but are not counted in the total kill count.");
|
||||
string s = XLAT("kills: %1", its(tkills()));
|
||||
long_kills = false;
|
||||
int siz = vid.fsize;
|
||||
if(cwt.at->land == laClearing && clearing::imputed.approx_ld() >= 100000) {
|
||||
long_kills = true;
|
||||
s = XLAT("leaves cut: " + (bignum(kills[moMutant]) + clearing::imputed).get_str(200));
|
||||
if(mouseovers == standard_help()) mouseovers = " ";
|
||||
while(siz > 4 && textwidth(siz, s) > vid.xres - textwidth(vid.fsize, scoreline)) siz--;
|
||||
}
|
||||
|
||||
if(displayButtonS(8, vid.fsize, s, forecolor, 0, siz)) {
|
||||
instat = true;
|
||||
getcstat = SDLK_F1;
|
||||
if(long_kills) { mouseovers = " "; help = generateHelpForMonster(moMutant); }
|
||||
else {
|
||||
mouseovers = XLAT("Your total kills")+": " + its(tkills()),
|
||||
help = helptitle(XLAT("Your total kills") + ": " + its(tkills()), 0x404040) +
|
||||
XLAT(
|
||||
"In most lands, more treasures are generated with each enemy native to this land you kill. "
|
||||
"Moreover, 100 kills is a requirement to enter the Graveyard and the Hive.\n\n"
|
||||
"Friendly creatures and parts of monsters (such as the Ivy) do appear in the list, "
|
||||
"but are not counted in the total kill count.");
|
||||
}
|
||||
}
|
||||
}
|
||||
string vers = VER;
|
||||
|
3
hyper.h
3
hyper.h
@ -246,7 +246,7 @@ struct videopar {
|
||||
ld xposition, yposition;
|
||||
|
||||
bool grid;
|
||||
int particles;
|
||||
bool particles;
|
||||
|
||||
int fsize;
|
||||
int flashtime;
|
||||
@ -325,6 +325,7 @@ struct videopar {
|
||||
|
||||
ld collignon_parameter; bool collignon_reflected;
|
||||
ld plevel_factor;
|
||||
bool bubbles_special, bubbles_threshold, bubbles_all;
|
||||
};
|
||||
|
||||
extern videopar vid;
|
||||
|
@ -1157,7 +1157,9 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
(hrand(50+items[itMutant]/2+yendor::hardness()) < 30) ? (hrand(100) < 50 ? waBigTree : waSmallTree) : waNone;
|
||||
}
|
||||
if(d == 8) {
|
||||
if(hrand(doCross ?450:15000) < 20 + (2 * items[itMutant] + yendor::hardness()) && !safety) {
|
||||
bool ok = c->landparam == 0;
|
||||
forCellEx(c2, c) if(c2->landparam) ok = false;
|
||||
if(ok && hrand(doCross ?450:15000) < 20 + (2 * items[itMutant] + yendor::hardness()) && !safety) {
|
||||
if(!peace::on) c->item = itMutant;
|
||||
c->landparam = items[itMutant] + 5 + hrand(11);
|
||||
c->wall = waNone;
|
||||
@ -1165,7 +1167,7 @@ EX void giantLandSwitch(cell *c, int d, cell *from) {
|
||||
if(c->move(i) && (c->move(i)->wall == waBigTree || c->move(i)->wall == waSmallTree))
|
||||
c->move(i)->wall = waNone;
|
||||
}
|
||||
else if(hrand_monster(15000) < 20 + (2 * items[itMutant] + yendor::hardness()) && !safety) {
|
||||
else if(hrand_monster(15000) < 20 + (2 * items[itMutant] + yendor::hardness()) && ok && !safety) {
|
||||
// for the Yendor Challenge, use only Mutants
|
||||
if(!(yendor::on && yendor::clev().l == laMirror)) {
|
||||
c->monst = moForestTroll;
|
||||
|
@ -38,6 +38,7 @@ EX int buildIvy(cell *c, int children, int minleaf) {
|
||||
leaf += leafchild;
|
||||
if(leaf < minleaf) {
|
||||
if(child) killIvy(child, moNone);
|
||||
dynamicval<int> k(kills[moIvyDead]);
|
||||
killIvy(c, moNone);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1333,8 +1333,18 @@ EX void movehex_rest(bool mounted) {
|
||||
}
|
||||
|
||||
EX void movemutant() {
|
||||
manual_celllister mcells;
|
||||
for(cell *c: currentmap->allcells()) mcells.add(c);
|
||||
if(!bounded)
|
||||
for(int i=0; i<isize(mcells.lst); i++) {
|
||||
cell *c = mcells.lst[i];
|
||||
if(c->land == laClearing && c->monst != moMutant && !pseudohept(c))
|
||||
forCellEx(c2, c) forCellEx(c3, c2) if(celldistAlt(c3) < celldistAlt(c))
|
||||
mcells.add(c3);
|
||||
}
|
||||
|
||||
vector<cell*> young;
|
||||
for(cell *c: currentmap->allcells())
|
||||
for(cell *c: mcells.lst)
|
||||
if(c->monst == moMutant && c->stuntime == mutantphase)
|
||||
young.push_back(c);
|
||||
|
||||
|
@ -958,6 +958,11 @@ EX void handleInput(int delta) {
|
||||
cdir = d;
|
||||
if(multi::multiPlayerTarget(i) == c) break;
|
||||
cdir = scdir;
|
||||
cwt = multi::player[i];
|
||||
calcMousedest();
|
||||
auto& sd = multi::whereto[i].subdir;
|
||||
sd = mousedest.subdir;
|
||||
if(sd == 0) sd = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,12 +224,15 @@ struct pcmove {
|
||||
};
|
||||
#endif
|
||||
|
||||
EX pcmove pcm;
|
||||
EX cell *global_pushto;
|
||||
|
||||
EX bool movepcto(int d, int subdir IS(1), bool checkonly IS(false)) {
|
||||
pcmove pcm;
|
||||
pcm.checkonly = checkonly;
|
||||
pcm.d = d; pcm.subdir = subdir;
|
||||
return pcm.movepcto();
|
||||
auto b = pcm.movepcto();
|
||||
global_pushto = pcm.mip.t;
|
||||
return b;
|
||||
}
|
||||
|
||||
bool pcmove::movepcto() {
|
||||
|
15
system.cpp
15
system.cpp
@ -394,7 +394,7 @@ bool havesave = true;
|
||||
|
||||
#if HDR
|
||||
#define MAXBOX 500
|
||||
#define POSSCORE 371 // update this when new boxes are added!
|
||||
#define POSSCORE 373 // update this when new boxes are added!
|
||||
struct score {
|
||||
string ver;
|
||||
int box[MAXBOX];
|
||||
@ -414,6 +414,16 @@ void applyBox(int& t) {
|
||||
else boxid++;
|
||||
}
|
||||
|
||||
void applyBoxBignum(bignum& tb) {
|
||||
float tf;
|
||||
int ti;
|
||||
if(saving) tf = tb.approx_ld();
|
||||
if(saving) memcpy(&ti, &tf, 4);
|
||||
applyBox(ti);
|
||||
if(loading) memcpy(&tf, &ti, 4);
|
||||
if(loading) tb = bignum(tf);
|
||||
}
|
||||
|
||||
EX void applyBoxNum(int& i, string name IS("")) {
|
||||
fakebox[boxid] = (name == "");
|
||||
boxname[boxid] = name;
|
||||
@ -814,6 +824,9 @@ EX void applyBoxes() {
|
||||
|
||||
applyBoxM(moNarciss);
|
||||
applyBoxM(moMirrorSpirit);
|
||||
|
||||
applyBox(clearing::direct);
|
||||
applyBoxBignum(clearing::imputed);
|
||||
|
||||
if(POSSCORE != boxid) printf("ERROR: %d boxes\n", boxid);
|
||||
}
|
||||
|
194
util.cpp
194
util.cpp
@ -325,4 +325,198 @@ EX string parser_help() {
|
||||
"(a)sin(h), (a)cos(h), (a)tan(h), exp, log, abs, re, im, conj, let(t=...,...t...), floor, frac, e, i, pi, s, ms, mousex, mousey, mousez, shot [1 if taking screenshot/animation], sqrt, to01, random, edge(7,3), regradius(7,3), ifp(a,v,w) [if positive]");
|
||||
}
|
||||
|
||||
#if HDR
|
||||
struct bignum {
|
||||
static const int BASE = 1000000000;
|
||||
static const long long BASE2 = BASE * (long long)BASE;
|
||||
vector<int> digits;
|
||||
bignum() {}
|
||||
bignum(int i) : digits() { digits.push_back(i); }
|
||||
void be(int i) { digits.resize(1); digits[0] = i; }
|
||||
bignum& operator +=(const bignum& b);
|
||||
void addmul(const bignum& b, int factor);
|
||||
string get_str(int max_length) const;
|
||||
bignum(ld d);
|
||||
|
||||
bool operator < (const bignum&) const;
|
||||
bool operator > (const bignum& b) const { return b < self; }
|
||||
|
||||
ld leading() const {
|
||||
switch(isize(digits)) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return digits.back();
|
||||
default:
|
||||
return digits.back() + ld(digits[isize(digits)-2]) / BASE;
|
||||
}
|
||||
}
|
||||
|
||||
ld approx() const {
|
||||
return leading() * pow(BASE, isize(digits) - 1);
|
||||
}
|
||||
|
||||
ld log_approx() const {
|
||||
return log(leading()) * log(BASE) * (isize(digits) - 1);
|
||||
}
|
||||
|
||||
ld approx_div(const bignum& b) const {
|
||||
return leading() / b.leading() * pow(BASE, isize(digits) - isize(b.digits));
|
||||
}
|
||||
|
||||
int approx_int() const {
|
||||
if(isize(digits) > 1) return BASE;
|
||||
if(digits.empty()) return 0;
|
||||
return digits[0];
|
||||
}
|
||||
|
||||
bool nonzero() { return approx_ld() != 0; }
|
||||
|
||||
bignum randomized_div(int x) const;
|
||||
|
||||
ld approx_ld() const {
|
||||
ld res = 0;
|
||||
for(int i=0; i<isize(digits); i++) res += digits[i] * pow(BASE, i);
|
||||
return res;
|
||||
}
|
||||
|
||||
long long approx_ll() const {
|
||||
if(isize(digits) > 2) return BASE2;
|
||||
if(digits.empty()) return 0;
|
||||
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; }
|
||||
};
|
||||
#endif
|
||||
|
||||
bignum& bignum::operator +=(const bignum& b) {
|
||||
int K = isize(b.digits);
|
||||
if(K > isize(digits)) digits.resize(K);
|
||||
int carry = 0;
|
||||
for(int i=0; i<K || carry; i++) {
|
||||
if(i >= isize(digits)) digits.push_back(0);
|
||||
digits[i] += carry;
|
||||
if(i < K) digits[i] += b.digits[i];
|
||||
if(digits[i] >= BASE) {
|
||||
digits[i] -= BASE;
|
||||
carry = 1;
|
||||
}
|
||||
else carry = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool bignum::operator < (const bignum& b) const {
|
||||
if(isize(digits) != isize(b.digits))
|
||||
return isize(digits) < isize(b.digits);
|
||||
for(int i = isize(digits)-1; i>=0; i--)
|
||||
if(digits[i] != b.digits[i])
|
||||
return digits[i] < b.digits[i];
|
||||
return false;
|
||||
}
|
||||
|
||||
bignum bignum::randomized_div(int x) const {
|
||||
bignum res = self;
|
||||
long long carry = 0;
|
||||
int K = isize(res.digits);
|
||||
for(int i=K-1; i>=0; i--) {
|
||||
carry *= BASE;
|
||||
carry += digits[i];
|
||||
tie(carry, res.digits[i]) = make_pair(carry % x, carry / x);
|
||||
}
|
||||
while(isize(res.digits) && res.digits.back() == 0) res.digits.pop_back();
|
||||
if(rand() % x < carry) res += 1;
|
||||
println(hlog, get_str(100), " / ", x, " = ", res.get_str(100));
|
||||
return res;
|
||||
}
|
||||
|
||||
void bignum::addmul(const bignum& b, int factor) {
|
||||
int K = isize(b.digits);
|
||||
if(K > isize(digits)) digits.resize(K);
|
||||
int carry = 0;
|
||||
for(int i=0; i<K || (carry > 0 || carry < -1) || (carry == -1 && i < isize(digits)); i++) {
|
||||
if(i >= isize(digits)) digits.push_back(0);
|
||||
long long l = digits[i];
|
||||
l += carry;
|
||||
if(i < K) l += b.digits[i] * factor;
|
||||
carry = 0;
|
||||
if(l >= BASE) carry = l / BASE;
|
||||
if(l < 0) carry = -(BASE-1-l) / BASE;
|
||||
l -= carry * BASE;
|
||||
digits[i] = l;
|
||||
}
|
||||
if(carry < 0) digits.back() -= BASE;
|
||||
while(isize(digits) && digits.back() == 0) digits.pop_back();
|
||||
}
|
||||
|
||||
EX bignum hrand(bignum b) {
|
||||
bignum res;
|
||||
int d = isize(b.digits);
|
||||
while(true) {
|
||||
res.digits.resize(d);
|
||||
for(int i=0; i<d-1; i++) res.digits[i] = hrand(bignum::BASE);
|
||||
res.digits.back() = hrand(b.digits.back() + 1);
|
||||
if(res < b) return res;
|
||||
}
|
||||
}
|
||||
|
||||
EX void operator ++(bignum &b, int) {
|
||||
int i = 0;
|
||||
while(true) {
|
||||
if(isize(b.digits) == i) { b.digits.push_back(1); break; }
|
||||
else if(b.digits[i] == bignum::BASE-1) {
|
||||
b.digits[i] = 0;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
b.digits[i]++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EX void operator --(bignum &b, int) {
|
||||
int i = 0;
|
||||
while(true) {
|
||||
if(isize(b.digits) == i) { b.digits.push_back(bignum::BASE-1); break; }
|
||||
else if(b.digits[i] == 0) {
|
||||
b.digits[i] = bignum::BASE-1;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
b.digits[i]--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string bignum::get_str(int max_length) const {
|
||||
if(digits.empty()) return "0";
|
||||
string ret = its(digits.back());
|
||||
for(int i=isize(digits)-2; i>=0; i--) {
|
||||
if(isize(ret) > max_length && i) {
|
||||
ret += XLAT(" (%1 more digits)", its(9 * (i+1)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret += " ";
|
||||
string val = its(digits[i]);
|
||||
while(isize(val) < 9) val = "0" + val;
|
||||
ret += val;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bignum::bignum(ld d) {
|
||||
if(d == 0) return;
|
||||
int n = 1;
|
||||
while(d > BASE) d /= BASE, n++;
|
||||
digits.resize(n);
|
||||
n--;
|
||||
while(n >= 0) { digits[n] = int(d); d -= digits[n]; d *= BASE; n--; }
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user