diff --git a/achievements.lst b/achievements.lst index 3e202bdd8..51a24e88f 100644 --- a/achievements.lst +++ b/achievements.lst @@ -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 diff --git a/graphics/Achievements/AchievementCheat.png b/graphics/Achievements/AchievementMatryoshka.png similarity index 100% rename from graphics/Achievements/AchievementCheat.png rename to graphics/Achievements/AchievementMatryoshka.png diff --git a/language.def_base b/language.def_base index 0b46aef1b..5d9a57f61 100644 --- a/language.def_base +++ b/language.def_base @@ -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"; diff --git a/language.es_base b/language.es_base index bb31a875a..cd9872ce9 100644 --- a/language.es_base +++ b/language.es_base @@ -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"; diff --git a/language.version b/language.version index fc6ef4bac..ebe159d39 100644 --- a/language.version +++ b/language.version @@ -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-"; diff --git a/zscript/handler/swwm_handler_cheats.zsc b/zscript/handler/swwm_handler_cheats.zsc index bbf46cbf0..178b1fec9 100644 --- a/zscript/handler/swwm_handler_cheats.zsc +++ b/zscript/handler/swwm_handler_cheats.zsc @@ -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; diff --git a/zscript/handler/swwm_statichandler_achievements.zsc b/zscript/handler/swwm_statichandler_achievements.zsc index f9c0b4f52..b59faecd0 100644 --- a/zscript/handler/swwm_statichandler_achievements.zsc +++ b/zscript/handler/swwm_statichandler_achievements.zsc @@ -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) ) + { + 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= 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= 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"); + } } } diff --git a/zscript/items/swwm_funstuff.zsc b/zscript/items/swwm_funstuff.zsc index 054ee693d..8e4ad79f7 100644 --- a/zscript/items/swwm_funstuff.zsc +++ b/zscript/items/swwm_funstuff.zsc @@ -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 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; i40,"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 { diff --git a/zscript/menu/swwm_achievementmenu.zsc b/zscript/menu/swwm_achievementmenu.zsc index d84977447..467ee464e 100644 --- a/zscript/menu/swwm_achievementmenu.zsc +++ b/zscript/menu/swwm_achievementmenu.zsc @@ -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= 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 cvarlist )