Achievement system fixes and stackable chanceboxes.
This commit is contained in:
parent
fc87562758
commit
35b0ad1b2b
10 changed files with 126 additions and 37 deletions
|
|
@ -3,7 +3,8 @@
|
|||
# basename: the base name used to construct cvars and localization strings
|
||||
# maxval: limit progress value (if any), a value of -1 means it needs special
|
||||
# handling in zscript (usually for cases where this is dynamic, like
|
||||
# the "all collectibles" achievement)
|
||||
# the "all collectibles" achievement), and a value below -1 indicates
|
||||
# this is a bitfield, where abs(maxval) bits must be set
|
||||
# hasformat: the TXT string has a %d in it to substitute for maxval
|
||||
# gametype: the game this belongs to (any, doom, heretic, hexen, raven, etc.)
|
||||
acid,50,yes,any
|
||||
|
|
@ -25,7 +26,6 @@ bune,500,yes,any
|
|||
bustin,50,yes,any
|
||||
butts,100,yes,any
|
||||
candy,1000,yes,any
|
||||
cheat,0,no,any
|
||||
cliffyb,0,no,nothexen
|
||||
clonk,0,no,any
|
||||
conga,10,yes,any
|
||||
|
|
@ -65,6 +65,7 @@ lead,1500,yes,any
|
|||
ligma,0,no,any
|
||||
love,10,yes,any
|
||||
#mashiro,0,no,any
|
||||
matryoshka,0,no,any
|
||||
mbf,0,no,doom
|
||||
mega,10000,yes,any
|
||||
moth,50,yes,any
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
|
@ -1146,8 +1146,6 @@ SWWM_ACHIEVEMENT_BUTTS_TAG = "Let's get to Bashing Butts";
|
|||
SWWM_ACHIEVEMENT_BUTTS_TXT = "Kill %d enemies by dashing backwards";
|
||||
SWWM_ACHIEVEMENT_CANDY_TAG = "Piece of Candy";
|
||||
SWWM_ACHIEVEMENT_CANDY_TXT = "Collect %d nuggets";
|
||||
SWWM_ACHIEVEMENT_CHEAT_TAG = "Mishe Trickery";
|
||||
SWWM_ACHIEVEMENT_CHEAT_TXT = "Successfully input a cheat code";
|
||||
SWWM_ACHIEVEMENT_CLIFFYB_TAG = "Errand Boy Bullshit";
|
||||
SWWM_ACHIEVEMENT_CLIFFYB_TXT = "Finish a map without collecting any keys";
|
||||
SWWM_ACHIEVEMENT_CLONK_TAG = "CLONK";
|
||||
|
|
@ -1230,6 +1228,8 @@ SWWM_ACHIEVEMENT_LOVE_TAG = "Lethal Love";
|
|||
SWWM_ACHIEVEMENT_LOVE_TXT = "Kill %d enemies with a blown kiss (not counting insta-kills)";
|
||||
SWWM_ACHIEVEMENT_MASHIRO_TAG = "Layers of White";
|
||||
SWWM_ACHIEVEMENT_MASHIRO_TXT = "Summon the White Lady";
|
||||
SWWM_ACHIEVEMENT_MATRYOSHKA_TAG = "Mishe Trickery";
|
||||
SWWM_ACHIEVEMENT_MATRYOSHKA_TXT = "A Chancebox inside a Chancebox inside a Chancebox inside a Chancebox inside a...";
|
||||
SWWM_ACHIEVEMENT_MBF_TAG = "You can Pet the Dog";
|
||||
SWWM_ACHIEVEMENT_MBF_TXT = "Pet a dog";
|
||||
SWWM_ACHIEVEMENT_MEGA_TAG = "Mass Massacre";
|
||||
|
|
|
|||
|
|
@ -1006,8 +1006,6 @@ SWWM_ACHIEVEMENT_BUTTS_TAG = "Esos Glúteos Firmes";
|
|||
SWWM_ACHIEVEMENT_BUTTS_TXT = "Mata %d enemigos embistiendo marcha atrás";
|
||||
SWWM_ACHIEVEMENT_CANDY_TAG = "Oh un Caramelo";
|
||||
SWWM_ACHIEVEMENT_CANDY_TXT = "Recoge %d pepitas";
|
||||
SWWM_ACHIEVEMENT_CHEAT_TAG = "Astucia Mishe";
|
||||
SWWM_ACHIEVEMENT_CHEAT_TXT = "Consigue meter un código de trampa";
|
||||
SWWM_ACHIEVEMENT_CLIFFYB_TAG = "Mierdas de Recadero";
|
||||
SWWM_ACHIEVEMENT_CLIFFYB_TXT = "Termina un mapa sin obtener ninguna llave";
|
||||
SWWM_ACHIEVEMENT_CLONK_TAG = "CLONK";
|
||||
|
|
@ -1084,6 +1082,8 @@ SWWM_ACHIEVEMENT_LOVE_TAG = "Amor Letal";
|
|||
SWWM_ACHIEVEMENT_LOVE_TXT = "Mata %d enemigos con un beso lanzado (sin contar insta-kills)";
|
||||
SWWM_ACHIEVEMENT_MASHIRO_TAG = "Capas de Blanco";
|
||||
SWWM_ACHIEVEMENT_MASHIRO_TXT = "Invoca a la Dama Blanca";
|
||||
SWWM_ACHIEVEMENT_MATRYOSHKA_TAG = "Astucia Mishe";
|
||||
SWWM_ACHIEVEMENT_MATRYOSHKA_TXT = "Una Caja Afortunada dentro de una Caja Afortunada dentro de una Caja Afortunada dentro de una Caja Afortunada dentro de...";
|
||||
SWWM_ACHIEVEMENT_MBF_TAG = "Puedes Acariciar el Perro";
|
||||
SWWM_ACHIEVEMENT_MBF_TXT = "Acaricia un perro";
|
||||
SWWM_ACHIEVEMENT_MEGA_TAG = "Masacre Masiva";
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[default]
|
||||
SWWM_MODVER="\chSWWM \czGZ\c- \cw1.2pre r105 \cu(Sat 8 Jan 17:52:30 CET 2022)\c-";
|
||||
SWWM_SHORTVER="\cw1.2pre r105 \cu(2022-01-08 17:52:30)\c-";
|
||||
SWWM_MODVER="\chSWWM \czGZ\c- \cw1.2pre r106 \cu(Tue 11 Jan 02:18:38 CET 2022)\c-";
|
||||
SWWM_SHORTVER="\cw1.2pre r106 \cu(2022-01-11 02:18:38)\c-";
|
||||
|
|
|
|||
|
|
@ -448,7 +448,6 @@ extend Class SWWMHandler
|
|||
StatusBar.AttachMessage(m,-1232);
|
||||
CVar.FindCVar('swwm_oldcheat').SetBool(true);
|
||||
}
|
||||
SWWMUtility.MarkAchievement("cheat",players[consoleplayer]);
|
||||
if ( SWWMUtility.CheatsDisabled(consoleplayer) )
|
||||
{
|
||||
kfail = true;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ Class SWWMAchievementInfo
|
|||
int baseindex; // sorting order in the list
|
||||
String basename; // base name for identifying achievement
|
||||
TextureID icon; // our icon
|
||||
int maxval; // maximum value (0: no progress, -1: special scripting needed)
|
||||
int maxval; // maximum value (0: no progress)
|
||||
bool hasformat; // achievement description text must be formatted to add maxval
|
||||
bool bitfield; // progress is tracked as a bitfield
|
||||
int state, val; // set by other scripts, used to avoid excessive dictionary lookups
|
||||
}
|
||||
|
||||
|
|
@ -23,16 +24,35 @@ extend Class SWWMStaticHandler
|
|||
if ( a.maxval )
|
||||
{
|
||||
int prog = achievementprogress.At(a.basename).ToInt();
|
||||
// special cases
|
||||
if ( val && (prog < a.maxval) )
|
||||
// special case for bitfields
|
||||
if ( a.bitfield )
|
||||
{
|
||||
achievementstate.Insert(a.basename,"0");
|
||||
val = 0;
|
||||
int pb = 0;
|
||||
for ( int i=0; i<a.maxval; i++ )
|
||||
pb += !!(prog&(1<<i));
|
||||
if ( val && (pb < a.maxval) )
|
||||
{
|
||||
achievementstate.Insert(a.basename,"0");
|
||||
val = 0;
|
||||
}
|
||||
else if ( !val && (pb >= a.maxval) )
|
||||
{
|
||||
achievementstate.Insert(a.basename,"1");
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
else if ( !val && (prog >= a.maxval) )
|
||||
else
|
||||
{
|
||||
achievementstate.Insert(a.basename,"1");
|
||||
val = 1;
|
||||
if ( val && (prog < a.maxval) )
|
||||
{
|
||||
achievementstate.Insert(a.basename,"0");
|
||||
val = 0;
|
||||
}
|
||||
else if ( !val && (prog >= a.maxval) )
|
||||
{
|
||||
achievementstate.Insert(a.basename,"1");
|
||||
val = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( (val == 1) && (gametic > lastachievementnotify) )
|
||||
|
|
@ -118,8 +138,8 @@ extend Class SWWMStaticHandler
|
|||
// fallback icon if one is not found
|
||||
if ( !ac.icon.IsValid() ) ac.icon = TexMan.CheckForTexture("graphics/Achievements/DefaultAchievement.png",TexMan.Type_Any);
|
||||
ac.maxval = ln[1].ToInt();
|
||||
// special case for maxval
|
||||
if ( ac.maxval && (ac.basename == "allcoll") )
|
||||
// special cases for maxval == -1 (currently only one, so this is simplified)
|
||||
if ( (ac.maxval == -1) && (ac.basename == "allcoll") )
|
||||
{
|
||||
int nc = 0;
|
||||
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
||||
|
|
@ -133,6 +153,12 @@ extend Class SWWMStaticHandler
|
|||
}
|
||||
ac.maxval = nc;
|
||||
}
|
||||
// bitfield
|
||||
else if ( ac.maxval < -1 )
|
||||
{
|
||||
ac.bitfield = true;
|
||||
ac.maxval = abs(ac.maxval);
|
||||
}
|
||||
ac.hasformat = (ln[2]~=="yes");
|
||||
achievements.Push(ac);
|
||||
bidx++;
|
||||
|
|
@ -210,7 +236,7 @@ extend Class SWWMStaticHandler
|
|||
}
|
||||
achievementprogress.Insert(keys[i].Left(colon),keys[i].Mid(colon+1));
|
||||
}
|
||||
// load achievement info and trim any bogus keys
|
||||
// load achievement info and trim any bogus keys, as well as adding any new ones that are missing
|
||||
ParseAchievementList(achievementinfo);
|
||||
let di = DictionaryIterator.Create(achievementstate);
|
||||
while ( di.Next() )
|
||||
|
|
@ -223,6 +249,11 @@ extend Class SWWMStaticHandler
|
|||
deleteme = false;
|
||||
break;
|
||||
}
|
||||
if ( deleteme )
|
||||
{
|
||||
if ( developer >= 2 ) Console.Printf("Deleting bogus achievement state %s = %s",key,di.Value());
|
||||
achievementstate.Remove(key);
|
||||
}
|
||||
}
|
||||
di = DictionaryIterator.Create(achievementprogress);
|
||||
while ( di.Next() )
|
||||
|
|
@ -236,6 +267,24 @@ extend Class SWWMStaticHandler
|
|||
deleteme = false;
|
||||
break;
|
||||
}
|
||||
if ( deleteme )
|
||||
{
|
||||
if ( developer >= 2 ) Console.Printf("Deleting bogus achievement progress %s = %s",key,di.Value());
|
||||
achievementprogress.Remove(key);
|
||||
}
|
||||
}
|
||||
for ( int i=0; i<achievementinfo.Size(); i++ )
|
||||
{
|
||||
if ( achievementstate.At(achievementinfo[i].basename) == "" )
|
||||
{
|
||||
if ( developer >= 2 ) Console.Printf("Adding missing achievement state %s",achievementinfo[i].basename);
|
||||
achievementstate.Insert(achievementinfo[i].basename,"0");
|
||||
}
|
||||
if ( achievementinfo[i].maxval && (achievementprogress.At(achievementinfo[i].basename) == "") )
|
||||
{
|
||||
if ( developer >= 2 ) Console.Printf("Adding missing achievement progress %s",achievementinfo[i].basename);
|
||||
achievementprogress.Insert(achievementinfo[i].basename,"0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -798,10 +798,10 @@ Class CBoxLight : SpotLightAttenuated
|
|||
Destroy();
|
||||
return;
|
||||
}
|
||||
Vector2 ofs = ((special1<2)?8:-8,(special1%2)?12:-12);
|
||||
Vector2 ofs = ((special1<2)?8:-8,(special1%2)?12:-12)*target.scale.x;
|
||||
double ang = (special1<2)?0:180;
|
||||
angle = target.angle+ang;
|
||||
SetOrigin(target.Vec3Offset(ofs.x*cos(target.angle)-ofs.y*sin(target.angle),ofs.y*cos(target.angle)+ofs.x*sin(target.angle),10),true);
|
||||
SetOrigin(target.Vec3Offset(ofs.x*cos(target.angle)-ofs.y*sin(target.angle),ofs.y*cos(target.angle)+ofs.x*sin(target.angle),10*target.scale.y),true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -883,9 +883,9 @@ Class Chancebox : Actor
|
|||
break;
|
||||
}
|
||||
if ( cz < bceil ) bceil = cz;
|
||||
if ( cz-fz < 56 ) continue; // too short
|
||||
if ( cz-fz < 60 ) continue; // too short
|
||||
bool blockedff = false;
|
||||
BlockThingsIterator bt = BlockThingsIterator.CreateFromPos(testpos.x,testpos.y,fz,56,256,false);
|
||||
BlockThingsIterator bt = BlockThingsIterator.CreateFromPos(testpos.x,testpos.y,fz,60,256,false);
|
||||
while ( bt.Next() )
|
||||
{
|
||||
if ( !bt.Thing ) continue;
|
||||
|
|
@ -901,10 +901,10 @@ Class Chancebox : Actor
|
|||
spots.Push(sp);
|
||||
}
|
||||
// spawn at the real floor
|
||||
if ( bceil-testpos.z < 56 ) continue; // too short
|
||||
if ( bceil-testpos.z < 60 ) continue; // too short
|
||||
// don't spawn on sky or hurtfloors if there are 3D floors
|
||||
if ( (nffloor > 0) && ((s.GetTexture(0) == skyflatnum) || (s.damageamount > 0)) ) continue;
|
||||
BlockThingsIterator bt = BlockThingsIterator.CreateFromPos(testpos.x,testpos.y,testpos.z,56,256,false);
|
||||
BlockThingsIterator bt = BlockThingsIterator.CreateFromPos(testpos.x,testpos.y,testpos.z,60,256,false);
|
||||
while ( bt.Next() )
|
||||
{
|
||||
if ( !bt.Thing ) continue;
|
||||
|
|
@ -954,7 +954,19 @@ Class Chancebox : Actor
|
|||
if ( (candidates.Size() <= 0) || invoker.dud )
|
||||
{
|
||||
// no candidates? just burst into treats
|
||||
if ( Random[Chancebox](0,1) )
|
||||
if ( (scale.x > .5) && (Random[Chancebox](0,int(9*scale.x*scale.x)) < 3) )
|
||||
{
|
||||
// spawn another smaller chancebox
|
||||
// (chance increases for the inner box, up until a scale factor of 50% is reached)
|
||||
let a = Spawn("Chancebox",pos+(0,0,3*scale.y));
|
||||
a.bDROPPED = false;
|
||||
a.bNOGRAVITY = false;
|
||||
a.vel.z = FRandom[Chancebox](2,4);
|
||||
a.angle = angle;
|
||||
a.scale *= scale.x-.125;
|
||||
if ( target && (a.scale.x <= .5) ) SWWMUtility.MarkAchievement("matryoshka",target.player);
|
||||
}
|
||||
else if ( Random[Chancebox](0,1) )
|
||||
{
|
||||
Class<Inventory> vipammodrop = null;
|
||||
if ( SWWMUtility.ItemExists("Ynykron") && Random[Chancebox](0,1) ) vipammodrop = "YnykronAmmo";
|
||||
|
|
@ -1109,14 +1121,14 @@ Class Chancebox : Actor
|
|||
}
|
||||
action void A_Confetti()
|
||||
{
|
||||
A_StartSound("misc/tada",CHAN_ITEM);
|
||||
A_StartSound("misc/tada",CHAN_ITEM,pitch:1./scale.x);
|
||||
double ang, pt;
|
||||
int numpt = Random[ExploS](100,120);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
ang = FRandom[ExploS](0,360);
|
||||
pt = FRandom[ExploS](-90,30);
|
||||
let c = Spawn("FancyConfetti",Vec3Offset(0,0,16));
|
||||
let c = Spawn("FancyConfetti",Vec3Offset(0,0,16*scale.y));
|
||||
c.vel = (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[ExploS](2,8);
|
||||
}
|
||||
}
|
||||
|
|
@ -1209,6 +1221,7 @@ Class Chancebox : Actor
|
|||
SWWMLoreLibrary.Add(user.player,"Chancebox");
|
||||
specialf2 = AngleTo(user);
|
||||
SetStateLabel("PreActive");
|
||||
target = user;
|
||||
return true;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
|
|
@ -1230,6 +1243,7 @@ Class Chancebox : Actor
|
|||
dud = true;
|
||||
break;
|
||||
}
|
||||
A_SetSize(default.radius*scale.x,default.height*scale.y);
|
||||
}
|
||||
Default
|
||||
{
|
||||
|
|
@ -1241,6 +1255,7 @@ Class Chancebox : Actor
|
|||
+SOLID;
|
||||
+INTERPOLATEANGLES;
|
||||
+COUNTITEM;
|
||||
+CANPASS;
|
||||
Species "Chancebox";
|
||||
}
|
||||
States
|
||||
|
|
@ -1263,7 +1278,7 @@ Class Chancebox : Actor
|
|||
{
|
||||
angle = specialf2;
|
||||
specialf1 = angle;
|
||||
A_StartSound("misc/drumroll",CHAN_WEAPON);
|
||||
A_StartSound("misc/drumroll",CHAN_WEAPON,pitch:1./scale.x);
|
||||
}
|
||||
XZW1 A 1
|
||||
{
|
||||
|
|
@ -1272,23 +1287,26 @@ Class Chancebox : Actor
|
|||
pitch = FRandom[Chancebox](-5,5);
|
||||
roll = FRandom[Chancebox](-5,5);
|
||||
special1++;
|
||||
return A_JumpIf(special1>40,"BlowUp");
|
||||
return A_JumpIf(special1>int(40*scale.x),"BlowUp");
|
||||
}
|
||||
Wait;
|
||||
BlowUp:
|
||||
XZW2 A 1
|
||||
{
|
||||
A_SetSize(12,3);
|
||||
A_SetSize(default.radius*scale.x,2.5*scale.y);
|
||||
A_QuakeEx(2,2,2,9,0,500,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:.2);
|
||||
A_StartSound("chancebox/explode",CHAN_VOICE);
|
||||
A_StartSound("chancebox/explode",CHAN_VOICE,pitch:1./scale.x);
|
||||
angle = specialf1;
|
||||
pitch = roll = 0;
|
||||
let t = Spawn("ChanceboxTop",Vec3Offset(0,0,20));
|
||||
let t = Spawn("ChanceboxTop",Vec3Offset(0,0,20*scale.y));
|
||||
t.angle = angle;
|
||||
let s1 = Spawn("ChanceboxSide",level.Vec3Offset(pos,(RotateVector((12,0),angle+90),0)));
|
||||
t.scale = scale;
|
||||
let s1 = Spawn("ChanceboxSide",level.Vec3Offset(pos,(RotateVector((12*scale.x,0),angle+90),0)));
|
||||
s1.angle = angle+90;
|
||||
let s2 = Spawn("ChanceboxSide",level.Vec3Offset(pos,(RotateVector((12,0),angle-90),0)));
|
||||
s1.scale = scale;
|
||||
let s2 = Spawn("ChanceboxSide",level.Vec3Offset(pos,(RotateVector((12*scale.x,0),angle-90),0)));
|
||||
s2.angle = angle-90;
|
||||
s2.scale = scale;
|
||||
A_DropSomething();
|
||||
}
|
||||
XZW2 BCDEFGHIJKLMNO 1;
|
||||
|
|
@ -1312,6 +1330,7 @@ Class ChanceboxTop : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
vel = (0,0,20);
|
||||
A_SetSize(default.radius*scale.x,default.height*scale.y);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -1347,6 +1366,7 @@ Class ChanceboxSide : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
vel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch))*20;
|
||||
A_SetSize(default.radius*scale.x,default.height*scale.y);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
|
|||
|
|
@ -91,7 +91,13 @@ Class SWWMAchievementMenu : GenericMenu
|
|||
if ( a.maxval && (!ShouldObscure || hasprogress) )
|
||||
{
|
||||
yy += (newsmallfont.GetHeight()+2)*CleanYFac_1;
|
||||
int val = a.val;
|
||||
int val = 0;
|
||||
if ( a.bitfield )
|
||||
{
|
||||
for ( int i=0; i<a.maxval; i++ )
|
||||
val += !!(a.val&(1<<i));
|
||||
}
|
||||
else val = a.val;
|
||||
val = clamp(val,0,a.maxval);
|
||||
if ( completed ) str = String.Format("%s / %s",SWWMUtility.ThousandsNum(a.maxval),SWWMUtility.ThousandsNum(a.maxval));
|
||||
else str = String.Format("%s / %s",SWWMUtility.ThousandsNum(val),SWWMUtility.ThousandsNum(a.maxval));
|
||||
|
|
|
|||
|
|
@ -98,6 +98,20 @@ Class SWWMUtility
|
|||
}
|
||||
hnd.achievementprogress.Insert(pvar,String.Format("%g",pval.ToDouble()+inc));
|
||||
}
|
||||
// for bitfields
|
||||
static clearscope void AchievementProgressOr( String pvar, int val, PlayerInfo p = null )
|
||||
{
|
||||
if ( !p || (p != players[consoleplayer]) ) return;
|
||||
let hnd = SWWMStaticHandler(StaticEventHandler.Find("SWWMStaticHandler"));
|
||||
if ( !hnd ) return;
|
||||
String pval = hnd.achievementprogress.At(pvar);
|
||||
if ( pval == "" )
|
||||
{
|
||||
if ( developer >= 2 ) Console.Printf("AchievementProgress: achievement '"..pvar.."' not found");
|
||||
return;
|
||||
}
|
||||
hnd.achievementprogress.Insert(pvar,String.Format("%d",pval.ToInt()|val));
|
||||
}
|
||||
|
||||
// gets the names of all mod cvars
|
||||
static clearscope void GetCVars( out Array<String> cvarlist )
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue