0.9.7b release:

- Quick Grenade function added.
 - Blow Kiss gesture added (+score bonus).
 - Fix Hellblazer not autoswitching ammo on empty reload.
 - Fix Eviscerator chunk glows not dying with the chunk itself.
 - Fix give cheat giving excess powerups/weapons inflating your score.
 - Fix dashing over bridge actors.
 - Fix dual Explodium Guns not autoswitching to single when dropping one from the inventory menu.
 - Adjust manual reload priority for dual Explodium Guns (gun with less bullets left will be reloaded first).
 - Add default binds for all actions.
This commit is contained in:
Mari the Deer 2020-09-21 21:35:23 +02:00
commit 5e60973d1b
29 changed files with 519 additions and 47 deletions

View file

@ -392,6 +392,7 @@ The scoring system is pretty straightforward. Each enemy you kill will give you
* +500 if the enemy was killed with the **Deep Impact** primary (humiliation).
* +300 if the enemy was killed with your butt while dashing (no, seriously).
* +600 if the enemy was killed with a blown kiss (oh my~).
* x2 for an overkill (enemy was gibbed or received twice its base health in damage).
* x1.5 for each combo level, up to x8 in steps of x0.5. Kills are considered combos if multiple enemies are killed within 5 seconds of each other.
* +100 for killing an enemy without having taken damage since last spawn, with extra +10 boosts for consecutive kills (extra boosts taper off after 10x).

View file

@ -6,7 +6,7 @@
- Omnibusting (all weapons can bust walls)
- Infinite fuel
- Confetti gibs
- Keen replacement (need ideas)
- Keen replacement
- Achievements
- Extra Demolitionist Menu tabs (radio, minigames)
- Collectables

View file

@ -55,10 +55,10 @@ user int swwm_numscale = 0; // damnum scaling (0 = use GZDoom scaling)
user int swwm_poiscale = 0; // point of interest scaling (0 = use GZDoom scaling)
user int swwm_detscale = 0; // item sense scaling (0 = use GZDoom scaling)
server bool swwm_blood = false; // custom blood/gibbing
server int swwm_maxblood = 1000; // max blood effects at any time
server int swwm_maxgibs = 200; // max gibs at any time
server int swwm_maxblood = 400; // max blood effects at any time
server int swwm_maxgibs = 100; // max gibs at any time
server int swwm_maxcasings = 200; // max casings and spent mags at any time
server int swwm_maxdebris = 1000; // max chunks of debris at any time
server int swwm_maxdebris = 500; // max chunks of debris at any time
user bool swwm_fuzz = true; // allows toggling the fuzz shader on the demolitionist menus, useful if you're streaming/recording since it destroys the encoding quality
user bool swwm_cbtpause = true; // wallbuster menu pauses the game
user noarchive int swwm_cbtmeme = 0; // easter egg, hidden cvar

View file

@ -3,16 +3,25 @@ addmenukey "$SWWM_PRIMARYFIRE" "+attack"
addmenukey "$SWWM_SECONDARYFIRE" "+altattack"
addmenukey "$SWWM_RELOADFIRE" "+reload"
addmenukey "$SWWM_ZOOMFIRE" "+zoom"
//addmenukey "$SWWM_EXTRAFIRE" "+user4"
addmenukey "$SWWM_EXTRAFIRE" "+user4"
addmenukey "$SWWM_MELEE" "+user1"
addmenukey "$SWWM_DASH" "+user2"
addmenukey "$SWWM_ITEMSENSE" "+user3"
addmenukey "$SWWM_GESTURE1" "netevent swwmgesture 0"
addmenukey "$SWWM_GESTURE2" "netevent swwmgesture 1"
addmenukey "$SWWM_GESTURE3" "netevent swwmgesture 2"
//addmenukey "$SWWM_GESTURE4" "netevent swwmgesture 3"
addmenukey "$SWWM_GESTURE4" "netevent swwmgesture 3"
addmenukey "$SWWM_KBASE" "openmenu SWWMKnowledgeBaseMenu"
defaultbind "j" "netevent swwmgesture 0"
defaultbind "k" "netevent swwmgesture 1"
defaultbind "l" "netevent swwmgesture 2"
defaultbind "mouse1" "+attack"
defaultbind "mouse2" "+altattack"
defaultbind "r" "+reload"
defaultbind "e" "+zoom"
defaultbind "g" "+user4"
defaultbind "f" "+user1"
defaultbind "alt" "+user2"
defaultbind "i" "+user3"
defaultbind "h" "netevent swwmgesture 0"
defaultbind "j" "netevent swwmgesture 1"
defaultbind "k" "netevent swwmgesture 2"
defaultbind "l" "netevent swwmgesture 3"
defaultbind "q" "openmenu SWWMKnowledgeBaseMenu"

