From 7c4828b3906509045537ddc083162fcd327d416e Mon Sep 17 00:00:00 2001 From: Ketmar Dark Date: Tue, 31 Oct 2017 07:15:07 +0200 Subject: [PATCH] `RandomChance` type, and two new item fields: `MagicEffectChance`, `MagicEffectDuration` for now they're used only in `slowaxe`. the syntax is: MagicEffectChance == 3; // will do !(RAND()%3) MagicEffectDuration = { rand: 200; add: 400; } // 400+RAND_N(200) --- script/_default/items/slowaxe.dat | 3 +++ script/item.dat | 2 ++ src/felib/femath.h | 12 ++++++------ src/felib/feparse.cpp | 30 ++++++++++++++++++++++++++++++ src/felib/feparse.h | 23 ++++++++++++++++++++++- src/game/char.cpp | 2 ++ src/game/database.cpp | 3 +++ src/game/gears/meleeweapon_slowaxe.cpp | 8 ++++++-- src/game/item.h | 4 ++++ src/game/ivancommon.cpp | 12 ++++++++++-- 10 files changed, 88 insertions(+), 11 deletions(-) diff --git a/script/_default/items/slowaxe.dat b/script/_default/items/slowaxe.dat index f17d1c7..4cc957c 100644 --- a/script/_default/items/slowaxe.dat +++ b/script/_default/items/slowaxe.dat @@ -20,6 +20,8 @@ slowaxe /* meleeweapon-> */ WieldedBitmapPos = 160, 176; EnchantmentPlusChance = 2; DamageFlags = SLASH; + MagicEffectChance == 3; // this is !(RAND()%3) + MagicEffectDuration = { add: 400; rand: 200; } Config BROKEN; { @@ -27,5 +29,6 @@ slowaxe /* meleeweapon-> */ BitmapPos = 32, 176; WieldedBitmapPos = 176, 176; EnchantmentPlusChance = 4; + MagicEffectChance == 0; // broken items aren't magic } } diff --git a/script/item.dat b/script/item.dat index 0ba4b0d..a565f0b 100644 --- a/script/item.dat +++ b/script/item.dat @@ -124,6 +124,8 @@ item IsThrowingWeapon = false; ThrowItemTypes = NONE; /*Possibilities: THROW_BONE|THROW_POTION|THROW_AXE|THROW_GAS_GRENADE|THROW_WAND;*/ CanFlame = false; + MagicEffectChance == 0; + MagicEffectDuration == 0; AllowedDungeons == ALL_DUNGEONS; // example: AllowedDungeons := { UNDER_WATER_TUNNEL, MONDEDR; } LevelTags := {} // {"*"} } diff --git a/src/felib/femath.h b/src/felib/femath.h index 6b0a263..588e533 100644 --- a/src/felib/femath.h +++ b/src/felib/femath.h @@ -54,14 +54,14 @@ public: PCG32 (uint64_t astate, uint64_t ainc=1) { setSeed(astate, ainc); } PCG32 (const PRNGSeed aseed) { seed = aseed; } - void setSeed (uint64_t astate, uint64_t ainc=1) { seed.state = astate; seed.inc = ainc; } - void setSeed (const PRNGSeed aseed) { seed = aseed; } + inline void setSeed (uint64_t astate, uint64_t ainc=1) { seed.state = astate; seed.inc = ainc; } + inline void setSeed (const PRNGSeed aseed) { seed = aseed; } - PRNGSeed getSeed () const { return seed; } + inline PRNGSeed getSeed () const { return seed; } void rndseed (); - uint32_t rand32 () { + inline uint32_t rand32 () { uint64_t oldstate = this->seed.state; // advance internal state this->seed.state = oldstate*6364136223846793005ULL+(this->seed.inc|1); @@ -85,8 +85,8 @@ public: static void SetSeed (const PRNGSeed aseed); static void SetSeed (feuLong); static void RandSeed (); - static sLong RandN (sLong N) { return sLong(double(N)*Rand()/0x80000000); } - static sLong RandGood (sLong N) { return sLong(double(N)*Rand()/0x80000000); } + static sLong RandN (sLong N) { return (sLong)((double)N*Rand()/0x80000000); } + static sLong RandGood (sLong N) { return (sLong)((double)N*Rand()/0x80000000); } static int WeightedRand (sLong *Possibility, sLong TotalPossibility); static int WeightedRand (const std::vector &Possibility, sLong TotalPossibility); static double CalculateAngle (v2 Direction); diff --git a/src/felib/feparse.cpp b/src/felib/feparse.cpp index 627a3b3..56c621e 100644 --- a/src/felib/feparse.cpp +++ b/src/felib/feparse.cpp @@ -1176,6 +1176,36 @@ void ReadData (fearray &Array, TextInput &SaveFile) { } +void ReadData (RandomChance &rc, TextInput &fl) { + festring w; + rc.clear(); + w = fl.ReadWord(); + auto tkline = fl.TokenLine(); + if (w == "==") { + rc.rnd = fl.ReadNumber(); + } else if (w == "=" || w == ":=") { + if (fl.ReadWord() != "{") ABORT("RandomChance syntax error: '{' expected in file %s, line %d!", fl.GetFileName().CStr(), fl.TokenLine()); + for (;;) { + w = fl.ReadWord(); + if (w == "}") break; + sLong *fptr = nullptr; + if (w.CompareIgnoreCase("add") == 0) fptr = &rc.add; + else if (w.CompareIgnoreCase("rnd") == 0) fptr = &rc.rnd; + else if (w.CompareIgnoreCase("rand") == 0) fptr = &rc.rnd; + else if (w.CompareIgnoreCase("rmin") == 0) fptr = &rc.rmin; + else if (w.CompareIgnoreCase("rmax") == 0) fptr = &rc.rmax; + if (!fptr) ABORT("RandomChance syntax error: unknown field '%s' in file %s, line %d!", w.CStr(), fl.GetFileName().CStr(), fl.TokenLine()); + w = fl.ReadWord(); + if (w != ":" && w != "=") ABORT("RandomChance syntax error: ':' expected in file %s, line %d!", fl.GetFileName().CStr(), fl.TokenLine()); + *fptr = fl.ReadNumber(); + } + } else { + ABORT("RandomChance syntax error: '=' or '==' expected in file %s, line %d!", fl.GetFileName().CStr(), tkline); + } + if (rc.rnd < 0) ABORT("Invalid random chance in file %s, line %d!", fl.GetFileName().CStr(), tkline); +} + + // ////////////////////////////////////////////////////////////////////////// // TextInputFile::TextInputFile (cfestring &FileName, const valuemap *aValueMap, truth AbortOnErr) { ifile.Open(FileName, AbortOnErr); diff --git a/src/felib/feparse.h b/src/felib/feparse.h index 3327acc..69ee150 100644 --- a/src/felib/feparse.h +++ b/src/felib/feparse.h @@ -16,6 +16,7 @@ #include "festring.h" #include "fearray.h" #include "fesave.h" +#include "femath.h" // ////////////////////////////////////////////////////////////////////////// // @@ -166,6 +167,25 @@ protected: // ////////////////////////////////////////////////////////////////////////// // +// `rand()` returns `add+RAND_N(rnd)` +// `inRange()` returns `true` if `rand()` is in [rmin..rmax] (inclusive!) +// script syntax: +// RCField = { add: num; rnd: num; rmin: num; rmax: num; } +// any field may absent +// or simplified: +// RCField == rnd; +struct RandomChance { + sLong add = 0; + sLong rnd = 0; + sLong rmin = 0, rmax = 0; + + inline void clear () { add = rnd = rmin = rmax = 0; } + inline sLong rand () const { return add+RAND_N(rnd); } + // if `rnd` is zero, assume "no chances" + inline truth inRange () const { if (rnd > 0) { auto v = rand(); return (v >= rmin && v <= rmax); } return false; } +}; + + inline void ReadData (char &Type, TextInput &infile) { Type = infile.ReadNumber(); } inline void ReadData (uChar &Type, TextInput &infile) { Type = infile.ReadNumber(); } inline void ReadData (short &Type, TextInput &infile) { Type = infile.ReadNumber(); } @@ -181,8 +201,9 @@ inline void ReadData (float &Type, TextInput &infile) { Type = infile.ReadFloat( void ReadData (festring &, TextInput &); void ReadData (fearray &, TextInput &); void ReadData (fearray &, TextInput &); +void ReadData (RandomChance &rc, TextInput &fl); -template inline void ReadData (fearray &Array, TextInput &infile) { +template void ReadData (fearray &Array, TextInput &infile) { Array.Clear(); festring Word; infile.ReadWord(Word); diff --git a/src/game/char.cpp b/src/game/char.cpp index 006ec29..48ba438 100644 --- a/src/game/char.cpp +++ b/src/game/char.cpp @@ -7467,6 +7467,8 @@ truth character::EquipmentScreen (stack *MainStack, stack *SecStack) { else if (firstEmpty >= 0) selected = firstEmpty; else if (firstNonEmpty >= 0) selected = firstNonEmpty; } + // 7: right ring; switch to left ring if that slot has nothing in it + if (selected == 7 && GetBodyPartOfEquipment(8) && !GetEquipment(8)) selected = 8; if (selected >= 0) List.SetSelected(selected); List.SetFlags(SELECTABLE|DRAW_BACKGROUND_AFTERWARDS); diff --git a/src/game/database.cpp b/src/game/database.cpp index 0b71901..9be6faa 100644 --- a/src/game/database.cpp +++ b/src/game/database.cpp @@ -322,6 +322,7 @@ INST_ADD_MEMBER(item, v2); INST_ADD_MEMBER(item, festring); INST_ADD_MEMBER(item, fearray); INST_ADD_MEMBER(item, fearray); +INST_ADD_MEMBER(item, RandomChance); INST_ADD_MEMBER(glterrain, int); //INST_ADD_MEMBER(glterrain, sLong); //k8:64 @@ -653,6 +654,8 @@ template<> void databasecreator::CreateDataBaseMemberMap () { ADD_MEMBER(IsThrowingWeapon); ADD_MEMBER(ThrowItemTypes); ADD_MEMBER(CanFlame); + ADD_MEMBER(MagicEffectDuration); + ADD_MEMBER(MagicEffectChance); ADD_MEMBER(AllowedDungeons); ADD_MEMBER(LevelTags); } diff --git a/src/game/gears/meleeweapon_slowaxe.cpp b/src/game/gears/meleeweapon_slowaxe.cpp index c6db3d6..9043522 100644 --- a/src/game/gears/meleeweapon_slowaxe.cpp +++ b/src/game/gears/meleeweapon_slowaxe.cpp @@ -11,7 +11,10 @@ ITEM(slowaxe, meleeweapon) truth slowaxe::HitEffect (character *Enemy, character *Hitter, v2 HitPos, int BodyPartIndex, int Direction, truth BlockedByArmour) { truth BaseSuccess = meleeweapon::HitEffect(Enemy, Hitter, HitPos, BodyPartIndex, Direction, BlockedByArmour); - if (!IsBroken() && Enemy->IsEnabled() && !(RAND()%3)) { + //fprintf(stderr, "chance: rnd=%d; add=%d; min=%d; max=%d\n", GetMagicEffectChance().rnd, GetMagicEffectChance().add, GetMagicEffectChance().rmin, GetMagicEffectChance().rmax); + //fprintf(stderr, "duration: rnd=%d; add=%d; min=%d; max=%d\n", GetMagicEffectDuration().rnd, GetMagicEffectDuration().add, GetMagicEffectDuration().rmin, GetMagicEffectDuration().rmax); + //fprintf(stderr, "dur=%d\n", GetMagicEffectDuration().rand()); + if (/*!IsBroken() &&*/ Enemy->IsEnabled() && /*!(RAND()%3)*/GetMagicEffectChance().inRange()) { if (Hitter) { if (Enemy->IsPlayer() || Hitter->IsPlayer() || Enemy->CanBeSeenByPlayer() || Hitter->CanBeSeenByPlayer()) { ADD_MESSAGE("%s axe chills %s.", Hitter->CHAR_POSSESSIVE_PRONOUN, Enemy->CHAR_DESCRIPTION(DEFINITE)); @@ -21,7 +24,8 @@ truth slowaxe::HitEffect (character *Enemy, character *Hitter, v2 HitPos, int Bo ADD_MESSAGE("The axe chills %s.", Enemy->CHAR_DESCRIPTION(DEFINITE)); } } - Enemy->BeginTemporaryState(SLOW, 400+RAND_N(200)); + //Enemy->BeginTemporaryState(SLOW, 400+RAND_N(200)); + Enemy->BeginTemporaryState(SLOW, GetMagicEffectDuration().rand()); //400+RAND_N(200) return BaseSuccess; } return BaseSuccess; diff --git a/src/game/item.h b/src/game/item.h index af1baf1..223d237 100644 --- a/src/game/item.h +++ b/src/game/item.h @@ -207,6 +207,8 @@ struct itemdatabase : public databasebase truth IsThrowingWeapon; sLong ThrowItemTypes; truth CanFlame; + RandomChance MagicEffectDuration; + RandomChance MagicEffectChance; fearray AllowedDungeons; fearray LevelTags; }; @@ -439,6 +441,8 @@ class item : public object DATA_BASE_TRUTH(IsThrowingWeapon); DATA_BASE_VALUE(sLong, ThrowItemTypes); DATA_BASE_TRUTH(CanFlame); + DATA_BASE_VALUE(RandomChance, MagicEffectDuration); + DATA_BASE_VALUE(RandomChance, MagicEffectChance); DATA_BASE_VALUE(const fearray &, AllowedDungeons); DATA_BASE_VALUE(const fearray &, LevelTags); truth CanBeSoldInLibrary(character* Librarian) const { return CanBeRead(Librarian); } diff --git a/src/game/ivancommon.cpp b/src/game/ivancommon.cpp index d3f6685..9a867cc 100644 --- a/src/game/ivancommon.cpp +++ b/src/game/ivancommon.cpp @@ -20,9 +20,17 @@ void *operator new (std::size_t size) throw (std::bad_alloc) { - if (size > 0x1fffffff) throw std::bad_alloc(); // ANSI/ISO compliant behavior + if (size > 0x1fffffff) { + //throw std::bad_alloc(); // ANSI/ISO compliant behavior + fprintf(stderr, "`new`: size > 0x1fffffff! (%u)\n", size); + *(int *)0 = 666; + } void *p = calloc(1, size+64); - if (!p) throw std::bad_alloc(); // ANSI/ISO compliant behavior + if (!p) { + fprintf(stderr, "`new`: out of memory for size=%u!\n", size); + *(int *)0 = 666; + //throw std::bad_alloc(); // ANSI/ISO compliant behavior + } //fprintf(stderr, "GLOBAL NEW!\n"); return p; } -- 2.11.4.GIT