Much is new:

- Deep Impact implemented (ammo display not done yet, so it's just text).
 - More HUD features: enemy healthbars, omnisight, damage/health/score numbers.
   (not yet tweakable, will add options later. also omnisight's usable line
   highlighting currently has incorrect positioning, will fix later too).
 - Fixes 'n stuff.
 - Library text adjustments.
This commit is contained in:
Mari the Deer 2020-02-07 03:18:55 +01:00
commit 8df8ed6155
43 changed files with 1223 additions and 58 deletions

View file

@ -1,3 +1,79 @@
decal WallCrack1
{
pic WallCrk1
translucent 0.75
shade "00 00 00"
x-scale 0.25
y-scale 0.25
randomflipx
randomflipy
}
decal WallCrack2
{
pic WallCrk2
translucent 0.75
shade "00 00 00"
x-scale 0.25
y-scale 0.25
randomflipx
randomflipy
}
decalgroup WallCrack
{
WallCrack1 1
WallCrack2 1
}
decal ShockMark
{
pic shockmrk
shade "00 00 00"
randomflipx
randomflipy
x-scale 0.6
y-scale 0.6
}
decal ShockMarkBig
{
pic shockmrk
shade "00 00 00"
randomflipx
randomflipy
x-scale 1.5
y-scale 1.5
}
decal BigBlast
{
pic bigblast
shade "00 00 00"
randomflipx
randomflipy
x-scale 1.5
y-scale 1.5
}
decal ImpactMark
{
pic impcrack
shade "00 00 00"
randomflipx
randomflipy
x-scale 0.5
y-scale 0.5
}
decal RipBlast
{
pic ripblast
shade "00 00 00"
randomflipx
randomflipy
x-scale 0.45
y-scale 0.45
}
decal HugeScorch
{
pic SCORCH1

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
graphics/Decals/mcblast.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
graphics/HUD/EnemyBar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

BIN
graphics/HUD/EnemyBox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

View file

@ -125,25 +125,25 @@ SWWM_TRADECONTROLS0 = "Enter: Select | ";
SWWM_TRADECONTROLS1 = "Enter: Send | Backspace: Return | ";
// mission entries
SWWM_MISSION_DOOM =
"Welcome to your first mission, Demolitionist. Since I have very little confidence in those UAC idiots, I have decided to send you up ahead to assist on the fight against the demon invaders that came to Earth, thanks to their very wonderful and very reliable teleportation experiments backfiring, which is something absolutely no one saw coming, oh no, definitely not. It's not like that hasn't happened like... several times now? If Samuel Hayden didn't have me blocked I'd be sending him all sorts of trash right now. Oh I'd love to see his reaction to this...\n"
"Welcome to your first mission, Demolitionist. Since I have very little confidence in those UAC idiots, I have decided to send you up ahead to assist on the fight against the demon invaders that came to Earth, thanks to their very wonderful and very reliable teleportation experiments backfiring, which is something absolutely no one saw coming, oh no, definitely not. It's not like that hasn't happened like... several times now? The UAC's \"problem solver\" may not be able to do much, so yeah, better send you in to make a REAL difference here. If Samuel Hayden didn't have me blocked I'd be sending him all sorts of trash right now. Oh I'd love to see his reaction to this... \n"
"\n"
"Anyway, let's get to the point here. Your main objective is to eliminate all hostile forces in the region. There's going to be a hell a of a lot of fighting up ahead, but I know you can do it, that's why I built you. Do this job well and maybe you'll be rewarded when you come back home, who knows. No, Ibuki won't hug you again, I promise, your chassis will be safe. Your reward will actually be something else, but I won't tell you more details, I want it to be a surprise.\n"
"\n"
"By the way, we haven't been able to provide you with all the available equipment, it would've been very expensive. Instead, be on the lookout for strategically placed supplies along the way. If that sounds too videogamey, you can eat my pants, I wasn't the one who made that decision. Whatever.\n"
"By the way, we haven't been able to provide you with all the available equipment, it would've been very expensive. Instead, be on the lookout for strategically placed supplies along the way (hopefully the demons haven't stolen all of it yet). If that sounds too videogamey, you can eat my pants, I wasn't the one who made that decision. Whatever.\n"
"\n"
"Saya out.";
SWWM_MISSION_HERETIC =
"Welcome to your second mission, Demolitionist. This one will be quite different, as you may see. While scouring the multiverse with our new portal technology we came across this cool little place called Parthoris. It's got elves 'n magic stuff, very fantasy-like setting, I dig it. Anyway I hope the ride wasn't too bumpy, crossing between universes and all.\n"
"\n"
"Here's what's up: We have information that there is some sort of ongoing war between a bunch of elves and some crazy cult. Your objective is to neutralize this cult, preferably also taking out its leader, some sort of wizard dude. They call him D'Sparil and he's part of a triad of big baddies called the \"Serpent Riders\", because they ride dragons or something I guess? Guy's tall, wears red robes, and talks backwards, can't miss him. I'm sure that when you get back you'll want to transfer over to your maidbot body again, so I'll be working on a couple extensions there to make things more... \"fun\", if you catch my drift.\n"
"Here's what's up: We have information that there is some sort of ongoing conflict between a bunch of elves and some crazy cult that took over. Your objective is to neutralize this cult, preferably also taking out its leader, some sort of wizard dude. They call him D'Sparil and he's part of a triad of big baddies called the \"Serpent Riders\", because they ride those beasts I guess? Guy's tall, wears red robes, and talks backwards, can't miss him. I'm sure that when you get back you'll want to transfer over to your maidbot body again, so I'll be working on a couple extensions there to make things more... \"fun\", if you catch my drift. Oh, I'm in the mood for some eggplant right now, yes...\n"
"\n"
"Once again, I'm sorry that we couldn't give you all your stuff. I'm taking the blame this time, I think I screwed something up with the deployment and it got scattered all over the place. It's possible that the locals may have also moved stuff around so... good luck finding it all.\n"
"So... uh... once again, I'm sorry that we couldn't give you all your stuff. I'm taking the blame this time, I think I screwed something up with the deployment and it got scattered all over the place. It's possible that the locals may have also moved stuff around so... good luck finding it all.\n"
"\n"
"Saya out.";
SWWM_MISSION_HEXEN =
"Welcome to your third mission, Demolitionist. We're sending you into another world, but this is actually related to your previous mission. First of all, yes I fucked up again, I'm sorry, really. All your stuff got lost... again, my bad. On top of that there was some sort of mixup with the ammo supplies and instead we got these weird \"Fabricator\" things from Cyrus. They do provide ammo, at least.\n"
"Welcome to your third mission, Demolitionist. We're sending you into another world, but this is actually related to your previous mission. First of all, yes I fucked up again, I'm sorry, really. All your stuff got lost... again, my bad. On top of that there was some sort of mixup with the ammo supplies and instead we got these weird \"Fabricator\" things from that nerdo. They do provide ammo, at least.\n"
"\n"
"So yeah, you're now in the land of Cronos, more of that cool dark fantasy stuff around. It seems that some old pal of that wizard dude from last time is being a stinky ass here, and we need that sorted out before we can start studying this place in more detail. So there you go, beat the crap outta him! As a reward, we can do some more of \"that\". Just you, me, maybe Ibuki too... hnnn... and then... *heavy breathing*\n"
"So yeah, you're now in the land of Cronos, more of that cool dark fantasy stuff around. It seems that some old pal of that wizard dude from last time is being a stinky ass here, and we need that sorted out before we can start studying this place in more detail. So there you go, beat the crap outta him! As a reward, we can do some more of \"that\". Just you, me, maybe Ibuki and Maidbot too... and I wonder... if Kirin-kun also... hnnn... and then... *heavy breathing*\n"
"\n"
"OK, wow... phew. Saya, focus. No hornyposting on mission statements. Anyway, more details about your target. Evil dragonish-looking dude, deep voice, and also a Serpent Rider, though I can't even begin to understand how he'd ride one. Maybe he's the one that receives the riding... u... ggdfgfhfhdfh... ok, pls no, BAD mental image, UGH. I think I'm going to need to spend a couple more hours drowning in Ibuki's tiddies to get this out of my head...\n"
"\n"
@ -164,7 +164,7 @@ SWWM_LORETXT_BELT =
"Designation: Adaptable Magnetic Utility Belt\n"
"Manufacturer: Symnatek\n"
"\n"
"Summary: A simple magnetic belt, adaptable to any waist size by detaching/attaching segments.\n"
"Summary: A simple magnetic belt, adaptable to any waist size by detaching/attaching segments. Its magnetic force is enough to keep any objects tightly attached no matter the force of impact the user faces.\n"
"\n"
"Addendum: This belt should allow you easy access to your Hammerspace containers and keychain, along with making it easier to reload certain weapons.";
SWWM_LORETAG_BLASTSUIT = "Blast Suit";
@ -200,7 +200,7 @@ SWWM_LORETXT_CRONOS =
"Designation: Cronos\n"
"Classification: Collection of worlds\n"
"\n"
"Summary: A cluster of pocket worlds connected by strange portals. Historical research says that these were once all part of a much larger, more compact realm, but some great cataclysm happened and it all got shattered. Fortunately some \"sages\" devised a way to connect the many hubworlds together once again.\n"
"Summary: A cluster of pocket worlds connected by strange portals. Historical research says that these were once all part of a much larger, more compact realm, but some great cataclysm happened and it all got shattered. Fortunately some \"sages\" devised a way to connect the many hubworlds together once again. We've also been informed that there are three major organizations at work here, but they're not friendly at all, since they've allied with a Serpent Rider. You may have to confront their leaders before facing the one pulling the strings.\n"
"\n"
"Addendum: The natives are known to enjoy puzzles, sometimes to a sickening degree.\n"
"\n"
@ -222,9 +222,9 @@ SWWM_LORETXT_DEEPIMPACT =
"\n"
"Summary: The Deep Impact is a compressed air gun, allegedly meant to be a child's toy. Its maximum pressure allows for deadly blasts of air that could cause severe internal hemorrhaging and crushing of vital organs.\n"
"\n"
"Primary Fire: Quick puffs of compressed air. This pocket of quickly expanding air can push away obstacles in front of the user, or, if aimed at a solid surface, allow the user to boost their jump height. It also deals considerable damage.\n"
"Primary Fire: Quick puffs of compressed air. Pushes away enemies and projectiles, while also dealing some damage.\n"
"\n"
"Secondary Fire: Compresses all the air into a single shot with very considerable force. This \"air bullet\" is capable of penetrating multiple targets, digging a hole staight through their bodies. Requires a full air tank.\n"
"Secondary Fire: Compresses all the air into a single highly destructive shot. This \"air bullet\" is capable of penetrating multiple targets, digging a hole staight through their bodies. Requires a full air tank.\n"
"\n"
"Reloading: The lever on the side must be pulled several times in order to refill the internal air tank. Once at full capacity, a smart mechanism will lock the lever to avoid accidental overfilling.\n"
"\n"
@ -236,7 +236,9 @@ SWWM_LORETXT_DEMOLITIONIST =
"Nationality: Japanese\n"
"Date Of Birth: 2148-01-20\n"
"\n"
"Summary: The Demolitionist is a refinement of the former Red Oni supersoldier program, an AI-controlled combat unit capable of efficiently utilizing any weaponry at its disposition. The first unit (that's you) was deployed in June of 2148 on Union States territory in order to combat the demonic invasion brought upon by the UAC's interventions on Hell.\n"
"Summary: The Demolitionist is a refinement of the former Red Oni supersoldier program, an AI-controlled combat unit capable of efficiently utilizing any weaponry at its disposition. Its AI core is built on the same technology as Akari Labs' maidbots, the Nekuronbot AI framework, provided as a gift of friendship between Saya and Zanaveth II, the current head of Nekuratek. Thanks to this technology, the Demolitionist is barely indistinguishable from a real person in its behaviour and emotional response, which makes interaction with civilians more comforting.\n"
"\n"
"Addendum: The first unit (that's you) was deployed in June of 2148 on Union States territory in order to combat the demonic invasion brought upon by the UAC's interventions on Hell.\n"
"\n"
"Saya's Note: Stop reading about yourself and get back to work.";
SWWM_LORETAG_DISPLAY = "CuteEmotion Display";
@ -258,7 +260,7 @@ SWWM_LORETXT_DOOMGUY =
"\n"
"Addendum: You have been ordered to not interact with this man, if you encounter him, please stand back and let him work.\n"
"\n"
"Saya's Note: Sorry about the lack of info here, those UAC goons really keep it well-guarded.";
"Saya's Note: Sorry about the lack of info here, those UAC goons really keep it well-guarded. Hell, I've even heard there's ANOTHER guy like this one, but he's like, ten times more hardcore? Some kinda ancient alien warrior or something, according to the leaks I saw (very little info here too, yeah).";
SWWM_LORETAG_EXPLODIUMGUN = "Explodium Gun";
SWWM_LORETXT_EXPLODIUMGUN =
"Designation: Explodium Gun\n"
@ -281,7 +283,7 @@ SWWM_LORETXT_FORX =
"\n"
"Summary: Founded by Harold Forx in 2029, this company is credited with singlehandedly rescuing the UK from its long fall into economic ruin after Brexit. Forx Aeronautics is the #1 supplier of propulsion engines for all types of aircraft, be it commercial jet planes, or even spaceships. The only exception being the UAC, who prefer their own in-house technology. Forx has also adapted his patented jet propulsion systems for other uses, such as in the \"JetBurst Impulsor\", one of the first tuly portable jetpacks, or the \"Rapid Jet Compensator\", a recoil dampening system for high caliber firearms that permits their use outside of heavy, unwieldy power armor.\n"
"\n"
"Saya's Note: Hey did you hear the story about that one time he tried to mow down an orphanage and the guy who ran it gave him a smack so fucking hard he did a complete 180 and left it alone? I've seen the archived footage like a dozen times and I always lose my shit with that asshole's face when he comes out.";
"Saya's Note: Hey did you hear the story about that one time he tried to mow down an orphanage and the guy who ran it smacked him so fucking hard he did a complete 180 and ran away crying? I've seen the archived footage like a dozen times and I always lose my shit with that asshole's face when he comes out.";
SWWM_LORETAG_HAMMERSPACE = "Hammerspace";
SWWM_LORETXT_HAMMERSPACE =
"Designation: Pocket Hammerspace Container\n"
@ -307,7 +309,7 @@ SWWM_LORETXT_IBUKI =
"Nationality: Japanese\n"
"Date of Birth: 2074-09-09\n"
"\n"
"Summary: Ibuki is the result of the Red Oni supersoldier program at Akari Labs, commissioned by the US government. Her purpose was to turn around the losing World War 3 that began due to a very badly received tweet from the President of the United States, an event reminiscent of the incident with Iran that the late Donald Trump had started. In a mere three years she was ready, thanks to an accelerated growth process. She's been enhanced to be effectively bulletproof, always standing strong under any circumstance, capable of handling extreme heat and cold, and trained for handling all kinds of weaponry. Much is also said about her personality, or her questionable physical traits such as the ludicrously impractical bust size, all of this which must clearly have been intentionally done by her creator and self-appointed \"mother\", Saya Miyamoto. After the end of the war she's gone through several jobs, crowning in her current one as a world-famous nude model and vlogger.\n"
"Summary: Ibuki is the result of the Red Oni supersoldier program at Akari Labs, commissioned by the US government. Her purpose was to turn the tides on the losing World War 3 that began due to a very badly received tweet from the President of the United States, an event reminiscent of the incident with Iran that the late Donald Trump had started. In a mere three years she was ready, thanks to an accelerated growth process. She's been enhanced to be effectively bulletproof, always standing strong under any circumstance, capable of handling extreme heat and cold, and trained for handling all kinds of weaponry. Much is also said about her personality, or her questionable physical traits such as the ludicrously impractical bust size, all of this which must clearly have been intentionally done by her creator and self-appointed \"mother\", Saya Miyamoto. After the end of the war she's gone through several jobs, crowning in her current one as a world-famous nude model and vlogger.\n"
"\n"
"Addendum: In a way, the Demolitionist project could be said to be a more economic alternative to the Red Oni program. Robots are easy to manufacture en-masse, after all.\n"
"\n"
@ -318,7 +320,7 @@ SWWM_LORETXT_LOCKE =
"Nationality: Qurensniv\n"
"Date of Birth: 1980-07-30\n"
"\n"
"Summary: A man who changed entirely after the loss of his older brother in 1987 during a very famous oil rig explosion near the town of Kereshnovka. Nowadays he's pretty much just a mad scientist shut-in who sometimes creates \"toys\" that are hilariously deadly. In 2049 he attempted to \"take over the world\", an event that backfired so hilariously he completely disappeared from the public eye afterwards.\n"
"Summary: A man who changed entirely after the loss of his older brother in 1987, in an oil rig explosion near the town of Kereshnovka. Nowadays he's pretty much just a mad scientist shut-in who sometimes creates \"toys\" that are hilariously deadly. In 2049 he attempted to \"take over the world\", an event that backfired so hilariously he completely disappeared from the public eye afterwards.\n"
"\n"
"Saya's Note: Guy's a total nut, but these \"toys\" are very reliable weapons for you. Just be careful when using them, shit could backfire catastrophically at any moment, who knows...";
SWWM_LORETAG_MUNCH = "Munch Innovations";
@ -337,7 +339,7 @@ SWWM_LORETXT_PARTHORIS =
"Designation: Parthoris\n"
"Classification: Alternate world\n"
"\n"
"Summary: One of the other worlds we've discovered during the initial interportal experiments. This is a land stuck in some sort of medieval-ish, fantasy type setting. Although some of our explorers have reported sights of unusually complex technology in a certain location we haven't been able to approach.\n"
"Summary: One of the other worlds we've discovered during the initial interportal experiments. This land is divided in seven major nations we don't yet know the name of, and appears to be stuck in some sort of a medieval-ish fantasy type setting, although some of our explorers have reported sights of unusually complex technology in a certain location we haven't been able to approach. As of now there is some hostility in the area what with a bunch of evildoers having taken over by force.\n"
"\n"
"Addendum: You are our ambassador here, so I hope you make a good impression.";
SWWM_LORETAG_PROPULSOR = "JetBurst Impulsor";
@ -365,9 +367,9 @@ SWWM_LORETXT_SERPENTRIDERS =
"Classification: Evil, definitely\n"
"Origin: Undetermined\n"
"\n"
"Summary: A triad of evildoers known all over these lands. All those who've dared to fight against them haven't been very lucky. D'Sparil claimed the land of Parthoris, his many armies of undead having ravaged the land long before our arrival here. Then in the land of Cronos there's Korax, a black beast that taunts all those who challenge him. We haven't received much information on the third member, but this stuff will come eventually as we keep exploring these new worlds.\n"
"Summary: A triad of evildoers known all over these lands. All those who've dared to fight against them haven't been very lucky. D'Sparil claimed the land of Parthoris, his many armies of undead having taken over the land before our arrival. Then in the land of Cronos there's Korax, a black beast that taunts all those who challenge him. We haven't received much information on the third member, but this stuff will come eventually as we keep exploring these new worlds.\n"
"\n"
"Saya's Note: I'm sure you can wipe out all these idiots without any issue, they have no idea of how strong you are (or of what you are, now that I think of it, this world hardly seems to know much about our technology).";
"Saya's Note: I'm sure you can wipe out all these idiots without any issue, they have no idea of how strong you are (or of what you are, now that I think of it, these worlds hardly seem to know much about our technology).";
SWWM_LORETAG_UAC = "UAC";
SWWM_LORETXT_UAC =
"Name: Union Aerospace Corporation\n"
@ -392,7 +394,7 @@ SWWM_LORETXT_SIDHE =
"Designation: Sidhe\n"
"Location: Parthoris\n"
"\n"
"Summary: An elf species native to this world, they have a natural bond with magic and are known to be great fighters. As the story goes they however face persecution by other groups, led mainly by the cult of D'Sparil, one of the Serpent Riders who has made the land his own.\n"
"Summary: An elf species native to this world, they have a natural bond with magic and are known to be great fighters. As the story goes they however face persecution by other groups due to the opposition to the current ruler. Most of them have been killed in the war, only few remain. It is your mission to help them.\n"
"\n"
"Saya's Note: How do you exactly pronounce \"Sidhe\" anyway?";
SWWM_LORETAG_HAMMERSPACEEMBIGGENER = "Hs. Embiggener";
@ -906,6 +908,13 @@ D_INVINCIBALL = "You are no longer invincible.";
D_RAGEKIT = "The Ragekit has ragequit.";
D_REFRESHER = "The Refresher boost has ended.";
D_WARARMOR = "The War Armor is no more.";
// targetter
SWWM_USABLE = "Usable";
SWWM_SHOOTABLE = "Shootable";
SWWM_BOTHUSE = "Usable / Shootable";
SWWM_EXIT = "Exit: ";
SWWM_NEXIT = "Exit";
SWWM_SEXIT = "Secret Exit";
// score messages
SWWM_FINDSECRET = "\cf%s\cf found a secret. +%d\c-";
SWWM_FINDKEY = "\cf%s\cf got the %s. +%d\c-";

View file

@ -11,3 +11,101 @@ Model "DeepImpact"
FrameIndex XZW1 A 0 0
}
Model "DeepImpact"
{
Path "models"
Model 1 "DeepImpact1st_d.3d"
SurfaceSkin 1 0 "DemoTags.png"
SurfaceSkin 1 1 "DemoArms.png"
SurfaceSkin 1 2 "DemoSoft.png"
SurfaceSkin 1 3 "DeepImpact.png"
Scale -0.005 0.0025 0.005
AngleOffset -90
Offset 0 0 -2
// Still / Down / Select
FrameIndex XZW2 A 1 0 // still / down
FrameIndex XZW2 B 1 1
FrameIndex XZW2 C 1 2
FrameIndex XZW2 D 1 3
FrameIndex XZW2 E 1 4
FrameIndex XZW2 F 1 5
FrameIndex XZW2 G 1 6
FrameIndex XZW2 H 1 7
FrameIndex XZW2 I 1 8 // enddown / startselect
FrameIndex XZW2 J 1 9
FrameIndex XZW2 K 1 10
FrameIndex XZW2 L 1 11
FrameIndex XZW2 M 1 12
FrameIndex XZW2 N 1 13
FrameIndex XZW2 O 1 14
FrameIndex XZW2 P 1 15
// Fire
FrameIndex XZW2 Q 1 17
FrameIndex XZW2 R 1 18
FrameIndex XZW2 S 1 19
FrameIndex XZW2 T 1 20
FrameIndex XZW2 U 1 21
// AltFire
FrameIndex XZW2 V 1 23
FrameIndex XZW2 W 1 24
FrameIndex XZW2 X 1 25
FrameIndex XZW2 Y 1 26
FrameIndex XZW2 Z 1 27
FrameIndex XZW3 A 1 28
FrameIndex XZW3 B 1 29
FrameIndex XZW3 C 1 30
FrameIndex XZW3 D 1 31
FrameIndex XZW3 E 1 32
FrameIndex XZW3 F 1 33
FrameIndex XZW3 G 1 34
// ReloadBeg
FrameIndex XZW3 H 1 36
FrameIndex XZW3 I 1 37
FrameIndex XZW3 J 1 38
// Reload
FrameIndex XZW3 K 1 39
FrameIndex XZW3 L 1 40
FrameIndex XZW3 M 1 41
FrameIndex XZW3 N 1 42
FrameIndex XZW3 O 1 43
FrameIndex XZW3 P 1 44
FrameIndex XZW3 Q 1 45
// ReloadEnd
FrameIndex XZW3 R 1 47
FrameIndex XZW3 S 1 48
FrameIndex XZW3 T 1 49
FrameIndex XZW3 U 1 50
FrameIndex XZW3 V 1 51
// CheckGun
FrameIndex XZW3 W 1 53
FrameIndex XZW3 X 1 54
FrameIndex XZW3 Y 1 55
FrameIndex XZW3 Z 1 56
FrameIndex XZW4 A 1 57
FrameIndex XZW4 B 1 58
FrameIndex XZW4 C 1 59
FrameIndex XZW4 D 1 60
FrameIndex XZW4 E 1 61
FrameIndex XZW4 F 1 62
FrameIndex XZW4 G 1 63
// Melee
FrameIndex XZW4 H 1 65
FrameIndex XZW4 I 1 66
FrameIndex XZW4 J 1 67
FrameIndex XZW4 K 1 68
FrameIndex XZW4 L 1 69
FrameIndex XZW4 M 1 70
FrameIndex XZW4 N 1 71
FrameIndex XZW4 O 1 72
FrameIndex XZW4 P 1 73
FrameIndex XZW4 Q 1 74
FrameIndex XZW4 R 1 75
FrameIndex XZW4 S 1 76
FrameIndex XZW4 T 1 77
FrameIndex XZW4 U 1 78
FrameIndex XZW4 V 1 79
}

BIN
models/DeepImpact1st.blend Normal file

Binary file not shown.

BIN
models/DeepImpact1st_a.3d Normal file

Binary file not shown.

BIN
models/DeepImpact1st_d.3d Normal file

Binary file not shown.

View file

@ -13,12 +13,12 @@ X candygun tertiary
Deep Impact:
- down/select
- fire anim
- altfire anim
- pump
- "check out gun" idle anim
- melee bash
* down/select
* fire anim
* altfire anim
* pump
* "check out gun" idle anim
* melee bash
Pusher:

BIN
palettes/ImpactWav2.pal Normal file

Binary file not shown.

View file

@ -296,6 +296,9 @@ demolitionist/swing1 sounds/demolitionist/demoswing1.ogg
demolitionist/swing2 sounds/demolitionist/demoswing2.ogg
demolitionist/swing3 sounds/demolitionist/demoswing3.ogg
$random demolitionist/swing { demolitionist/swing1 demolitionist/swing2 demolitionist/swing3 }
demolitionist/wswing1 sounds/demolitionist/demowswing1.ogg
demolitionist/wswing2 sounds/demolitionist/demowswing2.ogg
$random demolitionist/wswing { demolitionist/wswing1 demolitionist/wswing2 }
demolitionist/punch1 sounds/demolitionist/demopunch1.ogg
demolitionist/punch2 sounds/demolitionist/demopunch2.ogg
demolitionist/punch3 sounds/demolitionist/demopunch3.ogg
@ -331,6 +334,22 @@ $playersound demolitionist neutral *gasp DSEMPTY
$playersound demolitionist neutral *taunt DSEMPTY
$playersound demolitionist neutral *evillaugh DSEMPTY
deepimpact/fire sounds/deepimpact/impfire.ogg
deepimpact/charge sounds/deepimpact/impaltcharge.ogg
deepimpact/altfire sounds/deepimpact/impaltfire.ogg
deepimpact/dryfire sounds/deepimpact/impdryfire.ogg
deepimpact/select sounds/deepimpact/impsel.ogg
deepimpact/checkout sounds/deepimpact/impidle.ogg
deepimpact/deselect sounds/deepimpact/impdown.ogg
deepimpact/bullet sounds/deepimpact/impbulletfly.ogg
deepimpact/bullethit1 sounds/deepimpact/impexplo1.ogg
deepimpact/bullethit2 sounds/deepimpact/impexplo2.ogg
deepimpact/reloadbeg sounds/deepimpact/impreloadstart.ogg
deepimpact/reloadend sounds/deepimpact/impreloadend.ogg
deepimpact/reload sounds/deepimpact/impcrank.ogg
deepimpact/noreload sounds/deepimpact/impcrankhalt.ogg
$random deepimpact/bullethit { deepimpact/bullethit1 deepimpact/bullethit2 }
explodium/casing1 sounds/explodiumgun/expl_case1.ogg
explodium/casing2 sounds/explodiumgun/expl_case2.ogg
explodium/casing3 sounds/explodiumgun/expl_case3.ogg

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -250,6 +250,124 @@ Class SWWMLoreLibrary : Thinker
}
}
// floating scores
Class SWWMScoreObj : Thinker
{
int tcolor;
int score;
Vector3 pos;
int lifespan, initialspan;
int starttic, seed, seed2;
static SWWMScoreObj Spawn( int score, Vector3 pos, int tcolor = Font.CR_GOLD )
{
let o = new("SWWMScoreObj");
o.ChangeStatNum(STAT_USER);
o.score = score;
o.pos = pos;
o.lifespan = o.initialspan = 60;
o.tcolor = tcolor;
o.starttic = gametic;
o.seed = Random[ScoreBits]();
o.seed2 = Random[ScoreBits]();
return o;
}
override void Tick()
{
lifespan--;
if ( lifespan <= 0 ) Destroy();
}
}
enum EInterestType
{
INT_Key,
INT_Exit,
INT_Usable
};
Class SWWMInterest : Thinker
{
int type;
Key trackedkey;
Line trackedline;
Vector3 pos;
static SWWMInterest Spawn( Vector3 pos = (0,0,0), Key thekey = null, Line theline = null )
{
if ( (!thekey && !theline) || (thekey && theline) ) return null;
let i = new("SWWMInterest");
i.ChangeStatNum(STAT_USER);
i.trackedkey = thekey;
i.trackedline = theline;
if ( thekey ) i.type = INT_Key;
else if ( (theline.special == Exit_Normal) || (theline.special == Exit_Secret) || (theline.special == Teleport_EndGame) || (theline.special == Teleport_NewMap) )
i.type = INT_Exit;
else i.type = INT_Usable;
i.pos = thekey?thekey.Vec3Offset(0,0,thekey.height/2):pos;
return i;
}
override void Tick()
{
// update
if ( (type == INT_Key) && (!trackedkey || trackedkey.Owner) ) Destroy();
else if ( trackedkey ) pos = trackedkey.Vec3Offset(0,0,trackedkey.height/2);
else if ( (type == INT_Usable) && !trackedline.special ) Destroy();
}
}
// enemy combat tracker
Class SWWMCombatTracker : Thinker
{
Actor mytarget;
String mytag;
int updated, lasthealth, maxhealth;
transient DynamicValueInterpolator intp;
Vector3 pos, prevpos;
static SWWMCombatTracker Spawn( Actor target )
{
let t = new("SWWMCombatTracker");
t.ChangeStatNum(STAT_USER);
t.mytarget = target;
t.mytag = target.player?target.player.GetUserName():target.GetTag();
t.lasthealth = t.maxhealth = target.health;
t.updated = int.min;
t.pos = level.Vec3Offset(target.pos,(0,0,target.default.height));
t.prevpos = level.Vec3Offset(target.prev,(0,0,target.default.height));
t.intp = DynamicValueInterpolator.Create(t.lasthealth,.5,1,100);
return t;
}
override void Tick()
{
// update
if ( mytarget )
{
pos = level.Vec3Offset(mytarget.pos,(0,0,mytarget.default.height));
prevpos = level.Vec3Offset(mytarget.prev,(0,0,mytarget.default.height));
}
if ( !mytarget || (mytarget.Health <= 0) )
{
// we're done
if ( updated > gametic ) updated = gametic;
lasthealth = 0;
intp.Update(lasthealth);
if ( gametic > updated+35 ) Destroy();
return;
}
mytag = mytarget.player?mytarget.player.GetUserName():mytarget.GetTag();
int newhealth = mytarget.Health;
if ( newhealth != lasthealth ) updated = gametic+35;
if ( mytarget.target && (mytarget.target.Health > 0) && (mytarget.target.player == players[consoleplayer]) && mytarget.CheckSight(mytarget.target) ) updated = gametic+70;
if ( mytarget.IsFriend(players[consoleplayer].mo) ) updated = gametic;
lasthealth = newhealth;
intp.Update(lasthealth);
}
}
// One-liners
Class SWWMOneLiner : HUDMessageBase
{
@ -678,13 +796,51 @@ Class SWWMItemFog : Actor
}
}
Class TeleLight : PaletteLight
{
Default
{
Tag "ImpactWav";
ReactionTime 10;
Args 0,0,0,150;
}
}
Class SWWMTeleportFog : Actor
{
Default
{
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
SetOrigin(Vec3Offset(0,0,28),false);
A_StartSound("misc/teleport",CHAN_VOICE);
Spawn("TeleLight",pos);
}
States
{
Spawn:
TNT1 A 1;
Stop;
TNT1 A 1
{
int numpt = int(Random[ExploS](16,32)*alpha);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.3,8)*alpha;
let s = Spawn("SWWMSmallSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,2,3)*int(Random[ExploS](64,85)*alpha));
s.A_SetRenderStyle(s.alpha,STYLE_AddShaded);
s.scale *= 3.*alpha;
s.alpha *= alpha;
}
A_FadeOut();
}
Wait;
}
}
@ -967,6 +1123,64 @@ Class SWWMHandler : EventHandler
if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]);
if ( !e.IsSaveGame && !e.IsReopen && (gamestate != GS_TITLELEVEL) && (mutevoice.GetInt() < 3) )
AddOneliner("mapstart");
if ( !e.IsSaveGame && !e.IsReopen )
{
// for skipping over merged exit lines (sharing vertices)
Array<int> skipme;
skipme.Clear();
// find exit lines, and use lines that aren't exits
for ( int i=0; i<level.lines.Size(); i++ )
{
Line l = level.lines[i];
if ( skipme.Find(l.Index()) > skipme.Size() ) continue;
Vector3 al, ah, bl, bh;
// TODO properly center on the usable part
al = (l.v1.p.x,l.v1.p.y,l.frontsector.floorplane.ZatPoint(l.v1.p));
ah = (l.v1.p.x,l.v1.p.y,l.frontsector.ceilingplane.ZatPoint(l.v1.p));
bl = (l.v2.p.x,l.v2.p.y,l.frontsector.floorplane.ZatPoint(l.v2.p));
bh = (l.v2.p.x,l.v2.p.y,l.frontsector.ceilingplane.ZatPoint(l.v2.p));
Vector3 lpos = (al+ah+bl+bh)*.25;
if ( (l.special == Exit_Normal) || (l.special == Exit_Secret) || (l.special == Teleport_EndGame) || (l.special == Teleport_NewMap) )
{
// look for connected lines
int xcnt = 1;
if ( l.frontsector )
{
for ( int j=0; j<l.frontsector.Lines.Size(); j++ )
{
let l2 = l.frontsector.Lines[j];
if ( (l2 == l) || (l2.special != l.special) ) continue;
skipme.Push(l2.Index());
xcnt++;
al = (l.v1.p.x,l.v1.p.y,l.frontsector.floorplane.ZatPoint(l.v1.p));
ah = (l.v1.p.x,l.v1.p.y,l.frontsector.ceilingplane.ZatPoint(l.v1.p));
bl = (l.v2.p.x,l.v2.p.y,l.frontsector.floorplane.ZatPoint(l.v2.p));
bh = (l.v2.p.x,l.v2.p.y,l.frontsector.ceilingplane.ZatPoint(l.v2.p));
lpos += (al+ah+bl+bh)*.25;
}
}
if ( l.backsector )
{
for ( int j=0; j<l.backsector.Lines.Size(); j++ )
{
let l2 = l.backsector.Lines[j];
if ( (l2 == l) || (l2.special != l.special) ) continue;
skipme.Push(l2.Index());
xcnt++;
al = (l.v1.p.x,l.v1.p.y,l.frontsector.floorplane.ZatPoint(l.v1.p));
ah = (l.v1.p.x,l.v1.p.y,l.frontsector.ceilingplane.ZatPoint(l.v1.p));
bl = (l.v2.p.x,l.v2.p.y,l.frontsector.floorplane.ZatPoint(l.v2.p));
bh = (l.v2.p.x,l.v2.p.y,l.frontsector.ceilingplane.ZatPoint(l.v2.p));
lpos += (al+ah+bl+bh)*.25;
}
}
lpos /= xcnt;
SWWMInterest.Spawn(lpos,theline:l);
}
else if ( l.special && (l.activation&(SPAC_Use|SPAC_Impact)) )
SWWMInterest.Spawn(lpos,theline:l);
}
}
}
override void PlayerDied( PlayerEvent e )
@ -1159,6 +1373,8 @@ Class SWWMHandler : EventHandler
override void WorldThingDamaged( WorldEvent e )
{
if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]);
if ( e.Damage > 0 )
SWWMScoreObj.Spawn(-e.Damage,e.Thing.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+e.Thing.Height/2),Font.CR_RED);
if ( e.Thing.player )
{
tookdamage[e.Thing.PlayerNumber()] = true;
@ -1182,7 +1398,8 @@ Class SWWMHandler : EventHandler
}
if ( (e.DamageSource == players[consoleplayer].mo) && (e.Thing.bISMONSTER || e.Thing.player) )
{
if ( e.Thing.IsFriend(e.DamageSource) )
// make sure it's not a moth, because otherwise they won't shut up about accidentally hurting them (it happens a lot)
if ( e.Thing.IsFriend(e.DamageSource) && !(e.Thing is 'LampMoth') )
{
if ( (!lastcombat || (gametic > lastcombat+20)) && (mutevoice.GetInt() < 1) )
lastcombat = AddOneliner("hitfriend",15);
@ -1224,13 +1441,14 @@ Class SWWMHandler : EventHandler
score = int(score*(1.+.5*min(multilevel[pnum],16)));
if ( !tookdamage[pnum] ) score += 100+50*spreecount[pnum];
if ( e.Thing.bBOSS ) score += 10000;
SWWMCredits.Give(e.DamageSource.player,score);
if ( e.DamageSource.player == players[consoleplayer] )
SWWMScoreObj.Spawn(score,e.Thing.Vec3Offset(0,0,e.Thing.Height/2));
if ( level.killed_monsters+1 == level.total_monsters )
{
score += 5000;
SWWMCredits.Give(e.DamageSource.player,5000);
Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),e.DamageSource.player.GetUserName(),5000);
}
SWWMCredits.Give(e.DamageSource.player,score);
// TODO floating score for HUD
spreecount[pnum]++;
}
}
@ -1260,16 +1478,21 @@ Class SWWMHandler : EventHandler
else if ( a is 'KeyCastle' ) a.SetTag("$T_KEYCASTLE");
}
// tempfix keys have no tags
static void KeyTagFix( Actor a )
{
let hnd = SWWMHandler(Find("SWWMHandler"));
if ( hnd ) hnd.DoKeyTagFix(a);
}
// tempfix keys have no tags
override void WorldThingSpawned( WorldEvent e )
{
if ( e.Thing is 'Key' ) DoKeyTagFix(e.Thing);
if ( e.Thing is 'Key' )
{
DoKeyTagFix(e.Thing);
SWWMInterest.Spawn(thekey:Key(e.Thing));
}
if ( e.Thing.bSHOOTABLE && !(e.Thing is 'LampMoth') && !(e.Thing is 'CompanionLamp') ) SWWMCombatTracker.Spawn(e.Thing);
}
override void PostUiTick()
@ -1287,6 +1510,19 @@ Class SWWMHandler : EventHandler
}
}
override void WorldLineActivated( WorldEvent e )
{
if ( e.Thing.player != players[consoleplayer] ) return;
// remove lines that have been already used by the local player
let ti = ThinkerIterator.Create("SWWMInterest",Thinker.STAT_USER);
SWWMInterest i;
while ( i = SWWMInterest(ti.Next()) )
{
if ( (i.type != INT_Usable) || (i.trackedline != e.ActivatedLine) ) continue;
i.Destroy();
}
}
override void WorldLinePreActivated( WorldEvent e )
{
// oneliner on locked doors
@ -1663,6 +1899,14 @@ Class SWWMHandler : EventHandler
}
}
// stuff for hud
override void RenderUnderlay( RenderEvent e )
{
if ( !statusbar || !(statusbar is 'SWWMStatusBar') ) return;
SWWMStatusBar(statusbar).viewpos = e.viewpos;
SWWMStatusBar(statusbar).viewrot = (e.viewangle,e.viewpitch,e.viewroll);
}
static void DoFlash( Actor camera, Color c, int duration )
{
QueuedFlash qf = new("QueuedFlash");

View file

@ -1,12 +1,188 @@
// Dr. Locke's Mighty Wolf Breath Airgun aka "Deep Impact" Airblaster (from SWWM series)
// Slot 1, replaces Fist, Staff, Hexen starting weapons
Class AirBullet : FastProjectile
{
int tcnt;
Default
{
Radius 2;
Height 4;
DamageFunction 100;
Speed 400;
PROJECTILE;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
+RIPPER;
}
override void PostBeginPlay()
{
A_StartSound("deepimpact/bullet",CHAN_BODY,CHANF_LOOPING,1.,1.5);
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
SWWMHandler.DoKnockback(target,vel.unit(),10000);
return damage;
}
override void Effect()
{
let r = Spawn("AirBulletRing",pos);
r.angle = angle;
r.pitch = pitch;
r.roll = FRandom[Impact](0,360);
r.scale *= .3;
r.alpha *= .6;
int numpt = Random[ExploS](2,4);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](.1,.8);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel+vel.unit()*3.;
s.SetShade(Color(1,1,1)*Random[ExploS](240,255));
s.special1 = Random[ExploS](1,2);
s.scale *= 1.8;
s.alpha *= .2;
}
A_Explode(GetMissileDamage(0,0),80,0);
A_AlertMonsters(400);
tcnt++;
if ( tcnt < 2 ) return;
tcnt = 0;
Spawn("AirRingLight",pos);
}
void A_Splode()
{
A_AlertMonsters();
A_QuakeEx(6,6,6,20,0,250,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
A_StartSound("deepimpact/bullethit",CHAN_VOICE,CHANF_DEFAULT,1.,.3);
A_SprayDecal("ImpactMark");
Spawn("AirBulletLight",pos);
int numpt = Random[ExploS](10,20);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,6);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[ExploS](240,255));
s.special1 = Random[ExploS](1,2);
s.scale *= 2.4;
s.alpha *= .4;
}
numpt = Random[ExploS](8,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,6);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](6,16);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
}
States
{
Spawn:
TNT1 A -1;
Stop;
Death:
TNT1 A 1 A_Splode();
Stop;
}
}
Class AirBulletLight : PaletteLight
{
Default
{
Tag "ImpactWav";
ReactionTime 5;
Args 0,0,0,150;
}
}
Class AirRingLight : PaletteLight
{
Default
{
Tag "ImpactWav2";
ReactionTime 30;
Args 0,0,0,120;
}
}
Class AirBulletRing : Actor
{
Default
{
RenderStyle "Add";
+NOGRAVITY;
+NOBLOCKMAP;
+DONTSPLASH;
+ROLLSPRITE;
+ROLLCENTER;
+FORCEXYBILLBOARD;
Radius 0.1;
Height 0;
}
States
{
Spawn:
XRG1 ABCDEFGHIJKLMNOPQRSTUVWX 2;
Stop;
}
}
Class DeepTracer : LineTracer
{
Actor ignoreme;
Array<Actor> hitlist;
Array<double> hitdist;
override ETraceStatus TraceCallback()
{
if ( Results.HitType == TRACE_HitActor )
{
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
if ( Results.HitActor.bSHOOTABLE )
{
hitlist.Push(Results.HitActor);
hitdist.Push(Results.Distance);
return TRACE_Skip;
}
return TRACE_Skip;
}
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
{
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
return TRACE_Stop;
return TRACE_Skip;
}
return TRACE_Stop;
}
}
Class THitList
{
Actor a;
int nhits;
Vector3 avgdir;
double avgdist;
}
Class DeepImpact : SWWMWeapon
{
int clipcount;
double charge;
bool charging;
transient ui TextureID WeaponBox;
transient ui HUDFont mTewiFont;
transient ui Font TewiFont;
transient ui DynamicValueInterpolator ChargeInter;
Property ClipCount : clipcount;
@ -17,9 +193,195 @@ Class DeepImpact : SWWMWeapon
SWWMLoreLibrary.Add(other.player,"Locke");
}
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
{
//if ( !WeaponBox ) WeaponBox = TexMan.CheckForTexture("graphics/HUD/DeepImpactDisplay.png",TexMan.Type_Any);
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
//Screen.DrawTexture(WeaponBox,false,bx-25,by-23,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-58,by-14,String.Format("Air: %3d%%",ChargeInter?ChargeInter.GetValue():clipcount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
override void HudTick()
{
if ( !ChargeInter ) ChargeInter = DynamicValueInterpolator.Create(clipcount,.5,1,25);
ChargeInter.Update(clipcount);
}
override bool ReportHUDAmmo()
{
return true;
return (ClipCount>0);
}
action void A_BeginCharge()
{
invoker.charge = 0;
A_StartSound("deepimpact/charge",CHAN_WEAPONEXTRA);
A_QuakeEx(2,2,2,35,0,1,"",QF_RELATIVE|QF_SCALEUP,rollIntensity:.2);
A_AlertMonsters(100);
}
action void A_ChargeUp()
{
invoker.charge += 1./TICRATE;
A_WeaponOffset(FRandom[Impact](-1,1)*invoker.charge,32+FRandom[Impact](-1,1)*invoker.charge);
if ( invoker.charge >= 1. )
{
A_WeaponOffset(0,32);
player.SetPSprite(PSP_WEAPON,ResolveState("AltRelease"));
}
}
action void A_DryFire()
{
let weap = Weapon(invoker);
if ( !weap ) return;
A_StartSound("deepimpact/dryfire",CHAN_WEAPON,CHANF_OVERLAP,.5);
A_AlertMonsters(70);
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
int numpt = Random[Impact](5,7);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Impact](-.1,.1),FRandom[Impact](-.1,.1),FRandom[Impact](-.1,.1))).unit()*FRandom[Impact](.1,.4);
let s = Spawn("SWWMSmoke",origin);
s.vel = pvel;
s.scale *= .3;
s.alpha *= .05;
s.SetShade(Color(1,1,1)*Random[Impact](192,255));
}
}
action void A_Air()
{
let weap = Weapon(invoker);
if ( !weap ) return;
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.05);
A_StartSound("deepimpact/fire",CHAN_WEAPON,CHANF_OVERLAP);
A_Recoil(.05);
A_AlertMonsters(300);
invoker.clipcount = max(0,invoker.clipcount-3);
Vector3 x, y, z, dir;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
DeepTracer t = new("DeepTracer");
t.ignoreme = self;
Array<THitList> list;
list.Clear();
int rings = 1;
for ( double i=0; i<1.; i+=.05 )
{
for ( int j=0; j<360; j+=(360/rings) )
{
dir = (x+y*cos(j)*i+z*sin(j)*i).unit();
t.hitlist.Clear();
t.hitdist.Clear();
t.Trace(origin,level.PointInSector(origin.xy),dir,150-i*50,0);
for ( int i=0; i<t.hitlist.Size(); i++ )
{
int inl = -1;
for ( int k=0; k<list.Size(); k++ )
{
if ( list[k].a != t.hitlist[i] ) continue;
inl = k;
break;
}
if ( inl == -1 )
{
THitList l = new("THitList");
l.a = t.hitlist[i];
inl = list.Push(l);
}
list[inl].nhits++;
list[inl].avgdir += dir;
list[inl].avgdist += t.hitdist[i];
}
if ( t.Results.HitType == TRACE_HitWall ) t.Results.HitLine.RemoteActivate(self,t.Results.Side,SPAC_Impact,t.Results.HitPos);
}
rings += 5;
}
for ( int i=0; i<list.Size(); i++ )
{
Vector3 avgdir = list[i].avgdir/list[i].nhits;
double avgdist = list[i].avgdist/list[i].nhits;
double dmg = 4000.*(1.-clamp(avgdist/300.,0.,1.));
if ( !list[i].a.bCANNOTPUSH && (list[i].a.mass < LARGE_MASS) )
list[i].a.vel += ((avgdir+(0,0,.35))*dmg/max(50,list[i].a.mass));
list[i].a.DamageMobj(self,self,int(dmg/500.),'Push',DMG_THRUSTLESS);
}
let ti = ThinkerIterator.Create("Actor");
Actor m;
while ( m = Actor(ti.Next()) )
{
if ( !m.bMISSILE ) continue;
double rdist = level.Vec3Diff(origin,m.pos).length();
Vector3 rdir = level.Vec3Diff(origin,m.pos).unit();
if ( LineTrace(atan2(rdir.y,rdir.x),rdist,asin(-rdir.z),TRF_THRUACTORS|TRF_ABSPOSITION,origin.z,origin.x,origin.y) || (rdist > 150) || (rdir dot x < 0.7) ) continue;
m.speed = m.vel.length();
m.vel = m.speed*(m.vel.unit()*.2+rdir).unit();
if ( m.target == self ) continue;
if ( m.bSEEKERMISSILE ) m.tracer = m.target;
m.target = self;
}
int numpt = Random[Impact](7,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Impact](-.2,.2),FRandom[Impact](-.2,.2),FRandom[Impact](-.2,.2))).unit()*FRandom[Impact](.5,4);
let s = Spawn("SWWMSmoke",origin);
s.vel = pvel;
s.special1 = 1;
s.scale *= .5;
s.alpha *= .15;
s.SetShade(Color(1,1,1)*Random[Impact](192,255));
}
}
action void A_AltBullet()
{
let weap = Weapon(invoker);
if ( !weap ) return;
A_StopSound(CHAN_WEAPONEXTRA);
A_QuakeEx(6,6,6,10,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.7);
A_Recoil(4.);
A_StartSound("deepimpact/altfire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.5);
A_AlertMonsters();
invoker.charge = 0;
invoker.clipcount = 0;
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,.002);
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
let p = Spawn("AirBullet",origin);
p.target = self;
p.angle = atan2(dir.y,dir.x);
p.pitch = asin(-dir.z);
p.vel = dir*p.speed;
int numpt = Random[Impact](14,18);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](1,6);
let s = Spawn("SWWMSmoke",origin);
s.vel = pvel;
s.special1 = 2;
s.scale *= .7;
s.alpha *= .2;
s.SetShade(Color(1,1,1)*Random[Impact](192,255));
}
}
action void A_Crank()
{
invoker.clipcount = min(invoker.default.clipcount,invoker.clipcount+20);
A_StartSound("deepimpact/reload",CHAN_WEAPON,CHANF_OVERLAP);
A_QuakeEx(1,1,1,7,0,1,"",QF_RELATIVE|QF_SCALEUP,rollIntensity:.05);
}
action void A_NoCrank()
{
A_StartSound("deepimpact/noreload",CHAN_WEAPON,CHANF_OVERLAP);
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE|QF_SCALEUP,rollIntensity:.05);
}
Default
@ -27,7 +389,7 @@ Class DeepImpact : SWWMWeapon
Tag "$T_DEEPIMPACT";
Inventory.PickupMessage "$I_DEEPIMPACT";
Obituary "$O_DEEPIMPACT";
Weapon.UpSound "impact/select";
Weapon.UpSound "deepimpact/select";
Weapon.SlotNumber 1;
Weapon.SelectionOrder 3000;
Stamina 2000;
@ -39,5 +401,83 @@ Class DeepImpact : SWWMWeapon
Spawn:
XZW1 A -1;
Stop;
Select:
XZW2 I 2 A_FullRaise();
XZW2 JKLMNOP 2;
Goto Ready;
Ready:
XZW2 A 1 A_WeaponReady(WRF_ALLOWRELOAD|WRF_ALLOWUSER1|WRF_ALLOWZOOM);
Wait;
DryFire:
XZW2 A 1 A_DryFire();
XZW2 QR 2;
XZW2 TU 3;
XZW2 A 4;
Goto Ready;
Fire:
XZW2 A 0 A_JumpIf(invoker.ClipCount<=0,"DryFire");
XZW2 A 1 A_Air();
XZW2 QR 2;
XZW2 STUA 3;
Goto Ready;
AltFire:
XZW2 A 0 A_JumpIf(invoker.ClipCount<100,"Reload");
XZW2 A 0 A_BeginCharge();
XZW2 A 1 A_ChargeUp();
Wait;
AltRelease:
XZW2 A 1 A_AltBullet();
XZW2 VW 1;
XZW2 X 2;
XZW2 YZ 3;
XZW3 AB 5;
XZW3 CD 4;
XZW3 EFG 3;
Goto Ready;
Reload:
XZW2 A 0 A_JumpIf(invoker.clipcount>=invoker.default.clipcount,"NoReload");
XZW2 A 2 A_StartSound("deepimpact/reloadbeg",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 HIJ 2;
ReloadHold:
XZW3 K 2 A_Crank();
XZW3 LM 2;
XZW3 NOPQ 3;
XZW3 K 0 A_JumpIf((player.cmd.buttons&(BT_RELOAD|BT_ALTATTACK))&&(invoker.clipcount<invoker.default.clipcount),"ReloadHold");
XZW3 K 2 A_StartSound("deepimpact/reloadend",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 RSTUV 2;
Goto Ready;
NoReload:
XZW2 A 2 A_StartSound("deepimpact/reloadbeg",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 HIJ 2;
NoReloadHold:
XZW3 K 2 A_NoCrank();
XZW3 L 2;
XZW3 M 5;
XZW3 L 3;
XZW3 K 2 A_StartSound("deepimpact/reloadend",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 RSTUV 2;
Goto Ready;
Zoom:
XZW2 A 3 A_StartSound("deepimpact/checkout",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 WXYZ 3;
XZW4 AB 4;
XZW4 CD 3;
XZW4 EFG 2;
Goto Ready;
User1:
XZW2 A 3 A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
XZW4 H 4 A_StartSound("demolitionist/reloadbeg",CHAN_WEAPON,CHANF_OVERLAP);
XZW4 I 3;
XZW4 J 2;
XZW4 KLM 1;
XZW4 N 3 A_Melee(60);
XZW4 O 3 { invoker.PlayUpSound(self); }
XZW4 PQRSTUV 2;
Goto Ready;
Deselect:
XZW2 A 2 A_StartSound("deepimpact/deselect",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 BCDEFGHI 2;
XZW2 I -1 A_FullLower();
Stop;
}
}

View file

@ -69,6 +69,7 @@ Class RefresherRegen : Powerup
{
if ( Owner.GiveBody(int(Strength),500) )
{
SWWMScoreObj.Spawn(int(Strength),Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
SWWMHandler.DoFlash(Owner,Color(32,224,128,255),10);
Owner.A_StartSound("powerup/refresher",CHAN_ITEM,CHANF_LOCAL,.4);
}

View file

@ -9,14 +9,16 @@ Class MsgLine
Class SWWMStatusBar : BaseStatusBar
{
TextureID StatusTex, WeaponTex, ScoreTex, InventoryTex, ChatTex[6],
HealthTex[5], FuelTex, DashTex;
HealthTex[5], FuelTex, DashTex, EnemyBTex, EnemyHTex;
HUDFont mTewiFont;
// "Full History" contains all messages since session start, nothing is flushed
// this can be accessed from a section of the knowledge base
Array<MsgLine> MainQueue, PickupQueue, FullHistory;
Actor targetactors[40], scoreactors[60], keyactors[10];
Vector3 exitpoints[10], uselines[10];
Array<SWWMCombatTracker> targets; // healthbars
Array<SWWMScoreObj> scoreobjects; // floating scores
Array<SWWMInterest> interesting; // points of interest for omnisight
// client cvars
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol;
@ -27,6 +29,17 @@ Class SWWMStatusBar : BaseStatusBar
double FracTic;
int chatopen;
// shared from renderunderlay, needed for proper interpolation of some things
Vector3 viewpos, viewrot;
// libeye stuff
swwmLe__ProjScreen proj;
swwmLe__GLScreen gl_proj;
swwmLe__SWScreen sw_proj;
swwmLe__Viewport viewport;
bool can_project;
transient CVar cvar_renderer;
DynamicValueInterpolator HealthInter, ScoreInter, FuelInter, DashInter;
override void FlushNotify()
@ -98,9 +111,59 @@ Class SWWMStatusBar : BaseStatusBar
return true;
}
void PrepareProjection()
{
if ( !cvar_renderer ) cvar_renderer = CVar.GetCVar("vid_rendermode",players[consoleplayer]);
if ( !cvar_renderer )
{
can_project = proj = gl_proj;
return;
}
switch ( cvar_renderer.GetInt() )
{
case 0:
case 1:
proj = sw_proj;
break;
default:
proj = gl_proj;
break;
}
can_project = proj;
}
private bool CmpTarget( SWWMCombatTracker a, SWWMCombatTracker b )
{
return ((a.mytarget && a.mytarget.player) && (!b.mytarget || !b.mytarget.player));
}
private bool CmpScore( SWWMScoreObj a, SWWMScoreObj b )
{
int srt[3] = { Font.CR_GOLD, Font.CR_GREEN, Font.CR_RED };
int s1 = 0, s2 = 0;
for ( int i=0; i<3; i++ )
{
if ( a.tcolor == srt[i] ) s1 = i;
if ( b.tcolor == srt[i] ) s2 = i;
}
return s1 < s2;
}
private bool CmpInterest( SWWMInterest a, SWWMInterest b )
{
return a.type < b.type; }
private bool CmpDist( Vector3 a, Vector3 b )
{
double dista = level.Vec3Diff(viewpos,a).length();
double distb = level.Vec3Diff(viewpos,b).length();
return (dista < distb);
}
override void Tick()
{
Super.Tick();
PrepareProjection();
if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]);
if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]);
if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]);
@ -118,8 +181,97 @@ Class SWWMStatusBar : BaseStatusBar
MainQueue.Delete(i);
i--;
}
// update target actors
// update omnisight stuff
if ( CPlayer.mo.FindInventory("Omnisight") )
{
interesting.Clear();
let ii = ThinkerIterator.Create("SWWMInterest",Thinker.STAT_USER);
SWWMInterest poi; // :3
while ( poi = SWWMInterest(ii.Next()) )
{
if ( (poi.type == INT_Usable) && (level.Vec3Diff(viewpos,poi.pos).length() > 1000) ) continue;
interesting.Push(poi);
}
// sort by distance
for ( int i=0; i<interesting.Size(); i++ )
{
int j = 1;
while ( j < interesting.Size() )
{
int k = j;
while ( (k > 0) && (CmpInterest(interesting[k-1],interesting[k]) || CmpDist(interesting[k-1].pos,interesting[k].pos)) )
{
SWWMInterest tmp = interesting[k];
interesting[k] = interesting[k-1];
interesting[k-1] = tmp;
k--;
}
j++;
}
}
// trim size, for render performance
if ( interesting.Size() > 20 ) interesting.Resize(20);
}
// update target stuff
targets.Clear();
let ti = ThinkerIterator.Create("SWWMCombatTracker",Thinker.STAT_USER);
SWWMCombatTracker ct;
while ( ct = SWWMCombatTracker(ti.Next()) )
{
// ignore player unless chasecamming
if ( (ct.mytarget == players[consoleplayer].mo) && (players[consoleplayer].Camera == players[consoleplayer].mo) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( (level.Vec3Diff(viewpos,ct.pos).length() > ((ct.mytarget&&ct.mytarget.player)?8000:1000)) ) continue;
if ( ct.mytarget && ct.mytarget.player && deathmatch ) continue; // no players in dm
if ( gametic > ct.updated+35 ) continue;
targets.Push(ct);
}
// sort by distance (give priority to players)
for ( int i=0; i<targets.Size(); i++ )
{
int j = 1;
while ( j < targets.Size() )
{
int k = j;
while ( (k > 0) && (CmpTarget(targets[k-1],targets[k]) || CmpDist(targets[k-1].pos,targets[k].pos)) )
{
SWWMCombatTracker tmp = targets[k];
targets[k] = targets[k-1];
targets[k-1] = tmp;
k--;
}
j++;
}
}
// trim size, for render performance
if ( targets.Size() > 40 ) targets.Resize(40);
// update floating scores
scoreobjects.Clear();
let si = ThinkerIterator.Create("SWWMScoreObj",Thinker.STAT_USER);
SWWMScoreObj so;
while ( so = SWWMScoreObj(si.Next()) )
{
if ( level.Vec3Diff(viewpos,so.pos).length() > 2000 ) continue;
scoreobjects.Push(so);
}
// sort by distance
for ( int i=0; i<scoreobjects.Size(); i++ )
{
int j = 1;
while ( j < scoreobjects.Size() )
{
int k = j;
while ( (k > 0) && (CmpScore(scoreobjects[k-1],scoreobjects[k]) || CmpDist(scoreobjects[k-1].pos,scoreobjects[k].pos)) )
{
SWWMScoreObj tmp = scoreobjects[k];
scoreobjects[k] = scoreobjects[k-1];
scoreobjects[k-1] = tmp;
k--;
}
j++;
}
}
// trim size, for render performance
if ( scoreobjects.Size() > 60 ) scoreobjects.Resize(60);
// update interpolators
HealthInter.Update(CPlayer.health);
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
@ -135,6 +287,9 @@ Class SWWMStatusBar : BaseStatusBar
FuelInter.Update(0);
DashInter.Update(0);
}
// let weapons update their own interpolators
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' )
SWWMWeapon(CPlayer.ReadyWeapon).HudTick();
}
override void Init()
@ -158,19 +313,121 @@ Class SWWMStatusBar : BaseStatusBar
ChatTex[4] = TexMan.CheckForTexture("graphics/HUD/ChatBoxLine_Smol.png",TexMan.Type_Any);
ChatTex[5] = TexMan.CheckForTexture("graphics/HUD/ChatBoxBottom_Smol.png",TexMan.Type_Any);
InventoryTex = TexMan.CheckForTexture("graphics/HUD/InventoryBox.png",TexMan.Type_Any);
EnemyBTex = TexMan.CheckForTexture("graphics/HUD/EnemyBox.png",TexMan.Type_Any);
EnemyHTex = TexMan.CheckForTexture("graphics/HUD/EnemyBar.png",TexMan.Type_Any);
mTewiFont = HUDFont.Create("TewiShaded");
HealthInter = DynamicValueInterpolator.Create(100,.1,1,100);
ScoreInter = DynamicValueInterpolator.Create(0,.1,1,1000);
FuelInter = DynamicValueInterpolator.Create(120,.5,1,100);
DashInter = DynamicValueInterpolator.Create(120,.5,1,40);
gl_proj = new("swwmLe__GLScreen");
sw_proj = new("swwmLe__SWScreen");
PrepareProjection();
}
static private string FormatDist( double dist )
{
double meters = dist/32.;
if ( meters > 1000. ) return String.Format("\cj%d\cckm",int(meters/1000.));
return String.Format("\cj%d\ccm",int(meters));
}
private void DrawTarget()
{
// omnisight: usable highlights
// omnisight: key locations
viewport.FromHud();
proj.CacheResolution();
proj.CacheFov(players[consoleplayer].fov);
proj.Reorient(ViewPos,ViewRot);
proj.BeginProjection();
Vector3 vdir = (cos(ViewRot.x)*cos(ViewRot.y),sin(ViewRot.x)*cos(ViewRot.y),-sin(ViewRot.y));
// points of interest
String tag;
if ( CPlayer.mo.FindInventory("Omnisight") )
{
for ( int i=0; i<interesting.Size(); i++ )
{
Vector3 tdir = Level.Vec3Diff(ViewPos,interesting[i].pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( interesting[i].type == INT_Key ) tag = String.Format("\cf%s\c-",StringTable.Localize(interesting[i].trackedkey.GetTag()));
else if ( interesting[i].type == INT_Exit )
{
if ( interesting[i].trackedline.special == Exit_Secret )
tag = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_SEXIT"));
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
else if ( interesting[i].type == INT_Usable )
{
String basetag;
if ( interesting[i].trackedline.activation&SPAC_Use )
{
if ( interesting[i].trackedline.activation&SPAC_Impact ) basetag = StringTable.Localize("$SWWM_BOTHUSE");
else basetag = StringTable.Localize("$SWWM_USABLE");
}
else basetag = StringTable.Localize("$SWWM_SHOOTABLE");
tag = String.Format("\cb%s\c-",basetag);
}
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,(vpos.x-hs.x*mTewiFont.mFont.StringWidth(tag)/2.)/hs.x,(vpos.y-hs.y*mTewiFont.mFont.GetHeight()/2.)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
tag = String.Format("\cu(%s\cu)\c-",FormatDist(tdir.length()));
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,(vpos.x-hs.x*mTewiFont.mFont.StringWidth(tag)/2.)/hs.x,(vpos.y+hs.y*mTewiFont.mFont.GetHeight()/2.)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
// targetting array
// floating kill scores
for ( int i=0; i<targets.Size(); i++ )
{
Vector3 tdir = Level.Vec3Diff(ViewPos,targets[i].prevpos*(1.-fractic)+targets[i].pos*fractic);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
tag = targets[i].mytag;
double alph = ((targets[i].updated+35)-gametic)/35.;
Vector2 barsiz = TexMan.GetScaledSize(EnemyBTex);
barsiz.x *= hs.x;
barsiz.y *= hs.y;
Vector2 barpos = vpos-(barsiz/2.);
barpos.y -= 16.;
Screen.DrawTexture(EnemyBTex,false,barpos.x/hs.x,barpos.y/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
int hw = int((clamp(targets[i].intp.GetValue(),0,targets[i].maxhealth)*50.)/targets[i].maxhealth);
Screen.DrawTexture(EnemyHTex,false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
Screen.DrawText(mTewiFont.mFont,Font.CR_WHITE,(barpos.x+barsiz.x/2.-(mTewiFont.mFont.StringWidth(tag)*hs.x)/2.)/hs.x,(barpos.y-13*hs.y)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
// floating kill scores and others
for ( int i=0; i<scoreobjects.Size(); i++ )
{
Vector3 tdir = Level.Vec3Diff(ViewPos,scoreobjects[i].pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
tag = String.Format("%+d",scoreobjects[i].score);
double alph = clamp((scoreobjects[i].lifespan+fractic)/35.,0.,1.);
Vector2 fo = (0,0);
if ( scoreobjects[i].tcolor == Font.CR_RED )
{
// damage falls down
int initspd = (128-scoreobjects[i].seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 64+scoreobjects[i].seed2/2;
fo.x = (.05*initspd)*((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**.8);
fo.y = -((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**1.5)+boostup*sin((90./scoreobjects[i].initialspan)*(gametic+fractic-scoreobjects[i].starttic));
}
else if ( scoreobjects[i].tcolor == Font.CR_GREEN )
{
// health falls up (?)
int initspd = (128-scoreobjects[i].seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 16+scoreobjects[i].seed2/4;
fo.x = (.15*initspd)*((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**.6);
fo.y = ((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**1.2)-boostup*sin((90./scoreobjects[i].initialspan)*(gametic+fractic-scoreobjects[i].starttic));
}
else fo.y = scoreobjects[i].initialspan-(scoreobjects[i].lifespan+fractic); // score rises linearly
Screen.DrawText(mTewiFont.mFont,scoreobjects[i].tcolor,(vpos.x-hs.x*(fo.x+mTewiFont.mFont.StringWidth(tag)/2.))/hs.x,(vpos.y-hs.y*(fo.y+(mTewiFont.mFont.GetHeight()/2.)))/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}
private void DrawScore()

View file

@ -148,6 +148,7 @@ Class SWWMHealth : Inventory abstract
if ( UseSound ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_DEFAULT,.6);
SWWMHandler.DoFlash(Owner,Color(48,64,128,255),5);
Owner.GiveInventory(giveme,GetDefaultByType(giveme).Amount);
SWWMScoreObj.Spawn(GetDefaultByType(giveme).Amount,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
return true;
}
@ -402,6 +403,10 @@ Class SWWMWeapon : Weapon abstract
virtual ui void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
{
}
// HUD-side ticking
virtual ui void HudTick()
{
}
// instant raise/lower
action void A_FullRaise()
{
@ -450,8 +455,20 @@ Class SWWMWeapon : Weapon abstract
{
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
self.angle += clamp(diff,-5.,5.);
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Melee',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
SWWMHandler.DoKnockback(d.HitActor,d.HitDir+(0,0,.2),dmg*2000);
if ( CountInv("RagekitPower") )
{
invoker.bEXTREMEDEATH = true;
invoker.bNOEXTREMEDEATH = false;
}
else
{
invoker.bEXTREMEDEATH = false;
invoker.bNOEXTREMEDEATH = true;
}
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Melee',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
invoker.bEXTREMEDEATH = invoker.default.bEXTREMEDEATH;
invoker.bNOEXTREMEDEATH = invoker.default.bEXTREMEDEATH;
if ( d.HitActor.player ) d.HitActor.A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25);
if ( !d.HitActor.bNOBLOOD )
{

View file

@ -33,8 +33,8 @@ Class Demolitionist : PlayerPawn
Mass 500;
PainChance 255;
Player.DisplayName "Demolitionist";
Player.StartItem "DeepImpact";
Player.StartItem "ExplodiumGun";
Player.StartItem "DeepImpact";
Player.ViewHeight 52;
Player.AirCapacity 0;
Player.GruntSpeed 20;

View file

@ -15,6 +15,7 @@ Class GrilledCheeseSandwich : Inventory
Owner.A_QuakeEx(9,9,9,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
Owner.GiveBody(1000,1000);
SWWMScoreObj.Spawn(1000,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
let n = Owner.FindInventory("ArmorNugget");
if ( !n ) Owner.GiveInventory("ArmorNugget",GetDefaultByType("ArmorNugget").MaxAmount);
else n.Amount = n.MaxAmount;
@ -742,7 +743,7 @@ Class LampMoth : Actor
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_StartSound("moth/fly",CHAN_BODY,CHANF_LOOPING,.15,4.,FRandom[Moth](.8,1.2));
A_StartSound("moth/fly",CHAN_BODY,CHANF_LOOPING,.02,4.,FRandom[Moth](.8,1.2));
if ( master && master.player ) SetFriendPlayer(master.player);
else bFRIENDLY = false;
}
@ -1004,6 +1005,7 @@ Class CompanionLamp : Actor
Default
{
Tag "$T_LAMP";
+NOGRAVITY;
+SHOOTABLE;
+NOTELEPORT;
@ -1012,6 +1014,7 @@ Class CompanionLamp : Actor
+DONTSPLASH;
+INTERPOLATEANGLES;
+LOOKALLAROUND;
+FRIENDLY;
Radius 4;
Height 16;
}
@ -1119,7 +1122,7 @@ Class CompanionLamp : Actor
if ( foundspot && (i > 45) ) break;
}
Vector3 diff = level.Vec3Diff(pos,target.pos);
if ( (diff.length() > 400) || !CheckSight(target) )
if ( diff.length() > 400 )
{
Actor f = Spawn("SWWMItemFog",pos);
f.A_StartSound("lamp/disappear",CHAN_VOICE);
@ -1249,7 +1252,7 @@ Class SWWMLamp : Inventory
Super.DoEffect();
if ( !thelamp )
{
thelamp = Spawn("CompanionLamp",Owner.Vec3Offset(cos(Owner.angle-180)*32,sin(Owner.angle-180)*32,Owner.height-8));
thelamp = Spawn("CompanionLamp",Owner.Vec3Offset(cos(Owner.angle)*20,sin(Owner.angle)*20,24));
thelamp.target = Owner;
thelamp.master = self;
let f = Spawn("SWWMItemFog",thelamp.pos);

View file

@ -277,7 +277,7 @@ Class ExplodiumGun : SWWMWeapon
int clipcount;
bool chambered;
transient ui TextureID WeaponBox;
transient ui HUDFont mTewiFont;
transient ui Font TewiFont;
Property ClipCount : ClipCount;
@ -291,10 +291,10 @@ Class ExplodiumGun : SWWMWeapon
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
{
if ( !WeaponBox ) WeaponBox = TexMan.CheckForTexture("graphics/HUD/ExplodiumDisplay.png",TexMan.Type_Any);
if ( !mTewiFont ) mTewiFont = HUDFont.Create("TewiShaded");
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
Screen.DrawTexture(WeaponBox,false,bx-25,by-23,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( chambered ) Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,bx-23,by-22,"⁺¹",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,bx-20,by-15,String.Format("%d",max(clipcount,0)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( chambered ) Screen.DrawText(TewiFont,Font.CR_FIRE,bx-23,by-22,"⁺¹",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1);
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-20,by-15,String.Format("%d",max(clipcount,0)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
action void A_Schutt()

View file

@ -780,7 +780,7 @@ Class CandyGun : SWWMWeapon
int clipcount;
bool chambered;
transient ui TextureID WeaponBox;
transient ui HUDFont mTewiFont;
transient ui Font TewiFont;
bool tospecial;
Property ClipCount : ClipCount;
@ -795,13 +795,13 @@ Class CandyGun : SWWMWeapon
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
{
if ( !WeaponBox ) WeaponBox = TexMan.CheckForTexture("graphics/HUD/CandygunDisplay.png",TexMan.Type_Any);
if ( !mTewiFont ) mTewiFont = HUDFont.Create("TewiShaded");
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
Screen.DrawTexture(WeaponBox,false,bx-52,by-45,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( chambered ) Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,bx-23,by-22,"⁺¹",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,bx-20,by-15,String.Format("%d",max(clipcount,0)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( chambered ) Screen.DrawText(TewiFont,Font.CR_FIRE,bx-23,by-22,"⁺¹",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1);
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-20,by-15,String.Format("%d",max(clipcount,0)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
int cx = (Ammo1.Amount>9)?49:46;
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,bx-cx,by-19,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,bx-38,by-41,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-19,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-38,by-41,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
action void A_Schutt()
@ -964,6 +964,7 @@ Class CandyGun : SWWMWeapon
override bool ReportHUDAmmo()
{
if ( chambered || (clipcount > 0) ) return true;
if ( Ammo1.Amount <= 0 ) return false;
return Super.ReportHUDAmmo();
}