View file

@ -675,6 +675,7 @@ O_DASH = "%o was discombobulated by a very fast moving %k.";
O_BUTT = "%o received a lethal impact from %k's butt.";
O_JUMP = "%o was stepped on %k.";
O_MELEE = "%o was K.O.'d by %k.";
O_DOKIDOKI = "%o was defeated by %k's power of love.";
O_MOTH = "%%o was assaulted by %s's moths.";
O_MOTH2 = "%o was assaulted by moths.";
O_MASHIRO1 = "%o should have kept the lights on.";
@ -796,6 +797,7 @@ SWWM_UNIT_KILOMETER = "km";
SWWM_UNIT_KPH = "km/h";
SWWM_UNIT_LITER = "l";
SWWM_YOURSELF = "Yourself";
SWWM_DOKIDOKI = "The Power of Love™";
// boss tags
BT_BRUISERS = "Bruiser Brothers";
BT_CYBIE = "Tyrant of Babel";
@ -842,6 +844,7 @@ SWWM_LEG = "Legendary ";
SWWM_LEGPREFIX = "L";
SWWM_SHAMEFUL = "Humiliation";
SWWM_BUTTSLAM = "Buttslam";
SWWM_LOVED = "L\cg♥\c-VE";
// score messages
SWWM_FINDSECRET = "\cf%s\cf found a secret. +%d\c-";
SWWM_FINDKEY = "\cf%s\cf got the %s\cf. +%d\c-";

View file

@ -628,6 +628,7 @@ O_DASH = "%o fue descuajeringad@[ao_esp] a todo gas por %k.";
O_BUTT = "%o recibió un impacto letal del trasero de %k.";
O_JUMP = "%o fue pisotead@[ao_esp] por %k.";
O_MELEE = "%o fue noquead@[ao_esp] por %k.";
O_DOKIDOKI = "%o fue derrotad@[ao_esp] por el poder del amor de %k.";
O_MOTH = "%%o fue asaltad@[ao_esp] por las polillas de %s.";
O_MOTH2 = "%o fue asaltad@[ao_esp] por polillas.";
O_MASHIRO1 = "%o debería haber dejado la luz encendida.";
@ -743,6 +744,7 @@ SWWM_YNYKRONREADY = "Artefacto Ynykron listo para disparar.";
SWWM_TITLEPRESENTS = "presenta";
SWWM_TITLEMODBY = "un mod de \cxMarisa Kirisame";
SWWM_YOURSELF = "Tú";
SWWM_DOKIDOKI = "El Poder del Amor™";
// boss tags
BT_BRUISERS = "Hermanos de Guerra";
BT_CYBIE = "Tirano de Babel";

View file

@ -1,2 +1,2 @@
[default]
SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.6b r555 \cu(Sun 20 Sep 22:25:34 CEST 2020)";
SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.7b r557 \cu(Mon 21 Sep 21:39:06 CEST 2020)";

View file

@ -391,6 +391,36 @@ Model "Demolitionist"
FrameIndex XZWD B 0 338
FrameIndex XZWD C 0 339
FrameIndex XZWD D 0 340
// Blow Kiss
FrameIndex XZWD E 0 343
FrameIndex XZWD F 0 344
FrameIndex XZWD G 0 345
FrameIndex XZWD H 0 346
SurfaceSkin 0 1 "DemoFace_Blink.png"
FrameIndex XZWD I 0 347
FrameIndex XZWD J 0 348
FrameIndex XZWD K 0 349
FrameIndex XZWD L 0 350
SurfaceSkin 0 1 "DemoFace_Default.png"
FrameIndex XZWD M 0 351
FrameIndex XZWD N 0 352
FrameIndex XZWD O 0 353
SurfaceSkin 0 1 "DemoFace_Wink.png"
FrameIndex XZWD P 0 354
FrameIndex XZWD Q 0 355
FrameIndex XZWD R 0 356
FrameIndex XZWD S 0 357
FrameIndex XZWD T 0 358
FrameIndex XZWD U 0 359
SurfaceSkin 0 1 "DemoFace_Default.png"
FrameIndex XZWD V 0 360
FrameIndex XZWD W 0 361
// TODO Crouched Wave
// TODO Crouched Thumbs Up
// TODO Crouched Victory
// TODO Crouched Blow Kiss
// TODO Swim
// TODO Float
}
// Voodoo Doll
@ -452,7 +482,6 @@ Model "SWWMGesture"
SurfaceSkin 0 2 "DemoSoft.png"
AngleOffset -90
Scale -0.005 0.0025 0.005
IGNORETRANSLATION
// Wave
FrameIndex XZW1 A 0 0
@ -508,4 +537,48 @@ Model "SWWMGesture"
FrameIndex XZW2 W 0 51
FrameIndex XZW2 X 0 52
FrameIndex XZW2 Y 0 53
// Blow Kiss
FrameIndex XZW2 Z 0 55
FrameIndex XZW3 A 0 56
FrameIndex XZW3 B 0 57
FrameIndex XZW3 C 0 58
FrameIndex XZW3 D 0 59
FrameIndex XZW3 E 0 60 // smooch
FrameIndex XZW3 F 0 61
FrameIndex XZW3 G 0 62
FrameIndex XZW3 H 0 63
FrameIndex XZW3 I 0 64
FrameIndex XZW3 J 0 65
FrameIndex XZW3 K 0 66 // blow
FrameIndex XZW3 L 0 67
FrameIndex XZW3 M 0 68
FrameIndex XZW3 N 0 69
FrameIndex XZW3 O 0 70
FrameIndex XZW3 P 0 71
FrameIndex XZW3 Q 0 72
FrameIndex XZW3 R 0 73
// Quick Grenade
SurfaceSkin 0 3 "ExplodiumGun.png"
FrameIndex XZW3 S 0 75
FrameIndex XZW3 T 0 76
FrameIndex XZW3 U 0 77
FrameIndex XZW3 V 0 78
FrameIndex XZW3 W 0 79
FrameIndex XZW3 X 0 80 // arm
FrameIndex XZW3 Y 0 81
FrameIndex XZW3 Z 0 82
FrameIndex XZW4 A 0 83
FrameIndex XZW4 B 0 84
FrameIndex XZW4 C 0 85
FrameIndex XZW4 D 0 86 // swing
FrameIndex XZW4 E 0 87
FrameIndex XZW4 F 0 88
FrameIndex XZW4 G 0 89
FrameIndex XZW4 H 0 90
SurfaceSkin 0 3 ""
FrameIndex XZW4 I 0 91 // throw
FrameIndex XZW4 J 0 92
FrameIndex XZW4 K 0 93
FrameIndex XZW4 L 0 94
FrameIndex XZW4 M 0 95
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
models/GestureArms.blend1 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
palettes/LovePal.pal Normal file

Binary file not shown.

View file

@ -358,6 +358,8 @@ demolitionist/whitl1 sounds/demolitionist/demowhitl1.ogg
demolitionist/whitl2 sounds/demolitionist/demowhitl2.ogg
$random demolitionist/whitl { demolitionist/whitl1 demolitionist/whitl2 }
demolitionist/buttslam sounds/demolitionist/demobutt.ogg
demolitionist/smooch sounds/demolitionist/demokiss.ogg
demolitionist/blowkiss sounds/demolitionist/demoblow.ogg
$playersound demolitionist neutral *grunt DSEMPTY
$playeralias demolitionist neutral *pain100 demolitionist/lopain
@ -838,6 +840,7 @@ misc/sundowner sounds/SUNDOWNER.ogg
misc/emone sounds/EMONE.ogg
misc/drumroll sounds/DRUMROLL.ogg
misc/tada sounds/TADA.ogg
misc/heart sounds/KOKORO.ogg
misc/gibber1 sounds/general/Gib1.ogg
misc/gibber2 sounds/general/Gib2.ogg
misc/gibber3 sounds/general/Gib3.ogg

BIN
sounds/KOKORO.ogg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
sprites/DOKIA0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -1771,6 +1771,7 @@ Class Hellblazer : SWWMWeapon
Reload:
XZW2 A 2
{
if ( (invoker.clipcount <= 0) && (CountInv(invoker.nextammo) <= 0) ) A_PickNextAmmo();
if ( (invoker.clipcount >= invoker.LoadedCapacity()) && (invoker.loadammo == invoker.nextammo) )
return A_JumpByAmmoType("Idle_1","Idle_2","Idle_3","Idle_4","Idle_G");
return A_JumpByAmmoType("Unload_1","Unload_2","Unload_3","Unload_4","Unload_G");

View file

@ -87,9 +87,10 @@ Class EvisceratorChunkGlow : Actor
override void Tick()
{
if ( isFrozen() ) return;
if ( !EvisceratorChunk(target) )
if ( !EvisceratorChunk(target) || EvisceratorChunk(target).justdied )
{
Destroy();
Scale *= .9;
A_FadeOut();
return;
}
SetOrigin(target.pos,true);

View file

@ -994,6 +994,17 @@ Class SWWMHandler : EventHandler
scr.xcnt = ++ofs;
}
}
else if ( e.DamageType == 'Love' )
{
score += 600;
if ( scr )
{
scr.xscore[ofs] = 0;
scr.xtcolor[ofs] = Font.FindFontColor('BlushPink');
scr.xstr[ofs] = StringTable.Localize("$SWWM_LOVED");
scr.xcnt = ++ofs;
}
}
if ( (e.Damage >= e.Thing.GetSpawnHealth()*2) || (((e.Thing.Health <= e.Thing.GetGibHealth()) || (e.DamageSource.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageType == 'Extreme')) && !e.DamageSource.bNOEXTREMEDEATH && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH)) )
{
score *= 2;
@ -1484,18 +1495,7 @@ Class SWWMHandler : EventHandler
if ( (e.player == -1) || !playeringame[e.player] || !players[e.player].mo ) return;
let mo = players[e.player].mo;
if ( (mo.Health <= 0) || !(mo is 'Demolitionist') ) return;
switch ( e.Args[0] )
{
case 1:
SWWMGesture.SetGesture(mo,1);
break;
case 2:
SWWMGesture.SetGesture(mo,2);
break;
default:
SWWMGesture.SetGesture(mo,0);
break;
}
SWWMGesture.SetGesture(mo,e.Args[0]);
}
if ( e.IsManual ) return;
if ( e.Name.Left(14) ~== "swwmstoregive." )

View file

@ -1932,6 +1932,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
str = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_STATFAVWEAP"));
if ( stats.favweapon == -1 ) str = str.."N/A";
else if ( stats.wstats[stats.favweapon].w == 'SWWMWeapon' ) str = str..StringTable.Localize("$SWWM_YOURSELF");
else if ( stats.wstats[stats.favweapon].w == 'SWWMGesture' ) str = str..StringTable.Localize("$SWWM_DOKIDOKI");
else
{
let def = GetDefaultByType(stats.wstats[stats.favweapon].w);

View file

@ -100,7 +100,7 @@ Class Demolitionist : PlayerPawn
health = min(health+amount,1000);
player.health = health;
}
else player.health = health = 1000;
else player.health = health = 200;
}
if ( giveall || (name ~== "backpack") )
{
@ -210,6 +210,9 @@ Class Demolitionist : PlayerPawn
{
let type = (class<Weapon>)(AllActorClasses[i]);
if ( !type || (type == "Weapon") ) continue;
// Don't give already owned weapons
let owned = FindInventory(type);
if ( owned && (owned.Amount >= owned.MaxAmount) ) continue;
// Don't give replaced weapons unless the replacement was done by Dehacked.
let rep = GetReplacement(type);
if ( (rep == type) || (rep is "DehackedPickup") )
@ -231,6 +234,9 @@ Class Demolitionist : PlayerPawn
let type = (class<Inventory>)(AllActorClasses[i]);
if ( !type ) continue;
if ( !(gameinfo.gametype&(GAME_Hexen|GAME_Strife)) && (type is 'AmmoFabricator') ) continue; // no fabricators before hexen
// Don't give maxed items
let owned = FindInventory(type);
if ( owned && (owned.Amount >= owned.MaxAmount) ) continue;
let def = GetDefaultByType (type);
if ( def.Icon.isValid() &&
!(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor") && !(type is "Key") )
@ -495,6 +501,9 @@ Class Demolitionist : PlayerPawn
if ( player.onground && (player.jumptics < -18) )
player.jumptics = 0;
}
// quick grenade
if ( (player.playerstate != PST_DEAD) && (player.cmd.buttons&BT_USER4) )
SWWMGesture.SetGesture(self,-1);
}
override void Tick()
{
@ -690,12 +699,13 @@ Class Demolitionist : PlayerPawn
Vector3 diff = level.Vec3Diff(pos,a.pos);
Vector3 dirto = diff.unit();
if ( dir dot dirto < .1 ) continue;
if ( a.bACTLIKEBRIDGE && (diff.z <= -a.Height) ) continue; // don't bump bridges if hit by above
// large monsters will stop the player (unless hit from above if we're going at ground pound speed)
A_QuakeEx(4,4,4,10,0,128,"",QF_RELATIVE|QF_SCALEDOWN);
A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
a.A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
bumptic = gametic+int(20+spd/4.);
if ( (diff.z < a.height) && (lastvelz >= -25) && (a.bDONTTHRUST || (a.Mass >= maxmass) || (!a.bSHOOTABLE && !a.bPUSHABLE && (a.Health > 0))) && a.bSOLID && (dir dot dirto > .65) )
if ( (diff.z < a.height) && (lastvelz >= -25) && (a.bDONTTHRUST || a.bACTLIKEBRIDGE || (a.Mass >= maxmass) || (!a.bSHOOTABLE && !a.bPUSHABLE && (a.Health > 0))) && a.bSOLID && (dir dot dirto > .65) )
{
if ( bumped ) continue;
bumped = true;
@ -1970,6 +1980,10 @@ Class Demolitionist : PlayerPawn
#### # 3;
XZW6 EFGHIJKLMNOPQRSTUVW 3;
Goto Spawn+1;
BlowKiss:
#### # 3;
XZWD EFGHIJKLMNOPQRSTUVW 3;
Goto Spawn+1;
Missile:
// attacking
#### # 2;
@ -2447,6 +2461,240 @@ Class CastDemolitionist : Actor
}
}
Class LoveHeartTrail : Actor
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
Alpha .1;
+NOGRAVITY;
+NOBLOCKMAP;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
+FORCEXYBILLBOARD;
}
override void Tick()
{
if ( isFrozen() ) return;
A_FadeOut(.01);
scale *= .95;
}
States
{
Spawn:
DOKI A -1 Bright;
Stop;
}
}
Class LoveHeartSparkle : Actor
{
Default
{
Radius .1;
Height 0.;
Scale .03;
+NOGRAVITY;
+NOBLOCKMAP;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
+FORCEXYBILLBOARD;
}
override void PostBeginPlay()
{
Scale *= FRandom[ExploS](.75,1.5);
specialf1 = FRandom[ExploS](.95,.98);
specialf2 = FRandom[ExploS](.01,.03);
vel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch))*FRandom[ExploS](2,8);
}
override void Tick()
{
if ( isFrozen() ) return;
A_SetScale(scale.x*specialf1);
A_FadeOut(specialf2);
Vector3 dir = vel;
double magvel = dir.length();
magvel *= .99;
if ( magvel > 0. )
{
dir /= magvel;
dir += .2*(FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1));
vel = dir.unit()*magvel;
}
SetOrigin(level.Vec3Offset(pos,vel),true);
}
States
{
Spawn:
DOKI A -1 Bright;
Stop;
}
}
Class LoveHeartBurstLight : PaletteLight
{
Default
{
Tag "LovePal";
ReactionTime 15;
Args 0,0,0,150;
}
}
Class LoveHeart : Actor
{
Default
{
Obituary "$O_DOKIDOKI";
DamageType 'Love';
DamageFunction (clamp(special2,5,15));
Radius 4;
Height 4;
Speed 10;
Scale .2;
PROJECTILE;
+BLOODLESSIMPACT;
+FORCEXYBILLBOARD;
+SEEKERMISSILE;
+FOILINVUL;
+PAINLESS;
+NODAMAGETHRUST;
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
let raging = RagekitPower(self.target.FindInventory("RagekitPower"));
if ( target.IsFriend(self.target) || (target is 'MBFHelperDog') )
{
int healamt = clamp(special2,5,15);
if ( raging )
{
healamt *= 8;
raging.DoHitFX();
}
if ( target.GiveBody(healamt,target.GetSpawnHealth()) )
{
SWWMScoreObj.Spawn(healamt,target.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+target.Height/2),Font.CR_BLUE);
SWWMHandler.DoFlash(target,Color(32,224,128,255),10);
}
if ( target is 'MBFHelperDog' )
{
// befriend good doggo
target.bFRIENDLY = true;
if ( deathmatch )
target.SetFriendPlayer(self.target.player);
}
return 0;
}
let bread = target.FindState("Pain");
if ( bread ) target.SetState(bread);
if ( raging )
{
damage *= 8;
raging.DoHitFX();
}
return damage;
}
override int SpecialMissileHit( Actor victim )
{
if ( !victim.bSHOOTABLE && (victim != tracer) ) return 1;
if ( tracer && (victim != tracer) ) return 1;
return -1;
}
action void A_HeartTick()
{
special1++;
if ( !(special1%3) && (special2 > 0) ) special2--;
A_SetScale(.2+.02*sin(special1*.25*TICRATE));
double magvel = vel.length();
if ( magvel > 0 )
{
Vector3 dir = vel/magvel;
vel = dir*min(30,magvel*1.1);
}
double steppy = vel.length()/4.;
for ( int i=2; i<6; i++ )
{
Vector3 dir2 = vel.unit();
let t = Spawn("LoveHeartTrail",level.Vec3Offset(pos,-dir2*steppy*i));
t.scale = scale;
}
int numpt = Random[ExploS](1,3);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("LoveHeartSparkle",pos);
s.angle = FRandom[ExploS](0,360);
s.pitch = FRandom[ExploS](-90,90);
}
if ( !tracer || (tracer.Health <= 0) ) return;
double mag = vel.length();
vel = mag*(level.Vec3Diff(pos,tracer.Vec3Offset(0,0,tracer.height/2)).unit()*mag*6./TICRATE+vel).unit();
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_StartSound("misc/heart",CHAN_WEAPON);
A_AttachLight('LOVELIGHT',DynamicLight.PointLight,Color(255,176,208),80,80,DYNAMICLIGHT.LF_ATTENUATE);
special2 = 25;
}
action void A_HeartBurst()
{
A_SetRenderStyle(1.,STYLE_Add);
A_RemoveLight('LOVELIGHT');
A_QuakeEx(2,2,2,8,0,300,"",QF_RELATIVE|QF_SCALEDOWN);
A_StartSound("bestsound",CHAN_VOICE);
Spawn("LoveHeartBurstLight",pos);
int numpt = Random[ExploS](10,15);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.5,4);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(10,8,9)*Random[ExploS](20,25));
s.special1 = Random[ExploS](1,3);
s.scale *= 2.;
s.alpha *= .6;
}
numpt = Random[ExploS](40,50);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("LoveHeartSparkle",pos);
s.angle = FRandom[ExploS](0,360);
s.pitch = FRandom[ExploS](-90,90);
s.scale *= RandomPick[ExploS](1,3);
s.alpha *= 2;
}
}
action void A_HeartDie()
{
scale *= 1.2;
A_FadeOut();
}
States
{
Spawn:
DOKI A 1 Bright A_HeartTick();
Wait;
Death:
DOKI A 0 Bright A_HeartBurst();
DOKI A 1 Bright A_HeartDie();
Wait;
}
}
Class HHitList
{
Actor a;
Vector3 dir;
}
// First person gestures
Class SWWMGesture : SWWMWeapon
{
@ -2480,9 +2728,13 @@ Class SWWMGesture : SWWMWeapon
mo.player.PendingWeapon = w;
}
action void A_CallPlayerGesture( statelabel st )
action void A_CallPlayerGesture( statelabel st, statelabel cst )
{
if ( invoker.Owner.FindState(st) && (invoker.Owner.Health > 0) )
if ( invoker.Owner.Health <= 0 ) return;
// crouched gestures not yet added
/*if ( (player.crouchdir == -1) && invoker.Owner.FindState(cst) )
invoker.Owner.SetStateLabel(cst);
else */if ( invoker.Owner.FindState(st) )
invoker.Owner.SetStateLabel(st);
}
@ -2492,6 +2744,88 @@ Class SWWMGesture : SWWMWeapon
player.SetPSprite(PSP_WEAPON,ResolveState("Deselect"));
}
action void A_ThrowMag()
{
let weap = Weapon(invoker);
if ( !weap ) return;
Vector3 x, y, z, x2, y2, z2;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-2*y-3*z);
double a = FRandom[Spread](0,360), s = FRandom[Spread](0,.005);
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
let p = Spawn("ExplodiumMagProj",origin);
p.special1 = 7;
p.target = self;
p.angle = atan2(dir.y,dir.x);
p.pitch = asin(-dir.z);
p.vel = dir*p.speed;
p.vel.z += 5.;
p.vel += vel*.5;
}
action void A_Smooch()
{
if ( (player == players[consoleplayer]) && (CVar.GetCVar('swwm_mutevoice',player).GetInt() < 4) )
A_StartSound("demolitionist/smooch",CHAN_DEMOVOICE,CHANF_OVERLAP,.4);
}
action void A_BlowKiss()
{
if ( (player == players[consoleplayer]) && (CVar.GetCVar('swwm_mutevoice',player).GetInt() < 4) )
A_StartSound("demolitionist/blowkiss",CHAN_DEMOVOICE,CHANF_OVERLAP,.4);
let weap = Weapon(invoker);
if ( !weap ) return;
Vector3 x, y, z, x2, y2, z2, dir;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-1*z);
let p = Spawn("LoveHeart",origin);
p.target = self;
p.angle = angle;
p.pitch = BulletSlope();
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
// try to catch target in cone of vision
[x2, y2, z2] = swwm_CoordUtil.GetAxes(p.pitch,p.angle,0);
Array<HHitList> hits;
hits.Clear();
int rings = 1;
FLineTraceData d;
for ( double i=0; i<.2; i+=.02 )
{
for ( int j=0; j<360; j+=(360/rings) )
{
dir = (x2+y2*cos(j)*i+z2*sin(j)*i).unit();
LineTrace(atan2(dir.y,dir.x),8000.,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
if ( d.HitType != TRACE_HitActor ) continue;
bool addme = true;
for ( int k=0; k<hits.Size(); k++ )
{
if ( hits[k].a != d.HitActor ) continue;
if ( (hits[k].dir dot x2) < (dir dot x2) )
hits[k].dir = dir; // closer to centerpoint
addme = false;
break;
}
if ( !addme ) continue;
let nhit = new("HHitList");
nhit.a = d.HitActor;
nhit.dir = dir;
hits.Push(nhit);
}
rings += 5;
}
int closest = -1;
double closestdot = -1;
for ( int i=0; i<hits.Size(); i++ )
{
double thisdot = (hits[i].dir dot x2);
if ( thisdot < closestdot ) continue;
closest = i;
closestdot = thisdot;
}
if ( closest != -1 ) p.tracer = hits[closest].a;
}
Default
{
+WEAPON.CHEATNOTWEAPON;
@ -2514,16 +2848,46 @@ Class SWWMGesture : SWWMWeapon
Ready:
TNT1 A 1
{
if ( invoker.whichgesture == 1 ) return ResolveState("Approve");
if ( invoker.whichgesture == 2 ) return ResolveState("Victory");
switch ( invoker.whichgesture )
{
case -1:
return ResolveState("QuickGrenade");
case 1:
return ResolveState("Approve");
case 2:
return ResolveState("Victory");
case 3:
return ResolveState("BlowKiss");
}
return ResolveState("Wave");
}
Wait;
Fire:
TNT1 A 1;
Goto Ready;
QuickGrenade:
TNT1 A 3;
XZW3 S 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 TU 3;
XZW3 V 3 A_PlayerReload();
XZW3 W 2 A_StartSound("explodium/magpin",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 XY 2;
XZW3 Z 3;
XZW4 A 2
{
A_StartSound("explodium/throwmag",CHAN_WEAPON,CHANF_OVERLAP);
A_PlayerMelee();
}
XZW4 BC 2;
XZW4 DEFGH 2;
XZW4 I 2 A_ThrowMag();
XZW4 JKLM 3;
TNT1 A 4;
TNT1 A 0 A_JumpIf(player.cmd.buttons&BT_USER4,"QuickGrenade");
TNT1 A -1 A_FinishGesture();
Stop;
Wave:
TNT1 A 3 A_CallPlayerGesture("Wave");
TNT1 A 3 A_CallPlayerGesture("Wave","CrouchWave");
XZW1 AB 3;
XZW1 C 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW1 DEFGHIJ 3;
@ -2532,7 +2896,7 @@ Class SWWMGesture : SWWMWeapon
TNT1 A -1 A_FinishGesture();
Stop;
Approve:
TNT1 A 3 A_CallPlayerGesture("Approve");
TNT1 A 3 A_CallPlayerGesture("Approve","CrouchApprove");
XZW1 PQ 3;
XZW1 R 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW1 STUVWX 3;
@ -2542,7 +2906,7 @@ Class SWWMGesture : SWWMWeapon
TNT1 A -1 A_FinishGesture();
Stop;
Victory:
TNT1 A 3 A_CallPlayerGesture("Victory");
TNT1 A 3 A_CallPlayerGesture("Victory","CrouchVictory");
XZW2 GH 3;
XZW2 I 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 JKLMNOPQ 3;
@ -2550,6 +2914,19 @@ Class SWWMGesture : SWWMWeapon
XZW2 STUVWXY 3;
TNT1 A -1 A_FinishGesture();
Stop;
BlowKiss:
TNT1 A 3 A_CallPlayerGesture("BlowKiss","CrouchBlowKiss");
XZW2 Z 3;
XZW3 A 3;
XZW3 B 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 CD 3;
XZW3 E 3 A_Smooch();
XZW3 FGHI 3;
XZW3 J 3 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 K 3 A_BlowKiss();
XZW3 LMNOPQR 3;
TNT1 A -1 A_FinishGesture();
Stop;
Deselect:
TNT1 A -1 A_FullLower();
Stop;

View file

@ -503,6 +503,13 @@ Class ExplodiumGun : SWWMWeapon
copy.chambered = DualExplodiumGun(SisterWeapon).chambered;
copy.clipcount = DualExplodiumGun(SisterWeapon).clipcount;
copy.preinit = true; // signal that this copy has preset info
// forcibly switch back from sister weapon
if ( Owner.player.ReadyWeapon == SisterWeapon )
{
Owner.player.ReadyWeapon = self;
Owner.player.SetPSprite(PSP_WEAPON,FindState("Ready"));
Owner.player.SetPSprite(PSP_WEAPON+1,null); // delete left weapon psprite
}
}
return copy;
}
@ -849,13 +856,6 @@ Class DualExplodiumGun : SWWMWeapon
// disallow dropping if weapon isn't ready for switching
if ( (Owner.player.ReadyWeapon == self) && (!(Owner.player.WeaponState&WF_WEAPONSWITCHOK) || (Owner.player.WeaponState&WF_DISABLESWITCH)) )
return null;
// forcibly switch back to sister weapon
if ( Owner.player.ReadyWeapon == self )
{
Owner.player.ReadyWeapon = SisterWeapon;
Owner.player.SetPSprite(PSP_WEAPON,SisterWeapon.FindState("Ready"));
Owner.player.SetPSprite(PSP_WEAPON+1,null); // delete left weapon psprite
}
// call toss on sister
return SisterWeapon.CreateTossable(amt);
}
@ -904,7 +904,8 @@ Class DualExplodiumGun : SWWMWeapon
player.SetPSprite(PSP_WEAPON+1,ResolveState("LeftReload"));
else if ( (invoker.clipcount > 0) && !invoker.chambered )
player.SetPSprite(PSP_WEAPON+1,ResolveState("LeftPreSlide"));
else if ( (player.cmd.buttons&BT_RELOAD) && (ExplodiumGun(invoker.SisterWeapon).clipcount < ExplodiumGun(invoker.SisterWeapon).default.clipcount) )
else if ( (player.cmd.buttons&BT_RELOAD) && (ExplodiumGun(invoker.SisterWeapon).clipcount < ExplodiumGun(invoker.SisterWeapon).default.clipcount)
&& (ExplodiumGun(invoker.SisterWeapon).clipcount <= invoker.clipcount) ) // give priority only if less than left hand
player.SetPSprite(PSP_WEAPON,ResolveState("Reload"));
else if ( (player.cmd.buttons&BT_RELOAD) && (invoker.clipcount < invoker.default.clipcount) )
player.SetPSprite(PSP_WEAPON+1,ResolveState("LeftReload"));
@ -993,7 +994,7 @@ Class DualExplodiumGun : SWWMWeapon
}
XZW4 STUV 1;
XZW2 A 0 A_JumpIf(!ExplodiumGun(invoker.SisterWeapon).chambered,"Slide");
XZW2 A 9 { player.SetPSPrite(PSP_WEAPON+1,ResolveState("LeftRaise")); }
XZW2 A 0 { player.SetPSPrite(PSP_WEAPON+1,ResolveState("LeftRaise")); }
Goto Ready;
PreSlide:
XZW2 A 9 { player.SetPSPrite(PSP_WEAPON+1,ResolveState("LeftLower")); }
@ -1010,7 +1011,7 @@ Class DualExplodiumGun : SWWMWeapon
XZW5 EFG 1;
XZW5 H 1 A_StartSound("explodium/slideforward",CHAN_WEAPON,CHANF_OVERLAP);
XZW5 IJKLM 1;
XZW2 A 9 { player.SetPSPrite(PSP_WEAPON+1,ResolveState("LeftRaise")); }
XZW2 A 0 { player.SetPSPrite(PSP_WEAPON+1,ResolveState("LeftRaise")); }
Goto Ready;
LeftReload:
XZWB A 9 { player.SetPSPrite(PSP_WEAPON,ResolveState("Lower")); }
@ -1049,7 +1050,7 @@ Class DualExplodiumGun : SWWMWeapon
}
XZWD STUV 1;
XZWB A 0 A_JumpIf(!invoker.chambered,"LeftSlide");
XZWB A 9 { player.SetPSPrite(PSP_WEAPON,ResolveState("Raise")); }
XZWB A 0 { player.SetPSPrite(PSP_WEAPON,ResolveState("Raise")); }
Goto LeftReady;
LeftPreSlide:
XZWB A 9 { player.SetPSPrite(PSP_WEAPON,ResolveState("Lower")); }
@ -1066,14 +1067,13 @@ Class DualExplodiumGun : SWWMWeapon
XZWE EFG 1;
XZWE H 1 A_StartSound("explodium/slideforward",CHAN_WEAPON,CHANF_OVERLAP);
XZWE IJKLM 1;
XZWB A 9 { player.SetPSPrite(PSP_WEAPON,ResolveState("Raise")); }
XZWB A 0 { player.SetPSPrite(PSP_WEAPON,ResolveState("Raise")); }
Goto LeftReady;
Zoom:
XZW2 A 1 A_StartSound("explodium/speen",CHAN_WEAPON,CHANF_OVERLAP);
XZW9 ABCDEFG 1;
XZW9 H 1 { player.SetPSPrite(PSP_WEAPON+1,ResolveState("LeftZoom")); }
XZW9 IJKLMNOPQRSTUVW 1;
XZW2 A 9;
Goto Ready;
LeftZoom:
XZWB A 1;

View file

@ -119,6 +119,7 @@ Class SWWMStats : Thinker
}
Class<Weapon> which = myplayer.ReadyWeapon?myplayer.ReadyWeapon.GetClass():null;
if ( inflictor is 'Weapon' ) which = Weapon(inflictor).GetClass();
if ( which is 'DualExplodiumGun' ) which = 'ExplodiumGun'; // don't credit sister weapon
// properly credit some projectiles to their respective gun
if ( inflictor is 'AirBullet' ) which = 'DeepImpact';
else if ( inflictor is 'PusherProjectile' ) which = 'PusherWeapon';